diff -u --recursive --new-file v2.5.1/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.5.1/linux/Documentation/Configure.help	Tue Dec 18 14:56:33 2001
+++ linux/Documentation/Configure.help	Thu Jan  3 13:21:28 2002
@@ -12541,6 +12541,30 @@
   If you have an MGE Ellipse UPS, or you see timeouts in HID
   transactions, say Y; otherwise say N.
 
+EHCI (USB 2.0) support
+CONFIG_USB_EHCI_HCD
+  The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
+  "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware.
+  If your USB host controller supports USB 2.0, you will likely want to
+  configure this Host Controller Driver.  At this writing, the primary
+  implementation of EHCI is a chip from NEC, widely available in add-on
+  PCI cards, but implementations are in the works from other vendors
+  including Intel and Philips.  Motherboard support is appearing.
+
+  EHCI controllers are packaged with "companion" host controllers (OHCI
+  or UHCI) to handle USB 1.1 devices connected to root hub ports.  Ports
+  will connect to EHCI if it the device is high speed, otherwise they
+  connect to a companion controller.  If you configure EHCI, you should
+  probably configure the OHCI (for NEC and some other vendors) USB Host
+  Controller Driver too.
+
+  You may want to read <file:Documentation/usb/ehci.txt>.
+
+  This code 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 ehci-hcd.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
 UHCI (Intel PIIX4, VIA, ...) support
 CONFIG_USB_UHCI
   The Universal Host Controller Interface is a standard by Intel for
@@ -12841,6 +12865,17 @@
   The module will be called visor.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
+USB Compaq iPAQ Driver
+CONFIG_USB_SERIAL_IPAQ
+  Say Y here if you want to connect to your Compaq iPAQ running
+  Windows CE 3.0 using a USB autosync cable. For information on using
+  the driver, read <file:Documentation/usb/usb-serial.txt>.
+
+  This code 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 ipaq.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
 USB IR Dongle Serial Driver
 CONFIG_USB_SERIAL_IR
   Say Y here if you want to enable simple serial support for USB IrDA
@@ -13061,6 +13096,22 @@
   The module will be called io_edgeport.o.  If you want to compile it
   as a module, say M here and read <file:Documentation/modules.txt>.
 
+USB PalmConnect (and other KL5KUSB105-based) Single Port Serial Driver
+CONFIG_USB_SERIAL_KLSI
+  Say Y here if you want to use a KL5KUSB105 - based single port
+  serial adapter. The most widely known -- and currently the only
+  tested -- device in this category is the PalmConnect USB Serial
+  adapter sold by Palm Inc. for use with their Palm III and Palm V
+  series PDAs.
+
+  Please read <file:Documentation/usb/usb-serial.txt> for more
+  information.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called kl5kusb105.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
 USB Serial Converter verbose debug
 CONFIG_USB_SERIAL_DEBUG
   Say Y here if you want verbose debug messages from the USB Serial
@@ -13167,6 +13218,54 @@
   The module will be called pwc.o.  If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
+USB SE401 Camera support
+CONFIG_USB_SE401
+  Say Y here if you want to connect this type of camera to your
+  computer's USB port. See <file:Documentation/usb/se401.txt> for more
+  information and for a list of supported cameras.
+
+  This driver uses the Video For Linux API. You must say Y or M to
+  "Video For Linux" (under Multimedia Devices) to use this driver.
+  Information on this API and pointers to "v4l" programs may be found
+  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code 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 se401.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+USB STV680 (Pencam) Camera support
+CONFIG_USB_STV680
+  Say Y here if you want to connect this type of camera to your
+  computer's USB port. This includes the Pencam line of cameras.
+  See <file:Documentation/usb/stv680.txt> for more information and for
+  a list of supported cameras.
+
+  This driver uses the Video For Linux API. You must say Y or M to
+  "Video For Linux" (under Multimedia Devices) to use this driver.
+  Information on this API and pointers to "v4l" programs may be found
+  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code 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 stv680.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+Vicam
+CONFIG_USB_VICAM
+  Say Y here if you have 3com homeconnect camera (vicam).
+
+  This driver uses the Video For Linux API. You must say Y or M to
+  "Video For Linux" (under Multimedia Devices) to use this driver.
+  Information on this API and pointers to "v4l" programs may be found
+  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code 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 vicam.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+
 Pegasus/Pegasus II based USB-Ethernet device support
 CONFIG_USB_PEGASUS
   Say Y here if you know you have Pegasus or Pegasus II based adapter.
@@ -16960,22 +17059,6 @@
   Note that, even if you say N here, Linux on the x86 architecture
   will issue the hlt instruction if nothing is to be done, thereby
   sending the processor to sleep and saving power.
-
-USB SE401 Camera support
-CONFIG_USB_SE401
-  Say Y here if you want to connect this type of camera to your
-  computer's USB port. See <file:Documentation/usb/se401.txt> for more
-  information and for a list of supported cameras.
-
-  This driver uses the Video For Linux API. You must say Y or M to
-  "Video For Linux" (under Multimedia Devices) to use this driver.
-  Information on this API and pointers to "v4l" programs may be found
-  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  This code 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 se401.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
 
 ACPI support
 CONFIG_ACPI
diff -u --recursive --new-file v2.5.1/linux/Documentation/DocBook/kernel-hacking.tmpl linux/Documentation/DocBook/kernel-hacking.tmpl
--- v2.5.1/linux/Documentation/DocBook/kernel-hacking.tmpl	Fri Oct  5 12:06:51 2001
+++ linux/Documentation/DocBook/kernel-hacking.tmpl	Thu Dec 20 08:54:23 2001
@@ -18,8 +18,8 @@
   </authorgroup>
 
   <copyright>
-   <year>2000</year>
-   <holder>Paul Russell</holder>
+   <year>2001</year>
+   <holder>Rusty Russell</holder>
   </copyright>
 
   <legalnotice>
@@ -651,6 +651,29 @@
    </para> 
   </sect1>
  
+  <sect1 id="routines-endian">
+   <title><function>cpu_to_be32()</function>/<function>be32_to_cpu()</function>/<function>cpu_to_le32()</function>/<function>le32_to_cpu()</function>
+     <filename class=headerfile>include/asm/byteorder.h</filename> 
+   </title>
+
+   <para>
+    The <function>cpu_to_be32()</function> family (where the "32" can
+    be replaced by 64 or 16, and the "be" can be replaced by "le") are
+    the general way to do endian conversions in the kernel: they
+    return the converted value.  All variations supply the reverse as
+    well: <function>be32_to_cpu()</function>, etc.
+   </para>
+
+   <para>
+    There are two major variations of these functions: the pointer
+    variation, such as <function>cpu_to_be32p()</function>, which take
+    a pointer to the given type, and return the converted value.  The
+    other variation is the "in-situ" family, such as
+    <function>cpu_to_be32s()</function>, which convert value referred
+    to by the pointer, and return void.
+   </para> 
+  </sect1>
+
   <sect1 id="routines-local-irqs">
    <title><function>local_irq_save()</function>/<function>local_irq_restore()</function>
     <filename class=headerfile>include/asm/system.h</filename>
diff -u --recursive --new-file v2.5.1/linux/Documentation/filesystems/devfs/ChangeLog linux/Documentation/filesystems/devfs/ChangeLog
--- v2.5.1/linux/Documentation/filesystems/devfs/ChangeLog	Tue Dec 18 14:56:34 2001
+++ linux/Documentation/filesystems/devfs/ChangeLog	Thu Dec 27 08:29:14 2001
@@ -1794,3 +1794,72 @@
 - 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
+===============================================================================
+Changes for patch v200
+
+- Ported to kernel 2.5.1-pre2
+===============================================================================
+Changes for patch v201
+
+- Fixed bug in <devfsd_read>: was dereferencing freed pointer
+===============================================================================
+Changes for patch v202
+
+- Fixed bug in <devfsd_close>: was dereferencing freed pointer
+
+- Added process group check for devfsd privileges
+===============================================================================
+Changes for patch v203
+
+- Use SLAB_ATOMIC in <devfsd_notify_de> from <devfs_d_delete>
+===============================================================================
+Changes for patch v204
+
+- Removed long obsolete rc.devfs
+
+- Return old entry in <devfs_mk_dir> for 2.4.x kernels
+
+- Updated README from master HTML file
+
+- Increment refcount on module in <check_disc_changed>
+
+- Created <devfs_get_handle> and exported <devfs_put>
+
+- Increment refcount on module in <devfs_get_ops>
+
+- Created <devfs_put_ops> and used where needed to fix races
+
+- Added clarifying comments in response to preliminary EMC code review
+
+- Added poisoning to <devfs_put>
+
+- Improved debugging messages
+
+- Fixed unregister bugs in drivers/md/lvm-fs.c
+===============================================================================
+Changes for patch v205
+
+- Corrected (made useful) debugging message in <unregister>
+
+- Moved <kmem_cache_create> in <mount_devfs_fs> to <init_devfs_fs>
+
+- Fixed drivers/md/lvm-fs.c to create "lvm" entry
+
+- Added magic number to guard against scribbling drivers
+
+- Only return old entry in <devfs_mk_dir> if a directory
+
+- Defined macros for error and debug messages
+
+- Updated README from master HTML file
diff -u --recursive --new-file v2.5.1/linux/Documentation/filesystems/devfs/README linux/Documentation/filesystems/devfs/README
--- v2.5.1/linux/Documentation/filesystems/devfs/README	Tue Dec 18 14:56:34 2001
+++ linux/Documentation/filesystems/devfs/README	Thu Dec 27 08:29:14 2001
@@ -3,7 +3,7 @@
 
 Linux Devfs (Device File System) FAQ
 Richard Gooch
-9-NOV-2001
+21-DEC-2001
 
 -----------------------------------------------------------------------------
 
@@ -66,6 +66,9 @@
 
 Making things work
 Alternatives to devfs
+What I don't like about devfs
+How to report bugs
+Strange kernel messages
 
 
 Other resources
@@ -557,8 +560,10 @@
 
 Devfsd
 OK, if you're reading this, I assume you want to play with
-devfs. First you need to compile devfsd, the device management daemon,
-available at 
+devfs. First you should ensure that /usr/src/linux contains a
+recent kernel source tree. Then you need to compile devfsd, the device
+management daemon, available at
+
 http://www.atnf.csiro.au/~rgooch/linux/.
 Because the kernel has a naming scheme
 which is quite different from the old naming scheme, you need to
@@ -1470,6 +1475,8 @@
 Making things work
 Alternatives to devfs
 What I don't like about devfs
+How to report bugs
+Strange kernel messages
 
 
 
@@ -1733,6 +1740,93 @@
 
 This is not even remotely true. As shown above,
 both code and data size are quite modest.
+
+
+How to report bugs
+
+If you have (or think you have) a bug with devfs, please follow the
+steps below:
+
+
+
+please make sure you have the latest devfs patches applied. The
+latest kernel version might not have the latest devfs patches applied
+yet (Linus is very busy)
+
+
+save a copy of your complete kernel logs (preferably by
+using the dmesg programme) for later inclusion in your bug
+report. You may need to use the -s switch to increase the
+internal buffer size so you can capture all the boot messages
+
+
+try booting with devfs=dall passed to the kernel boot
+command line (read the documentation on your bootloader on how to do
+this), and save the result to a file. This may be quite verbose, and
+it may overflow the messages buffer, but try to get as much of it as
+you can
+
+
+if you get an Oops, run ksymoops to decode it so that the
+names of the offending functions are provided. A non-decoded Oops is
+pretty useless
+
+
+send a copy of your devfsd configuration file(s)
+
+send the bug report to me first.
+Don't expect that I will see it if you post it to the linux-kernel
+mailing list. Include all the information listed above, plus
+anything else that you think might be relevant. Put the string
+devfs somewhere in the subject line, so my mail filters mark
+it as urgent
+
+
+
+
+Here is a general guide on how to ask questions in a way that greatly
+improves your chances of getting a reply:
+
+http://www.tuxedo.org/~esr/faqs/smart-questions.html. If you have
+a bug to report, you should also read
+
+http://www.chiark.greenend.org.uk/~sgtatham/bugs.html.
+
+
+Strange kernel messages
+
+You may see devfs-related messages in your kernel logs. Below are some
+messages and what they mean (and what you should do about them, if
+anything).
+
+
+
+devfs_register(fred): could not append to parent, err: -17
+
+You need to check what the error code means, but usually 17 means
+EEXIST. This means that a driver attempted to create an entry
+fred in a directory, but there already was an entry with that
+name. This is often caused by flawed boot scripts which untar a bunch
+of inodes into /dev, as a way to restore permissions. This
+message is harmless, as the device nodes will still
+provide access to the driver (unless you use the devfs=only
+boot option, which is only for dedicated souls:-). If you want to get
+rid of these annoying messages, upgrade to devfsd-v1.3.20 and use the
+recommended RESTORE directive to restore permissions.
+
+
+devfs_mk_dir(bill): using old entry in dir: c1808724 ""
+
+This is similar to the message above, except that a driver attempted
+to create a directory named bill, and the parent directory
+has an entry with the same name. In this case, to ensure that drivers
+continue to work properly, the old entry is re-used and given to the
+driver. In 2.5 kernels, the driver is given a NULL entry, and thus,
+under rare circumstances, may not create the require device nodes.
+The solution is the same as above.
+
+
+
 
 -----------------------------------------------------------------------------
 
diff -u --recursive --new-file v2.5.1/linux/Documentation/filesystems/devfs/rc.devfs linux/Documentation/filesystems/devfs/rc.devfs
--- v2.5.1/linux/Documentation/filesystems/devfs/rc.devfs	Wed Feb 16 15:42:05 2000
+++ linux/Documentation/filesystems/devfs/rc.devfs	Wed Dec 31 16:00:00 1969
@@ -1,104 +0,0 @@
-#! /bin/sh
-#
-#  /etc/rc.d/rc.devfs
-#
-#  Linux Boot Scripts by  Richard Gooch <rgooch@atnf.csiro.au>
-#  Copyright 1993-1999 under GNU Copyleft version 2.0. See /etc/rc for
-#  copyright notice.
-#
-#  Save and restore devfs ownerships and permissions
-#
-#	Written by	Richard Gooch   11-JAN-1998
-#
-#	Updated by	Richard Gooch	23-JAN-1998: Added "start" and "stop".
-#
-#	Updated by	Richard Gooch	5-AUG-1998: Robustness improvements by
-# Roderich Schupp.
-#
-#	Updated by	Richard Gooch	9-AUG-1998: Took account of change from
-# ".epoch" to ".devfsd".
-#
-#	Updated by	Richard Gooch	19-AUG-1998: Test and tty pattern patch
-# by Roderich Schupp.
-#
-#	Updated by	Richard Gooch	24-MAY-1999: Use sed instead of tr.
-#
-#	Last updated by	Richard Gooch	25-MAY-1999: Don't save /dev/log.
-#
-#
-# Usage:  rc.devfs save|restore [savedir] [devfsdir]
-#
-# Note: "start" is a synonym for "restore" and "stop" is a synonym for "save".
-
-# Set VERBOSE to "no" if you would like a more quiet operation.
-VERBOSE=yes
-
-# Set TAROPTS to "v" or even "vv" to see which files get saved/restored.
-TAROPTS=
-
-option="$1"
-
-case "$option" in
-    save|restore) ;;
-    start)  option=restore ;;
-    stop)   option=save ;;
-    *)      echo "No save or restore option given" ; exit 1 ;;
-esac
-
-if [ "$2" = "" ]; then
-    savedir=/var/state
-else
-    savedir=$2
-fi
-
-if [ ! -d $savedir ]; then
-    echo "Directory: $savedir does not exist"
-    exit 1
-fi
-
-if [ "$3" = "" ]; then
-    if [ -d /devfs ]; then
-	devfs=/devfs
-    else
-	devfs=/dev
-    fi
-else
-    devfs=$3
-fi
-
-grep devfs /proc/filesystems >/dev/null || exit 0
-
-if [ ! -d $devfs ]; then
-    echo "Directory: $devfs does not exist"
-    exit 1
-elif [ ! -c $devfs/.devfsd ]; then
-    echo "Directory: $devfs is not the root of a devfs filesystem"
-    exit 1
-fi
-
-savefile=`echo $devfs | sed 's*/*_*g'`
-tarfile=${savedir}/devfssave.${savefile}.tar.gz
-
-cd $devfs
-
-case "$option" in
-    save)
-	[ "$VERBOSE" != no ] && echo "Saving $devfs permissions..."
-	
-	# You might want to adjust the pattern below to control
-	# which file's permissions will be saved.
-	# The sample pattern exludes all virtual consoles
-	# as well as old and new style pseudo terminals.
-	files=`find * -noleaf -cnewer .devfsd \
-	       ! -regex 'tty[0-9]+\|vc/.*\|vcsa?[0-9]+\|vcc/.*\|[pt]ty[a-z][0-9a-f]\|pt[ms]/.*\|log' -print`
-	rm -f $tarfile
-	[ -n "$files" ] && tar cz${TAROPTS}f $tarfile $files
-	;;
-
-    restore)
-	[ "$VERBOSE" != no ] && echo "Restoring $devfs permissions..."
-	[ -f $tarfile ] && tar xpz${TAROPTS}f $tarfile
-	;;
-esac
-
-exit 0
diff -u --recursive --new-file v2.5.1/linux/Documentation/usb/ehci.txt linux/Documentation/usb/ehci.txt
--- v2.5.1/linux/Documentation/usb/ehci.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/usb/ehci.txt	Thu Jan  3 13:21:28 2002
@@ -0,0 +1,164 @@
+18-Dec-2001
+
+The EHCI driver is used to talk to high speed USB 2.0 devices using
+USB 2.0-capable host controller hardware.  The USB 2.0 standard is
+compatible with the USB 1.1 standard. It defines three transfer speeds:
+
+    - "High Speed" 480 Mbit/sec (60 MByte/sec)
+    - "Full Speed" 12 Mbit/sec (1.5 MByte/sec)
+    - "Low Speed" 1.5 Mbit/sec
+
+USB 1.1 only addressed full speed and low speed.  High speed devices
+can be used on USB 1.1 systems, but they slow down to USB 1.1 speeds. 
+
+USB 1.1 devices may also be used on USB 2.0 systems.  When plugged
+into an EHCI controller, they are given to a USB 1.1 "companion"
+controller, which is a OHCI or UHCI controller as normally used with
+such devices.  When USB 1.1 devices plug into USB 2.0 hubs, they
+interact with the EHCI controller through a "Transaction Translator"
+(TT) in the hub, which turns low or full speed transactions into
+high speed "split transactions" that don't waste transfer bandwidth.
+
+At this writing, high speed devices are finally beginning to appear.
+While usb-storage devices have been available for some time (working
+quite speedily on the 2.4 version of this driver), hubs have only
+very recently become available.
+
+Note that USB 2.0 support involves more than just EHCI.  It requires
+other changes to the Linux-USB core APIs, including the hub driver,
+but those changes haven't needed to really change the basic "usbcore"
+APIs exposed to USB device drivers.
+
+- David Brownell
+  <dbrownell@users.sourceforge.net>
+
+
+FUNCTIONALITY
+
+This driver is regularly tested on x86 hardware, and has also been
+used on PPC hardware so big/little endianneess issues should be gone.
+It's believed to do all the right PCI magic so that I/O works even on
+systems with interesting DMA mapping issues.
+
+At this writing the driver should comfortably handle all control and bulk
+transfers, including requests to USB 1.1 devices through transaction
+translators (TTs) in USB 2.0 hubs.  However, there some situations where
+the hub driver needs to clear TT error state, which it doesn't yet do.
+
+Interrupt transfer support is newly functional and not yet as robust as
+control and bulk traffic.  As yet there is no support for split transaction
+scheduling for interrupt transfers, which means among other things that
+connecting USB 1.1 hubs, keyboards, and mice to USB 2.0 hubs won't work.
+Connect them to USB 1.1 hubs, or to a root hub.
+
+Isochronous (ISO) transfer support is not yet working.  No production
+high speed devices are available which would need it (though high quality
+webcams are in the works!).  Note that split transaction support for ISO
+transfers can't share much code with the code for high speed ISO transfers,
+since EHCI represents these with a different data structure.
+
+The EHCI root hub code should hand off USB 1.1 devices to its companion
+controller.  This driver doesn't need to know anything about those
+drivers; a OHCI or UHCI driver that works already doesn't need to change
+just because the EHCI driver is also present.
+
+There are some issues with power management; suspend/resume doesn't
+behave quite right at the moment.
+
+
+USE BY
+
+Assuming you have an EHCI controller (on a PCI card or motherboard)
+and have compiled this driver as a module, load this like:
+
+    # modprobe ehci-hcd
+
+and remove it by:
+
+    # rmmod ehci-hcd
+
+You should also have a driver for a "companion controller", such as
+"ohci-hcd", "usb-ohci", "usb-uhci", or "uhci".  In case of any trouble
+with the EHCI driver, remove its module and then the driver for that
+companion controller will take over (at lower speed) all the devices
+that were previously handled by the EHCI driver.
+
+Module parameters (pass to "modprobe") include:
+
+    log2_irq_thresh (default 0):
+	Log2 of default interrupt delay, in microframes.  The default
+	value is 0, indicating 1 microframe (125 usec).  Maximum value
+	is 6, indicating 2^6 = 64 microframes.  This controls how often
+	the EHCI controller can issue interrupts.
+
+The EHCI interrupt handler just acknowledges interrupts and schedules
+a tasklet to handle whatever needs handling.  That keeps latencies low,
+no matter how often interrupts are issued.
+
+Device drivers shouldn't care whether they're running over EHCI or not,
+but they may want to check for "usb_device->speed == USB_SPEED_HIGH".
+High speed devices can do things that full speed (or low speed) ones
+can't, such as "high bandwidth" periodic (interrupt or ISO) transfers.
+
+
+PERFORMANCE
+
+USB 2.0 throughput is gated by two main factors:  how fast the host
+controller can process requests, and how fast devices can respond to
+them.  The 480 Mbit/sec "raw transfer rate" is obeyed by all devices,
+but aggregate throughput is also affected by issues like delays between
+individual high speed packets, driver intelligence, and of course the
+overall system load.  Latency is also a performance concern.
+
+Bulk transfers are most often used where throughput is an issue.  It's
+good to keep in mind that bulk transfers are always in 512 byte packets,
+and at most 13 of those fit into one USB 2.0 microframe.  Eight USB 2.0
+microframes fit in a USB 1.1 frame; a microframe is 1 msec/8 = 125 usec.
+
+Hardware Performance
+
+At this writing, individual USB 2.0 devices tend to max out at around
+20 MByte/sec transfer rates.  This is of course subject to change;
+and some devices now go faster, while others go slower.
+
+The NEC implementation of EHCI seems to have a hardware bottleneck
+at around 28 MByte/sec aggregate transfer rate.  While this is clearly
+enough for a single device at 20 MByte/sec, putting three such devices
+onto one bus does not get you 60 MByte/sec.  The issue appears to be
+that the controller hardware won't do concurrent USB and PCI access,
+so that it's only trying six (or maybe seven) USB transactions each
+microframe rather than thirteen.  (Seems like a reasonable trade off
+for a product that beat all the others to market by over a year!)
+It's expected that newer implementations will better this, throwing
+more silicon real estate at the problem so that new motherboard chip
+sets will get closer to that 60 MByte/sec target.
+
+There's a minimum latency of one microframe (125 usec) for the host
+to receive interrupts from the EHCI controller indicating completion
+of requests.  That latency is tunable; there's a module option.  By
+default ehci-hcd driver uses the minimum latency, which means that if
+you issue a control or bulk request you can often expect to learn that
+it completed in less than 250 usec (depending on transfer size).
+
+Software Performance
+
+To get even 20 MByte/sec transfer rates, Linux-USB device drivers will
+need to keep the EHCI queue full.  That means issuing large requests,
+or using bulk queuing if a series of small requests needs to be issued.
+When drivers don't do that, their performance results will show it.
+
+In typical situations, a usb_bulk_msg() loop writing out 4 KB chunks is
+going to waste more than half the USB 2.0 bandwidth.  Delays between the
+I/O completion and the driver issuing the next request will take longer
+than the I/O.  If that same loop used 16 KB chunks, it'd be better; a
+sequence of 128 KB chunks would waste a lot less.
+
+But rather than depending on such large I/O buffers to make synchronous
+I/O be efficient, it's better to just queue all several (bulk) requests
+to the HC, and wait for them all to complete (or be canceled on error).
+Such URB queuing should work with all the USB 1.1 HC drivers too.
+
+TBD:  Interrupt and ISO transfer performance issues.  Those periodic
+transfers are fully scheduled, so the main issue is likely to be how
+to trigger "high bandwidth" modes.
+
diff -u --recursive --new-file v2.5.1/linux/Documentation/usb/stv680.txt linux/Documentation/usb/stv680.txt
--- v2.5.1/linux/Documentation/usb/stv680.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/usb/stv680.txt	Thu Jan  3 13:21:28 2002
@@ -0,0 +1,55 @@
+Linux driver for STV0680 based USB cameras
+
+Copyright, 2001, Kevin Sisson
+
+
+INTRODUCTION:
+
+STMicroelectronics produces the STV0680B chip, which comes in two 
+types, -001 and -003. The -003 version allows the recording and downloading 
+of sound clips from the camera, and allows a flash attachment. Otherwise, 
+it uses the same commands as the -001 version. Both versions support a 
+variety of SDRAM sizes and sensors, allowing for a maximum of 26 VGA or 20 
+CIF pictures. The STV0680 supports either a serial or a usb interface, and 
+video is possible through the usb interface.
+
+The following cameras are known to work with this driver, although any 
+camera with Vendor/Product codes of 0553/0202 should work:
+
+Aiptek Pencam (various models)
+Nisis QuickPix 2
+Radio Shack 'Kid's digital camera' (#60-1207)
+At least one Trust Spycam model
+Several other European brand models
+
+WHAT YOU NEED:
+
+-	USB support
+-	VIDEO4LINUX support
+
+More information about USB support for linux can be found at:
+http://www.linux-usb.org
+
+
+MODULE OPTIONS:
+
+When the driver is compiled as a module, you can set a "swapRGB=1"
+option, if necessary, for those applications that require it 
+(such as xawtv). However, the driver should detect and set this 
+automatically, so this option should not normally be used.
+
+
+KNOWN PROBLEMS:
+
+The driver seems to work better with the usb-ohci than the usb-uhci host 
+controller driver. 
+
+HELP:
+
+The latest info on this driver can be found at:
+http://personal.clt.bellsouth.net/~kjsisson or at
+http://stv0680-usb.sourceforge.net
+
+Any questions to me can be send to:  kjsisson@bellsouth.net
+
+
diff -u --recursive --new-file v2.5.1/linux/Documentation/usb/usb-serial.txt linux/Documentation/usb/usb-serial.txt
--- v2.5.1/linux/Documentation/usb/usb-serial.txt	Mon Nov 12 09:50:39 2001
+++ linux/Documentation/usb/usb-serial.txt	Thu Jan  3 13:21:28 2002
@@ -95,6 +95,66 @@
   Kroah-Hartman at greg@kroah.com
 
 
+Compaq iPAQ driver
+
+  This driver can be used to connect to Compaq iPAQ PDAs running
+  Windows CE 3.0 using a USB autosync cable. It has been tested only on
+  the Compaq H3135. It should work with the H3600 and later models too.
+  It may work with other CE based handhelds as well.
+
+  The driver presents a serial interface (usually on /dev/ttyUSB0) over
+  which one may run ppp and establish a TCP/IP link to the iPAQ. Once this
+  is done, you can transfer files, backup, download email etc. The most
+  significant advantage of using USB is speed - you can get 73 to 113
+  kbytes/sec for download/upload to the iPAQ.
+
+  The driver works intermittently with the usb-uhci driver but quite
+  reliably with the uhci driver. Make sure you have the right driver
+  loaded - usb-uhci is often the default.
+
+  You must setup hotplug to invoke pppd as soon as the iPAQ is connected.
+  A ppp script like the one below may be used:
+
+	#!/bin/bash
+
+	MYIP=linux.box.ip
+	REMOTEIP=ipaq.ip
+	MYDNS=my.dns.server
+	killall -9 pppd
+	/usr/sbin/pppd /dev/ttyUSB0 \
+	connect "/usr/sbin/chat -v TIMEOUT 60 CLIENT 'CLIENTSERVER\c'" \
+	nocrtscts local debug passive $MYIP:$REMOTEIP ms-dns $MYDNS noauth \
+	proxyarp
+
+  You must also download and install asyncd from http://synce.sourceforge.net
+  This is required to emulate keep-alive packets which are exchanged by
+  ActiveSync and the iPAQ.
+
+  On connecting the cable, you should see the usual "Device Connected",
+  "User Authenticated" messages flash by on your iPAQ. Once connected,
+  you can use Win CE programs like ftpView, Pocket Outlook from the iPAQ
+  and other synce utilities from the Linux side. Remember to enable IP
+  forwarding. 
+
+  To use Pocket IE, follow the instructions given at
+  http://www.tekguru.co.uk/EM500/usbtonet.htm to achieve the same thing
+  on Win98. Omit the proxy server part; Linux is quite capable of forwarding
+  packets unlike Win98. Another modification is required at least for the
+  iPAQ - disable autosync by going to the Start/Settings/Connections menu
+  and unchecking the "Automatically synchronize ..." box. Go to
+  Start/Programs/Connections, connect the cable and select "usbdial" (or
+  whatever you named your new USB connection). You should finally wind
+  up with a "Connected to usbdial" window with status shown as connected.
+  Now start up PIE and browse away.
+
+  If it doesn't work for some reason, load both the usbserial and ipaq module
+  with the module parameter "debug" set to 1 and examine the system log.
+  You can also try soft-resetting your iPAQ before attempting a connection.
+
+  For any questions or problems with the driver, please contact Ganesh
+  Varadarajan <ganesh@veritas.com>
+
+
 Keyspan PDA Serial Adapter
 
   Single port DB-9 serial adapter, pushed as a PDA adapter for iMacs (mostly
@@ -301,6 +361,32 @@
   For any questions or problems with this driver, please contact Greg
   Kroah-Hartman at greg@kroah.com
   
+
+KL5KUSB105 chipset / PalmConnect USB single-port adapter
+  
+Current status:
+  The driver was put together by looking at the usb bus transactions
+  done by Palm's driver under Windows, so a lot of functionality is
+  still missing.  Notably, serial ioctls are sometimes faked or not yet
+  implemented.  Support for finding out about DSR and CTS line status is
+  however implemented (though not nicely), so your favorite autopilot(1)
+  and pilot-manager -daemon calls will work.  Baud rates up to 115200
+  are supported, but handshaking (software or hardware) is not, which is
+  why it is wise to cut down on the rate used is wise for large
+  transfers until this is settled.
+  
+Options supported:
+  If this driver is compiled as a module you can pass the following
+  options to it:
+  debug			- extra verbose debugging info
+  			  (default: 0; nonzero enables)
+  use_lowlatency	- use low_latency flag to speed up tty layer
+			  when reading from from the device.
+			  (default: 0; nonzero enables)
+
+  See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
+  information on this driver.
+
 
 Generic Serial driver
 
diff -u --recursive --new-file v2.5.1/linux/MAINTAINERS linux/MAINTAINERS
--- v2.5.1/linux/MAINTAINERS	Tue Dec 18 14:56:34 2001
+++ linux/MAINTAINERS	Thu Dec 27 08:38:57 2001
@@ -843,7 +843,7 @@
 M:	vojtech@suse.cz
 L:	linux-joystick@atrey.karlin.mff.cuni.cz
 W:	http://www.suse.cz/development/joystick/
-S:	Supported
+S:	Maintained
 
 KERNEL AUTOMOUNTER (AUTOFS)
 P:	H. Peter Anvin
@@ -1322,8 +1322,10 @@
 S:	Maintained
 
 SCSI SUBSYSTEM
+P:	Jens Axboe
+M:	axboe@suse.de
 L:	linux-scsi@vger.kernel.org
-S:	Unmaintained
+S:	Maintained
 
 SCSI TAPE DRIVER
 P:	Kai Mäkisara
@@ -1538,7 +1540,7 @@
 M:	vojtech@suse.cz
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
-S:	Supported
+S:	Maintained
 
 USB BLUETOOTH DRIVER
 P:	Greg Kroah-Hartman
@@ -1561,7 +1563,7 @@
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 W:	http://www.suse.cz/development/input/
-S:	Supported
+S:	Maintained
 
 USB HUB
 P:	Johannes Erdfelt
@@ -1612,7 +1614,7 @@
 M:	vojtech@suse.cz
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
-S:	Supported
+S:	Maintained
 
 USB SE401 DRIVER
 P:	Jeroen Vreeken
diff -u --recursive --new-file v2.5.1/linux/Makefile linux/Makefile
--- v2.5.1/linux/Makefile	Tue Dec 18 14:56:34 2001
+++ linux/Makefile	Tue Jan  1 19:11:23 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 1
-EXTRAVERSION =
+SUBLEVEL = 2
+EXTRAVERSION =-pre7
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -u --recursive --new-file v2.5.1/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c
--- v2.5.1/linux/arch/alpha/kernel/alpha_ksyms.c	Tue Dec 18 14:56:34 2001
+++ linux/arch/alpha/kernel/alpha_ksyms.c	Sun Dec 30 10:06:16 2001
@@ -259,3 +259,8 @@
 EXPORT_SYMBOL_NOVERS(memchr);
 
 EXPORT_SYMBOL(get_wchan);
+
+#ifdef CONFIG_ALPHA_IRONGATE
+EXPORT_SYMBOL(irongate_ioremap);
+EXPORT_SYMBOL(irongate_iounmap);
+#endif
diff -u --recursive --new-file v2.5.1/linux/arch/alpha/kernel/pci-noop.c linux/arch/alpha/kernel/pci-noop.c
--- v2.5.1/linux/arch/alpha/kernel/pci-noop.c	Thu Sep 13 15:21:32 2001
+++ linux/arch/alpha/kernel/pci-noop.c	Sun Dec 30 10:06:16 2001
@@ -104,21 +104,21 @@
 }
 /* stubs for the routines in pci_iommu.c */
 void *
-pci_alloc_consistent(struct pci_dev *pdev, long size, dma_addr_t *dma_addrp)
+pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp)
 {
 }
 void
-pci_free_consistent(struct pci_dev *pdev, long size, void *cpu_addr,
+pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu_addr,
 		    dma_addr_t dma_addr)
 {
 }
 dma_addr_t
-pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size,
+pci_map_single(struct pci_dev *pdev, void *cpu_addr, size_t size,
 	       int direction)
 {
 }
 void
-pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size,
+pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
 		 int direction)
 {
 }
diff -u --recursive --new-file v2.5.1/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v2.5.1/linux/arch/alpha/kernel/process.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/alpha/kernel/process.c	Thu Dec 27 08:21:28 2001
@@ -75,7 +75,6 @@
 {
 	/* An endless idle loop with no priority at all.  */
 	current->nice = 20;
-	current->counter = -100;
 
 	while (1) {
 		/* FIXME -- EV6 and LCA45 know how to power down
diff -u --recursive --new-file v2.5.1/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c
--- v2.5.1/linux/arch/alpha/kernel/setup.c	Fri Nov 16 18:38:39 2001
+++ linux/arch/alpha/kernel/setup.c	Tue Dec 25 15:39:20 2001
@@ -440,12 +440,6 @@
         return MKDEV(TTY_MAJOR, 64 + c->index);
 }
 
-static int srm_console_wait_key(struct console *co)
-{
-  /* Huh? */
-	return 1;
-}
-
 static int __init srm_console_setup(struct console *co, char *options)
 {
 	return 1;
@@ -455,7 +449,6 @@
 	name:		"srm0",
 	write:		srm_console_write,
 	device:		srm_console_device,
-	wait_key:	srm_console_wait_key,
 	setup:		srm_console_setup,
 	flags:		CON_PRINTBUFFER | CON_ENABLED, /* fake it out */
 	index:		-1,
diff -u --recursive --new-file v2.5.1/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c
--- v2.5.1/linux/arch/alpha/kernel/smp.c	Wed Nov 21 10:31:09 2001
+++ linux/arch/alpha/kernel/smp.c	Sun Dec 30 10:02:19 2001
@@ -23,6 +23,7 @@
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/irq.h>
+#include <linux/cache.h>
 
 #include <asm/hwrpb.h>
 #include <asm/ptrace.h>
@@ -65,7 +66,7 @@
 	IPI_CPU_STOP,
 };
 
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 /* Set to a secondary's cpuid when it comes online.  */
 static unsigned long smp_secondary_alive;
diff -u --recursive --new-file v2.5.1/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c
--- v2.5.1/linux/arch/arm/kernel/process.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/arm/kernel/process.c	Thu Dec 27 08:21:28 2001
@@ -85,7 +85,6 @@
 	/* endless idle loop with no priority at all */
 	init_idle();
 	current->nice = 20;
-	current->counter = -100;
 
 	while (1) {
 		void (*idle)(void) = pm_idle;
diff -u --recursive --new-file v2.5.1/linux/arch/arm/lib/changebit.S linux/arch/arm/lib/changebit.S
--- v2.5.1/linux/arch/arm/lib/changebit.S	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/lib/changebit.S	Tue Dec 25 21:43:32 2001
@@ -14,7 +14,9 @@
 /* Purpose  : Function to change a bit
  * Prototype: int change_bit(int bit, void *addr)
  */
-ENTRY(change_bit)
+ENTRY(_change_bit_be)
+		eor	r0, r0, #0x18		@ big endian byte ordering
+ENTRY(_change_bit_le)
 		and	r2, r0, #7
 		mov	r3, #1
 		mov	r3, r3, lsl r2
diff -u --recursive --new-file v2.5.1/linux/arch/arm/lib/clearbit.S linux/arch/arm/lib/clearbit.S
--- v2.5.1/linux/arch/arm/lib/clearbit.S	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/lib/clearbit.S	Tue Dec 25 21:43:32 2001
@@ -15,8 +15,9 @@
  * Purpose  : Function to clear a bit
  * Prototype: int clear_bit(int bit, void *addr)
  */
-
-ENTRY(clear_bit)
+ENTRY(_clear_bit_be)
+		eor	r0, r0, #0x18		@ big endian byte ordering
+ENTRY(_clear_bit_le)
 		and	r2, r0, #7
 		mov	r3, #1
 		mov	r3, r3, lsl r2
diff -u --recursive --new-file v2.5.1/linux/arch/arm/lib/findbit.S linux/arch/arm/lib/findbit.S
--- v2.5.1/linux/arch/arm/lib/findbit.S	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/lib/findbit.S	Tue Dec 25 21:43:32 2001
@@ -15,14 +15,14 @@
  * Purpose  : Find a 'zero' bit
  * Prototype: int find_first_zero_bit(void *addr, int maxbit);
  */
-ENTRY(find_first_zero_bit)
+ENTRY(_find_first_zero_bit_le)
 		mov	r2, #0
-.bytelp:	ldrb	r3, [r0, r2, lsr #3]
+1:		ldrb	r3, [r0, r2, lsr #3]
 		eors	r3, r3, #0xff		@ invert bits
 		bne	.found			@ any now set - found zero bit
 		add	r2, r2, #8		@ next bit pointer
 		cmp	r2, r1			@ any more?
-		bcc	.bytelp
+		bcc	1b
 		add	r0, r1, #1		@ no free bits
 		RETINSTR(mov,pc,lr)
 
@@ -30,15 +30,43 @@
  * Purpose  : Find next 'zero' bit
  * Prototype: int find_next_zero_bit(void *addr, int maxbit, int offset)
  */
-ENTRY(find_next_zero_bit)
+ENTRY(_find_next_zero_bit_le)
 		ands	ip, r2, #7
-		beq	.bytelp			@ If new byte, goto old routine
+		beq	1b			@ If new byte, goto old routine
 		ldrb	r3, [r0, r2, lsr#3]
 		eor	r3, r3, #0xff		@ now looking for a 1 bit
 		movs	r3, r3, lsr ip		@ shift off unused bits
+		bne	.found
+		orr	r2, r2, #7		@ if zero, then no bits here
+		add	r2, r2, #1		@ align bit pointer
+		b	1b			@ loop for next bit
+
+#ifdef __ARMEB__
+
+ENTRY(_find_first_zero_bit_be)
+		mov	r2, #0
+1:		eor	r3, r2, #0x18		@ big endian byte ordering
+		ldrb	r3, [r0, r3, lsr #3]
+		eors	r3, r3, #0xff		@ invert bits
+		bne	.found			@ any now set - found zero bit
+		add	r2, r2, #8		@ next bit pointer
+		cmp	r2, r1			@ any more?
+		bcc	1b
+		add	r0, r1, #1		@ no free bits
+		RETINSTR(mov,pc,lr)
+
+ENTRY(_find_next_zero_bit_be)
+		ands	ip, r2, #7
+		beq	1b			@ If new byte, goto old routine
+		eor	r3, r2, #0x18		@ big endian byte ordering
+		ldrb	r3, [r0, r3, lsr#3]
+		eor	r3, r3, #0xff		@ now looking for a 1 bit
+		movs	r3, r3, lsr ip		@ shift off unused bits
 		orreq	r2, r2, #7		@ if zero, then no bits here
 		addeq	r2, r2, #1		@ align bit pointer
-		beq	.bytelp			@ loop for next bit
+		beq	1b			@ loop for next bit
+
+#endif
 
 /*
  * One or more bits in the LSB of r3 are assumed to be set.
diff -u --recursive --new-file v2.5.1/linux/arch/arm/lib/setbit.S linux/arch/arm/lib/setbit.S
--- v2.5.1/linux/arch/arm/lib/setbit.S	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/lib/setbit.S	Tue Dec 25 21:43:32 2001
@@ -9,22 +9,21 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-                .text
+		.text
 
 /*
  * Purpose  : Function to set a bit
  * Prototype: int set_bit(int bit, void *addr)
  */
-
-ENTRY(set_bit)
-                and     r2, r0, #7
-                mov     r3, #1
-                mov     r3, r3, lsl r2
+ENTRY(_set_bit_be)
+		eor	r0, r0, #0x18		@ big endian byte ordering
+ENTRY(_set_bit_le)
+		and	r2, r0, #7
+		mov	r3, #1
+		mov	r3, r3, lsl r2
 		save_and_disable_irqs ip, r2
 		ldrb	r2, [r1, r0, lsr #3]
 		orr	r2, r2, r3
 		strb	r2, [r1, r0, lsr #3]
 		restore_irqs ip
 		RETINSTR(mov,pc,lr)
-
-
diff -u --recursive --new-file v2.5.1/linux/arch/arm/lib/testchangebit.S linux/arch/arm/lib/testchangebit.S
--- v2.5.1/linux/arch/arm/lib/testchangebit.S	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/lib/testchangebit.S	Tue Dec 25 21:43:32 2001
@@ -11,7 +11,9 @@
 #include <asm/assembler.h>
                 .text
 
-ENTRY(test_and_change_bit)
+ENTRY(_test_and_change_bit_be)
+		eor	r0, r0, #0x18		@ big endian byte ordering
+ENTRY(_test_and_change_bit_le)
 		add	r1, r1, r0, lsr #3
 		and	r3, r0, #7
 		mov	r0, #1
diff -u --recursive --new-file v2.5.1/linux/arch/arm/lib/testclearbit.S linux/arch/arm/lib/testclearbit.S
--- v2.5.1/linux/arch/arm/lib/testclearbit.S	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/lib/testclearbit.S	Tue Dec 25 21:43:32 2001
@@ -11,7 +11,9 @@
 #include <asm/assembler.h>
                 .text
 
-ENTRY(test_and_clear_bit)
+ENTRY(_test_and_clear_bit_be)
+		eor	r0, r0, #0x18		@ big endian byte ordering
+ENTRY(_test_and_clear_bit_le)
 		add	r1, r1, r0, lsr #3	@ Get byte offset
 		and	r3, r0, #7		@ Get bit offset
 		mov	r0, #1
diff -u --recursive --new-file v2.5.1/linux/arch/arm/lib/testsetbit.S linux/arch/arm/lib/testsetbit.S
--- v2.5.1/linux/arch/arm/lib/testsetbit.S	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/lib/testsetbit.S	Tue Dec 25 21:43:32 2001
@@ -11,7 +11,9 @@
 #include <asm/assembler.h>
                 .text
 
-ENTRY(test_and_set_bit)
+ENTRY(_test_and_set_bit_be)
+		eor	r0, r0, #0x18		@ big endian byte ordering
+ENTRY(_test_and_set_bit_le)
 		add	r1, r1, r0, lsr #3	@ Get byte offset
 		and	r3, r0, #7		@ Get bit offset
 		mov	r0, #1
diff -u --recursive --new-file v2.5.1/linux/arch/arm/nwfpe/ARM-gcc.h linux/arch/arm/nwfpe/ARM-gcc.h
--- v2.5.1/linux/arch/arm/nwfpe/ARM-gcc.h	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/nwfpe/ARM-gcc.h	Tue Dec 25 21:43:32 2001
@@ -1,11 +1,3 @@
-
-/*
--------------------------------------------------------------------------------
-One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined.
--------------------------------------------------------------------------------
-*/
-#define LITTLEENDIAN
-
 /*
 -------------------------------------------------------------------------------
 The macro `BITS64' can be defined to indicate that 64-bit integer types are
diff -u --recursive --new-file v2.5.1/linux/arch/arm/nwfpe/entry.S linux/arch/arm/nwfpe/entry.S
--- v2.5.1/linux/arch/arm/nwfpe/entry.S	Sun Aug 12 11:13:59 2001
+++ linux/arch/arm/nwfpe/entry.S	Tue Dec 25 21:43:32 2001
@@ -50,11 +50,10 @@
 
 This routine does three things:
 
-1) It saves SP into a variable called userRegisters.  The kernel has
-created a struct pt_regs on the stack and saved the user registers
-into it.  See /usr/include/asm/proc/ptrace.h for details.  The
-emulator code uses userRegisters as the base of an array of words from
-which the contents of the registers can be extracted.
+1) The kernel has created a struct pt_regs on the stack and saved the
+user registers into it.  See /usr/include/asm/proc/ptrace.h for details.
+The emulator code uses userRegisters as the base of an array of words
+from which the contents of the registers can be extracted.
 
 2) It calls EmulateAll to emulate a floating point instruction.
 EmulateAll returns 1 if the emulation was successful, or 0 if not.
@@ -78,16 +77,18 @@
 	   of stealing two regs from the register allocator.  Not sure if
 	   it's worth it.  */
 	str sp, [r10]                   @ Store the user registers pointer in the fpa11 structure.
-        mov r4, sp			@ use r4 for local pointer
-        mov r10, lr			@ save the failure-return addresses
+        mov r4, lr			@ save the failure-return addresses
 
-        ldr r5, [r4, #60]	 	@ get contents of PC;
+	mov r0, r10
+	bl FPA11_CheckInit		@ check to see if we are initialised
+
+        ldr r5, [sp, #60]	 	@ get contents of PC;
 	sub r8, r5, #4
 .Lx2:	ldrt r0, [r8]			@ get actual instruction into r0
 emulate:
 	bl EmulateAll			@ emulate the instruction
    	cmp r0, #0			@ was emulation successful
-        moveq pc, r10			@ no, return failure
+        moveq pc, r4			@ no, return failure
 
 next:
 .Lx1:	ldrt r6, [r5], #4		@ get the next instruction and
@@ -99,10 +100,10 @@
         teqne r2, #0x0E000000
         movne pc, r9			@ return ok if not a fp insn
 
-        str r5, [r4, #60]		@ update PC copy in regs
+        str r5, [sp, #60]		@ update PC copy in regs
 
         mov r0, r6			@ save a copy
-        ldr r1, [r4, #64]		@ fetch the condition codes
+        ldr r1, [sp, #64]		@ fetch the condition codes
    	bl  checkCondition		@ check the condition
    	cmp r0, #0			@ r0 = 0 ==> condition failed
 
diff -u --recursive --new-file v2.5.1/linux/arch/arm/nwfpe/fpa11.c linux/arch/arm/nwfpe/fpa11.c
--- v2.5.1/linux/arch/arm/nwfpe/fpa11.c	Sun Aug 12 11:13:59 2001
+++ linux/arch/arm/nwfpe/fpa11.c	Tue Dec 25 21:43:32 2001
@@ -18,7 +18,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
-
+#include <linux/compiler.h>
 #include <asm/system.h>
 
 #include "fpa11.h"
@@ -123,47 +123,58 @@
   }
 }
 
-/* Emulate the instruction in the opcode. */
-unsigned int EmulateAll(unsigned int opcode)
+void FPA11_CheckInit(FPA11 *fpa11)
 {
-  unsigned int nRc = 0;
-  unsigned long flags;
-  FPA11 *fpa11; 
-  save_flags(flags); sti();
-
-  fpa11 = GET_FPA11();
-
-  if (fpa11->initflag == 0)		/* good place for __builtin_expect */
+  if (unlikely(fpa11->initflag == 0))
   {
     resetFPA11();
     SetRoundingMode(ROUND_TO_NEAREST);
     SetRoundingPrecision(ROUND_EXTENDED);
     fpa11->initflag = 1;
   }
+}
 
-  if (TEST_OPCODE(opcode,MASK_CPRT))
-  {
-    /* Emulate conversion opcodes. */
-    /* Emulate register transfer opcodes. */
-    /* Emulate comparison opcodes. */
-    nRc = EmulateCPRT(opcode);
-  }
-  else if (TEST_OPCODE(opcode,MASK_CPDO))
-  {
-    /* Emulate monadic arithmetic opcodes. */
-    /* Emulate dyadic arithmetic opcodes. */
-    nRc = EmulateCPDO(opcode);
-  }
-  else if (TEST_OPCODE(opcode,MASK_CPDT))
-  {
-    /* Emulate load/store opcodes. */
-    /* Emulate load/store multiple opcodes. */
-    nRc = EmulateCPDT(opcode);
-  }
-  else
+/* Emulate the instruction in the opcode. */
+unsigned int EmulateAll(unsigned int opcode)
+{
+  unsigned int nRc = 1, code;
+  unsigned long flags;
+  FPA11 *fpa11;
+
+  save_flags(flags); sti();
+
+  code = opcode & 0x00000f00;
+  if (code == 0x00000100 || code == 0x00000200)
   {
-    /* Invalid instruction detected.  Return FALSE. */
-    nRc = 0;
+    /* For coprocessor 1 or 2 (FPA11) */
+    code = opcode & 0x0e000000;
+    if (code == 0x0e000000)
+    {
+      if (opcode & 0x00000010)
+      {
+        /* Emulate conversion opcodes. */
+        /* Emulate register transfer opcodes. */
+        /* Emulate comparison opcodes. */
+        nRc = EmulateCPRT(opcode);
+      }
+      else
+      {
+        /* Emulate monadic arithmetic opcodes. */
+        /* Emulate dyadic arithmetic opcodes. */
+        nRc = EmulateCPDO(opcode);
+      }
+    }
+    else if (code == 0x0c000000)
+    {
+      /* Emulate load/store opcodes. */
+      /* Emulate load/store multiple opcodes. */
+      nRc = EmulateCPDT(opcode);
+    }
+    else
+    {
+      /* Invalid instruction detected.  Return FALSE. */
+      nRc = 0;
+    }
   }
 
   restore_flags(flags);
diff -u --recursive --new-file v2.5.1/linux/arch/arm/nwfpe/fpa11_cpdt.c linux/arch/arm/nwfpe/fpa11_cpdt.c
--- v2.5.1/linux/arch/arm/nwfpe/fpa11_cpdt.c	Sun Aug 12 11:13:59 2001
+++ linux/arch/arm/nwfpe/fpa11_cpdt.c	Tue Dec 25 21:43:32 2001
@@ -45,7 +45,7 @@
    fpa11->fType[Fn] = typeDouble;
    get_user(p[0], &pMem[1]);
    get_user(p[1], &pMem[0]); /* sign & exponent */
-}   
+}
 
 static inline
 void loadExtended(const unsigned int Fn,const unsigned int *pMem)
@@ -57,7 +57,7 @@
    get_user(p[0], &pMem[0]);  /* sign & exponent */
    get_user(p[1], &pMem[2]);  /* ls bits */
    get_user(p[2], &pMem[1]);  /* ms bits */
-}   
+}
 
 static inline
 void loadMultiple(const unsigned int Fn,const unsigned int *pMem)
@@ -69,7 +69,7 @@
    p = (unsigned int*)&(fpa11->fpreg[Fn]);
    get_user(x, &pMem[0]);
    fpa11->fType[Fn] = (x >> 14) & 0x00000003;
-   
+
    switch (fpa11->fType[Fn])
    {
       case typeSingle:
@@ -79,13 +79,13 @@
          get_user(p[1], &pMem[1]);  /* double msw */
          p[2] = 0;        /* empty */
       }
-      break; 
-   
+      break;
+
       case typeExtended:
       {
          get_user(p[1], &pMem[2]);
          get_user(p[2], &pMem[1]);  /* msw */
-         p[0] = (x & 0x80003fff);      
+         p[0] = (x & 0x80003fff);
       }
       break;
    }
@@ -95,82 +95,92 @@
 void storeSingle(const unsigned int Fn,unsigned int *pMem)
 {
    FPA11 *fpa11 = GET_FPA11();
-   float32 val;
-   register unsigned int *p = (unsigned int*)&val;
-   
+   union
+   {
+     float32 f;
+     unsigned int i[1];
+   } val;
+
    switch (fpa11->fType[Fn])
    {
-      case typeDouble: 
-         val = float64_to_float32(fpa11->fpreg[Fn].fDouble);
+      case typeDouble:
+         val.f = float64_to_float32(fpa11->fpreg[Fn].fDouble);
       break;
 
-      case typeExtended: 
-         val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended);
+      case typeExtended:
+         val.f = floatx80_to_float32(fpa11->fpreg[Fn].fExtended);
       break;
 
-      default: val = fpa11->fpreg[Fn].fSingle;
+      default: val.f = fpa11->fpreg[Fn].fSingle;
    }
-  
-   put_user(p[0], pMem);
-}   
+
+   put_user(val.i[0], pMem);
+}
 
 static inline
 void storeDouble(const unsigned int Fn,unsigned int *pMem)
 {
    FPA11 *fpa11 = GET_FPA11();
-   float64 val;
-   register unsigned int *p = (unsigned int*)&val;
+   union
+   {
+     float64 f;
+     unsigned int i[2];
+   } val;
 
    switch (fpa11->fType[Fn])
    {
-      case typeSingle: 
-         val = float32_to_float64(fpa11->fpreg[Fn].fSingle);
+      case typeSingle:
+         val.f = float32_to_float64(fpa11->fpreg[Fn].fSingle);
       break;
 
       case typeExtended:
-         val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended);
+         val.f = floatx80_to_float64(fpa11->fpreg[Fn].fExtended);
       break;
 
-      default: val = fpa11->fpreg[Fn].fDouble;
+      default: val.f = fpa11->fpreg[Fn].fDouble;
    }
-   put_user(p[1], &pMem[0]);	/* msw */
-   put_user(p[0], &pMem[1]);	/* lsw */
-}   
+
+   put_user(val.i[1], &pMem[0]);	/* msw */
+   put_user(val.i[0], &pMem[1]);	/* lsw */
+}
 
 static inline
 void storeExtended(const unsigned int Fn,unsigned int *pMem)
 {
    FPA11 *fpa11 = GET_FPA11();
-   floatx80 val;
-   register unsigned int *p = (unsigned int*)&val;
-   
+   union
+   {
+     floatx80 f;
+     unsigned int i[3];
+   } val;
+
    switch (fpa11->fType[Fn])
    {
-      case typeSingle: 
-         val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
+      case typeSingle:
+         val.f = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
       break;
 
-      case typeDouble: 
-         val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
+      case typeDouble:
+         val.f = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
       break;
 
-      default: val = fpa11->fpreg[Fn].fExtended;
+      default: val.f = fpa11->fpreg[Fn].fExtended;
    }
-   
-   put_user(p[0], &pMem[0]); /* sign & exp */
-   put_user(p[1], &pMem[2]);
-   put_user(p[2], &pMem[1]); /* msw */
-}   
+
+   put_user(val.i[0], &pMem[0]); /* sign & exp */
+   put_user(val.i[1], &pMem[2]);
+   put_user(val.i[2], &pMem[1]); /* msw */
+}
 
 static inline
 void storeMultiple(const unsigned int Fn,unsigned int *pMem)
 {
    FPA11 *fpa11 = GET_FPA11();
    register unsigned int nType, *p;
-   
+
    p = (unsigned int*)&(fpa11->fpreg[Fn]);
    nType = fpa11->fType[Fn];
-   
+
    switch (nType)
    {
       case typeSingle:
@@ -180,8 +190,8 @@
 	 put_user(p[1], &pMem[1]); /* double msw */
 	 put_user(nType << 14, &pMem[0]);
       }
-      break; 
-   
+      break;
+
       case typeExtended:
       {
 	 put_user(p[2], &pMem[1]); /* msw */
@@ -221,7 +231,7 @@
       case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break;
       default: nRc = 0;
    }
-   
+
    if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
    return nRc;
 }
@@ -230,10 +240,10 @@
 {
    unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
      write_back = WRITE_BACK(opcode);
-   
+
    //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
    SetRoundingMode(ROUND_TO_NEAREST);
-   
+
    pBase = (unsigned int*)readRegister(getRn(opcode));
    if (REG_PC == getRn(opcode))
    {
@@ -256,7 +266,7 @@
       case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break;
       default: nRc = 0;
    }
-   
+
    if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
    return nRc;
 }
@@ -297,14 +307,14 @@
 {
    unsigned int i, Fd, *pBase, *pAddress, *pFinal,
      write_back = WRITE_BACK(opcode);
-   
+
    pBase = (unsigned int*)readRegister(getRn(opcode));
    if (REG_PC == getRn(opcode))
    {
      pBase += 2;
      write_back = 0;
    }
-   
+
    pFinal = pBase;
    if (BIT_UP_SET(opcode))
      pFinal += getOffset(opcode);
@@ -331,7 +341,7 @@
   unsigned int nRc = 0;
 
   //printk("EmulateCPDT(0x%08x)\n",opcode);
-  
+
   if (LDF_OP(opcode))
   {
     nRc = PerformLDF(opcode);
@@ -343,7 +353,7 @@
   else if (STF_OP(opcode))
   {
     nRc = PerformSTF(opcode);
-  } 
+  }
   else if (SFM_OP(opcode))
   {
     nRc = PerformSFM(opcode);
@@ -352,7 +362,7 @@
   {
     nRc = 0;
   }
-  
+
   return nRc;
 }
 #endif
diff -u --recursive --new-file v2.5.1/linux/arch/cris/drivers/usb-host.c linux/arch/cris/drivers/usb-host.c
--- v2.5.1/linux/arch/cris/drivers/usb-host.c	Mon Oct  8 11:43:54 2001
+++ linux/arch/cris/drivers/usb-host.c	Tue Jan  1 13:52:10 2002
@@ -196,7 +196,7 @@
 static kmem_cache_t *usb_desc_cache;
 static struct usb_bus *etrax_usb_bus;
 
-static void dump_urb (purb_t purb);
+static void dump_urb (struct urb *urb);
 static void init_rx_buffers(void);
 static int etrax_rh_unlink_urb (urb_t *urb);
 static void etrax_rh_send_irq(urb_t *urb);
@@ -240,24 +240,24 @@
 };
 
 #ifdef USB_DEBUG_DESC
-static void dump_urb(purb_t purb)
+static void dump_urb(struct urb *urb)
 {
-	printk("\nurb                   :0x%08X\n", purb);
-	printk("next                  :0x%08X\n", purb->next);
-	printk("dev                   :0x%08X\n", purb->dev);
-	printk("pipe                  :0x%08X\n", purb->pipe);
-	printk("status                :%d\n", purb->status);
-	printk("transfer_flags        :0x%08X\n", purb->transfer_flags);
-	printk("transfer_buffer       :0x%08X\n", purb->transfer_buffer);
-	printk("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
-	printk("actual_length         :%d\n", purb->actual_length);
-	printk("setup_packet          :0x%08X\n", purb->setup_packet);
-	printk("start_frame           :%d\n", purb->start_frame);
-	printk("number_of_packets     :%d\n", purb->number_of_packets);
-	printk("interval              :%d\n", purb->interval);
-	printk("error_count           :%d\n", purb->error_count);
-	printk("context               :0x%08X\n", purb->context);
-	printk("complete              :0x%08X\n\n", purb->complete);
+	printk("\nurb                   :0x%08X\n", urb);
+	printk("next                  :0x%08X\n", urb->next);
+	printk("dev                   :0x%08X\n", urb->dev);
+	printk("pipe                  :0x%08X\n", urb->pipe);
+	printk("status                :%d\n", urb->status);
+	printk("transfer_flags        :0x%08X\n", urb->transfer_flags);
+	printk("transfer_buffer       :0x%08X\n", urb->transfer_buffer);
+	printk("transfer_buffer_length:%d\n", urb->transfer_buffer_length);
+	printk("actual_length         :%d\n", urb->actual_length);
+	printk("setup_packet          :0x%08X\n", urb->setup_packet);
+	printk("start_frame           :%d\n", urb->start_frame);
+	printk("number_of_packets     :%d\n", urb->number_of_packets);
+	printk("interval              :%d\n", urb->interval);
+	printk("error_count           :%d\n", urb->error_count);
+	printk("context               :0x%08X\n", urb->context);
+	printk("complete              :0x%08X\n\n", urb->complete);
 }
 
 static void dump_in_desc(USB_IN_Desc_t *in)
diff -u --recursive --new-file v2.5.1/linux/arch/cris/kernel/process.c linux/arch/cris/kernel/process.c
--- v2.5.1/linux/arch/cris/kernel/process.c	Fri Nov  9 13:58:02 2001
+++ linux/arch/cris/kernel/process.c	Thu Dec 27 08:21:28 2001
@@ -119,7 +119,6 @@
 int cpu_idle(void *unused)
 {
 	while(1) {
-		current->counter = -100;
 		schedule();
 	}
 }
diff -u --recursive --new-file v2.5.1/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.5.1/linux/arch/i386/config.in	Mon Nov 12 11:58:08 2001
+++ linux/arch/i386/config.in	Sun Dec 30 10:38:45 2001
@@ -52,6 +52,7 @@
    define_int  CONFIG_X86_L1_CACHE_SHIFT 4
    define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
    define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+   define_bool CONFIG_X86_PPRO_FENCE y
 else
    define_bool CONFIG_X86_WP_WORKS_OK y
    define_bool CONFIG_X86_INVLPG y
@@ -66,17 +67,20 @@
    define_int  CONFIG_X86_L1_CACHE_SHIFT 4
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
+   define_bool CONFIG_X86_PPRO_FENCE y
 fi
 if [ "$CONFIG_M586" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
+   define_bool CONFIG_X86_PPRO_FENCE y
 fi
 if [ "$CONFIG_M586TSC" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_TSC y
+   define_bool CONFIG_X86_PPRO_FENCE y
 fi
 if [ "$CONFIG_M586MMX" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
@@ -84,6 +88,7 @@
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
+   define_bool CONFIG_X86_PPRO_FENCE y
 fi
 if [ "$CONFIG_M686" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
@@ -91,6 +96,7 @@
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_PGE y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+   define_bool CONFIG_X86_PPRO_FENCE y
 fi
 if [ "$CONFIG_MPENTIUMIII" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
@@ -135,21 +141,24 @@
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+   define_bool CONFIG_X86_OOSTORE y
 fi
 if [ "$CONFIG_MWINCHIP2" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+   define_bool CONFIG_X86_OOSTORE y
 fi
 if [ "$CONFIG_MWINCHIP3D" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+   define_bool CONFIG_X86_OOSTORE 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 -u --recursive --new-file v2.5.1/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.5.1/linux/arch/i386/defconfig	Tue Dec 18 14:56:34 2001
+++ linux/arch/i386/defconfig	Tue Jan  1 13:59:48 2002
@@ -409,6 +409,7 @@
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
+# CONFIG_DE2104X is not set
 # CONFIG_TULIP is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
@@ -624,7 +625,7 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
diff -u --recursive --new-file v2.5.1/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile
--- v2.5.1/linux/arch/i386/kernel/Makefile	Fri Nov  9 14:21:21 2001
+++ linux/arch/i386/kernel/Makefile	Sun Dec 30 16:51:48 2001
@@ -39,6 +39,9 @@
 obj-$(CONFIG_SMP)		+= smp.o smpboot.o trampoline.o
 obj-$(CONFIG_X86_LOCAL_APIC)	+= mpparse.o apic.o nmi.o
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o acpitable.o
+ifdef CONFIG_VISWS
+obj-y += setup-visws.o
 obj-$(CONFIG_X86_VISWS_APIC)	+= visws_apic.o
+endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.5.1/linux/arch/i386/kernel/apic.c linux/arch/i386/kernel/apic.c
--- v2.5.1/linux/arch/i386/kernel/apic.c	Fri Nov  9 14:12:55 2001
+++ linux/arch/i386/kernel/apic.c	Tue Dec 25 17:04:40 2001
@@ -56,6 +56,14 @@
 	maxlvt = get_maxlvt();
 
 	/*
+	 * Masking an LVT entry on a P6 can trigger a local APIC error
+	 * if the vector is zero. Mask LVTERR first to prevent this.
+	 */
+	if (maxlvt >= 3) {
+		v = ERROR_APIC_VECTOR; /* any non-zero vector will do */
+		apic_write_around(APIC_LVTERR, v | APIC_LVT_MASKED);
+	}
+	/*
 	 * Careful: we have to set masks only first to deassert
 	 * any level-triggered sources.
 	 */
@@ -65,10 +73,6 @@
 	apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
 	v = apic_read(APIC_LVT1);
 	apic_write_around(APIC_LVT1, v | APIC_LVT_MASKED);
-	if (maxlvt >= 3) {
-		v = apic_read(APIC_LVTERR);
-		apic_write_around(APIC_LVTERR, v | APIC_LVT_MASKED);
-	}
 	if (maxlvt >= 4) {
 		v = apic_read(APIC_LVTPC);
 		apic_write_around(APIC_LVTPC, v | APIC_LVT_MASKED);
@@ -84,6 +88,8 @@
 		apic_write_around(APIC_LVTERR, APIC_LVT_MASKED);
 	if (maxlvt >= 4)
 		apic_write_around(APIC_LVTPC, APIC_LVT_MASKED);
+	apic_write(APIC_ESR, 0);
+	v = apic_read(APIC_ESR);
 }
 
 void __init connect_bsp_APIC(void)
@@ -480,6 +486,7 @@
 	l &= ~MSR_IA32_APICBASE_BASE;
 	l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
 	wrmsr(MSR_IA32_APICBASE, l, h);
+	apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED);
 	apic_write(APIC_ID, apic_pm_state.apic_id);
 	apic_write(APIC_DFR, apic_pm_state.apic_dfr);
 	apic_write(APIC_LDR, apic_pm_state.apic_ldr);
@@ -487,15 +494,15 @@
 	apic_write(APIC_SPIV, apic_pm_state.apic_spiv);
 	apic_write(APIC_LVT0, apic_pm_state.apic_lvt0);
 	apic_write(APIC_LVT1, apic_pm_state.apic_lvt1);
+	apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc);
+	apic_write(APIC_LVTT, apic_pm_state.apic_lvtt);
+	apic_write(APIC_TDCR, apic_pm_state.apic_tdcr);
+	apic_write(APIC_TMICT, apic_pm_state.apic_tmict);
 	apic_write(APIC_ESR, 0);
 	apic_read(APIC_ESR);
 	apic_write(APIC_LVTERR, apic_pm_state.apic_lvterr);
 	apic_write(APIC_ESR, 0);
 	apic_read(APIC_ESR);
-	apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc);
-	apic_write(APIC_LVTT, apic_pm_state.apic_lvtt);
-	apic_write(APIC_TDCR, apic_pm_state.apic_tdcr);
-	apic_write(APIC_TMICT, apic_pm_state.apic_tmict);
 	__restore_flags(flags);
 	if (apic_pm_state.perfctr_pmdev)
 		pm_send(apic_pm_state.perfctr_pmdev, PM_RESUME, data);
diff -u --recursive --new-file v2.5.1/linux/arch/i386/kernel/cpuid.c linux/arch/i386/kernel/cpuid.c
--- v2.5.1/linux/arch/i386/kernel/cpuid.c	Thu Oct 11 09:04:57 2001
+++ linux/arch/i386/kernel/cpuid.c	Thu Jan  3 12:20:00 2002
@@ -101,7 +101,7 @@
   u32 data[4];
   size_t rv;
   u32 reg = *ppos;
-  int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+  int cpu = minor(file->f_dentry->d_inode->i_rdev);
   
   if ( count % 16 )
     return -EINVAL; /* Invalid chunk size */
@@ -119,7 +119,7 @@
 
 static int cpuid_open(struct inode *inode, struct file *file)
 {
-  int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+  int cpu = minor(file->f_dentry->d_inode->i_rdev);
   struct cpuinfo_x86 *c = &(cpu_data)[cpu];
 
   if ( !(cpu_online_map & (1UL << cpu)) )
diff -u --recursive --new-file v2.5.1/linux/arch/i386/kernel/dmi_scan.c linux/arch/i386/kernel/dmi_scan.c
--- v2.5.1/linux/arch/i386/kernel/dmi_scan.c	Tue Dec 18 14:56:34 2001
+++ linux/arch/i386/kernel/dmi_scan.c	Sun Dec 30 09:44:51 2001
@@ -572,6 +572,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 -u --recursive --new-file v2.5.1/linux/arch/i386/kernel/msr.c linux/arch/i386/kernel/msr.c
--- v2.5.1/linux/arch/i386/kernel/msr.c	Thu Oct 11 09:04:57 2001
+++ linux/arch/i386/kernel/msr.c	Thu Jan  3 12:20:00 2002
@@ -181,7 +181,7 @@
   u32 data[2];
   size_t rv;
   u32 reg = *ppos;
-  int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+  int cpu = minor(file->f_dentry->d_inode->i_rdev);
   int err;
 
   if ( count % 8 )
@@ -206,7 +206,7 @@
   u32 data[2];
   size_t rv;
   u32 reg = *ppos;
-  int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+  int cpu = minor(file->f_dentry->d_inode->i_rdev);
   int err;
 
   if ( count % 8 )
@@ -226,7 +226,7 @@
 
 static int msr_open(struct inode *inode, struct file *file)
 {
-  int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+  int cpu = minor(file->f_dentry->d_inode->i_rdev);
   struct cpuinfo_x86 *c = &(cpu_data)[cpu];
   
   if ( !(cpu_online_map & (1UL << cpu)) )
diff -u --recursive --new-file v2.5.1/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c
--- v2.5.1/linux/arch/i386/kernel/pci-pc.c	Tue Dec 18 14:56:34 2001
+++ linux/arch/i386/kernel/pci-pc.c	Sun Dec 30 09:44:51 2001
@@ -30,7 +30,7 @@
  * This interrupt-safe spinlock protects all accesses to PCI
  * configuration space.
  */
-spinlock_t pci_config_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t pci_config_lock = SPIN_LOCK_UNLOCKED;
 
 
 /*
@@ -1109,17 +1109,15 @@
 }
 
 /*
- * Nobody seems to know what this does. Damn.
- *
- * But it does seem to fix some unspecified problem
- * with 'movntq' copies on Athlons.
+ * Addresses issues with problems in the memory write queue timer in
+ * certain VIA Northbridges.  This bugfix is per VIA's specifications.
  *
  * VIA 8363,8622,8361 Northbridges:
  *  - bits  5, 6, 7 at offset 0x55 need to be turned off
  * VIA 8367 (KT266x) Northbridges:
  *  - bits  5, 6, 7 at offset 0x95 need to be turned off
  */
-static void __init pci_fixup_via_athlon_bug(struct pci_dev *d)
+static void __init pci_fixup_via_northbridge_bug(struct pci_dev *d)
 {
 	u8 v;
 	int where = 0x55;
@@ -1131,7 +1129,7 @@
 
         pci_read_config_byte(d, where, &v);
 	if (v & 0xe0) {
-		printk("Trying to stomp on Athlon bug...\n");
+		printk("Disabling broken memory write queue.\n");
 		v &= 0x1f; /* clear bits 5, 6, 7 */
 		pci_write_config_byte(d, where, v);
 	}
@@ -1146,10 +1144,10 @@
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		pci_fixup_latency },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5598,		pci_fixup_latency },
  	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82371AB_3,	pci_fixup_piix4_acpi },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	pci_fixup_via_athlon_bug },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8622,	        pci_fixup_via_athlon_bug },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8361,	        pci_fixup_via_athlon_bug },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8367_0,	pci_fixup_via_athlon_bug },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	pci_fixup_via_northbridge_bug },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8622,	        pci_fixup_via_northbridge_bug },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8361,	        pci_fixup_via_northbridge_bug },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8367_0,	pci_fixup_via_northbridge_bug },
 	{ 0 }
 };
 
diff -u --recursive --new-file v2.5.1/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.5.1/linux/arch/i386/kernel/process.c	Thu Oct  4 18:42:54 2001
+++ linux/arch/i386/kernel/process.c	Thu Dec 27 08:21:28 2001
@@ -125,7 +125,6 @@
 	/* endless idle loop with no priority at all */
 	init_idle();
 	current->nice = 20;
-	current->counter = -100;
 
 	while (1) {
 		void (*idle)(void) = pm_idle;
diff -u --recursive --new-file v2.5.1/linux/arch/i386/kernel/setup-visws.c linux/arch/i386/kernel/setup-visws.c
--- v2.5.1/linux/arch/i386/kernel/setup-visws.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/kernel/setup-visws.c	Sun Dec 30 16:51:48 2001
@@ -0,0 +1,126 @@
+/*
+ *  Unmaintained SGI Visual Workstation support.
+ *  Split out from setup.c by davej@suse.de
+ */
+
+char visws_board_type = -1;
+char visws_board_rev = -1;
+
+#define	PIIX_PM_START		0x0F80
+
+#define	SIO_GPIO_START		0x0FC0
+
+#define	SIO_PM_START		0x0FC8
+
+#define	PMBASE			PIIX_PM_START
+#define	GPIREG0			(PMBASE+0x30)
+#define	GPIREG(x)		(GPIREG0+((x)/8))
+#define	PIIX_GPI_BD_ID1		18
+#define	PIIX_GPI_BD_REG		GPIREG(PIIX_GPI_BD_ID1)
+
+#define	PIIX_GPI_BD_SHIFT	(PIIX_GPI_BD_ID1 % 8)
+
+#define	SIO_INDEX	0x2e
+#define	SIO_DATA	0x2f
+
+#define	SIO_DEV_SEL	0x7
+#define	SIO_DEV_ENB	0x30
+#define	SIO_DEV_MSB	0x60
+#define	SIO_DEV_LSB	0x61
+
+#define	SIO_GP_DEV	0x7
+
+#define	SIO_GP_BASE	SIO_GPIO_START
+#define	SIO_GP_MSB	(SIO_GP_BASE>>8)
+#define	SIO_GP_LSB	(SIO_GP_BASE&0xff)
+
+#define	SIO_GP_DATA1	(SIO_GP_BASE+0)
+
+#define	SIO_PM_DEV	0x8
+
+#define	SIO_PM_BASE	SIO_PM_START
+#define	SIO_PM_MSB	(SIO_PM_BASE>>8)
+#define	SIO_PM_LSB	(SIO_PM_BASE&0xff)
+#define	SIO_PM_INDEX	(SIO_PM_BASE+0)
+#define	SIO_PM_DATA	(SIO_PM_BASE+1)
+
+#define	SIO_PM_FER2	0x1
+
+#define	SIO_PM_GP_EN	0x80
+
+void __init visws_get_board_type_and_rev(void)
+{
+	int raw;
+
+	visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG)
+							 >> PIIX_GPI_BD_SHIFT;
+/*
+ * Get Board rev.
+ * First, we have to initialize the 307 part to allow us access
+ * to the GPIO registers.  Let's map them at 0x0fc0 which is right
+ * after the PIIX4 PM section.
+ */
+	outb_p(SIO_DEV_SEL, SIO_INDEX);
+	outb_p(SIO_GP_DEV, SIO_DATA);	/* Talk to GPIO regs. */
+
+	outb_p(SIO_DEV_MSB, SIO_INDEX);
+	outb_p(SIO_GP_MSB, SIO_DATA);	/* MSB of GPIO base address */
+
+	outb_p(SIO_DEV_LSB, SIO_INDEX);
+	outb_p(SIO_GP_LSB, SIO_DATA);	/* LSB of GPIO base address */
+
+	outb_p(SIO_DEV_ENB, SIO_INDEX);
+	outb_p(1, SIO_DATA);		/* Enable GPIO registers. */
+
+/*
+ * Now, we have to map the power management section to write
+ * a bit which enables access to the GPIO registers.
+ * What lunatic came up with this shit?
+ */
+	outb_p(SIO_DEV_SEL, SIO_INDEX);
+	outb_p(SIO_PM_DEV, SIO_DATA);	/* Talk to GPIO regs. */
+
+	outb_p(SIO_DEV_MSB, SIO_INDEX);
+	outb_p(SIO_PM_MSB, SIO_DATA);	/* MSB of PM base address */
+
+	outb_p(SIO_DEV_LSB, SIO_INDEX);
+	outb_p(SIO_PM_LSB, SIO_DATA);	/* LSB of PM base address */
+
+	outb_p(SIO_DEV_ENB, SIO_INDEX);
+	outb_p(1, SIO_DATA);		/* Enable PM registers. */
+
+/*
+ * Now, write the PM register which enables the GPIO registers.
+ */
+	outb_p(SIO_PM_FER2, SIO_PM_INDEX);
+	outb_p(SIO_PM_GP_EN, SIO_PM_DATA);
+
+/*
+ * Now, initialize the GPIO registers.
+ * We want them all to be inputs which is the
+ * power on default, so let's leave them alone.
+ * So, let's just read the board rev!
+ */
+	raw = inb_p(SIO_GP_DATA1);
+	raw &= 0x7f;	/* 7 bits of valid board revision ID. */
+
+	if (visws_board_type == VISWS_320) {
+		if (raw < 0x6) {
+			visws_board_rev = 4;
+		} else if (raw < 0xc) {
+			visws_board_rev = 5;
+		} else {
+			visws_board_rev = 6;
+		}
+	} else if (visws_board_type == VISWS_540) {
+			visws_board_rev = 2;
+		} else {
+			visws_board_rev = raw;
+		}
+
+		printk(KERN_INFO "Silicon Graphics %s (rev %d)\n",
+			visws_board_type == VISWS_320 ? "320" :
+			(visws_board_type == VISWS_540 ? "540" :
+					"unknown"), visws_board_rev);
+	}
+}
diff -u --recursive --new-file v2.5.1/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.5.1/linux/arch/i386/kernel/setup.c	Tue Dec 18 14:56:34 2001
+++ linux/arch/i386/kernel/setup.c	Sun Dec 30 16:54:29 2001
@@ -158,6 +158,7 @@
 extern int root_mountflags;
 extern char _text, _etext, _edata, _end;
 extern int blk_nohighio;
+void __init visws_get_board_type_and_rev(void);
 
 static int disable_x86_serial_nr __initdata = 1;
 static int disable_x86_fxsr __initdata = 0;
@@ -191,131 +192,6 @@
 #define RAMDISK_PROMPT_FLAG		0x8000
 #define RAMDISK_LOAD_FLAG		0x4000	
 
-#ifdef	CONFIG_VISWS
-char visws_board_type = -1;
-char visws_board_rev = -1;
-
-#define	PIIX_PM_START		0x0F80
-
-#define	SIO_GPIO_START		0x0FC0
-
-#define	SIO_PM_START		0x0FC8
-
-#define	PMBASE			PIIX_PM_START
-#define	GPIREG0			(PMBASE+0x30)
-#define	GPIREG(x)		(GPIREG0+((x)/8))
-#define	PIIX_GPI_BD_ID1		18
-#define	PIIX_GPI_BD_REG		GPIREG(PIIX_GPI_BD_ID1)
-
-#define	PIIX_GPI_BD_SHIFT	(PIIX_GPI_BD_ID1 % 8)
-
-#define	SIO_INDEX	0x2e
-#define	SIO_DATA	0x2f
-
-#define	SIO_DEV_SEL	0x7
-#define	SIO_DEV_ENB	0x30
-#define	SIO_DEV_MSB	0x60
-#define	SIO_DEV_LSB	0x61
-
-#define	SIO_GP_DEV	0x7
-
-#define	SIO_GP_BASE	SIO_GPIO_START
-#define	SIO_GP_MSB	(SIO_GP_BASE>>8)
-#define	SIO_GP_LSB	(SIO_GP_BASE&0xff)
-
-#define	SIO_GP_DATA1	(SIO_GP_BASE+0)
-
-#define	SIO_PM_DEV	0x8
-
-#define	SIO_PM_BASE	SIO_PM_START
-#define	SIO_PM_MSB	(SIO_PM_BASE>>8)
-#define	SIO_PM_LSB	(SIO_PM_BASE&0xff)
-#define	SIO_PM_INDEX	(SIO_PM_BASE+0)
-#define	SIO_PM_DATA	(SIO_PM_BASE+1)
-
-#define	SIO_PM_FER2	0x1
-
-#define	SIO_PM_GP_EN	0x80
-
-static void __init visws_get_board_type_and_rev(void)
-{
-	int raw;
-
-	visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG)
-							 >> PIIX_GPI_BD_SHIFT;
-/*
- * Get Board rev.
- * First, we have to initialize the 307 part to allow us access
- * to the GPIO registers.  Let's map them at 0x0fc0 which is right
- * after the PIIX4 PM section.
- */
-	outb_p(SIO_DEV_SEL, SIO_INDEX);
-	outb_p(SIO_GP_DEV, SIO_DATA);	/* Talk to GPIO regs. */
-    
-	outb_p(SIO_DEV_MSB, SIO_INDEX);
-	outb_p(SIO_GP_MSB, SIO_DATA);	/* MSB of GPIO base address */
-
-	outb_p(SIO_DEV_LSB, SIO_INDEX);
-	outb_p(SIO_GP_LSB, SIO_DATA);	/* LSB of GPIO base address */
-
-	outb_p(SIO_DEV_ENB, SIO_INDEX);
-	outb_p(1, SIO_DATA);		/* Enable GPIO registers. */
-    
-/*
- * Now, we have to map the power management section to write
- * a bit which enables access to the GPIO registers.
- * What lunatic came up with this shit?
- */
-	outb_p(SIO_DEV_SEL, SIO_INDEX);
-	outb_p(SIO_PM_DEV, SIO_DATA);	/* Talk to GPIO regs. */
-
-	outb_p(SIO_DEV_MSB, SIO_INDEX);
-	outb_p(SIO_PM_MSB, SIO_DATA);	/* MSB of PM base address */
-    
-	outb_p(SIO_DEV_LSB, SIO_INDEX);
-	outb_p(SIO_PM_LSB, SIO_DATA);	/* LSB of PM base address */
-
-	outb_p(SIO_DEV_ENB, SIO_INDEX);
-	outb_p(1, SIO_DATA);		/* Enable PM registers. */
-    
-/*
- * Now, write the PM register which enables the GPIO registers.
- */
-	outb_p(SIO_PM_FER2, SIO_PM_INDEX);
-	outb_p(SIO_PM_GP_EN, SIO_PM_DATA);
-    
-/*
- * Now, initialize the GPIO registers.
- * We want them all to be inputs which is the
- * power on default, so let's leave them alone.
- * So, let's just read the board rev!
- */
-	raw = inb_p(SIO_GP_DATA1);
-	raw &= 0x7f;	/* 7 bits of valid board revision ID. */
-
-	if (visws_board_type == VISWS_320) {
-		if (raw < 0x6) {
-			visws_board_rev = 4;
-		} else if (raw < 0xc) {
-			visws_board_rev = 5;
-		} else {
-			visws_board_rev = 6;
-	
-		}
-	} else if (visws_board_type == VISWS_540) {
-			visws_board_rev = 2;
-		} else {
-			visws_board_rev = raw;
-		}
-
-		printk(KERN_INFO "Silicon Graphics %s (rev %d)\n",
-			visws_board_type == VISWS_320 ? "320" :
-			(visws_board_type == VISWS_540 ? "540" :
-					"unknown"),
-					visws_board_rev);
-	}
-#endif
-
 
 static char command_line[COMMAND_LINE_SIZE];
        char saved_command_line[COMMAND_LINE_SIZE];
@@ -1289,9 +1165,24 @@
 			}
 			break;
 
-		case 6:	/* An Athlon/Duron. We can trust the BIOS probably */
-			mcheck_init(c);
-			break;		
+		case 6: /* An Athlon/Duron */
+ 
+			/* Bit 15 of Athlon specific MSR 15, needs to be 0
+ 			 * to enable SSE on Palomino/Morgan CPU's.
+			 * If the BIOS didn't enable it already, enable it
+			 * here.
+			 */
+			if (c->x86_model == 6 || c->x86_model == 7) {
+				if (!test_bit(X86_FEATURE_XMM, &c->x86_capability)) {
+					printk(KERN_INFO "Enabling disabled K7/SSE Support.\n");
+					rdmsr(MSR_K7_HWCR, l, h);
+					l &= ~0x00008000;
+					wrmsr(MSR_K7_HWCR, l, h);
+					set_bit(X86_FEATURE_XMM, &c->x86_capability);
+				}
+			}
+			break;
+
 	}
 
 	display_cacheinfo(c);
@@ -1918,7 +1809,6 @@
 				c->x86_cache_size = (cc>>24)+(dd>>24);
 			}
 			sprintf( c->x86_model_id, "WinChip %s", name );
-			mcheck_init(c);
 			break;
 
 		case 6:
@@ -2202,9 +2092,56 @@
 
 	if ( p )
 		strcpy(c->x86_model_id, p);
+	
+#ifdef CONFIG_SMP
+	if (test_bit(X86_FEATURE_HT, &c->x86_capability)) {
+		extern	int phys_proc_id[NR_CPUS];
+		
+		u32 	eax, ebx, ecx, edx;
+		int 	index_lsb, index_msb, tmp;
+		int	initial_apic_id;
+		int 	cpu = smp_processor_id();
+
+		cpuid(1, &eax, &ebx, &ecx, &edx);
+		smp_num_siblings = (ebx & 0xff0000) >> 16;
+
+		if (smp_num_siblings == 1) {
+			printk(KERN_INFO  "CPU: Hyper-Threading is disabled\n");
+		} else if (smp_num_siblings > 1 ) {
+			index_lsb = 0;
+			index_msb = 31;
+			/*
+			 * At this point we only support two siblings per
+			 * processor package.
+			 */
+#define NR_SIBLINGS	2
+			if (smp_num_siblings != NR_SIBLINGS) {
+				printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings);
+				smp_num_siblings = 1;
+				goto too_many_siblings;
+			}
+			tmp = smp_num_siblings;
+			while ((tmp & 1) == 0) {
+				tmp >>=1 ;
+				index_lsb++;
+			}
+			tmp = smp_num_siblings;
+			while ((tmp & 0x80000000 ) == 0) {
+				tmp <<=1 ;
+				index_msb--;
+			}
+			if (index_lsb != index_msb )
+				index_msb++;
+			initial_apic_id = ebx >> 24 & 0xff;
+			phys_proc_id[cpu] = initial_apic_id >> index_msb;
 
-	/* Enable MCA if available */
-	mcheck_init(c);
+			printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
+                               phys_proc_id[cpu]);
+		}
+
+	}
+too_many_siblings:
+#endif
 }
 
 void __init get_cpu_vendor(struct cpuinfo_x86 *c)
@@ -2584,7 +2521,7 @@
 		init_rise(c);
 		break;
 	}
-	
+
 	printk(KERN_DEBUG "CPU: After vendor init, caps: %08x %08x %08x %08x\n",
 	       c->x86_capability[0],
 	       c->x86_capability[1],
@@ -2611,6 +2548,9 @@
 	/* Disable the PN if appropriate */
 	squash_the_stupid_serial_number(c);
 
+	/* Init Machine Check Exception if available. */
+	mcheck_init(c);
+
 	/* If the model name is still unset, do table lookup. */
 	if ( !c->x86_model_id[0] ) {
 		char *p;
@@ -2708,7 +2648,7 @@
 	        "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
 	        "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
 	        "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
-	        "fxsr", "sse", "sse2", "ss", NULL, "tm", "ia64", NULL,
+	        "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL,
 
 		/* AMD-defined */
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
diff -u --recursive --new-file v2.5.1/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- v2.5.1/linux/arch/i386/kernel/signal.c	Fri Sep 14 14:15:40 2001
+++ linux/arch/i386/kernel/signal.c	Wed Dec 19 15:27:12 2001
@@ -28,7 +28,7 @@
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
+int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
 
 int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
 {
diff -u --recursive --new-file v2.5.1/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.5.1/linux/arch/i386/kernel/smp.c	Tue Oct 23 14:17:10 2001
+++ linux/arch/i386/kernel/smp.c	Sun Dec 30 10:02:19 2001
@@ -17,6 +17,7 @@
 #include <linux/smp_lock.h>
 #include <linux/kernel_stat.h>
 #include <linux/mc146818rtc.h>
+#include <linux/cache.h>
 
 #include <asm/mtrr.h>
 #include <asm/pgalloc.h>
@@ -102,7 +103,7 @@
  */
 
 /* The 'big kernel lock' */
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 struct tlb_state cpu_tlbstate[NR_CPUS] = {[0 ... NR_CPUS-1] = { &init_mm, 0 }};
 
diff -u --recursive --new-file v2.5.1/linux/arch/i386/kernel/smpboot.c linux/arch/i386/kernel/smpboot.c
--- v2.5.1/linux/arch/i386/kernel/smpboot.c	Wed Nov 21 10:35:48 2001
+++ linux/arch/i386/kernel/smpboot.c	Sun Dec 30 16:54:29 2001
@@ -56,6 +56,10 @@
 /* Total count of live CPUs */
 int smp_num_cpus = 1;
 
+/* Number of siblings per CPU package */
+int smp_num_siblings = 1;
+int __initdata phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */
+
 /* Bitmask of currently online CPUs */
 unsigned long cpu_online_map;
 
@@ -971,6 +975,8 @@
 /* Where the IO area was mapped on multiquad, always 0 otherwise */
 void *xquad_portio = NULL;
 
+int cpu_sibling_map[NR_CPUS] __cacheline_aligned;
+
 void __init smp_boot_cpus(void)
 {
 	int apicid, cpu, bit;
@@ -1162,6 +1168,34 @@
 		printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n");
 	Dprintk("Boot done.\n");
 
+	/*
+	 * If Hyper-Threading is avaialble, construct cpu_sibling_map[], so
+	 * that we can tell the sibling CPU efficiently.
+	 */
+	if (test_bit(X86_FEATURE_HT, boot_cpu_data.x86_capability)
+	    && smp_num_siblings > 1) {
+		for (cpu = 0; cpu < NR_CPUS; cpu++)
+			cpu_sibling_map[cpu] = NO_PROC_ID;
+		
+		for (cpu = 0; cpu < smp_num_cpus; cpu++) {
+			int 	i;
+			
+			for (i = 0; i < smp_num_cpus; i++) {
+				if (i == cpu)
+					continue;
+				if (phys_proc_id[cpu] == phys_proc_id[i]) {
+					cpu_sibling_map[cpu] = i;
+					printk("cpu_sibling_map[%d] = %d\n", cpu, cpu_sibling_map[cpu]);
+					break;
+				}
+			}
+			if (cpu_sibling_map[cpu] == NO_PROC_ID) {
+				smp_num_siblings = 1;
+				printk(KERN_WARNING "WARNING: No sibling found for CPU %d.\n", cpu);
+			}
+		}
+	}
+	     
 #ifndef CONFIG_VISWS
 	/*
 	 * Here we can be sure that there is an IO-APIC in the system. Let's
diff -u --recursive --new-file v2.5.1/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c
--- v2.5.1/linux/arch/i386/kernel/vm86.c	Fri Jul  6 17:05:07 2001
+++ linux/arch/i386/kernel/vm86.c	Wed Dec 19 15:27:12 2001
@@ -62,7 +62,7 @@
         ( (unsigned)( & (((struct kernel_vm86_regs *)0)->VM86_REGS_PART2) ) )
 #define VM86_REGS_SIZE2 (sizeof(struct kernel_vm86_regs) - VM86_REGS_SIZE1)
 
-asmlinkage struct pt_regs * FASTCALL(save_v86_state(struct kernel_vm86_regs * regs));
+struct pt_regs * FASTCALL(save_v86_state(struct kernel_vm86_regs * regs));
 struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs)
 {
 	struct tss_struct *tss;
diff -u --recursive --new-file v2.5.1/linux/arch/ia64/hp/hpsim_console.c linux/arch/ia64/hp/hpsim_console.c
--- v2.5.1/linux/arch/ia64/hp/hpsim_console.c	Thu Oct 12 14:20:48 2000
+++ linux/arch/ia64/hp/hpsim_console.c	Tue Dec 25 15:39:20 2001
@@ -24,14 +24,12 @@
 
 static int simcons_init (struct console *, char *);
 static void simcons_write (struct console *, const char *, unsigned);
-static int simcons_wait_key (struct console *);
 static kdev_t simcons_console_device (struct console *);
 
 struct console hpsim_cons = {
 	name:		"simcons",
 	write:		simcons_write,
 	device:		simcons_console_device,
-	wait_key:	simcons_wait_key,
 	setup:		simcons_init,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
@@ -54,17 +52,6 @@
 		if (ch == '\n')
 		  ia64_ssc('\r', 0, 0, 0, SSC_PUTCHAR);
 	}
-}
-
-static int
-simcons_wait_key (struct console *cons)
-{
-	char ch;
-
-	do {
-		ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR);
-	} while (ch == '\0');
-	return ch;
 }
 
 static kdev_t
diff -u --recursive --new-file v2.5.1/linux/arch/ia64/kernel/process.c linux/arch/ia64/kernel/process.c
--- v2.5.1/linux/arch/ia64/kernel/process.c	Fri Nov  9 14:26:17 2001
+++ linux/arch/ia64/kernel/process.c	Thu Dec 27 08:21:28 2001
@@ -114,8 +114,6 @@
 	/* endless idle loop with no priority at all */
 	init_idle();
 	current->nice = 20;
-	current->counter = -100;
-
 
 	while (1) {
 #ifdef CONFIG_SMP
diff -u --recursive --new-file v2.5.1/linux/arch/ia64/kernel/smp.c linux/arch/ia64/kernel/smp.c
--- v2.5.1/linux/arch/ia64/kernel/smp.c	Fri Nov  9 14:26:17 2001
+++ linux/arch/ia64/kernel/smp.c	Sun Dec 30 10:02:19 2001
@@ -30,6 +30,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/mm.h>
 #include <linux/delay.h>
+#include <linux/cache.h>
 
 #include <asm/atomic.h>
 #include <asm/bitops.h>
@@ -51,7 +52,7 @@
 #include <asm/mca.h>
 
 /* The 'big kernel lock' */
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 /*
  * Structure and data for smp_call_function(). This is designed to minimise static memory
diff -u --recursive --new-file v2.5.1/linux/arch/ia64/sn/io/hcl.c linux/arch/ia64/sn/io/hcl.c
--- v2.5.1/linux/arch/ia64/sn/io/hcl.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/sn/io/hcl.c	Thu Dec 27 08:29:14 2001
@@ -1049,16 +1049,22 @@
 struct file_operations *
 hwgraph_cdevsw_get(devfs_handle_t de)
 {
-	return(devfs_get_ops(de));
+	struct file_operations *fops = devfs_get_ops(de);
+
+	devfs_put_ops(de); /*  FIXME: this may need to be moved to callers  */
+	return(fops);
 }
 
 /*
  * hwgraph_bdevsw_get - returns the fops of the given devfs entry.
 */
-struct file_operations *
+struct file_operations *    /*  FIXME: shouldn't this be a blkdev?  */
 hwgraph_bdevsw_get(devfs_handle_t de)
 {
-	return(devfs_get_ops(de));
+	struct file_operations *fops = devfs_get_ops(de);
+
+	devfs_put_ops(de); /*  FIXME: this may need to be moved to callers  */
+	return(fops);
 }
 
 /*
diff -u --recursive --new-file v2.5.1/linux/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c
--- v2.5.1/linux/arch/m68k/amiga/config.c	Tue Dec 18 14:56:34 2001
+++ linux/arch/m68k/amiga/config.c	Tue Dec 25 15:39:20 2001
@@ -98,7 +98,6 @@
 extern void amiga_floppy_setup(char *, int *);
 #endif
 static void amiga_reset (void);
-static int amiga_wait_key (struct console *co);
 extern void amiga_init_sound(void);
 static void amiga_savekmsg_init(void);
 static void amiga_mem_console_write(struct console *co, const char *b,
@@ -112,7 +111,6 @@
 
 static struct console amiga_console_driver = {
 	name:		"debug",
-	wait_key:	amiga_wait_key,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
 };
@@ -740,33 +738,6 @@
 	}
 
 	return 0;
-}
-
-static int amiga_wait_key (struct console *co)
-{
-    int i;
-
-    while (1) {
-	while (ciaa.pra & 0x40);
-
-	/* debounce */
-	for (i = 0; i < 1000; i++);
-
-	if (!(ciaa.pra & 0x40))
-	    break;
-    }
-
-    /* wait for button up */
-    while (1) {
-	while (!(ciaa.pra & 0x40));
-
-	/* debounce */
-	for (i = 0; i < 1000; i++);
-
-	if (ciaa.pra & 0x40)
-	    break;
-    }
-    return 0;
 }
 
 static NORET_TYPE void amiga_reset( void )
diff -u --recursive --new-file v2.5.1/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c
--- v2.5.1/linux/arch/m68k/kernel/process.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/m68k/kernel/process.c	Thu Dec 27 08:21:28 2001
@@ -81,7 +81,6 @@
 	/* endless idle loop with no priority at all */
 	init_idle();
 	current->nice = 20;
-	current->counter = -100;
 	idle();
 }
 
diff -u --recursive --new-file v2.5.1/linux/arch/m68k/mac/debug.c linux/arch/m68k/mac/debug.c
--- v2.5.1/linux/arch/m68k/mac/debug.c	Mon Jun 11 19:15:27 2001
+++ linux/arch/m68k/mac/debug.c	Tue Dec 25 15:39:20 2001
@@ -248,17 +248,6 @@
     return( scc.cha_b_data );
 }
 
-int mac_scca_console_wait_key(struct console *co)
-{
-    int i;
-    do {
-	for( i = uSEC; i > 0; --i )
-		barrier();
-    } while( !(scc.cha_a_ctrl & 0x01) ); /* wait for rx buf filled */
-    for( i = uSEC; i > 0; --i )
-	barrier();
-    return( scc.cha_a_data );
-}
 #endif
 
 /* The following two functions do a quick'n'dirty initialization of the MFP or
@@ -395,9 +384,6 @@
 	/* Mac modem port */
 	mac_init_scc_port( B9600|CS8, 0 );
 	mac_console_driver.write = mac_scca_console_write;
-#ifdef CONFIG_SERIAL_CONSOLE
-	mac_console_driver.wait_key = mac_scca_console_wait_key;
-#endif
 	scc_port = 0;
     }
     else if (!strcmp( m68k_debug_device, "ser2" )) {
diff -u --recursive --new-file v2.5.1/linux/arch/m68k/mvme147/config.c linux/arch/m68k/mvme147/config.c
--- v2.5.1/linux/arch/m68k/mvme147/config.c	Tue Dec 18 14:56:34 2001
+++ linux/arch/m68k/mvme147/config.c	Tue Dec 25 15:39:20 2001
@@ -241,31 +241,7 @@
 	restore_flags(flags);
 }
 
-
-static int m147_scc_wait_key (struct console *co)
-{
-	volatile unsigned char *p = (volatile char *)M147_SCC_A_ADDR;
-	unsigned long	flags;
-	int		c;
-
-	/* wait for rx buf filled */
-	while ((*p & 0x01) == 0)
-		;
-
-	save_flags(flags);
-	cli();
-
-	*p = 8;
-	scc_delay();
-	c = *p;
-
-	restore_flags(flags);
-	return c;
-}
-
-
 void mvme147_init_console_port (struct console *co, int cflag)
 {
 	co->write    = m147_scc_write;
-	co->wait_key = m147_scc_wait_key;
 }
diff -u --recursive --new-file v2.5.1/linux/arch/m68k/q40/config.c linux/arch/m68k/q40/config.c
--- v2.5.1/linux/arch/m68k/q40/config.c	Tue Dec 18 14:56:34 2001
+++ linux/arch/m68k/q40/config.c	Tue Dec 25 15:39:20 2001
@@ -72,10 +72,8 @@
 
 extern int ql_ticks;
 
-static int q40_wait_key(struct console *co){return 0;}
 static struct console q40_console_driver = {
 	name:		"debug",
-	wait_key:	q40_wait_key,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
 };
diff -u --recursive --new-file v2.5.1/linux/arch/m68k/sun3x/prom.c linux/arch/m68k/sun3x/prom.c
--- v2.5.1/linux/arch/m68k/sun3x/prom.c	Mon Jun 11 19:15:27 2001
+++ linux/arch/m68k/sun3x/prom.c	Tue Dec 25 15:39:20 2001
@@ -96,7 +96,6 @@
 	sun3x_prom_write,  	/* write */
 	NULL,			/* read */
 	NULL,			/* device */
-	NULL,			/* wait_key */
 	NULL,			/* unblank */
 	NULL,			/* setup */
 	CON_PRINTBUFFER,
diff -u --recursive --new-file v2.5.1/linux/arch/mips/au1000/common/serial.c linux/arch/mips/au1000/common/serial.c
--- v2.5.1/linux/arch/mips/au1000/common/serial.c	Fri Oct  5 12:06:51 2001
+++ linux/arch/mips/au1000/common/serial.c	Tue Dec 25 15:39:20 2001
@@ -2922,35 +2922,6 @@
 	serial_out(info, UART_IER, ier);
 }
 
-/*
- *	Receive character from the serial port
- */
-static int serial_console_wait_key(struct console *co)
-{
-	static struct async_struct *info;
-	int ier, c;
-
-	info = &async_sercons;
-
-	/*
-	 *	First save the IER then disable the interrupts so
-	 *	that the real driver for the port does not get the
-	 *	character.
-	 */
-	ier = serial_in(info, UART_IER);
-	serial_out(info, UART_IER, 0x00);
- 
-	while ((serial_in(info, UART_LSR) & UART_LSR_DR) == 0);
-	c = serial_in(info, UART_RX);
-
-	/*
-	 *	Restore the interrupts
-	 */
-	serial_out(info, UART_IER, ier);
-
-	return c;
-}
-
 static kdev_t serial_console_device(struct console *c)
 {
 	return MKDEV(TTY_MAJOR, 64 + c->index);
@@ -3075,7 +3046,6 @@
 	name:		"ttyS",
 	write:		serial_console_write,
 	device:		serial_console_device,
-	wait_key:	serial_console_wait_key,
 	setup:		serial_console_setup,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
diff -u --recursive --new-file v2.5.1/linux/arch/mips/baget/vacserial.c linux/arch/mips/baget/vacserial.c
--- v2.5.1/linux/arch/mips/baget/vacserial.c	Sun Sep  9 10:43:01 2001
+++ linux/arch/mips/baget/vacserial.c	Tue Dec 25 15:39:20 2001
@@ -2622,43 +2622,6 @@
 	serial_outp(&scr_info, VAC_UART_INT_MASK, ier);
 }
 
-/*
- *	Receive character from the serial port
- */
-static int serial_console_wait_key(struct console *co)
-{
-	struct serial_state *ser;
-	int ier;
-	int lsr;
-	int c;
-	struct async_struct scr_info; /* serial_{in,out} because HUB6 */
-
-	ser = rs_table + co->index;
-	scr_info.magic = SERIAL_MAGIC;
-	scr_info.port = ser->port;
-	scr_info.flags = ser->flags;
-
-	/*
-	 *	First save the IER then disable the interrupts so
-	 *	that the real driver for the port does not get the
-	 *	character.
-	 */
-	ier = serial_inp(&scr_info, VAC_UART_INT_MASK);
-	serial_outp(&scr_info, VAC_UART_INT_MASK, 0x00);
-
-	do {
-		lsr = serial_inp(&scr_info, VAC_UART_INT_STATUS);
-	} while (!(lsr & VAC_UART_STATUS_RX_READY));
-	c = serial_inp(&scr_info, VAC_UART_RX);
-
-	/*
-	 *	Restore the interrupts
-	 */
-	serial_outp(&scr_info, VAC_UART_INT_MASK, ier);
-
-	return c;
-}
-
 static kdev_t serial_console_device(struct console *c)
 {
 	return MKDEV(TTY_MAJOR, 64 + c->index);
@@ -2812,7 +2775,6 @@
 	name:		"ttyS",
 	write:		serial_console_write,
 	device:		serial_console_device,
-	wait_key:	serial_console_wait_key,
 	setup:		serial_console_setup,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
diff -u --recursive --new-file v2.5.1/linux/arch/mips/dec/promcon.c linux/arch/mips/dec/promcon.c
--- v2.5.1/linux/arch/mips/dec/promcon.c	Thu Oct 12 14:20:48 2000
+++ linux/arch/mips/dec/promcon.c	Tue Dec 25 15:39:20 2001
@@ -30,11 +30,6 @@
     }
 }
 
-static int prom_console_wait_key(struct console *co)
-{
-    return prom_getchar();
-}
-
 static int __init prom_console_setup(struct console *co, char *options)
 {
     return 0;
@@ -50,7 +45,6 @@
     name:	"ttyS",
     write:	prom_console_write,
     device:	prom_console_device,
-    wait_key:	prom_console_wait_key,
     setup:	prom_console_setup,
     flags:	CON_PRINTBUFFER,
     index:	-1,
diff -u --recursive --new-file v2.5.1/linux/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c
--- v2.5.1/linux/arch/mips/kernel/process.c	Sun Sep  9 10:43:01 2001
+++ linux/arch/mips/kernel/process.c	Thu Dec 27 08:21:28 2001
@@ -36,7 +36,6 @@
 {
 	/* endless idle loop with no priority at all */
 	current->nice = 20;
-	current->counter = -100;
 	init_idle();
 
 	while (1) {
diff -u --recursive --new-file v2.5.1/linux/arch/mips/kernel/smp.c linux/arch/mips/kernel/smp.c
--- v2.5.1/linux/arch/mips/kernel/smp.c	Wed Nov 21 10:31:09 2001
+++ linux/arch/mips/kernel/smp.c	Sun Dec 30 10:02:19 2001
@@ -31,6 +31,7 @@
 #include <linux/timex.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/cache.h>
 
 #include <asm/atomic.h>
 #include <asm/processor.h>
@@ -52,7 +53,7 @@
 
 
 /* Ze Big Kernel Lock! */
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 int smp_threads_ready;  /* Not used */
 int smp_num_cpus;    
 int global_irq_holder = NO_PROC_ID;
diff -u --recursive --new-file v2.5.1/linux/arch/mips64/kernel/process.c linux/arch/mips64/kernel/process.c
--- v2.5.1/linux/arch/mips64/kernel/process.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/mips64/kernel/process.c	Thu Dec 27 08:21:28 2001
@@ -34,7 +34,6 @@
 	/* endless idle loop with no priority at all */
 	init_idle();
 	current->nice = 20;
-	current->counter = -100;
 	while (1) {
 		while (!current->need_resched)
 			if (wait_available)
diff -u --recursive --new-file v2.5.1/linux/arch/mips64/kernel/smp.c linux/arch/mips64/kernel/smp.c
--- v2.5.1/linux/arch/mips64/kernel/smp.c	Wed Jul  4 11:50:39 2001
+++ linux/arch/mips64/kernel/smp.c	Sun Dec 30 10:02:19 2001
@@ -5,6 +5,7 @@
 #include <linux/time.h>
 #include <linux/timex.h>
 #include <linux/sched.h>
+#include <linux/cache.h>
 
 #include <asm/atomic.h>
 #include <asm/processor.h>
@@ -52,7 +53,7 @@
 #endif /* CONFIG_SGI_IP27 */
 
 /* The 'big kernel lock' */
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 int smp_threads_ready;	/* Not used */
 atomic_t smp_commenced = ATOMIC_INIT(0);
 struct cpuinfo_mips cpu_data[NR_CPUS];
diff -u --recursive --new-file v2.5.1/linux/arch/parisc/kernel/pdc_cons.c linux/arch/parisc/kernel/pdc_cons.c
--- v2.5.1/linux/arch/parisc/kernel/pdc_cons.c	Sun Sep 16 21:23:15 2001
+++ linux/arch/parisc/kernel/pdc_cons.c	Tue Dec 25 15:39:20 2001
@@ -105,10 +105,6 @@
 static struct console pdc_cons = {
 	name:		"ttyB",
 	write:		pdc_console_write,
-	read:		NULL,
-	device:		NULL, 
-	wait_key:	pdc_console_wait_key,
-	unblank:	NULL,
 	setup:		pdc_console_setup,
 	flags:		CON_PRINTBUFFER|CON_ENABLED,  // |CON_CONSDEV,
 	index:		-1,
diff -u --recursive --new-file v2.5.1/linux/arch/parisc/kernel/process.c linux/arch/parisc/kernel/process.c
--- v2.5.1/linux/arch/parisc/kernel/process.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/parisc/kernel/process.c	Thu Dec 27 08:21:28 2001
@@ -71,7 +71,6 @@
 	/* endless idle loop with no priority at all */
 	init_idle();
 	current->nice = 20;
-	current->counter = -100;
 
 	while (1) {
 		while (!current->need_resched) {
diff -u --recursive --new-file v2.5.1/linux/arch/ppc/8260_io/uart.c linux/arch/ppc/8260_io/uart.c
--- v2.5.1/linux/arch/ppc/8260_io/uart.c	Mon May 21 17:04:46 2001
+++ linux/arch/ppc/8260_io/uart.c	Thu Dec 27 08:21:28 2001
@@ -1732,7 +1732,7 @@
 		printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
 #endif
 		current->state = TASK_INTERRUPTIBLE;
-/*		current->counter = 0;	 make us low-priority */
+/*		current->dyn_prio = 0;	 make us low-priority */
 		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
@@ -2216,54 +2216,6 @@
 		info->tx_cur = (cbd_t *)bdp;
 }
 
-/*
- * Receive character from the serial port.  This only works well
- * before the port is initialize for real use.
- */
-static int serial_console_wait_key(struct console *co)
-{
-	struct serial_state		*ser;
-	u_char				c, *cp;
-	ser_info_t			*info;
-	volatile	cbd_t		*bdp;
-	volatile	smc_uart_t	*up;
-
-	ser = rs_table + co->index;
-
-	/* Pointer to UART in parameter ram.
-	*/
-	up = (smc_uart_t *)&immr->im_dprambase[ser->port];
-
-	/* Get the address of the host memory buffer.
-	 * If the port has been initialized for general use, we must
-	 * use information from the port structure.
-	 */
-	if ((info = (ser_info_t *)ser->info))
-		bdp = info->rx_cur;
-	else
-		bdp = (cbd_t *)&immr->im_dprambase[up->smc_rbase];
-
-	/*
-	 * We need to gracefully shut down the receiver, disable
-	 * interrupts, then read the input.
-	 */
-	while (bdp->cbd_sc & BD_SC_EMPTY);	/* Wait for a character */
-	cp = __va(bdp->cbd_bufaddr);
-
-	if (info) {
-		if (bdp->cbd_sc & BD_SC_WRAP) {
-			bdp = info->rx_bd_base;
-		}
-		else {
-			bdp++;
-		}
-		info->rx_cur = (cbd_t *)bdp;
-	}
-
-	c = *cp;
-	return((int)c);
-}
-
 static kdev_t serial_console_device(struct console *c)
 {
 	return MKDEV(TTYAUX_MAJOR, 64 + c->index);
@@ -2274,7 +2226,6 @@
 	name:		"ttyS",
 	write:		serial_console_write,
 	device:		serial_console_device,
-	wait_key:	serial_console_wait_key,
 	setup:		serial_console_setup,
 	flags:		CON_PRINTBUFFER,
 	index:		CONFIG_SERIAL_CONSOLE_PORT,
diff -u --recursive --new-file v2.5.1/linux/arch/ppc/8xx_io/uart.c linux/arch/ppc/8xx_io/uart.c
--- v2.5.1/linux/arch/ppc/8xx_io/uart.c	Fri Nov  2 17:43:54 2001
+++ linux/arch/ppc/8xx_io/uart.c	Thu Dec 27 08:21:28 2001
@@ -97,7 +97,6 @@
 static void serial_console_write(struct console *c, const char *s,
 				unsigned count);
 static kdev_t serial_console_device(struct console *c);
-static int serial_console_wait_key(struct console *co);
 
 #if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 static unsigned long break_pressed; /* break, really ... */
@@ -218,7 +217,6 @@
 	name:		"ttyS",
 	write:		serial_console_write,
 	device:		serial_console_device,
-	wait_key:	serial_console_wait_key,
 	setup:		serial_console_setup,
 	flags:		CON_PRINTBUFFER,
 	index:		CONFIG_SERIAL_CONSOLE_PORT,
@@ -1798,7 +1796,7 @@
 		printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
 #endif
 		current->state = TASK_INTERRUPTIBLE;
-/*		current->counter = 0;	 make us low-priority */
+/*		current->dyn_prio = 0;	 make us low-priority */
 		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
@@ -2400,11 +2398,6 @@
 	}
 
 	return((int)c);
-}
-
-static int serial_console_wait_key(struct console *co)
-{
-	return(my_console_wait_key(co->index, 0, NULL));
 }
 
 #ifdef CONFIG_XMON
diff -u --recursive --new-file v2.5.1/linux/arch/ppc/amiga/config.c linux/arch/ppc/amiga/config.c
--- v2.5.1/linux/arch/ppc/amiga/config.c	Tue Dec 18 14:56:34 2001
+++ linux/arch/ppc/amiga/config.c	Tue Dec 25 15:39:20 2001
@@ -104,7 +104,6 @@
 extern void amiga_floppy_setup(char *, int *);
 #endif
 static void amiga_reset (void);
-static int amiga_wait_key (struct console *co);
 extern void amiga_init_sound(void);
 static void amiga_savekmsg_init(void);
 static void amiga_mem_console_write(struct console *co, const char *b,
@@ -118,7 +117,6 @@
 
 static struct console amiga_console_driver = {
 	name:		"debug",
-	wait_key:	amiga_wait_key,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
 };
@@ -734,33 +732,6 @@
 	}
 
 	return 0;
-}
-
-static int amiga_wait_key (struct console *co)
-{
-    int i;
-
-    while (1) {
-	while (ciaa.pra & 0x40);
-
-	/* debounce */
-	for (i = 0; i < 1000; i++);
-
-	if (!(ciaa.pra & 0x40))
-	    break;
-    }
-
-    /* wait for button up */
-    while (1) {
-	while (!(ciaa.pra & 0x40));
-
-	/* debounce */
-	for (i = 0; i < 1000; i++);
-
-	if (ciaa.pra & 0x40)
-	    break;
-    }
-    return 0;
 }
 
 static NORET_TYPE void amiga_reset( void )
diff -u --recursive --new-file v2.5.1/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c
--- v2.5.1/linux/arch/ppc/kernel/idle.c	Fri Nov  2 17:43:54 2001
+++ linux/arch/ppc/kernel/idle.c	Thu Dec 27 08:21:28 2001
@@ -54,7 +54,6 @@
 
 	/* endless loop with no priority at all */
 	current->nice = 20;
-	current->counter = -100;
 	init_idle();
 	for (;;) {
 #ifdef CONFIG_SMP
diff -u --recursive --new-file v2.5.1/linux/arch/ppc/kernel/m8xx_setup.c linux/arch/ppc/kernel/m8xx_setup.c
--- v2.5.1/linux/arch/ppc/kernel/m8xx_setup.c	Fri Nov 16 10:10:08 2001
+++ linux/arch/ppc/kernel/m8xx_setup.c	Mon Dec 17 11:12:05 2001
@@ -55,12 +55,6 @@
 
 extern void m8xx_ide_init(void);
 
-#ifdef CONFIG_BLK_DEV_RAM
-extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
-extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
-extern int rd_image_start;	/* starting block # of image */
-#endif
-
 extern unsigned long find_available_memory(void);
 extern void m8xx_cpm_reset(uint);
 
diff -u --recursive --new-file v2.5.1/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
--- v2.5.1/linux/arch/ppc/kernel/prep_setup.c	Fri Nov 16 10:10:08 2001
+++ linux/arch/ppc/kernel/prep_setup.c	Mon Dec 17 11:12:05 2001
@@ -111,12 +111,6 @@
 extern int probingmem;
 extern unsigned long loops_per_jiffy;
 
-#ifdef CONFIG_BLK_DEV_RAM
-extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
-extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
-extern int rd_image_start;	/* starting block # of image */
-#endif
-
 #ifdef CONFIG_SOUND_MODULE
 EXPORT_SYMBOL(ppc_cs4232_dma);
 EXPORT_SYMBOL(ppc_cs4232_dma2);
diff -u --recursive --new-file v2.5.1/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- v2.5.1/linux/arch/ppc/kernel/smp.c	Wed Nov 21 10:31:09 2001
+++ linux/arch/ppc/kernel/smp.c	Sun Dec 30 10:02:19 2001
@@ -23,6 +23,7 @@
 #include <linux/unistd.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/cache.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
@@ -47,7 +48,7 @@
 struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 };
 atomic_t ipi_recv;
 atomic_t ipi_sent;
-spinlock_t kernel_flag __cacheline_aligned = SPIN_LOCK_UNLOCKED;
+spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 unsigned int prof_multiplier[NR_CPUS];
 unsigned int prof_counter[NR_CPUS];
 cycles_t cacheflush_time;
diff -u --recursive --new-file v2.5.1/linux/arch/s390/kernel/process.c linux/arch/s390/kernel/process.c
--- v2.5.1/linux/arch/s390/kernel/process.c	Thu Oct 11 09:04:57 2001
+++ linux/arch/s390/kernel/process.c	Thu Dec 27 08:21:28 2001
@@ -57,7 +57,6 @@
 	/* endless idle loop with no priority at all */
         init_idle();
 	current->nice = 20;
-	current->counter = -100;
 	wait_psw.mask = _WAIT_PSW_MASK;
 	wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L;
 	while(1) {
diff -u --recursive --new-file v2.5.1/linux/arch/s390/kernel/smp.c linux/arch/s390/kernel/smp.c
--- v2.5.1/linux/arch/s390/kernel/smp.c	Wed Nov 21 10:31:09 2001
+++ linux/arch/s390/kernel/smp.c	Sun Dec 30 10:02:19 2001
@@ -29,6 +29,7 @@
 #include <linux/smp_lock.h>
 
 #include <linux/delay.h>
+#include <linux/cache.h>
 
 #include <asm/sigp.h>
 #include <asm/pgalloc.h>
@@ -55,7 +56,7 @@
 int              smp_threads_ready=0;      /* Set when the idlers are all forked. */
 static atomic_t  smp_commenced = ATOMIC_INIT(0);
 
-spinlock_t       kernel_flag = SPIN_LOCK_UNLOCKED;
+spinlock_t       kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 unsigned long	 cpu_online_map;
 
diff -u --recursive --new-file v2.5.1/linux/arch/s390x/kernel/process.c linux/arch/s390x/kernel/process.c
--- v2.5.1/linux/arch/s390x/kernel/process.c	Thu Oct 11 09:04:57 2001
+++ linux/arch/s390x/kernel/process.c	Thu Dec 27 08:21:28 2001
@@ -57,7 +57,6 @@
 	/* endless idle loop with no priority at all */
         init_idle();
 	current->nice = 20;
-	current->counter = -100;
 	wait_psw.mask = _WAIT_PSW_MASK;
 	wait_psw.addr = (unsigned long) &&idle_wakeup;
 	while(1) {
diff -u --recursive --new-file v2.5.1/linux/arch/s390x/kernel/smp.c linux/arch/s390x/kernel/smp.c
--- v2.5.1/linux/arch/s390x/kernel/smp.c	Wed Nov 21 10:31:09 2001
+++ linux/arch/s390x/kernel/smp.c	Sun Dec 30 10:02:19 2001
@@ -29,6 +29,7 @@
 #include <linux/smp_lock.h>
 
 #include <linux/delay.h>
+#include <linux/cache.h>
 
 #include <asm/sigp.h>
 #include <asm/pgalloc.h>
@@ -55,7 +56,7 @@
 int              smp_threads_ready=0;      /* Set when the idlers are all forked. */
 static atomic_t  smp_commenced = ATOMIC_INIT(0);
 
-spinlock_t       kernel_flag = SPIN_LOCK_UNLOCKED;
+spinlock_t       kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 unsigned long	 cpu_online_map;
 
diff -u --recursive --new-file v2.5.1/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c
--- v2.5.1/linux/arch/sh/kernel/process.c	Mon Oct 15 13:36:48 2001
+++ linux/arch/sh/kernel/process.c	Thu Dec 27 08:21:28 2001
@@ -41,7 +41,6 @@
 	/* endless idle loop with no priority at all */
 	init_idle();
 	current->nice = 20;
-	current->counter = -100;
 
 	while (1) {
 		if (hlt_counter) {
diff -u --recursive --new-file v2.5.1/linux/arch/sh/kernel/setup.c linux/arch/sh/kernel/setup.c
--- v2.5.1/linux/arch/sh/kernel/setup.c	Fri Nov 16 18:38:39 2001
+++ linux/arch/sh/kernel/setup.c	Tue Dec 25 15:39:20 2001
@@ -140,15 +140,6 @@
     	sh_bios_console_write(s, count);
 }
 
-/*
- *	Receive character from the serial port
- */
-static int sh_console_wait_key(struct console *co)
-{
-	/* Not implemented yet */
-	return 0;
-}
-
 static kdev_t sh_console_device(struct console *c)
 {
     	/* TODO: this is totally bogus */
@@ -183,7 +174,6 @@
 	name:		"bios",
 	write:		sh_console_write,
 	device:		sh_console_device,
-	wait_key:	sh_console_wait_key,
 	setup:		sh_console_setup,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
diff -u --recursive --new-file v2.5.1/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- v2.5.1/linux/arch/sparc/kernel/process.c	Tue Nov 13 09:16:05 2001
+++ linux/arch/sparc/kernel/process.c	Thu Dec 27 08:21:28 2001
@@ -61,7 +61,6 @@
 
 	/* endless idle loop with no priority at all */
 	current->nice = 20;
-	current->counter = -100;
 	init_idle();
 
 	for (;;) {
@@ -110,7 +109,6 @@
 {
 	/* endless idle loop with no priority at all */
 	current->nice = 20;
-	current->counter = -100;
 	init_idle();
 
 	while(1) {
diff -u --recursive --new-file v2.5.1/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c
--- v2.5.1/linux/arch/sparc/kernel/smp.c	Tue Nov 13 09:16:05 2001
+++ linux/arch/sparc/kernel/smp.c	Sun Dec 30 10:02:19 2001
@@ -18,6 +18,7 @@
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/seq_file.h>
+#include <linux/cache.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
@@ -66,7 +67,7 @@
  */
 
 /* Kernel spinlock */
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 /* Used to make bitops atomic */
 unsigned char bitops_spinlock = 0;
diff -u --recursive --new-file v2.5.1/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.5.1/linux/arch/sparc64/kernel/process.c	Sun Oct 21 10:36:54 2001
+++ linux/arch/sparc64/kernel/process.c	Thu Dec 27 08:21:28 2001
@@ -54,7 +54,6 @@
 
 	/* endless idle loop with no priority at all */
 	current->nice = 20;
-	current->counter = -100;
 	init_idle();
 
 	for (;;) {
@@ -84,7 +83,6 @@
 int cpu_idle(void)
 {
 	current->nice = 20;
-	current->counter = -100;
 	init_idle();
 
 	while(1) {
diff -u --recursive --new-file v2.5.1/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- v2.5.1/linux/arch/sparc64/kernel/smp.c	Wed Nov 21 10:31:09 2001
+++ linux/arch/sparc64/kernel/smp.c	Sun Dec 30 10:02:19 2001
@@ -17,6 +17,7 @@
 #include <linux/spinlock.h>
 #include <linux/fs.h>
 #include <linux/seq_file.h>
+#include <linux/cache.h>
 
 #include <asm/head.h>
 #include <asm/ptrace.h>
@@ -39,17 +40,17 @@
 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;
 static int smp_activated = 0;
 
 /* Kernel spinlock */
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 volatile int smp_processors_ready = 0;
 unsigned long cpu_present_map = 0;
diff -u --recursive --new-file v2.5.1/linux/drivers/acorn/block/mfmhd.c linux/drivers/acorn/block/mfmhd.c
--- v2.5.1/linux/drivers/acorn/block/mfmhd.c	Thu Oct 25 13:58:35 2001
+++ linux/drivers/acorn/block/mfmhd.c	Mon Dec 31 17:56:19 2001
@@ -1311,10 +1311,8 @@
 	major:		MAJOR_NR,
 	major_name:	"mfm",
 	minor_shift:	6,
-	max_p:		1 << 6,
 	part:		mfm,
 	sizes:		mfm_sizes,
-	real_devices:	(void *)mfm_info,
 };
 
 static struct block_device_operations mfm_fops =
@@ -1473,7 +1471,7 @@
 	mfm_info[target].busy = 1;
 	restore_flags (flags);
 
-	maxp = mfm_gendisk.max_p;
+	maxp = 1 << mfm_gendisk.minor_shift;
 	start = target << mfm_gendisk.minor_shift;
 
 	for (i = maxp - 1; i >= 0; i--) {
diff -u --recursive --new-file v2.5.1/linux/drivers/acorn/scsi/acornscsi.c linux/drivers/acorn/scsi/acornscsi.c
--- v2.5.1/linux/drivers/acorn/scsi/acornscsi.c	Thu Oct 11 09:04:57 2001
+++ linux/drivers/acorn/scsi/acornscsi.c	Tue Dec 25 17:04:40 2001
@@ -3142,18 +3142,17 @@
 
 static int __init acornscsi_init(void)
 {
-	acornscsi_template.module = THIS_MODULE;
-	scsi_register_module(MODULE_SCSI_HA, &acornscsi_template);
+	scsi_register_host(&acornscsi_template);
 	if (acornscsi_template.present)
 		return 0;
 
-	scsi_unregister_module(MODULE_SCSI_HA, &acornscsi_template);
+	scsi_unregister_host(&acornscsi_template);
 	return -ENODEV;
 }
 
 static void __exit acornscsi_exit(void)
 {
-	scsi_unregister_module(MODULE_SCSI_HA, &acornscsi_template);
+	scsi_unregister_host(&acornscsi_template);
 }
 
 module_init(acornscsi_init);
diff -u --recursive --new-file v2.5.1/linux/drivers/acorn/scsi/arxescsi.c linux/drivers/acorn/scsi/arxescsi.c
--- v2.5.1/linux/drivers/acorn/scsi/arxescsi.c	Thu Oct 11 09:04:57 2001
+++ linux/drivers/acorn/scsi/arxescsi.c	Tue Dec 25 17:04:40 2001
@@ -423,17 +423,17 @@
 static int __init init_arxe_scsi_driver(void)
 {
         arxescsi_template.module = THIS_MODULE;
-	scsi_register_module(MODULE_SCSI_HA, &arxescsi_template);
+	scsi_register_host(&arxescsi_template);
 	if (arxescsi_template.present)
 		return 0;
 
-	scsi_unregister_module(MODULE_SCSI_HA, &arxescsi_template);
+	scsi_unregister_host(&arxescsi_template);
 	return -ENODEV;
 }
 
 static void __exit exit_arxe_scsi_driver(void)
 {
-	scsi_unregister_module(MODULE_SCSI_HA, &arxescsi_template);
+	scsi_unregister_host(&arxescsi_template);
 }
 
 module_init(init_arxe_scsi_driver);
diff -u --recursive --new-file v2.5.1/linux/drivers/acorn/scsi/cumana_1.c linux/drivers/acorn/scsi/cumana_1.c
--- v2.5.1/linux/drivers/acorn/scsi/cumana_1.c	Thu Sep 13 15:21:32 2001
+++ linux/drivers/acorn/scsi/cumana_1.c	Tue Dec 25 17:04:40 2001
@@ -409,17 +409,17 @@
 
 static int __init cumanascsi_init(void)
 {
-	scsi_register_module(MODULE_SCSI_HA, &cumanascsi_template);
+	scsi_register_host(&cumanascsi_template);
 	if (cumanascsi_template.present)
 		return 0;
 
-	scsi_unregister_module(MODULE_SCSI_HA, &cumanascsi_template);
+	scsi_unregister_host(&cumanascsi_template);
 	return -ENODEV;
 }
 
 static void __exit cumanascsi_exit(void)
 {
-	scsi_unregister_module(MODULE_SCSI_HA, &cumanascsi_template);
+	scsi_unregister_host(&cumanascsi_template);
 }
 
 module_init(cumanascsi_init);
diff -u --recursive --new-file v2.5.1/linux/drivers/acorn/scsi/cumana_2.c linux/drivers/acorn/scsi/cumana_2.c
--- v2.5.1/linux/drivers/acorn/scsi/cumana_2.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/acorn/scsi/cumana_2.c	Tue Dec 25 17:04:40 2001
@@ -579,17 +579,17 @@
 
 static int __init cumanascsi2_init(void)
 {
-	scsi_register_module(MODULE_SCSI_HA, &cumanascsi2_template);
+	scsi_register_host(&cumanascsi2_template);
 	if (cumanascsi2_template.present)
 		return 0;
 
-	scsi_unregister_module(MODULE_SCSI_HA, &cumanascsi2_template);
+	scsi_unregister_host(&cumanascsi2_template);
 	return -ENODEV;
 }
 
 static void __exit cumanascsi2_exit(void)
 {
-	scsi_unregister_module(MODULE_SCSI_HA, &cumanascsi2_template);
+	scsi_unregister_host(&cumanascsi2_template);
 }
 
 module_init(cumanascsi2_init);
diff -u --recursive --new-file v2.5.1/linux/drivers/acorn/scsi/ecoscsi.c linux/drivers/acorn/scsi/ecoscsi.c
--- v2.5.1/linux/drivers/acorn/scsi/ecoscsi.c	Thu Oct 25 13:53:46 2001
+++ linux/drivers/acorn/scsi/ecoscsi.c	Tue Dec 25 17:04:40 2001
@@ -276,17 +276,17 @@
 
 static int __init ecoscsi_init(void)
 {
-	scsi_register_module(MODULE_SCSI_HA, &ecoscsi_template);
+	scsi_register_host(&ecoscsi_template);
 	if (ecoscsi_template.present)
 		return 0;
 
-	scsi_unregister_module(MODULE_SCSI_HA, &ecoscsi_template);
+	scsi_unregister_host(&ecoscsi_template);
 	return -ENODEV;
 }
 
 static void __exit ecoscsi_exit(void)
 {
-	scsi_unregister_module(MODULE_SCSI_HA, &ecoscsi_template);
+	scsi_unregister_host(&ecoscsi_template);
 }
 
 module_init(ecoscsi_init);
diff -u --recursive --new-file v2.5.1/linux/drivers/acorn/scsi/eesox.c linux/drivers/acorn/scsi/eesox.c
--- v2.5.1/linux/drivers/acorn/scsi/eesox.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/acorn/scsi/eesox.c	Tue Dec 25 17:04:40 2001
@@ -581,17 +581,17 @@
 
 static int __init eesox_init(void)
 {
-	scsi_register_module(MODULE_SCSI_HA, &eesox_template);
+	scsi_register_host(&eesox_template);
 	if (eesox_template.present)
 		return 0;
 
-	scsi_unregister_module(MODULE_SCSI_HA, &eesox_template);
+	scsi_unregister_host(&eesox_template);
 	return -ENODEV;
 }
 
 static void __exit eesox_exit(void)
 {
-	scsi_unregister_module(MODULE_SCSI_HA, &eesox_template);
+	scsi_unregister_host(&eesox_template);
 }
 
 module_init(eesox_init);
diff -u --recursive --new-file v2.5.1/linux/drivers/acorn/scsi/oak.c linux/drivers/acorn/scsi/oak.c
--- v2.5.1/linux/drivers/acorn/scsi/oak.c	Thu Oct 11 09:04:57 2001
+++ linux/drivers/acorn/scsi/oak.c	Tue Dec 25 17:04:40 2001
@@ -270,17 +270,17 @@
 
 static int __init oakscsi_init(void)
 {
-	scsi_register_module(MODULE_SCSI_HA, &oakscsi_template);
+	scsi_register_host(&oakscsi_template);
 	if (oakscsi_template.present)
 		return 0;
 
-	scsi_unregister_module(MODULE_SCSI_HA, &oakscsi_template);
+	scsi_unregister_host(&oakscsi_template);
 	return -ENODEV;
 }
 
 static void __exit oakscsi_exit(void)
 {
-	scsi_unregister_module(MODULE_SCSI_HA, &oakscsi_template);
+	scsi_unregister_host(&oakscsi_template);
 }
 
 module_init(oakscsi_init);
diff -u --recursive --new-file v2.5.1/linux/drivers/acorn/scsi/powertec.c linux/drivers/acorn/scsi/powertec.c
--- v2.5.1/linux/drivers/acorn/scsi/powertec.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/acorn/scsi/powertec.c	Tue Dec 25 17:04:40 2001
@@ -481,17 +481,17 @@
 
 static int __init powertecscsi_init(void)
 {
-	scsi_register_module(MODULE_SCSI_HA, &powertecscsi_template);
+	scsi_register_host(&powertecscsi_template);
 	if (powertecscsi_template.present)
 		return 0;
 
-	scsi_unregister_module(MODULE_SCSI_HA, &powertecscsi_template);
+	scsi_unregister_host(&powertecscsi_template);
 	return -ENODEV;
 }
 
 static void __exit powertecscsi_exit(void)
 {
-	scsi_unregister_module(MODULE_SCSI_HA, &powertecscsi_template);
+	scsi_unregister_host(&powertecscsi_template);
 }
 
 module_init(powertecscsi_init);
diff -u --recursive --new-file v2.5.1/linux/drivers/acpi/ospm/ac_adapter/ac_osl.c linux/drivers/acpi/ospm/ac_adapter/ac_osl.c
--- v2.5.1/linux/drivers/acpi/ospm/ac_adapter/ac_osl.c	Wed Oct 24 14:06:22 2001
+++ linux/drivers/acpi/ospm/ac_adapter/ac_osl.c	Sun Dec 30 09:40:59 2001
@@ -35,6 +35,7 @@
 
 MODULE_AUTHOR("Andrew Grover");
 MODULE_DESCRIPTION("ACPI Component Architecture (CA) - AC Adapter Driver");
+MODULE_LICENSE("GPL");
 
 
 #define AC_PROC_ROOT		"ac_adapter"
diff -u --recursive --new-file v2.5.1/linux/drivers/acpi/ospm/battery/bt_osl.c linux/drivers/acpi/ospm/battery/bt_osl.c
--- v2.5.1/linux/drivers/acpi/ospm/battery/bt_osl.c	Wed Oct 24 14:06:22 2001
+++ linux/drivers/acpi/ospm/battery/bt_osl.c	Sun Dec 30 09:40:59 2001
@@ -44,6 +44,7 @@
 
 MODULE_AUTHOR("Andrew Grover");
 MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Control Method Battery Driver");
+MODULE_LICENSE("GPL");
 
 
 #define BT_PROC_ROOT		"battery"
diff -u --recursive --new-file v2.5.1/linux/drivers/acpi/ospm/busmgr/bm_osl.c linux/drivers/acpi/ospm/busmgr/bm_osl.c
--- v2.5.1/linux/drivers/acpi/ospm/busmgr/bm_osl.c	Wed Oct 24 14:06:22 2001
+++ linux/drivers/acpi/ospm/busmgr/bm_osl.c	Sun Dec 30 09:40:59 2001
@@ -38,6 +38,7 @@
 
 MODULE_AUTHOR("Andrew Grover");
 MODULE_DESCRIPTION("ACPI Component Architecture (CA) - ACPI Bus Manager");
+MODULE_LICENSE("GPL");
 
 
 /*****************************************************************************
diff -u --recursive --new-file v2.5.1/linux/drivers/acpi/ospm/button/bn_osl.c linux/drivers/acpi/ospm/button/bn_osl.c
--- v2.5.1/linux/drivers/acpi/ospm/button/bn_osl.c	Wed Oct 24 14:06:22 2001
+++ linux/drivers/acpi/ospm/button/bn_osl.c	Sun Dec 30 09:40:59 2001
@@ -35,6 +35,7 @@
 
 MODULE_AUTHOR("Andrew Grover");
 MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Button Driver");
+MODULE_LICENSE("GPL");
 
 
 #define BN_PROC_ROOT		"button"
diff -u --recursive --new-file v2.5.1/linux/drivers/acpi/ospm/ec/ec_osl.c linux/drivers/acpi/ospm/ec/ec_osl.c
--- v2.5.1/linux/drivers/acpi/ospm/ec/ec_osl.c	Wed Oct 24 14:06:22 2001
+++ linux/drivers/acpi/ospm/ec/ec_osl.c	Sun Dec 30 09:40:59 2001
@@ -36,6 +36,7 @@
 
 MODULE_AUTHOR("Andrew Grover");
 MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Embedded Controller Driver");
+MODULE_LICENSE("GPL");
 
 extern struct proc_dir_entry	*bm_proc_root;
 
diff -u --recursive --new-file v2.5.1/linux/drivers/acpi/ospm/processor/pr_osl.c linux/drivers/acpi/ospm/processor/pr_osl.c
--- v2.5.1/linux/drivers/acpi/ospm/processor/pr_osl.c	Fri Nov  9 13:58:02 2001
+++ linux/drivers/acpi/ospm/processor/pr_osl.c	Sun Dec 30 09:40:59 2001
@@ -37,6 +37,7 @@
 
 MODULE_AUTHOR("Andrew Grover");
 MODULE_DESCRIPTION("ACPI Component Architecture (CA) - IA32 Processor Driver");
+MODULE_LICENSE("GPL");
 
 
 #define PR_PROC_ROOT		"processor"
diff -u --recursive --new-file v2.5.1/linux/drivers/acpi/ospm/system/sm_osl.c linux/drivers/acpi/ospm/system/sm_osl.c
--- v2.5.1/linux/drivers/acpi/ospm/system/sm_osl.c	Wed Oct 24 14:06:22 2001
+++ linux/drivers/acpi/ospm/system/sm_osl.c	Sun Dec 30 09:40:59 2001
@@ -42,6 +42,7 @@
 
 MODULE_AUTHOR("Andrew Grover");
 MODULE_DESCRIPTION("ACPI Component Architecture (CA) - ACPI System Driver");
+MODULE_LICENSE("GPL");
 
 
 #define SM_PROC_INFO		"info"
diff -u --recursive --new-file v2.5.1/linux/drivers/acpi/ospm/thermal/tz_osl.c linux/drivers/acpi/ospm/thermal/tz_osl.c
--- v2.5.1/linux/drivers/acpi/ospm/thermal/tz_osl.c	Wed Oct 24 14:06:22 2001
+++ linux/drivers/acpi/ospm/thermal/tz_osl.c	Sun Dec 30 09:40:59 2001
@@ -35,6 +35,7 @@
 
 MODULE_AUTHOR("Andrew Grover");
 MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Thermal Zone Driver");
+MODULE_LICENSE("GPL");
 
 int TZP = 0;
 MODULE_PARM(TZP, "i");
diff -u --recursive --new-file v2.5.1/linux/drivers/acpi/ospm/thermal/tzpolicy.c linux/drivers/acpi/ospm/thermal/tzpolicy.c
--- v2.5.1/linux/drivers/acpi/ospm/thermal/tzpolicy.c	Wed Oct 24 14:06:22 2001
+++ linux/drivers/acpi/ospm/thermal/tzpolicy.c	Sun Dec 30 16:44:13 2001
@@ -31,6 +31,7 @@
 #include <linux/proc_fs.h>
 #include <linux/sysctl.h>
 #include <linux/pm.h>
+#include <linux/sched.h>
 
 #include <acpi.h>
 #include <bm.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/atm/fore200e.c linux/drivers/atm/fore200e.c
--- v2.5.1/linux/drivers/atm/fore200e.c	Thu Sep 13 15:21:32 2001
+++ linux/drivers/atm/fore200e.c	Sun Dec 30 10:31:51 2001
@@ -39,7 +39,6 @@
 #include <linux/atm_suni.h>
 #include <asm/io.h>
 #include <asm/string.h>
-#include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/irq.h>
 #include <asm/dma.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/block/DAC960.c linux/drivers/block/DAC960.c
--- v2.5.1/linux/drivers/block/DAC960.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/block/DAC960.c	Mon Dec 31 17:56:19 2001
@@ -45,7 +45,6 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <asm/io.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include "DAC960.h"
 
@@ -1974,9 +1973,7 @@
   Controller->GenericDiskInfo.major = MajorNumber;
   Controller->GenericDiskInfo.major_name = "rd";
   Controller->GenericDiskInfo.minor_shift = DAC960_MaxPartitionsBits;
-  Controller->GenericDiskInfo.max_p = DAC960_MaxPartitions;
   Controller->GenericDiskInfo.nr_real = DAC960_MaxLogicalDrives;
-  Controller->GenericDiskInfo.real_devices = Controller;
   Controller->GenericDiskInfo.next = NULL;
   Controller->GenericDiskInfo.fops = &DAC960_BlockDeviceOperations;
   /*
@@ -2025,10 +2022,9 @@
   Information Partition Sector Counts and Block Sizes.
 */
 
-static void DAC960_ComputeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo)
+static void DAC960_ComputeGenericDiskInfo(DAC960_Controller_T *Controller)
 {
-  DAC960_Controller_T *Controller =
-    (DAC960_Controller_T *) GenericDiskInfo->real_devices;
+  GenericDiskInfo_T *GenericDiskInfo = &Controller->GenericDiskInfo;
   int LogicalDriveNumber, i;
   for (LogicalDriveNumber = 0;
        LogicalDriveNumber < DAC960_MaxLogicalDrives;
@@ -2659,7 +2655,7 @@
       int LogicalDriveNumber;
       if (Controller == NULL) continue;
       DAC960_InitializeController(Controller);
-      DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+      DAC960_ComputeGenericDiskInfo(Controller);
       for (LogicalDriveNumber = 0;
 	   LogicalDriveNumber < DAC960_MaxLogicalDrives;
 	   LogicalDriveNumber++)
@@ -3162,7 +3158,7 @@
 				Controller->ControllerNumber,
 				LogicalDriveNumber);
 	      Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives;
-	      DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+	      DAC960_ComputeGenericDiskInfo(Controller);
 	    }
 	  if (NewEnquiry->NumberOfLogicalDrives < Controller->LogicalDriveCount)
 	    {
@@ -3174,7 +3170,7 @@
 				Controller->ControllerNumber,
 				LogicalDriveNumber);
 	      Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives;
-	      DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+	      DAC960_ComputeGenericDiskInfo(Controller);
 	    }
 	  if (NewEnquiry->StatusFlags.DeferredWriteError !=
 	      OldEnquiry->StatusFlags.DeferredWriteError)
@@ -4514,7 +4510,7 @@
 		{
 		  memset(LogicalDeviceInfo, 0,
 			 sizeof(DAC960_V2_LogicalDeviceInfo_T));
-		  DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+		  DAC960_ComputeGenericDiskInfo(Controller);
 		}
 	    }
 	  if (LogicalDeviceInfo != NULL)
@@ -4631,7 +4627,7 @@
 	      kfree(LogicalDeviceInfo);
 	      Controller->LogicalDriveInitiallyAccessible
 			  [LogicalDriveNumber] = false;
-	      DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+	      DAC960_ComputeGenericDiskInfo(Controller);
 	    }
 	  Controller->V2.NeedLogicalDeviceInformation = false;
 	}
@@ -5300,7 +5296,7 @@
   if (!Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber])
     {
       Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber] = true;
-      DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+      DAC960_ComputeGenericDiskInfo(Controller);
       DAC960_RegisterDisk(Controller, LogicalDriveNumber);
     }
   if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0)
diff -u --recursive --new-file v2.5.1/linux/drivers/block/DAC960.h linux/drivers/block/DAC960.h
--- v2.5.1/linux/drivers/block/DAC960.h	Tue Dec 18 14:56:35 2001
+++ linux/drivers/block/DAC960.h	Thu Jan  3 13:51:36 2002
@@ -2054,13 +2054,13 @@
 */
 
 #define DAC960_ControllerNumber(Device) \
-  (MAJOR(Device) - DAC960_MAJOR)
+  (major(Device) - DAC960_MAJOR)
 
 #define DAC960_LogicalDriveNumber(Device) \
-  (MINOR(Device) >> DAC960_MaxPartitionsBits)
+  (minor(Device) >> DAC960_MaxPartitionsBits)
 
 #define DAC960_PartitionNumber(Device) \
-  (MINOR(Device) & (DAC960_MaxPartitions - 1))
+  (minor(Device) & (DAC960_MaxPartitions - 1))
 
 #define DAC960_MajorNumber(ControllerNumber) \
   (DAC960_MAJOR + (ControllerNumber))
diff -u --recursive --new-file v2.5.1/linux/drivers/block/acsi.c linux/drivers/block/acsi.c
--- v2.5.1/linux/drivers/block/acsi.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/block/acsi.c	Mon Dec 31 17:56:19 2001
@@ -1386,10 +1386,8 @@
 	major:		MAJOR_NR,
 	major_name:	"ad",
 	minor_shift:	4,
-	max_p:		1 << 4,
 	part:		acsi_part,
 	sizes:		acsi_sizes,
-	real_devices:	(void *)acsi_info,
 	fops:		&acsi_fops,
 };
 	
diff -u --recursive --new-file v2.5.1/linux/drivers/block/blkpg.c linux/drivers/block/blkpg.c
--- v2.5.1/linux/drivers/block/blkpg.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/block/blkpg.c	Tue Jan  1 11:28:30 2002
@@ -85,14 +85,16 @@
 		return -ENXIO;
 
 	/* existing drive? */
-	drive = (MINOR(dev) >> g->minor_shift);
+	drive = (minor(dev) >> g->minor_shift);
 	first_minor = (drive << g->minor_shift);
-	end_minor   = first_minor + g->max_p;
+	end_minor   = first_minor + (1 << g->minor_shift);
 	if (drive >= g->nr_real)
 		return -ENXIO;
 
 	/* drive and partition number OK? */
-	if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p)
+	if (first_minor != minor(dev))
+		return -EINVAL;
+	if (p->pno <= 0 || p->pno >= (1 << g->minor_shift))
 		return -EINVAL;
 
 	/* partition number in use? */
@@ -136,10 +138,13 @@
 		return -ENXIO;
 
 	/* drive and partition number OK? */
-	drive = (MINOR(dev) >> g->minor_shift);
+	drive = (minor(dev) >> g->minor_shift);
 	first_minor = (drive << g->minor_shift);
-	if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p)
+
+	if (first_minor != minor(dev))
 		return -EINVAL;
+	if (p->pno <= 0 || p->pno >= (1 << g->minor_shift))
+  		return -EINVAL;
 
 	/* existing drive and partition? */
 	minor = first_minor + p->pno;
@@ -147,7 +152,7 @@
 		return -ENXIO;
 
 	/* partition in use? Incomplete check for now. */
-	devp = MKDEV(MAJOR(dev), minor);
+	devp = mk_kdev(major(dev), minor);
 	if (is_mounted(devp) || is_swap_partition(devp))
 		return -EBUSY;
 
@@ -201,8 +206,9 @@
 	struct gendisk *g;
 	u64 ullval = 0;
 	int intval, *iptr;
+	unsigned short usval;
 
-	if (!dev)
+	if (kdev_none(dev))
 		return -EINVAL;
 
 	intval = block_ioctl(dev, cmd, arg);
@@ -226,30 +232,33 @@
 				return -EACCES;
 			if(arg > 0xff)
 				return -EINVAL;
-			read_ahead[MAJOR(dev)] = arg;
+			read_ahead[major(dev)] = arg;
 			return 0;
 		case BLKRAGET:
 			if (!arg)
 				return -EINVAL;
-			return put_user(read_ahead[MAJOR(dev)], (long *) arg);
+			return put_user(read_ahead[major(dev)], (long *) arg);
 
 		case BLKFRASET:
 			if (!capable(CAP_SYS_ADMIN))
 				return -EACCES;
-			if (!(iptr = max_readahead[MAJOR(dev)]))
+			if (!(iptr = max_readahead[major(dev)]))
 				return -EINVAL;
-			iptr[MINOR(dev)] = arg;
+			iptr[minor(dev)] = arg;
 			return 0;
 
 		case BLKFRAGET:
-			if (!(iptr = max_readahead[MAJOR(dev)]))
+			if (!(iptr = max_readahead[major(dev)]))
 				return -EINVAL;
-			return put_user(iptr[MINOR(dev)], (long *) arg);
+			return put_user(iptr[minor(dev)], (long *) arg);
 
 		case BLKSECTGET:
-			if ((q = blk_get_queue(dev)))
-				return put_user(q->max_sectors, (unsigned short *)arg);
-			return -EINVAL;
+			if ((q = blk_get_queue(dev)) == NULL)
+				return -EINVAL;
+
+			usval = q->max_sectors;
+			blk_put_queue(q);
+			return put_user(usval, (unsigned short *)arg);
 
 		case BLKFLSBUF:
 			if (!capable(CAP_SYS_ADMIN))
@@ -267,7 +276,7 @@
 		case BLKGETSIZE64:
 			g = get_gendisk(dev);
 			if (g)
-				ullval = g->part[MINOR(dev)].nr_sects;
+				ullval = g->part[minor(dev)].nr_sects;
 
 			if (cmd == BLKGETSIZE)
 				return put_user((unsigned long)ullval, (unsigned long *)arg);
@@ -291,9 +300,7 @@
 
 		case BLKBSZGET:
 			/* get the logical block size (cf. BLKSSZGET) */
-			intval = BLOCK_SIZE;
-			if (blksize_size[MAJOR(dev)])
-				intval = blksize_size[MAJOR(dev)][MINOR(dev)];
+			intval = block_size(dev);
 			return put_user(intval, (int *) arg);
 
 		case BLKBSZSET:
diff -u --recursive --new-file v2.5.1/linux/drivers/block/block_ioctl.c linux/drivers/block/block_ioctl.c
--- v2.5.1/linux/drivers/block/block_ioctl.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/block/block_ioctl.c	Thu Dec 27 08:15:15 2001
@@ -35,7 +35,7 @@
 	DECLARE_COMPLETION(wait);
 	int err = 0;
 
-	rq->flags |= REQ_BARRIER;
+	rq->flags |= REQ_NOMERGE;
 	rq->waiting = &wait;
 	elv_add_request(q, rq, 1);
 	generic_unplug_device(q);
@@ -76,8 +76,8 @@
 			err = -ENOTTY;
 	}
 
-#if 0
 	blk_put_queue(q);
-#endif
 	return err;
 }
+
+EXPORT_SYMBOL(block_ioctl);
diff -u --recursive --new-file v2.5.1/linux/drivers/block/cciss.c linux/drivers/block/cciss.c
--- v2.5.1/linux/drivers/block/cciss.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/block/cciss.c	Thu Jan  3 11:35:33 2002
@@ -317,8 +317,8 @@
  */
 static int cciss_open(struct inode *inode, struct file *filep)
 {
-	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
-	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
+	int ctlr = major(inode->i_rdev) - MAJOR_NR;
+	int dsk  = minor(inode->i_rdev) >> NWD_SHIFT;
 
 #ifdef CCISS_DEBUG
 	printk(KERN_DEBUG "cciss_open %x (%x:%x)\n", inode->i_rdev, ctlr, dsk);
@@ -327,7 +327,7 @@
 	if (ctlr > MAX_CTLR || hba[ctlr] == NULL)
 		return -ENXIO;
 
-	if (!suser() && hba[ctlr]->sizes[ MINOR(inode->i_rdev)] == 0)
+	if (!suser() && hba[ctlr]->sizes[minor(inode->i_rdev)] == 0)
 		return -ENXIO;
 
 	/*
@@ -337,8 +337,8 @@
 	 * for "raw controller".
 	 */
 	if (suser()
-		&& (hba[ctlr]->sizes[MINOR(inode->i_rdev)] == 0) 
-		&& (MINOR(inode->i_rdev)!= 0))
+		&& (hba[ctlr]->sizes[minor(inode->i_rdev)] == 0) 
+		&& (minor(inode->i_rdev)!= 0))
 		return -ENXIO;
 
 	hba[ctlr]->drv[dsk].usage_count++;
@@ -350,8 +350,8 @@
  */
 static int cciss_release(struct inode *inode, struct file *filep)
 {
-	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
-	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
+	int ctlr = major(inode->i_rdev) - MAJOR_NR;
+	int dsk  = minor(inode->i_rdev) >> NWD_SHIFT;
 
 #ifdef CCISS_DEBUG
 	printk(KERN_DEBUG "cciss_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk);
@@ -370,8 +370,8 @@
 static int cciss_ioctl(struct inode *inode, struct file *filep, 
 		unsigned int cmd, unsigned long arg)
 {
-	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
-	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
+	int ctlr = major(inode->i_rdev) - MAJOR_NR;
+	int dsk  = minor(inode->i_rdev) >> NWD_SHIFT;
 
 #ifdef CCISS_DEBUG
 	printk(KERN_DEBUG "cciss_ioctl: Called with cmd=%x %lx\n", cmd, arg);
@@ -696,8 +696,8 @@
         unsigned long flags;
         int res;
 
-        target = MINOR(dev) >> NWD_SHIFT;
-        ctlr = MAJOR(dev) - MAJOR_NR;
+        target = minor(dev) >> NWD_SHIFT;
+        ctlr = major(dev) - MAJOR_NR;
         gdev = &(hba[ctlr]->gendisk);
 
         spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
@@ -746,8 +746,8 @@
 	int ctlr, i;
 	unsigned long flags;
 
-	ctlr = MAJOR(dev) - MAJOR_NR;
-        if (MINOR(dev) != 0)
+	ctlr = major(dev) - MAJOR_NR;
+        if (minor(dev) != 0)
                 return -ENXIO;
 
         spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
@@ -781,9 +781,11 @@
         hba[ctlr]->access.set_intr_mask(hba[ctlr], CCISS_INTR_ON);
 
         cciss_geninit(ctlr);
-        for(i=0; i<NWD; i++)
+        for(i=0; i<NWD; i++) {
+		kdev_t kdev = mk_kdev(major(dev), i << NWD_SHIFT);
                 if (hba[ctlr]->sizes[ i<<NWD_SHIFT ])
-                        revalidate_logvol(dev+(i<<NWD_SHIFT), 2);
+                        revalidate_logvol(kdev, 2);
+	}
 
         hba[ctlr]->usage_count--;
         return 0;
@@ -1205,7 +1207,6 @@
 	ctlr_info_t *h= q->queuedata; 
 	CommandList_struct *c;
 	int log_unit, start_blk, seg;
-	struct list_head *queue_head = &q->queue_head;
 	struct request *creq;
 	u64bit temp64;
 	struct scatterlist tmp_sg[MAXSGENTRIES];
@@ -1215,17 +1216,17 @@
 		goto startio;
 
 queue:
-	if (list_empty(queue_head))
+	if (blk_queue_empty(q))
 		goto startio;
 
 	creq = elv_next_request(q);
 	if (creq->nr_phys_segments > MAXSGENTRIES)
                 BUG();
 
-        if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR )
+        if (h->ctlr != major(creq->rq_dev)-MAJOR_NR )
         {
                 printk(KERN_WARNING "doreq cmd for %d, %x at %p\n",
-                                h->ctlr, creq->rq_dev, creq);
+                                h->ctlr, major(creq->rq_dev), creq);
                 blkdev_dequeue_request(creq);
                 complete_buffers(creq->bio, 0);
 		end_that_request_last(creq);
@@ -1243,7 +1244,7 @@
 	c->rq = creq;
 	
 	/* fill in the request */ 
-	log_unit = MINOR(creq->rq_dev) >> NWD_SHIFT; 
+	log_unit = minor(creq->rq_dev) >> NWD_SHIFT; 
 	c->Header.ReplyQueue = 0;  // unused in simple mode
 	c->Header.Tag.lower = c->busaddr;  // use the physical address the cmd block for tag
 	c->Header.LUN.LogDev.VolId= hba[h->ctlr]->drv[log_unit].LunID;
@@ -1886,7 +1887,6 @@
 	hba[i]->gendisk.major = MAJOR_NR + i;
 	hba[i]->gendisk.major_name = "cciss";
 	hba[i]->gendisk.minor_shift = NWD_SHIFT;
-	hba[i]->gendisk.max_p = MAX_PART;
 	hba[i]->gendisk.part = hba[i]->hd;
 	hba[i]->gendisk.sizes = hba[i]->sizes;
 	hba[i]->gendisk.nr_real = hba[i]->num_luns;
@@ -1897,7 +1897,7 @@
 	cciss_geninit(i);
 	for(j=0; j<NWD; j++)
 		register_disk(&(hba[i]->gendisk),
-			MKDEV(MAJOR_NR+i, j <<4), 
+			mk_kdev(MAJOR_NR+i, j <<4), 
 			MAX_PART, &cciss_fops, 
 			hba[i]->drv[j].nr_blocks);
 
diff -u --recursive --new-file v2.5.1/linux/drivers/block/cciss.h linux/drivers/block/cciss.h
--- v2.5.1/linux/drivers/block/cciss.h	Tue Dec 18 14:56:35 2001
+++ linux/drivers/block/cciss.h	Mon Dec 31 17:56:19 2001
@@ -8,7 +8,7 @@
 
 #define NWD		16
 #define NWD_SHIFT	4
-#define MAX_PART	16
+#define MAX_PART	(1 << NWD_SHIFT)
 
 #define IO_OK		0
 #define IO_ERROR	1
diff -u --recursive --new-file v2.5.1/linux/drivers/block/cciss_cmd.h linux/drivers/block/cciss_cmd.h
--- v2.5.1/linux/drivers/block/cciss_cmd.h	Tue Dec 18 14:56:35 2001
+++ linux/drivers/block/cciss_cmd.h	Thu Jan  3 11:34:10 2002
@@ -7,7 +7,7 @@
 
 //general boundary defintions
 #define SENSEINFOBYTES          32//note that this value may vary between host implementations
-#define MAXSGENTRIES            32
+#define MAXSGENTRIES            31
 #define MAXREPLYQS              256
 
 //Command Status value
diff -u --recursive --new-file v2.5.1/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c
--- v2.5.1/linux/drivers/block/cpqarray.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/block/cpqarray.c	Thu Jan  3 11:35:33 2002
@@ -483,7 +483,6 @@
 		ida_gendisk[i].major = MAJOR_NR + i;
 		ida_gendisk[i].major_name = "ida";
 		ida_gendisk[i].minor_shift = NWD_SHIFT;
-		ida_gendisk[i].max_p = 16;
 		ida_gendisk[i].part = ida + (i*256);
 		ida_gendisk[i].sizes = ida_sizes + (i*256);
 		ida_gendisk[i].nr_real = 0; 
@@ -500,7 +499,7 @@
 		ida_geninit(i);
 		for(j=0; j<NWD; j++)	
 			register_disk(&ida_gendisk[i], 
-				MKDEV(MAJOR_NR+i,j<<4),
+				mk_kdev(MAJOR_NR+i,j<<4),
 				16, &ida_fops, hba[i]->drv[j].nr_blks);
 
 	}
@@ -777,15 +776,15 @@
  */
 static int ida_open(struct inode *inode, struct file *filep)
 {
-	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
-	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
+	int ctlr = major(inode->i_rdev) - MAJOR_NR;
+	int dsk  = minor(inode->i_rdev) >> NWD_SHIFT;
 
 	DBGINFO(printk("ida_open %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) );
 	if (ctlr > MAX_CTLR || hba[ctlr] == NULL)
 		return -ENXIO;
 
 	if (!suser() && ida_sizes[(ctlr << CTLR_SHIFT) +
-						MINOR(inode->i_rdev)] == 0)
+						minor(inode->i_rdev)] == 0)
 		return -ENXIO;
 
 	/*
@@ -795,8 +794,8 @@
 	 * for "raw controller".
 	 */
 	if (suser()
-		&& ida_sizes[(ctlr << CTLR_SHIFT) + MINOR(inode->i_rdev)] == 0 
-		&& MINOR(inode->i_rdev) != 0)
+		&& ida_sizes[(ctlr << CTLR_SHIFT) + minor(inode->i_rdev)] == 0 
+		&& minor(inode->i_rdev) != 0)
 		return -ENXIO;
 
 	hba[ctlr]->drv[dsk].usage_count++;
@@ -809,8 +808,8 @@
  */
 static int ida_release(struct inode *inode, struct file *filep)
 {
-	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
-	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
+	int ctlr = major(inode->i_rdev) - MAJOR_NR;
+	int dsk  = minor(inode->i_rdev) >> NWD_SHIFT;
 
 	DBGINFO(printk("ida_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) );
 
@@ -858,7 +857,6 @@
 {
 	ctlr_info_t *h = q->queuedata;
 	cmdlist_t *c;
-	struct list_head * queue_head = &q->queue_head;
 	struct request *creq;
 	struct scatterlist tmp_sg[SG_MAX];
 	int i, dir, seg;
@@ -867,17 +865,17 @@
 		goto startio;
 
 queue_next:
-	if (list_empty(queue_head))
+	if (blk_queue_empty(q))
 		goto startio;
 
 	creq = elv_next_request(q);
 	if (creq->nr_phys_segments > SG_MAX)
 		BUG();
 
-	if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR || h->ctlr > nr_ctlr)
+	if (h->ctlr != major(creq->rq_dev)-MAJOR_NR || h->ctlr > nr_ctlr)
 	{
 		printk(KERN_WARNING "doreq cmd for %d, %x at %p\n",
-				h->ctlr, creq->rq_dev, creq);
+				h->ctlr, minor(creq->rq_dev), creq);
 		blkdev_dequeue_request(creq);
 		complete_buffers(creq->bio, 0);
 		end_that_request_last(creq);
@@ -892,7 +890,7 @@
 	spin_unlock_irq(q->queue_lock);
 
 	c->ctlr = h->ctlr;
-	c->hdr.unit = MINOR(creq->rq_dev) >> NWD_SHIFT;
+	c->hdr.unit = minor(creq->rq_dev) >> NWD_SHIFT;
 	c->hdr.size = sizeof(rblk_t) >> 2;
 	c->size += sizeof(rblk_t);
 
@@ -1110,8 +1108,8 @@
  */
 static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg)
 {
-	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
-	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
+	int ctlr = major(inode->i_rdev) - MAJOR_NR;
+	int dsk  = minor(inode->i_rdev) >> NWD_SHIFT;
 	int error;
 	int diskinfo[4];
 	struct hd_geometry *geo = (struct hd_geometry *)arg;
@@ -1493,8 +1491,8 @@
 	int ctlr, i;
 	unsigned long flags;
 
-	ctlr = MAJOR(dev) - MAJOR_NR;
-	if (MINOR(dev) != 0)
+	ctlr = major(dev) - MAJOR_NR;
+	if (minor(dev) != 0)
 		return -ENXIO;
 
 	spin_lock_irqsave(IDA_LOCK(ctlr), flags);
@@ -1527,9 +1525,11 @@
 	hba[ctlr]->access.set_intr_mask(hba[ctlr], FIFO_NOT_EMPTY);
 
 	ida_geninit(ctlr);
-	for(i=0; i<NWD; i++)
+	for(i=0; i<NWD; i++) {
+		kdev_t kdev = mk_kdev(major(dev), i << NWD_SHIFT);
 		if (ida_sizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)])
-			revalidate_logvol(dev+(i<<NWD_SHIFT), 2);
+			revalidate_logvol(kdev, 2);
+	}
 
 	hba[ctlr]->usage_count--;
 	return 0;
@@ -1544,7 +1544,7 @@
 	int res;
 
 	target = DEVICE_NR(dev);
-	ctlr = MAJOR(dev) - MAJOR_NR;
+	ctlr = major(dev) - MAJOR_NR;
 	gdev = &ida_gendisk[ctlr];
 	
 	spin_lock_irqsave(IDA_LOCK(ctlr), flags);
diff -u --recursive --new-file v2.5.1/linux/drivers/block/elevator.c linux/drivers/block/elevator.c
--- v2.5.1/linux/drivers/block/elevator.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/block/elevator.c	Thu Jan  3 11:34:10 2002
@@ -53,7 +53,7 @@
 	 * if .next is a valid request
 	 */
 	next = rq->queuelist.next;
-	if (next == head)
+	if (unlikely(next == head))
 		return 0;
 
 	next_rq = list_entry(next, struct request, queuelist);
@@ -70,7 +70,7 @@
 	 * if the device is different (not a normal case) just check if
 	 * bio is after rq
 	 */
-	if (next_rq->rq_dev != rq->rq_dev)
+	if (!kdev_same(next_rq->rq_dev, rq->rq_dev))
 		return bio->bi_sector > rq->sector;
 
 	/*
@@ -101,7 +101,7 @@
  */
 inline int elv_rq_merge_ok(struct request *rq, struct bio *bio)
 {
-	if (!(rq->flags & REQ_CMD))
+	if (!rq_mergeable(rq))
 		return 0;
 
 	/*
@@ -109,61 +109,92 @@
 	 */
 	if (bio_data_dir(bio) != rq_data_dir(rq))
 		return 0;
-	if (rq->flags & REQ_NOMERGE)
-		return 0;
 
 	/*
 	 * same device and no special stuff set, merge is ok
 	 */
-	if (rq->rq_dev == bio->bi_dev && !rq->waiting && !rq->special)
+	if (kdev_same(rq->rq_dev, bio->bi_dev) && !rq->waiting && !rq->special)
 		return 1;
 
 	return 0;
 }
 
-int elevator_linus_merge(request_queue_t *q, struct request **req,
-			 struct list_head *head, struct bio *bio)
+inline int elv_try_merge(struct request *__rq, struct bio *bio)
 {
-	unsigned int count = bio_sectors(bio);
-	struct list_head *entry = &q->queue_head;
 	int ret = ELEVATOR_NO_MERGE;
+
+	/*
+	 * we can merge and sequence is ok, check if it's possible
+	 */
+	if (elv_rq_merge_ok(__rq, bio)) {
+		if (__rq->sector + __rq->nr_sectors == bio->bi_sector)
+			ret = ELEVATOR_BACK_MERGE;
+		else if (__rq->sector - bio_sectors(bio) == bio->bi_sector)
+			ret = ELEVATOR_FRONT_MERGE;
+	}
+
+	return ret;
+}
+
+inline int elv_try_last_merge(request_queue_t *q, struct request **req,
+			      struct bio *bio)
+{
+	int ret = ELEVATOR_NO_MERGE;
+
+	/*
+	 * give a one-shot try to merging with the last touched
+	 * request
+	 */
+	if (q->last_merge) {
+		struct request *__rq = list_entry_rq(q->last_merge);
+		BUG_ON(__rq->flags & REQ_STARTED);
+
+		if ((ret = elv_try_merge(__rq, bio)))
+			*req = __rq;
+	}
+
+	return ret;
+}
+
+/*
+ * elevator_linux starts here
+ */
+int elevator_linus_merge(request_queue_t *q, struct request **req,
+			 struct bio *bio)
+{
+	struct list_head *entry;
 	struct request *__rq;
+	int ret;
+
+	if ((ret = elv_try_last_merge(q, req, bio)))
+		return ret;
 
 	entry = &q->queue_head;
-	while ((entry = entry->prev) != head) {
+	ret = ELEVATOR_NO_MERGE;
+	while ((entry = entry->prev) != &q->queue_head) {
 		__rq = list_entry_rq(entry);
 
-		prefetch(list_entry_rq(entry->prev));
+		if (__rq->flags & (REQ_BARRIER | REQ_STARTED))
+			break;
 
 		/*
 		 * simply "aging" of requests in queue
 		 */
-		if (__rq->elevator_sequence-- <= 0)
-			break;
-		if (__rq->flags & (REQ_BARRIER | REQ_STARTED))
+		if (elv_linus_sequence(__rq)-- <= 0)
 			break;
 		if (!(__rq->flags & REQ_CMD))
 			continue;
+		if (elv_linus_sequence(__rq) < bio_sectors(bio))
+			break;
 
 		if (!*req && bio_rq_in_between(bio, __rq, &q->queue_head))
 			*req = __rq;
-		if (!elv_rq_merge_ok(__rq, bio))
-			continue;
 
-		if (__rq->elevator_sequence < count)
-			break;
-
-		/*
-		 * we can merge and sequence is ok, check if it's possible
-		 */
-		if (__rq->sector + __rq->nr_sectors == bio->bi_sector) {
-			ret = ELEVATOR_BACK_MERGE;
-			*req = __rq;
-			break;
-		} else if (__rq->sector - count == bio->bi_sector) {
-			ret = ELEVATOR_FRONT_MERGE;
-			__rq->elevator_sequence -= count;
+		if ((ret = elv_try_merge(__rq, bio))) {
+			if (ret == ELEVATOR_FRONT_MERGE)
+				elv_linus_sequence(__rq) -= bio_sectors(bio);
 			*req = __rq;
+			q->last_merge = &__rq->queuelist;
 			break;
 		}
 	}
@@ -183,56 +214,76 @@
 	entry = &req->queuelist;
 	while ((entry = entry->next) != &q->queue_head) {
 		struct request *tmp;
-		prefetch(list_entry_rq(entry->next));
 		tmp = list_entry_rq(entry);
-		tmp->elevator_sequence -= count;
+		elv_linus_sequence(tmp) -= count;
 	}
 }
 
 void elevator_linus_merge_req(struct request *req, struct request *next)
 {
-	if (next->elevator_sequence < req->elevator_sequence)
-		req->elevator_sequence = next->elevator_sequence;
+	if (elv_linus_sequence(next) < elv_linus_sequence(req))
+		elv_linus_sequence(req) = elv_linus_sequence(next);
 }
 
-void elv_add_request_fn(request_queue_t *q, struct request *rq,
-			       struct list_head *insert_here)
+void elevator_linus_add_request(request_queue_t *q, struct request *rq,
+				struct list_head *insert_here)
 {
+	elevator_t *e = &q->elevator;
+	int lat = 0, *latency = e->elevator_data;
+
+	if (!(rq->flags & REQ_BARRIER))
+		lat = latency[rq_data_dir(rq)];
+
+	elv_linus_sequence(rq) = lat;
+
 	list_add(&rq->queuelist, insert_here);
+
+	/*
+	 * new merges must not precede this barrier
+	 */
+	if (rq->flags & REQ_BARRIER)
+		q->last_merge = NULL;
+	else if (!q->last_merge)
+		q->last_merge = &rq->queuelist;
 }
 
-struct request *elv_next_request_fn(request_queue_t *q)
+int elevator_linus_init(request_queue_t *q, elevator_t *e)
 {
-	if (!blk_queue_empty(q))
-		return list_entry(q->queue_head.next, struct request, queuelist);
+	int *latency;
 
-	return NULL;
-}
+	latency = kmalloc(2 * sizeof(int), GFP_KERNEL);
+	if (!latency)
+		return -ENOMEM;
 
-int elv_linus_init(request_queue_t *q, elevator_t *e)
-{
+	latency[READ] = 8192;
+	latency[WRITE] = 16384;
+
+	e->elevator_data = latency;
 	return 0;
 }
 
-void elv_linus_exit(request_queue_t *q, elevator_t *e)
+void elevator_linus_exit(request_queue_t *q, elevator_t *e)
 {
+	kfree(e->elevator_data);
 }
 
 /*
+ * elevator noop
+ *
  * See if we can find a request that this buffer can be coalesced with.
  */
 int elevator_noop_merge(request_queue_t *q, struct request **req,
-			struct list_head *head, struct bio *bio)
+			struct bio *bio)
 {
-	unsigned int count = bio_sectors(bio);
 	struct list_head *entry = &q->queue_head;
 	struct request *__rq;
+	int ret;
 
-	entry = &q->queue_head;
-	while ((entry = entry->prev) != head) {
-		__rq = list_entry_rq(entry);
+	if ((ret = elv_try_last_merge(q, req, bio)))
+		return ret;
 
-		prefetch(list_entry_rq(entry->prev));
+	while ((entry = entry->prev) != &q->queue_head) {
+		__rq = list_entry_rq(entry);
 
 		if (__rq->flags & (REQ_BARRIER | REQ_STARTED))
 			break;
@@ -240,33 +291,47 @@
 		if (!(__rq->flags & REQ_CMD))
 			continue;
 
-		if (!elv_rq_merge_ok(__rq, bio))
-			continue;
-
-		/*
-		 * we can merge and sequence is ok, check if it's possible
-		 */
-		if (__rq->sector + __rq->nr_sectors == bio->bi_sector) {
-			*req = __rq;
-			return ELEVATOR_BACK_MERGE;
-		} else if (__rq->sector - count == bio->bi_sector) {
+		if ((ret = elv_try_merge(__rq, bio))) {
 			*req = __rq;
-			return ELEVATOR_FRONT_MERGE;
+			q->last_merge = &__rq->queuelist;
+			return ret;
 		}
 	}
 
 	return ELEVATOR_NO_MERGE;
 }
 
-void elevator_noop_merge_cleanup(request_queue_t *q, struct request *req, int count) {}
+void elevator_noop_add_request(request_queue_t *q, struct request *rq,
+			       struct list_head *insert_here)
+{
+	list_add_tail(&rq->queuelist, &q->queue_head);
 
-void elevator_noop_merge_req(struct request *req, struct request *next) {}
+	/*
+	 * new merges must not precede this barrier
+	 */
+	if (rq->flags & REQ_BARRIER)
+		q->last_merge = NULL;
+	else if (!q->last_merge)
+		q->last_merge = &rq->queuelist;
+}
 
+struct request *elevator_noop_next_request(request_queue_t *q)
+{
+	if (!blk_queue_empty(q))
+		return list_entry_rq(q->queue_head.next);
+
+	return NULL;
+}
+
+/*
+ * general block -> elevator interface starts here
+ */
 int elevator_init(request_queue_t *q, elevator_t *e, elevator_t type)
 {
 	*e = type;
 
 	INIT_LIST_HEAD(&q->queue_head);
+	q->last_merge = NULL;
 
 	if (e->elevator_init_fn)
 		return e->elevator_init_fn(q, e);
@@ -285,4 +350,77 @@
 	return 0;
 }
 
+void elv_merge_cleanup(request_queue_t *q, struct request *rq,
+		       int nr_sectors)
+{
+	elevator_t *e = &q->elevator;
+
+	if (e->elevator_merge_cleanup_fn)
+		e->elevator_merge_cleanup_fn(q, rq, nr_sectors);
+}
+
+int elv_merge(request_queue_t *q, struct request **rq, struct bio *bio)
+{
+	elevator_t *e = &q->elevator;
+
+	if (e->elevator_merge_fn)
+		return e->elevator_merge_fn(q, rq, bio);
+
+	return ELEVATOR_NO_MERGE;
+}
+
+void elv_merge_requests(request_queue_t *q, struct request *rq,
+			     struct request *next)
+{
+	elevator_t *e = &q->elevator;
+
+	if (e->elevator_merge_req_fn)
+		e->elevator_merge_req_fn(rq, next);
+}
+
+/*
+ * add_request and next_request are required to be supported, naturally
+ */
+void __elv_add_request(request_queue_t *q, struct request *rq,
+			  struct list_head *insert_here)
+{
+	q->elevator.elevator_add_req_fn(q, rq, insert_here);
+}
+
+struct request *__elv_next_request(request_queue_t *q)
+{
+	return q->elevator.elevator_next_req_fn(q);
+}
+
+void elv_remove_request(request_queue_t *q, struct request *rq)
+{
+	elevator_t *e = &q->elevator;
+
+	if (e->elevator_remove_req_fn)
+		e->elevator_remove_req_fn(q, rq);
+}
+
+elevator_t elevator_linus = {
+	elevator_merge_fn:		elevator_linus_merge,
+	elevator_merge_cleanup_fn:	elevator_linus_merge_cleanup,
+	elevator_merge_req_fn:		elevator_linus_merge_req,
+	elevator_next_req_fn:		elevator_noop_next_request,
+	elevator_add_req_fn:		elevator_linus_add_request,
+	elevator_init_fn:		elevator_linus_init,
+	elevator_exit_fn:		elevator_linus_exit,
+};
+
+elevator_t elevator_noop = {
+	elevator_merge_fn:		elevator_noop_merge,
+	elevator_next_req_fn:		elevator_noop_next_request,
+	elevator_add_req_fn:		elevator_noop_add_request,
+};
+
 module_init(elevator_global_init);
+
+EXPORT_SYMBOL(elevator_linus);
+EXPORT_SYMBOL(elevator_noop);
+
+EXPORT_SYMBOL(__elv_add_request);
+EXPORT_SYMBOL(__elv_next_request);
+EXPORT_SYMBOL(elv_remove_request);
diff -u --recursive --new-file v2.5.1/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.5.1/linux/drivers/block/floppy.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/block/floppy.c	Tue Jan  1 11:30:48 2002
@@ -270,10 +270,10 @@
 static int initialising=1;
 
 static inline int TYPE(kdev_t x) {
-	return  (MINOR(x)>>2) & 0x1f;
+	return  (minor(x)>>2) & 0x1f;
 }
 static inline int DRIVE(kdev_t x) {
-	return (MINOR(x)&0x03) | ((MINOR(x)&0x80) >> 5);
+	return (minor(x)&0x03) | ((minor(x)&0x80) >> 5);
 }
 #define ITYPE(x) (((x)>>2) & 0x1f)
 #define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
@@ -2906,7 +2906,7 @@
 			unlock_fdc();
 			return;
 		}
-		if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
+		if (major(CURRENT->rq_dev) != MAJOR_NR)
 			panic(DEVICE_NAME ": request list destroyed");
 
 		device = CURRENT->rq_dev;
@@ -3332,7 +3332,7 @@
 			if (ITYPE(drive_state[cnt].fd_device) == type &&
 			    drive_state[cnt].fd_ref)
 				check_disk_change(
-					MKDEV(FLOPPY_MAJOR,
+					mk_kdev(FLOPPY_MAJOR,
 					      drive_state[cnt].fd_device));
 		}
 	} else {
@@ -3717,7 +3717,7 @@
 	if (TYPE(inode->i_rdev) >= NUMBER(floppy_type))
 		return -ENXIO;
 	old_dev = UDRS->fd_device;
-	if (UDRS->fd_ref && old_dev != MINOR(inode->i_rdev))
+	if (UDRS->fd_ref && old_dev != minor(inode->i_rdev))
 		return -EBUSY;
 
 	if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)){
@@ -3768,11 +3768,11 @@
 		}
 	}
 
-	UDRS->fd_device = MINOR(inode->i_rdev);
-	if (old_dev != -1 && old_dev != MINOR(inode->i_rdev)) {
+	UDRS->fd_device = minor(inode->i_rdev);
+	if (old_dev != -1 && old_dev != minor(inode->i_rdev)) {
 		if (buffer_drive == drive)
 			buffer_track = -1;
-		invalidate_buffers(MKDEV(FLOPPY_MAJOR,old_dev));
+		invalidate_buffers(mk_kdev(FLOPPY_MAJOR,old_dev));
 	}
 
 	/* Allow ioctls if we have write-permissions even if read-only open.
@@ -3806,7 +3806,7 @@
 {
 	int drive = DRIVE(dev);
 
-	if (MAJOR(dev) != MAJOR_NR) {
+	if (major(dev) != MAJOR_NR) {
 		DPRINT("check_floppy_change: not a floppy\n");
 		return 0;
 	}
@@ -3868,7 +3868,7 @@
 			UDRS->generation++;
 		if (NO_GEOM){
 			/* auto-sensing */
-			int size = floppy_blocksizes[MINOR(dev)];
+			int size = floppy_blocksizes[minor(dev)];
 			if (!size)
 				size = 1024;
 			if (!(bh = getblk(dev,0,size))){
@@ -4275,7 +4275,7 @@
 		if (fdc_state[FDC(drive)].version == FDC_NONE)
 			continue;
 		for (i = 0; i<NUMBER(floppy_type); i++)
-			register_disk(NULL, MKDEV(MAJOR_NR,TOMINOR(drive)+i*4),
+			register_disk(NULL, mk_kdev(MAJOR_NR,TOMINOR(drive)+i*4),
 					1, &floppy_fops, 0);
 	}
 	return have_no_fdc;
diff -u --recursive --new-file v2.5.1/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v2.5.1/linux/drivers/block/genhd.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/block/genhd.c	Tue Jan  1 11:29:13 2002
@@ -103,7 +103,7 @@
 get_gendisk(kdev_t dev)
 {
 	struct gendisk *gp = NULL;
-	int maj = MAJOR(dev);
+	int maj = major(dev);
 
 	read_lock(&gendisk_lock);
 	for (gp = gendisk_head; gp; gp = gp->next)
@@ -124,7 +124,7 @@
 
 	gp = get_gendisk(dev);
 	if (gp)
-		return gp->part[MINOR(dev)].start_sect;
+		return gp->part[minor(dev)].start_sect;
 	return 0;
 }
 
@@ -137,7 +137,7 @@
 
 	gp = get_gendisk(dev);
 	if (gp)
-		return gp->part[MINOR(dev)].nr_sects;
+		return gp->part[minor(dev)].nr_sects;
 	return 0;
 }
 
diff -u --recursive --new-file v2.5.1/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.5.1/linux/drivers/block/ll_rw_blk.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/block/ll_rw_blk.c	Thu Jan  3 11:34:10 2002
@@ -109,12 +109,17 @@
  **/
 inline request_queue_t *blk_get_queue(kdev_t dev)
 {
-	struct blk_dev_struct *bdev = blk_dev + MAJOR(dev);
+	struct blk_dev_struct *bdev = blk_dev + major(dev);
 
 	if (bdev->queue)
 		return bdev->queue(dev);
 	else
-		return &blk_dev[MAJOR(dev)].request_queue;
+		return &blk_dev[major(dev)].request_queue;
+}
+
+void blk_queue_prep_rq(request_queue_t *q, prep_rq_fn *pfn)
+{
+	q->prep_rq_fn = pfn;
 }
 
 /**
@@ -150,6 +155,11 @@
 	blk_queue_max_sectors(q, MAX_SECTORS);
 	blk_queue_hardsect_size(q, 512);
 
+	/*
+	 * by default assume old behaviour and bounce for any highmem page
+	 */
+	blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
+
 	init_waitqueue_head(&q->queue_wait);
 }
 
@@ -179,7 +189,6 @@
 	if (dma_addr == BLK_BOUNCE_ISA) {
 		init_emergency_isa_pool();
 		q->bounce_gfp = GFP_NOIO | GFP_DMA;
-		printk("isa pfn %lu, max low %lu, max %lu\n", bounce_pfn, blk_max_low_pfn, blk_max_pfn);
 	} else
 		q->bounce_gfp = GFP_NOHIGHIO;
 
@@ -300,7 +309,7 @@
 {
 	int bit;
 
-	printk("%s: dev %x: ", msg, rq->rq_dev);
+	printk("%s: dev %02x:%02x: ", msg, major(rq->rq_dev), minor(rq->rq_dev));
 	bit = 0;
 	do {
 		if (rq->flags & (1 << bit))
@@ -319,7 +328,7 @@
 /*
  * standard prep_rq_fn that builds 10 byte cmds
  */
-static int ll_10byte_cmd_build(request_queue_t *q, struct request *rq)
+int ll_10byte_cmd_build(request_queue_t *q, struct request *rq)
 {
 	int hard_sect = get_hardsect_size(rq->rq_dev);
 	sector_t block = rq->hard_sector / (hard_sect >> 9);
@@ -477,7 +486,7 @@
 				sg[nsegs - 1].length += nbytes;
 			} else {
 new_segment:
-				sg[nsegs].address = NULL;
+				memset(&sg[nsegs],0,sizeof(struct scatterlist));
 				sg[nsegs].page = bvec->bv_page;
 				sg[nsegs].length = nbytes;
 				sg[nsegs].offset = bvec->bv_offset;
@@ -504,6 +513,7 @@
 
 	if (req->nr_phys_segments + nr_phys_segs > q->max_phys_segments) {
 		req->flags |= REQ_NOMERGE;
+		q->last_merge = NULL;
 		return 0;
 	}
 
@@ -520,9 +530,12 @@
 				    struct bio *bio)
 {
 	int nr_hw_segs = bio_hw_segments(q, bio);
+	int nr_phys_segs = bio_phys_segments(q, bio);
 
-	if (req->nr_hw_segments + nr_hw_segs > q->max_hw_segments) {
+	if (req->nr_hw_segments + nr_hw_segs > q->max_hw_segments
+	    || req->nr_phys_segments + nr_phys_segs > q->max_phys_segments) {
 		req->flags |= REQ_NOMERGE;
+		q->last_merge = NULL;
 		return 0;
 	}
 
@@ -531,7 +544,7 @@
 	 * counters.
 	 */
 	req->nr_hw_segments += nr_hw_segs;
-	req->nr_phys_segments += bio_phys_segments(q, bio);
+	req->nr_phys_segments += nr_phys_segs;
 	return 1;
 }
 
@@ -540,11 +553,11 @@
 {
 	if (req->nr_sectors + bio_sectors(bio) > q->max_sectors) {
 		req->flags |= REQ_NOMERGE;
+		q->last_merge = NULL;
 		return 0;
 	}
 
-	if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(req->biotail),
-				  __BVEC_START(bio)))
+	if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(req->biotail), __BVEC_START(bio)))
 		return ll_new_mergeable(q, req, bio);
 
 	return ll_new_hw_segment(q, req, bio);
@@ -555,11 +568,11 @@
 {
 	if (req->nr_sectors + bio_sectors(bio) > q->max_sectors) {
 		req->flags |= REQ_NOMERGE;
+		q->last_merge = NULL;
 		return 0;
 	}
 
-	if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio),
-				  __BVEC_START(req->bio)))
+	if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio), __BVEC_START(req->bio)))
 		return ll_new_mergeable(q, req, bio);
 
 	return ll_new_hw_segment(q, req, bio);
@@ -568,7 +581,7 @@
 static int ll_merge_requests_fn(request_queue_t *q, struct request *req,
 				struct request *next)
 {
-	int total_phys_segments = req->nr_phys_segments + next->nr_phys_segments;
+	int total_phys_segments = req->nr_phys_segments +next->nr_phys_segments;
 	int total_hw_segments = req->nr_hw_segments + next->nr_hw_segments;
 
 	/*
@@ -790,7 +803,7 @@
 	if (blk_init_free_list(q))
 		return -ENOMEM;
 
-	if ((ret = elevator_init(q, &q->elevator, ELEVATOR_LINUS))) {
+	if ((ret = elevator_init(q, &q->elevator, elevator_linus))) {
 		blk_cleanup_queue(q);
 		return ret;
 	}
@@ -799,22 +812,21 @@
 	q->back_merge_fn       	= ll_back_merge_fn;
 	q->front_merge_fn      	= ll_front_merge_fn;
 	q->merge_requests_fn	= ll_merge_requests_fn;
-	q->prep_rq_fn		= ll_10byte_cmd_build;
+	q->prep_rq_fn		= NULL;
 	q->plug_tq.sync		= 0;
 	q->plug_tq.routine	= &generic_unplug_device;
 	q->plug_tq.data		= q;
 	q->queue_flags		= (1 << QUEUE_FLAG_CLUSTER);
 	q->queue_lock		= lock;
+	q->last_merge		= NULL;
 	
-	/*
-	 * by default assume old behaviour and bounce for any highmem page
-	 */
-	blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
-
 	blk_queue_segment_boundary(q, 0xffffffff);
 
 	blk_queue_make_request(q, __make_request);
 	blk_queue_max_segment_size(q, MAX_SEGMENT_SIZE);
+
+	blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS);
+	blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
 	return 0;
 }
 
@@ -874,11 +886,19 @@
 
 	BUG_ON(rw != READ && rw != WRITE);
 
+	spin_lock_irq(q->queue_lock);
 	rq = get_request(q, rw);
+	spin_unlock_irq(q->queue_lock);
 
 	if (!rq && (gfp_mask & __GFP_WAIT))
 		rq = get_request_wait(q, rw);
 
+	if (rq) {
+		rq->flags = 0;
+		rq->buffer = NULL;
+		rq->bio = rq->biotail = NULL;
+		rq->waiting = NULL;
+	}
 	return rq;
 }
 
@@ -895,8 +915,8 @@
 {
 	int minor,major;
 
-	major = MAJOR(dev);
-	minor = MINOR(dev);
+	major = major(dev);
+	minor = minor(dev);
 	if (major < 0 || major >= MAX_BLKDEV) return 0;
 	return ro_bits[major][minor >> 5] & (1 << (minor & 31));
 }
@@ -905,8 +925,8 @@
 {
 	int minor,major;
 
-	major = MAJOR(dev);
-	minor = MINOR(dev);
+	major = major(dev);
+	minor = minor(dev);
 	if (major < 0 || major >= MAX_BLKDEV) return;
 	if (flag) ro_bits[major][minor >> 5] |= 1 << (minor & 31);
 	else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31));
@@ -914,7 +934,7 @@
 
 void drive_stat_acct(struct request *rq, int nr_sectors, int new_io)
 {
-	unsigned int major = MAJOR(rq->rq_dev);
+	unsigned int major = major(rq->rq_dev);
 	int rw = rq_data_dir(rq);
 	unsigned int index;
 
@@ -944,19 +964,16 @@
 	drive_stat_acct(req, req->nr_sectors, 1);
 
 	/*
-	 * debug stuff...
+	 * it's a bug to let this rq preempt an already started request
 	 */
-	if (insert_here == &q->queue_head) {
-		struct request *__rq = __elv_next_request(q);
-
-		BUG_ON(__rq && (__rq->flags & REQ_STARTED));
-	}
+	if (insert_here->next != &q->queue_head)
+		BUG_ON(list_entry_rq(insert_here->next)->flags & REQ_STARTED);
 
 	/*
 	 * elevator indicated where it wants this request to be
 	 * inserted at elevator_merge time
 	 */
-	q->elevator.elevator_add_req_fn(q, req, insert_here);
+	__elv_add_request(q, req, insert_here);
 }
 
 /*
@@ -965,11 +982,17 @@
 void blkdev_release_request(struct request *req)
 {
 	struct request_list *rl = req->rl;
+	request_queue_t *q = req->q;
 
 	req->rq_status = RQ_INACTIVE;
 	req->q = NULL;
 	req->rl = NULL;
 
+	if (q) {
+		if (q->last_merge == &req->queuelist)
+			q->last_merge = NULL;
+	}
+
 	/*
 	 * Request may not have originated from ll_rw_blk. if not,
 	 * it didn't come out of our reserved rq pools
@@ -985,14 +1008,10 @@
 /*
  * Has to be called with the request spinlock acquired
  */
-static void attempt_merge(request_queue_t *q, struct request *req)
+static void attempt_merge(request_queue_t *q, struct request *req,
+			  struct request *next)
 {
-	struct request *next = blkdev_next_request(req);
-
-	/*
-	 * not a rw command
-	 */
-	if (!(next->flags & REQ_CMD))
+	if (!rq_mergeable(req) || !rq_mergeable(next))
 		return;
 
 	/*
@@ -1001,26 +1020,20 @@
 	if (req->sector + req->nr_sectors != next->sector)
 		return;
 
-	/*
-	 * don't touch NOMERGE rq, or one that has been started by driver
-	 */
-	if (next->flags & (REQ_NOMERGE | REQ_STARTED))
-		return;
-
 	if (rq_data_dir(req) != rq_data_dir(next)
-	    || req->rq_dev != next->rq_dev
+	    || !kdev_same(req->rq_dev, next->rq_dev)
 	    || req->nr_sectors + next->nr_sectors > q->max_sectors
 	    || next->waiting || next->special)
 		return;
 
 	/*
-	 * If we are not allowed to merge these requests, then
-	 * return.  If we are allowed to merge, then the count
-	 * will have been updated to the appropriate number,
-	 * and we shouldn't do it here too.
+	 * If we are allowed to merge, then append bio list
+	 * from next to rq and release next. merge_requests_fn
+	 * will have updated segment counts, update sector
+	 * counts here.
 	 */
 	if (q->merge_requests_fn(q, req, next)) {
-		q->elevator.elevator_merge_req_fn(req, next);
+		elv_merge_requests(q, req, next);
 
 		blkdev_dequeue_request(next);
 
@@ -1035,24 +1048,18 @@
 
 static inline void attempt_back_merge(request_queue_t *q, struct request *rq)
 {
-	if (&rq->queuelist != q->queue_head.prev)
-		attempt_merge(q, rq);
+	struct list_head *next = rq->queuelist.next;
+
+	if (next != &q->queue_head)
+		attempt_merge(q, rq, list_entry_rq(next));
 }
 
-static inline void attempt_front_merge(request_queue_t *q,
-				       struct list_head *head,
-				       struct request *rq)
+static inline void attempt_front_merge(request_queue_t *q, struct request *rq)
 {
 	struct list_head *prev = rq->queuelist.prev;
 
-	if (prev != head)
-		attempt_merge(q, blkdev_entry_to_request(prev));
-}
-
-static inline void __blk_attempt_remerge(request_queue_t *q, struct request *rq)
-{
-	if (rq->queuelist.next != &q->queue_head)
-		attempt_merge(q, rq);
+	if (prev != &q->queue_head)
+		attempt_merge(q, list_entry_rq(prev), rq);
 }
 
 /**
@@ -1073,16 +1080,15 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(q->queue_lock, flags);
-	__blk_attempt_remerge(q, rq);
+	attempt_back_merge(q, rq);
 	spin_unlock_irqrestore(q->queue_lock, flags);
 }
 
 static int __make_request(request_queue_t *q, struct bio *bio)
 {
 	struct request *req, *freereq = NULL;
-	int el_ret, latency = 0, rw, nr_sectors, cur_nr_sectors, barrier;
-	struct list_head *head, *insert_here;
-	elevator_t *elevator = &q->elevator;
+	int el_ret, rw, nr_sectors, cur_nr_sectors, barrier;
+	struct list_head *insert_here;
 	sector_t sector;
 
 	sector = bio->bi_sector;
@@ -1099,35 +1105,26 @@
 
 	spin_lock_prefetch(q->queue_lock);
 
-	latency = elevator_request_latency(elevator, rw);
 	barrier = test_bit(BIO_RW_BARRIER, &bio->bi_rw);
 
+	spin_lock_irq(q->queue_lock);
 again:
 	req = NULL;
-	head = &q->queue_head;
+	insert_here = q->queue_head.prev;
 
-	spin_lock_irq(q->queue_lock);
-
-	insert_here = head->prev;
 	if (blk_queue_empty(q) || barrier) {
 		blk_plug_device(q);
 		goto get_rq;
-	} else if ((req = __elv_next_request(q))) {
-		if (req->flags & REQ_STARTED)
-			head = head->next;
-
-		req = NULL;
 	}
 
-	el_ret = elevator->elevator_merge_fn(q, &req, head, bio);
+	el_ret = elv_merge(q, &req, bio);
 	switch (el_ret) {
 		case ELEVATOR_BACK_MERGE:
-			BUG_ON(req->flags & REQ_STARTED);
-			BUG_ON(req->flags & REQ_NOMERGE);
+			BUG_ON(!rq_mergeable(req));
 			if (!q->back_merge_fn(q, req, bio))
 				break;
 
-			elevator->elevator_merge_cleanup_fn(q, req, nr_sectors);
+			elv_merge_cleanup(q, req, nr_sectors);
 
 			req->biotail->bi_next = bio;
 			req->biotail = bio;
@@ -1137,12 +1134,11 @@
 			goto out;
 
 		case ELEVATOR_FRONT_MERGE:
-			BUG_ON(req->flags & REQ_STARTED);
-			BUG_ON(req->flags & REQ_NOMERGE);
+			BUG_ON(!rq_mergeable(req));
 			if (!q->front_merge_fn(q, req, bio))
 				break;
 
-			elevator->elevator_merge_cleanup_fn(q, req, nr_sectors);
+			elv_merge_cleanup(q, req, nr_sectors);
 
 			bio->bi_next = req->bio;
 			req->bio = bio;
@@ -1157,7 +1153,7 @@
 			req->sector = req->hard_sector = sector;
 			req->nr_sectors = req->hard_nr_sectors += nr_sectors;
 			drive_stat_acct(req, nr_sectors, 0);
-			attempt_front_merge(q, head, req);
+			attempt_front_merge(q, req);
 			goto out;
 
 		/*
@@ -1188,7 +1184,6 @@
 		req = freereq;
 		freereq = NULL;
 	} else if ((req = get_request(q, rw)) == NULL) {
-
 		spin_unlock_irq(q->queue_lock);
 
 		/*
@@ -1200,15 +1195,11 @@
 		}
 
 		freereq = get_request_wait(q, rw);
+		spin_lock_irq(q->queue_lock);
 		goto again;
 	}
 
 	/*
-	 * fill up the request-info, and add it to the queue
-	 */
-	req->elevator_sequence = latency;
-
-	/*
 	 * first three bits are identical in rq->flags and bio->bi_rw,
 	 * see bio.h and blkdev.h
 	 */
@@ -1252,14 +1243,14 @@
 	struct gendisk *g;
 	kdev_t dev0;
 
-	major = MAJOR(bio->bi_dev);
+	major = major(bio->bi_dev);
 	if ((g = get_gendisk(bio->bi_dev))) {
-		minor = MINOR(bio->bi_dev);
+		minor = minor(bio->bi_dev);
 		drive = (minor >> g->minor_shift);
 		minor0 = (drive << g->minor_shift); /* whole disk device */
 		/* that is, minor0 = (minor & ~((1<<g->minor_shift)-1)); */
-		dev0 = MKDEV(major, minor0);
-		if (dev0 != bio->bi_dev) {
+		dev0 = mk_kdev(major, minor0);
+		if (!kdev_same(dev0, bio->bi_dev)) {
 			bio->bi_dev = dev0;
 			bio->bi_sector += g->part[minor].start_sect;
 		}
@@ -1294,11 +1285,11 @@
  * */
 void generic_make_request(struct bio *bio)
 {
-	int major = MAJOR(bio->bi_dev);
-	int minor = MINOR(bio->bi_dev);
+	int major = major(bio->bi_dev);
+	int minor = minor(bio->bi_dev);
 	request_queue_t *q;
 	sector_t minorsize = 0;
-	int nr_sectors = bio_sectors(bio);
+	int ret, nr_sectors = bio_sectors(bio);
 
 	/* Test device or partition size, when known. */
 	if (blk_size[major])
@@ -1352,7 +1343,10 @@
 		 */
 		blk_partition_remap(bio);
 
-	} while (q->make_request_fn(q, bio));
+		ret = q->make_request_fn(q, bio);
+		blk_put_queue(q);
+
+	} while (ret);
 }
 
 /*
@@ -1481,7 +1475,7 @@
 	if (!nr)
 		return;
 
-	major = MAJOR(bhs[0]->b_dev);
+	major = major(bhs[0]->b_dev);
 
 	/* Determine correct block size for this device. */
 	correct_size = get_hardsect_size(bhs[0]->b_dev);
@@ -1572,21 +1566,23 @@
 
 inline void blk_recalc_rq_sectors(struct request *rq, int nsect)
 {
-	rq->hard_sector += nsect;
-	rq->hard_nr_sectors -= nsect;
-	rq->sector = rq->hard_sector;
-	rq->nr_sectors = rq->hard_nr_sectors;
+	if (rq->flags & REQ_CMD) {
+		rq->hard_sector += nsect;
+		rq->hard_nr_sectors -= nsect;
+		rq->sector = rq->hard_sector;
+		rq->nr_sectors = rq->hard_nr_sectors;
 
-	rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
-	rq->hard_cur_sectors = rq->current_nr_sectors;
+		rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
+		rq->hard_cur_sectors = rq->current_nr_sectors;
 
-	/*
-	 * if total number of sectors is less than the first segment
-	 * size, something has gone terribly wrong
-	 */
-	if (rq->nr_sectors < rq->current_nr_sectors) {
-		printk("blk: request botched\n");
-		rq->nr_sectors = rq->current_nr_sectors;
+		/*
+		 * if total number of sectors is less than the first segment
+		 * size, something has gone terribly wrong
+		 */
+		if (rq->nr_sectors < rq->current_nr_sectors) {
+			printk("blk: request botched\n");
+			rq->nr_sectors = rq->current_nr_sectors;
+		}
 	}
 }
 
@@ -1755,3 +1751,6 @@
 EXPORT_SYMBOL(blk_queue_assign_lock);
 EXPORT_SYMBOL(blk_phys_contig_segment);
 EXPORT_SYMBOL(blk_hw_contig_segment);
+
+EXPORT_SYMBOL(ll_10byte_cmd_build);
+EXPORT_SYMBOL(blk_queue_prep_rq);
diff -u --recursive --new-file v2.5.1/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.5.1/linux/drivers/block/loop.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/block/loop.c	Thu Jan  3 11:36:51 2002
@@ -155,8 +155,8 @@
 {
 	if (S_ISREG(lo_dentry->d_inode->i_mode))
 		return (lo_dentry->d_inode->i_size - lo->lo_offset) >> BLOCK_SIZE_BITS;
-	if (blk_size[MAJOR(lodev)])
-		return blk_size[MAJOR(lodev)][MINOR(lodev)] -
+	if (blk_size[major(lodev)])
+		return blk_size[major(lodev)][minor(lodev)] -
                                 (lo->lo_offset >> BLOCK_SIZE_BITS);
 	return MAX_DISK_SIZE;
 }
@@ -284,14 +284,7 @@
 
 static inline int loop_get_bs(struct loop_device *lo)
 {
-	int bs = 0;
-
-	if (blksize_size[MAJOR(lo->lo_device)])
-		bs = blksize_size[MAJOR(lo->lo_device)][MINOR(lo->lo_device)];
-	if (!bs)
-		bs = BLOCK_SIZE;	
-
-	return bs;
+	return block_size(lo->lo_device);
 }
 
 static inline unsigned long loop_get_iv(struct loop_device *lo,
@@ -386,12 +379,11 @@
  */
 static int loop_end_io_transfer(struct bio *bio, int nr_sectors)
 {
-	struct loop_device *lo = &loop_dev[MINOR(bio->bi_dev)];
+	struct bio *rbh = bio->bi_private;
+	struct loop_device *lo = &loop_dev[minor(rbh->bi_dev)];
 	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 
 	if (!uptodate || bio_rw(bio) == WRITE) {
-		struct bio *rbh = bio->bi_private;
-
 		bio_endio(rbh, uptodate, nr_sectors);
 		if (atomic_dec_and_test(&lo->lo_pending))
 			up(&lo->lo_bh_mutex);
@@ -436,10 +428,10 @@
 	unsigned long IV;
 	int rw = bio_rw(rbh);
 
-	if (MINOR(rbh->bi_dev) >= max_loop)
+	if (minor(rbh->bi_dev) >= max_loop)
 		goto out;
 
-	lo = &loop_dev[MINOR(rbh->bi_dev)];
+	lo = &loop_dev[minor(rbh->bi_dev)];
 	spin_lock_irq(&lo->lo_lock);
 	if (lo->lo_state != Lo_bound)
 		goto inactive;
@@ -559,6 +551,8 @@
 	atomic_inc(&lo->lo_pending);
 	spin_unlock_irq(&lo->lo_lock);
 
+	current->flags |= PF_NOIO;
+
 	/*
 	 * up sem, we are running
 	 */
@@ -600,7 +594,6 @@
 	kdev_t		lo_device;
 	int		lo_flags = 0;
 	int		error;
-	int		bs;
 
 	MOD_INC_USE_COUNT;
 
@@ -621,6 +614,10 @@
 
 	if (S_ISBLK(inode->i_mode)) {
 		lo_device = inode->i_rdev;
+		if (kdev_same(lo_device, dev)) {
+			error = -EBUSY;
+			goto out;
+		}
 	} else if (S_ISREG(inode->i_mode)) {
 		struct address_space_operations *aops = inode->i_mapping->a_ops;
 		/*
@@ -656,13 +653,7 @@
 	lo->old_gfp_mask = inode->i_mapping->gfp_mask;
 	inode->i_mapping->gfp_mask = GFP_NOIO;
 
-	bs = 0;
-	if (blksize_size[MAJOR(lo_device)])
-		bs = blksize_size[MAJOR(lo_device)][MINOR(lo_device)];
-	if (!bs)
-		bs = BLOCK_SIZE;
-
-	set_blocksize(dev, bs);
+	set_blocksize(dev, block_size(lo_device));
 
 	lo->lo_bio = lo->lo_biotail = NULL;
 	kernel_thread(loop_thread, lo, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
@@ -733,7 +724,7 @@
 	loop_release_xfer(lo);
 	lo->transfer = NULL;
 	lo->ioctl = NULL;
-	lo->lo_device = 0;
+	lo->lo_device = NODEV;
 	lo->lo_encrypt_type = 0;
 	lo->lo_offset = 0;
 	lo->lo_encrypt_key_size = 0;
@@ -826,12 +817,12 @@
 
 	if (!inode)
 		return -EINVAL;
-	if (MAJOR(inode->i_rdev) != MAJOR_NR) {
+	if (major(inode->i_rdev) != MAJOR_NR) {
 		printk(KERN_WARNING "lo_ioctl: pseudo-major != %d\n",
 		       MAJOR_NR);
 		return -ENODEV;
 	}
-	dev = MINOR(inode->i_rdev);
+	dev = minor(inode->i_rdev);
 	if (dev >= max_loop)
 		return -ENODEV;
 	lo = &loop_dev[dev];
@@ -881,11 +872,11 @@
 
 	if (!inode)
 		return -EINVAL;
-	if (MAJOR(inode->i_rdev) != MAJOR_NR) {
+	if (major(inode->i_rdev) != MAJOR_NR) {
 		printk(KERN_WARNING "lo_open: pseudo-major != %d\n", MAJOR_NR);
 		return -ENODEV;
 	}
-	dev = MINOR(inode->i_rdev);
+	dev = minor(inode->i_rdev);
 	if (dev >= max_loop)
 		return -ENODEV;
 
@@ -908,12 +899,12 @@
 
 	if (!inode)
 		return 0;
-	if (MAJOR(inode->i_rdev) != MAJOR_NR) {
+	if (major(inode->i_rdev) != MAJOR_NR) {
 		printk(KERN_WARNING "lo_release: pseudo-major != %d\n",
 		       MAJOR_NR);
 		return 0;
 	}
-	dev = MINOR(inode->i_rdev);
+	dev = minor(inode->i_rdev);
 	if (dev >= max_loop)
 		return 0;
 
@@ -1007,6 +998,7 @@
 		goto out_mem;
 
 	blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), loop_make_request);
+	blk_queue_bounce_limit(BLK_DEFAULT_QUEUE(MAJOR_NR), BLK_BOUNCE_HIGH);
 
 	for (i = 0; i < max_loop; i++) {
 		struct loop_device *lo = &loop_dev[i];
@@ -1023,7 +1015,7 @@
 	blk_size[MAJOR_NR] = loop_sizes;
 	blksize_size[MAJOR_NR] = loop_blksizes;
 	for (i = 0; i < max_loop; i++)
-		register_disk(NULL, MKDEV(MAJOR_NR, i), 1, &lo_fops, 0);
+		register_disk(NULL, mk_kdev(MAJOR_NR, i), 1, &lo_fops, 0);
 
 	printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop);
 	return 0;
diff -u --recursive --new-file v2.5.1/linux/drivers/block/nbd.c linux/drivers/block/nbd.c
--- v2.5.1/linux/drivers/block/nbd.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/block/nbd.c	Sun Dec 30 10:31:51 2001
@@ -45,7 +45,6 @@
 
 #include <linux/devfs_fs_kernel.h>
 
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <asm/types.h>
 
diff -u --recursive --new-file v2.5.1/linux/drivers/block/paride/Config.in linux/drivers/block/paride/Config.in
--- v2.5.1/linux/drivers/block/paride/Config.in	Thu Oct 25 00:07:39 2001
+++ linux/drivers/block/paride/Config.in	Sun Dec 30 10:19:58 2001
@@ -29,7 +29,7 @@
 dep_tristate '    Shuttle EPAT/EPEZ protocol' CONFIG_PARIDE_EPAT $CONFIG_PARIDE
 if [ "$CONFIG_PARIDE_EPAT" != "n" ]; then
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    bool '     Support c7/c8 chips (EXPERIMENTAL)' CONFIG_PARIDE_EPATC8 $CONFIG_PARIDE
+    bool '     Support c7/c8 chips (EXPERIMENTAL)' CONFIG_PARIDE_EPATC8
   fi
 fi
 
diff -u --recursive --new-file v2.5.1/linux/drivers/block/paride/pd.c linux/drivers/block/paride/pd.c
--- v2.5.1/linux/drivers/block/paride/pd.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/block/paride/pd.c	Mon Dec 31 17:56:19 2001
@@ -347,7 +347,6 @@
 	major:		PD_MAJOR,
 	major_name:	PD_NAME,
 	minor_shift:	PD_BITS,
-	max_p:		PD_PARTNS,
 	part:		pd_hd,
 	sizes:		pd_sizes,
 	fops:		&pd_fops,
diff -u --recursive --new-file v2.5.1/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c
--- v2.5.1/linux/drivers/block/ps2esdi.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/block/ps2esdi.c	Mon Dec 31 17:56:19 2001
@@ -51,7 +51,6 @@
 
 #include <asm/system.h>
 #include <asm/io.h>
-#include <asm/segment.h>
 #include <asm/dma.h>
 #include <asm/mca_dma.h>
 #include <asm/uaccess.h>
@@ -161,10 +160,8 @@
 	major:		MAJOR_NR,
 	major_name:	"ed",
 	minor_shift:	6,
-	max_p:		1 << 6,
 	part:		ps2esdi,
 	sizes:		ps2esdi_sizes,
-	real_devices:	(void *)ps2esdi_info,
 	fops:		&ps2esdi_fops,
 };
 
@@ -953,10 +950,10 @@
 		break;
 	}
 	if(ending != -1) {
-		spin_lock_irqsave(ps2esdi_LOCK, flags);
+		spin_lock_irqsave(&ps2esdi_lock, flags);
 		end_request(ending);
 		do_ps2esdi_request(BLK_DEFAULT_QUEUE(MAJOR_NR));
-		spin_unlock_irqrestore(ps2esdi_LOCK, flags);
+		spin_unlock_irqrestore(&ps2esdi_lock, flags);
 	}
 }				/* handle interrupts */
 
diff -u --recursive --new-file v2.5.1/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v2.5.1/linux/drivers/block/rd.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/block/rd.c	Tue Jan  1 14:41:04 2002
@@ -43,26 +43,12 @@
  */
 
 #include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/hdreg.h>
 #include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
 #include <linux/slab.h>
-#include <linux/ioctl.h>
-#include <linux/fd.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/devfs_fs_kernel.h>
-#include <linux/smp_lock.h>
-
-#include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/byteorder.h>
-
-extern void wait_for_keypress(void);
 
 /*
  * 35 has been officially registered as the RAMDISK major number, but
@@ -79,6 +65,8 @@
 #ifdef CONFIG_BLK_DEV_INITRD
 static int initrd_users;
 static spinlock_t initrd_users_lock = SPIN_LOCK_UNLOCKED;
+unsigned long initrd_start, initrd_end;
+int initrd_below_start_ok;
 #endif
 
 /* Various static variables go here.  Most are used only in the RAM disk code.
@@ -111,70 +99,6 @@
  */
 int rd_blocksize = BLOCK_SIZE;			/* blocksize of the RAM disks */
 
-#ifndef MODULE
-
-int rd_doload;			/* 1 = load RAM disk, 0 = don't load */
-int rd_prompt = 1;		/* 1 = prompt for RAM disk, 0 = don't prompt */
-int rd_image_start;		/* starting block # of image */
-#ifdef CONFIG_BLK_DEV_INITRD
-unsigned long initrd_start, initrd_end;
-int mount_initrd = 1;		/* zero if initrd should not be mounted */
-int initrd_below_start_ok;
-
-static int __init no_initrd(char *str)
-{
-	mount_initrd = 0;
-	return 1;
-}
-
-__setup("noinitrd", no_initrd);
-
-#endif
-
-static int __init ramdisk_start_setup(char *str)
-{
-	rd_image_start = simple_strtol(str,NULL,0);
-	return 1;
-}
-
-static int __init load_ramdisk(char *str)
-{
-	rd_doload = simple_strtol(str,NULL,0) & 3;
-	return 1;
-}
-
-static int __init prompt_ramdisk(char *str)
-{
-	rd_prompt = simple_strtol(str,NULL,0) & 1;
-	return 1;
-}
-
-static int __init ramdisk_size(char *str)
-{
-	rd_size = simple_strtol(str,NULL,0);
-	return 1;
-}
-
-static int __init ramdisk_size2(char *str)
-{
-	return ramdisk_size(str);
-}
-
-static int __init ramdisk_blocksize(char *str)
-{
-	rd_blocksize = simple_strtol(str,NULL,0);
-	return 1;
-}
-
-__setup("ramdisk_start=", ramdisk_start_setup);
-__setup("load_ramdisk=", load_ramdisk);
-__setup("prompt_ramdisk=", prompt_ramdisk);
-__setup("ramdisk=", ramdisk_size);
-__setup("ramdisk_size=", ramdisk_size2);
-__setup("ramdisk_blocksize=", ramdisk_blocksize);
-
-#endif
-
 /*
  * Copyright (C) 2000 Linus Torvalds.
  *               2000 Transmeta Corp.
@@ -322,7 +246,7 @@
 	unsigned long offset, len;
 	int rw = sbh->bi_rw;
 
-	minor = MINOR(sbh->bi_dev);
+	minor = minor(sbh->bi_dev);
 
 	if (minor >= NUM_RAMDISKS)
 		goto fail;
@@ -356,10 +280,10 @@
 	int error = -EINVAL;
 	unsigned int minor;
 
-	if (!inode || !inode->i_rdev) 	
+	if (!inode || kdev_none(inode->i_rdev))
 		goto out;
 
-	minor = MINOR(inode->i_rdev);
+	minor = minor(inode->i_rdev);
 
 	switch (cmd) {
 		case BLKFLSBUF:
@@ -483,7 +407,7 @@
 		rd_bdev[i] = NULL;
 		if (bdev)
 			blkdev_put(bdev, BDEV_FILE);
-		destroy_buffers(MKDEV(MAJOR_NR, i));
+		destroy_buffers(mk_kdev(MAJOR_NR, i));
 	}
 
 	devfs_unregister (devfs_handle);
@@ -492,7 +416,7 @@
 }
 
 /* This is the registration and initialization section of the RAM disk driver */
-int __init rd_init (void)
+static int __init rd_init (void)
 {
 	int		i;
 
@@ -525,7 +449,7 @@
 			       &rd_bd_op, NULL);
 
 	for (i = 0; i < NUM_RAMDISKS; i++)
-		register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &rd_bd_op, rd_size<<1);
+		register_disk(NULL, mk_kdev(MAJOR_NR,i), 1, &rd_bd_op, rd_size<<1);
 
 #ifdef CONFIG_BLK_DEV_INITRD
 	/* We ought to separate initrd operations here */
@@ -548,7 +472,28 @@
 module_init(rd_init);
 module_exit(rd_cleanup);
 
-/* loadable module support */
+/* options - nonmodular */
+#ifndef MODULE
+static int __init ramdisk_size(char *str)
+{
+	rd_size = simple_strtol(str,NULL,0);
+	return 1;
+}
+static int __init ramdisk_size2(char *str)	/* kludge */
+{
+	return ramdisk_size(str);
+}
+static int __init ramdisk_blocksize(char *str)
+{
+	rd_blocksize = simple_strtol(str,NULL,0);
+	return 1;
+}
+__setup("ramdisk=", ramdisk_size);
+__setup("ramdisk_size=", ramdisk_size2);
+__setup("ramdisk_blocksize=", ramdisk_blocksize);
+#endif
+
+/* options - modular */
 MODULE_PARM     (rd_size, "1i");
 MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes.");
 MODULE_PARM     (rd_blocksize, "i");
diff -u --recursive --new-file v2.5.1/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- v2.5.1/linux/drivers/block/xd.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/block/xd.c	Mon Dec 31 17:56:19 2001
@@ -130,10 +130,8 @@
 	major:		MAJOR_NR,
 	major_name:	"xd",
 	minor_shift:	6,
-	max_p:		1 << 6,
 	part:		xd_struct,
 	sizes:		xd_sizes,
-	real_devices:	(void *)xd_info,
 	fops:		&xd_fops,
 };
 
diff -u --recursive --new-file v2.5.1/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.5.1/linux/drivers/cdrom/cdrom.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/cdrom/cdrom.c	Tue Jan  1 11:33:22 2002
@@ -266,7 +266,6 @@
 #include <linux/init.h>
 
 #include <asm/fcntl.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 
 /* used to tell the module to turn on full debugging messages */
@@ -338,7 +337,7 @@
 int register_cdrom(struct cdrom_device_info *cdi)
 {
 	static char banner_printed;
-	int major = MAJOR(cdi->dev);
+	int major = major(cdi->dev);
         struct cdrom_device_ops *cdo = cdi->ops;
         int *change_capability = (int *)&cdo->capability; /* hack */
 
@@ -409,7 +408,7 @@
 int unregister_cdrom(struct cdrom_device_info *unreg)
 {
 	struct cdrom_device_info *cdi, *prev;
-	int major = MAJOR(unreg->dev);
+	int major = major(unreg->dev);
 
 	cdinfo(CD_OPEN, "entering unregister_cdrom\n"); 
 
@@ -418,7 +417,7 @@
 
 	prev = NULL;
 	cdi = topCdromPtr;
-	while (cdi != NULL && cdi->dev != unreg->dev) {
+	while (cdi != NULL && !kdev_same(cdi->dev, unreg->dev)) {
 		prev = cdi;
 		cdi = cdi->next;
 	}
@@ -441,7 +440,7 @@
 	struct cdrom_device_info *cdi;
 
 	cdi = topCdromPtr;
-	while (cdi != NULL && cdi->dev != dev)
+	while (cdi != NULL && !kdev_same(cdi->dev, dev))
 		cdi = cdi->next;
 
 	return cdi;
diff -u --recursive --new-file v2.5.1/linux/drivers/cdrom/cdu31a.c linux/drivers/cdrom/cdu31a.c
--- v2.5.1/linux/drivers/cdrom/cdu31a.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/cdrom/cdu31a.c	Sat Dec 29 11:17:37 2001
@@ -237,6 +237,7 @@
 static volatile unsigned short sony_cd_read_reg;
 static volatile unsigned short sony_cd_fifost_reg;
 
+static spinlock_t cdu31a_lock = SPIN_LOCK_UNLOCKED; /* queue lock */
 
 static int sony_spun_up = 0;	/* Has the drive been spun up? */
 
@@ -1605,17 +1606,7 @@
 			scd_spinup();
 		}
 
-		/* I don't use INIT_REQUEST because it calls return, which would
-		   return without unlocking the device.  It shouldn't matter,
-		   but just to be safe... */
-		if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) {
-			panic(DEVICE_NAME ": request list destroyed");
-		}
-		if (CURRENT->bh) {
-			if (!buffer_locked(CURRENT->bh)) {
-				panic(DEVICE_NAME ": block not locked");
-			}
-		}
+		INIT_REQUEST;
 
 		block = CURRENT->sector;
 		nblock = CURRENT->nr_sectors;
@@ -1626,112 +1617,105 @@
 			goto cdu31a_request_startover;
 		}
 
-		switch (CURRENT->cmd) {
-		case READ:
-			/*
-			 * If the block address is invalid or the request goes beyond the end of
-			 * the media, return an error.
-			 */
-#if 0
-			if ((block / 4) < sony_toc.start_track_lba) {
-				printk
-				    ("CDU31A: Request before beginning of media\n");
-				end_request(0);
-				goto cdu31a_request_startover;
-			}
-#endif
-			if ((block / 4) >= sony_toc.lead_out_start_lba) {
-				printk
-				    ("CDU31A: Request past end of media\n");
-				end_request(0);
-				goto cdu31a_request_startover;
-			}
-			if (((block + nblock) / 4) >=
-			    sony_toc.lead_out_start_lba) {
-				printk
-				    ("CDU31A: Request past end of media\n");
-				end_request(0);
-				goto cdu31a_request_startover;
-			}
-
-			num_retries = 0;
-
-		      try_read_again:
-			while (handle_sony_cd_attention());
-
-			if (!sony_toc_read) {
-				printk("CDU31A: TOC not read\n");
-				end_request(0);
-				goto cdu31a_request_startover;
-			}
-
-			/* If no data is left to be read from the drive, start the
-			   next request. */
-			if (sony_blocks_left == 0) {
-				if (start_request
-				    (block / 4, CDU31A_READAHEAD / 4, 0)) {
-					end_request(0);
-					goto cdu31a_request_startover;
-				}
-			}
-			/* If the requested block is not the next one waiting in
-			   the driver, abort the current operation and start a
-			   new one. */
-			else if (block != sony_next_block) {
-#if DEBUG
-				printk
-				    ("CDU31A Warning: Read for block %d, expected %d\n",
-				     block, sony_next_block);
-#endif
-				abort_read();
-				if (!sony_toc_read) {
-					printk("CDU31A: TOC not read\n");
+		if(CURRENT->flags & REQ_CMD) {
+			switch (rq_data_dir(CURRENT)) {
+			case READ:
+				/*
+				 * If the block address is invalid or the request goes beyond the end of
+				 * the media, return an error.
+				 */
+				if ((block / 4) >= sony_toc.lead_out_start_lba) {
+					printk
+						("CDU31A: Request past end of media\n");
 					end_request(0);
 					goto cdu31a_request_startover;
 				}
-				if (start_request
-				    (block / 4, CDU31A_READAHEAD / 4, 0)) {
+				if (((block + nblock) / 4) >=
+				    sony_toc.lead_out_start_lba) {
 					printk
-					    ("CDU31a: start request failed\n");
+						("CDU31A: Request past end of media\n");
 					end_request(0);
 					goto cdu31a_request_startover;
 				}
-			}
 
-			read_data_block(CURRENT->buffer, block, nblock,
-					res_reg, &res_size);
-			if (res_reg[0] == 0x20) {
-				if (num_retries > MAX_CDU31A_RETRIES) {
+				num_retries = 0;
+
+			try_read_again:
+				while (handle_sony_cd_attention());
+
+				if (!sony_toc_read) {
+					printk("CDU31A: TOC not read\n");
 					end_request(0);
 					goto cdu31a_request_startover;
 				}
 
-				num_retries++;
-				if (res_reg[1] == SONY_NOT_SPIN_ERR) {
-					do_sony_cd_cmd(SONY_SPIN_UP_CMD,
-						       NULL, 0, res_reg,
-						       &res_size);
-				} else {
+				/* If no data is left to be read from the drive, start the
+				   next request. */
+				if (sony_blocks_left == 0) {
+					if (start_request
+					    (block / 4, CDU31A_READAHEAD / 4, 0)) {
+						end_request(0);
+						goto cdu31a_request_startover;
+					}
+				}
+				/* If the requested block is not the next one waiting in
+				   the driver, abort the current operation and start a
+				   new one. */
+				else if (block != sony_next_block) {
+#if DEBUG
 					printk
-					    ("CDU31A: %s error for block %d, nblock %d\n",
-					     translate_error(res_reg[1]),
-					     block, nblock);
+						("CDU31A Warning: Read for block %d, expected %d\n",
+						 block, sony_next_block);
+#endif
+					abort_read();
+					if (!sony_toc_read) {
+						printk("CDU31A: TOC not read\n");
+						end_request(0);
+						goto cdu31a_request_startover;
+					}
+					if (start_request
+					    (block / 4, CDU31A_READAHEAD / 4, 0)) {
+						printk
+							("CDU31a: start request failed\n");
+						end_request(0);
+						goto cdu31a_request_startover;
+					}
 				}
-				goto try_read_again;
-			} else {
-				end_request(1);
-			}
-			break;
 
-		case WRITE:
-			end_request(0);
-			break;
+				read_data_block(CURRENT->buffer, block, nblock,
+						res_reg, &res_size);
+				if (res_reg[0] == 0x20) {
+					if (num_retries > MAX_CDU31A_RETRIES) {
+						end_request(0);
+						goto cdu31a_request_startover;
+					}
 
-		default:
-			panic("CDU31A: Unknown cmd");
+					num_retries++;
+					if (res_reg[1] == SONY_NOT_SPIN_ERR) {
+						do_sony_cd_cmd(SONY_SPIN_UP_CMD,
+							       NULL, 0, res_reg,
+							       &res_size);
+					} else {
+						printk
+							("CDU31A: %s error for block %d, nblock %d\n",
+							 translate_error(res_reg[1]),
+							 block, nblock);
+					}
+					goto try_read_again;
+				} else {
+					end_request(1);
+				}
+				break;
+
+			case WRITE:
+				end_request(0);
+				break;
+
+			default:
+				panic("CDU31A: Unknown cmd");
+			}
 		}
 	}
-
       end_do_cdu31a_request:
 	spin_lock_irq(&q->queue_lock);
 #if 0
@@ -3456,7 +3440,8 @@
 		    strcmp("CD-ROM CDU31A", drive_config.product_id) == 0;
 
 		blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR),
-			       DEVICE_REQUEST);
+			       DEVICE_REQUEST,
+			       &cdu31a_lock);
 		read_ahead[MAJOR_NR] = CDU31A_READAHEAD;
 		cdu31a_block_size = 1024;	/* 1kB default block size */
 		/* use 'mount -o block=2048' */
diff -u --recursive --new-file v2.5.1/linux/drivers/cdrom/sonycd535.c linux/drivers/cdrom/sonycd535.c
--- v2.5.1/linux/drivers/cdrom/sonycd535.c	Thu Oct 25 13:58:35 2001
+++ linux/drivers/cdrom/sonycd535.c	Thu Jan  3 11:34:10 2002
@@ -217,6 +217,8 @@
 static unsigned short read_status_reg;
 static unsigned short data_reg;
 
+static spinlock_t sonycd535_lock = SPIN_LOCK_UNLOCKED; /* queue lock */
+
 static int initialized;			/* Has the drive been initialized? */
 static int sony_disc_changed = 1;	/* Has the disk been changed
 					   since the last check? */
@@ -815,123 +817,124 @@
 			end_request(0);
 			continue;
 		}
-		switch (CURRENT->cmd) {
-		case READ:
-			/*
-			 * If the block address is invalid or the request goes beyond the end of
-			 * the media, return an error.
-			 */
-
-			if (sony_toc->lead_out_start_lba <= (block / 4)) {
-				end_request(0);
-				return;
-			}
-			if (sony_toc->lead_out_start_lba <= ((block + nsect) / 4)) {
-				end_request(0);
-				return;
-			}
-			while (0 < nsect) {
+		if(CURRENT->flags & REQ_CMD) {
+			switch (rq_data_dir(CURRENT)) {
+			case READ:
 				/*
-				 * If the requested sector is not currently in the read-ahead buffer,
-				 * it must be read in.
+				 * If the block address is invalid or the request goes beyond the end of
+				 * the media, return an error.
 				 */
-				if ((block < sony_first_block) || (sony_last_block < block)) {
-					sony_first_block = (block / 4) * 4;
-					log_to_msf(block / 4, params);
-
-					/*
-					 * If the full read-ahead would go beyond the end of the media, trim
-					 * it back to read just till the end of the media.
-					 */
-					if (sony_toc->lead_out_start_lba <= ((block / 4) + sony_buffer_sectors)) {
-						sony_last_block = (sony_toc->lead_out_start_lba * 4) - 1;
-						read_size = sony_toc->lead_out_start_lba - (block / 4);
-					} else {
-						sony_last_block = sony_first_block + (sony_buffer_sectors * 4) - 1;
-						read_size = sony_buffer_sectors;
-					}
-					size_to_buf(read_size, &params[3]);
-
+				
+				if (sony_toc->lead_out_start_lba <= (block / 4)) {
+					end_request(0);
+					return;
+				}
+				if (sony_toc->lead_out_start_lba <= ((block + nsect) / 4)) {
+					end_request(0);
+					return;
+				}
+				while (0 < nsect) {
 					/*
-					 * Read the data.  If the drive was not spinning,
-					 * spin it up and try some more.
+					 * If the requested sector is not currently in the read-ahead buffer,
+					 * it must be read in.
 					 */
-					for (spin_up_retry=0 ;; ++spin_up_retry) {
-						/* This loop has been modified to support the Sony
-						 * CDU-510/515 series, thanks to Claudio Porfiri 
-						 * <C.Porfiri@nisms.tei.ericsson.se>.
-						 */
+					if ((block < sony_first_block) || (sony_last_block < block)) {
+						sony_first_block = (block / 4) * 4;
+						log_to_msf(block / 4, params);
+						
 						/*
-						 * This part is to deal with very slow hardware.  We
-						 * try at most MAX_SPINUP_RETRY times to read the same
-						 * block.  A check for seek_and_read_N_blocks' result is
-						 * performed; if the result is wrong, the CDROM's engine
-						 * is restarted and the operation is tried again.
+						 * If the full read-ahead would go beyond the end of the media, trim
+						 * it back to read just till the end of the media.
 						 */
+						if (sony_toc->lead_out_start_lba <= ((block / 4) + sony_buffer_sectors)) {
+							sony_last_block = (sony_toc->lead_out_start_lba * 4) - 1;
+							read_size = sony_toc->lead_out_start_lba - (block / 4);
+						} else {
+							sony_last_block = sony_first_block + (sony_buffer_sectors * 4) - 1;
+							read_size = sony_buffer_sectors;
+						}
+						size_to_buf(read_size, &params[3]);
+						
 						/*
-						 * 1995-06-01: The system got problems when downloading
-						 * from Slackware CDROM, the problem seems to be:
-						 * seek_and_read_N_blocks returns BAD_STATUS and we
-						 * should wait for a while before retrying, so a new
-						 * part was added to discriminate the return value from
-						 * seek_and_read_N_blocks for the various cases.
+						 * Read the data.  If the drive was not spinning,
+						 * spin it up and try some more.
 						 */
-						int readStatus = seek_and_read_N_blocks(params, read_size,
-									status, sony_buffer, (read_size * CDU535_BLOCK_SIZE));
-						if (0 <= readStatus)	/* Good data; common case, placed first */
-							break;
-						if (readStatus == NO_ROOM || spin_up_retry == MAX_SPINUP_RETRY) {
-							/* give up */
-							if (readStatus == NO_ROOM)
-								printk(CDU535_MESSAGE_NAME " No room to read from CD\n");
-							else
-								printk(CDU535_MESSAGE_NAME " Read error: 0x%.2x\n",
-										status[0]);
-							sony_first_block = -1;
-							sony_last_block = -1;
-							end_request(0);
-							return;
-						}
-						if (readStatus == BAD_STATUS) {
-							/* Sleep for a while, then retry */
-							current->state = TASK_INTERRUPTIBLE;
-							schedule_timeout(RETRY_FOR_BAD_STATUS*HZ/10);
-						}
+						for (spin_up_retry=0 ;; ++spin_up_retry) {
+							/* This loop has been modified to support the Sony
+							 * CDU-510/515 series, thanks to Claudio Porfiri 
+							 * <C.Porfiri@nisms.tei.ericsson.se>.
+							 */
+							/*
+							 * This part is to deal with very slow hardware.  We
+							 * try at most MAX_SPINUP_RETRY times to read the same
+							 * block.  A check for seek_and_read_N_blocks' result is
+							 * performed; if the result is wrong, the CDROM's engine
+							 * is restarted and the operation is tried again.
+							 */
+							/*
+							 * 1995-06-01: The system got problems when downloading
+							 * from Slackware CDROM, the problem seems to be:
+							 * seek_and_read_N_blocks returns BAD_STATUS and we
+							 * should wait for a while before retrying, so a new
+							 * part was added to discriminate the return value from
+							 * seek_and_read_N_blocks for the various cases.
+							 */
+							int readStatus = seek_and_read_N_blocks(params, read_size,
+												status, sony_buffer, (read_size * CDU535_BLOCK_SIZE));
+							if (0 <= readStatus)	/* Good data; common case, placed first */
+								break;
+							if (readStatus == NO_ROOM || spin_up_retry == MAX_SPINUP_RETRY) {
+								/* give up */
+								if (readStatus == NO_ROOM)
+									printk(CDU535_MESSAGE_NAME " No room to read from CD\n");
+								else
+									printk(CDU535_MESSAGE_NAME " Read error: 0x%.2x\n",
+									       status[0]);
+								sony_first_block = -1;
+								sony_last_block = -1;
+								end_request(0);
+								return;
+							}
+							if (readStatus == BAD_STATUS) {
+								/* Sleep for a while, then retry */
+								current->state = TASK_INTERRUPTIBLE;
+								schedule_timeout(RETRY_FOR_BAD_STATUS*HZ/10);
+							}
 #if DEBUG > 0
-						printk(CDU535_MESSAGE_NAME
-							" debug: calling spin up when reading data!\n");
+							printk(CDU535_MESSAGE_NAME
+							       " debug: calling spin up when reading data!\n");
 #endif
-						cmd[0] = SONY535_SPIN_UP;
-						do_sony_cmd(cmd, 1, status, NULL, 0, 0);
+							cmd[0] = SONY535_SPIN_UP;
+							do_sony_cmd(cmd, 1, status, NULL, 0, 0);
+						}
 					}
+					/*
+					 * The data is in memory now, copy it to the buffer and advance to the
+					 * next block to read.
+					 */
+					copyoff = block - sony_first_block;
+					memcpy(CURRENT->buffer,
+					       sony_buffer[copyoff / 4] + 512 * (copyoff % 4), 512);
+					
+					block += 1;
+					nsect -= 1;
+					CURRENT->buffer += 512;
 				}
-				/*
-				 * The data is in memory now, copy it to the buffer and advance to the
-				 * next block to read.
-				 */
-				copyoff = block - sony_first_block;
-				memcpy(CURRENT->buffer,
-					   sony_buffer[copyoff / 4] + 512 * (copyoff % 4), 512);
-
-				block += 1;
-				nsect -= 1;
-				CURRENT->buffer += 512;
-			}
-
-			end_request(1);
-			break;
 
-		case WRITE:
-			end_request(0);
-			break;
-
-		default:
-			panic("Unknown SONY CD cmd");
+				end_request(1);
+				break;
+				
+			case WRITE:
+				end_request(0);
+				break;
+				
+			default:
+				panic("Unknown SONY CD cmd");
+			}
 		}
 	}
 }
 
-
 /*
  * Read the table of contents from the drive and set sony_toc_read if
  * successful.
@@ -1593,7 +1596,7 @@
 							MAJOR_NR, CDU535_MESSAGE_NAME);
 					return -EIO;
 				}
-				blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
+				blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, &sonycd535_lock);
 				blksize_size[MAJOR_NR] = &sonycd535_block_size;
 				read_ahead[MAJOR_NR] = 8;	/* 8 sector (4kB) read-ahead */
 
diff -u --recursive --new-file v2.5.1/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.5.1/linux/drivers/char/Config.in	Mon Nov 12 09:34:16 2001
+++ linux/drivers/char/Config.in	Sun Dec 30 10:32:43 2001
@@ -16,7 +16,7 @@
       tristate '   Dual serial port support' CONFIG_DUALSP_SERIAL
    fi
 fi
-if [ "$CONFIG_ACPI" = "y" ]; then
+if [ "$CONFIG_ACPI" = "y" -a "$CONFIG_IA64" = "y" ]; then
    bool '  Support for serial ports defined by ACPI tables' CONFIG_SERIAL_ACPI
 fi
 dep_mbool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL
diff -u --recursive --new-file v2.5.1/linux/drivers/char/acquirewdt.c linux/drivers/char/acquirewdt.c
--- v2.5.1/linux/drivers/char/acquirewdt.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/char/acquirewdt.c	Thu Jan  3 12:20:10 2002
@@ -117,7 +117,7 @@
 
 static int acq_open(struct inode *inode, struct file *file)
 {
-	switch(MINOR(inode->i_rdev))
+	switch(minor(inode->i_rdev))
 	{
 		case WATCHDOG_MINOR:
 			spin_lock(&acq_lock);
@@ -141,7 +141,7 @@
 
 static int acq_close(struct inode *inode, struct file *file)
 {
-	if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
+	if(minor(inode->i_rdev)==WATCHDOG_MINOR)
 	{
 		spin_lock(&acq_lock);
 #ifndef CONFIG_WATCHDOG_NOWAYOUT	
diff -u --recursive --new-file v2.5.1/linux/drivers/char/advantechwdt.c linux/drivers/char/advantechwdt.c
--- v2.5.1/linux/drivers/char/advantechwdt.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/char/advantechwdt.c	Thu Jan  3 12:20:10 2002
@@ -128,7 +128,7 @@
 static int
 advwdt_open(struct inode *inode, struct file *file)
 {
-	switch (MINOR(inode->i_rdev)) {
+	switch (minor(inode->i_rdev)) {
 		case WATCHDOG_MINOR:
 			spin_lock(&advwdt_lock);
 			if (advwdt_is_open) {
@@ -151,7 +151,7 @@
 static int
 advwdt_close(struct inode *inode, struct file *file)
 {
-	if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
+	if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
 		spin_lock(&advwdt_lock);
 #ifndef CONFIG_WATCHDOG_NOWAYOUT	
 		inb_p(WDT_STOP);
diff -u --recursive --new-file v2.5.1/linux/drivers/char/agp/agpgart_fe.c linux/drivers/char/agp/agpgart_fe.c
--- v2.5.1/linux/drivers/char/agp/agpgart_fe.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/char/agp/agpgart_fe.c	Tue Jan  1 11:33:49 2002
@@ -694,7 +694,7 @@
 
 static int agp_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	agp_file_private *priv;
 	agp_client *client;
 	int rc = -ENXIO;
diff -u --recursive --new-file v2.5.1/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c
--- v2.5.1/linux/drivers/char/busmouse.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/char/busmouse.c	Thu Jan  3 12:20:10 2002
@@ -51,7 +51,7 @@
 
 #define NR_MICE			15
 #define FIRST_MOUSE		0
-#define DEV_TO_MOUSE(dev)	MINOR_TO_MOUSE(MINOR(dev))
+#define DEV_TO_MOUSE(dev)	MINOR_TO_MOUSE(minor(dev))
 #define MINOR_TO_MOUSE(minor)	((minor) - FIRST_MOUSE)
 
 /*
diff -u --recursive --new-file v2.5.1/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.5.1/linux/drivers/char/console.c	Mon Oct 15 14:00:43 2001
+++ linux/drivers/char/console.c	Tue Jan  1 11:45:42 2002
@@ -2171,14 +2171,13 @@
 
 static kdev_t vt_console_device(struct console *c)
 {
-	return MKDEV(TTY_MAJOR, c->index ? c->index : fg_console + 1);
+	return mk_kdev(TTY_MAJOR, c->index ? c->index : fg_console + 1);
 }
 
 struct console vt_console_driver = {
 	name:		"tty",
 	write:		vt_console_print,
 	device:		vt_console_device,
-	wait_key:	keyboard_wait_for_keypress,
 	unblank:	unblank_screen,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
@@ -2326,7 +2325,7 @@
 	int console_num;
 	if (!tty)
 		return;
-	console_num = MINOR(tty->device) - (tty->driver.minor_start);
+	console_num = minor(tty->device) - (tty->driver.minor_start);
 	if (!vc_cons_allocated(console_num))
 		return;
 	set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
@@ -2341,7 +2340,7 @@
 	int console_num;
 	if (!tty)
 		return;
-	console_num = MINOR(tty->device) - (tty->driver.minor_start);
+	console_num = minor(tty->device) - (tty->driver.minor_start);
 	if (!vc_cons_allocated(console_num))
 		return;
 	clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
@@ -2369,7 +2368,7 @@
 	unsigned int	currcons;
 	int i;
 
-	currcons = MINOR(tty->device) - tty->driver.minor_start;
+	currcons = minor(tty->device) - tty->driver.minor_start;
 
 	i = vc_allocate(currcons);
 	if (i)
@@ -2392,7 +2391,7 @@
 	if (!tty)
 		return;
 	if (tty->count != 1) return;
-	vcs_make_devfs (MINOR (tty->device) - tty->driver.minor_start, 1);
+	vcs_make_devfs (minor(tty->device) - tty->driver.minor_start, 1);
 	tty->driver_data = 0;
 }
 
diff -u --recursive --new-file v2.5.1/linux/drivers/char/drm/drm_drv.h linux/drivers/char/drm/drm_drv.h
--- v2.5.1/linux/drivers/char/drm/drm_drv.h	Sun Oct 21 10:40:36 2001
+++ linux/drivers/char/drm/drm_drv.h	Tue Jan  1 11:34:36 2002
@@ -719,7 +719,7 @@
 	int i;
 
 	for (i = 0; i < DRM(numdevs); i++) {
-		if (MINOR(inode->i_rdev) == DRM(minor)[i]) {
+		if (minor(inode->i_rdev) == DRM(minor)[i]) {
 			dev = &(DRM(device)[i]);
 			break;
 		}
diff -u --recursive --new-file v2.5.1/linux/drivers/char/drm/drm_fops.h linux/drivers/char/drm/drm_fops.h
--- v2.5.1/linux/drivers/char/drm/drm_fops.h	Thu Nov 22 11:46:37 2001
+++ linux/drivers/char/drm/drm_fops.h	Tue Jan  1 19:14:13 2002
@@ -38,7 +38,7 @@
 
 int DRM(open_helper)(struct inode *inode, struct file *filp, drm_device_t *dev)
 {
-	kdev_t	     minor = MINOR(inode->i_rdev);
+	int	     minor = minor(inode->i_rdev);
 	drm_file_t   *priv;
 
 	if (filp->f_flags & O_EXCL)   return -EBUSY; /* No exclusive opens */
diff -u --recursive --new-file v2.5.1/linux/drivers/char/drm/drm_stub.h linux/drivers/char/drm/drm_stub.h
--- v2.5.1/linux/drivers/char/drm/drm_stub.h	Thu Nov 22 11:46:37 2001
+++ linux/drivers/char/drm/drm_stub.h	Tue Jan  1 19:14:13 2002
@@ -53,7 +53,7 @@
 
 static int DRM(stub_open)(struct inode *inode, struct file *filp)
 {
-	int                    minor = MINOR(inode->i_rdev);
+	int                    minor = minor(inode->i_rdev);
 	int                    err   = -ENODEV;
 	struct file_operations *old_fops;
 
diff -u --recursive --new-file v2.5.1/linux/drivers/char/dsp56k.c linux/drivers/char/dsp56k.c
--- v2.5.1/linux/drivers/char/dsp56k.c	Mon Sep 10 08:06:32 2001
+++ linux/drivers/char/dsp56k.c	Sun Dec 30 10:31:51 2001
@@ -37,7 +37,6 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/smp_lock.h>
 
-#include <asm/segment.h>
 #include <asm/atarihw.h>
 #include <asm/traps.h>
 #include <asm/uaccess.h>	/* For put_user and get_user */
diff -u --recursive --new-file v2.5.1/linux/drivers/char/dtlk.c linux/drivers/char/dtlk.c
--- v2.5.1/linux/drivers/char/dtlk.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/char/dtlk.c	Sun Dec 30 10:31:51 2001
@@ -57,7 +57,6 @@
 #include <linux/errno.h>	/* for -EBUSY */
 #include <linux/ioport.h>	/* for check_region, request_region */
 #include <linux/delay.h>	/* for loops_per_jiffy */
-#include <asm/segment.h>	/* for put_user_byte */
 #include <asm/io.h>		/* for inb_p, outb_p, inb, outb, etc. */
 #include <asm/uaccess.h>	/* for get_user, etc. */
 #include <linux/wait.h>		/* for wait_queue */
diff -u --recursive --new-file v2.5.1/linux/drivers/char/dz.c linux/drivers/char/dz.c
--- v2.5.1/linux/drivers/char/dz.c	Sun Sep  9 10:43:02 2001
+++ linux/drivers/char/dz.c	Tue Dec 25 15:39:20 2001
@@ -75,7 +75,6 @@
 
 DECLARE_TASK_QUEUE(tq_serial);
 
-extern wait_queue_head_t keypress_wait; 
 static struct dz_serial *lines[4];
 static unsigned char tmp_buffer[256];
 
@@ -228,8 +227,6 @@
 		if (info->is_console) {
 			if (ch == 0)
 				return;			/* it's a break ... */
-
-			wake_up (&keypress_wait);       /* It is a 'keyboard interrupt' ;-) */
 		}
 #endif
 
@@ -1509,11 +1506,6 @@
 	}
 }
 
-static int dz_console_wait_key(struct console *co)
-{
-	return 0;
-}
-
 static kdev_t dz_console_device(struct console *c)
 {
 	return MKDEV(TTY_MAJOR, 64 + c->index);
@@ -1614,7 +1606,6 @@
     name:	"ttyS",
     write:	dz_console_print,
     device:	dz_console_device,
-    wait_key:	dz_console_wait_key,
     setup:	dz_console_setup,
     flags:	CON_CONSDEV | CON_PRINTBUFFER,
     index:	CONSOLE_LINE,
diff -u --recursive --new-file v2.5.1/linux/drivers/char/epca.c linux/drivers/char/epca.c
--- v2.5.1/linux/drivers/char/epca.c	Fri Oct 12 13:48:42 2001
+++ linux/drivers/char/epca.c	Sun Dec 30 10:31:51 2001
@@ -897,7 +897,6 @@
 					inline void copy_from_user(void * to, const void * from,
 					                          unsigned long count);
 
-					You must include <asm/segment.h>
 					I also think (Check hackers guide) that optimization must
 					be turned ON.  (Which sounds strange to me...)
 	
diff -u --recursive --new-file v2.5.1/linux/drivers/char/esp.c linux/drivers/char/esp.c
--- v2.5.1/linux/drivers/char/esp.c	Fri Nov  9 14:01:21 2001
+++ linux/drivers/char/esp.c	Sun Dec 30 10:31:51 2001
@@ -60,7 +60,6 @@
 
 #include <asm/system.h>
 #include <asm/io.h>
-#include <asm/segment.h>
 #include <asm/bitops.h>
 
 #include <asm/dma.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/char/eurotechwdt.c linux/drivers/char/eurotechwdt.c
--- v2.5.1/linux/drivers/char/eurotechwdt.c	Thu Oct 25 13:53:47 2001
+++ linux/drivers/char/eurotechwdt.c	Thu Jan  3 12:20:10 2002
@@ -280,7 +280,7 @@
  
 static int eurwdt_open(struct inode *inode, struct file *file)
 {
-   switch (MINOR(inode->i_rdev)) {
+   switch (minor(inode->i_rdev)) {
       case WATCHDOG_MINOR:
          spin_lock(&eurwdt_lock);
          if (eurwdt_is_open) {
@@ -322,7 +322,7 @@
  
 static int eurwdt_release(struct inode *inode, struct file *file)
 {
-   if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
+   if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
 #ifndef CONFIG_WATCHDOG_NOWAYOUT
       eurwdt_disable_timer();
 #endif
diff -u --recursive --new-file v2.5.1/linux/drivers/char/ftape/lowlevel/ftape-buffer.c linux/drivers/char/ftape/lowlevel/ftape-buffer.c
--- v2.5.1/linux/drivers/char/ftape/lowlevel/ftape-buffer.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/ftape/lowlevel/ftape-buffer.c	Sun Dec 30 10:31:51 2001
@@ -24,7 +24,6 @@
  *  buffer.
  */
 
-#include <asm/segment.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/char/ftape/lowlevel/ftape-io.c linux/drivers/char/ftape/lowlevel/ftape-io.c
--- v2.5.1/linux/drivers/char/ftape/lowlevel/ftape-io.c	Mon Oct 16 12:58:51 2000
+++ linux/drivers/char/ftape/lowlevel/ftape-io.c	Sun Dec 30 10:31:51 2001
@@ -29,7 +29,6 @@
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <linux/ioctl.h>
 #include <linux/mtio.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/char/ftape/lowlevel/ftape-read.c linux/drivers/char/ftape/lowlevel/ftape-read.c
--- v2.5.1/linux/drivers/char/ftape/lowlevel/ftape-read.c	Tue Nov 25 14:45:27 1997
+++ linux/drivers/char/ftape/lowlevel/ftape-read.c	Sun Dec 30 10:31:51 2001
@@ -29,7 +29,6 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
-#include <asm/segment.h>
 
 #include <linux/ftape.h>
 #include <linux/qic117.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/char/ftape/lowlevel/ftape-setup.c linux/drivers/char/ftape/lowlevel/ftape-setup.c
--- v2.5.1/linux/drivers/char/ftape/lowlevel/ftape-setup.c	Thu Aug 12 11:53:22 1999
+++ linux/drivers/char/ftape/lowlevel/ftape-setup.c	Sun Dec 30 10:31:51 2001
@@ -29,7 +29,6 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
-#include <asm/segment.h>
 
 #include <linux/ftape.h>
 #if LINUX_VERSION_CODE >= KERNEL_VER(2,1,16)
diff -u --recursive --new-file v2.5.1/linux/drivers/char/ftape/lowlevel/ftape-write.c linux/drivers/char/ftape/lowlevel/ftape-write.c
--- v2.5.1/linux/drivers/char/ftape/lowlevel/ftape-write.c	Mon Oct 16 12:58:51 2000
+++ linux/drivers/char/ftape/lowlevel/ftape-write.c	Sun Dec 30 10:31:51 2001
@@ -28,7 +28,6 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
-#include <asm/segment.h>
 
 #include <linux/ftape.h>
 #include <linux/qic117.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/char/ftape/zftape/zftape-buffers.c linux/drivers/char/ftape/zftape/zftape-buffers.c
--- v2.5.1/linux/drivers/char/ftape/zftape/zftape-buffers.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/ftape/zftape/zftape-buffers.c	Sun Dec 30 10:31:51 2001
@@ -27,7 +27,6 @@
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <asm/segment.h>
 
 #include <linux/zftape.h>
 
diff -u --recursive --new-file v2.5.1/linux/drivers/char/ftape/zftape/zftape-init.c linux/drivers/char/ftape/zftape/zftape-init.c
--- v2.5.1/linux/drivers/char/ftape/zftape/zftape-init.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/char/ftape/zftape/zftape-init.c	Sun Dec 30 10:31:51 2001
@@ -25,7 +25,6 @@
 #include <linux/errno.h>
 #include <linux/version.h>
 #include <linux/fs.h>
-#include <asm/segment.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/major.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/char/ftape/zftape/zftape-rw.c linux/drivers/char/ftape/zftape/zftape-rw.c
--- v2.5.1/linux/drivers/char/ftape/zftape/zftape-rw.c	Mon Oct 16 12:58:51 2000
+++ linux/drivers/char/ftape/zftape/zftape-rw.c	Sun Dec 30 10:31:51 2001
@@ -27,7 +27,6 @@
 #include <linux/config.h> /* for CONFIG_ZFT_DFLT_BLK_SZ */
 #include <linux/errno.h>
 #include <linux/mm.h>
-#include <asm/segment.h>
 
 #include <linux/zftape.h>
 #include "../zftape/zftape-init.h"
diff -u --recursive --new-file v2.5.1/linux/drivers/char/ftape/zftape/zftape-vtbl.c linux/drivers/char/ftape/zftape/zftape-vtbl.c
--- v2.5.1/linux/drivers/char/ftape/zftape/zftape-vtbl.c	Fri Apr  6 10:42:55 2001
+++ linux/drivers/char/ftape/zftape/zftape-vtbl.c	Sun Dec 30 10:31:51 2001
@@ -31,7 +31,6 @@
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <asm/segment.h>
 
 #include <linux/zftape.h>
 #include "../zftape/zftape-init.h"
diff -u --recursive --new-file v2.5.1/linux/drivers/char/h8.c linux/drivers/char/h8.c
--- v2.5.1/linux/drivers/char/h8.c	Thu Sep 13 15:21:32 2001
+++ linux/drivers/char/h8.c	Sun Dec 30 10:31:51 2001
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 
 #include <asm/system.h>
-#include <asm/segment.h>
 #include <asm/io.h>
 
 #include <linux/types.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/char/i8k.c linux/drivers/char/i8k.c
--- v2.5.1/linux/drivers/char/i8k.c	Fri Nov  2 17:46:47 2001
+++ linux/drivers/char/i8k.c	Sun Dec 30 10:38:45 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 -u --recursive --new-file v2.5.1/linux/drivers/char/ib700wdt.c linux/drivers/char/ib700wdt.c
--- v2.5.1/linux/drivers/char/ib700wdt.c	Thu Oct 11 09:07:00 2001
+++ linux/drivers/char/ib700wdt.c	Thu Jan  3 12:20:10 2002
@@ -155,7 +155,7 @@
 static int
 ibwdt_open(struct inode *inode, struct file *file)
 {
-	switch (MINOR(inode->i_rdev)) {
+	switch (minor(inode->i_rdev)) {
 		case WATCHDOG_MINOR:
 			spin_lock(&ibwdt_lock);
 			if (ibwdt_is_open) {
@@ -179,7 +179,7 @@
 ibwdt_close(struct inode *inode, struct file *file)
 {
 	lock_kernel();
-	if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
+	if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
 		spin_lock(&ibwdt_lock);
 #ifndef CONFIG_WATCHDOG_NOWAYOUT
 		outb_p(WD_TIMO, WDT_STOP);
diff -u --recursive --new-file v2.5.1/linux/drivers/char/ip2main.c linux/drivers/char/ip2main.c
--- v2.5.1/linux/drivers/char/ip2main.c	Fri Nov  2 17:26:17 2001
+++ linux/drivers/char/ip2main.c	Sun Dec 30 10:31:51 2001
@@ -142,7 +142,6 @@
 // so blame them.
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,4)
-#	include <asm/segment.h>
 #	define GET_USER(error,value,addr) error = get_user(value,addr)
 #	define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
 #	define PUT_USER(error,value,addr) error = put_user(value,addr)
diff -u --recursive --new-file v2.5.1/linux/drivers/char/isicom.c linux/drivers/char/isicom.c
--- v2.5.1/linux/drivers/char/isicom.c	Fri Nov  9 14:01:21 2001
+++ linux/drivers/char/isicom.c	Sun Dec 30 10:31:51 2001
@@ -51,7 +51,6 @@
 #include <linux/timer.h>
 #include <linux/ioport.h>
 
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/char/joystick/serport.c linux/drivers/char/joystick/serport.c
--- v2.5.1/linux/drivers/char/joystick/serport.c	Wed Sep 12 15:34:06 2001
+++ linux/drivers/char/joystick/serport.c	Thu Jan  3 12:20:10 2002
@@ -149,9 +149,9 @@
 	char name[32];
 
 #ifdef CONFIG_DEVFS_FS
-	sprintf(name, tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
+	sprintf(name, tty->driver.name, minor(tty->device) - tty->driver.minor_start);
 #else
-	sprintf(name, "%s%d", tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
+	sprintf(name, "%s%d", tty->driver.name, minor(tty->device) - tty->driver.minor_start);
 #endif
 
 	serio_register_port(&serport->serio);
diff -u --recursive --new-file v2.5.1/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- v2.5.1/linux/drivers/char/keyboard.c	Tue Sep 18 13:39:51 2001
+++ linux/drivers/char/keyboard.c	Tue Dec 25 15:39:20 2001
@@ -67,15 +67,8 @@
 
 extern void ctrl_alt_del(void);
 
-DECLARE_WAIT_QUEUE_HEAD(keypress_wait);
 struct console;
 
-int keyboard_wait_for_keypress(struct console *co)
-{
-	sleep_on(&keypress_wait);
-	return 0;
-}
-
 /*
  * global state includes the following, and various static variables
  * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next.
@@ -334,7 +327,6 @@
 
 void put_queue(int ch)
 {
-	wake_up(&keypress_wait);
 	if (tty) {
 		tty_insert_flip_char(tty, ch, 0);
 		con_schedule_flip(tty);
@@ -343,7 +335,6 @@
 
 static void puts_queue(char *cp)
 {
-	wake_up(&keypress_wait);
 	if (!tty)
 		return;
 
diff -u --recursive --new-file v2.5.1/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.5.1/linux/drivers/char/lp.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/char/lp.c	Tue Jan  1 18:55:31 2002
@@ -294,7 +294,7 @@
 static ssize_t lp_write(struct file * file, const char * buf,
 		        size_t count, loff_t *ppos)
 {
-	unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+	unsigned int minor = minor(file->f_dentry->d_inode->i_rdev);
 	struct parport *port = lp_table[minor].dev->port;
 	char *kbuf = lp_table[minor].lp_buffer;
 	ssize_t retv = 0;
@@ -403,7 +403,7 @@
 static ssize_t lp_read(struct file * file, char * buf,
 		       size_t count, loff_t *ppos)
 {
-	unsigned int minor=MINOR(file->f_dentry->d_inode->i_rdev);
+	unsigned int minor=minor(file->f_dentry->d_inode->i_rdev);
 	struct parport *port = lp_table[minor].dev->port;
 	ssize_t retval = 0;
 	char *kbuf = lp_table[minor].lp_buffer;
@@ -430,7 +430,7 @@
 
 static int lp_open(struct inode * inode, struct file * file)
 {
-	unsigned int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 
 	if (minor >= LP_NO)
 		return -ENXIO;
@@ -488,7 +488,7 @@
 
 static int lp_release(struct inode * inode, struct file * file)
 {
-	unsigned int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 
 	lp_claim_parport_or_block (&lp_table[minor]);
 	parport_negotiate (lp_table[minor].dev->port, IEEE1284_MODE_COMPAT);
@@ -503,7 +503,7 @@
 static int lp_ioctl(struct inode *inode, struct file *file,
 		    unsigned int cmd, unsigned long arg)
 {
-	unsigned int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	int status;
 	int retval = 0;
 
diff -u --recursive --new-file v2.5.1/linux/drivers/char/machzwd.c linux/drivers/char/machzwd.c
--- v2.5.1/linux/drivers/char/machzwd.c	Thu Sep 13 15:21:32 2001
+++ linux/drivers/char/machzwd.c	Thu Jan  3 12:20:10 2002
@@ -378,7 +378,7 @@
 
 static int zf_open(struct inode *inode, struct file *file)
 {
-	switch(MINOR(inode->i_rdev)){
+	switch(minor(inode->i_rdev)){
 		case WATCHDOG_MINOR:
 			spin_lock(&zf_lock);
 			if(zf_is_open){
@@ -403,7 +403,7 @@
 
 static int zf_close(struct inode *inode, struct file *file)
 {
-	if(MINOR(inode->i_rdev) == WATCHDOG_MINOR){
+	if(minor(inode->i_rdev) == WATCHDOG_MINOR){
 
 		if(zf_expect_close){
 			zf_timer_off();
diff -u --recursive --new-file v2.5.1/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.5.1/linux/drivers/char/mem.c	Fri Sep 14 14:04:07 2001
+++ linux/drivers/char/mem.c	Tue Jan  1 11:36:41 2002
@@ -538,7 +538,7 @@
 
 static int memory_open(struct inode * inode, struct file * filp)
 {
-	switch (MINOR(inode->i_rdev)) {
+	switch (minor(inode->i_rdev)) {
 		case 1:
 			filp->f_op = &mem_fops;
 			break;
diff -u --recursive --new-file v2.5.1/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v2.5.1/linux/drivers/char/misc.c	Fri Nov  2 17:46:47 2001
+++ linux/drivers/char/misc.c	Tue Jan  1 11:43:01 2002
@@ -104,7 +104,7 @@
 
 static int misc_open(struct inode * inode, struct file * file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct miscdevice *c;
 	int err = -ENODEV;
 	struct file_operations *old_fops, *new_fops = NULL;
diff -u --recursive --new-file v2.5.1/linux/drivers/char/moxa.c linux/drivers/char/moxa.c
--- v2.5.1/linux/drivers/char/moxa.c	Thu Oct 25 13:53:47 2001
+++ linux/drivers/char/moxa.c	Sun Dec 30 10:31:51 2001
@@ -53,7 +53,6 @@
 
 #include <asm/system.h>
 #include <asm/io.h>
-#include <asm/segment.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
 
diff -u --recursive --new-file v2.5.1/linux/drivers/char/mxser.c linux/drivers/char/mxser.c
--- v2.5.1/linux/drivers/char/mxser.c	Thu Oct 25 13:53:47 2001
+++ linux/drivers/char/mxser.c	Sun Dec 30 10:31:51 2001
@@ -58,7 +58,6 @@
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/segment.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
 
diff -u --recursive --new-file v2.5.1/linux/drivers/char/n_hdlc.c linux/drivers/char/n_hdlc.c
--- v2.5.1/linux/drivers/char/n_hdlc.c	Thu Sep 13 15:21:32 2001
+++ linux/drivers/char/n_hdlc.c	Sun Dec 30 10:31:51 2001
@@ -112,7 +112,6 @@
 #include <linux/kerneld.h>
 #endif
 
-#include <asm/segment.h>
 #define GET_USER(error,value,addr) error = get_user(value,addr)
 #define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
 #define PUT_USER(error,value,addr) error = put_user(value,addr)
diff -u --recursive --new-file v2.5.1/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- v2.5.1/linux/drivers/char/n_tty.c	Fri Apr  6 10:42:55 2001
+++ linux/drivers/char/n_tty.c	Tue Jan  1 11:44:16 2002
@@ -45,8 +45,8 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 
-#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
-#define SYSCONS_DEV  MKDEV(TTYAUX_MAJOR,1)
+#define IS_CONSOLE_DEV(dev)	(kdev_val(dev) == __mkdev(TTY_MAJOR,0))
+#define IS_SYSCONS_DEV(dev)	(kdev_val(dev) == __mkdev(TTYAUX_MAJOR,1))
 
 #ifndef MIN
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
@@ -955,8 +955,8 @@
 	/* NOTE: not yet done after every sleep pending a thorough
 	   check of the logic of this change. -- jlc */
 	/* don't stop on /dev/console */
-	if (file->f_dentry->d_inode->i_rdev != CONSOLE_DEV &&
-	    file->f_dentry->d_inode->i_rdev != SYSCONS_DEV &&
+	if (!IS_CONSOLE_DEV(file->f_dentry->d_inode->i_rdev) &&
+	    !IS_SYSCONS_DEV(file->f_dentry->d_inode->i_rdev) &&
 	    current->tty == tty) {
 		if (tty->pgrp <= 0)
 			printk("read_chan: tty->pgrp <= 0!\n");
@@ -1135,8 +1135,8 @@
 
 	/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
 	if (L_TOSTOP(tty) && 
-	    file->f_dentry->d_inode->i_rdev != CONSOLE_DEV &&
-	    file->f_dentry->d_inode->i_rdev != SYSCONS_DEV) {
+	    !IS_CONSOLE_DEV(file->f_dentry->d_inode->i_rdev) &&
+	    !IS_SYSCONS_DEV(file->f_dentry->d_inode->i_rdev)) {
 		retval = tty_check_change(tty);
 		if (retval)
 			return retval;
diff -u --recursive --new-file v2.5.1/linux/drivers/char/pc110pad.c linux/drivers/char/pc110pad.c
--- v2.5.1/linux/drivers/char/pc110pad.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/char/pc110pad.c	Sun Dec 30 09:08:06 2001
@@ -590,7 +590,7 @@
 	spin_lock_irqsave(&pc110_lock, flags);
 	if (!--active_count)
 		outb(0x30, current_params.io+2);  /* switch off digitiser */
-	spin_unlock_irqrestore(&active_lock, flags);	
+	spin_unlock_irqrestore(&pc110_lock, flags);	
 	return 0;
 }
 
diff -u --recursive --new-file v2.5.1/linux/drivers/char/pcwd.c linux/drivers/char/pcwd.c
--- v2.5.1/linux/drivers/char/pcwd.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/char/pcwd.c	Thu Jan  3 12:20:10 2002
@@ -400,7 +400,7 @@
 
 static int pcwd_open(struct inode *ino, struct file *filep)
 {
-        switch (MINOR(ino->i_rdev))
+        switch (minor(ino->i_rdev))
         {
                 case WATCHDOG_MINOR:
                     if ( !atomic_dec_and_test(&open_allowed) )
@@ -433,7 +433,7 @@
 	/*  Can't seek (pread) on this device  */
 	if (ppos != &file->f_pos)
 		return -ESPIPE;
-	switch(MINOR(file->f_dentry->d_inode->i_rdev)) 
+	switch(minor(file->f_dentry->d_inode->i_rdev)) 
 	{
 		case TEMP_MINOR:
 			/*
@@ -453,7 +453,7 @@
 
 static int pcwd_close(struct inode *ino, struct file *filep)
 {
-	if (MINOR(ino->i_rdev)==WATCHDOG_MINOR)
+	if (minor(ino->i_rdev)==WATCHDOG_MINOR)
 	{
 #ifndef CONFIG_WATCHDOG_NOWAYOUT
 		/*  Disable the board  */
diff -u --recursive --new-file v2.5.1/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c
--- v2.5.1/linux/drivers/char/ppdev.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/char/ppdev.c	Tue Jan  1 18:55:31 2002
@@ -103,7 +103,7 @@
 static ssize_t pp_read (struct file * file, char * buf, size_t count,
 			loff_t * ppos)
 {
-	unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev);
+	unsigned int minor = minor (file->f_dentry->d_inode->i_rdev);
 	struct pp_struct *pp = file->private_data;
 	char * kbuffer;
 	ssize_t bytes_read = 0;
@@ -183,7 +183,7 @@
 static ssize_t pp_write (struct file * file, const char * buf, size_t count,
 			 loff_t * ppos)
 {
-	unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev);
+	unsigned int minor = minor (file->f_dentry->d_inode->i_rdev);
 	struct pp_struct *pp = file->private_data;
 	char * kbuffer;
 	ssize_t bytes_written = 0;
@@ -315,7 +315,7 @@
 static int pp_ioctl(struct inode *inode, struct file *file,
 		    unsigned int cmd, unsigned long arg)
 {
-	unsigned int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	struct pp_struct *pp = file->private_data;
 	struct parport * port;
 
@@ -613,7 +613,7 @@
 
 static int pp_open (struct inode * inode, struct file * file)
 {
-	unsigned int minor = MINOR (inode->i_rdev);
+	unsigned int minor = minor (inode->i_rdev);
 	struct pp_struct *pp;
 
 	if (minor >= PARPORT_MAX)
@@ -642,7 +642,7 @@
 
 static int pp_release (struct inode * inode, struct file * file)
 {
-	unsigned int minor = MINOR (inode->i_rdev);
+	unsigned int minor = minor (inode->i_rdev);
 	struct pp_struct *pp = file->private_data;
 	int compat_negot;
 
diff -u --recursive --new-file v2.5.1/linux/drivers/char/pty.c linux/drivers/char/pty.c
--- v2.5.1/linux/drivers/char/pty.c	Fri Sep 21 10:55:22 2001
+++ linux/drivers/char/pty.c	Tue Jan  1 11:42:40 2002
@@ -88,14 +88,14 @@
 		set_bit(TTY_OTHER_CLOSED, &tty->flags);
 #ifdef CONFIG_UNIX98_PTYS
 		{
-			unsigned int major = MAJOR(tty->device) - UNIX98_PTY_MASTER_MAJOR;
+			unsigned int major = major(tty->device) - UNIX98_PTY_MASTER_MAJOR;
 			if ( major < UNIX98_NR_MAJORS ) {
-				devpts_pty_kill( MINOR(tty->device)
+				devpts_pty_kill( minor(tty->device)
 			  - tty->driver.minor_start + tty->driver.name_base );
 			}
 		}
 #endif
-		tty_unregister_devfs (&tty->link->driver, MINOR (tty->device));
+		tty_unregister_devfs (&tty->link->driver, minor(tty->device));
 		tty_vhangup(tty->link);
 	}
 }
@@ -239,7 +239,7 @@
 #ifdef CONFIG_UNIX98_PTYS
 static int pty_get_device_number(struct tty_struct *tty, unsigned int *value)
 {
-	unsigned int result = MINOR(tty->device)
+	unsigned int result = minor(tty->device)
 		- tty->driver.minor_start + tty->driver.name_base;
 	return put_user(result, value);
 }
@@ -314,7 +314,7 @@
 	retval = -ENODEV;
 	if (!tty || !tty->link)
 		goto out;
-	line = MINOR(tty->device) - tty->driver.minor_start;
+	line = minor(tty->device) - tty->driver.minor_start;
 	if ((line < 0) || (line >= NR_PTYS))
 		goto out;
 	pty = (struct pty_struct *)(tty->driver.driver_state) + line;
@@ -334,10 +334,9 @@
 	/*  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);
+				   minor(tty->device)-tty->driver.minor_start);
 	retval = 0;
 out:
 	return retval;
diff -u --recursive --new-file v2.5.1/linux/drivers/char/raw.c linux/drivers/char/raw.c
--- v2.5.1/linux/drivers/char/raw.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/char/raw.c	Tue Jan  1 11:40:34 2002
@@ -74,7 +74,7 @@
 	int sector_size;
 	int sector_bits;
 
-	minor = MINOR(inode->i_rdev);
+	minor = minor(inode->i_rdev);
 	
 	/* 
 	 * Is it the control device? 
@@ -117,21 +117,8 @@
 	if (raw_devices[minor].inuse++)
 		goto out;
 
-	/* 
-	 * Don't interfere with mounted devices: we cannot safely set
-	 * the blocksize on a device which is already mounted.  
-	 */
-	
-	sector_size = 512;
-	if (is_mounted(rdev)) {
-		if (blksize_size[MAJOR(rdev)])
-			sector_size = blksize_size[MAJOR(rdev)][MINOR(rdev)];
-	} else
-		sector_size = get_hardsect_size(rdev);
-
-	set_blocksize(rdev, sector_size);
+	sector_size = get_hardsect_size(rdev);
 	raw_devices[minor].sector_size = sector_size;
-
 	for (sector_bits = 0; !(sector_size & 1); )
 		sector_size>>=1, sector_bits++;
 	raw_devices[minor].sector_bits = sector_bits;
@@ -147,7 +134,7 @@
 	int minor;
 	struct block_device *bdev;
 	
-	minor = MINOR(inode->i_rdev);
+	minor = minor(inode->i_rdev);
 	down(&raw_devices[minor].mutex);
 	bdev = raw_devices[minor].binding;
 	raw_devices[minor].inuse--;
@@ -205,8 +192,8 @@
 			 * major/minor numbers make sense. 
 			 */
 
-			if ((rq.block_major == NODEV && 
-			     rq.block_minor != NODEV) ||
+			if ((rq.block_major == 0 && 
+			     rq.block_minor != 0) ||
 			    rq.block_major > MAX_BLKDEV ||
 			    rq.block_minor > MINORMASK) {
 				err = -EINVAL;
@@ -222,7 +209,7 @@
 			if (raw_devices[minor].binding)
 				bdput(raw_devices[minor].binding);
 			raw_devices[minor].binding = 
-				bdget(kdev_t_to_nr(MKDEV(rq.block_major, rq.block_minor)));
+				bdget(kdev_t_to_nr(mk_kdev(rq.block_major, rq.block_minor)));
 			up(&raw_devices[minor].mutex);
 		} else {
 			struct block_device *bdev;
@@ -231,8 +218,8 @@
 			bdev = raw_devices[minor].binding;
 			if (bdev) {
 				dev = to_kdev_t(bdev->bd_dev);
-				rq.block_major = MAJOR(dev);
-				rq.block_minor = MINOR(dev);
+				rq.block_major = major(dev);
+				rq.block_minor = minor(dev);
 			} else {
 				rq.block_major = rq.block_minor = 0;
 			}
@@ -284,7 +271,7 @@
 	 * First, a few checks on device size limits 
 	 */
 
-	minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+	minor = minor(filp->f_dentry->d_inode->i_rdev);
 
 	new_iobuf = 0;
 	iobuf = filp->f_iobuf;
@@ -304,12 +291,12 @@
 	sector_bits = raw_devices[minor].sector_bits;
 	sector_mask = sector_size- 1;
 	
-	if (blk_size[MAJOR(dev)])
-		limit = (((loff_t) blk_size[MAJOR(dev)][MINOR(dev)]) << BLOCK_SIZE_BITS) >> sector_bits;
+	if (blk_size[major(dev)])
+		limit = (((loff_t) blk_size[major(dev)][minor(dev)]) << BLOCK_SIZE_BITS) >> sector_bits;
 	else
 		limit = INT_MAX;
 	dprintk ("rw_raw_dev: dev %d:%d (+%d)\n",
-		 MAJOR(dev), MINOR(dev), limit);
+		 major(dev), minor(dev), limit);
 	
 	err = -EINVAL;
 	if ((*offp & sector_mask) || (size & sector_mask))
diff -u --recursive --new-file v2.5.1/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.5.1/linux/drivers/char/serial.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/char/serial.c	Tue Jan  1 11:46:14 2002
@@ -3141,7 +3141,7 @@
 	unsigned long		page;
 
 	MOD_INC_USE_COUNT;
-	line = MINOR(tty->device) - tty->driver.minor_start;
+	line = minor(tty->device) - tty->driver.minor_start;
 	if ((line < 0) || (line >= NR_PORTS)) {
 		MOD_DEC_USE_COUNT;
 		return -ENODEV;
@@ -5825,35 +5825,6 @@
 	serial_out(info, UART_IER, ier);
 }
 
-/*
- *	Receive character from the serial port
- */
-static int serial_console_wait_key(struct console *co)
-{
-	static struct async_struct *info;
-	int ier, c;
-
-	info = &async_sercons;
-
-	/*
-	 *	First save the IER then disable the interrupts so
-	 *	that the real driver for the port does not get the
-	 *	character.
-	 */
-	ier = serial_in(info, UART_IER);
-	serial_out(info, UART_IER, 0x00);
- 
-	while ((serial_in(info, UART_LSR) & UART_LSR_DR) == 0);
-	c = serial_in(info, UART_RX);
-
-	/*
-	 *	Restore the interrupts
-	 */
-	serial_out(info, UART_IER, ier);
-
-	return c;
-}
-
 static kdev_t serial_console_device(struct console *c)
 {
 	return MKDEV(TTY_MAJOR, 64 + c->index);
@@ -5994,7 +5965,6 @@
 	name:		"ttyS",
 	write:		serial_console_write,
 	device:		serial_console_device,
-	wait_key:	serial_console_wait_key,
 	setup:		serial_console_setup,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
diff -u --recursive --new-file v2.5.1/linux/drivers/char/serial167.c linux/drivers/char/serial167.c
--- v2.5.1/linux/drivers/char/serial167.c	Sun Sep 16 21:23:07 2001
+++ linux/drivers/char/serial167.c	Sun Dec 30 10:31:51 2001
@@ -65,7 +65,6 @@
 
 #include <asm/system.h>
 #include <asm/io.h>
-#include <asm/segment.h>
 #include <asm/bitops.h>
 #include <asm/mvme16xhw.h>
 #include <asm/bootinfo.h>
@@ -2806,58 +2805,6 @@
 	restore_flags(flags);
 }
 
-/* This is a hack; if there are multiple chars waiting in the chip we
- * discard all but the last one, and return that.  The cd2401 is not really
- * designed to be driven in polled mode.
- */
-
-int serial167_console_wait_key(struct console *co)
-{
-	volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
-	unsigned long flags;
-	volatile u_char sink;
-	u_char ier;
-	int port;
-	int keypress = 0;
-
-	save_flags(flags); cli();
-
-	/* Ensure receiver is enabled! */
-
-	port = 0;
-	base_addr[CyCAR] = (u_char)port;
-	while (base_addr[CyCCR])
-		;
-	base_addr[CyCCR] = CyENB_RCVR;
-	ier = base_addr[CyIER];
-	base_addr[CyIER] = CyRxData;
-
-	while (!keypress) {
-		if (pcc2chip[PccSCCRICR] & 0x20)
-		{
-			/* We have an Rx int. Acknowledge it */
-			sink = pcc2chip[PccRPIACKR];
-			if ((base_addr[CyLICR] >> 2) == port) {
-				int cnt = base_addr[CyRFOC];
-				while (cnt-- > 0)
-				{
-					keypress = base_addr[CyRDR];
-				}
-				base_addr[CyREOIR] = 0;
-			}
-			else
-				base_addr[CyREOIR] = CyNOTRANS;
-		}
-	}
-
-	base_addr[CyIER] = ier;
-
-	restore_flags(flags);
-
-	return keypress;
-}
-
-
 static kdev_t serial167_console_device(struct console *c)
 {
 	return MKDEV(TTY_MAJOR, 64 + c->index);
@@ -2874,7 +2821,6 @@
 	name:		"ttyS",
 	write:		serial167_console_write,
 	device:		serial167_console_device,
-	wait_key:	serial167_console_wait_key,
 	setup:		serial167_console_setup,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
diff -u --recursive --new-file v2.5.1/linux/drivers/char/serial_21285.c linux/drivers/char/serial_21285.c
--- v2.5.1/linux/drivers/char/serial_21285.c	Thu Sep 13 15:21:32 2001
+++ linux/drivers/char/serial_21285.c	Tue Dec 25 15:39:20 2001
@@ -389,17 +389,6 @@
 	enable_irq(IRQ_CONTX);
 }
 
-static int rs285_console_wait_key(struct console *co)
-{
-	int c;
-
-	disable_irq(IRQ_CONRX);
-	while (*CSR_UARTFLG & 0x10);
-	c = *CSR_UARTDR;
-	enable_irq(IRQ_CONRX);
-	return c;
-}
-
 static kdev_t rs285_console_device(struct console *c)
 {
 	return MKDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);
@@ -493,7 +482,6 @@
 	name:		SERIAL_21285_NAME,
 	write:		rs285_console_write,
 	device:		rs285_console_device,
-	wait_key:	rs285_console_wait_key,
 	setup:		rs285_console_setup,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
diff -u --recursive --new-file v2.5.1/linux/drivers/char/serial_amba.c linux/drivers/char/serial_amba.c
--- v2.5.1/linux/drivers/char/serial_amba.c	Sun Sep 16 21:23:14 2001
+++ linux/drivers/char/serial_amba.c	Tue Dec 25 15:39:20 2001
@@ -1921,22 +1921,6 @@
 	UART_PUT_CR(port, old_cr);
 }
 
-/*
- *	Receive character from the serial port
- */
-static int ambauart_console_wait_key(struct console *co)
-{
-	struct amba_port *port = &amba_ports[co->index];
-	unsigned int status;
-	int c;
-
-	do {
-		status = UART_GET_FR(port);
-	} while (!UART_RX_DATA(status));
-	c = UART_GET_CHAR(port);
-	return c;
-}
-
 static kdev_t ambauart_console_device(struct console *c)
 {
 	return MKDEV(SERIAL_AMBA_MAJOR, SERIAL_AMBA_MINOR + c->index);
@@ -2015,7 +1999,6 @@
 	read:		ambauart_console_read,
 #endif
 	device:		ambauart_console_device,
-	wait_key:	ambauart_console_wait_key,
 	setup:		ambauart_console_setup,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
diff -u --recursive --new-file v2.5.1/linux/drivers/char/serial_tx3912.c linux/drivers/char/serial_tx3912.c
--- v2.5.1/linux/drivers/char/serial_tx3912.c	Fri Nov  9 14:01:21 2001
+++ linux/drivers/char/serial_tx3912.c	Tue Dec 25 15:39:20 2001
@@ -993,21 +993,6 @@
 	IntEnable2 = int2;
 }
 
-static int serial_console_wait_key(struct console *co)
-{
-	unsigned int int2, res;
-
-	int2 = IntEnable2;
-	IntEnable2 = 0;
-
-	while (!(UartA_Ctrl1 & UART_RX_HOLD_FULL));
-	res = UartA_Data;
-	udelay(10);
-	
-	IntEnable2 = int2;
-	return res;
-}
-
 static void serial_console_write(struct console *co, const char *s,
 		unsigned count)
 {
@@ -1065,7 +1050,6 @@
 	name:     "ttyS",
 	write:    serial_console_write,
 	device:   serial_console_device,
-	wait_key: serial_console_wait_key,
 	setup:    serial_console_setup,
 	flags:    CON_PRINTBUFFER,
 	index:    -1
diff -u --recursive --new-file v2.5.1/linux/drivers/char/sh-sci.c linux/drivers/char/sh-sci.c
--- v2.5.1/linux/drivers/char/sh-sci.c	Mon Oct 15 13:36:48 2001
+++ linux/drivers/char/sh-sci.c	Tue Dec 25 15:39:20 2001
@@ -1181,15 +1181,6 @@
 	put_string(sercons_port, s, count);
 }
 
-/*
- *	Receive character from the serial port
- */
-static int serial_console_wait_key(struct console *co)
-{
-	/* Not implemented yet */
-	return 0;
-}
-
 static kdev_t serial_console_device(struct console *c)
 {
 	return MKDEV(SCI_MAJOR, SCI_MINOR_START + c->index);
@@ -1273,7 +1264,6 @@
 	name:		"ttySC",
 	write:		serial_console_write,
 	device:		serial_console_device,
-	wait_key:	serial_console_wait_key,
 	setup:		serial_console_setup,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
diff -u --recursive --new-file v2.5.1/linux/drivers/char/synclink.c linux/drivers/char/synclink.c
--- v2.5.1/linux/drivers/char/synclink.c	Fri Sep 14 14:39:59 2001
+++ linux/drivers/char/synclink.c	Sun Dec 30 10:31:51 2001
@@ -114,7 +114,6 @@
 #endif
 #endif
 
-#include <asm/segment.h>
 #define GET_USER(error,value,addr) error = get_user(value,addr)
 #define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
 #define PUT_USER(error,value,addr) error = put_user(value,addr)
diff -u --recursive --new-file v2.5.1/linux/drivers/char/sysrq.c linux/drivers/char/sysrq.c
--- v2.5.1/linux/drivers/char/sysrq.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/char/sysrq.c	Thu Jan  3 12:20:10 2002
@@ -105,7 +105,7 @@
 /* Guesses if the device is a local hard drive */
 static int is_local_disk(kdev_t dev) {
 	unsigned int major;
-	major = MAJOR(dev);
+	major = major(dev);
 
 	switch (major) {
 	case IDE0_MAJOR:
@@ -206,7 +206,7 @@
 	for (sb = sb_entry(super_blocks.next);
 	     sb != sb_entry(&super_blocks); 
 	     sb = sb_entry(sb->s_list.next))
-		if (!is_local_disk(sb->s_dev) && MAJOR(sb->s_dev))
+		if (!is_local_disk(sb->s_dev) && major(sb->s_dev))
 			go_sync(sb, remount_flag);
 
 	unlock_kernel();
diff -u --recursive --new-file v2.5.1/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.5.1/linux/drivers/char/tty_io.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/char/tty_io.c	Thu Jan  3 13:22:21 2002
@@ -102,10 +102,10 @@
 
 #include <linux/kmod.h>
 
-#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
-#define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
-#define SYSCONS_DEV MKDEV(TTYAUX_MAJOR,1)
-#define PTMX_DEV MKDEV(TTYAUX_MAJOR,2)
+#define IS_CONSOLE_DEV(dev)	(kdev_val(dev) == __mkdev(TTY_MAJOR,0))
+#define IS_TTY_DEV(dev)		(kdev_val(dev) == __mkdev(TTYAUX_MAJOR,0))
+#define IS_SYSCONS_DEV(dev)	(kdev_val(dev) == __mkdev(TTYAUX_MAJOR,1))
+#define IS_PTMX_DEV(dev)	(kdev_val(dev) == __mkdev(TTYAUX_MAJOR,2))
 
 #undef TTY_DEBUG_HANGUP
 
@@ -185,7 +185,7 @@
 static char *
 _tty_make_name(struct tty_struct *tty, const char *name, char *buf)
 {
-	int idx = (tty)?MINOR(tty->device) - tty->driver.minor_start:0;
+	int idx = (tty)? minor(tty->device) - tty->driver.minor_start:0;
 
 	if (!tty) /* Hmm.  NULL pointer.  That's fun. */
 		strcpy(buf, "NULL tty");
@@ -196,7 +196,7 @@
 	return buf;
 }
 
-#define TTY_NUMBER(tty) (MINOR((tty)->device) - (tty)->driver.minor_start + \
+#define TTY_NUMBER(tty) (minor((tty)->device) - (tty)->driver.minor_start + \
 			 (tty)->driver.name_base)
 
 char *tty_name(struct tty_struct *tty, char *buf)
@@ -331,8 +331,8 @@
 	int	major, minor;
 	struct tty_driver *p;
 	
-	minor = MINOR(device);
-	major = MAJOR(device);
+	minor = minor(device);
+	major = major(device);
 
 	for (p = tty_drivers; p; p = p->next) {
 		if (p->major != major)
@@ -442,8 +442,8 @@
 	file_list_lock();
 	for (l = tty->tty_files.next; l != &tty->tty_files; l = l->next) {
 		struct file * filp = list_entry(l, struct file, f_list);
-		if (filp->f_dentry->d_inode->i_rdev == CONSOLE_DEV ||
-		    filp->f_dentry->d_inode->i_rdev == SYSCONS_DEV) {
+		if (IS_CONSOLE_DEV(filp->f_dentry->d_inode->i_rdev) ||
+		    IS_SYSCONS_DEV(filp->f_dentry->d_inode->i_rdev)) {
 			cons_filp = filp;
 			continue;
 		}
@@ -597,12 +597,6 @@
 	read_unlock(&tasklist_lock);
 }
 
-void wait_for_keypress(void)
-{
-        struct console *c = console_drivers;
-        if (c) c->wait_key(c);
-}
-
 void stop_tty(struct tty_struct *tty)
 {
 	if (tty->stopped)
@@ -658,7 +652,7 @@
 	   moved it to there.  This should only be done for the N_TTY
 	   line discipline, anyway.  Same goes for write_chan(). -- jlc. */
 #if 0
-	if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */
+	if (!IS_CONSOLE_DEV(inode->i_rdev) && /* don't stop on /dev/console */
 	    (tty->pgrp > 0) &&
 	    (current->tty == tty) &&
 	    (tty->pgrp != current->pgrp))
@@ -747,8 +741,8 @@
 	 *      well as /dev/tty0.
 	 */
 	inode = file->f_dentry->d_inode;
-	is_console = (inode->i_rdev == SYSCONS_DEV ||
-		      inode->i_rdev == CONSOLE_DEV);
+	is_console = IS_SYSCONS_DEV(inode->i_rdev) ||
+		     IS_CONSOLE_DEV(inode->i_rdev);
 
 	if (is_console && redirect)
 		tty = redirect;
@@ -809,7 +803,7 @@
 	if (!driver)
 		return -ENODEV;
 
-	idx = MINOR(device) - driver->minor_start;
+	idx = minor(device) - driver->minor_start;
 
 	/* 
 	 * Check whether we need to acquire the tty semaphore to avoid
@@ -863,7 +857,7 @@
 		if (!o_tty)
 			goto free_mem_out;
 		initialize_tty_struct(o_tty);
-		o_tty->device = (kdev_t) MKDEV(driver->other->major,
+		o_tty->device = mk_kdev(driver->other->major,
 					driver->other->minor_start + idx);
 		o_tty->driver = *driver->other;
 
@@ -1055,7 +1049,7 @@
 
 	tty_fasync(-1, filp, 0);
 
-	idx = MINOR(tty->device) - tty->driver.minor_start;
+	idx = minor(tty->device) - tty->driver.minor_start;
 	pty_master = (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
 		      tty->driver.subtype == PTY_TYPE_MASTER);
 	o_tty = tty->link;
@@ -1291,7 +1285,7 @@
 retry_open:
 	noctty = filp->f_flags & O_NOCTTY;
 	device = inode->i_rdev;
-	if (device == TTY_DEV) {
+	if (IS_TTY_DEV(device)) {
 		if (!current->tty)
 			return -ENXIO;
 		device = current->tty->device;
@@ -1299,13 +1293,13 @@
 		/* noctty = 1; */
 	}
 #ifdef CONFIG_VT
-	if (device == CONSOLE_DEV) {
+	if (IS_CONSOLE_DEV(device)) {
 		extern int fg_console;
-		device = MKDEV(TTY_MAJOR, fg_console + 1);
+		device = mk_kdev(TTY_MAJOR, fg_console + 1);
 		noctty = 1;
 	}
 #endif
-	if (device == SYSCONS_DEV) {
+	if (IS_SYSCONS_DEV(device)) {
 		struct console *c = console_drivers;
 		while(c && !c->device)
 			c = c->next;
@@ -1316,7 +1310,7 @@
 		noctty = 1;
 	}
 
-	if (device == PTMX_DEV) {
+	if (IS_PTMX_DEV(device)) {
 #ifdef CONFIG_UNIX98_PTYS
 
 		/* find a free pty. */
@@ -1330,7 +1324,7 @@
 			for (minor = driver->minor_start ;
 			     minor < driver->minor_start + driver->num ;
 			     minor++) {
-				device = MKDEV(driver->major, minor);
+				device = mk_kdev(driver->major, minor);
 				if (!init_dev(device, &tty)) goto ptmx_found; /* ok! */
 			}
 		}
@@ -1338,8 +1332,8 @@
 	ptmx_found:
 		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,
+		devpts_pty_new(driver->other->name_base + minor, mk_kdev(driver->other->major, minor + driver->other->minor_start));
+		tty_register_devfs(&pts_driver[major], DEVFS_FL_DEFAULT,
 				   pts_driver[major].minor_start + minor);
 		noctty = 1;
 		goto init_dev_done;
@@ -1511,8 +1505,8 @@
 static int tioccons(struct inode *inode,
 	struct tty_struct *tty, struct tty_struct *real_tty)
 {
-	if (inode->i_rdev == SYSCONS_DEV ||
-	    inode->i_rdev == CONSOLE_DEV) {
+	if (IS_SYSCONS_DEV(inode->i_rdev) ||
+	    IS_CONSOLE_DEV(inode->i_rdev)) {
 		if (!suser())
 			return -EPERM;
 		redirect = NULL;
@@ -2008,19 +2002,15 @@
 {
 #ifdef CONFIG_DEVFS_FS
 	umode_t mode = S_IFCHR | S_IRUSR | S_IWUSR;
-	kdev_t device = MKDEV (driver->major, minor);
+	kdev_t device = mk_kdev(driver->major, minor);
 	int idx = minor - driver->minor_start;
 	char buf[32];
 
-	switch (device) {
-		case TTY_DEV:
-		case PTMX_DEV:
+	if (IS_TTY_DEV(device) || IS_PTMX_DEV(device)) 
+		mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+	else {
+		if (driver->major == PTY_MASTER_MAJOR)
 			mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
-			break;
-		default:
-			if (driver->major == PTY_MASTER_MAJOR)
-				mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
-			break;
 	}
 	if ( (minor <  driver->minor_start) || 
 	     (minor >= driver->minor_start + driver->num) ) {
@@ -2295,8 +2285,8 @@
 	dev_ptmx_driver = dev_tty_driver;
 	dev_ptmx_driver.driver_name = "/dev/ptmx";
 	dev_ptmx_driver.name = dev_ptmx_driver.driver_name + 5;
-	dev_ptmx_driver.major= MAJOR(PTMX_DEV);
-	dev_ptmx_driver.minor_start = MINOR(PTMX_DEV);
+	dev_ptmx_driver.major= TTYAUX_MAJOR;
+	dev_ptmx_driver.minor_start = 2;
 	dev_ptmx_driver.type = TTY_DRIVER_TYPE_SYSTEM;
 	dev_ptmx_driver.subtype = SYSTEM_TYPE_SYSPTMX;
 
diff -u --recursive --new-file v2.5.1/linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c
--- v2.5.1/linux/drivers/char/vc_screen.c	Sun Sep 16 21:22:40 2001
+++ linux/drivers/char/vc_screen.c	Tue Jan  1 11:43:51 2002
@@ -49,7 +49,8 @@
 vcs_size(struct inode *inode)
 {
 	int size;
-	int currcons = MINOR(inode->i_rdev) & 127;
+	int minor = minor(inode->i_rdev);
+	int currcons = minor & 127;
 	if (currcons == 0)
 		currcons = fg_console;
 	else
@@ -59,7 +60,7 @@
 
 	size = video_num_lines * video_num_columns;
 
-	if (MINOR(inode->i_rdev) & 128)
+	if (minor & 128)
 		size = 2*size + HEADER_SIZE;
 	return size;
 }
@@ -97,7 +98,7 @@
 vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	unsigned int currcons = MINOR(inode->i_rdev);
+	unsigned int currcons = minor(inode->i_rdev);
 	long pos = *ppos;
 	long viewed, attr, read;
 	int col, maxcol;
@@ -266,7 +267,7 @@
 vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	unsigned int currcons = MINOR(inode->i_rdev);
+	unsigned int currcons = minor(inode->i_rdev);
 	long pos = *ppos;
 	long viewed, attr, size, written;
 	char *con_buf0;
@@ -449,7 +450,7 @@
 static int
 vcs_open(struct inode *inode, struct file *filp)
 {
-	unsigned int currcons = (MINOR(inode->i_rdev) & 127);
+	unsigned int currcons = minor(inode->i_rdev) & 127;
 	if(currcons && !vc_cons_allocated(currcons-1))
 		return -ENXIO;
 	return 0;
diff -u --recursive --new-file v2.5.1/linux/drivers/char/vme_scc.c linux/drivers/char/vme_scc.c
--- v2.5.1/linux/drivers/char/vme_scc.c	Sun Sep 16 21:22:50 2001
+++ linux/drivers/char/vme_scc.c	Tue Dec 25 15:39:20 2001
@@ -1065,41 +1065,6 @@
 	restore_flags(flags);
 }
 
-
-static int scc_console_wait_key(struct console *co)
-{
-	unsigned long	flags;
-	volatile char *p = NULL;
-	int c;
-	
-#ifdef CONFIG_MVME147_SCC
-	if (MACH_IS_MVME147)
-		p = (volatile char *)M147_SCC_A_ADDR;
-#endif
-#ifdef CONFIG_MVME162_SCC
-	if (MACH_IS_MVME16x)
-		p = (volatile char *)MVME_SCC_A_ADDR;
-#endif
-#ifdef CONFIG_BVME6000_SCC
-	if (MACH_IS_BVME6000)
-		p = (volatile char *)BVME_SCC_A_ADDR;
-#endif
-
-	save_flags(flags);
-	cli();
-
-	/* wait for rx buf filled */
-	while ((*p & 0x01) == 0)
-		;
-
-	*p = 8;
-	scc_delay();
-	c = *p;
-	restore_flags(flags);
-	return c;
-}
-
-
 static kdev_t scc_console_device(struct console *c)
 {
 	return MKDEV(TTY_MAJOR, SCC_MINOR_BASE + c->index);
@@ -1116,7 +1081,6 @@
 	name:		"ttyS",
 	write:		scc_console_write,
 	device:		scc_console_device,
-	wait_key:	scc_console_wait_key,
 	setup:		scc_console_setup,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
diff -u --recursive --new-file v2.5.1/linux/drivers/char/wdt.c linux/drivers/char/wdt.c
--- v2.5.1/linux/drivers/char/wdt.c	Tue Dec 18 14:56:35 2001
+++ linux/drivers/char/wdt.c	Thu Jan  3 12:20:10 2002
@@ -265,7 +265,7 @@
 	if (ptr != &file->f_pos)
 		return -ESPIPE;
 
-	switch(MINOR(file->f_dentry->d_inode->i_rdev))
+	switch(minor(file->f_dentry->d_inode->i_rdev))
 	{
 		case TEMP_MINOR:
 			c*=11;
@@ -334,7 +334,7 @@
  
 static int wdt_open(struct inode *inode, struct file *file)
 {
-	switch(MINOR(inode->i_rdev))
+	switch(minor(inode->i_rdev))
 	{
 		case WATCHDOG_MINOR:
 			if(test_and_set_bit(0, &wdt_is_open))
@@ -373,7 +373,7 @@
  
 static int wdt_release(struct inode *inode, struct file *file)
 {
-	if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
+	if(minor(inode->i_rdev)==WATCHDOG_MINOR)
 	{
 #ifndef CONFIG_WATCHDOG_NOWAYOUT	
 		inb_p(WDT_DC);		/* Disable counters */
diff -u --recursive --new-file v2.5.1/linux/drivers/char/wdt_pci.c linux/drivers/char/wdt_pci.c
--- v2.5.1/linux/drivers/char/wdt_pci.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/char/wdt_pci.c	Thu Jan  3 12:20:10 2002
@@ -281,7 +281,7 @@
 	if (ptr != &file->f_pos)
 		return -ESPIPE;
 
-	switch(MINOR(file->f_dentry->d_inode->i_rdev))
+	switch(minor(file->f_dentry->d_inode->i_rdev))
 	{
 		case TEMP_MINOR:
 			c*=11;
@@ -350,7 +350,7 @@
  
 static int wdtpci_open(struct inode *inode, struct file *file)
 {
-	switch(MINOR(inode->i_rdev))
+	switch(minor(inode->i_rdev))
 	{
 		case WATCHDOG_MINOR:
 			if( test_and_set_bit(0,&wdt_is_open) ) 
@@ -410,7 +410,7 @@
  
 static int wdtpci_release(struct inode *inode, struct file *file)
 {
-	if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
+	if(minor(inode->i_rdev)==WATCHDOG_MINOR)
 	{
 #ifndef CONFIG_WATCHDOG_NOWAYOUT	
 		inb_p(WDT_DC);		/* Disable counters */
diff -u --recursive --new-file v2.5.1/linux/drivers/i2c/i2c-dev.c linux/drivers/i2c/i2c-dev.c
--- v2.5.1/linux/drivers/i2c/i2c-dev.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/i2c/i2c-dev.c	Thu Jan  3 12:20:10 2002
@@ -382,7 +382,7 @@
 
 int i2cdev_open (struct inode *inode, struct file *file)
 {
-	unsigned int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	struct i2c_client *client;
 
 	if ((minor >= I2CDEV_ADAPS_MAX) || ! (i2cdev_adaps[minor])) {
@@ -415,7 +415,7 @@
 
 static int i2cdev_release (struct inode *inode, struct file *file)
 {
-	unsigned int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	kfree(file->private_data);
 	file->private_data=NULL;
 #ifdef DEBUG
diff -u --recursive --new-file v2.5.1/linux/drivers/ide/amd74xx.c linux/drivers/ide/amd74xx.c
--- v2.5.1/linux/drivers/ide/amd74xx.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/amd74xx.c	Mon Dec 17 10:49:31 2001
@@ -459,6 +459,8 @@
 	hwif->tuneproc = &amd74xx_tune_drive;
 	hwif->speedproc = &amd74xx_tune_chipset;
 
+	hwif->highmem = 1;
+
 #ifndef CONFIG_BLK_DEV_IDEDMA
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
diff -u --recursive --new-file v2.5.1/linux/drivers/ide/ataraid.c linux/drivers/ide/ataraid.c
--- v2.5.1/linux/drivers/ide/ataraid.c	Thu Oct 25 13:58:35 2001
+++ linux/drivers/ide/ataraid.c	Mon Dec 31 17:56:19 2001
@@ -269,7 +269,6 @@
 	ataraid_gendisk.major       = ATAMAJOR;
 	ataraid_gendisk.major_name  = "ataraid";
 	ataraid_gendisk.minor_shift = 4;
-	ataraid_gendisk.max_p	    = 15;
 	ataraid_gendisk.sizes	    = &ataraid_gendisk_sizes[0];
 	ataraid_gendisk.nr_real	    = 16;
 	ataraid_gendisk.fops        = &ataraid_fops;
diff -u --recursive --new-file v2.5.1/linux/drivers/ide/hd.c linux/drivers/ide/hd.c
--- v2.5.1/linux/drivers/ide/hd.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/hd.c	Mon Dec 31 17:56:19 2001
@@ -693,7 +693,6 @@
 	major:		MAJOR_NR,
 	major_name:	"hd",
 	minor_shift:	6,
-	max_p:		1 << 6,
 	part:		hd,
 	sizes:		hd_sizes,
 	fops:		&hd_fops,
diff -u --recursive --new-file v2.5.1/linux/drivers/ide/hptraid.c linux/drivers/ide/hptraid.c
--- v2.5.1/linux/drivers/ide/hptraid.c	Mon Oct 15 13:27:42 2001
+++ linux/drivers/ide/hptraid.c	Thu Dec 27 08:17:43 2001
@@ -226,32 +226,20 @@
 
 #include "hptraid.h"
 
-static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
+static int __init read_disk_sb(struct block_device *bdev,
+				struct highpoint_raid_conf *buf)
 {
-	int ret = -EINVAL;
-	struct buffer_head *bh = NULL;
-	kdev_t dev = MKDEV(major,minor);
-	
-	if (blksize_size[major]==NULL)	 /* device doesn't exist */
-		return -EINVAL;
-	
-
-	/* Superblock is at 4096+412 bytes */
-	set_blocksize (dev, 4096);
-	bh = bread (dev, 1, 4096);
-
-	
-	if (bh) {
-		memcpy (buffer, bh->b_data, bufsize);
-	} else {
-		printk(KERN_ERR "hptraid: Error reading superblock.\n");
-		goto abort;
+	/* Superblock is at 9*512 bytes */
+	Sector sect;
+	unsigned char *p = read_dev_sector(bdev, 9, &sect);
+
+	if (p) {
+		memcpy(buf, p, 512);
+		put_dev_sector(&sect);
+		return 0;
 	}
-	ret = 0;
-abort:
-	if (bh)
-		brelse (bh);
-	return ret;
+	printk(KERN_ERR "hptraid: Error reading superblock.\n");
+	return -1;
 }
 
 static unsigned long maxsectors (int major,int minor)
@@ -276,55 +264,58 @@
 	return lba;
 }
 
+static struct highpoint_raid_conf __initdata prom;
 static void __init probedisk(int major, int minor,int device)
 {
 	int i;
-        struct highpoint_raid_conf *prom;
-	static unsigned char block[4096];
-	struct block_device *bdev;
-	
-	if (maxsectors(major,minor)==0)
+	struct block_device *bdev = bdget(MKDEV(major,minor));
+	struct gendisk *gd;
+
+	if (!bdev)
 		return;
-	
-        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
-        	return;
-                                                                                                                 
-        prom = (struct highpoint_raid_conf*)&block[512];
-                
-        if (prom->magic!=  0x5a7816f0)
-        	return;
-        if (prom->type) {
+
+	if (blkdev_get(bdev,FMODE_READ|FMODE_WRITE,0,BDEV_RAW) < 0)
+		return;
+
+	if (maxsectors(major,minor)==0)
+		goto out;
+
+        if (read_disk_sb(bdev, &prom))
+        	goto out;
+
+        if (prom.magic!=  0x5a7816f0)
+        	goto out;
+        if (prom.type) {
         	printk(KERN_INFO "hptraid: only RAID0 is supported currently\n");
-        	return;
+        	goto out;
         }
 
-	i = prom->disk_number;
+	i = prom.disk_number;
 	if (i<0)
-		return;
+		goto out;
 	if (i>8) 
-		return;
+		goto out;
+
+	raid[device].disk[i].bdev = bdev;
+	/* This is supposed to prevent others from stealing our underlying disks */
+	/* now blank the /proc/partitions table for the wrong partition table,
+	   so that scripts don't accidentally mount it and crash the kernel */
+	 /* XXX: the 0 is an utter hack  --hch */
+	gd=get_gendisk(MKDEV(major, 0));
+	if (gd!=NULL) {
+		int j;
+		for (j=1+(minor<<gd->minor_shift);j<((minor+1)<<gd->minor_shift);j++) 
+			gd->part[j].nr_sects=0;					
+	}
 
-	bdev = bdget(MKDEV(major,minor));
-	if (bdev && blkdev_get(bdev,FMODE_READ|FMODE_WRITE,0,BDEV_RAW) == 0) {
-        	int j=0;
-        	struct gendisk *gd;
-		raid[device].disk[i].bdev = bdev;
-        	/* This is supposed to prevent others from stealing our underlying disks */
-		/* now blank the /proc/partitions table for the wrong partition table,
-		   so that scripts don't accidentally mount it and crash the kernel */
-		 /* XXX: the 0 is an utter hack  --hch */
-		gd=get_gendisk(MKDEV(major, 0));
-		if (gd!=NULL) {
-			for (j=1+(minor<<gd->minor_shift);j<((minor+1)<<gd->minor_shift);j++) 
-				gd->part[j].nr_sects=0;					
-		}
-        }
 	raid[device].disk[i].device = MKDEV(major,minor);
 	raid[device].disk[i].sectors = maxsectors(major,minor);
-	raid[device].stride = (1<<prom->raid0_shift);
-	raid[device].disks = prom->raid_disks;
-	raid[device].sectors = prom->total_secs;
-			
+	raid[device].stride = (1<<prom.raid0_shift);
+	raid[device].disks = prom.raid_disks;
+	raid[device].sectors = prom.total_secs;
+	return;
+out:
+	blkdev_put(bdev);
 }
 
 static void __init fill_cutoff(int device)
diff -u --recursive --new-file v2.5.1/linux/drivers/ide/icside.c linux/drivers/ide/icside.c
--- v2.5.1/linux/drivers/ide/icside.c	Thu Oct 25 13:53:47 2001
+++ linux/drivers/ide/icside.c	Tue Dec 25 21:43:32 2001
@@ -27,6 +27,7 @@
 #include <asm/io.h>
 
 extern char *ide_xfer_verbose (byte xfer_rate);
+extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
 
 /*
  * Maximum number of interfaces per card
@@ -225,29 +226,18 @@
 
 static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq)
 {
-	struct buffer_head *bh;
+	request_queue_t *q = &hwif->drives[DEVICE_NR(rq->rq_dev) & 1].queue;
 	struct scatterlist *sg = hwif->sg_table;
-	int nents = 0;
+	int nents = blk_rq_map_sg(q, rq, sg);
 
-	if (rq->cmd == READ)
+	if (rq->q && nents > rq->nr_phys_segments)
+		printk("icside: received %d segments, build %d\n",
+			rq->nr_phys_segments, nents);
+
+	if (rq_data_dir(rq) == READ)
 		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
 	else
 		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
-	bh = rq->bh;
-	do {
-		unsigned char *virt_addr = bh->b_data;
-		unsigned int size = bh->b_size;
-
-		while ((bh = bh->b_reqnext) != NULL) {
-			if ((virt_addr + size) != (unsigned char *)bh->b_data)
-				break;
-			size += bh->b_size;
-		}
-		memset(&sg[nents], 0, sizeof(*sg));
-		sg[nents].address = virt_addr;
-		sg[nents].length = size;
-		nents++;
-	} while (bh != NULL);
 
 	return pci_map_sg(NULL, sg, nents, hwif->sg_dma_direction);
 }
@@ -267,39 +257,56 @@
 	pci_unmap_sg(NULL, sg, nents, HWIF(drive)->sg_dma_direction);
 }
 
+/*
+ * Configure the IOMD to give the appropriate timings for the transfer
+ * mode being requested.  We take the advice of the ATA standards, and
+ * calculate the cycle time based on the transfer mode, and the EIDE
+ * MW DMA specs that the drive provides in the IDENTIFY command.
+ *
+ * We have the following IOMD DMA modes to choose from:
+ *
+ *	Type	Active		Recovery	Cycle
+ *	A	250 (250)	312 (550)	562 (800)
+ *	B	187		250		437
+ *	C	125 (125)	125 (375)	250 (500)
+ *	D	62		125		187
+ *
+ * (figures in brackets are actual measured timings)
+ *
+ * However, we also need to take care of the read/write active and
+ * recovery timings:
+ *
+ *			Read	Write
+ *  	Mode	Active	-- Recovery --	Cycle	IOMD type
+ *	MW0	215	50	215	480	A
+ *	MW1	80	50	50	150	C
+ *	MW2	70	25	25	120	C
+ */
 static int
 icside_config_if(ide_drive_t *drive, int xfer_mode)
 {
 	int func = ide_dma_off;
+	int cycle_time = 0, use_dma_info = 0;
 
 	switch (xfer_mode) {
-	case XFER_MW_DMA_2:
-		/*
-		 * The cycle time is limited to 250ns by the r/w
-		 * pulse width (90ns), however we should still
-		 * have a maximum burst transfer rate of 8MB/s.
-		 */
-		drive->drive_data = 250;
-		break;
-
-	case XFER_MW_DMA_1:
-		drive->drive_data = 250;
-		break;
+	case XFER_MW_DMA_2: cycle_time = 250; use_dma_info = 1;	break;
+	case XFER_MW_DMA_1: cycle_time = 250; use_dma_info = 1;	break;
+	case XFER_MW_DMA_0: cycle_time = 480;			break;
+	}
 
-	case XFER_MW_DMA_0:
-		drive->drive_data = 480;
-		break;
+	/*
+	 * If we're going to be doing MW_DMA_1 or MW_DMA_2, we should
+	 * take care to note the values in the ID...
+	 */
+	if (use_dma_info && drive->id->eide_dma_time > cycle_time)
+		cycle_time = drive->id->eide_dma_time;
 
-	default:
-		drive->drive_data = 0;
-		break;
-	}
+	drive->drive_data = cycle_time;
 
 	if (!drive->init_speed)
-		drive->init_speed = (byte) xfer_mode;
+		drive->init_speed = xfer_mode;
 
-	if (drive->drive_data &&
-	    ide_config_drive_speed(drive, (byte) xfer_mode) == 0)
+	if (cycle_time && ide_config_drive_speed(drive, xfer_mode) == 0)
 		func = ide_dma_on;
 	else
 		drive->drive_data = 480;
@@ -307,7 +314,7 @@
 	printk("%s: %s selected (peak %dMB/s)\n", drive->name,
 		ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
 
-	drive->current_speed = (byte) xfer_mode;
+	drive->current_speed = xfer_mode;
 
 	return func;
 }
@@ -414,7 +421,7 @@
  *  This is setup to be called as an extern for future support
  *  to other special driver code.
  */
-static int check_drive_lists(ide_drive_t *drive, int good_bad)
+static int icside_check_drive_lists(ide_drive_t *drive, int good_bad)
 {
 	struct hd_driveid *id = drive->id;
 
@@ -444,7 +451,7 @@
 	/*
 	 * Consult the list of known "bad" drives
 	 */
-	if (check_drive_lists(drive, 0)) {
+	if (icside_check_drive_lists(drive, 0)) {
 		func = ide_dma_off;
 		goto out;
 	}
@@ -469,7 +476,7 @@
 	/*
 	 * Consult the list of known "good" drives
 	 */
-	if (check_drive_lists(drive, 1)) {
+	if (icside_check_drive_lists(drive, 1)) {
 		if (id->eide_dma_time > 150)
 			goto out;
 		xfer_mode = XFER_MW_DMA_1;
@@ -502,6 +509,11 @@
 
 	case ide_dma_off_quietly:
 	case ide_dma_on:
+		/*
+		 * We don't need any bouncing.  Yes, this looks the
+		 * wrong way around, but it is correct.
+		 */
+		blk_queue_bounce_limit(&drive->queue, BLK_BOUNCE_ANY);
 		drive->using_dma = (func == ide_dma_on);
 		return 0;
 
@@ -553,7 +565,8 @@
 
 	case ide_dma_bad_drive:
 	case ide_dma_good_drive:
-		return check_drive_lists(drive, (func == ide_dma_good_drive));
+		return icside_check_drive_lists(drive, (func ==
+						ide_dma_good_drive));
 
 	case ide_dma_verbose:
 		return icside_dma_verbose(drive);
@@ -590,6 +603,15 @@
 failed:
 	printk(" -- ERROR, unable to allocate DMA table\n");
 	return 0;
+}
+
+int ide_release_dma(ide_hwif_t *hwif)
+{
+	if (hwif->sg_table) {
+		kfree(hwif->sg_table);
+		hwif->sg_table = NULL;
+	}
+	return 1;
 }
 #endif
 
diff -u --recursive --new-file v2.5.1/linux/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c
--- v2.5.1/linux/drivers/ide/ide-cd.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/ide-cd.c	Mon Dec 31 13:37:35 2001
@@ -594,7 +594,7 @@
 		cdrom_end_request (1, drive);
 		*startstop = ide_error (drive, "request sense failure", stat);
 		return 1;
-	} else if (rq->flags & REQ_PC) {
+	} else if (rq->flags & (REQ_PC | REQ_BLOCK_PC)) {
 		/* All other functions, except for READ. */
 		struct completion *wait = NULL;
 		pc = (struct packet_command *) rq->special;
@@ -2015,7 +2015,7 @@
 
 	/* Now try to get the total cdrom capacity. */
 	minor = (drive->select.b.unit) << PARTN_BITS;
-	dev = MKDEV(HWIF(drive)->major, minor);
+	dev = mk_kdev(HWIF(drive)->major, minor);
 	stat = cdrom_get_last_written(dev, &toc->capacity);
 	if (stat)
 		stat = cdrom_read_capacity(drive, &toc->capacity, sense);
@@ -2481,7 +2481,7 @@
 	struct cdrom_device_info *devinfo = &info->devinfo;
 	int minor = (drive->select.b.unit) << PARTN_BITS;
 
-	devinfo->dev = MKDEV (HWIF(drive)->major, minor);
+	devinfo->dev = mk_kdev(HWIF(drive)->major, minor);
 	devinfo->ops = &ide_cdrom_dops;
 	devinfo->mask = 0;
 	*(int *)&devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
@@ -2588,6 +2588,13 @@
 	if (cap.mechtype == mechtype_caddy || cap.mechtype == mechtype_popup)
 		CDROM_CONFIG_FLAGS (drive)->close_tray = 0;
 
+	/* Some drives used by Apple don't advertise audio play
+	 * but they do support reading TOC & audio datas
+	 */
+	if (strcmp (drive->id->model, "MATSHITADVD-ROM SR-8187") == 0 ||
+	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8186") == 0)
+		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
+
 #if ! STANDARD_ATAPI
 	if (cdi->sanyo_slot > 0) {
 		CDROM_CONFIG_FLAGS (drive)->is_changer = 1;
@@ -2671,10 +2678,12 @@
 	/*
 	 * default to read-only always and fix latter at the bottom
 	 */
-	set_device_ro(MKDEV(HWIF(drive)->major, minor), 1);
-	set_blocksize(MKDEV(HWIF(drive)->major, minor), CD_FRAMESIZE);
+	set_device_ro(mk_kdev(HWIF(drive)->major, minor), 1);
+	set_blocksize(mk_kdev(HWIF(drive)->major, minor), CD_FRAMESIZE);
 	blk_queue_hardsect_size(&drive->queue, CD_FRAMESIZE);
 
+	blk_queue_prep_rq(&drive->queue, ll_10byte_cmd_build);
+
 	drive->special.all	= 0;
 	drive->ready_stat	= 0;
 
@@ -2792,7 +2801,7 @@
 	nslots = ide_cdrom_probe_capabilities (drive);
 
 	if (CDROM_CONFIG_FLAGS(drive)->dvd_ram)
-		set_device_ro(MKDEV(HWIF(drive)->major, minor), 0);
+		set_device_ro(mk_kdev(HWIF(drive)->major, minor), 0);
 
 	if (ide_cdrom_register (drive, nslots)) {
 		printk ("%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
@@ -2839,7 +2848,7 @@
 static
 int ide_cdrom_check_media_change (ide_drive_t *drive)
 {
-	return cdrom_media_changed(MKDEV (HWIF (drive)->major,
+	return cdrom_media_changed(mk_kdev (HWIF (drive)->major,
 			(drive->select.b.unit) << PARTN_BITS));
 }
 
@@ -2867,7 +2876,7 @@
 	 * 1024 even for CDROM's
 	 */
 	blk_size[HWIF(drive)->major] = HWIF(drive)->gd->sizes;
-	set_blocksize(MKDEV(HWIF(drive)->major, minor), CD_FRAMESIZE);
+	set_blocksize(mk_kdev(HWIF(drive)->major, minor), CD_FRAMESIZE);
 }
 
 static
diff -u --recursive --new-file v2.5.1/linux/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c
--- v2.5.1/linux/drivers/ide/ide-disk.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/ide-disk.c	Thu Jan  3 11:37:49 2002
@@ -30,7 +30,7 @@
  * Version 1.11		Highmem I/O support, Jens Axboe <axboe@suse.de>
  */
 
-#define IDEDISK_VERSION	"1.10"
+#define IDEDISK_VERSION	"1.11"
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
@@ -70,7 +70,7 @@
 	}
 }
 
-static inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
 {
 	ide_input_data(drive, buffer, wcount);
 	if (drive->bswap)
@@ -863,8 +863,10 @@
 		}
 		/* We must remove proc entries defined in this module.
 		   Otherwise we oops while accessing these entries */
+#ifdef CONFIG_PROC_FS
 		if (drive->proc)
 			ide_remove_proc_entries(drive->proc, idedisk_proc);
+#endif
 	}
 	ide_unregister_module(&idedisk_module);
 }
diff -u --recursive --new-file v2.5.1/linux/drivers/ide/ide-floppy.c linux/drivers/ide/ide-floppy.c
--- v2.5.1/linux/drivers/ide/ide-floppy.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/ide-floppy.c	Sun Dec 30 16:54:29 2001
@@ -336,23 +336,7 @@
 #define	IDEFLOPPY_IOCTL_FORMAT_START		0x4602
 #define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS	0x4603
 
-/*
- *	Special requests for our block device strategy routine.
- */
-#define	IDEFLOPPY_FIRST_RQ		90
-
-/*
- * 	IDEFLOPPY_PC_RQ is used to queue a packet command in the request queue.
- */
-#define	IDEFLOPPY_PC_RQ			90
-
-#define IDEFLOPPY_LAST_RQ		90
-
-/*
- *	A macro which can be used to check if a given request command
- *	originated in the driver or in the buffer cache layer.
- */
-#define IDEFLOPPY_RQ_CMD(cmd) 		((cmd >= IDEFLOPPY_FIRST_RQ) && (cmd <= IDEFLOPPY_LAST_RQ))
+#define IDEFLOPPY_RQ			(REQ_SPECIAL)
 
 /*
  *	Error codes which are returned in rq->errors to the higher part
@@ -696,7 +680,7 @@
 	/* Why does this happen? */
 	if (!rq)
 		return;
-	if (!IDEFLOPPY_RQ_CMD (rq->cmd)) {
+	if (rq->flags & IDEFLOPPY_RQ) {
 		ide_end_request (uptodate, hwgroup);
 		return;
 	}
@@ -776,7 +760,7 @@
 {
 	ide_init_drive_cmd (rq);
 	rq->buffer = (char *) pc;
-	rq->cmd = IDEFLOPPY_PC_RQ;
+	rq->flags = IDEFLOPPY_RQ;
 	(void) ide_do_drive_cmd (drive, rq, ide_preempt);
 }
 
@@ -1192,6 +1176,7 @@
 {
 	int block = sector / floppy->bs_factor;
 	int blocks = rq->nr_sectors / floppy->bs_factor;
+	int cmd = rq_data_dir(rq);
 	
 #if IDEFLOPPY_DEBUG_LOG
 	printk ("create_rw1%d_cmd: block == %d, blocks == %d\n",
@@ -1200,18 +1185,18 @@
 
 	idefloppy_init_pc (pc);
 	if (test_bit (IDEFLOPPY_USE_READ12, &floppy->flags)) {
-		pc->c[0] = rq->cmd == READ ? IDEFLOPPY_READ12_CMD : IDEFLOPPY_WRITE12_CMD;
+		pc->c[0] = cmd == READ ? IDEFLOPPY_READ12_CMD : IDEFLOPPY_WRITE12_CMD;
 		put_unaligned (htonl (blocks), (unsigned int *) &pc->c[6]);
 	} else {
-		pc->c[0] = rq->cmd == READ ? IDEFLOPPY_READ10_CMD : IDEFLOPPY_WRITE10_CMD;
+		pc->c[0] = cmd == READ ? IDEFLOPPY_READ10_CMD : IDEFLOPPY_WRITE10_CMD;
 		put_unaligned (htons (blocks), (unsigned short *) &pc->c[7]);
 	}
 	put_unaligned (htonl (block), (unsigned int *) &pc->c[2]);
 	pc->callback = &idefloppy_rw_callback;
 	pc->rq = rq;
 	pc->b_data = rq->buffer;
-	pc->b_count = rq->cmd == READ ? 0 : rq->bio->bi_size;
-	if (rq->cmd == WRITE)
+	pc->b_count = cmd == READ ? 0 : rq->bio->bi_size;
+	if (rq->flags & REQ_RW)
 		set_bit (PC_WRITING, &pc->flags);
 	pc->buffer = NULL;
 	pc->request_transfer = pc->buffer_size = blocks * floppy->block_size;
@@ -1227,8 +1212,8 @@
 	idefloppy_pc_t *pc;
 
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
-	printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+	printk (KERN_INFO "rq_status: %d, rq_dev: %u, flags: %lx, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->flags,rq->errors);
+	printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
 	if (rq->errors >= ERROR_MAX) {
@@ -1240,24 +1225,20 @@
 		idefloppy_end_request (0, HWGROUP(drive));
 		return ide_stopped;
 	}
-	switch (rq->cmd) {
-		case READ:
-		case WRITE:
-			if (rq->sector % floppy->bs_factor || rq->nr_sectors % floppy->bs_factor) {
-				printk ("%s: unsupported r/w request size\n", drive->name);
-				idefloppy_end_request (0, HWGROUP(drive));
-				return ide_stopped;
-			}
-			pc = idefloppy_next_pc_storage (drive);
-			idefloppy_create_rw_cmd (floppy, pc, rq, block);
-			break;
-		case IDEFLOPPY_PC_RQ:
-			pc = (idefloppy_pc_t *) rq->buffer;
-			break;
-		default:
-			printk (KERN_ERR "ide-floppy: unsupported command %x in request queue\n", rq->cmd);
-			idefloppy_end_request (0,HWGROUP (drive));
+	if (rq->flags & REQ_CMD) {
+		if (rq->sector % floppy->bs_factor || rq->nr_sectors % floppy->bs_factor) {
+			printk ("%s: unsupported r/w request size\n", drive->name);
+			idefloppy_end_request (0, HWGROUP(drive));
 			return ide_stopped;
+		}
+		pc = idefloppy_next_pc_storage (drive);
+		idefloppy_create_rw_cmd (floppy, pc, rq, block);
+	} else if (rq->flags & IDEFLOPPY_RQ) {
+		pc = (idefloppy_pc_t *) rq->buffer;
+	} else {
+		blk_dump_rq_flags(rq, "ide-floppy: unsupported command in queue");
+		idefloppy_end_request (0,HWGROUP (drive));
+		return ide_stopped;
 	}
 	pc->rq = rq;
 	return idefloppy_issue_pc (drive, pc);
@@ -1273,7 +1254,7 @@
 
 	ide_init_drive_cmd (&rq);
 	rq.buffer = (char *) pc;
-	rq.cmd = IDEFLOPPY_PC_RQ;
+	rq.flags = IDEFLOPPY_RQ;
 	return ide_do_drive_cmd (drive, &rq, ide_wait);
 }
 
@@ -2048,10 +2029,13 @@
 			printk ("%s: cleanup_module() called while still busy\n", drive->name);
 			failed++;
 		}
+
+#ifdef CONFIG_PROC_FS
 		/* We must remove proc entries defined in this module.
 		   Otherwise we oops while accessing these entries */
 		if (drive->proc)
 			ide_remove_proc_entries(drive->proc, idefloppy_proc);
+#endif
 	}
 	ide_unregister_module(&idefloppy_module);
 }
diff -u --recursive --new-file v2.5.1/linux/drivers/ide/ide-probe.c linux/drivers/ide/ide-probe.c
--- v2.5.1/linux/drivers/ide/ide-probe.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/ide-probe.c	Thu Jan  3 11:37:49 2002
@@ -595,17 +595,18 @@
 {
 	request_queue_t *q = &drive->queue;
 	int max_sectors;
+#ifdef CONFIG_BLK_DEV_PDC4030
+	int is_pdc4030_chipset = (HWIF(drive)->chipset == ide_pdc4030);
+#else
+	const int is_pdc4030_chipset = 0;
+#endif
 
 	q->queuedata = HWGROUP(drive);
 	blk_init_queue(q, do_ide_request, &ide_lock);
 	blk_queue_segment_boundary(q, 0xffff);
 
 	/* IDE can do up to 128K per request, pdc4030 needs smaller limit */
-#ifdef CONFIG_BLK_DEV_PDC4030
-	max_sectors = 127;
-#else
-	max_sectors = 255;
-#endif
+	max_sectors = (is_pdc4030_chipset ? 127 : 255);
 	blk_queue_max_sectors(q, max_sectors);
 
 	/* IDE DMA can do PRD_ENTRIES number of segments. */
@@ -796,9 +797,7 @@
 	gd->major	= hwif->major;		/* our major device number */
 	gd->major_name	= IDE_MAJOR_NAME;	/* treated special in genhd.c */
 	gd->minor_shift	= PARTN_BITS;		/* num bits for partitions */
-	gd->max_p	= 1<<PARTN_BITS;	/* 1 + max partitions / drive */
 	gd->nr_real	= units;		/* current num real drives */
-	gd->real_devices= hwif;			/* ptr to internal data */
 	gd->next	= NULL;			/* linked list of major devs */
 	gd->fops        = ide_fops;             /* file operations */
 	gd->de_arr	= kmalloc (sizeof *gd->de_arr * units, GFP_KERNEL);
diff -u --recursive --new-file v2.5.1/linux/drivers/ide/ide-timing.h linux/drivers/ide/ide-timing.h
--- v2.5.1/linux/drivers/ide/ide-timing.h	Sat Feb  3 11:27:43 2001
+++ linux/drivers/ide/ide-timing.h	Thu Dec 27 08:38:57 2001
@@ -2,11 +2,9 @@
 #define _IDE_TIMING_H
 
 /*
- * $Id: ide-timing.h,v 1.5 2001/01/15 21:48:56 vojtech Exp $
+ * $Id: ide-timing.h,v 1.6 2001/12/23 22:47:56 vojtech Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  */
 
 /*
@@ -25,16 +23,14 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/hdreg.h>
 
-#ifndef XFER_PIO_5
 #define XFER_PIO_5		0x0d
 #define XFER_UDMA_SLOW		0x4f
-#endif
 
 struct ide_timing {
 	short mode;
@@ -49,13 +45,15 @@
 };
 
 /*
- * PIO 0-5, MWDMA 0-2 and UDMA 0-5 timings (in nanoseconds).
+ * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
  * These were taken from ATA/ATAPI-6 standard, rev 0a, except
- * for PIO 5, which is a nonstandard extension.
+ * for PIO 5, which is a nonstandard extension and UDMA6, which
+ * is currently supported only by Maxtor drives. 
  */
 
 static struct ide_timing ide_timing[] = {
 
+	{ XFER_UDMA_6,     0,   0,   0,   0,   0,   0,   0,  15 },
 	{ XFER_UDMA_5,     0,   0,   0,   0,   0,   0,   0,  20 },
 	{ XFER_UDMA_4,     0,   0,   0,   0,   0,   0,   0,  30 },
 	{ XFER_UDMA_3,     0,   0,   0,   0,   0,   0,   0,  45 },
@@ -105,6 +103,7 @@
 #define EZ(v,unit)	((v)?ENOUGH(v,unit):0)
 
 #define XFER_MODE	0xf0
+#define XFER_UDMA_133	0x48
 #define XFER_UDMA_100	0x44
 #define XFER_UDMA_66	0x42
 #define XFER_UDMA	0x40
@@ -123,6 +122,9 @@
 
 	if ((map & XFER_UDMA) && (id->field_valid & 4)) {	/* Want UDMA and UDMA bitmap valid */
 
+		if ((map & XFER_UDMA_133) == XFER_UDMA_133)
+			if ((best = (id->dma_ultra & 0x0040) ? XFER_UDMA_6 : 0)) return best;
+
 		if ((map & XFER_UDMA_100) == XFER_UDMA_100)
 			if ((best = (id->dma_ultra & 0x0020) ? XFER_UDMA_5 : 0)) return best;
 
@@ -174,14 +176,14 @@
 
 static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q, int T, int UT)
 {
-	q->setup   = EZ(t->setup,   T);
-	q->act8b   = EZ(t->act8b,   T);
-	q->rec8b   = EZ(t->rec8b,   T);
-	q->cyc8b   = EZ(t->cyc8b,   T);
-	q->active  = EZ(t->active,  T);
-	q->recover = EZ(t->recover, T);
-	q->cycle   = EZ(t->cycle,   T);
-	q->udma    = EZ(t->udma,   UT);
+	q->setup   = EZ(t->setup   * 1000,  T);
+	q->act8b   = EZ(t->act8b   * 1000,  T);
+	q->rec8b   = EZ(t->rec8b   * 1000,  T);
+	q->cyc8b   = EZ(t->cyc8b   * 1000,  T);
+	q->active  = EZ(t->active  * 1000,  T);
+	q->recover = EZ(t->recover * 1000,  T);
+	q->cycle   = EZ(t->cycle   * 1000,  T);
+	q->udma    = EZ(t->udma    * 1000, UT);
 }
 
 static void ide_timing_merge(struct ide_timing *a, struct ide_timing *b, struct ide_timing *m, unsigned int what)
diff -u --recursive --new-file v2.5.1/linux/drivers/ide/ide.c linux/drivers/ide/ide.c
--- v2.5.1/linux/drivers/ide/ide.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/ide.c	Thu Jan  3 11:34:10 2002
@@ -580,7 +580,7 @@
 	}
 
 	if (!end_that_request_first(rq, uptodate, nr_secs)) {
-		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		add_blkdev_randomness(major(rq->rq_dev));
 		blkdev_dequeue_request(rq);
         	hwgroup->rq = NULL;
 		end_that_request_last(rq);
@@ -653,7 +653,7 @@
 			continue;
 		if (drive->media!=ide_disk && drive->media!=ide_floppy)
 			continue;
-		register_disk(gd,MKDEV(hwif->major,unit<<PARTN_BITS),
+		register_disk(gd,mk_kdev(hwif->major,unit<<PARTN_BITS),
 #ifdef CONFIG_BLK_DEV_ISAPNP
 			(drive->forced_geom && drive->noprobe) ? 1 :
 #endif /* CONFIG_BLK_DEV_ISAPNP */
@@ -1223,7 +1223,7 @@
 {
 	ide_startstop_t startstop;
 	unsigned long block;
-	unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS;
+	unsigned int minor = minor(rq->rq_dev), unit = minor >> PARTN_BITS;
 	ide_hwif_t *hwif = HWIF(drive);
 
 	BUG_ON(!(rq->flags & REQ_STARTED));
@@ -1241,12 +1241,6 @@
 		printk("%s: bad device number: %s\n", hwif->name, kdevname(rq->rq_dev));
 		goto kill_rq;
 	}
-#ifdef DEBUG
-	if (rq->bh && !buffer_locked(rq->bh)) {
-		printk("%s: block not locked\n", drive->name);
-		goto kill_rq;
-	}
-#endif
 	block    = rq->sector;
 
 	/* Strange disk manager remap */
@@ -1478,7 +1472,7 @@
  */
 request_queue_t *ide_get_queue (kdev_t dev)
 {
-	ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[MAJOR(dev)].data;
+	ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[major(dev)].data;
 
 	return &hwif->drives[DEVICE_NR(dev) & 1].queue;
 }
@@ -1784,7 +1778,7 @@
  */
 ide_drive_t *get_info_ptr (kdev_t i_rdev)
 {
-	int		major = MAJOR(i_rdev);
+	int		major = major(i_rdev);
 	unsigned int	h;
 
 	for (h = 0; h < MAX_HWIFS; ++h) {
@@ -1851,7 +1845,7 @@
 #endif
 	rq->errors = 0;
 	rq->rq_status = RQ_ACTIVE;
-	rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);
+	rq->rq_dev = mk_kdev(major,(drive->select.b.unit)<<PARTN_BITS);
 	if (action == ide_wait)
 		rq->waiting = &wait;
 	spin_lock_irqsave(&ide_lock, flags);
@@ -1880,7 +1874,7 @@
 {
         struct gendisk *g = HWIF(drive)->gd;
         int minor = (drive->select.b.unit << g->minor_shift);
-        kdev_t dev = MKDEV(g->major, minor);
+        kdev_t dev = mk_kdev(g->major, minor);
 
         grok_partitions(dev, current_capacity(drive));
 }
@@ -1939,7 +1933,7 @@
 			if (drive->revalidate) {
 				drive->revalidate = 0;
 				if (!initializing)
-					(void) ide_revalidate_disk(MKDEV(hwif->major, unit<<PARTN_BITS));
+					(void) ide_revalidate_disk(mk_kdev(hwif->major, unit<<PARTN_BITS));
 			}
 		}
 	}
@@ -2119,7 +2113,7 @@
 		minor = drive->select.b.unit << PARTN_BITS;
 		for (p = 0; p < (1<<PARTN_BITS); ++p) {
 			if (drive->part[p].nr_sects > 0) {
-				kdev_t devp = MKDEV(hwif->major, minor+p);
+				kdev_t devp = mk_kdev(hwif->major, minor+p);
 				invalidate_device(devp, 0);
 			}
 		}
@@ -2624,9 +2618,8 @@
 	kdev_t dev;
 	ide_settings_t *setting;
 
-	if (!inode || !(dev = inode->i_rdev))
-		return -EINVAL;
-	major = MAJOR(dev); minor = MINOR(dev);
+	dev = inode->i_rdev;
+	major = major(dev); minor = minor(dev);
 	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
 		return -ENODEV;
 
@@ -2635,7 +2628,7 @@
 			err = ide_read_setting(drive, setting);
 			return err >= 0 ? put_user(err, (long *) arg) : err;
 		} else {
-			if ((MINOR(inode->i_rdev) & PARTN_MASK))
+			if ((minor(inode->i_rdev) & PARTN_MASK))
 				return -EINVAL;
 			return ide_write_setting(drive, setting, arg);
 		}
@@ -2651,7 +2644,7 @@
 			if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
 			if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
 			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
+			if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
 			return 0;
 		}
@@ -2664,7 +2657,7 @@
 			if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
 			if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
 			if (put_user(drive->bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
+			if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
 			return 0;
 		}
@@ -2676,7 +2669,7 @@
 			if (put_user(drive->head, (byte *) &loc->heads)) return -EFAULT;
 			if (put_user(drive->sect, (byte *) &loc->sectors)) return -EFAULT;
 			if (put_user(drive->cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
+			if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
 			return 0;
 		}
@@ -2687,7 +2680,7 @@
 
 		case HDIO_OBSOLETE_IDENTITY:
 		case HDIO_GET_IDENTITY:
-			if (MINOR(inode->i_rdev) & PARTN_MASK)
+			if (minor(inode->i_rdev) & PARTN_MASK)
 				return -EINVAL;
 			if (drive->id == NULL)
 				return -ENOMSG;
diff -u --recursive --new-file v2.5.1/linux/drivers/ide/pdc4030.c linux/drivers/ide/pdc4030.c
--- v2.5.1/linux/drivers/ide/pdc4030.c	Tue Jul 17 18:53:55 2001
+++ linux/drivers/ide/pdc4030.c	Thu Jan  3 11:37:49 2002
@@ -66,8 +66,10 @@
  * some technical information which has shed a glimmer of light on some of the
  * problems I was having, especially with writes. 
  *
- * There are still problems with the robustness and efficiency of this driver
- * because I still don't understand what the card is doing with interrupts.
+ * There are still potential problems with the robustness and efficiency of
+ * this driver because I still don't understand what the card is doing with
+ * interrupts, however, it has been stable for a while with no reports of ill
+ * effects.
  */
 
 #define DEBUG_READ
@@ -308,7 +310,9 @@
 	byte stat;
 	int total_remaining;
 	unsigned int sectors_left, sectors_avail, nsect;
+	unsigned long flags;
 	struct request *rq;
+	char *to;
 
 	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
 		return ide_error(drive, "promise_read_intr", stat);
@@ -330,15 +334,15 @@
 	if (nsect > sectors_avail)
 		nsect = sectors_avail;
 	sectors_avail -= nsect;
-	ide_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
+	to = ide_map_buffer(rq, &flags);
+	idedisk_input_data(drive, to, nsect * SECTOR_WORDS);
 #ifdef DEBUG_READ
 	printk(KERN_DEBUG "%s:  promise_read: sectors(%ld-%ld), "
 	       "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector,
-	       rq->sector+nsect-1, (unsigned long) rq->buffer,
-	       rq->nr_sectors-nsect);
+	       rq->sector+nsect-1, (unsigned long) to, rq->nr_sectors-nsect);
 #endif
+	ide_unmap_buffer(to, &flags);
 	rq->sector += nsect;
-	rq->buffer += nsect<<9;
 	rq->errors = 0;
 	rq->nr_sectors -= nsect;
 	total_remaining = rq->nr_sectors;
@@ -406,10 +410,7 @@
 #ifdef DEBUG_WRITE
 	printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);
 #endif
-	for (i = rq->nr_sectors; i > 0; ) {
-		i -= rq->current_nr_sectors;
-		ide_end_request(1, hwgroup);
-	}
+	__ide_end_request(hwgroup, 1, rq->nr_sectors);
 	return ide_stopped;
 }
 
@@ -498,7 +499,15 @@
 	unsigned long timeout;
 	byte stat;
 
-	if (rq->cmd == READ) {
+/* Check that it's a regular command. If not, bomb out early. */
+	if (!(rq->flags & REQ_CMD)) {
+		blk_dump_rq_flags(rq, "pdc4030 bad flags");
+		ide_end_request(0, HWGROUP(drive));
+		return ide_stopped;
+	}
+
+	switch (rq_data_dir(rq)) {
+	case READ:
 		OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG);
 /*
  * The card's behaviour is odd at this point. If the data is
@@ -531,9 +540,18 @@
 		printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n",
 			drive->name);
 		return ide_stopped;
-	} else if (rq->cmd == WRITE) {
+		break;
+
+	case WRITE:
 		ide_startstop_t startstop;
 		OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
+/*
+ * Strategy on write is:
+ *	look for the DRQ that should have been immediately asserted
+ *	copy the request into the hwgroup's scratchpad
+ *	call the promise_write function to deal with writing the data out
+ * NOTE: No interrupts are generated on writes. Write completion must be polled
+ */
 		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
 			printk(KERN_ERR "%s: no DRQ after issuing "
 			       "PROMISE_WRITE\n", drive->name);
@@ -543,11 +561,11 @@
 			__cli();	/* local CPU only */
 		HWGROUP(drive)->wrq = *rq; /* scratchpad */
 		return promise_write(drive);
+		break;
 
-	} else {
-		printk("KERN_WARNING %s: bad command: %d\n",
-		       drive->name, rq->cmd);
+	default:
+		printk(KERN_ERR "pdc4030: command not READ or WRITE! Huh?\n");
 		ide_end_request(0, HWGROUP(drive));
-		return ide_stopped;
+		break;
 	}
 }
diff -u --recursive --new-file v2.5.1/linux/drivers/ide/pdcraid.c linux/drivers/ide/pdcraid.c
--- v2.5.1/linux/drivers/ide/pdcraid.c	Tue Nov 13 09:19:41 2001
+++ linux/drivers/ide/pdcraid.c	Thu Dec 27 08:17:43 2001
@@ -387,18 +387,14 @@
 
 #include "pdcraid.h"
 
-static unsigned long calc_pdcblock_offset (int major,int minor)
+static unsigned long calc_pdcblock_offset(struct block_device *bdev)
 {
 	unsigned long lba = 0;
-	kdev_t dev;
-	ide_drive_t *ideinfo;
-	
-	dev = MKDEV(major,minor);
-	ideinfo = get_info_ptr (dev);
+	ide_drive_t *ideinfo = get_info_ptr(to_kdev_t(bdev->bd_dev));
+
 	if (ideinfo==NULL)
 		return 0;
-	
-	
+
 	/* first sector of the last cluster */
 	if (ideinfo->head==0) 
 		return 0;
@@ -412,42 +408,32 @@
 }
 
 
-static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
+static int read_disk_sb(struct block_device *bdev, struct promise_raid_conf *p)
 {
-	int ret = -EINVAL;
-	struct buffer_head *bh = NULL;
-	kdev_t dev = MKDEV(major,minor);
 	unsigned long sb_offset;
+	char *buffer;
+	int i;
 
-	if (blksize_size[major]==NULL)   /* device doesn't exist */
-		return -EINVAL;
-                       
-	
 	/*
 	 * Calculate the position of the superblock,
 	 * it's at first sector of the last cylinder
 	 */
-	sb_offset = calc_pdcblock_offset(major,minor)/8;
-	/* The /8 transforms sectors into 4Kb blocks */
+	sb_offset = calc_pdcblock_offset(bdev);
 
 	if (sb_offset==0)
 		return -1;	
-	
-	set_blocksize (dev, 4096);
 
-	bh = bread (dev, sb_offset, 4096);
-	
-	if (bh) {
-		memcpy (buffer, bh->b_data, bufsize);
-	} else {
-		printk(KERN_ERR "pdcraid: Error reading superblock.\n");
-		goto abort;
+	for (i = 0, buffer = (char*)p; i < 4; i++, buffer += 512) {
+		Sector sect;
+		char *q = read_dev_sector(bdev, sb_offset + i, &sect);
+		if (!p) {
+			printk(KERN_ERR "pdcraid: Error reading superblock.\n");
+			return -1;
+		}
+		memcpy(buffer, q, 512);
+		put_dev_sector(&sect);
 	}
-	ret = 0;
-abort:
-	if (bh)
-		brelse (bh);
-	return ret;
+	return 0;
 }
 
 static unsigned int calc_sb_csum (unsigned int* ptr)
@@ -464,12 +450,11 @@
 
 static int cookie = 0;
 
+static struct promise_raid_conf __initdata prom;
 static void __init probedisk(int devindex,int device, int raidlevel)
 {
 	int i;
 	int major, minor;
-        struct promise_raid_conf *prom;
-	static unsigned char block[4096];
 	struct block_device *bdev;
 
 	if (devlist[devindex].device!=-1) /* already assigned to another array */
@@ -478,44 +463,48 @@
 	major = devlist[devindex].major;
 	minor = devlist[devindex].minor; 
 
-        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
-        	return;
-                                                                                                                 
-        prom = (struct promise_raid_conf*)&block[512];
-
-        /* the checksums must match */
-	if (prom->checksum != calc_sb_csum((unsigned int*)prom))
-		return;
-	if (prom->raid.type!=raidlevel) /* different raidlevel */
+	bdev = bdget(MKDEV(major,minor));
+	if (!bdev)
 		return;
 
-	if ((cookie!=0) && (cookie != prom->raid.magic_1)) /* different array */
+	if (blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW) != 0)
 		return;
+
+        if (read_disk_sb(bdev, &prom))
+        	goto out;
+
+        /* the checksums must match */
+	if (prom.checksum != calc_sb_csum((unsigned int*)&prom))
+		goto out;
+	if (prom.raid.type!=raidlevel) /* different raidlevel */
+		goto out;
+
+	if ((cookie!=0) && (cookie != prom.raid.magic_1)) /* different array */
+		goto out;
 	
-	cookie = prom->raid.magic_1;
+	cookie = prom.raid.magic_1;
 
 	/* This looks evil. But basically, we have to search for our adapternumber
 	   in the arraydefinition, both of which are in the superblock */	
-        for (i=0;(i<prom->raid.total_disks)&&(i<8);i++) {
-        	if ( (prom->raid.disk[i].channel== prom->raid.channel) &&
-        	     (prom->raid.disk[i].device == prom->raid.device) ) {
-
-        	        bdev = bdget(MKDEV(major,minor));
-        	        if (bdev && blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW) == 0) {
-				raid[device].disk[i].bdev = bdev;
-			}
+        for (i=0;(i<prom.raid.total_disks)&&(i<8);i++) {
+        	if ( (prom.raid.disk[i].channel== prom.raid.channel) &&
+        	     (prom.raid.disk[i].device == prom.raid.device) ) {
+
+			raid[device].disk[i].bdev = bdev;
 			raid[device].disk[i].device = MKDEV(major,minor);
-			raid[device].disk[i].sectors = prom->raid.disk_secs;
-			raid[device].stride = (1<<prom->raid.raid0_shift);
-			raid[device].disks = prom->raid.total_disks;
-			raid[device].sectors = prom->raid.total_secs;
-			raid[device].geom.heads = prom->raid.heads+1;
-			raid[device].geom.sectors = prom->raid.sectors;
-			raid[device].geom.cylinders = prom->raid.cylinders+1;
+			raid[device].disk[i].sectors = prom.raid.disk_secs;
+			raid[device].stride = (1<<prom.raid.raid0_shift);
+			raid[device].disks = prom.raid.total_disks;
+			raid[device].sectors = prom.raid.total_secs;
+			raid[device].geom.heads = prom.raid.heads+1;
+			raid[device].geom.sectors = prom.raid.sectors;
+			raid[device].geom.cylinders = prom.raid.cylinders+1;
 			devlist[devindex].device=device;
-        	     }
+			return;
+		}
         }
-	               
+out:
+	blkdev_put(bdev, BDEV_RAW);
 }
 
 static void __init fill_cutoff(int device)
diff -u --recursive --new-file v2.5.1/linux/drivers/ide/via82cxxx.c linux/drivers/ide/via82cxxx.c
--- v2.5.1/linux/drivers/ide/via82cxxx.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/via82cxxx.c	Thu Dec 27 08:38:57 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: via82cxxx.c,v 3.29 2001/09/10 10:06:00 vojtech Exp $
+ * $Id: via82cxxx.c,v 3.33 2001/12/23 22:46:12 vojtech Exp $
  *
  *  Copyright (c) 2000-2001 Vojtech Pavlik
  *
@@ -7,23 +7,21 @@
  *	Michel Aubry
  *	Jeff Garzik
  *	Andre Hedrick
- *
- *  Sponsored by SuSE
  */
 
 /*
  * VIA IDE driver for Linux. Supports
  *
  *   vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
- *   vt82c686, vt82c686a, vt82c686b, vt8231, vt8233
+ *   vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a
  *
  * southbridges, which can be found in
  *
  *  VIA Apollo Master, VP, VP2, VP2/97, VP3, VPX, VPX/97, MVP3, MVP4, P6, Pro,
  *    ProII, ProPlus, Pro133, Pro133+, Pro133A, Pro133A Dual, Pro133T, Pro133Z,
  *    PLE133, PLE133T, Pro266, Pro266T, ProP4X266, PM601, PM133, PN133, PL133T,
- *    PX266, PM266, KX133, KT133, KT133A, KLE133, KT266, KX266, KM133, KM133A,
- *    KL133, KN133, KM266
+ *    PX266, PM266, KX133, KT133, KT133A, KT133E, KLE133, KT266, KX266, KM133,
+ *    KM133A, KL133, KN133, KM266
  *  PC-Chips VXPro, VXPro+, VXTwo, TXPro-III, TXPro-AGP, AGPPro, ViaGra, BXToo,
  *    BXTel, BXpert
  *  AMD 640, 640 AGP, 750 IronGate, 760, 760MP
@@ -32,9 +30,9 @@
  *
  * chipsets. Supports
  *
- *   PIO 0-5, MWDMA 0-2, SWDMA 0-2 and UDMA 0-5
+ *   PIO 0-5, MWDMA 0-2, SWDMA 0-2 and UDMA 0-6
  *
- * (this includes UDMA33, 66 and 100) modes. UDMA66 and higher modes are
+ * (this includes UDMA33, 66, 100 and 133) modes. UDMA66 and higher modes are
  * autoenabled only in case the BIOS has detected a 80 wire cable. To ignore
  * the BIOS data and assume the cable is present, use 'ide0=ata66' or
  * 'ide1=ata66' on the kernel command line.
@@ -56,8 +54,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/config.h>
@@ -87,10 +85,12 @@
 #define VIA_UDMA_33		0x001
 #define VIA_UDMA_66		0x002
 #define VIA_UDMA_100		0x003
+#define VIA_UDMA_133		0x004
 #define VIA_BAD_PREQ		0x010	/* Crashes if PREQ# till DDACK# set */
 #define VIA_BAD_CLK66		0x020	/* 66 MHz clock doesn't work correctly */
 #define VIA_SET_FIFO		0x040	/* Needs to have FIFO split set */
 #define VIA_NO_UNMASK		0x080	/* Doesn't work with IRQ unmasking on */
+#define VIA_BAD_ID		0x100	/* Has wrong vendor ID (0x1107) */
 
 /*
  * VIA SouthBridge chips.
@@ -104,10 +104,11 @@
 	unsigned short flags;
 } via_isa_bridges[] = {
 #ifdef FUTURE_BRIDGES
-	{ "vt8237",	PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_100 },
-	{ "vt8235",	PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_100 },
-	{ "vt8233c",	PCI_DEVICE_ID_VIA_8233C,    0x00, 0x2f, VIA_UDMA_100 },
+	{ "vt8237",	PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_133 },
+	{ "vt8235",	PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_133 },
 #endif
+	{ "vt8233a",	PCI_DEVICE_ID_VIA_8233A,    0x00, 0x2f, VIA_UDMA_133 },
+	{ "vt8233c",	PCI_DEVICE_ID_VIA_8233C_0,  0x00, 0x2f, VIA_UDMA_100 },
 	{ "vt8233",	PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, VIA_UDMA_100 },
 	{ "vt8231",	PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, VIA_UDMA_100 },
 	{ "vt82c686b",	PCI_DEVICE_ID_VIA_82C686,   0x40, 0x4f, VIA_UDMA_100 },
@@ -121,6 +122,7 @@
 	{ "vt82c586a",	PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
 	{ "vt82c586",	PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
 	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
+	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
 	{ NULL }
 };
 
@@ -128,7 +130,7 @@
 static unsigned char via_enabled;
 static unsigned int via_80w;
 static unsigned int via_clock;
-static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100" };
+static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
 
 /*
  * VIA /proc entry.
@@ -151,7 +153,7 @@
 
 static int via_get_info(char *buffer, char **addr, off_t offset, int count)
 {
-	short speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
+	int speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
 		 uen[4], udma[4], umul[4], active8b[4], recover8b[4];
 	struct pci_dev *dev = bmide_dev;
 	unsigned int v, u, i;
@@ -161,7 +163,7 @@
 
 	via_print("----------VIA BusMastering IDE Configuration----------------");
 
-	via_print("Driver Version:                     3.29");
+	via_print("Driver Version:                     3.33");
 	via_print("South Bridge:                       VIA %s", via_config->name);
 
 	pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t);
@@ -170,7 +172,7 @@
 	via_print("Highest DMA rate:                   %s", via_dma[via_config->flags & VIA_UDMA]);
 
 	via_print("BM-DMA base:                        %#x", via_base);
-	via_print("PCI clock:                          %dMHz", via_clock);
+	via_print("PCI clock:                          %d.%dMHz", via_clock / 1000, via_clock / 100 % 10);
 
 	pci_read_config_byte(dev, VIA_MISC_1, &t);
 	via_print("Master Read  Cycle IRDY:            %dws", (t & 64) >> 6);
@@ -218,40 +220,45 @@
 		uen[i]       = ((u >> ((3 - i) << 3)) & 0x20);
 		den[i]       = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2));
 
-		speed[i] = 20 * via_clock / (active[i] + recover[i]);
-		cycle[i] = 1000 / via_clock * (active[i] + recover[i]);
+		speed[i] = 2 * via_clock / (active[i] + recover[i]);
+		cycle[i] = 1000000 * (active[i] + recover[i]) / via_clock;
 
 		if (!uen[i] || !den[i])
 			continue;
 
 		switch (via_config->flags & VIA_UDMA) {
-			
-			case VIA_UDMA_100:
-				speed[i] = 60 * via_clock / udma[i];
-				cycle[i] = 333 / via_clock * udma[i];
+
+			case VIA_UDMA_33:
+				speed[i] = 2 * via_clock / udma[i];
+				cycle[i] = 1000000 * udma[i] / via_clock;
 				break;
 
 			case VIA_UDMA_66:
-				speed[i] = 40 * via_clock / (udma[i] * umul[i]);
-				cycle[i] = 500 / via_clock * (udma[i] * umul[i]);
+				speed[i] = 4 * via_clock / (udma[i] * umul[i]);
+				cycle[i] = 500000 * (udma[i] * umul[i]) / via_clock;
 				break;
 
-			case VIA_UDMA_33:
-				speed[i] = 20 * via_clock / udma[i];
-				cycle[i] = 1000 / via_clock * udma[i];
+			case VIA_UDMA_100:
+				speed[i] = 6 * via_clock / udma[i];
+				cycle[i] = 333333 * udma[i] / via_clock;
+				break;
+
+			case VIA_UDMA_133:
+				speed[i] = 8 * via_clock / udma[i];
+				cycle[i] = 250000 * udma[i] / via_clock;
 				break;
 		}
 	}
 
 	via_print_drive("Transfer Mode: ", "%10s", den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO");
 
-	via_print_drive("Address Setup: ", "%8dns", (1000 / via_clock) * setup[i]);
-	via_print_drive("Cmd Active:    ", "%8dns", (1000 / via_clock) * active8b[i]);
-	via_print_drive("Cmd Recovery:  ", "%8dns", (1000 / via_clock) * recover8b[i]);
-	via_print_drive("Data Active:   ", "%8dns", (1000 / via_clock) * active[i]);
-	via_print_drive("Data Recovery: ", "%8dns", (1000 / via_clock) * recover[i]);
+	via_print_drive("Address Setup: ", "%8dns", 1000000 * setup[i] / via_clock);
+	via_print_drive("Cmd Active:    ", "%8dns", 1000000 * active8b[i] / via_clock);
+	via_print_drive("Cmd Recovery:  ", "%8dns", 1000000 * recover8b[i] / via_clock);
+	via_print_drive("Data Active:   ", "%8dns", 1000000 * active[i] / via_clock);
+	via_print_drive("Data Recovery: ", "%8dns", 1000000 * recover[i] / via_clock);
 	via_print_drive("Cycle Time:    ", "%8dns", cycle[i]);
-	via_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 10, speed[i] % 10);
+	via_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 1000, speed[i] / 100 % 10);
 
 	return p - buffer;	/* hoping it is less than 4K... */
 }
@@ -280,6 +287,7 @@
 		case VIA_UDMA_33:  t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
 		case VIA_UDMA_66:  t = timing->udma ? (0xe8 | (FIT(timing->udma, 2, 9) - 2)) : 0x0f; break;
 		case VIA_UDMA_100: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
+		case VIA_UDMA_133: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
 		default: return;
 	}
 
@@ -296,20 +304,21 @@
 {
 	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
 	struct ide_timing t, p;
-	int T, UT;
+	unsigned int T, UT;
 
 	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
 		if (ide_config_drive_speed(drive, speed))
 			printk(KERN_WARNING "ide%d: Drive %d didn't accept speed setting. Oh, well.\n",
 				drive->dn >> 1, drive->dn & 1);
 
-	T = 1000 / via_clock;
+	T = 1000000000 / via_clock;
 
 	switch (via_config->flags & VIA_UDMA) {
 		case VIA_UDMA_33:   UT = T;   break;
 		case VIA_UDMA_66:   UT = T/2; break;
 		case VIA_UDMA_100:  UT = T/3; break;
-		default:	    UT = T;   break;
+		case VIA_UDMA_133:  UT = T/4; break;
+		default: UT = T;
 	}
 
 	ide_timing_compute(drive, speed, &t, T, UT);
@@ -365,7 +374,8 @@
 			XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
 			(via_config->flags & VIA_UDMA ? XFER_UDMA : 0) |
 			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) |
-			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0));
+			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) |
+			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0));
 
 		via_set_drive(drive, speed);
 
@@ -395,14 +405,16 @@
  */
 
 	for (via_config = via_isa_bridges; via_config->id; via_config++)
-		if ((isa = pci_find_device(PCI_VENDOR_ID_VIA, via_config->id, NULL))) {
+		if ((isa = pci_find_device(PCI_VENDOR_ID_VIA +
+			!!(via_config->flags & VIA_BAD_ID), via_config->id, NULL))) {
+
 			pci_read_config_byte(isa, PCI_REVISION_ID, &t);
 			if (t >= via_config->rev_min && t <= via_config->rev_max)
 				break;
 		}
 
 	if (!via_config->id) {
-		printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, contact Vojtech Pavlik <vojtech@suse.cz>\n");
+		printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, contact Vojtech Pavlik <vojtech@ucw.cz>\n");
 		return -ENODEV;
 	}
 
@@ -412,22 +424,28 @@
 
 	switch (via_config->flags & VIA_UDMA) {
 
-		case VIA_UDMA_100:
-
-			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
-			for (i = 24; i >= 0; i -= 8)
-				if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 3)))
-					via_80w |= (1 << (1 - (i >> 4)));	/* BIOS 80-wire bit or UDMA w/ < 50ns/cycle */
-			break;
-
 		case VIA_UDMA_66:
-
 			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);	/* Enable Clk66 */
 			pci_write_config_dword(dev, VIA_UDMA_TIMING, u | 0x80008);
 			for (i = 24; i >= 0; i -= 8)
 				if (((u >> (i & 16)) & 8) && ((u >> i) & 0x20) && (((u >> i) & 7) < 2))
 					via_80w |= (1 << (1 - (i >> 4)));	/* 2x PCI clock and UDMA w/ < 3T/cycle */
 			break;
+
+		case VIA_UDMA_100:
+			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+			for (i = 24; i >= 0; i -= 8)
+				if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 4)))
+					via_80w |= (1 << (1 - (i >> 4)));	/* BIOS 80-wire bit or UDMA w/ < 60ns/cycle */
+			break;
+
+		case VIA_UDMA_133:
+			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+			for (i = 24; i >= 0; i -= 8)
+				if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 8)))
+					via_80w |= (1 << (1 - (i >> 4)));	/* BIOS 80-wire bit or UDMA w/ < 60ns/cycle */
+			break;
+
 	}
 
 	if (via_config->flags & VIA_BAD_CLK66) {			/* Disable Clk66 */
@@ -466,10 +484,17 @@
  * Determine system bus clock.
  */
 
-	via_clock = system_bus_clock();
-	if (via_clock < 20 || via_clock > 50) {
+	via_clock = system_bus_clock() * 1000;
+
+	switch (via_clock) {
+		case 33000: via_clock = 33333; break;
+		case 37000: via_clock = 37500; break;
+		case 41000: via_clock = 41666; break;
+	}
+
+	if (via_clock < 20000 || via_clock > 50000) {
 		printk(KERN_WARNING "VP_IDE: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", via_clock);
-		printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want to force UDMA66/UDMA100.\n");
+		printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want to assume 80-wire cable.\n");
 		via_clock = 33;
 	}
 
diff -u --recursive --new-file v2.5.1/linux/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c
--- v2.5.1/linux/drivers/ieee1394/ohci1394.c	Mon Oct  1 21:24:24 2001
+++ linux/drivers/ieee1394/ohci1394.c	Sun Dec 30 10:31:51 2001
@@ -99,7 +99,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <linux/types.h>
 #include <linux/wrapper.h>
 #include <linux/vmalloc.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/ieee1394/video1394.c linux/drivers/ieee1394/video1394.c
--- v2.5.1/linux/drivers/ieee1394/video1394.c	Mon Oct  1 21:24:25 2001
+++ linux/drivers/ieee1394/video1394.c	Sun Dec 30 10:31:51 2001
@@ -43,7 +43,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <linux/types.h>
 #include <linux/wrapper.h>
 #include <linux/vmalloc.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/input/evdev.c linux/drivers/input/evdev.c
--- v2.5.1/linux/drivers/input/evdev.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/input/evdev.c	Thu Jan  3 12:20:10 2002
@@ -119,7 +119,7 @@
 static int evdev_open(struct inode * inode, struct file * file)
 {
 	struct evdev_list *list;
-	int i = MINOR(inode->i_rdev) - EVDEV_MINOR_BASE;
+	int i = minor(inode->i_rdev) - EVDEV_MINOR_BASE;
 
 	if (i >= EVDEV_MINORS || !evdev_table[i])
 		return -ENODEV;
diff -u --recursive --new-file v2.5.1/linux/drivers/input/input.c linux/drivers/input/input.c
--- v2.5.1/linux/drivers/input/input.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/input/input.c	Thu Jan  3 12:20:10 2002
@@ -368,7 +368,7 @@
 
 static int input_open_file(struct inode *inode, struct file *file)
 {
-	struct input_handler *handler = input_table[MINOR(inode->i_rdev) >> 5];
+	struct input_handler *handler = input_table[minor(inode->i_rdev) >> 5];
 	struct file_operations *old_fops, *new_fops = NULL;
 	int err;
 
diff -u --recursive --new-file v2.5.1/linux/drivers/input/joydev.c linux/drivers/input/joydev.c
--- v2.5.1/linux/drivers/input/joydev.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/input/joydev.c	Thu Jan  3 12:20:10 2002
@@ -31,7 +31,6 @@
 
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/segment.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/joystick.h>
@@ -190,7 +189,7 @@
 static int joydev_open(struct inode *inode, struct file *file)
 {
 	struct joydev_list *list;
-	int i = MINOR(inode->i_rdev) - JOYDEV_MINOR_BASE;
+	int i = minor(inode->i_rdev) - JOYDEV_MINOR_BASE;
 
 	if (i >= JOYDEV_MINORS || !joydev_table[i])
 		return -ENODEV;
diff -u --recursive --new-file v2.5.1/linux/drivers/input/mousedev.c linux/drivers/input/mousedev.c
--- v2.5.1/linux/drivers/input/mousedev.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/input/mousedev.c	Thu Jan  3 12:20:10 2002
@@ -214,7 +214,7 @@
 static int mousedev_open(struct inode * inode, struct file * file)
 {
 	struct mousedev_list *list;
-	int i = MINOR(inode->i_rdev) - MOUSEDEV_MINOR_BASE;
+	int i = minor(inode->i_rdev) - MOUSEDEV_MINOR_BASE;
 
 	if (i >= MOUSEDEV_MINORS || !mousedev_table[i])
 		return -ENODEV;
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/Config.in linux/drivers/isdn/Config.in
--- v2.5.1/linux/drivers/isdn/Config.in	Tue Dec 18 14:56:36 2001
+++ linux/drivers/isdn/Config.in	Tue Jan  1 19:00:01 2002
@@ -42,6 +42,7 @@
    fi
    bool '  HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
    bool '  HiSax Support for US NI1' CONFIG_HISAX_NI1
+   int  '  Maximum number of cards supported by HiSax' CONFIG_HISAX_MAX_CARDS 8
    comment '  HiSax supported cards'
    bool '  Teles 16.0/8.0' CONFIG_HISAX_16_0
    bool '  Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
@@ -81,7 +82,7 @@
    dep_tristate 'Sedlbauer PCMCIA cards' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_PCMCIA
    dep_tristate 'ELSA PCMCIA MicroLink cards' CONFIG_HISAX_ELSA_CS $CONFIG_PCMCIA
    dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)' CONFIG_HISAX_ST5481 $CONFIG_HISAX $CONFIG_USB $CONFIG_EXPERIMENTAL
-   dep_tristate 'Fritz!PCIv2 support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_HISAX $CONFIG_EXPERIMENTAL
+   dep_tristate 'AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_HISAX $CONFIG_EXPERIMENTAL
 fi
 endmenu
 
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/act2000/act2000.h linux/drivers/isdn/act2000/act2000.h
--- v2.5.1/linux/drivers/isdn/act2000/act2000.h	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/act2000/act2000.h	Sun Dec 30 10:31:51 2001
@@ -68,7 +68,6 @@
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/major.h>
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/avmb1/avmcard.h linux/drivers/isdn/avmb1/avmcard.h
--- v2.5.1/linux/drivers/isdn/avmb1/avmcard.h	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/avmb1/avmcard.h	Tue Jan  1 19:00:01 2002
@@ -1,4 +1,4 @@
-/* $Id: avmcard.h,v 1.8.6.4 2001/09/23 22:24:33 kai Exp $
+/* $Id: avmcard.h,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
  *
  * Copyright 1999 by Carsten Paeth <calle@calle.de>
  *
@@ -39,13 +39,21 @@
 	avm_c2
 };
 
+typedef struct avmcard_dmabuf {
+    long        size;
+    __u8       *dmabuf;
+    dma_addr_t  dmaaddr;
+} avmcard_dmabuf;
+
 typedef struct avmcard_dmainfo {
-	__u32 recvlen;   
-	__u8  recvbuf[128+2048];
-	struct sk_buff_head send_queue;
-	__u8  sendbuf[128+2048];
-} avmcard_dmainfo;
+	__u32                recvlen;
+        avmcard_dmabuf       recvbuf;
+
+        avmcard_dmabuf       sendbuf;
+	struct sk_buff_head  send_queue;
 
+	struct pci_dev      *pcidev;
+} avmcard_dmainfo;
 
 typedef struct avmcard {
 	char name[32];
@@ -543,6 +551,11 @@
 
 int b1ctl_read_proc(char *page, char **start, off_t off,
         		int count, int *eof, struct capi_ctr *ctrl);
+
+avmcard_dmainfo *avmcard_dma_alloc(char *name, struct pci_dev *,
+				   long rsize, long ssize);
+void avmcard_dma_free(avmcard_dmainfo *);
+
 
 /* b1dma.c */
 int b1pciv4_detect(avmcard *card);
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/avmb1/b1.c linux/drivers/isdn/avmb1/b1.c
--- v2.5.1/linux/drivers/isdn/avmb1/b1.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/avmb1/b1.c	Tue Jan  1 19:00:01 2002
@@ -1,4 +1,4 @@
-/* $Id: b1.c,v 1.20.6.7 2001/09/23 22:24:33 kai Exp $
+/* $Id: b1.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
  * 
  * Common module for AVM B1 cards.
  * 
@@ -11,6 +11,7 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/pci.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
@@ -27,7 +28,7 @@
 #include "capicmd.h"
 #include "capiutil.h"
 
-static char *revision = "$Revision: 1.20.6.7 $";
+static char *revision = "$Revision: 1.1.4.1.2.1 $";
 
 /* ------------------------------------------------------------- */
 
@@ -638,6 +639,65 @@
 }
 
 /* ------------------------------------------------------------- */
+
+#ifdef CONFIG_PCI
+
+avmcard_dmainfo *
+avmcard_dma_alloc(char *name, struct pci_dev *pdev, long rsize, long ssize)
+{
+	avmcard_dmainfo *p;
+	void *buf;
+
+	p = kmalloc(sizeof(avmcard_dmainfo), GFP_KERNEL);
+	if (!p) {
+		printk(KERN_WARNING "%s: no memory.\n", name);
+		goto err;
+	}
+	memset(p, 0, sizeof(avmcard_dmainfo));
+
+	p->recvbuf.size = rsize;
+	buf = pci_alloc_consistent(pdev, rsize, &p->recvbuf.dmaaddr);
+	if (!buf) {
+		printk(KERN_WARNING "%s: allocation of receive dma buffer failed.\n", name);
+		goto err_kfree;
+	}
+	p->recvbuf.dmabuf = buf;
+
+	p->sendbuf.size = ssize;
+	buf = pci_alloc_consistent(pdev, ssize, &p->sendbuf.dmaaddr);
+	if (!buf) {
+		printk(KERN_WARNING "%s: allocation of send dma buffer failed.\n", name);
+		goto err_free_consistent;
+	}
+
+	p->sendbuf.dmabuf = buf;
+	skb_queue_head_init(&p->send_queue);
+
+	return p;
+
+ err_free_consistent:
+	pci_free_consistent(p->pcidev, p->recvbuf.size,
+			    p->recvbuf.dmabuf, p->recvbuf.dmaaddr);
+ err_kfree:
+	kfree(p);
+ err:
+	return 0;
+}
+
+void avmcard_dma_free(avmcard_dmainfo *p)
+{
+	pci_free_consistent(p->pcidev, p->recvbuf.size,
+			    p->recvbuf.dmabuf, p->recvbuf.dmaaddr);
+	pci_free_consistent(p->pcidev, p->sendbuf.size,
+			    p->sendbuf.dmabuf, p->sendbuf.dmaaddr);
+	skb_queue_purge(&p->send_queue);
+	kfree(p);
+}
+
+EXPORT_SYMBOL(avmcard_dma_alloc);
+EXPORT_SYMBOL(avmcard_dma_free);
+
+#endif
 
 EXPORT_SYMBOL(b1_irq_table);
 
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/avmb1/b1dma.c linux/drivers/isdn/avmb1/b1dma.c
--- v2.5.1/linux/drivers/isdn/avmb1/b1dma.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/avmb1/b1dma.c	Tue Jan  1 19:00:01 2002
@@ -1,4 +1,4 @@
-/* $Id: b1dma.c,v 1.11.6.8 2001/09/23 22:24:33 kai Exp $
+/* $Id: b1dma.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
  * 
  * Common module for AVM B1 cards that support dma with AMCC
  * 
@@ -32,7 +32,7 @@
 #error FIXME: driver requires 32-bit platform
 #endif
 
-static char *revision = "$Revision: 1.11.6.8 $";
+static char *revision = "$Revision: 1.1.4.1.2.1 $";
 
 /* ------------------------------------------------------------- */
 
@@ -388,7 +388,7 @@
 		cmd = CAPIMSG_COMMAND(skb->data);
 		subcmd = CAPIMSG_SUBCOMMAND(skb->data);
 
-		p = dma->sendbuf;
+		p = dma->sendbuf.dmabuf;
 
 		if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
 			__u16 dlen = CAPIMSG_DATALEN(skb->data);
@@ -399,7 +399,7 @@
 			_put_byte(&p, SEND_MESSAGE);
 			_put_slice(&p, skb->data, len);
 		}
-		txlen = (__u8 *)p - (__u8 *)dma->sendbuf;
+		txlen = (__u8 *)p - (__u8 *)dma->sendbuf.dmabuf;
 #ifdef CONFIG_B1DMA_DEBUG
 		printk(KERN_DEBUG "tx(%d): put msg len=%d\n",
 				inint, txlen);
@@ -414,11 +414,11 @@
 		printk(KERN_DEBUG "tx(%d): put 0x%x len=%d\n",
 				inint, skb->data[2], txlen);
 #endif
-		memcpy(dma->sendbuf, skb->data+2, skb->len-2);
+		memcpy(dma->sendbuf.dmabuf, skb->data+2, skb->len-2);
 	}
 	txlen = (txlen + 3) & ~3;
 
-	b1dmaoutmeml(card->mbase+AMCC_TXPTR, virt_to_phys(dma->sendbuf));
+	b1dmaoutmeml(card->mbase+AMCC_TXPTR, dma->sendbuf.dmaaddr);
 	b1dmaoutmeml(card->mbase+AMCC_TXLEN, txlen);
 
 	card->csr |= EN_TX_TC_INT;
@@ -461,7 +461,7 @@
 	avmcard_dmainfo *dma = card->dma;
 	struct capi_ctr *ctrl = cinfo->capi_ctrl;
 	struct sk_buff *skb;
-	void *p = dma->recvbuf+4;
+	void *p = dma->recvbuf.dmabuf+4;
 	__u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
 	__u8 b1cmd =  _get_byte(&p);
 
@@ -597,18 +597,19 @@
 	b1dmaoutmeml(card->mbase+AMCC_INTCSR, newcsr);
 
 	if ((status & RX_TC_INT) != 0) {
-		__u8 *recvbuf = card->dma->recvbuf;
+		struct avmcard_dmainfo *dma = card->dma;
 		__u32 rxlen;
 	   	if (card->dma->recvlen == 0) {
-			card->dma->recvlen = *((__u32 *)recvbuf);
-			rxlen = (card->dma->recvlen + 3) & ~3;
+			dma->recvlen = *((__u32 *)dma->recvbuf.dmabuf);
+			rxlen = (dma->recvlen + 3) & ~3;
 			b1dmaoutmeml(card->mbase+AMCC_RXPTR,
-					virt_to_phys(recvbuf+4));
+					dma->recvbuf.dmaaddr+4);
 			b1dmaoutmeml(card->mbase+AMCC_RXLEN, rxlen);
 		} else {
 			b1dma_handle_rx(card);
-	   		card->dma->recvlen = 0;
-			b1dmaoutmeml(card->mbase+AMCC_RXPTR, virt_to_phys(recvbuf));
+	   		dma->recvlen = 0;
+			b1dmaoutmeml(card->mbase+AMCC_RXPTR,
+					dma->recvbuf.dmaaddr);
 			b1dmaoutmeml(card->mbase+AMCC_RXLEN, 4);
 		}
 	}
@@ -744,7 +745,7 @@
 	t1outp(card->port, 0x10, 0xF0);
 
 	card->dma->recvlen = 0;
-	b1dmaoutmeml(card->mbase+AMCC_RXPTR, virt_to_phys(card->dma->recvbuf));
+	b1dmaoutmeml(card->mbase+AMCC_RXPTR, card->dma->recvbuf.dmaaddr);
 	b1dmaoutmeml(card->mbase+AMCC_RXLEN, 4);
 	card->csr |= EN_RX_TC_INT;
 	b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
@@ -855,7 +856,7 @@
 	__u8 flag;
 	int len = 0;
 	char *s;
-	__u32 txaddr, txlen, rxaddr, rxlen, csr;
+	__u32 txoff, txlen, rxoff, rxlen, csr;
 
 	len += sprintf(page+len, "%-16s %s\n", "name", card->name);
 	len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
@@ -911,13 +912,11 @@
 	save_flags(flags);
 	cli();
 
-	txaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x2c));
-	txaddr -= (__u32)card->dma->sendbuf;
-	txlen  = b1dmainmeml(card->mbase+0x30);
-
-	rxaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x24));
-	rxaddr -= (__u32)card->dma->recvbuf;
-	rxlen  = b1dmainmeml(card->mbase+0x28);
+	txoff = (dma_addr_t)b1dmainmeml(card->mbase+0x2c)-card->dma->sendbuf.dmaaddr;
+	txlen = b1dmainmeml(card->mbase+0x30);
+
+	rxoff = (dma_addr_t)b1dmainmeml(card->mbase+0x24)-card->dma->recvbuf.dmaaddr;
+	rxlen = b1dmainmeml(card->mbase+0x28);
 
 	csr  = b1dmainmeml(card->mbase+AMCC_INTCSR);
 
@@ -928,11 +927,11 @@
         len += sprintf(page+len, "%-16s 0x%lx\n",
 				"csr", (unsigned long)csr);
         len += sprintf(page+len, "%-16s %lu\n",
-				"txoff", (unsigned long)txaddr);
+				"txoff", (unsigned long)txoff);
         len += sprintf(page+len, "%-16s %lu\n",
 				"txlen", (unsigned long)txlen);
         len += sprintf(page+len, "%-16s %lu\n",
-				"rxoff", (unsigned long)rxaddr);
+				"rxoff", (unsigned long)rxoff);
         len += sprintf(page+len, "%-16s %lu\n",
 				"rxlen", (unsigned long)rxlen);
 
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/avmb1/b1pci.c linux/drivers/isdn/avmb1/b1pci.c
--- v2.5.1/linux/drivers/isdn/avmb1/b1pci.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/avmb1/b1pci.c	Tue Jan  1 19:00:01 2002
@@ -1,4 +1,4 @@
-/* $Id: b1pci.c,v 1.29.6.5 2001/09/23 22:24:33 kai Exp $
+/* $Id: b1pci.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
  * 
  * Module for AVM B1 PCI-card.
  * 
@@ -26,7 +26,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.29.6.5 $";
+static char *revision = "$Revision: 1.1.4.1.2.1 $";
 
 /* ------------------------------------------------------------- */
 
@@ -108,7 +108,9 @@
 
 /* ------------------------------------------------------------- */
 
-static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
+static int b1pci_add_card(struct capi_driver *driver,
+                          struct capicardparams *p,
+			  struct pci_dev *dev)
 {
 	avmcard *card;
 	avmctrl_info *cinfo;
@@ -237,7 +239,7 @@
 	release_region(card->port, AVMB1_PORTLEN);
 	ctrl->driverdata = 0;
 	kfree(card->ctrlinfo);
-	kfree(card->dma);
+        avmcard_dma_free(card->dma);
 	kfree(card);
 
 	MOD_DEC_USE_COUNT;
@@ -262,7 +264,9 @@
 
 /* ------------------------------------------------------------- */
 
-static int b1pciv4_add_card(struct capi_driver *driver, struct capicardparams *p)
+static int b1pciv4_add_card(struct capi_driver *driver,
+                            struct capicardparams *p,
+			    struct pci_dev *dev)
 {
 	avmcard *card;
 	avmctrl_info *cinfo;
@@ -278,18 +282,17 @@
 		return -ENOMEM;
 	}
 	memset(card, 0, sizeof(avmcard));
-	card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC);
+        card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
 	if (!card->dma) {
-		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		printk(KERN_WARNING "%s: dma alloc.\n", driver->name);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
-	memset(card->dma, 0, sizeof(avmcard_dmainfo));
         cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
 	if (!cinfo) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		kfree(card->dma);
+                avmcard_dma_free(card->dma);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -ENOMEM;
@@ -308,7 +311,7 @@
 		       "%s: ports 0x%03x-0x%03x in use.\n",
 		       driver->name, card->port, card->port + AVMB1_PORTLEN);
 	        kfree(card->ctrlinfo);
-		kfree(card->dma);
+                avmcard_dma_free(card->dma);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -EBUSY;
@@ -319,7 +322,7 @@
 		printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
 					driver->name, card->membase);
 	        kfree(card->ctrlinfo);
-		kfree(card->dma);
+                avmcard_dma_free(card->dma);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -EIO;
@@ -332,7 +335,7 @@
 					driver->name, card->port, retval);
                 iounmap(card->mbase);
 	        kfree(card->ctrlinfo);
-		kfree(card->dma);
+                avmcard_dma_free(card->dma);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -EIO;
@@ -349,7 +352,7 @@
                 iounmap(card->mbase);
 		release_region(card->port, AVMB1_PORTLEN);
 	        kfree(card->ctrlinfo);
-		kfree(card->dma);
+                avmcard_dma_free(card->dma);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -EBUSY;
@@ -362,15 +365,13 @@
 		free_irq(card->irq, card);
 		release_region(card->port, AVMB1_PORTLEN);
 	        kfree(card->ctrlinfo);
-		kfree(card->dma);
+                avmcard_dma_free(card->dma);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -EBUSY;
 	}
 	card->cardnr = cinfo->capi_ctrl->cnr;
 
-	skb_queue_head_init(&card->dma->send_queue);
-
 	printk(KERN_INFO
 		"%s: AVM B1 PCI V4 at i/o %#x, irq %d, mem %#lx, revision %d (dma)\n",
 		driver->name, card->port, card->irq,
@@ -429,9 +430,9 @@
 		"%s: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n",
 		driver->name, param.port, param.irq, param.membase);
 #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
-		retval = b1pciv4_add_card(driver, &param);
+		retval = b1pciv4_add_card(driver, &param, dev);
 #else
-		retval = b1pci_add_card(driver, &param);
+		retval = b1pci_add_card(driver, &param, dev);
 #endif
 		if (retval != 0) {
 		        printk(KERN_ERR
@@ -445,7 +446,7 @@
 		printk(KERN_INFO
 		"%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n",
 		driver->name, param.port, param.irq);
-		retval = b1pci_add_card(driver, &param);
+		retval = b1pci_add_card(driver, &param, dev);
 		if (retval != 0) {
 		        printk(KERN_ERR
 			"%s: no AVM-B1 at i/o %#x, irq %d detected\n",
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c
--- v2.5.1/linux/drivers/isdn/avmb1/c4.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/avmb1/c4.c	Tue Jan  1 19:00:01 2002
@@ -1,4 +1,4 @@
-/* $Id: c4.c,v 1.20.6.11 2001/09/23 22:24:33 kai Exp $
+/* $Id: c4.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
  * 
  * Module for AVM C4 & C2 card.
  * 
@@ -29,7 +29,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.20.6.11 $";
+static char *revision = "$Revision: 1.1.4.1.2.1 $";
 
 #undef CONFIG_C4_DEBUG
 #undef CONFIG_C4_POLLDEBUG
@@ -439,7 +439,7 @@
 		cmd = CAPIMSG_COMMAND(skb->data);
 		subcmd = CAPIMSG_SUBCOMMAND(skb->data);
 
-		p = dma->sendbuf;
+		p = dma->sendbuf.dmabuf;
 
 		if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
 			__u16 dlen = CAPIMSG_DATALEN(skb->data);
@@ -450,7 +450,7 @@
 			_put_byte(&p, SEND_MESSAGE);
 			_put_slice(&p, skb->data, len);
 		}
-		txlen = (__u8 *)p - (__u8 *)dma->sendbuf;
+		txlen = (__u8 *)p - (__u8 *)dma->sendbuf.dmabuf;
 #ifdef CONFIG_C4_DEBUG
 		printk(KERN_DEBUG "%s: tx put msg len=%d\n", card->name, txlen);
 #endif
@@ -464,11 +464,11 @@
 		printk(KERN_DEBUG "%s: tx put 0x%x len=%d\n",
 				card->name, skb->data[2], txlen);
 #endif
-		memcpy(dma->sendbuf, skb->data+2, skb->len-2);
+		memcpy(dma->sendbuf.dmabuf, skb->data+2, skb->len-2);
 	}
 	txlen = (txlen + 3) & ~3;
 
-	c4outmeml(card->mbase+MBOX_DOWN_ADDR, virt_to_phys(dma->sendbuf));
+	c4outmeml(card->mbase+MBOX_DOWN_ADDR, dma->sendbuf.dmaaddr);
 	c4outmeml(card->mbase+MBOX_DOWN_LEN, txlen);
 
 	card->csr |= DBELL_DOWN_ARM;
@@ -510,7 +510,7 @@
 	struct capi_ctr *ctrl;
 	avmctrl_info *cinfo;
 	struct sk_buff *skb;
-	void *p = dma->recvbuf;
+	void *p = dma->recvbuf.dmabuf;
 	__u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
 	__u8 b1cmd =  _get_byte(&p);
 	__u32 cidx;
@@ -702,7 +702,7 @@
 		c4outmeml(card->mbase+MBOX_UP_LEN, 0);
 		c4_handle_rx(card);
 		card->dma->recvlen = 0;
-		c4outmeml(card->mbase+MBOX_UP_LEN, sizeof(card->dma->recvbuf));
+		c4outmeml(card->mbase+MBOX_UP_LEN, card->dma->recvbuf.size);
 		c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM);
 	}
 
@@ -885,8 +885,8 @@
 	c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x08);
 
 	card->dma->recvlen = 0;
-	c4outmeml(card->mbase+MBOX_UP_ADDR, virt_to_phys(card->dma->recvbuf));
-	c4outmeml(card->mbase+MBOX_UP_LEN, sizeof(card->dma->recvbuf));
+	c4outmeml(card->mbase+MBOX_UP_ADDR, card->dma->recvbuf.dmaaddr);
+	c4outmeml(card->mbase+MBOX_UP_LEN, card->dma->recvbuf.size);
 	c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM);
 	restore_flags(flags);
 
@@ -944,7 +944,7 @@
 	release_region(card->port, AVMB1_PORTLEN);
 	ctrl->driverdata = 0;
 	kfree(card->ctrlinfo);
-	kfree(card->dma);
+        avmcard_dma_free(card->dma);
 	kfree(card);
 
 	MOD_DEC_USE_COUNT;
@@ -1123,6 +1123,7 @@
 
 static int c4_add_card(struct capi_driver *driver,
 		       struct capicardparams *p,
+                       struct pci_dev *dev,
 		       int nr)
 {
 	avmctrl_info *cinfo;
@@ -1140,18 +1141,17 @@
 		return -ENOMEM;
 	}
 	memset(card, 0, sizeof(avmcard));
-	card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC);
+        card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
 	if (!card->dma) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
-	memset(card->dma, 0, sizeof(avmcard_dmainfo));
         cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info)*4, GFP_ATOMIC);
 	if (!cinfo) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		kfree(card->dma);
+                avmcard_dma_free(card->dma);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -ENOMEM;
@@ -1173,7 +1173,7 @@
 		       "%s: ports 0x%03x-0x%03x in use.\n",
 		       driver->name, card->port, card->port + AVMB1_PORTLEN);
 	        kfree(card->ctrlinfo);
-		kfree(card->dma);
+                avmcard_dma_free(card->dma);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -EBUSY;
@@ -1184,7 +1184,7 @@
 		printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
 					driver->name, card->membase);
 	        kfree(card->ctrlinfo);
-		kfree(card->dma);
+                avmcard_dma_free(card->dma);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -EIO;
@@ -1195,7 +1195,7 @@
 					driver->name, card->port, retval);
                 iounmap(card->mbase);
 	        kfree(card->ctrlinfo);
-		kfree(card->dma);
+                avmcard_dma_free(card->dma);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -EIO;
@@ -1211,7 +1211,7 @@
                 iounmap(card->mbase);
 		release_region(card->port, AVMB1_PORTLEN);
 	        kfree(card->ctrlinfo);
-		kfree(card->dma);
+                avmcard_dma_free(card->dma);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -EBUSY;
@@ -1231,7 +1231,7 @@
                 	iounmap(card->mbase);
 			free_irq(card->irq, card);
 			release_region(card->port, AVMB1_PORTLEN);
-	        	kfree(card->dma);
+                        avmcard_dma_free(card->dma);
 	        	kfree(card->ctrlinfo);
 			kfree(card);
 	        	MOD_DEC_USE_COUNT;
@@ -1241,8 +1241,6 @@
 			card->cardnr = cinfo->capi_ctrl->cnr;
 	}
 
-	skb_queue_head_init(&card->dma->send_queue);
-
 	printk(KERN_INFO
 		"%s: AVM C%d at i/o %#x, irq %d, mem %#lx\n",
 		driver->name, nr, card->port, card->irq, card->membase);
@@ -1335,7 +1333,7 @@
 		printk(KERN_INFO
 			"%s: PCI BIOS reports AVM-C%d at i/o %#x, irq %d, mem %#x\n",
 			driver->name, nr, param.port, param.irq, param.membase);
-		retval = c4_add_card(driver, &param, nr);
+		retval = c4_add_card(driver, &param, dev, nr);
 		if (retval != 0) {
 		        printk(KERN_ERR
 			"%s: no AVM-C%d at i/o %#x, irq %d detected, mem %#x\n",
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c
--- v2.5.1/linux/drivers/isdn/avmb1/capi.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/isdn/avmb1/capi.c	Thu Jan  3 12:20:10 2002
@@ -129,11 +129,9 @@
 };
 
 struct capidev {
-	struct capidev *next;
-	struct file    *file;
+	struct list_head list;
 	u16		applid;
 	u16		errcode;
-	unsigned int    minor;
 	unsigned        userflags;
 
 	struct sk_buff_head recvqueue;
@@ -150,17 +148,18 @@
 
 /* -------- global variables ---------------------------------------- */
 
-static struct capi_interface *capifuncs = 0;
-static struct capidev *capidev_openlist = 0;
+static struct capi_interface *capifuncs;
+static rwlock_t capidev_list_lock;
+static LIST_HEAD(capidev_list);
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-static struct capiminor *minors = 0;
+static struct capiminor *minors;
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 
-static kmem_cache_t *capidev_cachep = 0;
-static kmem_cache_t *capincci_cachep = 0;
+static kmem_cache_t *capidev_cachep;
+static kmem_cache_t *capincci_cachep;
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-static kmem_cache_t *capiminor_cachep = 0;
-static kmem_cache_t *capidh_cachep = 0;
+static kmem_cache_t *capiminor_cachep;
+static kmem_cache_t *capidh_cachep;
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
@@ -318,9 +317,9 @@
 		printk(KERN_DEBUG "set mp->nccip\n");
 #endif
 #if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
-		kdev = MKDEV(capi_rawmajor, mp->minor);
+		kdev = mk_kdev(capi_rawmajor, mp->minor);
 		capifs_new_ncci('r', mp->minor, kdev);
-		kdev = MKDEV(capi_ttymajor, mp->minor);
+		kdev = mk_kdev(capi_ttymajor, mp->minor);
 		capifs_new_ncci(0, mp->minor, kdev);
 #endif
 	}
@@ -391,48 +390,52 @@
 static struct capidev *capidev_alloc(struct file *file)
 {
 	struct capidev *cdev;
-	struct capidev **pp;
+	unsigned long flags;
 
 	cdev = (struct capidev *)kmem_cache_alloc(capidev_cachep, GFP_KERNEL);
 	if (!cdev)
 		return 0;
 	memset(cdev, 0, sizeof(struct capidev));
-	cdev->file = file;
-	cdev->minor = MINOR(file->f_dentry->d_inode->i_rdev);
 
 	skb_queue_head_init(&cdev->recvqueue);
 	init_waitqueue_head(&cdev->recvwait);
-	pp=&capidev_openlist;
-	while (*pp) pp = &(*pp)->next;
-	*pp = cdev;
+	write_lock_irqsave(&capidev_list_lock, flags);
+	list_add_tail(&cdev->list, &capidev_list);
+	write_unlock_irqrestore(&capidev_list_lock, flags);
         return cdev;
 }
 
 static void capidev_free(struct capidev *cdev)
 {
-	struct capidev **pp;
+	unsigned long flags;
 
 	if (cdev->applid)
 		(*capifuncs->capi_release) (cdev->applid);
 	cdev->applid = 0;
-
 	skb_queue_purge(&cdev->recvqueue);
-	
-	pp=&capidev_openlist;
-	while (*pp && *pp != cdev) pp = &(*pp)->next;
-	if (*pp)
-		*pp = cdev->next;
-
+	write_lock_irqsave(&capidev_list_lock, flags);
+	list_del(&cdev->list);
+	write_unlock_irqrestore(&capidev_list_lock, flags);
 	kmem_cache_free(capidev_cachep, cdev);
 }
 
 static struct capidev *capidev_find(u16 applid)
 {
-	struct capidev *p;
-	for (p=capidev_openlist; p; p = p->next) {
+	// FIXME this doesn't guarantee that the device won't go away shortly
+	struct list_head *l;
+	struct capidev *p = NULL;
+
+	read_lock(&capidev_list_lock);
+	list_for_each(l, &capidev_list) {
+		p = list_entry(l, struct capidev, list);
 		if (p->applid == applid)
 			break;
 	}
+	read_unlock(&capidev_list_lock);
+	
+	if (l == &capidev_list)
+		return NULL;
+	
 	return p;
 }
 
@@ -1088,7 +1091,7 @@
 
 	if (file->private_data)
 		return -EEXIST;
-	if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0)
+	if ((mp = capiminor_find(minor(file->f_dentry->d_inode->i_rdev))) == 0)
 		return -ENXIO;
 	if (mp->nccip == 0)
 		return -ENXIO;
@@ -1272,7 +1275,7 @@
 {
 	struct capiminor *mp;
 
-	if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0)
+	if ((mp = capiminor_find(minor(file->f_dentry->d_inode->i_rdev))) == 0)
 		return -ENXIO;
 	if (mp->nccip == 0)
 		return -ENXIO;
@@ -1662,11 +1665,13 @@
                                        int count, int *eof, void *data)
 {
         struct capidev *cdev;
+	struct list_head *l;
 	int len = 0;
 
-	for (cdev=capidev_openlist; cdev; cdev = cdev->next) {
-		len += sprintf(page+len, "%d %d %lu %lu %lu %lu\n",
-			cdev->minor,
+	read_lock(&capidev_list_lock);
+	list_for_each(l, &capidev_list) {
+		cdev = list_entry(l, struct capidev, list);
+		len += sprintf(page+len, "0 %d %lu %lu %lu %lu\n",
 			cdev->applid,
 			cdev->nrecvctlpkt,
 			cdev->nrecvdatapkt,
@@ -1680,11 +1685,13 @@
 				goto endloop;
 		}
 	}
+
 endloop:
+	read_unlock(&capidev_list_lock);
 	if (len < count)
 		*eof = 1;
-	if (len>count) len = count;
-	if (len<0) len = 0;
+	if (len > count) len = count;
+	if (len < 0) len = 0;
 	return len;
 }
 
@@ -1697,9 +1704,12 @@
 {
         struct capidev *cdev;
         struct capincci *np;
+	struct list_head *l;
 	int len = 0;
 
-	for (cdev=capidev_openlist; cdev; cdev = cdev->next) {
+	read_lock(&capidev_list_lock);
+	list_for_each(l, &capidev_list) {
+		cdev = list_entry(l, struct capidev, list);
 		for (np=cdev->nccis; np; np = np->next) {
 			len += sprintf(page+len, "%d 0x%x%s\n",
 				cdev->applid,
@@ -1719,6 +1729,7 @@
 		}
 	}
 endloop:
+	read_unlock(&capidev_list_lock);
 	*start = page+off;
 	if (len < count)
 		*eof = 1;
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/avmb1/capidrv.c linux/drivers/isdn/avmb1/capidrv.c
--- v2.5.1/linux/drivers/isdn/avmb1/capidrv.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/avmb1/capidrv.c	Sun Dec 30 10:31:51 2001
@@ -29,7 +29,6 @@
 #include <linux/kernelcapi.h>
 #include <linux/ctype.h>
 #include <linux/init.h>
-#include <asm/segment.h>
 
 #include "capiutil.h"
 #include "capicmd.h"
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/avmb1/capifs.c linux/drivers/isdn/avmb1/capifs.c
--- v2.5.1/linux/drivers/isdn/avmb1/capifs.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/avmb1/capifs.c	Thu Jan  3 12:20:10 2002
@@ -430,7 +430,7 @@
 			inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid;
 			inode->i_nlink = 1;
 			inode->i_ino = ino + 2;
-			init_special_inode(inode, sbi->mode|S_IFCHR, np->kdev);
+			init_special_inode(inode, sbi->mode|S_IFCHR, kdev_t_to_nr(np->kdev));
 		}
 	}
 }
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/avmb1/capiutil.c linux/drivers/isdn/avmb1/capiutil.c
--- v2.5.1/linux/drivers/isdn/avmb1/capiutil.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/avmb1/capiutil.c	Sun Dec 30 10:31:51 2001
@@ -17,7 +17,6 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/init.h>
-#include <asm/segment.h>
 #include <linux/config.h>
 #include "capiutil.h"
 
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/avmb1/kcapi.c linux/drivers/isdn/avmb1/kcapi.c
--- v2.5.1/linux/drivers/isdn/avmb1/kcapi.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/avmb1/kcapi.c	Sun Dec 30 10:31:51 2001
@@ -17,7 +17,6 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
-#include <asm/segment.h>
 #include <linux/proc_fs.h>
 #include <linux/skbuff.h>
 #include <linux/tqueue.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/avmb1/t1pci.c linux/drivers/isdn/avmb1/t1pci.c
--- v2.5.1/linux/drivers/isdn/avmb1/t1pci.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/avmb1/t1pci.c	Tue Jan  1 19:00:01 2002
@@ -1,4 +1,4 @@
-/* $Id: t1pci.c,v 1.13.6.6 2001/09/23 22:24:34 kai Exp $
+/* $Id: t1pci.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
  * 
  * Module for AVM T1 PCI-card.
  * 
@@ -26,7 +26,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.13.6.6 $";
+static char *revision = "$Revision: 1.1.4.1.2.1 $";
 
 #undef CONFIG_T1PCI_DEBUG
 #undef CONFIG_T1PCI_POLLDEBUG
@@ -62,7 +62,7 @@
 	release_region(card->port, AVMB1_PORTLEN);
 	ctrl->driverdata = 0;
 	kfree(card->ctrlinfo);
-	kfree(card->dma);
+	avmcard_dma_free(card->dma);
 	kfree(card);
 
 	MOD_DEC_USE_COUNT;
@@ -70,7 +70,9 @@
 
 /* ------------------------------------------------------------- */
 
-static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
+static int t1pci_add_card(struct capi_driver *driver,
+                          struct capicardparams *p,
+	                  struct pci_dev *dev)
 {
 	avmcard *card;
 	avmctrl_info *cinfo;
@@ -86,18 +88,17 @@
 		return -ENOMEM;
 	}
 	memset(card, 0, sizeof(avmcard));
-	card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC);
+        card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
 	if (!card->dma) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
-	memset(card->dma, 0, sizeof(avmcard_dmainfo));
         cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
 	if (!cinfo) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		kfree(card->dma);
+		avmcard_dma_free(card->dma);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -ENOMEM;
@@ -116,7 +117,7 @@
 		       "%s: ports 0x%03x-0x%03x in use.\n",
 		       driver->name, card->port, card->port + AVMB1_PORTLEN);
 	        kfree(card->ctrlinfo);
-		kfree(card->dma);
+		avmcard_dma_free(card->dma);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -EBUSY;
@@ -127,7 +128,7 @@
 		printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
 					driver->name, card->membase);
 	        kfree(card->ctrlinfo);
-		kfree(card->dma);
+		avmcard_dma_free(card->dma);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -EIO;
@@ -144,7 +145,7 @@
 					driver->name, card->port, retval);
                 iounmap(card->mbase);
 	        kfree(card->ctrlinfo);
-		kfree(card->dma);
+		avmcard_dma_free(card->dma);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -EIO;
@@ -160,7 +161,7 @@
                 iounmap(card->mbase);
 		release_region(card->port, AVMB1_PORTLEN);
 	        kfree(card->ctrlinfo);
-		kfree(card->dma);
+		avmcard_dma_free(card->dma);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -EBUSY;
@@ -173,15 +174,13 @@
 		free_irq(card->irq, card);
 		release_region(card->port, AVMB1_PORTLEN);
 	        kfree(card->ctrlinfo);
-		kfree(card->dma);
+		avmcard_dma_free(card->dma);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
 		return -EBUSY;
 	}
 	card->cardnr = cinfo->capi_ctrl->cnr;
 
-	skb_queue_head_init(&card->dma->send_queue);
-
 	printk(KERN_INFO
 		"%s: AVM T1 PCI at i/o %#x, irq %d, mem %#lx\n",
 		driver->name, card->port, card->irq, card->membase);
@@ -271,7 +270,7 @@
 		printk(KERN_INFO
 			"%s: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n",
 			driver->name, param.port, param.irq, param.membase);
-		retval = t1pci_add_card(driver, &param);
+		retval = t1pci_add_card(driver, &param, dev);
 		if (retval != 0) {
 		        printk(KERN_ERR
 			"%s: no AVM-T1-PCI at i/o %#x, irq %d detected, mem %#x\n",
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/eicon/eicon.h linux/drivers/isdn/eicon/eicon.h
--- v2.5.1/linux/drivers/isdn/eicon/eicon.h	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/eicon/eicon.h	Sun Dec 30 10:31:51 2001
@@ -123,7 +123,6 @@
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/major.h>
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/eicon/lincfg.c linux/drivers/isdn/eicon/lincfg.c
--- v2.5.1/linux/drivers/isdn/eicon/lincfg.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/eicon/lincfg.c	Sun Dec 30 10:31:51 2001
@@ -11,7 +11,6 @@
 #include <linux/fs.h>
 #undef N_DATA   /* Because we have our own definition */
 
-#include <asm/segment.h>
 #include <asm/io.h>
 
 #include "sys.h"
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/hisax/Makefile linux/drivers/isdn/hisax/Makefile
--- v2.5.1/linux/drivers/isdn/hisax/Makefile	Tue Dec 18 14:56:36 2001
+++ linux/drivers/isdn/hisax/Makefile	Tue Jan  1 19:00:01 2002
@@ -4,6 +4,10 @@
 
 O_TARGET	  := vmlinux-obj.o
 
+# Define maximum number of cards
+
+EXTRA_CFLAGS      += -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS)
+
 # Objects that export symbols.
 
 export-objs	  := config.o fsm.o hisax_isac.o
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c
--- v2.5.1/linux/drivers/isdn/hisax/config.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/isdn/hisax/config.c	Tue Jan  1 19:00:01 2002
@@ -1,4 +1,4 @@
-/* $Id: config.c,v 2.57.6.20 2001/09/23 22:24:47 kai Exp $
+/* $Id: config.c,v 1.1.4.2.2.1 2001/12/09 20:18:40 kai Exp $
  *
  * Author       Karsten Keil
  * Copyright    by Karsten Keil      <keil@isdn4linux.de>
@@ -336,27 +336,19 @@
 	NULL, \
 }
 
-#define EMPTY_CARD	{0, DEFAULT_PROTO, {0, 0, 0, 0}, NULL}
-
-struct IsdnCard cards[] = {
+struct IsdnCard cards[HISAX_MAX_CARDS] = {
 	FIRST_CARD,
-	EMPTY_CARD,
-	EMPTY_CARD,
-	EMPTY_CARD,
-	EMPTY_CARD,
-	EMPTY_CARD,
-	EMPTY_CARD,
-	EMPTY_CARD,
 };
 
-static char HiSaxID[64] __devinitdata = { 0, };
+#define HISAX_IDSIZE (HISAX_MAX_CARDS*8)
+static char HiSaxID[HISAX_IDSIZE] __devinitdata = { 0, };
 
 char *HiSax_id __devinitdata = HiSaxID;
 #ifdef MODULE
 /* Variables for insmod */
-static int type[8] __devinitdata = { 0, };
-static int protocol[8] __devinitdata = { 0, };
-static int io[8] __devinitdata = { 0, };
+static int type[HISAX_MAX_CARDS] __devinitdata = { 0, };
+static int protocol[HISAX_MAX_CARDS] __devinitdata = { 0, };
+static int io[HISAX_MAX_CARDS] __devinitdata = { 0, };
 #undef IO0_IO1
 #ifdef CONFIG_HISAX_16_3
 #define IO0_IO1
@@ -366,25 +358,27 @@
 #define IO0_IO1
 #endif
 #ifdef IO0_IO1
-static int io0[8] __devinitdata = { 0, };
-static int io1[8] __devinitdata = { 0, };
+static int io0[HISAX_MAX_CARDS] __devinitdata = { 0, };
+static int io1[HISAX_MAX_CARDS] __devinitdata = { 0, };
 #endif
-static int irq[8] __devinitdata = { 0, };
-static int mem[8] __devinitdata = { 0, };
+static int irq[HISAX_MAX_CARDS] __devinitdata = { 0, };
+static int mem[HISAX_MAX_CARDS] __devinitdata = { 0, };
 static char *id __devinitdata = HiSaxID;
 
+#define PARM_PARA "1-" __MODULE_STRING(HISAX_MAX_CARDS) "i"
+
 MODULE_DESCRIPTION("ISDN4Linux: Driver for passive ISDN cards");
 MODULE_AUTHOR("Karsten Keil");
 MODULE_LICENSE("GPL");
-MODULE_PARM(type, "1-8i");
-MODULE_PARM(protocol, "1-8i");
-MODULE_PARM(io, "1-8i");
-MODULE_PARM(irq, "1-8i");
-MODULE_PARM(mem, "1-8i");
+MODULE_PARM(type, PARM_PARA);
+MODULE_PARM(protocol, PARM_PARA);
+MODULE_PARM(io, PARM_PARA);
+MODULE_PARM(irq, PARM_PARA);
+MODULE_PARM(mem, PARM_PARA);
 MODULE_PARM(id, "s");
 #ifdef IO0_IO1
-MODULE_PARM(io0, "1-8i");
-MODULE_PARM(io1, "1-8i");
+MODULE_PARM(io0, PARM_PARA);
+MODULE_PARM(io1, PARM_PARA);
 #endif
 #endif /* MODULE */
 
@@ -448,6 +442,7 @@
 	i = 0;
 	j = 1;
 	while (argc && (i < HISAX_MAX_CARDS)) {
+		cards[i].protocol = DEFAULT_PROTO;
 		if (argc) {
 			cards[i].typ = ints[j];
 			j++;
@@ -475,13 +470,15 @@
 		}
 		i++;
 	}
-	if (str && *str) {
-		strcpy(HiSaxID, str);
-		HiSax_id = HiSaxID;
-	} else {
+  	if (str && *str) {
+		if (strlen(str) < HISAX_IDSIZE)
+			strcpy(HiSaxID, str);
+		else
+			printk(KERN_WARNING "HiSax: ID too long!");
+	} else
 		strcpy(HiSaxID, "HiSax");
-		HiSax_id = HiSaxID;
-	}
+
+	HiSax_id = HiSaxID;
 	return 1;
 }
 
@@ -1396,6 +1393,8 @@
 		if (protocol[i]) {
 			cards[j].protocol = protocol[i];
 			nzproto++;
+		} else {
+			cards[j].protocol = DEFAULT_PROTO;
 		}
 		switch (type[i]) {
 		case ISDN_CTYPE_16_0:
@@ -1473,15 +1472,22 @@
 			} else {
 				/* QUADRO is a 4 BRI card */
 				cards[j++].para[0] = 1;
-				cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
-				cards[j].protocol = protocol[i];
-				cards[j++].para[0] = 2;
-				cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
-				cards[j].protocol = protocol[i];
-				cards[j++].para[0] = 3;
-				cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
-				cards[j].protocol = protocol[i];
-				cards[j].para[0] = 4;
+				/* we need to check if further cards can be added */
+				if (j < HISAX_MAX_CARDS) {
+					cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+					cards[j].protocol = protocol[i];
+					cards[j++].para[0] = 2;
+				}
+				if (j < HISAX_MAX_CARDS) {
+					cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+					cards[j].protocol = protocol[i];
+					cards[j++].para[0] = 3;
+				}
+				if (j < HISAX_MAX_CARDS) {
+					cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+					cards[j].protocol = protocol[i];
+					cards[j].para[0] = 4;
+				}
 			}
 			break;
 		}
@@ -1554,6 +1560,8 @@
 		cards[i].typ = type[i];
 		if (protocol[i]) {
 			cards[i].protocol = protocol[i];
+		} else {
+			cards[i].protocol = DEFAULT_PROTO;
 		}
 	}
 	cards[0].para[0] = pcm_irq;
@@ -1594,6 +1602,8 @@
 		cards[i].typ = type[i];
 		if (protocol[i]) {
 			cards[i].protocol = protocol[i];
+		} else {
+			cards[i].protocol = DEFAULT_PROTO;
 		}
 	}
 	cards[0].para[0] = pcm_irq;
@@ -1634,6 +1644,8 @@
 		cards[i].typ = type[i];
 		if (protocol[i]) {
 			cards[i].protocol = protocol[i];
+		} else {
+			cards[i].protocol = DEFAULT_PROTO;
 		}
 	}
 	cards[0].para[0] = pcm_irq;
@@ -1674,6 +1686,8 @@
 		cards[i].typ = type[i];
 		if (protocol[i]) {
 			cards[i].protocol = protocol[i];
+		} else {
+			cards[i].protocol = DEFAULT_PROTO;
 		}
 	}
 	cards[0].para[0] = pcm_irq;
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h
--- v2.5.1/linux/drivers/isdn/hisax/hisax.h	Sun Sep 30 12:26:05 2001
+++ linux/drivers/isdn/hisax/hisax.h	Tue Jan  1 19:00:01 2002
@@ -1,4 +1,4 @@
-/* $Id: hisax.h,v 2.52.6.9 2001/09/23 22:24:48 kai Exp $
+/* $Id: hisax.h,v 1.1.4.1.2.1 2001/12/09 20:18:40 kai Exp $
  *
  * Basic declarations, defines and prototypes
  *
@@ -10,7 +10,6 @@
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/major.h>
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
@@ -949,8 +948,6 @@
 #define  MON1_RX	2
 #define  MON0_TX	4
 #define  MON1_TX	8
-
-#define	 HISAX_MAX_CARDS	8
 
 #define  ISDN_CTYPE_16_0	1
 #define  ISDN_CTYPE_8_0		2
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/icn/icn.h linux/drivers/isdn/icn/icn.h
--- v2.5.1/linux/drivers/isdn/icn/icn.h	Sun Sep 30 12:26:06 2001
+++ linux/drivers/isdn/icn/icn.h	Sun Dec 30 10:31:51 2001
@@ -39,7 +39,6 @@
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/major.h>
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/isdn_bsdcomp.c linux/drivers/isdn/isdn_bsdcomp.c
--- v2.5.1/linux/drivers/isdn/isdn_bsdcomp.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/isdn/isdn_bsdcomp.c	Sun Dec 30 10:31:51 2001
@@ -71,7 +71,6 @@
 
 #include <asm/system.h>
 #include <asm/bitops.h>
-#include <asm/segment.h>
 #include <asm/byteorder.h>
 #include <asm/types.h>
 
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
--- v2.5.1/linux/drivers/isdn/isdn_common.c	Fri Nov  9 13:41:41 2001
+++ linux/drivers/isdn/isdn_common.c	Thu Jan  3 12:20:10 2002
@@ -963,7 +963,7 @@
 static ssize_t
 isdn_read(struct file *file, char *buf, size_t count, loff_t * off)
 {
-	uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
+	uint minor = minor(file->f_dentry->d_inode->i_rdev);
 	int len = 0;
 	ulong flags;
 	int drvidx;
@@ -1077,7 +1077,7 @@
 static ssize_t
 isdn_write(struct file *file, const char *buf, size_t count, loff_t * off)
 {
-	uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
+	uint minor = minor(file->f_dentry->d_inode->i_rdev);
 	int drvidx;
 	int chidx;
 	int retval;
@@ -1143,7 +1143,7 @@
 isdn_poll(struct file *file, poll_table * wait)
 {
 	unsigned int mask = 0;
-	unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+	unsigned int minor = minor(file->f_dentry->d_inode->i_rdev);
 	int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
 
 	lock_kernel();
@@ -1184,7 +1184,7 @@
 static int
 isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
 {
-	uint minor = MINOR(inode->i_rdev);
+	uint minor = minor(inode->i_rdev);
 	isdn_ctrl c;
 	int drvidx;
 	int chidx;
@@ -1635,7 +1635,7 @@
 static int
 isdn_open(struct inode *ino, struct file *filep)
 {
-	uint minor = MINOR(ino->i_rdev);
+	uint minor = minor(ino->i_rdev);
 	int drvidx;
 	int chidx;
 	int retval = -ENODEV;
@@ -1696,7 +1696,7 @@
 static int
 isdn_close(struct inode *ino, struct file *filep)
 {
-	uint minor = MINOR(ino->i_rdev);
+	uint minor = minor(ino->i_rdev);
 
 	lock_kernel();
 	if (minor == ISDN_MINOR_STATUS) {
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c
--- v2.5.1/linux/drivers/isdn/isdn_ppp.c	Fri Nov  9 13:41:41 2001
+++ linux/drivers/isdn/isdn_ppp.c	Thu Jan  3 12:20:10 2002
@@ -586,7 +586,7 @@
 
 	if (is->debug & 0x2)
 		printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",
-				MINOR(file->f_dentry->d_inode->i_rdev));
+				minor(file->f_dentry->d_inode->i_rdev));
 
 	/* just registers wait_queue hook. This doesn't really wait. */
 	poll_wait(file, &is->wq, wait);
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c
--- v2.5.1/linux/drivers/isdn/isdn_tty.c	Fri Nov  9 13:41:41 2001
+++ linux/drivers/isdn/isdn_tty.c	Thu Jan  3 12:20:10 2002
@@ -1019,12 +1019,12 @@
 #ifdef MODEM_PARANOIA_CHECK
 	if (!info) {
 		printk(KERN_WARNING "isdn_tty: null info_struct for (%d, %d) in %s\n",
-		       MAJOR(device), MINOR(device), routine);
+		       major(device), minor(device), routine);
 		return 1;
 	}
 	if (info->magic != ISDN_ASYNC_MAGIC) {
 		printk(KERN_WARNING "isdn_tty: bad magic for modem struct (%d, %d) in %s\n",
-		       MAJOR(device), MINOR(device), routine);
+		       major(device), minor(device), routine);
 		return 1;
 	}
 #endif
@@ -1740,7 +1740,7 @@
 	int retval,
 	 line;
 
-	line = MINOR(tty->device) - tty->driver.minor_start;
+	line = minor(tty->device) - tty->driver.minor_start;
 	if (line < 0 || line > ISDN_MAX_CHANNELS)
 		return -ENODEV;
 	info = &dev->mdm.info[line];
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/isdnloop/isdnloop.h linux/drivers/isdn/isdnloop/isdnloop.h
--- v2.5.1/linux/drivers/isdn/isdnloop/isdnloop.h	Sun Sep 30 12:26:06 2001
+++ linux/drivers/isdn/isdnloop/isdnloop.h	Sun Dec 30 10:31:51 2001
@@ -37,7 +37,6 @@
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/major.h>
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/isdn/sc/includes.h linux/drivers/isdn/sc/includes.h
--- v2.5.1/linux/drivers/isdn/sc/includes.h	Sun Sep 30 12:26:06 2001
+++ linux/drivers/isdn/sc/includes.h	Sun Dec 30 10:31:51 2001
@@ -6,7 +6,6 @@
 
 #include <linux/version.h>
 #include <linux/errno.h>
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c
--- v2.5.1/linux/drivers/macintosh/mac_keyb.c	Tue Sep 18 14:23:14 2001
+++ linux/drivers/macintosh/mac_keyb.c	Tue Dec 25 15:39:20 2001
@@ -256,7 +256,6 @@
 #endif
 
 extern struct kbd_struct kbd_table[];
-extern wait_queue_head_t keypress_wait;
 
 extern void handle_scancode(unsigned char, int);
 
@@ -423,7 +422,6 @@
 	struct tty_struct *tty;
 
 	tty = console_driver.table? console_driver.table[fg_console]: NULL;
-	wake_up(&keypress_wait);
 	if (tty) {
 		tty_insert_flip_char(tty, ch, 0);
 		con_schedule_flip(tty);
diff -u --recursive --new-file v2.5.1/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
--- v2.5.1/linux/drivers/macintosh/macserial.c	Mon Oct 15 13:43:24 2001
+++ linux/drivers/macintosh/macserial.c	Sun Dec 30 10:31:51 2001
@@ -38,7 +38,6 @@
 #include <asm/irq.h>
 #include <asm/prom.h>
 #include <asm/system.h>
-#include <asm/segment.h>
 #include <asm/bitops.h>
 #include <asm/feature.h>
 #include <linux/adb.h>
@@ -2792,30 +2791,6 @@
 	/* Don't disable the transmitter. */
 }
 
-/*
- *	Receive character from the serial port
- */
-static int serial_console_wait_key(struct console *co)
-{
-	struct mac_serial *info = zs_soft + co->index;
-	int           val;
-
-	/* Turn of interrupts and enable the transmitter. */
-	write_zsreg(info->zs_channel, R1, info->curregs[1] & ~INT_ALL_Rx);
-	write_zsreg(info->zs_channel, R3, info->curregs[3] | RxENABLE);
-
-	/* Wait for something in the receive buffer. */
-	while((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0)
-		eieio();
-	val = read_zsdata(info->zs_channel);
-
-	/* Restore the values in the registers. */
-	write_zsreg(info->zs_channel, R1, info->curregs[1]);
-	write_zsreg(info->zs_channel, R3, info->curregs[3]);
-
-	return val;
-}
-
 static kdev_t serial_console_device(struct console *c)
 {
 	return MKDEV(TTY_MAJOR, 64 + c->index);
@@ -3006,7 +2981,6 @@
 	name:		"ttyS",
 	write:		serial_console_write,
 	device:		serial_console_device,
-	wait_key:	serial_console_wait_key,
 	setup:		serial_console_setup,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
diff -u --recursive --new-file v2.5.1/linux/drivers/md/lvm-fs.c linux/drivers/md/lvm-fs.c
--- v2.5.1/linux/drivers/md/lvm-fs.c	Sun Nov 11 10:09:32 2001
+++ linux/drivers/md/lvm-fs.c	Thu Dec 27 08:29:15 2001
@@ -30,6 +30,7 @@
  *    04/10/2001 - corrected devfs_register() call in lvm_init_fs()
  *    11/04/2001 - don't devfs_register("lvm") as user-space always does it
  *    10/05/2001 - show more of PV name in /proc/lvm/global
+ *    16/12/2001 - fix devfs unregister order and prevent duplicate unreg (REG)
  *
  */
 
@@ -64,9 +65,7 @@
 
 static void _show_uuid(const char *src, char *b, char *e);
 
-#if 0
 static devfs_handle_t lvm_devfs_handle;
-#endif
 static devfs_handle_t vg_devfs_handle[MAX_VG];
 static devfs_handle_t ch_devfs_handle[MAX_VG];
 static devfs_handle_t lv_devfs_handle[MAX_LV];
@@ -80,13 +79,11 @@
 void __init lvm_init_fs() {
 	struct proc_dir_entry *pde;
 
-/* User-space has already registered this */
-#if 0
+	/*  Must create device node. Think about "devfs=only" situation  */
 	lvm_devfs_handle = devfs_register(
 		0 , "lvm", 0, LVM_CHAR_MAJOR, 0,
 		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
 		&lvm_chr_fops, NULL);
-#endif
 
 	lvm_proc_dir = create_proc_entry(LVM_DIR, S_IFDIR, &proc_root);
 	if (lvm_proc_dir) {
@@ -98,9 +95,7 @@
 }
 
 void lvm_fin_fs() {
-#if 0
 	devfs_unregister (lvm_devfs_handle);
-#endif
 
 	remove_proc_entry(LVM_GLOBAL, lvm_proc_dir);
 	remove_proc_entry(LVM_VG_SUBDIR, lvm_proc_dir);
@@ -138,7 +133,7 @@
 	int i;
 
 	devfs_unregister(ch_devfs_handle[vg_ptr->vg_number]);
-	devfs_unregister(vg_devfs_handle[vg_ptr->vg_number]);
+	ch_devfs_handle[vg_ptr->vg_number] = NULL;
 
 	/* remove lv's */
 	for(i = 0; i < vg_ptr->lv_max; i++)
@@ -148,6 +143,10 @@
 	for(i = 0; i < vg_ptr->pv_max; i++)
 		if(vg_ptr->pv[i]) lvm_fs_remove_pv(vg_ptr, vg_ptr->pv[i]);
 
+	/* must not remove directory before leaf nodes */
+	devfs_unregister(vg_devfs_handle[vg_ptr->vg_number]);
+	vg_devfs_handle[vg_ptr->vg_number] = NULL;
+
 	if(vg_ptr->vg_dir_pde) {
 		remove_proc_entry(LVM_LV_SUBDIR, vg_ptr->vg_dir_pde);
 		vg_ptr->lv_subdir_pde = NULL;
@@ -189,6 +188,7 @@
 
 void lvm_fs_remove_lv(vg_t *vg_ptr, lv_t *lv) {
 	devfs_unregister(lv_devfs_handle[MINOR(lv->lv_dev)]);
+	lv_devfs_handle[MINOR(lv->lv_dev)] = NULL;
 
 	if(vg_ptr->lv_subdir_pde) {
 		const char *name = _basename(lv->lv_name);
diff -u --recursive --new-file v2.5.1/linux/drivers/md/lvm-snap.c linux/drivers/md/lvm-snap.c
--- v2.5.1/linux/drivers/md/lvm-snap.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/md/lvm-snap.c	Thu Dec 27 08:17:43 2001
@@ -206,20 +206,6 @@
 	return 1;
 }
 
-inline int lvm_get_blksize(kdev_t dev)
-{
-	int correct_size = BLOCK_SIZE, i, major;
-
-	major = MAJOR(dev);
-	if (blksize_size[major])
-	{
-		i = blksize_size[major][MINOR(dev)];
-		if (i)
-			correct_size = i;
-	}
-	return correct_size;
-}
-
 #ifdef DEBUG_SNAPSHOT
 static inline void invalidate_snap_cache(unsigned long start, unsigned long nr,
 					 kdev_t dev)
@@ -256,7 +242,7 @@
 
 	is--;
         blksize_snap =
-               lvm_get_blksize(lv_snap->lv_block_exception[is].rdev_new);
+               block_size(lv_snap->lv_block_exception[is].rdev_new);
         is -= is % (blksize_snap / sizeof(lv_COW_table_disk_t));
 
 	memset(lv_COW_table, 0, blksize_snap);
@@ -347,8 +333,8 @@
 
 	iobuf = lv_snap->lv_iobuf;
 
-	blksize_org = lvm_get_blksize(org_phys_dev);
-	blksize_snap = lvm_get_blksize(snap_phys_dev);
+	blksize_org = block_size(org_phys_dev);
+	blksize_snap = block_size(snap_phys_dev);
 	max_blksize = max(blksize_org, blksize_snap);
 	min_blksize = min(blksize_org, blksize_snap);
 	max_sectors = LVM_MAX_SECTORS * (min_blksize>>9);
@@ -592,7 +578,7 @@
 	snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new;
 	snap_pe_start = lv_snap->lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->lv_chunk_size;
 
-	blksize_snap = lvm_get_blksize(snap_phys_dev);
+	blksize_snap = block_size(snap_phys_dev);
 
         COW_entries_per_block = blksize_snap / sizeof(lv_COW_table_disk_t);
         idx_COW_table = idx % COW_entries_per_pe % COW_entries_per_block;
@@ -640,7 +626,7 @@
 			idx++;
 			snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new;
 			snap_pe_start = lv_snap->lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->lv_chunk_size;
-			blksize_snap = lvm_get_blksize(snap_phys_dev);
+			blksize_snap = block_size(snap_phys_dev);
 			blocks[0] = snap_pe_start >> (blksize_snap >> 10);
 		} else blocks[0]++;
 
diff -u --recursive --new-file v2.5.1/linux/drivers/md/lvm.c linux/drivers/md/lvm.c
--- v2.5.1/linux/drivers/md/lvm.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/md/lvm.c	Mon Dec 31 17:56:19 2001
@@ -179,6 +179,9 @@
  *		   (Jens Axboe)
  *               - Defer writes to an extent that is being moved [JT + AD]
  *    28/05/2001 - implemented missing BLKSSZGET ioctl [AD]
+ *    28/12/2001 - buffer_head -> bio
+ *                 removed huge allocation of a lv_t on stack
+ *                 (Anders Gustafsson)
  *
  */
 
@@ -209,7 +212,6 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/smp_lock.h>
 #include <asm/ioctl.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 
 #ifdef CONFIG_KERNELD
@@ -376,7 +378,6 @@
 	major:		MAJOR_NR,
 	major_name:	LVM_NAME,
 	minor_shift:	0,
-	max_p:		1,
 	part:		lvm_hd_struct,
 	sizes:		lvm_size,
 	nr_real:	MAX_LV,
@@ -1043,7 +1044,7 @@
 
 	memset(&bio,0,sizeof(bio));
 	bio.bi_dev = inode->i_rdev;
-	bio.bi_io_vec.bv_len = lvm_get_blksize(bio.bi_dev);
+	bio.bi_size = lvm_get_blksize(bio.bi_dev); /* NEEDED by bio_sectors */
  	bio.bi_sector = block * bio_sectors(&bio);
 	bio.bi_rw = READ;
 	if ((err=lvm_map(&bio)) < 0)  {
@@ -1119,19 +1120,18 @@
 	return 0;
 }
 
-static int lvm_map(struct bio *bh)
+static int lvm_map(struct bio *bi)
 {
-	int minor = MINOR(bh->bi_dev);
+	int minor = MINOR(bi->bi_dev);
 	ulong index;
 	ulong pe_start;
-	ulong size = bio_sectors(bh);
-	ulong rsector_org = bh->bi_sector;
+	ulong size = bio_sectors(bi);
+	ulong rsector_org = bi->bi_sector;
 	ulong rsector_map;
 	kdev_t rdev_map;
 	vg_t *vg_this = vg[VG_BLK(minor)];
 	lv_t *lv = vg_this->lv[LV_BLK(minor)];
-	int rw = bio_data_dir(bh);
-
+	int rw = bio_rw(bi);
 
 	down_read(&lv->lv_lock);
 	if (!(lv->lv_status & LV_ACTIVE)) {
@@ -1151,7 +1151,7 @@
 
 	P_MAP("%s - lvm_map minor: %d  *rdev: %s  *rsector: %lu  size:%lu\n",
 	      lvm_name, minor,
-	      kdevname(bh->bi_dev),
+	      kdevname(bi->bi_dev),
 	      rsector_org, size);
 
 	if (rsector_org + size > lv->lv_size) {
@@ -1205,7 +1205,7 @@
 	 * we need to queue this request, because this is in the fast path.
 	 */
 	if (rw == WRITE || rw == WRITEA) {
-		if(_defer_extent(bh, rw, rdev_map,
+		if(_defer_extent(bi, rw, rdev_map,
 				 rsector_map, vg_this->pe_size)) {
 
 			up_read(&lv->lv_lock);
@@ -1246,13 +1246,13 @@
  	}
 
  out:
-	bh->bi_dev = rdev_map;
-	bh->bi_sector = rsector_map;
+	bi->bi_dev = rdev_map;
+	bi->bi_sector = rsector_map;
 	up_read(&lv->lv_lock);
 	return 1;
 
  bad:
-	bio_io_error(bh);
+	bio_io_error(bi);
 	up_read(&lv->lv_lock);
 	return -1;
 } /* lvm_map() */
@@ -1436,9 +1436,9 @@
 {
 	int ret = 0;
 	ulong l, ls = 0, p, size;
-	lv_t lv;
 	vg_t *vg_ptr;
 	lv_t **snap_lv_ptr;
+	lv_t *tmplv;
 
 	if ((vg_ptr = kmalloc(sizeof(vg_t),GFP_KERNEL)) == NULL) {
 		printk(KERN_CRIT
@@ -1446,6 +1446,7 @@
 		       lvm_name, __LINE__);
 		return -ENOMEM;
 	}
+
 	/* get the volume group structure */
 	if (copy_from_user(vg_ptr, arg, sizeof(vg_t)) != 0) {
 		P_IOCTL("lvm_do_vg_create ERROR: copy VG ptr %p (%d bytes)\n",
@@ -1454,6 +1455,8 @@
 		return -EFAULT;
 	}
 
+
+
         /* VG_CREATE now uses minor number in VG structure */
         if (minor == -1) minor = vg_ptr->vg_number;
 
@@ -1513,19 +1516,30 @@
 	}
 	memset(snap_lv_ptr, 0, size);
 
+	if ((tmplv = kmalloc(sizeof(lv_t),GFP_KERNEL)) == NULL) {
+		printk(KERN_CRIT
+		       "%s -- VG_CREATE: kmalloc error LV at line %d\n",
+		       lvm_name, __LINE__);
+		vfree(snap_lv_ptr);
+		return -ENOMEM;
+	}
+
 	/* get the logical volume structures */
 	vg_ptr->lv_cur = 0;
 	for (l = 0; l < vg_ptr->lv_max; l++) {
 		lv_t *lvp;
+		
 		/* user space address */
 		if ((lvp = vg_ptr->lv[l]) != NULL) {
-			if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) {
+			if (copy_from_user(tmplv, lvp, sizeof(lv_t)) != 0) {
 				P_IOCTL("ERROR: copying LV ptr %p (%d bytes)\n",
 					lvp, sizeof(lv_t));
 				lvm_do_vg_remove(minor);
+				vfree(snap_lv_ptr);
+				kfree(tmplv);
 				return -EFAULT;
 			}
-			if ( lv.lv_access & LV_SNAPSHOT) {
+			if ( tmplv->lv_access & LV_SNAPSHOT) {
 				snap_lv_ptr[ls] = lvp;
 				vg_ptr->lv[l] = NULL;
 				ls++;
@@ -1533,8 +1547,10 @@
 			}
 			vg_ptr->lv[l] = NULL;
 			/* only create original logical volumes for now */
-			if (lvm_do_lv_create(minor, lv.lv_name, &lv) != 0) {
+			if (lvm_do_lv_create(minor, tmplv->lv_name, tmplv) != 0) {
 				lvm_do_vg_remove(minor);
+				vfree(snap_lv_ptr);
+				kfree(tmplv);
 				return -EFAULT;
 			}
 		}
@@ -1544,18 +1560,22 @@
 	   in place during first path above */
 	for (l = 0; l < ls; l++) {
 		lv_t *lvp = snap_lv_ptr[l];
-		if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) {
+		if (copy_from_user(tmplv, lvp, sizeof(lv_t)) != 0) {
 			lvm_do_vg_remove(minor);
+			vfree(snap_lv_ptr);
+			kfree(tmplv);
 			return -EFAULT;
 		}
-		if (lvm_do_lv_create(minor, lv.lv_name, &lv) != 0) {
+		if (lvm_do_lv_create(minor, tmplv->lv_name, tmplv) != 0) {
 			lvm_do_vg_remove(minor);
+			vfree(snap_lv_ptr);
+			kfree(tmplv);
 			return -EFAULT;
 		}
 	}
 
 	vfree(snap_lv_ptr);
-
+	kfree(tmplv);
 	vg_count++;
 
 
diff -u --recursive --new-file v2.5.1/linux/drivers/md/md.c linux/drivers/md/md.c
--- v2.5.1/linux/drivers/md/md.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/md/md.c	Mon Dec 31 17:56:19 2001
@@ -66,7 +66,7 @@
 
 /*
  * Current RAID-1,4,5 parallel reconstruction 'guaranteed speed limit'
- * is 100 KB/sec, so the extra system load does not show up that much.
+ * is 1000 KB/sec, so the extra system load does not show up that much.
  * Increase it if you want to have more _guaranteed_ speed. Note that
  * the RAID driver will use the maximum available bandwith if the IO
  * subsystem is idle. There is also an 'absolute maximum' reconstruction
@@ -76,8 +76,8 @@
  * you can change it via /proc/sys/dev/raid/speed_limit_min and _max.
  */
 
-static int sysctl_speed_limit_min = 100;
-static int sysctl_speed_limit_max = 100000;
+static int sysctl_speed_limit_min = 1000;
+static int sysctl_speed_limit_max = 200000;
 
 static struct ctl_table_header *raid_table_header;
 
@@ -118,11 +118,9 @@
 	major: MD_MAJOR,
 	major_name: "md",
 	minor_shift: 0,
-	max_p: 1,
 	part: md_hd_struct,
 	sizes: md_size,
 	nr_real: MAX_MD_DEVS,
-	real_devices: NULL,
 	next: NULL,
 	fops: &md_fops,
 };
@@ -469,40 +467,45 @@
 
 static int read_disk_sb(mdk_rdev_t * rdev)
 {
-	int ret = -EINVAL;
-	struct buffer_head *bh = NULL;
-	kdev_t dev = rdev->dev;
-	mdp_super_t *sb;
+	struct address_space *mapping = rdev->bdev->bd_inode->i_mapping;
+	struct page *page;
+	char *p;
 	unsigned long sb_offset;
+	int n = PAGE_CACHE_SIZE / BLOCK_SIZE;
 
 	if (!rdev->sb) {
 		MD_BUG();
-		goto abort;
+		return -EINVAL;
 	}
 
 	/*
 	 * Calculate the position of the superblock,
-	 * it's at the end of the disk
+	 * it's at the end of the disk.
+	 *
+	 * It also happens to be a multiple of 4Kb.
 	 */
 	sb_offset = calc_dev_sboffset(rdev->dev, rdev->mddev, 1);
 	rdev->sb_offset = sb_offset;
-	fsync_dev(dev);
-	set_blocksize (dev, MD_SB_BYTES);
-	bh = bread (dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES);
-
-	if (bh) {
-		sb = (mdp_super_t *) bh->b_data;
-		memcpy (rdev->sb, sb, MD_SB_BYTES);
-	} else {
-		printk(NO_SB,partition_name(rdev->dev));
-		goto abort;
-	}
+	page = read_cache_page(mapping, sb_offset/n,
+			(filler_t *)mapping->a_ops->readpage, NULL);
+	if (IS_ERR(page))
+		goto out;
+	wait_on_page(page);
+	if (!Page_Uptodate(page))
+		goto fail;
+	if (PageError(page))
+		goto fail;
+	p = (char *)page_address(page) + BLOCK_SIZE * (sb_offset % n);
+	memcpy((char*)rdev->sb, p, MD_SB_BYTES);
+	page_cache_release(page);
 	printk(KERN_INFO " [events: %08lx]\n", (unsigned long)rdev->sb->events_lo);
-	ret = 0;
-abort:
-	if (bh)
-		brelse (bh);
-	return ret;
+	return 0;
+
+fail:
+	page_cache_release(page);
+out:
+	printk(NO_SB,partition_name(rdev->dev));
+	return -EINVAL;
 }
 
 static unsigned int calc_sb_csum(mdp_super_t * sb)
@@ -884,15 +887,14 @@
 	return NULL;
 }
 
-#define GETBLK_FAILED KERN_ERR \
-"md: getblk failed for device %s\n"
-
 static int write_disk_sb(mdk_rdev_t * rdev)
 {
-	struct buffer_head *bh;
-	kdev_t dev;
+	struct address_space *mapping = rdev->bdev->bd_inode->i_mapping;
+	struct page *page;
+	unsigned offs;
+	int error;
+	kdev_t dev = rdev->dev;
 	unsigned long sb_offset, size;
-	mdp_super_t *sb;
 
 	if (!rdev->sb) {
 		MD_BUG();
@@ -907,7 +909,6 @@
 		return 1;
 	}
 
-	dev = rdev->dev;
 	sb_offset = calc_dev_sboffset(dev, rdev->mddev, 1);
 	if (rdev->sb_offset != sb_offset) {
 		printk(KERN_INFO "%s's sb offset has changed from %ld to %ld, skipping\n",
@@ -928,26 +929,32 @@
 
 	printk(KERN_INFO "(write) %s's sb offset: %ld\n", partition_name(dev), sb_offset);
 	fsync_dev(dev);
-	set_blocksize(dev, MD_SB_BYTES);
-	bh = getblk(dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES);
-	if (!bh) {
-		printk(GETBLK_FAILED, partition_name(dev));
-		return 1;
-	}
-	memset(bh->b_data,0,bh->b_size);
-	sb = (mdp_super_t *) bh->b_data;
-	memcpy(sb, rdev->sb, MD_SB_BYTES);
-
-	mark_buffer_uptodate(bh, 1);
-	mark_buffer_dirty(bh);
-	ll_rw_block(WRITE, 1, &bh);
-	wait_on_buffer(bh);
-	brelse(bh);
+	page = grab_cache_page(mapping, sb_offset/(PAGE_CACHE_SIZE/BLOCK_SIZE));
+	offs = sb_offset % (PAGE_CACHE_SIZE/BLOCK_SIZE);
+	if (!page)
+		goto fail;
+	error = mapping->a_ops->prepare_write(NULL, page, offs,
+						offs + MD_SB_BYTES);
+	if (error)
+		goto unlock;
+	memcpy((char *)page_address(page) + offs, rdev->sb, MD_SB_BYTES);
+	error = mapping->a_ops->commit_write(NULL, page, offs,
+						offs + MD_SB_BYTES);
+	if (error)
+		goto unlock;
+	UnlockPage(page);
+	wait_on_page(page);
+	page_cache_release(page);
 	fsync_dev(dev);
 skip:
 	return 0;
+unlock:
+	UnlockPage(page);
+	page_cache_release(page);
+fail:
+	printk("md: write_disk_sb failed for device %s\n", partition_name(dev));
+	return 1;
 }
-#undef GETBLK_FAILED
 
 static void set_this_disk(mddev_t *mddev, mdk_rdev_t *rdev)
 {
@@ -3336,7 +3343,7 @@
 int md_do_sync(mddev_t *mddev, mdp_disk_t *spare)
 {
 	mddev_t *mddev2;
-	unsigned int max_sectors, currspeed,
+	unsigned int max_sectors, currspeed = 0,
 		j, window, err, serialize;
 	unsigned long mark[SYNC_MARKS];
 	unsigned long mark_cnt[SYNC_MARKS];
@@ -3376,8 +3383,7 @@
 	max_sectors = mddev->sb->size << 1;
 
 	printk(KERN_INFO "md: syncing RAID array md%d\n", mdidx(mddev));
-	printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed: %d KB/sec/disc.\n",
-						sysctl_speed_limit_min);
+	printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed: %d KB/sec/disc.\n", sysctl_speed_limit_min);
 	printk(KERN_INFO "md: using maximum available idle IO bandwith "
 	       "(but not more than %d KB/sec) for reconstruction.\n",
 	       sysctl_speed_limit_max);
@@ -3409,7 +3415,7 @@
 	for (j = 0; j < max_sectors;) {
 		int sectors;
 
-		sectors = mddev->pers->sync_request(mddev, j);
+		sectors = mddev->pers->sync_request(mddev, j, currspeed < sysctl_speed_limit_min);
 		if (sectors < 0) {
 			err = sectors;
 			goto out;
@@ -4034,4 +4040,4 @@
 EXPORT_SYMBOL(mddev_map);
 EXPORT_SYMBOL(md_check_ordering);
 EXPORT_SYMBOL(get_spare);
-
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.1/linux/drivers/md/raid1.c linux/drivers/md/raid1.c
--- v2.5.1/linux/drivers/md/raid1.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/md/raid1.c	Wed Dec 19 15:18:11 2001
@@ -28,7 +28,6 @@
 #define MD_DRIVER
 #define MD_PERSONALITY
 
-#define MAX_WORK_PER_DISK 128
 /*
  * Number of guaranteed r1bios in case of extreme VM load:
  */
@@ -38,24 +37,6 @@
 static spinlock_t retry_list_lock = SPIN_LOCK_UNLOCKED;
 static LIST_HEAD(retry_list_head);
 
-static inline void check_all_w_bios_empty(r1bio_t *r1_bio)
-{
-	int i;
-
-	return;
-	for (i = 0; i < MD_SB_DISKS; i++)
-		if (r1_bio->write_bios[i])
-			BUG();
-}
-
-static inline void check_all_bios_empty(r1bio_t *r1_bio)
-{
-	return;
-	if (r1_bio->read_bio)
-		BUG();
-	check_all_w_bios_empty(r1_bio);
-}
-
 static void * r1bio_pool_alloc(int gfp_flags, void *data)
 {
 	r1bio_t *r1_bio;
@@ -69,11 +50,11 @@
 
 static void r1bio_pool_free(void *r1_bio, void *data)
 {
-	check_all_bios_empty(r1_bio);
 	kfree(r1_bio);
 }
 
 #define RESYNC_BLOCK_SIZE (64*1024)
+#define RESYNC_SECTORS (RESYNC_BLOCK_SIZE >> 9)
 #define RESYNC_PAGES ((RESYNC_BLOCK_SIZE + PAGE_SIZE-1) / PAGE_SIZE)
 #define RESYNC_WINDOW (2048*1024)
 
@@ -86,7 +67,6 @@
 	int i, j;
 
 	r1_bio = mempool_alloc(conf->r1bio_pool, gfp_flags);
-	check_all_bios_empty(r1_bio);
 
 	bio = bio_alloc(gfp_flags, RESYNC_PAGES);
 	if (!bio)
@@ -131,7 +111,6 @@
 	r1bio_t *r1bio = __r1_bio;
 	struct bio *bio = r1bio->master_bio;
 
-	check_all_bios_empty(r1bio);
 	if (atomic_read(&bio->bi_cnt) != 1)
 		BUG();
 	for (i = 0; i < RESYNC_PAGES; i++) {
@@ -163,13 +142,25 @@
 		}
 		*bio = NULL;
 	}
-	check_all_bios_empty(r1_bio);
 }
 
 static inline void free_r1bio(r1bio_t *r1_bio)
 {
+	unsigned long flags;
+
 	conf_t *conf = mddev_to_conf(r1_bio->mddev);
 
+	/*
+	 * Wake up any possible resync thread that waits for the device
+	 * to go idle.
+	 */
+	spin_lock_irqsave(&conf->resync_lock, flags);
+	if (!--conf->nr_pending) {
+		wake_up(&conf->wait_idle);
+		wake_up(&conf->wait_resume);
+	}
+	spin_unlock_irqrestore(&conf->resync_lock, flags);
+
 	put_all_bios(conf, r1_bio);
 	mempool_free(r1_bio, conf->r1bio_pool);
 }
@@ -178,7 +169,14 @@
 {
 	conf_t *conf = mddev_to_conf(r1_bio->mddev);
 	struct bio *bio = r1_bio->master_bio;
+	unsigned long flags;
 
+	spin_lock_irqsave(&conf->resync_lock, flags);
+	if (!--conf->nr_pending) {
+		wake_up(&conf->wait_idle);
+		wake_up(&conf->wait_resume);
+	}
+	spin_unlock_irqrestore(&conf->resync_lock, flags);
 	/*
 	 * undo any possible partial request fixup magic:
 	 */
@@ -222,37 +220,6 @@
 	md_wakeup_thread(conf->thread);
 }
 
-
-static void inline raid_request_done(unsigned long sector, conf_t *conf, int phase)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&conf->segment_lock, flags);
-	if (sector < conf->start_active)
-		conf->cnt_done--;
-	else if (sector >= conf->start_future && conf->phase == phase)
-		conf->cnt_future--;
-	else if (!--conf->cnt_pending)
-		wake_up(&conf->wait_ready);
-
-	spin_unlock_irqrestore(&conf->segment_lock, flags);
-}
-
-static void inline sync_request_done(sector_t sector, conf_t *conf)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&conf->segment_lock, flags);
-	if (sector >= conf->start_ready)
-		--conf->cnt_ready;
-	else if (sector >= conf->start_active) {
-		if (!--conf->cnt_active) {
-			conf->start_active = conf->start_ready;
-			wake_up(&conf->wait_done);
-		}
-	}
-	spin_unlock_irqrestore(&conf->segment_lock, flags);
-}
-
 /*
  * raid_end_bio_io() is called when we have finished servicing a mirrored
  * operation and are ready to return a success/failure code to the buffer
@@ -262,19 +229,29 @@
 {
 	struct bio *bio = r1_bio->master_bio;
 
-	raid_request_done(bio->bi_sector, mddev_to_conf(r1_bio->mddev),
-			test_bit(R1BIO_SyncPhase, &r1_bio->state));
-
 	bio_endio(bio, uptodate, nr_sectors);
 	free_r1bio(r1_bio);
 
 	return 0;
 }
 
+/*
+ * Update disk head position estimator based on IRQ completion info.
+ */
+static void inline update_head_pos(int disk, r1bio_t *r1_bio)
+{
+	conf_t *conf = mddev_to_conf(r1_bio->mddev);
+
+	conf->mirrors[disk].head_position =
+		r1_bio->sector + (r1_bio->master_bio->bi_size >> 9);
+	atomic_dec(&conf->mirrors[disk].nr_pending);
+}
+
 static int end_request(struct bio *bio, int nr_sectors)
 {
 	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
+	int i;
 
 	/*
 	 * this branch is our 'one mirror IO has finished' event handler:
@@ -287,20 +264,16 @@
 		 * we will return a good error code for to the higher
 		 * levels even if IO on some other mirrored buffer fails.
 		 *
-		 * The 'master' represents the complex operation to
+		 * The 'master' represents the composite IO operation to
 		 * user-side. So if something waits for IO, then it will
 		 * wait for the 'master' bio.
 		 */
 		set_bit(R1BIO_Uptodate, &r1_bio->state);
 
-	/*
-	 * We split up the read and write side, imho they are
-	 * conceptually different.
-	 */
-
 	if ((r1_bio->cmd == READ) || (r1_bio->cmd == READA)) {
 		if (!r1_bio->read_bio)
 			BUG();
+		update_head_pos(r1_bio->read_disk, r1_bio);
 		/*
 		 * we have only one bio on the read side
 		 */
@@ -322,6 +295,14 @@
 	/*
 	 * WRITE:
 	 *
+	 * First, find the disk this bio belongs to.
+	 */
+	for (i = 0; i < MD_SB_DISKS; i++)
+		if (r1_bio->write_bios[i] == bio) {
+			update_head_pos(i, r1_bio);
+			break;
+		}
+	/*
 	 * Let's see if all mirrored write operations have finished
 	 * already.
 	 */
@@ -332,44 +313,49 @@
 
 /*
  * This routine returns the disk from which the requested read should
- * be done. It bookkeeps the last read position for every disk
- * in array and when new read requests come, the disk which last
- * position is nearest to the request, is chosen.
+ * be done. There is a per-array 'next expected sequential IO' sector
+ * number - if this matches on the next IO then we use the last disk.
+ * There is also a per-disk 'last know head position' sector that is
+ * maintained from IRQ contexts, both the normal and the resync IO
+ * completion handlers update this position correctly. If there is no
+ * perfect sequential match then we pick the disk whose head is closest.
  *
- * TODO: now if there are 2 mirrors in the same 2 devices, performance
- * degrades dramatically because position is mirror, not device based.
- * This should be changed to be device based. Also atomic sequential
- * reads should be somehow balanced.
+ * If there are 2 mirrors in the same 2 devices, performance degrades
+ * because position is mirror, not device based.
  */
-
 static int read_balance(conf_t *conf, struct bio *bio, r1bio_t *r1_bio)
 {
-	const int sectors = bio->bi_size >> 9;
 	const unsigned long this_sector = r1_bio->sector;
-	unsigned long new_distance, current_distance;
 	int new_disk = conf->last_used, disk = new_disk;
+	const int sectors = bio->bi_size >> 9;
+	sector_t new_distance, current_distance;
 
 	/*
-	 * Check if it is sane at all to balance
-	 */
-
-	if (conf->resync_mirrors)
+	 * Check if it if we can balance. We can balance on the whole
+	 * device if no resync is going on, or below the resync window.
+	 * We take the first readable disk when above the resync window.
+	 */
+	if (conf->resync_mirrors && (this_sector + sectors >= conf->next_resync)) {
+		/* make sure that disk is operational */
+		new_disk = 0;
+		while (!conf->mirrors[new_disk].operational || conf->mirrors[new_disk].write_only) {
+			new_disk++;
+			if (new_disk == conf->raid_disks) {
+				new_disk = 0;
+				break;
+			}
+		}
 		goto rb_out;
+	}
 
 
-	/* make sure that disk is operational */
-	while( !conf->mirrors[new_disk].operational) {
-		if (new_disk <= 0) new_disk = conf->raid_disks;
+	/* make sure the disk is operational */
+	while (!conf->mirrors[new_disk].operational) {
+		if (new_disk <= 0)
+			new_disk = conf->raid_disks;
 		new_disk--;
 		if (new_disk == disk) {
-			/*
-			 * This means no working disk was found
-			 * Nothing much to do, lets not change anything
-			 * and hope for the best...
-			 */
-
 			new_disk = conf->last_used;
-
 			goto rb_out;
 		}
 	}
@@ -377,36 +363,16 @@
 	/* now disk == new_disk == starting point for search */
 
 	/*
-	 * Don't touch anything for sequential reads.
+	 * Don't change to another disk for sequential reads:
 	 */
-	if (this_sector == conf->mirrors[new_disk].head_position)
+	if (conf->next_seq_sect == this_sector)
 		goto rb_out;
-
-	/*
-	 * If reads have been done only on a single disk
-	 * for a time, lets give another disk a change.
-	 * This is for kicking those idling disks so that
-	 * they would find work near some hotspot.
-	 */
-	if (conf->sect_count >= conf->mirrors[new_disk].sect_limit) {
-		conf->sect_count = 0;
-
-		do {
-			if (new_disk <= 0)
-				new_disk = conf->raid_disks;
-			new_disk--;
-			if (new_disk == disk)
-				break;
-		} while ((conf->mirrors[new_disk].write_only) ||
-			(!conf->mirrors[new_disk].operational));
-
+	if (this_sector == conf->mirrors[new_disk].head_position)
 		goto rb_out;
-	}
 
-	current_distance = abs(this_sector -
-				conf->mirrors[disk].head_position);
+	current_distance = abs(this_sector - conf->mirrors[disk].head_position);
 
-	/* Find the disk which is closest */
+	/* Find the disk whose head is closest */
 
 	do {
 		if (disk <= 0)
@@ -417,44 +383,56 @@
 				(!conf->mirrors[disk].operational))
 			continue;
 
-		new_distance = abs(this_sector -
-					conf->mirrors[disk].head_position);
-
+		if (!atomic_read(&conf->mirrors[disk].nr_pending)) {
+			new_disk = disk;
+			break;
+		}
+		new_distance = abs(this_sector - conf->mirrors[disk].head_position);
 		if (new_distance < current_distance) {
-			conf->sect_count = 0;
 			current_distance = new_distance;
 			new_disk = disk;
 		}
 	} while (disk != conf->last_used);
 
 rb_out:
-	conf->mirrors[new_disk].head_position = this_sector + sectors;
+	r1_bio->read_disk = new_disk;
+	conf->next_seq_sect = this_sector + sectors;
 
 	conf->last_used = new_disk;
-	conf->sect_count += sectors;
 
 	return new_disk;
 }
 
 /*
- * Wait if the reconstruction state machine puts up a bar for
- * new requests in this sector range:
+ * Throttle resync depth, so that we can both get proper overlapping of
+ * requests, but are still able to handle normal requests quickly.
  */
-static inline void new_request(conf_t *conf, r1bio_t *r1_bio)
+#define RESYNC_DEPTH 32
+
+static void device_barrier(conf_t *conf, sector_t sect)
 {
-	spin_lock_irq(&conf->segment_lock);
-	wait_event_lock_irq(conf->wait_done,
-			r1_bio->sector < conf->start_active ||
-			r1_bio->sector >= conf->start_future,
-			conf->segment_lock);
-	if (r1_bio->sector < conf->start_active)
-		conf->cnt_done++;
-	else {
-		conf->cnt_future++;
-		if (conf->phase)
-			set_bit(R1BIO_SyncPhase, &r1_bio->state);
+	spin_lock_irq(&conf->resync_lock);
+	wait_event_lock_irq(conf->wait_idle, !waitqueue_active(&conf->wait_resume), conf->resync_lock);
+	
+	if (!conf->barrier++) {
+		wait_event_lock_irq(conf->wait_idle, !conf->nr_pending, conf->resync_lock);
+		if (conf->nr_pending)
+			BUG();
 	}
-	spin_unlock_irq(&conf->segment_lock);
+	wait_event_lock_irq(conf->wait_resume, conf->barrier < RESYNC_DEPTH, conf->resync_lock);
+	conf->next_resync = sect;
+	spin_unlock_irq(&conf->resync_lock);
+}
+
+static void resume_device(conf_t *conf)
+{
+	spin_lock_irq(&conf->resync_lock);
+	if (!conf->barrier)
+		BUG();
+	--conf->barrier;
+	wake_up(&conf->wait_resume);
+	wake_up(&conf->wait_idle);
+	spin_unlock_irq(&conf->resync_lock);
 }
 
 static int make_request(mddev_t *mddev, int rw, struct bio * bio)
@@ -466,6 +444,16 @@
 	int i, sum_bios = 0, disks = MD_SB_DISKS;
 
 	/*
+	 * Register the new request and wait if the reconstruction
+	 * thread has put up a bar for new requests.
+	 * Continue immediately if no resync is active currently.
+	 */
+	spin_lock_irq(&conf->resync_lock);
+	wait_event_lock_irq(conf->wait_resume, !conf->barrier, conf->resync_lock);
+	conf->nr_pending++;
+	spin_unlock_irq(&conf->resync_lock);
+
+	/*
 	 * make_request() can abort the operation when READA is being
 	 * used and no empty request is available.
 	 *
@@ -475,7 +463,6 @@
 		rw = READ;
 
 	r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO);
-	check_all_bios_empty(r1_bio);
 
 	r1_bio->master_bio = bio;
 
@@ -483,8 +470,6 @@
 	r1_bio->sector = bio->bi_sector;
 	r1_bio->cmd = rw;
 
-	new_request(conf, r1_bio);
-
 	if (rw == READ) {
 		/*
 		 * read balancing logic:
@@ -503,15 +488,13 @@
 		read_bio->bi_private = r1_bio;
 
 		generic_make_request(read_bio);
+		atomic_inc(&conf->mirrors[r1_bio->read_disk].nr_pending);
 		return 0;
 	}
 
 	/*
 	 * WRITE:
 	 */
-
-	check_all_w_bios_empty(r1_bio);
-
 	for (i = 0; i < disks; i++) {
 		struct bio *mbio;
 		if (!conf->mirrors[i].operational)
@@ -542,14 +525,13 @@
 
 	/*
 	 * We have to be a bit careful about the semaphore above, thats
-	 * why we start the requests separately. Since kmalloc() could
-	 * fail, sleep and make_request() can sleep too, this is the
-	 * safer solution. Imagine, end_request decreasing the semaphore
-	 * before we could have set it up ... We could play tricks with
-	 * the semaphore (presetting it and correcting at the end if
-	 * sum_bios is not 'n' but we have to do end_request by hand if
-	 * all requests finish until we had a chance to set up the
-	 * semaphore correctly ... lots of races).
+	 * why we start the requests separately. Since generic_make_request()
+	 * can sleep, this is the safer solution. Imagine, end_request
+	 * decreasing the semaphore before we could have set it up ...
+	 * We could play tricks with the semaphore (presetting it and
+	 * correcting at the end if sum_bios is not 'n' but we have to
+	 * do end_request by hand if all requests finish until we had a
+	 * chance to set up the semaphore correctly ... lots of races).
 	 */
 	for (i = 0; i < disks; i++) {
 		struct bio *mbio;
@@ -558,6 +540,7 @@
 			continue;
 
 		generic_make_request(mbio);
+		atomic_inc(&conf->mirrors[i].nr_pending);
 	}
 	return 0;
 }
@@ -610,8 +593,7 @@
 	md_wakeup_thread(conf->thread);
 	if (!mirror->write_only)
 		conf->working_disks--;
-	printk(DISK_FAILED, partition_name(mirror->dev),
-				conf->working_disks);
+	printk(DISK_FAILED, partition_name(mirror->dev), conf->working_disks);
 }
 
 static int error(mddev_t *mddev, kdev_t dev)
@@ -644,12 +626,6 @@
 	return 0;
 }
 
-#undef LAST_DISK
-#undef NO_SPARE_DISK
-#undef DISK_FAILED
-#undef START_SYNCING
-
-
 static void print_conf(conf_t *conf)
 {
 	int i;
@@ -674,29 +650,13 @@
 
 static void close_sync(conf_t *conf)
 {
-	mddev_t *mddev = conf->mddev;
-	/*
-	 * If reconstruction was interrupted, we need to close the "active"
-	 * and "pending" holes.
-	 * we know that there are no active rebuild requests,
-	 * os cnt_active == cnt_ready == 0
-	 */
-	spin_lock_irq(&conf->segment_lock);
-	conf->start_active = conf->start_pending;
-	conf->start_ready = conf->start_pending;
-	wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending, conf->segment_lock);
-	conf->start_active = conf->start_ready = conf->start_pending = conf->start_future;
-	conf->start_future = mddev->sb->size+1;
-	conf->cnt_pending = conf->cnt_future;
-	conf->cnt_future = 0;
-	conf->phase = conf->phase ^1;
-	wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending, conf->segment_lock);
-	conf->start_active = conf->start_ready = conf->start_pending = conf->start_future = 0;
-	conf->phase = 0;
-	conf->cnt_future = conf->cnt_done;;
-	conf->cnt_done = 0;
-	spin_unlock_irq(&conf->segment_lock);
-	wake_up(&conf->wait_done);
+	spin_lock_irq(&conf->resync_lock);
+	wait_event_lock_irq(conf->wait_resume, !conf->barrier, conf->resync_lock);
+	spin_unlock_irq(&conf->resync_lock);
+
+	if (conf->barrier) BUG();
+	if (waitqueue_active(&conf->wait_idle)) BUG();
+	if (waitqueue_active(&conf->wait_resume)) BUG();
 }
 
 static int diskop(mddev_t *mddev, mdp_disk_t **d, int state)
@@ -975,9 +935,9 @@
 	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
 
-	check_all_w_bios_empty(r1_bio);
 	if (r1_bio->read_bio != bio)
 		BUG();
+	update_head_pos(r1_bio->read_disk, r1_bio);
 	/*
 	 * we have read a block, now it needs to be re-written,
 	 * or re-read if the read failed.
@@ -997,13 +957,21 @@
 	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
 	mddev_t *mddev = r1_bio->mddev;
+	int i;
 
 	if (!uptodate)
 		md_error(mddev, bio->bi_dev);
 
+	for (i = 0; i < MD_SB_DISKS; i++)
+		if (r1_bio->write_bios[i] == bio) {
+			update_head_pos(i, r1_bio);
+			break;
+		}
+
 	if (atomic_dec_and_test(&r1_bio->remaining)) {
-		sync_request_done(r1_bio->sector, mddev_to_conf(mddev));
+		conf_t *conf = mddev_to_conf(mddev);
 		md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, uptodate);
+		resume_device(conf);
 		put_buf(r1_bio);
 	}
 	return 0;
@@ -1029,11 +997,11 @@
 		 */
 		printk(IO_ERROR, partition_name(bio->bi_dev), r1_bio->sector);
 		md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, 0);
+		resume_device(conf);
+		put_buf(r1_bio);
 		return;
 	}
 
-	check_all_w_bios_empty(r1_bio);
-
 	for (i = 0; i < disks ; i++) {
 		if (!conf->mirrors[i].operational)
 			continue;
@@ -1071,8 +1039,8 @@
 		 * must be done
 		 */
 		printk(IO_ERROR, partition_name(bio->bi_dev), r1_bio->sector);
-		sync_request_done(r1_bio->sector, conf);
 		md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, 0);
+		resume_device(conf);
 		put_buf(r1_bio);
 		return;
 	}
@@ -1083,6 +1051,7 @@
 
 		md_sync_acct(mbio->bi_dev, mbio->bi_size >> 9);
 		generic_make_request(mbio);
+		atomic_inc(&conf->mirrors[i].nr_pending);
 	}
 }
 
@@ -1101,6 +1070,7 @@
 	struct bio *bio;
 	unsigned long flags;
 	mddev_t *mddev;
+	conf_t *conf;
 	kdev_t dev;
 
 
@@ -1111,9 +1081,9 @@
 		r1_bio = list_entry(head->prev, r1bio_t, retry_list);
 		list_del(head->prev);
 		spin_unlock_irqrestore(&retry_list_lock, flags);
-		check_all_w_bios_empty(r1_bio);
 
 		mddev = r1_bio->mddev;
+		conf = mddev_to_conf(mddev);
 		if (mddev->sb_dirty) {
 			printk(KERN_INFO "raid1: dirty sb detected, updating.\n");
 			mddev->sb_dirty = 0;
@@ -1139,13 +1109,12 @@
 			bio->bi_rw = r1_bio->cmd;
 
 			generic_make_request(bio);
+			atomic_inc(&conf->mirrors[r1_bio->read_disk].nr_pending);
 			break;
 		}
 	}
 	spin_unlock_irqrestore(&retry_list_lock, flags);
 }
-#undef IO_ERROR
-#undef REDIRECT_SECTOR
 
 /*
  * Private kernel thread to reconstruct mirrors after an unclean
@@ -1177,101 +1146,27 @@
 {
 	int buffs;
 
-	conf->start_active = 0;
-	conf->start_ready = 0;
-	conf->start_pending = 0;
-	conf->start_future = 0;
-	conf->phase = 0;
-
 	buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE;
 	if (conf->r1buf_pool)
 		BUG();
 	conf->r1buf_pool = mempool_create(buffs, r1buf_pool_alloc, r1buf_pool_free, conf);
 	if (!conf->r1buf_pool)
 		return -ENOMEM;
-	conf->window = 2048;
-	conf->cnt_future += conf->cnt_done+conf->cnt_pending;
-	conf->cnt_done = conf->cnt_pending = 0;
-	if (conf->cnt_ready || conf->cnt_active)
-		MD_BUG();
+	conf->next_resync = 0;
 	return 0;
 }
 
-static void wait_sync_pending(conf_t *conf, sector_t sector_nr)
-{
-	spin_lock_irq(&conf->segment_lock);
-	while (sector_nr >= conf->start_pending) {
-//		printk("wait .. sect=%lu start_active=%d ready=%d pending=%d future=%d, cnt_done=%d active=%d ready=%d pending=%d future=%d\n", sector_nr, conf->start_active, conf->start_ready, conf->start_pending, conf->start_future, conf->cnt_done, conf->cnt_active, conf->cnt_ready, conf->cnt_pending, conf->cnt_future);
-		wait_event_lock_irq(conf->wait_done, !conf->cnt_active,
-					conf->segment_lock);
-		wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending,
-					conf->segment_lock);
-		conf->start_active = conf->start_ready;
-		conf->start_ready = conf->start_pending;
-		conf->start_pending = conf->start_future;
-		conf->start_future = conf->start_future+conf->window;
-
-		// Note: falling off the end is not a problem
-		conf->phase = conf->phase ^1;
-		conf->cnt_active = conf->cnt_ready;
-		conf->cnt_ready = 0;
-		conf->cnt_pending = conf->cnt_future;
-		conf->cnt_future = 0;
-		wake_up(&conf->wait_done);
-	}
-	conf->cnt_ready++;
-	spin_unlock_irq(&conf->segment_lock);
-}
-
 /*
  * perform a "sync" on one "block"
  *
  * We need to make sure that no normal I/O request - particularly write
  * requests - conflict with active sync requests.
- * This is achieved by conceptually dividing the block space into a
- * number of sections:
- *  DONE: 0 .. a-1     These blocks are in-sync
- *  ACTIVE: a.. b-1    These blocks may have active sync requests, but
- *                     no normal IO requests
- *  READY: b .. c-1    These blocks have no normal IO requests - sync
- *                     request may be happening
- *  PENDING: c .. d-1  These blocks may have IO requests, but no new
- *                     ones will be added
- *  FUTURE:  d .. end  These blocks are not to be considered yet. IO may
- *                     be happening, but not sync
- *
- * We keep a
- *   phase    which flips (0 or 1) each time d moves and
- * a count of:
- *   z =  active io requests in FUTURE since d moved - marked with
- *        current phase
- *   y =  active io requests in FUTURE before d moved, or PENDING -
- *        marked with previous phase
- *   x =  active sync requests in READY
- *   w =  active sync requests in ACTIVE
- *   v =  active io requests in DONE
  *
- * Normally, a=b=c=d=0 and z= active io requests
- *   or a=b=c=d=END and v= active io requests
- * Allowed changes to a,b,c,d:
- * A:  c==d &&  y==0 -> d+=window, y=z, z=0, phase=!phase
- * B:  y==0 -> c=d
- * C:   b=c, w+=x, x=0
- * D:  w==0 -> a=b
- * E: a==b==c==d==end -> a=b=c=d=0, z=v, v=0
- *
- * At start of sync we apply A.
- * When y reaches 0, we apply B then A then being sync requests
- * When sync point reaches c-1, we wait for y==0, and W==0, and
- * then apply apply B then A then D then C.
- * Finally, we apply E
- *
- * The sync request simply issues a "read" against a working drive
- * This is marked so that on completion the raid1d thread is woken to
- * issue suitable write requests
+ * This is achieved by tracking pending requests and a 'barrier' concept
+ * that can be installed to exclude normal IO requests.
  */
 
-static int sync_request(mddev_t *mddev, sector_t sector_nr)
+static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster)
 {
 	conf_t *conf = mddev_to_conf(mddev);
 	mirror_info_t *mirror;
@@ -1283,8 +1178,13 @@
 	if (!sector_nr)
 		if (init_resync(conf))
 			return -ENOMEM;
-
-	wait_sync_pending(conf, sector_nr);
+	/*
+	 * If there is non-resync activity waiting for us then
+	 * put in a delay to throttle resync.
+	 */
+	if (!go_faster && waitqueue_active(&conf->wait_resume))
+		schedule_timeout(HZ);
+	device_barrier(conf, sector_nr + RESYNC_SECTORS);
 
 	/*
 	 * If reconstructing, and >1 working disc,
@@ -1302,10 +1202,13 @@
 	}
 	conf->last_used = disk;
 
-	mirror = conf->mirrors+conf->last_used;
+	mirror = conf->mirrors + conf->last_used;
 
 	r1_bio = mempool_alloc(conf->r1buf_pool, GFP_NOIO);
-	check_all_bios_empty(r1_bio);
+
+	spin_lock_irq(&conf->resync_lock);
+	conf->nr_pending++;
+	spin_unlock_irq(&conf->resync_lock);
 
 	r1_bio->mddev = mddev;
 	r1_bio->sector = sector_nr;
@@ -1344,6 +1247,7 @@
 	md_sync_acct(read_bio->bi_dev, nr_sectors);
 
 	generic_make_request(read_bio);
+	atomic_inc(&conf->mirrors[conf->last_used].nr_pending);
 
 	return nr_sectors;
 }
@@ -1447,7 +1351,6 @@
 			disk->number = descriptor->number;
 			disk->raid_disk = disk_idx;
 			disk->dev = rdev->dev;
-			disk->sect_limit = MAX_WORK_PER_DISK;
 			disk->operational = 0;
 			disk->write_only = 0;
 			disk->spare = 0;
@@ -1479,7 +1382,6 @@
 			disk->number = descriptor->number;
 			disk->raid_disk = disk_idx;
 			disk->dev = rdev->dev;
-			disk->sect_limit = MAX_WORK_PER_DISK;
 			disk->operational = 1;
 			disk->write_only = 0;
 			disk->spare = 0;
@@ -1494,7 +1396,6 @@
 			disk->number = descriptor->number;
 			disk->raid_disk = disk_idx;
 			disk->dev = rdev->dev;
-			disk->sect_limit = MAX_WORK_PER_DISK;
 			disk->operational = 0;
 			disk->write_only = 0;
 			disk->spare = 1;
@@ -1507,9 +1408,9 @@
 	conf->mddev = mddev;
 	conf->device_lock = SPIN_LOCK_UNLOCKED;
 
-	conf->segment_lock = SPIN_LOCK_UNLOCKED;
-	init_waitqueue_head(&conf->wait_done);
-	init_waitqueue_head(&conf->wait_ready);
+	conf->resync_lock = SPIN_LOCK_UNLOCKED;
+	init_waitqueue_head(&conf->wait_idle);
+	init_waitqueue_head(&conf->wait_resume);
 
 	if (!conf->working_disks) {
 		printk(NONE_OPERATIONAL, mdidx(mddev));
@@ -1610,17 +1511,6 @@
 	MOD_DEC_USE_COUNT;
 	return -EIO;
 }
-
-#undef INVALID_LEVEL
-#undef NO_SB
-#undef ERRORS
-#undef NOT_IN_SYNC
-#undef INCONSISTENT
-#undef ALREADY_RUNNING
-#undef OPERATIONAL
-#undef SPARE
-#undef NONE_OPERATIONAL
-#undef ARRAY_IS_ACTIVE
 
 static int stop_resync(mddev_t *mddev)
 {
diff -u --recursive --new-file v2.5.1/linux/drivers/md/raid5.c linux/drivers/md/raid5.c
--- v2.5.1/linux/drivers/md/raid5.c	Wed Oct 17 14:21:00 2001
+++ linux/drivers/md/raid5.c	Thu Dec 27 08:17:43 2001
@@ -1226,23 +1226,6 @@
 	return 0;
 }
 
-/*
- * Determine correct block size for this device.
- */
-unsigned int device_bsize (kdev_t dev)
-{
-	unsigned int i, correct_size;
-
-	correct_size = BLOCK_SIZE;
-	if (blksize_size[MAJOR(dev)]) {
-		i = blksize_size[MAJOR(dev)][MINOR(dev)];
-		if (i)
-			correct_size = i;
-	}
-
-	return correct_size;
-}
-
 static int raid5_sync_request (mddev_t *mddev, unsigned long sector_nr)
 {
 	raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
diff -u --recursive --new-file v2.5.1/linux/drivers/media/video/adv7175.c linux/drivers/media/video/adv7175.c
--- v2.5.1/linux/drivers/media/video/adv7175.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/media/video/adv7175.c	Sun Dec 30 10:31:51 2001
@@ -38,7 +38,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <linux/types.h>
 #include <linux/wrapper.h>
 
diff -u --recursive --new-file v2.5.1/linux/drivers/media/video/bt856.c linux/drivers/media/video/bt856.c
--- v2.5.1/linux/drivers/media/video/bt856.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/media/video/bt856.c	Sun Dec 30 10:31:51 2001
@@ -40,7 +40,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <linux/types.h>
 #include <linux/wrapper.h>
 
diff -u --recursive --new-file v2.5.1/linux/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c
--- v2.5.1/linux/drivers/media/video/bttv-driver.c	Wed Oct 17 14:19:20 2001
+++ linux/drivers/media/video/bttv-driver.c	Sun Dec 30 10:31:51 2001
@@ -37,7 +37,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <linux/types.h>
 #include <linux/wrapper.h>
 #include <linux/interrupt.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/media/video/cpia.c linux/drivers/media/video/cpia.c
--- v2.5.1/linux/drivers/media/video/cpia.c	Thu Oct 25 13:53:47 2001
+++ linux/drivers/media/video/cpia.c	Thu Jan  3 12:20:10 2002
@@ -2386,7 +2386,7 @@
 		goto_high_power(cam);
 		do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
 		if (goto_low_power(cam))
-			return -NODEV;
+			return -ENODEV;
 	}
 	
 	/* procedure described in developer's guide p3-28 */
diff -u --recursive --new-file v2.5.1/linux/drivers/media/video/saa7185.c linux/drivers/media/video/saa7185.c
--- v2.5.1/linux/drivers/media/video/saa7185.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/media/video/saa7185.c	Sun Dec 30 10:31:51 2001
@@ -36,7 +36,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <linux/types.h>
 #include <linux/wrapper.h>
 
diff -u --recursive --new-file v2.5.1/linux/drivers/media/video/stradis.c linux/drivers/media/video/stradis.c
--- v2.5.1/linux/drivers/media/video/stradis.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/media/video/stradis.c	Sun Dec 30 10:31:51 2001
@@ -37,7 +37,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <asm/types.h>
 #include <linux/types.h>
 #include <linux/wrapper.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/media/video/videodev.c linux/drivers/media/video/videodev.c
--- v2.5.1/linux/drivers/media/video/videodev.c	Thu Oct 11 09:14:32 2001
+++ linux/drivers/media/video/videodev.c	Tue Jan  1 18:55:00 2002
@@ -70,7 +70,7 @@
 static ssize_t video_read(struct file *file,
 	char *buf, size_t count, loff_t *ppos)
 {
-	struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
+	struct video_device *vfl=video_device[minor(file->f_dentry->d_inode->i_rdev)];
 	if(vfl->read)
 		return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK);
 	else
@@ -86,7 +86,7 @@
 static ssize_t video_write(struct file *file, const char *buf, 
 	size_t count, loff_t *ppos)
 {
-	struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
+	struct video_device *vfl=video_device[minor(file->f_dentry->d_inode->i_rdev)];
 	if(vfl->write)
 		return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK);
 	else
@@ -100,7 +100,7 @@
 
 static unsigned int video_poll(struct file *file, poll_table * wait)
 {
-	struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
+	struct video_device *vfl=video_device[minor(file->f_dentry->d_inode->i_rdev)];
 	if(vfl->poll)
 		return vfl->poll(vfl, file, wait);
 	else
@@ -114,7 +114,7 @@
 
 static int video_open(struct inode *inode, struct file *file)
 {
-	unsigned int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	int err, retval = 0;
 	struct video_device *vfl;
 	
@@ -170,7 +170,7 @@
 {
 	struct video_device *vfl;
 	lock_kernel();
-	vfl=video_device[MINOR(inode->i_rdev)];
+	vfl=video_device[minor(inode->i_rdev)];
 	if(vfl->close)
 		vfl->close(vfl);
 	vfl->busy=0;
@@ -183,7 +183,7 @@
 static int video_ioctl(struct inode *inode, struct file *file,
 	unsigned int cmd, unsigned long arg)
 {
-	struct video_device *vfl=video_device[MINOR(inode->i_rdev)];
+	struct video_device *vfl=video_device[minor(inode->i_rdev)];
 	int err=vfl->ioctl(vfl, cmd, (void *)arg);
 
 	if(err!=-ENOIOCTLCMD)
@@ -203,7 +203,7 @@
 int video_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	int ret = -EINVAL;
-	struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
+	struct video_device *vfl=video_device[minor(file->f_dentry->d_inode->i_rdev)];
 	if(vfl->mmap) {
 		lock_kernel();
 		ret = vfl->mmap(vfl, (char *)vma->vm_start, 
diff -u --recursive --new-file v2.5.1/linux/drivers/media/video/zr36067.c linux/drivers/media/video/zr36067.c
--- v2.5.1/linux/drivers/media/video/zr36067.c	Fri Nov  9 14:01:22 2001
+++ linux/drivers/media/video/zr36067.c	Sun Dec 30 10:31:51 2001
@@ -58,7 +58,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <linux/types.h>
 #include <linux/wrapper.h>
 
diff -u --recursive --new-file v2.5.1/linux/drivers/media/video/zr36120.c linux/drivers/media/video/zr36120.c
--- v2.5.1/linux/drivers/media/video/zr36120.c	Fri Nov  9 14:01:22 2001
+++ linux/drivers/media/video/zr36120.c	Sun Dec 30 10:31:51 2001
@@ -35,7 +35,6 @@
 #include <asm/page.h>
 #include <linux/sched.h>
 #include <linux/video_decoder.h>
-#include <asm/segment.h>
 
 #include <linux/version.h>
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/message/i2o/i2o_block.c linux/drivers/message/i2o/i2o_block.c
--- v2.5.1/linux/drivers/message/i2o/i2o_block.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/message/i2o/i2o_block.c	Mon Dec 31 17:56:19 2001
@@ -1778,7 +1778,6 @@
 	major:		MAJOR_NR,
 	major_name:	"i2o/hd",
 	minor_shift:	4,
-	max_p:		1<<4,
 	part:		i2ob,
 	sizes:		i2ob_sizes,
 	nr_real:	MAX_I2OB,
diff -u --recursive --new-file v2.5.1/linux/drivers/mtd/devices/blkmtd.c linux/drivers/mtd/devices/blkmtd.c
--- v2.5.1/linux/drivers/mtd/devices/blkmtd.c	Fri Oct  5 12:06:51 2001
+++ linux/drivers/mtd/devices/blkmtd.c	Thu Dec 27 08:17:43 2001
@@ -63,7 +63,6 @@
 #define CONFIG_MTD_BLKDEV_ERASESIZE 128
 #define VERSION "1.1"
 extern int *blk_size[];
-extern int *blksize_size[];
 
 /* Info for the block device */
 typedef struct mtd_raw_dev_data_s {
@@ -905,14 +904,7 @@
   DEBUG(1, "blkmtd: devname = %s\n", bdevname(rdev));
   blocksize = BLOCK_SIZE;
 
-  if(bs) {
-    blocksize = bs;
-  } else {
-    if (blksize_size[maj] && blksize_size[maj][min]) {
-      DEBUG(2, "blkmtd: blksize_size = %d\n", blksize_size[maj][min]);
-      blocksize = blksize_size[maj][min];
-    }
-  }
+  blocksize = bs ? bs : block_size(rdev);
   i = blocksize;
   blocksize_bits = 0;
   while(i != 1) {
diff -u --recursive --new-file v2.5.1/linux/drivers/mtd/devices/doc1000.c linux/drivers/mtd/devices/doc1000.c
--- v2.5.1/linux/drivers/mtd/devices/doc1000.c	Thu Oct  4 15:14:59 2001
+++ linux/drivers/mtd/devices/doc1000.c	Sun Dec 30 10:31:51 2001
@@ -20,7 +20,6 @@
 #include <linux/ioctl.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/segment.h>
 #include <stdarg.h>
 #include <linux/delay.h>
 #include <linux/init.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/mtd/devices/pmc551.c linux/drivers/mtd/devices/pmc551.c
--- v2.5.1/linux/drivers/mtd/devices/pmc551.c	Thu Oct  4 15:14:59 2001
+++ linux/drivers/mtd/devices/pmc551.c	Sun Dec 30 10:31:51 2001
@@ -98,7 +98,6 @@
 #include <linux/ioctl.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/segment.h>
 #include <stdarg.h>
 #include <linux/pci.h>
 
diff -u --recursive --new-file v2.5.1/linux/drivers/mtd/devices/slram.c linux/drivers/mtd/devices/slram.c
--- v2.5.1/linux/drivers/mtd/devices/slram.c	Thu Oct  4 15:14:59 2001
+++ linux/drivers/mtd/devices/slram.c	Sun Dec 30 10:31:51 2001
@@ -20,7 +20,6 @@
 #include <linux/init.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/segment.h>
 #include <stdarg.h>
 
 #include <linux/mtd/mtd.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/mtd/ftl.c linux/drivers/mtd/ftl.c
--- v2.5.1/linux/drivers/mtd/ftl.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/mtd/ftl.c	Mon Dec 31 17:56:19 2001
@@ -72,33 +72,12 @@
 #include <linux/hdreg.h>
 #include <stdarg.h>
 
-#if (LINUX_VERSION_CODE >= 0x20100)
 #include <linux/vmalloc.h>
-#endif
-#if (LINUX_VERSION_CODE >= 0x20303)
 #include <linux/blkpg.h>
-#endif
 
 #include <linux/mtd/ftl.h>
-/*====================================================================*/
-/* Stuff which really ought to be in compatmac.h */
-
-#if (LINUX_VERSION_CODE < 0x20328)
-#define register_disk(dev, drive, minors, ops, size) \
-    do { (dev)->part[(drive)*(minors)].nr_sects = size; \
-        if (size == 0) (dev)->part[(drive)*(minors)].start_sect = -1; \
-        resetup_one_dev(dev, drive); } while (0);
-#endif
 
-#if (LINUX_VERSION_CODE < 0x20320)
-#define BLK_DEFAULT_QUEUE(n)    blk_dev[n].request_fn
-#define blk_init_queue(q, req)  q = (req)
-#define blk_cleanup_queue(q)    q = NULL
-#define request_arg_t           void
-#else
 #define request_arg_t           request_queue_t *q
-#endif
-
 
 /*====================================================================*/
 
@@ -206,10 +185,6 @@
     major:		FTL_MAJOR,
     major_name:		"ftl",
     minor_shift:	PART_BITS,
-    max_p:		MAX_PART,
-#if (LINUX_VERSION_CODE < 0x20328)
-    max_nr:		MAX_DEV*MAX_PART,
-#endif
     part:		ftl_hd,
     sizes:		ftl_sizes,
 };
@@ -224,23 +199,12 @@
 
 static void ftl_erase_callback(struct erase_info *done);
 
-#if LINUX_VERSION_CODE < 0x20326
-static struct file_operations ftl_blk_fops = {
-    open:	ftl_open,
-    release:	ftl_close,
-    ioctl:	ftl_ioctl,
-    read:	block_read,
-    write:	block_write,
-    fsync:	block_fsync
-};
-#else
 static struct block_device_operations ftl_blk_fops = {
     owner:	THIS_MODULE,
     open:	ftl_open,
     release:	ftl_close,
     ioctl:	ftl_ioctl,
 };
-#endif
 
 /*======================================================================
 
@@ -1177,22 +1141,11 @@
     case BLKRRPART:
 	ret = ftl_reread_partitions(minor);
 	break;
-#if (LINUX_VERSION_CODE < 0x20303)
-    case BLKFLSBUF:
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-	if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-#endif
-	fsync_dev(inode->i_rdev);
-	invalidate_buffers(inode->i_rdev);
-	break;
-    RO_IOCTLS(inode->i_rdev, arg);
-#else
     case BLKROSET:
     case BLKROGET:
     case BLKFLSBUF:
 	ret = blk_ioctl(inode->i_rdev, cmd, arg);
 	break;
-#endif
     default:
 	ret = -EINVAL;
     }
diff -u --recursive --new-file v2.5.1/linux/drivers/mtd/nftlcore.c linux/drivers/mtd/nftlcore.c
--- v2.5.1/linux/drivers/mtd/nftlcore.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/mtd/nftlcore.c	Mon Dec 31 17:56:19 2001
@@ -62,14 +62,9 @@
 static struct gendisk nftl_gendisk = {
 	major:		MAJOR_NR,
 	major_name:	"nftl",
-	minor_shift:	NFTL_PARTN_BITS,	/* Bits to shift to get real from partition */
-	max_p:		(1<<NFTL_PARTN_BITS)-1,	/* Number of partitions per real */
-#if LINUX_VERSION_CODE < 0x20328
-	max_nr:		MAX_NFTLS,      /* maximum number of real */
-	init:		dummy_init,     /* init function */
-#endif
-	part:		part_table,     /* hd struct */
-	sizes:		nftl_sizes,     /* block sizes */
+	minor_shift:	NFTL_PARTN_BITS,	/* # of partition bits */
+	part:		part_table,		/* hd struct */
+	sizes:		nftl_sizes,		/* block sizes */
 };
 
 struct NFTLrecord *NFTLs[MAX_NFTLS];
diff -u --recursive --new-file v2.5.1/linux/drivers/mtd/nftlmount.c linux/drivers/mtd/nftlmount.c
--- v2.5.1/linux/drivers/mtd/nftlmount.c	Thu Oct  4 15:13:18 2001
+++ linux/drivers/mtd/nftlmount.c	Thu Dec 20 08:53:28 2001
@@ -4,7 +4,7 @@
  * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
  * Copyright (C) 2000 Netgem S.A.
  *
- * $Id: nftlmount.c,v 1.23 2001/09/19 21:42:32 dwmw2 Exp $
+ * $Id: nftlmount.c,v 1.25 2001/11/30 16:46:27 dwmw2 Exp $
  *
  * 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
@@ -39,7 +39,7 @@
 
 #define SECTORSIZE 512
 
-char nftlmountrev[]="$Revision: 1.23 $";
+char nftlmountrev[]="$Revision: 1.25 $";
 
 /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
  *	various device information of the NFTL partition and Bad Unit Table. Update
@@ -94,11 +94,11 @@
 			continue;
 		}
 
-#if 1 /* Some people seem to have devices without ECC or erase marks
+#if 0 /* Some people seem to have devices without ECC or erase marks
 	 on the Media Header blocks. There are enough other sanity
 	 checks in here that we can probably do without it.
       */
-		if (le16_to_cpu ((h1.EraseMark | h1.EraseMark1) != ERASE_MARK)) {
+		if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) {
 			printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n",
 			       block * nftl->EraseSize, nftl->mtd->index, 
 			       le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1));
diff -u --recursive --new-file v2.5.1/linux/drivers/net/de2104x.c linux/drivers/net/de2104x.c
--- v2.5.1/linux/drivers/net/de2104x.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/net/de2104x.c	Tue Jan  1 18:09:37 2002
@@ -28,8 +28,8 @@
  */
 
 #define DRV_NAME		"de2104x"
-#define DRV_VERSION		"0.5.1"
-#define DRV_RELDATE		"Nov 20, 2001"
+#define DRV_VERSION		"0.5.4"
+#define DRV_RELDATE		"Jan 1, 2002"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -45,6 +45,7 @@
 #include <linux/rtnetlink.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
+#include <asm/unaligned.h>
 
 /* These identify the driver base version and may not be removed. */
 static char version[] __initdata =
@@ -99,6 +100,7 @@
 #define DE_DUMMY_SKB		((struct sk_buff *) 2)
 #define DE_SETUP_FRAME_WORDS	96
 #define DE_EEPROM_WORDS		256
+#define DE_EEPROM_SIZE		(DE_EEPROM_WORDS * sizeof(u16))
 #define DE_MAX_MEDIA		5
 
 #define DE_MEDIA_TP_AUTO	0
@@ -109,6 +111,8 @@
 #define DE_MEDIA_INVALID	DE_MAX_MEDIA
 #define DE_MEDIA_FIRST		0
 #define DE_MEDIA_LAST		(DE_MAX_MEDIA - 1)
+#define DE_AUI_BNC		(SUPPORTED_AUI | SUPPORTED_BNC)
+
 #define DE_TIMER_LINK		(60 * HZ)
 #define DE_TIMER_NO_LINK	(5 * HZ)
 
@@ -117,7 +121,9 @@
 #define DE_REGS_VER		1
 
 /* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  (6*HZ)
+#define TX_TIMEOUT		(6*HZ)
+
+#define DE_UNALIGNED_16(a)	(u16)(get_unaligned((u16 *)(a)))
 
 /* This is a mysterious value that can be written to CSR11 in the 21040 (only)
    to support a pre-NWay full-duplex signaling mechanism using short frames.
@@ -254,7 +260,6 @@
 	u16			default_media;
 	u8			n_blocks;
 	u8			unused;
-	struct de_srom_media_block	media[0];
 } __attribute__((packed));
 
 struct de_desc {
@@ -307,6 +312,7 @@
 	struct media_info	media[DE_MAX_MEDIA];
 	struct timer_list	media_timer;
 
+	u8			*ee_data;
 	unsigned		board_idx;
 	unsigned		de21040 : 1;
 	unsigned		media_lock : 1;
@@ -319,6 +325,7 @@
 static void de_media_interrupt (struct de_private *de, u32 status);
 static void de21040_media_timer (unsigned long data);
 static void de21041_media_timer (unsigned long data);
+static unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media);
 
 
 static struct pci_device_id de_pci_tbl[] __initdata = {
@@ -918,7 +925,6 @@
 
 	dw32(MacStatus, dr32(MacStatus));
 
-	synchronize_irq();
 	udelay(10);
 
 	de->rx_tail = 0;
@@ -968,15 +974,29 @@
 	else
 		de->macmode &= ~FullDuplex;
 	
-	if (netif_msg_link(de))
-		printk(KERN_INFO "%s: set link %s, mode %x, sia %x,%x,%x,%x\n"
-		       KERN_INFO "                 set mode %x, set sia %x,%x,%x\n",
+	if (netif_msg_link(de)) {
+		printk(KERN_INFO "%s: set link %s\n"
+		       KERN_INFO "%s:    mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n"
+		       KERN_INFO "%s:    set mode 0x%x, set sia 0x%x,0x%x,0x%x\n",
 		       de->dev->name, media_name[media],
-		       dr32(MacMode), dr32(SIAStatus), dr32(CSR13),
-		       dr32(CSR14), dr32(CSR15), de->macmode,
-			de->media[media].csr13,
-			de->media[media].csr14,
-			de->media[media].csr15);
+		       de->dev->name, dr32(MacMode), dr32(SIAStatus),
+		       dr32(CSR13), dr32(CSR14), dr32(CSR15),
+		       de->dev->name, de->macmode, de->media[media].csr13,
+		       de->media[media].csr14, de->media[media].csr15);
+	}
+}
+
+static void de_next_media (struct de_private *de, u32 *media,
+			   unsigned int n_media)
+{
+	unsigned int i;
+
+	for (i = 0; i < n_media; i++) {
+		if (de_ok_to_advertise(de, media[i])) {
+			de->media_type = media[i];
+			return;
+		}
+	}
 }
 
 static void de21040_media_timer (unsigned long data)
@@ -985,6 +1005,7 @@
 	struct net_device *dev = de->dev;
 	u32 status = dr32(SIAStatus);
 	unsigned int carrier;
+	unsigned long flags;
 	
 	carrier = (status & NetCxnErr) ? 0 : 1;
 		
@@ -1009,12 +1030,17 @@
 	if (de->media_lock)
 		return;
 
-	if (de->media_type == DE_MEDIA_AUI)
-		de->media_type = DE_MEDIA_TP;
-	else
-		de->media_type = DE_MEDIA_AUI;
+	if (de->media_type == DE_MEDIA_AUI) {
+		u32 next_state = DE_MEDIA_TP;
+		de_next_media(de, &next_state, 1);
+	} else {
+		u32 next_state = DE_MEDIA_AUI;
+		de_next_media(de, &next_state, 1);
+	}
 
+	spin_lock_irqsave(&de->lock, flags);
 	de_stop_rxtx(de);
+	spin_unlock_irqrestore(&de->lock, flags);
 	de_set_media(de);
 	de_start_rxtx(de);
 
@@ -1061,8 +1087,9 @@
 {
 	struct de_private *de = (struct de_private *) data;
 	struct net_device *dev = de->dev;
-	u32 status = dr32(SIAStatus), new_media;
+	u32 status = dr32(SIAStatus);
 	unsigned int carrier;
+	unsigned long flags;
 	
 	carrier = (status & NetCxnErr) ? 0 : 1;
 		
@@ -1093,27 +1120,55 @@
 
 	/* if activity detected, use that as hint for new media type */
 	if (status & NonselPortActive) {
-		if (de->media_type == DE_MEDIA_AUI)
-			de->media_type = DE_MEDIA_TP;
-		else
+		unsigned int have_media = 1;
+
+		/* if AUI/BNC selected, then activity is on TP port */
+		if (de->media_type == DE_MEDIA_AUI ||
+		    de->media_type == DE_MEDIA_BNC) {
+			if (de_ok_to_advertise(de, DE_MEDIA_TP_AUTO))
+				de->media_type = DE_MEDIA_TP_AUTO;
+			else
+				have_media = 0;
+		}
+
+		/* TP selected.  If there is only TP and BNC, then it's BNC */
+		else if (((de->media_supported & DE_AUI_BNC) == SUPPORTED_BNC) &&
+			 de_ok_to_advertise(de, DE_MEDIA_BNC))
+			de->media_type = DE_MEDIA_BNC;
+
+		/* TP selected.  If there is only TP and AUI, then it's AUI */
+		else if (((de->media_supported & DE_AUI_BNC) == SUPPORTED_AUI) &&
+			 de_ok_to_advertise(de, DE_MEDIA_AUI))
 			de->media_type = DE_MEDIA_AUI;
-		goto set_media;
-	}
 
-	/* move to next advertised media */
-	new_media = de->media_type;
-	do {
-		if (new_media == DE_MEDIA_LAST)
-			new_media = DE_MEDIA_FIRST;
+		/* otherwise, ignore the hint */
 		else
-			new_media++;
-	} while ((!de_ok_to_advertise(de, new_media)) &&
-	         (new_media != de->media_type));
+			have_media = 0;
 
-	de->media_type = new_media;
+		if (have_media)
+			goto set_media;
+	}
+
+	/*
+	 * Absent or ambiguous activity hint, move to next advertised
+	 * media state.  If de->media_type is left unchanged, this
+	 * simply resets the PHY and reloads the current media settings.
+	 */
+	if (de->media_type == DE_MEDIA_AUI) {
+		u32 next_states[] = { DE_MEDIA_BNC, DE_MEDIA_TP_AUTO };
+		de_next_media(de, next_states, ARRAY_SIZE(next_states));
+	} else if (de->media_type == DE_MEDIA_BNC) {
+		u32 next_states[] = { DE_MEDIA_TP_AUTO, DE_MEDIA_AUI };
+		de_next_media(de, next_states, ARRAY_SIZE(next_states));
+	} else {
+		u32 next_states[] = { DE_MEDIA_AUI, DE_MEDIA_BNC, DE_MEDIA_TP_AUTO };
+		de_next_media(de, next_states, ARRAY_SIZE(next_states));
+	}
 	
 set_media:
+	spin_lock_irqsave(&de->lock, flags);
 	de_stop_rxtx(de);
+	spin_unlock_irqrestore(&de->lock, flags);
 	de_set_media(de);
 	de_start_rxtx(de);
 
@@ -1145,20 +1200,21 @@
 
 static int de_reset_mac (struct de_private *de)
 {
-	unsigned tmp;
-	u32 status;
+	u32 status, tmp;
 
 	/*
 	 * Reset MAC.  Copied from de4x5.c.
 	 */
 
-	dr32 (BusMode);
+	tmp = dr32 (BusMode);
+	if (tmp == 0xffffffff)
+		return -ENODEV;
 	mdelay (1);
 
-	dw32 (BusMode, de_bus_mode | CmdReset);
+	dw32 (BusMode, tmp | CmdReset);
 	mdelay (1);
 
-	dw32 (BusMode, de_bus_mode);
+	dw32 (BusMode, tmp);
 	mdelay (1);
 
 	for (tmp = 0; tmp < 5; tmp++) {
@@ -1309,12 +1365,20 @@
 	}
 
 	for (i = 0; i < DE_TX_RING_SIZE; i++) {
-		if (de->tx_skb[i].skb) {
-			struct sk_buff *skb = de->tx_skb[i].skb;
-			pci_unmap_single(de->pdev, de->tx_skb[i].mapping,
-					 skb->len, PCI_DMA_TODEVICE);
-			dev_kfree_skb(skb);
-			de->net_stats.tx_dropped++;
+		struct sk_buff *skb = de->tx_skb[i].skb;
+		if ((skb) && (skb != DE_DUMMY_SKB)) {
+			if (skb != DE_SETUP_SKB) {
+				dev_kfree_skb(skb);
+				de->net_stats.tx_dropped++;
+				pci_unmap_single(de->pdev,
+					de->tx_skb[i].mapping,
+					skb->len, PCI_DMA_TODEVICE);
+			} else {
+				pci_unmap_single(de->pdev,
+					de->tx_skb[i].mapping,
+					sizeof(de->setup_frame),
+					PCI_DMA_TODEVICE);
+			}
 		}
 	}
 
@@ -1334,6 +1398,7 @@
 {
 	struct de_private *de = dev->priv;
 	int rc;
+	unsigned long flags;
 
 	if (netif_msg_ifup(de))
 		printk(KERN_DEBUG "%s: enabling interface\n", dev->name);
@@ -1362,11 +1427,15 @@
 	}
 
 	netif_start_queue(dev);
+	mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK);
 
 	return 0;
 
 err_out_hw:
+	spin_lock_irqsave(&de->lock, flags);
 	de_stop_hw(de);
+	spin_unlock_irqrestore(&de->lock, flags);
+
 err_out_free:
 	de_free_rings(de);
 	return rc;
@@ -1375,15 +1444,21 @@
 static int de_close (struct net_device *dev)
 {
 	struct de_private *de = dev->priv;
+	unsigned long flags;
 
 	if (netif_msg_ifdown(de))
 		printk(KERN_DEBUG "%s: disabling interface\n", dev->name);
 
-	netif_stop_queue(dev);
-	netif_carrier_off(dev);
 	del_timer_sync(&de->media_timer);
+
+	spin_lock_irqsave(&de->lock, flags);
 	de_stop_hw(de);
+	netif_stop_queue(dev);
+	netif_carrier_off(dev);
+	spin_unlock_irqrestore(&de->lock, flags);
+	
 	free_irq(dev->irq, dev);
+
 	de_free_rings(de);
 	de_adapter_sleep(de);
 	pci_disable_device(de->pdev);
@@ -1558,6 +1633,7 @@
 		strcpy (info.driver, DRV_NAME);
 		strcpy (info.version, DRV_VERSION);
 		strcpy (info.bus_info, de->pdev->slot_name);
+		info.eedump_len = DE_EEPROM_SIZE;
 		info.regdump_len = DE_REGS_SIZE;
 		if (copy_to_user (useraddr, &info, sizeof (info)))
 			return -EFAULT;
@@ -1658,6 +1734,23 @@
 		return 0;
 	}
 
+	/* get SROM dump */
+	case ETHTOOL_GEEPROM: {
+		struct ethtool_eeprom eeprom;
+
+		if (!de->ee_data)
+			break;
+		if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
+			return -EFAULT;
+		if ((eeprom.offset != 0) || (eeprom.magic != 0) ||
+		    (eeprom.len != DE_EEPROM_SIZE))
+			return -EINVAL;
+
+		useraddr += offsetof(struct ethtool_regs, data);
+		if (copy_to_user(useraddr, de->ee_data, DE_EEPROM_SIZE))
+			return -EFAULT;
+	}
+
 	default:
 		break;
 	}
@@ -1703,7 +1796,31 @@
 	}
 }
 
-/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/
+static void __init de21040_get_media_info(struct de_private *de)
+{
+	unsigned int i;
+
+	de->media_type = DE_MEDIA_TP;
+	de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Full |
+			       SUPPORTED_10baseT_Half | SUPPORTED_AUI;
+	de->media_advertise = de->media_supported;
+
+	for (i = 0; i < DE_MAX_MEDIA; i++) {
+		switch (i) {
+		case DE_MEDIA_AUI:
+		case DE_MEDIA_TP:
+		case DE_MEDIA_TP_FD:
+			de->media[i].type = i;
+			de->media[i].csr13 = t21040_csr13[i];
+			de->media[i].csr14 = t21040_csr14[i];
+			de->media[i].csr15 = t21040_csr15[i];
+			break;
+		default:
+			de->media[i].type = DE_MEDIA_INVALID;
+			break;
+		}
+	}
+}
 
 /* Note: this routine returns extra data bits for size detection. */
 static unsigned __init tulip_read_eeprom(void *regs, int location, int addr_len)
@@ -1741,15 +1858,16 @@
 	return retval;
 }
 
-static void __init tulip_get_srom_info (struct de_private *de)
+static void __init de21041_get_srom_info (struct de_private *de)
 {
 	unsigned i, sa_offset = 0, ofs;
-	u8 ee_data[DE_EEPROM_WORDS * sizeof(u16)];
+	u8 ee_data[DE_EEPROM_SIZE + 6] = {};
 	unsigned ee_addr_size = tulip_read_eeprom(de->regs, 0xff, 8) & 0x40000 ? 8 : 6;
 	struct de_srom_info_leaf *il;
+	void *bufp;
 
 	/* download entire eeprom */
-	for (i = 0; i < sizeof(ee_data)/2; i++)
+	for (i = 0; i < DE_EEPROM_WORDS; i++)
 		((u16 *)ee_data)[i] =
 			le16_to_cpu(tulip_read_eeprom(de->regs, i, ee_addr_size));
 
@@ -1780,13 +1898,18 @@
 		goto bad_srom;
 
 	/* get default media type */
-	switch (il->default_media) {
+	switch (DE_UNALIGNED_16(&il->default_media)) {
 	case 0x0001:  de->media_type = DE_MEDIA_BNC; break;
 	case 0x0002:  de->media_type = DE_MEDIA_AUI; break;
 	case 0x0204:  de->media_type = DE_MEDIA_TP_FD; break;
 	default: de->media_type = DE_MEDIA_TP_AUTO; break;
 	}
 	
+	if (netif_msg_probe(de))
+		printk(KERN_INFO "de%d: SROM leaf offset %u, default media %s\n",
+		       de->board_idx, ofs,
+		       media_name[de->media_type]);
+
 	/* init SIA register values to defaults */
 	for (i = 0; i < DE_MAX_MEDIA; i++) {
 		de->media[i].type = DE_MEDIA_INVALID;
@@ -1798,8 +1921,9 @@
 	/* parse media blocks to see what medias are supported,
 	 * and if any custom CSR values are provided
 	 */
+	bufp = ((void *)il) + sizeof(*il);
 	for (i = 0; i < il->n_blocks; i++) {
-		struct de_srom_media_block *ib = &il[i].media[0];
+		struct de_srom_media_block *ib = bufp;
 		unsigned idx;
 
 		/* index based on media type in media block */
@@ -1828,16 +1952,37 @@
 			goto bad_srom;
 		}
 
+		de->media[idx].type = idx;
+
+		if (netif_msg_probe(de))
+			printk(KERN_INFO "de%d:   media block #%u: %s",
+			       de->board_idx, i,
+			       media_name[de->media[idx].type]);
+
+		bufp += sizeof (ib->opts);
+
 		if (ib->opts & MediaCustomCSRs) {
-			de->media[idx].csr13 = ib->csr13;
-			de->media[idx].csr14 = ib->csr14;
-			de->media[idx].csr15 = ib->csr15;
-		}
+			de->media[idx].csr13 = DE_UNALIGNED_16(&ib->csr13);
+			de->media[idx].csr14 = DE_UNALIGNED_16(&ib->csr14);
+			de->media[idx].csr15 = DE_UNALIGNED_16(&ib->csr15);
+			bufp += sizeof(ib->csr13) + sizeof(ib->csr14) +
+				sizeof(ib->csr15);
+
+			if (netif_msg_probe(de))
+				printk(" (%x,%x,%x)\n",
+				       de->media[idx].csr13,
+				       de->media[idx].csr14,
+				       de->media[idx].csr15);
+				       
+		} else if (netif_msg_probe(de))
+			printk("\n");
 
-		de->media[idx].type = idx;
-		de->media_advertise |= de->media_supported;
+		if (bufp > ((void *)&ee_data[DE_EEPROM_SIZE - 3]))
+			break;
 	}
 
+	de->media_advertise = de->media_supported;
+
 fill_defaults:
 	/* fill in defaults, for cases where custom CSRs not used */
 	for (i = 0; i < DE_MAX_MEDIA; i++) {
@@ -1849,12 +1994,9 @@
 			de->media[i].csr15 = t21041_csr15[i];
 	}
 
-	if (netif_msg_link(de))
-		printk(KERN_INFO "de%d: SROM-listed ports: %s%s%s\n",
-		       de->board_idx,
-		       de->media_supported & SUPPORTED_TP ? "TP " : "",
-		       de->media_supported & SUPPORTED_BNC ? "BNC " : "",
-		       de->media_supported & SUPPORTED_AUI ? "AUI" : "");
+	de->ee_data = kmalloc(DE_EEPROM_SIZE, GFP_KERNEL);
+	if (de->ee_data)
+		memcpy(de->ee_data, &ee_data[0], DE_EEPROM_SIZE);
 
 	return;
 
@@ -1970,35 +2112,21 @@
 	de_adapter_wake(de);
 
 	/* make sure hardware is not running */
-	de_stop_hw(de);
+	rc = de_reset_mac(de);
+	if (rc) {
+		printk(KERN_ERR PFX "Cannot reset MAC, pci dev %s\n",
+		       pdev->slot_name);
+		goto err_out_iomap;
+	}
 
-	/* get MAC address, and some register values related to media types */
+	/* get MAC address, initialize default media type and
+	 * get list of supported media
+	 */
 	if (de->de21040) {
-		unsigned i;
-		
 		de21040_get_mac_address(de);
-
-		de->media_type = DE_MEDIA_TP;
-		de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Full |
-				  SUPPORTED_10baseT_Half | SUPPORTED_AUI;
-		de->media_advertise = de->media_supported;
-		for (i = 0; i < DE_MAX_MEDIA; i++) {
-			switch (i) {
-			case DE_MEDIA_AUI:
-			case DE_MEDIA_TP:
-			case DE_MEDIA_TP_FD:
-				de->media[i].type = i;
-				de->media[i].csr13 = t21040_csr13[i];
-				de->media[i].csr14 = t21040_csr14[i];
-				de->media[i].csr15 = t21040_csr15[i];
-				break;
-			default:
-				de->media[i].type = DE_MEDIA_INVALID;
-				break;
-			}
-		}
+		de21040_get_media_info(de);
 	} else {
-		tulip_get_srom_info(de);
+		de21041_get_srom_info(de);
 	}
 
 	/* register new network interface with kernel */
@@ -2029,6 +2157,8 @@
 	return 0;
 
 err_out_iomap:
+	if (de->ee_data)
+		kfree(de->ee_data);
 	iounmap(regs);
 err_out_res:
 	pci_release_regions(pdev);
@@ -2047,6 +2177,8 @@
 	if (!dev)
 		BUG();
 	unregister_netdev(dev);
+	if (de->ee_data)
+		kfree(de->ee_data);
 	iounmap(de->regs);
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
diff -u --recursive --new-file v2.5.1/linux/drivers/net/defxx.c linux/drivers/net/defxx.c
--- v2.5.1/linux/drivers/net/defxx.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/net/defxx.c	Thu Jan  3 12:20:12 2002
@@ -500,7 +500,7 @@
 
 static int __init dfx_eisa_init(void)
 {
-	int rc = -NODEV;
+	int rc = -ENODEV;
 	int i;			/* used in for loops */
 	u16 port;		/* temporary I/O (port) address */
 	u32 slot_id;		/* EISA hardware (slot) ID read from adapter */
diff -u --recursive --new-file v2.5.1/linux/drivers/net/fc/iph5526.c linux/drivers/net/fc/iph5526.c
--- v2.5.1/linux/drivers/net/fc/iph5526.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/net/fc/iph5526.c	Tue Dec 25 17:04:40 2001
@@ -4534,14 +4534,14 @@
 {
 int i = 0;
 
-	driver_template.module = &__this_module;
-	scsi_register_module(MODULE_SCSI_HA, &driver_template);
+	driver_template.module = THIS_MODULE;
+	scsi_register_host(&driver_template);
 	if (driver_template.present)
 		scsi_registered = TRUE; 
 	else {
 		printk("iph5526: SCSI registeration failed!!!\n");
 		scsi_registered = FALSE;
-		scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+		scsi_unregister_host(&driver_template);
 	}
 
 	while(fc[i] != NULL) {
@@ -4590,7 +4590,7 @@
 		i++;
 	}
 	if (scsi_registered == TRUE)
-		scsi_unregister_module(MODULE_SCSI_HA, &driver_template); 
+		scsi_unregister_host(&driver_template); 
 }
 #endif /* MODULE */
 
diff -u --recursive --new-file v2.5.1/linux/drivers/net/hamradio/bpqether.c linux/drivers/net/hamradio/bpqether.c
--- v2.5.1/linux/drivers/net/hamradio/bpqether.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/net/hamradio/bpqether.c	Sun Dec 30 10:31:51 2001
@@ -69,7 +69,6 @@
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/net/hamradio/dmascc.c linux/drivers/net/hamradio/dmascc.c
--- v2.5.1/linux/drivers/net/hamradio/dmascc.c	Wed Apr 18 14:40:06 2001
+++ linux/drivers/net/hamradio/dmascc.c	Sun Dec 30 10:31:51 2001
@@ -43,7 +43,6 @@
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <net/ax25.h>
 #include "z8530.h"
diff -u --recursive --new-file v2.5.1/linux/drivers/net/hamradio/mkiss.c linux/drivers/net/hamradio/mkiss.c
--- v2.5.1/linux/drivers/net/hamradio/mkiss.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/net/hamradio/mkiss.c	Sun Dec 30 10:31:51 2001
@@ -27,7 +27,6 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <asm/system.h>
-#include <asm/segment.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/net/irda/irda-usb.c linux/drivers/net/irda/irda-usb.c
--- v2.5.1/linux/drivers/net/irda/irda-usb.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/net/irda/irda-usb.c	Tue Jan  1 13:52:10 2002
@@ -112,9 +112,9 @@
 static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev);
 static int irda_usb_open(struct irda_usb_cb *self);
 static int irda_usb_close(struct irda_usb_cb *self);
-static void speed_bulk_callback(purb_t purb);
-static void write_bulk_callback(purb_t purb);
-static void irda_usb_receive(purb_t purb);
+static void speed_bulk_callback(struct urb *urb);
+static void write_bulk_callback(struct urb *urb);
+static void irda_usb_receive(struct urb *urb);
 static int irda_usb_net_init(struct net_device *dev);
 static int irda_usb_net_open(struct net_device *dev);
 static int irda_usb_net_close(struct net_device *dev);
@@ -248,15 +248,15 @@
 {
 	unsigned long flags;
 	__u8 *frame;
-	purb_t purb;
+	struct urb *urb;
 	int ret;
 
 	IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, xbofs=%d\n",
 		   self->new_speed, self->new_xbofs);
 
 	/* Grab the speed URB */
-	purb = &self->speed_urb;
-	if (purb->status != 0) {
+	urb = &self->speed_urb;
+	if (urb->status != 0) {
 		WARNING(__FUNCTION__ "(), URB still in use!\n");
 		return;
 	}
@@ -270,15 +270,15 @@
 	irda_usb_build_header(self, frame, 1);
 
 	/* Submit the 0 length IrDA frame to trigger new speed settings */
-        FILL_BULK_URB(purb, self->usbdev,
+        FILL_BULK_URB(urb, self->usbdev,
 		      usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
                       frame, IRDA_USB_SPEED_MTU,
                       speed_bulk_callback, self);
-	purb->transfer_buffer_length = USB_IRDA_HEADER;
-	purb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;
-	purb->timeout = MSECS_TO_JIFFIES(100);
+	urb->transfer_buffer_length = USB_IRDA_HEADER;
+	urb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;
+	urb->timeout = MSECS_TO_JIFFIES(100);
 
-	if ((ret = usb_submit_urb(purb))) {
+	if ((ret = usb_submit_urb(urb))) {
 		WARNING(__FUNCTION__ "(), failed Speed URB\n");
 	}
 	spin_unlock_irqrestore(&self->lock, flags);
@@ -288,9 +288,9 @@
 /*
  * Note : this function will be called with both speed_urb and empty_urb...
  */
-static void speed_bulk_callback(purb_t purb)
+static void speed_bulk_callback(struct urb *urb)
 {
-	struct irda_usb_cb *self = purb->context;
+	struct irda_usb_cb *self = urb->context;
 	
 	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
@@ -301,9 +301,9 @@
 	}
 
 	/* Check for timeout and other USB nasties */
-	if (purb->status != 0) {
+	if (urb->status != 0) {
 		/* I get a lot of -ECONNABORTED = -103 here - Jean II */
-		IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags);
+		IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", urb->status, urb->transfer_flags);
 
 		/* Don't do anything here, that might confuse the USB layer.
 		 * Instead, we will wait for irda_usb_net_timeout(), the
@@ -314,10 +314,10 @@
 	}
 
 	/* urb is now available */
-	purb->status = 0;
+	urb->status = 0;
 
 	/* If it was the speed URB, allow the stack to send more packets */
-	if(purb == &self->speed_urb) {
+	if(urb == &self->speed_urb) {
 		netif_wake_queue(self->netdev);
 	}
 }
@@ -329,7 +329,7 @@
 static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
 	struct irda_usb_cb *self = netdev->priv;
-	purb_t purb = &self->tx_urb;
+	struct urb *urb = &self->tx_urb;
 	unsigned long flags;
 	s32 speed;
 	s16 xbofs;
@@ -372,7 +372,7 @@
 		}
 	}
 
-	if (purb->status != 0) {
+	if (urb->status != 0) {
 		WARNING(__FUNCTION__ "(), URB still in use!\n");
 		dev_kfree_skb(skb);
 		return 0;
@@ -392,22 +392,22 @@
 	/* FIXME: Make macro out of this one */
 	((struct irda_skb_cb *)skb->cb)->context = self;
 
-        FILL_BULK_URB(purb, self->usbdev, 
+        FILL_BULK_URB(urb, self->usbdev, 
 		      usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
                       skb->data, IRDA_USB_MAX_MTU,
                       write_bulk_callback, skb);
-	purb->transfer_buffer_length = skb->len;
+	urb->transfer_buffer_length = skb->len;
 	/* Note : unlink *must* be Asynchronous because of the code in 
 	 * irda_usb_net_timeout() -> call in irq - Jean II */
-	purb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;
+	urb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;
 	/* This flag (USB_ZERO_PACKET) indicates that what we send is not
 	 * a continuous stream of data but separate packets.
 	 * In this case, the USB layer will insert an empty USB frame (TD)
 	 * after each of our packets that is exact multiple of the frame size.
 	 * This is how the dongle will detect the end of packet - Jean II */
-	purb->transfer_flags |= USB_ZERO_PACKET;
+	urb->transfer_flags |= USB_ZERO_PACKET;
 	/* Timeout need to be shorter than NET watchdog timer */
-	purb->timeout = MSECS_TO_JIFFIES(200);
+	urb->timeout = MSECS_TO_JIFFIES(200);
 
 	/* Generate min turn time. FIXME: can we do better than this? */
 	/* Trying to a turnaround time at this level is trying to measure
@@ -451,7 +451,7 @@
 	}
 	
 	/* Ask USB to send the packet */
-	if ((res = usb_submit_urb(purb))) {
+	if ((res = usb_submit_urb(urb))) {
 		WARNING(__FUNCTION__ "(), failed Tx URB\n");
 		self->stats.tx_errors++;
 		/* Let USB recover : We will catch that in the watchdog */
@@ -472,9 +472,9 @@
 /*
  * Note : this function will be called only for tx_urb...
  */
-static void write_bulk_callback(purb_t purb)
+static void write_bulk_callback(struct urb *urb)
 {
-	struct sk_buff *skb = purb->context;
+	struct sk_buff *skb = urb->context;
 	struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context;
 	
 	IRDA_DEBUG(2, __FUNCTION__ "()\n");
@@ -487,12 +487,12 @@
 
 	/* Free up the skb */
 	dev_kfree_skb_any(skb);
-	purb->context = NULL;
+	urb->context = NULL;
 
 	/* Check for timeout and other USB nasties */
-	if (purb->status != 0) {
+	if (urb->status != 0) {
 		/* I get a lot of -ECONNABORTED = -103 here - Jean II */
-		IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags);
+		IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", urb->status, urb->transfer_flags);
 
 		/* Don't do anything here, that might confuse the USB layer,
 		 * and we could go in recursion and blow the kernel stack...
@@ -504,7 +504,7 @@
 	}
 
 	/* urb is now available */
-	purb->status = 0;
+	urb->status = 0;
 
 	/* If the network is closed, stop everything */
 	if ((!self->netopen) || (!self->present)) {
@@ -534,7 +534,7 @@
 static void irda_usb_net_timeout(struct net_device *netdev)
 {
 	struct irda_usb_cb *self = netdev->priv;
-	purb_t purb;
+	struct urb *urb;
 	int	done = 0;	/* If we have made any progress */
 
 	IRDA_DEBUG(0, __FUNCTION__ "(), Network layer thinks we timed out!\n");
@@ -546,13 +546,13 @@
 	}
 
 	/* Check speed URB */
-	purb = &(self->speed_urb);
-	if (purb->status != 0) {
-		IRDA_DEBUG(0, "%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags);
+	urb = &(self->speed_urb);
+	if (urb->status != 0) {
+		IRDA_DEBUG(0, "%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, urb->status, urb->transfer_flags);
 
-		switch (purb->status) {
+		switch (urb->status) {
 		case -EINPROGRESS:
-			usb_unlink_urb(purb);
+			usb_unlink_urb(urb);
 			/* Note : above will  *NOT* call netif_wake_queue()
 			 * in completion handler, we will come back here.
 			 * Jean II */
@@ -563,7 +563,7 @@
 		case -ETIMEDOUT:		/* -110 */
 		case -ENOENT:			/* -2 (urb unlinked by us)  */
 		default:			/* ??? - Play safe */
-			purb->status = 0;
+			urb->status = 0;
 			netif_wake_queue(self->netdev);
 			done = 1;
 			break;
@@ -571,11 +571,11 @@
 	}
 
 	/* Check Tx URB */
-	purb = &(self->tx_urb);
-	if (purb->status != 0) {
-		struct sk_buff *skb = purb->context;
+	urb = &(self->tx_urb);
+	if (urb->status != 0) {
+		struct sk_buff *skb = urb->context;
 
-		IRDA_DEBUG(0, "%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags);
+		IRDA_DEBUG(0, "%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, urb->status, urb->transfer_flags);
 
 		/* Increase error count */
 		self->stats.tx_errors++;
@@ -589,11 +589,11 @@
 		irda_usb_change_speed_xbofs(self);
 #endif /* IU_BUG_KICK_TIMEOUT */
 
-		switch (purb->status) {
+		switch (urb->status) {
 		case -EINPROGRESS:
-			usb_unlink_urb(purb);
+			usb_unlink_urb(urb);
 			/* Note : above will  *NOT* call netif_wake_queue()
-			 * in completion handler, because purb->status will
+			 * in completion handler, because urb->status will
 			 * be -ENOENT. We will fix that at the next watchdog,
 			 * leaving more time to USB to recover...
 			 * Also, we are in interrupt, so we need to have
@@ -608,9 +608,9 @@
 		default:			/* ??? - Play safe */
 			if(skb != NULL) {
 				dev_kfree_skb_any(skb);
-				purb->context = NULL;
+				urb->context = NULL;
 			}
-			purb->status = 0;
+			urb->status = 0;
 			netif_wake_queue(self->netdev);
 			done = 1;
 			break;
@@ -685,7 +685,7 @@
  *
  * Jean II
  */
-static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_t purb)
+static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, struct urb *urb)
 {
 	struct irda_skb_cb *cb;
 	int ret;
@@ -693,8 +693,8 @@
 	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	/* Check that we have an urb */
-	if (!purb) {
-		WARNING(__FUNCTION__ "(), Bug : purb == NULL\n");
+	if (!urb) {
+		WARNING(__FUNCTION__ "(), Bug : urb == NULL\n");
 		return;
 	}
 
@@ -720,17 +720,17 @@
 	cb->context = self;
 
 	/* Reinitialize URB */
-	FILL_BULK_URB(purb, self->usbdev, 
+	FILL_BULK_URB(urb, self->usbdev, 
 		      usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep), 
 		      skb->data, skb->truesize,
                       irda_usb_receive, skb);
-	purb->transfer_flags = USB_QUEUE_BULK;
+	urb->transfer_flags = USB_QUEUE_BULK;
 	/* Note : unlink *must* be synchronous because of the code in 
 	 * irda_usb_net_close() -> free the skb - Jean II */
-	purb->status = 0;
-	purb->next = NULL;	/* Don't auto resubmit URBs */
+	urb->status = 0;
+	urb->next = NULL;	/* Don't auto resubmit URBs */
 	
-	ret = usb_submit_urb(purb);
+	ret = usb_submit_urb(urb);
 	if (ret) {
 		/* If this ever happen, we are in deep s***.
 		 * Basically, the Rx path will stop... */
@@ -740,19 +740,19 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Function irda_usb_receive(purb)
+ * Function irda_usb_receive(urb)
  *
  *     Called by the USB subsystem when a frame has been received
  *
  */
-static void irda_usb_receive(purb_t purb) 
+static void irda_usb_receive(struct urb *urb) 
 {
-	struct sk_buff *skb = (struct sk_buff *) purb->context;
+	struct sk_buff *skb = (struct sk_buff *) urb->context;
 	struct irda_usb_cb *self; 
 	struct irda_skb_cb *cb;
 	struct sk_buff *new;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), len=%d\n", purb->actual_length);
+	IRDA_DEBUG(2, __FUNCTION__ "(), len=%d\n", urb->actual_length);
 	
 	/* Find ourselves */
 	cb = (struct irda_skb_cb *) skb->cb;
@@ -768,27 +768,27 @@
 	}
 	
 	/* Check the status */
-	if (purb->status != 0) {
-		switch (purb->status) {
+	if (urb->status != 0) {
+		switch (urb->status) {
 		case -EILSEQ:
 			self->stats.rx_errors++;
 			self->stats.rx_crc_errors++;	
 			break;
 		case -ECONNRESET:		/* -104 */
-			IRDA_DEBUG(0, __FUNCTION__ "(), Connection Reset (-104), transfer_flags 0x%04X \n", purb->transfer_flags);
+			IRDA_DEBUG(0, __FUNCTION__ "(), Connection Reset (-104), transfer_flags 0x%04X \n", urb->transfer_flags);
 			/* uhci_cleanup_unlink() is going to kill the Rx
 			 * URB just after we return. No problem, at this
 			 * point the URB will be idle ;-) - Jean II */
 			break;
 		default:
-			IRDA_DEBUG(0, __FUNCTION__ "(), RX status %d,transfer_flags 0x%04X \n", purb->status, purb->transfer_flags);
+			IRDA_DEBUG(0, __FUNCTION__ "(), RX status %d,transfer_flags 0x%04X \n", urb->status, urb->transfer_flags);
 			break;
 		}
 		goto done;
 	}
 	
 	/* Check for empty frames */
-	if (purb->actual_length <= USB_IRDA_HEADER) {
+	if (urb->actual_length <= USB_IRDA_HEADER) {
 		WARNING(__FUNCTION__ "(), empty frame!\n");
 		goto done;
 	}
@@ -801,7 +801,7 @@
         get_fast_time(&self->stamp);
 
 	/* Fix skb, and remove USB-IrDA header */
-	skb_put(skb, purb->actual_length);
+	skb_put(skb, urb->actual_length);
 	skb_pull(skb, USB_IRDA_HEADER);
 
 	/* Don't waste a lot of memory on small IrDA frames */
@@ -834,7 +834,7 @@
         netif_rx(new);
 
 done:
-	/* Note : at this point, the URB we've just received (purb)
+	/* Note : at this point, the URB we've just received (urb)
 	 * is still referenced by the USB layer. For example, if we
 	 * have received a -ECONNRESET, uhci_cleanup_unlink() will
 	 * continue to process it (in fact, cleaning it up).
@@ -848,8 +848,8 @@
 	/* Submit the idle URB to replace the URB we've just received */
 	irda_usb_submit(self, skb, self->idle_rx_urb);
 	/* Recycle Rx URB : Now, the idle URB is the present one */
-	self->idle_rx_urb = purb;
-	purb->context = NULL;
+	self->idle_rx_urb = urb;
+	urb->context = NULL;
 }
 
 /*------------------------------------------------------------------*/
@@ -992,14 +992,14 @@
 
 	/* Deallocate all the Rx path buffers (URBs and skb) */
 	for (i = 0; i < IU_MAX_RX_URBS; i++) {
-		purb_t purb = &(self->rx_urb[i]);
-		struct sk_buff *skb = (struct sk_buff *) purb->context;
+		struct urb *urb = &(self->rx_urb[i]);
+		struct sk_buff *skb = (struct sk_buff *) urb->context;
 		/* Cancel the receive command */
-		usb_unlink_urb(purb);
+		usb_unlink_urb(urb);
 		/* The skb is ours, free it */
 		if(skb) {
 			dev_kfree_skb(skb);
-			purb->context = NULL;
+			urb->context = NULL;
 		}
 	}
 	/* Cancel Tx and speed URB */
diff -u --recursive --new-file v2.5.1/linux/drivers/net/irda/irtty.c linux/drivers/net/irda/irtty.c
--- v2.5.1/linux/drivers/net/irda/irtty.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/net/irda/irtty.c	Thu Jan  3 12:20:12 2002
@@ -32,7 +32,6 @@
 #include <linux/if_arp.h>
 #include <linux/rtnetlink.h>
 
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 
 #include <net/irda/irda.h>
@@ -173,7 +172,7 @@
 
 	/* Give self a name */
 	sprintf(name, "%s%d", tty->driver.name,
-		MINOR(tty->device) - tty->driver.minor_start +
+		minor(tty->device) - tty->driver.minor_start +
 		tty->driver.name_base);
 
 	hashbin_insert(irtty, (irda_queue_t *) self, (int) self, NULL);
@@ -911,7 +910,7 @@
 
 	/* Give self a hardware name */
 	sprintf(hwname, "%s%d", tty->driver.name,
-		MINOR(tty->device) - tty->driver.minor_start +
+		minor(tty->device) - tty->driver.minor_start +
 		tty->driver.name_base);
 
 	/* 
diff -u --recursive --new-file v2.5.1/linux/drivers/net/jazzsonic.c linux/drivers/net/jazzsonic.c
--- v2.5.1/linux/drivers/net/jazzsonic.c	Sun Sep  9 10:43:01 2001
+++ linux/drivers/net/jazzsonic.c	Sun Dec 30 10:31:51 2001
@@ -29,7 +29,6 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/pgtable.h>
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/jazz.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/net/macsonic.c linux/drivers/net/macsonic.c
--- v2.5.1/linux/drivers/net/macsonic.c	Tue Oct 16 21:56:29 2001
+++ linux/drivers/net/macsonic.c	Sun Dec 30 10:31:51 2001
@@ -40,7 +40,6 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/pgtable.h>
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/hwtest.h>
 #include <asm/dma.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/net/pcmcia/fmvj18x_cs.c linux/drivers/net/pcmcia/fmvj18x_cs.c
--- v2.5.1/linux/drivers/net/pcmcia/fmvj18x_cs.c	Tue Nov 13 09:02:30 2001
+++ linux/drivers/net/pcmcia/fmvj18x_cs.c	Sun Dec 30 09:40:59 2001
@@ -1247,3 +1247,4 @@
     }
     restore_flags(flags);
 }
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.1/linux/drivers/net/sgiseeq.c linux/drivers/net/sgiseeq.c
--- v2.5.1/linux/drivers/net/sgiseeq.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/sgiseeq.c	Sun Dec 30 10:31:51 2001
@@ -16,7 +16,6 @@
 #include <linux/delay.h>
 
 #include <asm/io.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/page.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/net/slip.c linux/drivers/net/slip.c
--- v2.5.1/linux/drivers/net/slip.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/net/slip.c	Thu Jan  3 12:20:12 2002
@@ -739,7 +739,7 @@
 			break;
 
 		if (slp->ctrl.leased) {
-			if (slp->ctrl.line != line)
+			if (!kdev_same(slp->ctrl.line, line))
 				continue;
 			if (slp->ctrl.tty)
 				return NULL;
@@ -753,7 +753,7 @@
 			continue;
 
 		if (current->pid == slp->ctrl.pid) {
-			if (slp->ctrl.line == line && score < 3) {
+			if (kdev_same(slp->ctrl.line, line) && score < 3) {
 				sel = i;
 				score = 3;
 				continue;
@@ -764,7 +764,7 @@
 			}
 			continue;
 		}
-		if (slp->ctrl.line == line && score < 1) {
+		if (kdev_same(slp->ctrl.line, line) && score < 1) {
 			sel = i;
 			score = 1;
 			continue;
@@ -944,7 +944,7 @@
 	tty->disc_data = 0;
 	sl->tty = NULL;
 	if (!sl->leased)
-		sl->line = 0;
+		sl->line = NODEV;
 
 	/* VSV = very important to remove timers */
 #ifdef CONFIG_SLIP_SMART
@@ -1394,7 +1394,7 @@
 		 */
 		do {
 			if (busy) {
-				current->counter = 0;
+				current->time_slice = 0;
 				schedule();
 			}
 
diff -u --recursive --new-file v2.5.1/linux/drivers/net/strip.c linux/drivers/net/strip.c
--- v2.5.1/linux/drivers/net/strip.c	Fri Nov  9 14:02:24 2001
+++ linux/drivers/net/strip.c	Sun Dec 30 10:31:51 2001
@@ -87,7 +87,6 @@
 #include <linux/init.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/segment.h>
 #include <asm/bitops.h>
 
 /*
diff -u --recursive --new-file v2.5.1/linux/drivers/net/wan/cosa.c linux/drivers/net/wan/cosa.c
--- v2.5.1/linux/drivers/net/wan/cosa.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/net/wan/cosa.c	Thu Jan  3 12:20:12 2002
@@ -940,12 +940,12 @@
 	unsigned long flags;
 	int n;
 
-	if ((n=MINOR(file->f_dentry->d_inode->i_rdev)>>CARD_MINOR_BITS)
+	if ((n=minor(file->f_dentry->d_inode->i_rdev)>>CARD_MINOR_BITS)
 		>= nr_cards)
 		return -ENODEV;
 	cosa = cosa_cards+n;
 
-	if ((n=MINOR(file->f_dentry->d_inode->i_rdev)
+	if ((n=minor(file->f_dentry->d_inode->i_rdev)
 		& ((1<<CARD_MINOR_BITS)-1)) >= cosa->nchannels)
 		return -ENODEV;
 	chan = cosa->chan + n;
diff -u --recursive --new-file v2.5.1/linux/drivers/net/wan/lapbether.c linux/drivers/net/wan/lapbether.c
--- v2.5.1/linux/drivers/net/wan/lapbether.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/net/wan/lapbether.c	Sun Dec 30 10:31:51 2001
@@ -32,7 +32,6 @@
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/net/wan/lmc/lmc_main.c linux/drivers/net/wan/lmc/lmc_main.c
--- v2.5.1/linux/drivers/net/wan/lmc/lmc_main.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/net/wan/lmc/lmc_main.c	Sun Dec 30 10:31:51 2001
@@ -50,7 +50,6 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <asm/segment.h>
 #include <linux/init.h>
 
 #if LINUX_VERSION_CODE < 0x20155
diff -u --recursive --new-file v2.5.1/linux/drivers/net/wan/lmc/lmc_media.c linux/drivers/net/wan/lmc/lmc_media.c
--- v2.5.1/linux/drivers/net/wan/lmc/lmc_media.c	Tue Mar  6 19:44:36 2001
+++ linux/drivers/net/wan/lmc/lmc_media.c	Sun Dec 30 10:31:51 2001
@@ -12,7 +12,6 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
-#include <asm/segment.h>
 //#include <asm/smp.h>
 
 #if LINUX_VERSION_CODE < 0x20155
diff -u --recursive --new-file v2.5.1/linux/drivers/net/wan/lmc/lmc_proto.c linux/drivers/net/wan/lmc/lmc_proto.c
--- v2.5.1/linux/drivers/net/wan/lmc/lmc_proto.c	Tue Mar  6 19:44:36 2001
+++ linux/drivers/net/wan/lmc/lmc_proto.c	Sun Dec 30 10:31:51 2001
@@ -30,7 +30,6 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
-#include <asm/segment.h>
 #include <asm/smp.h>
 
 #include <linux/in.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/net/wan/sdla_chdlc.c linux/drivers/net/wan/sdla_chdlc.c
--- v2.5.1/linux/drivers/net/wan/sdla_chdlc.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/net/wan/sdla_chdlc.c	Thu Jan  3 12:20:12 2002
@@ -3933,7 +3933,7 @@
 	
 	if (!tty->driver_data){
 		int port;
-		port = MINOR(tty->device) - tty->driver.minor_start;
+		port = minor(tty->device) - tty->driver.minor_start;
 		if ((port < 0) || (port >= NR_PORTS)) 
 			return -ENODEV;
 		
diff -u --recursive --new-file v2.5.1/linux/drivers/net/wireless/airo.c linux/drivers/net/wireless/airo.c
--- v2.5.1/linux/drivers/net/wireless/airo.c	Fri Nov  9 13:41:42 2001
+++ linux/drivers/net/wireless/airo.c	Sun Dec 30 10:31:51 2001
@@ -19,7 +19,6 @@
 
 #include <linux/config.h>
 #include <linux/version.h>
-#include <asm/segment.h>
 #include <linux/init.h>
 
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- v2.5.1/linux/drivers/pcmcia/ds.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/pcmcia/ds.c	Tue Jan  1 11:51:31 2002
@@ -558,7 +558,7 @@
 
 static int ds_open(struct inode *inode, struct file *file)
 {
-    socket_t i = MINOR(inode->i_rdev);
+    socket_t i = minor(inode->i_rdev);
     socket_info_t *s;
     user_info_t *user;
 
@@ -590,7 +590,7 @@
 
 static int ds_release(struct inode *inode, struct file *file)
 {
-    socket_t i = MINOR(inode->i_rdev);
+    socket_t i = minor(inode->i_rdev);
     socket_info_t *s;
     user_info_t *user, **link;
 
@@ -622,7 +622,7 @@
 static ssize_t ds_read(struct file *file, char *buf,
 		       size_t count, loff_t *ppos)
 {
-    socket_t i = MINOR(file->f_dentry->d_inode->i_rdev);
+    socket_t i = minor(file->f_dentry->d_inode->i_rdev);
     socket_info_t *s;
     user_info_t *user;
 
@@ -651,7 +651,7 @@
 static ssize_t ds_write(struct file *file, const char *buf,
 			size_t count, loff_t *ppos)
 {
-    socket_t i = MINOR(file->f_dentry->d_inode->i_rdev);
+    socket_t i = minor(file->f_dentry->d_inode->i_rdev);
     socket_info_t *s;
     user_info_t *user;
 
@@ -684,7 +684,7 @@
 /* No kernel lock - fine */
 static u_int ds_poll(struct file *file, poll_table *wait)
 {
-    socket_t i = MINOR(file->f_dentry->d_inode->i_rdev);
+    socket_t i = minor(file->f_dentry->d_inode->i_rdev);
     socket_info_t *s;
     user_info_t *user;
 
@@ -707,7 +707,7 @@
 static int ds_ioctl(struct inode * inode, struct file * file,
 		    u_int cmd, u_long arg)
 {
-    socket_t i = MINOR(inode->i_rdev);
+    socket_t i = minor(inode->i_rdev);
     socket_info_t *s;
     u_int size;
     int ret, err;
diff -u --recursive --new-file v2.5.1/linux/drivers/pcmcia/i82365.c linux/drivers/pcmcia/i82365.c
--- v2.5.1/linux/drivers/pcmcia/i82365.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/pcmcia/i82365.c	Sun Dec 30 10:31:51 2001
@@ -49,7 +49,6 @@
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/bitops.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 
 #include <pcmcia/version.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/pcmcia/tcic.c linux/drivers/pcmcia/tcic.c
--- v2.5.1/linux/drivers/pcmcia/tcic.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/pcmcia/tcic.c	Sun Dec 30 10:31:51 2001
@@ -39,7 +39,6 @@
 
 #include <asm/io.h>
 #include <asm/bitops.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/s390/block/dasd_int.h linux/drivers/s390/block/dasd_int.h
--- v2.5.1/linux/drivers/s390/block/dasd_int.h	Sun Sep 30 12:26:07 2001
+++ linux/drivers/s390/block/dasd_int.h	Mon Dec 31 17:56:19 2001
@@ -88,7 +88,6 @@
 	major:D_MAJOR, \
 	major_name:D_NAME, \
 	minor_shift:D_PARTN_BITS, \
-	max_p:1 << D_PARTN_BITS, \
 	max_nr:D_PER_MAJOR, \
 	nr_real:D_PER_MAJOR,
 static inline struct request * 
@@ -111,7 +110,6 @@
 	major:D_MAJOR, \
 	major_name:D_NAME, \
 	minor_shift:D_PARTN_BITS, \
-	max_p:1 << D_PARTN_BITS, \
 	nr_real:D_PER_MAJOR, \
         fops:&dasd_device_operations, 
 static inline struct request * 
diff -u --recursive --new-file v2.5.1/linux/drivers/s390/char/tuball.c linux/drivers/s390/char/tuball.c
--- v2.5.1/linux/drivers/s390/char/tuball.c	Thu Oct 11 09:43:29 2001
+++ linux/drivers/s390/char/tuball.c	Tue Dec 25 15:39:20 2001
@@ -84,7 +84,6 @@
 	tub3270_con_write,	/* write */
 	NULL,			/* read */
 	tub3270_con_device,	/* device */
-	NULL,			/* wait_key */
 	tub3270_con_unblank,	/* unblank */
 	NULL,			/* setup */
 	CON_PRINTBUFFER,	/* flags */
diff -u --recursive --new-file v2.5.1/linux/drivers/s390/s390io.c linux/drivers/s390/s390io.c
--- v2.5.1/linux/drivers/s390/s390io.c	Thu Nov 22 10:41:14 2001
+++ linux/drivers/s390/s390io.c	Sun Dec 30 16:54:29 2001
@@ -6,6 +6,7 @@
  *    Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
  *                             IBM Corporation
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
+ *               Cornelia Huck (cohuck@de.ibm.com) 
  *    ChangeLog: 01/07/2001 Blacklist cleanup (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
  *               01/04/2001 Holger Smolinski (smolinsk@de.ibm.com)
  *                          Fixed lost interrupts and do_adapter_IO
@@ -108,7 +109,9 @@
 static void s390_process_subchannels( void);
 static void s390_device_recognition_all( void);
 static void s390_device_recognition_irq( int irq);
+#ifdef CONFIG_PROC_FS
 static void s390_redo_validation(void);
+#endif
 static int  s390_validate_subchannel( int irq, int enable);
 static int  s390_SenseID( int irq, senseid_t *sid, __u8 lpm);
 static int  s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid);
@@ -117,7 +120,9 @@
 static int  enable_subchannel( unsigned int irq);
 static int  disable_subchannel( unsigned int irq);
 
+#ifdef CONFIG_PROC_FS
 static int chan_proc_init( void );
+#endif 
 
 static inline void do_adapter_IO( __u32 intparm );
 
@@ -666,6 +671,7 @@
 	
 __setup("cio_notoper_msg=", cio_notoper_setup);
 
+#ifdef CONFIG_PROC_FS
 static int __init cio_proc_devinfo_setup(char *parm)
 {
 	if (!strcmp(parm, "yes")) {
@@ -673,13 +679,14 @@
 	} else if (!strcmp(parm, "no")) {
 		cio_proc_devinfo = 0;
 	} else {
-		printk("cio_proc_devinfo_setup: invalid parameter '%s'\n",parm);
+		printk( KERN_ERR "cio_proc_devinfo_setup: invalid parameter '%s'\n",parm);
 	}
 
 	return 1;
 }
 
 __setup("cio_proc_devinfo=", cio_proc_devinfo_setup);
+#endif
 
 /*
  * register for adapter interrupts
@@ -4779,10 +4786,12 @@
 						
 					} 
 				}
+#ifdef CONFIG_PROC_FS
 				if (cio_proc_devinfo) 
 					if (irq < MAX_CIO_PROCFS_ENTRIES) {
 						cio_procfs_device_create(ioinfo[irq]->devno);
 				}
+#endif
 			}
 		}
 		irq++;
@@ -6523,10 +6532,11 @@
 				if ( ioinfo[irq]->ui.flags.oper == 0 )
 				{
 					 not_oper_handler_func_t nopfunc=ioinfo[irq]->nopfunc;
-					 
+#ifdef CONFIG_PROC_FS					 
 					 /* remove procfs entry */
 					 if (cio_proc_devinfo)
 						 cio_procfs_device_remove(dev_no);
+#endif
 					/*
 					 * If the device has gone
 					 *  call not oper handler        	
@@ -6573,12 +6583,13 @@
 								pdevreg->oper_func( irq, pdevreg );
 
 						} /* endif */
-
+#ifdef CONFIG_PROC_FS
 						/* add new procfs entry */
 						if (cio_proc_devinfo) 
 							if (highest_subchannel < MAX_CIO_PROCFS_ENTRIES) {
 								cio_procfs_device_create(ioinfo[irq]->devno);
 							}
+#endif
 					}
 					/*
 					 * ... it is and was operational, but
@@ -6586,23 +6597,26 @@
 					 */
 					else if ((ioinfo[irq]->devno != dev_no) && ( ioinfo[irq]->nopfunc != NULL ))   					
 					{
+#ifdef CONFIG_PROC_FS
 						int devno_old = ioinfo[irq]->devno;
+#endif
 						ioinfo[irq]->nopfunc( irq,
 						                      DEVSTAT_REVALIDATE );				
-
+#ifdef CONFIG_PROC_FS
 						/* remove old entry, add new */
 						if (cio_proc_devinfo) {
 							cio_procfs_device_remove(devno_old);
 							cio_procfs_device_create(ioinfo[irq]->devno);
 						}
+#endif
 					} /* endif */
 
 				} /* endif */
-
+#ifdef CONFIG_PROC_FS
 				/* get rid of dead procfs entries */
 				if (cio_proc_devinfo) 
 					cio_procfs_device_purge();
-
+#endif
 			} /* endif */
 
 			break;
@@ -6756,6 +6770,7 @@
 
 __initcall(cio_debug_init);
 
+#ifdef CONFIG_PROC_FS
 /* 
  * Display info on subchannels in /proc/subchannels. 
  * Adapted from procfs stuff in dasd.c by Cornelia Huck, 02/28/01.      
@@ -7163,19 +7178,19 @@
 				entry->cio_chpid_entry = create_proc_entry( "chpids", S_IFREG|S_IRUGO, entry->cio_device_entry);
 				entry->cio_chpid_entry->proc_fops = &cio_chpid_entry_file_ops;
 			} else {
-				printk("Error, could not allocate procfs structure!\n");
+				printk( KERN_WARNING "Error, could not allocate procfs structure!\n");
 				remove_proc_entry(buf, cio_procfs_deviceinfo_root);
 				kfree(entry);
 				rc = -ENOMEM;
 			}
 		} else {
-			printk("Error, could not allocate procfs structure!\n");
+			printk( KERN_WARNING "Error, could not allocate procfs structure!\n");
 			kfree(entry);
 			rc = -ENOMEM;
 		}
 
 	} else {
-		printk("Error, could not allocate procfs structure!\n");
+		printk( KERN_WARNING "Error, could not allocate procfs structure!\n");
 		rc = -ENOMEM;
 	}
 	return rc;
@@ -7370,7 +7385,7 @@
 	}
 	buffer[user_len]='\0';
 #ifdef CIO_DEBUG_IO
-	printk ("/proc/cio_ignore: '%s'\n", buffer);
+	printk ( KERN_DEBUG "/proc/cio_ignore: '%s'\n", buffer);
 #endif /* CIO_DEBUG_IO */
 	if (cio_debug_initialized)
 		debug_sprintf_event(cio_debug_msg_id, 2, "/proc/cio_ignore: '%s'\n",buffer);
@@ -7491,6 +7506,7 @@
 __initcall(cio_irq_proc_init);	
 
 /* end of procfs stuff */
+#endif
 
 schib_t *s390_get_schib( int irq )
 {
diff -u --recursive --new-file v2.5.1/linux/drivers/sbus/char/aurora.c linux/drivers/sbus/char/aurora.c
--- v2.5.1/linux/drivers/sbus/char/aurora.c	Tue Oct 30 15:08:11 2001
+++ linux/drivers/sbus/char/aurora.c	Sun Dec 30 10:31:51 2001
@@ -66,7 +66,6 @@
 #include <asm/irq.h>
 #include <asm/oplib.h>
 #include <asm/system.h>
-#include <asm/segment.h>
 #include <asm/bitops.h>
 #include <asm/kdebug.h>
 #include <asm/sbus.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/sbus/char/bpp.c linux/drivers/sbus/char/bpp.c
--- v2.5.1/linux/drivers/sbus/char/bpp.c	Thu Oct 11 09:43:29 2001
+++ linux/drivers/sbus/char/bpp.c	Sun Dec 30 10:31:51 2001
@@ -28,7 +28,6 @@
 
 #if defined(__i386__)
 # include <asm/system.h>
-# include <asm/segment.h>
 #endif
 
 #if defined(__sparc__)
diff -u --recursive --new-file v2.5.1/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c
--- v2.5.1/linux/drivers/sbus/char/sab82532.c	Wed Oct 17 14:16:39 2001
+++ linux/drivers/sbus/char/sab82532.c	Tue Dec 25 15:39:20 2001
@@ -361,10 +361,6 @@
 		writeb(SAB82532_CMDR_RMC, &info->regs->w.cmdr);
 	}
 
-#ifdef CONFIG_SERIAL_CONSOLE
-	if (info->is_console)
-		wake_up(&keypress_wait);
-#endif
 	if (!tty)
 		return;
 
@@ -2541,13 +2537,6 @@
 	sab82532_tec_wait(info);
 }
 
-static int
-sab82532_console_wait_key(struct console *con)
-{
-	sleep_on(&keypress_wait);
-	return 0;
-}
-
 static kdev_t
 sab82532_console_device(struct console *con)
 {
@@ -2622,7 +2611,6 @@
 	name:		"ttyS",
 	write:		sab82532_console_write,
 	device:		sab82532_console_device,
-	wait_key:	sab82532_console_wait_key,
 	setup:		sab82532_console_setup,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
diff -u --recursive --new-file v2.5.1/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c
--- v2.5.1/linux/drivers/sbus/char/su.c	Tue Nov 13 09:16:05 2001
+++ linux/drivers/sbus/char/su.c	Tue Dec 25 15:39:20 2001
@@ -2854,40 +2854,6 @@
 	su_outb(info, UART_IER, ier);
 }
 
-/*
- *	Receive character from the serial port
- */
-static int
-serial_console_wait_key(struct console *co)
-{
-	struct su_struct *info;
-	int ier;
-	int lsr;
-	int c;
-
-	info = su_table + co->index;
-
-	/*
-	 *	First save the IER then disable the interrupts so
-	 *	that the real driver for the port does not get the
-	 *	character.
-	 */
-	ier = su_inb(info, UART_IER);
-	su_outb(info, UART_IER, 0x00);
-
-	do {
-		lsr = su_inb(info, UART_LSR);
-	} while (!(lsr & UART_LSR_DR));
-	c = su_inb(info, UART_RX);
-
-	/*
-	 *	Restore the interrupts
-	 */
-	su_outb(info, UART_IER, ier);
-
-	return c;
-}
-
 static kdev_t
 serial_console_device(struct console *c)
 {
@@ -3013,7 +2979,6 @@
 	name:		"ttyS",
 	write:		serial_console_write,
 	device:		serial_console_device,
-	wait_key:	serial_console_wait_key,
 	setup:		serial_console_setup,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
diff -u --recursive --new-file v2.5.1/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c
--- v2.5.1/linux/drivers/sbus/char/sunkbd.c	Sun Sep 16 21:22:50 2001
+++ linux/drivers/sbus/char/sunkbd.c	Tue Dec 25 15:39:20 2001
@@ -82,16 +82,6 @@
 
 struct l1a_kbd_state l1a_state;
 
-#ifndef CONFIG_PCI
-DECLARE_WAIT_QUEUE_HEAD(keypress_wait);
-#endif
-
-int keyboard_wait_for_keypress(struct console *co)
-{
-	sleep_on(&keypress_wait);
-	return 0;
-}
-
 static spinlock_t sunkbd_lock = SPIN_LOCK_UNLOCKED;
 
 /*
@@ -629,7 +619,6 @@
 
 static void put_queue(int ch)
 {
-	wake_up(&keypress_wait);
 	if (tty) {
 		tty_insert_flip_char(tty, ch, 0);
 		con_schedule_flip(tty);
@@ -638,7 +627,6 @@
 
 static void puts_queue(char *cp)
 {
-	wake_up(&keypress_wait);
 	if (!tty)
 		return;
 
diff -u --recursive --new-file v2.5.1/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c
--- v2.5.1/linux/drivers/sbus/char/zs.c	Tue Oct 30 15:08:11 2001
+++ linux/drivers/sbus/char/zs.c	Tue Dec 25 15:39:20 2001
@@ -532,8 +532,6 @@
 				/* Continue execution... */
 				return;
 			}
-			/* It is a 'keyboard interrupt' ;-) */
-			wake_up(&keypress_wait);
 		}
 #ifndef __sparc_v9__
 		/* Look for kgdb 'stop' character, consult the gdb
@@ -2761,13 +2759,6 @@
 #endif
 }
 
-static int
-zs_console_wait_key(struct console *con)
-{
-	sleep_on(&keypress_wait);
-	return 0;
-}
-
 static kdev_t zs_console_device(struct console *con)
 {
 	return MKDEV(TTY_MAJOR, 64 + con->index);
@@ -2845,7 +2836,6 @@
 	name:		"ttyS",
 	write:		zs_console_write,
 	device:		zs_console_device,
-	wait_key:	zs_console_wait_key,
 	setup:		zs_console_setup,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c
--- v2.5.1/linux/drivers/scsi/BusLogic.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/BusLogic.c	Thu Dec 27 08:17:43 2001
@@ -4106,7 +4106,7 @@
   BusLogic_HostAdapter_T *HostAdapter =
     (BusLogic_HostAdapter_T *) Disk->device->host->hostdata;
   BIOS_DiskParameters_T *DiskParameters = (BIOS_DiskParameters_T *) Parameters;
-  struct buffer_head *BufferHead;
+  unsigned char *buf;
   if (HostAdapter->ExtendedTranslationEnabled &&
       Disk->capacity >= 2*1024*1024 /* 1 GB in 512 byte sectors */)
     {
@@ -4128,20 +4128,16 @@
     }
   DiskParameters->Cylinders =
     Disk->capacity / (DiskParameters->Heads * DiskParameters->Sectors);
-  /*
-    Attempt to read the first 1024 bytes from the disk device.
-  */
-  BufferHead = bread(MKDEV(MAJOR(Device), MINOR(Device) & ~0x0F), 0, 1024);
-  if (BufferHead == NULL) return 0;
+  buf = scsi_bios_ptable(Device);
+  if (buf == NULL) return 0;
   /*
     If the boot sector partition table flag is valid, search for a partition
     table entry whose end_head matches one of the standard BusLogic geometry
     translations (64/32, 128/32, or 255/63).
   */
-  if (*(unsigned short *) (BufferHead->b_data + 0x1FE) == 0xAA55)
+  if (*(unsigned short *) (buf+64) == 0xAA55)
     {
-      PartitionTable_T *FirstPartitionEntry =
-	(PartitionTable_T *) (BufferHead->b_data + 0x1BE);
+      PartitionTable_T *FirstPartitionEntry = (PartitionTable_T *) buf;
       PartitionTable_T *PartitionEntry = FirstPartitionEntry;
       int SavedCylinders = DiskParameters->Cylinders, PartitionNumber;
       unsigned char PartitionEntryEndHead, PartitionEntryEndSector;
@@ -4195,7 +4191,7 @@
 			   DiskParameters->Heads, DiskParameters->Sectors);
 	}
     }
-  brelse(BufferHead);
+  kfree(buf);
   return 0;
 }
 
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/BusLogic.h linux/drivers/scsi/BusLogic.h
--- v2.5.1/linux/drivers/scsi/BusLogic.h	Thu Jul 19 21:07:57 2001
+++ linux/drivers/scsi/BusLogic.h	Tue Jan  1 18:57:58 2002
@@ -1531,7 +1531,7 @@
 void BusLogic_AcquireHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter,
 				       ProcessorFlags_T *ProcessorFlags)
 {
-  spin_lock_irqsave(&io_request_lock, *ProcessorFlags);
+  spin_lock_irqsave(&HostAdapter->SCSI_Host->host_lock, *ProcessorFlags);
 }
 
 
@@ -1544,7 +1544,7 @@
 void BusLogic_ReleaseHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter,
 				       ProcessorFlags_T *ProcessorFlags)
 {
-  spin_unlock_irqrestore(&io_request_lock, *ProcessorFlags);
+  spin_unlock_irqrestore(&HostAdapter->SCSI_Host->host_lock, *ProcessorFlags);
 }
 
 
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
--- v2.5.1/linux/drivers/scsi/advansys.c	Fri Nov  9 14:05:06 2001
+++ linux/drivers/scsi/advansys.c	Tue Jan  1 18:56:19 2002
@@ -3610,36 +3610,6 @@
 #define ASC_MIN(a, b) (((a) < (b)) ? (a) : (b))
 #endif /* CONFIG_PROC_FS */
 
-/*
- * XXX - Release and acquire the io_request_lock. These macros are needed
- * because the 2.4 kernel SCSI mid-level driver holds the 'io_request_lock'
- * on entry to SCSI low-level drivers.
- *
- * These definitions and all code that uses code should be removed when the
- * SCSI mid-level driver no longer holds the 'io_request_lock' on entry to
- * SCSI low-level driver detect, queuecommand, and reset entrypoints.
- *
- * The interrupt flags values doesn't matter in the macros because the
- * SCSI mid-level will save and restore the flags values before and after
- * calling advansys_detect, advansys_queuecommand, and advansys_reset where
- * these macros are used. We do want interrupts enabled after the lock is
- * released so an explicit sti() is done. The driver only needs interrupts
- * disabled when it acquires the per board lock.
- */
-#define ASC_UNLOCK_IO_REQUEST_LOCK \
-    { \
-        ulong flags; /* flags value not needed, cf. comment above. */ \
-        save_flags(flags); \
-        spin_unlock_irqrestore(&io_request_lock, flags); \
-        sti(); /* enable interrupts */ \
-    }
-
-#define ASC_LOCK_IO_REQUEST_LOCK \
-    { \
-        ulong flags; /* flags value not needed, cf. comment above. */ \
-        spin_lock_irqsave(&io_request_lock, flags); \
-    }
-
 /* Asc Library return codes */
 #define ASC_TRUE        1
 #define ASC_FALSE       0
@@ -4084,7 +4054,6 @@
         ADVEEP_38C1600_CONFIG adv_38C1600_eep;  /* 38C1600 EEPROM config. */
     } eep_config;
     ulong                last_reset;            /* Saved last reset time */
-    spinlock_t lock;                            /* Board spinlock */
 #ifdef CONFIG_PROC_FS
     /* /proc/scsi/advansys/[0...] */
     char                 *prtbuf;               /* /proc print buffer */
@@ -4604,13 +4573,6 @@
 
     ASC_DBG(1, "advansys_detect: begin\n");
 
-    /*
-     * XXX - Remove this comment and the next line when SCSI mid-level
-     * no longer acquires 'io_request_lock' before calling the SCSI
-     * low-level detect entrypoint.
-     */
-    ASC_UNLOCK_IO_REQUEST_LOCK
-
 #if ASC_LINUX_KERNEL24
     tpnt->proc_name = "advansys";
 #elif ASC_LINUX_KERNEL22
@@ -4837,9 +4799,6 @@
             memset(boardp, 0, sizeof(asc_board_t));
             boardp->id = asc_board_count - 1;
 
-            /* Initialize spinlock. */
-            boardp->lock = SPIN_LOCK_UNLOCKED;
-
             /*
              * Handle both narrow and wide boards.
              *
@@ -5723,13 +5682,6 @@
         }
     }
 
-    /*
-     * XXX - Remove this comment and the next line when SCSI mid-level
-     * no longer acquires 'io_request_lock' before calling the SCSI
-     * low-level detect entrypoint.
-     */
-    ASC_LOCK_IO_REQUEST_LOCK
-
     ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n", asc_board_count);
     return asc_board_count;
 }
@@ -5893,14 +5845,7 @@
     boardp = ASC_BOARDP(shp);
     ASC_STATS(shp, queuecommand);
 
-    /*
-     * XXX - Remove this comment and the next line when SCSI mid-level
-     * no longer acquires 'io_request_lock' before calling the SCSI
-     * low-level queuecommand entrypoint.
-     */
-    ASC_UNLOCK_IO_REQUEST_LOCK
-
-    spin_lock_irqsave(&boardp->lock, flags);
+    spin_lock_irqsave(&shp->host_lock, flags);
 
     /*
      * Block new commands while handling a reset or abort request.
@@ -5917,7 +5862,7 @@
          * handling.
          */
         asc_enqueue(&boardp->done, scp, ASC_BACK);
-        spin_unlock_irqrestore(&boardp->lock, flags);
+        spin_unlock_irqrestore(&shp->host_lock, flags);
         return 0;
     }
 
@@ -5961,15 +5906,7 @@
         break;
     }
 
-    spin_unlock_irqrestore(&boardp->lock, flags);
-
-    /*
-     * XXX - Remove this comment and the next line when SCSI mid-level
-     * no longer acquires 'io_request_lock' before calling the SCSI
-     * low-level queuecommand entrypoint.
-     */
-    ASC_LOCK_IO_REQUEST_LOCK
-
+    spin_unlock_irqrestore(&shp->host_lock, flags);
     return 0;
 }
 
@@ -6015,20 +5952,13 @@
     /*
      * Check for re-entrancy.
      */
-    spin_lock_irqsave(&boardp->lock, flags);
+    spin_lock_irqsave(&shp->host_lock, flags);
     if (boardp->flags & ASC_HOST_IN_RESET) {
-        spin_unlock_irqrestore(&boardp->lock, flags);
+        spin_unlock_irqrestore(&shp->host_lock, flags);
         return FAILED;
     }
     boardp->flags |= ASC_HOST_IN_RESET;
-    spin_unlock_irqrestore(&boardp->lock, flags);
-
-    /*
-     * XXX - Remove this comment and the next line when SCSI mid-level
-     * no longer acquires 'io_request_lock' before calling the SCSI
-     * low-level reset entrypoint.
-     */
-    ASC_UNLOCK_IO_REQUEST_LOCK
+    spin_unlock_irqrestore(&shp->host_lock, flags);
 
     if (ASC_NARROW_BOARD(boardp)) {
         /*
@@ -6063,7 +5993,7 @@
         /*
          * Acquire the board lock.
          */
-        spin_lock_irqsave(&boardp->lock, flags);
+        spin_lock_irqsave(&shp->host_lock, flags);
 
     } else {
         /*
@@ -6094,7 +6024,7 @@
          * Acquire the board lock and ensure all requests completed by the
          * microcode have been processed by calling AdvISR().
          */
-        spin_lock_irqsave(&boardp->lock, flags);
+        spin_lock_irqsave(&shp->host_lock, flags);
         (void) AdvISR(adv_dvc_varp);
     }
 
@@ -6160,7 +6090,7 @@
     boardp->flags &= ~ASC_HOST_IN_RESET;
 
     /* Release the board. */
-    spin_unlock_irqrestore(&boardp->lock, flags);
+    spin_unlock_irqrestore(&shp->host_lock, flags);
 
     /*
      * Complete all the 'done_scp' requests.
@@ -6169,13 +6099,6 @@
         asc_scsi_done_list(done_scp);
     }
 
-    /*
-     * XXX - Remove this comment and the next line when SCSI mid-level
-     * no longer acquires 'io_request_lock' before calling the SCSI
-     * low-level reset entrypoint.
-     */
-    ASC_LOCK_IO_REQUEST_LOCK
-
     ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
 
     return ret;
@@ -6344,10 +6267,11 @@
      * AscISR() will call asc_isr_callback().
      */
     for (i = 0; i < asc_board_count; i++) {
-        boardp = ASC_BOARDP(asc_host[i]);
+	struct Scsi_Host *shp = asc_host[i];
+        boardp = ASC_BOARDP(shp);
         ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
             i, (ulong) boardp);
-        spin_lock_irqsave(&boardp->lock, flags);
+        spin_lock_irqsave(&shp->host_lock, flags);
         if (ASC_NARROW_BOARD(boardp)) {
             /*
              * Narrow Board
@@ -6403,7 +6327,7 @@
                 }
             }
         }
-        spin_unlock_irqrestore(&boardp->lock, flags);
+        spin_unlock_irqrestore(&shp->host_lock, flags);
     }
 
     /*
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- v2.5.1/linux/drivers/scsi/aha152x.c	Fri Nov  9 14:05:06 2001
+++ linux/drivers/scsi/aha152x.c	Tue Jan  1 18:57:58 2002
@@ -1349,9 +1349,9 @@
 
 		printk(KERN_INFO "aha152x%d: trying software interrupt, ", HOSTNO);
 		SETPORT(DMACNTRL0, SWINT|INTEN);
-		spin_unlock_irq(&io_request_lock);
+		spin_unlock_irq(&shpnt->host_lock);
 		mdelay(1000);
-		spin_lock_irq(&io_request_lock);
+		spin_lock_irq(&shpnt->host_lock);
 		free_irq(shpnt->irq, shpnt);
 
 		if (!HOSTDATA(shpnt)->swint) {
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c
--- v2.5.1/linux/drivers/scsi/aha1542.c	Fri Oct 12 15:35:53 2001
+++ linux/drivers/scsi/aha1542.c	Sat Dec 29 11:17:37 2001
@@ -67,10 +67,10 @@
 		       int nseg,
 		       int badseg)
 {
-	printk(KERN_CRIT "sgpnt[%d:%d] addr %p/0x%lx length %d\n",
+	printk(KERN_CRIT "sgpnt[%d:%d] page %p/0x%lx length %d\n",
 	       badseg, nseg,
-	       sgpnt[badseg].address,
-	       SCSI_PA(sgpnt[badseg].address),
+	       page_address(sgpnt[badseg].page) + sgpnt[badseg].offset,
+	       (unsigned long)page_to_bus(sgpnt[badseg].page) + sgpnt[badseg].offset,
 	       sgpnt[badseg].length);
 
 	/*
@@ -176,7 +176,7 @@
 
 static void setup_mailboxes(int base_io, struct Scsi_Host *shpnt);
 static int aha1542_restart(struct Scsi_Host *shost);
-static void aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs);
+static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id, struct pt_regs *regs);
 static void do_aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs);
 
 #define aha1542_intr_reset(base)  outb(IRST, CONTROL(base))
@@ -419,30 +419,30 @@
 static void do_aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
 {
 	unsigned long flags;
+	struct Scsi_Host *shost;
+
+	shost = aha_host[irq - 9];
+	if (!shost)
+		panic("Splunge!");
 
-	spin_lock_irqsave(&io_request_lock, flags);
-	aha1542_intr_handle(irq, dev_id, regs);
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_lock_irqsave(&shost->host_lock, flags);
+	aha1542_intr_handle(shost, dev_id, regs);
+	spin_unlock_irqrestore(&shost->host_lock, flags);
 }
 
 /* A "high" level interrupt handler */
-static void aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
+static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id, struct pt_regs *regs)
 {
 	void (*my_done) (Scsi_Cmnd *) = NULL;
 	int errstatus, mbi, mbo, mbistatus;
 	int number_serviced;
 	unsigned long flags;
-	struct Scsi_Host *shost;
 	Scsi_Cmnd *SCtmp;
 	int flag;
 	int needs_restart;
 	struct mailbox *mb;
 	struct ccb *ccb;
 
-	shost = aha_host[irq - 9];
-	if (!shost)
-		panic("Splunge!");
-
 	mb = HOSTDATA(shost)->mb;
 	ccb = HOSTDATA(shost)->ccb;
 
@@ -542,7 +542,7 @@
 		}
 		my_done = SCtmp->scsi_done;
 		if (SCtmp->host_scribble) {
-			scsi_free(SCtmp->host_scribble, 512);
+			kfree(SCtmp->host_scribble);
 			SCtmp->host_scribble = 0;
 		}
 		/* Fetch the sense data, and tuck it away, in the required slot.  The
@@ -703,18 +703,19 @@
 #endif
 		int i;
 		ccb[mbo].op = 2;	/* SCSI Initiator Command  w/scatter-gather */
-		SCpnt->host_scribble = (unsigned char *) scsi_malloc(512);
+		SCpnt->host_scribble = (unsigned char *) kmalloc(512, GFP_DMA);
 		sgpnt = (struct scatterlist *) SCpnt->request_buffer;
 		cptr = (struct chain *) SCpnt->host_scribble;
 		if (cptr == NULL)
 			panic("aha1542.c: unable to allocate DMA memory\n");
 		for (i = 0; i < SCpnt->use_sg; i++) {
 			if (sgpnt[i].length == 0 || SCpnt->use_sg > 16 ||
-			    (((int) sgpnt[i].address) & 1) || (sgpnt[i].length & 1)) {
+			    (((int) sgpnt[i].offset) & 1) || (sgpnt[i].length & 1)) {
 				unsigned char *ptr;
 				printk(KERN_CRIT "Bad segment list supplied to aha1542.c (%d, %d)\n", SCpnt->use_sg, i);
 				for (i = 0; i < SCpnt->use_sg; i++) {
-					printk(KERN_CRIT "%d: %p %d\n", i, sgpnt[i].address,
+					printk(KERN_CRIT "%d: %p %d\n", i,
+					       page_address(sgpnt[i].page) + sgpnt[i].offset,
 					       sgpnt[i].length);
 				};
 				printk(KERN_CRIT "cptr %x: ", (unsigned int) cptr);
@@ -723,8 +724,8 @@
 					printk("%02x ", ptr[i]);
 				panic("Foooooooood fight!");
 			};
-			any2scsi(cptr[i].dataptr, SCSI_PA(sgpnt[i].address));
-			if (SCSI_PA(sgpnt[i].address + sgpnt[i].length - 1) > ISA_DMA_THRESHOLD)
+			any2scsi(cptr[i].dataptr, page_to_bus(sgpnt[i].page) + sgpnt[i].offset);
+			if (page_to_bus(sgpnt[i].page) + sgpnt[i].offset + sgpnt[i].length - 1 > ISA_DMA_THRESHOLD)
 				BAD_SG_DMA(SCpnt, sgpnt, SCpnt->use_sg, i);
 			any2scsi(cptr[i].datalen, sgpnt[i].length);
 		};
@@ -1442,7 +1443,7 @@
 			Scsi_Cmnd *SCtmp;
 			SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
 			if (SCtmp->host_scribble) {
-				scsi_free(SCtmp->host_scribble, 512);
+				kfree(SCtmp->host_scribble);
 				SCtmp->host_scribble = NULL;
 			}
 			HOSTDATA(SCpnt->host)->SCint[i] = NULL;
@@ -1474,9 +1475,9 @@
 	 * check for timeout, and if we are doing something like this
 	 * we are pretty desperate anyways.
 	 */
-	spin_unlock_irq(&io_request_lock);
+	spin_unlock_irq(&SCpnt->host->host_lock);
 	scsi_sleep(4 * HZ);
-	spin_lock_irq(&io_request_lock);
+	spin_lock_irq(&SCpnt->host->host_lock);
 
 	WAIT(STATUS(SCpnt->host->io_port),
 	     STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
@@ -1505,7 +1506,7 @@
 				continue;
 			}
 			if (SCtmp->host_scribble) {
-				scsi_free(SCtmp->host_scribble, 512);
+				kfree(SCtmp->host_scribble);
 				SCtmp->host_scribble = NULL;
 			}
 			HOSTDATA(SCpnt->host)->SCint[i] = NULL;
@@ -1538,9 +1539,9 @@
 	 * check for timeout, and if we are doing something like this
 	 * we are pretty desperate anyways.
 	 */
-	spin_unlock_irq(&io_request_lock);
+	spin_unlock_irq(&SCpnt->host->host_lock);
 	scsi_sleep(4 * HZ);
-	spin_lock_irq(&io_request_lock);
+	spin_lock_irq(&SCpnt->host->host_lock);
 
 	WAIT(STATUS(SCpnt->host->io_port),
 	     STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
@@ -1574,7 +1575,7 @@
 				continue;
 			}
 			if (SCtmp->host_scribble) {
-				scsi_free(SCtmp->host_scribble, 512);
+				kfree(SCtmp->host_scribble);
 				SCtmp->host_scribble = NULL;
 			}
 			HOSTDATA(SCpnt->host)->SCint[i] = NULL;
@@ -1623,7 +1624,7 @@
 	if (mb[mbi].status) {
 		printk(KERN_ERR "Lost interrupt discovered on irq %d - attempting to recover\n",
 		       SCpnt->host->irq);
-		aha1542_intr_handle(SCpnt->host->irq, NULL);
+		aha1542_intr_handle(SCpnt->host, NULL);
 		return 0;
 	}
 	/* OK, no lost interrupt.  Try looking to see how many pending commands
@@ -1712,7 +1713,7 @@
 				SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
 				SCtmp->result = DID_RESET << 16;
 				if (SCtmp->host_scribble) {
-					scsi_free(SCtmp->host_scribble, 512);
+					kfree(SCtmp->host_scribble);
 					SCtmp->host_scribble = NULL;
 				}
 				printk(KERN_WARNING "Sending DID_RESET for target %d\n", SCpnt->target);
@@ -1758,7 +1759,7 @@
 						SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
 						SCtmp->result = DID_RESET << 16;
 						if (SCtmp->host_scribble) {
-							scsi_free(SCtmp->host_scribble, 512);
+							kfree(SCtmp->host_scribble);
 							SCtmp->host_scribble = NULL;
 						}
 						printk(KERN_WARNING "Sending DID_RESET for target %d\n", SCpnt->target);
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/aha1740.c linux/drivers/scsi/aha1740.c
--- v2.5.1/linux/drivers/scsi/aha1740.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/aha1740.c	Tue Jan  1 18:58:17 2002
@@ -213,6 +213,7 @@
 /* A "high" level interrupt handler */
 void aha1740_intr_handle(int irq, void *dev_id, struct pt_regs * regs)
 {
+    struct Scsi_Host *host = aha_host[irq - 9];
     void (*my_done)(Scsi_Cmnd *);
     int errstatus, adapstat;
     int number_serviced;
@@ -221,11 +222,10 @@
     unsigned int base;
     unsigned long flags;
 
-    spin_lock_irqsave(&io_request_lock, flags);
-
-    if (!aha_host[irq - 9])
+    if (!host)
 	panic("aha1740.c: Irq from unknown host!\n");
-    base = aha_host[irq - 9]->io_port;
+    spin_lock_irqsave(&host->host_lock, flags);
+    base = host->io_port;
     number_serviced = 0;
 
     while(inb(G2STAT(base)) & G2STAT_INTPEND)
@@ -299,7 +299,7 @@
 	number_serviced++;
     }
 
-    spin_unlock_irqrestore(&io_request_lock, flags);
+    spin_unlock_irqrestore(&host->host_lock, flags);
 }
 
 int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c linux/drivers/scsi/aic7xxx/aic7xxx_linux.c
--- v2.5.1/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_linux.c	Thu Dec 27 08:17:43 2001
@@ -2727,15 +2727,15 @@
 	int	ret;
 	int	extended;
 	struct	ahc_softc *ahc;
-	struct	buffer_head *bh;
+	unsigned char *buf;
 
 	ahc = *((struct ahc_softc **)disk->device->host->hostdata);
-	bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block_size(dev));
+	buf = scsi_bios_ptable(dev);
 
-	if (bh) {
-		ret = scsi_partsize(bh, disk->capacity,
+	if (buf) {
+		ret = scsi_partsize(buf, disk->capacity,
 				    &geom[2], &geom[0], &geom[1]);
-		brelse(bh);
+		kfree(buf);
 		if (ret != -1)
 			return (ret);
 	}
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/aic7xxx_old.c linux/drivers/scsi/aic7xxx_old.c
--- v2.5.1/linux/drivers/scsi/aic7xxx_old.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/aic7xxx_old.c	Thu Dec 27 08:17:43 2001
@@ -11737,15 +11737,15 @@
 {
   int heads, sectors, cylinders, ret;
   struct aic7xxx_host *p;
-  struct buffer_head *bh;
+  unsigned char *buf;
 
   p = (struct aic7xxx_host *) disk->device->host->hostdata;
-  bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, block_size(dev));
+  buf = scsi_bios_ptable(dev);
 
-  if ( bh )
+  if ( buf )
   {
-    ret = scsi_partsize(bh, disk->capacity, &geom[2], &geom[0], &geom[1]);
-    brelse(bh);
+    ret = scsi_partsize(buf, disk->capacity, &geom[2], &geom[0], &geom[1]);
+    kfree(buf);
     if ( ret != -1 )
       return(ret);
   }
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/cpqfcTSworker.c linux/drivers/scsi/cpqfcTSworker.c
--- v2.5.1/linux/drivers/scsi/cpqfcTSworker.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/cpqfcTSworker.c	Sat Dec 29 17:28:11 2001
@@ -159,7 +159,6 @@
 #ifdef PCI_KERNEL_TRACE
   PTACHYON fcChip = &cpqfcHBAdata->fcChip;
 #endif
-  struct fs_struct *fs;
   DECLARE_MUTEX_LOCKED(fcQueReady);
   DECLARE_MUTEX_LOCKED(fcTYOBcomplete); 
   DECLARE_MUTEX_LOCKED(TachFrozen);  
@@ -168,33 +167,7 @@
   ENTER("WorkerThread");
 
   lock_kernel();
-	/*
-	 * If we were started as result of loading a module, close all of the
-	 * user space pages.  We don't need them, and if we didn't close them
-	 * they would be locked into memory.
-	 */
-  exit_mm(current);
-
-  current->session = 1;
-  current->pgrp = 1;
-	
-  /* Become as one with the init task */
-	
-  exit_fs(current);	/* current->fs->count--; */
-  fs = init_task.fs;
-  // Some kernels compiled for SMP, while actually running
-  // on a uniproc machine, will return NULL for this call
-  if( !fs)
-  {
-    printk(" cpqfcTS FATAL: fs is NULL! Is this an SMP kernel on uniproc machine?\n ");
-  }
- 
-  else
-  { 
-    current->fs = fs;
-    atomic_inc(&fs->count);
-  }
-
+  daemonize();
   siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
 
 
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/dpt_i2o.c linux/drivers/scsi/dpt_i2o.c
--- v2.5.1/linux/drivers/scsi/dpt_i2o.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/dpt_i2o.c	Tue Jan  1 18:57:58 2002
@@ -1157,17 +1157,13 @@
 	msg[2] |= 0x80000000 | ((u32)wait_data->id);
 	timeout *= HZ;
 	if((status = adpt_i2o_post_this(pHba, msg, len)) == 0){
-		if(!timeout){
-			set_current_state(TASK_INTERRUPTIBLE);
-			spin_unlock_irq(&io_request_lock);
+		set_current_state(TASK_INTERRUPTIBLE);
+		spin_unlock_irq(&pHba->host->host_lock);
+		if (!timeout)
 			schedule();
-			spin_lock_irq(&io_request_lock);
-		} else {
-			set_current_state(TASK_INTERRUPTIBLE);
-			spin_unlock_irq(&io_request_lock);
+		else
 			schedule_timeout(timeout*HZ);
-			spin_lock_irq(&io_request_lock);
-		}
+		spin_lock_irq(&pHba->host->host_lock);
 	}
 	wq_write_lock_irq(&adpt_wq_i2o_post.lock);
 	__remove_wait_queue(&adpt_wq_i2o_post, &wait);
@@ -1560,7 +1556,7 @@
 
 	//TODO check for root access
 	//
-	minor = MINOR(inode->i_rdev);
+	minor = minor(inode->i_rdev);
 	if (minor >= hba_count) {
 		return -ENXIO;
 	}
@@ -1591,7 +1587,7 @@
 	int minor;
 	adpt_hba* pHba;
 
-	minor = MINOR(inode->i_rdev);
+	minor = minor(inode->i_rdev);
 	if (minor >= hba_count) {
 		return -ENXIO;
 	}
@@ -1705,7 +1701,7 @@
 	}
 
 	do {
-		spin_lock_irqsave(&io_request_lock, flags);
+		spin_lock_irqsave(&pHba->host->host_lock, flags);
 		// This state stops any new commands from enterring the
 		// controller while processing the ioctl
 //		pHba->state |= DPTI_STATE_IOCTL;
@@ -1713,7 +1709,7 @@
 //		the queue empties and stops.  We need a way to restart the queue
 		rcode = adpt_i2o_post_wait(pHba, msg, size, FOREVER);
 //		pHba->state &= ~DPTI_STATE_IOCTL;
-		spin_unlock_irqrestore(&io_request_lock, flags);
+		spin_unlock_irqrestore(&pHba->host->host_lock, flags);
 	} while(rcode == -ETIMEDOUT);  
 
 	if(rcode){
@@ -1887,7 +1883,7 @@
 	adpt_hba* pHba;
 	ulong flags;
 
-	minor = MINOR(inode->i_rdev);
+	minor = minor(inode->i_rdev);
 	if (minor >= DPTI_MAX_HBA){
 		return -ENXIO;
 	}
@@ -1951,9 +1947,9 @@
 		break;
 		}
 	case I2ORESETCMD:
-		spin_lock_irqsave(&io_request_lock, flags);
+		spin_lock_irqsave(&pHba->host->host_lock, flags);
 		adpt_hba_reset(pHba);
-		spin_unlock_irqrestore(&io_request_lock, flags);
+		spin_unlock_irqrestore(&pHba->host->host_lock, flags);
 		break;
 	case I2ORESCANCMD:
 		adpt_rescan(pHba);
@@ -1989,19 +1985,18 @@
 static void adpt_isr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	Scsi_Cmnd* cmd;
-	adpt_hba* pHba=NULL;
+	adpt_hba* pHba = dev_id;
 	u32 m;
 	ulong reply;
 	u32 status=0;
 	u32 context;
 	ulong flags = 0;
 
-	pHba = dev_id;
 	if (pHba == NULL ){
 		printk(KERN_WARNING"adpt_isr: NULL dev_id\n");
 		return;
 	}
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(&pHba->host->host_lock, flags);
 	while( readl(pHba->irq_mask) & I2O_INTERRUPT_PENDING_B) {
 		m = readl(pHba->reply_port);
 		if(m == EMPTY_QUEUE){
@@ -2011,8 +2006,7 @@
 			if(m == EMPTY_QUEUE){ 
 				// This really should not happen
 				printk(KERN_ERR"dpti: Could not get reply frame\n");
-				spin_unlock_irqrestore(&io_request_lock,flags);
-				return;
+				goto out;
 			}
 		}
 		reply = (ulong)bus_to_virt(m);
@@ -2067,9 +2061,7 @@
 		wmb();
 		rmb();
 	}
-	spin_unlock_irqrestore(&io_request_lock, flags);
-	return;
-
+out:	spin_unlock_irqrestore(&pHba->host->host_lock, flags);
 }
 
 static s32 adpt_scsi_to_i2o(adpt_hba* pHba, Scsi_Cmnd* cmd, struct adpt_device* d)
@@ -2342,18 +2334,14 @@
 	s32 rcode;
 	ulong flags;
 
-	spin_lock_irqsave(&io_request_lock, flags);
-	if ((rcode=adpt_i2o_lct_get(pHba)) < 0){
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return rcode;
-	}
-
-	if ((rcode=adpt_i2o_reparse_lct(pHba)) < 0){
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return rcode;
-	}
-	spin_unlock_irqrestore(&io_request_lock, flags);
-	return 0;
+	spin_lock_irqsave(&pHba->host->host_lock, flags);
+	if ((rcode=adpt_i2o_lct_get(pHba)) < 0)
+		goto out;
+	if ((rcode=adpt_i2o_reparse_lct(pHba)) < 0)
+		goto out;
+	rcode = 0;
+out:	spin_unlock_irqrestore(&pHba->host->host_lock, flags);
+	return rcode;
 }
 
 
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c
--- v2.5.1/linux/drivers/scsi/eata.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/eata.c	Thu Jan  3 12:19:03 2002
@@ -1,6 +1,13 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
  *
+ *      01 Jan 2002 Rev. 7.20 for linux 2.5.1
+ *        + Use the dynamic DMA mapping API.
+ *
+ *      19 Dec 2001 Rev. 7.02 for linux 2.5.1
+ *        + Use SCpnt->sc_data_direction if set.
+ *        + Use sglist.page instead of sglist.address.
+ *
  *      11 Dec 2001 Rev. 7.00 for linux 2.5.1
  *        + Use host->host_lock instead of io_request_lock.
  *
@@ -223,7 +230,7 @@
  *          This driver is based on the CAM (Common Access Method Committee)
  *          EATA (Enhanced AT Bus Attachment) rev. 2.0A, using DMA protocol.
  *
- *  Copyright (C) 1994-2001 Dario Ballabio (ballabio_dario@emc.com)
+ *  Copyright (C) 1994-2002 Dario Ballabio (ballabio_dario@emc.com)
  *
  *  Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it
  *
@@ -634,7 +641,7 @@
    u_int32_t data_len;   /* If sg=0 Data Length, if sg=1 sglist length */
    u_int32_t cpp_index;  /* Index of address to be returned in sp */
    u_int32_t data_address; /* If sg=0 Data Address, if sg=1 sglist address */
-   u_int32_t sp_addr;    /* Address where sp is DMA'ed when cp completes */
+   u_int32_t sp_dma_addr;  /* Address where sp is DMA'ed when cp completes */
    u_int32_t sense_addr; /* Address where Sense Data is DMA'ed on error */
    /* Additional fields begin here. */
    Scsi_Cmnd *SCpnt;
@@ -656,7 +663,11 @@
    unsigned long last_retried_pid;      /* Pid of last retried command */
    unsigned char subversion;            /* Bus type, either ISA or EISA/PCI */
    unsigned char protocol_rev;          /* EATA 2.0 rev., 'A' or 'B' or 'C' */
-   struct mssp sp[2];                   /* Returned status for this board */
+   unsigned char is_pci;                /* TRUE is bus type is PCI */
+   struct pci_dev *pdev;                /* pdev for PCI bus, NULL otherwise */
+   struct mssp *sp_cpu_addr;            /* cpu addr for DMA buffer sp */
+   dma_addr_t sp_dma_addr;              /* dma handle for DMA buffer sp */
+   struct mssp sp;                      /* Local copy of sp buffer */
    };
 
 static struct Scsi_Host *sh[MAX_BOARDS + 1];
@@ -693,10 +704,11 @@
 #define HD(board) ((struct hostdata *) &sh[board]->hostdata)
 #define BN(board) (HD(board)->board_name)
 
-#define H2DEV(x) htonl(x)
-#define DEV2H(x) H2DEV(x)
+/* Device is Big Endian */
+#define H2DEV(x) cpu_to_be32(x)
+#define DEV2H(x) be32_to_cpu(x)
+
 #define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
-#define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0)
 
 static void do_interrupt_handler(int, void *, struct pt_regs *);
 static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
@@ -855,7 +867,7 @@
 
 static inline int port_detect \
       (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt) {
-   unsigned char irq, dma_channel, subversion, i;
+   unsigned char irq, dma_channel, subversion, i, is_pci = FALSE;
    unsigned char protocol_rev;
    struct eata_info info;
    char *bus_type, dma_name[16], tag_type;
@@ -907,10 +919,12 @@
 
    if (!setup_done && j > 0 && j <= MAX_PCI) {
       bus_type = "PCI";
+      is_pci = TRUE;
       subversion = ESA;
       }
    else if (port_base > MAX_EISA_ADDR || (protocol_rev == 'C' && info.pci)) {
       bus_type = "PCI";
+      is_pci = TRUE;
       subversion = ESA;
       }
    else if (port_base >= MIN_EISA_ADDR || (protocol_rev == 'C' && info.eisa)) {
@@ -923,6 +937,7 @@
       }
    else if (port_base > MAX_ISA_ADDR) {
       bus_type = "PCI";
+      is_pci = TRUE;
       subversion = ESA;
       }
    else {
@@ -963,7 +978,13 @@
       printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n",
              name, irq);
 
-   pdev = get_pci_dev(port_base);
+   if (is_pci) {
+      pdev = get_pci_dev(port_base);
+      if (!pdev) 
+         printk("%s: warning, failed to get pci_dev structure.\n", name);
+      }
+   else
+      pdev = NULL;
 
    if (pdev && (irq != pdev->irq)) {
       printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, pdev->irq);
@@ -993,7 +1014,7 @@
 
    /* Set board configuration */
    memset((char *)&config, 0, sizeof(struct eata_config));
-   config.len = (ushort) htons((ushort)510);
+   config.len = (ushort) cpu_to_be16((ushort)510);
    config.ocena = TRUE;
 
    if (do_dma(port_base, (unsigned long)&config, SET_CONFIG_DMA)) {
@@ -1022,14 +1043,16 @@
    sh[j]->n_io_port = REGION_SIZE;
    sh[j]->dma_channel = dma_channel;
    sh[j]->irq = irq;
-   sh[j]->sg_tablesize = (ushort) ntohs(info.scatt_size);
+   sh[j]->sg_tablesize = (ushort) be16_to_cpu(info.scatt_size);
    sh[j]->this_id = (ushort) info.host_addr[3];
-   sh[j]->can_queue = (ushort) ntohs(info.queue_size);
+   sh[j]->can_queue = (ushort) be16_to_cpu(info.queue_size);
    sh[j]->cmd_per_lun = MAX_CMD_PER_LUN;
    sh[j]->select_queue_depths = select_queue_depths;
    memset(HD(j), 0, sizeof(struct hostdata));
    HD(j)->subversion = subversion;
    HD(j)->protocol_rev = protocol_rev;
+   HD(j)->is_pci = is_pci;
+   HD(j)->pdev = pdev;
    HD(j)->board_number = j;
 
    if (HD(j)->subversion == ESA)
@@ -1038,14 +1061,14 @@
       unsigned long flags;
       scsi_register_blocked_host(sh[j]);
       sh[j]->unchecked_isa_dma = TRUE;
-      
+
       flags=claim_dma_lock();
       disable_dma(dma_channel);
       clear_dma_ff(dma_channel);
       set_dma_mode(dma_channel, DMA_MODE_CASCADE);
       enable_dma(dma_channel);
       release_dma_lock(flags);
-      
+
       }
 
    strcpy(BN(j), name);
@@ -1094,6 +1117,13 @@
          return FALSE;
          }
 
+   if (! (HD(j)->sp_cpu_addr = pci_alloc_consistent(HD(j)->pdev, 
+         sizeof(struct mssp), &HD(j)->sp_dma_addr))) {
+      printk("%s: pci_alloc_consistent failed, detaching.\n", BN(j));
+      eata2x_release(sh[j]);
+      return FALSE;
+      }
+
    if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN)
        max_queue_depth = MAX_TAGGED_CMD_PER_LUN;
 
@@ -1108,7 +1138,7 @@
    else                                 tag_type = 'n';
 
    if (j == 0) {
-      printk("EATA/DMA 2.0x: Copyright (C) 1994-2001 Dario Ballabio.\n");
+      printk("EATA/DMA 2.0x: Copyright (C) 1994-2002 Dario Ballabio.\n");
       printk("%s config options -> tc:%c, lc:%c, mq:%d, rs:%c, et:%c.\n",
              driver_name, tag_type, YESNO(linked_comm), max_queue_depth,
              YESNO(rev_scan), YESNO(ext_tran));
@@ -1144,7 +1174,11 @@
              info.pci, info.eisa, info.raidnum);
 #endif
 
-   if (pdev) pci_set_master(pdev);
+   if (HD(j)->pdev) {
+      pci_set_master(HD(j)->pdev);
+      if (pci_set_dma_mask(HD(j)->pdev, 0xffffffff))
+         printk("%s: warning, pci_set_dma_mask failed.\n", BN(j));
+      }
 
    return TRUE;
 }
@@ -1271,25 +1305,92 @@
    return j;
 }
 
-static inline void build_sg_list(struct mscp *cpp, Scsi_Cmnd *SCpnt) {
-   unsigned int k;
+static inline void map_dma(unsigned int i, unsigned int j) {
+   unsigned int k, count, pci_dir;
    struct scatterlist *sgpnt;
+   struct mscp *cpp;
+   Scsi_Cmnd *SCpnt;
+
+   cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+   pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction);
+
+   if (SCpnt->sense_buffer)
+      cpp->sense_addr = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->sense_buffer,
+                           sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE));
+
+   cpp->sense_len = sizeof SCpnt->sense_buffer;
+
+   if (!SCpnt->use_sg) {
+
+      if (!SCpnt->request_bufflen)
+         cpp->data_address = V2DEV(SCpnt->request_buffer);
+
+      else if (SCpnt->request_buffer)
+         cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev,
+                  SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir));
+
+      cpp->data_len = H2DEV(SCpnt->request_bufflen);
+      return;
+      }
 
    sgpnt = (struct scatterlist *) SCpnt->request_buffer;
+   count = pci_map_sg(HD(j)->pdev, sgpnt, SCpnt->use_sg, pci_dir);
 
-   for (k = 0; k < SCpnt->use_sg; k++) {
-      cpp->sglist[k].address = V2DEV(sgpnt[k].address);
-      cpp->sglist[k].num_bytes = H2DEV(sgpnt[k].length);
+   for (k = 0; k < count; k++) {
+      cpp->sglist[k].address = H2DEV(sg_dma_address(&sgpnt[k]));
+      cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(&sgpnt[k]));
       }
 
+   cpp->sg = TRUE;
    cpp->data_address = V2DEV(cpp->sglist);
    cpp->data_len = H2DEV((SCpnt->use_sg * sizeof(struct sg_list)));
 }
 
-static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
-   unsigned int i, j, k;
+static void unmap_dma(unsigned int i, unsigned int j) {
+   unsigned int pci_dir;
    struct mscp *cpp;
-   struct mssp *spp;
+   Scsi_Cmnd *SCpnt;
+
+   cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+   pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction);
+
+   if (DEV2H(cpp->sense_addr))
+      pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr),
+                       DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
+
+   if (SCpnt->use_sg) 
+      pci_unmap_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir);
+
+   else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len))
+      pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address), 
+                       DEV2H(cpp->data_len), pci_dir);
+
+}
+
+static void sync_dma(unsigned int i, unsigned int j) {
+   unsigned int pci_dir;
+   struct mscp *cpp;
+   Scsi_Cmnd *SCpnt;
+
+   cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+   pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction);
+
+   if (DEV2H(cpp->sense_addr))
+      pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->sense_addr),
+                          DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
+
+   if (SCpnt->use_sg) 
+      pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, 
+                         SCpnt->use_sg, pci_dir);
+
+   else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len))
+      pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), 
+                          DEV2H(cpp->data_len), pci_dir);
+
+}
+
+static inline void scsi_to_dev_dir(unsigned int i, unsigned int j) {
+   unsigned int k;
 
    static const unsigned char data_out_cmds[] = {
       0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e,
@@ -1300,9 +1401,53 @@
    static const unsigned char data_none_cmds[] = {
       0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e,
       0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47,
-      0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5
+      0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5, 0x00
       };
 
+   struct mscp *cpp;
+   Scsi_Cmnd *SCpnt;
+
+   cpp = &HD(j)->cp[i];
+   SCpnt = cpp->SCpnt;
+
+   if (SCpnt->sc_data_direction == SCSI_DATA_READ) {
+      cpp->din  = TRUE;
+      cpp->dout = FALSE;
+      return;
+      }
+   else if (SCpnt->sc_data_direction == SCSI_DATA_WRITE) {
+      cpp->din  = FALSE;
+      cpp->dout = TRUE;
+      return;
+      }
+   else if (SCpnt->sc_data_direction == SCSI_DATA_NONE) {
+      cpp->din  = FALSE;
+      cpp->dout = FALSE;
+      return;
+      }
+
+   if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN) 
+      panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", BN(j));
+
+   for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
+      if (SCpnt->cmnd[0] == data_out_cmds[k]) {
+         cpp->dout = TRUE;
+         break;
+         }
+
+   if ((cpp->din = !cpp->dout))
+      for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++)
+         if (SCpnt->cmnd[0] == data_none_cmds[k]) {
+            cpp->din = FALSE;
+            break;
+            }
+
+}
+
+static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
+   unsigned int i, j, k;
+   struct mscp *cpp;
+
    /* j is the board number */
    j = ((struct hostdata *) SCpnt->host->hostdata)->board_number;
 
@@ -1334,11 +1479,8 @@
 
    memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *));
 
-   /* Set pointer to status packet structure */
-   spp = &HD(j)->sp[0];
-
-   /* The EATA protocol uses Big Endian format */
-   cpp->sp_addr = V2DEV(spp);
+   /* Set pointer to status packet structure, Big Endian format */
+   cpp->sp_dma_addr = H2DEV(HD(j)->sp_dma_addr);
 
    SCpnt->scsi_done = done;
    cpp->cpp_index = i;
@@ -1348,19 +1490,6 @@
                         BN(j), i, SCpnt->channel, SCpnt->target,
                         SCpnt->lun, SCpnt->pid);
 
-   for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
-     if (SCpnt->cmnd[0] == data_out_cmds[k]) {
-        cpp->dout = TRUE;
-        break;
-        }
-
-   if ((cpp->din = !cpp->dout))
-      for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++)
-        if (SCpnt->cmnd[0] == data_none_cmds[k]) {
-           cpp->din = FALSE;
-           break;
-           }
-
    cpp->reqsen = TRUE;
    cpp->dispri = TRUE;
 #if 0
@@ -1371,8 +1500,13 @@
    cpp->target = SCpnt->target;
    cpp->lun = SCpnt->lun;
    cpp->SCpnt = SCpnt;
-   cpp->sense_addr = V2DEV(SCpnt->sense_buffer);
-   cpp->sense_len = sizeof SCpnt->sense_buffer;
+   memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len);
+
+   /* Use data transfer direction SCpnt->sc_data_direction */
+   scsi_to_dev_dir(i, j);
+
+   /* Map DMA buffers and SG list */
+   map_dma(i, j);
 
    if (SCpnt->device->tagged_queue) {
 
@@ -1392,17 +1526,6 @@
       cpp->mess[1] = SCpnt->device->current_tag++;
       }
 
-   if (SCpnt->use_sg) {
-      cpp->sg = TRUE;
-      build_sg_list(cpp, SCpnt);
-      }
-   else {
-      cpp->data_address = V2DEV(SCpnt->request_buffer);
-      cpp->data_len = H2DEV(SCpnt->request_bufflen);
-      }
-
-   memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len);
-
    if (linked_comm && SCpnt->device->queue_depth > 2
                                      && TLDEV(SCpnt->device->type)) {
       HD(j)->cp_stat[i] = READY;
@@ -1412,6 +1535,7 @@
 
    /* Send control packet to the board */
    if (do_dma(sh[j]->io_port, (unsigned long) cpp, SEND_CP_DMA)) {
+      unmap_dma(i, j);
       SCpnt->host_scribble = NULL;
       printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n",
              BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid);
@@ -1468,6 +1592,7 @@
          printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i);
 
       if (SCarg->eh_state == SCSI_STATE_TIMEOUT) {
+         unmap_dma(i, j);
          SCarg->host_scribble = NULL;
          HD(j)->cp_stat[i] = FREE;
          printk("%s, abort, mbox %d, eh_state timeout, pid %ld.\n",
@@ -1489,6 +1614,7 @@
       }
 
    if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
+      unmap_dma(i, j);
       SCarg->result = DID_ABORT << 16;
       SCarg->host_scribble = NULL;
       HD(j)->cp_stat[i] = FREE;
@@ -1597,6 +1723,7 @@
 
       if (HD(j)->cp_stat[i] == IN_RESET) {
          SCpnt = HD(j)->cp[i].SCpnt;
+         unmap_dma(i, j);
          SCpnt->result = DID_RESET << 16;
          SCpnt->host_scribble = NULL;
 
@@ -1609,6 +1736,7 @@
 
       else if (HD(j)->cp_stat[i] == ABORTING) {
          SCpnt = HD(j)->cp[i].SCpnt;
+         unmap_dma(i, j);
          SCpnt->result = DID_RESET << 16;
          SCpnt->host_scribble = NULL;
 
@@ -1821,7 +1949,7 @@
 static inline void ihdlr(int irq, unsigned int j) {
    Scsi_Cmnd *SCpnt;
    unsigned int i, k, c, status, tstatus, reg;
-   struct mssp *dspp, *spp;
+   struct mssp *spp;
    struct mscp *cpp;
 
    if (sh[j]->irq != irq)
@@ -1843,14 +1971,13 @@
       return;
       }
 
-   dspp = &HD(j)->sp[0];
-   spp  = &HD(j)->sp[1];
+   spp  = &HD(j)->sp;
 
    /* Make a local copy just before clearing the interrupt indication */
-   memcpy(spp, dspp, sizeof(struct mssp));
+   memcpy(spp, HD(j)->sp_cpu_addr, sizeof(struct mssp));
 
    /* Clear the completion flag and cp pointer on the dynamic copy of sp */
-   memset(dspp, 0, sizeof(struct mssp));
+   memset(HD(j)->sp_cpu_addr, 0, sizeof(struct mssp));
 
    /* Read the status register to clear the interrupt indication */
    reg = inb(sh[j]->io_port + REG_STATUS);
@@ -1908,6 +2035,8 @@
       panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
             BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble);
 
+   sync_dma(i, j);
+
    if (linked_comm && SCpnt->device->queue_depth > 2
                                      && TLDEV(SCpnt->device->type))
       flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE);
@@ -1985,6 +2114,7 @@
 #else
             status = DID_BUS_BUSY << 16;
 #endif
+
             HD(j)->retries++;
             HD(j)->last_retried_pid = SCpnt->pid;
             }
@@ -2021,6 +2151,8 @@
              SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid,
              reg, HD(j)->iocount);
 
+   unmap_dma(i, j);
+
    /* Set the command state to inactive */
    SCpnt->host_scribble = NULL;
 
@@ -2052,13 +2184,15 @@
    if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n",
                             driver_name);
 
-   if( sh[j]->unchecked_isa_dma ) {
-	   scsi_deregister_blocked_host(sh[j]);
-   }
+   if(sh[j]->unchecked_isa_dma) scsi_deregister_blocked_host(sh[j]);
 
    for (i = 0; i < sh[j]->can_queue; i++)
       if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
 
+   if (HD(j)->sp_cpu_addr) 
+      pci_free_consistent(HD(j)->pdev, sizeof(struct mssp),
+                          HD(j)->sp_cpu_addr, HD(j)->sp_dma_addr);
+                       
    free_irq(sh[j]->irq, &sha[j]);
 
    if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel);
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/eata.h linux/drivers/scsi/eata.h
--- v2.5.1/linux/drivers/scsi/eata.h	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/eata.h	Thu Jan  3 12:19:03 2002
@@ -13,7 +13,7 @@
 int eata2x_reset(Scsi_Cmnd *);
 int eata2x_biosparam(Disk *, kdev_t, int *);
 
-#define EATA_VERSION "7.00.00"
+#define EATA_VERSION "7.20.00"
 
 #define EATA {                                                               \
                 name:              "EATA/DMA 2.0x rev. " EATA_VERSION " ",   \
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c
--- v2.5.1/linux/drivers/scsi/fdomain.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/fdomain.c	Tue Jan  1 20:16:00 2002
@@ -382,22 +382,23 @@
    Write_FIFO       = 12
 };
 
-static int               port_base         = 0;
-static unsigned long     bios_base         = 0;
-static int               bios_major        = 0;
-static int               bios_minor        = 0;
-static int               PCI_bus           = 0;
-static int               Quantum           = 0;	/* Quantum board variant */
-static int               interrupt_level   = 0;
-static volatile int      in_command        = 0;
-static Scsi_Cmnd         *current_SC       = NULL;
+/* .bss will zero all the static variables below */
+static int               port_base;
+static unsigned long     bios_base;
+static int               bios_major;
+static int               bios_minor;
+static int               PCI_bus;
+static int               Quantum;	/* Quantum board variant */
+static int               interrupt_level;
+static volatile int      in_command;
+static Scsi_Cmnd         *current_SC;
 static enum chip_type    chip              = unknown;
-static int               adapter_mask      = 0;
-static int               this_id           = 0;
-static int               setup_called      = 0;
+static int               adapter_mask;
+static int               this_id;
+static int               setup_called;
 
 #if DEBUG_RACE
-static volatile int      in_interrupt_flag = 0;
+static volatile int      in_interrupt_flag;
 #endif
 
 static int               SCSI_Mode_Cntl_port;
@@ -983,7 +984,7 @@
       /* Register the IRQ with the kernel */
 
       retcode = request_irq( interrupt_level,
-			     do_fdomain_16x0_intr, pdev?SA_SHIRQ:0, "fdomain", NULL);
+			     do_fdomain_16x0_intr, pdev?SA_SHIRQ:0, "fdomain", shpnt);
 
       if (retcode < 0) {
 	 if (retcode == -EINVAL) {
@@ -1265,9 +1266,9 @@
 #if EVERY_ACCESS
 	 printk( " AFAIL " );
 #endif
-         spin_lock_irqsave(&io_request_lock, flags);
+         spin_lock_irqsave(&current_SC->host->host_lock, flags);
 	 my_done( DID_BUS_BUSY << 16 );
-         spin_unlock_irqrestore(&io_request_lock, flags);
+         spin_unlock_irqrestore(&current_SC->host->host_lock, flags);
 	 return;
       }
       current_SC->SCp.phase = in_selection;
@@ -1291,9 +1292,9 @@
 #if EVERY_ACCESS
 	    printk( " SFAIL " );
 #endif
-            spin_lock_irqsave(&io_request_lock, flags);
+            spin_lock_irqsave(&current_SC->host->host_lock, flags);
 	    my_done( DID_NO_CONNECT << 16 );
-            spin_unlock_irqrestore(&io_request_lock, flags);
+            spin_unlock_irqrestore(&current_SC->host->host_lock, flags);
 	    return;
 	 } else {
 #if EVERY_ACCESS
@@ -1638,10 +1639,10 @@
 #if EVERY_ACCESS
       printk( "BEFORE MY_DONE. . ." );
 #endif
-      spin_lock_irqsave(&io_request_lock, flags);
+      spin_lock_irqsave(&current_SC->host->host_lock, flags);
       my_done( (current_SC->SCp.Status & 0xff)
 	       | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16) );
-      spin_unlock_irqrestore(&io_request_lock, flags);
+      spin_unlock_irqrestore(&current_SC->host->host_lock, flags);
 #if EVERY_ACCESS
       printk( "RETURNING.\n" );
 #endif
@@ -1932,11 +1933,11 @@
       0x0a bytes long.  Heads are one less than we need to report.
     */
 
-   if (MAJOR(dev) != SCSI_DISK0_MAJOR) {
+   if (major(dev) != SCSI_DISK0_MAJOR) {
       printk("scsi: <fdomain> fdomain_16x0_biosparam: too many disks");
       return 0;
    }
-   drive = MINOR(dev) >> 4;
+   drive = minor(dev) >> 4;
 
    if (bios_major == 2) {
       switch (Quantum) {
@@ -2033,6 +2034,15 @@
    }
    
    return 0;
+}
+
+int fdomain_16x0_release(struct Scsi_Host *shpnt)
+{
+	if (shpnt->irq)
+		free_irq(shpnt->irq, shpnt);
+	if (shpnt->io_port && shpnt->n_io_port)
+		release_region(shpnt->io_port, shpnt->n_io_port);
+
 }
 
 MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/fdomain.h linux/drivers/scsi/fdomain.h
--- v2.5.1/linux/drivers/scsi/fdomain.h	Thu Nov 11 16:57:30 1999
+++ linux/drivers/scsi/fdomain.h	Sun Dec 30 16:54:29 2001
@@ -34,6 +34,7 @@
 int        fdomain_16x0_biosparam( Disk *, kdev_t, int * );
 int        fdomain_16x0_proc_info( char *buffer, char **start, off_t offset,
 				   int length, int hostno, int inout );
+int        fdomain_16x0_release( struct Scsi_Host *shpnt );
 
 #define FDOMAIN_16X0 { proc_info:      fdomain_16x0_proc_info,           \
 		       detect:         fdomain_16x0_detect,              \
@@ -43,6 +44,7 @@
 		       abort:          fdomain_16x0_abort,               \
 		       reset:          fdomain_16x0_reset,               \
 		       bios_param:     fdomain_16x0_biosparam,           \
+		       release:        fdomain_16x0_release,		 \
 		       can_queue:      1, 				 \
 		       this_id:        6, 				 \
 		       sg_tablesize:   64, 				 \
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v2.5.1/linux/drivers/scsi/hosts.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/hosts.c	Tue Dec 25 17:04:40 2001
@@ -270,15 +270,6 @@
     return retval;
 }
 
-int
-scsi_register_device(struct Scsi_Device_Template * sdpnt)
-{
-    if(sdpnt->next) panic("Device already registered");
-    sdpnt->next = scsi_devicelist;
-    scsi_devicelist = sdpnt;
-    return 0;
-}
-
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h
--- v2.5.1/linux/drivers/scsi/hosts.h	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/hosts.h	Tue Jan  1 19:16:28 2002
@@ -521,17 +521,14 @@
 
 void  scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt);
 
-int scsi_register_device(struct Scsi_Device_Template * sdpnt);
 
-/* These are used by loadable modules */
-extern int scsi_register_module(int, void *);
-extern int scsi_unregister_module(int, void *);
-
-/* The different types of modules that we can load and unload */
-#define MODULE_SCSI_HA 1
-#define MODULE_SCSI_CONST 2
-#define MODULE_SCSI_IOCTL 3
-#define MODULE_SCSI_DEV 4
+/*
+ * Driver registration/unregistration.
+ */
+extern int scsi_register_device(struct Scsi_Device_Template *);
+extern int scsi_unregister_device(struct Scsi_Device_Template *);
+extern int scsi_register_host(Scsi_Host_Template *);
+extern int scsi_unregister_host(Scsi_Host_Template *);
 
 
 /*
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
--- v2.5.1/linux/drivers/scsi/ide-scsi.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/ide-scsi.c	Thu Jan  3 11:35:33 2002
@@ -50,7 +50,6 @@
 #include "scsi.h"
 #include "hosts.h"
 #include "sd.h"
-#include "ide-scsi.h"
 #include <scsi/sg.h>
 
 #define IDESCSI_DEBUG_LOG		0
@@ -748,7 +747,7 @@
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
 
-	if (MAJOR(cmd->request.rq_dev) == SCSI_GENERIC_MAJOR)
+	if (major(cmd->request.rq_dev) == SCSI_GENERIC_MAJOR)
 		return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
 	return test_bit(IDESCSI_TRANSFORM, &scsi->transform);
 }
@@ -840,13 +839,29 @@
 	return 0;
 }
 
-static Scsi_Host_Template idescsi_template = IDESCSI;
+static Scsi_Host_Template idescsi_template = {
+	module:		THIS_MODULE,
+	name:		"idescsi",
+	detect:		idescsi_detect,
+	release:	idescsi_release,
+	info:		idescsi_info,
+	ioctl:		idescsi_ioctl,
+	queuecommand:	idescsi_queue,
+	abort:		idescsi_abort,
+	reset:		idescsi_reset,
+	bios_param:	idescsi_bios,
+	can_queue:	10,
+	this_id:	-1,
+	sg_tablesize:	256,
+	cmd_per_lun:	5,
+	use_clustering:	DISABLE_CLUSTERING,
+	emulated:	1,
+};
 
 static int __init init_idescsi_module(void)
 {
 	idescsi_init();
-	idescsi_template.module = THIS_MODULE;
-	scsi_register_module (MODULE_SCSI_HA, &idescsi_template);
+	scsi_register_host(&idescsi_template);
 	return 0;
 }
 
@@ -856,7 +871,7 @@
 	byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
 	int i, failed;
 
-	scsi_unregister_module (MODULE_SCSI_HA, &idescsi_template);
+	scsi_unregister_host(&idescsi_template);
 	for (i = 0; media[i] != 255; i++) {
 		failed = 0;
 		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, &idescsi_driver, failed)) != NULL)
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/ide-scsi.h linux/drivers/scsi/ide-scsi.h
--- v2.5.1/linux/drivers/scsi/ide-scsi.h	Fri Apr 10 15:22:21 1998
+++ linux/drivers/scsi/ide-scsi.h	Wed Dec 31 16:00:00 1969
@@ -1,37 +0,0 @@
-/*
- * linux/drivers/scsi/ide-scsi.h
- *
- * Copyright (C) 1996, 1997 Gadi Oxman <gadio@netvision.net.il>
- */
-
-#ifndef IDESCSI_H
-#define IDESCSI_H
-
-extern int idescsi_detect (Scsi_Host_Template *host_template);
-extern int idescsi_release (struct Scsi_Host *host);
-extern const char *idescsi_info (struct Scsi_Host *host);
-extern int idescsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
-extern int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
-extern int idescsi_abort (Scsi_Cmnd *cmd);
-extern int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags);
-extern int idescsi_bios (Disk *disk, kdev_t dev, int *parm);
-
-#define IDESCSI  {								\
-	name:            "idescsi",		/* name		*/		\
-	detect:          idescsi_detect,	/* detect	*/		\
-	release:         idescsi_release,	/* release	*/		\
-	info:            idescsi_info,		/* info		*/		\
-	ioctl:           idescsi_ioctl,		/* ioctl        */		\
-	queuecommand:    idescsi_queue,		/* queuecommand */		\
-	abort:           idescsi_abort,		/* abort	*/		\
-	reset:           idescsi_reset,		/* reset	*/		\
-	bios_param:      idescsi_bios,		/* bios_param	*/		\
-	can_queue:       10,			/* can_queue	*/		\
-	this_id:         -1,			/* this_id	*/		\
-	sg_tablesize:    256,			/* sg_tablesize	*/		\
-	cmd_per_lun:     5,			/* cmd_per_lun	*/		\
-	use_clustering:  DISABLE_CLUSTERING,	/* clustering	*/		\
-	emulated:        1			/* emulated     */		\
-}
-
-#endif /* IDESCSI_H */
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/in2000.c linux/drivers/scsi/in2000.c
--- v2.5.1/linux/drivers/scsi/in2000.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/in2000.c	Tue Jan  1 20:16:00 2002
@@ -855,7 +855,7 @@
 
 /* Get the spin_lock and disable further ints, for SMP */
 
-   CLISPIN_LOCK(flags);
+   CLISPIN_LOCK(instance, flags);
 
 #ifdef PROC_STATISTICS
    hostdata->int_cnt++;
@@ -993,7 +993,7 @@
       write1_io(0, IO_LED_OFF);
 
 /* release the SMP spin_lock and restore irq state */
-      CLISPIN_UNLOCK(flags);
+      CLISPIN_UNLOCK(instance, flags);
       return;
       }
 
@@ -1011,7 +1011,7 @@
       write1_io(0, IO_LED_OFF);
 
 /* release the SMP spin_lock and restore irq state */
-      CLISPIN_UNLOCK(flags);
+      CLISPIN_UNLOCK(instance, flags);
       return;
       }
 
@@ -1433,7 +1433,7 @@
             hostdata->state = S_UNCONNECTED;
 
 /* release the SMP spin_lock and restore irq state */
-            CLISPIN_UNLOCK(flags);
+            CLISPIN_UNLOCK(instance, flags);
             return;
             }
 DB(DB_INTR,printk("UNEXP_DISC-%ld",cmd->pid))
@@ -1609,7 +1609,7 @@
 DB(DB_INTR,printk("} "))
 
 /* release the SMP spin_lock and restore irq state */
-   CLISPIN_UNLOCK(flags);
+   CLISPIN_UNLOCK(instance, flags);
 
 }
 
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/in2000.h linux/drivers/scsi/in2000.h
--- v2.5.1/linux/drivers/scsi/in2000.h	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/in2000.h	Tue Jan  1 20:16:00 2002
@@ -393,8 +393,9 @@
 # define in2000__INITFUNC(function) __initfunc(function)
 # define in2000__INIT __init
 # define in2000__INITDATA __initdata
-# define CLISPIN_LOCK(flags)   spin_lock_irqsave(&io_request_lock, flags)
-# define CLISPIN_UNLOCK(flags) spin_unlock_irqrestore(&io_request_lock, flags)
+# define CLISPIN_LOCK(host,flags)   spin_lock_irqsave(&host->host_lock, flags)
+# define CLISPIN_UNLOCK(host,flags) spin_unlock_irqrestore(&host->host_lock, \
+							   flags)
 
 int in2000_detect(Scsi_Host_Template *) in2000__INIT;
 int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/ips.c linux/drivers/scsi/ips.c
--- v2.5.1/linux/drivers/scsi/ips.c	Fri Nov  9 14:05:06 2001
+++ linux/drivers/scsi/ips.c	Tue Jan  1 20:16:00 2002
@@ -1769,14 +1769,13 @@
       char      *kern_area;
       u_int32_t  datasize;
 
-      /* free io_request_lock */
-      spin_unlock_irq(&io_request_lock);
+      spin_unlock_irq(&SC->host->host_lock);
 
       /* wait for the command to finish */
       down(&ha->ioctl_sem);
 
       /* reobtain the lock */
-      spin_lock_irq(&io_request_lock);
+      spin_lock_irq(&SC->host->host_lock);
 
       /* command finished -- copy back */
       user_area = *((char **) &SC->cmnd[4]);
@@ -1911,31 +1910,30 @@
 /****************************************************************************/
 void
 do_ipsintr(int irq, void *dev_id, struct pt_regs *regs) {
-   ips_ha_t         *ha;
+   ips_ha_t         *ha = (ips_ha_t *) dev_id;
    unsigned long     cpu_flags;
+   struct Scsi_Host *host = ips_sh[ha->host_num];
 
    METHOD_TRACE("do_ipsintr", 2);
 
-   ha = (ips_ha_t *) dev_id;
-
-   spin_lock_irqsave(&io_request_lock, cpu_flags);
+   spin_lock_irqsave(&host->host_lock, cpu_flags);
 
    if (test_and_set_bit(IPS_IN_INTR, &ha->flags)) {
-      spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+      spin_unlock_irqrestore(&host->host_lock, cpu_flags);
 
       return ;
    }
 
    if (!ha) {
       clear_bit(IPS_IN_INTR, &ha->flags);
-      spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+      spin_unlock_irqrestore(&host->host_lock, cpu_flags);
 
       return;
    }
 
    if (!ha->active) {
       clear_bit(IPS_IN_INTR, &ha->flags);
-      spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+      spin_unlock_irqrestore(&host->host_lock, cpu_flags);
 
       return;
    }
@@ -1944,10 +1942,11 @@
 
    clear_bit(IPS_IN_INTR, &ha->flags);
 
-   spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+   spin_unlock_irqrestore(&host->host_lock, cpu_flags);
 
    /* start the next command */
    ips_next(ha, IPS_INTR_ON);
+   return;
 }
 
 /****************************************************************************/
@@ -2487,8 +2486,8 @@
             task.routine = ips_scheduled_flash_bios;
             task.data = (void *) &flash_data;
 
-            /* Unlock the master lock */
-            spin_unlock_irq(&io_request_lock);
+            /* Unlock the per-board lock */
+            spin_unlock_irq(&SC->host->host_lock);
 
             queue_task(&task, &tq_immediate);
             mark_bh(IMMEDIATE_BH);
@@ -2496,8 +2495,8 @@
             /* Wait for the flash to complete */
             down(&ha->flash_ioctl_sem);
 
-            /* Obtain the master lock */
-            spin_lock_irq(&io_request_lock);
+            /* Obtain the per-board lock */
+            spin_lock_irq(&SC->host->host_lock);
 
             return (flash_data.retcode);
          }
@@ -2604,8 +2603,8 @@
             task.routine = ips_flash_bios_section;
             task.data = (void *) &flash_data;
 
-            /* Unlock the master lock */
-            spin_unlock_irq(&io_request_lock);
+            /* Unlock the per-board lock */
+            spin_unlock_irq(&SC->host->host_lock);
 
             queue_task(&task, &tq_immediate);
             mark_bh(IMMEDIATE_BH);
@@ -2613,8 +2612,8 @@
             /* Wait for the flash to complete */
             down(&ha->flash_ioctl_sem);
 
-            /* Obtain the master lock */
-            spin_lock_irq(&io_request_lock);
+            /* Obtain the per-board lock */
+            spin_lock_irq(&SC->host->host_lock);
 
             return (flash_data.retcode);
          }
@@ -3572,18 +3571,21 @@
    int                   intr_status;
    unsigned long         cpu_flags;
    unsigned long         cpu_flags2;
+   struct Scsi_Host *host;
 
    METHOD_TRACE("ips_next", 1);
 
    if (!ha)
       return ;
 
+   host = ips_sh[ha->host_num];
+
    /*
     * Block access to the queue function so
     * this command won't time out
     */
    if (intr == IPS_INTR_ON) {
-       spin_lock_irqsave(&io_request_lock, cpu_flags2);
+       spin_lock_irqsave(&host->host_lock, cpu_flags2);
        intr_status = IPS_INTR_IORL;
    } else {
        intr_status = intr;
@@ -3608,7 +3610,7 @@
    }
 
    if (intr == IPS_INTR_ON)
-       spin_unlock_irqrestore(&io_request_lock, cpu_flags2);
+       spin_unlock_irqrestore(&host->host_lock, cpu_flags2);
 
 #ifndef NO_IPS_CMDLINE
    /*
@@ -6604,6 +6606,8 @@
 
          clear_bit(IPS_IN_INTR, &ha->flags);
       } else if (intr == IPS_INTR_HAL) {
+	 struct Scsi_Host *host = ips_sh[ha->host_num];
+
          if (ha->waitflag == FALSE) {
             /*
              * controller generated an interrupt to
@@ -6621,7 +6625,7 @@
           * We were called under the HA lock so we can assume that interrupts
           * are masked.
           */
-         spin_lock(&io_request_lock);
+         spin_lock(&host->host_lock);
 
          while (test_and_set_bit(IPS_IN_INTR, &ha->flags))
             udelay(1000);
@@ -6630,7 +6634,7 @@
 
          clear_bit(IPS_IN_INTR, &ha->flags);
 
-         spin_unlock(&io_request_lock);
+         spin_unlock(&host->host_lock);
       }
 
       udelay(1000); /* 1 milisecond */
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/mac_scsi.c linux/drivers/scsi/mac_scsi.c
--- v2.5.1/linux/drivers/scsi/mac_scsi.c	Sat Nov 11 19:01:11 2000
+++ linux/drivers/scsi/mac_scsi.c	Sat Dec 29 12:08:55 2001
@@ -353,7 +353,7 @@
 	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
 	NCR5380_read( RESET_PARITY_INTERRUPT_REG );
 
-	for( end = jiffies + AFTER_RESET_DELAY; jiffies < end; )
+	for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); )
 		barrier();
 
 	/* switch on SCSI IRQ again */
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
--- v2.5.1/linux/drivers/scsi/megaraid.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/megaraid.c	Thu Dec 27 08:17:43 2001
@@ -4290,26 +4290,18 @@
 static int
 mega_partsize(Disk * disk, kdev_t dev, int *geom)
 {
-	struct buffer_head *bh;
 	struct partition *p, *largest = NULL;
 	int i, largest_cyl;
 	int heads, cyls, sectors;
 	int capacity = disk->capacity;
+	unsigned char *buf;
 
-	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 (!(buf = scsi_bios_ptable(dev)))
 		return -1;
 
-	if( *(unsigned short *)(bh->b_data + 510) == 0xAA55 ) {
+	if( *(unsigned short *)(buf + 64) == 0xAA55 ) {
 
-		for( largest_cyl = -1, p = (struct partition *)(0x1BE + bh->b_data),
+		for( largest_cyl = -1, p = (struct partition *)buf,
 				i = 0; i < 4; ++i, ++p) {
 
 			if (!p->sys_ind) continue;
@@ -4328,7 +4320,7 @@
 		sectors = largest->end_sector & 0x3f;
 
 		if (heads == 0 || sectors == 0) {
-			brelse(bh);
+			kfree(buf);
 			return -1;
 		}
 
@@ -4338,11 +4330,11 @@
 		geom[1] = sectors;
 		geom[2] = cyls;
 
-		brelse(bh);
+		kfree(buf);
 		return 0;
 	}
 
-	brelse(bh);
+	kfree(buf);
 	return -1;
 }
 
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.5.1/linux/drivers/scsi/ncr53c8xx.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/ncr53c8xx.c	Sun Dec 30 16:54:29 2001
@@ -8626,9 +8626,9 @@
      if (DEBUG_FLAGS & DEBUG_TINY) printk ("]\n");
 
      if (done_list) {
-          NCR_LOCK_SCSI_DONE(np, flags);
+          NCR_LOCK_SCSI_DONE(done_list->host, flags);
           ncr_flush_done_cmds(done_list);
-          NCR_UNLOCK_SCSI_DONE(np, flags);
+          NCR_UNLOCK_SCSI_DONE(done_list->host, flags);
      }
 }
 
@@ -8649,9 +8649,9 @@
      NCR_UNLOCK_NCB(np, flags);
 
      if (done_list) {
-          NCR_LOCK_SCSI_DONE(np, flags);
+          NCR_LOCK_SCSI_DONE(done_list->host, flags);
           ncr_flush_done_cmds(done_list);
-          NCR_UNLOCK_SCSI_DONE(np, flags);
+          NCR_UNLOCK_SCSI_DONE(done_list->host, flags);
      }
 }
 
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/osst.c linux/drivers/scsi/osst.c
--- v2.5.1/linux/drivers/scsi/osst.c	Tue Nov 13 09:19:41 2001
+++ linux/drivers/scsi/osst.c	Tue Dec 25 17:04:40 2001
@@ -159,6 +159,7 @@
 
 struct Scsi_Device_Template osst_template =
 {
+       module:		THIS_MODULE,
        name:		"OnStream tape",
        tag:		"osst",
        scsi_type:	TYPE_TAPE,
@@ -5583,8 +5584,7 @@
 static int __init init_osst(void) 
 {
 	validate_options();
-	osst_template.module = THIS_MODULE;
-	return scsi_register_module(MODULE_SCSI_DEV, &osst_template);
+	return scsi_register_device(&osst_template);
 }
 
 static void __exit exit_osst (void)
@@ -5592,7 +5592,7 @@
   int i;
   OS_Scsi_Tape * STp;
 
-  scsi_unregister_module(MODULE_SCSI_DEV, &osst_template);
+  scsi_unregister_device(&osst_template);
 #ifdef CONFIG_DEVFS_FS
   devfs_unregister_chrdev(MAJOR_NR, "osst");
 #else
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/pci2000.c linux/drivers/scsi/pci2000.c
--- v2.5.1/linux/drivers/scsi/pci2000.c	Fri Nov  9 14:05:06 2001
+++ linux/drivers/scsi/pci2000.c	Tue Jan  1 18:57:58 2002
@@ -275,11 +275,6 @@
 	int					z;
     unsigned long		flags;
 
-    /*
-     * Disable interrupts, if they aren't already disabled and acquire
-     * the I/O spinlock.
-     */
-    spin_lock_irqsave (&io_request_lock, flags);
 
 	DEB(printk ("\npci2000 received interrupt "));
 	for ( z = 0; z < NumAdapters;  z++ )										// scan for interrupt to process
@@ -298,9 +293,10 @@
 	if ( !shost )
 		{
 		DEB (printk ("\npci2000: not my interrupt"));
-		goto irq_return;
+		goto out;
 		}
 
+	spin_lock_irqsave(&shost->host_lock, flags);
 	padapter = HOSTDATA(shost);
 
 	tag0 = tag & 0x7F;															// mask off the error bit
@@ -392,14 +388,10 @@
 	outb_p (CMD_DONE, padapter->cmd);										// complete the op
 	OpDone (SCpnt, DID_OK << 16);
 
-irq_return:;
-    /*
-     * Release the I/O spinlock and restore the original flags
-     * which will enable interrupts if and only if they were
-     * enabled on entry.
-     */
-    spin_unlock_irqrestore (&io_request_lock, flags);
-	}
+irq_return:
+    spin_unlock_irqrestore(&shost->host_flag, flags);
+out:;
+}
 /****************************************************************
  *	Name:	Pci2000_QueueCommand
  *
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c
--- v2.5.1/linux/drivers/scsi/pci2220i.c	Fri Nov  9 14:05:06 2001
+++ linux/drivers/scsi/pci2220i.c	Tue Jan  1 18:57:58 2002
@@ -1152,6 +1152,7 @@
 static void TimerExpiry (unsigned long data)
 	{
 	PADAPTER2220I	padapter = (PADAPTER2220I)data;
+	struct Scsi_Host *host = padapter->SCpnt->host;
 	POUR_DEVICE		pdev = padapter->pdev;
 	UCHAR			status = IDE_STATUS_BUSY;
 	UCHAR			temp, temp1;
@@ -1161,7 +1162,7 @@
      * Disable interrupts, if they aren't already disabled and acquire
      * the I/O spinlock.
      */
-    spin_lock_irqsave (&io_request_lock, flags);
+    spin_lock_irqsave (&host->host_lock, flags);
 	DEB (printk ("\nPCI2220I: Timeout expired "));
 
 	if ( padapter->failinprog )
@@ -1295,7 +1296,7 @@
      * which will enable interrupts if and only if they were
      * enabled on entry.
      */
-    spin_unlock_irqrestore (&io_request_lock, flags);
+    spin_unlock_irqrestore (&host->host_lock, flags);
 	}
 /****************************************************************
  *	Name:			SetReconstruct	:LOCAL
@@ -1328,7 +1329,8 @@
  ****************************************************************/
 static void ReconTimerExpiry (unsigned long data)
 	{
-	PADAPTER2220I	padapter;
+	PADAPTER2220I	padapter = (PADAPTER2220I)data;
+	struct Scsi_Host *host = padapter->SCpnt->host;
 	POUR_DEVICE		pdev;
 	ULONG			testsize = 0;
 	PIDENTIFY_DATA	pid;
@@ -1342,9 +1344,8 @@
      * Disable interrupts, if they aren't already disabled and acquire
      * the I/O spinlock.
      */
-    spin_lock_irqsave (&io_request_lock, flags);
+    spin_lock_irqsave(&host->host_lock, flags);
 
-	padapter = (PADAPTER2220I)data;
 	if ( padapter->SCpnt )
 		goto reconTimerExpiry;
 
@@ -1567,7 +1568,7 @@
      * which will enable interrupts if and only if they were
      * enabled on entry.
      */
-    spin_unlock_irqrestore (&io_request_lock, flags);
+    spin_unlock_irqrestore(&host->host_lock, flags);
 	}
 /****************************************************************
  *	Name:	Irq_Handler	:LOCAL
@@ -1596,12 +1597,6 @@
 	ULONG				zl;
     unsigned long		flags;
 
-    /*
-     * Disable interrupts, if they aren't already disabled and acquire
-     * the I/O spinlock.
-     */
-    spin_lock_irqsave (&io_request_lock, flags);
-
 //	DEB (printk ("\npci2220i received interrupt\n"));
 
 	for ( z = 0; z < NumAdapters;  z++ )								// scan for interrupt to process
@@ -1619,9 +1614,10 @@
 	if ( !shost )
 		{
 		DEB (printk ("\npci2220i: not my interrupt"));
-		goto irq_return;
+		goto out;
 		}
 
+	spin_lock_irqsave(&shost->host_lock, flags);
 	padapter = HOSTDATA(shost);
 	pdev = padapter->pdev;
 	SCpnt = padapter->SCpnt;
@@ -2023,13 +2019,9 @@
 		zl = DID_OK << 16;
 
 	OpDone (padapter, zl);
-irq_return:;
-    /*
-     * Release the I/O spinlock and restore the original flags
-     * which will enable interrupts if and only if they were
-     * enabled on entry.
-     */
-    spin_unlock_irqrestore (&io_request_lock, flags);
+irq_return:
+    spin_unlock_irqrestore(&shost->host_lock, flags);
+out:;
 	}
 /****************************************************************
  *	Name:	Pci2220i_QueueCommand
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/pcmcia/aha152x_stub.c linux/drivers/scsi/pcmcia/aha152x_stub.c
--- v2.5.1/linux/drivers/scsi/pcmcia/aha152x_stub.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/pcmcia/aha152x_stub.c	Tue Dec 25 17:04:40 2001
@@ -290,7 +290,7 @@
     }
     aha152x_setup("PCMCIA setup", ints);
     
-    scsi_register_module(MODULE_SCSI_HA, &driver_template);
+    scsi_register_host(&driver_template);
 
     tail = &link->dev;
     info->ndev = 0;
@@ -356,7 +356,7 @@
 	return;
     }
 
-    scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+    scsi_unregister_host(&driver_template);
     link->dev = NULL;
     
     CardServices(ReleaseConfiguration, link->handle);
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/pcmcia/fdomain_stub.c linux/drivers/scsi/pcmcia/fdomain_stub.c
--- v2.5.1/linux/drivers/scsi/pcmcia/fdomain_stub.c	Fri Mar  2 18:38:39 2001
+++ linux/drivers/scsi/pcmcia/fdomain_stub.c	Tue Dec 25 17:04:40 2001
@@ -254,7 +254,7 @@
     ints[2] = link->irq.AssignedIRQ;
     fdomain_setup("PCMCIA setup", ints);
     
-    scsi_register_module(MODULE_SCSI_HA, &driver_template);
+    scsi_register_host(&driver_template);
 
     tail = &link->dev;
     info->ndev = 0;
@@ -319,7 +319,7 @@
 	return;
     }
 
-    scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+    scsi_unregister_host(&driver_template);
     link->dev = NULL;
     
     CardServices(ReleaseConfiguration, link->handle);
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/pcmcia/nsp_cs.c linux/drivers/scsi/pcmcia/nsp_cs.c
--- v2.5.1/linux/drivers/scsi/pcmcia/nsp_cs.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/pcmcia/nsp_cs.c	Tue Dec 25 17:04:40 2001
@@ -1515,7 +1515,7 @@
 		goto cs_failed;
 	}
 
-	scsi_register_module(MODULE_SCSI_HA, &driver_template);
+	scsi_register_host(&driver_template);
 
 	DEBUG(0, "GET_SCSI_INFO\n");
 	tail = &link->dev;
@@ -1611,7 +1611,7 @@
 	}
 
 	/* Unlink the device chain */
-	scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+	scsi_unregister_host(&driver_template);
 	link->dev = NULL;
 
 	if (link->win) {
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/pcmcia/qlogic_stub.c linux/drivers/scsi/pcmcia/qlogic_stub.c
--- v2.5.1/linux/drivers/scsi/pcmcia/qlogic_stub.c	Fri Mar  2 18:38:39 2001
+++ linux/drivers/scsi/pcmcia/qlogic_stub.c	Tue Dec 25 17:04:40 2001
@@ -277,7 +277,7 @@
     else
 	qlogicfas_preset(link->io.BasePort1, link->irq.AssignedIRQ);
     
-    scsi_register_module(MODULE_SCSI_HA, &driver_template);
+    scsi_register_host(&driver_template);
 
     tail = &link->dev;
     info->ndev = 0;
@@ -341,7 +341,7 @@
 	return;
     }
 
-    scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+    scsi_unregister_host(&driver_template);
     link->dev = NULL;
     
     CardServices(ReleaseConfiguration, link->handle);
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/qla1280.c linux/drivers/scsi/qla1280.c
--- v2.5.1/linux/drivers/scsi/qla1280.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/qla1280.c	Sun Dec 30 10:31:51 2001
@@ -192,7 +192,6 @@
 #include <stdarg.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/segment.h>
 #include <asm/byteorder.h>
 #include <linux/version.h>
 #include <linux/types.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/qlogicfas.c linux/drivers/scsi/qlogicfas.c
--- v2.5.1/linux/drivers/scsi/qlogicfas.c	Thu Oct 25 13:53:51 2001
+++ linux/drivers/scsi/qlogicfas.c	Mon Dec 17 10:49:31 2001
@@ -467,10 +467,11 @@
 static void	    do_ql_ihandl(int irq, void *dev_id, struct pt_regs * regs)
 {
 	unsigned long flags;
+	struct Scsi_Host *host = dev_id;
 
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(&host->host_lock, flags);
 	ql_ihandl(irq, dev_id, regs);
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(&host->host_lock, flags);
 }
 #endif
 
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.5.1/linux/drivers/scsi/scsi.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/scsi.c	Thu Jan  3 11:35:06 2002
@@ -200,14 +200,11 @@
 
 	/* Hardware imposed limit. */
 	blk_queue_max_hw_segments(q, SHpnt->sg_tablesize);
-
-	/*
-	 * When we remove scsi_malloc soonish, this can die too
-	 */
-	blk_queue_max_phys_segments(q, PAGE_SIZE / sizeof(struct scatterlist));
-
 	blk_queue_max_sectors(q, SHpnt->max_sectors);
 
+	/* scsi_alloc_sgtable max */
+	blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
+
 	if (!SHpnt->use_clustering)
 		clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
 }
@@ -1405,9 +1402,6 @@
 	SCpnt->done(SCpnt);
 }
 
-static int scsi_register_host(Scsi_Host_Template *);
-static int scsi_unregister_host(Scsi_Host_Template *);
-
 /*
  * Function:    scsi_release_commandblocks()
  *
@@ -1842,7 +1836,7 @@
  * This entry point should be called by a driver if it is trying
  * to add a low level scsi driver to the system.
  */
-static int scsi_register_host(Scsi_Host_Template * tpnt)
+int scsi_register_host(Scsi_Host_Template * tpnt)
 {
 	int pcount;
 	struct Scsi_Host *shpnt;
@@ -1992,7 +1986,7 @@
  * Similarly, this entry point should be called by a loadable module if it
  * is trying to remove a low level scsi driver from the system.
  */
-static int scsi_unregister_host(Scsi_Host_Template * tpnt)
+int scsi_unregister_host(Scsi_Host_Template * tpnt)
 {
 	int online_status;
 	int pcount0, pcount;
@@ -2203,22 +2197,27 @@
 	return -1;
 }
 
-static int scsi_unregister_device(struct Scsi_Device_Template *tpnt);
-
 /*
  * This entry point should be called by a loadable module if it is trying
  * add a high level scsi driver to the system.
  */
-static int scsi_register_device_module(struct Scsi_Device_Template *tpnt)
+int scsi_register_device(struct Scsi_Device_Template *tpnt)
 {
 	Scsi_Device *SDpnt;
 	struct Scsi_Host *shpnt;
 	int out_of_space = 0;
 
+#ifdef CONFIG_KMOD
+	if (scsi_hosts == NULL)
+		request_module("scsi_hostadapter");
+#endif
+
 	if (tpnt->next)
 		return 1;
 
-	scsi_register_device(tpnt);
+	tpnt->next = scsi_devicelist;
+	scsi_devicelist = tpnt;
+
 	/*
 	 * First scan the devices that we know about, and see if we notice them.
 	 */
@@ -2274,7 +2273,7 @@
 		return 0;
 }
 
-static int scsi_unregister_device(struct Scsi_Device_Template *tpnt)
+int scsi_unregister_device(struct Scsi_Device_Template *tpnt)
 {
 	Scsi_Device *SDpnt;
 	struct Scsi_Host *shpnt;
@@ -2332,60 +2331,6 @@
 error_out:
 	unlock_kernel();
 	return -1;
-}
-
-
-/* This function should be called by drivers which needs to register
- * with the midlevel scsi system. As of 2.4.0-test9pre3 this is our
- * main device/hosts register function	/mathiasen
- */
-int scsi_register_module(int module_type, void *ptr)
-{
-	switch (module_type) {
-	case MODULE_SCSI_HA:
-		return scsi_register_host((Scsi_Host_Template *) ptr);
-
-		/* Load upper level device handler of some kind */
-	case MODULE_SCSI_DEV:
-#ifdef CONFIG_KMOD
-		if (scsi_hosts == NULL)
-			request_module("scsi_hostadapter");
-#endif
-		return scsi_register_device_module((struct Scsi_Device_Template *) ptr);
-		/* The rest of these are not yet implemented */
-
-		/* Load constants.o */
-	case MODULE_SCSI_CONST:
-
-		/* Load specialized ioctl handler for some device.  Intended for
-		 * cdroms that have non-SCSI2 audio command sets. */
-	case MODULE_SCSI_IOCTL:
-
-	default:
-		return 1;
-	}
-}
-
-/* Reverse the actions taken above
- */
-int scsi_unregister_module(int module_type, void *ptr)
-{
-	int retval = 0;
-
-	switch (module_type) {
-	case MODULE_SCSI_HA:
-		retval = scsi_unregister_host((Scsi_Host_Template *) ptr);
-		break;
-	case MODULE_SCSI_DEV:
-		retval = scsi_unregister_device((struct Scsi_Device_Template *)ptr);
- 		break;
-		/* The rest of these are not yet implemented. */
-	case MODULE_SCSI_CONST:
-	case MODULE_SCSI_IOCTL:
-		break;
-	default:;
-	}
-	return retval;
 }
 
 #ifdef CONFIG_PROC_FS
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v2.5.1/linux/drivers/scsi/scsi.h	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/scsi.h	Tue Jan  1 19:16:28 2002
@@ -434,7 +434,7 @@
 /*
  * Prototypes for functions in scsicam.c
  */
-extern int  scsi_partsize(struct buffer_head *bh, unsigned long capacity,
+extern int  scsi_partsize(unsigned char *buf, unsigned long capacity,
                     unsigned int *cyls, unsigned int *hds,
                     unsigned int *secs);
 
@@ -548,10 +548,8 @@
  */
 
 struct scsi_device {
-/* private: */
 	/*
-	 * This information is private to the scsi mid-layer.  Wrapping it in a
-	 * struct private is a way of marking it in a sort of C++ type of way.
+	 * This information is private to the scsi mid-layer.
 	 */
 	struct scsi_device *next;	/* Used for linked list */
 	struct scsi_device *prev;	/* Used for linked list */
@@ -563,7 +561,6 @@
 	volatile unsigned short device_busy;	/* commands actually active on low-level */
 	Scsi_Cmnd *device_queue;	/* queue of SCSI Command structures */
 
-/* public: */
 	unsigned int id, lun, channel;
 
 	unsigned int manufacturer;	/* Manufacturer of device, for using 
@@ -681,11 +678,7 @@
  */
 struct scsi_cmnd {
 	int     sc_magic;
-/* private: */
-	/*
-	 * This information is private to the scsi mid-layer.  Wrapping it in a
-	 * struct private is a way of marking it in a sort of C++ type of way.
-	 */
+
 	struct Scsi_Host *host;
 	unsigned short state;
 	unsigned short owner;
@@ -726,8 +719,6 @@
 	unsigned volatile char internal_timeout;
 	struct scsi_cmnd *bh_next;	/* To enumerate the commands waiting 
 					   to be processed. */
-
-/* public: */
 
 	unsigned int target;
 	unsigned int lun;
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c
--- v2.5.1/linux/drivers/scsi/scsi_lib.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/scsi_lib.c	Thu Jan  3 11:34:10 2002
@@ -83,7 +83,6 @@
 	rq->q = NULL;
 	rq->bio = rq->biotail = NULL;
 	rq->nr_phys_segments = 0;
-	rq->elevator_sequence = 0;
 
 	/*
 	 * We have the option of inserting the head or the tail of the queue.
@@ -92,7 +91,7 @@
 	 * device, or a host that is unable to accept a particular command.
 	 */
 	spin_lock_irqsave(q->queue_lock, flags);
-	__elv_add_request(q, rq, !at_head, 0);
+	_elv_add_request(q, rq, !at_head, 0);
 	q->request_fn(q);
 	spin_unlock_irqrestore(q->queue_lock, flags);
 }
@@ -262,7 +261,7 @@
 		 * the bad sector.
 		 */
 		SCpnt->request.special = (void *) SCpnt;
-		__elv_add_request(q, &SCpnt->request, 0, 0);
+		_elv_add_request(q, &SCpnt->request, 0, 0);
 	}
 
 	/*
@@ -385,7 +384,7 @@
 	if (req->waiting)
 		complete(req->waiting);
 
-	add_blkdev_randomness(MAJOR(req->rq_dev));
+	add_blkdev_randomness(major(req->rq_dev));
 
 	/*
 	 * This will goose the queue request function at the end, so we don't
@@ -744,7 +743,7 @@
 {
 	struct Scsi_Device_Template *spnt;
 	kdev_t dev = req->rq_dev;
-	int major = MAJOR(dev);
+	int major = major(dev);
 
 	for (spnt = scsi_devicelist; spnt; spnt = spnt->next) {
 		/*
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/scsi_merge.c linux/drivers/scsi/scsi_merge.c
--- v2.5.1/linux/drivers/scsi/scsi_merge.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/scsi_merge.c	Thu Dec 20 08:50:13 2001
@@ -59,12 +59,10 @@
  */
 int scsi_init_io(Scsi_Cmnd *SCpnt)
 {
-	struct request     *req;
+	struct request     *req = &SCpnt->request;
 	struct scatterlist *sgpnt;
 	int count, gfp_mask;
 
-	req = &SCpnt->request;
-
 	/*
 	 * First we need to know how many scatter gather segments are needed.
 	 */
@@ -85,14 +83,13 @@
 	BUG_ON(!sgpnt);
 
 	SCpnt->request_buffer = (char *) sgpnt;
-	SCpnt->request_bufflen = 0;
+	SCpnt->request_bufflen = req->nr_sectors << 9;
 	req->buffer = NULL;
 
 	/* 
 	 * Next, walk the list, and fill in the addresses and sizes of
 	 * each segment.
 	 */
-	SCpnt->request_bufflen = req->nr_sectors << 9;
 	count = blk_rq_map_sg(req->q, req, SCpnt->request_buffer);
 
 	/*
@@ -142,8 +139,7 @@
 			bounce_limit = BLK_BOUNCE_ANY;
 		else
 			bounce_limit = SHpnt->pci_dev->dma_mask;
-	}
-	if (SHpnt->unchecked_isa_dma)
+	} else if (SHpnt->unchecked_isa_dma)
 		bounce_limit = BLK_BOUNCE_ISA;
 
 	blk_queue_bounce_limit(q, bounce_limit);
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/scsi_module.c linux/drivers/scsi/scsi_module.c
--- v2.5.1/linux/drivers/scsi/scsi_module.c	Wed Sep 20 13:11:53 2000
+++ linux/drivers/scsi/scsi_module.c	Tue Dec 25 17:04:40 2001
@@ -35,17 +35,17 @@
 static int __init init_this_scsi_driver(void)
 {
 	driver_template.module = THIS_MODULE;
-	scsi_register_module(MODULE_SCSI_HA, &driver_template);
+	scsi_register_host(&driver_template);
 	if (driver_template.present)
 		return 0;
 
-	scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+	scsi_unregister_host(&driver_template);
 	return -ENODEV;
 }
 
 static void __exit exit_this_scsi_driver(void)
 {
-	scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+	scsi_unregister_host(&driver_template);
 }
 
 module_init(init_this_scsi_driver);
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/scsi_scan.c linux/drivers/scsi/scsi_scan.c
--- v2.5.1/linux/drivers/scsi/scsi_scan.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/scsi_scan.c	Sun Dec 30 16:58:51 2001
@@ -155,11 +155,14 @@
 	{"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN},
 	{"CMD", "CRA-7280", "*", BLIST_SPARSELUN},   // CMD RAID Controller
 	{"CNSI", "G7324", "*", BLIST_SPARSELUN},     // Chaparral G7324 RAID
+	{"CNSi", "G8324", "*", BLIST_SPARSELUN},     // Chaparral G8324 RAID
 	{"Zzyzx", "RocketStor 500S", "*", BLIST_SPARSELUN},
 	{"Zzyzx", "RocketStor 2000", "*", BLIST_SPARSELUN},
 	{"SONY", "TSL",       "*", BLIST_FORCELUN},  // DDS3 & DDS4 autoloaders
 	{"DELL", "PERCRAID", "*", BLIST_FORCELUN},
 	{"HP", "NetRAID-4M", "*", BLIST_FORCELUN},
+	{"ADAPTEC", "AACRAID", "*", BLIST_FORCELUN},
+	{"ADAPTEC", "Adaptec 5400S", "*", BLIST_FORCELUN},
 
 	/*
 	 * Must be at end of list...
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/scsi_syms.c linux/drivers/scsi/scsi_syms.c
--- v2.5.1/linux/drivers/scsi/scsi_syms.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/scsi_syms.c	Thu Dec 27 08:17:43 2001
@@ -31,12 +31,15 @@
  * This source file contains the symbol table used by scsi loadable
  * modules.
  */
-EXPORT_SYMBOL(scsi_register_module);
-EXPORT_SYMBOL(scsi_unregister_module);
+EXPORT_SYMBOL(scsi_register_device);
+EXPORT_SYMBOL(scsi_unregister_device);
+EXPORT_SYMBOL(scsi_register_host);
+EXPORT_SYMBOL(scsi_unregister_host);
 EXPORT_SYMBOL(scsi_register);
 EXPORT_SYMBOL(scsi_unregister);
 EXPORT_SYMBOL(scsicam_bios_param);
 EXPORT_SYMBOL(scsi_partsize);
+EXPORT_SYMBOL(scsi_bios_ptable);
 EXPORT_SYMBOL(scsi_allocate_device);
 EXPORT_SYMBOL(scsi_do_cmd);
 EXPORT_SYMBOL(scsi_command_size);
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/scsicam.c linux/drivers/scsi/scsicam.c
--- v2.5.1/linux/drivers/scsi/scsicam.c	Thu Nov 18 19:09:14 1999
+++ linux/drivers/scsi/scsicam.c	Tue Jan  1 11:53:31 2002
@@ -26,6 +26,22 @@
 static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds,
 		   unsigned int *secs);
 
+unsigned char *scsi_bios_ptable(kdev_t dev)
+{
+	unsigned char *res = kmalloc(66, GFP_KERNEL);
+	kdev_t rdev = mk_kdev(major(dev), minor(dev) & ~0x0f);
+
+	if (res) {
+		struct buffer_head *bh = bread(rdev, 0, block_size(rdev));
+		if (bh) {
+			memcpy(res, bh->b_data + 0x1be, 66);
+		} else {
+			kfree(res);
+			res = NULL;
+		}
+	}
+	return res;
+}
 
 /*
  * Function : int scsicam_bios_param (Disk *disk, int dev, int *ip)
@@ -42,26 +58,18 @@
 		       kdev_t dev,	/* Device major, minor */
 		  int *ip /* Heads, sectors, cylinders in that order */ )
 {
-	struct buffer_head *bh;
 	int ret_code;
 	int size = disk->capacity;
 	unsigned long temp_cyl;
+	unsigned char *p = scsi_bios_ptable(dev);
 
-	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 (!p)
 		return -1;
 
 	/* try to infer mapping from partition table */
-	ret_code = scsi_partsize(bh, (unsigned long) size, (unsigned int *) ip + 2,
+	ret_code = scsi_partsize(p, (unsigned long) size, (unsigned int *) ip + 2,
 		       (unsigned int *) ip + 0, (unsigned int *) ip + 1);
-	brelse(bh);
+	kfree(p);
 
 	if (ret_code == -1) {
 		/* pick some standard mapping with at most 1024 cylinders,
@@ -86,7 +94,7 @@
 }
 
 /*
- * Function : static int scsi_partsize(struct buffer_head *bh, unsigned long 
+ * Function : static int scsi_partsize(unsigned char *buf, unsigned long 
  *     capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs);
  *
  * Purpose : to determine the BIOS mapping used to create the partition
@@ -96,18 +104,17 @@
  *
  */
 
-int scsi_partsize(struct buffer_head *bh, unsigned long capacity,
+int scsi_partsize(unsigned char *buf, unsigned long capacity,
 	       unsigned int *cyls, unsigned int *hds, unsigned int *secs)
 {
-	struct partition *p, *largest = NULL;
+	struct partition *p = (struct partition *)buf, *largest = NULL;
 	int i, largest_cyl;
 	int cyl, ext_cyl, end_head, end_cyl, end_sector;
 	unsigned int logical_end, physical_end, ext_physical_end;
 
 
-	if (*(unsigned short *) (bh->b_data + 510) == 0xAA55) {
-		for (largest_cyl = -1, p = (struct partition *)
-		     (0x1BE + bh->b_data), i = 0; i < 4; ++i, ++p) {
+	if (*(unsigned short *) (buf + 66) == 0xAA55) {
+		for (largest_cyl = -1, i = 0; i < 4; ++i, ++p) {
 			if (!p->sys_ind)
 				continue;
 #ifdef DEBUG
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.5.1/linux/drivers/scsi/sd.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/sd.c	Mon Dec 31 18:01:44 2001
@@ -66,7 +66,7 @@
 #define SCSI_DISKS_PER_MAJOR	16
 #define SD_MAJOR_NUMBER(i)	SD_MAJOR((i) >> 8)
 #define SD_MINOR_NUMBER(i)	((i) & 255)
-#define MKDEV_SD_PARTITION(i)	MKDEV(SD_MAJOR_NUMBER(i), (i) & 255)
+#define MKDEV_SD_PARTITION(i)	mk_kdev(SD_MAJOR_NUMBER(i), (i) & 255)
 #define MKDEV_SD(index)		MKDEV_SD_PARTITION((index) << 4)
 #define N_USED_SD_MAJORS	(1 + ((sd_template.dev_max - 1) >> 4))
 
@@ -99,6 +99,7 @@
 static int sd_init_command(Scsi_Cmnd *);
 
 static struct Scsi_Device_Template sd_template = {
+	module:THIS_MODULE,
 	name:"disk",
 	tag:"sd",
 	scsi_type:TYPE_DISK,
@@ -568,7 +569,6 @@
 	major:		SCSI_DISK0_MAJOR,
 	major_name:	"sd",
 	minor_shift:	4,
-	max_p:		1 << 4,
 	fops:		&sd_fops,
 };
 
@@ -968,9 +968,9 @@
 			 */
 			int hard_sector = sector_size;
 			int sz = rscsi_disks[i].capacity * (hard_sector/256);
+			request_queue_t *queue = &rscsi_disks[i].device->request_queue;
 
-			/* There are 16 minors allocated for each major device */
-			blk_queue_hardsect_size(blk_get_queue(SD_MAJOR(i)), hard_sector);
+			blk_queue_hardsect_size(queue, hard_sector);
 			printk("SCSI device %s: "
 			       "%d %d-byte hdwr sectors (%d MB)\n",
 			       nbuff, rscsi_disks[i].capacity,
@@ -1115,7 +1115,7 @@
 	}
 
 	for (i = 0; i < N_USED_SD_MAJORS; i++) {
-		request_queue_t *q = blk_get_queue(SD_MAJOR(i));
+		request_queue_t *q = blk_get_queue(mk_kdev(SD_MAJOR(i), 0));
 		int parts_per_major = (SCSI_DISKS_PER_MAJOR << 4);
 
 		blksize_size[SD_MAJOR(i)] =
@@ -1140,12 +1140,9 @@
 		sd_gendisks[i].major = SD_MAJOR(i);
 		sd_gendisks[i].major_name = "sd";
 		sd_gendisks[i].minor_shift = 4;
-		sd_gendisks[i].max_p = 1 << 4;
 		sd_gendisks[i].part = sd + i * (N << 4);
 		sd_gendisks[i].sizes = sd_sizes + i * (N << 4);
 		sd_gendisks[i].nr_real = 0;
-		sd_gendisks[i].real_devices =
-		    (void *) (rscsi_disks + i * SCSI_DISKS_PER_MAJOR);
 	}
 
 	return 0;
@@ -1308,7 +1305,7 @@
 	for (dpnt = rscsi_disks, i = 0; i < sd_template.dev_max; i++, dpnt++)
 		if (dpnt->device == SDp) {
 
-			max_p = sd_gendisk.max_p;
+			max_p = 1 << sd_gendisk.minor_shift;
 			start = i << sd_gendisk.minor_shift;
 			dev = MKDEV_SD_PARTITION(start);
 			wipe_partitions(dev);
@@ -1332,14 +1329,14 @@
 static int __init init_sd(void)
 {
 	sd_template.module = THIS_MODULE;
-	return scsi_register_module(MODULE_SCSI_DEV, &sd_template);
+	return scsi_register_device(&sd_template);
 }
 
 static void __exit exit_sd(void)
 {
 	int i;
 
-	scsi_unregister_module(MODULE_SCSI_DEV, &sd_template);
+	scsi_unregister_device(&sd_template);
 
 	for (i = 0; i < N_USED_SD_MAJORS; i++)
 		devfs_unregister_blkdev(SD_MAJOR(i), "sd");
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/sd.h linux/drivers/scsi/sd.h
--- v2.5.1/linux/drivers/scsi/sd.h	Thu Nov 22 11:49:15 2001
+++ linux/drivers/scsi/sd.h	Tue Jan  1 19:16:28 2002
@@ -45,7 +45,7 @@
 #define N_SD_MAJORS	8
 
 #define SD_MAJOR_MASK	(N_SD_MAJORS - 1)
-#define SD_PARTITION(i)		(((MAJOR(i) & SD_MAJOR_MASK) << 8) | (MINOR(i) & 255))
+#define SD_PARTITION(i)		(((major(i) & SD_MAJOR_MASK) << 8) | (minor(i) & 255))
 
 #endif
 
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v2.5.1/linux/drivers/scsi/sg.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/sg.c	Thu Jan  3 11:35:33 2002
@@ -121,6 +121,7 @@
 
 static struct Scsi_Device_Template sg_template =
 {
+      module:THIS_MODULE,
       tag:"sg",
       scsi_type:0xff,
       major:SCSI_GENERIC_MAJOR,
@@ -253,7 +254,7 @@
 
 static int sg_open(struct inode * inode, struct file * filp)
 {
-    int dev = MINOR(inode->i_rdev);
+    int dev = minor(inode->i_rdev);
     int flags = filp->f_flags;
     Sg_device * sdp;
     Sg_fd * sfp;
@@ -339,7 +340,7 @@
     if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) {
         return -ENXIO;
     }
-    SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", MINOR(sdp->i_rdev)));
+    SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", minor(sdp->i_rdev)));
     sg_fasync(-1, filp, 0);   /* remove filp from async notification list */
     if (0 == sg_remove_sfp(sdp, sfp)) { /* Returns 1 when sdp gone */
         if (! sdp->detached) {
@@ -368,7 +369,7 @@
     if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
         return -ENXIO;
     SCSI_LOG_TIMEOUT(3, printk("sg_read: dev=%d, count=%d\n",
-                               MINOR(sdp->i_rdev), (int)count));
+                               minor(sdp->i_rdev), (int)count));
     if (ppos != &filp->f_pos)
         ; /* FIXME: Hmm.  Seek to the right place, or fail?  */
     if ((k = verify_area(VERIFY_WRITE, buf, count)))
@@ -513,7 +514,7 @@
     if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
         return -ENXIO;
     SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n",
-                               MINOR(sdp->i_rdev), (int)count));
+                               minor(sdp->i_rdev), (int)count));
     if (sdp->detached)
     	return -ENODEV;
     if (! ((filp->f_flags & O_NONBLOCK) ||
@@ -730,7 +731,7 @@
     if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
         return -ENXIO;
     SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: dev=%d, cmd=0x%x\n",
-                               MINOR(sdp->i_rdev), (int)cmd_in));
+                               minor(sdp->i_rdev), (int)cmd_in));
     read_only = (O_RDWR != (filp->f_flags & O_ACCMODE));
 
     switch(cmd_in)
@@ -1010,7 +1011,7 @@
     else if (count < SG_MAX_QUEUE)
         res |= POLLOUT | POLLWRNORM;
     SCSI_LOG_TIMEOUT(3, printk("sg_poll: dev=%d, res=0x%x\n",
-                        MINOR(sdp->i_rdev), (int)res));
+                        minor(sdp->i_rdev), (int)res));
     return res;
 }
 
@@ -1023,7 +1024,7 @@
     if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
         return -ENXIO;
     SCSI_LOG_TIMEOUT(3, printk("sg_fasync: dev=%d, mode=%d\n",
-                               MINOR(sdp->i_rdev), mode));
+                               minor(sdp->i_rdev), mode));
 
     retval = fasync_helper(fd, filp, mode, &sfp->async_qp);
     return (retval < 0) ? retval : 0;
@@ -1034,7 +1035,7 @@
 static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt)
 {
     Scsi_Request * SRpnt = SCpnt->sc_request;
-    int dev = MINOR(SRpnt->sr_request.rq_dev);
+    int dev = minor(SRpnt->sr_request.rq_dev);
     Sg_device * sdp = NULL;
     Sg_fd * sfp;
     Sg_request * srp = NULL;
@@ -1277,7 +1278,7 @@
     sdp->sgdebug = 0;
     sdp->detached = 0;
     sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0;
-    sdp->i_rdev = MKDEV(SCSI_GENERIC_MAJOR, k);
+    sdp->i_rdev = mk_kdev(SCSI_GENERIC_MAJOR, k);
     sdp->de = devfs_register (scsidp->de, "generic", DEVFS_FL_DEFAULT,
                              SCSI_GENERIC_MAJOR, k,
                              S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
@@ -1378,8 +1379,7 @@
 static int __init init_sg(void) {
     if (def_reserved_size >= 0)
 	sg_big_buff = def_reserved_size;
-    sg_template.module = THIS_MODULE;
-    return scsi_register_module(MODULE_SCSI_DEV, &sg_template);
+    return scsi_register_device(&sg_template);
 }
 
 static void __exit exit_sg( void)
@@ -1387,7 +1387,7 @@
 #ifdef CONFIG_PROC_FS
     sg_proc_cleanup();
 #endif  /* CONFIG_PROC_FS */
-    scsi_unregister_module(MODULE_SCSI_DEV, &sg_template);
+    scsi_unregister_device(&sg_template);
     devfs_unregister_chrdev(SCSI_GENERIC_MAJOR, "sg");
     if(sg_dev_arr != NULL) {
 	kfree((char *)sg_dev_arr);
@@ -2415,7 +2415,7 @@
     SRpnt->sr_bufflen = 0;
     SRpnt->sr_buffer = NULL;
     SRpnt->sr_underflow = 0;
-    SRpnt->sr_request.rq_dev = MKDEV(0, 0);  /* "sg" _disowns_ command blk */
+    SRpnt->sr_request.rq_dev = mk_kdev(0, 0);  /* "sg" _disowns_ command blk */
 }
 
 static int sg_ms_to_jif(unsigned int msecs)
@@ -2694,7 +2694,7 @@
 		PRINT_PROC("device %d detached ??\n", j);
 		continue;
 	    }
-	    dev = MINOR(sdp->i_rdev);
+	    dev = minor(sdp->i_rdev);
 
 	    if (sg_get_nth_sfp(sdp, 0)) {
 		PRINT_PROC(" >>> device=sg%d ", dev);
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/sim710.c linux/drivers/scsi/sim710.c
--- v2.5.1/linux/drivers/scsi/sim710.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/scsi/sim710.c	Tue Jan  1 18:54:20 2002
@@ -904,11 +904,12 @@
 static void
 do_sim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
 {
+    struct Scsi_Host *host = dev_id;
     unsigned long flags;
 
-    spin_lock_irqsave(&io_request_lock, flags);
-    sim710_intr_handle(irq, dev_id, regs);
-    spin_unlock_irqrestore(&io_request_lock, flags);
+    spin_lock_irqsave(&host->host_lock, flags);
+    sim710_intr_handle(irq, host, regs);
+    spin_unlock_irqrestore(&host->host_lock, flags);
 }
 
 
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.5.1/linux/drivers/scsi/sr.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/sr.c	Thu Jan  3 11:35:33 2002
@@ -71,6 +71,7 @@
 
 static struct Scsi_Device_Template sr_template =
 {
+	module:THIS_MODULE,
 	name:"cdrom",
 	tag:"sr",
 	scsi_type:TYPE_ROM,
@@ -98,11 +99,11 @@
 
 static void sr_release(struct cdrom_device_info *cdi)
 {
-	if (scsi_CDs[MINOR(cdi->dev)].device->sector_size > 2048)
-		sr_set_blocklength(MINOR(cdi->dev), 2048);
-	scsi_CDs[MINOR(cdi->dev)].device->access_count--;
-	if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module)
-		__MOD_DEC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module);
+	if (scsi_CDs[minor(cdi->dev)].device->sector_size > 2048)
+		sr_set_blocklength(minor(cdi->dev), 2048);
+	scsi_CDs[minor(cdi->dev)].device->access_count--;
+	if (scsi_CDs[minor(cdi->dev)].device->host->hostt->module)
+		__MOD_DEC_USE_COUNT(scsi_CDs[minor(cdi->dev)].device->host->hostt->module);
 	if (sr_template.module)
 		__MOD_DEC_USE_COUNT(sr_template.module);
 }
@@ -149,7 +150,7 @@
 		/* no changer support */
 		return -EINVAL;
 	}
-	retval = scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device,
+	retval = scsi_ioctl(scsi_CDs[minor(cdi->dev)].device,
 			    SCSI_IOCTL_TEST_UNIT_READY, 0);
 
 	if (retval) {
@@ -158,13 +159,13 @@
 		 * and we will figure it out later once the drive is
 		 * available again.  */
 
-		scsi_CDs[MINOR(cdi->dev)].device->changed = 1;
+		scsi_CDs[minor(cdi->dev)].device->changed = 1;
 		return 1;	/* This will force a flush, if called from
 				 * check_disk_change */
 	};
 
-	retval = scsi_CDs[MINOR(cdi->dev)].device->changed;
-	scsi_CDs[MINOR(cdi->dev)].device->changed = 0;
+	retval = scsi_CDs[minor(cdi->dev)].device->changed;
+	scsi_CDs[minor(cdi->dev)].device->changed = 0;
 	/* If the disk changed, the capacity will now be different,
 	 * so we force a re-read of this information */
 	if (retval) {
@@ -178,9 +179,9 @@
 		 * be trying to use something that is too small if the disc
 		 * has changed.
 		 */
-		scsi_CDs[MINOR(cdi->dev)].needs_sector_size = 1;
+		scsi_CDs[minor(cdi->dev)].needs_sector_size = 1;
 
-		scsi_CDs[MINOR(cdi->dev)].device->sector_size = 2048;
+		scsi_CDs[minor(cdi->dev)].device->sector_size = 2048;
 	}
 	return retval;
 }
@@ -252,17 +253,17 @@
 	/*
 	 * No such device
 	 */
-	if (MINOR(dev) >= sr_template.dev_max || !scsi_CDs[MINOR(dev)].device)
+	if (minor(dev) >= sr_template.dev_max || !scsi_CDs[minor(dev)].device)
 		return NULL;
 
-	return &scsi_CDs[MINOR(dev)].device->request_queue;
+	return &scsi_CDs[minor(dev)].device->request_queue;
 }
 
 static int sr_init_command(Scsi_Cmnd * SCpnt)
 {
 	int dev, devm, block=0, this_count, s_size;
 
-	devm = MINOR(SCpnt->request.rq_dev);
+	devm = minor(SCpnt->request.rq_dev);
 	dev = DEVICE_NR(SCpnt->request.rq_dev);
 
 	SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %d, block = %d\n", devm, block));
@@ -287,9 +288,6 @@
 		return 0;
 	}
 
-	if (rq_data_dir(&SCpnt->request) == WRITE && !scsi_CDs[dev].device->writeable)
-		return 0;
-
 	/*
 	 * we do lazy blocksize switching (when reading XA sectors,
 	 * see CDROMREADMODE2 ioctl) 
@@ -401,20 +399,20 @@
 {
 	check_disk_change(cdi->dev);
 
-	if (MINOR(cdi->dev) >= sr_template.dev_max
-	    || !scsi_CDs[MINOR(cdi->dev)].device) {
+	if (minor(cdi->dev) >= sr_template.dev_max
+	    || !scsi_CDs[minor(cdi->dev)].device) {
 		return -ENXIO;	/* No such device */
 	}
 	/*
 	 * If the device is in error recovery, wait until it is done.
 	 * If the device is offline, then disallow any access to it.
 	 */
-	if (!scsi_block_when_processing_errors(scsi_CDs[MINOR(cdi->dev)].device)) {
+	if (!scsi_block_when_processing_errors(scsi_CDs[minor(cdi->dev)].device)) {
 		return -ENXIO;
 	}
-	scsi_CDs[MINOR(cdi->dev)].device->access_count++;
-	if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module)
-		__MOD_INC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module);
+	scsi_CDs[minor(cdi->dev)].device->access_count++;
+	if (scsi_CDs[minor(cdi->dev)].device->host->hostt->module)
+		__MOD_INC_USE_COUNT(scsi_CDs[minor(cdi->dev)].device->host->hostt->module);
 	if (sr_template.module)
 		__MOD_INC_USE_COUNT(sr_template.module);
 
@@ -423,8 +421,8 @@
 	 * this is the case, and try again.
 	 */
 
-	if (scsi_CDs[MINOR(cdi->dev)].needs_sector_size)
-		get_sectorsize(MINOR(cdi->dev));
+	if (scsi_CDs[minor(cdi->dev)].needs_sector_size)
+		get_sectorsize(minor(cdi->dev));
 
 	return 0;
 }
@@ -477,6 +475,7 @@
 	int the_result, retries;
 	int sector_size;
 	Scsi_Request *SRpnt;
+	request_queue_t *queue;
 
 	buffer = (unsigned char *) kmalloc(512, GFP_DMA);
 	SRpnt = scsi_allocate_request(scsi_CDs[i].device);
@@ -566,8 +565,9 @@
 		 */
 		scsi_CDs[i].needs_sector_size = 0;
 		sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9);
-	};
-	blk_queue_hardsect_size(blk_get_queue(MAJOR_NR), sector_size);
+	}
+	queue = &scsi_CDs[i].device->request_queue;
+	blk_queue_hardsect_size(queue, sector_size);
 	kfree(buffer);
 }
 
@@ -671,13 +671,13 @@
  */
 static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc)
 {
-	Scsi_Device *device = scsi_CDs[MINOR(cdi->dev)].device;
+	Scsi_Device *device = scsi_CDs[minor(cdi->dev)].device;
 
 	/* set the LUN */
 	if (device->scsi_level <= SCSI_2)
 		cgc->cmd[1] |= device->lun << 5;
 
-	cgc->stat = sr_do_ioctl(MINOR(cdi->dev), cgc->cmd, cgc->buffer, cgc->buflen, cgc->quiet, cgc->data_direction, cgc->sense);
+	cgc->stat = sr_do_ioctl(minor(cdi->dev), cgc->cmd, cgc->buffer, cgc->buflen, cgc->quiet, cgc->data_direction, cgc->sense);
 
 	return cgc->stat;
 }
@@ -766,7 +766,7 @@
 
 		scsi_CDs[i].cdi.ops = &sr_dops;
 		scsi_CDs[i].cdi.handle = &scsi_CDs[i];
-		scsi_CDs[i].cdi.dev = MKDEV(MAJOR_NR, i);
+		scsi_CDs[i].cdi.dev = mk_kdev(MAJOR_NR, i);
 		scsi_CDs[i].cdi.mask = 0;
 		scsi_CDs[i].cdi.capacity = 1;
 		/*
@@ -809,7 +809,7 @@
 			 * the device.
 			 * We should be kind to our buffer cache, however.
 			 */
-			invalidate_device(MKDEV(MAJOR_NR, i), 0);
+			invalidate_device(mk_kdev(MAJOR_NR, i), 0);
 
 			/*
 			 * Reset things back to a sane state so that one can
@@ -829,13 +829,12 @@
 
 static int __init init_sr(void)
 {
-	sr_template.module = THIS_MODULE;
-	return scsi_register_module(MODULE_SCSI_DEV, &sr_template);
+	return scsi_register_device(&sr_template);
 }
 
 static void __exit exit_sr(void)
 {
-	scsi_unregister_module(MODULE_SCSI_DEV, &sr_template);
+	scsi_unregister_device(&sr_template);
 	devfs_unregister_blkdev(MAJOR_NR, "sr");
 	sr_registered--;
 	if (scsi_CDs != NULL) {
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v2.5.1/linux/drivers/scsi/sr_ioctl.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/sr_ioctl.c	Thu Jan  3 11:35:33 2002
@@ -68,7 +68,7 @@
 	sr_cmd[6] = trk1_te.cdte_addr.msf.minute;
 	sr_cmd[7] = trk1_te.cdte_addr.msf.second;
 	sr_cmd[8] = trk1_te.cdte_addr.msf.frame;
-	return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL);
+	return sr_do_ioctl(minor(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL);
 }
 
 /* We do our own retries because we want to know what the specific
@@ -206,17 +206,17 @@
 	u_char sr_cmd[10];
 
 	sr_cmd[0] = GPCMD_START_STOP_UNIT;
-	sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ?
-	            ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0;
+	sr_cmd[1] = (scsi_CDs[minor(cdi->dev)].device->scsi_level <= SCSI_2) ?
+	            ((scsi_CDs[minor(cdi->dev)].device->lun) << 5) : 0;
 	sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
 	sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ;
 
-	return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL);
+	return sr_do_ioctl(minor(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL);
 }
 
 int sr_lock_door(struct cdrom_device_info *cdi, int lock)
 {
-	return scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device,
+	return scsi_ioctl(scsi_CDs[minor(cdi->dev)].device,
 		      lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK,
 			  0);
 }
@@ -227,7 +227,7 @@
 		/* we have no changer support */
 		return -EINVAL;
 	}
-	if (0 == test_unit_ready(MINOR(cdi->dev)))
+	if (0 == test_unit_ready(minor(cdi->dev)))
 		return CDS_DISC_OK;
 
 	return CDS_TRAY_OPEN;
@@ -256,7 +256,7 @@
 	if (!have_datatracks)
 		return CDS_AUDIO;
 
-	if (scsi_CDs[MINOR(cdi->dev)].xa_flag)
+	if (scsi_CDs[minor(cdi->dev)].xa_flag)
 		return CDS_XA_2_1;
 	else
 		return CDS_DATA_1;
@@ -265,9 +265,9 @@
 int sr_get_last_session(struct cdrom_device_info *cdi,
 			struct cdrom_multisession *ms_info)
 {
-	ms_info->addr.lba = scsi_CDs[MINOR(cdi->dev)].ms_offset;
-	ms_info->xa_flag = scsi_CDs[MINOR(cdi->dev)].xa_flag ||
-	    (scsi_CDs[MINOR(cdi->dev)].ms_offset > 0);
+	ms_info->addr.lba = scsi_CDs[minor(cdi->dev)].ms_offset;
+	ms_info->xa_flag = scsi_CDs[minor(cdi->dev)].xa_flag ||
+	    (scsi_CDs[minor(cdi->dev)].ms_offset > 0);
 
 	return 0;
 }
@@ -279,8 +279,8 @@
 	int result;
 
 	sr_cmd[0] = GPCMD_READ_SUBCHANNEL;
-	sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ?
-	            ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0;
+	sr_cmd[1] = (scsi_CDs[minor(cdi->dev)].device->scsi_level <= SCSI_2) ?
+	            ((scsi_CDs[minor(cdi->dev)].device->lun) << 5) : 0;
 	sr_cmd[2] = 0x40;	/* I do want the subchannel info */
 	sr_cmd[3] = 0x02;	/* Give me medium catalog number info */
 	sr_cmd[4] = sr_cmd[5] = 0;
@@ -289,7 +289,7 @@
 	sr_cmd[8] = 24;
 	sr_cmd[9] = 0;
 
-	result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0, SCSI_DATA_READ, NULL);
+	result = sr_do_ioctl(minor(cdi->dev), sr_cmd, buffer, 24, 0, SCSI_DATA_READ, NULL);
 
 	memcpy(mcn->medium_catalog_number, buffer + 9, 13);
 	mcn->medium_catalog_number[13] = 0;
@@ -314,12 +314,12 @@
 
 	memset(sr_cmd, 0, MAX_COMMAND_SIZE);
 	sr_cmd[0] = GPCMD_SET_SPEED;	/* SET CD SPEED */
-	sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ?
-	            ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0;
+	sr_cmd[1] = (scsi_CDs[minor(cdi->dev)].device->scsi_level <= SCSI_2) ?
+	            ((scsi_CDs[minor(cdi->dev)].device->lun) << 5) : 0;
 	sr_cmd[2] = (speed >> 8) & 0xff;	/* MSB for speed (in kbytes/sec) */
 	sr_cmd[3] = speed & 0xff;	/* LSB */
 
-	if (sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL))
+	if (sr_do_ioctl(minor(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL))
 		return -EIO;
 	return 0;
 }
@@ -333,7 +333,7 @@
 int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
 {
 	u_char sr_cmd[10];
-	int result, target = MINOR(cdi->dev);
+	int result, target = minor(cdi->dev);
 	unsigned char buffer[32];
 
 	memset(sr_cmd, 0, sizeof(sr_cmd));
@@ -541,7 +541,7 @@
 {
 	int target;
 
-	target = MINOR(cdi->dev);
+	target = minor(cdi->dev);
 
 	switch (cmd) {
 	case BLKGETSIZE:
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c
--- v2.5.1/linux/drivers/scsi/sr_vendor.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/sr_vendor.c	Thu Jan  3 11:35:33 2002
@@ -158,7 +158,7 @@
 	unsigned char cmd[MAX_COMMAND_SIZE];	/* the scsi-command */
 	int rc, no_multi, minor;
 
-	minor = MINOR(cdi->dev);
+	minor = minor(cdi->dev);
 	if (scsi_CDs[minor].cdi.mask & CDC_MULTI_SESSION)
 		return 0;
 
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.5.1/linux/drivers/scsi/st.c	Fri Nov  9 13:52:21 2001
+++ linux/drivers/scsi/st.c	Tue Dec 25 17:04:40 2001
@@ -3867,14 +3867,14 @@
 	validate_options();
 
 	st_template.module = THIS_MODULE;
-        return scsi_register_module(MODULE_SCSI_DEV, &st_template);
+        return scsi_register_device(&st_template);
 }
 
 static void __exit exit_st(void)
 {
 	int i;
 
-	scsi_unregister_module(MODULE_SCSI_DEV, &st_template);
+	scsi_unregister_device(&st_template);
 	devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st");
 	st_registered--;
 	if (scsi_tapes != NULL) {
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/sym53c8xx_comm.h linux/drivers/scsi/sym53c8xx_comm.h
--- v2.5.1/linux/drivers/scsi/sym53c8xx_comm.h	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/sym53c8xx_comm.h	Sun Dec 30 16:54:29 2001
@@ -438,10 +438,10 @@
 #define	NCR_LOCK_NCB(np, flags)    spin_lock_irqsave(&np->smp_lock, flags)
 #define	NCR_UNLOCK_NCB(np, flags)  spin_unlock_irqrestore(&np->smp_lock, flags)
 
-#define	NCR_LOCK_SCSI_DONE(np, flags) \
-		spin_lock_irqsave(&io_request_lock, flags)
-#define	NCR_UNLOCK_SCSI_DONE(np, flags) \
-		spin_unlock_irqrestore(&io_request_lock, flags)
+#define	NCR_LOCK_SCSI_DONE(host, flags) \
+		spin_lock_irqsave(&(host)->host_lock, flags)
+#define	NCR_UNLOCK_SCSI_DONE(host, flags) \
+		spin_unlock_irqrestore(&((host)->host_lock), flags)
 
 #else
 
@@ -452,8 +452,8 @@
 #define	NCR_LOCK_NCB(np, flags)    do { save_flags(flags); cli(); } while (0)
 #define	NCR_UNLOCK_NCB(np, flags)  do { restore_flags(flags); } while (0)
 
-#define	NCR_LOCK_SCSI_DONE(np, flags)    do {;} while (0)
-#define	NCR_UNLOCK_SCSI_DONE(np, flags)  do {;} while (0)
+#define	NCR_LOCK_SCSI_DONE(host, flags)    do {;} while (0)
+#define	NCR_UNLOCK_SCSI_DONE(host, flags)  do {;} while (0)
 
 #endif
 
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c
--- v2.5.1/linux/drivers/scsi/tmscsim.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/scsi/tmscsim.c	Thu Dec 27 08:17:43 2001
@@ -1371,7 +1371,7 @@
 #include <asm/unaligned.h>
 
 /*
- * Function : static int partsize(struct buffer_head *bh, unsigned long 
+ * Function : static int partsize(unsigned char *buf, unsigned long 
  *     capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs);
  *
  * Purpose : to determine the BIOS mapping used to create the partition
@@ -1381,7 +1381,7 @@
  *
  */
 
-static int partsize(struct buffer_head *bh, unsigned long capacity,
+static int partsize(unsigned char *buf, unsigned long capacity,
     unsigned int  *cyls, unsigned int *hds, unsigned int *secs) {
     struct partition *p, *largest = NULL;
     int i, largest_cyl;
@@ -1389,9 +1389,9 @@
     unsigned int logical_end, physical_end, ext_physical_end;
     
 
-    if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
-	for (largest_cyl = -1, p = (struct partition *) 
-    	    (0x1BE + bh->b_data), i = 0; i < 4; ++i, ++p) {
+    if (*(unsigned short *) (buf+64) == 0xAA55) {
+	for (largest_cyl = -1, p = (struct partition *) buf, 
+    	    i = 0; i < 4; ++i, ++p) {
     	    if (!p->sys_ind)
     	    	continue;
     	    cyl = p->cyl + ((p->sector & 0xc0) << 2);
@@ -1446,16 +1446,16 @@
 {
     int heads, sectors, cylinders;
     PACB pACB = (PACB) disk->device->host->hostdata;
-    struct buffer_head *bh;
     int ret_code = -1;
     int size = disk->capacity;
+    unsigned char *buf;
 
-    if ((bh = bread(MKDEV(MAJOR(devno), MINOR(devno)&~0xf), 0, 1024)))
+    if ((buf = scsi_bios_ptable(devno)))
     {
 	/* try to infer mapping from partition table */
-	ret_code = partsize (bh, (unsigned long) size, (unsigned int *) geom + 2,
+	ret_code = partsize (buf, (unsigned long) size, (unsigned int *) geom + 2,
 			     (unsigned int *) geom + 0, (unsigned int *) geom + 1);
-	brelse (bh);
+	kfree (buf);
     }
     if (ret_code == -1)
     {
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c
--- v2.5.1/linux/drivers/scsi/u14-34f.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/u14-34f.c	Thu Jan  3 12:19:03 2002
@@ -1,6 +1,13 @@
 /*
  *      u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
  *
+ *      01 Jan 2002 Rev. 7.20 for linux 2.5.1
+ *        + Use the dynamic DMA mapping API.
+ *
+ *      19 Dec 2001 Rev. 7.02 for linux 2.5.1
+ *        + Use SCpnt->sc_data_direction if set.
+ *        + Use sglist.page instead of sglist.address.
+ *
  *      11 Dec 2001 Rev. 7.00 for linux 2.5.1
  *        + Use host->host_lock instead of io_request_lock.
  *
@@ -186,7 +193,7 @@
  *
  *          Multiple U14F and/or U34F host adapters are supported.
  *
- *  Copyright (C) 1994-2001 Dario Ballabio (ballabio_dario@emc.com)
+ *  Copyright (C) 1994-2002 Dario Ballabio (ballabio_dario@emc.com)
  *
  *  Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it
  *
@@ -377,6 +384,7 @@
 #include "u14-34f.h"
 #include <linux/stat.h>
 #include <linux/config.h>
+#include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ctype.h>
 #include <linux/spinlock.h>
@@ -483,13 +491,13 @@
    unsigned char clink_id;              /* identifies command in chain */
    unsigned char use_sg;                /* (if sg is set) 8 bytes per list */
    unsigned char sense_len;
-   unsigned char scsi_cdbs_len;         /* 6, 10, or 12 */
-   unsigned char scsi_cdbs[12];         /* SCSI commands */
+   unsigned char cdb_len;               /* 6, 10, or 12 */
+   unsigned char cdb[12];               /* SCSI Command Descriptor Block */
    unsigned char adapter_status;        /* non-zero indicates HA error */
    unsigned char target_status;         /* non-zero indicates target error */
    unsigned int sense_addr PACKED;
    Scsi_Cmnd *SCpnt;
-   unsigned int index;                  /* cp index */
+   unsigned int cpp_index;              /* cp index */
    struct sg_list *sglist;
    };
 
@@ -507,6 +515,7 @@
    unsigned int retries;                /* Number of internal retries */
    unsigned long last_retried_pid;      /* Pid of last retried command */
    unsigned char subversion;            /* Bus type, either ISA or ESA */
+   struct pci_dev *pdev;                /* Always NULL */
    unsigned char heads;
    unsigned char sectors;
 
@@ -537,21 +546,11 @@
 #define HD(board) ((struct hostdata *) &sh[board]->hostdata)
 #define BN(board) (HD(board)->board_name)
 
-#define SWAP_BYTE(x) ((unsigned long)( \
-        (((unsigned long)(x) & 0x000000ffU) << 24) | \
-        (((unsigned long)(x) & 0x0000ff00U) <<  8) | \
-        (((unsigned long)(x) & 0x00ff0000U) >>  8) | \
-        (((unsigned long)(x) & 0xff000000U) >> 24)))
+/* Device is Little Endian */
+#define H2DEV(x) cpu_to_le32(x)
+#define DEV2H(x) le32_to_cpu(x)
 
-#if defined(__BIG_ENDIAN)
-#define H2DEV(x) SWAP_BYTE(x)
-#else
-#define H2DEV(x) (x)
-#endif
-
-#define DEV2H(x) H2DEV(x)
 #define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
-#define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0)
 
 static void do_interrupt_handler(int, void *, struct pt_regs *);
 static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
@@ -653,8 +652,8 @@
    cpp->xdir = DTD_IN;
    cpp->data_address = V2DEV(HD(j)->board_id);
    cpp->data_len = H2DEV(sizeof(HD(j)->board_id));
-   cpp->scsi_cdbs_len = 6;
-   cpp->scsi_cdbs[0] = HA_CMD_INQUIRY;
+   cpp->cdb_len = 6;
+   cpp->cdb[0] = HA_CMD_INQUIRY;
 
    if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
       printk("%s: board_inquiry, adapter busy.\n", BN(j));
@@ -832,14 +831,14 @@
       unsigned long flags;
       scsi_register_blocked_host(sh[j]);
       sh[j]->unchecked_isa_dma = TRUE;
-      
+
       flags=claim_dma_lock();
       disable_dma(dma_channel);
       clear_dma_ff(dma_channel);
       set_dma_mode(dma_channel, DMA_MODE_CASCADE);
       enable_dma(dma_channel);
       release_dma_lock(flags);
-      
+
       sh[j]->dma_channel = dma_channel;
       sprintf(BN(j), "U14F%d", j);
       bus_type = "ISA";
@@ -879,7 +878,7 @@
    if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN;
 
    if (j == 0) {
-      printk("UltraStor 14F/34F: Copyright (C) 1994-2001 Dario Ballabio.\n");
+      printk("UltraStor 14F/34F: Copyright (C) 1994-2002 Dario Ballabio.\n");
       printk("%s config options -> of:%c, lc:%c, mq:%d, et:%c.\n",
              driver_name, YESNO(have_old_firmware), YESNO(linked_comm),
              max_queue_depth, YESNO(ext_tran));
@@ -949,8 +948,7 @@
    return 1;
 }
 
-int u14_34f_detect(Scsi_Host_Template *tpnt)
-{
+int u14_34f_detect(Scsi_Host_Template *tpnt) {
    unsigned int j = 0, k;
 
    tpnt->proc_name = "u14-34f";
@@ -978,26 +976,95 @@
    return j;
 }
 
-static inline void build_sg_list(struct mscp *cpp, Scsi_Cmnd *SCpnt) {
-   unsigned int k, data_len = 0;
+static inline void map_dma(unsigned int i, unsigned int j) {
+   unsigned int data_len = 0;
+   unsigned int k, count, pci_dir;
    struct scatterlist *sgpnt;
+   struct mscp *cpp;
+   Scsi_Cmnd *SCpnt;
+
+   cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+   pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction);
+
+   if (SCpnt->sense_buffer)
+      cpp->sense_addr = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->sense_buffer,
+                           sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE));
+
+   cpp->sense_len = sizeof SCpnt->sense_buffer;
+
+   if (!SCpnt->use_sg) {
+
+      if (!SCpnt->request_bufflen)
+         cpp->data_address = V2DEV(SCpnt->request_buffer);
+
+      else if (SCpnt->request_buffer)
+         cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev,
+                  SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir));
+
+      cpp->data_len = H2DEV(SCpnt->request_bufflen);
+      return;
+      }
 
    sgpnt = (struct scatterlist *) SCpnt->request_buffer;
+   count = pci_map_sg(HD(j)->pdev, sgpnt, SCpnt->use_sg, pci_dir);
 
-   for (k = 0; k < SCpnt->use_sg; k++) {
-      cpp->sglist[k].address = V2DEV(sgpnt[k].address);
-      cpp->sglist[k].num_bytes = H2DEV(sgpnt[k].length);
+   for (k = 0; k < count; k++) {
+      cpp->sglist[k].address = H2DEV(sg_dma_address(&sgpnt[k]));
+      cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(&sgpnt[k]));
       data_len += sgpnt[k].length;
       }
 
+   cpp->sg = TRUE;
    cpp->use_sg = SCpnt->use_sg;
    cpp->data_address = V2DEV(cpp->sglist);
    cpp->data_len = H2DEV(data_len);
 }
 
-static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
-   unsigned int i, j, k;
+static void unmap_dma(unsigned int i, unsigned int j) {
+   unsigned int pci_dir;
+   struct mscp *cpp;
+   Scsi_Cmnd *SCpnt;
+
+   cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+   pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction);
+
+   if (DEV2H(cpp->sense_addr))
+      pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr),
+                       DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
+
+   if (SCpnt->use_sg) 
+      pci_unmap_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir);
+
+   else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len))
+      pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address), 
+                       DEV2H(cpp->data_len), pci_dir);
+
+}
+
+static void sync_dma(unsigned int i, unsigned int j) {
+   unsigned int pci_dir;
    struct mscp *cpp;
+   Scsi_Cmnd *SCpnt;
+
+   cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+   pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction);
+
+   if (DEV2H(cpp->sense_addr))
+      pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->sense_addr),
+                          DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
+
+   if (SCpnt->use_sg) 
+      pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, 
+                         SCpnt->use_sg, pci_dir);
+
+   else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len))
+      pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), 
+                          DEV2H(cpp->data_len), pci_dir);
+
+}
+
+static inline void scsi_to_dev_dir(unsigned int i, unsigned int j) {
+   unsigned int k;
 
    static const unsigned char data_out_cmds[] = {
       0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e,
@@ -1008,9 +1075,51 @@
    static const unsigned char data_none_cmds[] = {
       0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e,
       0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47,
-      0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5
+      0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5, 0x00
       };
 
+   struct mscp *cpp;
+   Scsi_Cmnd *SCpnt;
+
+   cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+
+   if (SCpnt->sc_data_direction == SCSI_DATA_READ) {
+      cpp->xdir = DTD_IN;
+      return;
+      }
+   else if (SCpnt->sc_data_direction == SCSI_DATA_WRITE) {
+      cpp->xdir = DTD_OUT;
+      return;
+      }
+   else if (SCpnt->sc_data_direction == SCSI_DATA_NONE) {
+      cpp->xdir = DTD_NONE;
+      return;
+      }
+
+   if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN) 
+      panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", BN(j));
+
+   cpp->xdir = DTD_IN;
+
+   for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
+      if (SCpnt->cmnd[0] == data_out_cmds[k]) {
+         cpp->xdir = DTD_OUT;
+         break;
+         }
+
+   if (cpp->xdir == DTD_IN)
+      for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++)
+         if (SCpnt->cmnd[0] == data_none_cmds[k]) {
+            cpp->xdir = DTD_NONE;
+            break;
+            }
+
+}
+
+static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
+   unsigned int i, j, k;
+   struct mscp *cpp;
+
    /* j is the board number */
    j = ((struct hostdata *) SCpnt->host->hostdata)->board_number;
 
@@ -1042,47 +1151,26 @@
 
    memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *));
    SCpnt->scsi_done = done;
-   cpp->index = i;
-   SCpnt->host_scribble = (unsigned char *) &cpp->index;
+   cpp->cpp_index = i;
+   SCpnt->host_scribble = (unsigned char *) &cpp->cpp_index;
 
    if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n",
                         BN(j), i, SCpnt->channel, SCpnt->target,
                         SCpnt->lun, SCpnt->pid);
 
-   cpp->xdir = DTD_IN;
-
-   for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
-      if (SCpnt->cmnd[0] == data_out_cmds[k]) {
-         cpp->xdir = DTD_OUT;
-         break;
-         }
-
-   if (cpp->xdir == DTD_IN)
-      for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++)
-         if (SCpnt->cmnd[0] == data_none_cmds[k]) {
-            cpp->xdir = DTD_NONE;
-            break;
-            }
-
    cpp->opcode = OP_SCSI;
    cpp->channel = SCpnt->channel;
    cpp->target = SCpnt->target;
    cpp->lun = SCpnt->lun;
    cpp->SCpnt = SCpnt;
-   cpp->sense_addr = V2DEV(SCpnt->sense_buffer);
-   cpp->sense_len = sizeof SCpnt->sense_buffer;
+   cpp->cdb_len = SCpnt->cmd_len;
+   memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len);
 
-   if (SCpnt->use_sg) {
-      cpp->sg = TRUE;
-      build_sg_list(cpp, SCpnt);
-      }
-   else {
-      cpp->data_address = V2DEV(SCpnt->request_buffer);
-      cpp->data_len = H2DEV(SCpnt->request_bufflen);
-      }
+   /* Use data transfer direction SCpnt->sc_data_direction */
+   scsi_to_dev_dir(i, j);
 
-   cpp->scsi_cdbs_len = SCpnt->cmd_len;
-   memcpy(cpp->scsi_cdbs, SCpnt->cmnd, cpp->scsi_cdbs_len);
+   /* Map DMA buffers and SG list */
+   map_dma(i, j);
 
    if (linked_comm && SCpnt->device->queue_depth > 2
                                      && TLDEV(SCpnt->device->type)) {
@@ -1092,6 +1180,7 @@
       }
 
    if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+      unmap_dma(i, j);
       SCpnt->host_scribble = NULL;
       printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n",
              BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid);
@@ -1154,6 +1243,7 @@
          printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i);
 
       if (SCarg->eh_state == SCSI_STATE_TIMEOUT) {
+         unmap_dma(i, j);
          SCarg->host_scribble = NULL;
          HD(j)->cp_stat[i] = FREE;
          printk("%s, abort, mbox %d, eh_state timeout, pid %ld.\n",
@@ -1175,6 +1265,7 @@
       }
 
    if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
+      unmap_dma(i, j);
       SCarg->result = DID_ABORT << 16;
       SCarg->host_scribble = NULL;
       HD(j)->cp_stat[i] = FREE;
@@ -1272,18 +1363,19 @@
 #endif
 
    HD(j)->in_reset = TRUE;
-   
+
    spin_unlock_irq(&sh[j]->host_lock);
    time = jiffies;
    while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
    spin_lock_irq(&sh[j]->host_lock);
-   
+
    printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
 
    for (i = 0; i < sh[j]->can_queue; i++) {
 
       if (HD(j)->cp_stat[i] == IN_RESET) {
          SCpnt = HD(j)->cp[i].SCpnt;
+         unmap_dma(i, j);
          SCpnt->result = DID_RESET << 16;
          SCpnt->host_scribble = NULL;
 
@@ -1296,6 +1388,7 @@
 
       else if (HD(j)->cp_stat[i] == ABORTING) {
          SCpnt = HD(j)->cp[i].SCpnt;
+         unmap_dma(i, j);
          SCpnt->result = DID_RESET << 16;
          SCpnt->host_scribble = NULL;
 
@@ -1536,23 +1629,25 @@
       return;
       }
 
-   spp = (struct mscp *)DEV2V(ret = inl(sh[j]->io_port + REG_ICM));
-   cpp = spp;
+   ret = inl(sh[j]->io_port + REG_ICM);
 
    /* Clear interrupt pending flag */
    outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
 
-#if defined(DEBUG_GENERATE_ABORTS)
-   if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) return;
-#endif
-
    /* Find the mailbox to be serviced on this board */
-   i = cpp - HD(j)->cp;
+   for (i = 0; i < sh[j]->can_queue; i++)
+      if (V2DEV(&(HD(j)->cp[i])) == ret) break;
 
-   if (cpp < HD(j)->cp || cpp >= HD(j)->cp + sh[j]->can_queue
-                                     || i >= sh[j]->can_queue)
+   if (i >= sh[j]->can_queue)
       panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n", BN(j),
-            (void *)ret, HD(j)->cp);
+            (void *)ret, (void *)V2DEV(HD(j)->cp));
+
+   cpp = &(HD(j)->cp[i]);
+   spp = cpp;
+
+#if defined(DEBUG_GENERATE_ABORTS)
+   if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) return;
+#endif
 
    if (HD(j)->cp_stat[i] == IGNORE) {
       HD(j)->cp_stat[i] = FREE;
@@ -1588,6 +1683,8 @@
       panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
             BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble);
 
+   sync_dma(i, j);
+
    if (linked_comm && SCpnt->device->queue_depth > 2
                                      && TLDEV(SCpnt->device->type))
       flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE);
@@ -1705,6 +1802,8 @@
              SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid,
              reg, HD(j)->iocount);
 
+   unmap_dma(i, j);
+
    /* Set the command state to inactive */
    SCpnt->host_scribble = NULL;
 
@@ -1736,9 +1835,7 @@
    if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n",
                             driver_name);
 
-   if( sh[j]->unchecked_isa_dma ) {
-	   scsi_deregister_blocked_host(sh[j]);
-   }
+   if(sh[j]->unchecked_isa_dma) scsi_deregister_blocked_host(sh[j]);
 
    for (i = 0; i < sh[j]->can_queue; i++)
       if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/u14-34f.h linux/drivers/scsi/u14-34f.h
--- v2.5.1/linux/drivers/scsi/u14-34f.h	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/u14-34f.h	Thu Jan  3 12:19:03 2002
@@ -13,7 +13,7 @@
 int u14_34f_reset(Scsi_Cmnd *);
 int u14_34f_biosparam(Disk *, kdev_t, int *);
 
-#define U14_34F_VERSION "7.00.00"
+#define U14_34F_VERSION "7.20.00"
 
 #define ULTRASTOR_14_34F {                                                   \
                 name:         "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
diff -u --recursive --new-file v2.5.1/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c
--- v2.5.1/linux/drivers/scsi/wd7000.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/scsi/wd7000.c	Mon Dec 31 10:02:26 2001
@@ -140,6 +140,11 @@
  *  03/01/1998
  *
  *  WD7000 driver now work on kernels >= 2.1.x
+ *
+ *
+ * 12/31/2001 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ * use host->host_lock, not io_request_lock, cleanups
  */
 
 #include <linux/module.h>
@@ -166,6 +171,11 @@
 
 #define ANY2SCSI_INLINE		/* undef this to use old macros */
 #undef  WD7000_DEBUG		/* general debug                */
+#ifdef WD7000_DEBUG
+#define dprintk printk
+#else
+#define dprintk(format,args...)
+#endif
 
 #include "wd7000.h"
 #include <linux/stat.h>
@@ -557,7 +567,7 @@
 } Icb;
 
 #ifdef MODULE
-static char * wd7000 = NULL;
+static char *wd7000;
 MODULE_PARM(wd7000, "s");
 #endif
 
@@ -568,23 +578,23 @@
  *  structure is not part of the Adapter structure.
  */
 static Scb scbs[MAX_SCBS];
-static Scb *scbfree = NULL;	/* free list         */
+static Scb *scbfree;		/* free list         */
 static int freescbs = MAX_SCBS;	/* free list counter */
 
 /*
  *  END of data/declarations - code follows.
  */
-static void setup_error (char *mesg, int *ints)
+static void __init setup_error(char *mesg, int *ints)
 {
     if (ints[0] == 3)
-        printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n",
-                ints[1], ints[2], ints[3], mesg);
+        printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n",
+               ints[1], ints[2], ints[3], mesg);
     else if (ints[0] == 4)
-        printk ("wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n",
-                ints[1], ints[2], ints[3], ints[4], mesg);
+        printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n",
+               ints[1], ints[2], ints[3], ints[4], mesg);
     else
-        printk ("wd7000_setup: \"wd7000=%d,%d,0x%x,%d,%d\" -> %s\n",
-                ints[1], ints[2], ints[3], ints[4], ints[5], mesg);
+        printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d,%d\" -> %s\n",
+               ints[1], ints[2], ints[3], ints[4], ints[5], mesg);
 }
 
 
@@ -604,21 +614,23 @@
  */
 static int __init wd7000_setup(char *str)
 {
-	static short wd7000_card_num = 0;
-	short i, j;
+	static short wd7000_card_num; /* .bss will zero this */
+	short i;
 	int ints[6];
 
 	(void)get_options(str, ARRAY_SIZE(ints), ints);
 
 	if (wd7000_card_num >= NUM_CONFIGS) {
-		printk("wd7000_setup: Too many \"wd7000=\" configurations in "
-		"command line!\n");
+		printk(KERN_ERR __FUNCTION__
+			": Too many \"wd7000=\" configurations in "
+			"command line!\n");
 		return 0;
 	}
 
 	if ((ints[0] < 3) || (ints[0] > 5)) {
-		printk("wd7000_setup: Error in command line!  "
-		"Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>[,<BUS_OFF>]]\n");
+		printk(KERN_ERR __FUNCTION__ ": Error in command line!  "
+			"Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>"
+			"[,<BUS_OFF>]]\n");
 	} else {
 		for (i = 0; i < NUM_IRQS; i++)
 			if (ints[1] == wd7000_irq[i])
@@ -652,7 +664,8 @@
 
 		if (ints[0] > 3) {
 			if ((ints[4] < 500) || (ints[4] > 31875)) {
-				setup_error("BUS_ON value is out of range (500 to 31875 nanoseconds)!", ints);
+				setup_error("BUS_ON value is out of range (500"
+					    " to 31875 nanoseconds)!", ints);
 				configs[wd7000_card_num].bus_on = BUS_ON;
 			} else
 				configs[wd7000_card_num].bus_on = ints[4] / 125;
@@ -661,36 +674,47 @@
 
 		if (ints[0] > 4) {
 			if ((ints[5] < 500) || (ints[5] > 31875)) {
-				setup_error("BUS_OFF value is out of range (500 to 31875 nanoseconds)!", ints);
+				setup_error("BUS_OFF value is out of range (500"
+					    " to 31875 nanoseconds)!", ints);
 				configs[wd7000_card_num].bus_off = BUS_OFF;
 			} else
-				configs[wd7000_card_num].bus_off = ints[5] / 125;
+				configs[wd7000_card_num].bus_off = ints[5] /
+								   125;
 		} else
 			configs[wd7000_card_num].bus_off = BUS_OFF;
 
 		if (wd7000_card_num) {
-			for (i = 0; i < (wd7000_card_num - 1); i++)
-				for (j = i + 1; j < wd7000_card_num; j++)
+			for (i = 0; i < (wd7000_card_num - 1); i++) {
+				int j = i + 1;
+
+				for (; j < wd7000_card_num; j++)
 					if (configs[i].irq == configs[j].irq) {
-						setup_error("duplicated IRQ!", ints);
+						setup_error("duplicated IRQ!",
+							    ints);
 						return 0;
-					} else if (configs[i].dma == configs[j].dma) {
-						setup_error("duplicated DMA channel!", ints);
+					}
+					if (configs[i].dma == configs[j].dma) {
+						setup_error("duplicated DMA "
+							    "channel!", ints);
 						return 0;
-					} else if (configs[i].iobase == configs[j].iobase) {
-						setup_error ("duplicated I/O base address!", ints);
+					}
+					if (configs[i].iobase ==
+					    configs[j].iobase) {
+						setup_error("duplicated I/O "
+							    "base address!",
+							    ints);
 						return 0;
 					}
+			}
 		}
 
-#ifdef WD7000_DEBUG
-		printk ("wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, BUS_ON=%dns, BUS_OFF=%dns\n",
+		dprintk(KERN_DEBUG "wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, "
+				  "BUS_ON=%dns, BUS_OFF=%dns\n",
 			configs[wd7000_card_num].irq,
 			configs[wd7000_card_num].dma,
 			configs[wd7000_card_num].iobase,
 			configs[wd7000_card_num].bus_on * 125,
 			configs[wd7000_card_num].bus_off * 125);
-#endif
 
 		wd7000_card_num++;
 	}
@@ -811,7 +835,7 @@
 	return (1);
     }
 
-    printk ("wd7000 command_out: WAIT failed(%d)\n", len + 1);
+    printk(KERN_WARNING "wd7000 command_out: WAIT failed(%d)\n", len + 1);
 
     return (0);
 }
@@ -827,7 +851,7 @@
  *  the satisfiability of a request is not dependent on the size of the
  *  request.
  */
-static inline Scb *alloc_scbs (int needed)
+static inline Scb *alloc_scbs(struct Scsi_Host *host, int needed)
 {
     register Scb *scb, *p;
     register unsigned long flags;
@@ -842,18 +866,18 @@
     save_flags (flags);
     cli ();
     while (busy) {		/* someone else is allocating */
-	spin_unlock_irq(&io_request_lock);
+	spin_unlock_irq(&host->host_lock);
 	for (now = jiffies; now == jiffies; );	/* wait a jiffy */
-	spin_lock_irq(&io_request_lock);
+	spin_lock_irq(&host->host_lock);
     }
     busy = 1;			/* not busy now; it's our turn */
 
     while (freescbs < needed) {
 	timeout = jiffies + WAITnexttimeout;
 	do {
-	    spin_unlock_irq(&io_request_lock);
+	    spin_unlock_irq(&host->host_lock);
 	    for (now = jiffies; now == jiffies; );	/* wait a jiffy */
-	    spin_lock_irq(&io_request_lock);
+	    spin_lock_irq(&host->host_lock);
 	} while (freescbs < needed && time_before_eq(jiffies, timeout));
 	/*
 	 *  If we get here with enough free Scbs, we can take them.
@@ -929,9 +953,7 @@
     Mailbox *ogmbs = host->mb.ogmb;
     int *next_ogmb = &(host->next_ogmb);
 
-#ifdef WD7000_DEBUG
-    printk ("wd7000_mail_out: 0x%06lx", (long) scbptr);
-#endif
+    dprintk("wd7000_mail_out: 0x%06lx", (long) scbptr);
 
     /* We first look for a free outgoing mailbox */
     save_flags (flags);
@@ -939,9 +961,7 @@
     ogmb = *next_ogmb;
     for (i = 0; i < OGMB_CNT; i++) {
 	if (ogmbs[ogmb].status == 0) {
-#ifdef WD7000_DEBUG
-	    printk (" using OGMB 0x%x", ogmb);
-#endif
+	    dprintk(" using OGMB 0x%x", ogmb);
 	    ogmbs[ogmb].status = 1;
 	    any2scsi ((unchar *) ogmbs[ogmb].scbptr, (int) scbptr);
 
@@ -953,9 +973,7 @@
     }
     restore_flags (flags);
 
-#ifdef WD7000_DEBUG
-    printk (", scb is 0x%06lx", (long) scbptr);
-#endif
+    dprintk(", scb is 0x%06lx", (long) scbptr);
 
     if (i >= OGMB_CNT) {
 	/*
@@ -966,9 +984,7 @@
 	 *  that marks OGMB's free, waiting even with interrupts off
 	 *  should work, since they are freed very quickly in most cases.
 	 */
-#ifdef WD7000_DEBUG
-	printk (", no free OGMBs.\n");
-#endif
+	dprintk(", no free OGMBs.\n");
 	return (0);
     }
 
@@ -977,9 +993,7 @@
     start_ogmb = START_OGMB | ogmb;
     command_out (host, &start_ogmb, 1);
 
-#ifdef WD7000_DEBUG
-    printk (", awaiting interrupt.\n");
-#endif
+    dprintk(", awaiting interrupt.\n");
 
     return (1);
 }
@@ -1026,7 +1040,7 @@
     }
 #ifdef WD7000_DEBUG
     if (scsierr || hosterr)
-	printk ("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n",
+	dprintk("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n",
 		scsierr, in_error, hosterr);
 #endif
     return (scsierr | (hosterr << 16));
@@ -1035,10 +1049,7 @@
 
 static void wd7000_scsi_done (Scsi_Cmnd *SCpnt)
 {
-#ifdef WD7000_DEBUG
-    printk ("wd7000_scsi_done: 0x%06lx\n", (long) SCpnt);
-#endif
-
+    dprintk("wd7000_scsi_done: 0x%06lx\n", (long)SCpnt);
     SCpnt->SCp.phase = 0;
 }
 
@@ -1057,15 +1068,11 @@
 
     host->int_counter++;
 
-#ifdef WD7000_DEBUG
-    printk ("wd7000_intr_handle: irq = %d, host = 0x%06lx\n", irq, (long) host);
-#endif
+    dprintk("wd7000_intr_handle: irq = %d, host = 0x%06lx\n", irq, (long) host);
 
     flag = inb (host->iobase + ASC_INTR_STAT);
 
-#ifdef WD7000_DEBUG
-    printk ("wd7000_intr_handle: intr stat = 0x%02x\n", flag);
-#endif
+    dprintk("wd7000_intr_handle: intr stat = 0x%02x\n", flag);
 
     if (!(inb (host->iobase + ASC_STAT) & INT_IM)) {
 	/* NB: these are _very_ possible if IRQ 15 is being used, since
@@ -1076,9 +1083,7 @@
 	 * can sort these out.  Otherwise, electrical noise and other such
 	 * problems would be indistinguishable from valid interrupts...
 	 */
-#ifdef WD7000_DEBUG
-	printk ("wd7000_intr_handle: phantom interrupt...\n");
-#endif
+	dprintk("wd7000_intr_handle: phantom interrupt...\n");
 	wd7000_intr_ack (host);
 	return;
     }
@@ -1086,9 +1091,7 @@
     if (flag & MB_INTR) {
 	/* The interrupt is for a mailbox */
 	if (!(flag & IMB_INTR)) {
-#ifdef WD7000_DEBUG
-	    printk ("wd7000_intr_handle: free outgoing mailbox\n");
-#endif
+	    dprintk("wd7000_intr_handle: free outgoing mailbox\n");
 	    /*
 	     * If sleep_on() and the "interrupt on free OGMB" command are
 	     * used in mail_out(), wake_up() should correspondingly be called
@@ -1102,10 +1105,8 @@
 	    icmb = flag & MB_MASK;
 	    icmb_status = icmbs[icmb].status;
 	    if (icmb_status & 0x80) {	/* unsolicited - result in ICMB */
-#ifdef WD7000_DEBUG
-		printk ("wd7000_intr_handle: unsolicited interrupt 0x%02x\n",
+		dprintk("wd7000_intr_handle: unsolicited interrupt 0x%02x\n",
 			icmb_status);
-#endif
 		wd7000_intr_ack (host);
 		return;
 	    }
@@ -1135,18 +1136,17 @@
 
     wd7000_intr_ack (host);
 
-#ifdef WD7000_DEBUG
-    printk ("wd7000_intr_handle: return from interrupt handler\n");
-#endif
+    dprintk("wd7000_intr_handle: return from interrupt handler\n");
 }
 
 void do_wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
 {
     unsigned long flags;
+    struct Scsi_Host *host = dev_id;
 
-    spin_lock_irqsave(&io_request_lock, flags);
+    spin_lock_irqsave(&host->host_lock, flags);
     wd7000_intr_handle(irq, dev_id, regs);
-    spin_unlock_irqrestore(&io_request_lock, flags);
+    spin_unlock_irqrestore(&host->host_lock, flags);
 }
 
 
@@ -1163,7 +1163,7 @@
     idlun = ((SCpnt->target << 5) & 0xe0) | (SCpnt->lun & 7);
     SCpnt->scsi_done = done;
     SCpnt->SCp.phase = 1;
-    scb = alloc_scbs (1);
+    scb = alloc_scbs(SCpnt->host, 1);
     scb->idlun = idlun;
     memcpy (scb->cdb, cdb, cdblen);
     scb->direc = 0x40;		/* Disable direction check */
@@ -1179,9 +1179,7 @@
 	if (SCpnt->host->sg_tablesize == SG_NONE) {
 	    panic ("wd7000_queuecommand: scatter/gather not supported.\n");
 	}
-#ifdef WD7000_DEBUG
-	printk ("Using scatter/gather with %d elements.\n", SCpnt->use_sg);
-#endif
+	dprintk ("Using scatter/gather with %d elements.\n", SCpnt->use_sg);
 
 	sgb = scb->sgb;
 	scb->op = 1;
@@ -1367,14 +1365,12 @@
     save_flags (flags);
     cli ();
 
-#ifdef WD7000_DEBUG
-    printk ("Buffer = <%.*s>, length = %d\n", length, buffer, length);
-#endif
+    dprintk("Buffer = <%.*s>, length = %d\n", length, buffer, length);
 
     /*
      * Currently this is a no-op
      */
-    printk ("Sorry, this function is currently out of order...\n");
+    dprintk("Sorry, this function is currently out of order...\n");
 
     restore_flags (flags);
 
@@ -1521,9 +1517,7 @@
     Adapter *host = NULL;
     struct Scsi_Host *sh;
 
-#ifdef WD7000_DEBUG
-    printk ("wd7000_detect: started\n");
-#endif
+    dprintk("wd7000_detect: started\n");
 
 #ifdef MODULE
 	if (wd7000)
@@ -1573,12 +1567,12 @@
 	 * BIOS SIGNATURE has been found.
 	 */
 #ifdef WD7000_DEBUG
-	printk ("wd7000_detect: pass %d\n", pass + 1);
+	dprintk("wd7000_detect: pass %d\n", pass + 1);
 
 	if (biosaddr_ptr == NUM_ADDRS)
-	    printk ("WD-7000 SST BIOS not detected...\n");
+	    dprintk("WD-7000 SST BIOS not detected...\n");
 	else
-	    printk ("WD-7000 SST BIOS detected at 0x%lx: checking...\n",
+	    dprintk("WD-7000 SST BIOS detected at 0x%lx: checking...\n",
 		    wd7000_biosaddr[biosaddr_ptr]);
 #endif
 
@@ -1587,15 +1581,11 @@
 
 	iobase = configs[pass].iobase;
 
-#ifdef WD7000_DEBUG
-	printk ("wd7000_detect: check IO 0x%x region...\n", iobase);
-#endif
+	dprintk("wd7000_detect: check IO 0x%x region...\n", iobase);
 
 	if (request_region (iobase, 4, "wd7000")) {
 
-#ifdef WD7000_DEBUG
-	    printk ("wd7000_detect: ASC reset (IO 0x%x) ...", iobase);
-#endif
+	    dprintk("wd7000_detect: ASC reset (IO 0x%x) ...", iobase);
 	    /*
 	     * ASC reset...
 	     */
@@ -1603,17 +1593,11 @@
 	    delay (1);
 	    outb (0, iobase + ASC_CONTROL);
 
-	    if (WAIT (iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0))
-#ifdef WD7000_DEBUG
-	    {
-		printk ("failed!\n");
+	    if (WAIT (iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
+		dprintk("failed!\n");
 		goto err_release;
-	    }
-	    else 
-		printk ("ok!\n");
-#else
-	    goto err_release;
-#endif
+	    } else 
+		dprintk("ok!\n");
 
 	    if (inb (iobase + ASC_INTR_STAT) == 1) {
 		/*
@@ -1629,10 +1613,8 @@
 
 		host = (Adapter *) sh->hostdata;
 
-#ifdef WD7000_DEBUG
-		printk ("wd7000_detect: adapter allocated at 0x%x\n", (int) host);
-#endif
-
+		dprintk("wd7000_detect: adapter allocated at 0x%x\n",
+			(int)host);
 		memset (host, 0, sizeof (Adapter));
 
 		host->irq = configs[pass].irq;
@@ -1643,11 +1625,9 @@
 		host->bus_off = configs[pass].bus_off;
 		host->sh = wd7000_host[host->irq - IRQ_MIN] = sh;
 
-#ifdef WD7000_DEBUG
-		printk ("wd7000_detect: Trying init WD-7000 card at IO "
+		dprintk("wd7000_detect: Trying init WD-7000 card at IO "
 			"0x%x, IRQ %d, DMA %d...\n",
 			host->iobase, host->irq, host->dma);
-#endif
 
 		if (!wd7000_init (host)) 	/* Initialization failed */
 		    goto err_unregister;
@@ -1675,12 +1655,9 @@
                 printk ("  BUS_ON time: %dns, BUS_OFF time: %dns\n",
                         host->bus_on * 125, host->bus_off * 125);
 	    }
-	}
-
-#ifdef WD7000_DEBUG
-	else
-	    printk ("wd7000_detect: IO 0x%x region already allocated!\n", iobase);
-#endif
+	} else
+		dprintk("wd7000_detect: IO 0x%x region already allocated!\n",
+			iobase);
 
 	continue;
 
@@ -1730,9 +1707,8 @@
  */
 int wd7000_biosparam (Disk *disk, kdev_t dev, int *ip)
 {
-#ifdef WD7000_DEBUG
-    printk ("wd7000_biosparam: dev=%s, size=%d, ", kdevname (dev), disk->capacity);
-#endif
+    dprintk("wd7000_biosparam: dev=%s, size=%d, ", kdevname(dev),
+	    disk->capacity);
 
     /*
      * try default translation
@@ -1766,14 +1742,13 @@
 	    ip[2] = info[2];
 
 	    if (info[0] == 255)
-		printk ("wd7000_biosparam: current partition table is using extended translation.\n");
+		printk(KERN_INFO __FUNCTION__ ": current partition table is "
+			"using extended translation.\n");
 	}
     }
 
-#ifdef WD7000_DEBUG
-    printk ("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]);
-    printk ("WARNING: check, if the bios geometry is correct.\n");
-#endif
+    dprintk("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]);
+    dprintk("WARNING: check, if the bios geometry is correct.\n");
 
     return (0);
 }
diff -u --recursive --new-file v2.5.1/linux/drivers/sgi/char/sgiserial.c linux/drivers/sgi/char/sgiserial.c
--- v2.5.1/linux/drivers/sgi/char/sgiserial.c	Mon Aug 27 08:56:31 2001
+++ linux/drivers/sgi/char/sgiserial.c	Tue Dec 25 15:39:20 2001
@@ -49,8 +49,6 @@
 #define NUM_SERIAL 1     /* One chip on board. */
 #define NUM_CHANNELS (NUM_SERIAL * 2)
 
-extern wait_queue_head_t keypress_wait;
-
 struct sgi_zslayout *zs_chips[NUM_SERIAL] = { 0, };
 struct sgi_zschannel *zs_channels[NUM_CHANNELS] = { 0, 0, };
 struct sgi_zschannel *zs_conschan;
@@ -428,8 +426,6 @@
 			show_buffers();
 			return;
 		}
-		/* It is a 'keyboard interrupt' ;-) */
-		wake_up(&keypress_wait);
 	}
 	/* Look for kgdb 'stop' character, consult the gdb documentation
 	 * for remote target debugging and arch/sparc/kernel/sparc-stub.c
@@ -2117,12 +2113,6 @@
 	rs_fair_output();
 }
 
-static int zs_console_wait_key(struct console *con)
-{
-	sleep_on(&keypress_wait);
-	return 0;
-}
-
 static kdev_t zs_console_device(struct console *con)
 {
 	return MKDEV(TTY_MAJOR, 64 + con->index);
@@ -2274,7 +2264,6 @@
 	name:		"ttyS",
 	write:		zs_console_write,
 	device:		zs_console_device,
-	wait_key:	zs_console_wait_key,
 	setup:		zs_console_setup,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
diff -u --recursive --new-file v2.5.1/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
--- v2.5.1/linux/drivers/sound/ad1848.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/sound/ad1848.c	Sun Dec 30 16:58:51 2001
@@ -134,7 +134,7 @@
 
 static int loaded;
 
-static int ad_format_mask[10 /*devc->model */ ] =
+static int ad_format_mask[13 /*devc->model */ ] =
 {
 	0,
 	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,
@@ -145,7 +145,10 @@
 	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
 	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
 	AFMT_U8 | AFMT_S16_LE /* CS4235 */,
-	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW	/* Ensoniq Soundscape*/
+	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW	/* Ensoniq Soundscape*/,
+	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
+	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
+	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM
 };
 
 static ad1848_info adev_info[MAX_AUDIO_DEV];
@@ -2965,6 +2968,10 @@
         	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('Y','M','H'), ISAPNP_FUNCTION(0x0021),
                 1, 0, 0, 1, 1},
+	{"Advanced Gravis InterWave Audio",
+		ISAPNP_VENDOR('G','R','V'), ISAPNP_DEVICE(0x0001),
+		ISAPNP_VENDOR('G','R','V'), ISAPNP_FUNCTION(0x0000),
+		0, 0, 0, 1, 0},
 	{0}
 };
 
@@ -2977,6 +2984,8 @@
 		ISAPNP_VENDOR('C','S','C'), ISAPNP_FUNCTION(0x0100), 0 },
         {       ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('Y','M','H'), ISAPNP_FUNCTION(0x0021), 0 },
+	{	ISAPNP_VENDOR('G','R','V'), ISAPNP_DEVICE(0x0001),
+		ISAPNP_VENDOR('G','R','V'), ISAPNP_FUNCTION(0x0000), 0 },
 	{0}
 };
 
diff -u --recursive --new-file v2.5.1/linux/drivers/sound/cs4281/cs4281m.c linux/drivers/sound/cs4281/cs4281m.c
--- v2.5.1/linux/drivers/sound/cs4281/cs4281m.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/sound/cs4281/cs4281m.c	Thu Jan  3 12:20:12 2002
@@ -2569,7 +2569,7 @@
 
 static int cs4281_open_mixdev(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	struct cs4281_state *s=NULL;
 	struct list_head *entry;
 
@@ -3625,7 +3625,7 @@
 
 static int cs4281_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	struct cs4281_state *s=NULL;
 	struct list_head *entry;
 
@@ -3966,7 +3966,7 @@
 static int cs4281_midi_open(struct inode *inode, struct file *file)
 {
 	unsigned long flags, temp1;
-	int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	struct cs4281_state *s=NULL;
 	struct list_head *entry;
 	list_for_each(entry, &cs4281_devs)
diff -u --recursive --new-file v2.5.1/linux/drivers/sound/cs46xx.c linux/drivers/sound/cs46xx.c
--- v2.5.1/linux/drivers/sound/cs46xx.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/sound/cs46xx.c	Thu Jan  3 12:20:12 2002
@@ -1835,7 +1835,7 @@
 
 static int cs_midi_open(struct inode *inode, struct file *file)
 {
-        int minor = MINOR(inode->i_rdev);
+        unsigned int minor = minor(inode->i_rdev);
         struct cs_card *card=NULL;
         unsigned long flags;
 	struct list_head *entry;
@@ -3198,7 +3198,7 @@
 	struct cs_state *state = NULL;
 	struct dmabuf *dmabuf = NULL;
 	struct list_head *entry;
-        int minor = MINOR(inode->i_rdev);
+        unsigned int minor = minor(inode->i_rdev);
 	int ret=0;
 	unsigned int tmp;
 
@@ -4047,7 +4047,7 @@
 static int cs_open_mixdev(struct inode *inode, struct file *file)
 {
 	int i=0;
-	int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	struct cs_card *card=NULL;
 	struct list_head *entry;
 	unsigned int tmp;
@@ -4094,7 +4094,7 @@
 
 static int cs_release_mixdev(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	struct cs_card *card=NULL;
 	struct list_head *entry;
 	int i;
diff -u --recursive --new-file v2.5.1/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c
--- v2.5.1/linux/drivers/sound/es1370.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/sound/es1370.c	Thu Jan  3 12:20:12 2002
@@ -1029,7 +1029,7 @@
 
 static int es1370_open_mixdev(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	struct list_head *list;
 	struct es1370_state *s;
 
@@ -1729,7 +1729,7 @@
 
 static int es1370_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
 	struct list_head *list;
@@ -2165,7 +2165,7 @@
 
 static int es1370_open_dac(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
 	struct list_head *list;
@@ -2408,7 +2408,7 @@
 
 static int es1370_midi_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
 	struct list_head *list;
diff -u --recursive --new-file v2.5.1/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c
--- v2.5.1/linux/drivers/sound/es1371.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/sound/es1371.c	Tue Jan  1 11:57:44 2002
@@ -1213,7 +1213,7 @@
 
 static int es1371_open_mixdev(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct list_head *list;
 	struct es1371_state *s;
 
@@ -1913,7 +1913,7 @@
 
 static int es1371_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
 	struct list_head *list;
@@ -2342,7 +2342,7 @@
 
 static int es1371_open_dac(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
 	struct list_head *list;
@@ -2584,7 +2584,7 @@
 
 static int es1371_midi_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
 	struct list_head *list;
diff -u --recursive --new-file v2.5.1/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c
--- v2.5.1/linux/drivers/sound/esssolo1.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/sound/esssolo1.c	Thu Jan  3 12:20:12 2002
@@ -913,7 +913,7 @@
 
 static int solo1_open_mixdev(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	struct solo1_state *s = NULL;
 	struct pci_dev *pci_dev;
 
@@ -1590,7 +1590,7 @@
 
 static int solo1_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	DECLARE_WAITQUEUE(wait, current);
 	struct solo1_state *s = NULL;
 	struct pci_dev *pci_dev;
@@ -1879,7 +1879,7 @@
 
 static int solo1_midi_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
 	struct solo1_state *s = NULL;
@@ -2105,7 +2105,7 @@
 
 static int solo1_dmfm_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	DECLARE_WAITQUEUE(wait, current);
 	struct solo1_state *s = NULL;
 	struct pci_dev *pci_dev;
diff -u --recursive --new-file v2.5.1/linux/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c
--- v2.5.1/linux/drivers/sound/i810_audio.c	Fri Nov  9 14:07:41 2001
+++ linux/drivers/sound/i810_audio.c	Thu Jan  3 12:20:12 2002
@@ -2345,7 +2345,7 @@
 static int i810_open_mixdev(struct inode *inode, struct file *file)
 {
 	int i;
-	int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	struct i810_card *card = devs;
 
 	for (card = devs; card != NULL; card = card->next)
diff -u --recursive --new-file v2.5.1/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c
--- v2.5.1/linux/drivers/sound/maestro.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/sound/maestro.c	Thu Jan  3 12:20:12 2002
@@ -2126,7 +2126,7 @@
 /* --------------------------------------------------------------------- */
 static int ess_open_mixdev(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	struct ess_card *card = NULL;
 	struct pci_dev *pdev;
 	struct pci_driver *drvr;
@@ -2967,7 +2967,7 @@
 static int 
 ess_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	struct ess_state *s = NULL;
 	unsigned char fmtm = ~0, fmts = 0;
 	struct pci_dev *pdev;
diff -u --recursive --new-file v2.5.1/linux/drivers/sound/maestro3.c linux/drivers/sound/maestro3.c
--- v2.5.1/linux/drivers/sound/maestro3.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/sound/maestro3.c	Thu Jan  3 12:20:12 2002
@@ -1969,7 +1969,7 @@
 
 static int m3_open(struct inode *inode, struct file *file)
 {
-    int minor = MINOR(inode->i_rdev);
+    unsigned int minor = minor(inode->i_rdev);
     struct m3_card *c;
     struct m3_state *s = NULL;
     int i;
@@ -2137,7 +2137,7 @@
 /* OSS /dev/mixer file operation methods */
 static int m3_open_mixdev(struct inode *inode, struct file *file)
 {
-    int minor = MINOR(inode->i_rdev);
+    unsigned int minor = minor(inode->i_rdev);
     struct m3_card *card = devs;
 
     for (card = devs; card != NULL; card = card->next) {
diff -u --recursive --new-file v2.5.1/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- v2.5.1/linux/drivers/sound/sb_card.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/sound/sb_card.c	Sun Dec 30 16:58:51 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 -u --recursive --new-file v2.5.1/linux/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c
--- v2.5.1/linux/drivers/sound/sound_core.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/sound/sound_core.c	Tue Jan  1 11:57:00 2002
@@ -478,7 +478,7 @@
 int soundcore_open(struct inode *inode, struct file *file)
 {
 	int chain;
-	int unit=MINOR(inode->i_rdev);
+	int unit = minor(inode->i_rdev);
 	struct sound_unit *s;
 	struct file_operations *new_fops = NULL;
 
diff -u --recursive --new-file v2.5.1/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v2.5.1/linux/drivers/sound/soundcard.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/sound/soundcard.c	Thu Jan  3 12:20:12 2002
@@ -35,7 +35,6 @@
 #include <linux/kmod.h>
 #include <asm/dma.h>
 #include <asm/io.h>
-#include <asm/segment.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
@@ -145,7 +144,7 @@
 
 static ssize_t sound_read(struct file *file, char *buf, size_t count, loff_t *ppos)
 {
-	int dev = MINOR(file->f_dentry->d_inode->i_rdev);
+	int dev = minor(file->f_dentry->d_inode->i_rdev);
 	int ret = -EINVAL;
 
 	/*
@@ -178,7 +177,7 @@
 
 static ssize_t sound_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
-	int dev = MINOR(file->f_dentry->d_inode->i_rdev);
+	int dev = minor(file->f_dentry->d_inode->i_rdev);
 	int ret = -EINVAL;
 	
 	lock_kernel();
@@ -205,7 +204,7 @@
 
 static int sound_open(struct inode *inode, struct file *file)
 {
-	int dev = MINOR(inode->i_rdev);
+	int dev = minor(inode->i_rdev);
 	int retval;
 
 	DEB(printk("sound_open(dev=%d)\n", dev));
@@ -256,7 +255,7 @@
 
 static int sound_release(struct inode *inode, struct file *file)
 {
-	int dev = MINOR(inode->i_rdev);
+	int dev = minor(inode->i_rdev);
 
 	lock_kernel();
 	DEB(printk("sound_release(dev=%d)\n", dev));
@@ -342,7 +341,7 @@
 		       unsigned int cmd, unsigned long arg)
 {
 	int err, len = 0, dtype;
-	int dev = MINOR(inode->i_rdev);
+	int dev = minor(inode->i_rdev);
 
 	if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) {
 		/*
@@ -405,7 +404,7 @@
 static unsigned int sound_poll(struct file *file, poll_table * wait)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	int dev = MINOR(inode->i_rdev);
+	int dev = minor(inode->i_rdev);
 
 	DEB(printk("sound_poll(dev=%d)\n", dev));
 	switch (dev & 0x0f) {
@@ -429,7 +428,7 @@
 	int dev_class;
 	unsigned long size;
 	struct dma_buffparms *dmap = NULL;
-	int dev = MINOR(file->f_dentry->d_inode->i_rdev);
+	int dev = minor(file->f_dentry->d_inode->i_rdev);
 
 	dev_class = dev & 0x0f;
 	dev >>= 4;
diff -u --recursive --new-file v2.5.1/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c
--- v2.5.1/linux/drivers/sound/sscape.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/sound/sscape.c	Sun Dec 30 10:31:51 2001
@@ -34,7 +34,6 @@
 #include <linux/kmod.h>
 #include <asm/dma.h>
 #include <asm/io.h>
-#include <asm/segment.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/tc/zs.c linux/drivers/tc/zs.c
--- v2.5.1/linux/drivers/tc/zs.c	Mon Aug 27 08:56:31 2001
+++ linux/drivers/tc/zs.c	Sun Dec 30 10:31:51 2001
@@ -64,7 +64,6 @@
 #include <asm/pgtable.h>
 #include <asm/irq.h>
 #include <asm/system.h>
-#include <asm/segment.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/wbflush.h>
@@ -2125,18 +2124,6 @@
 	}
 }
 
-/*
- *	Receive character from the serial port
- */
-static int serial_console_wait_key(struct console *co)
-{
-	struct dec_serial *info;
-
-        info = zs_soft + co->index;
-
-        return zs_poll_rx_char(info);
-}
-
 static kdev_t serial_console_device(struct console *c)
 {
 	return MKDEV(TTY_MAJOR, 64 + c->index);
@@ -2271,7 +2258,6 @@
 	name:		"ttyS",
 	write:		serial_console_write,
 	device:		serial_console_device,
-	wait_key:	serial_console_wait_key,
 	setup:		serial_console_setup,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
diff -u --recursive --new-file v2.5.1/linux/drivers/telephony/ixj.c linux/drivers/telephony/ixj.c
--- v2.5.1/linux/drivers/telephony/ixj.c	Thu Oct 25 13:53:52 2001
+++ linux/drivers/telephony/ixj.c	Sun Dec 30 10:31:51 2001
@@ -268,7 +268,6 @@
 #include <linux/pci.h>
 
 #include <asm/io.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 
 #include <linux/isapnp.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.5.1/linux/drivers/usb/Config.in	Tue Dec 18 14:56:38 2001
+++ linux/drivers/usb/Config.in	Thu Jan  3 13:21:28 2002
@@ -18,7 +18,8 @@
    bool '  Long timeout for slow-responding devices (some MGE Ellipse UPSes)' CONFIG_USB_LONG_TIMEOUT
 fi
 
-comment 'USB Controllers'
+comment 'USB Host Controller Drivers'
+source drivers/usb/hcd/Config.in
 if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
    dep_tristate '  UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
 fi
@@ -72,6 +73,8 @@
    dep_tristate '  USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
    dep_tristate '  USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV
    dep_tristate '  USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV
+   dep_tristate '  USB STV680 (Pencam) Camera support' CONFIG_USB_STV680 $CONFIG_USB $CONFIG_VIDEO_DEV
+   dep_tristate '  USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)' CONFIG_USB_VICAM $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
    dep_tristate '  D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
    dep_tristate '  DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
 fi
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/Makefile linux/drivers/usb/Makefile
--- v2.5.1/linux/drivers/usb/Makefile	Fri Oct  5 12:04:51 2001
+++ linux/drivers/usb/Makefile	Thu Jan  3 13:21:28 2002
@@ -10,19 +10,13 @@
 
 # Objects that export symbols.
 
-export-objs		:= usb.o
+export-objs		:= usb.o hcd.o ov511.o pwc-uncompress.o
 
 # Multipart objects.
 
-list-multi		:= usbcore.o hid.o
-usbcore-objs		:= usb.o usb-debug.o hub.o
+list-multi		:= usbcore.o hid.o pwc.o
+usbcore-objs		:= usb.o usb-debug.o hub.o hcd.o
 hid-objs		:= hid-core.o hid-input.o
-
-ifneq ($(CONFIG_USB_PWC),n)
-	export-objs		+= pwc-uncompress.o
-	list-multi		+= pwc.o
-endif
-
 pwc-objs		:= pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o
 
 
@@ -65,8 +59,10 @@
 obj-$(CONFIG_USB_MDC800)	+= mdc800.o
 obj-$(CONFIG_USB_USS720)	+= uss720.o
 obj-$(CONFIG_USB_DABUSB)	+= dabusb.o
+obj-$(CONFIG_USB_VICAM)		+= vicam.o
 obj-$(CONFIG_USB_OV511)		+= ov511.o
 obj-$(CONFIG_USB_SE401)		+= se401.o
+obj-$(CONFIG_USB_STV680)	+= stv680.o
 obj-$(CONFIG_USB_PEGASUS)	+= pegasus.o
 obj-$(CONFIG_USB_CATC)		+= catc.o
 obj-$(CONFIG_USB_KAWETH)        += kaweth.o
@@ -79,9 +75,15 @@
 obj-$(CONFIG_USB_USBNET)	+= usbnet.o
 
 # Object files in subdirectories
+mod-subdirs	:= serial hcd
 
+subdir-$(CONFIG_USB_EHCI_HCD)	+= hcd
 subdir-$(CONFIG_USB_SERIAL)	+= serial
 subdir-$(CONFIG_USB_STORAGE)	+= storage
+
+ifeq ($(CONFIG_USB_EHCI_HCD),y)
+	obj-y += hcd/ehci-hcd.o
+endif
 
 ifeq ($(CONFIG_USB_SERIAL),y)
 	obj-y += serial/usb-serial.o
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/acm.c linux/drivers/usb/acm.c
--- v2.5.1/linux/drivers/usb/acm.c	Fri Oct  5 12:06:08 2001
+++ linux/drivers/usb/acm.c	Thu Jan  3 12:14:38 2002
@@ -297,7 +297,7 @@
 
 static int acm_tty_open(struct tty_struct *tty, struct file *filp)
 {
-	struct acm *acm = acm_table[MINOR(tty->device)];
+	struct acm *acm = acm_table[minor(tty->device)];
 
 	if (!acm || !acm->dev) return -EINVAL;
 
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/audio.c linux/drivers/usb/audio.c
--- v2.5.1/linux/drivers/usb/audio.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/usb/audio.c	Thu Jan  3 12:20:14 2002
@@ -833,7 +833,7 @@
 	}
 }		
 
-static int usbin_prepare_desc(struct usbin *u, purb_t urb)
+static int usbin_prepare_desc(struct usbin *u, struct urb *urb)
 {
 	unsigned int i, maxsize, offs;
 
@@ -850,7 +850,7 @@
  * return value: 0 if descriptor should be restarted, -1 otherwise
  * convert sample format on the fly if necessary
  */
-static int usbin_retire_desc(struct usbin *u, purb_t urb)
+static int usbin_retire_desc(struct usbin *u, struct urb *urb)
 {
 	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, dmafree;
 	unsigned char *cp;
@@ -930,7 +930,7 @@
 /*
  * we output sync data
  */
-static int usbin_sync_prepare_desc(struct usbin *u, purb_t urb)
+static int usbin_sync_prepare_desc(struct usbin *u, struct urb *urb)
 {
 	unsigned char *cp = urb->transfer_buffer;
 	unsigned int i, offs;
@@ -948,7 +948,7 @@
 /*
  * return value: 0 if descriptor should be restarted, -1 otherwise
  */
-static int usbin_sync_retire_desc(struct usbin *u, purb_t urb)
+static int usbin_sync_retire_desc(struct usbin *u, struct urb *urb)
 {
 	unsigned int i;
 	
@@ -996,7 +996,7 @@
 {
 	struct usb_device *dev = as->state->usbdev;
 	struct usbin *u = &as->usbin;
-	purb_t urb;
+	struct urb *urb;
 	unsigned long flags;
 	unsigned int maxsze, bufsz;
 
@@ -1186,7 +1186,7 @@
 	}
 }		
 
-static int usbout_prepare_desc(struct usbout *u, purb_t urb)
+static int usbout_prepare_desc(struct usbout *u, struct urb *urb)
 {
 	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, offs;
 	unsigned char *cp = urb->transfer_buffer;
@@ -1238,7 +1238,7 @@
 /*
  * return value: 0 if descriptor should be restarted, -1 otherwise
  */
-static int usbout_retire_desc(struct usbout *u, purb_t urb)
+static int usbout_retire_desc(struct usbout *u, struct urb *urb)
 {
 	unsigned int i;
 
@@ -1285,7 +1285,7 @@
 	spin_unlock_irqrestore(&as->lock, flags);
 }
 
-static int usbout_sync_prepare_desc(struct usbout *u, purb_t urb)
+static int usbout_sync_prepare_desc(struct usbout *u, struct urb *urb)
 {
 	unsigned int i, offs;
 
@@ -1299,7 +1299,7 @@
 /*
  * return value: 0 if descriptor should be restarted, -1 otherwise
  */
-static int usbout_sync_retire_desc(struct usbout *u, purb_t urb)
+static int usbout_sync_retire_desc(struct usbout *u, struct urb *urb)
 {
 	unsigned char *cp = urb->transfer_buffer;
 	unsigned int f, i;
@@ -1361,7 +1361,7 @@
 {
 	struct usb_device *dev = as->state->usbdev;
 	struct usbout *u = &as->usbout;
-	purb_t urb;
+	struct urb *urb;
 	unsigned long flags;
 	unsigned int maxsze, bufsz;
 
@@ -1947,7 +1947,7 @@
 
 static int usb_audio_open_mixdev(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	struct list_head *devs, *mdevs;
 	struct usb_mixerdev *ms;
 	struct usb_audio_state *s;
@@ -2621,7 +2621,7 @@
 
 static int usb_audio_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	DECLARE_WAITQUEUE(wait, current);
 	struct list_head *devs, *adevs;
 	struct usb_audiodev *as;
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/bluetooth.c linux/drivers/usb/bluetooth.c
--- v2.5.1/linux/drivers/usb/bluetooth.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/usb/bluetooth.c	Thu Jan  3 12:14:38 2002
@@ -360,7 +360,7 @@
 	tty->driver_data = NULL;
 
 	/* get the bluetooth object associated with this tty pointer */
-	bluetooth = get_bluetooth_by_minor (MINOR(tty->device));
+	bluetooth = get_bluetooth_by_minor (minor(tty->device));
 
 	if (bluetooth_paranoia_check (bluetooth, __FUNCTION__)) {
 		return -ENODEV;
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/dabusb.c linux/drivers/usb/dabusb.c
--- v2.5.1/linux/drivers/usb/dabusb.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/usb/dabusb.c	Thu Jan  3 12:20:16 2002
@@ -83,24 +83,24 @@
 }
 /*-------------------------------------------------------------------*/
 #ifdef DEBUG 
-static void dump_urb (purb_t purb)
+static void dump_urb (struct urb *urb)
 {
-	dbg("urb                   :%p", purb);
-	dbg("next                  :%p", purb->next);
-	dbg("dev                   :%p", purb->dev);
-	dbg("pipe                  :%08X", purb->pipe);
-	dbg("status                :%d", purb->status);
-	dbg("transfer_flags        :%08X", purb->transfer_flags);
-	dbg("transfer_buffer       :%p", purb->transfer_buffer);
-	dbg("transfer_buffer_length:%d", purb->transfer_buffer_length);
-	dbg("actual_length         :%d", purb->actual_length);
-	dbg("setup_packet          :%p", purb->setup_packet);
-	dbg("start_frame           :%d", purb->start_frame);
-	dbg("number_of_packets     :%d", purb->number_of_packets);
-	dbg("interval              :%d", purb->interval);
-	dbg("error_count           :%d", purb->error_count);
-	dbg("context               :%p", purb->context);
-	dbg("complete              :%p", purb->complete);
+	dbg("urb                   :%p", urb);
+	dbg("next                  :%p", urb->next);
+	dbg("dev                   :%p", urb->dev);
+	dbg("pipe                  :%08X", urb->pipe);
+	dbg("status                :%d", urb->status);
+	dbg("transfer_flags        :%08X", urb->transfer_flags);
+	dbg("transfer_buffer       :%p", urb->transfer_buffer);
+	dbg("transfer_buffer_length:%d", urb->transfer_buffer_length);
+	dbg("actual_length         :%d", urb->actual_length);
+	dbg("setup_packet          :%p", urb->setup_packet);
+	dbg("start_frame           :%d", urb->start_frame);
+	dbg("number_of_packets     :%d", urb->number_of_packets);
+	dbg("interval              :%d", urb->interval);
+	dbg("error_count           :%d", urb->error_count);
+	dbg("context               :%p", urb->context);
+	dbg("complete              :%p", urb->complete);
 }
 #endif
 /*-------------------------------------------------------------------*/
@@ -167,7 +167,7 @@
 	return 0;
 }
 /*-------------------------------------------------------------------*/
-static void dabusb_iso_complete (purb_t purb)
+static void dabusb_iso_complete (struct urb *purb)
 {
 	pbuff_t b = purb->context;
 	pdabusb_t s = b->s;
@@ -482,7 +482,7 @@
 	int rem;
 	int cnt;
 	pbuff_t b;
-	purb_t purb = NULL;
+	struct urb *purb = NULL;
 
 	dbg("dabusb_read");
 
@@ -579,7 +579,7 @@
 
 static int dabusb_open (struct inode *inode, struct file *file)
 {
-	int devnum = MINOR (inode->i_rdev);
+	int devnum = minor (inode->i_rdev);
 	pdabusb_t s;
 
 	if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB))
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/dabusb.h linux/drivers/usb/dabusb.h
--- v2.5.1/linux/drivers/usb/dabusb.h	Tue Oct  3 09:24:40 2000
+++ linux/drivers/usb/dabusb.h	Tue Jan  1 13:52:10 2002
@@ -38,7 +38,7 @@
 typedef struct 
 {
 	pdabusb_t s;
-	purb_t purb;
+	struct urb *purb;
 	struct list_head buff_list;
 } buff_t,*pbuff_t;
 
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/dc2xx.c linux/drivers/usb/dc2xx.c
--- v2.5.1/linux/drivers/usb/dc2xx.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/usb/dc2xx.c	Thu Jan  3 12:20:16 2002
@@ -298,7 +298,7 @@
 	int			value = 0;
 
 	down (&state_table_mutex);
-	subminor = MINOR (inode->i_rdev) - USB_CAMERA_MINOR_BASE;
+	subminor = minor (inode->i_rdev) - USB_CAMERA_MINOR_BASE;
 	if (subminor < 0 || subminor >= MAX_CAMERAS
 			|| !(camera = minor_data [subminor])) {
 		up (&state_table_mutex);
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/devio.c linux/drivers/usb/devio.c
--- v2.5.1/linux/drivers/usb/devio.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/usb/devio.c	Tue Jan  1 13:52:10 2002
@@ -245,7 +245,7 @@
         return NULL;
 }
 
-static void async_completed(purb_t urb)
+static void async_completed(struct urb *urb)
 {
         struct async *as = (struct async *)urb->context;
         struct dev_state *ps = as->ps;
@@ -471,9 +471,7 @@
 	 */
 	lock_kernel();
 	ret = -ENOENT;
-	if (ITYPE(inode->i_ino) != IDEVICE)
-		goto out;
-	dev = inode->u.usbdev_i.p.dev;
+	dev = inode->u.generic_ip;
 	if (!dev)
 		goto out;
 	ret = -ENOMEM;
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/hcd/Config.in linux/drivers/usb/hcd/Config.in
--- v2.5.1/linux/drivers/usb/hcd/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/Config.in	Thu Jan  3 13:21:28 2002
@@ -0,0 +1,7 @@
+#
+# USB Host Controller Drivers
+#
+dep_tristate '  EHCI HCD (USB 2.0) support (EXPERIMENTAL)' CONFIG_USB_EHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
+# dep_tristate '  OHCI HCD support (EXPERIMENTAL)' CONFIG_USB_OHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
+# dep_tristate '  UHCI HCD (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_USB_UHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
+
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/hcd/Makefile linux/drivers/usb/hcd/Makefile
--- v2.5.1/linux/drivers/usb/hcd/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/Makefile	Tue Jan  1 13:52:10 2002
@@ -0,0 +1,27 @@
+#
+# Makefile for USB Host Controller Driver
+# framework and drivers
+#
+
+O_TARGET	:=
+
+obj-$(CONFIG_EHCI_HCD)			+= ehci-hcd.o
+# obj-$(CONFIG_OHCI_HCD)			+= ohci-hcd.o
+# obj-$(CONFIG_UHCI_HCD)			+= uhci-hcd.o
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+multi-y		:= $(filter $(list-multi), $(obj-y))
+multi-m		:= $(filter $(list-multi), $(obj-m))
+int-y		:= $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m		:= $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Take multi-part drivers out of obj-y and put components in.
+obj-y		:= $(filter-out $(list-multi), $(obj-y)) $(int-y)
+
+# Translate to Rules.make lists.
+OX_OBJS		:= $(obj-y)
+MX_OBJS		:= $(obj-m)
+MIX_OBJS	:= $(int-m)
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/hcd/ehci-dbg.c linux/drivers/usb/hcd/ehci-dbg.c
--- v2.5.1/linux/drivers/usb/hcd/ehci-dbg.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ehci-dbg.c	Tue Jan  1 13:52:10 2002
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+#ifdef EHCI_VERBOSE_DEBUG
+#	define vdbg dbg
+#else
+	static inline void vdbg (char *fmt, ...) { }
+#endif
+
+#ifdef	DEBUG
+
+/* check the values in the HCSPARAMS register - host controller structural parameters */
+/* see EHCI 0.95 Spec, Table 2-4 for each value */
+static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
+{
+	u32	params = readl (&ehci->caps->hcs_params);
+
+	dbg ("%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d",
+		label, params,
+		HCS_DEBUG_PORT (params),
+		HCS_INDICATOR (params) ? " ind" : "",
+		HCS_N_CC (params),
+		HCS_N_PCC (params),
+	        HCS_PORTROUTED (params) ? "" : " ordered",
+		HCS_PPC (params) ? "" : " !ppc",
+		HCS_N_PORTS (params)
+		);
+	/* Port routing, per EHCI 0.95 Spec, Section 2.2.5 */
+	if (HCS_PORTROUTED (params)) {
+		int i;
+		char buf [46], tmp [7], byte;
+
+		buf[0] = 0;
+		for (i = 0; i < HCS_N_PORTS (params); i++) {
+			byte = readb (&ehci->caps->portroute[(i>>1)]);
+			sprintf(tmp, "%d ", 
+				((i & 0x1) ? ((byte)&0xf) : ((byte>>4)&0xf)));
+			strcat(buf, tmp);
+		}
+		dbg ("%s: %s portroute %s", 
+			ehci->hcd.bus_name, label,
+			buf);
+	}
+}
+#else
+
+static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}
+
+#endif
+
+#ifdef	DEBUG
+
+/* check the values in the HCCPARAMS register - host controller capability parameters */
+/* see EHCI 0.95 Spec, Table 2-5 for each value */
+static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
+{
+	u32	params = readl (&ehci->caps->hcc_params);
+
+	if (HCC_EXT_CAPS (params)) {
+		// EHCI 0.96 ... could interpret these (legacy?)
+		dbg ("%s extended capabilities at pci %d",
+			label, HCC_EXT_CAPS (params));
+	}
+	if (HCC_ISOC_CACHE (params)) {
+		dbg ("%s hcc_params 0x%04x caching frame %s%s%s",
+		     label, params,
+		     HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
+		     HCC_CANPARK (params) ? " park" : "",
+		     HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
+	} else {
+		dbg ("%s hcc_params 0x%04x caching %d uframes %s%s%s",
+		     label,
+		     params,
+		     HCC_ISOC_THRES (params),
+		     HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
+		     HCC_CANPARK (params) ? " park" : "",
+		     HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
+	}
+}
+#else
+
+static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {}
+
+#endif
+
+#ifdef	DEBUG
+
+#if 0
+static void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	dbg ("%s %p info1 %x info2 %x hw_curr %x qtd_next %x", label,
+		qh, qh->hw_info1, qh->hw_info2,
+		qh->hw_current, qh->hw_qtd_next);
+	dbg ("  alt+errs= %x, token= %x, page0= %x, page1= %x",
+		qh->hw_alt_next, qh->hw_token,
+		qh->hw_buf [0], qh->hw_buf [1]);
+	if (qh->hw_buf [2]) {
+		dbg ("  page2= %x, page3= %x, page4= %x",
+			qh->hw_buf [2], qh->hw_buf [3],
+			qh->hw_buf [4]);
+	}
+}
+#endif
+
+static const char *const fls_strings [] =
+    { "1024", "512", "256", "??" };
+
+#else
+#if 0
+static inline void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) {}
+#endif
+#endif	/* DEBUG */
+
+/* functions have the "wrong" filename when they're output... */
+
+#define dbg_status(ehci, label, status) \
+	dbg ("%s status 0x%x%s%s%s%s%s%s%s%s%s%s", \
+		label, status, \
+		(status & STS_ASS) ? " Async" : "", \
+		(status & STS_PSS) ? " Periodic" : "", \
+		(status & STS_RECL) ? " Recl" : "", \
+		(status & STS_HALT) ? " Halt" : "", \
+		(status & STS_IAA) ? " IAA" : "", \
+		(status & STS_FATAL) ? " FATAL" : "", \
+		(status & STS_FLR) ? " FLR" : "", \
+		(status & STS_PCD) ? " PCD" : "", \
+		(status & STS_ERR) ? " ERR" : "", \
+		(status & STS_INT) ? " INT" : "" \
+		)
+
+#define dbg_cmd(ehci, label, command) \
+	dbg ("%s %x cmd %s=%d ithresh=%d%s%s%s%s period=%s%s %s", \
+		label, command, \
+		(command & CMD_PARK) ? "park" : "(park)", \
+		CMD_PARK_CNT (command), \
+		(command >> 16) & 0x3f, \
+		(command & CMD_LRESET) ? " LReset" : "", \
+		(command & CMD_IAAD) ? " IAAD" : "", \
+		(command & CMD_ASE) ? " Async" : "", \
+		(command & CMD_PSE) ? " Periodic" : "", \
+		fls_strings [(command >> 2) & 0x3], \
+		(command & CMD_RESET) ? " Reset" : "", \
+		(command & CMD_RUN) ? "RUN" : "HALT" \
+		)
+
+#define dbg_port(hcd, label, port, status) \
+	dbg ("%s port %d status 0x%x%s%s speed=%d%s%s%s%s%s%s%s%s%s", \
+		label, port, status, \
+		(status & PORT_OWNER) ? " OWNER" : "", \
+		(status & PORT_POWER) ? " POWER" : "", \
+		(status >> 10) & 3, \
+		(status & PORT_RESET) ? " RESET" : "", \
+		(status & PORT_SUSPEND) ? " SUSPEND" : "", \
+		(status & PORT_RESUME) ? " RESUME" : "", \
+		(status & PORT_OCC) ? " OCC" : "", \
+		(status & PORT_OC) ? " OC" : "", \
+		(status & PORT_PEC) ? " PEC" : "", \
+		(status & PORT_PE) ? " PE" : "", \
+		(status & PORT_CSC) ? " CSC" : "", \
+		(status & PORT_CONNECT) ? " CONNECT" : "" \
+	    )
+
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/hcd/ehci-hcd.c linux/drivers/usb/hcd/ehci-hcd.c
--- v2.5.1/linux/drivers/usb/hcd/ehci-hcd.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ehci-hcd.c	Tue Jan  1 13:52:10 2002
@@ -0,0 +1,758 @@
+/*
+ * Copyright (c) 2000-2001 by David Brownell
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+
+#ifndef CONFIG_USB_DEBUG
+	#define CONFIG_USB_DEBUG	/* this is still experimental! */
+#endif
+
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+
+#include <linux/usb.h>
+#include "../hcd.h"
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+//#undef KERN_DEBUG
+//#define KERN_DEBUG ""
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI hc_driver implementation ... experimental, incomplete.
+ * Based on the 0.96 register interface specification.
+ *
+ * There are lots of things to help out with here ... notably
+ * everything "periodic", and of course testing with all sorts
+ * of usb 2.0 devices and configurations.
+ *
+ * USB 2.0 shows up in upcoming www.pcmcia.org technology.
+ * First was PCMCIA, like ISA; then CardBus, which is PCI.
+ * Next comes "CardBay", using USB 2.0 signals.
+ *
+ * Contains additional contributions by:
+ *	Brad Hards
+ *	Rory Bolt
+ *	...
+ */
+
+#define DRIVER_VERSION "$Revision: 0.25 $"
+#define DRIVER_AUTHOR "David Brownell"
+#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
+
+
+// #define EHCI_VERBOSE_DEBUG
+// #define have_iso
+
+#ifdef	DEBUG
+#	define	EHCI_SLAB_FLAGS		(SLAB_POISON)
+#else
+#	define	EHCI_SLAB_FLAGS		0
+#endif
+
+/* magic numbers that can affect system performance */
+#define	EHCI_TUNE_CERR		3	/* 0-3 qtd retries; 0 == don't stop */
+#define	EHCI_TUNE_RL_HS		0	/* nak throttle; see 4.9 */
+#define	EHCI_TUNE_RL_TT		0
+#define	EHCI_TUNE_MULT_HS	1	/* 1-3 transactions/uframe; 4.10.3 */
+#define	EHCI_TUNE_MULT_TT	1
+
+/* Initial IRQ latency:  lower than default */
+static int log2_irq_thresh = 0;		// 0 to 6
+MODULE_PARM (log2_irq_thresh, "i");
+MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
+
+/* Some A steppings of the NEC controller need soft retries */
+//#define	EHCI_SOFT_RETRIES	5	/* after CERR-induced fault */
+
+#define	INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT)
+
+/*-------------------------------------------------------------------------*/
+
+#include "ehci.h"
+#include "ehci-dbg.c"
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * hc states include: unknown, halted, ready, running
+ * transitional states are messy just now
+ * trying to avoid "running" unless urbs are active
+ * a "ready" hc can be finishing prefetched work
+ */
+
+/* halt a non-running controller */
+static void ehci_reset (struct ehci_hcd *ehci)
+{
+	u32	command = readl (&ehci->regs->command);
+
+	command |= CMD_RESET;
+	dbg_cmd (ehci, "reset", command);
+	writel (command, &ehci->regs->command);
+	while (readl (&ehci->regs->command) & CMD_RESET)
+		continue;
+	ehci->hcd.state = USB_STATE_HALT;
+}
+
+/* idle the controller (from running) */
+static void ehci_ready (struct ehci_hcd *ehci)
+{
+	u32	command;
+
+#ifdef DEBUG
+	if (!HCD_IS_RUNNING (ehci->hcd.state))
+		BUG ();
+#endif
+
+	while (!(readl (&ehci->regs->status) & (STS_ASS | STS_PSS)))
+		udelay (100);
+	command = readl (&ehci->regs->command);
+	command &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
+	writel (command, &ehci->regs->command);
+
+	// hardware can take 16 microframes to turn off ...
+	ehci->hcd.state = USB_STATE_READY;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#include "ehci-hub.c"
+#include "ehci-mem.c"
+#include "ehci-q.c"
+#include "ehci-sched.c"
+
+/*-------------------------------------------------------------------------*/
+
+static void ehci_tasklet (unsigned long param);
+
+/* called by khubd or root hub init threads */
+
+static int ehci_start (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	u32			temp;
+	struct usb_device	*udev;
+	int			retval;
+	u32			hcc_params;
+	u8                      tempbyte;
+
+	// FIXME:  given EHCI 0.96 or later, and a controller with
+	// the USBLEGSUP/USBLEGCTLSTS extended capability, make sure
+	// the BIOS doesn't still own this controller.
+
+	spin_lock_init (&ehci->lock);
+
+	ehci->caps = (struct ehci_caps *) hcd->regs;
+	ehci->regs = (struct ehci_regs *) (hcd->regs + ehci->caps->length);
+	dbg_hcs_params (ehci, "ehci_start");
+	dbg_hcc_params (ehci, "ehci_start");
+
+	/*
+	 * hw default: 1K periodic list heads, one per frame.
+	 * periodic_size can shrink by USBCMD update if hcc_params allows.
+	 */
+	ehci->periodic_size = DEFAULT_I_TDPS;
+	if ((retval = ehci_mem_init (ehci, EHCI_SLAB_FLAGS | SLAB_KERNEL)) < 0)
+		return retval;
+	hcc_params = readl (&ehci->caps->hcc_params);
+
+	/* controllers may cache some of the periodic schedule ... */
+	if (HCC_ISOC_CACHE (hcc_params)) 	// full frame cache
+		ehci->i_thresh = 8;
+	else					// N microframes cached
+		ehci->i_thresh = 2 + HCC_ISOC_THRES (hcc_params);
+
+	ehci->async = 0;
+	ehci->reclaim = 0;
+	ehci->next_frame = -1;
+
+	/* controller state:  unknown --> reset */
+
+	/* EHCI spec section 4.1 */
+	ehci_reset (ehci);
+	writel (INTR_MASK, &ehci->regs->intr_enable);
+	writel (ehci->periodic_dma, &ehci->regs->frame_list);
+
+	/*
+	 * hcc_params controls whether ehci->regs->segment must (!!!)
+	 * be used; it constrains QH/ITD/SITD and QTD locations.
+	 * By default, pci_alloc_consistent() won't hand out addresses
+	 * above 4GB (via pdev->dma_mask) so we know this value.
+	 *
+	 * NOTE:  that pdev->dma_mask setting means that all DMA mappings
+	 * for I/O buffers will have the same restriction, though it's
+	 * neither necessary nor desirable in that case.
+	 */
+	if (HCC_64BIT_ADDR (hcc_params)) {
+		writel (0, &ehci->regs->segment);
+		info ("using segment 0 for 64bit DMA addresses ...");
+	}
+
+	/* clear interrupt enables, set irq latency */
+	temp = readl (&ehci->regs->command) & 0xff;
+	if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
+	    log2_irq_thresh = 0;
+	temp |= 1 << (16 + log2_irq_thresh);
+	// keeping default periodic framelist size
+	temp &= ~(CMD_IAAD | CMD_ASE | CMD_PSE),
+	writel (temp, &ehci->regs->command);
+	dbg_cmd (ehci, "init", temp);
+
+	/* set async sleep time = 10 us ... ? */
+
+	ehci->tasklet.func = ehci_tasklet;
+	ehci->tasklet.data = (unsigned long) ehci;
+
+	/* wire up the root hub */
+	hcd->bus->root_hub = udev = usb_alloc_dev (NULL, hcd->bus);
+	if (!udev) {
+done2:
+		ehci_mem_cleanup (ehci);
+		return -ENOMEM;
+	}
+
+	/*
+	 * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
+	 * are explicitly handed to companion controller(s), so no TT is
+	 * involved with the root hub.
+	 */
+	ehci->hcd.state = USB_STATE_READY;
+	writel (FLAG_CF, &ehci->regs->configured_flag);
+	readl (&ehci->regs->command);	/* unblock posted write */
+
+        /* PCI Serial Bus Release Number is at 0x60 offset */
+	pci_read_config_byte(hcd->pdev, 0x60, &tempbyte);
+	temp = readw (&ehci->caps->hci_version);
+	info ("USB %x.%x support enabled, EHCI rev %x.%2x",
+	      ((tempbyte & 0xf0)>>4),
+	      (tempbyte & 0x0f),
+	       temp >> 8,
+	       temp & 0xff);
+
+	/*
+	 * From here on, khubd concurrently accesses the root
+	 * hub; drivers will be talking to enumerated devices.
+	 *
+	 * Before this point the HC was idle/ready.  After, khubd
+	 * and device drivers may start it running.
+	 */
+	usb_connect (udev);
+	udev->speed = USB_SPEED_HIGH;
+	if (usb_new_device (udev) != 0) {
+		if (hcd->state == USB_STATE_RUNNING)
+			ehci_ready (ehci);
+		while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
+			udelay (100);
+		ehci_reset (ehci);
+		// usb_disconnect (udev); 
+		hcd->bus->root_hub = 0;
+		usb_free_dev (udev); 
+		retval = -ENODEV;
+		goto done2;
+	}
+
+	return 0;
+}
+
+/* always called by thread; normally rmmod */
+
+static void ehci_stop (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+
+	dbg ("%s: stop", hcd->bus_name);
+
+	if (hcd->state == USB_STATE_RUNNING)
+		ehci_ready (ehci);
+	while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
+		udelay (100);
+	ehci_reset (ehci);
+
+	// root hub is shut down separately (first, when possible)
+	scan_async (ehci);
+	if (ehci->next_frame != -1)
+		scan_periodic (ehci);
+	ehci_mem_cleanup (ehci);
+
+	dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
+}
+
+static int ehci_get_frame (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	CONFIG_PM
+
+/* suspend/resume, section 4.3 */
+
+static int ehci_suspend (struct usb_hcd *hcd, u32 state)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	u32			params;
+	int			ports;
+	int			i;
+
+	dbg ("%s: suspend to %d", hcd->bus_name, state);
+
+	params = readl (&ehci->caps->hcs_params);
+	ports = HCS_N_PORTS (params);
+
+	// FIXME:  This assumes what's probably a D3 level suspend...
+
+	// FIXME:  usb wakeup events on this bus should resume the machine.
+	// pci config register PORTWAKECAP controls which ports can do it;
+	// bios may have initted the register...
+
+	/* suspend each port, then stop the hc */
+	for (i = 0; i < ports; i++) {
+		int	temp = readl (&ehci->regs->port_status [i]);
+
+		if ((temp & PORT_PE) == 0
+				|| (temp & PORT_OWNER) != 0)
+			continue;
+dbg ("%s: suspend port %d", hcd->bus_name, i);
+		temp |= PORT_SUSPEND;
+		writel (temp, &ehci->regs->port_status [i]);
+	}
+
+	if (hcd->state == USB_STATE_RUNNING)
+		ehci_ready (ehci);
+	while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
+		udelay (100);
+	writel (readl (&ehci->regs->command) & ~CMD_RUN, &ehci->regs->command);
+
+// save pci FLADJ value
+
+	/* who tells PCI to reduce power consumption? */
+
+	return 0;
+}
+
+static int ehci_resume (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	u32			params;
+	int			ports;
+	int			i;
+
+	dbg ("%s: resume", hcd->bus_name);
+
+	params = readl (&ehci->caps->hcs_params);
+	ports = HCS_N_PORTS (params);
+
+	// FIXME:  if controller didn't retain state,
+	// return and let generic code clean it up
+	// test configured_flag ?
+
+	/* resume HC and each port */
+// restore pci FLADJ value
+	// khubd and drivers will set HC running, if needed;
+	hcd->state = USB_STATE_READY;
+	for (i = 0; i < ports; i++) {
+		int	temp = readl (&ehci->regs->port_status [i]);
+
+		if ((temp & PORT_PE) == 0
+				|| (temp & PORT_SUSPEND) != 0)
+			continue;
+dbg ("%s: resume port %d", hcd->bus_name, i);
+		temp |= PORT_RESUME;
+		writel (temp, &ehci->regs->port_status [i]);
+		readl (&ehci->regs->command);	/* unblock posted writes */
+
+		wait_ms (20);
+		temp &= ~PORT_RESUME;
+		writel (temp, &ehci->regs->port_status [i]);
+	}
+	readl (&ehci->regs->command);	/* unblock posted writes */
+	return 0;
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * tasklet scheduled by some interrupts and other events
+ * calls driver completion functions ... but not in_irq()
+ */
+static void ehci_tasklet (unsigned long param)
+{
+	struct ehci_hcd		*ehci = (struct ehci_hcd *) param;
+
+	if (ehci->reclaim_ready)
+		end_unlink_async (ehci);
+	scan_async (ehci);
+	if (ehci->next_frame != -1)
+		scan_periodic (ehci);
+
+	// FIXME:  when nothing is connected to the root hub,
+	// turn off the RUN bit so the host can enter C3 "sleep" power
+	// saving mode; make root hub code scan memory less often.
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void ehci_irq (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	u32			status = readl (&ehci->regs->status);
+	int			bh = 0;
+
+	/* clear (just) interrupts */
+	status &= INTR_MASK;
+	writel (status, &ehci->regs->status);
+	readl (&ehci->regs->command);	/* unblock posted write */
+
+	if (unlikely (hcd->state == USB_STATE_HALT))	/* irq sharing? */
+		return;
+
+#ifdef	EHCI_VERBOSE_DEBUG
+	/* unrequested/ignored: Port Change Detect, Frame List Rollover */
+	if (status & INTR_MASK)
+		dbg_status (ehci, "irq", status);
+#endif
+
+	/* INT, ERR, and IAA interrupt rates can be throttled */
+
+	/* normal [4.15.1.2] or error [4.15.1.1] completion */
+	if (likely ((status & (STS_INT|STS_ERR)) != 0))
+		bh = 1;
+
+	/* complete the unlinking of some qh [4.15.2.3] */
+	if (status & STS_IAA) {
+		ehci->reclaim_ready = 1;
+		bh = 1;
+	}
+
+	/* PCI errors [4.15.2.4] */
+	if (unlikely ((status & STS_FATAL) != 0)) {
+		err ("%s: fatal error, state %x", hcd->bus_name, hcd->state);
+		ehci_reset (ehci);
+		// generic layer kills/unlinks all urbs
+		// then tasklet cleans up the rest
+		bh = 1;
+	}
+
+	/* most work doesn't need to be in_irq() */
+	if (likely (bh == 1))
+		tasklet_schedule (&ehci->tasklet);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * non-error returns are a promise to giveback() the urb later
+ * we drop ownership so next owner (or urb unlink) can get it
+ *
+ * urb + dev is in hcd_dev.urb_list
+ * we're queueing TDs onto software and hardware lists
+ *
+ * hcd-specific init for hcpriv hasn't been done yet
+ *
+ * NOTE:  EHCI queues control and bulk requests transparently, like OHCI.
+ */
+static int ehci_urb_enqueue (
+	struct usb_hcd	*hcd,
+	struct urb	*urb,
+	int		mem_flags
+) {
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	struct list_head	qtd_list;
+
+	urb->transfer_flags &= ~EHCI_STATE_UNLINK;
+	INIT_LIST_HEAD (&qtd_list);
+	switch (usb_pipetype (urb->pipe)) {
+
+	case PIPE_CONTROL:
+	case PIPE_BULK:
+		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
+			return -ENOMEM;
+		submit_async (ehci, urb, &qtd_list, mem_flags);
+		break;
+
+	case PIPE_INTERRUPT:
+		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
+			return -ENOMEM;
+		return intr_submit (ehci, urb, &qtd_list, mem_flags);
+
+	case PIPE_ISOCHRONOUS:
+#ifdef have_iso
+		if (urb->dev->speed == USB_SPEED_HIGH)
+			return itd_submit (ehci, urb);
+		else
+			return sitd_submit (ehci, urb);
+#else
+		// FIXME highspeed iso stuff is written but never run/tested.
+		// and the split iso support isn't even written yet.
+		dbg ("no iso support yet");
+		return -ENOSYS;
+#endif /* have_iso */
+
+	}
+	return 0;
+}
+
+/* remove from hardware lists
+ * completions normally happen asynchronously
+ */
+
+static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	struct ehci_qh		*qh = (struct ehci_qh *) urb->hcpriv;
+	unsigned long		flags;
+
+	dbg ("%s urb_dequeue %p qh state %d",
+		hcd->bus_name, urb, qh->qh_state);
+
+	switch (usb_pipetype (urb->pipe)) {
+	case PIPE_CONTROL:
+	case PIPE_BULK:
+		spin_lock_irqsave (&ehci->lock, flags);
+		if (ehci->reclaim) {
+dbg ("dq: reclaim busy, %s", RUN_CONTEXT);
+			if (in_interrupt ()) {
+				spin_unlock_irqrestore (&ehci->lock, flags);
+				return -EAGAIN;
+			}
+			while (qh->qh_state == QH_STATE_LINKED
+					&& ehci->reclaim
+					&& ehci->hcd.state != USB_STATE_HALT
+					) {
+				spin_unlock_irqrestore (&ehci->lock, flags);
+// yeech ... this could spin for up to two frames!
+dbg ("wait for dequeue: state %d, reclaim %p, hcd state %d",
+    qh->qh_state, ehci->reclaim, ehci->hcd.state
+);
+				udelay (100);
+				spin_lock_irqsave (&ehci->lock, flags);
+			}
+		}
+		if (qh->qh_state == QH_STATE_LINKED)
+			start_unlink_async (ehci, qh);
+		spin_unlock_irqrestore (&ehci->lock, flags);
+		return 0;
+
+	case PIPE_INTERRUPT:
+		intr_deschedule (ehci, urb->start_frame, qh, urb->interval);
+		if (ehci->hcd.state == USB_STATE_HALT)
+			urb->status = -ESHUTDOWN;
+		qh_completions (ehci, &qh->qtd_list, 1);
+		return 0;
+
+	case PIPE_ISOCHRONOUS:
+		// itd or sitd ...
+
+		// wait till next completion, do it then.
+		// completion irqs can wait up to 128 msec,
+		urb->transfer_flags |= EHCI_STATE_UNLINK;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+/*-------------------------------------------------------------------------*/
+
+// bulk qh holds the data toggle
+
+static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct hcd_dev		*dev = (struct hcd_dev *)udev->hcpriv;
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	int			i;
+	unsigned long		flags;
+
+	/* ASSERT:  nobody can be submitting urbs for this any more */
+
+	dbg ("%s: free_config devnum %d", hcd->bus_name, udev->devnum);
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	for (i = 0; i < 32; i++) {
+		if (dev->ep [i]) {
+			struct ehci_qh		*qh;
+
+			// FIXME:  this might be an itd/sitd too ...
+			// or an interrupt urb (not on async list)
+			// can use "union ehci_shadow"
+
+			qh = (struct ehci_qh *) dev->ep [i];
+			vdbg ("free_config, ep 0x%02x qh %p", i, qh);
+			if (!list_empty (&qh->qtd_list)) {
+				dbg ("ep 0x%02x qh %p not empty!", i, qh);
+				BUG ();
+			}
+			dev->ep [i] = 0;
+
+			/* wait_ms() won't spin here -- we're a thread */
+			while (qh->qh_state == QH_STATE_LINKED
+					&& ehci->reclaim
+					&& ehci->hcd.state != USB_STATE_HALT
+					) {
+				spin_unlock_irqrestore (&ehci->lock, flags);
+				wait_ms (1);
+				spin_lock_irqsave (&ehci->lock, flags);
+			}
+			if (qh->qh_state == QH_STATE_LINKED) {
+				start_unlink_async (ehci, qh);
+				while (qh->qh_state != QH_STATE_IDLE) {
+					spin_unlock_irqrestore (&ehci->lock,
+						flags);
+					wait_ms (1);
+					spin_lock_irqsave (&ehci->lock, flags);
+				}
+			}
+			qh_unput (ehci, qh);
+		}
+	}
+
+	spin_unlock_irqrestore (&ehci->lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const char	hcd_name [] = "ehci-hcd";
+
+static const struct hc_driver ehci_driver = {
+	description:		hcd_name,
+
+	/*
+	 * generic hardware linkage
+	 */
+	irq:			ehci_irq,
+	flags:			HCD_MEMORY | HCD_USB2,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	start:			ehci_start,
+#ifdef	CONFIG_PM
+	suspend:		ehci_suspend,
+	resume:			ehci_resume,
+#endif
+	stop:			ehci_stop,
+
+	/*
+	 * memory lifecycle (except per-request)
+	 */
+	hcd_alloc:		ehci_hcd_alloc,
+	hcd_free:		ehci_hcd_free,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	urb_enqueue:		ehci_urb_enqueue,
+	urb_dequeue:		ehci_urb_dequeue,
+	free_config:		ehci_free_config,
+
+	/*
+	 * scheduling support
+	 */
+	get_frame_number:	ehci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	hub_status_data:	ehci_hub_status_data,
+	hub_control:		ehci_hub_control,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* EHCI spec says PCI is required. */
+
+/* PCI driver selection metadata; PCI hotplugging uses this */
+static const struct pci_device_id __devinitdata pci_ids [] = { {
+
+	/* handle any USB 2.0 EHCI controller */
+
+	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x20),
+	class_mask: 	~0,
+	driver_data:	(unsigned long) &ehci_driver,
+
+	/* no matter who makes it */
+	vendor:		PCI_ANY_ID,
+	device:		PCI_ANY_ID,
+	subvendor:	PCI_ANY_ID,
+	subdevice:	PCI_ANY_ID,
+
+}, { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE (pci, pci_ids);
+
+/* pci driver glue; this is a "new style" PCI driver module */
+static struct pci_driver ehci_pci_driver = {
+	name:		(char *) hcd_name,
+	id_table:	pci_ids,
+
+	probe:		usb_hcd_pci_probe,
+	remove:		usb_hcd_pci_remove,
+
+#ifdef	CONFIG_PM
+	suspend:	usb_hcd_pci_suspend,
+	resume:		usb_hcd_pci_resume,
+#endif
+};
+
+#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
+
+EXPORT_NO_SYMBOLS;
+MODULE_DESCRIPTION (DRIVER_INFO);
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_LICENSE ("GPL");
+
+static int __init init (void) 
+{
+	dbg (DRIVER_INFO);
+	dbg ("block sizes: qh %d qtd %d itd %d sitd %d",
+		sizeof (struct ehci_qh), sizeof (struct ehci_qtd),
+		sizeof (struct ehci_itd), sizeof (struct ehci_sitd));
+
+	return pci_module_init (&ehci_pci_driver);
+}
+module_init (init);
+
+static void __exit cleanup (void) 
+{	
+	pci_unregister_driver (&ehci_pci_driver);
+}
+module_exit (cleanup);
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/hcd/ehci-hub.c linux/drivers/usb/hcd/ehci-hub.c
--- v2.5.1/linux/drivers/usb/hcd/ehci-hub.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ehci-hub.c	Tue Jan  1 13:52:10 2002
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Root Hub ... the nonsharable stuff
+ *
+ * Registers don't need cpu_to_le32, that happens transparently
+ */
+
+/*-------------------------------------------------------------------------*/
+
+static int check_reset_complete (
+	struct ehci_hcd	*ehci,
+	int		index,
+	int		port_status
+) {
+	if (!(port_status & PORT_CONNECT)) {
+		ehci->reset_done [index] = 0;
+		return port_status;
+	}
+
+	/* if reset finished and it's still not enabled -- handoff */
+	if (!(port_status & PORT_PE)) {
+		dbg ("%s port %d full speed, give to companion, 0x%x",
+			ehci->hcd.bus_name, index + 1, port_status);
+
+		// what happens if HCS_N_CC(params) == 0 ?
+		port_status |= PORT_OWNER;
+		writel (port_status, &ehci->regs->port_status [index]);
+
+	} else
+		dbg ("%s port %d high speed", ehci->hcd.bus_name, index + 1);
+
+	return port_status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+
+/* build "status change" packet (one or two bytes) from HC registers */
+
+static int
+ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
+{
+	struct ehci_hcd	*ehci = hcd_to_ehci (hcd);
+	u32		temp, status = 0;
+	int		ports, i, retval = 1;
+	unsigned long	flags;
+
+	/* init status to no-changes */
+	buf [0] = 0;
+	temp = readl (&ehci->caps->hcs_params);
+	ports = HCS_N_PORTS (temp);
+	if (ports > 7) {
+		buf [1] = 0;
+		retval++;
+	}
+	
+	/* no hub change reports (bit 0) for now (power, ...) */
+
+	/* port N changes (bit N)? */
+	spin_lock_irqsave (&ehci->lock, flags);
+	for (i = 0; i < ports; i++) {
+		temp = readl (&ehci->regs->port_status [i]);
+		if (temp & PORT_OWNER) {
+			// get disconnected ports back if no companion driver
+			if (temp & PORT_CONNECT)
+				continue;
+			temp &= ~(PORT_OWNER|PORT_CSC);
+			writel (temp, &ehci->regs->port_status [i]);
+		}
+		if (!(temp & PORT_CONNECT))
+			ehci->reset_done [i] = 0;
+		if ((temp & (PORT_CSC | PORT_PEC | PORT_OCC)) != 0) {
+			set_bit (i, buf);
+			status = STS_PCD;
+		}
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	return status ? retval : 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+ehci_hub_descriptor (
+	struct ehci_hcd			*ehci,
+	struct usb_hub_descriptor	*desc
+) {
+	u32		params = readl (&ehci->caps->hcs_params);
+	int		ports = HCS_N_PORTS (params);
+	u16		temp;
+
+	desc->bDescriptorType = 0x29;
+	desc->bPwrOn2PwrGood = 0;	/* FIXME: f(system power) */
+	desc->bHubContrCurrent = 0;
+
+	desc->bNbrPorts = ports;
+	temp = 1 + (ports / 8);
+	desc->bDescLength = 7 + 2 * temp;
+
+	/* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+	memset (&desc->bitmap [0], 0, temp);
+	memset (&desc->bitmap [temp], 0xff, temp);
+
+	temp = 0x0008;			/* per-port overcurrent reporting */
+	if (HCS_PPC (params))		/* per-port power control */
+	    temp |= 0x0001;
+	if (HCS_INDICATOR (params))	/* per-port indicators (LEDs) */
+	    temp |= 0x0080;
+	desc->wHubCharacteristics = cpu_to_le16 (temp);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int ehci_hub_control (
+	struct usb_hcd	*hcd,
+	u16		typeReq,
+	u16		wValue,
+	u16		wIndex,
+	char		*buf,
+	u16		wLength
+) {
+	struct ehci_hcd	*ehci = hcd_to_ehci (hcd);
+	u32		params = readl (&ehci->caps->hcs_params);
+	int		ports = HCS_N_PORTS (params);
+	u32		temp;
+	unsigned long	flags;
+	int		retval = 0;
+
+	/*
+	 * FIXME:  support SetPortFeatures USB_PORT_FEAT_INDICATOR.
+	 * HCS_INDICATOR may say we can change LEDs to off/amber/green.
+	 * (track current state ourselves) ... blink for diagnostics,
+	 * power, "this is the one", etc.  EHCI spec supports this.
+	 */
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	switch (typeReq) {
+	case ClearHubFeature:
+		switch (wValue) {
+		case C_HUB_LOCAL_POWER:
+		case C_HUB_OVER_CURRENT:
+			/* no hub-wide feature/status flags */
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case ClearPortFeature:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		temp = readl (&ehci->regs->port_status [wIndex]);
+		if (temp & PORT_OWNER)
+			break;
+
+		switch (wValue) {
+		case USB_PORT_FEAT_ENABLE:
+			writel (temp & ~PORT_PE,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_C_ENABLE:
+			writel (temp | PORT_PEC,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_SUSPEND:
+		case USB_PORT_FEAT_C_SUSPEND:
+			/* ? */
+			break;
+		case USB_PORT_FEAT_POWER:
+			if (HCS_PPC (params))
+				writel (temp & ~PORT_POWER,
+					&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_C_CONNECTION:
+			writel (temp | PORT_CSC,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+			writel (temp | PORT_OCC,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_C_RESET:
+			/* GetPortStatus clears reset */
+			break;
+		default:
+			goto error;
+		}
+		readl (&ehci->regs->command);	/* unblock posted write */
+		break;
+	case GetHubDescriptor:
+		ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
+			buf);
+		break;
+	case GetHubStatus:
+		/* no hub-wide feature/status flags */
+		memset (buf, 0, 4);
+		//cpu_to_le32s ((u32 *) buf);
+		break;
+	case GetPortStatus:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		memset (buf, 0, 4);
+		temp = readl (&ehci->regs->port_status [wIndex]);
+
+		// wPortChange bits
+		if (temp & PORT_CSC)
+			set_bit (USB_PORT_FEAT_C_CONNECTION, buf);
+		if (temp & PORT_PEC)
+			set_bit (USB_PORT_FEAT_C_ENABLE, buf);
+		// USB_PORT_FEAT_C_SUSPEND
+		if (temp & PORT_OCC)
+			set_bit (USB_PORT_FEAT_C_OVER_CURRENT, buf);
+
+		/* whoever resets must GetPortStatus to complete it!! */
+		if ((temp & PORT_RESET)
+				&& jiffies > ehci->reset_done [wIndex]) {
+			set_bit (USB_PORT_FEAT_C_RESET, buf);
+
+			/* force reset to complete */
+			writel (temp & ~PORT_RESET,
+					&ehci->regs->port_status [wIndex]);
+			do {
+				temp = readl (
+					&ehci->regs->port_status [wIndex]);
+				udelay (10);
+			} while (temp & PORT_RESET);
+
+			/* see what we found out */
+			temp = check_reset_complete (ehci, wIndex, temp);
+		}
+
+		// don't show wPortStatus if it's owned by a companion hc
+		if (!(temp & PORT_OWNER)) {
+			if (temp & PORT_CONNECT) {
+				set_bit (USB_PORT_FEAT_CONNECTION, buf);
+				set_bit (USB_PORT_FEAT_HIGHSPEED, buf);
+			}
+			if (temp & PORT_PE)
+				set_bit (USB_PORT_FEAT_ENABLE, buf);
+			if (temp & PORT_SUSPEND)
+				set_bit (USB_PORT_FEAT_SUSPEND, buf);
+			if (temp & PORT_OC)
+				set_bit (USB_PORT_FEAT_OVER_CURRENT, buf);
+			if (temp & PORT_RESET)
+				set_bit (USB_PORT_FEAT_RESET, buf);
+			if (temp & PORT_POWER)
+				set_bit (USB_PORT_FEAT_POWER, buf);
+		}
+
+#ifndef	EHCI_VERBOSE_DEBUG
+	if (*(u16*)(buf+2))	/* only if wPortChange is interesting */
+#endif
+		dbg_port (hcd, "GetStatus", wIndex + 1, temp);
+		cpu_to_le32s ((u32 *) buf);
+		break;
+	case SetHubFeature:
+		switch (wValue) {
+		case C_HUB_LOCAL_POWER:
+		case C_HUB_OVER_CURRENT:
+			/* no hub-wide feature/status flags */
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case SetPortFeature:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		temp = readl (&ehci->regs->port_status [wIndex]);
+		if (temp & PORT_OWNER)
+			break;
+
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			writel (temp | PORT_SUSPEND,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_POWER:
+			if (HCS_PPC (params))
+				writel (temp | PORT_POWER,
+					&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_RESET:
+			/* line status bits may report this as low speed */
+			if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
+					&& PORT_USB11 (temp)) {
+				dbg ("%s port %d low speed, give to companion",
+					hcd->bus_name, wIndex + 1);
+				temp |= PORT_OWNER;
+			} else {
+				vdbg ("%s port %d reset",
+					hcd->bus_name, wIndex + 1);
+				temp |= PORT_RESET;
+				temp &= ~PORT_PE;
+
+				/*
+				 * caller must wait, then call GetPortStatus
+				 * usb 2.0 spec says 50 ms resets on root
+				 */
+				ehci->reset_done [wIndex] = jiffies
+				    	+ ((50 /* msec */ * HZ) / 1000);
+			}
+			writel (temp, &ehci->regs->port_status [wIndex]);
+			break;
+		default:
+			goto error;
+		}
+		readl (&ehci->regs->command);	/* unblock posted writes */
+		break;
+
+	default:
+error:
+		/* "stall" on error */
+		retval = -EPIPE;
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	return retval;
+}
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/hcd/ehci-mem.c linux/drivers/usb/hcd/ehci-mem.c
--- v2.5.1/linux/drivers/usb/hcd/ehci-mem.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ehci-mem.c	Tue Jan  1 13:52:10 2002
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * There's basically three types of memory:
+ *	- data used only by the HCD ... kmalloc is fine
+ *	- async and periodic schedules, shared by HC and HCD ... these
+ *	  need to use pci_pool or pci_alloc_consistent
+ *	- driver buffers, read/written by HC ... single shot DMA mapped 
+ *
+ * There's also PCI "register" data, which is memory mapped.
+ * No memory seen by this driver is pagable.
+ */
+
+/*-------------------------------------------------------------------------*/
+/* 
+ * Allocator / cleanup for the per device structure
+ * Called by hcd init / removal code
+ */
+static struct usb_hcd *ehci_hcd_alloc (void)
+{
+	struct ehci_hcd *ehci;
+
+	ehci = (struct ehci_hcd *)
+		kmalloc (sizeof (struct ehci_hcd), GFP_KERNEL);
+	if (ehci != 0) {
+		memset (ehci, 0, sizeof (struct ehci_hcd));
+		return &ehci->hcd;
+	}
+	return 0;
+}
+
+static void ehci_hcd_free (struct usb_hcd *hcd)
+{
+	kfree (hcd_to_ehci (hcd));
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Allocate the key transfer structures from the previously allocated pool */
+
+static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags)
+{
+	struct ehci_qtd		*qtd;
+	dma_addr_t		dma;
+
+	qtd = pci_pool_alloc (ehci->qtd_pool, flags, &dma);
+	if (qtd != 0) {
+		memset (qtd, 0, sizeof *qtd);
+		qtd->qtd_dma = dma;
+		qtd->hw_next = EHCI_LIST_END;
+		qtd->hw_alt_next = EHCI_LIST_END;
+		INIT_LIST_HEAD (&qtd->qtd_list);
+	}
+	return qtd;
+}
+
+static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
+{
+	pci_pool_free (ehci->qtd_pool, qtd, qtd->qtd_dma);
+}
+
+
+static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
+{
+	struct ehci_qh		*qh;
+	dma_addr_t		dma;
+
+	qh = (struct ehci_qh *)
+		pci_pool_alloc (ehci->qh_pool, flags, &dma);
+	if (qh) {
+		memset (qh, 0, sizeof *qh);
+		atomic_set (&qh->refcount, 1);
+		qh->qh_dma = dma;
+		// INIT_LIST_HEAD (&qh->qh_list);
+		INIT_LIST_HEAD (&qh->qtd_list);
+	}
+	return qh;
+}
+
+/* to share a qh (cpu threads, or hc) */
+static inline struct ehci_qh *qh_put (/* ehci, */ struct ehci_qh *qh)
+{
+	// dbg ("put %p (%d++)", qh, qh->refcount.counter);
+	atomic_inc (&qh->refcount);
+	return qh;
+}
+
+static void qh_unput (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	// dbg ("unput %p (--%d)", qh, qh->refcount.counter);
+	if (!atomic_dec_and_test (&qh->refcount))
+		return;
+	/* clean qtds first, and know this is not linked */
+	if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
+		dbg ("unused qh not empty!");
+		BUG ();
+	}
+	pci_pool_free (ehci->qh_pool, qh, qh->qh_dma);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* The queue heads and transfer descriptors are managed from pools tied 
+ * to each of the "per device" structures.
+ * This is the initialisation and cleanup code.
+ */
+
+static void ehci_mem_cleanup (struct ehci_hcd *ehci)
+{
+	/* PCI consistent memory and pools */
+	if (ehci->qtd_pool)
+		pci_pool_destroy (ehci->qtd_pool);
+	ehci->qtd_pool = 0;
+
+	if (ehci->qh_pool) {
+		pci_pool_destroy (ehci->qh_pool);
+		ehci->qh_pool = 0;
+	}
+
+	if (ehci->itd_pool)
+		pci_pool_destroy (ehci->itd_pool);
+	ehci->itd_pool = 0;
+
+	if (ehci->sitd_pool)
+		pci_pool_destroy (ehci->sitd_pool);
+	ehci->sitd_pool = 0;
+
+	if (ehci->periodic)
+		pci_free_consistent (ehci->hcd.pdev,
+			ehci->periodic_size * sizeof (u32),
+			ehci->periodic, ehci->periodic_dma);
+	ehci->periodic = 0;
+
+	/* shadow periodic table */
+	if (ehci->pshadow)
+		kfree (ehci->pshadow);
+	ehci->pshadow = 0;
+}
+
+/* remember to add cleanup code (above) if you add anything here */
+static int ehci_mem_init (struct ehci_hcd *ehci, int flags)
+{
+	int i;
+
+	/* QTDs for control/bulk/intr transfers */
+	ehci->qtd_pool = pci_pool_create ("ehci_qtd", ehci->hcd.pdev,
+			sizeof (struct ehci_qtd),
+			32 /* byte alignment (for hw parts) */,
+			4096 /* can't cross 4K */,
+			flags);
+	if (!ehci->qtd_pool) {
+		dbg ("no qtd pool");
+		ehci_mem_cleanup (ehci);
+		return -ENOMEM;
+	}
+
+	/* QH for control/bulk/intr transfers */
+	ehci->qh_pool = pci_pool_create ("ehci_qh", ehci->hcd.pdev,
+			sizeof (struct ehci_qh),
+			32 /* byte alignment (for hw parts) */,
+			4096 /* can't cross 4K */,
+			flags);
+	if (!ehci->qh_pool) {
+		dbg ("no qh pool");
+		ehci_mem_cleanup (ehci);
+		return -ENOMEM;
+	}
+
+	/* ITD for high speed ISO transfers */
+	ehci->itd_pool = pci_pool_create ("ehci_itd", ehci->hcd.pdev,
+			sizeof (struct ehci_itd),
+			32 /* byte alignment (for hw parts) */,
+			4096 /* can't cross 4K */,
+			flags);
+	if (!ehci->itd_pool) {
+		dbg ("no itd pool");
+		ehci_mem_cleanup (ehci);
+		return -ENOMEM;
+	}
+
+	/* SITD for full/low speed split ISO transfers */
+	ehci->sitd_pool = pci_pool_create ("ehci_sitd", ehci->hcd.pdev,
+			sizeof (struct ehci_sitd),
+			32 /* byte alignment (for hw parts) */,
+			4096 /* can't cross 4K */,
+			flags);
+	if (!ehci->sitd_pool) {
+		dbg ("no sitd pool");
+		ehci_mem_cleanup (ehci);
+		return -ENOMEM;
+	}
+
+	/* Hardware periodic table */
+	ehci->periodic = (u32 *)
+		pci_alloc_consistent (ehci->hcd.pdev,
+			ehci->periodic_size * sizeof (u32),
+			&ehci->periodic_dma);
+	if (ehci->periodic == 0) {
+		dbg ("no hw periodic table");
+		ehci_mem_cleanup (ehci);
+		return -ENOMEM;
+	}
+	for (i = 0; i < ehci->periodic_size; i++)
+		ehci->periodic [i] = EHCI_LIST_END;
+
+	/* software shadow of hardware table */
+	ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *),
+		flags & ~EHCI_SLAB_FLAGS);
+	if (ehci->pshadow == 0) {
+		dbg ("no shadow periodic table");
+		ehci_mem_cleanup (ehci);
+		return -ENOMEM;
+	}
+	memset (ehci->pshadow, 0, ehci->periodic_size * sizeof (void *));
+
+	return 0;
+}
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/hcd/ehci-q.c linux/drivers/usb/hcd/ehci-q.c
--- v2.5.1/linux/drivers/usb/hcd/ehci-q.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ehci-q.c	Tue Jan  1 13:52:10 2002
@@ -0,0 +1,949 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI hardware queue manipulation
+ *
+ * Control, bulk, and interrupt traffic all use "qh" lists.  They list "qtd"
+ * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned
+ * buffers needed for the larger number).  We use one QH per endpoint, queue
+ * multiple (bulk or control) urbs per endpoint.  URBs may need several qtds.
+ * A scheduled interrupt qh always has one qtd, one urb.
+ *
+ * ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with
+ * interrupts) needs careful scheduling.  Performance improvements can be
+ * an ongoing challenge.
+ * 
+ * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
+ * or otherwise through transaction translators (TTs) in USB 2.0 hubs using
+ * (b) special fields in qh entries or (c) split iso entries.  TTs will
+ * buffer low/full speed data so the host collects it at high speed.
+ */
+
+#ifdef	EHCI_SOFT_RETRIES
+static int soft_retries = EHCI_SOFT_RETRIES;
+MODULE_PARM (soft_retries, "i");
+MODULE_PARM_DESC (soft_retries, "Number of software retries for endpoint i/o");
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* fill a qtd, returning how much of the buffer we were able to queue up */
+
+static int
+qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token)
+{
+	int	i, count;
+
+	/* one buffer entry per 4K ... first might be short or unaligned */
+	qtd->hw_buf [0] = cpu_to_le32 (buf);
+	count = 0x1000 - (buf & 0x0fff);	/* rest of that page */
+	if (likely (len < count))		/* ... iff needed */
+		count = len;
+	else {
+		buf +=  0x1000;
+		buf &= ~0x0fff;
+
+		/* per-qtd limit: from 16K to 20K (best alignment) */
+		for (i = 1; count < len && i < 5; i++) {
+			u64	addr = buf;
+			qtd->hw_buf [i] = cpu_to_le32 ((u32)addr);
+			qtd->hw_buf_hi [i] = cpu_to_le32 ((u32)(addr >> 32));
+			buf += 0x1000;
+			if ((count + 0x1000) < len)
+				count += 0x1000;
+			else
+				count = len;
+		}
+	}
+	qtd->hw_token = cpu_to_le32 ((count << 16) | token);
+	qtd->length = count;
+
+#if 0
+	vdbg ("  qtd_fill %p, token %8x bytes %d dma %x",
+		qtd, le32_to_cpu (qtd->hw_token), count, qtd->hw_buf [0]);
+#endif
+
+	return count;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* update halted (but potentially linked) qh */
+
+static inline void qh_update (struct ehci_qh *qh, struct ehci_qtd *qtd)
+{
+	qh->hw_current = 0;
+	qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma);
+	qh->hw_alt_next = EHCI_LIST_END;
+
+	/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
+	qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline void qtd_copy_status (struct urb *urb, size_t length, u32 token)
+{
+	/* count IN/OUT bytes, not SETUP (even short packets) */
+	if (likely (QTD_PID (token) != 2))
+		urb->actual_length += length - QTD_LENGTH (token);
+
+	/* don't modify error codes */
+	if (unlikely (urb->status == -EINPROGRESS && (token & QTD_STS_HALT))) {
+		if (token & QTD_STS_BABBLE) {
+			urb->status = -EOVERFLOW;
+		} else if (!QTD_CERR (token)) {
+			if (token & QTD_STS_DBE)
+				urb->status = (QTD_PID (token) == 1) /* IN ? */
+					? -ENOSR  /* hc couldn't read data */
+					: -ECOMM; /* hc couldn't write data */
+			else if (token & QTD_STS_MMF)	/* missed tt uframe */
+				urb->status = -EPROTO;
+			else if (token & QTD_STS_XACT) {
+				if (QTD_LENGTH (token))
+					urb->status = -EPIPE;
+				else {
+					dbg ("3strikes");
+					urb->status = -EPROTO;
+				}
+			} else	/* presumably a stall */
+				urb->status = -EPIPE;
+
+		/* CERR nonzero + data left + halt --> stall */
+		} else if (QTD_LENGTH (token))
+			urb->status = -EPIPE;
+		else	/* unknown */
+			urb->status = -EPROTO;
+		dbg ("devpath %s ep %d-%s qtd token %x --> status %d",
+			urb->dev->devpath, usb_pipeendpoint (urb->pipe),
+			usb_pipein (urb->pipe) ? "in" : "out",
+			token, urb->status);
+
+		/* stall indicates some recovery action is needed */
+		if (urb->status == -EPIPE) {
+			int	pipe = urb->pipe;
+
+			if (!usb_pipecontrol (pipe))
+				usb_endpoint_halt (urb->dev,
+					usb_pipeendpoint (pipe),
+					usb_pipeout (pipe));
+			if (urb->dev->tt && !usb_pipeint (pipe)) {
+err ("must CLEAR_TT_BUFFER, hub %s port %d%s addr %d ep %d",
+    urb->dev->tt->hub->devpath, urb->dev->ttport,
+    urb->dev->tt->multi ? "" : " (all-ports TT)",
+    urb->dev->devnum, usb_pipeendpoint (urb->pipe));
+				// FIXME something (khubd?) should make the hub
+				// CLEAR_TT_BUFFER ASAP, it's blocking other
+				// fs/ls requests... hub_tt_clear_buffer() ?
+			}
+		}
+	}
+}
+
+static void ehci_urb_complete (
+	struct ehci_hcd		*ehci,
+	dma_addr_t		addr,
+	struct urb		*urb
+) {
+	if (urb->transfer_buffer_length && usb_pipein (urb->pipe))
+		pci_dma_sync_single (ehci->hcd.pdev, addr,
+			urb->transfer_buffer_length,
+			PCI_DMA_FROMDEVICE);
+
+	/* cleanse status if we saw no error */
+	if (likely (urb->status == -EINPROGRESS)) {
+		if (urb->actual_length != urb->transfer_buffer_length
+				&& (urb->transfer_flags & USB_DISABLE_SPD))
+			urb->status = -EREMOTEIO;
+		else
+			urb->status = 0;
+	}
+
+	/* only report unlinks once */
+	if (likely (urb->status != -ENOENT && urb->status != -ENOTCONN))
+		urb->complete (urb);
+}
+
+/* urb->lock ignored from here on (hcd is done with urb) */
+
+static void ehci_urb_done (
+	struct ehci_hcd		*ehci,
+	dma_addr_t		addr,
+	struct urb		*urb
+) {
+	if (urb->transfer_buffer_length)
+		pci_unmap_single (ehci->hcd.pdev,
+			addr,
+			urb->transfer_buffer_length,
+			usb_pipein (urb->pipe)
+			    ? PCI_DMA_FROMDEVICE
+			    : PCI_DMA_TODEVICE);
+	if (likely (urb->hcpriv != 0)) {
+		qh_unput (ehci, (struct ehci_qh *) urb->hcpriv);
+		urb->hcpriv = 0;
+	}
+
+	if (likely (urb->status == -EINPROGRESS)) {
+		if (urb->actual_length != urb->transfer_buffer_length
+				&& (urb->transfer_flags & USB_DISABLE_SPD))
+			urb->status = -EREMOTEIO;
+		else
+			urb->status = 0;
+	}
+
+	/* hand off urb ownership */
+	usb_hcd_giveback_urb (&ehci->hcd, urb);
+}
+
+
+/*
+ * Process completed qtds for a qh, issuing completions if needed.
+ * When freeing:  frees qtds, unmaps buf, returns URB to driver.
+ * When not freeing (queued periodic qh):  retain qtds, mapping, and urb.
+ * Races up to qh->hw_current; returns number of urb completions.
+ */
+static int
+qh_completions (
+	struct ehci_hcd		*ehci,
+	struct list_head	*qtd_list,
+	int			freeing
+) {
+	struct ehci_qtd		*qtd = 0;
+	struct list_head	*next = 0;
+	u32			token;
+	struct ehci_qh		*qh = 0;
+	struct urb		*urb = 0;
+	int			halted = 0;
+	unsigned long		flags;
+	int			retval = 0;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	if (unlikely (list_empty (qtd_list))) {
+		spin_unlock_irqrestore (&ehci->lock, flags);
+		return retval;
+	}
+
+	for (qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
+			next != qtd_list;
+			qtd = list_entry (next, struct ehci_qtd, qtd_list)) {
+		token = le32_to_cpu (qtd->hw_token);
+		if (!qh) {
+			urb = qtd->urb;
+			qh = (struct ehci_qh *) urb->hcpriv;
+		}
+		if (likely (qh != 0)) {
+			halted = halted
+				|| (ehci->hcd.state == USB_STATE_HALT)
+				|| (qh->qh_state == QH_STATE_IDLE);
+
+			if (unlikely ((token & QTD_STS_HALT) != 0)) {
+#ifdef	EHCI_SOFT_RETRIES
+				/* extra soft retries for protocol errors */
+				if (!halted
+						&& qh->retries < soft_retries
+						&& (QTD_STS_HALT|QTD_STS_XACT)
+							== (token & 0xff)
+						&& QTD_CERR (token) == 0) {
+					if (qh->retries == 0)
+						dbg ("soft retry, qh %p qtd %p",
+							qh, qtd);
+					qh->retries++;
+					token &= ~0x0ff;
+					token |= QTD_STS_ACTIVE;
+					token |= (EHCI_TUNE_CERR << 10);
+					/* qtd update not needed */
+					qh->hw_token = cpu_to_le32 (token);
+					spin_unlock_irqrestore (&ehci->lock,
+						flags);
+					return;
+
+				} else if (qh->retries >= soft_retries
+						&& soft_retries) {
+					dbg ("retried %d times, qh %p qtd %p",
+						qh->retries, qh, qtd);
+				}
+#endif	/* EHCI_SOFT_RETRIES */
+				halted = 1;
+			}
+
+			if (unlikely ((token & QTD_STS_ACTIVE) != 0)) {
+				/* stop scan if qtd is visible to the HC */
+				if (!halted) {
+					urb = 0;
+					break;
+				}
+
+				/* continue cleanup if HC is halted */
+				if (ehci->hcd.state == USB_STATE_HALT) {
+					urb->status = -ESHUTDOWN;
+					goto scrub;
+				}
+
+				/* stall? some other urb was unlinked? */
+				if (urb->status == -EINPROGRESS) {
+dbg ("?why? qh %p, qtd %p halted, urb %p, token %8x, len %d",
+	qh, qtd, urb, token, urb->actual_length);
+spin_unlock_irqrestore (&ehci->lock, flags);
+return retval;
+	    /*
+	     * FIXME: write this code.  When one queued urb is unlinked,
+	     * unlink every succeeding urb.
+	     */
+					continue;
+				}
+
+				/* else stopped for some other reason */
+			} 
+scrub:
+			spin_lock (&urb->lock);
+			qtd_copy_status (urb, qtd->length, token);
+			spin_unlock (&urb->lock);
+		}
+		next = qtd->qtd_list.next;
+
+		/*
+		 * NOTE:  this won't work right with interrupt urbs that
+		 * need multiple qtds ... only the first scan of qh->qtd_list
+		 * starts at the right qtd, yet multiple scans could happen
+		 * for transfers that are scheduled across multiple uframes. 
+		 */
+		if (likely (freeing != 0))
+			list_del (&qtd->qtd_list);
+		else {
+			/* restore everything the HC could change
+			 * from an interrupt QTD
+			 */
+			qtd->hw_token = (qtd->hw_token
+					& ~__constant_cpu_to_le32 (0x8300))
+				| cpu_to_le32 (qtd->length << 16)
+				| __constant_cpu_to_le32 (QTD_IOC
+					| (EHCI_TUNE_CERR << 10)
+					| QTD_STS_ACTIVE);
+			qtd->hw_buf [0] &= ~__constant_cpu_to_le32 (0x0fff);
+
+			/* this offset, and the length above,
+			 * are likely wrong on QTDs #2..N
+			 */
+			qtd->hw_buf [0] |= cpu_to_le32 (0x0fff & qtd->buf_dma);
+		}
+
+		spin_unlock_irqrestore (&ehci->lock, flags);
+
+#if 0
+		if (urb->status == -EINPROGRESS)
+			vdbg ("  qtd %p ok, urb %p, token %8x, len %d",
+				qtd, urb, token, urb->actual_length);
+		else
+			vdbg ("urb %p status %d, qtd %p, token %8x, len %d",
+				urb, urb->status, qtd, token,
+				urb->actual_length);
+#endif
+
+		/* SETUP for control urb? */
+		if (unlikely (QTD_PID (token) == 2))
+			pci_unmap_single (ehci->hcd.pdev,
+				qtd->buf_dma, sizeof (devrequest),
+				PCI_DMA_TODEVICE);
+
+		/* another queued urb? */
+		if (unlikely (qtd->urb != urb)) {
+			if (likely (freeing != 0))
+				ehci_urb_done (ehci, qtd->buf_dma, urb);
+			else
+				ehci_urb_complete (ehci, qtd->buf_dma, urb);
+			retval++;
+			urb = qtd->urb;
+		}
+
+		if (likely (freeing != 0))
+			ehci_qtd_free (ehci, qtd);
+		spin_lock_irqsave (&ehci->lock, flags);
+		qtd = list_entry (next, struct ehci_qtd, qtd_list);
+	}
+
+	/* patch up list head? */
+	if (unlikely (halted && qh && !list_empty (qtd_list))) {
+		qh_update (qh, list_entry (qtd_list->next,
+				struct ehci_qtd, qtd_list));
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+
+	/* last urb's completion might still need calling */
+	if (likely (qtd && urb)) {
+		if (likely (freeing != 0))
+			ehci_urb_done (ehci, qtd->buf_dma, urb);
+		else
+			ehci_urb_complete (ehci, qtd->buf_dma, urb);
+		retval++;
+	}
+	return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * create a list of filled qtds for this URB; won't link into qh.
+ */
+static struct list_head *
+qh_urb_transaction (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*head,
+	int			flags
+) {
+	struct ehci_qtd		*qtd, *qtd_prev;
+	dma_addr_t		buf, map_buf;
+	int			len, maxpacket;
+	u32			token;
+
+	/*
+	 * URBs map to sequences of QTDs:  one logical transaction
+	 */
+	qtd = ehci_qtd_alloc (ehci, flags);
+	if (unlikely (!qtd))
+		return 0;
+	qtd_prev = 0;
+	list_add_tail (&qtd->qtd_list, head);
+	qtd->urb = urb;
+
+	token = QTD_STS_ACTIVE;
+	token |= (EHCI_TUNE_CERR << 10);
+	/* for split transactions, SplitXState initialized to zero */
+
+	if (usb_pipecontrol (urb->pipe)) {
+		/* control request data is passed in the "setup" pid */
+
+		/* NOTE:  this isn't smart about 64bit DMA, since it uses the
+		 * default (32bit) mask rather than using the whole address
+		 * space.  we could set pdev->dma_mask to all-ones while
+		 * getting this mapping, locking it and restoring before
+		 * allocating qtd/qh/... or maybe only do that for the main
+		 * data phase (below).
+		 */
+		qtd->buf_dma = pci_map_single (
+					ehci->hcd.pdev,
+					urb->setup_packet,
+					sizeof (devrequest),
+					PCI_DMA_TODEVICE);
+		if (unlikely (!qtd->buf_dma))
+			goto cleanup;
+
+		/* SETUP pid */
+		qtd_fill (qtd, qtd->buf_dma, sizeof (devrequest),
+			token | (2 /* "setup" */ << 8));
+
+		/* ... and always at least one more pid */
+		token ^= QTD_TOGGLE;
+		qtd_prev = qtd;
+		qtd = ehci_qtd_alloc (ehci, flags);
+		if (unlikely (!qtd))
+			goto cleanup;
+		qtd->urb = urb;
+		qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+		list_add_tail (&qtd->qtd_list, head);
+	} 
+
+	/*
+	 * data transfer stage:  buffer setup
+	 */
+	len = urb->transfer_buffer_length;
+	if (likely (len > 0)) {
+		/* NOTE:  sub-optimal mapping with 64bit DMA (see above) */
+		buf = map_buf = pci_map_single (ehci->hcd.pdev,
+			urb->transfer_buffer, len,
+			usb_pipein (urb->pipe)
+			    ? PCI_DMA_FROMDEVICE
+			    : PCI_DMA_TODEVICE);
+		if (unlikely (!buf))
+			goto cleanup;
+	} else
+		buf = map_buf = 0;
+
+	if (!buf || usb_pipein (urb->pipe))
+		token |= (1 /* "in" */ << 8);
+	/* else it's already initted to "out" pid (0 << 8) */
+
+	maxpacket = usb_maxpacket (urb->dev, urb->pipe,
+			usb_pipeout (urb->pipe));
+
+	/*
+	 * buffer gets wrapped in one or more qtds;
+	 * last one may be "short" (including zero len)
+	 * and may serve as a control status ack
+	 */
+	for (;;) {
+		int this_qtd_len;
+
+		qtd->urb = urb;
+		qtd->buf_dma = map_buf;
+		this_qtd_len = qtd_fill (qtd, buf, len, token);
+		len -= this_qtd_len;
+		buf += this_qtd_len;
+
+		/* qh makes control packets use qtd toggle; maybe switch it */
+		if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
+			token ^= QTD_TOGGLE;
+
+		if (likely (len <= 0))
+			break;
+
+		qtd_prev = qtd;
+		qtd = ehci_qtd_alloc (ehci, flags);
+		if (unlikely (!qtd))
+			goto cleanup;
+		qtd->urb = urb;
+		qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+		list_add_tail (&qtd->qtd_list, head);
+	}
+
+	/*
+	 * control requests may need a terminating data "status" ack;
+	 * bulk ones may need a terminating short packet (zero length).
+	 */
+	if (likely (buf != 0)) {
+		int	one_more = 0;
+
+		if (usb_pipecontrol (urb->pipe)) {
+			one_more = 1;
+			token ^= 0x0100;	/* "in" <--> "out"  */
+			token |= QTD_TOGGLE;	/* force DATA1 */
+		} else if (usb_pipebulk (urb->pipe)
+				&& (urb->transfer_flags & USB_ZERO_PACKET)
+				&& !(urb->transfer_buffer_length % maxpacket)) {
+			one_more = 1;
+		}
+		if (one_more) {
+			qtd_prev = qtd;
+			qtd = ehci_qtd_alloc (ehci, flags);
+			if (unlikely (!qtd))
+				goto cleanup;
+			qtd->urb = urb;
+			qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+			list_add_tail (&qtd->qtd_list, head);
+
+			/* never any data in such packets */
+			qtd_fill (qtd, 0, 0, token);
+		}
+	}
+
+	/* by default, enable interrupt on urb completion */
+	if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
+		qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC);
+	return head;
+
+cleanup:
+	urb->status = -ENOMEM;
+	qh_completions (ehci, head, 1);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Hardware maintains data toggle (like OHCI) ... here we (re)initialize
+ * the hardware data toggle in the QH, and set the pseudo-toggle in udev
+ * so we can see if usb_clear_halt() was called.  NOP for control, since
+ * we set up qh->hw_info1 to always use the QTD toggle bits. 
+ */
+static inline void
+clear_toggle (struct usb_device *udev, int ep, int is_out, struct ehci_qh *qh)
+{
+	vdbg ("clear toggle, dev %d ep 0x%x-%s",
+		udev->devnum, ep, is_out ? "out" : "in");
+	qh->hw_token &= ~__constant_cpu_to_le32 (QTD_TOGGLE);
+	usb_settoggle (udev, ep, is_out, 1);
+}
+
+// Would be best to create all qh's from config descriptors,
+// when each interface/altsetting is established.  Unlink
+// any previous qh and cancel its urbs first; endpoints are
+// implicitly reset then (data toggle too).
+// That'd mean updating how usbcore talks to HCDs. (2.5?)
+
+
+/*
+ * Each QH holds a qtd list; a QH is used for everything except iso.
+ *
+ * For interrupt urbs, the scheduler must set the microframe scheduling
+ * mask(s) each time the QH gets scheduled.  For highspeed, that's
+ * just one microframe in the s-mask.  For split interrupt transactions
+ * there are additional complications: c-mask, maybe FSTNs.
+ */
+static struct ehci_qh *
+ehci_qh_make (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	int			flags
+) {
+	struct ehci_qh		*qh = ehci_qh_alloc (ehci, flags);
+	u32			info1 = 0, info2 = 0;
+
+	if (!qh)
+		return qh;
+
+	/*
+	 * init endpoint/device data for this QH
+	 */
+	info1 |= usb_pipeendpoint (urb->pipe) << 8;
+	info1 |= usb_pipedevice (urb->pipe) << 0;
+
+	/* using TT? */
+	switch (urb->dev->speed) {
+	case USB_SPEED_LOW:
+		info1 |= (1 << 12);	/* EPS "low" */
+		/* FALL THROUGH */
+
+	case USB_SPEED_FULL:
+		/* EPS 0 means "full" */
+		info1 |= (EHCI_TUNE_RL_TT << 28);
+		if (usb_pipecontrol (urb->pipe)) {
+			info1 |= (1 << 27);	/* for TT */
+			info1 |= 1 << 14;	/* toggle from qtd */
+		}
+		info1 |= usb_maxpacket (urb->dev, urb->pipe,
+					usb_pipeout (urb->pipe)) << 16;
+
+		info2 |= (EHCI_TUNE_MULT_TT << 30);
+		info2 |= urb->dev->ttport << 23;
+		info2 |= urb->dev->tt->hub->devnum << 16;
+
+		/* NOTE:  if (usb_pipeint (urb->pipe)) { scheduler sets c-mask }
+		 * ... and a 0.96 scheduler might use FSTN nodes too
+		 */
+		break;
+
+	case USB_SPEED_HIGH:		/* no TT involved */
+		info1 |= (2 << 12);	/* EPS "high" */
+		info1 |= (EHCI_TUNE_RL_HS << 28);
+		if (usb_pipecontrol (urb->pipe)) {
+			info1 |= 64 << 16;	/* usb2 fixed maxpacket */
+			info1 |= 1 << 14;	/* toggle from qtd */
+		} else if (usb_pipebulk (urb->pipe)) {
+			info1 |= 512 << 16;	/* usb2 fixed maxpacket */
+			info2 |= (EHCI_TUNE_MULT_HS << 30);
+		} else
+			info1 |= usb_maxpacket (urb->dev, urb->pipe,
+						usb_pipeout (urb->pipe)) << 16;
+		break;
+	default:
+#ifdef DEBUG
+		BUG ();
+#endif
+	}
+
+	/* NOTE:  if (usb_pipeint (urb->pipe)) { scheduler sets s-mask } */
+
+	qh->qh_state = QH_STATE_IDLE;
+	qh->hw_info1 = cpu_to_le32 (info1);
+	qh->hw_info2 = cpu_to_le32 (info2);
+
+	/* initialize sw and hw queues with these qtds */
+	list_splice (qtd_list, &qh->qtd_list);
+	qh_update (qh, list_entry (qtd_list->next, struct ehci_qtd, qtd_list));
+
+	/* initialize data toggle state */
+	if (!usb_pipecontrol (urb->pipe))
+		clear_toggle (urb->dev,
+			usb_pipeendpoint (urb->pipe),
+			usb_pipeout (urb->pipe),
+			qh);
+
+	return qh;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* move qh (and its qtds) onto async queue; maybe enable queue.  */
+
+static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	u32		dma = QH_NEXT (qh->qh_dma);
+	struct ehci_qh	*q;
+
+	if (unlikely (!(q = ehci->async))) {
+		u32	cmd = readl (&ehci->regs->command);
+
+		/* in case a clear of CMD_ASE didn't take yet */
+		while (readl (&ehci->regs->status) & STS_ASS)
+			udelay (100);
+
+		qh->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD); /* [4.8] */
+		qh->qh_next.qh = qh;
+		qh->hw_next = dma;
+		ehci->async = qh;
+		writel ((u32)qh->qh_dma, &ehci->regs->async_next);
+		cmd |= CMD_ASE | CMD_RUN;
+		writel (cmd, &ehci->regs->command);
+		ehci->hcd.state = USB_STATE_RUNNING;
+		/* posted write need not be known to HC yet ... */
+	} else {
+		/* splice right after "start" of ring */
+		qh->hw_info1 &= ~__constant_cpu_to_le32 (QH_HEAD); /* [4.8] */
+		qh->qh_next = q->qh_next;
+		qh->hw_next = q->hw_next;
+		q->qh_next.qh = qh;
+		q->hw_next = dma;
+	}
+	qh->qh_state = QH_STATE_LINKED;
+	/* qtd completions reported later by interrupt */
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+submit_async (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	int			mem_flags
+) {
+	struct ehci_qtd		*qtd;
+	struct hcd_dev		*dev;
+	int			epnum;
+	unsigned long		flags;
+	struct ehci_qh		*qh = 0;
+
+	qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
+	dev = (struct hcd_dev *)urb->dev->hcpriv;
+	epnum = usb_pipeendpoint (urb->pipe);
+	if (usb_pipein (urb->pipe))
+		epnum |= 0x10;
+
+	vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]",
+		ehci->hcd.bus_name, urb, urb->transfer_buffer_length,
+		epnum & 0x0f, (epnum & 0x10) ? "in" : "out",
+		qtd, dev ? dev->ep [epnum] : (void *)~0);
+
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	qh = (struct ehci_qh *) dev->ep [epnum];
+	if (likely (qh != 0)) {
+		u32	hw_next = QTD_NEXT (qtd->qtd_dma);
+
+		/* maybe patch the qh used for set_address */
+		if (unlikely (epnum == 0
+				&& le32_to_cpu (qh->hw_info1 & 0x7f) == 0))
+			qh->hw_info1 |= cpu_to_le32 (usb_pipedevice(urb->pipe));
+
+		/* is an URB is queued to this qh already? */
+		if (unlikely (!list_empty (&qh->qtd_list))) {
+			struct ehci_qtd		*last_qtd;
+
+			// dbg_qh ("non-empty qh", ehci, qh);
+			last_qtd = list_entry (qh->qtd_list.prev,
+					struct ehci_qtd, qtd_list);
+			last_qtd->hw_next = hw_next;
+
+			/* previous urb allows short rx? maybe optimize. */
+			if (!(last_qtd->urb->transfer_flags & USB_DISABLE_SPD)
+					&& (epnum & 0x10)) {
+				// only the last QTD for now
+				last_qtd->hw_alt_next = hw_next;
+			}
+
+		/* no URB queued */
+		} else {
+			// dbg_qh ("empty qh", ehci, qh);
+
+// FIXME:  how handle usb_clear_halt() for an EP with queued URBs?
+// usbcore may not let us handle that cleanly...
+// likely must cancel them all first!
+
+			/* usb_clear_halt() means qh data toggle gets reset */
+			if (usb_pipebulk (urb->pipe)
+					&& unlikely (!usb_gettoggle (urb->dev,
+						(epnum & 0x0f),
+						!(epnum & 0x10)))) {
+				clear_toggle (urb->dev,
+					epnum & 0x0f, !(epnum & 0x10), qh);
+			}
+			qh_update (qh, qtd);
+		}
+		list_splice (qtd_list, qh->qtd_list.prev);
+
+	} else {
+		/* can't sleep here, we have ehci->lock... */
+		qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC);
+		if (likely (qh != 0)) {
+			// dbg_qh ("new qh", ehci, qh);
+			dev->ep [epnum] = qh;
+		} else
+			urb->status = -ENOMEM;
+	}
+
+	/* Control/bulk operations through TTs don't need scheduling,
+	 * the HC and TT handle it when the TT has a buffer ready.
+	 */
+	if (likely (qh != 0)) {
+		urb->hcpriv = qh_put (qh);
+		if (likely (qh->qh_state == QH_STATE_IDLE))
+			qh_link_async (ehci, qh_put (qh));
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	if (unlikely (!qh))
+		qh_completions (ehci, qtd_list, 1);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* the async qh for the qtds being reclaimed are now unlinked from the HC */
+/* caller must not own ehci->lock */
+
+static void end_unlink_async (struct ehci_hcd *ehci)
+{
+	struct ehci_qh		*qh = ehci->reclaim;
+
+	qh->qh_state = QH_STATE_IDLE;
+	qh->qh_next.qh = 0;
+	qh_unput (ehci, qh);			// refcount from reclaim 
+	ehci->reclaim = 0;
+	ehci->reclaim_ready = 0;
+
+	qh_completions (ehci, &qh->qtd_list, 1);
+
+	// FIXME unlink any urb should unlink all following urbs,
+	// so that this will never happen
+	if (!list_empty (&qh->qtd_list)
+			&& HCD_IS_RUNNING (ehci->hcd.state))
+		qh_link_async (ehci, qh);
+	else
+		qh_unput (ehci, qh);		// refcount from async list
+}
+
+
+/* makes sure the async qh will become idle */
+/* caller must own ehci->lock */
+
+static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	int		cmd = readl (&ehci->regs->command);
+	struct ehci_qh	*prev;
+
+#ifdef DEBUG
+	if (ehci->reclaim
+			|| !ehci->async
+			|| qh->qh_state != QH_STATE_LINKED
+#ifdef CONFIG_SMP
+// this macro lies except on SMP compiles
+			|| !spin_is_locked (&ehci->lock)
+#endif
+			)
+		BUG ();
+#endif
+
+	qh->qh_state = QH_STATE_UNLINK;
+	ehci->reclaim = qh = qh_put (qh);
+
+	// dbg_qh ("start unlink", ehci, qh);
+
+	/* Remove the last QH (qhead)?  Stop async schedule first. */
+	if (unlikely (qh == ehci->async && qh->qh_next.qh == qh)) {
+		/* can't get here without STS_ASS set */
+		if (ehci->hcd.state != USB_STATE_HALT) {
+			if (cmd & CMD_PSE)
+				writel (cmd & __constant_cpu_to_le32 (~CMD_ASE),
+					&ehci->regs->command);
+			else {
+				ehci_ready (ehci);
+				while (!(readl (&ehci->regs->status) & STS_ASS))
+					udelay (100);
+			}
+		}
+		qh->qh_next.qh = ehci->async = 0;
+
+		ehci->reclaim_ready = 1;
+		tasklet_schedule (&ehci->tasklet);
+		return;
+	} 
+
+	if (unlikely (ehci->hcd.state == USB_STATE_HALT)) {
+		ehci->reclaim_ready = 1;
+		tasklet_schedule (&ehci->tasklet);
+		return;
+	}
+
+	prev = ehci->async;
+	while (prev->qh_next.qh != qh && prev->qh_next.qh != ehci->async)
+		prev = prev->qh_next.qh;
+#ifdef DEBUG
+	if (prev->qh_next.qh != qh)
+		BUG ();
+#endif
+
+	if (qh->hw_info1 & __constant_cpu_to_le32 (QH_HEAD)) {
+		ehci->async = prev;
+		prev->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD);
+	}
+	prev->hw_next = qh->hw_next;
+	prev->qh_next = qh->qh_next;
+
+	ehci->reclaim_ready = 0;
+	cmd |= CMD_IAAD;
+	writel (cmd, &ehci->regs->command);
+	/* posted write need not be known to HC yet ... */
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void scan_async (struct ehci_hcd *ehci)
+{
+	struct ehci_qh		*qh;
+	unsigned long		flags;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+rescan:
+	qh = ehci->async;
+	if (likely (qh != 0)) {
+		do {
+			/* clean any finished work for this qh */
+			if (!list_empty (&qh->qtd_list)) {
+				// dbg_qh ("scan_async", ehci, qh);
+				qh = qh_put (qh);
+				spin_unlock_irqrestore (&ehci->lock, flags);
+
+				/* concurrent unlink could happen here */
+				qh_completions (ehci, &qh->qtd_list, 1);
+
+				spin_lock_irqsave (&ehci->lock, flags);
+				qh_unput (ehci, qh);
+			}
+
+			/* unlink idle entries (reduces PCI usage) */
+			if (list_empty (&qh->qtd_list) && !ehci->reclaim) {
+				if (qh->qh_next.qh != qh) {
+					// dbg ("irq/empty");
+					start_unlink_async (ehci, qh);
+				} else {
+					// FIXME:  arrange to stop
+					// after it's been idle a while.
+				}
+			}
+			qh = qh->qh_next.qh;
+			if (!qh)		/* unlinked? */
+				goto rescan;
+		} while (qh != ehci->async);
+	}
+
+	spin_unlock_irqrestore (&ehci->lock, flags);
+}
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/hcd/ehci-sched.c linux/drivers/usb/hcd/ehci-sched.c
--- v2.5.1/linux/drivers/usb/hcd/ehci-sched.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ehci-sched.c	Tue Jan  1 13:52:10 2002
@@ -0,0 +1,1053 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI scheduled transaction support:  interrupt, iso, split iso
+ * These are called "periodic" transactions in the EHCI spec.
+ */
+
+/*
+ * Ceiling microseconds (typical) for that many bytes at high speed
+ * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
+ * to preallocate bandwidth)
+ */
+#define EHCI_HOST_DELAY	5	/* nsec, guess */
+#define HS_USECS(bytes) NS_TO_US ( ((55 * 8 * 2083)/1000) \
+	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
+	+ EHCI_HOST_DELAY)
+#define HS_USECS_ISO(bytes) NS_TO_US ( ((long)(38 * 8 * 2.083)) \
+	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
+	+ EHCI_HOST_DELAY)
+	
+static int ehci_get_frame (struct usb_hcd *hcd);
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * periodic_next_shadow - return "next" pointer on shadow list
+ * @periodic: host pointer to qh/itd/sitd
+ * @tag: hardware tag for type of this record
+ */
+static union ehci_shadow *
+periodic_next_shadow (union ehci_shadow *periodic, int tag)
+{
+	switch (tag) {
+	case Q_TYPE_QH:
+		return &periodic->qh->qh_next;
+	case Q_TYPE_FSTN:
+		return &periodic->fstn->fstn_next;
+#ifdef have_iso
+	case Q_TYPE_ITD:
+		return &periodic->itd->itd_next;
+	case Q_TYPE_SITD:
+		return &periodic->sitd->sitd_next;
+#endif /* have_iso */
+	}
+	dbg ("BAD shadow %p tag %d", periodic->ptr, tag);
+	// BUG ();
+	return 0;
+}
+
+/* returns true after successful unlink */
+/* caller must hold ehci->lock */
+static int periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
+{
+	union ehci_shadow	*prev_p = &ehci->pshadow [frame];
+	u32			*hw_p = &ehci->periodic [frame];
+	union ehci_shadow	here = *prev_p;
+	union ehci_shadow	*next_p;
+
+	/* find predecessor of "ptr"; hw and shadow lists are in sync */
+	while (here.ptr && here.ptr != ptr) {
+		prev_p = periodic_next_shadow (prev_p, Q_NEXT_TYPE (*hw_p));
+		hw_p = &here.qh->hw_next;
+		here = *prev_p;
+	}
+	/* an interrupt entry (at list end) could have been shared */
+	if (!here.ptr) {
+		dbg ("entry %p no longer on frame [%d]", ptr, frame);
+		return 0;
+	}
+	// vdbg ("periodic unlink %p from frame %d", ptr, frame);
+
+	/* update hardware list ... HC may still know the old structure, so
+	 * don't change hw_next until it'll have purged its cache
+	 */
+	next_p = periodic_next_shadow (&here, Q_NEXT_TYPE (*hw_p));
+	*hw_p = here.qh->hw_next;
+
+	/* unlink from shadow list; HCD won't see old structure again */
+	*prev_p = *next_p;
+	next_p->ptr = 0;
+
+	return 1;
+}
+
+/* how many of the uframe's 125 usecs are allocated? */
+static unsigned short
+periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
+{
+	u32			*hw_p = &ehci->periodic [frame];
+	union ehci_shadow	*q = &ehci->pshadow [frame];
+	unsigned		usecs = 0;
+#ifdef have_iso
+	u32			temp = 0;
+#endif
+
+	while (q->ptr) {
+		switch (Q_NEXT_TYPE (*hw_p)) {
+		case Q_TYPE_QH:
+			/* is it in the S-mask? */
+			if (q->qh->hw_info2 & cpu_to_le32 (1 << uframe))
+				usecs += q->qh->usecs;
+			q = &q->qh->qh_next;
+			break;
+		case Q_TYPE_FSTN:
+			/* for "save place" FSTNs, count the relevant INTR
+			 * bandwidth from the previous frame
+			 */
+			if (q->fstn->hw_prev != EHCI_LIST_END) {
+				dbg ("not counting FSTN bandwidth yet ...");
+			}
+			q = &q->fstn->fstn_next;
+			break;
+#ifdef have_iso
+		case Q_TYPE_ITD:
+			temp = le32_to_cpu (q->itd->transaction [uframe]);
+			temp >>= 16;
+			temp &= 0x0fff;
+			if (temp)
+				usecs += HS_USECS_ISO (temp);
+			q = &q->itd->itd_next;
+			break;
+		case Q_TYPE_SITD:
+			temp = q->sitd->hw_fullspeed_ep &
+				__constant_cpu_to_le32 (1 << 31);
+
+			// FIXME:  this doesn't count data bytes right...
+
+			/* is it in the S-mask?  (count SPLIT, DATA) */
+			if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) {
+				if (temp)
+					usecs += HS_USECS (188);
+				else
+					usecs += HS_USECS (1);
+			}
+
+			/* ... C-mask?  (count CSPLIT, DATA) */
+			if (q->sitd->hw_uframe &
+					cpu_to_le32 (1 << (8 + uframe))) {
+				if (temp)
+					usecs += HS_USECS (0);
+				else
+					usecs += HS_USECS (188);
+			}
+			q = &q->sitd->sitd_next;
+			break;
+#endif /* have_iso */
+		default:
+			BUG ();
+		}
+	}
+#ifdef	DEBUG
+	if (usecs > 100)
+		err ("overallocated uframe %d, periodic is %d usecs",
+			frame * 8 + uframe, usecs);
+#endif
+	return usecs;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void intr_deschedule (
+	struct ehci_hcd	*ehci,
+	unsigned	frame,
+	struct ehci_qh	*qh,
+	unsigned	period
+) {
+	unsigned long	flags;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	do {
+		periodic_unlink (ehci, frame, qh);
+		qh_unput (ehci, qh);
+		frame += period;
+	} while (frame < ehci->periodic_size);
+
+	qh->qh_state = QH_STATE_UNLINK;
+	qh->qh_next.ptr = 0;
+	ehci->periodic_urbs--;
+
+	/* maybe turn off periodic schedule */
+	if (!ehci->periodic_urbs) {
+		u32	cmd = readl (&ehci->regs->command);
+
+		/* did setting PSE not take effect yet?
+		 * takes effect only at frame boundaries...
+		 */
+		while (!(readl (&ehci->regs->status) & STS_PSS))
+			udelay (20);
+
+		cmd &= ~CMD_PSE;
+		writel (cmd, &ehci->regs->command);
+		/* posted write ... */
+
+		ehci->next_frame = -1;
+	} else
+		vdbg ("periodic schedule still enabled");
+
+	spin_unlock_irqrestore (&ehci->lock, flags);
+
+	/*
+	 * If the hc may be looking at this qh, then delay a uframe
+	 * (yeech!) to be sure it's done.
+	 * No other threads may be mucking with this qh.
+	 */
+	if (((ehci_get_frame (&ehci->hcd) - frame) % period) == 0)
+		udelay (125);
+
+	qh->qh_state = QH_STATE_IDLE;
+	qh->hw_next = EHCI_LIST_END;
+
+	vdbg ("descheduled qh %p, per = %d frame = %d count = %d, urbs = %d",
+		qh, period, frame,
+		atomic_read (&qh->refcount), ehci->periodic_urbs);
+}
+
+static int intr_submit (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	int			mem_flags
+) {
+	unsigned		epnum, period;
+	unsigned		temp;
+	unsigned short		mult, usecs;
+	unsigned long		flags;
+	struct ehci_qh		*qh;
+	struct hcd_dev		*dev;
+	int			status = 0;
+
+	/* get endpoint and transfer data */
+	epnum = usb_pipeendpoint (urb->pipe);
+	if (usb_pipein (urb->pipe)) {
+		temp = urb->dev->epmaxpacketin [epnum];
+		epnum |= 0x10;
+	} else
+		temp = urb->dev->epmaxpacketout [epnum];
+	mult = 1;
+	if (urb->dev->speed == USB_SPEED_HIGH) {
+		/* high speed "high bandwidth" is coded in ep maxpacket */
+		mult += (temp >> 11) & 0x03;
+		temp &= 0x03ff;
+	} else {
+		dbg ("no intr/tt scheduling yet"); 
+		status = -ENOSYS;
+		goto done;
+	}
+
+	/*
+	 * NOTE: current completion/restart logic doesn't handle more than
+	 * one qtd in a periodic qh ... 16-20 KB/urb is pretty big for this.
+	 * such big requests need many periods to transfer.
+	 */
+	if (unlikely (qtd_list->next != qtd_list->prev)) {
+		dbg ("only one intr qtd per urb allowed"); 
+		status = -EINVAL;
+		goto done;
+	}
+
+	usecs = HS_USECS (urb->transfer_buffer_length);
+
+	/*
+	 * force a power-of-two (frames) sized polling interval
+	 *
+	 * NOTE: endpoint->bInterval for highspeed is measured in uframes,
+	 * while for full/low speeds it's in frames.  Here we "know" that
+	 * urb->interval doesn't give acccess to high interrupt rates.
+	 */
+	period = ehci->periodic_size;
+	temp = period;
+	if (unlikely (urb->interval < 1))
+		urb->interval = 1;
+	while (temp > urb->interval)
+		temp >>= 1;
+	period = urb->interval = temp;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	/* get the qh (must be empty and idle) */
+	dev = (struct hcd_dev *)urb->dev->hcpriv;
+	qh = (struct ehci_qh *) dev->ep [epnum];
+	if (qh) {
+		/* only allow one queued interrupt urb per EP */
+		if (unlikely (qh->qh_state != QH_STATE_IDLE
+				|| !list_empty (&qh->qtd_list))) {
+			dbg ("interrupt urb already queued");
+			status = -EBUSY;
+		} else {
+			/* maybe reset hardware's data toggle in the qh */
+			if (unlikely (!usb_gettoggle (urb->dev, epnum & 0x0f,
+					!(epnum & 0x10)))) {
+				qh->hw_token |=
+					__constant_cpu_to_le32 (QTD_TOGGLE);
+				usb_settoggle (urb->dev, epnum & 0x0f,
+					!(epnum & 0x10), 1);
+			}
+			/* trust the QH was set up as interrupt ... */
+			list_splice (qtd_list, &qh->qtd_list);
+			qh_update (qh, list_entry (qtd_list->next,
+						struct ehci_qtd, qtd_list));
+		}
+	} else {
+		/* can't sleep here, we have ehci->lock... */
+		qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC);
+		qtd_list = &qh->qtd_list;
+		if (likely (qh != 0)) {
+			// dbg ("new INTR qh %p", qh);
+			dev->ep [epnum] = qh;
+		} else
+			status = -ENOMEM;
+	}
+
+	/* Schedule this periodic QH. */
+	if (likely (status == 0)) {
+		unsigned	frame = urb->interval;
+
+		qh->hw_next = EHCI_LIST_END;
+		qh->hw_info2 |= cpu_to_le32 (mult << 30);
+		qh->usecs = usecs;
+
+		urb->hcpriv = qh_put (qh);
+		status = -ENOSPC;
+
+		/* pick a set of schedule slots, link the QH into them */
+		do {
+			int	uframe;
+
+			/* Select some frame 0..(urb->interval - 1) with a
+			 * microframe that can hold this transaction.
+			 *
+			 * FIXME for TT splits, need uframes for start and end.
+			 * FSTNs can put end into next frame (uframes 0 or 1).
+			 */
+			frame--;
+			for (uframe = 0; uframe < 8; uframe++) {
+				int	claimed;
+				claimed = periodic_usecs (ehci, frame, uframe);
+				/* 80% periodic == 100 usec max committed */
+				if ((claimed + usecs) <= 100) {
+					vdbg ("frame %d.%d: %d usecs, plus %d",
+						frame, uframe, claimed, usecs);
+					break;
+				}
+			}
+			if (uframe == 8)
+				continue;
+// FIXME delete when code below handles non-empty queues
+			if (ehci->pshadow [frame].ptr)
+				continue;
+
+			/* QH will run once each period, starting there  */
+			urb->start_frame = frame;
+			status = 0;
+
+			/* set S-frame mask */
+			qh->hw_info2 |= cpu_to_le32 (1 << uframe);
+			// dbg_qh ("Schedule INTR qh", ehci, qh);
+
+			/* stuff into the periodic schedule */
+			qh->qh_state = QH_STATE_LINKED;
+			vdbg ("qh %p usecs %d period %d starting frame %d.%d",
+				qh, qh->usecs, period, frame, uframe);
+			do {
+				if (unlikely ((int)ehci->pshadow [frame].ptr)) {
+// FIXME -- just link to the end, before any qh with a shorter period,
+// AND handle it already being (implicitly) linked into this frame
+					BUG ();
+				} else {
+					ehci->pshadow [frame].qh = qh_put (qh);
+					ehci->periodic [frame] =
+						QH_NEXT (qh->qh_dma);
+				}
+				frame += period;
+			} while (frame < ehci->periodic_size);
+
+			/* maybe enable periodic schedule processing */
+			if (!ehci->periodic_urbs++) {
+				u32	cmd;
+
+				/* did clearing PSE did take effect yet?
+				 * takes effect only at frame boundaries...
+				 */
+				while (readl (&ehci->regs->status) & STS_PSS)
+					udelay (20);
+
+				cmd = readl (&ehci->regs->command) | CMD_PSE;
+				writel (cmd, &ehci->regs->command);
+				/* posted write ... PSS happens later */
+				ehci->hcd.state = USB_STATE_RUNNING;
+
+				/* make sure tasklet scans these */
+				ehci->next_frame = ehci_get_frame (&ehci->hcd);
+			}
+			break;
+
+		} while (frame);
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+done:
+	if (status) {
+		usb_complete_t	complete = urb->complete;
+
+		urb->complete = 0;
+		urb->status = status;
+		qh_completions (ehci, qtd_list, 1);
+		urb->complete = complete;
+	}
+	return status;
+}
+
+static unsigned long
+intr_complete (
+	struct ehci_hcd	*ehci,
+	unsigned	frame,
+	struct ehci_qh	*qh,
+	unsigned long	flags		/* caller owns ehci->lock ... */
+) {
+	struct ehci_qtd	*qtd;
+	struct urb	*urb;
+	int		unlinking;
+
+	/* nothing to report? */
+	if (likely ((qh->hw_token & __constant_cpu_to_le32 (QTD_STS_ACTIVE))
+			!= 0))
+		return flags;
+	
+	qtd = list_entry (qh->qtd_list.next, struct ehci_qtd, qtd_list);
+	urb = qtd->urb;
+	unlinking = (urb->status == -ENOENT) || (urb->status == -ECONNRESET);
+
+	/* call any completions, after patching for reactivation */
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	/* NOTE:  currently restricted to one qtd per qh! */
+	if (qh_completions (ehci, &qh->qtd_list, 0) == 0)
+		urb = 0;
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	/* never reactivate requests that were unlinked ... */
+	if (likely (urb != 0)) {
+		if (unlinking
+				|| urb->status == -ECONNRESET
+				|| urb->status == -ENOENT
+				// || (urb->dev == null)
+				|| ehci->hcd.state == USB_STATE_HALT)
+			urb = 0;
+		// FIXME look at all those unlink cases ... we always
+		// need exactly one completion that reports unlink.
+		// the one above might not have been it!
+	}
+
+	/* normally reactivate */
+	if (likely (urb != 0)) {
+		if (usb_pipeout (urb->pipe))
+			pci_dma_sync_single (ehci->hcd.pdev,
+				qtd->buf_dma,
+				urb->transfer_buffer_length,
+				PCI_DMA_TODEVICE);
+		urb->status = -EINPROGRESS;
+		urb->actual_length = 0;
+
+		/* patch qh and restart */
+		qh_update (qh, qtd);
+	}
+	return flags;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	have_iso
+
+static inline void itd_free (struct ehci_hcd *ehci, struct ehci_itd *itd)
+{
+	pci_pool_free (ehci->itd_pool, itd, itd->itd_dma);
+}
+
+/*
+ * Create itd and allocate into uframes within specified frame.
+ * Caller must update the resulting uframe links.
+ */
+static struct ehci_itd *
+itd_make (
+	struct ehci_hcd	*ehci,
+	struct urb	*urb,
+	unsigned	index,		// urb->iso_frame_desc [index]
+	unsigned	frame,		// scheduled start
+	dma_addr_t	dma,		// mapped transfer buffer
+	int		mem_flags
+) {
+	struct ehci_itd	*itd;
+	u64		temp;
+	u32		buf1;
+	unsigned	epnum, maxp, multi, usecs;
+	unsigned	length;
+	unsigned	i, bufnum;
+
+	/* allocate itd, start to fill it */
+	itd = pci_pool_alloc (ehci->itd_pool, mem_flags, &dma);
+	if (!itd)
+		return itd;
+
+	itd->hw_next = EHCI_LIST_END;
+	itd->urb = urb;
+	itd->index = index;
+	INIT_LIST_HEAD (&itd->itd_list);
+	itd->uframe = (frame * 8) % ehci->periodic_size;
+
+	/* tell itd about the buffer its transfers will consume */
+	length = urb->iso_frame_desc [index].length;
+	dma += urb->iso_frame_desc [index].offset;
+	temp = dma & ~0x0fff;
+	for (i = 0; i < 7; i++) {
+		itd->hw_bufp [i] = cpu_to_le32 ((u32) temp);
+		itd->hw_bufp_hi [i] = cpu_to_le32 ((u32)(temp >> 32));
+		temp += 0x0fff;
+	}
+
+	/*
+	 * this might be a "high bandwidth" highspeed endpoint,
+	 * as encoded in the ep descriptor's maxpacket field
+	 */
+	epnum = usb_pipeendpoint (urb->pipe);
+	if (usb_pipein (urb->pipe)) {
+		maxp = urb->dev->epmaxpacketin [epnum];
+		buf1 = (1 << 11) | maxp;
+	} else {
+		maxp = urb->dev->epmaxpacketout [epnum];
+		buf1 = maxp;
+	}
+	multi = 1;
+	multi += (temp >> 11) & 0x03;
+	maxp &= 0x03ff;
+
+	/* "plus" info in low order bits of buffer pointers */
+	itd->hw_bufp [0] |= cpu_to_le32 ((epnum << 8) | urb->dev->devnum);
+	itd->hw_bufp [1] |= cpu_to_le32 (buf1);
+	itd->hw_bufp [2] |= cpu_to_le32 (multi);
+
+	/* schedule as many uframes as needed */
+	maxp *= multi;
+	usecs = HS_USECS_ISO (maxp);
+	bufnum = 0;
+	for (i = 0; i < 8; i++) {
+		unsigned	t, offset, scratch;
+
+		if (length <= 0) {
+			itd->hw_transaction [i] = 0;
+			continue;
+		}
+
+		/* don't commit more than 80% periodic == 100 usec */
+		if ((periodic_usecs (ehci, itd->uframe, i) + usecs) > 100)
+			continue;
+
+		/* we'll use this uframe; figure hw_transaction */
+		t = EHCI_ISOC_ACTIVE;
+		t |= bufnum << 12;		// which buffer?
+		offset = temp & 0x0fff;		// offset therein
+		t |= offset;
+		if ((offset + maxp) >= 4096) 	// hc auto-wraps end-of-"page"
+			bufnum++;
+		if (length <= maxp) {
+			// interrupt only needed at end-of-urb
+			if ((index + 1) == urb->number_of_packets)
+				t |= EHCI_ITD_IOC;
+			scratch = length;
+		} else
+			scratch = maxp;
+		t |= scratch << 16;
+		t = cpu_to_le32 (t);
+
+		itd->hw_transaction [i] = itd->transaction [i] = t;
+		length -= scratch;
+	}
+	if (length > 0) {
+		dbg ("iso frame too big, urb %p [%d], %d extra (of %d)",
+			urb, index, length, urb->iso_frame_desc [index].length);
+		itd_free (ehci, itd);
+		itd = 0;
+	}
+	return itd;
+}
+
+static inline void
+itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
+{
+	u32		ptr;
+
+	ptr = cpu_to_le32 (itd->itd_dma);	// type 0 == itd
+	if (ehci->pshadow [frame].ptr) {
+		if (!itd->itd_next.ptr) {
+			itd->itd_next = ehci->pshadow [frame];
+			itd->hw_next = ehci->periodic [frame];
+		} else if (itd->itd_next.ptr != ehci->pshadow [frame].ptr) {
+			dbg ("frame %d itd link goof", frame);
+			BUG ();
+		}
+	}
+	ehci->pshadow [frame].itd = itd;
+	ehci->periodic [frame] = ptr;
+}
+
+#define	ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
+
+static unsigned long
+itd_complete (struct ehci_hcd *ehci, struct ehci_itd *itd, unsigned long flags)
+{
+	struct urb		*urb = itd->urb;
+
+	/* if not unlinking: */
+	if (!(urb->transfer_flags & EHCI_STATE_UNLINK)
+			&& ehci->hcd.state != USB_STATE_HALT) {
+		int			i;
+		iso_packet_descriptor_t	*desc;
+		struct ehci_itd		*first_itd = urb->hcpriv;
+
+		/* update status for this frame's transfers */
+		desc = &urb->iso_frame_desc [itd->index];
+		desc->status = 0;
+		desc->actual_length = 0;
+		for (i = 0; i < 8; i++) {
+			u32	 t = itd->hw_transaction [i];
+			if (t & (ISO_ERRS | EHCI_ISOC_ACTIVE)) {
+				if (t & EHCI_ISOC_ACTIVE)
+					desc->status = -EXDEV;
+				else if (t & EHCI_ISOC_BUF_ERR)
+					desc->status = usb_pipein (urb->pipe)
+						? -ENOSR  /* couldn't read */
+						: -ECOMM; /* couldn't write */
+				else if (t & EHCI_ISOC_BABBLE)
+					desc->status = -EOVERFLOW;
+				else /* (t & EHCI_ISOC_XACTERR) */
+					desc->status = -EPROTO;
+				break;
+			}
+			desc->actual_length += EHCI_ITD_LENGTH (t);
+		}
+
+		/* handle completion now? */
+		if ((itd->index + 1) != urb->number_of_packets)
+			return flags;
+
+		i = usb_pipein (urb->pipe);
+		if (i)
+			pci_dma_sync_single (ehci->hcd.pdev,
+				first_itd->buf_dma,
+				urb->transfer_buffer_length,
+				PCI_DMA_FROMDEVICE);
+
+		/* call completion with no locks; it can unlink ... */
+		spin_unlock_irqrestore (&ehci->lock, flags);
+		urb->complete (urb);
+		spin_lock_irqsave (&ehci->lock, flags);
+
+		/* re-activate this URB? or unlink? */
+		if (!(urb->transfer_flags & EHCI_STATE_UNLINK)
+				&& ehci->hcd.state != USB_STATE_HALT) {
+			if (!i)
+				pci_dma_sync_single (ehci->hcd.pdev,
+					first_itd->buf_dma,
+					urb->transfer_buffer_length,
+					PCI_DMA_TODEVICE);
+
+			itd = urb->hcpriv;
+			do {
+				for (i = 0; i < 8; i++)
+					itd->hw_transaction [i]
+						= itd->transaction [i];
+				itd = list_entry (itd->itd_list.next,
+						struct ehci_itd, itd_list);
+			} while (itd != urb->hcpriv);
+			return flags;
+		}
+
+	/* unlink done only on the last itd */
+	} else if ((itd->index + 1) != urb->number_of_packets)
+		return flags;
+
+	/* we're unlinking ... */
+
+	/* decouple urb from the hcd */
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	if (ehci->hcd.state == USB_STATE_HALT)
+		urb->status = -ESHUTDOWN;
+	itd = urb->hcpriv;
+	urb->hcpriv = 0;
+	ehci_urb_done (ehci, itd->buf_dma, urb);
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	/* take itds out of the hc's periodic schedule */
+	list_entry (itd->itd_list.prev, struct ehci_itd, itd_list)
+		->itd_list.next = 0;
+	do {
+		struct ehci_itd	*next;
+
+		if (itd->itd_list.next)
+			next = list_entry (itd->itd_list.next,
+				struct ehci_itd, itd_list);
+		else
+			next = 0;
+
+		// FIXME:  hc WILL (!) lap us here, if we get behind
+		// by 128 msec (or less, with smaller periodic_size).
+		// Reading/caching these itds will cause trouble...
+
+		periodic_unlink (ehci, itd->uframe, itd);
+		itd_free (ehci, itd);
+		itd = next;
+	} while (itd);
+	return flags;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int itd_submit (struct ehci_hcd *ehci, struct urb *urb)
+{
+	struct ehci_itd		*first_itd = 0, *itd;
+	unsigned		frame_index;
+	dma_addr_t		dma;
+	unsigned long		flags;
+
+	dbg ("itd_submit");
+
+	/* set up one dma mapping for this urb */
+	dma = pci_map_single (ehci->hcd.pdev,
+		urb->transfer_buffer, urb->transfer_buffer_length,
+		usb_pipein (urb->pipe)
+		    ? PCI_DMA_FROMDEVICE
+		    : PCI_DMA_TODEVICE);
+	if (dma == 0)
+		return -ENOMEM;
+
+	/*
+	 * Schedule as needed.  This is VERY optimistic about free
+	 * bandwidth!  But the API assumes drivers can pick frames
+	 * intelligently (how?), so there's no other good option.
+	 *
+	 * FIXME  this doesn't handle urb->next rings, or try to
+	 * use the iso periodicity.
+	 */
+	if (urb->transfer_flags & USB_ISO_ASAP) { 
+		urb->start_frame = ehci_get_frame (&ehci->hcd);
+		urb->start_frame++;
+	}
+	urb->start_frame %= ehci->periodic_size;
+
+	/* create and populate itds (doing uframe scheduling) */
+	spin_lock_irqsave (&ehci->lock, flags);
+	for (frame_index = 0;
+			frame_index < urb->number_of_packets;
+			frame_index++) {
+		itd = itd_make (ehci, urb, frame_index,
+			urb->start_frame + frame_index,
+			dma, SLAB_ATOMIC);
+		if (itd) {
+			if (first_itd)
+				list_add_tail (&itd->itd_list,
+						&first_itd->itd_list);
+			else
+				first_itd = itd;
+		} else {
+			spin_unlock_irqrestore (&ehci->lock, flags);
+			if (first_itd) {
+				while (!list_empty (&first_itd->itd_list)) {
+					itd = list_entry (
+						first_itd->itd_list.next,
+						struct ehci_itd, itd_list);
+					list_del (&itd->itd_list);
+					itd_free (ehci, itd);
+				}
+				itd_free (ehci, first_itd);
+			}
+			pci_unmap_single (ehci->hcd.pdev,
+				dma, urb->transfer_buffer_length,
+				usb_pipein (urb->pipe)
+				    ? PCI_DMA_FROMDEVICE
+				    : PCI_DMA_TODEVICE);
+			return -ENOMEM;
+		}
+	}
+
+	/* stuff into the schedule */
+	itd = first_itd;
+	do {
+		unsigned	i;
+
+		for (i = 0; i < 8; i++) {
+			if (!itd->hw_transaction [i])
+				continue;
+			itd_link (ehci, itd->uframe + i, itd);
+		}
+		itd = list_entry (itd->itd_list.next,
+			struct ehci_itd, itd_list);
+	} while (itd != first_itd);
+	urb->hcpriv = first_itd;
+
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * "Split ISO TDs" ... used for USB 1.1 devices going through
+ * the TTs in USB 2.0 hubs.
+ */
+
+static inline void
+sitd_free (struct ehci_hcd *ehci, struct ehci_sitd *sitd)
+{
+	pci_pool_free (ehci->sitd_pool, sitd, sitd->sitd_dma);
+}
+
+static struct ehci_sitd *
+sitd_make (
+	struct ehci_hcd	*ehci,
+	struct urb	*urb,
+	unsigned	index,		// urb->iso_frame_desc [index]
+	unsigned	uframe,		// scheduled start
+	dma_addr_t	dma,		// mapped transfer buffer
+	int		mem_flags
+) {
+	struct ehci_sitd	*sitd;
+	unsigned		length;
+
+	sitd = pci_pool_alloc (ehci->sitd_pool, mem_flags, &dma);
+	if (!sitd)
+		return sitd;
+	sitd->urb = urb;
+	length = urb->iso_frame_desc [index].length;
+	dma += urb->iso_frame_desc [index].offset;
+
+#if 0
+	// FIXME:  do the rest!
+#else
+	sitd_free (ehci, sitd);
+	return 0;
+#endif
+
+}
+
+static inline void
+sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
+{
+	u32		ptr;
+
+	ptr = cpu_to_le32 (sitd->sitd_dma | 2);	// type 2 == sitd
+	if (ehci->pshadow [frame].ptr) {
+		if (!sitd->sitd_next.ptr) {
+			sitd->sitd_next = ehci->pshadow [frame];
+			sitd->hw_next = ehci->periodic [frame];
+		} else if (sitd->sitd_next.ptr != ehci->pshadow [frame].ptr) {
+			dbg ("frame %d sitd link goof", frame);
+			BUG ();
+		}
+	}
+	ehci->pshadow [frame].sitd = sitd;
+	ehci->periodic [frame] = ptr;
+}
+
+static unsigned long
+sitd_complete (
+	struct ehci_hcd *ehci,
+	struct ehci_sitd	*sitd,
+	unsigned long		flags
+) {
+	// FIXME -- implement!
+
+	dbg ("NYI -- sitd_complete");
+	return flags;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb)
+{
+	// struct ehci_sitd	*first_sitd = 0;
+	unsigned		frame_index;
+	dma_addr_t		dma;
+	int			mem_flags;
+
+	dbg ("NYI -- sitd_submit");
+
+	// FIXME -- implement!
+
+	// FIXME:  setup one big dma mapping
+	dma = 0;
+
+	mem_flags = SLAB_ATOMIC;
+
+	for (frame_index = 0;
+			frame_index < urb->number_of_packets;
+			frame_index++) {
+		struct ehci_sitd	*sitd;
+		unsigned		uframe;
+
+		// FIXME:  use real arguments, schedule this!
+		uframe = -1;
+
+		sitd = sitd_make (ehci, urb, frame_index,
+				uframe, dma, mem_flags);
+
+		if (sitd) {
+    /*
+			if (first_sitd)
+				list_add_tail (&sitd->sitd_list,
+						&first_sitd->sitd_list);
+			else
+				first_sitd = sitd;
+    */
+		} else {
+			// FIXME:  clean everything up
+		}
+	}
+
+	// if we have a first sitd, then
+		// store them all into the periodic schedule!
+		// urb->hcpriv = first sitd in sitd_list
+
+	return -ENOSYS;
+}
+
+#endif	/* have_iso */
+
+/*-------------------------------------------------------------------------*/
+
+static void scan_periodic (struct ehci_hcd *ehci)
+{
+	unsigned	frame;
+	unsigned	clock;
+	unsigned long	flags;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	/*
+	 * When running, scan from last scan point up to "now"
+	 * Touches as few pages as possible:  cache-friendly.
+	 * It's safe to scan entries more than once, though.
+	 */
+	if (HCD_IS_RUNNING (ehci->hcd.state)) {
+		frame = ehci->next_frame;
+		clock = ehci_get_frame (&ehci->hcd);
+
+	/* when shutting down, scan everything for thoroughness */
+	} else {
+		frame = 0;
+		clock = ehci->periodic_size - 1;
+	}
+	for (;;) {
+		union ehci_shadow	 q;
+		u32	type;
+
+restart:
+		q.ptr = ehci->pshadow [frame].ptr;
+		type = Q_NEXT_TYPE (ehci->periodic [frame]);
+
+		/* scan each element in frame's queue for completions */
+		while (q.ptr != 0) {
+			int			last;
+			union ehci_shadow	temp;
+
+			switch (type) {
+			case Q_TYPE_QH:
+				last = (q.qh->hw_next == EHCI_LIST_END);
+				flags = intr_complete (ehci, frame,
+						qh_put (q.qh), flags);
+				type = Q_NEXT_TYPE (q.qh->hw_next);
+				temp = q.qh->qh_next;
+				qh_unput (ehci, q.qh);
+				q = temp;
+				break;
+			case Q_TYPE_FSTN:
+				last = (q.fstn->hw_next == EHCI_LIST_END);
+				/* for "save place" FSTNs, look at QH entries
+				 * in the previous frame for completions.
+				 */
+				if (q.fstn->hw_prev != EHCI_LIST_END) {
+					dbg ("ignoring completions from FSTNs");
+				}
+				type = Q_NEXT_TYPE (q.fstn->hw_next);
+				temp = q.fstn->fstn_next;
+				break;
+#ifdef have_iso
+			case Q_TYPE_ITD:
+				last = (q.itd->hw_next == EHCI_LIST_END);
+				flags = itd_complete (ehci, q.itd, flags);
+				type = Q_NEXT_TYPE (q.itd->hw_next);
+				q = q.itd->itd_next;
+				break;
+			case Q_TYPE_SITD:
+				last = (q.sitd->hw_next == EHCI_LIST_END);
+				flags = sitd_complete (ehci, q.sitd, flags);
+				type = Q_NEXT_TYPE (q.sitd->hw_next);
+				q = q.sitd->sitd_next;
+				break;
+#endif /* have_iso */
+			default:
+				dbg ("corrupt type %d frame %d shadow %p",
+					type, frame, q.ptr);
+				// BUG ();
+				last = 1;
+				q.ptr = 0;
+			}
+
+			/* did completion remove an interior q entry? */
+			if (unlikely (q.ptr == 0 && !last))
+				goto restart;
+		}
+
+		/* stop when we catch up to the HC */
+
+		// FIXME:  this assumes we won't get lapped when
+		// latencies climb; that should be rare, but...
+		// detect it, and just go all the way around.
+		// FLR might help detect this case, so long as latencies
+		// don't exceed periodic_size msec (default 1.024 sec).
+
+		// FIXME:  likewise assumes HC doesn't halt mid-scan
+
+		if (frame == clock) {
+			unsigned	now;
+
+			if (!HCD_IS_RUNNING (ehci->hcd.state))
+				break;
+			ehci->next_frame = clock;
+			now = ehci_get_frame (&ehci->hcd);
+			if (clock == now)
+				break;
+			clock = now;
+		} else if (++frame >= ehci->periodic_size)
+			frame = 0;
+	} 
+	spin_unlock_irqrestore (&ehci->lock, flags);
+ }
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/hcd/ehci.h linux/drivers/usb/hcd/ehci.h
--- v2.5.1/linux/drivers/usb/hcd/ehci.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ehci.h	Tue Jan  1 13:52:10 2002
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_EHCI_HCD_H
+#define __LINUX_EHCI_HCD_H
+
+/* definitions used for the EHCI driver */
+
+/* ehci_hcd->lock guards shared data against other CPUs:
+ *   ehci_hcd:	async, reclaim, periodic (and shadow), ...
+ *   hcd_dev:	ep[]
+ *   ehci_qh:	qh_next, qtd_list
+ *   ehci_qtd:	qtd_list
+ *
+ * Also, hold this lock when talking to HC registers or
+ * when updating hw_* fields in shared qh/qtd/... structures.
+ */
+
+#define	EHCI_MAX_ROOT_PORTS	15		/* see HCS_N_PORTS */
+
+struct ehci_hcd {			/* one per controller */
+	spinlock_t		lock;
+
+	/* async schedule support */
+	struct ehci_qh		*async;
+	struct ehci_qh		*reclaim;
+	int			reclaim_ready;
+
+	/* periodic schedule support */
+#define	DEFAULT_I_TDPS		1024		/* some HCs can do less */
+	unsigned		periodic_size;
+	u32			*periodic;	/* hw periodic table */
+	dma_addr_t		periodic_dma;
+	unsigned		i_thresh;	/* uframes HC might cache */
+
+	union ehci_shadow	*pshadow;	/* mirror hw periodic table */
+	int			next_frame;	/* scan periodic, start here */
+	unsigned		periodic_urbs;	/* how many urbs scheduled? */
+
+	/* deferred work from IRQ, etc */
+	struct tasklet_struct	tasklet;
+
+	/* per root hub port */
+	unsigned long		reset_done [EHCI_MAX_ROOT_PORTS];
+
+	/* glue to PCI and HCD framework */
+	struct usb_hcd		hcd;
+	struct ehci_caps	*caps;
+	struct ehci_regs	*regs;
+
+	/* per-HC memory pools (could be per-PCI-bus, but ...) */
+	struct pci_pool		*qh_pool;	/* qh per active urb */
+	struct pci_pool		*qtd_pool;	/* one or more per qh */
+	struct pci_pool		*itd_pool;	/* itd per iso urb */
+	struct pci_pool		*sitd_pool;	/* sitd per split iso urb */
+};
+
+/* unwrap an HCD pointer to get an EHCI_HCD pointer */ 
+#define hcd_to_ehci(hcd_ptr) list_entry(hcd_ptr, struct ehci_hcd, hcd)
+
+/* NOTE:  urb->transfer_flags expected to not use this bit !!! */
+#define EHCI_STATE_UNLINK	0x8000		/* urb being unlinked */
+
+/*-------------------------------------------------------------------------*/
+
+/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
+
+/* Section 2.2 Host Controller Capability Registers */
+struct ehci_caps {
+	u8		length;		/* CAPLENGTH - size of this struct */
+	u8		reserved;       /* offset 0x1 */
+	u16		hci_version;    /* HCIVERSION - offset 0x2 */
+	u32		hcs_params;     /* HCSPARAMS - offset 0x4 */
+#define HCS_DEBUG_PORT(p)	(((p)>>20)&0xf)	/* bits 23:20, debug port? */
+#define HCS_INDICATOR(p)	((p)&(1 << 16))	/* true: has port indicators */
+#define HCS_N_CC(p)		(((p)>>12)&0xf)	/* bits 15:12, #companion HCs */
+#define HCS_N_PCC(p)		(((p)>>8)&0xf)	/* bits 11:8, ports per CC */
+#define HCS_PORTROUTED(p)	((p)&(1 << 7))	/* true: port routing */ 
+#define HCS_PPC(p)		((p)&(1 << 4))	/* true: port power control */ 
+#define HCS_N_PORTS(p)		(((p)>>0)&0xf)	/* bits 3:0, ports on HC */
+
+	u32		hcc_params;      /* HCCPARAMS - offset 0x8 */
+#define HCC_EXT_CAPS(p)		(((p)>>8)&0xff)	/* for pci extended caps */
+#define HCC_ISOC_CACHE(p)       ((p)&(1 << 7))  /* true: can cache isoc frame */
+#define HCC_ISOC_THRES(p)       (((p)>>4)&0x7)  /* bits 6:4, uframes cached */
+#define HCC_CANPARK(p)		((p)&(1 << 2))  /* true: can park on async qh */
+#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1))  /* true: periodic_size changes*/
+#define HCC_64BIT_ADDR(p)       ((p)&(1))       /* true: can use 64-bit addr */
+	u8		portroute [8];	 /* nibbles for routing - offset 0xC */
+} __attribute__ ((packed));
+
+
+/* Section 2.3 Host Controller Operational Registers */
+struct ehci_regs {
+
+	/* USBCMD: offset 0x00 */
+	u32		command;
+/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
+#define CMD_PARK	(1<<11)		/* enable "park" on async qh */
+#define CMD_PARK_CNT(c)	(((c)>>8)&3)	/* how many transfers to park for */
+#define CMD_LRESET	(1<<7)		/* partial reset (no ports, etc) */
+#define CMD_IAAD	(1<<6)		/* "doorbell" interrupt async advance */
+#define CMD_ASE		(1<<5)		/* async schedule enable */
+#define CMD_PSE  	(1<<4)		/* periodic schedule enable */
+/* 3:2 is periodic frame list size */
+#define CMD_RESET	(1<<1)		/* reset HC not bus */
+#define CMD_RUN		(1<<0)		/* start/stop HC */
+
+	/* USBSTS: offset 0x04 */
+	u32		status;
+#define STS_ASS		(1<<15)		/* Async Schedule Status */
+#define STS_PSS		(1<<14)		/* Periodic Schedule Status */
+#define STS_RECL	(1<<13)		/* Reclamation */
+#define STS_HALT	(1<<12)		/* Not running (any reason) */
+/* some bits reserved */
+	/* these STS_* flags are also intr_enable bits (USBINTR) */
+#define STS_IAA		(1<<5)		/* Interrupted on async advance */
+#define STS_FATAL	(1<<4)		/* such as some PCI access errors */
+#define STS_FLR		(1<<3)		/* frame list rolled over */
+#define STS_PCD		(1<<2)		/* port change detect */
+#define STS_ERR		(1<<1)		/* "error" completion (overflow, ...) */
+#define STS_INT		(1<<0)		/* "normal" completion (short, ...) */
+
+	/* USBINTR: offset 0x08 */
+	u32		intr_enable;
+
+	/* FRINDEX: offset 0x0C */
+	u32		frame_index;	/* current microframe number */
+	/* CTRLDSSEGMENT: offset 0x10 */
+	u32		segment; 	/* address bits 63:32 if needed */
+	/* PERIODICLISTBASE: offset 0x14 */
+	u32		frame_list; 	/* points to periodic list */
+	/* ASYNCICLISTADDR: offset 0x18 */
+	u32		async_next;	/* address of next async queue head */
+
+	u32		reserved [9];
+
+	/* CONFIGFLAG: offset 0x40 */
+	u32		configured_flag;
+#define FLAG_CF		(1<<0)		/* true: we'll support "high speed" */
+
+	/* PORTSC: offset 0x44 */
+	u32		port_status [0];	/* up to N_PORTS */
+/* 31:23 reserved */
+#define PORT_WKOC_E	(1<<22)		/* wake on overcurrent (enable) */
+#define PORT_WKDISC_E	(1<<21)		/* wake on disconnect (enable) */
+#define PORT_WKCONN_E	(1<<20)		/* wake on connect (enable) */
+/* 19:16 for port testing */
+/* 15:14 for using port indicator leds (if HCS_INDICATOR allows) */
+#define PORT_OWNER	(1<<13)		/* true: companion hc owns this port */
+#define PORT_POWER	(1<<12)		/* true: has power (see PPC) */
+#define PORT_USB11(x) (((x)&(3<<10))==(1<<10))	/* USB 1.1 device */
+/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
+/* 9 reserved */
+#define PORT_RESET	(1<<8)		/* reset port */
+#define PORT_SUSPEND	(1<<7)		/* suspend port */
+#define PORT_RESUME	(1<<6)		/* resume it */
+#define PORT_OCC	(1<<5)		/* over current change */
+#define PORT_OC		(1<<4)		/* over current active */
+#define PORT_PEC	(1<<3)		/* port enable change */
+#define PORT_PE		(1<<2)		/* port enable */
+#define PORT_CSC	(1<<1)		/* connect status change */
+#define PORT_CONNECT	(1<<0)		/* device connected */
+} __attribute__ ((packed));
+
+
+/*-------------------------------------------------------------------------*/
+
+#define	QTD_NEXT(dma)	cpu_to_le32((u32)dma)
+
+/*
+ * EHCI Specification 0.95 Section 3.5
+ * QTD: describe data transfer components (buffer, direction, ...) 
+ * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
+ *
+ * These are associated only with "QH" (Queue Head) structures,
+ * used with control, bulk, and interrupt transfers.
+ */
+struct ehci_qtd {
+	/* first part defined by EHCI spec */
+	u32			hw_next;	  /* see EHCI 3.5.1 */
+	u32			hw_alt_next;      /* see EHCI 3.5.2 */
+	u32			hw_token;         /* see EHCI 3.5.3 */       
+#define	QTD_TOGGLE	(1 << 31)	/* data toggle */
+#define	QTD_LENGTH(tok)	(((tok)>>16) & 0x7fff)
+#define	QTD_IOC		(1 << 15)	/* interrupt on complete */
+#define	QTD_CERR(tok)	(((tok)>>10) & 0x3)
+#define	QTD_PID(tok)	(((tok)>>8) & 0x3)
+#define	QTD_STS_ACTIVE	(1 << 7)	/* HC may execute this */
+#define	QTD_STS_HALT	(1 << 6)	/* halted on error */
+#define	QTD_STS_DBE	(1 << 5)	/* data buffer error (in HC) */
+#define	QTD_STS_BABBLE	(1 << 4)	/* device was babbling (qtd halted) */
+#define	QTD_STS_XACT	(1 << 3)	/* device gave illegal response */
+#define	QTD_STS_MMF	(1 << 2)	/* incomplete split transaction */
+#define	QTD_STS_STS	(1 << 1)	/* split transaction state */
+#define	QTD_STS_PING	(1 << 0)	/* issue PING? */
+	u32			hw_buf [5];        /* see EHCI 3.5.4 */
+	u32			hw_buf_hi [5];        /* Appendix B */
+
+	/* the rest is HCD-private */
+	dma_addr_t		qtd_dma;		/* qtd address */
+	struct list_head	qtd_list;		/* sw qtd list */
+
+	/* dma same in urb's qtds, except 1st control qtd (setup buffer) */
+	struct urb		*urb;			/* qtd's urb */
+	dma_addr_t		buf_dma;		/* buffer address */
+	size_t			length;			/* length of buffer */
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+/* type tag from {qh,itd,sitd,fstn}->hw_next */
+#define Q_NEXT_TYPE(dma) ((dma) & __constant_cpu_to_le32 (3 << 1))
+
+/* values for that type tag */
+#define Q_TYPE_ITD	__constant_cpu_to_le32 (0 << 1)
+#define Q_TYPE_QH	__constant_cpu_to_le32 (1 << 1)
+#define Q_TYPE_SITD 	__constant_cpu_to_le32 (2 << 1)
+#define Q_TYPE_FSTN 	__constant_cpu_to_le32 (3 << 1)
+
+/* next async queue entry, or pointer to interrupt/periodic QH */
+#define	QH_NEXT(dma)	(cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH)
+
+/* for periodic/async schedules and qtd lists, mark end of list */
+#define	EHCI_LIST_END	__constant_cpu_to_le32(1) /* "null pointer" to hw */
+
+/*
+ * Entries in periodic shadow table are pointers to one of four kinds
+ * of data structure.  That's dictated by the hardware; a type tag is
+ * encoded in the low bits of the hardware's periodic schedule.  Use
+ * Q_NEXT_TYPE to get the tag.
+ *
+ * For entries in the async schedule, the type tag always says "qh".
+ */
+union ehci_shadow {
+	struct ehci_qh 		*qh;		/* Q_TYPE_QH */
+	struct ehci_itd		*itd;		/* Q_TYPE_ITD */
+	struct ehci_sitd	*sitd;		/* Q_TYPE_SITD */
+	struct ehci_fstn	*fstn;		/* Q_TYPE_FSTN */
+	void			*ptr;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.6
+ * QH: describes control/bulk/interrupt endpoints
+ * See Fig 3-7 "Queue Head Structure Layout".
+ *
+ * These appear in both the async and (for interrupt) periodic schedules.
+ */
+
+struct ehci_qh {
+	/* first part defined by EHCI spec */
+	u32			hw_next;	 /* see EHCI 3.6.1 */
+	u32			hw_info1;        /* see EHCI 3.6.2 */
+#define	QH_HEAD		0x00008000
+	u32			hw_info2;        /* see EHCI 3.6.2 */
+	u32			hw_current;	 /* qtd list - see EHCI 3.6.4 */
+	
+	/* qtd overlay (hardware parts of a struct ehci_qtd) */
+	u32			hw_qtd_next;
+	u32			hw_alt_next;
+	u32			hw_token;
+	u32			hw_buf [5];
+	u32			hw_buf_hi [5];
+
+	/* the rest is HCD-private */
+	dma_addr_t		qh_dma;		/* address of qh */
+	union ehci_shadow	qh_next;	/* ptr to qh; or periodic */
+	struct list_head	qtd_list;	/* sw qtd list */
+
+	atomic_t		refcount;
+	unsigned short		usecs;		/* intr bandwidth */
+	short			qh_state;
+#define	QH_STATE_LINKED		1		/* HC sees this */
+#define	QH_STATE_UNLINK		2		/* HC may still see this */
+#define	QH_STATE_IDLE		3		/* HC doesn't see this */
+
+#ifdef EHCI_SOFT_RETRIES
+	int			retries;
+#endif
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.3
+ * Fig 3-4 "Isochronous Transaction Descriptor (iTD)"
+ *
+ * Schedule records for high speed iso xfers
+ */
+struct ehci_itd {
+	/* first part defined by EHCI spec */
+	u32			hw_next;           /* see EHCI 3.3.1 */
+	u32			hw_transaction [8]; /* see EHCI 3.3.2 */
+#define EHCI_ISOC_ACTIVE        (1<<31)        /* activate transfer this slot */
+#define EHCI_ISOC_BUF_ERR       (1<<30)        /* Data buffer error */
+#define EHCI_ISOC_BABBLE        (1<<29)        /* babble detected */
+#define EHCI_ISOC_XACTERR       (1<<28)        /* XactErr - transaction error */
+#define	EHCI_ITD_LENGTH(tok)	(((tok)>>16) & 0x7fff)
+#define	EHCI_ITD_IOC		(1 << 15)	/* interrupt on complete */
+
+	u32			hw_bufp [7];	/* see EHCI 3.3.3 */ 
+	u32			hw_bufp_hi [7];	/* Appendix B */
+
+	/* the rest is HCD-private */
+	dma_addr_t		itd_dma;	/* for this itd */
+	union ehci_shadow	itd_next;	/* ptr to periodic q entry */
+
+	struct urb		*urb;
+	unsigned		index;		/* in urb->iso_frame_desc */
+	struct list_head	itd_list;	/* list of urb frames' itds */
+	dma_addr_t		buf_dma;	/* frame's buffer address */
+
+	unsigned		uframe;		/* in periodic schedule */
+	u32			transaction [8]; /* copy of hw_transaction */
+
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.4 
+ * siTD, aka split-transaction isochronous Transfer Descriptor
+ *       ... describe low/full speed iso xfers through TT in hubs
+ * see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD)
+ */
+struct ehci_sitd {
+	/* first part defined by EHCI spec */
+	u32			hw_next;
+/* uses bit field macros above - see EHCI 0.95 Table 3-8 */
+	u32			hw_fullspeed_ep;  /* see EHCI table 3-9 */
+	u32                     hw_uframe;        /* see EHCI table 3-10 */
+        u32                     hw_tx_results1;   /* see EHCI table 3-11 */
+	u32                     hw_tx_results2;   /* see EHCI table 3-12 */
+	u32                     hw_tx_results3;   /* see EHCI table 3-12 */
+        u32                     hw_backpointer;   /* see EHCI table 3-13 */
+	u32			hw_buf_hi [2];	  /* Appendix B */
+
+	/* the rest is HCD-private */
+	dma_addr_t		sitd_dma;
+	union ehci_shadow	sitd_next;	/* ptr to periodic q entry */
+	struct urb		*urb;
+	dma_addr_t		buf_dma;	/* buffer address */
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.96 Section 3.7
+ * Periodic Frame Span Traversal Node (FSTN)
+ *
+ * Manages split interrupt transactions (using TT) that span frame boundaries
+ * into uframes 0/1; see 4.12.2.2.  In those uframes, a "save place" FSTN
+ * makes the HC jump (back) to a QH to scan for fs/ls QH completions until
+ * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
+ */
+struct ehci_fstn {
+	u32			hw_next;	/* any periodic q entry */
+	u32			hw_prev;	/* qh or EHCI_LIST_END */
+
+	/* the rest is HCD-private */
+	dma_addr_t		fstn_dma;
+	union ehci_shadow	fstn_next;	/* ptr to periodic q entry */
+} __attribute__ ((aligned (32)));
+
+#endif /* __LINUX_EHCI_HCD_H */
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/hcd.c linux/drivers/usb/hcd.c
--- v2.5.1/linux/drivers/usb/hcd.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd.c	Tue Jan  1 13:52:10 2002
@@ -0,0 +1,1305 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/uts.h>			/* for UTS_SYSNAME */
+
+#ifndef CONFIG_USB_DEBUG
+	#define CONFIG_USB_DEBUG	/* this is experimental! */
+#endif
+
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+
+#include <linux/usb.h>
+#include "hcd.h"
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * USB Host Controller Driver framework
+ *
+ * Plugs into usbcore (usb_bus) and lets HCDs share code, minimizing
+ * HCD-specific behaviors/bugs.
+ *
+ * This does error checks, tracks devices and urbs, and delegates to a
+ * "hc_driver" only for code (and data) that really needs to know about
+ * hardware differences.  That includes root hub registers, i/o queues,
+ * and so on ... but as little else as possible.
+ *
+ * Shared code includes most of the "root hub" code (these are emulated,
+ * though each HC's hardware works differently) and PCI glue, plus request
+ * tracking overhead.  The HCD code should only block on spinlocks or on
+ * hardware handshaking; blocking on software events (such as other kernel
+ * threads releasing resources, or completing actions) is all generic.
+ *
+ * Happens the USB 2.0 spec says this would be invisible inside the "USBD",
+ * and includes mostly a "HCDI" (HCD Interface) along with some APIs used
+ * only by the hub driver ... and that neither should be seen or used by
+ * usb client device drivers.
+ *
+ * Contributors of ideas or unattributed patches include: David Brownell,
+ * Roman Weissgaerber, Rory Bolt, ...
+ *
+ * HISTORY:
+ * 2001-12-12	Initial patch version for Linux 2.5.1 kernel.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* host controllers we manage */
+static LIST_HEAD (hcd_list);
+
+/* used when updating list of hcds */
+static DECLARE_MUTEX (hcd_list_lock);
+
+/* used when updating hcd data */
+static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED;
+
+static struct usb_operations hcd_operations;
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Sharable chunks of root hub code.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* usb 2.0 root hub device descriptor */
+static const u8 usb2_rh_dev_descriptor [18] = {
+	0x12,       /*  __u8  bLength; */
+	0x01,       /*  __u8  bDescriptorType; Device */
+	0x00, 0x02, /*  __u16 bcdUSB; v2.0 */
+
+	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,	    /*  __u8  bDeviceSubClass; */
+	0x01,       /*  __u8  bDeviceProtocol; [ usb 2.0 single TT ]*/
+	0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
+
+	0x00, 0x00, /*  __u16 idVendor; */
+ 	0x00, 0x00, /*  __u16 idProduct; */
+ 	0x40, 0x02, /*  __u16 bcdDevice; (v2.4) */
+
+	0x03,       /*  __u8  iManufacturer; */
+	0x02,       /*  __u8  iProduct; */
+	0x01,       /*  __u8  iSerialNumber; */
+	0x01        /*  __u8  bNumConfigurations; */
+};
+
+/* no usb 2.0 root hub "device qualifier" descriptor: one speed only */
+
+/* usb 1.1 root hub device descriptor */
+static const u8 usb11_rh_dev_descriptor [18] = {
+	0x12,       /*  __u8  bLength; */
+	0x01,       /*  __u8  bDescriptorType; Device */
+	0x10, 0x01, /*  __u16 bcdUSB; v1.1 */
+
+	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,	    /*  __u8  bDeviceSubClass; */
+	0x00,       /*  __u8  bDeviceProtocol; [ low/full speeds only ] */
+	0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
+
+	0x00, 0x00, /*  __u16 idVendor; */
+ 	0x00, 0x00, /*  __u16 idProduct; */
+ 	0x40, 0x02, /*  __u16 bcdDevice; (v2.4) */
+
+	0x03,       /*  __u8  iManufacturer; */
+	0x02,       /*  __u8  iProduct; */
+	0x01,       /*  __u8  iSerialNumber; */
+	0x01        /*  __u8  bNumConfigurations; */
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Configuration descriptor for all our root hubs */
+
+static const u8 rh_config_descriptor [] = {
+
+	/* one configuration */
+	0x09,       /*  __u8  bLength; */
+	0x02,       /*  __u8  bDescriptorType; Configuration */
+	0x19, 0x00, /*  __u16 wTotalLength; */
+	0x01,       /*  __u8  bNumInterfaces; (1) */
+	0x01,       /*  __u8  bConfigurationValue; */
+	0x00,       /*  __u8  iConfiguration; */
+	0x40,       /*  __u8  bmAttributes; 
+				 Bit 7: Bus-powered,
+				     6: Self-powered,
+				     5 Remote-wakwup,
+				     4..0: resvd */
+	0x00,       /*  __u8  MaxPower; */
+      
+	/* USB 1.1:
+	 * USB 2.0, single TT organization (mandatory):
+	 *	one interface, protocol 0
+	 *
+	 * USB 2.0, multiple TT organization (optional):
+	 *	two interfaces, protocols 1 (like single TT)
+	 *	and 2 (multiple TT mode) ... config is
+	 *	sometimes settable
+	 *	NOT IMPLEMENTED
+	 */
+
+	/* one interface */
+	0x09,       /*  __u8  if_bLength; */
+	0x04,       /*  __u8  if_bDescriptorType; Interface */
+	0x00,       /*  __u8  if_bInterfaceNumber; */
+	0x00,       /*  __u8  if_bAlternateSetting; */
+	0x01,       /*  __u8  if_bNumEndpoints; */
+	0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,       /*  __u8  if_bInterfaceSubClass; */
+	0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
+	0x00,       /*  __u8  if_iInterface; */
+     
+	/* one endpoint (status change endpoint) */
+	0x07,       /*  __u8  ep_bLength; */
+	0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+ 	0x03,       /*  __u8  ep_bmAttributes; Interrupt */
+ 	0x02, 0x00, /*  __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
+	0x0c        /*  __u8  ep_bInterval; (12ms -- usb 2.0 spec) */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * helper routine for returning string descriptors in UTF-16LE
+ * input can actually be ISO-8859-1; ASCII is its 7-bit subset
+ */
+static int ascii2utf (char *ascii, u8 *utf, int utfmax)
+{
+	int retval;
+
+	for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
+		*utf++ = *ascii++ & 0x7f;
+		*utf++ = 0;
+	}
+	return retval;
+}
+
+/*
+ * rh_string - provides manufacturer, product and serial strings for root hub
+ * @id: the string ID number (1: serial number, 2: product, 3: vendor)
+ * @pci_desc: PCI device descriptor for the relevant HC
+ * @type: string describing our driver 
+ * @data: return packet in UTF-16 LE
+ * @len: length of the return packet
+ *
+ * Produces either a manufacturer, product or serial number string for the
+ * virtual root hub device.
+ */
+static int rh_string (
+	int		id,
+	struct pci_dev	*pci_desc,
+	char		*type,
+	u8		*data,
+	int		len
+) {
+	char buf [100];
+
+	// language ids
+	if (id == 0) {
+		*data++ = 4; *data++ = 3;	/* 4 bytes string data */
+		*data++ = 0; *data++ = 0;	/* some language id */
+		return 4;
+
+	// serial number
+	} else if (id == 1) {
+		strcpy (buf, pci_desc->slot_name);
+
+	// product description
+	} else if (id == 2) {
+                strcpy (buf, pci_desc->name);
+
+ 	// id 3 == vendor description
+	} else if (id == 3) {
+                sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE, type);
+
+	// unsupported IDs --> "protocol stall"
+	} else
+	    return 0;
+
+	data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
+	data [1] = 3;	/* type == string */
+	return data [0];
+}
+
+
+/* Root hub control transfers execute synchronously */
+static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
+{
+	devrequest	*cmd = (devrequest *) urb->setup_packet;
+ 	u16		typeReq, wValue, wIndex, wLength;
+	const u8	*bufp = 0;
+	u8		*ubuf = urb->transfer_buffer;
+	int		len = 0;
+
+	typeReq  = (cmd->requesttype << 8) | cmd->request;
+	wValue   = le16_to_cpu (cmd->value);
+	wIndex   = le16_to_cpu (cmd->index);
+	wLength  = le16_to_cpu (cmd->length);
+
+	if (wLength > urb->transfer_buffer_length)
+		goto error;
+
+	/* set up for success */
+	urb->status = 0;
+	urb->actual_length = wLength;
+	switch (typeReq) {
+
+	/* DEVICE REQUESTS */
+
+	case DeviceRequest | USB_REQ_GET_STATUS:
+		// DEVICE_REMOTE_WAKEUP
+		ubuf [0] = 1; // selfpowered
+		ubuf [1] = 0;
+			/* FALLTHROUGH */
+	case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
+	case DeviceOutRequest | USB_REQ_SET_FEATURE:
+		dbg ("no device features yet yet");
+		break;
+	case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+		ubuf [0] = 1;
+			/* FALLTHROUGH */
+	case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+		break;
+	case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+		switch (wValue & 0xff00) {
+		case USB_DT_DEVICE << 8:
+			if (hcd->driver->flags & HCD_USB2)
+				bufp = usb2_rh_dev_descriptor;
+			else if (hcd->driver->flags & HCD_USB11)
+				bufp = usb11_rh_dev_descriptor;
+			else
+				goto error;
+			len = 18;
+			break;
+		case USB_DT_CONFIG << 8:
+			bufp = rh_config_descriptor;
+			len = sizeof rh_config_descriptor;
+			break;
+		case USB_DT_STRING << 8:
+			urb->actual_length = rh_string (
+				wValue & 0xff,
+				 hcd->pdev,
+				(char *) hcd->description,
+				ubuf, wLength);
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case DeviceRequest | USB_REQ_GET_INTERFACE:
+		ubuf [0] = 0;
+			/* FALLTHROUGH */
+	case DeviceOutRequest | USB_REQ_SET_INTERFACE:
+		break;
+	case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+		// wValue == urb->dev->devaddr
+		dbg ("%s root hub device address %d",
+			hcd->bus_name, wValue);
+		break;
+
+	/* INTERFACE REQUESTS (no defined feature/status flags) */
+
+	/* ENDPOINT REQUESTS */
+
+	case EndpointRequest | USB_REQ_GET_STATUS:
+		// ENDPOINT_HALT flag
+		ubuf [0] = 0;
+		ubuf [1] = 0;
+			/* FALLTHROUGH */
+	case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
+	case EndpointOutRequest | USB_REQ_SET_FEATURE:
+		dbg ("no endpoint features yet");
+		break;
+
+	/* CLASS REQUESTS (and errors) */
+
+	default:
+		/* non-generic request */
+		urb->status = hcd->driver->hub_control (hcd,
+			typeReq, wValue, wIndex,
+			ubuf, wLength);
+		break;
+error:
+		/* "protocol stall" on error */
+		urb->status = -EPIPE;
+		dbg ("unsupported hub control message (maxchild %d)",
+				urb->dev->maxchild);
+	}
+	if (urb->status) {
+		urb->actual_length = 0;
+		dbg ("CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d",
+			typeReq, wValue, wIndex, wLength, urb->status);
+	}
+	if (bufp) {
+		if (urb->transfer_buffer_length < len)
+			len = urb->transfer_buffer_length;
+		urb->actual_length = len;
+		// always USB_DIR_IN, toward host
+		memcpy (ubuf, bufp, len);
+	}
+
+	/* any errors get returned through the urb completion */
+	usb_hcd_giveback_urb (hcd, urb);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Root Hub interrupt transfers are synthesized with a timer.
+ * Completions are called in_interrupt() but not in_irq().
+ */
+
+static void rh_report_status (unsigned long ptr);
+
+static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) 
+{
+	int	len = 1 + (urb->dev->maxchild / 8);
+
+	/* rh_timer protected by hcd_data_lock */
+	if (timer_pending (&hcd->rh_timer)
+			|| urb->status != -EINPROGRESS
+			|| !HCD_IS_RUNNING (hcd->state)
+			|| urb->transfer_buffer_length < len) {
+		dbg ("not queuing status urb, stat %d", urb->status);
+		return -EINVAL;
+	}
+
+	urb->hcpriv = hcd;	/* nonzero to indicate it's queued */
+	init_timer (&hcd->rh_timer);
+	hcd->rh_timer.function = rh_report_status;
+	hcd->rh_timer.data = (unsigned long) urb;
+	hcd->rh_timer.expires = jiffies
+		+ (HZ * (urb->interval < 30
+				? 30
+				: urb->interval)) / 1000;
+	add_timer (&hcd->rh_timer);
+	return 0;
+}
+
+/* timer callback */
+
+static void rh_report_status (unsigned long ptr)
+{
+	struct urb	*urb;
+	struct usb_hcd	*hcd;
+	int		length;
+	unsigned long	flags;
+
+	urb = (struct urb *) ptr;
+	spin_lock_irqsave (&urb->lock, flags);
+	if (!urb->dev) {
+		spin_unlock_irqrestore (&urb->lock, flags);
+		return;
+	}
+
+	hcd = urb->dev->bus->hcpriv;
+	if (urb->status == -EINPROGRESS) {
+		if (HCD_IS_RUNNING (hcd->state)) {
+			length = hcd->driver->hub_status_data (hcd,
+					urb->transfer_buffer);
+			spin_unlock_irqrestore (&urb->lock, flags);
+			if (length > 0) {
+				urb->actual_length = length;
+				urb->status = 0;
+				urb->complete (urb);
+			}
+			spin_lock_irqsave (&hcd_data_lock, flags);
+			urb->status = -EINPROGRESS;
+			if (HCD_IS_RUNNING (hcd->state)
+					&& rh_status_urb (hcd, urb) != 0) {
+				/* another driver snuck in? */
+				dbg ("%s, can't resubmit roothub status urb?",
+					hcd->bus_name);
+				spin_unlock_irqrestore (&hcd_data_lock, flags);
+				BUG ();
+			}
+			spin_unlock_irqrestore (&hcd_data_lock, flags);
+		} else
+			spin_unlock_irqrestore (&urb->lock, flags);
+	} else {
+		/* this urb's been unlinked */
+		urb->hcpriv = 0;
+		spin_unlock_irqrestore (&urb->lock, flags);
+
+		usb_hcd_giveback_urb (hcd, urb);
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
+{
+	if (usb_pipeint (urb->pipe)) {
+		int		retval;
+		unsigned long	flags;
+
+		spin_lock_irqsave (&hcd_data_lock, flags);
+		retval = rh_status_urb (hcd, urb);
+		spin_unlock_irqrestore (&hcd_data_lock, flags);
+		return retval;
+	}
+	if (usb_pipecontrol (urb->pipe))
+		return rh_call_control (hcd, urb);
+	else
+		return -EINVAL;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb)
+{
+	unsigned long	flags;
+
+	spin_lock_irqsave (&hcd_data_lock, flags);
+	del_timer_sync (&hcd->rh_timer);
+	hcd->rh_timer.data = 0;
+	spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+	/* we rely on RH callback code not unlinking its URB! */
+	usb_hcd_giveback_urb (hcd, urb);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_PCI
+
+/* PCI-based HCs are normal, but custom bus glue should be ok */
+
+static void hcd_irq (int irq, void *__hcd, struct pt_regs *r);
+static void hc_died (struct usb_hcd *hcd);
+
+/*-------------------------------------------------------------------------*/
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * usb_hcd_pci_probe - initialize PCI-based HCDs
+ * @dev: USB Host Controller being probed
+ * @id: pci hotplug id connecting controller to HCD framework
+ *
+ * Allocates basic PCI resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ * Store this function in the HCD's struct pci_driver as probe().
+ */
+int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct hc_driver	*driver;
+	unsigned long		resource, len;
+	void			*base;
+	u8			latency, limit;
+	struct usb_bus		*bus;
+	struct usb_hcd		*hcd;
+	int			retval, region;
+	char			buf [8], *bufp = buf;
+
+	if (!id || !(driver = (struct hc_driver *) id->driver_data))
+		return -EINVAL;
+
+	if (pci_enable_device (dev) < 0)
+		return -ENODEV;
+	
+        if (!dev->irq) {
+        	err ("Found HC with no IRQ.  Check BIOS/PCI %s setup!",
+			dev->slot_name);
+   	        return -ENODEV;
+        }
+	
+	if (driver->flags & HCD_MEMORY) {	// EHCI, OHCI
+		region = 0;
+		resource = pci_resource_start (dev, 0);
+		len = pci_resource_len (dev, 0);
+		if (!request_mem_region (resource, len, driver->description)) {
+			dbg ("controller already in use");
+			return -EBUSY;
+		}
+		base = ioremap_nocache (resource, len);
+		if (base == NULL) {
+			dbg ("error mapping memory");
+			retval = -EFAULT;
+clean_1:
+			release_mem_region (resource, len);
+			err ("init %s fail, %d", dev->slot_name, retval);
+			return retval;
+		}
+
+	} else { 				// UHCI
+		resource = len = 0;
+		for (region = 0; region < PCI_ROM_RESOURCE; region++) {
+			if (!(pci_resource_flags (dev, region) & IORESOURCE_IO))
+				continue;
+
+			resource = pci_resource_start (dev, region);
+			len = pci_resource_len (dev, region);
+			if (request_region (resource, len,
+					driver->description))
+				break;
+		}
+		if (region == PCI_ROM_RESOURCE) {
+			dbg ("no i/o regions available");
+			return -EBUSY;
+		}
+		base = (void *) resource;
+	}
+
+	// driver->start(), later on, will transfer device from
+	// control by SMM/BIOS to control by Linux (if needed)
+
+	pci_set_master (dev);
+	hcd = driver->hcd_alloc ();
+	if (hcd == NULL){
+		dbg ("hcd alloc fail");
+		retval = -ENOMEM;
+clean_2:
+		if (driver->flags & HCD_MEMORY) {
+			iounmap (base);
+			goto clean_1;
+		} else {
+			release_region (resource, len);
+			err ("init %s fail, %d", dev->slot_name, retval);
+			return retval;
+		}
+	}
+	dev->driver_data = hcd;
+	hcd->driver = driver;
+	hcd->description = driver->description;
+	hcd->pdev = dev;
+	info ("%s @ %s, %s", hcd->description,  dev->slot_name, dev->name);
+
+	pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
+	if (latency) {
+		pci_read_config_byte (dev, PCI_MAX_LAT, &limit);
+		if (limit && limit < latency) {
+			dbg ("PCI latency reduced to max %d", limit);
+			pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit);
+		}
+	}
+
+#ifndef __sparc__
+	sprintf (buf, "%d", dev->irq);
+#else
+	bufp = __irq_itoa(irq);
+#endif
+	if (request_irq (dev->irq, hcd_irq, SA_SHIRQ, hcd->description, hcd)
+			!= 0) {
+		err ("request interrupt %s failed", bufp);
+		retval = -EBUSY;
+clean_3:
+		driver->hcd_free (hcd);
+		goto clean_2;
+	}
+	hcd->irq = dev->irq;
+
+	hcd->regs = base;
+	hcd->region = region;
+	info ("irq %s, %s %p", bufp,
+		(driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
+		base);
+
+// FIXME simpler: make "bus" be that data, not pointer to it.
+	bus = usb_alloc_bus (&hcd_operations);
+	if (bus == NULL) {
+		dbg ("usb_alloc_bus fail");
+		retval = -ENOMEM;
+		free_irq (dev->irq, hcd);
+		goto clean_3;
+	}
+	hcd->bus = bus;
+	hcd->bus_name = dev->slot_name;
+	bus->hcpriv = (void *) hcd;
+
+	INIT_LIST_HEAD (&hcd->dev_list);
+	INIT_LIST_HEAD (&hcd->hcd_list);
+
+	down (&hcd_list_lock);
+	list_add (&hcd->hcd_list, &hcd_list);
+	up (&hcd_list_lock);
+
+	usb_register_bus (bus);
+
+	if ((retval = driver->start (hcd)) < 0)
+		usb_hcd_pci_remove (dev);
+
+	return retval;
+} 
+EXPORT_SYMBOL (usb_hcd_pci_probe);
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs
+ * @dev: USB Host Controller being removed
+ *
+ * Reverses the effect of usb_hcd_pci_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ * Store this function in the HCD's struct pci_driver as remove().
+ */
+void usb_hcd_pci_remove (struct pci_dev *dev)
+{
+	struct usb_hcd		*hcd;
+	struct usb_device	*hub;
+
+	hcd = (struct usb_hcd *) dev->driver_data;
+	if (!hcd)
+		return;
+	info ("remove: %s, state %x", hcd->bus_name, hcd->state);
+
+	if (in_interrupt ()) BUG ();
+
+	hub = hcd->bus->root_hub;
+	hcd->state = USB_STATE_QUIESCING;
+
+	dbg ("%s: roothub graceful disconnect", hcd->bus_name);
+	usb_disconnect (&hub);
+	// usb_disconnect (&hcd->bus->root_hub);
+
+	hcd->driver->stop (hcd);
+	hcd->state = USB_STATE_HALT;
+
+	free_irq (hcd->irq, hcd);
+	if (hcd->driver->flags & HCD_MEMORY) {
+		iounmap (hcd->regs);
+		release_mem_region (pci_resource_start (dev, 0),
+			pci_resource_len (dev, 0));
+	} else {
+		release_region (pci_resource_start (dev, hcd->region),
+			pci_resource_len (dev, hcd->region));
+	}
+
+	down (&hcd_list_lock);
+	list_del (&hcd->hcd_list);
+	up (&hcd_list_lock);
+
+	usb_deregister_bus (hcd->bus);
+	usb_free_bus (hcd->bus);
+	hcd->bus = NULL;
+
+	hcd->driver->hcd_free (hcd);
+}
+EXPORT_SYMBOL (usb_hcd_pci_remove);
+
+
+#ifdef	CONFIG_PM
+
+/*
+ * Some "sleep" power levels imply updating struct usb_driver
+ * to include a callback asking hcds to do their bit by checking
+ * if all the drivers can suspend.  Gets involved with remote wakeup.
+ *
+ * If there are pending urbs, then HCs will need to access memory,
+ * causing extra power drain.  New sleep()/wakeup() PM calls might
+ * be needed, beyond PCI suspend()/resume().  The root hub timer
+ * still be accessing memory though ...
+ *
+ * FIXME:  USB should have some power budgeting support working with
+ * all kinds of hubs.
+ *
+ * FIXME:  This assumes only D0->D3 suspend and D3->D0 resume.
+ * D1 and D2 states should do something, yes?
+ *
+ * FIXME:  Should provide generic enable_wake(), calling pci_enable_wake()
+ * for all supported states, so that USB remote wakeup can work for any
+ * devices that support it (and are connected via powered hubs).
+ *
+ * FIXME:  resume doesn't seem to work right any more...
+ */
+
+
+// 2.4 kernels have issued concurrent resumes (w/APM)
+// we defend against that error; PCI doesn't yet.
+
+/**
+ * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
+ * @dev: USB Host Controller being suspended
+ *
+ * Store this function in the HCD's struct pci_driver as suspend().
+ */
+int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
+{
+	struct usb_hcd		*hcd;
+	int			retval;
+
+	hcd = (struct usb_hcd *) dev->driver_data;
+	info ("suspend %s to state %d", hcd->bus_name, state);
+
+	pci_save_state (dev, hcd->pci_state);
+
+	// FIXME for all connected devices, leaf-to-root:
+	// driver->suspend()
+	// proposed "new 2.5 driver model" will automate that
+
+	/* driver may want to disable DMA etc */
+	retval = hcd->driver->suspend (hcd, state);
+	hcd->state = USB_STATE_SUSPENDED;
+
+ 	pci_set_power_state (dev, state);
+	return retval;
+}
+EXPORT_SYMBOL (usb_hcd_pci_suspend);
+
+/**
+ * usb_hcd_pci_resume - power management resume of a PCI-based HCD
+ * @dev: USB Host Controller being resumed
+ *
+ * Store this function in the HCD's struct pci_driver as resume().
+ */
+int usb_hcd_pci_resume (struct pci_dev *dev)
+{
+	struct usb_hcd		*hcd;
+	int			retval;
+
+	hcd = (struct usb_hcd *) dev->driver_data;
+	info ("resume %s", hcd->bus_name);
+
+	/* guard against multiple resumes (APM bug?) */
+	atomic_inc (&hcd->resume_count);
+	if (atomic_read (&hcd->resume_count) != 1) {
+		err ("concurrent PCI resumes for %s", hcd->bus_name);
+		retval = 0;
+		goto done;
+	}
+
+	retval = -EBUSY;
+	if (hcd->state != USB_STATE_SUSPENDED) {
+		dbg ("can't resume, not suspended!");
+		goto done;
+	}
+	hcd->state = USB_STATE_RESUMING;
+
+	pci_set_power_state (dev, 0);
+	pci_restore_state (dev, hcd->pci_state);
+
+	retval = hcd->driver->resume (hcd);
+	if (!HCD_IS_RUNNING (hcd->state)) {
+		dbg ("resume %s failure, retval %d", hcd->bus_name, retval);
+		hc_died (hcd);
+// FIXME:  recover, reset etc.
+	} else {
+		// FIXME for all connected devices, root-to-leaf:
+		// driver->resume ();
+		// proposed "new 2.5 driver model" will automate that
+	}
+
+done:
+	atomic_dec (&hcd->resume_count);
+	return retval;
+}
+EXPORT_SYMBOL (usb_hcd_pci_resume);
+
+#endif	/* CONFIG_PM */
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Generic HC operations.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* called from khubd, or root hub init threads for hcd-private init */
+static int hcd_alloc_dev (struct usb_device *udev)
+{
+	struct hcd_dev		*dev;
+	struct usb_hcd		*hcd;
+	unsigned long		flags;
+
+	if (!udev || udev->hcpriv)
+		return -EINVAL;
+	if (!udev->bus || !udev->bus->hcpriv)
+		return -ENODEV;
+	hcd = udev->bus->hcpriv;
+	if (hcd->state == USB_STATE_QUIESCING)
+		return -ENOLINK;
+
+	dev = (struct hcd_dev *) kmalloc (sizeof *dev, GFP_KERNEL);
+	if (dev == NULL)
+		return -ENOMEM;
+	memset (dev, 0, sizeof *dev);
+
+	INIT_LIST_HEAD (&dev->dev_list);
+	INIT_LIST_HEAD (&dev->urb_list);
+
+	spin_lock_irqsave (&hcd_data_lock, flags);
+	list_add (&dev->dev_list, &hcd->dev_list);
+	// refcount is implicit
+	udev->hcpriv = dev;
+	spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void hc_died (struct usb_hcd *hcd)
+{
+	struct list_head	*devlist, *urblist;
+	struct hcd_dev		*dev;
+	struct urb		*urb;
+	unsigned long		flags;
+	
+	/* flag every pending urb as done */
+	spin_lock_irqsave (&hcd_data_lock, flags);
+	list_for_each (devlist, &hcd->dev_list) {
+		dev = list_entry (devlist, struct hcd_dev, dev_list);
+		list_for_each (urblist, &dev->urb_list) {
+			urb = list_entry (urblist, struct urb, urb_list);
+			dbg ("shutdown %s urb %p pipe %x, current status %d",
+				hcd->bus_name, urb, urb->pipe, urb->status);
+			if (urb->status == -EINPROGRESS)
+				urb->status = -ESHUTDOWN;
+		}
+	}
+	urb = (struct urb *) hcd->rh_timer.data;
+	if (urb)
+		urb->status = -ESHUTDOWN;
+	spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+	if (urb)
+		rh_status_dequeue (hcd, urb);
+	hcd->driver->stop (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* may be called in any context with a valid urb->dev usecount */
+/* caller surrenders "ownership" of urb (and chain at urb->next).  */
+
+static int hcd_submit_urb (struct urb *urb)
+{
+	int			status;
+	struct usb_hcd		*hcd;
+	struct hcd_dev		*dev;
+	unsigned long		flags;
+	int			pipe;
+	int			mem_flags;
+
+	if (!urb || urb->hcpriv || !urb->complete)
+		return -EINVAL;
+
+	urb->status = -EINPROGRESS;
+	urb->actual_length = 0;
+	INIT_LIST_HEAD (&urb->urb_list);
+
+	if (!urb->dev || !urb->dev->bus || urb->dev->devnum <= 0)
+		return -ENODEV;
+	hcd = urb->dev->bus->hcpriv;
+	dev = urb->dev->hcpriv;
+	if (!hcd || !dev)
+		return -ENODEV;
+
+	/* can't submit new urbs when quiescing, halted, ... */
+	if (hcd->state == USB_STATE_QUIESCING || !HCD_IS_RUNNING (hcd->state))
+		return -ESHUTDOWN;
+	pipe = urb->pipe;
+	if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe),
+			usb_pipeout (pipe)))
+		return -EPIPE;
+
+	// FIXME paging/swapping requests over USB should not use GFP_KERNEL
+	// and might even need to use GFP_NOIO ... that flag actually needs
+	// to be passed from the higher level.
+	mem_flags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL;
+
+#ifdef DEBUG
+	{
+	unsigned int	orig_flags = urb->transfer_flags;
+	unsigned int	allowed;
+
+	/* enforce simple/standard policy */
+	allowed = USB_ASYNC_UNLINK;	// affects later unlinks
+	allowed |= USB_NO_FSBR;		// only affects UHCI
+	switch (usb_pipetype (pipe)) {
+	case PIPE_CONTROL:
+		allowed |= USB_DISABLE_SPD;
+		break;
+	case PIPE_BULK:
+		allowed |= USB_DISABLE_SPD | USB_QUEUE_BULK
+				| USB_ZERO_PACKET | URB_NO_INTERRUPT;
+		break;
+	case PIPE_INTERRUPT:
+		allowed |= USB_DISABLE_SPD;
+		break;
+	case PIPE_ISOCHRONOUS:
+		allowed |= USB_ISO_ASAP;
+		break;
+	}
+	urb->transfer_flags &= allowed;
+
+	/* warn if submitter gave bogus flags */
+	if (urb->transfer_flags != orig_flags)
+		warn ("BOGUS urb flags, %x --> %x",
+			orig_flags, urb->transfer_flags);
+	}
+#endif
+	/*
+	 * FIXME:  alloc periodic bandwidth here, for interrupt and iso?
+	 * Need to look at the ring submit mechanism for iso tds ... they
+	 * aren't actually "periodic" in 2.4 kernels.
+	 *
+	 * FIXME:  make urb timeouts be generic, keeping the HCD cores
+	 * as simple as possible.
+	 */
+
+	// NOTE:  a generic device/urb monitoring hook would go here.
+	// hcd_monitor_hook(MONITOR_URB_SUBMIT, urb)
+	// It would catch submission paths for all urbs.
+
+	/*
+	 * Atomically queue the urb,  first to our records, then to the HCD.
+	 * Access to urb->status is controlled by urb->lock ... changes on
+	 * i/o completion (normal or fault) or unlinking.
+	 */
+
+	// FIXME:  verify that quiescing hc works right (RH cleans up)
+
+	spin_lock_irqsave (&hcd_data_lock, flags);
+	if (HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_QUIESCING) {
+		usb_inc_dev_use (urb->dev);
+		list_add (&urb->urb_list, &dev->urb_list);
+		status = 0;
+	} else {
+		INIT_LIST_HEAD (&urb->urb_list);
+		status = -ESHUTDOWN;
+	}
+	spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+	if (!status) {
+		if (urb->dev == hcd->bus->root_hub)
+			status = rh_urb_enqueue (hcd, urb);
+		else
+			status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
+	}
+	if (status) {
+		if (urb->dev) {
+			urb->status = status;
+			usb_hcd_giveback_urb (hcd, urb);
+		}
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* called in any context */
+static int hcd_get_frame_number (struct usb_device *udev)
+{
+	struct usb_hcd	*hcd = (struct usb_hcd *)udev->bus->hcpriv;
+	return hcd->driver->get_frame_number (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+struct completion_splice {		// modified urb context:
+	/* did we complete? */
+	int			done;
+
+	/* original urb data */
+	void			(*complete)(struct urb *);
+	void			*context;
+};
+
+static void unlink_complete (struct urb *urb)
+{
+	struct completion_splice	*splice;
+
+	splice = (struct completion_splice *) urb->context;
+
+	/* issue original completion call */
+	urb->complete = splice->complete;
+	urb->context = splice->context;
+	urb->complete (urb);
+
+	splice->done = 1;
+}
+
+/*
+ * called in any context; note ASYNC_UNLINK restrictions
+ *
+ * caller guarantees urb won't be recycled till both unlink()
+ * and the urb's completion function return
+ */
+static int hcd_unlink_urb (struct urb *urb)
+{
+	struct hcd_dev			*dev;
+	struct usb_hcd			*hcd = 0;
+	unsigned long			flags;
+	struct completion_splice	splice;
+	int				retval;
+
+	if (!urb)
+		return -EINVAL;
+
+	// FIXME:  add some explicit records to flag the
+	// state where the URB is "in periodic completion".
+	// Workaround is for driver to set the urb status
+	// to "-EINPROGRESS", so it can get through here
+	// and unlink from the completion handler.
+
+	/*
+	 * we contend for urb->status with the hcd core,
+	 * which changes it while returning the urb.
+	 */
+	spin_lock_irqsave (&urb->lock, flags);
+	if (!urb->hcpriv
+			|| urb->status != -EINPROGRESS
+			|| urb->transfer_flags & USB_TIMEOUT_KILLED) {
+		retval = -EINVAL;
+		goto done;
+	}
+
+	if (!urb->dev || !urb->dev->bus) {
+		retval = -ENODEV;
+		goto done;
+	}
+	dev = urb->dev->hcpriv;
+	hcd = urb->dev->bus->hcpriv;
+	if (!dev || !hcd) {
+		retval = -ENODEV;
+		goto done;
+	}
+
+	/* maybe set up to block on completion notification */
+	if ((urb->transfer_flags & USB_TIMEOUT_KILLED))
+		urb->status = -ETIMEDOUT;
+	else if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
+		if (in_interrupt ()) {
+			dbg ("non-async unlink in_interrupt");
+			retval = -EWOULDBLOCK;
+			goto done;
+		}
+		/* synchronous unlink: block till we see the completion */
+		splice.done = 0;
+		splice.complete = urb->complete;
+		splice.context = urb->context;
+		urb->complete = unlink_complete;
+		urb->context = &splice;
+		urb->status = -ENOENT;
+	} else {
+		/* asynchronous unlink */
+		urb->status = -ECONNRESET;
+	}
+	spin_unlock_irqrestore (&urb->lock, flags);
+
+	if (urb == (struct urb *) hcd->rh_timer.data) {
+		rh_status_dequeue (hcd, urb);
+		retval = 0;
+	} else {
+		retval = hcd->driver->urb_dequeue (hcd, urb);
+// FIXME:  if retval and we tried to splice, whoa!!
+if (retval && urb->status == -ENOENT) err ("whoa! retval %d", retval);
+	}
+
+    	/* block till giveback, if needed */
+	if (!(urb->transfer_flags & (USB_ASYNC_UNLINK|USB_TIMEOUT_KILLED))
+			&& HCD_IS_RUNNING (hcd->state)
+			&& !retval) {
+		while (!splice.done) {
+			set_current_state (TASK_UNINTERRUPTIBLE);
+			schedule_timeout ((2/*msec*/ * HZ) / 1000);
+			dbg ("%s: wait for giveback urb %p",
+				hcd->bus_name, urb);
+		}
+	}
+	goto bye;
+done:
+	spin_unlock_irqrestore (&urb->lock, flags);
+bye:
+	if (retval)
+		dbg ("%s: hcd_unlink_urb fail %d",
+		    hcd ? hcd->bus_name : "(no bus?)",
+		    retval);
+	return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* called by khubd, rmmod, apmd, or other thread for hcd-private cleanup */
+
+// FIXME:  likely best to have explicit per-setting (config+alt)
+// setup primitives in the usbcore-to-hcd driver API, so nothing
+// is implicit.  kernel 2.5 needs a bunch of config cleanup...
+
+static int hcd_free_dev (struct usb_device *udev)
+{
+	struct hcd_dev		*dev;
+	struct usb_hcd		*hcd;
+	unsigned long		flags;
+
+	if (!udev || !udev->hcpriv)
+		return -EINVAL;
+
+	if (!udev->bus || !udev->bus->hcpriv)
+		return -ENODEV;
+
+	// should udev->devnum == -1 ??
+
+	dev = udev->hcpriv;
+	hcd = udev->bus->hcpriv;
+
+	/* device driver problem with refcounts? */
+	if (!list_empty (&dev->urb_list)) {
+		dbg ("free busy dev, %s devnum %d (bug!)",
+			hcd->bus_name, udev->devnum);
+		return -EINVAL;
+	}
+
+	hcd->driver->free_config (hcd, udev);
+
+	spin_lock_irqsave (&hcd_data_lock, flags);
+	list_del (&dev->dev_list);
+	udev->hcpriv = NULL;
+	spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+	kfree (dev);
+	return 0;
+}
+
+static struct usb_operations hcd_operations = {
+	allocate:		hcd_alloc_dev,
+	get_frame_number:	hcd_get_frame_number,
+	submit_urb:		hcd_submit_urb,
+	unlink_urb:		hcd_unlink_urb,
+	deallocate:		hcd_free_dev,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static void hcd_irq (int irq, void *__hcd, struct pt_regs * r)
+{
+	struct usb_hcd		*hcd = __hcd;
+	int			start = hcd->state;
+
+	hcd->driver->irq (hcd);
+	if (hcd->state != start && hcd->state == USB_STATE_HALT)
+		hc_died (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_hcd_giveback_urb - return URB from HCD to device driver
+ * @hcd: host controller returning the URB
+ * @urb: urb being returned to the USB device driver.
+ *
+ * This hands the URB from HCD to its USB device driver, using its
+ * completion function.  The HCD has freed all per-urb resources
+ * (and is done using urb->hcpriv).  It also released all HCD locks;
+ * the device driver won't cause deadlocks if it resubmits this URB,
+ * and won't confuse things by modifying and resubmitting this one.
+ * Bandwidth and other resources will be deallocated.
+ *
+ * HCDs must not use this for periodic URBs that are still scheduled
+ * and will be reissued.  They should just call their completion handlers
+ * until the urb is returned to the device driver by unlinking.
+ *
+ * In common cases, urb->next will be submitted before the completion
+ * function gets called.  That's not done if the URB includes error
+ * status (including unlinking).
+ */
+void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
+{
+	unsigned long		flags;
+	struct usb_device	*dev;
+
+	/* Release periodic transfer bandwidth */
+	if (urb->bandwidth) {
+		switch (usb_pipetype (urb->pipe)) {
+		case PIPE_INTERRUPT:
+			usb_release_bandwidth (urb->dev, urb, 0);
+			break;
+		case PIPE_ISOCHRONOUS:
+			usb_release_bandwidth (urb->dev, urb, 1);
+			break;
+		}
+	}
+
+	/* clear all state linking urb to this dev (and hcd) */
+
+	spin_lock_irqsave (&hcd_data_lock, flags);
+	list_del_init (&urb->urb_list);
+	dev = urb->dev;
+	urb->dev = NULL;
+	spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+	// NOTE:  a generic device/urb monitoring hook would go here.
+	// hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev)
+	// It would catch exit/unlink paths for all urbs, but non-exit
+	// completions for periodic urbs need hooks inside the HCD.
+	// hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev)
+
+	if (urb->status)
+		dbg ("giveback urb %p status %d", urb, urb->status);
+
+	/* if no error, make sure urb->next progresses */
+	else if (urb->next) {
+		int 	status;
+
+		status = usb_submit_urb (urb->next);
+		if (status) {
+			dbg ("urb %p chain fail, %d", urb->next, status);
+			urb->next->status = -ENOTCONN;
+		}
+
+		/* HCDs never modify the urb->next chain, and only use it here,
+		 * so that if urb->complete sees an URB there with -ENOTCONN,
+		 * it knows the driver chained it but it couldn't be submitted.
+		 */
+	}
+
+	/* pass ownership to the completion handler */
+	usb_dec_dev_use (dev);
+	urb->complete (urb);
+}
+EXPORT_SYMBOL (usb_hcd_giveback_urb);
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/hcd.h linux/drivers/usb/hcd.h
--- v2.5.1/linux/drivers/usb/hcd.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd.h	Tue Jan  1 13:52:10 2002
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * USB Host Controller Driver (usb_hcd) framework
+ *
+ * Since "struct usb_bus" is so thin, you can't share much code in it.
+ * This framework is a layer over that, and should be more sharable.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+struct usb_hcd {	/* usb_bus.hcpriv points to this */
+
+	/*
+	 * housekeeping
+	 */
+	struct usb_bus		*bus;		/* hcd is-a bus */
+	struct list_head	hcd_list;
+
+	const char		*bus_name;
+
+	const char		*description;	/* "ehci-hcd" etc */
+
+	struct timer_list	rh_timer;	/* drives root hub */
+	struct list_head	dev_list;	/* devices on this bus */
+
+	/*
+	 * hardware info/state
+	 */
+	struct hc_driver	*driver;	/* hw-specific hooks */
+	int			irq;		/* irq allocated */
+	void			*regs;		/* device memory/io */
+
+#ifdef	CONFIG_PCI
+	/* a few non-PCI controllers exist, mostly for OHCI */
+	struct pci_dev		*pdev;		/* pci is typical */
+	int			region;		/* pci region for regs */
+	u32			pci_state [16];	/* for PM state save */
+	atomic_t		resume_count;	/* multiple resumes issue */
+#endif
+
+	int			state;
+#	define	__ACTIVE		0x01
+#	define	__SLEEPY		0x02
+#	define	__SUSPEND		0x04
+#	define	__TRANSIENT		0x80
+
+#	define	USB_STATE_HALT		0
+#	define	USB_STATE_RUNNING	(__ACTIVE)
+#	define	USB_STATE_READY		(__ACTIVE|__SLEEPY)
+#	define	USB_STATE_QUIESCING	(__SUSPEND|__TRANSIENT|__ACTIVE)
+#	define	USB_STATE_RESUMING	(__SUSPEND|__TRANSIENT)
+#	define	USB_STATE_SUSPENDED	(__SUSPEND)
+
+#define	HCD_IS_RUNNING(state) ((state) & __ACTIVE)
+#define	HCD_IS_SUSPENDED(state) ((state) & __SUSPEND)
+
+	/* more shared queuing code would be good; it should support
+	 * smarter scheduling, handle transaction translators, etc;
+	 * input size of periodic table to an interrupt scheduler. 
+	 * (ohci 32, uhci 1024, ehci 256/512/1024).
+	 */
+};
+
+struct hcd_dev {	/* usb_device.hcpriv points to this */
+	struct list_head	dev_list;	/* on this hcd */
+	struct list_head	urb_list;	/* pending on this dev */
+
+	/* per-configuration HC/HCD state, such as QH or ED */
+	void			*ep[32];
+};
+
+// urb.hcpriv is really hardware-specific
+
+struct hcd_timeout {	/* timeouts we allocate */
+	struct list_head	timeout_list;
+	struct timer_list	timer;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* each driver provides one of these, and hardware init support */
+
+struct hc_driver {
+	const char	*description;	/* "ehci-hcd" etc */
+
+	/* irq handler */
+	void	(*irq) (struct usb_hcd *hcd);
+
+	int	flags;
+#define	HCD_MEMORY	0x0001		/* HC regs use memory (else I/O) */
+#define	HCD_USB11	0x0010		/* USB 1.1 */
+#define	HCD_USB2	0x0020		/* USB 2.0 */
+
+	/* called to init HCD and root hub */
+	int	(*start) (struct usb_hcd *hcd);
+
+	/* called after all devices were suspended */
+	int	(*suspend) (struct usb_hcd *hcd, u32 state);
+
+	/* called before any devices get resumed */
+	int	(*resume) (struct usb_hcd *hcd);
+
+	/* cleanly make HCD stop writing memory and doing I/O */
+	void	(*stop) (struct usb_hcd *hcd);
+
+	/* return current frame number */
+	int	(*get_frame_number) (struct usb_hcd *hcd);
+
+// FIXME: rework generic-to-specific HCD linkage (specific contains generic)
+
+	/* memory lifecycle */
+	struct usb_hcd	*(*hcd_alloc) (void);
+	void		(*hcd_free) (struct usb_hcd *hcd);
+
+	/* manage i/o requests, device state */
+	int	(*urb_enqueue) (struct usb_hcd *hcd, struct urb *urb,
+					int mem_flags);
+	int	(*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
+
+	// frees configuration resources -- allocated as needed during
+	// urb_enqueue, and not freed by urb_dequeue
+	void		(*free_config) (struct usb_hcd *hcd,
+				struct usb_device *dev);
+
+	/* root hub support */
+	int		(*hub_status_data) (struct usb_hcd *hcd, char *buf);
+	int		(*hub_control) (struct usb_hcd *hcd,
+				u16 typeReq, u16 wValue, u16 wIndex,
+				char *buf, u16 wLength);
+};
+
+extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
+
+#ifdef CONFIG_PCI
+
+extern int usb_hcd_pci_probe (struct pci_dev *dev,
+				const struct pci_device_id *id);
+extern void usb_hcd_pci_remove (struct pci_dev *dev);
+
+#ifdef CONFIG_PM
+// FIXME:  see Documentation/power/pci.txt (2.4.6 and later?)
+// extern int usb_hcd_pci_save_state (struct pci_dev *dev, u32 state);
+extern int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state);
+extern int usb_hcd_pci_resume (struct pci_dev *dev);
+// extern int usb_hcd_pci_enable_wake (struct pci_dev *dev, u32 state, int flg);
+#endif /* CONFIG_PM */
+
+#endif /* CONFIG_PCI */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * HCD Root Hub support
+ */
+
+#include "hub.h"
+
+/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */
+#define DeviceRequest \
+	((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
+#define DeviceOutRequest \
+	((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
+
+#define InterfaceRequest \
+	((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+
+#define EndpointRequest \
+	((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+#define EndpointOutRequest \
+	((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+
+/* table 9.6 standard features */
+#define DEVICE_REMOTE_WAKEUP	1
+#define ENDPOINT_HALT		0
+
+/* class requests from the USB 2.0 hub spec, table 11-15 */
+/* GetBusState and SetHubDescriptor are optional, omitted */
+#define ClearHubFeature		(0x2000 | USB_REQ_CLEAR_FEATURE)
+#define ClearPortFeature	(0x2300 | USB_REQ_CLEAR_FEATURE)
+#define GetHubDescriptor	(0xa000 | USB_REQ_GET_DESCRIPTOR)
+#define GetHubStatus		(0xa000 | USB_REQ_GET_STATUS)
+#define GetPortStatus		(0xa300 | USB_REQ_GET_STATUS)
+#define SetHubFeature		(0x2000 | USB_REQ_SET_FEATURE)
+#define SetPortFeature		(0x2300 | USB_REQ_SET_FEATURE)
+
+
+/*-------------------------------------------------------------------------*/
+
+/* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */
+// bleech -- resurfaced in 2.4.11 or 2.4.12
+#define bitmap 	DeviceRemovable
+
+
+/*-------------------------------------------------------------------------*/
+
+/* random stuff */
+
+#define	RUN_CONTEXT (in_irq () ? "in_irq" \
+		: (in_interrupt () ? "in_interrupt" : "can sleep"))
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/hiddev.c linux/drivers/usb/hiddev.c
--- v2.5.1/linux/drivers/usb/hiddev.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/usb/hiddev.c	Thu Jan  3 12:20:16 2002
@@ -218,7 +218,7 @@
 static int hiddev_open(struct inode * inode, struct file * file) {
 	struct hiddev_list *list;
 
-	int i = MINOR(inode->i_rdev) - HIDDEV_MINOR_BASE;
+	int i = minor(inode->i_rdev) - HIDDEV_MINOR_BASE;
 
 	if (i >= HIDDEV_MINORS || !hiddev_table[i])
 		return -ENODEV;
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/hpusbscsi.c linux/drivers/usb/hpusbscsi.c
--- v2.5.1/linux/drivers/usb/hpusbscsi.c	Tue Oct  9 15:15:02 2001
+++ linux/drivers/usb/hpusbscsi.c	Tue Dec 25 17:04:40 2001
@@ -117,7 +117,7 @@
 	(struct hpusbscsi *) new->ctempl.proc_dir = new;
 	new->ctempl.module = THIS_MODULE;
 
-	if (scsi_register_module (MODULE_SCSI_HA, &(new->ctempl)))
+	if (scsi_register_host(&new->ctempl))
 		goto err_out;
 
 	/* adding to list for module unload */
@@ -185,7 +185,7 @@
 		tmp = tmp->next;
 		o = (struct hpusbscsi *)old;
 		usb_unlink_urb(&o->controlurb);
-		scsi_unregister_module(MODULE_SCSI_HA,&o->ctempl);
+		scsi_unregister_host(&o->ctempl);
 		kfree(old);
 	}
 
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
--- v2.5.1/linux/drivers/usb/hub.c	Mon Nov 12 09:34:16 2001
+++ linux/drivers/usb/hub.c	Tue Jan  1 13:52:10 2002
@@ -35,7 +35,7 @@
 static DECLARE_MUTEX(usb_address0_sem);
 
 static LIST_HEAD(hub_event_list);	/* List of hubs needing servicing */
-static LIST_HEAD(hub_list);		/* List containing all of the hubs (for cleanup) */
+static LIST_HEAD(hub_list);		/* List of all hubs (for cleanup) */
 
 static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
 static int khubd_pid = 0;			/* PID of khubd */
@@ -110,22 +110,30 @@
 		data, sizeof(struct usb_hub_status), HZ);
 }
 
+/* completion function, fires on port status changes and various faults */
 static void hub_irq(struct urb *urb)
 {
 	struct usb_hub *hub = (struct usb_hub *)urb->context;
 	unsigned long flags;
 
-	/* Cause a hub reset after 10 consecutive errors */
-	if (urb->status) {
-		if (urb->status == -ENOENT)
-			return;
-
-		dbg("nonzero status in irq %d", urb->status);
+	switch (urb->status) {
+	case -ENOENT:		/* synchronous unlink */
+	case -ECONNRESET:	/* async unlink */
+	case -ESHUTDOWN:	/* hardware going away */
+		return;
 
+	default:		/* presumably an error */
+		/* Cause a hub reset after 10 consecutive errors */
+		dbg("hub '%s' status %d for interrupt transfer",
+			urb->dev->devpath, urb->status);
 		if ((++hub->nerrors < 10) || hub->error)
 			return;
-
 		hub->error = urb->status;
+		/* FALL THROUGH */
+	
+	/* let khubd handle things */
+	case 0:			/* we got data:  port status changed */
+		break;
 	}
 
 	hub->nerrors = 0;
@@ -152,7 +160,8 @@
 	wait_ms(hub->descriptor->bPwrOn2PwrGood * 2);
 }
 
-static int usb_hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor *endpoint)
+static int usb_hub_configure(struct usb_hub *hub,
+	struct usb_endpoint_descriptor *endpoint)
 {
 	struct usb_device *dev = hub->dev;
 	struct usb_hub_status hubstatus;
@@ -162,22 +171,30 @@
 
 	hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
 	if (!hub->descriptor) {
-		err("Unable to kmalloc %Zd bytes for hub descriptor", sizeof(*hub->descriptor));
+		err("Unable to kmalloc %Zd bytes for hub descriptor",
+			sizeof(*hub->descriptor));
 		return -1;
 	}
 
-	/* Request the entire hub descriptor. */
-	ret = usb_get_hub_descriptor(dev, hub->descriptor, sizeof(*hub->descriptor));
-		/* <hub->descriptor> is large enough for a hub with 127 ports;
-		 * the hub can/will return fewer bytes here. */
+	/* Request the entire hub descriptor.
+	 * hub->descriptor can handle USB_MAXCHILDREN ports,
+	 * but the hub can/will return fewer bytes here.
+	 */
+	ret = usb_get_hub_descriptor(dev, hub->descriptor,
+			sizeof(*hub->descriptor));
 	if (ret < 0) {
 		err("Unable to get hub descriptor (err = %d)", ret);
 		kfree(hub->descriptor);
 		return -1;
+	} else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN) {
+		err("Hub is too big! %d children", hub->descriptor->bNbrPorts);
+		kfree(hub->descriptor);
+		return -1;
 	}
 
 	dev->maxchild = hub->descriptor->bNbrPorts;
-	info("%d port%s detected", hub->descriptor->bNbrPorts, (hub->descriptor->bNbrPorts == 1) ? "" : "s");
+	info("%d port%s detected", dev->maxchild,
+		(dev->maxchild == 1) ? "" : "s");
 
 	le16_to_cpus(&hub->descriptor->wHubCharacteristics);
 
@@ -217,9 +234,12 @@
 			break;
 		case 1:
 			dbg("Single TT");
+			hub->tt.hub = dev;
 			break;
 		case 2:
-			dbg("Multiple TT");
+			dbg("TT per port");
+			hub->tt.hub = dev;
+			hub->tt.multi = 1;
 			break;
 		default:
 			dbg("Unrecognized hub protocol %d",
@@ -244,13 +264,18 @@
 	}
 
 	dbg("Port indicators are %s supported", 
-	    (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND) ? "" : "not");
+	    (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND)
+	    	? "" : "not");
 
-	dbg("power on to power good time: %dms", hub->descriptor->bPwrOn2PwrGood * 2);
-	dbg("hub controller current requirement: %dmA", hub->descriptor->bHubContrCurrent);
+	dbg("power on to power good time: %dms",
+		hub->descriptor->bPwrOn2PwrGood * 2);
+	dbg("hub controller current requirement: %dmA",
+		hub->descriptor->bHubContrCurrent);
 
 	for (i = 0; i < dev->maxchild; i++)
-		portstr[i] = hub->descriptor->DeviceRemovable[((i + 1) / 8)] & (1 << ((i + 1) % 8)) ? 'F' : 'R';
+		portstr[i] = hub->descriptor->DeviceRemovable
+			    [((i + 1) / 8)] & (1 << ((i + 1) % 8))
+			? 'F' : 'R';
 	portstr[dev->maxchild] = 0;
 
 	dbg("port removable status: %s", portstr);
@@ -265,7 +290,8 @@
 	le16_to_cpus(&hubstatus.wHubStatus);
 
 	dbg("local power source is %s",
-		(hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good");
+		(hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER)
+		? "lost (inactive)" : "good");
 
 	dbg("%sover-current condition exists",
 		(hubstatus.wHubStatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
@@ -337,14 +363,15 @@
 	}
 
 	/* If it's not an interrupt endpoint, we'd better punt! */
-	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) {
-		err("Device #%d is hub class, but has endpoint other than interrupt?",
+	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+			!= USB_ENDPOINT_XFER_INT) {
+		err("Device #%d is hub class, but endpoint is not interrupt?",
 			dev->devnum);
 		return NULL;
 	}
 
 	/* We found a hub */
-	info("USB hub found");
+	info("USB hub found at %s", dev->devpath);
 
 	hub = kmalloc(sizeof(*hub), GFP_KERNEL);
 	if (!hub) {
@@ -367,7 +394,7 @@
 	if (usb_hub_configure(hub, endpoint) >= 0)
 		return hub;
 
-	err("hub configuration failed for device #%d", dev->devnum);
+	err("hub configuration failed for device at %s", dev->devpath);
 
 	/* free hub, but first clean up its list. */
 	spin_lock_irqsave(&hub_event_lock, flags);
@@ -436,7 +463,8 @@
 				if (hub->children[i] == NULL)
 					info->port[i] = 0;
 				else
-					info->port[i] = hub->children[i]->devnum;
+					info->port[i] =
+						hub->children[i]->devnum;
 			}
 		}
 		spin_unlock_irqrestore(&hub_event_lock, flags);
@@ -493,7 +521,7 @@
 		}
 	}
 
-	err("cannot disconnect hub %d", dev->devnum);
+	err("cannot disconnect hub %s", dev->devpath);
 }
 
 #define HUB_RESET_TRIES		5
@@ -510,14 +538,17 @@
 	struct usb_port_status portsts;
 	unsigned short portchange, portstatus;
 
-	for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT; delay_time += delay) {
+	for (delay_time = 0;
+			delay_time < HUB_RESET_TIMEOUT;
+			delay_time += delay) {
 		/* wait to give the device a chance to reset */
 		wait_ms(delay);
 
 		/* read and decode port status */
 		ret = usb_get_port_status(hub, port + 1, &portsts);
 		if (ret < 0) {
-			err("get_port_status(%d) failed (err = %d)", port + 1, ret);
+			err("get_port_status(%d) failed (err = %d)",
+				port + 1, ret);
 			return -1;
 		}
 
@@ -546,8 +577,8 @@
 		if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
 			delay = HUB_LONG_RESET_TIME;
 
-		dbg("port %d of hub %d not reset yet, waiting %dms", port + 1,
-			hub->devnum, delay);
+		dbg("port %d of hub %s not reset yet, waiting %dms", port + 1,
+			hub->devpath, delay);
 	}
 
 	return -1;
@@ -566,17 +597,18 @@
 		/* return on disconnect or reset */
 		status = usb_hub_port_wait_reset(hub, port, dev, delay);
 		if (status != -1) {
-			usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_RESET);
+			usb_clear_port_feature(hub,
+				port + 1, USB_PORT_FEAT_C_RESET);
 			return status;
 		}
 
-		dbg("port %d of hub %d not enabled, trying reset again...",
-			port + 1, hub->devnum);
+		dbg("port %d of hub %s not enabled, trying reset again...",
+			port + 1, hub->devpath);
 		delay = HUB_LONG_RESET_TIME;
 	}
 
-	err("Cannot enable port %i of hub %d, disabling port.",
-		port + 1, hub->devnum);
+	err("Cannot enable port %i of hub %s, disabling port.",
+		port + 1, hub->devpath);
 	err("Maybe the USB cable is bad?");
 
 	return -1;
@@ -588,23 +620,24 @@
 
 	ret = usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE);
 	if (ret)
-		err("cannot disable port %d of hub %d (err = %d)",
-			port + 1, hub->devnum, ret);
+		err("cannot disable port %d of hub %s (err = %d)",
+			port + 1, hub->devpath, ret);
 }
 
-static void usb_hub_port_connect_change(struct usb_device *hub, int port,
+static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port,
 					struct usb_port_status *portsts)
 {
+	struct usb_device *hub = hubstate->dev;
 	struct usb_device *dev;
 	unsigned short portstatus, portchange;
 	unsigned int delay = HUB_SHORT_RESET_TIME;
 	int i;
-	char *portstr, *tempstr;
 
 	portstatus = le16_to_cpu(portsts->wPortStatus);
 	portchange = le16_to_cpu(portsts->wPortChange);
-	dbg("port %d, portstatus %x, change %x, %s",
-		port + 1, portstatus, portchange, portspeed (portstatus));
+	dbg("hub %s port %d, portstatus %x, change %x, %s",
+		hub->devpath, port + 1,
+		portstatus, portchange, portspeed (portstatus));
 
 	/* Clear the connection change status */
 	usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);
@@ -630,11 +663,9 @@
 
 	down(&usb_address0_sem);
 
-	tempstr = kmalloc(1024, GFP_KERNEL);
-	portstr = kmalloc(1024, GFP_KERNEL);
-
 	for (i = 0; i < HUB_PROBE_TRIES; i++) {
-		struct usb_device *pdev, *cdev;
+		struct usb_device *pdev;
+		int	len;
 
 		/* Allocate a new device struct */
 		dev = usb_alloc_dev(hub, hub->bus);
@@ -645,41 +676,46 @@
 
 		hub->children[port] = dev;
 
-		/* Reset the device */
+		/* Reset the device, and detect its speed */
 		if (usb_hub_port_reset(hub, port, dev, delay)) {
 			usb_free_dev(dev);
 			break;
 		}
 
-		/* Find a new device ID for it */
+		/* Find a new address for it */
 		usb_connect(dev);
 
-		/* Create a readable topology string */
-		cdev = dev;
-		pdev = dev->parent;
-		if (portstr && tempstr) {
-			portstr[0] = 0;
-			while (pdev) {
-				int port;
-
-				for (port = 0; port < pdev->maxchild; port++)
-					if (pdev->children[port] == cdev)
-						break;
-
-				strcpy(tempstr, portstr);
-				if (!strlen(tempstr))
-					sprintf(portstr, "%d", port + 1);
-				else
-					sprintf(portstr, "%d/%s", port + 1, tempstr);
+		/* Set up TT records, if needed  */
+		if (hub->tt) {
+			dev->tt = hub->tt;
+			dev->ttport = hub->ttport;
+		} else if (dev->speed != USB_SPEED_HIGH
+				&& hub->speed == USB_SPEED_HIGH) {
+			dev->tt = &hubstate->tt;
+			dev->ttport = port + 1;
+		}
 
-				cdev = pdev;
-				pdev = pdev->parent;
-			}
-			info("USB new device connect on bus%d/%s, assigned device number %d",
-				dev->bus->busnum, portstr, dev->devnum);
-		} else
-			info("USB new device connect on bus%d, assigned device number %d",
-				dev->bus->busnum, dev->devnum);
+		/* Save readable and stable topology id, distinguishing
+		 * devices by location for diagnostics, tools, etc.  The
+		 * string is a path along hub ports, from the root.  Each
+		 * device's id will be stable until USB is re-cabled, and
+		 * hubs are often labled with these port numbers.
+		 *
+		 * Initial size: "/NN" times five hubs + NUL = 16 bytes max
+		 * (quite rare, since most hubs have 4-6 ports).
+		 */
+		pdev = dev->parent;
+		if (pdev->devpath [1] != '\0')	/* parent not root */
+			len = snprintf (dev->devpath, sizeof dev->devpath,
+				"%s/%d", pdev->devpath, port + 1);
+		else	/* root == "/", root port 2 == "/2" */
+			len = snprintf (dev->devpath, sizeof dev->devpath,
+				"/%d", port + 1);
+		if (len == sizeof dev->devpath)
+			warn ("devpath size! usb/%03d/%03d path %s",
+				dev->bus->busnum, dev->devnum, dev->devpath);
+		info("new USB device on bus %d path %s, assigned address %d",
+			dev->bus->busnum, dev->devpath, dev->devnum);
 
 		/* Run it through the hoops (find a driver, etc) */
 		if (!usb_new_device(dev))
@@ -696,10 +732,6 @@
 	usb_hub_port_disable(hub, port);
 done:
 	up(&usb_address0_sem);
-	if (portstr)
-		kfree(portstr);
-	if (tempstr)
-		kfree(tempstr);
 }
 
 static void usb_hub_events(void)
@@ -737,10 +769,12 @@
 		spin_unlock_irqrestore(&hub_event_lock, flags);
 
 		if (hub->error) {
-			dbg("resetting hub %d for error %d", dev->devnum, hub->error);
+			dbg("resetting hub %s for error %d",
+				dev->devpath, hub->error);
 
 			if (usb_hub_reset(hub)) {
-				err("error resetting hub %d - disconnecting", dev->devnum);
+				err("error resetting hub %s - disconnecting",
+					dev->devpath);
 				up(&hub->khubd_sem);
 				usb_hub_disconnect(dev);
 				continue;
@@ -756,7 +790,8 @@
 
 			ret = usb_get_port_status(dev, i + 1, &portsts);
 			if (ret < 0) {
-				err("get_port_status failed (err = %d)", ret);
+				err("hub %s get_port_status failed (err = %d)",
+					dev->devpath, ret);
 				continue;
 			}
 
@@ -764,55 +799,68 @@
 			portchange = le16_to_cpu(portsts.wPortChange);
 
 			if (portchange & USB_PORT_STAT_C_CONNECTION) {
-				dbg("port %d connection change", i + 1);
-
-				usb_hub_port_connect_change(dev, i, &portsts);
+				dbg("hub %s port %d connection change",
+					dev->devpath, i + 1);
+				usb_hub_port_connect_change(hub, i, &portsts);
 			} else if (portchange & USB_PORT_STAT_C_ENABLE) {
-				dbg("port %d enable change, status %x", i + 1, portstatus);
-				usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE);
+				dbg("hub %s port %d enable change, status %x",
+					dev->devpath, i + 1, portstatus);
+				usb_clear_port_feature(dev,
+					i + 1, USB_PORT_FEAT_C_ENABLE);
 
 				/*
-				 * EM interference sometimes causes bad shielded USB devices to 
-				 * be shutdown by the hub, this hack enables them again.
+				 * EM interference sometimes causes badly
+				 * shielded USB devices to be shutdown by
+				 * the hub, this hack enables them again.
 				 * Works at least with mouse driver. 
 				 */
-				if (!(portstatus & USB_PORT_STAT_ENABLE) && 
-				    (portstatus & USB_PORT_STAT_CONNECTION) && (dev->children[i])) {
-					err("already running port %i disabled by hub (EMI?), re-enabling...",
-						i + 1);
-					usb_hub_port_connect_change(dev, i, &portsts);
+				if (!(portstatus & USB_PORT_STAT_ENABLE)
+				    && (portstatus & USB_PORT_STAT_CONNECTION)
+				    && (dev->children[i])) {
+					err("already running hub %s port %i "
+					    "disabled by hub (EMI?), "
+					    "re-enabling...",
+						dev->devpath, i + 1);
+					usb_hub_port_connect_change(hub,
+						i, &portsts);
 				}
 			}
 
 			if (portchange & USB_PORT_STAT_C_SUSPEND) {
-				dbg("port %d suspend change", i + 1);
-				usb_clear_port_feature(dev, i + 1,  USB_PORT_FEAT_C_SUSPEND);
+				dbg("hub %s port %d suspend change",
+					dev->devpath, i + 1);
+				usb_clear_port_feature(dev,
+					i + 1,  USB_PORT_FEAT_C_SUSPEND);
 			}
 			
 			if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
-				err("port %d over-current change", i + 1);
-				usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
+				err("hub %s port %d over-current change",
+					dev->devpath, i + 1);
+				usb_clear_port_feature(dev,
+					i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
 				usb_hub_power_on(hub);
 			}
 
 			if (portchange & USB_PORT_STAT_C_RESET) {
-				dbg("port %d reset change", i + 1);
-				usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET);
+				dbg("hub %s port %d reset change",
+					dev->devpath, i + 1);
+				usb_clear_port_feature(dev,
+					i + 1, USB_PORT_FEAT_C_RESET);
 			}
 		} /* end for i */
 
 		/* deal with hub status changes */
 		if (usb_get_hub_status(dev, &hubsts) < 0)
-			err("get_hub_status failed");
+			err("get_hub_status %s failed", dev->devpath);
 		else {
 			hubstatus = le16_to_cpup(&hubsts.wHubStatus);
 			hubchange = le16_to_cpup(&hubsts.wHubChange);
 			if (hubchange & HUB_CHANGE_LOCAL_POWER) {
-				dbg("hub power change");
+				dbg("hub %s power change", dev->devpath);
 				usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER);
 			}
 			if (hubchange & HUB_CHANGE_OVERCURRENT) {
-				dbg("hub overcurrent change");
+				dbg("hub %s overcurrent change", dev->devpath);
 				wait_ms(500);	/* Cool down */
 				usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT);
                         	usb_hub_power_on(hub);
@@ -851,6 +899,8 @@
 }
 
 static struct usb_device_id hub_id_table [] = {
+    { match_flags: USB_DEVICE_ID_MATCH_DEV_CLASS,
+      bDeviceClass: USB_CLASS_HUB},
     { match_flags: USB_DEVICE_ID_MATCH_INT_CLASS,
       bInterfaceClass: USB_CLASS_HUB},
     { }						/* Terminating entry */
@@ -989,9 +1039,13 @@
 		ret = usb_get_device_descriptor(dev);
 		if (ret < sizeof(dev->descriptor)) {
 			if (ret < 0)
-				err("unable to get device descriptor (error=%d)", ret);
+				err("unable to get device %s descriptor "
+					"(error=%d)", dev->devpath, ret);
 			else
-				err("USB device descriptor short read (expected %Zi, got %i)", sizeof(dev->descriptor), ret);
+				err("USB device %s descriptor short read "
+					"(expected %Zi, got %i)",
+					dev->devpath,
+					sizeof(dev->descriptor), ret);
         
 			clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
 			dev->devnum = -1;
@@ -1015,17 +1069,22 @@
 
 	ret = usb_set_configuration(dev, dev->actconfig->bConfigurationValue);
 	if (ret < 0) {
-		err("failed to set active configuration (error=%d)", ret);
+		err("failed to set dev %s active configuration (error=%d)",
+			dev->devpath, ret);
 		return ret;
 	}
 
 	for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
 		struct usb_interface *intf = &dev->actconfig->interface[i];
-		struct usb_interface_descriptor *as = &intf->altsetting[intf->act_altsetting];
+		struct usb_interface_descriptor *as;
 
-		ret = usb_set_interface(dev, as->bInterfaceNumber, as->bAlternateSetting);
+		as = &intf->altsetting[intf->act_altsetting];
+		ret = usb_set_interface(dev, as->bInterfaceNumber,
+			as->bAlternateSetting);
 		if (ret < 0) {
-			err("failed to set active alternate setting for interface %d (error=%d)", i, ret);
+			err("failed to set active alternate setting "
+				"for dev %s interface %d (error=%d)",
+				dev->devpath, i, ret);
 			return ret;
 		}
 	}
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/hub.h linux/drivers/usb/hub.h
--- v2.5.1/linux/drivers/usb/hub.h	Thu Nov 22 11:49:52 2001
+++ linux/drivers/usb/hub.h	Tue Jan  1 19:17:25 2002
@@ -1,6 +1,13 @@
 #ifndef __LINUX_HUB_H
 #define __LINUX_HUB_H
 
+/*
+ * Hub protocol and driver data structures.
+ *
+ * Some of these are known to the "virtual root hub" code
+ * in host controller drivers.
+ */
+
 #include <linux/list.h>
 
 /*
@@ -11,6 +18,15 @@
 #define USB_RT_PORT	(USB_TYPE_CLASS | USB_RECIP_OTHER)
 
 /*
+ * Hub class requests
+ * See USB 2.0 spec Table 11-16
+ */
+#define HUB_CLEAR_TT_BUFFER	8
+#define HUB_RESET_TT		9
+#define HUB_GET_TT_STATE	10
+#define HUB_STOP_TT		11
+
+/*
  * Hub Class feature numbers
  * See USB 2.0 spec Table 11-17
  */
@@ -55,7 +71,7 @@
 #define USB_PORT_STAT_SUSPEND		0x0004
 #define USB_PORT_STAT_OVERCURRENT	0x0008
 #define USB_PORT_STAT_RESET		0x0010
-/* bits 5 for 7 are reserved */
+/* bits 5 to 7 are reserved */
 #define USB_PORT_STAT_POWER		0x0100
 #define USB_PORT_STAT_LOW_SPEED		0x0200
 #define USB_PORT_STAT_HIGH_SPEED        0x0400
@@ -120,22 +136,21 @@
 struct usb_device;
 
 struct usb_hub {
-	struct usb_device *dev;
-
-	struct urb *urb;		/* Interrupt polling pipe */
-
-	char buffer[(USB_MAXCHILDREN + 1 + 7) / 8]; /* add 1 bit for hub status change */
-					/* and add 7 bits to round up to byte boundary */
-	int error;
-	int nerrors;
+	struct usb_device	*dev;		/* the "real" device */
+	struct urb		*urb;		/* for interrupt polling pipe */
 
-	struct list_head hub_list;
+	/* buffer for urb ... 1 bit each for hub and children, rounded up */
+	char			buffer[(USB_MAXCHILDREN + 1 + 7) / 8];
 
-	struct list_head event_list;
+	int			error;		/* last reported error */
+	int			nerrors;	/* track consecutive errors */
 
-	struct usb_hub_descriptor *descriptor;
+	struct list_head	hub_list;	/* all hubs */
+	struct list_head	event_list;	/* hubs w/data or errs ready */
 
-	struct semaphore khubd_sem;
+	struct usb_hub_descriptor *descriptor;	/* class descriptor */
+	struct semaphore	khubd_sem;
+	struct usb_tt		tt;		/* Transaction Translator */
 };
 
 #endif /* __LINUX_HUB_H */
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/inode.c linux/drivers/usb/inode.c
--- v2.5.1/linux/drivers/usb/inode.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/usb/inode.c	Tue Jan  1 13:52:10 2002
@@ -3,8 +3,8 @@
 /*
  *	inode.c  --  Inode/Dentry functions for the USB device file system.
  *
- *	Copyright (C) 2000
- *          Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *	Copyright (C) 2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *	Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.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
@@ -20,10 +20,9 @@
  *	along with this program; if not, write to the Free Software
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *  $Id: inode.c,v 1.3 2000/01/11 13:58:25 tom Exp $
- *
  *  History:
  *   0.1  04.01.2000  Created
+ *   0.2  10.12.2001  converted to use the vfs layer better
  */
 
 /*****************************************************************************/
@@ -32,146 +31,40 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/locks.h>
+#include <linux/pagemap.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
-#include <asm/uaccess.h>
-
-/* --------------------------------------------------------------------- */
-
-/*
- * This list of superblocks is still used,
- * but since usbdevfs became FS_SINGLE
- * there is only one super_block.
- */
-static LIST_HEAD(superlist);
-
-struct special {
-	const char *name;
-	struct file_operations *fops;
-	struct inode *inode;
-	struct list_head inodes;
-};
-
-static struct special special[] = { 
-	{ "devices", &usbdevfs_devices_fops,  },
-	{ "drivers", &usbdevfs_drivers_fops,  }
-};
-
-#define NRSPECIAL (sizeof(special)/sizeof(special[0]))
-
-/* --------------------------------------------------------------------- */
-
-static int dnumber(struct dentry *dentry)
-{
-	const char *name;
-	unsigned int s;
-
-	if (dentry->d_name.len != 3)
-		return -1;
-	name = dentry->d_name.name;
-	if (name[0] < '0' || name[0] > '9' ||
-	    name[1] < '0' || name[1] > '9' ||
-	    name[2] < '0' || name[2] > '9')
-		return -1;
-	s = name[0] - '0';
-	s = s * 10 + name[1] - '0';
-	s = s * 10 + name[2] - '0';
-	return s;
-}
-
-/*
- * utility functions; should be called with the kernel lock held
- * to protect against busses/devices appearing/disappearing
- */
-
-static void new_dev_inode(struct usb_device *dev, struct super_block *sb)
-{
-	struct inode *inode;
-	unsigned int devnum = dev->devnum;
-	unsigned int busnum = dev->bus->busnum;
-
-	if (devnum < 1 || devnum > 127 || busnum > 255)
-		return;
-	inode = iget(sb, IDEVICE | (busnum << 8) | devnum);
-	if (!inode) {
-		printk(KERN_ERR "usbdevfs: cannot create inode for bus %u device %u\n", busnum, devnum);
-		return;
-	}
-	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	inode->i_uid = sb->u.usbdevfs_sb.devuid;
-	inode->i_gid = sb->u.usbdevfs_sb.devgid;
-	inode->i_mode = sb->u.usbdevfs_sb.devmode | S_IFREG;
-	inode->i_fop = &usbdevfs_device_file_operations;
-	inode->i_size = sizeof(struct usb_device_descriptor);
-	inode->u.usbdev_i.p.dev = dev;
-	list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist);
-	list_add_tail(&inode->u.usbdev_i.dlist, &dev->inodes);
-}
 
-static void recurse_new_dev_inode(struct usb_device *dev, struct super_block *sb)
-{
-	unsigned int i;
 
-	if (!dev)
-		return;
-	new_dev_inode(dev, sb);
-	for (i = 0; i < dev->maxchild; i++) {
-                if (!dev->children[i])
-                        continue;
-		recurse_new_dev_inode(dev->children[i], sb);
-	}
-}
-
-static void new_bus_inode(struct usb_bus *bus, struct super_block *sb)
-{
-	struct inode *inode;
-	unsigned int busnum = bus->busnum;
-
-	if (busnum > 255)
-		return;
-	inode = iget(sb, IBUS | (busnum << 8));
-	if (!inode) {
-		printk(KERN_ERR "usbdevfs: cannot create inode for bus %u\n", busnum);
-		return;
-	}
-	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	inode->i_uid = sb->u.usbdevfs_sb.busuid;
-	inode->i_gid = sb->u.usbdevfs_sb.busgid;
-	inode->i_mode = sb->u.usbdevfs_sb.busmode | S_IFDIR;
-	inode->i_op = &usbdevfs_bus_inode_operations;
-	inode->i_fop = &usbdevfs_bus_file_operations;
-	inode->u.usbdev_i.p.bus = bus;
-	list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist);
-	list_add_tail(&inode->u.usbdev_i.dlist, &bus->inodes);
-}
-
-static void free_inode(struct inode *inode)
-{
-	inode->u.usbdev_i.p.bus = NULL;
-	inode->u.usbdev_i.p.dev = NULL;
-	inode->i_mode &= ~S_IRWXUGO;
-	inode->i_uid = inode->i_gid = 0;
-	inode->i_size = 0;
-	list_del(&inode->u.usbdev_i.slist);
-	INIT_LIST_HEAD(&inode->u.usbdev_i.slist);
-	list_del(&inode->u.usbdev_i.dlist);
-	INIT_LIST_HEAD(&inode->u.usbdev_i.dlist);
-	iput(inode);
-}
+static struct super_operations usbfs_ops;
+static struct address_space_operations usbfs_aops;
+static struct file_operations usbfs_dir_operations;
+static struct file_operations default_file_operations;
+static struct inode_operations usbfs_dir_inode_operations;
+static struct vfsmount *usbfs_mount;
+static spinlock_t mount_lock = SPIN_LOCK_UNLOCKED;
+static int mount_count;	/* = 0 */
+
+static struct dentry *devices_dentry;
+static struct dentry *drivers_dentry;
+static int num_buses;	/* = 0 */
+
+static uid_t devuid;	/* = 0 */
+static uid_t busuid;	/* = 0 */
+static uid_t listuid;	/* = 0 */
+static gid_t devgid;	/* = 0 */
+static gid_t busgid;	/* = 0 */
+static gid_t listgid;	/* = 0 */
+static umode_t devmode = S_IWUSR | S_IRUGO;
+static umode_t busmode = S_IXUGO | S_IRUGO;
+static umode_t listmode = S_IRUGO;
 
 static int parse_options(struct super_block *s, char *data)
 {
-	uid_t devuid = 0, busuid = 0, listuid = 0;
-	gid_t devgid = 0, busgid = 0, listgid = 0;
-	umode_t devmode = S_IWUSR | S_IRUGO, busmode = S_IXUGO | S_IRUGO, listmode = S_IRUGO;
 	char *curopt = NULL, *value;
 
-	/* parse options */
 	if (data)
 		curopt = strtok(data, ",");
 	for (; curopt; curopt = strtok(NULL, ",")) {
@@ -242,481 +135,572 @@
 		}
 	}
 
-	s->u.usbdevfs_sb.devuid = devuid;
-	s->u.usbdevfs_sb.devgid = devgid;
-	s->u.usbdevfs_sb.devmode = devmode;
-	s->u.usbdevfs_sb.busuid = busuid;
-	s->u.usbdevfs_sb.busgid = busgid;
-	s->u.usbdevfs_sb.busmode = busmode;
-	s->u.usbdevfs_sb.listuid = listuid;
-	s->u.usbdevfs_sb.listgid = listgid;
-	s->u.usbdevfs_sb.listmode = listmode;
+	return 0;
+}
+
+
+/* --------------------------------------------------------------------- */
 
+static struct dentry *usbfs_lookup (struct inode *dir, struct dentry *dentry)
+{
+	d_add(dentry, NULL);
+	return NULL;
+}
+
+static int usbfs_statfs(struct super_block *sb, struct statfs *buf)
+{
+	buf->f_type = USBDEVICE_SUPER_MAGIC;
+	buf->f_bsize = PAGE_CACHE_SIZE;
+	buf->f_namelen = NAME_MAX;
 	return 0;
 }
 
-static struct usb_bus *usbdevfs_findbus(int busnr)
+static struct inode *usbfs_get_inode (struct super_block *sb, int mode, int dev)
 {
-        struct list_head *list;
-        struct usb_bus *bus;
+	struct inode *inode = new_inode(sb);
 
-	down (&usb_bus_list_lock);
-        for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) {
-                bus = list_entry(list, struct usb_bus, bus_list);
-                if (bus->busnum == busnr) {
-			up (&usb_bus_list_lock);
-                        return bus;
+	if (inode) {
+		inode->i_mode = mode;
+		inode->i_uid = current->fsuid;
+		inode->i_gid = current->fsgid;
+		inode->i_blksize = PAGE_CACHE_SIZE;
+		inode->i_blocks = 0;
+		inode->i_rdev = NODEV;
+		inode->i_mapping->a_ops = &usbfs_aops;
+		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+		switch (mode & S_IFMT) {
+		default:
+			init_special_inode(inode, mode, dev);
+			break;
+		case S_IFREG:
+			inode->i_fop = &default_file_operations;
+			break;
+		case S_IFDIR:
+			inode->i_op = &usbfs_dir_inode_operations;
+			inode->i_fop = &usbfs_dir_operations;
+			break;
 		}
-        }
-	up (&usb_bus_list_lock);
-        return NULL;
+	}
+	return inode; 
 }
 
-#if 0
-static struct usb_device *finddev(struct usb_device *dev, int devnr)
+static int usbfs_mknod (struct inode *dir, struct dentry *dentry, int mode,
+			int dev)
 {
-        unsigned int i;
-        struct usb_device *d2;
+	struct inode *inode = usbfs_get_inode(dir->i_sb, mode, dev);
+	int error = -ENOSPC;
 
-        if (!dev)
-                return NULL;
-        if (dev->devnum == devnr)
-                return dev;
-        for (i = 0; i < dev->maxchild; i++) {
-                if (!dev->children[i])
-                        continue;
-                if ((d2 = finddev(dev->children[i], devnr)))
-                        return d2;
-        }
-        return NULL;
+	if (inode) {
+		d_instantiate(dentry, inode);
+		dget(dentry);
+		error = 0;
+	}
+	return error;
 }
 
-static struct usb_device *usbdevfs_finddevice(struct usb_bus *bus, int devnr)
+static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, int mode)
 {
-        return finddev(bus->root_hub, devnr);
+	return usbfs_mknod (dir, dentry, mode | S_IFDIR, 0);
 }
-#endif
 
-/* --------------------------------------------------------------------- */
+static int usbfs_create (struct inode *dir, struct dentry *dentry, int mode)
+{
+ 	return usbfs_mknod (dir, dentry, mode | S_IFREG, 0);
+}
 
-static int usbdevfs_revalidate(struct dentry *dentry, int flags)
+static int usbfs_link (struct dentry *old_dentry, struct inode *dir,
+		       struct dentry *dentry)
 {
-	struct inode *inode = dentry->d_inode;
+	struct inode *inode = old_dentry->d_inode;
 
-        if (!inode)
-                return 0;
-	if (ITYPE(inode->i_ino) == IBUS && !inode->u.usbdev_i.p.bus)
-		return 0;
-	if (ITYPE(inode->i_ino) == IDEVICE && !inode->u.usbdev_i.p.dev)
-		return 0;
-	return 1;
+	if(S_ISDIR(inode->i_mode))
+		return -EPERM;
+
+	inode->i_nlink++;
+	atomic_inc(&inode->i_count);
+ 	dget(dentry);
+	d_instantiate(dentry, inode);
+	return 0;
 }
 
-static struct dentry_operations usbdevfs_dentry_operations = {
-	d_revalidate:	usbdevfs_revalidate,
-};
+static inline int usbfs_positive (struct dentry *dentry)
+{
+	return dentry->d_inode && !d_unhashed(dentry);
+}
 
-static struct dentry *usbdevfs_root_lookup(struct inode *dir, struct dentry *dentry)
+static int usbfs_empty (struct dentry *dentry)
 {
-	int busnr;
-	unsigned long ino = 0;
-	unsigned int i;
-	struct inode *inode;
+	struct list_head *list;
 
-	/* sanity check */
-	if (dir->i_ino != IROOT)
-		return ERR_PTR(-EINVAL);
-	dentry->d_op = &usbdevfs_dentry_operations;
-	busnr = dnumber(dentry);
-	if (busnr >= 0 && busnr <= 255)
-		ino = IBUS | (busnr << 8);
-	if (!ino) {
-		for (i = 0; i < NRSPECIAL; i++) {
-			if (strlen(special[i].name) == dentry->d_name.len && 
-			    !strncmp(special[i].name, dentry->d_name.name, dentry->d_name.len)) {
-				ino = ISPECIAL | (i + IROOT + 1);
-				break;
-			}
+	spin_lock(&dcache_lock);
+
+	list_for_each(list, &dentry->d_subdirs) {
+		struct dentry *de = list_entry(list, struct dentry, d_child);
+		if (usbfs_positive(de)) {
+			spin_unlock(&dcache_lock);
+			return 0;
 		}
 	}
-	if (!ino)
-		return ERR_PTR(-ENOENT);
-	inode = iget(dir->i_sb, ino);
-	if (!inode)
-		return ERR_PTR(-EINVAL);
-	if (inode && ITYPE(ino) == IBUS && inode->u.usbdev_i.p.bus == NULL) {
-		iput(inode);
-		inode = NULL;
-	}
-	d_add(dentry, inode);
-	return NULL;
+
+	spin_unlock(&dcache_lock);
+	return 1;
 }
 
-static struct dentry *usbdevfs_bus_lookup(struct inode *dir, struct dentry *dentry)
+static int usbfs_unlink (struct inode *dir, struct dentry *dentry)
 {
-	struct inode *inode;
-	int devnr;
+	int error = -ENOTEMPTY;
 
-	/* sanity check */
-	if (ITYPE(dir->i_ino) != IBUS)
-		return ERR_PTR(-EINVAL);
-	dentry->d_op = &usbdevfs_dentry_operations;
-	devnr = dnumber(dentry);
-	if (devnr < 1 || devnr > 127)
-		return ERR_PTR(-ENOENT);
-	inode = iget(dir->i_sb, IDEVICE | (dir->i_ino & (0xff << 8)) | devnr);
-	if (!inode)
-		return ERR_PTR(-EINVAL);
-	if (inode && inode->u.usbdev_i.p.dev == NULL) {
-		iput(inode);
-		inode = NULL;
+	if (usbfs_empty(dentry)) {
+		struct inode *inode = dentry->d_inode;
+
+		inode->i_nlink--;
+		dput(dentry);
+		error = 0;
 	}
-	d_add(dentry, inode);
-	return NULL;
+	return error;
 }
 
-static int usbdevfs_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
+static int usbfs_rename (struct inode *old_dir, struct dentry *old_dentry,
+			 struct inode *new_dir, struct dentry *new_dentry)
 {
-	struct inode *inode = filp->f_dentry->d_inode;
-	unsigned long ino = inode->i_ino;
-	struct special *spec;
-	struct list_head *list;
-	struct usb_bus *bus;
-	char numbuf[8];
-	unsigned int i;
-
-	/* sanity check */
-	if (ino != IROOT)
-		return -EINVAL;
-	i = filp->f_pos;
-	switch (i) {
-	case 0:
-		if (filldir(dirent, ".", 1, i, IROOT, DT_DIR) < 0)
-			return 0;
-		filp->f_pos++;
-		i++;
-		/* fall through */
+	int error = -ENOTEMPTY;
 
-	case 1:
-		if (filldir(dirent, "..", 2, i, IROOT, DT_DIR) < 0)
-			return 0;
-		filp->f_pos++;
-		i++;
-		/* fall through */
-
-	default:
-		
-		while (i >= 2 && i < 2+NRSPECIAL) {
-			spec = &special[filp->f_pos-2];
-			if (filldir(dirent, spec->name, strlen(spec->name), i, ISPECIAL | (filp->f_pos-2+IROOT), DT_UNKNOWN) < 0)
-				return 0;
-			filp->f_pos++;
-			i++;
-		}
-		if (i < 2+NRSPECIAL)
-			return 0;
-		i -= 2+NRSPECIAL;
-		down (&usb_bus_list_lock);
-		for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) {
-			if (i > 0) {
-				i--;
-				continue;
-			}
-			bus = list_entry(list, struct usb_bus, bus_list);
-			sprintf(numbuf, "%03d", bus->busnum);
-			if (filldir(dirent, numbuf, 3, filp->f_pos, IBUS | ((bus->busnum & 0xff) << 8), DT_UNKNOWN) < 0)
-				break;
-			filp->f_pos++;
+	if (usbfs_empty(new_dentry)) {
+		struct inode *inode = new_dentry->d_inode;
+		if (inode) {
+			inode->i_nlink--;
+			dput(new_dentry);
 		}
-		up (&usb_bus_list_lock);
-		return 0;
+		error = 0;
 	}
+	return error;
 }
 
-static int bus_readdir(struct usb_device *dev, unsigned long ino, int pos, struct file *filp, void *dirent, filldir_t filldir)
+#define usbfs_rmdir usbfs_unlink
+
+/* default file operations */
+static ssize_t default_read_file (struct file *file, char *buf,
+				  size_t count, loff_t *ppos)
 {
-	char numbuf[8];
-	unsigned int i;
+	return 0;
+}
 
-	if (!dev)
-		return pos;
-	sprintf(numbuf, "%03d", dev->devnum);
-	if (pos > 0)
-		pos--;
-	else {
-		if (filldir(dirent, numbuf, 3, filp->f_pos, ino | (dev->devnum & 0xff), DT_UNKNOWN) < 0)
-			return -1;
-		filp->f_pos++;
-	}
-	for (i = 0; i < dev->maxchild; i++) {
-		if (!dev->children[i])
-			continue;
-		pos = bus_readdir(dev->children[i], ino, pos, filp, dirent, filldir);
-		if (pos < 0)
-			return -1;
-	}
-	return pos;
+static ssize_t default_write_file (struct file *file, const char *buf,
+				   size_t count, loff_t *ppos)
+{
+	return count;
 }
 
-static int usbdevfs_bus_readdir(struct file *filp, void *dirent, filldir_t filldir)
+static loff_t default_file_lseek (struct file *file, loff_t offset, int orig)
 {
-	struct inode *inode = filp->f_dentry->d_inode;
-	unsigned long ino = inode->i_ino;
-	struct usb_bus *bus;
+	loff_t retval = -EINVAL;
 
-	/* sanity check */
-	if (ITYPE(ino) != IBUS)
-		return -EINVAL;
-	switch ((unsigned int)filp->f_pos) {
+	switch(orig) {
 	case 0:
-		if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) < 0)
-			return 0;
-		filp->f_pos++;
-		/* fall through */
-
+		if (offset > 0) {
+			file->f_pos = offset;
+			retval = file->f_pos;
+		} 
+		break;
 	case 1:
-		if (filldir(dirent, "..", 2, filp->f_pos, IROOT, DT_DIR) < 0)
-			return 0;
-		filp->f_pos++;
-		/* fall through */
-
+		if ((offset + file->f_pos) > 0) {
+			file->f_pos += offset;
+			retval = file->f_pos;
+		} 
+		break;
 	default:
-		lock_kernel();
-		bus = usbdevfs_findbus(IBUSNR(ino));
-		bus_readdir(bus->root_hub, IDEVICE | ((bus->busnum & 0xff) << 8), filp->f_pos-2, filp, dirent, filldir);
-		unlock_kernel();
-		return 0;
+		break;
 	}
+	return retval;
+}
+
+static int default_open (struct inode *inode, struct file *filp)
+{
+	if (inode->u.generic_ip)
+		filp->private_data = inode->u.generic_ip;
+
+	return 0;
 }
 
-static struct file_operations usbdevfs_root_file_operations = {
-	readdir: usbdevfs_root_readdir,
+static int default_sync_file (struct file *file, struct dentry *dentry,
+			      int datasync)
+{
+	return 0;
+}
+
+static struct address_space_operations usbfs_aops = {
 };
 
-static struct inode_operations usbdevfs_root_inode_operations = {
-	lookup: usbdevfs_root_lookup,
+static struct file_operations usbfs_dir_operations = {
+	read:		generic_read_dir,
+	readdir:	dcache_readdir,
+	fsync:		default_sync_file,
 };
 
-static struct file_operations usbdevfs_bus_file_operations = {
-	readdir: usbdevfs_bus_readdir,
+static struct file_operations default_file_operations = {
+	read:		default_read_file,
+	write:		default_write_file,
+	open:		default_open,
+	llseek:		default_file_lseek,
+	fsync:		default_sync_file,
+	mmap:		generic_file_mmap,
 };
 
-static struct inode_operations usbdevfs_bus_inode_operations = {
-	lookup: usbdevfs_bus_lookup,
+static struct inode_operations usbfs_dir_inode_operations = {
+	create:		usbfs_create,
+	lookup:		usbfs_lookup,
+	link:		usbfs_link,
+	unlink:		usbfs_unlink,
+	mkdir:		usbfs_mkdir,
+	rmdir:		usbfs_rmdir,
+	mknod:		usbfs_mknod,
+	rename:		usbfs_rename,
 };
 
-static void usbdevfs_read_inode(struct inode *inode)
-{
-	struct special *spec;
+static struct super_operations usbfs_ops = {
+	statfs:		usbfs_statfs,
+	put_inode:	force_delete,
+};
 
-	inode->i_ctime = inode->i_mtime = inode->i_atime = CURRENT_TIME;
-	inode->i_mode = S_IFREG;
-	inode->i_gid = inode->i_uid = 0;
-	INIT_LIST_HEAD(&inode->u.usbdev_i.dlist);
-	INIT_LIST_HEAD(&inode->u.usbdev_i.slist);
-	inode->u.usbdev_i.p.dev = NULL;
-	inode->u.usbdev_i.p.bus = NULL;
-	switch (ITYPE(inode->i_ino)) {
-	case ISPECIAL:
-		if (inode->i_ino == IROOT) {
-			inode->i_op = &usbdevfs_root_inode_operations;
-			inode->i_fop = &usbdevfs_root_file_operations;
-			inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
-			return;
-		}
-		if (inode->i_ino <= IROOT || inode->i_ino > IROOT+NRSPECIAL)
-			return;
-		spec = &special[inode->i_ino-(IROOT+1)];
-		inode->i_fop = spec->fops;
-		return;
+static struct super_block *usbfs_read_super (struct super_block *sb, void *data, 
+					     int silent)
+{
+	struct inode *inode;
+	struct dentry *root;
 
-	case IDEVICE:
-		return;
+	if (parse_options(sb, data)) {
+		warn("usbfs: mount parameter error:");
+		return NULL;
+	}
 
-	case IBUS:
-		return;
+	sb->s_blocksize = PAGE_CACHE_SIZE;
+	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+	sb->s_magic = USBDEVICE_SUPER_MAGIC;
+	sb->s_op = &usbfs_ops;
+	inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0);
 
-	default:
-		return;
-        }
-}
+	if (!inode) {
+		dbg("%s: could not get inode!\n",__FUNCTION__);
+		return NULL;
+	}
 
-static void usbdevfs_put_super(struct super_block *sb)
-{
-	list_del(&sb->u.usbdevfs_sb.slist);
-	INIT_LIST_HEAD(&sb->u.usbdevfs_sb.slist);
-	while (!list_empty(&sb->u.usbdevfs_sb.ilist))
-		free_inode(list_entry(sb->u.usbdevfs_sb.ilist.next, struct inode, u.usbdev_i.slist));
+	root = d_alloc_root(inode);
+	if (!root) {
+		dbg("%s: could not get root dentry!\n",__FUNCTION__);
+		iput(inode);
+		return NULL;
+	}
+	sb->s_root = root;
+	return sb;
 }
 
-static int usbdevfs_statfs(struct super_block *sb, struct statfs *buf)
+/**
+ * fs_create_by_name - create a file, given a name
+ * @name:	name of file
+ * @mode:	type of file
+ * @parent:	dentry of directory to create it in
+ * @dentry:	resulting dentry of file
+ *
+ * There is a bit of overhead in creating a file - basically, we 
+ * have to hash the name of the file, then look it up. This will
+ * prevent files of the same name. 
+ * We then call the proper vfs_ function to take care of all the 
+ * file creation details. 
+ * This function handles both regular files and directories.
+ */
+static int fs_create_by_name (const char *name, mode_t mode,
+			      struct dentry *parent, struct dentry **dentry)
 {
-        buf->f_type = USBDEVICE_SUPER_MAGIC;
-        buf->f_bsize = PAGE_SIZE/sizeof(long);   /* ??? */
-        buf->f_bfree = 0;
-        buf->f_bavail = 0;
-        buf->f_ffree = 0;
-        buf->f_namelen = NAME_MAX;
-        return 0;
-}
+	struct dentry *d = NULL;
+	struct qstr qstr;
+	int error;
 
-static int usbdevfs_remount(struct super_block *s, int *flags, char *data)
-{
-	struct list_head *ilist = s->u.usbdevfs_sb.ilist.next;
-	struct inode *inode;
-	int ret;
+	/* If the parent is not specified, we create it in the root.
+	 * We need the root dentry to do this, which is in the super 
+	 * block. A pointer to that is in the struct vfsmount that we
+	 * have around.
+	 */
+	if (!parent ) {
+		if (usbfs_mount && usbfs_mount->mnt_sb) {
+			parent = usbfs_mount->mnt_sb->s_root;
+		}
+	}
 
-	if ((ret = parse_options(s, data))) {
-		printk(KERN_WARNING "usbdevfs: remount parameter error\n");
-		return ret;
+	if (!parent) {
+		dbg("Ah! can not find a parent!\n");
+		return -EFAULT;
 	}
 
-	for (; ilist != &s->u.usbdevfs_sb.ilist; ilist = ilist->next) {
-		inode = list_entry(ilist, struct inode, u.usbdev_i.slist);
+	*dentry = NULL;
+	qstr.name = name;
+	qstr.len = strlen(name);
+ 	qstr.hash = full_name_hash(name,qstr.len);
 
-		switch (ITYPE(inode->i_ino)) {
-			case ISPECIAL :
-				inode->i_uid = s->u.usbdevfs_sb.listuid;
-				inode->i_gid = s->u.usbdevfs_sb.listgid;
-				inode->i_mode = s->u.usbdevfs_sb.listmode | S_IFREG;
-				break;
-			case IBUS :
-				inode->i_uid = s->u.usbdevfs_sb.busuid;
-				inode->i_gid = s->u.usbdevfs_sb.busgid;
-				inode->i_mode = s->u.usbdevfs_sb.busmode | S_IFDIR;
+	parent = dget(parent);
+
+	down(&parent->d_inode->i_sem);
+
+	d = lookup_hash(&qstr,parent);
+
+	error = PTR_ERR(d);
+	if (!IS_ERR(d)) {
+		switch(mode & S_IFMT) {
+			case 0: 
+			case S_IFREG:
+				error = vfs_create(parent->d_inode,d,mode);
 				break;
-			case IDEVICE :
-				inode->i_uid = s->u.usbdevfs_sb.devuid;
-				inode->i_gid = s->u.usbdevfs_sb.devgid;
-				inode->i_mode = s->u.usbdevfs_sb.devmode | S_IFREG;
+			case S_IFDIR:
+				error = vfs_mkdir(parent->d_inode,d,mode);
 				break;
+			default:
+				err("cannot create special files\n");
 		}
+		*dentry = d;
 	}
+	up(&parent->d_inode->i_sem);
 
-	return 0;
+	dput(parent);
+	return error;
 }
 
-static struct super_operations usbdevfs_sops = { 
-	read_inode:	usbdevfs_read_inode,
-	put_super:	usbdevfs_put_super,
-	statfs:		usbdevfs_statfs,
-	remount_fs:	usbdevfs_remount,
-};
-
-struct super_block *usbdevfs_read_super(struct super_block *s, void *data, int silent)
+static struct dentry *fs_create_file (const char *name, mode_t mode,
+				      struct dentry *parent, void *data,
+				      struct file_operations *fops,
+				      uid_t uid, gid_t gid)
 {
-        struct inode *root_inode, *inode;
-	struct list_head *blist;
-	struct usb_bus *bus;
-	unsigned int i;
+	struct dentry *dentry;
+	int error;
 
-	if (parse_options(s, data)) {
-		printk(KERN_WARNING "usbdevfs: mount parameter error\n");
-		return NULL;
+	dbg("creating file '%s'\n",name);
+
+	error = fs_create_by_name(name,mode,parent,&dentry);
+	if (error) {
+		dentry = NULL;
+	} else {
+		if (dentry->d_inode) {
+			if (data)
+				dentry->d_inode->u.generic_ip = data;
+			if (fops)
+				dentry->d_inode->i_fop = fops;
+			dentry->d_inode->i_uid = uid;
+			dentry->d_inode->i_gid = gid;
+		}
 	}
 
-	/* fill superblock */
-        s->s_blocksize = 1024;
-        s->s_blocksize_bits = 10;
-        s->s_magic = USBDEVICE_SUPER_MAGIC;
-        s->s_op = &usbdevfs_sops;
-	INIT_LIST_HEAD(&s->u.usbdevfs_sb.slist);
-	INIT_LIST_HEAD(&s->u.usbdevfs_sb.ilist);
-	root_inode = iget(s, IROOT);
-        if (!root_inode)
-                goto out_no_root;
-        s->s_root = d_alloc_root(root_inode);
-        if (!s->s_root)
-                goto out_no_root;
-	list_add_tail(&s->u.usbdevfs_sb.slist, &superlist);
-	for (i = 0; i < NRSPECIAL; i++) {
-		if (!(inode = iget(s, IROOT+1+i)))
-			continue;
-		inode->i_uid = s->u.usbdevfs_sb.listuid;
-		inode->i_gid = s->u.usbdevfs_sb.listgid;
-		inode->i_mode = s->u.usbdevfs_sb.listmode | S_IFREG;
-		special[i].inode = inode;
-		list_add_tail(&inode->u.usbdev_i.slist, &s->u.usbdevfs_sb.ilist);
-		list_add_tail(&inode->u.usbdev_i.dlist, &special[i].inodes);
-	}
-	down (&usb_bus_list_lock);
-	for (blist = usb_bus_list.next; blist != &usb_bus_list; blist = blist->next) {
-		bus = list_entry(blist, struct usb_bus, bus_list);
-		new_bus_inode(bus, s);
-		recurse_new_dev_inode(bus->root_hub, s);
-	}
-	up (&usb_bus_list_lock);
-        return s;
-
- out_no_root:
-        printk("usbdevfs_read_super: get root inode failed\n");
-        iput(root_inode);
-        return NULL;
+	return dentry;
 }
 
+static void fs_remove_file (struct dentry *dentry)
+{
+	struct dentry *parent = dentry->d_parent;
+	
+	if (!parent || !parent->d_inode)
+		return;
+
+	down(&parent->d_inode->i_sem);
+	if (usbfs_positive(dentry)) {
+		if (dentry->d_inode) {
+			if (S_ISDIR(dentry->d_inode->i_mode))
+				vfs_rmdir(parent->d_inode,dentry);
+			else
+				vfs_unlink(parent->d_inode,dentry);
+		}
+
+		dput(dentry);
+	}
+	up(&parent->d_inode->i_sem);
+}
+
+/* --------------------------------------------------------------------- */
+
+
+
 /*
- * The usbdevfs name is now depreciated (as of 2.5.1).
+ * The usbdevfs name is now deprecated (as of 2.5.1).
  * It will be removed when the 2.7.x development cycle is started.
  * You have been warned :)
  */
-static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbdevfs_read_super, FS_SINGLE);
-static DECLARE_FSTYPE(usb_fs_type, "usbfs", usbdevfs_read_super, FS_SINGLE);
+static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbfs_read_super, FS_SINGLE);
+static DECLARE_FSTYPE(usb_fs_type,       "usbfs",    usbfs_read_super, FS_SINGLE);
 
 /* --------------------------------------------------------------------- */
+static int get_mount (void)
+{
+	struct vfsmount *mnt;
 
-static void update_special_inodes (void)
+	spin_lock (&mount_lock);
+	if (usbfs_mount) {
+		mntget(usbfs_mount);
+		++mount_count;
+		spin_unlock (&mount_lock);
+		goto go_ahead;
+	}
+
+	spin_unlock (&mount_lock);
+	mnt = kern_mount (&usbdevice_fs_type);
+	if (IS_ERR(mnt)) {
+		err ("could not mount the fs...erroring out!\n");
+		return -ENODEV;
+	}
+	spin_lock (&mount_lock);
+	if (!usbfs_mount) {
+		usbfs_mount = mnt;
+		++mount_count;
+		spin_unlock (&mount_lock);
+		goto go_ahead;
+	}
+	mntget(usbfs_mount);
+	++mount_count;
+	spin_unlock (&mount_lock);
+	mntput(mnt);
+
+go_ahead:
+	dbg("mount_count = %d\n", mount_count);
+	return 0;
+}
+
+static void remove_mount (void)
+{
+	struct vfsmount *mnt;
+
+	spin_lock (&mount_lock);
+	mnt = usbfs_mount;
+	--mount_count;
+	if (!mount_count)
+		usbfs_mount = NULL;
+
+	spin_unlock (&mount_lock);
+	mntput(mnt);
+	dbg("mount_count = %d\n", mount_count);
+}
+
+static int create_special_files (void)
+{
+	int retval;
+
+	/* create the devices and drivers special files */
+	retval = get_mount ();
+	if (retval)
+		return retval;
+	devices_dentry = fs_create_file ("devices",
+					 listmode | S_IFREG,
+					 NULL, NULL,
+					 &usbdevfs_devices_fops,
+					 listuid, listgid);
+	if (devices_dentry == NULL) {
+		err ("Unable to create devices usbfs file");
+		return -ENODEV;
+	}
+
+	drivers_dentry = fs_create_file ("drivers",
+					 listmode | S_IFREG,
+					 NULL, NULL,
+					 &usbdevfs_drivers_fops,
+					 listuid, listgid);
+	if (drivers_dentry == NULL) {
+		err ("Unable to create drivers usbfs file");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void remove_special_files (void)
+{
+	if (devices_dentry)
+		fs_remove_file (devices_dentry);
+	if (drivers_dentry)
+		fs_remove_file (drivers_dentry);
+	devices_dentry = NULL;
+	drivers_dentry = NULL;
+	remove_mount();
+}
+
+void usbfs_update_special (void)
 {
-	int i;
-	for (i = 0; i < NRSPECIAL; i++) {
-		struct inode *inode = special[i].inode;
+	struct inode *inode;
+
+	if (devices_dentry) {
+		inode = devices_dentry->d_inode;
+		if (inode)
+			inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	}
+	if (drivers_dentry) {
+		inode = devices_dentry->d_inode;
 		if (inode)
 			inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 	}
 }
 
-
-void usbdevfs_add_bus(struct usb_bus *bus)
+void usbfs_add_bus(struct usb_bus *bus)
 {
-	struct list_head *slist;
+	char name[8];
+	int retval;
+
+	/* create the special files if this is the first bus added */
+	if (num_buses == 0) {
+		retval = create_special_files();
+		if (retval)
+			return;
+	}
+	++num_buses;
+
+	sprintf (name, "%03d", bus->busnum);
+	bus->dentry = fs_create_file (name,
+				      busmode | S_IFDIR,
+				      NULL, bus, NULL,
+				      busuid, busgid);
+	if (bus->dentry == NULL)
+		return;
 
-	lock_kernel();
-	for (slist = superlist.next; slist != &superlist; slist = slist->next)
-		new_bus_inode(bus, list_entry(slist, struct super_block, u.usbdevfs_sb.slist));
-	update_special_inodes();
-	unlock_kernel();
+	usbfs_update_special();
 	usbdevfs_conn_disc_event();
 }
 
-void usbdevfs_remove_bus(struct usb_bus *bus)
+
+void usbfs_remove_bus(struct usb_bus *bus)
 {
-	lock_kernel();
-	while (!list_empty(&bus->inodes))
-		free_inode(list_entry(bus->inodes.next, struct inode, u.usbdev_i.dlist));
-	update_special_inodes();
-	unlock_kernel();
+	if (bus->dentry) {
+		fs_remove_file (bus->dentry);
+		bus->dentry = NULL;
+	}
+
+	--num_buses;
+	if (num_buses <= 0) {
+		remove_special_files();
+		num_buses = 0;
+	}
+
+	usbfs_update_special();
 	usbdevfs_conn_disc_event();
 }
 
-void usbdevfs_add_device(struct usb_device *dev)
+void usbfs_add_device(struct usb_device *dev)
 {
-	struct list_head *slist;
+	char name[8];
 
-	lock_kernel();
-	for (slist = superlist.next; slist != &superlist; slist = slist->next)
-		new_dev_inode(dev, list_entry(slist, struct super_block, u.usbdevfs_sb.slist));
-	update_special_inodes();
-	unlock_kernel();
+	sprintf (name, "%03d", dev->devnum);
+	dev->dentry = fs_create_file (name,
+				      devmode | S_IFREG,
+				      dev->bus->dentry, dev,
+				      &usbdevfs_device_file_operations,
+				      devuid, devgid);
+	if (dev->dentry == NULL)
+		return;
+
+	usbfs_update_special();
 	usbdevfs_conn_disc_event();
 }
 
-void usbdevfs_remove_device(struct usb_device *dev)
+void usbfs_remove_device(struct usb_device *dev)
 {
 	struct dev_state *ds;
 	struct siginfo sinfo;
 
-	lock_kernel();
-	while (!list_empty(&dev->inodes))
-		free_inode(list_entry(dev->inodes.next, struct inode, u.usbdev_i.dlist));
+	if (dev->dentry) {
+		fs_remove_file (dev->dentry);
+		dev->dentry = NULL;
+	}
 	while (!list_empty(&dev->filelist)) {
 		ds = list_entry(dev->filelist.next, struct dev_state, list);
 		list_del(&ds->list);
@@ -732,9 +716,7 @@
 			send_sig_info(ds->discsignr, &sinfo, ds->disctask);
 		}
 	}
-
-	update_special_inodes();
-	unlock_kernel();
+	usbfs_update_special();
 	usbdevfs_conn_disc_event();
 }
 
@@ -744,39 +726,42 @@
 static struct proc_dir_entry *usbdir = NULL;
 #endif	
 
-int __init usbdevfs_init(void)
+int __init usbfs_init(void)
 {
-	int ret;
+	int retval;
 
-	for (ret = 0; ret < NRSPECIAL; ret++) {
-		INIT_LIST_HEAD(&special[ret].inodes);
-	}
-	if ((ret = usb_register(&usbdevfs_driver)))
-		return ret;
-	if ((ret = register_filesystem(&usb_fs_type))) {
+	retval = usb_register(&usbdevfs_driver);
+	if (retval)
+		return retval;
+
+	retval = register_filesystem(&usb_fs_type);
+	if (retval) {
 		usb_deregister(&usbdevfs_driver);
-		return ret;
+		return retval;
 	}
-	if ((ret = register_filesystem(&usbdevice_fs_type))) {
+	retval = register_filesystem(&usbdevice_fs_type);
+	if (retval) {
 		unregister_filesystem(&usb_fs_type);
 		usb_deregister(&usbdevfs_driver);
-		return ret;
+		return retval;
 	}
+
 #ifdef CONFIG_PROC_FS		
 	/* create mount point for usbdevfs */
 	usbdir = proc_mkdir("usb", proc_bus);
 #endif	
-	return ret;
+
+	return 0;
 }
 
-void __exit usbdevfs_cleanup(void)
+void __exit usbfs_cleanup(void)
 {
 	usb_deregister(&usbdevfs_driver);
 	unregister_filesystem(&usb_fs_type);
 	unregister_filesystem(&usbdevice_fs_type);
 #ifdef CONFIG_PROC_FS	
-        if (usbdir)
-                remove_proc_entry("usb", proc_bus);
+	if (usbdir)
+		remove_proc_entry("usb", proc_bus);
 #endif
 }
 
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/mdc800.c linux/drivers/usb/mdc800.c
--- v2.5.1/linux/drivers/usb/mdc800.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/usb/mdc800.c	Tue Jan  1 13:52:10 2002
@@ -140,7 +140,7 @@
 
 	unsigned int		endpoint [4];
 
-	purb_t			irq_urb;
+	struct urb *		irq_urb;
 	wait_queue_head_t	irq_wait;
 	int			irq_woken;
 	char*			irq_urb_buffer;
@@ -149,13 +149,13 @@
 	int 			camera_request_ready; // Status to synchronize with irq
 	char 			camera_response [8];  // last Bytes send after busy
 
-	purb_t   		write_urb;
+	struct urb *   		write_urb;
 	char*			write_urb_buffer;
 	wait_queue_head_t	write_wait;
 	int			written;
 
 
-	purb_t	   		download_urb;
+	struct urb *   		download_urb;
 	char*			download_urb_buffer;
 	wait_queue_head_t	download_wait;
 	int			downloaded;
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/microtek.c linux/drivers/usb/microtek.c
--- v2.5.1/linux/drivers/usb/microtek.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/usb/microtek.c	Tue Dec 25 17:04:40 2001
@@ -367,7 +367,7 @@
 	}
 
 	MTS_DEBUG_GOT_HERE();
-	scsi_unregister_module(MODULE_SCSI_HA, &(to_remove->ctempl));
+	scsi_unregister_host(&to_remove->ctempl);
 	unlock_kernel();
 
 	kfree( to_remove );
@@ -982,11 +982,11 @@
 	MTS_DEBUG("registering SCSI module\n");
 
 	new_desc->ctempl.module = THIS_MODULE;
-	result = scsi_register_module(MODULE_SCSI_HA, &(new_desc->ctempl));
+	result = scsi_register_host(&new_desc->ctempl);
 	/* Will get hit back in microtek_detect by this func */
 	if ( result )
 	{
-		MTS_ERROR( "error %d from scsi_register_module! Help!\n",
+		MTS_ERROR( "error %d from scsi_register_host! Help!\n",
 			   (int)result );
 
 		/* FIXME: need more cleanup? */
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
--- v2.5.1/linux/drivers/usb/printer.c	Tue Oct  9 15:15:02 2001
+++ linux/drivers/usb/printer.c	Thu Jan  3 12:20:16 2002
@@ -201,7 +201,7 @@
 
 static int usblp_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev) - USBLP_MINOR_BASE;
+	int minor = minor(inode->i_rdev) - USBLP_MINOR_BASE;
 	struct usblp *usblp;
 	int retval;
 
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/pwc-if.c linux/drivers/usb/pwc-if.c
--- v2.5.1/linux/drivers/usb/pwc-if.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/usb/pwc-if.c	Tue Jan  1 13:52:10 2002
@@ -624,7 +624,7 @@
 /* This gets called for the Isochronous pipe (video). This is done in
  * interrupt time, so it has to be fast, not crash, and not stall. Neat.
  */
-static void pwc_isoc_handler(purb_t urb)
+static void pwc_isoc_handler(struct urb *urb)
 {
 	struct pwc_device *pdev;
 	int i, fst, flen;
@@ -786,7 +786,7 @@
 static int pwc_isoc_init(struct pwc_device *pdev)
 {
 	struct usb_device *udev;
-	purb_t urb;
+	struct urb *urb;
 	int i, j, ret;
 
 	struct usb_interface_descriptor *idesc;
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/pwc.h linux/drivers/usb/pwc.h
--- v2.5.1/linux/drivers/usb/pwc.h	Tue Dec 18 14:56:38 2001
+++ linux/drivers/usb/pwc.h	Tue Jan  1 13:52:10 2002
@@ -96,7 +96,7 @@
 	void *data;
 	int  length;
 	int  read;
-	purb_t urb;
+	struct urb *urb;
 };
 
 /* intermediate buffers with raw data from the USB cam */
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/scanner.c linux/drivers/usb/scanner.c
--- v2.5.1/linux/drivers/usb/scanner.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/usb/scanner.c	Thu Jan  3 12:20:16 2002
@@ -365,7 +365,7 @@
 	struct scn_usb_data *scn;
 	struct usb_device *dev;
 
-	kdev_t scn_minor;
+	int scn_minor;
 
 	int err=0;
 
@@ -432,7 +432,7 @@
 {
 	struct scn_usb_data *scn;
 
-	kdev_t scn_minor;
+	int scn_minor;
 
 	scn_minor = USB_SCN_MINOR (inode);
 
@@ -469,7 +469,7 @@
 	ssize_t bytes_written = 0; /* Overall count of bytes written */
 	ssize_t ret = 0;
 
-	kdev_t scn_minor;
+	int scn_minor;
 
 	int this_write;		/* Number of bytes to write */
 	int partial;		/* Number of bytes successfully written */
@@ -556,8 +556,7 @@
 	ssize_t bytes_read;	/* Overall count of bytes_read */
 	ssize_t ret;
 
-	kdev_t scn_minor;
-
+	int scn_minor;
 	int partial;		/* Number of bytes successfully read */
 	int this_read;		/* Max number of bytes to read */
 	int result;
@@ -671,7 +670,7 @@
 {
 	struct usb_device *dev;
 
-	kdev_t scn_minor;
+	int scn_minor;
 
 	scn_minor = USB_SCN_MINOR(inode);
 
@@ -810,8 +809,7 @@
 
 	int ep_cnt;
 	int ix;
-
-	kdev_t scn_minor;
+	int scn_minor;
 
 	char valid_device = 0;
 	char have_bulk_in, have_bulk_out, have_intr;
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/scanner.h linux/drivers/usb/scanner.h
--- v2.5.1/linux/drivers/usb/scanner.h	Tue Dec 18 14:56:38 2001
+++ linux/drivers/usb/scanner.h	Thu Jan  3 12:14:38 2002
@@ -203,7 +203,7 @@
 #define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
 #define IS_EP_INTR(ep) ((ep).bmAttributes == USB_ENDPOINT_XFER_INT ? 1 : 0)
 
-#define USB_SCN_MINOR(X) MINOR((X)->i_rdev) - SCN_BASE_MNR
+#define USB_SCN_MINOR(X) minor((X)->i_rdev) - SCN_BASE_MNR
 
 #ifdef DEBUG
 #define SCN_DEBUG(X) X
@@ -243,7 +243,7 @@
 	devfs_handle_t devfs;	/* devfs device */
 	struct urb scn_irq;
 	unsigned int ifnum;	/* Interface number of the USB device */
-	kdev_t scn_minor;	/* Scanner minor - used in disconnect() */
+	int scn_minor;		/* Scanner minor - used in disconnect() */
 	unsigned char button;	/* Front panel buffer */
 	char isopen;		/* Not zero if the device is open */
 	char present;		/* Not zero if device is present */
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/serial/Config.in linux/drivers/usb/serial/Config.in
--- v2.5.1/linux/drivers/usb/serial/Config.in	Wed Oct 17 14:35:17 2001
+++ linux/drivers/usb/serial/Config.in	Thu Jan  3 13:21:28 2002
@@ -15,6 +15,7 @@
 dep_tristate '  USB Empeg empeg-car Mark I/II Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB Handspring Visor / Palm m50x / Sony Clie Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
+dep_tristate '  USB Compaq iPAQ Driver' CONFIG_USB_SERIAL_IPAQ $CONFIG_USB_SERIAL
 dep_tristate '  USB IR Dongle Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_IR $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB Inside Out Edgeport Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
@@ -28,6 +29,7 @@
    dep_mbool '    USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W $CONFIG_USB_SERIAL_KEYSPAN
    dep_mbool '    USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W $CONFIG_USB_SERIAL_KEYSPAN
 dep_tristate '  USB MCT Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate '  USB KL5KUSB105 (Palmconnect) Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KLSI $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB Prolific 2303 Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_PL2303 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB REINER SCT cyberJack pinpad/e-com chipcard reader (EXPERIMENTAL)' CONFIG_USB_SERIAL_CYBERJACK $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB Xircom / Entregra Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_XIRCOM $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/serial/Makefile linux/drivers/usb/serial/Makefile
--- v2.5.1/linux/drivers/usb/serial/Makefile	Tue Oct  9 15:15:02 2001
+++ linux/drivers/usb/serial/Makefile	Thu Jan  3 13:21:28 2002
@@ -8,6 +8,7 @@
 
 obj-$(CONFIG_USB_SERIAL)                        += usbserial.o
 obj-$(CONFIG_USB_SERIAL_VISOR)			+= visor.o
+obj-$(CONFIG_USB_SERIAL_IPAQ)			+= ipaq.o
 obj-$(CONFIG_USB_SERIAL_WHITEHEAT)		+= whiteheat.o
 obj-$(CONFIG_USB_SERIAL_FTDI_SIO)		+= ftdi_sio.o
 obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA)		+= keyspan_pda.o
@@ -22,7 +23,8 @@
 obj-$(CONFIG_USB_SERIAL_PL2303)			+= pl2303.o
 obj-$(CONFIG_USB_SERIAL_CYBERJACK)		+= cyberjack.o
 obj-$(CONFIG_USB_SERIAL_IR)			+= ir-usb.o
- 
+obj-$(CONFIG_USB_SERIAL_KLSI)			+= kl5kusb105.o
+
 # Objects that export symbols.
 export-objs	:= usbserial.o
 
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/serial/ipaq.c linux/drivers/usb/serial/ipaq.c
--- v2.5.1/linux/drivers/usb/serial/ipaq.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/ipaq.c	Tue Jan  1 13:52:10 2002
@@ -0,0 +1,525 @@
+/*
+ * USB Compaq iPAQ driver
+ *
+ *	Copyright (C) 2001
+ *	    Ganesh Varadarajan <ganesh@veritas.com>
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	static int debug = 1;
+#else
+	static int debug = 0;
+#endif
+
+#include "usb-serial.h"
+#include "ipaq.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.1"
+#define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>"
+#define DRIVER_DESC "USB Compaq iPAQ driver"
+
+/* Function prototypes for an ipaq */
+static int  ipaq_open (struct usb_serial_port *port, struct file *filp);
+static void ipaq_close (struct usb_serial_port *port, struct file *filp);
+static int  ipaq_startup (struct usb_serial *serial);
+static void ipaq_shutdown (struct usb_serial *serial);
+static int ipaq_write(struct usb_serial_port *port, int from_user, const unsigned char *buf,
+		       int count);
+static int ipaq_write_bulk(struct usb_serial_port *port, int from_user, const unsigned char *buf,
+			   int count);
+static int ipaq_write_flush(struct usb_serial_port *port);
+static void ipaq_read_bulk_callback (struct urb *urb);
+static void ipaq_write_bulk_callback(struct urb *urb);
+static int ipaq_write_room(struct usb_serial_port *port);
+static int ipaq_chars_in_buffer(struct usb_serial_port *port);
+static void ipaq_destroy_lists(struct usb_serial_port *port);
+
+
+static __devinitdata struct usb_device_id ipaq_id_table [] = {
+	{ USB_DEVICE(IPAQ_VENDOR_ID, IPAQ_PRODUCT_ID) },
+	{ }					/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, ipaq_id_table);
+
+/* All of the device info needed for the Compaq iPAQ */
+struct usb_serial_device_type ipaq_device = {
+	owner:			THIS_MODULE,
+	name:			"Compaq iPAQ",
+	id_table:		ipaq_id_table,
+	num_interrupt_in:	0,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		1,
+	open:			ipaq_open,
+	close:			ipaq_close,
+	startup:		ipaq_startup,
+	shutdown:		ipaq_shutdown,
+	write:			ipaq_write,
+	write_room:		ipaq_write_room,
+	chars_in_buffer:	ipaq_chars_in_buffer,
+	read_bulk_callback:	ipaq_read_bulk_callback,
+	write_bulk_callback:	ipaq_write_bulk_callback,
+};
+
+static spinlock_t	write_list_lock;
+static int		bytes_in;
+static int		bytes_out;
+
+static int ipaq_open(struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial	*serial = port->serial;
+	struct ipaq_private	*priv;
+	struct ipaq_packet	*pkt;
+	int			i, result = 0;
+
+	if (port_paranoia_check(port, __FUNCTION__)) {
+		return -ENODEV;
+	}
+	
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	down(&port->sem);
+	
+	++port->open_count;
+	
+	if (port->open_count == 1) {
+		bytes_in = 0;
+		bytes_out = 0;
+		priv = (struct ipaq_private *)kmalloc(sizeof(struct ipaq_private), GFP_KERNEL);
+		if (priv == NULL) {
+			err(__FUNCTION__ " - Out of memory");
+			return -ENOMEM;
+		}
+		port->private = (void *)priv;
+		priv->active = 0;
+		priv->queue_len = 0;
+		INIT_LIST_HEAD(&priv->queue);
+		INIT_LIST_HEAD(&priv->freelist);
+
+		for (i = 0; i < URBDATA_QUEUE_MAX / PACKET_SIZE; i++) {
+			pkt = kmalloc(sizeof(struct ipaq_packet), GFP_KERNEL);
+			if (pkt == NULL) {
+				goto enomem;
+			}
+			pkt->data = kmalloc(PACKET_SIZE, GFP_KERNEL);
+			if (pkt->data == NULL) {
+				kfree(pkt);
+				goto enomem;
+			}
+			pkt->len = 0;
+			pkt->written = 0;
+			INIT_LIST_HEAD(&pkt->list);
+			list_add(&pkt->list, &priv->freelist);
+			priv->free_len += PACKET_SIZE;
+		}
+
+		/*
+		 * Force low latency on. This will immediately push data to the line
+		 * discipline instead of queueing.
+		 */
+
+		port->tty->low_latency = 1;
+
+		/*
+		 * Lose the small buffers usbserial provides. Make larger ones.
+		 */
+
+		kfree(port->bulk_in_buffer);
+		kfree(port->bulk_out_buffer);
+		port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
+		if (port->bulk_in_buffer == NULL) {
+			goto enomem;
+		}
+		port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
+		if (port->bulk_out_buffer == NULL) {
+			kfree(port->bulk_in_buffer);
+			goto enomem;
+		}
+		port->read_urb->transfer_buffer = port->bulk_in_buffer;
+		port->write_urb->transfer_buffer = port->bulk_out_buffer;
+		port->read_urb->transfer_buffer_length = URBDATA_SIZE;
+		port->bulk_out_size = port->write_urb->transfer_buffer_length = URBDATA_SIZE;
+		
+		/* Start reading from the device */
+		FILL_BULK_URB(port->read_urb, serial->dev, 
+			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+			      ipaq_read_bulk_callback, port);
+		result = usb_submit_urb(port->read_urb);
+		if (result) {
+			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+		}
+
+		/*
+		 * Send out two control messages observed in win98 sniffs. Not sure what
+		 * they do.
+		 */
+
+		result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
+				0x1, 0, NULL, 0, 5 * HZ);
+		if (result < 0) {
+			err(__FUNCTION__ " - failed doing control urb, error %d", result);
+		}
+		result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
+				0x1, 0, NULL, 0, 5 * HZ);
+		if (result < 0) {
+			err(__FUNCTION__ " - failed doing control urb, error %d", result);
+		}
+	}
+	
+	up(&port->sem);
+	
+	return result;
+
+enomem:
+	ipaq_destroy_lists(port);
+	kfree(priv);
+	err(__FUNCTION__ " - Out of memory");
+	return -ENOMEM;
+}
+
+
+static void ipaq_close(struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial	*serial;
+	struct ipaq_private	*priv = port->private;
+
+	if (port_paranoia_check(port, __FUNCTION__)) {
+		return; 
+	}
+	
+	dbg(__FUNCTION__ " - port %d", port->number);
+			 
+	serial = get_usb_serial(port, __FUNCTION__);
+	if (!serial)
+		return;
+	
+	down (&port->sem);
+
+	--port->open_count;
+
+	if (port->open_count <= 0) {
+
+		/*
+		 * shut down bulk read and write
+		 */
+
+		usb_unlink_urb(port->write_urb);
+		usb_unlink_urb(port->read_urb);
+		ipaq_destroy_lists(port);
+		kfree(priv);
+		port->private = NULL;
+		port->open_count = 0;
+
+	}
+	up (&port->sem);
+
+	/* Uncomment the following line if you want to see some statistics in your syslog */
+	/* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
+}
+
+static void ipaq_read_bulk_callback(struct urb *urb)
+{
+	struct usb_serial_port	*port = (struct usb_serial_port *)urb->context;
+	struct usb_serial	*serial = get_usb_serial (port, __FUNCTION__);
+	struct tty_struct	*tty;
+	unsigned char		*data = urb->transfer_buffer;
+	int			i, result;
+
+	if (port_paranoia_check(port, __FUNCTION__))
+		return;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	if (!serial) {
+		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		return;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+		return;
+	}
+
+	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+	tty = port->tty;
+	if (urb->actual_length) {
+		for (i = 0; i < urb->actual_length ; ++i) {
+			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
+			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				tty_flip_buffer_push(tty);
+			}
+			/* this doesn't actually push the data through unless tty->low_latency is set */
+			tty_insert_flip_char(tty, data[i], 0);
+		}
+		tty_flip_buffer_push(tty);
+		bytes_in += urb->actual_length;
+	}
+
+	/* Continue trying to always read  */
+	FILL_BULK_URB(port->read_urb, serial->dev, 
+		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+		      ipaq_read_bulk_callback, port);
+	result = usb_submit_urb(port->read_urb);
+	if (result)
+		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+	return;
+}
+
+static int ipaq_write(struct usb_serial_port *port, int from_user, const unsigned char *buf,
+		       int count)
+{
+	const unsigned char	*current_position = buf;
+	int			bytes_sent = 0;
+	int			transfer_size;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	usb_serial_debug_data(__FILE__, __FUNCTION__, count, buf);
+	
+	while (count > 0) {
+		transfer_size = min(count, PACKET_SIZE);
+		if (ipaq_write_bulk(port, from_user, current_position, transfer_size)) {
+			break;
+		}
+		current_position += transfer_size;
+		bytes_sent += transfer_size;
+		count -= transfer_size;
+		bytes_out += transfer_size;
+	}
+
+	return bytes_sent;
+} 
+
+static int ipaq_write_bulk(struct usb_serial_port *port, int from_user, const unsigned char *buf,
+			   int count)
+{
+	struct ipaq_private	*priv = port->private;
+	struct ipaq_packet	*pkt = NULL;
+	int			result = 0;
+	unsigned long		flags;
+
+	if (priv->free_len <= 0) {
+		dbg(__FUNCTION__ " - we're stuffed");
+		return -EAGAIN;
+	}
+
+	spin_lock_irqsave(&write_list_lock, flags);
+	if (!list_empty(&priv->freelist)) {
+		pkt = list_entry(priv->freelist.next, struct ipaq_packet, list);
+		list_del(&pkt->list);
+		priv->free_len -= PACKET_SIZE;
+	}
+	spin_unlock_irqrestore(&write_list_lock, flags);
+	if (pkt == NULL) {
+		dbg(__FUNCTION__ " - we're stuffed");
+		return -EAGAIN;
+	}
+
+	if (from_user) {
+		copy_from_user(pkt->data, buf, count);
+	} else {
+		memcpy(pkt->data, buf, count);
+	}
+	usb_serial_debug_data(__FILE__, __FUNCTION__, count, pkt->data);
+
+	pkt->len = count;
+	pkt->written = 0;
+	spin_lock_irqsave(&write_list_lock, flags);
+	list_add_tail(&pkt->list, &priv->queue);
+	priv->queue_len += count;
+	if (priv->active == 0) {
+		priv->active = 1;
+		result = ipaq_write_flush(port);
+	}
+	spin_unlock_irqrestore(&write_list_lock, flags);
+	return result;
+}
+
+static int ipaq_write_flush(struct usb_serial_port *port)
+{
+	struct ipaq_private	*priv = (struct ipaq_private *)port->private;
+	struct usb_serial	*serial = port->serial;
+	int			count, room, result;
+	struct ipaq_packet	*pkt;
+	struct urb		*urb = port->write_urb;
+	struct list_head	*tmp;
+
+	if (urb->status == -EINPROGRESS) {
+		/* Should never happen */
+		err(__FUNCTION__ " - flushing while urb is active !");
+		return -EAGAIN;
+	}
+	room = URBDATA_SIZE;
+	for (tmp = priv->queue.next; tmp != &priv->queue;) {
+		pkt = list_entry(tmp, struct ipaq_packet, list);
+		tmp = tmp->next;
+		count = min(room, (int)(pkt->len - pkt->written));
+		memcpy(urb->transfer_buffer + (URBDATA_SIZE - room),
+		       pkt->data + pkt->written, count);
+		room -= count;
+		pkt->written += count;
+		priv->queue_len -= count;
+		if (pkt->written == pkt->len) {
+			list_del(&pkt->list);
+			list_add(&pkt->list, &priv->freelist);
+			priv->free_len += PACKET_SIZE;
+		}
+		if (room == 0) {
+			break;
+		}
+	}
+
+	count = URBDATA_SIZE - room;
+	FILL_BULK_URB(port->write_urb, serial->dev, 
+		      usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
+		      port->write_urb->transfer_buffer, count, ipaq_write_bulk_callback,
+		      port);
+	result = usb_submit_urb(urb);
+	if (result) {
+		err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+	}
+	return result;
+}
+
+static void ipaq_write_bulk_callback(struct urb *urb)
+{
+	struct usb_serial_port	*port = (struct usb_serial_port *)urb->context;
+	struct ipaq_private	*priv = (struct ipaq_private *)port->private;
+	unsigned long		flags;
+
+	if (port_paranoia_check (port, __FUNCTION__)) {
+		return;
+	}
+	
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+	}
+
+	spin_lock_irqsave(&write_list_lock, flags);
+	if (!list_empty(&priv->queue)) {
+		ipaq_write_flush(port);
+	} else {
+		priv->active = 0;
+	}
+	spin_unlock_irqrestore(&write_list_lock, flags);
+	queue_task(&port->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+	
+	return;
+}
+
+static int ipaq_write_room(struct usb_serial_port *port)
+{
+	struct ipaq_private	*priv = (struct ipaq_private *)port->private;
+
+	dbg(__FUNCTION__ " - freelen %d", priv->free_len);
+	return priv->free_len;
+}
+
+static int ipaq_chars_in_buffer(struct usb_serial_port *port)
+{
+	struct ipaq_private	*priv = (struct ipaq_private *)port->private;
+
+	dbg(__FUNCTION__ " - queuelen %d", priv->queue_len);
+	return priv->queue_len;
+}
+
+static void ipaq_destroy_lists(struct usb_serial_port *port)
+{
+	struct ipaq_private	*priv = (struct ipaq_private *)port->private;
+	struct list_head	*tmp;
+	struct ipaq_packet	*pkt;
+
+	for (tmp = priv->queue.next; tmp != &priv->queue;) {
+		pkt = list_entry(tmp, struct ipaq_packet, list);
+		tmp = tmp->next;
+		kfree(pkt->data);
+		kfree(pkt);
+	}
+	for (tmp = priv->freelist.next; tmp != &priv->freelist;) {
+		pkt = list_entry(tmp, struct ipaq_packet, list);
+		tmp = tmp->next;
+		kfree(pkt->data);
+		kfree(pkt);
+	}
+	return;
+}
+
+
+static int ipaq_startup(struct usb_serial *serial)
+{
+	dbg(__FUNCTION__);
+	usb_set_configuration(serial->dev, 1);
+	return 0;
+}
+
+static void ipaq_shutdown(struct usb_serial *serial)
+{
+	int i;
+
+	dbg (__FUNCTION__);
+
+	/* stop reads and writes on all ports */
+	for (i=0; i < serial->num_ports; ++i) {
+		while (serial->port[i].open_count > 0) {
+			ipaq_close(&serial->port[i], NULL);
+		}
+	}
+}
+
+static int __init ipaq_init(void)
+{
+	usb_serial_register(&ipaq_device);
+	info(DRIVER_DESC " " DRIVER_VERSION);
+
+	return 0;
+}
+
+
+static void __exit ipaq_exit(void)
+{
+	usb_serial_deregister(&ipaq_device);
+}
+
+
+module_init(ipaq_init);
+module_exit(ipaq_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/serial/ipaq.h linux/drivers/usb/serial/ipaq.h
--- v2.5.1/linux/drivers/usb/serial/ipaq.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/ipaq.h	Tue Jan  1 13:52:10 2002
@@ -0,0 +1,60 @@
+/*
+ * USB Compaq iPAQ driver
+ *
+ *	Copyright (C) 2001
+ *	    Ganesh Varadarajan <ganesh@veritas.com>
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ * 
+ */
+
+#ifndef __LINUX_USB_SERIAL_IPAQ_H
+#define __LINUX_USB_SERIAL_IPAQ_H
+
+
+#define IPAQ_VENDOR_ID			0x049f
+#define IPAQ_PRODUCT_ID			0x0003
+
+/*
+ * Since we can't queue our bulk write urbs (don't know why - it just
+ * doesn't work), we can send down only one write urb at a time. The simplistic
+ * approach taken by the generic usbserial driver will work, but it's not good
+ * for performance. Therefore, we buffer upto URBDATA_QUEUE_MAX bytes of write
+ * requests coming from the line discipline. This is done by chaining them
+ * in lists of struct ipaq_packet, each packet holding a maximum of
+ * PACKET_SIZE bytes.
+ *
+ * ipaq_write() can be called from bottom half context; hence we can't
+ * allocate memory for packets there. So we initialize a pool of packets at
+ * the first open and maintain a freelist.
+ *
+ * The value of PACKET_SIZE was empirically determined by
+ * checking the maximum write sizes sent down by the ppp ldisc.
+ * URBDATA_QUEUE_MAX is set to 64K, which is the maximum TCP window size
+ * supported by the iPAQ.
+ */
+
+struct ipaq_packet {
+	char			*data;
+	size_t			len;
+	size_t			written;
+	struct list_head	list;
+};
+
+struct ipaq_private {
+	int			active;
+	int			queue_len;
+	int			free_len;
+	struct list_head	queue;
+	struct list_head	freelist;
+};
+
+#define URBDATA_SIZE		4096
+#define URBDATA_QUEUE_MAX	(64 * 1024)
+#define PACKET_SIZE		256
+
+#endif
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/serial/kl5kusb105.c linux/drivers/usb/serial/kl5kusb105.c
--- v2.5.1/linux/drivers/usb/serial/kl5kusb105.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/kl5kusb105.c	Tue Jan  1 13:52:10 2002
@@ -0,0 +1,1086 @@
+/*
+ * KLSI KL5KUSB105 chip RS232 converter driver
+ *
+ *   Copyright (C) 2001 Utz-Uwe Haus <haus@uuhaus.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ * All information about the device was acquired using SniffUSB ans snoopUSB
+ * on Windows98.
+ * It was written out of frustration with the PalmConnect USB Serial adapter
+ * sold by Palm Inc.
+ * Neither Palm, nor their contractor (MCCI) or their supplier (KLSI) provided
+ * information that was not already available.
+ *
+ * It seems that KLSI bought some silicon-design information from ScanLogic, 
+ * whose SL11R processor is at the core of the KL5KUSB chipset from KLSI.
+ * KLSI has firmware available for their devices; it is probable that the
+ * firmware differs from that used by KLSI in their products. If you have an
+ * original KLSI device and can provide some information on it, I would be 
+ * most interested in adding support for it here. If you have any information 
+ * on the protocol used (or find errors in my reverse-engineered stuff), please
+ * let me know.
+ *
+ * The code was only tested with a PalmConnect USB adapter; if you
+ * are adventurous, try it with any KLSI-based device and let me know how it
+ * breaks so that I can fix it!
+ */
+
+/* TODO:
+ *	check modem line signals
+ *	implement handshaking or decide that we do not support it
+ */
+
+/* History:
+ *   0.3a - implemented pools of write URBs
+ *   0.3  - alpha version for public testing
+ *   0.2  - TIOCMGET works, so autopilot(1) can be used!
+ *   0.1  - can be used to to pilot-xfer -p /dev/ttyUSB0 -l
+ *
+ *   The driver skeleton is mainly based on mct_u232.c and various other 
+ *   pieces of code shamelessly copied from the drivers/usb/serial/ directory.
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ 	static int debug = 1;
+#else
+ 	static int debug;
+#endif
+
+#include "usb-serial.h"
+#include "kl5kusb105.h"
+
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.3a"
+#define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>"
+#define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver"
+
+
+/*
+ * Function prototypes
+ */
+static int  klsi_105_startup	         (struct usb_serial *serial);
+static void klsi_105_shutdown	         (struct usb_serial *serial);
+static int  klsi_105_open	         (struct usb_serial_port *port,
+					  struct file *filp);
+static void klsi_105_close	         (struct usb_serial_port *port,
+					  struct file *filp);
+static int  klsi_105_write	         (struct usb_serial_port *port,
+					  int from_user,
+					  const unsigned char *buf,
+					  int count);
+static void klsi_105_write_bulk_callback (struct urb *urb);
+static int  klsi_105_chars_in_buffer     (struct usb_serial_port *port);
+static int  klsi_105_write_room          (struct usb_serial_port *port);
+
+static void klsi_105_read_bulk_callback  (struct urb *urb);
+static void klsi_105_set_termios         (struct usb_serial_port *port,
+					  struct termios * old);
+static int  klsi_105_ioctl	         (struct usb_serial_port *port,
+					  struct file * file,
+					  unsigned int cmd,
+					  unsigned long arg);
+static void klsi_105_throttle		 (struct usb_serial_port *port);
+static void klsi_105_unthrottle		 (struct usb_serial_port *port);
+/*
+static void klsi_105_break_ctl	         (struct usb_serial_port *port,
+					  int break_state );
+ */
+
+/*
+ * All of the device info needed for the KLSI converters.
+ */
+static __devinitdata struct usb_device_id id_table [] = {
+	{ USB_DEVICE(PALMCONNECT_VID, PALMCONNECT_PID) },
+	{ USB_DEVICE(KLSI_VID, KLSI_KL5KUSB105D_PID) },
+	{ }		/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+
+static struct usb_serial_device_type kl5kusb105d_device = {
+	owner:               THIS_MODULE,
+	name:		     "KL5KUSB105D / PalmConnect",
+	id_table:	     id_table,
+	num_interrupt_in:    1,
+	num_bulk_in:	     1,
+	num_bulk_out:	     1,
+	num_ports:	     1,
+	open:		     klsi_105_open,
+	close:		     klsi_105_close,
+	write:		     klsi_105_write,
+	write_bulk_callback: klsi_105_write_bulk_callback,
+	chars_in_buffer:     klsi_105_chars_in_buffer,
+	write_room:          klsi_105_write_room,
+	read_bulk_callback:  klsi_105_read_bulk_callback,
+	ioctl:		     klsi_105_ioctl,
+	set_termios:	     klsi_105_set_termios,
+	/*break_ctl:	     klsi_105_break_ctl,*/
+	startup:	     klsi_105_startup,
+	shutdown:	     klsi_105_shutdown,
+	throttle:	     klsi_105_throttle,
+	unthrottle:	     klsi_105_unthrottle,
+};
+
+struct klsi_105_port_settings {
+	__u8	pktlen;		/* always 5, it seems */
+	__u8	baudrate;
+	__u8	databits;
+	__u8	unknown1;
+	__u8	unknown2;
+} __attribute__ ((packed));
+
+/* we implement a pool of NUM_URBS urbs per usb_serial */
+#define NUM_URBS			1
+#define URB_TRANSFER_BUFFER_SIZE	64
+struct klsi_105_private {
+	struct klsi_105_port_settings	cfg;
+	struct termios			termios;
+	unsigned long			line_state; /* modem line settings */
+	/* write pool */
+	struct urb *			write_urb_pool[NUM_URBS];
+	spinlock_t			write_urb_pool_lock;
+	unsigned long			bytes_in;
+	unsigned long			bytes_out;
+};
+
+
+/*
+ * Handle vendor specific USB requests
+ */
+
+
+#define KLSI_TIMEOUT	 (HZ * 5 ) /* default urb timeout */
+
+static int klsi_105_chg_port_settings(struct usb_serial *serial,
+				      struct klsi_105_port_settings *settings)
+{
+	int rc;
+
+        rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			     KL5KUSB105A_SIO_SET_DATA,
+                             USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_INTERFACE,
+			     0, /* value */
+			     0, /* index */
+			     settings,
+			     sizeof(struct klsi_105_port_settings),
+			     KLSI_TIMEOUT);
+	if (rc < 0)
+		err("Change port settings failed (error = %d)", rc);
+	info(__FUNCTION__ " - %d byte block, baudrate %x, databits %d, u1 %d, u2 %d",
+	    settings->pktlen,
+	    settings->baudrate, settings->databits,
+	    settings->unknown1, settings->unknown2);
+        return rc;
+} /* klsi_105_chg_port_settings */
+
+/* translate a 16-bit status value from the device to linux's TIO bits */
+static unsigned long klsi_105_status2linestate(const __u16 status)
+{
+	unsigned long res = 0;
+
+	res =   ((status & KL5KUSB105A_DSR) ? TIOCM_DSR : 0)
+	      | ((status & KL5KUSB105A_CTS) ? TIOCM_CTS : 0)
+	      ;
+
+	return res;
+}
+/* 
+ * Read line control via vendor command and return result through
+ * *line_state_p 
+ */
+/* It seems that the status buffer has always only 2 bytes length */
+#define KLSI_STATUSBUF_LEN	2
+static int klsi_105_get_line_state(struct usb_serial *serial,
+				   unsigned long *line_state_p)
+{
+	int rc;
+	__u8 status_buf[KLSI_STATUSBUF_LEN] = { -1,-1};
+	__u16 status;
+
+	info(__FUNCTION__ " - sending SIO Poll request");
+        rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+			     KL5KUSB105A_SIO_POLL,
+                             USB_TYPE_VENDOR | USB_DIR_IN,
+			     0, /* value */
+			     0, /* index */
+			     status_buf, KLSI_STATUSBUF_LEN,
+			     10*HZ
+			     );
+	if (rc < 0)
+		err("Reading line status failed (error = %d)", rc);
+	else {
+		status = status_buf[0] + (status_buf[1]<<8);
+
+		info(__FUNCTION__ " - read status %x %x",
+		     status_buf[0], status_buf[1]);
+
+		*line_state_p = klsi_105_status2linestate(status);
+	}
+
+        return rc;
+}
+
+
+/*
+ * Driver's tty interface functions
+ */
+
+static int klsi_105_startup (struct usb_serial *serial)
+{
+	struct klsi_105_private *priv;
+	int i;
+
+	/* check if we support the product id (see keyspan.c)
+	 * FIXME
+	 */
+
+	/* allocate the private data structure */
+	for (i=0; i<serial->num_ports; i++) {
+		serial->port[i].private = kmalloc(sizeof(struct klsi_105_private),
+						   GFP_KERNEL);
+		if (!serial->port[i].private) {
+			dbg(__FUNCTION__ "kmalloc for klsi_105_private failed.");
+			return (-1); /* error */
+		}
+		priv = (struct klsi_105_private *)serial->port[i].private;
+		/* set initial values for control structures */
+		priv->cfg.pktlen    = 5;
+		priv->cfg.baudrate  = kl5kusb105a_sio_b9600;
+		priv->cfg.databits  = kl5kusb105a_dtb_8;
+		priv->cfg.unknown1  = 0;
+		priv->cfg.unknown2  = 1;
+
+		priv->line_state    = 0;
+
+		priv->bytes_in	    = 0;
+		priv->bytes_out	    = 0;
+
+		spin_lock_init (&priv->write_urb_pool_lock);
+		for (i=0; i<NUM_URBS; i++) {
+			struct urb* urb = usb_alloc_urb(0);
+
+			priv->write_urb_pool[i] = urb;
+			if (urb == NULL) {
+				err("No more urbs???");
+				continue;
+			}
+
+			urb->transfer_buffer = NULL;
+			urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE,
+							GFP_KERNEL);
+			if (!urb->transfer_buffer) {
+				err (__FUNCTION__ 
+				     " - out of memory for urb buffers.");
+				continue;
+			}
+		}
+
+		/* priv->termios is left uninitalized until port opening */
+		init_waitqueue_head(&serial->port[i].write_wait);
+	}
+	
+	return (0);
+} /* klsi_105_startup */
+
+
+static void klsi_105_shutdown (struct usb_serial *serial)
+{
+	int i;
+	
+	dbg (__FUNCTION__);
+
+	/* stop reads and writes on all ports */
+	for (i=0; i < serial->num_ports; ++i) {
+		struct klsi_105_private *priv = 
+			(struct klsi_105_private*) serial->port[i].private;
+		unsigned long flags;
+		while (serial->port[i].open_count > 0) {
+			klsi_105_close (&serial->port[i], NULL);
+		}
+
+		if (priv) {
+			/* kill our write urb pool */
+			int j;
+			struct urb **write_urbs = priv->write_urb_pool;
+			spin_lock_irqsave(&priv->write_urb_pool_lock,flags);
+
+			for (j = 0; j < NUM_URBS; j++) {
+				if (write_urbs[j]) {
+					/* FIXME - uncomment the following
+					 * usb_unlink_urb call when the host
+					 * controllers get fixed to set
+					 * urb->dev = NULL after the urb is
+					 * finished.  Otherwise this call
+					 * oopses. */
+					/* usb_unlink_urb(write_urbs[j]); */
+					if (write_urbs[j]->transfer_buffer)
+						    kfree(write_urbs[j]->transfer_buffer);
+					usb_free_urb (write_urbs[j]);
+				}
+			}
+
+			spin_unlock_irqrestore (&priv->write_urb_pool_lock,
+					       	flags);
+
+			kfree(serial->port[i].private);
+		}
+	}
+} /* klsi_105_shutdown */
+
+static int  klsi_105_open (struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial *serial = port->serial;
+	struct klsi_105_private *priv = (struct klsi_105_private *)port->private;
+	int retval = 0;
+
+	dbg(__FUNCTION__" port %d", port->number);
+
+	down (&port->sem);
+	
+	++port->open_count;
+
+	if (port->open_count == 1) {
+		int rc;
+		int i;
+		unsigned long line_state;
+
+		/* force low_latency on so that our tty_push actually forces
+		 * the data through
+		 * port->tty->low_latency = 1; */
+
+		/* Do a defined restart:
+		 * Set up sane default baud rate and send the 'READ_ON'
+		 * vendor command. 
+		 * FIXME: set modem line control (how?)
+		 * Then read the modem line control and store values in
+		 * priv->line_state.
+		 */
+		priv->cfg.pktlen   = 5;
+		priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+		priv->cfg.databits = kl5kusb105a_dtb_8;
+		priv->cfg.unknown1 = 0;
+		priv->cfg.unknown2 = 1;
+		klsi_105_chg_port_settings(serial, &(priv->cfg));
+		
+		/* set up termios structure */
+		priv->termios.c_iflag = port->tty->termios->c_iflag;
+		priv->termios.c_oflag = port->tty->termios->c_oflag;
+		priv->termios.c_cflag = port->tty->termios->c_cflag;
+		priv->termios.c_lflag = port->tty->termios->c_lflag;
+		for (i=0; i<NCCS; i++)
+			priv->termios.c_cc[i] = port->tty->termios->c_cc[i];
+
+
+		/* READ_ON and urb submission */
+		FILL_BULK_URB(port->read_urb, serial->dev, 
+			      usb_rcvbulkpipe(serial->dev,
+					      port->bulk_in_endpointAddress),
+			      port->read_urb->transfer_buffer,
+			      port->read_urb->transfer_buffer_length,
+			      klsi_105_read_bulk_callback,
+			      port);
+		port->read_urb->transfer_flags |= USB_QUEUE_BULK;
+
+		rc = usb_submit_urb(port->read_urb);
+		if (rc) {
+			err(__FUNCTION__ 
+			    " - failed submitting read urb, error %d", rc);
+			retval = rc;
+			goto exit;
+		}
+
+		rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0),
+				     KL5KUSB105A_SIO_CONFIGURE,
+				     USB_TYPE_VENDOR|USB_DIR_OUT|USB_RECIP_INTERFACE,
+				     KL5KUSB105A_SIO_CONFIGURE_READ_ON,
+				     0, /* index */
+				     NULL,
+				     0,
+				     KLSI_TIMEOUT);
+		if (rc < 0) {
+			err("Enabling read failed (error = %d)", rc);
+			retval = rc;
+		} else 
+			dbg(__FUNCTION__ " - enabled reading");
+
+		rc = klsi_105_get_line_state(serial, &line_state);
+		if (rc >= 0) {
+			priv->line_state = line_state;
+			dbg(__FUNCTION__ 
+			    " - read line state 0x%lx", line_state);
+			retval = 0;
+		} else
+			retval = rc;
+	}
+
+exit:
+	up (&port->sem);
+	
+	return retval;
+} /* klsi_105_open */
+
+
+static void klsi_105_close (struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial *serial;
+	struct klsi_105_private *priv 
+		= (struct klsi_105_private *)port->private;
+	dbg(__FUNCTION__" port %d", port->number);
+
+	serial = get_usb_serial (port, __FUNCTION__);
+
+	if(!serial)
+		return;
+
+	down (&port->sem);
+
+	--port->open_count;
+
+	if (port->open_count <= 0) {
+		/* send READ_OFF */
+		int rc = usb_control_msg(serial->dev,
+					 usb_sndctrlpipe(serial->dev, 0),
+					 KL5KUSB105A_SIO_CONFIGURE,
+					 USB_TYPE_VENDOR | USB_DIR_OUT,
+					 KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
+					 0, /* index */
+					 NULL, 0,
+					 KLSI_TIMEOUT);
+		if (rc < 0)
+			    err("Disabling read failed (error = %d)", rc);
+
+		/* shutdown our bulk reads and writes */
+		usb_unlink_urb (port->write_urb);
+		usb_unlink_urb (port->read_urb);
+		/* unlink our write pool */
+		/* FIXME */
+		/* wgg - do I need this? I think so. */
+		usb_unlink_urb (port->interrupt_in_urb);
+		port->open_count = 0;
+		info("kl5kusb105 port stats: %ld bytes in, %ld bytes out", priv->bytes_in, priv->bytes_out);
+	}
+	
+	up (&port->sem);
+} /* klsi_105_close */
+
+
+/* We need to write a complete 64-byte data block and encode the
+ * number actually sent in the first double-byte, LSB-order. That 
+ * leaves at most 62 bytes of payload.
+ */
+#define KLSI_105_DATA_OFFSET	2   /* in the bulk urb data block */
+
+
+static int klsi_105_write (struct usb_serial_port *port, int from_user,
+			   const unsigned char *buf, int count)
+{
+	struct usb_serial *serial = port->serial;
+	struct klsi_105_private *priv = 
+		(struct klsi_105_private*) port->private;
+	int result, size;
+	int bytes_sent=0;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	down (&port->sem);	/* to lock against someone else trying to
+				   take an URB we just selected from the pool */
+
+	while (count > 0) {
+		/* try to find a free urb (write 0 bytes if none) */
+		struct urb *urb = NULL;
+		unsigned long flags;
+		int i;
+		/* since the pool is per-port we might not need the spin lock !? */
+		spin_lock_irqsave (&priv->write_urb_pool_lock, flags);
+		for (i=0; i<NUM_URBS; i++) {
+			if (priv->write_urb_pool[i]->status != -EINPROGRESS) {
+				urb = priv->write_urb_pool[i];
+				dbg(__FUNCTION__ " - using pool URB %d", i);
+				break;
+			}
+		}
+		spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+
+		if (urb==NULL) {
+			dbg (__FUNCTION__ " - no more free urbs");
+			goto exit;
+		}
+
+		if (urb->transfer_buffer == NULL) {
+			urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+			if (urb->transfer_buffer == NULL) {
+				err(__FUNCTION__ " - no more kernel memory...");
+				goto exit;
+			}
+		}
+
+		size = min (count, port->bulk_out_size - KLSI_105_DATA_OFFSET);
+		size = min (size, URB_TRANSFER_BUFFER_SIZE - KLSI_105_DATA_OFFSET);
+
+		if (from_user) {
+			if (copy_from_user(urb->transfer_buffer
+					   + KLSI_105_DATA_OFFSET, buf, size)) {
+				up (&port->sem);
+				return -EFAULT;
+			}
+		} else {
+			memcpy (urb->transfer_buffer + KLSI_105_DATA_OFFSET,
+			       	buf, size);
+		}
+
+		/* write payload size into transfer buffer */
+		((__u8 *)urb->transfer_buffer)[0] = (__u8) (size & 0xFF);
+		((__u8 *)urb->transfer_buffer)[1] = (__u8) ((size & 0xFF00)>>8);
+
+		/* set up our urb */
+		FILL_BULK_URB(urb, serial->dev,
+			      usb_sndbulkpipe(serial->dev,
+					      port->bulk_out_endpointAddress),
+			      urb->transfer_buffer,
+			      URB_TRANSFER_BUFFER_SIZE,
+			      klsi_105_write_bulk_callback,
+			      port);
+		urb->transfer_flags |= USB_QUEUE_BULK;
+
+
+		/* send the data out the bulk port */
+		result = usb_submit_urb(urb);
+		if (result) {
+			err(__FUNCTION__
+			    " - failed submitting write urb, error %d", result);
+			goto exit;
+		}
+		buf += size;
+		bytes_sent += size;
+		count -= size;
+	}
+exit:
+	up (&port->sem);
+	priv->bytes_out+=bytes_sent;
+
+	return bytes_sent;	/* that's how much we wrote */
+} /* klsi_105_write */
+
+static void klsi_105_write_bulk_callback ( struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial = port->serial;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	if (!serial) {
+		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		return;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero write bulk status received: %d",
+		    urb->status);
+		return;
+	}
+
+	/* from generic_write_bulk_callback */
+	queue_task(&port->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+
+	return;
+} /* klsi_105_write_bulk_completion_callback */
+
+
+/* return number of characters currently in the writing process */
+static int klsi_105_chars_in_buffer (struct usb_serial_port *port)
+{
+	int chars = 0;
+	int i;
+	unsigned long flags;
+	struct klsi_105_private *priv = 
+		(struct klsi_105_private*) port->private;
+
+	spin_lock_irqsave (&priv->write_urb_pool_lock, flags);
+
+	for (i = 0; i < NUM_URBS; ++i) {
+		if (priv->write_urb_pool[i]->status == -EINPROGRESS) {
+			chars += URB_TRANSFER_BUFFER_SIZE;
+		}
+	}
+
+	spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+
+	dbg (__FUNCTION__ " - returns %d", chars);
+	return (chars);
+}
+
+static int klsi_105_write_room (struct usb_serial_port *port)
+{
+	unsigned long flags;
+	int i;
+	int room = 0;
+	struct klsi_105_private *priv = 
+		(struct klsi_105_private*) port->private;
+
+	spin_lock_irqsave (&priv->write_urb_pool_lock, flags);
+	for (i = 0; i < NUM_URBS; ++i) {
+		if (priv->write_urb_pool[i]->status != -EINPROGRESS) {
+			room += URB_TRANSFER_BUFFER_SIZE;
+		}
+	}
+
+	spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+
+	dbg(__FUNCTION__ " - returns %d", room);
+	return (room);
+}
+
+
+
+static void klsi_105_read_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial = port->serial;
+	struct klsi_105_private *priv = 
+		(struct klsi_105_private*) port->private;
+	struct tty_struct *tty;
+	unsigned char *data = urb->transfer_buffer;
+	int rc;
+
+        dbg(__FUNCTION__ " - port %d", port->number);
+
+	/* The urb might have been killed. */
+        if (urb->status) {
+                dbg(__FUNCTION__ " - nonzero read bulk status received: %d",
+		    urb->status);
+                return;
+        }
+	if (!serial) {
+		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		return;
+	}
+	
+	/* The data received is again preceded by a length double-byte in LSB-
+	 * first order (see klsi_105_write() )
+	 */
+	if (urb->actual_length == 0) {
+		/* empty urbs seem to happen, we ignore them */
+		/* dbg(__FUNCTION__ " - emtpy URB"); */
+	       ;
+	} else if (urb->actual_length <= 2) {
+		dbg(__FUNCTION__ " - size %d URB not understood",
+		    urb->actual_length);
+		usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+	} else {
+		int i;
+		int bytes_sent = ((__u8 *) data)[0] +
+				 ((unsigned int) ((__u8 *) data)[1] << 8);
+		tty = port->tty;
+		/* we should immediately resubmit the URB, before attempting
+		 * to pass the data on to the tty layer. But that needs locking
+		 * against re-entry an then mixed-up data because of
+		 * intermixed tty_flip_buffer_push()s
+		 * FIXME
+		 */ 
+		usb_serial_debug_data (__FILE__, __FUNCTION__,
+				       urb->actual_length, data);
+
+		if (bytes_sent + 2 > urb->actual_length) {
+			dbg(__FUNCTION__ 
+			    " - trying to read more data than available"
+			    " (%d vs. %d)",
+			    bytes_sent+2, urb->actual_length);
+			/* cap at implied limit */
+			bytes_sent = urb->actual_length - 2;
+		}
+
+		for (i = 2; i < 2+bytes_sent; i++) {
+			/* if we insert more than TTY_FLIPBUF_SIZE characters,
+			 * we drop them. */
+			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				tty_flip_buffer_push(tty);
+			}
+			/* this doesn't actually push the data through unless 
+			 * tty->low_latency is set */
+			tty_insert_flip_char(tty, ((__u8*) data)[i], 0);
+		}
+		tty_flip_buffer_push(tty);
+		priv->bytes_in += bytes_sent;
+	}
+	/* Continue trying to always read  */
+	FILL_BULK_URB(port->read_urb, serial->dev, 
+		      usb_rcvbulkpipe(serial->dev,
+				      port->bulk_in_endpointAddress),
+		      port->read_urb->transfer_buffer,
+		      port->read_urb->transfer_buffer_length,
+		      klsi_105_read_bulk_callback,
+		      port);
+	rc = usb_submit_urb(port->read_urb);
+	if (rc)
+		err(__FUNCTION__ 
+		    " - failed resubmitting read urb, error %d", rc);
+} /* klsi_105_read_bulk_callback */
+
+
+static void klsi_105_set_termios (struct usb_serial_port *port,
+				  struct termios *old_termios)
+{
+	struct usb_serial *serial = port->serial;
+	struct klsi_105_private *priv = (struct klsi_105_private *)port->private;
+	unsigned int iflag = port->tty->termios->c_iflag;
+	unsigned int old_iflag = old_termios->c_iflag;
+	unsigned int cflag = port->tty->termios->c_cflag;
+	unsigned int old_cflag = old_termios->c_cflag;
+	
+	/*
+	 * Update baud rate
+	 */
+	if( (cflag & CBAUD) != (old_cflag & CBAUD) ) {
+	        /* reassert DTR and (maybe) RTS on transition from B0 */
+		if( (old_cflag & CBAUD) == B0 ) {
+			dbg(__FUNCTION__ ": baud was B0");
+#if 0
+			priv->control_state |= TIOCM_DTR;
+			/* don't set RTS if using hardware flow control */
+			if (!(old_cflag & CRTSCTS)) {
+				priv->control_state |= TIOCM_RTS;
+			}
+			mct_u232_set_modem_ctrl(serial, priv->control_state);
+#endif
+		}
+		
+		switch(cflag & CBAUD) {
+		case B0: /* handled below */
+			break;
+		case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200;
+			break;
+		case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400;
+			break;
+		case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800;
+			break;
+		case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+			break;
+		case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200;
+			break;
+		case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400;
+			break;
+		case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600;
+			break;
+		case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200;
+			break;
+		default:
+			err("KLSI USB->Serial converter:"
+			    " unsupported baudrate request, using default"
+			    " of 9600");
+			priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+			break;
+		}
+		if ((cflag & CBAUD) == B0 ) {
+			dbg(__FUNCTION__ ": baud is B0");
+			/* Drop RTS and DTR */
+			/* maybe this should be simulated by sending read
+			 * disable and read enable messages?
+			 */
+			;
+#if 0
+			priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+        		mct_u232_set_modem_ctrl(serial, priv->control_state);
+#endif
+		}
+	}
+
+	if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
+		/* set the number of data bits */
+		switch (cflag & CSIZE) {
+		case CS5:
+			dbg(__FUNCTION__ " - 5 bits/byte not supported");
+			return ;
+		case CS6:
+			dbg(__FUNCTION__ " - 6 bits/byte not supported");
+			return ;
+		case CS7:
+			priv->cfg.databits = kl5kusb105a_dtb_7;
+			break;
+		case CS8:
+			priv->cfg.databits = kl5kusb105a_dtb_8;
+			break;
+		default:
+			err("CSIZE was not CS5-CS8, using default of 8");
+			priv->cfg.databits = kl5kusb105a_dtb_8;
+			break;
+		}
+	}
+
+	/*
+	 * Update line control register (LCR)
+	 */
+	if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))
+	    || (cflag & CSTOPB) != (old_cflag & CSTOPB) ) {
+		
+#if 0
+		priv->last_lcr = 0;
+
+		/* set the parity */
+		if (cflag & PARENB)
+			priv->last_lcr |= (cflag & PARODD) ?
+				MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN;
+		else
+			priv->last_lcr |= MCT_U232_PARITY_NONE;
+
+		/* set the number of stop bits */
+		priv->last_lcr |= (cflag & CSTOPB) ?
+			MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
+
+		mct_u232_set_line_ctrl(serial, priv->last_lcr);
+#endif
+		;
+	}
+	
+	/*
+	 * Set flow control: well, I do not really now how to handle DTR/RTS.
+	 * Just do what we have seen with SniffUSB on Win98.
+	 */
+	if( (iflag & IXOFF) != (old_iflag & IXOFF)
+	    || (iflag & IXON) != (old_iflag & IXON)
+	    ||  (cflag & CRTSCTS) != (old_cflag & CRTSCTS) ) {
+		
+		/* Drop DTR/RTS if no flow control otherwise assert */
+#if 0
+		if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS) )
+			priv->control_state |= TIOCM_DTR | TIOCM_RTS;
+		else
+			priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+		mct_u232_set_modem_ctrl(serial, priv->control_state);
+#endif
+		;
+	}
+
+	/* now commit changes to device */
+	klsi_105_chg_port_settings(serial, &(priv->cfg));
+} /* klsi_105_set_termios */
+
+
+#if 0
+static void mct_u232_break_ctl( struct usb_serial_port *port, int break_state )
+{
+	struct usb_serial *serial = port->serial;
+	struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
+	unsigned char lcr = priv->last_lcr;
+
+	dbg (__FUNCTION__ "state=%d", break_state);
+
+	if (break_state)
+		lcr |= MCT_U232_SET_BREAK;
+
+	mct_u232_set_line_ctrl(serial, lcr);
+} /* mct_u232_break_ctl */
+#endif
+
+static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file,
+			   unsigned int cmd, unsigned long arg)
+{
+	struct usb_serial *serial = port->serial;
+	struct klsi_105_private *priv = (struct klsi_105_private *)port->private;
+	int mask;
+	
+	dbg (__FUNCTION__ "cmd=0x%x", cmd);
+
+	/* Based on code from acm.c and others */
+	switch (cmd) {
+	case TIOCMGET: {
+		int rc;
+		unsigned long line_state;
+		dbg (__FUNCTION__ " - TIOCMGET request, just guessing");
+
+		rc = klsi_105_get_line_state(serial, &line_state);
+		if (rc < 0) {
+			err("Reading line control failed (error = %d)", rc);
+			/* better return value? EAGAIN? */
+			return -ENOIOCTLCMD;
+		} else {
+			priv->line_state = line_state;
+			dbg(__FUNCTION__ " - read line state 0x%lx", line_state);
+		}
+		return put_user(priv->line_state, (unsigned long *) arg); 
+	       };
+
+	case TIOCMSET: /* Turns on and off the lines as specified by the mask */
+	case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
+	case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
+		if (get_user(mask, (unsigned long *) arg))
+			return -EFAULT;
+
+		if ((cmd == TIOCMSET) || (mask & TIOCM_RTS)) {
+			/* RTS needs set */
+			if( ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) ||
+			    (cmd == TIOCMBIS) )
+				dbg (__FUNCTION__ " - set RTS not handled");
+				/* priv->control_state |=  TIOCM_RTS; */
+			else
+				dbg (__FUNCTION__ " - clear RTS not handled");
+				/* priv->control_state &= ~TIOCM_RTS; */
+		}
+
+		if ((cmd == TIOCMSET) || (mask & TIOCM_DTR)) {
+			/* DTR needs set */
+			if( ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) ||
+			    (cmd == TIOCMBIS) )
+				dbg (__FUNCTION__ " - set DTR not handled");
+			/*	priv->control_state |=  TIOCM_DTR; */
+			else
+				dbg (__FUNCTION__ " - clear DTR not handled");
+				/* priv->control_state &= ~TIOCM_DTR; */
+		}
+		/*
+		mct_u232_set_modem_ctrl(serial, priv->control_state);
+		*/
+		break;
+					
+	case TIOCMIWAIT:
+		/* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
+		/* TODO */
+		dbg (__FUNCTION__ " - TIOCMIWAIT not handled");
+		return -ENOIOCTLCMD;
+
+	case TIOCGICOUNT:
+		/* return count of modemline transitions */
+		/* TODO */
+		dbg (__FUNCTION__ " - TIOCGICOUNT not handled");
+		return -ENOIOCTLCMD;
+	case TCGETS: {
+	     /* return current info to caller */
+	     int retval;
+
+	     dbg (__FUNCTION__ " - TCGETS data faked/incomplete");
+
+	     retval = verify_area(VERIFY_WRITE, (void *)arg,
+				  sizeof(struct termios));
+
+	     if (retval)
+			 return(retval);
+
+	     kernel_termios_to_user_termios((struct termios *)arg,  
+					    &priv->termios);
+	     return(0);
+	     }
+	case TCSETS: {
+		/* set port termios to the one given by the user */
+		int retval;
+
+		dbg (__FUNCTION__ " - TCSETS not handled");
+
+		retval = verify_area(VERIFY_READ, (void *)arg,
+				     sizeof(struct termios));
+
+		if (retval)
+			    return(retval);
+
+		user_termios_to_kernel_termios(&priv->termios,
+					       (struct termios *)arg);
+		klsi_105_set_termios(port, &priv->termios);
+		return(0);
+	     }
+	case TCSETSW: {
+		/* set port termios and try to wait for completion of last
+		 * write operation */
+		/* We guess here. If there are not too many write urbs
+		 * outstanding, we lie. */
+		/* what is the right way to wait here? schedule() ? */
+	        /*
+		while (klsi_105_chars_in_buffer(port) > (NUM_URBS / 4 ) * URB_TRANSFER_BUFFER_SIZE)
+			    schedule();
+		 */
+		return -ENOIOCTLCMD;
+		      }
+	default:
+		dbg(__FUNCTION__ ": arg not supported - 0x%04x",cmd);
+		return(-ENOIOCTLCMD);
+		break;
+	}
+	return 0;
+} /* klsi_105_ioctl */
+
+static void klsi_105_throttle (struct usb_serial_port *port)
+{
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	down (&port->sem);
+
+	usb_unlink_urb (port->read_urb);
+
+	up (&port->sem);
+
+	return;
+}
+static void klsi_105_unthrottle (struct usb_serial_port *port)
+{
+	int result;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	down (&port->sem);
+
+	port->read_urb->dev = port->serial->dev;
+	result = usb_submit_urb(port->read_urb);
+	if (result)
+		err(__FUNCTION__ " - failed submitting read urb, error %d",
+		    result);
+
+	up (&port->sem);
+
+	return;
+}
+
+
+
+static int __init klsi_105_init (void)
+{
+	usb_serial_register (&kl5kusb105d_device);
+
+	info(DRIVER_DESC " " DRIVER_VERSION);
+	return 0;
+}
+
+
+static void __exit klsi_105_exit (void)
+{
+	usb_serial_deregister (&kl5kusb105d_device);
+}
+
+
+module_init (klsi_105_init);
+module_exit (klsi_105_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL"); 
+
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "enable extensive debugging messages");
+/* FIXME: implement
+MODULE_PARM(num_urbs, "i");
+MODULE_PARM_DESC(num_urbs, "number of URBs to use in write pool");
+*/
+
+/* vim: set sts=8 ts=8 sw=8: */
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/serial/kl5kusb105.h linux/drivers/usb/serial/kl5kusb105.h
--- v2.5.1/linux/drivers/usb/serial/kl5kusb105.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/kl5kusb105.h	Tue Jan  1 13:52:10 2002
@@ -0,0 +1,69 @@
+/*
+ * Definitions for the KLSI KL5KUSB105 serial port adapter
+ */
+
+/* vendor/product pairs that are known to contain this chipset */
+#define PALMCONNECT_VID		0x0830
+#define PALMCONNECT_PID		0x0080
+
+#define KLSI_VID		0x05e9
+#define KLSI_KL5KUSB105D_PID	0x00c0
+
+/* Vendor commands: */
+
+
+/* port table -- the chip supports up to 4 channels */
+
+/* baud rates */
+
+typedef enum {
+  kl5kusb105a_sio_b115200 = 0,
+  kl5kusb105a_sio_b57600  = 1,
+  kl5kusb105a_sio_b38400  = 2,
+  kl5kusb105a_sio_b19200  = 4,
+  kl5kusb105a_sio_b14400  = 5,
+  kl5kusb105a_sio_b9600   = 6,
+  kl5kusb105a_sio_b4800   = 8,   /* unchecked */
+  kl5kusb105a_sio_b2400   = 9,   /* unchecked */
+  kl5kusb105a_sio_b1200   = 0xa,  /* unchecked */
+  kl5kusb105a_sio_b600    = 0xb   /* unchecked */
+} KL5KUSB105A_SIO_baudrate_t;
+
+/* data bits */
+#define kl5kusb105a_dtb_7   7
+#define kl5kusb105a_dtb_8   8
+
+
+
+/* requests: */
+#define KL5KUSB105A_SIO_SET_DATA  1
+#define KL5KUSB105A_SIO_POLL      2
+#define KL5KUSB105A_SIO_CONFIGURE      3
+/* values used for request KL5KUSB105A_SIO_CONFIGURE */
+#define KL5KUSB105A_SIO_CONFIGURE_READ_ON      3
+#define KL5KUSB105A_SIO_CONFIGURE_READ_OFF     2
+
+/* Interpretation of modem status lines */
+/* These need sorting out by individually connecting pins and checking
+ * results. FIXME!
+ * When data is being sent we see 0x30 in the lower byte; this must
+ * contain DSR and CTS ...
+ */
+#define KL5KUSB105A_DSR			((1<<4) | (1<<5))
+#define KL5KUSB105A_CTS			((1<<5) | (1<<4))
+
+#define KL5KUSB105A_WANTS_TO_SEND	0x30
+//#define KL5KUSB105A_DTR			/* Data Terminal Ready */
+//#define KL5KUSB105A_CTS			/* Clear To Send */
+//#define KL5KUSB105A_CD			/* Carrier Detect */
+//#define KL5KUSB105A_DSR			/* Data Set Ready */
+//#define KL5KUSB105A_RxD			/* Receive pin */
+
+//#define KL5KUSB105A_LE
+//#define KL5KUSB105A_RTS		
+//#define KL5KUSB105A_ST		
+//#define KL5KUSB105A_SR		
+//#define KL5KUSB105A_RI			/* Ring Indicator */
+
+/* vim: set ts=8 sts=8: */
+
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c
--- v2.5.1/linux/drivers/usb/serial/usbserial.c	Tue Dec 18 14:56:39 2001
+++ linux/drivers/usb/serial/usbserial.c	Thu Jan  3 12:20:18 2002
@@ -397,16 +397,16 @@
 static LIST_HEAD(usb_serial_driver_list);
 
 
-static struct usb_serial *get_serial_by_minor (int minor)
+static struct usb_serial *get_serial_by_minor (unsigned int minor)
 {
 	return serial_table[minor];
 }
 
 
-static struct usb_serial *get_free_serial (int num_ports, int *minor)
+static struct usb_serial *get_free_serial (int num_ports, unsigned int *minor)
 {
 	struct usb_serial *serial = NULL;
-	int i, j;
+	unsigned int i, j;
 	int good_spot;
 
 	dbg(__FUNCTION__ " %d", num_ports);
@@ -505,7 +505,7 @@
 {
 	struct usb_serial *serial;
 	struct usb_serial_port *port;
-	int portNumber;
+	unsigned int portNumber;
 	
 	dbg(__FUNCTION__);
 
@@ -513,14 +513,14 @@
 	tty->driver_data = NULL;
 
 	/* get the serial object associated with this tty pointer */
-	serial = get_serial_by_minor (MINOR(tty->device));
+	serial = get_serial_by_minor (minor(tty->device));
 
 	if (serial_paranoia_check (serial, __FUNCTION__)) {
 		return -ENODEV;
 	}
 
 	/* set up our port structure making the tty driver remember our port object, and us it */
-	portNumber = MINOR(tty->device) - serial->minor;
+	portNumber = minor(tty->device) - serial->minor;
 	port = &serial->port[portNumber];
 	tty->driver_data = port;
 	port->tty = tty;
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/storage/usb.c linux/drivers/usb/storage/usb.c
--- v2.5.1/linux/drivers/usb/storage/usb.c	Sun Nov 11 10:01:32 2001
+++ linux/drivers/usb/storage/usb.c	Tue Dec 25 17:04:40 2001
@@ -1002,7 +1002,7 @@
 
 		/* now register	 - our detect function will be called */
 		ss->htmplt.module = THIS_MODULE;
-		scsi_register_module(MODULE_SCSI_HA, &(ss->htmplt));
+		scsi_register_host(&ss->htmplt);
 
 		/* lock access to the data structures */
 		down(&us_list_semaphore);
@@ -1107,8 +1107,8 @@
 	 * interface
 	 */
 	for (next = us_list; next; next = next->next) {
-		US_DEBUGP("-- calling scsi_unregister_module()\n");
-		scsi_unregister_module(MODULE_SCSI_HA, &(next->htmplt));
+		US_DEBUGP("-- calling scsi_unregister_host()\n");
+		scsi_unregister_host(&next->htmplt);
 	}
 
 	/* While there are still structures, free them.  Note that we are
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/stv680.c linux/drivers/usb/stv680.c
--- v2.5.1/linux/drivers/usb/stv680.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/stv680.c	Thu Jan  3 13:21:28 2002
@@ -0,0 +1,1633 @@
+/*
+ *  STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net)
+ *  
+ * Thanks to STMicroelectronics for information on the usb commands, and 
+ * to Steve Miller at STM for his help and encouragement while I was 
+ * writing this driver.
+ *
+ * This driver is based heavily on the 
+ * Endpoints (formerly known as AOX) se401 USB Camera Driver
+ * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
+ *
+ * Still somewhat based on the Linux ov511 driver.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History: 
+ * ver 0.1 October, 2001. Initial attempt. 
+ *
+ * ver 0.2 November, 2001. Fixed asbility to resize, added brightness
+ *                         function, made more stable (?)
+ *
+ * ver 0.21 Nov, 2001.     Added gamma correction and white balance, 
+ *                         due to Alexander Schwartz. Still trying to 
+ *                         improve stablility. Moved stuff into stv680.h
+ *
+ * ver 0.22 Nov, 2001.	   Added sharpen function (by Michael Sweet, 
+ *                         mike@easysw.com) from GIMP, also used in pencam. 
+ *                         Simple, fast, good integer math routine.
+ *
+ * ver 0.23 Dec, 2001 (gkh)
+ * 			   Took out sharpen function, ran code through
+ * 			   Lindent, and did other minor tweaks to get
+ * 			   things to work properly with 2.5.1
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/pagemap.h>
+#include <linux/wrapper.h>
+#include <linux/smp_lock.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/videodev.h>
+#include <linux/usb.h>
+
+#include "stv680.h"
+
+static int video_nr = -1;
+static int swapRGB = 0;
+
+static unsigned int debug = 0;
+
+#define PDEBUG(level, fmt, args...) \
+	do { \
+	if (debug >= level)	\
+		info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args);	\
+	} while (0)
+
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.23"
+#define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>"
+#define DRIVER_DESC "STV0680 USB Camera Driver"
+
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_DESCRIPTION (DRIVER_DESC);
+MODULE_LICENSE ("GPL");
+MODULE_PARM (debug, "i");
+MODULE_PARM_DESC (debug, "Debug enabled or not");
+MODULE_PARM (swapRGB, "i");
+MODULE_PARM_DESC (swapRGB, "Swap red and blue, e.g., for xawtv");
+MODULE_PARM (video_nr, "i");
+EXPORT_NO_SYMBOLS;
+
+/********************************************************************
+ *
+ * Memory management
+ *
+ * This is a shameless copy from the USB-cpia driver (linux kernel
+ * version 2.3.29 or so, I have no idea what this code actually does ;).
+ * Actually it seems to be a copy of a shameless copy of the bttv-driver.
+ * Or that is a copy of a shameless copy of ... (To the powers: is there
+ * no generic kernel-function to do this sort of stuff?)
+ *
+ * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
+ * there will be one, but apparentely not yet -jerdfelt
+ *
+ * So I copied it again for the ov511 driver -claudio
+ *
+ * Same for the se401 driver -Jeroen
+ *
+ * And the STV0680 driver - Kevin
+ ********************************************************************/
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline unsigned long uvirt_to_kva (pgd_t * pgd, unsigned long adr)
+{
+	unsigned long ret = 0UL;
+	pmd_t *pmd;
+	pte_t *ptep, pte;
+
+	if (!pgd_none (*pgd)) {
+		pmd = pmd_offset (pgd, adr);
+		if (!pmd_none (*pmd)) {
+			ptep = pte_offset (pmd, adr);
+			pte = *ptep;
+			if (pte_present (pte)) {
+				ret = (unsigned long) page_address (pte_page (pte));
+				ret |= (adr & (PAGE_SIZE - 1));
+			}
+		}
+	}
+	return ret;
+}
+
+/* Here we want the physical address of the memory. This is used when 
+ * initializing the contents of the area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa (unsigned long adr)
+{
+	unsigned long va, kva, ret;
+
+	va = VMALLOC_VMADDR (adr);
+	kva = uvirt_to_kva (pgd_offset_k (va), va);
+	ret = __pa (kva);
+	return ret;
+}
+
+static void *rvmalloc (unsigned long size)
+{
+	void *mem;
+	unsigned long adr, page;
+
+	/* Round it off to PAGE_SIZE */
+	size += (PAGE_SIZE - 1);
+	size &= ~(PAGE_SIZE - 1);
+
+	mem = vmalloc_32 (size);
+	if (!mem)
+		return NULL;
+
+	memset (mem, 0, size);	/* Clear the ram out, no junk to the user */
+	adr = (unsigned long) mem;
+	while (size > 0) {
+		page = kvirt_to_pa (adr);
+		mem_map_reserve (virt_to_page (__va (page)));
+		adr += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+	return mem;
+}
+
+static void rvfree (void *mem, unsigned long size)
+{
+	unsigned long adr, page;
+
+	if (!mem)
+		return;
+
+	size += (PAGE_SIZE - 1);
+	size &= ~(PAGE_SIZE - 1);
+
+	adr = (unsigned long) mem;
+	while (size > 0) {
+		page = kvirt_to_pa (adr);
+		mem_map_unreserve (virt_to_page (__va (page)));
+		adr += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+	vfree (mem);
+}
+
+
+/*********************************************************************
+ * pencam read/write functions
+ ********************************************************************/
+
+static int stv_sndctrl (int set, struct usb_stv *stv680, unsigned short req, unsigned short value, unsigned char *buffer, int size)
+{
+	int ret = -1;
+
+	switch (set) {
+	case 0:		/*  0xc1  */
+		ret = usb_control_msg (stv680->udev,
+				       usb_rcvctrlpipe (stv680->udev, 0),
+				       req,
+				       (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
+				       value, 0, buffer, size, PENCAM_TIMEOUT);
+		break;
+
+	case 1:		/*  0x41  */
+		ret = usb_control_msg (stv680->udev,
+				       usb_sndctrlpipe (stv680->udev, 0),
+				       req,
+				       (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
+				       value, 0, buffer, size, PENCAM_TIMEOUT);
+		break;
+
+	case 2:		/*  0x80  */
+		ret = usb_control_msg (stv680->udev,
+				       usb_rcvctrlpipe (stv680->udev, 0),
+				       req,
+				       (USB_DIR_IN | USB_RECIP_DEVICE),
+				       value, 0, buffer, size, PENCAM_TIMEOUT);
+		break;
+
+	case 3:		/*  0x40  */
+		ret = usb_control_msg (stv680->udev,
+				       usb_sndctrlpipe (stv680->udev, 0),
+				       req,
+				       (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
+				       value, 0, buffer, size, PENCAM_TIMEOUT);
+		break;
+
+	}
+	if ((ret < 0) && (req != 0x0a)) {
+		PDEBUG (1, "STV(e): usb_control_msg error %i, request = 0x%x, error = %i", set, req, ret);
+	}
+	return ret;
+}
+
+static int stv_set_config (struct usb_stv *dev, int configuration, int interface, int alternate)
+{
+
+	if (usb_set_configuration (dev->udev, configuration) < 0) {
+		PDEBUG (1, "STV(e): FAILED to set configuration %i", configuration);
+		return -1;
+	}
+	if (usb_set_interface (dev->udev, interface, alternate) < 0) {
+		PDEBUG (1, "STV(e): FAILED to set alternate interface %i", alternate);
+		return -1;
+	}
+	return 0;
+}
+
+static int stv_stop_video (struct usb_stv *dev)
+{
+	int i;
+	unsigned char *buf;
+
+	buf = kmalloc (40, GFP_KERNEL);
+	if (buf == NULL) {
+		PDEBUG (0, "STV(e): Out of (small buf) memory");
+		return -1;
+	}
+
+	/* this is a high priority command; it stops all lower order commands */
+	if ((i = stv_sndctrl (1, dev, 0x04, 0x0000, buf, 0x0)) < 0) {
+		i = stv_sndctrl (0, dev, 0x80, 0, buf, 0x02);	/* Get Last Error; 2 = busy */
+		PDEBUG (1, "STV(i): last error: %i,  command = 0x%x", buf[0], buf[1]);
+	} else {
+		PDEBUG (1, "STV(i): Camera reset to idle mode.");
+	}
+
+	if ((i = stv_set_config (dev, 1, 0, 0)) < 0)
+		PDEBUG (1, "STV(e): Reset config during exit failed");
+
+	/*  get current mode  */
+	buf[0] = 0xf0;
+	if ((i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08)) != 0x08)	/* get mode */
+		PDEBUG (0, "STV(e): Stop_video: problem setting original mode");
+	if (dev->origMode != buf[0]) {
+		memset (buf, 0, 8);
+		buf[0] = (unsigned char) dev->origMode;
+		if ((i = stv_sndctrl (3, dev, 0x07, 0x0100, buf, 0x08)) != 0x08) {
+			PDEBUG (0, "STV(e): Stop_video: Set_Camera_Mode failed");
+			i = -1;
+		}
+		buf[0] = 0xf0;
+		i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08);
+		if ((i != 0x08) || (buf[0] != dev->origMode)) {
+			PDEBUG (0, "STV(e): camera NOT set to original resolution.");
+			i = -1;
+		} else
+			PDEBUG (0, "STV(i): Camera set to original resolution");
+	}
+	/* origMode */
+	kfree (buf);
+	return i;
+}
+
+static int stv_set_video_mode (struct usb_stv *dev)
+{
+	int i, stop_video = 1;
+	unsigned char *buf;
+
+	buf = kmalloc (40, GFP_KERNEL);
+	if (buf == NULL) {
+		PDEBUG (0, "STV(e): Out of (small buf) memory");
+		return -1;
+	}
+
+	if ((i = stv_set_config (dev, 1, 0, 0)) < 0) {
+		kfree (buf);
+		return i;
+	}
+
+	i = stv_sndctrl (2, dev, 0x06, 0x0100, buf, 0x12);
+	if (!(i > 0) && (buf[8] == 0x53) && (buf[9] == 0x05)) {
+		PDEBUG (1, "STV(e): Could not get descriptor 0100.");
+		goto error;
+	}
+
+	/*  set alternate interface 1 */
+	if ((i = stv_set_config (dev, 1, 0, 1)) < 0)
+		goto error;
+
+	if ((i = stv_sndctrl (0, dev, 0x85, 0, buf, 0x10)) != 0x10)
+		goto error;
+	PDEBUG (1, "STV(i): Setting video mode.");
+	/*  Switch to Video mode: 0x0100 = VGA (640x480), 0x0000 = CIF (352x288) 0x0300 = QVGA (320x240)  */
+	if ((i = stv_sndctrl (1, dev, 0x09, dev->VideoMode, buf, 0x0)) < 0) {
+		stop_video = 0;
+		goto error;
+	}
+	goto exit;
+
+error:
+	kfree (buf);
+	if (stop_video == 1)
+		stv_stop_video (dev);
+	return -1;
+
+exit:
+	kfree (buf);
+	return 0;
+}
+
+static int stv_init (struct usb_stv *stv680)
+{
+	int i = 0;
+	unsigned char *buffer;
+	unsigned long int bufsize;
+
+	buffer = kmalloc (40, GFP_KERNEL);
+	if (buffer == NULL) {
+		PDEBUG (0, "STV(e): Out of (small buf) memory");
+		return -1;
+	}
+	memset (buffer, 0, 40);
+	udelay (100);
+
+	/* set config 1, interface 0, alternate 0 */
+	if ((i = stv_set_config (stv680, 1, 0, 0)) < 0) {
+		kfree (buffer);
+		PDEBUG (0, "STV(e): set config 1,0,0 failed");
+		return -1;
+	}
+	/* ping camera to be sure STV0680 is present */
+	if ((i = stv_sndctrl (0, stv680, 0x88, 0x5678, buffer, 0x02)) != 0x02)
+		goto error;
+	if ((buffer[0] != 0x56) || (buffer[1] != 0x78)) {
+		PDEBUG (1, "STV(e): camera ping failed!!");
+		goto error;
+	}
+
+	/* get camera descriptor */
+	if ((i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x09)) != 0x09)
+		goto error;
+	i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x22);
+	if (!(i >= 0) && (buffer[7] == 0xa0) && (buffer[8] == 0x23)) {
+		PDEBUG (1, "STV(e): Could not get descriptor 0200.");
+		goto error;
+	}
+	if ((i = stv_sndctrl (0, stv680, 0x8a, 0, buffer, 0x02)) != 0x02)
+		goto error;
+	if ((i = stv_sndctrl (0, stv680, 0x8b, 0, buffer, 0x24)) != 0x24)
+		goto error;
+	if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
+		goto error;
+
+	stv680->SupportedModes = buffer[7];
+	i = stv680->SupportedModes;
+	stv680->CIF = 0;
+	stv680->VGA = 0;
+	stv680->QVGA = 0;
+	if (i & 1)
+		stv680->CIF = 1;
+	if (i & 2)
+		stv680->VGA = 1;
+	if (i & 8)
+		stv680->QVGA = 1;
+	if (stv680->SupportedModes == 0) {
+		PDEBUG (0, "STV(e): There are NO supported STV680 modes!!");
+		i = -1;
+		goto error;
+	} else {
+		if (stv680->CIF)
+			PDEBUG (0, "STV(i): CIF is supported");
+		if (stv680->QVGA)
+			PDEBUG (0, "STV(i): QVGA is supported");
+	}
+	/* FW rev, ASIC rev, sensor ID  */
+	PDEBUG (1, "STV(i): Firmware rev is %i.%i", buffer[0], buffer[1]);
+	PDEBUG (1, "STV(i): ASIC rev is %i.%i", buffer[2], buffer[3]);
+	PDEBUG (1, "STV(i): Sensor ID is %i", (buffer[4]*16) + (buffer[5]>>4));
+
+	/*  set alternate interface 1 */
+	if ((i = stv_set_config (stv680, 1, 0, 1)) < 0)
+		goto error;
+
+	if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
+		goto error;
+	if ((i = stv_sndctrl (0, stv680, 0x8d, 0, buffer, 0x08)) != 0x08)
+		goto error;
+	i = buffer[3];
+	PDEBUG (0, "STV(i): Camera has %i pictures.", i);
+
+	/*  get current mode */
+	if ((i = stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08)) != 0x08)
+		goto error;
+	stv680->origMode = buffer[0];	/* 01 = VGA, 03 = QVGA, 00 = CIF */
+
+	/* This will attemp CIF mode, if supported. If not, set to QVGA  */
+	memset (buffer, 0, 8);
+	if (stv680->CIF)
+		buffer[0] = 0x00;
+	else if (stv680->QVGA)
+		buffer[0] = 0x03;
+	if ((i = stv_sndctrl (3, stv680, 0x07, 0x0100, buffer, 0x08)) != 0x08) {
+		PDEBUG (0, "STV(i): Set_Camera_Mode failed");
+		i = -1;
+		goto error;
+	}
+	buffer[0] = 0xf0;
+	stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08);
+	if (((stv680->CIF == 1) && (buffer[0] != 0x00)) || ((stv680->QVGA == 1) && (buffer[0] != 0x03))) {
+		PDEBUG (0, "STV(e): Error setting camera video mode!");
+		i = -1;
+		goto error;
+	} else {
+		if (buffer[0] == 0) {
+			stv680->VideoMode = 0x0000;
+			PDEBUG (0, "STV(i): Video Mode set to CIF");
+		}
+		if (buffer[0] == 0x03) {
+			stv680->VideoMode = 0x0300;
+			PDEBUG (0, "STV(i): Video Mode set to QVGA");
+		}
+	}
+	if ((i = stv_sndctrl (0, stv680, 0x8f, 0, buffer, 0x10)) != 0x10)
+		goto error;
+	bufsize = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]);
+	stv680->cwidth = (buffer[4] << 8) | (buffer[5]);	/* ->camera = 322, 356, 644  */
+	stv680->cheight = (buffer[6] << 8) | (buffer[7]);	/* ->camera = 242, 292, 484  */
+	stv680->origGain = buffer[12];
+
+	goto exit;
+
+error:
+	i = stv_sndctrl (0, stv680, 0x80, 0, buffer, 0x02);	/* Get Last Error */
+	PDEBUG (1, "STV(i): last error: %i,  command = 0x%x", buffer[0], buffer[1]);
+	kfree (buffer);
+	return -1;
+
+exit:
+	kfree (buffer);
+
+	/* video = 320x240, 352x288 */
+	if (stv680->CIF == 1) {
+		stv680->maxwidth = 352;
+		stv680->maxheight = 288;
+		stv680->vwidth = 352;
+		stv680->vheight = 288;
+	}
+	if (stv680->QVGA == 1) {
+		stv680->maxwidth = 320;
+		stv680->maxheight = 240;
+		stv680->vwidth = 320;
+		stv680->vheight = 240;
+	}
+
+	stv680->rawbufsize = bufsize;	/* must be ./. by 8 */
+	stv680->maxframesize = bufsize * 3;	/* RGB size */
+	PDEBUG (2, "STV(i): cwidth = %i, cheight = %i", stv680->cwidth, stv680->cheight);
+	PDEBUG (1, "STV(i): width = %i, height = %i, rawbufsize = %li", stv680->vwidth, stv680->vheight, stv680->rawbufsize);
+
+	/* some default values */
+	stv680->bulk_in_endpointAddr = 0x82;
+	stv680->dropped = 0;
+	stv680->error = 0;
+	stv680->framecount = 0;
+	stv680->readcount = 0;
+	stv680->streaming = 0;
+	/* bright, white, colour, hue, contrast are set by software, not in stv0680 */
+	stv680->brightness = 32767;
+	stv680->chgbright = 0;
+	stv680->whiteness = 0;	/* only for greyscale */
+	stv680->colour = 32767;
+	stv680->contrast = 32767;
+	stv680->hue = 32767;
+	stv680->palette = STV_VIDEO_PALETTE;
+	stv680->depth = 24;	/* rgb24 bits */
+	swapRGB = 0;
+	PDEBUG (1, "STV(i): swapRGB is OFF");
+
+	if (stv_set_video_mode (stv680) < 0) {
+		PDEBUG (0, "STV(e): Could not set video mode in stv_init");
+		return -1;
+	}
+
+	return 0;
+}
+
+/***************** last of pencam  routines  *******************/
+
+/********************************************************************
+ * /proc interface
+ *******************************************************************/
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+
+static struct proc_dir_entry *stv680_proc_entry = NULL;
+extern struct proc_dir_entry *video_proc_entry;
+
+#define YES_NO(x) ((x) ? "yes" : "no")
+
+static int stv680_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	char *out = page;
+	int len;
+	struct usb_stv *stv680 = data;
+
+	/* Stay under PAGE_SIZE or else bla bla bla.... */
+
+	out += sprintf (out, "driver_version  : %s\n", DRIVER_VERSION);
+	out += sprintf (out, "model           : %s\n", stv680->camera_name);
+	out += sprintf (out, "in use          : %s\n", YES_NO (stv680->user));
+	out += sprintf (out, "streaming       : %s\n", YES_NO (stv680->streaming));
+	out += sprintf (out, "num_frames      : %d\n", STV680_NUMFRAMES);
+
+	out += sprintf (out, "Current size    : %ix%i\n", stv680->vwidth, stv680->vheight);
+	out += sprintf (out, "swapRGB         : %s\n", YES_NO (swapRGB));
+	out += sprintf (out, "Palette         : %i", stv680->palette);
+
+	out += sprintf (out, "\n");
+
+	out += sprintf (out, "Frames total    : %d\n", stv680->readcount);
+	out += sprintf (out, "Frames read     : %d\n", stv680->framecount);
+	out += sprintf (out, "Packets dropped : %d\n", stv680->dropped);
+	out += sprintf (out, "Decoding Errors : %d\n", stv680->error);
+
+	len = out - page;
+	len -= off;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0)
+			return 0;
+	} else
+		len = count;
+
+	*start = page + off;
+	return len;
+}
+
+static int create_proc_stv680_cam (struct usb_stv *stv680)
+{
+	char name[9];
+	struct proc_dir_entry *ent;
+
+	if (!stv680_proc_entry || !stv680)
+		return -1;
+
+	sprintf (name, "video%d", stv680->vdev.minor);
+
+	ent = create_proc_entry (name, S_IFREG | S_IRUGO | S_IWUSR, stv680_proc_entry);
+	if (!ent)
+		return -1;
+
+	ent->data = stv680;
+	ent->read_proc = stv680_read_proc;
+	stv680->proc_entry = ent;
+	return 0;
+}
+
+static void destroy_proc_stv680_cam (struct usb_stv *stv680)
+{
+	/* One to much, just to be sure :) */
+	char name[9];
+
+	if (!stv680 || !stv680->proc_entry)
+		return;
+
+	sprintf (name, "video%d", stv680->vdev.minor);
+	remove_proc_entry (name, stv680_proc_entry);
+	stv680->proc_entry = NULL;
+}
+
+static int proc_stv680_create (void)
+{
+	if (video_proc_entry == NULL) {
+		PDEBUG (0, "STV(e): /proc/video/ doesn't exist!");
+		return -1;
+	}
+	stv680_proc_entry = create_proc_entry ("stv680", S_IFDIR, video_proc_entry);
+
+	if (stv680_proc_entry) {
+		stv680_proc_entry->owner = THIS_MODULE;
+	} else {
+		PDEBUG (0, "STV(e): Unable to initialize /proc/video/stv680");
+		return -1;
+	}
+	return 0;
+}
+
+static void proc_stv680_destroy (void)
+{
+	if (stv680_proc_entry == NULL)
+		return;
+
+	remove_proc_entry ("stv", video_proc_entry);
+}
+#endif				/* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */
+
+/********************************************************************
+ * Camera control
+ *******************************************************************/
+
+static int stv680_get_pict (struct usb_stv *stv680, struct video_picture *p)
+{
+	/* This sets values for v4l interface. max/min = 65535/0  */
+
+	p->brightness = stv680->brightness;
+	p->whiteness = stv680->whiteness;	/* greyscale */
+	p->colour = stv680->colour;
+	p->contrast = stv680->contrast;
+	p->hue = stv680->hue;
+	p->palette = stv680->palette;
+	p->depth = stv680->depth;
+	return 0;
+}
+
+static int stv680_set_pict (struct usb_stv *stv680, struct video_picture *p)
+{
+	/* See above stv680_get_pict  */
+
+	if (p->palette != STV_VIDEO_PALETTE) {
+		PDEBUG (2, "STV(e): Palette set error in _set_pic");
+		return 1;
+	}
+
+	if (stv680->brightness != p->brightness) {
+		stv680->chgbright = 1;
+		stv680->brightness = p->brightness;
+	} else {
+		stv680->chgbright = 0;
+	}
+
+	stv680->whiteness = p->whiteness;	/* greyscale */
+	stv680->colour = p->colour;
+	stv680->contrast = p->contrast;
+	stv680->hue = p->hue;
+	stv680->palette = p->palette;
+	stv680->depth = p->depth;
+
+	return 0;
+}
+
+static void stv680_video_irq (struct urb *urb)
+{
+	struct usb_stv *stv680 = urb->context;
+	int length = urb->actual_length;
+
+	if (length < stv680->rawbufsize)
+		PDEBUG (2, "STV(i): Lost data in transfer: exp %li, got %i", stv680->rawbufsize, length);
+
+	/* ohoh... */
+	if (!stv680->streaming)
+		return;
+
+	if (!stv680->udev) {
+		PDEBUG (0, "STV(e): device vapourished in video_irq");
+		return;
+	}
+
+	/* 0 sized packets happen if we are to fast, but sometimes the camera
+	   keeps sending them forever...
+	 */
+	if (length && !urb->status) {
+		stv680->nullpackets = 0;
+		switch (stv680->scratch[stv680->scratch_next].state) {
+		case BUFFER_READY:
+		case BUFFER_BUSY:
+			stv680->dropped++;
+			break;
+
+		case BUFFER_UNUSED:
+			memcpy (stv680->scratch[stv680->scratch_next].data,
+			        (unsigned char *) urb->transfer_buffer, length);
+			stv680->scratch[stv680->scratch_next].state = BUFFER_READY;
+			stv680->scratch[stv680->scratch_next].length = length;
+			if (waitqueue_active (&stv680->wq)) {
+				wake_up_interruptible (&stv680->wq);
+			}
+			stv680->scratch_overflow = 0;
+			stv680->scratch_next++;
+			if (stv680->scratch_next >= STV680_NUMSCRATCH)
+				stv680->scratch_next = 0;;
+			break;
+		}		/* switch  */
+	} else {
+		stv680->nullpackets++;
+		if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
+			if (waitqueue_active (&stv680->wq)) {
+				wake_up_interruptible (&stv680->wq);
+			}
+		}
+	}			/*  if - else */
+
+	/* Resubmit urb for new data */
+	urb->status = 0;
+	urb->dev = stv680->udev;
+	if (usb_submit_urb (urb))
+		PDEBUG (0, "STV(e): urb burned down in video irq");
+	return;
+}				/*  _video_irq  */
+
+static int stv680_start_stream (struct usb_stv *stv680)
+{
+	urb_t *urb;
+	int err = 0, i;
+
+	stv680->streaming = 1;
+
+	/* Do some memory allocation */
+	for (i = 0; i < STV680_NUMFRAMES; i++) {
+		stv680->frame[i].data = stv680->fbuf + i * stv680->maxframesize;
+		stv680->frame[i].curpix = 0;
+	}
+	/* packet size = 4096  */
+	for (i = 0; i < STV680_NUMSBUF; i++) {
+		stv680->sbuf[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
+		if (stv680->sbuf[i].data == NULL) {
+			PDEBUG (0, "STV(e): Could not kmalloc raw data buffer %i", i);
+			return -1;
+		}
+	}
+
+	stv680->scratch_next = 0;
+	stv680->scratch_use = 0;
+	stv680->scratch_overflow = 0;
+	for (i = 0; i < STV680_NUMSCRATCH; i++) {
+		stv680->scratch[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
+		if (stv680->scratch[i].data == NULL) {
+			PDEBUG (0, "STV(e): Could not kmalloc raw scratch buffer %i", i);
+			return -1;
+		}
+		stv680->scratch[i].state = BUFFER_UNUSED;
+	}
+
+	for (i = 0; i < STV680_NUMSBUF; i++) {
+		urb = usb_alloc_urb (0);
+		if (!urb)
+			return ENOMEM;
+
+		/* sbuf is urb->transfer_buffer, later gets memcpyed to scratch */
+		usb_fill_bulk_urb (urb, stv680->udev,
+				   usb_rcvbulkpipe (stv680->udev, stv680->bulk_in_endpointAddr),
+				   stv680->sbuf[i].data, stv680->rawbufsize,
+				   stv680_video_irq, stv680);
+		urb->timeout = PENCAM_TIMEOUT * 2;
+		urb->transfer_flags |= USB_QUEUE_BULK;
+		stv680->urb[i] = urb;
+		err = usb_submit_urb (stv680->urb[i]);
+		if (err)
+			PDEBUG (0, "STV(e): urb burned down in start stream");
+	}			/* i STV680_NUMSBUF */
+
+	stv680->framecount = 0;
+	return 0;
+}
+
+static int stv680_stop_stream (struct usb_stv *stv680)
+{
+	int i;
+
+	if (!stv680->streaming || !stv680->udev)
+		return 1;
+
+	stv680->streaming = 0;
+
+	for (i = 0; i < STV680_NUMSBUF; i++)
+		if (stv680->urb[i]) {
+			stv680->urb[i]->next = NULL;
+			usb_unlink_urb (stv680->urb[i]);
+			usb_free_urb (stv680->urb[i]);
+			stv680->urb[i] = NULL;
+			kfree (stv680->sbuf[i].data);
+		}
+	for (i = 0; i < STV680_NUMSCRATCH; i++) {
+		kfree (stv680->scratch[i].data);
+		stv680->scratch[i].data = NULL;
+	}
+
+	return 0;
+}
+
+static int stv680_set_size (struct usb_stv *stv680, int width, int height)
+{
+	int wasstreaming = stv680->streaming;
+
+	/* Check to see if we need to change */
+	if ((stv680->vwidth == width) && (stv680->vheight == height))
+		return 0;
+
+	PDEBUG (1, "STV(i): size request for %i x %i", width, height);
+	/* Check for a valid mode */
+	if ((!width || !height) || ((width & 1) || (height & 1))) {
+		PDEBUG (1, "STV(e): set_size error: request: v.width = %i, v.height = %i  actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
+		return 1;
+	}
+
+	if ((width < (stv680->maxwidth / 2)) || (height < (stv680->maxheight / 2))) {
+		width = stv680->maxwidth / 2;
+		height = stv680->maxheight / 2;
+	} else if ((width >= 158) && (width <= 166)) {
+		width = 160;
+		height = 120;
+	} else if ((width >= 172) && (width <= 180)) {
+		width = 176;
+		height = 144;
+	} else if ((width >= 318) && (width <= 350)) {
+		width = 320;
+		height = 240;
+	} else if ((width >= 350) && (width <= 358)) {
+		width = 352;
+		height = 288;
+	}
+
+	/* Stop a current stream and start it again at the new size */
+	if (wasstreaming)
+		stv680_stop_stream (stv680);
+	stv680->vwidth = width;
+	stv680->vheight = height;
+	PDEBUG (1, "STV(i): size set to %i x %i", stv680->vwidth, stv680->vheight);
+	if (wasstreaming)
+		stv680_start_stream (stv680);
+
+	return 0;
+}
+
+/**********************************************************************
+ * Video Decoding
+ **********************************************************************/
+
+/*******  routines from the pencam program; hey, they work!  ********/
+
+/*
+ * STV0680 Vision Camera Chipset Driver
+ * Copyright (C) 2000 Adam Harrison <adam@antispin.org> 
+*/
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+#define AD(x, y, w) (((y)*(w)+(x))*3)
+
+static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buffer)
+{
+	int x, y, i;
+	int w = stv680->cwidth;
+	int vw = stv680->cwidth, vh = stv680->cheight, vstep = 1;
+	unsigned int p = 0;
+	int colour = 0, bayer = 0;
+	unsigned char *raw = buffer->data;
+	struct stv680_frame *frame = &stv680->frame[stv680->curframe];
+	unsigned char *output = frame->data;
+	unsigned char *temp = frame->data;
+	int offset = buffer->offset;
+
+	if (frame->curpix == 0) {
+		if (frame->grabstate == FRAME_READY) {
+			frame->grabstate = FRAME_GRABBING;
+		}
+	}
+	if (offset != frame->curpix) {	/* Regard frame as lost :( */
+		frame->curpix = 0;
+		stv680->error++;
+		return;
+	}
+
+	if ((stv680->vwidth == 322) || (stv680->vwidth == 320)) {
+		vw = 320;
+		vh = 240;
+		vstep = 1;
+	}
+	if ((stv680->vwidth == 352)) {
+		vw = 352;
+		vh = 288;
+		vstep = 1;
+	}
+	if ((stv680->vwidth == 160)) {
+		vw = 160;
+		vh = 120;
+		vstep = 2;
+	}
+	if ((stv680->vwidth == 176)) {
+		vw = 176;
+		vh = 144;
+		vstep = 2;
+	}
+	memset (output, 0, 3 * vw * vh);	/* clear output matrix. Maybe not necessary. */
+
+	for (y = 0; y < vh; y++) {
+		for (x = 0; x < vw; x++) {
+
+			switch (vstep) {
+			case 1:
+				if (x & 1)
+					p = *(raw + y * w + (x >> 1));
+				else
+					p = *(raw + y * w + (x >> 1) + (w >> 1));
+				break;
+
+			case 2:
+				if (x & 1)
+					p = *(raw + ((y * w) << 1) + x);
+				else
+					p = *(raw + ((y * w) << 1) + x + (w >> 1));
+				break;
+			}
+
+			if (y & 1)
+				bayer = 2;
+			else
+				bayer = 0;
+			if (x & 1)
+				bayer++;
+
+			switch (bayer) {
+			case 0:
+			case 3:
+				colour = 1;
+				break;
+			case 1:
+				colour = 0;
+				break;
+			case 2:
+				colour = 2;
+				break;
+			}
+			i = (y * vw + x) * 3;	/* output already zeroed out with memset */
+			*(output + i + colour) = (unsigned char) p;
+		}		/* for x */
+	}			/* for y */
+
+	/****** gamma correction plus hardcoded white balance */
+	/* Thanks to Alexander Schwartx <alexander.schwartx@gmx.net> for this code.
+	   Correction values red[], green[], blue[], are generated by 
+	   (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255. 
+	   White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and 
+	   converted to unsigned char. Values are in stv680.h  */
+	for (y = 0; y < vh; y++) {
+		for (x = 0; x < vw; x++) {
+			i = (y * vw + x) * 3;
+			*(output + i) = red[*(output + i)];
+			*(output + i + 1) = green[*(output + i + 1)];
+			*(output + i + 2) = blue[*(output + i + 2)];
+		}
+	}
+
+	/******  bayer demosaic  ******/
+	for (y = 1; y < (vh - 1); y++) {
+		for (x = 1; x < (vw - 1); x++) {	/* work out pixel type */
+			if (y & 1)
+				bayer = 0;
+			else
+				bayer = 2;
+			if (!(x & 1))
+				bayer++;
+
+			switch (bayer) {
+			case 0:	/* green. blue lr, red tb */
+				*(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y, vw) + BLUE) + (int) *(output + AD (x + 1, y, vw) + BLUE)) >> 1;
+				*(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x, y - 1, vw) + RED) + (int) *(output + AD (x, y + 1, vw) + RED)) >> 1;
+				break;
+
+			case 1:	/* blue. green lrtb, red diagonals */
+				*(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
+				*(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y - 1, vw) + RED) + (int) *(output + AD (x - 1, y + 1, vw) + RED) + (int) *(output + AD (x + 1, y - 1, vw) + RED) + (int) *(output + AD (x + 1, y + 1, vw) + RED)) >> 2;
+				break;
+
+			case 2:	/* red. green lrtb, blue diagonals */
+				*(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
+				*(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y - 1, vw) + BLUE) + (int) *(output + AD (x + 1, y - 1, vw) + BLUE) + (int) *(output + AD (x - 1, y + 1, vw) + BLUE) + (int) *(output + AD (x + 1, y + 1, vw) + BLUE)) >> 2;
+				break;
+
+			case 3:	/* green. red lr, blue tb */
+				*(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y, vw) + RED) + (int) *(output + AD (x + 1, y, vw) + RED)) >> 1;
+				*(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x, y - 1, vw) + BLUE) + (int) *(output + AD (x, y + 1, vw) + BLUE)) >> 1;
+				break;
+			}	/* switch */
+		}		/* for x */
+	}			/* for y  - end demosaic  */
+
+	/* output is RGB; some programs want BGR  */
+	if (swapRGB == 1) {
+		for (y = 0; y < vh; y++) {
+			for (x = 0; x < vw; x++) {
+				i = (y * vw + x) * 3;
+				*(temp) = *(output + i);
+				*(output + i) = *(output + i + 2);
+				*(output + i + 2) = *(temp);
+			}
+		}
+	}
+	/* brightness */
+	if (stv680->chgbright == 1) {
+		if (stv680->brightness >= 32767) {
+			p = (stv680->brightness - 32767) / 256;
+			for (x = 0; x < (vw * vh * 3); x++) {
+				if ((*(output + x) + (unsigned char) p) > 255)
+					*(output + x) = 255;
+				else
+					*(output + x) += (unsigned char) p;
+			}	/* for */
+		} else {
+			p = (32767 - stv680->brightness) / 256;
+			for (x = 0; x < (vw * vh * 3); x++) {
+				if ((unsigned char) p > *(output + x))
+					*(output + x) = 0;
+				else
+					*(output + x) -= (unsigned char) p;
+			}	/* for */
+		}		/* else */
+	}
+	/* if */
+	frame->curpix = 0;
+	frame->curlinepix = 0;
+	frame->grabstate = FRAME_DONE;
+	stv680->framecount++;
+	stv680->readcount++;
+	if (stv680->frame[(stv680->curframe + 1) & (STV680_NUMFRAMES - 1)].grabstate == FRAME_READY) {
+		stv680->curframe = (stv680->curframe + 1) & (STV680_NUMFRAMES - 1);
+	}
+
+}				/* bayer_unshuffle */
+
+/*******  end routines from the pencam program  *********/
+
+static int stv680_newframe (struct usb_stv *stv680, int framenr)
+{
+	int errors = 0;
+
+	while (stv680->streaming && (stv680->frame[framenr].grabstate == FRAME_READY || stv680->frame[framenr].grabstate == FRAME_GRABBING)) {
+		if (!stv680->frame[framenr].curpix) {
+			errors++;
+		}
+		wait_event_interruptible (stv680->wq, (stv680->scratch[stv680->scratch_use].state == BUFFER_READY));
+
+		if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
+			stv680->nullpackets = 0;
+			PDEBUG (2, "STV(i): too many null length packets, restarting capture");
+			stv680_stop_stream (stv680);
+			stv680_start_stream (stv680);
+		} else {
+			if (stv680->scratch[stv680->scratch_use].state != BUFFER_READY) {
+				stv680->frame[framenr].grabstate = FRAME_ERROR;
+				PDEBUG (2, "STV(e): FRAME_ERROR in _newframe");
+				return -EIO;
+			}
+			stv680->scratch[stv680->scratch_use].state = BUFFER_BUSY;
+
+			bayer_unshuffle (stv680, &stv680->scratch[stv680->scratch_use]);
+
+			stv680->scratch[stv680->scratch_use].state = BUFFER_UNUSED;
+			stv680->scratch_use++;
+			if (stv680->scratch_use >= STV680_NUMSCRATCH)
+				stv680->scratch_use = 0;
+			if (errors > STV680_MAX_ERRORS) {
+				errors = 0;
+				PDEBUG (2, "STV(i): too many errors, restarting capture");
+				stv680_stop_stream (stv680);
+				stv680_start_stream (stv680);
+			}
+		}		/* else */
+	}			/* while */
+	return 0;
+}
+
+/*********************************************************************
+ * Video4Linux
+ *********************************************************************/
+
+static int stv_open (struct video_device *dev, int flags)
+{
+	struct usb_stv *stv680 = (struct usb_stv *) dev;
+	int err = 0;
+
+	/* we are called with the BKL held */
+	MOD_INC_USE_COUNT;
+	stv680->user = 1;
+	err = stv_init (stv680);	/* main initialization routine for camera */
+
+	if (err >= 0) {
+		stv680->fbuf = rvmalloc (stv680->maxframesize * STV680_NUMFRAMES);
+		if (!stv680->fbuf) {
+			PDEBUG (0, "STV(e): Could not rvmalloc frame bufer");
+			err = -ENOMEM;
+		}
+	}
+	if (err) {
+		MOD_DEC_USE_COUNT;
+		stv680->user = 0;
+	}
+
+	return err;
+}
+
+static void stv_close (struct video_device *dev)
+{
+	/* called with BKL held */
+	struct usb_stv *stv680 = (struct usb_stv *) dev;
+	int i;
+
+	for (i = 0; i < STV680_NUMFRAMES; i++)
+		stv680->frame[i].grabstate = FRAME_UNUSED;
+	if (stv680->streaming)
+		stv680_stop_stream (stv680);
+
+	if ((i = stv_stop_video (stv680)) < 0)
+		PDEBUG (1, "STV(e): stop_video failed in stv_close");
+
+	rvfree (stv680->fbuf, stv680->maxframesize * STV680_NUMFRAMES);
+	stv680->user = 0;
+
+	if (stv680->removed) {
+		video_unregister_device (&stv680->vdev);
+		kfree (stv680);
+		stv680 = NULL;
+		PDEBUG (0, "STV(i): device unregistered");
+	}
+	MOD_DEC_USE_COUNT;
+}
+
+static long stv680_write (struct video_device *dev, const char *buf, unsigned long count, int noblock)
+{
+	return -EINVAL;
+}
+
+static int stv680_ioctl (struct video_device *vdev, unsigned int cmd, void *arg)
+{
+	struct usb_stv *stv680 = (struct usb_stv *) vdev;
+
+	if (!stv680->udev)
+		return -EIO;
+
+	switch (cmd) {
+	case VIDIOCGCAP:{
+			struct video_capability b;
+
+			strcpy (b.name, stv680->camera_name);
+			b.type = VID_TYPE_CAPTURE;
+			b.channels = 1;
+			b.audios = 0;
+			b.maxwidth = stv680->maxwidth;
+			b.maxheight = stv680->maxheight;
+			b.minwidth = stv680->maxwidth / 2;
+			b.minheight = stv680->maxheight / 2;
+
+			if (copy_to_user (arg, &b, sizeof (b))) {
+				PDEBUG (2, "STV(e): VIDIOCGGAP failed");
+				return -EFAULT;
+			}
+			return 0;
+		}
+	case VIDIOCGCHAN:{
+			struct video_channel v;
+
+			if (copy_from_user (&v, arg, sizeof (v)))
+				return -EFAULT;
+			if (v.channel != 0)
+				return -EINVAL;
+
+			v.flags = 0;
+			v.tuners = 0;
+			v.type = VIDEO_TYPE_CAMERA;
+			strcpy (v.name, "STV Camera");
+
+			if (copy_to_user (arg, &v, sizeof (v))) {
+				PDEBUG (2, "STV(e): VIDIOCGCHAN failed");
+				return -EFAULT;
+			}
+			return 0;
+		}
+	case VIDIOCSCHAN:{
+			int v;
+
+			if (copy_from_user (&v, arg, sizeof (v))) {
+				PDEBUG (2, "STV(e): VIDIOCSCHAN failed");
+				return -EFAULT;
+			}
+			if (v != 0)
+				return -EINVAL;
+
+			return 0;
+		}
+	case VIDIOCGPICT:{
+			struct video_picture p;
+
+			stv680_get_pict (stv680, &p);
+			if (copy_to_user (arg, &p, sizeof (p))) {
+				PDEBUG (2, "STV(e): VIDIOCGPICT failed");
+				return -EFAULT;
+			}
+			return 0;
+		}
+	case VIDIOCSPICT:{
+			struct video_picture p;
+
+			if (copy_from_user (&p, arg, sizeof (p))) {
+				PDEBUG (2, "STV(e): VIDIOCSPICT failed");
+				return -EFAULT;
+			}
+			copy_from_user (&p, arg, sizeof (p));
+			PDEBUG (2, "STV(i): palette set to RGB in VIDIOSPICT");
+
+			if (stv680_set_pict (stv680, &p))
+				return -EINVAL;
+			return 0;
+		}
+	case VIDIOCSWIN:{
+			struct video_window vw;
+
+			if (copy_from_user (&vw, arg, sizeof (vw)))
+				return -EFAULT;
+			if (vw.flags)
+				return -EINVAL;
+			if (vw.clipcount)
+				return -EINVAL;
+			if (vw.width != stv680->vwidth) {
+				if (stv680_set_size (stv680, vw.width, vw.height)) {
+					PDEBUG (2, "STV(e): failed (from user) set size in VIDIOCSWIN");
+					return -EINVAL;
+				}
+			}
+			return 0;
+		}
+	case VIDIOCGWIN:{
+			struct video_window vw;
+
+			vw.x = 0;	/* FIXME */
+			vw.y = 0;
+			vw.chromakey = 0;
+			vw.flags = 0;
+			vw.clipcount = 0;
+			vw.width = stv680->vwidth;
+			vw.height = stv680->vheight;
+
+			if (copy_to_user (arg, &vw, sizeof (vw))) {
+				PDEBUG (2, "STV(e): VIDIOCGWIN failed");
+				return -EFAULT;
+			}
+			return 0;
+		}
+	case VIDIOCGMBUF:{
+			struct video_mbuf vm;
+			int i;
+
+			memset (&vm, 0, sizeof (vm));
+			vm.size = STV680_NUMFRAMES * stv680->maxframesize;
+			vm.frames = STV680_NUMFRAMES;
+			for (i = 0; i < STV680_NUMFRAMES; i++)
+				vm.offsets[i] = stv680->maxframesize * i;
+
+			if (copy_to_user ((void *) arg, (void *) &vm, sizeof (vm))) {
+				PDEBUG (2, "STV(e): VIDIOCGMBUF failed");
+				return -EFAULT;
+			}
+
+			return 0;
+		}
+	case VIDIOCMCAPTURE:{
+			struct video_mmap vm;
+
+			if (copy_from_user (&vm, arg, sizeof (vm))) {
+				PDEBUG (2, "STV(e): VIDIOCMCAPTURE failed");
+				return -EFAULT;
+			}
+			if (vm.format != STV_VIDEO_PALETTE) {
+				PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)",
+					vm.format, STV_VIDEO_PALETTE);
+				if (vm.format == 3) {
+					PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is ON");
+					/* this may fix those apps (e.g., xawtv) that want BGR */
+					swapRGB = 1;
+				}
+				return -EINVAL;
+			}
+			if (vm.frame >= STV680_NUMFRAMES) {
+				PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES");
+				return -EINVAL;
+			}
+			if (stv680->frame[vm.frame].grabstate != FRAME_UNUSED) {
+				PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate != FRAME_UNUSED");
+				return -EBUSY;
+			}
+			/* Is this according to the v4l spec??? */
+			if (stv680->vwidth != vm.width) {
+				if (stv680_set_size (stv680, vm.width, vm.height)) {
+					PDEBUG (2, "STV(e): VIDIOCMCAPTURE set_size failed");
+					return -EINVAL;
+				}
+			}
+			stv680->frame[vm.frame].grabstate = FRAME_READY;
+
+			if (!stv680->streaming)
+				stv680_start_stream (stv680);
+
+			return 0;
+		}
+	case VIDIOCSYNC:{
+			int frame, ret = 0;
+
+			if (copy_from_user ((void *) &frame, arg, sizeof (int))) {
+				PDEBUG (2, "STV(e): VIDIOCSYNC failed");
+				return -EFAULT;
+			}
+			if (frame < 0 || frame >= STV680_NUMFRAMES) {
+				PDEBUG (2, "STV(e): Bad frame # in VIDIOCSYNC");
+				return -EINVAL;
+			}
+			ret = stv680_newframe (stv680, frame);
+			stv680->frame[frame].grabstate = FRAME_UNUSED;
+			return ret;
+		}
+	case VIDIOCGFBUF:{
+			struct video_buffer vb;
+
+			memset (&vb, 0, sizeof (vb));
+			vb.base = NULL;	/* frame buffer not supported, not used */
+
+			if (copy_to_user ((void *) arg, (void *) &vb, sizeof (vb))) {
+				PDEBUG (2, "STV(e): VIDIOCSYNC failed");
+				return -EFAULT;
+			}
+			return 0;
+		}
+	case VIDIOCKEY:
+		return 0;
+	case VIDIOCCAPTURE:
+		{
+			PDEBUG (2, "STV(e): VIDIOCCAPTURE failed");
+			return -EINVAL;
+		}
+	case VIDIOCSFBUF:
+		return -EINVAL;
+	case VIDIOCGTUNER:
+	case VIDIOCSTUNER:
+		return -EINVAL;
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
+		return -EINVAL;
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+		return -EINVAL;
+	default:
+		return -ENOIOCTLCMD;
+	}			/* end switch */
+
+	return 0;
+}
+
+static int stv680_mmap (struct video_device *dev, const char *adr, unsigned long size)
+{
+	struct usb_stv *stv680 = (struct usb_stv *) dev;
+	unsigned long start = (unsigned long) adr;
+	unsigned long page, pos;
+
+	down (&stv680->lock);
+
+	if (stv680->udev == NULL) {
+		up (&stv680->lock);
+		return -EIO;
+	}
+	if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1)
+		    & ~(PAGE_SIZE - 1))) {
+		up (&stv680->lock);
+		return -EINVAL;
+	}
+	pos = (unsigned long) stv680->fbuf;
+	while (size > 0) {
+		page = kvirt_to_pa (pos);
+		if (remap_page_range (start, page, PAGE_SIZE, PAGE_SHARED)) {
+			up (&stv680->lock);
+			return -EAGAIN;
+		}
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+	up (&stv680->lock);
+
+	return 0;
+}
+
+static long stv680_read (struct video_device *dev, char *buf, unsigned long count, int noblock)
+{
+	unsigned long int realcount = count;
+	int ret = 0;
+	struct usb_stv *stv680 = (struct usb_stv *) dev;
+	unsigned long int i;
+
+	if (STV680_NUMFRAMES != 2) {
+		PDEBUG (0, "STV(e): STV680_NUMFRAMES needs to be 2!");
+		return -1;
+	}
+	if (stv680->udev == NULL)
+		return -EIO;
+	if (realcount > (stv680->vwidth * stv680->vheight * 3))
+		realcount = stv680->vwidth * stv680->vheight * 3;
+
+	/* Shouldn't happen: */
+	if (stv680->frame[0].grabstate == FRAME_GRABBING) {
+		PDEBUG (2, "STV(e): FRAME_GRABBING in stv680_read");
+		return -EBUSY;
+	}
+	stv680->frame[0].grabstate = FRAME_READY;
+	stv680->frame[1].grabstate = FRAME_UNUSED;
+	stv680->curframe = 0;
+
+	if (!stv680->streaming)
+		stv680_start_stream (stv680);
+
+	if (!stv680->streaming) {
+		ret = stv680_newframe (stv680, 0);	/* ret should = 0 */
+	}
+
+	ret = stv680_newframe (stv680, 0);
+
+	if (!ret) {
+		if ((i = copy_to_user (buf, stv680->frame[0].data, realcount)) != 0) {
+			PDEBUG (2, "STV(e): copy_to_user frame 0 failed, ret count = %li", i);
+			return -EFAULT;
+		}
+	} else {
+		realcount = ret;
+	}
+	stv680->frame[0].grabstate = FRAME_UNUSED;
+	return realcount;
+}				/* stv680_read */
+
+static int stv_init_done (struct video_device *dev)
+{
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+	if (create_proc_stv680_cam ((struct usb_stv *) dev) < 0)
+		return -1;
+#endif
+	return 0;
+}
+
+static struct video_device stv680_template = {
+	owner:		THIS_MODULE,
+	name:		"STV0680 USB camera",
+	type:		VID_TYPE_CAPTURE,
+	hardware:	VID_HARDWARE_SE401,
+	open:		stv_open,
+	close:		stv_close,
+	read:		stv680_read,
+	write:		stv680_write,
+	ioctl:		stv680_ioctl,
+	mmap:		stv680_mmap,
+	initialize:	stv_init_done,
+};
+
+static void *__devinit stv680_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
+{
+	struct usb_interface_descriptor *interface;
+	struct usb_stv *stv680;
+	char *camera_name = NULL;
+
+	/* We don't handle multi-config cameras */
+	if (dev->descriptor.bNumConfigurations != 1) {
+		PDEBUG (0, "STV(e): Number of Configurations != 1");
+		return NULL;
+	}
+
+	interface = &dev->actconfig->interface[ifnum].altsetting[0];
+	/* Is it a STV680? */
+	if ((dev->descriptor.idVendor == USB_PENCAM_VENDOR_ID) && (dev->descriptor.idProduct == USB_PENCAM_PRODUCT_ID)) {
+		camera_name = "STV0680";
+		PDEBUG (0, "STV(i): STV0680 camera found.");
+	} else {
+		PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 values.");
+		PDEBUG (0, "STV(e): Check that the STV0680 camera is connected to the computer.");
+		return NULL;
+	}
+	/* We found one */
+	if ((stv680 = kmalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) {
+		PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct.");
+		return NULL;
+	}
+
+	memset (stv680, 0, sizeof (*stv680));
+
+	stv680->udev = dev;
+	stv680->camera_name = camera_name;
+
+	memcpy (&stv680->vdev, &stv680_template, sizeof (stv680_template));
+	memcpy (stv680->vdev.name, stv680->camera_name, strlen (stv680->camera_name));
+	init_waitqueue_head (&stv680->wq);
+	init_MUTEX (&stv680->lock);
+	wmb ();
+
+	if (video_register_device (&stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+		kfree (stv680);
+		PDEBUG (0, "STV(e): video_register_device failed");
+		return NULL;
+	}
+	PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev.minor);
+
+	return stv680;
+}
+
+static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680)
+{
+	int i;
+
+	stv680->udev = NULL;
+	stv680->frame[0].grabstate = FRAME_ERROR;
+	stv680->frame[1].grabstate = FRAME_ERROR;
+	stv680->streaming = 0;
+
+	wake_up_interruptible (&stv680->wq);
+
+	for (i = 0; i < STV680_NUMSBUF; i++)
+		if (stv680->urb[i]) {
+			stv680->urb[i]->next = NULL;
+			usb_unlink_urb (stv680->urb[i]);
+			usb_free_urb (stv680->urb[i]);
+			stv680->urb[i] = NULL;
+			kfree (stv680->sbuf[i].data);
+		}
+	for (i = 0; i < STV680_NUMSCRATCH; i++)
+		if (stv680->scratch[i].data) {
+			kfree (stv680->scratch[i].data);
+		}
+	PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name);
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+	destroy_proc_stv680_cam (stv680);
+#endif
+	/* Free the memory */
+	kfree (stv680);
+}
+
+static void stv680_disconnect (struct usb_device *dev, void *ptr)
+{
+	struct usb_stv *stv680 = (struct usb_stv *) ptr;
+
+	lock_kernel ();
+	/* We don't want people trying to open up the device */
+	if (!stv680->user) {
+		video_unregister_device (&stv680->vdev);
+		usb_stv680_remove_disconnected (stv680);
+	} else {
+		stv680->removed = 1;
+	}
+	unlock_kernel ();
+}
+
+static struct usb_driver stv680_driver = {
+	name:		"stv680",
+	probe:		stv680_probe,
+	disconnect:	stv680_disconnect,
+	id_table:	device_table
+};
+
+/********************************************************************
+ *  Module routines
+ ********************************************************************/
+
+static int __init usb_stv680_init (void)
+{
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+	if (proc_stv680_create () < 0)
+		return -1;
+#endif
+	if (usb_register (&stv680_driver) < 0) {
+		PDEBUG (0, "STV(e): Could not setup STV0680 driver");
+		return -1;
+	}
+	PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION);
+
+	info(DRIVER_DESC " " DRIVER_VERSION);
+	return 0;
+}
+
+static void __exit usb_stv680_exit (void)
+{
+	usb_deregister (&stv680_driver);
+	PDEBUG (0, "STV(i): driver deregistered");
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+	proc_stv680_destroy ();
+#endif
+}
+
+module_init (usb_stv680_init);
+module_exit (usb_stv680_exit);
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/stv680.h linux/drivers/usb/stv680.h
--- v2.5.1/linux/drivers/usb/stv680.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/stv680.h	Thu Jan  3 13:21:28 2002
@@ -0,0 +1,222 @@
+/****************************************************************************
+ *
+ *  Filename: stv680.h
+ *
+ *  Description:
+ *     This is a USB driver for STV0680 based usb video cameras.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ * 
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ * 
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************************/
+
+/* size of usb transfers */
+#define STV680_PACKETSIZE	4096
+
+/* number of queued bulk transfers to use, may have problems if > 1 */
+#define STV680_NUMSBUF		1
+
+/* number of frames supported by the v4l part */
+#define STV680_NUMFRAMES	2
+
+/* scratch buffers for passing data to the decoders: 2 or 4 are good */
+#define STV680_NUMSCRATCH	2
+
+/* number of nul sized packets to receive before kicking the camera */
+#define STV680_MAX_NULLPACKETS	200
+
+/* number of decoding errors before kicking the camera */
+#define STV680_MAX_ERRORS	100
+
+#define USB_PENCAM_VENDOR_ID	0x0553
+#define USB_PENCAM_PRODUCT_ID	0x0202
+#define PENCAM_TIMEOUT          1000
+/* fmt 4 */
+#define STV_VIDEO_PALETTE    VIDEO_PALETTE_RGB24
+
+static __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
+	{}
+};
+MODULE_DEVICE_TABLE (usb, device_table);
+
+struct stv680_sbuf {
+	unsigned char *data;
+};
+
+enum {
+	FRAME_UNUSED,		/* Unused (no MCAPTURE) */
+	FRAME_READY,		/* Ready to start grabbing */
+	FRAME_GRABBING,		/* In the process of being grabbed into */
+	FRAME_DONE,		/* Finished grabbing, but not been synced yet */
+	FRAME_ERROR,		/* Something bad happened while processing */
+};
+
+enum {
+	BUFFER_UNUSED,
+	BUFFER_READY,
+	BUFFER_BUSY,
+	BUFFER_DONE,
+};
+
+/* raw camera data <- sbuf (urb transfer buf) */
+struct stv680_scratch {
+	unsigned char *data;
+	volatile int state;
+	int offset;
+	int length;
+};
+
+/* processed data for display ends up here, after bayer */
+struct stv680_frame {
+	unsigned char *data;	/* Frame buffer */
+	volatile int grabstate;	/* State of grabbing */
+	unsigned char *curline;
+	int curlinepix;
+	int curpix;
+};
+
+/* this is almost the video structure uvd_t, with extra parameters for stv */
+struct usb_stv {
+	struct video_device vdev;
+
+	struct usb_device *udev;
+
+	unsigned char bulk_in_endpointAddr;	/* __u8  the address of the bulk in endpoint */
+	char *camera_name;
+
+	unsigned int VideoMode;	/* 0x0100 = VGA, 0x0000 = CIF, 0x0300 = QVGA */
+	int SupportedModes;
+	int CIF;
+	int VGA;
+	int QVGA;
+	int cwidth;		/* camera width */
+	int cheight;		/* camera height */
+	int maxwidth;		/* max video width */
+	int maxheight;		/* max video height */
+	int vwidth;		/* current width for video window */
+	int vheight;		/* current height for video window */
+	unsigned long int rawbufsize;
+	unsigned long int maxframesize;	/* rawbufsize * 3 for RGB */
+
+	int origGain;
+	int origMode;		/* original camera mode */
+
+	struct semaphore lock;	/* to lock the structure */
+	int user;		/* user count for exclusive use */
+	int removed;		/* device disconnected */
+	int streaming;		/* Are we streaming video? */
+	char *fbuf;		/* Videodev buffer area */
+	urb_t *urb[STV680_NUMSBUF];	/* # of queued bulk transfers */
+	int curframe;		/* Current receiving frame */
+	struct stv680_frame frame[STV680_NUMFRAMES];	/* # frames supported by v4l part */
+	int readcount;
+	int framecount;
+	int error;
+	int dropped;
+	int scratch_next;
+	int scratch_use;
+	int scratch_overflow;
+	struct stv680_scratch scratch[STV680_NUMSCRATCH];	/* for decoders */
+	struct stv680_sbuf sbuf[STV680_NUMSBUF];
+
+	unsigned int brightness;
+	unsigned int chgbright;
+	unsigned int whiteness;
+	unsigned int colour;
+	unsigned int contrast;
+	unsigned int hue;
+	unsigned int palette;
+	unsigned int depth;	/* rgb24 in bits */
+
+	wait_queue_head_t wq;	/* Processes waiting */
+
+	struct proc_dir_entry *proc_entry;	/* /proc/stv680/videoX */
+	int nullpackets;
+};
+
+unsigned char red[256] = {
+	0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47,
+	50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77,
+	79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97,
+	98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113,
+	114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126,
+	127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
+	139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149,
+	150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159,
+	160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
+	169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177,
+	177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185,
+	186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193,
+	193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200,
+	201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207,
+	208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214,
+	214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220,
+	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
+	227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233,
+	233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
+	239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244,
+	245, 245, 246, 246
+};
+
+unsigned char green[256] = {
+	0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	24, 24, 24, 24, 24, 24, 24, 32, 39, 45, 50, 54,
+	58, 62, 65, 69, 71, 74, 77, 79, 83, 85, 87, 90,
+	92, 93, 95, 98, 100, 101, 104, 106, 107, 109, 111, 113,
+	114, 116, 118, 119, 121, 122, 124, 126, 127, 128, 129, 132,
+	133, 134, 135, 136, 138, 140, 141, 142, 143, 145, 146, 147,
+	148, 149, 150, 152, 153, 154, 155, 156, 157, 159, 160, 161,
+	162, 163, 164, 166, 167, 168, 168, 169, 170, 171, 173, 174,
+	175, 176, 176, 177, 179, 180, 181, 182, 182, 183, 184, 186,
+	187, 187, 188, 189, 190, 191, 191, 193, 194, 195, 195, 196,
+	197, 198, 198, 200, 201, 201, 202, 203, 204, 204, 205, 207,
+	207, 208, 209, 209, 210, 211, 212, 212, 214, 215, 215, 216,
+	217, 217, 218, 218, 219, 221, 221, 222, 223, 223, 224, 225,
+	225, 226, 226, 228, 229, 229, 230, 231, 231, 232, 232, 233,
+	235, 235, 236, 236, 237, 238, 238, 239, 239, 241, 241, 242,
+	243, 243, 244, 244, 245, 245, 246, 248, 248, 249, 249, 250,
+	250, 251, 251, 252, 253, 253, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255
+};
+
+unsigned char blue[256] = {
+	0, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+	31, 31, 31, 31, 31, 31, 31, 41, 50, 57, 63, 69,
+	74, 78, 82, 87, 90, 94, 97, 100, 105, 108, 111, 113,
+	116, 118, 121, 124, 127, 128, 131, 134, 136, 139, 140, 143,
+	145, 148, 149, 150, 153, 155, 156, 159, 161, 162, 164, 167,
+	168, 170, 171, 173, 174, 177, 179, 180, 182, 183, 185, 186,
+	187, 189, 190, 192, 193, 195, 196, 198, 199, 201, 202, 204,
+	205, 207, 208, 210, 211, 213, 213, 214, 216, 217, 219, 220,
+	222, 223, 223, 224, 226, 227, 229, 230, 230, 232, 233, 235,
+	236, 236, 238, 239, 241, 242, 242, 244, 245, 247, 247, 248,
+	250, 251, 251, 253, 254, 254, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255
+};
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/usb-debug.c linux/drivers/usb/usb-debug.c
--- v2.5.1/linux/drivers/usb/usb-debug.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/usb/usb-debug.c	Tue Jan  1 13:52:10 2002
@@ -181,23 +181,23 @@
 	kfree(buf);
 }
 
-void usb_dump_urb (purb_t purb)
+void usb_dump_urb (struct urb *urb)
 {
-	printk ("urb                   :%p\n", purb);
-	printk ("next                  :%p\n", purb->next);
-	printk ("dev                   :%p\n", purb->dev);
-	printk ("pipe                  :%08X\n", purb->pipe);
-	printk ("status                :%d\n", purb->status);
-	printk ("transfer_flags        :%08X\n", purb->transfer_flags);
-	printk ("transfer_buffer       :%p\n", purb->transfer_buffer);
-	printk ("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
-	printk ("actual_length         :%d\n", purb->actual_length);
-	printk ("setup_packet          :%p\n", purb->setup_packet);
-	printk ("start_frame           :%d\n", purb->start_frame);
-	printk ("number_of_packets     :%d\n", purb->number_of_packets);
-	printk ("interval              :%d\n", purb->interval);
-	printk ("error_count           :%d\n", purb->error_count);
-	printk ("context               :%p\n", purb->context);
-	printk ("complete              :%p\n", purb->complete);
+	printk ("urb                   :%p\n", urb);
+	printk ("next                  :%p\n", urb->next);
+	printk ("dev                   :%p\n", urb->dev);
+	printk ("pipe                  :%08X\n", urb->pipe);
+	printk ("status                :%d\n", urb->status);
+	printk ("transfer_flags        :%08X\n", urb->transfer_flags);
+	printk ("transfer_buffer       :%p\n", urb->transfer_buffer);
+	printk ("transfer_buffer_length:%d\n", urb->transfer_buffer_length);
+	printk ("actual_length         :%d\n", urb->actual_length);
+	printk ("setup_packet          :%p\n", urb->setup_packet);
+	printk ("start_frame           :%d\n", urb->start_frame);
+	printk ("number_of_packets     :%d\n", urb->number_of_packets);
+	printk ("interval              :%d\n", urb->interval);
+	printk ("error_count           :%d\n", urb->error_count);
+	printk ("context               :%p\n", urb->context);
+	printk ("complete              :%p\n", urb->complete);
 }
 
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.5.1/linux/drivers/usb/usb.c	Tue Dec 18 14:56:39 2001
+++ linux/drivers/usb/usb.c	Tue Jan  1 13:52:10 2002
@@ -97,6 +97,8 @@
 
 	usb_scan_devices();
 
+	usbfs_update_special();
+
 	return 0;
 }
 
@@ -192,6 +194,8 @@
 		usb_drivers_purge(driver, bus->root_hub);
 	}
 	up (&usb_bus_list_lock);
+
+	usbfs_update_special();
 }
 
 /**
@@ -421,7 +425,6 @@
 	bus->bandwidth_isoc_reqs = 0;
 
 	INIT_LIST_HEAD(&bus->bus_list);
-	INIT_LIST_HEAD(&bus->inodes);
 
 	atomic_set(&bus->refcnt, 1);
 
@@ -468,7 +471,7 @@
 	list_add(&bus->bus_list, &usb_bus_list);
 	up (&usb_bus_list_lock);
 
-	usbdevfs_add_bus(bus);
+	usbfs_add_bus(bus);
 
 	info("new USB bus registered, assigned bus number %d", bus->busnum);
 }
@@ -494,7 +497,7 @@
 	list_del(&bus->bus_list);
 	up (&usb_bus_list_lock);
 
-	usbdevfs_remove_bus(bus);
+	usbfs_remove_bus(bus);
 
 	clear_bit(bus->busnum, busmap.busmap);
 
@@ -923,7 +926,7 @@
 
 		/* a simple/common case: one config, one interface, one driver
 		 * with current altsetting being a reasonable setting.
-		 * everything needs a smart agent and usbdevfs; or can rely on
+		 * everything needs a smart agent and usbfs; or can rely on
 		 * device-specific binding policies.
 		 */
 		envp [i++] = scratch;
@@ -1013,10 +1016,11 @@
 
 	usb_bus_get(bus);
 
+	if (!parent)
+		dev->devpath [0] = '/';
 	dev->bus = bus;
 	dev->parent = parent;
 	atomic_set(&dev->refcnt, 1);
-	INIT_LIST_HEAD(&dev->inodes);
 	INIT_LIST_HEAD(&dev->filelist);
 
 	init_MUTEX(&dev->serialize);
@@ -1906,7 +1910,7 @@
 	/* Free the device number and remove the /proc/bus/usb entry */
 	if (dev->devnum > 0) {
 		clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
-		usbdevfs_remove_device(dev);
+		usbfs_remove_device(dev);
 	}
 
 	/* Free up the device itself */
@@ -2579,7 +2583,7 @@
 #endif
 
 	/* now that the basic setup is over, add a /proc/bus/usb entry */
-	usbdevfs_add_device(dev);
+	usbfs_add_device(dev);
 
 	/* find drivers willing to handle this device */
 	usb_find_drivers(dev);
@@ -2592,7 +2596,7 @@
 
 static int usb_open(struct inode * inode, struct file * file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct usb_driver *c = usb_minors[minor/16];
 	int err = -ENODEV;
 	struct file_operations *old_fops, *new_fops = NULL;
@@ -2660,7 +2664,7 @@
 {
 	init_MUTEX(&usb_bus_list_lock);
 	usb_major_init();
-	usbdevfs_init();
+	usbfs_init();
 	usb_hub_init();
 
 	return 0;
@@ -2672,7 +2676,7 @@
 static void __exit usb_exit(void)
 {
 	usb_major_cleanup();
-	usbdevfs_cleanup();
+	usbfs_cleanup();
 	usb_hub_cleanup();
 }
 
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/usbnet.c linux/drivers/usb/usbnet.c
--- v2.5.1/linux/drivers/usb/usbnet.c	Tue Dec 18 14:56:39 2001
+++ linux/drivers/usb/usbnet.c	Sun Dec 30 16:58:51 2001
@@ -1577,7 +1577,7 @@
 	struct nc_trailer	*trailer = 0;
 #endif	/* CONFIG_USB_NET1080 */
 
-	flags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL;
+	flags = in_interrupt () ? GFP_ATOMIC : GFP_NOIO; /* might be used for nfs */
 
 	// some devices want funky USB-level framing, for
 	// win32 driver (usually) and/or hardware quirks
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/vicam.c linux/drivers/usb/vicam.c
--- v2.5.1/linux/drivers/usb/vicam.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/vicam.c	Thu Jan  3 13:21:28 2002
@@ -0,0 +1,986 @@
+/* -*- linux-c -*-
+ * USB ViCAM driver
+ *
+ * Copyright (c) 2001 Christopher L Cheney (ccheney@cheney.cx)
+ * Copyright (c) 2001 Pavel Machek (pavel@suse.cz) sponsored by SuSE
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License as
+ *      published by the Free Software Foundation; either version 2 of
+ *      the License, or (at your option) any later version.
+ *
+ * This driver is for the Vista Imaging ViCAM and 3Com HomeConnect USB
+ *
+ * Thanks to Greg Kroah-Hartman for the USB Skeleton driver
+ *
+ * TODO:
+ *	- find out the ids for the Vista Imaging ViCAM
+ *
+ * History:
+ *
+ * 2001_07_07 - 0.1 - christopher: first version
+ * 2001_08_28 - 0.2 - pavel: messed it up, but for some fun, try 
+ 			while true; do dd if=/dev/video of=/dev/fb0 bs=$[0x1e480] count=1 2> /dev/null; done
+		      yep, moving pictures.
+ * 2001_08_29 - 0.3 - pavel: played a little bit more. Experimental mmap support. For some fun,
+ 			get gqcam-0.9, compile it and run. Better than dd ;-).
+ * 2001_08_29 - 0.4 - pavel: added shutter speed control (not much functional)
+ 			kill update_params if it does not seem to work for you.
+ * 2001_08_30 - 0.5 - pavel: fixed stupid bug with update_params & vicam_bulk
+
+ *
+ * FIXME: It crashes on rmmod with camera plugged.
+ */
+#define DEBUG 1
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/smp_lock.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/usb.h>
+
+#include <asm/io.h>
+#include <linux/wrapper.h>
+#include <linux/vmalloc.h>
+
+#include <linux/videodev.h>
+
+#include "vicam.h"
+#include "vicamurbs.h"
+
+/* Version Information */
+#define DRIVER_VERSION "v0"
+#define DRIVER_AUTHOR "Christopher L Cheney <ccheney@cheney.cx>, Pavel Machek <pavel@suse.cz>"
+#define DRIVER_DESC "USB ViCAM Driver"
+
+/* Define these values to match your device */
+#define USB_VICAM_VENDOR_ID	0x04C1
+#define USB_VICAM_PRODUCT_ID	0x009D
+
+/* table of devices that work with this driver */
+static struct usb_device_id vicam_table [] = {
+	{ USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID) },
+	{ }					/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, vicam_table);
+
+static int video_nr = -1; 		/* next avail video device */
+static struct usb_driver vicam_driver;
+
+static char *buf, *buf2;
+static int change_pending = 0; 
+
+static int vicam_parameters(struct usb_vicam *vicam);
+
+/******************************************************************************
+ *
+ *  Memory management functions
+ *
+ *  Taken from bttv-drivers.c 2.4.7-pre3
+ *
+ ******************************************************************************/
+
+/* [DaveM] I've recoded most of this so that:
+ * 1) It's easier to tell what is happening
+ * 2) It's more portable, especially for translating things
+ *    out of vmalloc mapped areas in the kernel.
+ * 3) Less unnecessary translations happen.
+ *
+ * The code used to assume that the kernel vmalloc mappings
+ * existed in the page tables of every process, this is simply
+ * not guarenteed.  We now use pgd_offset_k which is the
+ * defined way to get at the kernel page tables.
+ */
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
+{
+	unsigned long ret = 0UL;
+	pmd_t *pmd;
+	pte_t *ptep, pte;
+
+	if (!pgd_none(*pgd)) {
+		pmd = pmd_offset(pgd, adr);
+		if (!pmd_none(*pmd)) {
+			ptep = pte_offset(pmd, adr);
+			pte = *ptep;
+			if(pte_present(pte)) {
+				ret  = (unsigned long) page_address(pte_page(pte));
+				ret |= (adr & (PAGE_SIZE - 1));
+
+			}
+		}
+	}
+	return ret;
+}
+
+static inline unsigned long uvirt_to_bus(unsigned long adr)
+{
+	unsigned long kva, ret;
+
+	kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
+	ret = virt_to_bus((void *)kva);
+	return ret;
+}
+
+static inline unsigned long kvirt_to_bus(unsigned long adr)
+{
+	unsigned long va, kva, ret;
+
+	va = VMALLOC_VMADDR(adr);
+	kva = uvirt_to_kva(pgd_offset_k(va), va);
+	ret = virt_to_bus((void *)kva);
+	return ret;
+}
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+	unsigned long va, kva, ret;
+
+	va = VMALLOC_VMADDR(adr);
+	kva = uvirt_to_kva(pgd_offset_k(va), va);
+	ret = __pa(kva);
+	return ret;
+}
+
+static void * rvmalloc(signed long size)
+{
+	void * mem;
+	unsigned long adr, page;
+
+	mem=vmalloc_32(size);
+	if (mem)
+	{
+		memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+		adr=(unsigned long) mem;
+		while (size > 0)
+		{
+			page = kvirt_to_pa(adr);
+			mem_map_reserve(virt_to_page(__va(page)));
+			adr+=PAGE_SIZE;
+			size-=PAGE_SIZE;
+		}
+	}
+	return mem;
+}
+
+static void rvfree(void * mem, signed long size)
+{
+	unsigned long adr, page;
+
+	if (mem)
+	{
+		adr=(unsigned long) mem;
+		while (size > 0)
+		{
+			page = kvirt_to_pa(adr);
+			mem_map_unreserve(virt_to_page(__va(page)));
+			adr+=PAGE_SIZE;
+			size-=PAGE_SIZE;
+		}
+		vfree(mem);
+	}
+}
+
+/******************************************************************************
+ *
+ *  Foo Bar
+ *
+ ******************************************************************************/
+
+/**
+ *	usb_vicam_debug_data
+ */
+static inline void usb_vicam_debug_data (const char *function, int size, const unsigned char *data)
+{
+	int i;
+
+	if (!debug)
+		return;
+
+	printk (KERN_DEBUG __FILE__": %s - length = %d, data = ",
+		function, size);
+	for (i = 0; i < size; ++i) {
+		printk ("%.2x ", data[i]);
+	}
+	printk ("\n");
+}
+
+/*****************************************************************************
+ *
+ *  Send command to vicam
+ *
+ *****************************************************************************/
+
+static int vicam_sndctrl(int set, struct usb_vicam *vicam, unsigned short req,
+	unsigned short value, unsigned char *cp, int size)
+{
+	int ret;
+	unsigned char *transfer_buffer = kmalloc (size, GFP_KERNEL);
+
+	/* Needs to return data I think, works for sending though */
+	memcpy(transfer_buffer, cp, size);
+	
+	ret = usb_control_msg ( vicam->udev, set ? usb_sndctrlpipe(vicam->udev, 0) : usb_rcvctrlpipe(vicam->udev, 0), req, (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, 0, transfer_buffer, size, HZ);
+
+	kfree(transfer_buffer);
+	if (ret)
+		printk("vicam: error: %d\n", ret);
+	mdelay(100);
+	return ret;
+}
+
+
+/*****************************************************************************
+ *
+ *  Video4Linux Helpers
+ * 
+ *****************************************************************************/
+
+static int vicam_get_capability(struct usb_vicam *vicam, struct video_capability *b)
+{
+	dbg("vicam_get_capability");
+
+	strcpy(b->name, vicam->camera_name);
+	b->type = VID_TYPE_CAPTURE | VID_TYPE_MONOCHROME;
+	b->channels = 1;
+	b->audios = 0;
+
+	b->maxwidth = vicam->width[vicam->sizes-1];
+	b->maxheight = vicam->height[vicam->sizes-1];
+	b->minwidth = vicam->width[0];
+	b->minheight = vicam->height[0];
+
+	return 0;
+}
+		
+static int vicam_get_channel(struct usb_vicam *vicam, struct video_channel *v)
+{
+	dbg("vicam_get_channel");
+
+	if (v->channel != 0)
+		return -EINVAL;
+ 
+	v->flags = 0;
+	v->tuners = 0;
+	v->type = VIDEO_TYPE_CAMERA;
+	strcpy(v->name, "Camera");
+
+	return 0;
+} 
+		
+static int vicam_set_channel(struct usb_vicam *vicam, struct video_channel *v)
+{
+	dbg("vicam_set_channel");
+
+	if (v->channel != 0)
+		return -EINVAL;
+	
+	return 0;
+}
+		
+static int vicam_get_mmapbuffer(struct usb_vicam *vicam, struct video_mbuf *vm)
+{
+	int i;
+
+	dbg("vicam_get_mmapbuffer");
+
+	memset(vm, 0, sizeof(vm));
+	vm->size = VICAM_NUMFRAMES * vicam->maxframesize;
+	vm->frames = VICAM_NUMFRAMES;
+
+	for (i=0; i<VICAM_NUMFRAMES; i++)
+		vm->offsets[i] = vicam->maxframesize * i;
+
+	return 0;
+}
+
+static int vicam_get_picture(struct usb_vicam *vicam, struct video_picture *p)
+{
+	dbg("vicam_get_picture");
+
+	/* This is probably where that weird 0x56 call goes */
+	p->brightness = vicam->win.brightness;
+	p->hue = vicam->win.hue;
+	p->colour = vicam->win.colour;
+	p->contrast = vicam->win.contrast;
+	p->whiteness = vicam->win.whiteness;
+	p->depth = vicam->win.depth;
+	p->palette = vicam->win.palette;
+
+	return 0;
+}
+
+static void synchronize(struct usb_vicam *vicam)
+{
+	change_pending = 1;
+	interruptible_sleep_on(&vicam->wait);
+	vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0);
+	mdelay(10);
+	vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0);
+	mdelay(10);
+}
+
+static void params_changed(struct usb_vicam *vicam)
+{
+#if 1
+	synchronize(vicam);
+	mdelay(10);
+	vicam_parameters(vicam);
+	printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb));
+#endif
+}
+
+static int vicam_set_picture(struct usb_vicam *vicam, struct video_picture *p)
+{
+	int changed = 0;
+	info("vicam_set_picture (%d)", p->brightness);
+
+
+#define SET(x) \
+	if (vicam->win.x != p->x) \
+		vicam->win.x = p->x, changed = 1;
+	SET(brightness);
+	SET(hue);
+	SET(colour);
+	SET(contrast);
+	SET(whiteness);
+	SET(depth);
+	SET(palette);
+	if (changed)
+		params_changed(vicam);
+
+	return 0;
+	/* Investigate what should be done maybe 0x56 type call */
+	if (p->depth != 8) return 1;
+	if (p->palette != VIDEO_PALETTE_GREY) return 1;
+
+	return 0;
+}
+
+/* FIXME - vicam_sync_frame - important */
+static int vicam_sync_frame(struct usb_vicam *vicam, int frame)
+{
+	dbg("vicam_sync_frame");
+
+	if(frame <0 || frame >= VICAM_NUMFRAMES)
+		return -EINVAL;
+
+	/* Probably need to handle various cases */
+/*	ret=vicam_newframe(vicam, frame);
+	vicam->frame[frame].grabstate=FRAME_UNUSED;
+*/
+	return 0;
+}
+	
+static int vicam_get_window(struct usb_vicam *vicam, struct video_window *vw)
+{
+	dbg("vicam_get_window");
+
+	vw->x = 0;
+	vw->y = 0;
+	vw->chromakey = 0;
+	vw->flags = 0;
+	vw->clipcount = 0;
+	vw->width = vicam->win.width;
+	vw->height = vicam->win.height;
+
+	return 0;
+}
+
+static int vicam_set_window(struct usb_vicam *vicam, struct video_window *vw)
+{
+	info("vicam_set_window");
+		
+	if (vw->flags)
+		return -EINVAL;
+	if (vw->clipcount)
+		return -EINVAL;
+
+	if (vicam->win.width == vw->width && vicam->win.height == vw->height)
+		return 0;
+
+	/* Pick largest mode that is smaller than specified res */
+	/* If specified res is too small reject                 */
+
+	/* Add urb send to device... */
+
+	vicam->win.width = vw->width;
+	vicam->win.height = vw->height;
+	params_changed(vicam);
+
+	return 0;
+}
+
+/* FIXME - vicam_mmap_capture - important */
+static int vicam_mmap_capture(struct usb_vicam *vicam, struct video_mmap *vm)
+{
+	dbg("vicam_mmap_capture");
+
+	/* usbvideo.c looks good for using here */
+
+	/* 
+	if (vm->frame >= VICAM_NUMFRAMES)
+		return -EINVAL;
+	if (vicam->frame[vm->frame].grabstate != FRAME_UNUSED)
+		return -EBUSY;
+	vicam->frame[vm->frame].grabstate=FRAME_READY;
+	*/
+
+	/* No need to vicam_set_window here according to Alan */
+
+	/*
+	if (!vicam->streaming)
+		vicam_start_stream(vicam);
+	*/
+
+	/* set frame as ready */
+
+	return 0;
+}
+
+/*****************************************************************************
+ *
+ *  Video4Linux
+ * 
+ *****************************************************************************/
+
+static int vicam_v4l_open(struct video_device *vdev, int flags)
+{
+	struct usb_vicam *vicam = (struct usb_vicam *)vdev;
+	int err = 0;
+	
+	dbg("vicam_v4l_open");
+
+	MOD_INC_USE_COUNT; 
+	down(&vicam->sem);
+
+	if (vicam->open_count)		/* Maybe not needed? */
+		err = -EBUSY;
+	else {
+		vicam->fbuf = rvmalloc(vicam->maxframesize * VICAM_NUMFRAMES);
+		if (!vicam->fbuf)
+			err=-ENOMEM;
+		else {
+			vicam->open_count = 1;
+		}
+#ifdef BLINKING
+		vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);
+		info ("led on");
+		vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);
+#endif
+	}
+
+	up(&vicam->sem);
+	if (err)
+		MOD_DEC_USE_COUNT;
+	return err;
+}
+
+static void vicam_v4l_close(struct video_device *vdev)
+{
+	struct usb_vicam *vicam = (struct usb_vicam *)vdev;
+
+	dbg("vicam_v4l_close");
+	
+	down(&vicam->sem);
+
+#ifdef BLINKING
+	info ("led off");
+	vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0);
+//	vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); Leave it on
+#endif
+
+	rvfree(vicam->fbuf, vicam->maxframesize * VICAM_NUMFRAMES);
+	vicam->fbuf = 0;
+	vicam->open_count=0;
+
+	up(&vicam->sem);
+	/* Why does se401.c have a usbdevice check here? */
+	/* If device is unplugged while open, I guess we only may unregister now */
+	MOD_DEC_USE_COUNT;
+}
+
+static long vicam_v4l_read(struct video_device *vdev, char *user_buf, unsigned long buflen, int noblock)
+{
+	//struct usb_vicam *vicam = (struct usb_vicam *)vdev;
+
+	dbg("vicam_v4l_read(%ld)", buflen);
+
+	if (!vdev || !buf)
+		return -EFAULT;
+
+	if (copy_to_user(user_buf, buf2, buflen))
+		return -EFAULT;
+	return buflen;
+}
+
+static long vicam_v4l_write(struct video_device *dev, const char *buf, unsigned long count, int noblock)
+{
+	info("vicam_v4l_write");
+	return -EINVAL;
+}
+
+static int vicam_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
+{
+	struct usb_vicam *vicam = (struct usb_vicam *)vdev;
+	int ret = -EL3RST;
+
+	if (!vicam->udev)
+		return -EIO;
+
+	down(&vicam->sem);
+
+	switch (cmd) {
+	case VIDIOCGCAP:
+	{
+		struct video_capability b;
+		ret = vicam_get_capability(vicam,&b);
+		dbg("name %s",b.name);
+		if (copy_to_user(arg, &b, sizeof(b)))
+			ret = -EFAULT;
+	}
+	case VIDIOCGFBUF:
+	{
+		struct video_buffer vb;
+		info("vicam_v4l_ioctl - VIDIOCGBUF - query frame buffer param");
+		/* frame buffer not supported, not used */
+		memset(&vb, 0, sizeof(vb));
+		vb.base = NULL;
+		
+		/* FIXME - VIDIOCGFBUF - why the void */
+		if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
+			ret = -EFAULT;
+		ret = 0;
+	}
+	case VIDIOCGWIN:
+	{
+		struct video_window vw;
+		ret = vicam_get_window(vicam, &vw);
+		if (copy_to_user(arg, &vw, sizeof(vw)))
+			ret = -EFAULT;
+	}
+	case VIDIOCSWIN:
+	{
+		struct video_window vw;
+		if (copy_from_user(&vw, arg, sizeof(vw)))
+			ret = -EFAULT;
+		else
+			ret = vicam_set_window(vicam, &vw);
+		return ret;
+	}
+	case VIDIOCGCHAN:
+	{
+		struct video_channel v;
+
+		if (copy_from_user(&v, arg, sizeof(v)))
+			ret = -EFAULT;
+		else {
+			ret = vicam_get_channel(vicam,&v);
+			if (copy_to_user(arg, &v, sizeof(v)))
+				ret = -EFAULT;
+		}
+	}
+	case VIDIOCSCHAN:
+	{
+		struct video_channel v;
+		if (copy_from_user(&v, arg, sizeof(v)))
+			ret = -EFAULT;
+		else
+			ret = vicam_set_channel(vicam,&v);
+ 	}
+	case VIDIOCGPICT:
+	{
+		struct video_picture p;
+		ret = vicam_get_picture(vicam, &p);
+		if (copy_to_user(arg, &p, sizeof(p)))
+			ret = -EFAULT;
+	}
+	case VIDIOCSPICT:
+	{
+		struct video_picture p;
+		if (copy_from_user(&p, arg, sizeof(p)))
+			ret = -EFAULT;
+		else
+			ret = vicam_set_picture(vicam, &p);
+	}
+	case VIDIOCGMBUF:
+	{
+		struct video_mbuf vm;
+		ret = vicam_get_mmapbuffer(vicam,&vm);
+		/* FIXME - VIDIOCGMBUF - why the void */
+		if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+			ret = -EFAULT;
+	}
+	case VIDIOCMCAPTURE:
+	{
+		struct video_mmap vm;
+		ret = vicam_mmap_capture(vicam, &vm);
+		/* FIXME: This is probably not right */
+	}
+	case VIDIOCSYNC:
+	{
+		int frame;
+		/* FIXME - VIDIOCSYNC - why the void */
+		if (copy_from_user((void *)&frame, arg, sizeof(int)))
+			ret = -EFAULT;
+		else
+			ret = vicam_sync_frame(vicam,frame);
+	}
+
+	case VIDIOCKEY:
+		ret = 0;
+ 
+	case VIDIOCCAPTURE:
+	case VIDIOCSFBUF:
+	case VIDIOCGTUNER:
+	case VIDIOCSTUNER:
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+	case VIDIOCGUNIT:
+		ret = -EINVAL;
+
+	default:
+	{
+		info("vicam_v4l_ioctl - %ui",cmd);
+		ret = -ENOIOCTLCMD;
+	}
+	} /* end switch */
+
+	up(&vicam->sem);
+        return ret;
+}
+
+static int vicam_v4l_mmap(struct video_device *dev, const char *adr, unsigned long size)
+{
+	struct usb_vicam *vicam = (struct usb_vicam *)dev;
+	unsigned long start = (unsigned long)adr;
+	unsigned long page, pos;
+
+	down(&vicam->sem);
+	
+	if (vicam->udev == NULL) {
+		up(&vicam->sem);
+		return -EIO;
+	}
+#if 0
+	if (size > (((VICAM_NUMFRAMES * vicam->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
+		up(&vicam->sem);
+		return -EINVAL;
+	}
+#endif
+	pos = (unsigned long)vicam->fbuf;
+	while (size > 0) {
+		page = kvirt_to_pa(pos);
+		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
+			up(&vicam->sem);
+			return -EAGAIN;
+		}
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+	up(&vicam->sem);
+
+        return 0;
+}
+
+/* FIXME - vicam_v4l_init */
+static int vicam_v4l_init(struct video_device *dev)
+{
+	/* stick proc fs stuff in here if wanted */
+	dbg("vicam_v4l_init");
+	return 0;
+}
+
+/* FIXME - vicam_template - important */
+static struct video_device vicam_template = {
+	name:		"vicam USB camera",
+	type:		VID_TYPE_CAPTURE,
+	hardware:	VID_HARDWARE_SE401, /* need to ask for own id */
+	open:		vicam_v4l_open,
+	close:		vicam_v4l_close,
+	read:		vicam_v4l_read,
+	write:		vicam_v4l_write,
+	ioctl:		vicam_v4l_ioctl,
+	mmap:		vicam_v4l_mmap,
+	initialize:	vicam_v4l_init,
+};
+
+/******************************************************************************
+ *
+ *  Some Routines
+ *
+ ******************************************************************************/
+
+/*
+Flash the led
+vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);
+info ("led on");
+vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);
+info ("led off");
+vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0);
+vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0);
+*/
+
+static void vicam_bulk(struct urb *urb)
+{
+	struct usb_vicam *vicam = urb->context;
+
+	/*	if (!vicam || !vicam->dev || !vicam->used)
+		return;
+	*/
+
+	if (urb->status)
+		printk("vicam%d: nonzero read/write bulk status received: %d",
+			0, urb->status);
+
+	urb->actual_length = 0;
+	urb->dev = vicam->udev;
+
+	memcpy(buf2, buf+64, 0x1e480);
+	if (vicam->fbuf)
+		memcpy(vicam->fbuf, buf+64, 0x1e480);
+
+	if (!change_pending) {
+		if (usb_submit_urb(urb))
+			dbg("failed resubmitting read urb");
+	} else {
+		change_pending = 0;
+		wake_up_interruptible(&vicam->wait);
+	}
+}
+
+static int vicam_parameters(struct usb_vicam *vicam)
+{
+	unsigned char req[0x10];
+	unsigned int shutter;
+	shutter = 10;
+
+	switch (vicam->win.width) {
+	case 512:
+	default:
+		memcpy(req, s512x242bw, 0x10);
+		break;
+	case 256:
+		memcpy(req, s256x242bw, 0x10);
+		break;
+	case 128:
+		memcpy(req, s128x122bw, 0x10);
+		break;
+	}
+
+
+	mdelay(10);
+	vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);
+	info ("led on");
+	vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);
+
+	mdelay(10);
+
+	shutter = vicam->win.contrast / 256;
+	if (shutter == 0)
+		shutter = 1;
+	printk("vicam_parameters: brightness %d, shutter %d\n", vicam->win.brightness, shutter );
+	req[0] = vicam->win.brightness /256;
+	shutter = 15600/shutter - 1;
+	req[6] = shutter & 0xff;
+	req[7] = (shutter >> 8) & 0xff;
+	vicam_sndctrl(1, vicam, VICAM_REQ_CAPTURE, 0x80, req, 0x10);
+	mdelay(10);
+	vicam_sndctrl(0, vicam, VICAM_REQ_GET_SOMETHIN, 0, buf, 0x10);
+	mdelay(10);
+
+	return 0;
+}
+
+static int vicam_init(struct usb_vicam *vicam)
+{
+	int width[] = {128, 256, 512};
+	int height[] = {122, 242, 242};
+
+	dbg("vicam_init");
+	buf = kmalloc(0x1e480, GFP_KERNEL);
+	buf2 = kmalloc(0x1e480, GFP_KERNEL);
+	if ((!buf) || (!buf2)) {
+		printk("Not enough memory for vicam!\n");
+		goto error;
+	}
+
+	/* do we do aspect correction in kernel or not? */
+	vicam->sizes = 3;
+	vicam->width = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL);
+	vicam->height = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL);
+	memcpy(vicam->width, &width, sizeof(width));
+	memcpy(vicam->height, &height, sizeof(height));
+	vicam->maxframesize = vicam->width[vicam->sizes-1] * vicam->height[vicam->sizes-1];
+
+	/* Download firmware to camera */
+	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware1, sizeof(firmware1));
+	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex1, sizeof(findex1));
+	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup));
+	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware2, sizeof(firmware2));
+	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex2, sizeof(findex2));
+	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup));
+
+	vicam_parameters(vicam);
+
+	FILL_BULK_URB(&vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81),
+		      buf, 0x1e480, vicam_bulk, vicam);
+	printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb));
+
+	return 0;
+error:
+	if (buf)
+		kfree(buf);
+	if (buf2)
+		kfree(buf2);
+	return 1;
+}
+
+static void * __devinit vicam_probe(struct usb_device *udev, unsigned int ifnum,
+	const struct usb_device_id *id)
+{
+	struct usb_vicam *vicam;
+	char *camera_name=NULL;
+
+	dbg("vicam_probe");
+
+	/* See if the device offered us matches what we can accept */
+	if ((udev->descriptor.idVendor != USB_VICAM_VENDOR_ID) ||
+	    (udev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) {
+		return NULL;
+	}
+	
+	camera_name="3Com HomeConnect USB";
+	info("ViCAM camera found: %s", camera_name);
+	
+	vicam = kmalloc (sizeof(struct usb_vicam), GFP_KERNEL);
+	if (vicam == NULL) {
+		err ("couldn't kmalloc vicam struct");
+		return NULL;
+	}
+	memset(vicam, 0, sizeof(*vicam));
+	
+	vicam->udev = udev;
+	vicam->camera_name = camera_name;
+	vicam->win.brightness = 128;
+	vicam->win.contrast = 10;
+
+	/* FIXME */
+	if (vicam_init(vicam))
+		return NULL;
+	memcpy(&vicam->vdev, &vicam_template, sizeof(vicam_template));
+	memcpy(vicam->vdev.name, vicam->camera_name, strlen(vicam->camera_name));
+	
+	if (video_register_device(&vicam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+		err("video_register_device");
+		return NULL;
+	}
+
+	info("registered new video device: video%d", vicam->vdev.minor);
+	
+	init_MUTEX (&vicam->sem);
+	init_waitqueue_head(&vicam->wait);
+	
+	return vicam;
+}
+
+
+/* FIXME - vicam_disconnect - important */
+static void vicam_disconnect(struct usb_device *udev, void *ptr)
+{
+	struct usb_vicam *vicam;
+
+	vicam = (struct usb_vicam *) ptr;
+
+	if (!vicam->open_count)
+		video_unregister_device(&vicam->vdev);
+	vicam->udev = NULL;
+/*
+	vicam->frame[0].grabstate = FRAME_ERROR;
+	vicam->frame[1].grabstate = FRAME_ERROR;
+*/
+
+	/* Free buffers and shit */
+
+	info("%s disconnected", vicam->camera_name);
+	synchronize(vicam);
+
+	if (!vicam->open_count) {
+		/* Other random junk */
+		kfree(vicam);
+		vicam = NULL;
+	}
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver vicam_driver = {
+	name:		"vicam",
+	probe:		vicam_probe,
+	disconnect:	vicam_disconnect,
+	id_table:	vicam_table,
+};
+
+/******************************************************************************
+ *
+ *  Module Routines
+ *
+ ******************************************************************************/
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/* Module paramaters */
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+static int __init usb_vicam_init(void)
+{
+	int result;
+
+	printk("VICAM: initializing\n");
+	/* register this driver with the USB subsystem */
+	result = usb_register(&vicam_driver);
+	if (result < 0) {
+		err("usb_register failed for the "__FILE__" driver. Error number %d",
+		    result);
+		return -1;
+	}
+
+	info(DRIVER_VERSION " " DRIVER_AUTHOR);
+	info(DRIVER_DESC);
+	return 0;
+}
+
+static void __exit usb_vicam_exit(void)
+{
+	/* deregister this driver with the USB subsystem */
+	usb_deregister(&vicam_driver);
+}
+
+module_init(usb_vicam_init);
+module_exit(usb_vicam_exit);
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/vicam.h linux/drivers/usb/vicam.h
--- v2.5.1/linux/drivers/usb/vicam.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/vicam.h	Thu Jan  3 13:21:28 2002
@@ -0,0 +1,81 @@
+/*
+ *
+ * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver
+ * Christopher L Cheney (C) 2001
+ * 
+ */
+
+#ifndef __LINUX_VICAM_H
+#define __LINUX_VICAM_H
+
+
+#ifdef CONFIG_USB_DEBUG
+	static int debug = 1;
+#else
+	static int debug;
+#endif
+
+/* Use our own dbg macro */
+#undef dbg
+#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0)
+
+#define VICAM_NUMFRAMES 30
+#define VICAM_NUMSBUF 1
+
+/* USB REQUEST NUMBERS */
+#define VICAM_REQ_VENDOR	0xff
+#define VICAM_REQ_CAMERA_POWER	0x50
+#define VICAM_REQ_CAPTURE	0x51
+#define VICAM_REQ_LED_CONTROL	0x55
+#define VICAM_REQ_GET_SOMETHIN	0x56
+ 
+/* not required but lets you know camera is on */
+/* camera must be on to turn on led */
+/* 0x01 always on  0x03 on when picture taken (flashes) */
+
+struct picture_parm
+{
+	int width;
+	int height;
+	int brightness;
+	int hue;
+	int colour;
+	int contrast;
+	int whiteness;
+	int depth;
+	int palette;
+};
+
+struct vicam_scratch {
+        unsigned char *data;
+        volatile int state;
+        int offset;
+        int length;
+};
+
+/* Structure to hold all of our device specific stuff */
+struct usb_vicam
+{
+	struct video_device vdev;
+	struct usb_device *udev;
+
+	int open_count;	/* number of times this port has been opened */
+	struct semaphore sem;			/* locks this structure */
+	wait_queue_head_t wait;			/* Processes waiting */ 
+
+	int streaming;
+
+	/* v4l stuff */
+	char *camera_name;
+	char *fbuf;
+	urb_t *urb[VICAM_NUMSBUF];
+	int sizes;
+	int *width;
+	int *height;
+	int maxframesize;
+	struct picture_parm win;
+	struct proc_dir_entry *proc_entry;      /* /proc/se401/videoX */
+	struct urb readurb;
+};
+
+#endif
diff -u --recursive --new-file v2.5.1/linux/drivers/usb/vicamurbs.h linux/drivers/usb/vicamurbs.h
--- v2.5.1/linux/drivers/usb/vicamurbs.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/vicamurbs.h	Thu Jan  3 13:21:28 2002
@@ -0,0 +1,330 @@
+/*
+ *
+ * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver
+ * Christopher L Cheney (C) 2001
+ * 
+ */
+
+
+#ifndef __LINUX_VICAMURBS_H
+#define __LINUX_VICAMURBS_H
+
+/* -------------------------------------------------------------------------- */
+
+/* FIXME - Figure out transfers so that this doesn't need to be here
+ *
+ * Notice: in pieces below, "0" means other code will fill it while "0x00" means this is zero */
+
+/* Request 0x51 Image Setup */
+
+/* 128x98 ? 0x3180 size */
+static unsigned char s128x98bw[] = {
+  0,    0x34, 0xC4, 0x00, 0x00, 0x00, 0,    0,
+  0x18, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
+};
+
+/* 128x122 3D80 size */
+static unsigned char s128x122bw[] = {
+  0,    0x34, 0xF4, 0x00, 0x00, 0x00, 0,    0,
+  0x00, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
+};
+
+/* 256x242 ? 0xF280 size */
+static unsigned char s256x242bw[] = {
+  0,    0x03, 0xC8, 0x03, 0x00, 0x00, 0,    0,
+  0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
+};
+
+/* 512x242 0x1E480 size */
+static unsigned char s512x242bw[] = {
+  0,    0x05, 0x90, 0x07, 0x00, 0x00, 0,    0,
+  0x00, 0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
+};
+
+/* In s512x242:
+   byte 0: gain -- higher number means brighter image
+   byte 6, 7: shutter speed, little-endian; set this to 15600 * (shutter speed) - 1. (Where shutter speed is something like 1/1000).
+*/
+
+/* -------------------------------------------------------------------------- */
+
+static unsigned char fsetup[] = {
+  0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64,
+
+  0x00, 0x00
+};
+
+static unsigned char firmware1[] = {
+  0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64,
+
+  0xE7, 0x67, 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09,
+  0xDE, 0x00, 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03,
+  0xC0, 0x17, 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07,
+  0x00, 0x00, 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
+};
+
+static unsigned char findex1[] = {
+  0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64,
+
+  0x18, 0x00, 0x00, 0x00
+};
+
+static unsigned char firmware2[] = {
+  0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64,
+
+  0xE7, 0x07, 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07,
+  0x00, 0x00, 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01,
+  0xAA, 0x00, 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00,
+  0xE7, 0x07, 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07,
+  0x7C, 0x00, 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00,
+  0x18, 0x00, 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0,
+  0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07,
+  0xFF, 0xFF, 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00,
+  0x24, 0xC0, 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0,
+  0xE7, 0x07, 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87,
+  0x01, 0x00, 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09,
+  0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0,
+  0x09, 0xC1, 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01,
+  0xE7, 0x09, 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07,
+  0x07, 0x00, 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0,
+  0xC0, 0xDF, 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00,
+  0x17, 0x02, 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77,
+  0x01, 0x00, 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57,
+  0xFF, 0xFF, 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57,
+  0x00, 0x00, 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF,
+  0xC6, 0x00, 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05,
+  0xC1, 0x05, 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF,
+  0x27, 0xDA, 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00,
+  0x0B, 0x06, 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01,
+  0x9F, 0xAF, 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09,
+  0xFC, 0x05, 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06,
+  0x26, 0x01, 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0,
+  0xE7, 0x09, 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09,
+  0x02, 0x06, 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06,
+  0xFC, 0x05, 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06,
+  0x27, 0xDA, 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00,
+  0xFA, 0x05, 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF,
+  0x9F, 0xAF, 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07,
+  0x40, 0x00, 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05,
+  0x9F, 0xAF, 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17,
+  0x02, 0x00, 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06,
+  0x9F, 0xA0, 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00,
+  0x09, 0x06, 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57,
+  0x01, 0x00, 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03,
+  0xE7, 0x07, 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF,
+  0x47, 0xAF, 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07,
+  0x2E, 0x00, 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00,
+  0x09, 0x06, 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00,
+  0xC0, 0x57, 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02,
+  0xC0, 0x57, 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57,
+  0x55, 0x00, 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00,
+  0x9F, 0xC0, 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02,
+  0xC1, 0x0B, 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90,
+  0x08, 0x06, 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B,
+  0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF,
+  0x2F, 0x0E, 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07,
+  0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF,
+  0x28, 0x05, 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E,
+  0x02, 0x00, 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00,
+  0x09, 0x06, 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67,
+  0x7F, 0xFF, 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD,
+  0x22, 0xC0, 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0,
+  0xE7, 0x87, 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF,
+  0xB8, 0x05, 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0,
+  0x9F, 0xAF, 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00,
+  0x24, 0xC0, 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0,
+  0xC8, 0x07, 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00,
+  0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+  0x9F, 0xAF, 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00,
+  0x9F, 0xAF, 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE,
+  0x24, 0xC0, 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87,
+  0x00, 0x01, 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02,
+  0x0F, 0xC1, 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0,
+  0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
+  0x08, 0x00, 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1,
+  0xEF, 0x07, 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF,
+  0xEF, 0x07, 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF,
+  0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07,
+  0x00, 0x00, 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF,
+  0x09, 0x06, 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06,
+  0xE7, 0x67, 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67,
+  0x17, 0xD8, 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00,
+  0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0,
+  0x97, 0xCF, 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF,
+  0xDA, 0x02, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05,
+  0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07,
+  0x0E, 0x06, 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02,
+  0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07,
+  0x00, 0x80, 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C,
+  0x02, 0x00, 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00,
+  0x06, 0x06, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05,
+  0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07,
+  0xE2, 0x05, 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02,
+  0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07,
+  0x00, 0x80, 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF,
+  0x66, 0x04, 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF,
+  0x97, 0xCF, 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B,
+  0x0C, 0x06, 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05,
+  0xC0, 0x07, 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05,
+  0x68, 0x00, 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF,
+  0x44, 0x05, 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00,
+  0xE0, 0x07, 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06,
+  0xE8, 0x07, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02,
+  0xE0, 0x07, 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF,
+  0x97, 0xCF, 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05,
+  0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07,
+  0x0E, 0x06, 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06,
+  0xFE, 0x05, 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01,
+  0xE7, 0x07, 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07,
+  0x07, 0x00, 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07,
+  0x02, 0x00, 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01,
+  0xEF, 0x77, 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0,
+  0x14, 0x04, 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06,
+  0x37, 0xC0, 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06,
+  0x0F, 0xC1, 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06,
+  0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
+  0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00,
+  0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+  0xC8, 0x07, 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05,
+  0xC0, 0x07, 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05,
+  0xC1, 0x77, 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA,
+  0x75, 0xC1, 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1,
+  0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00,
+  0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00,
+  0x06, 0x06, 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00,
+  0xC1, 0x07, 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+  0xEF, 0x07, 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF,
+  0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57,
+  0x01, 0x00, 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07,
+  0x01, 0x00, 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF,
+  0x28, 0x05, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
+  0x30, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
+  0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
+  0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67,
+  0x03, 0x00, 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0,
+  0x08, 0xDA, 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00,
+  0xC1, 0x07, 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00,
+  0x06, 0x06, 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00,
+  0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00,
+  0xC1, 0x0B, 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05,
+  0xC0, 0x07, 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05,
+  0xE7, 0x09, 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8,
+  0xFA, 0x05, 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05,
+  0xE7, 0x07, 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07,
+  0x40, 0x00, 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05,
+  0x9F, 0xAF, 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B,
+  0xE2, 0x05, 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17,
+  0x23, 0x00, 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07,
+  0x04, 0x00, 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF,
+  0x28, 0x05, 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09,
+  0xE6, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+  0x07, 0x00, 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1,
+  0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00,
+  0xC1, 0x09, 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05,
+  0xC0, 0x07, 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05,
+  0xC1, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+  0x0D, 0x00, 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF,
+  0x28, 0x05, 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07,
+  0x32, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+  0x0F, 0x00, 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF,
+  0x28, 0x05, 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9,
+  0x24, 0xC0, 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00,
+  0xC0, 0x67, 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0,
+  0xE7, 0x87, 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67,
+  0xFF, 0xF9, 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA,
+  0x72, 0xC1, 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0,
+  0x97, 0xCF, 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87,
+  0xFF, 0x00, 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF,
+  0x24, 0xC0, 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0,
+  0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF,
+  0x9F, 0xAF, 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0,
+  0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
+  0x40, 0x00, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
+  0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05,
+  0xE7, 0x67, 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67,
+  0xFF, 0xFE, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
+  0x24, 0xC0, 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87,
+  0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07,
+  0x40, 0x00, 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67,
+  0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
+  0x24, 0xC0, 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0,
+  0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA,
+  0xE8, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00,
+  0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
+  0x00, 0xDA, 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1,
+  0xE7, 0x87, 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF,
+  0xE7, 0x07, 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77,
+  0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF,
+  0xE7, 0x07, 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77,
+  0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF,
+  0x09, 0x02, 0x19, 0x00, 0x01, 0x01, 0x00, 0x80,
+  0x96, 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static unsigned char findex2[] = {
+  0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64,
+
+  0x0E, 0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00,
+  0x26, 0x00, 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00,
+  0x92, 0x00, 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00,
+  0xB8, 0x00, 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00,
+  0xCE, 0x00, 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00,
+  0xE0, 0x00, 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00,
+  0xEC, 0x00, 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01,
+  0x0A, 0x01, 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01,
+  0x22, 0x01, 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01,
+  0x36, 0x01, 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01,
+  0x72, 0x01, 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01,
+  0x88, 0x01, 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01,
+  0xA0, 0x01, 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01,
+  0xB4, 0x01, 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01,
+  0xF6, 0x01, 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02,
+  0x3C, 0x02, 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02,
+  0x56, 0x02, 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02,
+  0x84, 0x02, 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02,
+  0x8E, 0x02, 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02,
+  0xAE, 0x02, 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02,
+  0xC0, 0x02, 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02,
+  0xD4, 0x02, 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02,
+  0xF8, 0x02, 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03,
+  0x24, 0x03, 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03,
+  0x3C, 0x03, 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03,
+  0x58, 0x03, 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03,
+  0x7A, 0x03, 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03,
+  0xB2, 0x03, 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03,
+  0xD4, 0x03, 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03,
+  0xFC, 0x03, 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04,
+  0x32, 0x04, 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04,
+  0x42, 0x04, 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04,
+  0x54, 0x04, 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04,
+  0x62, 0x04, 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04,
+  0x80, 0x04, 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04,
+  0x9A, 0x04, 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04,
+  0xB4, 0x04, 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04,
+  0x2A, 0x05, 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
+};
+
+#endif
diff -u --recursive --new-file v2.5.1/linux/drivers/video/aty/atyfb_base.c linux/drivers/video/aty/atyfb_base.c
--- v2.5.1/linux/drivers/video/aty/atyfb_base.c	Tue Oct 30 15:08:11 2001
+++ linux/drivers/video/aty/atyfb_base.c	Sun Dec 30 09:40:59 2001
@@ -2891,3 +2891,4 @@
 }
 
 #endif
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.1/linux/drivers/video/dn_cfb4.c linux/drivers/video/dn_cfb4.c
--- v2.5.1/linux/drivers/video/dn_cfb4.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/dn_cfb4.c	Sun Dec 30 10:31:51 2001
@@ -7,7 +7,6 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <asm/setup.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/amigahw.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/video/dn_cfb8.c linux/drivers/video/dn_cfb8.c
--- v2.5.1/linux/drivers/video/dn_cfb8.c	Mon Oct 15 13:47:13 2001
+++ linux/drivers/video/dn_cfb8.c	Sun Dec 30 10:31:51 2001
@@ -7,7 +7,6 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <asm/setup.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/amigahw.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/video/dnfb.c linux/drivers/video/dnfb.c
--- v2.5.1/linux/drivers/video/dnfb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/dnfb.c	Sun Dec 30 10:31:51 2001
@@ -7,7 +7,6 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <asm/setup.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/amigahw.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c
--- v2.5.1/linux/drivers/video/fbcon.c	Mon Oct 15 13:47:13 2001
+++ linux/drivers/video/fbcon.c	Thu Jan  3 12:20:18 2002
@@ -271,10 +271,10 @@
                 /* XXX Should report error here? */
                 return fgc;
 
-        if (MINOR(current->tty->device) < 1)
+        if (minor(current->tty->device) < 1)
                 return fgc;
 
-        return MINOR(current->tty->device) - 1;
+        return minor(current->tty->device) - 1;
 }
 
 
diff -u --recursive --new-file v2.5.1/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- v2.5.1/linux/drivers/video/fbmem.c	Wed Nov 14 15:41:37 2001
+++ linux/drivers/video/fbmem.c	Thu Jan  3 12:20:18 2002
@@ -21,6 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/slab.h>
+#include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/tty.h>
 #include <linux/console.h>
@@ -576,12 +577,13 @@
 		return -EINVAL;
 	off += start;
 	vma->vm_pgoff = off >> PAGE_SHIFT;
+	/* This is an IO map - tell maydump to skip this VMA */
+	vma->vm_flags |= VM_IO;
 #if defined(__sparc_v9__)
 	vma->vm_flags |= (VM_SHM | VM_LOCKED);
 	if (io_remap_page_range(vma->vm_start, off,
 				vma->vm_end - vma->vm_start, vma->vm_page_prot, 0))
 		return -EAGAIN;
-	vma->vm_flags |= VM_IO;
 #else
 #if defined(__mc68000__)
 #if defined(CONFIG_SUN3)
@@ -607,8 +609,6 @@
 	pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;
 #elif defined(__arm__)
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-	/* This is an IO map - tell maydump to skip this VMA */
-	vma->vm_flags |= VM_IO;
 #elif defined(__sh__)
 	pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE;
 #else
@@ -625,7 +625,7 @@
 #if 1 /* to go away in 2.5.0 */
 int GET_FB_IDX(kdev_t rdev)
 {
-    int fbidx = MINOR(rdev);
+    int fbidx = minor(rdev);
     if (fbidx >= 32) {
 	int newfbidx = fbidx >> 5;
 	static int warned;
@@ -719,7 +719,7 @@
 	for (i = 0 ; i < FB_MAX; i++)
 		if (!registered_fb[i])
 			break;
-	fb_info->node = MKDEV(FB_MAJOR, i);
+	fb_info->node = mk_kdev(FB_MAJOR, i);
 	registered_fb[i] = fb_info;
 	if (!fb_ever_opened[i]) {
 		struct module *owner = fb_info->fbops->owner;
@@ -931,3 +931,5 @@
 #if 1 /* to go away in 2.5.0 */
 EXPORT_SYMBOL(GET_FB_IDX);
 #endif
+
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.1/linux/drivers/video/q40fb.c linux/drivers/video/q40fb.c
--- v2.5.1/linux/drivers/video/q40fb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/q40fb.c	Sun Dec 30 10:31:51 2001
@@ -9,7 +9,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/setup.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 /*#include <asm/irq.h>*/
 #include <asm/q40_master.h>
diff -u --recursive --new-file v2.5.1/linux/drivers/video/vesafb.c linux/drivers/video/vesafb.c
--- v2.5.1/linux/drivers/video/vesafb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/vesafb.c	Thu Jan  3 12:20:18 2002
@@ -648,7 +648,7 @@
 	
 	strcpy(fb_info.modename, "VESA VGA");
 	fb_info.changevar = NULL;
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &vesafb_ops;
 	fb_info.disp=&disp;
 	fb_info.switch_con=&vesafb_switch;
diff -u --recursive --new-file v2.5.1/linux/fs/Config.in linux/fs/Config.in
--- v2.5.1/linux/fs/Config.in	Mon Nov 12 09:34:16 2001
+++ linux/fs/Config.in	Tue Dec 25 15:39:20 2001
@@ -45,7 +45,7 @@
 fi
 tristate 'Compressed ROM file system support' CONFIG_CRAMFS
 bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS
-tristate 'Simple RAM-based file system support' CONFIG_RAMFS
+define_bool CONFIG_RAMFS y
 
 tristate 'ISO 9660 CDROM file system support' CONFIG_ISO9660_FS
 dep_mbool '  Microsoft Joliet CDROM extensions' CONFIG_JOLIET $CONFIG_ISO9660_FS
diff -u --recursive --new-file v2.5.1/linux/fs/adfs/inode.c linux/fs/adfs/inode.c
--- v2.5.1/linux/fs/adfs/inode.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/adfs/inode.c	Sun Dec 30 10:53:53 2001
@@ -37,11 +37,8 @@
 			goto abort_toobig;
 
 		block = __adfs_block_map(inode->i_sb, inode->i_ino, block);
-		if (block) {
-			bh->b_dev = inode->i_dev;
-			bh->b_blocknr = block;
-			bh->b_state |= (1UL << BH_Mapped);
-		}
+		if (block)
+			map_bh(bh, inode->i_sb, block);
 		return 0;
 	}
 	/* don't support allocation of blocks yet */
@@ -251,7 +248,6 @@
 	if (!inode)
 		goto out;
 
-	inode->i_version = ++event;
 	inode->i_uid	 = sb->u.adfs_sb.s_uid;
 	inode->i_gid	 = sb->u.adfs_sb.s_gid;
 	inode->i_ino	 = obj->file_id;
diff -u --recursive --new-file v2.5.1/linux/fs/adfs/super.c linux/fs/adfs/super.c
--- v2.5.1/linux/fs/adfs/super.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/adfs/super.c	Tue Dec 25 15:39:20 2001
@@ -319,8 +319,7 @@
 	if (parse_options(sb, data))
 		goto error;
 
-	sb->s_blocksize = BLOCK_SIZE;
-	set_blocksize(dev, BLOCK_SIZE);
+	sb_set_blocksize(sb, BLOCK_SIZE);
 	if (!(bh = sb_bread(sb, ADFS_DISCRECORD / BLOCK_SIZE))) {
 		adfs_error(sb, "unable to read superblock");
 		goto error;
@@ -347,14 +346,8 @@
 		goto error_free_bh;
 	}
 
-	sb->s_blocksize_bits = dr->log2secsize;
-	sb->s_blocksize = 1 << sb->s_blocksize_bits;
-	if (sb->s_blocksize != BLOCK_SIZE &&
-	    (sb->s_blocksize == 512 || sb->s_blocksize == 1024 ||
-	     sb->s_blocksize == 2048 || sb->s_blocksize == 4096)) {
-
-		brelse(bh);
-		set_blocksize(dev, sb->s_blocksize);
+	brelse(bh);
+	if (sb_set_blocksize(sb, 1 << dr->log2secsize)) {
 		bh = sb_bread(sb, ADFS_DISCRECORD / sb->s_blocksize);
 		if (!bh) {
 			adfs_error(sb, "couldn't read superblock on "
@@ -367,12 +360,11 @@
 			goto error_free_bh;
 		}
 		dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET);
-	}
-	if (sb->s_blocksize != bh->b_size) {
+	} else {
 		if (!silent)
 			printk(KERN_ERR "VFS: Unsupported blocksize on dev "
 				"%s.\n", bdevname(dev));
-		goto error_free_bh;
+		goto error;
 	}
 
 	/*
diff -u --recursive --new-file v2.5.1/linux/fs/affs/file.c linux/fs/affs/file.c
--- v2.5.1/linux/fs/affs/file.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/affs/file.c	Thu Dec 27 08:17:43 2001
@@ -355,9 +355,7 @@
 	ext_bh = affs_get_extblock(inode, ext);
 	if (IS_ERR(ext_bh))
 		goto err_ext;
-	bh_result->b_blocknr = be32_to_cpu(AFFS_BLOCK(sb, ext_bh, block));
-	bh_result->b_dev = inode->i_dev;
-	bh_result->b_state |= (1UL << BH_Mapped);
+	map_bh(bh_result, sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, block)));
 
 	if (create) {
 		u32 blocknr = affs_alloc_block(inode, ext_bh->b_blocknr);
diff -u --recursive --new-file v2.5.1/linux/fs/affs/super.c linux/fs/affs/super.c
--- v2.5.1/linux/fs/affs/super.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/affs/super.c	Thu Jan  3 13:59:50 2002
@@ -262,7 +262,7 @@
 	 * blocks, we will have to change it.
 	 */
 
-	blocks = blk_size[MAJOR(dev)] ? blk_size[MAJOR(dev)][MINOR(dev)] : 0;
+	blocks = blk_size[major(dev)] ? blk_size[major(dev)][minor(dev)] : 0;
 	if (!blocks) {
 		printk(KERN_ERR "AFFS: Could not determine device size\n");
 		goto out_error;
@@ -326,10 +326,6 @@
 	/* N.B. after this point bh must be released */
 got_root:
 	root_block = AFFS_SB->s_root_block;
-
-	sb->s_blocksize_bits = blocksize == 512 ? 9 :
-			       blocksize == 1024 ? 10 :
-			       blocksize == 2048 ? 11 : 12;
 
 	/* Find out which kind of FS we have */
 	boot_bh = sb_bread(sb, 0);
diff -u --recursive --new-file v2.5.1/linux/fs/autofs/inode.c linux/fs/autofs/inode.c
--- v2.5.1/linux/fs/autofs/inode.c	Thu Oct 25 00:02:26 2001
+++ linux/fs/autofs/inode.c	Sat Dec 29 17:30:07 2001
@@ -11,6 +11,7 @@
  * ------------------------------------------------------------------------- */
 
 #include <linux/kernel.h>
+#include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/file.h>
 #include <linux/locks.h>
diff -u --recursive --new-file v2.5.1/linux/fs/autofs4/inode.c linux/fs/autofs4/inode.c
--- v2.5.1/linux/fs/autofs4/inode.c	Fri Nov  9 14:11:14 2001
+++ linux/fs/autofs4/inode.c	Mon Dec 31 18:25:49 2001
@@ -308,7 +308,7 @@
 	}
 	inode->i_blksize = PAGE_CACHE_SIZE;
 	inode->i_blocks = 0;
-	inode->i_rdev = 0;
+	inode->i_rdev = NODEV;
 	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 
 	if (S_ISDIR(inf->mode)) {
diff -u --recursive --new-file v2.5.1/linux/fs/bfs/dir.c linux/fs/bfs/dir.c
--- v2.5.1/linux/fs/bfs/dir.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/bfs/dir.c	Sun Dec 30 10:53:53 2001
@@ -28,13 +28,12 @@
 	struct inode * dir = f->f_dentry->d_inode;
 	struct buffer_head * bh;
 	struct bfs_dirent * de;
-	kdev_t dev = dir->i_dev;
 	unsigned int offset;
 	int block;
 
 	if (f->f_pos & (BFS_DIRENT_SIZE-1)) {
 		printf("Bad f_pos=%08lx for %s:%08lx\n", (unsigned long)f->f_pos, 
-			bdevname(dev), dir->i_ino);
+			bdevname(dir->i_dev), dir->i_ino);
 		return -EBADF;
 	}
 
@@ -174,7 +173,6 @@
 		inode->i_nlink = 1;
 	}
 	de->ino = 0;
-	dir->i_version = ++event;
 	mark_buffer_dirty(bh);
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(dir);
@@ -227,7 +225,6 @@
 	}
 	old_de->ino = 0;
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
-	old_dir->i_version = ++event;
 	mark_inode_dirty(old_dir);
 	if (new_inode) {
 		new_inode->i_nlink--;
@@ -256,7 +253,6 @@
 	struct buffer_head * bh;
 	struct bfs_dirent * de;
 	int block, sblock, eblock, off;
-	kdev_t dev;
 	int i;
 
 	dprintf("name=%s, namelen=%d\n", name, namelen);
@@ -266,7 +262,6 @@
 	if (namelen > BFS_NAMELEN)
 		return -ENAMETOOLONG;
 
-	dev = dir->i_dev;
 	sblock = dir->iu_sblock;
 	eblock = dir->iu_eblock;
 	for (block=sblock; block<=eblock; block++) {
@@ -282,7 +277,6 @@
 				}
 				dir->i_mtime = CURRENT_TIME;
 				mark_inode_dirty(dir);
-				dir->i_version = ++event;
 				de->ino = ino;
 				for (i=0; i<BFS_NAMELEN; i++)
 					de->name[i] = (i < namelen) ? name[i] : 0;
diff -u --recursive --new-file v2.5.1/linux/fs/bfs/file.c linux/fs/bfs/file.c
--- v2.5.1/linux/fs/bfs/file.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/bfs/file.c	Thu Dec 27 08:17:43 2001
@@ -25,14 +25,14 @@
 	mmap:	generic_file_mmap,
 };
 
-static int bfs_move_block(unsigned long from, unsigned long to, kdev_t dev)
+static int bfs_move_block(unsigned long from, unsigned long to, struct super_block *sb)
 {
 	struct buffer_head *bh, *new;
 
-	bh = bread(dev, from, BFS_BSIZE);
+	bh = sb_bread(sb, from);
 	if (!bh)
 		return -EIO;
-	new = getblk(dev, to, BFS_BSIZE);
+	new = sb_getblk(sb, to);
 	memcpy(new->b_data, bh->b_data, bh->b_size);
 	mark_buffer_dirty(new);
 	bforget(bh);
@@ -40,14 +40,14 @@
 	return 0;
 }
 
-static int bfs_move_blocks(kdev_t dev, unsigned long start, unsigned long end, 
+static int bfs_move_blocks(struct super_block *sb, unsigned long start, unsigned long end, 
 				unsigned long where)
 {
 	unsigned long i;
 
 	dprintf("%08lx-%08lx->%08lx\n", start, end, where);
 	for (i = start; i <= end; i++)
-		if(bfs_move_block(i, where + i, dev)) {
+		if(bfs_move_block(i, where + i, sb)) {
 			dprintf("failed to move block %08lx -> %08lx\n", i, where + i);
 			return -EIO;
 		}
@@ -69,9 +69,7 @@
 	if (!create) {
 		if (phys <= inode->iu_eblock) {
 			dprintf("c=%d, b=%08lx, phys=%08lx (granted)\n", create, block, phys);
-			bh_result->b_dev = inode->i_dev;
-			bh_result->b_blocknr = phys;
-			bh_result->b_state |= (1UL << BH_Mapped);
+			map_bh(bh_result, sb, phys);
 		}
 		return 0;
 	}
@@ -81,9 +79,7 @@
 	if (inode->i_size && phys <= inode->iu_eblock) {
 		dprintf("c=%d, b=%08lx, phys=%08lx (interim block granted)\n", 
 				create, block, phys);
-		bh_result->b_dev = inode->i_dev;
-		bh_result->b_blocknr = phys;
-		bh_result->b_state |= (1UL << BH_Mapped);
+		map_bh(bh_result, sb, phys);
 		return 0;
 	}
 
@@ -95,9 +91,7 @@
 	if (inode->iu_eblock == sb->su_lf_eblk) {
 		dprintf("c=%d, b=%08lx, phys=%08lx (simple extension)\n", 
 				create, block, phys);
-		bh_result->b_dev = inode->i_dev;
-		bh_result->b_blocknr = phys;
-		bh_result->b_state |= (1UL << BH_Mapped);
+		map_bh(bh_result, sb, phys);
 		sb->su_freeb -= phys - inode->iu_eblock;
 		sb->su_lf_eblk = inode->iu_eblock = phys;
 		mark_inode_dirty(inode);
@@ -109,7 +103,7 @@
 	/* Ok, we have to move this entire file to the next free block */
 	phys = sb->su_lf_eblk + 1;
 	if (inode->iu_sblock) { /* if data starts on block 0 then there is no data */
-		err = bfs_move_blocks(inode->i_dev, inode->iu_sblock, 
+		err = bfs_move_blocks(inode->i_sb, inode->iu_sblock, 
 				inode->iu_eblock, phys);
 		if (err) {
 			dprintf("failed to move ino=%08lx -> fs corruption\n", inode->i_ino);
@@ -128,9 +122,7 @@
 	sb->su_freeb -= inode->iu_eblock - inode->iu_sblock + 1 - inode->i_blocks;
 	mark_inode_dirty(inode);
 	mark_buffer_dirty(sbh);
-	bh_result->b_dev = inode->i_dev;
-	bh_result->b_blocknr = phys;
-	bh_result->b_state |= (1UL << BH_Mapped);
+	map_bh(bh_result, sb, phys);
 out:
 	unlock_kernel();
 	return err;
diff -u --recursive --new-file v2.5.1/linux/fs/bfs/inode.c linux/fs/bfs/inode.c
--- v2.5.1/linux/fs/bfs/inode.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/bfs/inode.c	Thu Dec 27 08:17:43 2001
@@ -35,13 +35,12 @@
 static void bfs_read_inode(struct inode * inode)
 {
 	unsigned long ino = inode->i_ino;
-	kdev_t dev = inode->i_dev;
 	struct bfs_inode * di;
 	struct buffer_head * bh;
 	int block, off;
 
 	if (ino < BFS_ROOT_INO || ino > inode->i_sb->su_lasti) {
-		printf("Bad inode number %s:%08lx\n", bdevname(dev), ino);
+		printf("Bad inode number %s:%08lx\n", bdevname(inode->i_dev), ino);
 		make_bad_inode(inode);
 		return;
 	}
@@ -49,7 +48,7 @@
 	block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
 	bh = sb_bread(inode->i_sb, block);
 	if (!bh) {
-		printf("Unable to read inode %s:%08lx\n", bdevname(dev), ino);
+		printf("Unable to read inode %s:%08lx\n", bdevname(inode->i_dev), ino);
 		make_bad_inode(inode);
 		return;
 	}
@@ -88,13 +87,12 @@
 static void bfs_write_inode(struct inode * inode, int unused)
 {
 	unsigned long ino = inode->i_ino;
-	kdev_t dev = inode->i_dev;
 	struct bfs_inode * di;
 	struct buffer_head * bh;
 	int block, off;
 
 	if (ino < BFS_ROOT_INO || ino > inode->i_sb->su_lasti) {
-		printf("Bad inode number %s:%08lx\n", bdevname(dev), ino);
+		printf("Bad inode number %s:%08lx\n", bdevname(inode->i_dev), ino);
 		return;
 	}
 
@@ -102,7 +100,7 @@
 	block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
 	bh = sb_bread(inode->i_sb, block);
 	if (!bh) {
-		printf("Unable to read inode %s:%08lx\n", bdevname(dev), ino);
+		printf("Unable to read inode %s:%08lx\n", bdevname(inode->i_dev), ino);
 		unlock_kernel();
 		return;
 	}
@@ -135,7 +133,6 @@
 static void bfs_delete_inode(struct inode * inode)
 {
 	unsigned long ino = inode->i_ino;
-	kdev_t dev = inode->i_dev;
 	struct bfs_inode * di;
 	struct buffer_head * bh;
 	int block, off;
@@ -155,7 +152,7 @@
 	block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
 	bh = sb_bread(s, block);
 	if (!bh) {
-		printf("Unable to read inode %s:%08lx\n", bdevname(dev), ino);
+		printf("Unable to read inode %s:%08lx\n", bdevname(inode->i_dev), ino);
 		unlock_kernel();
 		return;
 	}
@@ -241,16 +238,12 @@
 static struct super_block * bfs_read_super(struct super_block * s, 
 	void * data, int silent)
 {
-	kdev_t dev;
 	struct buffer_head * bh;
 	struct bfs_super_block * bfs_sb;
 	struct inode * inode;
 	int i, imap_len;
 
-	dev = s->s_dev;
-	set_blocksize(dev, BFS_BSIZE);
-	s->s_blocksize = BFS_BSIZE;
-	s->s_blocksize_bits = BFS_BSIZE_BITS;
+	sb_set_blocksize(s, BFS_BSIZE);
 
 	bh = sb_bread(s, 0);
 	if(!bh)
@@ -259,11 +252,11 @@
 	if (bfs_sb->s_magic != BFS_MAGIC) {
 		if (!silent)
 			printf("No BFS filesystem on %s (magic=%08x)\n", 
-				bdevname(dev), bfs_sb->s_magic);
+				bdevname(s->s_dev), bfs_sb->s_magic);
 		goto out;
 	}
 	if (BFS_UNCLEAN(bfs_sb, s) && !silent)
-		printf("%s is unclean, continuing\n", bdevname(dev));
+		printf("%s is unclean, continuing\n", bdevname(s->s_dev));
 
 	s->s_magic = BFS_MAGIC;
 	s->su_bfs_sb = bfs_sb;
diff -u --recursive --new-file v2.5.1/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.5.1/linux/fs/binfmt_elf.c	Sat Oct 20 19:16:59 2001
+++ linux/fs/binfmt_elf.c	Sun Dec 30 10:51:45 2001
@@ -32,7 +32,7 @@
 #include <linux/highuid.h>
 #include <linux/smp_lock.h>
 #include <linux/compiler.h>
-#include <linux/limits.h>
+#include <linux/highmem.h>
 
 #include <asm/uaccess.h>
 #include <asm/param.h>
@@ -505,30 +505,10 @@
 #if 0
 			printk("Using ELF interpreter %s\n", elf_interpreter);
 #endif
-#ifdef __sparc__
-			if (ibcs2_interpreter) {
-				unsigned long old_pers = current->personality;
-				struct exec_domain *old_domain = current->exec_domain;
-				struct exec_domain *new_domain;
-				struct fs_struct *old_fs = current->fs, *new_fs;
-				get_exec_domain(old_domain);
-				atomic_inc(&old_fs->count);
-
-				set_personality(PER_SVR4);
-				interpreter = open_exec(elf_interpreter);
-
-				new_domain = current->exec_domain;
-				new_fs = current->fs;
-				current->personality = old_pers;
-				current->exec_domain = old_domain;
-				current->fs = old_fs;
-				put_exec_domain(new_domain);
-				put_fs_struct(new_fs);
-			} else
-#endif
-			{
-				interpreter = open_exec(elf_interpreter);
-			}
+
+			SET_PERSONALITY(elf_ex, ibcs2_interpreter);
+
+			interpreter = open_exec(elf_interpreter);
 			retval = PTR_ERR(interpreter);
 			if (IS_ERR(interpreter))
 				goto out_free_interp;
@@ -602,10 +582,6 @@
 	current->flags &= ~PF_FORKNOEXEC;
 	elf_entry = (unsigned long) elf_ex.e_entry;
 
-	/* Do this immediately, since STACK_TOP as used in setup_arg_pages
-	   may depend on the personality.  */
-	SET_PERSONALITY(elf_ex, ibcs2_interpreter);
-
 	/* Do this so that we can load the interpreter, if need be.  We will
 	   change some of these later */
 	current->mm->rss = 0;
@@ -1032,6 +1008,25 @@
 	elf_fpregset_t fpu;		/* NT_PRFPREG */
 	struct elf_prpsinfo psinfo;	/* NT_PRPSINFO */
 
+	/* first copy the parameters from user space */
+	memset(&psinfo, 0, sizeof(psinfo));
+	{
+		int i, len;
+
+		len = current->mm->arg_end - current->mm->arg_start;
+		if (len >= ELF_PRARGSZ)
+			len = ELF_PRARGSZ-1;
+		copy_from_user(&psinfo.pr_psargs,
+			      (const char *)current->mm->arg_start, len);
+		for(i = 0; i < len; i++)
+			if (psinfo.pr_psargs[i] == 0)
+				psinfo.pr_psargs[i] = ' ';
+		psinfo.pr_psargs[len] = 0;
+
+	}
+
+	/* now stop all vm operations */
+	down_write(&current->mm->mmap_sem);
 	segs = current->mm->map_count;
 
 #ifdef DEBUG
@@ -1073,7 +1068,6 @@
 	 * Set up the notes in similar form to SVR4 core dumps made
 	 * with info from their /proc.
 	 */
-	memset(&psinfo, 0, sizeof(psinfo));
 	memset(&prstatus, 0, sizeof(prstatus));
 
 	notes[0].name = "CORE";
@@ -1129,23 +1123,6 @@
 	psinfo.pr_flag = current->flags;
 	psinfo.pr_uid = NEW_TO_OLD_UID(current->uid);
 	psinfo.pr_gid = NEW_TO_OLD_GID(current->gid);
-	{
-		int i, len;
-
-		set_fs(fs);
-
-		len = current->mm->arg_end - current->mm->arg_start;
-		if (len >= ELF_PRARGSZ)
-			len = ELF_PRARGSZ-1;
-		copy_from_user(&psinfo.pr_psargs,
-			      (const char *)current->mm->arg_start, len);
-		for(i = 0; i < len; i++)
-			if (psinfo.pr_psargs[i] == 0)
-				psinfo.pr_psargs[i] = ' ';
-		psinfo.pr_psargs[len] = 0;
-
-		set_fs(KERNEL_DS);
-	}
 	strncpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname));
 
 	notes[2].name = "CORE";
@@ -1217,8 +1194,6 @@
 		if (!writenote(&notes[i], file))
 			goto end_coredump;
 
-	set_fs(fs);
-
 	DUMP_SEEK(dataoff);
 
 	for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
@@ -1232,22 +1207,24 @@
 		for (addr = vma->vm_start;
 		     addr < vma->vm_end;
 		     addr += PAGE_SIZE) {
-			pgd_t *pgd;
-			pmd_t *pmd;
-			pte_t *pte;
-
-			pgd = pgd_offset(vma->vm_mm, addr);
-			if (pgd_none(*pgd))
-				goto nextpage_coredump;
-			pmd = pmd_offset(pgd, addr);
-			if (pmd_none(*pmd))
-				goto nextpage_coredump;
-			pte = pte_offset(pmd, addr);
-			if (pte_none(*pte)) {
-nextpage_coredump:
+			struct page* page;
+			struct vm_area_struct *vma;
+
+			if (get_user_pages(current, current->mm, addr, 1, 0, 1,
+						&page, &vma) <= 0) {
 				DUMP_SEEK (file->f_pos + PAGE_SIZE);
 			} else {
-				DUMP_WRITE((void*)addr, PAGE_SIZE);
+				if (page == ZERO_PAGE(addr)) {
+					DUMP_SEEK (file->f_pos + PAGE_SIZE);
+				} else {
+					void *kaddr;
+					flush_cache_page(vma, addr);
+					kaddr = kmap(page);
+					DUMP_WRITE(kaddr, PAGE_SIZE);
+					flush_page_to_ram(page);
+					kunmap(page);
+				}
+				put_page(page);
 			}
 		}
 	}
@@ -1260,6 +1237,7 @@
 
  end_coredump:
 	set_fs(fs);
+	up_write(&current->mm->mmap_sem);
 	return has_dumped;
 }
 #endif		/* USE_ELF_CORE_DUMP */
diff -u --recursive --new-file v2.5.1/linux/fs/bio.c linux/fs/bio.c
--- v2.5.1/linux/fs/bio.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/bio.c	Thu Dec 27 08:15:15 2001
@@ -142,6 +142,7 @@
 		bio->bi_io_vec = bvl;
 		return bio;
 	}
+
 	mempool_free(bio, bio_pool);
 	return NULL;
 }
@@ -311,28 +312,6 @@
 	return NULL;
 }
 
-#ifdef BIO_PAGEIO
-static int bio_end_io_page(struct bio *bio)
-{
-	struct page *page = bio_page(bio);
-
-	if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
-		SetPageError(page);
-	if (!PageError(page))
-		SetPageUptodate(page);
-
-	/*
-	 * Run the hooks that have to be done when a page I/O has completed.
-	 */
-	if (PageTestandClearDecrAfter(page))
-		atomic_dec(&nr_async_pages);
-
-	UnlockPage(page);
-	bio_put(bio);
-	return 1;
-}
-#endif
-
 static int bio_end_io_kio(struct bio *bio, int nr_sectors)
 {
 	struct kiobuf *kio = (struct kiobuf *) bio->bi_private;
@@ -465,7 +444,10 @@
 	else
 		clear_bit(BIO_UPTODATE, &bio->bi_flags);
 
-	return bio->bi_end_io(bio, nr_sectors);
+	if (bio->bi_end_io)
+		return bio->bi_end_io(bio, nr_sectors);
+
+	return 0;
 }
 
 static void __init biovec_init_pool(void)
diff -u --recursive --new-file v2.5.1/linux/fs/block_dev.c linux/fs/block_dev.c
--- v2.5.1/linux/fs/block_dev.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/block_dev.c	Tue Jan  1 13:09:10 2002
@@ -27,10 +27,10 @@
 static unsigned long max_block(kdev_t dev)
 {
 	unsigned int retval = ~0U;
-	int major = MAJOR(dev);
+	int major = major(dev);
 
 	if (blk_size[major]) {
-		int minor = MINOR(dev);
+		int minor = minor(dev);
 		unsigned int blocks = blk_size[major][minor];
 		if (blocks) {
 			unsigned int size = block_size(dev);
@@ -47,10 +47,10 @@
 static loff_t blkdev_size(kdev_t dev)
 {
 	unsigned int blocks = ~0U;
-	int major = MAJOR(dev);
+	int major = major(dev);
 
 	if (blk_size[major]) {
-		int minor = MINOR(dev);
+		int minor = minor(dev);
 		blocks = blk_size[major][minor];
 	}
 	return (loff_t) blocks << BLOCK_SIZE_BITS;
@@ -77,31 +77,51 @@
 		return -EINVAL;
 
 	/* No blocksize array? Implies hardcoded BLOCK_SIZE */
-	if (!blksize_size[MAJOR(dev)]) {
+	if (!blksize_size[major(dev)]) {
 		if (size == BLOCK_SIZE)
 			return 0;
 		return -EINVAL;
 	}
 
-	oldsize = blksize_size[MAJOR(dev)][MINOR(dev)];
+	oldsize = blksize_size[major(dev)][minor(dev)];
 	if (oldsize == size)
 		return 0;
 
 	if (!oldsize && size == BLOCK_SIZE) {
-		blksize_size[MAJOR(dev)][MINOR(dev)] = size;
+		blksize_size[major(dev)][minor(dev)] = size;
 		return 0;
 	}
 
 	/* Ok, we're actually changing the blocksize.. */
-	bdev = bdget(dev);
+	bdev = bdget(kdev_t_to_nr(dev));
 	sync_buffers(dev, 2);
-	blksize_size[MAJOR(dev)][MINOR(dev)] = size;
+	blksize_size[major(dev)][minor(dev)] = size;
 	bdev->bd_inode->i_blkbits = blksize_bits(size);
 	kill_bdev(bdev);
 	bdput(bdev);
 	return 0;
 }
 
+int sb_set_blocksize(struct super_block *sb, int size)
+{
+	int bits;
+	if (set_blocksize(sb->s_dev, size) < 0)
+		return 0;
+	sb->s_blocksize = size;
+	for (bits = 9, size >>= 9; size >>= 1; bits++)
+		;
+	sb->s_blocksize_bits = bits;
+	return sb->s_blocksize;
+}
+
+int sb_min_blocksize(struct super_block *sb, int size)
+{
+	int minsize = get_hardsect_size(sb->s_dev);
+	if (size < minsize)
+		size = minsize;
+	return sb_set_blocksize(sb, size);
+}
+
 static int blkdev_get_block(struct inode * inode, sector_t iblock, struct buffer_head * bh, int create)
 {
 	if (iblock >= max_block(inode->i_rdev))
@@ -491,15 +511,18 @@
 	int i;
 	const struct block_device_operations * bdops = NULL;
 
-	i = MAJOR(dev);
+	i = major(dev);
 	if (i < MAX_BLKDEV)
 		bdops = blkdevs[i].bdops;
 	if (bdops == NULL) {
 		devfs_handle_t de;
 
-		de = devfs_find_handle (NULL, NULL, i, MINOR (dev),
+		de = devfs_find_handle (NULL, NULL, i, minor(dev),
 					DEVFS_SPECIAL_BLK, 0);
-		if (de) bdops = devfs_get_ops (de);
+		if (de) {
+			bdops = devfs_get_ops (de);
+			devfs_put_ops (de); /* We're running in owner module */
+		}
 	}
 	if (bdops == NULL)
 		return 0;
@@ -540,7 +563,7 @@
 	down(&bdev->bd_sem);
 	lock_kernel();
 	if (!bdev->bd_op)
-		bdev->bd_op = get_blkfops(MAJOR(dev));
+		bdev->bd_op = get_blkfops(major(dev));
 	if (bdev->bd_op) {
 		ret = 0;
 		if (bdev->bd_op->owner)
@@ -663,11 +686,11 @@
 const char * bdevname(kdev_t dev)
 {
 	static char buffer[32];
-	const char * name = blkdevs[MAJOR(dev)].name;
+	const char * name = blkdevs[major(dev)].name;
 
 	if (!name)
 		name = "unknown-block";
 
-	sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
+	sprintf(buffer, "%s(%d,%d)", name, major(dev), minor(dev));
 	return buffer;
 }
diff -u --recursive --new-file v2.5.1/linux/fs/buffer.c linux/fs/buffer.c
--- v2.5.1/linux/fs/buffer.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/buffer.c	Tue Jan  1 12:55:46 2002
@@ -203,7 +203,7 @@
 		struct buffer_head * bh = next;
 		next = bh->b_next_free;
 
-		if (dev && bh->b_dev != dev)
+		if (!kdev_none(dev) && !kdev_same(bh->b_dev, dev))
 			continue;
 		if (test_and_set_bit(BH_Lock, &bh->b_state))
 			continue;
@@ -261,7 +261,7 @@
 				__refile_buffer(bh);
 			continue;
 		}
-		if (dev && bh->b_dev != dev)
+		if (!kdev_none(dev) && !kdev_same(bh->b_dev, dev))
 			continue;
 
 		get_bh(bh);
@@ -324,7 +324,7 @@
 
 	lock_kernel();
 	sync_inodes_sb(sb);
-	DQUOT_SYNC(dev);
+	DQUOT_SYNC(sb);
 	lock_super(sb);
 	if (sb->s_dirt && sb->s_op && sb->s_op->write_super)
 		sb->s_op->write_super(sb);
@@ -346,7 +346,14 @@
 
 	lock_kernel();
 	sync_inodes(dev);
-	DQUOT_SYNC(dev);
+	if (!kdev_none(dev)) {
+		struct super_block *sb = get_super(dev);
+		if (sb) {
+			DQUOT_SYNC(sb);
+			drop_super(sb);
+		}
+	} else
+			DQUOT_SYNC(NULL);
 	sync_supers(dev);
 	unlock_kernel();
 
@@ -364,7 +371,7 @@
 
 asmlinkage long sys_sync(void)
 {
-	fsync_dev(0);
+	fsync_dev(NODEV);
 	return 0;
 }
 
@@ -564,7 +571,7 @@
 			continue;
 		if (bh->b_size != size)
 			continue;
-		if (bh->b_dev != dev)
+		if (!kdev_same(bh->b_dev, dev))
 			continue;
 		get_bh(bh);
 		break;
@@ -668,7 +675,7 @@
 			bh_next = bh->b_next_free;
 
 			/* Another device? */
-			if (bh->b_dev != dev)
+			if (!kdev_same(bh->b_dev, dev))
 				continue;
 			/* Not hashed? */
 			if (!bh->b_pprev)
@@ -711,7 +718,7 @@
 
 void __invalidate_buffers(kdev_t dev, int destroy_dirty_buffers)
 {
-	struct block_device *bdev = bdget(dev);
+	struct block_device *bdev = bdget(kdev_t_to_nr(dev));
 	if (bdev) {
 		invalidate_bdev(bdev, destroy_dirty_buffers);
 		bdput(bdev);
@@ -1444,7 +1451,7 @@
 	return 1;
 }
 
-void create_empty_buffers(struct page *page, kdev_t dev, unsigned long blocksize)
+void create_empty_buffers(struct page *page, unsigned long blocksize)
 {
 	struct buffer_head *bh, *head, *tail;
 
@@ -1455,8 +1462,6 @@
 
 	bh = head;
 	do {
-		bh->b_dev = dev;
-		bh->b_blocknr = 0;
 		bh->b_end_io = NULL;
 		tail = bh;
 		bh = bh->b_this_page;
@@ -1518,7 +1523,7 @@
 		BUG();
 
 	if (!page->buffers)
-		create_empty_buffers(page, inode->i_dev, 1 << inode->i_blkbits);
+		create_empty_buffers(page, 1 << inode->i_blkbits);
 	head = page->buffers;
 
 	block = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
@@ -1585,7 +1590,7 @@
 
 	blocksize = 1 << inode->i_blkbits;
 	if (!page->buffers)
-		create_empty_buffers(page, inode->i_dev, blocksize);
+		create_empty_buffers(page, blocksize);
 	head = page->buffers;
 
 	bbits = inode->i_blkbits;
@@ -1702,7 +1707,7 @@
 		PAGE_BUG(page);
 	blocksize = 1 << inode->i_blkbits;
 	if (!page->buffers)
-		create_empty_buffers(page, inode->i_dev, blocksize);
+		create_empty_buffers(page, blocksize);
 	head = page->buffers;
 
 	blocks = PAGE_CACHE_SIZE >> inode->i_blkbits;
@@ -1907,7 +1912,7 @@
 		goto out;
 
 	if (!page->buffers)
-		create_empty_buffers(page, inode->i_dev, blocksize);
+		create_empty_buffers(page, blocksize);
 
 	/* Find the buffer that contains "offset" */
 	bh = page->buffers;
@@ -2123,13 +2128,14 @@
 		panic("brw_page: page not locked for I/O");
 
 	if (!page->buffers)
-		create_empty_buffers(page, dev, size);
+		create_empty_buffers(page, size);
 	head = bh = page->buffers;
 
 	/* Stage 1: lock all the buffers */
 	do {
 		lock_buffer(bh);
 		bh->b_blocknr = *(b++);
+		bh->b_dev = dev;
 		set_bit(BH_Mapped, &bh->b_state);
 		set_buffer_async_io(bh);
 		bh = bh->b_this_page;
@@ -2390,7 +2396,7 @@
 		struct buffer_head * p = tmp;
 		tmp = tmp->b_this_page;
 
-		if (p->b_dev == B_FREE) BUG();
+		if (kdev_same(p->b_dev, B_FREE)) BUG();
 
 		remove_inode_queue(p);
 		__remove_from_queues(p);
@@ -2556,7 +2562,7 @@
 {
 	lock_kernel();
 	sync_unlocked_inodes();
-	sync_supers(0);
+	sync_supers(NODEV);
 	unlock_kernel();
 
 	for (;;) {
diff -u --recursive --new-file v2.5.1/linux/fs/char_dev.c linux/fs/char_dev.c
--- v2.5.1/linux/fs/char_dev.c	Fri Nov  2 11:48:21 2001
+++ linux/fs/char_dev.c	Sat Dec 29 17:30:07 2001
@@ -6,6 +6,7 @@
 
 #include <linux/config.h>
 #include <linux/init.h>
+#include <linux/fs.h>
 #include <linux/slab.h>
 
 #define HASH_BITS	6
diff -u --recursive --new-file v2.5.1/linux/fs/coda/cache.c linux/fs/coda/cache.c
--- v2.5.1/linux/fs/coda/cache.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/coda/cache.c	Sun Dec 30 10:31:51 2001
@@ -14,7 +14,6 @@
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/locks.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
 #include <linux/list.h>
diff -u --recursive --new-file v2.5.1/linux/fs/coda/coda_linux.c linux/fs/coda/coda_linux.c
--- v2.5.1/linux/fs/coda/coda_linux.c	Wed Apr 25 16:18:54 2001
+++ linux/fs/coda/coda_linux.c	Sun Dec 30 10:31:51 2001
@@ -15,7 +15,6 @@
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/locks.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
 
diff -u --recursive --new-file v2.5.1/linux/fs/coda/file.c linux/fs/coda/file.c
--- v2.5.1/linux/fs/coda/file.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/coda/file.c	Sun Dec 30 10:31:51 2001
@@ -16,7 +16,6 @@
 #include <linux/errno.h>
 #include <linux/locks.h>
 #include <linux/smp_lock.h>
-#include <asm/segment.h>
 #include <linux/string.h>
 #include <asm/uaccess.h>
 
diff -u --recursive --new-file v2.5.1/linux/fs/coda/inode.c linux/fs/coda/inode.c
--- v2.5.1/linux/fs/coda/inode.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/coda/inode.c	Thu Jan  3 13:59:50 2002
@@ -25,7 +25,6 @@
 
 #include <linux/fs.h>
 #include <linux/vmalloc.h>
-#include <asm/segment.h>
 
 #include <linux/coda.h>
 #include <linux/coda_linux.h>
@@ -71,7 +70,7 @@
 		inode = file->f_dentry->d_inode;
 	
 	if(!inode || !S_ISCHR(inode->i_mode) ||
-	   MAJOR(inode->i_rdev) != CODA_PSDEV_MAJOR) {
+	   major(inode->i_rdev) != CODA_PSDEV_MAJOR) {
 		if(file)
 			fput(file);
 
@@ -79,7 +78,7 @@
 		return -1;
 	}
 
-	idx = MINOR(inode->i_rdev);
+	idx = minor(inode->i_rdev);
 	fput(file);
 
 	if(idx < 0 || idx >= MAX_CODADEVS) {
diff -u --recursive --new-file v2.5.1/linux/fs/coda/pioctl.c linux/fs/coda/pioctl.c
--- v2.5.1/linux/fs/coda/pioctl.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/coda/pioctl.c	Sun Dec 30 10:31:51 2001
@@ -14,7 +14,6 @@
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/locks.h>
-#include <asm/segment.h>
 #include <linux/string.h>
 #define __NO_VERSION__
 #include <linux/module.h>
diff -u --recursive --new-file v2.5.1/linux/fs/coda/psdev.c linux/fs/coda/psdev.c
--- v2.5.1/linux/fs/coda/psdev.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/coda/psdev.c	Sun Dec 30 10:31:51 2001
@@ -38,7 +38,6 @@
 #include <linux/list.h>
 #include <linux/smp_lock.h>
 #include <asm/io.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/poll.h>
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.5.1/linux/fs/coda/sysctl.c linux/fs/coda/sysctl.c
--- v2.5.1/linux/fs/coda/sysctl.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/coda/sysctl.c	Sun Dec 30 10:31:51 2001
@@ -21,7 +21,6 @@
 #include <linux/stat.h>
 #include <linux/ctype.h>
 #include <asm/bitops.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/utsname.h>
 #define __NO_VERSION__
diff -u --recursive --new-file v2.5.1/linux/fs/coda/upcall.c linux/fs/coda/upcall.c
--- v2.5.1/linux/fs/coda/upcall.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/coda/upcall.c	Sun Dec 30 10:31:51 2001
@@ -15,7 +15,6 @@
  */
 
 #include <asm/system.h>
-#include <asm/segment.h>
 #include <asm/signal.h>
 #include <linux/signal.h>
 
diff -u --recursive --new-file v2.5.1/linux/fs/cramfs/inode.c linux/fs/cramfs/inode.c
--- v2.5.1/linux/fs/cramfs/inode.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/cramfs/inode.c	Thu Jan  3 12:20:18 2002
@@ -115,7 +115,7 @@
 	struct buffer_head * read_array[BLKS_PER_BUF];
 	unsigned i, blocknr, buffer, unread;
 	unsigned long devsize;
-	int major, minor;
+	unsigned int major, minor;
 	
 	char *data;
 
@@ -140,8 +140,8 @@
 	}
 
 	devsize = ~0UL;
-	major = MAJOR(sb->s_dev);
-	minor = MINOR(sb->s_dev);
+	major = major(sb->s_dev);
+	minor = minor(sb->s_dev);
 
 	if (blk_size[major])
 		devsize = blk_size[major][minor] >> 2;
@@ -195,9 +195,7 @@
 	unsigned long root_offset;
 	struct super_block * retval = NULL;
 
-	set_blocksize(sb->s_dev, PAGE_CACHE_SIZE);
-	sb->s_blocksize = PAGE_CACHE_SIZE;
-	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+	sb_set_blocksize(sb, PAGE_CACHE_SIZE);
 
 	/* Invalidate the read buffers on mount: think disk change.. */
 	for (i = 0; i < READ_BUFFERS; i++)
diff -u --recursive --new-file v2.5.1/linux/fs/devfs/base.c linux/fs/devfs/base.c
--- v2.5.1/linux/fs/devfs/base.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/devfs/base.c	Thu Jan  3 13:59:50 2002
@@ -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.
@@ -562,6 +562,45 @@
     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
+    20011202   Richard Gooch <rgooch@atnf.csiro.au>
+	       Fixed bug in <devfsd_read>: was dereferencing freed pointer.
+  v1.3
+    20011203   Richard Gooch <rgooch@atnf.csiro.au>
+	       Fixed bug in <devfsd_close>: was dereferencing freed pointer.
+	       Added process group check for devfsd privileges.
+  v1.4
+    20011204   Richard Gooch <rgooch@atnf.csiro.au>
+	       Use SLAB_ATOMIC in <devfsd_notify_de> from <devfs_d_delete>.
+  v1.5
+    20011211   Richard Gooch <rgooch@atnf.csiro.au>
+	       Return old entry in <devfs_mk_dir> for 2.4.x kernels.
+    20011212   Richard Gooch <rgooch@atnf.csiro.au>
+	       Increment refcount on module in <check_disc_changed>.
+    20011215   Richard Gooch <rgooch@atnf.csiro.au>
+	       Created <devfs_get_handle> and exported <devfs_put>.
+	       Increment refcount on module in <devfs_get_ops>.
+	       Created <devfs_put_ops>.
+  v1.6
+    20011216   Richard Gooch <rgooch@atnf.csiro.au>
+	       Added poisoning to <devfs_put>.
+	       Improved debugging messages.
+  v1.7
+    20011221   Richard Gooch <rgooch@atnf.csiro.au>
+	       Corrected (made useful) debugging message in <unregister>.
+	       Moved <kmem_cache_create> in <mount_devfs_fs> to <init_devfs_fs>
+    20011224   Richard Gooch <rgooch@atnf.csiro.au>
+	       Added magic number to guard against scribbling drivers.
+    20011226   Richard Gooch <rgooch@atnf.csiro.au>
+	       Only return old entry in <devfs_mk_dir> if a directory.
+	       Defined macros for error and debug messages.
+  v1.8
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -594,13 +633,16 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 
-#define DEVFS_VERSION            "1.1 (20011122)"
+#define DEVFS_VERSION            "1.8 (20011226)"
 
 #define DEVFS_NAME "devfs"
 
 #define FIRST_INODE 1
 
 #define STRING_LENGTH 256
+#define FAKE_BLOCK_SIZE 1024
+#define POISON_PTR ( *(void **) poison_array )
+#define MAGIC_VALUE 0x327db823
 
 #ifndef TRUE
 #  define TRUE 1
@@ -637,9 +679,28 @@
 #define OPTION_MOUNT            0x01
 #define OPTION_ONLY             0x02
 
-#define OOPS(format, args...) {printk (format, ## args); \
-                               printk ("Forcing Oops\n"); \
-                               BUG();}
+#define PRINTK(format, args...) \
+   {printk (KERN_ERR "%s" format, __FUNCTION__ , ## args);}
+
+#define OOPS(format, args...) \
+   {printk (KERN_CRIT "%s" format, __FUNCTION__ , ## args); \
+    printk ("Forcing Oops\n"); \
+    BUG();}
+
+#ifdef CONFIG_DEVFS_DEBUG
+#  define VERIFY_ENTRY(de) \
+   {if ((de) && (de)->magic_number != MAGIC_VALUE) \
+        OOPS ("(%p): bad magic value: %x\n", (de), (de)->magic_number);}
+#  define WRITE_ENTRY_MAGIC(de,magic) (de)->magic_number = (magic)
+#  define DPRINTK(flag, format, args...) \
+   {if (devfs_debug & flag) \
+	printk (KERN_INFO "%s" format, __FUNCTION__ , ## args);}
+#else
+#  define VERIFY_ENTRY(de)
+#  define WRITE_ENTRY_MAGIC(de,magic)
+#  define DPRINTK(flag, format, args...)
+#endif
+
 
 struct directory_type
 {
@@ -696,6 +757,9 @@
 
 struct devfs_entry
 {
+#ifdef CONFIG_DEVFS_DEBUG
+    unsigned int magic_number;
+#endif
     void *info;
     atomic_t refcount;           /*  When this drops to zero, it's unused    */
     union 
@@ -740,6 +804,7 @@
     struct devfsd_buf_entry *devfsd_last_event;
     volatile int devfsd_sleeping;
     volatile struct task_struct *devfsd_task;
+    volatile pid_t devfsd_pgrp;
     volatile struct file *devfsd_file;
     struct devfsd_notify_struct *devfsd_info;
     volatile unsigned long devfsd_event_mask;
@@ -757,6 +822,8 @@
 static unsigned int stat_num_entries;
 static unsigned int stat_num_bytes;
 #endif
+static unsigned char poison_array[8] =
+    {0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a};
 
 #ifdef CONFIG_DEVFS_MOUNT
 static unsigned int boot_options = OPTION_MOUNT;
@@ -802,27 +869,26 @@
 
 static struct devfs_entry *devfs_get (struct devfs_entry *de)
 {
+    VERIFY_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.
+ *	@de:  The handle to the devfs entry.
  */
 
-static void devfs_put (struct devfs_entry *de)
+void devfs_put (devfs_handle_t de)
 {
     if (!de) return;
+    VERIFY_ENTRY (de);
+    if (de->info == POISON_PTR) OOPS ("(%p): poisoned pointer\n", de);
     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 (de == root_entry) OOPS ("(%p): root entry being freed\n", de);
+    DPRINTK (DEBUG_FREE, "(%s): de: %p, parent: %p \"%s\"\n",
+	     de->name, de, de->parent,
+	     de->parent ? de->parent->name : "no parent");
     if ( S_ISLNK (de->mode) ) kfree (de->u.symlink.linkname);
     if ( ( S_ISCHR (de->mode) || S_ISBLK (de->mode) ) && de->u.fcb.autogen )
     {
@@ -831,6 +897,7 @@
 			       MKDEV (de->u.fcb.u.device.major,
 				      de->u.fcb.u.device.minor) );
     }
+    WRITE_ENTRY_MAGIC (de, 0);
 #ifdef CONFIG_DEVFS_DEBUG
     spin_lock (&stat_lock);
     --stat_num_entries;
@@ -838,6 +905,7 @@
     if ( S_ISLNK (de->mode) ) stat_num_bytes -= de->u.symlink.length + 1;
     spin_unlock (&stat_lock);
 #endif
+    de->info = POISON_PTR;
     kfree (de);
 }   /*  End Function devfs_put  */
 
@@ -860,7 +928,7 @@
 
     if ( !S_ISDIR (dir->mode) )
     {
-	printk ("%s: search_dir(%s): not a directory\n", DEVFS_NAME,dir->name);
+	PRINTK ("(%s): not a directory\n", dir->name);
 	return NULL;
     }
     for (curr = dir->u.dir.first; curr != NULL; curr = curr->next)
@@ -893,7 +961,7 @@
     if ( name && (namelen < 1) ) namelen = strlen (name);
     if ( ( new = kmalloc (sizeof *new + namelen, GFP_KERNEL) ) == NULL )
 	return NULL;
-    memset (new, 0, sizeof *new + namelen);
+    memset (new, 0, sizeof *new + namelen);  /*  Will set '\0' on name  */
     new->mode = mode;
     if ( S_ISDIR (mode) ) rwlock_init (&new->u.dir.lock);
     atomic_set (&new->refcount, 1);
@@ -902,6 +970,7 @@
     spin_unlock (&counter_lock);
     if (name) memcpy (new->name, name, namelen);
     new->namelen = namelen;
+    WRITE_ENTRY_MAGIC (new, MAGIC_VALUE);
 #ifdef CONFIG_DEVFS_DEBUG
     spin_lock (&stat_lock);
     ++stat_num_entries;
@@ -918,7 +987,7 @@
  *	@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.
+ *		 be %NULL. An implicit devfs_get() is performed on this entry.
  *
  *  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.
@@ -934,8 +1003,7 @@
     if (old_de) *old_de = NULL;
     if ( !S_ISDIR (dir->mode) )
     {
-	printk ("%s: append_entry(%s): dir: \"%s\" is not a directory\n",
-		DEVFS_NAME, de->name, dir->name);
+	PRINTK ("(%s): dir: \"%s\" is not a directory\n", de->name, dir->name);
 	devfs_put (de);
 	return -ENOTDIR;
     }
@@ -995,16 +1063,16 @@
     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->u.fcb.u.device.major = major (devnum);
+    new->u.fcb.u.device.minor = minor (devnum);
     new->u.fcb.ops = &devfsd_fops;
     _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.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
@@ -1105,15 +1173,13 @@
     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);
+	PRINTK ("(%s): could not create parent path\n", 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);
+	PRINTK ("(%s): could not allocate entry\n", name);
 	devfs_put (*dir);
 	return NULL;
     }
@@ -1160,19 +1226,20 @@
 
 
 /**
- *	find_by_dev - Find a devfs entry in a directory.
+ *	_devfs_find_by_dev - Find a devfs entry in a directory.
  *	@dir: The directory where to search
  *	@major: The major number to search for.
  *	@minor: The minor number to search for.
  *	@type: The type of special file to search for. This may be either
  *		%DEVFS_SPECIAL_CHR or %DEVFS_SPECIAL_BLK.
  *
- *	Returns the devfs_entry pointer on success, else %NULL.
+ *	Returns the devfs_entry pointer on success, else %NULL. An implicit
+ *	devfs_get() is performed.
  */
 
-static struct devfs_entry *find_by_dev (struct devfs_entry *dir,
-					unsigned int major, unsigned int minor,
-					char type)
+static struct devfs_entry *_devfs_find_by_dev (struct devfs_entry *dir,
+					       unsigned int major,
+					       unsigned int minor, char type)
 {
     struct devfs_entry *entry, *de;
 
@@ -1180,7 +1247,7 @@
     if (dir == NULL) return NULL;
     if ( !S_ISDIR (dir->mode) )
     {
-	printk ("%s: find_by_dev(): not a directory\n", DEVFS_NAME);
+	PRINTK ("(%p): not a directory\n", dir);
 	devfs_put (dir);
 	return NULL;
     }
@@ -1205,7 +1272,7 @@
     for (entry = dir->u.dir.first; entry != NULL; entry = entry->next)
     {
 	if ( !S_ISDIR (entry->mode) ) continue;
-	de = find_by_dev (entry, major, minor, type);
+	de = _devfs_find_by_dev (entry, major, minor, type);
 	if (de)
 	{
 	    read_unlock (&dir->u.dir.lock);
@@ -1216,51 +1283,51 @@
     read_unlock (&dir->u.dir.lock);
     devfs_put (dir);
     return NULL;
-}   /*  End Function find_by_dev  */
+}   /*  End Function _devfs_find_by_dev  */
 
 
 /**
- *	find_entry - Find a devfs entry.
+ *	_devfs_find_entry - Find a devfs entry.
  *	@dir: The handle to the parent devfs directory entry. If this is %NULL the
  *		name is relative to the root of the devfs.
- *	@name: The name of the entry. This is ignored if @handle is not %NULL.
- *	@namelen: The number of characters in @name, not including a %NULL
- *		terminator. If this is 0, then @name must be %NULL-terminated and the
- *		length is computed internally.
- *	@major: The major number. This is used if @handle and @name are %NULL.
- *	@minor: The minor number. This is used if @handle and @name are %NULL.
+ *	@name: The name of the entry. This may be %NULL.
+ *	@major: The major number. This is used if lookup by @name fails.
+ *	@minor: The minor number. This is used if lookup by @name fails.
  *		NOTE: If @major and @minor are both 0, searching by major and minor
  *		numbers is disabled.
  *	@type: The type of special file to search for. This may be either
  *		%DEVFS_SPECIAL_CHR or %DEVFS_SPECIAL_BLK.
  *	@traverse_symlink: If %TRUE then symbolic links are traversed.
  *
- *	Returns the devfs_entry pointer on success, else %NULL.
+ *	Returns the devfs_entry pointer on success, else %NULL. An implicit
+ *	devfs_get() is performed.
  */
 
-static struct devfs_entry *find_entry (devfs_handle_t dir,
-				       const char *name, unsigned int namelen,
-				       unsigned int major, unsigned int minor,
-				       char type, int traverse_symlink)
+static struct devfs_entry *_devfs_find_entry (devfs_handle_t dir,
+					      const char *name,
+					      unsigned int major,
+					      unsigned int minor,
+					      char type, int traverse_symlink)
 {
     struct devfs_entry *entry;
 
     if (name != NULL)
     {
-	if (namelen < 1) namelen = strlen (name);
+	unsigned int namelen = strlen (name);
+
 	if (name[0] == '/')
 	{
 	    /*  Skip leading pathname component  */
 	    if (namelen < 2)
 	    {
-		printk ("%s: find_entry(%s): too short\n", DEVFS_NAME, name);
+		PRINTK ("(%s): too short\n", name);
 		return NULL;
 	    }
 	    for (++name, --namelen; (*name != '/') && (namelen > 0);
 		 ++name, --namelen);
 	    if (namelen < 2)
 	    {
-		printk ("%s: find_entry(%s): too short\n", DEVFS_NAME, name);
+		PRINTK ("(%s): too short\n", name);
 		return NULL;
 	    }
 	    ++name;
@@ -1271,12 +1338,13 @@
     }
     /*  Have to search by major and minor: slow  */
     if ( (major == 0) && (minor == 0) ) return NULL;
-    return find_by_dev (root_entry, major, minor, type);
-}   /*  End Function find_entry  */
+    return _devfs_find_by_dev (root_entry, major, minor, type);
+}   /*  End Function _devfs_find_entry  */
 
 static struct devfs_entry *get_devfs_entry_from_vfs_inode (struct inode *inode)
 {
     if (inode == NULL) return NULL;
+    VERIFY_ENTRY ( (struct devfs_entry *) inode->u.generic_ip );
     return inode->u.generic_ip;
 }   /*  End Function get_devfs_entry_from_vfs_inode  */
 
@@ -1315,10 +1383,14 @@
 {
     struct task_struct *p;
 
-    for (p = current; p != &init_task; p = p->p_opptr)
+    if (current == fs_info->devfsd_task) return (TRUE);
+    if (current->pgrp == fs_info->devfsd_pgrp) return (TRUE);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,1)
+    for (p = current->p_opptr; p != &init_task; p = p->p_opptr)
     {
 	if (p == fs_info->devfsd_task) return (TRUE);
     }
+#endif
     return (FALSE);
 }   /*  End Function is_devfsd_or_child  */
 
@@ -1375,13 +1447,16 @@
 
 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)
+			     uid_t uid, gid_t gid, struct fs_info *fs_info,
+			     int atomic)
 {
     struct devfsd_buf_entry *entry;
     struct devfs_entry *curr;
 
     if ( !( fs_info->devfsd_event_mask & (1 << type) ) ) return (FALSE);
-    if ( ( entry = kmem_cache_alloc (devfsd_buf_cache, 0) ) == NULL )
+    if ( ( entry = kmem_cache_alloc (devfsd_buf_cache,
+				     atomic ? SLAB_ATOMIC : SLAB_KERNEL) )
+	 == NULL )
     {
 	atomic_inc (&fs_info->devfsd_overrun_count);
 	return (FALSE);
@@ -1414,7 +1489,7 @@
 static void devfsd_notify (struct devfs_entry *de,unsigned short type,int wait)
 {
     if (devfsd_notify_de (de, type, de->mode, current->euid,
-			  current->egid, &fs_info) && wait)
+			  current->egid, &fs_info, 0) && wait)
 	wait_for_devfsd_finished (&fs_info);
 }   /*  End Function devfsd_notify  */
 
@@ -1451,7 +1526,7 @@
 
     if (name == NULL)
     {
-	printk ("%s: devfs_register(): NULL name pointer\n", DEVFS_NAME);
+	PRINTK ("(): NULL name pointer\n");
 	return NULL;
     }
     if (ops == NULL)
@@ -1459,23 +1534,19 @@
 	if ( S_ISBLK (mode) ) ops = (void *) get_blkfops (major);
 	if (ops == NULL)
 	{
-	    printk ("%s: devfs_register(%s): NULL ops pointer\n",
-		    DEVFS_NAME, name);
+	    PRINTK ("(%s): NULL ops pointer\n", name);
 	    return NULL;
 	}
-	printk ("%s: devfs_register(%s): NULL ops, got %p from major table\n",
-		DEVFS_NAME, name, ops);
+	PRINTK ("(%s): NULL ops, got %p from major table\n", name, ops);
     }
     if ( S_ISDIR (mode) )
     {
-	printk("%s: devfs_register(%s): creating directories is not allowed\n",
-	       DEVFS_NAME, name);
+	PRINTK ("(%s): creating directories is not allowed\n", name);
 	return NULL;
     }
     if ( S_ISLNK (mode) )
     {
-	printk ("%s: devfs_register(%s): creating symlinks is not allowed\n",
-		DEVFS_NAME, name);
+	PRINTK ("(%s): creating symlinks is not allowed\n", name);
 	return NULL;
     }
     if ( ( S_ISCHR (mode) || S_ISBLK (mode) ) &&
@@ -1483,17 +1554,16 @@
     {
 	if ( ( devnum = devfs_alloc_devnum (devtype) ) == NODEV )
 	{
-	    printk ("%s: devfs_register(%s): exhausted %s device numbers\n",
-		    DEVFS_NAME, name, S_ISCHR (mode) ? "char" : "block");
+	    PRINTK ("(%s): exhausted %s device numbers\n",
+		    name, S_ISCHR (mode) ? "char" : "block");
 	    return NULL;
 	}
-	major = MAJOR (devnum);
-	minor = MINOR (devnum);
+	major = major (devnum);
+	minor = minor (devnum);
     }
     if ( ( de = _devfs_prepare_leaf (&dir, name, mode) ) == NULL )
     {
-	printk ("%s: devfs_register(%s): could not prepare leaf\n",
-		DEVFS_NAME, name);
+	PRINTK ("(%s): could not prepare leaf\n", name);
 	if (devnum != NODEV) devfs_dealloc_devnum (devtype, devnum);
 	return NULL;
     }
@@ -1505,8 +1575,7 @@
     }
     else if ( !S_ISREG (mode) )
     {
-	printk ("%s: devfs_register(%s): illegal mode: %x\n",
-		DEVFS_NAME, name, mode);
+	PRINTK ("(%s): illegal mode: %x\n", name, mode);
 	devfs_put (de);
 	devfs_put (dir);
 	return (NULL);
@@ -1530,17 +1599,13 @@
     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);
+	PRINTK ("(%s): could not append to parent, err: %d\n", 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
+    DPRINTK (DEBUG_REGISTER, "(%s): de: %p dir: %p \"%s\"  pp: %p\n",
+	     name, de, dir, dir->name, dir->parent);
     devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT);
     devfs_put (dir);
     return de;
@@ -1576,7 +1641,7 @@
 
 
 /**
- *	unregister - Unregister a device entry from it's parent.
+ *	_devfs_unregister - Unregister a device entry from it's parent.
  *	@dir: The parent directory.
  *	@de: The entry to unregister.
  *
@@ -1584,7 +1649,7 @@
  *	unlocked by this function.
  */
 
-static void unregister (struct devfs_entry *dir, struct devfs_entry *de)
+static void _devfs_unregister (struct devfs_entry *dir, struct devfs_entry *de)
 {
     int unhooked = _devfs_unhook (de);
 
@@ -1603,34 +1668,30 @@
 	write_lock (&de->u.dir.lock);
 	de->u.dir.no_more_additions = TRUE;
 	child = de->u.dir.first;
-	unregister (de, child);
+	VERIFY_ENTRY (child);
+	_devfs_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
+	DPRINTK (DEBUG_UNREGISTER, "(%s): child: %p  refcount: %d\n",
+		 child->name, child, atomic_read (&child->refcount) );
 	devfs_put (child);
     }
-}   /*  End Function unregister  */
+}   /*  End Function _devfs_unregister  */
 
 
 /**
  *	devfs_unregister - Unregister a device entry.
  *	@de: A handle previously created by devfs_register() or returned from
- *		devfs_find_handle(). If this is %NULL the routine does nothing.
+ *		devfs_get_handle(). If this is %NULL the routine does nothing.
  */
 
 void devfs_unregister (devfs_handle_t de)
 {
+    VERIFY_ENTRY (de);
     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
+    DPRINTK (DEBUG_UNREGISTER, "(%s): de: %p  refcount: %d\n",
+	     de->name, de, atomic_read (&de->refcount) );
     write_lock (&de->parent->u.dir.lock);
-    unregister (de->parent, de);
+    _devfs_unregister (de->parent, de);
     devfs_put (de);
 }   /*  End Function devfs_unregister  */
 
@@ -1646,16 +1707,12 @@
     if (handle != NULL) *handle = NULL;
     if (name == NULL)
     {
-	printk ("%s: devfs_do_symlink(): NULL name pointer\n", DEVFS_NAME);
+	PRINTK ("(): NULL name pointer\n");
 	return -EINVAL;
     }
-#ifdef CONFIG_DEVFS_DEBUG
-    if (devfs_debug & DEBUG_REGISTER)
-	printk ("%s: devfs_do_symlink(%s)\n", DEVFS_NAME, name);
-#endif
     if (link == NULL)
     {
-	printk ("%s: devfs_do_symlink(): NULL link pointer\n", DEVFS_NAME);
+	PRINTK ("(%s): NULL link pointer\n", name);
 	return -EINVAL;
     }
     linklength = strlen (link);
@@ -1666,8 +1723,7 @@
     if ( ( de = _devfs_prepare_leaf (&dir, name, S_IFLNK | S_IRUGO | S_IXUGO) )
 	 == NULL )
     {
-	printk ("%s: devfs_do_symlink(%s): could not prepare leaf\n",
-		DEVFS_NAME, name);
+	PRINTK ("(%s): could not prepare leaf\n", name);
 	kfree (newlink);
 	return -ENOTDIR;
     }
@@ -1677,8 +1733,7 @@
     de->u.symlink.length = linklength;
     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);
+	PRINTK ("(%s): could not append to parent, err: %d\n", name, err);
 	devfs_put (dir);
 	return err;
     }
@@ -1713,6 +1768,7 @@
     devfs_handle_t de;
 
     if (handle != NULL) *handle = NULL;
+    DPRINTK (DEBUG_REGISTER, "(%s)\n", name);
     err = devfs_do_symlink (dir, name, flags, link, &de, info);
     if (err) return err;
     if (handle != NULL) *handle = de;
@@ -1738,39 +1794,47 @@
 devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name, void *info)
 {
     int err;
-    struct devfs_entry *de;
+    struct devfs_entry *de, *old;
 
     if (name == NULL)
     {
-	printk ("%s: devfs_mk_dir(): NULL name pointer\n", DEVFS_NAME);
+	PRINTK ("(): NULL name pointer\n");
 	return NULL;
     }
     if ( ( de = _devfs_prepare_leaf (&dir, name, MODE_DIR) ) == NULL )
     {
-	printk ("%s: devfs_mk_dir(%s): could not prepare leaf\n",
-		DEVFS_NAME, name);
+	PRINTK ("(%s): could not prepare leaf\n", name);
 	return NULL;
     }
     de->info = info;
-    if ( ( err = _devfs_append_entry (dir, de, FALSE, NULL) ) != 0 )
+    if ( ( err = _devfs_append_entry (dir, de, FALSE, &old) ) != 0 )
     {
-	printk ("%s: devfs_mk_dir(%s): could not append to dir: %p \"%s\", err: %d\n",
-		DEVFS_NAME, name, dir, dir->name, err);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,1)
+	if ( old && S_ISDIR (old->mode) )
+	{
+	    PRINTK ("(%s): using old entry in dir: %p \"%s\"\n",
+		    name, dir, dir->name);
+	    old->vfs_created = FALSE;
+	    devfs_put (dir);
+	    return old;
+	}
+#endif
+	PRINTK ("(%s): could not append to dir: %p \"%s\", err: %d\n",
+		name, dir, dir->name, err);
+	devfs_put (old);
 	devfs_put (dir);
 	return NULL;
     }
-#ifdef CONFIG_DEVFS_DEBUG
-    if (devfs_debug & DEBUG_REGISTER)
-	printk ("%s: devfs_mk_dir(%s): de: %p dir: %p \"%s\"\n",
-		DEVFS_NAME, name, de, dir, dir->name);
-#endif
+    DPRINTK (DEBUG_REGISTER, "(%s): de: %p dir: %p \"%s\"\n",
+	     name, de, dir, dir->name);
+    devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, 0);
     devfs_put (dir);
     return de;
 }   /*  End Function devfs_mk_dir  */
 
 
 /**
- *	devfs_find_handle - Find the handle of a devfs entry.
+ *	devfs_get_handle - Find the handle of a devfs entry.
  *	@dir: The handle to the parent devfs directory entry. If this is %NULL the
  *		name is relative to the root of the devfs.
  *	@name: The name of the entry.
@@ -1782,20 +1846,31 @@
  *		traversed. Symlinks pointing out of the devfs namespace will cause a
  *		failure. Symlink traversal consumes stack space.
  *
- *	Returns a handle which may later be used in a call to devfs_unregister(),
- *	devfs_get_flags(), or devfs_set_flags(). On failure %NULL is returned.
+ *	Returns a handle which may later be used in a call to
+ *	devfs_unregister(), devfs_get_flags(), or devfs_set_flags(). A
+ *	subsequent devfs_put() is required to decrement the refcount.
+ *	On failure %NULL is returned.
  */
 
+devfs_handle_t devfs_get_handle (devfs_handle_t dir, const char *name,
+				 unsigned int major, unsigned int minor,
+				 char type, int traverse_symlinks)
+{
+    if ( (name != NULL) && (name[0] == '\0') ) name = NULL;
+    return _devfs_find_entry (dir, name, major, minor, type,traverse_symlinks);
+}   /*  End Function devfs_get_handle  */
+
+
+/*  Compatibility function. Will be removed in sometime in 2.5  */
+
 devfs_handle_t devfs_find_handle (devfs_handle_t dir, const char *name,
 				  unsigned int major, unsigned int minor,
 				  char type, int traverse_symlinks)
 {
     devfs_handle_t de;
 
-    if ( (name != NULL) && (name[0] == '\0') ) name = NULL;
-    de = find_entry (dir, name, 0, major, minor, type, traverse_symlinks);
-    devfs_put (de);  /*  FIXME: in 2.5 consider dropping this and require a
-			 call to devfs_put()  */
+    de = devfs_get_handle (dir, name, major, minor, type, traverse_symlinks);
+    devfs_put (de);
     return de;
 }   /*  End Function devfs_find_handle  */
 
@@ -1813,6 +1888,7 @@
     unsigned int fl = 0;
 
     if (de == NULL) return -EINVAL;
+    VERIFY_ENTRY (de);
     if (de->hide) fl |= DEVFS_FL_HIDE;
     if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
     {
@@ -1836,11 +1912,8 @@
 int devfs_set_flags (devfs_handle_t de, unsigned int flags)
 {
     if (de == NULL) return -EINVAL;
-#ifdef CONFIG_DEVFS_DEBUG
-    if (devfs_debug & DEBUG_SET_FLAGS)
-	printk ("%s: devfs_set_flags(): de->name: \"%s\"\n",
-		DEVFS_NAME, de->name);
-#endif
+    VERIFY_ENTRY (de);
+    DPRINTK (DEBUG_SET_FLAGS, "(%s): flags: %x\n", de->name, flags);
     de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;
     if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
     {
@@ -1864,6 +1937,7 @@
 		       unsigned int *minor)
 {
     if (de == NULL) return -EINVAL;
+    VERIFY_ENTRY (de);
     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;
@@ -1904,6 +1978,7 @@
 #define NAMEOF(de) ( (de)->mode ? (de)->name : (de)->u.name )
 
     if (de == NULL) return -EINVAL;
+    VERIFY_ENTRY (de);
     if (de->namelen >= buflen) return -ENAMETOOLONG; /*  Must be first       */
     path[buflen - 1] = '\0';
     if (de->parent == NULL) return buflen - 1;       /*  Don't prepend root  */
@@ -1925,18 +2000,57 @@
  *	@de: The handle to the device entry.
  *
  *	Returns a pointer to the device operations on success, else NULL.
+ *	The use count for the module owning the operations will be incremented.
  */
 
 void *devfs_get_ops (devfs_handle_t de)
 {
+    struct module *owner;
+
     if (de == NULL) return NULL;
-    if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
-	return de->u.fcb.ops;
-    return NULL;
+    VERIFY_ENTRY (de);
+    if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) && !S_ISREG (de->mode) )
+	return NULL;
+    if (de->u.fcb.ops == NULL) return NULL;
+    read_lock (&de->parent->u.dir.lock);  /*  Prevent module from unloading  */
+    if (de->next == de) owner = NULL;     /*  Ops pointer is already stale   */
+    else if ( S_ISCHR (de->mode) || S_ISREG (de->mode) )
+	owner = ( (struct file_operations *) de->u.fcb.ops )->owner;
+    else owner = ( (struct block_device_operations *) de->u.fcb.ops )->owner;
+    if ( (de->next == de) || !try_inc_mod_count (owner) )
+    {   /*  Entry is already unhooked or module is unloading  */
+	read_unlock (&de->parent->u.dir.lock);
+	return NULL;
+    }
+    read_unlock (&de->parent->u.dir.lock);  /*  Module can continue unloading*/
+    return de->u.fcb.ops;
 }   /*  End Function devfs_get_ops  */
 
 
 /**
+ *	devfs_put_ops - Put the device operations for a devfs entry.
+ *	@de: The handle to the device entry.
+ *
+ *	The use count for the module owning the operations will be decremented.
+ */
+
+void devfs_put_ops (devfs_handle_t de)
+{
+    struct module *owner;
+
+    if (de == NULL) return;
+    VERIFY_ENTRY (de);
+    if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) && !S_ISREG (de->mode) )
+	return;
+    if (de->u.fcb.ops == NULL) return;
+    if ( S_ISCHR (de->mode) || S_ISREG (de->mode) )
+	owner = ( (struct file_operations *) de->u.fcb.ops )->owner;
+    else owner = ( (struct block_device_operations *) de->u.fcb.ops )->owner;
+    if (owner) __MOD_DEC_USE_COUNT (owner);
+}   /*  End Function devfs_put_ops  */
+
+
+/**
  *	devfs_set_file_size - Set the file size for a devfs regular file.
  *	@de: The handle to the device entry.
  *	@size: The new file size.
@@ -1947,6 +2061,7 @@
 int devfs_set_file_size (devfs_handle_t de, unsigned long size)
 {
     if (de == NULL) return -EINVAL;
+    VERIFY_ENTRY (de);
     if ( !S_ISREG (de->mode) ) return -EINVAL;
     if (de->u.fcb.u.file.size == size) return 0;
     de->u.fcb.u.file.size = size;
@@ -1966,6 +2081,7 @@
 void *devfs_get_info (devfs_handle_t de)
 {
     if (de == NULL) return NULL;
+    VERIFY_ENTRY (de);
     return de->info;
 }   /*  End Function devfs_get_info  */
 
@@ -1980,6 +2096,7 @@
 int devfs_set_info (devfs_handle_t de, void *info)
 {
     if (de == NULL) return -EINVAL;
+    VERIFY_ENTRY (de);
     de->info = info;
     return 0;
 }   /*  End Function devfs_set_info  */
@@ -1994,6 +2111,7 @@
 devfs_handle_t devfs_get_parent (devfs_handle_t de)
 {
     if (de == NULL) return NULL;
+    VERIFY_ENTRY (de);
     return de->parent;
 }   /*  End Function devfs_get_parent  */
 
@@ -2008,6 +2126,7 @@
 devfs_handle_t devfs_get_first_child (devfs_handle_t de)
 {
     if (de == NULL) return NULL;
+    VERIFY_ENTRY (de);
     if ( !S_ISDIR (de->mode) ) return NULL;
     return de->u.dir.first;
 }   /*  End Function devfs_get_first_child  */
@@ -2023,6 +2142,7 @@
 devfs_handle_t devfs_get_next_sibling (devfs_handle_t de)
 {
     if (de == NULL) return NULL;
+    VERIFY_ENTRY (de);
     return de->next;
 }   /*  End Function devfs_get_next_sibling  */
 
@@ -2038,14 +2158,15 @@
 void devfs_auto_unregister (devfs_handle_t master, devfs_handle_t slave)
 {
     if (master == NULL) return;
+    VERIFY_ENTRY (master);
+    VERIFY_ENTRY (slave);
     if (master->slave != NULL)
     {
 	/*  Because of the dumbness of the layers above, ignore duplicates  */
 	if (master->slave == slave) return;
-	printk ("%s: devfs_auto_unregister(): only one slave allowed\n",
-		DEVFS_NAME);
-	OOPS ("  master: \"%s\"  old slave: \"%s\"  new slave: \"%s\"\n",
-	      master->name, master->slave->name, slave->name);
+	PRINTK ("(%s): only one slave allowed\n", master->name);
+	OOPS ("():  old slave: \"%s\"  new slave: \"%s\"\n",
+	      master->slave->name, slave->name);
     }
     master->slave = slave;
 }   /*  End Function devfs_auto_unregister  */
@@ -2061,6 +2182,7 @@
 devfs_handle_t devfs_get_unregister_slave (devfs_handle_t master)
 {
     if (master == NULL) return NULL;
+    VERIFY_ENTRY (master);
     return master->slave;
 }   /*  End Function devfs_get_unregister_slave  */
 
@@ -2076,6 +2198,7 @@
 const char *devfs_get_name (devfs_handle_t de, unsigned int *namelen)
 {
     if (de == NULL) return NULL;
+    VERIFY_ENTRY (de);
     if (namelen != NULL) *namelen = de->namelen;
     return de->name;
 }   /*  End Function devfs_get_name  */
@@ -2218,10 +2341,12 @@
 
 __setup("devfs=", devfs_setup);
 
+EXPORT_SYMBOL(devfs_put);
 EXPORT_SYMBOL(devfs_register);
 EXPORT_SYMBOL(devfs_unregister);
 EXPORT_SYMBOL(devfs_mk_symlink);
 EXPORT_SYMBOL(devfs_mk_dir);
+EXPORT_SYMBOL(devfs_get_handle);
 EXPORT_SYMBOL(devfs_find_handle);
 EXPORT_SYMBOL(devfs_get_flags);
 EXPORT_SYMBOL(devfs_set_flags);
@@ -2268,8 +2393,9 @@
     buf->parent = parent;
     buf->namelen = namelen;
     buf->u.name = name;
+    WRITE_ENTRY_MAGIC (buf, MAGIC_VALUE);
     if ( !devfsd_notify_de (buf, DEVFSD_NOTIFY_LOOKUP, 0,
-			    current->euid, current->egid, fs_info) )
+			    current->euid, current->egid, fs_info, 0) )
 	return -ENOENT;
     /*  Possible success  */
     return 0;
@@ -2286,14 +2412,17 @@
 static int check_disc_changed (struct devfs_entry *de)
 {
     int tmp;
+    int retval = 0;
     kdev_t dev = MKDEV (de->u.fcb.u.device.major, de->u.fcb.u.device.minor);
-    struct block_device_operations *bdops = de->u.fcb.ops;
+    struct block_device_operations *bdops;
     extern int warn_no_part;
 
     if ( !S_ISBLK (de->mode) ) return 0;
-    if (bdops == NULL) return 0;
-    if (bdops->check_media_change == NULL) return 0;
-    if ( !bdops->check_media_change (dev) ) return 0;
+    bdops = devfs_get_ops (de);
+    if (!bdops) return 0;
+    if (bdops->check_media_change == NULL) goto out;
+    if ( !bdops->check_media_change (dev) ) goto out;
+    retval = 1;
     printk ( KERN_DEBUG "VFS: Disk change detected on device %s\n",
 	     kdevname (dev) );
     if (invalidate_device(dev, 0))
@@ -2303,7 +2432,9 @@
     warn_no_part = 0;
     if (bdops->revalidate) bdops->revalidate (dev);
     warn_no_part = tmp;
-    return 1;
+out:
+    devfs_put_ops (de);
+    return retval;
 }   /*  End Function check_disc_changed  */
 
 
@@ -2375,16 +2506,10 @@
     if (retval != 0) return retval;
     retval = inode_setattr (inode, iattr);
     if (retval != 0) return retval;
-#ifdef CONFIG_DEVFS_DEBUG
-    if (devfs_debug & DEBUG_I_CHANGE)
-    {
-	printk ("%s: notify_change(%d): VFS inode: %p  devfs_entry: %p\n",
-		DEVFS_NAME, (int) inode->i_ino, inode, de);
-	printk ("%s:   mode: 0%o  uid: %d  gid: %d\n",
-		DEVFS_NAME, (int) inode->i_mode,
-		(int) inode->i_uid, (int) inode->i_gid);
-    }
-#endif
+    DPRINTK (DEBUG_I_CHANGE, "(%d): VFS inode: %p  devfs_entry: %p\n",
+	     (int) inode->i_ino, inode, de);
+    DPRINTK (DEBUG_I_CHANGE, "():   mode: 0%o  uid: %d  gid: %d\n",
+	     (int) inode->i_mode, (int) inode->i_uid, (int) inode->i_gid);
     /*  Inode is not on hash chains, thus must save permissions here rather
 	than in a write_inode() method  */
     if ( ( !S_ISREG (inode->i_mode) && !S_ISCHR (inode->i_mode) &&
@@ -2397,16 +2522,17 @@
     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) )
+    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);
+			  inode->i_uid, inode->i_gid, fs_info, 0);
     return 0;
 }   /*  End Function devfs_notify_change  */
 
 static int devfs_statfs (struct super_block *sb, struct statfs *buf)
 {
     buf->f_type = DEVFS_SUPER_MAGIC;
-    buf->f_bsize = PAGE_SIZE / sizeof (long);
+    buf->f_bsize = FAKE_BLOCK_SIZE;
     buf->f_bfree = 0;
     buf->f_bavail = 0;
     buf->f_ffree = 0;
@@ -2428,7 +2554,7 @@
 
 
 /**
- *	get_vfs_inode - Get a VFS inode.
+ *	_devfs_get_vfs_inode - Get a VFS inode.
  *	@sb: The super block.
  *	@de: The devfs inode.
  *	@dentry: The dentry to register with the devfs inode.
@@ -2437,9 +2563,9 @@
  *       performed if the inode is created.
  */
 
-static struct inode *get_vfs_inode (struct super_block *sb,
-				    struct devfs_entry *de,
-				    struct dentry *dentry)
+static struct inode *_devfs_get_vfs_inode (struct super_block *sb,
+					   struct devfs_entry *de,
+					   struct dentry *dentry)
 {
     int is_fcb = FALSE;
     struct inode *inode;
@@ -2447,8 +2573,7 @@
     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);
+	PRINTK ("(%s): new_inode() failed, de: %p\n", de->name, de);
 	return NULL;
     }
     if (de->parent)
@@ -2465,13 +2590,10 @@
     }
     inode->u.generic_ip = devfs_get (de);
     inode->i_ino = de->inode.ino;
-#ifdef CONFIG_DEVFS_DEBUG
-    if (devfs_debug & DEBUG_I_GET)
-	printk ("%s: get_vfs_inode(%d): VFS inode: %p  devfs_entry: %p\n",
-		DEVFS_NAME, (int) inode->i_ino, inode, de);
-#endif
+    DPRINTK (DEBUG_I_GET, "(%d): VFS inode: %p  devfs_entry: %p\n",
+	     (int) inode->i_ino, inode, de);
     inode->i_blocks = 0;
-    inode->i_blksize = 1024;
+    inode->i_blksize = FAKE_BLOCK_SIZE;
     inode->i_op = &devfs_iops;
     inode->i_fop = &devfs_fops;
     inode->i_rdev = NODEV;
@@ -2491,8 +2613,7 @@
 	    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);
+	else PRINTK ("(%d): no block device from bdget()\n",(int)inode->i_ino);
 	is_fcb = TRUE;
     }
     else if ( S_ISFIFO (de->mode) ) inode->i_fop = &def_fifo_fops;
@@ -2519,14 +2640,10 @@
     inode->i_atime = de->inode.atime;
     inode->i_mtime = de->inode.mtime;
     inode->i_ctime = de->inode.ctime;
-#ifdef CONFIG_DEVFS_DEBUG
-    if (devfs_debug & DEBUG_I_GET)
-	printk ("%s:   mode: 0%o  uid: %d  gid: %d\n",
-		DEVFS_NAME, (int) inode->i_mode,
-		(int) inode->i_uid, (int) inode->i_gid);
-#endif
+    DPRINTK (DEBUG_I_GET, "():   mode: 0%o  uid: %d  gid: %d\n",
+	     (int) inode->i_mode, (int) inode->i_uid, (int) inode->i_gid);
     return inode;
-}   /*  End Function get_vfs_inode  */
+}   /*  End Function _devfs_get_vfs_inode  */
 
 
 /*  File operations for device entries follow  */
@@ -2542,11 +2659,8 @@
     fs_info = inode->i_sb->u.generic_sbp;
     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)
-	printk ("%s: readdir(): fs_info: %p  pos: %ld\n", DEVFS_NAME,
-		fs_info, (long) file->f_pos);
-#endif
+    DPRINTK (DEBUG_F_READDIR, "(%s): fs_info: %p  pos: %ld\n",
+	     parent->name, fs_info, (long) file->f_pos);
     switch ( (long) file->f_pos )
     {
       case 0:
@@ -2637,9 +2751,9 @@
 	inode->i_uid = current->euid;
 	inode->i_gid = current->egid;
     }
-    if (df->aopen_notify)
+    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);
+			  current->euid, current->egid, fs_info, 0);
     return 0;
 }   /*  End Function devfs_open  */
 
@@ -2666,13 +2780,7 @@
 
 static void devfs_d_release (struct dentry *dentry)
 {
-#ifdef CONFIG_DEVFS_DEBUG
-    struct inode *inode = dentry->d_inode;
-
-    if (devfs_debug & DEBUG_D_RELEASE)
-	printk ("%s: d_release(): dentry: %p inode: %p\n",
-		DEVFS_NAME, dentry, inode);
-#endif
+    DPRINTK (DEBUG_D_RELEASE, "(%p): inode: %p\n", dentry, dentry->d_inode);
 }   /*  End Function devfs_d_release  */
 
 /**
@@ -2686,14 +2794,11 @@
     struct devfs_entry *de;
 
     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
+    DPRINTK (DEBUG_D_IPUT,"(%s): dentry: %p inode: %p de: %p de->dentry: %p\n",
+	     de->name, dentry, inode, de, de->inode.dentry);
     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);
+	OOPS ("(%s): de: %p dentry: %p de->dentry: %p\n",
+	      de->name, de, dentry, de->inode.dentry);
     de->inode.dentry = NULL;
     iput (inode);
     devfs_put (de);
@@ -2733,20 +2838,13 @@
     /*  Unhash dentry if negative (has no inode)  */
     if (inode == NULL)
     {
-#ifdef CONFIG_DEVFS_DEBUG
-	if (devfs_debug & DEBUG_D_DELETE)
-	    printk ("%s: d_delete(): dropping negative dentry: %p\n",
-		    DEVFS_NAME, dentry);
-#endif
+	DPRINTK (DEBUG_D_DELETE, "(%p): dropping negative dentry\n", dentry);
 	return 1;
     }
     fs_info = inode->i_sb->u.generic_sbp;
     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",
-		DEVFS_NAME, dentry, inode, de);
-#endif
+    DPRINTK (DEBUG_D_DELETE, "(%p): inode: %p  devfs_entry: %p\n",
+	     dentry, inode, de);
     if (de == NULL) return 0;
     if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) && !S_ISREG (de->mode) )
 	return 0;
@@ -2754,7 +2852,7 @@
     de->u.fcb.open = FALSE;
     if (de->u.fcb.aopen_notify)
 	devfsd_notify_de (de, DEVFSD_NOTIFY_CLOSE, inode->i_mode,
-			  current->euid, current->egid, fs_info);
+			  current->euid, current->egid, fs_info, 1);
     if (!de->u.fcb.auto_owner) return 0;
     /*  Change the ownership/protection back  */
     inode->i_mode = (de->mode & S_IFMT) | S_IRUGO | S_IWUGO;
@@ -2774,25 +2872,19 @@
 	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
+	DPRINTK (DEBUG_I_LOOKUP, "(%s): dentry: %p by: \"%s\"\n",
+		 dentry->d_name.name, dentry, current->comm);
 	read_lock (&parent->u.dir.lock);
 	de = _devfs_search_dir (parent, dentry->d_name.name,
 				dentry->d_name.len);
-	read_lock (&parent->u.dir.lock);
+	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);
+	inode = _devfs_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
+	DPRINTK (DEBUG_I_LOOKUP, "(%s): new VFS inode(%u): %p  de: %p\n",
+		 de->name, de->inode.ino, inode, de);
 	d_instantiate (dentry, inode);
 	return 1;
     }
@@ -2805,21 +2897,17 @@
 
 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;
 
     /*  Set up the dentry operations before anything else, to ensure cleaning
 	up on any error  */
     dentry->d_op = &devfs_dops;
-    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);
-#ifdef CONFIG_DEVFS_DEBUG
-    if (devfs_debug & DEBUG_I_LOOKUP)
-	printk ("%s: lookup(%s): dentry: %p parent: %p by: \"%s\"\n",
-		DEVFS_NAME, dentry->d_name.name, dentry, parent,current->comm);
-#endif
+    DPRINTK (DEBUG_I_LOOKUP, "(%s): dentry: %p parent: %p by: \"%s\"\n",
+	     dentry->d_name.name, dentry, parent, current->comm);
     if (parent == NULL) return ERR_PTR (-ENOENT);
     read_lock (&parent->u.dir.lock);
     de = _devfs_search_dir (parent, dentry->d_name.name, dentry->d_name.len);
@@ -2872,14 +2960,11 @@
 	d_add (dentry, NULL);  /*  Open the floodgates  */
     }
     /*  Create an inode, now that the driver information is available  */
-    inode = get_vfs_inode (dir->i_sb, de, dentry);
+    inode = _devfs_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
+    DPRINTK (DEBUG_I_LOOKUP, "(%s): new VFS inode(%u): %p  de: %p\n",
+	     de->name, de->inode.ino, inode, de);
     d_instantiate (dentry, inode);
     if (dentry->d_op == &devfs_wait_dops)
     {   /*  Unlock directory semaphore, which will release any waiters. They
@@ -2897,20 +2982,19 @@
     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
-    if (devfs_debug & DEBUG_I_UNLINK)
-	printk ("%s: unlink(%s)\n", DEVFS_NAME, dentry->d_name.name);
-#endif
     de = get_devfs_entry_from_vfs_inode (inode);
+    DPRINTK (DEBUG_I_UNLINK, "(%s): de: %p\n", dentry->d_name.name, de);
     if (de == NULL) return -ENOENT;
     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;
-    devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
-		      inode->i_uid, inode->i_gid, dir->i_sb->u.generic_sbp);
+    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, 0);
     free_dentry (de);
     devfs_put (de);
     return 0;
@@ -2920,21 +3004,17 @@
 			  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);
     if (parent == NULL) return -ENOENT;
     err = devfs_do_symlink (parent, dentry->d_name.name, DEVFS_FL_NONE,
 			    symname, &de, NULL);
-#ifdef CONFIG_DEVFS_DEBUG
-    if (devfs_debug & DEBUG_DISABLED)
-	printk ("%s: symlink(): errcode from <devfs_do_symlink>: %d\n",
-		DEVFS_NAME, err);
-#endif
+    DPRINTK (DEBUG_DISABLED, "(%s): errcode from <devfs_do_symlink>: %d\n",
+	     dentry->d_name.name, err);
     if (err < 0) return err;
     de->vfs_created = TRUE;
     de->inode.uid = current->euid;
@@ -2942,28 +3022,25 @@
     de->inode.atime = CURRENT_TIME;
     de->inode.mtime = CURRENT_TIME;
     de->inode.ctime = CURRENT_TIME;
-    if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
+    if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
 	return -ENOMEM;
-#ifdef CONFIG_DEVFS_DEBUG
-    if (devfs_debug & DEBUG_DISABLED)
-	printk ("%s: symlink(): new VFS inode(%u): %p  dentry: %p\n",
-		DEVFS_NAME, de->inode.ino, inode, dentry);
-#endif
+    DPRINTK (DEBUG_DISABLED, "(%s): new VFS inode(%u): %p  dentry: %p\n",
+	     dentry->d_name.name, de->inode.ino, inode, dentry);
     d_instantiate (dentry, inode);
-    devfsd_notify_de (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, 0);
     return 0;
 }   /*  End Function devfs_symlink  */
 
 static int devfs_mkdir (struct inode *dir, struct dentry *dentry, int mode)
 {
     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;
 
     mode = (mode & ~S_IFMT) | S_IFDIR;  /*  VFS doesn't pass S_IFMT part  */
-    fs_info = dir->i_sb->u.generic_sbp;
     parent = get_devfs_entry_from_vfs_inode (dir);
     if (parent == NULL) return -ENOENT;
     de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
@@ -2976,16 +3053,14 @@
     de->inode.atime = CURRENT_TIME;
     de->inode.mtime = CURRENT_TIME;
     de->inode.ctime = CURRENT_TIME;
-    if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
+    if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
 	return -ENOMEM;
-#ifdef CONFIG_DEVFS_DEBUG
-    if (devfs_debug & DEBUG_DISABLED)
-	printk ("%s: mkdir(): new VFS inode(%u): %p  dentry: %p\n",
-		DEVFS_NAME, de->inode.ino, inode, dentry);
-#endif
+    DPRINTK (DEBUG_DISABLED, "(%s): new VFS inode(%u): %p  dentry: %p\n",
+	     dentry->d_name.name, de->inode.ino, inode, dentry);
     d_instantiate (dentry, inode);
-    devfsd_notify_de (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, 0);
     return 0;
 }   /*  End Function devfs_mkdir  */
 
@@ -2993,11 +3068,10 @@
 {
     int err = 0;
     struct devfs_entry *de;
-    struct fs_info *fs_info;
+    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);
     if (de == NULL) return -ENOENT;
     if ( !S_ISDIR (de->mode) ) return -ENOTDIR;
@@ -3013,8 +3087,9 @@
     if ( !_devfs_unhook (de) ) err = -ENOENT;
     write_unlock (&de->parent->u.dir.lock);
     if (err) return err;
-    devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
-		      inode->i_uid, inode->i_gid, fs_info);
+    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, 0);
     free_dentry (de);
     devfs_put (de);
     return 0;
@@ -3024,16 +3099,12 @@
 			int rdev)
 {
     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;
 
-#ifdef CONFIG_DEVFS_DEBUG
-    if (devfs_debug & DEBUG_I_MKNOD)
-	printk ("%s: mknod(%s): mode: 0%o  dev: %d\n",
-		DEVFS_NAME, dentry->d_name.name, mode, rdev);
-#endif
-    fs_info = dir->i_sb->u.generic_sbp;
+    DPRINTK (DEBUG_I_MKNOD, "(%s): mode: 0%o  dev: %d\n",
+	     dentry->d_name.name, mode, rdev);
     parent = get_devfs_entry_from_vfs_inode (dir);
     if (parent == NULL) return -ENOENT;
     de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
@@ -3051,16 +3122,14 @@
     de->inode.atime = CURRENT_TIME;
     de->inode.mtime = CURRENT_TIME;
     de->inode.ctime = CURRENT_TIME;
-    if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
+    if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
 	return -ENOMEM;
-#ifdef CONFIG_DEVFS_DEBUG
-    if (devfs_debug & DEBUG_I_MKNOD)
-	printk ("%s:   new VFS inode(%u): %p  dentry: %p\n",
-		DEVFS_NAME, de->inode.ino, inode, dentry);
-#endif
+    DPRINTK (DEBUG_I_MKNOD, ":   new VFS inode(%u): %p  dentry: %p\n",
+	     de->inode.ino, inode, dentry);
     d_instantiate (dentry, inode);
-    devfsd_notify_de (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, 0);
     return 0;
 }   /*  End Function devfs_mknod  */
 
@@ -3124,15 +3193,11 @@
     sb->s_blocksize_bits = 10;
     sb->s_magic = DEVFS_SUPER_MAGIC;
     sb->s_op = &devfs_sops;
-    if ( ( root_inode = get_vfs_inode (sb, root_entry, NULL) ) == NULL )
+    if ( ( root_inode = _devfs_get_vfs_inode (sb, root_entry, NULL) ) == NULL )
 	goto out_no_root;
     sb->s_root = d_alloc_root (root_inode);
     if (!sb->s_root) goto out_no_root;
-#ifdef CONFIG_DEVFS_DEBUG
-    if (devfs_debug & DEBUG_S_READ)
-	printk ("%s: read super, made devfs ptr: %p\n",
-		DEVFS_NAME, sb->u.generic_sbp);
-#endif
+    DPRINTK (DEBUG_S_READ, "(): made devfs ptr: %p\n", sb->u.generic_sbp);
     return sb;
 
 out_no_root:
@@ -3233,11 +3298,17 @@
     tlen = rpos - *ppos;
     if (done)
     {
+	devfs_handle_t parent;
+
 	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);
+	for (; de != NULL; de = parent)
+	{
+	    parent = 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;
@@ -3274,6 +3345,8 @@
 	    }
 	    fs_info->devfsd_task = current;
 	    spin_unlock (&lock);
+	    fs_info->devfsd_pgrp = (current->pgrp == current->pid) ?
+		current->pgrp : 0;
 	    fs_info->devfsd_file = file;
 	    fs_info->devfsd_info = kmalloc (sizeof *fs_info->devfsd_info,
 					    GFP_KERNEL);
@@ -3304,7 +3377,7 @@
 
 static int devfsd_close (struct inode *inode, struct file *file)
 {
-    struct devfsd_buf_entry *entry;
+    struct devfsd_buf_entry *entry, *next;
     struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
 
     if (fs_info->devfsd_file != file) return 0;
@@ -3320,10 +3393,14 @@
 	fs_info->devfsd_info = NULL;
     }
     spin_unlock (&fs_info->devfsd_buffer_lock);
+    fs_info->devfsd_pgrp = 0;
     fs_info->devfsd_task = NULL;
     wake_up (&fs_info->revalidate_wait_queue);
-    for (; entry; entry = entry->next)
+    for (; entry; entry = next)
+    {
+	next = entry->next;
 	kmem_cache_free (devfsd_buf_cache, entry);
+    }
     return 0;
 }   /*  End Function devfsd_close  */
 
@@ -3353,14 +3430,15 @@
 
     printk ("%s: v%s Richard Gooch (rgooch@atnf.csiro.au)\n",
 	    DEVFS_NAME, DEVFS_VERSION);
+    devfsd_buf_cache = kmem_cache_create ("devfsd_event",
+					  sizeof (struct devfsd_buf_entry),
+					  0, 0, NULL, NULL);
+    if (!devfsd_buf_cache) OOPS ("(): unable to allocate event slab\n");
 #ifdef CONFIG_DEVFS_DEBUG
     devfs_debug = devfs_debug_init;
     printk ("%s: devfs_debug: 0x%0x\n", DEVFS_NAME, devfs_debug);
 #endif
     printk ("%s: boot_options: 0x%0x\n", DEVFS_NAME, boot_options);
-    devfsd_buf_cache = kmem_cache_create ("devfsd_event",
-					  sizeof (struct devfsd_buf_entry),
-					  0, 0, NULL, NULL);
     err = register_filesystem (&devfs_fs_type);
     if (!err)
     {
diff -u --recursive --new-file v2.5.1/linux/fs/devfs/util.c linux/fs/devfs/util.c
--- v2.5.1/linux/fs/devfs/util.c	Thu Oct 11 09:43:30 2001
+++ linux/fs/devfs/util.c	Thu Jan  3 13:59:50 2002
@@ -61,67 +61,6 @@
 /*  Private functions follow  */
 
 /**
- *	_devfs_convert_name - Convert from an old style location-based name to new style.
- *	@new: The new name will be written here.
- *	@old: The old name.
- *	@disc: If true, disc partitioning information should be processed.
- */
-
-static void __init _devfs_convert_name (char *new, const char *old, int disc)
-{
-    int host, bus, target, lun;
-    char *ptr;
-    char part[8];
-
-    /*  Decode "c#b#t#u#"  */
-    if (old[0] != 'c') return;
-    host = simple_strtol (old + 1, &ptr, 10);
-    if (ptr[0] != 'b') return;
-    bus = simple_strtol (ptr + 1, &ptr, 10);
-    if (ptr[0] != 't') return;
-    target = simple_strtol (ptr + 1, &ptr, 10);
-    if (ptr[0] != 'u') return;
-    lun = simple_strtol (ptr + 1, &ptr, 10);
-    if (disc)
-    {
-	/*  Decode "p#"  */
-	if (ptr[0] == 'p') sprintf (part, "part%s", ptr + 1);
-	else strcpy (part, "disc");
-    }
-    else part[0] = '\0';
-    sprintf (new, "/host%d/bus%d/target%d/lun%d/%s",
-	     host, bus, target, lun, part);
-}   /*  End Function _devfs_convert_name  */
-
-
-/*  Public functions follow  */
-
-/**
- *	devfs_make_root - Create the root FS device entry if required.
- *	@name: The name of the root FS device, as passed by "root=".
- */
-
-void __init devfs_make_root (const char *name)
-{
-    char dest[64];
-
-    if ( (strncmp (name, "sd/", 3) == 0) || (strncmp (name, "sr/", 3) == 0) )
-    {
-	strcpy (dest, "../scsi");
-	_devfs_convert_name (dest + 7, name + 3, (name[1] == 'd') ? 1 : 0);
-    }
-    else if ( (strncmp (name, "ide/hd/", 7) == 0) ||
-	      (strncmp (name, "ide/cd/", 7) == 0) )
-    {
-	strcpy (dest, "..");
-	_devfs_convert_name (dest + 2, name + 7, (name[4] == 'h') ? 1 : 0);
-    }
-    else return;
-    devfs_mk_symlink (NULL, name, DEVFS_FL_DEFAULT, dest, NULL, NULL);
-}   /*  End Function devfs_make_root  */
-
-
-/**
  *	devfs_register_tape - Register a tape device in the "/dev/tapes" hierarchy.
  *	@de: Any tape device entry in the device directory.
  */
@@ -381,8 +320,8 @@
 	semaphore = &block_semaphore;
 	list = &block_list;
     }
-    major = MAJOR (devnum);
-    minor = MINOR (devnum);
+    major = major (devnum);
+    minor = minor (devnum);
     down (semaphore);
     for (entry = list->first; entry != NULL; entry = entry->next)
     {
diff -u --recursive --new-file v2.5.1/linux/fs/devices.c linux/fs/devices.c
--- v2.5.1/linux/fs/devices.c	Sat Sep 22 20:35:43 2001
+++ linux/fs/devices.c	Tue Jan  1 12:52:51 2002
@@ -27,7 +27,7 @@
 /* serial module kmod load support */
 struct tty_driver *get_tty_driver(kdev_t device);
 #define isa_tty_dev(ma)	(ma == TTY_MAJOR || ma == TTYAUX_MAJOR)
-#define need_serial(ma,mi) (get_tty_driver(MKDEV(ma,mi)) == NULL)
+#define need_serial(ma,mi) (get_tty_driver(mk_kdev(ma,mi)) == NULL)
 #endif
 
 struct device_struct {
@@ -145,7 +145,7 @@
 {
 	int ret = -ENODEV;
 
-	filp->f_op = get_chrfops(MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
+	filp->f_op = get_chrfops(major(inode->i_rdev), minor(inode->i_rdev));
 	if (filp->f_op) {
 		ret = 0;
 		if (filp->f_op->open != NULL) {
@@ -173,18 +173,18 @@
 const char * kdevname(kdev_t dev)
 {
 	static char buffer[32];
-	sprintf(buffer, "%02x:%02x", MAJOR(dev), MINOR(dev));
+	sprintf(buffer, "%02x:%02x", major(dev), minor(dev));
 	return buffer;
 }
 
 const char * cdevname(kdev_t dev)
 {
 	static char buffer[32];
-	const char * name = chrdevs[MAJOR(dev)].name;
+	const char * name = chrdevs[major(dev)].name;
 
 	if (!name)
 		name = "unknown-char";
-	sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
+	sprintf(buffer, "%s(%d,%d)", name, major(dev), minor(dev));
 	return buffer;
 }
   
diff -u --recursive --new-file v2.5.1/linux/fs/dquot.c linux/fs/dquot.c
--- v2.5.1/linux/fs/dquot.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/dquot.c	Thu Jan  3 12:20:18 2002
@@ -136,14 +136,14 @@
 	return is_enabled(sb_dqopt(sb), type);
 }
 
-static inline int const hashfn(kdev_t dev, unsigned int id, short type)
+static inline int const hashfn(struct super_block *sb, unsigned int id, short type)
 {
-	return((HASHDEV(dev) ^ id) * (MAXQUOTAS - type)) % NR_DQHASH;
+	return((HASHDEV(sb->s_dev) ^ id) * (MAXQUOTAS - type)) % NR_DQHASH;
 }
 
 static inline void insert_dquot_hash(struct dquot *dquot)
 {
-	struct list_head *head = dquot_hash + hashfn(dquot->dq_dev, dquot->dq_id, dquot->dq_type);
+	struct list_head *head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id, dquot->dq_type);
 	list_add(&dquot->dq_hash, head);
 }
 
@@ -153,14 +153,14 @@
 	INIT_LIST_HEAD(&dquot->dq_hash);
 }
 
-static inline struct dquot *find_dquot(unsigned int hashent, kdev_t dev, unsigned int id, short type)
+static inline struct dquot *find_dquot(unsigned int hashent, struct super_block *sb, unsigned int id, short type)
 {
 	struct list_head *head;
 	struct dquot *dquot;
 
 	for (head = dquot_hash[hashent].next; head != dquot_hash+hashent; head = head->next) {
 		dquot = list_entry(head, struct dquot, dq_hash);
-		if (dquot->dq_dev == dev && dquot->dq_id == id && dquot->dq_type == type)
+		if (dquot->dq_sb == sb && dquot->dq_id == id && dquot->dq_type == type)
 			return dquot;
 	}
 	return NODQUOT;
@@ -289,7 +289,7 @@
 					sizeof(struct dqblk), &offset);
 	if (ret != sizeof(struct dqblk))
 		printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
-			kdevname(dquot->dq_dev));
+			kdevname(dquot->dq_sb->s_dev));
 
 	set_fs(fs);
 	up(sem);
@@ -359,7 +359,7 @@
 	}
 }
 
-int sync_dquots(kdev_t dev, short type)
+int sync_dquots(struct super_block *sb, short type)
 {
 	struct list_head *head;
 	struct dquot *dquot;
@@ -368,7 +368,7 @@
 restart:
 	for (head = inuse_list.next; head != &inuse_list; head = head->next) {
 		dquot = list_entry(head, struct dquot, dq_inuse);
-		if (dev && dquot->dq_dev != dev)
+		if (sb && dquot->dq_sb != sb)
 			continue;
                 if (type != -1 && dquot->dq_type != type)
 			continue;
@@ -440,7 +440,8 @@
 	if (!dquot->dq_count) {
 		printk("VFS: dqput: trying to free free dquot\n");
 		printk("VFS: device %s, dquot of %s %d\n",
-			kdevname(dquot->dq_dev), quotatypes[dquot->dq_type],
+			kdevname(dquot->dq_sb->s_dev),
+			quotatypes[dquot->dq_type],
 			dquot->dq_id);
 		return;
 	}
@@ -493,7 +494,7 @@
 
 static struct dquot *dqget(struct super_block *sb, unsigned int id, short type)
 {
-	unsigned int hashent = hashfn(sb->s_dev, id, type);
+	unsigned int hashent = hashfn(sb, id, type);
 	struct dquot *dquot, *empty = NODQUOT;
 	struct quota_mount_options *dqopt = sb_dqopt(sb);
 
@@ -504,7 +505,7 @@
                 return NODQUOT;
 	}
 
-	if ((dquot = find_dquot(hashent, sb->s_dev, id, type)) == NODQUOT) {
+	if ((dquot = find_dquot(hashent, sb, id, type)) == NODQUOT) {
 		if (empty == NODQUOT) {
 			if ((empty = get_empty_dquot()) == NODQUOT)
 				schedule();	/* Try to wait for a moment... */
@@ -513,7 +514,6 @@
 		dquot = empty;
         	dquot->dq_id = id;
         	dquot->dq_type = type;
-        	dquot->dq_dev = sb->s_dev;
         	dquot->dq_sb = sb;
 		/* hash it first so it can be found */
 		insert_dquot_hash(dquot);
@@ -1471,7 +1471,7 @@
 			flags |= SET_QLIMIT;
 			break;
 		case Q_SYNC:
-			ret = sync_dquots(dev, type);
+			ret = sync_dquots(sb, type);
 			goto out;
 		case Q_GETSTATS:
 			ret = get_stats(addr);
@@ -1483,7 +1483,7 @@
 			goto out;
 	}
 
-	ret = -NODEV;
+	ret = -ENODEV;
 	if (sb && sb_has_quota_enabled(sb, type))
 		ret = set_dqblk(sb, id, type, flags, (struct dqblk *) addr);
 out:
diff -u --recursive --new-file v2.5.1/linux/fs/efs/file.c linux/fs/efs/file.c
--- v2.5.1/linux/fs/efs/file.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/efs/file.c	Thu Dec 27 08:17:43 2001
@@ -29,11 +29,8 @@
 		return 0;
 	}
 	phys = efs_map_block(inode, iblock);
-	if (phys) {
-		bh_result->b_dev = inode->i_dev;
-		bh_result->b_blocknr = phys;
-		bh_result->b_state |= (1UL << BH_Mapped);
-	}
+	if (phys)
+		map_bh(bh_result, inode->i_sb, phys);
 	return 0;
 }
 
diff -u --recursive --new-file v2.5.1/linux/fs/efs/super.c linux/fs/efs/super.c
--- v2.5.1/linux/fs/efs/super.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/efs/super.c	Tue Dec 25 15:39:20 2001
@@ -132,16 +132,13 @@
 }
 
 struct super_block *efs_read_super(struct super_block *s, void *d, int silent) {
-	kdev_t dev = s->s_dev;
 	struct efs_sb_info *sb;
 	struct buffer_head *bh;
 
  	sb = SUPER_INFO(s);
  
 	s->s_magic		= EFS_SUPER_MAGIC;
-	s->s_blocksize		= EFS_BLOCKSIZE;
-	s->s_blocksize_bits	= EFS_BLOCKSIZE_BITS;
-	set_blocksize(dev, EFS_BLOCKSIZE);
+	sb_set_blocksize(s, EFS_BLOCKSIZE);
   
 	/* read the vh (volume header) block */
 	bh = sb_bread(s, 0);
diff -u --recursive --new-file v2.5.1/linux/fs/exec.c linux/fs/exec.c
--- v2.5.1/linux/fs/exec.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/exec.c	Sun Dec 30 10:51:45 2001
@@ -973,9 +973,7 @@
 	if (do_truncate(file->f_dentry, 0) != 0)
 		goto close_fail;
 
-	down_read(&current->mm->mmap_sem);
 	retval = binfmt->core_dump(signr, regs, file);
-	up_read(&current->mm->mmap_sem);
 
 close_fail:
 	filp_close(file, NULL);
diff -u --recursive --new-file v2.5.1/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c
--- v2.5.1/linux/fs/ext2/ialloc.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/ext2/ialloc.c	Sun Dec 30 10:53:53 2001
@@ -393,7 +393,7 @@
 	if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
 		inode->i_flags |= S_SYNC;
 	insert_inode_hash(inode);
-	inode->i_generation = event++;
+	inode->i_generation = sb->u.ext2_sb.s_next_generation++;
 	mark_inode_dirty(inode);
 
 	unlock_super (sb);
diff -u --recursive --new-file v2.5.1/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- v2.5.1/linux/fs/ext2/inode.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/ext2/inode.c	Thu Dec 27 08:17:43 2001
@@ -524,9 +524,7 @@
 	/* Simplest case - block found, no allocation needed */
 	if (!partial) {
 got_it:
-		bh_result->b_dev = inode->i_dev;
-		bh_result->b_blocknr = le32_to_cpu(chain[depth-1].key);
-		bh_result->b_state |= (1UL << BH_Mapped);
+		map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key));
 		/* Clean up and exit */
 		partial = chain+depth-1; /* the whole chain */
 		goto cleanup;
diff -u --recursive --new-file v2.5.1/linux/fs/ext2/super.c linux/fs/ext2/super.c
--- v2.5.1/linux/fs/ext2/super.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/ext2/super.c	Sun Dec 30 16:58:51 2001
@@ -25,9 +25,12 @@
 #include <linux/init.h>
 #include <linux/locks.h>
 #include <linux/blkdev.h>
+#include <linux/random.h>
 #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 +38,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 +127,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 +310,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",
@@ -418,9 +420,6 @@
 	 * This is important for devices that have a hardware
 	 * sectorsize that is larger than the default.
 	 */
-	blocksize = get_hardsect_size(dev);
-	if(blocksize < BLOCK_SIZE )
-	    blocksize = BLOCK_SIZE;
 
 	sb->u.ext2_sb.s_mount_opt = 0;
 	if (!parse_options ((char *) data, &sb_block, &resuid, &resgid,
@@ -428,11 +427,11 @@
 		return NULL;
 	}
 
-	if (set_blocksize(dev, blocksize) < 0) {
-		printk ("EXT2-fs: unable to set blocksize %d\n", blocksize);
+	blocksize = sb_min_blocksize(sb, BLOCK_SIZE);
+	if (!blocksize) {
+		printk ("EXT2-fs: unable to set blocksize\n");
 		return NULL;
 	}
-	sb->s_blocksize = blocksize;
 
 	/*
 	 * If the superblock doesn't start on a sector boundary,
@@ -485,18 +484,12 @@
 		       bdevname(dev), i);
 		goto failed_mount;
 	}
-	sb->s_blocksize_bits =
-		le32_to_cpu(EXT2_SB(sb)->s_es->s_log_block_size) + 10;
-	sb->s_blocksize = 1 << sb->s_blocksize_bits;
-
-	sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits);
-
+	blocksize = BLOCK_SIZE << le32_to_cpu(EXT2_SB(sb)->s_es->s_log_block_size);
 	/* If the blocksize doesn't match, re-read the thing.. */
 	if (sb->s_blocksize != blocksize) {
-		blocksize = sb->s_blocksize;
 		brelse(bh);
 
-		if (set_blocksize(dev, blocksize) < 0) {
+		if (!sb_set_blocksize(sb, blocksize)) {
 			printk(KERN_ERR "EXT2-fs: blocksize too small for device.\n");
 			return NULL;
 		}
@@ -517,6 +510,8 @@
 		}
 	}
 
+	sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits);
+
 	if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) {
 		sb->u.ext2_sb.s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
 		sb->u.ext2_sb.s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
@@ -630,6 +625,7 @@
 	sb->u.ext2_sb.s_loaded_inode_bitmaps = 0;
 	sb->u.ext2_sb.s_loaded_block_bitmaps = 0;
 	sb->u.ext2_sb.s_gdb_count = db_count;
+	get_random_bytes(&sb->u.ext2_sb.s_next_generation, sizeof(u32));
 	/*
 	 * set up enough so that it can read an inode
 	 */
@@ -664,6 +660,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 +687,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 +731,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 +749,7 @@
 		if (!ext2_setup_super (sb, es, 0))
 			sb->s_flags &= ~MS_RDONLY;
 	}
+	ext2_sync_super(sb, es);
 	return 0;
 }
 
diff -u --recursive --new-file v2.5.1/linux/fs/ext3/Makefile linux/fs/ext3/Makefile
--- v2.5.1/linux/fs/ext3/Makefile	Fri Nov  9 14:25:04 2001
+++ linux/fs/ext3/Makefile	Sun Dec 30 16:58:52 2001
@@ -9,7 +9,7 @@
 
 O_TARGET := ext3.o
 
-obj-y    := acl.o balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
+obj-y    := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
 		ioctl.o namei.o super.o symlink.o
 obj-m    := $(O_TARGET)
 
diff -u --recursive --new-file v2.5.1/linux/fs/ext3/acl.c linux/fs/ext3/acl.c
--- v2.5.1/linux/fs/ext3/acl.c	Fri Nov  9 14:25:04 2001
+++ linux/fs/ext3/acl.c	Wed Dec 31 16:00:00 1969
@@ -1,17 +0,0 @@
-/*
- * linux/fs/ext3/acl.c
- *
- * Copyright (C) 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- */
-
-#include <linux/fs.h>
-#include <linux/sched.h>
-
-
-/*
- * This file will contain the Access Control Lists management for the
- * second extended file system.
- */
diff -u --recursive --new-file v2.5.1/linux/fs/ext3/ialloc.c linux/fs/ext3/ialloc.c
--- v2.5.1/linux/fs/ext3/ialloc.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/ext3/ialloc.c	Thu Jan  3 12:20:18 2002
@@ -189,7 +189,7 @@
 	struct ext3_super_block * es;
 	int fatal = 0, err;
 
-	if (!inode->i_dev) {
+	if (kdev_none(inode->i_dev)) {
 		printk ("ext3_free_inode: inode has no device\n");
 		return;
 	}
diff -u --recursive --new-file v2.5.1/linux/fs/ext3/inode.c linux/fs/ext3/inode.c
--- v2.5.1/linux/fs/ext3/inode.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/ext3/inode.c	Sun Dec 30 16:58:52 2001
@@ -32,7 +32,6 @@
 #include <linux/quotaops.h>
 #include <linux/module.h>
 
-
 /*
  * SEARCH_FROM_ZERO forces each block allocation to search from the start
  * of the filesystem.  This is to force rapid reallocation of recently-freed
@@ -715,6 +714,8 @@
  * reachable from inode.
  *
  * akpm: `handle' can be NULL if create == 0.
+ *
+ * The BKL may not be held on entry here.  Be sure to take it early.
  */
 
 static int ext3_get_block_handle(handle_t *handle, struct inode *inode, 
@@ -743,9 +744,7 @@
 	if (!partial) {
 		bh_result->b_state &= ~(1UL << BH_New);
 got_it:
-		bh_result->b_dev = inode->i_dev;
-		bh_result->b_blocknr = le32_to_cpu(chain[depth-1].key);
-		bh_result->b_state |= (1UL << BH_Mapped);
+		map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key));
 		/* Clean up and exit */
 		partial = chain+depth-1; /* the whole chain */
 		goto cleanup;
@@ -1020,13 +1019,26 @@
 		ret = PTR_ERR(handle);
 		goto out;
 	}
+	unlock_kernel();
 	ret = block_prepare_write(page, from, to, ext3_get_block);
+	lock_kernel();
 	if (ret != 0)
 		goto prepare_write_failed;
 
-	if (ext3_should_journal_data(inode))
+	if (ext3_should_journal_data(inode)) {
 		ret = walk_page_buffers(handle, page->buffers,
 				from, to, NULL, do_journal_get_write_access);
+		if (ret) {
+			/*
+			 * We're going to fail this prepare_write(),
+			 * so commit_write() will not be called.
+			 * We need to undo block_prepare_write()'s kmap().
+			 * AKPM: Do we need to clear PageUptodate?  I don't
+			 * think so.
+			 */
+			kunmap(page);
+		}
+	}
 prepare_write_failed:
 	if (ret)
 		ext3_journal_stop(handle, inode);
@@ -1094,7 +1106,7 @@
 		kunmap(page);
 		if (pos > inode->i_size)
 			inode->i_size = pos;
-		set_bit(EXT3_STATE_JDATA, &inode->u.ext3_i.i_state);
+		EXT3_I(inode)->i_state |= EXT3_STATE_JDATA;
 	} else {
 		if (ext3_should_order_data(inode)) {
 			ret = walk_page_buffers(handle, page->buffers,
@@ -1102,8 +1114,17 @@
 		}
 		/* Be careful here if generic_commit_write becomes a
 		 * required invocation after block_prepare_write. */
-		if (ret == 0)
+		if (ret == 0) {
 			ret = generic_commit_write(file, page, from, to);
+		} else {
+			/*
+			 * block_prepare_write() was called, but we're not
+			 * going to call generic_commit_write().  So we
+			 * need to perform generic_commit_write()'s kunmap
+			 * by hand.
+			 */
+			kunmap(page);
+		}
 	}
 	if (inode->i_size > inode->u.ext3_i.i_disksize) {
 		inode->u.ext3_i.i_disksize = inode->i_size;
@@ -1138,7 +1159,7 @@
 	journal_t *journal;
 	int err;
 	
-	if (test_and_clear_bit(EXT3_STATE_JDATA, &inode->u.ext3_i.i_state)) {
+	if (EXT3_I(inode)->i_state & EXT3_STATE_JDATA) {
 		/* 
 		 * This is a REALLY heavyweight approach, but the use of
 		 * bmap on dirty files is expected to be extremely rare:
@@ -1157,6 +1178,7 @@
 		 * everything they get.
 		 */
 		
+		EXT3_I(inode)->i_state &= ~EXT3_STATE_JDATA;
 		journal = EXT3_JOURNAL(inode);
 		journal_lock_updates(journal);
 		err = journal_flush(journal);
@@ -1265,8 +1287,7 @@
 	/* bget() all the buffers */
 	if (order_data) {
 		if (!page->buffers)
-			create_empty_buffers(page,
-				inode->i_dev, inode->i_sb->s_blocksize);
+			create_empty_buffers(page, inode->i_sb->s_blocksize);
 		page_buffers = page->buffers;
 		walk_page_buffers(handle, page_buffers, 0,
 				PAGE_CACHE_SIZE, NULL, bget_one);
@@ -1369,7 +1390,7 @@
 		goto out;
 
 	if (!page->buffers)
-		create_empty_buffers(page, inode->i_dev, blocksize);
+		create_empty_buffers(page, blocksize);
 
 	/* Find the buffer that contains "offset" */
 	bh = page->buffers;
@@ -2198,7 +2219,7 @@
 	/* If we are not tracking these fields in the in-memory inode,
 	 * then preserve them on disk, but still initialise them to zero
 	 * for new inodes. */
-	if (inode->u.ext3_i.i_state & EXT3_STATE_NEW) {
+	if (EXT3_I(inode)->i_state & EXT3_STATE_NEW) {
 		raw_inode->i_faddr = 0;
 		raw_inode->i_frag = 0;
 		raw_inode->i_fsize = 0;
@@ -2244,7 +2265,7 @@
 	rc = ext3_journal_dirty_metadata(handle, bh);
 	if (!err)
 		err = rc;
-	inode->u.ext3_i.i_state &= ~EXT3_STATE_NEW;
+	EXT3_I(inode)->i_state &= ~EXT3_STATE_NEW;
 
 out_brelse:
 	brelse (bh);
@@ -2328,12 +2349,20 @@
 int ext3_setattr(struct dentry *dentry, struct iattr *attr)
 {
 	struct inode *inode = dentry->d_inode;
-	int error, rc;
+	int error, rc = 0;
+	const unsigned int ia_valid = attr->ia_valid;
 
 	error = inode_change_ok(inode, attr);
 	if (error)
 		return error;
-	
+
+	if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
+		(ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
+		error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
+		if (error)
+			return error;
+	}
+
 	if (attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) {
 		handle_t *handle;
 
@@ -2351,7 +2380,7 @@
 		ext3_journal_stop(handle, inode);
 	}
 	
-	inode_setattr(inode, attr);
+	rc = inode_setattr(inode, attr);
 
 	/* If inode_setattr's call to ext3_truncate failed to get a
 	 * transaction handle at all, we need to clean up the in-core
@@ -2361,7 +2390,9 @@
 
 err_out:
 	ext3_std_error(inode->i_sb, error);
-	return 0;
+	if (!error)
+		error = rc;
+	return error;
 }
 
 
@@ -2662,6 +2693,3 @@
  * here, in ext3_aops_journal_start() to ensure that the forthcoming "see if we
  * need to extend" test in ext3_prepare_write() succeeds.  
  */
-
-
-MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/ext3/super.c linux/fs/ext3/super.c
--- v2.5.1/linux/fs/ext3/super.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/ext3/super.c	Thu Jan  3 12:20:18 2002
@@ -389,8 +389,8 @@
 	list_for_each(l, &sbi->s_orphan) {
 		struct inode *inode = orphan_list_entry(l);
 		printk(KERN_ERR "  "
-		       "inode 0x%04x:%ld at %p: mode %o, nlink %d, next %d\n",
-		       inode->i_dev, inode->i_ino, inode,
+		       "inode 0x%04x.0x%04x:%ld at %p: mode %o, nlink %d, next %d\n",
+		       major(inode->i_dev), minor(inode->i_dev), inode->i_ino, inode,
 		       inode->i_mode, inode->i_nlink, 
 		       le32_to_cpu(NEXT_ORPHAN(inode)));
 	}
@@ -430,7 +430,7 @@
 	J_ASSERT(list_empty(&sbi->s_orphan));
 
 	invalidate_buffers(sb->s_dev);
-	if (j_dev != sb->s_dev) {
+	if (!kdev_same(j_dev, sb->s_dev)) {
 		/*
 		 * Invalidate the journal device's buffers.  We don't want them
 		 * floating about in memory - the physical journal device may
@@ -912,21 +912,16 @@
 	 * This is important for devices that have a hardware
 	 * sectorsize that is larger than the default.
 	 */
-	blocksize = EXT3_MIN_BLOCK_SIZE;
-	hblock = get_hardsect_size(dev);
-	if (blocksize < hblock)
-		blocksize = hblock;
 
 	sbi->s_mount_opt = 0;
 	sbi->s_resuid = EXT3_DEF_RESUID;
 	sbi->s_resgid = EXT3_DEF_RESGID;
 	if (!parse_options ((char *) data, &sb_block, sbi, &journal_inum, 0)) {
-		sb->s_dev = 0;
+		sb->s_dev = NODEV;
 		goto out_fail;
 	}
 
-	sb->s_blocksize = blocksize;
-	set_blocksize (dev, blocksize);
+	blocksize = sb_min_blocksize(sb, EXT3_MIN_BLOCK_SIZE);
 
 	/*
 	 * The ext3 superblock will not be buffer aligned for other than 1kB
@@ -980,11 +975,10 @@
 		       bdevname(dev), i);
 		goto failed_mount;
 	}
-	sb->s_blocksize_bits = le32_to_cpu(es->s_log_block_size) + 10;
-	sb->s_blocksize = 1 << sb->s_blocksize_bits;
+	blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size);
 
-	if (sb->s_blocksize < EXT3_MIN_BLOCK_SIZE ||
-	    sb->s_blocksize > EXT3_MAX_BLOCK_SIZE) {
+	if (blocksize < EXT3_MIN_BLOCK_SIZE ||
+	    blocksize > EXT3_MAX_BLOCK_SIZE) {
 		printk(KERN_ERR 
 		       "EXT3-fs: Unsupported filesystem blocksize %d on %s.\n",
 		       blocksize, bdevname(dev));
@@ -993,21 +987,20 @@
 
 	sb->s_maxbytes = ext3_max_size(sb->s_blocksize_bits);
 
+	hblock = get_hardsect_size(dev);
 	if (sb->s_blocksize != blocksize) {
-		blocksize = sb->s_blocksize;
-
 		/*
 		 * Make sure the blocksize for the filesystem is larger
 		 * than the hardware sectorsize for the machine.
 		 */
-		if (sb->s_blocksize < hblock) {
+		if (blocksize < hblock) {
 			printk(KERN_ERR "EXT3-fs: blocksize %d too small for "
 			       "device blocksize %d.\n", blocksize, hblock);
 			goto failed_mount;
 		}
 
 		brelse (bh);
-		set_blocksize (dev, sb->s_blocksize);
+		sb_set_blocksize(sb, blocksize);
 		logic_sb_block = (sb_block * EXT3_MIN_BLOCK_SIZE) / blocksize;
 		offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize;
 		bh = sb_bread(sb, logic_sb_block);
@@ -1257,13 +1250,16 @@
 	}
 
 	journal = journal_init_inode(journal_inode);
-	if (!journal)
+	if (!journal) {
+		printk(KERN_ERR "EXT3-fs: Could not load journal inode\n");
 		iput(journal_inode);
+	}
+	
 	return journal;
 }
 
 static journal_t *ext3_get_dev_journal(struct super_block *sb,
-				       int dev)
+				       kdev_t j_dev)
 {
 	struct buffer_head * bh;
 	journal_t *journal;
@@ -1272,16 +1268,15 @@
 	int hblock, blocksize;
 	unsigned long sb_block;
 	unsigned long offset;
-	kdev_t journal_dev = to_kdev_t(dev);
 	struct ext3_super_block * es;
 	struct block_device *bdev;
 
-	bdev = ext3_blkdev_get(journal_dev);
+	bdev = ext3_blkdev_get(j_dev);
 	if (bdev == NULL)
 		return NULL;
 
 	blocksize = sb->s_blocksize;
-	hblock = get_hardsect_size(journal_dev);
+	hblock = get_hardsect_size(j_dev);
 	if (blocksize < hblock) {
 		printk(KERN_ERR
 			"EXT3-fs: blocksize too small for journal device.\n");
@@ -1290,8 +1285,8 @@
 	
 	sb_block = EXT3_MIN_BLOCK_SIZE / blocksize;
 	offset = EXT3_MIN_BLOCK_SIZE % blocksize;
-	set_blocksize(dev, blocksize);
-	if (!(bh = bread(dev, sb_block, blocksize))) {
+	set_blocksize(j_dev, blocksize);
+	if (!(bh = bread(j_dev, sb_block, blocksize))) {
 		printk(KERN_ERR "EXT3-fs: couldn't read superblock of "
 		       "external journal\n");
 		goto out_bdev;
@@ -1317,7 +1312,7 @@
 	start = sb_block + 1;
 	brelse(bh);	/* we're done with the superblock */
 
-	journal = journal_init_dev(journal_dev, sb->s_dev, 
+	journal = journal_init_dev(j_dev, sb->s_dev,
 					start, len, blocksize);
 	if (!journal) {
 		printk(KERN_ERR "EXT3-fs: failed to create device journal\n");
@@ -1349,8 +1344,8 @@
 {
 	journal_t *journal;
 	int journal_inum = le32_to_cpu(es->s_journal_inum);
-	int journal_dev = le32_to_cpu(es->s_journal_dev);
-	int err;
+	kdev_t journal_dev = to_kdev_t(le32_to_cpu(es->s_journal_dev));
+	int err = 0;
 	int really_read_only;
 
 	really_read_only = is_read_only(sb->s_dev);
@@ -1375,7 +1370,7 @@
 		}
 	}
 
-	if (journal_inum && journal_dev) {
+	if (journal_inum && !kdev_none(journal_dev)) {
 		printk(KERN_ERR "EXT3-fs: filesystem has both journal "
 		       "and inode journals!\n");
 		return -EINVAL;
@@ -1400,9 +1395,10 @@
 	}
 
 	if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER))
-		journal_wipe(journal, !really_read_only);
+		err = journal_wipe(journal, !really_read_only);
+	if (!err)
+		err = journal_load(journal);
 
-	err = journal_load(journal);
 	if (err) {
 		printk(KERN_ERR "EXT3-fs: error loading journal.\n");
 		journal_destroy(journal);
@@ -1740,6 +1736,8 @@
 
 EXPORT_NO_SYMBOLS;
 
+MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
+MODULE_DESCRIPTION("Second Extended Filesystem with journaling extensions");
 MODULE_LICENSE("GPL");
 module_init(init_ext3_fs)
 module_exit(exit_ext3_fs)
diff -u --recursive --new-file v2.5.1/linux/fs/fat/cache.c linux/fs/fat/cache.c
--- v2.5.1/linux/fs/fat/cache.c	Fri Oct 12 13:48:42 2001
+++ linux/fs/fat/cache.c	Thu Dec 27 08:17:43 2001
@@ -144,7 +144,7 @@
 	}
 	fat_cache = &cache[0];
 	for (count = 0; count < FAT_CACHE; count++) {
-		cache[count].device = 0;
+		cache[count].sb = NULL;
 		cache[count].next = count == FAT_CACHE-1 ? NULL :
 		    &cache[count+1];
 	}
@@ -162,7 +162,7 @@
 		return;
 	spin_lock(&fat_cache_lock);
 	for (walk = fat_cache; walk; walk = walk->next)
-		if (inode->i_dev == walk->device
+		if (inode->i_sb == walk->sb
 		    && walk->start_cluster == first
 		    && walk->file_cluster <= cluster
 		    && walk->file_cluster > *f_clu) {
@@ -188,8 +188,8 @@
 	struct fat_cache *walk;
 
 	for (walk = fat_cache; walk; walk = walk->next) {
-		if (walk->device)
-			printk("<%s,%d>(%d,%d) ", kdevname(walk->device),
+		if (walk->sb)
+			printk("<%s,%d>(%d,%d) ", bdevname(walk->sb->s_dev),
 			       walk->start_cluster, walk->file_cluster,
 			       walk->disk_cluster);
 		else printk("-- ");
@@ -207,7 +207,7 @@
 	last = NULL;
 	spin_lock(&fat_cache_lock);
 	for (walk = fat_cache; walk->next; walk = (last = walk)->next)
-		if (inode->i_dev == walk->device
+		if (inode->i_sb == walk->sb
 		    && walk->start_cluster == first
 		    && walk->file_cluster == f_clu) {
 			if (walk->disk_cluster != d_clu) {
@@ -231,7 +231,7 @@
 			spin_unlock(&fat_cache_lock);
 			return;
 		}
-	walk->device = inode->i_dev;
+	walk->sb = inode->i_sb;
 	walk->start_cluster = first;
 	walk->file_cluster = f_clu;
 	walk->disk_cluster = d_clu;
@@ -255,21 +255,21 @@
 
 	spin_lock(&fat_cache_lock);
 	for (walk = fat_cache; walk; walk = walk->next)
-		if (walk->device == inode->i_dev
+		if (walk->sb == inode->i_sb
 		    && walk->start_cluster == first)
-			walk->device = 0;
+			walk->sb = NULL;
 	spin_unlock(&fat_cache_lock);
 }
 
 
-void fat_cache_inval_dev(kdev_t device)
+void fat_cache_inval_dev(struct super_block *sb)
 {
 	struct fat_cache *walk;
 
 	spin_lock(&fat_cache_lock);
 	for (walk = fat_cache; walk; walk = walk->next)
-		if (walk->device == device)
-			walk->device = 0;
+		if (walk->sb == sb)
+			walk->sb = 0;
 	spin_unlock(&fat_cache_lock);
 }
 
diff -u --recursive --new-file v2.5.1/linux/fs/fat/file.c linux/fs/fat/file.c
--- v2.5.1/linux/fs/fat/file.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/fat/file.c	Thu Dec 27 08:17:43 2001
@@ -55,9 +55,7 @@
 
 	phys = fat_bmap(inode, iblock);
 	if (phys) {
-		bh_result->b_dev = inode->i_dev;
-		bh_result->b_blocknr = phys;
-		bh_result->b_state |= (1UL << BH_Mapped);
+		map_bh(bh_result, inode->i_sb, phys);
 		return 0;
 	}
 	if (!create)
@@ -74,10 +72,8 @@
 	phys = fat_bmap(inode, iblock);
 	if (!phys)
 		BUG();
-	bh_result->b_dev = inode->i_dev;
-	bh_result->b_blocknr = phys;
-	bh_result->b_state |= (1UL << BH_Mapped);
 	bh_result->b_state |= (1UL << BH_New);
+	map_bh(bh_result, inode->i_sb, phys);
 	return 0;
 }
 
diff -u --recursive --new-file v2.5.1/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v2.5.1/linux/fs/fat/inode.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/fat/inode.c	Sun Dec 30 10:53:53 2001
@@ -146,6 +146,7 @@
 		goto out;
 	*res = 0;
 	inode->i_ino = iunique(sb, MSDOS_ROOT_INO);
+	inode->i_version = 0;
 	fat_fill_inode(inode, de);
 	fat_attach(inode, ino);
 	insert_inode_hash(inode);
@@ -185,7 +186,7 @@
 	if (MSDOS_SB(sb)->fat_bits == 32) {
 		fat_clusters_flush(sb);
 	}
-	fat_cache_inval_dev(sb->s_dev);
+	fat_cache_inval_dev(sb);
 	set_blocksize (sb->s_dev,BLOCK_SIZE);
 	if (MSDOS_SB(sb)->nls_disk) {
 		unload_nls(MSDOS_SB(sb)->nls_disk);
@@ -383,7 +384,7 @@
 	MSDOS_I(inode)->i_fat_inode = inode;
 	inode->i_uid = sbi->options.fs_uid;
 	inode->i_gid = sbi->options.fs_gid;
-	inode->i_version = ++event;
+	inode->i_version++;
 	inode->i_generation = 0;
 	inode->i_mode = (S_IRWXUGO & ~sbi->options.fs_umask) | S_IFDIR;
 	inode->i_op = sbi->dir_ops;
@@ -569,10 +570,6 @@
 	sb->s_maxbytes = MAX_NON_LFS;
 	sb->s_op = &fat_sops;
 
-	hard_blksize = get_hardsect_size(sb->s_dev);
-	if (!hard_blksize)
-		hard_blksize = 512;
-
 	opts.isvfat = sbi->options.isvfat;
 	if (!parse_options((char *) data, &fat, &debug, &opts,
 			   cvf_format, cvf_options))
@@ -582,8 +579,7 @@
 
 	fat_cache_init();
 
-	sb->s_blocksize = hard_blksize;
-	set_blocksize(sb->s_dev, hard_blksize);
+	sb_min_blocksize(sb, 512);
 	bh = sb_bread(sb, 0);
 	if (bh == NULL) {
 		printk("FAT: unable to read boot sector\n");
@@ -625,13 +621,15 @@
 		goto out_invalid;
 	}
 
-	if (logical_sector_size < hard_blksize) {
+	if (logical_sector_size < sb->s_blocksize) {
 		printk("FAT: logical sector size too small for device"
 		       " (logical sector size = %d)\n", logical_sector_size);
 		brelse(bh);
 		goto out_invalid;
 	}
 
+	hard_blksize = sb->s_blocksize;
+
 	sbi->cluster_bits = ffs(logical_sector_size * sbi->cluster_size) - 1;
 	sbi->fats = b->fats;
 	sbi->fat_start = CF_LE_W(b->reserved);
@@ -716,9 +714,7 @@
 	if (error)
 		goto out_invalid;
 
-	sb->s_blocksize = logical_sector_size;
-	sb->s_blocksize_bits = ffs(logical_sector_size) - 1;
-	set_blocksize(sb->s_dev, sb->s_blocksize);
+	sb_set_blocksize(sb, logical_sector_size);
 	sbi->cvf_format = &default_cvf;
 	if (!strcmp(cvf_format, "none"))
 		i = -1;
@@ -781,6 +777,7 @@
 	if (!root_inode)
 		goto out_unload_nls;
 	root_inode->i_ino = MSDOS_ROOT_INO;
+	root_inode->i_version = 0;
 	fat_read_root(root_inode);
 	insert_inode_hash(root_inode);
 	sb->s_root = d_alloc_root(root_inode);
@@ -802,7 +799,7 @@
 out_invalid:
 	if (!silent) {
 		printk("VFS: Can't find a valid FAT filesystem on dev %s.\n",
-			kdevname(sb->s_dev));
+			bdevname(sb->s_dev));
 	}
 out_fail:
 	if (opts.iocharset) {
@@ -892,7 +889,7 @@
 	MSDOS_I(inode)->i_fat_inode = inode;
 	inode->i_uid = sbi->options.fs_uid;
 	inode->i_gid = sbi->options.fs_gid;
-	inode->i_version = ++event;
+	inode->i_version++;
 	inode->i_generation = CURRENT_TIME;
 	
 	if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) {
diff -u --recursive --new-file v2.5.1/linux/fs/freevxfs/vxfs_inode.c linux/fs/freevxfs/vxfs_inode.c
--- v2.5.1/linux/fs/freevxfs/vxfs_inode.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/freevxfs/vxfs_inode.c	Sat Dec 29 17:30:07 2001
@@ -35,6 +35,7 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/pagemap.h>
 
 #include "vxfs.h"
 #include "vxfs_inode.h"
diff -u --recursive --new-file v2.5.1/linux/fs/freevxfs/vxfs_subr.c linux/fs/freevxfs/vxfs_subr.c
--- v2.5.1/linux/fs/freevxfs/vxfs_subr.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/freevxfs/vxfs_subr.c	Thu Dec 27 08:17:43 2001
@@ -142,10 +142,7 @@
 
 	pblock = vxfs_bmap1(ip, iblock);
 	if (pblock != 0) {
-		bp->b_dev = ip->i_dev;
-		bp->b_blocknr = pblock;
-		bp->b_state |= (1UL << BH_Mapped);
-
+		map_bh(bp, ip->i_sb, pblock);
 		return 0;
 	}
 
diff -u --recursive --new-file v2.5.1/linux/fs/hfs/dir.c linux/fs/hfs/dir.c
--- v2.5.1/linux/fs/hfs/dir.c	Tue Feb 13 14:13:45 2001
+++ linux/fs/hfs/dir.c	Sun Dec 30 10:53:53 2001
@@ -69,8 +69,8 @@
 /*
  * update_dirs_plus()
  *
- * Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and
- * 'i_version' of the inodes associated with a directory that has
+ * Update the fields 'i_size', 'i_nlink', 'i_ctime' and 'i_mtime'
+ * of the inodes associated with a directory that has
  * had a file ('is_dir'==0) or directory ('is_dir'!=0) added to it.
  */
 static inline void update_dirs_plus(struct hfs_cat_entry *dir, int is_dir)
@@ -88,7 +88,6 @@
 					++(tmp->i_nlink);
 				}
 				tmp->i_size += HFS_I(tmp)->dir_size;
-				tmp->i_version = ++event;
 			}
 			tmp->i_ctime = tmp->i_mtime = CURRENT_TIME;
 			mark_inode_dirty(tmp);
@@ -100,7 +99,7 @@
  * update_dirs_minus()
  *
  * Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and
- * 'i_version' of the inodes associated with a directory that has
+ * of the inodes associated with a directory that has
  * had a file ('is_dir'==0) or directory ('is_dir'!=0) removed.
  */
 static inline void update_dirs_minus(struct hfs_cat_entry *dir, int is_dir)
@@ -118,7 +117,6 @@
 					--(tmp->i_nlink);
 				}
 				tmp->i_size -= HFS_I(tmp)->dir_size;
-				tmp->i_version = ++event;
 			}
 			tmp->i_ctime = tmp->i_mtime = CURRENT_TIME;
 			mark_inode_dirty(tmp);
diff -u --recursive --new-file v2.5.1/linux/fs/hfs/file.c linux/fs/hfs/file.c
--- v2.5.1/linux/fs/hfs/file.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/hfs/file.c	Thu Jan  3 13:59:50 2002
@@ -112,11 +112,9 @@
 
 	phys = hfs_extent_map(HFS_I(inode)->fork, iblock, create);
 	if (phys) {
-		bh_result->b_dev = inode->i_dev;
-		bh_result->b_blocknr = phys;
-		bh_result->b_state |= (1UL << BH_Mapped);
 		if (create)
 			bh_result->b_state |= (1UL << BH_New);
+		map_bh(bh_result, inode->i_sb, phys);
 		return 0;
 	}
 
@@ -312,8 +310,8 @@
 
 	bhb = bhe = buflist;
 	if (reada) {
-		if (blocks < read_ahead[MAJOR(dev)] / (HFS_SECTOR_SIZE>>9)) {
-			blocks = read_ahead[MAJOR(dev)] / (HFS_SECTOR_SIZE>>9);
+		if (blocks < read_ahead[major(dev)] / (HFS_SECTOR_SIZE>>9)) {
+			blocks = read_ahead[major(dev)] / (HFS_SECTOR_SIZE>>9);
 		}
 		if (block + blocks > size) {
 			blocks = size - block;
diff -u --recursive --new-file v2.5.1/linux/fs/hfs/file_cap.c linux/fs/hfs/file_cap.c
--- v2.5.1/linux/fs/hfs/file_cap.c	Mon Sep 10 07:31:25 2001
+++ linux/fs/hfs/file_cap.c	Sun Dec 30 10:53:53 2001
@@ -103,7 +103,6 @@
 		if (offset != file->f_pos) {
 			file->f_pos = offset;
 			file->f_reada = 0;
-			file->f_version = ++event;
 		}
 		retval = offset;
 	}
diff -u --recursive --new-file v2.5.1/linux/fs/hfs/file_hdr.c linux/fs/hfs/file_hdr.c
--- v2.5.1/linux/fs/hfs/file_hdr.c	Sun Aug 12 10:56:56 2001
+++ linux/fs/hfs/file_hdr.c	Sun Dec 30 10:53:53 2001
@@ -359,7 +359,6 @@
 		if (offset != file->f_pos) {
 			file->f_pos = offset;
 			file->f_reada = 0;
-			file->f_version = ++event;
 		}
 		retval = offset;
 	}
diff -u --recursive --new-file v2.5.1/linux/fs/hfs/super.c linux/fs/hfs/super.c
--- v2.5.1/linux/fs/hfs/super.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/hfs/super.c	Tue Dec 25 15:39:20 2001
@@ -401,9 +401,7 @@
 	}
 
 	/* set the device driver to 512-byte blocks */
-	set_blocksize(dev, HFS_SECTOR_SIZE);
-	s->s_blocksize_bits = HFS_SECTOR_SIZE_BITS;
-	s->s_blocksize = HFS_SECTOR_SIZE;
+	sb_set_blocksize(s, HFS_SECTOR_SIZE);
 
 #ifdef CONFIG_MAC_PARTITION
 	/* check to see if we're in a partition */
diff -u --recursive --new-file v2.5.1/linux/fs/hpfs/file.c linux/fs/hpfs/file.c
--- v2.5.1/linux/fs/hpfs/file.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/hpfs/file.c	Thu Dec 27 08:17:43 2001
@@ -73,9 +73,7 @@
 	secno s;
 	s = hpfs_bmap(inode, iblock);
 	if (s) {
-		bh_result->b_dev = inode->i_dev;
-		bh_result->b_blocknr = s;
-		bh_result->b_state |= (1UL << BH_Mapped);
+		map_bh(bh_result, inode->i_sb, s);
 		return 0;
 	}
 	if (!create) return 0;
@@ -89,9 +87,8 @@
 	}
 	inode->i_blocks++;
 	inode->u.hpfs_i.mmu_private += 512;
-	bh_result->b_dev = inode->i_dev;
-	bh_result->b_blocknr = s;
-	bh_result->b_state |= (1UL << BH_Mapped) | (1UL << BH_New);
+	bh_result->b_state |= 1UL << BH_New;
+	map_bh(bh_result, inode->i_sb, s);
 	return 0;
 }
 
diff -u --recursive --new-file v2.5.1/linux/fs/hpfs/hpfs_fn.h linux/fs/hpfs/hpfs_fn.h
--- v2.5.1/linux/fs/hpfs/hpfs_fn.h	Tue Dec 18 14:56:39 2001
+++ linux/fs/hpfs/hpfs_fn.h	Sun Dec 30 10:31:51 2001
@@ -19,7 +19,6 @@
 #include <linux/stat.h>
 #include <linux/string.h>
 #include <asm/bitops.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/smp_lock.h>
 
diff -u --recursive --new-file v2.5.1/linux/fs/hpfs/super.c linux/fs/hpfs/super.c
--- v2.5.1/linux/fs/hpfs/super.c	Thu Oct 25 00:02:26 2001
+++ linux/fs/hpfs/super.c	Tue Dec 25 15:39:20 2001
@@ -409,7 +409,7 @@
 
 	/*s->s_hpfs_mounting = 1;*/
 	dev = s->s_dev;
-	set_blocksize(dev, 512);
+	sb_set_blocksize(s, 512);
 	s->s_hpfs_fs_size = -1;
 	if (!(bootblock = hpfs_map_sector(s, 0, &bh0, 0))) goto bail1;
 	if (!(superblock = hpfs_map_sector(s, 16, &bh1, 1))) goto bail2;
@@ -436,8 +436,6 @@
 
 	/* Fill superblock stuff */
 	s->s_magic = HPFS_SUPER_MAGIC;
-	s->s_blocksize = 512;
-	s->s_blocksize_bits = 9;
 	s->s_op = &hpfs_sops;
 
 	s->s_hpfs_root = superblock->root;
diff -u --recursive --new-file v2.5.1/linux/fs/inflate_fs/inflate_syms.c linux/fs/inflate_fs/inflate_syms.c
--- v2.5.1/linux/fs/inflate_fs/inflate_syms.c	Thu Oct 25 13:53:53 2001
+++ linux/fs/inflate_fs/inflate_syms.c	Sun Dec 30 16:58:58 2001
@@ -19,3 +19,4 @@
 EXPORT_SYMBOL(zlib_fs_inflateReset);
 EXPORT_SYMBOL(zlib_fs_adler32);
 EXPORT_SYMBOL(zlib_fs_inflateSyncPoint);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/inode.c linux/fs/inode.c
--- v2.5.1/linux/fs/inode.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/inode.c	Tue Jan  1 13:14:00 2002
@@ -382,7 +382,7 @@
 	/*
 	 * Search the super_blocks array for the device(s) to sync.
 	 */
-	if (dev) {
+	if (!kdev_none(dev)) {
 		if ((s = get_super(dev)) != NULL) {
 			sync_inodes_sb(s);
 			drop_super(s);
@@ -826,7 +826,7 @@
 		inodes_stat.nr_inodes++;
 		list_add(&inode->i_list, &inode_in_use);
 		inode->i_sb = NULL;
-		inode->i_dev = 0;
+		inode->i_dev = NODEV;
 		inode->i_blkbits = 0;
 		inode->i_ino = ++last_ino;
 		inode->i_flags = 0;
diff -u --recursive --new-file v2.5.1/linux/fs/intermezzo/dcache.c linux/fs/intermezzo/dcache.c
--- v2.5.1/linux/fs/intermezzo/dcache.c	Tue Nov 13 09:20:56 2001
+++ linux/fs/intermezzo/dcache.c	Sun Dec 30 10:31:51 2001
@@ -16,7 +16,6 @@
 #include <linux/errno.h>
 #include <linux/locks.h>
 #include <linux/slab.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
 
diff -u --recursive --new-file v2.5.1/linux/fs/intermezzo/ext_attr.c linux/fs/intermezzo/ext_attr.c
--- v2.5.1/linux/fs/intermezzo/ext_attr.c	Sun Nov 11 10:20:21 2001
+++ linux/fs/intermezzo/ext_attr.c	Sun Dec 30 10:31:51 2001
@@ -28,7 +28,6 @@
 #include <asm/uaccess.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-#include <asm/segment.h>
 #include <linux/smp_lock.h>
 
 #include <linux/intermezzo_fs.h>
diff -u --recursive --new-file v2.5.1/linux/fs/intermezzo/file.c linux/fs/intermezzo/file.c
--- v2.5.1/linux/fs/intermezzo/file.c	Sun Nov 11 10:20:21 2001
+++ linux/fs/intermezzo/file.c	Sun Dec 30 16:59:00 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 -u --recursive --new-file v2.5.1/linux/fs/intermezzo/inode.c linux/fs/intermezzo/inode.c
--- v2.5.1/linux/fs/intermezzo/inode.c	Sun Nov 11 10:20:21 2001
+++ linux/fs/intermezzo/inode.c	Sun Dec 30 10:31:51 2001
@@ -29,7 +29,6 @@
 #include <asm/uaccess.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-#include <asm/segment.h>
 
 #include <linux/intermezzo_fs.h>
 #include <linux/intermezzo_upcall.h>
diff -u --recursive --new-file v2.5.1/linux/fs/intermezzo/journal.c linux/fs/intermezzo/journal.c
--- v2.5.1/linux/fs/intermezzo/journal.c	Tue Nov 13 09:20:56 2001
+++ linux/fs/intermezzo/journal.c	Sun Dec 30 16:59:00 2001
@@ -14,7 +14,6 @@
 #include <linux/time.h>
 #include <linux/errno.h>
 #include <linux/locks.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
 #include <linux/smp_lock.h>
@@ -1077,7 +1076,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 -u --recursive --new-file v2.5.1/linux/fs/intermezzo/journal_ext2.c linux/fs/intermezzo/journal_ext2.c
--- v2.5.1/linux/fs/intermezzo/journal_ext2.c	Sun Nov 11 10:20:21 2001
+++ linux/fs/intermezzo/journal_ext2.c	Sun Dec 30 10:31:51 2001
@@ -12,7 +12,6 @@
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/locks.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
 #include <linux/ext2_fs.h> 
diff -u --recursive --new-file v2.5.1/linux/fs/intermezzo/journal_ext3.c linux/fs/intermezzo/journal_ext3.c
--- v2.5.1/linux/fs/intermezzo/journal_ext3.c	Sun Nov 11 10:20:21 2001
+++ linux/fs/intermezzo/journal_ext3.c	Sun Dec 30 10:31:51 2001
@@ -17,7 +17,6 @@
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/locks.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
 #include <linux/smp_lock.h>
diff -u --recursive --new-file v2.5.1/linux/fs/intermezzo/journal_obdfs.c linux/fs/intermezzo/journal_obdfs.c
--- v2.5.1/linux/fs/intermezzo/journal_obdfs.c	Sun Nov 11 10:20:21 2001
+++ linux/fs/intermezzo/journal_obdfs.c	Sun Dec 30 10:31:51 2001
@@ -17,7 +17,6 @@
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/locks.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
 #ifdef CONFIG_OBDFS_FS
diff -u --recursive --new-file v2.5.1/linux/fs/intermezzo/journal_reiserfs.c linux/fs/intermezzo/journal_reiserfs.c
--- v2.5.1/linux/fs/intermezzo/journal_reiserfs.c	Sun Nov 11 10:20:21 2001
+++ linux/fs/intermezzo/journal_reiserfs.c	Sun Dec 30 10:31:51 2001
@@ -17,7 +17,6 @@
 #include <linux/errno.h>
 #include <linux/smp_lock.h>
 #include <linux/locks.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
 #if 0
diff -u --recursive --new-file v2.5.1/linux/fs/intermezzo/journal_xfs.c linux/fs/intermezzo/journal_xfs.c
--- v2.5.1/linux/fs/intermezzo/journal_xfs.c	Tue Nov 13 09:20:56 2001
+++ linux/fs/intermezzo/journal_xfs.c	Sun Dec 30 10:31:51 2001
@@ -12,7 +12,6 @@
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/locks.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
 #ifdef CONFIG_FS_XFS
diff -u --recursive --new-file v2.5.1/linux/fs/intermezzo/presto.c linux/fs/intermezzo/presto.c
--- v2.5.1/linux/fs/intermezzo/presto.c	Tue Nov 13 09:20:56 2001
+++ linux/fs/intermezzo/presto.c	Sun Dec 30 10:31:51 2001
@@ -17,7 +17,6 @@
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
 #include <linux/locks.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
 #include <linux/smp_lock.h>
diff -u --recursive --new-file v2.5.1/linux/fs/intermezzo/psdev.c linux/fs/intermezzo/psdev.c
--- v2.5.1/linux/fs/intermezzo/psdev.c	Sun Nov 11 10:20:21 2001
+++ linux/fs/intermezzo/psdev.c	Thu Jan  3 13:59:50 2002
@@ -35,6 +35,7 @@
 #include <linux/sched.h>
 #include <linux/lp.h>
 #include <linux/slab.h>
+#include <asm/ioctls.h>
 #include <linux/ioport.h>
 #include <linux/fcntl.h>
 #include <linux/delay.h>
@@ -45,8 +46,8 @@
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/list.h>
+#include <linux/termios.h>
 #include <asm/io.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/poll.h>
 #include <asm/uaccess.h>
@@ -77,12 +78,12 @@
 {
         int minor;
 
-        if ( MAJOR(file->f_dentry->d_inode->i_rdev) != PRESTO_PSDEV_MAJOR ) {
+        if ( major(file->f_dentry->d_inode->i_rdev) != PRESTO_PSDEV_MAJOR ) {
                 EXIT;
                 return NULL;
         }
 
-        minor = MINOR(file->f_dentry->d_inode->i_rdev);
+        minor = minor(file->f_dentry->d_inode->i_rdev);
         if ( minor < 0 || minor >= MAX_PRESTODEV ) {
                 EXIT;
                 return NULL;
@@ -176,7 +177,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 +210,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 +229,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 +282,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 +470,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 +622,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 +1245,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 +1572,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 -u --recursive --new-file v2.5.1/linux/fs/intermezzo/super.c linux/fs/intermezzo/super.c
--- v2.5.1/linux/fs/intermezzo/super.c	Sun Nov 11 10:20:21 2001
+++ linux/fs/intermezzo/super.c	Thu Jan  3 13:59:50 2002
@@ -159,7 +159,7 @@
 {
         struct nameidata nd;
         struct dentry *dentry;
-        kdev_t devno = 0;
+        kdev_t devno = NODEV;
         int error; 
         ENTRY;
 
@@ -188,19 +188,19 @@
 	}
 
         devno = dentry->d_inode->i_rdev;
-        if ( MAJOR(devno) != PRESTO_PSDEV_MAJOR ) { 
+        if ( major(devno) != PRESTO_PSDEV_MAJOR ) { 
 		EXIT;
 		goto out;
 	}
 
-        if ( MINOR(devno) >= MAX_PRESTODEV ) {
+        if ( minor(devno) >= MAX_PRESTODEV ) {
 		EXIT;
 		goto out;
 	}
 
 	EXIT;
  out:
-        *minor = MINOR(devno);
+        *minor = minor(devno);
         path_release(&nd);
         return 0;
 }
diff -u --recursive --new-file v2.5.1/linux/fs/intermezzo/sysctl.c linux/fs/intermezzo/sysctl.c
--- v2.5.1/linux/fs/intermezzo/sysctl.c	Sun Nov 11 10:20:21 2001
+++ linux/fs/intermezzo/sysctl.c	Sun Dec 30 10:31:51 2001
@@ -16,7 +16,6 @@
 #include <linux/ctype.h>
 #include <linux/init.h>
 #include <asm/bitops.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/utsname.h>
 #include <linux/blk.h>
diff -u --recursive --new-file v2.5.1/linux/fs/intermezzo/upcall.c linux/fs/intermezzo/upcall.c
--- v2.5.1/linux/fs/intermezzo/upcall.c	Sun Nov 11 10:20:21 2001
+++ linux/fs/intermezzo/upcall.c	Sun Dec 30 10:31:51 2001
@@ -20,7 +20,6 @@
  */
 
 #include <asm/system.h>
-#include <asm/segment.h>
 #include <asm/signal.h>
 #include <linux/signal.h>
 
@@ -37,7 +36,6 @@
 #include <linux/string.h>
 #include <asm/uaccess.h>
 #include <linux/vmalloc.h>
-#include <asm/segment.h>
 
 #include <linux/intermezzo_fs.h>
 #include <linux/intermezzo_upcall.h>
diff -u --recursive --new-file v2.5.1/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.5.1/linux/fs/isofs/inode.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/isofs/inode.c	Thu Dec 27 08:17:43 2001
@@ -480,7 +480,6 @@
 	int				iso_blknum, block;
 	int				orig_zonesize;
 	int				table;
-	unsigned int			blocksize, blocksize_bits;
 	unsigned int			vol_desc_start;
 	unsigned long			first_data_zone;
 	struct inode		      * inode;
@@ -508,26 +507,10 @@
 	 * larger than the blocksize the user specified, then use
 	 * that value.
 	 */
-	blocksize = get_hardsect_size(dev);
-	if(blocksize > opt.blocksize) {
-	    /*
-	     * Force the blocksize we are going to use to be the
-	     * hardware blocksize.
-	     */
-	    opt.blocksize = blocksize;
-	}
-
-	blocksize_bits = 0;
-	{
-	  int i = opt.blocksize;
-	  while (i != 1){
-	    blocksize_bits++;
-	    i >>=1;
-	  }
-	}
-
-	set_blocksize(dev, opt.blocksize);
-	s->s_blocksize = opt.blocksize;
+	/*
+	 * What if bugger tells us to go beyond page size?
+	 */
+	opt.blocksize = sb_min_blocksize(s, opt.blocksize);
 
 	s->u.isofs_sb.s_high_sierra = high_sierra = 0; /* default is iso9660 */
 
@@ -540,7 +523,7 @@
 	    struct hs_volume_descriptor   * hdp;
 	    struct iso_volume_descriptor  * vdp;
 
-	    block = iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits);
+	    block = iso_blknum << (ISOFS_BLOCK_BITS - s->s_blocksize_bits);
 	    if (!(bh = sb_bread(s, block)))
 		goto out_no_read;
 
@@ -651,7 +634,7 @@
 	 * blocks that were 512 bytes (which should only very rarely
 	 * happen.)
 	 */
-	if(blocksize != 0 && orig_zonesize < blocksize)
+	if(orig_zonesize < opt.blocksize)
 		goto out_bad_size;
 
 	/* RDE: convert log zone size to bit shift */
@@ -734,15 +717,7 @@
 	 * entries.  By forcing the blocksize in this way, we ensure
 	 * that we will never be required to do this.
 	 */
-	if ( orig_zonesize != opt.blocksize ) {
-		set_blocksize(dev, orig_zonesize);
-#ifndef BEQUIET
-		printk(KERN_DEBUG 
-			"ISOFS: Forcing new log zone size:%d\n", orig_zonesize);
-#endif
-	}
-	s->s_blocksize = orig_zonesize;
-	s->s_blocksize_bits = s -> u.isofs_sb.s_log_zone_size;
+	sb_set_blocksize(s, orig_zonesize);
 
 	s->u.isofs_sb.s_nls_iocharset = NULL;
 
@@ -853,7 +828,7 @@
 	goto out_freebh;
 out_bad_size:
 	printk(KERN_WARNING "Logical zone size(%d) < hardware blocksize(%u)\n",
-		orig_zonesize, blocksize);
+		orig_zonesize, opt.blocksize);
 	goto out_freebh;
 #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
 out_no_support:
@@ -890,7 +865,7 @@
  * (0 == error.)
  */
 int isofs_get_blocks(struct inode *inode, sector_t iblock,
-		     struct buffer_head **bh_result, unsigned long nblocks)
+		     struct buffer_head **bh, unsigned long nblocks)
 {
 	unsigned long b_off;
 	unsigned offset, sect_size;
@@ -952,16 +927,14 @@
 			}
 		}
 		
-		if ( *bh_result ) {
-			(*bh_result)->b_dev      = inode->i_dev;
-			(*bh_result)->b_blocknr  = firstext + b_off - offset;
-			(*bh_result)->b_state   |= (1UL << BH_Mapped);
+		if ( *bh ) {
+			map_bh(*bh, inode->i_sb, firstext + b_off - offset);
 		} else {
-			*bh_result = sb_getblk(inode->i_sb, firstext+b_off-offset);
-			if ( !*bh_result )
+			*bh = sb_getblk(inode->i_sb, firstext+b_off-offset);
+			if ( !*bh )
 				goto abort;
 		}
-		bh_result++;	/* Next buffer head */
+		bh++;	/* Next buffer head */
 		b_off++;	/* Next buffer offset */
 		nblocks--;
 		rv++;
diff -u --recursive --new-file v2.5.1/linux/fs/isofs/joliet.c linux/fs/isofs/joliet.c
--- v2.5.1/linux/fs/isofs/joliet.c	Sun Aug 12 10:56:56 2001
+++ linux/fs/isofs/joliet.c	Sat Dec 29 17:30:07 2001
@@ -8,7 +8,7 @@
 
 #include <linux/string.h>
 #include <linux/nls.h>
-#include <linux/slab.h>
+#include <linux/mm.h>
 #include <linux/iso_fs.h>
 #include <asm/unaligned.h>
 
diff -u --recursive --new-file v2.5.1/linux/fs/isofs/namei.c linux/fs/isofs/namei.c
--- v2.5.1/linux/fs/isofs/namei.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/isofs/namei.c	Sat Dec 29 17:30:07 2001
@@ -12,7 +12,7 @@
 #include <linux/string.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
-#include <linux/slab.h>
+#include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/config.h>	/* Joliet? */
 
diff -u --recursive --new-file v2.5.1/linux/fs/isofs/rock.c linux/fs/isofs/rock.c
--- v2.5.1/linux/fs/isofs/rock.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/isofs/rock.c	Mon Dec 31 18:27:26 2001
@@ -297,9 +297,9 @@
 	   * stored in the low field, and use that.
 	   */
 	  if((low & ~0xff) && high == 0) {
-	    inode->i_rdev = MKDEV(low >> 8, low & 0xff);
+	    inode->i_rdev = mk_kdev(low >> 8, low & 0xff);
 	  } else {
-	    inode->i_rdev = MKDEV(high, low);
+	    inode->i_rdev = mk_kdev(high, low);
 	  }
 	}
 	break;
diff -u --recursive --new-file v2.5.1/linux/fs/jbd/commit.c linux/fs/jbd/commit.c
--- v2.5.1/linux/fs/jbd/commit.c	Fri Nov  9 14:25:04 2001
+++ linux/fs/jbd/commit.c	Sun Dec 30 16:59:00 2001
@@ -47,7 +47,8 @@
 	struct buffer_head *wbuf[64];
 	int bufs;
 	int flags;
-	int blocknr;
+	int err;
+	unsigned long blocknr;
 	char *tagp = NULL;
 	journal_header_t *header;
 	journal_block_tag_t *tag = NULL;
@@ -352,6 +353,11 @@
 			jbd_debug(4, "JBD: get descriptor\n");
 
 			descriptor = journal_get_descriptor_buffer(journal);
+			if (!descriptor) {
+				__journal_abort_hard(journal);
+				continue;
+			}
+			
 			bh = jh2bh(descriptor);
 			jbd_debug(4, "JBD: got buffer %ld (%p)\n",
 				bh->b_blocknr, bh->b_data);
@@ -375,7 +381,14 @@
 
 		/* Where is the buffer to be written? */
 
-		blocknr = journal_next_log_block(journal);
+		err = journal_next_log_block(journal, &blocknr);
+		/* If the block mapping failed, just abandon the buffer
+		   and repeat this loop: we'll fall into the
+		   refile-on-abort condition above. */
+		if (err) {
+			__journal_abort_hard(journal);
+			continue;
+		}
 
 		/* Bump b_count to prevent truncate from stumbling over
                    the shadowed buffer!  @@@ This can go if we ever get
@@ -554,16 +567,20 @@
 
 	jbd_debug(3, "JBD: commit phase 6\n");
 
+	if (is_journal_aborted(journal))
+		goto skip_commit;
+
 	/* Done it all: now write the commit record.  We should have
 	 * cleaned up our previous buffers by now, so if we are in abort
 	 * mode we can now just skip the rest of the journal write
 	 * entirely. */
 
-	if (is_journal_aborted(journal))
-		goto skip_commit;
-
 	descriptor = journal_get_descriptor_buffer(journal);
-
+	if (!descriptor) {
+		__journal_abort_hard(journal);
+		goto skip_commit;
+	}
+	
 	/* AKPM: buglet - add `i' to tmp! */
 	for (i = 0; i < jh2bh(descriptor)->b_size; i += 512) {
 		journal_header_t *tmp =
diff -u --recursive --new-file v2.5.1/linux/fs/jbd/journal.c linux/fs/jbd/journal.c
--- v2.5.1/linux/fs/jbd/journal.c	Fri Nov  9 14:25:04 2001
+++ linux/fs/jbd/journal.c	Sun Dec 30 16:59:00 2001
@@ -70,7 +70,6 @@
 EXPORT_SYMBOL(journal_destroy);
 EXPORT_SYMBOL(journal_recover);
 EXPORT_SYMBOL(journal_update_superblock);
-EXPORT_SYMBOL(__journal_abort);
 EXPORT_SYMBOL(journal_abort);
 EXPORT_SYMBOL(journal_errno);
 EXPORT_SYMBOL(journal_ack_err);
@@ -606,7 +605,7 @@
  * Log buffer allocation routines:
  */
 
-unsigned long journal_next_log_block(journal_t *journal)
+int journal_next_log_block(journal_t *journal, unsigned long *retp)
 {
 	unsigned long blocknr;
 
@@ -617,7 +616,7 @@
 	journal->j_free--;
 	if (journal->j_head == journal->j_last)
 		journal->j_head = journal->j_first;
-	return journal_bmap(journal, blocknr);
+	return journal_bmap(journal, blocknr, retp);
 }
 
 /*
@@ -627,17 +626,28 @@
  * this is a no-op.  If needed, we can use j_blk_offset - everything is
  * ready.
  */
-unsigned long journal_bmap(journal_t *journal, unsigned long blocknr)
+int journal_bmap(journal_t *journal, unsigned long blocknr, 
+		 unsigned long *retp)
 {
+	int err = 0;
 	unsigned long ret;
 
 	if (journal->j_inode) {
 		ret = bmap(journal->j_inode, blocknr);
-		J_ASSERT(ret != 0);
+		if (ret)
+			*retp = ret;
+		else {
+			printk (KERN_ALERT __FUNCTION__ 
+				": journal block not found "
+				"at offset %lu on %s\n",
+				blocknr, bdevname(journal->j_dev));
+			err = -EIO;
+			__journal_abort_soft(journal, err);
+		}
 	} else {
-		ret = blocknr;	 /* +journal->j_blk_offset */
+		*retp = blocknr; /* +journal->j_blk_offset */
 	}
-	return ret;
+	return err;
 }
 
 /*
@@ -649,7 +659,13 @@
 struct journal_head * journal_get_descriptor_buffer(journal_t *journal)
 {
 	struct buffer_head *bh;
-	unsigned long blocknr = journal_next_log_block(journal);
+	unsigned long blocknr;
+	int err;
+
+	err = journal_next_log_block(journal, &blocknr);
+
+	if (err)
+		return NULL;
 
 	bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
 	bh->b_state |= (1 << BH_Dirty);
@@ -747,7 +763,8 @@
 {
 	struct buffer_head *bh;
 	journal_t *journal = journal_init_common();
-	int blocknr;
+	int err;
+	unsigned long blocknr;
 
 	if (!journal)
 		return NULL;
@@ -757,13 +774,22 @@
 	journal->j_inode = inode;
 	jbd_debug(1,
 		  "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n",
-		  journal, bdevname(inode->i_dev), inode->i_ino, inode->i_size,
+		  journal, bdevname(inode->i_dev), inode->i_ino, 
+		  (long long) inode->i_size,
 		  inode->i_sb->s_blocksize_bits, inode->i_sb->s_blocksize);
 
 	journal->j_maxlen = inode->i_size >> inode->i_sb->s_blocksize_bits;
 	journal->j_blocksize = inode->i_sb->s_blocksize;
 
-	blocknr = journal_bmap(journal, 0);
+	err = journal_bmap(journal, 0, &blocknr);
+	/* If that failed, give up */
+	if (err) {
+		printk(KERN_ERR __FUNCTION__ ": Cannnot locate journal "
+		       "superblock\n");
+		kfree(journal);
+		return NULL;
+	}
+	
 	bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
 	J_ASSERT(bh != NULL);
 	journal->j_sb_buffer = bh;
@@ -772,6 +798,18 @@
 	return journal;
 }
 
+/* 
+ * If the journal init or create aborts, we need to mark the journal
+ * superblock as being NULL to prevent the journal destroy from writing
+ * back a bogus superblock. 
+ */
+static void journal_fail_superblock (journal_t *journal)
+{
+	struct buffer_head *bh = journal->j_sb_buffer;
+	brelse(bh);
+	journal->j_sb_buffer = NULL;
+}
+
 /*
  * Given a journal_t structure, initialise the various fields for
  * startup of a new journaling session.  We use this both when creating
@@ -817,14 +855,15 @@
 
 int journal_create (journal_t *journal)
 {
-	int blocknr;
+	unsigned long blocknr;
 	struct buffer_head *bh;
 	journal_superblock_t *sb;
-	int i;
+	int i, err;
 
 	if (journal->j_maxlen < JFS_MIN_JOURNAL_BLOCKS) {
 		printk (KERN_ERR "Journal length (%d blocks) too short.\n",
 			journal->j_maxlen);
+		journal_fail_superblock(journal);
 		return -EINVAL;
 	}
 
@@ -841,7 +880,9 @@
 	   have any blocks on disk beginning with JFS_MAGIC_NUMBER. */
 	jbd_debug(1, "JBD: Zeroing out journal blocks...\n");
 	for (i = 0; i < journal->j_maxlen; i++) {
-		blocknr = journal_bmap(journal, i);
+		err = journal_bmap(journal, i, &blocknr);
+		if (err)
+			return err;
 		bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
 		wait_on_buffer(bh);
 		memset (bh->b_data, 0, journal->j_blocksize);
@@ -851,6 +892,7 @@
 		mark_buffer_uptodate(bh, 1);
 		__brelse(bh);
 	}
+
 	sync_dev(journal->j_dev);
 	jbd_debug(1, "JBD: journal cleared.\n");
 
@@ -915,7 +957,8 @@
 {
 	struct buffer_head *bh;
 	journal_superblock_t *sb;
-
+	int err = -EIO;
+	
 	bh = journal->j_sb_buffer;
 
 	J_ASSERT(bh != NULL);
@@ -925,16 +968,18 @@
 		if (!buffer_uptodate(bh)) {
 			printk (KERN_ERR
 				"JBD: IO error reading journal superblock\n");
-			return -EIO;
+			goto out;
 		}
 	}
 
 	sb = journal->j_superblock;
 
+	err = -EINVAL;
+	
 	if (sb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) ||
 	    sb->s_blocksize != htonl(journal->j_blocksize)) {
 		printk(KERN_WARNING "JBD: no valid journal superblock found\n");
-		return -EINVAL;
+		goto out;
 	}
 
 	switch(ntohl(sb->s_header.h_blocktype)) {
@@ -946,17 +991,21 @@
 		break;
 	default:
 		printk(KERN_WARNING "JBD: unrecognised superblock format ID\n");
-		return -EINVAL;
+		goto out;
 	}
 
 	if (ntohl(sb->s_maxlen) < journal->j_maxlen)
 		journal->j_maxlen = ntohl(sb->s_maxlen);
 	else if (ntohl(sb->s_maxlen) > journal->j_maxlen) {
 		printk (KERN_WARNING "JBD: journal file too short\n");
-		return -EINVAL;
+		goto out;
 	}
 
 	return 0;
+
+out:
+	journal_fail_superblock(journal);
+	return err;
 }
 
 /*
@@ -1061,7 +1110,10 @@
 	/* We can now mark the journal as empty. */
 	journal->j_tail = 0;
 	journal->j_tail_sequence = ++journal->j_transaction_sequence;
-	journal_update_superblock(journal, 1);
+	if (journal->j_sb_buffer) {
+		journal_update_superblock(journal, 1);
+		brelse(journal->j_sb_buffer);
+	}
 
 	if (journal->j_inode)
 		iput(journal->j_inode);
@@ -1069,7 +1121,6 @@
 		journal_destroy_revoke(journal);
 
 	unlock_journal(journal);
-	brelse(journal->j_sb_buffer);
 	kfree(journal);
 	MOD_DEC_USE_COUNT;
 }
@@ -1356,11 +1407,16 @@
  * progress).
  */
 
-/* Quick version for internal journal use (doesn't lock the journal) */
-void __journal_abort (journal_t *journal)
+/* Quick version for internal journal use (doesn't lock the journal).
+ * Aborts hard --- we mark the abort as occurred, but do _nothing_ else,
+ * and don't attempt to make any other journal updates. */
+void __journal_abort_hard (journal_t *journal)
 {
 	transaction_t *transaction;
 
+	if (journal->j_flags & JFS_ABORT)
+		return;
+
 	printk (KERN_ERR "Aborting journal on device %s.\n",
 		journal_dev_name(journal));
 
@@ -1370,23 +1426,27 @@
 		log_start_commit(journal, transaction);
 }
 
-/* Full version for external use */
-void journal_abort (journal_t *journal, int errno)
+/* Soft abort: record the abort error status in the journal superblock,
+ * but don't do any other IO. */
+void __journal_abort_soft (journal_t *journal, int errno)
 {
-	lock_journal(journal);
-
 	if (journal->j_flags & JFS_ABORT)
-		goto out;
+		return;
 
 	if (!journal->j_errno)
 		journal->j_errno = errno;
 
-	__journal_abort(journal);
+	__journal_abort_hard(journal);
 
 	if (errno)
 		journal_update_superblock(journal, 1);
+}
 
- out:
+/* Full version for external use */
+void journal_abort (journal_t *journal, int errno)
+{
+	lock_journal(journal);
+	__journal_abort_soft(journal, errno);
 	unlock_journal(journal);
 }
 
diff -u --recursive --new-file v2.5.1/linux/fs/jbd/recovery.c linux/fs/jbd/recovery.c
--- v2.5.1/linux/fs/jbd/recovery.c	Fri Nov  9 14:25:04 2001
+++ linux/fs/jbd/recovery.c	Sun Dec 30 16:59:00 2001
@@ -70,7 +70,8 @@
 static int do_readahead(journal_t *journal, unsigned int start)
 {
 	int err;
-	unsigned int max, nbufs, next, blocknr;
+	unsigned int max, nbufs, next;
+	unsigned long blocknr;
 	struct buffer_head *bh;
 	
 	struct buffer_head * bufs[MAXBUF];
@@ -86,12 +87,11 @@
 	nbufs = 0;
 	
 	for (next = start; next < max; next++) {
-		blocknr = journal_bmap(journal, next);
+		err = journal_bmap(journal, next, &blocknr);
 
-		if (!blocknr) {
+		if (err) {
 			printk (KERN_ERR "JBD: bad block at offset %u\n",
 				next);
-			err = -EIO;
 			goto failed;
 		}
 
@@ -132,19 +132,20 @@
 static int jread(struct buffer_head **bhp, journal_t *journal, 
 		 unsigned int offset)
 {
-	unsigned int blocknr;
+	int err;
+	unsigned long blocknr;
 	struct buffer_head *bh;
 
 	*bhp = NULL;
 
 	J_ASSERT (offset < journal->j_maxlen);
 	
-	blocknr = journal_bmap(journal, offset);
+	err = journal_bmap(journal, offset, &blocknr);
 
-	if (!blocknr) {
+	if (err) {
 		printk (KERN_ERR "JBD: bad block at offset %u\n",
 			offset);
-		return -EIO;
+		return err;
 	}
 
 	bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
diff -u --recursive --new-file v2.5.1/linux/fs/jbd/revoke.c linux/fs/jbd/revoke.c
--- v2.5.1/linux/fs/jbd/revoke.c	Fri Nov  9 14:25:04 2001
+++ linux/fs/jbd/revoke.c	Sun Dec 30 16:59:00 2001
@@ -495,6 +495,8 @@
 	
 	if (!descriptor) {
 		descriptor = journal_get_descriptor_buffer(journal);
+		if (!descriptor)
+			return;
 		header = (journal_header_t *) &jh2bh(descriptor)->b_data[0];
 		header->h_magic     = htonl(JFS_MAGIC_NUMBER);
 		header->h_blocktype = htonl(JFS_REVOKE_BLOCK);
diff -u --recursive --new-file v2.5.1/linux/fs/jbd/transaction.c linux/fs/jbd/transaction.c
--- v2.5.1/linux/fs/jbd/transaction.c	Fri Nov  9 14:25:04 2001
+++ linux/fs/jbd/transaction.c	Sun Dec 30 16:59:00 2001
@@ -1058,21 +1058,6 @@
 		JBUFFER_TRACE(jh, "not on a transaction");
 		__journal_file_buffer(jh, handle->h_transaction, wanted_jlist);
 	}
-	/*
-	 * We need to mark the buffer dirty and refile it inside the lock to
-	 * protect it from release by journal_try_to_free_buffer()
-	 *
-	 * We set ->b_flushtime to something small enough to typically keep
-	 * kupdate away from the buffer.
-	 *
-	 * We don't need to do a balance_dirty() - __block_commit_write()
-	 * does that.
-	 */
-	if (!async && !atomic_set_buffer_dirty(jh2bh(jh))) {
-		jh2bh(jh)->b_flushtime =
-			jiffies + journal->j_commit_interval + 1 * HZ;
-		refile_buffer(jh2bh(jh));
-	}
 no_journal:
 	spin_unlock(&journal_datalist_lock);
 	if (need_brelse) {
@@ -1604,8 +1589,6 @@
 
 	assert_spin_locked(&journal_datalist_lock);
 
-	if (!buffer_jbd(bh))
-		return 1;
 	jh = bh2jh(bh);
 
 	if (buffer_locked(bh) || buffer_dirty(bh)) {
diff -u --recursive --new-file v2.5.1/linux/fs/jffs/inode-v23.c linux/fs/jffs/inode-v23.c
--- v2.5.1/linux/fs/jffs/inode-v23.c	Thu Oct  4 15:14:35 2001
+++ linux/fs/jffs/inode-v23.c	Thu Jan  3 13:59:50 2002
@@ -81,7 +81,7 @@
 	D1(printk(KERN_NOTICE "JFFS: Trying to mount device %s.\n",
 		  kdevname(dev)));
 
-	if (MAJOR(dev) != MTD_BLOCK_MAJOR) {
+	if (major(dev) != MTD_BLOCK_MAJOR) {
 		printk(KERN_WARNING "JFFS: Trying to mount a "
 		       "non-mtd device.\n");
 		return 0;
@@ -365,7 +365,6 @@
 	inode->i_ctime = raw_inode->ctime;
 	inode->i_blksize = PAGE_SIZE;
 	inode->i_blocks = (inode->i_size + 511) >> 9;
-	inode->i_version = 0;
 
 	f = jffs_find_file(c, raw_inode->ino);
 
@@ -1023,7 +1022,6 @@
 	   from the in-memory file system structures.  */
 	jffs_insert_node(c, del_f, &raw_inode, 0, del_node);
 
-	dir->i_version = ++event;
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(dir);
 	inode->i_nlink--;
diff -u --recursive --new-file v2.5.1/linux/fs/jffs2/dir.c linux/fs/jffs2/dir.c
--- v2.5.1/linux/fs/jffs2/dir.c	Fri Sep 14 14:04:07 2001
+++ linux/fs/jffs2/dir.c	Thu Jan  3 13:59:50 2002
@@ -795,7 +795,7 @@
 	
 	if ((mode & S_IFMT) == S_IFBLK ||
 	    (mode & S_IFMT) == S_IFCHR) {
-		dev = (MAJOR(to_kdev_t(rdev)) << 8) | MINOR(to_kdev_t(rdev));
+		dev = (MAJOR(rdev) << 8) | MINOR(rdev);
 		devlen = sizeof(dev);
 	}
 	
diff -u --recursive --new-file v2.5.1/linux/fs/jffs2/file.c linux/fs/jffs2/file.c
--- v2.5.1/linux/fs/jffs2/file.c	Thu Oct  4 15:13:18 2001
+++ linux/fs/jffs2/file.c	Thu Jan  3 13:59:50 2002
@@ -105,8 +105,8 @@
 	if ((inode->i_mode & S_IFMT) == S_IFBLK ||
 	    (inode->i_mode & S_IFMT) == S_IFCHR) {
 		/* For these, we don't actually need to read the old node */
-		dev =  (MAJOR(to_kdev_t(dentry->d_inode->i_rdev)) << 8) | 
-			MINOR(to_kdev_t(dentry->d_inode->i_rdev));
+		dev =  (major(dentry->d_inode->i_rdev) << 8) | 
+			minor(dentry->d_inode->i_rdev);
 		mdata = (char *)&dev;
 		mdatalen = sizeof(dev);
 		D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen));
diff -u --recursive --new-file v2.5.1/linux/fs/jffs2/gc.c linux/fs/jffs2/gc.c
--- v2.5.1/linux/fs/jffs2/gc.c	Thu Oct  4 15:13:18 2001
+++ linux/fs/jffs2/gc.c	Thu Jan  3 13:59:50 2002
@@ -269,8 +269,8 @@
 	if ((inode->i_mode & S_IFMT) == S_IFBLK ||
 	    (inode->i_mode & S_IFMT) == S_IFCHR) {
 		/* For these, we don't actually need to read the old node */
-		dev =  (MAJOR(to_kdev_t(inode->i_rdev)) << 8) | 
-			MINOR(to_kdev_t(inode->i_rdev));
+		dev =  (major(inode->i_rdev) << 8) | 
+			minor(inode->i_rdev);
 		mdata = (char *)&dev;
 		mdatalen = sizeof(dev);
 		D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bytes of kdev_t\n", mdatalen));
diff -u --recursive --new-file v2.5.1/linux/fs/jffs2/super.c linux/fs/jffs2/super.c
--- v2.5.1/linux/fs/jffs2/super.c	Thu Oct  4 15:14:35 2001
+++ linux/fs/jffs2/super.c	Thu Jan  3 13:59:50 2002
@@ -199,7 +199,7 @@
 
 	D1(printk(KERN_DEBUG "jffs2: read_super for device %s\n", kdevname(sb->s_dev)));
 
-	if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) {
+	if (major(sb->s_dev) != MTD_BLOCK_MAJOR) {
 		if (!silent)
 			printk(KERN_DEBUG "jffs2: attempt to mount non-MTD device %s\n", kdevname(sb->s_dev));
 		return NULL;
diff -u --recursive --new-file v2.5.1/linux/fs/jffs2/write.c linux/fs/jffs2/write.c
--- v2.5.1/linux/fs/jffs2/write.c	Thu Oct  4 15:13:18 2001
+++ linux/fs/jffs2/write.c	Sun Dec 30 09:09:24 2001
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: write.c,v 1.28 2001/05/01 16:25:25 dwmw2 Exp $
+ * $Id: write.c,v 1.30 2001/12/30 16:01:11 dwmw2 Exp $
  *
  */
 
@@ -207,8 +207,6 @@
 	}
 	raw->flash_offset = flash_ofs;
 	raw->totlen = PAD(ri->totlen);
-	raw->next_in_ino = f->inocache->nodes;
-	f->inocache->nodes = raw;
 	raw->next_phys = NULL;
 
 	fn->ofs = ri->offset;
@@ -222,6 +220,14 @@
 		       sizeof(*ri)+datalen, flash_ofs, ret, retlen);
 		/* Mark the space as dirtied */
 		if (retlen) {
+			/* Doesn't belong to any inode */
+			raw->next_in_ino = NULL;
+
+			/* Don't change raw->size to match retlen. We may have 
+			   written the node header already, and only the data will
+			   seem corrupted, in which case the scan would skip over
+			   any node we write before the original intended end of 
+			   this node */
 			jffs2_add_physical_node_ref(c, raw, sizeof(*ri)+datalen, 1);
 			jffs2_mark_node_obsolete(c, raw);
 		} else {
@@ -237,6 +243,11 @@
 	}
 	/* Mark the space used */
 	jffs2_add_physical_node_ref(c, raw, retlen, 0);
+
+	/* Link into per-inode list */
+	raw->next_in_ino = f->inocache->nodes;
+	f->inocache->nodes = raw;
+
 	D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", flash_ofs, ri->dsize, ri->csize, ri->node_crc, ri->data_crc, ri->totlen));
 	if (writelen)
 		*writelen = retlen;
diff -u --recursive --new-file v2.5.1/linux/fs/lockd/svclock.c linux/fs/lockd/svclock.c
--- v2.5.1/linux/fs/lockd/svclock.c	Thu Oct 11 07:52:18 2001
+++ linux/fs/lockd/svclock.c	Tue Jan  1 12:23:29 2002
@@ -306,8 +306,9 @@
 	struct nlm_block	*block;
 	int			error;
 
-	dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
-				file->f_file.f_dentry->d_inode->i_dev,
+	dprintk("lockd: nlmsvc_lock(%02x:%02x/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
+				major(file->f_file.f_dentry->d_inode->i_dev),
+				minor(file->f_file.f_dentry->d_inode->i_dev),
 				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_type, lock->fl.fl_pid,
 				(long long)lock->fl.fl_start,
@@ -385,8 +386,9 @@
 {
 	struct file_lock	*fl;
 
-	dprintk("lockd: nlmsvc_testlock(%04x/%ld, ty=%d, %Ld-%Ld)\n",
-				file->f_file.f_dentry->d_inode->i_dev,
+	dprintk("lockd: nlmsvc_testlock(%02x:%02x/%ld, ty=%d, %Ld-%Ld)\n",
+				major(file->f_file.f_dentry->d_inode->i_dev),
+				minor(file->f_file.f_dentry->d_inode->i_dev),
 				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_type,
 				(long long)lock->fl.fl_start,
@@ -417,8 +419,9 @@
 {
 	int	error;
 
-	dprintk("lockd: nlmsvc_unlock(%04x/%ld, pi=%d, %Ld-%Ld)\n",
-				file->f_file.f_dentry->d_inode->i_dev,
+	dprintk("lockd: nlmsvc_unlock(%02x:%02x/%ld, pi=%d, %Ld-%Ld)\n",
+				major(file->f_file.f_dentry->d_inode->i_dev),
+				minor(file->f_file.f_dentry->d_inode->i_dev),
 				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_pid,
 				(long long)lock->fl.fl_start,
@@ -445,8 +448,9 @@
 {
 	struct nlm_block	*block;
 
-	dprintk("lockd: nlmsvc_cancel(%04x/%ld, pi=%d, %Ld-%Ld)\n",
-				file->f_file.f_dentry->d_inode->i_dev,
+	dprintk("lockd: nlmsvc_cancel(%02x:%02x/%ld, pi=%d, %Ld-%Ld)\n",
+				major(file->f_file.f_dentry->d_inode->i_dev),
+				minor(file->f_file.f_dentry->d_inode->i_dev),
 				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_pid,
 				(long long)lock->fl.fl_start,
diff -u --recursive --new-file v2.5.1/linux/fs/minix/inode.c linux/fs/minix/inode.c
--- v2.5.1/linux/fs/minix/inode.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/minix/inode.c	Sun Dec 30 16:59:04 2001
@@ -126,9 +126,7 @@
 	struct buffer_head **map;
 	struct minix_super_block *ms;
 	int i, block;
-	kdev_t dev = s->s_dev;
 	struct inode *root_inode;
-	unsigned int hblock;
 	struct minix_sb_info *sbi = &s->u.minix_sb;
 
 	/* N.B. These should be compile-time tests.
@@ -138,13 +136,9 @@
 	if (64 != sizeof(struct minix2_inode))
 		panic("bad V2 i-node size");
 
-	hblock = get_hardsect_size(dev);
-	if (hblock > BLOCK_SIZE)
+	if (!sb_set_blocksize(s, BLOCK_SIZE))
 		goto out_bad_hblock;
 
-	set_blocksize(dev, BLOCK_SIZE);
-	s->s_blocksize = BLOCK_SIZE;
-	s->s_blocksize_bits = BLOCK_SIZE_BITS;
 	if (!(bh = sb_bread(s, 1)))
 		goto out_bad_sb;
 
@@ -214,7 +208,7 @@
 	/* set up enough so that it can read an inode */
 	s->s_op = &minix_sops;
 	root_inode = iget(s, MINIX_ROOT_INO);
-	if (!root_inode)
+	if (!root_inode || is_bad_inode(root_inode))
 		goto out_no_root;
 
 	s->s_root = d_alloc_root(root_inode);
@@ -264,7 +258,7 @@
 out_no_fs:
 	if (!silent)
 		printk("VFS: Can't find a Minix or Minix V2 filesystem on device "
-		       "%s.\n", kdevname(dev));
+		       "%s.\n", bdevname(s->s_dev));
     out_release:
 	brelse(bh);
 	goto out;
@@ -353,8 +347,10 @@
 	int i;
 
 	raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh);
-	if (!raw_inode)
+	if (!raw_inode) {
+		make_bad_inode(inode);
 		return;
+	}
 	inode->i_mode = raw_inode->i_mode;
 	inode->i_uid = (uid_t)raw_inode->i_uid;
 	inode->i_gid = (gid_t)raw_inode->i_gid;
@@ -378,8 +374,10 @@
 	int i;
 
 	raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh);
-	if (!raw_inode)
+	if (!raw_inode) {
+		make_bad_inode(inode);
 		return;
+	}
 	inode->i_mode = raw_inode->i_mode;
 	inode->i_uid = (uid_t)raw_inode->i_uid;
 	inode->i_gid = (gid_t)raw_inode->i_gid;
diff -u --recursive --new-file v2.5.1/linux/fs/minix/itree_common.c linux/fs/minix/itree_common.c
--- v2.5.1/linux/fs/minix/itree_common.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/minix/itree_common.c	Thu Dec 27 08:17:43 2001
@@ -141,7 +141,7 @@
 }
 
 static inline int get_block(struct inode * inode, sector_t block,
-			struct buffer_head *bh_result, int create)
+			struct buffer_head *bh, int create)
 {
 	int err = -EIO;
 	int offsets[DEPTH];
@@ -160,9 +160,7 @@
 	/* Simplest case - block found, no allocation needed */
 	if (!partial) {
 got_it:
-		bh_result->b_dev = inode->i_dev;
-		bh_result->b_blocknr = block_to_cpu(chain[depth-1].key);
-		bh_result->b_state |= (1UL << BH_Mapped);
+		map_bh(bh, inode->i_sb, block_to_cpu(chain[depth-1].key));
 		/* Clean up and exit */
 		partial = chain+depth-1; /* the whole chain */
 		goto cleanup;
@@ -196,7 +194,7 @@
 	if (splice_branch(inode, chain, partial, left) < 0)
 		goto changed;
 
-	bh_result->b_state |= (1UL << BH_New);
+	bh->b_state |= (1UL << BH_New);
 	goto got_it;
 
 changed:
diff -u --recursive --new-file v2.5.1/linux/fs/msdos/msdosfs_syms.c linux/fs/msdos/msdosfs_syms.c
--- v2.5.1/linux/fs/msdos/msdosfs_syms.c	Mon Mar 13 12:35:39 2000
+++ linux/fs/msdos/msdosfs_syms.c	Sun Dec 30 16:58:58 2001
@@ -40,3 +40,4 @@
 
 module_init(init_msdos_fs)
 module_exit(exit_msdos_fs)
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v2.5.1/linux/fs/msdos/namei.c	Fri Oct 12 13:48:42 2001
+++ linux/fs/msdos/namei.c	Sun Dec 30 10:53:53 2001
@@ -476,7 +476,7 @@
 		if (error)
 			goto out;
 	}
-	new_dir->i_version = ++event;
+	new_dir->i_version++;
 
 	/* There we go */
 
@@ -491,7 +491,7 @@
 	else
 		MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
 	mark_inode_dirty(old_inode);
-	old_dir->i_version = ++event;
+	old_dir->i_version++;
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(old_dir);
 	if (new_inode) {
@@ -528,7 +528,7 @@
 	else
 		MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
 	mark_inode_dirty(old_inode);
-	old_dir->i_version = ++event;
+	old_dir->i_version++;
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(old_dir);
 	return 0;
diff -u --recursive --new-file v2.5.1/linux/fs/namei.c linux/fs/namei.c
--- v2.5.1/linux/fs/namei.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/namei.c	Tue Jan  1 15:24:13 2002
@@ -1589,7 +1589,7 @@
 		goto exit_lock;
 
 	error = -EXDEV;
-	if (dir->i_dev != inode->i_dev)
+	if (dir->i_sb != inode->i_sb)
 		goto exit_lock;
 
 	/*
@@ -1707,7 +1707,7 @@
 	if (error)
 		return error;
 
-	if (new_dir->i_dev != old_dir->i_dev)
+	if (new_dir->i_sb != old_dir->i_sb)
 		return -EXDEV;
 
 	if (!new_dentry->d_inode)
@@ -1787,7 +1787,7 @@
 	if (error)
 		return error;
 
-	if (new_dir->i_dev != old_dir->i_dev)
+	if (new_dir->i_sb != old_dir->i_sb)
 		return -EXDEV;
 
 	if (!new_dentry->d_inode)
diff -u --recursive --new-file v2.5.1/linux/fs/namespace.c linux/fs/namespace.c
--- v2.5.1/linux/fs/namespace.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/namespace.c	Sun Dec 30 16:59:04 2001
@@ -10,27 +10,26 @@
 
 #include <linux/config.h>
 #include <linux/slab.h>
+#include <linux/sched.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/quotaops.h>
 #include <linux/acct.h>
 #include <linux/module.h>
 #include <linux/seq_file.h>
+#include <linux/namespace.h>
 
 #include <asm/uaccess.h>
 
-struct vfsmount *do_kern_mount(char *type, int flags, char *name, void *data);
+struct vfsmount *do_kern_mount(const char *type, int flags, char *name, void *data);
 int do_remount_sb(struct super_block *sb, int flags, void * data);
 void kill_super(struct super_block *sb);
+int __init init_rootfs(void);
 
 static struct list_head *mount_hashtable;
 static int hash_mask, hash_bits;
 static kmem_cache_t *mnt_cache; 
 
-static LIST_HEAD(vfsmntlist);
-static DECLARE_MUTEX(mount_sem);
-static struct vfsmount *root_vfsmnt;
-
 static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
 {
 	unsigned long tmp = ((unsigned long) mnt / L1_CACHE_BYTES);
@@ -96,7 +95,7 @@
 	while (mnt->mnt_parent != mnt)
 		mnt = mnt->mnt_parent;
 	spin_unlock(&dcache_lock);
-	return mnt == root_vfsmnt;
+	return mnt == current->namespace->root;
 }
 
 static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd)
@@ -164,26 +163,29 @@
 /* iterator */
 static void *m_start(struct seq_file *m, loff_t *pos)
 {
+	struct namespace *n = m->private;
 	struct list_head *p;
-	loff_t n = *pos;
+	loff_t l = *pos;
 
-	down(&mount_sem);
-	list_for_each(p, &vfsmntlist)
-		if (!n--)
+	down_read(&n->sem);
+	list_for_each(p, &n->list)
+		if (!l--)
 			return list_entry(p, struct vfsmount, mnt_list);
 	return NULL;
 }
 
 static void *m_next(struct seq_file *m, void *v, loff_t *pos)
 {
+	struct namespace *n = m->private;
 	struct list_head *p = ((struct vfsmount *)v)->mnt_list.next;
 	(*pos)++;
-	return p==&vfsmntlist ? NULL : list_entry(p, struct vfsmount, mnt_list);
+	return p==&n->list ? NULL : list_entry(p, struct vfsmount, mnt_list);
 }
 
 static void m_stop(struct seq_file *m, void *v)
 {
-	up(&mount_sem);
+	struct namespace *n = m->private;
+	up_read(&n->sem);
 }
 
 static inline void mangle(struct seq_file *m, const char *s)
@@ -329,7 +331,7 @@
 		return retval;
 	}
 
-	down(&mount_sem);
+	down_write(&current->namespace->sem);
 	spin_lock(&dcache_lock);
 
 	if (atomic_read(&sb->s_active) == 1) {
@@ -337,7 +339,7 @@
 		spin_unlock(&dcache_lock);
 		lock_kernel();
 		DQUOT_OFF(sb);
-		acct_auto_close(sb->s_dev);
+		acct_auto_close(sb);
 		unlock_kernel();
 		spin_lock(&dcache_lock);
 	}
@@ -348,7 +350,7 @@
 		retval = 0;
 	}
 	spin_unlock(&dcache_lock);
-	up(&mount_sem);
+	up_write(&current->namespace->sem);
 	return retval;
 }
 
@@ -478,7 +480,7 @@
 		struct list_head head;
 		attach_mnt(mnt, nd);
 		list_add_tail(&head, &mnt->mnt_list);
-		list_splice(&head, vfsmntlist.prev);
+		list_splice(&head, current->namespace->list.prev);
 		mntget(mnt);
 		err = 0;
 	}
@@ -505,7 +507,7 @@
 	if (err)
 		return err;
 
-	down(&mount_sem);
+	down_write(&current->namespace->sem);
 	err = -EINVAL;
 	if (check_mnt(nd->mnt) && (!recurse || check_mnt(old_nd.mnt))) {
 		err = -ENOMEM;
@@ -525,7 +527,7 @@
 			mntput(mnt);
 	}
 
-	up(&mount_sem);
+	up_write(&current->namespace->sem);
 	path_release(&old_nd);
 	return err;
 }
@@ -572,7 +574,7 @@
 	if (err)
 		return err;
 
-	down(&mount_sem);
+	down_write(&current->namespace->sem);
 	while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
 		;
 	err = -EINVAL;
@@ -612,7 +614,7 @@
 out1:
 	up(&nd->dentry->d_inode->i_zombie);
 out:
-	up(&mount_sem);
+	up_write(&current->namespace->sem);
 	if (!err)
 		path_release(&parent_nd);
 	path_release(&old_nd);
@@ -622,13 +624,22 @@
 static int do_add_mount(struct nameidata *nd, char *type, int flags,
 			int mnt_flags, char *name, void *data)
 {
-	struct vfsmount *mnt = do_kern_mount(type, flags, name, data);
-	int err = PTR_ERR(mnt);
+	struct vfsmount *mnt;
+	int err;
+
+	if (!type || !memchr(type, 0, PAGE_SIZE))
+		return -EINVAL;
 
+	/* we need capabilities... */
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	mnt = do_kern_mount(type, flags, name, data);
+	err = PTR_ERR(mnt);
 	if (IS_ERR(mnt))
 		goto out;
 
-	down(&mount_sem);
+	down_write(&current->namespace->sem);
 	/* Something was mounted here while we slept */
 	while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
 		;
@@ -644,7 +655,7 @@
 	mnt->mnt_flags = mnt_flags;
 	err = graft_tree(mnt, nd);
 unlock:
-	up(&mount_sem);
+	up_write(&current->namespace->sem);
 	mntput(mnt);
 out:
 	return err;
@@ -744,6 +755,86 @@
 	return retval;
 }
 
+int copy_namespace(int flags, struct task_struct *tsk)
+{
+	struct namespace *namespace = tsk->namespace;
+	struct namespace *new_ns;
+	struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL;
+	struct fs_struct *fs = tsk->fs;
+
+	if (!namespace)
+		return 0;
+
+	get_namespace(namespace);
+
+	if (! (flags & CLONE_NEWNS))
+		return 0;
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		put_namespace(namespace);
+		return -EPERM;
+	}
+
+	new_ns = kmalloc(sizeof(struct namespace *), GFP_KERNEL);
+	if (!new_ns)
+		goto out;
+
+	atomic_set(&new_ns->count, 1);
+	init_rwsem(&new_ns->sem);
+	new_ns->root = NULL;
+	INIT_LIST_HEAD(&new_ns->list);
+
+	down_write(&tsk->namespace->sem);
+	/* First pass: copy the tree topology */
+	new_ns->root = copy_tree(namespace->root, namespace->root->mnt_root);
+	spin_lock(&dcache_lock);
+	list_add_tail(&new_ns->list, &new_ns->root->mnt_list);
+	spin_unlock(&dcache_lock);
+
+	/* Second pass: switch the tsk->fs->* elements */
+	if (fs) {
+		struct vfsmount *p, *q;
+		write_lock(&fs->lock);
+
+		p = namespace->root;
+		q = new_ns->root;
+		while (p) {
+			if (p == fs->rootmnt) {
+				rootmnt = p;
+				fs->rootmnt = mntget(q);
+			}
+			if (p == fs->pwdmnt) {
+				pwdmnt = p;
+				fs->pwdmnt = mntget(q);
+			}
+			if (p == fs->altrootmnt) {
+				altrootmnt = p;
+				fs->altrootmnt = mntget(q);
+			}
+			p = next_mnt(p, namespace->root);
+			q = next_mnt(q, new_ns->root);
+		}
+		write_unlock(&fs->lock);
+	}
+	up_write(&tsk->namespace->sem);
+
+	tsk->namespace = new_ns;
+
+	if (rootmnt)
+		mntput(rootmnt);
+	if (pwdmnt)
+		mntput(pwdmnt);
+	if (altrootmnt)
+		mntput(altrootmnt);
+
+	put_namespace(namespace);
+	return 0;
+
+out:
+	put_namespace(namespace);
+	return -ENOMEM;
+}
+
 asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
 			  unsigned long flags, void * data)
 {
@@ -862,7 +953,7 @@
 	user_nd.mnt = mntget(current->fs->rootmnt);
 	user_nd.dentry = dget(current->fs->root);
 	read_unlock(&current->fs->lock);
-	down(&mount_sem);
+	down_write(&current->namespace->sem);
 	down(&old_nd.dentry->d_inode->i_zombie);
 	error = -EINVAL;
 	if (!check_mnt(user_nd.mnt))
@@ -907,7 +998,7 @@
 	path_release(&parent_nd);
 out2:
 	up(&old_nd.dentry->d_inode->i_zombie);
-	up(&mount_sem);
+	up_write(&current->namespace->sem);
 	path_release(&user_nd);
 	path_release(&old_nd);
 out1:
@@ -920,95 +1011,34 @@
 	goto out2;
 }
 
-/*
- * Absolutely minimal fake fs - only empty root directory and nothing else.
- * In 2.5 we'll use ramfs or tmpfs, but for now it's all we need - just
- * something to go with root vfsmount.
- */
-static struct inode_operations rootfs_dir_inode_operations;
-static struct file_operations rootfs_dir_operations;
-static int rootfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
-{
-	struct inode * inode = new_inode(dir->i_sb);
-	int error = -ENOSPC;
-	if (inode) {
-		inode->i_mode = S_IFDIR|mode;
-		inode->i_uid = current->fsuid;
-		inode->i_gid = current->fsgid;
-		inode->i_op = &rootfs_dir_inode_operations;
-		inode->i_fop = &rootfs_dir_operations;
-		d_instantiate(dentry, inode);
-		dget(dentry);
-		error = 0;
-	}
-	return error;
-}
-static int rootfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev)
-{
-	struct inode * inode = new_inode(dir->i_sb);
-	int error = -ENOSPC;
-	if (inode) {
-		inode->i_uid = current->fsuid;
-		inode->i_gid = current->fsgid;
-		init_special_inode(inode, mode, dev);
-		d_instantiate(dentry, inode);
-		dget(dentry);
-		error = 0;
-	}
-	return error;
-}
-static int rootfs_unlink(struct inode * dir, struct dentry *dentry)
-{
-	dentry->d_inode->i_nlink--;
-	dput(dentry);
-	return 0;
-}
-static struct dentry *rootfs_lookup(struct inode *dir, struct dentry *dentry)
-{
-	d_add(dentry, NULL);
-	return NULL;
-}
-static struct file_operations rootfs_dir_operations = {
-	read:		generic_read_dir,
-	readdir:	dcache_readdir,
-};
-static struct inode_operations rootfs_dir_inode_operations = {
-	lookup:		rootfs_lookup,
-	mkdir:		rootfs_mkdir,
-	mknod:		rootfs_mknod,
-	unlink:		rootfs_unlink,
-};
-static struct super_block *rootfs_read_super(struct super_block * sb, void * data, int silent)
+static void __init init_mount_tree(void)
 {
-	struct inode * inode;
-	struct dentry * root;
-	static struct super_operations s_ops = {};
-	sb->s_op = &s_ops;
-	inode = new_inode(sb);
-	if (!inode)
-		return NULL;
-	inode->i_mode = S_IFDIR|0555;
-	inode->i_uid = inode->i_gid = 0;
-	inode->i_op = &rootfs_dir_inode_operations;
-	inode->i_fop = &rootfs_dir_operations;
-	root = d_alloc_root(inode);
-	if (!root) {
-		iput(inode);
-		return NULL;
+	struct vfsmount *mnt;
+	struct namespace *namespace;
+	struct task_struct *p;
+
+	mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
+	if (IS_ERR(mnt))
+		panic("Can't create rootfs");
+	namespace = kmalloc(sizeof(*namespace), GFP_KERNEL);
+	if (!namespace)
+		panic("Can't allocate initial namespace");
+	atomic_set(&namespace->count, 1);
+	INIT_LIST_HEAD(&namespace->list);
+	init_rwsem(&namespace->sem);
+	list_add(&mnt->mnt_list, &namespace->list);
+	namespace->root = mnt;
+
+	init_task.namespace = namespace;
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		get_namespace(namespace);
+		p->namespace = namespace;
 	}
-	sb->s_root = root;
-	return sb;
-}
-static DECLARE_FSTYPE(root_fs_type, "rootfs", rootfs_read_super, FS_NOMOUNT);
+	read_unlock(&tasklist_lock);
 
-static void __init init_mount_tree(void)
-{
-	register_filesystem(&root_fs_type);
-	root_vfsmnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
-	if (IS_ERR(root_vfsmnt))
-		panic("can't allocate root vfsmount");
-	set_fs_pwd(current->fs, root_vfsmnt, root_vfsmnt->mnt_root);
-	set_fs_root(current->fs, root_vfsmnt, root_vfsmnt->mnt_root);
+	set_fs_pwd(current->fs, namespace->root, namespace->root->mnt_root);
+	set_fs_root(current->fs, namespace->root, namespace->root->mnt_root);
 }
 
 void __init mnt_init(unsigned long mempages)
@@ -1066,5 +1096,6 @@
 		d++;
 		i--;
 	} while (i);
+	init_rootfs();
 	init_mount_tree();
 }
diff -u --recursive --new-file v2.5.1/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v2.5.1/linux/fs/ncpfs/inode.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/ncpfs/inode.c	Thu Jan  3 12:20:18 2002
@@ -181,7 +181,7 @@
 	inode->i_nlink = 1;
 	inode->i_uid = server->m.uid;
 	inode->i_gid = server->m.gid;
-	inode->i_rdev = 0;
+	inode->i_rdev = NODEV;
 	inode->i_blksize = NCP_BLOCK_SIZE;
 
 	inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
diff -u --recursive --new-file v2.5.1/linux/fs/ncpfs/symlink.c linux/fs/ncpfs/symlink.c
--- v2.5.1/linux/fs/ncpfs/symlink.c	Fri Dec 29 14:07:57 2000
+++ linux/fs/ncpfs/symlink.c	Sun Dec 30 10:31:51 2001
@@ -21,7 +21,6 @@
 #ifdef CONFIG_NCPFS_EXTRAS
 
 #include <asm/uaccess.h>
-#include <asm/segment.h>
 
 #include <linux/errno.h>
 #include <linux/fs.h>
diff -u --recursive --new-file v2.5.1/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.5.1/linux/fs/nfs/dir.c	Tue Jun 12 11:15:08 2001
+++ linux/fs/nfs/dir.c	Tue Jan  1 12:06:14 2002
@@ -643,8 +643,8 @@
 	struct nfs_fh fhandle;
 	int error;
 
-	dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name);
+	dfprintk(VFS, "NFS: create(%x:%x/%ld, %s\n",
+		major(dir->i_dev), minor(dir->i_dev), dir->i_ino, dentry->d_name.name);
 
 	attr.ia_mode = mode;
 	attr.ia_valid = ATTR_MODE;
@@ -675,8 +675,8 @@
 	struct nfs_fh fhandle;
 	int error;
 
-	dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name);
+	dfprintk(VFS, "NFS: mknod(%x:%x/%ld, %s\n",
+		major(dir->i_dev), minor(dir->i_dev), dir->i_ino, dentry->d_name.name);
 
 	attr.ia_mode = mode;
 	attr.ia_valid = ATTR_MODE;
@@ -701,8 +701,8 @@
 	struct nfs_fh fhandle;
 	int error;
 
-	dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name);
+	dfprintk(VFS, "NFS: mkdir(%x:%x/%ld, %s\n",
+		major(dir->i_dev), minor(dir->i_dev), dir->i_ino, dentry->d_name.name);
 
 	attr.ia_valid = ATTR_MODE;
 	attr.ia_mode = mode | S_IFDIR;
@@ -730,8 +730,8 @@
 {
 	int error;
 
-	dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name);
+	dfprintk(VFS, "NFS: rmdir(%x:%x/%ld, %s\n",
+		major(dir->i_dev), minor(dir->i_dev), dir->i_ino, dentry->d_name.name);
 
 	nfs_zap_caches(dir);
 	error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
@@ -877,8 +877,8 @@
 {
 	int error;
 
-	dfprintk(VFS, "NFS: unlink(%x/%ld, %s)\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name);
+	dfprintk(VFS, "NFS: unlink(%x:%x/%ld, %s)\n",
+		major(dir->i_dev), minor(dir->i_dev), dir->i_ino, dentry->d_name.name);
 
 	error = nfs_sillyrename(dir, dentry);
 	if (error && error != -EBUSY) {
@@ -900,8 +900,8 @@
 	unsigned int maxlen;
 	int error;
 
-	dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name, symname);
+	dfprintk(VFS, "NFS: symlink(%x:%x/%ld, %s, %s)\n",
+		major(dir->i_dev), minor(dir->i_dev), dir->i_ino, dentry->d_name.name, symname);
 
 	error = -ENAMETOOLONG;
 	maxlen = (NFS_PROTO(dir)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN;
diff -u --recursive --new-file v2.5.1/linux/fs/nfs/file.c linux/fs/nfs/file.c
--- v2.5.1/linux/fs/nfs/file.c	Sun Sep 23 09:48:01 2001
+++ linux/fs/nfs/file.c	Tue Jan  1 13:22:31 2002
@@ -73,7 +73,8 @@
 	struct inode	*inode = file->f_dentry->d_inode;
 	int		status;
 
-	dfprintk(VFS, "nfs: flush(%x/%ld)\n", inode->i_dev, inode->i_ino);
+	dfprintk(VFS, "nfs: flush(%02x:%02x/%ld)\n",
+		major(inode->i_dev), minor(inode->i_dev), inode->i_ino);
 
 	/* Make sure all async reads have been sent off. We don't bother
 	 * waiting on them though... */
@@ -132,7 +133,8 @@
 	struct inode *inode = dentry->d_inode;
 	int status;
 
-	dfprintk(VFS, "nfs: fsync(%x/%ld)\n", inode->i_dev, inode->i_ino);
+	dfprintk(VFS, "nfs: fsync(%02x:%02x/%ld)\n",
+		major(inode->i_dev), minor(inode->i_dev), inode->i_ino);
 
 	lock_kernel();
 	status = nfs_wb_file(inode, file);
@@ -161,15 +163,10 @@
 static int nfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
 {
 	long status;
-	loff_t pos = ((loff_t)page->index<<PAGE_CACHE_SHIFT) + to;
-	struct inode *inode = page->mapping->host;
 
 	lock_kernel();
 	status = nfs_updatepage(file, page, offset, to-offset);
 	unlock_kernel();
-	/* most likely it's already done. CHECKME */
-	if (pos > inode->i_size)
-		inode->i_size = pos;
 	return status;
 }
 
@@ -250,8 +247,8 @@
 	struct inode * inode = filp->f_dentry->d_inode;
 	int	status = 0;
 
-	dprintk("NFS: nfs_lock(f=%4x/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n",
-			inode->i_dev, inode->i_ino,
+	dprintk("NFS: nfs_lock(f=%02x:%02x/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n",
+			major(inode->i_dev), minor(inode->i_dev), inode->i_ino,
 			fl->fl_type, fl->fl_flags,
 			(long long)fl->fl_start, (long long)fl->fl_end);
 
diff -u --recursive --new-file v2.5.1/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.5.1/linux/fs/nfs/inode.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/nfs/inode.c	Tue Jan  1 12:09:34 2002
@@ -104,20 +104,13 @@
 {
 	inode->i_blksize = inode->i_sb->s_blocksize;
 	inode->i_mode = 0;
-	inode->i_rdev = 0;
+	inode->i_rdev = NODEV;
 	/* We can't support UPDATE_ATIME(), since the server will reset it */
 	inode->i_flags |= S_NOATIME;
-	NFS_FILEID(inode) = 0;
-	NFS_FSID(inode) = 0;
-	NFS_FLAGS(inode) = 0;
 	INIT_LIST_HEAD(&inode->u.nfs_i.read);
 	INIT_LIST_HEAD(&inode->u.nfs_i.dirty);
 	INIT_LIST_HEAD(&inode->u.nfs_i.commit);
 	INIT_LIST_HEAD(&inode->u.nfs_i.writeback);
-	inode->u.nfs_i.nread = 0;
-	inode->u.nfs_i.ndirty = 0;
-	inode->u.nfs_i.ncommit = 0;
-	inode->u.nfs_i.npages = 0;
 	NFS_CACHEINV(inode);
 	NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
 	NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
@@ -134,7 +127,7 @@
 static void
 nfs_delete_inode(struct inode * inode)
 {
-	dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
+	dprintk("NFS: delete_inode(%x:%x/%ld)\n", major(inode->i_dev), minor(inode->i_dev), inode->i_ino);
 
 	/*
 	 * The following can never actually happen...
@@ -655,19 +648,6 @@
 			inode->i_op = &nfs_symlink_inode_operations;
 		else
 			init_special_inode(inode, inode->i_mode, fattr->rdev);
-		/*
-		 * Preset the size and mtime, as there's no need
-		 * to invalidate the caches.
-		 */ 
-		inode->i_size  = nfs_size_to_loff_t(fattr->size);
-		inode->i_mtime = nfs_time_to_secs(fattr->mtime);
-		inode->i_atime = nfs_time_to_secs(fattr->atime);
-		inode->i_ctime = nfs_time_to_secs(fattr->ctime);
-		NFS_CACHE_CTIME(inode) = fattr->ctime;
-		NFS_CACHE_MTIME(inode) = fattr->mtime;
-		NFS_CACHE_ISIZE(inode) = fattr->size;
-		NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
-		NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
 		memcpy(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh));
 	}
 	nfs_refresh_inode(inode, fattr);
@@ -697,6 +677,9 @@
 		return 0;
 	if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0)
 		return 0;
+	/* Force an attribute cache update if inode->i_count == 0 */
+	if (!atomic_read(&inode->i_count))
+		NFS_CACHEINV(inode);
 	return 1;
 }
 
@@ -764,8 +747,9 @@
 		goto out_no_inode;
 
 	nfs_fill_inode(inode, fh, fattr);
-	dprintk("NFS: __nfs_fhget(%x/%Ld ct=%d)\n",
-		inode->i_dev, (long long)NFS_FILEID(inode),
+	dprintk("NFS: __nfs_fhget(%x:%x/%Ld ct=%d)\n",
+		major(inode->i_dev), minor(inode->i_dev),
+		(long long)NFS_FILEID(inode),
 		atomic_read(&inode->i_count));
 
 out:
@@ -797,7 +781,9 @@
 	if (!S_ISREG(inode->i_mode))
 		attr->ia_valid &= ~ATTR_SIZE;
 
+	filemap_fdatasync(inode->i_mapping);
 	error = nfs_wb_all(inode);
+	filemap_fdatawait(inode->i_mapping);
 	if (error)
 		goto out;
 
@@ -825,6 +811,8 @@
 		fattr.pre_ctime = NFS_CACHE_CTIME(inode);
 		fattr.valid |= NFS_ATTR_WCC;
 	}
+	/* Force an attribute cache update */
+	NFS_CACHEINV(inode);
 	error = nfs_refresh_inode(inode, &fattr);
 out:
 	return error;
@@ -915,8 +903,9 @@
 	int		 status = -ESTALE;
 	struct nfs_fattr fattr;
 
-	dfprintk(PAGECACHE, "NFS: revalidating (%x/%Ld)\n",
-		inode->i_dev, (long long)NFS_FILEID(inode));
+	dfprintk(PAGECACHE, "NFS: revalidating (%x:%x/%Ld)\n",
+		major(inode->i_dev), minor(inode->i_dev),
+		(long long)NFS_FILEID(inode));
 
 	lock_kernel();
 	if (!inode || is_bad_inode(inode))
@@ -937,8 +926,9 @@
 
 	status = NFS_PROTO(inode)->getattr(inode, &fattr);
 	if (status) {
-		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) getattr failed, error=%d\n",
-			 inode->i_dev, (long long)NFS_FILEID(inode), status);
+		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x:%x/%Ld) getattr failed, error=%d\n",
+			 major(inode->i_dev), minor(inode->i_dev),
+			 (long long)NFS_FILEID(inode), status);
 		if (status == -ESTALE) {
 			NFS_FLAGS(inode) |= NFS_INO_STALE;
 			if (inode != inode->i_sb->s_root->d_inode)
@@ -949,12 +939,14 @@
 
 	status = nfs_refresh_inode(inode, &fattr);
 	if (status) {
-		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) refresh failed, error=%d\n",
-			 inode->i_dev, (long long)NFS_FILEID(inode), status);
+		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x:%x/%Ld) refresh failed, error=%d\n",
+			 major(inode->i_dev), minor(inode->i_dev),
+			 (long long)NFS_FILEID(inode), status);
 		goto out;
 	}
-	dfprintk(PAGECACHE, "NFS: (%x/%Ld) revalidation complete\n",
-		inode->i_dev, (long long)NFS_FILEID(inode));
+	dfprintk(PAGECACHE, "NFS: (%x:%x/%Ld) revalidation complete\n",
+		major(inode->i_dev), minor(inode->i_dev),
+		(long long)NFS_FILEID(inode));
 
 	NFS_FLAGS(inode) &= ~NFS_INO_STALE;
 out:
@@ -966,6 +958,34 @@
 }
 
 /*
+ * nfs_fattr_obsolete - Test if attribute data is newer than cached data
+ * @inode: inode
+ * @fattr: attributes to test
+ *
+ * Avoid stuffing the attribute cache with obsolete information.
+ * We always accept updates if the attribute cache timed out, or if
+ * fattr->ctime is newer than our cached value.
+ * If fattr->ctime matches the cached value, we still accept the update
+ * if it increases the file size.
+ */
+static inline
+int nfs_fattr_obsolete(struct inode *inode, struct nfs_fattr *fattr)
+{
+	s64 cdif;
+
+	if (time_after(jiffies, NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
+		goto out_valid;
+	if ((cdif = (s64)fattr->ctime - (s64)NFS_CACHE_CTIME(inode)) > 0)
+		goto out_valid;
+	/* Ugh... */
+	if (cdif == 0 && fattr->size > NFS_CACHE_ISIZE(inode))
+		goto out_valid;
+	return -1;
+ out_valid:
+	return 0;
+}
+
+/*
  * Many nfs protocol calls return the new file attributes after
  * an operation.  Here we update the inode to reflect the state
  * of the server's inode.
@@ -982,10 +1002,11 @@
 {
 	__u64		new_size, new_mtime;
 	loff_t		new_isize;
+	time_t		new_atime;
 	int		invalid = 0;
 
-	dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d info=0x%x)\n",
-			inode->i_dev, inode->i_ino,
+	dfprintk(VFS, "NFS: refresh_inode(%x:%x/%ld ct=%d info=0x%x)\n",
+			major(inode->i_dev), minor(inode->i_dev), inode->i_ino,
 			atomic_read(&inode->i_count), fattr->valid);
 
 	if (NFS_FSID(inode) != fattr->fsid ||
@@ -1007,6 +1028,11 @@
 	new_size = fattr->size;
  	new_isize = nfs_size_to_loff_t(fattr->size);
 
+	new_atime = nfs_time_to_secs(fattr->atime);
+	/* Avoid races */
+	if (nfs_fattr_obsolete(inode, fattr))
+		goto out_nochange;
+
 	/*
 	 * Update the read time so we don't revalidate too often.
 	 */
@@ -1056,7 +1082,7 @@
 	NFS_CACHE_CTIME(inode) = fattr->ctime;
 	inode->i_ctime = nfs_time_to_secs(fattr->ctime);
 
-	inode->i_atime = nfs_time_to_secs(fattr->atime);
+	inode->i_atime = new_atime;
 
 	NFS_CACHE_MTIME(inode) = new_mtime;
 	inode->i_mtime = nfs_time_to_secs(new_mtime);
@@ -1079,7 +1105,7 @@
  		inode->i_blocks = fattr->du.nfs2.blocks;
  		inode->i_blksize = fattr->du.nfs2.blocksize;
  	}
- 	inode->i_rdev = 0;
+ 	inode->i_rdev = NODEV;
  	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
  		inode->i_rdev = to_kdev_t(fattr->rdev);
  
@@ -1093,7 +1119,10 @@
 	if (invalid)
 		nfs_zap_caches(inode);
 	return 0;
-
+ out_nochange:
+	if (new_atime - inode->i_atime > 0)
+		inode->i_atime = new_atime;
+	return 0;
  out_changed:
 	/*
 	 * Big trouble! The inode has become a different object.
diff -u --recursive --new-file v2.5.1/linux/fs/nfs/nfs2xdr.c linux/fs/nfs/nfs2xdr.c
--- v2.5.1/linux/fs/nfs/nfs2xdr.c	Fri Nov  2 17:40:09 2001
+++ linux/fs/nfs/nfs2xdr.c	Thu Dec 20 08:57:31 2001
@@ -270,14 +270,12 @@
 
 	count = ntohl(*p++);
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
-	recvd = req->rq_rlen - hdrlen;
-	if (p != iov[req->rq_rnr-1].iov_base) {
-		/* Unexpected reply header size. Punt.
-		 * XXX: Move iovec contents to align data on page
-		 * boundary and adjust RPC header size guess */
-		printk(KERN_WARNING "NFS: Odd RPC header size in read reply: %d\n", hdrlen);
-		return -errno_NFSERR_IO;
+	if (iov->iov_len > hdrlen) {
+		dprintk("NFS: READ header is short. iovec will be shifted.\n");
+		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
 	}
+
+	recvd = req->rq_rlen - hdrlen;
 	if (count > recvd) {
 		printk(KERN_WARNING "NFS: server cheating in read reply: "
 			"count %d > recvd %d\n", count, recvd);
@@ -448,27 +446,23 @@
 nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
 {
 	struct iovec		*iov = req->rq_rvec;
+	int			 hdrlen;
 	int			 status, nr;
 	u32			*end, *entry, len;
 
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
-	if ((void *) p != ((u8 *) iov->iov_base+iov->iov_len)) {
-		/* Unexpected reply header size. Punt. */
-		printk(KERN_WARNING "NFS: Odd RPC header size in readdirres reply\n");
-		return -errno_NFSERR_IO;
+
+	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
+	if (iov->iov_len > hdrlen) {
+		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
+		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
 	}
 
+
 	/* Get start and end address of XDR data */
 	p   = (u32 *) iov[1].iov_base;
 	end = (u32 *) ((u8 *) p + iov[1].iov_len);
-
-	/* Get start and end of dirent buffer */
-	if (res->buffer != p) {
-		printk(KERN_ERR "NFS: Bad result buffer in readdir\n");
-		return -errno_NFSERR_IO;
-	}
-
 	for (nr = 0; *p++; nr++) {
 		entry = p - 1;
 		if (p + 2 > end)
@@ -598,13 +592,21 @@
 static int
 nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_readlinkres *res)
 {
+	struct iovec *iov = req->rq_rvec;
 	u32	*strlen;
 	char	*string;
+	int	hdrlen;
 	int	status;
 	unsigned int len;
 
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
+	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
+	if (iov->iov_len > hdrlen) {
+		dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
+		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+	}
+
 	strlen = (u32*)res->buffer;
 	/* Convert length of symlink */
 	len = ntohl(*strlen);
diff -u --recursive --new-file v2.5.1/linux/fs/nfs/read.c linux/fs/nfs/read.c
--- v2.5.1/linux/fs/nfs/read.c	Fri Nov  9 14:28:15 2001
+++ linux/fs/nfs/read.c	Tue Jan  1 12:11:08 2002
@@ -108,9 +108,10 @@
 		if (count < rsize)
 			rsize = count;
 
-		dprintk("NFS: nfs_proc_read(%s, (%x/%Ld), %Ld, %d, %p)\n",
+		dprintk("NFS: nfs_proc_read(%s, (%x:%x/%Ld), %Ld, %d, %p)\n",
 			NFS_SERVER(inode)->hostname,
-			inode->i_dev, (long long)NFS_FILEID(inode),
+			major(inode->i_dev), minor(inode->i_dev),
+			(long long)NFS_FILEID(inode),
 			(long long)offset, rsize, buffer);
 
 		lock_kernel();
@@ -265,9 +266,10 @@
 	msg.rpc_cred = data->cred;
 
 	/* Start the async call */
-	dprintk("NFS: %4d initiated read call (req %x/%Ld count %d nriov %d.\n",
+	dprintk("NFS: %4d initiated read call (req %x:%x/%Ld count %d nriov %d.\n",
 		task->tk_pid,
-		inode->i_dev, (long long)NFS_FILEID(inode),
+		major(inode->i_dev), minor(inode->i_dev),
+		(long long)NFS_FILEID(inode),
 		data->args.count, data->args.nriov);
 
 	rpc_clnt_sigmask(clnt, &oldset);
@@ -397,7 +399,7 @@
 {
 	struct nfs_read_data	*data = (struct nfs_read_data *) task->tk_calldata;
 	struct inode		*inode = data->inode;
-	int			count = data->res.count;
+	unsigned int		count = data->res.count;
 
 	dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
 		task->tk_pid, task->tk_status);
@@ -408,17 +410,24 @@
 		struct page *page = req->wb_page;
 		nfs_list_remove_request(req);
 
-		if (task->tk_status >= 0 && count >= 0) {
+		if (task->tk_status >= 0) {
+			if (count < PAGE_CACHE_SIZE) {
+				char *p = kmap(page);
+				memset(p + count, 0, PAGE_CACHE_SIZE - count);
+				kunmap(page);
+				count = 0;
+			} else
+				count -= PAGE_CACHE_SIZE;
 			SetPageUptodate(page);
-			count -= PAGE_CACHE_SIZE;
 		} else
 			SetPageError(page);
 		flush_dcache_page(page);
 		kunmap(page);
 		UnlockPage(page);
 
-		dprintk("NFS: read (%x/%Ld %d@%Ld)\n",
-                        req->wb_inode->i_dev,
+		dprintk("NFS: read (%x:%x/%Ld %d@%Ld)\n",
+                        major(req->wb_inode->i_dev),
+                        minor(req->wb_inode->i_dev),
                         (long long)NFS_FILEID(req->wb_inode),
                         req->wb_bytes,
                         (long long)(page_offset(page) + req->wb_offset));
diff -u --recursive --new-file v2.5.1/linux/fs/nfs/write.c linux/fs/nfs/write.c
--- v2.5.1/linux/fs/nfs/write.c	Tue Nov 20 14:18:50 2001
+++ linux/fs/nfs/write.c	Tue Jan  1 18:08:28 2002
@@ -49,7 +49,7 @@
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/slab.h>
-#include <linux/swap.h>
+#include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/file.h>
 
@@ -159,8 +159,9 @@
 	if (!cred)
 		cred = get_rpccred(NFS_I(inode)->mm_cred);
 
-	dprintk("NFS:      nfs_writepage_sync(%x/%Ld %d@%Ld)\n",
-		inode->i_dev, (long long)NFS_FILEID(inode),
+	dprintk("NFS:      nfs_writepage_sync(%x:%x/%Ld %d@%Ld)\n",
+		major(inode->i_dev), minor(inode->i_dev),
+		(long long)NFS_FILEID(inode),
 		count, (long long)(page_offset(page) + offset));
 
 	buffer = kmap(page) + offset;
@@ -213,6 +214,7 @@
 		    unsigned int offset, unsigned int count)
 {
 	struct nfs_page	*req;
+	loff_t		end;
 	int		status;
 
 	req = nfs_update_request(file, inode, page, offset, count);
@@ -223,6 +225,10 @@
 		req->wb_cred = get_rpccred(NFS_I(inode)->mm_cred);
 	nfs_unlock_request(req);
 	nfs_strategy(inode);
+	end = ((loff_t)page->index<<PAGE_CACHE_SHIFT) + (loff_t)(offset + count);
+	if (inode->i_size < end)
+		inode->i_size = end;
+
  out:
 	return status;
 }
@@ -781,6 +787,7 @@
 	struct dentry	*dentry = file->f_dentry;
 	struct inode	*inode = dentry->d_inode;
 	struct nfs_page	*req;
+	loff_t		end;
 	int		status = 0;
 
 	dprintk("NFS:      nfs_updatepage(%s/%s %d@%Ld)\n",
@@ -812,6 +819,10 @@
 		goto done;
 
 	status = 0;
+	end = ((loff_t)page->index<<PAGE_CACHE_SHIFT) + (loff_t)(offset + count);
+	if (inode->i_size < end)
+		inode->i_size = end;
+
 	/* If we wrote past the end of the page.
 	 * Call the strategy routine so it can send out a bunch
 	 * of requests.
@@ -924,9 +935,9 @@
 	msg.rpc_resp = &data->res;
 	msg.rpc_cred = data->cred;
 
-	dprintk("NFS: %4d initiated write call (req %x/%Ld count %d nriov %d)\n",
+	dprintk("NFS: %4d initiated write call (req %x:%x/%Ld count %d nriov %d)\n",
 		task->tk_pid, 
-		inode->i_dev,
+		major(inode->i_dev), minor(inode->i_dev),
 		(long long)NFS_FILEID(inode),
 		data->args.count, data->args.nriov);
 
@@ -1039,8 +1050,9 @@
 
 		kunmap(page);
 
-		dprintk("NFS: write (%x/%Ld %d@%Ld)",
-			req->wb_inode->i_dev,
+		dprintk("NFS: write (%x:%x/%Ld %d@%Ld)",
+			major(req->wb_inode->i_dev),
+			minor(req->wb_inode->i_dev),
 			(long long)NFS_FILEID(req->wb_inode),
 			req->wb_bytes,
 			(long long)(page_offset(page) + req->wb_offset));
@@ -1189,8 +1201,9 @@
 		req = nfs_list_entry(data->pages.next);
 		nfs_list_remove_request(req);
 
-		dprintk("NFS: commit (%x/%Ld %d@%Ld)",
-			req->wb_inode->i_dev,
+		dprintk("NFS: commit (%02x:%02x/%Ld %d@%Ld)",
+			major(req->wb_inode->i_dev),
+			minor(req->wb_inode->i_dev),
 			(long long)NFS_FILEID(req->wb_inode),
 			req->wb_bytes,
 			(long long)(page_offset(req->wb_page) + req->wb_offset));
diff -u --recursive --new-file v2.5.1/linux/fs/nfsd/export.c linux/fs/nfsd/export.c
--- v2.5.1/linux/fs/nfsd/export.c	Wed Oct  3 22:57:36 2001
+++ linux/fs/nfsd/export.c	Tue Jan  1 12:47:16 2002
@@ -16,6 +16,7 @@
 
 #include <linux/unistd.h>
 #include <linux/slab.h>
+#include <linux/sched.h>
 #include <linux/stat.h>
 #include <linux/in.h>
 
@@ -49,7 +50,7 @@
 #define CLIENT_HASH(a) \
 		((((a)>>24) ^ ((a)>>16) ^ ((a)>>8) ^(a)) & CLIENT_HASHMASK)
 /* XXX: is this adequate for 32bit kdev_t ? */
-#define EXPORT_HASH(dev)	((dev) & (NFSCLNT_EXPMAX - 1))
+#define EXPORT_HASH(dev)	(minor(dev) & (NFSCLNT_EXPMAX - 1))
 
 struct svc_clnthash {
 	struct svc_clnthash *	h_next;
@@ -75,7 +76,7 @@
 	svc_export *	exp;
 
 	exp = clp->cl_export[EXPORT_HASH(dev)];
-	while (exp && exp->ex_dev != dev)
+	while (exp && !kdev_same(exp->ex_dev, dev))
 		exp = exp->ex_next;
 	return exp;
 }
@@ -94,7 +95,7 @@
 	exp = clp->cl_export[EXPORT_HASH(dev)];
 	if (exp)
 		do {
-			if (exp->ex_ino == ino && exp->ex_dev == dev)
+			if (exp->ex_ino == ino && kdev_same(exp->ex_dev, dev))
 				goto out;
 		} while (NULL != (exp = exp->ex_next));
 	exp = NULL;
@@ -197,9 +198,10 @@
 
 	inode = nd.dentry->d_inode;
 	err = -EINVAL;
-	if (inode->i_dev != dev || inode->i_ino != nxp->ex_ino) {
-		printk(KERN_DEBUG "exp_export: i_dev = %x, dev = %x\n",
-			inode->i_dev, dev); 
+	if (!kdev_same(inode->i_dev, dev) || inode->i_ino != nxp->ex_ino) {
+		printk(KERN_DEBUG "exp_export: i_dev = %02x:%02x, dev = %02x:%02x\n",
+			major(inode->i_dev), minor(inode->i_dev),
+			major(dev), minor(dev)); 
 		/* I'm just being paranoid... */
 		goto finish;
 	}
@@ -301,7 +303,7 @@
 	dentry = unexp->ex_dentry;
 	mnt = unexp->ex_mnt;
 	inode = dentry->d_inode;
-	if (unexp->ex_dev != inode->i_dev || unexp->ex_ino != inode->i_ino)
+	if (!kdev_same(unexp->ex_dev, inode->i_dev) || unexp->ex_ino != inode->i_ino)
 		printk(KERN_WARNING "nfsd: bad dentry in unexport!\n");
 	dput(dentry);
 	mntput(mnt);
@@ -352,9 +354,10 @@
 	err = -EINVAL;
 	clp = exp_getclientbyname(nxp->ex_client);
 	if (clp) {
-		expp = clp->cl_export + EXPORT_HASH(nxp->ex_dev);
+		kdev_t ex_dev = to_kdev_t(nxp->ex_dev);
+		expp = clp->cl_export + EXPORT_HASH(ex_dev);
 		while ((exp = *expp) != NULL) {
-			if (exp->ex_dev == nxp->ex_dev) {
+			if (kdev_same(exp->ex_dev, ex_dev)) {
 				if (exp->ex_ino == nxp->ex_ino) {
 					*expp = exp->ex_next;
 					exp_do_unexport(exp);
@@ -396,12 +399,13 @@
 		dev = nd.dentry->d_inode->i_dev;
 		ino = nd.dentry->d_inode->i_ino;
 	
-		dprintk("nfsd: exp_rootfh(%s [%p] %s:%x/%ld)\n",
-		         path, nd.dentry, clp->cl_ident, dev, (long) ino);
+		dprintk("nfsd: exp_rootfh(%s [%p] %s:%02x:%02x/%ld)\n",
+		         path, nd.dentry, clp->cl_ident,
+		         major(dev), minor(dev), (long) ino);
 		exp = exp_parent(clp, dev, nd.dentry);
 	} else {
-		dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n",
-		         clp->cl_ident, dev, (long) ino);
+		dprintk("nfsd: exp_rootfh(%s:%02x:%02x/%ld)\n",
+		         clp->cl_ident, major(dev), minor(dev), (long) ino);
 		if ((exp = exp_get(clp, dev, ino))) {
 			nd.mnt = mntget(exp->ex_mnt);
 			nd.dentry = dget(exp->ex_dentry);
@@ -417,11 +421,12 @@
 		printk("exp_rootfh: Aieee, NULL d_inode\n");
 		goto out;
 	}
-	if (inode->i_dev != dev || inode->i_ino != ino) {
+	if (!kdev_same(inode->i_dev, dev) || inode->i_ino != ino) {
 		printk("exp_rootfh: Aieee, ino/dev mismatch\n");
-		printk("exp_rootfh: arg[dev(%x):ino(%ld)]"
-		       " inode[dev(%x):ino(%ld)]\n",
-		       dev, (long) ino, inode->i_dev, (long) inode->i_ino);
+		printk("exp_rootfh: arg[dev(%02x:%02x):ino(%ld)]"
+		       " inode[dev(%02x:%02x):ino(%ld)]\n",
+		       major(dev), minor(dev), (long) ino,
+		       major(inode->i_dev), minor(inode->i_dev), (long) inode->i_ino);
 	}
 
 	/*
diff -u --recursive --new-file v2.5.1/linux/fs/nfsd/nfs3xdr.c linux/fs/nfsd/nfs3xdr.c
--- v2.5.1/linux/fs/nfsd/nfs3xdr.c	Wed Oct  3 22:27:48 2001
+++ linux/fs/nfsd/nfs3xdr.c	Thu Jan  3 12:20:18 2002
@@ -173,9 +173,9 @@
 		p = xdr_encode_hyper(p, (u64)(inode->i_size +511)& ~511);
 	else
 		p = xdr_encode_hyper(p, ((u64)inode->i_blocks) << 9);
-	*p++ = htonl((u32) MAJOR(inode->i_rdev));
-	*p++ = htonl((u32) MINOR(inode->i_rdev));
-	p = xdr_encode_hyper(p, (u64) inode->i_dev);
+	*p++ = htonl((u32) major(inode->i_rdev));
+	*p++ = htonl((u32) minor(inode->i_rdev));
+	p = xdr_encode_hyper(p, (u64) kdev_t_to_nr(inode->i_dev));
 	p = xdr_encode_hyper(p, (u64) inode->i_ino);
 	p = encode_time3(p, inode->i_atime);
 	p = encode_time3(p, lease_get_mtime(inode));
@@ -203,9 +203,9 @@
 		p = xdr_encode_hyper(p, (u64) fhp->fh_post_size);
 	}
 	p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
-	*p++ = htonl((u32) MAJOR(fhp->fh_post_rdev));
-	*p++ = htonl((u32) MINOR(fhp->fh_post_rdev));
-	p = xdr_encode_hyper(p, (u64) inode->i_dev);
+	*p++ = htonl((u32) major(fhp->fh_post_rdev));
+	*p++ = htonl((u32) minor(fhp->fh_post_rdev));
+	p = xdr_encode_hyper(p, (u64) kdev_t_to_nr(inode->i_dev));
 	p = xdr_encode_hyper(p, (u64) inode->i_ino);
 	p = encode_time3(p, fhp->fh_post_atime);
 	p = encode_time3(p, fhp->fh_post_mtime);
diff -u --recursive --new-file v2.5.1/linux/fs/nfsd/nfsctl.c linux/fs/nfsd/nfsctl.c
--- v2.5.1/linux/fs/nfsd/nfsctl.c	Sun Oct 21 10:32:33 2001
+++ linux/fs/nfsd/nfsctl.c	Tue Jan  1 12:21:20 2002
@@ -125,7 +125,7 @@
 	if (!(clp = exp_getclient(sin)))
 		err = -EPERM;
 	else
-		err = exp_rootfh(clp, 0, 0, data->gd_path, res, data->gd_maxlen);
+		err = exp_rootfh(clp, NODEV, 0, data->gd_path, res, data->gd_maxlen);
 	exp_unlock();
 	return err;
 }
@@ -148,7 +148,7 @@
 	if (!(clp = exp_getclient(sin)))
 		err = -EPERM;
 	else
-		err = exp_rootfh(clp, 0, 0, data->gd_path, &fh, NFS_FHSIZE);
+		err = exp_rootfh(clp, NODEV, 0, data->gd_path, &fh, NFS_FHSIZE);
 	exp_unlock();
 
 	if (err == 0) {
diff -u --recursive --new-file v2.5.1/linux/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c
--- v2.5.1/linux/fs/nfsd/nfsfh.c	Wed Oct  3 22:59:22 2001
+++ linux/fs/nfsd/nfsfh.c	Tue Jan  1 12:32:13 2002
@@ -424,7 +424,8 @@
 	/* It's a directory, or we are required to confirm the file's
 	 * location in the tree.
 	 */
-	dprintk("nfs_fh: need to look harder for %d/%d\n",sb->s_dev,datap[0]);
+	dprintk("nfs_fh: need to look harder for %02x:%02x/%d\n",
+		major(sb->s_dev), minor(sb->s_dev), datap[0]);
 
 	if (!S_ISDIR(result->d_inode->i_mode)) {
 		nfsdstats.fh_nocache_nondir++;
@@ -556,7 +557,7 @@
 			case 0:
 				if ((data_left-=2)<0) goto out;
 				nfsdev = ntohl(*datap++);
-				xdev = MKDEV(nfsdev>>16, nfsdev&0xFFFF);
+				xdev = mk_kdev(nfsdev>>16, nfsdev&0xFFFF);
 				xino = *datap++;
 				break;
 			default:
@@ -788,8 +789,8 @@
 	struct dentry *parent = dentry->d_parent;
 	__u32 *datap;
 
-	dprintk("nfsd: fh_compose(exp %x/%ld %s/%s, ino=%ld)\n",
-		exp->ex_dev, (long) exp->ex_ino,
+	dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n",
+		major(exp->ex_dev), minor(exp->ex_dev), (long) exp->ex_ino,
 		parent->d_name.name, dentry->d_name.name,
 		(inode ? inode->i_ino : 0));
 
@@ -811,7 +812,7 @@
 		memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE);
 		fhp->fh_handle.fh_size = NFS_FHSIZE;
 		fhp->fh_handle.ofh_dcookie = 0xfeebbaca;
-		fhp->fh_handle.ofh_dev =  htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
+		fhp->fh_handle.ofh_dev =  htonl((major(exp->ex_dev)<<16)| minor(exp->ex_dev));
 		fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev;
 		fhp->fh_handle.ofh_xino = ino_t_to_u32(exp->ex_ino);
 		fhp->fh_handle.ofh_dirino = ino_t_to_u32(dentry->d_parent->d_inode->i_ino);
@@ -823,7 +824,7 @@
 		fhp->fh_handle.fh_fsid_type = 0;
 		datap = fhp->fh_handle.fh_auth+0;
 		/* fsid_type 0 == 2byte major, 2byte minor, 4byte inode */
-		*datap++ = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
+		*datap++ = htonl((major(exp->ex_dev)<<16)| minor(exp->ex_dev));
 		*datap++ = ino_t_to_u32(exp->ex_ino);
 		fhp->fh_handle.fh_size = 3*4;
 		if (inode) {
diff -u --recursive --new-file v2.5.1/linux/fs/nfsd/nfsproc.c linux/fs/nfsd/nfsproc.c
--- v2.5.1/linux/fs/nfsd/nfsproc.c	Sun Oct 21 10:40:36 2001
+++ linux/fs/nfsd/nfsproc.c	Tue Jan  1 12:28:59 2002
@@ -197,7 +197,7 @@
 	struct inode	*inode;
 	struct dentry	*dchild;
 	int		nfserr, type, mode;
-	dev_t		rdev = NODEV;
+	dev_t		rdev = 0;
 
 	dprintk("nfsd: CREATE   %s %.*s\n",
 		SVCFH_fmt(dirfhp), argp->len, argp->name);
@@ -255,7 +255,7 @@
 				case S_IFCHR:
 				case S_IFBLK:
 					/* reserve rdev for later checking */
-					attr->ia_size = inode->i_rdev;
+					attr->ia_size = kdev_t_to_nr(inode->i_rdev);
 					attr->ia_valid |= ATTR_SIZE;
 
 					/* FALLTHROUGH */
@@ -313,7 +313,7 @@
 		/* Make sure the type and device matches */
 		nfserr = nfserr_exist;
 		if (inode && (type != (inode->i_mode & S_IFMT) || 
-		    (is_borc && inode->i_rdev != rdev)))
+		    (is_borc && kdev_t_to_nr(inode->i_rdev) != rdev)))
 			goto out_unlock;
 	}
 	
diff -u --recursive --new-file v2.5.1/linux/fs/nfsd/nfsxdr.c linux/fs/nfsd/nfsxdr.c
--- v2.5.1/linux/fs/nfsd/nfsxdr.c	Wed Oct 17 14:16:34 2001
+++ linux/fs/nfsd/nfsxdr.c	Tue Jan  1 12:48:41 2002
@@ -149,11 +149,11 @@
 	}
 	*p++ = htonl((u32) inode->i_blksize);
 	if (S_ISCHR(type) || S_ISBLK(type))
-		*p++ = htonl((u32) inode->i_rdev);
+		*p++ = htonl((u32) kdev_t_to_nr(inode->i_rdev));
 	else
 		*p++ = htonl(0xffffffff);
 	*p++ = htonl((u32) inode->i_blocks);
-	*p++ = htonl((u32) inode->i_dev);
+	*p++ = htonl((u32) kdev_t_to_nr(inode->i_dev));
 	*p++ = htonl((u32) inode->i_ino);
 	*p++ = htonl((u32) inode->i_atime);
 	*p++ = 0;
diff -u --recursive --new-file v2.5.1/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.5.1/linux/fs/nfsd/vfs.c	Fri Oct  5 12:23:53 2001
+++ linux/fs/nfsd/vfs.c	Tue Jan  1 12:34:36 2002
@@ -66,7 +66,7 @@
 	struct raparms		*p_next;
 	unsigned int		p_count;
 	ino_t			p_ino;
-	dev_t			p_dev;
+	kdev_t			p_dev;
 	unsigned long		p_reada,
 				p_ramax,
 				p_raend,
@@ -543,13 +543,13 @@
  * specified by (dev, ino).
  */
 static inline struct raparms *
-nfsd_get_raparms(dev_t dev, ino_t ino)
+nfsd_get_raparms(kdev_t dev, ino_t ino)
 {
 	struct raparms	*ra, **rap, **frap = NULL;
 	int depth = 0;
 	
 	for (rap = &raparm_cache; (ra = *rap); rap = &ra->p_next) {
-		if (ra->p_ino == ino && ra->p_dev == dev)
+		if (ra->p_ino == ino && kdev_same(ra->p_dev, dev))
 			goto found;
 		depth++;
 		if (ra->p_count == 0)
@@ -730,7 +730,7 @@
 		 */
 		if (EX_WGATHER(exp)) {
 			if (atomic_read(&inode->i_writecount) > 1
-			    || (last_ino == inode->i_ino && last_dev == inode->i_dev)) {
+			    || (last_ino == inode->i_ino && kdev_same(last_dev, inode->i_dev))) {
 				dprintk("nfsd: write defer %d\n", current->pid);
 				set_current_state(TASK_UNINTERRUPTIBLE);
 				schedule_timeout((HZ+99)/100);
@@ -1245,7 +1245,7 @@
 	tdir = tdentry->d_inode;
 
 	err = (rqstp->rq_vers == 2) ? nfserr_acces : nfserr_xdev;
-	if (fdir->i_dev != tdir->i_dev)
+	if (!kdev_same(fdir->i_dev, tdir->i_dev))
 		goto out;
 
 	err = nfserr_perm;
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_base.c linux/fs/nls/nls_base.c
--- v2.5.1/linux/fs/nls/nls_base.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/nls/nls_base.c	Sat Dec 29 17:30:07 2001
@@ -13,7 +13,7 @@
 #include <linux/string.h>
 #include <linux/config.h>
 #include <linux/nls.h>
-#include <linux/slab.h>
+#include <linux/kernel.h>
 #include <linux/errno.h>
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_big5.c linux/fs/nls/nls_big5.c
--- v2.5.1/linux/fs/nls/nls_big5.c	Mon Oct 16 12:58:51 2000
+++ linux/fs/nls/nls_big5.c	Sun Dec 30 11:16:26 2001
@@ -42,6 +42,7 @@
 
 module_init(init_nls_big5)
 module_exit(exit_nls_big5)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp1251.c linux/fs/nls/nls_cp1251.c
--- v2.5.1/linux/fs/nls/nls_cp1251.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/nls/nls_cp1251.c	Sun Dec 30 11:16:26 2001
@@ -315,4 +315,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp1255.c linux/fs/nls/nls_cp1255.c
--- v2.5.1/linux/fs/nls/nls_cp1255.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/nls/nls_cp1255.c	Sun Dec 30 11:16:26 2001
@@ -396,4 +396,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp437.c linux/fs/nls/nls_cp437.c
--- v2.5.1/linux/fs/nls/nls_cp437.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/nls/nls_cp437.c	Sun Dec 30 11:16:26 2001
@@ -401,4 +401,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp737.c linux/fs/nls/nls_cp737.c
--- v2.5.1/linux/fs/nls/nls_cp737.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/nls/nls_cp737.c	Sun Dec 30 11:16:26 2001
@@ -364,4 +364,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp775.c linux/fs/nls/nls_cp775.c
--- v2.5.1/linux/fs/nls/nls_cp775.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/nls/nls_cp775.c	Sun Dec 30 11:16:26 2001
@@ -333,4 +333,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp850.c linux/fs/nls/nls_cp850.c
--- v2.5.1/linux/fs/nls/nls_cp850.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/nls/nls_cp850.c	Sun Dec 30 11:16:26 2001
@@ -329,4 +329,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp852.c linux/fs/nls/nls_cp852.c
--- v2.5.1/linux/fs/nls/nls_cp852.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/nls/nls_cp852.c	Sun Dec 30 11:16:26 2001
@@ -351,4 +351,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp855.c linux/fs/nls/nls_cp855.c
--- v2.5.1/linux/fs/nls/nls_cp855.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/nls/nls_cp855.c	Sun Dec 30 11:16:26 2001
@@ -313,4 +313,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp857.c linux/fs/nls/nls_cp857.c
--- v2.5.1/linux/fs/nls/nls_cp857.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/nls/nls_cp857.c	Sun Dec 30 11:16:26 2001
@@ -315,4 +315,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp860.c linux/fs/nls/nls_cp860.c
--- v2.5.1/linux/fs/nls/nls_cp860.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/nls/nls_cp860.c	Sun Dec 30 11:16:26 2001
@@ -378,4 +378,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp861.c linux/fs/nls/nls_cp861.c
--- v2.5.1/linux/fs/nls/nls_cp861.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/nls/nls_cp861.c	Sun Dec 30 11:16:26 2001
@@ -401,4 +401,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp862.c linux/fs/nls/nls_cp862.c
--- v2.5.1/linux/fs/nls/nls_cp862.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/nls/nls_cp862.c	Sun Dec 30 11:16:26 2001
@@ -435,4 +435,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp863.c linux/fs/nls/nls_cp863.c
--- v2.5.1/linux/fs/nls/nls_cp863.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/nls/nls_cp863.c	Sun Dec 30 11:16:26 2001
@@ -395,4 +395,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp864.c linux/fs/nls/nls_cp864.c
--- v2.5.1/linux/fs/nls/nls_cp864.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/nls/nls_cp864.c	Sun Dec 30 11:16:26 2001
@@ -421,4 +421,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp865.c linux/fs/nls/nls_cp865.c
--- v2.5.1/linux/fs/nls/nls_cp865.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/nls/nls_cp865.c	Sun Dec 30 11:16:26 2001
@@ -401,4 +401,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp866.c linux/fs/nls/nls_cp866.c
--- v2.5.1/linux/fs/nls/nls_cp866.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/nls/nls_cp866.c	Sun Dec 30 11:16:26 2001
@@ -319,4 +319,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp869.c linux/fs/nls/nls_cp869.c
--- v2.5.1/linux/fs/nls/nls_cp869.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/nls/nls_cp869.c	Sun Dec 30 11:16:26 2001
@@ -329,4 +329,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp874.c linux/fs/nls/nls_cp874.c
--- v2.5.1/linux/fs/nls/nls_cp874.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/nls/nls_cp874.c	Sun Dec 30 11:16:26 2001
@@ -287,4 +287,4 @@
  * c-continued-brace-offset: 0
  * End:
  */
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp932.c linux/fs/nls/nls_cp932.c
--- v2.5.1/linux/fs/nls/nls_cp932.c	Fri Apr  6 10:51:19 2001
+++ linux/fs/nls/nls_cp932.c	Sun Dec 30 11:16:26 2001
@@ -7904,6 +7904,7 @@
 
 module_init(init_nls_cp932)
 module_exit(exit_nls_cp932)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp936.c linux/fs/nls/nls_cp936.c
--- v2.5.1/linux/fs/nls/nls_cp936.c	Fri Jul 21 15:19:51 2000
+++ linux/fs/nls/nls_cp936.c	Sun Dec 30 11:16:26 2001
@@ -11024,6 +11024,7 @@
 
 module_init(init_nls_cp936)
 module_exit(exit_nls_cp936)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp949.c linux/fs/nls/nls_cp949.c
--- v2.5.1/linux/fs/nls/nls_cp949.c	Fri Jul 21 15:19:51 2000
+++ linux/fs/nls/nls_cp949.c	Sun Dec 30 11:16:26 2001
@@ -13941,6 +13941,7 @@
 
 module_init(init_nls_cp949)
 module_exit(exit_nls_cp949)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_cp950.c linux/fs/nls/nls_cp950.c
--- v2.5.1/linux/fs/nls/nls_cp950.c	Fri Jul 21 15:19:51 2000
+++ linux/fs/nls/nls_cp950.c	Sun Dec 30 11:16:26 2001
@@ -9480,6 +9480,7 @@
 
 module_init(init_nls_cp950)
 module_exit(exit_nls_cp950)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_euc-jp.c linux/fs/nls/nls_euc-jp.c
--- v2.5.1/linux/fs/nls/nls_euc-jp.c	Fri Apr  6 10:51:19 2001
+++ linux/fs/nls/nls_euc-jp.c	Sun Dec 30 11:16:26 2001
@@ -581,6 +581,7 @@
 
 module_init(init_nls_euc_jp)
 module_exit(exit_nls_euc_jp)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_euc-kr.c linux/fs/nls/nls_euc-kr.c
--- v2.5.1/linux/fs/nls/nls_euc-kr.c	Mon Oct 16 12:58:51 2000
+++ linux/fs/nls/nls_euc-kr.c	Sun Dec 30 11:16:26 2001
@@ -42,6 +42,7 @@
 
 module_init(init_nls_euc_kr)
 module_exit(exit_nls_euc_kr)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_gb2312.c linux/fs/nls/nls_gb2312.c
--- v2.5.1/linux/fs/nls/nls_gb2312.c	Mon Oct 16 12:58:51 2000
+++ linux/fs/nls/nls_gb2312.c	Sun Dec 30 11:16:26 2001
@@ -42,6 +42,7 @@
 
 module_init(init_nls_gb2312)
 module_exit(exit_nls_gb2312)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_iso8859-1.c linux/fs/nls/nls_iso8859-1.c
--- v2.5.1/linux/fs/nls/nls_iso8859-1.c	Tue Jul 18 22:48:33 2000
+++ linux/fs/nls/nls_iso8859-1.c	Sun Dec 30 11:16:26 2001
@@ -254,6 +254,7 @@
 
 module_init(init_nls_iso8859_1)
 module_exit(exit_nls_iso8859_1)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_iso8859-13.c linux/fs/nls/nls_iso8859-13.c
--- v2.5.1/linux/fs/nls/nls_iso8859-13.c	Sat May 19 17:47:55 2001
+++ linux/fs/nls/nls_iso8859-13.c	Sun Dec 30 11:16:26 2001
@@ -282,6 +282,7 @@
 
 module_init(init_nls_iso8859_13)
 module_exit(exit_nls_iso8859_13)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_iso8859-14.c linux/fs/nls/nls_iso8859-14.c
--- v2.5.1/linux/fs/nls/nls_iso8859-14.c	Tue Jul 18 22:48:33 2000
+++ linux/fs/nls/nls_iso8859-14.c	Sun Dec 30 11:16:26 2001
@@ -338,6 +338,7 @@
 
 module_init(init_nls_iso8859_14)
 module_exit(exit_nls_iso8859_14)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_iso8859-15.c linux/fs/nls/nls_iso8859-15.c
--- v2.5.1/linux/fs/nls/nls_iso8859-15.c	Fri Jul 21 15:19:51 2000
+++ linux/fs/nls/nls_iso8859-15.c	Sun Dec 30 11:16:26 2001
@@ -304,6 +304,7 @@
 
 module_init(init_nls_iso8859_15)
 module_exit(exit_nls_iso8859_15)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_iso8859-2.c linux/fs/nls/nls_iso8859-2.c
--- v2.5.1/linux/fs/nls/nls_iso8859-2.c	Fri Jul 21 15:19:51 2000
+++ linux/fs/nls/nls_iso8859-2.c	Sun Dec 30 11:16:26 2001
@@ -305,6 +305,7 @@
 
 module_init(init_nls_iso8859_2)
 module_exit(exit_nls_iso8859_2)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_iso8859-3.c linux/fs/nls/nls_iso8859-3.c
--- v2.5.1/linux/fs/nls/nls_iso8859-3.c	Fri Jul 21 15:19:51 2000
+++ linux/fs/nls/nls_iso8859-3.c	Sun Dec 30 11:16:26 2001
@@ -305,6 +305,7 @@
 
 module_init(init_nls_iso8859_3)
 module_exit(exit_nls_iso8859_3)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_iso8859-4.c linux/fs/nls/nls_iso8859-4.c
--- v2.5.1/linux/fs/nls/nls_iso8859-4.c	Fri Jul 21 15:19:51 2000
+++ linux/fs/nls/nls_iso8859-4.c	Sun Dec 30 11:16:26 2001
@@ -305,6 +305,7 @@
 
 module_init(init_nls_iso8859_4)
 module_exit(exit_nls_iso8859_4)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_iso8859-5.c linux/fs/nls/nls_iso8859-5.c
--- v2.5.1/linux/fs/nls/nls_iso8859-5.c	Fri Jul 21 15:19:51 2000
+++ linux/fs/nls/nls_iso8859-5.c	Sun Dec 30 11:16:26 2001
@@ -269,6 +269,7 @@
 
 module_init(init_nls_iso8859_5)
 module_exit(exit_nls_iso8859_5)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_iso8859-6.c linux/fs/nls/nls_iso8859-6.c
--- v2.5.1/linux/fs/nls/nls_iso8859-6.c	Fri Jul 21 15:19:51 2000
+++ linux/fs/nls/nls_iso8859-6.c	Sun Dec 30 11:16:26 2001
@@ -260,6 +260,7 @@
 
 module_init(init_nls_iso8859_6)
 module_exit(exit_nls_iso8859_6)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_iso8859-7.c linux/fs/nls/nls_iso8859-7.c
--- v2.5.1/linux/fs/nls/nls_iso8859-7.c	Fri Jul 21 15:19:51 2000
+++ linux/fs/nls/nls_iso8859-7.c	Sun Dec 30 11:16:26 2001
@@ -314,6 +314,7 @@
 
 module_init(init_nls_iso8859_7)
 module_exit(exit_nls_iso8859_7)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_iso8859-8.c linux/fs/nls/nls_iso8859-8.c
--- v2.5.1/linux/fs/nls/nls_iso8859-8.c	Fri Apr  6 10:51:19 2001
+++ linux/fs/nls/nls_iso8859-8.c	Sun Dec 30 11:16:26 2001
@@ -42,6 +42,7 @@
 
 module_init(init_nls_iso8859_8)
 module_exit(exit_nls_iso8859_8)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_iso8859-9.c linux/fs/nls/nls_iso8859-9.c
--- v2.5.1/linux/fs/nls/nls_iso8859-9.c	Fri Jul 21 15:19:51 2000
+++ linux/fs/nls/nls_iso8859-9.c	Sun Dec 30 11:16:26 2001
@@ -269,6 +269,7 @@
 
 module_init(init_nls_iso8859_9)
 module_exit(exit_nls_iso8859_9)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_koi8-r.c linux/fs/nls/nls_koi8-r.c
--- v2.5.1/linux/fs/nls/nls_koi8-r.c	Fri Jul 21 15:19:51 2000
+++ linux/fs/nls/nls_koi8-r.c	Sun Dec 30 11:16:26 2001
@@ -320,6 +320,7 @@
 
 module_init(init_nls_koi8_r)
 module_exit(exit_nls_koi8_r)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_koi8-ru.c linux/fs/nls/nls_koi8-ru.c
--- v2.5.1/linux/fs/nls/nls_koi8-ru.c	Sat May 19 17:47:55 2001
+++ linux/fs/nls/nls_koi8-ru.c	Sun Dec 30 11:16:26 2001
@@ -80,6 +80,7 @@
 
 module_init(init_nls_koi8_ru)
 module_exit(exit_nls_koi8_ru)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_koi8-u.c linux/fs/nls/nls_koi8-u.c
--- v2.5.1/linux/fs/nls/nls_koi8-u.c	Sat May 19 17:47:55 2001
+++ linux/fs/nls/nls_koi8-u.c	Sun Dec 30 11:16:26 2001
@@ -327,6 +327,7 @@
 
 module_init(init_nls_koi8_u)
 module_exit(exit_nls_koi8_u)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_sjis.c linux/fs/nls/nls_sjis.c
--- v2.5.1/linux/fs/nls/nls_sjis.c	Mon Oct 16 12:58:51 2000
+++ linux/fs/nls/nls_sjis.c	Sun Dec 30 11:16:26 2001
@@ -42,6 +42,7 @@
 
 module_init(init_nls_sjis)
 module_exit(exit_nls_sjis)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_tis-620.c linux/fs/nls/nls_tis-620.c
--- v2.5.1/linux/fs/nls/nls_tis-620.c	Fri Apr  6 10:51:19 2001
+++ linux/fs/nls/nls_tis-620.c	Sun Dec 30 11:16:26 2001
@@ -42,6 +42,7 @@
 
 module_init(init_nls_tis_620)
 module_exit(exit_nls_tis_620)
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.5.1/linux/fs/nls/nls_utf8.c linux/fs/nls/nls_utf8.c
--- v2.5.1/linux/fs/nls/nls_utf8.c	Tue Jul 18 22:48:33 2000
+++ linux/fs/nls/nls_utf8.c	Sun Dec 30 11:16:26 2001
@@ -58,3 +58,4 @@
 
 module_init(init_nls_utf8)
 module_exit(exit_nls_utf8)
+MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.1/linux/fs/ntfs/fs.c linux/fs/ntfs/fs.c
--- v2.5.1/linux/fs/ntfs/fs.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/ntfs/fs.c	Tue Dec 25 15:39:20 2001
@@ -1016,14 +1016,11 @@
 	init_ntfs_super_block(vol);
 	if (!parse_options(vol, (char*)options))
 		goto ntfs_read_super_vol;
-	blocksize = get_hardsect_size(sb->s_dev);
-	if (blocksize < 512)
-		blocksize = 512;
-	if (set_blocksize(sb->s_dev, blocksize) < 0) {
-		ntfs_error("Unable to set blocksize %d.\n", blocksize);
+	blocksize = sb_min_blocksize(sb, 512);
+	if (!blocksize) {
+		ntfs_error("Unable to set blocksize.\n");
 		goto ntfs_read_super_vol;
 	}
-	sb->s_blocksize = blocksize;
 	/* Read the super block (boot block). */
 	if (!(bh = sb_bread(sb, 0))) {
 		ntfs_error("Reading super block failed\n");
@@ -1052,10 +1049,7 @@
 	}
 	ntfs_debug(DEBUG_OTHER, "Done to init volume\n");
 	/* Inform the kernel that a device block is a NTFS cluster. */
-	sb->s_blocksize = vol->cluster_size;
-	sb->s_blocksize_bits = vol->cluster_size_bits;
-	if (blocksize != vol->cluster_size &&
-			set_blocksize(sb->s_dev, sb->s_blocksize) < 0) {
+	if (!sb_set_blocksize(sb, vol->cluster_size)) {
 		ntfs_error("Cluster size too small for device.\n");
 		goto ntfs_read_super_unl;
 	}
diff -u --recursive --new-file v2.5.1/linux/fs/partitions/acorn.c linux/fs/partitions/acorn.c
--- v2.5.1/linux/fs/partitions/acorn.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/partitions/acorn.c	Thu Jan  3 13:59:50 2002
@@ -28,7 +28,7 @@
 	extern void xd_set_geometry(kdev_t dev, unsigned char, unsigned char,
 				    unsigned long, unsigned int);
 
-	if (MAJOR(dev) == MFM_ACORN_MAJOR) {
+	if (major(dev) == MFM_ACORN_MAJOR) {
 		unsigned long totalblocks = hd->part[MINOR(dev)].nr_sects;
 		xd_set_geometry(dev, secspertrack, heads, totalblocks, 1);
 	}
diff -u --recursive --new-file v2.5.1/linux/fs/partitions/atari.c linux/fs/partitions/atari.c
--- v2.5.1/linux/fs/partitions/atari.c	Mon Oct  1 20:03:26 2001
+++ linux/fs/partitions/atari.c	Mon Dec 31 17:56:19 2001
@@ -43,7 +43,7 @@
 int atari_partition (struct gendisk *hd, struct block_device *bdev,
 		     unsigned long first_sector, int minor)
 {
-	int m_lim = minor + hd->max_p;
+	int m_lim = minor + (1 << hd->minor_shift);
 	Sector sect;
 	struct rootsector *rs;
 	struct partition_info *pi;
diff -u --recursive --new-file v2.5.1/linux/fs/partitions/check.c linux/fs/partitions/check.c
--- v2.5.1/linux/fs/partitions/check.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/partitions/check.c	Tue Jan  1 12:50:55 2002
@@ -38,7 +38,8 @@
 
 int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
 
-static int (*check_part[])(struct gendisk *hd, struct block_device *bdev, unsigned long first_sect, int first_minor) = {
+static int (*check_part[])(struct gendisk *hd, struct block_device *bdev,
+			   unsigned long first_sect, int first_minor) = {
 #ifdef CONFIG_ACORN_PARTITION
 	acorn_partition,
 #endif
@@ -227,26 +228,26 @@
 	if (first_time)
 		printk(KERN_INFO "Partition check:\n");
 	first_time = 0;
-	first_sector = hd->part[MINOR(dev)].start_sect;
+	first_sector = hd->part[minor(dev)].start_sect;
 
 	/*
 	 * This is a kludge to allow the partition check to be
 	 * skipped for specific drives (e.g. IDE CD-ROM drives)
 	 */
 	if ((int)first_sector == -1) {
-		hd->part[MINOR(dev)].start_sect = 0;
+		hd->part[minor(dev)].start_sect = 0;
 		return;
 	}
 
 	if (hd->de_arr)
-		de = hd->de_arr[MINOR(dev) >> hd->minor_shift];
+		de = hd->de_arr[minor(dev) >> hd->minor_shift];
 	i = devfs_generate_path (de, buf, sizeof buf);
 	if (i >= 0)
 		printk(KERN_INFO " /dev/%s:", buf + i);
 	else
-		printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf));
+		printk(KERN_INFO " %s:", disk_name(hd, minor(dev), buf));
 	bdev = bdget(kdev_t_to_nr(dev));
-	bdev->bd_inode->i_size = (loff_t)hd->part[MINOR(dev)].nr_sects << 9;
+	bdev->bd_inode->i_size = (loff_t)hd->part[minor(dev)].nr_sects << 9;
 	bdev->bd_inode->i_blkbits = blksize_bits(block_size(dev));
 	for (i = 0; check_part[i]; i++) {
 		int res;
@@ -333,11 +334,12 @@
 void devfs_register_partitions (struct gendisk *dev, int minor, int unregister)
 {
 #ifdef CONFIG_DEVFS_FS
-	int part;
+	int part, max_p;
 
 	if (!unregister)
 		devfs_register_disc (dev, minor);
-	for (part = 1; part < dev->max_p; part++) {
+	max_p = (1 << dev->minor_shift);
+	for (part = 1; part < max_p; part++) {
 		if ( unregister || (dev->part[part + minor].nr_sects < 1) ) {
 			devfs_unregister (dev->part[part + minor].de);
 			dev->part[part + minor].de = NULL;
@@ -381,10 +383,10 @@
 		return;
 
 	minors = 1 << g->minor_shift;
-	first_minor = MINOR(dev);
+	first_minor = minor(dev);
 	if (first_minor & (minors-1)) {
 		printk("grok_partitions: bad device 0x%02x:%02x\n",
-		       MAJOR(dev), first_minor);
+		       major(dev), first_minor);
 		first_minor &= ~(minors-1);
 	}
 	end_minor = first_minor + minors;
@@ -404,7 +406,7 @@
 			g->sizes[i] = 0;
 	}
 	blk_size[g->major] = g->sizes;
-	check_partition(g, MKDEV(g->major, first_minor), 1 + first_minor);
+	check_partition(g, mk_kdev(g->major, first_minor), 1 + first_minor);
 
  	/*
  	 * We need to set the sizes array before we will be able to access
@@ -450,8 +452,8 @@
 		return -EINVAL;
 
 	max_p = 1 << g->minor_shift;
-	major = MAJOR(dev);
-	minor = MINOR(dev);
+	major = major(dev);
+	minor = minor(dev);
 	minor0 = minor & ~(max_p - 1);
 	if (minor0 != minor)		/* for now only whole-disk reread */
 		return -EINVAL;		/* %%% later.. */
@@ -459,7 +461,7 @@
 	/* invalidate stuff */
 	for (p = max_p - 1; p >= 0; p--) {
 		minor = minor0 + p;
-		devp = MKDEV(major,minor);
+		devp = mk_kdev(major,minor);
 #if 0					/* %%% superfluous? */
 		if (g->part[minor].nr_sects == 0)
 			continue;
diff -u --recursive --new-file v2.5.1/linux/fs/partitions/check.h linux/fs/partitions/check.h
--- v2.5.1/linux/fs/partitions/check.h	Tue Dec 18 14:56:40 2001
+++ linux/fs/partitions/check.h	Tue Jan  1 19:15:21 2002
@@ -1,18 +1,10 @@
 #include <linux/pagemap.h>
+#include <linux/blkdev.h>
 
 /*
  * add_gd_partition adds a partitions details to the devices partition
  * description.
  */
 void add_gd_partition(struct gendisk *hd, int minor, int start, int size);
-
-typedef struct {struct page *v;} Sector;
-
-unsigned char *read_dev_sector(struct block_device *, unsigned long, Sector *);
-
-static inline void put_dev_sector(Sector p)
-{
-	page_cache_release(p.v);
-}
 
 extern int warn_no_part;
diff -u --recursive --new-file v2.5.1/linux/fs/partitions/ibm.c linux/fs/partitions/ibm.c
--- v2.5.1/linux/fs/partitions/ibm.c	Mon Oct  1 20:03:26 2001
+++ linux/fs/partitions/ibm.c	Thu Jan  3 13:59:50 2002
@@ -125,7 +125,7 @@
 		return 0;
 	if (ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo);
 		return 0;
-	blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)];
+	blocksize = hardsect_size[major(dev)][minor(dev)];
 	if ( blocksize <= 0 ) {
 		return 0;
 	}
diff -u --recursive --new-file v2.5.1/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.5.1/linux/fs/proc/array.c	Thu Oct 11 09:00:01 2001
+++ linux/fs/proc/array.c	Tue Jan  1 12:51:15 2002
@@ -335,8 +335,7 @@
 
 	/* scale priority and nice values from timeslices to -20..20 */
 	/* to make it look like a "normal" Unix priority/nice value  */
-	priority = task->counter;
-	priority = 20 - (priority * 10 + DEF_COUNTER / 2) / DEF_COUNTER;
+	priority = task->dyn_prio;
 	nice = task->nice;
 
 	read_lock(&tasklist_lock);
@@ -556,7 +555,7 @@
 	str[3] = flags & VM_MAYSHARE ? 's' : 'p';
 	str[4] = 0;
 
-	dev = 0;
+	dev = NODEV;
 	ino = 0;
 	if (map->vm_file != NULL) {
 		dev = map->vm_file->f_dentry->d_inode->i_dev;
diff -u --recursive --new-file v2.5.1/linux/fs/proc/base.c linux/fs/proc/base.c
--- v2.5.1/linux/fs/proc/base.c	Wed Oct 10 23:42:47 2001
+++ linux/fs/proc/base.c	Sat Dec 29 17:30:07 2001
@@ -23,6 +23,9 @@
 #include <linux/init.h>
 #include <linux/file.h>
 #include <linux/string.h>
+#include <linux/seq_file.h>
+#include <linux/namespace.h>
+#include <linux/mm.h>
 
 /*
  * For hysterical raisins we keep the same inumbers as in the old procfs.
@@ -246,6 +249,46 @@
 	read:		pid_maps_read,
 };
 
+extern struct seq_operations mounts_op;
+static int mounts_open(struct inode *inode, struct file *file)
+{
+	struct task_struct *task = inode->u.proc_i.task;
+	int ret = seq_open(file, &mounts_op);
+
+	if (!ret) {
+		struct seq_file *m = file->private_data;
+		struct namespace *namespace;
+		task_lock(task);
+		namespace = task->namespace;
+		if (namespace)
+			get_namespace(namespace);
+		task_unlock(task);
+
+		if (namespace)
+			m->private = namespace;
+		else {
+			seq_release(inode, file);
+			ret = -EINVAL;
+		}
+	}
+	return ret;
+}
+
+static int mounts_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *m = file->private_data;
+	struct namespace *namespace = m->private;
+	put_namespace(namespace);
+	return seq_release(inode, file);
+}
+
+static struct file_operations proc_mounts_operations = {
+	open:		mounts_open,
+	read:		seq_read,
+	llseek:		seq_lseek,
+	release:	mounts_release,
+};
+
 #define PROC_BLOCK_SIZE	(3*1024)		/* 4K page size but our output routines use some slack for overruns */
 
 static ssize_t proc_info_read(struct file * file, char * buf,
@@ -497,6 +540,7 @@
 	PROC_PID_STATM,
 	PROC_PID_MAPS,
 	PROC_PID_CPU,
+	PROC_PID_MOUNTS,
 	PROC_PID_FD_DIR = 0x8000,	/* 0x8000-0xffff */
 };
 
@@ -516,6 +560,7 @@
   E(PROC_PID_CWD,	"cwd",		S_IFLNK|S_IRWXUGO),
   E(PROC_PID_ROOT,	"root",		S_IFLNK|S_IRWXUGO),
   E(PROC_PID_EXE,	"exe",		S_IFLNK|S_IRWXUGO),
+  E(PROC_PID_MOUNTS,	"mounts",	S_IFREG|S_IRUGO),
   {0,0,NULL,0}
 };
 #undef E
@@ -874,6 +919,9 @@
 		case PROC_PID_MEM:
 			inode->i_op = &proc_mem_inode_operations;
 			inode->i_fop = &proc_mem_operations;
+			break;
+		case PROC_PID_MOUNTS:
+			inode->i_fop = &proc_mounts_operations;
 			break;
 		default:
 			printk("procfs: impossible type (%d)",p->type);
diff -u --recursive --new-file v2.5.1/linux/fs/proc/proc_misc.c linux/fs/proc/proc_misc.c
--- v2.5.1/linux/fs/proc/proc_misc.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/proc/proc_misc.c	Tue Dec 25 15:39:20 2001
@@ -500,18 +500,6 @@
 	write:		write_profile,
 };
 
-extern struct seq_operations mounts_op;
-static int mounts_open(struct inode *inode, struct file *file)
-{
-	return seq_open(file, &mounts_op);
-}
-static struct file_operations proc_mounts_operations = {
-	open:		mounts_open,
-	read:		seq_read,
-	llseek:		seq_lseek,
-	release:	seq_release,
-};
-
 struct proc_dir_entry *proc_root_kcore;
 
 static void create_seq_entry(char *name, mode_t mode, struct file_operations *f)
@@ -555,11 +543,12 @@
 	for (p = simple_ones; p->name; p++)
 		create_proc_read_entry(p->name, 0, NULL, p->read_proc, NULL);
 
+	proc_symlink("mounts", NULL, "self/mounts");
+
 	/* And now for trickier ones */
 	entry = create_proc_entry("kmsg", S_IRUSR, &proc_root);
 	if (entry)
 		entry->proc_fops = &proc_kmsg_operations;
-	create_seq_entry("mounts", 0, &proc_mounts_operations);
 	create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
 	create_seq_entry("interrupts", 0, &proc_interrupts_operations);
 #ifdef CONFIG_MODULES
diff -u --recursive --new-file v2.5.1/linux/fs/qnx4/dir.c linux/fs/qnx4/dir.c
--- v2.5.1/linux/fs/qnx4/dir.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/qnx4/dir.c	Sun Dec 30 10:31:51 2001
@@ -18,7 +18,6 @@
 #include <linux/qnx4_fs.h>
 #include <linux/stat.h>
 
-#include <asm/segment.h>
 
 static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
diff -u --recursive --new-file v2.5.1/linux/fs/qnx4/fsync.c linux/fs/qnx4/fsync.c
--- v2.5.1/linux/fs/qnx4/fsync.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/qnx4/fsync.c	Sun Dec 30 10:31:51 2001
@@ -21,7 +21,6 @@
 #include <linux/fs.h>
 #include <linux/qnx4_fs.h>
 
-#include <asm/segment.h>
 #include <asm/system.h>
 
 /*
diff -u --recursive --new-file v2.5.1/linux/fs/qnx4/inode.c linux/fs/qnx4/inode.c
--- v2.5.1/linux/fs/qnx4/inode.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/qnx4/inode.c	Sat Dec 29 17:30:07 2001
@@ -18,8 +18,8 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
-#include <linux/qnx4_fs.h>
 #include <linux/fs.h>
+#include <linux/qnx4_fs.h>
 #include <linux/locks.h>
 #include <linux/init.h>
 #include <linux/highuid.h>
@@ -213,9 +213,7 @@
 	phys = qnx4_block_map( inode, iblock );
 	if ( phys ) {
 		// logical block is before EOF
-		bh->b_dev     = inode->i_dev;
-		bh->b_blocknr = phys;
-		bh->b_state  |= (1UL << BH_Mapped);
+		map_bh(bh, inode->i_sb, phys);
 	} else if ( create ) {
 		// to be done.
 	}
@@ -339,13 +337,10 @@
 					   void *data, int silent)
 {
 	struct buffer_head *bh;
-	kdev_t dev = s->s_dev;
 	struct inode *root;
 	const char *errmsg;
 
-	set_blocksize(dev, QNX4_BLOCK_SIZE);
-	s->s_blocksize = QNX4_BLOCK_SIZE;
-	s->s_blocksize_bits = QNX4_BLOCK_SIZE_BITS;
+	sb_set_blocksize(s, QNX4_BLOCK_SIZE);
 
 	/* Check the boot signature. Since the qnx4 code is
 	   dangerous, we should leave as quickly as possible
diff -u --recursive --new-file v2.5.1/linux/fs/qnx4/namei.c linux/fs/qnx4/namei.c
--- v2.5.1/linux/fs/qnx4/namei.c	Tue Sep  5 14:07:30 2000
+++ linux/fs/qnx4/namei.c	Sun Dec 30 10:31:51 2001
@@ -21,7 +21,6 @@
 #include <linux/fcntl.h>
 #include <linux/errno.h>
 
-#include <asm/segment.h>
 
 /*
  * check if the filename is correct. For some obscure reason, qnx writes a
diff -u --recursive --new-file v2.5.1/linux/fs/qnx4/truncate.c linux/fs/qnx4/truncate.c
--- v2.5.1/linux/fs/qnx4/truncate.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/qnx4/truncate.c	Sat Dec 29 17:30:07 2001
@@ -13,9 +13,8 @@
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/qnx4_fs.h>
 #include <linux/fs.h>
+#include <linux/qnx4_fs.h>
 #include <linux/locks.h>
 #include <asm/uaccess.h>
 
diff -u --recursive --new-file v2.5.1/linux/fs/ramfs/inode.c linux/fs/ramfs/inode.c
--- v2.5.1/linux/fs/ramfs/inode.c	Wed Oct 24 15:19:18 2001
+++ linux/fs/ramfs/inode.c	Tue Dec 25 15:39:20 2001
@@ -325,6 +325,7 @@
 }
 
 static DECLARE_FSTYPE(ramfs_fs_type, "ramfs", ramfs_read_super, FS_LITTER);
+static DECLARE_FSTYPE(rootfs_fs_type, "rootfs", ramfs_read_super, FS_NOMOUNT|FS_LITTER);
 
 static int __init init_ramfs_fs(void)
 {
@@ -338,5 +339,11 @@
 
 module_init(init_ramfs_fs)
 module_exit(exit_ramfs_fs)
+
+int __init init_rootfs(void)
+{
+	return register_filesystem(&rootfs_fs_type);
+}
+
 MODULE_LICENSE("GPL");
 
diff -u --recursive --new-file v2.5.1/linux/fs/reiserfs/buffer2.c linux/fs/reiserfs/buffer2.c
--- v2.5.1/linux/fs/reiserfs/buffer2.c	Fri Nov  9 14:18:25 2001
+++ linux/fs/reiserfs/buffer2.c	Thu Dec 27 08:21:28 2001
@@ -47,7 +47,7 @@
     }
     run_task_queue(&tq_disk);
     current->policy |= SCHED_YIELD;
-    /*current->counter = 0;*/
+	/* current->dyn_prio = 0; */
     schedule();
   }
   if (repeat_counter > 30000000) {
@@ -64,12 +64,12 @@
    block. */
 /* The function is NOT SCHEDULE-SAFE! */
 
-struct buffer_head  * reiserfs_bread (struct super_block *super, int n_block, int n_size) 
+struct buffer_head  * reiserfs_bread (struct super_block *super, int n_block) 
 {
     struct buffer_head  *result;
     PROC_EXP( unsigned int ctx_switches = kstat.context_swtch );
 
-    result = bread (super -> s_dev, n_block, n_size);
+    result = sb_bread(super, n_block);
     PROC_INFO_INC( super, breads );
     PROC_EXP( if( kstat.context_swtch != ctx_switches ) 
 	      PROC_INFO_INC( super, bread_miss ) );
@@ -84,9 +84,9 @@
    actually get the block off of the disk. */
 /* The function is NOT SCHEDULE-SAFE! */
 
-struct buffer_head  * reiserfs_getblk (kdev_t n_dev, int n_block, int n_size)
+struct buffer_head  * reiserfs_getblk(struct super_block *sb, int n_block)
 {
-    return getblk (n_dev, n_block, n_size);
+    return sb_getblk(sb, n_block);
 }
 
 #ifdef NEW_GET_NEW_BUFFER
@@ -114,7 +114,7 @@
                                              blocknr, 1)) == NO_DISK_SPACE )
     return NO_DISK_SPACE;
   
-  *pp_s_new_bh = reiserfs_getblk(p_s_sb->s_dev, n_new_blocknumber, p_s_sb->s_blocksize);
+  *pp_s_new_bh = reiserfs_getblk(p_s_sb, n_new_blocknumber);
   if ( buffer_uptodate(*pp_s_new_bh) ) {
 
     RFALSE( buffer_dirty(*pp_s_new_bh) || (*pp_s_new_bh)->b_dev == NODEV,
@@ -149,7 +149,7 @@
 	printk("get_new_buffer(%u): counter(%d) too big", current->pid, repeat_counter);
 #endif
 
-      current->counter = 0;
+      current->time_slice = 0;
       schedule();
     }
 
@@ -291,7 +291,7 @@
   if ( (n_repeat = reiserfs_new_unf_blocknrs (th, &n_new_blocknumber, p_s_bh->b_blocknr)) == NO_DISK_SPACE )
     return NO_DISK_SPACE;
   
-  *pp_s_new_bh = reiserfs_getblk(p_s_sb->s_dev, n_new_blocknumber, p_s_sb->s_blocksize);
+  *pp_s_new_bh = reiserfs_getblk(p_s_sb, n_new_blocknumber);
   if (atomic_read (&(*pp_s_new_bh)->b_count) > 1) {
     /* Free path buffers to prevent deadlock which can occur in the
        situation like : this process holds p_s_path; Block
diff -u --recursive --new-file v2.5.1/linux/fs/reiserfs/fix_node.c linux/fs/reiserfs/fix_node.c
--- v2.5.1/linux/fs/reiserfs/fix_node.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/reiserfs/fix_node.c	Thu Dec 27 08:17:43 2001
@@ -806,7 +806,7 @@
     RFALSE( ! *p_n_blocknr,
 	    "PAP-8135: reiserfs_new_blocknrs failed when got new blocks");
 
-    p_s_new_bh = reiserfs_getblk(p_s_sb->s_dev, *p_n_blocknr, p_s_sb->s_blocksize);
+    p_s_new_bh = reiserfs_getblk(p_s_sb, *p_n_blocknr);
     if (atomic_read (&(p_s_new_bh->b_count)) > 1) {
 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
 /*
@@ -1926,7 +1926,7 @@
 
 	n_child_position = ( p_s_bh == p_s_tb->FL[n_h] ) ? p_s_tb->lkey[n_h] : B_NR_ITEMS (p_s_tb->FL[n_h]);
 	n_son_number = B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position);
-	p_s_bh = reiserfs_bread(p_s_sb, n_son_number, p_s_sb->s_blocksize);
+	p_s_bh = reiserfs_bread(p_s_sb, n_son_number);
 	if (!p_s_bh)
 	    return IO_ERROR;
 	if ( FILESYSTEM_CHANGED_TB (p_s_tb) ) {
@@ -1959,7 +1959,7 @@
 
 	n_child_position = ( p_s_bh == p_s_tb->FR[n_h] ) ? p_s_tb->rkey[n_h] + 1 : 0;
 	n_son_number = B_N_CHILD_NUM(p_s_tb->FR[n_h], n_child_position);
-	p_s_bh = reiserfs_bread(p_s_sb, n_son_number, p_s_sb->s_blocksize);
+	p_s_bh = reiserfs_bread(p_s_sb, n_son_number);
 	if (!p_s_bh)
 	    return IO_ERROR;
 	if ( FILESYSTEM_CHANGED_TB (p_s_tb) ) {
diff -u --recursive --new-file v2.5.1/linux/fs/reiserfs/inode.c linux/fs/reiserfs/inode.c
--- v2.5.1/linux/fs/reiserfs/inode.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/reiserfs/inode.c	Thu Dec 27 08:17:43 2001
@@ -205,9 +205,7 @@
 static inline void set_block_dev_mapped (struct buffer_head * bh, 
 					 b_blocknr_t block, struct inode * inode)
 {
-  bh->b_dev = inode->i_dev;
-  bh->b_blocknr = block;
-  bh->b_state |= (1UL << BH_Mapped);
+	map_bh(bh, inode->i_sb, block);
 }
 
 
@@ -287,9 +285,7 @@
 	blocknr = get_block_num(ind_item, path.pos_in_item) ;
 	ret = 0 ;
 	if (blocknr) {
-	    bh_result->b_dev = inode->i_dev;
-	    bh_result->b_blocknr = blocknr;
-	    bh_result->b_state |= (1UL << BH_Mapped);
+		map_bh(bh_result, inode->i_sb, blocknr);
 	} else if ((args & GET_BLOCK_NO_HOLE)) {
 	    ret = -ENOENT ;
 	}
@@ -380,10 +376,9 @@
 
 finished:
     pathrelse (&path);
-    bh_result->b_blocknr = 0 ;
-    bh_result->b_dev = inode->i_dev;
+    /* I _really_ doubt that you want it.  Chris? */
+    map_bh(bh_result, inode->i_sb, 0);
     mark_buffer_uptodate (bh_result, 1);
-    bh_result->b_state |= (1UL << BH_Mapped);
     return 0;
 }
 
diff -u --recursive --new-file v2.5.1/linux/fs/reiserfs/namei.c linux/fs/reiserfs/namei.c
--- v2.5.1/linux/fs/reiserfs/namei.c	Fri Nov  9 14:18:25 2001
+++ linux/fs/reiserfs/namei.c	Thu Dec 27 08:21:28 2001
@@ -1168,7 +1168,7 @@
 	    // FIXME: do we need this? shouldn't we simply continue?
 	    run_task_queue(&tq_disk);
 	    current->policy |= SCHED_YIELD;
-	    /*current->counter = 0;*/
+	    /*current->time_slice = 0;*/
 	    schedule();
 #endif
 	    continue;
diff -u --recursive --new-file v2.5.1/linux/fs/reiserfs/resize.c linux/fs/reiserfs/resize.c
--- v2.5.1/linux/fs/reiserfs/resize.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/reiserfs/resize.c	Thu Dec 27 08:17:43 2001
@@ -111,7 +111,7 @@
 	    for (i = 0; i < bmap_nr; i++)
 		bitmap[i] = SB_AP_BITMAP(s)[i];
 	    for (i = bmap_nr; i < bmap_nr_new; i++) {
-		bitmap[i] = reiserfs_getblk(s->s_dev, i * s->s_blocksize * 8, s->s_blocksize);
+		bitmap[i] = reiserfs_getblk(s, i * s->s_blocksize * 8);
 		memset(bitmap[i]->b_data, 0, sb->s_blocksize);
 		reiserfs_test_and_set_le_bit(0, bitmap[i]->b_data);
 
diff -u --recursive --new-file v2.5.1/linux/fs/reiserfs/stree.c linux/fs/reiserfs/stree.c
--- v2.5.1/linux/fs/reiserfs/stree.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/reiserfs/stree.c	Thu Dec 27 08:17:43 2001
@@ -604,7 +604,7 @@
     if (blocknr == 0)
 	return;
 
-    bh = reiserfs_getblk (s->s_dev, blocknr, s->s_blocksize);
+    bh = reiserfs_getblk (s, blocknr);
   
     if (!buffer_uptodate (bh)) {
 	ll_rw_block (READA, 1, &bh);
@@ -649,8 +649,7 @@
                                        DISK_LEAF_NODE_LEVEL */
     ) {
     int  n_block_number = SB_ROOT_BLOCK (p_s_sb),
-      expected_level = SB_TREE_HEIGHT (p_s_sb),
-      n_block_size    = p_s_sb->s_blocksize;
+      expected_level = SB_TREE_HEIGHT (p_s_sb);
     struct buffer_head  *       p_s_bh;
     struct path_element *       p_s_last_element;
     int				n_node_level, n_retval;
@@ -697,7 +696,7 @@
 	/* Read the next tree node, and set the last element in the path to
            have a pointer to it. */
 	if ( ! (p_s_bh = p_s_last_element->pe_buffer =
-		reiserfs_bread(p_s_sb, n_block_number, n_block_size)) ) {
+		reiserfs_bread(p_s_sb, n_block_number)) ) {
 	    p_s_search_path->path_length --;
 	    pathrelse(p_s_search_path);
 	    return IO_ERROR;
diff -u --recursive --new-file v2.5.1/linux/fs/reiserfs/super.c linux/fs/reiserfs/super.c
--- v2.5.1/linux/fs/reiserfs/super.c	Fri Nov  9 14:18:25 2001
+++ linux/fs/reiserfs/super.c	Sat Dec 29 11:13:15 2001
@@ -19,6 +19,7 @@
 #include <linux/smp_lock.h>
 #include <linux/locks.h>
 #include <linux/init.h>
+#include <linux/blkdev.h>
 
 #define REISERFS_OLD_BLOCKSIZE 4096
 #define REISERFS_SUPER_MAGIC_STRING_OFFSET_NJ 20
@@ -302,11 +303,11 @@
        labeling scheme currently used will have enough space. Then we
        need one block for the super.  -Hans */
     bmp = (REISERFS_DISK_OFFSET_IN_BYTES / s->s_blocksize) + 1;	/* first of bitmap blocks */
-    SB_AP_BITMAP (s)[0] = reiserfs_bread (s, bmp, s->s_blocksize);
+    SB_AP_BITMAP (s)[0] = reiserfs_bread (s, bmp);
     if(!SB_AP_BITMAP(s)[0])
 	return 1;
     for (i = 1, bmp = dl = s->s_blocksize * 8; i < sb_bmap_nr(rs); i ++) {
-	SB_AP_BITMAP (s)[i] = reiserfs_bread (s, bmp, s->s_blocksize);
+	SB_AP_BITMAP (s)[i] = reiserfs_bread (s, bmp);
 	if (!SB_AP_BITMAP (s)[i])
 	    return 1;
 	bmp += dl;
@@ -329,7 +330,7 @@
   memset (SB_AP_BITMAP (s), 0, sizeof (struct buffer_head *) * sb_bmap_nr(rs));
 
   for (i = 0; i < sb_bmap_nr(rs); i ++) {
-    SB_AP_BITMAP (s)[i] = reiserfs_bread (s, bmp1 + i, s->s_blocksize);
+    SB_AP_BITMAP (s)[i] = reiserfs_bread (s, bmp1 + i);
     if (!SB_AP_BITMAP (s)[i])
       return 1;
   }
@@ -355,17 +356,17 @@
 		      free, SB_FREE_BLOCKS (s));
 }
 
-static int read_super_block (struct super_block * s, int size, int offset)
+static int read_super_block (struct super_block * s, int offset)
 {
     struct buffer_head * bh;
     struct reiserfs_super_block * rs;
  
 
-    bh = bread (s->s_dev, offset / size, size);
+    bh = sb_bread (s, offset / s->s_blocksize);
     if (!bh) {
       printk ("read_super_block: "
               "bread failed (dev %s, block %d, size %d)\n",
-              kdevname (s->s_dev), offset / size, size);
+              kdevname (s->s_dev), offset / s->s_blocksize, s->s_blocksize);
       return 1;
     }
  
@@ -373,7 +374,7 @@
     if (!is_reiserfs_magic_string (rs)) {
       printk ("read_super_block: "
               "can't find a reiserfs filesystem on (dev %s, block %lu, size %d)\n",
-              kdevname(s->s_dev), bh->b_blocknr, size);
+              kdevname(s->s_dev), bh->b_blocknr, s->s_blocksize);
       brelse (bh);
       return 1;
     }
@@ -381,30 +382,23 @@
     //
     // ok, reiserfs signature (old or new) found in at the given offset
     //    
-    s->s_blocksize = sb_blocksize(rs);
-    s->s_blocksize_bits = 0;
-    while ((1 << s->s_blocksize_bits) != s->s_blocksize)
-	s->s_blocksize_bits ++;
-
     brelse (bh);
     
-    if (s->s_blocksize != size)
-	set_blocksize (s->s_dev, s->s_blocksize);
+    sb_set_blocksize (s, sb_blocksize(rs));
 
-    bh = reiserfs_bread (s, offset / s->s_blocksize, s->s_blocksize);
+    bh = reiserfs_bread (s, offset / s->s_blocksize);
     if (!bh) {
 	printk("read_super_block: "
                 "bread failed (dev %s, block %d, size %d)\n",
-                kdevname (s->s_dev), offset / size, size);
+                kdevname (s->s_dev), offset / s->s_blocksize, s->s_blocksize);
 	return 1;
     }
     
     rs = (struct reiserfs_super_block *)bh->b_data;
-    if (!is_reiserfs_magic_string (rs) ||
-	sb_blocksize(rs) != s->s_blocksize) {
+    if (!is_reiserfs_magic_string (rs) || sb_blocksize(rs) != s->s_blocksize) {
 	printk ("read_super_block: "
 		"can't find a reiserfs filesystem on (dev %s, block %lu, size %d)\n",
-		kdevname(s->s_dev), bh->b_blocknr, size);
+		kdevname(s->s_dev), bh->b_blocknr, s->s_blocksize);
 	brelse (bh);
 	printk ("read_super_block: can't find a reiserfs filesystem on dev %s.\n", kdevname(s->s_dev));
 	return 1;
@@ -612,9 +606,7 @@
 {
     int size;
     struct inode *root_inode;
-    kdev_t dev = s->s_dev;
     int j;
-    extern int *blksize_size[];
     struct reiserfs_transaction_handle th ;
     int old_format = 0;
     unsigned long blocks;
@@ -633,18 +625,14 @@
 	return NULL;
     }	
 
-    if (blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)] != 0) {
-	/* as blocksize is set for partition we use it */
-	size = blksize_size[MAJOR(dev)][MINOR(dev)];
-    } else {
-	size = BLOCK_SIZE;
-	set_blocksize (s->s_dev, BLOCK_SIZE);
-    }
+    size = block_size(s->s_dev);
+    sb_set_blocksize(s, size);
 
     /* read block (64-th 1k block), which can contain reiserfs super block */
-    if (read_super_block (s, size, REISERFS_DISK_OFFSET_IN_BYTES)) {
+    if (read_super_block (s, REISERFS_DISK_OFFSET_IN_BYTES)) {
 	// try old format (undistributed bitmap, super block in 8-th 1k block of a device)
-	if (read_super_block (s, size, REISERFS_OLD_DISK_OFFSET_IN_BYTES)) 
+	sb_set_blocksize(s, size);
+	if (read_super_block (s, REISERFS_OLD_DISK_OFFSET_IN_BYTES)) 
 	    goto error;
 	else
 	    old_format = 1;
diff -u --recursive --new-file v2.5.1/linux/fs/romfs/inode.c linux/fs/romfs/inode.c
--- v2.5.1/linux/fs/romfs/inode.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/romfs/inode.c	Thu Jan  3 12:20:18 2002
@@ -102,9 +102,7 @@
 
 	/* I would parse the options here, but there are none.. :) */
 
-	set_blocksize(dev, ROMBSIZE);
-	s->s_blocksize = ROMBSIZE;
-	s->s_blocksize_bits = ROMBSBITS;
+	sb_set_blocksize(s, ROMBSIZE);
 	s->u.generic_sbp = (void *) 0;
 	s->s_maxbytes = 0xFFFFFFFF;
 
@@ -520,7 +518,9 @@
 		default:
 			/* depending on MBZ for sock/fifos */
 			nextfh = ntohl(ri.spec);
-			nextfh = kdev_t_to_nr(MKDEV(nextfh>>16,nextfh&0xffff));
+			/* convert back and forth for typechecking and
+			 * source tagging */
+			nextfh = kdev_t_to_nr(mk_kdev(nextfh>>16,nextfh&0xffff));
 			init_special_inode(i, ino, nextfh);
 	}
 }
diff -u --recursive --new-file v2.5.1/linux/fs/smbfs/ChangeLog linux/fs/smbfs/ChangeLog
--- v2.5.1/linux/fs/smbfs/ChangeLog	Tue Oct  2 17:03:34 2001
+++ linux/fs/smbfs/ChangeLog	Thu Jan  3 13:33:50 2002
@@ -1,5 +1,15 @@
 ChangeLog for smbfs.
 
+2001-12-31 René Scharfe <l.s.r@web.de>
+
+	* inode.c: added smb_show_options to show mount options in /proc/mounts
+	* inode.c, getopt.c, getopt.h: merged flag and has_arg in struct option
+	* inode.c: use S_IRWXUGO where appropriate
+
+2001-12-22 Urban Widmark <urban@teststation.com>
+
+	* file.c, proc.c: Fix problems triggered by the "fsx test"
+
 2001-09-17 Urban Widmark <urban@teststation.com>
 
 	* proc.c: Use 4096 (was 512) as the blocksize for better write
diff -u --recursive --new-file v2.5.1/linux/fs/smbfs/file.c linux/fs/smbfs/file.c
--- v2.5.1/linux/fs/smbfs/file.c	Tue Oct  2 17:03:34 2001
+++ linux/fs/smbfs/file.c	Thu Jan  3 13:33:50 2002
@@ -270,7 +270,6 @@
 static int smb_prepare_write(struct file *file, struct page *page, 
 			     unsigned offset, unsigned to)
 {
-	kmap(page);
 	return 0;
 }
 
@@ -283,7 +282,6 @@
 	lock_kernel();
 	status = smb_updatepage(file, page, offset, to-offset);
 	unlock_kernel();
-	kunmap(page);
 	return status;
 }
 
@@ -349,8 +347,14 @@
 smb_file_release(struct inode *inode, struct file * file)
 {
 	lock_kernel();
-	if (!--inode->u.smbfs_i.openers)
+	if (!--inode->u.smbfs_i.openers) {
+		/* We must flush any dirty pages now as we won't be able to
+		   write anything after close. mmap can trigger this.
+		   "openers" should perhaps include mmap'ers ... */
+		filemap_fdatasync(inode->i_mapping);
+		filemap_fdatawait(inode->i_mapping);
 		smb_close(inode);
+	}
 	unlock_kernel();
 	return 0;
 }
diff -u --recursive --new-file v2.5.1/linux/fs/smbfs/getopt.c linux/fs/smbfs/getopt.c
--- v2.5.1/linux/fs/smbfs/getopt.c	Fri Apr 27 14:10:32 2001
+++ linux/fs/smbfs/getopt.c	Thu Jan  3 13:33:50 2002
@@ -46,7 +46,7 @@
 
 	for (i = 0; opts[i].name != NULL; i++) {
 		if (!strcmp(opts[i].name, token)) {
-			if (opts[i].has_arg && (!val || !*val)) {
+			if (!opts[i].flag && (!val || !*val)) {
 				printk("%s: the %s option requires an argument\n",
 				       caller, token);
 				return -1;
diff -u --recursive --new-file v2.5.1/linux/fs/smbfs/getopt.h linux/fs/smbfs/getopt.h
--- v2.5.1/linux/fs/smbfs/getopt.h	Mon Aug 14 13:31:10 2000
+++ linux/fs/smbfs/getopt.h	Thu Jan  3 13:33:50 2002
@@ -3,7 +3,6 @@
 
 struct option {
 	const char *name;
-	int has_arg;
 	unsigned long flag;
 	int val;
 };
diff -u --recursive --new-file v2.5.1/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.5.1/linux/fs/smbfs/inode.c	Tue Oct  2 17:03:34 2001
+++ linux/fs/smbfs/inode.c	Thu Jan  3 13:33:50 2002
@@ -22,6 +22,7 @@
 #include <linux/dcache.h>
 #include <linux/smp_lock.h>
 #include <linux/nls.h>
+#include <linux/seq_file.h>
 
 #include <linux/smb_fs.h>
 #include <linux/smbno.h>
@@ -41,9 +42,12 @@
 #define SMB_NLS_REMOTE ""
 #endif
 
+#define SMB_TTL_DEFAULT 1000
+
 static void smb_delete_inode(struct inode *);
 static void smb_put_super(struct super_block *);
 static int  smb_statfs(struct super_block *, struct statfs *);
+static int  smb_show_options(struct seq_file *, struct vfsmount *);
 
 static struct super_operations smb_sops =
 {
@@ -51,6 +55,7 @@
 	delete_inode:	smb_delete_inode,
 	put_super:	smb_put_super,
 	statfs:		smb_statfs,
+	show_options:	smb_show_options,
 };
 
 
@@ -259,21 +264,20 @@
 	clear_inode(ino);
 }
 
-/* FIXME: flags and has_arg could probably be merged. */
 static struct option opts[] = {
-	{ "version",	1, 0, 'v' },
-	{ "win95",	0, SMB_MOUNT_WIN95, 1 },
-	{ "oldattr",	0, SMB_MOUNT_OLDATTR, 1 },
-	{ "dirattr",	0, SMB_MOUNT_DIRATTR, 1 },
-	{ "case",	0, SMB_MOUNT_CASE, 1 },
-	{ "uid",	1, 0, 'u' },
-	{ "gid",	1, 0, 'g' },
-	{ "file_mode",	1, 0, 'f' },
-	{ "dir_mode",	1, 0, 'd' },
-	{ "iocharset",	1, 0, 'i' },
-	{ "codepage",	1, 0, 'c' },
-	{ "ttl",	1, 0, 't' },
-	{ NULL,		0, 0, 0}
+	{ "version",	0, 'v' },
+	{ "win95",	SMB_MOUNT_WIN95, 1 },
+	{ "oldattr",	SMB_MOUNT_OLDATTR, 1 },
+	{ "dirattr",	SMB_MOUNT_DIRATTR, 1 },
+	{ "case",	SMB_MOUNT_CASE, 1 },
+	{ "uid",	0, 'u' },
+	{ "gid",	0, 'g' },
+	{ "file_mode",	0, 'f' },
+	{ "dir_mode",	0, 'd' },
+	{ "iocharset",	0, 'i' },
+	{ "codepage",	0, 'c' },
+	{ "ttl",	0, 't' },
+	{ NULL,		0, 0}
 };
 
 static int
@@ -310,12 +314,10 @@
 			mnt->gid = value;
 			break;
 		case 'f':
-			mnt->file_mode = value & (S_IRWXU | S_IRWXG | S_IRWXO);
-			mnt->file_mode |= S_IFREG;
+			mnt->file_mode = (value & S_IRWXUGO) | S_IFREG;
 			break;
 		case 'd':
-			mnt->dir_mode = value & (S_IRWXU | S_IRWXG | S_IRWXO);
-			mnt->dir_mode |= S_IFDIR;
+			mnt->dir_mode = (value & S_IRWXUGO) | S_IFDIR;
 			break;
 		case 'i':
 			strncpy(mnt->codepage.local_name, optarg, 
@@ -338,6 +340,45 @@
 	return c;
 }
 
+/*
+ * smb_show_options() is for displaying mount options in /proc/mounts.
+ * It tries to avoid showing settings that were not changed from their
+ * defaults.
+ */
+static int
+smb_show_options(struct seq_file *s, struct vfsmount *m)
+{
+	struct smb_mount_data_kernel *mnt = m->mnt_sb->u.smbfs_sb.mnt;
+	int i;
+
+	for (i = 0; opts[i].name != NULL; i++)
+		if (mnt->flags & opts[i].flag)
+			seq_printf(s, ",%s", opts[i].name);
+
+	if (mnt->uid != 0)
+		seq_printf(s, ",uid=%d", mnt->uid);
+	if (mnt->gid != 0)
+		seq_printf(s, ",gid=%d", mnt->gid);
+	if (mnt->mounted_uid != 0)
+		seq_printf(s, ",mounted_uid=%d", mnt->mounted_uid);
+
+	/* 
+	 * Defaults for file_mode and dir_mode are unknown to us; they
+	 * depend on the current umask of the user doing the mount.
+	 */
+	seq_printf(s, ",file_mode=%04o", mnt->file_mode & S_IRWXUGO);
+	seq_printf(s, ",dir_mode=%04o", mnt->dir_mode & S_IRWXUGO);
+
+	if (strcmp(mnt->codepage.local_name, CONFIG_NLS_DEFAULT))
+		seq_printf(s, ",iocharset=%s", mnt->codepage.local_name);
+	if (strcmp(mnt->codepage.remote_name, SMB_NLS_REMOTE))
+		seq_printf(s, ",codepage=%s", mnt->codepage.remote_name);
+
+	if (mnt->ttl != SMB_TTL_DEFAULT)
+		seq_printf(s, ",ttl=%d", mnt->ttl);
+
+	return 0;
+}
 
 static void
 smb_put_super(struct super_block *sb)
@@ -425,7 +466,7 @@
 	strncpy(mnt->codepage.remote_name, SMB_NLS_REMOTE,
 		SMB_NLS_MAXNAMELEN);
 
-	mnt->ttl = 1000;
+	mnt->ttl = SMB_TTL_DEFAULT;
 	if (ver == SMB_MOUNT_OLDVERSION) {
 		mnt->version = oldmnt->version;
 
@@ -434,12 +475,8 @@
 		mnt->uid = oldmnt->uid;
 		mnt->gid = oldmnt->gid;
 
-		mnt->file_mode =
-			oldmnt->file_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
-		mnt->dir_mode =
-			oldmnt->dir_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
-		mnt->file_mode |= S_IFREG;
-		mnt->dir_mode  |= S_IFDIR;
+		mnt->file_mode = (oldmnt->file_mode & S_IRWXUGO) | S_IFREG;
+		mnt->dir_mode = (oldmnt->dir_mode & S_IRWXUGO) | S_IFDIR;
 
 		mnt->flags = (oldmnt->file_mode >> 9);
 	} else {
@@ -510,7 +547,7 @@
 {
 	struct inode *inode = dentry->d_inode;
 	struct smb_sb_info *server = server_from_dentry(dentry);
-	unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
+	unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXUGO);
 	int error, changed, refresh = 0;
 	struct smb_fattr fattr;
 
@@ -535,6 +572,10 @@
 		VERBOSE("changing %s/%s, old size=%ld, new size=%ld\n",
 			DENTRY_PATH(dentry),
 			(long) inode->i_size, (long) attr->ia_size);
+
+		filemap_fdatasync(inode->i_mapping);
+		filemap_fdatawait(inode->i_mapping);
+
 		error = smb_open(dentry, O_WRONLY);
 		if (error)
 			goto out;
diff -u --recursive --new-file v2.5.1/linux/fs/super.c linux/fs/super.c
--- v2.5.1/linux/fs/super.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/super.c	Tue Jan  1 12:58:39 2002
@@ -34,8 +34,6 @@
 #define __NO_VERSION__
 #include <linux/module.h>
 
-int do_remount_sb(struct super_block *sb, int flags, void * data);
-
 LIST_HEAD(super_blocks);
 spinlock_t sb_lock = SPIN_LOCK_UNLOCKED;
 
@@ -377,7 +375,7 @@
 	get_filesystem(type);
 }
 
-void put_unnamed_dev(kdev_t dev);	/* should become static */
+static void put_anon_dev(kdev_t dev);
 
 /**
  *	remove_super	-	makes superblock unreachable
@@ -407,7 +405,7 @@
 	if (bdev)
 		blkdev_put(bdev, BDEV_FS);
 	else
-		put_unnamed_dev(dev);
+		put_anon_dev(dev);
 }
 
 struct vfsmount *alloc_vfsmnt(void);
@@ -420,7 +418,7 @@
 
 	list_for_each(p, &super_blocks) {
 		struct super_block * s = sb_entry(p);
-		if (s->s_dev == dev) {
+		if (kdev_same(s->s_dev, dev)) {
 			s->s_count++;
 			return s;
 		}
@@ -452,7 +450,7 @@
 {
 	struct super_block * sb;
 
-	if (dev) {
+	if (!kdev_none(dev)) {
 		sb = get_super(dev);
 		if (sb) {
 			if (sb->s_dirt)
@@ -489,7 +487,7 @@
 {
 	struct super_block * s;
 
-	if (!dev)
+	if (kdev_none(dev))
 		return NULL;
 
 	while (1) {
@@ -530,40 +528,127 @@
 	return err;
 }
 
+/**
+ *	do_remount_sb	-	asks filesystem to change mount options.
+ *	@sb:	superblock in question
+ *	@flags:	numeric part of options
+ *	@data:	the rest of options
+ *
+ *	Alters the mount options of a mounted file system.
+ */
+int do_remount_sb(struct super_block *sb, int flags, void *data)
+{
+	int retval;
+	
+	if (!(flags & MS_RDONLY) && !kdev_none(sb->s_dev) && is_read_only(sb->s_dev))
+		return -EACCES;
+		/*flags |= MS_RDONLY;*/
+	if (flags & MS_RDONLY)
+		acct_auto_close(sb);
+	shrink_dcache_sb(sb);
+	fsync_super(sb);
+	/* If we are remounting RDONLY, make sure there are no rw files open */
+	if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
+		if (!fs_may_remount_ro(sb))
+			return -EBUSY;
+	if (sb->s_op && sb->s_op->remount_fs) {
+		lock_super(sb);
+		retval = sb->s_op->remount_fs(sb, &flags, data);
+		unlock_super(sb);
+		if (retval)
+			return retval;
+	}
+	sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
+	return 0;
+}
+
 /*
  * Unnamed block devices are dummy devices used by virtual
  * filesystems which don't use real block-devices.  -- jrs
  */
 
-static unsigned long unnamed_dev_in_use[256/(8*sizeof(unsigned long))];
+enum {Max_anon = 256};
+static unsigned long unnamed_dev_in_use[Max_anon/(8*sizeof(unsigned long))];
+static spinlock_t unnamed_dev_lock = SPIN_LOCK_UNLOCKED;/* protects the above */
 
-kdev_t get_unnamed_dev(void)
+/**
+ *	put_anon_dev	-	release anonymous device number.
+ *	@dev:	device in question
+ */
+static void put_anon_dev(kdev_t dev)
 {
-	int i;
-
-	for (i = 1; i < 256; i++) {
-		if (!test_and_set_bit(i,unnamed_dev_in_use))
-			return MKDEV(UNNAMED_MAJOR, i);
-	}
-	return 0;
+	spin_lock(&unnamed_dev_lock);
+	clear_bit(minor(dev), unnamed_dev_in_use);
+	spin_unlock(&unnamed_dev_lock);
 }
 
-void put_unnamed_dev(kdev_t dev)
+/**
+ *	get_anon_super	-	allocate a superblock for non-device fs
+ *	@type:		filesystem type
+ *	@compare:	check if existing superblock is what we want
+ *	@data:		argument for @compare.
+ *
+ *	get_anon_super is a helper for non-blockdevice filesystems.
+ *	It either finds and returns one of the superblocks of given type
+ *	(if it can find one that would satisfy caller) or creates a new
+ *	one.  In the either case we return an active reference to superblock
+ *	with ->s_umount locked.  If superblock is new it gets a new
+ *	anonymous device allocated for it and is inserted into lists -
+ *	other initialization is left to caller.
+ *
+ *	Rather than duplicating all that logics every time when
+ *	we want something that doesn't fit "nodev" and "single" we pull
+ *	the relevant code into common helper and let get_sb_...() call
+ *	it.
+ *
+ *	NB: get_sb_...() is going to become an fs type method, with
+ *	current ->read_super() becoming a callback used by common instances.
+ */
+struct super_block *get_anon_super(struct file_system_type *type,
+	int (*compare)(struct super_block *,void *), void *data)
 {
-	if (!dev || MAJOR(dev) != UNNAMED_MAJOR)
-		return;
-	if (test_and_clear_bit(MINOR(dev), unnamed_dev_in_use))
-		return;
-	printk("VFS: put_unnamed_dev: freeing unused device %s\n",
-			kdevname(dev));
+	struct super_block *s = alloc_super();
+	int dev;
+	struct list_head *p;
+
+	if (!s)
+		return ERR_PTR(-ENOMEM);
+
+	spin_lock(&unnamed_dev_lock);
+	dev = find_first_zero_bit(unnamed_dev_in_use, Max_anon);
+	if (dev == Max_anon) {
+		spin_unlock(&unnamed_dev_lock);
+		destroy_super(s);
+		return ERR_PTR(-EMFILE);
+	}
+	set_bit(dev, unnamed_dev_in_use);
+	spin_unlock(&unnamed_dev_lock);
+
+retry:
+	spin_lock(&sb_lock);
+	if (compare) list_for_each(p, &type->fs_supers) {
+		struct super_block *old;
+		old = list_entry(p, struct super_block, s_instances);
+		if (!compare(old, data))
+			continue;
+		if (!grab_super(old))
+			goto retry;
+		destroy_super(s);
+		return old;
+	}
+
+	s->s_dev = mk_kdev(0, dev);
+	insert_super(s, type);
+	return s;
 }
 
 static struct super_block *get_sb_bdev(struct file_system_type *fs_type,
-	char *dev_name, int flags, void * data)
+	int flags, char *dev_name, void * data)
 {
 	struct inode *inode;
 	struct block_device *bdev;
 	struct block_device_operations *bdops;
+	devfs_handle_t de;
 	struct super_block * s;
 	struct nameidata nd;
 	struct list_head *p;
@@ -587,28 +672,26 @@
 		goto out;
 	bd_acquire(inode);
 	bdev = inode->i_bdev;
-	bdops = devfs_get_ops ( devfs_get_handle_from_inode (inode) );
+	de = devfs_get_handle_from_inode (inode);
+	bdops = devfs_get_ops (de);         /*  Increments module use count  */
 	if (bdops) bdev->bd_op = bdops;
 	/* Done with lookups, semaphore down */
 	dev = to_kdev_t(bdev->bd_dev);
 	if (!(flags & MS_RDONLY))
 		mode |= FMODE_WRITE;
 	error = blkdev_get(bdev, mode, 0, BDEV_FS);
+	devfs_put_ops (de);   /*  Decrement module use count now we're safe  */
 	if (error)
 		goto out;
 	check_disk_change(dev);
 	error = -EACCES;
-	if (!(flags & MS_RDONLY) && is_read_only(dev)) {
-		blkdev_put(bdev, BDEV_FS);
-		goto out;
-	}
+	if (!(flags & MS_RDONLY) && is_read_only(dev))
+		goto out1;
 
 	error = -ENOMEM;
 	s = alloc_super();
-	if (!s) {
-		blkdev_put(bdev, BDEV_FS);
-		goto out;
-	}
+	if (!s)
+		goto out1;
 
 	error = -EBUSY;
 restart:
@@ -616,14 +699,13 @@
 
 	list_for_each(p, &super_blocks) {
 		struct super_block *old = sb_entry(p);
-		if (old->s_dev != dev)
+		if (!kdev_same(old->s_dev, dev))
 			continue;
 		if (old->s_type != fs_type ||
 		    ((flags ^ old->s_flags) & MS_RDONLY)) {
 			spin_unlock(&sb_lock);
 			destroy_super(s);
-			blkdev_put(bdev, BDEV_FS);
-			goto out;
+			goto out1;
 		}
 		if (!grab_super(old))
 			goto restart;
@@ -636,97 +718,103 @@
 	s->s_bdev = bdev;
 	s->s_flags = flags;
 	insert_super(s, fs_type);
-
-	error = -EINVAL;
-	lock_super(s);
 	if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0))
-		goto out_fail;
+		goto Einval;
 	s->s_flags |= MS_ACTIVE;
-	unlock_super(s);
 	path_release(&nd);
 	return s;
 
-out_fail:
-	unlock_super(s);
+Einval:
 	deactivate_super(s);
 	remove_super(s);
+	error = -EINVAL;
+	goto out;
+out1:
+	blkdev_put(bdev, BDEV_FS);
 out:
 	path_release(&nd);
 	return ERR_PTR(error);
 }
 
 static struct super_block *get_sb_nodev(struct file_system_type *fs_type,
-	int flags, void * data)
+	int flags, char *dev_name, void *data)
 {
-	struct super_block *s = alloc_super();
+	struct super_block *s = get_anon_super(fs_type, NULL, NULL);
+
+	if (IS_ERR(s))
+		return s;
 
-	if (!s)
-		return ERR_PTR(-ENOMEM);
-	s->s_dev = get_unnamed_dev();
-	if (!s->s_dev) {
-		destroy_super(s);
-		return ERR_PTR(-EMFILE);
-	}
 	s->s_flags = flags;
-	spin_lock(&sb_lock);
-	insert_super(s, fs_type);
-	lock_super(s);
-	if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0))
-		goto out_fail;
+	if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0)) {
+		deactivate_super(s);
+		remove_super(s);
+		return ERR_PTR(-EINVAL);
+	}
 	s->s_flags |= MS_ACTIVE;
-	unlock_super(s);
 	return s;
+}
 
-out_fail:
-	unlock_super(s);
-	deactivate_super(s);
-	remove_super(s);
-	return ERR_PTR(-EINVAL);
+static int compare_single(struct super_block *s, void *p)
+{
+	return 1;
 }
 
 static struct super_block *get_sb_single(struct file_system_type *fs_type,
-	int flags, void *data)
+	int flags, char *dev_name, void *data)
 {
-	struct super_block * s = alloc_super();
-	if (!s)
-		return ERR_PTR(-ENOMEM);
-	/*
-	 * Get the superblock of kernel-wide instance, but
-	 * keep the reference to fs_type.
-	 */
-retry:
-	spin_lock(&sb_lock);
-	if (!list_empty(&fs_type->fs_supers)) {
-		struct super_block *old;
-		old = list_entry(fs_type->fs_supers.next, struct super_block,
-				s_instances);
-		if (!grab_super(old))
-			goto retry;
-		destroy_super(s);
-		do_remount_sb(old, flags, data);
-		return old;
-	} else {
-		s->s_dev = get_unnamed_dev();
-		if (!s->s_dev) {
-			spin_unlock(&sb_lock);
-			destroy_super(s);
-			return ERR_PTR(-EMFILE);
-		}
+	struct super_block *s = get_anon_super(fs_type, compare_single, NULL);
+
+	if (IS_ERR(s))
+		return s;
+	if (!s->s_root) {
 		s->s_flags = flags;
-		insert_super(s, fs_type);
-		lock_super(s);
-		if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0))
-			goto out_fail;
+		if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0)) {
+			deactivate_super(s);
+			remove_super(s);
+			return ERR_PTR(-EINVAL);
+		}
 		s->s_flags |= MS_ACTIVE;
-		unlock_super(s);
-		return s;
-
-	out_fail:
-		unlock_super(s);
-		deactivate_super(s);
-		remove_super(s);
-		return ERR_PTR(-EINVAL);
 	}
+	do_remount_sb(s, flags, data);
+	return s;
+}
+
+struct vfsmount *
+do_kern_mount(const char *fstype, int flags, char *name, void *data)
+{
+	struct file_system_type *type = get_fs_type(fstype);
+	struct super_block *sb = ERR_PTR(-ENOMEM);
+	struct vfsmount *mnt;
+
+	if (!type)
+		return ERR_PTR(-ENODEV);
+
+	mnt = alloc_vfsmnt();
+	if (!mnt)
+		goto out;
+	set_devname(mnt, name);
+	if (type->fs_flags & FS_REQUIRES_DEV)
+		sb = get_sb_bdev(type, flags, name, data);
+	else if (type->fs_flags & FS_SINGLE)
+		sb = get_sb_single(type, flags, name, data);
+	else
+		sb = get_sb_nodev(type, flags, name, data);
+	if (IS_ERR(sb))
+		goto out_mnt;
+	if (type->fs_flags & FS_NOMOUNT)
+		sb->s_flags |= MS_NOUSER;
+	mnt->mnt_sb = sb;
+	mnt->mnt_root = dget(sb->s_root);
+	mnt->mnt_mountpoint = sb->s_root;
+	mnt->mnt_parent = mnt;
+	up_write(&sb->s_umount);
+	put_filesystem(type);
+	return mnt;
+out_mnt:
+	free_vfsmnt(mnt);
+out:
+	put_filesystem(type);
+	return (struct vfsmount *)sb;
 }
 
 void kill_super(struct super_block *sb)
@@ -739,7 +827,6 @@
 		return;
 
 	down_write(&sb->s_umount);
-	lock_kernel();
 	sb->s_root = NULL;
 	/* Need to clean after the sucker */
 	if (fs->fs_flags & FS_LITTER)
@@ -748,6 +835,7 @@
 	dput(root);
 	fsync_super(sb);
 	lock_super(sb);
+	lock_kernel();
 	sb->s_flags &= ~MS_ACTIVE;
 	invalidate_inodes(sb);	/* bad name - it should be evict_inodes() */
 	if (sop) {
@@ -768,96 +856,7 @@
 	remove_super(sb);
 }
 
-/*
- * Alters the mount flags of a mounted file system. Only the mount point
- * is used as a reference - file system type and the device are ignored.
- */
-
-int do_remount_sb(struct super_block *sb, int flags, void *data)
-{
-	int retval;
-	
-	if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev))
-		return -EACCES;
-		/*flags |= MS_RDONLY;*/
-	if (flags & MS_RDONLY)
-		acct_auto_close(sb->s_dev);
-	shrink_dcache_sb(sb);
-	fsync_super(sb);
-	/* If we are remounting RDONLY, make sure there are no rw files open */
-	if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
-		if (!fs_may_remount_ro(sb))
-			return -EBUSY;
-	if (sb->s_op && sb->s_op->remount_fs) {
-		lock_super(sb);
-		retval = sb->s_op->remount_fs(sb, &flags, data);
-		unlock_super(sb);
-		if (retval)
-			return retval;
-	}
-	sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
-
-	/*
-	 * We can't invalidate inodes as we can loose data when remounting
-	 * (someone might manage to alter data while we are waiting in lock_super()
-	 * or in foo_remount_fs()))
-	 */
-
-	return 0;
-}
-
-struct vfsmount *do_kern_mount(char *type, int flags, char *name, void *data)
-{
-	struct file_system_type * fstype;
-	struct vfsmount *mnt = NULL;
-	struct super_block *sb;
-
-	if (!type || !memchr(type, 0, PAGE_SIZE))
-		return ERR_PTR(-EINVAL);
-
-	/* we need capabilities... */
-	if (!capable(CAP_SYS_ADMIN))
-		return ERR_PTR(-EPERM);
-
-	/* ... filesystem driver... */
-	fstype = get_fs_type(type);
-	if (!fstype)		
-		return ERR_PTR(-ENODEV);
-
-	/* ... allocated vfsmount... */
-	mnt = alloc_vfsmnt();
-	if (!mnt) {
-		mnt = ERR_PTR(-ENOMEM);
-		goto fs_out;
-	}
-	set_devname(mnt, name);
-	/* get locked superblock */
-	if (fstype->fs_flags & FS_REQUIRES_DEV)
-		sb = get_sb_bdev(fstype, name, flags, data);
-	else if (fstype->fs_flags & FS_SINGLE)
-		sb = get_sb_single(fstype, flags, data);
-	else
-		sb = get_sb_nodev(fstype, flags, data);
-
-	if (IS_ERR(sb)) {
-		free_vfsmnt(mnt);
-		mnt = (struct vfsmount *)sb;
-		goto fs_out;
-	}
-	if (fstype->fs_flags & FS_NOMOUNT)
-		sb->s_flags |= MS_NOUSER;
-
-	mnt->mnt_sb = sb;
-	mnt->mnt_root = dget(sb->s_root);
-	mnt->mnt_mountpoint = mnt->mnt_root;
-	mnt->mnt_parent = mnt;
-	up_write(&sb->s_umount);
-fs_out:
-	put_filesystem(fstype);
-	return mnt;
-}
-
 struct vfsmount *kern_mount(struct file_system_type *type)
 {
-	return do_kern_mount((char *)type->name, 0, (char *)type->name, NULL);
+	return do_kern_mount(type->name, 0, (char *)type->name, NULL);
 }
diff -u --recursive --new-file v2.5.1/linux/fs/sysv/ChangeLog linux/fs/sysv/ChangeLog
--- v2.5.1/linux/fs/sysv/ChangeLog	Fri Nov  9 13:45:35 2001
+++ linux/fs/sysv/ChangeLog	Sun Dec 30 16:59:04 2001
@@ -1,3 +1,12 @@
+Sat Dec 15 2001  Christoph Hellwig  <hch@caldera.de>
+
+	* inode.c (sysv_read_inode): Mark inode as bad in case of failure.
+	* super.c (complete_read_super): Check for bad root inode.
+
+Wed Nov 21 2001  Andrew Morton  <andrewm@uow.edu.au>
+
+	* file.c (sysv_sync_file): Call fsync_inode_data_buffers.
+
 Fri Oct 26 2001  Christoph Hellwig  <hch@caldera.de>
 
 	* dir.c, ialloc.c, namei.c, include/linux/sysv_fs_i.h:
diff -u --recursive --new-file v2.5.1/linux/fs/sysv/dir.c linux/fs/sysv/dir.c
--- v2.5.1/linux/fs/sysv/dir.c	Fri Nov  9 13:45:35 2001
+++ linux/fs/sysv/dir.c	Sun Dec 30 10:53:53 2001
@@ -41,7 +41,6 @@
 	struct inode *dir = (struct inode *)page->mapping->host;
 	int err = 0;
 
-	dir->i_version = ++event;
 	page->mapping->a_ops->commit_write(NULL, page, from, to);
 	if (IS_SYNC(dir))
 		err = waitfor_one_page(page);
@@ -111,7 +110,6 @@
 
 done:
 	filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
-	filp->f_version = inode->i_version;
 	UPDATE_ATIME(inode);
 	return 0;
 }
diff -u --recursive --new-file v2.5.1/linux/fs/sysv/inode.c linux/fs/sysv/inode.c
--- v2.5.1/linux/fs/sysv/inode.c	Fri Nov  9 13:45:35 2001
+++ linux/fs/sysv/inode.c	Sun Dec 30 16:59:04 2001
@@ -152,13 +152,13 @@
 		printk("Bad inode number on dev %s"
 		       ": %d is out of range\n",
 		       kdevname(inode->i_dev), ino);
-		return;
+		goto bad_inode;
 	}
 	raw_inode = sysv_raw_inode(sb, ino, &bh);
 	if (!raw_inode) {
 		printk("Major problem: unable to read inode from dev %s\n",
 		       bdevname(inode->i_dev));
-		return;
+		goto bad_inode;
 	}
 	/* SystemV FS: kludge permissions if ino==SYSV_ROOT_INO ?? */
 	inode->i_mode = fs16_to_cpu(sb, raw_inode->i_mode);
@@ -178,6 +178,11 @@
 		rdev = (u16)fs32_to_cpu(sb, inode->u.sysv_i.i_data[0]);
 	inode->u.sysv_i.i_dir_start_lookup = 0;
 	sysv_set_inode(inode, rdev);
+	return;
+
+bad_inode:
+	make_bad_inode(inode);
+	return;
 }
 
 static struct buffer_head * sysv_update_inode(struct inode * inode)
diff -u --recursive --new-file v2.5.1/linux/fs/sysv/itree.c linux/fs/sysv/itree.c
--- v2.5.1/linux/fs/sysv/itree.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/sysv/itree.c	Thu Dec 27 08:17:43 2001
@@ -211,9 +211,7 @@
 	/* Simplest case - block found, no allocation needed */
 	if (!partial) {
 got_it:
-		bh_result->b_dev = sb->s_dev;
-		bh_result->b_blocknr = block_to_cpu(sb, chain[depth-1].key);
-		bh_result->b_state |= (1UL << BH_Mapped);
+		map_bh(bh_result, sb, block_to_cpu(sb, chain[depth-1].key));
 		/* Clean up and exit */
 		partial = chain+depth-1; /* the whole chain */
 		goto cleanup;
diff -u --recursive --new-file v2.5.1/linux/fs/sysv/super.c linux/fs/sysv/super.c
--- v2.5.1/linux/fs/sysv/super.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/sysv/super.c	Sun Dec 30 16:59:04 2001
@@ -315,8 +315,6 @@
 	sb->sv_ninodes = (sb->sv_firstdatazone - sb->sv_firstinodezone)
 		<< sb->sv_inodes_per_block_bits;
 
-	sb->s_blocksize = bsize;
-	sb->s_blocksize_bits = n_bits;
 	if (!silent)
 		printk("VFS: Found a %s FS (block size = %ld) on device %s\n",
 		       found, sb->s_blocksize, bdevname(sb->s_dev));
@@ -325,7 +323,7 @@
 	/* set up enough so that it can read an inode */
 	sb->s_op = &sysv_sops;
 	root_inode = iget(sb,SYSV_ROOT_INO);
-	if (!root_inode) {
+	if (!root_inode || is_bad_inode(root_inode)) {
 		printk("SysV FS: get root inode failed\n");
 		return 0;
 	}
@@ -361,8 +359,7 @@
 		panic("Coherent FS: bad super-block size");
 	if (64 != sizeof (struct sysv_inode))
 		panic("sysv fs: bad i-node size");
-	set_blocksize(dev,BLOCK_SIZE);
-	sb->s_blocksize = BLOCK_SIZE;
+	sb_set_blocksize(sb, BLOCK_SIZE);
 	sb->sv_block_base = 0;
 
 	for (i = 0; i < sizeof(flavours)/sizeof(flavours[0]) && !size; i++) {
@@ -380,8 +377,7 @@
 		case 1:
 			blocknr = bh->b_blocknr << 1;
 			brelse(bh);
-			set_blocksize(dev, 512);
-			sb->s_blocksize = 512;
+			sb_set_blocksize(sb, 512);
 			bh1 = sb_bread(sb, blocknr);
 			bh = sb_bread(sb, blocknr + 1);
 			break;
@@ -391,8 +387,7 @@
 		case 3:
 			blocknr = bh->b_blocknr >> 1;
 			brelse(bh);
-			set_blocksize(dev, 2048);
-			sb->s_blocksize = 2048;
+			sb_set_blocksize(sb, 2048);
 			bh1 = bh = sb_bread(sb, blocknr);
 			break;
 		default:
@@ -408,7 +403,7 @@
 
 	brelse(bh1);
 	brelse(bh);
-	set_blocksize(sb->s_dev,BLOCK_SIZE);
+	sb_set_blocksize(sb, BLOCK_SIZE);
 	printk("oldfs: cannot read superblock\n");
 failed:
 	return NULL;
@@ -443,8 +438,7 @@
 	sb->sv_type = FSTYPE_V7;
 	sb->sv_bytesex = BYTESEX_PDP;
 
-	set_blocksize(dev, 512);
-	sb->s_blocksize = 512;
+	sb_set_blocksize(sb, 512);
 
 	if ((bh = sb_bread(sb, 1)) == NULL) {
 		if (!silent)
diff -u --recursive --new-file v2.5.1/linux/fs/udf/inode.c linux/fs/udf/inode.c
--- v2.5.1/linux/fs/udf/inode.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/udf/inode.c	Sun Dec 30 10:53:53 2001
@@ -215,7 +215,6 @@
 	page_cache_release(page);
 
 	mark_inode_dirty(inode);
-	inode->i_version ++;
 }
 
 struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int *err)
@@ -310,7 +309,6 @@
 	mark_buffer_dirty(sbh);
 	udf_release_data(sbh);
 	mark_inode_dirty(inode);
-	inode->i_version ++;
 	return dbh;
 }
 
@@ -324,11 +322,7 @@
 	{
 		phys = udf_block_map(inode, block);
 		if (phys)
-		{
-			bh_result->b_dev = inode->i_dev;
-			bh_result->b_blocknr = phys;
-			bh_result->b_state |= (1UL << BH_Mapped);
-		}
+			map_bh(bh_result, inode->i_sb, phys);
 		return 0;
 	}
 
@@ -357,11 +351,9 @@
 	if (!phys)
 		BUG();
 
-	bh_result->b_dev = inode->i_dev;
-	bh_result->b_blocknr = phys;
-	bh_result->b_state |= (1UL << BH_Mapped);
 	if (new)
 		bh_result->b_state |= (1UL << BH_New);
+	map_bh(bh_result, inode->i_sb, phys);
 abort:
 	unlock_kernel();
 	return err;
@@ -1039,7 +1031,6 @@
 	long convtime_usec;
 	int offset, alen;
 
-	inode->i_version = ++event;
 	UDF_I_NEW_INODE(inode) = 0;
 
 	fe = (struct FileEntry *)bh->b_data;
diff -u --recursive --new-file v2.5.1/linux/fs/udf/namei.c linux/fs/udf/namei.c
--- v2.5.1/linux/fs/udf/namei.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/udf/namei.c	Sun Dec 30 10:53:53 2001
@@ -595,7 +595,6 @@
 		dir->i_size += nfidlen;
 		if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
 			UDF_I_LENALLOC(dir) += nfidlen;
-		dir->i_version = ++event;
 		mark_inode_dirty(dir);
 		return fi;
 	}
@@ -654,7 +653,6 @@
 	if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
 	{
 		mark_inode_dirty(dir);
-		dir->i_version = ++event;
 	}
 	if (fibh.sbh != fibh.ebh)
 		udf_release_data(fibh.ebh);
@@ -692,7 +690,6 @@
 	if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
 	{
 		mark_inode_dirty(dir);
-		dir->i_version = ++event;
 	}
 	mark_inode_dirty(inode);
 
@@ -756,7 +753,6 @@
 		cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
 	cfi.fileCharacteristics |= FILE_DIRECTORY;
 	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
-	dir->i_version = ++event;
 	dir->i_nlink++;
 	mark_inode_dirty(dir);
 	d_instantiate(dentry, inode);
@@ -851,14 +847,12 @@
 	if (!empty_dir(inode))
 		goto end_rmdir;
 	retval = udf_delete_entry(dir, fi, &fibh, &cfi);
-	dir->i_version = ++event;
 	if (retval)
 		goto end_rmdir;
 	if (inode->i_nlink != 2)
 		udf_warning(inode->i_sb, "udf_rmdir",
 			"empty directory has nlink != 2 (%d)",
 			inode->i_nlink);
-	inode->i_version = ++event;
 	inode->i_nlink = 0;
 	inode->i_size = 0;
 	mark_inode_dirty(inode);
@@ -1070,7 +1064,6 @@
 	if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
 	{
 		mark_inode_dirty(dir);
-		dir->i_version = ++event;
 	}
 	if (fibh.sbh != fibh.ebh)
 		udf_release_data(fibh.ebh);
@@ -1123,7 +1116,6 @@
 	if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
 	{
 		mark_inode_dirty(dir);
-		dir->i_version = ++event;
 	}
 	if (fibh.sbh != fibh.ebh)
 		udf_release_data(fibh.ebh);
@@ -1205,7 +1197,6 @@
 		if (!nfi)
 			goto end_rename;
 	}
-	new_dir->i_version = ++event;
 
 	/*
 	 * Like most other Unix systems, set the ctime for inodes on a
@@ -1227,7 +1218,6 @@
 	ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi);
 	udf_delete_entry(old_dir, ofi, &ofibh, &ocfi);
 
-	old_dir->i_version = ++event;
 	if (new_inode)
 	{
 		new_inode->i_nlink--;
@@ -1247,7 +1237,6 @@
 		if (UDF_I_ALLOCTYPE(old_inode) == ICB_FLAG_AD_IN_ICB)
 		{
 			mark_inode_dirty(old_inode);
-			old_inode->i_version = ++event;
 		}
 		else
 			mark_buffer_dirty_inode(dir_bh, old_inode);
diff -u --recursive --new-file v2.5.1/linux/fs/udf/super.c linux/fs/udf/super.c
--- v2.5.1/linux/fs/udf/super.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/udf/super.c	Tue Dec 25 15:39:20 2001
@@ -357,30 +357,11 @@
 static  int
 udf_set_blocksize(struct super_block *sb, int bsize)
 {
-	/* Use specified block size if specified */
-	if (bsize)
-		sb->s_blocksize = bsize;
-	if (get_hardsect_size(sb->s_dev) > sb->s_blocksize)
-		sb->s_blocksize = get_hardsect_size(sb->s_dev); 
-
-	/* Block size must be an even multiple of 512 */
-	switch (sb->s_blocksize)
-	{
-		case 512: sb->s_blocksize_bits = 9;	break;
-		case 1024: sb->s_blocksize_bits = 10; break;
-		case 2048: sb->s_blocksize_bits = 11; break;
-		case 4096: sb->s_blocksize_bits = 12; break;
-		case 8192: sb->s_blocksize_bits = 13; break;
-		default:
-		{
-			udf_debug("Bad block size (%ld)\n", sb->s_blocksize);
-			printk(KERN_ERR "udf: bad block size (%ld)\n", sb->s_blocksize);
-			return 0;
-		}
+	if (!sb_min_blocksize(sb, bsize)) {
+		udf_debug("Bad block size (%d)\n", bsize);
+		printk(KERN_ERR "udf: bad block size (%d)\n", bsize);
+		return 0;
 	}
-
-	/* Set the block size */
-	set_blocksize(sb->s_dev, sb->s_blocksize);
 	return sb->s_blocksize;
 }
 
diff -u --recursive --new-file v2.5.1/linux/fs/ufs/inode.c linux/fs/ufs/inode.c
--- v2.5.1/linux/fs/ufs/inode.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/ufs/inode.c	Sun Dec 30 16:59:04 2001
@@ -310,22 +310,16 @@
 
 static int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create)
 {
-	struct super_block * sb;
-	struct ufs_sb_private_info * uspi;
+	struct super_block * sb = inode->i_sb;
+	struct ufs_sb_private_info * uspi = sb->u.ufs_sb.s_uspi;
 	struct buffer_head * bh;
 	int ret, err, new;
 	unsigned long ptr, phys;
 	
-	sb = inode->i_sb;
-	uspi = sb->u.ufs_sb.s_uspi;
-
 	if (!create) {
 		phys = ufs_frag_map(inode, fragment);
-		if (phys) {
-			bh_result->b_dev = inode->i_dev;
-			bh_result->b_blocknr = phys;
-			bh_result->b_state |= (1UL << BH_Mapped);
-		}
+		if (phys)
+			map_bh(bh_result, sb, phys);
 		return 0;
 	}
 
@@ -392,11 +386,9 @@
 out:
 	if (err)
 		goto abort;
-	bh_result->b_dev = inode->i_dev;
-	bh_result->b_blocknr = phys;
-	bh_result->b_state |= (1UL << BH_Mapped);
 	if (new)
 		bh_result->b_state |= (1UL << BH_New);
+	map_bh(bh_result, sb, phys);
 abort:
 	unlock_kernel();
 	return err;
@@ -494,13 +486,13 @@
 	if (inode->i_ino < UFS_ROOTINO || 
 	    inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) {
 		ufs_warning (sb, "ufs_read_inode", "bad inode number (%lu)\n", inode->i_ino);
-		return;
+		goto bad_inode;
 	}
 	
 	bh = sb_bread(sb, uspi->s_sbbase + ufs_inotofsba(inode->i_ino));
 	if (!bh) {
 		ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino);
-		return;
+		goto bad_inode;
 	}
 	ufs_inode = (struct ufs_inode *) (bh->b_data + sizeof(struct ufs_inode) * ufs_inotofsbo(inode->i_ino));
 
@@ -565,6 +557,11 @@
 	brelse (bh);
 
 	UFSD(("EXIT\n"))
+	return;
+
+bad_inode:
+	make_bad_inode(inode);
+	return;
 }
 
 static int ufs_update_inode(struct inode * inode, int do_sync)
diff -u --recursive --new-file v2.5.1/linux/fs/ufs/super.c linux/fs/ufs/super.c
--- v2.5.1/linux/fs/ufs/super.c	Tue Dec 18 14:56:40 2001
+++ linux/fs/ufs/super.c	Sun Dec 30 16:59:04 2001
@@ -442,6 +442,7 @@
 	struct ufs_super_block_second * usb2;
 	struct ufs_super_block_third * usb3;
 	struct ufs_buffer_head * ubh;	
+	struct inode *inode;
 	unsigned block_size, super_block_size;
 	unsigned flags;
 
@@ -596,8 +597,7 @@
 	}
 	
 again:	
-	set_blocksize (sb->s_dev, block_size);
-	sb->s_blocksize = block_size;
+	sb_set_blocksize(sb, block_size);
 
 	/*
 	 * read ufs super block from device
@@ -716,8 +716,6 @@
 	/*
 	 * Read ufs_super_block into internal data structures
 	 */
-	sb->s_blocksize = fs32_to_cpu(sb, usb1->fs_fsize);
-	sb->s_blocksize_bits = fs32_to_cpu(sb, usb1->fs_fshift);
 	sb->s_op = &ufs_super_ops;
 	sb->dq_op = NULL; /***/
 	sb->s_magic = fs32_to_cpu(sb, usb3->fs_magic);
@@ -790,7 +788,13 @@
 		    fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_maxsymlinklen);
 	
 	sb->u.ufs_sb.s_flags = flags;
-	sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO));
+
+	inode = iget(sb, UFS_ROOTINO);
+	if (!inode || is_bad_inode(inode))
+		goto failed;
+	sb->s_root = d_alloc_root(inode);
+	if (!sb->s_root)
+		goto dalloc_failed;
 
 
 	/*
@@ -803,6 +807,8 @@
 	UFSD(("EXIT\n"))
 	return(sb);
 
+dalloc_failed:
+	iput(inode);
 failed:
 	if (ubh) ubh_brelse_uspi (uspi);
 	if (uspi) kfree (uspi);
diff -u --recursive --new-file v2.5.1/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- v2.5.1/linux/fs/umsdos/inode.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/umsdos/inode.c	Tue Jan  1 18:55:00 2002
@@ -49,7 +49,7 @@
 void UMSDOS_put_super (struct super_block *sb)
 {
 	Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n"));
-	if (saved_root && pseudo_root && sb->s_dev == ROOT_DEV) {
+	if (saved_root && pseudo_root && kdev_same(sb->s_dev, ROOT_DEV)) {
 		shrink_dcache_parent(saved_root);
 		dput(saved_root);
 		saved_root = NULL;
@@ -414,7 +414,7 @@
 	 * must check like this, because we can be used with initrd
 	 */
 		
-	if (sb->s_dev != ROOT_DEV)
+	if (!kdev_same(sb->s_dev, ROOT_DEV))
 		goto out_noroot;
 
 	/* 
diff -u --recursive --new-file v2.5.1/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.5.1/linux/fs/vfat/namei.c	Thu Oct 25 00:02:26 2001
+++ linux/fs/vfat/namei.c	Sun Dec 30 10:53:53 2001
@@ -1040,8 +1040,8 @@
 		return res;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(inode);
-	inode->i_version = ++event;
-	dir->i_version = event;
+	inode->i_version++;
+	dir->i_version++;
 	dentry->d_time = dentry->d_parent->d_inode->i_version;
 	d_instantiate(dentry,inode);
 	return 0;
@@ -1057,7 +1057,7 @@
 	/* remove the shortname */
 	dir->i_mtime = CURRENT_TIME;
 	dir->i_atime = CURRENT_TIME;
-	dir->i_version = ++event;
+	dir->i_version++;
 	mark_inode_dirty(dir);
 	de->name[0] = DELETED_FLAG;
 	fat_mark_buffer_dirty(sb, bh);
@@ -1138,8 +1138,8 @@
 		goto out;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(inode);
-	inode->i_version = ++event;
-	dir->i_version = event;
+	inode->i_version++;
+	dir->i_version++;
 	dir->i_nlink++;
 	inode->i_nlink = 2; /* no need to mark them dirty */
 	res = fat_new_dir(inode, dir, 1);
@@ -1209,7 +1209,7 @@
 		if (res < 0) goto rename_done;
 	}
 
-	new_dir->i_version = ++event;
+	new_dir->i_version++;
 
 	/* releases old_bh */
 	vfat_remove_entry(old_dir,&old_sinfo,old_bh,old_de);
@@ -1218,7 +1218,7 @@
 	fat_attach(old_inode, sinfo.ino);
 	mark_inode_dirty(old_inode);
 
-	old_dir->i_version = ++event;
+	old_dir->i_version++;
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(old_dir);
 	if (new_inode) {
diff -u --recursive --new-file v2.5.1/linux/fs/vfat/vfatfs_syms.c linux/fs/vfat/vfatfs_syms.c
--- v2.5.1/linux/fs/vfat/vfatfs_syms.c	Fri Oct 12 13:48:42 2001
+++ linux/fs/vfat/vfatfs_syms.c	Sun Dec 30 16:59:00 2001
@@ -33,3 +33,4 @@
 
 module_init(init_vfat_fs)
 module_exit(exit_vfat_fs)
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.1/linux/include/asm-arm/bitops.h linux/include/asm-arm/bitops.h
--- v2.5.1/linux/include/asm-arm/bitops.h	Sun Aug 12 11:14:00 2001
+++ linux/include/asm-arm/bitops.h	Tue Dec 25 21:43:32 2001
@@ -2,6 +2,8 @@
  * Copyright 1995, Russell King.
  * Various bits and pieces copyrights include:
  *  Linus Torvalds (test_bit).
+ * Big endian support: Copyright 2001, Nicolas Pitre
+ *  reworked by rmk.
  *
  * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
  *
@@ -17,81 +19,271 @@
 
 #ifdef __KERNEL__
 
+#include <asm/system.h>
+
 #define smp_mb__before_clear_bit()	do { } while (0)
 #define smp_mb__after_clear_bit()	do { } while (0)
 
 /*
- * Function prototypes to keep gcc -Wall happy.
+ * These functions are the basis of our bit ops.
+ * First, the atomic bitops.
+ *
+ * The endian issue for these functions is handled by the macros below.
  */
-extern void set_bit(int nr, volatile void * addr);
+static inline void
+____atomic_set_bit_mask(unsigned int mask, volatile unsigned char *p)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	*p |= mask;
+	local_irq_restore(flags);
+}
 
-static inline void __set_bit(int nr, volatile void *addr)
+static inline void
+____atomic_clear_bit_mask(unsigned int mask, volatile unsigned char *p)
 {
-	((unsigned char *) addr)[nr >> 3] |= (1U << (nr & 7));
+	unsigned long flags;
+
+	local_irq_save(flags);
+	*p &= ~mask;
+	local_irq_restore(flags);
 }
 
-extern void clear_bit(int nr, volatile void * addr);
+static inline void
+____atomic_change_bit_mask(unsigned int mask, volatile unsigned char *p)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	*p ^= mask;
+	local_irq_restore(flags);
+}
 
-static inline void __clear_bit(int nr, volatile void *addr)
+static inline int
+____atomic_test_and_set_bit_mask(unsigned int mask, volatile unsigned char *p)
 {
-	((unsigned char *) addr)[nr >> 3] &= ~(1U << (nr & 7));
+	unsigned long flags;
+	unsigned int res;
+
+	local_irq_save(flags);
+	res = *p;
+	*p = res | mask;
+	local_irq_restore(flags);
+
+	return res & mask;
 }
 
-extern void change_bit(int nr, volatile void * addr);
+static inline int
+____atomic_test_and_clear_bit_mask(unsigned int mask, volatile unsigned char *p)
+{
+	unsigned long flags;
+	unsigned int res;
 
-static inline void __change_bit(int nr, volatile void *addr)
+	local_irq_save(flags);
+	res = *p;
+	*p = res & ~mask;
+	local_irq_restore(flags);
+
+	return res & mask;
+}
+
+static inline int
+____atomic_test_and_change_bit_mask(unsigned int mask, volatile unsigned char *p)
 {
-	((unsigned char *) addr)[nr >> 3] ^= (1U << (nr & 7));
+	unsigned long flags;
+	unsigned int res;
+
+	local_irq_save(flags);
+	res = *p;
+	*p = res ^ mask;
+	local_irq_restore(flags);
+
+	return res & mask;
 }
 
-extern int test_and_set_bit(int nr, volatile void * addr);
+/*
+ * Now the non-atomic variants.  We let the compiler handle all optimisations
+ * for these.
+ */
+static inline void ____nonatomic_set_bit(int nr, volatile void *p)
+{
+	((unsigned char *) p)[nr >> 3] |= (1U << (nr & 7));
+}
+
+static inline void ____nonatomic_clear_bit(int nr, volatile void *p)
+{
+	((unsigned char *) p)[nr >> 3] &= ~(1U << (nr & 7));
+}
+
+static inline void ____nonatomic_change_bit(int nr, volatile void *p)
+{
+	((unsigned char *) p)[nr >> 3] ^= (1U << (nr & 7));
+}
 
-static inline int __test_and_set_bit(int nr, volatile void *addr)
+static inline int ____nonatomic_test_and_set_bit(int nr, volatile void *p)
 {
 	unsigned int mask = 1 << (nr & 7);
 	unsigned int oldval;
 
-	oldval = ((unsigned char *) addr)[nr >> 3];
-	((unsigned char *) addr)[nr >> 3] = oldval | mask;
+	oldval = ((unsigned char *) p)[nr >> 3];
+	((unsigned char *) p)[nr >> 3] = oldval | mask;
 	return oldval & mask;
 }
 
-extern int test_and_clear_bit(int nr, volatile void * addr);
-
-static inline int __test_and_clear_bit(int nr, volatile void *addr)
+static inline int ____nonatomic_test_and_clear_bit(int nr, volatile void *p)
 {
 	unsigned int mask = 1 << (nr & 7);
 	unsigned int oldval;
 
-	oldval = ((unsigned char *) addr)[nr >> 3];
-	((unsigned char *) addr)[nr >> 3] = oldval & ~mask;
+	oldval = ((unsigned char *) p)[nr >> 3];
+	((unsigned char *) p)[nr >> 3] = oldval & ~mask;
 	return oldval & mask;
 }
 
-extern int test_and_change_bit(int nr, volatile void * addr);
-
-static inline int __test_and_change_bit(int nr, volatile void *addr)
+static inline int ____nonatomic_test_and_change_bit(int nr, volatile void *p)
 {
 	unsigned int mask = 1 << (nr & 7);
 	unsigned int oldval;
 
-	oldval = ((unsigned char *) addr)[nr >> 3];
-	((unsigned char *) addr)[nr >> 3] = oldval ^ mask;
+	oldval = ((unsigned char *) p)[nr >> 3];
+	((unsigned char *) p)[nr >> 3] = oldval ^ mask;
 	return oldval & mask;
 }
 
-extern int find_first_zero_bit(void * addr, unsigned size);
-extern int find_next_zero_bit(void * addr, int size, int offset);
-
 /*
  * This routine doesn't need to be atomic.
  */
-static inline int test_bit(int nr, const void * addr)
+static inline int ____test_bit(int nr, const void * p)
 {
-    return ((unsigned char *) addr)[nr >> 3] & (1U << (nr & 7));
+    return ((volatile unsigned char *) p)[nr >> 3] & (1U << (nr & 7));
 }	
 
 /*
+ *  A note about Endian-ness.
+ *  -------------------------
+ *
+ * When the ARM is put into big endian mode via CR15, the processor
+ * merely swaps the order of bytes within words, thus:
+ *
+ *          ------------ physical data bus bits -----------
+ *          D31 ... D24  D23 ... D16  D15 ... D8  D7 ... D0
+ * little     byte 3       byte 2       byte 1      byte 0
+ * big        byte 0       byte 1       byte 2      byte 3
+ *
+ * This means that reading a 32-bit word at address 0 returns the same
+ * value irrespective of the endian mode bit.
+ *
+ * Peripheral devices should be connected with the data bus reversed in
+ * "Big Endian" mode.  ARM Application Note 61 is applicable, and is
+ * available from http://www.arm.com/.
+ *
+ * The following assumes that the data bus connectivity for big endian
+ * mode has been followed.
+ *
+ * Note that bit 0 is defined to be 32-bit word bit 0, not byte 0 bit 0.
+ */
+
+/*
+ * Little endian assembly bitops.  nr = 0 -> byte 0 bit 0.
+ */
+extern void _set_bit_le(int nr, volatile void * p);
+extern void _clear_bit_le(int nr, volatile void * p);
+extern void _change_bit_le(int nr, volatile void * p);
+extern int _test_and_set_bit_le(int nr, volatile void * p);
+extern int _test_and_clear_bit_le(int nr, volatile void * p);
+extern int _test_and_change_bit_le(int nr, volatile void * p);
+extern int _find_first_zero_bit_le(void * p, unsigned size);
+extern int _find_next_zero_bit_le(void * p, int size, int offset);
+
+/*
+ * Big endian assembly bitops.  nr = 0 -> byte 3 bit 0.
+ */
+extern void _set_bit_be(int nr, volatile void * p);
+extern void _clear_bit_be(int nr, volatile void * p);
+extern void _change_bit_be(int nr, volatile void * p);
+extern int _test_and_set_bit_be(int nr, volatile void * p);
+extern int _test_and_clear_bit_be(int nr, volatile void * p);
+extern int _test_and_change_bit_be(int nr, volatile void * p);
+extern int _find_first_zero_bit_be(void * p, unsigned size);
+extern int _find_next_zero_bit_be(void * p, int size, int offset);
+
+
+/*
+ * The __* form of bitops are non-atomic and may be reordered.
+ */
+#define	ATOMIC_BITOP_LE(name,nr,p)		\
+	(__builtin_constant_p(nr) ?		\
+	 ____atomic_##name##_mask(1 << ((nr) & 7), \
+			((unsigned char *)(p)) + ((nr) >> 3)) : \
+	 _##name##_le(nr,p))
+
+#define	ATOMIC_BITOP_BE(name,nr,p)		\
+	(__builtin_constant_p(nr) ?		\
+	 ____atomic_##name##_mask(1 << ((nr) & 7), \
+			((unsigned char *)(p)) + (((nr) >> 3) ^ 3)) : \
+	 _##name##_be(nr,p))
+
+#define NONATOMIC_BITOP_LE(name,nr,p)	\
+	(____nonatomic_##name(nr, p))
+
+#define NONATOMIC_BITOP_BE(name,nr,p)	\
+	(____nonatomic_##name(nr ^ 0x18, p))
+
+#ifndef __ARMEB__
+/*
+ * These are the little endian, atomic definitions.
+ */
+#define set_bit(nr,p)			ATOMIC_BITOP_LE(set_bit,nr,p)
+#define clear_bit(nr,p)			ATOMIC_BITOP_LE(clear_bit,nr,p)
+#define change_bit(nr,p)		ATOMIC_BITOP_LE(change_bit,nr,p)
+#define test_and_set_bit(nr,p)		ATOMIC_BITOP_LE(test_and_set_bit,nr,p)
+#define test_and_clear_bit(nr,p)	ATOMIC_BITOP_LE(test_and_clear_bit,nr,p)
+#define test_and_change_bit(nr,p)	ATOMIC_BITOP_LE(test_and_change_bit,nr,p)
+#define test_bit(nr,p)			____test_bit(nr,p)
+#define find_first_zero_bit(p,sz)	_find_first_zero_bit_le(p,sz)
+#define find_next_zero_bit(p,sz,off)	_find_next_zero_bit_le(p,sz,off)
+
+/*
+ * These are the little endian, non-atomic definitions.
+ */
+#define __set_bit(nr,p)			NONATOMIC_BITOP_LE(set_bit,nr,p)
+#define __clear_bit(nr,p)		NONATOMIC_BITOP_LE(clear_bit,nr,p)
+#define __change_bit(nr,p)		NONATOMIC_BITOP_LE(change_bit,nr,p)
+#define __test_and_set_bit(nr,p)	NONATOMIC_BITOP_LE(test_and_set_bit,nr,p)
+#define __test_and_clear_bit(nr,p)	NONATOMIC_BITOP_LE(test_and_clear_bit,nr,p)
+#define __test_and_change_bit(nr,p)	NONATOMIC_BITOP_LE(test_and_change_bit,nr,p)
+#define __test_bit(nr,p)		____test_bit(nr,p)
+
+#else
+
+/*
+ * These are the little endian, atomic definitions.
+ */
+#define set_bit(nr,p)			ATOMIC_BITOP_BE(set_bit,nr,p)
+#define clear_bit(nr,p)			ATOMIC_BITOP_BE(clear_bit,nr,p)
+#define change_bit(nr,p)		ATOMIC_BITOP_BE(change_bit,nr,p)
+#define test_and_set_bit(nr,p)		ATOMIC_BITOP_BE(test_and_set_bit,nr,p)
+#define test_and_clear_bit(nr,p)	ATOMIC_BITOP_BE(test_and_clear_bit,nr,p)
+#define test_and_change_bit(nr,p)	ATOMIC_BITOP_BE(test_and_change_bit,nr,p)
+#define test_bit(nr,p)			____test_bit((nr) ^ 0x18, p)
+#define find_first_zero_bit(p,sz)	_find_first_zero_bit_be(p,sz)
+#define find_next_zero_bit(p,sz,off)	_find_next_zero_bit_be(p,sz,off)
+
+/*
+ * These are the little endian, non-atomic definitions.
+ */
+#define __set_bit(nr,p)			NONATOMIC_BITOP_BE(set_bit,nr,p)
+#define __clear_bit(nr,p)		NONATOMIC_BITOP_BE(clear_bit,nr,p)
+#define __change_bit(nr,p)		NONATOMIC_BITOP_BE(change_bit,nr,p)
+#define __test_and_set_bit(nr,p)	NONATOMIC_BITOP_BE(test_and_set_bit,nr,p)
+#define __test_and_clear_bit(nr,p)	NONATOMIC_BITOP_BE(test_and_clear_bit,nr,p)
+#define __test_and_change_bit(nr,p)	NONATOMIC_BITOP_BE(test_and_change_bit,nr,p)
+#define __test_bit(nr,p)		____test_bit((nr) ^ 0x18, p)
+
+#endif
+
+/*
  * ffz = Find First Zero in word. Undefined if no zero exists,
  * so code should check against ~0UL first..
  */
@@ -126,18 +318,25 @@
 #define hweight16(x) generic_hweight16(x)
 #define hweight8(x) generic_hweight8(x)
 
-#define ext2_set_bit			test_and_set_bit
-#define ext2_clear_bit			test_and_clear_bit
-#define ext2_test_bit			test_bit
-#define ext2_find_first_zero_bit	find_first_zero_bit
-#define ext2_find_next_zero_bit		find_next_zero_bit
-
-/* Bitmap functions for the minix filesystem. */
-#define minix_test_and_set_bit(nr,addr)	test_and_set_bit(nr,addr)
-#define minix_set_bit(nr,addr)		set_bit(nr,addr)
-#define minix_test_and_clear_bit(nr,addr)	test_and_clear_bit(nr,addr)
-#define minix_test_bit(nr,addr)		test_bit(nr,addr)
-#define minix_find_first_zero_bit(addr,size)	find_first_zero_bit(addr,size)
+/*
+ * Ext2 is defined to use little-endian byte ordering.
+ * These do not need to be atomic.
+ */
+#define ext2_set_bit(nr,p)			NONATOMIC_BITOP_LE(test_and_set_bit,nr,p)
+#define ext2_clear_bit(nr,p)			NONATOMIC_BITOP_LE(test_and_clear_bit,nr,p)
+#define ext2_test_bit(nr,p)			__test_bit(nr,p)
+#define ext2_find_first_zero_bit(p,sz)		_find_first_zero_bit_le(p,sz)
+#define ext2_find_next_zero_bit(p,sz,off)	_find_next_zero_bit_le(p,sz,off)
+
+/*
+ * Minix is defined to use little-endian byte ordering.
+ * These do not need to be atomic.
+ */
+#define minix_set_bit(nr,p)			NONATOMIC_BITOP_LE(set_bit,nr,p)
+#define minix_test_bit(nr,p)			__test_bit(nr,p)
+#define minix_test_and_set_bit(nr,p)		NONATOMIC_BITOP_LE(test_and_set_bit,nr,p)
+#define minix_test_and_clear_bit(nr,p)		NONATOMIC_BITOP_LE(test_and_clear_bit,nr,p)
+#define minix_find_first_zero_bit(p,sz)		_find_first_zero_bit_le(p,sz)
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.5.1/linux/include/asm-i386/cpufeature.h linux/include/asm-i386/cpufeature.h
--- v2.5.1/linux/include/asm-i386/cpufeature.h	Sun Nov 12 21:55:50 2000
+++ linux/include/asm-i386/cpufeature.h	Sun Dec 30 16:54:29 2001
@@ -40,6 +40,7 @@
 #define X86_FEATURE_XMM		(0*32+25) /* Streaming SIMD Extensions */
 #define X86_FEATURE_XMM2	(0*32+26) /* Streaming SIMD Extensions-2 */
 #define X86_FEATURE_SELFSNOOP	(0*32+27) /* CPU self snoop */
+#define X86_FEATURE_HT		(0*32+28) /* Hyper-Threading */
 #define X86_FEATURE_ACC		(0*32+29) /* Automatic clock control */
 #define X86_FEATURE_IA64	(0*32+30) /* IA-64 processor */
 
diff -u --recursive --new-file v2.5.1/linux/include/asm-i386/msr.h linux/include/asm-i386/msr.h
--- v2.5.1/linux/include/asm-i386/msr.h	Sat Sep  1 11:01:28 2001
+++ linux/include/asm-i386/msr.h	Sun Dec 30 16:59:04 2001
@@ -81,6 +81,7 @@
 
 #define MSR_K7_EVNTSEL0			0xC0010000
 #define MSR_K7_PERFCTR0			0xC0010004
+#define MSR_K7_HWCR			0xC0010015
 
 /* Centaur-Hauls/IDT defined MSRs. */
 #define MSR_IDT_FCR1			0x107
diff -u --recursive --new-file v2.5.1/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h
--- v2.5.1/linux/include/asm-i386/smp.h	Thu Nov 22 11:46:19 2001
+++ linux/include/asm-i386/smp.h	Tue Jan  1 19:13:38 2002
@@ -57,6 +57,9 @@
 extern unsigned long cpu_online_map;
 extern volatile unsigned long smp_invalidate_needed;
 extern int pic_mode;
+extern int smp_num_siblings;
+extern int cpu_sibling_map[];
+
 extern void smp_flush_tlb(void);
 extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
 extern void smp_send_reschedule(int cpu);
diff -u --recursive --new-file v2.5.1/linux/include/asm-sparc/keyboard.h linux/include/asm-sparc/keyboard.h
--- v2.5.1/linux/include/asm-sparc/keyboard.h	Tue Aug 28 07:09:44 2001
+++ linux/include/asm-sparc/keyboard.h	Tue Dec 25 15:39:20 2001
@@ -40,7 +40,6 @@
 #define kbd_init			pcikbd_init
 
 #define compute_shiftstate		pci_compute_shiftstate
-#define keyboard_wait_for_keypress	pci_wait_for_keypress
 #define getkeycode			pci_getkeycode
 #define setkeycode			pci_setkeycode
 #define getledstate			pci_getledstate
diff -u --recursive --new-file v2.5.1/linux/include/asm-sparc64/keyboard.h linux/include/asm-sparc64/keyboard.h
--- v2.5.1/linux/include/asm-sparc64/keyboard.h	Tue Aug 28 07:09:44 2001
+++ linux/include/asm-sparc64/keyboard.h	Tue Dec 25 15:39:20 2001
@@ -38,7 +38,6 @@
 #define kbd_init			pcikbd_init
 
 #define compute_shiftstate		pci_compute_shiftstate
-#define keyboard_wait_for_keypress	pci_wait_for_keypress
 #define getkeycode			pci_getkeycode
 #define setkeycode			pci_setkeycode
 #define getledstate			pci_getledstate
diff -u --recursive --new-file v2.5.1/linux/include/linux/acct.h linux/include/linux/acct.h
--- v2.5.1/linux/include/linux/acct.h	Thu Nov 22 11:46:18 2001
+++ linux/include/linux/acct.h	Tue Jan  1 19:13:37 2002
@@ -76,7 +76,7 @@
 #include <linux/config.h>
 
 #ifdef CONFIG_BSD_PROCESS_ACCT
-extern void acct_auto_close(kdev_t dev);
+extern void acct_auto_close(struct super_block *sb);
 extern int acct_process(long exitcode);
 #else
 #define acct_auto_close(x)	do { } while (0)
diff -u --recursive --new-file v2.5.1/linux/include/linux/amigaffs.h linux/include/linux/amigaffs.h
--- v2.5.1/linux/include/linux/amigaffs.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/amigaffs.h	Tue Dec 25 15:39:20 2001
@@ -23,8 +23,7 @@
 static inline void
 affs_set_blocksize(struct super_block *sb, int size)
 {
-	set_blocksize(sb->s_dev, size);
-	sb->s_blocksize = size;
+	sb_set_blocksize(sb, size);
 }
 static inline struct buffer_head *
 affs_bread(struct super_block *sb, int block)
diff -u --recursive --new-file v2.5.1/linux/include/linux/bio.h linux/include/linux/bio.h
--- v2.5.1/linux/include/linux/bio.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/bio.h	Tue Jan  1 19:14:01 2002
@@ -35,6 +35,7 @@
 #endif
 
 #define BIO_MAX_SECTORS	128
+#define BIO_MAX_SIZE	(BIO_MAX_SECTORS << 9)
 
 /*
  * was unsigned short, but we might as well be ready for > 64kB I/O pages
diff -u --recursive --new-file v2.5.1/linux/include/linux/blk.h linux/include/linux/blk.h
--- v2.5.1/linux/include/linux/blk.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/blk.h	Thu Jan  3 11:34:10 2002
@@ -2,6 +2,7 @@
 #define _BLK_H
 
 #include <linux/blkdev.h>
+#include <linux/elevator.h>
 #include <linux/locks.h>
 #include <linux/config.h>
 #include <linux/spinlock.h>
@@ -20,7 +21,6 @@
 #define INITRD_MINOR 250 /* shouldn't collide with /dev/ram* too soon ... */
 
 extern unsigned long initrd_start,initrd_end;
-extern int mount_initrd; /* zero if initrd should not be mounted */
 extern int initrd_below_start_ok; /* 1 if it is not an error if initrd_start < memory_start */
 extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
 extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
@@ -44,9 +44,10 @@
 static inline void blkdev_dequeue_request(struct request *req)
 {
 	list_del(&req->queuelist);
-}
 
-#define __elv_next_request(q)	(q)->elevator.elevator_next_req_fn((q))
+	if (req->q)
+		elv_remove_request(req->q, req);
+}
 
 extern inline struct request *elv_next_request(request_queue_t *q)
 {
@@ -55,6 +56,9 @@
 	while ((rq = __elv_next_request(q))) {
 		rq->flags |= REQ_STARTED;
 
+		if (&rq->queuelist == q->last_merge)
+			q->last_merge = NULL;
+
 		if ((rq->flags & REQ_DONTPREP) || !q->prep_rq_fn)
 			break;
 
@@ -77,21 +81,21 @@
 	return rq;
 }
 
-#define __elv_add_request_core(q, rq, where, plug)			\
+#define _elv_add_request_core(q, rq, where, plug)			\
 	do {								\
 		if ((plug))						\
 			blk_plug_device((q));				\
 		(q)->elevator.elevator_add_req_fn((q), (rq), (where));	\
 	} while (0)
 
-#define __elv_add_request(q, rq, back, p) do {				      \
+#define _elv_add_request(q, rq, back, p) do {				      \
 	if ((back))							      \
-		__elv_add_request_core((q), (rq), (q)->queue_head.prev, (p)); \
+		_elv_add_request_core((q), (rq), (q)->queue_head.prev, (p)); \
 	else								      \
-		__elv_add_request_core((q), (rq), &(q)->queue_head, 0);	      \
+		_elv_add_request_core((q), (rq), &(q)->queue_head, 0);	      \
 } while (0)
 
-#define elv_add_request(q, rq, back) __elv_add_request((q), (rq), (back), 1)
+#define elv_add_request(q, rq, back) _elv_add_request((q), (rq), (back), 1)
 	
 #if defined(MAJOR_NR) || defined(IDE_DRIVER)
 
@@ -104,14 +108,14 @@
 
 #ifdef IDE_DRIVER
 
-#define DEVICE_NR(device)	(MINOR(device) >> PARTN_BITS)
+#define DEVICE_NR(device)	(minor(device) >> PARTN_BITS)
 #define DEVICE_NAME "ide"
 
 #elif (MAJOR_NR == RAMDISK_MAJOR)
 
 /* ram disk */
 #define DEVICE_NAME "ramdisk"
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 #define DEVICE_NO_RANDOM
 
 #elif (MAJOR_NR == Z2RAM_MAJOR)
@@ -119,7 +123,7 @@
 /* Zorro II Ram */
 #define DEVICE_NAME "Z2RAM"
 #define DEVICE_REQUEST do_z2_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == FLOPPY_MAJOR)
 
@@ -128,7 +132,7 @@
 #define DEVICE_NAME "floppy"
 #define DEVICE_INTR do_floppy
 #define DEVICE_REQUEST do_fd_request
-#define DEVICE_NR(device) ( (MINOR(device) & 3) | ((MINOR(device) & 0x80 ) >> 5 ))
+#define DEVICE_NR(device) ( (minor(device) & 3) | ((minor(device) & 0x80 ) >> 5 ))
 #define DEVICE_OFF(device) floppy_off(DEVICE_NR(device))
 
 #elif (MAJOR_NR == HD_MAJOR)
@@ -138,188 +142,188 @@
 #define DEVICE_INTR do_hd
 #define TIMEOUT_VALUE (6*HZ)
 #define DEVICE_REQUEST do_hd_request
-#define DEVICE_NR(device) (MINOR(device)>>6)
+#define DEVICE_NR(device) (minor(device)>>6)
 
 #elif (SCSI_DISK_MAJOR(MAJOR_NR))
 
 #define DEVICE_NAME "scsidisk"
 #define TIMEOUT_VALUE (2*HZ)
-#define DEVICE_NR(device) (((MAJOR(device) & SD_MAJOR_MASK) << (8 - 4)) + (MINOR(device) >> 4))
+#define DEVICE_NR(device) (((major(device) & SD_MAJOR_MASK) << (8 - 4)) + (minor(device) >> 4))
 
 /* Kludge to use the same number for both char and block major numbers */
 #elif  (MAJOR_NR == MD_MAJOR) && defined(MD_DRIVER)
 
 #define DEVICE_NAME "Multiple devices driver"
 #define DEVICE_REQUEST do_md_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == SCSI_TAPE_MAJOR)
 
 #define DEVICE_NAME "scsitape"
 #define DEVICE_INTR do_st  
-#define DEVICE_NR(device) (MINOR(device) & 0x7f)
+#define DEVICE_NR(device) (minor(device) & 0x7f)
 
 #elif (MAJOR_NR == OSST_MAJOR)
 
 #define DEVICE_NAME "onstream" 
 #define DEVICE_INTR do_osst
-#define DEVICE_NR(device) (MINOR(device) & 0x7f) 
+#define DEVICE_NR(device) (minor(device) & 0x7f) 
 #define DEVICE_ON(device) 
 #define DEVICE_OFF(device) 
 
 #elif (MAJOR_NR == SCSI_CDROM_MAJOR)
 
 #define DEVICE_NAME "CD-ROM"
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == XT_DISK_MAJOR)
 
 #define DEVICE_NAME "xt disk"
 #define DEVICE_REQUEST do_xd_request
-#define DEVICE_NR(device) (MINOR(device) >> 6)
+#define DEVICE_NR(device) (minor(device) >> 6)
 
 #elif (MAJOR_NR == PS2ESDI_MAJOR)
 
 #define DEVICE_NAME "PS/2 ESDI"
 #define DEVICE_REQUEST do_ps2esdi_request
-#define DEVICE_NR(device) (MINOR(device) >> 6)
+#define DEVICE_NR(device) (minor(device) >> 6)
 
 #elif (MAJOR_NR == CDU31A_CDROM_MAJOR)
 
 #define DEVICE_NAME "CDU31A"
 #define DEVICE_REQUEST do_cdu31a_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == ACSI_MAJOR) && (defined(CONFIG_ATARI_ACSI) || defined(CONFIG_ATARI_ACSI_MODULE))
 
 #define DEVICE_NAME "ACSI"
 #define DEVICE_INTR do_acsi
 #define DEVICE_REQUEST do_acsi_request
-#define DEVICE_NR(device) (MINOR(device) >> 4)
+#define DEVICE_NR(device) (minor(device) >> 4)
 
 #elif (MAJOR_NR == MITSUMI_CDROM_MAJOR)
 
 #define DEVICE_NAME "Mitsumi CD-ROM"
 /* #define DEVICE_INTR do_mcd */
 #define DEVICE_REQUEST do_mcd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == MITSUMI_X_CDROM_MAJOR)
 
 #define DEVICE_NAME "Mitsumi CD-ROM"
 /* #define DEVICE_INTR do_mcdx */
 #define DEVICE_REQUEST do_mcdx_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == MATSUSHITA_CDROM_MAJOR)
 
 #define DEVICE_NAME "Matsushita CD-ROM controller #1"
 #define DEVICE_REQUEST do_sbpcd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == MATSUSHITA_CDROM2_MAJOR)
 
 #define DEVICE_NAME "Matsushita CD-ROM controller #2"
 #define DEVICE_REQUEST do_sbpcd2_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == MATSUSHITA_CDROM3_MAJOR)
 
 #define DEVICE_NAME "Matsushita CD-ROM controller #3"
 #define DEVICE_REQUEST do_sbpcd3_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == MATSUSHITA_CDROM4_MAJOR)
 
 #define DEVICE_NAME "Matsushita CD-ROM controller #4"
 #define DEVICE_REQUEST do_sbpcd4_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == AZTECH_CDROM_MAJOR)
 
 #define DEVICE_NAME "Aztech CD-ROM"
 #define DEVICE_REQUEST do_aztcd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == CDU535_CDROM_MAJOR)
 
 #define DEVICE_NAME "SONY-CDU535"
 #define DEVICE_INTR do_cdu535
 #define DEVICE_REQUEST do_cdu535_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == GOLDSTAR_CDROM_MAJOR)
 
 #define DEVICE_NAME "Goldstar R420"
 #define DEVICE_REQUEST do_gscd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == CM206_CDROM_MAJOR)
 #define DEVICE_NAME "Philips/LMS CD-ROM cm206"
 #define DEVICE_REQUEST do_cm206_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == OPTICS_CDROM_MAJOR)
 
 #define DEVICE_NAME "DOLPHIN 8000AT CD-ROM"
 #define DEVICE_REQUEST do_optcd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == SANYO_CDROM_MAJOR)
 
 #define DEVICE_NAME "Sanyo H94A CD-ROM"
 #define DEVICE_REQUEST do_sjcd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == APBLOCK_MAJOR)
 
 #define DEVICE_NAME "apblock"
 #define DEVICE_REQUEST ap_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == DDV_MAJOR)
 
 #define DEVICE_NAME "ddv"
 #define DEVICE_REQUEST ddv_request
-#define DEVICE_NR(device) (MINOR(device)>>PARTN_BITS)
+#define DEVICE_NR(device) (minor(device)>>PARTN_BITS)
 
 #elif (MAJOR_NR == MFM_ACORN_MAJOR)
 
 #define DEVICE_NAME "mfm disk"
 #define DEVICE_INTR do_mfm
 #define DEVICE_REQUEST do_mfm_request
-#define DEVICE_NR(device) (MINOR(device) >> 6)
+#define DEVICE_NR(device) (minor(device) >> 6)
 
 #elif (MAJOR_NR == NBD_MAJOR)
 
 #define DEVICE_NAME "nbd"
 #define DEVICE_REQUEST do_nbd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == MDISK_MAJOR)
 
 #define DEVICE_NAME "mdisk"
 #define DEVICE_REQUEST mdisk_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == DASD_MAJOR)
 
 #define DEVICE_NAME "dasd"
 #define DEVICE_REQUEST do_dasd_request
-#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS)
+#define DEVICE_NR(device) (minor(device) >> PARTN_BITS)
 
 #elif (MAJOR_NR == I2O_MAJOR)
 
 #define DEVICE_NAME "I2O block"
 #define DEVICE_REQUEST i2ob_request
-#define DEVICE_NR(device) (MINOR(device)>>4)
+#define DEVICE_NR(device) (minor(device)>>4)
 
 #elif (MAJOR_NR == COMPAQ_SMART2_MAJOR)
 
 #define DEVICE_NAME "ida"
 #define TIMEOUT_VALUE (25*HZ)
 #define DEVICE_REQUEST do_ida_request
-#define DEVICE_NR(device) (MINOR(device) >> 4)
+#define DEVICE_NR(device) (minor(device) >> 4)
 
 #endif /* MAJOR_NR == whatever */
 
@@ -373,7 +377,7 @@
 		CLEAR_INTR;					\
 		return;						\
 	}							\
-	if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) 		\
+	if (major(CURRENT->rq_dev) != MAJOR_NR) 			\
 		panic(DEVICE_NAME ": request list destroyed");	\
 	if (!CURRENT->bio)					\
 		panic(DEVICE_NAME ": no bio");			\
@@ -393,7 +397,7 @@
 		return;
 
 #ifndef DEVICE_NO_RANDOM
-	add_blkdev_randomness(MAJOR(req->rq_dev));
+	add_blkdev_randomness(major(req->rq_dev));
 #endif
 	DEVICE_OFF(req->rq_dev);
 	blkdev_dequeue_request(req);
diff -u --recursive --new-file v2.5.1/linux/include/linux/blkdev.h linux/include/linux/blkdev.h
--- v2.5.1/linux/include/linux/blkdev.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/blkdev.h	Thu Jan  3 11:34:10 2002
@@ -6,7 +6,7 @@
 #include <linux/genhd.h>
 #include <linux/tqueue.h>
 #include <linux/list.h>
-#include <linux/mm.h>
+#include <linux/pagemap.h>
 
 #include <asm/scatterlist.h>
 
@@ -25,7 +25,7 @@
 	struct list_head queuelist; /* looking for ->queue? you must _not_
 				     * access it directly, use
 				     * blkdev_dequeue_request! */
-	int elevator_sequence;
+	void *elevator_private;
 
 	unsigned char cmd[16];
 
@@ -130,16 +130,17 @@
 struct request_queue
 {
 	/*
-	 * the queue request freelist, one for reads and one for writes
-	 */
-	struct request_list	rq[2];
-
-	/*
 	 * Together with queue_head for cacheline sharing
 	 */
 	struct list_head	queue_head;
+	struct list_head	*last_merge;
 	elevator_t		elevator;
 
+	/*
+	 * the queue request freelist, one for reads and one for writes
+	 */
+	struct request_list	rq[2];
+
 	request_fn_proc		*request_fn;
 	merge_request_fn	*back_merge_fn;
 	merge_request_fn	*front_merge_fn;
@@ -195,8 +196,7 @@
 #define RQ_SCSI_DISCONNECTING	0xffe0
 
 #define QUEUE_FLAG_PLUGGED	0	/* queue is plugged */
-#define QUEUE_FLAG_NOSPLIT	1	/* can process bio over several goes */
-#define QUEUE_FLAG_CLUSTER	2	/* cluster several segments into 1 */
+#define QUEUE_FLAG_CLUSTER	1	/* cluster several segments into 1 */
 
 #define blk_queue_plugged(q)	test_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags)
 #define blk_mark_plugged(q)	set_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags)
@@ -206,6 +206,14 @@
 #define rq_data_dir(rq)		((rq)->flags & 1)
 
 /*
+ * mergeable request must not have _NOMERGE or _BARRIER bit set, nor may
+ * it already be started by driver.
+ */
+#define rq_mergeable(rq)	\
+	(!((rq)->flags & (REQ_NOMERGE | REQ_STARTED | REQ_BARRIER))	\
+	&& ((rq)->flags & REQ_CMD))
+
+/*
  * noop, requests are automagically marked as active/inactive by I/O
  * scheduler -- see elv_next_request
  */
@@ -213,27 +221,25 @@
 
 extern unsigned long blk_max_low_pfn, blk_max_pfn;
 
-#define BLK_BOUNCE_HIGH	(blk_max_low_pfn << PAGE_SHIFT)
-#define BLK_BOUNCE_ANY	(blk_max_pfn << PAGE_SHIFT)
-#define BLK_BOUNCE_ISA	(ISA_DMA_THRESHOLD)
-
-#ifdef CONFIG_HIGHMEM
+/*
+ * standard bounce addresses:
+ *
+ * BLK_BOUNCE_HIGH	: bounce all highmem pages
+ * BLK_BOUNCE_ANY	: don't bounce anything
+ * BLK_BOUNCE_ISA	: bounce pages above ISA DMA boundary
+ */
+#define BLK_BOUNCE_HIGH		(blk_max_low_pfn << PAGE_SHIFT)
+#define BLK_BOUNCE_ANY		(blk_max_pfn << PAGE_SHIFT)
+#define BLK_BOUNCE_ISA		(ISA_DMA_THRESHOLD)
 
+extern int init_emergency_isa_pool(void);
 extern void create_bounce(unsigned long pfn, int gfp, struct bio **bio_orig);
-extern void init_emergency_isa_pool(void);
 
 extern inline void blk_queue_bounce(request_queue_t *q, struct bio **bio)
 {
 	create_bounce(q->bounce_pfn, q->bounce_gfp, bio);
 }
 
-#else /* CONFIG_HIGHMEM */
-
-#define blk_queue_bounce(q, bio)	do { } while (0)
-#define init_emergency_isa_pool()	do { } while (0)
-
-#endif /* CONFIG_HIGHMEM */
-
 #define rq_for_each_bio(bio, rq)	\
 	if ((rq->bio))			\
 		for (bio = (rq)->bio; bio; bio = bio->bi_next)
@@ -275,9 +281,13 @@
 extern void blk_recount_segments(request_queue_t *, struct bio *);
 extern inline int blk_phys_contig_segment(request_queue_t *q, struct bio *, struct bio *);
 extern inline int blk_hw_contig_segment(request_queue_t *q, struct bio *, struct bio *);
-extern void blk_queue_assign_lock(request_queue_t *q, spinlock_t *);
-
 extern int block_ioctl(kdev_t, unsigned int, unsigned long);
+extern int ll_10byte_cmd_build(request_queue_t *, struct request *);
+
+/*
+ * get ready for proper ref counting
+ */
+#define blk_put_queue(q)	do { } while (0)
 
 /*
  * Access functions for manipulating queue properties
@@ -292,6 +302,9 @@
 extern void blk_queue_max_segment_size(request_queue_t *q, unsigned int);
 extern void blk_queue_hardsect_size(request_queue_t *q, unsigned short);
 extern void blk_queue_segment_boundary(request_queue_t *q, unsigned long);
+extern void blk_queue_assign_lock(request_queue_t *q, spinlock_t *);
+extern void blk_queue_prep_rq(request_queue_t *q, prep_rq_fn *pfn);
+
 extern int blk_rq_map_sg(request_queue_t *, struct request *, struct scatterlist *);
 extern void blk_dump_rq_flags(struct request *, char *);
 extern void generic_unplug_device(void *);
@@ -358,14 +371,23 @@
 extern inline unsigned int block_size(kdev_t dev)
 {
 	int retval = BLOCK_SIZE;
-	int major = MAJOR(dev);
+	int major = major(dev);
 
 	if (blksize_size[major]) {
-		int minor = MINOR(dev);
+		int minor = minor(dev);
 		if (blksize_size[major][minor])
 			retval = blksize_size[major][minor];
 	}
 	return retval;
+}
+
+typedef struct {struct page *v;} Sector;
+
+unsigned char *read_dev_sector(struct block_device *, unsigned long, Sector *);
+
+static inline void put_dev_sector(Sector p)
+{
+	page_cache_release(p.v);
 }
 
 #endif
diff -u --recursive --new-file v2.5.1/linux/include/linux/blkdev.h.orig linux/include/linux/blkdev.h.orig
--- v2.5.1/linux/include/linux/blkdev.h.orig	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/blkdev.h.orig	Wed Dec 31 16:00:00 1969
@@ -1,371 +0,0 @@
-#ifndef _LINUX_BLKDEV_H
-#define _LINUX_BLKDEV_H
-
-#include <linux/major.h>
-#include <linux/sched.h>
-#include <linux/genhd.h>
-#include <linux/tqueue.h>
-#include <linux/list.h>
-#include <linux/mm.h>
-
-#include <asm/scatterlist.h>
-
-struct request_queue;
-typedef struct request_queue request_queue_t;
-struct elevator_s;
-typedef struct elevator_s elevator_t;
-
-struct request_list {
-	unsigned int count;
-	struct list_head free;
-	wait_queue_head_t wait;
-};
-
-struct request {
-	struct list_head queuelist; /* looking for ->queue? you must _not_
-				     * access it directly, use
-				     * blkdev_dequeue_request! */
-	int elevator_sequence;
-
-	unsigned char cmd[16];
-
-	unsigned long flags;		/* see REQ_ bits below */
-
-	int rq_status;	/* should split this into a few status bits */
-	kdev_t rq_dev;
-	int errors;
-	sector_t sector;
-	unsigned long nr_sectors;
-	unsigned long hard_sector;	/* the hard_* are block layer
-					 * internals, no driver should
-					 * touch them
-					 */
-	unsigned long hard_nr_sectors;
-
-	/* Number of scatter-gather DMA addr+len pairs after
-	 * physical address coalescing is performed.
-	 */
-	unsigned short nr_phys_segments;
-
-	/* Number of scatter-gather addr+len pairs after
-	 * physical and DMA remapping hardware coalescing is performed.
-	 * This is the number of scatter-gather entries the driver
-	 * will actually have to deal with after DMA mapping is done.
-	 */
-	unsigned short nr_hw_segments;
-
-	unsigned int current_nr_sectors;
-	unsigned int hard_cur_sectors;
-	void *special;
-	char *buffer;
-	struct completion *waiting;
-	struct bio *bio, *biotail;
-	request_queue_t *q;
-	struct request_list *rl;
-};
-
-/*
- * first three bits match BIO_RW* bits, important
- */
-enum rq_flag_bits {
-	__REQ_RW,	/* not set, read. set, write */
-	__REQ_RW_AHEAD,	/* READA */
-	__REQ_BARRIER,	/* may not be passed */
-	__REQ_CMD,	/* is a regular fs rw request */
-	__REQ_NOMERGE,	/* don't touch this for merging */
-	__REQ_STARTED,	/* drive already may have started this one */
-	__REQ_DONTPREP,	/* don't call prep for this one */
-	/*
-	 * for IDE
- 	*/
-	__REQ_DRIVE_CMD,
-	__REQ_DRIVE_TASK,
-
-	__REQ_PC,	/* packet command (special) */
-	__REQ_BLOCK_PC,	/* queued down pc from block layer */
-	__REQ_SENSE,	/* sense retrival */
-
-	__REQ_SPECIAL,	/* driver special command */
-
-	__REQ_NR_BITS,	/* stops here */
-};
-
-#define REQ_RW		(1 << __REQ_RW)
-#define REQ_RW_AHEAD	(1 << __REQ_RW_AHEAD)
-#define REQ_BARRIER	(1 << __REQ_BARRIER)
-#define REQ_CMD		(1 << __REQ_CMD)
-#define REQ_NOMERGE	(1 << __REQ_NOMERGE)
-#define REQ_STARTED	(1 << __REQ_STARTED)
-#define REQ_DONTPREP	(1 << __REQ_DONTPREP)
-#define REQ_DRIVE_CMD	(1 << __REQ_DRIVE_CMD)
-#define REQ_DRIVE_TASK	(1 << __REQ_DRIVE_TASK)
-#define REQ_PC		(1 << __REQ_PC)
-#define REQ_SENSE	(1 << __REQ_SENSE)
-#define REQ_BLOCK_PC	(1 << __REQ_BLOCK_PC)
-#define REQ_SPECIAL	(1 << __REQ_SPECIAL)
-
-#include <linux/elevator.h>
-
-typedef int (merge_request_fn) (request_queue_t *, struct request *,
-				struct bio *);
-typedef int (merge_requests_fn) (request_queue_t *, struct request *,
-				 struct request *);
-typedef void (request_fn_proc) (request_queue_t *q);
-typedef request_queue_t * (queue_proc) (kdev_t dev);
-typedef int (make_request_fn) (request_queue_t *q, struct bio *bio);
-typedef int (prep_rq_fn) (request_queue_t *, struct request *);
-typedef void (unplug_device_fn) (void *q);
-
-enum blk_queue_state {
-	Queue_down,
-	Queue_up,
-};
-
-/*
- * Default nr free requests per queue, ll_rw_blk will scale it down
- * according to available RAM at init time
- */
-#define QUEUE_NR_REQUESTS	8192
-
-struct request_queue
-{
-	/*
-	 * the queue request freelist, one for reads and one for writes
-	 */
-	struct request_list	rq[2];
-
-	/*
-	 * Together with queue_head for cacheline sharing
-	 */
-	struct list_head	queue_head;
-	elevator_t		elevator;
-
-	request_fn_proc		*request_fn;
-	merge_request_fn	*back_merge_fn;
-	merge_request_fn	*front_merge_fn;
-	merge_requests_fn	*merge_requests_fn;
-	make_request_fn		*make_request_fn;
-	prep_rq_fn		*prep_rq_fn;
-
-	/*
-	 * The queue owner gets to use this for whatever they like.
-	 * ll_rw_blk doesn't touch it.
-	 */
-	void			*queuedata;
-
-	/*
-	 * queue needs bounce pages for pages above this limit
-	 */
-	unsigned long		bounce_pfn;
-	int			bounce_gfp;
-
-	/*
-	 * This is used to remove the plug when tq_disk runs.
-	 */
-	struct tq_struct	plug_tq;
-
-	/*
-	 * various queue flags, see QUEUE_* below
-	 */
-	unsigned long		queue_flags;
-
-	/*
-	 * protects queue structures from reentrancy
-	 */
-	spinlock_t		*queue_lock;
-
-	/*
-	 * queue settings
-	 */
-	unsigned short		max_sectors;
-	unsigned short		max_phys_segments;
-	unsigned short		max_hw_segments;
-	unsigned short		hardsect_size;
-	unsigned int		max_segment_size;
-
-	unsigned long		seg_boundary_mask;
-
-	wait_queue_head_t	queue_wait;
-};
-
-#define RQ_INACTIVE		(-1)
-#define RQ_ACTIVE		1
-#define RQ_SCSI_BUSY		0xffff
-#define RQ_SCSI_DONE		0xfffe
-#define RQ_SCSI_DISCONNECTING	0xffe0
-
-#define QUEUE_FLAG_PLUGGED	0	/* queue is plugged */
-#define QUEUE_FLAG_NOSPLIT	1	/* can process bio over several goes */
-#define QUEUE_FLAG_CLUSTER	2	/* cluster several segments into 1 */
-
-#define blk_queue_plugged(q)	test_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags)
-#define blk_mark_plugged(q)	set_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags)
-#define blk_queue_empty(q)	elv_queue_empty(q)
-#define list_entry_rq(ptr)	list_entry((ptr), struct request, queuelist)
-
-#define rq_data_dir(rq)		((rq)->flags & 1)
-
-/*
- * noop, requests are automagically marked as active/inactive by I/O
- * scheduler -- see elv_next_request
- */
-#define blk_queue_headactive(q, head_active)
-
-extern unsigned long blk_max_low_pfn, blk_max_pfn;
-
-#define BLK_BOUNCE_HIGH	(blk_max_low_pfn << PAGE_SHIFT)
-#define BLK_BOUNCE_ANY	(blk_max_pfn << PAGE_SHIFT)
-#define BLK_BOUNCE_ISA	(ISA_DMA_THRESHOLD)
-
-#ifdef CONFIG_HIGHMEM
-
-extern void create_bounce(unsigned long pfn, int gfp, struct bio **bio_orig);
-extern void init_emergency_isa_pool(void);
-
-extern inline void blk_queue_bounce(request_queue_t *q, struct bio **bio)
-{
-	create_bounce(q->bounce_pfn, q->bounce_gfp, bio);
-}
-
-#else /* CONFIG_HIGHMEM */
-
-#define blk_queue_bounce(q, bio)	do { } while (0)
-#define init_emergency_isa_pool()	do { } while (0)
-
-#endif /* CONFIG_HIGHMEM */
-
-#define rq_for_each_bio(bio, rq)	\
-	if ((rq->bio))			\
-		for (bio = (rq)->bio; bio; bio = bio->bi_next)
-
-struct blk_dev_struct {
-	/*
-	 * queue_proc has to be atomic
-	 */
-	request_queue_t		request_queue;
-	queue_proc		*queue;
-	void			*data;
-};
-
-struct sec_size {
-	unsigned block_size;
-	unsigned block_size_bits;
-};
-
-/*
- * Used to indicate the default queue for drivers that don't bother
- * to implement multiple queues.  We have this access macro here
- * so as to eliminate the need for each and every block device
- * driver to know about the internal structure of blk_dev[].
- */
-#define BLK_DEFAULT_QUEUE(_MAJOR)  &blk_dev[_MAJOR].request_queue
-
-extern struct sec_size * blk_sec[MAX_BLKDEV];
-extern struct blk_dev_struct blk_dev[MAX_BLKDEV];
-extern void grok_partitions(kdev_t dev, long size);
-extern int wipe_partitions(kdev_t dev);
-extern void register_disk(struct gendisk *dev, kdev_t first, unsigned minors, struct block_device_operations *ops, long size);
-extern void generic_make_request(struct bio *bio);
-extern inline request_queue_t *blk_get_queue(kdev_t dev);
-extern void blkdev_release_request(struct request *);
-extern void blk_attempt_remerge(request_queue_t *, struct request *);
-extern struct request *blk_get_request(request_queue_t *, int, int);
-extern void blk_put_request(struct request *);
-extern void blk_plug_device(request_queue_t *);
-extern void blk_recount_segments(request_queue_t *, struct bio *);
-extern inline int blk_phys_contig_segment(request_queue_t *q, struct bio *, struct bio *);
-extern inline int blk_hw_contig_segment(request_queue_t *q, struct bio *, struct bio *);
-extern void blk_queue_assign_lock(request_queue_t *q, spinlock_t *);
-
-extern int block_ioctl(kdev_t, unsigned int, unsigned long);
-
-/*
- * Access functions for manipulating queue properties
- */
-extern int blk_init_queue(request_queue_t *, request_fn_proc *, spinlock_t *);
-extern void blk_cleanup_queue(request_queue_t *);
-extern void blk_queue_make_request(request_queue_t *, make_request_fn *);
-extern void blk_queue_bounce_limit(request_queue_t *, u64);
-extern void blk_queue_max_sectors(request_queue_t *q, unsigned short);
-extern void blk_queue_max_phys_segments(request_queue_t *q, unsigned short);
-extern void blk_queue_max_hw_segments(request_queue_t *q, unsigned short);
-extern void blk_queue_max_segment_size(request_queue_t *q, unsigned int);
-extern void blk_queue_hardsect_size(request_queue_t *q, unsigned short);
-extern void blk_queue_segment_boundary(request_queue_t *q, unsigned long);
-extern int blk_rq_map_sg(request_queue_t *, struct request *, struct scatterlist *);
-extern void blk_dump_rq_flags(struct request *, char *);
-extern void generic_unplug_device(void *);
-
-extern int * blk_size[MAX_BLKDEV];
-
-extern int * blksize_size[MAX_BLKDEV];
-
-extern int * max_readahead[MAX_BLKDEV];
-
-#define MAX_PHYS_SEGMENTS 128
-#define MAX_HW_SEGMENTS 128
-#define MAX_SECTORS 255
-
-#define MAX_SEGMENT_SIZE	65536
-
-/* read-ahead in pages.. */
-#define MAX_READAHEAD	31
-#define MIN_READAHEAD	3
-
-#define blkdev_entry_to_request(entry) list_entry((entry), struct request, queuelist)
-#define blkdev_entry_next_request(entry) blkdev_entry_to_request((entry)->next)
-#define blkdev_entry_prev_request(entry) blkdev_entry_to_request((entry)->prev)
-#define blkdev_next_request(req) blkdev_entry_to_request((req)->queuelist.next)
-#define blkdev_prev_request(req) blkdev_entry_to_request((req)->queuelist.prev)
-
-extern void drive_stat_acct(struct request *, int, int);
-
-extern inline void blk_clear(int major)
-{
-	blk_size[major] = NULL;
-#if 0
-	blk_size_in_bytes[major] = NULL;
-#endif
-	blksize_size[major] = NULL;
-	max_readahead[major] = NULL;
-	read_ahead[major] = 0;
-}
-
-extern inline int get_hardsect_size(kdev_t dev)
-{
-	request_queue_t *q = blk_get_queue(dev);
-	int retval = 512;
-
-	if (q && q->hardsect_size)
-		retval = q->hardsect_size;
-
-	return retval;
-}
-
-#define blk_finished_io(nsects)	do { } while (0)
-#define blk_started_io(nsects)	do { } while (0)
-
-extern inline unsigned int blksize_bits(unsigned int size)
-{
-	unsigned int bits = 8;
-	do {
-		bits++;
-		size >>= 1;
-	} while (size > 256);
-	return bits;
-}
-
-extern inline unsigned int block_size(kdev_t dev)
-{
-	int retval = BLOCK_SIZE;
-	int major = MAJOR(dev);
-
-	if (blksize_size[major]) {
-		int minor = MINOR(dev);
-		if (blksize_size[major][minor])
-			retval = blksize_size[major][minor];
-	}
-	return retval;
-}
-
-#endif
diff -u --recursive --new-file v2.5.1/linux/include/linux/cdrom.h linux/include/linux/cdrom.h
--- v2.5.1/linux/include/linux/cdrom.h	Thu Nov 22 11:47:04 2001
+++ linux/include/linux/cdrom.h	Tue Jan  1 19:13:38 2002
@@ -792,7 +792,7 @@
 
 	sprintf (vname, "cdroms/cdrom%d", cdi->number);
 	cdi->de = devfs_register (NULL, vname, DEVFS_FL_DEFAULT,
-				    MAJOR (cdi->dev), MINOR (cdi->dev),
+				    major(cdi->dev), minor(cdi->dev),
 				    S_IFBLK | S_IRUGO | S_IWUGO,
 				    ops, NULL);
 }
diff -u --recursive --new-file v2.5.1/linux/include/linux/console.h linux/include/linux/console.h
--- v2.5.1/linux/include/linux/console.h	Thu Nov 22 11:46:19 2001
+++ linux/include/linux/console.h	Tue Jan  1 19:13:37 2002
@@ -97,7 +97,6 @@
 	void	(*write)(struct console *, const char *, unsigned);
 	int	(*read)(struct console *, const char *, unsigned);
 	kdev_t	(*device)(struct console *);
-	int	(*wait_key)(struct console *);
 	void	(*unblank)(void);
 	int	(*setup)(struct console *, char *);
 	short	flags;
diff -u --recursive --new-file v2.5.1/linux/include/linux/devfs_fs.h linux/include/linux/devfs_fs.h
--- v2.5.1/linux/include/linux/devfs_fs.h	Fri Sep 21 10:55:23 2001
+++ linux/include/linux/devfs_fs.h	Thu Dec 27 08:29:15 2001
@@ -26,7 +26,7 @@
 					      binary interface will change   */
 
 struct devfsd_notify_struct
-{
+{   /*  Use native C types to ensure same types in kernel and user space     */
     unsigned int type;           /*  DEVFSD_NOTIFY_* value                   */
     unsigned int mode;           /*  Mode of the inode or device entry       */
     unsigned int major;          /*  Major number of device entry            */
diff -u --recursive --new-file v2.5.1/linux/include/linux/devfs_fs_kernel.h linux/include/linux/devfs_fs_kernel.h
--- v2.5.1/linux/include/linux/devfs_fs_kernel.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/devfs_fs_kernel.h	Tue Jan  1 19:13:38 2002
@@ -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
 
 
@@ -61,6 +60,7 @@
 
 #define UNIQUE_NUMBERSPACE_INITIALISER {SPIN_LOCK_UNLOCKED, 0, 0, 0, NULL}
 
+extern void devfs_put (devfs_handle_t de);
 extern devfs_handle_t devfs_register (devfs_handle_t dir, const char *name,
 				      unsigned int flags,
 				      unsigned int major, unsigned int minor,
@@ -71,6 +71,9 @@
 			     devfs_handle_t *handle, void *info);
 extern devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name,
 				    void *info);
+extern devfs_handle_t devfs_get_handle (devfs_handle_t dir, const char *name,
+					unsigned int major,unsigned int minor,
+					char type, int traverse_symlinks);
 extern devfs_handle_t devfs_find_handle (devfs_handle_t dir, const char *name,
 					 unsigned int major,unsigned int minor,
 					 char type, int traverse_symlinks);
@@ -81,6 +84,7 @@
 extern devfs_handle_t devfs_get_handle_from_inode (struct inode *inode);
 extern int devfs_generate_path (devfs_handle_t de, char *path, int buflen);
 extern void *devfs_get_ops (devfs_handle_t de);
+extern void devfs_put_ops (devfs_handle_t de);
 extern int devfs_set_file_size (devfs_handle_t de, unsigned long size);
 extern void *devfs_get_info (devfs_handle_t de);
 extern int devfs_set_info (devfs_handle_t de, void *info);
@@ -112,7 +116,6 @@
 					 int number);
 
 extern void mount_devfs_fs (void);
-extern void devfs_make_root (const char *name);
 
 #else  /*  CONFIG_DEVFS_FS  */
 
@@ -123,6 +126,10 @@
 
 #define UNIQUE_NUMBERSPACE_INITIALISER {0}
 
+static inline void devfs_put (devfs_handle_t de)
+{
+    return;
+}
 static inline devfs_handle_t devfs_register (devfs_handle_t dir,
 					     const char *name,
 					     unsigned int flags,
@@ -148,6 +155,15 @@
 {
     return NULL;
 }
+static inline devfs_handle_t devfs_get_handle (devfs_handle_t dir,
+					       const char *name,
+					       unsigned int major,
+					       unsigned int minor,
+					       char type,
+					       int traverse_symlinks)
+{
+    return NULL;
+}
 static inline devfs_handle_t devfs_find_handle (devfs_handle_t dir,
 						const char *name,
 						unsigned int major,
@@ -183,6 +199,10 @@
 {
     return NULL;
 }
+static inline void devfs_put_ops (devfs_handle_t de)
+{
+    return;
+}
 static inline int devfs_set_file_size (devfs_handle_t de, unsigned long size)
 {
     return -ENOSYS;
@@ -288,10 +308,6 @@
 }
 
 static inline void mount_devfs_fs (void)
-{
-    return;
-}
-static inline void devfs_make_root (const char *name)
 {
     return;
 }
diff -u --recursive --new-file v2.5.1/linux/include/linux/elevator.h linux/include/linux/elevator.h
--- v2.5.1/linux/include/linux/elevator.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/elevator.h	Thu Jan  3 11:34:10 2002
@@ -1,12 +1,8 @@
 #ifndef _LINUX_ELEVATOR_H
 #define _LINUX_ELEVATOR_H
 
-typedef void (elevator_fn) (struct request *, elevator_t *,
-			    struct list_head *,
-			    struct list_head *, int);
-
 typedef int (elevator_merge_fn) (request_queue_t *, struct request **,
-				 struct list_head *, struct bio *);
+				 struct bio *);
 
 typedef void (elevator_merge_cleanup_fn) (request_queue_t *, struct request *, int);
 
@@ -15,37 +11,53 @@
 typedef struct request *(elevator_next_req_fn) (request_queue_t *);
 
 typedef void (elevator_add_req_fn) (request_queue_t *, struct request *, struct list_head *);
+typedef int (elevator_queue_empty_fn) (request_queue_t *);
+typedef void (elevator_remove_req_fn) (request_queue_t *, struct request *);
 
 typedef int (elevator_init_fn) (request_queue_t *, elevator_t *);
 typedef void (elevator_exit_fn) (request_queue_t *, elevator_t *);
 
 struct elevator_s
 {
-	int read_latency;
-	int write_latency;
-
 	elevator_merge_fn *elevator_merge_fn;
 	elevator_merge_cleanup_fn *elevator_merge_cleanup_fn;
 	elevator_merge_req_fn *elevator_merge_req_fn;
 
 	elevator_next_req_fn *elevator_next_req_fn;
 	elevator_add_req_fn *elevator_add_req_fn;
+	elevator_remove_req_fn *elevator_remove_req_fn;
+
+	elevator_queue_empty_fn *elevator_queue_empty_fn;
 
 	elevator_init_fn *elevator_init_fn;
 	elevator_exit_fn *elevator_exit_fn;
+
+	void *elevator_data;
 };
 
-int elevator_noop_merge(request_queue_t *, struct request **, struct list_head *, struct bio *);
-void elevator_noop_merge_cleanup(request_queue_t *, struct request *, int);
-void elevator_noop_merge_req(struct request *, struct request *);
-
-int elevator_linus_merge(request_queue_t *, struct request **, struct list_head *, struct bio *);
-void elevator_linus_merge_cleanup(request_queue_t *, struct request *, int);
-void elevator_linus_merge_req(struct request *, struct request *);
-int elv_linus_init(request_queue_t *, elevator_t *);
-void elv_linus_exit(request_queue_t *, elevator_t *);
-struct request *elv_next_request_fn(request_queue_t *);
-void elv_add_request_fn(request_queue_t *, struct request *,struct list_head *);
+/*
+ * block elevator interface
+ */
+extern void __elv_add_request(request_queue_t *, struct request *,
+			      struct list_head *);
+extern struct request *__elv_next_request(request_queue_t *);
+extern void elv_merge_cleanup(request_queue_t *, struct request *, int);
+extern int elv_merge(request_queue_t *, struct request **, struct bio *);
+extern void elv_merge_requests(request_queue_t *, struct request *,
+			       struct request *);
+extern void elv_remove_request(request_queue_t *, struct request *);
+
+/*
+ * noop I/O scheduler. always merges, always inserts new request at tail
+ */
+extern elevator_t elevator_noop;
+
+/*
+ * elevator linus. based on linus ideas of starvation control, using
+ * sequencing to manage inserts and merges.
+ */
+extern elevator_t elevator_linus;
+#define elv_linus_sequence(rq)	((long)(rq)->elevator_private)
 
 /*
  * use the /proc/iosched interface, all the below is history ->
@@ -70,76 +82,9 @@
 #define ELEVATOR_BACK_MERGE	2
 
 /*
- * This is used in the elevator algorithm.  We don't prioritise reads
- * over writes any more --- although reads are more time-critical than
- * writes, by treating them equally we increase filesystem throughput.
- * This turns out to give better overall performance.  -- sct
- */
-#define IN_ORDER(s1,s2)				\
-	((((s1)->rq_dev == (s2)->rq_dev &&	\
-	   (s1)->sector < (s2)->sector)) ||	\
-	 (s1)->rq_dev < (s2)->rq_dev)
-
-#define BHRQ_IN_ORDER(bh, rq)			\
-	((((bh)->b_rdev == (rq)->rq_dev &&	\
-	   (bh)->b_rsector < (rq)->sector)) ||	\
-	 (bh)->b_rdev < (rq)->rq_dev)
-
-static inline int elevator_request_latency(elevator_t * elevator, int rw)
-{
-	int latency;
-
-	latency = elevator->read_latency;
-	if (rw != READ)
-		latency = elevator->write_latency;
-
-	return latency;
-}
-
-/*
  * will change once we move to a more complex data structure than a simple
  * list for pending requests
  */
 #define elv_queue_empty(q)	list_empty(&(q)->queue_head)
-
-/*
- * elevator private data
- */
-struct elv_linus_data {
-	unsigned long flags;
-};
-
-#define ELV_DAT(e) ((struct elv_linus_data *)(e)->elevator_data)
-
-#define ELV_LINUS_BACK_MERGE	1
-#define ELV_LINUS_FRONT_MERGE	2
-
-#define ELEVATOR_NOOP							\
-((elevator_t) {								\
-	0,				/* read_latency */		\
-	0,				/* write_latency */		\
-									\
-	elevator_noop_merge,		/* elevator_merge_fn */		\
-	elevator_noop_merge_cleanup,	/* elevator_merge_cleanup_fn */	\
-	elevator_noop_merge_req,	/* elevator_merge_req_fn */	\
-	elv_next_request_fn,						\
-	elv_add_request_fn,						\
-	elv_linus_init,							\
-	elv_linus_exit,							\
-	})
-
-#define ELEVATOR_LINUS							\
-((elevator_t) {								\
-	8192,				/* read passovers */		\
-	16384,				/* write passovers */		\
-									\
-	elevator_linus_merge,		/* elevator_merge_fn */		\
-	elevator_linus_merge_cleanup,	/* elevator_merge_cleanup_fn */	\
-	elevator_linus_merge_req,	/* elevator_merge_req_fn */	\
-	elv_next_request_fn,						\
-	elv_add_request_fn,						\
-	elv_linus_init,							\
-	elv_linus_exit,							\
-	})
 
 #endif
diff -u --recursive --new-file v2.5.1/linux/include/linux/ext2_fs_sb.h linux/include/linux/ext2_fs_sb.h
--- v2.5.1/linux/include/linux/ext2_fs_sb.h	Fri Dec 29 14:36:44 2000
+++ linux/include/linux/ext2_fs_sb.h	Sun Dec 30 10:53:53 2001
@@ -56,6 +56,7 @@
 	int s_desc_per_block_bits;
 	int s_inode_size;
 	int s_first_ino;
+	u32 s_next_generation;
 };
 
 #endif	/* _LINUX_EXT2_FS_SB */
diff -u --recursive --new-file v2.5.1/linux/include/linux/ext3_fs.h linux/include/linux/ext3_fs.h
--- v2.5.1/linux/include/linux/ext3_fs.h	Fri Nov  9 14:25:04 2001
+++ linux/include/linux/ext3_fs.h	Sun Dec 30 16:58:52 2001
@@ -36,8 +36,8 @@
 /*
  * The second extended file system version
  */
-#define EXT3FS_DATE		"06 Nov 2001"
-#define EXT3FS_VERSION		"2.4-0.9.15"
+#define EXT3FS_DATE		"02 Dec 2001"
+#define EXT3FS_VERSION		"2.4-0.9.16"
 
 /*
  * Debug code
@@ -577,10 +577,6 @@
 					 ~EXT3_DIR_ROUND)
 
 #ifdef __KERNEL__
-
-/* Filesize hard limits for 64-bit file offsets */
-extern long long ext3_max_sizes[];
-
 /*
  * Describe an inode's exact location on disk and in memory
  */
@@ -603,9 +599,6 @@
 # define ATTRIB_NORET  __attribute__((noreturn))
 # define NORET_AND     noreturn,
 
-/* acl.c */
-extern int ext3_permission (struct inode *, int);
-
 /* balloc.c */
 extern int ext3_bg_has_super(struct super_block *sb, int group);
 extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group);
@@ -619,16 +612,10 @@
 						    unsigned int block_group,
 						    struct buffer_head ** bh);
 
-/* bitmap.c */
-extern unsigned long ext3_count_free (struct buffer_head *, unsigned);
-
 /* dir.c */
 extern int ext3_check_dir_entry(const char *, struct inode *,
 				struct ext3_dir_entry_2 *, struct buffer_head *,
 				unsigned long);
-
-/* file.c */
-
 /* fsync.c */
 extern int ext3_sync_file (struct file *, struct dentry *, int);
 
@@ -638,9 +625,9 @@
 extern struct inode * ext3_orphan_get (struct super_block *, ino_t);
 extern unsigned long ext3_count_free_inodes (struct super_block *);
 extern void ext3_check_inodes_bitmap (struct super_block *);
+extern unsigned long ext3_count_free (struct buffer_head *, unsigned);
 
 /* inode.c */
-
 extern struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *);
 extern struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *);
 
@@ -654,13 +641,13 @@
 extern void ext3_discard_prealloc (struct inode *);
 extern void ext3_dirty_inode(struct inode *);
 extern int ext3_change_inode_journal_flag(struct inode *, int);
+extern void ext3_truncate (struct inode *);
 
 /* ioctl.c */
 extern int ext3_ioctl (struct inode *, struct file *, unsigned int,
 		       unsigned long);
 
 /* namei.c */
-extern struct inode_operations ext3_dir_inode_operations;
 extern int ext3_orphan_add(handle_t *, struct inode *);
 extern int ext3_orphan_del(handle_t *, struct inode *);
 
@@ -684,9 +671,6 @@
 extern struct super_block * ext3_read_super (struct super_block *,void *,int);
 extern int ext3_statfs (struct super_block *, struct statfs *);
 
-/* truncate.c */
-extern void ext3_truncate (struct inode *);
-
 #define ext3_std_error(sb, errno)				\
 do {								\
 	if ((errno))						\
@@ -705,10 +689,15 @@
 extern struct inode_operations ext3_file_inode_operations;
 extern struct file_operations ext3_file_operations;
 
+/* inode.c */
+extern struct address_space_operations ext3_aops;
+
+/* namei.c */
+extern struct inode_operations ext3_dir_inode_operations;
+
 /* symlink.c */
 extern struct inode_operations ext3_fast_symlink_inode_operations;
 
-extern struct address_space_operations ext3_aops;
 
 #endif	/* __KERNEL__ */
 
diff -u --recursive --new-file v2.5.1/linux/include/linux/ext3_jbd.h linux/include/linux/ext3_jbd.h
--- v2.5.1/linux/include/linux/ext3_jbd.h	Fri Nov  9 14:25:04 2001
+++ linux/include/linux/ext3_jbd.h	Sun Dec 30 16:59:04 2001
@@ -196,9 +196,22 @@
  */
 static inline handle_t *ext3_journal_start(struct inode *inode, int nblocks)
 {
+	journal_t *journal;
+	
 	if (inode->i_sb->s_flags & MS_RDONLY)
 		return ERR_PTR(-EROFS);
-	return journal_start(EXT3_JOURNAL(inode), nblocks);
+
+	/* Special case here: if the journal has aborted behind our
+	 * backs (eg. EIO in the commit thread), then we still need to
+	 * take the FS itself readonly cleanly. */
+	journal = EXT3_JOURNAL(inode);
+	if (is_journal_aborted(journal)) {
+		ext3_abort(inode->i_sb, __FUNCTION__,
+			   "Detected aborted journal");
+		return ERR_PTR(-EROFS);
+	}
+	
+	return journal_start(journal, nblocks);
 }
 
 static inline handle_t *
diff -u --recursive --new-file v2.5.1/linux/include/linux/file.h linux/include/linux/file.h
--- v2.5.1/linux/include/linux/file.h	Wed Aug 23 11:22:26 2000
+++ linux/include/linux/file.h	Tue Jan  1 19:13:40 2002
@@ -5,6 +5,8 @@
 #ifndef __LINUX_FILE_H
 #define __LINUX_FILE_H
 
+#include <linux/sched.h>
+
 extern void FASTCALL(fput(struct file *));
 extern struct file * FASTCALL(fget(unsigned int fd));
  
diff -u --recursive --new-file v2.5.1/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.5.1/linux/include/linux/fs.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/fs.h	Tue Jan  1 19:13:38 2002
@@ -311,7 +311,6 @@
 #include <linux/udf_fs_i.h>
 #include <linux/ncp_fs_i.h>
 #include <linux/proc_fs_i.h>
-#include <linux/usbdev_fs_i.h>
 #include <linux/jffs2_fs_i.h>
 #include <linux/cramfs_fs_sb.h>
 
@@ -502,7 +501,6 @@
 		struct ncp_inode_info		ncpfs_i;
 		struct proc_inode_info		proc_i;
 		struct socket			socket_i;
-		struct usbdev_inode_info        usbdev_i;
 		struct jffs2_inode_info		jffs2_i;
 		void				*generic_ip;
 	} u;
@@ -686,7 +684,6 @@
 #include <linux/bfs_fs_sb.h>
 #include <linux/udf_fs_sb.h>
 #include <linux/ncp_fs_sb.h>
-#include <linux/usbdev_fs_sb.h>
 #include <linux/cramfs_fs_sb.h>
 #include <linux/jffs2_fs_sb.h>
 
@@ -744,7 +741,6 @@
 		struct bfs_sb_info	bfs_sb;
 		struct udf_sb_info	udf_sb;
 		struct ncp_sb_info	ncpfs_sb;
-		struct usbdev_sb_info   usbdevfs_sb;
 		struct jffs2_sb_info	jffs2_sb;
 		struct cramfs_sb_info	cramfs_sb;
 		void			*generic_sbp;
@@ -982,6 +978,7 @@
 extern struct vfsmount *kern_mount(struct file_system_type *);
 extern int may_umount(struct vfsmount *);
 extern long do_mount(char *, char *, char *, unsigned long, void *);
+extern void umount_tree(struct vfsmount *);
 
 #define kern_umount mntput
 
@@ -1102,7 +1099,7 @@
 
 extern int try_to_free_buffers(struct page *, unsigned int);
 extern void refile_buffer(struct buffer_head * buf);
-extern void create_empty_buffers(struct page *, kdev_t, unsigned long);
+extern void create_empty_buffers(struct page *, unsigned long);
 extern void end_buffer_io_sync(struct buffer_head *bh, int uptodate);
 
 /* reiserfs_writepage needs this */
@@ -1378,6 +1375,8 @@
 		__bforget(buf);
 }
 extern int set_blocksize(kdev_t, int);
+extern int sb_set_blocksize(struct super_block *, int);
+extern int sb_min_blocksize(struct super_block *, int);
 extern struct buffer_head * bread(kdev_t, int, int);
 static inline struct buffer_head * sb_bread(struct super_block *sb, int block)
 {
@@ -1390,6 +1389,12 @@
 static inline struct buffer_head * sb_get_hash_table(struct super_block *sb, int block)
 {
 	return get_hash_table(sb->s_dev, block, sb->s_blocksize);
+}
+static inline void map_bh(struct buffer_head *bh, struct super_block *sb, int block)
+{
+	bh->b_state |= 1 << BH_Mapped;
+	bh->b_dev = sb->s_dev;
+	bh->b_blocknr = block;
 }
 extern void wakeup_bdflush(void);
 extern void put_unused_buffer_head(struct buffer_head * bh);
diff -u --recursive --new-file v2.5.1/linux/include/linux/genhd.h linux/include/linux/genhd.h
--- v2.5.1/linux/include/linux/genhd.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/genhd.h	Tue Jan  1 19:13:38 2002
@@ -71,13 +71,11 @@
 	const char *major_name;		/* name of major driver */
 	int minor_shift;		/* number of times minor is shifted to
 					   get real minor */
-	int max_p;			/* maximum partitions per device */
 
 	struct hd_struct *part;		/* [indexed by minor] */
 	int *sizes;			/* [idem], device size in blocks */
 	int nr_real;			/* number of real devices */
 
-	void *real_devices;		/* internal use */
 	struct gendisk *next;
 	struct block_device_operations *fops;
 
@@ -247,7 +245,7 @@
 static inline unsigned int disk_index (kdev_t dev)
 {
 	struct gendisk *g = get_gendisk(dev);
-	return g ? (MINOR(dev) >> g->minor_shift) : 0;
+	return g ? (minor(dev) >> g->minor_shift) : 0;
 }
 
 #endif
diff -u --recursive --new-file v2.5.1/linux/include/linux/gfp.h linux/include/linux/gfp.h
--- v2.5.1/linux/include/linux/gfp.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/gfp.h	Tue Jan  1 19:13:37 2002
@@ -0,0 +1,81 @@
+#ifndef __LINUX_GFP_H
+#define __LINUX_GFP_H
+
+#include <linux/mmzone.h>
+#include <linux/stddef.h>
+#include <linux/linkage.h>
+/*
+ * GFP bitmasks..
+ */
+/* Zone modifiers in GFP_ZONEMASK (see linux/mmzone.h - low four bits) */
+#define __GFP_DMA	0x01
+#define __GFP_HIGHMEM	0x02
+
+/* Action modifiers - doesn't change the zoning */
+#define __GFP_WAIT	0x10	/* Can wait and reschedule? */
+#define __GFP_HIGH	0x20	/* Should access emergency pools? */
+#define __GFP_IO	0x40	/* Can start low memory physical IO? */
+#define __GFP_HIGHIO	0x80	/* Can start high mem physical IO? */
+#define __GFP_FS	0x100	/* Can call down to low-level FS? */
+
+#define GFP_NOHIGHIO	(__GFP_HIGH | __GFP_WAIT | __GFP_IO)
+#define GFP_NOIO	(__GFP_HIGH | __GFP_WAIT)
+#define GFP_NOFS	(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO)
+#define GFP_ATOMIC	(__GFP_HIGH)
+#define GFP_USER	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
+#define GFP_HIGHUSER	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS | __GFP_HIGHMEM)
+#define GFP_KERNEL	(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
+#define GFP_NFS		(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
+#define GFP_KSWAPD	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
+
+/* Flag - indicates that the buffer will be suitable for DMA.  Ignored on some
+   platforms, used as appropriate on others */
+
+#define GFP_DMA		__GFP_DMA
+
+/*
+ * There is only one page-allocator function, and two main namespaces to
+ * it. The alloc_page*() variants return 'struct page *' and as such
+ * can allocate highmem pages, the *get*page*() variants return
+ * virtual kernel addresses to the allocated page(s).
+ */
+extern struct page * FASTCALL(_alloc_pages(unsigned int gfp_mask, unsigned int order));
+extern struct page * FASTCALL(__alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_t *zonelist));
+extern struct page * alloc_pages_node(int nid, unsigned int gfp_mask, unsigned int order);
+
+static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order)
+{
+	/*
+	 * Gets optimized away by the compiler.
+	 */
+	if (order >= MAX_ORDER)
+		return NULL;
+	return _alloc_pages(gfp_mask, order);
+}
+
+#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)
+
+extern unsigned long FASTCALL(__get_free_pages(unsigned int gfp_mask, unsigned int order));
+extern unsigned long FASTCALL(get_zeroed_page(unsigned int gfp_mask));
+
+#define __get_free_page(gfp_mask) \
+		__get_free_pages((gfp_mask),0)
+
+#define __get_dma_pages(gfp_mask, order) \
+		__get_free_pages((gfp_mask) | GFP_DMA,(order))
+
+/*
+ * The old interface name will be removed in 2.5:
+ */
+#define get_free_page get_zeroed_page
+
+/*
+ * There is only one 'core' page-freeing function.
+ */
+extern void FASTCALL(__free_pages(struct page *page, unsigned int order));
+extern void FASTCALL(free_pages(unsigned long addr, unsigned int order));
+
+#define __free_page(page) __free_pages((page), 0)
+#define free_page(addr) free_pages((addr),0)
+
+#endif /* __LINUX_GFP_H */
diff -u --recursive --new-file v2.5.1/linux/include/linux/i8k.h linux/include/linux/i8k.h
--- v2.5.1/linux/include/linux/i8k.h	Fri Nov  2 17:46:47 2001
+++ linux/include/linux/i8k.h	Sun Dec 30 10:38:45 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 -u --recursive --new-file v2.5.1/linux/include/linux/ide.h linux/include/linux/ide.h
--- v2.5.1/linux/include/linux/ide.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/ide.h	Thu Jan  3 11:37:49 2002
@@ -18,13 +18,13 @@
 
 /*
  * This is the multiple IDE interface driver, as evolved from hd.c.
- * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
+ * It supports up to four IDE interfaces, on one or more IRQs (usually 14, 15).
  * There can be up to two drives per interface, as per the ATA-2 spec.
  *
- * Primary i/f:    ide0: major=3;  (hda)         minor=0; (hdb)         minor=64
- * Secondary i/f:  ide1: major=22; (hdc or hd1a) minor=0; (hdd or hd1b) minor=64
- * Tertiary i/f:   ide2: major=33; (hde)         minor=0; (hdf)         minor=64
- * Quaternary i/f: ide3: major=34; (hdg)         minor=0; (hdh)         minor=64
+ * Primary i/f:    ide0: major=3;  (hda) minor=0; (hdb) minor=64
+ * Secondary i/f:  ide1: major=22; (hdc) minor=0; (hdd) minor=64
+ * Tertiary i/f:   ide2: major=33; (hde) minor=0; (hdf) minor=64
+ * Quaternary i/f: ide3: major=34; (hdg) minor=0; (hdh) minor=64
  */
 
 /******************************************************************************
@@ -915,6 +915,12 @@
  * to a drive as part of a disk multwrite operation.
  */
 int ide_multwrite (ide_drive_t *drive, unsigned int mcount);
+
+/*
+ * idedisk_input_data() is a wrapper around ide_input_data() which copes
+ * with byte-swapping the input data if required.
+ */
+inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
 
 /*
  * ide_stall_queue() can be used by a drive to give excess bandwidth back
diff -u --recursive --new-file v2.5.1/linux/include/linux/interrupt.h linux/include/linux/interrupt.h
--- v2.5.1/linux/include/linux/interrupt.h	Thu Nov 22 11:46:19 2001
+++ linux/include/linux/interrupt.h	Tue Jan  1 19:13:38 2002
@@ -3,12 +3,14 @@
 #define _LINUX_INTERRUPT_H
 
 #include <linux/config.h>
+#include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/smp.h>
 #include <linux/cache.h>
 
 #include <asm/bitops.h>
 #include <asm/atomic.h>
+#include <asm/system.h>
 #include <asm/ptrace.h>
 
 struct irqaction {
diff -u --recursive --new-file v2.5.1/linux/include/linux/isdn.h linux/include/linux/isdn.h
--- v2.5.1/linux/include/linux/isdn.h	Sun Sep 30 12:26:42 2001
+++ linux/include/linux/isdn.h	Sun Dec 30 10:31:51 2001
@@ -150,7 +150,6 @@
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/major.h>
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
diff -u --recursive --new-file v2.5.1/linux/include/linux/jbd.h linux/include/linux/jbd.h
--- v2.5.1/linux/include/linux/jbd.h	Fri Nov  9 14:25:04 2001
+++ linux/include/linux/jbd.h	Sun Dec 30 16:59:04 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 {
@@ -564,7 +564,7 @@
 
 /* Log buffer allocation */
 extern struct journal_head * journal_get_descriptor_buffer(journal_t *);
-extern unsigned long journal_next_log_block(journal_t *);
+int journal_next_log_block(journal_t *, unsigned long *);
 
 /* Commit management */
 extern void journal_commit_transaction(journal_t *);
@@ -664,15 +664,16 @@
 extern void	   journal_destroy    (journal_t *);
 extern int	   journal_recover    (journal_t *journal);
 extern int	   journal_wipe       (journal_t *, int);
-extern int	   journal_skip_recovery (journal_t *);
-extern void	   journal_update_superblock (journal_t *, int);
-extern void	   __journal_abort      (journal_t *);
+extern int	   journal_skip_recovery	(journal_t *);
+extern void	   journal_update_superblock	(journal_t *, int);
+extern void	   __journal_abort_hard	(journal_t *);
+extern void	   __journal_abort_soft	(journal_t *, int);
 extern void	   journal_abort      (journal_t *, int);
 extern int	   journal_errno      (journal_t *);
 extern void	   journal_ack_err    (journal_t *);
 extern int	   journal_clear_err  (journal_t *);
-extern unsigned long journal_bmap(journal_t *journal, unsigned long blocknr);
-extern int	    journal_force_commit(journal_t *journal);
+extern int	   journal_bmap(journal_t *, unsigned long, unsigned long *);
+extern int	   journal_force_commit(journal_t *);
 
 /*
  * journal_head management
diff -u --recursive --new-file v2.5.1/linux/include/linux/kbd_kern.h linux/include/linux/kbd_kern.h
--- v2.5.1/linux/include/linux/kbd_kern.h	Thu Nov 22 11:47:23 2001
+++ linux/include/linux/kbd_kern.h	Tue Jan  1 19:15:04 2002
@@ -140,7 +140,6 @@
 int getkeycode(unsigned int scancode);
 int setkeycode(unsigned int scancode, unsigned int keycode);
 void compute_shiftstate(void);
-int keyboard_wait_for_keypress(struct console *);
 
 /* defkeymap.c */
 
diff -u --recursive --new-file v2.5.1/linux/include/linux/kdev_t.h linux/include/linux/kdev_t.h
--- v2.5.1/linux/include/linux/kdev_t.h	Fri Feb 16 16:06:17 2001
+++ linux/include/linux/kdev_t.h	Tue Jan  1 11:10:48 2002
@@ -57,48 +57,84 @@
 aeb - 950811
 */
 
-/* Since MINOR(dev) is used as index in static arrays,
-   the kernel is not quite ready yet for larger minors.
-   However, everything runs fine with an arbitrary kdev_t type. */
 
+/*
+ * NOTE NOTE NOTE!
+ *
+ * The kernel-internal "kdev_t" will eventually have
+ * 20 bits for minor numbers, and 12 bits for majors.
+ *
+ * HOWEVER, the external representation is still 8+8
+ * bits, and there is no way to generate the extended
+ * "kdev_t" format yet. Which is just as well, since
+ * we still use "minor" as an index into various
+ * static arrays, and they are sized for a 8-bit index.
+ */
+typedef struct {
+	unsigned short value;
+} kdev_t;
+
+#define KDEV_MINOR_BITS		8
+#define KDEV_MAJOR_BITS		8
+
+#define __mkdev(major,minor)	(((major) << KDEV_MINOR_BITS) + (minor))
+
+#define mk_kdev(major, minor)	((kdev_t) { __mkdev(major,minor) } )
+
+/*
+ * The "values" are just _cookies_, usable for 
+ * internal equality comparisons and for things
+ * like NFS filehandle conversion.
+ */
+static inline unsigned int kdev_val(kdev_t dev)
+{
+	return dev.value;
+}
+
+static inline kdev_t val_to_kdev(unsigned int val)
+{
+	kdev_t dev;
+	dev.value = val;
+	return dev;
+}
+
+#define HASHDEV(dev)	(kdev_val(dev))
+#define NODEV		(mk_kdev(0,0))
+#define B_FREE		(mk_kdev(0xff,0xff))
+
+extern const char * kdevname(kdev_t);	/* note: returns pointer to static data! */
+
+static inline int kdev_same(kdev_t dev1, kdev_t dev2)
+{
+	return dev1.value == dev2.value;
+}
+
+#define kdev_none(d1)	(!kdev_val(d1))
+
+/* Mask off the high bits for now.. */
+#define minor(dev)	((dev).value & 0xff)
+#define major(dev)	(((dev).value >> KDEV_MINOR_BITS) & 0xff)
+
+/* These are for user-level "dev_t" */
 #define MINORBITS	8
 #define MINORMASK	((1U << MINORBITS) - 1)
 
-typedef unsigned short kdev_t;
-
 #define MAJOR(dev)	((unsigned int) ((dev) >> MINORBITS))
 #define MINOR(dev)	((unsigned int) ((dev) & MINORMASK))
-#define HASHDEV(dev)	((unsigned int) (dev))
-#define NODEV		0
 #define MKDEV(ma,mi)	(((ma) << MINORBITS) | (mi))
-#define B_FREE		0xffff		/* yuk */
-
-extern const char * kdevname(kdev_t);	/* note: returns pointer to static data! */
 
 /*
-As long as device numbers in the outside world have 16 bits only,
-we use these conversions.
-*/
+ * Conversion functions
+ */
 
-static inline unsigned int kdev_t_to_nr(kdev_t dev) {
-	return (MAJOR(dev)<<8) | MINOR(dev);
+static inline int kdev_t_to_nr(kdev_t dev)
+{
+	return MKDEV(major(dev), minor(dev));
 }
 
 static inline kdev_t to_kdev_t(int dev)
 {
-	int major, minor;
-#if 0
-	major = (dev >> 16);
-	if (!major) {
-		major = (dev >> 8);
-		minor = (dev & 0xff);
-	} else
-		minor = (dev & 0xffff);
-#else
-	major = (dev >> 8);
-	minor = (dev & 0xff);
-#endif
-	return MKDEV(major, minor);
+	return mk_kdev(MAJOR(dev),MINOR(dev));
 }
 
 #else /* __KERNEL__ || _LVM_H_INCLUDE */
diff -u --recursive --new-file v2.5.1/linux/include/linux/kernel.h linux/include/linux/kernel.h
--- v2.5.1/linux/include/linux/kernel.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/kernel.h	Tue Jan  1 19:13:37 2002
@@ -37,16 +37,6 @@
 #define	KERN_INFO	"<6>"	/* informational			*/
 #define	KERN_DEBUG	"<7>"	/* debug-level messages			*/
 
-# define NORET_TYPE    /**/
-# define ATTRIB_NORET  __attribute__((noreturn))
-# define NORET_AND     noreturn,
-
-#ifdef __i386__
-#define FASTCALL(x)	x __attribute__((regparm(3)))
-#else
-#define FASTCALL(x)	x
-#endif
-
 struct completion;
 
 extern struct notifier_block *panic_notifier_list;
diff -u --recursive --new-file v2.5.1/linux/include/linux/keyboard.h linux/include/linux/keyboard.h
--- v2.5.1/linux/include/linux/keyboard.h	Thu Nov 22 11:47:07 2001
+++ linux/include/linux/keyboard.h	Tue Jan  1 19:14:49 2002
@@ -26,7 +26,6 @@
 extern const int max_vals[];
 extern unsigned short *key_maps[MAX_NR_KEYMAPS];
 extern unsigned short plain_map[NR_KEYS];
-extern wait_queue_head_t keypress_wait;
 extern unsigned char keyboard_type;
 #endif
 
diff -u --recursive --new-file v2.5.1/linux/include/linux/linkage.h linux/include/linux/linkage.h
--- v2.5.1/linux/include/linux/linkage.h	Mon Dec 11 12:49:54 2000
+++ linux/include/linux/linkage.h	Sat Dec 29 17:30:07 2001
@@ -60,4 +60,14 @@
 
 #endif
 
+# define NORET_TYPE    /**/
+# define ATTRIB_NORET  __attribute__((noreturn))
+# define NORET_AND     noreturn,
+
+#ifdef __i386__
+#define FASTCALL(x)	x __attribute__((regparm(3)))
+#else
+#define FASTCALL(x)	x
+#endif
+
 #endif
diff -u --recursive --new-file v2.5.1/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.5.1/linux/include/linux/mm.h	Thu Nov 22 11:46:20 2001
+++ linux/include/linux/mm.h	Tue Jan  1 19:13:38 2002
@@ -7,6 +7,7 @@
 #ifdef __KERNEL__
 
 #include <linux/config.h>
+#include <linux/gfp.h>
 #include <linux/string.h>
 #include <linux/list.h>
 #include <linux/mmzone.h>
@@ -344,51 +345,6 @@
 /* The array of struct pages */
 extern mem_map_t * mem_map;
 
-/*
- * There is only one page-allocator function, and two main namespaces to
- * it. The alloc_page*() variants return 'struct page *' and as such
- * can allocate highmem pages, the *get*page*() variants return
- * virtual kernel addresses to the allocated page(s).
- */
-extern struct page * FASTCALL(_alloc_pages(unsigned int gfp_mask, unsigned int order));
-extern struct page * FASTCALL(__alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_t *zonelist));
-extern struct page * alloc_pages_node(int nid, unsigned int gfp_mask, unsigned int order);
-
-static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order)
-{
-	/*
-	 * Gets optimized away by the compiler.
-	 */
-	if (order >= MAX_ORDER)
-		return NULL;
-	return _alloc_pages(gfp_mask, order);
-}
-
-#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)
-
-extern unsigned long FASTCALL(__get_free_pages(unsigned int gfp_mask, unsigned int order));
-extern unsigned long FASTCALL(get_zeroed_page(unsigned int gfp_mask));
-
-#define __get_free_page(gfp_mask) \
-		__get_free_pages((gfp_mask),0)
-
-#define __get_dma_pages(gfp_mask, order) \
-		__get_free_pages((gfp_mask) | GFP_DMA,(order))
-
-/*
- * The old interface name will be removed in 2.5:
- */
-#define get_free_page get_zeroed_page
-
-/*
- * There is only one 'core' page-freeing function.
- */
-extern void FASTCALL(__free_pages(struct page *page, unsigned int order));
-extern void FASTCALL(free_pages(unsigned long addr, unsigned int order));
-
-#define __free_page(page) __free_pages((page), 0)
-#define free_page(addr) free_pages((addr),0)
-
 extern void show_free_areas(void);
 extern void show_free_areas_node(pg_data_t *pgdat);
 
@@ -418,6 +374,9 @@
 extern void ptrace_disable(struct task_struct *);
 extern int ptrace_check_attach(struct task_struct *task, int kill);
 
+int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
+		int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
+
 /*
  * On a two-level page table, this ends up being trivial. Thus the
  * inlining and the symmetry break with pte_alloc() that does all
@@ -511,35 +470,6 @@
 /* generic vm_area_ops exported for stackable file systems */
 extern int filemap_sync(struct vm_area_struct *, unsigned long,	size_t, unsigned int);
 extern struct page *filemap_nopage(struct vm_area_struct *, unsigned long, int);
-
-/*
- * GFP bitmasks..
- */
-/* Zone modifiers in GFP_ZONEMASK (see linux/mmzone.h - low four bits) */
-#define __GFP_DMA	0x01
-#define __GFP_HIGHMEM	0x02
-
-/* Action modifiers - doesn't change the zoning */
-#define __GFP_WAIT	0x10	/* Can wait and reschedule? */
-#define __GFP_HIGH	0x20	/* Should access emergency pools? */
-#define __GFP_IO	0x40	/* Can start low memory physical IO? */
-#define __GFP_HIGHIO	0x80	/* Can start high mem physical IO? */
-#define __GFP_FS	0x100	/* Can call down to low-level FS? */
-
-#define GFP_NOHIGHIO	(__GFP_HIGH | __GFP_WAIT | __GFP_IO)
-#define GFP_NOIO	(__GFP_HIGH | __GFP_WAIT)
-#define GFP_NOFS	(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO)
-#define GFP_ATOMIC	(__GFP_HIGH)
-#define GFP_USER	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
-#define GFP_HIGHUSER	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS | __GFP_HIGHMEM)
-#define GFP_KERNEL	(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
-#define GFP_NFS		(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
-#define GFP_KSWAPD	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
-
-/* Flag - indicates that the buffer will be suitable for DMA.  Ignored on some
-   platforms, used as appropriate on others */
-
-#define GFP_DMA		__GFP_DMA
 
 /* vma is the first one with  address < vma->vm_end,
  * and even  address < vma->vm_start. Have to extend vma. */
diff -u --recursive --new-file v2.5.1/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h
--- v2.5.1/linux/include/linux/msdos_fs.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/msdos_fs.h	Thu Dec 27 08:17:43 2001
@@ -200,7 +200,7 @@
 #include <linux/nls.h>
 
 struct fat_cache {
-	kdev_t device; /* device number. 0 means unused. */
+	struct super_block *sb; /* fs in question.  NULL means unused */
 	int start_cluster; /* first cluster of the chain. */
 	int file_cluster; /* cluster number in the file. */
 	int disk_cluster; /* cluster number on disk. */
@@ -252,7 +252,7 @@
 			     int *d_clu);
 extern void fat_cache_add(struct inode *inode, int f_clu, int d_clu);
 extern void fat_cache_inval_inode(struct inode *inode);
-extern void fat_cache_inval_dev(kdev_t device);
+extern void fat_cache_inval_dev(struct super_block *sb);
 extern int fat_get_cluster(struct inode *inode, int cluster);
 extern int fat_free(struct inode *inode, int skip);
 
diff -u --recursive --new-file v2.5.1/linux/include/linux/namespace.h linux/include/linux/namespace.h
--- v2.5.1/linux/include/linux/namespace.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/namespace.h	Tue Dec 25 15:39:20 2001
@@ -0,0 +1,42 @@
+#ifndef _NAMESPACE_H_
+#define _NAMESPACE_H_
+#ifdef __KERNEL__
+
+struct namespace {
+	atomic_t		count;
+	struct vfsmount *	root;
+	struct list_head	list;
+	struct rw_semaphore	sem;
+};
+
+static inline void put_namespace(struct namespace *namespace)
+{
+	if (atomic_dec_and_test(&namespace->count)) {
+		down_write(&namespace->sem);
+		spin_lock(&dcache_lock);
+		umount_tree(namespace->root);
+		spin_unlock(&dcache_lock);
+		up_write(&namespace->sem);
+		kfree(namespace);
+	}
+}
+
+static inline void exit_namespace(struct task_struct *p)
+{
+	struct namespace *namespace = p->namespace;
+	if (namespace) {
+		task_lock(p);
+		p->namespace = NULL;
+		task_unlock(p);
+		put_namespace(namespace);
+	}
+}
+extern int copy_namespace(int, struct task_struct *);
+
+static inline void get_namespace(struct namespace *namespace)
+{
+	atomic_inc(&namespace->count);
+}
+
+#endif
+#endif
diff -u --recursive --new-file v2.5.1/linux/include/linux/nfsd/nfsfh.h linux/include/linux/nfsd/nfsfh.h
--- v2.5.1/linux/include/linux/nfsd/nfsfh.h	Thu Nov 22 11:47:20 2001
+++ linux/include/linux/nfsd/nfsfh.h	Tue Jan  1 19:14:33 2002
@@ -119,15 +119,37 @@
 
 /*
  * Conversion macros for the filehandle fields.
+ *
+ * Keep the device numbers in "backwards compatible
+ * format", ie the low 16 bits contain the low 8 bits
+ * of the 20-bit minor and the 12-bit major number.
+ *
+ * The high 16 bits contain the rest (4 bits major
+ * and 12 bits minor),
  */
 static inline __u32 kdev_t_to_u32(kdev_t dev)
 {
-	return (__u32) dev;
+	unsigned int minor = minor(dev);
+	unsigned int major = major(dev);
+	__u32 udev;
+
+	/* Create the low 16 bits.. */
+	udev = ((major & 0xff) << 8) + (minor & 0xff);
+
+	/* ..and then the rest. */
+	major >>= 8; minor >>= 8;
+	udev |= (major << 28) | (minor << 16);
+
+	return udev;
 }
 
 static inline kdev_t u32_to_kdev_t(__u32 udev)
 {
-	return (kdev_t) udev;
+	unsigned int minor, major;
+
+	minor = (udev & 0xff) | ((udev >> 8) & 0xfff00);
+	major = ((udev >> 8) & 0xff) | ((udev >> 20) & 0xf00);
+	return mk_kdev(major, minor);
 }
 
 static inline __u32 ino_t_to_u32(ino_t ino)
diff -u --recursive --new-file v2.5.1/linux/include/linux/parport.h linux/include/linux/parport.h
--- v2.5.1/linux/include/linux/parport.h	Wed Nov 14 14:52:47 2001
+++ linux/include/linux/parport.h	Sat Dec 29 17:30:07 2001
@@ -8,6 +8,7 @@
 
 #ifndef _PARPORT_H_
 #define _PARPORT_H_
+#include <linux/sched.h>
 
 /* Start off with user-visible constants */
 
diff -u --recursive --new-file v2.5.1/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h
--- v2.5.1/linux/include/linux/pci_ids.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/pci_ids.h	Thu Dec 27 08:38:57 2001
@@ -946,11 +946,12 @@
 #define PCI_DEVICE_ID_VIA_8233_7	0x3065
 #define PCI_DEVICE_ID_VIA_82C686_6	0x3068
 #define PCI_DEVICE_ID_VIA_8233_0	0x3074
-#define PCI_DEVICE_ID_VIA_8622          0x3102 
-#define PCI_DEVICE_ID_VIA_8233C_0	0x3109
-#define PCI_DEVICE_ID_VIA_8361          0x3112 
 #define PCI_DEVICE_ID_VIA_8633_0	0x3091
 #define PCI_DEVICE_ID_VIA_8367_0	0x3099 
+#define PCI_DEVICE_ID_VIA_8622		0x3102 
+#define PCI_DEVICE_ID_VIA_8233C_0	0x3109
+#define PCI_DEVICE_ID_VIA_8361		0x3112 
+#define PCI_DEVICE_ID_VIA_8233A		0x3147
 #define PCI_DEVICE_ID_VIA_86C100A	0x6100
 #define PCI_DEVICE_ID_VIA_8231		0x8231
 #define PCI_DEVICE_ID_VIA_8231_4	0x8235
@@ -960,7 +961,7 @@
 #define PCI_DEVICE_ID_VIA_82C597_1	0x8597
 #define PCI_DEVICE_ID_VIA_82C598_1	0x8598
 #define PCI_DEVICE_ID_VIA_8601_1	0x8601
-#define PCI_DEVICE_ID_VIA_8505_1	0X8605
+#define PCI_DEVICE_ID_VIA_8505_1	0x8605
 #define PCI_DEVICE_ID_VIA_8633_1	0xB091
 #define PCI_DEVICE_ID_VIA_8367_1	0xB099
 
diff -u --recursive --new-file v2.5.1/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.5.1/linux/include/linux/proc_fs.h	Thu Nov 22 11:46:23 2001
+++ linux/include/linux/proc_fs.h	Tue Jan  1 19:13:38 2002
@@ -3,6 +3,8 @@
 
 #include <linux/config.h>
 #include <linux/slab.h>
+#include <linux/fs.h>
+#include <asm/atomic.h>
 
 /*
  * The proc filesystem constants/structures
diff -u --recursive --new-file v2.5.1/linux/include/linux/quota.h linux/include/linux/quota.h
--- v2.5.1/linux/include/linux/quota.h	Thu Nov 22 10:38:31 2001
+++ linux/include/linux/quota.h	Thu Dec 27 08:17:43 2001
@@ -167,7 +167,6 @@
 	/* fields after this point are cleared when invalidating */
 	struct super_block *dq_sb;	/* superblock this applies to */
 	unsigned int dq_id;		/* ID this applies to (uid, gid) */
-	kdev_t dq_dev;			/* Device this applies to */
 	short dq_type;			/* Type of quota */
 	short dq_flags;			/* See DQ_* */
 	unsigned long dq_referenced;	/* Number of times this dquot was 
diff -u --recursive --new-file v2.5.1/linux/include/linux/quotaops.h linux/include/linux/quotaops.h
--- v2.5.1/linux/include/linux/quotaops.h	Thu Nov 22 11:46:52 2001
+++ linux/include/linux/quotaops.h	Tue Jan  1 19:14:05 2002
@@ -23,7 +23,7 @@
 extern void dquot_initialize(struct inode *inode, short type);
 extern void dquot_drop(struct inode *inode);
 extern int  quota_off(struct super_block *sb, short type);
-extern int  sync_dquots(kdev_t dev, short type);
+extern int  sync_dquots(struct super_block *sb, short type);
 
 extern int  dquot_alloc_block(struct inode *inode, unsigned long number, char prealloc);
 extern int  dquot_alloc_inode(const struct inode *inode, unsigned long number);
@@ -159,7 +159,7 @@
 	return 0;
 }
 
-#define DQUOT_SYNC(dev)	sync_dquots(dev, -1)
+#define DQUOT_SYNC(sb)	sync_dquots(sb, -1)
 #define DQUOT_OFF(sb)	quota_off(sb, -1)
 
 #else
@@ -171,7 +171,7 @@
 #define DQUOT_DROP(inode)			do { } while(0)
 #define DQUOT_ALLOC_INODE(inode)		(0)
 #define DQUOT_FREE_INODE(inode)			do { } while(0)
-#define DQUOT_SYNC(dev)				do { } while(0)
+#define DQUOT_SYNC(sb)				do { } while(0)
 #define DQUOT_OFF(sb)				do { } while(0)
 #define DQUOT_TRANSFER(inode, iattr)		(0)
 extern __inline__ int DQUOT_PREALLOC_BLOCK_NODIRTY(struct inode *inode, int nr)
diff -u --recursive --new-file v2.5.1/linux/include/linux/raid/md_k.h linux/include/linux/raid/md_k.h
--- v2.5.1/linux/include/linux/raid/md_k.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/raid/md_k.h	Tue Jan  1 12:49:26 2002
@@ -77,9 +77,9 @@
 
 static inline mddev_t * kdev_to_mddev (kdev_t dev)
 {
-	if (MAJOR(dev) != MD_MAJOR)
+	if (major(dev) != MD_MAJOR)
 		BUG();
-        return mddev_map[MINOR(dev)].mddev;
+        return mddev_map[minor(dev)].mddev;
 }
 
 /*
@@ -240,7 +240,7 @@
 
 	int (*stop_resync)(mddev_t *mddev);
 	int (*restart_resync)(mddev_t *mddev);
-	int (*sync_request)(mddev_t *mddev, sector_t sector_nr);
+	int (*sync_request)(mddev_t *mddev, sector_t sector_nr, int go_faster);
 };
 
 
@@ -256,7 +256,7 @@
 
 static inline kdev_t mddev_to_kdev(mddev_t * mddev)
 {
-	return MKDEV(MD_MAJOR, mdidx(mddev));
+	return mk_kdev(MD_MAJOR, mdidx(mddev));
 }
 
 extern mdk_rdev_t * find_rdev(mddev_t * mddev, kdev_t dev);
diff -u --recursive --new-file v2.5.1/linux/include/linux/raid/raid1.h linux/include/linux/raid/raid1.h
--- v2.5.1/linux/include/linux/raid/raid1.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/raid/raid1.h	Wed Dec 19 15:18:10 2001
@@ -9,8 +9,8 @@
 	int		number;
 	int		raid_disk;
 	kdev_t		dev;
-	int		sect_limit;
-	int		head_position;
+	sector_t	head_position;
+	atomic_t	nr_pending;
 
 	/*
 	 * State bits:
@@ -31,23 +31,21 @@
 	int			raid_disks;
 	int			working_disks;
 	int			last_used;
-	sector_t		next_sect;
-	int			sect_count;
+	sector_t		next_seq_sect;
 	mdk_thread_t		*thread, *resync_thread;
 	int			resync_mirrors;
 	mirror_info_t		*spare;
 	spinlock_t		device_lock;
 
 	/* for use when syncing mirrors: */
-	unsigned long	start_active, start_ready,
-		start_pending, start_future;
-	int	cnt_done, cnt_active, cnt_ready,
-		cnt_pending, cnt_future;
-	int	phase;
-	int	window;
-	wait_queue_head_t	wait_done;
-	wait_queue_head_t	wait_ready;
-	spinlock_t		segment_lock;
+
+	spinlock_t		resync_lock;
+	int nr_pending;
+	int barrier;
+	sector_t		next_resync;
+
+	wait_queue_head_t	wait_idle;
+	wait_queue_head_t	wait_resume;
 
 	mempool_t *r1bio_pool;
 	mempool_t *r1buf_pool;
@@ -62,7 +60,8 @@
 #define mddev_to_conf(mddev) ((conf_t *) mddev->private)
 
 /*
- * this is our 'private' 'collective' RAID1 buffer head.
+ * this is our 'private' RAID1 bio.
+ *
  * it contains information about what kind of IO operations were started
  * for this RAID1 operation, and about their status:
  */
@@ -83,6 +82,7 @@
 	 * if the IO is in READ direction, then this bio is used:
 	 */
 	struct bio		*read_bio;
+	int			read_disk;
 	/*
 	 * if the IO is in WRITE direction, then multiple bios are used:
 	 */
@@ -94,5 +94,5 @@
 
 /* bits for r1bio.state */
 #define	R1BIO_Uptodate	1
-#define	R1BIO_SyncPhase	2
+
 #endif
diff -u --recursive --new-file v2.5.1/linux/include/linux/reiserfs_fs.h linux/include/linux/reiserfs_fs.h
--- v2.5.1/linux/include/linux/reiserfs_fs.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/reiserfs_fs.h	Sat Dec 29 17:30:07 2001
@@ -15,10 +15,10 @@
 #include <linux/types.h>
 #ifdef __KERNEL__
 #include <linux/slab.h>
+#include <linux/interrupt.h>
 #include <linux/tqueue.h>
 #include <asm/unaligned.h>
 #include <linux/bitops.h>
-#include <asm/hardirq.h>
 #include <linux/proc_fs.h>
 #endif
 
@@ -1827,12 +1827,12 @@
 //void decrement_i_read_sync_counter (struct inode * p_s_inode);
 
 
-#define block_size(inode) ((inode)->i_sb->s_blocksize)
+#define i_block_size(inode) ((inode)->i_sb->s_blocksize)
 #define file_size(inode) ((inode)->i_size)
-#define tail_size(inode) (file_size (inode) & (block_size (inode) - 1))
+#define tail_size(inode) (file_size (inode) & (i_block_size (inode) - 1))
 
 #define tail_has_to_be_packed(inode) (!dont_have_tails ((inode)->i_sb) &&\
-!STORE_TAIL_IN_UNFM(file_size (inode), tail_size(inode), block_size (inode)))
+!STORE_TAIL_IN_UNFM(file_size (inode), tail_size(inode), i_block_size (inode)))
 
 /*
 int get_buffer_by_range (struct super_block * p_s_sb, struct key * p_s_range_begin, struct key * p_s_range_end, 
@@ -1989,10 +1989,9 @@
 
 
 /* buffer2.c */
-struct buffer_head * reiserfs_getblk (kdev_t n_dev, int n_block, int n_size);
+struct buffer_head * reiserfs_getblk (struct super_block *super, int n_block);
 void wait_buffer_until_released (const struct buffer_head * bh);
-struct buffer_head * reiserfs_bread (struct super_block *super, int n_block, 
-				     int n_size);
+struct buffer_head * reiserfs_bread (struct super_block *super, int n_block);
 
 /* fix_nodes.c */
 void * reiserfs_kmalloc (size_t size, int flags, struct super_block * s);
diff -u --recursive --new-file v2.5.1/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.5.1/linux/include/linux/sched.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/sched.h	Thu Jan  3 12:13:01 2002
@@ -41,6 +41,7 @@
 #define CLONE_VFORK	0x00004000	/* set if the parent wants the child to wake it up on mm_release */
 #define CLONE_PARENT	0x00008000	/* set if we want to have the same parent as the cloner */
 #define CLONE_THREAD	0x00010000	/* Same thread group? */
+#define CLONE_NEWNS	0x00020000	/* New namespace group? */
 
 #define CLONE_SIGNAL	(CLONE_SIGHAND | CLONE_THREAD)
 
@@ -149,6 +150,7 @@
 extern void update_process_times(int user);
 extern void update_one_process(struct task_struct *p, unsigned long user,
 			       unsigned long system, int cpu);
+extern void expire_task(struct task_struct *p);
 
 #define	MAX_SCHEDULE_TIMEOUT	LONG_MAX
 extern signed long FASTCALL(schedule_timeout(signed long timeout));
@@ -165,6 +167,7 @@
  */
 #define NR_OPEN_DEFAULT BITS_PER_LONG
 
+struct namespace;
 /*
  * Open file table structure
  */
@@ -299,7 +302,7 @@
  * all fields in a single cacheline that are needed for
  * the goodness() loop in schedule().
  */
-	long counter;
+	unsigned long dyn_prio;
 	long nice;
 	unsigned long policy;
 	struct mm_struct *mm;
@@ -318,7 +321,9 @@
 	 * that's just fine.)
 	 */
 	struct list_head run_list;
-	unsigned long sleep_time;
+	long time_slice;
+	/* recalculation loop checkpoint */
+	unsigned long rcl_last;
 
 	struct task_struct *next_task, *prev_task;
 	struct mm_struct *active_mm;
@@ -388,6 +393,8 @@
 	struct fs_struct *fs;
 /* open file information */
 	struct files_struct *files;
+/* namespace */
+	struct namespace *namespace;
 /* signal handlers */
 	spinlock_t sigmask_lock;	/* Protects signal and blocked */
 	struct signal_struct *sig;
@@ -425,6 +432,7 @@
 #define PF_MEMALLOC	0x00000800	/* Allocating memory */
 #define PF_MEMDIE	0x00001000	/* Killed for out-of-memory */
 #define PF_FREE_PAGES	0x00002000	/* per process page freeing */
+#define PF_NOIO		0x00004000	/* avoid generating further I/O */
 
 #define PF_USEDFPU	0x00100000	/* task used FPU this quantum (SMP) */
 
@@ -444,8 +452,9 @@
  */
 #define _STK_LIM	(8*1024*1024)
 
-#define DEF_COUNTER	(10*HZ/100)	/* 100 ms time slice */
-#define MAX_COUNTER	(20*HZ/100)
+#define MAX_DYNPRIO	40
+#define DEF_TSLICE	(6 * HZ / 100)
+#define MAX_TSLICE	(20 * HZ / 100)
 #define DEF_NICE	(0)
 
 
@@ -466,14 +475,16 @@
     addr_limit:		KERNEL_DS,					\
     exec_domain:	&default_exec_domain,				\
     lock_depth:		-1,						\
-    counter:		DEF_COUNTER,					\
+    dyn_prio:		0,					\
     nice:		DEF_NICE,					\
     policy:		SCHED_OTHER,					\
     mm:			NULL,						\
     active_mm:		&init_mm,					\
     cpus_runnable:	-1,						\
     cpus_allowed:	-1,						\
-    run_list:		LIST_HEAD_INIT(tsk.run_list),			\
+    run_list:		{ NULL, NULL },			\
+    rcl_last:		0,					\
+    time_slice:		DEF_TSLICE,					\
     next_task:		&tsk,						\
     prev_task:		&tsk,						\
     p_opptr:		&tsk,						\
@@ -874,7 +885,6 @@
 static inline void del_from_runqueue(struct task_struct * p)
 {
 	nr_running--;
-	p->sleep_time = jiffies;
 	list_del(&p->run_list);
 	p->run_list.next = NULL;
 }
diff -u --recursive --new-file v2.5.1/linux/include/linux/shm.h linux/include/linux/shm.h
--- v2.5.1/linux/include/linux/shm.h	Thu Nov 22 11:46:18 2001
+++ linux/include/linux/shm.h	Tue Jan  1 19:13:40 2002
@@ -80,7 +80,6 @@
 asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, unsigned long *addr);
 asmlinkage long sys_shmdt (char *shmaddr);
 asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf);
-extern void shm_unuse(swp_entry_t entry, struct page *page);
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.5.1/linux/include/linux/slab.h linux/include/linux/slab.h
--- v2.5.1/linux/include/linux/slab.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/slab.h	Tue Jan  1 19:13:38 2002
@@ -11,8 +11,8 @@
 
 typedef struct kmem_cache_s kmem_cache_t;
 
-#include	<linux/mm.h>
-#include	<linux/cache.h>
+#include	<linux/gfp.h>
+#include	<linux/types.h>
 
 /* flags for kmem_cache_alloc() */
 #define	SLAB_NOFS		GFP_NOFS
@@ -64,6 +64,7 @@
 extern int FASTCALL(kmem_cache_reap(int));
 extern int slabinfo_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data);
+struct file;
 extern int slabinfo_write_proc(struct file *file, const char *buffer,
 			   unsigned long count, void *data);
 
diff -u --recursive --new-file v2.5.1/linux/include/linux/sunrpc/clnt.h linux/include/linux/sunrpc/clnt.h
--- v2.5.1/linux/include/linux/sunrpc/clnt.h	Thu Nov 22 11:47:20 2001
+++ linux/include/linux/sunrpc/clnt.h	Tue Jan  1 19:14:33 2002
@@ -15,6 +15,7 @@
 #include <linux/sunrpc/auth.h>
 #include <linux/sunrpc/stats.h>
 #include <linux/sunrpc/xdr.h>
+#include <asm/signal.h>
 
 /*
  * This defines an RPC port mapping
diff -u --recursive --new-file v2.5.1/linux/include/linux/threads.h linux/include/linux/threads.h
--- v2.5.1/linux/include/linux/threads.h	Thu Nov 22 11:46:18 2001
+++ linux/include/linux/threads.h	Tue Jan  1 19:13:36 2002
@@ -5,7 +5,7 @@
 
 /*
  * The default limit for the nr of threads is now in
- * /proc/sys/kernel/max-threads.
+ * /proc/sys/kernel/threads-max.
  */
  
 #ifdef CONFIG_SMP
diff -u --recursive --new-file v2.5.1/linux/include/linux/usb.h linux/include/linux/usb.h
--- v2.5.1/linux/include/linux/usb.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/usb.h	Tue Jan  1 19:17:12 2002
@@ -521,7 +521,7 @@
 
 	struct semaphore serialize;
 
-	/* ioctl -- userspace apps can talk to drivers through usbdevfs */
+	/* ioctl -- userspace apps can talk to drivers through usbfs */
 	int (*ioctl)(struct usb_device *dev, unsigned int code, void *buf);
 
 	/* support for "new-style" USB hotplugging */
@@ -567,7 +567,7 @@
 	unsigned int length;		/* expected length */
 	unsigned int actual_length;
 	unsigned int status;
-} iso_packet_descriptor_t, *piso_packet_descriptor_t;
+} iso_packet_descriptor_t;
 
 struct urb;
 
@@ -629,7 +629,7 @@
  *
  * This structure identifies USB transfer requests.  URBs may be allocated
  * in any way, although usb_alloc_urb() is often convenient.  Initialization
- * may be done using various FILL_*_URB() macros.  URBs are submitted
+ * may be done using various usb_fill_*_urb() functions.  URBs are submitted
  * using usb_submit_urb(), and pending requests may be canceled using
  * usb_unlink_urb().
  *
@@ -729,87 +729,7 @@
 	iso_packet_descriptor_t iso_frame_desc[0];	/* (in) ISO ONLY */
 };
 
-typedef struct urb urb_t, *purb_t;
-
-/**
- * FILL_CONTROL_URB - macro to help initialize a control urb
- * @URB: pointer to the urb to initialize.
- * @DEV: pointer to the struct usb_device for this urb.
- * @PIPE: the endpoint pipe
- * @SETUP_PACKET: pointer to the setup_packet buffer
- * @TRANSFER_BUFFER: pointer to the transfer buffer
- * @BUFFER_LENGTH: length of the transfer buffer
- * @COMPLETE: pointer to the usb_complete_t function
- * @CONTEXT: what to set the urb context to.
- *
- * Initializes a control urb with the proper information needed to submit
- * it to a device.  This macro is depreciated, the usb_fill_control_urb()
- * function should be used instead.
- */
-#define FILL_CONTROL_URB(URB,DEV,PIPE,SETUP_PACKET,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \
-    do {\
-	spin_lock_init(&(URB)->lock);\
-	(URB)->dev=DEV;\
-	(URB)->pipe=PIPE;\
-	(URB)->setup_packet=SETUP_PACKET;\
-	(URB)->transfer_buffer=TRANSFER_BUFFER;\
-	(URB)->transfer_buffer_length=BUFFER_LENGTH;\
-	(URB)->complete=COMPLETE;\
-	(URB)->context=CONTEXT;\
-    } while (0)
-
-/**
- * FILL_BULK_URB - macro to help initialize a bulk urb
- * @URB: pointer to the urb to initialize.
- * @DEV: pointer to the struct usb_device for this urb.
- * @PIPE: the endpoint pipe
- * @TRANSFER_BUFFER: pointer to the transfer buffer
- * @BUFFER_LENGTH: length of the transfer buffer
- * @COMPLETE: pointer to the usb_complete_t function
- * @CONTEXT: what to set the urb context to.
- *
- * Initializes a bulk urb with the proper information needed to submit it
- * to a device.  This macro is depreciated, the usb_fill_bulk_urb()
- * function should be used instead.
- */
-#define FILL_BULK_URB(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \
-    do {\
-	spin_lock_init(&(URB)->lock);\
-	(URB)->dev=DEV;\
-	(URB)->pipe=PIPE;\
-	(URB)->transfer_buffer=TRANSFER_BUFFER;\
-	(URB)->transfer_buffer_length=BUFFER_LENGTH;\
-	(URB)->complete=COMPLETE;\
-	(URB)->context=CONTEXT;\
-    } while (0)
-    
-/**
- * FILL_INT_URB - macro to help initialize a interrupt urb
- * @URB: pointer to the urb to initialize.
- * @DEV: pointer to the struct usb_device for this urb.
- * @PIPE: the endpoint pipe
- * @TRANSFER_BUFFER: pointer to the transfer buffer
- * @BUFFER_LENGTH: length of the transfer buffer
- * @COMPLETE: pointer to the usb_complete_t function
- * @CONTEXT: what to set the urb context to.
- * @INTERVAL: what to set the urb interval to.
- *
- * Initializes a interrupt urb with the proper information needed to submit
- * it to a device.  This macro is depreciated, the usb_fill_int_urb()
- * function should be used instead.
- */
-#define FILL_INT_URB(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT,INTERVAL) \
-    do {\
-	spin_lock_init(&(URB)->lock);\
-	(URB)->dev=DEV;\
-	(URB)->pipe=PIPE;\
-	(URB)->transfer_buffer=TRANSFER_BUFFER;\
-	(URB)->transfer_buffer_length=BUFFER_LENGTH;\
-	(URB)->complete=COMPLETE;\
-	(URB)->context=CONTEXT;\
-	(URB)->interval=INTERVAL;\
-	(URB)->start_frame=-1;\
-    } while (0)
+typedef struct urb urb_t;
 
 /**
  * usb_fill_control_urb - initializes a control urb
@@ -908,11 +828,22 @@
 	urb->interval = interval;
 	urb->start_frame = -1;
 }
-    
+
+/*
+ * old style macros to enable 2.4 and 2.2 drivers to build
+ * properly.  Please do not use these for new USB drivers.
+ */
+#define FILL_CONTROL_URB(URB,DEV,PIPE,SETUP_PACKET,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \
+    usb_fill_control_urb(URB,DEV,PIPE,SETUP_PACKET,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT)
+#define FILL_BULK_URB(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \
+    usb_fill_bulk_urb(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT)
+#define FILL_INT_URB(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT,INTERVAL) \
+    usb_fill_int_urb(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT,INTERVAL)
+
 extern struct urb *usb_alloc_urb(int iso_packets);
-extern void usb_free_urb(struct urb *purb);
-extern int usb_submit_urb(struct urb *purb);
-extern int usb_unlink_urb(struct urb *purb);
+extern void usb_free_urb(struct urb *urb);
+extern int usb_submit_urb(struct urb *urb);
+extern int usb_unlink_urb(struct urb *urb);
 
 /*-------------------------------------------------------------------*
  *                         SYNCHRONOUS CALL SUPPORT                  *
@@ -959,8 +890,8 @@
 	int (*allocate)(struct usb_device *);
 	int (*deallocate)(struct usb_device *);
 	int (*get_frame_number) (struct usb_device *usb_dev);
-	int (*submit_urb) (struct urb* purb);
-	int (*unlink_urb) (struct urb* purb);
+	int (*submit_urb) (struct urb *urb);
+	int (*unlink_urb) (struct urb *urb);
 };
 
 #define DEVNUM_ROUND_ROBIN	/***** OPTION *****/
@@ -989,8 +920,7 @@
 	int bandwidth_int_reqs;		/* number of Interrupt requesters */
 	int bandwidth_isoc_reqs;	/* number of Isoc. requesters */
 
-	/* usbdevfs inode list */
-	struct list_head inodes;
+	struct dentry *dentry;		/* usbfs dentry entry for the bus */
 
 	atomic_t refcnt;
 };
@@ -1028,6 +958,21 @@
 #define NS_TO_US(ns)	((ns + 500L) / 1000L)
 			/* convert & round nanoseconds to microseconds */
 
+/*
+ * As of USB 2.0, full/low speed devices are segregated into trees.
+ * One type grows from USB 1.1 host controllers (OHCI, UHCI etc).
+ * The other type grows from high speed hubs when they connect to
+ * full/low speed devices using "Transaction Translators" (TTs).
+ *
+ * TTs should only be known to the hub driver, and high speed bus
+ * drivers (only EHCI for now).  They affect periodic scheduling and
+ * sometimes control/bulk error recovery.
+ */
+struct usb_tt {
+	struct usb_device	*hub;	/* upstream highspeed hub */
+	int			multi;	/* true means one TT per port */
+};
+
 
 /* -------------------------------------------------------------------------- */
 
@@ -1056,7 +1001,8 @@
 #define USB_MAXCHILDREN		(16)
 
 struct usb_device {
-	int devnum;			/* Device number on USB bus */
+	int		devnum;		/* Address on USB bus */
+	char		devpath [16];	/* Use in messages: /port/port/... */
 
 	enum {
 		USB_SPEED_UNKNOWN = 0,			/* enumerating */
@@ -1064,8 +1010,8 @@
 		USB_SPEED_HIGH				/* usb 2.0 */
 	} speed;
 
-	struct usb_device *tt;		/* usb1.1 device on usb2.0 bus */
-	int ttport;			/* device/hub port on that tt */
+	struct usb_tt	*tt; 		/* low/full speed dev, highspeed hub */
+	int		ttport;		/* device port on that tt hub */
 
 	atomic_t refcnt;		/* Reference count */
 	struct semaphore serialize;
@@ -1090,9 +1036,8 @@
   
 	void *hcpriv;			/* Host Controller private data */
 	
-        /* usbdevfs inode list */
-	struct list_head inodes;
 	struct list_head filelist;
+	struct dentry *dentry;		/* usbfs dentry entry for the device */
 
 	/*
 	 * Child devices - these can be either new devices
@@ -1254,7 +1199,7 @@
 
 /*
  * bus and driver list
- * exported only for usbdevfs (not visible outside usbcore)
+ * exported only for usbfs (not visible outside usbcore)
  */
 
 extern struct list_head usb_driver_list;
@@ -1271,23 +1216,25 @@
  * these are expected to be called from the USB core/hub thread
  * with the kernel lock held
  */
-extern void usbdevfs_add_bus(struct usb_bus *bus);
-extern void usbdevfs_remove_bus(struct usb_bus *bus);
-extern void usbdevfs_add_device(struct usb_device *dev);
-extern void usbdevfs_remove_device(struct usb_device *dev);
+extern void usbfs_add_bus(struct usb_bus *bus);
+extern void usbfs_remove_bus(struct usb_bus *bus);
+extern void usbfs_add_device(struct usb_device *dev);
+extern void usbfs_remove_device(struct usb_device *dev);
+extern void usbfs_update_special (void);
 
-extern int usbdevfs_init(void);
-extern void usbdevfs_cleanup(void);
+extern int usbfs_init(void);
+extern void usbfs_cleanup(void);
 
 #else /* CONFIG_USB_DEVICEFS */
 
-static inline void usbdevfs_add_bus(struct usb_bus *bus) {}
-static inline void usbdevfs_remove_bus(struct usb_bus *bus) {}
-static inline void usbdevfs_add_device(struct usb_device *dev) {}
-static inline void usbdevfs_remove_device(struct usb_device *dev) {}
+static inline void usbfs_add_bus(struct usb_bus *bus) {}
+static inline void usbfs_remove_bus(struct usb_bus *bus) {}
+static inline void usbfs_add_device(struct usb_device *dev) {}
+static inline void usbfs_remove_device(struct usb_device *dev) {}
+static inline void usbfs_update_special (void) {}
 
-static inline int usbdevfs_init(void) { return 0; }
-static inline void usbdevfs_cleanup(void) { }
+static inline int usbfs_init(void) { return 0; }
+static inline void usbfs_cleanup(void) { }
 
 #endif /* CONFIG_USB_DEVICEFS */
 
diff -u --recursive --new-file v2.5.1/linux/include/linux/usbdevice_fs.h linux/include/linux/usbdevice_fs.h
--- v2.5.1/linux/include/linux/usbdevice_fs.h	Thu Nov 22 11:49:52 2001
+++ linux/include/linux/usbdevice_fs.h	Tue Jan  1 19:17:25 2002
@@ -150,17 +150,6 @@
 #include <linux/list.h>
 #include <asm/semaphore.h>
 
-/*
- * inode number macros
- */
-#define ITYPE(x)   ((x)&(0xf<<28))
-#define ISPECIAL   (0<<28)
-#define IBUS       (1<<28)
-#define IDEVICE    (2<<28)
-#define IBUSNR(x)  (((x)>>8)&0xff)
-#define IDEVNR(x)  ((x)&0xff)
-
-#define IROOT      1
 
 struct dev_state {
 	struct list_head list;      /* state list */
diff -u --recursive --new-file v2.5.1/linux/include/linux/vt_kern.h linux/include/linux/vt_kern.h
--- v2.5.1/linux/include/linux/vt_kern.h	Thu Nov 22 11:47:07 2001
+++ linux/include/linux/vt_kern.h	Tue Jan  1 19:14:49 2002
@@ -9,6 +9,7 @@
 #include <linux/config.h>
 #include <linux/vt.h>
 #include <linux/kd.h>
+#include <linux/tty.h>
 
 /*
  * Presently, a lot of graphics programs do not restore the contents of
diff -u --recursive --new-file v2.5.1/linux/include/linux/wait.h linux/include/linux/wait.h
--- v2.5.1/linux/include/linux/wait.h	Thu Nov 22 11:46:19 2001
+++ linux/include/linux/wait.h	Tue Jan  1 19:13:37 2002
@@ -19,24 +19,11 @@
 #include <asm/page.h>
 #include <asm/processor.h>
 
-/*
- * Debug control.  Slow but useful.
- */
-#if defined(CONFIG_DEBUG_WAITQ)
-#define WAITQUEUE_DEBUG 1
-#else
-#define WAITQUEUE_DEBUG 0
-#endif
-
 struct __wait_queue {
 	unsigned int flags;
 #define WQ_FLAG_EXCLUSIVE	0x01
 	struct task_struct * task;
 	struct list_head task_list;
-#if WAITQUEUE_DEBUG
-	long __magic;
-	long __waker;
-#endif
 };
 typedef struct __wait_queue wait_queue_t;
 
@@ -77,129 +64,47 @@
 struct __wait_queue_head {
 	wq_lock_t lock;
 	struct list_head task_list;
-#if WAITQUEUE_DEBUG
-	long __magic;
-	long __creator;
-#endif
 };
 typedef struct __wait_queue_head wait_queue_head_t;
 
 
 /*
- * Debugging macros.  We eschew `do { } while (0)' because gcc can generate
- * spurious .aligns.
- */
-#if WAITQUEUE_DEBUG
-#define WQ_BUG()	BUG()
-#define CHECK_MAGIC(x)							\
-	do {									\
-		if ((x) != (long)&(x)) {					\
-			printk("bad magic %lx (should be %lx), ",		\
-				(long)x, (long)&(x));				\
-			WQ_BUG();						\
-		}								\
-	} while (0)
-#define CHECK_MAGIC_WQHEAD(x)							\
-	do {									\
-		if ((x)->__magic != (long)&((x)->__magic)) {			\
-			printk("bad magic %lx (should be %lx, creator %lx), ",	\
-			(x)->__magic, (long)&((x)->__magic), (x)->__creator);	\
-			WQ_BUG();						\
-		}								\
-	} while (0)
-#define WQ_CHECK_LIST_HEAD(list) 						\
-	do {									\
-		if (!(list)->next || !(list)->prev)				\
-			WQ_BUG();						\
-	} while(0)
-#define WQ_NOTE_WAKER(tsk)							\
-	do {									\
-		(tsk)->__waker = (long)__builtin_return_address(0);		\
-	} while (0)
-#else
-#define WQ_BUG()
-#define CHECK_MAGIC(x)
-#define CHECK_MAGIC_WQHEAD(x)
-#define WQ_CHECK_LIST_HEAD(list)
-#define WQ_NOTE_WAKER(tsk)
-#endif
-
-/*
  * Macros for declaration and initialisaton of the datatypes
  */
 
-#if WAITQUEUE_DEBUG
-# define __WAITQUEUE_DEBUG_INIT(name) (long)&(name).__magic, 0
-# define __WAITQUEUE_HEAD_DEBUG_INIT(name) (long)&(name).__magic, (long)&(name).__magic
-#else
-# define __WAITQUEUE_DEBUG_INIT(name)
-# define __WAITQUEUE_HEAD_DEBUG_INIT(name)
-#endif
-
 #define __WAITQUEUE_INITIALIZER(name, tsk) {				\
 	task:		tsk,						\
-	task_list:	{ NULL, NULL },					\
-			 __WAITQUEUE_DEBUG_INIT(name)}
+	task_list:	{ NULL, NULL } }
 
 #define DECLARE_WAITQUEUE(name, tsk)					\
 	wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)
 
 #define __WAIT_QUEUE_HEAD_INITIALIZER(name) {				\
 	lock:		WAITQUEUE_RW_LOCK_UNLOCKED,			\
-	task_list:	{ &(name).task_list, &(name).task_list },	\
-			__WAITQUEUE_HEAD_DEBUG_INIT(name)}
+	task_list:	{ &(name).task_list, &(name).task_list } }
 
 #define DECLARE_WAIT_QUEUE_HEAD(name) \
 	wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
 
 static inline void init_waitqueue_head(wait_queue_head_t *q)
 {
-#if WAITQUEUE_DEBUG
-	if (!q)
-		WQ_BUG();
-#endif
 	q->lock = WAITQUEUE_RW_LOCK_UNLOCKED;
 	INIT_LIST_HEAD(&q->task_list);
-#if WAITQUEUE_DEBUG
-	q->__magic = (long)&q->__magic;
-	q->__creator = (long)current_text_addr();
-#endif
 }
 
 static inline void init_waitqueue_entry(wait_queue_t *q, struct task_struct *p)
 {
-#if WAITQUEUE_DEBUG
-	if (!q || !p)
-		WQ_BUG();
-#endif
 	q->flags = 0;
 	q->task = p;
-#if WAITQUEUE_DEBUG
-	q->__magic = (long)&q->__magic;
-#endif
 }
 
 static inline int waitqueue_active(wait_queue_head_t *q)
 {
-#if WAITQUEUE_DEBUG
-	if (!q)
-		WQ_BUG();
-	CHECK_MAGIC_WQHEAD(q);
-#endif
-
 	return !list_empty(&q->task_list);
 }
 
 static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new)
 {
-#if WAITQUEUE_DEBUG
-	if (!head || !new)
-		WQ_BUG();
-	CHECK_MAGIC_WQHEAD(head);
-	CHECK_MAGIC(new->__magic);
-	if (!head->task_list.next || !head->task_list.prev)
-		WQ_BUG();
-#endif
 	list_add(&new->task_list, &head->task_list);
 }
 
@@ -209,25 +114,12 @@
 static inline void __add_wait_queue_tail(wait_queue_head_t *head,
 						wait_queue_t *new)
 {
-#if WAITQUEUE_DEBUG
-	if (!head || !new)
-		WQ_BUG();
-	CHECK_MAGIC_WQHEAD(head);
-	CHECK_MAGIC(new->__magic);
-	if (!head->task_list.next || !head->task_list.prev)
-		WQ_BUG();
-#endif
 	list_add_tail(&new->task_list, &head->task_list);
 }
 
 static inline void __remove_wait_queue(wait_queue_head_t *head,
 							wait_queue_t *old)
 {
-#if WAITQUEUE_DEBUG
-	if (!old)
-		WQ_BUG();
-	CHECK_MAGIC(old->__magic);
-#endif
 	list_del(&old->task_list);
 }
 
diff -u --recursive --new-file v2.5.1/linux/include/scsi/scsicam.h linux/include/scsi/scsicam.h
--- v2.5.1/linux/include/scsi/scsicam.h	Mon Feb 19 17:14:38 2001
+++ linux/include/scsi/scsicam.h	Tue Jan  1 11:51:57 2002
@@ -14,6 +14,7 @@
 #define SCSICAM_H
 #include <linux/kdev_t.h>
 extern int scsicam_bios_param (Disk *disk, kdev_t dev, int *ip);
-extern int scsi_partsize(struct buffer_head *bh, unsigned long capacity,
+extern int scsi_partsize(unsigned char *buf, unsigned long capacity,
            unsigned int  *cyls, unsigned int *hds, unsigned int *secs);
+extern unsigned char *scsi_bios_ptable(kdev_t dev);
 #endif /* def SCSICAM_H */
diff -u --recursive --new-file v2.5.1/linux/init/do_mounts.c linux/init/do_mounts.c
--- v2.5.1/linux/init/do_mounts.c	Tue Dec 18 14:56:40 2001
+++ linux/init/do_mounts.c	Tue Jan  1 11:23:07 2002
@@ -1,15 +1,15 @@
 #define __KERNEL_SYSCALLS__
 #include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/unistd.h>
-#include <linux/string.h>
 #include <linux/ctype.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/blk.h>
-#include <linux/tty.h>
 #include <linux/fd.h>
+#include <linux/tty.h>
+#include <linux/init.h>
 
 #include <linux/nfs_fs.h>
 #include <linux/nfs_fs_sb.h>
@@ -18,12 +18,9 @@
 #include <linux/ext2_fs.h>
 #include <linux/romfs_fs.h>
 
-#include <asm/uaccess.h>
-
 #define BUILD_CRAMDISK
 
 extern int get_filesystem_list(char * buf);
-extern void wait_for_keypress(void);
 
 asmlinkage long sys_mount(char *dev_name, char *dir_name, char *type,
 	 unsigned long flags, void *data);
@@ -38,12 +35,21 @@
 
 #ifdef CONFIG_BLK_DEV_INITRD
 unsigned int real_root_dev;	/* do_proc_dointvec cannot handle kdev_t */
-#endif
-#ifdef CONFIG_BLK_DEV_RAM
-extern int rd_doload;
+static int __initdata mount_initrd = 1;
+
+static int __init no_initrd(char *str)
+{
+	mount_initrd = 0;
+	return 1;
+}
+
+__setup("noinitrd", no_initrd);
 #else
-static int rd_doload = 0;
+static int __initdata mount_initrd = 0;
 #endif
+
+int __initdata rd_doload;	/* 1 = load RAM disk, 0 = don't load */
+
 int root_mountflags = MS_RDONLY | MS_VERBOSE;
 static char root_device_name[64];
 
@@ -52,6 +58,13 @@
 
 static int do_devfs = 0;
 
+static int __init load_ramdisk(char *str)
+{
+	rd_doload = simple_strtol(str,NULL,0) & 3;
+	return 1;
+}
+__setup("load_ramdisk=", load_ramdisk);
+
 static int __init readonly(char *str)
 {
 	if (*str)
@@ -341,8 +354,8 @@
 	if (!do_devfs)
 		return sys_mknod(name, S_IFBLK|0600, kdev_t_to_nr(dev));
 
-	handle = devfs_find_handle(NULL, dev ? NULL : devfs_name,
-				MAJOR(dev), MINOR(dev), DEVFS_SPECIAL_BLK, 1);
+	handle = devfs_find_handle(NULL, kdev_none(dev) ? devfs_name : NULL,
+				major(dev), minor(dev), DEVFS_SPECIAL_BLK, 1);
 	if (!handle)
 		return -1;
 	n = devfs_generate_path(handle, path + 5, sizeof (path) - 5);
@@ -353,8 +366,9 @@
 
 static void __init change_floppy(char *fmt, ...)
 {
-	extern void wait_for_keypress(void);
+	struct termios termios;
 	char buf[80];
+	char c;
 	int fd;
 	va_list args;
 	va_start(args, fmt);
@@ -366,11 +380,38 @@
 		close(fd);
 	}
 	printk(KERN_NOTICE "VFS: Insert %s and press ENTER\n", buf);
-	wait_for_keypress();
+	fd = open("/dev/console", O_RDWR, 0);
+	if (fd >= 0) {
+		sys_ioctl(fd, TCGETS, (long)&termios);
+		termios.c_lflag &= ~ICANON;
+		sys_ioctl(fd, TCSETSF, (long)&termios);
+		read(fd, &c, 1);
+		termios.c_lflag |= ICANON;
+		sys_ioctl(fd, TCSETSF, (long)&termios);
+		close(fd);
+	}
 }
 
 #ifdef CONFIG_BLK_DEV_RAM
 
+int __initdata rd_prompt = 1;	/* 1 = prompt for RAM disk, 0 = don't prompt */
+
+static int __init prompt_ramdisk(char *str)
+{
+	rd_prompt = simple_strtol(str,NULL,0) & 1;
+	return 1;
+}
+__setup("prompt_ramdisk=", prompt_ramdisk);
+
+int __initdata rd_image_start;		/* starting block # of image */
+
+static int __init ramdisk_start_setup(char *str)
+{
+	rd_image_start = simple_strtol(str,NULL,0);
+	return 1;
+}
+__setup("ramdisk_start=", ramdisk_start_setup);
+
 static int __init crd_load(int in_fd, int out_fd);
 
 /*
@@ -588,7 +629,6 @@
 static int __init rd_load_disk(int n)
 {
 #ifdef CONFIG_BLK_DEV_RAM
-	extern int rd_prompt;
 	if (rd_prompt)
 		change_floppy("root floppy disk to be loaded into RAM disk");
 	create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, n), NULL);
@@ -596,6 +636,63 @@
 	return rd_load_image("/dev/root");
 }
 
+#ifdef CONFIG_DEVFS_FS
+
+static void __init convert_name(char *prefix, char *name, char *p, int part)
+{
+	int host, bus, target, lun;
+	char dest[64];
+	char src[64];
+	char *base = p - 1;
+
+	/*  Decode "c#b#t#u#"  */
+	if (*p++ != 'c')
+		return;
+	host = simple_strtol(p, &p, 10);
+	if (*p++ != 'b')
+		return;
+	bus = simple_strtol(p, &p, 10);
+	if (*p++ != 't')
+		return;
+	target = simple_strtol(p, &p, 10);
+	if (*p++ != 'u')
+		return;
+	lun = simple_strtol(p, &p, 10);
+	if (!part)
+		sprintf(dest, "%s/host%d/bus%d/target%d/lun%d",
+				prefix, host, bus, target, lun);
+	else if (*p++ == 'p')
+		sprintf(dest, "%s/host%d/bus%d/target%d/lun%d/part%s",
+				prefix, host, bus, target, lun, p);
+	else
+		sprintf(dest, "%s/host%d/bus%d/target%d/lun%d/disc",
+				prefix, host, bus, target, lun);
+	*base = '\0';
+	sprintf(src, "/dev/%s", name);
+	sys_mkdir(src, 0755);
+	*base = '/';
+	sprintf(src, "/dev/%s", name);
+	sys_symlink(dest, src);
+}
+
+static void __init devfs_make_root(char *name)
+{
+
+	if (!strncmp(name, "sd/", 3))
+		convert_name("../scsi", name, name+3, 1);
+	else if (!strncmp(name, "sr/", 3))
+		convert_name("../scsi", name, name+3, 0);
+	else if (!strncmp(name, "ide/hd/", 7))
+		convert_name("..", name, name + 7, 1);
+	else if (!strncmp(name, "ide/cd/", 7))
+		convert_name("..", name, name + 7, 0);
+}
+#else
+static void __init devfs_make_root(char *name)
+{
+}
+#endif
+
 static void __init mount_root(void)
 {
 #ifdef CONFIG_ROOT_NFS
@@ -613,11 +710,11 @@
 	devfs_make_root(root_device_name);
 	create_dev("/dev/root", ROOT_DEV, root_device_name);
 #ifdef CONFIG_BLK_DEV_FD
-	if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
+	if (major(ROOT_DEV) == FLOPPY_MAJOR) {
 		/* rd_doload is 2 for a dual initrd/ramload setup */
 		if (rd_doload==2) {
 			if (rd_load_disk(1)) {
-				ROOT_DEV = MKDEV(RAMDISK_MAJOR, 1);
+				ROOT_DEV = mk_kdev(RAMDISK_MAJOR, 1);
 				create_dev("/dev/root", ROOT_DEV, NULL);
 			}
 		} else
@@ -715,30 +812,28 @@
  */
 void prepare_namespace(void)
 {
-	int do_initrd = 0;
-	int is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
+	int is_floppy = major(ROOT_DEV) == FLOPPY_MAJOR;
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (!initrd_start)
 		mount_initrd = 0;
-	if (mount_initrd)
-		do_initrd = 1;
 	real_root_dev = ROOT_DEV;
 #endif
 	sys_mkdir("/dev", 0700);
 	sys_mkdir("/root", 0700);
+	sys_mknod("/dev/console", S_IFCHR|0600, MKDEV(TTYAUX_MAJOR, 1));
 #ifdef CONFIG_DEVFS_FS
 	sys_mount("devfs", "/dev", "devfs", 0, NULL);
 	do_devfs = 1;
 #endif
 
 	create_dev("/dev/root", ROOT_DEV, NULL);
-	if (do_initrd) {
-		if (initrd_load() && ROOT_DEV != MKDEV(RAMDISK_MAJOR, 0)) {
+	if (mount_initrd) {
+		if (initrd_load() && kdev_same(ROOT_DEV, mk_kdev(RAMDISK_MAJOR, 0))) {
 			handle_initrd();
 			goto out;
 		}
 	} else if (is_floppy && rd_doload && rd_load_disk(0))
-		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+		ROOT_DEV = mk_kdev(RAMDISK_MAJOR, 0);
 	mount_root();
 out:
 	sys_umount("/dev", 0);
diff -u --recursive --new-file v2.5.1/linux/ipc/shm.c linux/ipc/shm.c
--- v2.5.1/linux/ipc/shm.c	Tue Dec 18 14:56:40 2001
+++ linux/ipc/shm.c	Sat Dec 29 17:30:07 2001
@@ -17,6 +17,7 @@
 
 #include <linux/config.h>
 #include <linux/slab.h>
+#include <linux/mm.h>
 #include <linux/shm.h>
 #include <linux/init.h>
 #include <linux/file.h>
diff -u --recursive --new-file v2.5.1/linux/kernel/acct.c linux/kernel/acct.c
--- v2.5.1/linux/kernel/acct.c	Mon Mar 19 12:35:08 2001
+++ linux/kernel/acct.c	Thu Dec 27 08:17:43 2001
@@ -213,10 +213,10 @@
 	goto out;
 }
 
-void acct_auto_close(kdev_t dev)
+void acct_auto_close(struct super_block *sb)
 {
 	lock_kernel();
-	if (acct_file && acct_file->f_dentry->d_inode->i_dev == dev)
+	if (acct_file && acct_file->f_dentry->d_inode->i_sb == sb)
 		sys_acct(NULL);
 	unlock_kernel();
 }
diff -u --recursive --new-file v2.5.1/linux/kernel/device.c linux/kernel/device.c
--- v2.5.1/linux/kernel/device.c	Tue Dec 18 14:56:40 2001
+++ linux/kernel/device.c	Thu Jan  3 13:41:54 2002
@@ -732,15 +732,10 @@
 
 	error = -EINVAL;
 
-	if (!num_args) {
-		printk("have no arguments\n");
+	if (!num_args)
 		goto done;
-	}
 
 	if (!strnicmp(str_command,"suspend",7)) {
-
-		printk("%s: we know it's a suspend action\n",__FUNCTION__);
-
 		if (num_args != 3)
 			goto done;
 		if (!strnicmp(str_stage,"notify",6))
@@ -775,8 +770,7 @@
 			error = dev->driver->resume(dev,int_stage);
 		else
 			error = 0;
-	} else
-		printk("%s: couldn't find any thing to do\n",__FUNCTION__);
+	}
  done:
 	put_device(dev);
 
diff -u --recursive --new-file v2.5.1/linux/kernel/exit.c linux/kernel/exit.c
--- v2.5.1/linux/kernel/exit.c	Tue Dec 18 14:56:41 2001
+++ linux/kernel/exit.c	Sat Dec 29 17:30:07 2001
@@ -5,6 +5,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/smp_lock.h>
@@ -12,6 +13,7 @@
 #include <linux/completion.h>
 #include <linux/personality.h>
 #include <linux/tty.h>
+#include <linux/namespace.h>
 #ifdef CONFIG_BSD_PROCESS_ACCT
 #include <linux/acct.h>
 #endif
@@ -62,9 +64,9 @@
 		 * timeslices, because any timeslice recovered here
 		 * was given away by the parent in the first place.)
 		 */
-		current->counter += p->counter;
-		if (current->counter >= MAX_COUNTER)
-			current->counter = MAX_COUNTER;
+		current->time_slice += p->time_slice;
+		if (current->time_slice > MAX_TSLICE)
+			current->time_slice = MAX_TSLICE;
 		p->pid = 0;
 		free_task_struct(p);
 	} else {
@@ -452,6 +454,7 @@
 	sem_exit();
 	__exit_files(tsk);
 	__exit_fs(tsk);
+	exit_namespace(tsk);
 	exit_sighand(tsk);
 	exit_thread();
 
diff -u --recursive --new-file v2.5.1/linux/kernel/fork.c linux/kernel/fork.c
--- v2.5.1/linux/kernel/fork.c	Tue Dec 18 14:56:41 2001
+++ linux/kernel/fork.c	Thu Dec 27 14:44:58 2001
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/completion.h>
+#include <linux/namespace.h>
 #include <linux/personality.h>
 
 #include <asm/pgtable.h>
@@ -566,6 +567,9 @@
 	struct task_struct *p;
 	struct completion vfork;
 
+	if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
+		return -EINVAL;
+
 	retval = -EPERM;
 
 	/* 
@@ -585,8 +589,10 @@
 	*p = *current;
 
 	retval = -EAGAIN;
-	if (atomic_read(&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur)
-		goto bad_fork_free;
+	if (atomic_read(&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur) {
+		if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE))
+			goto bad_fork_free;
+	}
 
 	atomic_inc(&p->user->__count);
 	atomic_inc(&p->user->processes);
@@ -661,9 +667,11 @@
 		goto bad_fork_cleanup_fs;
 	if (copy_mm(clone_flags, p))
 		goto bad_fork_cleanup_sighand;
+	if (copy_namespace(clone_flags, p))
+		goto bad_fork_cleanup_mm;
 	retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
 	if (retval)
-		goto bad_fork_cleanup_mm;
+		goto bad_fork_cleanup_namespace;
 	p->semundo = NULL;
 	
 	/* Our parent execution domain becomes current domain
@@ -682,9 +690,9 @@
 	 * more scheduling fairness. This is only important in the first
 	 * timeslice, on the long run the scheduling behaviour is unchanged.
 	 */
-	p->counter = (current->counter + 1) >> 1;
-	current->counter >>= 1;
-	if (!current->counter)
+	p->time_slice = (current->time_slice + 1) >> 1;
+	current->time_slice >>= 1;
+	if (!current->time_slice)
 		current->need_resched = 1;
 
 	/*
@@ -730,6 +738,8 @@
 fork_out:
 	return retval;
 
+bad_fork_cleanup_namespace:
+	exit_namespace(p);
 bad_fork_cleanup_mm:
 	exit_mm(p);
 bad_fork_cleanup_sighand:
diff -u --recursive --new-file v2.5.1/linux/kernel/kmod.c linux/kernel/kmod.c
--- v2.5.1/linux/kernel/kmod.c	Tue Jul 17 18:23:50 2001
+++ linux/kernel/kmod.c	Tue Dec 25 15:39:20 2001
@@ -24,6 +24,8 @@
 #include <linux/unistd.h>
 #include <linux/kmod.h>
 #include <linux/smp_lock.h>
+#include <linux/slab.h>
+#include <linux/namespace.h>
 #include <linux/completion.h>
 
 #include <asm/uaccess.h>
@@ -36,6 +38,7 @@
 	struct fs_struct *our_fs, *init_fs;
 	struct dentry *root, *pwd;
 	struct vfsmount *rootmnt, *pwdmnt;
+	struct namespace *our_ns, *init_ns;
 
 	/*
 	 * Make modprobe's fs context be a copy of init's.
@@ -55,6 +58,11 @@
 	 */
 
 	init_fs = init_task.fs;
+	init_ns = init_task.namespace;
+	get_namespace(init_ns);
+	our_ns = current->namespace;
+	current->namespace = init_ns;
+	put_namespace(our_ns);
 	read_lock(&init_fs->lock);
 	rootmnt = mntget(init_fs->rootmnt);
 	root = dget(init_fs->root);
diff -u --recursive --new-file v2.5.1/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.5.1/linux/kernel/ksyms.c	Tue Dec 18 14:56:41 2001
+++ linux/kernel/ksyms.c	Sat Dec 29 11:23:46 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)
@@ -116,11 +117,11 @@
 EXPORT_SYMBOL(find_vma);
 EXPORT_SYMBOL(get_unmapped_area);
 EXPORT_SYMBOL(init_mm);
+EXPORT_SYMBOL(create_bounce);
 #ifdef CONFIG_HIGHMEM
 EXPORT_SYMBOL(kmap_high);
 EXPORT_SYMBOL(kunmap_high);
 EXPORT_SYMBOL(highmem_start_page);
-EXPORT_SYMBOL(create_bounce);
 EXPORT_SYMBOL(kmap_prot);
 EXPORT_SYMBOL(kmap_pte);
 #endif
@@ -188,6 +189,8 @@
 EXPORT_SYMBOL(write_inode_now);
 EXPORT_SYMBOL(notify_change);
 EXPORT_SYMBOL(set_blocksize);
+EXPORT_SYMBOL(sb_set_blocksize);
+EXPORT_SYMBOL(sb_min_blocksize);
 EXPORT_SYMBOL(getblk);
 EXPORT_SYMBOL(cdget);
 EXPORT_SYMBOL(cdput);
@@ -305,6 +308,7 @@
 EXPORT_SYMBOL(ioctl_by_bdev);
 EXPORT_SYMBOL(grok_partitions);
 EXPORT_SYMBOL(register_disk);
+EXPORT_SYMBOL(read_dev_sector);
 EXPORT_SYMBOL(tq_disk);
 EXPORT_SYMBOL(init_buffer);
 EXPORT_SYMBOL(refile_buffer);
@@ -477,6 +481,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 -u --recursive --new-file v2.5.1/linux/kernel/pm.c linux/kernel/pm.c
--- v2.5.1/linux/kernel/pm.c	Fri Apr  6 10:51:19 2001
+++ linux/kernel/pm.c	Sat Dec 29 17:30:07 2001
@@ -20,6 +20,7 @@
 
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/pm.h>
 #include <linux/interrupt.h>
diff -u --recursive --new-file v2.5.1/linux/kernel/ptrace.c linux/kernel/ptrace.c
--- v2.5.1/linux/kernel/ptrace.c	Wed Nov 21 14:43:01 2001
+++ linux/kernel/ptrace.c	Sun Dec 30 10:51:45 2001
@@ -121,119 +121,17 @@
 }
 
 /*
- * Access another process' address space, one page at a time.
+ * Access another process' address space.
+ * Source/target buffer must be kernel space, 
+ * Do not walk the page table directly, use get_user_pages
  */
-static int access_one_page(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write)
-{
-	pgd_t * pgdir;
-	pmd_t * pgmiddle;
-	pte_t * pgtable;
-	char *maddr; 
-	struct page *page;
-
-repeat:
-	spin_lock(&mm->page_table_lock);
-	pgdir = pgd_offset(vma->vm_mm, addr);
-	if (pgd_none(*pgdir))
-		goto fault_in_page;
-	if (pgd_bad(*pgdir))
-		goto bad_pgd;
-	pgmiddle = pmd_offset(pgdir, addr);
-	if (pmd_none(*pgmiddle))
-		goto fault_in_page;
-	if (pmd_bad(*pgmiddle))
-		goto bad_pmd;
-	pgtable = pte_offset(pgmiddle, addr);
-	if (!pte_present(*pgtable))
-		goto fault_in_page;
-	if (write && (!pte_write(*pgtable) || !pte_dirty(*pgtable)))
-		goto fault_in_page;
-	page = pte_page(*pgtable);
-
-	/* ZERO_PAGE is special: reads from it are ok even though it's marked reserved */
-	if (page != ZERO_PAGE(addr) || write) {
-		if ((!VALID_PAGE(page)) || PageReserved(page)) {
-			spin_unlock(&mm->page_table_lock);
-			return 0;
-		}
-	}
-	get_page(page);
-	spin_unlock(&mm->page_table_lock);
-	flush_cache_page(vma, addr);
-
-	if (write) {
-		maddr = kmap(page);
-		memcpy(maddr + (addr & ~PAGE_MASK), buf, len);
-		flush_page_to_ram(page);
-		flush_icache_page(vma, page);
-		kunmap(page);
-	} else {
-		maddr = kmap(page);
-		memcpy(buf, maddr + (addr & ~PAGE_MASK), len);
-		flush_page_to_ram(page);
-		kunmap(page);
-	}
-	put_page(page);
-	return len;
-
-fault_in_page:
-	spin_unlock(&mm->page_table_lock);
-	/* -1: out of memory. 0 - unmapped page */
-	if (handle_mm_fault(mm, vma, addr, write) > 0)
-		goto repeat;
-	return 0;
-
-bad_pgd:
-	spin_unlock(&mm->page_table_lock);
-	pgd_ERROR(*pgdir);
-	return 0;
-
-bad_pmd:
-	spin_unlock(&mm->page_table_lock);
-	pmd_ERROR(*pgmiddle);
-	return 0;
-}
-
-static int access_mm(struct mm_struct *mm, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write)
-{
-	int copied = 0;
-
-	for (;;) {
-		unsigned long offset = addr & ~PAGE_MASK;
-		int this_len = PAGE_SIZE - offset;
-		int retval;
-
-		if (this_len > len)
-			this_len = len;
-		retval = access_one_page(mm, vma, addr, buf, this_len, write);
-		copied += retval;
-		if (retval != this_len)
-			break;
-
-		len -= retval;
-		if (!len)
-			break;
-
-		addr += retval;
-		buf += retval;
-
-		if (addr < vma->vm_end)
-			continue;	
-		if (!vma->vm_next)
-			break;
-		if (vma->vm_next->vm_start != vma->vm_end)
-			break;
-	
-		vma = vma->vm_next;
-	}
-	return copied;
-}
 
 int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
 {
-	int copied;
 	struct mm_struct *mm;
-	struct vm_area_struct * vma;
+	struct vm_area_struct *vma;
+	struct page *page;
+	void *old_buf = buf;
 
 	/* Worry about races with exit() */
 	task_lock(tsk);
@@ -245,14 +143,41 @@
 		return 0;
 
 	down_read(&mm->mmap_sem);
-	vma = find_extend_vma(mm, addr);
-	copied = 0;
-	if (vma)
-		copied = access_mm(mm, vma, addr, buf, len, write);
+	/* ignore errors, just check how much was sucessfully transfered */
+	while (len) {
+		int bytes, ret, offset;
+		void *maddr;
+
+		ret = get_user_pages(current, mm, addr, 1,
+				write, 1, &page, &vma);
+		if (ret <= 0)
+			break;
+
+		bytes = len;
+		offset = addr & (PAGE_SIZE-1);
+		if (bytes > PAGE_SIZE-offset)
+			bytes = PAGE_SIZE-offset;
 
+		flush_cache_page(vma, addr);
+
+		maddr = kmap(page);
+		if (write) {
+			memcpy(maddr + offset, buf, bytes);
+			flush_page_to_ram(page);
+			flush_icache_page(vma, page);
+		} else {
+			memcpy(buf, maddr + offset, bytes);
+			flush_page_to_ram(page);
+		}
+		kunmap(page);
+		put_page(page);
+		len -= bytes;
+		buf += bytes;
+	}
 	up_read(&mm->mmap_sem);
 	mmput(mm);
-	return copied;
+	
+	return buf - old_buf;
 }
 
 int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len)
diff -u --recursive --new-file v2.5.1/linux/kernel/sched.c linux/kernel/sched.c
--- v2.5.1/linux/kernel/sched.c	Wed Nov 21 16:25:48 2001
+++ linux/kernel/sched.c	Thu Jan  3 12:13:01 2002
@@ -51,25 +51,16 @@
  * NOTE! The unix "nice" value influences how long a process
  * gets. The nice value ranges from -20 to +19, where a -20
  * is a "high-priority" task, and a "+10" is a low-priority
- * task.
- *
- * We want the time-slice to be around 50ms or so, so this
- * calculation depends on the value of HZ.
+ * task. The default time slice for zero-nice tasks will be 37ms.
  */
-#if HZ < 200
-#define TICK_SCALE(x)	((x) >> 2)
-#elif HZ < 400
-#define TICK_SCALE(x)	((x) >> 1)
-#elif HZ < 800
-#define TICK_SCALE(x)	(x)
-#elif HZ < 1600
-#define TICK_SCALE(x)	((x) << 1)
-#else
-#define TICK_SCALE(x)	((x) << 2)
-#endif
+#define NICE_RANGE	40
+#define MIN_NICE_TSLICE	5000
+#define MAX_NICE_TSLICE	70000
+#define TASK_TIMESLICE(p)	((int) ts_table[19 - (p)->nice])
 
-#define NICE_TO_TICKS(nice)	(TICK_SCALE(20-(nice))+1)
+static unsigned char ts_table[NICE_RANGE];
 
+#define MM_AFFINITY_BONUS	1
 
 /*
  *	Init task must be ok at boot for the ix86 as we will check its signals
@@ -94,6 +85,8 @@
 
 static LIST_HEAD(runqueue_head);
 
+static unsigned long rcl_curr;
+
 /*
  * We align per-CPU scheduling data on cacheline boundaries,
  * to prevent cacheline ping-pong.
@@ -165,10 +158,11 @@
 		 * Don't do any other calculations if the time slice is
 		 * over..
 		 */
-		weight = p->counter;
-		if (!weight)
-			goto out;
-			
+		if (!p->time_slice)
+			return 0;
+
+		weight = p->dyn_prio + 1;
+
 #ifdef CONFIG_SMP
 		/* Give a largish advantage to the same processor...   */
 		/* (this is equivalent to penalizing other processors) */
@@ -178,7 +172,7 @@
 
 		/* .. and a slight advantage to the current MM */
 		if (p->mm == this_mm || !p->mm)
-			weight += 1;
+			weight += MM_AFFINITY_BONUS;
 		weight += 20 - p->nice;
 		goto out;
 	}
@@ -262,6 +256,21 @@
 		 * a problem.
 		 */
 		if (tsk == idle_task(cpu)) {
+#if defined(__i386__) && defined(CONFIG_SMP)
+                        /*
+			 * Check if two siblings are idle in the same
+			 * physical package. Use them if found.
+			 */
+			if (smp_num_siblings == 2) {
+				if (cpu_curr(cpu_sibling_map[cpu]) == 
+			            idle_task(cpu_sibling_map[cpu])) {
+					oldest_idle = last_schedule(cpu);
+					target_tsk = tsk;
+					break;
+				}
+				
+                        }
+#endif		
 			if (last_schedule(cpu) < oldest_idle) {
 				oldest_idle = last_schedule(cpu);
 				target_tsk = tsk;
@@ -309,6 +318,10 @@
  */
 static inline void add_to_runqueue(struct task_struct * p)
 {
+	p->dyn_prio += rcl_curr - p->rcl_last;
+	p->rcl_last = rcl_curr;
+	if (p->dyn_prio > MAX_DYNPRIO)
+		p->dyn_prio = MAX_DYNPRIO;
 	list_add(&p->run_list, &runqueue_head);
 	nr_running++;
 }
@@ -361,9 +374,7 @@
 
 static void process_timeout(unsigned long __data)
 {
-	struct task_struct * p = (struct task_struct *) __data;
-
-	wake_up_process(p);
+	wake_up_process((struct task_struct *)__data);
 }
 
 /**
@@ -521,6 +532,25 @@
 	__schedule_tail(prev);
 }
 
+void expire_task(struct task_struct *p)
+{
+	if (unlikely(!p->time_slice))
+		goto need_resched;
+
+	if (!--p->time_slice) {
+		if (p->dyn_prio) {
+			p->time_slice--;
+			p->dyn_prio--;
+		}
+		p->need_resched = 1;
+	} else
+		if (p->time_slice < -TASK_TIMESLICE(p)) {
+			p->time_slice = 0;
+need_resched:
+			p->need_resched = 1;
+		}
+}
+
 /*
  *  'schedule()' is the scheduler function. It's a very simple and nice
  * scheduler: it's not perfect, but certainly works for most things.
@@ -563,20 +593,20 @@
 
 	/* move an exhausted RR process to be last.. */
 	if (unlikely(prev->policy == SCHED_RR))
-		if (!prev->counter) {
-			prev->counter = NICE_TO_TICKS(prev->nice);
+		if (!prev->time_slice) {
+			prev->time_slice = TASK_TIMESLICE(prev);
 			move_last_runqueue(prev);
 		}
 
 	switch (prev->state) {
-		case TASK_INTERRUPTIBLE:
-			if (signal_pending(prev)) {
-				prev->state = TASK_RUNNING;
-				break;
-			}
-		default:
-			del_from_runqueue(prev);
-		case TASK_RUNNING:;
+	case TASK_INTERRUPTIBLE:
+		if (signal_pending(prev)) {
+			prev->state = TASK_RUNNING;
+			break;
+		}
+	default:
+		del_from_runqueue(prev);
+	case TASK_RUNNING:;
 	}
 	prev->need_resched = 0;
 
@@ -601,14 +631,12 @@
 
 	/* Do we need to re-calculate counters? */
 	if (unlikely(!c)) {
-		struct task_struct *p;
-
-		spin_unlock_irq(&runqueue_lock);
-		read_lock(&tasklist_lock);
-		for_each_task(p)
-			p->counter = (p->counter >> 1) + NICE_TO_TICKS(p->nice);
-		read_unlock(&tasklist_lock);
-		spin_lock_irq(&runqueue_lock);
+		rcl_curr++;
+		list_for_each(tmp, &runqueue_head) {
+			p = list_entry(tmp, struct task_struct, run_list);
+			p->time_slice = TASK_TIMESLICE(p);
+			p->rcl_last = rcl_curr;
+		}
 		goto repeat_schedule;
 	}
 
@@ -704,21 +732,17 @@
 	struct list_head *tmp;
 	struct task_struct *p;
 
-	CHECK_MAGIC_WQHEAD(q);
-	WQ_CHECK_LIST_HEAD(&q->task_list);
-	
 	list_for_each(tmp,&q->task_list) {
 		unsigned int state;
-                wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list);
+		wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list);
 
-		CHECK_MAGIC(curr->__magic);
 		p = curr->task;
 		state = p->state;
-		if (state & mode) {
-			WQ_NOTE_WAKER(curr);
-			if (try_to_wake_up(p, sync) && (curr->flags&WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
-				break;
-		}
+		if ((state & mode) &&
+				try_to_wake_up(p, sync) &&
+				((curr->flags & WQ_FLAG_EXCLUSIVE) &&
+					!--nr_exclusive))
+			break;
 	}
 }
 
@@ -876,11 +900,7 @@
 
 static inline struct task_struct *find_process_by_pid(pid_t pid)
 {
-	struct task_struct *tsk = current;
-
-	if (pid)
-		tsk = find_task_by_pid(pid);
-	return tsk;
+	return pid ? find_task_by_pid(pid) : current;
 }
 
 static int setscheduler(pid_t pid, int policy, 
@@ -1049,9 +1069,9 @@
 			current->policy |= SCHED_YIELD;
 		current->need_resched = 1;
 
-		spin_lock_irq(&runqueue_lock);
-		move_last_runqueue(current);
-		spin_unlock_irq(&runqueue_lock);
+		current->time_slice = 0;
+		if (++current->dyn_prio > MAX_DYNPRIO)
+			current->dyn_prio = MAX_DYNPRIO;
 	}
 	return 0;
 }
@@ -1100,7 +1120,7 @@
 	read_lock(&tasklist_lock);
 	p = find_process_by_pid(pid);
 	if (p)
-		jiffies_to_timespec(p->policy & SCHED_FIFO ? 0 : NICE_TO_TICKS(p->nice),
+		jiffies_to_timespec(p->policy & SCHED_FIFO ? 0 : TASK_TIMESLICE(p),
 				    &t);
 	read_unlock(&tasklist_lock);
 	if (p)
@@ -1216,35 +1236,33 @@
  */
 void reparent_to_init(void)
 {
-	struct task_struct *this_task = current;
-
 	write_lock_irq(&tasklist_lock);
 
 	/* Reparent to init */
-	REMOVE_LINKS(this_task);
-	this_task->p_pptr = child_reaper;
-	this_task->p_opptr = child_reaper;
-	SET_LINKS(this_task);
+	REMOVE_LINKS(current);
+	current->p_pptr = child_reaper;
+	current->p_opptr = child_reaper;
+	SET_LINKS(current);
 
 	/* Set the exit signal to SIGCHLD so we signal init on exit */
-	this_task->exit_signal = SIGCHLD;
+	current->exit_signal = SIGCHLD;
 
 	/* We also take the runqueue_lock while altering task fields
 	 * which affect scheduling decisions */
 	spin_lock(&runqueue_lock);
 
-	this_task->ptrace = 0;
-	this_task->nice = DEF_NICE;
-	this_task->policy = SCHED_OTHER;
+	current->ptrace = 0;
+	current->nice = DEF_NICE;
+	current->policy = SCHED_OTHER;
 	/* cpus_allowed? */
 	/* rt_priority? */
 	/* signals? */
-	this_task->cap_effective = CAP_INIT_EFF_SET;
-	this_task->cap_inheritable = CAP_INIT_INH_SET;
-	this_task->cap_permitted = CAP_FULL_SET;
-	this_task->keep_capabilities = 0;
-	memcpy(this_task->rlim, init_task.rlim, sizeof(*(this_task->rlim)));
-	this_task->user = INIT_USER;
+	current->cap_effective = CAP_INIT_EFF_SET;
+	current->cap_inheritable = CAP_INIT_INH_SET;
+	current->cap_permitted = CAP_FULL_SET;
+	current->keep_capabilities = 0;
+	memcpy(current->rlim, init_task.rlim, sizeof(*(current->rlim)));
+	current->user = INIT_USER;
 
 	spin_unlock(&runqueue_lock);
 	write_unlock_irq(&tasklist_lock);
@@ -1291,9 +1309,10 @@
 
 	if (current != &init_task && task_on_runqueue(current)) {
 		printk("UGH! (%d:%d) was on the runqueue, removing.\n",
-			smp_processor_id(), current->pid);
+			   smp_processor_id(), current->pid);
 		del_from_runqueue(current);
 	}
+	current->dyn_prio = 0;
 	sched_data->curr = current;
 	sched_data->last_schedule = get_cycles();
 	clear_bit(current->processor, &wait_init_idle);
@@ -1301,6 +1320,18 @@
 
 extern void init_timervecs (void);
 
+static void fill_tslice_map(void)
+{
+	int i;
+
+	for (i = 0; i < NICE_RANGE; i++) {
+		ts_table[i] = ((MIN_NICE_TSLICE +
+						((MAX_NICE_TSLICE -
+						  MIN_NICE_TSLICE) / (NICE_RANGE - 1)) * i) * HZ) / 1000000;
+		if (!ts_table[i]) ts_table[i] = 1;
+	}
+}
+
 void __init sched_init(void)
 {
 	/*
@@ -1314,6 +1345,8 @@
 
 	for(nr = 0; nr < PIDHASH_SZ; nr++)
 		pidhash[nr] = NULL;
+
+	fill_tslice_map();
 
 	init_timervecs();
 
diff -u --recursive --new-file v2.5.1/linux/kernel/signal.c linux/kernel/signal.c
--- v2.5.1/linux/kernel/signal.c	Tue Dec 18 14:56:41 2001
+++ linux/kernel/signal.c	Thu Dec 20 08:50:19 2001
@@ -649,10 +649,8 @@
 /*
  * kill_something_info() interprets pid in interesting ways just like kill(2).
  *
- * POSIX (2001) specifies "If pid is -1, sig shall be sent to all processes
- * (excluding an unspecified set of system processes) for which the process
- * has permission to send that signal."
- * So, probably the process should also signal itself.
+ * POSIX specifies that kill(-1,sig) is unspecified, but what we have
+ * is probably wrong.  Should make it like BSD or SYSV.
  */
 
 static int kill_something_info(int sig, struct siginfo *info, int pid)
@@ -665,7 +663,7 @@
 
 		read_lock(&tasklist_lock);
 		for_each_task(p) {
-			if (p->pid > 1) {
+			if (p->pid > 1 && p != current) {
 				int err = send_sig_info(sig, info, p);
 				++count;
 				if (err != -EPERM)
diff -u --recursive --new-file v2.5.1/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v2.5.1/linux/kernel/sysctl.c	Tue Dec 18 14:56:41 2001
+++ linux/kernel/sysctl.c	Sat Dec 29 17:30:07 2001
@@ -19,6 +19,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/sysctl.h>
 #include <linux/swapctl.h>
diff -u --recursive --new-file v2.5.1/linux/kernel/timer.c linux/kernel/timer.c
--- v2.5.1/linux/kernel/timer.c	Mon Oct  8 10:41:41 2001
+++ linux/kernel/timer.c	Thu Dec 27 08:21:28 2001
@@ -583,10 +583,7 @@
 
 	update_one_process(p, user_tick, system, cpu);
 	if (p->pid) {
-		if (--p->counter <= 0) {
-			p->counter = 0;
-			p->need_resched = 1;
-		}
+		expire_task(p);
 		if (p->nice > 0)
 			kstat.per_cpu_nice[cpu] += user_tick;
 		else
diff -u --recursive --new-file v2.5.1/linux/mm/Makefile linux/mm/Makefile
--- v2.5.1/linux/mm/Makefile	Tue Dec 18 14:56:41 2001
+++ linux/mm/Makefile	Mon Dec 17 10:49:31 2001
@@ -14,8 +14,6 @@
 obj-y	 := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \
 	    vmalloc.o slab.o bootmem.o swap.o vmscan.o page_io.o \
 	    page_alloc.o swap_state.o swapfile.o numa.o oom_kill.o \
-	    shmem.o mempool.o
-
-obj-$(CONFIG_HIGHMEM) += highmem.o
+	    shmem.o highmem.o mempool.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.5.1/linux/mm/filemap.c linux/mm/filemap.c
--- v2.5.1/linux/mm/filemap.c	Tue Dec 18 14:56:41 2001
+++ linux/mm/filemap.c	Tue Jan  1 11:59:57 2002
@@ -1132,9 +1132,9 @@
 
 static inline int get_max_readahead(struct inode * inode)
 {
-	if (!inode->i_dev || !max_readahead[MAJOR(inode->i_dev)])
+	if (kdev_none(inode->i_dev) || !max_readahead[major(inode->i_dev)])
 		return MAX_READAHEAD;
-	return max_readahead[MAJOR(inode->i_dev)][MINOR(inode->i_dev)];
+	return max_readahead[major(inode->i_dev)][minor(inode->i_dev)];
 }
 
 static void generic_file_readahead(int reada_ok,
diff -u --recursive --new-file v2.5.1/linux/mm/highmem.c linux/mm/highmem.c
--- v2.5.1/linux/mm/highmem.c	Tue Dec 18 14:56:41 2001
+++ linux/mm/highmem.c	Sun Dec 30 10:02:19 2001
@@ -19,6 +19,21 @@
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/mempool.h>
+#include <linux/blkdev.h>
+
+static mempool_t *page_pool, *isa_page_pool;
+
+static void *page_pool_alloc(int gfp_mask, void *data)
+{
+	int gfp = gfp_mask | (int) data;
+
+	return alloc_page(gfp);
+}
+
+static void page_pool_free(void *page, void *data)
+{
+	__free_page(page);
+}
 
 /*
  * Virtual_count is not a pure "count".
@@ -28,9 +43,10 @@
  *    since the last TLB flush - so we can't use it.
  *  n means that there are (n-1) current users of it.
  */
+#ifdef CONFIG_HIGHMEM
 static int pkmap_count[LAST_PKMAP];
 static unsigned int last_pkmap_nr;
-static spinlock_t kmap_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t kmap_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 pte_t * pkmap_page_table;
 
@@ -185,19 +201,6 @@
 }
 
 #define POOL_SIZE	64
-#define ISA_POOL_SIZE	16
-
-static mempool_t *page_pool, *isa_page_pool;
-
-static void *page_pool_alloc(int gfp_mask, void *data)
-{
-	return alloc_page(gfp_mask);
-}
-
-static void page_pool_free(void *page, void *data)
-{
-	__free_page(page);
-}
 
 static __init int init_emergency_pool(void)
 {
@@ -211,11 +214,37 @@
 	page_pool = mempool_create(POOL_SIZE, page_pool_alloc, page_pool_free, NULL);
 	if (!page_pool)
 		BUG();
-	printk("highmem bounce pool size: %d pages and bhs.\n", POOL_SIZE);
+	printk("highmem bounce pool size: %d pages\n", POOL_SIZE);
 
 	return 0;
 }
 
+__initcall(init_emergency_pool);
+
+/*
+ * highmem version, map in to vec
+ */
+static inline void bounce_copy_vec(struct bio_vec *to, unsigned char *vfrom)
+{
+	unsigned long flags;
+	unsigned char *vto;
+
+	local_irq_save(flags);
+	vto = kmap_atomic(to->bv_page, KM_BOUNCE_READ);
+	memcpy(vto + to->bv_offset, vfrom, to->bv_len);
+	kunmap_atomic(vto, KM_BOUNCE_READ);
+	local_irq_restore(flags);
+}
+
+#else /* CONFIG_HIGHMEM */
+
+#define bounce_copy_vec(to, vfrom)	\
+	memcpy(page_address((to)->bv_page) + (to)->bv_offset, vfrom, (to)->bv_len)
+
+#endif
+
+#define ISA_POOL_SIZE	16
+
 /*
  * gets called "every" time someone init's a queue with BLK_BOUNCE_ISA
  * as the max address, so check if the pool has already been created.
@@ -225,7 +254,7 @@
 	if (isa_page_pool)
 		return 0;
 
-	isa_page_pool = mempool_create(ISA_POOL_SIZE, page_pool_alloc, page_pool_free, NULL);
+	isa_page_pool = mempool_create(ISA_POOL_SIZE, page_pool_alloc, page_pool_free, (void *) __GFP_DMA);
 	if (!isa_page_pool)
 		BUG();
 
@@ -233,8 +262,6 @@
 	return 0;
 }
 
-__initcall(init_emergency_pool);
-
 /*
  * Simple bounce buffer support for highmem pages. Depending on the
  * queue gfp mask set, *to may or may not be a highmem page. kmap it
@@ -242,13 +269,12 @@
  */
 static inline void copy_to_high_bio_irq(struct bio *to, struct bio *from)
 {
-	unsigned char *vto, *vfrom;
-	unsigned long flags;
+	unsigned char *vfrom;
 	struct bio_vec *tovec, *fromvec;
 	int i;
 
 	__bio_for_each_segment(tovec, to, i, 0) {
-		fromvec = &from->bi_io_vec[i];
+		fromvec = from->bi_io_vec + i;
 
 		/*
 		 * not bounced
@@ -258,11 +284,7 @@
 
 		vfrom = page_address(fromvec->bv_page) + fromvec->bv_offset;
 
-		local_irq_save(flags);
-		vto = kmap_atomic(tovec->bv_page, KM_BOUNCE_READ);
-		memcpy(vto + tovec->bv_offset, vfrom, tovec->bv_len);
-		kunmap_atomic(vto, KM_BOUNCE_READ);
-		local_irq_restore(flags);
+		bounce_copy_vec(tovec, vfrom);
 	}
 }
 
@@ -281,7 +303,7 @@
 	 * free up bounce indirect pages used
 	 */
 	__bio_for_each_segment(bvec, bio, i, 0) {
-		org_vec = &bio_orig->bi_io_vec[i];
+		org_vec = bio_orig->bi_io_vec + i;
 		if (bvec->bv_page == org_vec->bv_page)
 			continue;
 
@@ -336,10 +358,25 @@
 
 	BUG_ON((*bio_orig)->bi_idx);
 
+	/*
+	 * for non-isa bounce case, just check if the bounce pfn is equal
+	 * to or bigger than the highest pfn in the system -- in that case,
+	 * don't waste time iterating over bio segments
+	 */
 	if (!(gfp & GFP_DMA)) {
+		if (pfn >= blk_max_pfn)
+			return;
+
+#ifndef CONFIG_HIGHMEM
+		/*
+		 * should not hit for non-highmem case
+		 */
+		BUG();
+#endif
 		bio_gfp = GFP_NOHIGHIO;
 		pool = page_pool;
 	} else {
+		BUG_ON(!isa_page_pool);
 		bio_gfp = GFP_NOIO;
 		pool = isa_page_pool;
 	}
@@ -359,7 +396,7 @@
 		if (!bio)
 			bio = bio_alloc(bio_gfp, (*bio_orig)->bi_vcnt);
 
-		to = &bio->bi_io_vec[i];
+		to = bio->bi_io_vec + i;
 
 		to->bv_page = mempool_alloc(pool, gfp);
 		to->bv_len = from->bv_len;
diff -u --recursive --new-file v2.5.1/linux/mm/memory.c linux/mm/memory.c
--- v2.5.1/linux/mm/memory.c	Tue Dec 18 14:56:41 2001
+++ linux/mm/memory.c	Sun Dec 30 10:51:45 2001
@@ -397,17 +397,16 @@
 	spin_unlock(&mm->page_table_lock);
 }
 
-
 /*
  * Do a quick page-table lookup for a single page. 
  */
-static struct page * follow_page(unsigned long address, int write) 
+static struct page * follow_page(struct mm_struct *mm, unsigned long address, int write) 
 {
 	pgd_t *pgd;
 	pmd_t *pmd;
 	pte_t *ptep, pte;
 
-	pgd = pgd_offset(current->mm, address);
+	pgd = pgd_offset(mm, address);
 	if (pgd_none(*pgd) || pgd_bad(*pgd))
 		goto out;
 
@@ -443,21 +442,74 @@
 	return page;
 }
 
+int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
+		int len, int write, int force, struct page **pages, struct vm_area_struct **vmas)
+{
+	int i = 0;
+
+	do {
+		struct vm_area_struct *	vma;
+
+		vma = find_extend_vma(mm, start);
+
+		if ( !vma ||
+		    (!force &&
+		     	((write && (!(vma->vm_flags & VM_WRITE))) ||
+		    	 (!write && (!(vma->vm_flags & VM_READ))) ) )) {
+			if (i) return i;
+			return -EFAULT;
+		}
+
+		spin_lock(&mm->page_table_lock);
+		do {
+			struct page *map;
+			while (!(map = follow_page(mm, start, write))) {
+				spin_unlock(&mm->page_table_lock);
+				switch (handle_mm_fault(mm, vma, start, write)) {
+				case 1:
+					tsk->min_flt++;
+					break;
+				case 2:
+					tsk->maj_flt++;
+					break;
+				case 0:
+					if (i) return i;
+					return -EFAULT;
+				default:
+					if (i) return i;
+					return -ENOMEM;
+				}
+				spin_lock(&mm->page_table_lock);
+			}
+			if (pages) {
+				pages[i] = get_page_map(map);
+				/* FIXME: call the correct function,
+				 * depending on the type of the found page
+				 */
+				if (pages[i])
+					page_cache_get(pages[i]);
+			}
+			if (vmas)
+				vmas[i] = vma;
+			i++;
+			start += PAGE_SIZE;
+			len--;
+		} while(len && start < vma->vm_end);
+		spin_unlock(&mm->page_table_lock);
+	} while(len);
+	return i;
+}
+
 /*
  * Force in an entire range of pages from the current process's user VA,
  * and pin them in physical memory.  
  */
-
 #define dprintk(x...)
+
 int map_user_kiobuf(int rw, struct kiobuf *iobuf, unsigned long va, size_t len)
 {
-	unsigned long		ptr, end;
-	int			err;
+	int pgcount, err;
 	struct mm_struct *	mm;
-	struct vm_area_struct *	vma = 0;
-	struct page *		map;
-	int			i;
-	int			datain = (rw == READ);
 	
 	/* Make sure the iobuf is not already mapped somewhere. */
 	if (iobuf->nr_pages)
@@ -466,79 +518,37 @@
 	mm = current->mm;
 	dprintk ("map_user_kiobuf: begin\n");
 	
-	ptr = va & PAGE_MASK;
-	end = (va + len + PAGE_SIZE - 1) & PAGE_MASK;
-	err = expand_kiobuf(iobuf, (end - ptr) >> PAGE_SHIFT);
+	pgcount = (va + len + PAGE_SIZE - 1)/PAGE_SIZE - va/PAGE_SIZE;
+	/* mapping 0 bytes is not permitted */
+	if (!pgcount) BUG();
+	err = expand_kiobuf(iobuf, pgcount);
 	if (err)
 		return err;
 
-	down_read(&mm->mmap_sem);
-
-	err = -EFAULT;
 	iobuf->locked = 0;
-	iobuf->offset = va & ~PAGE_MASK;
+	iobuf->offset = va & (PAGE_SIZE-1);
 	iobuf->length = len;
 	
-	i = 0;
-	
-	/* 
-	 * First of all, try to fault in all of the necessary pages
-	 */
-	while (ptr < end) {
-		if (!vma || ptr >= vma->vm_end) {
-			vma = find_vma(current->mm, ptr);
-			if (!vma) 
-				goto out_unlock;
-			if (vma->vm_start > ptr) {
-				if (!(vma->vm_flags & VM_GROWSDOWN))
-					goto out_unlock;
-				if (expand_stack(vma, ptr))
-					goto out_unlock;
-			}
-			if (((datain) && (!(vma->vm_flags & VM_WRITE))) ||
-					(!(vma->vm_flags & VM_READ))) {
-				err = -EACCES;
-				goto out_unlock;
-			}
-		}
-		spin_lock(&mm->page_table_lock);
-		while (!(map = follow_page(ptr, datain))) {
-			int ret;
-
-			spin_unlock(&mm->page_table_lock);
-			ret = handle_mm_fault(current->mm, vma, ptr, datain);
-			if (ret <= 0) {
-				if (!ret)
-					goto out_unlock;
-				else {
-					err = -ENOMEM;
-					goto out_unlock;
-				}
-			}
-			spin_lock(&mm->page_table_lock);
-		}			
-		map = get_page_map(map);
-		if (map) {
-			flush_dcache_page(map);
-			page_cache_get(map);
-		} else
-			printk (KERN_INFO "Mapped page missing [%d]\n", i);
-		spin_unlock(&mm->page_table_lock);
-		iobuf->maplist[i] = map;
-		iobuf->nr_pages = ++i;
-		
-		ptr += PAGE_SIZE;
-	}
-
+	/* Try to fault in all of the necessary pages */
+	down_read(&mm->mmap_sem);
+	/* rw==READ means read from disk, write into memory area */
+	err = get_user_pages(current, mm, va, pgcount,
+			(rw==READ), 0, iobuf->maplist, NULL);
 	up_read(&mm->mmap_sem);
+	if (err < 0) {
+		unmap_kiobuf(iobuf);
+		dprintk ("map_user_kiobuf: end %d\n", err);
+		return err;
+	}
+	iobuf->nr_pages = err;
+	while (pgcount--) {
+		/* FIXME: flush superflous for rw==READ,
+		 * probably wrong function for rw==WRITE
+		 */
+		flush_dcache_page(iobuf->maplist[pgcount]);
+	}
 	dprintk ("map_user_kiobuf: end OK\n");
 	return 0;
-
- out_unlock:
-	up_read(&mm->mmap_sem);
-	unmap_kiobuf(iobuf);
-	dprintk ("map_user_kiobuf: end %d\n", err);
-	return err;
 }
 
 /*
@@ -588,6 +598,9 @@
 		if (map) {
 			if (iobuf->locked)
 				UnlockPage(map);
+			/* FIXME: cache flush missing for rw==READ
+			 * FIXME: call the correct reference counting function
+			 */
 			page_cache_release(map);
 		}
 	}
@@ -1414,23 +1427,19 @@
 	return pte_offset(pmd, address);
 }
 
-/*
- * Simplistic page force-in..
- */
 int make_pages_present(unsigned long addr, unsigned long end)
 {
-	int write;
-	struct mm_struct *mm = current->mm;
+	int ret, len, write;
 	struct vm_area_struct * vma;
 
-	vma = find_vma(mm, addr);
+	vma = find_vma(current->mm, addr);
 	write = (vma->vm_flags & VM_WRITE) != 0;
 	if (addr >= end)
 		BUG();
-	do {
-		if (handle_mm_fault(mm, vma, addr, write) < 0)
-			return -1;
-		addr += PAGE_SIZE;
-	} while (addr < end);
-	return 0;
+	if (end > vma->vm_end)
+		BUG();
+	len = (end+PAGE_SIZE-1)/PAGE_SIZE-addr/PAGE_SIZE;
+	ret = get_user_pages(current, current->mm, addr,
+			len, write, 0, NULL, NULL);
+	return ret == len ? 0 : -1;
 }
diff -u --recursive --new-file v2.5.1/linux/mm/mempool.c linux/mm/mempool.c
--- v2.5.1/linux/mm/mempool.c	Tue Dec 18 14:56:41 2001
+++ linux/mm/mempool.c	Sat Dec 29 17:30:07 2001
@@ -8,6 +8,7 @@
  *  started by Ingo Molnar, Copyright (C) 2001
  */
 
+#include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/mempool.h>
diff -u --recursive --new-file v2.5.1/linux/mm/mprotect.c linux/mm/mprotect.c
--- v2.5.1/linux/mm/mprotect.c	Mon Sep 17 15:30:23 2001
+++ linux/mm/mprotect.c	Sat Dec 29 17:30:07 2001
@@ -3,6 +3,7 @@
  *
  *  (C) Copyright 1994 Linus Torvalds
  */
+#include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include <linux/shm.h>
diff -u --recursive --new-file v2.5.1/linux/mm/mremap.c linux/mm/mremap.c
--- v2.5.1/linux/mm/mremap.c	Thu Sep 20 20:31:26 2001
+++ linux/mm/mremap.c	Sat Dec 29 17:30:07 2001
@@ -4,6 +4,7 @@
  *	(C) Copyright 1996 Linus Torvalds
  */
 
+#include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include <linux/shm.h>
diff -u --recursive --new-file v2.5.1/linux/mm/oom_kill.c linux/mm/oom_kill.c
--- v2.5.1/linux/mm/oom_kill.c	Sat Nov  3 17:05:25 2001
+++ linux/mm/oom_kill.c	Thu Dec 27 08:21:28 2001
@@ -149,7 +149,8 @@
 	 * all the memory it needs. That way it should be able to
 	 * exit() and clear out its resources quickly...
 	 */
-	p->counter = 5 * HZ;
+	p->time_slice = 2 * MAX_TSLICE;
+	p->dyn_prio = MAX_DYNPRIO + 1;
 	p->flags |= PF_MEMALLOC | PF_MEMDIE;
 
 	/* This process has hardware access, be more careful. */
diff -u --recursive --new-file v2.5.1/linux/mm/page_io.c linux/mm/page_io.c
--- v2.5.1/linux/mm/page_io.c	Tue Dec 18 14:56:41 2001
+++ linux/mm/page_io.c	Mon Dec 31 18:19:44 2001
@@ -38,7 +38,7 @@
 	unsigned long offset;
 	sector_t zones[PAGE_SIZE/512];
 	int zones_used;
-	kdev_t dev = 0;
+	kdev_t dev = NODEV;
 	int block_size;
 	struct inode *swapf = 0;
 
@@ -49,7 +49,7 @@
 		kstat.pswpout++;
 
 	get_swaphandle_info(entry, &offset, &dev, &swapf);
-	if (dev) {
+	if (!kdev_none(dev)) {
 		zones[0] = offset;
 		zones_used = 1;
 		block_size = PAGE_SIZE;
diff -u --recursive --new-file v2.5.1/linux/mm/slab.c linux/mm/slab.c
--- v2.5.1/linux/mm/slab.c	Tue Dec 18 14:56:41 2001
+++ linux/mm/slab.c	Sat Dec 29 17:30:07 2001
@@ -70,6 +70,8 @@
 
 #include	<linux/config.h>
 #include	<linux/slab.h>
+#include	<linux/mm.h>
+#include	<linux/cache.h>
 #include	<linux/interrupt.h>
 #include	<linux/init.h>
 #include	<linux/compiler.h>
diff -u --recursive --new-file v2.5.1/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.5.1/linux/mm/swapfile.c	Tue Dec 18 14:56:41 2001
+++ linux/mm/swapfile.c	Tue Jan  1 12:02:10 2002
@@ -5,6 +5,7 @@
  *  Swap reorganised 29.12.95, Stephen Tweedie
  */
 
+#include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include <linux/kernel_stat.h>
@@ -773,7 +774,7 @@
 		swap_list_unlock();
 		goto out_dput;
 	}
-	if (p->swap_device)
+	if (!kdev_none(p->swap_device))
 		blkdev_put(p->swap_file->d_inode->i_bdev, BDEV_SWAP);
 	path_release(&nd);
 
@@ -783,7 +784,7 @@
 	nd.dentry = p->swap_file;
 	p->swap_vfsmnt = NULL;
 	p->swap_file = NULL;
-	p->swap_device = 0;
+	p->swap_device = NODEV;
 	p->max = 0;
 	swap_map = p->swap_map;
 	p->swap_map = NULL;
@@ -825,7 +826,7 @@
 				}
 			len += sprintf(buf + len, "%-39s %s\t%d\t%d\t%d\n",
 				       path,
-				       ptr->swap_device ? "partition" : "file\t",
+				       kdev_none(ptr->swap_device) ? "file\t" : "partition",
 				       ptr->pages << (PAGE_SHIFT - 10),
 				       usedswap << (PAGE_SHIFT - 10),
 				       ptr->prio);
@@ -841,7 +842,7 @@
 
 	for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
 		if (ptr->flags & SWP_USED)
-			if (ptr->swap_device == dev)
+			if (kdev_same(ptr->swap_device, dev))
 				return 1;
 	}
 	return 0;
@@ -887,7 +888,7 @@
 	p->flags = SWP_USED;
 	p->swap_file = NULL;
 	p->swap_vfsmnt = NULL;
-	p->swap_device = 0;
+	p->swap_device = NODEV;
 	p->swap_map = NULL;
 	p->lowest_bit = 0;
 	p->highest_bit = 0;
@@ -913,26 +914,29 @@
 	if (S_ISBLK(swap_inode->i_mode)) {
 		kdev_t dev = swap_inode->i_rdev;
 		struct block_device_operations *bdops;
+		devfs_handle_t de;
 
 		p->swap_device = dev;
 		set_blocksize(dev, PAGE_SIZE);
 		
 		bd_acquire(swap_inode);
 		bdev = swap_inode->i_bdev;
-		bdops = devfs_get_ops(devfs_get_handle_from_inode(swap_inode));
+		de = devfs_get_handle_from_inode(swap_inode);
+		bdops = devfs_get_ops(de);  /*  Increments module use count  */
 		if (bdops) bdev->bd_op = bdops;
 
 		error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_SWAP);
+		devfs_put_ops(de);/*Decrement module use count now we're safe*/
 		if (error)
 			goto bad_swap_2;
 		set_blocksize(dev, PAGE_SIZE);
 		error = -ENODEV;
-		if (!dev || (blk_size[MAJOR(dev)] &&
-		     !blk_size[MAJOR(dev)][MINOR(dev)]))
+		if (kdev_none(dev) || (blk_size[major(dev)] &&
+		     !blk_size[major(dev)][minor(dev)]))
 			goto bad_swap;
 		swapfilesize = 0;
-		if (blk_size[MAJOR(dev)])
-			swapfilesize = blk_size[MAJOR(dev)][MINOR(dev)]
+		if (blk_size[major(dev)])
+			swapfilesize = blk_size[major(dev)][minor(dev)]
 				>> (PAGE_SHIFT - 10);
 	} else if (S_ISREG(swap_inode->i_mode))
 		swapfilesize = swap_inode->i_size >> PAGE_SHIFT;
@@ -1088,7 +1092,7 @@
 	swap_map = p->swap_map;
 	nd.mnt = p->swap_vfsmnt;
 	nd.dentry = p->swap_file;
-	p->swap_device = 0;
+	p->swap_device = NODEV;
 	p->swap_file = NULL;
 	p->swap_vfsmnt = NULL;
 	p->swap_map = NULL;
@@ -1241,7 +1245,7 @@
 		return;
 	}
 
-	if (p->swap_device) {
+	if (!kdev_none(p->swap_device)) {
 		*dev = p->swap_device;
 	} else if (p->swap_file) {
 		*swapf = p->swap_file->d_inode;
diff -u --recursive --new-file v2.5.1/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.5.1/linux/mm/vmscan.c	Sat Nov 17 19:18:17 2001
+++ linux/mm/vmscan.c	Sat Dec 29 17:30:07 2001
@@ -11,6 +11,7 @@
  *  Multiqueue VM started 5.8.00, Rik van Riel.
  */
 
+#include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/kernel_stat.h>
 #include <linux/swap.h>
diff -u --recursive --new-file v2.5.1/linux/net/802/fddi.c linux/net/802/fddi.c
--- v2.5.1/linux/net/802/fddi.c	Tue Nov 28 21:53:45 2000
+++ linux/net/802/fddi.c	Sun Dec 30 10:31:51 2001
@@ -27,7 +27,6 @@
  */
  
 #include <linux/config.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.5.1/linux/net/802/hippi.c linux/net/802/hippi.c
--- v2.5.1/linux/net/802/hippi.c	Wed Jun 20 21:00:55 2001
+++ linux/net/802/hippi.c	Sun Dec 30 10:31:51 2001
@@ -36,7 +36,6 @@
 #include <net/sock.h>
 #include <asm/uaccess.h>
 #include <asm/checksum.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 
 /*
diff -u --recursive --new-file v2.5.1/linux/net/8021q/vlanproc.c linux/net/8021q/vlanproc.c
--- v2.5.1/linux/net/8021q/vlanproc.c	Tue Nov 13 09:19:41 2001
+++ linux/net/8021q/vlanproc.c	Sun Dec 30 10:31:51 2001
@@ -25,7 +25,6 @@
 #include <linux/mm.h>		/* verify_area(), etc. */
 #include <linux/string.h>	/* inline mem*, str* functions */
 #include <linux/init.h>		/* __initfunc et al. */
-#include <asm/segment.h>	/* kernel <-> user copy */
 #include <asm/byteorder.h>	/* htons(), etc. */
 #include <asm/uaccess.h>	/* copy_to_user */
 #include <asm/io.h>
diff -u --recursive --new-file v2.5.1/linux/net/atm/resources.c linux/net/atm/resources.c
--- v2.5.1/linux/net/atm/resources.c	Fri Nov  9 14:11:15 2001
+++ linux/net/atm/resources.c	Sun Dec 30 10:31:51 2001
@@ -11,7 +11,6 @@
 #include <linux/module.h>
 #include <linux/bitops.h>
 #include <net/sock.h>	 /* for struct sock */
-#include <asm/segment.h> /* for get_fs_long and put_fs_long */
 
 #include "common.h"
 #include "resources.h"
diff -u --recursive --new-file v2.5.1/linux/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c
--- v2.5.1/linux/net/decnet/af_decnet.c	Fri Nov  9 14:12:54 2001
+++ linux/net/decnet/af_decnet.c	Sun Dec 30 10:31:51 2001
@@ -112,7 +112,6 @@
 #include <linux/route.h>
 #include <linux/netfilter.h>
 #include <net/sock.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/ioctls.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.5.1/linux/net/decnet/dn_nsp_in.c linux/net/decnet/dn_nsp_in.c
--- v2.5.1/linux/net/decnet/dn_nsp_in.c	Fri Nov  9 14:12:54 2001
+++ linux/net/decnet/dn_nsp_in.c	Sun Dec 30 10:31:51 2001
@@ -59,7 +59,6 @@
 #include <linux/inet.h>
 #include <linux/route.h>
 #include <net/sock.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.5.1/linux/net/decnet/dn_nsp_out.c linux/net/decnet/dn_nsp_out.c
--- v2.5.1/linux/net/decnet/dn_nsp_out.c	Mon Jan 22 13:32:10 2001
+++ linux/net/decnet/dn_nsp_out.c	Sun Dec 30 10:31:51 2001
@@ -51,7 +51,6 @@
 #include <linux/inet.h>
 #include <linux/route.h>
 #include <net/sock.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.5.1/linux/net/irda/ircomm/ircomm_tty.c linux/net/irda/ircomm/ircomm_tty.c
--- v2.5.1/linux/net/irda/ircomm/ircomm_tty.c	Sun Sep 30 12:26:09 2001
+++ linux/net/irda/ircomm/ircomm_tty.c	Thu Jan  3 12:20:18 2002
@@ -38,7 +38,6 @@
 #include <linux/tty.h>
 #include <linux/interrupt.h>
 
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 
 #include <net/irda/irda.h>
@@ -387,13 +386,13 @@
 static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
 {
 	struct ircomm_tty_cb *self;
-	int line;
+	unsigned int line;
 	int ret;
 
 	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	MOD_INC_USE_COUNT;
-	line = MINOR(tty->device) - tty->driver.minor_start;
+	line = minor(tty->device) - tty->driver.minor_start;
 	if ((line < 0) || (line >= IRCOMM_TTY_PORTS)) {
 		MOD_DEC_USE_COUNT;
 		return -ENODEV;
diff -u --recursive --new-file v2.5.1/linux/net/irda/ircomm/ircomm_tty_ioctl.c linux/net/irda/ircomm/ircomm_tty_ioctl.c
--- v2.5.1/linux/net/irda/ircomm/ircomm_tty_ioctl.c	Wed Jul  4 11:50:38 2001
+++ linux/net/irda/ircomm/ircomm_tty_ioctl.c	Sun Dec 30 10:31:51 2001
@@ -35,7 +35,6 @@
 #include <linux/tty.h>
 #include <linux/serial.h>
 
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 
 #include <net/irda/irda.h>
diff -u --recursive --new-file v2.5.1/linux/net/irda/irda_device.c linux/net/irda/irda_device.c
--- v2.5.1/linux/net/irda/irda_device.c	Mon Nov 12 11:29:57 2001
+++ linux/net/irda/irda_device.c	Sun Dec 30 10:31:51 2001
@@ -44,7 +44,6 @@
 #include <linux/spinlock.h>
 
 #include <asm/ioctls.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <asm/dma.h>
 #include <asm/io.h>
diff -u --recursive --new-file v2.5.1/linux/net/irda/irsyms.c linux/net/irda/irsyms.c
--- v2.5.1/linux/net/irda/irsyms.c	Fri Nov  9 14:22:17 2001
+++ linux/net/irda/irsyms.c	Sun Dec 30 10:31:51 2001
@@ -31,7 +31,6 @@
 #include <linux/proc_fs.h>
 #include <linux/smp_lock.h>
 
-#include <asm/segment.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
diff -u --recursive --new-file v2.5.1/linux/net/irda/irsysctl.c linux/net/irda/irsysctl.c
--- v2.5.1/linux/net/irda/irsysctl.c	Tue Dec 18 14:56:41 2001
+++ linux/net/irda/irsysctl.c	Sun Dec 30 10:31:51 2001
@@ -27,7 +27,6 @@
 #include <linux/mm.h>
 #include <linux/ctype.h>
 #include <linux/sysctl.h>
-#include <asm/segment.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irias_object.h>
diff -u --recursive --new-file v2.5.1/linux/net/netlink/netlink_dev.c linux/net/netlink/netlink_dev.c
--- v2.5.1/linux/net/netlink/netlink_dev.c	Fri Nov  9 14:12:55 2001
+++ linux/net/netlink/netlink_dev.c	Tue Jan  1 18:08:56 2002
@@ -41,7 +41,7 @@
  
 static unsigned int netlink_poll(struct file *file, poll_table * wait)
 {
-	struct socket *sock = netlink_user[MINOR(file->f_dentry->d_inode->i_rdev)];
+	struct socket *sock = netlink_user[minor(file->f_dentry->d_inode->i_rdev)];
 
 	if (sock->ops->poll==NULL)
 		return 0;
@@ -56,7 +56,7 @@
 			     size_t count, loff_t *pos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	struct socket *sock = netlink_user[MINOR(inode->i_rdev)];
+	struct socket *sock = netlink_user[minor(inode->i_rdev)];
 	struct msghdr msg;
 	struct iovec iov;
 
@@ -80,7 +80,7 @@
 			    size_t count, loff_t *pos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	struct socket *sock = netlink_user[MINOR(inode->i_rdev)];
+	struct socket *sock = netlink_user[minor(inode->i_rdev)];
 	struct msghdr msg;
 	struct iovec iov;
 
@@ -105,7 +105,7 @@
 
 static int netlink_open(struct inode * inode, struct file * file)
 {
-	unsigned int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	struct socket *sock;
 	struct sockaddr_nl nladdr;
 	int err;
@@ -137,7 +137,7 @@
 
 static int netlink_release(struct inode * inode, struct file * file)
 {
-	unsigned int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	struct socket *sock;
 
 	sock = netlink_user[minor];
@@ -151,7 +151,7 @@
 static int netlink_ioctl(struct inode *inode, struct file *file,
 		    unsigned int cmd, unsigned long arg)
 {
-	unsigned int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	int retval = 0;
 
 	if (minor >= MAX_LINKS)
diff -u --recursive --new-file v2.5.1/linux/net/packet/af_packet.c linux/net/packet/af_packet.c
--- v2.5.1/linux/net/packet/af_packet.c	Tue Oct 30 15:08:12 2001
+++ linux/net/packet/af_packet.c	Sun Dec 30 16:59:00 2001
@@ -5,7 +5,7 @@
  *
  *		PACKET - implements raw packet sockets.
  *
- * Version:	$Id: af_packet.c,v 1.57 2001/10/30 03:38:37 davem Exp $
+ * Version:	$Id: af_packet.c,v 1.58 2001/11/28 21:02:10 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1902,3 +1902,4 @@
 
 module_init(packet_init);
 module_exit(packet_exit);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.1/linux/net/rose/af_rose.c linux/net/rose/af_rose.c
--- v2.5.1/linux/net/rose/af_rose.c	Mon Sep 10 07:58:35 2001
+++ linux/net/rose/af_rose.c	Sun Dec 30 10:31:51 2001
@@ -44,7 +44,6 @@
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/fcntl.h>
diff -u --recursive --new-file v2.5.1/linux/net/rose/rose_dev.c linux/net/rose/rose_dev.c
--- v2.5.1/linux/net/rose/rose_dev.c	Wed Jun 27 17:10:55 2001
+++ linux/net/rose/rose_dev.c	Sun Dec 30 10:31:51 2001
@@ -32,7 +32,6 @@
 #include <linux/if_ether.h>	/* For the statistics structure. */
 
 #include <asm/system.h>
-#include <asm/segment.h>
 #include <asm/io.h>
 
 #include <linux/inet.h>
diff -u --recursive --new-file v2.5.1/linux/net/rose/rose_in.c linux/net/rose/rose_in.c
--- v2.5.1/linux/net/rose/rose_in.c	Fri Dec 29 14:44:46 2000
+++ linux/net/rose/rose_in.c	Sun Dec 30 10:31:51 2001
@@ -38,7 +38,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <net/ip.h>			/* For ip_rcv */
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.5.1/linux/net/rose/rose_link.c linux/net/rose/rose_link.c
--- v2.5.1/linux/net/rose/rose_link.c	Fri Dec 29 14:44:46 2000
+++ linux/net/rose/rose_link.c	Sun Dec 30 10:31:51 2001
@@ -29,7 +29,6 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.5.1/linux/net/rose/rose_out.c linux/net/rose/rose_out.c
--- v2.5.1/linux/net/rose/rose_out.c	Fri Dec 29 14:44:46 2000
+++ linux/net/rose/rose_out.c	Sun Dec 30 10:31:51 2001
@@ -30,7 +30,6 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.5.1/linux/net/rose/rose_route.c linux/net/rose/rose_route.c
--- v2.5.1/linux/net/rose/rose_route.c	Fri Jun 29 19:38:26 2001
+++ linux/net/rose/rose_route.c	Sun Dec 30 10:31:51 2001
@@ -36,7 +36,6 @@
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/fcntl.h>
diff -u --recursive --new-file v2.5.1/linux/net/rose/rose_subr.c linux/net/rose/rose_subr.c
--- v2.5.1/linux/net/rose/rose_subr.c	Fri Jun 29 19:38:26 2001
+++ linux/net/rose/rose_subr.c	Sun Dec 30 10:31:51 2001
@@ -30,7 +30,6 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.5.1/linux/net/rose/rose_timer.c linux/net/rose/rose_timer.c
--- v2.5.1/linux/net/rose/rose_timer.c	Fri Dec 29 14:44:46 2000
+++ linux/net/rose/rose_timer.c	Sun Dec 30 10:31:51 2001
@@ -30,7 +30,6 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.5.1/linux/net/sunrpc/auth_null.c linux/net/sunrpc/auth_null.c
--- v2.5.1/linux/net/sunrpc/auth_null.c	Thu Aug 16 09:39:37 2001
+++ linux/net/sunrpc/auth_null.c	Sat Dec 29 17:30:07 2001
@@ -7,11 +7,11 @@
  */
 
 #include <linux/types.h>
-#include <linux/slab.h>
 #include <linux/socket.h>
 #include <linux/in.h>
 #include <linux/utsname.h>
 #include <linux/sunrpc/clnt.h>
+#include <linux/sched.h>
 
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY	RPCDBG_AUTH
diff -u --recursive --new-file v2.5.1/linux/net/sunrpc/auth_unix.c linux/net/sunrpc/auth_unix.c
--- v2.5.1/linux/net/sunrpc/auth_unix.c	Thu Aug 16 09:39:37 2001
+++ linux/net/sunrpc/auth_unix.c	Sat Dec 29 17:30:07 2001
@@ -7,7 +7,7 @@
  */
 
 #include <linux/types.h>
-#include <linux/slab.h>
+#include <linux/sched.h>
 #include <linux/socket.h>
 #include <linux/in.h>
 #include <linux/sunrpc/clnt.h>
diff -u --recursive --new-file v2.5.1/linux/net/x25/af_x25.c linux/net/x25/af_x25.c
--- v2.5.1/linux/net/x25/af_x25.c	Mon Sep 10 07:58:35 2001
+++ linux/net/x25/af_x25.c	Sun Dec 30 10:31:51 2001
@@ -46,7 +46,6 @@
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/fcntl.h>
diff -u --recursive --new-file v2.5.1/linux/net/x25/x25_dev.c linux/net/x25/x25_dev.c
--- v2.5.1/linux/net/x25/x25_dev.c	Mon Jan 22 13:32:10 2001
+++ linux/net/x25/x25_dev.c	Sun Dec 30 10:31:51 2001
@@ -33,7 +33,6 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/fcntl.h>
diff -u --recursive --new-file v2.5.1/linux/net/x25/x25_facilities.c linux/net/x25/x25_facilities.c
--- v2.5.1/linux/net/x25/x25_facilities.c	Wed Jan 24 15:28:36 2001
+++ linux/net/x25/x25_facilities.c	Sun Dec 30 10:31:51 2001
@@ -32,7 +32,6 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.5.1/linux/net/x25/x25_in.c linux/net/x25/x25_in.c
--- v2.5.1/linux/net/x25/x25_in.c	Wed Jan 24 15:28:36 2001
+++ linux/net/x25/x25_in.c	Sun Dec 30 10:31:51 2001
@@ -37,7 +37,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <net/ip.h>			/* For ip_rcv */
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.5.1/linux/net/x25/x25_link.c linux/net/x25/x25_link.c
--- v2.5.1/linux/net/x25/x25_link.c	Fri Jun 29 19:38:26 2001
+++ linux/net/x25/x25_link.c	Sun Dec 30 10:31:51 2001
@@ -34,7 +34,6 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/fcntl.h>
diff -u --recursive --new-file v2.5.1/linux/net/x25/x25_out.c linux/net/x25/x25_out.c
--- v2.5.1/linux/net/x25/x25_out.c	Thu Apr 12 12:11:39 2001
+++ linux/net/x25/x25_out.c	Sun Dec 30 10:31:51 2001
@@ -35,7 +35,6 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.5.1/linux/net/x25/x25_route.c linux/net/x25/x25_route.c
--- v2.5.1/linux/net/x25/x25_route.c	Mon Jan 22 13:32:10 2001
+++ linux/net/x25/x25_route.c	Sun Dec 30 10:31:51 2001
@@ -33,7 +33,6 @@
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/fcntl.h>
diff -u --recursive --new-file v2.5.1/linux/net/x25/x25_subr.c linux/net/x25/x25_subr.c
--- v2.5.1/linux/net/x25/x25_subr.c	Fri Jun 29 19:38:26 2001
+++ linux/net/x25/x25_subr.c	Sun Dec 30 10:31:51 2001
@@ -34,7 +34,6 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.5.1/linux/net/x25/x25_timer.c linux/net/x25/x25_timer.c
--- v2.5.1/linux/net/x25/x25_timer.c	Wed Jan 24 15:28:36 2001
+++ linux/net/x25/x25_timer.c	Sun Dec 30 10:31:51 2001
@@ -32,7 +32,6 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
