diff -Nur --exclude=*~ linux-2.4.16/CREDITS linux/CREDITS
--- linux-2.4.16/CREDITS	Mon Nov 26 08:35:00 2001
+++ linux/CREDITS	Fri Nov 30 13:04:36 2001
@@ -1634,6 +1634,13 @@
 S: 80-283 Gdansk
 S: Poland
 
+N: Jakob Kemi
+E: jakob.kemi@telia.com
+D: V4L W9966 Webcam driver
+S: Forsbyvägen 33
+S: 74143 Knivsta
+S: Sweden
+
 N: Gero Kuhlmann
 E: gero@gkminix.han.de
 D: mounting root via NFS
diff -Nur --exclude=*~ linux-2.4.16/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.4.16/Documentation/Configure.help	Mon Nov 26 08:35:04 2001
+++ linux/Documentation/Configure.help	Fri Nov 30 15:29:24 2001
@@ -899,7 +899,7 @@
 
   It is normally safe to answer Y; however, the default is N.
 
-ATA Work(s) In Progress (EXPERIMENTAL)‹
+ATA Work(s) In Progress (EXPERIMENTAL)
 CONFIG_IDEDMA_PCI_WIP
   If you enable this you will be able to use and test highly
   developmental projects. If you say N, the configurator will
@@ -8684,6 +8684,19 @@
   a module, say M here and read <file:Documentation/modules.txt>. If
   unsure, say N.
 
+Asix AX88190 PCMCIA support
+CONFIG_PCMCIA_AXNET
+  Say Y here if you intend to attach an Asix AX88190-based PCMCIA
+  (PC-card) Fast Ethernet card to your computer.  These cards are
+  nearly NE2000 compatible but need a separate driver due to a few
+  misfeatures.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called axnet_cs.o.  If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.  If
+  unsure, say N.
+
 New Media PCMCIA support
 CONFIG_PCMCIA_NMCLAN
   Say Y here if you intend to attach a New Media Ethernet or LiveWire
@@ -16925,8 +16938,8 @@
   can be downloaded from:
   <http://developer.intel.com/technology/iapc/acpi/downloads.htm>.
 
-  The ACPI mailing list may also be of interest:
-  <http://phobos.fs.tum.de/acpi/index.html>.
+  The ACPI Sourceforge project may also be of interest:
+  <http://sf.net/projects/acpi/>
 
 Enable ACPI 2.0 with errata 1.3
 CONFIG_ACPI20
@@ -17321,23 +17334,24 @@
   Say Y if you intend to run this kernel on a Toshiba portable.
   Say N otherwise.
 
-Dell Inspiron 8000 support
+Dell laptop support
 CONFIG_I8K
   This adds a driver to safely access the System Management Mode
-  of the CPU on the Dell Inspiron 8000. The System Management Mode
-  is used to read cpu temperature and cooling fan status and to
-  control the fans on the I8K portables.
-
-  This driver has been tested only on the Inspiron 8000 but it may
-  also work with other Dell laptops. You can force loading on other
-  models by passing the parameter `force=1' to the module. Use at
-  your own risk.
-
-  For information on utilities to make use of this driver see the
-  I8K Linux utilities web site at:
-  <http://www.debian.org/~dz/i8k/>
+  of the CPU on the Dell Inspiron and Latitude laptops. The System
+  Management Mode is used to read cpu temperature, cooling fan
+  status and Fn-keys status on Dell laptops. It can also be used
+  to switch the fans on and off.
+
+  The driver has been developed and tested on an Inspiron 8000
+  but it should work on any Dell Inspiron or Latitude laptop.
+  You can force loading on unsupported models by passing the
+  parameter `force=1' to the module. Use at your own risk.
+
+  For more information on this driver and for utilities that make
+  use of the module see the I8K Linux Utilities web site at:
+  <http://www.debian.org/~dz/i8k/>.
 
-  Say Y if you intend to run this kernel on a Dell Inspiron 8000.
+  Say Y if you intend to run this kernel on a Dell laptop.
   Say N otherwise.
 
 /dev/cpu/microcode - Intel IA32 CPU microcode support
@@ -21444,7 +21458,7 @@
   as a module (c-qcam.o).
   Read <file:Documentation/video4linux/CQcam.txt> for more information.
 
-Winbond W9966CF Webcam Video For Linux
+W9966 Webcam (FlyCam Supra and others) Video For Linux
 CONFIG_VIDEO_W9966
   Video4linux driver for Winbond's w9966 based Webcams.
   Currently tested with the LifeView FlyCam Supra.
@@ -21453,7 +21467,7 @@
   This driver is also available as a module (w9966.o).
 
   Check out <file:Documentation/video4linux/w9966.txt> and
-  <file:Documentation/video4linux/w9966.c> for more information.
+  <file:drivers/media/video/w9966.c> for more information.
 
 CPiA Video For Linux
 CONFIG_VIDEO_CPIA
diff -Nur --exclude=*~ linux-2.4.16/Documentation/filesystems/devfs/ChangeLog linux/Documentation/filesystems/devfs/ChangeLog
--- linux-2.4.16/Documentation/filesystems/devfs/ChangeLog	Mon Nov 26 08:35:04 2001
+++ linux/Documentation/filesystems/devfs/ChangeLog	Wed Nov 28 18:15:57 2001
@@ -1778,3 +1778,30 @@
   Thanks to Kari Hurtta <hurtta@leija.mh.fmi.fi>
 
 - Avoid deadlock in <devfs_follow_link> by using temporary buffer
+===============================================================================
+Changes for patch v197
+
+- First release of new locking code for devfs core (v1.0)
+
+- Fixed bug in drivers/cdrom/cdrom.c
+===============================================================================
+Changes for patch v198
+
+- Discard temporary buffer, now use "%s" for dentry names
+
+- Don't generate path in <try_modload>: use fake entry instead
+
+- Use "existing" directory in <_devfs_make_parent_for_leaf>
+
+- Use slab cache rather than fixed buffer for devfsd events
+===============================================================================
+Changes for patch v199
+
+- Removed obsolete usage of DEVFS_FL_NO_PERSISTENCE
+
+- Send DEVFSD_NOTIFY_REGISTERED events in <devfs_mk_dir>
+
+- Fixed locking bug in <devfs_d_revalidate_wait> due to typo
+
+- Do not send CREATE, CHANGE, ASYNC_OPEN or DELETE events from devfsd
+  or children
diff -Nur --exclude=*~ linux-2.4.16/Documentation/filesystems/devfs/README linux/Documentation/filesystems/devfs/README
--- linux-2.4.16/Documentation/filesystems/devfs/README	Mon Nov 26 08:35:04 2001
+++ linux/Documentation/filesystems/devfs/README	Wed Nov 28 18:15:57 2001
@@ -3,7 +3,7 @@
 
 Linux Devfs (Device File System) FAQ
 Richard Gooch
-29-SEP-2001
+9-NOV-2001
 
 -----------------------------------------------------------------------------
 
@@ -11,7 +11,9 @@
 
 http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.html
 and looks much better than the text version distributed with the
-kernel sources.
+kernel sources. A mirror site is available at:
+
+http://www.ras.ucalgary.ca/~rgooch/linux/docs/devfs.html
 
 There is also an optional daemon that may be used with devfs. You can
 find out more about it at:
diff -Nur --exclude=*~ linux-2.4.16/Documentation/pm.txt linux/Documentation/pm.txt
--- linux-2.4.16/Documentation/pm.txt	Mon Nov 26 08:35:04 2001
+++ linux/Documentation/pm.txt	Fri Nov 30 15:29:24 2001
@@ -34,7 +34,7 @@
 system the associated daemon will exit gracefully.
 
   apmd:   http://worldvisions.ca/~apenwarr/apmd/
-  acpid:  http://phobos.fs.tum.de/acpi/
+  acpid:  http://acpid.sf.net/
 
 Driver Interface
 ----------------
@@ -260,7 +260,7 @@
 Q: Who do I contact for additional information about
    enabling power management for my specific driver/device?
 
-ACPI4Linux mailing list: acpi@phobos.fs.tum.de
+ACPI Development mailing list: acpi-devel@lists.sourceforge.net
 
 System Interface
 ----------------
diff -Nur --exclude=*~ linux-2.4.16/Documentation/usb/philips.txt linux/Documentation/usb/philips.txt
--- linux-2.4.16/Documentation/usb/philips.txt	Mon Nov 26 08:35:04 2001
+++ linux/Documentation/usb/philips.txt	Fri Nov 30 15:58:51 2001
@@ -1,5 +1,5 @@
 This file contains some additional information for the Philips webcams.
-E-mail: webcam@smcc.demon.nl                        Last updated: 2001-07-27
+E-mail: webcam@smcc.demon.nl                        Last updated: 2001-09-24
 
 The main webpage for the Philips driver is http://www.smcc.demon.nl/webcam/.
 It contains a lot of extra information, a FAQ, and the binary plugin
@@ -13,11 +13,9 @@
 the latter, since it makes troubleshooting a lot easier. The built-in
 microphone is supported through the USB Audio class.
 
-(Taken from install.html)
-
 When you load the module you can set some default settings for the
-camera; some programs depend on a particular image-size or -format. The
-options are:
+camera; some programs depend on a particular image-size or -format and
+don't know how to set it properly in the driver. The options are:
 
 size
    Can be one of 'sqcif', 'qsif', 'qcif', 'sif', 'cif' or
@@ -99,6 +97,57 @@
    This parameter works only with the ToUCam range of cameras (730, 740,
    750). For other cameras this command is silently ignored, and the LED
    cannot be controlled.
+
+dev_hint
+   A long standing problem with USB devices is their dynamic nature: you
+   never know what device a camera gets assigned; it depends on module load
+   order, the hub configuration, the order in which devices are plugged in,
+   and the phase of the moon (i.e. it can be random). With this option you
+   can give the driver a hint as to what video device node (/dev/videoX) it
+   should use with a specific camera. This is also handy if you have two
+   cameras of the same model.
+
+   A camera is specified by its type (the number from the camera model,
+   like PCA645, PCVC750VC, etc) and optionally the serial number (visible
+   in /proc/bus/usb/devices). A hint consists of a string with the following
+   format:
+
+      [type[.serialnumber]:]node
+      
+   The square brackets mean that both the type and the serialnumber are
+   optional, but a serialnumber cannot be specified without a type (which
+   would be rather pointless). The serialnumber is separated from the type
+   by a '.'; the node number by a ':'.
+   
+   This somewhat cryptic syntax is best explained by a few examples:
+
+     dev_hint=3,5              The first detected cam gets assigned
+                               /dev/video3, the second /dev/video5. Any
+                               other cameras will get the first free 
+                               available slot (see below).
+
+     dev_hint=645:1,680=2      The PCA645 camera will get /dev/video1,
+                               and a PCVC680 /dev/video2.
+                               
+     dev_hint=645.0123:3,645.4567:0	The PCA645 camera with serialnumber 
+                                        0123 goes to /dev/video3, the same
+                                        camera model with the 4567 serial
+                                        gets /dev/video0.
+
+     dev_hint=750:1,4,5,6       The PCVC750 camera will get /dev/video1, the 
+                                next 3 Philips cams will use /dev/video4 
+                                through /dev/video6.
+
+   Some points worth knowing:
+   - Serialnumbers are case sensitive and must be written full, including 
+     leading zeroes (it's treated as a string).
+   - If a device node is already occupied, registration will fail and 
+     the webcam is not available.
+   - You can have up to 64 video devices; be sure to make enough device
+     nodes in /dev if you want to spread the numbers (this does not apply
+     to devfs). After /dev/video9 comes /dev/video10 (not /dev/videoA).
+   - If a camera does not match any dev_hint, it will simply get assigned
+     the first available device node, just as it used to be.
 
 trace
    In order to better detect problems, it is now possible to turn on a
diff -Nur --exclude=*~ linux-2.4.16/Documentation/usb/scanner.txt linux/Documentation/usb/scanner.txt
--- linux-2.4.16/Documentation/usb/scanner.txt	Mon Nov 26 08:35:04 2001
+++ linux/Documentation/usb/scanner.txt	Fri Nov 30 15:58:52 2001
@@ -83,7 +83,7 @@
 	`mknod /dev/usbscanner1 c 180 49`
                       . 
                       .
-	`mknod /dev/usbscanner15 180 63`
+	`mknod /dev/usbscanner15 c 180 63`
 
 
 If you foresee using only one scanner it is best to:
diff -Nur --exclude=*~ linux-2.4.16/Documentation/video4linux/Zoran linux/Documentation/video4linux/Zoran
--- linux-2.4.16/Documentation/video4linux/Zoran	Mon Nov 26 08:35:04 2001
+++ linux/Documentation/video4linux/Zoran	Wed Nov 28 18:15:57 2001
@@ -160,9 +160,9 @@
   set aside the necessary memory during boot time. There seem to be
   several versions of this patch against various kernel versions
   floating around in the net, you may obtain one e.g. from:
-  http://www.polyware.nl/~middelin/patch/bigphysarea-2.2.1.tar.gz You
-  also have to compile your driver AFTER installing that patch in order
-  to get it working
+  http://www.polyware.nl/~middelin/hob-v4l.html#bigphysarea
+  You also have to compile your driver AFTER installing that patch in
+  order to get it working
 
   or
 
diff -Nur --exclude=*~ linux-2.4.16/Documentation/video4linux/w9966.txt linux/Documentation/video4linux/w9966.txt
--- linux-2.4.16/Documentation/video4linux/w9966.txt	Mon Nov 26 08:35:04 2001
+++ linux/Documentation/video4linux/w9966.txt	Fri Nov 30 13:04:36 2001
@@ -1,37 +1,33 @@
+W9966 Camera driver, written by Jakob Kemi (jakob.kemi@telia.com)
 
-W9966 Camera driver, written by Jakob Kemi (jakob.kemi@post.utfors.se)
+After a lot of work in softice & wdasm, reading .pdf-files and tiresome
+trial-and-error work I've finally got everything to work. I needed vision for a
+robotics project so I borrowed this camera from a friend and started hacking.
+Anyway I've converted my original code from the AVR 8bit RISC C/ASM code into
+a working Linux driver.
 
-Ok, after a lot of work in softice, wdasm, reading pdf-files
-and trial-and-error work I've finally got everything to work.
-Since I needed some vision for a robotics project I borrowed
-this camera from a friend and started hacking. Anyway I've
-converted my original code from the AVR 8bit RISC C/asm
-into a working linux driver. I would really appreciate _any_
-kind of feedback regarding this driver.
-
-To get it working quickly configure your kernel
-to support parport, ieee1284, video4linux, experimental drivers
-and w9966
+To get it working simply configure your kernel to support
+parport, ieee1284, video4linux and w9966
 
-If w9966 is statically linked it will perform aggressive probing
-for the camera. If built as a module you'll have more configuration options.
+If w9966 is statically linked it will always perform aggressive probing for
+the camera. If built as a module you'll have more configuration options.
 
 Options:
-modprobe w9966.o pardev=parport0(or whatever) parmode=0 (0=auto, 1=ecp, 2=epp)
- 
+ modprobe w9966.o pardev=parport0(or whatever) parmode=0 (0=auto, 1=ecp, 2=epp)
 voila!
 
 you can also type 'modinfo -p w9966.o' for option usage
 (or checkout w9966.c)
 
-I've only tested it with custom built testprograms
-(http://hem.fyristorg.com/mogul/w9966.html) and with gqcam.
-(you'll need to tweak the code to qcam a bit to make it work,
-dimensions and such)
+The only thing to keep in mind is that the image format is in Y-U-Y-V format
+where every two pixels take 4 bytes. In SDL (www.libsdl.org) this format
+is called VIDEO_PALETTE_YUV422 (16 bpp).
+
+A minimal test application (with source) is available from:
+  http://hem.fyristorg.com/mogul/w9966.html
 
 The slow framerate is due to missing DMA ECP read support in the 
 parport drivers. I might add working EPP support later.
 
 Good luck!
-
-    /Jakob
+    /Jakob Kemi
diff -Nur --exclude=*~ linux-2.4.16/MAINTAINERS linux/MAINTAINERS
--- linux-2.4.16/MAINTAINERS	Mon Nov 26 08:35:01 2001
+++ linux/MAINTAINERS	Fri Nov 30 15:29:24 2001
@@ -148,8 +148,8 @@
 ACPI
 P:	Andy Grover
 M:	andrew.grover@intel.com
-L:	acpi@phobos.fs.tum.de
-W:	http://phobos.fs.tum.de/acpi/index.html
+L:	acpi-devel@lists.sourceforge.net
+W:	http://sf.net/projects/acpi/
 S:	Maintained
 
 AD1816 SOUND DRIVER
@@ -404,6 +404,12 @@
 L:	linux-decnet-user@lists.sourceforge.net
 S:	Maintained
 
+DELL LAPTOP SMM DRIVER
+P:	Massimo Dal Zotto
+M:	dz@debian.org
+W:	http://www.debian.org/~dz/i8k/
+S:	Maintained
+
 DEVICE NUMBER REGISTRY
 P:	H. Peter Anvin
 M:	hpa@zytor.com
@@ -1660,8 +1666,8 @@
 W:	http://misc.nu/hugh/keyspan/
 
 USB SUBSYSTEM
-P:	Johannes Erdfelt
-M:	johannes@erdfelt.com
+P:	Greg Kroah-Hartman
+M:	greg@kroah.com
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 W:	http://www.linux-usb.org
diff -Nur --exclude=*~ linux-2.4.16/arch/i386/config.in linux/arch/i386/config.in
--- linux-2.4.16/arch/i386/config.in	Mon Nov 26 08:35:03 2001
+++ linux/arch/i386/config.in	Wed Nov 28 18:15:57 2001
@@ -149,7 +149,7 @@
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
 fi
 tristate 'Toshiba Laptop support' CONFIG_TOSHIBA
-tristate 'Dell Inspiron 8000 support' CONFIG_I8K
+tristate 'Dell laptop support' CONFIG_I8K
 
 tristate '/dev/cpu/microcode - Intel IA32 CPU microcode support' CONFIG_MICROCODE
 tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR
diff -Nur --exclude=*~ linux-2.4.16/arch/i386/kernel/dmi_scan.c linux/arch/i386/kernel/dmi_scan.c
--- linux-2.4.16/arch/i386/kernel/dmi_scan.c	Mon Nov 26 08:35:03 2001
+++ linux/arch/i386/kernel/dmi_scan.c	Wed Nov 28 18:15:57 2001
@@ -564,6 +564,11 @@
 			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0094.P10"),
 			NO_MATCH, NO_MATCH
                         } },
+	{ broken_pirq, "l44GX Bios", {        		/* Bad $PIR */
+			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
+			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0120.P12"),
+			NO_MATCH, NO_MATCH
+                        } },
 	{ broken_pirq, "l44GX Bios", {		/* Bad $PIR */
 			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
 			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0125.P13"),
diff -Nur --exclude=*~ linux-2.4.16/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- linux-2.4.16/arch/i386/mm/init.c	Mon Nov 26 08:35:03 2001
+++ linux/arch/i386/mm/init.c	Thu Nov 29 18:32:55 2001
@@ -25,6 +25,7 @@
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
 #include <linux/bootmem.h>
+#include <linux/slab.h>
 
 #include <asm/processor.h>
 #include <asm/system.h>
@@ -596,3 +597,17 @@
 	val->mem_unit = PAGE_SIZE;
 	return;
 }
+
+#if defined(CONFIG_X86_PAE)
+struct kmem_cache_s *pae_pgd_cachep;
+void __init pgtable_cache_init(void)
+{
+	/*
+	 * PAE pgds must be 16-byte aligned:
+	 */
+	pae_pgd_cachep = kmem_cache_create("pae_pgd", 32, 0,
+		SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN, NULL, NULL);
+	if (!pae_pgd_cachep)
+		panic("init_pae(): Cannot alloc pae_pgd SLAB cache");
+}
+#endif /* CONFIG_X86_PAE */
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc/defconfig linux/arch/sparc/defconfig
--- linux-2.4.16/arch/sparc/defconfig	Mon Nov 26 08:35:03 2001
+++ linux/arch/sparc/defconfig	Fri Nov 30 13:01:25 2001
@@ -138,7 +138,7 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK is not set
+CONFIG_NETLINK_DEV=y
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
@@ -148,6 +148,7 @@
 # CONFIG_IP_PNP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 CONFIG_IPV6=m
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc/mm/extable.c linux/arch/sparc/mm/extable.c
--- linux-2.4.16/arch/sparc/mm/extable.c	Mon Nov 26 08:35:03 2001
+++ linux/arch/sparc/mm/extable.c	Fri Nov 30 13:01:25 2001
@@ -11,35 +11,49 @@
 
 static unsigned long
 search_one_table(const struct exception_table_entry *start,
-		 const struct exception_table_entry *last,
+		 const struct exception_table_entry *end,
 		 unsigned long value, unsigned long *g2)
 {
-	const struct exception_table_entry *first = start;
-	const struct exception_table_entry *mid;
-	long diff = 0;
-        while (first <= last) {
-		mid = (last - first) / 2 + first;
-		diff = mid->insn - value;
-                if (diff == 0) {
-                	if (!mid->fixup) {
-                		*g2 = 0;
-                		return (mid + 1)->fixup;
-                	} else
-	                        return mid->fixup;
-                } else if (diff < 0)
-                        first = mid+1;
-                else
-                        last = mid-1;
-        }
-        if (last->insn < value && !last->fixup && last[1].insn > value) {
-        	*g2 = (value - last->insn)/4;
-        	return last[1].fixup;
-        }
-        if (first > start && first[-1].insn < value
-	    && !first[-1].fixup && first->insn < value) {
-        	*g2 = (value - first[-1].insn)/4;
-        	return first->fixup;
-        }
+	const struct exception_table_entry *walk;
+
+	/* Single insn entries are encoded as:
+	 *	word 1:	insn address
+	 *	word 2:	fixup code address
+	 *
+	 * Range entries are encoded as:
+	 *	word 1: first insn address
+	 *	word 2: 0
+	 *	word 3: last insn address + 4 bytes
+	 *	word 4: fixup code address
+	 *
+	 * See asm/uaccess.h for more details.
+	 */
+
+	/* 1. Try to find an exact match. */
+	for (walk = start; walk <= end; walk++) {
+		if (walk->fixup == 0) {
+			/* A range entry, skip both parts. */
+			walk++;
+			continue;
+		}
+
+		if (walk->insn == value)
+			return walk->fixup;
+	}
+
+	/* 2. Try to find a range match. */
+	for (walk = start; walk <= (end - 1); walk++) {
+		if (walk->fixup)
+			continue;
+
+		if (walk[0].insn <= value &&
+		    walk[1].insn > value) {
+			*g2 = (value - walk[0].insn) / 4;
+			return walk[1].fixup;
+		}
+		walk++;
+	}
+
         return 0;
 }
 
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
--- linux-2.4.16/arch/sparc/mm/fault.c	Mon Nov 26 08:35:03 2001
+++ linux/arch/sparc/mm/fault.c	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.121 2001/10/30 04:54:22 davem Exp $
+/* $Id: fault.c,v 1.122 2001/11/17 07:19:26 davem Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -155,34 +155,47 @@
 asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, 
 			    unsigned long address)
 {
+	struct pt_regs regs;
 	unsigned long g2;
+	unsigned int insn;
 	int i;
-	unsigned insn;
-	struct pt_regs regs;
 	
-	i = search_exception_table (ret_pc, &g2);
+	i = search_exception_table(ret_pc, &g2);
 	switch (i) {
-	/* load & store will be handled by fixup */
-	case 3: return 3;
-	/* store will be handled by fixup, load will bump out */
-	/* for _to_ macros */
-	case 1: insn = (unsigned)pc; if ((insn >> 21) & 1) return 1; break;
-	/* load will be handled by fixup, store will bump out */
-	/* for _from_ macros */
-	case 2: insn = (unsigned)pc; 
-		if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) return 2; 
+	case 3:
+		/* load & store will be handled by fixup */
+		return 3;
+
+	case 1:
+		/* store will be handled by fixup, load will bump out */
+		/* for _to_ macros */
+		insn = *((unsigned int *) pc);
+		if ((insn >> 21) & 1)
+			return 1;
+		break;
+
+	case 2:
+		/* load will be handled by fixup, store will bump out */
+		/* for _from_ macros */
+		insn = *((unsigned int *) pc);
+		if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15)
+			return 2; 
 		break; 
-	default: break;
-	}
-	memset (&regs, 0, sizeof (regs));
+
+	default:
+		break;
+	};
+
+	memset(&regs, 0, sizeof (regs));
 	regs.pc = pc;
 	regs.npc = pc + 4;
-	__asm__ __volatile__ (
+	__asm__ __volatile__(
 		"rd %%psr, %0\n\t"
 		"nop\n\t"
 		"nop\n\t"
 		"nop\n" : "=r" (regs.psr));
-	unhandled_fault (address, current, &regs);
+	unhandled_fault(address, current, &regs);
+
 	/* Not reached */
 	return 0;
 }
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- linux-2.4.16/arch/sparc/mm/init.c	Mon Nov 26 08:35:03 2001
+++ linux/arch/sparc/mm/init.c	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.100 2001/09/21 22:51:47 davem Exp $
+/*  $Id: init.c,v 1.103 2001/11/19 19:03:08 davem Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -410,9 +410,6 @@
 	int datapages = 0;
 	int initpages = 0; 
 	int i;
-#ifdef CONFIG_BLK_DEV_INITRD
-	unsigned long addr, last;
-#endif
 
 	highmem_start_page = mem_map + highstart_pfn;
 
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/Makefile linux/arch/sparc64/Makefile
--- linux-2.4.16/arch/sparc64/Makefile	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/Makefile	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.49 2001/10/17 18:26:58 davem Exp $
+# $Id: Makefile,v 1.51 2001/11/17 00:15:27 davem Exp $
 # sparc64/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -38,11 +38,6 @@
 AS		:= $(AS) --undeclared-regs
 endif
 
-#
-# Uncomment the first CFLAGS if you are doing kgdb source level
-# debugging of the kernel to get the proper debugging information.
-
-#CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7 
 ifneq ($(NEW_GCC),y)
   CFLAGS := $(CFLAGS) -pipe -mno-fpu -mtune=ultrasparc -mmedlow \
 	    -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
@@ -51,25 +46,6 @@
 	    -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare \
 	    $(CC_UNDECL)
   AFLAGS += -m64 -mcpu=ultrasparc $(CC_UNDECL)
-endif
-
-# Uncomment this to get spinlock/rwlock debugging on SMP.
-# DEBUG_SPINLOCK = 1
-
-ifdef CONFIG_SMP
-  ifdef DEBUG_SPINLOCK
-    CFLAGS += -DSPIN_LOCK_DEBUG
-    AFLAGS += -DSPIN_LOCK_DEBUG
-  endif
-endif
-
-# Uncomment this to keep track of how often flush_dcache_page
-# actually flushes the caches, output via /proc/cpuinfo
-#
-# DEBUG_DCACHE_FLUSH = 1
-ifdef DEBUG_DCACHE_FLUSH
-  CFLAGS += -DDCFLUSH_DEBUG
-  AFLAGS += -DDCFLUSH_DEBUG
 endif
 
 LINKFLAGS = -T arch/sparc64/vmlinux.lds
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/config.in linux/arch/sparc64/config.in
--- linux-2.4.16/arch/sparc64/config.in	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/config.in	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.152 2001/11/12 10:20:47 davem Exp $
+# $Id: config.in,v 1.155 2001/11/17 00:15:27 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -191,21 +191,21 @@
       if [ "$CONFIG_SCSI_SYM53C8XX_2" != "y" ]; then
          dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
          dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI
-      fi
-      if [ "$CONFIG_SCSI_NCR53C8XX" != "n" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
-	 int 'default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
-	 int 'maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
-	 int 'synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 10
-	 bool '  enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE
-         if [ "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
-	    bool '  include support for the NCR PQS/PDS SCSI card' CONFIG_SCSI_NCR53C8XX_PQS_PDS
+         if [ "$CONFIG_SCSI_NCR53C8XX" != "n" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
+            int 'default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
+            int 'maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
+            int 'synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 10
+            bool '  enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE
+            if [ "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
+	       bool '  include support for the NCR PQS/PDS SCSI card' CONFIG_SCSI_NCR53C8XX_PQS_PDS
+            fi
+            if [ "$CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS" = "0" ]; then
+               bool '  not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
+            fi
+            if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+               bool '  assume boards are SYMBIOS compatible (EXPERIMENTAL)' CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
+            fi
          fi
-	 if [ "$CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS" = "0" ]; then
-	    bool '  not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
-	 fi
-	 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-	    bool '  assume boards are SYMBIOS compatible (EXPERIMENTAL)' CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
-	 fi
       fi
       dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
       dep_tristate 'Qlogic ISP FC SCSI support' CONFIG_SCSI_QLOGIC_FC $CONFIG_SCSI
@@ -295,6 +295,13 @@
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
-bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
-#bool 'ECache flush trap support at ta 0x72' CONFIG_EC_FLUSH_TRAP
+bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
+if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
+   bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
+   bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
+   bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
+   bool '  Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE
+   bool '  D-cache flush debugging' CONFIG_DEBUG_DCFLUSH
+fi
+
 endmenu
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- linux-2.4.16/arch/sparc64/defconfig	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/defconfig	Fri Nov 30 13:01:25 2001
@@ -158,15 +158,16 @@
 #
 # 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_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-# CONFIG_BLK_DEV_RAM 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_MD_MULTIPATH=m
+CONFIG_BLK_DEV_LVM=m
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_INITRD is not set
 
 #
@@ -174,8 +175,6 @@
 #
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
 CONFIG_NETLINK_DEV=y
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
@@ -354,15 +353,11 @@
 CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT=y
 CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_OLD_PROC_STATS=y
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-CONFIG_SCSI_NCR53C8XX=m
-CONFIG_SCSI_SYM53C8XX=y
-CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=40
-# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
-# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
 CONFIG_SCSI_QLOGIC_ISP=m
 CONFIG_SCSI_QLOGIC_FC=y
 CONFIG_SCSI_QLOGIC_FC_FIRMWARE=y
@@ -493,6 +488,7 @@
 CONFIG_SUNDANCE=m
 # CONFIG_TLAN is not set
 CONFIG_VIA_RHINE=m
+# CONFIG_VIA_RHINE_MMIO is not set
 CONFIG_WINBOND_840=m
 # CONFIG_NET_POCKET is not set
 
@@ -539,7 +535,7 @@
 CONFIG_NET_FC=y
 # CONFIG_IPHASE5526 is not set
 # CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
+CONFIG_SHAPER=m
 
 #
 # Wan interfaces
@@ -861,4 +857,9 @@
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_DCFLUSH is not set
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile
--- linux-2.4.16/arch/sparc64/kernel/Makefile	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/kernel/Makefile	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.67 2001/05/11 04:31:55 davem Exp $
+# $Id: Makefile,v 1.69 2001/11/19 04:09:53 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -68,7 +68,7 @@
 	@echo "#include <linux/config.h>" > tmp.c
 	@echo "#undef CONFIG_SMP" >> tmp.c
 	@echo "#include <linux/sched.h>" >> tmp.c
-	$(CPP) $(CPPFLAGS) tmp.c -o tmp.i
+	$(CPP) $(CPPFLAGS) -P tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
 	@echo "#include <linux/config.h>" >> check_asm_data.c
 	@echo "#undef CONFIG_SMP" >> check_asm_data.c
@@ -95,12 +95,12 @@
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
 	@echo -e "\n#else /* CONFIG_SMP */\n" >> asm_offsets.h
-	@echo -e "#ifndef SPIN_LOCK_DEBUG\n" >>asm_offsets.h
+	@echo -e "#ifndef CONFIG_DEBUG_SPINLOCK\n" >>asm_offsets.h
 	@echo "#include <linux/config.h>" > tmp.c
 	@echo "#undef CONFIG_SMP" >> tmp.c
 	@echo "#define CONFIG_SMP 1" >> tmp.c
 	@echo "#include <linux/sched.h>" >> tmp.c
-	$(CPP) $(CPPFLAGS) tmp.c -o tmp.i
+	$(CPP) $(CPPFLAGS) -P tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
 	@echo "#include <linux/config.h>" >> check_asm_data.c
 	@echo "#undef CONFIG_SMP" >> check_asm_data.c
@@ -127,9 +127,9 @@
 	$(HOSTCC) -o check_asm check_asm.c
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
-	@echo -e "\n#else /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h
+	@echo -e "\n#else /* CONFIG_DEBUG_SPINLOCK */\n" >> asm_offsets.h
 	@echo "#include <linux/sched.h>" > tmp.c
-	$(CPP) $(CPPFLAGS) -DSPIN_LOCK_DEBUG tmp.c -o tmp.i
+	$(CPP) $(CPPFLAGS) -P -DCONFIG_DEBUG_SPINLOCK tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
 	@echo "#include <linux/config.h>" >> check_asm_data.c
 	@echo "#undef CONFIG_SMP" >> check_asm_data.c
@@ -140,7 +140,7 @@
 	$(SH) ./check_asm.sh -data mm tmp.i check_asm_data.c
 	$(SH) ./check_asm.sh -data thread tmp.i check_asm_data.c
 	@echo '};' >> check_asm_data.c
-	$(CC) $(CPPFLAGS) -DSPIN_LOCK_DEBUG $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm_data.s check_asm_data.c
+	$(CC) $(CPPFLAGS) -DCONFIG_DEBUG_SPINLOCK $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm_data.s check_asm_data.c
 	@echo "/* Automatically generated. Do not edit. */" > check_asm.c
 	@echo 'extern int printf(const char *fmt, ...);' >>check_asm.c
 	@echo 'unsigned int check_asm_data[] = {' >> check_asm.c
@@ -156,7 +156,7 @@
 	$(HOSTCC) -o check_asm check_asm.c
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
-	@echo -e "#endif /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h
+	@echo -e "#endif /* CONFIG_DEBUG_SPINLOCK */\n" >> asm_offsets.h
 	@echo -e "#endif /* CONFIG_SMP */\n" >> asm_offsets.h
 	@echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
 	@if test -r $(HPATH)/asm/asm_offsets.h; then \
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- linux-2.4.16/arch/sparc64/kernel/entry.S	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/kernel/entry.S	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.137 2001/10/18 09:06:36 davem Exp $
+/* $Id: entry.S,v 1.138 2001/11/14 17:24:36 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -657,15 +657,15 @@
 	stx		%g5, [%g1 + %lo(pdma_size)]
 	sethi		%hi(auxio_register), %g1
 	ldx		[%g1 + %lo(auxio_register)], %g7
-	ldub		[%g7], %g5
+	lduba		[%g7] ASI_PHYS_BYPASS_EC_E, %g5
 	or		%g5, 0xc2, %g5
-	stb		%g5, [%g7]
+	stba		%g5, [%g7] ASI_PHYS_BYPASS_EC_E
 	andn		%g5, 0x02, %g5
 
 	nop; nop;  nop; nop;  nop; nop;
 	nop; nop;  nop; nop;  nop; nop;
 
-	stb		%g5, [%g7]
+	stba		%g5, [%g7] ASI_PHYS_BYPASS_EC_E
 	sethi		%hi(doing_pdma), %g1
 	b,pt		%xcc, floppy_dosoftint
 	 st		%g0, [%g1 + %lo(doing_pdma)]
@@ -678,7 +678,12 @@
 	sethi		%hi(irq_action), %g1
 	or		%g1, %lo(irq_action), %g1
 	ldx		[%g1 + (11 << 3)], %g3		! irqaction[floppy_irq]
-	ldx		[%g3 + 0x10], %g4		! action->mask == ino_bucket ptr
+	ldx		[%g3 + 0x08], %g4		! action->flags>>48==ino
+	sethi		%hi(ivector_table), %g3
+	srlx		%g4, 48, %g4
+	or		%g3, %lo(ivector_table), %g3
+	sllx		%g4, 5, %g4
+	ldx		[%g3 + %g4], %g4		! &ivector_table[ino]
 	ldx		[%g4 + 0x10], %g4		! bucket->iclr
 	stwa		%g0, [%g4] ASI_PHYS_BYPASS_EC_E	! ICLR_IDLE
 	membar		#Sync				! probably not needed...
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- linux-2.4.16/arch/sparc64/kernel/ioctl32.c	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/kernel/ioctl32.c	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.132 2001/11/07 05:56:19 davem Exp $
+/* $Id: ioctl32.c,v 1.133 2001/11/14 06:14:29 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
@@ -2421,6 +2421,7 @@
 	u32 pv[ABS_MAX_PV + 1];
 	u32 lv[ABS_MAX_LV + 1];
     	uint8_t vg_uuid[UUID_LEN+1];	/* volume group UUID */
+	uint8_t dummy1[200];
 } vg32_t;
 
 typedef struct {
@@ -2462,7 +2463,7 @@
 } lv_status_byindex_req32_t;
 
 typedef struct {
-	dev_t dev;
+	__kernel_dev_t32 dev;
 	u32   lv;
 } lv_status_bydev_req32_t;
 
@@ -2535,7 +2536,8 @@
 	lv_block_exception32_t *lbe32;
 	lv_block_exception_t *lbe;
 	lv32_t *ul = (lv32_t *)A(p);
-	lv_t *l = (lv_t *)kmalloc(sizeof(lv_t), GFP_KERNEL);
+	lv_t *l = (lv_t *) kmalloc(sizeof(lv_t), GFP_KERNEL);
+
 	if (!l) {
 		*errp = -ENOMEM;
 		return NULL;
@@ -2565,12 +2567,11 @@
 		if (l->lv_block_exception) {
 			lbe32 = (lv_block_exception32_t *)A(ptr2);
 			memset(lbe, 0, size);
-                       for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) {
-                               err |= get_user(lbe->rsector_org, &lbe32->rsector_org);
-                               err |= __get_user(lbe->rdev_org, &lbe32->rdev_org);
-                               err |= __get_user(lbe->rsector_new, &lbe32->rsector_new);
-                               err |= __get_user(lbe->rdev_new, &lbe32->rdev_new);
-
+			for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) {
+				err |= get_user(lbe->rsector_org, &lbe32->rsector_org);
+				err |= __get_user(lbe->rdev_org, &lbe32->rdev_org);
+				err |= __get_user(lbe->rsector_new, &lbe32->rsector_new);
+				err |= __get_user(lbe->rdev_new, &lbe32->rdev_new);
 			}
 		}
 	}
@@ -2608,7 +2609,7 @@
 
 static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-	vg_t *v;
+	vg_t *v = NULL;
 	union {
 		lv_req_t lv_req;
 		le_remap_req_t le_remap;
@@ -2626,17 +2627,22 @@
 	switch (cmd) {
 	case VG_STATUS:
 		v = kmalloc(sizeof(vg_t), GFP_KERNEL);
-		if (!v) return -ENOMEM;
+		if (!v)
+			return -ENOMEM;
 		karg = v;
 		break;
+
+	case VG_CREATE_OLD:
 	case VG_CREATE:
 		v = kmalloc(sizeof(vg_t), GFP_KERNEL);
-		if (!v) return -ENOMEM;
-		if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc) ||
-		    __get_user(v->proc, &((vg32_t *)arg)->proc)) {
+		if (!v)
+			return -ENOMEM;
+		if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc)) {
 			kfree(v);
 			return -EFAULT;
 		}
+		/* 'proc' field is unused, just NULL it out. */
+		v->proc = NULL;
 		if (copy_from_user(v->vg_uuid, ((vg32_t *)arg)->vg_uuid, UUID_LEN+1)) {
 			kfree(v);
 			return -EFAULT;
@@ -2648,39 +2654,46 @@
 			return -EPERM;
 		for (i = 0; i < v->pv_max; i++) {
 			err = __get_user(ptr, &((vg32_t *)arg)->pv[i]);
-			if (err) break;
+			if (err)
+				break;
 			if (ptr) {
 				v->pv[i] = kmalloc(sizeof(pv_t), GFP_KERNEL);
 				if (!v->pv[i]) {
 					err = -ENOMEM;
 					break;
 				}
-				err = copy_from_user(v->pv[i], (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1);
+				err = copy_from_user(v->pv[i], (void *)A(ptr),
+						     sizeof(pv32_t) - 8 - UUID_LEN+1);
 				if (err) {
 					err = -EFAULT;
 					break;
 				}
-				err = copy_from_user(v->pv[i]->pv_uuid, ((pv32_t *)A(ptr))->pv_uuid, UUID_LEN+1);
+				err = copy_from_user(v->pv[i]->pv_uuid,
+						     ((pv32_t *)A(ptr))->pv_uuid,
+						     UUID_LEN+1);
 				if (err) {
 				        err = -EFAULT;
 					break;
 				}
 
-				
-				v->pv[i]->pe = NULL; v->pv[i]->inode = NULL;
+				v->pv[i]->pe = NULL;
+				v->pv[i]->bd = NULL;
 			}
 		}
 		if (!err) {
 			for (i = 0; i < v->lv_max; i++) {
 				err = __get_user(ptr, &((vg32_t *)arg)->lv[i]);
-				if (err) break;
+				if (err)
+					break;
 				if (ptr) {
 					v->lv[i] = get_lv_t(ptr, &err);
-					if (err) break;
+					if (err)
+						break;
 				}
 			}
 		}
 		break;
+
 	case LV_CREATE:
 	case LV_EXTEND:
 	case LV_REDUCE:
@@ -2688,54 +2701,70 @@
 	case LV_RENAME:
 	case LV_STATUS_BYNAME:
 	        err = copy_from_user(&u.pv_status, arg, sizeof(u.pv_status.pv_name));
-		if (err) return -EFAULT;
+		if (err)
+			return -EFAULT;
 		if (cmd != LV_REMOVE) {
 			err = __get_user(ptr, &((lv_req32_t *)arg)->lv);
-			if (err) return err;
+			if (err)
+				return err;
 			u.lv_req.lv = get_lv_t(ptr, &err);
 		} else
 			u.lv_req.lv = NULL;
 		break;
 
-
 	case LV_STATUS_BYINDEX:
-		err = get_user(u.lv_byindex.lv_index, &((lv_status_byindex_req32_t *)arg)->lv_index);
+		err = get_user(u.lv_byindex.lv_index,
+			       &((lv_status_byindex_req32_t *)arg)->lv_index);
 		err |= __get_user(ptr, &((lv_status_byindex_req32_t *)arg)->lv);
-		if (err) return err;
+		if (err)
+			return err;
 		u.lv_byindex.lv = get_lv_t(ptr, &err);
 		break;
+
 	case LV_STATUS_BYDEV:
 	        err = get_user(u.lv_bydev.dev, &((lv_status_bydev_req32_t *)arg)->dev);
+		err |= __get_user(ptr, &((lv_status_bydev_req32_t *)arg)->lv);
+		if (err)
+			return err;
 		u.lv_bydev.lv = get_lv_t(ptr, &err);
-		if (err) return err;
-		u.lv_bydev.lv = &p;
-		p.pe = NULL; p.inode = NULL;		
-		break;		
+		break;
+
 	case VG_EXTEND:
 		err = copy_from_user(&p, (void *)arg, sizeof(pv32_t) - 8 - UUID_LEN+1);
-		if (err) return -EFAULT;
+		if (err)
+			return -EFAULT;
 		err = copy_from_user(p.pv_uuid, ((pv32_t *)arg)->pv_uuid, UUID_LEN+1);
-		if (err) return -EFAULT;
-		p.pe = NULL; p.inode = NULL;
+		if (err)
+			return -EFAULT;
+		p.pe = NULL;
+		p.bd = NULL;
 		karg = &p;
 		break;
+
 	case PV_CHANGE:
 	case PV_STATUS:
 		err = copy_from_user(&u.pv_status, arg, sizeof(u.lv_req.lv_name));
-		if (err) return -EFAULT;
+		if (err)
+			return -EFAULT;
 		err = __get_user(ptr, &((pv_status_req32_t *)arg)->pv);
-		if (err) return err;
+		if (err)
+			return err;
 		u.pv_status.pv = &p;
 		if (cmd == PV_CHANGE) {
-			err = copy_from_user(&p, (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1);
-			if (err) return -EFAULT;
-			p.pe = NULL; p.inode = NULL;
+			err = copy_from_user(&p, (void *)A(ptr),
+					     sizeof(pv32_t) - 8 - UUID_LEN+1);
+			if (err)
+				return -EFAULT;
+			p.pe = NULL;
+			p.bd = NULL;
 		}
 		break;
-	}
+	};
+
         old_fs = get_fs(); set_fs (KERNEL_DS);
         err = sys_ioctl (fd, cmd, (unsigned long)karg);
         set_fs (old_fs);
+
 	switch (cmd) {
 	case VG_STATUS:
 		if (!err) {
@@ -2748,42 +2777,60 @@
 		}
 		kfree(v);
 		break;
+
+	case VG_CREATE_OLD:
 	case VG_CREATE:
-		for (i = 0; i < v->pv_max; i++)
-			if (v->pv[i]) kfree(v->pv[i]);
-		for (i = 0; i < v->lv_max; i++)
-			if (v->lv[i]) put_lv_t(v->lv[i]);
+		for (i = 0; i < v->pv_max; i++) {
+			if (v->pv[i])
+				kfree(v->pv[i]);
+		}
+		for (i = 0; i < v->lv_max; i++) {
+			if (v->lv[i])
+				put_lv_t(v->lv[i]);
+		}
 		kfree(v);
 		break;
+
 	case LV_STATUS_BYNAME:
-		if (!err && u.lv_req.lv) err = copy_lv_t(ptr, u.lv_req.lv);
+		if (!err && u.lv_req.lv)
+			err = copy_lv_t(ptr, u.lv_req.lv);
 		/* Fall through */
+
         case LV_CREATE:
 	case LV_EXTEND:
 	case LV_REDUCE:
-		if (u.lv_req.lv) put_lv_t(u.lv_req.lv);
+		if (u.lv_req.lv)
+			put_lv_t(u.lv_req.lv);
 		break;
+
 	case LV_STATUS_BYINDEX:
 		if (u.lv_byindex.lv) {
-			if (!err) err = copy_lv_t(ptr, u.lv_byindex.lv);
+			if (!err)
+				err = copy_lv_t(ptr, u.lv_byindex.lv);
 			put_lv_t(u.lv_byindex.lv);
 		}
 		break;
+
+	case LV_STATUS_BYDEV:
+	        if (u.lv_bydev.lv) {
+			if (!err)
+				err = copy_lv_t(ptr, u.lv_bydev.lv);
+			put_lv_t(u.lv_byindex.lv);
+	        }
+	        break;
+
 	case PV_STATUS:
 		if (!err) {
 			err = copy_to_user((void *)A(ptr), &p, sizeof(pv32_t) - 8 - UUID_LEN+1);
-			if (err) return -EFAULT;
+			if (err)
+				return -EFAULT;
 			err = copy_to_user(((pv_t *)A(ptr))->pv_uuid, p.pv_uuid, UUID_LEN + 1);
-			if (err) return -EFAULT;
+			if (err)
+				return -EFAULT;
 		}
 		break;
-	case LV_STATUS_BYDEV:
-	        if (!err) {
-			if (!err) err = copy_lv_t(ptr, u.lv_bydev.lv);
-			put_lv_t(u.lv_byindex.lv);
-	        }
-	        break;
-	}
+	};
+
 	return err;
 }
 #endif
@@ -4666,6 +4713,7 @@
 HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl)
 #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
 HANDLE_IOCTL(VG_STATUS, do_lvm_ioctl)
+HANDLE_IOCTL(VG_CREATE_OLD, do_lvm_ioctl)
 HANDLE_IOCTL(VG_CREATE, do_lvm_ioctl)
 HANDLE_IOCTL(VG_EXTEND, do_lvm_ioctl)
 HANDLE_IOCTL(LV_CREATE, do_lvm_ioctl)
@@ -4675,6 +4723,7 @@
 HANDLE_IOCTL(LV_RENAME, do_lvm_ioctl)
 HANDLE_IOCTL(LV_STATUS_BYNAME, do_lvm_ioctl)
 HANDLE_IOCTL(LV_STATUS_BYINDEX, do_lvm_ioctl)
+HANDLE_IOCTL(LV_STATUS_BYDEV, do_lvm_ioctl)
 HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl)
 HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl)
 #endif /* LVM */
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c
--- linux-2.4.16/arch/sparc64/kernel/irq.c	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/kernel/irq.c	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.109 2001/11/12 22:22:37 davem Exp $
+/* $Id: irq.c,v 1.112 2001/11/16 00:04:54 kanoj Exp $
  * irq.c: UltraSparc IRQ handling/init/registry.
  *
  * Copyright (C) 1997  David S. Miller  (davem@caip.rutgers.edu)
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/proc_fs.h>
+#include <linux/kbd_ll.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -34,6 +35,7 @@
 #include <asm/softirq.h>
 #include <asm/starfire.h>
 #include <asm/uaccess.h>
+#include <asm/cache.h>
 
 #ifdef CONFIG_SMP
 static void distribute_irqs(void);
@@ -52,10 +54,10 @@
  * at the same time.
  */
 
-struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (64)));
+struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BYTES)));
 
 #ifndef CONFIG_SMP
-unsigned int __up_workvec[16] __attribute__ ((aligned (64)));
+unsigned int __up_workvec[16] __attribute__ ((aligned (SMP_CACHE_BYTES)));
 #define irq_work(__cpu, __pil)	&(__up_workvec[(void)(__cpu), (__pil)])
 #else
 #define irq_work(__cpu, __pil)	&(cpu_data[(__cpu)].irq_worklists[(__pil)])
@@ -821,6 +823,11 @@
 
 	irq_enter(cpu, irq);
 	kstat.irqs[cpu][irq]++;
+
+#ifdef CONFIG_PCI
+	if (irq == 9)
+		kbd_pt_regs = regs;
+#endif
 
 	/* Sliiiick... */
 #ifndef CONFIG_SMP
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c
--- linux-2.4.16/arch/sparc64/kernel/pci_psycho.c	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/kernel/pci_psycho.c	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.29 2001/10/11 00:44:38 davem Exp $
+/* $Id: pci_psycho.c,v 1.30 2001/11/14 13:17:56 davem Exp $
  * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -371,6 +371,7 @@
 		case PCI_BASE_CLASS_MULTIMEDIA:
 		case PCI_BASE_CLASS_MEMORY:
 		case PCI_BASE_CLASS_BRIDGE:
+		case PCI_BASE_CLASS_SERIAL:
 			ret = 10;
 			break;
 
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c
--- linux-2.4.16/arch/sparc64/kernel/pci_sabre.c	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/kernel/pci_sabre.c	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.40 2001/10/11 00:44:38 davem Exp $
+/* $Id: pci_sabre.c,v 1.41 2001/11/14 13:17:56 davem Exp $
  * pci_sabre.c: Sabre specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -589,6 +589,11 @@
 {
 	int ret;
 
+	if (pdev &&
+	    pdev->vendor == PCI_VENDOR_ID_SUN &&
+	    pdev->device == PCI_DEVICE_ID_SUN_RIO_USB)
+		return 9;
+
 	ret = sabre_pil_table[ino];
 	if (ret == 0 && pdev == NULL) {
 		ret = 1;
@@ -609,6 +614,7 @@
 		case PCI_BASE_CLASS_MULTIMEDIA:
 		case PCI_BASE_CLASS_MEMORY:
 		case PCI_BASE_CLASS_BRIDGE:
+		case PCI_BASE_CLASS_SERIAL:
 			ret = 10;
 			break;
 
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/kernel/pci_schizo.c linux/arch/sparc64/kernel/pci_schizo.c
--- linux-2.4.16/arch/sparc64/kernel/pci_schizo.c	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/kernel/pci_schizo.c	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_schizo.c,v 1.22 2001/10/11 00:44:38 davem Exp $
+/* $Id: pci_schizo.c,v 1.23 2001/11/14 13:17:56 davem Exp $
  * pci_schizo.c: SCHIZO specific PCI controller support.
  *
  * Copyright (C) 2001 David S. Miller (davem@redhat.com)
@@ -337,6 +337,11 @@
 {
 	int ret;
 
+	if (pdev &&
+	    pdev->vendor == PCI_VENDOR_ID_SUN &&
+	    pdev->device == PCI_DEVICE_ID_SUN_RIO_USB)
+		return 9;
+
 	ret = schizo_pil_table[ino];
 	if (ret == 0 && pdev == NULL) {
 		ret = 1;
@@ -357,6 +362,7 @@
 		case PCI_BASE_CLASS_MULTIMEDIA:
 		case PCI_BASE_CLASS_MEMORY:
 		case PCI_BASE_CLASS_BRIDGE:
+		case PCI_BASE_CLASS_SERIAL:
 			ret = 10;
 			break;
 
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- linux-2.4.16/arch/sparc64/kernel/process.c	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/kernel/process.c	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.122 2001/10/18 09:06:36 davem Exp $
+/*  $Id: process.c,v 1.125 2001/11/17 00:10:48 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -276,7 +276,12 @@
 #ifdef CONFIG_SMP
 	unsigned long flags;
 
-	spin_lock_irqsave(&regdump_lock, flags);
+	/* Protect against xcall ipis which might lead to livelock on the lock */
+	__asm__ __volatile__("rdpr      %%pstate, %0\n\t"
+			     "wrpr      %0, %1, %%pstate"
+			     : "=r" (flags)
+			     : "i" (PSTATE_IE));
+	spin_lock(&regdump_lock);
 	printk("CPU[%d]: local_irq_count[%u] irqs_running[%d]\n",
 	       smp_processor_id(),
 	       local_irq_count(smp_processor_id()),
@@ -298,7 +303,9 @@
 	       regs->u_regs[15]);
 	show_regwindow(regs);
 #ifdef CONFIG_SMP
-	spin_unlock_irqrestore(&regdump_lock, flags);
+	spin_unlock(&regdump_lock);
+	__asm__ __volatile__("wrpr	%0, 0, %%pstate"
+			     : : "r" (flags));
 #endif
 }
 
@@ -583,6 +590,11 @@
 {
 	struct thread_struct *t = &p->thread;
 	char *child_trap_frame;
+
+#ifdef CONFIG_DEBUG_SPINLOCK
+	t->smp_lock_count = 0;
+	t->smp_lock_pc = 0;
+#endif
 
 	/* Calculate offset to stack_frame & pt_regs */
 	child_trap_frame = ((char *)p) + (THREAD_SIZE - (TRACEREG_SZ+REGWIN_SZ));
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/kernel/semaphore.c linux/arch/sparc64/kernel/semaphore.c
--- linux-2.4.16/arch/sparc64/kernel/semaphore.c	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/kernel/semaphore.c	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: semaphore.c,v 1.8 2001/05/18 08:01:35 davem Exp $
+/* $Id: semaphore.c,v 1.9 2001/11/18 00:12:56 davem Exp $
  * semaphore.c: Sparc64 semaphore implementation.
  *
  * This is basically the PPC semaphore scheme ported to use
@@ -31,7 +31,7 @@
 "	cas	[%3], %0, %1\n"
 "	cmp	%0, %1\n"
 "	bne,pn	%%icc, 1b\n"
-"	 nop\n"
+"	 membar #StoreLoad | #StoreStore\n"
 	: "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
 	: "r" (&sem->count), "r" (incr), "m" (sem->count)
 	: "cc");
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- linux-2.4.16/arch/sparc64/kernel/smp.c	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/kernel/smp.c	Fri Nov 30 13:01:25 2001
@@ -39,10 +39,10 @@
 extern void calibrate_delay(void);
 extern unsigned prom_cpu_nodes[];
 
-struct cpuinfo_sparc cpu_data[NR_CPUS]  __attribute__ ((aligned (64)));
+cpuinfo_sparc cpu_data[NR_CPUS];
 
-volatile int __cpu_number_map[NR_CPUS]  __attribute__ ((aligned (64)));
-volatile int __cpu_logical_map[NR_CPUS] __attribute__ ((aligned (64)));
+volatile int __cpu_number_map[NR_CPUS]  __attribute__ ((aligned (SMP_CACHE_BYTES)));
+volatile int __cpu_logical_map[NR_CPUS] __attribute__ ((aligned (SMP_CACHE_BYTES)));
 
 /* Please don't make this stuff initdata!!!  --DaveM */
 static unsigned char boot_cpu_id = 0;
@@ -223,7 +223,6 @@
 {
 	trap_init();
 	init_IRQ();
-	smp_callin();
 	return cpu_idle();
 }
 
@@ -276,7 +275,7 @@
 			init_tasks[cpucount] = p;
 
 			p->processor = i;
-			p->cpus_runnable = 1 << i; /* we schedule the first task manually */
+			p->cpus_runnable = 1UL << i; /* we schedule the first task manually */
 
 			del_from_runqueue(p);
 			unhash_process(p);
@@ -482,7 +481,7 @@
 		__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
 				     : : "r" (pstate));
 
-		if ((stuck & ~(0x5555555555555555UL)) == 0) {
+		if ((dispatch_stat & ~(0x5555555555555555UL)) == 0) {
 			/* Busy bits will not clear, continue instead
 			 * of freezing up on this cpu.
 			 */
@@ -542,6 +541,9 @@
 	int wait;
 };
 
+static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
+static struct call_data_struct *call_data;
+
 extern unsigned long xcall_call_function;
 
 int smp_call_function(void (*func)(void *info), void *info,
@@ -549,6 +551,7 @@
 {
 	struct call_data_struct data;
 	int cpus = smp_num_cpus - 1;
+	long timeout;
 
 	if (!cpus)
 		return 0;
@@ -558,19 +561,36 @@
 	atomic_set(&data.finished, 0);
 	data.wait = wait;
 
-	smp_cross_call(&xcall_call_function,
-		       0, (u64) &data, 0);
+	spin_lock_bh(&call_lock);
+
+	call_data = &data;
+
+	smp_cross_call(&xcall_call_function, 0, 0, 0);
+
 	/* 
 	 * Wait for other cpus to complete function or at
 	 * least snap the call data.
 	 */
-	while (atomic_read(&data.finished) != cpus)
+	timeout = 1000000;
+	while (atomic_read(&data.finished) != cpus) {
+		if (--timeout <= 0)
+			goto out_timeout;
 		barrier();
+		udelay(1);
+	}
+
+	spin_unlock_bh(&call_lock);
+
+	return 0;
 
+out_timeout:
+	spin_unlock_bh(&call_lock);
+	printk("XCALL: Remote cpus not responding, ncpus=%d finished=%d\n",
+	       smp_num_cpus - 1, atomic_read(&data.finished));
 	return 0;
 }
 
-void smp_call_function_client(struct call_data_struct *call_data)
+void smp_call_function_client(void)
 {
 	void (*func) (void *info) = call_data->func;
 	void *info = call_data->info;
@@ -597,7 +617,7 @@
 extern unsigned long xcall_flush_dcache_page_cheetah;
 extern unsigned long xcall_flush_dcache_page_spitfire;
 
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
 extern atomic_t dcpage_flushes;
 extern atomic_t dcpage_flushes_xcall;
 #endif
@@ -620,7 +640,7 @@
 	if (smp_processors_ready) {
 		unsigned long mask = 1UL << cpu;
 
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
 		atomic_inc(&dcpage_flushes);
 #endif
 		if (cpu == smp_processor_id()) {
@@ -642,7 +662,7 @@
 						      __pa(page->virtual),
 						      0, mask);
 			}
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
 			atomic_inc(&dcpage_flushes_xcall);
 #endif
 		}
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- linux-2.4.16/arch/sparc64/kernel/sparc64_ksyms.c	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.116 2001/10/26 15:49:21 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.118 2001/11/17 00:10:48 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -98,7 +98,7 @@
 #ifdef CONFIG_SMP
 extern spinlock_t kernel_flag;
 extern int smp_num_cpus;
-#ifdef SPIN_LOCK_DEBUG
+#ifdef CONFIG_DEBUG_SPINLOCK
 extern void _do_spin_lock (spinlock_t *lock, char *str);
 extern void _do_spin_unlock (spinlock_t *lock);
 extern int _spin_trylock (spinlock_t *lock);
@@ -113,7 +113,7 @@
 
 /* used by various drivers */
 #ifdef CONFIG_SMP
-#ifndef SPIN_LOCK_DEBUG
+#ifndef CONFIG_DEBUG_SPINLOCK
 /* Out of line rw-locking implementation. */
 EXPORT_SYMBOL(__read_lock);
 EXPORT_SYMBOL(__read_unlock);
@@ -145,7 +145,7 @@
 EXPORT_SYMBOL(__cpu_logical_map);
 
 /* Spinlock debugging library, optional. */
-#ifdef SPIN_LOCK_DEBUG
+#ifdef CONFIG_DEBUG_SPINLOCK
 EXPORT_SYMBOL(_do_spin_lock);
 EXPORT_SYMBOL(_do_spin_unlock);
 EXPORT_SYMBOL(_spin_trylock);
@@ -354,4 +354,8 @@
 
 void VISenter(void);
 /* RAID code needs this */
-EXPORT_SYMBOL(VISenter);
+EXPORT_SYMBOL_NOVERS(VISenter);
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+EXPORT_SYMBOL(do_BUG);
+#endif
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/kernel/time.c linux/arch/sparc64/kernel/time.c
--- linux-2.4.16/arch/sparc64/kernel/time.c	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/kernel/time.c	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.40 2001/09/06 02:44:28 davem Exp $
+/* $Id: time.c,v 1.41 2001/11/20 18:24:55 kanoj Exp $
  * time.c: UltraSparc timer and TOD clock support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -609,7 +609,6 @@
 	unsigned long clock;
 
 	init_timers(timer_interrupt, &clock);
-	timer_tick_offset = clock / HZ;
 	timer_ticks_per_usec_quotient = ((1UL<<32) / (clock / 1000020));
 }
 
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/kernel/trampoline.S linux/arch/sparc64/kernel/trampoline.S
--- linux-2.4.16/arch/sparc64/kernel/trampoline.S	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/kernel/trampoline.S	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.22 2001/09/07 21:04:40 kanoj Exp $
+/* $Id: trampoline.S,v 1.24 2001/11/16 21:59:20 davem Exp $
  * trampoline.S: Jump start slave processors on sparc64.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c
--- linux-2.4.16/arch/sparc64/kernel/traps.c	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/kernel/traps.c	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.79 2001/09/21 02:14:39 kanoj Exp $
+/* $Id: traps.c,v 1.82 2001/11/18 00:12:56 davem Exp $
  * arch/sparc64/kernel/traps.c
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -38,16 +38,19 @@
 
 void bad_trap (struct pt_regs *regs, long lvl)
 {
+	char buffer[32];
 	siginfo_t info;
 
 	if (lvl < 0x100) {
-		char buffer[24];
-		
-		sprintf (buffer, "Bad hw trap %lx at tl0\n", lvl);
+		sprintf(buffer, "Bad hw trap %lx at tl0\n", lvl);
+		die_if_kernel(buffer, regs);
+	}
+
+	lvl -= 0x100;
+	if (regs->tstate & TSTATE_PRIV) {
+		sprintf(buffer, "Kernel bad sw trap %lx", lvl);
 		die_if_kernel (buffer, regs);
 	}
-	if (regs->tstate & TSTATE_PRIV)
-		die_if_kernel ("Kernel bad trap", regs);
 	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
@@ -56,7 +59,7 @@
 	info.si_errno = 0;
 	info.si_code = ILL_ILLTRP;
 	info.si_addr = (void *)regs->tpc;
-	info.si_trapno = lvl - 0x100;
+	info.si_trapno = lvl;
 	force_sig_info(SIGILL, &info, current);
 }
 
@@ -68,6 +71,14 @@
 	die_if_kernel (buffer, regs);
 }
 
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+void do_BUG(const char *file, int line)
+{
+	bust_spinlocks(1);
+	printk("kernel BUG at %s:%d!\n", file, line);
+}
+#endif
+
 void instruction_access_exception (struct pt_regs *regs,
 				   unsigned long sfsr, unsigned long sfar)
 {
@@ -947,6 +958,7 @@
 	__asm__ __volatile__("ldxa	[%0] %3, %%g0\n\t"
 			     "ldxa	[%1] %3, %%g0\n\t"
 			     "casxa	[%2] %3, %%g0, %%g0\n\t"
+			     "membar	#StoreLoad | #StoreStore\n\t"
 			     "ldxa	[%0] %3, %%g0\n\t"
 			     "ldxa	[%1] %3, %%g0\n\t"
 			     "membar	#Sync"
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/lib/atomic.S linux/arch/sparc64/lib/atomic.S
--- linux-2.4.16/arch/sparc64/lib/atomic.S	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/lib/atomic.S	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: atomic.S,v 1.3 2000/03/16 16:44:37 davem Exp $
+/* $Id: atomic.S,v 1.4 2001/11/18 00:12:56 davem Exp $
  * atomic.S: These things are too big to do inline.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -19,7 +19,7 @@
 	cas	[%o1], %g5, %g7
 	cmp	%g5, %g7
 	bne,pn	%icc, __atomic_add
-	 nop
+	 membar	#StoreLoad | #StoreStore
 	retl
 	 add	%g7, %o0, %o0
 
@@ -30,7 +30,7 @@
 	cas	[%o1], %g5, %g7
 	cmp	%g5, %g7
 	bne,pn	%icc, __atomic_sub
-	 nop
+	 membar	#StoreLoad | #StoreStore
 	retl
 	 sub	%g7, %o0, %o0
 atomic_impl_end:
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/lib/bitops.S linux/arch/sparc64/lib/bitops.S
--- linux-2.4.16/arch/sparc64/lib/bitops.S	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/lib/bitops.S	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: bitops.S,v 1.2 2001/04/14 01:12:02 davem Exp $
+/* $Id: bitops.S,v 1.3 2001/11/18 00:12:56 davem Exp $
  * bitops.S: Sparc64 atomic bit operations.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -28,7 +28,7 @@
 	bne,a,pn %xcc, 1b
 	 ldx	[%o1], %g7
 2:	retl
-	 nop
+	 membar	#StoreLoad | #StoreStore
 
 	.globl	___test_and_clear_bit
 ___test_and_clear_bit:	/* %o0=nr, %o1=addr */
@@ -47,7 +47,7 @@
 	bne,a,pn %xcc, 1b
 	 ldx	[%o1], %g7
 2:	retl
-	 nop
+	 membar	#StoreLoad | #StoreStore
 
 	.globl	___test_and_change_bit
 ___test_and_change_bit:	/* %o0=nr, %o1=addr */
@@ -65,7 +65,7 @@
 	bne,a,pn %xcc, 1b
 	 ldx	[%o1], %g7
 2:	retl
-	 nop
+	 membar	#StoreLoad | #StoreStore
 	nop
 
 	.globl	___test_and_set_le_bit
@@ -85,7 +85,7 @@
 	bne,a,pn %icc, 1b
 	 lduwa	[%o1] ASI_PL, %g7
 2:	retl
-	 nop
+	 membar	#StoreLoad | #StoreStore
 
 	.globl	___test_and_clear_le_bit
 ___test_and_clear_le_bit:	/* %o0=nr, %o1=addr */
@@ -104,7 +104,7 @@
 	bne,a,pn %icc, 1b
 	 lduwa	[%o1] ASI_PL, %g7
 2:	retl
-	 nop
+	 membar	#StoreLoad | #StoreStore
 
 	.globl	__bitops_end
 __bitops_end:
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/lib/debuglocks.c linux/arch/sparc64/lib/debuglocks.c
--- linux-2.4.16/arch/sparc64/lib/debuglocks.c	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/lib/debuglocks.c	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: debuglocks.c,v 1.6 2001/04/24 01:09:12 davem Exp $
+/* $Id: debuglocks.c,v 1.9 2001/11/17 00:10:48 davem Exp $
  * debuglocks.c: Debugging versions of SMP locking primitives.
  *
  * Copyright (C) 1998 David S. Miller (davem@redhat.com)
@@ -10,10 +10,7 @@
 #include <linux/spinlock.h>
 #include <asm/system.h>
 
-#ifdef CONFIG_SMP
-
-/* To enable this code, just define SPIN_LOCK_DEBUG in asm/spinlock.h */
-#ifdef SPIN_LOCK_DEBUG
+#if defined(CONFIG_SMP) && defined(CONFIG_DEBUG_SPINLOCK)
 
 #define GET_CALLER(PC) __asm__ __volatile__("mov %%i7, %0" : "=r" (PC))
 
@@ -56,6 +53,7 @@
 	unsigned long caller, val;
 	int stuck = INIT_STUCK;
 	int cpu = smp_processor_id();
+	int shown = 0;
 
 	GET_CALLER(caller);
 again:
@@ -67,7 +65,8 @@
 	if (val) {
 		while (lock->lock) {
 			if (!--stuck) {
-				show(str, lock, caller);
+				if (shown++ <= 2)
+					show(str, lock, caller);
 				stuck = INIT_STUCK;
 			}
 			membar("#LoadLoad");
@@ -76,6 +75,8 @@
 	}
 	lock->owner_pc = ((unsigned int)caller);
 	lock->owner_cpu = cpu;
+	current->thread.smp_lock_count++;
+	current->thread.smp_lock_pc = ((unsigned int)caller);
 }
 
 int _spin_trylock(spinlock_t *lock)
@@ -92,6 +93,8 @@
 	if (!val) {
 		lock->owner_pc = ((unsigned int)caller);
 		lock->owner_cpu = cpu;
+		current->thread.smp_lock_count++;
+		current->thread.smp_lock_pc = ((unsigned int)caller);
 	}
 	return val == 0;
 }
@@ -102,6 +105,7 @@
 	lock->owner_cpu = NO_PROC_ID;
 	membar("#StoreStore | #LoadStore");
 	lock->lock = 0;
+	current->thread.smp_lock_count--;
 }
 
 /* Keep INIT_STUCK the same... */
@@ -111,13 +115,15 @@
 	unsigned long caller, val;
 	int stuck = INIT_STUCK;
 	int cpu = smp_processor_id();
+	int shown = 0;
 
 	GET_CALLER(caller);
 wlock_again:
 	/* Wait for any writer to go away.  */
 	while (((long)(rw->lock)) < 0) {
 		if (!--stuck) {
-			show_read(str, rw, caller);
+			if (shown++ <= 2)
+				show_read(str, rw, caller);
 			stuck = INIT_STUCK;
 		}
 		membar("#LoadLoad");
@@ -137,6 +143,8 @@
 	if (val)
 		goto wlock_again;
 	rw->reader_pc[cpu] = ((unsigned int)caller);
+	current->thread.smp_lock_count++;
+	current->thread.smp_lock_pc = ((unsigned int)caller);
 }
 
 void _do_read_unlock (rwlock_t *rw, char *str)
@@ -144,11 +152,13 @@
 	unsigned long caller, val;
 	int stuck = INIT_STUCK;
 	int cpu = smp_processor_id();
+	int shown = 0;
 
 	GET_CALLER(caller);
 
 	/* Drop our identity _first_. */
 	rw->reader_pc[cpu] = 0;
+	current->thread.smp_lock_count--;
 runlock_again:
 	/* Spin trying to decrement the counter using casx.  */
 	__asm__ __volatile__(
@@ -162,7 +172,8 @@
 	: "g5", "g7", "memory");
 	if (val) {
 		if (!--stuck) {
-			show_read(str, rw, caller);
+			if (shown++ <= 2)
+				show_read(str, rw, caller);
 			stuck = INIT_STUCK;
 		}
 		goto runlock_again;
@@ -174,13 +185,15 @@
 	unsigned long caller, val;
 	int stuck = INIT_STUCK;
 	int cpu = smp_processor_id();
+	int shown = 0;
 
 	GET_CALLER(caller);
 wlock_again:
 	/* Spin while there is another writer. */
 	while (((long)rw->lock) < 0) {
 		if (!--stuck) {
-			show_write(str, rw, caller);
+			if (shown++ <= 2)
+				show_write(str, rw, caller);
 			stuck = INIT_STUCK;
 		}
 		membar("#LoadLoad");
@@ -204,7 +217,8 @@
 	if (val) {
 		/* We couldn't get the write bit. */
 		if (!--stuck) {
-			show_write(str, rw, caller);
+			if (shown++ <= 2)
+				show_write(str, rw, caller);
 			stuck = INIT_STUCK;
 		}
 		goto wlock_again;
@@ -214,7 +228,8 @@
 		 * lock, spin, and try again.
 		 */
 		if (!--stuck) {
-			show_write(str, rw, caller);
+			if (shown++ <= 2)
+				show_write(str, rw, caller);
 			stuck = INIT_STUCK;
 		}
 		__asm__ __volatile__(
@@ -231,7 +246,8 @@
 		: "g3", "g5", "g7", "cc", "memory");
 		while(rw->lock != 0) {
 			if (!--stuck) {
-				show_write(str, rw, caller);
+				if (shown++ <= 2)
+					show_write(str, rw, caller);
 				stuck = INIT_STUCK;
 			}
 			membar("#LoadLoad");
@@ -242,18 +258,22 @@
 	/* We have it, say who we are. */
 	rw->writer_pc = ((unsigned int)caller);
 	rw->writer_cpu = cpu;
+	current->thread.smp_lock_count++;
+	current->thread.smp_lock_pc = ((unsigned int)caller);
 }
 
 void _do_write_unlock(rwlock_t *rw)
 {
 	unsigned long caller, val;
 	int stuck = INIT_STUCK;
+	int shown = 0;
 
 	GET_CALLER(caller);
 
 	/* Drop our identity _first_ */
 	rw->writer_pc = 0;
 	rw->writer_cpu = NO_PROC_ID;
+	current->thread.smp_lock_count--;
 wlock_again:
 	__asm__ __volatile__(
 "	mov	1, %%g3\n"
@@ -268,12 +288,21 @@
 	: "g3", "g5", "g7", "memory");
 	if (val) {
 		if (!--stuck) {
-			show_write("write_unlock", rw, caller);
+			if (shown++ <= 2)
+				show_write("write_unlock", rw, caller);
 			stuck = INIT_STUCK;
 		}
 		goto wlock_again;
 	}
 }
 
-#endif /* SPIN_LOCK_DEBUG */
-#endif /* CONFIG_SMP */
+int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+{
+	spin_lock(lock);
+	if (atomic_dec_and_test(atomic))
+		return 1;
+	spin_unlock(lock);
+	return 0;
+}
+
+#endif /* CONFIG_SMP && CONFIG_DEBUG_SPINLOCK */
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/lib/dec_and_lock.S linux/arch/sparc64/lib/dec_and_lock.S
--- linux-2.4.16/arch/sparc64/lib/dec_and_lock.S	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/lib/dec_and_lock.S	Fri Nov 30 13:01:25 2001
@@ -1,10 +1,12 @@
-/* $Id: dec_and_lock.S,v 1.2 2000/08/13 18:24:12 davem Exp $
+/* $Id: dec_and_lock.S,v 1.5 2001/11/18 00:12:56 davem Exp $
  * dec_and_lock.S: Sparc64 version of "atomic_dec_and_lock()"
  *                 using cas and ldstub instructions.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
  */
+#include <linux/config.h>
 
+#ifndef CONFIG_DEBUG_SPINLOCK
 	.text
 	.align	64
 
@@ -34,13 +36,15 @@
 	bne,pn	%icc, loop1
 	 mov	0, %g1
 
-out:	retl
+out:
+	membar	#StoreLoad | #StoreStore
+	retl
 	 mov	%g1, %o0
-to_zero:ldstub	[%o1], %g3
+to_zero:
+	ldstub	[%o1], %g3
 	brnz,pn	%g3, spin_on_lock
 	 membar	#StoreLoad | #StoreStore
 loop2:	cas	[%o0], %g5, %g7		/* ASSERT(g7 == 0) */
-	nop
 	cmp	%g5, %g7
 
 	be,pt	%icc, out
@@ -61,3 +65,5 @@
 	ba,pt	%xcc, to_zero
 	 nop
 	nop
+
+#endif /* !(CONFIG_DEBUG_SPINLOCK) */
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/mm/extable.c linux/arch/sparc64/mm/extable.c
--- linux-2.4.16/arch/sparc64/mm/extable.c	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/mm/extable.c	Fri Nov 30 13:01:25 2001
@@ -11,35 +11,49 @@
 
 static unsigned long
 search_one_table(const struct exception_table_entry *start,
-		 const struct exception_table_entry *last,
+		 const struct exception_table_entry *end,
 		 unsigned long value, unsigned long *g2)
 {
-	const struct exception_table_entry *first = start;
-	const struct exception_table_entry *mid;
-	long diff = 0;
-        while (first <= last) {
-		mid = (last - first) / 2 + first;
-		diff = mid->insn - value;
-                if (diff == 0) {
-                	if (!mid->fixup) {
-                		*g2 = 0;
-                		return (mid + 1)->fixup;
-                	} else
-	                        return mid->fixup;
-                } else if (diff < 0)
-                        first = mid+1;
-                else
-                        last = mid-1;
-        }
-        if (last->insn < value && !last->fixup && last[1].insn > value) {
-        	*g2 = (value - last->insn)/4;
-        	return last[1].fixup;
-        }
-        if (first > start && first[-1].insn < value
-	    && !first[-1].fixup && first->insn < value) {
-        	*g2 = (value - first[-1].insn)/4;
-        	return first->fixup;
-        }
+	const struct exception_table_entry *walk;
+
+	/* Single insn entries are encoded as:
+	 *	word 1:	insn address
+	 *	word 2:	fixup code address
+	 *
+	 * Range entries are encoded as:
+	 *	word 1: first insn address
+	 *	word 2: 0
+	 *	word 3: last insn address + 4 bytes
+	 *	word 4: fixup code address
+	 *
+	 * See asm/uaccess.h for more details.
+	 */
+
+	/* 1. Try to find an exact match. */
+	for (walk = start; walk <= end; walk++) {
+		if (walk->fixup == 0) {
+			/* A range entry, skip both parts. */
+			walk++;
+			continue;
+		}
+
+		if (walk->insn == value)
+			return walk->fixup;
+	}
+
+	/* 2. Try to find a range match. */
+	for (walk = start; walk <= (end - 1); walk++) {
+		if (walk->fixup)
+			continue;
+
+		if (walk[0].insn <= value &&
+		    walk[1].insn > value) {
+			*g2 = (value - walk[0].insn) / 4;
+			return walk[1].fixup;
+		}
+		walk++;
+	}
+
         return 0;
 }
 
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- linux-2.4.16/arch/sparc64/mm/init.c	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/mm/init.c	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.202 2001/11/13 00:49:28 davem Exp $
+/*  $Id: init.c,v 1.205 2001/11/19 19:03:08 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -111,7 +111,7 @@
 
 extern void __update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
 
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
 atomic_t dcpage_flushes = ATOMIC_INIT(0);
 #ifdef CONFIG_SMP
 atomic_t dcpage_flushes_xcall = ATOMIC_INIT(0);
@@ -120,7 +120,7 @@
 
 __inline__ void flush_dcache_page_impl(struct page *page)
 {
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
 	atomic_inc(&dcpage_flushes);
 #endif
 
@@ -152,7 +152,7 @@
 			     "casx	[%2], %%g7, %%g5\n\t"
 			     "cmp	%%g7, %%g5\n\t"
 			     "bne,pn	%%xcc, 1b\n\t"
-			     " nop"
+			     " membar	#StoreLoad | #StoreStore"
 			     : /* no outputs */
 			     : "r" (mask), "r" (non_cpu_bits), "r" (&page->flags)
 			     : "g5", "g7");
@@ -172,7 +172,7 @@
 			     "casx	[%2], %%g7, %%g5\n\t"
 			     "cmp	%%g7, %%g5\n\t"
 			     "bne,pn	%%xcc, 1b\n\t"
-			     " nop\n"
+			     " membar	#StoreLoad | #StoreStore\n"
 			     "2:"
 			     : /* no outputs */
 			     : "r" (cpu), "r" (mask), "r" (&page->flags)
@@ -261,14 +261,14 @@
 	else
 		seq_printf(m, "MMU Type\t: ???\n");
 
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
 	seq_printf(m, "DCPageFlushes\t: %d\n",
 		   atomic_read(&dcpage_flushes));
 #ifdef CONFIG_SMP
 	seq_printf(m, "DCPageFlushesXC\t: %d\n",
 		   atomic_read(&dcpage_flushes_xcall));
 #endif /* CONFIG_SMP */
-#endif /* DCFLUSH_DEBUG */
+#endif /* CONFIG_DEBUG_DCFLUSH */
 }
 
 struct linux_prom_translation {
diff -Nur --exclude=*~ linux-2.4.16/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S
--- linux-2.4.16/arch/sparc64/mm/ultra.S	Mon Nov 26 08:35:04 2001
+++ linux/arch/sparc64/mm/ultra.S	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.68 2001/11/09 14:59:19 davem Exp $
+/* $Id: ultra.S,v 1.69 2001/11/15 10:37:14 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
@@ -679,20 +679,15 @@
 
 	.globl		xcall_call_function
 xcall_call_function:
-	mov		TLB_TAG_ACCESS, %g5		! wheee...
-	stxa		%g1, [%g5] ASI_IMMU		! save call_data here for a bit
-	membar		#Sync
 	rdpr		%pstate, %g2
 	wrpr		%g2, PSTATE_IG | PSTATE_AG, %pstate
-	mov		TLB_TAG_ACCESS, %g2
-	ldxa		[%g2] ASI_IMMU, %g5
 	rdpr		%pil, %g2
 	wrpr		%g0, 15, %pil
 	sethi		%hi(109f), %g7
 	b,pt		%xcc, etrap_irq
 109:	 or		%g7, %lo(109b), %g7
 	call		smp_call_function_client
-	 mov		%l5, %o0
+	 nop
 	b,pt		%xcc, rtrap
 	 clr		%l6
 
diff -Nur --exclude=*~ linux-2.4.16/drivers/atm/idt77252.c linux/drivers/atm/idt77252.c
--- linux-2.4.16/drivers/atm/idt77252.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/atm/idt77252.c	Wed Nov 28 18:54:05 2001
@@ -1,8 +1,8 @@
 /******************************************************************* 
- * ident "$Id: idt77252.c,v 1.2 2001/11/11 08:13:54 ecd Exp $"
+ * ident "$Id: idt77252.c,v 1.3 2001/11/17 00:30:19 ecd Exp $"
  *
  * $Author: ecd $
- * $Date: 2001/11/11 08:13:54 $
+ * $Date: 2001/11/17 00:30:19 $
  *
  * Copyright (c) 2000 ATecoM GmbH 
  *
@@ -30,7 +30,7 @@
  *
  *******************************************************************/
 static char const rcsid[] =
-"$Id: idt77252.c,v 1.2 2001/11/11 08:13:54 ecd Exp $";
+"$Id: idt77252.c,v 1.3 2001/11/17 00:30:19 ecd Exp $";
 
 
 #include <linux/module.h>
diff -Nur --exclude=*~ linux-2.4.16/drivers/block/rd.c linux/drivers/block/rd.c
--- linux-2.4.16/drivers/block/rd.c	Mon Nov 26 08:35:01 2001
+++ linux/drivers/block/rd.c	Wed Nov 28 18:15:57 2001
@@ -110,7 +110,7 @@
  */
 int rd_size = CONFIG_BLK_DEV_RAM_SIZE;		/* Size of the RAM disks */
 /*
- * It would be very desiderable to have a soft-blocksize (that in the case
+ * It would be very desirable to have a soft-blocksize (that in the case
  * of the ramdisk driver is also the hardblocksize ;) of PAGE_SIZE because
  * doing that we'll achieve a far better MM footprint. Using a rd_blocksize of
  * BLOCK_SIZE in the worst case we'll make PAGE_SIZE/BLOCK_SIZE buffer-pages
diff -Nur --exclude=*~ linux-2.4.16/drivers/char/i8k.c linux/drivers/char/i8k.c
--- linux-2.4.16/drivers/char/i8k.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/char/i8k.c	Wed Nov 28 18:15:57 2001
@@ -1,5 +1,7 @@
 /*
- * i8k.c -- Linux driver for accessing the SMM BIOS on Dell I8000 laptops
+ * i8k.c -- Linux driver for accessing the SMM BIOS on Dell laptops.
+ *	    See http://www.debian.org/~dz/i8k/ for more information
+ *	    and for latest version of this driver.
  *
  * Copyright (C) 2001  Massimo Dal Zotto <dz@debian.org>
  *
@@ -19,15 +21,13 @@
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
-#include <asm/io.h>
+#include <linux/apm_bios.h>
 #include <asm/uaccess.h>
+#include <asm/io.h>
 
 #include <linux/i8k.h>
 
-#define I8K_VERSION		"1.1 02/11/2001"
-#define I8K_BIOS_SIGNATURE	"Dell System Inspiron 8000"
-#define I8K_BIOS_SIGNATURE_ADDR 0x000ec000
-#define I8K_BIOS_VERSION_OFFSET	32
+#define I8K_VERSION		"1.7 21/11/2001"
 
 #define I8K_SMM_FN_STATUS	0x0025
 #define I8K_SMM_POWER_STATUS	0x0069
@@ -35,31 +35,47 @@
 #define I8K_SMM_GET_FAN		0x00a3
 #define I8K_SMM_GET_SPEED	0x02a3
 #define I8K_SMM_GET_TEMP	0x10a3
+#define I8K_SMM_GET_DELL_SIG	0xffa3
 #define I8K_SMM_BIOS_VERSION	0x00a6
 
 #define I8K_FAN_MULT		30
 #define I8K_MAX_TEMP		127
 
-#define I8K_FN_NONE		0x08
-#define I8K_FN_UP		0x09
-#define I8K_FN_DOWN		0x0a
-#define I8K_FN_MUTE		0x0c
+#define I8K_FN_NONE		0x00
+#define I8K_FN_UP		0x01
+#define I8K_FN_DOWN		0x02
+#define I8K_FN_MUTE		0x04
+#define I8K_FN_MASK		0x07
+#define I8K_FN_SHIFT		8
 
 #define I8K_POWER_AC		0x05
 #define I8K_POWER_BATTERY	0x01
 
 #define I8K_TEMPERATURE_BUG	1
 
-static char bios_version[4] = "?";
-static char bios_machine_id[16] = "?";
+#define DELL_SIGNATURE		"Dell Computer"
+
+static char *supported_models[] = {
+    "Inspiron",
+    "Latitude",
+    NULL
+};
+
+static char system_vendor[48] = "?";
+static char product_name [48] = "?";
+static char bios_version [4]  = "?";
+static char serial_number[16] = "?";
 
 int force = 0;
+int power_status = 0;
 
 MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
-MODULE_DESCRIPTION("Driver for accessing the SMM BIOS on Dell I8000 laptops");
+MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops");
 MODULE_LICENSE("GPL");
 MODULE_PARM(force, "i");
-MODULE_PARM_DESC(force, "Force loading without checking for an Inspiron 8000");
+MODULE_PARM(power_status, "i");
+MODULE_PARM_DESC(force, "Force loading without checking for supported models");
+MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
 
 static ssize_t i8k_read(struct file *, char *, size_t, loff_t *);
 static int i8k_ioctl(struct inode *, struct file *, unsigned int,
@@ -79,12 +95,19 @@
     unsigned int edi __attribute__ ((packed));
 } SMMRegisters;
 
+typedef struct {
+    u8	type;
+    u8	length;
+    u16	handle;
+} DMIHeader;
+
 /*
- * Call the System Management Mode BIOS.
+ * Call the System Management Mode BIOS. Code provided by Jonathan Buzzard.
  */
 static int i8k_smm(SMMRegisters *regs)
 {
     int rc;
+    int eax = regs->eax;
 
     asm("pushl %%eax\n\t" \
 	"movl 0(%%eax),%%edx\n\t" \
@@ -112,7 +135,7 @@
 	: "a" (regs)
 	: "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
 
-    if ((rc != 0) || ((regs->eax & 0xffff) == 0xffff)) {
+    if ((rc != 0) || ((regs->eax & 0xffff) == 0xffff) || (regs->eax == eax)) {
 	return -EINVAL;
     }
 
@@ -137,11 +160,12 @@
 }
 
 /*
- * Read the machine id. Not yet implemented.
+ * Read the machine id.
  */
-static int i8k_get_machine_id(unsigned char *buff)
+static int i8k_get_serial_number(unsigned char *buff)
 {
-    return -EINVAL;
+    strncpy(buff, serial_number, 16);
+    return 0;
 }
 
 /*
@@ -157,7 +181,7 @@
 	return rc;
     }
 
-    switch ((regs.eax & 0xff00) >> 8) {
+    switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) {
     case I8K_FN_UP:
 	return I8K_VOL_UP;
     case I8K_FN_DOWN:
@@ -281,6 +305,23 @@
     return temp;
 }
 
+static int i8k_get_dell_signature(void)
+{
+    SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
+    int rc;
+
+    regs.eax = I8K_SMM_GET_DELL_SIG;
+    if ((rc=i8k_smm(&regs)) < 0) {
+	return rc;
+    }
+
+    if ((regs.eax == 1145651527) && (regs.edx == 1145392204)) {
+	return 0;
+    } else {
+	return -1;
+    }
+}
+
 static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
 		     unsigned long arg)
 {
@@ -299,7 +340,7 @@
 
     case I8K_MACHINE_ID:
 	memset(buff, 0, 16);
-	val = i8k_get_machine_id(buff);
+	val = i8k_get_serial_number(buff);
 	break;
 
     case I8K_FN_STATUS:
@@ -375,13 +416,17 @@
     int n, fn_key, cpu_temp, ac_power;
     int left_fan, right_fan, left_speed, right_speed;
 
-    cpu_temp    = i8k_get_cpu_temp();
-    left_fan    = i8k_get_fan_status(I8K_FAN_LEFT);
-    right_fan   = i8k_get_fan_status(I8K_FAN_RIGHT);
-    left_speed  = i8k_get_fan_speed(I8K_FAN_LEFT);
-    right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT);
-    ac_power    = i8k_get_power_status();
-    fn_key      = i8k_get_fn_status();
+    cpu_temp     = i8k_get_cpu_temp();			/* 11100 µs */
+    left_fan     = i8k_get_fan_status(I8K_FAN_LEFT);	/*   580 µs */
+    right_fan    = i8k_get_fan_status(I8K_FAN_RIGHT);	/*   580 µs */
+    left_speed   = i8k_get_fan_speed(I8K_FAN_LEFT);	/*   580 µs */
+    right_speed  = i8k_get_fan_speed(I8K_FAN_RIGHT);	/*   580 µs */
+    fn_key       = i8k_get_fn_status();			/*   750 µs */
+    if (power_status) {
+	ac_power = i8k_get_power_status();		/* 14700 µs */
+    } else {
+	ac_power = -1;
+    }
 
     /*
      * Info:
@@ -400,7 +445,7 @@
     n = sprintf(buffer, "%s %s %s %d %d %d %d %d %d %d\n",
 		I8K_PROC_FMT,
 		bios_version,
-		bios_machine_id,
+		serial_number,
 		cpu_temp,
 		left_fan,
 		right_fan,
@@ -438,76 +483,253 @@
     return len;
 }
 
+static char* __init string_trim(char *s, int size)
+{
+    int len;
+    char *p;
+
+    if ((len = strlen(s)) > size) {
+	len = size;
+    }
+
+    for (p=s+len-1; len && (*p==' '); len--,p--) {
+	*p = '\0';
+    }
+
+    return s;
+}
+
+/* DMI code, stolen from arch/i386/kernel/dmi_scan.c */
+
 /*
- * Probe for the presence of an Inspiron I8000.
+ * |<-- dmi->length -->|
+ * |                   |
+ * |dmi header    s=N  | string1,\0, ..., stringN,\0, ..., \0
+ *                |                       |
+ *                +-----------------------+
  */
-static int i8k_probe(void)
+static char* __init dmi_string(DMIHeader *dmi, u8 s)
 {
-    unsigned char *buff, *p;
-    unsigned char bios_vers[4];
-    int version;
+    u8 *p;
+
+    if (!s) {
+	return "";
+    }
+    s--;
+
+    p = (u8 *)dmi + dmi->length;
+    while (s > 0) {
+	p += strlen(p);
+	p++;
+	s--;
+    }
+
+    return p;
+}
+
+static void __init dmi_decode(DMIHeader *dmi)
+{
+    u8 *data = (u8 *) dmi;
+    char *p;
+
+#ifdef I8K_DEBUG
+    int i;
+    printk("%08x ", (int)data);
+    for (i=0; i<data[1] && i<64; i++) {
+	printk("%02x ", data[i]);
+    }
+    printk("\n");
+#endif
+
+    switch (dmi->type) {
+    case  0:	/* BIOS Information */
+	p = dmi_string(dmi,data[5]);
+	if (*p) {
+	    strncpy(bios_version, p, sizeof(bios_version));
+	    string_trim(bios_version, sizeof(bios_version));
+	}
+	break;	
+    case 1:	/* System Information */
+	p = dmi_string(dmi,data[4]);
+	if (*p) {
+	    strncpy(system_vendor, p, sizeof(system_vendor));
+	    string_trim(system_vendor, sizeof(system_vendor));
+	}
+	p = dmi_string(dmi,data[5]);
+	if (*p) {
+	    strncpy(product_name, p, sizeof(product_name));
+	    string_trim(product_name, sizeof(product_name));
+	}
+	p = dmi_string(dmi,data[7]);
+	if (*p) {
+	    strncpy(serial_number, p, sizeof(serial_number));
+	    string_trim(serial_number, sizeof(serial_number));
+	}
+	break;
+    }
+}
+
+static int __init dmi_table(u32 base, int len, int num, void (*fn)(DMIHeader*))
+{
+    u8 *buf;
+    u8 *data;
+    DMIHeader *dmi;
+    int i = 1;
+
+    buf = ioremap(base, len);
+    if (buf == NULL) {
+	return -1;
+    }
+    data = buf;
 
     /*
-     * Until Dell tell us how to reliably check for an Inspiron system
-     * look for a signature at a fixed location in the BIOS memory.
-     * Ugly but safe.
+     * Stop when we see al the items the table claimed to have
+     * or we run off the end of the table (also happens)
      */
-    if (!force) {
-	buff = ioremap(I8K_BIOS_SIGNATURE_ADDR, I8K_BIOS_VERSION_OFFSET+4);
-	if (buff == NULL) {
-	    printk("i8k: ioremap failed\n");
-	    return -ENODEV;
+    while ((i<num) && ((data-buf) < len)) {
+	dmi = (DMIHeader *)data;
+	/*
+	 * Avoid misparsing crud if the length of the last
+	 * record is crap
+	 */
+	if ((data-buf+dmi->length) >= len) {
+	    break;
+	}
+	fn(dmi);
+	data += dmi->length;
+	/*
+	 * Don't go off the end of the data if there is
+	 * stuff looking like string fill past the end
+	 */
+	while (((data-buf) < len) && (*data || data[1])) {
+	    data++;
 	}
-	if (strncmp(buff,I8K_BIOS_SIGNATURE,sizeof(I8K_BIOS_SIGNATURE)) != 0) {
-	    printk("i8k: Inspiron 8000 BIOS signature not found\n");
-	    iounmap(buff);
-	    return -ENODEV;
+	data += 2;
+	i++;
+    }
+    iounmap(buf);
+
+    return 0;
+}
+
+static int __init dmi_iterate(void (*decode)(DMIHeader *))
+{
+    unsigned char buf[20];
+    long fp = 0x000e0000L;
+    fp -= 16;
+
+    while (fp < 0x000fffffL) {
+	fp += 16;
+	isa_memcpy_fromio(buf, fp, 20);
+	if (memcmp(buf, "_DMI_", 5)==0) {
+	    u16 num  = buf[13]<<8  | buf[12];
+	    u16 len  = buf [7]<<8  | buf [6];
+	    u32 base = buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8];
+#ifdef I8K_DEBUG
+	    printk(KERN_INFO "DMI %d.%d present.\n",
+		   buf[14]>>4, buf[14]&0x0F);
+	    printk(KERN_INFO "%d structures occupying %d bytes.\n",
+		   buf[13]<<8 | buf[12],
+		   buf [7]<<8 | buf[6]);
+	    printk(KERN_INFO "DMI table at 0x%08X.\n",
+		   buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8]);
+#endif
+	    if (dmi_table(base, len, num, decode)==0) {
+		return 0;
+	    }
 	}
-	strncpy(bios_vers, buff+I8K_BIOS_VERSION_OFFSET, 3);
-	bios_vers[3] = '\0';
-	iounmap(buff);
-    }
-    if (force >= 2) {
-	buff = ioremap(0x000c0000, 0x00100000-0x000c0000);
-	if (buff == NULL) {
-	    printk("i8k: ioremap failed\n");
+    }
+    return -1;
+}
+/* end of DMI code */
+
+/*
+ * Get DMI information.
+ */
+static int __init i8k_dmi_probe(void)
+{
+    char **p;
+
+    if (dmi_iterate(dmi_decode) != 0) {
+	printk(KERN_INFO "i8k: unable to get DMI information\n");
+	return -ENODEV;
+    }
+
+    if (strncmp(system_vendor,DELL_SIGNATURE,strlen(DELL_SIGNATURE)) != 0) {
+	printk(KERN_INFO "i8k: not running on a Dell system\n");
+	return -ENODEV;
+    }
+
+    for (p=supported_models; ; p++) {
+	if (!*p) {
+	    printk(KERN_INFO "i8k: unsupported model: %s\n", product_name);
 	    return -ENODEV;
 	}
-	for (p=buff; (p-buff)<(0x00100000-0x000c0000); p+=16) {
-	    if (strncmp(p,I8K_BIOS_SIGNATURE,sizeof(I8K_BIOS_SIGNATURE))==0) {
-		printk("i8k: Inspiron 8000 BIOS signature found at %08x\n",
-		       0x000c0000+(p-buff));
-		break;
-	    }
+	if (strncmp(product_name,*p,strlen(*p)) == 0) {
+	    break;
 	}
-	iounmap(buff);
     }
 
+    return 0;
+}
+
+/*
+ * Probe for the presence of a supported laptop.
+ */
+static int __init i8k_probe(void)
+{
+    char buff[4];
+    int version;
+    int smm_found = 0;
+
     /*
-     * Next try to get the BIOS version with an SMM call. If this
-     * fails SMM can't be reliably used on this system.
+     * Get DMI information
      */
-    version = i8k_get_bios_version();
-    if (version <= 0) {
-	printk("i8k: unable to get BIOS version\n");
-	return -ENODEV;
+    if (i8k_dmi_probe() != 0) {
+	printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n",
+	       system_vendor, product_name, bios_version);
     }
-    bios_version[0] = (version >> 16) & 0xff;
-    bios_version[1] = (version >>  8) & 0xff;
-    bios_version[2] = (version)       & 0xff;
-    bios_version[3] = '\0';
 
     /*
-     * Finally check if the two versions match.
+     * Get SMM Dell signature
      */
-    if (!force) {
-	if (strncmp(bios_version,bios_vers,sizeof(bios_version)) != 0) {
-	    printk("i8k: BIOS version mismatch: %s != %s\n",
-		   bios_version, bios_vers);
-	    return -ENODEV;
+    if (i8k_get_dell_signature() != 0) {
+	printk(KERN_INFO "i8k: unable to get SMM Dell signature\n");
+    } else {
+	smm_found = 1;
+    }
+
+    /*
+     * Get SMM BIOS version.
+     */
+    version = i8k_get_bios_version();
+    if (version <= 0) {
+	printk(KERN_INFO "i8k: unable to get SMM BIOS version\n");
+    } else {
+	smm_found = 1;
+	buff[0] = (version >> 16) & 0xff;
+	buff[1] = (version >>  8) & 0xff;
+	buff[2] = (version)       & 0xff;
+	buff[3] = '\0';
+	/*
+	 * If DMI BIOS version is unknown use SMM BIOS version.
+	 */
+	if (bios_version[0] == '?') {
+	    strcpy(bios_version, buff);
+	}
+	/*
+	 * Check if the two versions match.
+	 */
+	if (strncmp(buff,bios_version,sizeof(bios_version)) != 0) {
+	    printk(KERN_INFO "i8k: BIOS version mismatch: %s != %s\n",
+		   buff, bios_version);
 	}
     }
 
+    if (!smm_found && !force) {
+	return -ENODEV;
+    }
+
     return 0;
 }
 
@@ -518,7 +740,7 @@
 {
     struct proc_dir_entry *proc_i8k;
 
-    /* Are we running on an Inspiron 8000 laptop? */
+    /* Are we running on an supported laptop? */
     if (i8k_probe() != 0) {
 	return -ENODEV;
     }
@@ -532,7 +754,7 @@
     SET_MODULE_OWNER(proc_i8k);
 
     printk(KERN_INFO
-	   "Inspiron 8000 SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
+	   "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
 	   I8K_VERSION);
 
     return 0;
diff -Nur --exclude=*~ linux-2.4.16/drivers/char/ip2/i2cmd.c linux/drivers/char/ip2/i2cmd.c
--- linux-2.4.16/drivers/char/ip2/i2cmd.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/char/ip2/i2cmd.c	Fri Nov 30 12:41:48 2001
@@ -139,7 +139,7 @@
 //static UCHAR ct86[]={ 2, BTH,     0x56,0                   }; // RCV_ENABLE
 static UCHAR ct87[] = { 1, BYP,     0x57                     }; // HW_TEST
 //static UCHAR ct88[]={ 3, BTH,     0x58,0,0                 }; // RCV_THRESHOLD
-static UCHAR ct89[]={ 1, BYP,     0x59                     }; // DSS_NOW
+//static UCHAR ct89[]={ 1, BYP,     0x59                     }; // DSS_NOW
 //static UCHAR ct90[]={ 3, BYP,     0x5A,0,0                 }; // Set SILO
 //static UCHAR ct91[]={ 2, BYP,     0x5B,0                   }; // timed break
 
diff -Nur --exclude=*~ linux-2.4.16/drivers/char/ip2/i2ellis.c linux/drivers/char/ip2/i2ellis.c
--- linux-2.4.16/drivers/char/ip2/i2ellis.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/char/ip2/i2ellis.c	Fri Nov 30 12:41:48 2001
@@ -102,6 +102,7 @@
 // This routine performs any required cleanup of the iiEllis subsystem.
 //
 //******************************************************************************
+#if 0 /* Unused */
 static void
 iiEllisCleanup(void)
 {
@@ -109,6 +110,7 @@
 		kfree ( pDelayTimer );
 	}
 }
+#endif
 
 //******************************************************************************
 // Function:   iiSetAddress(pB, address, delay)
diff -Nur --exclude=*~ linux-2.4.16/drivers/char/ip2.c linux/drivers/char/ip2.c
--- linux-2.4.16/drivers/char/ip2.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/char/ip2.c	Fri Nov 30 12:41:48 2001
@@ -33,9 +33,10 @@
 */
 static int io[IP2_MAX_BOARDS]= { 0, 0, 0, 0 };
 static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 }; 
-static int poll_only = 0;
 
 #ifdef MODULE
+
+static int poll_only = 0;
 
 #	if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
 		MODULE_AUTHOR("Doug McNash");
diff -Nur --exclude=*~ linux-2.4.16/drivers/char/pcmcia/serial_cs.c linux/drivers/char/pcmcia/serial_cs.c
--- linux-2.4.16/drivers/char/pcmcia/serial_cs.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/char/pcmcia/serial_cs.c	Fri Nov 30 13:18:53 2001
@@ -2,7 +2,7 @@
 
     A driver for PCMCIA serial devices
 
-    serial_cs.c 1.123 2000/08/24 18:46:38
+    serial_cs.c 1.128 2001/10/18 12:18:35
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -19,8 +19,8 @@
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
-    terms of the GNU General Public License version 2 (the "GPL"), in which
-    case the provisions of the GPL are applicable instead of the
+    terms of the GNU General Public License version 2 (the "GPL"), in
+    which case the provisions of the GPL are applicable instead of the
     above.  If you wish to allow the use of your version of this file
     only under the terms of the GPL and not to allow others to use
     your version of this file under the MPL, indicate your decision
@@ -44,6 +44,7 @@
 #include <linux/major.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/byteorder.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -53,30 +54,32 @@
 #include <pcmcia/ds.h>
 #include <pcmcia/cisreg.h>
 
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"serial_cs.c 1.123 2000/08/24 18:46:38 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
-
 /*====================================================================*/
 
-/* Parameters that can be set with 'insmod' */
+/* Module parameters */
+
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("PCMCIA serial card driver");
+MODULE_LICENSE("Dual MPL/GPL");
+
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
 /* Bit map of interrupts to choose from */
-static u_int irq_mask = 0xdeb8;
+INT_MODULE_PARM(irq_mask, 0xdeb8);
 static int irq_list[4] = { -1 };
+MODULE_PARM(irq_list, "1-4i");
 
 /* Enable the speaker? */
-static int do_sound = 1;
+INT_MODULE_PARM(do_sound, 1);
 
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-4i");
-MODULE_PARM(do_sound, "i");
+#ifdef PCMCIA_DEBUG
+INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"serial_cs.c 1.128 2001/10/18 12:18:35 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
 
 /*====================================================================*/
 
@@ -93,6 +96,8 @@
     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
     { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
+    { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 },
+    { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 },
     { MANFID_SOCKET, PRODID_SOCKET_DUAL_RS232, 2 },
     { MANFID_INTEL, PRODID_INTEL_DUAL_RS232, 2 },
     { MANFID_NATINST, PRODID_NATINST_QUAD_RS232, 4 }
@@ -357,7 +362,6 @@
 
 found_port:
     if (i != CS_SUCCESS) {
-	printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n");
 	cs_error(link->handle, RequestIO, i);
 	return -1;
     }
@@ -437,7 +441,6 @@
     
     i = CardServices(RequestIRQ, link->handle, &link->irq);
     if (i != CS_SUCCESS) {
-	printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n");
 	cs_error(link->handle, RequestIRQ, i);
 	link->irq.AssignedIRQ = 0;
     }
@@ -663,5 +666,3 @@
 
 module_init(init_serial_cs);
 module_exit(exit_serial_cs);
-
-MODULE_LICENSE("GPL");
diff -Nur --exclude=*~ linux-2.4.16/drivers/char/pty.c linux/drivers/char/pty.c
--- linux-2.4.16/drivers/char/pty.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/char/pty.c	Wed Nov 28 18:15:57 2001
@@ -334,8 +334,7 @@
 	/*  Register a slave for the master  */
 	if (tty->driver.major == PTY_MASTER_MAJOR)
 		tty_register_devfs(&tty->link->driver,
-				   DEVFS_FL_CURRENT_OWNER |
-				   DEVFS_FL_NO_PERSISTENCE | DEVFS_FL_WAIT,
+				   DEVFS_FL_CURRENT_OWNER | DEVFS_FL_WAIT,
 				   tty->link->driver.minor_start +
 				   MINOR(tty->device)-tty->driver.minor_start);
 	retval = 0;
diff -Nur --exclude=*~ linux-2.4.16/drivers/char/rtc.c linux/drivers/char/rtc.c
--- linux-2.4.16/drivers/char/rtc.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/char/rtc.c	Fri Nov 30 13:00:57 2001
@@ -785,6 +785,9 @@
 		printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", guess, epoch);
 #endif
 #if RTC_IRQ
+	if (rtc_has_irq == 0)
+		goto no_irq2;
+
 	init_timer(&rtc_irq_timer);
 	rtc_irq_timer.function = rtc_dropped_irq;
 	spin_lock_irq(&rtc_lock);
@@ -792,6 +795,7 @@
 	CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
 	spin_unlock_irq(&rtc_lock);
 	rtc_freq = 1024;
+no_irq2:
 #endif
 
 	printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n");
diff -Nur --exclude=*~ linux-2.4.16/drivers/char/serial.c linux/drivers/char/serial.c
--- linux-2.4.16/drivers/char/serial.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/char/serial.c	Fri Nov 30 13:49:10 2001
@@ -3133,6 +3133,10 @@
  * enables interrupts for a serial port, linking in its async structure into
  * the IRQ chain.   It also performs the serial-specific
  * initialization for the tty structure.
+ *
+ * Note that on failure, we don't decrement the module use count - the tty
+ * later will call rs_close, which will decrement it for us as long as
+ * tty->driver_data is set non-NULL. --rmk
  */
 static int rs_open(struct tty_struct *tty, struct file * filp)
 {
@@ -3153,10 +3157,8 @@
 	}
 	tty->driver_data = info;
 	info->tty = tty;
-	if (serial_paranoia_check(info, tty->device, "rs_open")) {
-		MOD_DEC_USE_COUNT;		
+	if (serial_paranoia_check(info, tty->device, "rs_open"))
 		return -ENODEV;
-	}
 
 #ifdef SERIAL_DEBUG_OPEN
 	printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
@@ -3171,10 +3173,8 @@
 	 */
 	if (!tmp_buf) {
 		page = get_zeroed_page(GFP_KERNEL);
-		if (!page) {
-			MOD_DEC_USE_COUNT;
+		if (!page)
 			return -ENOMEM;
-		}
 		if (tmp_buf)
 			free_page(page);
 		else
@@ -3188,7 +3188,6 @@
 	    (info->flags & ASYNC_CLOSING)) {
 		if (info->flags & ASYNC_CLOSING)
 			interruptible_sleep_on(&info->close_wait);
-		MOD_DEC_USE_COUNT;
 #ifdef SERIAL_DO_RESTART
 		return ((info->flags & ASYNC_HUP_NOTIFY) ?
 			-EAGAIN : -ERESTARTSYS);
@@ -3201,10 +3200,8 @@
 	 * Start up serial port
 	 */
 	retval = startup(info);
-	if (retval) {
-		MOD_DEC_USE_COUNT;
+	if (retval)
 		return retval;
-	}
 
 	retval = block_til_ready(tty, filp, info);
 	if (retval) {
@@ -3212,7 +3209,6 @@
 		printk("rs_open returning after block_til_ready with %d\n",
 		       retval);
 #endif
-		MOD_DEC_USE_COUNT;
 		return retval;
 	}
 
diff -Nur --exclude=*~ linux-2.4.16/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- linux-2.4.16/drivers/char/tty_io.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/char/tty_io.c	Wed Nov 28 18:15:57 2001
@@ -1343,7 +1343,7 @@
 		set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
 		minor -= driver->minor_start;
 		devpts_pty_new(driver->other->name_base + minor, MKDEV(driver->other->major, minor + driver->other->minor_start));
-		tty_register_devfs(&pts_driver[major], DEVFS_FL_NO_PERSISTENCE,
+		tty_register_devfs(&pts_driver[major], DEVFS_FL_DEFAULT,
 				   pts_driver[major].minor_start + minor);
 		noctty = 1;
 		goto init_dev_done;
diff -Nur --exclude=*~ linux-2.4.16/drivers/ieee1394/hosts.c linux/drivers/ieee1394/hosts.c
--- linux-2.4.16/drivers/ieee1394/hosts.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/ieee1394/hosts.c	Fri Nov 30 14:04:55 2001
@@ -170,10 +170,10 @@
 	list_for_each(hlh, &tmpl->hosts) {
 		host = list_entry(hlh, struct hpsb_host, list);
                 if (host->initialized) {
+                        highlevel_remove_host(host);
+
                         host->initialized = 0;
                         abort_requests(host);
-
-                        highlevel_remove_host(host);
 
                         tmpl->release_host(host);
                         while (test_bit(0, &host->timeout_tq.sync)) {
diff -Nur --exclude=*~ linux-2.4.16/drivers/ieee1394/ieee1394_core.c linux/drivers/ieee1394/ieee1394_core.c
--- linux-2.4.16/drivers/ieee1394/ieee1394_core.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/ieee1394/ieee1394_core.c	Fri Nov 30 14:04:55 2001
@@ -318,7 +318,7 @@
 
 void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
 {
-        host->node_id = 0xffc0 | phyid;
+        host->node_id = LOCAL_BUS | phyid;
         host->in_bus_reset = 0;
         host->is_root = isroot;
 
diff -Nur --exclude=*~ linux-2.4.16/drivers/ieee1394/ieee1394_syms.c linux/drivers/ieee1394/ieee1394_syms.c
--- linux-2.4.16/drivers/ieee1394/ieee1394_syms.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/ieee1394/ieee1394_syms.c	Wed Dec 31 21:00:00 1969
@@ -1,88 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Exported symbols for module usage.
- *
- * Copyright (C) 1999 Andreas E. Bombe
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "ieee1394_transactions.h"
-#include "ieee1394_hotplug.h"
-#include "highlevel.h"
-#include "nodemgr.h"
-
-EXPORT_SYMBOL(hpsb_register_lowlevel);
-EXPORT_SYMBOL(hpsb_unregister_lowlevel);
-EXPORT_SYMBOL(hpsb_get_host);
-EXPORT_SYMBOL(hpsb_inc_host_usage);
-EXPORT_SYMBOL(hpsb_dec_host_usage);
-
-EXPORT_SYMBOL(alloc_hpsb_packet);
-EXPORT_SYMBOL(free_hpsb_packet);
-EXPORT_SYMBOL(hpsb_send_packet);
-EXPORT_SYMBOL(hpsb_reset_bus);
-EXPORT_SYMBOL(hpsb_bus_reset);
-EXPORT_SYMBOL(hpsb_selfid_received);
-EXPORT_SYMBOL(hpsb_selfid_complete);
-EXPORT_SYMBOL(hpsb_packet_sent);
-EXPORT_SYMBOL(hpsb_packet_received);
-
-EXPORT_SYMBOL(get_tlabel);
-EXPORT_SYMBOL(free_tlabel);
-EXPORT_SYMBOL(fill_async_readquad);
-EXPORT_SYMBOL(fill_async_readquad_resp);
-EXPORT_SYMBOL(fill_async_readblock);
-EXPORT_SYMBOL(fill_async_readblock_resp);
-EXPORT_SYMBOL(fill_async_writequad);
-EXPORT_SYMBOL(fill_async_writeblock);
-EXPORT_SYMBOL(fill_async_write_resp);
-EXPORT_SYMBOL(fill_async_lock);
-EXPORT_SYMBOL(fill_async_lock_resp);
-EXPORT_SYMBOL(fill_iso_packet);
-EXPORT_SYMBOL(fill_phy_packet);
-EXPORT_SYMBOL(hpsb_make_readqpacket);
-EXPORT_SYMBOL(hpsb_make_readbpacket);
-EXPORT_SYMBOL(hpsb_make_writeqpacket);
-EXPORT_SYMBOL(hpsb_make_writebpacket);
-EXPORT_SYMBOL(hpsb_make_lockpacket);
-EXPORT_SYMBOL(hpsb_make_phypacket);
-EXPORT_SYMBOL(hpsb_packet_success);
-EXPORT_SYMBOL(hpsb_make_packet);
-EXPORT_SYMBOL(hpsb_read);
-EXPORT_SYMBOL(hpsb_write);
-EXPORT_SYMBOL(hpsb_lock);
-
-EXPORT_SYMBOL(hpsb_register_highlevel);
-EXPORT_SYMBOL(hpsb_unregister_highlevel);
-EXPORT_SYMBOL(hpsb_register_addrspace);
-EXPORT_SYMBOL(hpsb_listen_channel);
-EXPORT_SYMBOL(hpsb_unlisten_channel);
-EXPORT_SYMBOL(highlevel_read);
-EXPORT_SYMBOL(highlevel_write);
-EXPORT_SYMBOL(highlevel_lock);
-EXPORT_SYMBOL(highlevel_lock64);
-EXPORT_SYMBOL(highlevel_add_host);
-EXPORT_SYMBOL(highlevel_remove_host);
-EXPORT_SYMBOL(highlevel_host_reset);
-EXPORT_SYMBOL(highlevel_add_one_host);
-
-EXPORT_SYMBOL(hpsb_guid_get_entry);
-EXPORT_SYMBOL(hpsb_nodeid_get_entry);
-EXPORT_SYMBOL(hpsb_get_host_by_ne);
-EXPORT_SYMBOL(hpsb_guid_fill_packet);
-EXPORT_SYMBOL(hpsb_register_protocol);
-EXPORT_SYMBOL(hpsb_unregister_protocol);
-EXPORT_SYMBOL(hpsb_release_unit_directory);
-
-MODULE_LICENSE("GPL");
diff -Nur --exclude=*~ linux-2.4.16/drivers/ieee1394/nodemgr.c linux/drivers/ieee1394/nodemgr.c
--- linux-2.4.16/drivers/ieee1394/nodemgr.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/ieee1394/nodemgr.c	Fri Nov 30 14:04:55 2001
@@ -359,7 +359,7 @@
 	kfree(buf);
 	kfree(envp);
 	if (value != 0)
-		HPSB_DEBUG("NodeMgr: hotplug policy returned 0x%x", value);
+		HPSB_DEBUG("NodeMgr: hotplug policy returned %d", value);
 }
 
 #else
@@ -369,9 +369,8 @@
 {
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
 	HPSB_DEBUG("NodeMgr: nodemgr_call_policy(): hotplug not enabled");
-#else
-	return;
 #endif
+	return;
 } 
 
 #endif /* CONFIG_HOTPLUG */
@@ -582,13 +581,13 @@
                                struct hpsb_host *host, nodeid_t nodeid)
 {
 	struct list_head *lh;
+	struct unit_directory *ud;
 
-	if (ne->nodeid != nodeid)
+	if (ne->nodeid != nodeid) {
 		HPSB_DEBUG("Node " NODE_BUS_FMT " changed to " NODE_BUS_FMT,
 			   NODE_BUS_ARGS(ne->nodeid), NODE_BUS_ARGS(nodeid));
-
-	ne->host = host;
-	ne->nodeid = nodeid;
+		ne->nodeid = nodeid;
+	}
 
 	if (ne->busopt.generation != ((busoptions >> 4) & 0xf))
 		nodemgr_process_config_rom (ne, busoptions);
@@ -597,8 +596,6 @@
 	atomic_set(&ne->generation, get_hpsb_generation(ne->host));
 
 	list_for_each (lh, &ne->unit_directories) {
-		struct unit_directory *ud;
-
 		ud = list_entry (lh, struct unit_directory, node_list);
 		if (ud->driver != NULL && ud->driver->update != NULL)
 			ud->driver->update(ud);
@@ -679,57 +676,76 @@
 	return;
 }
 
+/* Used to schedule each nodes config rom probe */
+struct node_probe_task {
+	nodeid_t nodeid;
+	struct hpsb_host *host;
+	atomic_t *count;
+	struct tq_struct task;
+};
+
 /* This is where we probe the nodes for their information and provided
  * features.  */
-static void nodemgr_node_probe(void *data)
+static void nodemgr_node_probe_one(void *__npt)
 {
-	struct hpsb_host *host = (struct hpsb_host *)data;
-        struct selfid *sid = (struct selfid *)host->topology_map;
-	struct list_head *lh, *next;
+	struct node_probe_task *npt = (struct node_probe_task *)__npt;
 	struct node_entry *ne;
-        int nodecount = host->node_count;
-        nodeid_t nodeid = LOCAL_BUS;
 	quadlet_t buffer[5];
 	octlet_t guid;
-	unsigned long flags;
 
 	/* We need to detect when the ConfigROM's generation has changed,
 	 * so we only update the node's info when it needs to be.  */
-        for (; nodecount; nodecount--, nodeid++, sid++) {
-		/* Skip extended, and non-active node's */
-                while (sid->extended)
-			sid++;
-                if (!sid->link_active)
-			continue;
 
-		if (read_businfo_block (host, nodeid, buffer, sizeof(buffer) >> 2))
-			continue;
+	if (read_businfo_block (npt->host, npt->nodeid, buffer, sizeof(buffer) >> 2))
+		goto probe_complete;
 
-		if (buffer[1] != IEEE1394_BUSID_MAGIC) {
-			/* This isn't a 1394 device */
-			HPSB_ERR("Node " NODE_BUS_FMT " isn't an IEEE 1394 device",
-				 NODE_BUS_ARGS(nodeid));
-			continue;
-		}
+	if (buffer[1] != IEEE1394_BUSID_MAGIC) {
+		/* This isn't a 1394 device */
+		HPSB_ERR("Node " NODE_BUS_FMT " isn't an IEEE 1394 device",
+			 NODE_BUS_ARGS(npt->nodeid));
+		goto probe_complete;
+	}
+
+	guid = ((u64)buffer[3] << 32) | buffer[4];
+	ne = hpsb_guid_get_entry(guid);
+
+	if (!ne)
+		nodemgr_create_node(guid, buffer[2], npt->host, npt->nodeid);
+	else
+		nodemgr_update_node(ne, buffer[2], npt->host, npt->nodeid);
+
+probe_complete:
+	atomic_dec(npt->count);
+
+	kfree(npt);
+
+	return;
+}
 
-		guid = ((u64)buffer[3] << 32) | buffer[4];
-		ne = hpsb_guid_get_entry(guid);
+static void nodemgr_node_probe_cleanup(void *__npt)
+{
+	struct node_probe_task *npt = (struct node_probe_task *)__npt;
+	unsigned long flags;
+	struct list_head *lh, *next;
+	struct node_entry *ne;
+
+	/* If things aren't done yet, reschedule ourselves. */
+        if (atomic_read(npt->count)) {
+                schedule_task(&npt->task);
+		return;
+	}
 
-		if (!ne)
-			nodemgr_create_node(guid, buffer[2], host, nodeid);
-		else
-			nodemgr_update_node(ne, buffer[2], host, nodeid);
-        }
+	kfree(npt->count);
 
 	/* Now check to see if we have any nodes that aren't referenced
 	 * any longer.  */
-        write_lock_irqsave(&node_lock, flags);
+	write_lock_irqsave(&node_lock, flags);
 	for (lh = node_list.next; lh != &node_list; lh = next) {
 		ne = list_entry(lh, struct node_entry, list);
 		next = lh->next;
 
 		/* Only checking this host */
-		if (ne->host != host)
+		if (ne->host != npt->host)
 			continue;
 
 		/* If the generation didn't get updated, then either the
@@ -741,9 +757,70 @@
 	}
 	write_unlock_irqrestore(&node_lock, flags);
 
+	kfree(npt);
+
 	return;
 }
 
+static void nodemgr_node_probe(void *__host)
+{
+	struct hpsb_host *host = (struct hpsb_host *)__host;
+	int nodecount = host->node_count;
+	struct selfid *sid = (struct selfid *)host->topology_map;
+	nodeid_t nodeid = LOCAL_BUS;
+	struct node_probe_task *npt;
+	atomic_t *count;
+
+	count = kmalloc(sizeof (*count), GFP_KERNEL);
+
+	if (count == NULL) {
+		HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe");
+		return;
+	}
+
+	atomic_set(count, 0);
+
+	for (; nodecount; nodecount--, nodeid++, sid++) {
+		while (sid->extended)
+			sid++;
+		if (!sid->link_active || nodeid == host->node_id)
+			continue;
+
+		npt = kmalloc(sizeof (*npt), GFP_KERNEL);
+
+		if (npt == NULL) {
+			HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe");
+			break;
+		}
+
+		INIT_TQUEUE(&npt->task, nodemgr_node_probe_one, npt);
+		npt->host = host;
+		npt->nodeid = nodeid;
+		npt->count = count;
+
+		atomic_inc(count);
+
+		schedule_task(&npt->task);
+	}
+
+	/* Now schedule a task to clean things up after the node probes
+	 * are done.  */
+	npt = kmalloc (sizeof (*npt), GFP_KERNEL);
+
+	if (npt == NULL) {
+		HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe");
+		return;
+	}
+
+	INIT_TQUEUE(&npt->task, nodemgr_node_probe_cleanup, npt);
+	npt->host = host;
+	npt->nodeid = 0;
+	npt->count = count;
+
+	schedule_task(&npt->task);
+
+	return;
+}
 
 struct node_entry *hpsb_guid_get_entry(u64 guid)
 {
@@ -864,7 +941,7 @@
 	write_unlock_irqrestore(&node_lock, flags);
 
 	spin_lock_irqsave (&host_info_lock, flags);
-	list_for_each(lh, &host_info_list) {
+	list_for_each_safe(lh, next, &host_info_list) {
 		struct host_info *hi = list_entry(lh, struct host_info, list);
 		if (hi->host == host) {
 			list_del(&hi->list);
diff -Nur --exclude=*~ linux-2.4.16/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c
--- linux-2.4.16/drivers/ieee1394/ohci1394.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/ieee1394/ohci1394.c	Fri Nov 30 14:04:55 2001
@@ -106,16 +106,12 @@
 #include <linux/init.h>
 
 #ifdef CONFIG_ALL_PPC
-#include <asm/feature.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
 #endif
 
-/* Revert to old bus reset algorithm that works on my Pismo until
- * the new one is fixed
- */
-#undef BUSRESET_WORKAROUND
-
 #include "ieee1394.h"
 #include "ieee1394_types.h"
 #include "hosts.h"
@@ -175,7 +171,7 @@
 MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl);
 
 static char version[] __devinitdata =
-	"v0.51 08/08/01 Ben Collins <bcollins@debian.org>";
+	"$Revision: 1.80 $ Ben Collins <bcollins@debian.org>";
 
 /* Module Parameters */
 MODULE_PARM(attempt_root,"i");
@@ -516,12 +512,9 @@
 	/* After enabling LPS, we need to wait for the connection
 	 * between phy and link to be established.  This should be
 	 * signaled by the LPS bit becoming 1, but this happens
-	 * immediately.  Instead we wait for reads from LinkControl to
-	 * give a valid result, i.e. not 0xffffffff. */
-	while (reg_read(ohci, OHCI1394_LinkControlSet) == 0xffffffff) {
-		DBGMSG(ohci->id, "waiting for phy-link connection");
-		mdelay(2);
-	}
+	 * immediately.  There seems to be no consistent way to wait
+	 * for this, but 50ms seems to be enough. */
+	mdelay(50);
 
 	/* Set the bus number */
 	reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
@@ -1131,11 +1124,7 @@
 	 * selfIDComplete interrupt. */
 	spin_lock_irqsave(&ohci->event_lock, flags);
 	event = reg_read(ohci, OHCI1394_IntEventClear);
-#ifdef BUSRESET_WORKAROUND
-	reg_write(ohci, OHCI1394_IntEventClear, event);
-#else
 	reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset);
-#endif
 	spin_unlock_irqrestore(&ohci->event_lock, flags);
 
 	if (!event) return;
@@ -1154,11 +1143,17 @@
 		 * selfID phase, so we disable busReset interrupts, to
 		 * avoid burying the cpu in interrupt requests. */
 		spin_lock_irqsave(&ohci->event_lock, flags);
-#ifdef BUSRESET_WORKAROUND
-		reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
-#else
   		reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset);
-#endif		
+		if (ohci->dev->vendor == PCI_VENDOR_ID_APPLE && 
+		    ohci->dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) {
+  			udelay(10);
+  			while(reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) {
+  				reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
+				spin_unlock_irqrestore(&ohci->event_lock, flags);
+	  			udelay(10);
+				spin_lock_irqsave(&ohci->event_lock, flags);
+  			}
+  		}
 		spin_unlock_irqrestore(&ohci->event_lock, flags);
 		if (!host->in_bus_reset) {
 			DBGMSG(ohci->id, "irq_handler: Bus reset requested%s",
@@ -1309,12 +1304,10 @@
 
 		/* Finally, we clear the busReset event and reenable
 		 * the busReset interrupt. */
-#ifndef BUSRESET_WORKAROUND
 		spin_lock_irqsave(&ohci->event_lock, flags);
 		reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); 
 		reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
 		spin_unlock_irqrestore(&ohci->event_lock, flags);
-#endif
 		event &= ~OHCI1394_selfIDComplete;	
 	}
 
@@ -1966,8 +1959,6 @@
 	cf_put_keyval(&cr, 0x03, 0x00005e);	/* Vendor ID */
 	cf_put_refer(&cr, 0x81, 2);		/* Textual description unit */
 	cf_put_keyval(&cr, 0x0c, 0x0083c0);	/* Node capabilities */
-	cf_put_refer(&cr, 0xd1, 3);		/* IPv4 unit directory */
-	cf_put_refer(&cr, 0xd1, 4);		/* IPv6 unit directory */
 	/* NOTE: Add other unit referers here, and append at bottom */
 	cf_unit_end(&cr);
 
@@ -1980,46 +1971,6 @@
 	cf_put_4bytes(&cr, '9', '4', 0x0, 0x0);
 	cf_unit_end(&cr);
 
-	/* IPv4 unit directory, RFC 2734 */
-	cf_unit_begin(&cr, 3);
-	cf_put_keyval(&cr, 0x12, 0x00005e);	/* Unit spec ID */
-	cf_put_refer(&cr, 0x81, 6);		/* Textual description unit */
-	cf_put_keyval(&cr, 0x13, 0x000001);	/* Unit software version */
-	cf_put_refer(&cr, 0x81, 7);		/* Textual description unit */
-	cf_unit_end(&cr);
-
-	cf_unit_begin(&cr, 6);
-	cf_put_keyval(&cr, 0, 0);
-	cf_put_1quad(&cr, 0);
-	cf_put_4bytes(&cr, 'I', 'A', 'N', 'A');
-	cf_unit_end(&cr);
-
-	cf_unit_begin(&cr, 7);
-	cf_put_keyval(&cr, 0, 0);
-	cf_put_1quad(&cr, 0);
-	cf_put_4bytes(&cr, 'I', 'P', 'v', '4');
-	cf_unit_end(&cr);
-
-	/* IPv6 unit directory, draft-ietf-ipngwg-1394-01.txt */
-	cf_unit_begin(&cr, 4);
-	cf_put_keyval(&cr, 0x12, 0x00005e);	/* Unit spec ID */
-	cf_put_refer(&cr, 0x81, 8);		/* Textual description unit */
-	cf_put_keyval(&cr, 0x13, 0x000002);	/* (Proposed) Unit software version */
-	cf_put_refer(&cr, 0x81, 9);		/* Textual description unit */
-	cf_unit_end(&cr);
-
-	cf_unit_begin(&cr, 8);
-	cf_put_keyval(&cr, 0, 0);
-	cf_put_1quad(&cr, 0);
-	cf_put_4bytes(&cr, 'I', 'A', 'N', 'A');
-	cf_unit_end(&cr);
-
-	cf_unit_begin(&cr, 9);
-	cf_put_keyval(&cr, 0, 0);
-	cf_put_1quad(&cr, 0);
-	cf_put_4bytes(&cr, 'I', 'P', 'v', '6');
-	cf_unit_end(&cr);
-
 	ohci->csr_config_rom_length = cr.data - ohci->csr_config_rom_cpu;
 }
 
@@ -2309,8 +2260,8 @@
 
 		of_node = pci_device_to_OF_node(ohci->dev);
 		if (of_node) {
-			feature_set_firewire_power(of_node, 0);
-			feature_set_firewire_cable_power(of_node, 0);
+			pmac_call_feature(PMAC_FTR_1394_ENABLE, of_node, 0, 0);
+			pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, of_node, 0, 0);
 		}
 	}
 #endif /* CONFIG_ALL_PPC */
diff -Nur --exclude=*~ linux-2.4.16/drivers/ieee1394/pcilynx.c linux/drivers/ieee1394/pcilynx.c
--- linux-2.4.16/drivers/ieee1394/pcilynx.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/ieee1394/pcilynx.c	Fri Nov 30 14:04:55 2001
@@ -1637,8 +1637,8 @@
 
 static void __exit pcilynx_cleanup(void)
 {
-        pci_unregister_driver(&lynx_pcidriver);
         hpsb_unregister_lowlevel(&lynx_template);
+	pci_unregister_driver(&lynx_pcidriver);
         PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module");
 }
 
diff -Nur --exclude=*~ linux-2.4.16/drivers/ieee1394/sbp2.c linux/drivers/ieee1394/sbp2.c
--- linux-2.4.16/drivers/ieee1394/sbp2.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/ieee1394/sbp2.c	Fri Nov 30 14:04:55 2001
@@ -222,8 +222,25 @@
  *                 when we register our driver.  This change 
  *                 automtically adds hotplug support to the driver.
  *                                 Kristian Hogsberg <hogsberg@users.sf.net>
+ *
+ *      11/17/01 - Various bugfixes/cleanups:
+ *                 * Remember to logout of device in sbp2_disconnect.
+ *                 * If we fail to reconnect to a device after bus reset
+ *                   remember to release unit directory, so the ieee1394
+ *                   knows we no longer manage it.
+ *                 * Unregister scsi hosts in sbp2_remove_host when a
+ *                   hpsb_host goes away.
+ *                 * Remove stupid hack in sbp2_remove_host.
+ *                 * Switched to "manual" module initialization
+ *                   (i.e. not scsi_module.c) and moved sbp2_cleanup
+ *                   moved sbp2scsi_release to sbp2_module_ext.  The
+ *                   release function is called once pr. registered
+ *                   scsi host, but sbp2_cleanup should only be called
+ *                   upon module unload.  Moved much initialization
+ *                   from sbp2scsi_detect to sbp2_module_init.
+ *                                 Kristian Hogsberg <hogsberg@users.sf.net>
  */
-    
+
 
 
 /*
@@ -244,6 +261,7 @@
 #include <linux/proc_fs.h>
 #include <linux/blk.h>
 #include <linux/smp_lock.h>
+#include <linux/init.h>
 #include <asm/current.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -395,7 +413,7 @@
  * Globals
  */
 
-Scsi_Host_Template *global_scsi_tpnt = NULL;
+static Scsi_Host_Template scsi_driver_template;
 
 static u8 sbp2_speedto_maxrec[] = { 0x7, 0x8, 0x9 };
 
@@ -671,13 +689,13 @@
 static void sbp2util_remove_command_orb_pool(struct scsi_id_instance_data *scsi_id,
 					     struct sbp2scsi_host_info *hi)
 {
-	struct list_head *lh;
+	struct list_head *lh, *next;
 	struct sbp2_command_info *command;
 	unsigned long flags;
         
 	sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags);
 	if (!list_empty(&scsi_id->sbp2_command_orb_completed)) {
-		list_for_each(lh, &scsi_id->sbp2_command_orb_completed) {
+		list_for_each_safe(lh, next, &scsi_id->sbp2_command_orb_completed) {
 			command = list_entry(lh, struct sbp2_command_info, list);
 
 			/* Release our generic DMA's */
@@ -868,7 +886,6 @@
 		hpsb_unregister_highlevel(sbp2_hl_handle);
 		sbp2_hl_handle = NULL;
 	}
-	return;
 }
 
 static int sbp2_probe(struct unit_directory *ud)
@@ -889,8 +906,10 @@
 	SBP2_DEBUG("sbp2_disconnect");
 	hi = sbp2_find_host_info(ud->ne->host);
 
-	if (hi != NULL)
-		sbp2_remove_device(hi, scsi_id);
+	if (hi != NULL) {
+		sbp2_logout_device(hi, scsi_id);
+ 		sbp2_remove_device(hi, scsi_id);
+	}
 }
 
 static void sbp2_update(struct unit_directory *ud)
@@ -909,12 +928,10 @@
 		 */
 		if (sbp2_login_device(hi, scsi_id)) {
 
-			/* Login failed too... so, just mark him as
-			 * unvalidated, so that he gets cleaned up
-			 * later.
-			 */
+			/* Login failed too, just remove the device. */
 			SBP2_ERR("sbp2_reconnect_device failed!");
 			sbp2_remove_device(hi, scsi_id);
+			hpsb_release_unit_directory(ud);
 			return;
 		}
 	}
@@ -978,7 +995,10 @@
 	sbp2_spin_unlock(&sbp2_host_info_lock, flags);
 
 	/* Register our host with the SCSI stack. */
-	sbp2scsi_register_scsi_host(hi);
+	hi->scsi_host = scsi_register (&scsi_driver_template, sizeof(void *));
+	if (hi->scsi_host)
+		hi->scsi_host->hostdata[0] = (unsigned long)hi;
+	scsi_driver_template.present++;
 
 	return;
 }
@@ -1003,13 +1023,12 @@
 }
 
 /*
- * This function is called when the host is removed
+ * This function is called when a host is removed.
  */
 static void sbp2_remove_host(struct hpsb_host *host)
 {
 	struct sbp2scsi_host_info *hi;
 	unsigned long flags;
-	int i;
 
 	SBP2_DEBUG("sbp2_remove_host");
 
@@ -1017,22 +1036,11 @@
 
 	hi = sbp2_find_host_info(host);
 	if (hi != NULL) {
-		/* Here's an annoying hack: we get a disconnect
-		 * callback for each device, so this loop shouldn't be
-		 * necessary.  However, the sbp2 driver receives the
-		 * remove_host callback before the nodemgr, so when we
-		 * get the disconnect callback, we've already freed
-		 * the host.  Thus, we free the devices here...
-		 */
-		for (i = 0; i < SBP2SCSI_MAX_SCSI_IDS; i++) {
-			if (hi->scsi_id[i] != NULL) {
-				sbp2_logout_device(hi, hi->scsi_id[i]);
-				sbp2_remove_device(hi, hi->scsi_id[i]);
-			}
-		}
 		sbp2util_remove_request_packet_pool(hi);
 		sbp2_host_count--;
 		list_del(&hi->list);
+		scsi_unregister(hi->scsi_host);
+		scsi_driver_template.present--;
 		kfree(hi);
 	}
 	else
@@ -1203,10 +1211,7 @@
 	 */
 	if (sbp2_login_device(hi, scsi_id)) {
 
-		/*
-		 * Login failed... so, just mark him as unvalidated, so
-		 * that he gets cleaned up later.
-		 */
+		/* Login failed, just remove the device. */
 		SBP2_ERR("sbp2_login_device failed");
 		sbp2_remove_device(hi, scsi_id);
 		return -EBUSY;
@@ -1231,11 +1236,13 @@
 }
 
 /*
- * This function removes (cleans-up after) any unvalidated sbp2 devices
+ * This function removes an sbp2 device from the sbp2scsi_host_info struct.
  */
 static void sbp2_remove_device(struct sbp2scsi_host_info *hi, 
 			       struct scsi_id_instance_data *scsi_id)
 {
+	SBP2_DEBUG("sbp2_remove_device");
+
 	/* Complete any pending commands with selection timeout */
 	sbp2scsi_complete_all_commands(hi, scsi_id, DID_NO_CONNECT);
        			
@@ -1276,8 +1283,7 @@
 		SBP2_DMA_FREE("single logout orb");
 	}
 
-	SBP2_DEBUG("Unvalidated SBP-2 device removed, SCSI ID = %d", 
-		   scsi_id->id);
+	SBP2_DEBUG("SBP-2 device removed, SCSI ID = %d", scsi_id->id);
 	hi->scsi_id[scsi_id->id] = NULL;
 	kfree(scsi_id);
 }
@@ -1381,7 +1387,7 @@
 
 	/*
 	 * Check status
-	 */				       
+	 */
 	if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) ||
 	    STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||
 	    STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {
@@ -1687,9 +1693,9 @@
 	scsi_id->max_payload_size = min(sbp2_speedto_maxrec[scsi_id->speed_code],
 					(u8)(((be32_to_cpu(hi->host->csr.rom[2]) >> 12) & 0xf) - 1));
 
-	SBP2_ERR("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [0x%02x/%u]",
+	SBP2_ERR("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [%u]",
 		 NODE_BUS_ARGS(scsi_id->ne->nodeid), hpsb_speedto_str[scsi_id->speed_code],
-		 scsi_id->max_payload_size, 1 << ((u32)scsi_id->max_payload_size + 2));
+		 1 << ((u32)scsi_id->max_payload_size + 2));
 
 	return(0);
 }
@@ -2860,127 +2866,111 @@
 	return(0);
 }
 
-/*
- * This routine is called at setup (init) and does nothing. Not used here.   =)
- */
-void sbp2scsi_setup( char *str, int *ints) 
-{
-	SBP2_DEBUG("sbp2scsi_setup");
-	return;
-}
-
-/*
- * This is our detection routine, and is where we init everything.
- */
 static int sbp2scsi_detect (Scsi_Host_Template *tpnt) 
 {
 	SBP2_DEBUG("sbp2scsi_detect");
 
-	global_scsi_tpnt = tpnt;
+	/*
+	 * Call sbp2_init to register with the ieee1394 stack.  This
+	 * results in a callback to sbp2_add_host for each ieee1394
+	 * host controller currently registered, and for each of those
+	 * we register a scsi host with the scsi stack.
+	 */
+	sbp2_init();
+
+	/* We return the number of hosts registered. */
+	return sbp2_host_count;
+}
+
+MODULE_AUTHOR("James Goodwin <jamesg@filanet.com>");
+MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver");
+MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME);
+MODULE_LICENSE("GPL");
+
+/* SCSI host template */
+static Scsi_Host_Template scsi_driver_template = {
+	name:		"IEEE-1394 SBP-2 protocol driver",
+	detect:		sbp2scsi_detect,
+	queuecommand:	sbp2scsi_queuecommand,
+	abort:		sbp2scsi_abort,
+	reset:		sbp2scsi_reset,
+	bios_param:	sbp2scsi_biosparam,
+	can_queue:	SBP2SCSI_MAX_OUTSTANDING_CMDS,
+	this_id:	-1,
+	sg_tablesize:	SBP2_MAX_SG_ELEMENTS,
+	cmd_per_lun:	SBP2SCSI_MAX_CMDS_PER_LUN,
+	use_clustering:	SBP2_CLUSTERING,
+	emulated:	1,
+
+	module:         THIS_MODULE,
+
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,26)
-	global_scsi_tpnt->proc_name = SBP2_DEVICE_NAME;
+	proc_name: SBP2_DEVICE_NAME
 #endif
+};
+
+static int sbp2_module_init(void)
+{
+	SBP2_DEBUG("sbp2_module_init");
+
 	/*
 	 * Module load option for force one command at a time
 	 */
 	if (serialize_io) {
 		SBP2_ERR("Driver forced to serialize I/O (serialize_io = 1)");
-		global_scsi_tpnt->can_queue = 1;
-		global_scsi_tpnt->cmd_per_lun = 1;
+		scsi_driver_template.can_queue = 1;
+		scsi_driver_template.cmd_per_lun = 1;
 	}
 
 	/*
-	 * Module load option to limit max size of requests from the scsi drivers
+	 * Module load option to limit max size of requests from the
+	 * scsi drivers
 	 */
 	if (no_large_packets) {
-		SBP2_ERR("Driver forced to limit max transfer size (no_large_packets = 1)");
-		global_scsi_tpnt->sg_tablesize = 0x1f;
-		global_scsi_tpnt->use_clustering = DISABLE_CLUSTERING;
+		SBP2_ERR("Driver forced to limit max transfer size "
+			 "(no_large_packets = 1)");
+		scsi_driver_template.sg_tablesize = 0x1f;
+		scsi_driver_template.use_clustering = DISABLE_CLUSTERING;
 	}
 
 	if (mode_sense_hack) {
 		SBP2_ERR("Mode sense emulation enabled (mode_sense_hack = 1)");
 	}
 
-	sbp2_init();
-
-	if (!sbp2_host_count) {
-		SBP2_ERR("Please load the lower level IEEE-1394 driver (e.g. ohci1394) before sbp2...");
+	/*
+	 * Ideally we would register our scsi_driver_template with the
+	 * scsi stack and after that register with the ieee1394 stack
+	 * and process the add_host callbacks.  However, the detect
+	 * function in the scsi host template requires that we find at
+	 * least one host, so we "nest" the registrations by calling
+	 * sbp2_init from the detect function.
+	 */
+	if (scsi_register_module(MODULE_SCSI_HA, &scsi_driver_template) ||
+	    !scsi_driver_template.present) {
+		SBP2_ERR("Please load the lower level IEEE-1394 driver "
+			 "(e.g. ohci1394) before sbp2...");
 		sbp2_cleanup();
+		return -ENODEV;
 	}
 
-	/*
-	 * Since we are returning this count, it means that sbp2 must be
-	 * loaded "after" the host adapter module...
-	 */
-	return(sbp2_host_count);
+	return 0;
 }
 
-/*
- * This function is called from sbp2_add_host, and is where we register
- * our scsi host
- */
-static void sbp2scsi_register_scsi_host(struct sbp2scsi_host_info *hi)
+static void __exit sbp2_module_exit(void)
 {
-	struct Scsi_Host *shpnt = NULL;
-
-	SBP2_DEBUG("sbp2scsi_register_scsi_host");
-	SBP2_DEBUG("sbp2scsi_host_info = %p", hi);
+	SBP2_DEBUG("sbp2_module_exit");
 
 	/*
-	 * Let's register with the scsi stack
+	 * On module unload we unregister with the ieee1394 stack
+	 * which results in remove_host callbacks for all ieee1394
+	 * host controllers.  In the callbacks we unregister the
+	 * corresponding scsi hosts.
 	 */
-	if (global_scsi_tpnt) {
-
-		shpnt = scsi_register (global_scsi_tpnt, sizeof(void *));
-
-		/*
-		 * If successful, save off a context (to be used when SCSI
-		 * commands are received)
-		 */
-		if (shpnt) {
-			shpnt->hostdata[0] = (unsigned long)hi;
-		}
-	}
-
-	return;
-}
-
-/* Called when our module is released */
-static int sbp2scsi_release(struct Scsi_Host *host)
-{
-	SBP2_DEBUG("sbp2scsi_release");
 	sbp2_cleanup();
-	return(0);
-}
 
-/* Called for contents of procfs */
-static const char *sbp2scsi_info (struct Scsi_Host *host)
-{
-	return "IEEE-1394 SBP-2 protocol driver";
+	if (scsi_unregister_module(MODULE_SCSI_HA, &scsi_driver_template))
+		SBP2_ERR("sbp2_module_exit: couldn't unregister scsi driver");
 }
 
-MODULE_AUTHOR("James Goodwin <jamesg@filanet.com>");
-MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver");
-MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME);
-MODULE_LICENSE("GPL");
-
-/* SCSI host template */
-static Scsi_Host_Template driver_template = {
-	name:		"IEEE1394 SBP-2",
-	detect:		sbp2scsi_detect,
-	release:	sbp2scsi_release,
-	info:		sbp2scsi_info,
-	queuecommand:	sbp2scsi_queuecommand,
-	abort:		sbp2scsi_abort,
-	reset:		sbp2scsi_reset,
-	bios_param:	sbp2scsi_biosparam,
-	can_queue:	SBP2SCSI_MAX_OUTSTANDING_CMDS,
-	this_id:	-1,
-	sg_tablesize:	SBP2_MAX_SG_ELEMENTS,
-	cmd_per_lun:	SBP2SCSI_MAX_CMDS_PER_LUN,
-	use_clustering:	SBP2_CLUSTERING,
-	emulated:	1
-};
-
-#include "../scsi/scsi_module.c"
+module_init(sbp2_module_init);
+module_exit(sbp2_module_exit);
diff -Nur --exclude=*~ linux-2.4.16/drivers/ieee1394/sbp2.h linux/drivers/ieee1394/sbp2.h
--- linux-2.4.16/drivers/ieee1394/sbp2.h	Mon Nov 26 08:35:03 2001
+++ linux/drivers/ieee1394/sbp2.h	Fri Nov 30 14:04:55 2001
@@ -403,6 +403,13 @@
 	spinlock_t sbp2_request_packet_lock;
 
 	/*
+	 * This is the scsi host we register with the scsi mid level.
+	 * We keep a reference to it here, so we can unregister it
+	 * when the hpsb_host is removed.
+	 */
+	struct Scsi_Host *scsi_host;
+
+	/*
 	 * Lists keeping track of inuse/free sbp2_request_packets. These structures are
 	 * used for sending out sbp2 command and agent reset packets. We initially create
 	 * a pool of request packets so that we don't have to do any kmallocs while in critical
@@ -498,7 +505,6 @@
 /*
  * Scsi interface related prototypes
  */
-static const char *sbp2scsi_info (struct Scsi_Host *host);
 static int sbp2scsi_detect (Scsi_Host_Template *tpnt);
 void sbp2scsi_setup(char *str, int *ints);
 static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]);
@@ -509,6 +515,5 @@
 					   u32 status);
 static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, 
 				      u32 scsi_status, Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
-static void sbp2scsi_register_scsi_host(struct sbp2scsi_host_info *hi);
 
 #endif /* SBP2_H */
diff -Nur --exclude=*~ linux-2.4.16/drivers/ieee1394/video1394.c linux/drivers/ieee1394/video1394.c
--- linux-2.4.16/drivers/ieee1394/video1394.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/ieee1394/video1394.c	Fri Nov 30 14:04:55 2001
@@ -47,6 +47,8 @@
 #include <linux/types.h>
 #include <linux/wrapper.h>
 #include <linux/vmalloc.h>
+#include <linux/timex.h>
+#include <linux/mm.h>
 
 #include "ieee1394.h"
 #include "ieee1394_types.h"
@@ -95,6 +97,7 @@
         struct dma_cmd **ir_prg;
 	struct it_dma_prg **it_prg;
 	unsigned int *buffer_status;
+        struct timeval *buffer_time; /* time when the buffer was received */
 	unsigned int *last_used_cmd; /* For ISO Transmit with 
 					variable sized packets only ! */
 	int ctrlClear;
@@ -102,8 +105,8 @@
 	int cmdPtr;
 	int ctxMatch;
 	wait_queue_head_t waitq;
-        spinlock_t lock;
-    unsigned int syt_offset;
+	spinlock_t lock;
+	unsigned int syt_offset;
 	int flags;
 };
 
@@ -304,6 +307,8 @@
 
 	if ((*d)->buffer_status)
 		kfree((*d)->buffer_status);
+	if ((*d)->buffer_time)
+		kfree((*d)->buffer_time);
 	if ((*d)->last_used_cmd)
 		kfree((*d)->last_used_cmd);
 	if ((*d)->next_buffer)
@@ -437,6 +442,8 @@
 
 	d->buffer_status = kmalloc(d->num_desc * sizeof(unsigned int),
 				   GFP_KERNEL);
+	d->buffer_time = kmalloc(d->num_desc * sizeof(struct timeval),
+				   GFP_KERNEL);
 	d->last_used_cmd = kmalloc(d->num_desc * sizeof(unsigned int),
 				   GFP_KERNEL);
 	d->next_buffer = kmalloc(d->num_desc * sizeof(int),
@@ -447,6 +454,11 @@
 		free_dma_iso_ctx(&d);
 		return NULL;
 	}
+	if (d->buffer_time == NULL) {
+		PRINT(KERN_ERR, ohci->id, "Failed to allocate buffer_time");
+		free_dma_iso_ctx(&d);
+		return NULL;
+	}
 	if (d->last_used_cmd == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate last_used_cmd");
 		free_dma_iso_ctx(&d);
@@ -458,6 +470,7 @@
 		return NULL;
 	}
 	memset(d->buffer_status, 0, d->num_desc * sizeof(unsigned int));
+	memset(d->buffer_time, 0, d->num_desc * sizeof(struct timeval));
 	memset(d->last_used_cmd, 0, d->num_desc * sizeof(unsigned int));
 	memset(d->next_buffer, -1, d->num_desc * sizeof(int));
 	
@@ -604,6 +617,7 @@
 		if (d->ir_prg[i][d->nb_cmd-1].status & 0xFFFF0000) {
 			reset_ir_status(d, i);
 			d->buffer_status[i] = VIDEO1394_BUFFER_READY;
+			get_fast_time(&d->buffer_time[i]);
 		}
 	}
 	spin_unlock(&d->lock);
@@ -876,9 +890,23 @@
 
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
 			return -EFAULT;
+
+		/* if channel < 0, find lowest available one */
+		if (v.channel < 0) {
+		    mask = (u64)0x1;
+		    for (i=0; i<ISO_CHANNELS; i++) {
+			if (!(ohci->ISO_channel_usage & mask)) {
+			    v.channel = i;
+			    PRINT(KERN_INFO, ohci->id, "Found free channel %d\n", i);
+			    break;
+			}
+			mask = mask << 1;
+		    }
+		}
+		    
 		if (v.channel<0 || v.channel>(ISO_CHANNELS-1)) {
 			PRINT(KERN_ERR, ohci->id, 
-			      "Iso channel %d out of bound", v.channel);
+			      "Iso channel %d out of bounds", v.channel);
 			return -EFAULT;
 		}
 		mask = (u64)0x1<<v.channel;
@@ -1092,6 +1120,7 @@
 		
 	}
 	case VIDEO1394_LISTEN_WAIT_BUFFER:
+	case VIDEO1394_LISTEN_POLL_BUFFER:
 	{
 		struct video1394_wait v;
 		struct dma_iso_ctx *d;
@@ -1120,6 +1149,12 @@
 			d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
 			break;
 		case VIDEO1394_BUFFER_QUEUED:
+			if (cmd == VIDEO1394_LISTEN_POLL_BUFFER) {
+			    /* for polling, return error code EINTR */
+			    spin_unlock_irqrestore(&d->lock, flags);
+			    return -EINTR;
+			}
+
 #if 1
 			while(d->buffer_status[v.buffer]!=
 			      VIDEO1394_BUFFER_READY) {
@@ -1147,6 +1182,10 @@
 			return -EFAULT;
 		}
 
+		/* set time of buffer */
+		v.filltime = d->buffer_time[v.buffer];
+//		printk("Buffer %d time %d\n", v.buffer, (d->buffer_time[v.buffer]).tv_usec);
+
 		/*
 		 * Look ahead to see how many more buffers have been received
 		 */
@@ -1596,7 +1635,8 @@
 {
 	struct ti_ohci *ohci;
 	unsigned long flags;
-	struct list_head *lh;
+	struct list_head *lh, *next;
+	struct video_card *p;
 
 	/* We only work with the OHCI-1394 driver */
 	if (strcmp(host->template->name, OHCI1394_DRIVER_NAME))
@@ -1605,14 +1645,11 @@
 	ohci = (struct ti_ohci *)host->hostdata;
 
         spin_lock_irqsave(&video1394_cards_lock, flags);
-	if (!list_empty(&video1394_cards)) {
-		struct video_card *p;
-		list_for_each(lh, &video1394_cards) {
-			p = list_entry(lh, struct video_card, list);
-			if (p ->ohci == ohci) {
-				remove_card(p);
-				break;
-			}
+	list_for_each_safe(lh, next, &video1394_cards) {
+		p = list_entry(lh, struct video_card, list);
+		if (p->ohci == ohci) {
+			remove_card(p);
+			break;
 		}
 	}
 	spin_unlock_irqrestore(&video1394_cards_lock, flags);
@@ -1652,7 +1689,7 @@
 	devfs_unregister(devfs_handle);
 	devfs_unregister_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME);
 
-	PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module\n");
+	PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module");
 }
 
 static int __init video1394_init_module (void)
@@ -1678,6 +1715,7 @@
 		return -ENOMEM;
 	}
 
+	PRINT_G(KERN_INFO, "Installed " VIDEO1394_DRIVER_NAME " module");
 	return 0;
 }
 
diff -Nur --exclude=*~ linux-2.4.16/drivers/ieee1394/video1394.h linux/drivers/ieee1394/video1394.h
--- linux-2.4.16/drivers/ieee1394/video1394.h	Mon Nov 26 08:35:03 2001
+++ linux/drivers/ieee1394/video1394.h	Fri Nov 30 14:04:55 2001
@@ -35,11 +35,12 @@
 	VIDEO1394_LISTEN_CHANNEL = 0,
 	VIDEO1394_UNLISTEN_CHANNEL,
 	VIDEO1394_LISTEN_QUEUE_BUFFER,
-	VIDEO1394_LISTEN_WAIT_BUFFER,
+	VIDEO1394_LISTEN_WAIT_BUFFER,  // wait until buffer is ready
 	VIDEO1394_TALK_CHANNEL,
 	VIDEO1394_UNTALK_CHANNEL,
 	VIDEO1394_TALK_QUEUE_BUFFER,
-	VIDEO1394_TALK_WAIT_BUFFER
+	VIDEO1394_TALK_WAIT_BUFFER,
+	VIDEO1394_LISTEN_POLL_BUFFER   // return immediately with -EINTR if not ready
 };
 
 #define VIDEO1394_SYNC_FRAMES          0x00000001
@@ -47,7 +48,7 @@
 #define VIDEO1394_VARIABLE_PACKET_SIZE 0x00000004
 
 struct video1394_mmap {
-	unsigned int channel;
+	int channel;			/* -1 to find an open channel in LISTEN/TALK */
 	unsigned int sync_tag;
 	unsigned int nb_buffers;
 	unsigned int buf_size;
@@ -69,6 +70,7 @@
 struct video1394_wait {
 	unsigned int channel;
 	unsigned int buffer;
+	struct timeval filltime;	/* time of buffer full */
 };
 
 
diff -Nur --exclude=*~ linux-2.4.16/drivers/md/lvm-snap.c linux/drivers/md/lvm-snap.c
--- linux-2.4.16/drivers/md/lvm-snap.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/md/lvm-snap.c	Fri Nov 30 12:42:36 2001
@@ -542,8 +542,6 @@
 
 void lvm_snapshot_release(lv_t * lv)
 {
-	int 	nbhs = KIO_MAX_SECTORS;
-
 	if (lv->lv_block_exception)
 	{
 		vfree(lv->lv_block_exception);
diff -Nur --exclude=*~ linux-2.4.16/drivers/media/video/Config.in linux/drivers/media/video/Config.in
--- linux-2.4.16/drivers/media/video/Config.in	Mon Nov 26 08:35:03 2001
+++ linux/drivers/media/video/Config.in	Fri Nov 30 13:04:36 2001
@@ -22,10 +22,8 @@
    fi
 fi
 if [ "$CONFIG_PARPORT" != "n" ]; then
-   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      if [ "$CONFIG_PARPORT_1284" != "n" ]; then
-         dep_tristate '  Winbond W9966CF Webcam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_W9966 $CONFIG_VIDEO_DEV $CONFIG_PARPORT
-      fi
+   if [ "$CONFIG_PARPORT_1284" != "n" ]; then
+      dep_tristate '  W9966CF Webcam (FlyCam Supra and others) Video For Linux' CONFIG_VIDEO_W9966 $CONFIG_VIDEO_DEV $CONFIG_PARPORT
    fi
 fi
 dep_tristate '  CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV
diff -Nur --exclude=*~ linux-2.4.16/drivers/media/video/w9966.c linux/drivers/media/video/w9966.c
--- linux-2.4.16/drivers/media/video/w9966.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/media/video/w9966.c	Fri Nov 30 13:04:36 2001
@@ -1,9 +1,7 @@
 /*
 	Winbond w9966cf Webcam parport driver.
 
-	Version 0.32
-
-	Copyright (C) 2001 Jakob Kemi <jakob.kemi@post.utfors.se>
+	Copyright (C) 2001 Jakob Kemi <jakob.kemi@telia.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
@@ -21,33 +19,16 @@
 */
 /*
 	Supported devices:
-	*Lifeview FlyCam Supra (using the Philips saa7111a chip)
-
-	Does any other model using the w9966 interface chip exist ?
+	  * Lifeview FlyCam Supra (using the Philips saa7111a chip)
 
 	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
+	  * Add a working EPP mode
+	  * Support other ccd-control chips than the saa7111
+	    (what combinations exists?)
+	  * Add proper probing. IEEE1284 probing of w9966 chips haven't
+	    worked since parport drivers changed in 2.4.x.
+	  * Probe for onboard SRAM, port directions etc. (if possible)
 
-	Please support me by sending feedback!
-	
 	Changes:
 	
 	Alan Cox:	Removed RGB mode for kernel merge, added THIS_MODULE
@@ -59,6 +40,8 @@
 #include <linux/delay.h>
 #include <linux/videodev.h>
 #include <linux/parport.h>
+#include <linux/types.h>
+#include <linux/slab.h>
 
 //#define DEBUG				// Undef me for production
 
@@ -99,43 +82,44 @@
 #define W9966_I2C_W_CLOCK	0x01
 
 struct w9966_dev {
-	unsigned char dev_state;
-	unsigned char i2c_state;
-	unsigned short ppmode;
+	u8 dev_state;
+	u8 i2c_state;
+	int 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;
+	u16 width;
+	u16 height;
+	u8 brightness;
+	s8 contrast;
+	s8 color;
+	s8 hue;
+	u8* buffer;
 };
 
 /*
  *	Module specific properties
  */
 
-MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>");
-MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)");
+MODULE_AUTHOR("Jakob Kemi <jakob.kemi@telia.com>");
+MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (FlyCam Supra and others)");
 MODULE_LICENSE("GPL");
 
 
-#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 const char* pardev[] = {[0 ... W9966_MAXCAMS] = "auto"};
+MODULE_PARM(pardev, "0-" __MODULE_STRING(W9966_MAXCAMS) "s");
+MODULE_PARM_DESC(pardev,"\n\
+<auto|name|none[,...]> Where to find cameras.\n\
+  auto = probe all parports for camera\n\
+  name = name of parport (eg parport0)\n\
+  none = don't search for this camera\n\
+You can specify all cameras this way, for example:
+  pardev=parport2,auto,none,parport0 would search for cam1 on parport2, search\n\
+  for cam2 on all parports, skip cam3 and search for cam4 on parport0");
 
 static int parmode = 0;
 MODULE_PARM(parmode, "i");
-MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp");
+MODULE_PARM_DESC(parmode, "\n<0|1|2> transfer mode (0=auto, 1=ecp, 2=epp)");
 
 static int video_nr = -1;
 MODULE_PARM(video_nr, "i");
@@ -277,17 +261,23 @@
 	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 if (port->modes & PARPORT_MODE_EPP)
+			cam->ppmode = IEEE1284_MODE_EPP;*/
 		else
-			cam->ppmode = IEEE1284_MODE_ECP;
+			cam->ppmode = IEEE1284_MODE_ECPSWE;
 		break;	
 	case 1:		// hw- or sw-ecp
-		cam->ppmode = IEEE1284_MODE_ECP;
+		if (port->modes & PARPORT_MODE_ECP)
+			cam->ppmode = IEEE1284_MODE_ECP;
+		else
+			cam->ppmode = IEEE1284_MODE_ECPSWE;
 		break;
 	case 2:		// hw- or sw-epp
-		cam->ppmode = IEEE1284_MODE_EPP;
-	break;
+		if (port->modes & PARPORT_MODE_EPP)
+			cam->ppmode = IEEE1284_MODE_EPP;
+		else
+			cam->ppmode = IEEE1284_MODE_EPPSWE;
+		break;
 	}
 	
 // Tell the parport driver that we exists
@@ -325,6 +315,8 @@
 	
 	w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
 	
+	cam->buffer = NULL;
+	
 	// All ok
 	printk(
 		"w9966cf: Found and initialized a webcam on %s.\n",
@@ -337,6 +329,12 @@
 // Terminate everything gracefully
 static void w9966_term(struct w9966_dev* cam)
 {
+// Delete allocated buffer if needed
+	if (cam->buffer != NULL) {
+		kfree(cam->buffer);
+		cam->buffer = NULL;
+	}
+
 // Unregister from v4l
 	if (w9966_getState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) {
 		video_unregister_device(&cam->vdev);
@@ -431,9 +429,9 @@
 {
 	unsigned int i;
 	unsigned int enh_s, enh_e;
-	unsigned char scale_x, scale_y;
-	unsigned char regs[0x1c];
-	unsigned char saa7111_regs[] = {
+	u8 scale_x, scale_y;
+	u8 regs[0x1c];
+	u8 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,
@@ -664,6 +662,7 @@
 	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)
@@ -693,11 +692,23 @@
 
 static int w9966_v4l_open(struct video_device *vdev, int flags)
 {
+	struct w9966_dev *cam = (struct w9966_dev*)vdev->priv;
+	cam->buffer = (u8*)kmalloc(W9966_RBUFFER, GFP_KERNEL);
+	
+	if (cam->buffer == NULL)
+		return -EFAULT;
+
 	return 0;
 }
 
 static void w9966_v4l_close(struct video_device *vdev)
 {
+	struct w9966_dev *cam = (struct w9966_dev*)vdev->priv;
+	
+	if (cam->buffer != NULL) {
+		kfree(cam->buffer);
+		cam->buffer = NULL;
+	}
 }
 
 static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
@@ -920,13 +931,12 @@
 	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) {
+		if (parport_read(cam->pport, cam->buffer, tsize) < tsize) {
 			w9966_pdev_release(cam);
 			return -EFAULT;
 		}
-		if (copy_to_user(dest, tbuf, tsize) != 0) {
+		if (copy_to_user(dest, cam->buffer, tsize) != 0) {
 			w9966_pdev_release(cam);
 			return -EFAULT;
 		}
@@ -948,14 +958,14 @@
 	
 	for (i = 0; i < W9966_MAXCAMS; i++)
 	{
+		if (strcmp(pardev[i], "none") == 0)	// Skip if 'none'
+			continue;
 		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 (strcmp(pardev[i], "auto") == 0 ||
+		    strcmp(pardev[i], port->name) == 0) {
 			if (w9966_init(&w9966_cams[i], port) != 0)
-			w9966_term(&w9966_cams[i]);
+				w9966_term(&w9966_cams[i]);
 			break;	// return
 		}
 	}
diff -Nur --exclude=*~ linux-2.4.16/drivers/net/bonding.c linux/drivers/net/bonding.c
--- linux-2.4.16/drivers/net/bonding.c	Mon Nov 26 08:35:01 2001
+++ linux/drivers/net/bonding.c	Wed Nov 28 18:47:22 2001
@@ -185,7 +185,6 @@
 
 #include <linux/if_bonding.h>
 #include <linux/smp.h>
-#include <limits.h>
 #include <linux/if_ether.h>
 #include <linux/if_arp.h>
 
diff -Nur --exclude=*~ linux-2.4.16/drivers/net/irda/vlsi_ir.c linux/drivers/net/irda/vlsi_ir.c
--- linux-2.4.16/drivers/net/irda/vlsi_ir.c	Mon Nov 26 08:35:01 2001
+++ linux/drivers/net/irda/vlsi_ir.c	Fri Nov 30 18:28:15 2001
@@ -2,7 +2,7 @@
  *
  *	vlsi_ir.c:	VLSI82C147 PCI IrDA controller driver for Linux
  *
- *	Version:	0.3, Sep 30, 2001
+ *	Version:	0.3a, Nov 10, 2001
  *
  *	Copyright (c) 2001 Martin Diehl
  *
@@ -490,7 +490,7 @@
 	if (mode == IFF_FIR)
 		config ^= IRENABLE_FIR_ON;
 	else if (mode == IFF_MIR)
-		config ^= (IRENABLE_FIR_ON|IRENABLE_CRC16_ON);
+		config ^= (IRENABLE_MIR_ON|IRENABLE_CRC16_ON);
 	else
 		config ^= IRENABLE_SIR_ON;
 
@@ -877,6 +877,7 @@
 	idev->irlap = irlap_open(ndev,&idev->qos,hwname);
 
 	netif_start_queue(ndev);
+	outw(0, ndev->base_addr+VLSI_PIO_PROMPT);	/* kick hw state machine */
 
 	printk(KERN_INFO "%s: device %s operational using (%d,%d) tx,rx-ring\n",
 		__FUNCTION__, ndev->name, ringsize[0], ringsize[1]);
@@ -1200,7 +1201,6 @@
 	int			alloc_size;
 
 
-	vlsi_reg_debug(0x3000, "vlsi initial state");
 	if (pci_enable_device(pdev))
 		goto out;
 
diff -Nur --exclude=*~ linux-2.4.16/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in
--- linux-2.4.16/drivers/net/pcmcia/Config.in	Mon Nov 26 08:35:01 2001
+++ linux/drivers/net/pcmcia/Config.in	Fri Nov 30 13:18:53 2001
@@ -11,10 +11,10 @@
    dep_tristate '  3Com 3c574 PCMCIA support' CONFIG_PCMCIA_3C574 $CONFIG_PCMCIA
    dep_tristate '  Fujitsu FMV-J18x PCMCIA support' CONFIG_PCMCIA_FMVJ18X $CONFIG_PCMCIA
    dep_tristate '  NE2000 compatible PCMCIA support' CONFIG_PCMCIA_PCNET $CONFIG_PCMCIA
+   dep_tristate '  Asix AX88190 PCMCIA support' CONFIG_PCMCIA_AXNET $CONFIG_PCMCIA
    dep_tristate '  New Media PCMCIA support' CONFIG_PCMCIA_NMCLAN $CONFIG_PCMCIA
    dep_tristate '  SMC 91Cxx PCMCIA support' CONFIG_PCMCIA_SMC91C92 $CONFIG_PCMCIA
    dep_tristate '  Xircom 16-bit PCMCIA support' CONFIG_PCMCIA_XIRC2PS $CONFIG_PCMCIA
-   dep_tristate '  broken NS8390-cards support' CONFIG_PCMCIA_AXNET $CONFIG_PCMCIA
    dep_tristate '  COM20020 ARCnet PCMCIA support' CONFIG_ARCNET_COM20020_CS $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET $CONFIG_PCMCIA
    if [ "$CONFIG_IBMTR" != "y" ]; then
       dep_tristate '  IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA
diff -Nur --exclude=*~ linux-2.4.16/drivers/net/pcmcia/ax8390.h linux/drivers/net/pcmcia/ax8390.h
--- linux-2.4.16/drivers/net/pcmcia/ax8390.h	Mon Nov 26 08:35:01 2001
+++ linux/drivers/net/pcmcia/ax8390.h	Wed Dec 31 21:00:00 1969
@@ -1,193 +0,0 @@
-/* Generic NS8390 register definitions. */
-/* This file is part of Donald Becker's 8390 drivers, and is distributed
-   under the same license. Auto-loading of 8390.o only in v2.2 - Paul G.
-   Some of these names and comments originated from the Crynwr
-   packet drivers, which are distributed under the GPL. */
-
-#ifndef _8390_h
-#define _8390_h
-
-#include <linux/config.h>
-#include <linux/if_ether.h>
-#include <linux/ioport.h>
-#include <linux/skbuff.h>
-
-#define TX_2X_PAGES 12
-#define TX_1X_PAGES 6
-
-/* Should always use two Tx slots to get back-to-back transmits. */
-#define EI_PINGPONG
-
-#ifdef EI_PINGPONG
-#define TX_PAGES TX_2X_PAGES
-#else
-#define TX_PAGES TX_1X_PAGES
-#endif
-
-#define ETHER_ADDR_LEN 6
-
-/* The 8390 specific per-packet-header format. */
-struct e8390_pkt_hdr {
-  unsigned char status; /* status */
-  unsigned char next;   /* pointer to next packet. */
-  unsigned short count; /* header + packet length in bytes */
-};
-
-#ifdef notdef
-extern int ei_debug;
-#else
-#define ei_debug 1
-#endif
-
-#ifndef HAVE_AUTOIRQ
-/* From auto_irq.c */
-extern void autoirq_setup(int waittime);
-extern unsigned long autoirq_report(int waittime);
-#endif
-
-static int ethdev_init(struct net_device *dev);
-static void NS8390_init(struct net_device *dev, int startp);
-static int ei_open(struct net_device *dev);
-static int ei_close(struct net_device *dev);
-static void ei_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-
-/* Most of these entries should be in 'struct net_device' (or most of the
-   things in there should be here!) */
-/* You have one of these per-board */
-struct ei_device {
-	const char *name;
-	void (*reset_8390)(struct net_device *);
-	void (*get_8390_hdr)(struct net_device *, struct e8390_pkt_hdr *, int);
-	void (*block_output)(struct net_device *, int, const unsigned char *, int);
-	void (*block_input)(struct net_device *, int, struct sk_buff *, int);
-	unsigned char mcfilter[8];
-	unsigned open:1;
-	unsigned word16:1;  		/* We have the 16-bit (vs 8-bit) version of the card. */
-	unsigned txing:1;		/* Transmit Active */
-	unsigned irqlock:1;		/* 8390's intrs disabled when '1'. */
-	unsigned dmaing:1;		/* Remote DMA Active */
-	unsigned char tx_start_page, rx_start_page, stop_page;
-	unsigned char current_page;	/* Read pointer in buffer  */
-	unsigned char interface_num;	/* Net port (AUI, 10bT.) to use. */
-	unsigned char txqueue;		/* Tx Packet buffer queue length. */
-	short tx1, tx2;			/* Packet lengths for ping-pong tx. */
-	short lasttx;			/* Alpha version consistency check. */
-	unsigned char reg0;		/* Register '0' in a WD8013 */
-	unsigned char reg5;		/* Register '5' in a WD8013 */
-	unsigned char saved_irq;	/* Original dev->irq value. */
-	struct net_device_stats stat;	/* The new statistics table. */
-	u32 *reg_offset;		/* Register mapping table */
-	spinlock_t page_lock;		/* Page register locks */
-	unsigned long priv;		/* Private field to store bus IDs etc. */
-};
-
-/* The maximum number of 8390 interrupt service routines called per IRQ. */
-#define MAX_SERVICE 12
-
-/* The maximum time waited (in jiffies) before assuming a Tx failed. (20ms) */
-#define TX_TIMEOUT (20*HZ/100)
-
-#define ei_status (*(struct ei_device *)(dev->priv))
-
-/* Some generic ethernet register configurations. */
-#define E8390_TX_IRQ_MASK	0xa	/* For register EN0_ISR */
-#define E8390_RX_IRQ_MASK	0x5
-#define E8390_RXCONFIG		0x44	/* EN0_RXCR: broadcasts, no multicast,errors */
-#define E8390_RXOFF		0x20	/* EN0_RXCR: Accept no packets */
-#define E8390_TXCONFIG		0x00	/* EN0_TXCR: Normal transmit mode */
-#define E8390_TXOFF		0x02	/* EN0_TXCR: Transmitter off */
-
-/*  Register accessed at EN_CMD, the 8390 base addr.  */
-#define E8390_STOP	0x01	/* Stop and reset the chip */
-#define E8390_START	0x02	/* Start the chip, clear reset */
-#define E8390_TRANS	0x04	/* Transmit a frame */
-#define E8390_RREAD	0x08	/* Remote read */
-#define E8390_RWRITE	0x10	/* Remote write  */
-#define E8390_NODMA	0x20	/* Remote DMA */
-#define E8390_PAGE0	0x00	/* Select page chip registers */
-#define E8390_PAGE1	0x40	/* using the two high-order bits */
-#define E8390_PAGE2	0x80	/* Page 3 is invalid. */
-
-/*
- *	Only generate indirect loads given a machine that needs them.
- */
- 
-#if defined(CONFIG_MAC) || defined(CONFIG_AMIGA_PCMCIA) || \
-    defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE) || \
-    defined(CONFIG_HYDRA) || defined(CONFIG_HYDRA_MODULE)
-#define EI_SHIFT(x)	(ei_local->reg_offset[x])
-#else
-#define EI_SHIFT(x)	(x)
-#endif
-
-#define E8390_CMD	EI_SHIFT(0x00)  /* The command register (for all pages) */
-/* Page 0 register offsets. */
-#define EN0_CLDALO	EI_SHIFT(0x01)	/* Low byte of current local dma addr  RD */
-#define EN0_STARTPG	EI_SHIFT(0x01)	/* Starting page of ring bfr WR */
-#define EN0_CLDAHI	EI_SHIFT(0x02)	/* High byte of current local dma addr  RD */
-#define EN0_STOPPG	EI_SHIFT(0x02)	/* Ending page +1 of ring bfr WR */
-#define EN0_BOUNDARY	EI_SHIFT(0x03)	/* Boundary page of ring bfr RD WR */
-#define EN0_TSR		EI_SHIFT(0x04)	/* Transmit status reg RD */
-#define EN0_TPSR	EI_SHIFT(0x04)	/* Transmit starting page WR */
-#define EN0_NCR		EI_SHIFT(0x05)	/* Number of collision reg RD */
-#define EN0_TCNTLO	EI_SHIFT(0x05)	/* Low  byte of tx byte count WR */
-#define EN0_FIFO	EI_SHIFT(0x06)	/* FIFO RD */
-#define EN0_TCNTHI	EI_SHIFT(0x06)	/* High byte of tx byte count WR */
-#define EN0_ISR		EI_SHIFT(0x07)	/* Interrupt status reg RD WR */
-#define EN0_CRDALO	EI_SHIFT(0x08)	/* low byte of current remote dma address RD */
-#define EN0_RSARLO	EI_SHIFT(0x08)	/* Remote start address reg 0 */
-#define EN0_CRDAHI	EI_SHIFT(0x09)	/* high byte, current remote dma address RD */
-#define EN0_RSARHI	EI_SHIFT(0x09)	/* Remote start address reg 1 */
-#define EN0_RCNTLO	EI_SHIFT(0x0a)	/* Remote byte count reg WR */
-#define EN0_RCNTHI	EI_SHIFT(0x0b)	/* Remote byte count reg WR */
-#define EN0_RSR		EI_SHIFT(0x0c)	/* rx status reg RD */
-#define EN0_RXCR	EI_SHIFT(0x0c)	/* RX configuration reg WR */
-#define EN0_TXCR	EI_SHIFT(0x0d)	/* TX configuration reg WR */
-#define EN0_COUNTER0	EI_SHIFT(0x0d)	/* Rcv alignment error counter RD */
-#define EN0_DCFG	EI_SHIFT(0x0e)	/* Data configuration reg WR */
-#define EN0_COUNTER1	EI_SHIFT(0x0e)	/* Rcv CRC error counter RD */
-#define EN0_IMR		EI_SHIFT(0x0f)	/* Interrupt mask reg WR */
-#define EN0_COUNTER2	EI_SHIFT(0x0f)	/* Rcv missed frame error counter RD */
-
-/* Bits in EN0_ISR - Interrupt status register */
-#define ENISR_RX	0x01	/* Receiver, no error */
-#define ENISR_TX	0x02	/* Transmitter, no error */
-#define ENISR_RX_ERR	0x04	/* Receiver, with error */
-#define ENISR_TX_ERR	0x08	/* Transmitter, with error */
-#define ENISR_OVER	0x10	/* Receiver overwrote the ring */
-#define ENISR_COUNTERS	0x20	/* Counters need emptying */
-#define ENISR_RDC	0x40	/* remote dma complete */
-#define ENISR_RESET	0x80	/* Reset completed */
-#define ENISR_ALL	0x3f	/* Interrupts we will enable */
-
-/* Bits in EN0_DCFG - Data config register */
-#define ENDCFG_WTS	0x01	/* word transfer mode selection */
-
-/* Page 1 register offsets. */
-#define EN1_PHYS   EI_SHIFT(0x01)	/* This board's physical enet addr RD WR */
-#define EN1_PHYS_SHIFT(i)  EI_SHIFT(i+1) /* Get and set mac address */
-#define EN1_CURPAG EI_SHIFT(0x07)	/* Current memory page RD WR */
-#define EN1_MULT   EI_SHIFT(0x08)	/* Multicast filter mask array (8 bytes) RD WR */
-#define EN1_MULT_SHIFT(i)  EI_SHIFT(8+i) /* Get and set multicast filter */
-
-/* Bits in received packet status byte and EN0_RSR*/
-#define ENRSR_RXOK	0x01	/* Received a good packet */
-#define ENRSR_CRC	0x02	/* CRC error */
-#define ENRSR_FAE	0x04	/* frame alignment error */
-#define ENRSR_FO	0x08	/* FIFO overrun */
-#define ENRSR_MPA	0x10	/* missed pkt */
-#define ENRSR_PHY	0x20	/* physical/multicast address */
-#define ENRSR_DIS	0x40	/* receiver disable. set in monitor mode */
-#define ENRSR_DEF	0x80	/* deferring */
-
-/* Transmitted packet status, EN0_TSR. */
-#define ENTSR_PTX 0x01	/* Packet transmitted without error */
-#define ENTSR_ND  0x02	/* The transmit wasn't deferred. */
-#define ENTSR_COL 0x04	/* The transmit collided at least once. */
-#define ENTSR_ABT 0x08  /* The transmit collided 16 times, and was deferred. */
-#define ENTSR_CRS 0x10	/* The carrier sense was lost. */
-#define ENTSR_FU  0x20  /* A "FIFO underrun" occurred during transmit. */
-#define ENTSR_CDH 0x40	/* The collision detect "heartbeat" signal was lost. */
-#define ENTSR_OWC 0x80  /* There was an out-of-window collision. */
-
-#endif /* _8390_h */
diff -Nur --exclude=*~ linux-2.4.16/drivers/net/pcmcia/axnet_cs.c linux/drivers/net/pcmcia/axnet_cs.c
--- linux-2.4.16/drivers/net/pcmcia/axnet_cs.c	Mon Nov 26 08:35:01 2001
+++ linux/drivers/net/pcmcia/axnet_cs.c	Fri Nov 30 13:18:53 2001
@@ -11,7 +11,7 @@
 
     Copyright (C) 2001 David A. Hinds -- dahinds@users.sourceforge.net
 
-    axnet_cs.c 1.11 2001/06/12 12:42:40
+    axnet_cs.c 1.24 2001/11/18 02:46:51
     
     The network driver code is based on Donald Becker's NE2000 code:
 
@@ -20,7 +20,7 @@
     Director, National Security Agency.  This software may be used and
     distributed according to the terms of the GNU General Public License,
     incorporated herein by reference.
-    Donald Becker may be reached at becker@cesdis1.gsfc.nasa.gov
+    Donald Becker may be reached at becker@scyld.com
 
 ======================================================================*/
 
@@ -33,12 +33,13 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/delay.h>
+#include <linux/spinlock.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
 
 #include <linux/netdevice.h>
-#include "ax8390.h"
+#include "../8390.h"
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -51,7 +52,6 @@
 #define AXNET_CMD	0x00
 #define AXNET_DATAPORT	0x10	/* NatSemi-defined port window offset. */
 #define AXNET_RESET	0x1f	/* Issue a read to reset, a write to clear. */
-#define AXNET_MISC	0x18	/* For IBM CCAE and Socket EA cards */
 #define AXNET_MII_EEP	0x14	/* Offset of MII access port */
 
 #define AXNET_START_PG	0x40	/* First page of TX buffer */
@@ -59,26 +59,13 @@
 
 #define AXNET_RDC_TIMEOUT 0x02	/* Max wait in jiffies for Tx RDC */
 
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"axnet_cs.c 1.11 2001/06/12 12:42:40 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
-
-#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb);
-#define skb_tx_check(dev, skb)
-#define add_rx_bytes(stats, n) (stats)->rx_bytes += n;
-#define add_tx_bytes(stats, n) (stats)->tx_bytes += n;
-#define netif_mark_up(dev)	do { } while (0)
-#define netif_mark_down(dev)	do { } while (0)
-
 /*====================================================================*/
 
-/* Parameters that can be set with 'insmod' */
+/* Module parameters */
+
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("Asix AX88190 PCMCIA ethernet driver");
+MODULE_LICENSE("GPL");
 
 #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
@@ -87,9 +74,14 @@
 static int irq_list[4] = { -1 };
 MODULE_PARM(irq_list, "1-4i");
 
-/* Ugh!  Let the user hardwire the hardware address for queer cards */
-static int hw_addr[6] = { 0, /* ... */ };
-MODULE_PARM(hw_addr, "6i");
+#ifdef PCMCIA_DEBUG
+INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"axnet_cs.c 1.24 2001/11/18 02:46:51 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
 
 /*====================================================================*/
 
@@ -120,6 +112,11 @@
 static dev_info_t dev_info = "axnet_cs";
 static dev_link_t *dev_list;
 
+static int axdev_init(struct net_device *dev);
+static void AX88190_init(struct net_device *dev, int startp);
+static int ax_open(struct net_device *dev);
+static void ax_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
 /*====================================================================*/
 
 typedef struct axnet_dev_t {
@@ -210,7 +207,7 @@
     link->conf.Attributes = CONF_ENABLE_IRQ;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
-    ethdev_init(dev);
+    axdev_init(dev);
     dev->init = &axnet_init;
     dev->open = &axnet_open;
     dev->stop = &axnet_close;
@@ -302,7 +299,7 @@
 	{0x00,	EN0_RCNTHI},
 	{0x00,	EN0_IMR},	/* Mask completion irq. */
 	{0xFF,	EN0_ISR},
-	{E8390_RXOFF, EN0_RXCR},	/* 0x20  Set to monitor */
+	{E8390_RXOFF|0x40, EN0_RXCR},	/* 0x60  Set to monitor */
 	{E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
 	{0x10,	EN0_RCNTLO},
 	{0x00,	EN0_RCNTHI},
@@ -331,30 +328,6 @@
 
 /*======================================================================
 
-    This should be totally unnecessary... but when we can't figure
-    out the hardware address any other way, we'll let the user hard
-    wire it when the module is initialized.
-
-======================================================================*/
-
-static int get_hwired(dev_link_t *link)
-{
-    struct net_device *dev = link->priv;
-    int i;
-
-    for (i = 0; i < 6; i++)
-	if (hw_addr[i] != 0) break;
-    if (i == 6)
-	return 0;
-
-    for (i = 0; i < 6; i++)
-	dev->dev_addr[i] = hw_addr[i];
-
-    return 1;
-} /* get_hwired */
-
-/*======================================================================
-
     axnet_config() is scheduled to run after a CARD_INSERTION event
     is received, to configure the PCMCIA socket, and to make the
     ethernet device available to the system.
@@ -419,7 +392,8 @@
     CS_CHECK(GetTupleData, handle, &tuple);
     CS_CHECK(ParseTuple, handle, &tuple, &parse);
     link->conf.ConfigBase = parse.config.base;
-    link->conf.Present = parse.config.rmask[0];
+    /* don't trust the CIS on this; Linksys got it wrong */
+    link->conf.Present = 0x63;
 
     /* Configure card */
     link->state |= DEV_CONFIG;
@@ -440,7 +414,7 @@
 	if ((cfg->index == 0) || (cfg->io.nwin == 0))
 	    goto next_entry;
 	
-	link->conf.ConfigIndex = cfg->index;
+	link->conf.ConfigIndex = 0x05;
 	/* For multifunction cards, by convention, we configure the
 	   network function with window 0, and serial with window 1 */
 	if (io->nwin > 1) {
@@ -480,9 +454,9 @@
 	goto failed;
     }
 
-    if (!get_prom(link) && !get_hwired(link)) {
-	printk(KERN_NOTICE "axnet_cs: unable to read hardware net"
-	       " address for io base %#3lx\n", dev->base_addr);
+    if (!get_prom(link)) {
+	printk(KERN_NOTICE "axnet_cs: this is not an AX88190 card!\n");
+	printk(KERN_NOTICE "axnet_cs: use pcnet_cs instead.\n");
 	unregister_netdev(dev);
 	goto failed;
     }
@@ -542,7 +516,7 @@
 
     if (link->open) {
 	DEBUG(1, "axnet_cs: release postponed, '%s' still open\n",
-	      info->node.dev_name);
+	      ((axnet_dev_t *)(link->priv))->node.dev_name);
 	link->state |= DEV_STALE_CONFIG;
 	return;
     }
@@ -602,7 +576,7 @@
 	    CardServices(RequestConfiguration, link->handle, &link->conf);
 	    if (link->open) {
 		axnet_reset_8390(&info->dev);
-		NS8390_init(&info->dev, 1);
+		AX88190_init(&info->dev, 1);
 		netif_device_attach(&info->dev);
 	    }
 	}
@@ -692,7 +666,7 @@
     info->watchdog.expires = jiffies + HZ;
     add_timer(&info->watchdog);
 
-    return ei_open(dev);
+    return ax_open(dev);
 } /* axnet_open */
 
 /*====================================================================*/
@@ -708,7 +682,6 @@
     
     link->open--;
     netif_stop_queue(dev);
-    netif_mark_down(dev);
     del_timer(&info->watchdog);
     if (link->state & DEV_STALE_CONFIG)
 	mod_timer(&link->release, jiffies + HZ/20);
@@ -755,7 +728,7 @@
 {
     axnet_dev_t *info = dev_id;
     info->stale = 0;
-    ei_interrupt(irq, dev_id, regs);
+    ax_interrupt(irq, dev_id, regs);
 }
 
 static void ei_watchdog(u_long arg)
@@ -807,7 +780,7 @@
 	    else
 		printk(KERN_INFO "%s: link partner did not autonegotiate\n",
 		       dev->name);
-	    NS8390_init(dev, 1);
+	    AX88190_init(dev, 1);
 	}
 	info->link_status = link;
     }
@@ -944,10 +917,11 @@
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
-	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
-	Center of Excellence in Space Data and Information Sciences
-	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
-  
+	The author may be reached as becker@scyld.com, or C/O
+	Scyld Computing Corporation
+	410 Severn Ave., Suite 210
+	Annapolis MD 21403
+
   This is the chip-specific code for many 8390-based ethernet adaptors.
   This is not a complete driver, it must be combined with board-specific
   code such as ne.c, wd.c, 3c503.c, etc.
@@ -957,7 +931,6 @@
   a simple innocent change. Please contact me or Donald if you think
   you have found something that needs changing. -- PG
 
-
   Changelog:
 
   Paul Gortmaker	: remove set_bit lock, other cleanups.
@@ -981,8 +954,8 @@
 
   */
 
-static const char *version =
-    "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+static const char *version_8390 =
+    "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@scyld.com)\n";
 
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
@@ -1062,25 +1035,23 @@
  *	them.
  */
  
-
-
 /**
- * ei_open - Open/initialize the board.
+ * ax_open - Open/initialize the board.
  * @dev: network device to initialize
  *
  * This routine goes all-out, setting everything
  * up anew at each open, even though many of these registers should only
  * need to be set once at boot.
  */
-static int ei_open(struct net_device *dev)
+static int ax_open(struct net_device *dev)
 {
 	unsigned long flags;
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 
-	/* This can't happen unless somebody forgot to call ethdev_init(). */
+	/* This can't happen unless somebody forgot to call axdev_init(). */
 	if (ei_local == NULL) 
 	{
-		printk(KERN_EMERG "%s: ei_open passed a non-existent device!\n", dev->name);
+		printk(KERN_EMERG "%s: ax_open passed a non-existent device!\n", dev->name);
 		return -ENXIO;
 	}
 
@@ -1099,10 +1070,9 @@
 	 */
       
       	spin_lock_irqsave(&ei_local->page_lock, flags);
-	NS8390_init(dev, 1);
+	AX88190_init(dev, 1);
 	/* Set the flag before we drop the lock, That way the IRQ arrives
 	   after its set and we get no silly warnings */
-	netif_mark_up(dev);
 	netif_start_queue(dev);
       	spin_unlock_irqrestore(&ei_local->page_lock, flags);
 	ei_local->irqlock = 0;
@@ -1110,27 +1080,6 @@
 }
 
 /**
- * ei_close - shut down network device
- * @dev: network device to close
- *
- * Opposite of ei_open(). Only used when "ifconfig <devname> down" is done.
- */
-static int ei_close(struct net_device *dev)
-{
-	unsigned long flags;
-
-	/*
-	 *	Hold the page lock during close
-	 */
-
-	spin_lock_irqsave(&((struct ei_device *)dev->priv)->page_lock, flags);
-	NS8390_init(dev, 0);
-	spin_unlock_irqrestore(&((struct ei_device *)dev->priv)->page_lock, flags);
-	netif_stop_queue(dev);
-	return 0;
-}
-
-/**
  * ei_tx_timeout - handle transmit time out condition
  * @dev: network device which has apparently fallen asleep
  *
@@ -1169,7 +1118,7 @@
 		
 	/* Try to restart the card.  Perhaps the user has fixed something. */
 	ei_reset_8390(dev);
-	NS8390_init(dev, 1);
+	AX88190_init(dev, 1);
 		
 	spin_unlock(&ei_local->page_lock);
 	enable_irq(dev->irq);
@@ -1192,7 +1141,6 @@
 	unsigned long flags;
 
 	netif_stop_queue(dev);
-	skb_tx_check(dev, skb);
 
 	length = skb->len;
 
@@ -1205,7 +1153,6 @@
 	outb_p(0x00, e8390_base + EN0_IMR);
 	spin_unlock_irqrestore(&ei_local->page_lock, flags);
 	
-	
 	/*
 	 *	Slow phase with lock held.
 	 */
@@ -1218,8 +1165,6 @@
 
 	send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
     
-#ifdef EI_PINGPONG
-
 	/*
 	 * We have two Tx slots available for use. Find the first free
 	 * slot, and then perform some sanity checks. With two Tx bufs,
@@ -1288,22 +1233,6 @@
 	else
 		netif_start_queue(dev);
 
-#else	/* EI_PINGPONG */
-
-	/*
-	 * Only one Tx buffer in use. You need two Tx bufs to come close to
-	 * back-to-back transmits. Expect a 20 -> 25% performance hit on
-	 * reasonable hardware if you only use one Tx buffer.
-	 */
-
-	ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
-	ei_local->txing = 1;
-	NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
-	dev->trans_start = jiffies;
-	netif_stop_queue(dev);
-
-#endif	/* EI_PINGPONG */
-
 	/* Turn 8390 interrupts back on. */
 	ei_local->irqlock = 0;
 	outb_p(ENISR_ALL, e8390_base + EN0_IMR);
@@ -1311,14 +1240,14 @@
 	spin_unlock(&ei_local->page_lock);
 	enable_irq(dev->irq);
 
-	DEV_KFREE_SKB (skb);
-	add_tx_bytes(&ei_local->stat, send_length);
+	dev_kfree_skb (skb);
+	ei_local->stat.tx_bytes += send_length;
     
 	return 0;
 }
 
 /**
- * ei_interrupt - handle the interrupts from an 8390
+ * ax_interrupt - handle the interrupts from an 8390
  * @irq: interrupt number
  * @dev_id: a pointer to the net_device
  * @regs: unused
@@ -1330,7 +1259,7 @@
  * needed.
  */
 
-static void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static void ax_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct net_device *dev = dev_id;
 	long e8390_base;
@@ -1497,8 +1426,6 @@
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 	int status = inb(e8390_base + EN0_TSR);
     
-#ifdef EI_PINGPONG
-
 	/*
 	 * There are two Tx buffers, see which one finished, and trigger
 	 * the send of another one if it exists.
@@ -1541,13 +1468,6 @@
 //	else printk(KERN_WARNING "%s: unexpected TX-done interrupt, lasttx=%d.\n",
 //			dev->name, ei_local->lasttx);
 
-#else	/* EI_PINGPONG */
-	/*
-	 *  Single Tx buffer: mark it free so another packet can be loaded.
-	 */
-	ei_local->txing = 0;
-#endif
-
 	/* Minimize Tx latency: update the statistics after we restart TXing. */
 	if (status & ENTSR_COL)
 		ei_local->stat.collisions++;
@@ -1655,7 +1575,7 @@
 				netif_rx(skb);
 				dev->last_rx = jiffies;
 				ei_local->stat.rx_packets++;
-				add_rx_bytes(&ei_local->stat, pkt_len);
+				ei_local->stat.rx_bytes += pkt_len;
 				if (pkt_stat & ENRSR_PHY)
 					ei_local->stat.multicast++;
 			}
@@ -1801,11 +1721,11 @@
 	long e8390_base = dev->base_addr;
 
   	if(dev->flags&IFF_PROMISC)
-  		outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR);
+  		outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR);
 	else if(dev->flags&IFF_ALLMULTI || dev->mc_list)
-  		outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR);
+  		outb_p(E8390_RXCONFIG | 0x48, e8390_base + EN0_RXCR);
   	else
-  		outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
+  		outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR);
 }
 
 /*
@@ -1813,28 +1733,30 @@
  *	be parallel to just about everything else. Its also fairly quick and
  *	not called too often. Must protect against both bh and irq users
  */
- 
+
+#define dev_lock(dev) (((struct ei_device *)(dev)->priv)->page_lock)
+
 static void set_multicast_list(struct net_device *dev)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&((struct ei_device *)dev->priv)->page_lock, flags);
+	spin_lock_irqsave(&dev_lock(dev), flags);
 	do_set_multicast_list(dev);
-	spin_unlock_irqrestore(&((struct ei_device *)dev->priv)->page_lock, flags);
+	spin_unlock_irqrestore(&dev_lock(dev), flags);
 }	
 
 /**
- * ethdev_init - init rest of 8390 device struct
+ * axdev_init - init rest of 8390 device struct
  * @dev: network device structure to init
  *
  * Initialize the rest of the 8390 device structure.  Do NOT __init
  * this, as it is used by 8390 based modular drivers too.
  */
 
-static int ethdev_init(struct net_device *dev)
+static int axdev_init(struct net_device *dev)
 {
 	if (ei_debug > 1)
-		printk(version);
+		printk(version_8390);
     
 	if (dev->priv == NULL) 
 	{
@@ -1857,20 +1779,18 @@
 	return 0;
 }
 
-
-
 /* This page of functions should be 8390 generic */
 /* Follow National Semi's recommendations for initializing the "NIC". */
 
 /**
- * NS8390_init - initialize 8390 hardware
+ * AX88190_init - initialize 8390 hardware
  * @dev: network device to initialize
  * @startp: boolean.  non-zero value to initiate chip processing
  *
  *	Must be called with lock held.
  */
 
-static void NS8390_init(struct net_device *dev, int startp)
+static void AX88190_init(struct net_device *dev, int startp)
 {
 	axnet_dev_t *info = (axnet_dev_t *)dev;
 	long e8390_base = dev->base_addr;
@@ -1887,7 +1807,7 @@
 	outb_p(0x00,  e8390_base + EN0_RCNTLO);
 	outb_p(0x00,  e8390_base + EN0_RCNTHI);
 	/* Set to monitor and loopback mode -- this is vital!. */
-	outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */
+	outb_p(E8390_RXOFF|0x40, e8390_base + EN0_RXCR); /* 0x60 */
 	outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */
 	/* Set the transmit page and receive ring. */
 	outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR);
@@ -1931,7 +1851,7 @@
 		outb_p(E8390_TXCONFIG | info->duplex_flag,
 		       e8390_base + EN0_TXCR); /* xmit on. */
 		/* 3c503 TechMan says rxconfig only after the NIC is started. */
-		outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on,  */
+		outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR); /* rx on, */
 		do_set_multicast_list(dev);	/* (re)load the mcast table */
 	}
 }
diff -Nur --exclude=*~ linux-2.4.16/drivers/net/pcmcia/netwave_cs.c linux/drivers/net/pcmcia/netwave_cs.c
--- linux-2.4.16/drivers/net/pcmcia/netwave_cs.c	Mon Nov 26 08:35:01 2001
+++ linux/drivers/net/pcmcia/netwave_cs.c	Fri Nov 30 13:18:53 2001
@@ -200,6 +200,8 @@
 MODULE_PARM(irq_mask, "i");
 MODULE_PARM(irq_list, "1-4i");
 
+MODULE_LICENSE("GPL");
+
 /*====================================================================*/
 
 /* PCMCIA (Card Services) related functions */
@@ -1597,4 +1599,3 @@
     writeb(rcvMode, ramBase + NETWAVE_EREG_CB + 1);
     writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2);
 }
-MODULE_LICENSE("GPL");
diff -Nur --exclude=*~ linux-2.4.16/drivers/net/shaper.c linux/drivers/net/shaper.c
--- linux-2.4.16/drivers/net/shaper.c	Mon Nov 26 08:35:01 2001
+++ linux/drivers/net/shaper.c	Fri Nov 30 12:47:01 2001
@@ -737,6 +737,11 @@
 
 static void __exit shaper_exit (void)
 {
+	int i;
+
+	for (i = 0; i < shapers; i++)
+		unregister_netdev(&devs[i]);
+
 	kfree(devs);
 	devs = NULL;
 }
diff -Nur --exclude=*~ linux-2.4.16/drivers/net/wan/comx-hw-mixcom.c linux/drivers/net/wan/comx-hw-mixcom.c
--- linux-2.4.16/drivers/net/wan/comx-hw-mixcom.c	Mon Nov 26 08:35:01 2001
+++ linux/drivers/net/wan/comx-hw-mixcom.c	Fri Nov 30 12:48:05 2001
@@ -566,8 +566,6 @@
 
 	return 0;
 	
-err_restore_flags:
-	restore_flags(flags);
 err_release_region:
 	release_region(dev->base_addr, MIXCOM_IO_EXTENT);
 err_ret:
diff -Nur --exclude=*~ linux-2.4.16/drivers/parport/parport_cs.c linux/drivers/parport/parport_cs.c
--- linux-2.4.16/drivers/parport/parport_cs.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/parport/parport_cs.c	Fri Nov 30 13:18:53 2001
@@ -5,7 +5,7 @@
     (specifically, for the Quatech SPP-100 EPP card: other cards will
     probably require driver tweaks)
     
-    parport_cs.c 1.20 2000/11/02 23:15:05
+    parport_cs.c 1.24 2001/10/13 14:04:05
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -57,32 +57,31 @@
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ciscode.h>
 
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"parport_cs.c 1.20 2000/11/02 23:15:05 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
+/*====================================================================*/
 
-#ifndef VERSION
-#define VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
-#endif
+/* Module parameters */
 
-/*====================================================================*/
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("PCMCIA parallel port card driver");
+MODULE_LICENSE("Dual MPL/GPL");
 
-/* Parameters that can be set with 'insmod' */
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
 /* Bit map of interrupts to choose from */
-static u_int irq_mask = 0xdeb8;
+INT_MODULE_PARM(irq_mask, 0xdeb8);
 static int irq_list[4] = { -1 };
-static int epp_mode = 1;
-
-MODULE_PARM(irq_mask, "i");
 MODULE_PARM(irq_list, "1-4i");
-MODULE_PARM(epp_mode, "i");
+
+INT_MODULE_PARM(epp_mode, 1);
+
+#ifdef PCMCIA_DEBUG
+INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"parport_cs.c 1.24 2001/10/13 14:04:05 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
 
 /*====================================================================*/
 
@@ -105,9 +104,6 @@
 static dev_info_t dev_info = "parport_cs";
 static dev_link_t *dev_list = NULL;
 
-extern struct parport_operations parport_pc_ops;
-static struct parport_operations parport_cs_ops;
-
 /*====================================================================*/
 
 static void cs_error(client_handle_t handle, int func, int ret)
@@ -307,19 +303,6 @@
 	goto failed;
     }
 
-#if (LINUX_VERSION_CODE < VERSION(2,3,6))
-#if (LINUX_VERSION_CODE >= VERSION(2,2,8))
-    p->private_data = kmalloc(sizeof(struct parport_pc_private),
-			      GFP_KERNEL);
-    ((struct parport_pc_private *)(p->private_data))->ctr = 0x0c;
-#endif
-    parport_proc_register(p);
-    p->flags |= PARPORT_FLAG_COMA;
-    parport_pc_write_econtrol(p, 0x00);
-    parport_pc_write_control(p, 0x0c);
-    parport_pc_write_data(p, 0x00);
-#endif
-
     p->modes |= PARPORT_MODE_PCSPP;
     if (epp_mode)
 	p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP;
@@ -365,14 +348,8 @@
 
     if (info->ndev) {
 	struct parport *p = info->port;
-#if (LINUX_VERSION_CODE < VERSION(2,3,6))
-	if (!(p->flags & PARPORT_FLAG_COMA))
-	    parport_quiesce(p);
-#endif
 	parport_proc_unregister(p);
-#if (LINUX_VERSION_CODE >= VERSION(2,2,8))
 	kfree(p->private_data);
-#endif
 	parport_unregister_port(p);
     }
     info->ndev = 0;
@@ -430,24 +407,6 @@
 
 /*====================================================================*/
 
-#if (LINUX_VERSION_CODE < VERSION(2,3,6))
-
-static void inc_use_count(void)
-{
-    MOD_INC_USE_COUNT;
-    parport_pc_ops.inc_use_count();
-}
-
-static void dec_use_count(void)
-{
-    MOD_DEC_USE_COUNT;
-    parport_pc_ops.dec_use_count();
-}
-
-#endif
-
-/*====================================================================*/
-
 static int __init init_parport_cs(void)
 {
     servinfo_t serv;
@@ -459,13 +418,6 @@
 	return -1;
     }
 
-#if (LINUX_VERSION_CODE < VERSION(2,3,6))
-    /* This is to protect against unloading modules out of order */
-    parport_cs_ops = parport_pc_ops;
-    parport_cs_ops.inc_use_count = &inc_use_count;
-    parport_cs_ops.dec_use_count = &dec_use_count;
-#endif
-
     register_pccard_driver(&dev_info, &parport_attach, &parport_detach);
     return 0;
 }
@@ -480,4 +432,3 @@
 
 module_init(init_parport_cs);
 module_exit(exit_parport_cs);
-MODULE_LICENSE("Dual MPL/GPL");
diff -Nur --exclude=*~ linux-2.4.16/drivers/pcmcia/cistpl.c linux/drivers/pcmcia/cistpl.c
--- linux-2.4.16/drivers/pcmcia/cistpl.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/pcmcia/cistpl.c	Fri Nov 30 13:23:00 2001
@@ -264,11 +264,11 @@
 	(s->cis_mem.sys_start == 0)) {
 	int low = !(s->cap.features & SS_CAP_PAGE_REGS);
 	vs = s;
-	validate_mem(cis_readable, checksum_match, low);
+	validate_mem(cis_readable, checksum_match, low, s);
 	s->cis_mem.sys_start = 0;
 	vs = NULL;
 	if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size,
-			    s->cap.map_size, low, "card services")) {
+			    s->cap.map_size, low, "card services", s)) {
 	    printk(KERN_NOTICE "cs: unable to map card memory!\n");
 	    return CS_OUT_OF_RESOURCE;
 	}
diff -Nur --exclude=*~ linux-2.4.16/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c
--- linux-2.4.16/drivers/pcmcia/cs.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/pcmcia/cs.c	Fri Nov 30 13:23:00 2001
@@ -809,7 +809,7 @@
 	    return 1;
     for (i = 0; i < MAX_IO_WIN; i++) {
 	if (s->io[i].NumPorts == 0) {
-	    if (find_io_region(base, num, align, name) == 0) {
+	    if (find_io_region(base, num, align, name, s) == 0) {
 		s->io[i].Attributes = attr;
 		s->io[i].BasePort = *base;
 		s->io[i].NumPorts = s->io[i].InUse = num;
@@ -821,7 +821,7 @@
 	/* Try to extend top of window */
 	try = s->io[i].BasePort + s->io[i].NumPorts;
 	if ((*base == 0) || (*base == try))
-	    if (find_io_region(&try, num, 0, name) == 0) {
+	    if (find_io_region(&try, num, 0, name, s) == 0) {
 		*base = try;
 		s->io[i].NumPorts += num;
 		s->io[i].InUse += num;
@@ -830,7 +830,7 @@
 	/* Try to extend bottom of window */
 	try = s->io[i].BasePort - num;
 	if ((*base == 0) || (*base == try))
-	    if (find_io_region(&try, num, 0, name) == 0) {
+	    if (find_io_region(&try, num, 0, name, s) == 0) {
 		s->io[i].BasePort = *base = try;
 		s->io[i].NumPorts += num;
 		s->io[i].InUse += num;
@@ -1974,7 +1974,7 @@
 	find_mem_region(&win->base, win->size, align,
 			(req->Attributes & WIN_MAP_BELOW_1MB) ||
 			!(s->cap.features & SS_CAP_PAGE_REGS),
-			(*handle)->dev_info))
+			(*handle)->dev_info, s))
 	return CS_IN_USE;
     (*handle)->state |= CLIENT_WIN_REQ(w);
 
diff -Nur --exclude=*~ linux-2.4.16/drivers/pcmcia/cs_internal.h linux/drivers/pcmcia/cs_internal.h
--- linux-2.4.16/drivers/pcmcia/cs_internal.h	Mon Nov 26 08:35:03 2001
+++ linux/drivers/pcmcia/cs_internal.h	Fri Nov 30 19:05:09 2001
@@ -238,11 +238,11 @@
 
 /* In rsrc_mgr */
 void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
-		  int force_low);
+		  int force_low, socket_info_t *s);
 int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align,
-		   char *name);
+		   char *name, socket_info_t *s);
 int find_mem_region(u_long *base, u_long num, u_long align,
-		    int force_low, char *name);
+		    int force_low, char *name, socket_info_t *s);
 int try_irq(u_int Attributes, int irq, int specific);
 void undo_irq(u_int Attributes, int irq);
 int adjust_resource_info(client_handle_t handle, adjust_t *adj);
diff -Nur --exclude=*~ linux-2.4.16/drivers/pcmcia/rsrc_mgr.c linux/drivers/pcmcia/rsrc_mgr.c
--- linux-2.4.16/drivers/pcmcia/rsrc_mgr.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/pcmcia/rsrc_mgr.c	Fri Nov 30 13:23:00 2001
@@ -44,6 +44,7 @@
 #include <linux/ioport.h>
 #include <linux/timer.h>
 #include <linux/proc_fs.h>
+#include <linux/pci.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
@@ -103,8 +104,78 @@
 
 ======================================================================*/
 
-#define check_io_resource(b,n)	check_resource(&ioport_resource, (b), (n))
-#define check_mem_resource(b,n)	check_resource(&iomem_resource, (b), (n))
+static struct resource *resource_parent(unsigned long b, unsigned long n,
+					int flags, struct pci_dev *dev)
+{
+	struct resource res;
+
+	if (dev == NULL) {
+		if (flags & IORESOURCE_MEM)
+			return &iomem_resource;
+		return &ioport_resource;
+	}
+	res.start = b;
+	res.end = b + n - 1;
+	res.flags = flags;
+	return pci_find_parent_resource(dev, &res);
+}
+
+static inline int check_io_resource(unsigned long b, unsigned long n,
+				    struct pci_dev *dev)
+{
+	return check_resource(resource_parent(b, n, IORESOURCE_IO, dev), b, n);
+}
+
+static inline int check_mem_resource(unsigned long b, unsigned long n,
+				     struct pci_dev *dev)
+{
+	return check_resource(resource_parent(b, n, IORESOURCE_MEM, dev), b, n);
+}
+
+static struct resource *make_resource(unsigned long b, unsigned long n,
+				      int flags, char *name)
+{
+	struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
+
+	if (res) {
+		memset(res, 0, sizeof(*res));
+		res->name = name;
+		res->start = b;
+		res->end = b + n - 1;
+		res->flags = flags | IORESOURCE_BUSY;
+	}
+	return res;
+}
+
+static int request_io_resource(unsigned long b, unsigned long n,
+			       char *name, struct pci_dev *dev)
+{
+	struct resource *res = make_resource(b, n, IORESOURCE_IO, name);
+	struct resource *pr = resource_parent(b, n, IORESOURCE_IO, dev);
+	int err = -ENOMEM;
+
+	if (res) {
+		err = request_resource(pr, res);
+		if (err)
+			kfree(res);
+	}
+	return err;
+}
+
+static int request_mem_resource(unsigned long b, unsigned long n,
+				char *name, struct pci_dev *dev)
+{
+	struct resource *res = make_resource(b, n, IORESOURCE_MEM, name);
+	struct resource *pr = resource_parent(b, n, IORESOURCE_MEM, dev);
+	int err = -ENOMEM;
+
+	if (res) {
+		err = request_resource(pr, res);
+		if (err)
+			kfree(res);
+	}
+	return err;
+}
 
 /*======================================================================
 
@@ -194,7 +265,7 @@
     }   
     memset(b, 0, 256);
     for (i = base, most = 0; i < base+num; i += 8) {
-	if (check_io_resource(i, 8))
+	if (check_io_resource(i, 8, NULL))
 	    continue;
 	hole = inb(i);
 	for (j = 1; j < 8; j++)
@@ -207,7 +278,7 @@
 
     bad = any = 0;
     for (i = base; i < base+num; i += 8) {
-	if (check_io_resource(i, 8))
+	if (check_io_resource(i, 8, NULL))
 	    continue;
 	for (j = 0; j < 8; j++)
 	    if (inb(i+j) != most) break;
@@ -247,7 +318,8 @@
 ======================================================================*/
 
 static int do_mem_probe(u_long base, u_long num,
-			int (*is_valid)(u_long), int (*do_cksum)(u_long))
+			int (*is_valid)(u_long), int (*do_cksum)(u_long),
+			socket_info_t *s)
 {
     u_long i, j, bad, fail, step;
 
@@ -258,13 +330,14 @@
     for (i = j = base; i < base+num; i = j + step) {
 	if (!fail) {	
 	    for (j = i; j < base+num; j += step)
-		if ((check_mem_resource(j, step) == 0) && is_valid(j))
+		if ((check_mem_resource(j, step, s->cap.cb_dev) == 0) &&
+		    is_valid(j))
 		    break;
 	    fail = ((i == base) && (j == base+num));
 	}
 	if (fail) {
 	    for (j = i; j < base+num; j += 2*step)
-		if ((check_mem_resource(j, 2*step) == 0) &&
+		if ((check_mem_resource(j, 2*step, s->cap.cb_dev) == 0) &&
 		    do_cksum(j) && do_cksum(j+step))
 		    break;
 	}
@@ -283,12 +356,12 @@
 
 static u_long inv_probe(int (*is_valid)(u_long),
 			int (*do_cksum)(u_long),
-			resource_map_t *m)
+			resource_map_t *m, socket_info_t *s)
 {
     u_long ok;
     if (m == &mem_db)
 	return 0;
-    ok = inv_probe(is_valid, do_cksum, m->next);
+    ok = inv_probe(is_valid, do_cksum, m->next, s);
     if (ok) {
 	if (m->base >= 0x100000)
 	    sub_interval(&mem_db, m->base, m->num);
@@ -296,11 +369,11 @@
     }
     if (m->base < 0x100000)
 	return 0;
-    return do_mem_probe(m->base, m->num, is_valid, do_cksum);
+    return do_mem_probe(m->base, m->num, is_valid, do_cksum, s);
 }
 
 void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
-		  int force_low)
+		  int force_low, socket_info_t *s)
 {
     resource_map_t *m, *n;
     static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
@@ -310,7 +383,7 @@
     if (!probe_mem) return;
     /* We do up to four passes through the list */
     if (!force_low) {
-	if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next) > 0))
+	if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next, s) > 0))
 	    return;
 	printk(KERN_NOTICE "cs: warning: no high memory space "
 	       "available!\n");
@@ -321,7 +394,7 @@
 	/* Only probe < 1 MB */
 	if (m->base >= 0x100000) continue;
 	if ((m->base | m->num) & 0xffff) {
-	    ok += do_mem_probe(m->base, m->num, is_valid, do_cksum);
+	    ok += do_mem_probe(m->base, m->num, is_valid, do_cksum, s);
 	    continue;
 	}
 	/* Special probe for 64K-aligned block */
@@ -331,7 +404,7 @@
 		if (ok >= mem_limit)
 		    sub_interval(&mem_db, b, 0x10000);
 		else
-		    ok += do_mem_probe(b, 0x10000, is_valid, do_cksum);
+		    ok += do_mem_probe(b, 0x10000, is_valid, do_cksum, s);
 	    }
 	}
     }
@@ -340,7 +413,7 @@
 #else /* CONFIG_ISA */
 
 void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
-		  int force_low)
+		  int force_low, socket_info_t *s)
 {
     resource_map_t *m;
     static int done = 0;
@@ -348,7 +421,7 @@
     if (!probe_mem || done++)
 	return;
     for (m = mem_db.next; m != &mem_db; m = m->next)
-	if (do_mem_probe(m->base, m->num, is_valid, do_cksum))
+	if (do_mem_probe(m->base, m->num, is_valid, do_cksum, s))
 	    return;
 }
 
@@ -368,7 +441,7 @@
 ======================================================================*/
 
 int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align,
-		   char *name)
+		   char *name, socket_info_t *s)
 {
     ioaddr_t try;
     resource_map_t *m;
@@ -378,9 +451,8 @@
 	for (try = (try >= m->base) ? try : try+align;
 	     (try >= m->base) && (try+num <= m->base+m->num);
 	     try += align) {
-	    if (check_io_resource(try, num) == 0) {
+	    if (request_io_resource(try, num, name, s->cap.cb_dev) == 0) {
 		*base = try;
-		request_region(try, num, name);
 		return 0;
 	    }
 	    if (!align) break;
@@ -390,7 +462,7 @@
 }
 
 int find_mem_region(u_long *base, u_long num, u_long align,
-		    int force_low, char *name)
+		    int force_low, char *name, socket_info_t *s)
 {
     u_long try;
     resource_map_t *m;
@@ -403,8 +475,7 @@
 	    for (try = (try >= m->base) ? try : try+align;
 		 (try >= m->base) && (try+num <= m->base+m->num);
 		 try += align) {
-		if (check_mem_resource(try, num) == 0) {
-		    request_mem_region(try, num, name);
+		if (request_mem_resource(try, num, name, s->cap.cb_dev) == 0) {
 		    *base = try;
 		    return 0;
 		}
diff -Nur --exclude=*~ linux-2.4.16/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c
--- linux-2.4.16/drivers/scsi/BusLogic.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/scsi/BusLogic.c	Wed Nov 28 18:15:57 2001
@@ -4131,7 +4131,7 @@
   /*
     Attempt to read the first 1024 bytes from the disk device.
   */
-  BufferHead = bread(MKDEV(MAJOR(Device), MINOR(Device) & ~0x0F), 0, 1024);
+  BufferHead = bread(MKDEV(MAJOR(Device), MINOR(Device) & ~0x0F), 0, block_size(Device));
   if (BufferHead == NULL) return 0;
   /*
     If the boot sector partition table flag is valid, search for a partition
diff -Nur --exclude=*~ linux-2.4.16/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
--- linux-2.4.16/drivers/scsi/ide-scsi.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/scsi/ide-scsi.c	Fri Nov 30 18:29:42 2001
@@ -785,7 +785,7 @@
 	rq->buffer = (char *) pc;
 	rq->bh = idescsi_dma_bh (drive, pc);
 	rq->cmd = IDESCSI_PC_RQ;
-	spin_unlock(&io_request_lock);
+	spin_unlock_irq(&io_request_lock);
 	(void) ide_do_drive_cmd (drive, rq, ide_end);
 	spin_lock_irq(&io_request_lock);
 	return 0;
diff -Nur --exclude=*~ linux-2.4.16/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
--- linux-2.4.16/drivers/scsi/megaraid.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/scsi/megaraid.c	Wed Nov 28 18:15:57 2001
@@ -4296,15 +4296,7 @@
 	int heads, cyls, sectors;
 	int capacity = disk->capacity;
 
-	int ma = MAJOR(dev);
-	int mi = (MINOR(dev) & ~0xf);
-
-	int block = 1024; 
-
-	if(blksize_size[ma])
-		block = blksize_size[ma][mi];
-		
-	if(!(bh = bread(MKDEV(ma,mi), 0, block)))
+	if(!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, block_size(dev))))
 		return -1;
 
 	if( *(unsigned short *)(bh->b_data + 510) == 0xAA55 ) {
diff -Nur --exclude=*~ linux-2.4.16/drivers/scsi/osst.c linux/drivers/scsi/osst.c
--- linux-2.4.16/drivers/scsi/osst.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/scsi/osst.c	Wed Nov 28 18:15:57 2001
@@ -16,15 +16,15 @@
   Copyright 1992 - 2000 Kai Makisara
 		 email Kai.Makisara@metla.fi
 
-  $Header: /home/cvsroot/Driver/osst.c,v 1.61 2001/06/03 21:55:12 riede Exp $
+  $Header: /home/cvsroot/Driver/osst.c,v 1.65 2001/11/11 20:38:56 riede Exp $
 
   Microscopic alterations - Rik Ling, 2000/12/21
   Last modified: Wed Feb  2 22:04:05 2000 by makisara@kai.makisara.local
   Some small formal changes - aeb, 950809
 */
 
-static const char * cvsid = "$Id: osst.c,v 1.61 2001/06/03 21:55:12 riede Exp $";
-const char * osst_version = "0.9.8";
+static const char * cvsid = "$Id: osst.c,v 1.65 2001/11/11 20:38:56 riede Exp $";
+const char * osst_version = "0.9.10";
 
 /* The "failure to reconnect" firmware bug */
 #define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/
@@ -225,20 +225,20 @@
 		 SRpnt->sr_cmnd[0] != MODE_SENSE &&
 		 SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
 		if (driver_byte(result) & DRIVER_SENSE) {
-			printk(KERN_WARNING "osst%d:W: Error with sense data: ", dev);
-			print_req_sense("osst", SRpnt);
+			printk(KERN_WARNING "osst%d:W: Command with sense data: ", dev);
+			print_req_sense("osst:", SRpnt);
 		}
 		else {
 			static	int	notyetprinted = 1;
 
 			printk(KERN_WARNING
-			     "osst%d:W: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
+			     "osst%d:W: Warning %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
 			     dev, result, suggestion(result), driver_byte(result) & DRIVER_MASK,
 			     host_byte(result));
 			if (notyetprinted) {
 				notyetprinted = 0;
 				printk(KERN_INFO
-					"osst%d:I: This error may be caused by your scsi controller,\n", dev);
+					"osst%d:I: This warning may be caused by your scsi controller,\n", dev);
 				printk(KERN_INFO
 					"osst%d:I: it has been reported with some Buslogic cards.\n", dev);
 			}
@@ -270,11 +270,10 @@
 /* Wakeup from interrupt */
 static void osst_sleep_done (Scsi_Cmnd * SCpnt)
 {
-	unsigned int dev;
+	unsigned int dev = TAPE_NR(SCpnt->request.rq_dev);
 	OS_Scsi_Tape * STp;
 
-	if ((dev = TAPE_NR(SCpnt->request.rq_dev)) < osst_template.nr_dev) {
-		STp = os_scsi_tapes[dev];
+	if (os_scsi_tapes && (STp = os_scsi_tapes[dev])) {
 		if ((STp->buffer)->writing &&
 		    (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
 		    (SCpnt->sense_buffer[2] & 0x40)) {
@@ -480,7 +479,8 @@
 			for (i=0; i < STp->buffer->sg_segs; i++)
 				memset(STp->buffer->sg[i].address, 0, STp->buffer->sg[i].length);
 			strcpy(STp->buffer->b_data, "READ ERROR ON FRAME");
-		}
+                } else
+			STp->buffer->buffer_bytes = OS_FRAME_SIZE;
 		return 1;
 	}
 	if (STp->buffer->syscall_result) {
@@ -619,8 +619,10 @@
 	if (!SRpnt) return (-EBUSY);
 
 	while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
-		SRpnt->sr_sense_buffer[2]  == 2 && SRpnt->sr_sense_buffer[12] == 4          &&
-	       (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8)         ) {
+	       (( SRpnt->sr_sense_buffer[2]  == 2 && SRpnt->sr_sense_buffer[12] == 4    &&
+		 (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8)    ) ||
+		( SRpnt->sr_sense_buffer[2]  == 6 && SRpnt->sr_sense_buffer[12] == 0x28 &&
+		  SRpnt->sr_sense_buffer[13] == 0                                        )  )) {
 #if DEBUG
 	    if (debugging) {
 		printk(OSST_DEB_MSG "osst%d:D: Sleeping in onstream wait ready\n", dev);
@@ -628,7 +630,7 @@
 		debugging = 0;
 	    }
 #endif
-	    current->state = TASK_INTERRUPTIBLE;
+	    set_current_state(TASK_INTERRUPTIBLE);
 	    schedule_timeout(HZ / 10);
 
 	    memset(cmd, 0, MAX_COMMAND_SIZE);
@@ -656,6 +658,66 @@
 	return 0;
 }
 
+/*
+ * Wait for a tape to be inserted in the unit
+ */
+static int osst_wait_for_medium(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned timeout)
+{
+	unsigned char	cmd[MAX_COMMAND_SIZE];
+	Scsi_Request  * SRpnt;
+	long		startwait = jiffies;
+#if DEBUG
+	int		dbg = debugging;
+	int		dev  = TAPE_NR(STp->devt);
+
+	printk(OSST_DEB_MSG "osst%d:D: Reached onstream wait for medium\n", dev);
+#endif
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = TEST_UNIT_READY;
+
+	SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
+	*aSRpnt = SRpnt;
+	if (!SRpnt) return (-EBUSY);
+
+	while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
+		SRpnt->sr_sense_buffer[2]  == 2 && SRpnt->sr_sense_buffer[12] == 0x3a       &&
+	        SRpnt->sr_sense_buffer[13] == 0                                             ) {
+#if DEBUG
+	    if (debugging) {
+		printk(OSST_DEB_MSG "osst%d:D: Sleeping in onstream wait medium\n", dev);
+		printk(OSST_DEB_MSG "osst%d:D: Turning off debugging for a while\n", dev);
+		debugging = 0;
+	    }
+#endif
+	    set_current_state(TASK_INTERRUPTIBLE);
+	    schedule_timeout(HZ / 10);
+
+	    memset(cmd, 0, MAX_COMMAND_SIZE);
+	    cmd[0] = TEST_UNIT_READY;
+
+	    SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
+	}
+	*aSRpnt = SRpnt;
+#if DEBUG
+	debugging = dbg;
+#endif
+	if ( STp->buffer->syscall_result     && SRpnt->sr_sense_buffer[2]  != 2 &&
+	     SRpnt->sr_sense_buffer[12] != 4 && SRpnt->sr_sense_buffer[13] == 1) {
+#if DEBUG
+	    printk(OSST_DEB_MSG "osst%d:D: Abnormal exit from onstream wait medium\n", dev);
+	    printk(OSST_DEB_MSG "osst%d:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", dev,
+			STp->buffer->syscall_result, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2],
+			SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
+#endif
+	    return 0;
+	}
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%d:D: Normal exit from onstream wait medium\n", dev);
+#endif
+	return 1;
+}
+
 static int osst_position_tape_and_confirm(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int frame)
 {
 	int	retval;
@@ -694,7 +756,7 @@
 		result = osst_write_error_recovery(STp, aSRpnt, 0);
 
 	result |= osst_wait_ready(STp, aSRpnt, 5 * 60);
-	STp->ps[STp->partition].rw = ST_IDLE;
+	STp->ps[STp->partition].rw = OS_WRITING_COMPLETE;
 	return (result);
 }
 
@@ -743,7 +805,7 @@
 			notyetprinted--;
 		}
 #endif
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout (HZ / OSST_POLL_PER_SEC);
 	}
 #if DEBUG
@@ -901,6 +963,8 @@
 #endif
 		if ( osst_initiate_read(STp, aSRpnt)
                 || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) {
+			if (STp->raw)
+				return (-EIO);
 			position = osst_get_frame_position(STp, aSRpnt);
 			if (position >= 0xbae && position < 0xbb8)
 				position = 0xbb8;
@@ -966,7 +1030,7 @@
 	if (cnt > 1) {
 		STp->recover_count++;
 		STp->recover_erreg++;
-		printk(KERN_WARNING "osst%d:I: Read error at position %d recovered\n", 
+		printk(KERN_WARNING "osst%d:I: Don't worry, Read error at position %d recovered\n", 
 					dev, STp->read_error_frame);
  	}
 	STp->read_count++;
@@ -1523,7 +1587,10 @@
 			retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending);
 		else
 			retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending);
-		printk(KERN_WARNING "osst%d:I: Write error%srecovered\n", dev, retval?" not ":" ");
+		printk(KERN_WARNING "osst%d:%s: %sWrite error%srecovered\n", dev,
+			       	retval?"E"    :"I",
+			       	retval?""     :"Don't worry, ",
+			       	retval?" not ":" ");
 		break;
 	   case OS_WRITE_LAST_MARK:
 		printk(KERN_ERR "osst%d:E: Bad frame in update last marker, fatal\n", dev);
@@ -1594,7 +1661,7 @@
 			       mt_count, last_mark_ppos);
 #endif
 		if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) {
-			osst_set_frame_position(STp, aSRpnt, last_mark_ppos, 0);
+			osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
 			if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
 #if DEBUG
 				printk(OSST_DEB_MSG 
@@ -1626,7 +1693,7 @@
 #if DEBUG
 		printk(OSST_DEB_MSG "osst%d:D: Positioning to last mark at %d\n", dev, last_mark_ppos);
 #endif
-		osst_set_frame_position(STp, aSRpnt, last_mark_ppos, 0);
+		osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
 		cnt++;
 		if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
 #if DEBUG
@@ -1753,7 +1820,7 @@
 #endif
 			return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
 		} else {
-			osst_set_frame_position(STp, aSRpnt, next_mark_ppos, 0);
+			osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
 			if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
 #if DEBUG
 				printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks\n",
@@ -1793,7 +1860,7 @@
 #endif
 					return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
 				}
-				osst_set_frame_position(STp, aSRpnt, STp->first_mark_ppos, 0);
+				osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos);
 				if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
 #if DEBUG
 					printk(OSST_DEB_MSG
@@ -1825,7 +1892,7 @@
 #if DEBUG
 			else printk(OSST_DEB_MSG "osst%d:D: Positioning to next mark at %d\n", dev, next_mark_ppos);
 #endif
-			osst_set_frame_position(STp, aSRpnt, next_mark_ppos, 0);
+			osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
 			cnt++;
 			if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
 #if DEBUG
@@ -2462,7 +2529,7 @@
 	}
 
 #if DEBUG
-	printk(KERN_INFO "osst%d:D: Block Size changed to 32.5K\n", dev);
+	printk(KERN_INFO "osst%d:D: Drive Block Size changed to 32.5K\n", dev);
 	 /*
 	 * In debug mode, we want to see as many errors as possible
 	 * to test the error recovery mechanism.
@@ -3400,6 +3467,7 @@
 		if (retval)
 			goto out;
 		STps->rw = ST_IDLE;
+		/* FIXME -- this may leave the tape without EOD and up2date headers */
 	}
 
 	if ((count % STp->block_size) != 0) {
@@ -3812,6 +3880,10 @@
 			ioctl_result = osst_flush_write_buffer(STp, &SRpnt);
 		 else
 			ioctl_result = 0;
+#if DEBUG
+		 if (debugging) 
+			   printk(OSST_DEB_MSG "osst%d:D: Writing %ld filemark(s).\n", dev, arg);
+#endif
 		 for (i=0; i<arg; i++)
 			ioctl_result |= osst_write_filemark(STp, &SRpnt);
 		 if (fileno >= 0) fileno += arg;
@@ -3831,14 +3903,9 @@
 		 cmd[4] = arg;
 		 timeout = STp->timeout;
 #if DEBUG
-		 if (debugging) {
-			if (cmd_in == MTWEOF)
-			   printk(OSST_DEB_MSG "osst%d:D: Writing %d filemarks.\n", dev,
-				  cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-			else
-			   printk(OSST_DEB_MSG "osst%d:D: Writing %d setmarks.\n", dev,
+		 if (debugging) 
+			   printk(OSST_DEB_MSG "osst%d:D: Writing %d setmark(s).\n", dev,
 				  cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-		 }
 #endif
 		 if (fileno >= 0)
 			fileno += arg;
@@ -3851,8 +3918,12 @@
 	 case MTRETEN:
 		 cmd[0] = START_STOP;
 		 cmd[1] = 1;			/* Don't wait for completion */
-		 if (cmd_in == MTLOAD)
+		 if (cmd_in == MTLOAD) {
+		     if (STp->ready == ST_NO_TAPE)
+			 cmd[4] = 4;		/* open tray */
+		      else
 			 cmd[4] = 1;		/* load */
+		 }
 		 if (cmd_in == MTRETEN)
 			 cmd[4] = 3;		/* retension then mount */
 		 if (cmd_in == MTOFFL)
@@ -3991,7 +4062,7 @@
 		printk(OSST_DEB_MSG "osst%d:D: IOCTL (%d) Result=%d\n", dev, cmd_in, ioctl_result);
 #endif
 
-	if (!ioctl_result) {
+	if (!ioctl_result) {				/* success */
 
 		if (cmd_in == MTFSFM) {
 			 fileno--;
@@ -4068,6 +4139,8 @@
 		if (cmd_in == MTLOCK)
 			STp->door_locked = ST_LOCK_FAILS;
 
+		if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60))
+			ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60);
 	}
 	*aSRpnt = SRpnt;
 
@@ -4108,6 +4181,7 @@
 		 __MOD_INC_USE_COUNT(STp->device->host->hostt->module);
 	if (osst_template.module)
 		 __MOD_INC_USE_COUNT(osst_template.module);
+	STp->device->access_count++;
 
 	if (mode != STp->current_mode) {
 #if DEBUG
@@ -4124,6 +4198,8 @@
 	STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
 
 	STp->raw = (MINOR(inode->i_rdev) & 0x40) != 0;
+	if (STp->raw)
+		STp->header_ok = 0;
 
 	/* Allocate a buffer for this user */
 	need_dma_buffer = STp->restr_dma;
@@ -4214,7 +4290,7 @@
 			STp->nbr_partitions = 1;  /* This guess will be updated later if necessary */
 		for (i=0; i < ST_NBR_PARTITIONS; i++) {
 			STps = &(STp->ps[i]);
-			STps->rw = ST_IDLE;			/* FIXME - seems to be redundant... */
+			STps->rw = ST_IDLE;		/* FIXME - seems to be redundant... */
 			STps->eof = ST_NOEOF;
 			STps->at_sm = 0;
 			STps->last_block_valid = FALSE;
@@ -4262,8 +4338,8 @@
 					STp->door_locked = ST_LOCKED_AUTO;
 			}
 			if (!STp->frame_in_buffer) {
-				STp->block_size = (STp->raw) ? OS_FRAME_SIZE : (
-					    (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
+				STp->block_size = (STm->default_blksize > 0) ?
+							STm->default_blksize : OS_DATA_SIZE;
 				STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
 			}
 			STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
@@ -4356,8 +4432,6 @@
 		return 0;
 	}
 
-	STp->min_block = STp->max_block = (-1);
-
 	osst_configure_onstream(STp, &SRpnt);
 
 /*	STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; FIXME */
@@ -4384,11 +4458,9 @@
 	} else
 		STp->buffer->aux = NULL; /* this had better never happen! */
 
-	STp->block_size = (STp->raw) ? OS_FRAME_SIZE : (
+	STp->block_size = STp->raw ? OS_FRAME_SIZE : (
 			     (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
-	STp->min_block  = 512;
-	STp->max_block  = OS_DATA_SIZE;
-	STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
+	STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size;
 	STp->buffer->buffer_bytes  =
 	STp->buffer->read_pointer  =
 	STp->frame_in_buffer       = 0;
@@ -4446,6 +4518,8 @@
 		STp->buffer = NULL;
 	}
 	STp->in_use = 0;
+	STp->header_ok = 0;
+	STp->device->access_count--;
 
 	if (STp->device->host->hostt->module)
 	    __MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
@@ -4482,7 +4556,7 @@
 		if (result != 0 && result != (-ENOSPC))
 			goto out;
 	}
-	if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) {
+	if ( STps->rw >= ST_WRITING && !(STp->device)->was_reset) {
 
 #if DEBUG
 		if (debugging) {
@@ -4492,16 +4566,17 @@
 					       dev, STp->nbr_waits, STp->nbr_finished);
 		}
 #endif
+		if (STp->write_type != OS_WRITE_NEW_MARK) {
+			/* true unless the user wrote the filemark for us */
+			result = osst_flush_drive_buffer(STp, &SRpnt);
+			if (result < 0) goto out;
+			result = osst_write_filemark(STp, &SRpnt);
+			if (result < 0) goto out;
 
-		result = osst_flush_drive_buffer(STp, &SRpnt);
-		if (result < 0) goto out;
-		result = osst_write_filemark(STp, &SRpnt);
-		if (result < 0) goto out;
-
-		if (STps->drv_file >= 0)
-			STps->drv_file++ ;
-		STps->drv_block = 0;
-
+			if (STps->drv_file >= 0)
+				STps->drv_file++ ;
+			STps->drv_block = 0;
+		}
 		result = osst_write_eod(STp, &SRpnt);
 		osst_write_header(STp, &SRpnt, !(STp->rew_at_close));
 
@@ -4585,7 +4660,12 @@
 	if (STp->buffer != NULL)
 		STp->buffer->in_use = 0;
 
+	if (STp->raw)
+		STp->header_ok = 0;
+
 	STp->in_use = 0;
+	STp->device->access_count--;
+
 	if (STp->device->host->hostt->module)
 		__MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
 	if(osst_template.module)
@@ -4635,7 +4715,10 @@
 
 	cmd_type = _IOC_TYPE(cmd_in);
 	cmd_nr   = _IOC_NR(cmd_in);
-
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%d:D: Ioctl %d,%d in %s mode\n", dev,
+			    cmd_type, cmd_nr, STp->raw?"raw":"normal");
+#endif
 	if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
 		struct mtop mtc;
 
@@ -4718,8 +4801,8 @@
 			}
 		}
 
-		if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
-		    mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTWSM &&
+		if (mtc.mt_op != MTNOP && mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM &&
+		    mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETBLK &&
 		    mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART)
 			STps->rw = ST_IDLE;  /* Prevent automatic WEOF and fsf */
 
@@ -4771,7 +4854,10 @@
 	 	}
 
 		if (mtc.mt_op == MTSEEK) {
-			i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
+			if (STp->raw)
+				i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0);
+			else
+				i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
 			if (!STp->can_partitions)
 				STp->ps[0].rw = ST_IDLE;
 			retval = i;
@@ -4876,7 +4962,10 @@
 			retval = (-EINVAL);
 			goto out;
 		}
-		blk = osst_get_sector(STp, &SRpnt);
+		if (STp->raw)
+			blk = osst_get_frame_position(STp, &SRpnt);
+		else
+			blk = osst_get_sector(STp, &SRpnt);
 		if (blk < 0) {
 			retval = blk;
 			goto out;
@@ -4971,7 +5060,7 @@
 				tb = NULL;
 				break;
 			    }
-			    tb->sg[segs].page = NULL;
+                            tb->sg[segs].page = NULL;
 			    tb->sg[segs].length = b_size;
 			    got += b_size;
 			    segs++;
@@ -5423,6 +5512,8 @@
 	tpnt->partition = 0;
 	tpnt->new_partition = 0;
 	tpnt->nbr_partitions = 0;
+	tpnt->min_block = 512;
+	tpnt->max_block = OS_DATA_SIZE;
 	tpnt->timeout = OSST_TIMEOUT;
 	tpnt->long_timeout = OSST_LONG_TIMEOUT;
 
@@ -5462,6 +5553,7 @@
 
 	tpnt->current_mode = 0;
 	tpnt->modes[0].defined = TRUE;
+	tpnt->modes[2].defined = TRUE;
 	tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = FALSE;
 	init_MUTEX(&tpnt->lock);
 
diff -Nur --exclude=*~ linux-2.4.16/drivers/scsi/osst.h linux/drivers/scsi/osst.h
--- linux-2.4.16/drivers/scsi/osst.h	Mon Nov 26 08:35:02 2001
+++ linux/drivers/scsi/osst.h	Fri Nov 30 19:05:52 2001
@@ -1,5 +1,5 @@
 /*
- *	$Header: /home/cvsroot/Driver/osst.h,v 1.11 2001/01/26 01:54:49 riede Exp $
+ *	$Header: /home/cvsroot/Driver/osst.h,v 1.12 2001/10/11 00:30:15 riede Exp $
  */
 
 #include <asm/byteorder.h>
@@ -638,3 +638,5 @@
 #define OS_WRITE_HEADER    4
 #define OS_WRITE_FILLER    5
 
+/* Additional rw state */
+#define OS_WRITING_COMPLETE 3
diff -Nur --exclude=*~ linux-2.4.16/drivers/scsi/pcmcia/aha152x_stub.c linux/drivers/scsi/pcmcia/aha152x_stub.c
--- linux-2.4.16/drivers/scsi/pcmcia/aha152x_stub.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/scsi/pcmcia/aha152x_stub.c	Fri Nov 30 13:18:53 2001
@@ -5,7 +5,7 @@
     This driver supports the Adaptec AHA-1460, the New Media Bus
     Toaster, and the New Media Toast & Jam.
     
-    aha152x_cs.c 1.54 2000/06/12 21:27:25
+    aha152x_cs.c 1.58 2001/10/13 00:08:51
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -22,8 +22,8 @@
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
-    terms of the GNU General Public License version 2 (the "GPL"), in which
-    case the provisions of the GPL are applicable instead of the
+    terms of the GNU General Public License version 2 (the "GPL"), in
+    which case the provisions of the GPL are applicable instead of the
     above.  If you wish to allow the use of your version of this file
     only under the terms of the GPL and not to allow others to use
     your version of this file under the MPL, indicate your decision
@@ -57,42 +57,39 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"aha152x_cs.c 1.54 2000/06/12 21:27:25 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
-
 /*====================================================================*/
 
-/* Parameters that can be set with 'insmod' */
+/* Module parameters */
+
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("Adaptec AHA152x-compatible PCMCIA SCSI driver");
+MODULE_LICENSE("Dual MPL/GPL");
 
-/* Bit map of interrupts to choose from */
-static u_int irq_mask = 0xdeb8;
 static int irq_list[4] = { -1 };
+MODULE_PARM(irq_list, "1-4i");
 
-/* SCSI bus setup options */
-static int host_id = 7;
-static int reconnect = 1;
-static int parity = 1;
-static int synchronous = 0;
-static int reset_delay = 100;
-static int ext_trans = 0;
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-4i");
-MODULE_PARM(host_id, "i");
-MODULE_PARM(reconnect, "i");
-MODULE_PARM(parity, "i");
-MODULE_PARM(synchronous, "i");
-MODULE_PARM(reset_delay, "i");
-MODULE_PARM(ext_trans, "i");
+INT_MODULE_PARM(irq_mask,	0xdeb8);
+INT_MODULE_PARM(host_id,	7);
+INT_MODULE_PARM(reconnect,	1);
+INT_MODULE_PARM(parity,		1);
+INT_MODULE_PARM(synchronous,	0);
+INT_MODULE_PARM(reset_delay,	100);
+INT_MODULE_PARM(ext_trans,	0);
 
-MODULE_LICENSE("Dual MPL/GPL");
+#ifdef AHA152X_DEBUG
+INT_MODULE_PARM(debug,		0);
+#endif
+
+#ifdef PCMCIA_DEBUG
+INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"aha152x_cs.c 1.58 2001/10/13 00:08:51 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
 
 /*====================================================================*/
 
@@ -277,7 +274,6 @@
     release_region(link->io.BasePort1, link->io.NumPorts1);
     
     /* Set configuration options for the aha152x driver */
-    ints[0] = 7;
     ints[1] = link->io.BasePort1;
     ints[2] = link->irq.AssignedIRQ;
     ints[3] = host_id;
@@ -285,9 +281,13 @@
     ints[5] = parity;
     ints[6] = synchronous;
     ints[7] = reset_delay;
-    if (ext_trans) {
-	ints[8] = ext_trans; ints[0] = 8;
-    }
+    ints[8] = ext_trans;
+#ifdef AHA152X_DEBUG
+    ints[9] = debug;
+    ints[0] = 9;
+#else
+    ints[0] = 8;
+#endif
     aha152x_setup("PCMCIA setup", ints);
     
     scsi_register_module(MODULE_SCSI_HA, &driver_template);
diff -Nur --exclude=*~ linux-2.4.16/drivers/scsi/pcmcia/fdomain_stub.c linux/drivers/scsi/pcmcia/fdomain_stub.c
--- linux-2.4.16/drivers/scsi/pcmcia/fdomain_stub.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/scsi/pcmcia/fdomain_stub.c	Fri Nov 30 13:18:53 2001
@@ -2,7 +2,7 @@
 
     A driver for Future Domain-compatible PCMCIA SCSI cards
 
-    fdomain_cs.c 1.43 2000/06/12 21:27:25
+    fdomain_cs.c 1.47 2001/10/13 00:08:52
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -19,8 +19,8 @@
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
-    terms of the GNU General Public License version 2 (the "GPL"), in which
-    case the provisions of the GPL are applicable instead of the
+    terms of the GNU General Public License version 2 (the "GPL"), in
+    which case the provisions of the GPL are applicable instead of the
     above.  If you wish to allow the use of your version of this file
     only under the terms of the GPL and not to allow others to use
     your version of this file under the MPL, indicate your decision
@@ -54,27 +54,30 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"fdomain_cs.c 1.43 2000/06/12 21:27:25 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
-
 /*====================================================================*/
 
-/* Parameters that can be set with 'insmod' */
+/* Module parameters */
+
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver");
+MODULE_LICENSE("Dual MPL/GPL");
+
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
 /* Bit map of interrupts to choose from */
-static u_int irq_mask = 0xdeb8;
+INT_MODULE_PARM(irq_mask, 0xdeb8);
 static int irq_list[4] = { -1 };
-
-MODULE_PARM(irq_mask, "i");
 MODULE_PARM(irq_list, "1-4i");
 
+#ifdef PCMCIA_DEBUG
+INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"fdomain_cs.c 1.47 2001/10/13 00:08:52 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
 /*====================================================================*/
 
 typedef struct scsi_info_t {
@@ -212,6 +215,7 @@
     u_char tuple_data[64];
     Scsi_Device *dev;
     dev_node_t *node, **tail;
+    char str[16];
     struct Scsi_Host *host;
 
     DEBUG(0, "fdomain_config(0x%p)\n", link);
@@ -252,7 +256,8 @@
     ints[0] = 2;
     ints[1] = link->io.BasePort1;
     ints[2] = link->irq.AssignedIRQ;
-    fdomain_setup("PCMCIA setup", ints);
+    sprintf(str, "%d,%d", link->io.BasePort1, link->irq.AssignedIRQ);
+    fdomain_setup(str, ints);
     
     scsi_register_module(MODULE_SCSI_HA, &driver_template);
 
diff -Nur --exclude=*~ linux-2.4.16/drivers/scsi/pcmcia/qlogic_stub.c linux/drivers/scsi/pcmcia/qlogic_stub.c
--- linux-2.4.16/drivers/scsi/pcmcia/qlogic_stub.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/scsi/pcmcia/qlogic_stub.c	Fri Nov 30 13:18:53 2001
@@ -2,7 +2,7 @@
 
     A driver for the Qlogic SCSI card
 
-    qlogic_cs.c 1.79 2000/06/12 21:27:26
+    qlogic_cs.c 1.83 2001/10/13 00:08:53
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -19,8 +19,8 @@
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
-    terms of the GNU General Public License version 2 (the "GPL"), in which
-    case the provisions of the GPL are applicable instead of the
+    terms of the GNU General Public License version 2 (the "GPL"), in
+    which case the provisions of the GPL are applicable instead of the
     above.  If you wish to allow the use of your version of this file
     only under the terms of the GPL and not to allow others to use
     your version of this file under the MPL, indicate your decision
@@ -40,6 +40,7 @@
 #include <linux/timer.h>
 #include <linux/ioport.h>
 #include <asm/io.h>
+#include <asm/byteorder.h>
 #include <scsi/scsi.h>
 #include <linux/major.h>
 #include <linux/blk.h>
@@ -61,26 +62,29 @@
 
 extern void qlogicfas_preset(int port, int irq);
 
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"qlogic_cs.c 1.79 2000/06/12 21:27:26 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
-
 /*====================================================================*/
 
-/* Parameters that can be set with 'insmod' */
+/* Module parameters */
+
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("Qlogic PCMCIA SCSI driver");
+MODULE_LICENSE("Dual MPL/GPL");
+
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
 /* Bit map of interrupts to choose from */
-static u_int irq_mask = 0xdeb8;
+INT_MODULE_PARM(irq_mask, 0xdeb8);
 static int irq_list[4] = { -1 };
-
-MODULE_PARM(irq_mask, "i");
 MODULE_PARM(irq_list, "1-4i");
+
+#ifdef PCMCIA_DEBUG
+INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"qlogic_cs.c 1.83 2001/10/13 00:08:53 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
 
 /*====================================================================*/
 
diff -Nur --exclude=*~ linux-2.4.16/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c
--- linux-2.4.16/drivers/scsi/scsi_debug.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/scsi/scsi_debug.c	Fri Nov 30 12:46:14 2001
@@ -653,7 +653,6 @@
 
 int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info)
 {
-	int size = disk->capacity;
 	info[0] = N_HEAD;
 	info[1] = N_SECTOR;
 	info[2] = N_CYLINDER;
diff -Nur --exclude=*~ linux-2.4.16/drivers/scsi/scsicam.c linux/drivers/scsi/scsicam.c
--- linux-2.4.16/drivers/scsi/scsicam.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/scsi/scsicam.c	Wed Nov 28 18:15:57 2001
@@ -47,15 +47,7 @@
 	int size = disk->capacity;
 	unsigned long temp_cyl;
 
-	int ma = MAJOR(dev);
-	int mi = (MINOR(dev) & ~0xf);
-
-	int block = 1024; 
-
-	if(blksize_size[ma])
-		block = blksize_size[ma][mi];
-		
-	if (!(bh = bread(MKDEV(ma,mi), 0, block)))
+	if (!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, block_size(dev))))
 		return -1;
 
 	/* try to infer mapping from partition table */
diff -Nur --exclude=*~ linux-2.4.16/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c
--- linux-2.4.16/drivers/scsi/tmscsim.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/scsi/tmscsim.c	Wed Nov 28 18:15:57 2001
@@ -1450,7 +1450,7 @@
     int ret_code = -1;
     int size = disk->capacity;
 
-    if ((bh = bread(MKDEV(MAJOR(devno), MINOR(devno)&~0xf), 0, 1024)))
+    if ((bh = bread(MKDEV(MAJOR(devno), MINOR(devno)&~0xf), 0, block_size(devno))))
     {
 	/* try to infer mapping from partition table */
 	ret_code = partsize (bh, (unsigned long) size, (unsigned int *) geom + 2,
diff -Nur --exclude=*~ linux-2.4.16/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
--- linux-2.4.16/drivers/sound/ad1848.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/sound/ad1848.c	Fri Nov 30 13:09:13 2001
@@ -30,6 +30,12 @@
  * Aki Laukkanen	: added power management support
  * Arnaldo C. de Melo	: added missing restore_flags in ad1848_resume
  * Miguel Freitas       : added ISA PnP support
+ * Alan Cox		: Added CS4236->4239 identification
+ * Daniel T. Cobra	: Alernate config/mixer for later chips
+ * Alan Cox		: Merged chip idents and config code
+ *
+ * TODO
+ *		APM save restore assist code on IBM thinkpad
  *
  * Status:
  *		Tested. Believed fully functional.
@@ -57,7 +63,7 @@
 	int             dual_dma;	/* 1, when two DMA channels allocated */
 	int 		subtype;
 	unsigned char   MCE_bit;
-	unsigned char   saved_regs[32];
+	unsigned char   saved_regs[64];	/* Includes extended register space */
 	int             debug_flag;
 
 	int             audio_flags;
@@ -78,6 +84,9 @@
 #define MD_IWAVE	7
 #define MD_4235         8 /* Crystal Audio CS4235  */
 #define MD_1845_SSCAPE  9 /* Ensoniq Soundscape PNP*/
+#define MD_4236		10 /* 4236 and higher */
+#define MD_42xB		11 /* CS 42xB */
+#define MD_4239		12 /* CS4239 */
 
 	/* Mixer parameters */
 	int             recmask;
@@ -202,9 +211,22 @@
 
 	save_flags(flags);
 	cli();
-	outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc));
-	x = inb(io_Indexed_Data(devc));
-/* printk("(%02x<-%02x) ", reg|devc->MCE_bit, x); */
+	
+	if(reg < 32)
+	{
+		outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc));
+		x = inb(io_Indexed_Data(devc));
+	}
+	else
+	{
+		int xreg, xra;
+
+		xreg = (reg & 0xff) - 32;
+		xra = (((xreg & 0x0f) << 4) & 0xf0) | 0x08 | ((xreg & 0x10) >> 2);
+		outb(((unsigned char) (23 & 0xff) | devc->MCE_bit), io_Index_Addr(devc));
+		outb(((unsigned char) (xra & 0xff)), io_Indexed_Data(devc));
+		x = inb(io_Indexed_Data(devc));
+	}
 	restore_flags(flags);
 
 	return x;
@@ -220,9 +242,22 @@
 
 	save_flags(flags);
 	cli();
-	outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc));
-	outb(((unsigned char) (data & 0xff)), io_Indexed_Data(devc));
-	/* printk("(%02x->%02x) ", reg|devc->MCE_bit, data); */
+	
+	if(reg < 32)
+	{
+		outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc));
+		outb(((unsigned char) (data & 0xff)), io_Indexed_Data(devc));
+	}
+	else
+	{
+		int xreg, xra;
+		
+		xreg = (reg & 0xff) - 32;
+		xra = (((xreg & 0x0f) << 4) & 0xf0) | 0x08 | ((xreg & 0x10) >> 2);
+		outb(((unsigned char) (23 & 0xff) | devc->MCE_bit), io_Index_Addr(devc));
+		outb(((unsigned char) (xra & 0xff)), io_Indexed_Data(devc));
+		outb((unsigned char) (data & 0xff), io_Indexed_Data(devc));
+	}
 	restore_flags(flags);
 }
 
@@ -591,7 +626,13 @@
 			devc->mix_devices = &(iwave_mix_devices[0]);
 			break;
 
+		case MD_42xB:
+		case MD_4239:
+			devc->mix_devices = &(cs42xb_mix_devices[0]);
+			devc->supported_devices = MODE3_MIXER_DEVICES;
+			break;
 		case MD_4232:
+		case MD_4236:
 			devc->supported_devices = MODE3_MIXER_DEVICES;
 			break;
 
@@ -1118,7 +1159,7 @@
 	}
 	old_fs = ad_read(devc, 8);
 
-	if (devc->model == MD_4232)
+	if (devc->model == MD_4232 || devc->model >= MD_4236)
 	{
 		tmp = ad_read(devc, 16);
 		ad_write(devc, 16, tmp | 0x30);
@@ -1139,7 +1180,7 @@
 	while (timeout < 10000 && inb(devc->base) == 0x80)
 		timeout++;
 
-	if (devc->model == MD_4232)
+	if (devc->model >= MD_4232)
 		ad_write(devc, 16, tmp & ~0x30);
 
 	ad_leave_MCE(devc);	/*
@@ -1403,11 +1444,12 @@
 static void ad1848_init_hw(ad1848_info * devc)
 {
 	int i;
+	int *init_values;
 
 	/*
 	 * Initial values for the indirect registers of CS4248/AD1848.
 	 */
-	static int      init_values[] =
+	static int      init_values_a[] =
 	{
 		0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
 		0x00, 0x0c, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00,
@@ -1417,6 +1459,31 @@
 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 	};
 
+	static int      init_values_b[] =
+	{
+		/* 
+		   Values for the newer chips
+		   Some of the register initialization values were changed. In
+		   order to get rid of the click that preceded PCM playback,
+		   calibration was disabled on the 10th byte. On that same byte,
+		   dual DMA was enabled; on the 11th byte, ADC dithering was
+		   enabled, since that is theoretically desirable; on the 13th
+		   byte, Mode 3 was selected, to enable access to extended
+		   registers.
+		 */
+		0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+		0x00, 0x00, 0x06, 0x00, 0xe0, 0x01, 0x00, 0x00,
+ 		0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x1f, 0x40,
+ 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	};
+
+	/*
+	 *	Select initialisation data
+	 */
+	 
+	init_values = init_values_a;
+	if(devc->model >= MD_4236)
+		init_values = init_values_b;
 
 	for (i = 0; i < 16; i++)
 		ad_write(devc, i, init_values[i]);
@@ -1768,19 +1835,49 @@
 				else
 				{
 					switch (id & 0x1f) {
-					case 3: /* CS4236/CS4235 */
+					case 3: /* CS4236/CS4235/CS42xB/CS4239 */
 						{
 							int xid;
 							ad_write(devc, 12, ad_read(devc, 12) | 0x60); /* switch to mode 3 */
 							ad_write(devc, 23, 0x9c); /* select extended register 25 */
 							xid = inb(io_Indexed_Data(devc));
 							ad_write(devc, 12, ad_read(devc, 12) & ~0x60); /* back to mode 0 */
-							if ((xid & 0x1f) == 0x1d) {
-								devc->chip_name = "CS4235";
-								devc->model = MD_4235;
-							} else {
-								devc->chip_name = "CS4236";
-								devc->model = MD_4232;
+							switch (xid & 0x1f)
+							{
+								case 0x00:
+									devc->chip_name = "CS4237B(B)";
+									devc->model = MD_42xB;
+									break;
+								case 0x08:
+									/* Seems to be a 4238 ?? */
+									devc->chip_name = "CS4238";
+									devc->model = MD_42xB;
+									break;
+								case 0x09:
+									devc->chip_name = "CS4238B";
+									devc->model = MD_42xB;
+									break;
+								case 0x0b:
+									devc->chip_name = "CS4236B";
+									devc->model = MD_4236;
+									break;
+								case 0x10:
+									devc->chip_name = "CS4237B";
+									devc->model = MD_42xB;
+									break;
+								case 0x1d:
+									devc->chip_name = "CS4235";
+									devc->model = MD_4235;
+									break;
+								case 0x1e:
+									devc->chip_name = "CS4239";
+									devc->model = MD_4239;
+									break;
+								default:
+									printk("Chip ident is %X.\n", xid&0x1F);
+									devc->chip_name = "CS42xx";
+									devc->model = MD_4232;
+									break;
 							}
 						}
 						break;
@@ -2747,6 +2844,10 @@
 
 	save_flags(flags);
 	cli();
+	
+	/* Thinkpad is a bit more of PITA than normal. The BIOS tends to
+	   restore it in a different config to the one we use.  Need to
+	   fix this somehow */
 
 	/* store old mixer levels */
 	memcpy(mixer_levels, devc->levels, sizeof (mixer_levels));  
diff -Nur --exclude=*~ linux-2.4.16/drivers/sound/ad1848_mixer.h linux/drivers/sound/ad1848_mixer.h
--- linux-2.4.16/drivers/sound/ad1848_mixer.h	Mon Nov 26 08:35:02 2001
+++ linux/drivers/sound/ad1848_mixer.h	Fri Nov 30 13:09:13 2001
@@ -57,14 +57,14 @@
 				 SOUND_MASK_OGAIN)
 
 struct mixer_def {
-	unsigned int regno:5;		/* register number for volume */
+	unsigned int regno:6;		/* register number for volume */
 	unsigned int polarity:1;	/* volume polarity: 0=normal, 1=reversed */
 	unsigned int bitpos:3;		/* position of bits in register for volume */
 	unsigned int nbits:3;		/* number of bits in register for volume */
-	unsigned int mutereg:5;		/* register number for mute bit */
+	unsigned int mutereg:6;		/* register number for mute bit */
 	unsigned int mutepol:1;		/* mute polarity: 0=normal, 1=reversed */
 	unsigned int mutepos:4;		/* position of mute bit in register */
-	unsigned int recreg:5;		/* register number for recording bit */
+	unsigned int recreg:6;		/* register number for recording bit */
 	unsigned int recpol:1;		/* recording polarity: 0=normal, 1=reversed */
 	unsigned int recpos:4;		/* position of recording bit in register */
 };
@@ -104,43 +104,69 @@
 		    rec_reg_r, rec_pola_r, rec_pos_r}}
 
 static mixer_ents ad1848_mix_devices[32] = {
-MIX_ENT(SOUND_MIXER_VOLUME,	27, 1, 0, 4,	29, 1, 0, 4,  8),
-MIX_ENT(SOUND_MIXER_BASS,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_TREBLE,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_SYNTH,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_PCM,	 6, 1, 0, 6,	 7, 1, 0, 6,  7),
-MIX_ENT(SOUND_MIXER_SPEAKER,	26, 1, 0, 4,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_LINE,	18, 1, 0, 5,	19, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_MIC,	 0, 0, 5, 1,	 1, 0, 5, 1,  8),
-MIX_ENT(SOUND_MIXER_CD,		 2, 1, 0, 5,	 3, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_IMIX,	13, 1, 2, 6,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_RECLEV,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_IGAIN,	 0, 0, 0, 4,	 1, 0, 0, 4,  8),
-MIX_ENT(SOUND_MIXER_OGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_LINE1,	 2, 1, 0, 5,	 3, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_LINE2,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_LINE3,	18, 1, 0, 5,	19, 1, 0, 5,  7)
+	MIX_ENT(SOUND_MIXER_VOLUME,	27, 1, 0, 4,	29, 1, 0, 4,  8),
+	MIX_ENT(SOUND_MIXER_BASS,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_TREBLE,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_SYNTH,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_PCM,	 6, 1, 0, 6,	 7, 1, 0, 6,  7),
+	MIX_ENT(SOUND_MIXER_SPEAKER,	26, 1, 0, 4,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_LINE,	18, 1, 0, 5,	19, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_MIC,	 0, 0, 5, 1,	 1, 0, 5, 1,  8),
+	MIX_ENT(SOUND_MIXER_CD,		 2, 1, 0, 5,	 3, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_IMIX,	13, 1, 2, 6,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_RECLEV,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_IGAIN,	 0, 0, 0, 4,	 1, 0, 0, 4,  8),
+	MIX_ENT(SOUND_MIXER_OGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_LINE1,	 2, 1, 0, 5,	 3, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_LINE2,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_LINE3,	18, 1, 0, 5,	19, 1, 0, 5,  7)
 };
 
 static mixer_ents iwave_mix_devices[32] = {
-MIX_ENT(SOUND_MIXER_VOLUME,	25, 1, 0, 5,	27, 1, 0, 5,  8),
-MIX_ENT(SOUND_MIXER_BASS,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_TREBLE,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_SYNTH,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_PCM,	 6, 1, 0, 6,	 7, 1, 0, 6,  7),
-MIX_ENT(SOUND_MIXER_SPEAKER,	26, 1, 0, 4,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_LINE,	18, 1, 0, 5,	19, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_MIC,	 0, 0, 5, 1,	 1, 0, 5, 1,  8),
-MIX_ENT(SOUND_MIXER_CD,		 2, 1, 0, 5,	 3, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_IMIX,	16, 1, 0, 5,	17, 1, 0, 5,  8),
-MIX_ENT(SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_RECLEV,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_IGAIN,	 0, 0, 0, 4,	 1, 0, 0, 4,  8),
-MIX_ENT(SOUND_MIXER_OGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_LINE1,	 2, 1, 0, 5,	 3, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_LINE2,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_LINE3,	18, 1, 0, 5,	19, 1, 0, 5,  7)
+	MIX_ENT(SOUND_MIXER_VOLUME,	25, 1, 0, 5,	27, 1, 0, 5,  8),
+	MIX_ENT(SOUND_MIXER_BASS,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_TREBLE,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_SYNTH,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_PCM,	 6, 1, 0, 6,	 7, 1, 0, 6,  7),
+	MIX_ENT(SOUND_MIXER_SPEAKER,	26, 1, 0, 4,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_LINE,	18, 1, 0, 5,	19, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_MIC,	 0, 0, 5, 1,	 1, 0, 5, 1,  8),
+	MIX_ENT(SOUND_MIXER_CD,		 2, 1, 0, 5,	 3, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_IMIX,	16, 1, 0, 5,	17, 1, 0, 5,  8),
+	MIX_ENT(SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_RECLEV,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_IGAIN,	 0, 0, 0, 4,	 1, 0, 0, 4,  8),
+	MIX_ENT(SOUND_MIXER_OGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_LINE1,	 2, 1, 0, 5,	 3, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_LINE2,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_LINE3,	18, 1, 0, 5,	19, 1, 0, 5,  7)
+};
+
+static mixer_ents cs42xb_mix_devices[32] = {
+	/* Digital master volume actually has seven bits, but we only use
+	   six to avoid the discontinuity when the analog gain kicks in. */
+	MIX_ENT(SOUND_MIXER_VOLUME,	46, 1, 0, 6,	47, 1, 0, 6,  7),
+	MIX_ENT(SOUND_MIXER_BASS,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_TREBLE,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_SYNTH,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_PCM,	 6, 1, 0, 6,	 7, 1, 0, 6,  7),
+	MIX_ENT(SOUND_MIXER_SPEAKER,	26, 1, 0, 4,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_LINE,	18, 1, 0, 5,	19, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_MIC,	34, 1, 0, 5,	35, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_CD,		 2, 1, 0, 5,	 3, 1, 0, 5,  7),
+	/* For the IMIX entry, it was not possible to use the MIX_ENT macro
+	   because the mute bit is in different positions for the two
+	   channels and requires reverse polarity. */
+	[SOUND_MIXER_IMIX] = {{13, 1, 2, 6, 13, 1, 0, 0, 0, 8},
+		      {42, 1, 0, 6, 42, 1, 7, 0, 0, 8}},
+	MIX_ENT(SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_RECLEV,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_IGAIN,	 0, 0, 0, 4,	 1, 0, 0, 4,  8),
+	MIX_ENT(SOUND_MIXER_OGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_LINE1,	 2, 1, 0, 5,	 3, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_LINE2,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_LINE3,	38, 1, 0, 6,	39, 1, 0, 6,  7)
 };
 
 /* OPTi 82C930 has somewhat different port addresses.
@@ -149,68 +175,68 @@
  * MIC is level of mic monitoring direct to output. Same for CD, LINE, etc.
  */
 static mixer_ents c930_mix_devices[32] = {
-MIX_ENT(SOUND_MIXER_VOLUME,	22, 1, 1, 5,	23, 1, 1, 5,  7),
-MIX_ENT(SOUND_MIXER_BASS,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_TREBLE,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_SYNTH,	 4, 1, 1, 4,	 5, 1, 1, 4,  7),
-MIX_ENT(SOUND_MIXER_PCM,	 6, 1, 0, 5,	 7, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_SPEAKER,	22, 1, 1, 5,	23, 1, 1, 5,  7),
-MIX_ENT(SOUND_MIXER_LINE,	18, 1, 1, 4,	19, 1, 1, 4,  7),
-MIX_ENT(SOUND_MIXER_MIC,	20, 1, 1, 4,	21, 1, 1, 4,  7),
-MIX_ENT(SOUND_MIXER_CD,		 2, 1, 1, 4,	 3, 1, 1, 4,  7),
-MIX_ENT(SOUND_MIXER_IMIX,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_RECLEV,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_IGAIN,	 0, 0, 0, 4,	 1, 0, 0, 4,  8),
-MIX_ENT(SOUND_MIXER_OGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_LINE1,	 2, 1, 1, 4,	 3, 1, 1, 4,  7),
-MIX_ENT(SOUND_MIXER_LINE2,	 4, 1, 1, 4,	 5, 1, 1, 4,  7),
-MIX_ENT(SOUND_MIXER_LINE3,	18, 1, 1, 4,	19, 1, 1, 4,  7)
+	MIX_ENT(SOUND_MIXER_VOLUME,	22, 1, 1, 5,	23, 1, 1, 5,  7),
+	MIX_ENT(SOUND_MIXER_BASS,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_TREBLE,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_SYNTH,	 4, 1, 1, 4,	 5, 1, 1, 4,  7),
+	MIX_ENT(SOUND_MIXER_PCM,	 6, 1, 0, 5,	 7, 1, 0, 5,  7),
+	MIX_ENT(SOUND_MIXER_SPEAKER,	22, 1, 1, 5,	23, 1, 1, 5,  7),
+	MIX_ENT(SOUND_MIXER_LINE,	18, 1, 1, 4,	19, 1, 1, 4,  7),
+	MIX_ENT(SOUND_MIXER_MIC,	20, 1, 1, 4,	21, 1, 1, 4,  7),
+	MIX_ENT(SOUND_MIXER_CD,		 2, 1, 1, 4,	 3, 1, 1, 4,  7),
+	MIX_ENT(SOUND_MIXER_IMIX,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_RECLEV,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_IGAIN,	 0, 0, 0, 4,	 1, 0, 0, 4,  8),
+	MIX_ENT(SOUND_MIXER_OGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
+	MIX_ENT(SOUND_MIXER_LINE1,	 2, 1, 1, 4,	 3, 1, 1, 4,  7),
+	MIX_ENT(SOUND_MIXER_LINE2,	 4, 1, 1, 4,	 5, 1, 1, 4,  7),
+	MIX_ENT(SOUND_MIXER_LINE3,	18, 1, 1, 4,	19, 1, 1, 4,  7)
 };
 
 static mixer_ents spro_mix_devices[32] = {
-MIX_ENT (SOUND_MIXER_VOLUME,	19, 0, 4, 4,			 19, 0, 0, 4,  8),
-MIX_ENT (SOUND_MIXER_BASS,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
-MIX_ENT (SOUND_MIXER_TREBLE,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
-MIX_ENT2(SOUND_MIXER_SYNTH,	 4, 1, 1, 4, 23, 0, 3,  0, 0, 8,
-	 			 5, 1, 1, 4, 23, 0, 3, 0, 0, 8),
-MIX_ENT (SOUND_MIXER_PCM,	 6, 1, 1, 4,			  7, 1, 1, 4,  8),
-MIX_ENT (SOUND_MIXER_SPEAKER,	18, 0, 3, 2,			  0, 0, 0, 0,  8),
-MIX_ENT2(SOUND_MIXER_LINE,	20, 0, 4, 4, 17, 1, 4, 16, 0, 2,
-	 			20, 0, 0, 4, 17, 1, 3, 16, 0, 1),
-MIX_ENT2(SOUND_MIXER_MIC,	18, 0, 0, 3, 17, 1, 0, 16, 0, 0,
-	 			 0, 0, 0, 0,  0, 0, 0,  0, 0, 0),
-MIX_ENT2(SOUND_MIXER_CD,	21, 0, 4, 4, 17, 1, 2, 16, 0, 4,
-				21, 0, 0, 4, 17, 1, 1, 16, 0, 3),
-MIX_ENT (SOUND_MIXER_IMIX,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
-MIX_ENT (SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
-MIX_ENT (SOUND_MIXER_RECLEV,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
-MIX_ENT (SOUND_MIXER_IGAIN,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
-MIX_ENT (SOUND_MIXER_OGAIN,	17, 1, 6, 1,			  0, 0, 0, 0,  8),
-/* This is external wavetable */
-MIX_ENT2(SOUND_MIXER_LINE1,	22, 0, 4, 4, 23, 1, 1, 23, 0, 4,
-	 			22, 0, 0, 4, 23, 1, 0, 23, 0, 5),
+	MIX_ENT (SOUND_MIXER_VOLUME,	19, 0, 4, 4,			 19, 0, 0, 4,  8),
+	MIX_ENT (SOUND_MIXER_BASS,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
+	MIX_ENT (SOUND_MIXER_TREBLE,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
+	MIX_ENT2(SOUND_MIXER_SYNTH,	 4, 1, 1, 4, 23, 0, 3,  0, 0, 8,
+		 			 5, 1, 1, 4, 23, 0, 3, 0, 0, 8),
+	MIX_ENT (SOUND_MIXER_PCM,	 6, 1, 1, 4,			  7, 1, 1, 4,  8),
+	MIX_ENT (SOUND_MIXER_SPEAKER,	18, 0, 3, 2,			  0, 0, 0, 0,  8),
+	MIX_ENT2(SOUND_MIXER_LINE,	20, 0, 4, 4, 17, 1, 4, 16, 0, 2,
+		 			20, 0, 0, 4, 17, 1, 3, 16, 0, 1),
+	MIX_ENT2(SOUND_MIXER_MIC,	18, 0, 0, 3, 17, 1, 0, 16, 0, 0,
+		 			 0, 0, 0, 0,  0, 0, 0,  0, 0, 0),
+	MIX_ENT2(SOUND_MIXER_CD,	21, 0, 4, 4, 17, 1, 2, 16, 0, 4,
+					21, 0, 0, 4, 17, 1, 1, 16, 0, 3),
+	MIX_ENT (SOUND_MIXER_IMIX,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
+	MIX_ENT (SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
+	MIX_ENT (SOUND_MIXER_RECLEV,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
+	MIX_ENT (SOUND_MIXER_IGAIN,	 0, 0, 0, 0,			  0, 0, 0, 0,  8),
+	MIX_ENT (SOUND_MIXER_OGAIN,	17, 1, 6, 1,			  0, 0, 0, 0,  8),
+	/* This is external wavetable */
+	MIX_ENT2(SOUND_MIXER_LINE1,	22, 0, 4, 4, 23, 1, 1, 23, 0, 4,
+		 			22, 0, 0, 4, 23, 1, 0, 23, 0, 5),
 };
 
 static int default_mixer_levels[32] =
 {
-  0x3232,			/* Master Volume */
-  0x3232,			/* Bass */
-  0x3232,			/* Treble */
-  0x4b4b,			/* FM */
-  0x3232,			/* PCM */
-  0x1515,			/* PC Speaker */
-  0x2020,			/* Ext Line */
-  0x1010,			/* Mic */
-  0x4b4b,			/* CD */
-  0x0000,			/* Recording monitor */
-  0x4b4b,			/* Second PCM */
-  0x4b4b,			/* Recording level */
-  0x4b4b,			/* Input gain */
-  0x4b4b,			/* Output gain */
-  0x2020,			/* Line1 */
-  0x2020,			/* Line2 */
-  0x1515			/* Line3 (usually line in)*/
+	0x3232,			/* Master Volume */
+	0x3232,			/* Bass */
+	0x3232,			/* Treble */
+	0x4b4b,			/* FM */
+	0x3232,			/* PCM */
+	0x1515,			/* PC Speaker */
+	0x2020,			/* Ext Line */
+	0x1010,			/* Mic */
+	0x4b4b,			/* CD */
+	0x0000,			/* Recording monitor */
+	0x4b4b,			/* Second PCM */
+	0x4b4b,			/* Recording level */
+	0x4b4b,			/* Input gain */
+	0x4b4b,			/* Output gain */
+	0x2020,			/* Line1 */
+	0x2020,			/* Line2 */
+	0x1515			/* Line3 (usually line in)*/
 };
 
 #define LEFT_CHN	0
diff -Nur --exclude=*~ linux-2.4.16/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c
--- linux-2.4.16/drivers/sound/i810_audio.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/sound/i810_audio.c	Wed Nov 28 18:15:57 2001
@@ -1405,10 +1405,9 @@
 		if (dmabuf->count < 0) {
 			dmabuf->count = 0;
 		}
-		cnt = dmabuf->dmasize - dmabuf->fragsize - dmabuf->count;
-		// this is to make the copy_from_user simpler below
-		if(cnt > (dmabuf->dmasize - swptr))
-			cnt = dmabuf->dmasize - swptr;
+		cnt = dmabuf->dmasize - swptr;
+		if(cnt > (dmabuf->dmasize - dmabuf->count))
+			cnt = dmabuf->dmasize - dmabuf->count;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
 #ifdef DEBUG2
@@ -1419,16 +1418,13 @@
 		if (cnt <= 0) {
 			unsigned long tmo;
 			// There is data waiting to be played
+			i810_update_lvi(state,0);
 			if(!dmabuf->enable && dmabuf->count) {
 				/* force the starting incase SETTRIGGER has been used */
 				/* to stop it, otherwise this is a deadlock situation */
 				dmabuf->trigger |= PCM_ENABLE_OUTPUT;
 				start_dac(state);
 			}
-			// Update the LVI pointer in case we have already
-			// written data in this syscall and are just waiting
-			// on the tail bit of data
-			i810_update_lvi(state,0);
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret) ret = -EAGAIN;
 				goto ret;
@@ -1860,7 +1856,7 @@
 		if(dmabuf->mapped)
 			abinfo.bytes = dmabuf->count;
 		else
-			abinfo.bytes = dmabuf->dmasize - dmabuf->count;
+			abinfo.bytes = dmabuf->dmasize - dmabuf->fragsize - dmabuf->count;
 		abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 #ifdef DEBUG
diff -Nur --exclude=*~ linux-2.4.16/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- linux-2.4.16/drivers/sound/sb_card.c	Mon Nov 26 08:35:02 2001
+++ linux/drivers/sound/sb_card.c	Wed Nov 28 18:15:57 2001
@@ -378,6 +378,11 @@
 		0,0,0,0,
 		0,1,1,-1},
 	{"Sound Blaster AWE 32",
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0047),
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster AWE 32",
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0048), 
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
 		0,0,0,0,
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/dabusb.c linux/drivers/usb/dabusb.c
--- linux-2.4.16/drivers/usb/dabusb.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/dabusb.c	Fri Nov 30 15:58:46 2001
@@ -224,7 +224,7 @@
 			err("kmalloc(sizeof(buff_t))==NULL");
 			goto err;
 		}
-		memset (b, sizeof (buff_t), 0);
+		memset (b, 0, sizeof (buff_t));
 		b->s = s;
 		b->purb = usb_alloc_urb(packets);
 		if (!b->purb) {
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/dc2xx.c linux/drivers/usb/dc2xx.c
--- linux-2.4.16/drivers/usb/dc2xx.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/dc2xx.c	Fri Nov 30 15:58:49 2001
@@ -112,12 +112,15 @@
 	/* These have a different application level protocol which
 	 * is part of the Flashpoint "DigitaOS".  That supports some
 	 * non-camera devices, and some non-Kodak cameras.
+	 * Use this driver to get USB and "OpenDis" to talk.
 	 */  
 	{ USB_DEVICE(0x040a, 0x0100) },		// Kodak DC-220
 	{ USB_DEVICE(0x040a, 0x0110) },		// Kodak DC-260
 	{ USB_DEVICE(0x040a, 0x0111) },		// Kodak DC-265
 	{ USB_DEVICE(0x040a, 0x0112) },		// Kodak DC-290
 	{ USB_DEVICE(0xf003, 0x6002) },		// HP PhotoSmart C500
+	{ USB_DEVICE(0x03f0, 0x4102) },		// HP PhotoSmart C618
+	{ USB_DEVICE(0x0a17, 0x1001) },		// Pentax EI-200
 
 	/* Other USB devices may well work here too, so long as they
 	 * just stick to half duplex bulk packet exchanges.  That
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/hid-core.c linux/drivers/usb/hid-core.c
--- linux-2.4.16/drivers/usb/hid-core.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/hid-core.c	Fri Nov 30 15:58:50 2001
@@ -1236,7 +1236,7 @@
 
 	c = "Device";
 	for (i = 0; i < hid->maxapplication; i++)
-		if (IS_INPUT_APPLICATION(hid->application[i])) {
+		if ((hid->application[i] & 0xffff) < ARRAY_SIZE(hid_types)) {
 			c = hid_types[hid->application[i] & 0xffff];
 			break;
 		}
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/pwc-ctrl.c linux/drivers/usb/pwc-ctrl.c
--- linux-2.4.16/drivers/usb/pwc-ctrl.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/pwc-ctrl.c	Fri Nov 30 15:58:51 2001
@@ -782,7 +782,7 @@
 {
 	char buf;
 
-	if (pdev->type < 675 || pdev->release < 6)
+	if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6))
 		return 0;	/* Not supported by Nala or Timon < release 6 */
 
 	if (power)
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/pwc-if.c linux/drivers/usb/pwc-if.c
--- linux-2.4.16/drivers/usb/pwc-if.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/pwc-if.c	Fri Nov 30 15:58:51 2001
@@ -91,6 +91,8 @@
 	disconnect:		usb_pwc_disconnect,	/* disconnect() */
 };
 
+#define MAX_DEV_HINTS 10
+
 static int default_size = PSZ_QCIF;
 static int default_fps = 10;
 static int default_palette = VIDEO_PALETTE_YUV420P; /* This format is understood by most tools */
@@ -99,13 +101,17 @@
        int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
 static int power_save = 0;
 static int led_on = 1, led_off = 0; /* defaults to LED that is on while in use */
-int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
+       int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
+static struct {
+	int type;
+	char serial_number[30];
+	int device_node;
+	struct pwc_device *pdev;
+} device_hint[MAX_DEV_HINTS];
 
 static struct semaphore mem_lock;
 static void *mem_leak = NULL; /* For delayed kfree()s. See below */
 
-static int video_nr = -1;
-
 /***/
 
 static int  pwc_video_open(struct video_device *vdev, int mode);
@@ -647,7 +653,8 @@
 		errmsg = "Unknown";
 		switch(urb->status) {
 			case -ENOSR:		errmsg = "Buffer error (overrun)"; break;
-			case -EPIPE:		errmsg = "Babble/stalled (bad cable?)"; break;
+			case -EPIPE:		errmsg = "Stalled (device not responding)"; break;
+			case -EOVERFLOW:	errmsg = "Babble (bad cable?)"; break;
 			case -EPROTO:		errmsg = "Bit-stuff error (bad cable?)"; break;
 			case -EILSEQ:		errmsg = "CRC/Timeout"; break;
 			case -ETIMEDOUT:	errmsg = "NAK (device does not respond)"; break;
@@ -765,6 +772,11 @@
 			} /* .. flen < last_packet_size */
 			pdev->vlast_packet_size = flen;
 		} /* ..status == 0 */
+#ifdef PWC_DEBUG
+		/* This is normally not interesting to the user, unless you are really debugging something */
+		else 
+			Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
+#endif			
 	}
 	if (awake)
 		wake_up_interruptible(&pdev->frameq);
@@ -1140,7 +1152,7 @@
 	                	return -ERESTARTSYS;
 	                }
 	                schedule();
-	                set_current_state(TASK_INTERRUPTIBLE);
+	               	set_current_state(TASK_INTERRUPTIBLE);
 		}
 		remove_wait_queue(&pdev->frameq, &wait);
 		set_current_state(TASK_RUNNING);
@@ -1595,7 +1607,9 @@
 	struct pwc_device *pdev = NULL;
 	struct video_device *vdev;
 	int vendor_id, product_id, type_id;
-	int i;
+	int i, hint;
+	int video_nr = -1; /* default: use next available device */
+	char serial_number[30];
 
 	free_mem_leak();
 	
@@ -1698,6 +1712,10 @@
 	}
 	else return NULL; /* Not Philips, Askey, Logitech or Samsung, for sure. */
 
+	memset(serial_number, 0, 30);
+	usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
+	Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number);
+
 	if (udev->descriptor.bNumConfigurations > 1)
 		Info("Warning: more than 1 configuration available.\n");
 
@@ -1734,6 +1752,21 @@
 	pdev->release = udev->descriptor.bcdDevice;
 	Trace(TRACE_PROBE, "Release: %04x\n", pdev->release);
 
+
+	/* Now search device_hint[] table for a match, so we can hint a node number. */
+	for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
+		if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) &&
+		     (device_hint[hint].pdev == NULL)) {
+			/* so far, so good... try serial number */
+			if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
+			    	/* match! */
+			    	video_nr = device_hint[hint].device_node;
+			    	Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr);
+			    	break;
+			}
+		}
+	}
+
 	i = video_register_device(vdev, VFL_TYPE_GRABBER, video_nr);
 	if (i < 0) {
 		Err("Failed to register as video device (%d).\n", i);
@@ -1743,6 +1776,9 @@
 		Trace(TRACE_PROBE, "Registered video struct at 0x%p.\n", vdev);
 		Info("Registered as /dev/video%d.\n", vdev->minor & 0x3F);
 	}
+	/* occupy slot */
+	if (hint < MAX_DEV_HINTS) 
+		device_hint[hint].pdev = pdev;
 
 #if 0
 	/* Shut down camera now (some people like the LED off) */
@@ -1762,6 +1798,7 @@
 static void usb_pwc_disconnect(struct usb_device *udev, void *ptr)
 {
 	struct pwc_device *pdev;
+	int hint;
 
 	lock_kernel();
 	free_mem_leak();
@@ -1815,12 +1852,31 @@
 			pdev->vdev = NULL;
 		}
 	}
+
+	/* search device_hint[] table if we occupy a slot, by any chance */
+	for (hint = 0; hint < MAX_DEV_HINTS; hint++)
+		if (device_hint[hint].pdev == pdev)
+			device_hint[hint].pdev = NULL;
+
 	pdev->udev = NULL;
 	unlock_kernel();
 	kfree(pdev);
 }
 
 
+/* *grunt* We have to do atoi ourselves :-( */
+static int pwc_atoi(char *s)
+{
+	int k = 0;
+	
+	k = 0;
+	while (*s != '\0' && *s >= '0' && *s <= '9') {
+		k = 10 * k + (*s - '0');
+		s++;
+	}
+	return k;
+}
+
 
 /* 
  * Initialization code & module stuff 
@@ -1833,8 +1889,8 @@
 static int trace = -1;
 static int compression = -1;
 static int leds[2] = { -1, -1 };
+static char *dev_hint[10] = { };
 
-MODULE_PARM(video_nr, "i");
 MODULE_PARM(size, "s");
 MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
 MODULE_PARM(fps, "i");
@@ -1851,13 +1907,16 @@
 MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
 MODULE_PARM(leds, "2i");
 MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
+MODULE_PARM(dev_hint, "0-10s");
+MODULE_PARM_DESC(dev_hint, "Device node hints");
+
 MODULE_DESCRIPTION("Philips USB webcam driver");
 MODULE_AUTHOR("Nemosoft Unv. <nemosoft@smcc.demon.nl>");
 MODULE_LICENSE("GPL");
 
 static int __init usb_pwc_init(void)
 {
-	int s;
+	int i, sz;
 	char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
 
 	Info("Philips PCA645/646 + PCVC675/680/690 + PCVC730/740/750 webcam module version " PWC_VERSION " loaded.\n");
@@ -1874,13 +1933,13 @@
 	
 	if (size) {
 		/* string; try matching with array */
-		for (s = 0; s < PSZ_MAX; s++) {
-			if (!strcmp(sizenames[s], size)) { /* Found! */
-				default_size = s;
+		for (sz = 0; sz < PSZ_MAX; sz++) {
+			if (!strcmp(sizenames[sz], size)) { /* Found! */
+				default_size = sz;
 				break;
 			}
 		}
-		if (s == PSZ_MAX) {
+		if (sz == PSZ_MAX) {
 			Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
 			return -EINVAL;
 		}
@@ -1920,6 +1979,74 @@
 		led_on = leds[0] / 100;
 	if (leds[1] >= 0)
 		led_off = leds[1] / 100;
+
+	/* Big device node whoopla. Basicly, it allows you to assign a 
+	   device node (/dev/videoX) to a camera, based on its type 
+	   & serial number. The format is [type[.serialnumber]:]node.
+
+           Any camera that isn't matched by these rules gets the next 
+           available free device node.
+	 */
+	for (i = 0; i < MAX_DEV_HINTS; i++) {
+		char *s, *colon, *dot;
+
+		/* This loop also initializes the array */
+		device_hint[i].pdev = NULL;
+		s = dev_hint[i];
+		if (s != NULL && *s != '\0') {
+			device_hint[i].type = -1; /* wildcard */
+			strcpy(device_hint[i].serial_number, "*");
+
+			/* parse string: chop at ':' & '/' */
+			colon = dot = s;
+			while (*colon != '\0' && *colon != ':')
+				colon++;
+			while (*dot != '\0' && *dot != '.')
+				dot++;
+			/* Few sanity checks */
+			if (*dot != '\0' && dot > colon) {
+				Err("Malformed camera hint: the colon must be after the dot.\n");
+				return -EINVAL;
+			}
+
+			if (*colon == '\0') {
+				/* No colon */
+				if (*dot != '\0') {
+					Err("Malformed camera hint: no colon + device node given.\n");
+					return -EINVAL;
+				}
+				else {
+					/* No type or serial number specified, just a number. */
+					device_hint[i].device_node = pwc_atoi(s);
+				}
+			}
+			else {
+				/* There's a colon, so we have at least a type and a device node */
+				device_hint[i].type = pwc_atoi(s);
+				device_hint[i].device_node = pwc_atoi(colon + 1);
+				if (*dot != '\0') {
+					/* There's a serial number as well */
+					int k;
+					
+					dot++;
+					k = 0;
+					while (*dot != ':' && k < 29) {
+						device_hint[i].serial_number[k++] = *dot;
+						dot++;
+					}
+					device_hint[i].serial_number[k] = '\0';
+				}
+			}
+#ifdef PWC_DEBUG		
+			Debug("device_hint[%d]:\n", i);
+			Debug("  type    : %d\n", device_hint[i].type);
+			Debug("  serial# : %s\n", device_hint[i].serial_number);
+			Debug("  node    : %d\n", device_hint[i].device_node);
+#endif			
+		}
+		else
+			device_hint[i].type = 0; /* not filled */
+	} /* ..for MAX_DEV_HINTS */
 
 	init_MUTEX(&mem_lock);
  	Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver);
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/pwc.h linux/drivers/usb/pwc.h
--- linux-2.4.16/drivers/usb/pwc.h	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/pwc.h	Fri Nov 30 19:05:50 2001
@@ -60,8 +60,8 @@
 
 /* Version block */
 #define PWC_MAJOR	8
-#define PWC_MINOR	3
-#define PWC_VERSION 	"8.3"
+#define PWC_MINOR	4
+#define PWC_VERSION 	"8.4"
 #define PWC_NAME 	"pwc"
 
 /* Turn certain features on/off */
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/scanner.c linux/drivers/usb/scanner.c
--- linux-2.4.16/drivers/usb/scanner.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/scanner.c	Fri Nov 30 15:58:52 2001
@@ -278,6 +278,28 @@
  *    - Users are now notified to consult the Documentation/usb/scanner.txt
  *      for common error messages rather than the maintainer.
  *
+ * 0.4.7  11/28/2001
+ *    - Fixed typo in Documentation/scanner.txt.  Thanks to
+ *      Karel <karel.vervaeke@pandora.be> for pointing it out.
+ *    - Added ID's for a Memorex 6136u. Thanks to Álvaro Gaspar de
+ *      Valenzuela" <agaspard@utsi.edu>.
+ *    - Added ID's for Agfa e25.  Thanks to Heinrich 
+ *      Rust <Heinrich.Rust@gmx.de>.  Also reported to work with
+ *      Linux and SANE (?).
+ *    - Added Canon FB620U, D646U, and 1220U ID's.  Thanks to Paul
+ *      Rensing <Paul_Rensing@StanfordAlumni.org>.  For more info
+ *      on Linux support for these models, contact 
+ *      salvestrini@users.sourceforge.net.
+ *    - Added Plustek OpticPro UT12, OpticPro U24, KYE/Genius
+ *      ColorPage-HR6 V2 ID's in addition to many "Unknown" models
+ *      under those vendors.  Thanks to
+ *      Jaeger, Gerhard" <g.jaeger@earthling.net>.  These scanner are
+ *      apparently based upon the LM983x IC's.
+ *    - Applied Frank's patch that addressed some locking and module
+ *      referencing counts.  Thanks to both
+ *      Frank Zago <fzago@greshamstorage.com> and
+ *      Oliver Neukum <520047054719-0001@t-online.de> for reviewing/testing.
+ *
  * TODO
  *    - Performance
  *    - Select/poll methods
@@ -324,17 +346,16 @@
 	struct scn_usb_data *scn;
 	unsigned char *data;
 	scn = urb->context;
-	down(&(scn->sem));
+
 	data = &scn->button;
 	data += 0;		/* Keep gcc from complaining about unused var */
 
 	if (urb->status) {
-		up(&(scn->sem));
 		return;
 	}
 
 	dbg("irq_scanner(%d): data:%x", scn->scn_minor, *data);
-	up(&(scn->sem));
+
 	return;
 }
 
@@ -358,6 +379,7 @@
 
 	if (!p_scn_table[scn_minor]) {
 		up(&scn_mutex);
+		MOD_DEC_USE_COUNT;
 		err("open_scanner(%d): Unable to access minor data", scn_minor);
 		return -ENODEV;
 	}
@@ -939,6 +961,7 @@
 /* Check to make sure that the last slot isn't already taken */
 	if (p_scn_table[scn_minor]) {
 		err("probe_scanner: No more minor devices remaining.");
+		up(&scn_mutex);
 		return NULL;
 	}
 
@@ -946,6 +969,7 @@
 
 	if (!(scn = kmalloc (sizeof (struct scn_usb_data), GFP_KERNEL))) {
 		err("probe_scanner: Out of memory.");
+		up(&scn_mutex);
 		return NULL;
 	}
 	memset (scn, 0, sizeof(struct scn_usb_data));
@@ -1028,9 +1052,11 @@
 	if (scn->devfs == NULL)
 		dbg("scanner%d: device node registration failed", scn_minor);
 
+	p_scn_table[scn_minor] = scn;
+
 	up(&scn_mutex);
 
-	return p_scn_table[scn_minor] = scn;
+	return scn;
 }
 
 static void
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/scanner.h linux/drivers/usb/scanner.h
--- linux-2.4.16/drivers/usb/scanner.h	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/scanner.h	Fri Nov 30 19:05:46 2001
@@ -86,12 +86,23 @@
 	{ USB_DEVICE(0x06bd, 0x2061) },	/* Another SnapScan 1212U (?)*/
 	{ USB_DEVICE(0x06bd, 0x0100) },	/* SnapScan Touch */
 	{ USB_DEVICE(0x06bd, 0x2091) }, /* SnapScan e20 */
+	{ USB_DEVICE(0x06bd, 0x2095) }, /* SnapScan e25 */
 	{ USB_DEVICE(0x06bd, 0x2097) }, /* SnapScan e26 */
 	{ USB_DEVICE(0x06bd, 0x208d) }, /* Snapscan e40 */
+	/* Canon */
+	{ USB_DEVICE(0x04a9, 0x2202) }, /* FB620U */
+	{ USB_DEVICE(0x04a9, 0x220b) }, /* D646U */
+	{ USB_DEVICE(0x04a9, 0x2207) }, /* 1220U */
 	/* Colorado -- See Primax/Colorado below */
 	/* Epson -- See Seiko/Epson below */
 	/* Genius */
 	{ USB_DEVICE(0x0458, 0x2001) },	/* ColorPage-Vivid Pro */
+	{ USB_DEVICE(0x0458, 0x2007) },	/* ColorPage HR6 V2 */
+	{ USB_DEVICE(0x0458, 0x2008) },	/* Unknown */
+	{ USB_DEVICE(0x0458, 0x2009) },	/* Unknown */
+	{ USB_DEVICE(0x0458, 0x2013) },	/* Unknown */
+	{ USB_DEVICE(0x0458, 0x2015) },	/* Unknown  */
+	{ USB_DEVICE(0x0458, 0x2016) },	/* Unknown  */
 	/* Hewlett Packard */
 	{ USB_DEVICE(0x03f0, 0x0205) },	/* 3300C */
 	{ USB_DEVICE(0x03f0, 0x0405) }, /* 3400C */
@@ -108,6 +119,8 @@
 	{ USB_DEVICE(0x0638, 0x0268) }, /* 1200U */
 	/* Lifetec */
 	{ USB_DEVICE(0x05d8, 0x4002) }, /* Lifetec LT9385 */
+	/* Memorex */
+	{ USB_DEVICE(0x0461, 0x0346) }, /* 6136u - repackaged Primax ? */
 	/* Microtek -- No longer supported - Enable SCSI and USB Microtek in kernel config */
 	//	{ USB_DEVICE(0x05da, 0x0099) },	/* ScanMaker X6 - X6U */
 	//	{ USB_DEVICE(0x05da, 0x0094) },	/* Phantom 336CX - C3 */
@@ -128,6 +141,19 @@
 	{ USB_DEVICE(0x0400, 0x1001) }, /* BearPaw 2400 */
 	{ USB_DEVICE(0x055f, 0x0008) }, /* 1200 CU Plus */
 	{ USB_DEVICE(0x0ff5, 0x0010) }, /* BearPaw 1200F */
+	/* Plustek */
+	{ USB_DEVICE(0x07b3, 0x0017) }, /* OpticPro UT12 */
+	{ USB_DEVICE(0x07b3, 0x0011) }, /* OpticPro UT24 */
+	{ USB_DEVICE(0x07b3, 0x0005) }, /* Unknown */
+	{ USB_DEVICE(0x07b3, 0x0007) }, /* Unknown */
+	{ USB_DEVICE(0x07b3, 0x000F) }, /* Unknown */
+	{ USB_DEVICE(0x07b3, 0x0010) }, /* Unknown */
+	{ USB_DEVICE(0x07b3, 0x0012) }, /* Unknown */
+	{ USB_DEVICE(0x07b3, 0x0013) }, /* Unknown */
+	{ USB_DEVICE(0x07b3, 0x0014) }, /* Unknown */
+	{ USB_DEVICE(0x07b3, 0x0015) }, /* Unknown */
+	{ USB_DEVICE(0x07b3, 0x0016) }, /* Unknown */
+	{ USB_DEVICE(0x07b3, 0x0012) }, /* Unknown */
 	/* Primax/Colorado */
 	{ USB_DEVICE(0x0461, 0x0300) },	/* G2-300 #1 */
 	{ USB_DEVICE(0x0461, 0x0380) },	/* G2-600 #1 */
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/serial/belkin_sa.c linux/drivers/usb/serial/belkin_sa.c
--- linux-2.4.16/drivers/usb/serial/belkin_sa.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/serial/belkin_sa.c	Fri Nov 30 15:58:57 2001
@@ -140,7 +140,7 @@
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
 /* All of the device info needed for the Belkin dockstation serial converter */
-struct usb_serial_device_type belkin_dockstation_device = {
+static struct usb_serial_device_type belkin_dockstation_device = {
 	name:			"Belkin F5U120-PC USB Serial Adapter",
 	id_table:		belkin_dockstation_table,		/* the Belkin F5U103 device */
 	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
@@ -161,7 +161,7 @@
 };
 
 /* All of the device info needed for the Belkin serial converter */
-struct usb_serial_device_type belkin_sa_device = {
+static struct usb_serial_device_type belkin_sa_device = {
 	name:			"Belkin F5U103 USB Serial Adapter",
 	id_table:		belkin_sa_table,		/* the Belkin F5U103 device */
 	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
@@ -183,7 +183,7 @@
 
 
 /* This driver also supports the "old" school Belkin single port adaptor */
-struct usb_serial_device_type belkin_old_device = {
+static struct usb_serial_device_type belkin_old_device = {
 	name:			"Belkin USB Serial Adapter",
 	id_table:		belkin_old_table,		/* the old Belkin device */
 	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
@@ -204,7 +204,7 @@
 };
 
 /* this driver also works for the Peracom single port adapter */
-struct usb_serial_device_type peracom_device = {
+static struct usb_serial_device_type peracom_device = {
 	name:			"Peracom single port USB Serial Adapter",
 	id_table:		peracom_table,			/* the Peracom device */
 	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
@@ -225,7 +225,7 @@
 };
 
 /* the GoHubs Go-COM232 device is the same as the Peracom single port adapter */
-struct usb_serial_device_type gocom232_device = {
+static struct usb_serial_device_type gocom232_device = {
 	name:			"GO-COM232 USB Serial Converter",
 	id_table:		gocom232_table,			/* the GO-COM232 device */
 	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/serial/cyberjack.c linux/drivers/usb/serial/cyberjack.c
--- linux-2.4.16/drivers/usb/serial/cyberjack.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/serial/cyberjack.c	Fri Nov 30 15:58:57 2001
@@ -76,7 +76,7 @@
 
 MODULE_DEVICE_TABLE (usb, id_table);
 
-struct usb_serial_device_type cyberjack_device = {
+static struct usb_serial_device_type cyberjack_device = {
 	name:			"Reiner SCT Cyberjack USB card reader",
 	id_table:		id_table,
 	needs_interrupt_in:	MUST_HAVE,
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/serial/empeg.c linux/drivers/usb/serial/empeg.c
--- linux-2.4.16/drivers/usb/serial/empeg.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/serial/empeg.c	Fri Nov 30 15:58:57 2001
@@ -113,7 +113,7 @@
 
 MODULE_DEVICE_TABLE (usb, id_table);
 
-struct usb_serial_device_type empeg_device = {
+static struct usb_serial_device_type empeg_device = {
 	name:			"Empeg",
 	id_table:		id_table,
 	needs_interrupt_in:	MUST_HAVE_NOT,	/* must not have an interrupt in endpoint */
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c
--- linux-2.4.16/drivers/usb/serial/ftdi_sio.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/serial/ftdi_sio.c	Fri Nov 30 15:58:57 2001
@@ -173,7 +173,7 @@
 /* Should rename most ftdi_sio's to ftdi_ now since there are two devices 
    which share common code */ 
 
-struct usb_serial_device_type ftdi_sio_device = {
+static struct usb_serial_device_type ftdi_sio_device = {
 	name:			"FTDI SIO",
 	id_table:		id_table_sio,
 	needs_interrupt_in:	MUST_HAVE_NOT,
@@ -196,7 +196,7 @@
         shutdown:               ftdi_sio_shutdown,
 };
 
-struct usb_serial_device_type ftdi_8U232AM_device = {
+static struct usb_serial_device_type ftdi_8U232AM_device = {
 	name:			"FTDI 8U232AM",
 	id_table:		id_table_8U232AM,
 	needs_interrupt_in:	DONT_CARE,
@@ -660,7 +660,7 @@
 } /* ftdi_sio_serial_read_bulk_callback */
 
 
-__u16 translate_baudrate_to_ftdi(unsigned int cflag, ftdi_type_t ftdi_type) 
+static __u16 translate_baudrate_to_ftdi(unsigned int cflag, ftdi_type_t ftdi_type) 
 { /* translate_baudrate_to_ftdi */
 	
 	__u16 urb_value = ftdi_sio_b9600;
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/serial/io_edgeport.c linux/drivers/usb/serial/io_edgeport.c
--- linux-2.4.16/drivers/usb/serial/io_edgeport.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/serial/io_edgeport.c	Fri Nov 30 15:58:57 2001
@@ -318,11 +318,6 @@
 };
 
 
-/* the info for all of the devices that this driver supports */
-int EdgeportDevices[] = EDGEPORT_DEVICE_IDS;
-#define NUM_EDGEPORT_DEVICES (sizeof(EdgeportDevices) / sizeof(int))
-
-
 /* Transmit Fifo 
  * This Transmit queue is an extension of the edgeport Rx buffer. 
  * The maximum amount of data buffered in both the edgeport 
@@ -495,17 +490,15 @@
 // ************************************************************************
 // ************************************************************************
 
-// These functions should be in firmware.c
-
 /************************************************************************
  *									*
- *	update_edgeport_E2PROM()	Compare current versions of		*
+ * update_edgeport_E2PROM()	Compare current versions of		*
  *				Boot ROM and Manufacture 		*
  *				Descriptors with versions		*
  *				embedded in this driver			*
  *									*
  ************************************************************************/
-void update_edgeport_E2PROM (struct edgeport_serial *edge_serial)
+static void update_edgeport_E2PROM (struct edgeport_serial *edge_serial)
 {
 	__u32 BootCurVer;
 	__u32 BootNewVer;
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/serial/keyspan.c linux/drivers/usb/serial/keyspan.c
--- linux-2.4.16/drivers/usb/serial/keyspan.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/serial/keyspan.c	Fri Nov 30 15:58:57 2001
@@ -176,7 +176,7 @@
 
 
 /* Functions used by new usb-serial code. */
-int keyspan_init (void)
+static int __init keyspan_init (void)
 {
 	usb_serial_register (&keyspan_usa18x_pre_device);
 	usb_serial_register (&keyspan_usa19_pre_device);
@@ -201,7 +201,7 @@
 	return 0;
 }
 
-void keyspan_exit (void)
+static void __exit keyspan_exit (void)
 {
 	usb_serial_deregister (&keyspan_usa18x_pre_device);
 	usb_serial_deregister (&keyspan_usa19_pre_device);
@@ -1089,7 +1089,7 @@
 	return urb;
 }
 
-struct callbacks {
+static struct callbacks {
 	void	(*instat_callback)(urb_t *);
 	void	(*glocont_callback)(urb_t *);
 	void	(*indat_callback)(urb_t *);
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/serial/keyspan.h linux/drivers/usb/serial/keyspan.h
--- linux-2.4.16/drivers/usb/serial/keyspan.h	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/serial/keyspan.h	Fri Nov 30 19:05:58 2001
@@ -448,7 +448,7 @@
 };
 
     /* Structs for the devices, pre and post renumeration. */
-struct usb_serial_device_type keyspan_usa18x_pre_device = {
+static struct usb_serial_device_type keyspan_usa18x_pre_device = {
 	name:			"Keyspan USA18X - (without firmware)",
 	id_table:		keyspan_usa18x_pre_ids,
 	needs_interrupt_in:	DONT_CARE,
@@ -461,7 +461,7 @@
 	startup:		keyspan_fake_startup	
 };
 
-struct usb_serial_device_type keyspan_usa19_pre_device = {
+static struct usb_serial_device_type keyspan_usa19_pre_device = {
 	name:			"Keyspan USA19 - (without firmware)",
 	id_table:		keyspan_usa19_pre_ids,
 	needs_interrupt_in:	DONT_CARE,
@@ -475,7 +475,7 @@
 };
 
 
-struct usb_serial_device_type keyspan_usa19w_pre_device = {
+static struct usb_serial_device_type keyspan_usa19w_pre_device = {
 	name:			"Keyspan USA19W - (without firmware)",
 	id_table:		keyspan_usa19w_pre_ids,
 	needs_interrupt_in:	DONT_CARE,
@@ -489,7 +489,7 @@
 };
 
 
-struct usb_serial_device_type keyspan_usa28_pre_device = {
+static struct usb_serial_device_type keyspan_usa28_pre_device = {
 	name:			"Keyspan USA28 - (without firmware)",
 	id_table:		keyspan_usa28_pre_ids,
 	needs_interrupt_in:	DONT_CARE,
@@ -502,7 +502,7 @@
 	startup:		keyspan_fake_startup	
 };
 
-struct usb_serial_device_type keyspan_usa28x_pre_device = {
+static struct usb_serial_device_type keyspan_usa28x_pre_device = {
 	name:			"Keyspan USA28X - (without firmware)",
 	id_table:		keyspan_usa28x_pre_ids,
 	needs_interrupt_in:	DONT_CARE,
@@ -515,7 +515,7 @@
 	startup:		keyspan_fake_startup	
 };
 
-struct usb_serial_device_type keyspan_usa28xa_pre_device = {
+static struct usb_serial_device_type keyspan_usa28xa_pre_device = {
 	name:			"Keyspan USA28XA - (without firmware)",
 	id_table:		keyspan_usa28xa_pre_ids,
 	needs_interrupt_in:	DONT_CARE,
@@ -528,7 +528,7 @@
 	startup:		keyspan_fake_startup	
 };
 
-struct usb_serial_device_type keyspan_usa28xb_pre_device = {
+static struct usb_serial_device_type keyspan_usa28xb_pre_device = {
 	name:			"Keyspan USA28XB - (without firmware)",
 	id_table:		keyspan_usa28xb_pre_ids,
 	needs_interrupt_in:	DONT_CARE,
@@ -541,7 +541,7 @@
 	startup:		keyspan_fake_startup	
 };
 
-struct usb_serial_device_type keyspan_usa49w_pre_device = {
+static struct usb_serial_device_type keyspan_usa49w_pre_device = {
 	name:			"Keyspan USA49W - (without firmware)",
 	id_table:		keyspan_usa49w_pre_ids,
 	needs_interrupt_in:	DONT_CARE,
@@ -554,7 +554,7 @@
 	startup:		keyspan_fake_startup	
 };
 
-struct usb_serial_device_type keyspan_usa18x_device = {
+static struct usb_serial_device_type keyspan_usa18x_device = {
 	name:			"Keyspan USA18X",
 	id_table:		keyspan_usa18x_ids,
 	needs_interrupt_in:	DONT_CARE,	
@@ -580,7 +580,7 @@
 	shutdown:		keyspan_shutdown,
 };
 
-struct usb_serial_device_type keyspan_usa19_device = {
+static struct usb_serial_device_type keyspan_usa19_device = {
 	name:			"Keyspan USA19",
 	id_table:		keyspan_usa19_ids,
 	needs_interrupt_in:	DONT_CARE,	
@@ -607,7 +607,7 @@
 };
 
 
-struct usb_serial_device_type keyspan_usa19w_device = {
+static struct usb_serial_device_type keyspan_usa19w_device = {
 	name:			"Keyspan USA19W",
 	id_table:		keyspan_usa19w_ids,
 	needs_interrupt_in:	DONT_CARE,	
@@ -634,7 +634,7 @@
 };
 
 
-struct usb_serial_device_type keyspan_usa28_device = {
+static struct usb_serial_device_type keyspan_usa28_device = {
 	name:			"Keyspan USA28",
 	id_table:		keyspan_usa28_ids,
 	needs_interrupt_in:	DONT_CARE,	
@@ -652,7 +652,7 @@
 };
 
 
-struct usb_serial_device_type keyspan_usa28x_device = {
+static struct usb_serial_device_type keyspan_usa28x_device = {
 	name:			"Keyspan USA28X/XB",
 	id_table:		keyspan_usa28x_ids,
 	needs_interrupt_in:	DONT_CARE,	
@@ -679,7 +679,7 @@
 
 };
 
-struct usb_serial_device_type keyspan_usa28xa_device = {
+static struct usb_serial_device_type keyspan_usa28xa_device = {
 	name:			"Keyspan USA28XA",
 	id_table:		keyspan_usa28xa_ids,
 	needs_interrupt_in:	DONT_CARE,	
@@ -706,7 +706,7 @@
 
 };
 
-struct usb_serial_device_type keyspan_usa49w_device = {
+static struct usb_serial_device_type keyspan_usa49w_device = {
 	name:			"Keyspan USA49W",
 	id_table:		keyspan_usa49w_ids,
 	needs_interrupt_in:	DONT_CARE,	
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/serial/mct_u232.c linux/drivers/usb/serial/mct_u232.c
--- linux-2.4.16/drivers/usb/serial/mct_u232.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/serial/mct_u232.c	Fri Nov 30 15:58:57 2001
@@ -154,7 +154,7 @@
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
 
-struct usb_serial_device_type mct_u232_device = {
+static struct usb_serial_device_type mct_u232_device = {
 	name:		     "Magic Control Technology USB-RS232",
 	id_table:	     mct_u232_table,
 	needs_interrupt_in:  MUST_HAVE,	 /* 2 interrupt-in endpoints */
@@ -178,7 +178,7 @@
 	shutdown:	     mct_u232_shutdown,
 };
 
-struct usb_serial_device_type mct_u232_sitecom_device = {
+static struct usb_serial_device_type mct_u232_sitecom_device = {
 	name:		     "MCT/Sitecom USB-RS232",
 	id_table:	     mct_u232_sitecom_table,
 	needs_interrupt_in:  MUST_HAVE,	 /* 2 interrupt-in endpoints */
@@ -202,7 +202,7 @@
 	shutdown:	     mct_u232_shutdown,
 };
 
-struct usb_serial_device_type mct_u232_du_h3sp_device = {
+static struct usb_serial_device_type mct_u232_du_h3sp_device = {
         name:                "MCT/D-Link DU-H3SP USB BAY",
         id_table:            mct_u232_du_h3sp_table,
         needs_interrupt_in:  MUST_HAVE,  /* 2 interrupt-in endpoints */
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/serial/omninet.c linux/drivers/usb/serial/omninet.c
--- linux-2.4.16/drivers/usb/serial/omninet.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/serial/omninet.c	Fri Nov 30 15:58:57 2001
@@ -87,7 +87,7 @@
 MODULE_DEVICE_TABLE (usb, id_table);
 
 
-struct usb_serial_device_type zyxel_omninet_device = {
+static struct usb_serial_device_type zyxel_omninet_device = {
 	name:			"ZyXEL - omni.net lcd plus usb",
 	id_table:		id_table,
 	needs_interrupt_in:	MUST_HAVE,
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c
--- linux-2.4.16/drivers/usb/serial/usbserial.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/serial/usbserial.c	Fri Nov 30 15:58:57 2001
@@ -397,7 +397,7 @@
 static struct usb_serial	*serial_table[SERIAL_TTY_MINORS];	/* initially all NULL */
 
 
-LIST_HEAD(usb_serial_driver_list);
+static LIST_HEAD(usb_serial_driver_list);
 
 
 static struct usb_serial *get_serial_by_minor (int minor)
@@ -1433,7 +1433,7 @@
 };
 
 
-int usb_serial_init(void)
+static int __init usb_serial_init(void)
 {
 	int i;
 	int result;
@@ -1473,7 +1473,7 @@
 }
 
 
-void usb_serial_exit(void)
+static void __exit usb_serial_exit(void)
 {
 
 #ifdef CONFIG_USB_SERIAL_GENERIC
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c
--- linux-2.4.16/drivers/usb/serial/visor.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/serial/visor.c	Fri Nov 30 15:58:57 2001
@@ -184,7 +184,7 @@
 
 
 /* All of the device info needed for the Handspring Visor */
-struct usb_serial_device_type handspring_device = {
+static struct usb_serial_device_type handspring_device = {
 	name:			"Handspring Visor",
 	id_table:		visor_id_table,
 	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
@@ -210,7 +210,7 @@
 };
 
 /* device info for the Palm 4.0 devices */
-struct usb_serial_device_type palm_4_0_device = {
+static struct usb_serial_device_type palm_4_0_device = {
 	name:			"Palm 4.0",
 	id_table:		palm_4_0_id_table,
 	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/serial/whiteheat.c linux/drivers/usb/serial/whiteheat.c
--- linux-2.4.16/drivers/usb/serial/whiteheat.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/serial/whiteheat.c	Fri Nov 30 15:58:57 2001
@@ -131,7 +131,7 @@
 static int  whiteheat_startup		(struct usb_serial *serial);
 static void whiteheat_shutdown		(struct usb_serial *serial);
 
-struct usb_serial_device_type whiteheat_fake_device = {
+static struct usb_serial_device_type whiteheat_fake_device = {
 	name:			"Connect Tech - WhiteHEAT - (prerenumeration)",
 	id_table:		id_table_prerenumeration,
 	needs_interrupt_in:	DONT_CARE,				/* don't have to have an interrupt in endpoint */
@@ -144,7 +144,7 @@
 	startup:		whiteheat_startup	
 };
 
-struct usb_serial_device_type whiteheat_device = {
+static struct usb_serial_device_type whiteheat_device = {
 	name:			"Connect Tech - WhiteHEAT",
 	id_table:		id_table_std,
 	needs_interrupt_in:	DONT_CARE,				/* don't have to have an interrupt in endpoint */
diff -Nur --exclude=*~ linux-2.4.16/drivers/usb/usbnet.c linux/drivers/usb/usbnet.c
--- linux-2.4.16/drivers/usb/usbnet.c	Mon Nov 26 08:35:03 2001
+++ linux/drivers/usb/usbnet.c	Fri Nov 30 15:58:56 2001
@@ -1870,6 +1870,11 @@
 	USB_DEVICE (0x0547, 0x2720),	// AnchorChips defaults
 	driver_info:	(unsigned long) &an2720_info,
 },
+
+{
+	USB_DEVICE (0x0547, 0x2727),	// Xircom PGUNET
+	driver_info:	(unsigned long) &an2720_info,
+},
 #endif
 
 #ifdef	CONFIG_USB_BELKIN
diff -Nur --exclude=*~ linux-2.4.16/fs/buffer.c linux/fs/buffer.c
--- linux-2.4.16/fs/buffer.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/buffer.c	Fri Nov 30 18:39:05 2001
@@ -1036,6 +1036,7 @@
 	unsigned long dirty, tot, hard_dirty_limit, soft_dirty_limit;
 
 	dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT;
+	dirty += size_buffers_type[BUF_LOCKED] >> PAGE_SHIFT;
 	tot = nr_free_buffer_pages();
 
 	dirty *= 100;
diff -Nur --exclude=*~ linux-2.4.16/fs/devfs/base.c linux/fs/devfs/base.c
--- linux-2.4.16/fs/devfs/base.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/devfs/base.c	Wed Nov 28 18:15:57 2001
@@ -427,7 +427,7 @@
 	       Work sponsored by SGI.
   v0.92
     20000306   Richard Gooch <rgooch@atnf.csiro.au>
-	       Added DEVFS_FL_NO_PERSISTENCE flag.
+	       Added DEVFS_ FL_NO_PERSISTENCE flag.
 	       Removed unnecessary call to <update_devfs_inode_from_entry> in
 	       <devfs_readdir>.
 	       Work sponsored by SGI.
@@ -545,21 +545,30 @@
     20010919   Richard Gooch <rgooch@atnf.csiro.au>
 	       Set inode->i_mapping->a_ops for block nodes in <get_vfs_inode>.
   v0.116
-    20010927   Richard Gooch <rgooch@atnf.csiro.au>
-	       Went back to global rwsem for symlinks (refcount scheme no good)
-  v0.117
     20011008   Richard Gooch <rgooch@atnf.csiro.au>
 	       Fixed overrun in <devfs_link> by removing function (not needed).
-  v0.118
     20011009   Richard Gooch <rgooch@atnf.csiro.au>
 	       Fixed buffer underrun in <try_modload>.
-	       Moved down_read() from <search_for_entry_in_dir> to <find_entry>
-  v0.119
     20011029   Richard Gooch <rgooch@atnf.csiro.au>
 	       Fixed race in <devfsd_ioctl> when setting event mask.
-    20011103   Richard Gooch <rgooch@atnf.csiro.au>
-	       Avoid deadlock in <devfs_follow_link> by using temporary buffer.
-  v0.120
+    20011114   Richard Gooch <rgooch@atnf.csiro.au>
+	       First release of new locking code.
+  v1.0
+    20011117   Richard Gooch <rgooch@atnf.csiro.au>
+	       Discard temporary buffer, now use "%s" for dentry names.
+    20011118   Richard Gooch <rgooch@atnf.csiro.au>
+	       Don't generate path in <try_modload>: use fake entry instead.
+	       Use "existing" directory in <_devfs_make_parent_for_leaf>.
+    20011122   Richard Gooch <rgooch@atnf.csiro.au>
+	       Use slab cache rather than fixed buffer for devfsd events.
+  v1.1
+    20011125   Richard Gooch <rgooch@atnf.csiro.au>
+	       Send DEVFSD_NOTIFY_REGISTERED events in <devfs_mk_dir>.
+    20011127   Richard Gooch <rgooch@atnf.csiro.au>
+	       Fixed locking bug in <devfs_d_revalidate_wait> due to typo.
+	       Do not send CREATE, CHANGE, ASYNC_OPEN or DELETE events from
+	       devfsd or children.
+  v1.2
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -592,7 +601,7 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 
-#define DEVFS_VERSION            "0.120 (20011103)"
+#define DEVFS_VERSION            "1.2 (20011127)"
 
 #define DEVFS_NAME "devfs"
 
@@ -605,27 +614,30 @@
 #  define FALSE 0
 #endif
 
-#define IS_HIDDEN(de) (( ((de)->hide && !is_devfsd_or_child(fs_info)) || !(de)->registered))
+#define MODE_DIR (S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO)
 
-#define DEBUG_NONE         0x00000
-#define DEBUG_MODULE_LOAD  0x00001
-#define DEBUG_REGISTER     0x00002
-#define DEBUG_UNREGISTER   0x00004
-#define DEBUG_SET_FLAGS    0x00008
-#define DEBUG_S_PUT        0x00010
-#define DEBUG_I_LOOKUP     0x00020
-#define DEBUG_I_CREATE     0x00040
-#define DEBUG_I_GET        0x00080
-#define DEBUG_I_CHANGE     0x00100
-#define DEBUG_I_UNLINK     0x00200
-#define DEBUG_I_RLINK      0x00400
-#define DEBUG_I_FLINK      0x00800
-#define DEBUG_I_MKNOD      0x01000
-#define DEBUG_F_READDIR    0x02000
-#define DEBUG_D_DELETE     0x04000
-#define DEBUG_D_RELEASE    0x08000
-#define DEBUG_D_IPUT       0x10000
-#define DEBUG_ALL          0xfffff
+#define IS_HIDDEN(de) ( (de)->hide && !is_devfsd_or_child(fs_info) )
+
+#define DEBUG_NONE         0x0000000
+#define DEBUG_MODULE_LOAD  0x0000001
+#define DEBUG_REGISTER     0x0000002
+#define DEBUG_UNREGISTER   0x0000004
+#define DEBUG_FREE         0x0000008
+#define DEBUG_SET_FLAGS    0x0000010
+#define DEBUG_S_READ       0x0000100        /*  Break  */
+#define DEBUG_I_LOOKUP     0x0001000        /*  Break  */
+#define DEBUG_I_CREATE     0x0002000
+#define DEBUG_I_GET        0x0004000
+#define DEBUG_I_CHANGE     0x0008000
+#define DEBUG_I_UNLINK     0x0010000
+#define DEBUG_I_RLINK      0x0020000
+#define DEBUG_I_FLINK      0x0040000
+#define DEBUG_I_MKNOD      0x0080000
+#define DEBUG_F_READDIR    0x0100000        /*  Break  */
+#define DEBUG_D_DELETE     0x1000000        /*  Break  */
+#define DEBUG_D_RELEASE    0x2000000
+#define DEBUG_D_IPUT       0x4000000
+#define DEBUG_ALL          0xfffffff
 #define DEBUG_DISABLED     DEBUG_NONE
 
 #define OPTION_NONE             0x00
@@ -638,9 +650,11 @@
 
 struct directory_type
 {
+    rwlock_t lock;                   /*  Lock for searching(R)/updating(W)   */
     struct devfs_entry *first;
     struct devfs_entry *last;
-    unsigned int num_removable;
+    unsigned short num_removable;    /*  Lock for writing but not reading    */
+    unsigned char no_more_additions:1;
 };
 
 struct file_type
@@ -656,8 +670,6 @@
 
 struct fcb_type  /*  File, char, block type  */
 {
-    uid_t default_uid;
-    gid_t default_gid;
     void *ops;
     union 
     {
@@ -678,20 +690,13 @@
     char *linkname;              /*  This is NULL-terminated                 */
 };
 
-struct fifo_type
-{
-    uid_t uid;
-    gid_t gid;
-};
-
-struct devfs_inode  /*  This structure is for "persistent" inode storage  */
+struct devfs_inode     /*  This structure is for "persistent" inode storage  */
 {
+    struct dentry *dentry;
     time_t atime;
     time_t mtime;
     time_t ctime;
-    unsigned int ino;          /*  Inode number as seen in the VFS  */
-    struct dentry *dentry;
-    umode_t mode;
+    unsigned int ino;            /*  Inode number as seen in the VFS         */
     uid_t uid;
     gid_t gid;
 };
@@ -699,12 +704,13 @@
 struct devfs_entry
 {
     void *info;
+    atomic_t refcount;           /*  When this drops to zero, it's unused    */
     union 
     {
 	struct directory_type dir;
 	struct fcb_type fcb;
 	struct symlink_type symlink;
-	struct fifo_type fifo;
+	const char *name;        /*  Only used for (mode == 0)               */
     }
     u;
     struct devfs_entry *prev;    /*  Previous entry in the parent directory  */
@@ -713,12 +719,11 @@
     struct devfs_entry *slave;   /*  Another entry to unregister             */
     struct devfs_inode inode;
     umode_t mode;
-    unsigned short namelen;  /*  I think 64k+ filenames are a way off...  */
-    unsigned char registered:1;
+    unsigned short namelen;      /*  I think 64k+ filenames are a way off... */
     unsigned char hide:1;
-    unsigned char no_persistence:1;
-    char name[1];            /*  This is just a dummy: the allocated array is
-				 bigger. This is NULL-terminated  */
+    unsigned char vfs_created:1; /*  Whether created by driver or VFS        */
+    char name[1];                /*  This is just a dummy: the allocated array
+				     is bigger. This is NULL-terminated      */
 };
 
 /*  The root of the device tree  */
@@ -726,35 +731,38 @@
 
 struct devfsd_buf_entry
 {
-    void *data;
-    unsigned int type;
+    struct devfs_entry *de;      /*  The name is generated with this         */
+    unsigned short type;         /*  The type of event                       */
     umode_t mode;
     uid_t uid;
     gid_t gid;
+    struct devfsd_buf_entry *next;
 };
 
-struct fs_info      /*  This structure is for the mounted devfs  */
+struct fs_info                  /*  This structure is for the mounted devfs  */
 {
     struct super_block *sb;
-    volatile struct devfsd_buf_entry *devfsd_buffer;
-    spinlock_t devfsd_buffer_lock;
-    volatile unsigned int devfsd_buf_in;
-    volatile unsigned int devfsd_buf_out;
+    spinlock_t devfsd_buffer_lock;  /*  Lock when inserting/deleting events  */
+    struct devfsd_buf_entry *devfsd_first_event;
+    struct devfsd_buf_entry *devfsd_last_event;
     volatile int devfsd_sleeping;
     volatile struct task_struct *devfsd_task;
     volatile struct file *devfsd_file;
     struct devfsd_notify_struct *devfsd_info;
     volatile unsigned long devfsd_event_mask;
     atomic_t devfsd_overrun_count;
-    wait_queue_head_t devfsd_wait_queue;
-    wait_queue_head_t revalidate_wait_queue;
+    wait_queue_head_t devfsd_wait_queue;      /*  Wake devfsd on input       */
+    wait_queue_head_t revalidate_wait_queue;  /*  Wake when devfsd sleeps    */
 };
 
 static struct fs_info fs_info = {devfsd_buffer_lock: SPIN_LOCK_UNLOCKED};
-static const int devfsd_buf_size = PAGE_SIZE / sizeof(struct devfsd_buf_entry);
+static kmem_cache_t *devfsd_buf_cache;
 #ifdef CONFIG_DEVFS_DEBUG
 static unsigned int devfs_debug_init __initdata = DEBUG_NONE;
 static unsigned int devfs_debug = DEBUG_NONE;
+static spinlock_t stat_lock = SPIN_LOCK_UNLOCKED;
+static unsigned int stat_num_entries;
+static unsigned int stat_num_bytes;
 #endif
 
 #ifdef CONFIG_DEVFS_MOUNT
@@ -763,19 +771,23 @@
 static unsigned int boot_options = OPTION_NONE;
 #endif
 
-static DECLARE_RWSEM (symlink_rwsem);
-
 /*  Forward function declarations  */
-static struct devfs_entry *search_for_entry (struct devfs_entry *dir,
-					     const char *name,
-					     unsigned int namelen, int mkdir,
-					     int mkfile, int *is_new,
-					     int traverse_symlink);
+static devfs_handle_t _devfs_walk_path (struct devfs_entry *dir,
+					const char *name, int namelen,
+					int traverse_symlink);
 static ssize_t devfsd_read (struct file *file, char *buf, size_t len,
 			    loff_t *ppos);
 static int devfsd_ioctl (struct inode *inode, struct file *file,
 			 unsigned int cmd, unsigned long arg);
 static int devfsd_close (struct inode *inode, struct file *file);
+#ifdef CONFIG_DEVFS_DEBUG
+static int stat_read (struct file *file, char *buf, size_t len,
+			    loff_t *ppos);
+static struct file_operations stat_fops =
+{
+    read:    stat_read,
+};
+#endif
 
 
 /*  Devfs daemon file operations  */
@@ -791,46 +803,95 @@
 
 
 /**
- *	search_for_entry_in_dir - Search for a devfs entry inside another devfs entry.
- *	@parent:  The parent devfs entry.
- *	@name:  The name of the entry.
+ *	devfs_get - Get a reference to a devfs entry.
+ *	@de:  The devfs entry.
+ */
+
+static struct devfs_entry *devfs_get (struct devfs_entry *de)
+{
+    if (de) atomic_inc (&de->refcount);
+    return de;
+}   /*  End Function devfs_get  */
+
+/**
+ *	devfs_put - Put (release) a reference to a devfs entry.
+ *	@de:  The devfs entry.
+ */
+
+static void devfs_put (struct devfs_entry *de)
+{
+    if (!de) return;
+    if ( !atomic_dec_and_test (&de->refcount) ) return;
+    if (de == root_entry)
+	OOPS ("%s: devfs_put(): root entry being freed\n", DEVFS_NAME);
+#ifdef CONFIG_DEVFS_DEBUG
+    if (devfs_debug & DEBUG_FREE)
+	printk ("%s: devfs_put(%s): de: %p, parent: %p \"%s\"\n",
+		DEVFS_NAME, de->name, de, de->parent,
+		de->parent ? de->parent->name : "no parent");
+#endif
+    if ( S_ISLNK (de->mode) ) kfree (de->u.symlink.linkname);
+    if ( ( S_ISCHR (de->mode) || S_ISBLK (de->mode) ) && de->u.fcb.autogen )
+    {
+	devfs_dealloc_devnum ( S_ISCHR (de->mode) ? DEVFS_SPECIAL_CHR :
+			       DEVFS_SPECIAL_BLK,
+			       MKDEV (de->u.fcb.u.device.major,
+				      de->u.fcb.u.device.minor) );
+    }
+#ifdef CONFIG_DEVFS_DEBUG
+    spin_lock (&stat_lock);
+    --stat_num_entries;
+    stat_num_bytes -= sizeof *de + de->namelen;
+    if ( S_ISLNK (de->mode) ) stat_num_bytes -= de->u.symlink.length + 1;
+    spin_unlock (&stat_lock);
+#endif
+    kfree (de);
+}   /*  End Function devfs_put  */
+
+/**
+ *	_devfs_search_dir - Search for a devfs entry in a directory.
+ *	@dir:  The directory to search.
+ *	@name:  The name of the entry to search for.
  *	@namelen:  The number of characters in @name.
- *	@traverse_symlink:  If %TRUE then the entry is traversed if it is a symlink.
  *
- *  Search for a devfs entry inside another devfs entry and returns a pointer
- *   to the entry on success, else %NULL.
+ *  Search for a devfs entry in a directory and returns a pointer to the entry
+ *   on success, else %NULL. The directory must be locked already.
+ *   An implicit devfs_get() is performed on the returned entry.
  */
 
-static struct devfs_entry *search_for_entry_in_dir (struct devfs_entry *parent,
-						    const char *name,
-						    unsigned int namelen,
-						    int traverse_symlink)
+static struct devfs_entry *_devfs_search_dir (struct devfs_entry *dir,
+					      const char *name,
+					      unsigned int namelen)
 {
-    struct devfs_entry *curr, *retval;
+    struct devfs_entry *curr;
 
-    if ( !S_ISDIR (parent->mode) )
+    if ( !S_ISDIR (dir->mode) )
     {
-	printk ("%s: entry is not a directory\n", DEVFS_NAME);
+	printk ("%s: search_dir(%s): not a directory\n", DEVFS_NAME,dir->name);
 	return NULL;
     }
-    for (curr = parent->u.dir.first; curr != NULL; curr = curr->next)
+    for (curr = dir->u.dir.first; curr != NULL; curr = curr->next)
     {
 	if (curr->namelen != namelen) continue;
 	if (memcmp (curr->name, name, namelen) == 0) break;
 	/*  Not found: try the next one  */
     }
-    if (curr == NULL) return NULL;
-    if (!S_ISLNK (curr->mode) || !traverse_symlink) return curr;
-    /*  Need to follow the link: this is a stack chomper  */
-    retval = curr->registered ?
-	search_for_entry (parent, curr->u.symlink.linkname,
-			  curr->u.symlink.length, FALSE, FALSE, NULL,
-			  TRUE) : NULL;
-    return retval;
-}   /*  End Function search_for_entry_in_dir  */
+    return devfs_get (curr);
+}   /*  End Function _devfs_search_dir  */
+
 
-static struct devfs_entry *create_entry (struct devfs_entry *parent,
-					 const char *name,unsigned int namelen)
+/**
+ *	_devfs_alloc_entry - Allocate a devfs entry.
+ *	@name:  The name of the entry.
+ *	@namelen:  The number of characters in @name.
+ *
+ *  Allocate a devfs entry and returns a pointer to the entry on success, else
+ *   %NULL.
+ */
+
+static struct devfs_entry *_devfs_alloc_entry (const char *name,
+					       unsigned int namelen,
+					       umode_t mode)
 {
     struct devfs_entry *new;
     static unsigned long inode_counter = FIRST_INODE;
@@ -839,168 +900,270 @@
     if ( name && (namelen < 1) ) namelen = strlen (name);
     if ( ( new = kmalloc (sizeof *new + namelen, GFP_KERNEL) ) == NULL )
 	return NULL;
-    /*  Magic: this will set the ctime to zero, thus subsequent lookups will
-	trigger the call to <update_devfs_inode_from_entry>  */
     memset (new, 0, sizeof *new + namelen);
+    new->mode = mode;
+    if ( S_ISDIR (mode) ) rwlock_init (&new->u.dir.lock);
+    atomic_set (&new->refcount, 1);
     spin_lock (&counter_lock);
     new->inode.ino = inode_counter++;
     spin_unlock (&counter_lock);
-    new->parent = parent;
     if (name) memcpy (new->name, name, namelen);
     new->namelen = namelen;
-    if (parent == NULL) return new;
-    new->prev = parent->u.dir.last;
-    /*  Insert into the parent directory's list of children  */
-    if (parent->u.dir.first == NULL) parent->u.dir.first = new;
-    else parent->u.dir.last->next = new;
-    parent->u.dir.last = new;
+#ifdef CONFIG_DEVFS_DEBUG
+    spin_lock (&stat_lock);
+    ++stat_num_entries;
+    stat_num_bytes += sizeof *new + namelen;
+    spin_unlock (&stat_lock);
+#endif
     return new;
-}   /*  End Function create_entry  */
+}   /*  End Function _devfs_alloc_entry  */
+
 
-static void update_devfs_inode_from_entry (struct devfs_entry *de)
+/**
+ *	_devfs_append_entry - Append a devfs entry to a directory's child list.
+ *	@dir:  The directory to add to.
+ *	@de:  The devfs entry to append.
+ *	@removable: If TRUE, increment the count of removable devices for %dir.
+ *	@old_de: If an existing entry exists, it will be written here. This may
+ *		 be %NULL.
+ *
+ *  Append a devfs entry to a directory's list of children, checking first to
+ *   see if an entry of the same name exists. The directory will be locked.
+ *   The value 0 is returned on success, else a negative error code.
+ *   On failure, an implicit devfs_put() is performed on %de.
+ */
+
+static int _devfs_append_entry (devfs_handle_t dir, devfs_handle_t de,
+				int removable, devfs_handle_t *old_de)
 {
-    if (de == NULL) return;
-    if ( S_ISDIR (de->mode) )
-    {
-	de->inode.mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
-	de->inode.uid = 0;
-	de->inode.gid = 0;
-    }
-    else if ( S_ISLNK (de->mode) )
-    {
-	de->inode.mode = S_IFLNK | S_IRUGO | S_IXUGO;
-	de->inode.uid = 0;
-	de->inode.gid = 0;
-    }
-    else if ( S_ISFIFO (de->mode) )
+    int retval;
+
+    if (old_de) *old_de = NULL;
+    if ( !S_ISDIR (dir->mode) )
     {
-	de->inode.mode = de->mode;
-	de->inode.uid = de->u.fifo.uid;
-	de->inode.gid = de->u.fifo.gid;
+	printk ("%s: append_entry(%s): dir: \"%s\" is not a directory\n",
+		DEVFS_NAME, de->name, dir->name);
+	devfs_put (de);
+	return -ENOTDIR;
     }
+    write_lock (&dir->u.dir.lock);
+    if (dir->u.dir.no_more_additions) retval = -ENOENT;
     else
     {
-	if (de->u.fcb.auto_owner)
-	    de->inode.mode = (de->mode & ~S_IALLUGO) | S_IRUGO | S_IWUGO;
-	else de->inode.mode = de->mode;
-	de->inode.uid = de->u.fcb.default_uid;
-	de->inode.gid = de->u.fcb.default_gid;
+	struct devfs_entry *old;
+
+	old = _devfs_search_dir (dir, de->name, de->namelen);
+	if (old_de) *old_de = old;
+	else devfs_put (old);
+	if (old == NULL)
+	{
+	    de->parent = dir;
+	    de->prev = dir->u.dir.last;
+	    /*  Append to the directory's list of children  */
+	    if (dir->u.dir.first == NULL) dir->u.dir.first = de;
+	    else dir->u.dir.last->next = de;
+	    dir->u.dir.last = de;
+	    if (removable) ++dir->u.dir.num_removable;
+	    retval = 0;
+	}
+	else retval = -EEXIST;
     }
-}   /*  End Function update_devfs_inode_from_entry  */
+    write_unlock (&dir->u.dir.lock);
+    if (retval) devfs_put (de);
+    return retval;
+}   /*  End Function _devfs_append_entry  */
+
 
 /**
- *	get_root_entry - Get the root devfs entry.
+ *	_devfs_get_root_entry - Get the root devfs entry.
  *
  *	Returns the root devfs entry on success, else %NULL.
  */
 
-static struct devfs_entry *get_root_entry (void)
+static struct devfs_entry *_devfs_get_root_entry (void)
 {
     kdev_t devnum;
     struct devfs_entry *new;
+    static spinlock_t root_lock = SPIN_LOCK_UNLOCKED;
 
     /*  Always ensure the root is created  */
-    if (root_entry != NULL) return root_entry;
-    if ( ( root_entry = create_entry (NULL, NULL, 0) ) == NULL ) return NULL;
-    root_entry->mode = S_IFDIR;
-    /*  Force an inode update, because lookup() is never done for the root  */
-    update_devfs_inode_from_entry (root_entry);
-    root_entry->registered = TRUE;
+    if (root_entry) return root_entry;
+    if ( ( new = _devfs_alloc_entry (NULL, 0,MODE_DIR) ) == NULL ) return NULL;
+    spin_lock (&root_lock);
+    if (root_entry)
+    {
+	spin_unlock (&root_lock);
+	devfs_put (new);
+	return (root_entry);
+    }
+    root_entry = new;
+    spin_unlock (&root_lock);
     /*  And create the entry for ".devfsd"  */
-    if ( ( new = create_entry (root_entry, ".devfsd", 0) ) == NULL )
-	return NULL;
+    if ( ( new = _devfs_alloc_entry (".devfsd", 0, S_IFCHR |S_IRUSR |S_IWUSR) )
+	 == NULL ) return NULL;
     devnum = devfs_alloc_devnum (DEVFS_SPECIAL_CHR);
     new->u.fcb.u.device.major = MAJOR (devnum);
     new->u.fcb.u.device.minor = MINOR (devnum);
-    new->mode = S_IFCHR | S_IRUSR | S_IWUSR;
-    new->u.fcb.default_uid = 0;
-    new->u.fcb.default_gid = 0;
     new->u.fcb.ops = &devfsd_fops;
-    new->registered = TRUE;
+    _devfs_append_entry (root_entry, new, FALSE, NULL);
+#ifdef CONFIG_DEVFS_DEBUG
+    if ( ( new = _devfs_alloc_entry (".stat", 0, S_IFCHR | S_IRUGO | S_IWUGO) )
+	 == NULL ) return NULL;
+    devnum = devfs_alloc_devnum (DEVFS_SPECIAL_CHR);
+    new->u.fcb.u.device.major = MAJOR (devnum);
+    new->u.fcb.u.device.minor = MINOR (devnum);
+    new->u.fcb.ops = &stat_fops;
+    _devfs_append_entry (root_entry, new, FALSE, NULL);
+#endif
     return root_entry;
-}   /*  End Function get_root_entry  */
+}   /*  End Function _devfs_get_root_entry  */
 
 
 /**
- *	search_for_entry - Search for an entry in the devfs tree.
- *	@dir: The parent directory to search from. If this is %NULL the root is used
- *	@name: The name of the entry.
- *	@namelen: The number of characters in @name.
- *	@mkdir: If %TRUE intermediate directories are created as needed.
- *	@mkfile: If %TRUE the file entry is created if it doesn't exist.
- *	@is_new: If the returned entry was newly made, %TRUE is written here. If
- * 		this is %NULL nothing is written here.
- *	@traverse_symlink: If %TRUE then symbolic links are traversed.
+ *	_devfs_descend - Descend down a tree using the next component name.
+ *	@dir:  The directory to search.
+ *	@name:  The component name to search for.
+ *	@namelen:  The length of %name.
+ *	@next_pos:  The position of the next '/' or '\0' is written here.
  *
- *	If the entry is created, then it will be in the unregistered state.
- *	Returns a pointer to the entry on success, else %NULL.
+ *  Descend into a directory, searching for a component. This function forms
+ *   the core of a tree-walking algorithm. The directory will be locked.
+ *   The devfs entry corresponding to the component is returned. If there is
+ *   no matching entry, %NULL is returned.
+ *   An implicit devfs_get() is performed on the returned entry.
  */
 
-static struct devfs_entry *search_for_entry (struct devfs_entry *dir,
-					     const char *name,
-					     unsigned int namelen, int mkdir,
-					     int mkfile, int *is_new,
-					     int traverse_symlink)
+static struct devfs_entry *_devfs_descend (struct devfs_entry *dir,
+					   const char *name, int namelen,
+					   int *next_pos)
 {
-    int len;
-    const char *subname, *stop, *ptr;
+    const char *stop, *ptr;
     struct devfs_entry *entry;
 
-    if (is_new) *is_new = FALSE;
-    if (dir == NULL) dir = get_root_entry ();
-    if (dir == NULL) return NULL;
-    /*  Extract one filename component  */
-    subname = name;
+    if ( (namelen >= 3) && (strncmp (name, "../", 3) == 0) )
+    {   /*  Special-case going to parent directory  */
+	*next_pos = 3;
+	return devfs_get (dir->parent);
+    }
     stop = name + namelen;
-    while (subname < stop)
-    {
-	/*  Search for a possible '/'  */
-	for (ptr = subname; (ptr < stop) && (*ptr != '/'); ++ptr);
-	if (ptr >= stop)
-	{
-	    /*  Look for trailing component  */
-	    len = stop - subname;
-	    entry = search_for_entry_in_dir (dir, subname, len,
-					     traverse_symlink);
-	    if (entry != NULL) return entry;
-	    if (!mkfile) return NULL;
-	    entry = create_entry (dir, subname, len);
-	    if (entry && is_new) *is_new = TRUE;
-	    return entry;
-	}
-	/*  Found '/': search for directory  */
-	if (strncmp (subname, "../", 3) == 0)
-	{
-	    /*  Going up  */
-	    dir = dir->parent;
-	    if (dir == NULL) return NULL;  /*  Cannot escape from devfs  */
-	    subname += 3;
-	    continue;
+    /*  Search for a possible '/'  */
+    for (ptr = name; (ptr < stop) && (*ptr != '/'); ++ptr);
+    *next_pos = ptr - name;
+    read_lock (&dir->u.dir.lock);
+    entry = _devfs_search_dir (dir, name, *next_pos);
+    read_unlock (&dir->u.dir.lock);
+    return entry;
+}   /*  End Function _devfs_descend  */
+
+
+static devfs_handle_t _devfs_make_parent_for_leaf (struct devfs_entry *dir,
+						   const char *name,
+						   int namelen, int *leaf_pos)
+{
+    int next_pos = 0;
+
+    if (dir == NULL) dir = _devfs_get_root_entry ();
+    if (dir == NULL) return NULL;
+    devfs_get (dir);
+    /*  Search for possible trailing component and ignore it  */
+    for (--namelen; (namelen > 0) && (name[namelen] != '/'); --namelen);
+    *leaf_pos = (name[namelen] == '/') ? (namelen + 1) : 0;
+    for (; namelen > 0; name += next_pos, namelen -= next_pos)
+    {
+	struct devfs_entry *de, *old;
+
+	if ( ( de = _devfs_descend (dir, name, namelen, &next_pos) ) == NULL )
+	{
+	    de = _devfs_alloc_entry (name, next_pos, MODE_DIR);
+	    devfs_get (de);
+	    if ( !de || _devfs_append_entry (dir, de, FALSE, &old) )
+	    {
+		devfs_put (de);
+		if ( !old || !S_ISDIR (old->mode) )
+		{
+		    devfs_put (old);
+		    devfs_put (dir);
+		    return NULL;
+		}
+		de = old;  /*  Use the existing directory  */
+	    }
 	}
-	len = ptr - subname;
-	entry = search_for_entry_in_dir (dir, subname, len, traverse_symlink);
-	if (!entry && !mkdir) return NULL;
-	if (entry == NULL)
+	if (de == dir->parent)
 	{
-	    /*  Make it  */
-	    if ( ( entry = create_entry (dir, subname, len) ) == NULL )
-		return NULL;
-	    entry->mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
-	    if (is_new) *is_new = TRUE;
+	    devfs_put (dir);
+	    devfs_put (de);
+	    return NULL;
 	}
-	if ( !S_ISDIR (entry->mode) )
+	devfs_put (dir);
+	dir = de;
+	if (name[next_pos] == '/') ++next_pos;
+    }
+    return dir;
+}   /*  End Function _devfs_make_parent_for_leaf  */
+
+
+static devfs_handle_t _devfs_prepare_leaf (devfs_handle_t *dir,
+					   const char *name, umode_t mode)
+{
+    int namelen, leaf_pos;
+    struct devfs_entry *de;
+
+    namelen = strlen (name);
+    if ( ( *dir = _devfs_make_parent_for_leaf (*dir, name, namelen,
+					       &leaf_pos) ) == NULL )
+    {
+	printk ("%s: prepare_leaf(%s): could not create parent path\n",
+		DEVFS_NAME, name);
+	return NULL;
+    }
+    if ( ( de = _devfs_alloc_entry (name + leaf_pos, namelen - leaf_pos,mode) )
+	 == NULL )
+    {
+	printk ("%s: prepare_leaf(%s): could not allocate entry\n",
+		DEVFS_NAME, name);
+	devfs_put (*dir);
+	return NULL;
+    }
+    return de;
+}   /*  End Function _devfs_prepare_leaf  */
+
+
+static devfs_handle_t _devfs_walk_path (struct devfs_entry *dir,
+					const char *name, int namelen,
+					int traverse_symlink)
+{
+    int next_pos = 0;
+
+    if (dir == NULL) dir = _devfs_get_root_entry ();
+    if (dir == NULL) return NULL;
+    devfs_get (dir);
+    for (; namelen > 0; name += next_pos, namelen -= next_pos)
+    {
+	struct devfs_entry *de, *link;
+
+	if ( ( de = _devfs_descend (dir, name, namelen, &next_pos) ) == NULL )
 	{
-	    printk ("%s: existing non-directory entry\n", DEVFS_NAME);
+	    devfs_put (dir);
 	    return NULL;
 	}
-	/*  Ensure an unregistered entry is re-registered and visible  */
-	entry->hide = FALSE;
-	entry->registered = TRUE;
-	subname = ptr + 1;
-	dir = entry;
+	if (S_ISLNK (de->mode) && traverse_symlink)
+	{   /*  Need to follow the link: this is a stack chomper  */
+	    link = _devfs_walk_path (dir, de->u.symlink.linkname,
+				     de->u.symlink.length, TRUE);
+	    devfs_put (de);
+	    if (!link)
+	    {
+		devfs_put (dir);
+		return NULL;
+	    }
+	    de = link;
+	}
+	devfs_put (dir);
+	dir = de;
+	if (name[next_pos] == '/') ++next_pos;
     }
-    return NULL;
-}   /*  End Function search_for_entry  */
+    return dir;
+}   /*  End Function _devfs_walk_path  */
 
 
 /**
@@ -1020,20 +1183,29 @@
 {
     struct devfs_entry *entry, *de;
 
+    devfs_get (dir);
     if (dir == NULL) return NULL;
     if ( !S_ISDIR (dir->mode) )
     {
 	printk ("%s: find_by_dev(): not a directory\n", DEVFS_NAME);
+	devfs_put (dir);
 	return NULL;
     }
     /*  First search files in this directory  */
+    read_lock (&dir->u.dir.lock);
     for (entry = dir->u.dir.first; entry != NULL; entry = entry->next)
     {
 	if ( !S_ISCHR (entry->mode) && !S_ISBLK (entry->mode) ) continue;
 	if ( S_ISCHR (entry->mode) && (type != DEVFS_SPECIAL_CHR) ) continue;
 	if ( S_ISBLK (entry->mode) && (type != DEVFS_SPECIAL_BLK) ) continue;
 	if ( (entry->u.fcb.u.device.major == major) &&
-	     (entry->u.fcb.u.device.minor == minor) ) return entry;
+	     (entry->u.fcb.u.device.minor == minor) )
+	{
+	    devfs_get (entry);
+	    read_unlock (&dir->u.dir.lock);
+	    devfs_put (dir);
+	    return entry;
+	}
 	/*  Not found: try the next one  */
     }
     /*  Now recursively search the subdirectories: this is a stack chomper  */
@@ -1041,8 +1213,15 @@
     {
 	if ( !S_ISDIR (entry->mode) ) continue;
 	de = find_by_dev (entry, major, minor, type);
-	if (de) return de;
+	if (de)
+	{
+	    read_unlock (&dir->u.dir.lock);
+	    devfs_put (dir);
+	    return de;
+	}
     }
+    read_unlock (&dir->u.dir.lock);
+    devfs_put (dir);
     return NULL;
 }   /*  End Function find_by_dev  */
 
@@ -1063,7 +1242,6 @@
  *		%DEVFS_SPECIAL_CHR or %DEVFS_SPECIAL_BLK.
  *	@traverse_symlink: If %TRUE then symbolic links are traversed.
  *
- *	FIXME: What the hell is @handle? - ch
  *	Returns the devfs_entry pointer on success, else %NULL.
  */
 
@@ -1095,10 +1273,7 @@
 	    ++name;
 	    --namelen;
 	}
-	if (traverse_symlink) down_read (&symlink_rwsem);
-	entry = search_for_entry (dir, name, namelen, FALSE, FALSE, NULL,
-				  traverse_symlink);
-	if (traverse_symlink) up_read (&symlink_rwsem);
+	entry = _devfs_walk_path (dir, name, namelen, traverse_symlink);
 	if (entry != NULL) return entry;
     }
     /*  Have to search by major and minor: slow  */
@@ -1106,42 +1281,34 @@
     return find_by_dev (root_entry, major, minor, type);
 }   /*  End Function find_entry  */
 
-static struct devfs_entry *get_devfs_entry_from_vfs_inode (struct inode *inode,
-							   int do_check)
+static struct devfs_entry *get_devfs_entry_from_vfs_inode (struct inode *inode)
 {
-    struct devfs_entry *de;
-
     if (inode == NULL) return NULL;
-    de = inode->u.generic_ip;
-    if (!de) printk (__FUNCTION__ "(): NULL de for inode %ld\n", inode->i_ino);
-    if (do_check && de && !de->registered) de = NULL;
-    return de;
+    return inode->u.generic_ip;
 }   /*  End Function get_devfs_entry_from_vfs_inode  */
 
 
 /**
- *	free_dentries - Free the dentries for a device entry and invalidate inodes.
+ *	free_dentry - Free the dentry for a device entry and invalidate inode.
  *	@de: The entry.
+ *
+ *	This must only be called after the entry has been unhooked from it's
+ *	 parent directory.
  */
 
-static void free_dentries (struct devfs_entry *de)
+static void free_dentry (struct devfs_entry *de)
 {
-    struct dentry *dentry;
+    struct dentry *dentry = de->inode.dentry;
 
+    if (!dentry) return;
     spin_lock (&dcache_lock);
-    dentry = de->inode.dentry;
-    if (dentry != NULL)
-    {
-	dget_locked (dentry);
-	de->inode.dentry = NULL;
-	spin_unlock (&dcache_lock);
-	/*  Forcefully remove the inode  */
-	if (dentry->d_inode != NULL) dentry->d_inode->i_nlink = 0;
-	d_drop (dentry);
-	dput (dentry);
-    }
-    else spin_unlock (&dcache_lock);
-}   /*  End Function free_dentries  */
+    dget_locked (dentry);
+    spin_unlock (&dcache_lock);
+    /*  Forcefully remove the inode  */
+    if (dentry->d_inode != NULL) dentry->d_inode->i_nlink = 0;
+    d_drop (dentry);
+    dput (dentry);
+}   /*  End Function free_dentry  */
 
 
 /**
@@ -1172,7 +1339,7 @@
 
 static inline int devfsd_queue_empty (struct fs_info *fs_info)
 {
-    return (fs_info->devfsd_buf_out == fs_info->devfsd_buf_in) ? TRUE : FALSE;
+    return (fs_info->devfsd_last_event) ? FALSE : TRUE;
 }   /*  End Function devfsd_queue_empty  */
 
 
@@ -1201,8 +1368,9 @@
 
 
 /**
- *	devfsd_notify_one - Notify a single devfsd daemon of a change.
- *	@data: Data to be passed.
+ *	devfsd_notify_de - Notify the devfsd daemon of a change.
+ *	@de: The devfs entry that has changed. This and all parent entries will
+ *            have their reference counts incremented if the event was queued.
  *	@type: The type of change.
  *	@mode: The mode of the entry.
  *	@uid: The user ID.
@@ -1212,51 +1380,48 @@
  *	Returns %TRUE if an event was queued and devfsd woken up, else %FALSE.
  */
 
-static int devfsd_notify_one (void *data, unsigned int type, umode_t mode,
-			      uid_t uid, gid_t gid, struct fs_info *fs_info)
+static int devfsd_notify_de (struct devfs_entry *de,
+			     unsigned short type, umode_t mode,
+			     uid_t uid, gid_t gid, struct fs_info *fs_info)
 {
-    unsigned int next_pos;
-    unsigned long flags;
     struct devfsd_buf_entry *entry;
+    struct devfs_entry *curr;
 
     if ( !( fs_info->devfsd_event_mask & (1 << type) ) ) return (FALSE);
-    next_pos = fs_info->devfsd_buf_in + 1;
-    if (next_pos >= devfsd_buf_size) next_pos = 0;
-    if (next_pos == fs_info->devfsd_buf_out)
+    if ( ( entry = kmem_cache_alloc (devfsd_buf_cache, 0) ) == NULL )
     {
-	/*  Running up the arse of the reader: drop it  */
 	atomic_inc (&fs_info->devfsd_overrun_count);
 	return (FALSE);
     }
-    spin_lock_irqsave (&fs_info->devfsd_buffer_lock, flags);
-    next_pos = fs_info->devfsd_buf_in + 1;
-    if (next_pos >= devfsd_buf_size) next_pos = 0;
-    entry = (struct devfsd_buf_entry *) fs_info->devfsd_buffer +
-	fs_info->devfsd_buf_in;
-    entry->data = data;
+    for (curr = de; curr != NULL; curr = curr->parent) devfs_get (curr);
+    entry->de = de;
     entry->type = type;
     entry->mode = mode;
     entry->uid = uid;
     entry->gid = gid;
-    fs_info->devfsd_buf_in = next_pos;
-    spin_unlock_irqrestore (&fs_info->devfsd_buffer_lock, flags);
+    entry->next = NULL;
+    spin_lock (&fs_info->devfsd_buffer_lock);
+    if (!fs_info->devfsd_first_event) fs_info->devfsd_first_event = entry;
+    if (fs_info->devfsd_last_event) fs_info->devfsd_last_event->next = entry;
+    fs_info->devfsd_last_event = entry;
+    spin_unlock (&fs_info->devfsd_buffer_lock);
     wake_up_interruptible (&fs_info->devfsd_wait_queue);
     return (TRUE);
-}   /*  End Function devfsd_notify_one  */
+}   /*  End Function devfsd_notify_de  */
 
 
 /**
- *	devfsd_notify - Notify all devfsd daemons of a change.
+ *	devfsd_notify - Notify the devfsd daemon of a change.
  *	@de: The devfs entry that has changed.
  *	@type: The type of change event.
- *	@wait: If TRUE, the functions waits for all daemons to finish processing
+ *	@wait: If TRUE, the function waits for the daemon to finish processing
  *		the event.
  */
 
-static void devfsd_notify (struct devfs_entry *de, unsigned int type, int wait)
+static void devfsd_notify (struct devfs_entry *de,unsigned short type,int wait)
 {
-    if (devfsd_notify_one (de, type, de->mode, current->euid,
-			   current->egid, &fs_info) && wait)
+    if (devfsd_notify_de (de, type, de->mode, current->euid,
+			  current->egid, &fs_info) && wait)
 	wait_for_devfsd_finished (&fs_info);
 }   /*  End Function devfsd_notify  */
 
@@ -1287,7 +1452,7 @@
 			       umode_t mode, void *ops, void *info)
 {
     char devtype = S_ISCHR (mode) ? DEVFS_SPECIAL_CHR : DEVFS_SPECIAL_BLK;
-    int is_new;
+    int err;
     kdev_t devnum = NODEV;
     struct devfs_entry *de;
 
@@ -1332,146 +1497,127 @@
 	major = MAJOR (devnum);
 	minor = MINOR (devnum);
     }
-    de = search_for_entry (dir, name, strlen (name), TRUE, TRUE, &is_new,
-			   FALSE);
-    if (de == NULL)
+    if ( ( de = _devfs_prepare_leaf (&dir, name, mode) ) == NULL )
     {
-	printk ("%s: devfs_register(): could not create entry: \"%s\"\n",
+	printk ("%s: devfs_register(%s): could not prepare leaf\n",
 		DEVFS_NAME, name);
 	if (devnum != NODEV) devfs_dealloc_devnum (devtype, devnum);
 	return NULL;
     }
-#ifdef CONFIG_DEVFS_DEBUG
-    if (devfs_debug & DEBUG_REGISTER)
-	printk ("%s: devfs_register(%s): de: %p %s\n",
-		DEVFS_NAME, name, de, is_new ? "new" : "existing");
-#endif
-    if (!is_new)
-    {
-	/*  Existing entry  */
-	if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) &&
-	     !S_ISREG (de->mode) )
-	{
-	    printk ("%s: devfs_register(): existing non-device/file entry: \"%s\"\n",
-		    DEVFS_NAME, name);
-	    if (devnum != NODEV) devfs_dealloc_devnum (devtype, devnum);
-	    return NULL;
-	}
-	if (de->registered)
-	{
-	    printk("%s: devfs_register(): device already registered: \"%s\"\n",
-		   DEVFS_NAME, name);
-	    if (devnum != NODEV) devfs_dealloc_devnum (devtype, devnum);
-	    return NULL;
-	}
-    }
-    de->u.fcb.autogen = FALSE;
     if ( S_ISCHR (mode) || S_ISBLK (mode) )
     {
 	de->u.fcb.u.device.major = major;
 	de->u.fcb.u.device.minor = minor;
 	de->u.fcb.autogen = (devnum == NODEV) ? FALSE : TRUE;
     }
-    else if ( S_ISREG (mode) ) de->u.fcb.u.file.size = 0;
-    else
+    else if ( !S_ISREG (mode) )
     {
-	printk ("%s: devfs_register(): illegal mode: %x\n",
-		DEVFS_NAME, mode);
+	printk ("%s: devfs_register(%s): illegal mode: %x\n",
+		DEVFS_NAME, name, mode);
+	devfs_put (de);
+	devfs_put (dir);
 	return (NULL);
     }
     de->info = info;
-    de->mode = mode;
     if (flags & DEVFS_FL_CURRENT_OWNER)
     {
-	de->u.fcb.default_uid = current->uid;
-	de->u.fcb.default_gid = current->gid;
+	de->inode.uid = current->uid;
+	de->inode.gid = current->gid;
     }
     else
     {
-	de->u.fcb.default_uid = 0;
-	de->u.fcb.default_gid = 0;
+	de->inode.uid = 0;
+	de->inode.gid = 0;
     }
     de->u.fcb.ops = ops;
     de->u.fcb.auto_owner = (flags & DEVFS_FL_AUTO_OWNER) ? TRUE : FALSE;
     de->u.fcb.aopen_notify = (flags & DEVFS_FL_AOPEN_NOTIFY) ? TRUE : FALSE;
-    if (flags & DEVFS_FL_REMOVABLE)
-    {
-	de->u.fcb.removable = TRUE;
-	++de->parent->u.dir.num_removable;
-    }
-    de->u.fcb.open = FALSE;
     de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;
-    de->no_persistence = (flags & DEVFS_FL_NO_PERSISTENCE) ? TRUE : FALSE;
-    de->registered = TRUE;
+    if (flags & DEVFS_FL_REMOVABLE) de->u.fcb.removable = TRUE;
+    if ( ( err = _devfs_append_entry (dir, de, de->u.fcb.removable, NULL) )
+	 != 0 )
+    {
+	printk("%s: devfs_register(%s): could not append to parent, err: %d\n",
+	       DEVFS_NAME, name, err);
+	devfs_put (dir);
+	if (devnum != NODEV) devfs_dealloc_devnum (devtype, devnum);
+	return NULL;
+    }
+#ifdef CONFIG_DEVFS_DEBUG
+    if (devfs_debug & DEBUG_REGISTER)
+	printk ("%s: devfs_register(%s): de: %p dir: %p \"%s\"  pp: %p\n",
+		DEVFS_NAME, name, de, dir, dir->name, dir->parent);
+#endif
     devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT);
+    devfs_put (dir);
     return de;
 }   /*  End Function devfs_register  */
 
 
 /**
- *	unregister - Unregister a device entry.
+ *	_devfs_unhook - Unhook a device entry from its parents list
+ *	@de: The entry to unhook.
+ *
+ *	Returns %TRUE if the entry was unhooked, else %FALSE if it was
+ *		previously unhooked.
+ *	The caller must have a write lock on the parent directory.
+ */
+
+static int _devfs_unhook (struct devfs_entry *de)
+{
+    struct devfs_entry *parent;
+
+    if ( !de || (de->prev == de) ) return FALSE;
+    parent = de->parent;
+    if (de->prev == NULL) parent->u.dir.first = de->next;
+    else de->prev->next = de->next;
+    if (de->next == NULL) parent->u.dir.last = de->prev;
+    else de->next->prev = de->prev;
+    de->prev = de;          /*  Indicate we're unhooked                      */
+    de->next = NULL;        /*  Force early termination for <devfs_readdir>  */
+    if ( ( S_ISREG (de->mode) || S_ISCHR (de->mode) || S_ISBLK (de->mode) ) &&
+	 de->u.fcb.removable )
+	--parent->u.dir.num_removable;
+    return TRUE;
+}   /*  End Function _devfs_unhook  */
+
+
+/**
+ *	unregister - Unregister a device entry from it's parent.
+ *	@dir: The parent directory.
  *	@de: The entry to unregister.
+ *
+ *	The caller must have a write lock on the parent directory, which is
+ *	unlocked by this function.
  */
 
-static void unregister (struct devfs_entry *de)
+static void unregister (struct devfs_entry *dir, struct devfs_entry *de)
 {
-    struct devfs_entry *child;
+    int unhooked = _devfs_unhook (de);
 
-    if ( (child = de->slave) != NULL )
-    {
-	de->slave = NULL;  /* Unhook first in case slave is parent directory */
-	unregister (child);
-    }
-    if (de->registered)
-    {
-	devfsd_notify (de, DEVFSD_NOTIFY_UNREGISTERED, 0);
-	free_dentries (de);
-    }
-    de->info = NULL;
-    if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
-    {
-	de->registered = FALSE;
-	de->u.fcb.ops = NULL;
-	if (!S_ISREG (de->mode) && de->u.fcb.autogen)
-	{
-	    devfs_dealloc_devnum ( S_ISCHR (de->mode) ? DEVFS_SPECIAL_CHR :
-				   DEVFS_SPECIAL_BLK,
-				   MKDEV (de->u.fcb.u.device.major,
-					  de->u.fcb.u.device.minor) );
-	}
-	de->u.fcb.autogen = FALSE;
-	return;
-    }
-    if (S_ISLNK (de->mode) && de->registered)
-    {
-	de->registered = FALSE;
-	down_write (&symlink_rwsem);
-	if (de->u.symlink.linkname) kfree (de->u.symlink.linkname);
-	de->u.symlink.linkname = NULL;
-	up_write (&symlink_rwsem);
-	return;
-    }
-    if ( S_ISFIFO (de->mode) )
-    {
-	de->registered = FALSE;
-	return;
-    }
-    if (!de->registered) return;
-    if ( !S_ISDIR (de->mode) )
-    {
-	printk ("%s: unregister(): unsupported type\n", DEVFS_NAME);
-	return;
-    }
-    de->registered = FALSE;
-    /*  Now recursively search the subdirectories: this is a stack chomper  */
-    for (child = de->u.dir.first; child != NULL; child = child->next)
-    {
+    write_unlock (&dir->u.dir.lock);
+    if (!unhooked) return;
+    devfs_get (dir);
+    devfs_unregister (de->slave);  /*  Let it handle the locking  */
+    devfsd_notify (de, DEVFSD_NOTIFY_UNREGISTERED, 0);
+    free_dentry (de);
+    devfs_put (dir);
+    if ( !S_ISDIR (de->mode) ) return;
+    while (TRUE)  /*  Recursively unregister: this is a stack chomper  */
+    {
+	struct devfs_entry *child;
+
+	write_lock (&de->u.dir.lock);
+	de->u.dir.no_more_additions = TRUE;
+	child = de->u.dir.first;
+	unregister (de, child);
+	if (!child) break;
 #ifdef CONFIG_DEVFS_DEBUG
 	if (devfs_debug & DEBUG_UNREGISTER)
 	    printk ("%s: unregister(): child->name: \"%s\" child: %p\n",
 		    DEVFS_NAME, child->name, child);
 #endif
-	unregister (child);
+	devfs_put (child);
     }
 }   /*  End Function unregister  */
 
@@ -1484,20 +1630,22 @@
 
 void devfs_unregister (devfs_handle_t de)
 {
-    if (de == NULL) return;
+    if ( (de == NULL) || (de->parent == NULL) ) return;
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_UNREGISTER)
 	printk ("%s: devfs_unregister(): de->name: \"%s\" de: %p\n",
 		DEVFS_NAME, de->name, de);
 #endif
-    unregister (de);
+    write_lock (&de->parent->u.dir.lock);
+    unregister (de->parent, de);
+    devfs_put (de);
 }   /*  End Function devfs_unregister  */
 
 static int devfs_do_symlink (devfs_handle_t dir, const char *name,
 			     unsigned int flags, const char *link,
 			     devfs_handle_t *handle, void *info)
 {
-    int is_new;
+    int err;
     unsigned int linklength;
     char *newlink;
     struct devfs_entry *de;
@@ -1522,28 +1670,31 @@
 	return -ENOMEM;
     memcpy (newlink, link, linklength);
     newlink[linklength] = '\0';
-    if ( ( de = search_for_entry (dir, name, strlen (name), TRUE, TRUE,
-				  &is_new, FALSE) ) == NULL )
+    if ( ( de = _devfs_prepare_leaf (&dir, name, S_IFLNK | S_IRUGO | S_IXUGO) )
+	 == NULL )
     {
-	kfree (newlink);
-	return -ENOMEM;
-    }
-    down_write (&symlink_rwsem);
-    if (de->registered)
-    {
-	up_write (&symlink_rwsem);
-	kfree (newlink);
-	printk ("%s: devfs_do_symlink(%s): entry already exists\n",
+	printk ("%s: devfs_do_symlink(%s): could not prepare leaf\n",
 		DEVFS_NAME, name);
-	return -EEXIST;
+	kfree (newlink);
+	return -ENOTDIR;
     }
-    de->mode = S_IFLNK | S_IRUGO | S_IXUGO;
     de->info = info;
     de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;
     de->u.symlink.linkname = newlink;
     de->u.symlink.length = linklength;
-    de->registered = TRUE;
-    up_write (&symlink_rwsem);
+    if ( ( err = _devfs_append_entry (dir, de, FALSE, NULL) ) != 0 )
+    {
+	printk ("%s: devfs_do_symlink(%s): could not append to parent, err: %d\n",
+		DEVFS_NAME, name, err);
+	devfs_put (dir);
+	return err;
+    }
+    devfs_put (dir);
+#ifdef CONFIG_DEVFS_DEBUG
+    spin_lock (&stat_lock);
+    stat_num_bytes += linklength + 1;
+    spin_unlock (&stat_lock);
+#endif
     if (handle != NULL) *handle = de;
     return 0;
 }   /*  End Function devfs_do_symlink  */
@@ -1593,7 +1744,7 @@
 
 devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name, void *info)
 {
-    int is_new;
+    int err;
     struct devfs_entry *de;
 
     if (name == NULL)
@@ -1601,36 +1752,27 @@
 	printk ("%s: devfs_mk_dir(): NULL name pointer\n", DEVFS_NAME);
 	return NULL;
     }
-    de = search_for_entry (dir, name, strlen (name), TRUE, TRUE, &is_new,
-			   FALSE);
-    if (de == NULL)
+    if ( ( de = _devfs_prepare_leaf (&dir, name, MODE_DIR) ) == NULL )
     {
-	printk ("%s: devfs_mk_dir(): could not create entry: \"%s\"\n",
+	printk ("%s: devfs_mk_dir(%s): could not prepare leaf\n",
 		DEVFS_NAME, name);
 	return NULL;
     }
-    if (!S_ISDIR (de->mode) && de->registered)
+    de->info = info;
+    if ( ( err = _devfs_append_entry (dir, de, FALSE, NULL) ) != 0 )
     {
-	printk ("%s: devfs_mk_dir(): existing non-directory entry: \"%s\"\n",
-		DEVFS_NAME, name);
+	printk ("%s: devfs_mk_dir(%s): could not append to dir: %p \"%s\", err: %d\n",
+		DEVFS_NAME, name, dir, dir->name, err);
+	devfs_put (dir);
 	return NULL;
     }
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_REGISTER)
-	printk ("%s: devfs_mk_dir(%s): de: %p %s\n",
-		DEVFS_NAME, name, de, is_new ? "new" : "existing");
+	printk ("%s: devfs_mk_dir(%s): de: %p dir: %p \"%s\"\n",
+		DEVFS_NAME, name, de, dir, dir->name);
 #endif
-    if (!S_ISDIR (de->mode) && !is_new)
-    {
-	/*  Transmogrifying an old entry  */
-	de->u.dir.first = NULL;
-	de->u.dir.last = NULL;
-    }
-    de->mode = S_IFDIR | S_IRUGO | S_IXUGO;
-    de->info = info;
-    if (!de->registered) de->u.dir.num_removable = 0;
-    de->hide = FALSE;
-    de->registered = TRUE;
+    devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, DEVFS_FL_NONE);
+    devfs_put (dir);
     return de;
 }   /*  End Function devfs_mk_dir  */
 
@@ -1660,8 +1802,8 @@
 
     if ( (name != NULL) && (name[0] == '\0') ) name = NULL;
     de = find_entry (dir, name, 0, major, minor, type, traverse_symlinks);
-    if (de == NULL) return NULL;
-    if (!de->registered) return NULL;
+    devfs_put (de);  /*  FIXME: in 2.5 consider dropping this and require a
+			 call to devfs_put()  */
     return de;
 }   /*  End Function devfs_find_handle  */
 
@@ -1679,7 +1821,6 @@
     unsigned int fl = 0;
 
     if (de == NULL) return -EINVAL;
-    if (!de->registered) return -ENODEV;
     if (de->hide) fl |= DEVFS_FL_HIDE;
     if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
     {
@@ -1703,7 +1844,6 @@
 int devfs_set_flags (devfs_handle_t de, unsigned int flags)
 {
     if (de == NULL) return -EINVAL;
-    if (!de->registered) return -ENODEV;
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_SET_FLAGS)
 	printk ("%s: devfs_set_flags(): de->name: \"%s\"\n",
@@ -1714,16 +1854,6 @@
     {
 	de->u.fcb.auto_owner = (flags & DEVFS_FL_AUTO_OWNER) ? TRUE : FALSE;
 	de->u.fcb.aopen_notify = (flags & DEVFS_FL_AOPEN_NOTIFY) ? TRUE:FALSE;
-	if ( de->u.fcb.removable && !(flags & DEVFS_FL_REMOVABLE) )
-	{
-	    de->u.fcb.removable = FALSE;
-	    --de->parent->u.dir.num_removable;
-	}
-	else if ( !de->u.fcb.removable && (flags & DEVFS_FL_REMOVABLE) )
-	{
-	    de->u.fcb.removable = TRUE;
-	    ++de->parent->u.dir.num_removable;
-	}
     }
     return 0;
 }   /*  End Function devfs_set_flags  */
@@ -1742,7 +1872,6 @@
 		       unsigned int *minor)
 {
     if (de == NULL) return -EINVAL;
-    if (!de->registered) return -ENODEV;
     if ( S_ISDIR (de->mode) ) return -EISDIR;
     if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) ) return -EINVAL;
     if (major != NULL) *major = de->u.fcb.u.device.major;
@@ -1762,7 +1891,7 @@
 {
     if (!inode || !inode->i_sb) return NULL;
     if (inode->i_sb->s_magic != DEVFS_SUPER_MAGIC) return NULL;
-    return get_devfs_entry_from_vfs_inode (inode, TRUE);
+    return get_devfs_entry_from_vfs_inode (inode);
 }   /*  End Function devfs_get_handle_from_inode  */
 
 
@@ -1780,19 +1909,20 @@
 int devfs_generate_path (devfs_handle_t de, char *path, int buflen)
 {
     int pos;
+#define NAMEOF(de) ( (de)->mode ? (de)->name : (de)->u.name )
 
     if (de == NULL) return -EINVAL;
     if (de->namelen >= buflen) return -ENAMETOOLONG; /*  Must be first       */
     path[buflen - 1] = '\0';
     if (de->parent == NULL) return buflen - 1;       /*  Don't prepend root  */
     pos = buflen - de->namelen - 1;
-    memcpy (path + pos, de->name, de->namelen);
+    memcpy (path + pos, NAMEOF (de), de->namelen);
     for (de = de->parent; de->parent != NULL; de = de->parent)
     {
 	if (pos - de->namelen - 1 < 0) return -ENAMETOOLONG;
 	path[--pos] = '/';
 	pos -= de->namelen;
-	memcpy (path + pos, de->name, de->namelen);
+	memcpy (path + pos, NAMEOF (de), de->namelen);
     }
     return pos;
 }   /*  End Function devfs_generate_path  */
@@ -1808,7 +1938,6 @@
 void *devfs_get_ops (devfs_handle_t de)
 {
     if (de == NULL) return NULL;
-    if (!de->registered) return NULL;
     if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
 	return de->u.fcb.ops;
     return NULL;
@@ -1826,7 +1955,6 @@
 int devfs_set_file_size (devfs_handle_t de, unsigned long size)
 {
     if (de == NULL) return -EINVAL;
-    if (!de->registered) return -EINVAL;
     if ( !S_ISREG (de->mode) ) return -EINVAL;
     if (de->u.fcb.u.file.size == size) return 0;
     de->u.fcb.u.file.size = size;
@@ -1846,7 +1974,6 @@
 void *devfs_get_info (devfs_handle_t de)
 {
     if (de == NULL) return NULL;
-    if (!de->registered) return NULL;
     return de->info;
 }   /*  End Function devfs_get_info  */
 
@@ -1861,7 +1988,6 @@
 int devfs_set_info (devfs_handle_t de, void *info)
 {
     if (de == NULL) return -EINVAL;
-    if (!de->registered) return -EINVAL;
     de->info = info;
     return 0;
 }   /*  End Function devfs_set_info  */
@@ -1876,7 +2002,6 @@
 devfs_handle_t devfs_get_parent (devfs_handle_t de)
 {
     if (de == NULL) return NULL;
-    if (!de->registered) return NULL;
     return de->parent;
 }   /*  End Function devfs_get_parent  */
 
@@ -1891,7 +2016,6 @@
 devfs_handle_t devfs_get_first_child (devfs_handle_t de)
 {
     if (de == NULL) return NULL;
-    if (!de->registered) return NULL;
     if ( !S_ISDIR (de->mode) ) return NULL;
     return de->u.dir.first;
 }   /*  End Function devfs_get_first_child  */
@@ -1907,7 +2031,6 @@
 devfs_handle_t devfs_get_next_sibling (devfs_handle_t de)
 {
     if (de == NULL) return NULL;
-    if (!de->registered) return NULL;
     return de->next;
 }   /*  End Function devfs_get_next_sibling  */
 
@@ -1961,7 +2084,6 @@
 const char *devfs_get_name (devfs_handle_t de, unsigned int *namelen)
 {
     if (de == NULL) return NULL;
-    if (!de->registered) return NULL;
     if (namelen != NULL) *namelen = de->namelen;
     return de->name;
 }   /*  End Function devfs_get_name  */
@@ -2057,8 +2179,10 @@
 	{"dmod",      DEBUG_MODULE_LOAD,  &devfs_debug_init},
 	{"dreg",      DEBUG_REGISTER,     &devfs_debug_init},
 	{"dunreg",    DEBUG_UNREGISTER,   &devfs_debug_init},
+	{"dfree",     DEBUG_FREE,         &devfs_debug_init},
 	{"diget",     DEBUG_I_GET,        &devfs_debug_init},
 	{"dchange",   DEBUG_SET_FLAGS,    &devfs_debug_init},
+	{"dsread",    DEBUG_S_READ,       &devfs_debug_init},
 	{"dichange",  DEBUG_I_CHANGE,     &devfs_debug_init},
 	{"dimknod",   DEBUG_I_MKNOD,      &devfs_debug_init},
 	{"dilookup",  DEBUG_I_LOOKUP,     &devfs_debug_init},
@@ -2129,34 +2253,31 @@
 
 
 /**
- *	try_modload - Notify devfsd of an inode lookup.
+ *	try_modload - Notify devfsd of an inode lookup by a non-devfsd process.
  *	@parent: The parent devfs entry.
  *	@fs_info: The filesystem info.
  *	@name: The device name.
  *	@namelen: The number of characters in @name.
- *	@buf: A working area that will be used. This must not go out of scope until
- *		devfsd is idle again.
+ *	@buf: A working area that will be used. This must not go out of scope
+ *            until devfsd is idle again.
  *
  *	Returns 0 on success, else a negative error code.
  */
 
 static int try_modload (struct devfs_entry *parent, struct fs_info *fs_info,
 			const char *name, unsigned namelen,
-			char buf[STRING_LENGTH])
+			struct devfs_entry *buf)
 {
-    int pos = STRING_LENGTH - namelen - 1;
-
     if ( !( fs_info->devfsd_event_mask & (1 << DEVFSD_NOTIFY_LOOKUP) ) )
 	return -ENOENT;
     if ( is_devfsd_or_child (fs_info) ) return -ENOENT;
-    if (namelen >= STRING_LENGTH - 1) return -ENAMETOOLONG;
-    memcpy (buf + pos, name, namelen);
-    buf[STRING_LENGTH - 1] = '\0';
-    if (parent->parent != NULL) pos = devfs_generate_path (parent, buf, pos);
-    if (pos < 0) return pos;
-    buf[STRING_LENGTH - namelen - 2] = '/';
-    if ( !devfsd_notify_one (buf + pos, DEVFSD_NOTIFY_LOOKUP, 0,
-			     current->euid, current->egid, fs_info) )
+    memset (buf, 0, sizeof *buf);
+    atomic_set (&buf->refcount, 1);
+    buf->parent = parent;
+    buf->namelen = namelen;
+    buf->u.name = name;
+    if ( !devfsd_notify_de (buf, DEVFSD_NOTIFY_LOOKUP, 0,
+			    current->euid, current->egid, fs_info) )
 	return -ENOENT;
     /*  Possible success  */
     return 0;
@@ -2206,7 +2327,6 @@
     if (dir->u.dir.num_removable < 1) return;
     for (de = dir->u.dir.first; de != NULL; de = de->next)
     {
-	if (!de->registered) continue;
 	if ( !S_ISBLK (de->mode) ) continue;
 	if (!de->u.fcb.removable) continue;
 	check_disc_changed (de);
@@ -2229,7 +2349,6 @@
 
     for (de = dir->u.dir.first; de != NULL; de = de->next)
     {
-	if (!de->registered) continue;
 	if ( !S_ISBLK (de->mode) ) continue;
 	if (!de->u.fcb.removable) continue;
 	if (strcmp (de->name, "disc") == 0) return check_disc_changed (de);
@@ -2258,7 +2377,7 @@
     struct inode *inode = dentry->d_inode;
     struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
 
-    de = get_devfs_entry_from_vfs_inode (inode, TRUE);
+    de = get_devfs_entry_from_vfs_inode (inode);
     if (de == NULL) return -ENODEV;
     retval = inode_change_ok (inode, iattr);
     if (retval != 0) return retval;
@@ -2276,15 +2395,20 @@
 #endif
     /*  Inode is not on hash chains, thus must save permissions here rather
 	than in a write_inode() method  */
-    de->inode.mode = inode->i_mode;
-    de->inode.uid = inode->i_uid;
-    de->inode.gid = inode->i_gid;
+    if ( ( !S_ISREG (inode->i_mode) && !S_ISCHR (inode->i_mode) &&
+	   !S_ISBLK (inode->i_mode) ) || !de->u.fcb.auto_owner )
+    {
+	de->mode = inode->i_mode;
+	de->inode.uid = inode->i_uid;
+	de->inode.gid = inode->i_gid;
+    }
     de->inode.atime = inode->i_atime;
     de->inode.mtime = inode->i_mtime;
     de->inode.ctime = inode->i_ctime;
-    if ( iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID) )
-	devfsd_notify_one (de, DEVFSD_NOTIFY_CHANGE, inode->i_mode,
-			   inode->i_uid, inode->i_gid, fs_info);
+    if ( ( iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID) ) &&
+	 !is_devfsd_or_child (fs_info) )
+	devfsd_notify_de (de, DEVFSD_NOTIFY_CHANGE, inode->i_mode,
+			  inode->i_uid, inode->i_gid, fs_info);
     return 0;
 }   /*  End Function devfs_notify_change  */
 
@@ -2299,11 +2423,10 @@
     return 0;
 }   /*  End Function devfs_statfs  */
 
-static void devfs_clear_inode(struct inode *inode)
+static void devfs_clear_inode (struct inode *inode)
 {
-	if (S_ISBLK(inode->i_mode))
-		bdput(inode->i_bdev);
-}
+    if ( S_ISBLK (inode->i_mode) ) bdput (inode->i_bdev);
+}   /*  End Function devfs_clear_inode  */
 
 static struct super_operations devfs_sops =
 { 
@@ -2319,32 +2442,37 @@
  *	@de: The devfs inode.
  *	@dentry: The dentry to register with the devfs inode.
  *
- *	Returns the inode on success, else %NULL.
+ *	Returns the inode on success, else %NULL. An implicit devfs_get() is
+ *       performed if the inode is created.
  */
 
 static struct inode *get_vfs_inode (struct super_block *sb,
 				    struct devfs_entry *de,
 				    struct dentry *dentry)
 {
+    int is_fcb = FALSE;
     struct inode *inode;
 
-    if (de->inode.dentry != NULL)
-    {
-	printk ("%s: get_vfs_inode(%u): old de->inode.dentry: %p \"%s\"  new dentry: %p \"%s\"\n",
-		DEVFS_NAME, de->inode.ino,
-		de->inode.dentry, de->inode.dentry->d_name.name,
-		dentry, dentry->d_name.name);
-	printk ("  old inode: %p\n", de->inode.dentry->d_inode);
-	return NULL;
-    }
+    if (de->prev == de) return NULL;  /*  Quick check to see if unhooked  */
     if ( ( inode = new_inode (sb) ) == NULL )
     {
 	printk ("%s: get_vfs_inode(%s): new_inode() failed, de: %p\n",
 		DEVFS_NAME, de->name, de);
 	return NULL;
     }
-    de->inode.dentry = dentry;
-    inode->u.generic_ip = de;
+    if (de->parent)
+    {
+	read_lock (&de->parent->u.dir.lock);
+	if (de->prev != de) de->inode.dentry = dentry; /*      Not unhooked  */
+	read_unlock (&de->parent->u.dir.lock);
+    }
+    else de->inode.dentry = dentry;             /*  Root: no locking needed  */
+    if (de->inode.dentry != dentry)
+    {   /*  Must have been unhooked  */
+	iput (inode);
+	return NULL;
+    }
+    inode->u.generic_ip = devfs_get (de);
     inode->i_ino = de->inode.ino;
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_I_GET)
@@ -2356,37 +2484,45 @@
     inode->i_op = &devfs_iops;
     inode->i_fop = &devfs_fops;
     inode->i_rdev = NODEV;
-    if ( S_ISCHR (de->inode.mode) )
+    if ( S_ISCHR (de->mode) )
     {
 	inode->i_rdev = MKDEV (de->u.fcb.u.device.major,
 			       de->u.fcb.u.device.minor);
-	inode->i_cdev = cdget (kdev_t_to_nr(inode->i_rdev));
+	inode->i_cdev = cdget ( kdev_t_to_nr (inode->i_rdev) );
+	is_fcb = TRUE;
     }
-    else if ( S_ISBLK (de->inode.mode) )
+    else if ( S_ISBLK (de->mode) )
     {
 	inode->i_rdev = MKDEV (de->u.fcb.u.device.major,
 			       de->u.fcb.u.device.minor);
-	if (bd_acquire(inode) == 0)
+	if (bd_acquire (inode) == 0)
 	{
 	    if (!inode->i_bdev->bd_op && de->u.fcb.ops)
 		inode->i_bdev->bd_op = de->u.fcb.ops;
 	}
 	else printk ("%s: get_vfs_inode(%d): no block device from bdget()\n",
 		     DEVFS_NAME, (int) inode->i_ino);
+	is_fcb = TRUE;
+    }
+    else if ( S_ISFIFO (de->mode) ) inode->i_fop = &def_fifo_fops;
+    else if ( S_ISREG (de->mode) )
+    {
+	inode->i_size = de->u.fcb.u.file.size;
+	is_fcb = TRUE;
     }
-    else if ( S_ISFIFO (de->inode.mode) ) inode->i_fop = &def_fifo_fops;
-    else if ( S_ISREG (de->inode.mode) ) inode->i_size = de->u.fcb.u.file.size;
-    else if ( S_ISDIR (de->inode.mode) )
+    else if ( S_ISDIR (de->mode) )
     {
 	inode->i_op = &devfs_dir_iops;
     	inode->i_fop = &devfs_dir_fops;
     }
-    else if ( S_ISLNK (de->inode.mode) )
+    else if ( S_ISLNK (de->mode) )
     {
 	inode->i_op = &devfs_symlink_iops;
 	inode->i_size = de->u.symlink.length;
     }
-    inode->i_mode = de->inode.mode;
+    if (is_fcb && de->u.fcb.auto_owner)
+	inode->i_mode = (de->mode & S_IFMT) | S_IRUGO | S_IWUGO;
+    else inode->i_mode = de->mode;
     inode->i_uid = de->inode.uid;
     inode->i_gid = de->inode.gid;
     inode->i_atime = de->inode.atime;
@@ -2409,11 +2545,11 @@
     int err, count;
     int stored = 0;
     struct fs_info *fs_info;
-    struct devfs_entry *parent, *de;
+    struct devfs_entry *parent, *de, *next = NULL;
     struct inode *inode = file->f_dentry->d_inode;
 
     fs_info = inode->i_sb->u.generic_sbp;
-    parent = get_devfs_entry_from_vfs_inode (file->f_dentry->d_inode, TRUE);
+    parent = get_devfs_entry_from_vfs_inode (file->f_dentry->d_inode);
     if ( (long) file->f_pos < 0 ) return -EINVAL;
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_F_READDIR)
@@ -2441,19 +2577,32 @@
       default:
 	/*  Skip entries  */
 	count = file->f_pos - 2;
-	for (de = parent->u.dir.first; (de != NULL) && (count > 0);
-	     de = de->next)
+	read_lock (&parent->u.dir.lock);
+	for (de = parent->u.dir.first; de && (count > 0); de = de->next)
 	    if ( !IS_HIDDEN (de) ) --count;
+	devfs_get (de);
+	read_unlock (&parent->u.dir.lock);
 	/*  Now add all remaining entries  */
-	for (; de != NULL; de = de->next)
+	while (de)
 	{
-	    if ( IS_HIDDEN (de) ) continue;
-	    err = (*filldir) (dirent, de->name, de->namelen,
-			      file->f_pos, de->inode.ino, de->mode >> 12);
+	    if ( IS_HIDDEN (de) ) err = 0;
+	    else
+	    {
+		err = (*filldir) (dirent, de->name, de->namelen,
+				  file->f_pos, de->inode.ino, de->mode >> 12);
+		if (err >= 0)
+		{
+		    file->f_pos++;
+		    ++stored;
+		}
+	    }
+	    read_lock (&parent->u.dir.lock);
+	    next = devfs_get (de->next);
+	    read_unlock (&parent->u.dir.lock);
+	    devfs_put (de);
+	    de = next;
 	    if (err == -EINVAL) break;
 	    if (err < 0) return err;
-	    file->f_pos++;
-	    ++stored;
 	}
 	break;
     }
@@ -2467,14 +2616,9 @@
     struct devfs_entry *de;
     struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
 
-    lock_kernel ();
-    de = get_devfs_entry_from_vfs_inode (inode, TRUE);
-    err = -ENODEV;
-    if (de == NULL)
-	goto out;
-    err = 0;
-    if ( S_ISDIR (de->mode) )
-	goto out;
+    de = get_devfs_entry_from_vfs_inode (inode);
+    if (de == NULL) return -ENODEV;
+    if ( S_ISDIR (de->mode) ) return 0;
     df = &de->u.fcb;
     file->private_data = de->info;
     if ( S_ISBLK (inode->i_mode) )
@@ -2482,7 +2626,7 @@
 	file->f_op = &def_blk_fops;
 	if (df->ops) inode->i_bdev->bd_op = df->ops;
     }
-    else file->f_op = fops_get ( (struct file_operations*) df->ops );
+    else file->f_op = fops_get ( (struct file_operations *) df->ops );
     if (file->f_op)
 	err = file->f_op->open ? (*file->f_op->open) (inode, file) : 0;
     else
@@ -2491,39 +2635,33 @@
 	if ( S_ISCHR (inode->i_mode) ) err = chrdev_open (inode, file);
 	else err = -ENODEV;
     }
-    if (err < 0) goto out;
+    if (err < 0) return err;
     /*  Open was successful  */
-    err = 0;
-    if (df->open) goto out;
+    if (df->open) return 0;
     df->open = TRUE;  /*  This is the first open  */
     if (df->auto_owner)
     {
-	/*  Change the ownership/protection  */
-	de->inode.mode = (de->inode.mode & ~S_IALLUGO) |(de->mode & S_IRWXUGO);
-	de->inode.uid = current->euid;
-	de->inode.gid = current->egid;
-	inode->i_mode = de->inode.mode;
-	inode->i_uid = de->inode.uid;
-	inode->i_gid = de->inode.gid;
-    }
-    if (df->aopen_notify)
-	devfsd_notify_one (de, DEVFSD_NOTIFY_ASYNC_OPEN, inode->i_mode,
-			   current->euid, current->egid, fs_info);
-out:
-    unlock_kernel ();
-    return err;
+	/*  Change the ownership/protection to what driver specified  */
+	inode->i_mode = de->mode;
+	inode->i_uid = current->euid;
+	inode->i_gid = current->egid;
+    }
+    if ( df->aopen_notify && !is_devfsd_or_child (fs_info) )
+	devfsd_notify_de (de, DEVFSD_NOTIFY_ASYNC_OPEN, inode->i_mode,
+			  current->euid, current->egid, fs_info);
+    return 0;
 }   /*  End Function devfs_open  */
 
 static struct file_operations devfs_fops =
 {
-    open: devfs_open,
+    open:    devfs_open,
 };
 
 static struct file_operations devfs_dir_fops =
 {
-    read: generic_read_dir,
+    read:    generic_read_dir,
     readdir: devfs_readdir,
-    open: devfs_open,
+    open:    devfs_open,
 };
 
 
@@ -2556,16 +2694,18 @@
 {
     struct devfs_entry *de;
 
-    lock_kernel ();
-    de = get_devfs_entry_from_vfs_inode (inode, FALSE);
+    de = get_devfs_entry_from_vfs_inode (inode);
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_D_IPUT)
 	printk ("%s: d_iput(): dentry: %p inode: %p de: %p  de->dentry: %p\n",
 		DEVFS_NAME, dentry, inode, de, de->inode.dentry);
 #endif
-    if (de->inode.dentry == dentry) de->inode.dentry = NULL;
-    unlock_kernel ();
+    if ( de->inode.dentry && (de->inode.dentry != dentry) )
+	OOPS ("%s: d_iput(%s): de: %p dentry: %p de->dentry: %p\n",
+	      DEVFS_NAME, de->name, de, dentry, de->inode.dentry);
+    de->inode.dentry = NULL;
     iput (inode);
+    devfs_put (de);
 }   /*  End Function devfs_d_iput  */
 
 static int devfs_d_delete (struct dentry *dentry);
@@ -2610,7 +2750,7 @@
 	return 1;
     }
     fs_info = inode->i_sb->u.generic_sbp;
-    de = get_devfs_entry_from_vfs_inode (inode, TRUE);
+    de = get_devfs_entry_from_vfs_inode (inode);
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_D_DELETE)
 	printk ("%s: d_delete(): dentry: %p  inode: %p  devfs_entry: %p\n",
@@ -2622,14 +2762,11 @@
     if (!de->u.fcb.open) return 0;
     de->u.fcb.open = FALSE;
     if (de->u.fcb.aopen_notify)
-	devfsd_notify_one (de, DEVFSD_NOTIFY_CLOSE, inode->i_mode,
-			   current->euid, current->egid, fs_info);
+	devfsd_notify_de (de, DEVFSD_NOTIFY_CLOSE, inode->i_mode,
+			  current->euid, current->egid, fs_info);
     if (!de->u.fcb.auto_owner) return 0;
     /*  Change the ownership/protection back  */
-    de->inode.mode = (de->inode.mode & ~S_IALLUGO) | S_IRUGO | S_IWUGO;
-    de->inode.uid = de->u.fcb.default_uid;
-    de->inode.gid = de->u.fcb.default_gid;
-    inode->i_mode = de->inode.mode;
+    inode->i_mode = (de->mode & S_IFMT) | S_IRUGO | S_IWUGO;
     inode->i_uid = de->inode.uid;
     inode->i_gid = de->inode.gid;
     return 0;
@@ -2637,59 +2774,38 @@
 
 static int devfs_d_revalidate_wait (struct dentry *dentry, int flags)
 {
-    devfs_handle_t de = dentry->d_fsdata;
-    struct inode *dir;
-    struct fs_info *fs_info;
+    struct inode *dir = dentry->d_parent->d_inode;
+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
 
-    lock_kernel ();
-    dir = dentry->d_parent->d_inode;
-    fs_info = dir->i_sb->u.generic_sbp;
-    if (!de || de->registered)
+    if ( !dentry->d_inode && is_devfsd_or_child (fs_info) )
     {
-	if ( !dentry->d_inode && is_devfsd_or_child (fs_info) )
-	{
-	    struct inode *inode;
-
-#ifdef CONFIG_DEVFS_DEBUG
-	    char txt[STRING_LENGTH];
-
-	    memset (txt, 0, STRING_LENGTH);
-	    memcpy (txt, dentry->d_name.name,
-		    (dentry->d_name.len >= STRING_LENGTH) ?
-		    (STRING_LENGTH - 1) : dentry->d_name.len);
-	    if (devfs_debug & DEBUG_I_LOOKUP)
-		printk ("%s: d_revalidate(): dentry: %p name: \"%s\" by: \"%s\"\n",
-			DEVFS_NAME, dentry, txt, current->comm);
-#endif
-	    if (de == NULL)
-	    {
-		devfs_handle_t parent;
-
-		parent = get_devfs_entry_from_vfs_inode (dir, TRUE);
-		de = search_for_entry_in_dir (parent, dentry->d_name.name,
-					      dentry->d_name.len, FALSE);
-	    }
-	    if (de == NULL) goto out;
-	    /*  Create an inode, now that the driver information is available
-	     */
-	    if (de->no_persistence) update_devfs_inode_from_entry (de);
-	    else if (de->inode.ctime == 0) update_devfs_inode_from_entry (de);
-	    else de->inode.mode =
-		     (de->mode & ~S_IALLUGO) | (de->inode.mode & S_IALLUGO);
-	    if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
-		goto out;
-#ifdef CONFIG_DEVFS_DEBUG
-	    if (devfs_debug & DEBUG_I_LOOKUP)
-		printk ("%s: d_revalidate(): new VFS inode(%u): %p  devfs_entry: %p\n",
-			DEVFS_NAME, de->inode.ino, inode, de);
+	devfs_handle_t de;
+	devfs_handle_t parent = get_devfs_entry_from_vfs_inode (dir);
+	struct inode *inode;
+
+#ifdef CONFIG_DEVFS_DEBUG
+	if (devfs_debug & DEBUG_I_LOOKUP)
+	    printk ("%s: d_revalidate(%s): dentry: %p by: \"%s\"\n",
+		    DEVFS_NAME, dentry->d_name.name, dentry, current->comm);
+#endif
+	read_lock (&parent->u.dir.lock);
+	de = _devfs_search_dir (parent, dentry->d_name.name,
+				dentry->d_name.len);
+	read_unlock (&parent->u.dir.lock);
+	if (de == NULL) return 1;
+	/*  Create an inode, now that the driver information is available  */
+	inode = get_vfs_inode (dir->i_sb, de, dentry);
+	devfs_put (de);
+	if (!inode) return 1;
+#ifdef CONFIG_DEVFS_DEBUG
+	if (devfs_debug & DEBUG_I_LOOKUP)
+	    printk ("%s: d_revalidate(): new VFS inode(%u): %p  devfs_entry: %p\n",
+		    DEVFS_NAME, de->inode.ino, inode, de);
 #endif
-	    d_instantiate (dentry, inode);
-	    goto out;
-	}
+	d_instantiate (dentry, inode);
+	return 1;
     }
     if ( wait_for_devfsd_finished (fs_info) ) dentry->d_op = &devfs_dops;
-out:
-    unlock_kernel ();
     return 1;
 }   /*  End Function devfs_d_revalidate_wait  */
 
@@ -2698,70 +2814,63 @@
 
 static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry)
 {
-    struct fs_info *fs_info;
+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
     struct devfs_entry *parent, *de;
     struct inode *inode;
-    char txt[STRING_LENGTH];
 
     /*  Set up the dentry operations before anything else, to ensure cleaning
 	up on any error  */
     dentry->d_op = &devfs_dops;
-    memset (txt, 0, STRING_LENGTH);
-    memcpy (txt, dentry->d_name.name,
-	    (dentry->d_name.len >= STRING_LENGTH) ?
-	    (STRING_LENGTH - 1) : dentry->d_name.len);
-    fs_info = dir->i_sb->u.generic_sbp;
     /*  First try to get the devfs entry for this directory  */
-    parent = get_devfs_entry_from_vfs_inode (dir, TRUE);
+    parent = get_devfs_entry_from_vfs_inode (dir);
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_I_LOOKUP)
 	printk ("%s: lookup(%s): dentry: %p parent: %p by: \"%s\"\n",
-		DEVFS_NAME, txt, dentry, parent, current->comm);
+		DEVFS_NAME, dentry->d_name.name, dentry, parent,current->comm);
 #endif
     if (parent == NULL) return ERR_PTR (-ENOENT);
-    /*  Try to reclaim an existing devfs entry  */
-    de = search_for_entry_in_dir (parent,
-				  dentry->d_name.name, dentry->d_name.len,
-				  FALSE);
-    if ( ( (de == NULL) || !de->registered ) &&
-	 (parent->u.dir.num_removable > 0) &&
+    read_lock (&parent->u.dir.lock);
+    de = _devfs_search_dir (parent, dentry->d_name.name, dentry->d_name.len);
+    read_unlock (&parent->u.dir.lock);
+    if ( (de == NULL) && (parent->u.dir.num_removable > 0) &&
 	 get_removable_partition (parent, dentry->d_name.name,
 				  dentry->d_name.len) )
     {
-	if (de == NULL)
-	    de = search_for_entry_in_dir (parent, dentry->d_name.name,
-					  dentry->d_name.len, FALSE);
+	read_lock (&parent->u.dir.lock);
+	de = _devfs_search_dir (parent, dentry->d_name.name,
+				dentry->d_name.len);
+	read_unlock (&parent->u.dir.lock);
     }
-    if ( (de == NULL) || !de->registered )
-    {
-	/*  Try with devfsd. For any kind of failure, leave a negative dentry
+    if (de == NULL)
+    {   /*  Try with devfsd. For any kind of failure, leave a negative dentry
 	    so someone else can deal with it (in the case where the sysadmin
 	    does a mknod()). It's important to do this before hashing the
 	    dentry, so that the devfsd queue is filled before revalidates
 	    can start  */
+	struct devfs_entry tmp;
+
 	if (try_modload (parent, fs_info,
-			 dentry->d_name.name, dentry->d_name.len, txt) < 0)
+			 dentry->d_name.name, dentry->d_name.len, &tmp) < 0)
 	{
 	    d_add (dentry, NULL);
 	    return NULL;
 	}
 	/*  devfsd claimed success  */
 	dentry->d_op = &devfs_wait_dops;
-	dentry->d_fsdata = de;
 	d_add (dentry, NULL);  /*  Open the floodgates  */
 	/*  Unlock directory semaphore, which will release any waiters. They
 	    will get the hashed dentry, and may be forced to wait for
 	    revalidation  */
 	up (&dir->i_sem);
-	devfs_d_revalidate_wait (dentry, 0);  /*  I might have to wait too  */
+	devfs_d_revalidate_wait (dentry, 0);  /*  I might have to wait too   */
 	down (&dir->i_sem);      /*  Grab it again because them's the rules  */
 	/*  If someone else has been so kind as to make the inode, we go home
 	    early  */
 	if (dentry->d_inode) return NULL;
-	if (de && !de->registered) return NULL;
-	if (de == NULL)
-	    de = search_for_entry_in_dir (parent, dentry->d_name.name,
-					  dentry->d_name.len, FALSE);
+	read_lock (&parent->u.dir.lock);
+	de = _devfs_search_dir (parent, dentry->d_name.name,
+				dentry->d_name.len);
+	read_unlock (&parent->u.dir.lock);
 	if (de == NULL) return NULL;
 	/*  OK, there's an entry now, but no VFS inode yet  */
     }
@@ -2771,58 +2880,49 @@
 	d_add (dentry, NULL);  /*  Open the floodgates  */
     }
     /*  Create an inode, now that the driver information is available  */
-    if (de->no_persistence) update_devfs_inode_from_entry (de);
-    else if (de->inode.ctime == 0) update_devfs_inode_from_entry (de);
-    else de->inode.mode =
-	     (de->mode & ~S_IALLUGO) | (de->inode.mode & S_IALLUGO);
-    if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
-	return ERR_PTR (-ENOMEM);
+    inode = get_vfs_inode (dir->i_sb, de, dentry);
+    devfs_put (de);
+    if (!inode) return ERR_PTR (-ENOMEM);
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_I_LOOKUP)
 	printk ("%s: lookup(): new VFS inode(%u): %p  devfs_entry: %p\n",
 		DEVFS_NAME, de->inode.ino, inode, de);
 #endif
     d_instantiate (dentry, inode);
-    /*  Unlock directory semaphore, which will release any waiters. They will
-	get the hashed dentry, and may be forced to wait for revalidation  */
-    up (&dir->i_sem);
     if (dentry->d_op == &devfs_wait_dops)
-	devfs_d_revalidate_wait (dentry, 0);  /*  I might have to wait too  */
-    down (&dir->i_sem);          /*  Grab it again because them's the rules  */
+    {   /*  Unlock directory semaphore, which will release any waiters. They
+	    will get the hashed dentry, and may be forced to wait for
+	    revalidation  */
+	up (&dir->i_sem);
+	devfs_d_revalidate_wait (dentry, 0);  /*  I might have to wait too   */
+	down (&dir->i_sem);      /*  Grab it again because them's the rules  */
+    }
     return NULL;
 }   /*  End Function devfs_lookup  */
 
 static int devfs_unlink (struct inode *dir, struct dentry *dentry)
 {
+    int unhooked;
     struct devfs_entry *de;
     struct inode *inode = dentry->d_inode;
+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
 
 #ifdef CONFIG_DEVFS_DEBUG
-    char txt[STRING_LENGTH];
-
     if (devfs_debug & DEBUG_I_UNLINK)
-    {
-	memset (txt, 0, STRING_LENGTH);
-	memcpy (txt, dentry->d_name.name, dentry->d_name.len);
-	txt[STRING_LENGTH - 1] = '\0';
-	printk ("%s: unlink(%s)\n", DEVFS_NAME, txt);
-    }
+	printk ("%s: unlink(%s)\n", DEVFS_NAME, dentry->d_name.name);
 #endif
-
-    de = get_devfs_entry_from_vfs_inode (dentry->d_inode, TRUE);
+    de = get_devfs_entry_from_vfs_inode (inode);
     if (de == NULL) return -ENOENT;
-    devfsd_notify_one (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
-		       inode->i_uid, inode->i_gid, dir->i_sb->u.generic_sbp);
-    de->registered = FALSE;
-    de->hide = TRUE;
-    if ( S_ISLNK (de->mode) )
-    {
-	down_write (&symlink_rwsem);
-	if (de->u.symlink.linkname) kfree (de->u.symlink.linkname);
-	de->u.symlink.linkname = NULL;
-	up_write (&symlink_rwsem);
-    }
-    free_dentries (de);
+    if (!de->vfs_created) return -EPERM;
+    write_lock (&de->parent->u.dir.lock);
+    unhooked = _devfs_unhook (de);
+    write_unlock (&de->parent->u.dir.lock);
+    if (!unhooked) return -ENOENT;
+    if ( !is_devfsd_or_child (fs_info) )
+	devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
+			  inode->i_uid, inode->i_gid, fs_info);
+    free_dentry (de);
+    devfs_put (de);
     return 0;
 }   /*  End Function devfs_unlink  */
 
@@ -2830,13 +2930,12 @@
 			  const char *symname)
 {
     int err;
-    struct fs_info *fs_info;
+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
     struct devfs_entry *parent, *de;
     struct inode *inode;
 
-    fs_info = dir->i_sb->u.generic_sbp;
     /*  First try to get the devfs entry for this directory  */
-    parent = get_devfs_entry_from_vfs_inode (dir, TRUE);
+    parent = get_devfs_entry_from_vfs_inode (dir);
     if (parent == NULL) return -ENOENT;
     err = devfs_do_symlink (parent, dentry->d_name.name, DEVFS_FL_NONE,
 			    symname, &de, NULL);
@@ -2846,7 +2945,9 @@
 		DEVFS_NAME, err);
 #endif
     if (err < 0) return err;
-    de->inode.mode = de->mode;
+    de->vfs_created = TRUE;
+    de->inode.uid = current->euid;
+    de->inode.gid = current->egid;
     de->inode.atime = CURRENT_TIME;
     de->inode.mtime = CURRENT_TIME;
     de->inode.ctime = CURRENT_TIME;
@@ -2857,50 +2958,33 @@
 	printk ("%s: symlink(): new VFS inode(%u): %p  dentry: %p\n",
 		DEVFS_NAME, de->inode.ino, inode, dentry);
 #endif
-    de->hide = FALSE;
     d_instantiate (dentry, inode);
-    devfsd_notify_one (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
-		       inode->i_uid, inode->i_gid, fs_info);
+    if ( !is_devfsd_or_child (fs_info) )
+	devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
+			  inode->i_uid, inode->i_gid, fs_info);
     return 0;
 }   /*  End Function devfs_symlink  */
 
 static int devfs_mkdir (struct inode *dir, struct dentry *dentry, int mode)
 {
-    int is_new;
-    struct fs_info *fs_info;
+    int err;
+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
     struct devfs_entry *parent, *de;
     struct inode *inode;
 
-    mode = (mode & ~S_IFMT) | S_IFDIR;
-    fs_info = dir->i_sb->u.generic_sbp;
-    /*  First try to get the devfs entry for this directory  */
-    parent = get_devfs_entry_from_vfs_inode (dir, TRUE);
+    mode = (mode & ~S_IFMT) | S_IFDIR;  /*  VFS doesn't pass S_IFMT part  */
+    parent = get_devfs_entry_from_vfs_inode (dir);
     if (parent == NULL) return -ENOENT;
-    /*  Try to reclaim an existing devfs entry, create if there isn't one  */
-    de = search_for_entry (parent, dentry->d_name.name, dentry->d_name.len,
-			   FALSE, TRUE, &is_new, FALSE);
-    if (de == NULL) return -ENOMEM;
-    if (de->registered)
-    {
-	printk ("%s: mkdir(): existing entry\n", DEVFS_NAME);
-	return -EEXIST;
-    }
-    de->hide = FALSE;
-    if (!S_ISDIR (de->mode) && !is_new)
-    {
-	/*  Transmogrifying an old entry  */
-	de->u.dir.first = NULL;
-	de->u.dir.last = NULL;
-    }
-    de->mode = mode;
-    de->u.dir.num_removable = 0;
-    de->inode.mode = mode;
+    de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
+    if (!de) return -ENOMEM;
+    de->vfs_created = TRUE;
+    if ( ( err = _devfs_append_entry (parent, de, FALSE, NULL) ) != 0 )
+	return err;
     de->inode.uid = current->euid;
     de->inode.gid = current->egid;
     de->inode.atime = CURRENT_TIME;
     de->inode.mtime = CURRENT_TIME;
     de->inode.ctime = CURRENT_TIME;
-    de->registered = TRUE;
     if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
 	return -ENOMEM;
 #ifdef CONFIG_DEVFS_DEBUG
@@ -2909,100 +2993,73 @@
 		DEVFS_NAME, de->inode.ino, inode, dentry);
 #endif
     d_instantiate (dentry, inode);
-    devfsd_notify_one (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
-		       inode->i_uid, inode->i_gid, fs_info);
+    if ( !is_devfsd_or_child (fs_info) )
+	devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
+			  inode->i_uid, inode->i_gid, fs_info);
     return 0;
 }   /*  End Function devfs_mkdir  */
 
 static int devfs_rmdir (struct inode *dir, struct dentry *dentry)
 {
-    int has_children = FALSE;
-    struct fs_info *fs_info;
-    struct devfs_entry *de, *child;
+    int err = 0;
+    struct devfs_entry *de;
+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
     struct inode *inode = dentry->d_inode;
 
     if (dir->i_sb->u.generic_sbp != inode->i_sb->u.generic_sbp) return -EINVAL;
-    fs_info = dir->i_sb->u.generic_sbp;
-    de = get_devfs_entry_from_vfs_inode (inode, TRUE);
+    de = get_devfs_entry_from_vfs_inode (inode);
     if (de == NULL) return -ENOENT;
     if ( !S_ISDIR (de->mode) ) return -ENOTDIR;
-    for (child = de->u.dir.first; child != NULL; child = child->next)
-    {
-	if (child->registered)
-	{
-	    has_children = TRUE;
-	    break;
-	}
-    }
-    if (has_children) return -ENOTEMPTY;
-    devfsd_notify_one (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
-		       inode->i_uid, inode->i_gid, fs_info);
-    de->hide = TRUE;
-    de->registered = FALSE;
-    free_dentries (de);
+    if (!de->vfs_created) return -EPERM;
+    /*  First ensure the directory is empty and will stay thay way  */
+    write_lock (&de->u.dir.lock);
+    de->u.dir.no_more_additions = TRUE;
+    if (de->u.dir.first) err = -ENOTEMPTY;
+    write_unlock (&de->u.dir.lock);
+    if (err) return err;
+    /*  Now unhook the directory from it's parent  */
+    write_lock (&de->parent->u.dir.lock);
+    if ( !_devfs_unhook (de) ) err = -ENOENT;
+    write_unlock (&de->parent->u.dir.lock);
+    if (err) return err;
+    if ( !is_devfsd_or_child (fs_info) )
+	devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
+			  inode->i_uid, inode->i_gid, fs_info);
+    free_dentry (de);
+    devfs_put (de);
     return 0;
 }   /*  End Function devfs_rmdir  */
 
 static int devfs_mknod (struct inode *dir, struct dentry *dentry, int mode,
 			int rdev)
 {
-    int is_new;
-    struct fs_info *fs_info;
+    int err;
+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
     struct devfs_entry *parent, *de;
     struct inode *inode;
 
 #ifdef CONFIG_DEVFS_DEBUG
-    char txt[STRING_LENGTH];
-
     if (devfs_debug & DEBUG_I_MKNOD)
-    {
-	memset (txt, 0, STRING_LENGTH);
-	memcpy (txt, dentry->d_name.name, dentry->d_name.len);
-	txt[STRING_LENGTH - 1] = '\0';
 	printk ("%s: mknod(%s): mode: 0%o  dev: %d\n",
-		DEVFS_NAME, txt, mode, rdev);
-    }
+		DEVFS_NAME, dentry->d_name.name, mode, rdev);
 #endif
-
-    fs_info = dir->i_sb->u.generic_sbp;
-    /*  First try to get the devfs entry for this directory  */
-    parent = get_devfs_entry_from_vfs_inode (dir, TRUE);
+    parent = get_devfs_entry_from_vfs_inode (dir);
     if (parent == NULL) return -ENOENT;
-    /*  Try to reclaim an existing devfs entry, create if there isn't one  */
-    de = search_for_entry (parent, dentry->d_name.name, dentry->d_name.len,
-			   FALSE, TRUE, &is_new, FALSE);
-    if (de == NULL) return -ENOMEM;
-    if (de->registered)
-    {
-	printk ("%s: mknod(): existing entry\n", DEVFS_NAME);
-	return -EEXIST;
-    }
-    de->info = NULL;
-    de->mode = mode;
+    de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
+    if (!de) return -ENOMEM;
+    de->vfs_created = TRUE;
     if ( S_ISBLK (mode) || S_ISCHR (mode) )
     {
 	de->u.fcb.u.device.major = MAJOR (rdev);
 	de->u.fcb.u.device.minor = MINOR (rdev);
-	de->u.fcb.default_uid = current->euid;
-	de->u.fcb.default_gid = current->egid;
-	de->u.fcb.ops = NULL;
-	de->u.fcb.auto_owner = FALSE;
-	de->u.fcb.aopen_notify = FALSE;
-	de->u.fcb.open = FALSE;
-    }
-    else if ( S_ISFIFO (mode) )
-    {
-	de->u.fifo.uid = current->euid;
-	de->u.fifo.gid = current->egid;
     }
-    de->hide = FALSE;
-    de->inode.mode = mode;
+    if ( ( err = _devfs_append_entry (parent, de, FALSE, NULL) ) != 0 )
+	return err;
     de->inode.uid = current->euid;
     de->inode.gid = current->egid;
     de->inode.atime = CURRENT_TIME;
     de->inode.mtime = CURRENT_TIME;
     de->inode.ctime = CURRENT_TIME;
-    de->registered = TRUE;
     if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
 	return -ENOMEM;
 #ifdef CONFIG_DEVFS_DEBUG
@@ -3011,8 +3068,9 @@
 		DEVFS_NAME, de->inode.ino, inode, dentry);
 #endif
     d_instantiate (dentry, inode);
-    devfsd_notify_one (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
-		       inode->i_uid, inode->i_gid, fs_info);
+    if ( !is_devfsd_or_child (fs_info) )
+	devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
+			  inode->i_uid, inode->i_gid, fs_info);
     return 0;
 }   /*  End Function devfs_mknod  */
 
@@ -3021,12 +3079,9 @@
     int err;
     struct devfs_entry *de;
 
-    de = get_devfs_entry_from_vfs_inode (dentry->d_inode, TRUE);
+    de = get_devfs_entry_from_vfs_inode (dentry->d_inode);
     if (!de) return -ENODEV;
-    down_read (&symlink_rwsem);
-    err = de->registered ? vfs_readlink (dentry, buffer, buflen,
-					 de->u.symlink.linkname) : -ENODEV;
-    up_read (&symlink_rwsem);
+    err = vfs_readlink (dentry, buffer, buflen, de->u.symlink.linkname);
     return err;
 }   /*  End Function devfs_readlink  */
 
@@ -3034,25 +3089,10 @@
 {
     int err;
     struct devfs_entry *de;
-    char *copy;
 
-    de = get_devfs_entry_from_vfs_inode (dentry->d_inode, TRUE);
+    de = get_devfs_entry_from_vfs_inode (dentry->d_inode);
     if (!de) return -ENODEV;
-    down_read (&symlink_rwsem);
-    if (!de->registered)
-    {
-	up_read (&symlink_rwsem);
-	return -ENODEV;
-    }
-    copy = kmalloc (de->u.symlink.length + 1, GFP_KERNEL);
-    if (copy) memcpy (copy, de->u.symlink.linkname, de->u.symlink.length + 1);
-    up_read (&symlink_rwsem);
-    if (copy)
-    {
-	err = vfs_follow_link (nd, copy);
-	kfree (copy);
-    }
-    else err = -ENOMEM;
+    err = vfs_follow_link (nd, de->u.symlink.linkname);
     return err;
 }   /*  End Function devfs_follow_link  */
 
@@ -3084,7 +3124,7 @@
 {
     struct inode *root_inode = NULL;
 
-    if (get_root_entry () == NULL) goto out_no_root;
+    if (_devfs_get_root_entry () == NULL) goto out_no_root;
     atomic_set (&fs_info.devfsd_overrun_count, 0);
     init_waitqueue_head (&fs_info.devfsd_wait_queue);
     init_waitqueue_head (&fs_info.revalidate_wait_queue);
@@ -3099,7 +3139,7 @@
     sb->s_root = d_alloc_root (root_inode);
     if (!sb->s_root) goto out_no_root;
 #ifdef CONFIG_DEVFS_DEBUG
-    if (devfs_debug & DEBUG_DISABLED)
+    if (devfs_debug & DEBUG_S_READ)
 	printk ("%s: read super, made devfs ptr: %p\n",
 		DEVFS_NAME, sb->u.generic_sbp);
 #endif
@@ -3123,6 +3163,7 @@
     int done = FALSE;
     int ival;
     loff_t pos, devname_offset, tlen, rpos;
+    devfs_handle_t de;
     struct devfsd_buf_entry *entry;
     struct fs_info *fs_info = file->f_dentry->d_inode->i_sb->u.generic_sbp;
     struct devfsd_notify_struct *info = fs_info->devfsd_info;
@@ -3149,40 +3190,28 @@
 	    current->state = TASK_RUNNING;
 	    return -EINTR;
 	}
-	set_current_state(TASK_INTERRUPTIBLE);
+	set_current_state (TASK_INTERRUPTIBLE);
     }
     remove_wait_queue (&fs_info->devfsd_wait_queue, &wait);
     current->state = TASK_RUNNING;
     /*  Now play with the data  */
     ival = atomic_read (&fs_info->devfsd_overrun_count);
-    if (ival > 0) atomic_sub (ival, &fs_info->devfsd_overrun_count);
     info->overrun_count = ival;
-    entry = (struct devfsd_buf_entry *) fs_info->devfsd_buffer +
-	fs_info->devfsd_buf_out;
+    entry = fs_info->devfsd_first_event;
     info->type = entry->type;
     info->mode = entry->mode;
     info->uid = entry->uid;
     info->gid = entry->gid;
-    if (entry->type == DEVFSD_NOTIFY_LOOKUP)
+    de = entry->de;
+    if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) )
     {
-	info->namelen = strlen (entry->data);
-	pos = 0;
-	memcpy (info->devname, entry->data, info->namelen + 1);
-    }
-    else
-    {
-	devfs_handle_t de = entry->data;
-
-	if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
-	{
-	    info->major = de->u.fcb.u.device.major;
-	    info->minor = de->u.fcb.u.device.minor;
-	}
-	pos = devfs_generate_path (de, info->devname, DEVFS_PATHLEN);
-	if (pos < 0) return pos;
-	info->namelen = DEVFS_PATHLEN - pos - 1;
-	if (info->mode == 0) info->mode = de->mode;
+	info->major = de->u.fcb.u.device.major;
+	info->minor = de->u.fcb.u.device.minor;
     }
+    pos = devfs_generate_path (de, info->devname, DEVFS_PATHLEN);
+    if (pos < 0) return pos;
+    info->namelen = DEVFS_PATHLEN - pos - 1;
+    if (info->mode == 0) info->mode = de->mode;
     devname_offset = info->devname - (char *) info;
     rpos = *ppos;
     if (rpos < devname_offset)
@@ -3214,10 +3243,13 @@
     tlen = rpos - *ppos;
     if (done)
     {
-	unsigned int next_pos = fs_info->devfsd_buf_out + 1;
-
-	if (next_pos >= devfsd_buf_size) next_pos = 0;
-	fs_info->devfsd_buf_out = next_pos;
+	spin_lock (&fs_info->devfsd_buffer_lock);
+	fs_info->devfsd_first_event = entry->next;
+	if (entry->next == NULL) fs_info->devfsd_last_event = NULL;
+	spin_unlock (&fs_info->devfsd_buffer_lock);
+	for (; de != NULL; de = de->parent) devfs_put (de);
+	kmem_cache_free (devfsd_buf_cache, entry);
+	if (ival > 0) atomic_sub (ival, &fs_info->devfsd_overrun_count);
 	*ppos = 0;
     }
     else *ppos = rpos;
@@ -3253,15 +3285,13 @@
 	    fs_info->devfsd_task = current;
 	    spin_unlock (&lock);
 	    fs_info->devfsd_file = file;
-	    fs_info->devfsd_buffer = (void *) __get_free_page (GFP_KERNEL);
 	    fs_info->devfsd_info = kmalloc (sizeof *fs_info->devfsd_info,
 					    GFP_KERNEL);
-	    if (!fs_info->devfsd_buffer || !fs_info->devfsd_info)
+	    if (!fs_info->devfsd_info)
 	    {
 		devfsd_close (inode, file);
 		return -ENOMEM;
 	    }
-	    fs_info->devfsd_buf_out = fs_info->devfsd_buf_in;
 	}
 	else if (fs_info->devfsd_task != current) return -EBUSY;
 	fs_info->devfsd_event_mask = arg;  /*  Let the masses come forth  */
@@ -3284,29 +3314,48 @@
 
 static int devfsd_close (struct inode *inode, struct file *file)
 {
-    unsigned long flags;
+    struct devfsd_buf_entry *entry;
     struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
 
     if (fs_info->devfsd_file != file) return 0;
     fs_info->devfsd_event_mask = 0;
     fs_info->devfsd_file = NULL;
-    spin_lock_irqsave (&fs_info->devfsd_buffer_lock, flags);
-    if (fs_info->devfsd_buffer)
-    {
-	free_page ( (unsigned long) fs_info->devfsd_buffer );
-	fs_info->devfsd_buffer = NULL;
-    }
+    spin_lock (&fs_info->devfsd_buffer_lock);
+    entry = fs_info->devfsd_first_event;
+    fs_info->devfsd_first_event = NULL;
+    fs_info->devfsd_last_event = NULL;
     if (fs_info->devfsd_info)
     {
 	kfree (fs_info->devfsd_info);
 	fs_info->devfsd_info = NULL;
     }
-    spin_unlock_irqrestore (&fs_info->devfsd_buffer_lock, flags);
+    spin_unlock (&fs_info->devfsd_buffer_lock);
     fs_info->devfsd_task = NULL;
     wake_up (&fs_info->revalidate_wait_queue);
+    for (; entry; entry = entry->next)
+	kmem_cache_free (devfsd_buf_cache, entry);
     return 0;
 }   /*  End Function devfsd_close  */
 
+#ifdef CONFIG_DEVFS_DEBUG
+static ssize_t stat_read (struct file *file, char *buf, size_t len,
+			  loff_t *ppos)
+{
+    ssize_t num;
+    char txt[80];
+
+    num = sprintf (txt, "Number of entries: %u  number of bytes: %u\n",
+		   stat_num_entries, stat_num_bytes) + 1;
+    /*  Can't seek (pread) on this device  */
+    if (ppos != &file->f_pos) return -ESPIPE;
+    if (*ppos >= num) return 0;
+    if (*ppos + len > num) len = num - *ppos;
+    if ( copy_to_user (buf, txt + *ppos, len) ) return -EFAULT;
+    *ppos += len;
+    return len;
+}   /*  End Function stat_read  */
+#endif
+
 
 static int __init init_devfs_fs (void)
 {
@@ -3333,6 +3382,9 @@
 {
     int err;
 
+    devfsd_buf_cache = kmem_cache_create ("devfsd_event",
+					  sizeof (struct devfsd_buf_entry),
+					  0, 0, NULL, NULL);
     if ( !(boot_options & OPTION_MOUNT) ) return;
     err = do_mount ("none", "/dev", "devfs", 0, "");
     if (err == 0) printk ("Mounted devfs on /dev\n");
diff -Nur --exclude=*~ linux-2.4.16/fs/exec.c linux/fs/exec.c
--- linux-2.4.16/fs/exec.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/exec.c	Fri Nov 30 13:29:24 2001
@@ -586,7 +586,7 @@
 flush_failed:
 	spin_lock_irq(&current->sigmask_lock);
 	if (current->sig != oldsig) {
-		kfree(current->sig);
+		kmem_cache_free(sigact_cachep, current->sig);
 		current->sig = oldsig;
 	}
 	spin_unlock_irq(&current->sigmask_lock);
diff -Nur --exclude=*~ linux-2.4.16/fs/ext2/super.c linux/fs/ext2/super.c
--- linux-2.4.16/fs/ext2/super.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/ext2/super.c	Fri Nov 30 18:34:11 2001
@@ -28,6 +28,8 @@
 #include <asm/uaccess.h>
 
 
+static void ext2_sync_super(struct super_block *sb,
+			    struct ext2_super_block *es);
 
 static char error_buf[1024];
 
@@ -35,13 +37,13 @@
 		 const char * fmt, ...)
 {
 	va_list args;
+	struct ext2_super_block *es = EXT2_SB(sb)->s_es;
 
 	if (!(sb->s_flags & MS_RDONLY)) {
 		sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS;
-		sb->u.ext2_sb.s_es->s_state =
-			cpu_to_le16(le16_to_cpu(sb->u.ext2_sb.s_es->s_state) | EXT2_ERROR_FS);
-		mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
-		sb->s_dirt = 1;
+		es->s_state =
+			cpu_to_le16(le16_to_cpu(es->s_state) | EXT2_ERROR_FS);
+		ext2_sync_super(sb, es);
 	}
 	va_start (args, fmt);
 	vsprintf (error_buf, fmt, args);
@@ -124,8 +126,10 @@
 	int i;
 
 	if (!(sb->s_flags & MS_RDONLY)) {
-		sb->u.ext2_sb.s_es->s_state = le16_to_cpu(sb->u.ext2_sb.s_mount_state);
-		mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
+		struct ext2_super_block *es = EXT2_SB(sb)->s_es;
+
+		es->s_state = le16_to_cpu(EXT2_SB(sb)->s_mount_state);
+		ext2_sync_super(sb, es);
 	}
 	db_count = EXT2_SB(sb)->s_gdb_count;
 	for (i = 0; i < db_count; i++)
@@ -305,13 +309,10 @@
 		(le32_to_cpu(es->s_lastcheck) + le32_to_cpu(es->s_checkinterval) <= CURRENT_TIME))
 		printk ("EXT2-fs warning: checktime reached, "
 			"running e2fsck is recommended\n");
-	es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT2_VALID_FS);
 	if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
 		es->s_max_mnt_count = (__s16) cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT);
 	es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1);
-	es->s_mtime = cpu_to_le32(CURRENT_TIME);
-	mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
-	sb->s_dirt = 1;
+	ext2_write_super(sb);
 	if (test_opt (sb, DEBUG))
 		printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, "
 			"bpg=%lu, ipg=%lu, mo=%04lx]\n",
@@ -664,6 +665,15 @@
 	sb->s_dirt = 0;
 }
 
+static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es)
+{
+	es->s_wtime = cpu_to_le32(CURRENT_TIME);
+	mark_buffer_dirty(EXT2_SB(sb)->s_sbh);
+	ll_rw_block(WRITE, 1, &EXT2_SB(sb)->s_sbh);
+	wait_on_buffer(EXT2_SB(sb)->s_sbh);
+	sb->s_dirt = 0;
+}
+
 /*
  * In the second extended file system, it is not necessary to
  * write the super block since we use a mapping of the
@@ -682,13 +692,14 @@
 	if (!(sb->s_flags & MS_RDONLY)) {
 		es = sb->u.ext2_sb.s_es;
 
-		ext2_debug ("setting valid to 0\n");
-
 		if (le16_to_cpu(es->s_state) & EXT2_VALID_FS) {
-			es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT2_VALID_FS);
+			ext2_debug ("setting valid to 0\n");
+			es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) &
+						  ~EXT2_VALID_FS);
 			es->s_mtime = cpu_to_le32(CURRENT_TIME);
-		}
-		ext2_commit_super (sb, es);
+			ext2_sync_super(sb, es);
+		} else
+			ext2_commit_super (sb, es);
 	}
 	sb->s_dirt = 0;
 }
@@ -725,11 +736,7 @@
 		 */
 		es->s_state = cpu_to_le16(sb->u.ext2_sb.s_mount_state);
 		es->s_mtime = cpu_to_le32(CURRENT_TIME);
-		mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
-		sb->s_dirt = 1;
-		ext2_commit_super (sb, es);
-	}
-	else {
+	} else {
 		int ret;
 		if ((ret = EXT2_HAS_RO_COMPAT_FEATURE(sb,
 					       ~EXT2_FEATURE_RO_COMPAT_SUPP))) {
@@ -747,6 +754,7 @@
 		if (!ext2_setup_super (sb, es, 0))
 			sb->s_flags &= ~MS_RDONLY;
 	}
+	ext2_sync_super(sb, es);
 	return 0;
 }
 
diff -Nur --exclude=*~ linux-2.4.16/fs/inflate_fs/inflate_syms.c linux/fs/inflate_fs/inflate_syms.c
--- linux-2.4.16/fs/inflate_fs/inflate_syms.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/inflate_fs/inflate_syms.c	Wed Nov 28 18:15:57 2001
@@ -19,3 +19,4 @@
 EXPORT_SYMBOL(zlib_fs_inflateReset);
 EXPORT_SYMBOL(zlib_fs_adler32);
 EXPORT_SYMBOL(zlib_fs_inflateSyncPoint);
+MODULE_LICENSE("GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/inode.c linux/fs/inode.c
--- linux-2.4.16/fs/inode.c	Mon Nov 26 08:35:11 2001
+++ linux/fs/inode.c	Fri Nov 30 15:44:38 2001
@@ -1072,7 +1072,7 @@
 				}
 				inodes_stat.nr_unused++;
 				spin_unlock(&inode_lock);
-				if (!sb || sb->s_flags & MS_ACTIVE)
+				if (!sb || (sb->s_flags & MS_ACTIVE))
 					return;
 				write_inode_now(inode, 1);
 				spin_lock(&inode_lock);
@@ -1187,6 +1187,8 @@
  
 void update_atime (struct inode *inode)
 {
+	if (inode->i_atime == CURRENT_TIME)
+		return;
 	if ( IS_NOATIME (inode) ) return;
 	if ( IS_NODIRATIME (inode) && S_ISDIR (inode->i_mode) ) return;
 	if ( IS_RDONLY (inode) ) return;
diff -Nur --exclude=*~ linux-2.4.16/fs/intermezzo/file.c linux/fs/intermezzo/file.c
--- linux-2.4.16/fs/intermezzo/file.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/intermezzo/file.c	Fri Nov 30 12:39:48 2001
@@ -344,7 +344,7 @@
                 << file->f_dentry->d_inode->i_sb->s_blocksize_bits);
 
         error = presto_reserve_space(fset->fset_cache, res_size); 
-        CDEBUG(D_INODE, "Reserved %Ld for %d\n", res_size, size); 
+        CDEBUG(D_INODE, "Reserved %Ld for %Zd\n", res_size, size); 
         if ( error ) { 
                 EXIT;
                 return -ENOSPC;
@@ -397,7 +397,7 @@
         fops = filter_c2cffops(cache->cache_filter);
         res = fops->write(file, buf, size, off);
         if ( res != size ) {
-                CDEBUG(D_FILE, "file write returns short write: size %d, res %d\n", size, res); 
+                CDEBUG(D_FILE, "file write returns short write: size %Zd, res %Zd\n", size, res); 
         }
 
         if ( (res > 0) && fdata ) 
diff -Nur --exclude=*~ linux-2.4.16/fs/intermezzo/journal.c linux/fs/intermezzo/journal.c
--- linux-2.4.16/fs/intermezzo/journal.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/intermezzo/journal.c	Fri Nov 30 12:39:48 2001
@@ -1077,7 +1077,7 @@
                 return 0;
         }
 
-        CDEBUG(D_JOURNAL, "reading prefix: off %ld, size %d\n", 
+        CDEBUG(D_JOURNAL, "reading prefix: off %ld, size %Zd\n", 
                (long)lml_offset, sizeof(record));
         rc = presto_fread(fset->fset_lml.fd_file, (char *)&record,
                           sizeof(record), &offset);
diff -Nur --exclude=*~ linux-2.4.16/fs/intermezzo/psdev.c linux/fs/intermezzo/psdev.c
--- linux-2.4.16/fs/intermezzo/psdev.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/intermezzo/psdev.c	Fri Nov 30 12:39:48 2001
@@ -176,7 +176,7 @@
 
         /* move data into response buffer. */
         if (req->rq_bufsize < count) {
-                printk("psdev_write: too much cnt: %d, cnt: %d, "
+                printk("psdev_write: too much cnt: %d, cnt: %Zd, "
                        "opc: %d, uniq: %d.\n",
                        req->rq_bufsize, count, hdr.opcode, hdr.unique);
                 count = req->rq_bufsize; /* don't have more space! */
@@ -209,7 +209,7 @@
                        __FUNCTION__, kdevname(dev));
         }
 
-        CDEBUG(D_PSDEV, "count %d\n", count);
+        CDEBUG(D_PSDEV, "count %Zd\n", count);
         if (list_empty(&(upccom->uc_pending))) {
                 CDEBUG(D_UPCALL, "Empty pending list in read, not good\n");
                 return -EINVAL;
@@ -228,7 +228,7 @@
         }
 
         if (count < req->rq_bufsize) {
-                printk ("psdev_read: buffer too small, read %d of %d bytes\n",
+                printk ("psdev_read: buffer too small, read %Zd of %d bytes\n",
                         count, req->rq_bufsize);
         }
 
@@ -281,7 +281,7 @@
                 error = copy_from_user(&readmount, (void *)arg,
                                        sizeof(readmount));
                 if ( error )  {
-                        printk("psdev: can't copy %d bytes from %p to %p\n",
+                        printk("psdev: can't copy %Zd bytes from %p to %p\n",
                                 sizeof(readmount), (struct readmount *) arg,
                                 &readmount);
                         EXIT;
@@ -469,7 +469,7 @@
                 input.size = size;
                 upccom->uc_pid = saved_pid;
 
-                CDEBUG(D_PSDEV, "get_kmlsize: size = %d\n", size);
+                CDEBUG(D_PSDEV, "get_kmlsize: size = %Zd\n", size);
 
                 EXIT;
                 return copy_to_user((char *)arg, &input, sizeof(input));
@@ -621,7 +621,7 @@
 
                 error = copy_from_user(&kopt, (void *)arg, sizeof(kopt));
                 if ( error )  {
-                        printk("psdev: can't copyin %d bytes from %p to %p\n",
+                        printk("psdev: can't copyin %Zd bytes from %p to %p\n",
                                sizeof(kopt), (struct kopt *) arg, &kopt);
                         EXIT;
                         return error;
@@ -1244,7 +1244,7 @@
         
         default:
                 CDEBUG(D_PSDEV, "bad ioctl 0x%x, \n", cmd);
-                CDEBUG(D_PSDEV, "valid are 0x%x - 0x%x, 0x%x - 0x%x \n",
+                CDEBUG(D_PSDEV, "valid are 0x%Zx - 0x%Zx, 0x%Zx - 0x%Zx \n",
                         PRESTO_GETMOUNT, PRESTO_GET_KMLSIZE,
                         PRESTO_VFS_SETATTR, PRESTO_VFS_IOPEN);
                 EXIT;
@@ -1571,8 +1571,8 @@
                req->rq_opcode, jiffies - req->rq_posttime,
                req->rq_unique, req->rq_rep_size);
         CDEBUG(D_UPCALL,
-               "..process %d woken up by Lento for req at 0x%x, data at %x\n",
-               current->pid, (int)req, (int)req->rq_data);
+               "..process %d woken up by Lento for req at 0x%p, data at %p\n",
+               current->pid, req, req->rq_data);
 
         if (upc_commp->uc_pid) {      /* i.e. Lento is still alive */
           /* Op went through, interrupt or not we go on */
diff -Nur --exclude=*~ linux-2.4.16/fs/msdos/msdosfs_syms.c linux/fs/msdos/msdosfs_syms.c
--- linux-2.4.16/fs/msdos/msdosfs_syms.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/msdos/msdosfs_syms.c	Wed Nov 28 18:15:57 2001
@@ -40,3 +40,4 @@
 
 module_init(init_msdos_fs)
 module_exit(exit_msdos_fs)
+MODULE_LICENSE("GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/namespace.c linux/fs/namespace.c
--- linux-2.4.16/fs/namespace.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/namespace.c	Wed Nov 28 18:15:57 2001
@@ -19,9 +19,6 @@
 
 #include <asm/uaccess.h>
 
-#include <linux/nfs_fs.h>
-#include <linux/nfs_fs_sb.h>
-#include <linux/nfs_mount.h>
 #include <linux/seq_file.h>
 
 struct vfsmount *do_kern_mount(char *type, int flags, char *name, void *data);
@@ -198,50 +195,10 @@
 	seq_escape(m, s, " \t\n\\");
 }
 
-static void show_nfs_mount(struct seq_file *m, struct vfsmount *mnt)
-{
-	static struct proc_nfs_info {
-		int flag;
-		char *str;
-		char *nostr;
-	} nfs_info[] = {
-		{ NFS_MOUNT_SOFT, ",soft", ",hard" },
-		{ NFS_MOUNT_INTR, ",intr", "" },
-		{ NFS_MOUNT_POSIX, ",posix", "" },
-		{ NFS_MOUNT_TCP, ",tcp", ",udp" },
-		{ NFS_MOUNT_NOCTO, ",nocto", "" },
-		{ NFS_MOUNT_NOAC, ",noac", "" },
-		{ NFS_MOUNT_NONLM, ",nolock", ",lock" },
-		{ NFS_MOUNT_BROKEN_SUID, ",broken_suid", "" },
-		{ 0, NULL, NULL }
-	};
-	struct proc_nfs_info *nfs_infop;
-	struct nfs_server *nfss = &mnt->mnt_sb->u.nfs_sb.s_server;
-
-	seq_printf(m, ",v%d", nfss->rpc_ops->version);
-	seq_printf(m, ",rsize=%d", nfss->rsize);
-	seq_printf(m, ",wsize=%d", nfss->wsize);
-	if (nfss->acregmin != 3*HZ)
-		seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ);
-	if (nfss->acregmax != 60*HZ)
-		seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ);
-	if (nfss->acdirmin != 30*HZ)
-		seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ);
-	if (nfss->acdirmax != 60*HZ)
-		seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ);
-	for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
-		if (nfss->flags & nfs_infop->flag)
-			seq_puts(m, nfs_infop->str);
-		else
-			seq_puts(m, nfs_infop->nostr);
-	}
-	seq_puts(m, ",addr=");
-	mangle(m, nfss->hostname);
-}
-
 static int show_vfsmnt(struct seq_file *m, void *v)
 {
 	struct vfsmount *mnt = v;
+	int err = 0;
 	static struct proc_fs_info {
 		int flag;
 		char *str;
@@ -281,10 +238,10 @@
 		if (mnt->mnt_flags & fs_infop->flag)
 			seq_puts(m, fs_infop->str);
 	}
-	if (strcmp("nfs", mnt->mnt_sb->s_type->name) == 0)
-		show_nfs_mount(m, mnt);
+	if (mnt->mnt_sb->s_op->show_options)
+		err = mnt->mnt_sb->s_op->show_options(m, mnt);
 	seq_puts(m, " 0 0\n");
-	return 0;
+	return err;
 }
 
 struct seq_operations mounts_op = {
diff -Nur --exclude=*~ linux-2.4.16/fs/ncpfs/ncplib_kernel.c linux/fs/ncpfs/ncplib_kernel.c
--- linux-2.4.16/fs/ncpfs/ncplib_kernel.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/ncpfs/ncplib_kernel.c	Fri Nov 30 12:43:11 2001
@@ -52,14 +52,6 @@
 	return;
 }
 
-static void ncp_add_mem_fromfs(struct ncp_server *server, const char *source, int size)
-{
-	assert_server_locked(server);
-	copy_from_user(&(server->packet[server->current_size]), source, size);
-	server->current_size += size;
-	return;
-}
-
 static void ncp_add_pstring(struct ncp_server *server, const char *s)
 {
 	int len = strlen(s);
diff -Nur --exclude=*~ linux-2.4.16/fs/nfs/inode.c linux/fs/nfs/inode.c
--- linux-2.4.16/fs/nfs/inode.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nfs/inode.c	Wed Nov 28 18:15:57 2001
@@ -32,6 +32,7 @@
 #include <linux/nfs_flushd.h>
 #include <linux/lockd/bind.h>
 #include <linux/smp_lock.h>
+#include <linux/seq_file.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -51,6 +52,7 @@
 static void nfs_clear_inode(struct inode *);
 static void nfs_umount_begin(struct super_block *);
 static int  nfs_statfs(struct super_block *, struct statfs *);
+static int  nfs_show_options(struct seq_file *, struct vfsmount *);
 
 static struct super_operations nfs_sops = { 
 	read_inode:	nfs_read_inode,
@@ -60,6 +62,7 @@
 	statfs:		nfs_statfs,
 	clear_inode:	nfs_clear_inode,
 	umount_begin:	nfs_umount_begin,
+	show_options:	nfs_show_options,
 };
 
 /*
@@ -551,6 +554,48 @@
  out_err:
 	printk("nfs_statfs: statfs error = %d\n", -error);
 	buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1;
+	return 0;
+}
+
+static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
+{
+	static struct proc_nfs_info {
+		int flag;
+		char *str;
+		char *nostr;
+	} nfs_info[] = {
+		{ NFS_MOUNT_SOFT, ",soft", ",hard" },
+		{ NFS_MOUNT_INTR, ",intr", "" },
+		{ NFS_MOUNT_POSIX, ",posix", "" },
+		{ NFS_MOUNT_TCP, ",tcp", ",udp" },
+		{ NFS_MOUNT_NOCTO, ",nocto", "" },
+		{ NFS_MOUNT_NOAC, ",noac", "" },
+		{ NFS_MOUNT_NONLM, ",nolock", ",lock" },
+		{ NFS_MOUNT_BROKEN_SUID, ",broken_suid", "" },
+		{ 0, NULL, NULL }
+	};
+	struct proc_nfs_info *nfs_infop;
+	struct nfs_server *nfss = &mnt->mnt_sb->u.nfs_sb.s_server;
+
+	seq_printf(m, ",v%d", nfss->rpc_ops->version);
+	seq_printf(m, ",rsize=%d", nfss->rsize);
+	seq_printf(m, ",wsize=%d", nfss->wsize);
+	if (nfss->acregmin != 3*HZ)
+		seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ);
+	if (nfss->acregmax != 60*HZ)
+		seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ);
+	if (nfss->acdirmin != 30*HZ)
+		seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ);
+	if (nfss->acdirmax != 60*HZ)
+		seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ);
+	for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
+		if (nfss->flags & nfs_infop->flag)
+			seq_puts(m, nfs_infop->str);
+		else
+			seq_puts(m, nfs_infop->nostr);
+	}
+	seq_puts(m, ",addr=");
+	seq_escape(m, nfss->hostname, " \t\n\\");
 	return 0;
 }
 
diff -Nur --exclude=*~ linux-2.4.16/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- linux-2.4.16/fs/nfsd/vfs.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nfsd/vfs.c	Wed Nov 28 18:15:57 2001
@@ -560,9 +560,13 @@
 		return NULL;
 	rap = frap;
 	ra = *frap;
-	memset(ra, 0, sizeof(*ra));
 	ra->p_dev = dev;
 	ra->p_ino = ino;
+	ra->p_reada = 0;
+	ra->p_ramax = 0;
+	ra->p_raend = 0;
+	ra->p_ralen = 0;
+	ra->p_rawin = 0;
 found:
 	if (rap != &raparm_cache) {
 		*rap = ra->p_next;
diff -Nur --exclude=*~ linux-2.4.16/fs/nls/nls_cp1251.c linux/fs/nls/nls_cp1251.c
--- linux-2.4.16/fs/nls/nls_cp1251.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nls/nls_cp1251.c	Fri Nov 30 13:46:40 2001
@@ -315,4 +315,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/nls/nls_cp1255.c linux/fs/nls/nls_cp1255.c
--- linux-2.4.16/fs/nls/nls_cp1255.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nls/nls_cp1255.c	Fri Nov 30 13:46:40 2001
@@ -396,4 +396,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/nls/nls_cp437.c linux/fs/nls/nls_cp437.c
--- linux-2.4.16/fs/nls/nls_cp437.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nls/nls_cp437.c	Fri Nov 30 13:46:40 2001
@@ -401,4 +401,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/nls/nls_cp737.c linux/fs/nls/nls_cp737.c
--- linux-2.4.16/fs/nls/nls_cp737.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nls/nls_cp737.c	Fri Nov 30 13:46:40 2001
@@ -364,4 +364,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/nls/nls_cp775.c linux/fs/nls/nls_cp775.c
--- linux-2.4.16/fs/nls/nls_cp775.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nls/nls_cp775.c	Fri Nov 30 13:46:40 2001
@@ -333,4 +333,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/nls/nls_cp850.c linux/fs/nls/nls_cp850.c
--- linux-2.4.16/fs/nls/nls_cp850.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nls/nls_cp850.c	Fri Nov 30 13:46:40 2001
@@ -329,4 +329,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/nls/nls_cp852.c linux/fs/nls/nls_cp852.c
--- linux-2.4.16/fs/nls/nls_cp852.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nls/nls_cp852.c	Fri Nov 30 13:46:40 2001
@@ -351,4 +351,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/nls/nls_cp855.c linux/fs/nls/nls_cp855.c
--- linux-2.4.16/fs/nls/nls_cp855.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nls/nls_cp855.c	Fri Nov 30 13:46:40 2001
@@ -313,4 +313,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/nls/nls_cp857.c linux/fs/nls/nls_cp857.c
--- linux-2.4.16/fs/nls/nls_cp857.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nls/nls_cp857.c	Fri Nov 30 13:46:40 2001
@@ -315,4 +315,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/nls/nls_cp860.c linux/fs/nls/nls_cp860.c
--- linux-2.4.16/fs/nls/nls_cp860.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nls/nls_cp860.c	Fri Nov 30 13:46:40 2001
@@ -378,4 +378,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/nls/nls_cp861.c linux/fs/nls/nls_cp861.c
--- linux-2.4.16/fs/nls/nls_cp861.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nls/nls_cp861.c	Fri Nov 30 13:46:40 2001
@@ -401,4 +401,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/nls/nls_cp862.c linux/fs/nls/nls_cp862.c
--- linux-2.4.16/fs/nls/nls_cp862.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nls/nls_cp862.c	Fri Nov 30 13:46:40 2001
@@ -435,4 +435,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/nls/nls_cp863.c linux/fs/nls/nls_cp863.c
--- linux-2.4.16/fs/nls/nls_cp863.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nls/nls_cp863.c	Fri Nov 30 13:46:40 2001
@@ -395,4 +395,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/nls/nls_cp864.c linux/fs/nls/nls_cp864.c
--- linux-2.4.16/fs/nls/nls_cp864.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nls/nls_cp864.c	Fri Nov 30 13:46:40 2001
@@ -421,4 +421,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/nls/nls_cp865.c linux/fs/nls/nls_cp865.c
--- linux-2.4.16/fs/nls/nls_cp865.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nls/nls_cp865.c	Fri Nov 30 13:46:40 2001
@@ -401,4 +401,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/nls/nls_cp866.c linux/fs/nls/nls_cp866.c
--- linux-2.4.16/fs/nls/nls_cp866.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nls/nls_cp866.c	Fri Nov 30 13:46:40 2001
@@ -319,4 +319,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/nls/nls_cp869.c linux/fs/nls/nls_cp869.c
--- linux-2.4.16/fs/nls/nls_cp869.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nls/nls_cp869.c	Fri Nov 30 13:46:40 2001
@@ -329,4 +329,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/nls/nls_cp874.c linux/fs/nls/nls_cp874.c
--- linux-2.4.16/fs/nls/nls_cp874.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/nls/nls_cp874.c	Fri Nov 30 13:46:40 2001
@@ -287,4 +287,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Nur --exclude=*~ linux-2.4.16/fs/openpromfs/inode.c linux/fs/openpromfs/inode.c
--- linux-2.4.16/fs/openpromfs/inode.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/openpromfs/inode.c	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: inode.c,v 1.14 2001/02/13 01:17:17 davem Exp $
+/* $Id: inode.c,v 1.15 2001/11/12 09:43:39 davem Exp $
  * openpromfs.c: /proc/openprom handling routines
  *
  * Copyright (C) 1996-1999 Jakub Jelinek  (jakub@redhat.com)
diff -Nur --exclude=*~ linux-2.4.16/fs/reiserfs/bitmap.c linux/fs/reiserfs/bitmap.c
--- linux-2.4.16/fs/reiserfs/bitmap.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/reiserfs/bitmap.c	Fri Nov 30 14:55:16 2001
@@ -103,6 +103,13 @@
 
   get_bit_address (s, block, &nr, &offset);
 
+  if (nr >= sb_bmap_nr (rs)) {
+	  reiserfs_warning ("vs-4075: reiserfs_free_block: "
+			    "block %lu is out of range on %s\n", 
+			    block, bdevname(s->s_dev));
+	  return;
+  }
+
   /* mark it before we clear it, just in case */
   journal_mark_freed(th, s, block) ;
 
diff -Nur --exclude=*~ linux-2.4.16/fs/reiserfs/inode.c linux/fs/reiserfs/inode.c
--- linux-2.4.16/fs/reiserfs/inode.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/reiserfs/inode.c	Fri Nov 30 14:55:15 2001
@@ -1138,6 +1138,30 @@
     }
 
     init_inode (inode, &path_to_sd);
+   
+    /* It is possible that knfsd is trying to access inode of a file
+       that is being removed from the disk by some other thread. As we
+       update sd on unlink all that is required is to check for nlink
+       here. This bug was first found by Sizif when debugging
+       SquidNG/Butterfly, forgotten, and found again after Philippe
+       Gramoulle <philippe.gramoulle@mmania.com> reproduced it. 
+
+       More logical fix would require changes in fs/inode.c:iput() to
+       remove inode from hash-table _after_ fs cleaned disk stuff up and
+       in iget() to return NULL if I_FREEING inode is found in
+       hash-table. */
+    /* Currently there is one place where it's ok to meet inode with
+       nlink==0: processing of open-unlinked and half-truncated files
+       during mount (fs/reiserfs/super.c:finish_unfinished()). */
+    if( ( inode -> i_nlink == 0 ) && 
+	! inode -> i_sb -> u.reiserfs_sb.s_is_unlinked_ok ) {
+	    reiserfs_warning( "vs-13075: reiserfs_read_inode2: "
+			      "dead inode read from disk %K. "
+			      "This is likely to be race with knfsd. Ignore\n", 
+			      &key );
+	    make_bad_inode( inode );
+    }
+
     reiserfs_check_path(&path_to_sd) ; /* init inode should be relsing */
 
 }
diff -Nur --exclude=*~ linux-2.4.16/fs/reiserfs/journal.c linux/fs/reiserfs/journal.c
--- linux-2.4.16/fs/reiserfs/journal.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/reiserfs/journal.c	Fri Nov 30 14:55:14 2001
@@ -147,7 +147,7 @@
   }
   bn = allocate_bitmap_node(p_s_sb) ;
   if (!bn) {
-    current->policy = SCHED_YIELD ;
+    current->policy |= SCHED_YIELD ;
     schedule() ;
     goto repeat ;
   }
diff -Nur --exclude=*~ linux-2.4.16/fs/reiserfs/stree.c linux/fs/reiserfs/stree.c
--- linux-2.4.16/fs/reiserfs/stree.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/reiserfs/stree.c	Fri Nov 30 14:55:17 2001
@@ -992,10 +992,6 @@
     struct item_head    * p_le_ih = PATH_PITEM_HEAD(p_s_path);
     struct buffer_head  * p_s_bh = PATH_PLAST_BUFFER(p_s_path);
 
-#ifdef CONFIG_REISERFS_CHECK
-    int n_repeat_counter = 0;
-#endif
-
     /* Stat_data item. */
     if ( is_statdata_le_ih (p_le_ih) ) {
 
@@ -1020,13 +1016,11 @@
     {
 	int                   n_unfm_number,    /* Number of the item unformatted nodes. */
 	    n_counter,
-	    n_retry,        /* Set to one if there is unformatted node buffer in use. */
 	    n_blk_size;
 	__u32               * p_n_unfm_pointer; /* Pointer to the unformatted node number. */
 	__u32 tmp;
 	struct item_head      s_ih;           /* Item header. */
 	char                  c_mode;           /* Returned mode of the balance. */
-	struct buffer_head  * p_s_un_bh;
 	int need_research;
 
 
@@ -1099,8 +1093,8 @@
 	    // note: path could be changed, first line in for loop takes care
 	    // of it
 
-	    for ( n_retry = 0, n_counter = *p_n_removed;
-		  n_counter < n_unfm_number; n_counter++, p_n_unfm_pointer-- )  {
+	    for (n_counter = *p_n_removed;
+		 n_counter < n_unfm_number; n_counter++, p_n_unfm_pointer-- ) {
 
 		if (item_moved (&s_ih, p_s_path)) {
 		    need_research = 1 ;
@@ -1110,69 +1104,23 @@
 			p_n_unfm_pointer > (__u32 *)B_I_PITEM(p_s_bh, &s_ih) + I_UNFM_NUM(&s_ih) - 1,
 			"vs-5265: pointer out of range");
 
-		if ( ! get_block_num(p_n_unfm_pointer,0) )  { /* Hole, nothing to remove. */
-		    if ( ! n_retry )
+		/* Hole, nothing to remove. */
+		if ( ! get_block_num(p_n_unfm_pointer,0) )  { 
 			(*p_n_removed)++;
-		    continue;
+			continue;
 		}
-		/* Search for the buffer in cache. */
-		p_s_un_bh = get_hash_table(p_s_sb->s_dev, get_block_num(p_n_unfm_pointer,0), n_blk_size);
 
-		if (p_s_un_bh) {
-		    mark_buffer_clean(p_s_un_bh) ;
-		    if (buffer_locked(p_s_un_bh)) {
-		  __wait_on_buffer(p_s_un_bh) ;
-		    }
-		    /* even if the item moves, the block number of the
-		    ** unformatted node we want to cut won't.  So, it was
-		    ** safe to clean the buffer here, this block _will_
-		    ** get freed during this call to prepare_for_delete_or_cut
-		    */
-		  if ( item_moved (&s_ih, p_s_path) )  {
-		      need_research = 1;
-		      brelse(p_s_un_bh) ;
-		      break ;
-		  }
-		}
-		if ( p_s_un_bh && block_in_use (p_s_un_bh)) {
-		    /* Block is locked or held more than by one holder and by
-                       journal. */
-
-#ifdef CONFIG_REISERFS_CHECK
-		    if (n_repeat_counter && (n_repeat_counter % 100000) == 0) {
-		      printk("prepare_for_delete, waiting on buffer %lu, b_count %d, %s%cJDIRTY %cJDIRTY_WAIT\n", 
-			     p_s_un_bh->b_blocknr, atomic_read (&p_s_un_bh->b_count),
-			     buffer_locked (p_s_un_bh) ? "locked, " : "",
-			     buffer_journaled(p_s_un_bh) ? ' ' : '!', 
-			     buffer_journal_dirty(p_s_un_bh) ? ' ' : '!') ;
-
-		    }
-#endif
-		    n_retry = 1;
-		    brelse (p_s_un_bh);
-		    continue;
-		}
-      
-		if ( ! n_retry )
-		    (*p_n_removed)++;
-      
-		RFALSE( p_s_un_bh &&
-                     get_block_num(p_n_unfm_pointer, 0) != p_s_un_bh->b_blocknr,
-		    // note: minix_truncate allows that. As truncate is
-		    // protected by down (inode->i_sem), two truncates can not
-		    // co-exist
-		    "PAP-5280: blocks numbers are different");	
+		(*p_n_removed)++;
 
 		tmp = get_block_num(p_n_unfm_pointer,0);
 		put_block_num(p_n_unfm_pointer, 0, 0);
 		journal_mark_dirty (th, p_s_sb, p_s_bh);
-		bforget (p_s_un_bh);
 		inode->i_blocks -= p_s_sb->s_blocksize / 512;
 		reiserfs_free_block(th, tmp);
 		if ( item_moved (&s_ih, p_s_path) )  {
-		    need_research = 1;
-		    break ;
-		    }
+			need_research = 1;
+			break ;
+		}
 	    }
 
 	    /* a trick.  If the buffer has been logged, this
@@ -1182,28 +1130,6 @@
 	    */
 	    reiserfs_restore_prepared_buffer(p_s_sb, p_s_bh);
 
-	    if ( n_retry ) {
-		/* There is block in use. Wait, they should release it soon */
-
-		RFALSE( *p_n_removed >= n_unfm_number, "PAP-5290: illegal case");
-#ifdef CONFIG_REISERFS_CHECK
-		if ( !(++n_repeat_counter % 500000) ) {
-		    reiserfs_warning("PAP-5300: prepare_for_delete_or_cut: (pid %u): "
-				     "could not delete item %k in (%d) iterations. New file length %Lu. (inode %Ld), Still trying\n",
-				     current->pid, p_s_item_key, n_repeat_counter, n_new_file_length, inode->i_size);
-		    if (n_repeat_counter == 5000000) {
-			print_block (PATH_PLAST_BUFFER(p_s_path), 3, 
-				     PATH_LAST_POSITION (p_s_path) - 2, PATH_LAST_POSITION (p_s_path) + 2);
-			reiserfs_panic(p_s_sb, "PAP-5305: prepare_for_delete_or_cut: key %k, new_file_length %Ld",
-				       p_s_item_key, n_new_file_length);
-		    }
-		}
-#endif
-
-		run_task_queue(&tq_disk);
-		current->policy |= SCHED_YIELD;
-		schedule();
-	    }
 	    /* This loop can be optimized. */
 	} while ( (*p_n_removed < n_unfm_number || need_research) &&
 		  search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path) == POSITION_FOUND );
diff -Nur --exclude=*~ linux-2.4.16/fs/vfat/vfatfs_syms.c linux/fs/vfat/vfatfs_syms.c
--- linux-2.4.16/fs/vfat/vfatfs_syms.c	Mon Nov 26 08:35:00 2001
+++ linux/fs/vfat/vfatfs_syms.c	Wed Nov 28 18:15:57 2001
@@ -33,3 +33,4 @@
 
 module_init(init_vfat_fs)
 module_exit(exit_vfat_fs)
+MODULE_LICENSE("GPL");
diff -Nur --exclude=*~ linux-2.4.16/include/asm-i386/pgalloc.h linux/include/asm-i386/pgalloc.h
--- linux-2.4.16/include/asm-i386/pgalloc.h	Mon Nov 26 08:35:00 2001
+++ linux/include/asm-i386/pgalloc.h	Fri Nov 30 19:02:25 2001
@@ -18,15 +18,21 @@
  * Allocate and free page tables.
  */
 
-#if CONFIG_X86_PAE
+#if defined (CONFIG_X86_PAE)
+/*
+ * We can't include <linux/slab.h> here, thus these uglinesses.
+ */
+struct kmem_cache_s;
+
+extern struct kmem_cache_s *pae_pgd_cachep;
+extern void *kmem_cache_alloc(struct kmem_cache_s *, int);
+extern void kmem_cache_free(struct kmem_cache_s *, void *);
 
-extern void *kmalloc(size_t, int);
-extern void kfree(const void *);
 
-static __inline__ pgd_t *get_pgd_slow(void)
+static inline pgd_t *get_pgd_slow(void)
 {
 	int i;
-	pgd_t *pgd = kmalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL);
+	pgd_t *pgd = kmem_cache_alloc(pae_pgd_cachep, GFP_KERNEL);
 
 	if (pgd) {
 		for (i = 0; i < USER_PTRS_PER_PGD; i++) {
@@ -36,32 +42,36 @@
 			clear_page(pmd);
 			set_pgd(pgd + i, __pgd(1 + __pa(pmd)));
 		}
-		memcpy(pgd + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+		memcpy(pgd + USER_PTRS_PER_PGD,
+			swapper_pg_dir + USER_PTRS_PER_PGD,
+			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
 	}
 	return pgd;
 out_oom:
 	for (i--; i >= 0; i--)
 		free_page((unsigned long)__va(pgd_val(pgd[i])-1));
-	kfree(pgd);
+	kmem_cache_free(pae_pgd_cachep, pgd);
 	return NULL;
 }
 
 #else
 
-static __inline__ pgd_t *get_pgd_slow(void)
+static inline pgd_t *get_pgd_slow(void)
 {
 	pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
 
 	if (pgd) {
 		memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
-		memcpy(pgd + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+		memcpy(pgd + USER_PTRS_PER_PGD,
+			swapper_pg_dir + USER_PTRS_PER_PGD,
+			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
 	}
 	return pgd;
 }
 
-#endif
+#endif /* CONFIG_X86_PAE */
 
-static __inline__ pgd_t *get_pgd_fast(void)
+static inline pgd_t *get_pgd_fast(void)
 {
 	unsigned long *ret;
 
@@ -74,21 +84,21 @@
 	return (pgd_t *)ret;
 }
 
-static __inline__ void free_pgd_fast(pgd_t *pgd)
+static inline void free_pgd_fast(pgd_t *pgd)
 {
 	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
 	pgd_quicklist = (unsigned long *) pgd;
 	pgtable_cache_size++;
 }
 
-static __inline__ void free_pgd_slow(pgd_t *pgd)
+static inline void free_pgd_slow(pgd_t *pgd)
 {
-#if CONFIG_X86_PAE
+#if defined(CONFIG_X86_PAE)
 	int i;
 
 	for (i = 0; i < USER_PTRS_PER_PGD; i++)
 		free_page((unsigned long)__va(pgd_val(pgd[i])-1));
-	kfree(pgd);
+	kmem_cache_free(pae_pgd_cachep, pgd);
 #else
 	free_page((unsigned long)pgd);
 #endif
@@ -104,7 +114,8 @@
 	return pte;
 }
 
-static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
+static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm,
+					unsigned long address)
 {
 	unsigned long *ret;
 
@@ -116,7 +127,7 @@
 	return (pte_t *)ret;
 }
 
-static __inline__ void pte_free_fast(pte_t *pte)
+static inline void pte_free_fast(pte_t *pte)
 {
 	*(unsigned long *)pte = (unsigned long) pte_quicklist;
 	pte_quicklist = (unsigned long *) pte;
@@ -128,14 +139,9 @@
 	free_page((unsigned long)pte);
 }
 
-#define pte_free(pte)		pte_free_fast(pte)
-#ifdef CONFIG_X86_PAE
-#define pgd_alloc(mm)		get_pgd_slow()
+#define pte_free(pte)		pte_free_slow(pte)
 #define pgd_free(pgd)		free_pgd_slow(pgd)
-#else
 #define pgd_alloc(mm)		get_pgd_fast()
-#define pgd_free(pgd)		free_pgd_fast(pgd)
-#endif
 
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
diff -Nur --exclude=*~ linux-2.4.16/include/asm-ia64/pal.h linux/include/asm-ia64/pal.h
--- linux-2.4.16/include/asm-ia64/pal.h	Mon Nov 26 08:35:00 2001
+++ linux/include/asm-ia64/pal.h	Fri Nov 30 13:33:59 2001
@@ -88,10 +88,10 @@
 typedef s64				pal_status_t;
 
 #define PAL_STATUS_SUCCESS		0	/* No error */
-#define PAL_STATUS_UNIMPLEMENTED	-1	/* Unimplemented procedure */
-#define PAL_STATUS_EINVAL		-2	/* Invalid argument */
-#define PAL_STATUS_ERROR		-3	/* Error */
-#define PAL_STATUS_CACHE_INIT_FAIL	-4	/* Could not initialize the
+#define PAL_STATUS_UNIMPLEMENTED	(-1)	/* Unimplemented procedure */
+#define PAL_STATUS_EINVAL		(-2)	/* Invalid argument */
+#define PAL_STATUS_ERROR		(-3)	/* Error */
+#define PAL_STATUS_CACHE_INIT_FAIL	(-4)	/* Could not initialize the
 						 * specified level and type of
 						 * cache without sideeffects
 						 * and "restrict" was 1
diff -Nur --exclude=*~ linux-2.4.16/include/asm-ia64/siginfo.h linux/include/asm-ia64/siginfo.h
--- linux-2.4.16/include/asm-ia64/siginfo.h	Mon Nov 26 08:35:01 2001
+++ linux/include/asm-ia64/siginfo.h	Fri Nov 30 13:33:59 2001
@@ -119,11 +119,11 @@
 
 #define SI_USER		0		/* sent by kill, sigsend, raise */
 #define SI_KERNEL	0x80		/* sent by the kernel from somewhere */
-#define SI_QUEUE	-1		/* sent by sigqueue */
+#define SI_QUEUE	(-1)		/* sent by sigqueue */
 #define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
-#define SI_MESGQ	-3		/* sent by real time mesq state change */
-#define SI_ASYNCIO	-4		/* sent by AIO completion */
-#define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_MESGQ	(-3)		/* sent by real time mesq state change */
+#define SI_ASYNCIO	(-4)		/* sent by AIO completion */
+#define SI_SIGIO	(-5)		/* sent by queued SIGIO */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -Nur --exclude=*~ linux-2.4.16/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h
--- linux-2.4.16/include/asm-sparc/bitops.h	Mon Nov 26 08:35:00 2001
+++ linux/include/asm-sparc/bitops.h	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.65 2001/10/30 04:08:26 davem Exp $
+/* $Id: bitops.h,v 1.67 2001/11/19 18:36:34 davem Exp $
  * bitops.h: Bit string operations on the Sparc.
  *
  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
diff -Nur --exclude=*~ linux-2.4.16/include/asm-sparc64/bitops.h linux/include/asm-sparc64/bitops.h
--- linux-2.4.16/include/asm-sparc64/bitops.h	Mon Nov 26 08:35:00 2001
+++ linux/include/asm-sparc64/bitops.h	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.36 2001/06/14 12:34:49 davem Exp $
+/* $Id: bitops.h,v 1.38 2001/11/19 18:36:34 davem Exp $
  * bitops.h: Bit string operations on the V9.
  *
  * Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -13,9 +13,9 @@
 extern long ___test_and_clear_bit(unsigned long nr, volatile void *addr);
 extern long ___test_and_change_bit(unsigned long nr, volatile void *addr);
 
-#define test_and_set_bit(nr,addr)	(___test_and_set_bit(nr,addr)!=0)
-#define test_and_clear_bit(nr,addr)	(___test_and_clear_bit(nr,addr)!=0)
-#define test_and_change_bit(nr,addr)	(___test_and_change_bit(nr,addr)!=0)
+#define test_and_set_bit(nr,addr)	({___test_and_set_bit(nr,addr)!=0;})
+#define test_and_clear_bit(nr,addr)	({___test_and_clear_bit(nr,addr)!=0;})
+#define test_and_change_bit(nr,addr)	({___test_and_change_bit(nr,addr)!=0;})
 #define set_bit(nr,addr)		((void)___test_and_set_bit(nr,addr))
 #define clear_bit(nr,addr)		((void)___test_and_clear_bit(nr,addr))
 #define change_bit(nr,addr)		((void)___test_and_change_bit(nr,addr))
@@ -214,8 +214,8 @@
 extern long ___test_and_set_le_bit(int nr, volatile void *addr);
 extern long ___test_and_clear_le_bit(int nr, volatile void *addr);
 
-#define test_and_set_le_bit(nr,addr)	(___test_and_set_le_bit(nr,addr)!=0)
-#define test_and_clear_le_bit(nr,addr)	(___test_and_clear_le_bit(nr,addr)!=0)
+#define test_and_set_le_bit(nr,addr)	({___test_and_set_le_bit(nr,addr)!=0;})
+#define test_and_clear_le_bit(nr,addr)	({___test_and_clear_le_bit(nr,addr)!=0;})
 #define set_le_bit(nr,addr)		((void)___test_and_set_le_bit(nr,addr))
 #define clear_le_bit(nr,addr)		((void)___test_and_clear_le_bit(nr,addr))
 
diff -Nur --exclude=*~ linux-2.4.16/include/asm-sparc64/page.h linux/include/asm-sparc64/page.h
--- linux-2.4.16/include/asm-sparc64/page.h	Mon Nov 26 08:35:00 2001
+++ linux/include/asm-sparc64/page.h	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.36 2000/08/10 01:04:53 davem Exp $ */
+/* $Id: page.h,v 1.37 2001/11/17 00:10:48 davem Exp $ */
 
 #ifndef _SPARC64_PAGE_H
 #define _SPARC64_PAGE_H
@@ -18,7 +18,16 @@
 
 #ifndef __ASSEMBLY__
 
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+extern void do_BUG(const char *file, int line);
+#define BUG() do {					\
+	do_BUG(__FILE__, __LINE__);			\
+	__builtin_trap();				\
+} while (0)
+#else
 #define BUG()		__builtin_trap()
+#endif
+
 #define PAGE_BUG(page)	BUG()
 
 extern void _clear_page(void *page);
diff -Nur --exclude=*~ linux-2.4.16/include/asm-sparc64/processor.h linux/include/asm-sparc64/processor.h
--- linux-2.4.16/include/asm-sparc64/processor.h	Mon Nov 26 08:35:00 2001
+++ linux/include/asm-sparc64/processor.h	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.76 2001/10/08 09:32:13 davem Exp $
+/* $Id: processor.h,v 1.80 2001/11/17 00:10:48 davem Exp $
  * include/asm-sparc64/processor.h
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -66,6 +66,15 @@
 	unsigned long gsr[7];
 	unsigned long xfsr[7];
 
+#ifdef CONFIG_DEBUG_SPINLOCK
+	/* How many spinlocks held by this thread.
+	 * Used with spin lock debugging to catch tasks
+	 * sleeping illegally with locks held.
+	 */
+	int smp_lock_count;
+	unsigned int smp_lock_pc;
+#endif
+
 	struct reg_window reg_window[NSWINS];
 	unsigned long rwbuf_stkptrs[NSWINS];
 	
@@ -88,6 +97,7 @@
 #define FAULT_CODE_ITLB		0x04	/* Miss happened in I-TLB		*/
 #define FAULT_CODE_WINFIXUP	0x08	/* Miss happened during spill/fill	*/
 
+#ifndef CONFIG_DEBUG_SPINLOCK
 #define INIT_THREAD  {					\
 /* ksp, wstate, cwp, flags, current_ds, */ 		\
    0,   0,      0,   0,     KERNEL_DS,			\
@@ -104,6 +114,24 @@
 /* user_cntd0, user_cndd1, kernel_cntd0, kernel_cntd0, pcr_reg */ \
    0,          0,          0,		 0,            0, \
 }
+#else /* CONFIG_DEBUG_SPINLOCK */
+#define INIT_THREAD  {					\
+/* ksp, wstate, cwp, flags, current_ds, */ 		\
+   0,   0,      0,   0,     KERNEL_DS,			\
+/* w_saved, fpdepth, fault_code, use_blkcommit, */	\
+   0,       0,       0,          0,			\
+/* fault_address, fpsaved, __pad2, kregs, */		\
+   0,             { 0 },   0,      0,			\
+/* utraps, gsr,   xfsr,  smp_lock_count, smp_lock_pc, */\
+   0,	   { 0 }, { 0 }, 0,		 0,		\
+/* reg_window */					\
+   { { { 0, }, { 0, } }, }, 				\
+/* rwbuf_stkptrs */					\
+   { 0, 0, 0, 0, 0, 0, 0, },				\
+/* user_cntd0, user_cndd1, kernel_cntd0, kernel_cntd0, pcr_reg */ \
+   0,          0,          0,		 0,            0, \
+}
+#endif /* !(CONFIG_DEBUG_SPINLOCK) */
 
 #ifdef __KERNEL__
 #if PAGE_SHIFT == 13
diff -Nur --exclude=*~ linux-2.4.16/include/asm-sparc64/rwsem.h linux/include/asm-sparc64/rwsem.h
--- linux-2.4.16/include/asm-sparc64/rwsem.h	Mon Nov 26 08:35:00 2001
+++ linux/include/asm-sparc64/rwsem.h	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: rwsem.h,v 1.4 2001/04/26 02:36:36 davem Exp $
+/* $Id: rwsem.h,v 1.5 2001/11/18 00:12:56 davem Exp $
  * rwsem.h: R/W semaphores implemented using CAS
  *
  * Written by David S. Miller (davem@redhat.com), 2001.
@@ -59,7 +59,7 @@
 		" add		%%g7, 1, %%g7\n\t"
 		"cmp		%%g7, 0\n\t"
 		"bl,pn		%%icc, 3f\n\t"
-		" membar	#StoreStore\n"
+		" membar	#StoreLoad | #StoreStore\n"
 		"2:\n\t"
 		".subsection	2\n"
 		"3:\tmov	%0, %%g5\n\t"
@@ -92,7 +92,7 @@
 		"bne,pn		%%icc, 1b\n\t"
 		" cmp		%%g7, 0\n\t"
 		"bne,pn		%%icc, 3f\n\t"
-		" membar	#StoreStore\n"
+		" membar	#StoreLoad | #StoreStore\n"
 		"2:\n\t"
 		".subsection	2\n"
 		"3:\tmov	%0, %%g5\n\t"
@@ -122,7 +122,7 @@
 		"bne,pn		%%icc, 1b\n\t"
 		" cmp		%%g7, 0\n\t"
 		"bl,pn		%%icc, 3f\n\t"
-		" membar	#StoreStore\n"
+		" membar	#StoreLoad | #StoreStore\n"
 		"2:\n\t"
 		".subsection	2\n"
 		"3:\tsethi	%%hi(%2), %%g1\n\t"
@@ -160,7 +160,7 @@
 		" sub		%%g7, %%g1, %%g7\n\t"
 		"cmp		%%g7, 0\n\t"
 		"bl,pn		%%icc, 3f\n\t"
-		" membar	#StoreStore\n"
+		" membar	#StoreLoad | #StoreStore\n"
 		"2:\n\t"
 		".subsection 2\n"
 		"3:\tmov	%0, %%g5\n\t"
@@ -189,7 +189,7 @@
 		"cas		[%2], %%g5, %%g7\n\t"
 		"cmp		%%g5, %%g7\n\t"
 		"bne,pn		%%icc, 1b\n\t"
-		" nop\n\t"
+		" membar	#StoreLoad | #StoreStore\n\t"
 		"mov		%%g7, %0\n\t"
 		: "=&r" (tmp)
 		: "0" (tmp), "r" (sem)
@@ -208,7 +208,7 @@
 
 again:
 	__asm__ __volatile__("cas	[%2], %3, %0\n\t"
-			     "membar	#StoreStore | #StoreLoad"
+			     "membar	#StoreLoad | #StoreStore"
 			     : "=&r" (prev)
 			     : "0" (new), "r" (sem), "r" (old)
 			     : "memory");
diff -Nur --exclude=*~ linux-2.4.16/include/asm-sparc64/semaphore.h linux/include/asm-sparc64/semaphore.h
--- linux-2.4.16/include/asm-sparc64/semaphore.h	Mon Nov 26 08:35:00 2001
+++ linux/include/asm-sparc64/semaphore.h	Fri Nov 30 13:01:25 2001
@@ -75,7 +75,7 @@
 "	bne,pn	%%icc, 1b\n"
 "	 cmp	%%g7, 1\n"
 "	bl,pn	%%icc, 3f\n"
-"	 membar	#StoreStore\n"
+"	 membar	#StoreLoad | #StoreStore\n"
 "2:\n"
 "	.subsection 2\n"
 "3:	mov	%0, %%g5\n"
@@ -120,7 +120,7 @@
 "	bne,pn	%%icc, 1b\n"
 "	 cmp	%%g7, 1\n"
 "	bl,pn	%%icc, 3f\n"
-"	 membar	#StoreStore\n"
+"	 membar	#StoreLoad | #StoreStore\n"
 "2:\n"
 "	.subsection 2\n"
 "3:	mov	%2, %%g5\n"
@@ -173,7 +173,7 @@
 "	cmp	%%g5, %%g7\n"
 "	bne,pn	%%icc, 1b\n"
 "	 mov	0, %0\n"
-"	membar	#StoreStore\n"
+"	membar	#StoreLoad | #StoreStore\n"
 "2:\n"
 	: "=&r" (ret)
 	: "r" (sem)
@@ -207,7 +207,7 @@
 "	bne,pn	%%icc, 1b\n"
 "	 addcc	%%g7, 1, %%g0\n"
 "	ble,pn	%%icc, 3f\n"
-"	 nop\n"
+"	 membar	#StoreLoad | #StoreStore\n"
 "2:\n"
 "	.subsection 2\n"
 "3:	mov	%0, %%g5\n"
diff -Nur --exclude=*~ linux-2.4.16/include/asm-sparc64/smp.h linux/include/asm-sparc64/smp.h
--- linux-2.4.16/include/asm-sparc64/smp.h	Mon Nov 26 08:35:00 2001
+++ linux/include/asm-sparc64/smp.h	Fri Nov 30 13:01:25 2001
@@ -8,6 +8,7 @@
 
 #include <linux/config.h>
 #include <linux/threads.h>
+#include <linux/cache.h>
 #include <asm/asi.h>
 #include <asm/starfire.h>
 #include <asm/spitfire.h>
@@ -34,7 +35,7 @@
 /* Per processor Sparc parameters we need. */
 
 /* Keep this a multiple of 64-bytes for cache reasons. */
-struct cpuinfo_sparc {
+typedef struct {
 	/* Dcache line 1 */
 	unsigned int	__pad0;		/* bh_count moved to irq_stat for consistency. KAO */
 	unsigned int	multiplier;
@@ -51,9 +52,9 @@
 
 	/* Dcache lines 3 and 4 */
 	unsigned int	irq_worklists[16];
-};
+} ____cacheline_aligned cpuinfo_sparc;
 
-extern struct cpuinfo_sparc cpu_data[NR_CPUS];
+extern cpuinfo_sparc cpu_data[NR_CPUS];
 
 /*
  *	Private routines/data
diff -Nur --exclude=*~ linux-2.4.16/include/asm-sparc64/spinlock.h linux/include/asm-sparc64/spinlock.h
--- linux-2.4.16/include/asm-sparc64/spinlock.h	Mon Nov 26 08:35:00 2001
+++ linux/include/asm-sparc64/spinlock.h	Fri Nov 30 13:01:25 2001
@@ -6,11 +6,13 @@
 #ifndef __SPARC64_SPINLOCK_H
 #define __SPARC64_SPINLOCK_H
 
+#include <linux/config.h>
+
 #ifndef __ASSEMBLY__
 
 /* To get debugging spinlocks which detect and catch
- * deadlock situations, set DEBUG_SPINLOCKS in the sparc64
- * specific makefile and rebuild your kernel.
+ * deadlock situations, set CONFIG_DEBUG_SPINLOCK
+ * and rebuild your kernel.
  */
 
 /* All of these locking primitives are expected to work properly
@@ -26,7 +28,7 @@
  * must be pre-V9 branches.
  */
 
-#ifndef SPIN_LOCK_DEBUG
+#ifndef CONFIG_DEBUG_SPINLOCK
 
 typedef unsigned char spinlock_t;
 #define SPIN_LOCK_UNLOCKED	0
@@ -75,7 +77,7 @@
 			     : "memory");
 }
 
-#else /* !(SPIN_LOCK_DEBUG) */
+#else /* !(CONFIG_DEBUG_SPINLOCK) */
 
 typedef struct {
 	unsigned char lock;
@@ -101,11 +103,11 @@
 #define spin_lock(lock)		_do_spin_lock(lock, "spin_lock")
 #define spin_unlock(lock)	_do_spin_unlock(lock)
 
-#endif /* SPIN_LOCK_DEBUG */
+#endif /* CONFIG_DEBUG_SPINLOCK */
 
 /* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */
 
-#ifndef SPIN_LOCK_DEBUG
+#ifndef CONFIG_DEBUG_SPINLOCK
 
 typedef unsigned int rwlock_t;
 #define RW_LOCK_UNLOCKED	0
@@ -121,7 +123,7 @@
 #define write_lock(p)	__write_lock(p)
 #define write_unlock(p)	__write_unlock(p)
 
-#else /* !(SPIN_LOCK_DEBUG) */
+#else /* !(CONFIG_DEBUG_SPINLOCK) */
 
 typedef struct {
 	unsigned long lock;
@@ -164,7 +166,7 @@
 	__restore_flags(flags); \
 } while(0)
 
-#endif /* SPIN_LOCK_DEBUG */
+#endif /* CONFIG_DEBUG_SPINLOCK */
 
 #endif /* !(__ASSEMBLY__) */
 
diff -Nur --exclude=*~ linux-2.4.16/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h
--- linux-2.4.16/include/asm-sparc64/system.h	Mon Nov 26 08:35:00 2001
+++ linux/include/asm-sparc64/system.h	Fri Nov 30 13:01:25 2001
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.64 2001/08/30 03:22:00 kanoj Exp $ */
+/* $Id: system.h,v 1.68 2001/11/18 00:12:56 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -145,6 +145,24 @@
 #define flush_register_windows flushw_all
 #define prepare_to_switch flushw_all
 
+#ifndef CONFIG_DEBUG_SPINLOCk
+#define CHECK_LOCKS(PREV)	do { } while(0)
+#else /* CONFIG_DEBUG_SPINLOCk */
+#define CHECK_LOCKS(PREV)						\
+if ((PREV)->thread.smp_lock_count) {					\
+	unsigned long rpc;						\
+	__asm__ __volatile__("mov %%i7, %0" : "=r" (rpc));		\
+	printk(KERN_CRIT "(%s)[%d]: Sleeping with %d locks held!\n",	\
+	       (PREV)->comm, (PREV)->pid,				\
+	       (PREV)->thread.smp_lock_count);				\
+	printk(KERN_CRIT "(%s)[%d]: Last lock at %08x\n",		\
+	       (PREV)->comm, (PREV)->pid,				\
+	       (PREV)->thread.smp_lock_pc);				\
+	printk(KERN_CRIT "(%s)[%d]: Sched caller %016lx\n",		\
+	       (PREV)->comm, (PREV)->pid, rpc);				\
+}
+#endif /* !(CONFIG_DEBUG_SPINLOCk) */
+
 	/* See what happens when you design the chip correctly?
 	 *
 	 * We tell gcc we clobber all non-fixed-usage registers except
@@ -155,7 +173,8 @@
 	 * and 2 stores in this critical code path.  -DaveM
 	 */
 #define switch_to(prev, next, last)						\
-do {	if (current->thread.flags & SPARC_FLAG_PERFCTR) {			\
+do {	CHECK_LOCKS(prev);							\
+	if (current->thread.flags & SPARC_FLAG_PERFCTR) {			\
 		unsigned long __tmp;						\
 		read_pcr(__tmp);						\
 		current->thread.pcr_reg = __tmp;				\
@@ -276,7 +295,7 @@
 __cmpxchg_u32(volatile int *m, int old, int new)
 {
 	__asm__ __volatile__("cas [%2], %3, %0\n\t"
-			     "membar #StoreStore | #StoreLoad"
+			     "membar #StoreLoad | #StoreStore"
 			     : "=&r" (new)
 			     : "0" (new), "r" (m), "r" (old)
 			     : "memory");
@@ -288,7 +307,7 @@
 __cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
 {
 	__asm__ __volatile__("casx [%2], %3, %0\n\t"
-			     "membar #StoreStore | #StoreLoad"
+			     "membar #StoreLoad | #StoreStore"
 			     : "=&r" (new)
 			     : "0" (new), "r" (m), "r" (old)
 			     : "memory");
diff -Nur --exclude=*~ linux-2.4.16/include/linux/devfs_fs_kernel.h linux/include/linux/devfs_fs_kernel.h
--- linux-2.4.16/include/linux/devfs_fs_kernel.h	Mon Nov 26 08:35:00 2001
+++ linux/include/linux/devfs_fs_kernel.h	Fri Nov 30 19:02:37 2001
@@ -37,8 +37,7 @@
 				       */
 #define DEVFS_FL_REMOVABLE      0x010 /* This is a removable media device    */
 #define DEVFS_FL_WAIT           0x020 /* Wait for devfsd to finish           */
-#define DEVFS_FL_NO_PERSISTENCE 0x040 /* Forget changes after unregister     */
-#define DEVFS_FL_CURRENT_OWNER  0x080 /* Set initial ownership to current    */
+#define DEVFS_FL_CURRENT_OWNER  0x040 /* Set initial ownership to current    */
 #define DEVFS_FL_DEFAULT        DEVFS_FL_NONE
 
 
diff -Nur --exclude=*~ linux-2.4.16/include/linux/fs.h linux/include/linux/fs.h
--- linux-2.4.16/include/linux/fs.h	Mon Nov 26 08:35:11 2001
+++ linux/include/linux/fs.h	Fri Nov 30 19:02:25 2001
@@ -854,6 +854,8 @@
 	int (*getattr) (struct dentry *, struct iattr *);
 };
 
+struct seq_file;
+
 /*
  * NOTE: write_inode, delete_inode, clear_inode, put_inode can be called
  * without the big kernel lock held in all filesystems.
@@ -905,6 +907,7 @@
 	 */
 	struct dentry * (*fh_to_dentry)(struct super_block *sb, __u32 *fh, int len, int fhtype, int parent);
 	int (*dentry_to_fh)(struct dentry *, __u32 *fh, int *lenp, int need_parent);
+	int (*show_options)(struct seq_file *, struct vfsmount *);
 };
 
 /* Inode state bits.. */
diff -Nur --exclude=*~ linux-2.4.16/include/linux/i8k.h linux/include/linux/i8k.h
--- linux-2.4.16/include/linux/i8k.h	Mon Nov 26 08:35:00 2001
+++ linux/include/linux/i8k.h	Wed Nov 28 18:15:57 2001
@@ -1,5 +1,5 @@
 /*
- * i8k.h -- Linux driver for accessing the SMM BIOS on Dell I8000 laptops
+ * i8k.h -- Linux driver for accessing the SMM BIOS on Dell laptops
  *
  * Copyright (C) 2001  Massimo Dal Zotto <dz@debian.org>
  *
@@ -36,9 +36,9 @@
 #define I8K_FAN_HIGH		2
 #define I8K_FAN_MAX		I8K_FAN_HIGH
 
-#define I8K_VOL_UP		0x01
-#define I8K_VOL_DOWN		0x02
-#define I8K_VOL_MUTE		0x03
+#define I8K_VOL_UP		1
+#define I8K_VOL_DOWN		2
+#define I8K_VOL_MUTE		4
 
 #define I8K_AC			1
 #define I8K_BATTERY		0
diff -Nur --exclude=*~ linux-2.4.16/include/linux/jbd.h linux/include/linux/jbd.h
--- linux-2.4.16/include/linux/jbd.h	Mon Nov 26 08:35:00 2001
+++ linux/include/linux/jbd.h	Fri Nov 30 19:03:55 2001
@@ -221,7 +221,7 @@
 #endif
 
 #else
-#define J_ASSERT(assert)
+#define J_ASSERT(assert)	do { } while (0)
 #endif		/* JBD_ASSERTIONS */
 
 enum jbd_state_bits {
diff -Nur --exclude=*~ linux-2.4.16/include/linux/reiserfs_fs_sb.h linux/include/linux/reiserfs_fs_sb.h
--- linux-2.4.16/include/linux/reiserfs_fs_sb.h	Mon Nov 26 08:35:00 2001
+++ linux/include/linux/reiserfs_fs_sb.h	Fri Nov 30 19:02:25 2001
@@ -420,6 +420,10 @@
     int s_bmaps_without_search;
     int s_direct2indirect;
     int s_indirect2direct;
+	/* set up when it's ok for reiserfs_read_inode2() to read from
+	   disk inode with nlink==0. Currently this is only used during
+	   finish_unfinished() processing at mount time */
+    int s_is_unlinked_ok;
     reiserfs_proc_info_data_t s_proc_info_data;
     struct proc_dir_entry *procdir;
 };
diff -Nur --exclude=*~ linux-2.4.16/include/linux/slab.h linux/include/linux/slab.h
--- linux-2.4.16/include/linux/slab.h	Mon Nov 26 08:35:00 2001
+++ linux/include/linux/slab.h	Fri Nov 30 19:02:26 2001
@@ -38,6 +38,7 @@
 #define	SLAB_NO_REAP		0x00001000UL	/* never reap from the cache */
 #define	SLAB_HWCACHE_ALIGN	0x00002000UL	/* align objs on a h/w cache lines */
 #define SLAB_CACHE_DMA		0x00004000UL	/* use GFP_DMA memory */
+#define SLAB_MUST_HWCACHE_ALIGN	0x00008000UL	/* force alignment */
 
 /* flags passed to a constructor func */
 #define	SLAB_CTOR_CONSTRUCTOR	0x001UL		/* if not set, then deconstructor */
diff -Nur --exclude=*~ linux-2.4.16/include/linux/socket.h linux/include/linux/socket.h
--- linux-2.4.16/include/linux/socket.h	Mon Nov 26 08:35:00 2001
+++ linux/include/linux/socket.h	Fri Nov 30 19:02:25 2001
@@ -156,6 +156,7 @@
 #define AF_IRDA		23	/* IRDA sockets			*/
 #define AF_PPPOX	24	/* PPPoX sockets		*/
 #define AF_WANPIPE	25	/* Wanpipe API Sockets */
+#define AF_LLC		26	/* Linux LLC			*/
 #define AF_BLUETOOTH	31	/* Bluetooth sockets 		*/
 #define AF_MAX		32	/* For now.. */
 
@@ -187,6 +188,7 @@
 #define PF_IRDA		AF_IRDA
 #define PF_PPPOX	AF_PPPOX
 #define PF_WANPIPE	AF_WANPIPE
+#define PF_LLC		AF_LLC
 #define PF_BLUETOOTH	AF_BLUETOOTH
 #define PF_MAX		AF_MAX
 
@@ -237,6 +239,8 @@
 #define SOL_ATM		264	/* ATM layer (cell level) */
 #define SOL_AAL		265	/* ATM Adaption Layer (packet level) */
 #define SOL_IRDA        266
+#define SOL_NETBEUI	267
+#define SOL_LLC		268
 
 /* IPX options */
 #define IPX_TYPE	1
diff -Nur --exclude=*~ linux-2.4.16/include/net/irda/irlmp.h linux/include/net/irda/irlmp.h
--- linux-2.4.16/include/net/irda/irlmp.h	Mon Nov 26 08:35:00 2001
+++ linux/include/net/irda/irlmp.h	Fri Nov 30 19:04:33 2001
@@ -264,4 +264,16 @@
 	return IRLAP_GET_TX_QUEUE_LEN(self->lap->irlap);
 }
 
+/* After doing a irlmp_dup(), this get one of the two socket back into
+ * a state where it's waiting incomming connections.
+ * Note : this can be used *only* if the socket is not yet connected
+ * (i.e. NO irlmp_connect_response() done on this socket).
+ * - Jean II */
+static inline void irlmp_listen(struct lsap_cb *self)
+{
+	self->dlsap_sel = LSAP_ANY;
+	self->lap = NULL;
+	self->lsap_state = LSAP_DISCONNECTED;
+}
+
 #endif
diff -Nur --exclude=*~ linux-2.4.16/include/net/irda/irttp.h linux/include/net/irda/irttp.h
--- linux-2.4.16/include/net/irda/irttp.h	Mon Nov 26 08:35:00 2001
+++ linux/include/net/irda/irttp.h	Fri Nov 30 19:04:35 2001
@@ -148,6 +148,17 @@
 	return self->max_seg_size;
 }
 
+/* After doing a irttp_dup(), this get one of the two socket back into
+ * a state where it's waiting incomming connections.
+ * Note : this can be used *only* if the socket is not yet connected
+ * (i.e. NO irttp_connect_response() done on this socket).
+ * - Jean II */
+static inline void irttp_listen(struct tsap_cb *self)
+{
+	irlmp_listen(self->lsap);
+	self->dtsap_sel = LSAP_ANY;
+}
+
 extern struct irttp_cb *irttp;
 
 #endif /* IRTTP_H */
diff -Nur --exclude=*~ linux-2.4.16/include/pcmcia/ciscode.h linux/include/pcmcia/ciscode.h
--- linux-2.4.16/include/pcmcia/ciscode.h	Mon Nov 26 08:35:00 2001
+++ linux/include/pcmcia/ciscode.h	Fri Nov 30 13:18:53 2001
@@ -1,5 +1,5 @@
 /*
- * ciscode.h 1.45 2000/08/12 02:08:23
+ * ciscode.h 1.48 2001/08/24 12:16:12
  *
  * The contents of this file are subject to the Mozilla Public License
  * Version 1.1 (the "License"); you may not use this file except in
@@ -16,8 +16,8 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in which
- * case the provisions of the GPL are applicable instead of the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
  * your version of this file under the MPL, indicate your decision by
@@ -104,6 +104,8 @@
 #define PRODID_QUATECH_DUAL_RS232	0x0012
 #define PRODID_QUATECH_DUAL_RS232_D1	0x0007
 #define PRODID_QUATECH_QUAD_RS232	0x001b
+#define PRODID_QUATECH_DUAL_RS422	0x000e
+#define PRODID_QUATECH_QUAD_RS422	0x0045
 
 #define MANFID_SMC			0x0108
 #define PRODID_SMC_ETHER		0x0105
diff -Nur --exclude=*~ linux-2.4.16/include/pcmcia/cs.h linux/include/pcmcia/cs.h
--- linux-2.4.16/include/pcmcia/cs.h	Mon Nov 26 08:35:00 2001
+++ linux/include/pcmcia/cs.h	Fri Nov 30 13:18:53 2001
@@ -1,5 +1,5 @@
 /*
- * cs.h 1.71 2000/08/29 00:54:20
+ * cs.h 1.74 2001/10/04 03:15:22
  *
  * The contents of this file are subject to the Mozilla Public License
  * Version 1.1 (the "License"); you may not use this file except in
@@ -16,8 +16,8 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in which
- * case the provisions of the GPL are applicable instead of the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
  * your version of this file under the MPL, indicate your decision by
@@ -181,6 +181,7 @@
 #define INT_MEMORY		0x01
 #define INT_MEMORY_AND_IO	0x02
 #define INT_CARDBUS		0x04
+#define INT_ZOOMED_VIDEO	0x08
 
 /* For RequestIO and ReleaseIO */
 typedef struct io_req_t {
diff -Nur --exclude=*~ linux-2.4.16/include/pcmcia/version.h linux/include/pcmcia/version.h
--- linux-2.4.16/include/pcmcia/version.h	Mon Nov 26 08:35:00 2001
+++ linux/include/pcmcia/version.h	Fri Nov 30 13:18:53 2001
@@ -1,4 +1,4 @@
-/* version.h 1.94 2000/10/03 17:55:48 (David Hinds) */
+/* version.h 1.102 2001/08/29 23:13:22 (David Hinds) */
 
-#define CS_RELEASE "3.1.22"
-#define CS_RELEASE_CODE 0x3116
+#define CS_RELEASE "3.1.30"
+#define CS_RELEASE_CODE 0x311e
diff -Nur --exclude=*~ linux-2.4.16/init/main.c linux/init/main.c
--- linux-2.4.16/init/main.c	Mon Nov 26 08:35:00 2001
+++ linux/init/main.c	Thu Nov 29 18:32:55 2001
@@ -591,6 +591,8 @@
 #endif
 	mem_init();
 	kmem_cache_sizes_init();
+	pgtable_cache_init();
+
 	mempages = num_physpages;
 
 	fork_init(mempages);
diff -Nur --exclude=*~ linux-2.4.16/kernel/exec_domain.c linux/kernel/exec_domain.c
--- linux-2.4.16/kernel/exec_domain.c	Mon Nov 26 08:35:00 2001
+++ linux/kernel/exec_domain.c	Wed Nov 28 18:15:57 2001
@@ -102,7 +102,7 @@
 	}
 #endif
 
-	ep = NULL;
+	ep = &default_exec_domain;
 out:
 	read_unlock(&exec_domains_lock);
 	return (ep);
@@ -162,8 +162,6 @@
 	struct exec_domain	*ep, *oep;
 
 	ep = lookup_exec_domain(personality);
-	if (ep == NULL)
-		return -EINVAL;
 	if (ep == current->exec_domain) {
 		current->personality = personality;
 		return 0;
diff -Nur --exclude=*~ linux-2.4.16/kernel/ksyms.c linux/kernel/ksyms.c
--- linux-2.4.16/kernel/ksyms.c	Mon Nov 26 08:35:00 2001
+++ linux/kernel/ksyms.c	Wed Nov 28 18:15:57 2001
@@ -46,6 +46,7 @@
 #include <linux/tty.h>
 #include <linux/in6.h>
 #include <linux/completion.h>
+#include <linux/seq_file.h>
 #include <asm/checksum.h>
 
 #if defined(CONFIG_PROC_FS)
@@ -476,6 +477,12 @@
 EXPORT_SYMBOL(reparent_to_init);
 EXPORT_SYMBOL(daemonize);
 EXPORT_SYMBOL(csum_partial); /* for networking and md */
+EXPORT_SYMBOL(seq_escape);
+EXPORT_SYMBOL(seq_printf);
+EXPORT_SYMBOL(seq_open);
+EXPORT_SYMBOL(seq_release);
+EXPORT_SYMBOL(seq_read);
+EXPORT_SYMBOL(seq_lseek);
 
 /* Program loader interfaces */
 EXPORT_SYMBOL(setup_arg_pages);
diff -Nur --exclude=*~ linux-2.4.16/mm/slab.c linux/mm/slab.c
--- linux-2.4.16/mm/slab.c	Mon Nov 26 08:35:00 2001
+++ linux/mm/slab.c	Thu Nov 29 18:32:55 2001
@@ -109,9 +109,11 @@
 #if DEBUG
 # define CREATE_MASK	(SLAB_DEBUG_INITIAL | SLAB_RED_ZONE | \
 			 SLAB_POISON | SLAB_HWCACHE_ALIGN | \
-			 SLAB_NO_REAP | SLAB_CACHE_DMA)
+			 SLAB_NO_REAP | SLAB_CACHE_DMA | \
+			 SLAB_MUST_HWCACHE_ALIGN)
 #else
-# define CREATE_MASK	(SLAB_HWCACHE_ALIGN | SLAB_NO_REAP | SLAB_CACHE_DMA)
+# define CREATE_MASK	(SLAB_HWCACHE_ALIGN | SLAB_NO_REAP | \
+			 SLAB_CACHE_DMA | SLAB_MUST_HWCACHE_ALIGN)
 #endif
 
 /*
@@ -649,7 +651,7 @@
 		flags &= ~SLAB_POISON;
 	}
 #if FORCED_DEBUG
-	if (size < (PAGE_SIZE>>3))
+	if ((size < (PAGE_SIZE>>3)) && !(flags & SLAB_MUST_HWCACHE_ALIGN))
 		/*
 		 * do not red zone large object, causes severe
 		 * fragmentation.
diff -Nur --exclude=*~ linux-2.4.16/net/irda/af_irda.c linux/net/irda/af_irda.c
--- linux-2.4.16/net/irda/af_irda.c	Mon Nov 26 08:35:01 2001
+++ linux/net/irda/af_irda.c	Fri Nov 30 18:28:17 2001
@@ -914,8 +914,7 @@
 	memcpy(&new->qos_tx, &self->qos_tx, sizeof(struct qos_info));
 
 	/* Clean up the original one to keep it in listen state */
-	self->tsap->dtsap_sel = self->tsap->lsap->dlsap_sel = LSAP_ANY;
-	self->tsap->lsap->lsap_state = LSAP_DISCONNECTED;
+	irttp_listen(self->tsap);
 
 	skb->sk = NULL;
 	skb->destructor = NULL;
@@ -1845,15 +1844,36 @@
 		  	return -EFAULT;
 		}
 
-		/* Find the object we target */
-		ias_obj = irias_find_object(ias_opt->irda_class_name);
+		/* Find the object we target.
+		 * If the user gives us an empty string, we use the object
+		 * associated with this socket. This will workaround
+		 * duplicated class name - Jean II */
+		if(ias_opt->irda_class_name[0] == '\0') {
+			if(self->ias_obj == NULL) {
+				kfree(ias_opt);
+				return -EINVAL;
+			}
+			ias_obj = self->ias_obj;
+		} else
+			ias_obj = irias_find_object(ias_opt->irda_class_name);
+
+		/* Only ROOT can mess with the global IAS database.
+		 * Users can only add attributes to the object associated
+		 * with the socket they own - Jean II */
+		if((!capable(CAP_NET_ADMIN)) &&
+		   ((ias_obj == NULL) || (ias_obj != self->ias_obj))) {
+			kfree(ias_opt);
+			return -EPERM;
+		}
+
+		/* If the object doesn't exist, create it */
 		if(ias_obj == (struct ias_object *) NULL) {
 			/* Create a new object */
 			ias_obj = irias_new_object(ias_opt->irda_class_name,
 						   jiffies);
 		}
 
-		/* Do we have it already ? */
+		/* Do we have the attribute already ? */
 		if(irias_find_attrib(ias_obj, ias_opt->irda_attrib_name)) {
 			kfree(ias_opt);
 			return -EINVAL;
@@ -1927,13 +1947,28 @@
 		  	return -EFAULT;
 		}
 
-		/* Find the object we target */
-		ias_obj = irias_find_object(ias_opt->irda_class_name);
+		/* Find the object we target.
+		 * If the user gives us an empty string, we use the object
+		 * associated with this socket. This will workaround
+		 * duplicated class name - Jean II */
+		if(ias_opt->irda_class_name[0] == '\0')
+			ias_obj = self->ias_obj;
+		else
+			ias_obj = irias_find_object(ias_opt->irda_class_name);
 		if(ias_obj == (struct ias_object *) NULL) {
 			kfree(ias_opt);
 			return -EINVAL;
 		}
 
+		/* Only ROOT can mess with the global IAS database.
+		 * Users can only del attributes from the object associated
+		 * with the socket they own - Jean II */
+		if((!capable(CAP_NET_ADMIN)) &&
+		   ((ias_obj == NULL) || (ias_obj != self->ias_obj))) {
+			kfree(ias_opt);
+			return -EPERM;
+		}
+
 		/* Find the attribute (in the object) we target */
 		ias_attr = irias_find_attrib(ias_obj,
 					     ias_opt->irda_attrib_name); 
@@ -2166,8 +2201,14 @@
 		  	return -EFAULT;
 		}
 
-		/* Find the object we target */
-		ias_obj = irias_find_object(ias_opt->irda_class_name);
+		/* Find the object we target.
+		 * If the user gives us an empty string, we use the object
+		 * associated with this socket. This will workaround
+		 * duplicated class name - Jean II */
+		if(ias_opt->irda_class_name[0] == '\0')
+			ias_obj = self->ias_obj;
+		else
+			ias_obj = irias_find_object(ias_opt->irda_class_name);
 		if(ias_obj == (struct ias_object *) NULL) {
 			kfree(ias_opt);
 			return -EINVAL;
diff -Nur --exclude=*~ linux-2.4.16/net/irda/iriap.c linux/net/irda/iriap.c
--- linux-2.4.16/net/irda/iriap.c	Mon Nov 26 08:35:01 2001
+++ linux/net/irda/iriap.c	Fri Nov 30 18:28:17 2001
@@ -800,9 +800,7 @@
 	new->max_header_size = max_header_size;
 
 	/* Clean up the original one to keep it in listen state */
-	self->lsap->dlsap_sel = LSAP_ANY;
-	self->lsap->lsap_state = LSAP_DISCONNECTED;
-	/* FIXME: refcount in irlmp might get wrong */
+	irlmp_listen(self->lsap);
 	
 	iriap_do_server_event(new, IAP_LM_CONNECT_INDICATION, userdata);
 }
diff -Nur --exclude=*~ linux-2.4.16/net/irda/irlap.c linux/net/irda/irlap.c
--- linux-2.4.16/net/irda/irlap.c	Mon Nov 26 08:35:01 2001
+++ linux/net/irda/irlap.c	Fri Nov 30 18:28:16 2001
@@ -51,6 +51,11 @@
 hashbin_t *irlap = NULL;
 int sysctl_slot_timeout = SLOT_TIMEOUT * 1000 / HZ;
 
+/* This is the delay of missed pf period before generating an event
+ * to the application. The spec mandate 3 seconds, but in some cases
+ * it's way too long. - Jean II */
+int sysctl_warn_noreply_time = 3;
+
 extern void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb);
 static void __irlap_close(struct irlap_cb *self);
 
@@ -527,22 +532,7 @@
 	self->discovery_cmd = discovery;
 	info.discovery = discovery;
 	
-	/* Check if the slot timeout is within limits */
-	if (sysctl_slot_timeout < 20) {
-		ERROR(__FUNCTION__ 
-		      "(), to low value for slot timeout!\n");
-		sysctl_slot_timeout = 20;
-	}
-	/* 
-	 * Highest value is actually 8, but we allow higher since
-	 * some devices seems to require it.
-	 */
-	if (sysctl_slot_timeout > 160) {
-		ERROR(__FUNCTION__ 
-		      "(), to high value for slot timeout!\n");
-		sysctl_slot_timeout = 160;
-	}
-	
+	/* sysctl_slot_timeout bounds are checked in irsysctl.c - Jean II */
 	self->slot_timeout = sysctl_slot_timeout * HZ / 1000;
 	
 	irlap_do_event(self, DISCOVERY_REQUEST, NULL, &info);
@@ -931,9 +921,6 @@
 	/* Set data size */
 	/*self->qos_rx.data_size.bits &= 0x03;*/
 
-	/* Set disconnect time -> done properly in qos.c */
-	/*self->qos_rx.link_disc_time.bits &= 0x07;*/
-
 	irda_qos_bits_to_value(&self->qos_rx);
 }
 
@@ -1070,8 +1057,11 @@
 	/*
 	 *  Set N1 to 0 if Link Disconnect/Threshold Time = 3 and set it to 
 	 *  3 seconds otherwise. See page 71 in IrLAP for more details.
+	 *  Actually, it's not always 3 seconds, as we allow to set
+	 *  it via sysctl... Max maxtt is 500ms, and N1 need to be multiple
+	 *  of 2, so 1 second is minimum we can allow. - Jean II
 	 */
-	if (self->qos_tx.link_disc_time.value == 3)
+	if (self->qos_tx.link_disc_time.value == sysctl_warn_noreply_time)
 		/* 
 		 * If we set N1 to 0, it will trigger immediately, which is
 		 * not what we want. What we really want is to disable it,
@@ -1079,7 +1069,8 @@
 		 */
 		self->N1 = -2; /* Disable - Need to be multiple of 2*/
 	else
-		self->N1 = 3000 / self->qos_rx.max_turn_time.value;
+		self->N1 = sysctl_warn_noreply_time * 1000 /
+		  self->qos_rx.max_turn_time.value;
 	
 	IRDA_DEBUG(4, "Setting N1 = %d\n", self->N1);
 	
diff -Nur --exclude=*~ linux-2.4.16/net/irda/irlap_event.c linux/net/irda/irlap_event.c
--- linux-2.4.16/net/irda/irlap_event.c	Mon Nov 26 08:35:01 2001
+++ linux/net/irda/irlap_event.c	Fri Nov 30 18:28:16 2001
@@ -1405,30 +1405,29 @@
 		}
 		self->add_wait = FALSE;
 
-		if ((self->retry_count < self->N2) && 
-		    (self->retry_count != self->N1)) {
-			
+		/* N2 is the disconnect timer. Until we reach it, we retry */
+		if (self->retry_count < self->N2) {
+			/* Retry sending the pf bit to the secondary */
 			irlap_wait_min_turn_around(self, &self->qos_tx);
 			irlap_send_rr_frame(self, CMD_FRAME);
 			
 			irlap_start_final_timer(self, self->final_timeout);
 		 	self->retry_count++;
-
 			IRDA_DEBUG(4, "irlap_state_nrm_p: FINAL_TIMER_EXPIRED:"
 				   " retry_count=%d\n", self->retry_count);
-			/* Keep state */
-		} else if (self->retry_count == self->N1) {
-			irlap_status_indication(self, STATUS_NO_ACTIVITY);
-			irlap_wait_min_turn_around(self, &self->qos_tx);
-			irlap_send_rr_frame(self, CMD_FRAME);
-			
-			irlap_start_final_timer(self, self->final_timeout);
-			self->retry_count++;
 
-			IRDA_DEBUG(4, "retry count = N1; retry_count=%d\n", 
-				   self->retry_count);
+			/* Early warning event. I'm using a pretty liberal
+			 * interpretation of the spec and generate an event
+			 * every time the timer is multiple of N1 (and not
+			 * only the first time). This allow application
+			 * to know precisely if connectivity restart...
+			 * Jean II */
+			if((self->retry_count % self->N1) == 0)
+				irlap_status_indication(self,
+							STATUS_NO_ACTIVITY);
+
 			/* Keep state */
-		} else if (self->retry_count >= self->N2) {
+		} else {
 			irlap_apply_default_connection_parameters(self);
 
 			/* Always switch state before calling upper layers */
@@ -1991,6 +1990,7 @@
 		 *  Wait until retry_count * n matches negotiated threshold/
 		 *  disconnect time (note 2 in IrLAP p. 82)
 		 *
+		 * Similar to irlap_state_nrm_p() -> FINAL_TIMER_EXPIRED
 		 * Note : self->wd_timeout = (self->final_timeout * 2),
 		 *   which explain why we use (self->N2 / 2) here !!!
 		 * Jean II
@@ -1998,16 +1998,15 @@
 		IRDA_DEBUG(1, __FUNCTION__ "(), retry_count = %d\n", 
 			   self->retry_count);
 
-		if ((self->retry_count <  (self->N2 / 2))  && 
-		    (self->retry_count != (self->N1 / 2))) {
-			
+		if (self->retry_count < (self->N2 / 2)) {
+			/* No retry, just wait for primary */
 			irlap_start_wd_timer(self, self->wd_timeout);
 			self->retry_count++;
-		} else if (self->retry_count == (self->N1 / 2)) {
-			irlap_status_indication(self, STATUS_NO_ACTIVITY);
-			irlap_start_wd_timer(self, self->wd_timeout);
-			self->retry_count++;
-		} else if (self->retry_count >= (self->N2 / 2)) {
+
+			if((self->retry_count % (self->N1 / 2)) == 0)
+				irlap_status_indication(self,
+							STATUS_NO_ACTIVITY);
+		} else {
 			irlap_apply_default_connection_parameters(self);
 			
 			/* Always switch state before calling upper layers */
diff -Nur --exclude=*~ linux-2.4.16/net/irda/irlmp.c linux/net/irda/irlmp.c
--- linux-2.4.16/net/irda/irlmp.c	Mon Nov 26 08:35:01 2001
+++ linux/net/irda/irlmp.c	Fri Nov 30 18:28:17 2001
@@ -469,7 +469,12 @@
 
 	IRDA_DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", 
 		   self->slsap_sel, self->dlsap_sel);
-	
+
+	/* Note : self->lap is set in irlmp_link_data_indication(),
+	 * (case CONNECT_CMD:) because we have no way to set it here.
+	 * Similarly, self->dlsap_sel is usually set in irlmp_find_lsap().
+	 * Jean II */
+
 	self->qos = *self->lap->qos;
 
 	max_seg_size = self->lap->qos->data_size.value-LMP_HEADER;
@@ -577,7 +582,9 @@
 	/* Dup */
 	memcpy(new, orig, sizeof(struct lsap_cb));
 	new->notify.instance = instance;
-	
+	/* new->lap = orig->lap; => done in the memcpy() */
+	/* new->slsap_sel = orig->slsap_sel; => done in the memcpy() */
+
 	init_timer(&new->watchdog_timer);
 	
 	hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) new, (int) new, 
diff -Nur --exclude=*~ linux-2.4.16/net/irda/irlmp_event.c linux/net/irda/irlmp_event.c
--- linux-2.4.16/net/irda/irlmp_event.c	Mon Nov 26 08:35:01 2001
+++ linux/net/irda/irlmp_event.c	Fri Nov 30 18:28:16 2001
@@ -407,12 +407,7 @@
 		 *  removed later and moved to the list of unconnected LSAPs
 		 */
 		if (HASHBIN_GET_SIZE(self->lsaps) > 0) {
-			/* Make sure the timer has sensible value (the user
-			 * may have set it) - Jean II */
-			if(sysctl_lap_keepalive_time < 100)	/* 100ms */
-				sysctl_lap_keepalive_time = 100;
-			if(sysctl_lap_keepalive_time > 10000)	/* 10s */
-				sysctl_lap_keepalive_time = 10000;
+			/* Timer value is checked in irsysctl - Jean II */
 			irlmp_start_idle_timer(self, sysctl_lap_keepalive_time * HZ / 1000);
 		} else {
 			/* No more connections, so close IrLAP */
diff -Nur --exclude=*~ linux-2.4.16/net/irda/irnet/irnet.h linux/net/irda/irnet/irnet.h
--- linux-2.4.16/net/irda/irnet/irnet.h	Mon Nov 26 08:35:01 2001
+++ linux/net/irda/irnet/irnet.h	Fri Nov 30 19:07:33 2001
@@ -199,6 +199,13 @@
  *	o Avoid leaking discovery log and skb
  *	o Replace "self" with "server" in irnet_connect_indication() to
  *	  better detect cut'n'paste error ;-)
+ *
+ * v9 - 29.11.01 - Jean II
+ *	o Fix event generation in disconnect indication that I broke in v8
+ *	  It was always generation "No-Answer" because I was testing ttp_open
+ *	  just after clearing it. *blush*.
+ *	o Use newly created irttp_listen() to fix potential crash when LAP
+ *	  destroyed before irnet module removed.
  */
 
 /***************************** INCLUDES *****************************/
diff -Nur --exclude=*~ linux-2.4.16/net/irda/irnet/irnet_irda.c linux/net/irda/irnet/irnet_irda.c
--- linux-2.4.16/net/irda/irnet/irnet_irda.c	Mon Nov 26 08:35:01 2001
+++ linux/net/irda/irnet/irnet_irda.c	Fri Nov 30 18:28:17 2001
@@ -830,8 +830,7 @@
 #endif /* STREAM_COMPAT */
 
   /* Clean up the original one to keep it in listen state */
-  server->tsap->dtsap_sel = server->tsap->lsap->dlsap_sel = LSAP_ANY;
-  server->tsap->lsap->lsap_state = LSAP_DISCONNECTED;
+  irttp_listen(server->tsap);
 
   /* Send a connection response on the new socket */
   irttp_connect_response(new->tsap, new->max_sdu_size_rx, NULL);
@@ -897,8 +896,7 @@
 		   self->saddr, self->daddr, self->rname);
 
   /* Clean up the server to keep it in listen state */
-  self->tsap->dtsap_sel = self->tsap->lsap->dlsap_sel = LSAP_ANY;
-  self->tsap->lsap->lsap_state = LSAP_DISCONNECTED;
+  irttp_listen(self->tsap);
 
   DEXIT(IRDA_SERV_TRACE, "\n");
   return;
@@ -1081,7 +1079,8 @@
 			    struct sk_buff *skb)
 {
   irnet_socket *	self = (irnet_socket *) instance;
-  int			test = 0;
+  int			test_open;
+  int			test_connect;
 
   DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
   DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n");
@@ -1091,23 +1090,23 @@
     dev_kfree_skb(skb);
 
   /* Prevent higher layer from accessing IrTTP */
-  test = test_and_clear_bit(0, &self->ttp_open);
+  test_open = test_and_clear_bit(0, &self->ttp_open);
   /* Not connecting anymore...
    * (note : TSAP is open, so IAP callbacks are no longer pending...) */
-  test |= test_and_clear_bit(0, &self->ttp_connect);
+  test_connect = test_and_clear_bit(0, &self->ttp_connect);
 
   /* If both self->ttp_open and self->ttp_connect are NULL, it mean that we
    * have a race condition with irda_irnet_destroy() or
    * irnet_connect_indication(), so don't mess up tsap...
    */
-  if(!test)
+  if(!(test_open || test_connect))
     {
       DERROR(IRDA_CB_ERROR, "Race condition detected...\n");
       return;
     }
 
   /* If we were active, notify the control channel */
-  if(test_bit(0, &self->ttp_open))
+  if(test_open)
     irnet_post_event(self, IRNET_DISCONNECT_FROM,
 		     self->saddr, self->daddr, self->rname);
   else
diff -Nur --exclude=*~ linux-2.4.16/net/irda/irsysctl.c linux/net/irda/irsysctl.c
--- linux-2.4.16/net/irda/irsysctl.c	Mon Nov 26 08:35:01 2001
+++ linux/net/irda/irsysctl.c	Fri Nov 30 18:28:16 2001
@@ -10,6 +10,7 @@
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1997, 1999 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -32,24 +33,47 @@
 #include <net/irda/irias_object.h>
 
 #define NET_IRDA 412 /* Random number */
-enum { DISCOVERY=1, DEVNAME, DEBUG, SLOTS, DISCOVERY_TIMEOUT, 
-       SLOT_TIMEOUT, MAX_BAUD_RATE, MAX_INACTIVE_TIME, LAP_KEEPALIVE_TIME, };
+enum { DISCOVERY=1, DEVNAME, DEBUG, FAST_POLL, DISCOVERY_SLOTS,
+       DISCOVERY_TIMEOUT, SLOT_TIMEOUT, MAX_BAUD_RATE, MIN_TX_TURN_TIME,
+       MAX_NOREPLY_TIME, WARN_NOREPLY_TIME, LAP_KEEPALIVE_TIME };
 
 extern int  sysctl_discovery;
 extern int  sysctl_discovery_slots;
 extern int  sysctl_discovery_timeout;
-extern int  sysctl_slot_timeout;
+extern int  sysctl_slot_timeout;	/* Candidate */
 extern int  sysctl_fast_poll_increase;
 int         sysctl_compression = 0;
 extern char sysctl_devname[];
 extern int  sysctl_max_baud_rate;
-extern int  sysctl_max_inactive_time;
+extern int  sysctl_min_tx_turn_time;
+extern int  sysctl_max_noreply_time;
+extern int  sysctl_warn_noreply_time;
 extern int  sysctl_lap_keepalive_time;
 
 #ifdef CONFIG_IRDA_DEBUG
 extern unsigned int irda_debug;
 #endif
 
+/* this is needed for the proc_dointvec_minmax - Jean II */
+static int max_discovery_slots = 16;		/* ??? */
+static int min_discovery_slots = 1;
+/* IrLAP 6.13.2 says 25ms to 10+70ms - allow higher since some devices
+ * seems to require it. (from Dag's comment) */
+static int max_slot_timeout = 160;
+static int min_slot_timeout = 20;
+static int max_max_baud_rate = 16000000;	/* See qos.c - IrLAP spec */
+static int min_max_baud_rate = 2400;
+static int max_min_tx_turn_time = 10000;	/* See qos.c - IrLAP spec */
+static int min_min_tx_turn_time = 0;
+static int max_max_noreply_time = 40;		/* See qos.c - IrLAP spec */
+static int min_max_noreply_time = 3;
+static int max_warn_noreply_time = 3;		/* 3s == standard */
+static int min_warn_noreply_time = 1;		/* 1s == min WD_TIMER */
+static int max_lap_keepalive_time = 10000;	/* 10s */
+static int min_lap_keepalive_time = 100;	/* 100us */
+/* For other sysctl, I've no idea of the range. Maybe Dag could help
+ * us on that - Jean II */
+
 static int do_devname(ctl_table *table, int write, struct file *filp,
 		      void *buffer, size_t *lenp)
 {
@@ -77,21 +101,32 @@
 	  sizeof(int), 0644, NULL, &proc_dointvec },
 #endif
 #ifdef CONFIG_IRDA_FAST_RR
-        { SLOTS, "fast_poll_increase", &sysctl_fast_poll_increase,
+        { FAST_POLL, "fast_poll_increase", &sysctl_fast_poll_increase,
 	  sizeof(int), 0644, NULL, &proc_dointvec },
 #endif
-	{ SLOTS, "discovery_slots", &sysctl_discovery_slots,
-	  sizeof(int), 0644, NULL, &proc_dointvec },
+	{ DISCOVERY_SLOTS, "discovery_slots", &sysctl_discovery_slots,
+	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
+	  NULL, &min_discovery_slots, &max_discovery_slots },
 	{ DISCOVERY_TIMEOUT, "discovery_timeout", &sysctl_discovery_timeout,
 	  sizeof(int), 0644, NULL, &proc_dointvec },
 	{ SLOT_TIMEOUT, "slot_timeout", &sysctl_slot_timeout,
-	  sizeof(int), 0644, NULL, &proc_dointvec },
+	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
+	  NULL, &min_slot_timeout, &max_slot_timeout },
 	{ MAX_BAUD_RATE, "max_baud_rate", &sysctl_max_baud_rate,
-	  sizeof(int), 0644, NULL, &proc_dointvec },
-	{ MAX_INACTIVE_TIME, "max_inactive_time", &sysctl_max_inactive_time,
-	  sizeof(int), 0644, NULL, &proc_dointvec },
+	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
+	  NULL, &min_max_baud_rate, &max_max_baud_rate },
+	{ MIN_TX_TURN_TIME, "min_tx_turn_time", &sysctl_min_tx_turn_time,
+	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
+	  NULL, &min_min_tx_turn_time, &max_min_tx_turn_time },
+	{ MAX_NOREPLY_TIME, "max_noreply_time", &sysctl_max_noreply_time,
+	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
+	  NULL, &min_max_noreply_time, &max_max_noreply_time },
+	{ WARN_NOREPLY_TIME, "warn_noreply_time", &sysctl_warn_noreply_time,
+	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
+	  NULL, &min_warn_noreply_time, &max_warn_noreply_time },
 	{ LAP_KEEPALIVE_TIME, "lap_keepalive_time", &sysctl_lap_keepalive_time,
-	  sizeof(int), 0644, NULL, &proc_dointvec },
+	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
+	  NULL, &min_lap_keepalive_time, &max_lap_keepalive_time },
 	{ 0 }
 };
 
diff -Nur --exclude=*~ linux-2.4.16/net/irda/qos.c linux/net/irda/qos.c
--- linux-2.4.16/net/irda/qos.c	Mon Nov 26 08:35:01 2001
+++ linux/net/irda/qos.c	Fri Nov 30 18:28:16 2001
@@ -51,7 +51,16 @@
  * may want to keep the LAP alive longuer or shorter in case of link failure.
  * Remember that the threshold time (early warning) is fixed to 3s...
  */
-int sysctl_max_inactive_time = 12;
+int sysctl_max_noreply_time = 12;
+/*
+ * Minimum turn time to be applied before transmitting to the peer.
+ * Nonzero values (usec) are used as lower limit to the per-connection
+ * mtt value which was announced by the other end during negotiation.
+ * Might be helpful if the peer device provides too short mtt.
+ * Default is 10 which means using the unmodified value given by the peer
+ * except if it's 0 (0 is likely a bug in the other stack).
+ */
+unsigned sysctl_min_tx_turn_time = 10;
 
 static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get);
 static int irlap_param_link_disconnect(void *instance, irda_param_t *parm, 
@@ -184,7 +193,6 @@
  * Function value_lower_bits (value, array)
  *
  *    Returns a bit field marking all possibility lower than value.
- *    We may need a "value_higher_bits" in the future...
  */
 static inline int value_lower_bits(__u32 value, __u32 *array, int size, __u16 *field)
 {
@@ -207,6 +215,33 @@
 	return i;
 }
 
+/*
+ * Function value_highest_bit (value, array)
+ *
+ *    Returns a bit field marking the highest possibility lower than value.
+ */
+static inline int value_highest_bit(__u32 value, __u32 *array, int size, __u16 *field)
+{
+	int	i;
+	__u16	mask = 0x1;
+	__u16	result = 0x0;
+
+	for (i=0; i < size; i++) {
+		/* Finished ? */
+		if (array[i] <= value)
+			break;
+		/* Shift mask */
+		mask <<= 1;
+	}
+	/* Set the current value to the bit field */
+	result |= mask;
+	/* Send back a valid index */
+	if(i >= size)
+	  i = size - 1;	/* Last item */
+	*field = result;
+	return i;
+}
+
 /* -------------------------- MAIN CALLS -------------------------- */
 
 /*
@@ -254,9 +289,9 @@
 	sysctl_max_baud_rate = index_value(i, baud_rates);
 
 	/* Set configured max disc time */
-	i = value_lower_bits(sysctl_max_inactive_time, link_disc_times, 8,
+	i = value_lower_bits(sysctl_max_noreply_time, link_disc_times, 8,
 			     &qos->link_disc_time.bits);
-	sysctl_max_inactive_time = index_value(i, link_disc_times);
+	sysctl_max_noreply_time = index_value(i, link_disc_times);
 
 	/* LSB is first byte, MSB is second byte */
 	qos->baud_rate.bits    &= 0x03ff;
@@ -281,6 +316,19 @@
 	int index;
 
 	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	/*
+	 * Make sure the mintt is sensible.
+	 */
+	if (sysctl_min_tx_turn_time > qos->min_turn_time.value) {
+		int i;
+
+		/* We don't really need bits, but easier this way */
+		i = value_highest_bit(sysctl_min_tx_turn_time, min_turn_times,
+				      8, &qos->min_turn_time.bits);
+		sysctl_min_tx_turn_time = index_value(i, min_turn_times);
+		qos->min_turn_time.value = sysctl_min_tx_turn_time;
+	}
 
 	/* 
 	 * Not allowed to use a max turn time less than 500 ms if the baudrate
diff -Nur --exclude=*~ linux-2.4.16/net/packet/af_packet.c linux/net/packet/af_packet.c
--- linux-2.4.16/net/packet/af_packet.c	Mon Nov 26 08:35:01 2001
+++ linux/net/packet/af_packet.c	Wed Nov 28 18:15:57 2001
@@ -1902,3 +1902,4 @@
 
 module_init(packet_init);
 module_exit(packet_exit);
+MODULE_LICENSE("GPL");
