-mm1
--- diff/CREDITS	2004-02-18 08:54:06.000000000 +0000
+++ source/CREDITS	2004-03-09 11:51:47.000000000 +0000
@@ -289,6 +289,15 @@ S: Via Delle Palme, 9
 S: Terni 05100
 S: Italy
 
+N: Krzysztof Benedyczak
+E: golbi@mat.uni.torun.pl
+W: http://www.mat.uni.torun.pl/~golbi
+D: POSIX message queues fs (with M. Wronski)
+S: ul. Podmiejska 52
+S: Radunica
+S: 83-000 Pruszcz Gdanski
+S: Poland
+
 N: Randolph Bentson
 E: bentson@grieg.seaslug.org
 W: http://www.aa.net/~bentson/
@@ -975,8 +984,7 @@ N: Ben Fennema
 E: bfennema@falcon.csc.calpoly.edu
 W: http://www.csc.calpoly.edu/~bfennema
 D: UDF filesystem
-S: 21760 Irma Lyle Drive
-S: Los Gatos, CA 95033-8942
+S: (ask for current address)
 S: USA
 
 N: Jürgen Fischer
@@ -3489,6 +3497,14 @@ S: 12725 SW Millikan Way, Suite 400
 S: Beaverton, OR 97005
 S: USA
 
+N: Michal Wronski
+E: wrona@mat.uni.torun.pl
+W: http://www.mat.uni.torun.pl/~wrona
+D: POSIX message queues fs (with K. Benedyczak)
+S: ul. Teczowa 23/12
+S: 80-680 Gdansk-Sobieszewo
+S: Poland
+
 N: Frank Xia
 E: qx@math.columbia.edu
 D: Xiafs filesystem [defunct]
--- diff/Documentation/DMA-mapping.txt	2003-08-26 10:00:51.000000000 +0100
+++ source/Documentation/DMA-mapping.txt	2004-03-09 11:51:47.000000000 +0000
@@ -283,7 +283,7 @@ There are two types of DMA mappings:
              in order to get correct behavior on all platforms.
 
 - Streaming DMA mappings which are usually mapped for one DMA transfer,
-  unmapped right after it (unless you use pci_dma_sync below) and for which
+  unmapped right after it (unless you use pci_dma_sync_* below) and for which
   hardware can optimize for sequential accesses.
 
   This of "streaming" as "asynchronous" or "outside the coherency
@@ -543,14 +543,30 @@ same bus address space) and you could re
 all bus addresses.
 
 If you need to use the same streaming DMA region multiple times and touch
-the data in between the DMA transfers, just map it with
-pci_map_{single,sg}, and after each DMA transfer call either:
+the data in between the DMA transfers, the buffer needs to be synced
+properly in order for the cpu and device to see the most uptodate and
+correct copy of the DMA buffer.
 
-	pci_dma_sync_single(dev, dma_handle, size, direction);
+So, firstly, just map it with pci_map_{single,sg}, and after each DMA
+transfer call either:
+
+	pci_dma_sync_single_for_cpu(dev, dma_handle, size, direction);
 
 or:
 
-	pci_dma_sync_sg(dev, sglist, nents, direction);
+	pci_dma_sync_sg_for_cpu(dev, sglist, nents, direction);
+
+as appropriate.
+
+Then, if you wish to let the device get at the DMA area again,
+finish accessing the data with the cpu, and then before actually
+giving the buffer to the hardware call either:
+
+	pci_dma_sync_single_for_device(dev, dma_handle, size, direction);
+
+or:
+
+	pci_dma_sync_sg_for_device(dev, sglist, nents, direction);
 
 as appropriate.
 
@@ -590,8 +606,9 @@ to use the pci_dma_sync_*() interfaces.
 			 * the DMA transfer with the CPU first
 			 * so that we see updated contents.
 			 */
-			pci_dma_sync_single(cp->pdev, cp->rx_dma, cp->rx_len,
-					    PCI_DMA_FROMDEVICE);
+			pci_dma_sync_single_for_cpu(cp->pdev, cp->rx_dma,
+						    cp->rx_len,
+						    PCI_DMA_FROMDEVICE);
 
 			/* Now it is safe to examine the buffer. */
 			hp = (struct my_card_header *) cp->rx_buf;
@@ -601,7 +618,13 @@ to use the pci_dma_sync_*() interfaces.
 				pass_to_upper_layers(cp->rx_buf);
 				make_and_setup_new_rx_buf(cp);
 			} else {
-				/* Just give the buffer back to the card. */
+				/* Just sync the buffer and give it back
+				 * to the card.
+				 */
+				pci_dma_sync_single_for_device(cp->pdev,
+							       cp->rx_dma,
+							       cp->rx_len,
+							       PCI_DMA_FROMDEVICE);
 				give_rx_buf_to_card(cp);
 			}
 		}
@@ -709,12 +732,21 @@ interfaces.  To reiterate:
 
 When the DMA transfer is complete, invoke:
 
-	void pci_dac_dma_sync_single(struct pci_dev *pdev,
-				     dma64_addr_t dma_addr,
-				     size_t len, int direction);
+	void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev,
+					     dma64_addr_t dma_addr,
+					     size_t len, int direction);
 
 This must be done before the CPU looks at the buffer again.
-This interface behaves identically to pci_dma_sync_{single,sg}().
+This interface behaves identically to pci_dma_sync_{single,sg}_for_cpu().
+
+And likewise, if you wish to let the device get back at the buffer after
+the cpu has read/written it, invoke:
+
+	void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev,
+						dma64_addr_t dma_addr,
+						size_t len, int direction);
+
+before letting the device access the DMA area again.
 
 If you need to get back to the PAGE/OFFSET tuple from a dma64_addr_t
 the following interfaces are provided:
--- diff/Documentation/DocBook/gadget.tmpl	2003-09-30 15:46:10.000000000 +0100
+++ source/Documentation/DocBook/gadget.tmpl	2004-03-09 11:51:47.000000000 +0000
@@ -454,6 +454,7 @@ but some optional utilities are provided
 </para>
 
 !Edrivers/usb/gadget/usbstring.c
+!Edrivers/usb/gadget/config.c
 </sect1>
 
 </chapter>
--- diff/Documentation/IPMI.txt	2003-05-21 11:49:59.000000000 +0100
+++ source/Documentation/IPMI.txt	2004-03-09 11:51:47.000000000 +0000
@@ -22,6 +22,58 @@ are not familiar with IPMI itself, see t
 http://www.intel.com/design/servers/ipmi/index.htm.  IPMI is a big
 subject and I can't cover it all here!
 
+Configuration
+-------------
+
+The LinuxIPMI driver is modular, which means you have to pick several
+things to have it work right depending on your hardware.  Most of
+these are available in the 'Character Devices' menu.
+
+No matter what, you must pick 'IPMI top-level message handler' to use
+IPMI.  What you do beyond that depends on your needs and hardware.
+
+The message handler does not provide any user-level interfaces.
+Kernel code (like the watchdog) can still use it.  If you need access
+from userland, you need to select 'Device interface for IPMI' if you
+want access through a device driver.  Another interface is also
+available, you may select 'IPMI sockets' in the 'Networking Support'
+main menu.  This provides a socket interface to IPMI.  You may select
+both of these at the same time, they will both work together.
+
+The driver interface depends on your hardware.  If you have a board
+with a standard interface (These will generally be either "KCS",
+"SMIC", or "BT", consult your hardware manual), choose the 'IPMI SI
+handler' option.  A driver also exists for direct I2C access to the
+IPMI management controller.  Some boards support this, but it is
+unknown if it will work on every board.  For this, choose 'IPMI SMBus
+handler', but be ready to try to do some figuring to see if it will
+work.
+
+There is also a KCS-only driver interface supplied, but it is
+depracated in favor of the SI interface.
+
+You should generally enable ACPI on your system, as systems with IPMI
+should have ACPI tables describing them.
+
+If you have a standard interface and the board manufacturer has done
+their job correctly, the IPMI controller should be automatically
+detect (via ACPI or SMBIOS tables) and should just work.  Sadly, many
+boards do not have this information.  The driver attempts standard
+defaults, but they may not work.  If you fall into this situation, you
+need to read the section below named 'The SI Driver' on how to
+hand-configure your system.
+
+IPMI defines a standard watchdog timer.  You can enable this with the
+'IPMI Watchdog Timer' config option.  If you compile the driver into
+the kernel, then via a kernel command-line option you can have the
+watchdog timer start as soon as it intitializes.  It also have a lot
+of other options, see the 'Watchdog' section below for more details.
+Note that you can also have the watchdog continue to run if it is
+closed (by default it is disabled on close).  Go into the 'Watchdog
+Cards' menu, enable 'Watchdog Timer Support', and enable the option
+'Disable watchdog shutdown on close'.
+
+
 Basic Design
 ------------
 
@@ -41,18 +93,30 @@ ipmi_devintf - This provides a userland 
 driver, each open file for this device ties in to the message handler
 as an IPMI user.
 
-ipmi_kcs_drv - A driver for the KCS SMI.  Most system have a KCS
-interface for IPMI.
+ipmi_si - A driver for various system interfaces.  This supports
+KCS, SMIC, and may support BT in the future.  Unless you have your own
+custom interface, you probably need to use this.
+
+ipmi_smb - A driver for accessing BMCs on the SMBus. It uses the
+I2C kernel driver's SMBus interfaces to send and receive IPMI messages
+over the SMBus.
 
+af_ipmi - A network socket interface to IPMI.  This doesn't take up
+a character device in your system.
+
+Note that the KCS-only interface ahs been removed.
 
 Much documentation for the interface is in the include files.  The
 IPMI include files are:
 
-ipmi.h - Contains the user interface and IOCTL interface for IPMI.
+net/af_ipmi.h - Contains the socket interface.
+
+linux/ipmi.h - Contains the user interface and IOCTL interface for IPMI.
 
-ipmi_smi.h - Contains the interface for SMI drivers to use.
+linux/ipmi_smi.h - Contains the interface for system management interfaces
+(things that interface to IPMI controllers) to use.
 
-ipmi_msgdefs.h - General definitions for base IPMI messaging.
+linux/ipmi_msgdefs.h - General definitions for base IPMI messaging.
 
 
 Addressing
@@ -260,70 +324,131 @@ they register with the message handler. 
 in the order they register, although if an SMI unregisters and then
 another one registers, all bets are off.
 
-The ipmi_smi.h defines the interface for SMIs, see that for more
-details.
+The ipmi_smi.h defines the interface for management interfaces, see
+that for more details.
 
 
-The KCS Driver
---------------
+The SI Driver
+-------------
 
-The KCS driver allows up to 4 KCS interfaces to be configured in the
-system.  By default, the driver will register one KCS interface at the
-spec-specified I/O port 0xca2 without interrupts.  You can change this
-at module load time (for a module) with:
+The SI driver allows up to 4 KCS or SMIC interfaces to be configured
+in the system.  By default, scan the ACPI tables for interfaces, and
+if it doesn't find any the driver will attempt to register one KCS
+interface at the spec-specified I/O port 0xca2 without interrupts.
+You can change this at module load time (for a module) with:
 
-  insmod ipmi_kcs_drv.o kcs_ports=<port1>,<port2>... kcs_addrs=<addr1>,<addr2>
-       kcs_irqs=<irq1>,<irq2>... kcs_trydefaults=[0|1]
+  modprobe ipmi_si.o type=<type1>,<type2>....
+       ports=<port1>,<port2>... addrs=<addr1>,<addr2>...
+       irqs=<irq1>,<irq2>... trydefaults=[0|1]
 
-The KCS driver supports two types of interfaces, ports (for I/O port
-based KCS interfaces) and memory addresses (for KCS interfaces in
-memory).  The driver will support both of them simultaneously, setting
-the port to zero (or just not specifying it) will allow the memory
-address to be used.  The port will override the memory address if it
-is specified and non-zero.  kcs_trydefaults sets whether the standard
-IPMI interface at 0xca2 and any interfaces specified by ACPE are
-tried.  By default, the driver tries it, set this value to zero to
-turn this off.
+Each of these except si_trydefaults is a list, the first item for the
+first interface, second item for the second interface, etc.
+
+The si_type may be either "kcs", "smic", or "bt".  If you leave it blank, it
+defaults to "kcs".
+
+If you specify si_addrs as non-zero for an interface, the driver will
+use the memory address given as the address of the device.  This
+overrides si_ports.
+
+If you specify si_ports as non-zero for an interface, the driver will
+use the I/O port given as the device address.
+
+If you specify si_irqs as non-zero for an interface, the driver will
+attempt to use the given interrupt for the device.
+
+si_trydefaults sets whether the standard IPMI interface at 0xca2 and
+any interfaces specified by ACPE are tried.  By default, the driver
+tries it, set this value to zero to turn this off.
 
 When compiled into the kernel, the addresses can be specified on the
 kernel command line as:
 
-  ipmi_kcs=<bmc1>:<irq1>,<bmc2>:<irq2>....,[nodefault]
-
-The <bmcx> values is either "p<port>" or "m<addr>" for port or memory
-addresses.  So for instance, a KCS interface at port 0xca2 using
-interrupt 9 and a memory interface at address 0xf9827341 with no
-interrupt would be specified "ipmi_kcs=p0xca2:9,m0xf9827341".
-If you specify zero for in irq or don't specify it, the driver will
-run polled unless the software can detect the interrupt to use in the
-ACPI tables.
-
-By default, the driver will attempt to detect a KCS device at the
-spec-specified 0xca2 address and any address specified by ACPI.  If
-you want to turn this off, use the "nodefault" option.
+  ipmi_si.type=<type1>,<type2>...
+       ipmi_si.ports=<port1>,<port2>... ipmi_si.addrs=<addr1>,<addr2>...
+       ipmi_si.irqs=<irq1>,<irq2>... ipmi_si.trydefaults=[0|1]
+
+It works the same as the module parameters of the same names.
+
+By default, the driver will attempt to detect any device specified by
+ACPI, and if none of those then a KCS device at the spec-specified
+0xca2.  If you want to turn this off, set the "trydefaults" option to
+false.
 
 If you have high-res timers compiled into the kernel, the driver will
 use them to provide much better performance.  Note that if you do not
 have high-res timers enabled in the kernel and you don't have
 interrupts enabled, the driver will run VERY slowly.  Don't blame me,
-the KCS interface sucks.
+these interfaces suck.
+
+
+The SMBus Driver
+----------------
+
+The SMBus driver allows up to 4 SMBus devices to be configured in the
+system.  By default, the driver will register any SMBus interfaces it finds
+in the I2C address range of 0x20 to 0x4f on any adapter.  You can change this
+at module load time (for a module) with:
+
+  modprobe ipmi_smb.o
+	addr=<adapter1>,<i2caddr1>[,<adapter2>,<i2caddr2>[,...]]
+	dbg=<flags1>,<flags2>...
+	[defaultprobe=0] [dbg_probe=1]
+
+The addresses are specified in pairs, the first is the adapter ID and the
+second is the I2C address on that adapter.
+
+The debug flags are bit flags for each BMC found, they are:
+IPMI messages: 1, driver state: 2, timing: 4, I2C probe: 8
+
+Setting smb_defaultprobe to zero disabled the default probing of SMBus
+interfaces at address range 0x20 to 0x4f.  This means that only the
+BMCs specified on the smb_addr line will be detected.
+
+Setting smb_dbg_probe to 1 will enable debugging of the probing and
+detection process for BMCs on the SMBusses.
+
+Discovering the IPMI compilant BMC on the SMBus can cause devices
+on the I2C bus to fail. The SMBus driver writes a "Get Device ID" IPMI
+message as a block write to the I2C bus and waits for a response.
+This action can be detrimental to some I2C devices. It is highly recommended
+that the known I2c address be given to the SMBus driver in the smb_addr
+parameter. The default adrress range will not be used when a smb_addr
+parameter is provided.
+
+When compiled into the kernel, the addresses can be specified on the
+kernel command line as:
+
+  ipmb_smb.addr=<adapter1>,<i2caddr1>[,<adapter2>,<i2caddr2>[,...]]
+	ipmi_smb.dbg=<flags1>,<flags2>...
+	ipmi_smb.defaultprobe=0 ipmi_smb.dbg_probe=1
+
+These are the same options as on the module command line.
+
+Note that you might need some I2C changes if CONFIG_IPMI_PANIC_EVENT
+is enabled along with this, so the I2C driver knows to run to
+completion during sending a panic event.
 
 
 Other Pieces
 ------------
 
 Watchdog
+--------
 
 A watchdog timer is provided that implements the Linux-standard
 watchdog timer interface.  It has three module parameters that can be
 used to control it:
 
-  insmod ipmi_watchdog timeout=<t> pretimeout=<t> action=<action type>
-      preaction=<preaction type> preop=<preop type>
+  modprobe ipmi_watchdog timeout=<t> pretimeout=<t> action=<action type>
+      preaction=<preaction type> preop=<preop type> start_now=x
 
 The timeout is the number of seconds to the action, and the pretimeout
 is the amount of seconds before the reset that the pre-timeout panic will
-occur (if pretimeout is zero, then pretimeout will not be enabled).
+occur (if pretimeout is zero, then pretimeout will not be enabled).  Note
+that the pretimeout is the time before the final timeout.  So if the
+timeout is 50 seconds and the pretimeout is 10 seconds, then the pretimeout
+will occur in 40 second (10 seconds before the timeout).
 
 The action may be "reset", "power_cycle", or "power_off", and
 specifies what to do when the timer times out, and defaults to
@@ -344,16 +469,19 @@ When preop is set to "preop_give_data", 
 on the device when the pretimeout occurs.  Select and fasync work on
 the device, as well.
 
+If start_now is set to 1, the watchdog timer will start running as
+soon as the driver is loaded.
+
 When compiled into the kernel, the kernel command line is available
 for configuring the watchdog:
 
-  ipmi_wdog=<timeout>[,<pretimeout>[,<option>[,<options>....]]]
+  ipmi_watchdog.timeout=<t> ipmi_watchdog.pretimeout=<t>
+	ipmi_watchdog.action=<action type>
+	ipmi_watchdog.preaction=<preaction type>
+	ipmi_watchdog.preop=<preop type>
+	ipmi_watchdog.start_now=x
 
-The options are the actions and preaction above (if an option
-controlling the same thing is specified twice, the last is taken).  An
-options "start_now" is also there, if included, the watchdog will
-start running immediately when all the drivers are ready, it doesn't
-have to have a user hooked up to start it.
+The options are the same as the module parameter options.
 
 The watchdog will panic and start a 120 second reset timeout if it
 gets a pre-action.  During a panic or a reboot, the watchdog will
--- diff/Documentation/binfmt_misc.txt	2003-10-09 09:47:33.000000000 +0100
+++ source/Documentation/binfmt_misc.txt	2004-03-09 11:51:47.000000000 +0000
@@ -15,7 +15,7 @@ First you must mount binfmt_misc:
 	mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc 
 
 To actually register a new binary type, you have to set up a string looking like
-:name:type:offset:magic:mask:interpreter: (where you can choose the ':' upon
+:name:type:offset:magic:mask:interpreter:flags (where you can choose the ':' upon
 your needs) and echo it to /proc/sys/fs/binfmt_misc/register.
 Here is what the fields mean:
  - 'name' is an identifier string. A new /proc file will be created with this
@@ -34,6 +34,28 @@ Here is what the fields mean:
    The mask is anded with the byte sequence of the file.
  - 'interpreter' is the program that should be invoked with the binary as first
    argument (specify the full path)
+ - 'flags' is an optional field that controls several aspects of the invocation
+   of the interpreter. It is a string of capital letters, each controls a certain
+   aspect. The following flags are supported -
+      'P' - preserve-argv[0].  Legacy behavior of binfmt_misc is to overwrite the
+            original argv[0] with the full path to the binary.  When this flag is
+            included, binfmt_misc will add an argument to the argument vector for
+            this purpose, thus preserving the original argv[0].
+      'O' - open-binary. Legacy behavior of binfmt_misc is to pass the full path
+            of the binary to the interpreter as an argument. When this flag is
+            included, binfmt_misc will open the file for reading and pass its
+            descriptor as an argument, instead of the full path, thus allowing
+            the interpreter to execute non-readable binaries. This feature should
+            be used with care - the interpreter has to be trusted not to emit
+            the contents of the non-readable binary.
+      'C' - credentials. Currently, the behavior of binfmt_misc is to calculate
+            the credentials and security token of the new process according to
+            the interpreter. When this flag is included, these attributes are
+            calculated according to the binary. It also implies the 'O' flag.
+            This feature should be used with care as the interpreter
+            will run with root permissions when a setuid binary owned by root
+            is run with binfmt_misc.
+
 
 There are some restrictions:
  - the whole register string may not exceed 255 characters
@@ -83,9 +105,9 @@ If you want to pass special arguments to
 write a wrapper script for it. See Documentation/java.txt for an
 example.
 
-Your interpreter should NOT look in the PATH for the filename; the
-kernel passes it the full filename to use.  Using the PATH can cause
-unexpected behaviour and be a security hazard.
+Your interpreter should NOT look in the PATH for the filename; the kernel
+passes it the full filename (or the file descriptor) to use.  Using $PATH can
+cause unexpected behaviour and can be a security hazard.
 
 
 There is a web page about binfmt_misc at
--- diff/Documentation/cdrom/ide-cd	2002-10-16 04:28:31.000000000 +0100
+++ source/Documentation/cdrom/ide-cd	2004-03-09 11:51:47.000000000 +0000
@@ -74,7 +74,7 @@ This driver provides the following featu
 3. The CDROM drive should be connected to the host on an IDE
    interface.  Each interface on a system is defined by an I/O port
    address and an IRQ number, the standard assignments being
-   0x170 and 14 for the primary interface and 0x1f0 and 15 for the
+   0x1f0 and 14 for the primary interface and 0x170 and 15 for the
    secondary interface.  Each interface can control up to two devices,
    where each device can be a hard drive, a CDROM drive, a floppy drive, 
    or a tape drive.  The two devices on an interface are called `master'
@@ -268,8 +268,8 @@ b. Timeout/IRQ errors.
 
   - Double-check your hardware configuration to make sure that the IRQ
     number of your IDE interface matches what the driver expects.
-    (The usual assignments are 14 for the primary (0x170) interface
-    and 15 for the secondary (0x1f0) interface.)  Also be sure that
+    (The usual assignments are 14 for the primary (0x1f0) interface
+    and 15 for the secondary (0x170) interface.)  Also be sure that
     you don't have some other hardware which might be conflicting with
     the IRQ you're using.  Also check the BIOS setup for your system;
     some have the ability to disable individual IRQ levels, and I've
--- diff/Documentation/crypto/api-intro.txt	2004-03-04 11:41:42.000000000 +0000
+++ source/Documentation/crypto/api-intro.txt	2004-03-09 11:51:47.000000000 +0000
@@ -186,6 +186,7 @@ Original developers of the crypto algori
   Dag Arne Osvik (Serpent)
   Brian Gladman (AES)
   Kartikey Mahendra Bhatt (CAST6)
+  Jon Oberheide (ARC4)
 
 SHA1 algorithm contributors:
   Jean-Francois Dive
--- diff/Documentation/early-userspace/README	2003-08-26 10:00:51.000000000 +0100
+++ source/Documentation/early-userspace/README	2004-03-09 11:51:47.000000000 +0000
@@ -71,5 +71,31 @@ custom initramfs images that meet your n
 For questions and help, you can sign up for the early userspace
 mailing list at http://www.zytor.com/mailman/listinfo/klibc
 
+How does it work?
+=================
+
+The kernel has currently 3 ways to mount the root filesystem:
+
+a) all required device and filesystem drivers compiled into the kernel, no
+   initrd.  init/main.c:init() will call prepare_namespace() to mount the
+   final root filesystem, based on the root= option and optional init= to run
+   some other init binary than listed at the end of init/main.c:init().
+
+b) some device and filesystem drivers built as modules and stored in an
+   initrd.  The initrd must contain a binary '/linuxrc' which is supposed to
+   load these driver modules.  It is also possible to mount the final root
+   filesystem via linuxrc and use the pivot_root syscall.  The initrd is
+   mounted and executed via prepare_namespace().
+
+c) using initramfs.  The call to prepare_namespace() must be skipped.
+   This means that a binary must do all the work.  Said binary can be stored
+   into initramfs either via modifying usr/gen_init_cpio.c or via the new
+   initrd format, an cpio archive.  It must be called "/init".  This binary
+   is responsible to do all the things prepare_namespace() would do.
+
+   To remain backwards compatibility, the /init binary will only run if it
+   comes via an initramfs cpio archive.  If this is not the case,
+   init/main.c:init() will run prepare_namespace() to mount the final root
+   and exec one of the predefined init binaries.
 
 Bryan O'Sullivan <bos@serpentine.com>
--- diff/Documentation/filesystems/proc.txt	2004-03-04 11:41:42.000000000 +0000
+++ source/Documentation/filesystems/proc.txt	2004-03-09 11:51:47.000000000 +0000
@@ -38,6 +38,7 @@ Table of Contents
   2.8	/proc/sys/net/ipv4 - IPV4 settings
   2.9	Appletalk
   2.10	IPX
+  2.11	/proc/sys/fs/mqueue - POSIX message queues filesystem
 
 ------------------------------------------------------------------------------
 Preface
@@ -1814,6 +1815,30 @@ The /proc/net/ipx_route  table  holds  a
 gives the  destination  network, the router node (or Directly) and the network
 address of the router (or Connected) for internal networks.
 
+2.11 /proc/sys/fs/mqueue - POSIX message queues filesystem
+----------------------------------------------------------
+
+The "mqueue"  filesystem provides  the necessary kernel features to enable the
+creation of a  user space  library that  implements  the  POSIX message queues
+API (as noted by the  MSG tag in the  POSIX 1003.1-2001 version  of the System
+Interfaces specification.)
+
+The "mqueue" filesystem contains values for determining/setting  the amount of
+resources used by the file system.
+
+/proc/sys/fs/mqueue/queues_max is a read/write  file for  setting/getting  the
+maximum number of message queues allowed on the system.
+
+/proc/sys/fs/mqueue/msg_max  is  a  read/write file  for  setting/getting  the
+maximum number of messages in a queue value.  In fact it is the limiting value
+for another (user) limit which is set in mq_open invocation. This attribute of
+a queue must be less or equal then msg_max.
+
+/proc/sys/fs/mqueue/msgsize_max is  a read/write  file for setting/getting the
+maximum  message size value (it is every  message queue's attribute set during
+its creation).
+
+
 ------------------------------------------------------------------------------
 Summary
 ------------------------------------------------------------------------------
--- diff/Documentation/filesystems/udf.txt	2002-10-16 04:28:34.000000000 +0100
+++ source/Documentation/filesystems/udf.txt	2004-03-09 11:51:47.000000000 +0000
@@ -1,7 +1,7 @@
 *
 * ./Documentation/filesystems/udf.txt
 *
-UDF Filesystem version 0.9.5
+UDF Filesystem version 0.9.8.1
 
 If you encounter problems with reading UDF discs using this driver,
 please report them to linux_udf@hpesjro.fc.hp.com, which is the
@@ -16,7 +16,7 @@ The following mount options are supporte
 	gid=		Set the default group.
 	umask=		Set the default umask.
 	uid=		Set the default user.
-	bs=			Set the block size. 
+	bs=		Set the block size.
 	unhide		Show otherwise hidden files.
 	undelete	Show deleted files in lists.
 	adinicb		Embed data in the inode (default)
@@ -47,15 +47,11 @@ The following expect a offset from the p
 -------------------------------------------------------------------------------
 
 
-For more information see:
-	http://www.trylinux.com/projects/udf/index.html
-
 For the latest version and toolset see:
-	http://www.csc.calpoly.edu/~bfennema/udf.html
 	http://linux-udf.sourceforge.net/
 
 Documentation on UDF and ECMA 167 is available FREE from:
-    http://www.osta.org/
-    http://www.ecma.ch/
+	http://www.osta.org/
+	http://www.ecma-international.org/
 
 Ben Fennema <bfennema@falcon.csc.calpoly.edu>
--- diff/Documentation/filesystems/ufs.txt	2002-10-16 04:28:31.000000000 +0100
+++ source/Documentation/filesystems/ufs.txt	2004-03-09 11:51:47.000000000 +0000
@@ -20,6 +20,9 @@ ufstype=type_of_ufs
 	44bsd	used in FreeBSD, NetBSD, OpenBSD
 		supported os read-write
 
+       ufs2    used in FreeBSD 5.x
+               supported os read-only
+
 	sun	used in SunOS (Solaris)
 		supported as read-write
 
--- diff/Documentation/input/joystick-parport.txt	2002-10-16 04:29:06.000000000 +0100
+++ source/Documentation/input/joystick-parport.txt	2004-03-09 11:51:47.000000000 +0000
@@ -434,7 +434,7 @@ Here are described their command lines:
   Using gamecon.c you can connect up to five devices to one parallel port. It
 uses the following kernel/module command line:
 
-	gc=port,pad1,pad2,pad3,pad4,pad5
+	gamecon.map=port,pad1,pad2,pad3,pad4,pad5
 
   Where 'port' the number of the parport interface (eg. 0 for parport0).
 
@@ -457,15 +457,15 @@ uses the following kernel/module command
 your controller plugged in before initializing.
 
   Should you want to use more than one of parallel ports at once, you can use
-gc_2 and gc_3 as additional command line parameters for two more parallel
-ports.
+gamecon.map2 and gamecon.map3 as additional command line parameters for two
+more parallel ports.
 
 3.2 db9.c
 ~~~~~~~~~
   Apart from making an interface, there is nothing difficult on using the
 db9.c driver. It uses the following kernel/module command line:
 
-	db9=port,type
+	db9.dev=port,type
 
   Where 'port' is the number of the parport interface (eg. 0 for parport0).
 
@@ -489,14 +489,14 @@ Old parallel ports may not have this fea
 	 10  | Amiga CD32 pad
 
   Should you want to use more than one of these joysticks/pads at once, you
-can use db9_2 and db9_3 as additional command line parameters for two
+can use db9.dev2 and db9.dev3 as additional command line parameters for two
 more joysticks/pads.
 
 3.3 turbografx.c
 ~~~~~~~~~~~~~~~~
   The turbografx.c driver uses a very simple kernel/module command line:
 
-	tgfx=port,js1,js2,js3,js4,js5,js6,js7
+	turbografx.map=port,js1,js2,js3,js4,js5,js6,js7
 
   Where 'port' is the number of the parport interface (eg. 0 for parport0).
 
@@ -504,8 +504,8 @@ more joysticks/pads.
 interface ports 1-7 have. For a standard multisystem joystick, this is 1.
 
   Should you want to use more than one of these interfaces at once, you can
-use tgfx_2 and tgfx_3 as additional command line parameters for two more
-interfaces.
+use turbografx.map2 and turbografx.map3 as additional command line parameters
+for two more interfaces.
 
 3.4 PC parallel port pinout
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
--- diff/Documentation/input/joystick.txt	2002-10-16 04:29:05.000000000 +0100
+++ source/Documentation/input/joystick.txt	2004-03-09 11:51:47.000000000 +0000
@@ -111,7 +111,7 @@ your needs:
 	alias tty-ldisc-2 serport
 	alias char-major-13 input
 	above input joydev ns558 analog
-	options analog js=gamepad
+	options analog map=gamepad,none,2btn
 
 2.5 Verifying that it works
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -185,7 +185,7 @@ you'll need to specify the types either 
 module command line, when inserting analog.o into the kernel. The
 parameters are:
 
-	js=type,type,type,....
+	analog.map=<type1>,<type2>,<type3>,....
 
   'type' is type of the joystick from the table below, defining joysticks
 present on gameports in the system, starting with gameport0, second 'type'
@@ -419,7 +419,7 @@ card.
   Amiga joysticks, connected to an Amiga, are supported by the amijoy.c
 driver. Since they can't be autodetected, the driver has a command line.
 
-	amijoy=a,b
+	amijoy.map=<a>,<b>
 
   a and b define the joysticks connected to the JOY0DAT and JOY1DAT ports of
 the Amiga.
--- diff/Documentation/kernel-parameters.txt	2004-03-04 11:41:42.000000000 +0000
+++ source/Documentation/kernel-parameters.txt	2004-03-09 11:51:47.000000000 +0000
@@ -90,10 +90,13 @@ running once the system is up.
 			Format: <irq>, default is 13
 
 	acpi=		[HW,ACPI] Advanced Configuration and Power Interface 
-			Format: { force | off | ht }
+			Format: { force | off | ht | strict }
 			force -- enables ACPI for systems with default off
 			off -- disabled ACPI for systems with default on
 			ht -- run only enough ACPI to enable Hyper Threading
+			strict --  Be less tolerant of platforms that are not
+				strictly ACPI specification compliant.
+
 			See also Documentation/pm.txt.
  
 	acpi_pic_sci=	[HW,ACPI] ACPI System Control Interrupt trigger mode
@@ -151,7 +154,15 @@ running once the system is up.
 			Format: <host-scsi-id>,<target-scsi-id>,<max-rate>,<max-offset>
 			See also header of drivers/scsi/AM53C974.c.
 
-	amijoy=		[HW,JOY] Amiga joystick support 
+	amijoy.map=	[HW,JOY] Amiga joystick support
+			Map of devices attached to JOY0DAT and JOY1DAT
+			Format: <a>,<b>
+			See also Documentation/kernel/input/joystick.txt
+
+	analog.map=	[HW,JOY] Analog joystick and gamepad support
+			Specifies type or capabilities of an analog joystick
+			connected to one of 16 gameports
+			Format: <type1>,<type2>,..<type16>
 
 	apc=		[HW,SPARC] Power management functions (SPARCstation-4/5 + deriv.)
 			Format: noidle
@@ -174,11 +185,18 @@ running once the system is up.
 
 	atascsi=	[HW,SCSI] Atari SCSI
 
-	atkbd.set=	[HW] Select keyboard code set
-			Format: <int>
+	atkbd.extra=	[HW] Enable extra LEDs and keys on IBM RapidAccess, EzKey
+			and similar keyboards
+
+	atkbd.reset=	[HW] Reset keyboard during initialization
+
+	atkbd.set=	[HW] Select keyboard code set 
+			Format: <int> (2 = AT (default) 3 = PS/2)
+
+	atkbd.scroll=	[HW] Enable scroll wheel on MS Office and similar keyboards
+	
 	atkbd.softrepeat=
 			[HW] Use software keyboard repeat
-	atkbd.reset=	[HW] Reset keyboard during initialization
 
 	autotest	[IA64]
 
@@ -280,10 +298,11 @@ running once the system is up.
 	dasd=		[HW,NET]    
 			See header of drivers/s390/block/dasd_devmap.c.
 
-	db9=		[HW,JOY]
-	db9_2=
-	db9_3=
- 
+	db9.dev[2|3]=	[HW,JOY] Multisystem joystick support via parallel port
+			(one device per port)
+			Format: <port#>,<type>
+			See also Documentation/input/joystick-parport.txt
+
 	debug		[KNL] Enable kernel debugging (events log level).
 
 	decnet=		[HW,NET]
@@ -377,12 +396,14 @@ running once the system is up.
 	ftape=		[HW] Floppy Tape subsystem debugging options.
 			See Documentation/ftape.txt.
 
+	gamecon.map[2|3]=
+			[HW,JOY] Multisystem joystick and NES/SNES/PSX pad
+			support via parallel port (up to 5 devices per port)
+			Format: <port#>,<pad1>,<pad2>,<pad3>,<pad4>,<pad5>
+			See also Documentation/input/joystick-parport.txt
+
 	gamma=		[HW,DRM]
 
-	gc=		[HW,JOY]
-	gc_2=		See Documentation/input/joystick-parport.txt.
-	gc_3=		
- 
 	gdth=		[HW,SCSI]
 			See header of drivers/scsi/gdth.c.
 
@@ -609,9 +630,9 @@ running once the system is up.
 
 	mga=		[HW,DRM]
 
-	mousedev.xres	[MOUSE] Horizontal screen resolution, used for devices
+	mousedev.xres=	[MOUSE] Horizontal screen resolution, used for devices
 			reporting absolute coordinates, such as tablets
-	mousedev.yres	[MOUSE] Vertical screen resolution, used for devices
+	mousedev.yres=	[MOUSE] Vertical screen resolution, used for devices
 			reporting absolute coordinates, such as tablets
 
 	mpu401=		[HW,OSS]
@@ -1156,10 +1177,6 @@ running once the system is up.
 			See header of drivers/scsi/t128.c.
 
 	tdfx=		[HW,DRM]
- 
-	tgfx=		[HW,JOY] TurboGraFX parallel port interface
-	tgfx_2=		See Documentation/input/joystick-parport.txt.
-	tgfx_3=
 
 	thash_entries=	[KNL,NET]
 			Set number of hash buckets for TCP connection
@@ -1182,8 +1199,13 @@ running once the system is up.
 	trix=		[HW,OSS] MediaTrix AudioTrix Pro
 			Format: <io>,<irq>,<dma>,<dma2>,<sb_io>,<sb_irq>,<sb_dma>,<mpu_io>,<mpu_irq>
  
-	tsdev.xres	[TS] Horizontal screen resolution.
-	tsdev.yres	[TS] Vertical screen resolution.
+	tsdev.xres=	[TS] Horizontal screen resolution.
+	tsdev.yres=	[TS] Vertical screen resolution.
+
+	turbografx.map[2|3]=
+			[HW,JOY] TurboGraFX parallel port interface
+			Format: <port#>,<js1>,<js2>,<js3>,<js4>,<js5>,<js6>,<js7>
+			See also Documentation/input/joystick-parport.txt
 
 	u14-34f=	[HW,SCSI] UltraStor 14F/34F SCSI host adapter
 			See header of drivers/scsi/u14-34f.c.
--- diff/Documentation/scsi/st.txt	2004-03-04 11:41:42.000000000 +0000
+++ source/Documentation/scsi/st.txt	2004-03-09 11:51:47.000000000 +0000
@@ -2,7 +2,7 @@ This file contains brief information abo
 The driver is currently maintained by Kai Mäkisara (email
 Kai.Makisara@kolumbus.fi)
 
-Last modified: Thu Feb 19 21:57:30 2004 by makisara
+Last modified: Wed Feb 25 14:09:08 2004 by makisara
 
 
 BASICS
@@ -36,8 +36,9 @@ The user can override the parameters def
 manager. The changes persist until the defaults again come into
 effect.
 
-3. Up to four modes can be defined and selected using the minor number
-(bits 5 and 6). Mode 0 corresponds to the defaults discussed
+3. By default, up to four modes can be defined and selected using the minor
+number (bits 5 and 6). The number of modes can be changed by changing
+ST_NBR_MODE_BITS in st.h. Mode 0 corresponds to the defaults discussed
 above. Additional modes are dormant until they are defined by the
 system manager (root). When specification of a new mode is started,
 the configuration of mode 0 is used to provide a starting point for
@@ -107,7 +108,7 @@ The minor numbers consist of the followi
 dev_upper non-rew mode dev-lower
   20 -  8     7    6 5  4      0
 The non-rewind bit is always bit 7 (the uppermost bit in the lowermost
-byte). The bits defining the mode are next to the non-rewind bits. The
+byte). The bits defining the mode are below the non-rewind bit. The
 remaining bits define the tape device number. This numbering is
 backward compatible with the numbering used when the minor number was
 only 8 bits wide.
@@ -117,10 +118,10 @@ SYSFS SUPPORT
 
 The driver creates the directory /sys/class/scsi_tape and populates it with
 directories corresponding to the existing tape devices. There are autorewind
-and non-rewind entries for each mode. The names are stxmy and stxmyn, where x
-is the tape number and y is the mode. For example, the directories for the
-first tape device are (assuming four modes): st0m0  st0m0n  st0m1  st0m1n
-st0m2  st0m2n  st0m3  st0m3n.
+and non-rewind entries for each mode. The names are stxy and nstxy, where x
+is the tape number and y a character corresponding to the mode (none, l, m,
+a). For example, the directories for the first tape device are (assuming four
+modes): st0  nst0  st0l  nst0l  st0m  nst0m  st0a  nst0a.
 
 Each directory contains the entries: default_blksize  default_compression
 default_density  defined  dev  device  driver. The file 'defined' contains 1
@@ -130,7 +131,7 @@ file 'dev' contains the device numbers c
 'device' and 'driver' point to the SCSI device and driver entries.
 
 A link named 'tape' is made from the SCSI device directory to the class
-directory corresponding to the mode 0 auto-rewind device (e.g., st0m0). 
+directory corresponding to the mode 0 auto-rewind device (e.g., st0). 
 
 
 BSD AND SYS V SEMANTICS
--- diff/Documentation/sound/alsa/ALSA-Configuration.txt	2004-02-18 08:54:06.000000000 +0000
+++ source/Documentation/sound/alsa/ALSA-Configuration.txt	2004-03-09 11:51:47.000000000 +0000
@@ -692,6 +692,15 @@ Module parameters
 
     The power-management is supported.
 
+  Module snd-mixart
+  -----------------
+
+    Module for Digigram miXart8 soundcards.
+
+    Module supports multiple cards.
+    Note: One miXart8 board will be represented as 4 alsa cards.
+          See MIXART.txt for details.
+
   Module snd-mpu401
   -----------------
 
@@ -1170,6 +1179,16 @@ Module parameters
 
     The power-management is supported.
 
+  Module snd-pdaudiocf
+  --------------------
+
+    Module for Sound Core PDAudioCF soundcard.
+
+    irq_mask	  - IRQ mask (PCMCIA type)
+    irq_list	  - List of available interrupts for this soundcard
+
+    Note: the driver is build only when CONFIG_ISA is set.
+
 
 Configuring Non-ISAPNP Cards
 ============================
--- diff/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl	2004-02-18 08:54:06.000000000 +0000
+++ source/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl	2004-03-09 11:51:47.000000000 +0000
@@ -3769,14 +3769,20 @@ struct _snd_pcm_runtime {
             <programlisting>
 <![CDATA[
   static int snd_myctl_info(snd_kcontrol_t *kcontrol,
-  static char *texts[4] = {
-          "First", "Second", "Third", "Fourth"
-  };
-  uinfo->value.enumerated.items = 4;
-  if (uinfo->value.enumerated.item > 3)
-          uinfo->value.enumerated.item = 3;
-  strcpy(uinfo->value.enumerated.name,
-         texts[uinfo->value.enumerated.item]);
+                          snd_ctl_elem_info_t *uinfo)
+  {
+          static char *texts[4] = {
+                  "First", "Second", "Third", "Fourth"
+          };
+          uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+          uinfo->count = 1;
+          uinfo->value.enumerated.items = 4;
+          if (uinfo->value.enumerated.item > 3)
+                  uinfo->value.enumerated.item = 3;
+          strcpy(uinfo->value.enumerated.name,
+                 texts[uinfo->value.enumerated.item]);
+          return 0;
+  }
 ]]>
             </programlisting>
           </informalexample>
--- diff/Documentation/sound/alsa/Joystick.txt	2004-02-18 08:54:06.000000000 +0000
+++ source/Documentation/sound/alsa/Joystick.txt	2004-03-09 11:51:47.000000000 +0000
@@ -43,7 +43,8 @@ The following PCI drivers support the jo
     ens1370	joystick	0 = disable (default), 1 = enable
     ens1371	joystick_port	0 = disable (default), 1 = auto-detect,
                                 manual: 0x200, 0x208, 0x210, 0x218
-    cmipci	joystick	0 = disable (default), 1 = enable
+    cmipci	joystick_port	0 = disable (default), 1 = auto-detect,
+                                manual: any address (e.g. 0x200)
     cs4281	N/A		N/A
     cs46xx	N/A		N/A
     es1938	N/A		N/A
--- diff/Documentation/usb/acm.txt	2002-10-16 04:27:22.000000000 +0100
+++ source/Documentation/usb/acm.txt	2004-03-09 11:51:47.000000000 +0000
@@ -28,7 +28,7 @@ in the package: See the file COPYING.
 
 1. Usage
 ~~~~~~~~
-  The drivers/usb/acm.c drivers works with USB modems and USB ISDN terminal
+  The drivers/usb/class/cdc-acm.c drivers works with USB modems and USB ISDN terminal
 adapters that conform to the Universal Serial Bus Communication Device Class
 Abstract Control Model (USB CDC ACM) specification.
 
@@ -65,9 +65,9 @@ minor/major numbers anywhere you want, b
 
   To use the modems you need these modules loaded:
 
-	usbcore.o
-	usb-[uo]hci.o or uhci.o
-	acm.o
+	usbcore.ko
+	uhci-hcd.ko ohci-hcd.ko or ehci-hcd.ko
+	cdc-acm.ko
 
   After that, the modem[s] should be accessible. You should be able to use
 minicom, ppp and mgetty with them.
--- diff/Documentation/usb/error-codes.txt	2002-10-16 04:27:08.000000000 +0100
+++ source/Documentation/usb/error-codes.txt	2004-03-09 11:51:47.000000000 +0000
@@ -70,7 +70,9 @@ one or more packets could finish before 
 			(That is, if drivers see this it's a bug.)
 
 -EPROTO (*)		a) bitstuff error
-			b) unknown USB error 
+			b) no response packet received within the
+			   prescribed bus turn-around time
+			c) unknown USB error 
 
 -EILSEQ (*)		CRC mismatch
 
--- diff/MAINTAINERS	2004-03-04 11:41:42.000000000 +0000
+++ source/MAINTAINERS	2004-03-09 11:51:47.000000000 +0000
@@ -172,7 +172,7 @@ ACPI
 P:	Len Brown
 M:	len.brown@intel.com
 L:	acpi-devel@lists.sourceforge.net
-W:	http://sf.net/projects/acpi/
+W:	http://acpi.sourceforge.net/
 S:	Maintained
 
 AD1816 SOUND DRIVER
@@ -1186,6 +1186,12 @@ W:	http://sf.net/projects/kernel-janitor
 W:	http://developer.osdl.org/rddunlap/kj-patches/
 S:	Maintained
 
+KGDB FOR I386 PLATFORM
+P:	George Anzinger
+M:	george@mvista.com
+L:	linux-net@vger.kernel.org
+S:	Supported
+
 KERNEL NFSD
 P:	Neil Brown
 M:	neilb@cse.unsw.edu.au
@@ -2037,8 +2043,6 @@ S:	Maintained
 UDF FILESYSTEM
 P:	Ben Fennema
 M:	bfennema@falcon.csc.calpoly.edu
-P:	Dave Boynton
-M:	dave@trylinux.com
 L:	linux_udf@hpesjro.fc.hp.com
 W:	http://linux-udf.sourceforge.net
 S:	Maintained
--- diff/Makefile	2004-03-04 11:41:42.000000000 +0000
+++ source/Makefile	2004-03-09 11:51:47.000000000 +0000
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 4
-EXTRAVERSION =-rc2
+EXTRAVERSION =-rc2-mm1
 NAME=Feisty Dunnart
 
 # *DOCUMENTATION*
@@ -444,6 +444,7 @@ endif
 
 ifdef CONFIG_DEBUG_INFO
 CFLAGS		+= -g
+AFLAGS		+= -g
 endif
 
 # warn about C99 declaration after statement
@@ -757,26 +758,15 @@ endef
 #                Any core files spread around are deleted as well
 # make distclean Remove editor backup files, patch leftover files and the like
 
-# Files removed with 'make clean'
-CLEAN_FILES += vmlinux System.map MC*
+# Directories & files removed with 'make clean'
+CLEAN_DIRS  += $(MODVERDIR) include/config include2
+CLEAN_FILES +=	vmlinux System.map \
+		include/linux/autoconf.h include/linux/version.h \
+		include/asm include/linux/modversions.h \
+		kernel.spec .tmp*
 
 # Files removed with 'make mrproper'
-MRPROPER_FILES += \
-	include/linux/autoconf.h include/linux/version.h \
-	.version .config .config.old config.in config.old \
-	.menuconfig.log \
-	include/asm \
-	.hdepend include/linux/modversions.h \
-	tags TAGS cscope* kernel.spec \
-	.tmp*
-
-# Directories removed with 'make mrproper'
-MRPROPER_DIRS += \
-	$(MODVERDIR) \
-	.tmp_export-objs \
-	include/config \
-	include/linux/modules \
-	include2
+MRPROPER_FILES += .version .config .config.old tags TAGS cscope*
 
 # clean - Delete all intermediate files
 #
@@ -785,28 +775,36 @@ clean-dirs += $(addprefix _clean_,$(ALL_
 $(clean-dirs):
 	$(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@)
 
-quiet_cmd_rmclean = RM  $$(CLEAN_FILES)
-cmd_rmclean	  = rm -f $(CLEAN_FILES)
+clean:		rm-dirs  := $(wildcard $(CLEAN_DIRS))
+mrproper:	rm-dirs  := $(wildcard $(MRPROPER_DIRS))
+quiet_cmd_rmdirs = $(if $(rm-dirs),CLEAN   $(rm-dirs))
+      cmd_rmdirs = rm -rf $(rm-dirs)
+
+clean:		rm-files := $(wildcard $(CLEAN_FILES))
+mrproper:	rm-files := $(wildcard $(MRPROPER_FILES))
+quiet_cmd_rmfiles = $(if $(rm-files),CLEAN   $(rm-files))
+      cmd_rmfiles = rm -rf $(rm-files)
+
 clean: archclean $(clean-dirs)
-	$(call cmd,rmclean)
+	$(call cmd,rmdirs)
+	$(call cmd,rmfiles)
 	@find . $(RCS_FIND_IGNORE) \
 	 	\( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
 		-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \) \
 		-type f -print | xargs rm -f
 
-# mrproper - delete configuration + modules + core files
+# mrproper
 #
-quiet_cmd_mrproper = RM  $$(MRPROPER_DIRS) + $$(MRPROPER_FILES)
-cmd_mrproper = rm -rf $(MRPROPER_DIRS) && rm -f $(MRPROPER_FILES)
-mrproper distclean: clean archmrproper
-	@echo '  Making $@ in the srctree'
+distclean: mrproper
+mrproper: clean archmrproper
+	$(call cmd,rmdirs)
+	$(call cmd,rmfiles)
 	@find . $(RCS_FIND_IGNORE) \
 	 	\( -name '*.orig' -o -name '*.rej' -o -name '*~' \
 		-o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
 	 	-o -name '.*.rej' -o -size 0 \
 		-o -name '*%' -o -name '.*.cmd' -o -name 'core' \) \
 		-type f -print | xargs rm -f
-	$(call cmd,mrproper)
 
 # Generate tags for editors
 # ---------------------------------------------------------------------------
--- diff/arch/alpha/kernel/alpha_ksyms.c	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/alpha/kernel/alpha_ksyms.c	2004-03-09 11:51:47.000000000 +0000
@@ -35,9 +35,6 @@
 #include <asm/cacheflush.h>
 #include <asm/vga.h>
 
-#define __KERNEL_SYSCALLS__
-#include <asm/unistd.h>
-
 extern struct hwrpb_struct *hwrpb;
 extern void dump_thread(struct pt_regs *, struct user *);
 extern spinlock_t rtc_lock;
--- diff/arch/alpha/kernel/ptrace.c	2003-06-30 10:07:18.000000000 +0100
+++ source/arch/alpha/kernel/ptrace.c	2004-03-09 11:51:47.000000000 +0000
@@ -369,8 +369,8 @@ do_sys_ptrace(long request, long pid, lo
 		/* Mark single stepping.  */
 		child->thread_info->bpt_nsaved = -1;
 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-		wake_up_process(child);
 		child->exit_code = data;
+		wake_up_process(child);
 		/* give it a chance to run. */
 		ret = 0;
 		goto out;
--- diff/arch/alpha/kernel/smp.c	2003-10-09 09:47:33.000000000 +0100
+++ source/arch/alpha/kernel/smp.c	2004-03-09 11:51:47.000000000 +0000
@@ -39,9 +39,6 @@
 #include <asm/mmu_context.h>
 #include <asm/tlbflush.h>
 
-#define __KERNEL_SYSCALLS__
-#include <asm/unistd.h>
-
 #include "proto.h"
 #include "irq_impl.h"
 
--- diff/arch/arm/Makefile	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/arm/Makefile	2004-03-09 11:51:47.000000000 +0000
@@ -23,6 +23,11 @@ CFLAGS		+= -mbig-endian
 AS		+= -EB
 LD		+= -EB
 AFLAGS		+= -mbig-endian
+else
+CFLAGS		+= -mlittle-endian
+AS		+= -EL
+LD		+= -EL
+AFLAGS		+= -mlittle-endian
 endif
 
 comma = ,
--- diff/arch/arm/common/sa1111-pcibuf.c	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/arm/common/sa1111-pcibuf.c	2004-03-09 11:51:47.000000000 +0000
@@ -457,8 +457,8 @@ void sa1111_unmap_sg(struct device *dev,
 	local_irq_restore(flags);
 }
 
-void sa1111_dma_sync_single(struct device *dev, dma_addr_t dma_addr,
-			    size_t size, enum dma_data_direction dir)
+void sa1111_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_addr,
+				    size_t size, enum dma_data_direction dir)
 {
 	unsigned long flags;
 
@@ -472,8 +472,44 @@ void sa1111_dma_sync_single(struct devic
 	local_irq_restore(flags);
 }
 
-void sa1111_dma_sync_sg(struct device *dev, struct scatterlist *sg,
-			int nents, enum dma_data_direction dir)
+void sa1111_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_addr,
+				       size_t size, enum dma_data_direction dir)
+{
+	unsigned long flags;
+
+	dev_dbg(dev, "%s(ptr=%08lx,size=%d,dir=%x)\n",
+		__func__, dma_addr, size, dir);
+
+	local_irq_save(flags);
+
+	sync_single(dev, dma_addr, size, dir);
+
+	local_irq_restore(flags);
+}
+
+void sa1111_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+				int nents, enum dma_data_direction dir)
+{
+	unsigned long flags;
+	int i;
+
+	dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n",
+		__func__, sg, nents, dir);
+
+	local_irq_save(flags);
+
+	for (i = 0; i < nents; i++, sg++) {
+		dma_addr_t dma_addr = sg->dma_address;
+		unsigned int length = sg->length;
+
+		sync_single(dev, dma_addr, length, dir);
+	}
+
+	local_irq_restore(flags);
+}
+
+void sa1111_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+				   int nents, enum dma_data_direction dir)
 {
 	unsigned long flags;
 	int i;
@@ -497,8 +533,10 @@ EXPORT_SYMBOL(sa1111_map_single);
 EXPORT_SYMBOL(sa1111_unmap_single);
 EXPORT_SYMBOL(sa1111_map_sg);
 EXPORT_SYMBOL(sa1111_unmap_sg);
-EXPORT_SYMBOL(sa1111_dma_sync_single);
-EXPORT_SYMBOL(sa1111_dma_sync_sg);
+EXPORT_SYMBOL(sa1111_dma_sync_single_for_cpu);
+EXPORT_SYMBOL(sa1111_dma_sync_single_for_device);
+EXPORT_SYMBOL(sa1111_dma_sync_sg_for_cpu);
+EXPORT_SYMBOL(sa1111_dma_sync_sg_for_device);
 
 /* **************************************** */
 
--- diff/arch/arm/kernel/armksyms.c	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/arm/kernel/armksyms.c	2004-03-09 11:51:47.000000000 +0000
@@ -187,6 +187,7 @@ EXPORT_SYMBOL(__arch_copy_from_user);
 EXPORT_SYMBOL(__arch_copy_to_user);
 EXPORT_SYMBOL(__arch_clear_user);
 EXPORT_SYMBOL(__arch_strnlen_user);
+EXPORT_SYMBOL(__arch_strncpy_from_user);
 
 	/* consistent area handling */
 EXPORT_SYMBOL(consistent_alloc);
--- diff/arch/arm/mm/Kconfig	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/arm/mm/Kconfig	2004-03-09 11:51:48.000000000 +0000
@@ -347,7 +347,7 @@ config CPU_BIG_ENDIAN
 	help
 	  Say Y if you plan on running a kernel in big-endian mode.
 	  Note that your board must be properly built and your board
-	  port must properly enable and big-endian related features
+	  port must properly enable any big-endian related features
 	  of your chipset/board/processor.
 
 config CPU_ICACHE_DISABLE
--- diff/arch/arm26/Kconfig	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/arm26/Kconfig	2004-03-09 11:51:48.000000000 +0000
@@ -198,11 +198,6 @@ source "drivers/input/Kconfig"
 
 source "drivers/char/Kconfig"
 
-config KBDMOUSE
-	bool
-	depends on ARCH_ACORN && BUSMOUSE=y
-	default y
-
 source "drivers/media/Kconfig"
 
 source "fs/Kconfig"
--- diff/arch/cris/kernel/process.c	2003-10-09 09:47:33.000000000 +0100
+++ source/arch/cris/kernel/process.c	2004-03-09 11:51:48.000000000 +0000
@@ -91,8 +91,6 @@
  * This file handles the architecture-dependent parts of process handling..
  */
 
-#define __KERNEL_SYSCALLS__
-
 #include <asm/atomic.h>
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
--- diff/arch/h8300/kernel/sys_h8300.c	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/h8300/kernel/sys_h8300.c	2004-03-09 11:51:48.000000000 +0000
@@ -260,11 +260,6 @@ asmlinkage int sys_ipc (uint call, int f
 	return -EINVAL;
 }
 
-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on)
-{
-  return -ENOSYS;
-}
-
 /* sys_cacheflush -- no support.  */
 asmlinkage int
 sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
--- diff/arch/h8300/kernel/syscalls.S	2003-08-26 10:00:51.000000000 +0100
+++ source/arch/h8300/kernel/syscalls.S	2004-03-09 11:51:48.000000000 +0000
@@ -116,7 +116,7 @@ SYMBOL_NAME_LABEL(sys_call_table)	
 	.long SYMBOL_NAME(sys_ni_syscall)				/* old profil syscall holder */
 	.long SYMBOL_NAME(sys_statfs)
 	.long SYMBOL_NAME(sys_fstatfs)		/* 100 */
-	.long SYMBOL_NAME(sys_ioperm)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* ioperm for i386 */
 	.long SYMBOL_NAME(sys_socketcall)
 	.long SYMBOL_NAME(sys_syslog)
 	.long SYMBOL_NAME(sys_setitimer)
--- diff/arch/i386/Kconfig	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/i386/Kconfig	2004-03-09 11:51:48.000000000 +0000
@@ -269,9 +269,6 @@ config MK8
 	  use of some extended instructions, and passes appropriate optimization
 	  flags to GCC.
 
-config MELAN
-	bool "Elan"
-
 config MCRUSOE
 	bool "Crusoe"
 	help
@@ -421,6 +418,54 @@ config X86_OOSTORE
 	depends on (MWINCHIP3D || MWINCHIP2 || MWINCHIPC6) && MTRR
 	default y
 
+config X86_4G
+	bool "4 GB kernel-space and 4 GB user-space virtual memory support"
+	help
+          This option is only useful for systems that have more than 1 GB
+          of RAM.
+
+          The default kernel VM layout leaves 1 GB of virtual memory for
+          kernel-space mappings, and 3 GB of VM for user-space applications.
+          This option ups both the kernel-space VM and the user-space VM to
+          4 GB.
+
+          The cost of this option is additional TLB flushes done at
+          system-entry points that transition from user-mode into kernel-mode.
+          I.e. system calls and page faults, and IRQs that interrupt user-mode
+          code. There's also additional overhead to kernel operations that copy
+          memory to/from user-space. The overhead from this is hard to tell and
+          depends on the workload - it can be anything from no visible overhead
+          to 20-30% overhead. A good rule of thumb is to count with a runtime
+          overhead of 20%.
+
+          The upside is the much increased kernel-space VM, which more than
+          quadruples the maximum amount of RAM supported. Kernels compiled with
+          this option boot on 64GB of RAM and still have more than 3.1 GB of
+          'lowmem' left. Another bonus is that highmem IO bouncing decreases,
+          if used with drivers that still use bounce-buffers.
+
+          There's also a 33% increase in user-space VM size - database
+          applications might see a boost from this.
+
+          But the cost of the TLB flushes and the runtime overhead has to be
+          weighed against the bonuses offered by the larger VM spaces. The
+          dividing line depends on the actual workload - there might be 4 GB
+          systems that benefit from this option. Systems with less than 4 GB
+          of RAM will rarely see a benefit from this option - but it's not
+          out of question, the exact circumstances have to be considered.
+
+config X86_SWITCH_PAGETABLES
+	def_bool X86_4G
+
+config X86_4G_VM_LAYOUT
+	def_bool X86_4G
+
+config X86_UACCESS_INDIRECT
+	def_bool X86_4G
+
+config X86_HIGH_ENTRY
+	def_bool X86_4G
+
 config HPET_TIMER
 	bool "HPET Timer Support"
 	help
@@ -478,6 +523,16 @@ config NR_CPUS
 	  This is purely to save memory - each supported CPU adds
 	  approximately eight kilobytes to the kernel image.
 
+config SCHED_SMT
+	bool "SMT (Hyperthreading) scheduler support"
+	depends on SMP
+	default off
+	help
+	  SMT scheduler support improves the CPU scheduler's decision making
+	  when dealing with Intel Pentium 4 chips with HyperThreading at a
+	  cost of slightly increased overhead in some places. If unsure say
+	  N here.
+
 config PREEMPT
 	bool "Preemptible Kernel"
 	help
@@ -552,7 +607,7 @@ config X86_MCE
 	  the 386 and 486, so nearly everyone can say Y here.
 
 config X86_MCE_NONFATAL
-	bool "Check for non-fatal errors on AMD Athlon/Duron / Intel Pentium 4"
+	tristate "Check for non-fatal errors on AMD Athlon/Duron / Intel Pentium 4"
 	depends on X86_MCE
 	help
 	  Enabling this feature starts a timer that triggers every 5 seconds which
@@ -1068,12 +1123,16 @@ config PCI_GOBIOS
 	  PCI-based systems don't have any BIOS at all. Linux can also try to
 	  detect the PCI hardware directly without using the BIOS.
 
-	  With this option, you can specify how Linux should detect the PCI
-	  devices. If you choose "BIOS", the BIOS will be used, if you choose
-	  "Direct", the BIOS won't be used, and if you choose "Any", the
-	  kernel will try the direct access method and falls back to the BIOS
-	  if that doesn't work. If unsure, go with the default, which is
-	  "Any".
+	  With this option, you can specify how Linux should detect the
+	  PCI devices. If you choose "BIOS", the BIOS will be used,
+	  if you choose "Direct", the BIOS won't be used, and if you
+	  choose "MMConfig", then PCI Express MMCONFIG will be used.
+	  If you choose "Any", the kernel will try MMCONFIG, then the
+	  direct access method and falls back to the BIOS if that doesn't
+	  work. If unsure, go with the default, which is "Any".
+
+config PCI_GOMMCONFIG
+	bool "MMConfig"
 
 config PCI_GODIRECT
 	bool "Direct"
@@ -1093,6 +1152,12 @@ config PCI_DIRECT
  	depends on PCI && ((PCI_GODIRECT || PCI_GOANY) || X86_VISWS)
 	default y
 
+config PCI_MMCONFIG
+	bool
+	depends on PCI && (PCI_GOMMCONFIG || PCI_GOANY)
+	select ACPI_BOOT
+	default y
+
 config PCI_USE_VECTOR
 	bool "Vector-based interrupt indexing (MSI)"
 	depends on X86_LOCAL_APIC && X86_IO_APIC
@@ -1231,17 +1296,6 @@ config DEBUG_SLAB
 	  allocation as well as poisoning memory on free to catch use of freed
 	  memory.
 
-config DEBUG_IOVIRT
-	bool "Memory mapped I/O debugging"
-	depends on DEBUG_KERNEL
-	help
-	  Say Y here to get warned whenever an attempt is made to do I/O on
-	  obviously invalid addresses such as those generated when ioremap()
-	  calls are forgotten.  Memory mapped I/O will go through an extra
-	  check to catch access to unmapped ISA addresses, an access method
-	  that can still be used by old drivers that are being ported from
-	  2.0/2.2.
-
 config MAGIC_SYSRQ
 	bool "Magic SysRq key"
 	depends on DEBUG_KERNEL
@@ -1273,6 +1327,15 @@ config DEBUG_PAGEALLOC
 	  This results in a large slowdown, but helps to find certain types
 	  of memory corruptions.
 
+config SPINLINE
+	bool "Spinlock inlining"
+	depends on DEBUG_KERNEL
+	help
+	  This will change spinlocks from out of line to inline, making them
+	  account cost to the callers in readprofile, rather than the lock
+	  itself (as ".text.lock.filename"). This can be helpful for finding
+	  the callers of locks.
+
 config DEBUG_HIGHMEM
 	bool "Highmem debugging"
 	depends on DEBUG_KERNEL && HIGHMEM
@@ -1289,20 +1352,217 @@ config DEBUG_INFO
 	  Say Y here only if you plan to use gdb to debug the kernel.
 	  If you don't debug the kernel, you can say N.
 	  
+config LOCKMETER
+	bool "Kernel lock metering"
+	depends on SMP
+	help
+	  Say Y to enable kernel lock metering, which adds overhead to SMP locks,
+	  but allows you to see various statistics using the lockstat command.
+
 config DEBUG_SPINLOCK_SLEEP
 	bool "Sleep-inside-spinlock checking"
 	help
 	  If you say Y here, various routines which may sleep will become very
 	  noisy if they are called with a spinlock held.	
 
+config KGDB
+	bool "Include kgdb kernel debugger"
+	depends on DEBUG_KERNEL
+	help
+	  If you say Y here, the system will be compiled with the debug
+	  option (-g) and a debugging stub will be included in the
+	  kernel.  This stub communicates with gdb on another (host)
+	  computer via a serial port.  The host computer should have
+	  access to the kernel binary file (vmlinux) and a serial port
+	  that is connected to the target machine.  Gdb can be made to
+	  configure the serial port or you can use stty and setserial to
+	  do this. See the 'target' command in gdb. This option also
+	  configures in the ability to request a breakpoint early in the
+	  boot process.  To request the breakpoint just include 'kgdb'
+	  as a boot option when booting the target machine.  The system
+	  will then break as soon as it looks at the boot options.  This
+	  option also installs a breakpoint in panic and sends any
+	  kernel faults to the debugger. For more information see the
+	  Documentation/i386/kgdb/kgdb.txt file.
+
+choice
+	depends on KGDB
+    	prompt "Debug serial port BAUD"
+	default KGDB_115200BAUD
+	help
+	  Gdb and the kernel stub need to agree on the baud rate to be
+	  used.  Some systems (x86 family at this writing) allow this to
+	  be configured.
+
+config KGDB_9600BAUD
+	bool "9600"
+
+config KGDB_19200BAUD
+	bool "19200"
+
+config KGDB_38400BAUD
+	bool "38400"
+
+config KGDB_57600BAUD
+	bool "57600"
+
+config KGDB_115200BAUD
+	bool "115200"
+endchoice
+
+config KGDB_PORT
+	hex "hex I/O port address of the debug serial port"
+	depends on KGDB
+	default  3f8
+	help
+	  Some systems (x86 family at this writing) allow the port
+	  address to be configured.  The number entered is assumed to be
+	  hex, don't put 0x in front of it.  The standard address are:
+	  COM1 3f8 , irq 4 and COM2 2f8 irq 3.  Setserial /dev/ttySx
+	  will tell you what you have.  It is good to test the serial
+	  connection with a live system before trying to debug.
+
+config KGDB_IRQ
+	int "IRQ of the debug serial port"
+	depends on KGDB
+	default 4
+	help
+	  This is the irq for the debug port.  If everything is working
+	  correctly and the kernel has interrupts on a control C to the
+	  port should cause a break into the kernel debug stub.
+
+config DEBUG_INFO
+	bool
+	depends on KGDB
+	default y
+
+config KGDB_MORE
+	bool "Add any additional compile options"
+	depends on KGDB
+	default n
+	help
+	  Saying yes here turns on the ability to enter additional
+	  compile options.
+
+
+config KGDB_OPTIONS
+	depends on KGDB_MORE
+	string "Additional compile arguments"
+	default "-O1"
+	help
+	  This option allows you enter additional compile options for
+	  the whole kernel compile.  Each platform will have a default
+	  that seems right for it.  For example on PPC "-ggdb -O1", and
+	  for i386 "-O1".  Note that by configuring KGDB "-g" is already
+	  turned on.  In addition, on i386 platforms
+	  "-fomit-frame-pointer" is deleted from the standard compile
+	  options.
+
+config NO_KGDB_CPUS
+	int "Number of CPUs"
+	depends on KGDB && SMP
+	default NR_CPUS
+	help
+
+	  This option sets the number of cpus for kgdb ONLY.  It is used
+	  to prune some internal structures so they look "nice" when
+	  displayed with gdb.  This is to overcome possibly larger
+	  numbers that may have been entered above.  Enter the real
+	  number to get nice clean kgdb_info displays.
+
+config KGDB_TS
+	bool "Enable kgdb time stamp macros?"
+	depends on KGDB
+	default n
+	help
+	  Kgdb event macros allow you to instrument your code with calls
+	  to the kgdb event recording function.  The event log may be
+	  examined with gdb at a break point.  Turning on this
+	  capability also allows you to choose how many events to
+	  keep. Kgdb always keeps the lastest events.
+
+choice
+	depends on KGDB_TS
+	prompt "Max number of time stamps to save?"
+	default KGDB_TS_128
+
+config KGDB_TS_64
+	bool "64"
+
+config KGDB_TS_128
+	bool "128"
+
+config KGDB_TS_256
+	bool "256"
+
+config KGDB_TS_512
+	bool "512"
+
+config KGDB_TS_1024
+	bool "1024"
+
+endchoice
+
+config STACK_OVERFLOW_TEST
+	bool "Turn on kernel stack overflow testing?"
+	depends on KGDB
+	default n
+	help
+	  This option enables code in the front line interrupt handlers
+	  to check for kernel stack overflow on interrupts and system
+	  calls.  This is part of the kgdb code on x86 systems.
+
+config KGDB_CONSOLE
+	bool "Enable serial console thru kgdb port"
+	depends on KGDB
+	default n
+	help
+	  This option enables the command line "console=kgdb" option.
+	  When the system is booted with this option in the command line
+	  all kernel printk output is sent to gdb (as well as to other
+	  consoles).  For this to work gdb must be connected.  For this
+	  reason, this command line option will generate a breakpoint if
+	  gdb has not yet connected.  After the gdb continue command is
+	  given all pent up console output will be printed by gdb on the
+	  host machine.  Neither this option, nor KGDB require the
+	  serial driver to be configured.
+
+config KGDB_SYSRQ
+	bool "Turn on SysRq 'G' command to do a break?"
+	depends on KGDB
+	default y
+	help
+	  This option includes an option in the SysRq code that allows
+	  you to enter SysRq G which generates a breakpoint to the KGDB
+	  stub.  This will work if the keyboard is alive and can
+	  interrupt the system.  Because of constraints on when the
+	  serial port interrupt can be enabled, this code may allow you
+	  to interrupt the system before the serial port control C is
+	  available.  Just say yes here.
+
 config FRAME_POINTER
 	bool "Compile the kernel with frame pointers"
+	default KGDB
 	help
 	  If you say Y here the resulting kernel image will be slightly larger
 	  and slower, but it will give very useful debugging information.
 	  If you don't debug the kernel, you can say N, but we may not be able
 	  to solve problems without frame pointers.
 
+config MAGIC_SYSRQ
+	bool
+	depends on KGDB_SYSRQ
+	default y
+
+config 4KSTACKS
+	bool "Use 4Kb for kernel stacks instead of 8Kb"
+	help
+	  If you say Y here the kernel will use a 4Kb stacksize for the
+	  kernel stack attached to each process/thread. This facilitates
+	  running more threads on a system and also reduces the pressure
+	  on the VM subsystem for higher order allocations. This option
+	  will also use IRQ stacks to compensate for the reduced stackspace.
+
 config X86_FIND_SMP_CONFIG
 	bool
 	depends on X86_LOCAL_APIC || X86_VOYAGER
@@ -1336,11 +1596,6 @@ config X86_BIOS_REBOOT
 	depends on !(X86_VISWS || X86_VOYAGER)
 	default y
 
-config X86_TRAMPOLINE
-	bool
-	depends on SMP || X86_VISWS
-	default y
-
 config PC
 	bool
 	depends on X86 && !EMBEDDED
--- diff/arch/i386/Makefile	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/i386/Makefile	2004-03-09 11:51:48.000000000 +0000
@@ -19,7 +19,7 @@ LDFLAGS		:= -m elf_i386
 OBJCOPYFLAGS	:= -O binary -R .note -R .comment -S
 LDFLAGS_vmlinux :=
 
-CFLAGS += -pipe
+CFLAGS += -pipe -msoft-float
 
 # prevent gcc from keeping the stack 16 byte aligned
 CFLAGS += $(call check_gcc,-mpreferred-stack-boundary=2,)
@@ -56,9 +56,9 @@ cflags-$(CONFIG_X86_ELAN)	+= -march=i486
 GCC_VERSION			:= $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC))
 cflags-$(CONFIG_REGPARM) 	+= $(shell if [ $(GCC_VERSION) -ge 0300 ] ; then echo "-mregparm=3"; fi ;)
 
-# Enable unit-at-a-time mode when possible. It shrinks the
-# kernel considerably.
-CFLAGS += $(call check_gcc,-funit-at-a-time,)
+# Disable unit-at-a-time mode, it makes gcc use a lot more stack
+# due to the lack of sharing of stacklots.
+CFLAGS += $(call check_gcc,-fno-unit-at-a-time,)
 
 CFLAGS += $(cflags-y)
 
@@ -97,6 +97,9 @@ mcore-$(CONFIG_X86_ES7000)	:= mach-es700
 # default subarch .h files
 mflags-y += -Iinclude/asm-i386/mach-default
 
+mflags-$(CONFIG_KGDB) += -gdwarf-2
+mflags-$(CONFIG_KGDB_MORE) += $(shell echo $(CONFIG_KGDB_OPTIONS) | sed -e 's/"//g')
+
 head-y := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
 
 libs-y 					+= arch/i386/lib/
--- diff/arch/i386/boot/setup.S	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/i386/boot/setup.S	2004-03-09 11:51:48.000000000 +0000
@@ -164,7 +164,7 @@ cmd_line_ptr:	.long 0			# (Header versio
 					# can be located anywhere in
 					# low memory 0x10000 or higher.
 
-ramdisk_max:	.long MAXMEM-1		# (Header version 0x0203 or later)
+ramdisk_max:	.long __MAXMEM-1	# (Header version 0x0203 or later)
 					# The highest safe address for
 					# the contents of an initrd
 
--- diff/arch/i386/boot/tools/build.c	2003-05-21 11:49:49.000000000 +0100
+++ source/arch/i386/boot/tools/build.c	2004-03-09 11:51:48.000000000 +0000
@@ -150,10 +150,8 @@ int main(int argc, char ** argv)
 	sz = sb.st_size;
 	fprintf (stderr, "System is %d kB\n", sz/1024);
 	sys_size = (sz + 15) / 16;
-	/* 0x40000*16 = 4.0 MB, reasonable estimate for the current maximum */
-	if (sys_size > (is_big_kernel ? 0x40000 : DEF_SYSSIZE))
-		die("System is too big. Try using %smodules.",
-			is_big_kernel ? "" : "bzImage or ");
+	if (!is_big_kernel && sys_size > DEF_SYSSIZE)
+		die("System is too big. Try using bzImage or modules.");
 	while (sz > 0) {
 		int l, n;
 
--- diff/arch/i386/defconfig	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/i386/defconfig	2004-03-09 11:51:48.000000000 +0000
@@ -1212,5 +1212,4 @@ CONFIG_CRC32=y
 CONFIG_X86_SMP=y
 CONFIG_X86_HT=y
 CONFIG_X86_BIOS_REBOOT=y
-CONFIG_X86_TRAMPOLINE=y
 CONFIG_PC=y
--- diff/arch/i386/kernel/Makefile	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/i386/kernel/Makefile	2004-03-09 11:51:48.000000000 +0000
@@ -7,19 +7,19 @@ extra-y := head.o init_task.o vmlinux.ld
 obj-y	:= process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
 		ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
 		pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \
-		doublefault.o
+		doublefault.o entry_trampoline.o
 
 obj-y				+= cpu/
 obj-y				+= timers/
 obj-$(CONFIG_ACPI_BOOT)		+= acpi/
 obj-$(CONFIG_X86_BIOS_REBOOT)	+= reboot.o
 obj-$(CONFIG_MCA)		+= mca.o
+obj-$(CONFIG_KGDB)		+= kgdb_stub.o
 obj-$(CONFIG_X86_MSR)		+= msr.o
 obj-$(CONFIG_X86_CPUID)		+= cpuid.o
 obj-$(CONFIG_MICROCODE)		+= microcode.o
 obj-$(CONFIG_APM)		+= apm.o
-obj-$(CONFIG_X86_SMP)		+= smp.o smpboot.o
-obj-$(CONFIG_X86_TRAMPOLINE)	+= trampoline.o
+obj-$(CONFIG_X86_SMP)		+= smp.o smpboot.o trampoline.o
 obj-$(CONFIG_X86_MPPARSE)	+= mpparse.o
 obj-$(CONFIG_X86_LOCAL_APIC)	+= apic.o nmi.o
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
--- diff/arch/i386/kernel/acpi/boot.c	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/i386/kernel/acpi/boot.c	2004-03-09 11:51:48.000000000 +0000
@@ -35,7 +35,7 @@
 #include <asm/irq.h>
 #include <asm/mpspec.h>
 
-#if defined (CONFIG_X86_LOCAL_APIC)
+#ifdef CONFIG_X86_LOCAL_APIC
 #include <mach_apic.h>
 #include <mach_mpparse.h>
 #include <asm/io_apic.h>
@@ -43,17 +43,26 @@
 
 #define PREFIX			"ACPI: "
 
-int acpi_noirq __initdata = 0;	/* skip ACPI IRQ initialization */
+int acpi_noirq __initdata;	/* skip ACPI IRQ initialization */
 int acpi_ht __initdata = 1;	/* enable HT */
 
 int acpi_lapic;
 int acpi_ioapic;
+int acpi_strict;
+
+#ifdef CONFIG_X86_LOCAL_APIC
+static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
+#endif
 
 /* --------------------------------------------------------------------------
                               Boot-time Configuration
    -------------------------------------------------------------------------- */
 
-enum acpi_irq_model_id		acpi_irq_model;
+/*
+ * The default interrupt routing model is PIC (8259).  This gets
+ * overriden if IOAPICs are enumerated (below).
+ */
+enum acpi_irq_model_id		acpi_irq_model = ACPI_IRQ_MODEL_PIC;
 
 /*
  * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END,
@@ -96,11 +105,32 @@ char *__acpi_map_table(unsigned long phy
 }
 
 
-#ifdef CONFIG_X86_LOCAL_APIC
+#ifdef CONFIG_PCI_MMCONFIG
+static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
+{
+	struct acpi_table_mcfg *mcfg;
 
-static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
+	if (!phys_addr || !size)
+		return -EINVAL;
+
+	mcfg = (struct acpi_table_mcfg *) __acpi_map_table(phys_addr, size);
+	if (!mcfg) {
+		printk(KERN_WARNING PREFIX "Unable to map MCFG\n");
+		return -ENODEV;
+	}
 
+	if (mcfg->base_reserved) {
+		printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n");
+		return -ENODEV;
+	}
+
+	pci_mmcfg_base_addr = mcfg->base_address;
+
+	return 0;
+}
+#endif /* CONFIG_PCI_MMCONFIG */
 
+#ifdef CONFIG_X86_LOCAL_APIC
 static int __init
 acpi_parse_madt (
 	unsigned long		phys_addr,
@@ -117,11 +147,12 @@ acpi_parse_madt (
 		return -ENODEV;
 	}
 
-	if (madt->lapic_address)
+	if (madt->lapic_address) {
 		acpi_lapic_addr = (u64) madt->lapic_address;
 
-	printk(KERN_INFO PREFIX "Local APIC address 0x%08x\n",
-		madt->lapic_address);
+		printk(KERN_DEBUG PREFIX "Local APIC address 0x%08x\n",
+			madt->lapic_address);
+	}
 
 	acpi_madt_oem_check(madt->header.oem_id, madt->header.oem_table_id);
 	
@@ -251,7 +282,7 @@ acpi_parse_nmi_src (
 	return 0;
 }
 
-#endif /*CONFIG_X86_IO_APIC*/
+#endif /* CONFIG_X86_IO_APIC */
 
 #ifdef	CONFIG_ACPI_BUS
 /*
@@ -259,7 +290,7 @@ acpi_parse_nmi_src (
  * programs the PIC-mode SCI to Level Trigger.
  * (NO-OP if the BIOS set Level Trigger already)
  *
- * If a PIC-mode SCI is not recogznied or gives spurious IRQ7's
+ * If a PIC-mode SCI is not recognized or gives spurious IRQ7's
  * it may require Edge Trigger -- use "acpi_pic_sci=edge"
  * (NO-OP if the BIOS set Edge Trigger already)
  *
@@ -339,7 +370,7 @@ acpi_scan_rsdp (
 	 * RSDP signature.
 	 */
 	for (offset = 0; offset < length; offset += 16) {
-		if (strncmp((char *) (start + offset), "RSD PTR ", sig_len))
+		if (strncmp((char *) __va(start + offset), "RSD PTR ", sig_len))
 			continue;
 		return (start + offset);
 	}
@@ -347,6 +378,25 @@ acpi_scan_rsdp (
 	return 0;
 }
 
+static int __init acpi_parse_sbf(unsigned long phys_addr, unsigned long size)
+{
+	struct acpi_table_sbf *sb;
+
+	if (!phys_addr || !size)
+	return -EINVAL;
+
+	sb = (struct acpi_table_sbf *) __acpi_map_table(phys_addr, size);
+	if (!sb) {
+		printk(KERN_WARNING PREFIX "Unable to map SBF\n");
+		return -ENODEV;
+	}
+
+	sbf_port = sb->sbf_cmos; /* Save CMOS port */
+
+	return 0;
+}
+
+
 #ifdef CONFIG_HPET_TIMER
 extern unsigned long hpet_address;
 
@@ -429,126 +479,61 @@ acpi_find_rsdp (void)
 	return rsdp_phys;
 }
 
+#ifdef	CONFIG_X86_LOCAL_APIC
 /*
- * acpi_boot_init()
- *  called from setup_arch(), always.
- *	1. maps ACPI tables for later use
- *	2. enumerates lapics
- *	3. enumerates io-apics
- *
- * side effects:
- *	acpi_lapic = 1 if LAPIC found
- *	acpi_ioapic = 1 if IOAPIC found
- *	if (acpi_lapic && acpi_ioapic) smp_found_config = 1;
- *	if acpi_blacklisted() acpi_disabled = 1;
- *	acpi_irq_model=...
- *	...
- *
- * return value: (currently ignored)
- *	0: success
- *	!0: failure
+ * Parse LAPIC entries in MADT
+ * returns 0 on success, < 0 on error
  */
-
-int __init
-acpi_boot_init (void)
+static int __init
+acpi_parse_madt_lapic_entries(void)
 {
-	int			result = 0;
-
-	if (acpi_disabled && !acpi_ht)
-		 return 1;
-
-	/*
-	 * The default interrupt routing model is PIC (8259).  This gets
-	 * overriden if IOAPICs are enumerated (below).
-	 */
-	acpi_irq_model = ACPI_IRQ_MODEL_PIC;
-
-	/* 
-	 * Initialize the ACPI boot-time table parser.
-	 */
-	result = acpi_table_init();
-	if (result) {
-		acpi_disabled = 1;
-		return result;
-	}
-
-	result = acpi_blacklisted();
-	if (result) {
-		printk(KERN_WARNING PREFIX "BIOS listed in blacklist, disabling ACPI support\n");
-		acpi_disabled = 1;
-		return result;
-	}
-
-#ifdef CONFIG_X86_PM_TIMER
-	acpi_table_parse(ACPI_FADT, acpi_parse_fadt);
-#endif
-
-#ifdef CONFIG_X86_LOCAL_APIC
-
-	/* 
-	 * MADT
-	 * ----
-	 * Parse the Multiple APIC Description Table (MADT), if exists.
-	 * Note that this table provides platform SMP configuration 
-	 * information -- the successor to MPS tables.
-	 */
-
-	result = acpi_table_parse(ACPI_APIC, acpi_parse_madt);
-	if (!result) {
-		return 0;
-	}
-	else if (result < 0) {
-		printk(KERN_ERR PREFIX "Error parsing MADT\n");
-		return result;
-	}
-	else if (result > 1) 
-		printk(KERN_WARNING PREFIX "Multiple MADT tables exist\n");
+	int count;
 
 	/* 
-	 * Local APIC
-	 * ----------
 	 * Note that the LAPIC address is obtained from the MADT (32-bit value)
 	 * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value).
 	 */
 
-	result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0);
-	if (result < 0) {
+	count = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0);
+	if (count < 0) {
 		printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n");
-		return result;
+		return count;
 	}
 
 	mp_register_lapic_address(acpi_lapic_addr);
 
-	result = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic,
+	count = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic,
 				       MAX_APICS);
-	if (!result) { 
+	if (!count) { 
 		printk(KERN_ERR PREFIX "No LAPIC entries present\n");
 		/* TBD: Cleanup to allow fallback to MPS */
 		return -ENODEV;
 	}
-	else if (result < 0) {
+	else if (count < 0) {
 		printk(KERN_ERR PREFIX "Error parsing LAPIC entry\n");
 		/* TBD: Cleanup to allow fallback to MPS */
-		return result;
+		return count;
 	}
 
-	result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0);
-	if (result < 0) {
+	count = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0);
+	if (count < 0) {
 		printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
 		/* TBD: Cleanup to allow fallback to MPS */
-		return result;
+		return count;
 	}
-
-	acpi_lapic = 1;
-
-#endif /*CONFIG_X86_LOCAL_APIC*/
+	return 0;
+}
+#endif /* CONFIG_X86_LOCAL_APIC */
 
 #if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_ACPI_INTERPRETER)
-
-	/* 
-	 * I/O APIC 
-	 * --------
-	 */
+/*
+ * Parse IOAPIC related entries in MADT
+ * returns 0 on success, < 0 on error
+ */
+static int __init
+acpi_parse_madt_ioapic_entries(void)
+{
+	int count;
 
 	/*
 	 * ACPI interpreter is required to complete interrupt setup,
@@ -557,7 +542,7 @@ acpi_boot_init (void)
 	 * otherwise the system will stay in PIC mode
 	 */
 	if (acpi_disabled || acpi_noirq) {
-		return 1;
+		return -ENODEV;
         }
 
 	/*
@@ -566,54 +551,152 @@ acpi_boot_init (void)
 	if (ioapic_setup_disabled()) {
 		printk(KERN_INFO PREFIX "Skipping IOAPIC probe "
 			"due to 'noapic' option.\n");
-		return 1;
+		return -ENODEV;
 	}
 
-	result = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic, MAX_IO_APICS);
-	if (!result) {
+	count = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic, MAX_IO_APICS);
+	if (!count) {
 		printk(KERN_ERR PREFIX "No IOAPIC entries present\n");
 		return -ENODEV;
 	}
-	else if (result < 0) {
+	else if (count < 0) {
 		printk(KERN_ERR PREFIX "Error parsing IOAPIC entry\n");
-		return result;
+		return count;
 	}
 
 	/* Build a default routing table for legacy (ISA) interrupts. */
 	mp_config_acpi_legacy_irqs();
 
-	result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, NR_IRQ_VECTORS);
-	if (result < 0) {
+	count = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, NR_IRQ_VECTORS);
+	if (count < 0) {
 		printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n");
 		/* TBD: Cleanup to allow fallback to MPS */
-		return result;
+		return count;
 	}
 
-	result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, NR_IRQ_VECTORS);
-	if (result < 0) {
+	count = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, NR_IRQ_VECTORS);
+	if (count < 0) {
 		printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
 		/* TBD: Cleanup to allow fallback to MPS */
-		return result;
+		return count;
 	}
 
-	acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
+	return 0;
+}
+#else
+static inline int acpi_parse_madt_ioapic_entries(void)
+{
+	return -1;
+}
+#endif /* !(CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER) */
 
-	acpi_irq_balance_set(NULL);
 
-	acpi_ioapic = 1;
+static void __init
+acpi_process_madt(void)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+	int count, error;
 
-#endif /* CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER */
+	count = acpi_table_parse(ACPI_APIC, acpi_parse_madt);
+	if (count == 1) {
 
-#ifdef CONFIG_X86_LOCAL_APIC
-	if (acpi_lapic && acpi_ioapic) {
-		smp_found_config = 1;
-		clustered_apic_check();
+		/*
+		 * Parse MADT LAPIC entries
+		 */
+		error = acpi_parse_madt_lapic_entries();
+		if (!error) {
+			acpi_lapic = 1;
+
+			/*
+			 * Parse MADT IO-APIC entries
+			 */
+			error = acpi_parse_madt_ioapic_entries();
+			if (!error) {
+				acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
+				acpi_irq_balance_set(NULL);
+				acpi_ioapic = 1;
+
+				smp_found_config = 1;
+				clustered_apic_check();
+			}
+		}
 	}
 #endif
+	return;
+}
+
+/*
+ * acpi_boot_init()
+ *  called from setup_arch(), always.
+ *	1. checksums all tables
+ *	2. enumerates lapics
+ *	3. enumerates io-apics
+ *
+ * side effects:
+ *	acpi_lapic = 1 if LAPIC found
+ *	acpi_ioapic = 1 if IOAPIC found
+ *	if (acpi_lapic && acpi_ioapic) smp_found_config = 1;
+ *	if acpi_blacklisted() acpi_disabled = 1;
+ *	acpi_irq_model=...
+ *	...
+ *
+ * return value: (currently ignored)
+ *	0: success
+ *	!0: failure
+ */
+
+int __init
+acpi_boot_init (void)
+{
+	int error;
+
+	/*
+	 * If acpi_disabled, bail out
+	 * One exception: acpi=ht continues far enough to enumerate LAPICs
+	 */
+	if (acpi_disabled && !acpi_ht)
+		 return 1;
+
+	/* 
+	 * Initialize the ACPI boot-time table parser.
+	 */
+	error = acpi_table_init();
+	if (error) {
+		acpi_disabled = 1;
+		return error;
+	}
+
+	(void) acpi_table_parse(ACPI_BOOT, acpi_parse_sbf);
+
+	/*
+	 * blacklist may disable ACPI entirely
+	 */
+	error = acpi_blacklisted();
+	if (error) {
+		printk(KERN_WARNING PREFIX "BIOS listed in blacklist, disabling ACPI support\n");
+		acpi_disabled = 1;
+		return error;
+	}
+
+	/*
+	 * Process the Multiple APIC Description Table (MADT), if present
+	 */
+	acpi_process_madt();
+
+#ifdef CONFIG_X86_PM_TIMER
+	acpi_table_parse(ACPI_FADT, acpi_parse_fadt);
+#endif
 
 #ifdef CONFIG_HPET_TIMER
-	acpi_table_parse(ACPI_HPET, acpi_parse_hpet);
+	(void) acpi_table_parse(ACPI_HPET, acpi_parse_hpet);
+#endif
+
+#ifdef CONFIG_PCI_MMCONFIG
+	error = acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+	if (error)
+		printk(KERN_ERR PREFIX "Error %d parsing MCFG\n", error);
 #endif
 
 	return 0;
 }
+
--- diff/arch/i386/kernel/apic.c	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/i386/kernel/apic.c	2004-03-09 11:51:48.000000000 +0000
@@ -1182,9 +1182,6 @@ int __init APIC_init_uniprocessor (void)
 	phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid);
 
 	setup_local_APIC();
-
-	if (nmi_watchdog == NMI_LOCAL_APIC)
-		check_nmi_watchdog();
 #ifdef CONFIG_X86_IO_APIC
 	if (smp_found_config)
 		if (!skip_ioapic_setup && nr_ioapics)
--- diff/arch/i386/kernel/asm-offsets.c	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/kernel/asm-offsets.c	2004-03-09 11:51:48.000000000 +0000
@@ -4,9 +4,11 @@
  * to extract and format the required data.
  */
 
+#include <linux/sched.h>
 #include <linux/signal.h>
 #include <asm/ucontext.h>
 #include "sigframe.h"
+#include <asm/fixmap.h>
 
 #define DEFINE(sym, val) \
         asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -28,4 +30,20 @@ void foo(void)
 
 	DEFINE(RT_SIGFRAME_sigcontext,
 	       offsetof (struct rt_sigframe, uc.uc_mcontext));
+
+	DEFINE(TI_task, offsetof (struct thread_info, task));
+	DEFINE(TI_exec_domain, offsetof (struct thread_info, exec_domain));
+	DEFINE(TI_flags, offsetof (struct thread_info, flags));
+	DEFINE(TI_preempt_count, offsetof (struct thread_info, preempt_count));
+	DEFINE(TI_addr_limit, offsetof (struct thread_info, addr_limit));
+	DEFINE(TI_real_stack, offsetof (struct thread_info, real_stack));
+	DEFINE(TI_virtual_stack, offsetof (struct thread_info, virtual_stack));
+	DEFINE(TI_user_pgd, offsetof (struct thread_info, user_pgd));
+
+	DEFINE(FIX_ENTRY_TRAMPOLINE_0_addr,
+			__fix_to_virt(FIX_ENTRY_TRAMPOLINE_0));
+	DEFINE(FIX_VSYSCALL_addr, __fix_to_virt(FIX_VSYSCALL));
+	DEFINE(PAGE_SIZE_asm, PAGE_SIZE);
+	DEFINE(task_thread_db7,
+		offsetof (struct task_struct, thread.debugreg[7]));
 }
--- diff/arch/i386/kernel/bootflag.c	2002-12-30 10:17:12.000000000 +0000
+++ source/arch/i386/kernel/bootflag.c	2004-03-09 11:51:48.000000000 +0000
@@ -1,6 +1,5 @@
 /*
- *	Implement 'Simple Boot Flag Specification 1.0'
- *
+ *	Implement 'Simple Boot Flag Specification 2.0'
  */
 
 
@@ -11,6 +10,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/acpi.h>
 #include <asm/io.h>
 
 #include <linux/mc146818rtc.h>
@@ -23,56 +23,8 @@
 #define SBF_PARITY   (1<<7)
 
 
-struct sbf_boot
-{
-	u8 sbf_signature[4];
-	u32 sbf_len;
-	u8 sbf_revision __attribute((packed));
-	u8 sbf_csum __attribute((packed));
-	u8 sbf_oemid[6] __attribute((packed));
-	u8 sbf_oemtable[8] __attribute((packed));
-	u8 sbf_revdata[4] __attribute((packed));
-	u8 sbf_creator[4] __attribute((packed));
-	u8 sbf_crearev[4] __attribute((packed));
-	u8 sbf_cmos __attribute((packed));
-	u8 sbf_spare[3] __attribute((packed));
-};
-
-
-static int sbf_port __initdata = -1;
-
-static int __init sbf_struct_valid(unsigned long tptr)
-{
-	u8 *ap;
-	u8 v;
-	unsigned int i;
-	struct sbf_boot sb;
-	
-	memcpy_fromio(&sb, (void *)tptr, sizeof(sb));
-
-	if(sb.sbf_len != 40 && sb.sbf_len != 39)
-		// 39 on IBM ThinkPad A21m, BIOS version 1.02b (KXET24WW; 2000-12-19).
-		return 0;
-
-	ap = (u8 *)&sb;
-	v= 0;
-	
-	for(i=0;i<sb.sbf_len;i++)
-		v+=*ap++;
-		
-	if(v)
-		return 0;
-
-	if(memcmp(sb.sbf_signature, "BOOT", 4))
-		return 0;
+int sbf_port __initdata = -1;	/* set via acpi_boot_init() */
 
-	if (sb.sbf_len == 39)
-		printk (KERN_WARNING "SBF: ACPI BOOT descriptor is wrong length (%d)\n",
-			sb.sbf_len);
-
-	sbf_port = sb.sbf_cmos;	/* Save CMOS port */
-	return 1;
-}
 
 static int __init parity(u8 v)
 {
@@ -96,7 +48,7 @@ static void __init sbf_write(u8 v)
 		if(!parity(v))
 			v|=SBF_PARITY;
 
-		printk(KERN_INFO "SBF: Setting boot flags 0x%x\n",v);
+		printk(KERN_INFO "Simple Boot Flag 0x%x\n", v);
 
 		spin_lock_irqsave(&rtc_lock, flags);
 		CMOS_WRITE(v, sbf_port);
@@ -125,15 +77,15 @@ static int __init sbf_value_valid(u8 v)
 	return 1;
 }
 
-
-static void __init sbf_bootup(void)
+static int __init sbf_init(void)
 {
 	u8 v;
 	if(sbf_port == -1)
-		return;
+		return 0;
 	v = sbf_read();
 	if(!sbf_value_valid(v))
-		printk(KERN_WARNING "SBF: Simple boot flag value 0x%x read from CMOS RAM was invalid\n",v);
+		printk(KERN_WARNING "Simple Boot Flag value 0x%x read from CMOS RAM was invalid\n",v);
+
 	v &= ~SBF_RESERVED;
 	v &= ~SBF_BOOTING;
 	v &= ~SBF_DIAG;
@@ -141,112 +93,6 @@ static void __init sbf_bootup(void)
 	v |= SBF_PNPOS;
 #endif
 	sbf_write(v);
-}
-
-static int __init sbf_init(void)
-{
-	unsigned int i;
-	void *rsdt;
-	u32 rsdtlen = 0;
-	u32 rsdtbase = 0;
-	u8 sum = 0;
-	int n;
-	
-	u8 *p;
-	
-	for(i=0xE0000; i <= 0xFFFE0; i+=16)
-	{
-		p = phys_to_virt(i);
-		
-		if(memcmp(p, "RSD PTR ", 8))
-			continue;
-		
-		sum = 0;
-		for(n=0; n<20; n++)
-			sum+=p[n];
-			
-		if(sum != 0)
-			continue;
-			
-		/* So it says RSD PTR and it checksums... */
-
-		/*
-		 *	Process the RDSP pointer
-		 */
-	 
-		rsdtbase = *(u32 *)(p+16);
-		
-		/*
-		 *	RSDT length is ACPI 2 only, for ACPI 1 we must map
-		 *	and remap.
-		 */
-		 
-		if(p[15]>1)
-			rsdtlen = *(u32 *)(p+20);
-		else
-			rsdtlen = 36;
-
-		if(rsdtlen < 36 || rsdtlen > 1024)
-			continue;
-		break;
-	}
-	if(i>0xFFFE0)
-		return 0;
-		
-		
-	rsdt = ioremap(rsdtbase, rsdtlen);
-	if(rsdt == 0)
-		return 0;
-		
-	i = readl(rsdt + 4);
-	
-	/*
-	 *	Remap if needed
-	 */
-	 
-	if(i > rsdtlen)
-	{
-		rsdtlen = i;
-		iounmap(rsdt);
-		rsdt = ioremap(rsdtbase, rsdtlen);
-		if(rsdt == 0)
-			return 0;
-	}
-	
-	for(n = 0; n < i; n++)
-		sum += readb(rsdt + n);
-		
-	if(sum)
-	{
-		iounmap(rsdt);
-		return 0;
-	}
-	
-	/* Ok the RSDT checksums too */
-	
-	for(n = 36; n+3 < i; n += 4)
-	{
-		unsigned long rp = readl(rsdt+n);
-		int len = 4096;
-
-		if(rp > 0xFFFFFFFFUL - len)
-			len = 0xFFFFFFFFUL - rp;
-			
-		/* Too close to the end!! */
-		if(len < 20)
-			continue;
-		rp = (unsigned long)ioremap(rp, 4096);
-		if(rp == 0)
-			continue;
-		if(sbf_struct_valid(rp))
-		{
-			/* Found the BOOT table and processed it */
-			printk(KERN_INFO "SBF: Simple Boot Flag extension found and enabled.\n");
-		}
-		iounmap((void *)rp);
-	}
-	iounmap(rsdt);
-	sbf_bootup();
 	return 0;
 }
 
--- diff/arch/i386/kernel/cpu/centaur.c	2003-05-21 11:49:49.000000000 +0100
+++ source/arch/i386/kernel/cpu/centaur.c	2004-03-09 11:51:48.000000000 +0000
@@ -246,7 +246,15 @@ static void __init winchip2_protect_mcr(
 	lo&=~0x1C0;	/* blank bits 8-6 */
 	wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
 }
-#endif
+#endif /* CONFIG_X86_OOSTORE */
+
+#define ACE_PRESENT	(1 << 6)
+#define ACE_ENABLED	(1 << 7)
+#define ACE_FCR		(1 << 28)	/* MSR_VIA_FCR */
+
+#define RNG_PRESENT	(1 << 2)
+#define RNG_ENABLED	(1 << 3)
+#define RNG_ENABLE	(1 << 6)	/* MSR_VIA_RNG */
 
 static void __init init_c3(struct cpuinfo_x86 *c)
 {
@@ -254,6 +262,24 @@ static void __init init_c3(struct cpuinf
 
 	/* Test for Centaur Extended Feature Flags presence */
 	if (cpuid_eax(0xC0000000) >= 0xC0000001) {
+		u32 tmp = cpuid_edx(0xC0000001);
+
+		/* enable ACE unit, if present and disabled */
+		if ((tmp & (ACE_PRESENT | ACE_ENABLED)) == ACE_PRESENT) {
+			rdmsr (MSR_VIA_FCR, lo, hi);
+			lo |= ACE_FCR;		/* enable ACE unit */
+			wrmsr (MSR_VIA_FCR, lo, hi);
+			printk(KERN_INFO "CPU: Enabled ACE h/w crypto\n");
+		}
+
+		/* enable RNG unit, if present and disabled */
+		if ((tmp & (RNG_PRESENT | RNG_ENABLED)) == RNG_PRESENT) {
+			rdmsr (MSR_VIA_RNG, lo, hi);
+			lo |= RNG_ENABLE;	/* enable RNG unit */
+			wrmsr (MSR_VIA_RNG, lo, hi);
+			printk(KERN_INFO "CPU: Enabled h/w RNG\n");
+		}
+
 		/* store Centaur Extended Feature Flags as
 		 * word 5 of the CPU capability bit array
 		 */
--- diff/arch/i386/kernel/cpu/common.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/i386/kernel/cpu/common.c	2004-03-09 11:51:48.000000000 +0000
@@ -514,12 +514,16 @@ void __init cpu_init (void)
 	set_tss_desc(cpu,t);
 	cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff;
 	load_TR_desc();
-	load_LDT(&init_mm.context);
+	if (cpu)
+		load_LDT(&init_mm.context);
 
 	/* Set up doublefault TSS pointer in the GDT */
 	__set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss);
 	cpu_gdt_table[cpu][GDT_ENTRY_DOUBLEFAULT_TSS].b &= 0xfffffdff;
 
+	if (cpu)
+		trap_init_virtual_GDT();
+
 	/* Clear %fs and %gs. */
 	asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs");
 
--- diff/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c	2004-03-09 11:51:48.000000000 +0000
@@ -57,8 +57,7 @@ static int cpufreq_p4_setdc(unsigned int
 	u32 l, h;
 	cpumask_t cpus_allowed, affected_cpu_map;
 	struct cpufreq_freqs freqs;
-	int hyperthreading = 0;
-	int sibling = 0;
+	int j;
 
 	if (!cpu_online(cpu) || (newstate > DC_DISABLE) || 
 		(newstate == DC_RESV))
@@ -68,13 +67,10 @@ static int cpufreq_p4_setdc(unsigned int
 	cpus_allowed = current->cpus_allowed;
 
 	/* only run on CPU to be set, or on its sibling */
-       affected_cpu_map = cpumask_of_cpu(cpu);
-#ifdef CONFIG_X86_HT
-	hyperthreading = ((cpu_has_ht) && (smp_num_siblings == 2));
-	if (hyperthreading) {
-		sibling = cpu_sibling_map[cpu];
-                cpu_set(sibling, affected_cpu_map);
-	}
+#ifdef CONFIG_SMP
+	affected_cpu_map = cpu_sibling_map[cpu];
+#else
+	affected_cpu_map = cpumask_of_cpu(cpu);
 #endif
 	set_cpus_allowed(current, affected_cpu_map);
         BUG_ON(!cpu_isset(smp_processor_id(), affected_cpu_map));
@@ -97,11 +93,11 @@ static int cpufreq_p4_setdc(unsigned int
 	/* notifiers */
 	freqs.old = stock_freq * l / 8;
 	freqs.new = stock_freq * newstate / 8;
-	freqs.cpu = cpu;
-	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-	if (hyperthreading) {
-		freqs.cpu = sibling;
-		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	for_each_cpu(j) {
+		if (cpu_isset(j, affected_cpu_map)) {
+			freqs.cpu = j;
+			cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+		}
 	}
 
 	rdmsr(MSR_IA32_THERM_STATUS, l, h);
@@ -132,10 +128,11 @@ static int cpufreq_p4_setdc(unsigned int
 	set_cpus_allowed(current, cpus_allowed);
 
 	/* notifiers */
-	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-	if (hyperthreading) {
-		freqs.cpu = cpu;
-		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	for_each_cpu(j) {
+		if (cpu_isset(j, affected_cpu_map)) {
+			freqs.cpu = j;
+			cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+		}
 	}
 
 	return 0;
--- diff/arch/i386/kernel/cpu/intel.c	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/i386/kernel/cpu/intel.c	2004-03-09 11:51:48.000000000 +0000
@@ -10,6 +10,7 @@
 #include <asm/processor.h>
 #include <asm/msr.h>
 #include <asm/uaccess.h>
+#include <asm/desc.h>
 
 #include "cpu.h"
 
@@ -19,8 +20,6 @@
 #include <mach_apic.h>
 #endif
 
-extern int trap_init_f00f_bug(void);
-
 #ifdef CONFIG_X86_INTEL_USERCOPY
 /*
  * Alignment at which movsl is preferred for bulk memory copies.
@@ -165,7 +164,7 @@ static void __init init_intel(struct cpu
 
 		c->f00f_bug = 1;
 		if ( !f00f_workaround_enabled ) {
-			trap_init_f00f_bug();
+			trap_init_virtual_IDT();
 			printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n");
 			f00f_workaround_enabled = 1;
 		}
@@ -250,6 +249,12 @@ static void __init init_intel(struct cpu
 	/* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it until model 3 mask 3 */
 	if ((c->x86<<8 | c->x86_model<<4 | c->x86_mask) < 0x633)
 		clear_bit(X86_FEATURE_SEP, c->x86_capability);
+	/*
+	 * FIXME: SEP is disabled for 4G/4G for now:
+	 */
+#ifdef CONFIG_X86_HIGH_ENTRY
+	clear_bit(X86_FEATURE_SEP, c->x86_capability);
+#endif
 
 	/* Names for the Pentium II/Celeron processors 
 	   detectable only by also checking the cache size.
--- diff/arch/i386/kernel/cpu/mcheck/mce.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/i386/kernel/cpu/mcheck/mce.c	2004-03-09 11:51:48.000000000 +0000
@@ -7,6 +7,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/thread_info.h>
 
@@ -18,6 +19,8 @@
 int mce_disabled __initdata = 0;
 int nr_mce_banks;
 
+EXPORT_SYMBOL_GPL(nr_mce_banks);	/* non-fatal.o */
+
 /* Handle unconfigured int18 (should never happen) */
 static asmlinkage void unexpected_machine_check(struct pt_regs * regs, long error_code)
 {	
--- diff/arch/i386/kernel/cpu/proc.c	2003-08-26 10:00:51.000000000 +0100
+++ source/arch/i386/kernel/cpu/proc.c	2004-03-09 11:51:48.000000000 +0000
@@ -50,7 +50,7 @@ static int show_cpuinfo(struct seq_file 
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
 		/* VIA/Cyrix/Centaur-defined */
-		NULL, NULL, "xstore", NULL, NULL, NULL, NULL, NULL,
+		NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
--- diff/arch/i386/kernel/doublefault.c	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/kernel/doublefault.c	2004-03-09 11:51:48.000000000 +0000
@@ -7,12 +7,13 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/desc.h>
+#include <asm/fixmap.h>
 
 #define DOUBLEFAULT_STACKSIZE (1024)
 static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE];
 #define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE)
 
-#define ptr_ok(x) ((x) > 0xc0000000 && (x) < 0xc1000000)
+#define ptr_ok(x) (((x) > __PAGE_OFFSET && (x) < (__PAGE_OFFSET + 0x01000000)) || ((x) >= FIXADDR_START))
 
 static void doublefault_fn(void)
 {
@@ -38,8 +39,8 @@ static void doublefault_fn(void)
 
 			printk("eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx\n",
 				t->eax, t->ebx, t->ecx, t->edx);
-			printk("esi = %08lx, edi = %08lx\n",
-				t->esi, t->edi);
+			printk("esi = %08lx, edi = %08lx, ebp = %08lx\n",
+				t->esi, t->edi, t->ebp);
 		}
 	}
 
--- diff/arch/i386/kernel/entry.S	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/i386/kernel/entry.S	2004-03-09 11:51:48.000000000 +0000
@@ -43,11 +43,25 @@
 #include <linux/config.h>
 #include <linux/linkage.h>
 #include <asm/thread_info.h>
+#include <asm/asm_offsets.h>
 #include <asm/errno.h>
 #include <asm/segment.h>
+#include <asm/page.h>
 #include <asm/smp.h>
 #include <asm/page.h>
 #include "irq_vectors.h"
+        /* We do not recover from a stack overflow, but at least
+         * we know it happened and should be able to track it down.
+         */
+#ifdef CONFIG_STACK_OVERFLOW_TEST
+#define STACK_OVERFLOW_TEST \
+        testl $7680,%esp;    \
+        jnz   10f;            \
+        call  stack_overflow; \
+10:
+#else
+#define STACK_OVERFLOW_TEST
+#endif
 
 #define nr_syscalls ((syscall_table_size)/4)
 
@@ -87,7 +101,102 @@ TSS_ESP0_OFFSET = (4 - 0x200)
 #define resume_kernel		restore_all
 #endif
 
-#define SAVE_ALL \
+#ifdef CONFIG_X86_HIGH_ENTRY
+
+#ifdef CONFIG_X86_SWITCH_PAGETABLES
+
+#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)
+/*
+ * If task is preempted in __SWITCH_KERNELSPACE, and moved to another cpu,
+ * __switch_to repoints %esp to the appropriate virtual stack; but %ebp is
+ * left stale, so we must check whether to repeat the real stack calculation.
+ */
+#define repeat_if_esp_changed				\
+	xorl %esp, %ebp;				\
+	testl $-THREAD_SIZE, %ebp;			\
+	jnz 0b
+#else
+#define repeat_if_esp_changed
+#endif
+
+/* clobbers ebx, edx and ebp */
+
+#define __SWITCH_KERNELSPACE				\
+	cmpl $0xff000000, %esp;				\
+	jb 1f;						\
+							\
+	/*						\
+	 * switch pagetables and load the real stack,	\
+	 * keep the stack offset:			\
+	 */						\
+							\
+	movl $swapper_pg_dir-__PAGE_OFFSET, %edx;	\
+							\
+	/* GET_THREAD_INFO(%ebp) intermixed */		\
+0:							\
+	movl %esp, %ebp;				\
+	movl %esp, %ebx;				\
+	andl $(-THREAD_SIZE), %ebp;				\
+	andl $(THREAD_SIZE-1), %ebx;				\
+	orl TI_real_stack(%ebp), %ebx;			\
+	repeat_if_esp_changed;				\
+							\
+	movl %edx, %cr3;				\
+	movl %ebx, %esp;				\
+1:
+
+#endif
+
+
+#define __SWITCH_USERSPACE \
+	/* interrupted any of the user return paths? */	\
+							\
+	movl EIP(%esp), %eax;				\
+							\
+	cmpl $int80_ret_start_marker, %eax;		\
+	jb 33f; /* nope - continue with sysexit check */\
+	cmpl $int80_ret_end_marker, %eax;		\
+	jb 22f; /* yes - switch to virtual stack */	\
+33:							\
+	cmpl $sysexit_ret_start_marker, %eax;		\
+	jb 44f; /* nope - continue with user check */	\
+	cmpl $sysexit_ret_end_marker, %eax;		\
+	jb 22f; /* yes - switch to virtual stack */	\
+	/* return to userspace? */			\
+44:							\
+	movl EFLAGS(%esp),%ecx;				\
+	movb CS(%esp),%cl;				\
+	testl $(VM_MASK | 3),%ecx;			\
+	jz 2f;						\
+22:							\
+	/*						\
+	 * switch to the virtual stack, then switch to	\
+	 * the userspace pagetables.			\
+	 */						\
+							\
+	GET_THREAD_INFO(%ebp);				\
+	movl TI_virtual_stack(%ebp), %edx;		\
+	movl TI_user_pgd(%ebp), %ecx;			\
+							\
+	movl %esp, %ebx;				\
+	andl $(THREAD_SIZE-1), %ebx;				\
+	orl %ebx, %edx;					\
+int80_ret_start_marker:					\
+	movl %edx, %esp; 				\
+	movl %ecx, %cr3;				\
+							\
+	__RESTORE_ALL;					\
+int80_ret_end_marker:					\
+2:
+
+#else /* !CONFIG_X86_HIGH_ENTRY */
+
+#define __SWITCH_KERNELSPACE
+#define __SWITCH_USERSPACE
+
+#endif
+
+#define __SAVE_ALL \
 	cld; \
 	pushl %es; \
 	pushl %ds; \
@@ -102,7 +211,7 @@ TSS_ESP0_OFFSET = (4 - 0x200)
 	movl %edx, %ds; \
 	movl %edx, %es;
 
-#define RESTORE_INT_REGS \
+#define __RESTORE_INT_REGS \
 	popl %ebx;	\
 	popl %ecx;	\
 	popl %edx;	\
@@ -111,29 +220,28 @@ TSS_ESP0_OFFSET = (4 - 0x200)
 	popl %ebp;	\
 	popl %eax
 
-#define RESTORE_REGS	\
-	RESTORE_INT_REGS; \
-1:	popl %ds;	\
-2:	popl %es;	\
+#define __RESTORE_REGS	\
+	__RESTORE_INT_REGS; \
+111:	popl %ds;	\
+222:	popl %es;	\
 .section .fixup,"ax";	\
-3:	movl $0,(%esp);	\
-	jmp 1b;		\
-4:	movl $0,(%esp);	\
-	jmp 2b;		\
+444:	movl $0,(%esp);	\
+	jmp 111b;	\
+555:	movl $0,(%esp);	\
+	jmp 222b;	\
 .previous;		\
 .section __ex_table,"a";\
 	.align 4;	\
-	.long 1b,3b;	\
-	.long 2b,4b;	\
+	.long 111b,444b;\
+	.long 222b,555b;\
 .previous
 
-
-#define RESTORE_ALL	\
-	RESTORE_REGS	\
+#define __RESTORE_ALL	\
+	__RESTORE_REGS	\
 	addl $4, %esp;	\
-1:	iret;		\
+333:	iret;		\
 .section .fixup,"ax";   \
-2:	sti;		\
+666:	sti;		\
 	movl $(__USER_DS), %edx; \
 	movl %edx, %ds; \
 	movl %edx, %es; \
@@ -142,10 +250,19 @@ TSS_ESP0_OFFSET = (4 - 0x200)
 .previous;		\
 .section __ex_table,"a";\
 	.align 4;	\
-	.long 1b,2b;	\
+	.long 333b,666b;\
 .previous
 
+#define SAVE_ALL \
+	__SAVE_ALL;					\
+	__SWITCH_KERNELSPACE;				\
+        STACK_OVERFLOW_TEST;
+
+#define RESTORE_ALL					\
+	__SWITCH_USERSPACE;				\
+	__RESTORE_ALL;
 
+.section .entry.text,"ax"
 
 ENTRY(lcall7)
 	pushfl			# We get a different stack layout with call
@@ -163,7 +280,7 @@ do_lcall:
 	movl %edx,EIP(%ebp)	# Now we move them to their "normal" places
 	movl %ecx,CS(%ebp)	#
 	GET_THREAD_INFO_WITH_ESP(%ebp)	# GET_THREAD_INFO
-	movl TI_EXEC_DOMAIN(%ebp), %edx	# Get the execution domain
+	movl TI_exec_domain(%ebp), %edx	# Get the execution domain
 	call *4(%edx)		# Call the lcall7 handler for the domain
 	addl $4, %esp
 	popl %eax
@@ -208,7 +325,7 @@ ENTRY(resume_userspace)
  	cli				# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
-	movl TI_FLAGS(%ebp), %ecx
+	movl TI_flags(%ebp), %ecx
 	andl $_TIF_WORK_MASK, %ecx	# is there any work to be done on
 					# int/exception return?
 	jne work_pending
@@ -216,18 +333,18 @@ ENTRY(resume_userspace)
 
 #ifdef CONFIG_PREEMPT
 ENTRY(resume_kernel)
-	cmpl $0,TI_PRE_COUNT(%ebp)	# non-zero preempt_count ?
+	cmpl $0,TI_preempt_count(%ebp)	# non-zero preempt_count ?
 	jnz restore_all
 need_resched:
-	movl TI_FLAGS(%ebp), %ecx	# need_resched set ?
+	movl TI_flags(%ebp), %ecx	# need_resched set ?
 	testb $_TIF_NEED_RESCHED, %cl
 	jz restore_all
 	testl $IF_MASK,EFLAGS(%esp)     # interrupts off (exception path) ?
 	jz restore_all
-	movl $PREEMPT_ACTIVE,TI_PRE_COUNT(%ebp)
+	movl $PREEMPT_ACTIVE,TI_preempt_count(%ebp)
 	sti
 	call schedule
-	movl $0,TI_PRE_COUNT(%ebp)
+	movl $0,TI_preempt_count(%ebp)
 	cli
 	jmp need_resched
 #endif
@@ -246,37 +363,50 @@ sysenter_past_esp:
 	pushl $(__USER_CS)
 	pushl $SYSENTER_RETURN
 
-/*
- * Load the potential sixth argument from user stack.
- * Careful about security.
- */
-	cmpl $__PAGE_OFFSET-3,%ebp
-	jae syscall_fault
-1:	movl (%ebp),%ebp
-.section __ex_table,"a"
-	.align 4
-	.long 1b,syscall_fault
-.previous
-
 	pushl %eax
 	SAVE_ALL
 	GET_THREAD_INFO(%ebp)
 	cmpl $(nr_syscalls), %eax
 	jae syscall_badsys
 
-	testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebp)
+	testb $_TIF_SYSCALL_TRACE,TI_flags(%ebp)
 	jnz syscall_trace_entry
 	call *sys_call_table(,%eax,4)
 	movl %eax,EAX(%esp)
 	cli
-	movl TI_FLAGS(%ebp), %ecx
+	movl TI_flags(%ebp), %ecx
 	testw $_TIF_ALLWORK_MASK, %cx
 	jne syscall_exit_work
+
+#ifdef CONFIG_X86_SWITCH_PAGETABLES
+
+	GET_THREAD_INFO(%ebp)
+	movl TI_virtual_stack(%ebp), %edx
+	movl TI_user_pgd(%ebp), %ecx
+	movl %esp, %ebx
+	andl $(THREAD_SIZE-1), %ebx
+	orl %ebx, %edx
+sysexit_ret_start_marker:
+	movl %edx, %esp
+	movl %ecx, %cr3
+#endif
+	/*
+	 * only ebx is not restored by the userspace sysenter vsyscall
+	 * code, it assumes it to be callee-saved.
+	 */
+	movl EBX(%esp), %ebx
+
 /* if something modifies registers it must also disable sysexit */
+
 	movl EIP(%esp), %edx
 	movl OLDESP(%esp), %ecx
+
 	sti
 	sysexit
+#ifdef CONFIG_X86_SWITCH_PAGETABLES
+sysexit_ret_end_marker:
+	nop
+#endif
 
 
 	# system call handler stub
@@ -287,7 +417,7 @@ ENTRY(system_call)
 	cmpl $(nr_syscalls), %eax
 	jae syscall_badsys
 					# system call tracing in operation
-	testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebp)
+	testb $_TIF_SYSCALL_TRACE,TI_flags(%ebp)
 	jnz syscall_trace_entry
 syscall_call:
 	call *sys_call_table(,%eax,4)
@@ -296,10 +426,23 @@ syscall_exit:
 	cli				# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
-	movl TI_FLAGS(%ebp), %ecx
+	movl TI_flags(%ebp), %ecx
 	testw $_TIF_ALLWORK_MASK, %cx	# current->work
 	jne syscall_exit_work
 restore_all:
+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
+	movl EFLAGS(%esp), %eax		# mix EFLAGS and CS
+	movb CS(%esp), %al
+	testl $(VM_MASK | 3), %eax
+	jz resume_kernelX		# returning to kernel or vm86-space
+
+	cmpl $0,TI_preempt_count(%ebp)	# non-zero preempt_count ?
+	jz resume_kernelX
+
+        int $3
+
+resume_kernelX:
+#endif
 	RESTORE_ALL
 
 	# perform work that needs to be done immediately before resumption
@@ -312,7 +455,7 @@ work_resched:
 	cli				# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
-	movl TI_FLAGS(%ebp), %ecx
+	movl TI_flags(%ebp), %ecx
 	andl $_TIF_WORK_MASK, %ecx	# is there any work to be done other
 					# than syscall tracing?
 	jz restore_all
@@ -327,6 +470,22 @@ work_notifysig:				# deal with pending s
 					# vm86-space
 	xorl %edx, %edx
 	call do_notify_resume
+
+#if CONFIG_X86_HIGH_ENTRY
+	/*
+	 * Reload db7 if necessary:
+	 */
+	movl TI_flags(%ebp), %ecx
+	testb $_TIF_DB7, %cl
+	jnz work_db7
+
+	jmp restore_all
+
+work_db7:
+	movl TI_task(%ebp), %edx;
+	movl task_thread_db7(%edx), %edx;
+	movl %edx, %db7;
+#endif
 	jmp restore_all
 
 	ALIGN
@@ -382,7 +541,7 @@ syscall_badsys:
  */
 .data
 ENTRY(interrupt)
-.text
+.previous
 
 vector=0
 ENTRY(irq_entries_start)
@@ -392,7 +551,7 @@ ENTRY(irq_entries_start)
 	jmp common_interrupt
 .data
 	.long 1b
-.text
+.previous
 vector=vector+1
 .endr
 
@@ -433,12 +592,17 @@ error_code:
 	movl ES(%esp), %edi		# get the function address
 	movl %eax, ORIG_EAX(%esp)
 	movl %ecx, ES(%esp)
-	movl %esp, %edx
 	pushl %esi			# push the error code
-	pushl %edx			# push the pt_regs pointer
 	movl $(__USER_DS), %edx
 	movl %edx, %ds
 	movl %edx, %es
+
+/* clobbers edx, ebx and ebp */
+	__SWITCH_KERNELSPACE
+
+	leal 4(%esp), %edx		# prepare pt_regs
+	pushl %edx			# push pt_regs
+
 	call *%edi
 	addl $8, %esp
 	jmp ret_from_exception
@@ -529,7 +693,7 @@ nmi_stack_correct:
 	pushl %edx
 	call do_nmi
 	addl $8, %esp
-	RESTORE_ALL
+	jmp restore_all
 
 nmi_stack_fixup:
 	FIX_STACK(12,nmi_stack_correct, 1)
@@ -606,6 +770,8 @@ ENTRY(spurious_interrupt_bug)
 	pushl $do_spurious_interrupt_bug
 	jmp error_code
 
+.previous
+
 .data
 ENTRY(sys_call_table)
 	.long sys_restart_syscall	/* 0 - old "setup()" system call, used for restarting */
@@ -865,7 +1031,7 @@ ENTRY(sys_call_table)
 	.long sys_epoll_create
 	.long sys_epoll_ctl	/* 255 */
 	.long sys_epoll_wait
- 	.long sys_remap_file_pages
+ 	.long old_remap_file_pages
  	.long sys_set_tid_address
  	.long sys_timer_create
  	.long sys_timer_settime		/* 260 */
@@ -882,5 +1048,12 @@ ENTRY(sys_call_table)
 	.long sys_utimes
  	.long sys_fadvise64_64
 	.long sys_ni_syscall	/* sys_vserver */
+	.long sys_mq_open
+	.long sys_mq_unlink	/* 275 */
+	.long sys_mq_timedsend
+	.long sys_mq_timedreceive
+	.long sys_mq_notify
+	.long sys_mq_getsetattr
+	.long sys_remap_file_pages	/* 280 */
 
 syscall_table_size=(.-sys_call_table)
--- diff/arch/i386/kernel/head.S	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/i386/kernel/head.S	2004-03-09 11:51:48.000000000 +0000
@@ -17,7 +17,7 @@
 #include <asm/desc.h>
 #include <asm/cache.h>
 #include <asm/thread_info.h>
-
+#include <asm/asm_offsets.h>
 
 #define OLD_CL_MAGIC_ADDR	0x90020
 #define OLD_CL_MAGIC		0xA33F
@@ -40,49 +40,89 @@
 #define X86_VENDOR_ID	CPU_PARAMS+36	/* offset dependent on NCAPINTS */
 
 /*
- * Initialize page tables
+ * This is how much memory *in addition to the memory covered up to
+ * and including _end* we need mapped initially.  We need one bit for
+ * each possible page, but only in low memory, which means
+ * 2^32/4096/8 = 128K worst case (4G/4G split.)
+ *
+ * Modulo rounding, each megabyte assigned here requires a kilobyte of
+ * memory, which is currently unreclaimed.
+ *
+ * This should be a multiple of a page.
  */
-#define INIT_PAGE_TABLES \
-	movl $pg0 - __PAGE_OFFSET, %edi; \
-	/* "007" doesn't mean with license to kill, but	PRESENT+RW+USER */ \
-	movl $007, %eax; \
-2:	stosl; \
-	add $0x1000, %eax; \
-	cmp $empty_zero_page - __PAGE_OFFSET, %edi; \
-	jne 2b;
+#define INIT_MAP_BEYOND_END	(128*1024)
+
 
 /*
- * swapper_pg_dir is the main page directory, address 0x00101000
- *
- * On entry, %esi points to the real-mode code as a 32-bit pointer.
+ * 32-bit kernel entrypoint; only used by the boot CPU.  On entry,
+ * %esi points to the real-mode code as a 32-bit pointer.
+ * CS and DS must be 4 GB flat segments, but we don't depend on
+ * any particular GDT layout, because we load our own as soon as we
+ * can.
  */
 ENTRY(startup_32)
 
-#ifdef CONFIG_X86_VISWS
 /*
- * On SGI Visual Workstations boot CPU starts in protected mode.
+ * Set segments to known values.
  */
-	orw %bx, %bx
-	jnz 1f
-	INIT_PAGE_TABLES
-	movl $swapper_pg_dir - __PAGE_OFFSET, %eax
-	movl %eax, %cr3
-	lgdt boot_gdt
-1:
-#endif
+	cld
+	lgdt boot_gdt_descr - __PAGE_OFFSET
+	movl $(__BOOT_DS),%eax
+	movl %eax,%ds
+	movl %eax,%es
+	movl %eax,%fs
+	movl %eax,%gs
 
 /*
- * Set segments to known values
+ * Initialize page tables.  This creates a PDE and a set of page
+ * tables, which are located immediately beyond _end.  The variable
+ * init_pg_tables_end is set up to point to the first "safe" location.
+ *
+ * Warning: don't use %esi or the stack in this code.  However, %esp
+ * can be used as a GPR if you really need it...
  */
+page_pde_offset = (__PAGE_OFFSET >> 20);
+
+	movl $(pg0 - __PAGE_OFFSET), %edi
+	movl $(swapper_pg_dir - __PAGE_OFFSET), %edx
+	movl $0x007, %eax			/* 0x007 = PRESENT+RW+USER */
+10:
+	leal 0x007(%edi),%ecx			/* Create PDE entry */
+	movl %ecx,(%edx)			/* Store identity PDE entry */
+	movl %ecx,page_pde_offset(%edx)		/* Store kernel PDE entry */
+	addl $4,%edx
+	movl $1024, %ecx
+11:
+	stosl
+	addl $0x1000,%eax
+	loop 11b
+	/* End condition: we must map up to and including INIT_MAP_BEYOND_END */
+	/* bytes beyond the end of our own page tables; the +0x007 is the attribute bits */
+	leal (INIT_MAP_BEYOND_END+0x007)(%edi),%ebp
+	cmpl %ebp,%eax
+	jb 10b
+	movl %edi,(init_pg_tables_end - __PAGE_OFFSET)
+
+#ifdef CONFIG_SMP
+	xorl %ebx,%ebx				/* This is the boot CPU (BSP) */
+	jmp 3f
+
+/*
+ * Non-boot CPU entry point; entered from trampoline.S
+ * We can't lgdt here, because lgdt itself uses a data segment, but
+ * we know the trampoline has already loaded the boot_gdt_table GDT
+ * for us.
+ */
+ENTRY(startup_32_smp)
 	cld
 	movl $(__BOOT_DS),%eax
 	movl %eax,%ds
 	movl %eax,%es
 	movl %eax,%fs
 	movl %eax,%gs
-#ifdef CONFIG_SMP
-	orw %bx,%bx
-	jz 1f
+
+	xorl %ebx,%ebx
+	incl %ebx				/* This is a secondary processor (AP) */
 
 /*
  *	New page tables may be in 4Mbyte page mode and may
@@ -99,37 +139,40 @@ ENTRY(startup_32)
  *	not yet offset PAGE_OFFSET..
  */
 #define cr4_bits mmu_cr4_features-__PAGE_OFFSET
-	cmpl $0,cr4_bits
-	je 3f
+	movl cr4_bits,%edx
+	andl %edx,%edx
+	jz 3f
 	movl %cr4,%eax		# Turn on paging options (PSE,PAE,..)
-	orl cr4_bits,%eax
+	orl %edx,%eax
 	movl %eax,%cr4
-	jmp 3f
-1:
-#endif
-	INIT_PAGE_TABLES
+
+3:
+#endif /* CONFIG_SMP */
+
 /*
  * Enable paging
  */
-3:
 	movl $swapper_pg_dir-__PAGE_OFFSET,%eax
 	movl %eax,%cr3		/* set the page table pointer.. */
 	movl %cr0,%eax
 	orl $0x80000000,%eax
 	movl %eax,%cr0		/* ..and set paging (PG) bit */
-	jmp 1f			/* flush the prefetch-queue */
-1:
-	movl $1f,%eax
-	jmp *%eax		/* make sure eip is relocated */
+	ljmp $__BOOT_CS,$1f	/* Clear prefetch and normalize %eip */
 1:
 	/* Set up the stack pointer */
 	lss stack_start,%esp
 
-#ifdef CONFIG_SMP
-	orw  %bx,%bx
-	jz  1f				/* Initial CPU cleans BSS */
+/*
+ * Initialize eflags.  Some BIOS's leave bits like NT set.  This would
+ * confuse the debugger if this code is traced.
+ * XXX - best to initialize before switching to protected mode.
+ */
 	pushl $0
 	popfl
+
+#ifdef CONFIG_SMP
+	andl %ebx,%ebx
+	jz  1f				/* Initial CPU cleans BSS */
 	jmp checkCPUtype
 1:
 #endif /* CONFIG_SMP */
@@ -142,21 +185,15 @@ ENTRY(startup_32)
 	movl $__bss_start,%edi
 	movl $__bss_stop,%ecx
 	subl %edi,%ecx
-	rep
-	stosb
+	shrl $2,%ecx
+	rep ; stosl
 
 /*
  * start system 32-bit setup. We need to re-do some of the things done
  * in 16-bit mode for the "real" operations.
  */
 	call setup_idt
-/*
- * Initialize eflags.  Some BIOS's leave bits like NT set.  This would
- * confuse the debugger if this code is traced.
- * XXX - best to initialize before switching to protected mode.
- */
-	pushl $0
-	popfl
+
 /*
  * Copy bootup parameters out of the way. First 2kB of
  * _empty_zero_page is for boot parameters, second 2kB
@@ -273,7 +310,7 @@ is386:	movl $2,%ecx		# set MP
 	call initialize_secondary
 	jmp L6
 1:
-#endif
+#endif /* CONFIG_SMP */
 	call start_kernel
 L6:
 	jmp L6			# main should never return here, but
@@ -309,6 +346,8 @@ check_x87:
  *  and the kernel moved to PAGE_OFFSET. Interrupts
  *  are enabled elsewhere, when we can be relatively
  *  sure everything is ok.
+ *
+ *  Warning: %esi is live across this function.
  */
 setup_idt:
 	lea ignore_int,%edx
@@ -332,7 +371,7 @@ ENTRY(stack_start)
 
 /* This is the default interrupt "handler" :-) */
 int_msg:
-	.asciz "Unknown interrupt\n"
+	.asciz "Unknown interrupt or fault at EIP %p %p %p\n"
 	ALIGN
 ignore_int:
 	cld
@@ -344,9 +383,13 @@ ignore_int:
 	movl $(__KERNEL_DS),%eax
 	movl %eax,%ds
 	movl %eax,%es
+	pushl 16(%esp)
+	pushl 24(%esp)
+	pushl 32(%esp)
+	pushl 40(%esp)
 	pushl $int_msg
 	call printk
-	popl %eax
+	addl $(5*4),%esp
 	popl %ds
 	popl %es
 	popl %edx
@@ -361,10 +404,17 @@ ignore_int:
  * segment size, and 32-bit linear address value:
  */
 
+.globl boot_gdt_descr
 .globl idt_descr
 .globl cpu_gdt_descr
 
 	ALIGN
+# early boot GDT descriptor (must use 1:1 address mapping)
+	.word 0				# 32 bit align gdt_desc.address
+boot_gdt_descr:
+	.word __BOOT_DS+7
+	.long boot_gdt_table - __PAGE_OFFSET
+
 	.word 0				# 32-bit align idt_desc.address
 idt_descr:
 	.word IDT_ENTRIES*8-1		# idt contains 256 entries
@@ -379,41 +429,25 @@ cpu_gdt_descr:
 	.fill NR_CPUS-1,8,0		# space for the other GDT descriptors
 
 /*
- * This is initialized to create an identity-mapping at 0-8M (for bootup
- * purposes) and another mapping of the 0-8M area at virtual address
- * PAGE_OFFSET.
+ * swapper_pg_dir is the main page directory, address 0x00101000
+ *
+ * This is initialized to create an identity-mapping at 0 (for bootup
+ * purposes) and another mapping at virtual address PAGE_OFFSET.  The
+ * values put here should be all invalid (zero); the valid
+ * entries are created dynamically at boot time.
+ *
+ * The code creates enough page tables to map 0-_end, the page tables
+ * themselves, plus INIT_MAP_BEYOND_END bytes; see comment at beginning.
  */
 .org 0x1000
 ENTRY(swapper_pg_dir)
-	.long 0x00102007
-	.long 0x00103007
-	.fill BOOT_USER_PGD_PTRS-2,4,0
-	/* default: 766 entries */
-	.long 0x00102007
-	.long 0x00103007
-	/* default: 254 entries */
-	.fill BOOT_KERNEL_PGD_PTRS-2,4,0
+	.fill 1024,4,0
 
-/*
- * The page tables are initialized to only 8MB here - the final page
- * tables are set up later depending on memory size.
- */
 .org 0x2000
-ENTRY(pg0)
-
-.org 0x3000
-ENTRY(pg1)
-
-/*
- * empty_zero_page must immediately follow the page tables ! (The
- * initialization loop counts until empty_zero_page)
- */
-
-.org 0x4000
 ENTRY(empty_zero_page)
+	.fill 4096,1,0
 
-.org 0x5000
-
+.org 0x3000
 /*
  * Real beginning of normal "text" segment
  */
@@ -428,20 +462,19 @@ ENTRY(_stext)
 .data
 
 /*
- * The Global Descriptor Table contains 28 quadwords, per-CPU.
- */
-#if defined(CONFIG_SMP) || defined(CONFIG_X86_VISWS)
-/*
  * The boot_gdt_table must mirror the equivalent in setup.S and is
- * used only by the trampoline for booting other CPUs
+ * used only for booting.
  */
 	.align L1_CACHE_BYTES
 ENTRY(boot_gdt_table)
 	.fill GDT_ENTRY_BOOT_CS,8,0
 	.quad 0x00cf9a000000ffff	/* kernel 4GB code at 0x00000000 */
 	.quad 0x00cf92000000ffff	/* kernel 4GB data at 0x00000000 */
-#endif
-	.align L1_CACHE_BYTES
+
+/*
+ * The Global Descriptor Table contains 28 quadwords, per-CPU.
+ */
+	.align PAGE_SIZE_asm
 ENTRY(cpu_gdt_table)
 	.quad 0x0000000000000000	/* NULL descriptor */
 	.quad 0x0000000000000000	/* 0x0b reserved */
@@ -488,4 +521,3 @@ ENTRY(cpu_gdt_table)
 #ifdef CONFIG_SMP
 	.fill (NR_CPUS-1)*GDT_ENTRIES,8,0 /* other CPU's GDT */
 #endif
-
--- diff/arch/i386/kernel/i386_ksyms.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/i386/kernel/i386_ksyms.c	2004-03-09 11:51:48.000000000 +0000
@@ -88,16 +88,11 @@ EXPORT_SYMBOL(get_cmos_time);
 EXPORT_SYMBOL(cpu_khz);
 EXPORT_SYMBOL(apm_info);
 
-#ifdef CONFIG_DEBUG_IOVIRT
-EXPORT_SYMBOL(__io_virt_debug);
-#endif
-
 EXPORT_SYMBOL_NOVERS(__down_failed);
 EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
 EXPORT_SYMBOL_NOVERS(__down_failed_trylock);
 EXPORT_SYMBOL_NOVERS(__up_wakeup);
 /* Networking helper routines. */
-EXPORT_SYMBOL(csum_partial_copy_generic);
 /* Delay loops */
 EXPORT_SYMBOL(__ndelay);
 EXPORT_SYMBOL(__udelay);
@@ -111,13 +106,17 @@ EXPORT_SYMBOL_NOVERS(__get_user_4);
 EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(strstr);
 
+#if !defined(CONFIG_X86_UACCESS_INDIRECT)
 EXPORT_SYMBOL(strncpy_from_user);
-EXPORT_SYMBOL(__strncpy_from_user);
+EXPORT_SYMBOL(__direct_strncpy_from_user);
 EXPORT_SYMBOL(clear_user);
 EXPORT_SYMBOL(__clear_user);
 EXPORT_SYMBOL(__copy_from_user_ll);
 EXPORT_SYMBOL(__copy_to_user_ll);
 EXPORT_SYMBOL(strnlen_user);
+#else /* CONFIG_X86_UACCESS_INDIRECT */
+EXPORT_SYMBOL(direct_csum_partial_copy_generic);
+#endif
 
 EXPORT_SYMBOL(dma_alloc_coherent);
 EXPORT_SYMBOL(dma_free_coherent);
--- diff/arch/i386/kernel/i387.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/i386/kernel/i387.c	2004-03-09 11:51:48.000000000 +0000
@@ -218,6 +218,7 @@ void set_fpu_mxcsr( struct task_struct *
 static int convert_fxsr_to_user( struct _fpstate __user *buf,
 					struct i387_fxsave_struct *fxsave )
 {
+	struct _fpreg tmp[8]; /* 80 bytes scratch area */
 	unsigned long env[7];
 	struct _fpreg __user *to;
 	struct _fpxreg *from;
@@ -234,23 +235,25 @@ static int convert_fxsr_to_user( struct 
 	if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) )
 		return 1;
 
-	to = &buf->_st[0];
+	to = tmp;
 	from = (struct _fpxreg *) &fxsave->st_space[0];
 	for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
 		unsigned long *t = (unsigned long *)to;
 		unsigned long *f = (unsigned long *)from;
 
-		if (__put_user(*f, t) ||
-				__put_user(*(f + 1), t + 1) ||
-				__put_user(from->exponent, &to->exponent))
-			return 1;
+		*t = *f;
+		*(t + 1) = *(f+1);
+		to->exponent = from->exponent;
 	}
+	if (copy_to_user(buf->_st, tmp, sizeof(struct _fpreg [8])))
+		return 1;
 	return 0;
 }
 
 static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave,
 					  struct _fpstate __user *buf )
 {
+	struct _fpreg tmp[8]; /* 80 bytes scratch area */
 	unsigned long env[7];
 	struct _fpxreg *to;
 	struct _fpreg __user *from;
@@ -258,6 +261,8 @@ static int convert_fxsr_from_user( struc
 
 	if ( __copy_from_user( env, buf, 7 * sizeof(long) ) )
 		return 1;
+	if (copy_from_user(tmp, buf->_st, sizeof(struct _fpreg [8])))
+		return 1;
 
 	fxsave->cwd = (unsigned short)(env[0] & 0xffff);
 	fxsave->swd = (unsigned short)(env[1] & 0xffff);
@@ -269,15 +274,14 @@ static int convert_fxsr_from_user( struc
 	fxsave->fos = env[6];
 
 	to = (struct _fpxreg *) &fxsave->st_space[0];
-	from = &buf->_st[0];
+	from = tmp;
 	for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
 		unsigned long *t = (unsigned long *)to;
 		unsigned long *f = (unsigned long *)from;
 
-		if (__get_user(*t, f) ||
-				__get_user(*(t + 1), f + 1) ||
-				__get_user(to->exponent, &from->exponent))
-			return 1;
+		*t = *f;
+		*(t + 1) = *(f + 1);
+		to->exponent = from->exponent;
 	}
 	return 0;
 }
--- diff/arch/i386/kernel/i8259.c	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/i386/kernel/i8259.c	2004-03-09 11:51:48.000000000 +0000
@@ -444,4 +444,7 @@ void __init init_IRQ(void)
 	 */
 	if (boot_cpu_data.hard_math && !cpu_has_fpu)
 		setup_irq(FPU_IRQ, &fpu_irq);
+
+	current_thread_info()->cpu = 0;
+	irq_ctx_init(0);
 }
--- diff/arch/i386/kernel/init_task.c	2003-10-09 09:47:33.000000000 +0100
+++ source/arch/i386/kernel/init_task.c	2004-03-09 11:51:48.000000000 +0000
@@ -26,7 +26,7 @@ EXPORT_SYMBOL(init_mm);
  */
 union thread_union init_thread_union 
 	__attribute__((__section__(".data.init_task"))) =
-		{ INIT_THREAD_INFO(init_task) };
+		{ INIT_THREAD_INFO(init_task, init_thread_union) };
 
 /*
  * Initial task structure.
@@ -44,5 +44,5 @@ EXPORT_SYMBOL(init_task);
  * section. Since TSS's are completely CPU-local, we want them
  * on exact cacheline boundaries, to eliminate cacheline ping-pong.
  */ 
-struct tss_struct init_tss[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = INIT_TSS };
+struct tss_struct init_tss[NR_CPUS] __attribute__((__section__(".data.tss"))) = { [0 ... NR_CPUS-1] = INIT_TSS };
 
--- diff/arch/i386/kernel/io_apic.c	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/i386/kernel/io_apic.c	2004-03-09 11:51:48.000000000 +0000
@@ -317,8 +317,7 @@ struct irq_cpu_info {
 
 #define IRQ_ALLOWED(cpu, allowed_mask)	cpu_isset(cpu, allowed_mask)
 
-#define CPU_TO_PACKAGEINDEX(i) \
-		((physical_balance && i > cpu_sibling_map[i]) ? cpu_sibling_map[i] : i)
+#define CPU_TO_PACKAGEINDEX(i) (first_cpu(cpu_sibling_map[i]))
 
 #define MAX_BALANCED_IRQ_INTERVAL	(5*HZ)
 #define MIN_BALANCED_IRQ_INTERVAL	(HZ/2)
@@ -401,6 +400,7 @@ static void do_irq_balance(void)
 	unsigned long max_cpu_irq = 0, min_cpu_irq = (~0);
 	unsigned long move_this_load = 0;
 	int max_loaded = 0, min_loaded = 0;
+	int load;
 	unsigned long useful_load_threshold = balanced_irq_interval + 10;
 	int selected_irq;
 	int tmp_loaded, first_attempt = 1;
@@ -452,7 +452,7 @@ static void do_irq_balance(void)
 	for (i = 0; i < NR_CPUS; i++) {
 		if (!cpu_online(i))
 			continue;
-		if (physical_balance && i > cpu_sibling_map[i])
+		if (i != CPU_TO_PACKAGEINDEX(i))
 			continue;
 		if (min_cpu_irq > CPU_IRQ(i)) {
 			min_cpu_irq = CPU_IRQ(i);
@@ -471,7 +471,7 @@ tryanothercpu:
 	for (i = 0; i < NR_CPUS; i++) {
 		if (!cpu_online(i))
 			continue;
-		if (physical_balance && i > cpu_sibling_map[i])
+		if (i != CPU_TO_PACKAGEINDEX(i))
 			continue;
 		if (max_cpu_irq <= CPU_IRQ(i)) 
 			continue;
@@ -551,9 +551,14 @@ tryanotherirq:
 	 * We seek the least loaded sibling by making the comparison
 	 * (A+B)/2 vs B
 	 */
-	if (physical_balance && (CPU_IRQ(min_loaded) >> 1) >
-					CPU_IRQ(cpu_sibling_map[min_loaded]))
-		min_loaded = cpu_sibling_map[min_loaded];
+	load = CPU_IRQ(min_loaded) >> 1;
+	for_each_cpu_mask(j, cpu_sibling_map[min_loaded]) {
+		if (load > CPU_IRQ(j)) {
+			/* This won't change cpu_sibling_map[min_loaded] */
+			load = CPU_IRQ(j);
+			min_loaded = j;
+		}
+	}
 
 	cpus_and(allowed_mask, cpu_online_map, irq_affinity[selected_irq]);
 	target_cpu_mask = cpumask_of_cpu(min_loaded);
--- diff/arch/i386/kernel/irq.c	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/i386/kernel/irq.c	2004-03-09 11:51:48.000000000 +0000
@@ -75,6 +75,14 @@ irq_desc_t irq_desc[NR_IRQS] __cacheline
 static void register_irq_proc (unsigned int irq);
 
 /*
+ * per-CPU IRQ handling stacks
+ */
+#ifdef CONFIG_4KSTACKS
+union irq_ctx *hardirq_ctx[NR_CPUS];
+union irq_ctx *softirq_ctx[NR_CPUS];
+#endif
+
+/*
  * Special irq handlers.
  */
 
@@ -213,7 +221,7 @@ inline void synchronize_irq(unsigned int
  * waste of time and is not what some drivers would
  * prefer.
  */
-int handle_IRQ_event(unsigned int irq,
+asmlinkage int handle_IRQ_event(unsigned int irq,
 		struct pt_regs *regs, struct irqaction *action)
 {
 	int status = 1;	/* Force the "do bottom halves" bit */
@@ -436,7 +444,7 @@ asmlinkage unsigned int do_IRQ(struct pt
 
 		__asm__ __volatile__("andl %%esp,%0" :
 					"=r" (esp) : "0" (THREAD_SIZE - 1));
-		if (unlikely(esp < (sizeof(struct thread_info) + 1024))) {
+		if (unlikely(esp < (sizeof(struct thread_info) + STACK_WARN))) {
 			printk("do_IRQ: stack overflow: %ld\n",
 				esp - sizeof(struct thread_info));
 			dump_stack();
@@ -484,11 +492,70 @@ asmlinkage unsigned int do_IRQ(struct pt
 	 * useful for irq hardware that does not mask cleanly in an
 	 * SMP environment.
 	 */
+#ifdef CONFIG_4KSTACKS
+
+	for (;;) {
+		irqreturn_t action_ret;
+		u32 *isp;
+		union irq_ctx * curctx;
+		union irq_ctx * irqctx;
+
+		curctx = (union irq_ctx *) current_thread_info();
+		irqctx = hardirq_ctx[smp_processor_id()];
+
+		spin_unlock(&desc->lock);
+
+		/*
+		 * this is where we switch to the IRQ stack. However, if we are already using
+		 * the IRQ stack (because we interrupted a hardirq handler) we can't do that
+		 * and just have to keep using the current stack (which is the irq stack already
+		 * after all)
+		 */
+
+		if (curctx == irqctx)
+			action_ret = handle_IRQ_event(irq, &regs, action);
+		else {
+			/* build the stack frame on the IRQ stack */
+			isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
+			irqctx->tinfo.task = curctx->tinfo.task;
+			irqctx->tinfo.real_stack = curctx->tinfo.real_stack;
+			irqctx->tinfo.virtual_stack = curctx->tinfo.virtual_stack;
+			irqctx->tinfo.previous_esp = current_stack_pointer();
+
+			*--isp = (u32) action;
+			*--isp = (u32) &regs;
+			*--isp = (u32) irq;
+
+			asm volatile(
+				"       xchgl   %%ebx,%%esp     \n"
+				"       call    handle_IRQ_event \n"
+				"       xchgl   %%ebx,%%esp     \n"
+				: "=a"(action_ret)
+				: "b"(isp)
+				: "memory", "cc", "edx", "ecx"
+			);
+
+
+		}
+		spin_lock(&desc->lock);
+		if (!noirqdebug)
+			note_interrupt(irq, desc, action_ret);
+		if (curctx != irqctx)
+			irqctx->tinfo.task = NULL;
+		if (likely(!(desc->status & IRQ_PENDING)))
+			break;
+		desc->status &= ~IRQ_PENDING;
+	}
+
+#else
+
 	for (;;) {
 		irqreturn_t action_ret;
 
 		spin_unlock(&desc->lock);
+
 		action_ret = handle_IRQ_event(irq, &regs, action);
+
 		spin_lock(&desc->lock);
 		if (!noirqdebug)
 			note_interrupt(irq, desc, action_ret);
@@ -496,6 +563,7 @@ asmlinkage unsigned int do_IRQ(struct pt
 			break;
 		desc->status &= ~IRQ_PENDING;
 	}
+#endif
 	desc->status &= ~IRQ_INPROGRESS;
 
 out:
@@ -508,6 +576,8 @@ out:
 
 	irq_exit();
 
+	kgdb_process_breakpoint();
+
 	return 1;
 }
 
@@ -1053,3 +1123,81 @@ void init_irq_proc (void)
 		register_irq_proc(i);
 }
 
+
+#ifdef CONFIG_4KSTACKS
+static char softirq_stack[NR_CPUS * THREAD_SIZE]  __attribute__((__aligned__(THREAD_SIZE)));
+static char hardirq_stack[NR_CPUS * THREAD_SIZE]  __attribute__((__aligned__(THREAD_SIZE)));
+
+/*
+ * allocate per-cpu stacks for hardirq and for softirq processing
+ */
+void irq_ctx_init(int cpu)
+{
+	union irq_ctx *irqctx;
+
+	if (hardirq_ctx[cpu])
+		return;
+
+	irqctx = (union irq_ctx*) &hardirq_stack[cpu*THREAD_SIZE];
+	irqctx->tinfo.task              = NULL;
+	irqctx->tinfo.exec_domain       = NULL;
+	irqctx->tinfo.cpu               = cpu;
+	irqctx->tinfo.preempt_count     = HARDIRQ_OFFSET;
+	irqctx->tinfo.addr_limit        = MAKE_MM_SEG(0);
+
+	hardirq_ctx[cpu] = irqctx;
+
+	irqctx = (union irq_ctx*) &softirq_stack[cpu*THREAD_SIZE];
+	irqctx->tinfo.task              = NULL;
+	irqctx->tinfo.exec_domain       = NULL;
+	irqctx->tinfo.cpu               = cpu;
+	irqctx->tinfo.preempt_count     = SOFTIRQ_OFFSET;
+	irqctx->tinfo.addr_limit        = MAKE_MM_SEG(0);
+
+	softirq_ctx[cpu] = irqctx;
+
+	printk("CPU %u irqstacks, hard=%p soft=%p\n",
+		cpu,hardirq_ctx[cpu],softirq_ctx[cpu]);
+}
+
+extern asmlinkage void __do_softirq(void);
+
+asmlinkage void do_softirq(void)
+{
+	unsigned long flags;
+	struct thread_info *curctx;
+	union irq_ctx *irqctx;
+	u32 *isp;
+
+	if (in_interrupt())
+		return;
+
+	local_irq_save(flags);
+
+	if (local_softirq_pending()) {
+		curctx = current_thread_info();
+		irqctx = softirq_ctx[smp_processor_id()];
+		irqctx->tinfo.task = curctx->task;
+		irqctx->tinfo.real_stack = curctx->real_stack;
+		irqctx->tinfo.virtual_stack = curctx->virtual_stack;
+		irqctx->tinfo.previous_esp = current_stack_pointer();
+
+		/* build the stack frame on the softirq stack */
+		isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
+
+
+		asm volatile(
+			"       xchgl   %%ebx,%%esp     \n"
+			"       call    __do_softirq    \n"
+			"       movl    %%ebx,%%esp     \n"
+			: "=b"(isp)
+			: "0"(isp)
+			: "memory", "cc", "edx", "ecx", "eax"
+		);
+	}
+
+	local_irq_restore(flags);
+}
+
+EXPORT_SYMBOL(do_softirq);
+#endif
--- diff/arch/i386/kernel/ldt.c	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/kernel/ldt.c	2004-03-09 11:51:48.000000000 +0000
@@ -2,7 +2,7 @@
  * linux/kernel/ldt.c
  *
  * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
- * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
+ * Copyright (C) 1999, 2003 Ingo Molnar <mingo@redhat.com>
  */
 
 #include <linux/errno.h>
@@ -18,6 +18,8 @@
 #include <asm/system.h>
 #include <asm/ldt.h>
 #include <asm/desc.h>
+#include <linux/highmem.h>
+#include <asm/atomic_kmap.h>
 
 #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
 static void flush_ldt(void *null)
@@ -29,34 +31,31 @@ static void flush_ldt(void *null)
 
 static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
 {
-	void *oldldt;
-	void *newldt;
-	int oldsize;
+	int oldsize, newsize, i;
 
 	if (mincount <= pc->size)
 		return 0;
+	/*
+	 * LDT got larger - reallocate if necessary.
+	 */
 	oldsize = pc->size;
 	mincount = (mincount+511)&(~511);
-	if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE)
-		newldt = vmalloc(mincount*LDT_ENTRY_SIZE);
-	else
-		newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL);
-
-	if (!newldt)
-		return -ENOMEM;
-
-	if (oldsize)
-		memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE);
-	oldldt = pc->ldt;
-	memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE);
-	pc->ldt = newldt;
-	wmb();
+	newsize = mincount*LDT_ENTRY_SIZE;
+	for (i = 0; i < newsize; i += PAGE_SIZE) {
+		int nr = i/PAGE_SIZE;
+		BUG_ON(i >= 64*1024);
+		if (!pc->ldt_pages[nr]) {
+			pc->ldt_pages[nr] = alloc_page(GFP_HIGHUSER);
+			if (!pc->ldt_pages[nr])
+				return -ENOMEM;
+			clear_highpage(pc->ldt_pages[nr]);
+		}
+	}
 	pc->size = mincount;
-	wmb();
-
 	if (reload) {
 #ifdef CONFIG_SMP
 		cpumask_t mask;
+
 		preempt_disable();
 		load_LDT(pc);
 		mask = cpumask_of_cpu(smp_processor_id());
@@ -67,21 +66,20 @@ static int alloc_ldt(mm_context_t *pc, i
 		load_LDT(pc);
 #endif
 	}
-	if (oldsize) {
-		if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE)
-			vfree(oldldt);
-		else
-			kfree(oldldt);
-	}
 	return 0;
 }
 
 static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
 {
-	int err = alloc_ldt(new, old->size, 0);
-	if (err < 0)
+	int i, err, size = old->size, nr_pages = (size*LDT_ENTRY_SIZE + PAGE_SIZE-1)/PAGE_SIZE;
+
+	err = alloc_ldt(new, size, 0);
+	if (err < 0) {
+		new->size = 0;
 		return err;
-	memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
+	}
+	for (i = 0; i < nr_pages; i++)
+		copy_user_highpage(new->ldt_pages[i], old->ldt_pages[i], 0);
 	return 0;
 }
 
@@ -96,6 +94,7 @@ int init_new_context(struct task_struct 
 
 	init_MUTEX(&mm->context.sem);
 	mm->context.size = 0;
+	memset(mm->context.ldt_pages, 0, sizeof(struct page *) * MAX_LDT_PAGES);
 	old_mm = current->mm;
 	if (old_mm && old_mm->context.size > 0) {
 		down(&old_mm->context.sem);
@@ -107,23 +106,21 @@ int init_new_context(struct task_struct 
 
 /*
  * No need to lock the MM as we are the last user
+ * Do not touch the ldt register, we are already
+ * in the next thread.
  */
 void destroy_context(struct mm_struct *mm)
 {
-	if (mm->context.size) {
-		if (mm == current->active_mm)
-			clear_LDT();
-		if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE)
-			vfree(mm->context.ldt);
-		else
-			kfree(mm->context.ldt);
-		mm->context.size = 0;
-	}
+	int i, nr_pages = (mm->context.size*LDT_ENTRY_SIZE + PAGE_SIZE-1) / PAGE_SIZE;
+
+	for (i = 0; i < nr_pages; i++)
+		__free_page(mm->context.ldt_pages[i]);
+	mm->context.size = 0;
 }
 
 static int read_ldt(void __user * ptr, unsigned long bytecount)
 {
-	int err;
+	int err, i;
 	unsigned long size;
 	struct mm_struct * mm = current->mm;
 
@@ -138,8 +135,25 @@ static int read_ldt(void __user * ptr, u
 		size = bytecount;
 
 	err = 0;
-	if (copy_to_user(ptr, mm->context.ldt, size))
-		err = -EFAULT;
+	/*
+	 * This is necessary just in case we got here straight from a
+	 * context-switch where the ptes were set but no tlb flush
+	 * was done yet. We rather avoid doing a TLB flush in the
+	 * context-switch path and do it here instead.
+	 */
+	__flush_tlb_global();
+
+	for (i = 0; i < size; i += PAGE_SIZE) {
+		int nr = i / PAGE_SIZE, bytes;
+		char *kaddr = kmap(mm->context.ldt_pages[nr]);
+
+		bytes = size - i;
+		if (bytes > PAGE_SIZE)
+			bytes = PAGE_SIZE;
+		if (copy_to_user(ptr + i, kaddr, size - i))
+			err = -EFAULT;
+		kunmap(mm->context.ldt_pages[nr]);
+	}
 	up(&mm->context.sem);
 	if (err < 0)
 		return err;
@@ -158,7 +172,7 @@ static int read_default_ldt(void __user 
 
 	err = 0;
 	address = &default_ldt[0];
-	size = 5*sizeof(struct desc_struct);
+	size = 5*LDT_ENTRY_SIZE;
 	if (size > bytecount)
 		size = bytecount;
 
@@ -200,7 +214,15 @@ static int write_ldt(void __user * ptr, 
 			goto out_unlock;
 	}
 
-	lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.ldt);
+	/*
+	 * No rescheduling allowed from this point to the install.
+	 *
+	 * We do a TLB flush for the same reason as in the read_ldt() path.
+	 */
+	preempt_disable();
+	__flush_tlb_global();
+	lp = (__u32 *) ((ldt_info.entry_number << 3) +
+			(char *) __kmap_atomic_vaddr(KM_LDT_PAGE0));
 
    	/* Allow LDTs to be cleared by the user. */
    	if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
@@ -221,6 +243,7 @@ install:
 	*lp	= entry_1;
 	*(lp+1)	= entry_2;
 	error = 0;
+	preempt_enable();
 
 out_unlock:
 	up(&mm->context.sem);
@@ -248,3 +271,26 @@ asmlinkage int sys_modify_ldt(int func, 
 	}
 	return ret;
 }
+
+/*
+ * load one particular LDT into the current CPU
+ */
+void load_LDT_nolock(mm_context_t *pc, int cpu)
+{
+	struct page **pages = pc->ldt_pages;
+	int count = pc->size;
+	int nr_pages, i;
+
+	if (likely(!count)) {
+		pages = &default_ldt_page;
+		count = 5;
+	}
+       	nr_pages = (count*LDT_ENTRY_SIZE + PAGE_SIZE-1) / PAGE_SIZE;
+
+	for (i = 0; i < nr_pages; i++) {
+		__kunmap_atomic_type(KM_LDT_PAGE0 - i);
+		__kmap_atomic(pages[i], KM_LDT_PAGE0 - i);
+	}
+	set_ldt_desc(cpu, (void *)__kmap_atomic_vaddr(KM_LDT_PAGE0), count);
+	load_LDT_desc();
+}
--- diff/arch/i386/kernel/mpparse.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/i386/kernel/mpparse.c	2004-03-09 11:51:48.000000000 +0000
@@ -668,7 +668,7 @@ void __init get_smp_config (void)
 		 * Read the physical hardware table.  Anything here will
 		 * override the defaults.
 		 */
-		if (!smp_read_mpc((void *)mpf->mpf_physptr)) {
+		if (!smp_read_mpc((void *)phys_to_virt(mpf->mpf_physptr))) {
 			smp_found_config = 0;
 			printk(KERN_ERR "BIOS bug, MP table errors detected!...\n");
 			printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n");
@@ -1156,7 +1156,7 @@ void __init mp_parse_prt (void)
 			continue;
 		}
 		if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
-			printk(KERN_DEBUG "Pin %d-%d already programmed\n",
+			Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
 				mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
  			entry->irq = acpi_irq_to_vector(irq);
 			continue;
--- diff/arch/i386/kernel/nmi.c	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/i386/kernel/nmi.c	2004-03-09 11:51:48.000000000 +0000
@@ -31,9 +31,19 @@
 #include <asm/mpspec.h>
 #include <asm/nmi.h>
 
+#ifdef CONFIG_KGDB
+#include <asm/kgdb.h>
+#ifdef CONFIG_SMP
+unsigned int nmi_watchdog = NMI_IO_APIC;
+#else
+unsigned int nmi_watchdog = NMI_LOCAL_APIC;
+#endif
+#else
 unsigned int nmi_watchdog = NMI_NONE;
+#endif
 static unsigned int nmi_hz = HZ;
-unsigned int nmi_perfctr_msr;	/* the MSR to reset in NMI handler */
+static unsigned int nmi_perfctr_msr;	/* the MSR to reset in NMI handler */
+static unsigned int nmi_p4_cccr_val;
 extern void show_registers(struct pt_regs *regs);
 
 /* nmi_active:
@@ -66,7 +76,8 @@ int nmi_active;
 #define P4_ESCR_EVENT_SELECT(N)	((N)<<25)
 #define P4_ESCR_OS		(1<<3)
 #define P4_ESCR_USR		(1<<2)
-#define P4_CCCR_OVF_PMI		(1<<26)
+#define P4_CCCR_OVF_PMI0	(1<<26)
+#define P4_CCCR_OVF_PMI1	(1<<27)
 #define P4_CCCR_THRESHOLD(N)	((N)<<20)
 #define P4_CCCR_COMPLEMENT	(1<<19)
 #define P4_CCCR_COMPARE		(1<<18)
@@ -79,7 +90,7 @@ int nmi_active;
 #define MSR_P4_IQ_COUNTER0	0x30C
 #define P4_NMI_CRU_ESCR0	(P4_ESCR_EVENT_SELECT(0x3F)|P4_ESCR_OS|P4_ESCR_USR)
 #define P4_NMI_IQ_CCCR0	\
-	(P4_CCCR_OVF_PMI|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT|	\
+	(P4_CCCR_OVF_PMI0|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT|	\
 	 P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE)
 
 int __init check_nmi_watchdog (void)
@@ -107,11 +118,6 @@ int __init check_nmi_watchdog (void)
 	}
 	printk("OK.\n");
 
-	/* now that we know it works we can reduce NMI frequency to
-	   something more reasonable; makes a difference in some configs */
-	if (nmi_watchdog == NMI_LOCAL_APIC)
-		nmi_hz = 1;
-
 	return 0;
 }
 
@@ -322,6 +328,11 @@ static int setup_p4_watchdog(void)
 		return 0;
 
 	nmi_perfctr_msr = MSR_P4_IQ_COUNTER0;
+	nmi_p4_cccr_val = P4_NMI_IQ_CCCR0;
+#ifdef CONFIG_SMP
+	if (smp_num_siblings == 2)
+		nmi_p4_cccr_val |= P4_CCCR_OVF_PMI1;
+#endif
 
 	if (!(misc_enable & MSR_P4_MISC_ENABLE_PEBS_UNAVAIL))
 		clear_msr_range(0x3F1, 2);
@@ -339,12 +350,14 @@ static int setup_p4_watchdog(void)
 	Dprintk("setting P4_IQ_COUNTER0 to 0x%08lx\n", -(cpu_khz/nmi_hz*1000));
 	wrmsr(MSR_P4_IQ_COUNTER0, -(cpu_khz/nmi_hz*1000), -1);
 	apic_write(APIC_LVTPC, APIC_DM_NMI);
-	wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0);
+	wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0);
 	return 1;
 }
 
 void setup_apic_nmi_watchdog (void)
 {
+	nmi_hz = 1;
+
 	switch (boot_cpu_data.x86_vendor) {
 	case X86_VENDOR_AMD:
 		if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15)
@@ -408,6 +421,9 @@ void touch_nmi_watchdog (void)
 	for (i = 0; i < NR_CPUS; i++)
 		alert_counter[i] = 0;
 }
+#ifdef CONFIG_KGDB
+int tune_watchdog = 5*HZ;
+#endif
 
 void nmi_watchdog_tick (struct pt_regs * regs)
 {
@@ -421,12 +437,24 @@ void nmi_watchdog_tick (struct pt_regs *
 
 	sum = irq_stat[cpu].apic_timer_irqs;
 
+#ifdef CONFIG_KGDB
+ 	if (! in_kgdb(regs) && last_irq_sums[cpu] == sum ) {
+
+#else
 	if (last_irq_sums[cpu] == sum) {
+#endif
 		/*
 		 * Ayiee, looks like this CPU is stuck ...
 		 * wait a few IRQs (5 seconds) before doing the oops ...
 		 */
 		alert_counter[cpu]++;
+#ifdef CONFIG_KGDB
+                if (alert_counter[cpu] == tune_watchdog) {
+                        kgdb_handle_exception(2, SIGPWR, 0, regs);
+                        last_irq_sums[cpu] = sum;
+                        alert_counter[cpu] = 0;
+                }
+#endif
 		if (alert_counter[cpu] == 5*nmi_hz) {
 			spin_lock(&nmi_print_lock);
 			/*
@@ -455,7 +483,7 @@ void nmi_watchdog_tick (struct pt_regs *
 			 * - LVTPC is masked on interrupt and must be
 			 *   unmasked by the LVTPC handler.
 			 */
-			wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0);
+			wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0);
 			apic_write(APIC_LVTPC, APIC_DM_NMI);
 		}
 		wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1);
--- diff/arch/i386/kernel/pci-dma.c	2003-01-16 11:30:40.000000000 +0000
+++ source/arch/i386/kernel/pci-dma.c	2004-03-09 11:51:48.000000000 +0000
@@ -20,8 +20,9 @@ void *dma_alloc_coherent(struct device *
 	/* ignore region specifiers */
 	gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
 
-	if (dev == NULL || (*dev->dma_mask < 0xffffffff))
+	if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
 		gfp |= GFP_DMA;
+
 	ret = (void *)__get_free_pages(gfp, get_order(size));
 
 	if (ret != NULL) {
--- diff/arch/i386/kernel/process.c	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/i386/kernel/process.c	2004-03-09 11:51:48.000000000 +0000
@@ -45,6 +45,7 @@
 #include <asm/i387.h>
 #include <asm/irq.h>
 #include <asm/desc.h>
+#include <asm/atomic_kmap.h>
 #ifdef CONFIG_MATH_EMULATION
 #include <asm/math_emu.h>
 #endif
@@ -302,6 +303,9 @@ void flush_thread(void)
 	struct task_struct *tsk = current;
 
 	memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8);
+#ifdef CONFIG_X86_HIGH_ENTRY
+	clear_thread_flag(TIF_DB7);
+#endif
 	memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));	
 	/*
 	 * Forget coprocessor state..
@@ -315,9 +319,8 @@ void release_thread(struct task_struct *
 	if (dead_task->mm) {
 		// temporary debugging check
 		if (dead_task->mm->context.size) {
-			printk("WARNING: dead process %8s still has LDT? <%p/%d>\n",
+			printk("WARNING: dead process %8s still has LDT? <%d>\n",
 					dead_task->comm,
-					dead_task->mm->context.ldt,
 					dead_task->mm->context.size);
 			BUG();
 		}
@@ -352,7 +355,17 @@ int copy_thread(int nr, unsigned long cl
 	p->thread.esp = (unsigned long) childregs;
 	p->thread.esp0 = (unsigned long) (childregs+1);
 
+	/*
+	 * get the two stack pages, for the virtual stack.
+	 *
+	 * IMPORTANT: this code relies on the fact that the task
+	 * structure is an 8K aligned piece of physical memory.
+	 */
+	p->thread.stack_page0 = virt_to_page((unsigned long)p->thread_info);
+	p->thread.stack_page1 = virt_to_page((unsigned long)p->thread_info + PAGE_SIZE);
+
 	p->thread.eip = (unsigned long) ret_from_fork;
+	p->thread_info->real_stack = p->thread_info;
 
 	savesegment(fs,p->thread.fs);
 	savesegment(gs,p->thread.gs);
@@ -493,7 +506,7 @@ int dump_task_regs(struct task_struct *t
  * the task-switch, and shows up in ret_from_fork in entry.S,
  * for example.
  */
-struct task_struct * __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
+struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
 {
 	struct thread_struct *prev = &prev_p->thread,
 				 *next = &next_p->thread;
@@ -504,10 +517,41 @@ struct task_struct * __switch_to(struct 
 
 	__unlazy_fpu(prev_p);
 
+#ifdef CONFIG_X86_HIGH_ENTRY
+	/*
+	 * Set the ptes of the virtual stack. (NOTE: a one-page TLB flush is
+	 * needed because otherwise NMIs could interrupt the
+	 * user-return code with a virtual stack and stale TLBs.)
+	 */
+	__kunmap_atomic_type(KM_VSTACK0);
+	__kunmap_atomic_type(KM_VSTACK1);
+	__kmap_atomic(next->stack_page0, KM_VSTACK0);
+	__kmap_atomic(next->stack_page1, KM_VSTACK1);
+
+	/*
+	 * NOTE: here we rely on the task being the stack as well
+	 */
+	next_p->thread_info->virtual_stack =
+			(void *)__kmap_atomic_vaddr(KM_VSTACK0);
+
+#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)
+	/*
+	 * If next was preempted on entry from userspace to kernel,
+	 * and now it's on a different cpu, we need to adjust %esp.
+	 * This assumes that entry.S does not copy %esp while on the
+	 * virtual stack (with interrupts enabled): which is so,
+	 * except within __SWITCH_KERNELSPACE itself.
+	 */
+	if (unlikely(next->esp >= TASK_SIZE)) {
+		next->esp &= THREAD_SIZE - 1;
+		next->esp |= (unsigned long) next_p->thread_info->virtual_stack;
+	}
+#endif
+#endif
 	/*
 	 * Reload esp0, LDT and the page table pointer:
 	 */
-	load_esp0(tss, next);
+	load_virtual_esp0(tss, next_p);
 
 	/*
 	 * Load the per-thread Thread-Local Storage descriptor.
--- diff/arch/i386/kernel/reboot.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/i386/kernel/reboot.c	2004-03-09 11:51:48.000000000 +0000
@@ -155,12 +155,11 @@ void machine_real_restart(unsigned char 
 	CMOS_WRITE(0x00, 0x8f);
 	spin_unlock_irqrestore(&rtc_lock, flags);
 
-	/* Remap the kernel at virtual address zero, as well as offset zero
-	   from the kernel segment.  This assumes the kernel segment starts at
-	   virtual address PAGE_OFFSET. */
-
-	memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
-		sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
+	/*
+	 * Remap the first 16 MB of RAM (which includes the kernel image)
+	 * at virtual address zero:
+	 */
+	setup_identity_mappings(swapper_pg_dir, 0, 16*1024*1024);
 
 	/*
 	 * Use `swapper_pg_dir' as our page directory.
--- diff/arch/i386/kernel/setup.c	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/i386/kernel/setup.c	2004-03-09 11:51:48.000000000 +0000
@@ -50,6 +50,11 @@
 #include "setup_arch_pre.h"
 #include "mach_resources.h"
 
+/* This value is set up by the early boot code to point to the value
+   immediately after the boot time page tables.  It contains a *physical*
+   address, and must not be in the .bss segment! */
+unsigned long init_pg_tables_end __initdata = ~0UL;
+
 int disable_pse __initdata = 0;
 
 static inline char * __init machine_specific_memory_setup(void);
@@ -115,7 +120,6 @@ extern void early_cpu_init(void);
 extern void dmi_scan_machine(void);
 extern void generic_apic_probe(char *);
 extern int root_mountflags;
-extern char _end[];
 
 unsigned long saved_videomode;
 
@@ -569,6 +573,11 @@ static void __init parse_cmdline_early (
 			acpi_disabled = 0;
 		}
 
+		/* acpi=strict disables out-of-spec workarounds */
+		else if (!memcmp(from, "acpi=strict", 11)) {
+			acpi_strict = 1;
+		}
+
 		/* Limit ACPI just to boot-time to enable HT */
 		else if (!memcmp(from, "acpi=ht", 7)) {
 			acpi_ht = 1;
@@ -785,7 +794,7 @@ static unsigned long __init setup_memory
 	 * partially used pages are not usable - thus
 	 * we are rounding upwards:
 	 */
-	start_pfn = PFN_UP(__pa(_end));
+	start_pfn = PFN_UP(init_pg_tables_end);
 
 	find_max_pfn();
 
@@ -823,6 +832,13 @@ static unsigned long __init setup_memory
 	 */
 	reserve_bootmem(0, PAGE_SIZE);
 
+    /* could be an AMD 768MPX chipset. Reserve a page  before VGA to prevent
+       PCI prefetch into it (errata #56). Usually the page is reserved anyways,
+       unless you have no PS/2 mouse plugged in. */
+	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+	    boot_cpu_data.x86 == 6)
+	     reserve_bootmem(0xa0000 - 4096, 4096);
+
 #ifdef CONFIG_SMP
 	/*
 	 * But first pinch a few for the stack/trampoline stuff
@@ -1097,7 +1113,7 @@ void __init setup_arch(char **cmdline_p)
 	init_mm.start_code = (unsigned long) _text;
 	init_mm.end_code = (unsigned long) _etext;
 	init_mm.end_data = (unsigned long) _edata;
-	init_mm.brk = (unsigned long) _end;
+	init_mm.brk = init_pg_tables_end + PAGE_OFFSET;
 
 	code_resource.start = virt_to_phys(_text);
 	code_resource.end = virt_to_phys(_etext)-1;
--- diff/arch/i386/kernel/signal.c	2003-11-25 15:24:57.000000000 +0000
+++ source/arch/i386/kernel/signal.c	2004-03-09 11:51:48.000000000 +0000
@@ -128,28 +128,29 @@ sys_sigaltstack(const stack_t __user *us
  */
 
 static int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax)
+restore_sigcontext(struct pt_regs *regs,
+		struct sigcontext __user *__sc, int *peax)
 {
-	unsigned int err = 0;
+	struct sigcontext scratch; /* 88 bytes of scratch area */
 
 	/* Always make any pending restarted system calls return -EINTR */
 	current_thread_info()->restart_block.fn = do_no_restart_syscall;
 
-#define COPY(x)		err |= __get_user(regs->x, &sc->x)
+	if (copy_from_user(&scratch, __sc, sizeof(scratch)))
+		return -EFAULT;
+
+#define COPY(x)		regs->x = scratch.x
 
 #define COPY_SEG(seg)							\
-	{ unsigned short tmp;						\
-	  err |= __get_user(tmp, &sc->seg);				\
+	{ unsigned short tmp = scratch.seg;				\
 	  regs->x##seg = tmp; }
 
 #define COPY_SEG_STRICT(seg)						\
-	{ unsigned short tmp;						\
-	  err |= __get_user(tmp, &sc->seg);				\
+	{ unsigned short tmp = scratch.seg;				\
 	  regs->x##seg = tmp|3; }
 
 #define GET_SEG(seg)							\
-	{ unsigned short tmp;						\
-	  err |= __get_user(tmp, &sc->seg);				\
+	{ unsigned short tmp = scratch.seg;				\
 	  loadsegment(seg,tmp); }
 
 	GET_SEG(gs);
@@ -168,27 +169,23 @@ restore_sigcontext(struct pt_regs *regs,
 	COPY_SEG_STRICT(ss);
 	
 	{
-		unsigned int tmpflags;
-		err |= __get_user(tmpflags, &sc->eflags);
+		unsigned int tmpflags = scratch.eflags;
 		regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
 		regs->orig_eax = -1;		/* disable syscall checks */
 	}
 
 	{
-		struct _fpstate __user * buf;
-		err |= __get_user(buf, &sc->fpstate);
+		struct _fpstate * buf = scratch.fpstate;
 		if (buf) {
 			if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
-				goto badframe;
-			err |= restore_i387(buf);
+				return -EFAULT;
+			if (restore_i387(buf))
+				return -EFAULT;
 		}
 	}
 
-	err |= __get_user(*peax, &sc->eax);
-	return err;
-
-badframe:
-	return 1;
+	*peax = scratch.eax;
+	return 0;
 }
 
 asmlinkage int sys_sigreturn(unsigned long __unused)
@@ -266,46 +263,47 @@ badframe:
  */
 
 static int
-setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
+setup_sigcontext(struct sigcontext __user *__sc, struct _fpstate __user *fpstate,
 		 struct pt_regs *regs, unsigned long mask)
 {
-	int tmp, err = 0;
+	struct sigcontext sc; /* 88 bytes of scratch area */
+	int tmp;
 
 	tmp = 0;
 	__asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
-	err |= __put_user(tmp, (unsigned int *)&sc->gs);
+	*(unsigned int *)&sc.gs = tmp;
 	__asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
-	err |= __put_user(tmp, (unsigned int *)&sc->fs);
-
-	err |= __put_user(regs->xes, (unsigned int *)&sc->es);
-	err |= __put_user(regs->xds, (unsigned int *)&sc->ds);
-	err |= __put_user(regs->edi, &sc->edi);
-	err |= __put_user(regs->esi, &sc->esi);
-	err |= __put_user(regs->ebp, &sc->ebp);
-	err |= __put_user(regs->esp, &sc->esp);
-	err |= __put_user(regs->ebx, &sc->ebx);
-	err |= __put_user(regs->edx, &sc->edx);
-	err |= __put_user(regs->ecx, &sc->ecx);
-	err |= __put_user(regs->eax, &sc->eax);
-	err |= __put_user(current->thread.trap_no, &sc->trapno);
-	err |= __put_user(current->thread.error_code, &sc->err);
-	err |= __put_user(regs->eip, &sc->eip);
-	err |= __put_user(regs->xcs, (unsigned int *)&sc->cs);
-	err |= __put_user(regs->eflags, &sc->eflags);
-	err |= __put_user(regs->esp, &sc->esp_at_signal);
-	err |= __put_user(regs->xss, (unsigned int *)&sc->ss);
+	*(unsigned int *)&sc.fs = tmp;
+	*(unsigned int *)&sc.es = regs->xes;
+	*(unsigned int *)&sc.ds = regs->xds;
+	sc.edi = regs->edi;
+	sc.esi = regs->esi;
+	sc.ebp = regs->ebp;
+	sc.esp = regs->esp;
+	sc.ebx = regs->ebx;
+	sc.edx = regs->edx;
+	sc.ecx = regs->ecx;
+	sc.eax = regs->eax;
+	sc.trapno = current->thread.trap_no;
+	sc.err = current->thread.error_code;
+	sc.eip = regs->eip;
+	*(unsigned int *)&sc.cs = regs->xcs;
+	sc.eflags = regs->eflags;
+	sc.esp_at_signal = regs->esp;
+	*(unsigned int *)&sc.ss = regs->xss;
 
 	tmp = save_i387(fpstate);
 	if (tmp < 0)
-	  err = 1;
-	else
-	  err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
+		return 1;
+	sc.fpstate = tmp ? fpstate : NULL;
 
 	/* non-iBCS2 extensions.. */
-	err |= __put_user(mask, &sc->oldmask);
-	err |= __put_user(current->thread.cr2, &sc->cr2);
+	sc.oldmask = mask;
+	sc.cr2 = current->thread.cr2;
 
-	return err;
+	if (copy_to_user(__sc, &sc, sizeof(sc)))
+		return 1;
+	return 0;
 }
 
 /*
@@ -443,7 +441,7 @@ static void setup_rt_frame(int sig, stru
 	/* Create the ucontext.  */
 	err |= __put_user(0, &frame->uc.uc_flags);
 	err |= __put_user(0, &frame->uc.uc_link);
-	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+	err |= __put_user(current->sas_ss_sp, (unsigned long *)&frame->uc.uc_stack.ss_sp);
 	err |= __put_user(sas_ss_flags(regs->esp),
 			  &frame->uc.uc_stack.ss_flags);
 	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
@@ -551,7 +549,7 @@ handle_signal(unsigned long sig, siginfo
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
  */
-int do_signal(struct pt_regs *regs, sigset_t *oldset)
+int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset)
 {
 	siginfo_t info;
 	int signr;
--- diff/arch/i386/kernel/smp.c	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/kernel/smp.c	2004-03-09 11:51:48.000000000 +0000
@@ -150,7 +150,7 @@ inline void __send_IPI_shortcut(unsigned
 	apic_write_around(APIC_ICR, cfg);
 }
 
-void send_IPI_self(int vector)
+void fastcall send_IPI_self(int vector)
 {
 	__send_IPI_shortcut(APIC_DEST_SELF, vector);
 }
@@ -327,10 +327,12 @@ asmlinkage void smp_invalidate_interrupt
 		 
 	if (flush_mm == cpu_tlbstate[cpu].active_mm) {
 		if (cpu_tlbstate[cpu].state == TLBSTATE_OK) {
+#ifndef CONFIG_X86_SWITCH_PAGETABLES
 			if (flush_va == FLUSH_ALL)
 				local_flush_tlb();
 			else
 				__flush_tlb_one(flush_va);
+#endif
 		} else
 			leave_mm(cpu);
 	}
@@ -396,21 +398,6 @@ static void flush_tlb_others(cpumask_t c
 	spin_unlock(&tlbstate_lock);
 }
 	
-void flush_tlb_current_task(void)
-{
-	struct mm_struct *mm = current->mm;
-	cpumask_t cpu_mask;
-
-	preempt_disable();
-	cpu_mask = mm->cpu_vm_mask;
-	cpu_clear(smp_processor_id(), cpu_mask);
-
-	local_flush_tlb();
-	if (!cpus_empty(cpu_mask))
-		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
-	preempt_enable();
-}
-
 void flush_tlb_mm (struct mm_struct * mm)
 {
 	cpumask_t cpu_mask;
@@ -442,7 +429,10 @@ void flush_tlb_page(struct vm_area_struc
 
 	if (current->active_mm == mm) {
 		if(current->mm)
-			__flush_tlb_one(va);
+#ifndef CONFIG_X86_SWITCH_PAGETABLES
+			__flush_tlb_one(va)
+#endif
+				;
 		 else
 		 	leave_mm(smp_processor_id());
 	}
@@ -466,7 +456,17 @@ void flush_tlb_all(void)
 {
 	on_each_cpu(do_flush_tlb_all, 0, 1, 1);
 }
-
+#ifdef CONFIG_KGDB
+/*
+ * By using the NMI code instead of a vector we just sneak thru the
+ * word generator coming out with just what we want.  AND it does
+ * not matter if clustered_apic_mode is set or not.
+ */
+void smp_send_nmi_allbutself(void)
+{
+	send_IPI_allbutself(APIC_DM_NMI);
+}
+#endif
 /*
  * this function sends a 'reschedule' IPI to another CPU.
  * it goes straight through and wastes no time serializing
--- diff/arch/i386/kernel/smpboot.c	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/i386/kernel/smpboot.c	2004-03-09 11:51:48.000000000 +0000
@@ -39,6 +39,7 @@
 #include <linux/kernel.h>
 
 #include <linux/mm.h>
+#include <linux/sched.h>
 #include <linux/kernel_stat.h>
 #include <linux/smp_lock.h>
 #include <linux/irq.h>
@@ -815,6 +816,8 @@ static int __init do_boot_cpu(int apicid
 	/* Stack for startup_32 can be just as for start_secondary onwards */
 	stack_start.esp = (void *) idle->thread.esp;
 
+	irq_ctx_init(cpu);
+
 	/*
 	 * This grunge runs the startup process for
 	 * the targeted processor.
@@ -934,7 +937,7 @@ static int boot_cpu_logical_apicid;
 /* Where the IO area was mapped on multiquad, always 0 otherwise */
 void *xquad_portio;
 
-int cpu_sibling_map[NR_CPUS] __cacheline_aligned;
+cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
 
 static void __init smp_boot_cpus(unsigned int max_cpus)
 {
@@ -953,6 +956,8 @@ static void __init smp_boot_cpus(unsigne
 
 	current_thread_info()->cpu = 0;
 	smp_tune_scheduling();
+	cpus_clear(cpu_sibling_map[0]);
+	cpu_set(0, cpu_sibling_map[0]);
 
 	/*
 	 * If we couldn't find an SMP configuration at boot time,
@@ -1079,32 +1084,34 @@ static void __init smp_boot_cpus(unsigne
 	Dprintk("Boot done.\n");
 
 	/*
-	 * If Hyper-Threading is avaialble, construct cpu_sibling_map[], so
-	 * that we can tell the sibling CPU efficiently.
+	 * construct cpu_sibling_map[], so that we can tell sibling CPUs
+	 * efficiently.
 	 */
-	if (cpu_has_ht && smp_num_siblings > 1) {
-		for (cpu = 0; cpu < NR_CPUS; cpu++)
-			cpu_sibling_map[cpu] = NO_PROC_ID;
-		
-		for (cpu = 0; cpu < NR_CPUS; cpu++) {
-			int 	i;
-			if (!cpu_isset(cpu, cpu_callout_map))
-				continue;
+	for (cpu = 0; cpu < NR_CPUS; cpu++)
+		cpus_clear(cpu_sibling_map[cpu]);
 
+	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+		int siblings = 0;
+		int i;
+		if (!cpu_isset(cpu, cpu_callout_map))
+			continue;
+
+		if (smp_num_siblings > 1) {
 			for (i = 0; i < NR_CPUS; i++) {
-				if (i == cpu || !cpu_isset(i, cpu_callout_map))
+				if (!cpu_isset(i, cpu_callout_map))
 					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;
+					siblings++;
+					cpu_set(i, cpu_sibling_map[cpu]);
 				}
 			}
-			if (cpu_sibling_map[cpu] == NO_PROC_ID) {
-				smp_num_siblings = 1;
-				printk(KERN_WARNING "WARNING: No sibling found for CPU %d.\n", cpu);
-			}
+		} else {
+			siblings++;
+			cpu_set(cpu, cpu_sibling_map[cpu]);
 		}
+
+		if (siblings != smp_num_siblings)
+			printk(KERN_WARNING "WARNING: %d siblings found for CPU%d, should be %d\n", siblings, cpu, smp_num_siblings);
 	}
 
 	smpboot_setup_io_apic();
@@ -1118,6 +1125,224 @@ static void __init smp_boot_cpus(unsigne
 		synchronize_tsc_bp();
 }
 
+#ifdef CONFIG_SCHED_SMT
+#ifdef CONFIG_NUMA
+static struct sched_group sched_group_cpus[NR_CPUS];
+static struct sched_group sched_group_phys[NR_CPUS];
+static struct sched_group sched_group_nodes[MAX_NUMNODES];
+static DEFINE_PER_CPU(struct sched_domain, phys_domains);
+static DEFINE_PER_CPU(struct sched_domain, node_domains);
+__init void arch_init_sched_domains(void)
+{
+	int i;
+	struct sched_group *first_cpu = NULL, *last_cpu = NULL;
+
+	/* Set up domains */
+	for_each_cpu(i) {
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+		struct sched_domain *phys_domain = &per_cpu(phys_domains, i);
+		struct sched_domain *node_domain = &per_cpu(node_domains, i);
+		int node = cpu_to_node(i);
+		cpumask_t nodemask = node_to_cpumask(node);
+
+		*cpu_domain = SD_SIBLING_INIT;
+		cpu_domain->span = cpu_sibling_map[i];
+
+		*phys_domain = SD_CPU_INIT;
+		phys_domain->span = nodemask;
+
+		*node_domain = SD_NODE_INIT;
+		node_domain->span = cpu_possible_map;
+	}
+
+	/* Set up CPU (sibling) groups */
+	for_each_cpu(i) {
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+		int j;
+		first_cpu = last_cpu = NULL;
+
+		if (i != first_cpu(cpu_domain->span)) {
+			cpu_sched_domain(i)->flags |= SD_FLAG_SHARE_CPUPOWER;
+			cpu_sched_domain(first_cpu(cpu_domain->span))->flags |=
+				SD_FLAG_SHARE_CPUPOWER;
+			continue;
+		}
+
+		for_each_cpu_mask(j, cpu_domain->span) {
+			struct sched_group *cpu = &sched_group_cpus[j];
+
+			cpu->cpumask = CPU_MASK_NONE;
+			cpu_set(j, cpu->cpumask);
+			cpu->cpu_power = SCHED_LOAD_SCALE;
+
+			if (!first_cpu)
+				first_cpu = cpu;
+			if (last_cpu)
+				last_cpu->next = cpu;
+			last_cpu = cpu;
+		}
+		last_cpu->next = first_cpu;
+	}
+
+	for (i = 0; i < MAX_NUMNODES; i++) {
+		int j;
+		cpumask_t nodemask;
+		struct sched_group *node = &sched_group_nodes[i];
+		cpus_and(nodemask, node_to_cpumask(i), cpu_possible_map);
+
+		if (cpus_empty(nodemask))
+			continue;
+
+		first_cpu = last_cpu = NULL;
+		/* Set up physical groups */
+		for_each_cpu_mask(j, nodemask) {
+			struct sched_domain *cpu_domain = cpu_sched_domain(j);
+			struct sched_group *cpu = &sched_group_phys[j];
+
+			if (j != first_cpu(cpu_domain->span))
+				continue;
+
+			cpu->cpumask = cpu_domain->span;
+			/*
+			 * Make each extra sibling increase power by 10% of
+			 * the basic CPU. This is very arbitrary.
+			 */
+			cpu->cpu_power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE*(cpus_weight(cpu->cpumask)-1) / 10;
+			node->cpu_power += cpu->cpu_power;
+
+			if (!first_cpu)
+				first_cpu = cpu;
+			if (last_cpu)
+				last_cpu->next = cpu;
+			last_cpu = cpu;
+		}
+		last_cpu->next = first_cpu;
+	}
+
+	/* Set up nodes */
+	first_cpu = last_cpu = NULL;
+	for (i = 0; i < MAX_NUMNODES; i++) {
+		struct sched_group *cpu = &sched_group_nodes[i];
+		cpumask_t nodemask;
+		cpus_and(nodemask, node_to_cpumask(i), cpu_possible_map);
+
+		if (cpus_empty(nodemask))
+			continue;
+
+		cpu->cpumask = nodemask;
+		/* ->cpu_power already setup */
+
+		if (!first_cpu)
+			first_cpu = cpu;
+		if (last_cpu)
+			last_cpu->next = cpu;
+		last_cpu = cpu;
+	}
+	last_cpu->next = first_cpu;
+
+	mb();
+	for_each_cpu(i) {
+		int node = cpu_to_node(i);
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+		struct sched_domain *phys_domain = &per_cpu(phys_domains, i);
+		struct sched_domain *node_domain = &per_cpu(node_domains, i);
+		struct sched_group *cpu_group = &sched_group_cpus[i];
+		struct sched_group *phys_group = &sched_group_phys[first_cpu(cpu_domain->span)];
+		struct sched_group *node_group = &sched_group_nodes[node];
+
+		cpu_domain->parent = phys_domain;
+		phys_domain->parent = node_domain;
+
+		node_domain->groups = node_group;
+		phys_domain->groups = phys_group;
+		cpu_domain->groups = cpu_group;
+	}
+}
+#else /* CONFIG_NUMA */
+static struct sched_group sched_group_cpus[NR_CPUS];
+static struct sched_group sched_group_phys[NR_CPUS];
+static DEFINE_PER_CPU(struct sched_domain, phys_domains);
+__init void arch_init_sched_domains(void)
+{
+	int i;
+	struct sched_group *first_cpu = NULL, *last_cpu = NULL;
+
+	/* Set up domains */
+	for_each_cpu(i) {
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+		struct sched_domain *phys_domain = &per_cpu(phys_domains, i);
+
+		*cpu_domain = SD_SIBLING_INIT;
+		cpu_domain->span = cpu_sibling_map[i];
+
+		*phys_domain = SD_CPU_INIT;
+		phys_domain->span = cpu_possible_map;
+	}
+
+	/* Set up CPU (sibling) groups */
+	for_each_cpu(i) {
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+		int j;
+		first_cpu = last_cpu = NULL;
+
+		if (i != first_cpu(cpu_domain->span)) {
+			cpu_sched_domain(i)->flags |= SD_FLAG_SHARE_CPUPOWER;
+			cpu_sched_domain(first_cpu(cpu_domain->span))->flags |=
+				SD_FLAG_SHARE_CPUPOWER;
+			continue;
+		}
+
+		for_each_cpu_mask(j, cpu_domain->span) {
+			struct sched_group *cpu = &sched_group_cpus[j];
+
+			cpus_clear(cpu->cpumask);
+			cpu_set(j, cpu->cpumask);
+			cpu->cpu_power = SCHED_LOAD_SCALE;
+
+			if (!first_cpu)
+				first_cpu = cpu;
+			if (last_cpu)
+				last_cpu->next = cpu;
+			last_cpu = cpu;
+		}
+		last_cpu->next = first_cpu;
+	}
+
+	first_cpu = last_cpu = NULL;
+	/* Set up physical groups */
+	for_each_cpu(i) {
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+		struct sched_group *cpu = &sched_group_phys[i];
+
+		if (i != first_cpu(cpu_domain->span))
+			continue;
+
+		cpu->cpumask = cpu_domain->span;
+		/* See SMT+NUMA setup for comment */
+		cpu->cpu_power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE*(cpus_weight(cpu->cpumask)-1) / 10;
+
+		if (!first_cpu)
+			first_cpu = cpu;
+		if (last_cpu)
+			last_cpu->next = cpu;
+		last_cpu = cpu;
+	}
+	last_cpu->next = first_cpu;
+
+	mb();
+	for_each_cpu(i) {
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+		struct sched_domain *phys_domain = &per_cpu(phys_domains, i);
+		struct sched_group *cpu_group = &sched_group_cpus[i];
+		struct sched_group *phys_group = &sched_group_phys[first_cpu(cpu_domain->span)];
+		cpu_domain->parent = phys_domain;
+		phys_domain->groups = phys_group;
+		cpu_domain->groups = cpu_group;
+	}
+}
+#endif /* CONFIG_NUMA */
+#endif /* CONFIG_SCHED_SMT */
+
 /* These are wrappers to interface to the new boot process.  Someone
    who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */
 void __init smp_prepare_cpus(unsigned int max_cpus)
--- diff/arch/i386/kernel/sysenter.c	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/kernel/sysenter.c	2004-03-09 11:51:48.000000000 +0000
@@ -18,13 +18,18 @@
 #include <asm/msr.h>
 #include <asm/pgtable.h>
 #include <asm/unistd.h>
+#include <linux/highmem.h>
 
 extern asmlinkage void sysenter_entry(void);
 
 void enable_sep_cpu(void *info)
 {
 	int cpu = get_cpu();
+#ifdef CONFIG_X86_HIGH_ENTRY
+	struct tss_struct *tss = (struct tss_struct *) __fix_to_virt(FIX_TSS_0) + cpu;
+#else
 	struct tss_struct *tss = init_tss + cpu;
+#endif
 
 	tss->ss1 = __KERNEL_CS;
 	tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss;
--- diff/arch/i386/kernel/trampoline.S	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/i386/kernel/trampoline.S	2004-03-09 11:51:48.000000000 +0000
@@ -23,9 +23,13 @@
  *	and IP is zero.  Thus, data addresses need to be absolute
  *	(no relocation) and are taken with regard to r_base.
  *
- *	If you work on this file, check the object module with objdump
- *	--full-contents --reloc to make sure there are no relocation
- *	entries except for the gdt one..
+ *	If you work on this file, check the object module with
+ *	objdump --reloc to make sure there are no relocation
+ *	entries except for:
+ *
+ *	TYPE              VALUE
+ *	R_386_32          startup_32_smp
+ *	R_386_32          boot_gdt_table
  */
 
 #include <linux/linkage.h>
@@ -42,7 +46,6 @@ r_base = .
 	mov	%cs, %ax	# Code and data in the same place
 	mov	%ax, %ds
 
-	mov	$1, %bx		# Flag an SMP trampoline
 	cli			# We should be safe anyway
 
 	movl	$0xA5A5A5A5, trampoline_data - r_base
@@ -54,22 +57,18 @@ r_base = .
 	xor	%ax, %ax
 	inc	%ax		# protected mode (PE) bit
 	lmsw	%ax		# into protected mode
-	jmp	flush_instr
-flush_instr:
-	ljmpl	$__BOOT_CS, $0x00100000
-			# jump to startup_32 in arch/i386/kernel/head.S
-
-boot_idt:
-	.word	0			# idt limit = 0
-	.word	0, 0			# idt base = 0L
+	# flush prefetch and jump to startup_32_smp in arch/i386/kernel/head.S
+	ljmpl	$__BOOT_CS, $(startup_32_smp-__PAGE_OFFSET)
 
-#
-# NOTE: here we actually use CPU#0's GDT - but that is OK, we reload
-# the proper GDT shortly after booting up the secondary CPUs.
-#
-ENTRY(boot_gdt)
+	# These need to be in the same 64K segment as the above;
+	# hence we don't use the boot_gdt_descr defined in head.S
+boot_gdt:
 	.word	__BOOT_DS + 7			# gdt limit
-	.long	boot_gdt_table-__PAGE_OFFSET	# gdt base = gdt (first SMP CPU)
+	.long	boot_gdt_table-__PAGE_OFFSET	# gdt base
+
+boot_idt:
+	.word	0				# idt limit = 0
+	.long	0				# idt base = 0L
 
 .globl trampoline_end
 trampoline_end:
--- diff/arch/i386/kernel/traps.c	2004-03-04 11:41:42.000000000 +0000
+++ source/arch/i386/kernel/traps.c	2004-03-09 11:51:48.000000000 +0000
@@ -54,12 +54,8 @@
 
 #include "mach_traps.h"
 
-asmlinkage int system_call(void);
-asmlinkage void lcall7(void);
-asmlinkage void lcall27(void);
-
-struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 },
-		{ 0, 0 }, { 0, 0 } };
+struct desc_struct default_ldt[] __attribute__((__section__(".data.default_ldt"))) = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
+struct page *default_ldt_page;
 
 /* Do we ignore FPU interrupts ? */
 char ignore_fpu_irq = 0;
@@ -91,6 +87,41 @@ asmlinkage void alignment_check(void);
 asmlinkage void spurious_interrupt_bug(void);
 asmlinkage void machine_check(void);
 
+#ifdef CONFIG_KGDB
+extern void sysenter_entry(void);
+#include <asm/kgdb.h>
+#include <linux/init.h>
+void set_intr_gate(unsigned int n, void *addr);
+static void set_intr_usr_gate(unsigned int n, void *addr);
+/*
+ * Should be able to call this breakpoint() very early in
+ * bring up.  Just hard code the call where needed.
+ * The breakpoint() code is here because set_?_gate() functions
+ * are local (static) to trap.c.  They need be done only once,
+ * but it does not hurt to do them over.
+ */
+void breakpoint(void)
+{
+	init_entry_mappings();
+        set_intr_usr_gate(3,&int3); /* disable ints on trap */
+	set_intr_gate(1,&debug);
+	set_intr_gate(14,&page_fault);
+
+        BREAKPOINT;
+}
+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)		\
+    {									\
+	if (!user_mode(regs)  ) \
+	{								\
+		kgdb_handle_exception(trapnr, signr, error_code, regs);	\
+		after;							\
+	} else if ((trapnr == 3) && (regs->eflags &0x200)) local_irq_enable(); \
+    }
+#else
+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)
+#endif
+
+
 static int kstack_depth_to_print = 24;
 
 void show_trace(struct task_struct *task, unsigned long * stack)
@@ -104,12 +135,20 @@ void show_trace(struct task_struct *task
 #ifdef CONFIG_KALLSYMS
 	printk("\n");
 #endif
-	while (!kstack_end(stack)) {
-		addr = *stack++;
-		if (kernel_text_address(addr)) {
-			printk(" [<%08lx>] ", addr);
-			print_symbol("%s\n", addr);
+	while (1) {
+		struct thread_info *context;
+		context = (struct thread_info*) ((unsigned long)stack & (~(THREAD_SIZE - 1)));
+		while (!kstack_end(stack)) {
+			addr = *stack++;
+			if (kernel_text_address(addr)) {
+				printk(" [<%08lx>] ", addr);
+				print_symbol("%s\n", addr);
+			}
 		}
+		stack = (unsigned long*)context->previous_esp;
+		if (!stack)
+			break;
+		printk(" =======================\n");
 	}
 	printk("\n");
 }
@@ -175,8 +214,9 @@ void show_registers(struct pt_regs *regs
 		ss = regs->xss & 0xffff;
 	}
 	print_modules();
-	printk("CPU:    %d\nEIP:    %04x:[<%08lx>]    %s\nEFLAGS: %08lx\n",
-		smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags);
+	printk("CPU:    %d\nEIP:    %04x:[<%08lx>]    %s VLI\nEFLAGS: %08lx\n",
+		smp_processor_id(), 0xffff & regs->xcs,
+		regs->eip, print_tainted(), regs->eflags);
 
 	print_symbol("EIP is at %s\n", regs->eip);
 	printk("eax: %08lx   ebx: %08lx   ecx: %08lx   edx: %08lx\n",
@@ -192,23 +232,27 @@ void show_registers(struct pt_regs *regs
 	 * time of the fault..
 	 */
 	if (in_kernel) {
+		u8 *eip;
 
 		printk("\nStack: ");
 		show_stack(NULL, (unsigned long*)esp);
 
 		printk("Code: ");
-		if(regs->eip < PAGE_OFFSET)
-			goto bad;
 
-		for(i=0;i<20;i++)
-		{
-			unsigned char c;
-			if(__get_user(c, &((unsigned char*)regs->eip)[i])) {
-bad:
+		eip = (u8 *)regs->eip - 43;
+		for (i = 0; i < 64; i++, eip++) {
+			unsigned char c = 0xff;
+
+			if ((user_mode(regs) && get_user(c, eip)) ||
+			    (!user_mode(regs) && __direct_get_user(c, eip))) {
+
 				printk(" Bad EIP value.");
 				break;
 			}
-			printk("%02x ", c);
+			if (eip == (u8 *)regs->eip)
+				printk("<%02x> ", c);
+			else
+				printk("%02x ", c);
 		}
 	}
 	printk("\n");
@@ -227,16 +271,14 @@ static void handle_BUG(struct pt_regs *r
 
 	eip = regs->eip;
 
-	if (eip < PAGE_OFFSET)
-		goto no_bug;
-	if (__get_user(ud2, (unsigned short *)eip))
+	if (__direct_get_user(ud2, (unsigned short *)eip))
 		goto no_bug;
 	if (ud2 != 0x0b0f)
 		goto no_bug;
-	if (__get_user(line, (unsigned short *)(eip + 2)))
+	if (__direct_get_user(line, (unsigned short *)(eip + 2)))
 		goto bug;
-	if (__get_user(file, (char **)(eip + 4)) ||
-		(unsigned long)file < PAGE_OFFSET || __get_user(c, file))
+	if (__direct_get_user(file, (char **)(eip + 4)) ||
+			__direct_get_user(c, file))
 		file = "<bad filename>";
 
 	printk("------------[ cut here ]------------\n");
@@ -276,6 +318,15 @@ void die(const char * str, struct pt_reg
 #endif
 	if (nl)
 		printk("\n");
+#ifdef CONFIG_KGDB
+	/* This is about the only place we want to go to kgdb even if in
+	 * user mode.  But we must go in via a trap so within kgdb we will
+	 * always be in kernel mode.
+	 */
+	if (user_mode(regs))
+		BREAKPOINT;
+#endif
+ 	CHK_REMOTE_DEBUG(0,SIGTRAP,err,regs,)
 	show_registers(regs);
 	bust_spinlocks(0);
 	spin_unlock_irq(&die_lock);
@@ -345,6 +396,7 @@ static inline void do_trap(int trapnr, i
 #define DO_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,)\
 	do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
 }
 
@@ -362,7 +414,9 @@ asmlinkage void do_##name(struct pt_regs
 #define DO_VM86_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	CHK_REMOTE_DEBUG(trapnr, signr, error_code,regs, return)\
 	do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \
+	return; \
 }
 
 #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
@@ -409,8 +463,10 @@ gp_in_vm86:
 	return;
 
 gp_in_kernel:
-	if (!fixup_exception(regs))
+	if (!fixup_exception(regs)){
+ 		CHK_REMOTE_DEBUG(13,SIGSEGV,error_code,regs,)
 		die("general protection fault", regs, error_code);
+	}
 }
 
 static void mem_parity_error(unsigned char reason, struct pt_regs * regs)
@@ -549,10 +605,18 @@ asmlinkage void do_debug(struct pt_regs 
 	if (regs->eflags & X86_EFLAGS_IF)
 		local_irq_enable();
 
-	/* Mask out spurious debug traps due to lazy DR7 setting */
+	/*
+	 * Mask out spurious debug traps due to lazy DR7 setting or
+	 * due to 4G/4G kernel mode:
+	 */
 	if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
 		if (!tsk->thread.debugreg[7])
 			goto clear_dr7;
+		if (!user_mode(regs)) {
+			// restore upon return-to-userspace:
+			set_thread_flag(TIF_DB7);
+			goto clear_dr7;
+		}
 	}
 
 	if (regs->eflags & VM_MASK)
@@ -572,8 +636,18 @@ asmlinkage void do_debug(struct pt_regs 
 		 * allowing programs to debug themselves without the ptrace()
 		 * interface.
 		 */
+#ifdef CONFIG_KGDB
+		/*
+		 * I think this is the only "real" case of a TF in the kernel
+		 * that really belongs to user space.  Others are
+		 * "Ours all ours!"
+		 */
+		if (((regs->xcs & 3) == 0) && ((void *)regs->eip == sysenter_entry))
+			goto clear_TF_reenable;
+#else
 		if ((regs->xcs & 3) == 0)
 			goto clear_TF_reenable;
+#endif
 		if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
 			goto clear_TF;
 	}
@@ -585,6 +659,17 @@ asmlinkage void do_debug(struct pt_regs 
 	info.si_errno = 0;
 	info.si_code = TRAP_BRKPT;
 	
+#ifdef CONFIG_KGDB
+        /*
+	 * If this is a kernel mode trap, we need to reset db7 to allow us
+	 * to continue sanely ALSO skip the signal delivery
+         */
+	if ((regs->xcs & 3) == 0)
+		goto clear_dr7;
+
+        /* if not kernel, allow ints but only if they were on */
+       if ( regs->eflags & 0x200) local_irq_enable();
+#endif
 	/* If this is a kernel mode trap, save the user PC on entry to 
 	 * the kernel, that's what the debugger can make sense of.
 	 */
@@ -599,6 +684,7 @@ clear_dr7:
 	__asm__("movl %0,%%db7"
 		: /* no output */
 		: "r" (0));
+	CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,)
 	return;
 
 debug_vm86:
@@ -794,19 +880,53 @@ asmlinkage void math_emulate(long arg)
 
 #endif /* CONFIG_MATH_EMULATION */
 
-#ifdef CONFIG_X86_F00F_BUG
-void __init trap_init_f00f_bug(void)
+void __init trap_init_virtual_IDT(void)
 {
-	__set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO);
-
 	/*
-	 * Update the IDT descriptor and reload the IDT so that
-	 * it uses the read-only mapped virtual address.
+	 * "idt" is magic - it overlaps the idt_descr
+	 * variable so that updating idt will automatically
+	 * update the idt descriptor..
 	 */
-	idt_descr.address = fix_to_virt(FIX_F00F_IDT);
+	__set_fixmap(FIX_IDT, __pa(&idt_table), PAGE_KERNEL_RO);
+	idt_descr.address = __fix_to_virt(FIX_IDT);
+
 	__asm__ __volatile__("lidt %0" : : "m" (idt_descr));
 }
-#endif
+
+void __init trap_init_virtual_GDT(void)
+{
+	int cpu = smp_processor_id();
+	struct Xgt_desc_struct *gdt_desc = cpu_gdt_descr + cpu;
+	struct Xgt_desc_struct tmp_desc = {0, 0};
+	struct tss_struct * t;
+
+	__asm__ __volatile__("sgdt %0": "=m" (tmp_desc): :"memory");
+
+#ifdef CONFIG_X86_HIGH_ENTRY
+	if (!cpu) {
+		__set_fixmap(FIX_GDT_0, __pa(cpu_gdt_table), PAGE_KERNEL);
+		__set_fixmap(FIX_GDT_1, __pa(cpu_gdt_table) + PAGE_SIZE, PAGE_KERNEL);
+		__set_fixmap(FIX_TSS_0, __pa(init_tss), PAGE_KERNEL);
+		__set_fixmap(FIX_TSS_1, __pa(init_tss) + 1*PAGE_SIZE, PAGE_KERNEL);
+		__set_fixmap(FIX_TSS_2, __pa(init_tss) + 2*PAGE_SIZE, PAGE_KERNEL);
+		__set_fixmap(FIX_TSS_3, __pa(init_tss) + 3*PAGE_SIZE, PAGE_KERNEL);
+	}
+
+	gdt_desc->address = __fix_to_virt(FIX_GDT_0) + sizeof(cpu_gdt_table[0]) * cpu;
+#else
+	gdt_desc->address = (unsigned long)cpu_gdt_table[cpu];
+#endif
+	__asm__ __volatile__("lgdt %0": "=m" (*gdt_desc));
+
+#ifdef CONFIG_X86_HIGH_ENTRY
+	t = (struct tss_struct *) __fix_to_virt(FIX_TSS_0) + cpu;
+#else
+	t = init_tss + cpu;
+#endif
+	set_tss_desc(cpu, t);
+	cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff;
+	load_TR_desc();
+}
 
 #define _set_gate(gate_addr,type,dpl,addr,seg) \
 do { \
@@ -833,20 +953,26 @@ void set_intr_gate(unsigned int n, void 
 	_set_gate(idt_table+n,14,0,addr,__KERNEL_CS);
 }
 
-static void __init set_trap_gate(unsigned int n, void *addr)
+void __init set_trap_gate(unsigned int n, void *addr)
 {
 	_set_gate(idt_table+n,15,0,addr,__KERNEL_CS);
 }
 
-static void __init set_system_gate(unsigned int n, void *addr)
+void __init set_system_gate(unsigned int n, void *addr)
 {
 	_set_gate(idt_table+n,15,3,addr,__KERNEL_CS);
 }
 
-static void __init set_call_gate(void *a, void *addr)
+void __init set_call_gate(void *a, void *addr)
 {
 	_set_gate(a,12,3,addr,__KERNEL_CS);
 }
+#ifdef CONFIG_KGDB
+void set_intr_usr_gate(unsigned int n, void *addr)
+{
+	_set_gate(idt_table+n,14,3,addr,__KERNEL_CS);
+}
+#endif
 
 static void __init set_task_gate(unsigned int n, unsigned int gdt_entry)
 {
@@ -865,11 +991,16 @@ void __init trap_init(void)
 #ifdef CONFIG_X86_LOCAL_APIC
 	init_apic_mappings();
 #endif
+	init_entry_mappings();
 
 	set_trap_gate(0,&divide_error);
 	set_intr_gate(1,&debug);
 	set_intr_gate(2,&nmi);
+#ifndef CONFIG_KGDB
 	set_system_gate(3,&int3);	/* int3-5 can be called from all */
+#else
+	set_intr_usr_gate(3,&int3);	/* int3-5 can be called from all */
+#endif
 	set_system_gate(4,&overflow);
 	set_system_gate(5,&bounds);
 	set_trap_gate(6,&invalid_op);
--- diff/arch/i386/kernel/vm86.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/i386/kernel/vm86.c	2004-03-09 11:51:48.000000000 +0000
@@ -95,7 +95,7 @@
 #define VM86_REGS_SIZE2 (sizeof(struct kernel_vm86_regs) - VM86_REGS_SIZE1)
 
 struct pt_regs * FASTCALL(save_v86_state(struct kernel_vm86_regs * regs));
-struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs)
+struct pt_regs * fastcall save_v86_state(struct kernel_vm86_regs * regs)
 {
 	struct tss_struct *tss;
 	struct pt_regs *ret;
@@ -125,7 +125,7 @@ struct pt_regs * save_v86_state(struct k
 	tss = init_tss + get_cpu();
 	current->thread.esp0 = current->thread.saved_esp0;
 	current->thread.sysenter_cs = __KERNEL_CS;
-	load_esp0(tss, &current->thread);
+	load_virtual_esp0(tss, current);
 	current->thread.saved_esp0 = 0;
 	put_cpu();
 
@@ -305,7 +305,7 @@ static void do_sys_vm86(struct kernel_vm
 	tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
 	if (cpu_has_sep)
 		tsk->thread.sysenter_cs = 0;
-	load_esp0(tss, &tsk->thread);
+	load_virtual_esp0(tss, tsk);
 	put_cpu();
 
 	tsk->thread.screen_bitmap = info->screen_bitmap;
--- diff/arch/i386/kernel/vmlinux.lds.S	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/kernel/vmlinux.lds.S	2004-03-09 11:51:48.000000000 +0000
@@ -3,6 +3,9 @@
  */
 
 #include <asm-generic/vmlinux.lds.h>
+#include <linux/config.h>
+#include <asm/page.h>
+#include <asm/asm_offsets.h>
 	
 OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
 OUTPUT_ARCH(i386)
@@ -10,7 +13,7 @@ ENTRY(startup_32)
 jiffies = jiffies_64;
 SECTIONS
 {
-  . = 0xC0000000 + 0x100000;
+  . = __PAGE_OFFSET + 0x100000;
   /* read-only */
   _text = .;			/* Text and read-only data */
   .text : {
@@ -19,6 +22,19 @@ SECTIONS
 	*(.gnu.warning)
 	} = 0x9090
 
+#ifdef CONFIG_X86_4G
+  . = ALIGN(PAGE_SIZE_asm);
+  __entry_tramp_start = .;
+  . = FIX_ENTRY_TRAMPOLINE_0_addr;
+  __start___entry_text = .;
+  .entry.text : AT (__entry_tramp_start) { *(.entry.text) }
+  __entry_tramp_end = __entry_tramp_start + SIZEOF(.entry.text);
+  . = __entry_tramp_end;
+  . = ALIGN(PAGE_SIZE_asm);
+#else
+  .entry.text : { *(.entry.text) }
+#endif
+
   _etext = .;			/* End of text section */
 
   . = ALIGN(16);		/* Exception table */
@@ -34,15 +50,12 @@ SECTIONS
 	CONSTRUCTORS
 	}
 
-  . = ALIGN(4096);
+  . = ALIGN(PAGE_SIZE_asm);
   __nosave_begin = .;
   .data_nosave : { *(.data.nosave) }
-  . = ALIGN(4096);
+  . = ALIGN(PAGE_SIZE_asm);
   __nosave_end = .;
 
-  . = ALIGN(4096);
-  .data.page_aligned : { *(.data.idt) }
-
   . = ALIGN(32);
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
@@ -52,7 +65,7 @@ SECTIONS
   .data.init_task : { *(.data.init_task) }
 
   /* will be freed after init */
-  . = ALIGN(4096);		/* Init code and data */
+  . = ALIGN(PAGE_SIZE_asm);		/* Init code and data */
   __init_begin = .;
   .init.text : { 
 	_sinittext = .;
@@ -91,7 +104,7 @@ SECTIONS
      from .altinstructions and .eh_frame */
   .exit.text : { *(.exit.text) }
   .exit.data : { *(.exit.data) }
-  . = ALIGN(4096);
+  . = ALIGN(PAGE_SIZE_asm);
   __initramfs_start = .;
   .init.ramfs : { *(.init.ramfs) }
   __initramfs_end = .;
@@ -99,16 +112,33 @@ SECTIONS
   __per_cpu_start = .;
   .data.percpu  : { *(.data.percpu) }
   __per_cpu_end = .;
-  . = ALIGN(4096);
+  . = ALIGN(PAGE_SIZE_asm);
   __init_end = .;
   /* freed after init ends here */
-	
+
+  . = ALIGN(PAGE_SIZE_asm);
+  .data.page_aligned_tss : { *(.data.tss) }
+
+  . = ALIGN(PAGE_SIZE_asm);
+  .data.page_aligned_default_ldt : { *(.data.default_ldt) }
+
+  . = ALIGN(PAGE_SIZE_asm);
+  .data.page_aligned_idt : { *(.data.idt) }
+
+  . = ALIGN(PAGE_SIZE_asm);
+  .data.page_aligned_gdt : { *(.data.gdt) }
+
   __bss_start = .;		/* BSS */
   .bss : { *(.bss) }
+  . = ALIGN(4);
   __bss_stop = .; 
 
   _end = . ;
 
+  /* This is where the kernel creates the early boot page tables */
+  . = ALIGN(4096);
+  pg0 = .;
+
   /* Sections to be discarded */
   /DISCARD/ : {
 	*(.exitcall.exit)
@@ -122,4 +152,6 @@ SECTIONS
   .stab.index 0 : { *(.stab.index) }
   .stab.indexstr 0 : { *(.stab.indexstr) }
   .comment 0 : { *(.comment) }
+
+
 }
--- diff/arch/i386/kernel/vsyscall-sysenter.S	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/kernel/vsyscall-sysenter.S	2004-03-09 11:51:48.000000000 +0000
@@ -7,6 +7,11 @@
 	.type __kernel_vsyscall,@function
 __kernel_vsyscall:
 .LSTART_vsyscall:
+	cmpl $192, %eax
+	jne 1f
+	int $0x80
+	ret
+1:
 	push %ecx
 .Lpush_ecx:
 	push %edx
--- diff/arch/i386/kernel/vsyscall.lds	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/kernel/vsyscall.lds	2004-03-09 11:51:48.000000000 +0000
@@ -5,7 +5,7 @@
  */
 
 /* This must match <asm/fixmap.h>.  */
-VSYSCALL_BASE = 0xffffe000;
+VSYSCALL_BASE = 0xffffd000;
 
 SECTIONS
 {
--- diff/arch/i386/lib/Makefile	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/lib/Makefile	2004-03-09 11:51:48.000000000 +0000
@@ -9,4 +9,4 @@ lib-y = checksum.o delay.o \
 
 lib-$(CONFIG_X86_USE_3DNOW) += mmx.o
 lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
-lib-$(CONFIG_DEBUG_IOVIRT)  += iodebug.o
+lib-$(CONFIG_KGDB) += kgdb_serial.o
--- diff/arch/i386/lib/checksum.S	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/lib/checksum.S	2004-03-09 11:51:48.000000000 +0000
@@ -280,14 +280,14 @@ unsigned int csum_partial_copy_generic (
 	.previous
 
 .align 4
-.globl csum_partial_copy_generic
+.globl direct_csum_partial_copy_generic
 				
 #ifndef CONFIG_X86_USE_PPRO_CHECKSUM
 
 #define ARGBASE 16		
 #define FP		12
 		
-csum_partial_copy_generic:
+direct_csum_partial_copy_generic:
 	subl  $4,%esp	
 	pushl %edi
 	pushl %esi
@@ -422,7 +422,7 @@ DST(	movb %cl, (%edi)	)
 
 #define ARGBASE 12
 		
-csum_partial_copy_generic:
+direct_csum_partial_copy_generic:
 	pushl %ebx
 	pushl %edi
 	pushl %esi
--- diff/arch/i386/lib/dec_and_lock.c	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/lib/dec_and_lock.c	2004-03-09 11:51:48.000000000 +0000
@@ -10,6 +10,7 @@
 #include <linux/spinlock.h>
 #include <asm/atomic.h>
 
+#ifndef ATOMIC_DEC_AND_LOCK
 int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
 {
 	int counter;
@@ -38,3 +39,5 @@ slow_path:
 	spin_unlock(lock);
 	return 0;
 }
+#endif
+
--- diff/arch/i386/lib/getuser.S	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/lib/getuser.S	2004-03-09 11:51:48.000000000 +0000
@@ -9,6 +9,7 @@
  * return value.
  */
 #include <asm/thread_info.h>
+#include <asm/asm_offsets.h>
 
 
 /*
@@ -28,7 +29,7 @@
 .globl __get_user_1
 __get_user_1:
 	GET_THREAD_INFO(%edx)
-	cmpl TI_ADDR_LIMIT(%edx),%eax
+	cmpl TI_addr_limit(%edx),%eax
 	jae bad_get_user
 1:	movzbl (%eax),%edx
 	xorl %eax,%eax
@@ -40,7 +41,7 @@ __get_user_2:
 	addl $1,%eax
 	jc bad_get_user
 	GET_THREAD_INFO(%edx)
-	cmpl TI_ADDR_LIMIT(%edx),%eax
+	cmpl TI_addr_limit(%edx),%eax
 	jae bad_get_user
 2:	movzwl -1(%eax),%edx
 	xorl %eax,%eax
@@ -52,7 +53,7 @@ __get_user_4:
 	addl $3,%eax
 	jc bad_get_user
 	GET_THREAD_INFO(%edx)
-	cmpl TI_ADDR_LIMIT(%edx),%eax
+	cmpl TI_addr_limit(%edx),%eax
 	jae bad_get_user
 3:	movl -3(%eax),%edx
 	xorl %eax,%eax
--- diff/arch/i386/lib/usercopy.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/i386/lib/usercopy.c	2004-03-09 11:51:48.000000000 +0000
@@ -76,7 +76,7 @@ do {									   \
  * and returns @count.
  */
 long
-__strncpy_from_user(char *dst, const char __user *src, long count)
+__direct_strncpy_from_user(char *dst, const char __user *src, long count)
 {
 	long res;
 	__do_strncpy_from_user(dst, src, count, res);
@@ -102,7 +102,7 @@ __strncpy_from_user(char *dst, const cha
  * and returns @count.
  */
 long
-strncpy_from_user(char *dst, const char __user *src, long count)
+direct_strncpy_from_user(char *dst, const char __user *src, long count)
 {
 	long res = -EFAULT;
 	if (access_ok(VERIFY_READ, src, 1))
@@ -147,7 +147,7 @@ do {									\
  * On success, this will be zero.
  */
 unsigned long
-clear_user(void __user *to, unsigned long n)
+direct_clear_user(void __user *to, unsigned long n)
 {
 	might_sleep();
 	if (access_ok(VERIFY_WRITE, to, n))
@@ -167,7 +167,7 @@ clear_user(void __user *to, unsigned lon
  * On success, this will be zero.
  */
 unsigned long
-__clear_user(void __user *to, unsigned long n)
+__direct_clear_user(void __user *to, unsigned long n)
 {
 	__do_clear_user(to, n);
 	return n;
@@ -184,7 +184,7 @@ __clear_user(void __user *to, unsigned l
  * On exception, returns 0.
  * If the string is too long, returns a value greater than @n.
  */
-long strnlen_user(const char __user *s, long n)
+long direct_strnlen_user(const char __user *s, long n)
 {
 	unsigned long mask = -__addr_ok(s);
 	unsigned long res, tmp;
@@ -575,3 +575,4 @@ unsigned long __copy_from_user_ll(void *
 		n = __copy_user_zeroing_intel(to, (const void *) from, n);
 	return n;
 }
+
--- diff/arch/i386/mach-default/Makefile	2002-12-30 10:17:12.000000000 +0000
+++ source/arch/i386/mach-default/Makefile	2004-03-09 11:51:48.000000000 +0000
@@ -2,6 +2,4 @@
 # Makefile for the linux kernel.
 #
 
-EXTRA_CFLAGS	+= -I../kernel
-
 obj-y				:= setup.o topology.o
--- diff/arch/i386/mach-es7000/Makefile	2003-06-30 10:07:28.000000000 +0100
+++ source/arch/i386/mach-es7000/Makefile	2004-03-09 11:51:48.000000000 +0000
@@ -2,6 +2,4 @@
 # Makefile for the linux kernel.
 #
 
-EXTRA_CFLAGS	+= -I../kernel
-
 obj-y		:= setup.o topology.o es7000.o
--- diff/arch/i386/mach-pc9800/Makefile	2003-05-21 11:49:54.000000000 +0100
+++ source/arch/i386/mach-pc9800/Makefile	2004-03-09 11:51:48.000000000 +0000
@@ -2,6 +2,4 @@
 # Makefile for the linux kernel.
 #
 
-EXTRA_CFLAGS	+= -I../kernel
-
 obj-y				:= setup.o topology.o
--- diff/arch/i386/mach-visws/Makefile	2003-02-26 16:01:06.000000000 +0000
+++ source/arch/i386/mach-visws/Makefile	2004-03-09 11:51:48.000000000 +0000
@@ -2,8 +2,6 @@
 # Makefile for the linux kernel.
 #
 
-EXTRA_CFLAGS	+= -I../kernel
-
 obj-y				:= setup.o traps.o reboot.o
 
 obj-$(CONFIG_X86_VISWS_APIC)	+= visws_apic.o
--- diff/arch/i386/math-emu/fpu_system.h	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/math-emu/fpu_system.h	2004-03-09 11:51:48.000000000 +0000
@@ -15,6 +15,7 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <asm/atomic_kmap.h>
 
 /* This sets the pointer FPU_info to point to the argument part
    of the stack frame of math_emulate() */
@@ -22,7 +23,7 @@
 
 /* s is always from a cpu register, and the cpu does bounds checking
  * during register load --> no further bounds checks needed */
-#define LDT_DESCRIPTOR(s)	(((struct desc_struct *)current->mm->context.ldt)[(s) >> 3])
+#define LDT_DESCRIPTOR(s)	(((struct desc_struct *)__kmap_atomic_vaddr(KM_LDT_PAGE0))[(s) >> 3])
 #define SEG_D_SIZE(x)		((x).b & (3 << 21))
 #define SEG_G_BIT(x)		((x).b & (1 << 23))
 #define SEG_GRANULARITY(x)	(((x).b & (1 << 23)) ? 4096 : 1)
--- diff/arch/i386/mm/discontig.c	2003-09-30 15:46:11.000000000 +0100
+++ source/arch/i386/mm/discontig.c	2004-03-09 11:51:48.000000000 +0000
@@ -66,7 +66,7 @@ extern void find_max_pfn(void);
 extern void one_highpage_init(struct page *, int, int);
 
 extern struct e820map e820;
-extern char _end;
+extern unsigned long init_pg_tables_end;
 extern unsigned long highend_pfn, highstart_pfn;
 extern unsigned long max_low_pfn;
 extern unsigned long totalram_pages;
@@ -237,7 +237,7 @@ unsigned long __init setup_memory(void)
 	reserve_pages = calculate_numa_remap_pages();
 
 	/* partially used pages are not usable - thus round upwards */
-	system_start_pfn = min_low_pfn = PFN_UP(__pa(&_end));
+	system_start_pfn = min_low_pfn = PFN_UP(init_pg_tables_end);
 
 	find_max_pfn();
 	system_max_low_pfn = max_low_pfn = find_max_low_pfn();
--- diff/arch/i386/mm/extable.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/i386/mm/extable.c	2004-03-09 11:51:48.000000000 +0000
@@ -12,7 +12,7 @@ int fixup_exception(struct pt_regs *regs
 	const struct exception_table_entry *fixup;
 
 #ifdef CONFIG_PNPBIOS
-	if (unlikely((regs->xcs | 8) == 0x88)) /* 0x80 or 0x88 */
+	if (unlikely((regs->xcs & ~15) == (GDT_ENTRY_PNPBIOS_BASE << 3)))
 	{
 		extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp;
 		extern u32 pnp_bios_is_utter_crap;
@@ -21,7 +21,7 @@ int fixup_exception(struct pt_regs *regs
 		__asm__ volatile(
 			"movl %0, %%esp\n\t"
 			"jmp *%1\n\t"
-			: "=a" (pnp_bios_fault_esp), "=b" (pnp_bios_fault_eip));
+			: : "g" (pnp_bios_fault_esp), "g" (pnp_bios_fault_eip));
 		panic("do_trap: can't hit this");
 	}
 #endif
--- diff/arch/i386/mm/fault.c	2003-12-19 09:51:11.000000000 +0000
+++ source/arch/i386/mm/fault.c	2004-03-09 11:51:48.000000000 +0000
@@ -27,6 +27,7 @@
 #include <asm/pgalloc.h>
 #include <asm/hardirq.h>
 #include <asm/desc.h>
+#include <asm/tlbflush.h>
 
 extern void die(const char *,struct pt_regs *,long);
 
@@ -104,8 +105,17 @@ static inline unsigned long get_segment_
 	if (seg & (1<<2)) {
 		/* Must lock the LDT while reading it. */
 		down(&current->mm->context.sem);
+#if 1
+		/* horrible hack for 4/4 disabled kernels.
+		   I'm not quite sure what the TLB flush is good for,
+		   it's mindlessly copied from the read_ldt code */
+		__flush_tlb_global();
+		desc = kmap(current->mm->context.ldt_pages[(seg&~7)/PAGE_SIZE]);
+		desc = (void *)desc + ((seg & ~7) % PAGE_SIZE);
+#else
 		desc = current->mm->context.ldt;
 		desc = (void *)desc + (seg & ~7);
+#endif
 	} else {
 		/* Must disable preemption while reading the GDT. */
 		desc = (u32 *)&cpu_gdt_table[get_cpu()];
@@ -118,6 +128,9 @@ static inline unsigned long get_segment_
 		 (desc[1] & 0xff000000);
 
 	if (seg & (1<<2)) { 
+#if 1
+		kunmap((void *)((unsigned long)desc & PAGE_MASK));
+#endif
 		up(&current->mm->context.sem);
 	} else
 		put_cpu();
@@ -243,6 +256,19 @@ asmlinkage void do_page_fault(struct pt_
 	 * (error_code & 4) == 0, and that the fault was not a
 	 * protection error (error_code & 1) == 0.
 	 */
+#ifdef CONFIG_X86_4G
+	/*
+	 * On 4/4 all kernels faults are either bugs, vmalloc or prefetch
+	 */
+	if (unlikely((regs->xcs & 3) == 0)) {
+		if (error_code & 3)
+			goto bad_area_nosemaphore;
+
+		/* If it's vm86 fall through */
+		if (!(regs->eflags & VM_MASK))
+			goto vmalloc_fault;
+	}
+#else
 	if (unlikely(address >= TASK_SIZE)) { 
 		if (!(error_code & 5))
 			goto vmalloc_fault;
@@ -252,6 +278,7 @@ asmlinkage void do_page_fault(struct pt_
 		 */
 		goto bad_area_nosemaphore;
 	} 
+#endif
 
 	mm = tsk->mm;
 
@@ -326,6 +353,8 @@ good_area:
 			goto do_sigbus;
 		case VM_FAULT_OOM:
 			goto out_of_memory;
+		case VM_FAULT_SIGSEGV:
+			goto bad_area;
 		default:
 			BUG();
 	}
@@ -403,6 +432,12 @@ no_context:
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
  */
+#ifdef CONFIG_KGDB
+        if (!user_mode(regs)){
+                kgdb_handle_exception(14,SIGBUS, error_code, regs);
+                return;
+        }
+#endif
 
 	bust_spinlocks(1);
 
--- diff/arch/i386/mm/hugetlbpage.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/i386/mm/hugetlbpage.c	2004-03-09 11:51:48.000000000 +0000
@@ -61,6 +61,27 @@ static struct page *alloc_fresh_huge_pag
 
 static void free_huge_page(struct page *page);
 
+#ifdef CONFIG_NUMA
+
+static inline void huge_inc_rss(struct mm_struct *mm, struct page *page)
+{
+	mm->rss += (HPAGE_SIZE / PAGE_SIZE);
+	mm->pernode_rss[page_nodenum(page)] += (HPAGE_SIZE / PAGE_SIZE);
+}
+
+static inline void huge_dec_rss(struct mm_struct *mm, struct page *page)
+{
+	mm->rss -= (HPAGE_SIZE / PAGE_SIZE);
+	mm->pernode_rss[page_nodenum(page)] -= (HPAGE_SIZE / PAGE_SIZE);
+}
+
+#else /* !CONFIG_NUMA */
+
+#define huge_inc_rss(mm, page)	((mm)->rss += (HPAGE_SIZE / PAGE_SIZE))
+#define huge_dec_rss(mm, page)	((mm)->rss -= (HPAGE_SIZE / PAGE_SIZE))
+
+#endif /* CONFIG_NUMA */
+
 static struct page *alloc_hugetlb_page(void)
 {
 	int i;
@@ -105,7 +126,7 @@ static void set_huge_pte(struct mm_struc
 {
 	pte_t entry;
 
-	mm->rss += (HPAGE_SIZE / PAGE_SIZE);
+	huge_inc_rss(mm, page);
 	if (write_access) {
 		entry =
 		    pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
@@ -145,7 +166,7 @@ int copy_hugetlb_page_range(struct mm_st
 		ptepage = pte_page(entry);
 		get_page(ptepage);
 		set_pte(dst_pte, entry);
-		dst->rss += (HPAGE_SIZE / PAGE_SIZE);
+		huge_inc_rss(dst, ptepage);
 		addr += HPAGE_SIZE;
 	}
 	return 0;
@@ -314,8 +335,8 @@ void unmap_hugepage_range(struct vm_area
 		page = pte_page(*pte);
 		huge_page_release(page);
 		pte_clear(pte);
+		huge_dec_rss(mm, page);
 	}
-	mm->rss -= (end - start) >> PAGE_SHIFT;
 	flush_tlb_range(vma, start, end);
 }
 
--- diff/arch/i386/mm/init.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/i386/mm/init.c	2004-03-09 11:51:48.000000000 +0000
@@ -40,125 +40,13 @@
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
 #include <asm/sections.h>
+#include <asm/desc.h>
 
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 unsigned long highstart_pfn, highend_pfn;
 
 static int do_test_wp_bit(void);
 
-/*
- * Creates a middle page table and puts a pointer to it in the
- * given global directory entry. This only returns the gd entry
- * in non-PAE compilation mode, since the middle layer is folded.
- */
-static pmd_t * __init one_md_table_init(pgd_t *pgd)
-{
-	pmd_t *pmd_table;
-		
-#ifdef CONFIG_X86_PAE
-	pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
-	set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT));
-	if (pmd_table != pmd_offset(pgd, 0)) 
-		BUG();
-#else
-	pmd_table = pmd_offset(pgd, 0);
-#endif
-
-	return pmd_table;
-}
-
-/*
- * Create a page table and place a pointer to it in a middle page
- * directory entry.
- */
-static pte_t * __init one_page_table_init(pmd_t *pmd)
-{
-	if (pmd_none(*pmd)) {
-		pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
-		set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));
-		if (page_table != pte_offset_kernel(pmd, 0))
-			BUG();	
-
-		return page_table;
-	}
-	
-	return pte_offset_kernel(pmd, 0);
-}
-
-/*
- * This function initializes a certain range of kernel virtual memory 
- * with new bootmem page tables, everywhere page tables are missing in
- * the given range.
- */
-
-/*
- * NOTE: The pagetables are allocated contiguous on the physical space 
- * so we can cache the place of the first one and move around without 
- * checking the pgd every time.
- */
-static void __init page_table_range_init (unsigned long start, unsigned long end, pgd_t *pgd_base)
-{
-	pgd_t *pgd;
-	pmd_t *pmd;
-	int pgd_idx, pmd_idx;
-	unsigned long vaddr;
-
-	vaddr = start;
-	pgd_idx = pgd_index(vaddr);
-	pmd_idx = pmd_index(vaddr);
-	pgd = pgd_base + pgd_idx;
-
-	for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) {
-		if (pgd_none(*pgd)) 
-			one_md_table_init(pgd);
-
-		pmd = pmd_offset(pgd, vaddr);
-		for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) {
-			if (pmd_none(*pmd)) 
-				one_page_table_init(pmd);
-
-			vaddr += PMD_SIZE;
-		}
-		pmd_idx = 0;
-	}
-}
-
-/*
- * This maps the physical memory to kernel virtual address space, a total 
- * of max_low_pfn pages, by creating page tables starting from address 
- * PAGE_OFFSET.
- */
-static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
-{
-	unsigned long pfn;
-	pgd_t *pgd;
-	pmd_t *pmd;
-	pte_t *pte;
-	int pgd_idx, pmd_idx, pte_ofs;
-
-	pgd_idx = pgd_index(PAGE_OFFSET);
-	pgd = pgd_base + pgd_idx;
-	pfn = 0;
-
-	for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) {
-		pmd = one_md_table_init(pgd);
-		if (pfn >= max_low_pfn)
-			continue;
-		for (pmd_idx = 0; pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_idx++) {
-			/* Map with big pages if possible, otherwise create normal page tables. */
-			if (cpu_has_pse) {
-				set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE));
-				pfn += PTRS_PER_PTE;
-			} else {
-				pte = one_page_table_init(pmd);
-
-				for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++)
-					set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));
-			}
-		}
-	}	
-}
-
 static inline int page_kills_ppro(unsigned long pagenr)
 {
 	if (pagenr >= 0x70000 && pagenr <= 0x7003F)
@@ -206,11 +94,8 @@ static inline int page_is_ram(unsigned l
 	return 0;
 }
 
-#ifdef CONFIG_HIGHMEM
 pte_t *kmap_pte;
-pgprot_t kmap_prot;
 
-EXPORT_SYMBOL(kmap_prot);
 EXPORT_SYMBOL(kmap_pte);
 
 #define kmap_get_fixmap_pte(vaddr)					\
@@ -218,29 +103,7 @@ EXPORT_SYMBOL(kmap_pte);
 
 void __init kmap_init(void)
 {
-	unsigned long kmap_vstart;
-
-	/* cache the first kmap pte */
-	kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
-	kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
-
-	kmap_prot = PAGE_KERNEL;
-}
-
-void __init permanent_kmaps_init(pgd_t *pgd_base)
-{
-	pgd_t *pgd;
-	pmd_t *pmd;
-	pte_t *pte;
-	unsigned long vaddr;
-
-	vaddr = PKMAP_BASE;
-	page_table_range_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);
-
-	pgd = swapper_pg_dir + pgd_index(vaddr);
-	pmd = pmd_offset(pgd, vaddr);
-	pte = pte_offset_kernel(pmd, vaddr);
-	pkmap_page_table = pte;	
+	kmap_pte = kmap_get_fixmap_pte(__fix_to_virt(FIX_KMAP_BEGIN));
 }
 
 void __init one_highpage_init(struct page *page, int pfn, int bad_ppro)
@@ -255,6 +118,8 @@ void __init one_highpage_init(struct pag
 		SetPageReserved(page);
 }
 
+#ifdef CONFIG_HIGHMEM
+
 #ifndef CONFIG_DISCONTIGMEM
 void __init set_highmem_pages_init(int bad_ppro) 
 {
@@ -266,12 +131,9 @@ void __init set_highmem_pages_init(int b
 #else
 extern void set_highmem_pages_init(int);
 #endif /* !CONFIG_DISCONTIGMEM */
-
 #else
-#define kmap_init() do { } while (0)
-#define permanent_kmaps_init(pgd_base) do { } while (0)
-#define set_highmem_pages_init(bad_ppro) do { } while (0)
-#endif /* CONFIG_HIGHMEM */
+# define set_highmem_pages_init(bad_ppro) do { } while (0)
+#endif
 
 unsigned long __PAGE_KERNEL = _PAGE_KERNEL;
 
@@ -281,30 +143,125 @@ unsigned long __PAGE_KERNEL = _PAGE_KERN
 extern void __init remap_numa_kva(void);
 #endif
 
-static void __init pagetable_init (void)
+static __init void prepare_pagetables(pgd_t *pgd_base, unsigned long address)
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	pgd = pgd_base + pgd_index(address);
+	pmd = pmd_offset(pgd, address);
+	if (!pmd_present(*pmd)) {
+		pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+		set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)));
+	}
+}
+
+static void __init fixrange_init (unsigned long start, unsigned long end, pgd_t *pgd_base)
 {
 	unsigned long vaddr;
-	pgd_t *pgd_base = swapper_pg_dir;
 
+	for (vaddr = start; vaddr != end; vaddr += PAGE_SIZE)
+		prepare_pagetables(pgd_base, vaddr);
+}
+
+void setup_identity_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end)
+{
+	unsigned long vaddr;
+	pgd_t *pgd;
+	int i, j, k;
+	pmd_t *pmd;
+	pte_t *pte, *pte_base;
+
+	pgd = pgd_base;
+
+	for (i = 0; i < PTRS_PER_PGD; pgd++, i++) {
+		vaddr = i*PGDIR_SIZE;
+		if (end && (vaddr >= end))
+			break;
+		pmd = pmd_offset(pgd, 0);
+		for (j = 0; j < PTRS_PER_PMD; pmd++, j++) {
+			vaddr = i*PGDIR_SIZE + j*PMD_SIZE;
+			if (end && (vaddr >= end))
+				break;
+			if (vaddr < start)
+				continue;
+			if (cpu_has_pse) {
+				unsigned long __pe;
+
+				set_in_cr4(X86_CR4_PSE);
+				boot_cpu_data.wp_works_ok = 1;
+				__pe = _KERNPG_TABLE + _PAGE_PSE + vaddr - start;
+				/* Make it "global" too if supported */
+				if (cpu_has_pge) {
+					set_in_cr4(X86_CR4_PGE);
+#if !defined(CONFIG_X86_SWITCH_PAGETABLES)
+					__pe += _PAGE_GLOBAL;
+					__PAGE_KERNEL |= _PAGE_GLOBAL;
+#endif
+				}
+				set_pmd(pmd, __pmd(__pe));
+				continue;
+			}
+			if (!pmd_present(*pmd))
+				pte_base = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+			else
+				pte_base = (pte_t *) page_address(pmd_page(*pmd));
+			pte = pte_base;
+			for (k = 0; k < PTRS_PER_PTE; pte++, k++) {
+				vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE;
+				if (end && (vaddr >= end))
+					break;
+				if (vaddr < start)
+					continue;
+				*pte = mk_pte_phys(vaddr-start, PAGE_KERNEL);
+			}
+			set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte_base)));
+		}
+	}
+}
+
+static void __init pagetable_init (void)
+{
+	unsigned long vaddr, end;
+	pgd_t *pgd_base;
 #ifdef CONFIG_X86_PAE
 	int i;
-	/* Init entries of the first-level page table to the zero page */
-	for (i = 0; i < PTRS_PER_PGD; i++)
-		set_pgd(pgd_base + i, __pgd(__pa(empty_zero_page) | _PAGE_PRESENT));
 #endif
 
-	/* Enable PSE if available */
-	if (cpu_has_pse) {
-		set_in_cr4(X86_CR4_PSE);
-	}
+	/*
+	 * This can be zero as well - no problem, in that case we exit
+	 * the loops anyway due to the PTRS_PER_* conditions.
+	 */
+	end = (unsigned long)__va(max_low_pfn*PAGE_SIZE);
 
-	/* Enable PGE if available */
-	if (cpu_has_pge) {
-		set_in_cr4(X86_CR4_PGE);
-		__PAGE_KERNEL |= _PAGE_GLOBAL;
+	pgd_base = swapper_pg_dir;
+#ifdef CONFIG_X86_PAE
+	/*
+	 * It causes too many problems if there's no proper pmd set up
+	 * for all 4 entries of the PGD - so we allocate all of them.
+	 * PAE systems will not miss this extra 4-8K anyway ...
+	 */
+	for (i = 0; i < PTRS_PER_PGD; i++) {
+		pmd_t *pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+		set_pgd(pgd_base + i, __pgd(__pa(pmd) + 0x1));
 	}
+#endif
+	/*
+	 * Set up lowmem-sized identity mappings at PAGE_OFFSET:
+	 */
+	setup_identity_mappings(pgd_base, PAGE_OFFSET, end);
 
-	kernel_physical_mapping_init(pgd_base);
+	/*
+	 * Add flat-mode identity-mappings - SMP needs it when
+	 * starting up on an AP from real-mode. (In the non-PAE
+	 * case we already have these mappings through head.S.)
+	 * All user-space mappings are explicitly cleared after
+	 * SMP startup.
+	 */
+#if defined(CONFIG_SMP) && defined(CONFIG_X86_PAE)
+	setup_identity_mappings(pgd_base, 0, 16*1024*1024);
+#endif
 	remap_numa_kva();
 
 	/*
@@ -312,38 +269,64 @@ static void __init pagetable_init (void)
 	 * created - mappings will be set by set_fixmap():
 	 */
 	vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
-	page_table_range_init(vaddr, 0, pgd_base);
+	fixrange_init(vaddr, 0, pgd_base);
 
-	permanent_kmaps_init(pgd_base);
+#ifdef CONFIG_HIGHMEM
+	{
+		pgd_t *pgd;
+		pmd_t *pmd;
+		pte_t *pte;
 
-#ifdef CONFIG_X86_PAE
-	/*
-	 * Add low memory identity-mappings - SMP needs it when
-	 * starting up on an AP from real-mode. In the non-PAE
-	 * case we already have these mappings through head.S.
-	 * All user-space mappings are explicitly cleared after
-	 * SMP startup.
-	 */
-	pgd_base[0] = pgd_base[USER_PTRS_PER_PGD];
+		/*
+		 * Permanent kmaps:
+		 */
+		vaddr = PKMAP_BASE;
+		fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);
+
+		pgd = swapper_pg_dir + pgd_index(vaddr);
+		pmd = pmd_offset(pgd, vaddr);
+		pte = pte_offset_kernel(pmd, vaddr);
+		pkmap_page_table = pte;
+	}
 #endif
 }
 
-void zap_low_mappings (void)
+/*
+ * Clear kernel pagetables in a PMD_SIZE-aligned range.
+ */
+static void clear_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end)
 {
-	int i;
+	unsigned long vaddr;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	int i, j;
+
+	pgd = pgd_base;
+
+	for (i = 0; i < PTRS_PER_PGD; pgd++, i++) {
+		vaddr = i*PGDIR_SIZE;
+		if (end && (vaddr >= end))
+			break;
+		pmd = pmd_offset(pgd, 0);
+		for (j = 0; j < PTRS_PER_PMD; pmd++, j++) {
+			vaddr = i*PGDIR_SIZE + j*PMD_SIZE;
+			if (end && (vaddr >= end))
+				break;
+			if (vaddr < start)
+				continue;
+			pmd_clear(pmd);
+		}
+	}
+	flush_tlb_all();
+}
+
+void zap_low_mappings(void)
+{
+	printk("zapping low mappings.\n");
 	/*
 	 * Zap initial low-memory mappings.
-	 *
-	 * Note that "pgd_clear()" doesn't do it for
-	 * us, because pgd_clear() is a no-op on i386.
 	 */
-	for (i = 0; i < USER_PTRS_PER_PGD; i++)
-#ifdef CONFIG_X86_PAE
-		set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page)));
-#else
-		set_pgd(swapper_pg_dir+i, __pgd(0));
-#endif
-	flush_tlb_all();
+	clear_mappings(swapper_pg_dir, 0, 16*1024*1024);
 }
 
 #ifndef CONFIG_DISCONTIGMEM
@@ -393,7 +376,15 @@ void __init paging_init(void)
 		set_in_cr4(X86_CR4_PAE);
 #endif
 	__flush_tlb_all();
-
+	/*
+	 * Subtle. SMP is doing it's boot stuff late (because it has to
+	 * fork idle threads) - but it also needs low mappings for the
+	 * protected-mode entry to work. We zap these entries only after
+	 * the WP-bit has been tested.
+	 */
+#ifndef CONFIG_SMP
+	zap_low_mappings();
+#endif
 	kmap_init();
 	zone_sizes_init();
 }
@@ -515,22 +506,18 @@ void __init mem_init(void)
 	if (boot_cpu_data.wp_works_ok < 0)
 		test_wp_bit();
 
-	/*
-	 * Subtle. SMP is doing it's boot stuff late (because it has to
-	 * fork idle threads) - but it also needs low mappings for the
-	 * protected-mode entry to work. We zap these entries only after
-	 * the WP-bit has been tested.
-	 */
-#ifndef CONFIG_SMP
-	zap_low_mappings();
-#endif
+	entry_trampoline_setup();
+	default_ldt_page = virt_to_page(default_ldt);
+	load_LDT(&init_mm.context);
 }
 
-kmem_cache_t *pgd_cache;
-kmem_cache_t *pmd_cache;
+kmem_cache_t *pgd_cache, *pmd_cache, *kpmd_cache;
 
 void __init pgtable_cache_init(void)
 {
+	void (*ctor)(void *, kmem_cache_t *, unsigned long);
+	void (*dtor)(void *, kmem_cache_t *, unsigned long);
+
 	if (PTRS_PER_PMD > 1) {
 		pmd_cache = kmem_cache_create("pmd",
 					PTRS_PER_PMD*sizeof(pmd_t),
@@ -540,13 +527,36 @@ void __init pgtable_cache_init(void)
 					NULL);
 		if (!pmd_cache)
 			panic("pgtable_cache_init(): cannot create pmd cache");
+
+		if (TASK_SIZE > PAGE_OFFSET) {
+			kpmd_cache = kmem_cache_create("kpmd",
+					PTRS_PER_PMD*sizeof(pmd_t),
+					0,
+					SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN,
+					kpmd_ctor,
+					NULL);
+			if (!kpmd_cache)
+				panic("pgtable_cache_init(): "
+						"cannot create kpmd cache");
+		}
 	}
+
+	if (PTRS_PER_PMD == 1 || TASK_SIZE <= PAGE_OFFSET)
+		ctor = pgd_ctor;
+	else
+		ctor = NULL;
+
+	if (PTRS_PER_PMD == 1 && TASK_SIZE <= PAGE_OFFSET)
+		dtor = pgd_dtor;
+	else
+		dtor = NULL;
+
 	pgd_cache = kmem_cache_create("pgd",
 				PTRS_PER_PGD*sizeof(pgd_t),
 				0,
 				SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN,
-				pgd_ctor,
-				PTRS_PER_PMD == 1 ? pgd_dtor : NULL);
+				ctor,
+				dtor);
 	if (!pgd_cache)
 		panic("pgtable_cache_init(): Cannot create pgd cache");
 }
--- diff/arch/i386/mm/pgtable.c	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/mm/pgtable.c	2004-03-09 11:51:48.000000000 +0000
@@ -21,6 +21,7 @@
 #include <asm/e820.h>
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
+#include <asm/atomic_kmap.h>
 
 void show_mem(void)
 {
@@ -157,11 +158,20 @@ void pmd_ctor(void *pmd, kmem_cache_t *c
 	memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t));
 }
 
+void kpmd_ctor(void *__pmd, kmem_cache_t *cache, unsigned long flags)
+{
+	pmd_t *kpmd, *pmd;
+	kpmd = pmd_offset(&swapper_pg_dir[PTRS_PER_PGD-1],
+				(PTRS_PER_PMD - NR_SHARED_PMDS)*PMD_SIZE);
+	pmd = (pmd_t *)__pmd + (PTRS_PER_PMD - NR_SHARED_PMDS);
+
+	memset(__pmd, 0, (PTRS_PER_PMD - NR_SHARED_PMDS)*sizeof(pmd_t));
+	memcpy(pmd, kpmd, NR_SHARED_PMDS*sizeof(pmd_t));
+}
+
 /*
- * List of all pgd's needed for non-PAE so it can invalidate entries
- * in both cached and uncached pgd's; not needed for PAE since the
- * kernel pmd is shared. If PAE were not to share the pmd a similar
- * tactic would be needed. This is essentially codepath-based locking
+ * List of all pgd's needed so it can invalidate entries in both cached
+ * and uncached pgd's. This is essentially codepath-based locking
  * against pageattr.c; it is the unique case in which a valid change
  * of kernel pagetables can't be lazily synchronized by vmalloc faults.
  * vmalloc faults work because attached pagetables are never freed.
@@ -170,30 +180,60 @@ void pmd_ctor(void *pmd, kmem_cache_t *c
  * could be used. The locking scheme was chosen on the basis of
  * manfred's recommendations and having no core impact whatsoever.
  * -- wli
+ *
+ * The entire issue goes away when XKVA is configured.
  */
 spinlock_t pgd_lock = SPIN_LOCK_UNLOCKED;
 LIST_HEAD(pgd_list);
 
-void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused)
+/*
+ * This is not that hard to figure out.
+ * (a) PTRS_PER_PMD == 1 means non-PAE.
+ * (b) PTRS_PER_PMD > 1 means PAE.
+ * (c) TASK_SIZE > PAGE_OFFSET means XKVA.
+ * (d) TASK_SIZE <= PAGE_OFFSET means non-XKVA.
+ *
+ * Do *NOT* back out the preconstruction like the patch I'm cleaning
+ * up after this very instant did, or at all, for that matter.
+ * This is never called when PTRS_PER_PMD > 1 && TASK_SIZE > PAGE_OFFSET.
+ * -- wli
+ */
+void pgd_ctor(void *__pgd, kmem_cache_t *cache, unsigned long unused)
 {
+	pgd_t *pgd = (pgd_t *)__pgd;
 	unsigned long flags;
 
-	if (PTRS_PER_PMD == 1)
-		spin_lock_irqsave(&pgd_lock, flags);
+	if (PTRS_PER_PMD == 1) {
+		if (TASK_SIZE <= PAGE_OFFSET)
+			spin_lock_irqsave(&pgd_lock, flags);
+		else
+ 			memcpy(&pgd[PTRS_PER_PGD - NR_SHARED_PMDS],
+ 				&swapper_pg_dir[PTRS_PER_PGD - NR_SHARED_PMDS],
+ 				NR_SHARED_PMDS * sizeof(pgd_t));
+	}
 
-	memcpy((pgd_t *)pgd + USER_PTRS_PER_PGD,
-			swapper_pg_dir + USER_PTRS_PER_PGD,
-			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+	if (TASK_SIZE <= PAGE_OFFSET)
+ 		memcpy(pgd + USER_PTRS_PER_PGD,
+ 			swapper_pg_dir + USER_PTRS_PER_PGD,
+ 			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
 
 	if (PTRS_PER_PMD > 1)
 		return;
 
-	list_add(&virt_to_page(pgd)->lru, &pgd_list);
-	spin_unlock_irqrestore(&pgd_lock, flags);
-	memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
+	if (TASK_SIZE > PAGE_OFFSET)
+		memset(pgd, 0, (PTRS_PER_PGD - NR_SHARED_PMDS)*sizeof(pgd_t));
+	else {
+		list_add(&virt_to_page(pgd)->lru, &pgd_list);
+		spin_unlock_irqrestore(&pgd_lock, flags);
+		memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
+	}
 }
 
-/* never called when PTRS_PER_PMD > 1 */
+/*
+ * Never called when PTRS_PER_PMD > 1 || TASK_SIZE > PAGE_OFFSET
+ * for with PAE we would list_del() multiple times, and for non-PAE
+ * with XKVA all the AGP pgd shootdown code is unnecessary.
+ */
 void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused)
 {
 	unsigned long flags; /* can be called from interrupt context */
@@ -203,6 +243,12 @@ void pgd_dtor(void *pgd, kmem_cache_t *c
 	spin_unlock_irqrestore(&pgd_lock, flags);
 }
 
+/*
+ * See the comments above pgd_ctor() wrt. preconstruction.
+ * Do *NOT* memcpy() here. If you do, you back out important
+ * anti- cache pollution code.
+ *
+ */
 pgd_t *pgd_alloc(struct mm_struct *mm)
 {
 	int i;
@@ -211,15 +257,33 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
 	if (PTRS_PER_PMD == 1 || !pgd)
 		return pgd;
 
+	/*
+	 * In the 4G userspace case alias the top 16 MB virtual
+	 * memory range into the user mappings as well (these
+	 * include the trampoline and CPU data structures).
+	 */
 	for (i = 0; i < USER_PTRS_PER_PGD; ++i) {
-		pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL);
+		kmem_cache_t *cache;
+		pmd_t *pmd;
+
+		if (TASK_SIZE > PAGE_OFFSET && i == USER_PTRS_PER_PGD - 1)
+			cache = kpmd_cache;
+		else
+			cache = pmd_cache;
+
+		pmd = kmem_cache_alloc(cache, GFP_KERNEL);
 		if (!pmd)
 			goto out_oom;
 		set_pgd(&pgd[i], __pgd(1 + __pa((u64)((u32)pmd))));
 	}
-	return pgd;
 
+	return pgd;
 out_oom:
+	/*
+	 * we don't have to handle the kpmd_cache here, since it's the
+	 * last allocation, and has either nothing to free or when it
+	 * succeeds the whole operation succeeds.
+	 */
 	for (i--; i >= 0; i--)
 		kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1));
 	kmem_cache_free(pgd_cache, pgd);
@@ -230,10 +294,29 @@ void pgd_free(pgd_t *pgd)
 {
 	int i;
 
-	/* in the PAE case user pgd entries are overwritten before usage */
-	if (PTRS_PER_PMD > 1)
-		for (i = 0; i < USER_PTRS_PER_PGD; ++i)
-			kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1));
 	/* in the non-PAE case, clear_page_tables() clears user pgd entries */
+	if (PTRS_PER_PMD == 1)
+		goto out_free;
+
+	/* in the PAE case user pgd entries are overwritten before usage */
+	for (i = 0; i < USER_PTRS_PER_PGD; ++i) {
+		kmem_cache_t *cache;
+		pmd_t *pmd = __va(pgd_val(pgd[i]) - 1);
+
+		/*
+		 * only userspace pmd's are cleared for us
+		 * by mm/memory.c; it's a slab cache invariant
+		 * that we must separate the kernel pmd slab
+		 * all times, else we'll have bad pmd's.
+		 */
+		if (TASK_SIZE > PAGE_OFFSET && i == USER_PTRS_PER_PGD - 1)
+			cache = kpmd_cache;
+		else
+			cache = pmd_cache;
+
+		kmem_cache_free(cache, pmd);
+	}
+out_free:
 	kmem_cache_free(pgd_cache, pgd);
 }
+
--- diff/arch/i386/oprofile/op_model_p4.c	2003-08-26 10:00:51.000000000 +0100
+++ source/arch/i386/oprofile/op_model_p4.c	2004-03-09 11:51:48.000000000 +0000
@@ -382,11 +382,8 @@ static struct p4_event_binding p4_events
 static unsigned int get_stagger(void)
 {
 #ifdef CONFIG_SMP
-	int cpu;
-	if (smp_num_siblings > 1) {
-		cpu = smp_processor_id();
-		return (cpu_sibling_map[cpu] > cpu) ? 0 : 1;
-	}
+	int cpu = smp_processor_id();
+	return (cpu != first_cpu(cpu_sibling_map[cpu]));
 #endif	
 	return 0;
 }
--- diff/arch/i386/pci/Makefile	2003-07-08 09:55:17.000000000 +0100
+++ source/arch/i386/pci/Makefile	2004-03-09 11:51:48.000000000 +0000
@@ -1,6 +1,7 @@
 obj-y				:= i386.o
 
 obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
+obj-$(CONFIG_PCI_MMCONFIG)	+= mmconfig.o
 obj-$(CONFIG_PCI_DIRECT)	+= direct.o
 
 pci-y				:= fixup.o
--- diff/arch/i386/pci/common.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/i386/pci/common.c	2004-03-09 11:51:48.000000000 +0000
@@ -20,7 +20,8 @@
 extern  void pcibios_sort(void);
 #endif
 
-unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
+unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
+				PCI_PROBE_MMCONF;
 
 int pcibios_last_bus = -1;
 struct pci_bus *pci_root_bus = NULL;
@@ -198,6 +199,12 @@ char * __devinit  pcibios_setup(char *st
 		return NULL;
 	}
 #endif
+#ifdef CONFIG_PCI_MMCONFIG
+	else if (!strcmp(str, "nommconf")) {
+		pci_probe &= ~PCI_PROBE_MMCONF;
+		return NULL;
+	}
+#endif
 	else if (!strcmp(str, "noacpi")) {
 		acpi_noirq_set();
 		return NULL;
--- diff/arch/i386/pci/pci.h	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/i386/pci/pci.h	2004-03-09 11:51:48.000000000 +0000
@@ -15,6 +15,9 @@
 #define PCI_PROBE_BIOS		0x0001
 #define PCI_PROBE_CONF1		0x0002
 #define PCI_PROBE_CONF2		0x0004
+#define PCI_PROBE_MMCONF	0x0008
+#define PCI_PROBE_MASK		0x000f
+
 #define PCI_NO_SORT		0x0100
 #define PCI_BIOS_SORT		0x0200
 #define PCI_NO_CHECKS		0x0400
--- diff/arch/ia64/Kconfig	2004-03-04 11:41:43.000000000 +0000
+++ source/arch/ia64/Kconfig	2004-03-09 11:51:48.000000000 +0000
@@ -616,7 +616,18 @@ config DEBUG_INFO
 	  debugging info resulting in a larger kernel image.
 	  Say Y here only if you plan to use gdb to debug the kernel.
 	  If you don't debug the kernel, you can say N.
-	  
+
+config LOCKMETER
+       bool "Kernel lock metering"
+       depends on SMP
+       help
+         Say Y to enable kernel lock metering, which adds overhead to SMP locks,
+         but allows you to see various statistics using the lockstat command.
+
+config SYSVIPC_COMPAT
+	bool
+	depends on COMPAT && SYSVIPC
+	default y
 endmenu
 
 source "security/Kconfig"
--- diff/arch/ia64/ia32/sys_ia32.c	2004-03-04 11:41:43.000000000 +0000
+++ source/arch/ia64/ia32/sys_ia32.c	2004-03-09 11:51:48.000000000 +0000
@@ -1023,143 +1023,6 @@ sys32_writev (int fd, struct compat_iove
 	return ret;
 }
 
-/*
- * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation..
- *
- * This is really horribly ugly.
- */
-
-struct msgbuf32 { s32 mtype; char mtext[1]; };
-
-struct ipc_perm32 {
-	key_t key;
-	compat_uid_t uid;
-	compat_gid_t gid;
-	compat_uid_t cuid;
-	compat_gid_t cgid;
-	compat_mode_t mode;
-	unsigned short seq;
-};
-
-struct ipc64_perm32 {
-	key_t key;
-	compat_uid32_t uid;
-	compat_gid32_t gid;
-	compat_uid32_t cuid;
-	compat_gid32_t cgid;
-	compat_mode_t mode;
-	unsigned short __pad1;
-	unsigned short seq;
-	unsigned short __pad2;
-	unsigned int unused1;
-	unsigned int unused2;
-};
-
-struct semid_ds32 {
-	struct ipc_perm32 sem_perm;               /* permissions .. see ipc.h */
-	compat_time_t   sem_otime;              /* last semop time */
-	compat_time_t   sem_ctime;              /* last change time */
-	u32 sem_base;              /* ptr to first semaphore in array */
-	u32 sem_pending;          /* pending operations to be processed */
-	u32 sem_pending_last;    /* last pending operation */
-	u32 undo;                  /* undo requests on this array */
-	unsigned short  sem_nsems;              /* no. of semaphores in array */
-};
-
-struct semid64_ds32 {
-	struct ipc64_perm32 sem_perm;
-	compat_time_t   sem_otime;
-	unsigned int __unused1;
-	compat_time_t   sem_ctime;
-	unsigned int __unused2;
-	unsigned int sem_nsems;
-	unsigned int __unused3;
-	unsigned int __unused4;
-};
-
-struct msqid_ds32 {
-	struct ipc_perm32 msg_perm;
-	u32 msg_first;
-	u32 msg_last;
-	compat_time_t   msg_stime;
-	compat_time_t   msg_rtime;
-	compat_time_t   msg_ctime;
-	u32 wwait;
-	u32 rwait;
-	unsigned short msg_cbytes;
-	unsigned short msg_qnum;
-	unsigned short msg_qbytes;
-	compat_ipc_pid_t msg_lspid;
-	compat_ipc_pid_t msg_lrpid;
-};
-
-struct msqid64_ds32 {
-	struct ipc64_perm32 msg_perm;
-	compat_time_t   msg_stime;
-	unsigned int __unused1;
-	compat_time_t   msg_rtime;
-	unsigned int __unused2;
-	compat_time_t   msg_ctime;
-	unsigned int __unused3;
-	unsigned int msg_cbytes;
-	unsigned int msg_qnum;
-	unsigned int msg_qbytes;
-	compat_pid_t msg_lspid;
-	compat_pid_t msg_lrpid;
-	unsigned int __unused4;
-	unsigned int __unused5;
-};
-
-struct shmid_ds32 {
-	struct ipc_perm32 shm_perm;
-	int shm_segsz;
-	compat_time_t   shm_atime;
-	compat_time_t   shm_dtime;
-	compat_time_t   shm_ctime;
-	compat_ipc_pid_t shm_cpid;
-	compat_ipc_pid_t shm_lpid;
-	unsigned short shm_nattch;
-};
-
-struct shmid64_ds32 {
-	struct ipc64_perm32 shm_perm;
-	compat_size_t shm_segsz;
-	compat_time_t   shm_atime;
-	unsigned int __unused1;
-	compat_time_t   shm_dtime;
-	unsigned int __unused2;
-	compat_time_t   shm_ctime;
-	unsigned int __unused3;
-	compat_pid_t shm_cpid;
-	compat_pid_t shm_lpid;
-	unsigned int shm_nattch;
-	unsigned int __unused4;
-	unsigned int __unused5;
-};
-
-struct shminfo64_32 {
-	unsigned int shmmax;
-	unsigned int shmmin;
-	unsigned int shmmni;
-	unsigned int shmseg;
-	unsigned int shmall;
-	unsigned int __unused1;
-	unsigned int __unused2;
-	unsigned int __unused3;
-	unsigned int __unused4;
-};
-
-struct shm_info32 {
-	int used_ids;
-	u32 shm_tot, shm_rss, shm_swp;
-	u32 swap_attempts, swap_successes;
-};
-
-struct ipc_kludge {
-	u32 msgp;
-	s32 msgtyp;
-};
-
 #define SEMOP		 1
 #define SEMGET		 2
 #define SEMCTL		 3
@@ -1173,454 +1036,6 @@ struct ipc_kludge {
 #define SHMGET		23
 #define SHMCTL		24
 
-#define IPCOP_MASK(__x)	(1UL << (__x))
-
-static int
-ipc_parse_version32 (int *cmd)
-{
-	if (*cmd & IPC_64) {
-		*cmd ^= IPC_64;
-		return IPC_64;
-	} else {
-		return IPC_OLD;
-	}
-}
-
-static int
-semctl32 (int first, int second, int third, void *uptr)
-{
-	union semun fourth;
-	u32 pad;
-	int err = 0, err2;
-	struct semid64_ds s;
-	mm_segment_t old_fs;
-	int version = ipc_parse_version32(&third);
-
-	if (!uptr)
-		return -EINVAL;
-	if (get_user(pad, (u32 *)uptr))
-		return -EFAULT;
-	if (third == SETVAL)
-		fourth.val = (int)pad;
-	else
-		fourth.__pad = (void *)A(pad);
-	switch (third) {
-	      default:
-		err = -EINVAL;
-		break;
-
-	      case IPC_INFO:
-	      case IPC_RMID:
-	      case IPC_SET:
-	      case SEM_INFO:
-	      case GETVAL:
-	      case GETPID:
-	      case GETNCNT:
-	      case GETZCNT:
-	      case GETALL:
-	      case SETVAL:
-	      case SETALL:
-		err = sys_semctl(first, second, third, fourth);
-		break;
-
-	      case IPC_STAT:
-	      case SEM_STAT:
-		fourth.__pad = &s;
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		err = sys_semctl(first, second, third, fourth);
-		set_fs(old_fs);
-
-		if (version == IPC_64) {
-			struct semid64_ds32 *usp64 = (struct semid64_ds32 *) A(pad);
-
-			if (!access_ok(VERIFY_WRITE, usp64, sizeof(*usp64))) {
-				err = -EFAULT;
-				break;
-			}
-			err2 = __put_user(s.sem_perm.key, &usp64->sem_perm.key);
-			err2 |= __put_user(s.sem_perm.uid, &usp64->sem_perm.uid);
-			err2 |= __put_user(s.sem_perm.gid, &usp64->sem_perm.gid);
-			err2 |= __put_user(s.sem_perm.cuid, &usp64->sem_perm.cuid);
-			err2 |= __put_user(s.sem_perm.cgid, &usp64->sem_perm.cgid);
-			err2 |= __put_user(s.sem_perm.mode, &usp64->sem_perm.mode);
-			err2 |= __put_user(s.sem_perm.seq, &usp64->sem_perm.seq);
-			err2 |= __put_user(s.sem_otime, &usp64->sem_otime);
-			err2 |= __put_user(s.sem_ctime, &usp64->sem_ctime);
-			err2 |= __put_user(s.sem_nsems, &usp64->sem_nsems);
-		} else {
-			struct semid_ds32 *usp32 = (struct semid_ds32 *) A(pad);
-
-			if (!access_ok(VERIFY_WRITE, usp32, sizeof(*usp32))) {
-				err = -EFAULT;
-				break;
-			}
-			err2 = __put_user(s.sem_perm.key, &usp32->sem_perm.key);
-			err2 |= __put_user(s.sem_perm.uid, &usp32->sem_perm.uid);
-			err2 |= __put_user(s.sem_perm.gid, &usp32->sem_perm.gid);
-			err2 |= __put_user(s.sem_perm.cuid, &usp32->sem_perm.cuid);
-			err2 |= __put_user(s.sem_perm.cgid, &usp32->sem_perm.cgid);
-			err2 |= __put_user(s.sem_perm.mode, &usp32->sem_perm.mode);
-			err2 |= __put_user(s.sem_perm.seq, &usp32->sem_perm.seq);
-			err2 |= __put_user(s.sem_otime, &usp32->sem_otime);
-			err2 |= __put_user(s.sem_ctime, &usp32->sem_ctime);
-			err2 |= __put_user(s.sem_nsems, &usp32->sem_nsems);
-		}
-		if (err2)
-		    err = -EFAULT;
-		break;
-	}
-	return err;
-}
-
-static int
-do_sys32_msgsnd (int first, int second, int third, void *uptr)
-{
-	struct msgbuf *p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
-	struct msgbuf32 *up = (struct msgbuf32 *)uptr;
-	mm_segment_t old_fs;
-	int err;
-
-	if (!p)
-		return -ENOMEM;
-	err = get_user(p->mtype, &up->mtype);
-	err |= copy_from_user(p->mtext, &up->mtext, second);
-	if (err)
-		goto out;
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	err = sys_msgsnd(first, p, second, third);
-	set_fs(old_fs);
-  out:
-	kfree(p);
-	return err;
-}
-
-static int
-do_sys32_msgrcv (int first, int second, int msgtyp, int third, int version, void *uptr)
-{
-	struct msgbuf32 *up;
-	struct msgbuf *p;
-	mm_segment_t old_fs;
-	int err;
-
-	if (!version) {
-		struct ipc_kludge *uipck = (struct ipc_kludge *)uptr;
-		struct ipc_kludge ipck;
-
-		err = -EINVAL;
-		if (!uptr)
-			goto out;
-		err = -EFAULT;
-		if (copy_from_user(&ipck, uipck, sizeof(struct ipc_kludge)))
-			goto out;
-		uptr = (void *)A(ipck.msgp);
-		msgtyp = ipck.msgtyp;
-	}
-	err = -ENOMEM;
-	p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
-	if (!p)
-		goto out;
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	err = sys_msgrcv(first, p, second, msgtyp, third);
-	set_fs(old_fs);
-	if (err < 0)
-		goto free_then_out;
-	up = (struct msgbuf32 *)uptr;
-	if (put_user(p->mtype, &up->mtype) || copy_to_user(&up->mtext, p->mtext, err))
-		err = -EFAULT;
-free_then_out:
-	kfree(p);
-out:
-	return err;
-}
-
-static int
-msgctl32 (int first, int second, void *uptr)
-{
-	int err = -EINVAL, err2;
-	struct msqid64_ds m64;
-	struct msqid_ds32 *up32 = (struct msqid_ds32 *)uptr;
-	struct msqid64_ds32 *up64 = (struct msqid64_ds32 *)uptr;
-	mm_segment_t old_fs;
-	int version = ipc_parse_version32(&second);
-
-	switch (second) {
-	      case IPC_INFO:
-	      case IPC_RMID:
-	      case MSG_INFO:
-		err = sys_msgctl(first, second, (struct msqid_ds *)uptr);
-		break;
-
-	      case IPC_SET:
-		if (version == IPC_64) {
-			err = get_user(m64.msg_perm.uid, &up64->msg_perm.uid);
-			err |= get_user(m64.msg_perm.gid, &up64->msg_perm.gid);
-			err |= get_user(m64.msg_perm.mode, &up64->msg_perm.mode);
-			err |= get_user(m64.msg_qbytes, &up64->msg_qbytes);
-		} else {
-			err = get_user(m64.msg_perm.uid, &up32->msg_perm.uid);
-			err |= get_user(m64.msg_perm.gid, &up32->msg_perm.gid);
-			err |= get_user(m64.msg_perm.mode, &up32->msg_perm.mode);
-			err |= get_user(m64.msg_qbytes, &up32->msg_qbytes);
-		}
-		if (err)
-			break;
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		err = sys_msgctl(first, second, (struct msqid_ds *)&m64);
-		set_fs(old_fs);
-		break;
-
-	      case IPC_STAT:
-	      case MSG_STAT:
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		err = sys_msgctl(first, second, (struct msqid_ds *)&m64);
-		set_fs(old_fs);
-
-		if (version == IPC_64) {
-			if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) {
-				err = -EFAULT;
-				break;
-			}
-			err2 = __put_user(m64.msg_perm.key, &up64->msg_perm.key);
-			err2 |= __put_user(m64.msg_perm.uid, &up64->msg_perm.uid);
-			err2 |= __put_user(m64.msg_perm.gid, &up64->msg_perm.gid);
-			err2 |= __put_user(m64.msg_perm.cuid, &up64->msg_perm.cuid);
-			err2 |= __put_user(m64.msg_perm.cgid, &up64->msg_perm.cgid);
-			err2 |= __put_user(m64.msg_perm.mode, &up64->msg_perm.mode);
-			err2 |= __put_user(m64.msg_perm.seq, &up64->msg_perm.seq);
-			err2 |= __put_user(m64.msg_stime, &up64->msg_stime);
-			err2 |= __put_user(m64.msg_rtime, &up64->msg_rtime);
-			err2 |= __put_user(m64.msg_ctime, &up64->msg_ctime);
-			err2 |= __put_user(m64.msg_cbytes, &up64->msg_cbytes);
-			err2 |= __put_user(m64.msg_qnum, &up64->msg_qnum);
-			err2 |= __put_user(m64.msg_qbytes, &up64->msg_qbytes);
-			err2 |= __put_user(m64.msg_lspid, &up64->msg_lspid);
-			err2 |= __put_user(m64.msg_lrpid, &up64->msg_lrpid);
-			if (err2)
-				err = -EFAULT;
-		} else {
-			if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) {
-				err = -EFAULT;
-				break;
-			}
-			err2 = __put_user(m64.msg_perm.key, &up32->msg_perm.key);
-			err2 |= __put_user(m64.msg_perm.uid, &up32->msg_perm.uid);
-			err2 |= __put_user(m64.msg_perm.gid, &up32->msg_perm.gid);
-			err2 |= __put_user(m64.msg_perm.cuid, &up32->msg_perm.cuid);
-			err2 |= __put_user(m64.msg_perm.cgid, &up32->msg_perm.cgid);
-			err2 |= __put_user(m64.msg_perm.mode, &up32->msg_perm.mode);
-			err2 |= __put_user(m64.msg_perm.seq, &up32->msg_perm.seq);
-			err2 |= __put_user(m64.msg_stime, &up32->msg_stime);
-			err2 |= __put_user(m64.msg_rtime, &up32->msg_rtime);
-			err2 |= __put_user(m64.msg_ctime, &up32->msg_ctime);
-			err2 |= __put_user(m64.msg_cbytes, &up32->msg_cbytes);
-			err2 |= __put_user(m64.msg_qnum, &up32->msg_qnum);
-			err2 |= __put_user(m64.msg_qbytes, &up32->msg_qbytes);
-			err2 |= __put_user(m64.msg_lspid, &up32->msg_lspid);
-			err2 |= __put_user(m64.msg_lrpid, &up32->msg_lrpid);
-			if (err2)
-				err = -EFAULT;
-		}
-		break;
-	}
-	return err;
-}
-
-static int
-shmat32 (int first, int second, int third, int version, void *uptr)
-{
-	unsigned long raddr;
-	u32 *uaddr = (u32 *)A((u32)third);
-	int err;
-
-	if (version == 1)
-		return -EINVAL;	/* iBCS2 emulator entry point: unsupported */
-	err = do_shmat(first, uptr, second, &raddr);
-	if (err)
-		return err;
-	return put_user(raddr, uaddr);
-}
-
-static int
-shmctl32 (int first, int second, void *uptr)
-{
-	int err = -EFAULT, err2;
-
-	struct shmid64_ds s64;
-	struct shmid_ds32 *up32 = (struct shmid_ds32 *)uptr;
-	struct shmid64_ds32 *up64 = (struct shmid64_ds32 *)uptr;
-	mm_segment_t old_fs;
-	struct shm_info32 *uip = (struct shm_info32 *)uptr;
-	struct shm_info si;
-	int version = ipc_parse_version32(&second);
-	struct shminfo64 smi;
-	struct shminfo *usi32 = (struct shminfo *) uptr;
-	struct shminfo64_32 *usi64 = (struct shminfo64_32 *) uptr;
-
-	switch (second) {
-	      case IPC_INFO:
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		err = sys_shmctl(first, second, (struct shmid_ds *)&smi);
-		set_fs(old_fs);
-
-		if (version == IPC_64) {
-			if (!access_ok(VERIFY_WRITE, usi64, sizeof(*usi64))) {
-				err = -EFAULT;
-				break;
-			}
-			err2 = __put_user(smi.shmmax, &usi64->shmmax);
-			err2 |= __put_user(smi.shmmin, &usi64->shmmin);
-			err2 |= __put_user(smi.shmmni, &usi64->shmmni);
-			err2 |= __put_user(smi.shmseg, &usi64->shmseg);
-			err2 |= __put_user(smi.shmall, &usi64->shmall);
-		} else {
-			if (!access_ok(VERIFY_WRITE, usi32, sizeof(*usi32))) {
-				err = -EFAULT;
-				break;
-			}
-			err2 = __put_user(smi.shmmax, &usi32->shmmax);
-			err2 |= __put_user(smi.shmmin, &usi32->shmmin);
-			err2 |= __put_user(smi.shmmni, &usi32->shmmni);
-			err2 |= __put_user(smi.shmseg, &usi32->shmseg);
-			err2 |= __put_user(smi.shmall, &usi32->shmall);
-		}
-		if (err2)
-			err = -EFAULT;
-		break;
-
-	      case IPC_RMID:
-	      case SHM_LOCK:
-	      case SHM_UNLOCK:
-		err = sys_shmctl(first, second, (struct shmid_ds *)uptr);
-		break;
-
-	      case IPC_SET:
-		if (version == IPC_64) {
-			err = get_user(s64.shm_perm.uid, &up64->shm_perm.uid);
-			err |= get_user(s64.shm_perm.gid, &up64->shm_perm.gid);
-			err |= get_user(s64.shm_perm.mode, &up64->shm_perm.mode);
-		} else {
-			err = get_user(s64.shm_perm.uid, &up32->shm_perm.uid);
-			err |= get_user(s64.shm_perm.gid, &up32->shm_perm.gid);
-			err |= get_user(s64.shm_perm.mode, &up32->shm_perm.mode);
-		}
-		if (err)
-			break;
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		err = sys_shmctl(first, second, (struct shmid_ds *)&s64);
-		set_fs(old_fs);
-		break;
-
-	      case IPC_STAT:
-	      case SHM_STAT:
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		err = sys_shmctl(first, second, (struct shmid_ds *)&s64);
-		set_fs(old_fs);
-		if (err < 0)
-			break;
-		if (version == IPC_64) {
-			if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) {
-				err = -EFAULT;
-				break;
-			}
-			err2 = __put_user(s64.shm_perm.key, &up64->shm_perm.key);
-			err2 |= __put_user(s64.shm_perm.uid, &up64->shm_perm.uid);
-			err2 |= __put_user(s64.shm_perm.gid, &up64->shm_perm.gid);
-			err2 |= __put_user(s64.shm_perm.cuid, &up64->shm_perm.cuid);
-			err2 |= __put_user(s64.shm_perm.cgid, &up64->shm_perm.cgid);
-			err2 |= __put_user(s64.shm_perm.mode, &up64->shm_perm.mode);
-			err2 |= __put_user(s64.shm_perm.seq, &up64->shm_perm.seq);
-			err2 |= __put_user(s64.shm_atime, &up64->shm_atime);
-			err2 |= __put_user(s64.shm_dtime, &up64->shm_dtime);
-			err2 |= __put_user(s64.shm_ctime, &up64->shm_ctime);
-			err2 |= __put_user(s64.shm_segsz, &up64->shm_segsz);
-			err2 |= __put_user(s64.shm_nattch, &up64->shm_nattch);
-			err2 |= __put_user(s64.shm_cpid, &up64->shm_cpid);
-			err2 |= __put_user(s64.shm_lpid, &up64->shm_lpid);
-		} else {
-			if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) {
-				err = -EFAULT;
-				break;
-			}
-			err2 = __put_user(s64.shm_perm.key, &up32->shm_perm.key);
-			err2 |= __put_user(s64.shm_perm.uid, &up32->shm_perm.uid);
-			err2 |= __put_user(s64.shm_perm.gid, &up32->shm_perm.gid);
-			err2 |= __put_user(s64.shm_perm.cuid, &up32->shm_perm.cuid);
-			err2 |= __put_user(s64.shm_perm.cgid, &up32->shm_perm.cgid);
-			err2 |= __put_user(s64.shm_perm.mode, &up32->shm_perm.mode);
-			err2 |= __put_user(s64.shm_perm.seq, &up32->shm_perm.seq);
-			err2 |= __put_user(s64.shm_atime, &up32->shm_atime);
-			err2 |= __put_user(s64.shm_dtime, &up32->shm_dtime);
-			err2 |= __put_user(s64.shm_ctime, &up32->shm_ctime);
-			err2 |= __put_user(s64.shm_segsz, &up32->shm_segsz);
-			err2 |= __put_user(s64.shm_nattch, &up32->shm_nattch);
-			err2 |= __put_user(s64.shm_cpid, &up32->shm_cpid);
-			err2 |= __put_user(s64.shm_lpid, &up32->shm_lpid);
-		}
-		if (err2)
-			err = -EFAULT;
-		break;
-
-	      case SHM_INFO:
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		err = sys_shmctl(first, second, (void *)&si);
-		set_fs(old_fs);
-		if (err < 0)
-			break;
-
-		if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip))) {
-			err = -EFAULT;
-			break;
-		}
-		err2 = __put_user(si.used_ids, &uip->used_ids);
-		err2 |= __put_user(si.shm_tot, &uip->shm_tot);
-		err2 |= __put_user(si.shm_rss, &uip->shm_rss);
-		err2 |= __put_user(si.shm_swp, &uip->shm_swp);
-		err2 |= __put_user(si.swap_attempts, &uip->swap_attempts);
-		err2 |= __put_user(si.swap_successes, &uip->swap_successes);
-		if (err2)
-			err = -EFAULT;
-		break;
-
-	}
-	return err;
-}
-
-extern int sem_ctls[];
-#define sc_semopm	(sem_ctls[2])
-
-static long
-semtimedop32(int semid, struct sembuf *tsops, int nsops,
-	     struct compat_timespec *timeout32)
-{
-	struct timespec t;
-	mm_segment_t oldfs;
-	long ret;
-
-	/* parameter checking precedence should mirror sys_semtimedop() */
-	if (nsops < 1 || semid < 0)
-		return -EINVAL;
-	if (nsops > sc_semopm)
-		return -E2BIG;
-	if (!access_ok(VERIFY_READ, tsops, nsops * sizeof(struct sembuf)) ||
-	    get_compat_timespec(&t, timeout32))
-		return -EFAULT;
-
-	oldfs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_semtimedop(semid, tsops, nsops, &t);
-	set_fs(oldfs);
-	return ret;
-}
-
 asmlinkage long
 sys32_ipc(u32 call, int first, int second, int third, u32 ptr, u32 fifth)
 {
@@ -1632,36 +1047,36 @@ sys32_ipc(u32 call, int first, int secon
 	switch (call) {
 	      case SEMTIMEDOP:
 		if (fifth)
-			return semtimedop32(first, (struct sembuf *)AA(ptr),
-				second, (struct compat_timespec *)AA(fifth));
+			return compat_sys_semtimedop(first, compat_ptr(ptr),
+				second, compat_ptr(fifth));
 		/* else fall through for normal semop() */
 	      case SEMOP:
 		/* struct sembuf is the same on 32 and 64bit :)) */
-		return sys_semtimedop(first, (struct sembuf *)AA(ptr), second,
+		return sys_semtimedop(first, compat_ptr(ptr), second,
 				      NULL);
 	      case SEMGET:
 		return sys_semget(first, second, third);
 	      case SEMCTL:
-		return semctl32(first, second, third, (void *)AA(ptr));
+		return compat_sys_semctl(first, second, third, compat_ptr(ptr));
 
 	      case MSGSND:
-		return do_sys32_msgsnd(first, second, third, (void *)AA(ptr));
+		return compat_sys_msgsnd(first, second, third, compat_ptr(ptr));
 	      case MSGRCV:
-		return do_sys32_msgrcv(first, second, fifth, third, version, (void *)AA(ptr));
+		return compat_sys_msgrcv(first, second, fifth, third, version, compat_ptr(ptr));
 	      case MSGGET:
 		return sys_msgget((key_t) first, second);
 	      case MSGCTL:
-		return msgctl32(first, second, (void *)AA(ptr));
+		return compat_sys_msgctl(first, second, compat_ptr(ptr));
 
 	      case SHMAT:
-		return shmat32(first, second, third, version, (void *)AA(ptr));
+		return compat_sys_shmat(first, second, third, version, compat_ptr(ptr));
 		break;
 	      case SHMDT:
-		return sys_shmdt((char *)AA(ptr));
+		return sys_shmdt(compat_ptr(ptr));
 	      case SHMGET:
 		return sys_shmget(first, second, third);
 	      case SHMCTL:
-		return shmctl32(first, second, (void *)AA(ptr));
+		return compat_sys_shmctl(first, second, compat_ptr(ptr));
 
 	      default:
 		return -ENOSYS;
--- diff/arch/ia64/lib/dec_and_lock.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/ia64/lib/dec_and_lock.c	2004-03-09 11:51:48.000000000 +0000
@@ -13,6 +13,7 @@
 #include <linux/spinlock.h>
 #include <asm/atomic.h>
 
+#ifndef CONFIG_LOCKMETER
 /*
  * Decrement REFCOUNT and if the count reaches zero, acquire the spinlock.  Both of these
  * operations have to be done atomically, so that the count doesn't drop to zero without
@@ -40,3 +41,4 @@ atomic_dec_and_lock (atomic_t *refcount,
 }
 
 EXPORT_SYMBOL(atomic_dec_and_lock);
+#endif
--- diff/arch/ia64/lib/swiotlb.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/ia64/lib/swiotlb.c	2004-03-09 11:51:48.000000000 +0000
@@ -47,7 +47,7 @@
 #define IO_TLB_SHIFT 11
 
 /*
- * Used to do a quick range check in swiotlb_unmap_single and swiotlb_sync_single, to see
+ * Used to do a quick range check in swiotlb_unmap_single and swiotlb_sync_single_*, to see
  * if the memory was in fact allocated by this API.
  */
 static char *io_tlb_start, *io_tlb_end;
@@ -381,11 +381,24 @@ swiotlb_unmap_single (struct device *hwd
  *
  * If you perform a swiotlb_map_single() but wish to interrogate the buffer using the cpu,
  * yet do not wish to teardown the PCI dma mapping, you must call this function before
- * doing so.  At the next point you give the PCI dma address back to the card, the device
- * again owns the buffer.
+ * doing so.  At the next point you give the PCI dma address back to the card, you must
+ * first perform a swiotlb_dma_sync_for_device, and then the device again owns the buffer
  */
 void
-swiotlb_sync_single (struct device *hwdev, dma_addr_t dev_addr, size_t size, int dir)
+swiotlb_sync_single_for_cpu (struct device *hwdev, dma_addr_t dev_addr, size_t size, int dir)
+{
+	char *dma_addr = phys_to_virt(dev_addr);
+
+	if (dir == DMA_NONE)
+		BUG();
+	if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
+		sync_single(hwdev, dma_addr, size, dir);
+	else if (dir == DMA_FROM_DEVICE)
+		mark_clean(dma_addr, size);
+}
+
+void
+swiotlb_sync_single_for_device (struct device *hwdev, dma_addr_t dev_addr, size_t size, int dir)
 {
 	char *dma_addr = phys_to_virt(dev_addr);
 
@@ -456,11 +469,24 @@ swiotlb_unmap_sg (struct device *hwdev, 
  * Make physical memory consistent for a set of streaming mode DMA translations after a
  * transfer.
  *
- * The same as swiotlb_dma_sync_single but for a scatter-gather list, same rules and
+ * The same as swiotlb_sync_single_* but for a scatter-gather list, same rules and
  * usage.
  */
 void
-swiotlb_sync_sg (struct device *hwdev, struct scatterlist *sg, int nelems, int dir)
+swiotlb_sync_sg_for_cpu (struct device *hwdev, struct scatterlist *sg, int nelems, int dir)
+{
+	int i;
+
+	if (dir == DMA_NONE)
+		BUG();
+
+	for (i = 0; i < nelems; i++, sg++)
+		if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
+			sync_single(hwdev, (void *) sg->dma_address, sg->dma_length, dir);
+}
+
+void
+swiotlb_sync_sg_for_device (struct device *hwdev, struct scatterlist *sg, int nelems, int dir)
 {
 	int i;
 
@@ -488,8 +514,10 @@ EXPORT_SYMBOL(swiotlb_map_single);
 EXPORT_SYMBOL(swiotlb_unmap_single);
 EXPORT_SYMBOL(swiotlb_map_sg);
 EXPORT_SYMBOL(swiotlb_unmap_sg);
-EXPORT_SYMBOL(swiotlb_sync_single);
-EXPORT_SYMBOL(swiotlb_sync_sg);
+EXPORT_SYMBOL(swiotlb_sync_single_for_cpu);
+EXPORT_SYMBOL(swiotlb_sync_single_for_device);
+EXPORT_SYMBOL(swiotlb_sync_sg_for_cpu);
+EXPORT_SYMBOL(swiotlb_sync_sg_for_device);
 EXPORT_SYMBOL(swiotlb_alloc_coherent);
 EXPORT_SYMBOL(swiotlb_free_coherent);
 EXPORT_SYMBOL(swiotlb_dma_supported);
--- diff/arch/ia64/sn/io/machvec/pci_dma.c	2004-03-04 11:41:43.000000000 +0000
+++ source/arch/ia64/sn/io/machvec/pci_dma.c	2004-03-09 11:51:48.000000000 +0000
@@ -152,7 +152,7 @@ sn_pci_alloc_consistent(struct pci_dev *
 	 *   pcibr_dmatrans_addr ignores a missing PCIIO_DMA_A64 flag on
 	 *   PCI-X buses.
 	 */
-	if (hwdev->consistent_dma_mask == ~0UL)
+	if (hwdev->dev.coherent_dma_mask == ~0UL)
 		*dma_handle = pcibr_dmatrans_addr(vhdl, NULL, phys_addr, size,
 					  PCIIO_DMA_CMD | PCIIO_DMA_A64);
 	else {
@@ -169,7 +169,7 @@ sn_pci_alloc_consistent(struct pci_dev *
 		}
 	}
 
-	if (!*dma_handle || *dma_handle > hwdev->consistent_dma_mask) {
+	if (!*dma_handle || *dma_handle > hwdev->dev.coherent_dma_mask) {
 		if (dma_map) {
 			pcibr_dmamap_done(dma_map);
 			pcibr_dmamap_free(dma_map);
@@ -437,7 +437,8 @@ sn_pci_unmap_single(struct pci_dev *hwde
 }
 
 /**
- * sn_pci_dma_sync_single - make sure all DMAs have completed
+ * sn_pci_dma_sync_single_* - make sure all DMAs or CPU accesses
+ * have completed
  * @hwdev: device to sync
  * @dma_handle: DMA address to sync
  * @size: size of region
@@ -448,14 +449,19 @@ sn_pci_unmap_single(struct pci_dev *hwde
  * anything on our platform.
  */
 void
-sn_pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
+sn_pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
 {
 	return;
+}
 
+void
+sn_pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
+{
+	return;
 }
 
 /**
- * sn_pci_dma_sync_sg - make sure all DMAs have completed
+ * sn_pci_dma_sync_sg_* - make sure all DMAs or CPU accesses have completed
  * @hwdev: device to sync
  * @sg: scatterlist to sync
  * @nents: number of entries in the scatterlist
@@ -466,10 +472,15 @@ sn_pci_dma_sync_single(struct pci_dev *h
  * on our platform.
  */
 void
-sn_pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
+sn_pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
 {
 	return;
+}
 
+void
+sn_pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
+{
+	return;
 }
 
 /**
@@ -602,28 +613,51 @@ sn_dma_unmap_sg(struct device *dev, stru
 EXPORT_SYMBOL(sn_dma_unmap_sg);
 
 void
-sn_dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size,
+sn_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
+			   int direction)
+{
+	BUG_ON(dev->bus != &pci_bus_type);
+
+	sn_pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle, size, (int)direction);
+}
+EXPORT_SYMBOL(sn_dma_sync_single_for_cpu);
+
+void
+sn_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
 		int direction)
 {
 	BUG_ON(dev->bus != &pci_bus_type);
 
-	sn_pci_dma_sync_single(to_pci_dev(dev), dma_handle, size, (int)direction);
+	sn_pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle, size, (int)direction);
+}
+EXPORT_SYMBOL(sn_dma_sync_single_for_device);
+
+void
+sn_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
+	    int direction)
+{
+	BUG_ON(dev->bus != &pci_bus_type);
+
+	sn_pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, nelems, (int)direction);
 }
-EXPORT_SYMBOL(sn_dma_sync_single);
+EXPORT_SYMBOL(sn_dma_sync_sg_for_cpu);
 
 void
-sn_dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems,
+sn_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
 	    int direction)
 {
 	BUG_ON(dev->bus != &pci_bus_type);
 
-	sn_pci_dma_sync_sg(to_pci_dev(dev), sg, nelems, (int)direction);
+	sn_pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, nelems, (int)direction);
 }
-EXPORT_SYMBOL(sn_dma_sync_sg);
+EXPORT_SYMBOL(sn_dma_sync_sg_for_device);
 
 EXPORT_SYMBOL(sn_pci_unmap_single);
 EXPORT_SYMBOL(sn_pci_map_single);
-EXPORT_SYMBOL(sn_pci_dma_sync_single);
+EXPORT_SYMBOL(sn_pci_dma_sync_single_for_cpu);
+EXPORT_SYMBOL(sn_pci_dma_sync_single_for_device);
+EXPORT_SYMBOL(sn_pci_dma_sync_sg_for_cpu);
+EXPORT_SYMBOL(sn_pci_dma_sync_sg_for_device);
 EXPORT_SYMBOL(sn_pci_map_sg);
 EXPORT_SYMBOL(sn_pci_unmap_sg);
 EXPORT_SYMBOL(sn_pci_alloc_consistent);
--- diff/arch/m68k/amiga/amiints.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/m68k/amiga/amiints.c	2004-03-09 11:51:48.000000000 +0000
@@ -197,7 +197,7 @@ int amiga_request_irq(unsigned int irq,
 	}
 
 	if (irq >= IRQ_AMIGA_AUTO)
-		return sys_request_irq(irq - IRQ_AMIGA_AUTO, handler,
+		return cpu_request_irq(irq - IRQ_AMIGA_AUTO, handler,
 		                       flags, devname, dev_id);
 
 	if (irq >= IRQ_AMIGA_CIAB)
@@ -244,7 +244,7 @@ void amiga_free_irq(unsigned int irq, vo
 	}
 
 	if (irq >= IRQ_AMIGA_AUTO)
-		sys_free_irq(irq - IRQ_AMIGA_AUTO, dev_id);
+		cpu_free_irq(irq - IRQ_AMIGA_AUTO, dev_id);
 
 	if (irq >= IRQ_AMIGA_CIAB) {
 		cia_free_irq(&ciab_base, irq - IRQ_AMIGA_CIAB, dev_id);
--- diff/arch/m68k/bvme6000/bvmeints.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/m68k/bvme6000/bvmeints.c	2004-03-09 11:51:48.000000000 +0000
@@ -73,7 +73,7 @@ int bvme6000_request_irq(unsigned int ir
 	 */
 
 	if (irq >= VEC_INT1 && irq <= VEC_INT7)
-		return sys_request_irq(irq - VEC_SPUR, handler, flags,
+		return cpu_request_irq(irq - VEC_SPUR, handler, flags,
 						devname, dev_id);
 #endif
 	if (!(irq_tab[irq].flags & IRQ_FLG_STD)) {
@@ -103,7 +103,7 @@ void bvme6000_free_irq(unsigned int irq,
 	}
 #if 0
 	if (irq >= VEC_INT1 && irq <= VEC_INT7) {
-		sys_free_irq(irq - VEC_SPUR, dev_id);
+		cpu_free_irq(irq - VEC_SPUR, dev_id);
 		return;
 	}
 #endif
--- diff/arch/m68k/hp300/time.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/m68k/hp300/time.c	2004-03-09 11:51:48.000000000 +0000
@@ -68,7 +68,7 @@ void __init hp300_sched_init(irqreturn_t
 
   asm volatile(" movpw %0,%1@(5)" : : "d" (INTVAL), "a" (CLOCKBASE));
 
-  sys_request_irq(6, hp300_tick, IRQ_FLG_STD, "timer tick", vector);
+  cpu_request_irq(6, hp300_tick, IRQ_FLG_STD, "timer tick", vector);
 
   out_8(CLOCKBASE + CLKCR2, 0x1);		/* select CR1 */
   out_8(CLOCKBASE + CLKCR1, 0x40);		/* enable irq */
--- diff/arch/m68k/kernel/entry.S	2004-03-04 11:41:43.000000000 +0000
+++ source/arch/m68k/kernel/entry.S	2004-03-09 11:51:48.000000000 +0000
@@ -528,7 +528,7 @@ sys_call_table:
 	.long sys_ni_syscall				/* old profil syscall holder */
 	.long sys_statfs
 	.long sys_fstatfs	/* 100 */
-	.long sys_ioperm
+	.long sys_ni_syscall				/* ioperm for i386 */
 	.long sys_socketcall
 	.long sys_syslog
 	.long sys_setitimer
--- diff/arch/m68k/kernel/ints.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/m68k/kernel/ints.c	2004-03-09 11:51:48.000000000 +0000
@@ -137,8 +137,8 @@ void free_irq(unsigned int irq, void *de
 
 EXPORT_SYMBOL(free_irq);
 
-int sys_request_irq(unsigned int irq, 
-                    irqreturn_t (*handler)(int, void *, struct pt_regs *), 
+int cpu_request_irq(unsigned int irq,
+                    irqreturn_t (*handler)(int, void *, struct pt_regs *),
                     unsigned long flags, const char *devname, void *dev_id)
 {
 	if (irq < IRQ1 || irq > IRQ7) {
@@ -169,7 +169,7 @@ int sys_request_irq(unsigned int irq, 
 	return 0;
 }
 
-void sys_free_irq(unsigned int irq, void *dev_id)
+void cpu_free_irq(unsigned int irq, void *dev_id)
 {
 	if (irq < IRQ1 || irq > IRQ7) {
 		printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
--- diff/arch/m68k/kernel/sys_m68k.c	2004-03-04 11:41:43.000000000 +0000
+++ source/arch/m68k/kernel/sys_m68k.c	2004-03-09 11:51:48.000000000 +0000
@@ -261,12 +261,6 @@ asmlinkage int sys_ipc (uint call, int f
 	return -EINVAL;
 }
 
-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on)
-{
-  return -ENOSYS;
-}
-
-
 /* Convert virtual (user) address VADDR to physical address PADDR */
 #define virt_to_phys_040(vaddr)						\
 ({									\
--- diff/arch/m68k/mac/iop.c	2004-03-04 11:41:43.000000000 +0000
+++ source/arch/m68k/mac/iop.c	2004-03-09 11:51:48.000000000 +0000
@@ -317,7 +317,7 @@ void __init iop_register_interrupts(void
 {
 	if (iop_ism_present) {
 		if (oss_present) {
-			sys_request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq,
+			cpu_request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq,
 					IRQ_FLG_LOCK, "ISM IOP",
 					(void *) IOP_NUM_ISM);
 			oss_irq_enable(IRQ_MAC_ADB);
--- diff/arch/m68k/mac/macints.c	2004-03-04 11:41:43.000000000 +0000
+++ source/arch/m68k/mac/macints.c	2004-03-09 11:51:48.000000000 +0000
@@ -261,7 +261,8 @@ void mac_init_IRQ(void)
 	if (psc_present) psc_register_interrupts();
 	if (baboon_present) baboon_register_interrupts();
 	iop_register_interrupts();
-	sys_request_irq(7, mac_nmi_handler, IRQ_FLG_LOCK, "NMI", mac_nmi_handler);
+	cpu_request_irq(7, mac_nmi_handler, IRQ_FLG_LOCK, "NMI",
+			mac_nmi_handler);
 #ifdef DEBUG_MACINTS
 	printk("mac_init_IRQ(): Done!\n");
 #endif
@@ -507,7 +508,7 @@ int mac_request_irq(unsigned int irq,
 #endif
 
 	if (irq < VIA1_SOURCE_BASE) {
-		return sys_request_irq(irq, handler, flags, devname, dev_id);
+		return cpu_request_irq(irq, handler, flags, devname, dev_id);
 	}
 
 	if (irq >= NUM_MAC_SOURCES) {
@@ -544,7 +545,7 @@ void mac_free_irq(unsigned int irq, void
 #endif
 
 	if (irq < VIA1_SOURCE_BASE) {
-		return sys_free_irq(irq, dev_id);
+		return cpu_free_irq(irq, dev_id);
 	}
 
 	if (irq >= NUM_MAC_SOURCES) {
--- diff/arch/m68k/mac/oss.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/m68k/mac/oss.c	2004-03-09 11:51:48.000000000 +0000
@@ -67,15 +67,15 @@ void __init oss_init(void)
 
 void __init oss_register_interrupts(void)
 {
-	sys_request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK,
+	cpu_request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK,
 			"scsi", (void *) oss);
-	sys_request_irq(OSS_IRQLEV_IOPSCC, mac_scc_dispatch, IRQ_FLG_LOCK,
+	cpu_request_irq(OSS_IRQLEV_IOPSCC, mac_scc_dispatch, IRQ_FLG_LOCK,
 			"scc", mac_scc_dispatch);
-	sys_request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK,
+	cpu_request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK,
 			"nubus", (void *) oss);
-	sys_request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK,
+	cpu_request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK,
 			"sound", (void *) oss);
-	sys_request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK,
+	cpu_request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK,
 			"via1", (void *) via1);
 }
 
--- diff/arch/m68k/mac/psc.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/m68k/mac/psc.c	2004-03-09 11:51:48.000000000 +0000
@@ -117,14 +117,10 @@ void __init psc_init(void)
 
 void __init psc_register_interrupts(void)
 {
-	sys_request_irq(3, psc_irq, IRQ_FLG_LOCK, "psc3",
-			(void *) 0x30);
-	sys_request_irq(4, psc_irq, IRQ_FLG_LOCK, "psc4",
-			(void *) 0x40);
-	sys_request_irq(5, psc_irq, IRQ_FLG_LOCK, "psc5",
-			(void *) 0x50);
-	sys_request_irq(6, psc_irq, IRQ_FLG_LOCK, "psc6",
-			(void *) 0x60);
+	cpu_request_irq(3, psc_irq, IRQ_FLG_LOCK, "psc3", (void *) 0x30);
+	cpu_request_irq(4, psc_irq, IRQ_FLG_LOCK, "psc4", (void *) 0x40);
+	cpu_request_irq(5, psc_irq, IRQ_FLG_LOCK, "psc5", (void *) 0x50);
+	cpu_request_irq(6, psc_irq, IRQ_FLG_LOCK, "psc6", (void *) 0x60);
 }
 
 /*
--- diff/arch/m68k/mac/via.c	2004-03-04 11:41:43.000000000 +0000
+++ source/arch/m68k/mac/via.c	2004-03-09 11:51:48.000000000 +0000
@@ -260,24 +260,27 @@ void __init via_init_clock(irqreturn_t (
 void __init via_register_interrupts(void)
 {
 	if (via_alt_mapping) {
-		sys_request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
-				"software", (void *) via1);
-		sys_request_irq(IRQ_AUTO_6, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
-				"via1", (void *) via1);
+		cpu_request_irq(IRQ_AUTO_1, via1_irq,
+				IRQ_FLG_LOCK|IRQ_FLG_FAST, "software",
+				(void *) via1);
+		cpu_request_irq(IRQ_AUTO_6, via1_irq,
+				IRQ_FLG_LOCK|IRQ_FLG_FAST, "via1",
+				(void *) via1);
 	} else {
-		sys_request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
-				"via1", (void *) via1);
+		cpu_request_irq(IRQ_AUTO_1, via1_irq,
+				IRQ_FLG_LOCK|IRQ_FLG_FAST, "via1",
+				(void *) via1);
 #if 0 /* interferes with serial on some machines */
 		if (!psc_present) {
-			sys_request_irq(IRQ_AUTO_6, mac_bang, IRQ_FLG_LOCK,
+			cpu_request_irq(IRQ_AUTO_6, mac_bang, IRQ_FLG_LOCK,
 					"Off Switch", mac_bang);
 		}
 #endif
 	}
-	sys_request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+	cpu_request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
 			"via2", (void *) via2);
 	if (!psc_present) {
-		sys_request_irq(IRQ_AUTO_4, mac_scc_dispatch, IRQ_FLG_LOCK,
+		cpu_request_irq(IRQ_AUTO_4, mac_scc_dispatch, IRQ_FLG_LOCK,
 				"scc", mac_scc_dispatch);
 	}
 	request_irq(IRQ_MAC_NUBUS, via_nubus_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
--- diff/arch/m68k/q40/config.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/m68k/q40/config.c	2004-03-09 11:51:48.000000000 +0000
@@ -40,7 +40,7 @@
 extern void floppy_setup(char *str, int *ints);
 
 extern irqreturn_t q40_process_int (int level, struct pt_regs *regs);
-extern irqreturn_t (*q40_sys_default_handler[]) (int, void *, struct pt_regs *);  /* added just for debugging */
+extern irqreturn_t (*q40_default_handler[]) (int, void *, struct pt_regs *);  /* added just for debugging */
 extern void q40_init_IRQ (void);
 extern void q40_free_irq (unsigned int, void *);
 extern int  show_q40_interrupts (struct seq_file *, void *);
@@ -185,7 +185,7 @@ void __init config_q40(void)
     mach_request_irq	 = q40_request_irq;
     enable_irq		 = q40_enable_irq;
     disable_irq          = q40_disable_irq;
-    mach_default_handler = &q40_sys_default_handler;
+    mach_default_handler = &q40_default_handler;
     mach_get_model       = q40_get_model;
     mach_get_hardware_list = q40_get_hardware_list;
 
--- diff/arch/m68k/q40/q40ints.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/m68k/q40/q40ints.c	2004-03-09 11:51:48.000000000 +0000
@@ -46,10 +46,8 @@ extern int ints_inited;
 irqreturn_t q40_irq2_handler (int, void *, struct pt_regs *fp);
 
 
-extern irqreturn_t (*q40_sys_default_handler[]) (int, void *, struct pt_regs *);
-
 static irqreturn_t q40_defhand (int irq, void *dev_id, struct pt_regs *fp);
-static irqreturn_t sys_default_handler(int lev, void *dev_id, struct pt_regs *regs);
+static irqreturn_t default_handler(int lev, void *dev_id, struct pt_regs *regs);
 
 
 #define DEVNAME_SIZE 24
@@ -96,7 +94,8 @@ void q40_init_IRQ (void)
 	}
 
 	/* setup handler for ISA ints */
-	sys_request_irq(IRQ2,q40_irq2_handler, 0, "q40 ISA and master chip", NULL);
+	cpu_request_irq(IRQ2, q40_irq2_handler, 0, "q40 ISA and master chip",
+			NULL);
 
 	/* now enable some ints.. */
 	master_outb(1,EXT_ENABLE_REG);  /* ISA IRQ 5-15 */
@@ -153,8 +152,8 @@ int q40_request_irq(unsigned int irq,
 	  }
 	else {
 	  /* Q40_IRQ_SAMPLE :somewhat special actions required here ..*/
-	  sys_request_irq(4,handler,flags,devname,dev_id);
-	  sys_request_irq(6,handler,flags,devname,dev_id);
+	  cpu_request_irq(4, handler, flags, devname, dev_id);
+	  cpu_request_irq(6, handler, flags, devname, dev_id);
 	  return 0;
 	}
 }
@@ -192,8 +191,8 @@ void q40_free_irq(unsigned int irq, void
 	  }
 	else
 	  { /* == Q40_IRQ_SAMPLE */
-	    sys_free_irq(4,dev_id);
-	    sys_free_irq(6,dev_id);
+	    cpu_free_irq(4, dev_id);
+	    cpu_free_irq(6, dev_id);
 	  }
 }
 
@@ -417,16 +416,16 @@ static irqreturn_t q40_defhand (int irq,
 	else master_outb(-1,KEYBOARD_UNLOCK_REG);
 	return IRQ_NONE;
 }
-static irqreturn_t sys_default_handler(int lev, void *dev_id, struct pt_regs *regs)
+static irqreturn_t default_handler(int lev, void *dev_id, struct pt_regs *regs)
 {
 	printk ("Uninitialised interrupt level %d\n", lev);
 	return IRQ_NONE;
 }
 
- irqreturn_t (*q40_sys_default_handler[SYS_IRQS]) (int, void *, struct pt_regs *) = {
-	 sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler,
-	 sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler
- };
+irqreturn_t (*q40_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
+	 default_handler, default_handler, default_handler, default_handler,
+	 default_handler, default_handler, default_handler, default_handler
+};
 
 
 void q40_enable_irq (unsigned int irq)
--- diff/arch/m68k/sun3/sun3ints.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/m68k/sun3/sun3ints.c	2004-03-09 11:51:48.000000000 +0000
@@ -153,8 +153,8 @@ void sun3_init_IRQ(void)
 	for(i = 0; i < SYS_IRQS; i++)
 	{
 		if(dev_names[i])
-			sys_request_irq(i, sun3_default_handler[i],
-					0, dev_names[i], NULL);
+			cpu_request_irq(i, sun3_default_handler[i], 0,
+					dev_names[i], NULL);
 	}
 
 	for(i = 0; i < 192; i++) 
@@ -178,7 +178,8 @@ int sun3_request_irq(unsigned int irq, i
 		dev_names[irq] = devname;
 		
 		/* setting devname would be nice */
-		sys_request_irq(irq, sun3_default_handler[irq], 0, devname, NULL);
+		cpu_request_irq(irq, sun3_default_handler[irq], 0, devname,
+				NULL);
 
 		return 0;
 	} else {
--- diff/arch/m68knommu/kernel/sys_m68k.c	2004-03-04 11:41:43.000000000 +0000
+++ source/arch/m68knommu/kernel/sys_m68k.c	2004-03-09 11:51:48.000000000 +0000
@@ -193,12 +193,6 @@ asmlinkage int sys_ipc (uint call, int f
 	return -EINVAL;
 }
 
-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on)
-{
-  return -ENOSYS;
-}
-
-
 /* sys_cacheflush -- flush (part of) the processor cache.  */
 asmlinkage int
 sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
--- diff/arch/m68knommu/kernel/syscalltable.S	2003-05-21 11:49:45.000000000 +0100
+++ source/arch/m68knommu/kernel/syscalltable.S	2004-03-09 11:51:48.000000000 +0000
@@ -120,7 +120,7 @@ ENTRY(sys_call_table)
 	.long sys_ni_syscall	/* old profil syscall holder */
 	.long sys_statfs
 	.long sys_fstatfs	/* 100 */
-	.long sys_ioperm
+	.long sys_ni_syscall	/* ioperm for i386 */
 	.long sys_socketcall
 	.long sys_syslog
 	.long sys_setitimer
--- diff/arch/mips/kernel/ioctl32.c	2004-03-04 11:41:44.000000000 +0000
+++ source/arch/mips/kernel/ioctl32.c	2004-03-09 11:51:48.000000000 +0000
@@ -1277,20 +1277,6 @@ COMPATIBLE_IOCTL(SBPROF_ZBSTOP)
 COMPATIBLE_IOCTL(SBPROF_ZBWAITFULL)
 #endif /* CONFIG_SIBYTE_TBPROF */
 
-#if defined(CONFIG_BLK_DEV_DM) || defined(CONFIG_BLK_DEV_DM_MODULE)
-COMPATIBLE_IOCTL(DM_VERSION)
-COMPATIBLE_IOCTL(DM_REMOVE_ALL)
-COMPATIBLE_IOCTL(DM_DEV_CREATE)
-COMPATIBLE_IOCTL(DM_DEV_REMOVE)
-COMPATIBLE_IOCTL(DM_DEV_RELOAD)
-COMPATIBLE_IOCTL(DM_DEV_SUSPEND)
-COMPATIBLE_IOCTL(DM_DEV_RENAME)
-COMPATIBLE_IOCTL(DM_DEV_DEPS)
-COMPATIBLE_IOCTL(DM_DEV_STATUS)
-COMPATIBLE_IOCTL(DM_TARGET_STATUS)
-COMPATIBLE_IOCTL(DM_TARGET_WAIT)
-#endif /* CONFIG_BLK_DEV_DM */
-
 COMPATIBLE_IOCTL(MTIOCTOP)			/* mtio.h ioctls  */
 HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans)
 HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans)
--- diff/arch/mips/mm/dma-coherent.c	2004-03-04 11:41:44.000000000 +0000
+++ source/arch/mips/mm/dma-coherent.c	2004-03-09 11:51:48.000000000 +0000
@@ -119,30 +119,55 @@ void dma_unmap_sg(struct device *dev, st
 
 EXPORT_SYMBOL(dma_unmap_sg);
 
-void dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size,
+void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
 		enum dma_data_direction direction)
 {
 	BUG_ON(direction == DMA_NONE);
 }
 
-EXPORT_SYMBOL(dma_sync_single);
+EXPORT_SYMBOL(dma_sync_single_for_cpu);
 
-void dma_sync_single_range(struct device *dev, dma_addr_t dma_handle,
+void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
+		enum dma_data_direction direction)
+{
+	BUG_ON(direction == DMA_NONE);
+}
+
+EXPORT_SYMBOL(dma_sync_single_for_device);
+
+void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+		      unsigned long offset, size_t size,
+		      enum dma_data_direction direction)
+{
+	BUG_ON(direction == DMA_NONE);
+}
+
+EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
+
+void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
 		      unsigned long offset, size_t size,
 		      enum dma_data_direction direction)
 {
 	BUG_ON(direction == DMA_NONE);
 }
 
-EXPORT_SYMBOL(dma_sync_single_range);
+EXPORT_SYMBOL(dma_sync_single_range_for_device);
 
-void dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems,
+void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
 		 enum dma_data_direction direction)
 {
 	BUG_ON(direction == DMA_NONE);
 }
 
-EXPORT_SYMBOL(dma_sync_sg);
+EXPORT_SYMBOL(dma_sync_sg_for_cpu);
+
+void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
+		 enum dma_data_direction direction)
+{
+	BUG_ON(direction == DMA_NONE);
+}
+
+EXPORT_SYMBOL(dma_sync_sg_for_device);
 
 int dma_supported(struct device *dev, u64 mask)
 {
@@ -204,12 +229,20 @@ unsigned long pci_dac_dma_to_offset(stru
 
 EXPORT_SYMBOL(pci_dac_dma_to_offset);
 
-void pci_dac_dma_sync_single(struct pci_dev *pdev,
+void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev,
+	dma64_addr_t dma_addr, size_t len, int direction)
+{
+	BUG_ON(direction == PCI_DMA_NONE);
+}
+
+EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu);
+
+void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev,
 	dma64_addr_t dma_addr, size_t len, int direction)
 {
 	BUG_ON(direction == PCI_DMA_NONE);
 }
 
-EXPORT_SYMBOL(pci_dac_dma_sync_single);
+EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device);
 
 #endif /* CONFIG_PCI */
--- diff/arch/mips/mm/dma-ip27.c	2004-03-04 11:41:44.000000000 +0000
+++ source/arch/mips/mm/dma-ip27.c	2004-03-09 11:51:48.000000000 +0000
@@ -125,30 +125,55 @@ void dma_unmap_sg(struct device *dev, st
 
 EXPORT_SYMBOL(dma_unmap_sg);
 
-void dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size,
+void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
 		enum dma_data_direction direction)
 {
 	BUG_ON(direction == DMA_NONE);
 }
 
-EXPORT_SYMBOL(dma_sync_single);
+EXPORT_SYMBOL(dma_sync_single_for_cpu);
 
-void dma_sync_single_range(struct device *dev, dma_addr_t dma_handle,
+void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
+		enum dma_data_direction direction)
+{
+	BUG_ON(direction == DMA_NONE);
+}
+
+EXPORT_SYMBOL(dma_sync_single_for_device);
+
+void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+		      unsigned long offset, size_t size,
+		      enum dma_data_direction direction)
+{
+	BUG_ON(direction == DMA_NONE);
+}
+
+EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
+
+void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
 		      unsigned long offset, size_t size,
 		      enum dma_data_direction direction)
 {
 	BUG_ON(direction == DMA_NONE);
 }
 
-EXPORT_SYMBOL(dma_sync_single_range);
+EXPORT_SYMBOL(dma_sync_single_range_for_device);
 
-void dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems,
+void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
 		 enum dma_data_direction direction)
 {
 	BUG_ON(direction == DMA_NONE);
 }
 
-EXPORT_SYMBOL(dma_sync_sg);
+EXPORT_SYMBOL(dma_sync_sg_for_cpu);
+
+void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
+		 enum dma_data_direction direction)
+{
+	BUG_ON(direction == DMA_NONE);
+}
+
+EXPORT_SYMBOL(dma_sync_sg_for_device);
 
 int dma_supported(struct device *dev, u64 mask)
 {
@@ -208,10 +233,18 @@ unsigned long pci_dac_dma_to_offset(stru
 
 EXPORT_SYMBOL(pci_dac_dma_to_offset);
 
-void pci_dac_dma_sync_single(struct pci_dev *pdev,
+void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev,
+	dma64_addr_t dma_addr, size_t len, int direction)
+{
+	BUG_ON(direction == PCI_DMA_NONE);
+}
+
+EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu);
+
+void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev,
 	dma64_addr_t dma_addr, size_t len, int direction)
 {
 	BUG_ON(direction == PCI_DMA_NONE);
 }
 
-EXPORT_SYMBOL(pci_dac_dma_sync_single);
+EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device);
--- diff/arch/mips/mm/dma-noncoherent.c	2004-03-04 11:41:44.000000000 +0000
+++ source/arch/mips/mm/dma-noncoherent.c	2004-03-09 11:51:48.000000000 +0000
@@ -226,7 +226,7 @@ void dma_unmap_sg(struct device *dev, st
 
 EXPORT_SYMBOL(dma_unmap_sg);
 
-void dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size,
+void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
 	enum dma_data_direction direction)
 {
 	unsigned long addr;
@@ -237,9 +237,35 @@ void dma_sync_single(struct device *dev,
 	__dma_sync(addr, size, direction);
 }
 
-EXPORT_SYMBOL(dma_sync_single);
+EXPORT_SYMBOL(dma_sync_single_for_cpu);
 
-void dma_sync_single_range(struct device *dev, dma_addr_t dma_handle,
+void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
+	enum dma_data_direction direction)
+{
+	unsigned long addr;
+
+	BUG_ON(direction == DMA_NONE);
+
+	addr = dma_handle + PAGE_OFFSET;
+	__dma_sync(addr, size, direction);
+}
+
+EXPORT_SYMBOL(dma_sync_single_for_device);
+
+void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+	unsigned long offset, size_t size, enum dma_data_direction direction)
+{
+	unsigned long addr;
+
+	BUG_ON(direction == DMA_NONE);
+
+	addr = dma_handle + offset + PAGE_OFFSET;
+	__dma_sync(addr, size, direction);
+}
+
+EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
+
+void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
 	unsigned long offset, size_t size, enum dma_data_direction direction)
 {
 	unsigned long addr;
@@ -250,9 +276,9 @@ void dma_sync_single_range(struct device
 	__dma_sync(addr, size, direction);
 }
 
-EXPORT_SYMBOL(dma_sync_single_range);
+EXPORT_SYMBOL(dma_sync_single_range_for_device);
 
-void dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems,
+void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
 	enum dma_data_direction direction)
 {
 	int i;
@@ -265,7 +291,22 @@ void dma_sync_sg(struct device *dev, str
 		           sg->length, direction);
 }
 
-EXPORT_SYMBOL(dma_sync_sg);
+EXPORT_SYMBOL(dma_sync_sg_for_cpu);
+
+void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
+	enum dma_data_direction direction)
+{
+	int i;
+
+	BUG_ON(direction == DMA_NONE);
+
+	/* Make sure that gcc doesn't leave the empty loop body.  */
+	for (i = 0; i < nelems; i++, sg++)
+		__dma_sync((unsigned long)page_address(sg->page),
+		           sg->length, direction);
+}
+
+EXPORT_SYMBOL(dma_sync_sg_for_device);
 
 int dma_supported(struct device *dev, u64 mask)
 {
@@ -329,7 +370,17 @@ unsigned long pci_dac_dma_to_offset(stru
 
 EXPORT_SYMBOL(pci_dac_dma_to_offset);
 
-void pci_dac_dma_sync_single(struct pci_dev *pdev,
+void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev,
+	dma64_addr_t dma_addr, size_t len, int direction)
+{
+	BUG_ON(direction == PCI_DMA_NONE);
+
+	dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len);
+}
+
+EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu);
+
+void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev,
 	dma64_addr_t dma_addr, size_t len, int direction)
 {
 	BUG_ON(direction == PCI_DMA_NONE);
@@ -337,6 +388,6 @@ void pci_dac_dma_sync_single(struct pci_
 	dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len);
 }
 
-EXPORT_SYMBOL(pci_dac_dma_sync_single);
+EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device);
 
 #endif /* CONFIG_PCI */
--- diff/arch/parisc/kernel/drivers.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/parisc/kernel/drivers.c	2004-03-09 11:51:48.000000000 +0000
@@ -618,6 +618,7 @@ static void parisc_generic_device_regist
 		 tmp1);
 	/* make the generic dma mask a pointer to the parisc one */
 	dev->dev.dma_mask = &dev->dma_mask;
+	dev->dev.coherent_dma_mask = dev->dma_mask;
 	pr_debug("device_register(%s)\n", dev->dev.bus_id);
 	device_register(&dev->dev);
 }
--- diff/arch/parisc/kernel/pci-dma.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/parisc/kernel/pci-dma.c	2004-03-09 11:51:48.000000000 +0000
@@ -372,7 +372,7 @@ static void * pa11_dma_alloc_consistent 
 ** ISA cards will certainly only support 24-bit DMA addressing.
 ** Not clear if we can, want, or need to support ISA.
 */
-	if (!dev || *dev->dma_mask != 0xffffffff)
+	if (!dev || *dev->coherent_dma_mask < 0xffffffff)
 		gfp |= GFP_DMA;
 #endif
 	return (void *)vaddr;
@@ -413,7 +413,7 @@ static void pa11_dma_unmap_single(struct
 	/*
 	 * For PCI_DMA_FROMDEVICE this flush is not necessary for the
 	 * simple map/unmap case. However, it IS necessary if if
-	 * pci_dma_sync_single has been called and the buffer reused.
+	 * pci_dma_sync_single_* has been called and the buffer reused.
 	 */
 
 	flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), size);
@@ -453,7 +453,7 @@ static void pa11_dma_unmap_sg(struct dev
 	return;
 }
 
-static void pa11_dma_sync_single(struct device *dev, dma_addr_t dma_handle, unsigned long offset, size_t size, enum dma_data_direction direction)
+static void pa11_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, unsigned long offset, size_t size, enum dma_data_direction direction)
 {
 	if (direction == DMA_NONE)
 	    BUG();
@@ -461,7 +461,25 @@ static void pa11_dma_sync_single(struct 
 	flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle) + offset, size);
 }
 
-static void pa11_dma_sync_sg(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction)
+static void pa11_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, unsigned long offset, size_t size, enum dma_data_direction direction)
+{
+	if (direction == DMA_NONE)
+	    BUG();
+
+	flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle) + offset, size);
+}
+
+static void pa11_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction)
+{
+	int i;
+
+	/* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */
+
+	for (i = 0; i < nents; i++, sglist++ )
+		flush_kernel_dcache_range(sg_virt_addr(sglist), sglist->length);
+}
+
+static void pa11_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction)
 {
 	int i;
 
@@ -480,8 +498,10 @@ struct hppa_dma_ops pcxl_dma_ops = {
 	.unmap_single =		pa11_dma_unmap_single,
 	.map_sg =		pa11_dma_map_sg,
 	.unmap_sg =		pa11_dma_unmap_sg,
-	.dma_sync_single =	pa11_dma_sync_single,
-	.dma_sync_sg =		pa11_dma_sync_sg,
+	.dma_sync_single_for_cpu = pa11_dma_sync_single_for_cpu,
+	.dma_sync_single_for_device = pa11_dma_sync_single_for_device,
+	.dma_sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu,
+	.dma_sync_sg_for_device = pa11_dma_sync_sg_for_device,
 };
 
 static void *fail_alloc_consistent(struct device *dev, size_t size,
@@ -519,8 +539,10 @@ struct hppa_dma_ops pcx_dma_ops = {
 	.unmap_single =		pa11_dma_unmap_single,
 	.map_sg =		pa11_dma_map_sg,
 	.unmap_sg =		pa11_dma_unmap_sg,
-	.dma_sync_single =	pa11_dma_sync_single,
-	.dma_sync_sg =		pa11_dma_sync_sg,
+	.dma_sync_single_cpu =	pa11_dma_sync_single_cpu,
+	.dma_sync_single_device = pa11_dma_sync_single_device,
+	.dma_sync_sg_cpu =	pa11_dma_sync_sg_cpu,
+	.dma_sync_sg_device =	pa11_dma_sync_sg_device,
 };
 
 
--- diff/arch/parisc/kernel/process.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/parisc/kernel/process.c	2004-03-09 11:51:48.000000000 +0000
@@ -32,7 +32,6 @@
  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#define __KERNEL_SYSCALLS__
 #include <stdarg.h>
 
 #include <linux/elf.h>
--- diff/arch/parisc/kernel/smp.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/parisc/kernel/smp.c	2004-03-09 11:51:48.000000000 +0000
@@ -16,7 +16,6 @@
 **      the Free Software Foundation; either version 2 of the License, or
 **      (at your option) any later version.
 */
-#define __KERNEL_SYSCALLS__
 #undef ENTRY_SYS_CPUS	/* syscall support for iCOD-like functionality */
 
 #include <linux/autoconf.h>
--- diff/arch/parisc/kernel/sys_parisc.c	2004-03-04 11:41:44.000000000 +0000
+++ source/arch/parisc/kernel/sys_parisc.c	2004-03-09 11:51:48.000000000 +0000
@@ -242,14 +242,6 @@ asmlinkage ssize_t parisc_readahead(int 
 	return sys_readahead(fd, (loff_t)high << 32 | low, count);
 }
 
-/*
- * This changes the io permissions bitmap in the current task.
- */
-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
-{
-	return -ENOSYS;
-}
-
 asmlinkage unsigned long sys_alloc_hugepages(int key, unsigned long addr, unsigned long len, int prot, int flag)
 {
 	return -ENOMEM;
--- diff/arch/ppc/boot/ld.script	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/ppc/boot/ld.script	2004-03-09 11:51:48.000000000 +0000
@@ -82,6 +82,7 @@ SECTIONS
     *(__ksymtab)
     *(__ksymtab_strings)
     *(__bug_table)
+    *(__kcrctab)
   }
 
 }
--- diff/arch/ppc/boot/openfirmware/Makefile	2003-09-17 12:28:02.000000000 +0100
+++ source/arch/ppc/boot/openfirmware/Makefile	2004-03-09 11:51:48.000000000 +0000
@@ -104,10 +104,10 @@ quiet_cmd_gen-coff = COFF    $@
 			$(HACKCOFF) $@ && \
 			ln -sf $(notdir $@) $(images)/zImage$(initrd).pmac
 
-$(images)/vmlinux.coff: $(obj)/coffboot
+$(images)/vmlinux.coff: $(obj)/coffboot $(boot)/ld.script
 	$(call cmd,gen-coff)
 
-$(images)/vmlinux.initrd.coff: $(obj)/coffboot.initrd
+$(images)/vmlinux.initrd.coff: $(obj)/coffboot.initrd $(boot)/ld.script
 	$(call cmd,gen-coff)
 
 quiet_cmd_gen-elf-pmac = ELF     $@
@@ -116,19 +116,19 @@ quiet_cmd_gen-elf-pmac = ELF     $@
 			$(OBJCOPY) $@ $@ --add-section=.note=$(obj)/note \
 					 -R .comment $(del-ramdisk-sec)
 
-$(images)/vmlinux.elf-pmac: $(obj)/image.o $(NEWWORLDOBJS) $(LIBS) $(obj)/note
+$(images)/vmlinux.elf-pmac: $(obj)/image.o $(NEWWORLDOBJS) $(LIBS) $(obj)/note $(boot)/ld.script
 	$(call cmd,gen-elf-pmac)
 $(images)/vmlinux.initrd.elf-pmac: $(obj)/image.initrd.o $(NEWWORLDOBJS) \
-				   $(LIBS) $(obj)/note
+				   $(LIBS) $(obj)/note $(boot)/ld.script
 	$(call cmd,gen-elf-pmac)
 
 quiet_cmd_gen-chrp = CHRP    $@
       cmd_gen-chrp = $(LD) $(CHRP_LD_ARGS) -o $@ $^ && \
 			$(OBJCOPY) $@ $@ -R .comment $(del-ramdisk-sec)
 
-$(images)/zImage.chrp: $(CHRPOBJS) $(obj)/image.o $(LIBS)
+$(images)/zImage.chrp: $(CHRPOBJS) $(obj)/image.o $(LIBS) $(boot)/ld.script
 	$(call cmd,gen-chrp)
-$(images)/zImage.initrd.chrp: $(CHRPOBJS) $(obj)/image.initrd.o $(LIBS)
+$(images)/zImage.initrd.chrp: $(CHRPOBJS) $(obj)/image.initrd.o $(LIBS) $(boot)/ld.script
 	$(call cmd,gen-chrp)
 
 quiet_cmd_addnote = ADDNOTE $@
--- diff/arch/ppc/kernel/head.S	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ppc/kernel/head.S	2004-03-09 11:51:48.000000000 +0000
@@ -1492,22 +1492,22 @@ BEGIN_FTR_SECTION
 	 * seems that doesn't affect our ability to actually
 	 * write to these SPRs.
 	 */
-	mtspr	SPRN_DBAT4U,r20
-	mtspr	SPRN_DBAT4L,r20
-	mtspr	SPRN_DBAT5U,r20
-	mtspr	SPRN_DBAT5L,r20
-	mtspr	SPRN_DBAT6U,r20
-	mtspr	SPRN_DBAT6L,r20
-	mtspr	SPRN_DBAT7U,r20
-	mtspr	SPRN_DBAT7L,r20
-	mtspr	SPRN_IBAT4U,r20
-	mtspr	SPRN_IBAT4L,r20
-	mtspr	SPRN_IBAT5U,r20
-	mtspr	SPRN_IBAT5L,r20
-	mtspr	SPRN_IBAT6U,r20
-	mtspr	SPRN_IBAT6L,r20
-	mtspr	SPRN_IBAT7U,r20
-	mtspr	SPRN_IBAT7L,r20
+	mtspr	SPRN_DBAT4U,r10
+	mtspr	SPRN_DBAT4L,r10
+	mtspr	SPRN_DBAT5U,r10
+	mtspr	SPRN_DBAT5L,r10
+	mtspr	SPRN_DBAT6U,r10
+	mtspr	SPRN_DBAT6L,r10
+	mtspr	SPRN_DBAT7U,r10
+	mtspr	SPRN_DBAT7L,r10
+	mtspr	SPRN_IBAT4U,r10
+	mtspr	SPRN_IBAT4L,r10
+	mtspr	SPRN_IBAT5U,r10
+	mtspr	SPRN_IBAT5L,r10
+	mtspr	SPRN_IBAT6U,r10
+	mtspr	SPRN_IBAT6L,r10
+	mtspr	SPRN_IBAT7U,r10
+	mtspr	SPRN_IBAT7L,r10
 END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
 	blr
 
--- diff/arch/ppc/kernel/misc.S	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ppc/kernel/misc.S	2004-03-09 11:51:48.000000000 +0000
@@ -1108,17 +1108,7 @@ _GLOBAL(name) \
 	li	r3,-1; \
 	blr
 
-#define __NR__exit __NR_exit
-
-SYSCALL(setsid)
-SYSCALL(open)
-SYSCALL(read)
-SYSCALL(write)
-SYSCALL(lseek)
-SYSCALL(close)
-SYSCALL(dup)
 SYSCALL(execve)
-SYSCALL(waitpid)
 
 /* Why isn't this a) automatic, b) written in 'C'? */
 	.data
--- diff/arch/ppc/kernel/ppc_ksyms.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ppc/kernel/ppc_ksyms.c	2004-03-09 11:51:48.000000000 +0000
@@ -32,8 +32,6 @@
 #include <linux/pmu.h>
 #include <asm/prom.h>
 #include <asm/system.h>
-#define __KERNEL_SYSCALLS__
-#include <asm/unistd.h>
 #include <asm/pci-bridge.h>
 #include <asm/irq.h>
 #include <asm/pmac_feature.h>
@@ -189,10 +187,6 @@ EXPORT_SYMBOL(consistent_sync);
 EXPORT_SYMBOL(flush_dcache_all);
 #endif
 
-EXPORT_SYMBOL(open);
-EXPORT_SYMBOL(read);
-EXPORT_SYMBOL(lseek);
-EXPORT_SYMBOL(close);
 EXPORT_SYMBOL(start_thread);
 EXPORT_SYMBOL(kernel_thread);
 
--- diff/arch/ppc/kernel/smp.c	2004-03-04 11:41:44.000000000 +0000
+++ source/arch/ppc/kernel/smp.c	2004-03-09 11:51:48.000000000 +0000
@@ -17,8 +17,6 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/delay.h>
-#define __KERNEL_SYSCALLS__
-#include <linux/unistd.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/cache.h>
--- diff/arch/ppc/platforms/chrp_smp.c	2003-05-21 11:49:59.000000000 +0100
+++ source/arch/ppc/platforms/chrp_smp.c	2004-03-09 11:51:48.000000000 +0000
@@ -16,8 +16,6 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/delay.h>
-#define __KERNEL_SYSCALLS__
-#include <linux/unistd.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
 
--- diff/arch/ppc/platforms/pmac_smp.c	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/ppc/platforms/pmac_smp.c	2004-03-09 11:51:48.000000000 +0000
@@ -29,8 +29,6 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/delay.h>
-#define __KERNEL_SYSCALLS__
-#include <linux/unistd.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/errno.h>
--- diff/arch/ppc64/Kconfig	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/ppc64/Kconfig	2004-03-09 11:51:48.000000000 +0000
@@ -300,10 +300,6 @@ config VIOCD
 	  If you are running Linux on an IBM iSeries system and you want to
 	  read a CD drive owned by OS/400, say Y here.
 
-config VIOCD_AZTECH
-	bool "iSeries Virtual CD Aztech emulation"
-	depends on VIOCD
-
 config VIOTAPE
 	tristate "iSeries Virtual Tape Support"
 	help
--- diff/arch/ppc64/kernel/iSeries_iommu.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/ppc64/kernel/iSeries_iommu.c	2004-03-09 11:51:48.000000000 +0000
@@ -43,6 +43,7 @@
 #include <asm/iommu.h>
 #include <asm/pci-bridge.h>
 #include <asm/iSeries/iSeries_pci.h>
+#include <asm/iSeries/vio.h>
 
 #include <asm/machdep.h>
 
@@ -58,11 +59,6 @@ static struct iSeries_Device_Node vio_de
 static struct pci_dev _veth_dev = { .sysdata = &veth_dev_node };
 static struct pci_dev _vio_dev  = { .sysdata = &vio_dev_node, .dev.bus = &pci_bus_type  };
 
-/*
- * I wonder what the deal is with these.  Nobody uses them.  Why do they
- * exist? Why do we export them to modules? Why is this comment here, and
- * why didn't I just delete them?
- */
 struct pci_dev *iSeries_veth_dev = &_veth_dev;
 struct device *iSeries_vio_dev = &_vio_dev.dev;
 
--- diff/arch/ppc64/kernel/mf.c	2004-02-09 10:36:08.000000000 +0000
+++ source/arch/ppc64/kernel/mf.c	2004-03-09 11:51:48.000000000 +0000
@@ -38,10 +38,9 @@
 #include <asm/iSeries/ItSpCommArea.h>
 #include <asm/iSeries/iSeries_proc.h>
 #include <asm/uaccess.h>
-#include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/bcd.h>
-
-extern struct pci_dev *iSeries_vio_dev;
+#include <asm/iSeries/vio.h>
 
 /*
  * This is the structure layout for the Machine Facilites LPAR event
@@ -791,7 +790,8 @@ void mf_setCmdLine(const char *cmdline, 
 {
 	struct VspCmdData myVspCmd;
 	dma_addr_t dma_addr = 0;
-	char *page = pci_alloc_consistent(iSeries_vio_dev, size, &dma_addr);
+	char *page = dma_alloc_coherent(iSeries_vio_dev, size, &dma_addr,
+			GFP_ATOMIC);
 
 	if (page == NULL) {
 		printk(KERN_ERR "mf.c: couldn't allocate memory to set command line\n");
@@ -809,7 +809,7 @@ void mf_setCmdLine(const char *cmdline, 
 	mb();
 	(void)signal_vsp_instruction(&myVspCmd);
 
-	pci_free_consistent(iSeries_vio_dev, size, page, dma_addr);
+	dma_free_coherent(iSeries_vio_dev, size, page, dma_addr);
 }
 
 int mf_getCmdLine(char *cmdline, int *size, u64 side)
@@ -819,8 +819,8 @@ int mf_getCmdLine(char *cmdline, int *si
 	int len = *size;
 	dma_addr_t dma_addr;
 
-	dma_addr = pci_map_single(iSeries_vio_dev, cmdline, len,
-			PCI_DMA_FROMDEVICE);
+	dma_addr = dma_map_single(iSeries_vio_dev, cmdline, len,
+			DMA_FROM_DEVICE);
 	memset(cmdline, 0, len);
 	memset(&myVspCmd, 0, sizeof(myVspCmd));
 	myVspCmd.cmd = 33;
@@ -840,7 +840,7 @@ int mf_getCmdLine(char *cmdline, int *si
 #endif
 	}
 
-	pci_unmap_single(iSeries_vio_dev, dma_addr, *size, PCI_DMA_FROMDEVICE);
+	dma_unmap_single(iSeries_vio_dev, dma_addr, *size, DMA_FROM_DEVICE);
 
 	return len;
 }
@@ -851,7 +851,8 @@ int mf_setVmlinuxChunk(const char *buffe
 	struct VspCmdData myVspCmd;
 	int rc;
 	dma_addr_t dma_addr = 0;
-	char *page = pci_alloc_consistent(iSeries_vio_dev, size, &dma_addr);
+	char *page = dma_alloc_coherent(iSeries_vio_dev, size, &dma_addr,
+			GFP_ATOMIC);
 
 	if (page == NULL) {
 		printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n");
@@ -876,7 +877,7 @@ int mf_setVmlinuxChunk(const char *buffe
 			rc = -ENOMEM;
 	}
 
-	pci_free_consistent(iSeries_vio_dev, size, page, dma_addr);
+	dma_free_coherent(iSeries_vio_dev, size, page, dma_addr);
 
 	return rc;
 }
@@ -888,8 +889,8 @@ int mf_getVmlinuxChunk(char *buffer, int
 	int len = *size;
 	dma_addr_t dma_addr;
 
-	dma_addr = pci_map_single(iSeries_vio_dev, buffer, len,
-			PCI_DMA_FROMDEVICE);
+	dma_addr = dma_map_single(iSeries_vio_dev, buffer, len,
+			DMA_FROM_DEVICE);
 	memset(buffer, 0, len);
 	memset(&myVspCmd, 0, sizeof(myVspCmd));
 	myVspCmd.cmd = 32;
@@ -907,7 +908,7 @@ int mf_getVmlinuxChunk(char *buffer, int
 			rc = -ENOMEM;
 	}
 
-	pci_unmap_single(iSeries_vio_dev, dma_addr, len, PCI_DMA_FROMDEVICE);
+	dma_unmap_single(iSeries_vio_dev, dma_addr, len, DMA_FROM_DEVICE);
 
 	return rc;
 }
--- diff/arch/ppc64/kernel/misc.S	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/ppc64/kernel/misc.S	2004-03-09 11:51:48.000000000 +0000
@@ -582,17 +582,7 @@ _GLOBAL(name) \
 	li	r3,-1; \
 	blr
 
-#define __NR__exit __NR_exit
-
-SYSCALL(setsid)
-SYSCALL(open)
-SYSCALL(read)
-SYSCALL(write)
-SYSCALL(lseek)
-SYSCALL(close)
-SYSCALL(dup)
 SYSCALL(execve)
-SYSCALL(waitpid)
 
 #ifdef CONFIG_PPC_ISERIES	/* hack hack hack */
 #define ppc_rtas	sys_ni_syscall
--- diff/arch/ppc64/kernel/pmac_smp.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/ppc64/kernel/pmac_smp.c	2004-03-09 11:51:48.000000000 +0000
@@ -29,8 +29,6 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/delay.h>
-#define __KERNEL_SYSCALLS__
-#include <linux/unistd.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/errno.h>
--- diff/arch/ppc64/kernel/stab.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/ppc64/kernel/stab.c	2004-03-09 11:51:48.000000000 +0000
@@ -184,13 +184,13 @@ int ste_allocate(unsigned long ea)
 	/* Kernel or user address? */
 	if (REGION_ID(ea) >= KERNEL_REGION_ID) {
 		vsid = get_kernel_vsid(ea);
-		context = REGION_ID(ea);
+		context = KERNEL_CONTEXT(ea);
 	} else {
 		if (!current->mm)
 			return 1;
 
 		context = current->mm->context;
-		vsid = get_vsid(context, ea);
+		vsid = get_vsid(context.id, ea);
 	}
 
 	esid = GET_ESID(ea);
@@ -223,7 +223,7 @@ static void preload_stab(struct task_str
 
 	if (!IS_VALID_EA(pc) || (REGION_ID(pc) >= KERNEL_REGION_ID))
 		return;
-	vsid = get_vsid(mm->context, pc);
+	vsid = get_vsid(mm->context.id, pc);
 	__ste_allocate(pc_esid, vsid);
 
 	if (pc_esid == stack_esid)
@@ -231,7 +231,7 @@ static void preload_stab(struct task_str
 
 	if (!IS_VALID_EA(stack) || (REGION_ID(stack) >= KERNEL_REGION_ID))
 		return;
-	vsid = get_vsid(mm->context, stack);
+	vsid = get_vsid(mm->context.id, stack);
 	__ste_allocate(stack_esid, vsid);
 
 	if (pc_esid == unmapped_base_esid || stack_esid == unmapped_base_esid)
@@ -240,7 +240,7 @@ static void preload_stab(struct task_str
 	if (!IS_VALID_EA(unmapped_base) ||
 	    (REGION_ID(unmapped_base) >= KERNEL_REGION_ID))
 		return;
-	vsid = get_vsid(mm->context, unmapped_base);
+	vsid = get_vsid(mm->context.id, unmapped_base);
 	__ste_allocate(unmapped_base_esid, vsid);
 
 	/* Order update */
@@ -406,14 +406,14 @@ int slb_allocate(unsigned long ea)
 
 	/* Kernel or user address? */
 	if (REGION_ID(ea) >= KERNEL_REGION_ID) {
-		context = REGION_ID(ea);
+		context = KERNEL_CONTEXT(ea);
 		vsid = get_kernel_vsid(ea);
 	} else {
 		if (unlikely(!current->mm))
 			return 1;
 
 		context = current->mm->context;
-		vsid = get_vsid(context, ea);
+		vsid = get_vsid(context.id, ea);
 	}
 
 	esid = GET_ESID(ea);
@@ -444,7 +444,7 @@ static void preload_slb(struct task_stru
 
 	if (!IS_VALID_EA(pc) || (REGION_ID(pc) >= KERNEL_REGION_ID))
 		return;
-	vsid = get_vsid(mm->context, pc);
+	vsid = get_vsid(mm->context.id, pc);
 	__slb_allocate(pc_esid, vsid, mm->context);
 
 	if (pc_esid == stack_esid)
@@ -452,7 +452,7 @@ static void preload_slb(struct task_stru
 
 	if (!IS_VALID_EA(stack) || (REGION_ID(stack) >= KERNEL_REGION_ID))
 		return;
-	vsid = get_vsid(mm->context, stack);
+	vsid = get_vsid(mm->context.id, stack);
 	__slb_allocate(stack_esid, vsid, mm->context);
 
 	if (pc_esid == unmapped_base_esid || stack_esid == unmapped_base_esid)
@@ -461,7 +461,7 @@ static void preload_slb(struct task_stru
 	if (!IS_VALID_EA(unmapped_base) ||
 	    (REGION_ID(unmapped_base) >= KERNEL_REGION_ID))
 		return;
-	vsid = get_vsid(mm->context, unmapped_base);
+	vsid = get_vsid(mm->context.id, unmapped_base);
 	__slb_allocate(unmapped_base_esid, vsid, mm->context);
 }
 
--- diff/arch/ppc64/kernel/viopath.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/ppc64/kernel/viopath.c	2004-03-09 11:51:48.000000000 +0000
@@ -35,7 +35,6 @@
 #include <linux/vmalloc.h>
 #include <linux/string.h>
 #include <linux/proc_fs.h>
-#include <linux/device.h>
 #include <linux/dma-mapping.h>
 #include <linux/wait.h>
 
@@ -49,8 +48,6 @@
 #include <asm/iSeries/iSeries_proc.h>
 #include <asm/iSeries/vio.h>
 
-extern struct device *iSeries_vio_dev;
-
 /* Status of the path to each other partition in the system.
  * This is overkill, since we will only ever establish connections
  * to our hosting partition and the primary partition on the system.
--- diff/arch/ppc64/mm/hash_utils.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/ppc64/mm/hash_utils.c	2004-03-09 11:51:48.000000000 +0000
@@ -265,7 +265,7 @@ int hash_page(unsigned long ea, unsigned
 		if (mm == NULL)
 			return 1;
 
-		vsid = get_vsid(mm->context, ea);
+		vsid = get_vsid(mm->context.id, ea);
 		break;
 	case IO_REGION_ID:
 		mm = &ioremap_mm;
--- diff/arch/ppc64/mm/hugetlbpage.c	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/ppc64/mm/hugetlbpage.c	2004-03-09 11:51:48.000000000 +0000
@@ -244,7 +244,7 @@ static int open_32bit_htlbpage_range(str
 	struct vm_area_struct *vma;
 	unsigned long addr;
 
-	if (mm->context & CONTEXT_LOW_HPAGES)
+	if (mm->context.low_hpages)
 		return 0; /* The window is already open */
 	
 	/* Check no VMAs are in the region */
@@ -281,7 +281,7 @@ static int open_32bit_htlbpage_range(str
 
 	/* FIXME: do we need to scan for PTEs too? */
 
-	mm->context |= CONTEXT_LOW_HPAGES;
+	mm->context.low_hpages = 1;
 
 	/* the context change must make it to memory before the slbia,
 	 * so that further SLB misses do the right thing. */
@@ -589,7 +589,6 @@ full_search:
 	}
 }
 
-
 unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
 					unsigned long len, unsigned long pgoff,
 					unsigned long flags)
@@ -778,7 +777,7 @@ static void flush_hash_hugepage(mm_conte
 	BUG_ON(hugepte_bad(pte));
 	BUG_ON(!in_hugepage_area(context, ea));
 
-	vsid = get_vsid(context, ea);
+	vsid = get_vsid(context.id, ea);
 
 	va = (vsid << 28) | (ea & 0x0fffffff);
 	vpn = va >> LARGE_PAGE_SHIFT;
--- diff/arch/ppc64/mm/init.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/ppc64/mm/init.c	2004-03-09 11:51:48.000000000 +0000
@@ -794,7 +794,7 @@ void update_mmu_cache(struct vm_area_str
 	if (!ptep)
 		return;
 
-	vsid = get_vsid(vma->vm_mm->context, ea);
+	vsid = get_vsid(vma->vm_mm->context.id, ea);
 
 	tmp = cpumask_of_cpu(smp_processor_id());
 	if (cpus_equal(vma->vm_mm->cpu_vm_mask, tmp))
--- diff/arch/ppc64/mm/tlb.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/ppc64/mm/tlb.c	2004-03-09 11:51:48.000000000 +0000
@@ -62,7 +62,7 @@ void hpte_update(pte_t *ptep, unsigned l
 	addr = ptep_to_address(ptep);
 
 	if (REGION_ID(addr) == USER_REGION_ID)
-		context = mm->context;
+		context = mm->context.id;
 	i = batch->index;
 
 	/*
--- diff/arch/ppc64/xmon/xmon.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/ppc64/xmon/xmon.c	2004-03-09 11:51:48.000000000 +0000
@@ -344,7 +344,7 @@ xmon(struct pt_regs *excp)
 #endif /* CONFIG_SMP */
 	set_msrd(msr);		/* restore interrupt enable */
 
-	return 0;
+	return 1;
 }
 
 int
--- diff/arch/s390/Kconfig	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/s390/Kconfig	2004-03-09 11:51:48.000000000 +0000
@@ -143,6 +143,11 @@ config COMPAT
 	depends on S390_SUPPORT
 	default y
 
+config SYSVIPC_COMPAT
+	bool
+	depends on COMPAT && SYSVIPC
+	default y
+
 config BINFMT_ELF32
 	tristate "Kernel support for 31 bit ELF binaries"
 	depends on S390_SUPPORT
--- diff/arch/s390/kernel/compat_linux.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/s390/kernel/compat_linux.c	2004-03-09 11:51:48.000000000 +0000
@@ -293,541 +293,6 @@ static inline long put_tv32(struct compa
 		 __put_user(i->tv_usec, &o->tv_usec)));
 }
 
-struct msgbuf32 { s32 mtype; char mtext[1]; };
-
-struct ipc64_perm_ds32
-{
-        __kernel_key_t          key;
-        __kernel_uid32_t        uid;
-        __kernel_gid32_t        gid;
-        __kernel_uid32_t        cuid;
-        __kernel_gid32_t        cgid;
-        compat_mode_t       mode;
-        unsigned short          __pad1;
-        unsigned short          seq;
-        unsigned short          __pad2;
-        unsigned int            __unused1;
-        unsigned int            __unused2;
-};
-
-struct ipc_perm32
-{
-	key_t    	  key;
-        compat_uid_t  uid;
-        compat_gid_t  gid;
-        compat_uid_t  cuid;
-        compat_gid_t  cgid;
-        compat_mode_t mode;
-        unsigned short  seq;
-};
-
-struct semid_ds32 {
-        struct ipc_perm32 sem_perm;               /* permissions .. see ipc.h */
-        compat_time_t   sem_otime;              /* last semop time */
-        compat_time_t   sem_ctime;              /* last change time */
-        u32 sem_base;              /* ptr to first semaphore in array */
-        u32 sem_pending;          /* pending operations to be processed */
-        u32 sem_pending_last;    /* last pending operation */
-        u32 undo;                  /* undo requests on this array */
-        unsigned short  sem_nsems;              /* no. of semaphores in array */
-};
-
-struct semid64_ds32 {
-	struct ipc64_perm_ds32 sem_perm;
-	unsigned int	  __pad1;
-	compat_time_t   sem_otime;
-	unsigned int	  __pad2;
-	compat_time_t   sem_ctime;
-	u32 sem_nsems;
-	u32 __unused1;
-	u32 __unused2;
-};
-
-struct msqid_ds32
-{
-        struct ipc_perm32 msg_perm;
-        u32 msg_first;
-        u32 msg_last;
-        compat_time_t   msg_stime;
-        compat_time_t   msg_rtime;
-        compat_time_t   msg_ctime;
-        u32 wwait;
-        u32 rwait;
-        unsigned short msg_cbytes;
-        unsigned short msg_qnum;  
-        unsigned short msg_qbytes;
-        compat_ipc_pid_t msg_lspid;
-        compat_ipc_pid_t msg_lrpid;
-};
-
-struct msqid64_ds32 {
-	struct ipc64_perm_ds32 msg_perm;
-	unsigned int   __pad1;
-	compat_time_t msg_stime;
-	unsigned int   __pad2;
-	compat_time_t msg_rtime;
-	unsigned int   __pad3;
-	compat_time_t msg_ctime;
-	unsigned int  msg_cbytes;
-	unsigned int  msg_qnum;
-	unsigned int  msg_qbytes;
-	compat_pid_t msg_lspid;
-	compat_pid_t msg_lrpid;
-	unsigned int  __unused1;
-	unsigned int  __unused2;
-};
-
-
-struct shmid_ds32 {
-	struct ipc_perm32       shm_perm;
-	int                     shm_segsz;
-	compat_time_t         shm_atime;
-	compat_time_t         shm_dtime;
-	compat_time_t         shm_ctime;
-	compat_ipc_pid_t    shm_cpid; 
-	compat_ipc_pid_t    shm_lpid; 
-	unsigned short          shm_nattch;
-};
-
-struct shmid64_ds32 {
-	struct ipc64_perm_ds32	shm_perm;
-	compat_size_t	shm_segsz;
-	compat_time_t  	shm_atime;
-	unsigned int		__unused1;
-	compat_time_t  	shm_dtime;
-	unsigned int		__unused2;
-	compat_time_t  	shm_ctime;
-	unsigned int		__unused3;
-	compat_pid_t	shm_cpid;
-	compat_pid_t	shm_lpid;
-	unsigned int		shm_nattch;
-	unsigned int		__unused4;
-	unsigned int		__unused5;
-};
-
-extern int sem_ctls[];
-#define sc_semopm	(sem_ctls[2])
-#define SEMOPM_FAST	64  /* ~ 372 bytes on stack */
-
-static long
-do_sys32_semtimedop (int semid, struct sembuf *tsops, int nsops,
-		     struct compat_timespec *timeout32)
-{
-	struct sembuf *sops, fast_sops[SEMOPM_FAST];
-	struct timespec t;
-	mm_segment_t oldfs;
-	long ret;
-
-	/* parameter checking precedence should mirror sys_semtimedop() */
-	if (nsops < 1 || semid < 0)
-		return -EINVAL;
-	if (nsops > sc_semopm)
-		return -E2BIG;
-	if (nsops <= SEMOPM_FAST)
-		sops = fast_sops;
-	else {
-		sops = kmalloc(nsops * sizeof(*sops), GFP_KERNEL);
-		if (sops == NULL)
-			return -ENOMEM;
-	}
-	if (copy_from_user(sops, tsops, nsops * sizeof(*tsops)) ||
-	    get_compat_timespec(&t, timeout32))
-		ret = -EFAULT;
-	else {
-		oldfs = get_fs();
-		set_fs(KERNEL_DS);
-		ret = sys_semtimedop(semid, sops, nsops, &t);
-		set_fs(oldfs);
-	}
-	if (sops != fast_sops)
-		kfree(sops);
-	return ret;
-}
-
-#define IPCOP_MASK(__x)	(1UL << (__x))
-static int do_sys32_semctl(int first, int second, int third, void *uptr)
-{
-	union semun fourth;
-	u32 pad;
-	int err = -EINVAL;
-
-	if (!uptr)
-		goto out;
-	err = -EFAULT;
-	if (get_user (pad, (u32 *)uptr))
-		goto out;
-	if(third == SETVAL)
-		fourth.val = (int)pad;
-	else
-		fourth.__pad = (void *)A(pad);
-	if (IPCOP_MASK (third) &
-	    (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (SEM_INFO) | IPCOP_MASK (GETVAL) |
-	     IPCOP_MASK (GETPID) | IPCOP_MASK (GETNCNT) | IPCOP_MASK (GETZCNT) |
-	     IPCOP_MASK (GETALL) | IPCOP_MASK (SETALL) | IPCOP_MASK (IPC_RMID))) {
-		err = sys_semctl (first, second, third, fourth);
-	} else if (third & IPC_64) {
-		struct semid64_ds s;
-		struct semid64_ds32 *usp = (struct semid64_ds32 *)A(pad);
-		mm_segment_t old_fs;
-		int need_back_translation;
-
-		if (third == (IPC_SET|IPC_64)) {
-			err = get_user (s.sem_perm.uid, &usp->sem_perm.uid);
-			err |= __get_user (s.sem_perm.gid, &usp->sem_perm.gid);
-			err |= __get_user (s.sem_perm.mode, &usp->sem_perm.mode);
-			if (err)
-				goto out;
-			fourth.__pad = &s;
-		}
-		need_back_translation =
-			(IPCOP_MASK (third) &
-			 (IPCOP_MASK (SEM_STAT) | IPCOP_MASK (IPC_STAT))) != 0;
-		if (need_back_translation)
-			fourth.__pad = &s;
-		old_fs = get_fs ();
-		set_fs (KERNEL_DS);
-		err = sys_semctl (first, second, third, fourth);
-		set_fs (old_fs);
-		if (need_back_translation) {
-			int err2 = put_user (s.sem_perm.key, &usp->sem_perm.key);
-			err2 |= __put_user (high2lowuid(s.sem_perm.uid), &usp->sem_perm.uid);
-			err2 |= __put_user (high2lowgid(s.sem_perm.gid), &usp->sem_perm.gid);
-			err2 |= __put_user (high2lowuid(s.sem_perm.cuid), &usp->sem_perm.cuid);
-			err2 |= __put_user (high2lowgid(s.sem_perm.cgid), &usp->sem_perm.cgid);
-			err2 |= __put_user (s.sem_perm.mode, &usp->sem_perm.mode);
-			err2 |= __put_user (s.sem_perm.seq, &usp->sem_perm.seq);
-			err2 |= __put_user (s.sem_otime, &usp->sem_otime);
-			err2 |= __put_user (s.sem_ctime, &usp->sem_ctime);
-			err2 |= __put_user (s.sem_nsems, &usp->sem_nsems);
-			if (err2) err = -EFAULT;
-		}
-	} else {
-		struct semid_ds s;
-		struct semid_ds32 *usp = (struct semid_ds32 *)A(pad);
-		mm_segment_t old_fs;
-		int need_back_translation;
-
-		if (third == IPC_SET) {
-			err = get_user (s.sem_perm.uid, &usp->sem_perm.uid);
-			err |= __get_user (s.sem_perm.gid, &usp->sem_perm.gid);
-			err |= __get_user (s.sem_perm.mode, &usp->sem_perm.mode);
-			if (err)
-				goto out;
-			fourth.__pad = &s;
-		}
-		need_back_translation =
-			(IPCOP_MASK (third) &
-			 (IPCOP_MASK (SEM_STAT) | IPCOP_MASK (IPC_STAT))) != 0;
-		if (need_back_translation)
-			fourth.__pad = &s;
-		old_fs = get_fs ();
-		set_fs (KERNEL_DS);
-		err = sys_semctl (first, second, third, fourth);
-		set_fs (old_fs);
-		if (need_back_translation) {
-			int err2 = put_user (s.sem_perm.key, &usp->sem_perm.key);
-			err2 |= __put_user (high2lowuid(s.sem_perm.uid), &usp->sem_perm.uid);
-			err2 |= __put_user (high2lowgid(s.sem_perm.gid), &usp->sem_perm.gid);
-			err2 |= __put_user (high2lowuid(s.sem_perm.cuid), &usp->sem_perm.cuid);
-			err2 |= __put_user (high2lowgid(s.sem_perm.cgid), &usp->sem_perm.cgid);
-			err2 |= __put_user (s.sem_perm.mode, &usp->sem_perm.mode);
-			err2 |= __put_user (s.sem_perm.seq, &usp->sem_perm.seq);
-			err2 |= __put_user (s.sem_otime, &usp->sem_otime);
-			err2 |= __put_user (s.sem_ctime, &usp->sem_ctime);
-			err2 |= __put_user (s.sem_nsems, &usp->sem_nsems);
-			if (err2) err = -EFAULT;
-		}
-	}
-out:
-	return err;
-}
-
-static int do_sys32_msgsnd (int first, int second, int third, void *uptr)
-{
-	struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf), GFP_USER);
-	struct msgbuf32 *up = (struct msgbuf32 *)uptr;
-	mm_segment_t old_fs;
-	int err;
-
-	if (!p)
-		return -ENOMEM;
-
-	err = -EINVAL;
-	if (second > MSGMAX || first < 0 || second < 0)
-		goto out;
-
-	err = -EFAULT;
-	if (!uptr)
-		goto out;
-        if (get_user (p->mtype, &up->mtype) ||
-	    __copy_from_user (p->mtext, &up->mtext, second))
-		goto out;
-	old_fs = get_fs ();
-	set_fs (KERNEL_DS);
-	err = sys_msgsnd (first, p, second, third);
-	set_fs (old_fs);
-out:
-	kfree (p);
-	return err;
-}
-
-static int do_sys32_msgrcv (int first, int second, int msgtyp, int third,
-			    int version, void *uptr)
-{
-	struct msgbuf32 *up;
-	struct msgbuf *p;
-	mm_segment_t old_fs;
-	int err;
-
-	if (first < 0 || second < 0)
-		return -EINVAL;
-
-	if (!version) {
-		struct ipc_kludge_32 *uipck = (struct ipc_kludge_32 *)uptr;
-		struct ipc_kludge_32 ipck;
-
-		err = -EINVAL;
-		if (!uptr)
-			goto out;
-		err = -EFAULT;
-		if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge_32)))
-			goto out;
-		uptr = (void *)A(ipck.msgp);
-		msgtyp = ipck.msgtyp;
-	}
-	err = -ENOMEM;
-	p = kmalloc (second + sizeof (struct msgbuf), GFP_USER);
-	if (!p)
-		goto out;
-	old_fs = get_fs ();
-	set_fs (KERNEL_DS);
-	err = sys_msgrcv (first, p, second, msgtyp, third);
-	set_fs (old_fs);
-	if (err < 0)
-		goto free_then_out;
-	up = (struct msgbuf32 *)uptr;
-	if (put_user (p->mtype, &up->mtype) ||
-	    __copy_to_user (&up->mtext, p->mtext, err))
-		err = -EFAULT;
-free_then_out:
-	kfree (p);
-out:
-	return err;
-}
-
-static int do_sys32_msgctl (int first, int second, void *uptr)
-{
-	int err;
-
-	if (IPCOP_MASK (second) &
-	    (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (MSG_INFO) |
-	     IPCOP_MASK (IPC_RMID))) {
-		err = sys_msgctl (first, second, (struct msqid_ds *)uptr);
-	} else if (second & IPC_64) {
-		struct msqid64_ds m;
-		struct msqid64_ds32 *up = (struct msqid64_ds32 *)uptr;
-		mm_segment_t old_fs;
-
-		if (second == (IPC_SET|IPC_64)) {
-			err = get_user (m.msg_perm.uid, &up->msg_perm.uid);
-			err |= __get_user (m.msg_perm.gid, &up->msg_perm.gid);
-			err |= __get_user (m.msg_perm.mode, &up->msg_perm.mode);
-			err |= __get_user (m.msg_qbytes, &up->msg_qbytes);
-			if (err)
-				goto out;
-		}
-		old_fs = get_fs ();
-		set_fs (KERNEL_DS);
-		err = sys_msgctl (first, second, (struct msqid_ds *)&m);
-		set_fs (old_fs);
-		if (IPCOP_MASK (second) &
-		    (IPCOP_MASK (MSG_STAT) | IPCOP_MASK (IPC_STAT))) {
-			int err2 = put_user (m.msg_perm.key, &up->msg_perm.key);
-			err2 |= __put_user (high2lowuid(m.msg_perm.uid), &up->msg_perm.uid);
-			err2 |= __put_user (high2lowgid(m.msg_perm.gid), &up->msg_perm.gid);
-			err2 |= __put_user (high2lowuid(m.msg_perm.cuid), &up->msg_perm.cuid);
-			err2 |= __put_user (high2lowgid(m.msg_perm.cgid), &up->msg_perm.cgid);
-			err2 |= __put_user (m.msg_perm.mode, &up->msg_perm.mode);
-			err2 |= __put_user (m.msg_perm.seq, &up->msg_perm.seq);
-			err2 |= __put_user (m.msg_stime, &up->msg_stime);
-			err2 |= __put_user (m.msg_rtime, &up->msg_rtime);
-			err2 |= __put_user (m.msg_ctime, &up->msg_ctime);
-			err2 |= __put_user (m.msg_cbytes, &up->msg_cbytes);
-			err2 |= __put_user (m.msg_qnum, &up->msg_qnum);
-			err2 |= __put_user (m.msg_qbytes, &up->msg_qbytes);
-			err2 |= __put_user (m.msg_lspid, &up->msg_lspid);
-			err2 |= __put_user (m.msg_lrpid, &up->msg_lrpid);
-			if (err2)
-				err = -EFAULT;
-		}
-	} else {
-		struct msqid_ds m;
-		struct msqid_ds32 *up = (struct msqid_ds32 *)uptr;
-		mm_segment_t old_fs;
-
-		if (second == IPC_SET) {
-			err = get_user (m.msg_perm.uid, &up->msg_perm.uid);
-			err |= __get_user (m.msg_perm.gid, &up->msg_perm.gid);
-			err |= __get_user (m.msg_perm.mode, &up->msg_perm.mode);
-			err |= __get_user (m.msg_qbytes, &up->msg_qbytes);
-			if (err)
-				goto out;
-		}
-		old_fs = get_fs ();
-		set_fs (KERNEL_DS);
-		err = sys_msgctl (first, second, &m);
-		set_fs (old_fs);
-		if (IPCOP_MASK (second) &
-		    (IPCOP_MASK (MSG_STAT) | IPCOP_MASK (IPC_STAT))) {
-			int err2 = put_user (m.msg_perm.key, &up->msg_perm.key);
-			err2 |= __put_user (high2lowuid(m.msg_perm.uid), &up->msg_perm.uid);
-			err2 |= __put_user (high2lowgid(m.msg_perm.gid), &up->msg_perm.gid);
-			err2 |= __put_user (high2lowuid(m.msg_perm.cuid), &up->msg_perm.cuid);
-			err2 |= __put_user (high2lowgid(m.msg_perm.cgid), &up->msg_perm.cgid);
-			err2 |= __put_user (m.msg_perm.mode, &up->msg_perm.mode);
-			err2 |= __put_user (m.msg_perm.seq, &up->msg_perm.seq);
-			err2 |= __put_user (m.msg_stime, &up->msg_stime);
-			err2 |= __put_user (m.msg_rtime, &up->msg_rtime);
-			err2 |= __put_user (m.msg_ctime, &up->msg_ctime);
-			err2 |= __put_user (m.msg_cbytes, &up->msg_cbytes);
-			err2 |= __put_user (m.msg_qnum, &up->msg_qnum);
-			err2 |= __put_user (m.msg_qbytes, &up->msg_qbytes);
-			err2 |= __put_user (m.msg_lspid, &up->msg_lspid);
-			err2 |= __put_user (m.msg_lrpid, &up->msg_lrpid);
-			if (err2)
-				err = -EFAULT;
-		}
-	}
-
-out:
-	return err;
-}
-
-static int do_sys32_shmat (int first, int second, int third, int version, void *uptr)
-{
-	unsigned long raddr;
-	u32 *uaddr = (u32 *)A((u32)third);
-	int err = -EINVAL;
-
-	if (version == 1)
-		goto out;
-	err = do_shmat (first, uptr, second, &raddr);
-	if (err)
-		goto out;
-	err = put_user (raddr, uaddr);
-out:
-	return err;
-}
-
-static int do_sys32_shmctl (int first, int second, void *uptr)
-{
-	int err;
-
-	if (IPCOP_MASK (second) &
-	    (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (SHM_LOCK) | IPCOP_MASK (SHM_UNLOCK) |
-	     IPCOP_MASK (IPC_RMID))) {
-		if (second == (IPC_INFO|IPC_64))
-			second = IPC_INFO; /* So that we don't have to translate it */
-		err = sys_shmctl (first, second, (struct shmid_ds *)uptr);
-	} else if ((second & IPC_64) && second != (SHM_INFO|IPC_64)) {
-		struct shmid64_ds s;
-		struct shmid64_ds32 *up = (struct shmid64_ds32 *)uptr;
-		mm_segment_t old_fs;
-
-		if (second == (IPC_SET|IPC_64)) {
-			err = get_user (s.shm_perm.uid, &up->shm_perm.uid);
-			err |= __get_user (s.shm_perm.gid, &up->shm_perm.gid);
-			err |= __get_user (s.shm_perm.mode, &up->shm_perm.mode);
-			if (err)
-				goto out;
-		}
-		old_fs = get_fs ();
-		set_fs (KERNEL_DS);
-		err = sys_shmctl (first, second, (struct shmid_ds *)&s);
-		set_fs (old_fs);
-		if (err < 0)
-			goto out;
-
-		/* Mask it even in this case so it becomes a CSE. */
-		if (IPCOP_MASK (second) &
-		    (IPCOP_MASK (SHM_STAT) | IPCOP_MASK (IPC_STAT))) {
-			int err2 = put_user (s.shm_perm.key, &up->shm_perm.key);
-			err2 |= __put_user (high2lowuid(s.shm_perm.uid), &up->shm_perm.uid);
-			err2 |= __put_user (high2lowgid(s.shm_perm.gid), &up->shm_perm.gid);
-			err2 |= __put_user (high2lowuid(s.shm_perm.cuid), &up->shm_perm.cuid);
-			err2 |= __put_user (high2lowgid(s.shm_perm.cgid), &up->shm_perm.cgid);
-			err2 |= __put_user (s.shm_perm.mode, &up->shm_perm.mode);
-			err2 |= __put_user (s.shm_perm.seq, &up->shm_perm.seq);
-			err2 |= __put_user (s.shm_atime, &up->shm_atime);
-			err2 |= __put_user (s.shm_dtime, &up->shm_dtime);
-			err2 |= __put_user (s.shm_ctime, &up->shm_ctime);
-			err2 |= __put_user (s.shm_segsz, &up->shm_segsz);
-			err2 |= __put_user (s.shm_nattch, &up->shm_nattch);
-			err2 |= __put_user (s.shm_cpid, &up->shm_cpid);
-			err2 |= __put_user (s.shm_lpid, &up->shm_lpid);
-			if (err2)
-				err = -EFAULT;
-		}
-	} else {
-		struct shmid_ds s;
-		struct shmid_ds32 *up = (struct shmid_ds32 *)uptr;
-		mm_segment_t old_fs;
-
-		second &= ~IPC_64;
-		if (second == IPC_SET) {
-			err = get_user (s.shm_perm.uid, &up->shm_perm.uid);
-			err |= __get_user (s.shm_perm.gid, &up->shm_perm.gid);
-			err |= __get_user (s.shm_perm.mode, &up->shm_perm.mode);
-			if (err)
-				goto out;
-		}
-		old_fs = get_fs ();
-		set_fs (KERNEL_DS);
-		err = sys_shmctl (first, second, &s);
-		set_fs (old_fs);
-		if (err < 0)
-			goto out;
-
-		/* Mask it even in this case so it becomes a CSE. */
-		if (second == SHM_INFO) {
-			struct shm_info32 {
-				int used_ids;
-				u32 shm_tot, shm_rss, shm_swp;
-				u32 swap_attempts, swap_successes;
-			} *uip = (struct shm_info32 *)uptr;
-			struct shm_info *kp = (struct shm_info *)&s;
-			int err2 = put_user (kp->used_ids, &uip->used_ids);
-			err2 |= __put_user (kp->shm_tot, &uip->shm_tot);
-			err2 |= __put_user (kp->shm_rss, &uip->shm_rss);
-			err2 |= __put_user (kp->shm_swp, &uip->shm_swp);
-			err2 |= __put_user (kp->swap_attempts, &uip->swap_attempts);
-			err2 |= __put_user (kp->swap_successes, &uip->swap_successes);
-			if (err2)
-				err = -EFAULT;
-		} else if (IPCOP_MASK (second) &
-			   (IPCOP_MASK (SHM_STAT) | IPCOP_MASK (IPC_STAT))) {
-			int err2 = put_user (s.shm_perm.key, &up->shm_perm.key);
-			err2 |= __put_user (high2lowuid(s.shm_perm.uid), &up->shm_perm.uid);
-			err2 |= __put_user (high2lowgid(s.shm_perm.gid), &up->shm_perm.gid);
-			err2 |= __put_user (high2lowuid(s.shm_perm.cuid), &up->shm_perm.cuid);
-			err2 |= __put_user (high2lowgid(s.shm_perm.cgid), &up->shm_perm.cgid);
-			err2 |= __put_user (s.shm_perm.mode, &up->shm_perm.mode);
-			err2 |= __put_user (s.shm_perm.seq, &up->shm_perm.seq);
-			err2 |= __put_user (s.shm_atime, &up->shm_atime);
-			err2 |= __put_user (s.shm_dtime, &up->shm_dtime);
-			err2 |= __put_user (s.shm_ctime, &up->shm_ctime);
-			err2 |= __put_user (s.shm_segsz, &up->shm_segsz);
-			err2 |= __put_user (s.shm_nattch, &up->shm_nattch);
-			err2 |= __put_user (s.shm_cpid, &up->shm_cpid);
-			err2 |= __put_user (s.shm_lpid, &up->shm_lpid);
-			if (err2)
-				err = -EFAULT;
-		}
-	}
-out:
-	return err;
-}
-
 /*
  * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation.
  *
@@ -835,84 +300,64 @@ out:
  */
 asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr)
 {
-	int version, err;
+	if(call >> 16) /* hack for backward compatibility */
+		return -EINVAL;
 
-	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
 
-	if(version)
-		return -EINVAL;
-
 	if (call <= SEMTIMEDOP)
 		switch (call) {
 		case SEMTIMEDOP:
-			if (third) {
-				err = do_sys32_semtimedop(first,
-					(struct sembuf *)AA(ptr),
-					second,
-					(struct compat_timespec *)
-						AA((u32)third));
-				goto out;
-			}
+			if (third)
+				return compat_sys_semtimedop(first,
+						compat_ptr(ptr), second,
+						compat_ptr(third));
 			/* else fall through for normal semop() */
 		case SEMOP:
 			/* struct sembuf is the same on 32 and 64bit :)) */
-			err = sys_semtimedop (first, (struct sembuf *)AA(ptr),
+			return sys_semtimedop (first, compat_ptr(ptr),
 					      second, NULL);
-			goto out;
 		case SEMGET:
-			err = sys_semget (first, second, third);
-			goto out;
+			return sys_semget (first, second, third);
 		case SEMCTL:
-			err = do_sys32_semctl (first, second, third, (void *)AA(ptr));
-			goto out;
+			return compat_sys_semctl (first, second, third,
+						 compat_ptr(ptr));
 		default:
-			err = -EINVAL;
-			goto out;
+			return -EINVAL;
 		};
 	if (call <= MSGCTL) 
 		switch (call) {
 		case MSGSND:
-			err = do_sys32_msgsnd (first, second, third, (void *)AA(ptr));
-			goto out;
+			return compat_sys_msgsnd (first, second, third,
+						compat_ptr(ptr));
 		case MSGRCV:
-			err = do_sys32_msgrcv (first, second, 0, third,
-					       version, (void *)AA(ptr));
-			goto out;
+			return compat_sys_msgrcv (first, second, 0, third,
+					       0, compat_ptr(ptr));
 		case MSGGET:
-			err = sys_msgget ((key_t) first, second);
-			goto out;
+			return sys_msgget ((key_t) first, second);
 		case MSGCTL:
-			err = do_sys32_msgctl (first, second, (void *)AA(ptr));
-			goto out;
+			return compat_sys_msgctl (first, second,
+						compat_ptr(ptr));
 		default:
-			err = -EINVAL;
-			goto out;
+			return -EINVAL;
 		}
 	if (call <= SHMCTL) 
 		switch (call) {
 		case SHMAT:
-			err = do_sys32_shmat (first, second, third,
-					      version, (void *)AA(ptr));
-			goto out;
+			return compat_sys_shmat (first, second, third,
+						0, compat_ptr(ptr));
 		case SHMDT: 
-			err = sys_shmdt ((char *)AA(ptr));
-			goto out;
+			return sys_shmdt(compat_ptr(ptr));
 		case SHMGET:
-			err = sys_shmget (first, second, third);
-			goto out;
+			return sys_shmget(first, second, third);
 		case SHMCTL:
-			err = do_sys32_shmctl (first, second, (void *)AA(ptr));
-			goto out;
+			return compat_sys_shmctl(first, second,
+						compat_ptr(ptr));
 		default:
-			err = -EINVAL;
-			goto out;
+			return -EINVAL;
 		}
 
-	err = -EINVAL;
-
-out:
-	return err;
+	return -EINVAL;
 }
 
 asmlinkage int sys32_truncate64(const char * path, unsigned long high, unsigned long low)
--- diff/arch/s390/kernel/sys_s390.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/s390/kernel/sys_s390.c	2004-03-09 11:51:48.000000000 +0000
@@ -289,11 +289,6 @@ asmlinkage int sys_olduname(struct oldol
 	return error;
 }
 
-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on)
-{
-	return -ENOSYS;
-}
-
 #else /* CONFIG_ARCH_S390X */
 
 asmlinkage int s390x_newuname(struct new_utsname * name)
--- diff/arch/s390/kernel/syscalls.S	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/s390/kernel/syscalls.S	2004-03-09 11:51:48.000000000 +0000
@@ -109,7 +109,7 @@ SYSCALL(sys_setpriority,sys_setpriority,
 NI_SYSCALL							/* old profil syscall */
 SYSCALL(sys_statfs,sys_statfs,compat_sys_statfs_wrapper)
 SYSCALL(sys_fstatfs,sys_fstatfs,compat_sys_fstatfs_wrapper)	/* 100 */
-SYSCALL(sys_ioperm,sys_ni_syscall,sys_ni_syscall)
+NI_SYSCALL							/* ioperm for i386 */
 SYSCALL(sys_socketcall,sys_socketcall,compat_sys_socketcall_wrapper)
 SYSCALL(sys_syslog,sys_syslog,sys32_syslog_wrapper)
 SYSCALL(sys_setitimer,sys_setitimer,compat_sys_setitimer_wrapper)
--- diff/arch/sparc/Kconfig	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/sparc/Kconfig	2004-03-09 11:51:48.000000000 +0000
@@ -380,11 +380,32 @@ source "drivers/char/watchdog/Kconfig"
 
 menu "Kernel hacking"
 
+config DEBUG_KERNEL
+	bool "Kernel debugging"
+	help
+	  Say Y here if you are developing drivers or trying to debug and
+	  identify kernel problems.
+
+config DEBUG_STACK_USAGE
+	bool "Enable stack utilization instrumentation"
+	depends on DEBUG_KERNEL
+	help
+	  Enables the display of the minimum amount of free stack which each
+	  task has ever had available in the sysrq-T and sysrq-P debug output.
+
+	  This option will slow down process creation somewhat.
+
 config DEBUG_SLAB
 	bool "Debug memory allocations"
+	depends on DEBUG_KERNEL
+	help
+	  Say Y here to have the kernel do limited verification on memory
+	  allocation as well as poisoning memory on free to catch use of freed
+	  memory.
 
 config MAGIC_SYSRQ
 	bool "Magic SysRq key"
+	depends on DEBUG_KERNEL
 	help
 	  If you say Y here, you will have some control over the system even
 	  if the system crashes for example during kernel debugging (e.g., you
@@ -398,22 +419,30 @@ config MAGIC_SYSRQ
 
 config DEBUG_SPINLOCK
 	bool "Spinlock debugging"
+	depends on DEBUG_KERNEL
+	help
+	  Say Y here and build SMP to catch missing spinlock initialization
+	  and certain other kinds of spinlock errors commonly made.  This is
+	  best used in conjunction with the NMI watchdog so that spinlock
+	  deadlocks are also debuggable.
 
 config DEBUG_HIGHMEM
 	bool "Highmem debugging"
 	depends on DEBUG_KERNEL && HIGHMEM
 	help
-	  This options enables addition error checking for high memory systems.
-	  Disable for production systems.
+	  This options enables additional error checking for high memory
+	  systems.  Disable for production systems.
 
 config DEBUG_SPINLOCK_SLEEP
 	bool "Sleep-inside-spinlock checking"
+	depends on DEBUG_KERNEL
 	help
 	  If you say Y here, various routines which may sleep will become very
 	  noisy if they are called with a spinlock held.	
 
 config DEBUG_BUGVERBOSE
 	bool "Verbose BUG() reporting (adds 70K)"
+	depends on DEBUG_KERNEL
 	help
 	  Say Y here to make BUG() panics output the file name and line number
 	  of the BUG call as well as the EIP and oops trace.  This aids
--- diff/arch/sparc/kernel/ioport.c	2003-09-17 12:28:03.000000000 +0100
+++ source/arch/sparc/kernel/ioport.c	2004-03-09 11:51:48.000000000 +0000
@@ -360,7 +360,7 @@ void sbus_unmap_sg(struct sbus_dev *sdev
 
 /*
  */
-void sbus_dma_sync_single(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction)
+void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction)
 {
 #if 0
 	unsigned long va;
@@ -380,9 +380,34 @@ void sbus_dma_sync_single(struct sbus_de
 #endif
 }
 
-void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
+void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction)
 {
-	printk("sbus_dma_sync_sg: not implemented yet\n");
+#if 0
+	unsigned long va;
+	struct resource *res;
+
+	/* We do not need the resource, just print a message if invalid. */
+	res = _sparc_find_resource(&_sparc_dvma, ba);
+	if (res == NULL)
+		panic("sbus_dma_sync_single: 0x%x\n", ba);
+
+	va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */
+	/*
+	 * XXX This bogosity will be fixed with the iommu rewrite coming soon
+	 * to a kernel near you. - Anton
+	 */
+	/* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */
+#endif
+}
+
+void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
+{
+	printk("sbus_dma_sync_sg_for_cpu: not implemented yet\n");
+}
+
+void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
+{
+	printk("sbus_dma_sync_sg_for_device: not implemented yet\n");
 }
 #endif /* CONFIG_SBUS */
 
@@ -482,7 +507,7 @@ void pci_free_consistent(struct pci_dev 
  * The 32-bit bus address to use is returned.
  *
  * Once the device is given the dma address, the device owns this memory
- * until either pci_unmap_single or pci_dma_sync_single is performed.
+ * until either pci_unmap_single or pci_dma_sync_single_* is performed.
  */
 dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size,
     int direction)
@@ -591,10 +616,21 @@ void pci_unmap_sg(struct pci_dev *hwdev,
  * If you perform a pci_map_single() but wish to interrogate the
  * buffer using the cpu, yet do not wish to teardown the PCI dma
  * mapping, you must call this function before doing so.  At the
- * next point you give the PCI dma address back to the card, the
+ * next point you give the PCI dma address back to the card, you
+ * must first perform a pci_dma_sync_for_device, and then the
  * device again owns the buffer.
  */
-void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction)
+void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction)
+{
+	if (direction == PCI_DMA_NONE)
+		BUG();
+	if (direction != PCI_DMA_TODEVICE) {
+		mmu_inval_dma_area((unsigned long)phys_to_virt(ba),
+		    (size + PAGE_SIZE-1) & PAGE_MASK);
+	}
+}
+
+void pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction)
 {
 	if (direction == PCI_DMA_NONE)
 		BUG();
@@ -607,10 +643,27 @@ void pci_dma_sync_single(struct pci_dev 
 /* Make physical memory consistent for a set of streaming
  * mode DMA translations after a transfer.
  *
- * The same as pci_dma_sync_single but for a scatter-gather list,
+ * The same as pci_dma_sync_single_* but for a scatter-gather list,
  * same rules and usage.
  */
-void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
+void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
+{
+	int n;
+
+	if (direction == PCI_DMA_NONE)
+		BUG();
+	if (direction != PCI_DMA_TODEVICE) {
+		for (n = 0; n < nents; n++) {
+			if (page_address(sg->page) == NULL) BUG();
+			mmu_inval_dma_area(
+			    (unsigned long) page_address(sg->page),
+			    (sg->length + PAGE_SIZE-1) & PAGE_MASK);
+			sg++;
+		}
+	}
+}
+
+void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
 {
 	int n;
 
--- diff/arch/sparc/kernel/process.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/sparc/kernel/process.c	2004-03-09 11:51:48.000000000 +0000
@@ -9,7 +9,6 @@
  * This file handles the architecture-dependent parts of process handling..
  */
 
-#define __KERNEL_SYSCALLS__
 #include <stdarg.h>
 
 #include <linux/errno.h>
@@ -19,7 +18,6 @@
 #include <linux/kallsyms.h>
 #include <linux/mm.h>
 #include <linux/stddef.h>
-#include <linux/unistd.h>
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
--- diff/arch/sparc/kernel/setup.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/sparc/kernel/setup.c	2004-03-09 11:51:48.000000000 +0000
@@ -389,11 +389,6 @@ static int __init set_preferred_console(
 }
 console_initcall(set_preferred_console);
 
-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on)
-{
-	return -EIO;
-}
-
 extern char *sparc_cpu_type[];
 extern char *sparc_fpu_type[];
 
--- diff/arch/sparc/kernel/smp.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/sparc/kernel/smp.c	2004-03-09 11:51:48.000000000 +0000
@@ -33,9 +33,6 @@
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
-#define __KERNEL_SYSCALLS__
-#include <linux/unistd.h>
-
 #define IRQ_RESCHEDULE		13
 #define IRQ_STOP_CPU		14
 #define IRQ_CROSS_CALL		15
--- diff/arch/sparc/kernel/sparc_ksyms.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/sparc/kernel/sparc_ksyms.c	2004-03-09 11:51:48.000000000 +0000
@@ -157,7 +157,6 @@ EXPORT_SYMBOL(___change_bit);
 
 #ifdef CONFIG_SMP
 /* IRQ implementation. */
-EXPORT_SYMBOL(global_irq_holder);
 EXPORT_SYMBOL(synchronize_irq);
 
 /* Misc SMP information */
@@ -206,8 +205,10 @@ EXPORT_SYMBOL(sbus_map_single);
 EXPORT_SYMBOL(sbus_unmap_single);
 EXPORT_SYMBOL(sbus_map_sg);
 EXPORT_SYMBOL(sbus_unmap_sg);
-EXPORT_SYMBOL(sbus_dma_sync_single);
-EXPORT_SYMBOL(sbus_dma_sync_sg);
+EXPORT_SYMBOL(sbus_dma_sync_single_for_cpu);
+EXPORT_SYMBOL(sbus_dma_sync_single_for_device);
+EXPORT_SYMBOL(sbus_dma_sync_sg_for_cpu);
+EXPORT_SYMBOL(sbus_dma_sync_sg_for_device);
 EXPORT_SYMBOL(sbus_iounmap);
 EXPORT_SYMBOL(sbus_ioremap);
 #endif
@@ -219,7 +220,10 @@ EXPORT_SYMBOL(pci_alloc_consistent);
 EXPORT_SYMBOL(pci_free_consistent);
 EXPORT_SYMBOL(pci_map_single);
 EXPORT_SYMBOL(pci_unmap_single);
-EXPORT_SYMBOL(pci_dma_sync_single);
+EXPORT_SYMBOL(pci_dma_sync_single_for_cpu);
+EXPORT_SYMBOL(pci_dma_sync_single_for_device);
+EXPORT_SYMBOL(pci_dma_sync_sg_for_cpu);
+EXPORT_SYMBOL(pci_dma_sync_sg_for_device);
 /* Actually, ioremap/iounmap are not PCI specific. But it is ok for drivers. */
 EXPORT_SYMBOL(ioremap);
 EXPORT_SYMBOL(iounmap);
--- diff/arch/sparc/kernel/sun4d_smp.c	2003-09-30 15:46:12.000000000 +0100
+++ source/arch/sparc/kernel/sun4d_smp.c	2004-03-09 11:51:48.000000000 +0000
@@ -32,9 +32,6 @@
 #include <asm/sbus.h>
 #include <asm/sbi.h>
 
-#define __KERNEL_SYSCALLS__
-#include <linux/unistd.h>
-
 #define IRQ_CROSS_CALL		15
 
 extern ctxd_t *srmmu_ctx_table_phys;
--- diff/arch/sparc/kernel/sun4m_smp.c	2003-05-21 11:50:00.000000000 +0100
+++ source/arch/sparc/kernel/sun4m_smp.c	2004-03-09 11:51:48.000000000 +0000
@@ -27,9 +27,6 @@
 #include <asm/oplib.h>
 #include <asm/hardirq.h>
 
-#define __KERNEL_SYSCALLS__
-#include <linux/unistd.h>
-
 #define IRQ_RESCHEDULE		13
 #define IRQ_STOP_CPU		14
 #define IRQ_CROSS_CALL		15
--- diff/arch/sparc/kernel/trampoline.S	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/sparc/kernel/trampoline.S	2004-03-09 11:51:48.000000000 +0000
@@ -13,6 +13,7 @@
 #include <asm/ptrace.h>
 #include <asm/vaddrs.h>
 #include <asm/contregs.h>
+#include <asm/thread_info.h>
 
 	.globl sun4m_cpu_startup, __smp4m_processor_id
 	.globl sun4d_cpu_startup, __smp4d_processor_id
--- diff/arch/sparc/mm/nosun4c.c	2002-10-16 04:29:07.000000000 +0100
+++ source/arch/sparc/mm/nosun4c.c	2004-03-09 11:51:48.000000000 +0000
@@ -57,6 +57,11 @@ pte_t *sun4c_pte_offset(pmd_t * dir, uns
 	return NULL;
 }
 
+pte_t *sun4c_pte_offset_kernel(pmd_t *dir, unsigned long address)
+{
+	return NULL;
+}
+
 void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 {
 }
--- diff/arch/sparc/mm/srmmu.c	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/sparc/mm/srmmu.c	2004-03-09 11:51:48.000000000 +0000
@@ -627,8 +627,15 @@ static void srmmu_unmapiorange(unsigned 
  */
 struct thread_info *srmmu_alloc_thread_info(void)
 {
-	return (struct thread_info *)
-	    __get_free_pages(GFP_KERNEL, THREAD_INFO_ORDER);
+	struct thread_info *ret;
+
+	ret = (struct thread_info *)__get_free_pages(GFP_KERNEL,
+						     THREAD_INFO_ORDER);
+#ifdef CONFIG_DEBUG_STACK_USAGE
+	memset(ret, 0, PAGE_SIZE << THREAD_INFO_ORDER);
+#endif /* DEBUG_STACK_USAGE */
+
+	return ret;
 }
 
 static void srmmu_free_thread_info(struct thread_info *ti)
--- diff/arch/sparc/mm/sun4c.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/sparc/mm/sun4c.c	2004-03-09 11:51:48.000000000 +0000
@@ -1058,6 +1058,11 @@ static struct thread_info *sun4c_alloc_t
 #ifndef CONFIG_SUN4	
 	sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE));
 #endif
+
+#ifdef CONFIG_DEBUG_STACK_USAGE
+	memset((void *)addr, 0, PAGE_SIZE << THREAD_INFO_ORDER);
+#endif /* DEBUG_STACK_USAGE */
+
 	return (struct thread_info *) addr;
 }
 
--- diff/arch/sparc64/Kconfig	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/sparc64/Kconfig	2004-03-09 11:51:48.000000000 +0000
@@ -687,12 +687,19 @@ config DEBUG_BOOTMEM
 	depends on DEBUG_KERNEL
 	bool "Debug BOOTMEM initialization"
 
+config LOCKMETER
+	bool "Kernel lock metering"
+	depends on SMP && !PREEMPT
+	help
+	  Say Y to enable kernel lock metering, which adds overhead to SMP locks,
+	  but allows you to see various statistics using the lockstat command.
+
 # We have a custom atomic_dec_and_lock() implementation but it's not
 # compatible with spinlock debugging so we need to fall back on
 # the generic version in that case.
 config HAVE_DEC_LOCK
 	bool
-	depends on SMP && !DEBUG_SPINLOCK
+	depends on SMP && !DEBUG_SPINLOCK && !LOCKMETER
 	default y
 
 config MCOUNT
--- diff/arch/sparc64/defconfig	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/sparc64/defconfig	2004-03-09 11:51:49.000000000 +0000
@@ -100,19 +100,19 @@ CONFIG_PARPORT_1284=y
 CONFIG_PRINTER=m
 CONFIG_ENVCTRL=m
 CONFIG_DISPLAY7SEG=m
-CONFIG_WATCHDOG_CP1XXX=m
-CONFIG_WATCHDOG_RIO=m
 # CONFIG_CMDLINE_BOOL is not set
 
 #
 # Generic Driver Options
 #
 CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Graphics support
 #
 CONFIG_FB=y
+# CONFIG_FB_PM2 is not set
 # CONFIG_FB_CYBER2000 is not set
 # CONFIG_FB_IMSTT is not set
 # CONFIG_FB_BW2 is not set
@@ -211,7 +211,6 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
-CONFIG_DCSSBLK=m
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -407,6 +406,8 @@ CONFIG_IEEE1394=m
 #
 # CONFIG_IEEE1394_VERBOSEDEBUG is not set
 CONFIG_IEEE1394_OUI_DB=y
+CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
+CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
 
 #
 # Device Drivers
@@ -1638,6 +1639,8 @@ CONFIG_WATCHDOG=y
 # Watchdog Device Drivers
 #
 CONFIG_SOFT_WATCHDOG=m
+CONFIG_WATCHDOG_CP1XXX=m
+CONFIG_WATCHDOG_RIO=m
 
 #
 # PCI-based Watchdog Cards
@@ -1647,6 +1650,11 @@ CONFIG_WDTPCI=m
 CONFIG_WDT_501_PCI=y
 
 #
+# USB-based Watchdog Cards
+#
+CONFIG_USBPCWATCHDOG=m
+
+#
 # Profiling support
 #
 CONFIG_PROFILING=y
@@ -1691,6 +1699,7 @@ CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_AES=m
 CONFIG_CRYPTO_CAST5=m
 CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_DEFLATE=y
 CONFIG_CRYPTO_TEST=m
 
--- diff/arch/sparc64/kernel/ioctl32.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/sparc64/kernel/ioctl32.c	2004-03-09 11:51:49.000000000 +0000
@@ -1117,34 +1117,6 @@ COMPATIBLE_IOCTL(BNEPCONNADD)
 COMPATIBLE_IOCTL(BNEPCONNDEL)
 COMPATIBLE_IOCTL(BNEPGETCONNLIST)
 COMPATIBLE_IOCTL(BNEPGETCONNINFO)
-/* device-mapper */
-#if defined(CONFIG_DM_IOCTL_V4)
-COMPATIBLE_IOCTL(DM_VERSION)
-COMPATIBLE_IOCTL(DM_REMOVE_ALL)
-COMPATIBLE_IOCTL(DM_LIST_DEVICES)
-COMPATIBLE_IOCTL(DM_DEV_CREATE)
-COMPATIBLE_IOCTL(DM_DEV_REMOVE)
-COMPATIBLE_IOCTL(DM_DEV_RENAME)
-COMPATIBLE_IOCTL(DM_DEV_SUSPEND)
-COMPATIBLE_IOCTL(DM_DEV_STATUS)
-COMPATIBLE_IOCTL(DM_DEV_WAIT)
-COMPATIBLE_IOCTL(DM_TABLE_LOAD)
-COMPATIBLE_IOCTL(DM_TABLE_CLEAR)
-COMPATIBLE_IOCTL(DM_TABLE_DEPS)
-COMPATIBLE_IOCTL(DM_TABLE_STATUS)
-#else
-COMPATIBLE_IOCTL(DM_VERSION)
-COMPATIBLE_IOCTL(DM_REMOVE_ALL)
-COMPATIBLE_IOCTL(DM_DEV_CREATE)
-COMPATIBLE_IOCTL(DM_DEV_REMOVE)
-COMPATIBLE_IOCTL(DM_DEV_RELOAD)
-COMPATIBLE_IOCTL(DM_DEV_SUSPEND)
-COMPATIBLE_IOCTL(DM_DEV_RENAME)
-COMPATIBLE_IOCTL(DM_DEV_DEPS)
-COMPATIBLE_IOCTL(DM_DEV_STATUS)
-COMPATIBLE_IOCTL(DM_TARGET_STATUS)
-COMPATIBLE_IOCTL(DM_TARGET_WAIT)
-#endif
 /* And these ioctls need translation */
 /* NCPFS */
 HANDLE_IOCTL(NCP_IOC_NCPREQUEST_32, do_ncp_ncprequest)
--- diff/arch/sparc64/kernel/pci_iommu.c	2003-08-20 14:16:26.000000000 +0100
+++ source/arch/sparc64/kernel/pci_iommu.c	2004-03-09 11:51:49.000000000 +0000
@@ -661,7 +661,7 @@ void pci_unmap_sg(struct pci_dev *pdev, 
 /* Make physical memory consistent for a single
  * streaming mode DMA translation after a transfer.
  */
-void pci_dma_sync_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
+void pci_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
 {
 	struct pcidev_cookie *pcp;
 	struct pci_iommu *iommu;
@@ -722,7 +722,7 @@ void pci_dma_sync_single(struct pci_dev 
 /* Make physical memory consistent for a set of streaming
  * mode DMA translations after a transfer.
  */
-void pci_dma_sync_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
+void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
 {
 	struct pcidev_cookie *pcp;
 	struct pci_iommu *iommu;
--- diff/arch/sparc64/kernel/process.c	2003-10-09 09:47:33.000000000 +0100
+++ source/arch/sparc64/kernel/process.c	2004-03-09 11:51:49.000000000 +0000
@@ -10,7 +10,6 @@
  * This file handles the architecture-dependent parts of process handling..
  */
 
-#define __KERNEL_SYSCALLS__
 #include <stdarg.h>
 
 #include <linux/errno.h>
@@ -22,7 +21,6 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/stddef.h>
-#include <linux/unistd.h>
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
--- diff/arch/sparc64/kernel/sbus.c	2003-05-21 11:50:14.000000000 +0100
+++ source/arch/sparc64/kernel/sbus.c	2004-03-09 11:51:49.000000000 +0000
@@ -540,7 +540,7 @@ void sbus_unmap_sg(struct sbus_dev *sdev
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-void sbus_dma_sync_single(struct sbus_dev *sdev, dma_addr_t base, size_t size, int direction)
+void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t base, size_t size, int direction)
 {
 	struct sbus_iommu *iommu = sdev->bus->iommu;
 	unsigned long flags;
@@ -552,7 +552,11 @@ void sbus_dma_sync_single(struct sbus_de
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction)
+void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t base, size_t size, int direction)
+{
+}
+
+void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction)
 {
 	struct sbus_iommu *iommu = sdev->bus->iommu;
 	unsigned long flags, size;
@@ -572,6 +576,10 @@ void sbus_dma_sync_sg(struct sbus_dev *s
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
+void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction)
+{
+}
+
 /* Enable 64-bit DVMA mode for the given device. */
 void sbus_set_sbus64(struct sbus_dev *sdev, int bursts)
 {
--- diff/arch/sparc64/kernel/setup.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/sparc64/kernel/setup.c	2004-03-09 11:51:49.000000000 +0000
@@ -603,11 +603,6 @@ static int __init set_preferred_console(
 }
 console_initcall(set_preferred_console);
 
-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on)
-{
-	return -EIO;
-}
-
 /* BUFFER is PAGE_SIZE bytes long. */
 
 extern char *sparc_cpu_type;
--- diff/arch/sparc64/kernel/smp.c	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/sparc64/kernel/smp.c	2004-03-09 11:51:49.000000000 +0000
@@ -36,9 +36,6 @@
 #include <asm/timer.h>
 #include <asm/starfire.h>
 
-#define __KERNEL_SYSCALLS__
-#include <linux/unistd.h>
-
 extern int linux_num_cpus;
 extern void calibrate_delay(void);
 
@@ -46,7 +43,6 @@ extern void calibrate_delay(void);
 static unsigned char boot_cpu_id;
 
 cpumask_t cpu_online_map = CPU_MASK_NONE;
-atomic_t sparc64_num_cpus_possible = ATOMIC_INIT(0);
 cpumask_t phys_cpu_present_map = CPU_MASK_NONE;
 static cpumask_t smp_commenced_mask;
 static cpumask_t cpu_callout_map;
@@ -1236,20 +1232,17 @@ void __init smp_prepare_cpus(unsigned in
 
 	instance = 0;
 	while (!cpu_find_by_instance(instance, NULL, &mid)) {
-		if (mid < max_cpus) {
+		if (mid < max_cpus)
 			cpu_set(mid, phys_cpu_present_map);
-			atomic_inc(&sparc64_num_cpus_possible);
-		}
 		instance++;
 	}
 
-	if (atomic_read(&sparc64_num_cpus_possible) > max_cpus) {
+	if (num_possible_cpus() > max_cpus) {
 		instance = 0;
 		while (!cpu_find_by_instance(instance, NULL, &mid)) {
 			if (mid != boot_cpu_id) {
 				cpu_clear(mid, phys_cpu_present_map);
-				atomic_dec(&sparc64_num_cpus_possible);
-				if (atomic_read(&sparc64_num_cpus_possible) <= max_cpus)
+				if (num_possible_cpus() <= max_cpus)
 					break;
 			}
 			instance++;
--- diff/arch/sparc64/kernel/sparc64_ksyms.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/sparc64/kernel/sparc64_ksyms.c	2004-03-09 11:51:49.000000000 +0000
@@ -145,7 +145,6 @@ EXPORT_SYMBOL_NOVERS(mcount);
 /* CPU online map and active count.  */
 EXPORT_SYMBOL(cpu_online_map);
 EXPORT_SYMBOL(phys_cpu_present_map);
-EXPORT_SYMBOL(sparc64_num_cpus_possible);
 
 /* Spinlock debugging library, optional. */
 #ifdef CONFIG_DEBUG_SPINLOCK
@@ -214,8 +213,8 @@ EXPORT_SYMBOL(sbus_map_single);
 EXPORT_SYMBOL(sbus_unmap_single);
 EXPORT_SYMBOL(sbus_map_sg);
 EXPORT_SYMBOL(sbus_unmap_sg);
-EXPORT_SYMBOL(sbus_dma_sync_single);
-EXPORT_SYMBOL(sbus_dma_sync_sg);
+EXPORT_SYMBOL(sbus_dma_sync_single_for_cpu);
+EXPORT_SYMBOL(sbus_dma_sync_sg_for_cpu);
 #endif
 EXPORT_SYMBOL(outsb);
 EXPORT_SYMBOL(outsw);
@@ -233,8 +232,8 @@ EXPORT_SYMBOL(pci_map_single);
 EXPORT_SYMBOL(pci_unmap_single);
 EXPORT_SYMBOL(pci_map_sg);
 EXPORT_SYMBOL(pci_unmap_sg);
-EXPORT_SYMBOL(pci_dma_sync_single);
-EXPORT_SYMBOL(pci_dma_sync_sg);
+EXPORT_SYMBOL(pci_dma_sync_single_for_cpu);
+EXPORT_SYMBOL(pci_dma_sync_sg_for_cpu);
 EXPORT_SYMBOL(pci_dma_supported);
 #endif
 
--- diff/arch/sparc64/kernel/sys_sparc32.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/sparc64/kernel/sys_sparc32.c	2004-03-09 11:51:49.000000000 +0000
@@ -282,11 +282,6 @@ static inline long put_tv32(struct compa
 		 __put_user(i->tv_usec, &o->tv_usec)));
 }
 
-asmlinkage long sys32_ioperm(u32 from, u32 num, int on)
-{
-	return sys_ioperm((unsigned long)from, (unsigned long)num, on);
-}
-
 struct msgbuf32 { s32 mtype; char mtext[1]; };
 
 struct ipc_perm32
--- diff/arch/sparc64/lib/rwlock.S	2003-11-25 15:24:57.000000000 +0000
+++ source/arch/sparc64/lib/rwlock.S	2004-03-09 11:51:49.000000000 +0000
@@ -85,5 +85,20 @@ __write_trylock_succeed:
 __write_trylock_fail:
 	retl
 	 mov		0, %o0
+
+	.globl	__read_trylock
+__read_trylock: /* %o0 = lock_ptr */
+	ldsw		[%o0], %g5
+	brlz,pn		%g5, 100f
+	add		%g5, 1, %g7
+	cas		[%o0], %g5, %g7
+	cmp		%g5, %g7
+	bne,pn		%icc, __read_trylock
+	 membar		#StoreLoad | #StoreStore
+	retl
+	mov		1, %o0
+100:	retl
+	mov		0, %o0
+
 rwlock_impl_end:
 
--- diff/arch/v850/kernel/rte_mb_a_pci.c	2003-08-20 14:16:26.000000000 +0100
+++ source/arch/v850/kernel/rte_mb_a_pci.c	2004-03-09 11:51:49.000000000 +0000
@@ -687,10 +687,11 @@ void pci_unmap_single (struct pci_dev *p
    If you perform a pci_map_single() but wish to interrogate the
    buffer using the cpu, yet do not wish to teardown the PCI dma
    mapping, you must call this function before doing so.  At the next
-   point you give the PCI dma address back to the card, the device
-   again owns the buffer.  */
+   point you give the PCI dma address back to the card, you must first
+   perform a pci_dma_sync_for_device, and then the device again owns
+   the buffer.  */
 void
-pci_dma_sync_single (struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
+pci_dma_sync_single_for_cpu (struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
 		     int dir)
 {
 	void *mb_sram_addr = PCI_TO_MB_SRAM (dma_addr);
@@ -700,6 +701,22 @@ pci_dma_sync_single (struct pci_dev *pde
 	if (dir == PCI_DMA_FROMDEVICE)
 		memcpy (mapping->cpu_addr, mb_sram_addr, size);
 	else if (dir == PCI_DMA_TODEVICE)
+		; /* nothing to do */
+	else
+		panic("pci_dma_sync_single: unsupported sync dir: %d", dir);
+}
+
+void
+pci_dma_sync_single_for_device (struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
+				int dir)
+{
+	void *mb_sram_addr = PCI_TO_MB_SRAM (dma_addr);
+	struct dma_mapping *mapping = find_dma_mapping (mb_sram_addr);
+
+	/* Synchronize the DMA buffer with the CPU buffer if necessary.  */
+	if (dir == PCI_DMA_FROMDEVICE)
+		; /* nothing to do */
+	else if (dir == PCI_DMA_TODEVICE)
 		memcpy (mb_sram_addr, mapping->cpu_addr, size);
 	else
 		panic("pci_dma_sync_single: unsupported sync dir: %d", dir);
@@ -724,11 +741,18 @@ pci_unmap_sg (struct pci_dev *pdev, stru
 }
 
 /* Make physical memory consistent for a set of streaming mode DMA
-   translations after a transfer.  The same as pci_dma_sync_single but
+   translations after a transfer.  The same as pci_dma_sync_single_* but
    for a scatter-gather list, same rules and usage.  */
 
 void
-pci_dma_sync_sg (struct pci_dev *dev, struct scatterlist *sg, int sg_len,
+pci_dma_sync_sg_for_cpu (struct pci_dev *dev, struct scatterlist *sg, int sg_len,
+		 int dir)
+{
+	BUG ();
+}
+
+void
+pci_dma_sync_sg_for_device (struct pci_dev *dev, struct scatterlist *sg, int sg_len,
 		 int dir)
 {
 	BUG ();
@@ -770,4 +794,5 @@ EXPORT_SYMBOL (pci_map_single);
 EXPORT_SYMBOL (pci_unmap_single);
 EXPORT_SYMBOL (pci_alloc_consistent);
 EXPORT_SYMBOL (pci_free_consistent);
-EXPORT_SYMBOL (pci_dma_sync_single);
+EXPORT_SYMBOL (pci_dma_sync_single_for_cpu);
+EXPORT_SYMBOL (pci_dma_sync_single_for_device);
--- diff/arch/x86_64/Kconfig	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/x86_64/Kconfig	2004-03-09 11:51:49.000000000 +0000
@@ -381,6 +381,10 @@ config COMPAT
 	depends on IA32_EMULATION
 	default y
 
+config SYSVIPC_COMPAT
+	bool
+	depends on COMPAT && SYSVIPC
+	default y
 
 config UID16
 	bool
@@ -452,6 +456,7 @@ config INIT_DEBUG
 config DEBUG_INFO
 	bool "Compile the kernel with debug info"
 	depends on DEBUG_KERNEL
+	default n
 	help
           If you say Y here the resulting kernel image will include
 	  debugging info resulting in a larger kernel image.
@@ -483,9 +488,8 @@ config IOMMU_LEAK
        help
          Add a simple leak tracer to the IOMMU code. This is useful when you
 	 are debugging a buggy device driver that leaks IOMMU mappings.
-       
-#config X86_REMOTE_DEBUG
-#       bool "kgdb debugging stub"
+
+source "arch/x86_64/Kconfig.kgdb"
 
 endmenu
 
--- diff/arch/x86_64/ia32/ia32entry.S	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/x86_64/ia32/ia32entry.S	2004-03-09 11:51:49.000000000 +0000
@@ -467,7 +467,7 @@ ia32_sys_call_table:
 	.quad sys_epoll_create
 	.quad sys_epoll_ctl
 	.quad sys_epoll_wait
-	.quad sys_remap_file_pages
+	.quad old_remap_file_pages
 	.quad sys_set_tid_address
 	.quad sys32_timer_create
 	.quad compat_timer_settime
--- diff/arch/x86_64/ia32/ipc32.c	2004-03-04 11:41:45.000000000 +0000
+++ source/arch/x86_64/ia32/ipc32.c	2004-03-09 11:51:49.000000000 +0000
@@ -1,656 +1,19 @@
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/fs.h> 
-#include <linux/file.h> 
+#include <linux/spinlock.h>
+#include <linux/list.h>
 #include <linux/syscalls.h>
+#include <linux/time.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
-#include <linux/mm.h>
 #include <linux/shm.h>
-#include <linux/slab.h>
 #include <linux/ipc.h>
 #include <linux/compat.h>
-#include <asm/mman.h>
-#include <asm/types.h>
-#include <asm/uaccess.h>
-#include <asm/semaphore.h>
-#include <asm/ipc.h>
-
-#include <asm/ia32.h>
-
-/*
- * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation..
- *
- * This is really horribly ugly.
- */
-
-struct msgbuf32 { 
-	s32 mtype; 
-	char mtext[1]; 
-};
-
-struct ipc_perm32 {
-	int key;
-	compat_uid_t uid;
-	compat_gid_t gid;
-	compat_uid_t cuid;
-	compat_gid_t cgid;
-	unsigned short mode;
-	unsigned short seq;
-};
-
-struct ipc64_perm32 {
-        unsigned key;
-	compat_uid32_t uid;
-	compat_gid32_t gid;
-	compat_uid32_t cuid;
-	compat_gid32_t cgid;
-	unsigned short mode;
-	unsigned short __pad1;
-	unsigned short seq;
-	unsigned short __pad2;
-	unsigned int unused1;
-	unsigned int unused2;
-};
-
-struct semid_ds32 {
-	struct ipc_perm32 sem_perm;               /* permissions .. see ipc.h */
-	compat_time_t sem_otime;              /* last semop time */
-	compat_time_t sem_ctime;              /* last change time */
-	u32 sem_base;              /* ptr to first semaphore in array */
-	u32 sem_pending;          /* pending operations to be processed */
-	u32 sem_pending_last;    /* last pending operation */
-	u32 undo;                  /* undo requests on this array */
-	unsigned short  sem_nsems;              /* no. of semaphores in array */
-};
-
-struct semid64_ds32 {
-	struct ipc64_perm32 sem_perm;
-	compat_time_t sem_otime;
-	unsigned int __unused1;
-	compat_time_t sem_ctime;
-	unsigned int __unused2;
-	unsigned int sem_nsems;
-	unsigned int __unused3;
-	unsigned int __unused4;
-};
-
-struct msqid_ds32 {
-	struct ipc_perm32 msg_perm;
-	u32 msg_first;
-	u32 msg_last;
-	compat_time_t msg_stime;
-	compat_time_t msg_rtime;
-	compat_time_t msg_ctime;
-	u32 wwait;
-	u32 rwait;
-	unsigned short msg_cbytes;
-	unsigned short msg_qnum;
-	unsigned short msg_qbytes;
-	compat_ipc_pid_t msg_lspid;
-	compat_ipc_pid_t msg_lrpid;
-};
-
-struct msqid64_ds32 {
-	struct ipc64_perm32 msg_perm;
-	compat_time_t msg_stime;
-	unsigned int __unused1;
-	compat_time_t msg_rtime;
-	unsigned int __unused2;
-	compat_time_t msg_ctime;
-	unsigned int __unused3;
-	unsigned int msg_cbytes;
-	unsigned int msg_qnum;
-	unsigned int msg_qbytes;
-	compat_pid_t msg_lspid;
-	compat_pid_t msg_lrpid;
-	unsigned int __unused4;
-	unsigned int __unused5;
-};
-
-struct shmid_ds32 {
-	struct ipc_perm32 shm_perm;
-	int shm_segsz;
-	compat_time_t shm_atime;
-	compat_time_t shm_dtime;
-	compat_time_t shm_ctime;
-	compat_ipc_pid_t shm_cpid;
-	compat_ipc_pid_t shm_lpid;
-	unsigned short shm_nattch;
-};
-
-struct shmid64_ds32 {
-	struct ipc64_perm32 shm_perm;
-	compat_size_t shm_segsz;
-	compat_time_t shm_atime;
-	unsigned int __unused1;
-	compat_time_t shm_dtime;
-	unsigned int __unused2;
-	compat_time_t shm_ctime;
-	unsigned int __unused3;
-	compat_pid_t shm_cpid;
-	compat_pid_t shm_lpid;
-	unsigned int shm_nattch;
-	unsigned int __unused4;
-	unsigned int __unused5;
-};
-
-struct shminfo64_32 {
-	unsigned int shmmax;
-	unsigned int shmmin;
-	unsigned int shmmni;
-	unsigned int shmseg;
-	unsigned int shmall;
-	unsigned int __unused1;
-	unsigned int __unused2;
-	unsigned int __unused3;
-	unsigned int __unused4;
-};
-
-struct shm_info32 {
-	int used_ids;
-	u32 shm_tot, shm_rss, shm_swp;
-	u32 swap_attempts, swap_successes;
-};
-
-struct ipc_kludge {
-	u32 msgp;
-	s32 msgtyp;
-};
-
-
-#define A(__x)		((unsigned long)(__x))
-#define AA(__x)		((unsigned long)(__x))
-
-#define SEMOP		 1
-#define SEMGET		 2
-#define SEMCTL		 3
-#define TIMEDSEMOP	 4
-#define MSGSND		11
-#define MSGRCV		12
-#define MSGGET		13
-#define MSGCTL		14
-#define SHMAT		21
-#define SHMDT		22
-#define SHMGET		23
-#define SHMCTL		24
-
-#define IPCOP_MASK(__x)	(1UL << (__x))
-
-static int
-ipc_parse_version32 (int *cmd)
-{
-	if (*cmd & IPC_64) {
-		*cmd ^= IPC_64;
-		return IPC_64;
-	} else {
-		return IPC_OLD;
-	}
-}
-
-static int put_semid(void *user_semid, struct semid64_ds *s, int version)
-{
-	int err2;
-	switch (version) { 
-	case IPC_64: { 
-		struct semid64_ds32 *usp64 = (struct semid64_ds32 *) user_semid;
-		
-		if (!access_ok(VERIFY_WRITE, usp64, sizeof(*usp64))) {
-			err2 = -EFAULT;
-			break;
-		} 
-		err2 = __put_user(s->sem_perm.key, &usp64->sem_perm.key);
-		err2 |= __put_user(s->sem_perm.uid, &usp64->sem_perm.uid);
-		err2 |= __put_user(s->sem_perm.gid, &usp64->sem_perm.gid);
-		err2 |= __put_user(s->sem_perm.cuid, &usp64->sem_perm.cuid);
-		err2 |= __put_user(s->sem_perm.cgid, &usp64->sem_perm.cgid);
-		err2 |= __put_user(s->sem_perm.mode, &usp64->sem_perm.mode);
-		err2 |= __put_user(s->sem_perm.seq, &usp64->sem_perm.seq);
-		err2 |= __put_user(s->sem_otime, &usp64->sem_otime);
-		err2 |= __put_user(s->sem_ctime, &usp64->sem_ctime);
-		err2 |= __put_user(s->sem_nsems, &usp64->sem_nsems);
-		break;
-	}
-	default: {
-		struct semid_ds32 *usp32 = (struct semid_ds32 *) user_semid;
-		
-		if (!access_ok(VERIFY_WRITE, usp32, sizeof(*usp32))) {
-			err2 = -EFAULT;
-			break;
-		} 
-		err2 = __put_user(s->sem_perm.key, &usp32->sem_perm.key);
-		err2 |= __put_user(s->sem_perm.uid, &usp32->sem_perm.uid);
-		err2 |= __put_user(s->sem_perm.gid, &usp32->sem_perm.gid);
-		err2 |= __put_user(s->sem_perm.cuid, &usp32->sem_perm.cuid);
-		err2 |= __put_user(s->sem_perm.cgid, &usp32->sem_perm.cgid);
-		err2 |= __put_user(s->sem_perm.mode, &usp32->sem_perm.mode);
-		err2 |= __put_user(s->sem_perm.seq, &usp32->sem_perm.seq);
-		err2 |= __put_user(s->sem_otime, &usp32->sem_otime);
-		err2 |= __put_user(s->sem_ctime, &usp32->sem_ctime);
-		err2 |= __put_user(s->sem_nsems, &usp32->sem_nsems);
-		break;
-	}
-	}
-	return err2;
-}
-
-static int
-semctl32 (int first, int second, int third, void *uptr)
-{
-	union semun fourth;
-	u32 pad;
-	int err;
-	struct semid64_ds s;
-	mm_segment_t old_fs;
-	int version = ipc_parse_version32(&third);
-
-	if (!uptr)
-		return -EINVAL;
-	if (get_user(pad, (u32 *)uptr))
-		return -EFAULT;
-	if (third == SETVAL)
-		fourth.val = (int)pad;
-	else
-		fourth.__pad = (void *)A(pad);
-	switch (third) {
-	      case IPC_INFO:
-	      case IPC_RMID:
-	      case IPC_SET:
-	      case SEM_INFO:
-	      case GETVAL:
-	      case GETPID:
-	      case GETNCNT:
-	      case GETZCNT:
-	      case GETALL:
-	      case SETVAL:
-	      case SETALL:
-		err = sys_semctl(first, second, third, fourth);
-		break;
-
-	      case IPC_STAT:
-	      case SEM_STAT:
-		fourth.__pad = &s;
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		err = sys_semctl(first, second, third, fourth);
-		set_fs(old_fs);
-		if (!err)
-			err = put_semid((void *)A(pad), &s, version);
-		break;
-	default:
-		err = -EINVAL;
-		break;
-	}
-	return err;
-}
-
-#define MAXBUF (64*1024)
-
-static int
-do_sys32_msgsnd (int first, int second, int third, void *uptr)
-{
-	struct msgbuf *p;
-	struct msgbuf32 *up = (struct msgbuf32 *)uptr;
-	mm_segment_t old_fs;
-	int err;
-
-	if (second >= MAXBUF-sizeof(struct msgbuf))
-		return -EINVAL;
-	p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
-	if (!p)
-		return -ENOMEM;
-	err = get_user(p->mtype, &up->mtype);
-	err |= (copy_from_user(p->mtext, &up->mtext, second) ? -EFAULT : 0);
-	if (err)
-		goto out;
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	err = sys_msgsnd(first, p, second, third);
-	set_fs(old_fs);
-  out:
-	kfree(p);
-	return err;
-}
-
-static int
-do_sys32_msgrcv (int first, int second, int msgtyp, int third, int version, void *uptr)
-{
-	struct msgbuf32 *up;
-	struct msgbuf *p;
-	mm_segment_t old_fs;
-	int err;
-
-	if (!version) {
-		struct ipc_kludge *uipck = (struct ipc_kludge *)uptr;
-		struct ipc_kludge ipck;
-
-		err = -EINVAL;
-		if (!uptr)
-			goto out;
-		err = -EFAULT;
-		if (copy_from_user(&ipck, uipck, sizeof(struct ipc_kludge)))
-			goto out;
-		uptr = (void *)A(ipck.msgp);
-		msgtyp = ipck.msgtyp;
-	}
-	if (second >= MAXBUF-sizeof(struct msgbuf))
-		return -EINVAL; 
-	err = -ENOMEM;
-	p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
-	if (!p)
-		goto out;
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	err = sys_msgrcv(first, p, second, msgtyp, third);
-	set_fs(old_fs);
-	if (err < 0)
-		goto free_then_out;
-	up = (struct msgbuf32 *)uptr;
-	if (put_user(p->mtype, &up->mtype) || copy_to_user(&up->mtext, p->mtext, err))
-		err = -EFAULT;
-free_then_out:
-	kfree(p);
-out:
-	return err;
-}
-
-
-static int
-msgctl32 (int first, int second, void *uptr)
-{
-	int err = -EINVAL, err2;
-	struct msqid_ds m;
-	struct msqid64_ds m64;
-	struct msqid_ds32 *up32 = (struct msqid_ds32 *)uptr;
-	struct msqid64_ds32 *up64 = (struct msqid64_ds32 *)uptr;
-	mm_segment_t old_fs;
-	int version = ipc_parse_version32(&second);
-
-	switch (second) {
-	      case IPC_INFO:
-	      case IPC_RMID:
-	      case MSG_INFO:
-		err = sys_msgctl(first, second, (struct msqid_ds *)uptr);
-		break;
-
-	      case IPC_SET:
-		if (version == IPC_64) {
-			err = get_user(m.msg_perm.uid, &up64->msg_perm.uid);
-			err |= get_user(m.msg_perm.gid, &up64->msg_perm.gid);
-			err |= get_user(m.msg_perm.mode, &up64->msg_perm.mode);
-			err |= get_user(m.msg_qbytes, &up64->msg_qbytes);
-		} else {
-			err = get_user(m.msg_perm.uid, &up32->msg_perm.uid);
-			err |= get_user(m.msg_perm.gid, &up32->msg_perm.gid);
-			err |= get_user(m.msg_perm.mode, &up32->msg_perm.mode);
-			err |= get_user(m.msg_qbytes, &up32->msg_qbytes);
-		}
-		if (err)
-			break;
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		err = sys_msgctl(first, second, &m);
-		set_fs(old_fs);
-		break;
-
-	      case IPC_STAT:
-	      case MSG_STAT:
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		err = sys_msgctl(first, second, (void *) &m64);
-		set_fs(old_fs);
-		if (version == IPC_64) {
-			if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) {
-				err = -EFAULT;
-				break;
-			}
-			err2 = __put_user(m64.msg_perm.key, &up64->msg_perm.key);
-			err2 |= __put_user(m64.msg_perm.uid, &up64->msg_perm.uid);
-			err2 |= __put_user(m64.msg_perm.gid, &up64->msg_perm.gid);
-			err2 |= __put_user(m64.msg_perm.cuid, &up64->msg_perm.cuid);
-			err2 |= __put_user(m64.msg_perm.cgid, &up64->msg_perm.cgid);
-			err2 |= __put_user(m64.msg_perm.mode, &up64->msg_perm.mode);
-			err2 |= __put_user(m64.msg_perm.seq, &up64->msg_perm.seq);
-			err2 |= __put_user(m64.msg_stime, &up64->msg_stime);
-			err2 |= __put_user(m64.msg_rtime, &up64->msg_rtime);
-			err2 |= __put_user(m64.msg_ctime, &up64->msg_ctime);
-			err2 |= __put_user(m64.msg_cbytes, &up64->msg_cbytes);
-			err2 |= __put_user(m64.msg_qnum, &up64->msg_qnum);
-			err2 |= __put_user(m64.msg_qbytes, &up64->msg_qbytes);
-			err2 |= __put_user(m64.msg_lspid, &up64->msg_lspid);
-			err2 |= __put_user(m64.msg_lrpid, &up64->msg_lrpid);
-			if (err2)
-				err = -EFAULT;
-		} else {
-			if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) {
-				err = -EFAULT;
-				break;
-			}
-			err2 = __put_user(m64.msg_perm.key, &up32->msg_perm.key);
-			err2 |= __put_user(m64.msg_perm.uid, &up32->msg_perm.uid);
-			err2 |= __put_user(m64.msg_perm.gid, &up32->msg_perm.gid);
-			err2 |= __put_user(m64.msg_perm.cuid, &up32->msg_perm.cuid);
-			err2 |= __put_user(m64.msg_perm.cgid, &up32->msg_perm.cgid);
-			err2 |= __put_user(m64.msg_perm.mode, &up32->msg_perm.mode);
-			err2 |= __put_user(m64.msg_perm.seq, &up32->msg_perm.seq);
-			err2 |= __put_user(m64.msg_stime, &up32->msg_stime);
-			err2 |= __put_user(m64.msg_rtime, &up32->msg_rtime);
-			err2 |= __put_user(m64.msg_ctime, &up32->msg_ctime);
-			err2 |= __put_user(m64.msg_cbytes, &up32->msg_cbytes);
-			err2 |= __put_user(m64.msg_qnum, &up32->msg_qnum);
-			err2 |= __put_user(m64.msg_qbytes, &up32->msg_qbytes);
-			err2 |= __put_user(m64.msg_lspid, &up32->msg_lspid);
-			err2 |= __put_user(m64.msg_lrpid, &up32->msg_lrpid);
-			if (err2)
-				err = -EFAULT;
-		}
-		break;
-	}
-	return err;
-}
-
-static int
-shmat32 (int first, int second, int third, int version, void *uptr)
-{
-	unsigned long raddr;
-	u32 *uaddr = (u32 *)A((u32)third);
-	int err;
-
-	if (version == 1)
-		return -EINVAL;	/* iBCS2 emulator entry point: unsupported */
-	err = do_shmat(first, uptr, second, &raddr);
-	if (err)
-		return err;
-	return put_user(raddr, uaddr);
-}
-
-static int put_shmid64(struct shmid64_ds *s64p, void *uptr, int version) 
-{ 
-	int err2; 
-#define s64 (*s64p)
-	if (version == IPC_64) {
-		struct shmid64_ds32 *up64 = (struct shmid64_ds32 *)uptr;
-
-		if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
-			return -EFAULT;
-
-		err2 = __put_user(s64.shm_perm.key, &up64->shm_perm.key);
-		err2 |= __put_user(s64.shm_perm.uid, &up64->shm_perm.uid);
-		err2 |= __put_user(s64.shm_perm.gid, &up64->shm_perm.gid);
-		err2 |= __put_user(s64.shm_perm.cuid, &up64->shm_perm.cuid);
-		err2 |= __put_user(s64.shm_perm.cgid, &up64->shm_perm.cgid);
-		err2 |= __put_user(s64.shm_perm.mode, &up64->shm_perm.mode);
-		err2 |= __put_user(s64.shm_perm.seq, &up64->shm_perm.seq);
-		err2 |= __put_user(s64.shm_atime, &up64->shm_atime);
-		err2 |= __put_user(s64.shm_dtime, &up64->shm_dtime);
-		err2 |= __put_user(s64.shm_ctime, &up64->shm_ctime);
-		err2 |= __put_user(s64.shm_segsz, &up64->shm_segsz);
-		err2 |= __put_user(s64.shm_nattch, &up64->shm_nattch);
-		err2 |= __put_user(s64.shm_cpid, &up64->shm_cpid);
-		err2 |= __put_user(s64.shm_lpid, &up64->shm_lpid);
-	} else {
-		struct shmid_ds32 *up32 = (struct shmid_ds32 *)uptr;
-
-		if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) 
-			return -EFAULT;
-
-		err2 = __put_user(s64.shm_perm.key, &up32->shm_perm.key);
-		err2 |= __put_user(s64.shm_perm.uid, &up32->shm_perm.uid);
-		err2 |= __put_user(s64.shm_perm.gid, &up32->shm_perm.gid);
-		err2 |= __put_user(s64.shm_perm.cuid, &up32->shm_perm.cuid);
-		err2 |= __put_user(s64.shm_perm.cgid, &up32->shm_perm.cgid);
-		err2 |= __put_user(s64.shm_perm.mode, &up32->shm_perm.mode);
-		err2 |= __put_user(s64.shm_perm.seq, &up32->shm_perm.seq);
-		err2 |= __put_user(s64.shm_atime, &up32->shm_atime);
-		err2 |= __put_user(s64.shm_dtime, &up32->shm_dtime);
-		err2 |= __put_user(s64.shm_ctime, &up32->shm_ctime);
-		err2 |= __put_user(s64.shm_segsz, &up32->shm_segsz);
-		err2 |= __put_user(s64.shm_nattch, &up32->shm_nattch);
-		err2 |= __put_user(s64.shm_cpid, &up32->shm_cpid);
-		err2 |= __put_user(s64.shm_lpid, &up32->shm_lpid);
-	}
-#undef s64
-	return err2 ? -EFAULT : 0;
-}
-static int
-shmctl32 (int first, int second, void *uptr)
-{
-	int err = -EFAULT, err2;
-	struct shmid_ds s;
-	struct shmid64_ds s64;
-	mm_segment_t old_fs;
-	struct shm_info32 *uip = (struct shm_info32 *)uptr;
-	struct shm_info si;
-	int version = ipc_parse_version32(&second);
-	struct shminfo64 smi;
-	struct shminfo *usi32 = (struct shminfo *) uptr;
-	struct shminfo64_32 *usi64 = (struct shminfo64_32 *) uptr;
-
-	switch (second) {
-	      case IPC_INFO:
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		err = sys_shmctl(first, second, (struct shmid_ds *)&smi);
-		set_fs(old_fs);
-
-		if (version == IPC_64) {
-			if (!access_ok(VERIFY_WRITE, usi64, sizeof(*usi64))) {
-				err = -EFAULT;
-				break;
-			}
-			err2 = __put_user(smi.shmmax, &usi64->shmmax);
-			err2 |= __put_user(smi.shmmin, &usi64->shmmin);
-			err2 |= __put_user(smi.shmmni, &usi64->shmmni);
-			err2 |= __put_user(smi.shmseg, &usi64->shmseg);
-			err2 |= __put_user(smi.shmall, &usi64->shmall);
-		} else {
-			if (!access_ok(VERIFY_WRITE, usi32, sizeof(*usi32))) {
-				err = -EFAULT;
-				break;
-			}
-			err2 = __put_user(smi.shmmax, &usi32->shmmax);
-			err2 |= __put_user(smi.shmmin, &usi32->shmmin);
-			err2 |= __put_user(smi.shmmni, &usi32->shmmni);
-			err2 |= __put_user(smi.shmseg, &usi32->shmseg);
-			err2 |= __put_user(smi.shmall, &usi32->shmall);
-		}
-		if (err2)
-			err = -EFAULT;
-		break;
-
-	      case IPC_RMID:
-	      case SHM_LOCK:
-	      case SHM_UNLOCK:
-		err = sys_shmctl(first, second, (struct shmid_ds *)uptr);
-		break;
-
-	      case IPC_SET: 
-		if (version == IPC_64) {
-			struct shmid64_ds32 *up64 = (struct shmid64_ds32 *)uptr;
-			err = get_user(s.shm_perm.uid, &up64->shm_perm.uid);
-			err |= get_user(s.shm_perm.gid, &up64->shm_perm.gid);
-			err |= get_user(s.shm_perm.mode, &up64->shm_perm.mode);
-		} else {
-			struct shmid_ds32 *up32 = (struct shmid_ds32 *)uptr;
-			err = get_user(s.shm_perm.uid, &up32->shm_perm.uid);
-			err |= get_user(s.shm_perm.gid, &up32->shm_perm.gid);
-			err |= get_user(s.shm_perm.mode, &up32->shm_perm.mode);
-		}
-		if (err)
-			break;
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		err = sys_shmctl(first, second, &s);
-		set_fs(old_fs);
-		break;
-
-	      case IPC_STAT:
-	      case SHM_STAT:
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		err = sys_shmctl(first, second, (void *) &s64);
-		set_fs(old_fs);
-		
-		if (err < 0)
-			break;
-	        err2 = put_shmid64(&s64, uptr, version); 		
-		if (err2) 
-			err = err2;
-		break;
-
-	      case SHM_INFO:
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		err = sys_shmctl(first, second, (void *)&si);
-		set_fs(old_fs);
-		if (err < 0)
-			break;
-
-		if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip))) {
-			err = -EFAULT;
-			break;
-		}
-		err2 = __put_user(si.used_ids, &uip->used_ids);
-		err2 |= __put_user(si.shm_tot, &uip->shm_tot);
-		err2 |= __put_user(si.shm_rss, &uip->shm_rss);
-		err2 |= __put_user(si.shm_swp, &uip->shm_swp);
-		err2 |= __put_user(si.swap_attempts, &uip->swap_attempts);
-		err2 |= __put_user(si.swap_successes, &uip->swap_successes);
-		if (err2)
-			err = -EFAULT;
-		break;
-	default:
-		err = -EINVAL;
-		break;
-	}
-	return err;
-}
-
-extern int sem_ctls[];
-
-static long semtimedop32(int semid, struct sembuf *sb, 
-			 unsigned nsops, struct compat_timespec *ts32)
-{ 
-	struct timespec ts;
-	mm_segment_t oldfs = get_fs(); 
-	long ret;
-
-	if (nsops > sem_ctls[2]) 
-		return -E2BIG;
-	if (!access_ok(VERIFY_READ, sb, nsops * sizeof(struct sembuf)))
-		return -EFAULT; 
-	if (ts32 && get_compat_timespec(&ts, ts32))
-		return -EFAULT;
-
-	set_fs(KERNEL_DS);  
-	ret = sys_semtimedop(semid, sb, nsops, ts32 ? &ts : NULL);
-	set_fs(oldfs); 
-	return ret;
-}
 
+#include <asm-i386/ipc.h>
 
 asmlinkage long
-sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
+sys32_ipc(u32 call, int first, int second, int third,
+		compat_uptr_t ptr, u32 fifth)
 {
 	int version;
 
@@ -660,35 +23,35 @@ sys32_ipc (u32 call, int first, int seco
 	switch (call) {
 	      case SEMOP:
 		/* struct sembuf is the same on 32 and 64bit :)) */
-		return sys_semtimedop(first, (struct sembuf *)AA(ptr), second,
-				      NULL);
-	      case TIMEDSEMOP:
-		return semtimedop32(first, (struct sembuf *)AA(ptr), second,
-				  (struct compat_timespec *)AA(fifth)); 
+		return sys_semtimedop(first, compat_ptr(ptr), second, NULL);
+	      case SEMTIMEDOP:
+		return compat_sys_semtimedop(first, compat_ptr(ptr), second,
+						compat_ptr(fifth));
 	      case SEMGET:
 		return sys_semget(first, second, third);
 	      case SEMCTL:
-		return semctl32(first, second, third, (void *)AA(ptr));
+		return compat_sys_semctl(first, second, third, compat_ptr(ptr));
 
 	      case MSGSND:
-		return do_sys32_msgsnd(first, second, third, (void *)AA(ptr));
+		return compat_sys_msgsnd(first, second, third, compat_ptr(ptr));
 	      case MSGRCV:
-		return do_sys32_msgrcv(first, second, fifth, third, version, (void *)AA(ptr));
+		return compat_sys_msgrcv(first, second, fifth, third,
+					 version, compat_ptr(ptr));
 	      case MSGGET:
 		return sys_msgget((key_t) first, second);
 	      case MSGCTL:
-		return msgctl32(first, second, (void *)AA(ptr));
+		return compat_sys_msgctl(first, second, compat_ptr(ptr));
 
 	      case SHMAT:
-		return shmat32(first, second, third, version, (void *)AA(ptr));
+		return compat_sys_shmat(first, second, third, version,
+					compat_ptr(ptr));
 		break;
 	      case SHMDT:
-		return sys_shmdt((char *)AA(ptr));
+		return sys_shmdt(compat_ptr(ptr));
 	      case SHMGET:
 		return sys_shmget(first, second, third);
 	      case SHMCTL:
-		return shmctl32(first, second, (void *)AA(ptr));
+		return compat_sys_shmctl(first, second, compat_ptr(ptr));
 	}
 	return -ENOSYS;
 }
-
--- diff/arch/x86_64/kernel/Makefile	2004-03-04 11:41:46.000000000 +0000
+++ source/arch/x86_64/kernel/Makefile	2004-03-09 11:51:49.000000000 +0000
@@ -27,6 +27,7 @@ obj-$(CONFIG_DUMMY_IOMMU)	+= pci-nommu.o
 obj-$(CONFIG_SWIOTLB)		+= swiotlb.o
 
 obj-$(CONFIG_MODULES)		+= module.o
+obj-$(CONFIG_KGDB)		+= kgdb_stub.o
 
 obj-y				+= topology.o
 
--- diff/arch/x86_64/kernel/acpi/boot.c	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/x86_64/kernel/acpi/boot.c	2004-03-09 11:51:49.000000000 +0000
@@ -48,11 +48,12 @@
 
 #define PREFIX			"ACPI: "
 
-int acpi_noirq __initdata = 0;	/* skip ACPI IRQ initialization */
+int acpi_noirq __initdata;	/* skip ACPI IRQ initialization */
 int acpi_ht __initdata = 1;	/* enable HT */
 
 int acpi_lapic;
 int acpi_ioapic;
+int acpi_strict;
 
 /* --------------------------------------------------------------------------
                               Boot-time Configuration
@@ -264,7 +265,7 @@ acpi_parse_hpet (
  * programs the PIC-mode SCI to Level Trigger.
  * (NO-OP if the BIOS set Level Trigger already)
  *
- * If a PIC-mode SCI is not recogznied or gives spurious IRQ7's
+ * If a PIC-mode SCI is not recognized or gives spurious IRQ7's
  * it may require Edge Trigger -- use "acpi_pic_sci=edge"
  * (NO-OP if the BIOS set Edge Trigger already)
  *
--- diff/arch/x86_64/kernel/irq.c	2004-03-04 11:41:46.000000000 +0000
+++ source/arch/x86_64/kernel/irq.c	2004-03-09 11:51:49.000000000 +0000
@@ -405,6 +405,9 @@ out:
 	spin_unlock(&desc->lock);
 
 	irq_exit();
+
+	kgdb_process_breakpoint();
+
 	return 1;
 }
 
--- diff/arch/x86_64/kernel/mpparse.c	2004-03-04 11:41:46.000000000 +0000
+++ source/arch/x86_64/kernel/mpparse.c	2004-03-09 11:51:49.000000000 +0000
@@ -996,7 +996,7 @@ void __init mp_parse_prt (void)
 			continue;
 		}
 		if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
-			printk(KERN_DEBUG "Pin %d-%d already programmed\n",
+			Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
 				mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
  			if (use_pci_vector() && !platform_legacy_irq(irq))
  				irq = IO_APIC_VECTOR(irq);
--- diff/arch/x86_64/kernel/pci-gart.c	2004-03-04 11:41:46.000000000 +0000
+++ source/arch/x86_64/kernel/pci-gart.c	2004-03-09 11:51:49.000000000 +0000
@@ -177,7 +177,7 @@ void *pci_alloc_consistent(struct pci_de
 		gfp |= GFP_DMA; 
 		dma_mask = 0xffffffff; 
 	} else {
-		dma_mask = hwdev->consistent_dma_mask; 
+		dma_mask = hwdev->dev.coherent_dma_mask;
 	}
 
 	if (dma_mask == 0) 
--- diff/arch/x86_64/kernel/process.c	2004-03-04 11:41:46.000000000 +0000
+++ source/arch/x86_64/kernel/process.c	2004-03-09 11:51:49.000000000 +0000
@@ -16,7 +16,6 @@
  * This file handles the architecture-dependent parts of process handling..
  */
 
-#define __KERNEL_SYSCALLS__
 #include <stdarg.h>
 
 #include <linux/errno.h>
@@ -25,7 +24,6 @@
 #include <linux/mm.h>
 #include <linux/elfcore.h>
 #include <linux/smp.h>
-#include <linux/unistd.h>
 #include <linux/slab.h>
 #include <linux/user.h>
 #include <linux/module.h>
--- diff/arch/x86_64/kernel/smp.c	2003-11-25 15:24:57.000000000 +0000
+++ source/arch/x86_64/kernel/smp.c	2004-03-09 11:51:49.000000000 +0000
@@ -362,6 +362,18 @@ void smp_send_reschedule(int cpu)
 	send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR);
 }
 
+#ifdef CONFIG_KGDB
+/*
+ * By using the NMI code instead of a vector we just sneak thru the
+ * word generator coming out with just what we want.  AND it does
+ * not matter if clustered_apic_mode is set or not.
+ */
+void smp_send_nmi_allbutself(void)
+{
+	send_IPI_allbutself(APIC_DM_NMI);
+}
+#endif
+
 /*
  * Structure and data for smp_call_function(). This is designed to minimise
  * static memory requirements. It also looks cleaner.
--- diff/arch/x86_64/kernel/traps.c	2004-03-04 11:41:46.000000000 +0000
+++ source/arch/x86_64/kernel/traps.c	2004-03-09 11:51:49.000000000 +0000
@@ -45,6 +45,9 @@
 #include <asm/proto.h>
 
 #include <linux/irq.h>
+#ifdef CONFIG_KGDB
+#include <asm/kgdb.h>
+#endif
 
 extern struct gate_struct idt_table[256]; 
 
--- diff/arch/x86_64/kernel/x8664_ksyms.c	2004-03-04 11:41:46.000000000 +0000
+++ source/arch/x86_64/kernel/x8664_ksyms.c	2004-03-09 11:51:49.000000000 +0000
@@ -63,10 +63,6 @@ EXPORT_SYMBOL(pm_idle);
 EXPORT_SYMBOL(pm_power_off);
 EXPORT_SYMBOL(get_cmos_time);
 
-#ifdef CONFIG_IO_DEBUG
-EXPORT_SYMBOL(__io_virt_debug);
-#endif
-
 EXPORT_SYMBOL_NOVERS(__down_failed);
 EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
 EXPORT_SYMBOL_NOVERS(__down_failed_trylock);
--- diff/arch/x86_64/lib/Makefile	2003-06-30 10:07:20.000000000 +0100
+++ source/arch/x86_64/lib/Makefile	2004-03-09 11:51:49.000000000 +0000
@@ -9,5 +9,5 @@ lib-y := csum-partial.o csum-copy.o csum
 	thunk.o io.o clear_page.o copy_page.o bitstr.o
 lib-y += memcpy.o memmove.o memset.o copy_user.o
 
-lib-$(CONFIG_IO_DEBUG) += iodebug.o
 lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
+lib-$(CONFIG_KGDB) += kgdb_serial.o
--- diff/arch/x86_64/lib/io.c	2002-12-30 10:17:12.000000000 +0000
+++ source/arch/x86_64/lib/io.c	2004-03-09 11:51:49.000000000 +0000
@@ -4,12 +4,12 @@
 
 void *memcpy_toio(void *dst,const void*src,unsigned len)
 {
-	return __inline_memcpy(__io_virt(dst),src,len);
+	return __inline_memcpy(dst,src,len);
 }
 
 void *memcpy_fromio(void *dst,const void*src,unsigned len)
 {
-	return __inline_memcpy(dst,__io_virt(src),len);
+	return __inline_memcpy(dst,src,len);
 }
 
 EXPORT_SYMBOL(memcpy_toio);
--- diff/crypto/Kconfig	2003-10-09 09:47:33.000000000 +0100
+++ source/crypto/Kconfig	2004-03-09 11:51:49.000000000 +0000
@@ -140,6 +140,16 @@ config CRYPTO_CAST6
 	  The CAST6 encryption algorithm (synonymous with CAST-256) is
 	  described in RFC2612.
 
+config CRYPTO_ARC4
+	tristate "ARC4 cipher algorithm"
+	depends on CRYPTO
+	help
+	  ARC4 cipher algorithm.
+
+	  This is a stream cipher using keys ranging from 8 bits to 2048
+	  bits in length.  ARC4 is commonly used in protocols such as WEP 
+	  and SSL.
+
 config CRYPTO_DEFLATE
 	tristate "Deflate compression algorithm"
 	depends on CRYPTO
--- diff/crypto/Makefile	2004-03-04 11:41:46.000000000 +0000
+++ source/crypto/Makefile	2004-03-09 11:51:49.000000000 +0000
@@ -21,6 +21,7 @@ obj-$(CONFIG_CRYPTO_SERPENT) += serpent.
 obj-$(CONFIG_CRYPTO_AES) += aes.o
 obj-$(CONFIG_CRYPTO_CAST5) += cast5.o
 obj-$(CONFIG_CRYPTO_CAST6) += cast6.o
+obj-$(CONFIG_CRYPTO_ARC4) += arc4.o
 obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
 
 obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
--- diff/crypto/tcrypt.c	2004-01-19 10:22:55.000000000 +0000
+++ source/crypto/tcrypt.c	2004-03-09 11:51:49.000000000 +0000
@@ -61,7 +61,7 @@ static char *tvmem;
 static char *check[] = {
 	"des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish",
 	"twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6", 
-	"deflate", NULL
+	"arc4", "deflate", NULL
 };
 
 static void
@@ -556,6 +556,10 @@ do_test(void)
 		test_cipher ("cast6", MODE_ECB, ENCRYPT, cast6_enc_tv_template, CAST6_ENC_TEST_VECTORS);
 		test_cipher ("cast6", MODE_ECB, DECRYPT, cast6_dec_tv_template, CAST6_DEC_TEST_VECTORS);
 
+		//ARC4
+		test_cipher ("arc4", MODE_ECB, ENCRYPT, arc4_enc_tv_template, ARC4_ENC_TEST_VECTORS);
+		test_cipher ("arc4x", MODE_ECB, DECRYPT, arc4_dec_tv_template, ARC4_DEC_TEST_VECTORS);
+
 		test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS);
 		test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS);
 		test_deflate();		
@@ -638,6 +642,11 @@ do_test(void)
 		test_cipher ("cast6", MODE_ECB, DECRYPT, cast6_dec_tv_template, CAST6_DEC_TEST_VECTORS);
 		break;
 
+	case 16:
+		test_cipher ("arc4", MODE_ECB, ENCRYPT, arc4_enc_tv_template, ARC4_ENC_TEST_VECTORS);
+		test_cipher ("arc4", MODE_ECB, DECRYPT, arc4_dec_tv_template, ARC4_DEC_TEST_VECTORS);
+		break;
+
 #ifdef CONFIG_CRYPTO_HMAC
 	case 100:
 		test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS);
--- diff/crypto/tcrypt.h	2004-01-19 10:22:55.000000000 +0000
+++ source/crypto/tcrypt.h	2004-03-09 11:51:49.000000000 +0000
@@ -1488,6 +1488,147 @@ struct cipher_testvec cast5_dec_tv_templ
 	},
 };
 
+/* 
+ * ARC4 test vectors from OpenSSL 
+ */
+#define ARC4_ENC_TEST_VECTORS	7
+#define ARC4_DEC_TEST_VECTORS	7
+
+struct cipher_testvec arc4_enc_tv_template[] =
+{
+	{
+		.key	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
+		.klen	= 8,
+		.input	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
+		.ilen	= 8,
+		.result	= { 0x75, 0xb7, 0x87, 0x80, 0x99, 0xe0, 0xc5, 0x96 },
+		.rlen	= 8,
+	}, {
+		.key	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
+		.klen	= 8,
+		.input	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.ilen	= 8,
+		.result	= { 0x74, 0x94, 0xc2, 0xe7, 0x10, 0x4b, 0x08, 0x79 },
+		.rlen	= 8,
+	}, {
+		.key	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.klen	= 8,
+		.input	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.ilen	= 8,
+		.result	= { 0xde, 0x18, 0x89, 0x41, 0xa3, 0x37, 0x5d, 0x3a },
+		.rlen	= 8,
+	}, {
+		.key	= { 0xef, 0x01, 0x23, 0x45},
+		.klen	= 4,
+		.input	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			    0x00, 0x00, 0x00, 0x00 },
+		.ilen	= 20,
+		.result	= { 0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf,
+			    0xbd, 0x61, 0x5a, 0x11, 0x62, 0xe1, 0xc7, 0xba,
+			    0x36, 0xb6, 0x78, 0x58 },
+		.rlen	= 20,
+	}, {
+		.key	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
+		.klen	= 8,
+		.input	= { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0,
+			    0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0,
+			    0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0,
+			    0x12, 0x34, 0x56, 0x78 },
+		.ilen	= 28,
+		.result	= { 0x66, 0xa0, 0x94, 0x9f, 0x8a, 0xf7, 0xd6, 0x89,
+			    0x1f, 0x7f, 0x83, 0x2b, 0xa8, 0x33, 0xc0, 0x0c,
+			    0x89, 0x2e, 0xbe, 0x30, 0x14, 0x3c, 0xe2, 0x87,
+			    0x40, 0x01, 0x1e, 0xcf },
+		.rlen	= 28,
+	}, {
+		.key	= { 0xef, 0x01, 0x23, 0x45 },
+		.klen	= 4,
+		.input	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			    0x00, 0x00 },
+		.ilen	= 10,
+		.result	= { 0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf,
+			    0xbd, 0x61 },
+		.rlen	= 10,
+	}, {
+		.key	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
+		            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.klen	= 16,
+		.input	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF },
+		.ilen	= 8,
+		.result	= { 0x69, 0x72, 0x36, 0x59, 0x1B, 0x52, 0x42, 0xB1 },
+		.rlen	= 8,
+	},
+};
+
+struct cipher_testvec arc4_dec_tv_template[] =
+{
+	{
+		.key	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
+		.klen	= 8,
+		.input	= { 0x75, 0xb7, 0x87, 0x80, 0x99, 0xe0, 0xc5, 0x96 },
+		.ilen	= 8,
+		.result	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
+		.rlen	= 8,
+	}, {
+		.key	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
+		.klen	= 8,
+		.input	= { 0x74, 0x94, 0xc2, 0xe7, 0x10, 0x4b, 0x08, 0x79 },
+		.ilen	= 8,
+		.result	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.rlen	= 8,
+	}, {
+		.key	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.klen	= 8,
+		.input	= { 0xde, 0x18, 0x89, 0x41, 0xa3, 0x37, 0x5d, 0x3a },
+		.ilen	= 8,
+		.result	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.rlen	= 8,
+	}, {
+		.key	= { 0xef, 0x01, 0x23, 0x45},
+		.klen	= 4,
+		.input	= { 0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf,
+			    0xbd, 0x61, 0x5a, 0x11, 0x62, 0xe1, 0xc7, 0xba,
+			    0x36, 0xb6, 0x78, 0x58 },
+		.ilen	= 20,
+		.result	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			    0x00, 0x00, 0x00, 0x00 },
+		.rlen	= 20,
+	}, {
+		.key	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
+		.klen	= 8,
+		.input	= { 0x66, 0xa0, 0x94, 0x9f, 0x8a, 0xf7, 0xd6, 0x89,
+			    0x1f, 0x7f, 0x83, 0x2b, 0xa8, 0x33, 0xc0, 0x0c,
+			    0x89, 0x2e, 0xbe, 0x30, 0x14, 0x3c, 0xe2, 0x87,
+			    0x40, 0x01, 0x1e, 0xcf },
+		.ilen	= 28,
+		.result	= { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0,
+			    0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0,
+			    0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0,
+			    0x12, 0x34, 0x56, 0x78 },
+		.rlen	= 28,
+	}, {
+		.key	= { 0xef, 0x01, 0x23, 0x45 },
+		.klen	= 4,
+		.input	= { 0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf,
+			    0xbd, 0x61 },
+		.ilen	= 10,
+		.result	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			    0x00, 0x00 },
+		.rlen	= 10,
+	}, {
+		.key	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
+		            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.klen	= 16,
+		.input	= { 0x69, 0x72, 0x36, 0x59, 0x1B, 0x52, 0x42, 0xB1 },
+		.ilen	= 8,
+		.result	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF },
+		.rlen	= 8,
+	},
+};
+
+
 /*
  * Compression stuff.
  */
--- diff/drivers/acpi/Kconfig	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/acpi/Kconfig	2004-03-09 11:51:49.000000000 +0000
@@ -251,18 +251,6 @@ config ACPI_SYSTEM
 	  This driver will enable your system to shut down using ACPI, and
 	  dump your ACPI DSDT table using /proc/acpi/dsdt.
 
-config ACPI_RELAXED_AML
-	bool "Relaxed AML"
-	depends on ACPI_INTERPRETER
-	depends on !IA64_SGI_SN
-	default n
-	help
-	  If you say `Y' here, the ACPI interpreter will relax its checking
-	  for valid AML and will ignore some AML mistakes, such as off-by-one
-	  errors in region sizes.  Some laptops may require this option.  In
-	  particular, many Toshiba laptops require this for correct operation
-	  of the AC module.
-
 config X86_PM_TIMER
 	bool "Power Management Timer Support"
 	depends on X86 && ACPI
--- diff/drivers/acpi/executer/exfldio.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/acpi/executer/exfldio.c	2004-03-09 11:51:49.000000000 +0000
@@ -154,8 +154,7 @@ acpi_ex_setup_region (
 			field_datum_byte_offset, obj_desc->common_field.access_byte_width,
 			acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length));
 
-		#ifdef CONFIG_ACPI_RELAXED_AML
-		{
+		if (!acpi_strict) {
 			/*
 			 * Allow access to the field if it is within the region size
 			 * rounded up to a multiple of the access byte width.  This
@@ -186,9 +185,9 @@ acpi_ex_setup_region (
 				return_ACPI_STATUS (AE_OK);
 			}
 		}
-		#else
+		else {
 			return_ACPI_STATUS (AE_AML_REGION_LIMIT);
-		#endif
+		}
 	}
 
 	return_ACPI_STATUS (AE_OK);
--- diff/drivers/acpi/hardware/hwgpe.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/hardware/hwgpe.c	2004-03-09 11:51:49.000000000 +0000
@@ -528,6 +528,14 @@ acpi_hw_enable_non_wakeup_gpe_block (
 	/* Examine each GPE register within the block */
 
 	for (i = 0; i < gpe_block->register_count; i++) {
+		/* Clear the entire status register */
+
+		status = acpi_hw_low_level_write (8, 0xFF,
+				 &gpe_block->register_info[i].status_address);
+		if (ACPI_FAILURE (status)) {
+			return (status);
+		}
+
 		/*
 		 * We previously stored the enabled status of all GPEs.
 		 * Blast them back in.
--- diff/drivers/acpi/hardware/hwregs.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/hardware/hwregs.c	2004-03-09 11:51:49.000000000 +0000
@@ -152,11 +152,11 @@ acpi_get_sleep_type_data (
 	/*
 	 * Evaluate the namespace object containing the values for this state
 	 */
-	status = acpi_ns_evaluate_by_name ((char *) acpi_gbl_db_sleep_states[sleep_state],
+	status = acpi_ns_evaluate_by_name ((char *) acpi_gbl_sleep_state_names[sleep_state],
 			  NULL, &obj_desc);
 	if (ACPI_FAILURE (status)) {
 		ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s while evaluating sleep_state [%s]\n",
-			acpi_format_exception (status), acpi_gbl_db_sleep_states[sleep_state]));
+			acpi_format_exception (status), acpi_gbl_sleep_state_names[sleep_state]));
 
 		return_ACPI_STATUS (status);
 	}
@@ -201,7 +201,7 @@ acpi_get_sleep_type_data (
 
 	if (ACPI_FAILURE (status)) {
 		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "While evaluating sleep_state [%s], bad Sleep object %p type %s\n",
-			acpi_gbl_db_sleep_states[sleep_state], obj_desc, acpi_ut_get_object_type_name (obj_desc)));
+			acpi_gbl_sleep_state_names[sleep_state], obj_desc, acpi_ut_get_object_type_name (obj_desc)));
 	}
 
 	acpi_ut_remove_reference (obj_desc);
--- diff/drivers/acpi/hardware/hwsleep.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/acpi/hardware/hwsleep.c	2004-03-09 11:51:49.000000000 +0000
@@ -48,6 +48,19 @@
 	 ACPI_MODULE_NAME    ("hwsleep")
 
 
+#define METHOD_NAME__BFS        "\\_BFS"
+#define METHOD_NAME__GTS        "\\_GTS"
+#define METHOD_NAME__PTS        "\\_PTS"
+#define METHOD_NAME__SST        "\\_SI._SST"
+#define METHOD_NAME__WAK        "\\_WAK"
+
+#define ACPI_SST_INDICATOR_OFF  0
+#define ACPI_SST_WORKING        1
+#define ACPI_SST_WAKING         2
+#define ACPI_SST_SLEEPING       3
+#define ACPI_SST_SLEEP_CONTEXT  4
+
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_set_firmware_waking_vector
@@ -171,19 +184,41 @@ acpi_enter_sleep_state_prep (
 
 	/* Run the _PTS and _GTS methods */
 
-	status = acpi_evaluate_object (NULL, "\\_PTS", &arg_list, NULL);
+	status = acpi_evaluate_object (NULL, METHOD_NAME__PTS, &arg_list, NULL);
 	if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
 		return_ACPI_STATUS (status);
 	}
 
-	status = acpi_evaluate_object (NULL, "\\_GTS", &arg_list, NULL);
+	status = acpi_evaluate_object (NULL, METHOD_NAME__GTS, &arg_list, NULL);
 	if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
 		return_ACPI_STATUS (status);
 	}
 
+	/* Setup the argument to _SST */
+
+	switch (sleep_state) {
+	case ACPI_STATE_S0:
+		arg.integer.value = ACPI_SST_WORKING;
+		break;
+
+	case ACPI_STATE_S1:
+	case ACPI_STATE_S2:
+	case ACPI_STATE_S3:
+		arg.integer.value = ACPI_SST_SLEEPING;
+		break;
+
+	case ACPI_STATE_S4:
+		arg.integer.value = ACPI_SST_SLEEP_CONTEXT;
+		break;
+
+	default:
+		arg.integer.value = ACPI_SST_INDICATOR_OFF; /* Default is indicator off */
+		break;
+	}
+
 	/* Set the system indicators to show the desired sleep state. */
 
-	status = acpi_evaluate_object (NULL, "\\_SI._SST", &arg_list, NULL);
+	status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL);
 	if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
 		 ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status)));
 	}
@@ -359,7 +394,7 @@ acpi_enter_sleep_state (
  *
  ******************************************************************************/
 
-acpi_status
+acpi_status asmlinkage
 acpi_enter_sleep_state_s4bios (
 	void)
 {
@@ -477,19 +512,19 @@ acpi_leave_sleep_state (
 
 	/* Ignore any errors from these methods */
 
-	arg.integer.value = 0;
-	status = acpi_evaluate_object (NULL, "\\_SI._SST", &arg_list, NULL);
+	arg.integer.value = ACPI_SST_WAKING;
+	status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL);
 	if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
 		ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status)));
 	}
 
 	arg.integer.value = sleep_state;
-	status = acpi_evaluate_object (NULL, "\\_BFS", &arg_list, NULL);
+	status = acpi_evaluate_object (NULL, METHOD_NAME__BFS, &arg_list, NULL);
 	if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
 		ACPI_REPORT_ERROR (("Method _BFS failed, %s\n", acpi_format_exception (status)));
 	}
 
-	status = acpi_evaluate_object (NULL, "\\_WAK", &arg_list, NULL);
+	status = acpi_evaluate_object (NULL, METHOD_NAME__WAK, &arg_list, NULL);
 	if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
 		ACPI_REPORT_ERROR (("Method _WAK failed, %s\n", acpi_format_exception (status)));
 	}
@@ -501,8 +536,25 @@ acpi_leave_sleep_state (
 		return_ACPI_STATUS (status);
 	}
 
+	/* Enable power button */
+
+	acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].enable_register_id,
+			1, ACPI_MTX_DO_NOT_LOCK);
+	acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].status_register_id,
+			1, ACPI_MTX_DO_NOT_LOCK);
+
 	/* Enable BM arbitration */
 
 	status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_LOCK);
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
+
+	arg.integer.value = ACPI_SST_WORKING;
+	status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL);
+	if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
+		ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status)));
+	}
+
 	return_ACPI_STATUS (status);
 }
--- diff/drivers/acpi/namespace/nseval.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/namespace/nseval.c	2004-03-09 11:51:49.000000000 +0000
@@ -110,7 +110,7 @@ acpi_ns_evaluate_relative (
 
 	status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
 	if (ACPI_FAILURE (status)) {
-		return_ACPI_STATUS (status);
+		goto cleanup;
 	}
 
 	prefix_node = acpi_ns_map_handle_to_node (handle);
@@ -197,7 +197,7 @@ acpi_ns_evaluate_by_name (
 
 	status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
 	if (ACPI_FAILURE (status)) {
-		return_ACPI_STATUS (status);
+		goto cleanup;
 	}
 
 	/* Lookup the name in the namespace */
--- diff/drivers/acpi/namespace/nsutils.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/namespace/nsutils.c	2004-03-09 11:51:49.000000000 +0000
@@ -918,7 +918,7 @@ acpi_ns_get_node_by_path (
 
 	status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
 	if (ACPI_FAILURE (status)) {
-		return_ACPI_STATUS (status);
+		goto cleanup;
 	}
 
 	/* Setup lookup scope (search starting point) */
@@ -936,10 +936,10 @@ acpi_ns_get_node_by_path (
 				internal_path, acpi_format_exception (status)));
 	}
 
-	/* Cleanup */
-
 	(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
 
+cleanup:
+	/* Cleanup */
 	if (internal_path) {
 		ACPI_MEM_FREE (internal_path);
 	}
--- diff/drivers/acpi/namespace/nsxfname.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/namespace/nsxfname.c	2004-03-09 11:51:49.000000000 +0000
@@ -326,6 +326,13 @@ acpi_get_object_info (
 			info.valid |= ACPI_VALID_ADR;
 		}
 
+		/* Execute the Device._sx_d methods */
+
+		status = acpi_ut_execute_sxds (node, info.highest_dstates);
+		if (ACPI_SUCCESS (status)) {
+			info.valid |= ACPI_VALID_STA;
+		}
+
 		status = AE_OK;
 	}
 
--- diff/drivers/acpi/pci_link.c	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/acpi/pci_link.c	2004-03-09 11:51:49.000000000 +0000
@@ -768,7 +768,6 @@ __setup("acpi_irq_pci=", acpi_irq_pci);
 
 static int __init acpi_irq_nobalance_set(char *str)
 {
-printk("ACPI STATIC SET\n");
 	acpi_irq_balance = 0;
 	return(1);
 }
@@ -776,7 +775,6 @@ __setup("acpi_irq_nobalance", acpi_irq_n
 
 int __init acpi_irq_balance_set(char *str)
 {
-printk("ACPI BALANCE SET\n");
 	acpi_irq_balance = 1;
 	return(1);
 }
--- diff/drivers/acpi/power.c	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/acpi/power.c	2004-03-09 11:51:49.000000000 +0000
@@ -23,6 +23,18 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
+/*
+ * ACPI power-managed devices may be controlled in two ways:
+ * 1. via "Device Specific (D-State) Control"
+ * 2. via "Power Resource Control".
+ * This module is used to manage devices relying on Power Resource Control.
+ * 
+ * An ACPI "power resource object" describes a software controllable power
+ * plane, clock plane, or other resource used by a power managed device.
+ * A device may rely on multiple power resources, and a power resource
+ * may be shared by multiple devices.
+ */
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
--- diff/drivers/acpi/resources/rsxface.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/resources/rsxface.c	2004-03-09 11:51:49.000000000 +0000
@@ -239,6 +239,7 @@ acpi_walk_resources (
 	acpi_status                         status;
 	struct acpi_buffer                  buffer = {ACPI_ALLOCATE_BUFFER, NULL};
 	struct acpi_resource                *resource;
+	struct acpi_resource                *buffer_end;
 
 
 	ACPI_FUNCTION_TRACE ("acpi_walk_resources");
@@ -255,7 +256,13 @@ acpi_walk_resources (
 		return_ACPI_STATUS (status);
 	}
 
-	resource = (struct acpi_resource *) buffer.pointer;
+	/* Setup pointers */
+
+	resource  = (struct acpi_resource *) buffer.pointer;
+	buffer_end = (struct acpi_resource *) ((u8 *) buffer.pointer + buffer.length);
+
+	/* Walk the resource list */
+
 	for (;;) {
 		if (!resource || resource->id == ACPI_RSTYPE_END_TAG) {
 			break;
@@ -268,6 +275,7 @@ acpi_walk_resources (
 		case AE_CTRL_DEPTH:
 
 			/* Just keep going */
+
 			status = AE_OK;
 			break;
 
@@ -285,7 +293,15 @@ acpi_walk_resources (
 			goto cleanup;
 		}
 
+		/* Get the next resource descriptor */
+
 		resource = ACPI_NEXT_RESOURCE (resource);
+
+		/* Check for end-of-buffer */
+
+		if (resource >= buffer_end) {
+			goto cleanup;
+		}
 	}
 
 cleanup:
--- diff/drivers/acpi/tables.c	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/acpi/tables.c	2004-03-09 11:51:49.000000000 +0000
@@ -58,6 +58,7 @@ static char *acpi_table_signatures[ACPI_
 	[ACPI_SSDT]		= "SSDT",
 	[ACPI_SPMI]		= "SPMI",
 	[ACPI_HPET]		= "HPET",
+	[ACPI_MCFG]		= "MCFG",
 };
 
 static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" };
@@ -550,6 +551,14 @@ acpi_table_get_sdt (
 	return 0;
 }
 
+/*
+ * acpi_table_init()
+ *
+ * find RSDP, find and checksum SDT/XSDT.
+ * checksum all tables, print SDT/XSDT
+ * 
+ * result: sdt_entry[] is initialized
+ */
 
 int __init
 acpi_table_init (void)
--- diff/drivers/acpi/utilities/uteval.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/utilities/uteval.c	2004-03-09 11:51:49.000000000 +0000
@@ -562,3 +562,63 @@ acpi_ut_execute_STA (
 	acpi_ut_remove_reference (obj_desc);
 	return_ACPI_STATUS (status);
 }
+
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_execute_Sxds
+ *
+ * PARAMETERS:  device_node         - Node for the device
+ *              *Flags              - Where the status flags are returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Executes _STA for selected device and stores results in
+ *              *Flags.
+ *
+ *              NOTE: Internal function, no parameter validation
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_execute_sxds (
+	struct acpi_namespace_node      *device_node,
+	u8                              *highest)
+{
+	union acpi_operand_object       *obj_desc;
+	acpi_status                     status;
+	u32                             i;
+
+
+	ACPI_FUNCTION_TRACE ("ut_execute_Sxds");
+
+
+	for (i = 0; i < 4; i++) {
+		highest[i] = 0xFF;
+		status = acpi_ut_evaluate_object (device_node,
+				 (char *) acpi_gbl_highest_dstate_names[i],
+				 ACPI_BTYPE_INTEGER, &obj_desc);
+		if (ACPI_FAILURE (status)) {
+			if (status != AE_NOT_FOUND) {
+				ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+					"%s on Device %4.4s, %s\n",
+					(char *) acpi_gbl_highest_dstate_names[i],
+					acpi_ut_get_node_name (device_node),
+					acpi_format_exception (status)));
+
+				return_ACPI_STATUS (status);
+			}
+		}
+		else {
+			/* Extract the Dstate value */
+
+			highest[i] = (u8) obj_desc->integer.value;
+
+			/* Delete the return object */
+
+			acpi_ut_remove_reference (obj_desc);
+		}
+	}
+
+	return_ACPI_STATUS (AE_OK);
+}
--- diff/drivers/acpi/utilities/utglobal.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/utilities/utglobal.c	2004-03-09 11:51:49.000000000 +0000
@@ -171,7 +171,7 @@ u8                                  acpi
 
 const u8                            acpi_gbl_decode_to8bit [8] = {1,2,4,8,16,32,64,128};
 
-const char                          *acpi_gbl_db_sleep_states[ACPI_S_STATE_COUNT] = {
+const char                          *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = {
 			  "\\_S0_",
 			  "\\_S1_",
 			  "\\_S2_",
@@ -179,6 +179,11 @@ const char                          *acp
 			  "\\_S4_",
 			  "\\_S5_"};
 
+const char                          *acpi_gbl_highest_dstate_names[4] = {
+					   "_S1D",
+					   "_S2D",
+					   "_S3D",
+					   "_S4D"};
 
 /******************************************************************************
  *
--- diff/drivers/atm/fore200e.c	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/atm/fore200e.c	2004-03-09 11:51:49.000000000 +0000
@@ -482,11 +482,19 @@ fore200e_pca_dma_unmap(struct fore200e* 
 
 
 static void
-fore200e_pca_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
+fore200e_pca_dma_sync_for_cpu(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
 {
     DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
 
-    pci_dma_sync_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction);
+    pci_dma_sync_single_for_cpu((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction);
+}
+
+static void
+fore200e_pca_dma_sync_for_device(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
+{
+    DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
+
+    pci_dma_sync_single_for_device((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction);
 }
 
 
@@ -761,11 +769,19 @@ fore200e_sba_dma_unmap(struct fore200e* 
 
 
 static void
-fore200e_sba_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
+fore200e_sba_dma_sync_for_cpu(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
 {
     DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
     
-    sbus_dma_sync_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
+    sbus_dma_sync_single_for_cpu((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
+}
+
+static void
+fore200e_sba_dma_sync_for_device(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
+{
+    DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
+
+    sbus_dma_sync_single_for_device((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
 }
 
 
@@ -1149,10 +1165,13 @@ fore200e_push_rpd(struct fore200e* fore2
 	/* rebuild rx buffer address from rsd handle */
 	buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle);
 	
-	/* ensure DMA synchronisation */
-	fore200e->bus->dma_sync(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, FORE200E_DMA_FROMDEVICE);
+	/* Make device DMA transfer visible to CPU.  */
+	fore200e->bus->dma_sync_for_cpu(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, FORE200E_DMA_FROMDEVICE);
 	
 	memcpy(skb_put(skb, rpd->rsd[ i ].length), buffer->data.align_addr, rpd->rsd[ i ].length);
+
+	/* Now let the device get at it again.  */
+	fore200e->bus->dma_sync_for_device(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, FORE200E_DMA_FROMDEVICE);
     }
     
     DPRINTK(3, "rx skb: len = %d, truesize = %d\n", skb->len, skb->truesize);
@@ -1584,8 +1603,9 @@ fore200e_send(struct atm_vcc *vcc, struc
 
     tasklet_enable(&fore200e->tasklet);
 
-    /* ensure DMA synchronisation */
-    fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length, FORE200E_DMA_TODEVICE);
+    /* The dma_map call above implies a dma_sync so the device can use it,
+     * thus no explicit dma_sync call is necessary here.
+     */
     
     DPRINTK(3, "tx on %d.%d.%d:%d, len = %u (%u)\n", 
 	    vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal),
@@ -2918,7 +2938,8 @@ static const struct fore200e_bus fore200
       fore200e_pca_write,
       fore200e_pca_dma_map,
       fore200e_pca_dma_unmap,
-      fore200e_pca_dma_sync,
+      fore200e_pca_dma_sync_for_cpu,
+      fore200e_pca_dma_sync_for_device,
       fore200e_pca_dma_chunk_alloc,
       fore200e_pca_dma_chunk_free,
       fore200e_pca_detect,
@@ -2940,7 +2961,8 @@ static const struct fore200e_bus fore200
       fore200e_sba_write,
       fore200e_sba_dma_map,
       fore200e_sba_dma_unmap,
-      fore200e_sba_dma_sync,
+      fore200e_sba_dma_sync_for_cpu,
+      fore200e_sba_dma_sync_for_device,
       fore200e_sba_dma_chunk_alloc,
       fore200e_sba_dma_chunk_free,
       fore200e_sba_detect, 
--- diff/drivers/atm/fore200e.h	2002-10-16 04:28:23.000000000 +0100
+++ source/drivers/atm/fore200e.h	2004-03-09 11:51:49.000000000 +0000
@@ -801,7 +801,8 @@ typedef struct fore200e_bus {
     void                 (*write)(u32, volatile u32*);
     u32                  (*dma_map)(struct fore200e*, void*, int, int);
     void                 (*dma_unmap)(struct fore200e*, u32, int, int);
-    void                 (*dma_sync)(struct fore200e*, u32, int, int);
+    void                 (*dma_sync_for_cpu)(struct fore200e*, u32, int, int);
+    void                 (*dma_sync_for_device)(struct fore200e*, u32, int, int);
     int                  (*dma_chunk_alloc)(struct fore200e*, struct chunk*, int, int, int);
     void                 (*dma_chunk_free)(struct fore200e*, struct chunk*);
     struct fore200e*     (*detect)(const struct fore200e_bus*, int);
--- diff/drivers/atm/idt77252.c	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/atm/idt77252.c	2004-03-09 11:51:49.000000000 +0000
@@ -1064,8 +1064,8 @@ dequeue_rx(struct idt77252_dev *card, st
 
 	vcc = vc->rx_vcc;
 
-	pci_dma_sync_single(card->pcidev, IDT77252_PRV_PADDR(skb),
-			    skb->end - skb->data, PCI_DMA_FROMDEVICE);
+	pci_dma_sync_single_for_cpu(card->pcidev, IDT77252_PRV_PADDR(skb),
+				    skb->end - skb->data, PCI_DMA_FROMDEVICE);
 
 	if ((vcc->qos.aal == ATM_AAL0) ||
 	    (vcc->qos.aal == ATM_AAL34)) {
@@ -1903,6 +1903,9 @@ recycle_rx_skb(struct idt77252_dev *card
 	u32 handle = IDT77252_PRV_POOL(skb);
 	int err;
 
+	pci_dma_sync_single_for_device(card->pcidev, IDT77252_PRV_PADDR(skb),
+				       skb->end - skb->data, PCI_DMA_FROMDEVICE);
+
 	err = push_rx_skb(card, skb, POOL_QUEUE(handle));
 	if (err) {
 		pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
--- diff/drivers/base/cpu.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/base/cpu.c	2004-03-09 11:51:49.000000000 +0000
@@ -7,6 +7,7 @@
 #include <linux/init.h>
 #include <linux/cpu.h>
 #include <linux/topology.h>
+#include <linux/device.h>
 
 
 struct sysdev_class cpu_sysdev_class = {
@@ -14,6 +15,46 @@ struct sysdev_class cpu_sysdev_class = {
 };
 EXPORT_SYMBOL(cpu_sysdev_class);
 
+#ifdef CONFIG_HOTPLUG_CPU
+static ssize_t show_online(struct sys_device *dev, char *buf)
+{
+	struct cpu *cpu = container_of(dev, struct cpu, sysdev);
+
+	return sprintf(buf, "%u\n", !!cpu_online(cpu->sysdev.id));
+}
+
+static ssize_t store_online(struct sys_device *dev, const char *buf,
+			    size_t count)
+{
+	struct cpu *cpu = container_of(dev, struct cpu, sysdev);
+	ssize_t ret;
+
+	switch (buf[0]) {
+	case '0':
+		ret = cpu_down(cpu->sysdev.id);
+		break;
+	case '1':
+		ret = cpu_up(cpu->sysdev.id);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret >= 0)
+		ret = count;
+	return ret;
+}
+static SYSDEV_ATTR(online, 0600, show_online, store_online);
+
+static void __init register_cpu_control(struct cpu *cpu)
+{
+	sysdev_create_file(&cpu->sysdev, &attr_online);
+}
+#else /* ... !CONFIG_HOTPLUG_CPU */
+static void __init register_cpu_control(struct cpu *cpu)
+{
+}
+#endif /* CONFIG_HOTPLUG_CPU */
 
 /*
  * register_cpu - Setup a driverfs device for a CPU.
@@ -34,6 +75,8 @@ int __init register_cpu(struct cpu *cpu,
 		error = sysfs_create_link(&root->sysdev.kobj,
 					  &cpu->sysdev.kobj,
 					  kobject_name(&cpu->sysdev.kobj));
+	if (!error)
+		register_cpu_control(cpu);
 	return error;
 }
 
--- diff/drivers/block/Kconfig	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/block/Kconfig	2004-03-09 11:51:49.000000000 +0000
@@ -321,6 +321,7 @@ config BLK_DEV_RAM_SIZE
 
 config BLK_DEV_INITRD
 	bool "Initial RAM disk (initrd) support"
+	depends on BLK_DEV_RAM && BLK_DEV_RAM!=m
 	help
 	  The initial RAM disk is a RAM disk that is loaded by the boot loader
 	  (loadlin or lilo) and that is mounted as root before the normal boot
--- diff/drivers/block/Kconfig.iosched	2003-10-09 09:47:16.000000000 +0100
+++ source/drivers/block/Kconfig.iosched	2004-03-09 11:51:49.000000000 +0000
@@ -27,3 +27,10 @@ config IOSCHED_DEADLINE
 	  a disk at any one time, its behaviour is almost identical to the
 	  anticipatory I/O scheduler and so is a good choice.
 
+config IOSCHED_CFQ
+	bool "CFQ I/O scheduler" if EMBEDDED
+	default y
+	---help---
+	  The CFQ I/O scheduler tries to distribute bandwidth equally
+	  among all processes in the system. It should provide a fair
+	  working environment, suitable for desktop systems.
--- diff/drivers/block/Makefile	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/block/Makefile	2004-03-09 11:51:49.000000000 +0000
@@ -18,6 +18,7 @@ obj-y	:= elevator.o ll_rw_blk.o ioctl.o 
 obj-$(CONFIG_IOSCHED_NOOP)	+= noop-iosched.o
 obj-$(CONFIG_IOSCHED_AS)	+= as-iosched.o
 obj-$(CONFIG_IOSCHED_DEADLINE)	+= deadline-iosched.o
+obj-$(CONFIG_IOSCHED_CFQ)	+= cfq-iosched.o
 obj-$(CONFIG_MAC_FLOPPY)	+= swim3.o
 obj-$(CONFIG_BLK_DEV_FD)	+= floppy.o
 obj-$(CONFIG_BLK_DEV_FD98)	+= floppy98.o
--- diff/drivers/block/floppy.c	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/block/floppy.c	2004-03-09 11:51:49.000000000 +0000
@@ -4242,6 +4242,15 @@ int __init floppy_init(void)
 		disks[i] = alloc_disk(1);
 		if (!disks[i])
 			goto Enomem;
+
+		disks[i]->major = FLOPPY_MAJOR;
+		disks[i]->first_minor = TOMINOR(i);
+		disks[i]->fops = &floppy_fops;
+		sprintf(disks[i]->disk_name, "fd%d", i);
+
+		init_timer(&motor_off_timer[i]);
+		motor_off_timer[i].data = i;
+		motor_off_timer[i].function = motor_off_callback;
 	}
 
 	devfs_mk_dir ("floppy");
@@ -4255,13 +4264,6 @@ int __init floppy_init(void)
 		goto fail_queue;
 	}
 
-	for (i=0; i<N_DRIVE; i++) {
-		disks[i]->major = FLOPPY_MAJOR;
-		disks[i]->first_minor = TOMINOR(i);
-		disks[i]->fops = &floppy_fops;
-		sprintf(disks[i]->disk_name, "fd%d", i);
-	}
-
 	blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
 				floppy_find, NULL, NULL);
 
@@ -4366,9 +4368,6 @@ int __init floppy_init(void)
 	}
 	
 	for (drive = 0; drive < N_DRIVE; drive++) {
-		init_timer(&motor_off_timer[drive]);
-		motor_off_timer[drive].data = drive;
-		motor_off_timer[drive].function = motor_off_callback;
 		if (!(allowed_drive_mask & (1 << drive)))
 			continue;
 		if (fdc_state[FDC(drive)].version == FDC_NONE)
--- diff/drivers/block/ll_rw_blk.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/block/ll_rw_blk.c	2004-03-09 11:51:49.000000000 +0000
@@ -27,6 +27,12 @@
 #include <linux/completion.h>
 #include <linux/slab.h>
 #include <linux/swap.h>
+#include <linux/writeback.h>
+
+/*
+ * for max sense size
+ */
+#include <scsi/scsi_cmnd.h>
 
 static void blk_unplug_work(void *data);
 static void blk_unplug_timeout(unsigned long data);
@@ -521,10 +527,10 @@ init_tag_map(request_queue_t *q, struct 
 {
 	int bits, i;
 
-	if (depth > q->nr_requests * 2) {
-		depth = q->nr_requests * 2;
-		printk(KERN_ERR "%s: adjusted depth to %d\n",
-				__FUNCTION__, depth);
+	if (depth > q->nr_requests / 2) {
+		q->nr_requests = depth * 2;
+		printk(KERN_INFO "%s: large TCQ depth: adjusted nr_requests "
+				 "to %lu\n", __FUNCTION__, q->nr_requests);
 	}
 
 	tags->tag_index = kmalloc(depth * sizeof(struct request *), GFP_ATOMIC);
@@ -1136,8 +1142,6 @@ static inline void __generic_unplug_devi
 	if (!blk_remove_plug(q))
 		return;
 
-	del_timer(&q->unplug_timer);
-
 	/*
 	 * was plugged, fire request_fn if queue has stuff to do
 	 */
@@ -1334,6 +1338,8 @@ static elevator_t *chosen_elevator =
 	&iosched_as;
 #elif defined(CONFIG_IOSCHED_DEADLINE)
 	&iosched_deadline;
+#elif defined(CONFIG_IOSCHED_CFQ)
+	&iosched_cfq;
 #elif defined(CONFIG_IOSCHED_NOOP)
 	&elevator_noop;
 #else
@@ -1352,6 +1358,10 @@ static int __init elevator_setup(char *s
 	if (!strcmp(str, "as"))
 		chosen_elevator = &iosched_as;
 #endif
+#ifdef CONFIG_IOSCHED_CFQ
+	if (!strcmp(str, "cfq"))
+		chosen_elevator = &iosched_cfq;
+#endif
 #ifdef CONFIG_IOSCHED_NOOP
 	if (!strcmp(str, "noop"))
 		chosen_elevator = &elevator_noop;
@@ -1757,6 +1767,138 @@ void blk_insert_request(request_queue_t 
 
 EXPORT_SYMBOL(blk_insert_request);
 
+/**
+ * blk_rq_map_user - map user data to a request, for REQ_BLOCK_PC usage
+ * @q:		request queue where request should be inserted
+ * @rw:		READ or WRITE data
+ * @ubuf:	the user buffer
+ * @len:	length of user data
+ *
+ * Description:
+ *    Data will be mapped directly for zero copy io, if possible. Otherwise
+ *    a kernel bounce buffer is used.
+ *
+ *    A matching blk_rq_unmap_user() must be issued at the end of io, while
+ *    still in process context.
+ */
+struct request *blk_rq_map_user(request_queue_t *q, int rw, void __user *ubuf,
+				unsigned int len)
+{
+	struct request *rq = NULL;
+	char *buf = NULL;
+	struct bio *bio;
+
+	rq = blk_get_request(q, rw, __GFP_WAIT);
+	if (!rq)
+		return NULL;
+
+	bio = bio_map_user(q, NULL, (unsigned long) ubuf, len, rw == READ);
+	if (!bio) {
+		buf = kmalloc(len, q->bounce_gfp | GFP_USER);
+		if (!buf)
+			goto fault;
+
+		if (rw == WRITE) {
+			if (copy_from_user(buf, ubuf, len))
+				goto fault;
+		} else
+			memset(buf, 0, len);
+	}
+
+	rq->bio = rq->biotail = bio;
+	if (rq->bio)
+		blk_rq_bio_prep(q, rq, bio);
+
+	rq->buffer = rq->data = buf;
+	rq->data_len = len;
+	return rq;
+fault:
+	if (buf)
+		kfree(buf);
+	if (bio)
+		bio_unmap_user(bio, 1);
+	if (rq)
+		blk_put_request(rq);
+
+	return NULL;
+}
+
+EXPORT_SYMBOL(blk_rq_map_user);
+
+/**
+ * blk_rq_unmap_user - unmap a request with user data
+ * @rq:		request to be unmapped
+ * @ubuf:	user buffer
+ * @ulen:	length of user buffer
+ * @rw:		operation was a READ or WRITE
+ *
+ * Description:
+ *    Unmap a request previously mapped by blk_rq_map_user().
+ */
+int blk_rq_unmap_user(struct request *rq, void __user *ubuf, unsigned int ulen,
+		      int rw)
+{
+	int ret = 0;
+
+	if (rq->biotail)
+		bio_unmap_user(rq->biotail, rw == READ);
+	if (rq->buffer) {
+		if (rw == READ && copy_to_user(ubuf, rq->buffer, ulen))
+			ret = -EFAULT;
+		kfree(rq->buffer);
+	}
+
+	blk_put_request(rq);
+	return ret;
+}
+
+EXPORT_SYMBOL(blk_rq_unmap_user);
+
+/**
+ * blk_execute_rq - insert a request into queue for execution
+ * @q:		queue to insert the request in
+ * @bd_disk:	matching gendisk
+ * @rq:		request to insert
+ *
+ * Description:
+ *    Insert a fully prepared request at the back of the io scheduler queue
+ *    for execution.
+ */
+int blk_execute_rq(request_queue_t *q, struct gendisk *bd_disk,
+		   struct request *rq)
+{
+	DECLARE_COMPLETION(wait);
+	char sense[SCSI_SENSE_BUFFERSIZE];
+	int err = 0;
+
+	rq->rq_disk = bd_disk;
+
+	/*
+	 * we need an extra reference to the request, so we can look at
+	 * it after io completion
+	 */
+	rq->ref_count++;
+
+	if (!rq->sense) {
+		memset(sense, 0, sizeof(sense));
+		rq->sense = sense;
+		rq->sense_len = 0;
+	}
+
+	rq->flags |= REQ_NOMERGE;
+	rq->waiting = &wait;
+	elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
+	generic_unplug_device(q);
+	wait_for_completion(&wait);
+
+	if (rq->errors)
+		err = -EIO;
+
+	return err;
+}
+
+EXPORT_SYMBOL(blk_execute_rq);
+
 void drive_stat_acct(struct request *rq, int nr_sectors, int new_io)
 {
 	int rw = rq_data_dir(rq);
@@ -1884,18 +2026,22 @@ EXPORT_SYMBOL(blk_put_request);
  * Waits for up to @timeout jiffies for a queue (any queue) to exit congestion.
  * If no queues are congested then just wait for the next request to be
  * returned.
+ *
+ * Returns the number of jiffies remaining, this is zero, unless we returned
+ * before @timeout expired.
  */
-void blk_congestion_wait(int rw, long timeout)
+long blk_congestion_wait(int rw, long timeout)
 {
+	long ret;
 	DEFINE_WAIT(wait);
 	wait_queue_head_t *wqh = &congestion_wqh[rw];
 
 	blk_run_queues();
 	prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
-	io_schedule_timeout(timeout);
+	ret = io_schedule_timeout(timeout);
 	finish_wait(wqh, &wait);
+	return ret;
 }
-
 EXPORT_SYMBOL(blk_congestion_wait);
 
 /*
@@ -2305,6 +2451,15 @@ int submit_bio(int rw, struct bio *bio)
 		mod_page_state(pgpgout, count);
 	else
 		mod_page_state(pgpgin, count);
+
+	if (unlikely(block_dump)) {
+		char b[BDEVNAME_SIZE];
+		printk("%s(%d): %s block %Lu on %s\n",
+			current->comm, current->pid,
+			(rw & WRITE) ? "WRITE" : "READ",
+			(unsigned long long)bio->bi_sector, bdevname(bio->bi_bdev,b));
+	}
+
 	generic_make_request(bio);
 	return 1;
 }
@@ -2592,10 +2747,22 @@ void end_that_request_last(struct reques
 		unsigned long duration = jiffies - req->start_time;
 		switch (rq_data_dir(req)) {
 		    case WRITE:
+			/*
+			 * schedule the writeout of pending dirty data when the disk is idle.
+			 * (Writeback is not postponed by writes, only by reads.)
+			 */
+			if (unlikely(laptop_mode))
+				disk_is_spun_up(0);
 			disk_stat_inc(disk, writes);
 			disk_stat_add(disk, write_ticks, duration);
 			break;
 		    case READ:
+			/*
+			 * schedule the writeout of pending dirty data when the disk is idle.
+			 * (postpone writeback until system is quiescent again.)
+			 */
+			if (unlikely(laptop_mode))
+				disk_is_spun_up(1);
 			disk_stat_inc(disk, reads);
 			disk_stat_add(disk, read_ticks, duration);
 			break;
--- diff/drivers/block/loop.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/block/loop.c	2004-03-09 11:51:49.000000000 +0000
@@ -66,6 +66,7 @@
 #include <linux/suspend.h>
 #include <linux/writeback.h>
 #include <linux/buffer_head.h>		/* for invalidate_bdev() */
+#include <linux/completion.h>
 
 #include <asm/uaccess.h>
 
@@ -148,14 +149,12 @@ static struct loop_func_table *xfer_func
 	&xor_funcs
 };
 
-static int
-figure_loop_size(struct loop_device *lo)
+static loff_t get_loop_size(struct loop_device *lo, struct file *file)
 {
 	loff_t size, offset, loopsize;
-	sector_t x;
 
 	/* Compute loopsize in bytes */
-	size = i_size_read(lo->lo_backing_file->f_mapping->host);
+	size = i_size_read(file->f_mapping->host);
 	offset = lo->lo_offset;
 	loopsize = size - offset;
 	if (lo->lo_sizelimit > 0 && lo->lo_sizelimit < loopsize)
@@ -165,8 +164,14 @@ figure_loop_size(struct loop_device *lo)
 	 * Unfortunately, if we want to do I/O on the device,
 	 * the number of 512-byte sectors has to fit into a sector_t.
 	 */
-	size = loopsize >> 9;
-	x = (sector_t)size;
+	return loopsize >> 9;
+}
+
+static int
+figure_loop_size(struct loop_device *lo)
+{
+	loff_t size = get_loop_size(lo, lo->lo_backing_file);
+	sector_t x = (sector_t)size;
 
 	if ((loff_t)x != size)
 		return -EFBIG;
@@ -429,12 +434,24 @@ inactive:
 	goto out;
 }
 
+struct switch_request {
+	struct file *file;
+	struct completion wait;
+};
+
+static void do_loop_switch(struct loop_device *, struct switch_request *);
+
 static inline void loop_handle_bio(struct loop_device *lo, struct bio *bio)
 {
 	int ret;
 
-	ret = do_bio_filebacked(lo, bio);
-	bio_endio(bio, bio->bi_size, ret);
+	if (unlikely(!bio->bi_bdev)) {
+		do_loop_switch(lo, bio->bi_private);
+		bio_put(bio);
+	} else {
+		ret = do_bio_filebacked(lo, bio);
+		bio_endio(bio, bio->bi_size, ret);
+	}
 }
 
 /*
@@ -495,6 +512,103 @@ static int loop_thread(void *data)
 	return 0;
 }
 
+/*
+ * loop_switch performs the hard work of switching a backing store.
+ * First it needs to flush existing IO, it does this by sending a magic
+ * BIO down the pipe. The completion of this BIO does the actual switch.
+ */
+static int loop_switch(struct loop_device *lo, struct file *file)
+{
+	struct switch_request w;
+	struct bio *bio = bio_alloc(GFP_KERNEL, 1);
+	if (!bio)
+		return -ENOMEM;
+	init_completion(&w.wait);
+	w.file = file;
+	bio->bi_private = &w;
+	bio->bi_bdev = NULL;
+	loop_make_request(lo->lo_queue, bio);
+	wait_for_completion(&w.wait);
+	return 0;
+}
+
+/*
+ * Do the actual switch; called from the BIO completion routine
+ */
+static void do_loop_switch(struct loop_device *lo, struct switch_request *p)
+{
+	struct file *file = p->file;
+	struct file *old_file = lo->lo_backing_file;
+	struct address_space *mapping = file->f_mapping;
+
+	mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask);
+	lo->lo_backing_file = file;
+	lo->lo_blocksize = mapping->host->i_blksize;
+	lo->old_gfp_mask = mapping_gfp_mask(mapping);
+	mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
+	complete(&p->wait);
+}
+
+
+/*
+ * loop_change_fd switched the backing store of a loopback device to
+ * a new file. This is useful for operating system installers to free up
+ * the original file and in High Availability environments to switch to
+ * an alternative location for the content in case of server meltdown.
+ * This can only work if the loop device is used read-only, and if the
+ * new backing store is the same size and type as the old backing store.
+ */
+static int loop_change_fd(struct loop_device *lo, struct file *lo_file,
+		       struct block_device *bdev, unsigned int arg)
+{
+	struct file	*file, *old_file;
+	struct inode	*inode;
+	int		error;
+
+	error = -ENXIO;
+	if (lo->lo_state != Lo_bound)
+		goto out;
+
+	/* the loop device has to be read-only */
+	error = -EINVAL;
+	if (lo->lo_flags != LO_FLAGS_READ_ONLY)
+		goto out;
+
+	error = -EBADF;
+	file = fget(arg);
+	if (!file)
+		goto out;
+
+	inode = file->f_mapping->host;
+	old_file = lo->lo_backing_file;
+
+	error = -EINVAL;
+
+	if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))
+		goto out_putf;
+
+	/* new backing store needs to support loop (eg sendfile) */
+	if (!inode->i_fop->sendfile)
+		goto out_putf;
+
+	/* size of the new backing store needs to be the same */
+	if (get_loop_size(lo, file) != get_loop_size(lo, old_file))
+		goto out_putf;
+
+	/* and ... switch */
+	error = loop_switch(lo, file);
+	if (error)
+		goto out_putf;
+
+	fput(old_file);
+	return 0;
+
+ out_putf:
+	fput(file);
+ out:
+	return error;
+}
+
 static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
 		       struct block_device *bdev, unsigned int arg)
 {
@@ -505,6 +619,7 @@ static int loop_set_fd(struct loop_devic
 	unsigned lo_blocksize;
 	int		lo_flags = 0;
 	int		error;
+	loff_t		size;
 
 	/* This is safe, since we have a reference from open(). */
 	__module_get(THIS_MODULE);
@@ -543,6 +658,13 @@ static int loop_set_fd(struct loop_devic
 		goto out_putf;
 	}
 
+	size = get_loop_size(lo, file);
+
+	if ((loff_t)(sector_t)size != size) {
+		error = -EFBIG;
+		goto out_putf;
+	}
+
 	if (!(lo_file->f_mode & FMODE_WRITE))
 		lo_flags |= LO_FLAGS_READ_ONLY;
 
@@ -555,10 +677,7 @@ static int loop_set_fd(struct loop_devic
 	lo->transfer = NULL;
 	lo->ioctl = NULL;
 	lo->lo_sizelimit = 0;
-	if (figure_loop_size(lo)) {
-		error = -EFBIG;
-		goto out_putf;
-	}
+	bd_set_size(bdev,(loff_t)get_capacity(disks[lo->lo_number])<<9);
 	lo->old_gfp_mask = mapping_gfp_mask(mapping);
 	mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
 
@@ -571,6 +690,8 @@ static int loop_set_fd(struct loop_devic
 	blk_queue_make_request(lo->lo_queue, loop_make_request);
 	lo->lo_queue->queuedata = lo;
 
+	set_capacity(disks[lo->lo_number], size);
+
 	set_blocksize(bdev, lo_blocksize);
 
 	kernel_thread(loop_thread, lo, CLONE_KERNEL);
@@ -660,6 +781,7 @@ static int loop_clr_fd(struct loop_devic
 	memset(lo->lo_file_name, 0, LO_NAME_SIZE);
 	invalidate_bdev(bdev, 0);
 	set_capacity(disks[lo->lo_number], 0);
+	bd_set_size(bdev, 0);
 	mapping_set_gfp_mask(filp->f_mapping, gfp);
 	lo->lo_state = Lo_unbound;
 	fput(filp);
@@ -881,6 +1003,9 @@ static int lo_ioctl(struct inode * inode
 	case LOOP_SET_FD:
 		err = loop_set_fd(lo, file, inode->i_bdev, arg);
 		break;
+	case LOOP_CHANGE_FD:
+		err = loop_change_fd(lo, file, inode->i_bdev, arg);
+		break;
 	case LOOP_CLR_FD:
 		err = loop_clr_fd(lo, inode->i_bdev);
 		break;
--- diff/drivers/block/rd.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/block/rd.c	2004-03-09 11:51:49.000000000 +0000
@@ -316,6 +316,7 @@ static void __exit rd_cleanup(void)
 		}
 		del_gendisk(rd_disks[i]);
 		put_disk(rd_disks[i]);
+		blk_cleanup_queue(rd_queue[i]);
 	}
 	devfs_remove("rd");
 	unregister_blkdev(RAMDISK_MAJOR, "ramdisk");
@@ -379,8 +380,10 @@ static int __init rd_init(void)
 out_queue:
 	unregister_blkdev(RAMDISK_MAJOR, "ramdisk");
 out:
-	while (i--)
+	while (i--) {
 		put_disk(rd_disks[i]);
+		blk_cleanup_queue(rd_queue[i]);
+	}
 	return err;
 }
 
--- diff/drivers/block/scsi_ioctl.c	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/block/scsi_ioctl.c	2004-03-09 11:51:49.000000000 +0000
@@ -30,7 +30,7 @@
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_ioctl.h>
-
+#include <scsi/scsi_cmnd.h>
 
 /* Command group 3 is reserved and should never be used.  */
 const unsigned char scsi_command_size[8] =
@@ -41,44 +41,6 @@ const unsigned char scsi_command_size[8]
 
 #define BLK_DEFAULT_TIMEOUT	(60 * HZ)
 
-/* defined in ../scsi/scsi.h  ... should it be included? */
-#ifndef SCSI_SENSE_BUFFERSIZE
-#define SCSI_SENSE_BUFFERSIZE 64
-#endif
-
-static int blk_do_rq(request_queue_t *q, struct gendisk *bd_disk,
-		     struct request *rq)
-{
-	char sense[SCSI_SENSE_BUFFERSIZE];
-	DECLARE_COMPLETION(wait);
-	int err = 0;
-
-	rq->rq_disk = bd_disk;
-
-	/*
-	 * we need an extra reference to the request, so we can look at
-	 * it after io completion
-	 */
-	rq->ref_count++;
-
-	if (!rq->sense) {
-		memset(sense, 0, sizeof(sense));
-		rq->sense = sense;
-		rq->sense_len = 0;
-	}
-
-	rq->flags |= REQ_NOMERGE;
-	rq->waiting = &wait;
-	elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
-	generic_unplug_device(q);
-	wait_for_completion(&wait);
-
-	if (rq->errors)
-		err = -EIO;
-
-	return err;
-}
-
 #include <scsi/sg.h>
 
 static int sg_get_version(int *p)
@@ -246,7 +208,7 @@ static int sg_io(request_queue_t *q, str
 	 * (if he doesn't check that is his problem).
 	 * N.B. a non-zero SCSI status is _not_ necessarily an error.
 	 */
-	blk_do_rq(q, bd_disk, rq);
+	blk_execute_rq(q, bd_disk, rq);
 
 	if (bio)
 		bio_unmap_user(bio, reading);
@@ -312,7 +274,7 @@ static int sg_scsi_ioctl(request_queue_t
 		return -EFAULT;
 	if (in_len > PAGE_SIZE || out_len > PAGE_SIZE)
 		return -EINVAL;
-	if (get_user(opcode, sic->data))
+	if (get_user(opcode, (int *)sic->data))
 		return -EFAULT;
 
 	bytes = max(in_len, out_len);
@@ -369,7 +331,7 @@ static int sg_scsi_ioctl(request_queue_t
 	rq->data_len = bytes;
 	rq->flags |= REQ_BLOCK_PC;
 
-	blk_do_rq(q, bd_disk, rq);
+	blk_execute_rq(q, bd_disk, rq);
 	err = rq->errors & 0xff;	/* only 8 bit SCSI status */
 	if (err) {
 		if (rq->sense_len && rq->sense) {
@@ -529,7 +491,7 @@ int scsi_cmd_ioctl(struct gendisk *bd_di
 			rq->cmd[0] = GPCMD_START_STOP_UNIT;
 			rq->cmd[4] = 0x02 + (close != 0);
 			rq->cmd_len = 6;
-			err = blk_do_rq(q, bd_disk, rq);
+			err = blk_execute_rq(q, bd_disk, rq);
 			blk_put_request(rq);
 			break;
 		default:
--- diff/drivers/bluetooth/hci_usb.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/bluetooth/hci_usb.c	2004-03-09 11:51:49.000000000 +0000
@@ -31,7 +31,7 @@
  *
  * $Id: hci_usb.c,v 1.8 2002/07/18 17:23:09 maxk Exp $    
  */
-#define VERSION "2.4"
+#define VERSION "2.5"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -70,12 +70,6 @@
 static struct usb_driver hci_usb_driver; 
 
 static struct usb_device_id bluetooth_ids[] = {
-	/* Broadcom BCM2033 without firmware */
-	{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE },
-
-	/* Digianswer device */
-	{ USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER },
-
 	/* Generic Bluetooth USB device */
 	{ USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) },
 
@@ -93,6 +87,19 @@ static struct usb_device_id bluetooth_id
 
 MODULE_DEVICE_TABLE (usb, bluetooth_ids);
 
+static struct usb_device_id blacklist_ids[] = {
+	/* Broadcom BCM2033 without firmware */
+	{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE },
+
+	/* Broadcom BCM2035 */
+	{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET },
+
+	/* Digianswer device */
+	{ USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER },
+
+	{ }     /* Terminating entry */
+};
+
 struct _urb *_urb_alloc(int isoc, int gfp)
 {
 	struct _urb *_urb = kmalloc(sizeof(struct _urb) +
@@ -644,7 +651,7 @@ static inline int __recv_frame(struct hc
 #endif
 			}
 			BT_DBG("new packet len %d", len);
-				
+
 			skb = bt_skb_alloc(len, GFP_ATOMIC);
 			if (!skb) {
 				BT_ERR("%s no memory for the packet", husb->hdev->name);
@@ -790,6 +797,13 @@ int hci_usb_probe(struct usb_interface *
 
 	BT_DBG("udev %p ifnum %d", udev, ifnum);
 
+	if (!id->driver_info) {
+		const struct usb_device_id *match;
+		match = usb_match_id(intf, blacklist_ids);
+		if (match)
+			id = match;
+	}
+
 	iface = udev->actconfig->interface[0];
 
 	if (id->driver_info & HCI_IGNORE)
@@ -928,6 +942,9 @@ int hci_usb_probe(struct usb_interface *
 
 	hdev->owner = THIS_MODULE;
 
+	if (id->driver_info & HCI_RESET)
+		set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
+
 	if (hci_register_dev(hdev) < 0) {
 		BT_ERR("Can't register HCI device");
 		hci_free_dev(hdev);
@@ -994,6 +1011,6 @@ void hci_usb_cleanup(void)
 module_init(hci_usb_init);
 module_exit(hci_usb_cleanup);
 
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth HCI USB driver ver " VERSION);
 MODULE_LICENSE("GPL");
--- diff/drivers/bluetooth/hci_usb.h	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/bluetooth/hci_usb.h	2004-03-09 11:51:49.000000000 +0000
@@ -38,7 +38,8 @@
 #define HCI_DIGI_REQ	     0x40
 
 #define HCI_IGNORE           0x01
-#define HCI_DIGIANSWER       0x02
+#define HCI_RESET            0x02
+#define HCI_DIGIANSWER       0x04
 
 #define HCI_MAX_IFACE_NUM	3 
 
--- diff/drivers/cdrom/Makefile	2003-02-13 11:46:51.000000000 +0000
+++ source/drivers/cdrom/Makefile	2004-03-09 11:51:49.000000000 +0000
@@ -20,3 +20,4 @@ obj-$(CONFIG_OPTCD)		+= optcd.o
 obj-$(CONFIG_SBPCD)		+= sbpcd.o      cdrom.o
 obj-$(CONFIG_SJCD)		+= sjcd.o
 obj-$(CONFIG_CDU535)		+= sonycd535.o
+obj-$(CONFIG_VIOCD)		+= viocd.o      cdrom.o
--- diff/drivers/cdrom/cdrom.c	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/cdrom/cdrom.c	2004-03-09 11:51:49.000000000 +0000
@@ -406,6 +406,11 @@ int register_cdrom(struct cdrom_device_i
 	if (CDROM_CAN(CDC_MRW_W))
 		cdi->exit = cdrom_mrw_exit;
 
+	if (cdi->disk)
+		cdi->cdda_method = CDDA_BPC_FULL;
+	else
+		cdi->cdda_method = CDDA_OLD;
+
 	cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
 	spin_lock(&cdrom_lock);
 	cdi->next = topCdromPtr; 	
@@ -1788,6 +1793,143 @@ static int cdrom_read_block(struct cdrom
 	return cdo->generic_packet(cdi, cgc);
 }
 
+static int cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf,
+			       int lba, int nframes)
+{
+	struct cdrom_generic_command cgc;
+	int nr, ret;
+
+	memset(&cgc, 0, sizeof(cgc));
+
+	/*
+	 * start with will ra.nframes size, back down if alloc fails
+	 */
+	nr = nframes;
+	do {
+		cgc.buffer = kmalloc(CD_FRAMESIZE_RAW * nr, GFP_KERNEL);
+		if (cgc.buffer)
+			break;
+
+		nr >>= 1;
+	} while (nr);
+
+	if (!nr)
+		return -ENOMEM;
+
+	if (!access_ok(VERIFY_WRITE, ubuf, nframes * CD_FRAMESIZE_RAW)) {
+		kfree(cgc.buffer);
+		return -EFAULT;
+	}
+
+	cgc.data_direction = CGC_DATA_READ;
+	while (nframes > 0) {
+		if (nr > nframes)
+			nr = nframes;
+
+		ret = cdrom_read_block(cdi, &cgc, lba, nr, 1, CD_FRAMESIZE_RAW);
+		if (ret)
+			break;
+		__copy_to_user(ubuf, cgc.buffer, CD_FRAMESIZE_RAW * nr);
+		ubuf += CD_FRAMESIZE_RAW * nr;
+		nframes -= nr;
+		lba += nr;
+	}
+	kfree(cgc.buffer);
+	return 0;
+}
+
+static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
+			       int lba, int nframes)
+{
+	request_queue_t *q = cdi->disk->queue;
+	struct request *rq;
+	unsigned int len;
+	int nr, ret = 0;
+
+	if (!q)
+		return -ENXIO;
+
+	while (nframes) {
+		nr = nframes;
+		if (cdi->cdda_method == CDDA_BPC_SINGLE)
+			nr = 1;
+		if (nr * CD_FRAMESIZE_RAW > (q->max_sectors << 9))
+			nr = (q->max_sectors << 9) / CD_FRAMESIZE_RAW;
+
+		len = nr * CD_FRAMESIZE_RAW;
+
+		rq = blk_rq_map_user(q, READ, ubuf, len);
+		if (!rq)
+			return -ENOMEM;
+
+		memset(rq->cmd, 0, sizeof(rq->cmd));
+		rq->cmd[0] = GPCMD_READ_CD;
+		rq->cmd[1] = 1 << 2;
+		rq->cmd[2] = (lba >> 24) & 0xff;
+		rq->cmd[3] = (lba >> 16) & 0xff;
+		rq->cmd[4] = (lba >>  8) & 0xff;
+		rq->cmd[5] = lba & 0xff;
+		rq->cmd[6] = (nr >> 16) & 0xff;
+		rq->cmd[7] = (nr >>  8) & 0xff;
+		rq->cmd[8] = nr & 0xff;
+		rq->cmd[9] = 0xf8;
+
+		rq->cmd_len = 12;
+		rq->flags |= REQ_BLOCK_PC;
+		rq->timeout = 60 * HZ;
+
+		if (blk_execute_rq(q, cdi->disk, rq)) {
+			struct request_sense *s = rq->sense;
+			ret = -EIO;
+			printk("cdrom: cdda rip sense %02x/%02x/%02x\n", s->sense_key, s->asc, s->ascq);
+		}
+
+		if (blk_rq_unmap_user(rq, ubuf, len, READ))
+			ret = -EFAULT;
+
+		if (ret)
+			break;
+
+		nframes -= nr;
+		lba += nr;
+	}
+
+	return ret;
+}
+
+static int cdrom_read_cdda(struct cdrom_device_info *cdi, __u8 __user *ubuf,
+			   int lba, int nframes)
+{
+	int ret;
+
+	if (cdi->cdda_method == CDDA_OLD)
+		return cdrom_read_cdda_old(cdi, ubuf, lba, nframes);
+
+	do {
+		ret = cdrom_read_cdda_bpc(cdi, ubuf, lba, nframes);
+
+		if (!ret)
+			break;
+
+		/*
+		 * I've seen drives get sense 4/8/3 udma crc errors on multi
+		 * frame dma, so drop to single frame dma if we need to
+		 */
+		if (cdi->cdda_method == CDDA_BPC_FULL && nframes > 1) {
+			printk("cdrom: dropping to single frame dma\n");
+			cdi->cdda_method = CDDA_BPC_SINGLE;
+			continue;
+		}
+
+		printk("cdrom: dropping to old style cdda\n");
+		cdi->cdda_method = CDDA_OLD;
+		ret = cdrom_read_cdda_old(cdi, ubuf, lba, nframes);
+		break;
+	} while (1);
+
+	return ret;
+}
+
 /* Just about every imaginable ioctl is supported in the Uniform layer
  * these days. ATAPI / SCSI specific code now mainly resides in
  * mmc_ioct().
@@ -2280,7 +2422,7 @@ static int mmc_ioctl(struct cdrom_device
 		}
 	case CDROMREADAUDIO: {
 		struct cdrom_read_audio ra;
-		int lba, nr;
+		int lba;
 
 		IOCTL_IN(arg, struct cdrom_read_audio, ra);
 
@@ -2297,40 +2439,7 @@ static int mmc_ioctl(struct cdrom_device
 		if (lba < 0 || ra.nframes <= 0 || ra.nframes > CD_FRAMES)
 			return -EINVAL;
 
-		/*
-		 * start with will ra.nframes size, back down if alloc fails
-		 */
-		nr = ra.nframes;
-		do {
-			cgc.buffer = kmalloc(CD_FRAMESIZE_RAW * nr, GFP_KERNEL);
-			if (cgc.buffer)
-				break;
-
-			nr >>= 1;
-		} while (nr);
-
-		if (!nr)
-			return -ENOMEM;
-
-		if (!access_ok(VERIFY_WRITE, ra.buf, ra.nframes*CD_FRAMESIZE_RAW)) {
-			kfree(cgc.buffer);
-			return -EFAULT;
-		}
-		cgc.data_direction = CGC_DATA_READ;
-		while (ra.nframes > 0) {
-			if (nr > ra.nframes)
-				nr = ra.nframes;
-
-			ret = cdrom_read_block(cdi, &cgc, lba, nr, 1, CD_FRAMESIZE_RAW);
-			if (ret)
-				break;
-			__copy_to_user(ra.buf, cgc.buffer, CD_FRAMESIZE_RAW*nr);
-			ra.buf += CD_FRAMESIZE_RAW * nr;
-			ra.nframes -= nr;
-			lba += nr;
-		}
-		kfree(cgc.buffer);
-		return ret;
+		return cdrom_read_cdda(cdi, ra.buf, lba, ra.nframes);
 		}
 	case CDROMSUBCHNL: {
 		struct cdrom_subchnl q;
--- diff/drivers/char/Kconfig	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/char/Kconfig	2004-03-09 11:51:49.000000000 +0000
@@ -599,30 +599,6 @@ config PC9800_OLDLP_CONSOLE
 	bool "Support for console on line printer"
 	depends on PC9800_OLDLP
 
-
-menu "Mice"
-
-config BUSMOUSE
-	tristate "Bus Mouse Support"
-	---help---
-	  Say Y here if your machine has a bus mouse as opposed to a serial
-	  mouse. Most people have a regular serial MouseSystem or
-	  Microsoft mouse (made by Logitech) that plugs into a COM port
-	  (rectangular with 9 or 25 pins). These people say N here. 
-
-	  If you have a laptop, you either have to check the documentation or
-	  experiment a bit to find out whether the trackball is a serial mouse
-	  or not; it's best to say Y here for you.
-
-	  This is the generic bus mouse driver code. If you have a bus mouse,
-	  you will have to say Y here and also to the specific driver for your
-	  mouse below.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called busmouse.
-
-endmenu
-
 config QIC02_TAPE
 	tristate "QIC-02 tape support"
 	help
--- diff/drivers/char/Makefile	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/Makefile	2004-03-09 11:51:49.000000000 +0000
@@ -49,7 +49,6 @@ obj-$(CONFIG_PRINTER) += lp.o
 obj-$(CONFIG_TIPAR) += tipar.o
 obj-$(CONFIG_PC9800_OLDLP) += lp_old98.o
 
-obj-$(CONFIG_BUSMOUSE) += busmouse.o
 obj-$(CONFIG_DTLK) += dtlk.o
 obj-$(CONFIG_R3964) += n_r3964.o
 obj-$(CONFIG_APPLICOM) += applicom.o
--- diff/drivers/char/drm/Kconfig	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/char/drm/Kconfig	2004-03-09 11:51:49.000000000 +0000
@@ -76,7 +76,7 @@ config DRM_SIS
 	tristate "SiS video cards"
 	depends on DRM && AGP
 	help
-	  Choose this option if you have a SiS 630 or compatibel video 
+	  Choose this option if you have a SiS 630 or compatible video 
           chipset. If M is selected the module will be called sis. AGP
           support is required for this driver to work.
 
--- diff/drivers/char/drm/drm.h	2003-07-22 18:54:27.000000000 +0100
+++ source/drivers/char/drm/drm.h	2004-03-09 11:51:49.000000000 +0000
@@ -580,6 +580,16 @@ typedef struct drm_scatter_gather {
 	unsigned long handle;	/**< Used for mapping / unmapping */
 } drm_scatter_gather_t;
 
+/**
+ * DRM_IOCTL_SET_VERSION ioctl argument type.
+ */
+typedef struct drm_set_version {
+	int drm_di_major;
+	int drm_di_minor;
+	int drm_dd_major;
+	int drm_dd_minor;
+} drm_set_version_t;
+
 
 #define DRM_IOCTL_BASE			'd'
 #define DRM_IO(nr)			_IO(DRM_IOCTL_BASE,nr)
@@ -594,6 +604,7 @@ typedef struct drm_scatter_gather {
 #define DRM_IOCTL_GET_MAP               DRM_IOWR(0x04, drm_map_t)
 #define DRM_IOCTL_GET_CLIENT            DRM_IOWR(0x05, drm_client_t)
 #define DRM_IOCTL_GET_STATS             DRM_IOR( 0x06, drm_stats_t)
+#define DRM_IOCTL_SET_VERSION		DRM_IOWR(0x07, drm_set_version_t)
 
 #define DRM_IOCTL_SET_UNIQUE		DRM_IOW( 0x10, drm_unique_t)
 #define DRM_IOCTL_AUTH_MAGIC		DRM_IOW( 0x11, drm_auth_t)
--- diff/drivers/char/drm/drmP.h	2004-01-19 10:22:56.000000000 +0000
+++ source/drivers/char/drm/drmP.h	2004-03-09 11:51:49.000000000 +0000
@@ -92,8 +92,8 @@
 #ifndef __HAVE_DMA
 #define __HAVE_DMA		0
 #endif
-#ifndef __HAVE_DMA_IRQ
-#define __HAVE_DMA_IRQ		0
+#ifndef __HAVE_IRQ
+#define __HAVE_IRQ		0
 #endif
 #ifndef __HAVE_DMA_WAITLIST
 #define __HAVE_DMA_WAITLIST	0
@@ -324,6 +324,7 @@ do {											\
 #define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x))
 #define DRM_WAITCOUNT(dev,idx) DRM_BUFCOUNT(&dev->queuelist[idx]->waitlist)
 
+#define DRM_IF_VERSION(maj, min) ((maj) << 16 | (min))
 /**
  * Get the private SAREA mapping.
  *
@@ -362,10 +363,13 @@ do {									\
 typedef int drm_ioctl_t( struct inode *inode, struct file *filp,
 			 unsigned int cmd, unsigned long arg );
 
-typedef struct drm_pci_list {
-	u16 vendor;
-	u16 device;
-} drm_pci_list_t;
+typedef struct drm_pci_id_list
+{
+	int vendor;
+	int device;
+	long driver_private;
+	char *name;
+} drm_pci_id_list_t;
 
 typedef struct drm_ioctl_desc {
 	drm_ioctl_t	     *func;
@@ -488,6 +492,9 @@ typedef struct drm_file {
 	struct drm_device *dev;
 	int 		  remove_auth_on_close;
 	unsigned long     lock_count;
+#ifdef DRIVER_FILE_FIELDS
+	DRIVER_FILE_FIELDS;
+#endif
 } drm_file_t;
 
 /** Wait queue */
@@ -622,6 +629,8 @@ typedef struct drm_device {
 	int		  unique_len;	/**< Length of unique field */
 	dev_t		  device;	/**< Device number for mknod */
 	char		  *devname;	/**< For /proc/interrupts */
+	int		  minor;        /**< Minor device number */
+	int		  if_version;	/**< Highest interface version set */
 
 	int		  blocked;	/**< Blocked due to VC switch? */
 	struct proc_dir_entry *root;	/**< Root for this device's entries */
@@ -679,6 +688,7 @@ typedef struct drm_device {
 	/** \name Context support */
 	/*@{*/
 	int		  irq;		/**< Interrupt used by board */
+	int		  irq_enabled;	/**< True if irq handler is enabled */
 	__volatile__ long context_flag;	/**< Context swapping flag */
 	__volatile__ long interrupt_flag; /**< Interruption handler flag */
 	__volatile__ long dma_flag;	/**< DMA dispatch flag */
@@ -714,7 +724,12 @@ typedef struct drm_device {
 #if __REALLY_HAVE_AGP
 	drm_agp_head_t    *agp;	/**< AGP data */
 #endif
-	struct pci_dev *pdev;		/**< PCI device structure */
+
+	struct pci_dev    *pdev;	/**< PCI device structure */
+	int               pci_domain;	/**< PCI bus domain number */
+	int               pci_bus;	/**< PCI bus number */
+	int               pci_slot;	/**< PCI slot number */
+	int               pci_func;	/**< PCI function number */
 #ifdef __alpha__
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3)
 	struct pci_controler *hose;
@@ -804,8 +819,8 @@ extern int           DRM(unbind_agp)(DRM
 #endif
 
 				/* Misc. IOCTL support (drm_ioctl.h) */
-extern int	     DRM(irq_busid)(struct inode *inode, struct file *filp,
-				    unsigned int cmd, unsigned long arg);
+extern int	     DRM(irq_by_busid)(struct inode *inode, struct file *filp,
+				       unsigned int cmd, unsigned long arg);
 extern int	     DRM(getunique)(struct inode *inode, struct file *filp,
 				    unsigned int cmd, unsigned long arg);
 extern int	     DRM(setunique)(struct inode *inode, struct file *filp,
@@ -816,6 +831,8 @@ extern int	     DRM(getclient)(struct in
 				    unsigned int cmd, unsigned long arg);
 extern int	     DRM(getstats)(struct inode *inode, struct file *filp,
 				   unsigned int cmd, unsigned long arg);
+extern int	     DRM(setversion)(struct inode *inode, struct file *filp,
+				     unsigned int cmd, unsigned long arg);
 
 				/* Context IOCTL support (drm_context.h) */
 extern int	     DRM(resctx)( struct inode *inode, struct file *filp,
@@ -900,12 +917,17 @@ extern int	     DRM(dma_setup)(drm_devic
 extern void	     DRM(dma_takedown)(drm_device_t *dev);
 extern void	     DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf);
 extern void	     DRM(reclaim_buffers)( struct file *filp );
-#if __HAVE_DMA_IRQ
+#endif /* __HAVE_DMA */
+
+				/* IRQ support (drm_irq.h) */
+#if __HAVE_IRQ || __HAVE_DMA
 extern int           DRM(control)( struct inode *inode, struct file *filp,
 				   unsigned int cmd, unsigned long arg );
-extern int           DRM(irq_install)( drm_device_t *dev, int irq );
+#endif
+#if __HAVE_IRQ
+extern int           DRM(irq_install)( drm_device_t *dev );
 extern int           DRM(irq_uninstall)( drm_device_t *dev );
-extern irqreturn_t   DRM(dma_service)( DRM_IRQ_ARGS );
+extern irqreturn_t   DRM(irq_handler)( DRM_IRQ_ARGS );
 extern void          DRM(driver_irq_preinstall)( drm_device_t *dev );
 extern void          DRM(driver_irq_postinstall)( drm_device_t *dev );
 extern void          DRM(driver_irq_uninstall)( drm_device_t *dev );
@@ -915,12 +937,11 @@ extern int           DRM(wait_vblank)(st
 extern int           DRM(vblank_wait)(drm_device_t *dev, unsigned int *vbl_seq);
 extern void          DRM(vbl_send_signals)( drm_device_t *dev );
 #endif
-#if __HAVE_DMA_IRQ_BH
-extern void          DRM(dma_immediate_bh)( void *dev );
+#if __HAVE_IRQ_BH
+extern void          DRM(irq_immediate_bh)( void *dev );
 #endif
 #endif
 
-#endif /* __HAVE_DMA */
 
 #if __REALLY_HAVE_AGP
 				/* AGP/GART support (drm_agpsupport.h) */
--- diff/drivers/char/drm/drm_bufs.h	2003-07-22 18:54:27.000000000 +0100
+++ source/drivers/char/drm/drm_bufs.h	2004-03-09 11:51:49.000000000 +0000
@@ -147,7 +147,9 @@ int DRM(addmap)( struct inode *inode, st
 					      MTRR_TYPE_WRCOMB, 1 );
 		}
 #endif
-		map->handle = DRM(ioremap)( map->offset, map->size, dev );
+		if (map->type == _DRM_REGISTERS)
+			map->handle = DRM(ioremap)( map->offset, map->size,
+						    dev );
 		break;
 
 	case _DRM_SHM:
@@ -160,6 +162,12 @@ int DRM(addmap)( struct inode *inode, st
 		}
 		map->offset = (unsigned long)map->handle;
 		if ( map->flags & _DRM_CONTAINS_LOCK ) {
+			/* Prevent a 2nd X Server from creating a 2nd lock */
+			if (dev->lock.hw_lock != NULL) {
+				vfree( map->handle );
+				DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
+				return -EBUSY;
+			}
 			dev->sigdata.lock =
 			dev->lock.hw_lock = map->handle; /* Pointer to lock */
 		}
--- diff/drivers/char/drm/drm_dma.h	2003-07-22 18:54:27.000000000 +0100
+++ source/drivers/char/drm/drm_dma.h	2004-03-09 11:51:49.000000000 +0000
@@ -43,15 +43,6 @@
 #ifndef __HAVE_DMA_RECLAIM
 #define __HAVE_DMA_RECLAIM	0
 #endif
-#ifndef __HAVE_SHARED_IRQ
-#define __HAVE_SHARED_IRQ	0
-#endif
-
-#if __HAVE_SHARED_IRQ
-#define DRM_IRQ_TYPE		SA_SHIRQ
-#else
-#define DRM_IRQ_TYPE		0
-#endif
 
 #if __HAVE_DMA
 
@@ -214,293 +205,11 @@ void DRM(reclaim_buffers)( struct file *
 }
 #endif
 
-
-
-
-#if __HAVE_DMA_IRQ
-
-/**
- * Install IRQ handler.
- *
- * \param dev DRM device.
- * \param irq IRQ number.
- *
- * Initializes the IRQ related data, and setups drm_device::vbl_queue. Installs the handler, calling the driver
- * \c DRM(driver_irq_preinstall)() and \c DRM(driver_irq_postinstall)() functions
- * before and after the installation.
- */
-int DRM(irq_install)( drm_device_t *dev, int irq )
-{
-	int ret;
-
-	if ( !irq )
-		return -EINVAL;
-
-	down( &dev->struct_sem );
-
-	/* Driver must have been initialized */
-	if ( !dev->dev_private ) {
-		up( &dev->struct_sem );
-		return -EINVAL;
-	}
-
-	if ( dev->irq ) {
-		up( &dev->struct_sem );
-		return -EBUSY;
-	}
-	dev->irq = irq;
-	up( &dev->struct_sem );
-
-	DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq );
-
-	dev->context_flag = 0;
-	dev->interrupt_flag = 0;
-	dev->dma_flag = 0;
-
-	dev->dma->next_buffer = NULL;
-	dev->dma->next_queue = NULL;
-	dev->dma->this_buffer = NULL;
-
-#if __HAVE_DMA_IRQ_BH
-	INIT_WORK(&dev->work, DRM(dma_immediate_bh), dev);
-#endif
-
-#if __HAVE_VBL_IRQ
-	init_waitqueue_head(&dev->vbl_queue);
-
-	spin_lock_init( &dev->vbl_lock );
-
-	INIT_LIST_HEAD( &dev->vbl_sigs.head );
-
-	dev->vbl_pending = 0;
-#endif
-
-				/* Before installing handler */
-	DRM(driver_irq_preinstall)(dev);
-
-				/* Install handler */
-	ret = request_irq( dev->irq, DRM(dma_service),
-			   DRM_IRQ_TYPE, dev->devname, dev );
-	if ( ret < 0 ) {
-		down( &dev->struct_sem );
-		dev->irq = 0;
-		up( &dev->struct_sem );
-		return ret;
-	}
-
-				/* After installing handler */
-	DRM(driver_irq_postinstall)(dev);
-
-	return 0;
-}
-
-/**
- * Uninstall the IRQ handler.
- *
- * \param dev DRM device.
- *
- * Calls the driver's \c DRM(driver_irq_uninstall)() function, and stops the irq.
- */
-int DRM(irq_uninstall)( drm_device_t *dev )
-{
-	int irq;
-
-	down( &dev->struct_sem );
-	irq = dev->irq;
-	dev->irq = 0;
-	up( &dev->struct_sem );
-
-	if ( !irq )
-		return -EINVAL;
-
-	DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq );
-
-	DRM(driver_irq_uninstall)( dev );
-
-	free_irq( irq, dev );
-
-	return 0;
-}
-
-/**
- * IRQ control ioctl.
- *
- * \param inode device inode.
- * \param filp file pointer.
- * \param cmd command.
- * \param arg user argument, pointing to a drm_control structure.
- * \return zero on success or a negative number on failure.
- *
- * Calls irq_install() or irq_uninstall() according to \p arg.
- */
-int DRM(control)( struct inode *inode, struct file *filp,
-		  unsigned int cmd, unsigned long arg )
-{
-	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
-	drm_control_t ctl;
-
-	if ( copy_from_user( &ctl, (drm_control_t *)arg, sizeof(ctl) ) )
-		return -EFAULT;
-
-	switch ( ctl.func ) {
-	case DRM_INST_HANDLER:
-		return DRM(irq_install)( dev, ctl.irq );
-	case DRM_UNINST_HANDLER:
-		return DRM(irq_uninstall)( dev );
-	default:
-		return -EINVAL;
-	}
-}
-
-#if __HAVE_VBL_IRQ
-
-/**
- * Wait for VBLANK.
- *
- * \param inode device inode.
- * \param filp file pointer.
- * \param cmd command.
- * \param data user argument, pointing to a drm_wait_vblank structure.
- * \return zero on success or a negative number on failure.
- *
- * Verifies the IRQ is installed. 
- *
- * If a signal is requested checks if this task has already scheduled the same signal
- * for the same vblank sequence number - nothing to be done in
- * that case. If the number of tasks waiting for the interrupt exceeds 100 the
- * function fails. Otherwise adds a new entry to drm_device::vbl_sigs for this
- * task.
- *
- * If a signal is not requested, then calls vblank_wait().
- */
-int DRM(wait_vblank)( DRM_IOCTL_ARGS )
-{
-	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
-	drm_wait_vblank_t vblwait;
-	struct timeval now;
-	int ret = 0;
-	unsigned int flags;
-
-	if (!dev->irq)
-		return -EINVAL;
-
-	DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data,
-				  sizeof(vblwait) );
-
-	switch ( vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK ) {
-	case _DRM_VBLANK_RELATIVE:
-		vblwait.request.sequence += atomic_read( &dev->vbl_received );
-		vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
-	case _DRM_VBLANK_ABSOLUTE:
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
-	
-	if ( flags & _DRM_VBLANK_SIGNAL ) {
-		unsigned long irqflags;
-		drm_vbl_sig_t *vbl_sig;
-		
-		vblwait.reply.sequence = atomic_read( &dev->vbl_received );
-
-		spin_lock_irqsave( &dev->vbl_lock, irqflags );
-
-		/* Check if this task has already scheduled the same signal
-		 * for the same vblank sequence number; nothing to be done in
-		 * that case
-		 */
-		list_for_each_entry( vbl_sig, &dev->vbl_sigs.head, head ) {
-			if (vbl_sig->sequence == vblwait.request.sequence
-			    && vbl_sig->info.si_signo == vblwait.request.signal
-			    && vbl_sig->task == current)
-			{
-				spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
-				goto done;
-			}
-		}
-
-		if ( dev->vbl_pending >= 100 ) {
-			spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
-			return -EBUSY;
-		}
-
-		dev->vbl_pending++;
-
-		spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
-
-		if ( !( vbl_sig = DRM_MALLOC( sizeof( drm_vbl_sig_t ) ) ) ) {
-			return -ENOMEM;
-		}
-
-		memset( (void *)vbl_sig, 0, sizeof(*vbl_sig) );
-
-		vbl_sig->sequence = vblwait.request.sequence;
-		vbl_sig->info.si_signo = vblwait.request.signal;
-		vbl_sig->task = current;
-
-		spin_lock_irqsave( &dev->vbl_lock, irqflags );
-
-		list_add_tail( (struct list_head *) vbl_sig, &dev->vbl_sigs.head );
-
-		spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
-	} else {
-		ret = DRM(vblank_wait)( dev, &vblwait.request.sequence );
-
-		do_gettimeofday( &now );
-		vblwait.reply.tval_sec = now.tv_sec;
-		vblwait.reply.tval_usec = now.tv_usec;
-	}
-
-done:
-	DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait,
-				sizeof(vblwait) );
-
-	return ret;
-}
-
-/**
- * Send the VBLANK signals.
- *
- * \param dev DRM device.
- *
- * Sends a signal for each task in drm_device::vbl_sigs and empties the list.
- *
- * If a signal is not requested, then calls vblank_wait().
+#if !__HAVE_IRQ
+/* This stub DRM_IOCTL_CONTROL handler is for the drivers that used to require
+ * IRQs for DMA but no longer do.  It maintains compatibility with the X Servers
+ * that try to use the control ioctl by simply returning success.
  */
-void DRM(vbl_send_signals)( drm_device_t *dev )
-{
-	struct list_head *list, *tmp;
-	drm_vbl_sig_t *vbl_sig;
-	unsigned int vbl_seq = atomic_read( &dev->vbl_received );
-	unsigned long flags;
-
-	spin_lock_irqsave( &dev->vbl_lock, flags );
-
-	list_for_each_safe( list, tmp, &dev->vbl_sigs.head ) {
-		vbl_sig = list_entry( list, drm_vbl_sig_t, head );
-		if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) {
-			vbl_sig->info.si_code = vbl_seq;
-			send_sig_info( vbl_sig->info.si_signo, &vbl_sig->info, vbl_sig->task );
-
-			list_del( list );
-
-			DRM_FREE( vbl_sig, sizeof(*vbl_sig) );
-
-			dev->vbl_pending--;
-		}
-	}
-
-	spin_unlock_irqrestore( &dev->vbl_lock, flags );
-}
-
-#endif	/* __HAVE_VBL_IRQ */
-
-#else
-
 int DRM(control)( struct inode *inode, struct file *filp,
 		  unsigned int cmd, unsigned long arg )
 {
@@ -517,7 +226,6 @@ int DRM(control)( struct inode *inode, s
 		return -EINVAL;
 	}
 }
-
-#endif /* __HAVE_DMA_IRQ */
+#endif
 
 #endif /* __HAVE_DMA */
--- diff/drivers/char/drm/drm_drv.h	2003-10-27 09:20:43.000000000 +0000
+++ source/drivers/char/drm/drm_drv.h	2004-03-09 11:51:49.000000000 +0000
@@ -58,8 +58,8 @@
 #ifndef __HAVE_CTX_BITMAP
 #define __HAVE_CTX_BITMAP		0
 #endif
-#ifndef __HAVE_DMA_IRQ
-#define __HAVE_DMA_IRQ			0
+#ifndef __HAVE_IRQ
+#define __HAVE_IRQ			0
 #endif
 #ifndef __HAVE_DMA_QUEUE
 #define __HAVE_DMA_QUEUE		0
@@ -126,6 +126,9 @@
 #ifndef DRIVER_IOCTLS
 #define DRIVER_IOCTLS
 #endif
+#ifndef DRIVER_OPEN_HELPER
+#define DRIVER_OPEN_HELPER( priv, dev )
+#endif
 #ifndef DRIVER_FOPS
 #define DRIVER_FOPS				\
 static struct file_operations	DRM(fops) = {	\
@@ -159,15 +162,8 @@ __setup( DRIVER_NAME "=", DRM_OPTIONS_FU
 #undef DRM_OPTIONS_FUNC
 #endif
 
-/**
- * The default number of instances (minor numbers) to initialize.
- */
-#ifndef DRIVER_NUM_CARDS
-#define DRIVER_NUM_CARDS 1
-#endif
-
-static drm_device_t	*DRM(device);
-static int		*DRM(minor);
+#define MAX_DEVICES 4
+static drm_device_t	DRM(device)[MAX_DEVICES];
 static int		DRM(numdevs) = 0;
 
 DRIVER_FOPS;
@@ -177,10 +173,13 @@ static drm_ioctl_desc_t		  DRM(ioctls)[]
 	[DRM_IOCTL_NR(DRM_IOCTL_VERSION)]       = { DRM(version),     0, 0 },
 	[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)]    = { DRM(getunique),   0, 0 },
 	[DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)]     = { DRM(getmagic),    0, 0 },
-	[DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)]     = { DRM(irq_busid),   0, 1 },
+#if __HAVE_IRQ
+	[DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)]     = { DRM(irq_by_busid), 0, 1 },
+#endif
 	[DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)]       = { DRM(getmap),      0, 0 },
 	[DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)]    = { DRM(getclient),   0, 0 },
 	[DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)]     = { DRM(getstats),    0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_SET_VERSION)]   = { DRM(setversion),  0, 1 },
 
 	[DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)]    = { DRM(setunique),   1, 1 },
 	[DRM_IOCTL_NR(DRM_IOCTL_BLOCK)]         = { DRM(noop),        1, 1 },
@@ -222,9 +221,9 @@ static drm_ioctl_desc_t		  DRM(ioctls)[]
 	[DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)]     = { DRM(infobufs),    1, 0 },
 	[DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)]      = { DRM(mapbufs),     1, 0 },
 	[DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)]     = { DRM(freebufs),    1, 0 },
-
-	/* The DRM_IOCTL_DMA ioctl should be defined by the driver.
-	 */
+	/* The DRM_IOCTL_DMA ioctl should be defined by the driver. */
+#endif
+#if __HAVE_IRQ || __HAVE_DMA
 	[DRM_IOCTL_NR(DRM_IOCTL_CONTROL)]       = { DRM(control),     1, 1 },
 #endif
 
@@ -337,7 +336,7 @@ static int DRM(setup)( drm_device_t *dev
 	dev->queue_reserved = 0;
 	dev->queue_slots = 0;
 	dev->queuelist = NULL;
-	dev->irq = 0;
+	dev->irq_enabled = 0;
 	dev->context_flag = 0;
 	dev->interrupt_flag = 0;
 	dev->dma_flag = 0;
@@ -345,6 +344,7 @@ static int DRM(setup)( drm_device_t *dev
 	dev->last_switch = 0;
 	dev->last_checked = 0;
 	init_waitqueue_head( &dev->context_wait );
+	dev->if_version = 0;
 
 	dev->ctx_start = 0;
 	dev->lck_start = 0;
@@ -391,8 +391,8 @@ static int DRM(takedown)( drm_device_t *
 	DRM_DEBUG( "\n" );
 
 	DRIVER_PRETAKEDOWN();
-#if __HAVE_DMA_IRQ
-	if ( dev->irq ) DRM(irq_uninstall)( dev );
+#if __HAVE_IRQ
+	if ( dev->irq_enabled ) DRM(irq_uninstall)( dev );
 #endif
 
 	down( &dev->struct_sem );
@@ -534,52 +534,111 @@ static int DRM(takedown)( drm_device_t *
 	return 0;
 }
 
-/**
- * Figure out how many instances to initialize.
- *
- * \return number of cards found.
- *
- * Searches for every PCI card in \c DRIVER_CARD_LIST with matching vendor and device ids.
- */
-static int drm_count_cards(void)
+static drm_pci_id_list_t DRM(pciidlist)[] = {
+	DRIVER_PCI_IDS
+};
+
+static int DRM(probe)(struct pci_dev *pdev)
 {
-	int num = 0;
-#if defined(DRIVER_CARD_LIST)
-	int i;
-	drm_pci_list_t *l;
-	u16 device, vendor;
-	struct pci_dev *pdev = NULL;
+	drm_device_t *dev;
+#if __HAVE_CTX_BITMAP
+	int retcode;
 #endif
+	int i;
+	char *desc = NULL;
 
 	DRM_DEBUG( "\n" );
 
-#if defined(DRIVER_COUNT_CARDS)
-	num = DRIVER_COUNT_CARDS();
-#elif defined(DRIVER_CARD_LIST)
-	for (i = 0, l = DRIVER_CARD_LIST; l[i].vendor != 0; i++) {
-		pdev = NULL;
-		vendor = l[i].vendor;
-		device = l[i].device;
-		if(device == 0xffff) device = PCI_ANY_ID;
-		if(vendor == 0xffff) vendor = PCI_ANY_ID;
-		while ((pdev = pci_find_device(vendor, device, pdev))) {
-			num++;
+	for (i = 0; DRM(pciidlist)[i].vendor != 0; i++) {
+		if ((DRM(pciidlist)[i].vendor == pdev->vendor) &&
+		    (DRM(pciidlist)[i].device == pdev->device)) {
+			desc = DRM(pciidlist)[i].name;
 		}
 	}
+	if (desc == NULL)
+		return -ENODEV;
+
+	if (DRM(numdevs) >= MAX_DEVICES)
+		return -ENODEV;
+
+	dev = &(DRM(device)[DRM(numdevs)]);
+
+	memset( (void *)dev, 0, sizeof(*dev) );
+	dev->count_lock = SPIN_LOCK_UNLOCKED;
+	init_timer( &dev->timer );
+	sema_init( &dev->struct_sem, 1 );
+
+	if ((dev->minor = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0)
+		return -EPERM;
+	dev->device = MKDEV(DRM_MAJOR, dev->minor );
+	dev->name   = DRIVER_NAME;
+
+	dev->pdev   = pdev;
+#ifdef __alpha__
+	dev->hose   = pdev->sysdata;
+	dev->pci_domain = dev->hose->bus->number;
 #else
-	num = DRIVER_NUM_CARDS;
+	dev->pci_domain = 0;
+#endif
+	dev->pci_bus = pdev->bus->number;
+	dev->pci_slot = PCI_SLOT(pdev->devfn);
+	dev->pci_func = PCI_FUNC(pdev->devfn);
+	dev->irq = pdev->irq;
+
+	DRIVER_PREINIT();
+
+#if __REALLY_HAVE_AGP
+	dev->agp = DRM(agp_init)();
+#if __MUST_HAVE_AGP
+	if ( dev->agp == NULL ) {
+		DRM_ERROR( "Cannot initialize the agpgart module.\n" );
+		DRM(stub_unregister)(dev->minor);
+		DRM(takedown)( dev );
+		return -ENOMEM;
+	}
+#endif
+#if __REALLY_HAVE_MTRR
+	if (dev->agp)
+		dev->agp->agp_mtrr = mtrr_add( dev->agp->agp_info.aper_base,
+					dev->agp->agp_info.aper_size*1024*1024,
+					MTRR_TYPE_WRCOMB,
+					1 );
+#endif
+#endif
+
+#if __HAVE_CTX_BITMAP
+	retcode = DRM(ctxbitmap_init)( dev );
+	if( retcode ) {
+		DRM_ERROR( "Cannot allocate memory for context bitmap.\n" );
+		DRM(stub_unregister)(dev->minor);
+		DRM(takedown)( dev );
+		return retcode;
+ 	}
 #endif
-	DRM_DEBUG("numdevs = %d\n", num);
-	return num;
+	DRM(numdevs)++; /* no errors, mark it reserved */
+	
+	DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d: %s\n",
+		DRIVER_NAME,
+		DRIVER_MAJOR,
+		DRIVER_MINOR,
+		DRIVER_PATCHLEVEL,
+		DRIVER_DATE,
+		dev->minor,
+		desc );
+
+	DRIVER_POSTINIT();
+
+	return 0;
 }
 
+
 /**
  * Module initialization. Called via init_module at module load time, or via
  * linux/init/main.c (this is not currently supported).
  *
  * \return zero on success or a negative number on failure.
  *
- * Allocates and initialize an array of drm_device structures, and attempts to
+ * Initializes an array of drm_device structures, and attempts to
  * initialize all available devices, using consecutive minors, registering the
  * stubs and initializing the AGP device.
  * 
@@ -588,88 +647,19 @@ static int drm_count_cards(void)
  */
 static int __init drm_init( void )
 {
+	struct pci_dev *pdev = NULL;
 
-	drm_device_t *dev;
-	int i;
-#if __HAVE_CTX_BITMAP
-	int retcode;
-#endif
 	DRM_DEBUG( "\n" );
 
 #ifdef MODULE
 	DRM(parse_options)( drm_opts );
 #endif
 
-	DRM(numdevs) = drm_count_cards();
-	/* Force at least one instance. */
-	if (DRM(numdevs) <= 0)
-		DRM(numdevs) = 1;
-
-	DRM(device) = kmalloc(sizeof(*DRM(device)) * DRM(numdevs), GFP_KERNEL);
-	if (!DRM(device)) {
-		return -ENOMEM;
-	}
-	DRM(minor) = kmalloc(sizeof(*DRM(minor)) * DRM(numdevs), GFP_KERNEL);
-	if (!DRM(minor)) {
-		kfree(DRM(device));
-		return -ENOMEM;
-	}
-
-	DRIVER_PREINIT();
-
 	DRM(mem_init)();
 
-	for (i = 0; i < DRM(numdevs); i++) {
-		dev = &(DRM(device)[i]);
-		memset( (void *)dev, 0, sizeof(*dev) );
-		dev->count_lock = SPIN_LOCK_UNLOCKED;
-		init_timer( &dev->timer );
-		sema_init( &dev->struct_sem, 1 );
-
-		if ((DRM(minor)[i] = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0)
-			return -EPERM;
-		dev->device = MKDEV(DRM_MAJOR, DRM(minor)[i] );
-		dev->name   = DRIVER_NAME;
-
-#if __REALLY_HAVE_AGP
-		dev->agp = DRM(agp_init)();
-#if __MUST_HAVE_AGP
-		if ( dev->agp == NULL ) {
-			DRM_ERROR( "Cannot initialize the agpgart module.\n" );
-			DRM(stub_unregister)(DRM(minor)[i]);
-			DRM(takedown)( dev );
-			return -EINVAL;
-		}
-#endif
-#if __REALLY_HAVE_MTRR
-		if (dev->agp)
-			dev->agp->agp_mtrr = mtrr_add( dev->agp->agp_info.aper_base,
-				       dev->agp->agp_info.aper_size*1024*1024,
-				       MTRR_TYPE_WRCOMB,
-				       1 );
-#endif
-#endif
-
-#if __HAVE_CTX_BITMAP
-		retcode = DRM(ctxbitmap_init)( dev );
-		if( retcode ) {
-			DRM_ERROR( "Cannot allocate memory for context bitmap.\n" );
-			DRM(stub_unregister)(DRM(minor)[i]);
-			DRM(takedown)( dev );
-			return retcode;
-		}
-#endif
-		DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d\n",
-		  	DRIVER_NAME,
-		  	DRIVER_MAJOR,
-		  	DRIVER_MINOR,
-		  	DRIVER_PATCHLEVEL,
-		  	DRIVER_DATE,
-		  	DRM(minor)[i] );
+	while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
+		DRM(probe)(pdev);
 	}
-
-	DRIVER_POSTINIT();
-
 	return 0;
 }
 
@@ -689,10 +679,10 @@ static void __exit drm_cleanup( void )
 
 	for (i = DRM(numdevs) - 1; i >= 0; i--) {
 		dev = &(DRM(device)[i]);
-		if ( DRM(stub_unregister)(DRM(minor)[i]) ) {
+		if ( DRM(stub_unregister)(dev->minor) ) {
 			DRM_ERROR( "Cannot unload module\n" );
 		} else {
-			DRM_DEBUG("minor %d unregistered\n", DRM(minor)[i]);
+			DRM_DEBUG("minor %d unregistered\n", dev->minor);
 			if (i == 0) {
 				DRM_INFO( "Module unloaded\n" );
 			}
@@ -722,8 +712,6 @@ static void __exit drm_cleanup( void )
 #endif
 	}
 	DRIVER_POSTCLEANUP();
-	kfree(DRM(minor));
-	kfree(DRM(device));
 	DRM(numdevs) = 0;
 }
 
@@ -795,7 +783,7 @@ int DRM(open)( struct inode *inode, stru
 	int i;
 
 	for (i = 0; i < DRM(numdevs); i++) {
-		if (iminor(inode) == DRM(minor)[i]) {
+		if (iminor(inode) == DRM(device)[i].minor) {
 			dev = &(DRM(device)[i]);
 			break;
 		}
--- diff/drivers/char/drm/drm_fops.h	2003-10-09 09:47:16.000000000 +0100
+++ source/drivers/char/drm/drm_fops.h	2004-03-09 11:51:49.000000000 +0000
@@ -72,6 +72,8 @@ int DRM(open_helper)(struct inode *inode
 	priv->authenticated = capable(CAP_SYS_ADMIN);
 	priv->lock_count    = 0;
 
+	DRIVER_OPEN_HELPER( priv, dev );
+
 	down(&dev->struct_sem);
 	if (!dev->file_last) {
 		priv->next	= NULL;
--- diff/drivers/char/drm/drm_ioctl.h	2003-07-22 18:54:27.000000000 +0100
+++ source/drivers/char/drm/drm_ioctl.h	2004-03-09 11:51:49.000000000 +0000
@@ -35,69 +35,7 @@
 
 #include "drmP.h"
 
-
-/**
- * Get interrupt from bus id.
- * 
- * \param inode device inode.
- * \param filp file pointer.
- * \param cmd command.
- * \param arg user argument, pointing to a drm_irq_busid structure.
- * \return zero on success or a negative number on failure.
- * 
- * Finds the PCI device with the specified bus id and gets its IRQ number.
- */
-int DRM(irq_busid)(struct inode *inode, struct file *filp,
-		   unsigned int cmd, unsigned long arg)
-{
-	drm_irq_busid_t p;
-	struct pci_dev	*dev;
-
-	if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p)))
-		return -EFAULT;
-#ifdef __alpha__
-	{
-		int domain = p.busnum >> 8;
-		p.busnum &= 0xff;
-
-		/*
-		 * Find the hose the device is on (the domain number is the
-		 * hose index) and offset the bus by the root bus of that
-		 * hose.
-		 */
-                for(dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,NULL);
-                    dev;
-                    dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,dev)) {
-			struct pci_controller *hose = dev->sysdata;
-			
-			if (hose->index == domain) {
-				p.busnum += hose->bus->number;
-				break;
-			}
-		}
-	}
-#endif
-	dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum));
-	if (!dev) {
-		DRM_ERROR("pci_find_slot failed for %d:%d:%d\n",
-			  p.busnum, p.devnum, p.funcnum);
-		p.irq = 0;
-		goto out;
-	}			
-	if (pci_enable_device(dev) != 0) {
-		DRM_ERROR("pci_enable_device failed for %d:%d:%d\n",
-			  p.busnum, p.devnum, p.funcnum);
-		p.irq = 0;
-		goto out;
-	}		
-	p.irq = dev->irq;
- out:
-	DRM_DEBUG("%d:%d:%d => IRQ %d\n",
-		  p.busnum, p.devnum, p.funcnum, p.irq);
-	if (copy_to_user((drm_irq_busid_t *)arg, &p, sizeof(p)))
-		return -EFAULT;
-	return 0;
-}
+#include <linux/pci.h>
 
 /**
  * Get the bus id.
@@ -138,8 +76,10 @@ int DRM(getunique)(struct inode *inode, 
  * \param arg user argument, pointing to a drm_unique structure.
  * \return zero on success or a negative number on failure.
  *
- * Copies the bus id from userspace into drm_device::unique, and searches for
- * the respective PCI device, updating drm_device::pdev.
+ * Copies the bus id from userspace into drm_device::unique, and verifies that
+ * it matches the device this DRM is attached to (EINVAL otherwise).  Deprecated
+ * in interface version 1.1 and will return EBUSY when setversion has requested
+ * version 1.1 or greater.
  */
 int DRM(setunique)(struct inode *inode, struct file *filp,
 		   unsigned int cmd, unsigned long arg)
@@ -147,6 +87,7 @@ int DRM(setunique)(struct inode *inode, 
 	drm_file_t	 *priv	 = filp->private_data;
 	drm_device_t	 *dev	 = priv->dev;
 	drm_unique_t	 u;
+	int		 domain, bus, slot, func, ret;
 
 	if (dev->unique_len || dev->unique) return -EBUSY;
 
@@ -164,55 +105,42 @@ int DRM(setunique)(struct inode *inode, 
 
 	dev->devname = DRM(alloc)(strlen(dev->name) + strlen(dev->unique) + 2,
 				  DRM_MEM_DRIVER);
-	if(!dev->devname) {
-		DRM(free)(dev->devname, sizeof(*dev->devname), DRM_MEM_DRIVER);
+	if (!dev->devname)
 		return -ENOMEM;
-	}
+
 	sprintf(dev->devname, "%s@%s", dev->name, dev->unique);
 
-	do {
-		struct pci_dev *pci_dev;
-                int domain, b, d, f;
-                char *p;
- 
-                for(p = dev->unique; p && *p && *p != ':'; p++);
-                if (!p || !*p) break;
-                b = (int)simple_strtoul(p+1, &p, 10);
-                if (*p != ':') break;
-                d = (int)simple_strtoul(p+1, &p, 10);
-                if (*p != ':') break;
-                f = (int)simple_strtoul(p+1, &p, 10);
-                if (*p) break;
- 
-		domain = b >> 8;
-		b &= 0xff;
-
-#ifdef __alpha__
-		/*
-		 * Find the hose the device is on (the domain number is the
-		 * hose index) and offset the bus by the root bus of that
-		 * hose.
-		 */
-                for(pci_dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,NULL);
-                    pci_dev;
-                    pci_dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,pci_dev)) {
-			struct pci_controller *hose = pci_dev->sysdata;
-			
-			if (hose->index == domain) {
-				b += hose->bus->number;
-				break;
-			}
-		}
-#endif
+	/* Return error if the busid submitted doesn't match the device's actual
+	 * busid.
+	 */
+	ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
+	if (ret != 3)
+		return DRM_ERR(EINVAL);
+	domain = bus >> 8;
+	bus &= 0xff;
+	
+	if ((domain != dev->pci_domain) ||
+	    (bus != dev->pci_bus) ||
+	    (slot != dev->pci_slot) ||
+	    (func != dev->pci_func))
+		return -EINVAL;
 
-                pci_dev = pci_find_slot(b, PCI_DEVFN(d,f));
-                if (pci_dev) {
-			dev->pdev = pci_dev;
-#ifdef __alpha__
-			dev->hose = pci_dev->sysdata;
-#endif
-		}
-        } while(0);
+	return 0;
+}
+
+static int
+DRM(set_busid)(drm_device_t *dev)
+{
+	if (dev->unique != NULL)
+		return EBUSY;
+
+	dev->unique_len = 20;
+	dev->unique = DRM(alloc)(dev->unique_len + 1, DRM_MEM_DRIVER);
+	if (dev->unique == NULL)
+		return ENOMEM;
+
+	snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d",
+		dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func);
 
 	return 0;
 }
@@ -363,3 +291,48 @@ int DRM(getstats)( struct inode *inode, 
 		return -EFAULT;
 	return 0;
 }
+
+#define DRM_IF_MAJOR	1
+#define DRM_IF_MINOR	2
+
+int DRM(setversion)(DRM_IOCTL_ARGS)
+{
+	DRM_DEVICE;
+	drm_set_version_t sv;
+	drm_set_version_t retv;
+	int if_version;
+
+	DRM_COPY_FROM_USER_IOCTL(sv, (drm_set_version_t *)data, sizeof(sv));
+
+	retv.drm_di_major = DRM_IF_MAJOR;
+	retv.drm_di_minor = DRM_IF_MINOR;
+	retv.drm_dd_major = DRIVER_MAJOR;
+	retv.drm_dd_minor = DRIVER_MINOR;
+
+	DRM_COPY_TO_USER_IOCTL((drm_set_version_t *)data, retv, sizeof(sv));
+
+	if (sv.drm_di_major != -1) {
+		if (sv.drm_di_major != DRM_IF_MAJOR ||
+		    sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR)
+			return EINVAL;
+		if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_dd_minor);
+		dev->if_version = DRM_MAX(if_version, dev->if_version);
+		if (sv.drm_di_minor >= 1) {
+			/*
+			 * Version 1.1 includes tying of DRM to specific device
+			 */
+			DRM(set_busid)(dev);
+		}
+	}
+
+	if (sv.drm_dd_major != -1) {
+		if (sv.drm_dd_major != DRIVER_MAJOR ||
+		    sv.drm_dd_minor < 0 || sv.drm_dd_minor > DRIVER_MINOR)
+			return EINVAL;
+#ifdef DRIVER_SETVERSION
+		DRIVER_SETVERSION(dev, &sv);
+#endif
+	}
+	return 0;
+}
+
--- diff/drivers/char/drm/drm_os_linux.h	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/drm_os_linux.h	2004-03-09 11:51:49.000000000 +0000
@@ -62,8 +62,12 @@
 	verify_area( VERIFY_READ, uaddr, size )
 #define DRM_COPY_FROM_USER_UNCHECKED(arg1, arg2, arg3) 	\
 	__copy_from_user(arg1, arg2, arg3)
+#define DRM_COPY_TO_USER_UNCHECKED(arg1, arg2, arg3)	\
+	__copy_to_user(arg1, arg2, arg3)
 #define DRM_GET_USER_UNCHECKED(val, uaddr)		\
 	__get_user(val, uaddr)
+#define DRM_PUT_USER_UNCHECKED(uaddr, val)		\
+	__put_user(val, uaddr)
 
 
 /** 'malloc' without the overhead of DRM(alloc)() */
@@ -71,6 +75,8 @@
 /** 'free' without the overhead of DRM(free)() */
 #define DRM_FREE(x,size) kfree(x)
 
+#define DRM_GET_PRIV_WITH_RETURN(_priv, _filp) _priv = _filp->private_data
+
 /** 
  * Get the pointer to the SAREA.
  *
--- diff/drivers/char/drm/gamma.h	2003-05-21 11:50:14.000000000 +0100
+++ source/drivers/char/drm/gamma.h	2004-03-09 11:51:49.000000000 +0000
@@ -53,6 +53,10 @@
 	[DRM_IOCTL_NR(DRM_IOCTL_GAMMA_INIT)] = { gamma_dma_init,  1, 1 }, \
 	[DRM_IOCTL_NR(DRM_IOCTL_GAMMA_COPY)] = { gamma_dma_copy,  1, 1 }
 
+#define DRIVER_PCI_IDS							\
+	{0x3d3d, 0x0008, 0, "3DLabs GLINT Gamma G1"},			\
+	{0, 0, 0, NULL}
+
 #define IOCTL_TABLE_NAME	DRM(ioctls)
 #define IOCTL_FUNC_NAME 	DRM(ioctl)
 
@@ -104,8 +108,8 @@
 	return 0;							\
 } while (0)
 
-#define __HAVE_DMA_IRQ			1
-#define __HAVE_DMA_IRQ_BH		1
+#define __HAVE_IRQ			1
+#define __HAVE_IRQ_BH			1
 
 #define DRIVER_AGP_BUFFERS_MAP( dev )					\
 	((drm_gamma_private_t *)((dev)->dev_private))->buffers
--- diff/drivers/char/drm/gamma_dma.c	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/gamma_dma.c	2004-03-09 11:51:49.000000000 +0000
@@ -116,7 +116,7 @@ static inline int gamma_dma_is_ready(drm
 	return (!GAMMA_READ(GAMMA_DMACOUNT));
 }
 
-irqreturn_t gamma_dma_service( DRM_IRQ_ARGS )
+irqreturn_t gamma_irq_handler( DRM_IRQ_ARGS )
 {
 	drm_device_t	 *dev = (drm_device_t *)arg;
 	drm_device_dma_t *dma = dev->dma;
@@ -262,7 +262,7 @@ static void gamma_dma_timer_bh(unsigned 
 	gamma_dma_schedule((drm_device_t *)dev, 0);
 }
 
-void gamma_dma_immediate_bh(void *dev)
+void gamma_irq_immediate_bh(void *dev)
 {
 	gamma_dma_schedule(dev, 0);
 }
@@ -656,12 +656,12 @@ int gamma_do_cleanup_dma( drm_device_t *
 {
 	DRM_DEBUG( "%s\n", __FUNCTION__ );
 
-#if _HAVE_DMA_IRQ
+#if __HAVE_IRQ
 	/* Make sure interrupts are disabled here because the uninstall ioctl
 	 * may not have been called from userspace and after dev_private
 	 * is freed, it's too late.
 	 */
-	if ( dev->irq ) DRM(irq_uninstall)(dev);
+	if ( dev->irq_enabled ) DRM(irq_uninstall)(dev);
 #endif
 
 	if ( dev->dev_private ) {
--- diff/drivers/char/drm/gamma_drv.c	2003-05-21 11:50:14.000000000 +0100
+++ source/drivers/char/drm/gamma_drv.c	2004-03-09 11:51:49.000000000 +0000
@@ -48,6 +48,7 @@
 #include "drm_fops.h"
 #include "drm_init.h"
 #include "drm_ioctl.h"
+#include "drm_irq.h"
 #include "gamma_lists.h"        /* NOTE */
 #include "drm_lock.h"
 #include "gamma_lock.h"		/* NOTE */
--- diff/drivers/char/drm/i810.h	2003-08-26 10:00:52.000000000 +0100
+++ source/drivers/char/drm/i810.h	2004-03-09 11:51:49.000000000 +0000
@@ -77,7 +77,14 @@
 	[DRM_IOCTL_NR(DRM_IOCTL_I810_MC)]      = { i810_dma_mc,     1, 1 }, \
 	[DRM_IOCTL_NR(DRM_IOCTL_I810_RSTATUS)] = { i810_rstatus,    1, 0 }, \
 	[DRM_IOCTL_NR(DRM_IOCTL_I810_FLIP)] =    { i810_flip_bufs,  1, 0 }
- 
+
+#define DRIVER_PCI_IDS							\
+	{0x8086, 0x7121, 0, "Intel i810 GMCH"},				\
+	{0x8086, 0x7123, 0, "Intel i810-DC100 GMCH"},			\
+	{0x8086, 0x7125, 0, "Intel i810E GMCH"},			\
+	{0x8086, 0x1132, 0, "Intel i815 GMCH"},				\
+	{0, 0, 0, NULL}
+
 
 #define __HAVE_COUNTERS         4
 #define __HAVE_COUNTER6         _DRM_STAT_IRQ
@@ -112,7 +119,7 @@
  * a noop stub is generated for compatibility.
  */
 /* XXX: Add vblank support? */
-#define __HAVE_DMA_IRQ		0
+#define __HAVE_IRQ		0
 
 /* Buffer customization:
  */
--- diff/drivers/char/drm/i810_dma.c	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/i810_dma.c	2004-03-09 11:51:49.000000000 +0000
@@ -53,41 +53,41 @@
 
 static inline void i810_print_status_page(drm_device_t *dev)
 {
-   	drm_device_dma_t *dma = dev->dma;
-      	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_device_dma_t *dma = dev->dma;
+	drm_i810_private_t *dev_priv = dev->dev_private;
 	u32 *temp = dev_priv->hw_status_page;
-   	int i;
+	int i;
 
-   	DRM_DEBUG(  "hw_status: Interrupt Status : %x\n", temp[0]);
-   	DRM_DEBUG(  "hw_status: LpRing Head ptr : %x\n", temp[1]);
-   	DRM_DEBUG(  "hw_status: IRing Head ptr : %x\n", temp[2]);
-      	DRM_DEBUG(  "hw_status: Reserved : %x\n", temp[3]);
+	DRM_DEBUG(  "hw_status: Interrupt Status : %x\n", temp[0]);
+	DRM_DEBUG(  "hw_status: LpRing Head ptr : %x\n", temp[1]);
+	DRM_DEBUG(  "hw_status: IRing Head ptr : %x\n", temp[2]);
+	DRM_DEBUG(  "hw_status: Reserved : %x\n", temp[3]);
 	DRM_DEBUG(  "hw_status: Last Render: %x\n", temp[4]);
-   	DRM_DEBUG(  "hw_status: Driver Counter : %d\n", temp[5]);
-   	for(i = 6; i < dma->buf_count + 6; i++) {
-	   	DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 6, temp[i]);
+	DRM_DEBUG(  "hw_status: Driver Counter : %d\n", temp[5]);
+	for(i = 6; i < dma->buf_count + 6; i++) {
+		DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 6, temp[i]);
 	}
 }
 
 static drm_buf_t *i810_freelist_get(drm_device_t *dev)
 {
-   	drm_device_dma_t *dma = dev->dma;
+	drm_device_dma_t *dma = dev->dma;
 	int		 i;
-   	int 		 used;
+	int		 used;
 
 	/* Linear search might not be the best solution */
 
-   	for (i = 0; i < dma->buf_count; i++) {
-	   	drm_buf_t *buf = dma->buflist[ i ];
-	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+	for (i = 0; i < dma->buf_count; i++) {
+		drm_buf_t *buf = dma->buflist[ i ];
+		drm_i810_buf_priv_t *buf_priv = buf->dev_private;
 		/* In use is already a pointer */
-	   	used = cmpxchg(buf_priv->in_use, I810_BUF_FREE,
+		used = cmpxchg(buf_priv->in_use, I810_BUF_FREE,
 			       I810_BUF_CLIENT);
 		if (used == I810_BUF_FREE) {
 			return buf;
 		}
 	}
-   	return NULL;
+	return NULL;
 }
 
 /* This should only be called if the buffer is not sent to the hardware
@@ -96,17 +96,17 @@ static drm_buf_t *i810_freelist_get(drm_
 
 static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf)
 {
-   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
-   	int used;
+	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+	int used;
 
-   	/* In use is already a pointer */
-   	used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE);
+	/* In use is already a pointer */
+	used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE);
 	if (used != I810_BUF_CLIENT) {
-	   	DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);
-	   	return -EINVAL;
+		DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);
+		return -EINVAL;
 	}
 
-   	return 0;
+	return 0;
 }
 
 static struct file_operations i810_buffer_fops = {
@@ -135,7 +135,7 @@ int i810_mmap_buffers(struct file *filp,
 	vma->vm_flags |= (VM_IO | VM_DONTCOPY);
 	vma->vm_file = filp;
 
-   	buf_priv->currently_mapped = I810_BUF_MAPPED;
+	buf_priv->currently_mapped = I810_BUF_MAPPED;
 	unlock_kernel();
 
 	if (remap_page_range(DRM_RPR_ARG(vma) vma->vm_start,
@@ -150,8 +150,8 @@ static int i810_map_buffer(drm_buf_t *bu
 	drm_file_t	  *priv	  = filp->private_data;
 	drm_device_t	  *dev	  = priv->dev;
 	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
-      	drm_i810_private_t *dev_priv = dev->dev_private;
-   	struct file_operations *old_fops;
+	drm_i810_private_t *dev_priv = dev->dev_private;
+	struct file_operations *old_fops;
 	int retcode = 0;
 
 	if (buf_priv->currently_mapped == I810_BUF_MAPPED) 
@@ -192,8 +192,8 @@ static int i810_unmap_buffer(drm_buf_t *
 			    (size_t) buf->total);
 	up_write(&current->mm->mmap_sem);
 
-   	buf_priv->currently_mapped = I810_BUF_UNMAPPED;
-   	buf_priv->virtual = 0;
+	buf_priv->currently_mapped = I810_BUF_UNMAPPED;
+	buf_priv->virtual = 0;
 
 	return retcode;
 }
@@ -208,22 +208,22 @@ static int i810_dma_get_buffer(drm_devic
 	buf = i810_freelist_get(dev);
 	if (!buf) {
 		retcode = -ENOMEM;
-	   	DRM_DEBUG("retcode=%d\n", retcode);
+		DRM_DEBUG("retcode=%d\n", retcode);
 		return retcode;
 	}
 
 	retcode = i810_map_buffer(buf, filp);
 	if (retcode) {
 		i810_freelist_put(dev, buf);
-	   	DRM_ERROR("mapbuf failed, retcode %d\n", retcode);
+		DRM_ERROR("mapbuf failed, retcode %d\n", retcode);
 		return retcode;
 	}
 	buf->filp = filp;
 	buf_priv = buf->dev_private;
 	d->granted = 1;
-   	d->request_idx = buf->idx;
-   	d->request_size = buf->total;
-   	d->virtual = buf_priv->virtual;
+	d->request_idx = buf->idx;
+	d->request_size = buf->total;
+	d->virtual = buf_priv->virtual;
 
 	return retcode;
 }
@@ -232,33 +232,33 @@ int i810_dma_cleanup(drm_device_t *dev)
 {
 	drm_device_dma_t *dma = dev->dma;
 
-#if _HAVE_DMA_IRQ
+#if __HAVE_IRQ
 	/* Make sure interrupts are disabled here because the uninstall ioctl
 	 * may not have been called from userspace and after dev_private
 	 * is freed, it's too late.
 	 */
-	if (dev->irq) DRM(irq_uninstall)(dev);
+	if (dev->irq_enabled) DRM(irq_uninstall)(dev);
 #endif
 
 	if (dev->dev_private) {
 		int i;
-	   	drm_i810_private_t *dev_priv =
-	     		(drm_i810_private_t *) dev->dev_private;
+		drm_i810_private_t *dev_priv =
+			(drm_i810_private_t *) dev->dev_private;
 
 		if (dev_priv->ring.virtual_start) {
-		   	DRM(ioremapfree)((void *) dev_priv->ring.virtual_start,
+			DRM(ioremapfree)((void *) dev_priv->ring.virtual_start,
 					 dev_priv->ring.Size, dev);
 		}
-	   	if (dev_priv->hw_status_page) {
-		   	pci_free_consistent(dev->pdev, PAGE_SIZE,
+		if (dev_priv->hw_status_page) {
+			pci_free_consistent(dev->pdev, PAGE_SIZE,
 					    dev_priv->hw_status_page,
 					    dev_priv->dma_status_page);
-		   	/* Need to rewrite hardware status page */
-		   	I810_WRITE(0x02080, 0x1ffff000);
+			/* Need to rewrite hardware status page */
+			I810_WRITE(0x02080, 0x1ffff000);
 		}
-	   	DRM(free)(dev->dev_private, sizeof(drm_i810_private_t),
+		DRM(free)(dev->dev_private, sizeof(drm_i810_private_t),
 			 DRM_MEM_DRIVER);
-	   	dev->dev_private = NULL;
+		dev->dev_private = NULL;
 
 		for (i = 0; i < dma->buf_count; i++) {
 			drm_buf_t *buf = dma->buflist[ i ];
@@ -267,73 +267,73 @@ int i810_dma_cleanup(drm_device_t *dev)
 				DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total, dev);
 		}
 	}
-   	return 0;
+	return 0;
 }
 
 static int i810_wait_ring(drm_device_t *dev, int n)
 {
-   	drm_i810_private_t *dev_priv = dev->dev_private;
-   	drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
-   	int iters = 0;
-   	unsigned long end;
+	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
+	int iters = 0;
+	unsigned long end;
 	unsigned int last_head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
 
 	end = jiffies + (HZ*3);
-   	while (ring->space < n) {
-	   	ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
-	   	ring->space = ring->head - (ring->tail+8);
+	while (ring->space < n) {
+		ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+		ring->space = ring->head - (ring->tail+8);
 		if (ring->space < 0) ring->space += ring->Size;
-	   
+
 		if (ring->head != last_head) {
 			end = jiffies + (HZ*3);
 			last_head = ring->head;
 		}
 	  
-	   	iters++;
+		iters++;
 		if (time_before(end, jiffies)) {
-		   	DRM_ERROR("space: %d wanted %d\n", ring->space, n);
-		   	DRM_ERROR("lockup\n");
-		   	goto out_wait_ring;
+			DRM_ERROR("space: %d wanted %d\n", ring->space, n);
+			DRM_ERROR("lockup\n");
+			goto out_wait_ring;
 		}
 		udelay(1);
 	}
 
 out_wait_ring:
-   	return iters;
+	return iters;
 }
 
 static void i810_kernel_lost_context(drm_device_t *dev)
 {
-      	drm_i810_private_t *dev_priv = dev->dev_private;
-   	drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
+	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
 
-   	ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
-     	ring->tail = I810_READ(LP_RING + RING_TAIL);
-     	ring->space = ring->head - (ring->tail+8);
-     	if (ring->space < 0) ring->space += ring->Size;
+	ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+	ring->tail = I810_READ(LP_RING + RING_TAIL);
+	ring->space = ring->head - (ring->tail+8);
+	if (ring->space < 0) ring->space += ring->Size;
 }
 
 static int i810_freelist_init(drm_device_t *dev, drm_i810_private_t *dev_priv)
 {
-      	drm_device_dma_t *dma = dev->dma;
-   	int my_idx = 24;
-   	u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx);
-   	int i;
+	drm_device_dma_t *dma = dev->dma;
+	int my_idx = 24;
+	u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx);
+	int i;
 
 	if (dma->buf_count > 1019) {
-	   	/* Not enough space in the status page for the freelist */
-	   	return -EINVAL;
+		/* Not enough space in the status page for the freelist */
+		return -EINVAL;
 	}
 
-   	for (i = 0; i < dma->buf_count; i++) {
-	   	drm_buf_t *buf = dma->buflist[ i ];
-	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+	for (i = 0; i < dma->buf_count; i++) {
+		drm_buf_t *buf = dma->buflist[ i ];
+		drm_i810_buf_priv_t *buf_priv = buf->dev_private;
 
-	   	buf_priv->in_use = hw_status++;
-	   	buf_priv->my_use_idx = my_idx;
-	   	my_idx += 4;
+		buf_priv->in_use = hw_status++;
+		buf_priv->my_use_idx = my_idx;
+		my_idx += 4;
 
-	   	*buf_priv->in_use = I810_BUF_FREE;
+		*buf_priv->in_use = I810_BUF_FREE;
 
 		buf_priv->kernel_virtual = DRM(ioremap)(buf->bus_address,
 							buf->total, dev);
@@ -347,7 +347,7 @@ static int i810_dma_initialize(drm_devic
 {
 	struct list_head *list;
 
-   	memset(dev_priv, 0, sizeof(drm_i810_private_t));
+	memset(dev_priv, 0, sizeof(drm_i810_private_t));
 
 	list_for_each(list, &dev->maplist->head) {
 		drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head);
@@ -355,51 +355,51 @@ static int i810_dma_initialize(drm_devic
 		    r_list->map->type == _DRM_SHM &&
 		    r_list->map->flags & _DRM_CONTAINS_LOCK ) {
 			dev_priv->sarea_map = r_list->map;
- 			break;
- 		}
- 	}
+			break;
+		}
+	}
 	if (!dev_priv->sarea_map) {
 		dev->dev_private = (void *)dev_priv;
-	   	i810_dma_cleanup(dev);
-	   	DRM_ERROR("can not find sarea!\n");
-	   	return -EINVAL;
+		i810_dma_cleanup(dev);
+		DRM_ERROR("can not find sarea!\n");
+		return -EINVAL;
 	}
 	DRM_FIND_MAP( dev_priv->mmio_map, init->mmio_offset );
 	if (!dev_priv->mmio_map) {
 		dev->dev_private = (void *)dev_priv;
-	   	i810_dma_cleanup(dev);
-	   	DRM_ERROR("can not find mmio map!\n");
-	   	return -EINVAL;
+		i810_dma_cleanup(dev);
+		DRM_ERROR("can not find mmio map!\n");
+		return -EINVAL;
 	}
 	DRM_FIND_MAP( dev_priv->buffer_map, init->buffers_offset );
 	if (!dev_priv->buffer_map) {
 		dev->dev_private = (void *)dev_priv;
-	   	i810_dma_cleanup(dev);
-	   	DRM_ERROR("can not find dma buffer map!\n");
-	   	return -EINVAL;
+		i810_dma_cleanup(dev);
+		DRM_ERROR("can not find dma buffer map!\n");
+		return -EINVAL;
 	}
 
 	dev_priv->sarea_priv = (drm_i810_sarea_t *)
 		((u8 *)dev_priv->sarea_map->handle +
 		 init->sarea_priv_offset);
 
-   	dev_priv->ring.Start = init->ring_start;
-   	dev_priv->ring.End = init->ring_end;
-   	dev_priv->ring.Size = init->ring_size;
+	dev_priv->ring.Start = init->ring_start;
+	dev_priv->ring.End = init->ring_end;
+	dev_priv->ring.Size = init->ring_size;
 
-   	dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base +
+	dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base +
 						    init->ring_start,
 						    init->ring_size, dev);
 
-   	if (dev_priv->ring.virtual_start == NULL) {
+	if (dev_priv->ring.virtual_start == NULL) {
 		dev->dev_private = (void *) dev_priv;
-	   	i810_dma_cleanup(dev);
-	   	DRM_ERROR("can not ioremap virtual address for"
+		i810_dma_cleanup(dev);
+		DRM_ERROR("can not ioremap virtual address for"
 			  " ring buffer\n");
-	   	return -ENOMEM;
+		return -ENOMEM;
 	}
 
-   	dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
+	dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
 
 	dev_priv->w = init->w;
 	dev_priv->h = init->h;
@@ -415,33 +415,33 @@ static int i810_dma_initialize(drm_devic
 	dev_priv->back_di1 = init->back_offset | init->pitch_bits;
 	dev_priv->zi1 = init->depth_offset | init->pitch_bits;
 
-   	/* Program Hardware Status Page */
-   	dev_priv->hw_status_page =
+	/* Program Hardware Status Page */
+	dev_priv->hw_status_page =
 		pci_alloc_consistent(dev->pdev, PAGE_SIZE,
 						&dev_priv->dma_status_page);
-   	if (!dev_priv->hw_status_page) {
+	if (!dev_priv->hw_status_page) {
 		dev->dev_private = (void *)dev_priv;
 		i810_dma_cleanup(dev);
 		DRM_ERROR("Can not allocate hardware status page\n");
 		return -ENOMEM;
 	}
-   	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
-   	DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
+	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
+	DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
 
 	I810_WRITE(0x02080, dev_priv->dma_status_page);
-   	DRM_DEBUG("Enabled hardware status page\n");
+	DRM_DEBUG("Enabled hardware status page\n");
 
-   	/* Now we need to init our freelist */
+	/* Now we need to init our freelist */
 	if (i810_freelist_init(dev, dev_priv) != 0) {
 		dev->dev_private = (void *)dev_priv;
-	   	i810_dma_cleanup(dev);
-	   	DRM_ERROR("Not enough space in the status page for"
+		i810_dma_cleanup(dev);
+		DRM_ERROR("Not enough space in the status page for"
 			  " the freelist\n");
-	   	return -ENOMEM;
+		return -ENOMEM;
 	}
 	dev->dev_private = (void *)dev_priv;
 
-   	return 0;
+	return 0;
 }
 
 /* i810 DRM version 1.1 used a smaller init structure with different
@@ -476,12 +476,12 @@ int i810_dma_init_compat(drm_i810_init_t
 
 		/* This is a v1.1 client, fix the params */
 		DRM_INFO("Using PRE v1.2 init.\n");
-	 	init->pitch_bits = init->h;
-	 	init->pitch = init->w;
-	 	init->h = init->overlay_physical;
-	 	init->w = init->overlay_offset;
-	 	init->overlay_physical = 0;
-	 	init->overlay_offset = 0;
+		init->pitch_bits = init->h;
+		init->pitch = init->w;
+		init->h = init->overlay_physical;
+		init->w = init->overlay_offset;
+		init->overlay_physical = 0;
+		init->overlay_offset = 0;
 	}
 
 	return 0;
@@ -490,55 +490,55 @@ int i810_dma_init_compat(drm_i810_init_t
 int i810_dma_init(struct inode *inode, struct file *filp,
 		  unsigned int cmd, unsigned long arg)
 {
-   	drm_file_t *priv = filp->private_data;
-   	drm_device_t *dev = priv->dev;
-   	drm_i810_private_t *dev_priv;
-   	drm_i810_init_t init;
-   	int retcode = 0;
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_i810_private_t *dev_priv;
+	drm_i810_init_t init;
+	int retcode = 0;
 
 	/* Get only the init func */
 	if (copy_from_user(&init, (void *)arg, sizeof(drm_i810_init_func_t))) 
 		return -EFAULT;
 
-   	switch(init.func) {
-	 	case I810_INIT_DMA:
-	 	       	/* This case is for backward compatibility. It
+	switch(init.func) {
+		case I810_INIT_DMA:
+			/* This case is for backward compatibility. It
 			 * handles XFree 4.1.0 and 4.2.0, and has to
 			 * do some parameter checking as described below.
 			 * It will someday go away.
 			 */
 			retcode = i810_dma_init_compat(&init, arg);
-			if (retcode)
+			if (retcode) 
 				return retcode;
 
-	   		dev_priv = DRM(alloc)(sizeof(drm_i810_private_t),
+			dev_priv = DRM(alloc)(sizeof(drm_i810_private_t),
 					     DRM_MEM_DRIVER);
-	   		if (dev_priv == NULL)
-				return -ENOMEM;
-	   		retcode = i810_dma_initialize(dev, dev_priv, &init);
+			if (dev_priv == NULL)
+			       return -ENOMEM;
+			retcode = i810_dma_initialize(dev, dev_priv, &init);
 			break;
 
 		default:
-	 	case I810_INIT_DMA_1_4:
+		case I810_INIT_DMA_1_4:
 			DRM_INFO("Using v1.4 init.\n");
-  			if (copy_from_user(&init, (drm_i810_init_t *)arg,
+			if (copy_from_user(&init, (drm_i810_init_t *)arg,
 					  sizeof(drm_i810_init_t))) {
 				return -EFAULT;
 			}
-	   		dev_priv = DRM(alloc)(sizeof(drm_i810_private_t),
+			dev_priv = DRM(alloc)(sizeof(drm_i810_private_t),
 					     DRM_MEM_DRIVER);
 			if (dev_priv == NULL) 
 				return -ENOMEM;
-	   		retcode = i810_dma_initialize(dev, dev_priv, &init);
+			retcode = i810_dma_initialize(dev, dev_priv, &init);
 			break;
 
-	 	case I810_CLEANUP_DMA:
-		        DRM_INFO("DMA Cleanup\n");
-	   		retcode = i810_dma_cleanup(dev);
-              	   	break;
+		case I810_CLEANUP_DMA:
+			DRM_INFO("DMA Cleanup\n");
+			retcode = i810_dma_cleanup(dev);
+			break;
 	}
 
-   	return retcode;
+	return retcode;
 }
 
 
@@ -552,7 +552,7 @@ int i810_dma_init(struct inode *inode, s
 static void i810EmitContextVerified( drm_device_t *dev,
 				     volatile unsigned int *code )
 {
-   	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_private_t *dev_priv = dev->dev_private;
 	int i, j = 0;
 	unsigned int tmp;
 	RING_LOCALS;
@@ -586,7 +586,7 @@ static void i810EmitContextVerified( drm
 static void i810EmitTexVerified( drm_device_t *dev,
 				 volatile unsigned int *code )
 {
-   	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_private_t *dev_priv = dev->dev_private;
 	int i, j = 0;
 	unsigned int tmp;
 	RING_LOCALS;
@@ -622,7 +622,7 @@ static void i810EmitTexVerified( drm_dev
 static void i810EmitDestVerified( drm_device_t *dev,
 				  volatile unsigned int *code )
 {
-   	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_private_t *dev_priv = dev->dev_private;
 	unsigned int tmp;
 	RING_LOCALS;
 
@@ -658,8 +658,8 @@ static void i810EmitDestVerified( drm_de
 
 static void i810EmitState( drm_device_t *dev )
 {
-   	drm_i810_private_t *dev_priv = dev->dev_private;
-      	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	unsigned int dirty = sarea_priv->dirty;
 	
 	DRM_DEBUG("%s %x\n", __FUNCTION__, dirty);
@@ -693,8 +693,8 @@ static void i810_dma_dispatch_clear( drm
 				     unsigned int clear_color,
 				     unsigned int clear_zval )
 {
-   	drm_i810_private_t *dev_priv = dev->dev_private;
-      	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	int nbox = sarea_priv->nbox;
 	drm_clip_rect_t *pbox = sarea_priv->boxes;
 	int pitch = dev_priv->pitch;
@@ -703,17 +703,17 @@ static void i810_dma_dispatch_clear( drm
 	RING_LOCALS;
 	
 	if ( dev_priv->current_page == 1 ) {
-	        unsigned int tmp = flags;
-	       
+		unsigned int tmp = flags;
+
 		flags &= ~(I810_FRONT | I810_BACK);
 		if (tmp & I810_FRONT) flags |= I810_BACK;
 		if (tmp & I810_BACK) flags |= I810_FRONT;
 	}
 
-  	i810_kernel_lost_context(dev);
+	i810_kernel_lost_context(dev);
 
-      	if (nbox > I810_NR_SAREA_CLIPRECTS)
-     		nbox = I810_NR_SAREA_CLIPRECTS;
+	if (nbox > I810_NR_SAREA_CLIPRECTS)
+		nbox = I810_NR_SAREA_CLIPRECTS;
 
 	for (i = 0 ; i < nbox ; i++, pbox++) {
 		unsigned int x = pbox->x1;
@@ -728,7 +728,7 @@ static void i810_dma_dispatch_clear( drm
 		    pbox->y2 > dev_priv->h)
 			continue;
 
-	   	if ( flags & I810_FRONT ) {
+		if ( flags & I810_FRONT ) {
 			BEGIN_LP_RING( 6 );
 			OUT_RING( BR00_BITBLT_CLIENT |
 				  BR00_OP_COLOR_BLT | 0x3 );
@@ -768,8 +768,8 @@ static void i810_dma_dispatch_clear( drm
 
 static void i810_dma_dispatch_swap( drm_device_t *dev )
 {
-   	drm_i810_private_t *dev_priv = dev->dev_private;
-      	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	int nbox = sarea_priv->nbox;
 	drm_clip_rect_t *pbox = sarea_priv->boxes;
 	int pitch = dev_priv->pitch;
@@ -779,10 +779,10 @@ static void i810_dma_dispatch_swap( drm_
 
 	DRM_DEBUG("swapbuffers\n");
 
-  	i810_kernel_lost_context(dev);
+	i810_kernel_lost_context(dev);
 
-      	if (nbox > I810_NR_SAREA_CLIPRECTS)
-     		nbox = I810_NR_SAREA_CLIPRECTS;
+	if (nbox > I810_NR_SAREA_CLIPRECTS)
+		nbox = I810_NR_SAREA_CLIPRECTS;
 
 	for (i = 0 ; i < nbox; i++, pbox++)
 	{
@@ -820,19 +820,19 @@ static void i810_dma_dispatch_vertex(drm
 				     int discard,
 				     int used)
 {
-   	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_private_t *dev_priv = dev->dev_private;
 	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
-   	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
-   	drm_clip_rect_t *box = sarea_priv->boxes;
-   	int nbox = sarea_priv->nbox;
+	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_clip_rect_t *box = sarea_priv->boxes;
+	int nbox = sarea_priv->nbox;
 	unsigned long address = (unsigned long)buf->bus_address;
 	unsigned long start = address - dev->agp->base;
 	int i = 0;
-   	RING_LOCALS;
+	RING_LOCALS;
 
-   	i810_kernel_lost_context(dev);
+	i810_kernel_lost_context(dev);
 
-   	if (nbox > I810_NR_SAREA_CLIPRECTS)
+	if (nbox > I810_NR_SAREA_CLIPRECTS)
 		nbox = I810_NR_SAREA_CLIPRECTS;
 
 	if (used > 4*1024)
@@ -898,7 +898,7 @@ static void i810_dma_dispatch_vertex(drm
 
 static void i810_dma_dispatch_flip( drm_device_t *dev )
 {
-        drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_private_t *dev_priv = dev->dev_private;
 	int pitch = dev_priv->pitch;
 	RING_LOCALS;
 
@@ -907,10 +907,10 @@ static void i810_dma_dispatch_flip( drm_
 		dev_priv->current_page,
 		dev_priv->sarea_priv->pf_current_page);
 	
-        i810_kernel_lost_context(dev);
+	i810_kernel_lost_context(dev);
 
 	BEGIN_LP_RING( 2 );
-   	OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); 
+	OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); 
 	OUT_RING( 0 );
 	ADVANCE_LP_RING();
 
@@ -945,44 +945,44 @@ static void i810_dma_dispatch_flip( drm_
 
 void i810_dma_quiescent(drm_device_t *dev)
 {
-      	drm_i810_private_t *dev_priv = dev->dev_private;
-   	RING_LOCALS;
+	drm_i810_private_t *dev_priv = dev->dev_private;
+	RING_LOCALS;
 
-/*  	printk("%s\n", __FUNCTION__); */
+/*	printk("%s\n", __FUNCTION__); */
 
-  	i810_kernel_lost_context(dev);
+	i810_kernel_lost_context(dev);
 
-   	BEGIN_LP_RING(4);
-   	OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE );
-   	OUT_RING( CMD_REPORT_HEAD );
-      	OUT_RING( 0 );
-      	OUT_RING( 0 );
-   	ADVANCE_LP_RING();
+	BEGIN_LP_RING(4);
+	OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE );
+	OUT_RING( CMD_REPORT_HEAD );
+	OUT_RING( 0 );
+	OUT_RING( 0 );
+	ADVANCE_LP_RING();
 
 	i810_wait_ring( dev, dev_priv->ring.Size - 8 );
 }
 
 static int i810_flush_queue(drm_device_t *dev)
 {
-   	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_private_t *dev_priv = dev->dev_private;
 	drm_device_dma_t *dma = dev->dma;
-   	int i, ret = 0;
-   	RING_LOCALS;
+	int i, ret = 0;
+	RING_LOCALS;
 	
-/*  	printk("%s\n", __FUNCTION__); */
+/*	printk("%s\n", __FUNCTION__); */
 
-   	i810_kernel_lost_context(dev);
+	i810_kernel_lost_context(dev);
 
-   	BEGIN_LP_RING(2);
-      	OUT_RING( CMD_REPORT_HEAD );
-      	OUT_RING( 0 );
-      	ADVANCE_LP_RING();
+	BEGIN_LP_RING(2);
+	OUT_RING( CMD_REPORT_HEAD );
+	OUT_RING( 0 );
+	ADVANCE_LP_RING();
 
 	i810_wait_ring( dev, dev_priv->ring.Size - 8 );
 
-   	for (i = 0; i < dma->buf_count; i++) {
-	   	drm_buf_t *buf = dma->buflist[ i ];
-	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+	for (i = 0; i < dma->buf_count; i++) {
+		drm_buf_t *buf = dma->buflist[ i ];
+		drm_i810_buf_priv_t *buf_priv = buf->dev_private;
 
 		int used = cmpxchg(buf_priv->in_use, I810_BUF_HARDWARE,
 				   I810_BUF_FREE);
@@ -993,7 +993,7 @@ static int i810_flush_queue(drm_device_t
 			DRM_DEBUG("still on client\n");
 	}
 
-   	return ret;
+	return ret;
 }
 
 /* Must be called with the lock held */
@@ -1005,14 +1005,14 @@ void i810_reclaim_buffers(struct file *f
 	int		 i;
 
 	if (!dma) return;
-      	if (!dev->dev_private) return;
+	if (!dev->dev_private) return;
 	if (!dma->buflist) return;
 
-        i810_flush_queue(dev);
+	i810_flush_queue(dev);
 
 	for (i = 0; i < dma->buf_count; i++) {
-	   	drm_buf_t *buf = dma->buflist[ i ];
-	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+		drm_buf_t *buf = dma->buflist[ i ];
+		drm_i810_buf_priv_t *buf_priv = buf->dev_private;
 
 		if (buf->filp == filp && buf_priv) {
 			int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
@@ -1021,7 +1021,7 @@ void i810_reclaim_buffers(struct file *f
 			if (used == I810_BUF_CLIENT)
 				DRM_DEBUG("reclaimed from client\n");
 			if (buf_priv->currently_mapped == I810_BUF_MAPPED)
-		     		buf_priv->currently_mapped = I810_BUF_UNMAPPED;
+				buf_priv->currently_mapped = I810_BUF_UNMAPPED;
 		}
 	}
 }
@@ -1029,16 +1029,16 @@ void i810_reclaim_buffers(struct file *f
 int i810_flush_ioctl(struct inode *inode, struct file *filp,
 		     unsigned int cmd, unsigned long arg)
 {
-   	drm_file_t	  *priv	  = filp->private_data;
-   	drm_device_t	  *dev	  = priv->dev;
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
 
 	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
 		DRM_ERROR("i810_flush_ioctl called without lock held\n");
 		return -EINVAL;
 	}
 
-   	i810_flush_queue(dev);
-   	return 0;
+	i810_flush_queue(dev);
+	return 0;
 }
 
 
@@ -1048,10 +1048,10 @@ int i810_dma_vertex(struct inode *inode,
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->dev;
 	drm_device_dma_t *dma = dev->dma;
-   	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
-      	u32 *hw_status = dev_priv->hw_status_page;
-   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
-     					dev_priv->sarea_priv;
+	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+	u32 *hw_status = dev_priv->hw_status_page;
+	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
+					dev_priv->sarea_priv;
 	drm_i810_vertex_t vertex;
 
 	if (copy_from_user(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex)))
@@ -1072,10 +1072,10 @@ int i810_dma_vertex(struct inode *inode,
 				  dma->buflist[ vertex.idx ],
 				  vertex.discard, vertex.used );
 
-   	atomic_add(vertex.used, &dev->counts[_DRM_STAT_SECONDARY]);
+	atomic_add(vertex.used, &dev->counts[_DRM_STAT_SECONDARY]);
 	atomic_inc(&dev->counts[_DRM_STAT_DMA]);
 	sarea_priv->last_enqueue = dev_priv->counter-1;
-   	sarea_priv->last_dispatch = (int) hw_status[5];
+	sarea_priv->last_dispatch = (int) hw_status[5];
 
 	return 0;
 }
@@ -1089,7 +1089,7 @@ int i810_clear_bufs(struct inode *inode,
 	drm_device_t *dev = priv->dev;
 	drm_i810_clear_t clear;
 
-   	if (copy_from_user(&clear, (drm_i810_clear_t *)arg, sizeof(clear)))
+	if (copy_from_user(&clear, (drm_i810_clear_t *)arg, sizeof(clear)))
 		return -EFAULT;
 
 	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
@@ -1097,15 +1097,15 @@ int i810_clear_bufs(struct inode *inode,
 		return -EINVAL;
 	}
 
- 	/* GH: Someone's doing nasty things... */
- 	if (!dev->dev_private) {
- 		return -EINVAL;
- 	}
+	/* GH: Someone's doing nasty things... */
+	if (!dev->dev_private) {
+		return -EINVAL;
+	}
 
 	i810_dma_dispatch_clear( dev, clear.flags,
 				 clear.clear_color,
 				 clear.clear_depth );
-   	return 0;
+	return 0;
 }
 
 int i810_swap_bufs(struct inode *inode, struct file *filp,
@@ -1122,20 +1122,20 @@ int i810_swap_bufs(struct inode *inode, 
 	}
 
 	i810_dma_dispatch_swap( dev );
-   	return 0;
+	return 0;
 }
 
 int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
 		unsigned long arg)
 {
-   	drm_file_t	  *priv	    = filp->private_data;
+	drm_file_t	  *priv	    = filp->private_data;
 	drm_device_t	  *dev	    = priv->dev;
-   	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
-      	u32 *hw_status = dev_priv->hw_status_page;
-   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
-     					dev_priv->sarea_priv;
+	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+	u32 *hw_status = dev_priv->hw_status_page;
+	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
+					dev_priv->sarea_priv;
 
-      	sarea_priv->last_dispatch = (int) hw_status[5];
+	sarea_priv->last_dispatch = (int) hw_status[5];
 	return 0;
 }
 
@@ -1146,12 +1146,12 @@ int i810_getbuf(struct inode *inode, str
 	drm_device_t	  *dev	    = priv->dev;
 	int		  retcode   = 0;
 	drm_i810_dma_t	  d;
-   	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
-   	u32 *hw_status = dev_priv->hw_status_page;
-   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
-     					dev_priv->sarea_priv;
+	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+	u32 *hw_status = dev_priv->hw_status_page;
+	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
+					dev_priv->sarea_priv;
 
-   	if (copy_from_user(&d, (drm_i810_dma_t *)arg, sizeof(d)))
+	if (copy_from_user(&d, (drm_i810_dma_t *)arg, sizeof(d)))
 		return -EFAULT;
 
 	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
@@ -1168,7 +1168,7 @@ int i810_getbuf(struct inode *inode, str
 
 	if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d)))
 		return -EFAULT;
-   	sarea_priv->last_dispatch = (int) hw_status[5];
+	sarea_priv->last_dispatch = (int) hw_status[5];
 
 	return retcode;
 }
@@ -1384,5 +1384,5 @@ int i810_flip_bufs(struct inode *inode, 
 		i810_do_init_pageflip( dev );
 
 	i810_dma_dispatch_flip( dev );
-   	return 0;
+	return 0;
 }
--- diff/drivers/char/drm/i830.h	2003-05-21 11:50:14.000000000 +0100
+++ source/drivers/char/drm/i830.h	2004-03-09 11:51:49.000000000 +0000
@@ -77,6 +77,13 @@
 	[DRM_IOCTL_NR(DRM_IOCTL_I830_GETPARAM)] = { i830_getparam,  1, 0 }, \
 	[DRM_IOCTL_NR(DRM_IOCTL_I830_SETPARAM)] = { i830_setparam,  1, 0 } 
 
+#define DRIVER_PCI_IDS							\
+	{0x8086, 0x3577, 0, "Intel i830M GMCH"},			\
+	{0x8086, 0x2562, 0, "Intel i845G GMCH"},			\
+	{0x8086, 0x3582, 0, "Intel i852GM/i855GM GMCH"},		\
+ 	{0x8086, 0x2572, 0, "Intel i865G GMCH"}, 		\
+	{0, 0, 0, NULL}
+
 #define __HAVE_COUNTERS         4
 #define __HAVE_COUNTER6         _DRM_STAT_IRQ
 #define __HAVE_COUNTER7         _DRM_STAT_PRIMARY
@@ -115,10 +122,10 @@
 #define USE_IRQS 0
 
 #if USE_IRQS
-#define __HAVE_DMA_IRQ		1
+#define __HAVE_IRQ		1
 #define __HAVE_SHARED_IRQ	1
 #else
-#define __HAVE_DMA_IRQ          0
+#define __HAVE_IRQ		0
 #endif
 
 
--- diff/drivers/char/drm/i830_dma.c	2003-06-09 14:18:18.000000000 +0100
+++ source/drivers/char/drm/i830_dma.c	2004-03-09 11:51:49.000000000 +0000
@@ -231,12 +231,12 @@ int i830_dma_cleanup(drm_device_t *dev)
 {
 	drm_device_dma_t *dma = dev->dma;
 
-#if _HAVE_DMA_IRQ
+#if __HAVE_IRQ
 	/* Make sure interrupts are disabled here because the uninstall ioctl
 	 * may not have been called from userspace and after dev_private
 	 * is freed, it's too late.
 	 */
-	if (dev->irq) DRM(irq_uninstall)(dev);
+	if (dev->irq_enabled) DRM(irq_uninstall)(dev);
 #endif
 
 	if (dev->dev_private) {
@@ -1539,7 +1539,7 @@ int i830_getparam( struct inode *inode, 
 
 	switch( param.param ) {
 	case I830_PARAM_IRQ_ACTIVE:
-		value = dev->irq ? 1 : 0;
+		value = dev->irq_enabled;
 		break;
 	default:
 		return -EINVAL;
--- diff/drivers/char/drm/i830_drv.c	2003-05-21 11:50:14.000000000 +0100
+++ source/drivers/char/drm/i830_drv.c	2004-03-09 11:51:49.000000000 +0000
@@ -50,6 +50,7 @@
 #include "drm_fops.h"
 #include "drm_init.h"
 #include "drm_ioctl.h"
+#include "drm_irq.h"
 #include "drm_lock.h"
 #include "drm_memory.h"
 #include "drm_proc.h"
--- diff/drivers/char/drm/i830_irq.c	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/i830_irq.c	2004-03-09 11:51:49.000000000 +0000
@@ -35,7 +35,7 @@
 #include <linux/delay.h>
 
 
-irqreturn_t DRM(dma_service)( DRM_IRQ_ARGS )
+irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS )
 {
 	drm_device_t	 *dev = (drm_device_t *)arg;
       	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
--- diff/drivers/char/drm/mga.h	2003-05-21 11:50:14.000000000 +0100
+++ source/drivers/char/drm/mga.h	2004-03-09 11:51:49.000000000 +0000
@@ -64,6 +64,12 @@
 	[DRM_IOCTL_NR(DRM_IOCTL_MGA_BLIT)]    = { mga_dma_blit,    1, 0 }, \
 	[DRM_IOCTL_NR(DRM_IOCTL_MGA_GETPARAM)]= { mga_getparam,    1, 0 },
 
+#define DRIVER_PCI_IDS							\
+	{0x102b, 0x0521, 0, "Matrox G200 (AGP)"},			\
+	{0x102b, 0x0525, 0, "Matrox G400/G450 (AGP)"},			\
+	{0x102b, 0x2527, 0, "Matrox G550 (AGP)"},			\
+	{0, 0, 0, NULL}
+
 #define __HAVE_COUNTERS         3
 #define __HAVE_COUNTER6         _DRM_STAT_IRQ
 #define __HAVE_COUNTER7         _DRM_STAT_PRIMARY
@@ -78,7 +84,7 @@
 /* DMA customization:
  */
 #define __HAVE_DMA		1
-#define __HAVE_DMA_IRQ		1
+#define __HAVE_IRQ		1
 #define __HAVE_VBL_IRQ		1
 #define __HAVE_SHARED_IRQ       1
 
--- diff/drivers/char/drm/mga_dma.c	2003-06-09 14:18:18.000000000 +0100
+++ source/drivers/char/drm/mga_dma.c	2004-03-09 11:51:49.000000000 +0000
@@ -500,14 +500,6 @@ static int mga_do_init_dma( drm_device_t
 		return DRM_ERR(EINVAL);
 	}
 
-	DRM_FIND_MAP( dev_priv->fb, init->fb_offset );
-	if(!dev_priv->fb) {
-		DRM_ERROR( "failed to find framebuffer!\n" );
-		/* Assign dev_private so we can do cleanup. */
-		dev->dev_private = (void *)dev_priv;
-		mga_do_cleanup_dma( dev );
-		return DRM_ERR(EINVAL);
-	}
 	DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset );
 	if(!dev_priv->mmio) {
 		DRM_ERROR( "failed to find mmio region!\n" );
@@ -639,12 +631,12 @@ int mga_do_cleanup_dma( drm_device_t *de
 {
 	DRM_DEBUG( "\n" );
 
-#if _HAVE_DMA_IRQ
+#if __HAVE_IRQ
 	/* Make sure interrupts are disabled here because the uninstall ioctl
 	 * may not have been called from userspace and after dev_private
 	 * is freed, it's too late.
 	 */
-	if ( dev->irq ) DRM(irq_uninstall)(dev);
+	if ( dev->irq_enabled ) DRM(irq_uninstall)(dev);
 #endif
 
 	if ( dev->dev_private ) {
--- diff/drivers/char/drm/mga_drv.c	2002-10-16 04:27:56.000000000 +0100
+++ source/drivers/char/drm/mga_drv.c	2004-03-09 11:51:49.000000000 +0000
@@ -45,6 +45,7 @@
 #include "drm_fops.h"
 #include "drm_init.h"
 #include "drm_ioctl.h"
+#include "drm_irq.h"
 #include "drm_lock.h"
 #include "drm_memory.h"
 #include "drm_proc.h"
--- diff/drivers/char/drm/mga_drv.h	2003-06-09 14:18:18.000000000 +0100
+++ source/drivers/char/drm/mga_drv.h	2004-03-09 11:51:49.000000000 +0000
@@ -91,7 +91,6 @@ typedef struct drm_mga_private {
 	unsigned int texture_size;
 
 	drm_local_map_t *sarea;
-	drm_local_map_t *fb;
 	drm_local_map_t *mmio;
 	drm_local_map_t *status;
 	drm_local_map_t *warp;
--- diff/drivers/char/drm/mga_irq.c	2003-05-21 11:50:14.000000000 +0100
+++ source/drivers/char/drm/mga_irq.c	2004-03-09 11:51:49.000000000 +0000
@@ -36,7 +36,7 @@
 #include "mga_drm.h"
 #include "mga_drv.h"
 
-irqreturn_t mga_dma_service( DRM_IRQ_ARGS )
+irqreturn_t mga_irq_handler( DRM_IRQ_ARGS )
 {
 	drm_device_t *dev = (drm_device_t *) arg;
 	drm_mga_private_t *dev_priv = 
--- diff/drivers/char/drm/r128.h	2003-08-26 10:00:52.000000000 +0100
+++ source/drivers/char/drm/r128.h	2004-03-09 11:51:49.000000000 +0000
@@ -79,6 +79,46 @@
    [DRM_IOCTL_NR(DRM_IOCTL_R128_INDIRECT)]   = { r128_cce_indirect, 1, 1 }, \
    [DRM_IOCTL_NR(DRM_IOCTL_R128_GETPARAM)]   = { r128_getparam, 1, 0 },
 
+#define DRIVER_PCI_IDS							\
+	{0x1002, 0x4c45, 0, "ATI Rage 128 Mobility LE (PCI)"},		\
+	{0x1002, 0x4c46, 0, "ATI Rage 128 Mobility LF (AGP)"},		\
+	{0x1002, 0x4d46, 0, "ATI Rage 128 Mobility MF (AGP)"},		\
+	{0x1002, 0x4d4c, 0, "ATI Rage 128 Mobility ML (AGP)"},		\
+	{0x1002, 0x5041, 0, "ATI Rage 128 Pro PA (PCI)"},		\
+	{0x1002, 0x5042, 0, "ATI Rage 128 Pro PB (AGP)"},		\
+	{0x1002, 0x5043, 0, "ATI Rage 128 Pro PC (AGP)"},		\
+	{0x1002, 0x5044, 0, "ATI Rage 128 Pro PD (PCI)"},		\
+	{0x1002, 0x5045, 0, "ATI Rage 128 Pro PE (AGP)"},		\
+	{0x1002, 0x5046, 0, "ATI Rage 128 Pro PF (AGP)"},		\
+	{0x1002, 0x5047, 0, "ATI Rage 128 Pro PG (PCI)"},		\
+	{0x1002, 0x5048, 0, "ATI Rage 128 Pro PH (AGP)"},		\
+	{0x1002, 0x5049, 0, "ATI Rage 128 Pro PI (AGP)"},		\
+	{0x1002, 0x504A, 0, "ATI Rage 128 Pro PJ (PCI)"},		\
+	{0x1002, 0x504B, 0, "ATI Rage 128 Pro PK (AGP)"},		\
+	{0x1002, 0x504C, 0, "ATI Rage 128 Pro PL (AGP)"},		\
+	{0x1002, 0x504D, 0, "ATI Rage 128 Pro PM (PCI)"},		\
+	{0x1002, 0x504E, 0, "ATI Rage 128 Pro PN (AGP)"},		\
+	{0x1002, 0x504F, 0, "ATI Rage 128 Pro PO (AGP)"},		\
+	{0x1002, 0x5050, 0, "ATI Rage 128 Pro PP (PCI)"},		\
+	{0x1002, 0x5051, 0, "ATI Rage 128 Pro PQ (AGP)"},		\
+	{0x1002, 0x5052, 0, "ATI Rage 128 Pro PR (PCI)"},		\
+	{0x1002, 0x5053, 0, "ATI Rage 128 Pro PS (PCI)"},		\
+	{0x1002, 0x5054, 0, "ATI Rage 128 Pro PT (AGP)"},		\
+	{0x1002, 0x5055, 0, "ATI Rage 128 Pro PU (AGP)"},		\
+	{0x1002, 0x5056, 0, "ATI Rage 128 Pro PV (PCI)"},		\
+	{0x1002, 0x5057, 0, "ATI Rage 128 Pro PW (AGP)"},		\
+	{0x1002, 0x5058, 0, "ATI Rage 128 Pro PX (AGP)"},		\
+	{0x1002, 0x5245, 0, "ATI Rage 128 RE (PCI)"},			\
+	{0x1002, 0x5246, 0, "ATI Rage 128 RF (AGP)"},			\
+	{0x1002, 0x5247, 0, "ATI Rage 128 RG (AGP)"},			\
+	{0x1002, 0x524b, 0, "ATI Rage 128 RK (PCI)"},			\
+	{0x1002, 0x524c, 0, "ATI Rage 128 RL (AGP)"},			\
+	{0x1002, 0x534d, 0, "ATI Rage 128 SM (AGP)"},			\
+	{0x1002, 0x5446, 0, "ATI Rage 128 Pro Ultra TF (AGP)"},		\
+	{0x1002, 0x544C, 0, "ATI Rage 128 Pro Ultra TL (AGP)"},		\
+	{0x1002, 0x5452, 0, "ATI Rage 128 Pro Ultra TR (AGP)"},		\
+	{0, 0, 0, NULL}
+
 /* Driver customization:
  */
 #define DRIVER_PRERELEASE() do {					\
@@ -97,7 +137,7 @@
 /* DMA customization:
  */
 #define __HAVE_DMA		1
-#define __HAVE_DMA_IRQ		1
+#define __HAVE_IRQ		1
 #define __HAVE_VBL_IRQ		1
 #define __HAVE_SHARED_IRQ       1
 
--- diff/drivers/char/drm/r128_cce.c	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/r128_cce.c	2004-03-09 11:51:49.000000000 +0000
@@ -212,7 +212,7 @@ int r128_do_cce_idle( drm_r128_private_t
 	int i;
 
 	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
-		if ( GET_RING_HEAD( &dev_priv->ring ) == dev_priv->ring.tail ) {
+		if ( GET_RING_HEAD( dev_priv ) == dev_priv->ring.tail ) {
 			int pm4stat = R128_READ( R128_PM4_STAT );
 			if ( ( (pm4stat & R128_PM4_FIFOCNT_MASK) >=
 			       dev_priv->cce_fifo_size ) &&
@@ -238,7 +238,8 @@ static void r128_do_cce_start( drm_r128_
 	r128_do_wait_for_idle( dev_priv );
 
 	R128_WRITE( R128_PM4_BUFFER_CNTL,
-		    dev_priv->cce_mode | dev_priv->ring.size_l2qw );
+		    dev_priv->cce_mode | dev_priv->ring.size_l2qw
+		    | R128_PM4_BUFFER_CNTL_NOUPDATE );
 	R128_READ( R128_PM4_BUFFER_ADDR ); /* as per the sample code */
 	R128_WRITE( R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN );
 
@@ -253,7 +254,6 @@ static void r128_do_cce_reset( drm_r128_
 {
 	R128_WRITE( R128_PM4_BUFFER_DL_WPTR, 0 );
 	R128_WRITE( R128_PM4_BUFFER_DL_RPTR, 0 );
-	SET_RING_HEAD( &dev_priv->ring, 0 );
 	dev_priv->ring.tail = 0;
 }
 
@@ -264,7 +264,8 @@ static void r128_do_cce_reset( drm_r128_
 static void r128_do_cce_stop( drm_r128_private_t *dev_priv )
 {
 	R128_WRITE( R128_PM4_MICRO_CNTL, 0 );
-	R128_WRITE( R128_PM4_BUFFER_CNTL, R128_PM4_NONPM4 );
+	R128_WRITE( R128_PM4_BUFFER_CNTL,
+		    R128_PM4_NONPM4 | R128_PM4_BUFFER_CNTL_NOUPDATE );
 
 	dev_priv->cce_running = 0;
 }
@@ -333,26 +334,6 @@ static void r128_cce_init_ring_buffer( d
 	R128_WRITE( R128_PM4_BUFFER_DL_WPTR, 0 );
 	R128_WRITE( R128_PM4_BUFFER_DL_RPTR, 0 );
 
-	/* DL_RPTR_ADDR is a physical address in AGP space. */
-	SET_RING_HEAD( &dev_priv->ring, 0 );
-
-	if ( !dev_priv->is_pci ) {
-		R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR,
-			    dev_priv->ring_rptr->offset );
-	} else {
-		drm_sg_mem_t *entry = dev->sg;
-		unsigned long tmp_ofs, page_ofs;
-
-		tmp_ofs = dev_priv->ring_rptr->offset - dev->sg->handle;
-		page_ofs = tmp_ofs >> PAGE_SHIFT;
-
-		R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR,
-     			    entry->busaddr[page_ofs]);
-		DRM_DEBUG( "ring rptr: offset=0x%08lx handle=0x%08lx\n",
-			   (unsigned long) entry->busaddr[page_ofs],
-     			   entry->handle + tmp_ofs );
-	}
-
 	/* Set watermark control */
 	R128_WRITE( R128_PM4_BUFFER_WM_CNTL,
 		    ((R128_WATERMARK_L/4) << R128_WMA_SHIFT)
@@ -486,13 +467,6 @@ static int r128_do_init_cce( drm_device_
 		return DRM_ERR(EINVAL);
 	}
 
-	DRM_FIND_MAP( dev_priv->fb, init->fb_offset );
-	if(!dev_priv->fb) {
-		DRM_ERROR("could not find framebuffer!\n");
-		dev->dev_private = (void *)dev_priv;
-		r128_do_cleanup_cce( dev );
-		return DRM_ERR(EINVAL);
-	}
 	DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset );
 	if(!dev_priv->mmio) {
 		DRM_ERROR("could not find mmio region!\n");
@@ -567,9 +541,6 @@ static int r128_do_init_cce( drm_device_
 #endif
 		dev_priv->cce_buffers_offset = dev->sg->handle;
 
-	dev_priv->ring.head = ((__volatile__ u32 *)
-			       dev_priv->ring_rptr->handle);
-
 	dev_priv->ring.start = (u32 *)dev_priv->cce_ring->handle;
 	dev_priv->ring.end = ((u32 *)dev_priv->cce_ring->handle
 			      + init->ring_size / sizeof(u32));
@@ -580,7 +551,6 @@ static int r128_do_init_cce( drm_device_
 		(dev_priv->ring.size / sizeof(u32)) - 1;
 
 	dev_priv->ring.high_mark = 128;
-	dev_priv->ring.ring_rptr = dev_priv->ring_rptr;
 
 	dev_priv->sarea_priv->last_frame = 0;
 	R128_WRITE( R128_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame );
@@ -589,8 +559,9 @@ static int r128_do_init_cce( drm_device_
 	R128_WRITE( R128_LAST_DISPATCH_REG,
 		    dev_priv->sarea_priv->last_dispatch );
 
-#if __REALLY_HAVE_SG
+#if __REALLY_HAVE_AGP
 	if ( dev_priv->is_pci ) {
+#endif
 		if (!DRM(ati_pcigart_init)( dev, &dev_priv->phys_pci_gart,
      					    &dev_priv->bus_pci_gart) ) {
 			DRM_ERROR( "failed to init PCI GART!\n" );
@@ -599,6 +570,7 @@ static int r128_do_init_cce( drm_device_
 			return DRM_ERR(ENOMEM);
 		}
 		R128_WRITE( R128_PCI_GART_PAGE, dev_priv->bus_pci_gart );
+#if __REALLY_HAVE_AGP
 	}
 #endif
 
@@ -615,12 +587,12 @@ static int r128_do_init_cce( drm_device_
 int r128_do_cleanup_cce( drm_device_t *dev )
 {
 
-#if _HAVE_DMA_IRQ
+#if __HAVE_IRQ
 	/* Make sure interrupts are disabled here because the uninstall ioctl
 	 * may not have been called from userspace and after dev_private
 	 * is freed, it's too late.
 	 */
-	if ( dev->irq ) DRM(irq_uninstall)(dev);
+	if ( dev->irq_enabled ) DRM(irq_uninstall)(dev);
 #endif
 
 	if ( dev->dev_private ) {
@@ -901,7 +873,7 @@ int r128_wait_ring( drm_r128_private_t *
 	int i;
 
 	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
-		r128_update_ring_snapshot( ring );
+		r128_update_ring_snapshot( dev_priv );
 		if ( ring->space >= n )
 			return 0;
 		DRM_UDELAY( 1 );
--- diff/drivers/char/drm/r128_drv.c	2002-10-16 04:27:48.000000000 +0100
+++ source/drivers/char/drm/r128_drv.c	2004-03-09 11:51:49.000000000 +0000
@@ -47,6 +47,7 @@
 #include "drm_fops.h"
 #include "drm_init.h"
 #include "drm_ioctl.h"
+#include "drm_irq.h"
 #include "drm_lock.h"
 #include "drm_memory.h"
 #include "drm_proc.h"
--- diff/drivers/char/drm/r128_drv.h	2003-08-20 14:16:27.000000000 +0100
+++ source/drivers/char/drm/r128_drv.h	2004-03-09 11:51:49.000000000 +0000
@@ -34,8 +34,7 @@
 #ifndef __R128_DRV_H__
 #define __R128_DRV_H__
 
-#define GET_RING_HEAD(ring)		DRM_READ32(  (ring)->ring_rptr, 0 ) /* (ring)->head */
-#define SET_RING_HEAD(ring,val)		DRM_WRITE32( (ring)->ring_rptr, 0, (val) ) /* (ring)->head */
+#define GET_RING_HEAD(dev_priv)		R128_READ( R128_PM4_BUFFER_DL_RPTR )
 
 typedef struct drm_r128_freelist {
    	unsigned int age;
@@ -50,13 +49,11 @@ typedef struct drm_r128_ring_buffer {
 	int size;
 	int size_l2qw;
 
-	volatile u32 *head;
 	u32 tail;
 	u32 tail_mask;
 	int space;
 
 	int high_mark;
-	drm_local_map_t *ring_rptr;
 } drm_r128_ring_buffer_t;
 
 typedef struct drm_r128_private {
@@ -100,7 +97,6 @@ typedef struct drm_r128_private {
 	u32 span_pitch_offset_c;
 
 	drm_local_map_t *sarea;
-	drm_local_map_t *fb;
 	drm_local_map_t *mmio;
 	drm_local_map_t *cce_ring;
 	drm_local_map_t *ring_rptr;
@@ -132,14 +128,6 @@ extern drm_buf_t *r128_freelist_get( drm
 
 extern int r128_wait_ring( drm_r128_private_t *dev_priv, int n );
 
-static __inline__ void
-r128_update_ring_snapshot( drm_r128_ring_buffer_t *ring )
-{
-	ring->space = (GET_RING_HEAD( ring ) - ring->tail) * sizeof(u32);
-	if ( ring->space <= 0 )
-		ring->space += ring->size;
-}
-
 extern int r128_do_cce_idle( drm_r128_private_t *dev_priv );
 extern int r128_do_cleanup_cce( drm_device_t *dev );
 extern int r128_do_cleanup_pageflip( drm_device_t *dev );
@@ -279,6 +267,7 @@ extern int r128_cce_indirect( DRM_IOCTL_
 #	define R128_PM4_64PIO_64VCBM_64INDBM	(7  << 28)
 #	define R128_PM4_64BM_64VCBM_64INDBM	(8  << 28)
 #	define R128_PM4_64PIO_64VCPIO_64INDPIO	(15 << 28)
+#	define R128_PM4_BUFFER_CNTL_NOUPDATE	(1  << 27)
 
 #define R128_PM4_BUFFER_WM_CNTL		0x0708
 #	define R128_WMA_SHIFT			0
@@ -403,6 +392,15 @@ extern int R128_READ_PLL(drm_device_t *d
 					 (pkt) | ((n) << 16))
 
 
+static __inline__ void
+r128_update_ring_snapshot( drm_r128_private_t *dev_priv )
+{
+	drm_r128_ring_buffer_t *ring = &dev_priv->ring;
+	ring->space = (GET_RING_HEAD( dev_priv ) - ring->tail) * sizeof(u32);
+	if ( ring->space <= 0 )
+		ring->space += ring->size;
+}
+
 /* ================================================================
  * Misc helper macros
  */
@@ -412,7 +410,7 @@ do {									\
 	drm_r128_ring_buffer_t *ring = &dev_priv->ring; int i;		\
 	if ( ring->space < ring->high_mark ) {				\
 		for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {	\
-			r128_update_ring_snapshot( ring );		\
+			r128_update_ring_snapshot( dev_priv );		\
 			if ( ring->space >= ring->high_mark )		\
 				goto __ring_space_done;			\
 			DRM_UDELAY(1);				\
@@ -445,17 +443,10 @@ do {									\
  * Ring control
  */
 
-#if defined(__powerpc__)
-#define r128_flush_write_combine()	(void) GET_RING_HEAD( &dev_priv->ring )
-#else
-#define r128_flush_write_combine()	DRM_WRITEMEMORYBARRIER()
-#endif
-
-
 #define R128_VERBOSE	0
 
 #define RING_LOCALS							\
-	int write; unsigned int tail_mask; volatile u32 *ring;
+	int write, _nr; unsigned int tail_mask; volatile u32 *ring;
 
 #define BEGIN_RING( n ) do {						\
 	if ( R128_VERBOSE ) {						\
@@ -463,9 +454,10 @@ do {									\
 			   (n), __FUNCTION__ );				\
 	}								\
 	if ( dev_priv->ring.space <= (n) * sizeof(u32) ) {		\
+		COMMIT_RING();						\
 		r128_wait_ring( dev_priv, (n) * sizeof(u32) );		\
 	}								\
-	dev_priv->ring.space -= (n) * sizeof(u32);			\
+	_nr = n; dev_priv->ring.space -= (n) * sizeof(u32);		\
 	ring = dev_priv->ring.start;					\
 	write = dev_priv->ring.tail;					\
 	tail_mask = dev_priv->ring.tail_mask;				\
@@ -488,9 +480,23 @@ do {									\
 			dev_priv->ring.start,				\
 			write * sizeof(u32) );				\
 	}								\
-	r128_flush_write_combine();					\
-	dev_priv->ring.tail = write;					\
-	R128_WRITE( R128_PM4_BUFFER_DL_WPTR, write );			\
+	if (((dev_priv->ring.tail + _nr) & tail_mask) != write) {	\
+		DRM_ERROR( 						\
+			"ADVANCE_RING(): mismatch: nr: %x write: %x line: %d\n",	\
+			((dev_priv->ring.tail + _nr) & tail_mask),	\
+			write, __LINE__);				\
+	} else								\
+		dev_priv->ring.tail = write;				\
+} while (0)
+
+#define COMMIT_RING() do {						\
+	if ( R128_VERBOSE ) {						\
+		DRM_INFO( "COMMIT_RING() tail=0x%06x\n",		\
+			dev_priv->ring.tail );				\
+	}								\
+	DRM_MEMORYBARRIER();						\
+	R128_WRITE( R128_PM4_BUFFER_DL_WPTR, dev_priv->ring.tail );	\
+	R128_READ( R128_PM4_BUFFER_DL_WPTR );				\
 } while (0)
 
 #define OUT_RING( x ) do {						\
--- diff/drivers/char/drm/r128_irq.c	2003-05-21 11:50:14.000000000 +0100
+++ source/drivers/char/drm/r128_irq.c	2004-03-09 11:51:49.000000000 +0000
@@ -36,7 +36,7 @@
 #include "r128_drm.h"
 #include "r128_drv.h"
 
-irqreturn_t r128_dma_service( DRM_IRQ_ARGS )
+irqreturn_t r128_irq_handler( DRM_IRQ_ARGS )
 {
 	drm_device_t *dev = (drm_device_t *) arg;
 	drm_r128_private_t *dev_priv = 
--- diff/drivers/char/drm/r128_state.c	2003-08-20 14:16:27.000000000 +0100
+++ source/drivers/char/drm/r128_state.c	2004-03-09 11:51:49.000000000 +0000
@@ -45,7 +45,7 @@ static void r128_emit_clip_rects( drm_r1
 	RING_LOCALS;
 	DRM_DEBUG( "    %s\n", __FUNCTION__ );
 
-	BEGIN_RING( 17 );
+	BEGIN_RING( (count < 3? count: 3) * 5 + 2 );
 
 	if ( count >= 1 ) {
 		OUT_RING( CCE_PACKET0( R128_AUX1_SC_LEFT, 3 ) );
@@ -1269,6 +1269,7 @@ int r128_cce_clear( DRM_IOCTL_ARGS )
 		sarea_priv->nbox = R128_NR_SAREA_CLIPRECTS;
 
 	r128_cce_dispatch_clear( dev, &clear );
+	COMMIT_RING();
 
 	/* Make sure we restore the 3D state next time.
 	 */
@@ -1304,8 +1305,10 @@ int r128_do_cleanup_pageflip( drm_device
 	R128_WRITE( R128_CRTC_OFFSET,      dev_priv->crtc_offset );
 	R128_WRITE( R128_CRTC_OFFSET_CNTL, dev_priv->crtc_offset_cntl );
 
-	if (dev_priv->current_page != 0)
+	if (dev_priv->current_page != 0) {
 		r128_cce_dispatch_flip( dev );
+		COMMIT_RING();
+	}
 
 	dev_priv->page_flipping = 0;
 	return 0;
@@ -1330,6 +1333,7 @@ int r128_cce_flip( DRM_IOCTL_ARGS )
 
 	r128_cce_dispatch_flip( dev );
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1351,6 +1355,7 @@ int r128_cce_swap( DRM_IOCTL_ARGS )
 	dev_priv->sarea_priv->dirty |= (R128_UPLOAD_CONTEXT |
 					R128_UPLOAD_MASKS);
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1410,6 +1415,7 @@ int r128_cce_vertex( DRM_IOCTL_ARGS )
 
 	r128_cce_dispatch_vertex( dev, buf );
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1481,6 +1487,7 @@ int r128_cce_indices( DRM_IOCTL_ARGS )
 
 	r128_cce_dispatch_indices( dev, buf, elts.start, elts.end, count );
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1490,6 +1497,7 @@ int r128_cce_blit( DRM_IOCTL_ARGS )
 	drm_device_dma_t *dma = dev->dma;
 	drm_r128_private_t *dev_priv = dev->dev_private;
 	drm_r128_blit_t blit;
+	int ret;
 
 	LOCK_TEST_WITH_RETURN( dev, filp );
 
@@ -1507,7 +1515,10 @@ int r128_cce_blit( DRM_IOCTL_ARGS )
 	RING_SPACE_TEST_WITH_RETURN( dev_priv );
 	VB_AGE_TEST_WITH_RETURN( dev_priv );
 
-	return r128_cce_dispatch_blit( filp, dev, &blit );
+	ret = r128_cce_dispatch_blit( filp, dev, &blit );
+
+	COMMIT_RING();
+	return ret;
 }
 
 int r128_cce_depth( DRM_IOCTL_ARGS )
@@ -1515,6 +1526,7 @@ int r128_cce_depth( DRM_IOCTL_ARGS )
 	DRM_DEVICE;
 	drm_r128_private_t *dev_priv = dev->dev_private;
 	drm_r128_depth_t depth;
+	int ret;
 
 	LOCK_TEST_WITH_RETURN( dev, filp );
 
@@ -1523,18 +1535,20 @@ int r128_cce_depth( DRM_IOCTL_ARGS )
 
 	RING_SPACE_TEST_WITH_RETURN( dev_priv );
 
+	ret = DRM_ERR(EINVAL);
 	switch ( depth.func ) {
 	case R128_WRITE_SPAN:
-		return r128_cce_dispatch_write_span( dev, &depth );
+		ret = r128_cce_dispatch_write_span( dev, &depth );
 	case R128_WRITE_PIXELS:
-		return r128_cce_dispatch_write_pixels( dev, &depth );
+		ret = r128_cce_dispatch_write_pixels( dev, &depth );
 	case R128_READ_SPAN:
-		return r128_cce_dispatch_read_span( dev, &depth );
+		ret = r128_cce_dispatch_read_span( dev, &depth );
 	case R128_READ_PIXELS:
-		return r128_cce_dispatch_read_pixels( dev, &depth );
+		ret = r128_cce_dispatch_read_pixels( dev, &depth );
 	}
 
-	return DRM_ERR(EINVAL);
+	COMMIT_RING();
+	return ret;
 }
 
 int r128_cce_stipple( DRM_IOCTL_ARGS )
@@ -1557,6 +1571,7 @@ int r128_cce_stipple( DRM_IOCTL_ARGS )
 
 	r128_cce_dispatch_stipple( dev, mask );
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1632,6 +1647,7 @@ int r128_cce_indirect( DRM_IOCTL_ARGS )
 	 */
 	r128_cce_dispatch_indirect( dev, buf, indirect.start, indirect.end );
 
+	COMMIT_RING();
 	return 0;
 }
 
--- diff/drivers/char/drm/radeon.h	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/radeon.h	2004-03-09 11:51:49.000000000 +0000
@@ -51,7 +51,7 @@
 #define DRIVER_DATE		"20020828"
 
 #define DRIVER_MAJOR		1
-#define DRIVER_MINOR		9
+#define DRIVER_MINOR		10
 #define DRIVER_PATCHLEVEL	0
 
 /* Interface history:
@@ -81,6 +81,9 @@
  *       Add 'GET' queries for starting additional clients on different VT's.
  * 1.9 - Add DRM_IOCTL_RADEON_CP_RESUME ioctl.
  *       Add texture rectangle support for r100.
+ * 1.10- Add SETPARAM ioctl; first parameter to set is FB_LOCATION, which
+ *       clients use to tell the DRM where they think the framebuffer is 
+ *       located in the card's address space
  */
 #define DRIVER_IOCTLS							     \
  [DRM_IOCTL_NR(DRM_IOCTL_DMA)]               = { radeon_cp_buffers,  1, 0 }, \
@@ -106,10 +109,82 @@
  [DRM_IOCTL_NR(DRM_IOCTL_RADEON_ALLOC)]      = { radeon_mem_alloc,   1, 0 }, \
  [DRM_IOCTL_NR(DRM_IOCTL_RADEON_FREE)]       = { radeon_mem_free,    1, 0 }, \
  [DRM_IOCTL_NR(DRM_IOCTL_RADEON_INIT_HEAP)]  = { radeon_mem_init_heap, 1, 1 }, \
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_EMIT)]   = { radeon_irq_emit, 1, 0 }, \
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_WAIT)]   = { radeon_irq_wait, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_EMIT)]   = { radeon_irq_emit,    1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_WAIT)]   = { radeon_irq_wait,    1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_SETPARAM)]   = { radeon_cp_setparam, 1, 0 }, \
+
+#define DRIVER_PCI_IDS							\
+	{0x1002, 0x4136, 0, "ATI Radeon RS100 IGP 320M"},		\
+	{0x1002, 0x4137, 0, "ATI Radeon RS200 IGP"},			\
+	{0x1002, 0x4237, 0, "ATI Radeon RS250 IGP"},			\
+	{0x1002, 0x4242, 0, "ATI Radeon BB R200 AIW 8500DV"},		\
+	{0x1002, 0x4242, 0, "ATI Radeon BC R200"},			\
+	{0x1002, 0x4336, 0, "ATI Radeon RS100 Mobility U1"},		\
+	{0x1002, 0x4337, 0, "ATI Radeon RS200 Mobility IGP 340M"},	\
+	{0x1002, 0x4437, 0, "ATI Radeon RS250 Mobility IGP"},		\
+	{0x1002, 0x4964, 0, "ATI Radeon Id R250 9000"},			\
+	{0x1002, 0x4965, 0, "ATI Radeon Ie R250 9000"},			\
+	{0x1002, 0x4966, 0, "ATI Radeon If R250 9000"},			\
+	{0x1002, 0x4967, 0, "ATI Radeon Ig R250 9000"},			\
+	{0x1002, 0x4C57, 0, "ATI Radeon LW Mobility 7500 M7"},		\
+	{0x1002, 0x4C58, 0, "ATI Radeon LX RV200 Mobility FireGL 7800 M7"}, \
+	{0x1002, 0x4C59, 0, "ATI Radeon LY Mobility M6"},		\
+	{0x1002, 0x4C5A, 0, "ATI Radeon LZ Mobility M6"},		\
+	{0x1002, 0x4C64, 0, "ATI Radeon Ld R250 Mobility 9000 M9"},	\
+	{0x1002, 0x4C65, 0, "ATI Radeon Le R250 Mobility 9000 M9"},	\
+	{0x1002, 0x4C66, 0, "ATI Radeon Lf R250 Mobility 9000 M9"},	\
+	{0x1002, 0x4C67, 0, "ATI Radeon Lg R250 Mobility 9000 M9"},	\
+	{0x1002, 0x5144, 0, "ATI Radeon QD R100"},			\
+	{0x1002, 0x5145, 0, "ATI Radeon QE R100"},			\
+	{0x1002, 0x5146, 0, "ATI Radeon QF R100"},			\
+	{0x1002, 0x5147, 0, "ATI Radeon QG R100"},			\
+	{0x1002, 0x5148, 0, "ATI Radeon QH R200 8500"},			\
+	{0x1002, 0x5149, 0, "ATI Radeon QI R200"},			\
+	{0x1002, 0x514A, 0, "ATI Radeon QJ R200"},			\
+	{0x1002, 0x514B, 0, "ATI Radeon QK R200"},			\
+	{0x1002, 0x514C, 0, "ATI Radeon QL R200 8500 LE"},		\
+	{0x1002, 0x514D, 0, "ATI Radeon QM R200 9100"},			\
+	{0x1002, 0x514E, 0, "ATI Radeon QN R200 8500 LE"},		\
+	{0x1002, 0x514F, 0, "ATI Radeon QO R200 8500 LE"},		\
+	{0x1002, 0x5157, 0, "ATI Radeon QW RV200 7500"},		\
+	{0x1002, 0x5158, 0, "ATI Radeon QX RV200 7500"},		\
+	{0x1002, 0x5159, 0, "ATI Radeon QY RV100 7000/VE"},		\
+	{0x1002, 0x515A, 0, "ATI Radeon QZ RV100 7000/VE"},		\
+	{0x1002, 0x5168, 0, "ATI Radeon Qh R200"},			\
+	{0x1002, 0x5169, 0, "ATI Radeon Qi R200"},			\
+	{0x1002, 0x516A, 0, "ATI Radeon Qj R200"},			\
+	{0x1002, 0x516B, 0, "ATI Radeon Qk R200"},			\
+	{0x1002, 0x516C, 0, "ATI Radeon Ql R200"},			\
+	{0x1002, 0x5834, 0, "ATI Radeon RS300 IGP"},			\
+	{0x1002, 0x5835, 0, "ATI Radeon RS300 Mobility IGP"},		\
+	{0x1002, 0x5836, 0, "ATI Radeon RS300 IGP"},			\
+	{0x1002, 0x5837, 0, "ATI Radeon RS300 IGP"},			\
+	{0x1002, 0x5960, 0, "ATI Radeon RV280 9200"},			\
+	{0x1002, 0x5961, 0, "ATI Radeon RV280 9200 SE"},		\
+	{0x1002, 0x5962, 0, "ATI Radeon RV280 9200"},			\
+	{0x1002, 0x5963, 0, "ATI Radeon RV280 9200"},			\
+	{0x1002, 0x5964, 0, "ATI Radeon RV280 9200 SE"},		\
+	{0x1002, 0x5968, 0, "ATI Radeon RV280 9200"},			\
+	{0x1002, 0x5969, 0, "ATI Radeon RV280 9200"},			\
+	{0x1002, 0x596A, 0, "ATI Radeon RV280 9200"},			\
+	{0x1002, 0x596B, 0, "ATI Radeon RV280 9200"},			\
+	{0x1002, 0x5c61, 0, "ATI Radeon RV280 Mobility"},		\
+	{0x1002, 0x5c62, 0, "ATI Radeon RV280"},			\
+	{0x1002, 0x5c63, 0, "ATI Radeon RV280 Mobility"},		\
+	{0x1002, 0x5c64, 0, "ATI Radeon RV280"},			\
+	{0, 0, 0, NULL}
 
+#define DRIVER_FILE_FIELDS						\
+	int64_t radeon_fb_delta;					\
 
+#define DRIVER_OPEN_HELPER( filp_priv, dev )				\
+do {									\
+	drm_radeon_private_t *dev_priv = dev->dev_private;		\
+	if ( dev_priv )							\
+		filp_priv->radeon_fb_delta = dev_priv->fb_location;	\
+	else								\
+		filp_priv->radeon_fb_delta = 0;				\
+} while( 0 )
 
 /* When a client dies:
  *    - Check for and clean up flipped page state
@@ -125,7 +200,7 @@ do {									\
 			radeon_do_cleanup_pageflip( dev );		\
 		}							\
 		radeon_mem_release( filp, dev_priv->gart_heap );	\
-                radeon_mem_release( filp, dev_priv->fb_heap );		\
+		radeon_mem_release( filp, dev_priv->fb_heap );		\
 	}								\
 } while (0)
 
@@ -142,7 +217,7 @@ do {						\
 /* DMA customization:
  */
 #define __HAVE_DMA		1
-#define __HAVE_DMA_IRQ		1
+#define __HAVE_IRQ		1
 #define __HAVE_VBL_IRQ		1
 #define __HAVE_SHARED_IRQ       1
 
--- diff/drivers/char/drm/radeon_cp.c	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/radeon_cp.c	2004-03-09 11:51:49.000000000 +0000
@@ -855,7 +855,8 @@ static void radeon_cp_init_ring_buffer( 
 
 	/* Initialize the memory controller */
 	RADEON_WRITE( RADEON_MC_FB_LOCATION,
-		      (dev_priv->gart_vm_start - 1) & 0xffff0000 );
+		      ( ( dev_priv->gart_vm_start - 1 ) & 0xffff0000 )
+		    | ( dev_priv->fb_location >> 16 ) );
 
 #if __REALLY_HAVE_AGP
 	if ( !dev_priv->is_pci ) {
@@ -1071,13 +1072,6 @@ static int radeon_do_init_cp( drm_device
 	dev_priv->depth_offset	= init->depth_offset;
 	dev_priv->depth_pitch	= init->depth_pitch;
 
-	dev_priv->front_pitch_offset = (((dev_priv->front_pitch/64) << 22) |
-					(dev_priv->front_offset >> 10));
-	dev_priv->back_pitch_offset = (((dev_priv->back_pitch/64) << 22) |
-				       (dev_priv->back_offset >> 10));
-	dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch/64) << 22) |
-					(dev_priv->depth_offset >> 10));
-
 	/* Hardware state for depth clears.  Remove this if/when we no
 	 * longer clear the depth buffer with a 3D rectangle.  Hard-code
 	 * all values to prevent unwanted 3D state from slipping through
@@ -1124,13 +1118,6 @@ static int radeon_do_init_cp( drm_device
 		return DRM_ERR(EINVAL);
 	}
 
-	DRM_FIND_MAP( dev_priv->fb, init->fb_offset );
-	if(!dev_priv->fb) {
-		DRM_ERROR("could not find framebuffer!\n");
-		dev->dev_private = (void *)dev_priv;
-		radeon_do_cleanup_cp(dev);
-		return DRM_ERR(EINVAL);
-	}
 	DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset );
 	if(!dev_priv->mmio) {
 		DRM_ERROR("could not find mmio region!\n");
@@ -1204,9 +1191,26 @@ static int radeon_do_init_cp( drm_device
 			   dev_priv->buffers->handle );
 	}
 
+	dev_priv->fb_location = ( RADEON_READ( RADEON_MC_FB_LOCATION )
+				& 0xffff ) << 16;
+
+	dev_priv->front_pitch_offset = (((dev_priv->front_pitch/64) << 22) |
+					( ( dev_priv->front_offset
+					  + dev_priv->fb_location ) >> 10 ) );
+
+	dev_priv->back_pitch_offset = (((dev_priv->back_pitch/64) << 22) |
+				       ( ( dev_priv->back_offset
+					 + dev_priv->fb_location ) >> 10 ) );
+
+	dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch/64) << 22) |
+					( ( dev_priv->depth_offset
+					  + dev_priv->fb_location ) >> 10 ) );
+
 
 	dev_priv->gart_size = init->gart_size;
-	dev_priv->gart_vm_start = RADEON_READ( RADEON_CONFIG_APER_SIZE );
+	dev_priv->gart_vm_start = dev_priv->fb_location
+				+ RADEON_READ( RADEON_CONFIG_APER_SIZE );
+
 #if __REALLY_HAVE_AGP
 	if ( !dev_priv->is_pci )
 		dev_priv->gart_buffers_offset = (dev_priv->buffers->offset
@@ -1271,12 +1275,12 @@ int radeon_do_cleanup_cp( drm_device_t *
 {
 	DRM_DEBUG( "\n" );
 
-#if _HAVE_DMA_IRQ
+#if __HAVE_IRQ
 	/* Make sure interrupts are disabled here because the uninstall ioctl
 	 * may not have been called from userspace and after dev_private
 	 * is freed, it's too late.
 	 */
-	if ( dev->irq ) DRM(irq_uninstall)(dev);
+	if ( dev->irq_enabled ) DRM(irq_uninstall)(dev);
 #endif
 
 	if ( dev->dev_private ) {
--- diff/drivers/char/drm/radeon_drm.h	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/radeon_drm.h	2004-03-09 11:51:49.000000000 +0000
@@ -390,6 +390,7 @@ typedef struct {
 #define DRM_IOCTL_RADEON_IRQ_WAIT   DRM_IOW( 0x57, drm_radeon_irq_wait_t)
 /* added by Charl P. Botha - see radeon_cp.c for details */
 #define DRM_IOCTL_RADEON_CP_RESUME  DRM_IO(0x58)
+#define DRM_IOCTL_RADEON_SETPARAM   DRM_IOW(0x59, drm_radeon_setparam_t)
 
 typedef struct drm_radeon_init {
 	enum {
@@ -502,7 +503,7 @@ typedef struct drm_radeon_tex_image {
 } drm_radeon_tex_image_t;
 
 typedef struct drm_radeon_texture {
-	int offset;
+	unsigned int offset;
 	int pitch;
 	int format;
 	int width;			/* Texture image coordinates */
@@ -537,6 +538,7 @@ typedef struct drm_radeon_indirect {
 #define RADEON_PARAM_STATUS_HANDLE         8
 #define RADEON_PARAM_SAREA_HANDLE          9
 #define RADEON_PARAM_GART_TEX_HANDLE       10
+#define RADEON_PARAM_SCRATCH_OFFSET        11
 
 typedef struct drm_radeon_getparam {
 	int param;
@@ -578,4 +580,16 @@ typedef struct drm_radeon_irq_wait {
 } drm_radeon_irq_wait_t;
 
 
+/* 1.10: Clients tell the DRM where they think the framebuffer is located in
+ * the card's address space, via a new generic ioctl to set parameters
+ */
+
+typedef struct drm_radeon_setparam {
+	unsigned int param;
+	int64_t      value;
+} drm_radeon_setparam_t;
+
+#define RADEON_SETPARAM_FB_LOCATION    1 /* determined framebuffer location */
+
+
 #endif
--- diff/drivers/char/drm/radeon_drv.c	2003-07-22 18:54:27.000000000 +0100
+++ source/drivers/char/drm/radeon_drv.c	2004-03-09 11:51:49.000000000 +0000
@@ -48,6 +48,7 @@
 #include "drm_fops.h"
 #include "drm_init.h"
 #include "drm_ioctl.h"
+#include "drm_irq.h"
 #include "drm_lock.h"
 #include "drm_memory.h"
 #include "drm_proc.h"
--- diff/drivers/char/drm/radeon_drv.h	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/radeon_drv.h	2004-03-09 11:51:49.000000000 +0000
@@ -73,6 +73,8 @@ typedef struct drm_radeon_private {
 	drm_radeon_ring_buffer_t ring;
 	drm_radeon_sarea_t *sarea_priv;
 
+	u32 fb_location;
+
 	int gart_size;
 	u32 gart_vm_start;
 	unsigned long gart_buffers_offset;
@@ -133,7 +135,6 @@ typedef struct drm_radeon_private {
 	unsigned long gart_textures_offset;
 
 	drm_local_map_t *sarea;
-	drm_local_map_t *fb;
 	drm_local_map_t *mmio;
 	drm_local_map_t *cp_ring;
 	drm_local_map_t *ring_rptr;
@@ -184,6 +185,7 @@ extern int radeon_cp_indirect( DRM_IOCTL
 extern int radeon_cp_vertex2( DRM_IOCTL_ARGS );
 extern int radeon_cp_cmdbuf( DRM_IOCTL_ARGS );
 extern int radeon_cp_getparam( DRM_IOCTL_ARGS );
+extern int radeon_cp_setparam( DRM_IOCTL_ARGS );
 extern int radeon_cp_flip( DRM_IOCTL_ARGS );
 
 extern int radeon_mem_alloc( DRM_IOCTL_ARGS );
@@ -239,6 +241,7 @@ extern void radeon_do_release(drm_device
 #define RADEON_CRTC2_OFFSET		0x0324
 #define RADEON_CRTC2_OFFSET_CNTL	0x0328
 
+#define RADEON_RB3D_COLOROFFSET		0x1c40
 #define RADEON_RB3D_COLORPITCH		0x1c48
 
 #define RADEON_DP_GUI_MASTER_CNTL	0x146c
@@ -332,6 +335,7 @@ extern void radeon_do_release(drm_device
 #define RADEON_PP_MISC			0x1c14
 #define RADEON_PP_ROT_MATRIX_0		0x1d58
 #define RADEON_PP_TXFILTER_0		0x1c54
+#define RADEON_PP_TXOFFSET_0		0x1c5c
 #define RADEON_PP_TXFILTER_1		0x1c6c
 #define RADEON_PP_TXFILTER_2		0x1c84
 
--- diff/drivers/char/drm/radeon_irq.c	2003-05-21 11:50:14.000000000 +0100
+++ source/drivers/char/drm/radeon_irq.c	2004-03-09 11:51:49.000000000 +0000
@@ -54,7 +54,7 @@
  * tied to dma at all, this is just a hangover from dri prehistory.
  */
 
-irqreturn_t DRM(dma_service)( DRM_IRQ_ARGS )
+irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS )
 {
 	drm_device_t *dev = (drm_device_t *) arg;
 	drm_radeon_private_t *dev_priv = 
--- diff/drivers/char/drm/radeon_state.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/drm/radeon_state.c	2004-03-09 11:51:49.000000000 +0000
@@ -36,6 +36,151 @@
 
 
 /* ================================================================
+ * Helper functions for client state checking and fixup
+ */
+
+static __inline__ int radeon_check_and_fixup_offset( drm_radeon_private_t *dev_priv,
+						     drm_file_t *filp_priv,
+						     u32 *offset ) {
+	u32 off = *offset;
+
+	if ( off >= dev_priv->fb_location &&
+	     off < ( dev_priv->gart_vm_start + dev_priv->gart_size ) )
+		return 0;
+
+	off += filp_priv->radeon_fb_delta;
+
+	DRM_DEBUG( "offset fixed up to 0x%x\n", off );
+
+	if ( off < dev_priv->fb_location ||
+	     off >= ( dev_priv->gart_vm_start + dev_priv->gart_size ) )
+		return DRM_ERR( EINVAL );
+
+	*offset = off;
+
+	return 0;
+}
+
+static __inline__ int radeon_check_and_fixup_offset_user( drm_radeon_private_t *dev_priv,
+							  drm_file_t *filp_priv,
+							  u32 *offset ) {
+	u32 off;
+
+	DRM_GET_USER_UNCHECKED( off, offset );
+
+	if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &off ) )
+		return DRM_ERR( EINVAL );
+
+	DRM_PUT_USER_UNCHECKED( offset, off );
+
+	return 0;
+}
+
+static __inline__ int radeon_check_and_fixup_packets( drm_radeon_private_t *dev_priv,
+						      drm_file_t *filp_priv,
+						      int id,
+						      u32 *data ) {
+	if ( id == RADEON_EMIT_PP_MISC &&
+	     radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+						 &data[( RADEON_RB3D_DEPTHOFFSET
+							 - RADEON_PP_MISC ) / 4] ) ) {
+		DRM_ERROR( "Invalid depth buffer offset\n" );
+		return DRM_ERR( EINVAL );
+	} else if ( id == RADEON_EMIT_PP_CNTL &&
+		    radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+							&data[( RADEON_RB3D_COLOROFFSET
+								- RADEON_PP_CNTL ) / 4] ) ) {
+		DRM_ERROR( "Invalid colour buffer offset\n" );
+		return DRM_ERR( EINVAL );
+	} else if ( id >= R200_EMIT_PP_TXOFFSET_0 &&
+		    id <= R200_EMIT_PP_TXOFFSET_5 &&
+		    radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+							&data[0] ) ) {
+		DRM_ERROR( "Invalid R200 texture offset\n" );
+		return DRM_ERR( EINVAL );
+	} else if ( ( id == RADEON_EMIT_PP_TXFILTER_0 || id == RADEON_EMIT_PP_TXFILTER_1 ||
+		      id == RADEON_EMIT_PP_TXFILTER_2 /*|| id == RADEON_EMIT_PP_TXFILTER_3 ||
+		      id == RADEON_EMIT_PP_TXFILTER_4 || id == RADEON_EMIT_PP_TXFILTER_5*/ ) &&
+		    radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+							&data[( RADEON_PP_TXOFFSET_0
+								- RADEON_PP_TXFILTER_0 ) / 4] ) ) {
+		DRM_ERROR( "Invalid R100 texture offset\n" );
+		return DRM_ERR( EINVAL );
+	} else if ( id == R200_PP_CUBIC_OFFSET_F1_0 || id == R200_PP_CUBIC_OFFSET_F1_1 ||
+		    id == R200_PP_CUBIC_OFFSET_F1_2 || id == R200_PP_CUBIC_OFFSET_F1_3 ||
+		    id == R200_PP_CUBIC_OFFSET_F1_4 || id == R200_PP_CUBIC_OFFSET_F1_5 ) {
+		int i;
+		for ( i = 0; i < 6; i++ ) {
+			if ( radeon_check_and_fixup_offset_user( dev_priv,
+								 filp_priv,
+								 &data[i] ) ) {
+				DRM_ERROR( "Invalid R200 cubic texture offset\n" );
+				return DRM_ERR( EINVAL );
+			}
+		}
+	}
+
+	return 0;
+}
+
+static __inline__ int radeon_check_and_fixup_packet3( drm_radeon_private_t *dev_priv,
+						      drm_file_t *filp_priv,
+						      drm_radeon_cmd_buffer_t *cmdbuf,
+						      unsigned int *cmdsz ) {
+	u32 tmp[4], *cmd = ( u32* )cmdbuf->buf;
+
+	if ( DRM_COPY_FROM_USER_UNCHECKED( tmp, cmd, sizeof( tmp ) ) ) {
+		DRM_ERROR( "Failed to copy data from user space\n" );
+		return DRM_ERR( EFAULT );
+	}
+
+	*cmdsz = 2 + ( ( tmp[0] & RADEON_CP_PACKET_COUNT_MASK ) >> 16 );
+
+	if ( ( tmp[0] & 0xc0000000 ) != RADEON_CP_PACKET3 ) {
+		DRM_ERROR( "Not a type 3 packet\n" );
+		return DRM_ERR( EINVAL );
+	}
+
+	if ( 4 * *cmdsz > cmdbuf->bufsz ) {
+		DRM_ERROR( "Packet size larger than size of data provided\n" );
+		return DRM_ERR( EINVAL );
+	}
+
+	/* Check client state and fix it up if necessary */
+	if ( tmp[0] & 0x8000 ) { /* MSB of opcode: next DWORD GUI_CNTL */
+		u32 offset;
+
+		if ( tmp[1] & ( RADEON_GMC_SRC_PITCH_OFFSET_CNTL
+			      | RADEON_GMC_DST_PITCH_OFFSET_CNTL ) ) {
+			offset = tmp[2] << 10;
+			if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &offset ) ) {
+				DRM_ERROR( "Invalid first packet offset\n" );
+				return DRM_ERR( EINVAL );
+			}
+			tmp[2] = ( tmp[2] & 0xffc00000 ) | offset >> 10;
+		}
+
+		if ( ( tmp[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL ) &&
+		     ( tmp[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL ) ) {
+			offset = tmp[3] << 10;
+			if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &offset ) ) {
+				DRM_ERROR( "Invalid second packet offset\n" );
+				return DRM_ERR( EINVAL );
+			}
+			tmp[3] = ( tmp[3] & 0xffc00000 ) | offset >> 10;
+		}
+
+		if ( DRM_COPY_TO_USER_UNCHECKED( cmd, tmp, sizeof( tmp ) ) ) {
+			DRM_ERROR( "Failed to copy data to user space\n" );
+			return DRM_ERR( EFAULT );
+		}
+	}
+
+	return 0;
+}
+
+
+/* ================================================================
  * CP hardware state programming functions
  */
 
@@ -57,15 +202,28 @@ static __inline__ void radeon_emit_clip_
 
 /* Emit 1.1 state
  */
-static void radeon_emit_state( drm_radeon_private_t *dev_priv,
-			       drm_radeon_context_regs_t *ctx,
-			       drm_radeon_texture_regs_t *tex,
-			       unsigned int dirty )
+static int radeon_emit_state( drm_radeon_private_t *dev_priv,
+			      drm_file_t *filp_priv,
+			      drm_radeon_context_regs_t *ctx,
+			      drm_radeon_texture_regs_t *tex,
+			      unsigned int dirty )
 {
 	RING_LOCALS;
 	DRM_DEBUG( "dirty=0x%08x\n", dirty );
 
 	if ( dirty & RADEON_UPLOAD_CONTEXT ) {
+		if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+						    &ctx->rb3d_depthoffset ) ) {
+			DRM_ERROR( "Invalid depth buffer offset\n" );
+			return DRM_ERR( EINVAL );
+		}
+
+		if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+						    &ctx->rb3d_coloroffset ) ) {
+			DRM_ERROR( "Invalid depth buffer offset\n" );
+			return DRM_ERR( EINVAL );
+		}
+
 		BEGIN_RING( 14 );
 		OUT_RING( CP_PACKET0( RADEON_PP_MISC, 6 ) );
 		OUT_RING( ctx->pp_misc );
@@ -149,6 +307,12 @@ static void radeon_emit_state( drm_radeo
 	}
 
 	if ( dirty & RADEON_UPLOAD_TEX0 ) {
+		if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+						    &tex[0].pp_txoffset ) ) {
+			DRM_ERROR( "Invalid texture offset for unit 0\n" );
+			return DRM_ERR( EINVAL );
+		}
+
 		BEGIN_RING( 9 );
 		OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_0, 5 ) );
 		OUT_RING( tex[0].pp_txfilter );
@@ -163,6 +327,12 @@ static void radeon_emit_state( drm_radeo
 	}
 
 	if ( dirty & RADEON_UPLOAD_TEX1 ) {
+		if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+						    &tex[1].pp_txoffset ) ) {
+			DRM_ERROR( "Invalid texture offset for unit 1\n" );
+			return DRM_ERR( EINVAL );
+		}
+
 		BEGIN_RING( 9 );
 		OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_1, 5 ) );
 		OUT_RING( tex[1].pp_txfilter );
@@ -177,6 +347,12 @@ static void radeon_emit_state( drm_radeo
 	}
 
 	if ( dirty & RADEON_UPLOAD_TEX2 ) {
+		if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+						    &tex[2].pp_txoffset ) ) {
+			DRM_ERROR( "Invalid texture offset for unit 2\n" );
+			return DRM_ERR( EINVAL );
+		}
+
 		BEGIN_RING( 9 );
 		OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_2, 5 ) );
 		OUT_RING( tex[2].pp_txfilter );
@@ -189,12 +365,15 @@ static void radeon_emit_state( drm_radeo
 		OUT_RING( tex[2].pp_border_color );
 		ADVANCE_RING();
 	}
+
+	return 0;
 }
 
 /* Emit 1.2 state
  */
-static void radeon_emit_state2( drm_radeon_private_t *dev_priv,
-				drm_radeon_state_t *state )
+static int radeon_emit_state2( drm_radeon_private_t *dev_priv,
+			       drm_file_t *filp_priv,
+			       drm_radeon_state_t *state )
 {
 	RING_LOCALS;
 
@@ -206,7 +385,7 @@ static void radeon_emit_state2( drm_rade
 		ADVANCE_RING();
 	}
 
-	radeon_emit_state( dev_priv, &state->context, 
+	return radeon_emit_state( dev_priv, filp_priv, &state->context,
 			   state->tex, state->dirty );
 }
 
@@ -1065,6 +1244,7 @@ static int radeon_cp_dispatch_texture( D
 				       drm_radeon_tex_image_t *image )
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_file_t *filp_priv;
 	drm_buf_t *buf;
 	u32 format;
 	u32 *buffer;
@@ -1074,6 +1254,13 @@ static int radeon_cp_dispatch_texture( D
 	int i;
 	RING_LOCALS;
 
+	DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
+	if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &tex->offset ) ) {
+		DRM_ERROR( "Invalid destination offset\n" );
+		return DRM_ERR( EINVAL );
+	}
+
 	dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD;
 
 	/* Flush the pixel cache.  This ensures no pixel data gets mixed
@@ -1377,6 +1564,7 @@ int radeon_cp_vertex( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_file_t *filp_priv;
 	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	drm_device_dma_t *dma = dev->dma;
 	drm_buf_t *buf;
@@ -1390,6 +1578,8 @@ int radeon_cp_vertex( DRM_IOCTL_ARGS )
 		return DRM_ERR(EINVAL);
 	}
 
+	DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
 	DRM_COPY_FROM_USER_IOCTL( vertex, (drm_radeon_vertex_t *)data,
 			     sizeof(vertex) );
 
@@ -1429,11 +1619,14 @@ int radeon_cp_vertex( DRM_IOCTL_ARGS )
 		buf->used = vertex.count; /* not used? */
 
 		if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) {
-			radeon_emit_state( dev_priv,
-					   &sarea_priv->context_state,
-					   sarea_priv->tex_state,
-					   sarea_priv->dirty );
-			
+			if ( radeon_emit_state( dev_priv, filp_priv,
+						&sarea_priv->context_state,
+						sarea_priv->tex_state,
+						sarea_priv->dirty ) ) {
+				DRM_ERROR( "radeon_emit_state failed\n" );
+				return DRM_ERR( EINVAL );
+			}
+
 			sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
 					       RADEON_UPLOAD_TEX1IMAGES |
 					       RADEON_UPLOAD_TEX2IMAGES |
@@ -1461,6 +1654,7 @@ int radeon_cp_indices( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_file_t *filp_priv;
 	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	drm_device_dma_t *dma = dev->dma;
 	drm_buf_t *buf;
@@ -1475,6 +1669,8 @@ int radeon_cp_indices( DRM_IOCTL_ARGS )
 		return DRM_ERR(EINVAL);
 	}
 
+	DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
 	DRM_COPY_FROM_USER_IOCTL( elts, (drm_radeon_indices_t *)data,
 			     sizeof(elts) );
 
@@ -1523,10 +1719,13 @@ int radeon_cp_indices( DRM_IOCTL_ARGS )
 	buf->used = elts.end;
 
 	if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) {
-		radeon_emit_state( dev_priv,
-				   &sarea_priv->context_state,
-				   sarea_priv->tex_state,
-				   sarea_priv->dirty );
+		if ( radeon_emit_state( dev_priv, filp_priv,
+					&sarea_priv->context_state,
+					sarea_priv->tex_state,
+					sarea_priv->dirty ) ) {
+			DRM_ERROR( "radeon_emit_state failed\n" );
+			return DRM_ERR( EINVAL );
+		}
 
 		sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
 				       RADEON_UPLOAD_TEX1IMAGES |
@@ -1686,6 +1885,7 @@ int radeon_cp_vertex2( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_file_t *filp_priv;
 	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	drm_device_dma_t *dma = dev->dma;
 	drm_buf_t *buf;
@@ -1700,6 +1900,8 @@ int radeon_cp_vertex2( DRM_IOCTL_ARGS )
 		return DRM_ERR(EINVAL);
 	}
 
+	DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
 	DRM_COPY_FROM_USER_IOCTL( vertex, (drm_radeon_vertex2_t *)data,
 			     sizeof(vertex) );
 
@@ -1747,7 +1949,10 @@ int radeon_cp_vertex2( DRM_IOCTL_ARGS )
 					     sizeof(state) ) )
 				return DRM_ERR(EFAULT);
 
-			radeon_emit_state2( dev_priv, &state );
+			if ( radeon_emit_state2( dev_priv, filp_priv, &state ) ) {
+				DRM_ERROR( "radeon_emit_state2 failed\n" );
+				return DRM_ERR( EINVAL );
+			}
 
 			laststate = prim.stateidx;
 		}
@@ -1784,6 +1989,7 @@ int radeon_cp_vertex2( DRM_IOCTL_ARGS )
 
 static int radeon_emit_packets( 
 	drm_radeon_private_t *dev_priv,
+	drm_file_t *filp_priv,
 	drm_radeon_cmd_header_t header,
 	drm_radeon_cmd_buffer_t *cmdbuf )
 {
@@ -1798,8 +2004,15 @@ static int radeon_emit_packets( 
 	sz = packet[id].len;
 	reg = packet[id].start;
 
-	if (sz * sizeof(int) > cmdbuf->bufsz) 
+	if (sz * sizeof(int) > cmdbuf->bufsz) {
+		DRM_ERROR( "Packet size provided larger than data provided\n" );
 		return DRM_ERR(EINVAL);
+	}
+
+	if ( radeon_check_and_fixup_packets( dev_priv, filp_priv, id, data ) ) {
+		DRM_ERROR( "Packet verification failed\n" );
+		return DRM_ERR( EINVAL );
+	}
 
 	BEGIN_RING(sz+1);
 	OUT_RING( CP_PACKET0( reg, (sz-1) ) );
@@ -1882,24 +2095,21 @@ static __inline__ int radeon_emit_vector
 
 
 static int radeon_emit_packet3( drm_device_t *dev,
+				drm_file_t *filp_priv,
 				drm_radeon_cmd_buffer_t *cmdbuf )
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
-	int cmdsz, tmp;
-	int *cmd = (int *)cmdbuf->buf;
+	unsigned int cmdsz;
+	int *cmd = (int *)cmdbuf->buf, ret;
 	RING_LOCALS;
 
-
 	DRM_DEBUG("\n");
 
-	if (DRM_GET_USER_UNCHECKED( tmp, &cmd[0]))
-		return DRM_ERR(EFAULT);
-
-	cmdsz = 2 + ((tmp & RADEON_CP_PACKET_COUNT_MASK) >> 16);
-
-	if ((tmp & 0xc0000000) != RADEON_CP_PACKET3 ||
-	    cmdsz * 4 > cmdbuf->bufsz)
-		return DRM_ERR(EINVAL);
+	if ( ( ret = radeon_check_and_fixup_packet3( dev_priv, filp_priv,
+						     cmdbuf, &cmdsz ) ) ) {
+		DRM_ERROR( "Packet verification failed\n" );
+		return ret;
+	}
 
 	BEGIN_RING( cmdsz );
 	OUT_RING_USER_TABLE( cmd, cmdsz );
@@ -1912,27 +2122,25 @@ static int radeon_emit_packet3( drm_devi
 
 
 static int radeon_emit_packet3_cliprect( drm_device_t *dev,
+					 drm_file_t *filp_priv,
 					 drm_radeon_cmd_buffer_t *cmdbuf,
 					 int orig_nbox )
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_clip_rect_t box;
-	int cmdsz, tmp;
-	int *cmd = (int *)cmdbuf->buf;
+	unsigned int cmdsz;
+	int *cmd = (int *)cmdbuf->buf, ret;
 	drm_clip_rect_t *boxes = cmdbuf->boxes;
 	int i = 0;
 	RING_LOCALS;
 
 	DRM_DEBUG("\n");
 
-	if (DRM_GET_USER_UNCHECKED( tmp, &cmd[0]))
-		return DRM_ERR(EFAULT);
-
-	cmdsz = 2 + ((tmp & RADEON_CP_PACKET_COUNT_MASK) >> 16);
-
-	if ((tmp & 0xc0000000) != RADEON_CP_PACKET3 ||
-	    cmdsz * 4 > cmdbuf->bufsz)
-		return DRM_ERR(EINVAL);
+	if ( ( ret = radeon_check_and_fixup_packet3( dev_priv, filp_priv,
+						     cmdbuf, &cmdsz ) ) ) {
+		DRM_ERROR( "Packet verification failed\n" );
+		return ret;
+	}
 
 	if (!orig_nbox)
 		goto out;
@@ -2009,6 +2217,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_file_t *filp_priv;
 	drm_device_dma_t *dma = dev->dma;
 	drm_buf_t *buf = 0;
 	int idx;
@@ -2023,6 +2232,8 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
 		return DRM_ERR(EINVAL);
 	}
 
+	DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
 	DRM_COPY_FROM_USER_IOCTL( cmdbuf, (drm_radeon_cmd_buffer_t *)data,
 			     sizeof(cmdbuf) );
 
@@ -2053,7 +2264,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
 		switch (header.header.cmd_type) {
 		case RADEON_CMD_PACKET: 
 			DRM_DEBUG("RADEON_CMD_PACKET\n");
-			if (radeon_emit_packets( dev_priv, header, &cmdbuf )) {
+			if (radeon_emit_packets( dev_priv, filp_priv, header, &cmdbuf )) {
 				DRM_ERROR("radeon_emit_packets failed\n");
 				return DRM_ERR(EINVAL);
 			}
@@ -2096,7 +2307,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
 
 		case RADEON_CMD_PACKET3:
 			DRM_DEBUG("RADEON_CMD_PACKET3\n");
-			if (radeon_emit_packet3( dev, &cmdbuf )) {
+			if (radeon_emit_packet3( dev, filp_priv, &cmdbuf )) {
 				DRM_ERROR("radeon_emit_packet3 failed\n");
 				return DRM_ERR(EINVAL);
 			}
@@ -2104,7 +2315,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
 
 		case RADEON_CMD_PACKET3_CLIP:
 			DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n");
-			if (radeon_emit_packet3_cliprect( dev, &cmdbuf, orig_nbox )) {
+			if (radeon_emit_packet3_cliprect( dev, filp_priv, &cmdbuf, orig_nbox )) {
 				DRM_ERROR("radeon_emit_packet3_clip failed\n");
 				return DRM_ERR(EINVAL);
 			}
@@ -2214,3 +2425,31 @@ int radeon_cp_getparam( DRM_IOCTL_ARGS )
 	
 	return 0;
 }
+
+int radeon_cp_setparam( DRM_IOCTL_ARGS ) {
+	DRM_DEVICE;
+	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_file_t *filp_priv;
+	drm_radeon_setparam_t sp;
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+		return DRM_ERR( EINVAL );
+	}
+
+	DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
+	DRM_COPY_FROM_USER_IOCTL( sp, ( drm_radeon_setparam_t* )data,
+				  sizeof( sp ) );
+
+	switch( sp.param ) {
+	case RADEON_SETPARAM_FB_LOCATION:
+		filp_priv->radeon_fb_delta = dev_priv->fb_location - sp.value;
+		break;
+	default:
+		DRM_DEBUG( "Invalid parameter %d\n", sp.param );
+		return DRM_ERR( EINVAL );
+	}
+
+	return 0;
+}
--- diff/drivers/char/drm/sis.h	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/sis.h	2004-03-09 11:51:49.000000000 +0000
@@ -62,6 +62,13 @@
 	[DRM_IOCTL_NR(DRM_IOCTL_SIS_AGP_FREE)]	= { sis_ioctl_agp_free,	1, 0 }, \
 	[DRM_IOCTL_NR(DRM_IOCTL_SIS_FB_INIT)]	= { sis_fb_init,	1, 1 }
 
+#define DRIVER_PCI_IDS							\
+	{0x1039, 0x0300, 0, "SiS 300/305"},				\
+	{0x1039, 0x5300, 0, "SiS 540"},					\
+	{0x1039, 0x6300, 0, "SiS 630"},					\
+	{0x1039, 0x7300, 0, "SiS 730"},					\
+	{0, 0, 0, NULL}
+
 #define __HAVE_COUNTERS		5
 
 /* Buffer customization:
--- diff/drivers/char/drm/sis_mm.c	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/sis_mm.c	2004-03-09 11:51:49.000000000 +0000
@@ -34,7 +34,11 @@
 #include "sis_drv.h"
 #include "sis_ds.h"
 #if defined(__linux__) && defined(CONFIG_FB_SIS)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 #include <video/sisfb.h>
+#else
+#include <linux/sisfb.h>
+#endif
 #endif
 
 #define MAX_CONTEXT 100
@@ -132,7 +136,7 @@ int sis_fb_free( DRM_IOCTL_ARGS )
 		retval = DRM_ERR(EINVAL);
 	sis_free(fb.free);
 
-	DRM_DEBUG("free fb, offset = %lu\n", fb.free);
+	DRM_DEBUG("free fb, offset = 0x%lx\n", fb.free);
 
 	return retval;
 }
--- diff/drivers/char/drm/tdfx.h	2002-10-16 04:28:22.000000000 +0100
+++ source/drivers/char/drm/tdfx.h	2004-03-09 11:51:49.000000000 +0000
@@ -39,4 +39,22 @@
 #define __HAVE_MTRR		1
 #define __HAVE_CTX_BITMAP	1
 
+#define DRIVER_AUTHOR		"VA Linux Systems Inc."
+
+#define DRIVER_NAME		"tdfx"
+#define DRIVER_DESC		"3dfx Banshee/Voodoo3+"
+#define DRIVER_DATE		"20010216"
+
+#define DRIVER_MAJOR		1
+#define DRIVER_MINOR		0
+#define DRIVER_PATCHLEVEL	0
+
+#define DRIVER_PCI_IDS							\
+	{0x121a, 0x0003, 0, "3dfx Voodoo Banshee"},			\
+	{0x121a, 0x0004, 0, "3dfx Voodoo3 2000"},			\
+	{0x121a, 0x0005, 0, "3dfx Voodoo3 3000"},			\
+	{0x121a, 0x0007, 0, "3dfx Voodoo4"},				\
+	{0x121a, 0x0009, 0, "3dfx Voodoo5"},				\
+	{0, 0, 0, NULL}
+
 #endif
--- diff/drivers/char/drm/tdfx_drv.c	2002-10-16 04:28:22.000000000 +0100
+++ source/drivers/char/drm/tdfx_drv.c	2004-03-09 11:51:49.000000000 +0000
@@ -34,47 +34,6 @@
 #include "tdfx.h"
 #include "drmP.h"
 
-#define DRIVER_AUTHOR		"VA Linux Systems Inc."
-
-#define DRIVER_NAME		"tdfx"
-#define DRIVER_DESC		"3dfx Banshee/Voodoo3+"
-#define DRIVER_DATE		"20010216"
-
-#define DRIVER_MAJOR		1
-#define DRIVER_MINOR		0
-#define DRIVER_PATCHLEVEL	0
-
-#ifndef PCI_VENDOR_ID_3DFX
-#define PCI_VENDOR_ID_3DFX 0x121A
-#endif
-#ifndef PCI_DEVICE_ID_3DFX_VOODOO5
-#define PCI_DEVICE_ID_3DFX_VOODOO5 0x0009
-#endif
-#ifndef PCI_DEVICE_ID_3DFX_VOODOO4
-#define PCI_DEVICE_ID_3DFX_VOODOO4 0x0007
-#endif
-#ifndef PCI_DEVICE_ID_3DFX_VOODOO3_3000 /* Voodoo3 3000 */
-#define PCI_DEVICE_ID_3DFX_VOODOO3_3000 0x0005
-#endif
-#ifndef PCI_DEVICE_ID_3DFX_VOODOO3_2000 /* Voodoo3 3000 */
-#define PCI_DEVICE_ID_3DFX_VOODOO3_2000 0x0004
-#endif
-#ifndef PCI_DEVICE_ID_3DFX_BANSHEE
-#define PCI_DEVICE_ID_3DFX_BANSHEE 0x0003
-#endif
-
-static drm_pci_list_t DRM(idlist)[] = {
-	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE },
-	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3_2000 },
-	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3_3000 },
-	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO4 },
-	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO5 },
-	{ 0, 0 }
-};
-
-#define DRIVER_CARD_LIST DRM(idlist)
-
-
 #include "drm_auth.h"
 #include "drm_bufs.h"
 #include "drm_context.h"
--- diff/drivers/char/genrtc.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/char/genrtc.c	2004-03-09 11:51:49.000000000 +0000
@@ -466,6 +466,17 @@ static int gen_rtc_read_proc(char *page,
 	return len;
 }
 
+static int __init gen_rtc_proc_init(void)
+{
+	struct proc_dir_entry *r;
+
+	r = create_proc_read_entry("driver/rtc", 0, 0, gen_rtc_read_proc, NULL);
+	if (!r)
+		return -ENOMEM;
+	return 0;
+}
+#else
+static inline int gen_rtc_proc_init(void) { return 0; }
 #endif /* CONFIG_PROC_FS */
 
 
@@ -498,15 +509,14 @@ static int __init rtc_generic_init(void)
 	printk(KERN_INFO "Generic RTC Driver v%s\n", RTC_VERSION);
 
 	retval = misc_register(&rtc_gen_dev);
-	if(retval < 0)
+	if (retval < 0)
 		return retval;
 
-#ifdef CONFIG_PROC_FS
-	if((create_proc_read_entry ("driver/rtc", 0, 0, gen_rtc_read_proc, NULL)) == NULL){
+	retval = gen_rtc_proc_init();
+	if (retval) {
 		misc_deregister(&rtc_gen_dev);
-		return -ENOMEM;
+		return retval;
 	}
-#endif
 
 	return 0;
 }
--- diff/drivers/char/hw_random.c	2003-09-30 15:46:13.000000000 +0100
+++ source/drivers/char/hw_random.c	2004-03-09 11:51:49.000000000 +0000
@@ -454,11 +454,7 @@ static int __init via_init(struct pci_de
 
 static void via_cleanup(void)
 {
-	u32 lo, hi;
-
-	rdmsr(MSR_VIA_RNG, lo, hi);
-	lo &= ~VIA_RNG_ENABLE;
-	wrmsr(MSR_VIA_RNG, lo, hi);
+	/* do nothing */
 }
 
 
--- diff/drivers/char/ipmi/Kconfig	2003-10-27 09:20:37.000000000 +0000
+++ source/drivers/char/ipmi/Kconfig	2004-03-09 11:51:49.000000000 +0000
@@ -43,11 +43,24 @@ config IPMI_DEVICE_INTERFACE
          This provides an IOCTL interface to the IPMI message handler so
 	 userland processes may use IPMI.  It supports poll() and select().
 
-config IPMI_KCS
-       tristate 'IPMI KCS handler'
+config IPMI_SI
+       tristate 'IPMI System Interface handler'
        depends on IPMI_HANDLER
        help
-         Provides a driver for a KCS-style interface to a BMC.
+         Provides a driver for System Interfaces (KCS, SMIC, BT).
+	 Currently, only KCS and SMIC are supported.  If
+	 you are using IPMI, you should probably say "y" here.
+
+config IPMI_SMB
+       tristate 'IPMI SMBus handler'
+       depends on IPMI_HANDLER && I2C
+       help
+         Provides a driver for a SMBus interface to a BMC, meaning that you
+	 have a driver that must be accessed over an I2C bus instead of a
+	 standard interface.  This module requires I2C support.  Note that
+	 you might need some I2C changes if CONFIG_IPMI_PANIC_EVENT is
+	 enabled along with this, so the I2C driver knows to run to
+	 completion during sending a panic event.
 
 config IPMI_WATCHDOG
        tristate 'IPMI Watchdog Timer'
--- diff/drivers/char/ipmi/Makefile	2003-02-13 11:46:51.000000000 +0000
+++ source/drivers/char/ipmi/Makefile	2004-03-09 11:51:49.000000000 +0000
@@ -2,12 +2,14 @@
 # Makefile for the ipmi drivers.
 #
 
-ipmi_kcs_drv-objs := ipmi_kcs_sm.o ipmi_kcs_intf.o
+ipmi_si-objs := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o
 
 obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o
 obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
-obj-$(CONFIG_IPMI_KCS) += ipmi_kcs_drv.o
+obj-$(CONFIG_IPMI_SI) += ipmi_si.o
+obj-$(CONFIG_IPMI_SMB) += ipmi_smb.o
 obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o
 
-ipmi_kcs_drv.o:	$(ipmi_kcs_drv-objs)
-	$(LD) -r -o $@ $(ipmi_kcs_drv-objs) 
+ipmi_si.o:	$(ipmi_si-objs)
+	$(LD) -r -o $@ $(ipmi_si-objs)
+
--- diff/drivers/char/ipmi/ipmi_devintf.c	2003-09-17 12:28:05.000000000 +0100
+++ source/drivers/char/ipmi/ipmi_devintf.c	2004-03-09 11:51:49.000000000 +0000
@@ -33,6 +33,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/errno.h>
 #include <asm/system.h>
 #include <linux/sched.h>
@@ -44,6 +45,8 @@
 #include <asm/semaphore.h>
 #include <linux/init.h>
 
+#define IPMI_DEVINTF_VERSION "v31"
+
 struct ipmi_file_private
 {
 	ipmi_user_t          user;
@@ -53,6 +56,8 @@ struct ipmi_file_private
 	struct fasync_struct *fasync_queue;
 	wait_queue_head_t    wait;
 	struct semaphore     recv_sem;
+	int                  default_retries;
+	unsigned int         default_retry_time_ms;
 };
 
 static void file_receive_handler(struct ipmi_recv_msg *msg,
@@ -138,6 +143,10 @@ static int ipmi_open(struct inode *inode
 	priv->fasync_queue = NULL;
 	sema_init(&(priv->recv_sem), 1);
 
+	/* Use the low-level defaults. */
+	priv->default_retries = -1;
+	priv->default_retry_time_ms = 0;
+
 	return 0;
 }
 
@@ -158,6 +167,63 @@ static int ipmi_release(struct inode *in
 	return 0;
 }
 
+static int handle_send_req(ipmi_user_t     user,
+			   struct ipmi_req *req,
+			   int             retries,
+			   unsigned int    retry_time_ms)
+{
+	int              rv;
+	struct ipmi_addr addr;
+	unsigned char    *msgdata;
+
+	if (req->addr_len > sizeof(struct ipmi_addr))
+		return -EINVAL;
+
+	if (copy_from_user(&addr, req->addr, req->addr_len))
+		return -EFAULT;
+
+	msgdata = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
+	if (!msgdata)
+		return -ENOMEM;
+
+	/* From here out we cannot return, we must jump to "out" for
+	   error exits to free msgdata. */
+
+	rv = ipmi_validate_addr(&addr, req->addr_len);
+	if (rv)
+		goto out;
+
+	if (req->msg.data != NULL) {
+		if (req->msg.data_len > IPMI_MAX_MSG_LENGTH) {
+			rv = -EMSGSIZE;
+			goto out;
+		}
+
+		if (copy_from_user(&msgdata,
+				   req->msg.data,
+				   req->msg.data_len))
+		{
+			rv = -EFAULT;
+			goto out;
+		}
+	} else {
+		req->msg.data_len = 0;
+	}
+	req->msg.data = msgdata;
+
+	rv = ipmi_request_settime(user,
+				  &addr,
+				  req->msgid,
+				  &(req->msg),
+				  NULL,
+				  0,
+				  retries,
+				  retry_time_ms);
+ out:
+	kfree(msgdata);
+	return rv;
+}
+
 static int ipmi_ioctl(struct inode  *inode,
 		      struct file   *file,
 		      unsigned int  cmd,
@@ -170,54 +236,33 @@ static int ipmi_ioctl(struct inode  *ino
 	{
 	case IPMICTL_SEND_COMMAND:
 	{
-		struct ipmi_req    req;
-		struct ipmi_addr   addr;
-		unsigned char msgdata[IPMI_MAX_MSG_LENGTH];
+		struct ipmi_req req;
 
 		if (copy_from_user(&req, (void *) data, sizeof(req))) {
 			rv = -EFAULT;
 			break;
 		}
 
-		if (req.addr_len > sizeof(struct ipmi_addr))
-		{
-			rv = -EINVAL;
-			break;
-		}
+		rv = handle_send_req(priv->user,
+				     &req,
+				     priv->default_retries,
+				     priv->default_retry_time_ms);
+		break;
+	}
 
-		if (copy_from_user(&addr, req.addr, req.addr_len)) {
-			rv = -EFAULT;
-			break;
-		}
+	case IPMICTL_SEND_COMMAND_SETTIME:
+	{
+		struct ipmi_req_settime req;
 
-		rv = ipmi_validate_addr(&addr, req.addr_len);
-		if (rv)
+		if (copy_from_user(&req, (void *) data, sizeof(req))) {
+			rv = -EFAULT;
 			break;
-
-		if (req.msg.data != NULL) {
-			if (req.msg.data_len > IPMI_MAX_MSG_LENGTH) {
-				rv = -EMSGSIZE;
-				break;
-			}
-
-			if (copy_from_user(&msgdata,
-					   req.msg.data,
-					   req.msg.data_len))
-			{
-				rv = -EFAULT;
-				break;
-			}
-		} else {
-			req.msg.data_len = 0;
 		}
 
-		req.msg.data = msgdata;
-
-		rv = ipmi_request(priv->user,
-				  &addr,
-				  req.msgid,
-				  &(req.msg),
-				  0);
+		rv = handle_send_req(priv->user,
+				     &req.req,
+				     req.retries,
+				     req.retry_time_ms);
 		break;
 	}
 
@@ -416,7 +461,36 @@ static int ipmi_ioctl(struct inode  *ino
 		rv = 0;
 		break;
 	}
+	case IPMICTL_SET_TIMING_PARMS_CMD:
+	{
+		struct ipmi_timing_parms parms;
+
+		if (copy_from_user(&parms, (void *) data, sizeof(parms))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		priv->default_retries = parms.retries;
+		priv->default_retry_time_ms = parms.retry_time_ms;
+		rv = 0;
+		break;
+	}
+
+	case IPMICTL_GET_TIMING_PARMS_CMD:
+	{
+		struct ipmi_timing_parms parms;
+
+		parms.retries = priv->default_retries;
+		parms.retry_time_ms = priv->default_retry_time_ms;
 
+		if (copy_to_user((void *) data, &parms, sizeof(parms))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		rv = 0;
+		break;
+	}
 	}
   
 	return rv;
@@ -435,29 +509,30 @@ static struct file_operations ipmi_fops 
 #define DEVICE_NAME     "ipmidev"
 
 static int ipmi_major = 0;
-MODULE_PARM(ipmi_major, "i");
-
-#define MAX_DEVICES 10
+module_param(ipmi_major, int, 0);
+MODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device.  By"
+		 " default, or if you set it to zero, it will choose the next"
+		 " available device.  Setting it to -1 will disable the"
+		 " interface.  Other values will set the major device number"
+		 " to that value.");
 
 static void ipmi_new_smi(int if_num)
 {
-	if (if_num <= MAX_DEVICES) {
-		devfs_mk_cdev(MKDEV(ipmi_major, if_num),
-				S_IFCHR | S_IRUSR | S_IWUSR,
-				"ipmidev/%d", if_num);
-	}
+	devfs_mk_cdev(MKDEV(ipmi_major, if_num),
+		      S_IFCHR | S_IRUSR | S_IWUSR,
+		      "ipmidev/%d", if_num);
 }
 
 static void ipmi_smi_gone(int if_num)
 {
-	if (if_num <= MAX_DEVICES)
-		devfs_remove("ipmidev/%d", if_num);
+	devfs_remove("ipmidev/%d", if_num);
 }
 
 static struct ipmi_smi_watcher smi_watcher =
 {
-	.new_smi	= ipmi_new_smi,
-	.smi_gone	= ipmi_smi_gone,
+	.owner    = THIS_MODULE,
+	.new_smi  = ipmi_new_smi,
+	.smi_gone = ipmi_smi_gone,
 };
 
 static __init int init_ipmi_devintf(void)
@@ -467,6 +542,9 @@ static __init int init_ipmi_devintf(void
 	if (ipmi_major < 0)
 		return -EINVAL;
 
+	printk(KERN_INFO "ipmi device interface version "
+	       IPMI_DEVINTF_VERSION "\n");
+
 	rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
 	if (rv < 0) {
 		printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
@@ -482,13 +560,10 @@ static __init int init_ipmi_devintf(void
 	rv = ipmi_smi_watcher_register(&smi_watcher);
 	if (rv) {
 		unregister_chrdev(ipmi_major, DEVICE_NAME);
-		printk(KERN_WARNING "ipmi: can't register smi watcher");
+		printk(KERN_WARNING "ipmi: can't register smi watcher\n");
 		return rv;
 	}
 
-	printk(KERN_INFO "ipmi: device interface at char major %d\n",
-	       ipmi_major);
-
 	return 0;
 }
 module_init(init_ipmi_devintf);
@@ -500,21 +575,5 @@ static __exit void cleanup_ipmi(void)
 	unregister_chrdev(ipmi_major, DEVICE_NAME);
 }
 module_exit(cleanup_ipmi);
-#ifndef MODULE
-static __init int ipmi_setup (char *str)
-{
-	int x;
-
-	if (get_option (&str, &x)) {
-		/* ipmi=x sets the major number to x. */
-		ipmi_major = x;
-	} else if (!strcmp(str, "off")) {
-		ipmi_major = -1;
-	}
-
-	return 1;
-}
-#endif
 
-__setup("ipmi=", ipmi_setup);
 MODULE_LICENSE("GPL");
--- diff/drivers/char/ipmi/ipmi_kcs_sm.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/char/ipmi/ipmi_kcs_sm.c	2004-03-09 11:51:49.000000000 +0000
@@ -39,11 +39,13 @@
 
 #include <linux/types.h>
 
-#include <asm/io.h>
+#include <linux/kernel.h> /* For printk. */
 #include <asm/string.h>		/* Gets rid of memcpy warning */
-#include <asm/system.h>
+#include <linux/ipmi_msgdefs.h>		/* for completion codes */
 
-#include "ipmi_kcs_sm.h"
+#include "ipmi_si_sm.h"
+
+#define IPMI_KCS_VERSION "v31"
 
 /* Set this if you want a printout of why the state machine was hosed
    when it gets hosed. */
@@ -95,32 +97,28 @@ enum kcs_states {
 #define OBF_RETRY_TIMEOUT 1000000
 #define MAX_ERROR_RETRIES 10
 
-#define IPMI_ERR_MSG_TRUNCATED	0xc6
-#define IPMI_ERR_UNSPECIFIED	0xff
-
-struct kcs_data
+struct si_sm_data
 {
-	enum kcs_states state;
-	unsigned int    port;
-	unsigned char	*addr;
-	unsigned char   write_data[MAX_KCS_WRITE_SIZE];
-	int             write_pos;
-	int             write_count;
-	int             orig_write_count;
-	unsigned char   read_data[MAX_KCS_READ_SIZE];
-	int             read_pos;
-	int	        truncated;
+	enum kcs_states  state;
+	struct si_sm_io *io;
+	unsigned char    write_data[MAX_KCS_WRITE_SIZE];
+	int              write_pos;
+	int              write_count;
+	int              orig_write_count;
+	unsigned char    read_data[MAX_KCS_READ_SIZE];
+	int              read_pos;
+	int	         truncated;
 
 	unsigned int  error_retries;
 	long          ibf_timeout;
 	long          obf_timeout;
 };
 
-void init_kcs_data(struct kcs_data *kcs, unsigned int port, unsigned char *addr)
+static unsigned int init_kcs_data(struct si_sm_data *kcs,
+				  struct si_sm_io *io)
 {
 	kcs->state = KCS_IDLE;
-	kcs->port = port;
-	kcs->addr = addr;
+	kcs->io = io;
 	kcs->write_pos = 0;
 	kcs->write_count = 0;
 	kcs->orig_write_count = 0;
@@ -129,40 +127,29 @@ void init_kcs_data(struct kcs_data *kcs,
 	kcs->truncated = 0;
 	kcs->ibf_timeout = IBF_RETRY_TIMEOUT;
 	kcs->obf_timeout = OBF_RETRY_TIMEOUT;
-}
 
-/* Remember, init_one_kcs() insured port and addr can't both be set */
+	/* Reserve 2 I/O bytes. */
+	return 2;
+}
 
-static inline unsigned char read_status(struct kcs_data *kcs)
+static inline unsigned char read_status(struct si_sm_data *kcs)
 {
-        if (kcs->port)
-		return inb(kcs->port + 1);
-        else
-		return readb(kcs->addr + 1);
+	return kcs->io->inputb(kcs->io, 1);
 }
 
-static inline unsigned char read_data(struct kcs_data *kcs)
+static inline unsigned char read_data(struct si_sm_data *kcs)
 {
-        if (kcs->port)
-		return inb(kcs->port + 0);
-        else
-		return readb(kcs->addr + 0);
+	return kcs->io->inputb(kcs->io, 0);
 }
 
-static inline void write_cmd(struct kcs_data *kcs, unsigned char data)
+static inline void write_cmd(struct si_sm_data *kcs, unsigned char data)
 {
-        if (kcs->port)
-		outb(data, kcs->port + 1);
-        else
-		writeb(data, kcs->addr + 1);
+	kcs->io->outputb(kcs->io, 1, data);
 }
 
-static inline void write_data(struct kcs_data *kcs, unsigned char data)
+static inline void write_data(struct si_sm_data *kcs, unsigned char data)
 {
-        if (kcs->port)
-		outb(data, kcs->port + 0);
-        else
-		writeb(data, kcs->addr + 0);
+	kcs->io->outputb(kcs->io, 0, data);
 }
 
 /* Control codes. */
@@ -182,14 +169,14 @@ static inline void write_data(struct kcs
 #define GET_STATUS_OBF(status) ((status) & 0x01)
 
 
-static inline void write_next_byte(struct kcs_data *kcs)
+static inline void write_next_byte(struct si_sm_data *kcs)
 {
 	write_data(kcs, kcs->write_data[kcs->write_pos]);
 	(kcs->write_pos)++;
 	(kcs->write_count)--;
 }
 
-static inline void start_error_recovery(struct kcs_data *kcs, char *reason)
+static inline void start_error_recovery(struct si_sm_data *kcs, char *reason)
 {
 	(kcs->error_retries)++;
 	if (kcs->error_retries > MAX_ERROR_RETRIES) {
@@ -202,7 +189,7 @@ static inline void start_error_recovery(
 	}
 }
 
-static inline void read_next_byte(struct kcs_data *kcs)
+static inline void read_next_byte(struct si_sm_data *kcs)
 {
 	if (kcs->read_pos >= MAX_KCS_READ_SIZE) {
 		/* Throw the data away and mark it truncated. */
@@ -215,9 +202,8 @@ static inline void read_next_byte(struct
 	write_data(kcs, KCS_READ_BYTE);
 }
 
-static inline int check_ibf(struct kcs_data *kcs,
-			    unsigned char   status,
-			    long            time)
+static inline int check_ibf(struct si_sm_data *kcs, unsigned char status,
+			    long time)
 {
 	if (GET_STATUS_IBF(status)) {
 		kcs->ibf_timeout -= time;
@@ -232,9 +218,8 @@ static inline int check_ibf(struct kcs_d
 	return 1;
 }
 
-static inline int check_obf(struct kcs_data *kcs,
-			    unsigned char   status,
-			    long            time)
+static inline int check_obf(struct si_sm_data *kcs, unsigned char status,
+			    long time)
 {
 	if (! GET_STATUS_OBF(status)) {
 		kcs->obf_timeout -= time;
@@ -248,13 +233,13 @@ static inline int check_obf(struct kcs_d
 	return 1;
 }
 
-static void clear_obf(struct kcs_data *kcs, unsigned char status)
+static void clear_obf(struct si_sm_data *kcs, unsigned char status)
 {
 	if (GET_STATUS_OBF(status))
 		read_data(kcs);
 }
 
-static void restart_kcs_transaction(struct kcs_data *kcs)
+static void restart_kcs_transaction(struct si_sm_data *kcs)
 {
 	kcs->write_count = kcs->orig_write_count;
 	kcs->write_pos = 0;
@@ -265,7 +250,8 @@ static void restart_kcs_transaction(stru
 	write_cmd(kcs, KCS_WRITE_START);
 }
 
-int start_kcs_transaction(struct kcs_data *kcs, char *data, unsigned int size)
+static int start_kcs_transaction(struct si_sm_data *kcs, unsigned char *data,
+				 unsigned int size)
 {
 	if ((size < 2) || (size > MAX_KCS_WRITE_SIZE)) {
 		return -1;
@@ -287,7 +273,8 @@ int start_kcs_transaction(struct kcs_dat
 	return 0;
 }
 
-int kcs_get_result(struct kcs_data *kcs, unsigned char *data, int length)
+static int get_kcs_result(struct si_sm_data *kcs, unsigned char *data,
+			  unsigned int length)
 {
 	if (length < kcs->read_pos) {
 		kcs->read_pos = length;
@@ -316,7 +303,7 @@ int kcs_get_result(struct kcs_data *kcs,
 /* This implements the state machine defined in the IPMI manual, see
    that for details on how this works.  Divide that flowchart into
    sections delimited by "Wait for IBF" and this will become clear. */
-enum kcs_result kcs_event(struct kcs_data *kcs, long time)
+static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time)
 {
 	unsigned char status;
 	unsigned char state;
@@ -328,7 +315,7 @@ enum kcs_result kcs_event(struct kcs_dat
 #endif
 	/* All states wait for ibf, so just do it here. */
 	if (!check_ibf(kcs, status, time))
-		return KCS_CALL_WITH_DELAY;
+		return SI_SM_CALL_WITH_DELAY;
 
 	/* Just about everything looks at the KCS state, so grab that, too. */
 	state = GET_STATUS_STATE(status);
@@ -339,9 +326,9 @@ enum kcs_result kcs_event(struct kcs_dat
 		clear_obf(kcs, status);
 
 		if (GET_STATUS_ATN(status))
-			return KCS_ATTN;
+			return SI_SM_ATTN;
 		else
-			return KCS_SM_IDLE;
+			return SI_SM_IDLE;
 
 	case KCS_START_OP:
 		if (state != KCS_IDLE) {
@@ -408,7 +395,7 @@ enum kcs_result kcs_event(struct kcs_dat
 
 		if (state == KCS_READ_STATE) {
 			if (! check_obf(kcs, status, time))
-				return KCS_CALL_WITH_DELAY;
+				return SI_SM_CALL_WITH_DELAY;
 			read_next_byte(kcs);
 		} else {
 			/* We don't implement this exactly like the state
@@ -421,7 +408,7 @@ enum kcs_result kcs_event(struct kcs_dat
 			clear_obf(kcs, status);
 			kcs->orig_write_count = 0;
 			kcs->state = KCS_IDLE;
-			return KCS_TRANSACTION_COMPLETE;
+			return SI_SM_TRANSACTION_COMPLETE;
 		}
 		break;
 
@@ -444,7 +431,7 @@ enum kcs_result kcs_event(struct kcs_dat
 			break;
 		}
 		if (! check_obf(kcs, status, time))
-			return KCS_CALL_WITH_DELAY;
+			return SI_SM_CALL_WITH_DELAY;
 
 		clear_obf(kcs, status);
 		write_data(kcs, KCS_READ_BYTE);
@@ -459,14 +446,14 @@ enum kcs_result kcs_event(struct kcs_dat
 		}
 
 		if (! check_obf(kcs, status, time))
-			return KCS_CALL_WITH_DELAY;
+			return SI_SM_CALL_WITH_DELAY;
 
 		clear_obf(kcs, status);
 		if (kcs->orig_write_count) {
 			restart_kcs_transaction(kcs);
 		} else {
 			kcs->state = KCS_IDLE;
-			return KCS_TRANSACTION_COMPLETE;
+			return SI_SM_TRANSACTION_COMPLETE;
 		}
 		break;
 			
@@ -475,14 +462,42 @@ enum kcs_result kcs_event(struct kcs_dat
 	}
 
 	if (kcs->state == KCS_HOSED) {
-		init_kcs_data(kcs, kcs->port, kcs->addr);
-		return KCS_SM_HOSED;
+		init_kcs_data(kcs, kcs->io);
+		return SI_SM_HOSED;
 	}
 
-	return KCS_CALL_WITHOUT_DELAY;
+	return SI_SM_CALL_WITHOUT_DELAY;
 }
 
-int kcs_size(void)
+static int kcs_size(void)
 {
-	return sizeof(struct kcs_data);
+	return sizeof(struct si_sm_data);
 }
+
+static int kcs_detect(struct si_sm_data *kcs)
+{
+	/* It's impossible for the KCS status register to be all 1's,
+	   (assuming a properly functioning, self-initialized BMC)
+	   but that's what you get from reading a bogus address, so we
+	   test that first. */
+	if (read_status(kcs) == 0xff)
+		return 1;
+
+	return 0;
+}
+
+static void kcs_cleanup(struct si_sm_data *kcs)
+{
+}
+
+struct si_sm_handlers kcs_smi_handlers =
+{
+	.version           = IPMI_KCS_VERSION,
+	.init_data         = init_kcs_data,
+	.start_transaction = start_kcs_transaction,
+	.get_result        = get_kcs_result,
+	.event             = kcs_event,
+	.detect            = kcs_detect,
+	.cleanup           = kcs_cleanup,
+	.size              = kcs_size,
+};
--- diff/drivers/char/ipmi/ipmi_msghandler.c	2003-10-27 09:20:37.000000000 +0000
+++ source/drivers/char/ipmi/ipmi_msghandler.c	2004-03-09 11:51:49.000000000 +0000
@@ -44,16 +44,21 @@
 #include <linux/ipmi_smi.h>
 #include <linux/notifier.h>
 #include <linux/init.h>
+#include <linux/proc_fs.h>
+
+#define IPMI_MSGHANDLER_VERSION "v31"
 
 struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
 static int ipmi_init_msghandler(void);
 
 static int initialized = 0;
 
+static struct proc_dir_entry *proc_ipmi_root = NULL;
+
 #define MAX_EVENTS_IN_QUEUE	25
 
 /* Don't let a message sit in a queue forever, always time it with at lest
-   the max message timer. */
+   the max message timer.  This is in milliseconds. */
 #define MAX_MSG_TIMEOUT		60000
 
 struct ipmi_user
@@ -82,7 +87,8 @@ struct cmd_rcvr
 
 struct seq_table
 {
-	int                  inuse : 1;
+	unsigned int         inuse : 1;
+	unsigned int         broadcast : 1;
 
 	unsigned long        timeout;
 	unsigned long        orig_timeout;
@@ -111,10 +117,19 @@ struct seq_table
 
 #define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
 
+struct ipmi_channel
+{
+	unsigned char medium;
+	unsigned char protocol;
+};
 
 #define IPMI_IPMB_NUM_SEQ	64
+#define IPMI_MAX_CHANNELS       8
 struct ipmi_smi
 {
+	/* What interface number are we? */
+	int intf_num;
+
 	/* The list of upper layers that are using me.  We read-lock
            this when delivering messages to the upper layer to keep
            the user from going away while we are processing the
@@ -123,6 +138,9 @@ struct ipmi_smi
 	rwlock_t                users_lock;
 	struct list_head        users;
 
+	/* Used for wake ups at startup. */
+	wait_queue_head_t waitq;
+
 	/* The IPMI version of the BMC on the other end. */
 	unsigned char       version_major;
 	unsigned char       version_minor;
@@ -182,6 +200,86 @@ struct ipmi_smi
 	   it.  Note that the message will still be freed by the
 	   caller.  This only works on the system interface. */
 	void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_smi_msg *msg);
+
+	/* When we are scanning the channels for an SMI, this will
+	   tell which channel we are scanning. */
+	int curr_channel;
+
+	/* Channel information */
+	struct ipmi_channel channels[IPMI_MAX_CHANNELS];
+
+	/* Proc FS stuff. */
+	struct proc_dir_entry *proc_dir;
+	char                  proc_dir_name[10];
+
+	spinlock_t   counter_lock; /* For making counters atomic. */
+
+	/* Commands we got that were invalid. */
+	unsigned int sent_invalid_commands;
+
+	/* Commands we sent to the MC. */
+	unsigned int sent_local_commands;
+	/* Responses from the MC that were delivered to a user. */
+	unsigned int handled_local_responses;
+	/* Responses from the MC that were not delivered to a user. */
+	unsigned int unhandled_local_responses;
+
+	/* Commands we sent out to the IPMB bus. */
+	unsigned int sent_ipmb_commands;
+	/* Commands sent on the IPMB that had errors on the SEND CMD */
+	unsigned int sent_ipmb_command_errs;
+	/* Each retransmit increments this count. */
+	unsigned int retransmitted_ipmb_commands;
+	/* When a message times out (runs out of retransmits) this is
+           incremented. */
+	unsigned int timed_out_ipmb_commands;
+
+	/* This is like above, but for broadcasts.  Broadcasts are
+           *not* included in the above count (they are expected to
+           time out). */
+	unsigned int timed_out_ipmb_broadcasts;
+
+	/* Responses I have sent to the IPMB bus. */
+	unsigned int sent_ipmb_responses;
+
+	/* The response was delivered to the user. */
+	unsigned int handled_ipmb_responses;
+	/* The response had invalid data in it. */
+	unsigned int invalid_ipmb_responses;
+	/* The response didn't have anyone waiting for it. */
+	unsigned int unhandled_ipmb_responses;
+
+	/* Commands we sent out to the IPMB bus. */
+	unsigned int sent_lan_commands;
+	/* Commands sent on the IPMB that had errors on the SEND CMD */
+	unsigned int sent_lan_command_errs;
+	/* Each retransmit increments this count. */
+	unsigned int retransmitted_lan_commands;
+	/* When a message times out (runs out of retransmits) this is
+           incremented. */
+	unsigned int timed_out_lan_commands;
+
+	/* Responses I have sent to the IPMB bus. */
+	unsigned int sent_lan_responses;
+
+	/* The response was delivered to the user. */
+	unsigned int handled_lan_responses;
+	/* The response had invalid data in it. */
+	unsigned int invalid_lan_responses;
+	/* The response didn't have anyone waiting for it. */
+	unsigned int unhandled_lan_responses;
+
+	/* The command was delivered to the user. */
+	unsigned int handled_commands;
+	/* The command had invalid data in it. */
+	unsigned int invalid_commands;
+	/* The command didn't have anyone waiting for it. */
+	unsigned int unhandled_commands;
+
+	/* Invalid data in an event. */
+	unsigned int invalid_events;
+	/* Events that were received with the proper format. */
+	unsigned int events;
 };
 
 int
@@ -264,6 +362,21 @@ int ipmi_smi_watcher_unregister(struct i
 	return 0;
 }
 
+static void
+call_smi_watchers(int i)
+{
+	struct ipmi_smi_watcher *w;
+
+	down_read(&smi_watchers_sem);
+	list_for_each_entry(w, &smi_watchers, link) {
+		if (try_module_get(w->owner)) {
+			w->new_smi(i);
+			module_put(w->owner);
+		}
+	}
+	up_read(&smi_watchers_sem);
+}
+
 int
 ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
 {
@@ -293,6 +406,19 @@ ipmi_addr_equal(struct ipmi_addr *addr1,
 			&& (ipmb_addr1->lun == ipmb_addr2->lun));
 	}
 
+	if (addr1->addr_type == IPMI_LAN_ADDR_TYPE) {
+		struct ipmi_lan_addr *lan_addr1
+			= (struct ipmi_lan_addr *) addr1;
+		struct ipmi_lan_addr *lan_addr2
+		    = (struct ipmi_lan_addr *) addr2;
+
+		return ((lan_addr1->remote_SWID == lan_addr2->remote_SWID)
+			&& (lan_addr1->local_SWID == lan_addr2->local_SWID)
+			&& (lan_addr1->session_handle
+			    == lan_addr2->session_handle)
+			&& (lan_addr1->lun == lan_addr2->lun));
+	}
+
 	return 1;
 }
 
@@ -322,6 +448,13 @@ int ipmi_validate_addr(struct ipmi_addr 
 		return 0;
 	}
 
+	if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
+		if (len < sizeof(struct ipmi_lan_addr)) {
+			return -EINVAL;
+		}
+		return 0;
+	}
+
 	return -EINVAL;
 }
 
@@ -341,7 +474,7 @@ unsigned int ipmi_addr_length(int addr_t
 
 static void deliver_response(struct ipmi_recv_msg *msg)
 {
-    msg->user->handler->ipmi_recv_hndl(msg, msg->user->handler_data);
+	msg->user->handler->ipmi_recv_hndl(msg, msg->user->handler_data);
 }
 
 /* Find the next sequence number not being used and add the given
@@ -351,6 +484,7 @@ static int intf_next_seq(ipmi_smi_t     
 			 struct ipmi_recv_msg *recv_msg,
 			 unsigned long        timeout,
 			 int                  retries,
+			 int                  broadcast,
 			 unsigned char        *seq,
 			 long                 *seqid)
 {
@@ -373,6 +507,7 @@ static int intf_next_seq(ipmi_smi_t     
 		intf->seq_table[i].timeout = MAX_MSG_TIMEOUT;
 		intf->seq_table[i].orig_timeout = timeout;
 		intf->seq_table[i].retries_left = retries;
+		intf->seq_table[i].broadcast = broadcast;
 		intf->seq_table[i].inuse = 1;
 		intf->seq_table[i].seqid = NEXT_SEQID(intf->seq_table[i].seqid);
 		*seq = i;
@@ -425,8 +560,8 @@ static int intf_find_seq(ipmi_smi_t     
 
 
 /* Start the timer for a specific sequence table entry. */
-static int intf_start_seq_timer(ipmi_smi_t           intf,
-				long                 msgid)
+static int intf_start_seq_timer(ipmi_smi_t intf,
+				long       msgid)
 {
 	int           rv = -ENODEV;
 	unsigned long flags;
@@ -451,6 +586,46 @@ static int intf_start_seq_timer(ipmi_smi
 	return rv;
 }
 
+/* Got an error for the send message for a specific sequence number. */
+static int intf_err_seq(ipmi_smi_t   intf,
+			long         msgid,
+			unsigned int err)
+{
+	int                  rv = -ENODEV;
+	unsigned long        flags;
+	unsigned char        seq;
+	unsigned long        seqid;
+	struct ipmi_recv_msg *msg = NULL;
+
+
+	GET_SEQ_FROM_MSGID(msgid, seq, seqid);
+
+	spin_lock_irqsave(&(intf->seq_lock), flags);
+	/* We do this verification because the user can be deleted
+           while a message is outstanding. */
+	if ((intf->seq_table[seq].inuse)
+	    && (intf->seq_table[seq].seqid == seqid))
+	{
+		struct seq_table *ent = &(intf->seq_table[seq]);
+
+		ent->inuse = 0;
+		msg = ent->recv_msg;
+		rv = 0;
+	}
+	spin_unlock_irqrestore(&(intf->seq_lock), flags);
+
+	if (msg) {
+		msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
+		msg->msg_data[0] = err;
+		msg->msg.netfn |= 1; /* Convert to a response. */
+		msg->msg.data_len = 1;
+		msg->msg.data = msg->msg_data;
+		deliver_response(msg);
+	}
+
+	return rv;
+}
+
 
 int ipmi_create_user(unsigned int          if_num,
 		     struct ipmi_user_hndl *handler,
@@ -523,15 +698,14 @@ static int ipmi_destroy_user_nolock(ipmi
 {
 	int              rv = -ENODEV;
 	ipmi_user_t      t_user;
-	struct list_head *entry, *entry2;
+	struct cmd_rcvr  *rcvr, *rcvr2;
 	int              i;
 	unsigned long    flags;
 
 	/* Find the user and delete them from the list. */
-	list_for_each(entry, &(user->intf->users)) {
-		t_user = list_entry(entry, struct ipmi_user, link);
+	list_for_each_entry(t_user, &(user->intf->users), link) {
 		if (t_user == user) {
-			list_del(entry);
+			list_del(&t_user->link);
 			rv = 0;
 			break;
 		}
@@ -554,11 +728,9 @@ static int ipmi_destroy_user_nolock(ipmi
 
 	/* Remove the user from the command receiver's table. */
 	write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);
-	list_for_each_safe(entry, entry2, &(user->intf->cmd_rcvrs)) {
-		struct cmd_rcvr *rcvr;
-		rcvr = list_entry(entry, struct cmd_rcvr, link);
+	list_for_each_entry_safe(rcvr, rcvr2, &(user->intf->cmd_rcvrs), link) {
 		if (rcvr->user == user) {
-			list_del(entry);
+			list_del(&rcvr->link);
 			kfree(rcvr);
 		}
 	}
@@ -621,8 +793,7 @@ unsigned char ipmi_get_my_LUN(ipmi_user_
 int ipmi_set_gets_events(ipmi_user_t user, int val)
 {
 	unsigned long         flags;
-	struct list_head      *e, *e2;
-	struct ipmi_recv_msg  *msg;
+	struct ipmi_recv_msg  *msg, *msg2;
 
 	read_lock(&(user->intf->users_lock));
 	spin_lock_irqsave(&(user->intf->events_lock), flags);
@@ -630,9 +801,8 @@ int ipmi_set_gets_events(ipmi_user_t use
 
 	if (val) {
 		/* Deliver any queued events. */
-		list_for_each_safe(e, e2, &(user->intf->waiting_events)) {
-			msg = list_entry(e, struct ipmi_recv_msg, link);
-			list_del(e);
+		list_for_each_entry_safe(msg, msg2, &(user->intf->waiting_events), link) {
+			list_del(&msg->link);
 			msg->user = user;
 			deliver_response(msg);
 		}
@@ -648,7 +818,7 @@ int ipmi_register_for_cmd(ipmi_user_t   
 			  unsigned char netfn,
 			  unsigned char cmd)
 {
-	struct list_head *entry;
+	struct cmd_rcvr  *cmp;
 	unsigned long    flags;
 	struct cmd_rcvr  *rcvr;
 	int              rv = 0;
@@ -666,9 +836,7 @@ int ipmi_register_for_cmd(ipmi_user_t   
 	}
 
 	/* Make sure the command/netfn is not already registered. */
-	list_for_each(entry, &(user->intf->cmd_rcvrs)) {
-		struct cmd_rcvr *cmp;
-		cmp = list_entry(entry, struct cmd_rcvr, link);
+	list_for_each_entry(cmp, &(user->intf->cmd_rcvrs), link) {
 		if ((cmp->netfn == netfn) && (cmp->cmd == cmd)) {
 			rv = -EBUSY;
 			break;
@@ -695,7 +863,6 @@ int ipmi_unregister_for_cmd(ipmi_user_t 
 			    unsigned char netfn,
 			    unsigned char cmd)
 {
-	struct list_head *entry;
 	unsigned long    flags;
 	struct cmd_rcvr  *rcvr;
 	int              rv = -ENOENT;
@@ -703,11 +870,10 @@ int ipmi_unregister_for_cmd(ipmi_user_t 
 	read_lock(&(user->intf->users_lock));
 	write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);
 	/* Make sure the command/netfn is not already registered. */
-	list_for_each(entry, &(user->intf->cmd_rcvrs)) {
-		rcvr = list_entry(entry, struct cmd_rcvr, link);
+	list_for_each_entry(rcvr, &(user->intf->cmd_rcvrs), link) {
 		if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
 			rv = 0;
-			list_del(entry);
+			list_del(&rcvr->link);
 			kfree(rcvr);
 			break;
 		}
@@ -771,6 +937,43 @@ static inline void format_ipmb_msg(struc
 	smi_msg->msgid = msgid;
 }
 
+static inline void format_lan_msg(struct ipmi_smi_msg   *smi_msg,
+				  struct ipmi_msg       *msg,
+				  struct ipmi_lan_addr  *lan_addr,
+				  long                  msgid,
+				  unsigned char         ipmb_seq,
+				  unsigned char         source_lun)
+{
+	/* Format the IPMB header data. */
+	smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	smi_msg->data[1] = IPMI_SEND_MSG_CMD;
+	smi_msg->data[2] = lan_addr->channel;
+	smi_msg->data[3] = lan_addr->session_handle;
+	smi_msg->data[4] = lan_addr->remote_SWID;
+	smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3);
+	smi_msg->data[6] = ipmb_checksum(&(smi_msg->data[4]), 2);
+	smi_msg->data[7] = lan_addr->local_SWID;
+	smi_msg->data[8] = (ipmb_seq << 2) | source_lun;
+	smi_msg->data[9] = msg->cmd;
+
+	/* Now tack on the data to the message. */
+	if (msg->data_len > 0)
+		memcpy(&(smi_msg->data[10]), msg->data,
+		       msg->data_len);
+	smi_msg->data_size = msg->data_len + 10;
+
+	/* Now calculate the checksum and tack it on. */
+	smi_msg->data[smi_msg->data_size]
+		= ipmb_checksum(&(smi_msg->data[7]),
+				smi_msg->data_size-7);
+
+	/* Add on the checksum size and the offset from the
+	   broadcast. */
+	smi_msg->data_size += 1;
+
+	smi_msg->msgid = msgid;
+}
+
 /* Separate from ipmi_request so that the user does not have to be
    supplied in certain circumstances (mainly at panic time).  If
    messages are supplied, they will be freed, even if an error
@@ -780,11 +983,14 @@ static inline int i_ipmi_request(ipmi_us
 				 struct ipmi_addr     *addr,
 				 long                 msgid,
 				 struct ipmi_msg      *msg,
+				 void                 *user_msg_data,
 				 void                 *supplied_smi,
 				 struct ipmi_recv_msg *supplied_recv,
 				 int                  priority,
 				 unsigned char        source_address,
-				 unsigned char        source_lun)
+				 unsigned char        source_lun,
+				 int                  retries,
+				 unsigned int         retry_time_ms)
 {
 	int                  rv = 0;
 	struct ipmi_smi_msg  *smi_msg;
@@ -800,6 +1006,7 @@ static inline int i_ipmi_request(ipmi_us
 			return -ENOMEM;
 		}
 	}
+	recv_msg->user_msg_data = user_msg_data;
 
 	if (supplied_smi) {
 		smi_msg = (struct ipmi_smi_msg *) supplied_smi;
@@ -811,11 +1018,6 @@ static inline int i_ipmi_request(ipmi_us
 		}
 	}
 
-	if (addr->channel > IPMI_NUM_CHANNELS) {
-	    rv = -EINVAL;
-	    goto out_err;
-	}
-
 	recv_msg->user = user;
 	recv_msg->msgid = msgid;
 	/* Store the message to send in the receive message so timeout
@@ -825,10 +1027,20 @@ static inline int i_ipmi_request(ipmi_us
 	if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
 		struct ipmi_system_interface_addr *smi_addr;
 
+		if (msg->netfn & 1) {
+			/* Responses are not allowed to the SMI. */
+			rv = -EINVAL;
+			goto out_err;
+		}
 
 		smi_addr = (struct ipmi_system_interface_addr *) addr;
-		if (smi_addr->lun > 3)
-			return -EINVAL;
+		if (smi_addr->lun > 3) {
+			spin_lock_irqsave(&intf->counter_lock, flags);
+			intf->sent_invalid_commands++;
+			spin_unlock_irqrestore(&intf->counter_lock, flags);
+			rv = -EINVAL;
+			goto out_err;
+		}
 
 		memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
 
@@ -839,11 +1051,17 @@ static inline int i_ipmi_request(ipmi_us
 		{
 			/* We don't let the user do these, since we manage
 			   the sequence numbers. */
+			spin_lock_irqsave(&intf->counter_lock, flags);
+			intf->sent_invalid_commands++;
+			spin_unlock_irqrestore(&intf->counter_lock, flags);
 			rv = -EINVAL;
 			goto out_err;
 		}
 
 		if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
+			spin_lock_irqsave(&intf->counter_lock, flags);
+			intf->sent_invalid_commands++;
+			spin_unlock_irqrestore(&intf->counter_lock, flags);
 			rv = -EMSGSIZE;
 			goto out_err;
 		}
@@ -855,41 +1073,69 @@ static inline int i_ipmi_request(ipmi_us
 		if (msg->data_len > 0)
 			memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
 		smi_msg->data_size = msg->data_len + 2;
+		spin_lock_irqsave(&intf->counter_lock, flags);
+		intf->sent_local_commands++;
+		spin_unlock_irqrestore(&intf->counter_lock, flags);
 	} else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
 		   || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
 	{
 		struct ipmi_ipmb_addr *ipmb_addr;
 		unsigned char         ipmb_seq;
 		long                  seqid;
-		int                   broadcast;
-		int                   retries;
+		int                   broadcast = 0;
+
+		if (addr->channel > IPMI_NUM_CHANNELS) {
+			spin_lock_irqsave(&intf->counter_lock, flags);
+			intf->sent_invalid_commands++;
+			spin_unlock_irqrestore(&intf->counter_lock, flags);
+			rv = -EINVAL;
+			goto out_err;
+		}
 
-		if (addr == NULL) {
+		if (intf->channels[addr->channel].medium
+		    != IPMI_CHANNEL_MEDIUM_IPMB)
+		{
+			spin_lock_irqsave(&intf->counter_lock, flags);
+			intf->sent_invalid_commands++;
+			spin_unlock_irqrestore(&intf->counter_lock, flags);
 			rv = -EINVAL;
 			goto out_err;
 		}
 
+		if (retries < 0) {
+		    if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)
+			retries = 0; /* Don't retry broadcasts. */
+		    else
+			retries = 4;
+		}
 		if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
 		    /* Broadcasts add a zero at the beginning of the
 		       message, but otherwise is the same as an IPMB
 		       address. */
 		    addr->addr_type = IPMI_IPMB_ADDR_TYPE;
 		    broadcast = 1;
-		    retries = 0; /* Don't retry broadcasts. */
-		} else {
-		    broadcast = 0;
-		    retries = 4;
 		}
 
+
+		/* Default to 1 second retries. */
+		if (retry_time_ms == 0)
+		    retry_time_ms = 1000;
+
 		/* 9 for the header and 1 for the checksum, plus
                    possibly one for the broadcast. */
 		if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
+			spin_lock_irqsave(&intf->counter_lock, flags);
+			intf->sent_invalid_commands++;
+			spin_unlock_irqrestore(&intf->counter_lock, flags);
 			rv = -EMSGSIZE;
 			goto out_err;
 		}
 
 		ipmb_addr = (struct ipmi_ipmb_addr *) addr;
 		if (ipmb_addr->lun > 3) {
+			spin_lock_irqsave(&intf->counter_lock, flags);
+			intf->sent_invalid_commands++;
+			spin_unlock_irqrestore(&intf->counter_lock, flags);
 			rv = -EINVAL;
 			goto out_err;
 		}
@@ -899,21 +1145,32 @@ static inline int i_ipmi_request(ipmi_us
 		if (recv_msg->msg.netfn & 0x1) {
 			/* It's a response, so use the user's sequence
                            from msgid. */
+			spin_lock_irqsave(&intf->counter_lock, flags);
+			intf->sent_ipmb_responses++;
+			spin_unlock_irqrestore(&intf->counter_lock, flags);
 			format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
 					msgid, broadcast,
 					source_address, source_lun);
+
+			/* Save the receive message so we can use it
+			   to deliver the response. */
+			smi_msg->user_data = recv_msg;
 		} else {
 			/* It's a command, so get a sequence for it. */
 
 			spin_lock_irqsave(&(intf->seq_lock), flags);
 
+			spin_lock(&intf->counter_lock);
+			intf->sent_ipmb_commands++;
+			spin_unlock(&intf->counter_lock);
+
 			/* Create a sequence number with a 1 second
                            timeout and 4 retries. */
-			/* FIXME - magic number for the timeout. */
 			rv = intf_next_seq(intf,
 					   recv_msg,
-					   1000,
+					   retry_time_ms,
 					   retries,
+					   broadcast,
 					   &ipmb_seq,
 					   &seqid);
 			if (rv) {
@@ -947,18 +1204,132 @@ static inline int i_ipmi_request(ipmi_us
                            to be correct. */
 			spin_unlock_irqrestore(&(intf->seq_lock), flags);
 		}
+	} else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
+		struct ipmi_lan_addr  *lan_addr;
+		unsigned char         ipmb_seq;
+		long                  seqid;
+
+		if (addr->channel > IPMI_NUM_CHANNELS) {
+			spin_lock_irqsave(&intf->counter_lock, flags);
+			intf->sent_invalid_commands++;
+			spin_unlock_irqrestore(&intf->counter_lock, flags);
+			rv = -EINVAL;
+			goto out_err;
+		}
+
+		if ((intf->channels[addr->channel].medium
+		    != IPMI_CHANNEL_MEDIUM_8023LAN)
+		    && (intf->channels[addr->channel].medium
+			!= IPMI_CHANNEL_MEDIUM_ASYNC))
+		{
+			spin_lock_irqsave(&intf->counter_lock, flags);
+			intf->sent_invalid_commands++;
+			spin_unlock_irqrestore(&intf->counter_lock, flags);
+			rv = -EINVAL;
+			goto out_err;
+		}
+
+		retries = 4;
+
+		/* Default to 1 second retries. */
+		if (retry_time_ms == 0)
+		    retry_time_ms = 1000;
+
+		/* 11 for the header and 1 for the checksum. */
+		if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
+			spin_lock_irqsave(&intf->counter_lock, flags);
+			intf->sent_invalid_commands++;
+			spin_unlock_irqrestore(&intf->counter_lock, flags);
+			rv = -EMSGSIZE;
+			goto out_err;
+		}
+
+		lan_addr = (struct ipmi_lan_addr *) addr;
+		if (lan_addr->lun > 3) {
+			spin_lock_irqsave(&intf->counter_lock, flags);
+			intf->sent_invalid_commands++;
+			spin_unlock_irqrestore(&intf->counter_lock, flags);
+			rv = -EINVAL;
+			goto out_err;
+		}
+
+		memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
+
+		if (recv_msg->msg.netfn & 0x1) {
+			/* It's a response, so use the user's sequence
+                           from msgid. */
+			spin_lock_irqsave(&intf->counter_lock, flags);
+			intf->sent_lan_responses++;
+			spin_unlock_irqrestore(&intf->counter_lock, flags);
+			format_lan_msg(smi_msg, msg, lan_addr, msgid,
+				       msgid, source_lun);
+
+			/* Save the receive message so we can use it
+			   to deliver the response. */
+			smi_msg->user_data = recv_msg;
+		} else {
+			/* It's a command, so get a sequence for it. */
+
+			spin_lock_irqsave(&(intf->seq_lock), flags);
+
+			spin_lock(&intf->counter_lock);
+			intf->sent_lan_commands++;
+			spin_unlock(&intf->counter_lock);
+
+			/* Create a sequence number with a 1 second
+                           timeout and 4 retries. */
+			rv = intf_next_seq(intf,
+					   recv_msg,
+					   retry_time_ms,
+					   retries,
+					   0,
+					   &ipmb_seq,
+					   &seqid);
+			if (rv) {
+				/* We have used up all the sequence numbers,
+				   probably, so abort. */
+				spin_unlock_irqrestore(&(intf->seq_lock),
+						       flags);
+				goto out_err;
+			}
+
+			/* Store the sequence number in the message,
+                           so that when the send message response
+                           comes back we can start the timer. */
+			format_lan_msg(smi_msg, msg, lan_addr,
+				       STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
+				       ipmb_seq, source_lun);
+
+			/* Copy the message into the recv message data, so we
+			   can retransmit it later if necessary. */
+			memcpy(recv_msg->msg_data, smi_msg->data,
+			       smi_msg->data_size);
+			recv_msg->msg.data = recv_msg->msg_data;
+			recv_msg->msg.data_len = smi_msg->data_size;
+
+			/* We don't unlock until here, because we need
+                           to copy the completed message into the
+                           recv_msg before we release the lock.
+                           Otherwise, race conditions may bite us.  I
+                           know that's pretty paranoid, but I prefer
+                           to be correct. */
+			spin_unlock_irqrestore(&(intf->seq_lock), flags);
+		}
 	} else {
 	    /* Unknown address type. */
-	    rv = -EINVAL;
-	    goto out_err;
+		spin_lock_irqsave(&intf->counter_lock, flags);
+		intf->sent_invalid_commands++;
+		spin_unlock_irqrestore(&intf->counter_lock, flags);
+		rv = -EINVAL;
+		goto out_err;
 	}
 
 #if DEBUG_MSGING
 	{
-	    int m;
-	    for (m=0; m<smi_msg->data_size; m++)
-		printk(" %2.2x", smi_msg->data[m]);
-	    printk("\n");
+		int m;
+		for (m=0; m<smi_msg->data_size; m++)
+			printk(" %2.2x", smi_msg->data[m]);
+		printk("\n");
 	}
 #endif
 	intf->handlers->sender(intf->send_info, smi_msg, priority);
@@ -975,6 +1346,7 @@ int ipmi_request(ipmi_user_t      user,
 		 struct ipmi_addr *addr,
 		 long             msgid,
 		 struct ipmi_msg  *msg,
+		 void             *user_msg_data,
 		 int              priority)
 {
 	return i_ipmi_request(user,
@@ -982,16 +1354,42 @@ int ipmi_request(ipmi_user_t      user,
 			      addr,
 			      msgid,
 			      msg,
+			      user_msg_data,
 			      NULL, NULL,
 			      priority,
 			      user->intf->my_address,
-			      user->intf->my_lun);
+			      user->intf->my_lun,
+			      -1, 0);
+}
+
+int ipmi_request_settime(ipmi_user_t      user,
+			 struct ipmi_addr *addr,
+			 long             msgid,
+			 struct ipmi_msg  *msg,
+			 void             *user_msg_data,
+			 int              priority,
+			 int              retries,
+			 unsigned int     retry_time_ms)
+{
+	return i_ipmi_request(user,
+			      user->intf,
+			      addr,
+			      msgid,
+			      msg,
+			      user_msg_data,
+			      NULL, NULL,
+			      priority,
+			      user->intf->my_address,
+			      user->intf->my_lun,
+			      retries,
+			      retry_time_ms);
 }
 
 int ipmi_request_supply_msgs(ipmi_user_t          user,
 			     struct ipmi_addr     *addr,
 			     long                 msgid,
 			     struct ipmi_msg      *msg,
+			     void                 *user_msg_data,
 			     void                 *supplied_smi,
 			     struct ipmi_recv_msg *supplied_recv,
 			     int                  priority)
@@ -1001,17 +1399,20 @@ int ipmi_request_supply_msgs(ipmi_user_t
 			      addr,
 			      msgid,
 			      msg,
+			      user_msg_data,
 			      supplied_smi,
 			      supplied_recv,
 			      priority,
 			      user->intf->my_address,
-			      user->intf->my_lun);
+			      user->intf->my_lun,
+			      -1, 0);
 }
 
 int ipmi_request_with_source(ipmi_user_t      user,
 			     struct ipmi_addr *addr,
 			     long             msgid,
 			     struct ipmi_msg  *msg,
+			     void             *user_msg_data,
 			     int              priority,
 			     unsigned char    source_address,
 			     unsigned char    source_lun)
@@ -1021,10 +1422,215 @@ int ipmi_request_with_source(ipmi_user_t
 			      addr,
 			      msgid,
 			      msg,
+			      user_msg_data,
 			      NULL, NULL,
 			      priority,
 			      source_address,
-			      source_lun);
+			      source_lun,
+			      -1, 0);
+}
+
+static int ipmb_file_read_proc(char *page, char **start, off_t off,
+			       int count, int *eof, void *data)
+{
+	char       *out = (char *) page;
+	ipmi_smi_t intf = data;
+
+	return sprintf(out, "%x\n", intf->my_address);
+}
+
+static int version_file_read_proc(char *page, char **start, off_t off,
+				  int count, int *eof, void *data)
+{
+	char       *out = (char *) page;
+	ipmi_smi_t intf = data;
+
+	return sprintf(out, "%d.%d\n",
+		       intf->version_major, intf->version_minor);
+}
+
+static int stat_file_read_proc(char *page, char **start, off_t off,
+			       int count, int *eof, void *data)
+{
+	char       *out = (char *) page;
+	ipmi_smi_t intf = data;
+
+	out += sprintf(out, "sent_invalid_commands:       %d\n",
+		       intf->sent_invalid_commands);
+	out += sprintf(out, "sent_local_commands:         %d\n",
+		       intf->sent_local_commands);
+	out += sprintf(out, "handled_local_responses:     %d\n",
+		       intf->handled_local_responses);
+	out += sprintf(out, "unhandled_local_responses:   %d\n",
+		       intf->unhandled_local_responses);
+	out += sprintf(out, "sent_ipmb_commands:          %d\n",
+		       intf->sent_ipmb_commands);
+	out += sprintf(out, "sent_ipmb_command_errs:      %d\n",
+		       intf->sent_ipmb_command_errs);
+	out += sprintf(out, "retransmitted_ipmb_commands: %d\n",
+		       intf->retransmitted_ipmb_commands);
+	out += sprintf(out, "timed_out_ipmb_commands:     %d\n",
+		       intf->timed_out_ipmb_commands);
+	out += sprintf(out, "timed_out_ipmb_broadcasts:   %d\n",
+		       intf->timed_out_ipmb_broadcasts);
+	out += sprintf(out, "sent_ipmb_responses:         %d\n",
+		       intf->sent_ipmb_responses);
+	out += sprintf(out, "handled_ipmb_responses:      %d\n",
+		       intf->handled_ipmb_responses);
+	out += sprintf(out, "invalid_ipmb_responses:      %d\n",
+		       intf->invalid_ipmb_responses);
+	out += sprintf(out, "unhandled_ipmb_responses:    %d\n",
+		       intf->unhandled_ipmb_responses);
+	out += sprintf(out, "sent_lan_commands:           %d\n",
+		       intf->sent_lan_commands);
+	out += sprintf(out, "sent_lan_command_errs:       %d\n",
+		       intf->sent_lan_command_errs);
+	out += sprintf(out, "retransmitted_lan_commands:  %d\n",
+		       intf->retransmitted_lan_commands);
+	out += sprintf(out, "timed_out_lan_commands:      %d\n",
+		       intf->timed_out_lan_commands);
+	out += sprintf(out, "sent_lan_responses:          %d\n",
+		       intf->sent_lan_responses);
+	out += sprintf(out, "handled_lan_responses:       %d\n",
+		       intf->handled_lan_responses);
+	out += sprintf(out, "invalid_lan_responses:       %d\n",
+		       intf->invalid_lan_responses);
+	out += sprintf(out, "unhandled_lan_responses:     %d\n",
+		       intf->unhandled_lan_responses);
+	out += sprintf(out, "handled_commands:            %d\n",
+		       intf->handled_commands);
+	out += sprintf(out, "invalid_commands:            %d\n",
+		       intf->invalid_commands);
+	out += sprintf(out, "unhandled_commands:          %d\n",
+		       intf->unhandled_commands);
+	out += sprintf(out, "invalid_events:              %d\n",
+		       intf->invalid_events);
+	out += sprintf(out, "events:                      %d\n",
+		       intf->events);
+
+	return (out - ((char *) page));
+}
+
+int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
+			    read_proc_t *read_proc, write_proc_t *write_proc,
+			    void *data, struct module *owner)
+{
+	struct proc_dir_entry *file;
+	int                   rv = 0;
+
+	file = create_proc_entry(name, 0, smi->proc_dir);
+	if (!file)
+		rv = -ENOMEM;
+	else {
+		file->nlink = 1;
+		file->data = data;
+		file->read_proc = read_proc;
+		file->write_proc = write_proc;
+		file->owner = owner;
+	}
+
+	return rv;
+}
+
+static int add_proc_entries(ipmi_smi_t smi, int num)
+{
+	int rv = 0;
+
+	sprintf(smi->proc_dir_name, "%d", num);
+	smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
+	if (!smi->proc_dir)
+		rv = -ENOMEM;
+	else {
+		smi->proc_dir->owner = THIS_MODULE;
+	}
+
+	if (rv == 0)
+		rv = ipmi_smi_add_proc_entry(smi, "stats",
+					     stat_file_read_proc, NULL,
+					     smi, THIS_MODULE);
+
+	if (rv == 0)
+		rv = ipmi_smi_add_proc_entry(smi, "ipmb",
+					     ipmb_file_read_proc, NULL,
+					     smi, THIS_MODULE);
+
+	if (rv == 0)
+		rv = ipmi_smi_add_proc_entry(smi, "version",
+					     version_file_read_proc, NULL,
+					     smi, THIS_MODULE);
+
+	return rv;
+}
+
+static int
+send_channel_info_cmd(ipmi_smi_t intf, int chan)
+{
+	struct ipmi_msg                   msg;
+	unsigned char                     data[1];
+	struct ipmi_system_interface_addr si;
+
+	si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	si.channel = IPMI_BMC_CHANNEL;
+	si.lun = 0;
+
+	msg.netfn = IPMI_NETFN_APP_REQUEST;
+	msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
+	msg.data = data;
+	msg.data_len = 1;
+	data[0] = chan;
+	return i_ipmi_request(NULL,
+			      intf,
+			      (struct ipmi_addr *) &si,
+			      0,
+			      &msg,
+			      NULL,
+			      NULL,
+			      NULL,
+			      0,
+			      intf->my_address,
+			      intf->my_lun,
+			      -1, 0);
+}
+
+static void
+channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+{
+	int rv = 0;
+	int chan;
+
+	if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2))
+	    && (msg->rsp[1] == IPMI_GET_CHANNEL_INFO_CMD))
+	{
+		/* It's the one we want */
+		if (msg->rsp[2] != 0) {
+			/* Got an error from the channel, just go on. */
+			goto next_channel;
+		}
+		if (msg->rsp_size < 6) {
+			/* Message not big enough, just go on. */
+			goto next_channel;
+		}
+		chan = intf->curr_channel;
+		intf->channels[chan].medium = msg->rsp[4] & 0x7f;
+		intf->channels[chan].protocol = msg->rsp[5] & 0x1f;
+
+	next_channel:
+		intf->curr_channel++;
+		if (intf->curr_channel >= IPMI_MAX_CHANNELS)
+			wake_up(&intf->waitq);
+		else
+			rv = send_channel_info_cmd(intf, intf->curr_channel);
+
+		if (rv) {
+			/* Got an error somehow, just give up. */
+			intf->curr_channel = IPMI_MAX_CHANNELS;
+			wake_up(&intf->waitq);
+
+			printk(KERN_WARNING "ipmi_msghandler: Error sending"
+			       "channel information: 0x%x\n",
+			       rv);
+		}
+	}
 }
 
 int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
@@ -1036,7 +1642,6 @@ int ipmi_register_smi(struct ipmi_smi_ha
 	int              i, j;
 	int              rv;
 	ipmi_smi_t       new_intf;
-	struct list_head *entry;
 	unsigned long    flags;
 
 
@@ -1055,12 +1660,16 @@ int ipmi_register_smi(struct ipmi_smi_ha
 	new_intf = kmalloc(sizeof(*new_intf), GFP_KERNEL);
 	if (!new_intf)
 		return -ENOMEM;
+	memset(new_intf, 0, sizeof(*new_intf));
+
+	new_intf->proc_dir = NULL;
 
 	rv = -ENOMEM;
 
 	down_write(&interfaces_sem);
 	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
 		if (ipmi_interfaces[i] == NULL) {
+			new_intf->intf_num = i;
 			new_intf->version_major = version_major;
 			new_intf->version_minor = version_minor;
 			new_intf->my_address = IPMI_BMC_SLAVE_ADDR;
@@ -1081,9 +1690,12 @@ int ipmi_register_smi(struct ipmi_smi_ha
 			INIT_LIST_HEAD(&(new_intf->waiting_events));
 			new_intf->waiting_events_count = 0;
 			rwlock_init(&(new_intf->cmd_rcvr_lock));
+			init_waitqueue_head(&new_intf->waitq);
 			INIT_LIST_HEAD(&(new_intf->cmd_rcvrs));
 			new_intf->all_cmd_rcvr = NULL;
 
+			spin_lock_init(&(new_intf->counter_lock));
+
 			spin_lock_irqsave(&interfaces_lock, flags);
 			ipmi_interfaces[i] = new_intf;
 			spin_unlock_irqrestore(&interfaces_lock, flags);
@@ -1096,46 +1708,71 @@ int ipmi_register_smi(struct ipmi_smi_ha
 
 	downgrade_write(&interfaces_sem);
 
+	if (rv == 0)
+		rv = add_proc_entries(*intf, i);
+
 	if (rv == 0) {
-		/* Call all the watcher interfaces to tell them that a
-		   new interface is available. */
-		down_read(&smi_watchers_sem);
-		list_for_each(entry, &smi_watchers) {
-			struct ipmi_smi_watcher *w;
-			w = list_entry(entry, struct ipmi_smi_watcher, link);
-			w->new_smi(i);
-		}
-		up_read(&smi_watchers_sem);
+		if ((version_major > 1)
+		    || ((version_major == 1) && (version_minor >= 5)))
+		{
+			/* Start scanning the channels to see what is
+			   available. */
+			(*intf)->null_user_handler = channel_handler;
+			(*intf)->curr_channel = 0;
+			rv = send_channel_info_cmd(*intf, 0);
+			if (rv)
+				goto out;
+
+			/* Wait for the channel info to be read. */
+			up_read(&interfaces_sem);
+			wait_event((*intf)->waitq,
+				   ((*intf)->curr_channel>=IPMI_MAX_CHANNELS));
+			down_read(&interfaces_sem);
+
+			if (ipmi_interfaces[i] != new_intf)
+				/* Well, it went away.  Just return. */
+				goto out;
+		} else {
+			/* Assume a single IPMB channel at zero. */
+			(*intf)->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
+			(*intf)->channels[0].protocol
+				= IPMI_CHANNEL_PROTOCOL_IPMB;
+  		}
+
+		/* Call all the watcher interfaces to tell
+		   them that a new interface is available. */
+		call_smi_watchers(i);
 	}
 
+ out:
 	up_read(&interfaces_sem);
 
-	if (rv)
+	if (rv) {
+		if (new_intf->proc_dir)
+			remove_proc_entry(new_intf->proc_dir_name,
+					  proc_ipmi_root);
 		kfree(new_intf);
+	}
 
 	return rv;
 }
 
 static void free_recv_msg_list(struct list_head *q)
 {
-	struct list_head     *entry, *entry2;
-	struct ipmi_recv_msg *msg;
+	struct ipmi_recv_msg *msg, *msg2;
 
-	list_for_each_safe(entry, entry2, q) {
-		msg = list_entry(entry, struct ipmi_recv_msg, link);
-		list_del(entry);
+	list_for_each_entry_safe(msg, msg2, q, link) {
+		list_del(&msg->link);
 		ipmi_free_recv_msg(msg);
 	}
 }
 
 static void free_cmd_rcvr_list(struct list_head *q)
 {
-	struct list_head *entry, *entry2;
-	struct cmd_rcvr  *rcvr;
+	struct cmd_rcvr  *rcvr, *rcvr2;
 
-	list_for_each_safe(entry, entry2, q) {
-		rcvr = list_entry(entry, struct cmd_rcvr, link);
-		list_del(entry);
+	list_for_each_entry_safe(rcvr, rcvr2, q, link) {
+		list_del(&rcvr->link);
 		kfree(rcvr);
 	}
 }
@@ -1159,16 +1796,18 @@ static void clean_up_interface_data(ipmi
 
 int ipmi_unregister_smi(ipmi_smi_t intf)
 {
-	int              rv = -ENODEV;
-	int              i;
-	struct list_head *entry;
-	unsigned long    flags;
+	int                     rv = -ENODEV;
+	int                     i;
+	struct ipmi_smi_watcher *w;
+	unsigned long           flags;
 
 	down_write(&interfaces_sem);
 	if (list_empty(&(intf->users)))
 	{
 		for (i=0; i<MAX_IPMI_INTERFACES; i++) {
 			if (ipmi_interfaces[i] == intf) {
+				remove_proc_entry(intf->proc_dir_name,
+						  proc_ipmi_root);
 				spin_lock_irqsave(&interfaces_lock, flags);
 				ipmi_interfaces[i] = NULL;
 				clean_up_interface_data(intf);
@@ -1191,11 +1830,7 @@ int ipmi_unregister_smi(ipmi_smi_t intf)
 	/* Call all the watcher interfaces to tell them that
 	   an interface is gone. */
 	down_read(&smi_watchers_sem);
-	list_for_each(entry, &smi_watchers) {
-		struct ipmi_smi_watcher *w;
-		w = list_entry(entry,
-			       struct ipmi_smi_watcher,
-			       link);
+	list_for_each_entry(w, &smi_watchers, link) {
 		w->smi_gone(i);
 	}
 	up_read(&smi_watchers_sem);
@@ -1203,20 +1838,28 @@ int ipmi_unregister_smi(ipmi_smi_t intf)
 	return 0;
 }
 
-static int handle_get_msg_rsp(ipmi_smi_t          intf,
-			      struct ipmi_smi_msg *msg)
+static int handle_ipmb_get_msg_rsp(ipmi_smi_t          intf,
+				   struct ipmi_smi_msg *msg)
 {
 	struct ipmi_ipmb_addr ipmb_addr;
 	struct ipmi_recv_msg  *recv_msg;
+	unsigned long         flags;
 
 	
-	if (msg->rsp_size < 11)
+	/* This is 11, not 10, because the response must contain a
+	 * completion code. */
+	if (msg->rsp_size < 11) {
 		/* Message not big enough, just ignore it. */
+		spin_lock_irqsave(&intf->counter_lock, flags);
+		intf->invalid_ipmb_responses++;
+		spin_unlock_irqrestore(&intf->counter_lock, flags);
 		return 0;
+	}
 
-	if (msg->rsp[2] != 0)
+	if (msg->rsp[2] != 0) {
 		/* An error getting the response, just ignore it. */
 		return 0;
+	}
 
 	ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
 	ipmb_addr.slave_addr = msg->rsp[6];
@@ -1235,6 +1878,9 @@ static int handle_get_msg_rsp(ipmi_smi_t
 	{
 		/* We were unable to find the sequence number,
 		   so just nuke the message. */
+		spin_lock_irqsave(&intf->counter_lock, flags);
+		intf->unhandled_ipmb_responses++;
+		spin_unlock_irqrestore(&intf->counter_lock, flags);
 		return 0;
 	}
 
@@ -1248,26 +1894,33 @@ static int handle_get_msg_rsp(ipmi_smi_t
 	recv_msg->msg.data = recv_msg->msg_data;
 	recv_msg->msg.data_len = msg->rsp_size - 10;
 	recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
+	spin_lock_irqsave(&intf->counter_lock, flags);
+	intf->handled_ipmb_responses++;
+	spin_unlock_irqrestore(&intf->counter_lock, flags);
 	deliver_response(recv_msg);
 
 	return 0;
 }
 
-static int handle_get_msg_cmd(ipmi_smi_t          intf,
-			      struct ipmi_smi_msg *msg)
+static int handle_ipmb_get_msg_cmd(ipmi_smi_t          intf,
+				   struct ipmi_smi_msg *msg)
 {
-	struct list_head *entry;
 	struct cmd_rcvr       *rcvr;
-	int              rv = 0;
-	unsigned char    netfn;
-	unsigned char    cmd;
-	ipmi_user_t      user = NULL;
+	int                   rv = 0;
+	unsigned char         netfn;
+	unsigned char         cmd;
+	ipmi_user_t           user = NULL;
 	struct ipmi_ipmb_addr *ipmb_addr;
 	struct ipmi_recv_msg  *recv_msg;
+	unsigned long         flags;
 
-	if (msg->rsp_size < 10)
+	if (msg->rsp_size < 10) {
 		/* Message not big enough, just ignore it. */
+		spin_lock_irqsave(&intf->counter_lock, flags);
+		intf->invalid_commands++;
+		spin_unlock_irqrestore(&intf->counter_lock, flags);
 		return 0;
+	}
 
 	if (msg->rsp[2] != 0) {
 		/* An error getting the response, just ignore it. */
@@ -1283,8 +1936,7 @@ static int handle_get_msg_cmd(ipmi_smi_t
 		user = intf->all_cmd_rcvr;
 	} else {
 		/* Find the command/netfn. */
-		list_for_each(entry, &(intf->cmd_rcvrs)) {
-			rcvr = list_entry(entry, struct cmd_rcvr, link);
+		list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
 			if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
 				user = rcvr->user;
 				break;
@@ -1295,6 +1947,10 @@ static int handle_get_msg_cmd(ipmi_smi_t
 
 	if (user == NULL) {
 		/* We didn't find a user, deliver an error response. */
+		spin_lock_irqsave(&intf->counter_lock, flags);
+		intf->unhandled_commands++;
+		spin_unlock_irqrestore(&intf->counter_lock, flags);
+
 		msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
 		msg->data[1] = IPMI_SEND_MSG_CMD;
 		msg->data[2] = msg->rsp[3];
@@ -1309,12 +1965,25 @@ static int handle_get_msg_cmd(ipmi_smi_t
 		msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
 		msg->data_size = 11;
 
+#if DEBUG_MSGING
+	{
+		int m;
+		printk("Invalid command:");
+		for (m=0; m<msg->data_size; m++)
+			printk(" %2.2x", msg->data[m]);
+		printk("\n");
+	}
+#endif
 		intf->handlers->sender(intf->send_info, msg, 0);
 
 		rv = -1; /* We used the message, so return the value that
 			    causes it to not be freed or queued. */
 	} else {
 		/* Deliver the message to the user. */
+		spin_lock_irqsave(&intf->counter_lock, flags);
+		intf->handled_commands++;
+		spin_unlock_irqrestore(&intf->counter_lock, flags);
+
 		recv_msg = ipmi_alloc_recv_msg();
 		if (! recv_msg) {
 			/* We couldn't allocate memory for the
@@ -1322,18 +1991,24 @@ static int handle_get_msg_cmd(ipmi_smi_t
                            later. */
 			rv = 1;
 		} else {
+			/* Extract the source address from the data. */
 			ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
 			ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
 			ipmb_addr->slave_addr = msg->rsp[6];
 			ipmb_addr->lun = msg->rsp[7] & 3;
-			ipmb_addr->channel = msg->rsp[3];
+			ipmb_addr->channel = msg->rsp[3] & 0xf;
 
+			/* Extract the rest of the message information
+			   from the IPMB header.*/
 			recv_msg->user = user;
 			recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
 			recv_msg->msgid = msg->rsp[7] >> 2;
 			recv_msg->msg.netfn = msg->rsp[4] >> 2;
 			recv_msg->msg.cmd = msg->rsp[8];
 			recv_msg->msg.data = recv_msg->msg_data;
+
+			/* We chop off 10, not 9 bytes because the checksum
+			   at the end also needs to be removed. */
 			recv_msg->msg.data_len = msg->rsp_size - 10;
 			memcpy(recv_msg->msg_data,
 			       &(msg->rsp[9]),
@@ -1345,6 +2020,169 @@ static int handle_get_msg_cmd(ipmi_smi_t
 	return rv;
 }
 
+static int handle_lan_get_msg_rsp(ipmi_smi_t          intf,
+				  struct ipmi_smi_msg *msg)
+{
+	struct ipmi_lan_addr  lan_addr;
+	struct ipmi_recv_msg  *recv_msg;
+	unsigned long         flags;
+
+
+	/* This is 13, not 12, because the response must contain a
+	 * completion code. */
+	if (msg->rsp_size < 13) {
+		/* Message not big enough, just ignore it. */
+		spin_lock_irqsave(&intf->counter_lock, flags);
+		intf->invalid_lan_responses++;
+		spin_unlock_irqrestore(&intf->counter_lock, flags);
+		return 0;
+	}
+
+	if (msg->rsp[2] != 0) {
+		/* An error getting the response, just ignore it. */
+		return 0;
+	}
+
+	lan_addr.addr_type = IPMI_LAN_ADDR_TYPE;
+	lan_addr.session_handle = msg->rsp[4];
+	lan_addr.remote_SWID = msg->rsp[8];
+	lan_addr.local_SWID = msg->rsp[5];
+	lan_addr.channel = msg->rsp[3] & 0x0f;
+	lan_addr.privilege = msg->rsp[3] >> 4;
+	lan_addr.lun = msg->rsp[9] & 3;
+
+	/* It's a response from a remote entity.  Look up the sequence
+	   number and handle the response. */
+	if (intf_find_seq(intf,
+			  msg->rsp[9] >> 2,
+			  msg->rsp[3] & 0x0f,
+			  msg->rsp[10],
+			  (msg->rsp[6] >> 2) & (~1),
+			  (struct ipmi_addr *) &(lan_addr),
+			  &recv_msg))
+	{
+		/* We were unable to find the sequence number,
+		   so just nuke the message. */
+		spin_lock_irqsave(&intf->counter_lock, flags);
+		intf->unhandled_lan_responses++;
+		spin_unlock_irqrestore(&intf->counter_lock, flags);
+		return 0;
+	}
+
+	memcpy(recv_msg->msg_data,
+	       &(msg->rsp[11]),
+	       msg->rsp_size - 11);
+	/* The other fields matched, so no need to set them, except
+           for netfn, which needs to be the response that was
+           returned, not the request value. */
+	recv_msg->msg.netfn = msg->rsp[6] >> 2;
+	recv_msg->msg.data = recv_msg->msg_data;
+	recv_msg->msg.data_len = msg->rsp_size - 12;
+	recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
+	spin_lock_irqsave(&intf->counter_lock, flags);
+	intf->handled_lan_responses++;
+	spin_unlock_irqrestore(&intf->counter_lock, flags);
+	deliver_response(recv_msg);
+
+	return 0;
+}
+
+static int handle_lan_get_msg_cmd(ipmi_smi_t          intf,
+				  struct ipmi_smi_msg *msg)
+{
+	struct cmd_rcvr       *rcvr;
+	int                   rv = 0;
+	unsigned char         netfn;
+	unsigned char         cmd;
+	ipmi_user_t           user = NULL;
+	struct ipmi_lan_addr  *lan_addr;
+	struct ipmi_recv_msg  *recv_msg;
+	unsigned long         flags;
+
+	if (msg->rsp_size < 12) {
+		/* Message not big enough, just ignore it. */
+		spin_lock_irqsave(&intf->counter_lock, flags);
+		intf->invalid_commands++;
+		spin_unlock_irqrestore(&intf->counter_lock, flags);
+		return 0;
+	}
+
+	if (msg->rsp[2] != 0) {
+		/* An error getting the response, just ignore it. */
+		return 0;
+	}
+
+	netfn = msg->rsp[6] >> 2;
+	cmd = msg->rsp[10];
+
+	read_lock(&(intf->cmd_rcvr_lock));
+
+	if (intf->all_cmd_rcvr) {
+		user = intf->all_cmd_rcvr;
+	} else {
+		/* Find the command/netfn. */
+		list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
+			if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
+				user = rcvr->user;
+				break;
+			}
+		}
+	}
+	read_unlock(&(intf->cmd_rcvr_lock));
+
+	if (user == NULL) {
+		/* We didn't find a user, deliver an error response. */
+		spin_lock_irqsave(&intf->counter_lock, flags);
+		intf->unhandled_commands++;
+		spin_unlock_irqrestore(&intf->counter_lock, flags);
+
+		rv = 0; /* Don't do anything with these messages, just
+			   allow them to be freed. */
+	} else {
+		/* Deliver the message to the user. */
+		spin_lock_irqsave(&intf->counter_lock, flags);
+		intf->handled_commands++;
+		spin_unlock_irqrestore(&intf->counter_lock, flags);
+
+		recv_msg = ipmi_alloc_recv_msg();
+		if (! recv_msg) {
+			/* We couldn't allocate memory for the
+                           message, so requeue it for handling
+                           later. */
+			rv = 1;
+		} else {
+			/* Extract the source address from the data. */
+			lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
+			lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
+			lan_addr->session_handle = msg->rsp[4];
+			lan_addr->remote_SWID = msg->rsp[8];
+			lan_addr->local_SWID = msg->rsp[5];
+			lan_addr->lun = msg->rsp[9] & 3;
+			lan_addr->channel = msg->rsp[3] & 0xf;
+			lan_addr->privilege = msg->rsp[3] >> 4;
+
+			/* Extract the rest of the message information
+			   from the IPMB header.*/
+			recv_msg->user = user;
+			recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
+			recv_msg->msgid = msg->rsp[9] >> 2;
+			recv_msg->msg.netfn = msg->rsp[6] >> 2;
+			recv_msg->msg.cmd = msg->rsp[10];
+			recv_msg->msg.data = recv_msg->msg_data;
+
+			/* We chop off 12, not 11 bytes because the checksum
+			   at the end also needs to be removed. */
+			recv_msg->msg.data_len = msg->rsp_size - 12;
+			memcpy(recv_msg->msg_data,
+			       &(msg->rsp[11]),
+			       msg->rsp_size - 12);
+			deliver_response(recv_msg);
+		}
+	}
+
+	return rv;
+}
+
 static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
 				     struct ipmi_smi_msg  *msg)
 {
@@ -1368,9 +2206,8 @@ static void copy_event_into_recv_msg(str
 static int handle_read_event_rsp(ipmi_smi_t          intf,
 				 struct ipmi_smi_msg *msg)
 {
-	struct ipmi_recv_msg *recv_msg;
+	struct ipmi_recv_msg *recv_msg, *recv_msg2;
 	struct list_head     msgs;
-	struct list_head     *entry, *entry2;
 	ipmi_user_t          user;
 	int                  rv = 0;
 	int                  deliver_count = 0;
@@ -1378,6 +2215,9 @@ static int handle_read_event_rsp(ipmi_sm
 
 	if (msg->rsp_size < 19) {
 		/* Message is too small to be an IPMB event. */
+		spin_lock_irqsave(&intf->counter_lock, flags);
+		intf->invalid_events++;
+		spin_unlock_irqrestore(&intf->counter_lock, flags);
 		return 0;
 	}
 
@@ -1390,21 +2230,20 @@ static int handle_read_event_rsp(ipmi_sm
 
 	spin_lock_irqsave(&(intf->events_lock), flags);
 
+	spin_lock(&intf->counter_lock);
+	intf->events++;
+	spin_unlock(&intf->counter_lock);
+
 	/* Allocate and fill in one message for every user that is getting
 	   events. */
-	list_for_each(entry, &(intf->users)) {
-		user = list_entry(entry, struct ipmi_user, link);
-
+	list_for_each_entry(user, &(intf->users), link) {
 		if (! user->gets_events)
 			continue;
 
 		recv_msg = ipmi_alloc_recv_msg();
 		if (! recv_msg) {
-			list_for_each_safe(entry, entry2, &msgs) {
-				recv_msg = list_entry(entry,
-						      struct ipmi_recv_msg,
-						      link);
-				list_del(entry);
+			list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
+				list_del(&recv_msg->link);
 				ipmi_free_recv_msg(recv_msg);
 			}
 			/* We couldn't allocate memory for the
@@ -1423,11 +2262,8 @@ static int handle_read_event_rsp(ipmi_sm
 
 	if (deliver_count) {
 		/* Now deliver all the messages. */
-		list_for_each_safe(entry, entry2, &msgs) {
-			recv_msg = list_entry(entry,
-					      struct ipmi_recv_msg,
-					      link);
-			list_del(entry);
+		list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
+			list_del(&recv_msg->link);
 			deliver_response(recv_msg);
 		}
 	} else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
@@ -1462,15 +2298,14 @@ static int handle_bmc_rsp(ipmi_smi_t    
 {
 	struct ipmi_recv_msg *recv_msg;
 	int                  found = 0;
-	struct list_head     *entry;
+	struct ipmi_user     *user;
+	unsigned long        flags;
 
 	recv_msg = (struct ipmi_recv_msg *) msg->user_data;
 
 	/* Make sure the user still exists. */
-	list_for_each(entry, &(intf->users)) {
-		if (list_entry(entry, struct ipmi_user, link)
-		    == recv_msg->user)
-		{
+	list_for_each_entry(user, &(intf->users), link) {
+		if (user == recv_msg->user) {
 			/* Found it, so we can deliver it */
 			found = 1;
 			break;
@@ -1482,10 +2317,16 @@ static int handle_bmc_rsp(ipmi_smi_t    
 		if (!recv_msg->user && intf->null_user_handler)
 			intf->null_user_handler(intf, msg);
 		/* The user for the message went away, so give up. */
+		spin_lock_irqsave(&intf->counter_lock, flags);
+		intf->unhandled_local_responses++;
+		spin_unlock_irqrestore(&intf->counter_lock, flags);
 		ipmi_free_recv_msg(recv_msg);
 	} else {
 		struct ipmi_system_interface_addr *smi_addr;
 
+		spin_lock_irqsave(&intf->counter_lock, flags);
+		intf->handled_local_responses++;
+		spin_unlock_irqrestore(&intf->counter_lock, flags);
 		recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
 		recv_msg->msgid = msg->msgid;
 		smi_addr = ((struct ipmi_system_interface_addr *)
@@ -1513,28 +2354,86 @@ static int handle_new_recv_msg(ipmi_smi_
 			       struct ipmi_smi_msg *msg)
 {
 	int requeue;
+	int chan;
 
+#if DEBUG_MSGING
+	int m;
+	printk("Recv:");
+	for (m=0; m<msg->rsp_size; m++)
+		printk(" %2.2x", msg->rsp[m]);
+	printk("\n");
+#endif
 	if (msg->rsp_size < 2) {
 		/* Message is too small to be correct. */
 		requeue = 0;
-	} else if (msg->rsp[1] == IPMI_GET_MSG_CMD) {
-#if DEBUG_MSGING
-		int m;
-		printk("Response:");
-		for (m=0; m<msg->rsp_size; m++)
-			printk(" %2.2x", msg->rsp[m]);
-		printk("\n");
-#endif
+	} else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
+		   && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
+		   && (msg->user_data != NULL))
+	{
+		/* It's a response to a response we sent.  For this we
+		   deliver a send message response to the user. */
+		struct ipmi_recv_msg *recv_msg = msg->user_data;
+
+		requeue = 0;
+		if (msg->rsp_size < 2)
+			/* Message is too small to be correct. */
+			goto out;
+
+		chan = msg->data[2] & 0x0f;
+		if (chan >= IPMI_MAX_CHANNELS)
+			/* Invalid channel number */
+			goto out;
+
+		if (recv_msg) {
+			recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
+			recv_msg->msg.data = recv_msg->msg_data;
+			recv_msg->msg.data_len = 1;
+			recv_msg->msg_data[0] = msg->rsp[2];
+			deliver_response(recv_msg);
+		}
+	} else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
+		   && (msg->rsp[1] == IPMI_GET_MSG_CMD))
+	{
 		/* It's from the receive queue. */
-		if (msg->rsp[4] & 0x04) {
-			/* It's a response, so find the
-			   requesting message and send it up. */
-			requeue = handle_get_msg_rsp(intf, msg);
-		} else {
-			/* It's a command to the SMS from some other
-			   entity.  Handle that. */
-			requeue = handle_get_msg_cmd(intf, msg);
+		chan = msg->rsp[3] & 0xf;
+		if (chan >= IPMI_MAX_CHANNELS) {
+			/* Invalid channel number */
+			requeue = 0;
+			goto out;
 		}
+
+		switch (intf->channels[chan].medium) {
+		case IPMI_CHANNEL_MEDIUM_IPMB:
+			if (msg->rsp[4] & 0x04) {
+				/* It's a response, so find the
+				   requesting message and send it up. */
+				requeue = handle_ipmb_get_msg_rsp(intf, msg);
+			} else {
+				/* It's a command to the SMS from some other
+				   entity.  Handle that. */
+				requeue = handle_ipmb_get_msg_cmd(intf, msg);
+			}
+			break;
+
+		case IPMI_CHANNEL_MEDIUM_8023LAN:
+		case IPMI_CHANNEL_MEDIUM_ASYNC:
+			if (msg->rsp[6] & 0x04) {
+				/* It's a response, so find the
+				   requesting message and send it up. */
+				requeue = handle_lan_get_msg_rsp(intf, msg);
+			} else {
+				/* It's a command to the SMS from some other
+				   entity.  Handle that. */
+				requeue = handle_lan_get_msg_cmd(intf, msg);
+			}
+			break;
+
+		default:
+			/* We don't handle the channel type, so just
+			 * free the message. */
+			requeue = 0;
+		}
+
 	} else if (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD) {
 		/* It's an asyncronous event. */
 		requeue = handle_read_event_rsp(intf, msg);
@@ -1543,6 +2442,7 @@ static int handle_new_recv_msg(ipmi_smi_
 		requeue = handle_bmc_rsp(intf, msg);
 	}
 
+ out:
 	return requeue;
 }
 
@@ -1558,10 +2458,43 @@ void ipmi_smi_msg_received(ipmi_smi_t   
 	   working on it. */
 	read_lock(&(intf->users_lock));
 
-	if ((msg->data_size >= 2) && (msg->data[1] == IPMI_SEND_MSG_CMD)) {
-		/* This is the local response to a send, start the
-                   timer for these. */
-		intf_start_seq_timer(intf, msg->msgid);
+	if ((msg->data_size >= 2)
+	    && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
+	    && (msg->data[1] == IPMI_SEND_MSG_CMD)
+	    && (msg->user_data == NULL)) {
+		/* This is the local response to a command send, start
+                   the timer for these.  The user_data will not be
+                   NULL if this is a response send, and we will let
+                   response sends just go through. */
+
+		/* Check for errors, if we get certain errors (ones
+                   that mean basically we can try again later), we
+                   ignore them and start the timer.  Otherwise we
+                   report the error immediately. */
+		if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
+		    && (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
+		    && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR))
+		{
+			int chan = msg->rsp[3] & 0xf;
+
+			/* Got an error sending the message, handle it. */
+			spin_lock_irqsave(&intf->counter_lock, flags);
+			if (chan >= IPMI_MAX_CHANNELS)
+				; /* This shouldn't happen */
+			else if ((intf->channels[chan].medium
+				  == IPMI_CHANNEL_MEDIUM_8023LAN)
+				 || (intf->channels[chan].medium
+				     == IPMI_CHANNEL_MEDIUM_ASYNC))
+				intf->sent_lan_command_errs++;
+			else
+				intf->sent_ipmb_command_errs++;
+			spin_unlock_irqrestore(&intf->counter_lock, flags);
+			intf_err_seq(intf, msg->msgid, msg->rsp[2]);
+		} else {
+			/* The message was sent, start the timer. */
+			intf_start_seq_timer(intf, msg->msgid);
+		}
+
 		ipmi_free_smi_msg(msg);
 		goto out_unlock;
 	}
@@ -1593,13 +2526,10 @@ void ipmi_smi_msg_received(ipmi_smi_t   
 
 void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
 {
-	struct list_head *entry;
-	ipmi_user_t      user;
+	ipmi_user_t user;
 
 	read_lock(&(intf->users_lock));
-	list_for_each(entry, &(intf->users)) {
-		user = list_entry(entry, struct ipmi_user, link);
-
+	list_for_each_entry(user, &(intf->users), link) {
 		if (! user->handler->ipmi_watchdog_pretimeout)
 			continue;
 
@@ -1657,10 +2587,9 @@ ipmi_timeout_handler(long timeout_period
 {
 	ipmi_smi_t           intf;
 	struct list_head     timeouts;
-	struct ipmi_recv_msg *msg;
-	struct ipmi_smi_msg  *smi_msg;
+	struct ipmi_recv_msg *msg, *msg2;
+	struct ipmi_smi_msg  *smi_msg, *smi_msg2;
 	unsigned long        flags;
-	struct list_head     *entry, *entry2;
 	int                  i, j;
 
 	INIT_LIST_HEAD(&timeouts);
@@ -1675,10 +2604,9 @@ ipmi_timeout_handler(long timeout_period
 
 		/* See if any waiting messages need to be processed. */
 		spin_lock_irqsave(&(intf->waiting_msgs_lock), flags);
-		list_for_each_safe(entry, entry2, &(intf->waiting_msgs)) {
-			smi_msg = list_entry(entry, struct ipmi_smi_msg, link);
+		list_for_each_entry_safe(smi_msg, smi_msg2, &(intf->waiting_msgs), link) {
 			if (! handle_new_recv_msg(intf, smi_msg)) {
-				list_del(entry);
+				list_del(&smi_msg->link);
 				ipmi_free_smi_msg(smi_msg);
 			} else {
 				/* To preserve message order, quit if we
@@ -1706,6 +2634,15 @@ ipmi_timeout_handler(long timeout_period
 				ent->inuse = 0;
 				msg = ent->recv_msg;
 				list_add_tail(&(msg->link), &timeouts);
+				spin_lock(&intf->counter_lock);
+				if (ent->broadcast)
+					intf->timed_out_ipmb_broadcasts++;
+				else if (ent->recv_msg->addr.addr_type
+					 == IPMI_LAN_ADDR_TYPE)
+					intf->timed_out_lan_commands++;
+				else
+					intf->timed_out_ipmb_commands++;
+				spin_unlock(&intf->counter_lock);
 			} else {
 				/* More retries, send again. */
 
@@ -1715,12 +2652,18 @@ ipmi_timeout_handler(long timeout_period
 				ent->retries_left--;
 				send_from_recv_msg(intf, ent->recv_msg, NULL,
 						   j, ent->seqid);
+				spin_lock(&intf->counter_lock);
+				if (ent->recv_msg->addr.addr_type
+				    == IPMI_LAN_ADDR_TYPE)
+					intf->retransmitted_lan_commands++;
+				else
+					intf->retransmitted_ipmb_commands++;
+				spin_unlock(&intf->counter_lock);
 			}
 		}
 		spin_unlock_irqrestore(&(intf->seq_lock), flags);
 
-		list_for_each_safe(entry, entry2, &timeouts) {
-			msg = list_entry(entry, struct ipmi_recv_msg, link);
+		list_for_each_entry_safe(msg, msg2, &timeouts, link) {
 			handle_msg_timeout(msg);
 		}
 
@@ -1747,13 +2690,16 @@ static void ipmi_request_event(void)
 
 static struct timer_list ipmi_timer;
 
-/* Call every 100 ms. */
+/* Call every ~100 ms. */
 #define IPMI_TIMEOUT_TIME	100
-#define IPMI_TIMEOUT_JIFFIES	((IPMI_TIMEOUT_TIME * HZ)/1000)
 
-/* Request events from the queue every second.  Hopefully, in the
-   future, IPMI will add a way to know immediately if an event is
-   in the queue. */
+/* How many jiffies does it take to get to the timeout time. */
+#define IPMI_TIMEOUT_JIFFIES	((IPMI_TIMEOUT_TIME * HZ) / 1000)
+
+/* Request events from the queue every second (this is the number of
+   IPMI_TIMEOUT_TIMES between event requests).  Hopefully, in the
+   future, IPMI will add a way to know immediately if an event is in
+   the queue and this silliness can go away. */
 #define IPMI_REQUEST_EV_TIME	(1000 / (IPMI_TIMEOUT_TIME))
 
 static volatile int stop_operation = 0;
@@ -1796,6 +2742,7 @@ struct ipmi_smi_msg *ipmi_alloc_smi_msg(
 	rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
 	if (rv) {
 		rv->done = free_smi_msg;
+		rv->user_data = NULL;
 		atomic_inc(&smi_msg_inuse_count);
 	}
 	return rv;
@@ -1907,11 +2854,13 @@ static void send_panic_events(char *str)
 			       &addr,
 			       0,
 			       &msg,
+			       NULL,
 			       &smi_msg,
 			       &recv_msg,
 			       0,
 			       intf->my_address,
-			       intf->my_lun);
+			       intf->my_lun,
+			       0, 1); /* Don't retry, and don't wait. */
 	}
 
 #ifdef CONFIG_IPMI_PANIC_STRING
@@ -1951,11 +2900,13 @@ static void send_panic_events(char *str)
 			       &addr,
 			       0,
 			       &msg,
+			       NULL,
 			       &smi_msg,
 			       &recv_msg,
 			       0,
 			       intf->my_address,
-			       intf->my_lun);
+			       intf->my_lun,
+			       0, 1); /* Don't retry, and don't wait. */
 
 		if (intf->local_event_generator) {
 			/* Request the event receiver from the local MC. */
@@ -1969,11 +2920,13 @@ static void send_panic_events(char *str)
 				       &addr,
 				       0,
 				       &msg,
+				       NULL,
 				       &smi_msg,
 				       &recv_msg,
 				       0,
 				       intf->my_address,
-				       intf->my_lun);
+				       intf->my_lun,
+				       0, 1); /* no retry, and no wait. */
 		}
 		intf->null_user_handler = NULL;
 
@@ -2029,11 +2982,13 @@ static void send_panic_events(char *str)
 				       &addr,
 				       0,
 				       &msg,
+				       NULL,
 				       &smi_msg,
 				       &recv_msg,
 				       0,
 				       intf->my_address,
-				       intf->my_lun);
+				       intf->my_lun,
+				       0, 1); /* no retry, and no wait. */
 		}
 	}	
 #endif /* CONFIG_IPMI_PANIC_STRING */
@@ -2075,7 +3030,6 @@ static struct notifier_block panic_block
 	200   /* priority: INT_MAX >= x >= 0 */
 };
 
-
 static __init int ipmi_init_msghandler(void)
 {
 	int i;
@@ -2083,10 +3037,21 @@ static __init int ipmi_init_msghandler(v
 	if (initialized)
 		return 0;
 
+	printk(KERN_INFO "ipmi message handler version "
+	       IPMI_MSGHANDLER_VERSION "\n");
+
 	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
 		ipmi_interfaces[i] = NULL;
 	}
 
+	proc_ipmi_root = proc_mkdir("ipmi", 0);
+	if (!proc_ipmi_root) {
+	    printk("Unable to create IPMI proc dir");
+	    return -ENOMEM;
+	}
+
+	proc_ipmi_root->owner = THIS_MODULE;
+
 	init_timer(&ipmi_timer);
 	ipmi_timer.data = 0;
 	ipmi_timer.function = ipmi_timeout;
@@ -2097,8 +3062,6 @@ static __init int ipmi_init_msghandler(v
 
 	initialized = 1;
 
-	printk(KERN_INFO "ipmi: message handler initialized\n");
-
 	return 0;
 }
 
@@ -2118,9 +3081,12 @@ static __exit void cleanup_ipmi(void)
 	   problems with race conditions removing the timer here. */
 	stop_operation = 1;
 	while (!timer_stopped) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(1);
 	}
 
+	remove_proc_entry(proc_ipmi_root->name, &proc_root);
+
 	initialized = 0;
 
 	/* Check for buffer leaks. */
@@ -2143,6 +3109,7 @@ EXPORT_SYMBOL(ipmi_create_user);
 EXPORT_SYMBOL(ipmi_destroy_user);
 EXPORT_SYMBOL(ipmi_get_version);
 EXPORT_SYMBOL(ipmi_request);
+EXPORT_SYMBOL(ipmi_request_settime);
 EXPORT_SYMBOL(ipmi_request_supply_msgs);
 EXPORT_SYMBOL(ipmi_request_with_source);
 EXPORT_SYMBOL(ipmi_register_smi);
@@ -2164,3 +3131,4 @@ EXPORT_SYMBOL(ipmi_set_my_address);
 EXPORT_SYMBOL(ipmi_get_my_address);
 EXPORT_SYMBOL(ipmi_set_my_LUN);
 EXPORT_SYMBOL(ipmi_get_my_LUN);
+EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
--- diff/drivers/char/ipmi/ipmi_watchdog.c	2003-09-17 12:28:05.000000000 +0100
+++ source/drivers/char/ipmi/ipmi_watchdog.c	2004-03-09 11:51:49.000000000 +0000
@@ -33,6 +33,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/ipmi.h>
 #include <linux/ipmi_smi.h>
 #include <linux/watchdog.h>
@@ -50,6 +51,8 @@
 #include <asm/apic.h>
 #endif
 
+#define IPMI_WATCHDOG_VERSION "v31"
+
 /*
  * The IPMI command/response information for the watchdog timer.
  */
@@ -137,26 +140,41 @@ static int pretimeout = 0;
 /* Default action is to reset the board on a timeout. */
 static unsigned char action_val = WDOG_TIMEOUT_RESET;
 
-static char *action = "reset";
+static char action[16] = "reset";
 
 static unsigned char preaction_val = WDOG_PRETIMEOUT_NONE;
 
-static char *preaction = "pre_none";
+static char preaction[16] = "pre_none";
 
 static unsigned char preop_val = WDOG_PREOP_NONE;
 
-static char *preop = "preop_none";
+static char preop[16] = "preop_none";
 static spinlock_t ipmi_read_lock = SPIN_LOCK_UNLOCKED;
 static char data_to_read = 0;
 static DECLARE_WAIT_QUEUE_HEAD(read_q);
 static struct fasync_struct *fasync_q = NULL;
 static char pretimeout_since_last_heartbeat = 0;
 
-MODULE_PARM(timeout, "i");
-MODULE_PARM(pretimeout, "i");
-MODULE_PARM(action, "s");
-MODULE_PARM(preaction, "s");
-MODULE_PARM(preop, "s");
+/* If true, the driver will start running as soon as it is configured
+   and ready. */
+static int start_now = 0;
+
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Timeout value in seconds.");
+module_param(pretimeout, int, 0);
+MODULE_PARM_DESC(pretimeout, "Pretimeout value in seconds.");
+module_param_string(action, action, sizeof(action), 0);
+MODULE_PARM_DESC(action, "Timeout action. One of: "
+		 "reset, none, power_cycle, power_off.");
+module_param_string(preaction, preaction, sizeof(preaction), 0);
+MODULE_PARM_DESC(preaction, "Pretimeout action.  One of: "
+		 "pre_none, pre_smi, pre_nmi, pre_int.");
+module_param_string(preop, preop, sizeof(preop), 0);
+MODULE_PARM_DESC(preop, "Pretimeout driver operation.  One of: "
+		 "preop_none, preop_panic, preop_give_data.");
+module_param(start_now, int, 0);
+MODULE_PARM_DESC(start_now, "Set to 1 to start the watchdog as"
+		 "soon as the driver is loaded.");
 
 /* Default state of the timer. */
 static unsigned char ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
@@ -167,10 +185,6 @@ static int ipmi_ignore_heartbeat = 0;
 /* Is someone using the watchdog?  Only one user is allowed. */
 static int ipmi_wdog_open = 0;
 
-/* If true, the driver will start running as soon as it is configured
-   and ready. */
-static int start_now = 0;
-
 /* If set to 1, the heartbeat command will set the state to reset and
    start the timer.  The timer doesn't normally run when the driver is
    first opened until the heartbeat is set the first time, this
@@ -260,6 +274,7 @@ static int i_ipmi_set_timeout(struct ipm
 				      (struct ipmi_addr *) &addr,
 				      0,
 				      &msg,
+				      NULL,
 				      smi_msg,
 				      recv_msg,
 				      1);
@@ -435,6 +450,7 @@ static int ipmi_heartbeat(void)
 				      (struct ipmi_addr *) &addr,
 				      0,
 				      &msg,
+				      NULL,
 				      &heartbeat_smi_msg,
 				      &heartbeat_recv_msg,
 				      1);
@@ -483,6 +499,7 @@ static void panic_halt_ipmi_heartbeat(vo
 				 (struct ipmi_addr *) &addr,
 				 0,
 				 &msg,
+				 NULL,
 				 &panic_halt_heartbeat_smi_msg,
 				 &panic_halt_heartbeat_recv_msg,
 				 1);
@@ -903,6 +920,7 @@ static void ipmi_smi_gone(int if_num)
 
 static struct ipmi_smi_watcher smi_watcher =
 {
+	.owner    = THIS_MODULE,
 	.new_smi  = ipmi_new_smi,
 	.smi_gone = ipmi_smi_gone
 };
@@ -911,6 +929,9 @@ static int __init ipmi_wdog_init(void)
 {
 	int rv;
 
+	printk(KERN_INFO "IPMI watchdog driver version "
+	       IPMI_WATCHDOG_VERSION "\n");
+
 	if (strcmp(action, "reset") == 0) {
 		action_val = WDOG_TIMEOUT_RESET;
 	} else if (strcmp(action, "none") == 0) {
@@ -999,14 +1020,10 @@ static int __init ipmi_wdog_init(void)
 	register_reboot_notifier(&wdog_reboot_notifier);
 	notifier_chain_register(&panic_notifier_list, &wdog_panic_notifier);
 
-	printk(KERN_INFO "IPMI watchdog by "
-	       "Corey Minyard (minyard@mvista.com)\n");
-
 	return 0;
 }
 
-#ifdef MODULE
-static void ipmi_unregister_watchdog(void)
+static __exit void ipmi_unregister_watchdog(void)
 {
 	int rv;
 
@@ -1034,6 +1051,7 @@ static void ipmi_unregister_watchdog(voi
 	   pointers to our buffers, we want to make sure they are done before
 	   we release our memory. */
 	while (atomic_read(&set_timeout_tofree)) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(1);
 	}
 
@@ -1056,76 +1074,6 @@ static void __exit ipmi_wdog_exit(void)
 	ipmi_unregister_watchdog();
 }
 module_exit(ipmi_wdog_exit);
-#else
-static int __init ipmi_wdog_setup(char *str)
-{
-	int  val;
-	int  rv;
-	char *option;
-
-	rv = get_option(&str, &val);
-	if (rv == 0)
-		return 1;
-	if (val > 0)
-		timeout = val;
-	if (rv == 1)
-		return 1;
-
-	rv = get_option(&str, &val);
-	if (rv == 0)
-		return 1;
-	if (val >= 0)
-		pretimeout = val;
-	if (rv == 1)
-		return 1;
-
-	while ((option = strsep(&str, ",")) != NULL) {
-		if (strcmp(option, "reset") == 0) {
-			action = "reset";
-		}
-		else if (strcmp(option, "none") == 0) {
-			action = "none";
-		}
-		else if (strcmp(option, "power_cycle") == 0) {
-			action = "power_cycle";
-		}
-		else if (strcmp(option, "power_off") == 0) {
-			action = "power_off";
-		}
-		else if (strcmp(option, "pre_none") == 0) {
-			preaction = "pre_none";
-		}
-		else if (strcmp(option, "pre_smi") == 0) {
-			preaction = "pre_smi";
-		}
-#ifdef HAVE_NMI_HANDLER
-		else if (strcmp(option, "pre_nmi") == 0) {
-			preaction = "pre_nmi";
-		}
-#endif
-		else if (strcmp(option, "pre_int") == 0) {
-			preaction = "pre_int";
-		}
-		else if (strcmp(option, "start_now") == 0) {
-			start_now = 1;
-		}
-		else if (strcmp(option, "preop_none") == 0) {
-			preop = "preop_none";
-		}
-		else if (strcmp(option, "preop_panic") == 0) {
-			preop = "preop_panic";
-		}
-		else if (strcmp(option, "preop_give_data") == 0) {
-			preop = "preop_give_data";
-		} else {
-		    printk("Unknown IPMI watchdog option: '%s'\n", option);
-		}
-	}
-
-	return 1;
-}
-__setup("ipmi_wdog=", ipmi_wdog_setup);
-#endif
 
 EXPORT_SYMBOL(ipmi_delayed_shutdown);
 
--- diff/drivers/char/keyboard.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/keyboard.c	2004-03-09 11:51:49.000000000 +0000
@@ -1066,6 +1066,9 @@ void kbd_keycode(unsigned int keycode, i
 	}
 	if (sysrq_down && down && !rep) {
 		handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty);
+#ifdef CONFIG_KGDB_SYSRQ
+                sysrq_down = 0;        /* in case we miss the "up" event */
+#endif
 		return;
 	}
 #endif
--- diff/drivers/char/mem.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/char/mem.c	2004-03-09 11:51:49.000000000 +0000
@@ -39,6 +39,7 @@ extern void fbmem_init(void);
 extern void tapechar_init(void);
 #endif
 
+#ifdef pgprot_noncached
 /*
  * Architectures vary in how they handle caching for addresses
  * outside of main memory.
@@ -64,7 +65,8 @@ static inline int uncached_access(struct
 	  && addr >= __pa(high_memory);
 #elif defined(CONFIG_IA64)
 	/*
-	 * On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases.
+	 * On ia64, we ignore O_SYNC because we cannot tolerate memory
+	 * attribute aliases.
 	 */
 	return !(efi_mem_attributes(addr) & EFI_MEMORY_WB);
 #elif defined(CONFIG_PPC64)
@@ -77,14 +79,15 @@ static inline int uncached_access(struct
 	return !page_is_ram(addr);
 #else
 	/*
-	 * Accessing memory above the top the kernel knows about or through a file pointer
-	 * that was marked O_SYNC will be done non-cached.
+	 * Accessing memory above the top the kernel knows about or through a
+	 * file pointer that was marked O_SYNC will be done non-cached.
 	 */
 	if (file->f_flags & O_SYNC)
 		return 1;
 	return addr >= __pa(high_memory);
 #endif
 }
+#endif
 
 #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE
 static inline int valid_phys_addr_range(unsigned long addr, size_t *count)
@@ -174,28 +177,24 @@ static ssize_t write_mem(struct file * f
 	return do_write_mem(file, __va(p), p, buf, count, ppos);
 }
 
-static int mmap_mem(struct file * file, struct vm_area_struct * vma)
+static int mmap_mem(struct file *file, struct vm_area_struct *vma)
 {
 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-	int uncached;
 
-	uncached = uncached_access(file, offset);
 #ifdef pgprot_noncached
-	if (uncached)
+	if (uncached_access(file, offset))
 		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 #endif
 
-	/* Don't try to swap out physical pages.. */
-	vma->vm_flags |= VM_RESERVED;
-
 	/*
-	 * Don't dump addresses that are not real memory to a core file.
+	 * Don't try to swap out physical pages..
+	 * And treat /dev/mem mappings as "IO" regions: they may not
+	 * describe valid pageframes.
 	 */
-	if (uncached)
-		vma->vm_flags |= VM_IO;
+	vma->vm_flags |= VM_RESERVED|VM_IO;
 
-	if (remap_page_range(vma, vma->vm_start, offset, vma->vm_end-vma->vm_start,
-			     vma->vm_page_prot))
+	if (remap_page_range(vma, vma->vm_start, offset,
+			vma->vm_end-vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
 	return 0;
 }
--- diff/drivers/char/rio/rioctrl.c	2003-05-21 11:49:55.000000000 +0100
+++ source/drivers/char/rio/rioctrl.c	2004-03-09 11:51:49.000000000 +0000
@@ -522,7 +522,7 @@ RIO_DEBUG_CTRL, 				if (su)
 					else {
 		 				rio_dprintk (RIO_DEBUG_CTRL, "p->RIOBindTab full! - Rta %x not added\n",
 		  					(int) arg);
-		 				return 1;
+		 				return -ENOMEM;
 					}
 					return 0;
 				}
@@ -1593,12 +1593,12 @@ RIO_DEBUG_CTRL, 				if (su)
 			case RIO_NO_MESG:
 				if ( su )
 					 p->RIONoMessage = 1;
-				return su ? 0 : EPERM;
+				return su ? 0 : -EPERM;
 
 			case RIO_MESG:
 				if ( su )
 					p->RIONoMessage = 0;
-				return su ? 0 : EPERM;
+				return su ? 0 : -EPERM;
 
 			case RIO_WHAT_MESG:
 				if ( copyout( (caddr_t)&p->RIONoMessage, (int)arg, 
--- diff/drivers/char/sysrq.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/char/sysrq.c	2004-03-09 11:51:49.000000000 +0000
@@ -35,6 +35,25 @@
 #include <linux/spinlock.h>
 
 #include <asm/ptrace.h>
+#ifdef CONFIG_KGDB_SYSRQ
+
+#define  GDB_OP &kgdb_op
+static void kgdb_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
+{
+	printk("kgdb sysrq\n");
+	breakpoint();
+}
+
+static struct sysrq_key_op kgdb_op = {
+	.handler	= kgdb_sysrq,
+	.help_msg	= "kGdb|Fgdb",
+	.action_msg	= "Debug breakpoint\n",
+};
+
+#else
+#define  GDB_OP NULL
+#endif
+
 
 extern void reset_vc(unsigned int);
 
@@ -238,8 +257,8 @@ static struct sysrq_key_op *sysrq_key_ta
 /* c */ NULL,
 /* d */	NULL,
 /* e */	&sysrq_term_op,
-/* f */	NULL,
-/* g */	NULL,
+/* f */	GDB_OP,
+/* g */	GDB_OP,
 /* h */	NULL,
 /* i */	&sysrq_kill_op,
 /* j */	NULL,
--- diff/drivers/char/watchdog/amd7xx_tco.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/watchdog/amd7xx_tco.c	2004-03-09 11:51:49.000000000 +0000
@@ -365,25 +365,6 @@ static void __exit amdtco_exit(void)
 	unregister_reboot_notifier(&amdtco_notifier);
 }
 
-
-#ifndef MODULE
-static int __init amdtco_setup(char *str)
-{
-	int ints[4];
-
-	str = get_options (str, ARRAY_SIZE(ints), ints);
-	if (ints[0] > 0)
-		timeout = ints[1];
-
-	if (!timeout || timeout > MAX_TIMEOUT)
-		timeout = MAX_TIMEOUT;
-
-	return 1;
-}
-
-__setup("amd7xx_tco=", amdtco_setup);
-#endif
-
 module_init(amdtco_init);
 module_exit(amdtco_exit);
 
--- diff/drivers/char/watchdog/cpu5wdt.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/char/watchdog/cpu5wdt.c	2004-03-09 11:51:49.000000000 +0000
@@ -20,6 +20,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/miscdevice.h>
@@ -295,11 +296,11 @@ MODULE_SUPPORTED_DEVICE("sma cpu5 watchd
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 
-MODULE_PARM(port, "i");
+module_param(port, int, 0);
 MODULE_PARM_DESC(port, "base address of watchdog card, default is 0x91");
 
-MODULE_PARM(verbose, "i");
+module_param(verbose, int, 0);
 MODULE_PARM_DESC(verbose, "be verbose, default is 0 (no)");
 
-MODULE_PARM(ticks, "i");
+module_param(ticks, int, 0);
 MODULE_PARM_DESC(ticks, "count down ticks, default is 10000");
--- diff/drivers/char/watchdog/eurotechwdt.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/char/watchdog/eurotechwdt.c	2004-03-09 11:51:49.000000000 +0000
@@ -43,6 +43,7 @@
 #include <linux/config.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
@@ -77,7 +78,7 @@ static int nowayout = 1;
 static int nowayout = 0;
 #endif
 
-MODULE_PARM(nowayout,"i");
+module_param(nowayout, int, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
 /*
@@ -94,41 +95,11 @@ MODULE_PARM_DESC(nowayout, "Watchdog can
 #define WDT_TIMER_CFG		0xf3
 
 
-#ifndef MODULE
-
-/**
- * eurwdt_setup:
- * @str: command line string
- *
- * Setup options. The board isn't really probe-able so we have to
- * get the user to tell us the configuration. Sane people build it
- * modular but the others come here.
- */
-
-static int __init eurwdt_setup(char *str)
-{
-	int ints[4];
-
-str = get_options (str, ARRAY_SIZE(ints), ints);
-
-	if (ints[0] > 0) {
-		io = ints[1];
-		if (ints[0] > 1)
-			irq = ints[2];
-	}
-
-	return 1;
-}
-
-__setup("eurwdt=", eurwdt_setup);
-
-#endif /* !MODULE */
-
-MODULE_PARM(io, "i");
+module_param(io, int, 0);
 MODULE_PARM_DESC(io, "Eurotech WDT io port (default=0x3f0)");
-MODULE_PARM(irq, "i");
+module_param(irq, int, 0);
 MODULE_PARM_DESC(irq, "Eurotech WDT irq (default=10)");
-MODULE_PARM(ev, "s");
+module_param(ev, charp, 0);
 MODULE_PARM_DESC(ev, "Eurotech WDT event type (default is `int')");
 
 
--- diff/drivers/char/watchdog/sc1200wdt.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/char/watchdog/sc1200wdt.c	2004-03-09 11:51:49.000000000 +0000
@@ -29,6 +29,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/ioport.h>
@@ -80,13 +81,13 @@ spinlock_t sc1200wdt_lock;	/* io port ac
 static int isapnp = 1;
 static struct pnp_dev *wdt_dev;
 
-MODULE_PARM(isapnp, "i");
+module_param(isapnp, int, 0);
 MODULE_PARM_DESC(isapnp, "When set to 0 driver ISA PnP support will be disabled");
 #endif
 
-MODULE_PARM(io, "i");
+module_param(io, int, 0);
 MODULE_PARM_DESC(io, "io port");
-MODULE_PARM(timeout, "i");
+module_param(timeout, int, 0);
 MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1");
 
 #ifdef CONFIG_WATCHDOG_NOWAYOUT
@@ -95,7 +96,7 @@ static int nowayout = 1;
 static int nowayout = 0;
 #endif
 
-MODULE_PARM(nowayout,"i");
+module_param(nowayout, int, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
 
@@ -454,32 +455,6 @@ static void __exit sc1200wdt_exit(void)
 	release_region(io, io_len);
 }
 
-
-#ifndef MODULE
-static int __init sc1200wdt_setup(char *str)
-{
-	int ints[4];
-
-	str = get_options (str, ARRAY_SIZE(ints), ints);
-
-	if (ints[0] > 0) {
-		io = ints[1];
-		if (ints[0] > 1)
-			timeout = ints[2];
-
-#if defined CONFIG_PNP
-		if (ints[0] > 2)
-			isapnp = ints[3];
-#endif
-	}
-
-	return 1;
-}
-
-__setup("sc1200wdt=", sc1200wdt_setup);
-#endif /* MODULE */
-
-
 module_init(sc1200wdt_init);
 module_exit(sc1200wdt_exit);
 
--- diff/drivers/char/watchdog/wdt.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/char/watchdog/wdt.c	2004-03-09 11:51:49.000000000 +0000
@@ -34,6 +34,7 @@
 #include <linux/config.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
@@ -70,43 +71,12 @@ static int nowayout = 1;
 static int nowayout = 0;
 #endif
 
-MODULE_PARM(nowayout,"i");
+module_param(nowayout, int, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
-#ifndef MODULE
-
-/**
- *	wdt_setup:
- *	@str: command line string
- *
- *	Setup options. The board isn't really probe-able so we have to
- *	get the user to tell us the configuration. Sane people build it
- *	modular but the others come here.
- */
-
-static int __init wdt_setup(char *str)
-{
-	int ints[4];
-
-	str = get_options (str, ARRAY_SIZE(ints), ints);
-
-	if (ints[0] > 0)
-	{
-		io = ints[1];
-		if(ints[0] > 1)
-			irq = ints[2];
-	}
-
-	return 1;
-}
-
-__setup("wdt=", wdt_setup);
-
-#endif /* !MODULE */
-
-MODULE_PARM(io, "i");
+module_param(io, int, 0);
 MODULE_PARM_DESC(io, "WDT io port (default=0x240)");
-MODULE_PARM(irq, "i");
+module_param(irq, int, 0);
 MODULE_PARM_DESC(irq, "WDT irq (default=11)");
 
 /*
--- diff/drivers/eisa/eisa-bus.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/eisa/eisa-bus.c	2004-03-09 11:51:49.000000000 +0000
@@ -187,6 +187,7 @@ static int __init eisa_init_device (stru
 	edev->dev.parent = root->dev;
 	edev->dev.bus = &eisa_bus_type;
 	edev->dev.dma_mask = &edev->dma_mask;
+	edev->dev.coherent_dma_mask = edev->dma_mask;
 	sprintf (edev->dev.bus_id, "%02X:%02X", root->bus_nr, slot);
 
 	for (i = 0; i < EISA_MAX_RESOURCES; i++) {
--- diff/drivers/i2c/busses/i2c-elv.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/i2c/busses/i2c-elv.c	2004-03-09 11:51:49.000000000 +0000
@@ -152,7 +152,7 @@ static int __init i2c_bitelv_init(void)
 			return -ENODEV;
 		}
 	}
-	pr_debug("i2c-elv: found device at %#x.\n",base);
+	pr_debug("i2c-elv: found device at %#lx.\n",base);
 	return 0;
 }
 
--- diff/drivers/i2c/busses/i2c-velleman.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/i2c/busses/i2c-velleman.c	2004-03-09 11:51:49.000000000 +0000
@@ -138,7 +138,7 @@ static int __init i2c_bitvelle_init(void
 			return -ENODEV;
 		}
 	}
-	pr_debug("i2c-velleman: found device at %#x.\n",base);
+	pr_debug("i2c-velleman: found device at %#lx.\n",base);
 	return 0;
 }
 
--- diff/drivers/ide/Kconfig	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/ide/Kconfig	2004-03-09 11:51:49.000000000 +0000
@@ -559,6 +559,16 @@ config BLK_DEV_AMD74XX
 	  change PIO, DMA and UDMA speeds and to configure the chip to
 	  optimum performance.
 
+config BLK_DEV_ATIIXP
+	tristate "ATI IXP chipset IDE support"
+	depends on X86
+	help
+	  This driver adds explicit support for ATI IXP chipset.
+	  This allows the kernel to change PIO, DMA and UDMA speeds
+	  and to configure the chip to optimum performance.
+
+	  Say Y here if you have an ATI IXP chipset IDE controller.
+
 config BLK_DEV_CMD64X
 	tristate "CMD64{3|6|8|9} chipset support"
 	help
--- diff/drivers/ide/ide-cd.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/ide/ide-cd.c	2004-03-09 11:51:49.000000000 +0000
@@ -554,53 +554,6 @@ static void cdrom_queue_request_sense(id
 	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
-
-/*
- * Error reporting, in human readable form (luxurious, but a memory hog).
- */
-byte ide_cdrom_dump_status (ide_drive_t *drive, const char *msg, byte stat)
-{
-	unsigned long flags;
-
-	atapi_status_t status;
-	atapi_error_t error;
-
-	status.all = stat;
-	local_irq_set(flags);
-	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
-#if FANCY_STATUS_DUMPS
-	printk(" { ");
-	if (status.b.bsy)
-		printk("Busy ");
-	else {
-		if (status.b.drdy)	printk("DriveReady ");
-		if (status.b.df)	printk("DeviceFault ");
-		if (status.b.dsc)	printk("SeekComplete ");
-		if (status.b.drq)	printk("DataRequest ");
-		if (status.b.corr)	printk("CorrectedError ");
-		if (status.b.idx)	printk("Index ");
-		if (status.b.check)	printk("Error ");
-	}
-	printk("}");
-#endif	/* FANCY_STATUS_DUMPS */
-	printk("\n");
-	if ((status.all & (status.b.bsy|status.b.check)) == status.b.check) {
-		error.all = HWIF(drive)->INB(IDE_ERROR_REG);
-		printk("%s: %s: error=0x%02x", drive->name, msg, error.all);
-#if FANCY_STATUS_DUMPS
-		if (error.b.ili)	printk("IllegalLengthIndication ");
-		if (error.b.eom)	printk("EndOfMedia ");
-		if (error.b.abrt)	printk("Aborted Command ");
-		if (error.b.mcr)	printk("MediaChangeRequested ");
-		if (error.b.sense_key)	printk("LastFailedSense 0x%02x ",
-						error.b.sense_key);
-#endif	/* FANCY_STATUS_DUMPS */
-		printk("\n");
-	}
-	local_irq_restore(flags);
-	return error.all;
-}
-
 /*
  * ide_error() takes action based on the error returned by the drive.
  */
@@ -609,7 +562,7 @@ ide_startstop_t ide_cdrom_error (ide_dri
 	struct request *rq;
 	byte err;
 
-	err = ide_cdrom_dump_status(drive, msg, stat);
+	err = ide_dump_atapi_status(drive, msg, stat);
 	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
 		return ide_stopped;
 	/* retry only "normal" I/O: */
@@ -2931,6 +2884,7 @@ static int ide_cdrom_register (ide_drive
 	if (!CDROM_CONFIG_FLAGS(drive)->mrw_w)
 		devinfo->mask |= CDC_MRW_W;
 
+	devinfo->disk = drive->disk;
 	return register_cdrom(devinfo);
 }
 
@@ -3411,7 +3365,7 @@ static ide_driver_t ide_cdrom_driver = {
 	.supports_dsc_overlap	= 1,
 	.cleanup		= ide_cdrom_cleanup,
 	.do_request		= ide_do_rw_cdrom,
-	.sense			= ide_cdrom_dump_status,
+	.sense			= ide_dump_atapi_status,
 	.error			= ide_cdrom_error,
 	.abort			= ide_cdrom_abort,
 	.capacity		= ide_cdrom_capacity,
--- diff/drivers/ide/ide-disk.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/ide/ide-disk.c	2004-03-09 11:51:49.000000000 +0000
@@ -569,28 +569,37 @@ ide_startstop_t __ide_do_rw_disk (ide_dr
 }
 EXPORT_SYMBOL_GPL(__ide_do_rw_disk);
 
-static task_ioreg_t get_command (ide_drive_t *drive, int cmd)
+static u8 get_command(ide_drive_t *drive, int cmd, ide_task_t *task)
 {
-	int lba48bit = (drive->addressing == 1) ? 1 : 0;
+	unsigned int lba48 = (drive->addressing == 1) ? 1 : 0;
 
-	if ((cmd == READ) && drive->using_tcq)
-		return lba48bit ? WIN_READDMA_QUEUED_EXT : WIN_READDMA_QUEUED;
-	if ((cmd == READ) && (drive->using_dma))
-		return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA;
-	else if ((cmd == READ) && (drive->mult_count))
-		return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD;
-	else if (cmd == READ)
-		return (lba48bit) ? WIN_READ_EXT : WIN_READ;
-	else if ((cmd == WRITE) && drive->using_tcq)
-		return lba48bit ? WIN_WRITEDMA_QUEUED_EXT : WIN_WRITEDMA_QUEUED;
-	else if ((cmd == WRITE) && (drive->using_dma))
-		return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
-	else if ((cmd == WRITE) && (drive->mult_count))
-		return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
-	else if (cmd == WRITE)
-		return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE;
-	else
-		return WIN_NOP;
+	if (cmd == READ) {
+		task->command_type = IDE_DRIVE_TASK_IN;
+		if (drive->using_tcq)
+			return lba48 ? WIN_READDMA_QUEUED_EXT : WIN_READDMA_QUEUED;
+		if (drive->using_dma)
+			return lba48 ? WIN_READDMA_EXT : WIN_READDMA;
+		if (drive->mult_count) {
+			task->handler = &task_mulin_intr;
+			return lba48 ? WIN_MULTREAD_EXT : WIN_MULTREAD;
+		}
+		task->handler = &task_in_intr;
+		return lba48 ? WIN_READ_EXT : WIN_READ;
+	} else {
+		task->command_type = IDE_DRIVE_TASK_RAW_WRITE;
+		if (drive->using_tcq)
+			return lba48 ? WIN_WRITEDMA_QUEUED_EXT : WIN_WRITEDMA_QUEUED;
+		if (drive->using_dma)
+			return lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+		if (drive->mult_count) {
+			task->prehandler = &pre_task_mulout_intr;
+			task->handler = &task_mulout_intr;
+			return lba48 ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
+		}
+		task->prehandler = &pre_task_out_intr;
+		task->handler = &task_out_intr;
+		return lba48 ? WIN_WRITE_EXT : WIN_WRITE;
+	}
 }
 
 static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
@@ -598,7 +607,6 @@ static ide_startstop_t chs_rw_disk (ide_
 	ide_task_t		args;
 	int			sectors;
 	ata_nsector_t		nsectors;
-	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
 	unsigned int track	= (block / drive->sect);
 	unsigned int sect	= (block % drive->sect) + 1;
 	unsigned int head	= (track % drive->head);
@@ -628,8 +636,7 @@ static ide_startstop_t chs_rw_disk (ide_
 	args.tfRegister[IDE_HCYL_OFFSET]	= (cyl>>8);
 	args.tfRegister[IDE_SELECT_OFFSET]	= head;
 	args.tfRegister[IDE_SELECT_OFFSET]	|= drive->select.all;
-	args.tfRegister[IDE_COMMAND_OFFSET]	= command;
-	args.command_type			= ide_cmd_type_parser(&args);
+	args.tfRegister[IDE_COMMAND_OFFSET]	= get_command(drive, rq_data_dir(rq), &args);
 	args.rq					= (struct request *) rq;
 	rq->special				= (ide_task_t *)&args;
 	return do_rw_taskfile(drive, &args);
@@ -640,7 +647,6 @@ static ide_startstop_t lba_28_rw_disk (i
 	ide_task_t		args;
 	int			sectors;
 	ata_nsector_t		nsectors;
-	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
 
 	nsectors.all = (u16) rq->nr_sectors;
 
@@ -666,8 +672,7 @@ static ide_startstop_t lba_28_rw_disk (i
 	args.tfRegister[IDE_HCYL_OFFSET]	= (block>>=8);
 	args.tfRegister[IDE_SELECT_OFFSET]	= ((block>>8)&0x0f);
 	args.tfRegister[IDE_SELECT_OFFSET]	|= drive->select.all;
-	args.tfRegister[IDE_COMMAND_OFFSET]	= command;
-	args.command_type			= ide_cmd_type_parser(&args);
+	args.tfRegister[IDE_COMMAND_OFFSET]	= get_command(drive, rq_data_dir(rq), &args);
 	args.rq					= (struct request *) rq;
 	rq->special				= (ide_task_t *)&args;
 	return do_rw_taskfile(drive, &args);
@@ -684,7 +689,6 @@ static ide_startstop_t lba_48_rw_disk (i
 	ide_task_t		args;
 	int			sectors;
 	ata_nsector_t		nsectors;
-	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
 
 	nsectors.all = (u16) rq->nr_sectors;
 
@@ -702,24 +706,23 @@ static ide_startstop_t lba_48_rw_disk (i
 	if (blk_rq_tagged(rq)) {
 		args.tfRegister[IDE_FEATURE_OFFSET] = sectors;
 		args.tfRegister[IDE_NSECTOR_OFFSET] = rq->tag << 3;
-		args.hobRegister[IDE_FEATURE_OFFSET_HOB] = sectors >> 8;
-		args.hobRegister[IDE_NSECTOR_OFFSET_HOB] = 0;
+		args.hobRegister[IDE_FEATURE_OFFSET] = sectors >> 8;
+		args.hobRegister[IDE_NSECTOR_OFFSET] = 0;
 	} else {
 		args.tfRegister[IDE_NSECTOR_OFFSET] = sectors;
-		args.hobRegister[IDE_NSECTOR_OFFSET_HOB] = sectors >> 8;
+		args.hobRegister[IDE_NSECTOR_OFFSET] = sectors >> 8;
 	}
 
 	args.tfRegister[IDE_SECTOR_OFFSET]	= block;	/* low lba */
 	args.tfRegister[IDE_LCYL_OFFSET]	= (block>>=8);	/* mid lba */
 	args.tfRegister[IDE_HCYL_OFFSET]	= (block>>=8);	/* hi  lba */
 	args.tfRegister[IDE_SELECT_OFFSET]	= drive->select.all;
-	args.tfRegister[IDE_COMMAND_OFFSET]	= command;
-	args.hobRegister[IDE_SECTOR_OFFSET_HOB]	= (block>>=8);	/* low lba */
-	args.hobRegister[IDE_LCYL_OFFSET_HOB]	= (block>>=8);	/* mid lba */
-	args.hobRegister[IDE_HCYL_OFFSET_HOB]	= (block>>=8);	/* hi  lba */
-	args.hobRegister[IDE_SELECT_OFFSET_HOB]	= drive->select.all;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= get_command(drive, rq_data_dir(rq), &args);
+	args.hobRegister[IDE_SECTOR_OFFSET]	= (block>>=8);	/* low lba */
+	args.hobRegister[IDE_LCYL_OFFSET]	= (block>>=8);	/* mid lba */
+	args.hobRegister[IDE_HCYL_OFFSET]	= (block>>=8);	/* hi  lba */
+	args.hobRegister[IDE_SELECT_OFFSET]	= drive->select.all;
 	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
-	args.command_type			= ide_cmd_type_parser(&args);
 	args.rq					= (struct request *) rq;
 	rq->special				= (ide_task_t *)&args;
 	return do_rw_taskfile(drive, &args);
@@ -927,7 +930,8 @@ static unsigned long idedisk_read_native
 	memset(&args, 0, sizeof(ide_task_t));
 	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX;
-	args.command_type			= ide_cmd_type_parser(&args);
+	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
+	args.handler				= &task_no_data_intr;
 	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 
@@ -952,15 +956,16 @@ static unsigned long long idedisk_read_n
 
 	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX_EXT;
-	args.command_type			= ide_cmd_type_parser(&args);
+	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
+	args.handler				= &task_no_data_intr;
         /* submit command request */
         ide_raw_taskfile(drive, &args, NULL);
 
 	/* if OK, compute maximum address value */
 	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
-		u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
-			   ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
-  			    (args.hobRegister[IDE_SECTOR_OFFSET_HOB]); 
+		u32 high = (args.hobRegister[IDE_HCYL_OFFSET] << 16) |
+			   (args.hobRegister[IDE_LCYL_OFFSET] <<  8) |
+			    args.hobRegister[IDE_SECTOR_OFFSET];
 		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
 			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
 			    (args.tfRegister[IDE_SECTOR_OFFSET]);
@@ -988,7 +993,8 @@ static unsigned long idedisk_set_max_add
 	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >> 16) & 0xff);
 	args.tfRegister[IDE_SELECT_OFFSET]	= ((addr_req >> 24) & 0x0f) | 0x40;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX;
-	args.command_type			= ide_cmd_type_parser(&args);
+	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
+	args.handler				= &task_no_data_intr;
 	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 	/* if OK, read new maximum address value */
@@ -1015,19 +1021,20 @@ static unsigned long long idedisk_set_ma
 	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);
 	args.tfRegister[IDE_SELECT_OFFSET]      = 0x40;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX_EXT;
-	args.hobRegister[IDE_SECTOR_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
-	args.hobRegister[IDE_LCYL_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
-	args.hobRegister[IDE_HCYL_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
-	args.hobRegister[IDE_SELECT_OFFSET_HOB]	= 0x40;
+	args.hobRegister[IDE_SECTOR_OFFSET]	= (addr_req >>= 8) & 0xff;
+	args.hobRegister[IDE_LCYL_OFFSET]	= (addr_req >>= 8) & 0xff;
+	args.hobRegister[IDE_HCYL_OFFSET]	= (addr_req >>= 8) & 0xff;
+	args.hobRegister[IDE_SELECT_OFFSET]	= 0x40;
 	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
-	args.command_type			= ide_cmd_type_parser(&args);
+	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
+	args.handler				= &task_no_data_intr;
 	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 	/* if OK, compute maximum address value */
 	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
-		u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
-			   ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
-			    (args.hobRegister[IDE_SECTOR_OFFSET_HOB]);
+		u32 high = (args.hobRegister[IDE_HCYL_OFFSET] << 16) |
+			   (args.hobRegister[IDE_LCYL_OFFSET] <<  8) |
+			    args.hobRegister[IDE_SECTOR_OFFSET];
 		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
 			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
 			    (args.tfRegister[IDE_SECTOR_OFFSET]);
@@ -1158,7 +1165,8 @@ static ide_startstop_t idedisk_special (
 			args.tfRegister[IDE_HCYL_OFFSET]    = drive->cyl>>8;
 			args.tfRegister[IDE_SELECT_OFFSET]  = ((drive->head-1)|drive->select.all)&0xBF;
 			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY;
-			args.command_type = ide_cmd_type_parser(&args);
+			args.command_type = IDE_DRIVE_TASK_NO_DATA;
+			args.handler	  = &set_geometry_intr;
 			do_rw_taskfile(drive, &args);
 		}
 	} else if (s->b.recalibrate) {
@@ -1168,7 +1176,8 @@ static ide_startstop_t idedisk_special (
 			memset(&args, 0, sizeof(ide_task_t));
 			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
 			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE;
-			args.command_type = ide_cmd_type_parser(&args);
+			args.command_type = IDE_DRIVE_TASK_NO_DATA;
+			args.handler	  = &recal_intr;
 			do_rw_taskfile(drive, &args);
 		}
 	} else if (s->b.set_multmode) {
@@ -1180,7 +1189,8 @@ static ide_startstop_t idedisk_special (
 			memset(&args, 0, sizeof(ide_task_t));
 			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req;
 			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT;
-			args.command_type = ide_cmd_type_parser(&args);
+			args.command_type = IDE_DRIVE_TASK_NO_DATA;
+			args.handler	  = &set_multmode_intr;
 			do_rw_taskfile(drive, &args);
 		}
 	} else if (s->all) {
@@ -1218,7 +1228,8 @@ static int smart_enable(ide_drive_t *dri
 	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
 	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
-	args.command_type			= ide_cmd_type_parser(&args);
+	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
+	args.handler				= &task_no_data_intr;
 	return ide_raw_taskfile(drive, &args, NULL);
 }
 
@@ -1232,7 +1243,8 @@ static int get_smart_values(ide_drive_t 
 	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
 	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
-	args.command_type			= ide_cmd_type_parser(&args);
+	args.command_type			= IDE_DRIVE_TASK_IN;
+	args.handler				= &task_in_intr;
 	(void) smart_enable(drive);
 	return ide_raw_taskfile(drive, &args, buf);
 }
@@ -1246,7 +1258,8 @@ static int get_smart_thresholds(ide_driv
 	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
 	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
-	args.command_type			= ide_cmd_type_parser(&args);
+	args.command_type			= IDE_DRIVE_TASK_IN;
+	args.handler				= &task_in_intr;
 	(void) smart_enable(drive);
 	return ide_raw_taskfile(drive, &args, buf);
 }
@@ -1356,7 +1369,8 @@ static int write_cache (ide_drive_t *dri
 	args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ?
 			SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
-	args.command_type			= ide_cmd_type_parser(&args);
+	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
+	args.handler				= &task_no_data_intr;
 	(void) ide_raw_taskfile(drive, &args, NULL);
 
 	drive->wcache = arg;
@@ -1372,7 +1386,8 @@ static int do_idedisk_flushcache (ide_dr
 		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE_EXT;
 	else
 		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE;
-	args.command_type	 		= ide_cmd_type_parser(&args);
+	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
+	args.handler				= &task_no_data_intr;
 	return ide_raw_taskfile(drive, &args, NULL);
 }
 
@@ -1385,7 +1400,8 @@ static int set_acoustic (ide_drive_t *dr
 							  SETFEATURES_DIS_AAM;
 	args.tfRegister[IDE_NSECTOR_OFFSET]	= arg;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
-	args.command_type = ide_cmd_type_parser(&args);
+	args.command_type = IDE_DRIVE_TASK_NO_DATA;
+	args.handler	  = &task_no_data_intr;
 	ide_raw_taskfile(drive, &args, NULL);
 	drive->acoustic = arg;
 	return 0;
@@ -1504,11 +1520,13 @@ static ide_startstop_t idedisk_start_pow
 			args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE_EXT;
 		else
 			args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE;
-		args->command_type = ide_cmd_type_parser(args);
+		args->command_type = IDE_DRIVE_TASK_NO_DATA;
+		args->handler	   = &task_no_data_intr;
 		return do_rw_taskfile(drive, args);
 	case idedisk_pm_standby:	/* Suspend step 2 (standby) */
 		args->tfRegister[IDE_COMMAND_OFFSET] = WIN_STANDBYNOW1;
-		args->command_type = ide_cmd_type_parser(args);
+		args->command_type = IDE_DRIVE_TASK_NO_DATA;
+		args->handler	   = &task_no_data_intr;
 		return do_rw_taskfile(drive, args);
 
 	case idedisk_pm_restore_dma:	/* Resume step 1 (restore DMA) */
@@ -1716,7 +1734,8 @@ static int idedisk_open(struct inode *in
 		u8 cf;
 		memset(&args, 0, sizeof(ide_task_t));
 		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK;
-		args.command_type = ide_cmd_type_parser(&args);
+		args.command_type = IDE_DRIVE_TASK_NO_DATA;
+		args.handler	  = &task_no_data_intr;
 		check_disk_change(inode->i_bdev);
 		/*
 		 * Ignore the return code from door_lock,
@@ -1762,7 +1781,8 @@ static int idedisk_release(struct inode 
 		ide_task_t args;
 		memset(&args, 0, sizeof(ide_task_t));
 		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK;
-		args.command_type = ide_cmd_type_parser(&args);
+		args.command_type = IDE_DRIVE_TASK_NO_DATA;
+		args.handler	  = &task_no_data_intr;
 		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
 			drive->doorlocking = 0;
 	}
--- diff/drivers/ide/ide-io.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/ide/ide-io.c	2004-03-09 11:51:49.000000000 +0000
@@ -197,7 +197,7 @@ void ide_end_drive_cmd (ide_drive_t *dri
 			if (args->tf_in_flags.b.data) {
 				u16 data				= hwif->INW(IDE_DATA_REG);
 				args->tfRegister[IDE_DATA_OFFSET]	= (data) & 0xFF;
-				args->hobRegister[IDE_DATA_OFFSET_HOB]	= (data >> 8) & 0xFF;
+				args->hobRegister[IDE_DATA_OFFSET]	= (data >> 8) & 0xFF;
 			}
 			args->tfRegister[IDE_ERROR_OFFSET]   = err;
 			args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG);
@@ -208,12 +208,12 @@ void ide_end_drive_cmd (ide_drive_t *dri
 			args->tfRegister[IDE_STATUS_OFFSET]  = stat;
 
 			if (drive->addressing == 1) {
-				hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
-				args->hobRegister[IDE_FEATURE_OFFSET_HOB] = hwif->INB(IDE_FEATURE_REG);
-				args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = hwif->INB(IDE_NSECTOR_REG);
-				args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = hwif->INB(IDE_SECTOR_REG);
-				args->hobRegister[IDE_LCYL_OFFSET_HOB]    = hwif->INB(IDE_LCYL_REG);
-				args->hobRegister[IDE_HCYL_OFFSET_HOB]    = hwif->INB(IDE_HCYL_REG);
+				hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
+				args->hobRegister[IDE_FEATURE_OFFSET]	= hwif->INB(IDE_FEATURE_REG);
+				args->hobRegister[IDE_NSECTOR_OFFSET]	= hwif->INB(IDE_NSECTOR_REG);
+				args->hobRegister[IDE_SECTOR_OFFSET]	= hwif->INB(IDE_SECTOR_REG);
+				args->hobRegister[IDE_LCYL_OFFSET]	= hwif->INB(IDE_LCYL_REG);
+				args->hobRegister[IDE_HCYL_OFFSET]	= hwif->INB(IDE_HCYL_REG);
 			}
 		}
 	} else if (blk_pm_request(rq)) {
--- diff/drivers/ide/ide-lib.c	2003-09-17 12:28:05.000000000 +0100
+++ source/drivers/ide/ide-lib.c	2004-03-09 11:51:49.000000000 +0000
@@ -447,3 +447,55 @@ int ide_set_xfer_rate(ide_drive_t *drive
 
 EXPORT_SYMBOL_GPL(ide_set_xfer_rate);
 
+/**
+ *	ide_dump_atapi_status       -       print human readable atapi status
+ *	@drive: drive that status applies to
+ *	@msg: text message to print
+ *	@stat: status byte to decode
+ *
+ *	Error reporting, in human readable form (luxurious, but a memory hog).
+ */
+byte ide_dump_atapi_status (ide_drive_t *drive, const char *msg, byte stat)
+{
+	unsigned long flags;
+
+	atapi_status_t status;
+	atapi_error_t error;
+
+	status.all = stat;
+	local_irq_set(flags);
+	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
+#if FANCY_STATUS_DUMPS
+	printk(" { ");
+	if (status.b.bsy)
+		printk("Busy ");
+	else {
+		if (status.b.drdy)	printk("DriveReady ");
+		if (status.b.df)	printk("DeviceFault ");
+		if (status.b.dsc)	printk("SeekComplete ");
+		if (status.b.drq)	printk("DataRequest ");
+		if (status.b.corr)	printk("CorrectedError ");
+		if (status.b.idx)	printk("Index ");
+		if (status.b.check)	printk("Error ");
+	}
+	printk("}");
+#endif	/* FANCY_STATUS_DUMPS */
+	printk("\n");
+	if ((status.all & (status.b.bsy|status.b.check)) == status.b.check) {
+		error.all = HWIF(drive)->INB(IDE_ERROR_REG);
+		printk("%s: %s: error=0x%02x", drive->name, msg, error.all);
+#if FANCY_STATUS_DUMPS
+		if (error.b.ili)	printk("IllegalLengthIndication ");
+		if (error.b.eom)	printk("EndOfMedia ");
+		if (error.b.abrt)	printk("Aborted Command ");
+		if (error.b.mcr)	printk("MediaChangeRequested ");
+		if (error.b.sense_key)	printk("LastFailedSense 0x%02x ",
+						error.b.sense_key);
+#endif	/* FANCY_STATUS_DUMPS */
+		printk("\n");
+	}
+	local_irq_restore(flags);
+	return error.all;
+}
+
+EXPORT_SYMBOL(ide_dump_atapi_status);
--- diff/drivers/ide/ide-probe.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/ide/ide-probe.c	2004-03-09 11:51:49.000000000 +0000
@@ -922,8 +922,12 @@ static int ide_init_queue(ide_drive_t *d
 	q->queuedata = HWGROUP(drive);
 	blk_queue_segment_boundary(q, 0xffff);
 
-	if (!hwif->rqsize)
-		hwif->rqsize = hwif->no_lba48 ? 256 : 65536;
+	if (!hwif->rqsize) {
+		if (hwif->max_rqsize)
+			hwif->rqsize = hwif->max_rqsize(drive);
+		else
+			hwif->rqsize = hwif->no_lba48 ? 256 : 65536;
+	}
 	if (hwif->rqsize < max_sectors)
 		max_sectors = hwif->rqsize;
 	blk_queue_max_sectors(q, max_sectors);
--- diff/drivers/ide/ide-taskfile.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/ide/ide-taskfile.c	2004-03-09 11:51:49.000000000 +0000
@@ -101,7 +101,8 @@ int taskfile_lib_get_identify (ide_drive
 		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_IDENTIFY;
 	else
 		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_PIDENTIFY;
-	args.command_type			= ide_cmd_type_parser(&args);
+	args.command_type = IDE_DRIVE_TASK_IN;
+	args.handler	  = &task_in_intr;
 	return ide_raw_taskfile(drive, &args, buf);
 }
 
@@ -120,13 +121,13 @@ void debug_taskfile (ide_drive_t *drive,
 	printk("TF.6=x%02x ", args->tfRegister[IDE_SELECT_OFFSET]);
 	printk("TF.7=x%02x\n", args->tfRegister[IDE_COMMAND_OFFSET]);
 	printk(KERN_INFO "%s: ", drive->name);
-//	printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET_HOB]);
-	printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET_HOB]);
-	printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET_HOB]);
-	printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET_HOB]);
-	printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET_HOB]);
-	printk("HTF.5=x%02x ", args->hobRegister[IDE_HCYL_OFFSET_HOB]);
-	printk("HTF.6=x%02x ", args->hobRegister[IDE_SELECT_OFFSET_HOB]);
+//	printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET]);
+	printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET]);
+	printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET]);
+	printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET]);
+	printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET]);
+	printk("HTF.5=x%02x ", args->hobRegister[IDE_HCYL_OFFSET]);
+	printk("HTF.6=x%02x ", args->hobRegister[IDE_SELECT_OFFSET]);
 	printk("HTF.7=x%02x\n", args->hobRegister[IDE_CONTROL_OFFSET_HOB]);
 }
 #endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
@@ -990,320 +991,6 @@ EXPORT_SYMBOL(pre_task_mulout_intr);
 
 #endif /* !CONFIG_IDE_TASKFILE_IO */
 
-/* Called by internal to feature out type of command being called */
-//ide_pre_handler_t * ide_pre_handler_parser (task_struct_t *taskfile, hob_struct_t *hobfile)
-ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
-{
-	switch(taskfile->command) {
-				/* IDE_DRIVE_TASK_RAW_WRITE */
-		case CFA_WRITE_MULTI_WO_ERASE:
-	//	case WIN_WRITE_LONG:
-	//	case WIN_WRITE_LONG_ONCE:
-		case WIN_MULTWRITE:
-		case WIN_MULTWRITE_EXT:
-			return &pre_task_mulout_intr;
-			
-				/* IDE_DRIVE_TASK_OUT */
-		case WIN_WRITE:
-	//	case WIN_WRITE_ONCE:
-		case WIN_WRITE_EXT:
-		case WIN_WRITE_VERIFY:
-		case WIN_WRITE_BUFFER:
-		case CFA_WRITE_SECT_WO_ERASE:
-		case WIN_DOWNLOAD_MICROCODE:
-			return &pre_task_out_intr;
-				/* IDE_DRIVE_TASK_OUT */
-		case WIN_SMART:
-			if (taskfile->feature == SMART_WRITE_LOG_SECTOR)
-				return &pre_task_out_intr;
-		case WIN_WRITEDMA:
-	//	case WIN_WRITEDMA_ONCE:
-		case WIN_WRITEDMA_QUEUED:
-		case WIN_WRITEDMA_EXT:
-		case WIN_WRITEDMA_QUEUED_EXT:
-				/* IDE_DRIVE_TASK_OUT */
-		default:
-			break;
-	}
-	return(NULL);
-}
-
-EXPORT_SYMBOL(ide_pre_handler_parser);
-
-/* Called by internal to feature out type of command being called */
-//ide_handler_t * ide_handler_parser (task_struct_t *taskfile, hob_struct_t *hobfile)
-ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
-{
-	switch(taskfile->command) {
-		case WIN_IDENTIFY:
-		case WIN_PIDENTIFY:
-		case CFA_TRANSLATE_SECTOR:
-		case WIN_READ_BUFFER:
-		case WIN_READ:
-	//	case WIN_READ_ONCE:
-		case WIN_READ_EXT:
-			return &task_in_intr;
-		case WIN_SECURITY_DISABLE:
-		case WIN_SECURITY_ERASE_UNIT:
-		case WIN_SECURITY_SET_PASS:
-		case WIN_SECURITY_UNLOCK:
-		case WIN_DOWNLOAD_MICROCODE:
-		case CFA_WRITE_SECT_WO_ERASE:
-		case WIN_WRITE_BUFFER:
-		case WIN_WRITE_VERIFY:
-		case WIN_WRITE:
-	//	case WIN_WRITE_ONCE:	
-		case WIN_WRITE_EXT:
-			return &task_out_intr;
-	//	case WIN_READ_LONG:
-	//	case WIN_READ_LONG_ONCE:
-		case WIN_MULTREAD:
-		case WIN_MULTREAD_EXT:
-			return &task_mulin_intr;
-	//	case WIN_WRITE_LONG:
-	//	case WIN_WRITE_LONG_ONCE:
-		case CFA_WRITE_MULTI_WO_ERASE:
-		case WIN_MULTWRITE:
-		case WIN_MULTWRITE_EXT:
-			return &task_mulout_intr;
-		case WIN_SMART:
-			switch(taskfile->feature) {
-				case SMART_READ_VALUES:
-				case SMART_READ_THRESHOLDS:
-				case SMART_READ_LOG_SECTOR:
-					return &task_in_intr;
-				case SMART_WRITE_LOG_SECTOR:
-					return &task_out_intr;
-				default:
-					return &task_no_data_intr;
-			}
-		case CFA_REQ_EXT_ERROR_CODE:
-		case CFA_ERASE_SECTORS:
-		case WIN_VERIFY:
-	//	case WIN_VERIFY_ONCE:
-		case WIN_VERIFY_EXT:
-		case WIN_SEEK:
-			return &task_no_data_intr;
-		case WIN_SPECIFY:
-			return &set_geometry_intr;
-		case WIN_RECAL:
-	//	case WIN_RESTORE:
-			return &recal_intr;
-		case WIN_NOP:
-		case WIN_DIAGNOSE:
-		case WIN_FLUSH_CACHE:
-		case WIN_FLUSH_CACHE_EXT:
-		case WIN_STANDBYNOW1:
-		case WIN_STANDBYNOW2:
-		case WIN_SLEEPNOW1:
-		case WIN_SLEEPNOW2:
-		case WIN_SETIDLE1:
-		case WIN_CHECKPOWERMODE1:
-		case WIN_CHECKPOWERMODE2:
-		case WIN_GETMEDIASTATUS:
-		case WIN_MEDIAEJECT:
-			return &task_no_data_intr;
-		case WIN_SETMULT:
-			return &set_multmode_intr;
-		case WIN_READ_NATIVE_MAX:
-		case WIN_SET_MAX:
-		case WIN_READ_NATIVE_MAX_EXT:
-		case WIN_SET_MAX_EXT:
-		case WIN_SECURITY_ERASE_PREPARE:
-		case WIN_SECURITY_FREEZE_LOCK:
-		case WIN_DOORLOCK:
-		case WIN_DOORUNLOCK:
-		case WIN_SETFEATURES:
-			return &task_no_data_intr;
-		case DISABLE_SEAGATE:
-		case EXABYTE_ENABLE_NEST:
-			return &task_no_data_intr;
-		case WIN_READDMA:
-	//	case WIN_READDMA_ONCE:
-		case WIN_IDENTIFY_DMA:
-		case WIN_READDMA_QUEUED:
-		case WIN_READDMA_EXT:
-		case WIN_READDMA_QUEUED_EXT:
-		case WIN_WRITEDMA:
-	//	case WIN_WRITEDMA_ONCE:
-		case WIN_WRITEDMA_QUEUED:
-		case WIN_WRITEDMA_EXT:
-		case WIN_WRITEDMA_QUEUED_EXT:
-		case WIN_FORMAT:
-		case WIN_INIT:
-		case WIN_DEVICE_RESET:
-		case WIN_QUEUED_SERVICE:
-		case WIN_PACKETCMD:
-		default:
-			return(NULL);
-	}	
-}
-
-EXPORT_SYMBOL(ide_handler_parser);
-
-ide_post_handler_t * ide_post_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
-{
-	switch(taskfile->command) {
-		case WIN_SPECIFY:	/* set_geometry_intr */
-		case WIN_RESTORE:	/* recal_intr */
-		case WIN_SETMULT:	/* set_multmode_intr */
-		default:
-			return(NULL);
-	}
-}
-
-EXPORT_SYMBOL(ide_post_handler_parser);
-
-/* Called by ioctl to feature out type of command being called */
-int ide_cmd_type_parser (ide_task_t *args)
-{
-
-	task_struct_t *taskfile = (task_struct_t *) args->tfRegister;
-	hob_struct_t *hobfile   = (hob_struct_t *) args->hobRegister;
-
-	args->prehandler	= ide_pre_handler_parser(taskfile, hobfile);
-	args->handler		= ide_handler_parser(taskfile, hobfile);
-	args->posthandler	= ide_post_handler_parser(taskfile, hobfile);
-
-	switch(args->tfRegister[IDE_COMMAND_OFFSET]) {
-		case WIN_IDENTIFY:
-		case WIN_PIDENTIFY:
-			return IDE_DRIVE_TASK_IN;
-		case CFA_TRANSLATE_SECTOR:
-		case WIN_READ:
-	//	case WIN_READ_ONCE:
-		case WIN_READ_EXT:
-		case WIN_READ_BUFFER:
-			return IDE_DRIVE_TASK_IN;
-		case WIN_WRITE:
-	//	case WIN_WRITE_ONCE:
-		case WIN_WRITE_EXT:
-		case WIN_WRITE_VERIFY:
-		case WIN_WRITE_BUFFER:
-		case CFA_WRITE_SECT_WO_ERASE:
-		case WIN_DOWNLOAD_MICROCODE:
-			return IDE_DRIVE_TASK_RAW_WRITE;
-	//	case WIN_READ_LONG:
-	//	case WIN_READ_LONG_ONCE:
-		case WIN_MULTREAD:
-		case WIN_MULTREAD_EXT:
-			return IDE_DRIVE_TASK_IN;
-	//	case WIN_WRITE_LONG:
-	//	case WIN_WRITE_LONG_ONCE:
-		case CFA_WRITE_MULTI_WO_ERASE:
-		case WIN_MULTWRITE:
-		case WIN_MULTWRITE_EXT:
-			return IDE_DRIVE_TASK_RAW_WRITE;
-		case WIN_SECURITY_DISABLE:
-		case WIN_SECURITY_ERASE_UNIT:
-		case WIN_SECURITY_SET_PASS:
-		case WIN_SECURITY_UNLOCK:
-			return IDE_DRIVE_TASK_OUT;
-		case WIN_SMART:
-			args->tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS;
-			args->tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS;
-			switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
-				case SMART_READ_VALUES:
-				case SMART_READ_THRESHOLDS:
-				case SMART_READ_LOG_SECTOR:
-					return IDE_DRIVE_TASK_IN;
-				case SMART_WRITE_LOG_SECTOR:
-					return IDE_DRIVE_TASK_OUT;
-				default:
-					return IDE_DRIVE_TASK_NO_DATA;
-			}
-		case WIN_READDMA:
-	//	case WIN_READDMA_ONCE:
-		case WIN_IDENTIFY_DMA:
-		case WIN_READDMA_QUEUED:
-		case WIN_READDMA_EXT:
-		case WIN_READDMA_QUEUED_EXT:
-			return IDE_DRIVE_TASK_IN;
-		case WIN_WRITEDMA:
-	//	case WIN_WRITEDMA_ONCE:
-		case WIN_WRITEDMA_QUEUED:
-		case WIN_WRITEDMA_EXT:
-		case WIN_WRITEDMA_QUEUED_EXT:
-			return IDE_DRIVE_TASK_RAW_WRITE;
-		case WIN_SETFEATURES:
-			switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
-				case SETFEATURES_EN_8BIT:
-				case SETFEATURES_EN_WCACHE:
-					return IDE_DRIVE_TASK_NO_DATA;
-				case SETFEATURES_XFER:
-					return IDE_DRIVE_TASK_SET_XFER;
-				case SETFEATURES_DIS_DEFECT:
-				case SETFEATURES_EN_APM:
-				case SETFEATURES_DIS_MSN:
-				case SETFEATURES_DIS_RETRY:
-				case SETFEATURES_EN_AAM:
-				case SETFEATURES_RW_LONG:
-				case SETFEATURES_SET_CACHE:
-				case SETFEATURES_DIS_RLA:
-				case SETFEATURES_EN_RI:
-				case SETFEATURES_EN_SI:
-				case SETFEATURES_DIS_RPOD:
-				case SETFEATURES_DIS_WCACHE:
-				case SETFEATURES_EN_DEFECT:
-				case SETFEATURES_DIS_APM:
-				case SETFEATURES_EN_ECC:
-				case SETFEATURES_EN_MSN:
-				case SETFEATURES_EN_RETRY:
-				case SETFEATURES_EN_RLA:
-				case SETFEATURES_PREFETCH:
-				case SETFEATURES_4B_RW_LONG:
-				case SETFEATURES_DIS_AAM:
-				case SETFEATURES_EN_RPOD:
-				case SETFEATURES_DIS_RI:
-				case SETFEATURES_DIS_SI:
-				default:
-					return IDE_DRIVE_TASK_NO_DATA;
-			}
-		case WIN_NOP:
-		case CFA_REQ_EXT_ERROR_CODE:
-		case CFA_ERASE_SECTORS:
-		case WIN_VERIFY:
-	//	case WIN_VERIFY_ONCE:
-		case WIN_VERIFY_EXT:
-		case WIN_SEEK:
-		case WIN_SPECIFY:
-		case WIN_RESTORE:
-		case WIN_DIAGNOSE:
-		case WIN_FLUSH_CACHE:
-		case WIN_FLUSH_CACHE_EXT:
-		case WIN_STANDBYNOW1:
-		case WIN_STANDBYNOW2:
-		case WIN_SLEEPNOW1:
-		case WIN_SLEEPNOW2:
-		case WIN_SETIDLE1:
-		case DISABLE_SEAGATE:
-		case WIN_CHECKPOWERMODE1:
-		case WIN_CHECKPOWERMODE2:
-		case WIN_GETMEDIASTATUS:
-		case WIN_MEDIAEJECT:
-		case WIN_SETMULT:
-		case WIN_READ_NATIVE_MAX:
-		case WIN_SET_MAX:
-		case WIN_READ_NATIVE_MAX_EXT:
-		case WIN_SET_MAX_EXT:
-		case WIN_SECURITY_ERASE_PREPARE:
-		case WIN_SECURITY_FREEZE_LOCK:
-		case EXABYTE_ENABLE_NEST:
-		case WIN_DOORLOCK:
-		case WIN_DOORUNLOCK:
-			return IDE_DRIVE_TASK_NO_DATA;
-		case WIN_FORMAT:
-		case WIN_INIT:
-		case WIN_DEVICE_RESET:
-		case WIN_QUEUED_SERVICE:
-		case WIN_PACKETCMD:
-		default:
-			return IDE_DRIVE_TASK_INVALID;
-	}
-}
-
-EXPORT_SYMBOL(ide_cmd_type_parser);
-
 /*
  * This function is intended to be used prior to invoking ide_do_drive_cmd().
  */
@@ -1331,7 +1018,7 @@ int ide_diag_taskfile (ide_drive_t *driv
 	 */
 	if (args->command_type != IDE_DRIVE_TASK_NO_DATA) {
 		if (data_size == 0)
-			rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
+			rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
 		else
 			rq.nr_sectors = data_size / SECTOR_SIZE;
 
@@ -1339,16 +1026,6 @@ int ide_diag_taskfile (ide_drive_t *driv
 		rq.hard_cur_sectors = rq.current_nr_sectors = rq.nr_sectors;
 	}
 
-	if (args->tf_out_flags.all == 0) {
-		/*
-		 * clean up kernel settings for driver sanity, regardless.
-		 * except for discrete diag services.
-		 */
-		args->posthandler = ide_post_handler_parser(
-				(struct hd_drive_task_hdr *) args->tfRegister,
-				(struct hd_drive_hob_hdr *) args->hobRegister);
-
-	}
 	rq.special = args;
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
@@ -1451,11 +1128,9 @@ int ide_taskfile_ioctl (ide_drive_t *dri
 #if 0
 			args.prehandler = &pre_task_out_intr;
 			args.handler = &task_out_intr;
-			args.posthandler = NULL;
 			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
 			args.prehandler = NULL;
 			args.handler = &task_in_intr;
-			args.posthandler = NULL;
 			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
 			break;
 #else
--- diff/drivers/ide/ide-tcq.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/ide/ide-tcq.c	2004-03-09 11:51:49.000000000 +0000
@@ -483,7 +483,7 @@ static int ide_tcq_check_autopoll(ide_dr
 
 	args->tfRegister[IDE_FEATURE_OFFSET] = 0x01;
 	args->tfRegister[IDE_COMMAND_OFFSET] = WIN_NOP;
-	args->command_type = ide_cmd_type_parser(args);
+	args->command_type = IDE_DRIVE_TASK_NO_DATA;
 	args->handler = ide_tcq_nop_handler;
 	return ide_raw_taskfile(drive, args, NULL);
 }
@@ -513,7 +513,8 @@ static int ide_tcq_configure(ide_drive_t
 	memset(args, 0, sizeof(ide_task_t));
 	args->tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES;
 	args->tfRegister[IDE_FEATURE_OFFSET] = SETFEATURES_EN_WCACHE;
-	args->command_type = ide_cmd_type_parser(args);
+	args->command_type = IDE_DRIVE_TASK_NO_DATA;
+	args->handler	   = &task_no_data_intr;
 
 	if (ide_raw_taskfile(drive, args, NULL)) {
 		printk(KERN_WARNING "%s: failed to enable write cache\n", drive->name);
@@ -527,7 +528,8 @@ static int ide_tcq_configure(ide_drive_t
 	memset(args, 0, sizeof(ide_task_t));
 	args->tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES;
 	args->tfRegister[IDE_FEATURE_OFFSET] = SETFEATURES_DIS_RI;
-	args->command_type = ide_cmd_type_parser(args);
+	args->command_type = IDE_DRIVE_TASK_NO_DATA;
+	args->handler	   = &task_no_data_intr;
 
 	if (ide_raw_taskfile(drive, args, NULL)) {
 		printk(KERN_ERR "%s: disabling release interrupt fail\n", drive->name);
@@ -541,7 +543,8 @@ static int ide_tcq_configure(ide_drive_t
 	memset(args, 0, sizeof(ide_task_t));
 	args->tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES;
 	args->tfRegister[IDE_FEATURE_OFFSET] = SETFEATURES_EN_SI;
-	args->command_type = ide_cmd_type_parser(args);
+	args->command_type = IDE_DRIVE_TASK_NO_DATA;
+	args->handler	   = &task_no_data_intr;
 
 	if (ide_raw_taskfile(drive, args, NULL)) {
 		printk(KERN_ERR "%s: enabling service interrupt fail\n", drive->name);
--- diff/drivers/ide/legacy/pdc4030.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/ide/legacy/pdc4030.c	2004-03-09 11:51:49.000000000 +0000
@@ -814,11 +814,10 @@ static ide_startstop_t promise_rw_disk (
 
 	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
 	memset(args.hobRegister, 0, sizeof(struct hd_drive_hob_hdr));
-	/* We can't call ide_cmd_type_parser here, since it won't understand
-	   our command, but that doesn't matter, since we don't use the
-	   generic interrupt handlers either. Setup the bits of args that we
-	   do need.
-	*/
+	/*
+	 * Setup the bits of args that we do need.
+	 * Note that we don't use the generic interrupt handlers.
+	 */
 	args.handler		= NULL;
 	args.rq			= (struct request *) rq;
 	rq->special		= (ide_task_t *)&args;
--- diff/drivers/ide/pci/Makefile	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/ide/pci/Makefile	2004-03-09 11:51:49.000000000 +0000
@@ -3,6 +3,7 @@ obj-$(CONFIG_BLK_DEV_ADMA100)		+= adma10
 obj-$(CONFIG_BLK_DEV_AEC62XX)		+= aec62xx.o
 obj-$(CONFIG_BLK_DEV_ALI15X3)		+= alim15x3.o
 obj-$(CONFIG_BLK_DEV_AMD74XX)		+= amd74xx.o
+obj-$(CONFIG_BLK_DEV_ATIIXP)		+= atiixp.o
 obj-$(CONFIG_BLK_DEV_CMD64X)		+= cmd64x.o
 obj-$(CONFIG_BLK_DEV_CS5520)		+= cs5520.o
 obj-$(CONFIG_BLK_DEV_CS5530)		+= cs5530.o
--- diff/drivers/ide/pci/pdc202xx_new.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/ide/pci/pdc202xx_new.c	2004-03-09 11:51:49.000000000 +0000
@@ -140,108 +140,6 @@ static int check_in_drive_lists (ide_dri
 	return 0;
 }
 
-static int pdcnew_tune_chipset (ide_drive_t *drive, u8 xferspeed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	u8 drive_pci		= 0x60 + (drive->dn << 2);
-	u8 speed	= ide_rate_filter(pdcnew_ratemask(drive), xferspeed);
-
-	u32			drive_conf;
-	u8			AP, BP, CP, DP;
-	u8			TA = 0, TB = 0, TC = 0;
-
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
-		return -1;
-
-	pci_read_config_dword(dev, drive_pci, &drive_conf);
-	pci_read_config_byte(dev, (drive_pci), &AP);
-	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
-
-	if (speed < XFER_SW_DMA_0) {
-		if ((AP & 0x0F) || (BP & 0x07)) {
-			/* clear PIO modes of lower 8421 bits of A Register */
-			pci_write_config_byte(dev, (drive_pci), AP &~0x0F);
-			pci_read_config_byte(dev, (drive_pci), &AP);
-
-			/* clear PIO modes of lower 421 bits of B Register */
-			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0x07);
-			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-
-			pci_read_config_byte(dev, (drive_pci), &AP);
-			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-		}
-	} else {
-		if ((BP & 0xF0) && (CP & 0x0F)) {
-			/* clear DMA modes of upper 842 bits of B Register */
-			/* clear PIO forced mode upper 1 bit of B Register */
-			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0xF0);
-			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-
-			/* clear DMA modes of lower 8421 bits of C Register */
-			pci_write_config_byte(dev, (drive_pci)|0x02, CP &~0x0F);
-			pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-		}
-	}
-
-	pci_read_config_byte(dev, (drive_pci), &AP);
-	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-
-	switch(speed) {
-		case XFER_UDMA_6:	speed = XFER_UDMA_5;
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;
-		case XFER_UDMA_2:	TB = 0x20; TC = 0x01; break;
-		case XFER_UDMA_3:
-		case XFER_UDMA_1:	TB = 0x40; TC = 0x02; break;
-		case XFER_UDMA_0:
-		case XFER_MW_DMA_2:	TB = 0x60; TC = 0x03; break;
-		case XFER_MW_DMA_1:	TB = 0x60; TC = 0x04; break;
-		case XFER_MW_DMA_0:
-		case XFER_SW_DMA_2:	TB = 0x60; TC = 0x05; break;
-		case XFER_SW_DMA_1:	TB = 0x80; TC = 0x06; break;
-		case XFER_SW_DMA_0:	TB = 0xC0; TC = 0x0B; break;
-		case XFER_PIO_4:	TA = 0x01; TB = 0x04; break;
-		case XFER_PIO_3:	TA = 0x02; TB = 0x06; break;
-		case XFER_PIO_2:	TA = 0x03; TB = 0x08; break;
-		case XFER_PIO_1:	TA = 0x05; TB = 0x0C; break;
-		case XFER_PIO_0:
-		default:		TA = 0x09; TB = 0x13; break;
-	}
-
-	if (speed < XFER_SW_DMA_0) {
-		pci_write_config_byte(dev, (drive_pci), AP|TA);
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
-	} else {
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
-		pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
-	}
-
-#if PDC202XX_DECODE_REGISTER_INFO
-	pci_read_config_byte(dev, (drive_pci), &AP);
-	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
-
-	decode_registers(REG_A, AP);
-	decode_registers(REG_B, BP);
-	decode_registers(REG_C, CP);
-	decode_registers(REG_D, DP);
-#endif /* PDC202XX_DECODE_REGISTER_INFO */
-#if PDC202XX_DEBUG_DRIVE_INFO
-	printk(KERN_DEBUG "%s: %s drive%d 0x%08x ",
-		drive->name, ide_xfer_verbose(speed),
-		drive->dn, drive_conf);
-		pci_read_config_dword(dev, drive_pci, &drive_conf);
-	printk("0x%08x\n", drive_conf);
-#endif /* PDC202XX_DEBUG_DRIVE_INFO */
-
-	return (ide_config_drive_speed(drive, speed));
-}
-
 static int pdcnew_new_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
@@ -288,19 +186,14 @@ static int pdcnew_new_tune_chipset (ide_
  * 180, 120,  90,  90,  90,  60,  30
  *  11,   5,   4,   3,   2,   1,   0
  */
-static int config_chipset_for_pio (ide_drive_t *drive, u8 pio)
+static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio)
 {
-	u8 speed = 0;
+	u8 speed;
 
 	if (pio == 5) pio = 4;
 	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
-        
-	return ((int) pdcnew_tune_chipset(drive, speed));
-}
 
-static void pdcnew_tune_drive (ide_drive_t *drive, u8 pio)
-{
-	(void) config_chipset_for_pio(drive, pio);
+	(void)pdcnew_new_tune_chipset(drive, speed);
 }
 
 static u8 pdcnew_new_cable_detect (ide_hwif_t *hwif)
@@ -312,56 +205,15 @@ static int config_chipset_for_dma (ide_d
 {
 	struct hd_driveid *id	= drive->id;
 	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
 	u8 speed		= -1;
-	u8 cable		= 0;
+	u8 cable;
 
 	u8 ultra_66		= ((id->dma_ultra & 0x0010) ||
 				   (id->dma_ultra & 0x0008)) ? 1 : 0;
 
-	switch(dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20277:
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20271:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20270:
-		case PCI_DEVICE_ID_PROMISE_20268:
-			cable = pdcnew_new_cable_detect(hwif);
-#if PDC202_DEBUG_CABLE
-			printk(KERN_DEBUG "%s: %s-pin cable, %s-pin cable, %d\n",
-				hwif->name, hwif->udma_four ? "80" : "40",
-				cable ? "40" : "80", cable);
-#endif /* PDC202_DEBUG_CABLE */
-			break;
-		default:
-			/* If it's not one we know we should never
-			   arrive here.. */
-			BUG();
-	}
+	cable = pdcnew_new_cable_detect(hwif);
 
-	/*
-	 * Set the control register to use the 66Mhz system
-	 * clock for UDMA 3/4 mode operation. If one drive on
-	 * a channel is U66 capable but the other isn't we
-	 * fall back to U33 mode. The BIOS INT 13 hooks turn
-	 * the clock on then off for each read/write issued. I don't
-	 * do that here because it would require modifying the
-	 * kernel, separating the fop routines from the kernel or
-	 * somehow hooking the fops calls. It may also be possible to
-	 * leave the 66Mhz clock on and readjust the timing
-	 * parameters.
-	 */
-
-	if ((ultra_66) && (cable)) {
-#ifdef DEBUG
-		printk(KERN_DEBUG "ULTRA 66/100/133: %s channel of Ultra 66/100/133 "
-			"requires an 80-pin cable for Ultra66 operation.\n",
-			hwif->channel ? "Secondary" : "Primary");
-		printk(KERN_DEBUG "         Switching to Ultra33 mode.\n");
-#endif /* DEBUG */
-		/* Primary   : zero out second bit */
-		/* Secondary : zero out fourth bit */
+	if (ultra_66 && cable) {
 		printk(KERN_WARNING "Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
 		printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name);
 	}
@@ -590,10 +442,7 @@ static void __init init_hwif_pdc202new (
 	hwif->speedproc = &pdcnew_new_tune_chipset;
 	hwif->resetproc = &pdcnew_new_reset;
 
-	if (!hwif->dma_base) {
-		hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
-		return;
-	}
+	hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
 
 	hwif->ultra_mask = 0x7f;
 	hwif->mwdma_mask = 0x07;
--- diff/drivers/ide/pci/pdc202xx_new.h	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/ide/pci/pdc202xx_new.h	2004-03-09 11:51:49.000000000 +0000
@@ -5,15 +5,6 @@
 #include <linux/pci.h>
 #include <linux/ide.h>
 
-#define DISPLAY_PDC202XX_TIMINGS
-
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-
-#define PDC202XX_DEBUG_DRIVE_INFO		0
-#define PDC202XX_DECODE_REGISTER_INFO		0
-
 const static char *pdc_quirk_drives[] = {
 	"QUANTUM FIREBALLlct08 08",
 	"QUANTUM FIREBALLP KA6.4",
@@ -26,116 +17,6 @@ const static char *pdc_quirk_drives[] = 
 	NULL
 };
 
-/* A Register */
-#define	SYNC_ERRDY_EN	0xC0
-
-#define	SYNC_IN		0x80	/* control bit, different for master vs. slave drives */
-#define	ERRDY_EN	0x40	/* control bit, different for master vs. slave drives */
-#define	IORDY_EN	0x20	/* PIO: IOREADY */
-#define	PREFETCH_EN	0x10	/* PIO: PREFETCH */
-
-#define	PA3		0x08	/* PIO"A" timing */
-#define	PA2		0x04	/* PIO"A" timing */
-#define	PA1		0x02	/* PIO"A" timing */
-#define	PA0		0x01	/* PIO"A" timing */
-
-/* B Register */
-
-#define	MB2		0x80	/* DMA"B" timing */
-#define	MB1		0x40	/* DMA"B" timing */
-#define	MB0		0x20	/* DMA"B" timing */
-
-#define	PB4		0x10	/* PIO_FORCE 1:0 */
-
-#define	PB3		0x08	/* PIO"B" timing */	/* PIO flow Control mode */
-#define	PB2		0x04	/* PIO"B" timing */	/* PIO 4 */
-#define	PB1		0x02	/* PIO"B" timing */	/* PIO 3 half */
-#define	PB0		0x01	/* PIO"B" timing */	/* PIO 3 other half */
-
-/* C Register */
-#define	IORDYp_NO_SPEED	0x4F
-#define	SPEED_DIS	0x0F
-
-#define	DMARQp		0x80
-#define	IORDYp		0x40
-#define	DMAR_EN		0x20
-#define	DMAW_EN		0x10
-
-#define	MC3		0x08	/* DMA"C" timing */
-#define	MC2		0x04	/* DMA"C" timing */
-#define	MC1		0x02	/* DMA"C" timing */
-#define	MC0		0x01	/* DMA"C" timing */
-
-#if PDC202XX_DECODE_REGISTER_INFO
-
-#define REG_A		0x01
-#define REG_B		0x02
-#define REG_C		0x04
-#define REG_D		0x08
-
-static void decode_registers (u8 registers, u8 value)
-{
-	u8	bit = 0, bit1 = 0, bit2 = 0;
-
-	switch(registers) {
-		case REG_A:
-			bit2 = 0;
-			printk("A Register ");
-			if (value & 0x80) printk("SYNC_IN ");
-			if (value & 0x40) printk("ERRDY_EN ");
-			if (value & 0x20) printk("IORDY_EN ");
-			if (value & 0x10) printk("PREFETCH_EN ");
-			if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; }
-			if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; }
-			if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; }
-			if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; }
-			printk("PIO(A) = %d ", bit2);
-			break;
-		case REG_B:
-			bit1 = 0;bit2 = 0;
-			printk("B Register ");
-			if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; }
-			if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; }
-			if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; }
-			printk("DMA(B) = %d ", bit1 >> 5);
-			if (value & 0x10) printk("PIO_FORCED/PB4 ");
-			if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; }
-			if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; }
-			if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; }
-			if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; }
-			printk("PIO(B) = %d ", bit2);
-			break;
-		case REG_C:
-			bit2 = 0;
-			printk("C Register ");
-			if (value & 0x80) printk("DMARQp ");
-			if (value & 0x40) printk("IORDYp ");
-			if (value & 0x20) printk("DMAR_EN ");
-			if (value & 0x10) printk("DMAW_EN ");
-
-			if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; }
-			if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; }
-			if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; }
-			if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; }
-			printk("DMA(C) = %d ", bit2);
-			break;
-		case REG_D:
-			printk("D Register ");
-			break;
-		default:
-			return;
-	}
-	printk("\n        %s ", (registers & REG_D) ? "DP" :
-				(registers & REG_C) ? "CP" :
-				(registers & REG_B) ? "BP" :
-				(registers & REG_A) ? "AP" : "ERROR");
-	for (bit=128;bit>0;bit/=2)
-		printk("%s", (value & bit) ? "1" : "0");
-	printk("\n");
-}
-
-#endif /* PDC202XX_DECODE_REGISTER_INFO */
-
 #define set_2regs(a, b)					\
 	do {						\
 		hwif->OUTB((a + adj), indexreg);	\
--- diff/drivers/ide/pci/piix.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/ide/pci/piix.c	2004-03-09 11:51:49.000000000 +0000
@@ -814,7 +814,7 @@ static struct pci_driver driver = {
 	.probe		= piix_init_one,
 };
 
-static int piix_ide_init(void)
+static int __init piix_ide_init(void)
 {
 	piix_check_450nx();
 	return ide_pci_register_driver(&driver);
--- diff/drivers/ide/pci/siimage.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/ide/pci/siimage.c	2004-03-09 11:51:49.000000000 +0000
@@ -203,13 +203,12 @@ static byte siimage_ratemask (ide_drive_
 	else
 		pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
 
-	if(is_sata(hwif))
-	{
-		if(strstr(drive->id->model, "Maxtor"))
+	if (is_sata(hwif)) {
+		if (strstr(drive->id->model, "Maxtor 4D060H3"))
 			return 3;
 		return 4;
 	}
-	
+
 	if ((scsc & 0x30) == 0x10)	/* 133 */
 		mode = 4;
 	else if ((scsc & 0x30) == 0x20)	/* 2xPCI */
@@ -1046,25 +1045,34 @@ static void __init init_mmio_iops_siimag
 	hwif->mmio			= 2;
 }
 
-static int is_dev_seagate_sata(ide_drive_t *drive)
+/* TODO firmware versions should be added - eric */
+static const char * sil_blacklist [] = {
+	"ST320012AS",
+	"ST330013AS",
+	"ST340017AS",
+	"ST360015AS",
+	"ST380023AS",
+	"ST3120023AS",
+	"ST340014ASL",
+	"ST360014ASL",
+	"ST380011ASL",
+	"ST3120022ASL",
+	"ST3160021ASL",
+};
+
+static unsigned int siimage_sata_max_rqsize(ide_drive_t *drive)
 {
 	const char *s = &drive->id->model[0];
-	unsigned len;
+	unsigned int n;
 
-	if (!drive->present)
-		return 0;
-
-	len = strnlen(s, sizeof(drive->id->model));
-
-	if ((len > 4) && (!memcmp(s, "ST", 2))) {
-		if ((!memcmp(s + len - 2, "AS", 2)) ||
-		    (!memcmp(s + len - 3, "ASL", 3))) {
-			printk(KERN_INFO "%s: applying pessimistic Seagate "
-					 "errata fix\n", drive->name);
-			return 1;
+	for (n = 0; n < ARRAY_SIZE(sil_blacklist); n++)
+		if (!memcmp(sil_blacklist[n], s, strlen(sil_blacklist[n]))) {
+			printk(KERN_INFO "%s: applying Seagate errata fix\n",
+					 drive->name);
+			return 15;
 		}
-	}
-	return 0;
+
+	return 128;
 }
 
 /**
@@ -1087,9 +1095,10 @@ static void __init init_iops_siimage (id
 	
 	hwif->hwif_data = 0;
 
-	hwif->rqsize = 128;
-	if (is_sata(hwif) && is_dev_seagate_sata(&hwif->drives[0]))
-		hwif->rqsize = 15;
+	if (is_sata(hwif) && (class_rev <= 0x01))
+		hwif->max_rqsize = siimage_sata_max_rqsize;
+	else
+		hwif->rqsize = 128;
 
 	if (pci_get_drvdata(dev) == NULL)
 		return;
--- diff/drivers/ieee1394/dma.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/ieee1394/dma.c	2004-03-09 11:51:49.000000000 +0000
@@ -168,7 +168,7 @@ dma_addr_t dma_region_offset_to_bus(stru
 	return sg_dma_address(sg) + rem;
 }
 
-void dma_region_sync(struct dma_region *dma, unsigned long offset, unsigned long len)
+void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset, unsigned long len)
 {
 	int first, last;
 	unsigned long rem;
@@ -179,7 +179,21 @@ void dma_region_sync(struct dma_region *
 	first = dma_region_find(dma, offset, &rem);
 	last = dma_region_find(dma, offset + len - 1, &rem);
 
-	pci_dma_sync_sg(dma->dev, &dma->sglist[first], last - first + 1, dma->direction);
+	pci_dma_sync_sg_for_cpu(dma->dev, &dma->sglist[first], last - first + 1, dma->direction);
+}
+
+void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset, unsigned long len)
+{
+	int first, last;
+	unsigned long rem;
+
+	if (!len)
+		len = 1;
+
+	first = dma_region_find(dma, offset, &rem);
+	last = dma_region_find(dma, offset + len - 1, &rem);
+
+	pci_dma_sync_sg_for_device(dma->dev, &dma->sglist[first], last - first + 1, dma->direction);
 }
 
 /* nopage() handler for mmap access */
--- diff/drivers/ieee1394/dma.h	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/ieee1394/dma.h	2004-03-09 11:51:49.000000000 +0000
@@ -60,8 +60,10 @@ int  dma_region_alloc(struct dma_region 
 /* unmap and free the buffer */
 void dma_region_free(struct dma_region *dma);
 
-/* sync the IO bus' view of the buffer with the CPU's view */
-void dma_region_sync(struct dma_region *dma, unsigned long offset, unsigned long len);
+/* sync the CPU's view of the buffer */
+void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset, unsigned long len);
+/* sync the IO bus' view of the buffer */
+void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset, unsigned long len);
 
 /* map the buffer into a user space process */
 int  dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma);
--- diff/drivers/ieee1394/dv1394.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/ieee1394/dv1394.c	2004-03-09 11:51:49.000000000 +0000
@@ -553,7 +553,7 @@ static void frame_prepare(struct video_c
 	*(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors);
 
 	/* make the latest version of this frame visible to the PCI card */
-	dma_region_sync(&video->dv_buf, f->data - (unsigned long) video->dv_buf.kvirt, video->frame_size);
+	dma_region_sync_for_device(&video->dv_buf, f->data - (unsigned long) video->dv_buf.kvirt, video->frame_size);
 
 	/* lock against DMA interrupt */
 	spin_lock_irqsave(&video->spinlock, irq_flags);
@@ -2033,9 +2033,9 @@ static void ir_tasklet_func(unsigned lon
 			struct packet *p = dma_region_i(&video->packet_buf, struct packet, video->current_packet);
 
 			/* make sure we are seeing the latest changes to p */
-			dma_region_sync(&video->packet_buf,
-					(unsigned long) p - (unsigned long) video->packet_buf.kvirt,
-					sizeof(struct packet));
+			dma_region_sync_for_cpu(&video->packet_buf,
+						(unsigned long) p - (unsigned long) video->packet_buf.kvirt,
+						sizeof(struct packet));
 					
 			packet_length = le16_to_cpu(p->data_length);
 			packet_time   = le16_to_cpu(p->timestamp);
--- diff/drivers/ieee1394/ieee1394_core.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/ieee1394/ieee1394_core.c	2004-03-09 11:51:49.000000000 +0000
@@ -1201,7 +1201,8 @@ EXPORT_SYMBOL(dma_prog_region_free);
 EXPORT_SYMBOL(dma_region_init);
 EXPORT_SYMBOL(dma_region_alloc);
 EXPORT_SYMBOL(dma_region_free);
-EXPORT_SYMBOL(dma_region_sync);
+EXPORT_SYMBOL(dma_region_sync_for_cpu);
+EXPORT_SYMBOL(dma_region_sync_for_device);
 EXPORT_SYMBOL(dma_region_mmap);
 EXPORT_SYMBOL(dma_region_offset_to_bus);
 
--- diff/drivers/ieee1394/ohci1394.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/ieee1394/ohci1394.c	2004-03-09 11:51:49.000000000 +0000
@@ -1732,7 +1732,7 @@ static void ohci_iso_recv_bufferfill_tas
 		/* OK, the block is finished... */
 		
 		/* sync our view of the block */
-		dma_region_sync(&iso->data_buf, recv->block_dma*recv->buf_stride, recv->buf_stride);
+		dma_region_sync_for_cpu(&iso->data_buf, recv->block_dma*recv->buf_stride, recv->buf_stride);
 		
 		/* reset the DMA descriptor */
 		im->status = recv->buf_stride;
@@ -1789,7 +1789,7 @@ static void ohci_iso_recv_packetperbuf_t
 		}
 
 		/* sync our view of the buffer */
-		dma_region_sync(&iso->data_buf, iso->pkt_dma * recv->buf_stride, recv->buf_stride);
+		dma_region_sync_for_cpu(&iso->data_buf, iso->pkt_dma * recv->buf_stride, recv->buf_stride);
 			
 		/* record the per-packet info */
 		{
@@ -2016,7 +2016,7 @@ static int ohci_iso_xmit_queue(struct hp
 	sy = info->sy;
 
 	/* sync up the card's view of the buffer */
-	dma_region_sync(&iso->data_buf, offset, len);
+	dma_region_sync_for_device(&iso->data_buf, offset, len);
 
 	/* append first_packet to the DMA chain */
 	/* by linking the previous descriptor to it */
--- diff/drivers/ieee1394/sbp2.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/ieee1394/sbp2.c	2004-03-09 11:51:49.000000000 +0000
@@ -1948,12 +1948,12 @@ static int sbp2_link_orb_command(struct 
 	SBP2_ORB_DEBUG("sending command orb %p, total orbs = %x",
 			command_orb, global_outstanding_command_orbs);
 
-	pci_dma_sync_single(hi->host->pdev, command->command_orb_dma,
-			    sizeof(struct sbp2_command_orb),
-			    PCI_DMA_BIDIRECTIONAL);
-	pci_dma_sync_single(hi->host->pdev, command->sge_dma,
-			    sizeof(command->scatter_gather_element),
-			    PCI_DMA_BIDIRECTIONAL);
+	pci_dma_sync_single_for_device(hi->host->pdev, command->command_orb_dma,
+				       sizeof(struct sbp2_command_orb),
+				       PCI_DMA_BIDIRECTIONAL);
+	pci_dma_sync_single_for_device(hi->host->pdev, command->sge_dma,
+				       sizeof(command->scatter_gather_element),
+				       PCI_DMA_BIDIRECTIONAL);
 	/*
 	 * Check to see if there are any previous orbs to use
 	 */
@@ -1994,9 +1994,9 @@ static int sbp2_link_orb_command(struct 
 			cpu_to_be32(command->command_orb_dma);
 		/* Tells hardware that this pointer is valid */
 		scsi_id->last_orb->next_ORB_hi = 0x0;
-		pci_dma_sync_single(hi->host->pdev, scsi_id->last_orb_dma,
-				    sizeof(struct sbp2_command_orb),
-				    PCI_DMA_BIDIRECTIONAL);
+		pci_dma_sync_single_for_device(hi->host->pdev, scsi_id->last_orb_dma,
+					       sizeof(struct sbp2_command_orb),
+					       PCI_DMA_BIDIRECTIONAL);
 
 		/*
 		 * Ring the doorbell
@@ -2358,12 +2358,12 @@ static int sbp2_handle_status_write(stru
 	if (command) {
 
 		SBP2_DEBUG("Found status for command ORB");
-		pci_dma_sync_single(hi->host->pdev, command->command_orb_dma,
-				    sizeof(struct sbp2_command_orb),
-				    PCI_DMA_BIDIRECTIONAL);
-		pci_dma_sync_single(hi->host->pdev, command->sge_dma,
-				    sizeof(command->scatter_gather_element),
-				    PCI_DMA_BIDIRECTIONAL);
+		pci_dma_sync_single_for_cpu(hi->host->pdev, command->command_orb_dma,
+					    sizeof(struct sbp2_command_orb),
+					    PCI_DMA_BIDIRECTIONAL);
+		pci_dma_sync_single_for_cpu(hi->host->pdev, command->sge_dma,
+					    sizeof(command->scatter_gather_element),
+					    PCI_DMA_BIDIRECTIONAL);
 
 		SBP2_ORB_DEBUG("matched command orb %p", &command->command_orb);
 		outstanding_orb_decr;
@@ -2534,12 +2534,12 @@ static void sbp2scsi_complete_all_comman
 		SBP2_DEBUG("Found pending command to complete");
 		lh = scsi_id->sbp2_command_orb_inuse.next;
 		command = list_entry(lh, struct sbp2_command_info, list);
-		pci_dma_sync_single(hi->host->pdev, command->command_orb_dma,
-				    sizeof(struct sbp2_command_orb),
-				    PCI_DMA_BIDIRECTIONAL);
-		pci_dma_sync_single(hi->host->pdev, command->sge_dma,
-				    sizeof(command->scatter_gather_element),
-				    PCI_DMA_BIDIRECTIONAL);
+		pci_dma_sync_single_for_cpu(hi->host->pdev, command->command_orb_dma,
+					    sizeof(struct sbp2_command_orb),
+					    PCI_DMA_BIDIRECTIONAL);
+		pci_dma_sync_single_for_cpu(hi->host->pdev, command->sge_dma,
+					    sizeof(command->scatter_gather_element),
+					    PCI_DMA_BIDIRECTIONAL);
 		sbp2util_mark_command_completed(scsi_id, command);
 		if (command->Current_SCpnt) {
 			void (*done)(Scsi_Cmnd *) = command->Current_done;
@@ -2699,14 +2699,14 @@ static int sbp2scsi_abort (Scsi_Cmnd *SC
 		command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt);
 		if (command) {
 			SBP2_DEBUG("Found command to abort");
-			pci_dma_sync_single(hi->host->pdev,
-					    command->command_orb_dma,
-					    sizeof(struct sbp2_command_orb),
-					    PCI_DMA_BIDIRECTIONAL);
-			pci_dma_sync_single(hi->host->pdev,
-					    command->sge_dma,
-					    sizeof(command->scatter_gather_element),
-					    PCI_DMA_BIDIRECTIONAL);
+			pci_dma_sync_single_for_cpu(hi->host->pdev,
+						    command->command_orb_dma,
+						    sizeof(struct sbp2_command_orb),
+						    PCI_DMA_BIDIRECTIONAL);
+			pci_dma_sync_single_for_cpu(hi->host->pdev,
+						    command->sge_dma,
+						    sizeof(command->scatter_gather_element),
+						    PCI_DMA_BIDIRECTIONAL);
 			sbp2util_mark_command_completed(scsi_id, command);
 			if (command->Current_SCpnt) {
 				void (*done)(Scsi_Cmnd *) = command->Current_done;
--- diff/drivers/input/evdev.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/input/evdev.c	2004-03-09 11:51:49.000000000 +0000
@@ -209,7 +209,7 @@ static int evdev_ioctl(struct inode *ino
 	struct evdev *evdev = list->evdev;
 	struct input_dev *dev = evdev->handle.dev;
 	struct input_absinfo abs;
-	int t, u, v;
+	int i, t, u, v;
 
 	if (!evdev->exist) return -ENODEV;
 
@@ -234,6 +234,9 @@ static int evdev_ioctl(struct inode *ino
 			u = SET_INPUT_KEYCODE(dev, t, v);
 			clear_bit(u, dev->keybit);
 			set_bit(v, dev->keybit);
+			for (i = 0; i < dev->keycodemax; i++)
+				if (INPUT_KEYCODE(dev,i) == u)
+					set_bit(u, dev->keybit);
 			return 0;
 
 		case EVIOCSFF:
--- diff/drivers/input/gameport/ns558.c	2003-08-26 10:00:52.000000000 +0100
+++ source/drivers/input/gameport/ns558.c	2004-03-09 11:51:49.000000000 +0000
@@ -77,7 +77,7 @@ static void ns558_isa_probe(int io)
  * No one should be using this address.
  */
 
-	if (check_region(io, 1))
+	if (!request_region(io, 1, "ns558-isa"))
 		return;
 
 /*
@@ -89,7 +89,8 @@ static void ns558_isa_probe(int io)
 	outb(~c & ~3, io);
 	if (~(u = v = inb(io)) & 3) {
 		outb(c, io);
-		return;
+		i = 0;
+		goto out;
 	}
 /*
  * After a trigger, there must be at least some bits changing.
@@ -99,7 +100,8 @@ static void ns558_isa_probe(int io)
 
 	if (u == v) {
 		outb(c, io);
-		return;
+		i = 0;
+		goto out;
 	}
 	wait_ms(3);
 /*
@@ -110,7 +112,8 @@ static void ns558_isa_probe(int io)
 	for (i = 0; i < 1000; i++)
 		if ((u ^ inb(io)) & 0xf) {
 			outb(c, io);
-			return;
+			i = 0;
+			goto out;
 		}
 /* 
  * And now find the number of mirrors of the port.
@@ -118,7 +121,9 @@ static void ns558_isa_probe(int io)
 
 	for (i = 1; i < 5; i++) {
 
-		if (check_region(io & (-1 << i), (1 << i)))	/* Don't disturb anyone */
+		release_region(io & (-1 << (i-1)), (1 << (i-1)));
+
+		if (!request_region(io & (-1 << i), (1 << i), "ns558-isa"))	/* Don't disturb anyone */
 			break;
 
 		outb(0xff, io & (-1 << i));
@@ -126,18 +131,25 @@ static void ns558_isa_probe(int io)
 			if (inb(io & (-1 << i)) != inb((io & (-1 << i)) + (1 << i) - 1)) b++;
 		wait_ms(3);
 
-		if (b > 300)					/* We allow 30% difference */
+		if (b > 300) {					/* We allow 30% difference */
+			release_region(io & (-1 << i), (1 << i));
 			break;
+		}
 	}
 
 	i--;
 
+	if (i != 4) {
+		if (!request_region(io & (-1 << i), (1 << i), "ns558-isa"))
+			return;
+	}
+
 	if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
 		printk(KERN_ERR "ns558: Memory allocation failed.\n");
-		return;
+		goto out;
 	}
-       	memset(port, 0, sizeof(struct ns558));
-	
+	memset(port, 0, sizeof(struct ns558));
+
 	port->type = NS558_ISA;
 	port->size = (1 << i);
 	port->gameport.io = io;
@@ -148,8 +160,6 @@ static void ns558_isa_probe(int io)
 	sprintf(port->phys, "isa%04x/gameport0", io & (-1 << i));
 	sprintf(port->name, "NS558 ISA");
 
-	request_region(io & (-1 << i), (1 << i), "ns558-isa");
-
 	gameport_register_port(&port->gameport);
 
 	printk(KERN_INFO "gameport: NS558 ISA at %#x", port->gameport.io);
@@ -157,6 +167,9 @@ static void ns558_isa_probe(int io)
 	printk(" speed %d kHz\n", port->gameport.speed);
 
 	list_add(&port->node, &ns558_list);
+	return;
+out:
+	release_region(io & (-1 << i), (1 << i));
 }
 
 #ifdef CONFIG_PNP
--- diff/drivers/input/joystick/amijoy.c	2003-06-09 14:18:18.000000000 +0100
+++ source/drivers/input/joystick/amijoy.c	2004-03-09 11:51:49.000000000 +0000
@@ -32,6 +32,7 @@
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
@@ -42,10 +43,15 @@
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Driver for Amiga joysticks");
-MODULE_PARM(amijoy, "1-2i");
 MODULE_LICENSE("GPL");
 
 static int amijoy[2] = { 0, 1 };
+static int amijoy_nargs;  
+module_param_array_named(map, amijoy, uint, amijoy_nargs, 0);
+MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is 0,1)");
+
+__obsolete_setup("amijoy=");
+
 static int amijoy_used[2] = { 0, 0 };
 static struct input_dev amijoy_dev[2];
 static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" };
@@ -101,17 +107,6 @@ static void amijoy_close(struct input_de
 		free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
 }
 
-static int __init amijoy_setup(char *str)
-{
-	int i;
-	int ints[4];
-
-	str = get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 2; i++) amijoy[i] = ints[i+1];
-	return 1;
-}
-__setup("amijoy=", amijoy_setup);
-
 static int __init amijoy_init(void)
 {
 	int i, j;
--- diff/drivers/input/joystick/analog.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/input/joystick/analog.c	2004-03-09 11:51:49.000000000 +0000
@@ -32,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/slab.h>
 #include <linux/bitops.h>
 #include <linux/init.h>
@@ -50,9 +51,12 @@ MODULE_LICENSE("GPL");
 #define ANALOG_PORTS		16
 
 static char *js[ANALOG_PORTS];
+static int js_nargs;
 static int analog_options[ANALOG_PORTS];
-MODULE_PARM(js, "1-" __MODULE_STRING(ANALOG_PORTS) "s");
-MODULE_PARM_DESC(js, "Analog joystick options");
+module_param_array_named(map, js, charp, js_nargs, 0);
+MODULE_PARM_DESC(map, "Describes analog joysticks type/capabilities");
+
+__obsolete_setup("js=");
 
 /*
  * Times, feature definitions.
@@ -711,7 +715,7 @@ static void analog_parse_options(void)
 	int i, j;
 	char *end;
 
-	for (i = 0; i < ANALOG_PORTS && js[i]; i++) {
+	for (i = 0; i < js_nargs; i++) {
 
 		for (j = 0; analog_types[j].name; j++)
 			if (!strcmp(analog_types[j].name, js[i])) {
@@ -742,24 +746,6 @@ static struct gameport_dev analog_dev = 
 	.disconnect =	analog_disconnect,
 };
 
-#ifndef MODULE
-static int __init analog_setup(char *str)
-{
-	char *s = str;
-	int i = 0;
-
-	if (!str || !*str) return 0;
-
-	while ((str = s) && (i < ANALOG_PORTS)) {
-		if ((s = strchr(str,','))) *s++ = 0;
-		js[i++] = str;
-	}
-
-	return 1;
-}
-__setup("js=", analog_setup);
-#endif
-
 int __init analog_init(void)
 {
 	analog_parse_options();
--- diff/drivers/input/joystick/db9.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/input/joystick/db9.c	2004-03-09 11:51:49.000000000 +0000
@@ -33,6 +33,7 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/parport.h>
@@ -42,9 +43,24 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@u
 MODULE_DESCRIPTION("Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(db9, "2i");
-MODULE_PARM(db9_2, "2i");
-MODULE_PARM(db9_3, "2i");
+static int db9[] __initdata = { -1, 0 };
+static int db9_nargs __initdata = 0;
+module_param_array_named(dev, db9, int, db9_nargs, 0);
+MODULE_PARM_DESC(dev, "Describes first attached device (<parport#>,<type>)");
+
+static int db9_2[] __initdata = { -1, 0 };
+static int db9_nargs_2 __initdata = 0;
+module_param_array_named(dev2, db9_2, int, db9_nargs_2, 0);
+MODULE_PARM_DESC(dev2, "Describes second attached device (<parport#>,<type>)");
+
+static int db9_3[] __initdata = { -1, 0 };
+static int db9_nargs_3 __initdata = 0;
+module_param_array_named(dev3, db9_3, int, db9_nargs_3, 0);
+MODULE_PARM_DESC(dev3, "Describes third attached device (<parport#>,<type>)");
+
+__obsolete_setup("db9=");
+__obsolete_setup("db9_2=");
+__obsolete_setup("db9_3=");
 
 #define DB9_MULTI_STICK		0x01
 #define DB9_MULTI2_STICK	0x02
@@ -76,10 +92,6 @@ MODULE_PARM(db9_3, "2i");
 #define DB9_GENESIS6_DELAY	14
 #define DB9_REFRESH_TIME	HZ/100
 
-static int db9[] __initdata = { -1, 0 };
-static int db9_2[] __initdata = { -1, 0 };
-static int db9_3[] __initdata = { -1, 0 };
-
 struct db9 {
 	struct input_dev dev[DB9_MAX_DEVICES];
 	struct timer_list timer;
@@ -518,7 +530,7 @@ static void db9_close(struct input_dev *
 	}
 }
 
-static struct db9 __init *db9_probe(int *config)
+static struct db9 __init *db9_probe(int *config, int nargs)
 {
 	struct db9 *db9;
 	struct parport *pp;
@@ -526,6 +538,12 @@ static struct db9 __init *db9_probe(int 
 
 	if (config[0] < 0)
 		return NULL;
+
+	if (nargs < 2) {
+		printk(KERN_ERR "db9.c: Device type must be specified.\n");
+		return NULL;
+	}
+
 	if (config[1] < 1 || config[1] >= DB9_MAX_PAD || !db9_buttons[config[1]]) {
 		printk(KERN_ERR "db9.c: bad config\n");
 		return NULL;
@@ -601,38 +619,11 @@ static struct db9 __init *db9_probe(int 
 	return db9;
 }
 
-#ifndef MODULE
-static int __init db9_setup(char *str)
-{
-	int i, ints[3];
-	get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 2; i++) db9[i] = ints[i + 1];
-	return 1;
-}
-static int __init db9_setup_2(char *str)
-{
-	int i, ints[3];
-	get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 2; i++) db9_2[i] = ints[i + 1];
-	return 1;
-}
-static int __init db9_setup_3(char *str)
-{
-	int i, ints[3];
-	get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 2; i++) db9_3[i] = ints[i + 1];
-	return 1;
-}
-__setup("db9=", db9_setup);
-__setup("db9_2=", db9_setup_2);
-__setup("db9_3=", db9_setup_3);
-#endif
-
 int __init db9_init(void)
 {
-	db9_base[0] = db9_probe(db9);
-	db9_base[1] = db9_probe(db9_2);
-	db9_base[2] = db9_probe(db9_3);
+	db9_base[0] = db9_probe(db9, db9_nargs);
+	db9_base[1] = db9_probe(db9_2, db9_nargs_2);
+	db9_base[2] = db9_probe(db9_3, db9_nargs_3);
 
 	if (db9_base[0] || db9_base[1] || db9_base[2])
 		return 0;
--- diff/drivers/input/joystick/gamecon.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/input/joystick/gamecon.c	2004-03-09 11:51:49.000000000 +0000
@@ -35,6 +35,7 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/parport.h>
 #include <linux/input.h>
@@ -43,10 +44,26 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@u
 MODULE_DESCRIPTION("NES, SNES, N64, MultiSystem, PSX gamepad driver");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(gc, "2-6i");
-MODULE_PARM(gc_2,"2-6i");
-MODULE_PARM(gc_3,"2-6i");
-MODULE_PARM(gc_psx_delay, "i");
+static int gc[] __initdata = { -1, 0, 0, 0, 0, 0 };
+static int gc_nargs __initdata = 0;
+module_param_array_named(map, gc, int, gc_nargs, 0);
+MODULE_PARM_DESC(map, "Describers first set of devices (<parport#>,<pad1>,<pad2>,..<pad5>)");
+
+static int gc_2[] __initdata = { -1, 0, 0, 0, 0, 0 };
+static int gc_nargs_2 __initdata = 0;
+module_param_array_named(map2, gc_2, int, gc_nargs_2, 0);
+MODULE_PARM_DESC(map2, "Describers second set of devices");
+
+static int gc_3[] __initdata = { -1, 0, 0, 0, 0, 0 };
+static int gc_nargs_3 __initdata = 0;
+module_param_array_named(map3, gc_3, int, gc_nargs_3, 0);
+MODULE_PARM_DESC(map3, "Describers third set of devices");
+
+__obsolete_setup("gc=");
+__obsolete_setup("gc_2=");
+__obsolete_setup("gc_3=");
+
+/* see also gs_psx_delay parameter in PSX support section */
 
 #define GC_SNES		1
 #define GC_NES		2
@@ -71,10 +88,6 @@ struct gc {
 
 static struct gc *gc_base[3];
 
-static int gc[] __initdata = { -1, 0, 0, 0, 0, 0 };
-static int gc_2[] __initdata = { -1, 0, 0, 0, 0, 0 };
-static int gc_3[] __initdata = { -1, 0, 0, 0, 0, 0 };
-
 static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
 
 static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
@@ -232,6 +245,11 @@ static void gc_multi_read_packet(struct 
 #define GC_PSX_LEN(x)	((x) & 0xf)	/* Low nibble is length in words */
 
 static int gc_psx_delay = GC_PSX_DELAY;
+module_param_named(psx_delay, gc_psx_delay, uint, 0);
+MODULE_PARM_DESC(psx_delay, "Delay when accessing Sony PSX controller (usecs)");
+
+__obsolete_setup("gc_psx_delay=");
+
 static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y };
 static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
 				BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR };
@@ -468,7 +486,7 @@ static void gc_close(struct input_dev *d
 	}
 }
 
-static struct gc __init *gc_probe(int *config)
+static struct gc __init *gc_probe(int *config, int nargs)
 {
 	struct gc *gc;
 	struct parport *pp;
@@ -478,6 +496,11 @@ static struct gc __init *gc_probe(int *c
 	if (config[0] < 0)
 		return NULL;
 
+	if (nargs < 2) {
+		printk(KERN_ERR "gamecon.c: at least one device must be specified\n");
+		return NULL;
+	}
+
 	pp = parport_find_number(config[0]);
 
 	if (!pp) {
@@ -507,7 +530,7 @@ static struct gc __init *gc_probe(int *c
 	gc->timer.data = (long) gc;
 	gc->timer.function = gc_timer;
 
-	for (i = 0; i < 5; i++) {
+	for (i = 0; i < nargs - 1; i++) {
 
 		if (!config[i + 1])
 			continue;
@@ -632,44 +655,11 @@ static struct gc __init *gc_probe(int *c
 	return gc;
 }
 
-#ifndef MODULE
-static int __init gc_setup(char *str)
-{
-	int i, ints[7];
-	get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 6; i++) gc[i] = ints[i + 1];
-	return 1;
-}
-static int __init gc_setup_2(char *str)
-{
-	int i, ints[7];
-	get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 6; i++) gc_2[i] = ints[i + 1];
-	return 1;
-}
-static int __init gc_setup_3(char *str)
-{
-	int i, ints[7];
-	get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 6; i++) gc_3[i] = ints[i + 1];
-	return 1;
-}
-static int __init gc_psx_setup(char *str)
-{
-        get_option(&str, &gc_psx_delay);
-        return 1;
-}
-__setup("gc=", gc_setup);
-__setup("gc_2=", gc_setup_2);
-__setup("gc_3=", gc_setup_3);
-__setup("gc_psx_delay=", gc_psx_setup);
-#endif
-
 int __init gc_init(void)
 {
-	gc_base[0] = gc_probe(gc);
-	gc_base[1] = gc_probe(gc_2);
-	gc_base[2] = gc_probe(gc_3);
+	gc_base[0] = gc_probe(gc, gc_nargs);
+	gc_base[1] = gc_probe(gc_2, gc_nargs_2);
+	gc_base[2] = gc_probe(gc_3, gc_nargs_3);
 
 	if (gc_base[0] || gc_base[1] || gc_base[2])
 		return 0;
--- diff/drivers/input/joystick/iforce/iforce-usb.c	2003-09-30 15:46:14.000000000 +0100
+++ source/drivers/input/joystick/iforce/iforce-usb.c	2004-03-09 11:51:49.000000000 +0000
@@ -135,7 +135,7 @@ static int iforce_usb_probe(struct usb_i
 	struct usb_endpoint_descriptor *epirq, *epout;
 	struct iforce *iforce;
 
-	interface = &intf->altsetting[intf->act_altsetting];
+	interface = intf->cur_altsetting;
 
 	epirq = &interface->endpoint[0].desc;
 	epout = &interface->endpoint[1].desc;
--- diff/drivers/input/joystick/turbografx.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/input/joystick/turbografx.c	2004-03-09 11:51:49.000000000 +0000
@@ -35,15 +35,31 @@
 #include <linux/parport.h>
 #include <linux/input.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("TurboGraFX parallel port interface driver");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(tgfx, "2-8i");
-MODULE_PARM(tgfx_2, "2-8i");
-MODULE_PARM(tgfx_3, "2-8i");
+static int tgfx[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
+static int tgfx_nargs __initdata = 0;
+module_param_array_named(map, tgfx, int, tgfx_nargs, 0);
+MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<js1>,<js2>,..<js7>");
+
+static int tgfx_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
+static int tgfx_nargs_2 __initdata = 0;
+module_param_array_named(map2, tgfx_2, int, tgfx_nargs_2, 0);
+MODULE_PARM_DESC(map2, "Describes second set of devices");
+
+static int tgfx_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
+static int tgfx_nargs_3 __initdata = 0;
+module_param_array_named(map3, tgfx_3, int, tgfx_nargs_3, 0);
+MODULE_PARM_DESC(map3, "Describes third set of devices");
+
+__obsolete_setup("tgfx=");
+__obsolete_setup("tgfx_2=");
+__obsolete_setup("tgfx_3=");
 
 #define TGFX_REFRESH_TIME	HZ/100	/* 10 ms */
 
@@ -58,10 +74,6 @@ MODULE_PARM(tgfx_3, "2-8i");
 #define TGFX_TOP		0x01
 #define TGFX_TOP2		0x08
 
-static int tgfx[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
-static int tgfx_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
-static int tgfx_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
-
 static int tgfx_buttons[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2 };
 static char *tgfx_name = "TurboGraFX Multisystem joystick";
 
@@ -133,7 +145,7 @@ static void tgfx_close(struct input_dev 
  * tgfx_probe() probes for tg gamepads.
  */
 
-static struct tgfx __init *tgfx_probe(int *config)
+static struct tgfx __init *tgfx_probe(int *config, int nargs)
 {
 	struct tgfx *tgfx;
 	struct parport *pp;
@@ -142,6 +154,11 @@ static struct tgfx __init *tgfx_probe(in
 	if (config[0] < 0)
 		return NULL;
 
+	if (nargs < 2) {
+		printk(KERN_ERR "turbografx.c: at least one joystick must be specified\n");
+		return NULL;
+	}
+
 	pp = parport_find_number(config[0]);
 
 	if (!pp) {
@@ -171,7 +188,7 @@ static struct tgfx __init *tgfx_probe(in
 
 	tgfx->sticks = 0;
 
-	for (i = 0; i < 7; i++)
+	for (i = 0; i < nargs - 1; i++)
 		if (config[i+1] > 0 && config[i+1] < 6) {
 
 			tgfx->sticks |= (1 << i);
@@ -212,38 +229,11 @@ static struct tgfx __init *tgfx_probe(in
 	return tgfx;
 }
 
-#ifndef MODULE
-static int __init tgfx_setup(char *str)
-{
-	int i, ints[9];
-	get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 8; i++) tgfx[i] = ints[i + 1];
-	return 1;
-}
-static int __init tgfx_setup_2(char *str)
-{
-	int i, ints[9];
-	get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 8; i++) tgfx_2[i] = ints[i + 1];
-	return 1;
-}
-static int __init tgfx_setup_3(char *str)
-{
-	int i, ints[9];
-	get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 8; i++) tgfx_3[i] = ints[i + 1];
-	return 1;
-}
-__setup("tgfx=", tgfx_setup);
-__setup("tgfx_2=", tgfx_setup_2);
-__setup("tgfx_3=", tgfx_setup_3);
-#endif
-
 int __init tgfx_init(void)
 {
-	tgfx_base[0] = tgfx_probe(tgfx);
-	tgfx_base[1] = tgfx_probe(tgfx_2);
-	tgfx_base[2] = tgfx_probe(tgfx_3);
+	tgfx_base[0] = tgfx_probe(tgfx, tgfx_nargs);
+	tgfx_base[1] = tgfx_probe(tgfx_2, tgfx_nargs_2);
+	tgfx_base[2] = tgfx_probe(tgfx_3, tgfx_nargs_3);
 
 	if (tgfx_base[0] || tgfx_base[1] || tgfx_base[2])
 		return 0;
--- diff/drivers/input/keyboard/Kconfig	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/input/keyboard/Kconfig	2004-03-09 11:51:49.000000000 +0000
@@ -17,6 +17,7 @@ config KEYBOARD_ATKBD
 	depends on INPUT && INPUT_KEYBOARD
 	select SERIO
 	select SERIO_I8042 if PC
+	select SERIO_GSCPS2 if GSC
 	help
 	  Say Y here if you want to use a standard AT or PS/2 keyboard. Usually
 	  you'll need this, unless you have a different type keyboard (USB, ADB
@@ -40,6 +41,19 @@ config KEYBOARD_SUNKBD
 	  To compile this driver as a module, choose M here: the
 	  module will be called sunkbd.
 
+config KEYBOARD_LKKBD
+	tristate "DECstation/VAXstation LK201/LK401 keyboard support"
+	depends on INPUT && INPUT_KEYBOARD
+	select SERIO
+	help
+	  Say Y here if you want to use a LK201 or LK401 style serial
+	  keyboard. This keyboard is also useable on PCs if you attach
+	  it with the inputattach program. The connector pinout is
+	  described within lkkbd.c.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called lkkbd.
+
 config KEYBOARD_XTKBD
 	tristate "XT Keyboard support"
 	depends on INPUT && INPUT_KEYBOARD
--- diff/drivers/input/keyboard/Makefile	2003-05-21 11:49:55.000000000 +0100
+++ source/drivers/input/keyboard/Makefile	2004-03-09 11:51:49.000000000 +0000
@@ -7,6 +7,7 @@
 obj-$(CONFIG_KEYBOARD_ATKBD)		+= atkbd.o
 obj-$(CONFIG_KEYBOARD_MAPLE)		+= maple_keyb.o
 obj-$(CONFIG_KEYBOARD_SUNKBD)		+= sunkbd.o
+obj-$(CONFIG_KEYBOARD_LKKBD)		+= lkkbd.o
 obj-$(CONFIG_KEYBOARD_XTKBD)		+= xtkbd.o
 obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o
 obj-$(CONFIG_KEYBOARD_NEWTON)		+= newtonkbd.o
--- diff/drivers/input/keyboard/atkbd.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/input/keyboard/atkbd.c	2004-03-09 11:51:49.000000000 +0000
@@ -30,21 +30,17 @@
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_DESCRIPTION("AT and PS/2 keyboard driver");
-MODULE_PARM(atkbd_set, "1i");
-MODULE_PARM(atkbd_reset, "1i");
-MODULE_PARM(atkbd_softrepeat, "1i");
 MODULE_LICENSE("GPL");
 
 static int atkbd_set = 2;
 module_param_named(set, atkbd_set, int, 0);
-MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3, 4)");
+MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)");
+
 #if defined(__i386__) || defined(__x86_64__) || defined(__hppa__)
 static int atkbd_reset;
 #else
 static int atkbd_reset = 1;
 #endif
-static int atkbd_softrepeat;
-
 module_param_named(reset, atkbd_reset, bool, 0);
 MODULE_PARM_DESC(reset, "Reset keyboard during initialization");
 
@@ -52,6 +48,18 @@ static int atkbd_softrepeat;
 module_param_named(softrepeat, atkbd_softrepeat, bool, 0);
 MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat");
 
+static int atkbd_scroll;
+module_param_named(scroll, atkbd_scroll, bool, 0);
+MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
+
+static int atkbd_extra;
+module_param_named(extra, atkbd_extra, bool, 0);
+MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
+
+__obsolete_setup("atkbd_set=");
+__obsolete_setup("atkbd_reset");
+__obsolete_setup("atkbd_softrepeat=");
+
 /*
  * Scancode to keycode tables. These are just the default setting, and
  * are loadable via an userland utility.
@@ -127,11 +135,11 @@ static unsigned char atkbd_unxlate_table
 #define ATKBD_CMD_EX_SETLEDS	0x20eb
 #define ATKBD_CMD_OK_GETID	0x02e8
 
+
 #define ATKBD_RET_ACK		0xfa
 #define ATKBD_RET_NAK		0xfe
 #define ATKBD_RET_BAT		0xaa
 #define ATKBD_RET_EMUL0		0xe0
-#define ATKBD_RET_EMULX		0x80
 #define ATKBD_RET_EMUL1		0xe1
 #define ATKBD_RET_RELEASE	0xf0
 #define ATKBD_RET_HANGUEL	0xf1
@@ -141,6 +149,22 @@ static unsigned char atkbd_unxlate_table
 #define ATKBD_KEY_UNKNOWN	  0
 #define ATKBD_KEY_NULL		255
 
+#define ATKBD_SCR_1		254
+#define ATKBD_SCR_2		253
+#define ATKBD_SCR_4		252
+#define ATKBD_SCR_8		251
+#define ATKBD_SCR_CLICK		250
+
+#define ATKBD_SPECIAL		250
+
+static unsigned char atkbd_scroll_keys[5][2] = {
+	{ ATKBD_SCR_1,     0x45 },
+	{ ATKBD_SCR_2,     0x29 },
+	{ ATKBD_SCR_4,     0x36 },
+	{ ATKBD_SCR_8,     0x27 },
+	{ ATKBD_SCR_CLICK, 0x60 },
+};
+
 /*
  * The atkbd control structure
  */
@@ -155,6 +179,7 @@ struct atkbd {
 	unsigned char cmdbuf[4];
 	unsigned char cmdcnt;
 	unsigned char set;
+	unsigned char extra;
 	unsigned char release;
 	int lastkey;
 	volatile signed char ack;
@@ -189,6 +214,7 @@ static irqreturn_t atkbd_interrupt(struc
 {
 	struct atkbd *atkbd = serio->private;
 	unsigned int code = data;
+	int scroll = 0, click = -1;
 	int value;
 
 #ifdef ATKBD_DEBUG
@@ -202,7 +228,7 @@ static irqreturn_t atkbd_interrupt(struc
 		atkbd->resend = 1;
 		goto out;
 	}
-	
+
 	if (!flags && data == ATKBD_RET_ACK)
 		atkbd->resend = 0;
 #endif
@@ -276,7 +302,7 @@ static irqreturn_t atkbd_interrupt(struc
 		case ATKBD_KEY_UNKNOWN:
 			printk(KERN_WARNING "atkbd.c: Unknown key %s (%s set %d, code %#x on %s).\n",
 				atkbd->release ? "released" : "pressed",
-				atkbd->translated ? "translated" : "raw", 
+				atkbd->translated ? "translated" : "raw",
 				atkbd->set, code, serio->phys);
 			if (atkbd->translated && atkbd->set == 2 && code == 0x7a)
 				printk(KERN_WARNING "atkbd.c: This is an XFree86 bug. It shouldn't access"
@@ -284,6 +310,21 @@ static irqreturn_t atkbd_interrupt(struc
 			else
 				printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' to make it known.\n",						code & 0x80 ? "e0" : "", code & 0x7f);
 			break;
+		case ATKBD_SCR_1:
+			scroll = 1 - atkbd->release * 2;
+			break;
+		case ATKBD_SCR_2:
+			scroll = 2 - atkbd->release * 4;
+			break;
+		case ATKBD_SCR_4:
+			scroll = 4 - atkbd->release * 8;
+			break;
+		case ATKBD_SCR_8:
+			scroll = 8 - atkbd->release * 16;
+			break;
+		case ATKBD_SCR_CLICK:
+			click = !atkbd->release;
+			break;
 		default:
 			value = atkbd->release ? 0 :
 				(1 + (!atkbd_softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key)));
@@ -305,6 +346,13 @@ static irqreturn_t atkbd_interrupt(struc
 			atkbd_report_key(&atkbd->dev, regs, atkbd->keycode[code], value);
 	}
 
+	if (scroll || click != -1) {
+		input_regs(&atkbd->dev, regs);
+		input_report_key(&atkbd->dev, BTN_MIDDLE, click);
+		input_report_rel(&atkbd->dev, REL_WHEEL, scroll);
+		input_sync(&atkbd->dev);
+	}
+
 	atkbd->release = 0;
 out:
 	return IRQ_HANDLED;
@@ -353,7 +401,7 @@ static int atkbd_command(struct atkbd *a
 	if (receive && param)
 		for (i = 0; i < receive; i++)
 			atkbd->cmdbuf[(receive - 1) - i] = param[i];
-	
+
 	if (command & 0xff)
 		if (atkbd_sendbyte(atkbd, command & 0xff))
 			return (atkbd->cmdcnt = 0) - 1;
@@ -373,7 +421,7 @@ static int atkbd_command(struct atkbd *a
 			atkbd->cmdcnt = 0;
 			break;
 		}
-	
+
 		udelay(1);
 	}
 
@@ -420,7 +468,7 @@ static int atkbd_event(struct input_dev 
 			         | (test_bit(LED_CAPSL,   dev->led) ? 4 : 0);
 		        atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS);
 
-			if (atkbd->set == 4) {
+			if (atkbd->extra) {
 				param[0] = 0;
 				param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
 					 | (test_bit(LED_SLEEP,   dev->led) ? 0x02 : 0)
@@ -466,7 +514,7 @@ static int atkbd_probe(struct atkbd *atk
  */
 
 	if (atkbd_reset)
-		if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT)) 
+		if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT))
 			printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", atkbd->serio->phys);
 
 /*
@@ -529,21 +577,22 @@ static int atkbd_set_3(struct atkbd *atk
 		return 3;
 	}
 
-	if (atkbd_set != 2) 
-		if (!atkbd_command(atkbd, param, ATKBD_CMD_OK_GETID)) {
-			atkbd->id = param[0] << 8 | param[1];
+	if (atkbd_extra) {
+		param[0] = 0x71;
+		if (!atkbd_command(atkbd, param, ATKBD_CMD_EX_ENABLE)) {
+			atkbd->extra = 1;
 			return 2;
 		}
-
-	if (atkbd_set == 4) {
-		param[0] = 0x71;
-		if (!atkbd_command(atkbd, param, ATKBD_CMD_EX_ENABLE))
-			return 4;
 	}
 
-	if (atkbd_set != 3) 
+	if (atkbd_set != 3)
 		return 2;
 
+	if (!atkbd_command(atkbd, param, ATKBD_CMD_OK_GETID)) {
+		atkbd->id = param[0] << 8 | param[1];
+		return 2;
+	}
+
 	param[0] = 3;
 	if (atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET))
 		return 2;
@@ -637,7 +686,7 @@ static void atkbd_connect(struct serio *
 
 	switch (serio->type & SERIO_TYPE) {
 
-		case SERIO_8042_XL: 
+		case SERIO_8042_XL:
 			atkbd->translated = 1;
 		case SERIO_8042:
 			if (serio->write)
@@ -650,7 +699,7 @@ static void atkbd_connect(struct serio *
 			kfree(atkbd);
 			return;
 	}
-			
+
 	if (atkbd->write) {
 		atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
 		atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
@@ -687,7 +736,7 @@ static void atkbd_connect(struct serio *
 			kfree(atkbd);
 			return;
 		}
-		
+
 		atkbd->set = atkbd_set_3(atkbd);
 		atkbd_enable(atkbd);
 
@@ -696,24 +745,32 @@ static void atkbd_connect(struct serio *
 		atkbd->id = 0xab00;
 	}
 
-	if (atkbd->set == 4) {
+	if (atkbd->extra) {
 		atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC);
-		sprintf(atkbd->name, "AT Set 2 Extended keyboard");
+		sprintf(atkbd->name, "AT Set 2 Extra keyboard");
 	} else
 		sprintf(atkbd->name, "AT %s Set %d keyboard",
 			atkbd->translated ? "Translated" : "Raw", atkbd->set);
 
 	sprintf(atkbd->phys, "%s/input0", serio->phys);
 
+	if (atkbd_scroll) {
+		for (i = 0; i < 5; i++)
+			atkbd_set2_keycode[atkbd_scroll_keys[i][1]] = atkbd_scroll_keys[i][0];
+		atkbd->dev.evbit[0] |= BIT(EV_REL);
+		atkbd->dev.relbit[0] = BIT(REL_WHEEL);
+		set_bit(BTN_MIDDLE, atkbd->dev.keybit);
+	}
+
 	if (atkbd->translated) {
 		for (i = 0; i < 128; i++) {
 			atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
 			atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
 		}
-	} else if (atkbd->set == 2) {
-		memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
-	} else {
+	} else if (atkbd->set == 3) {
 		memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
+	} else {
+		memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
 	}
 
 	atkbd->dev.name = atkbd->name;
@@ -724,7 +781,7 @@ static void atkbd_connect(struct serio *
 	atkbd->dev.id.version = atkbd->id;
 
 	for (i = 0; i < 512; i++)
-		if (atkbd->keycode[i] && atkbd->keycode[i] < 255)
+		if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)
 			set_bit(atkbd->keycode[i], atkbd->dev.keybit);
 
 	input_register_device(&atkbd->dev);
@@ -741,46 +798,20 @@ static int atkbd_reconnect(struct serio 
 {
 	struct atkbd *atkbd = serio->private;
 	struct serio_dev *dev = serio->dev;
-	int i;
 
-        if (!dev) {
-                printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
-                return -1;
-        }
+	if (!dev) {
+		printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
+		return -1;
+	}
 
 	if (atkbd->write) {
 		if (atkbd_probe(atkbd))
 			return -1;
-
-		atkbd->set = atkbd_set_3(atkbd);
+		if (atkbd->set != atkbd_set_3(atkbd))
+			return -1;
 		atkbd_enable(atkbd);
-	} else {
-		atkbd->set = 2;
-		atkbd->id = 0xab00;
 	}
 
-	/*
-	 * Here we probably should check if the keyboard has the same set that
-         * it had before and bail out if it's different. But this will most likely
-         * cause new keyboard device be created... and for the user it will look
-         * like keyboard is lost
-	 */
-
-	if (atkbd->translated) {
-		for (i = 0; i < 128; i++) {
-			atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
-			atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
-		}
-	} else if (atkbd->set == 2) {
-		memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
-	} else {
-		memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
-	}
-
-	for (i = 0; i < 512; i++)
-		if (atkbd->keycode[i] && atkbd->keycode[i] < 255)
-			set_bit(atkbd->keycode[i], atkbd->dev.keybit);
-
 	return 0;
 }
 
--- diff/drivers/input/keyboard/hpps2atkbd.h	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/input/keyboard/hpps2atkbd.h	2004-03-09 11:51:49.000000000 +0000
@@ -4,14 +4,9 @@
  * Copyright (c) 2004 Helge Deller <deller@gmx.de>
  * Copyright (c) 2002 Laurent Canet <canetl@esiee.fr>
  * Copyright (c) 2002 Thibaut Varene <varenet@esiee.fr>
+ * Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr>
  *
- * based on linux-2.4's hp_mouse.c & hp_keyb.c
- * 	Copyright (c) 1999 Alex deVries <adevries@thepuffingroup.com>
- *	Copyright (c) 1999-2000 Philipp Rumpf <prumpf@tux.org>
- *	Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr>
- *	Copyright (c) 2000-2001 Thomas Marteau <marteaut@esiee.fr>
- *
- * HP PS/2 AT-compatible Keyboard, found in PA/RISC Workstations
+ * HP PS/2 AT-compatible Keyboard, found in PA/RISC Workstations & Laptops
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -19,87 +14,100 @@
  */
 
 
-#define KBD_UNKNOWN 0
-
-/* Raw SET 2 scancode table */
+/* undefine if you have a RDI PRECISIONBOOK */
+#define STANDARD_KEYBOARD
 
-#if 0
-	/* conflicting keys between a RDI Precisionbook keyboard and a normal HP keyboard */
-        keytable[0x07] = KEY_F1;        /* KEY_F12      */
-        keytable[0x11] = KEY_LEFTCTRL;  /* KEY_LEFTALT  */
-        keytable[0x14] = KEY_CAPSLOCK;  /* KEY_LEFTCTRL */
-        keytable[0x61] = KEY_LEFT;      /* KEY_102ND    */
+#if defined(STANDARD_KEYBOARD)
+# define CONFLICT(x,y) x
+#else
+# define CONFLICT(x,y) y
 #endif
 
+/* sadly RDI (Tadpole) decided to ship a different keyboard layout
+   than HP for their PS/2 laptop keyboard which leads to conflicting
+   keycodes between a normal HP PS/2 keyboard and a RDI Precisionbook.
+                                HP:		RDI:            */
+#define C_07	CONFLICT(	KEY_F12,	KEY_F1		)
+#define C_11	CONFLICT(	KEY_LEFTALT,	KEY_LEFTCTRL	)
+#define C_14	CONFLICT(	KEY_LEFTCTRL,	KEY_CAPSLOCK	)
+#define C_58	CONFLICT(	KEY_CAPSLOCK,	KEY_RIGHTCTRL	)
+#define C_61	CONFLICT(	KEY_102ND,	KEY_LEFT	)
 
-static unsigned char atkbd_set2_keycode[512] = {
+/* Raw SET 2 scancode table */
 
-	/* 00 */  KBD_UNKNOWN,  KEY_F9,        KBD_UNKNOWN,   KEY_F5,        KEY_F3,        KEY_F1,       KEY_F2,        KEY_F1,
-	/* 08 */  KEY_ESC,      KEY_F10,       KEY_F8,        KEY_F6,        KEY_F4,        KEY_TAB,      KEY_GRAVE,     KEY_F2,
-	/* 10 */  KBD_UNKNOWN,  KEY_LEFTCTRL,  KEY_LEFTSHIFT, KBD_UNKNOWN,   KEY_CAPSLOCK,  KEY_Q,        KEY_1,         KEY_F3,
-	/* 18 */  KBD_UNKNOWN,  KEY_LEFTALT,   KEY_Z,         KEY_S,         KEY_A,         KEY_W,        KEY_2,         KEY_F4,
-	/* 20 */  KBD_UNKNOWN,  KEY_C,         KEY_X,         KEY_D,         KEY_E,         KEY_4,        KEY_3,         KEY_F5,
-	/* 28 */  KBD_UNKNOWN,  KEY_SPACE,     KEY_V,         KEY_F,         KEY_T,         KEY_R,        KEY_5,         KEY_F6,
-	/* 30 */  KBD_UNKNOWN,  KEY_N,         KEY_B,         KEY_H,         KEY_G,         KEY_Y,        KEY_6,         KEY_F7,
-	/* 38 */  KBD_UNKNOWN,  KEY_RIGHTALT,  KEY_M,         KEY_J,         KEY_U,         KEY_7,        KEY_8,         KEY_F8,
-	/* 40 */  KBD_UNKNOWN,  KEY_COMMA,     KEY_K,         KEY_I,         KEY_O,         KEY_0,        KEY_9,         KEY_F9,
-	/* 48 */  KBD_UNKNOWN,  KEY_DOT,       KEY_SLASH,     KEY_L,         KEY_SEMICOLON, KEY_P,        KEY_MINUS,     KEY_F10,
-	/* 50 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_APOSTROPHE,KBD_UNKNOWN,   KEY_LEFTBRACE, KEY_EQUAL,    KEY_F11,       KEY_SYSRQ,
-	/* 58 */  KEY_CAPSLOCK, KEY_RIGHTSHIFT,KEY_ENTER,     KEY_RIGHTBRACE,KEY_BACKSLASH, KEY_BACKSLASH,KEY_F12,       KEY_SCROLLLOCK,
-	/* 60 */  KEY_DOWN,     KEY_LEFT,      KEY_PAUSE,     KEY_UP,        KEY_DELETE,    KEY_END,      KEY_BACKSPACE, KEY_INSERT,
-	/* 68 */  KBD_UNKNOWN,  KEY_KP1,       KEY_RIGHT,     KEY_KP4,       KEY_KP7,       KEY_PAGEDOWN, KEY_HOME,      KEY_PAGEUP,
-	/* 70 */  KEY_KP0,      KEY_KPDOT,     KEY_KP2,       KEY_KP5,       KEY_KP6,       KEY_KP8,      KEY_ESC,       KEY_NUMLOCK,
-	/* 78 */  KEY_F11,      KEY_KPPLUS,    KEY_KP3,       KEY_KPMINUS,   KEY_KPASTERISK,KEY_KP9,      KEY_SCROLLLOCK,KEY_103RD,
-	/* 80 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 88 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 90 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 98 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* a0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* a8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* b0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* b8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* c0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* c8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* d0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* d8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* e0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* e8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* f0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* f8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-
-	/* These are offset for escaped keycodes: */
-
-	/* 00 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KEY_F7,        KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 08 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KEY_LEFTMETA,  KEY_RIGHTMETA, KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 10 */  KBD_UNKNOWN,  KEY_RIGHTALT,  KBD_UNKNOWN,   KBD_UNKNOWN,   KEY_RIGHTCTRL, KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 18 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 20 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 28 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 30 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 38 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 40 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 48 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_KPSLASH,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 50 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 58 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_KPENTER,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 60 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 68 */  KBD_UNKNOWN,  KEY_END,       KBD_UNKNOWN,   KEY_LEFT,      KEY_HOME,      KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 70 */  KEY_INSERT,   KEY_DELETE,    KEY_DOWN,      KBD_UNKNOWN,   KEY_RIGHT,     KEY_UP,       KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 78 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_PAGEDOWN,  KBD_UNKNOWN,   KEY_SYSRQ,     KEY_PAGEUP,   KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 80 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 88 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 90 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 98 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* a0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* a8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* b0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* b8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* c0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* c8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* d0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* d8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* e0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* e8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* f0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* f8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN
+/* 00 */  KEY_RESERVED, KEY_F9,        KEY_RESERVED,  KEY_F5,        KEY_F3,        KEY_F1,       KEY_F2,        C_07,
+/* 08 */  KEY_ESC,      KEY_F10,       KEY_F8,        KEY_F6,        KEY_F4,        KEY_TAB,      KEY_GRAVE,     KEY_F2,
+/* 10 */  KEY_RESERVED, C_11,          KEY_LEFTSHIFT, KEY_RESERVED,  C_14,          KEY_Q,        KEY_1,         KEY_F3,
+/* 18 */  KEY_RESERVED, KEY_LEFTALT,   KEY_Z,         KEY_S,         KEY_A,         KEY_W,        KEY_2,         KEY_F4,
+/* 20 */  KEY_RESERVED, KEY_C,         KEY_X,         KEY_D,         KEY_E,         KEY_4,        KEY_3,         KEY_F5,
+/* 28 */  KEY_RESERVED, KEY_SPACE,     KEY_V,         KEY_F,         KEY_T,         KEY_R,        KEY_5,         KEY_F6,
+/* 30 */  KEY_RESERVED, KEY_N,         KEY_B,         KEY_H,         KEY_G,         KEY_Y,        KEY_6,         KEY_F7,
+/* 38 */  KEY_RESERVED, KEY_RIGHTALT,  KEY_M,         KEY_J,         KEY_U,         KEY_7,        KEY_8,         KEY_F8,
+/* 40 */  KEY_RESERVED, KEY_COMMA,     KEY_K,         KEY_I,         KEY_O,         KEY_0,        KEY_9,         KEY_F9,
+/* 48 */  KEY_RESERVED, KEY_DOT,       KEY_SLASH,     KEY_L,         KEY_SEMICOLON, KEY_P,        KEY_MINUS,     KEY_F10,
+/* 50 */  KEY_RESERVED, KEY_RESERVED,  KEY_APOSTROPHE,KEY_RESERVED,  KEY_LEFTBRACE, KEY_EQUAL,    KEY_F11,       KEY_SYSRQ,
+/* 58 */  C_58,         KEY_RIGHTSHIFT,KEY_ENTER,     KEY_RIGHTBRACE,KEY_BACKSLASH, KEY_BACKSLASH,KEY_F12,       KEY_SCROLLLOCK,
+/* 60 */  KEY_DOWN,     C_61,          KEY_PAUSE,     KEY_UP,        KEY_DELETE,    KEY_END,      KEY_BACKSPACE, KEY_INSERT,
+/* 68 */  KEY_RESERVED, KEY_KP1,       KEY_RIGHT,     KEY_KP4,       KEY_KP7,       KEY_PAGEDOWN, KEY_HOME,      KEY_PAGEUP,
+/* 70 */  KEY_KP0,      KEY_KPDOT,     KEY_KP2,       KEY_KP5,       KEY_KP6,       KEY_KP8,      KEY_ESC,       KEY_NUMLOCK,
+/* 78 */  KEY_F11,      KEY_KPPLUS,    KEY_KP3,       KEY_KPMINUS,   KEY_KPASTERISK,KEY_KP9,      KEY_SCROLLLOCK,KEY_103RD,
+/* 80 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 88 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 90 */  KEY_RESERVED, KEY_RIGHTALT,  KEY_SYSRQ,     KEY_RESERVED,  KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 98 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_CAPSLOCK, KEY_RESERVED,  KEY_LEFTMETA,
+/* a0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RIGHTMETA,
+/* a8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_COMPOSE,
+/* b0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* b8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* c0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* c8 */  KEY_RESERVED, KEY_RESERVED,  KEY_KPSLASH,   KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* d0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* d8 */  KEY_RESERVED, KEY_RESERVED,  KEY_KPENTER,   KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* e0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* e8 */  KEY_RESERVED, KEY_END,       KEY_RESERVED,  KEY_LEFT,      KEY_HOME,      KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* f0 */  KEY_INSERT,   KEY_DELETE,    KEY_DOWN,      KEY_RESERVED,  KEY_RIGHT,     KEY_UP,       KEY_RESERVED,  KEY_PAUSE,
+/* f8 */  KEY_RESERVED, KEY_RESERVED,  KEY_PAGEDOWN,  KEY_RESERVED,  KEY_SYSRQ,     KEY_PAGEUP,   KEY_RESERVED,  KEY_RESERVED,
+
+/* These are offset for escaped keycodes: */
+
+/* 00 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_F7,        KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 08 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_LEFTMETA,  KEY_RIGHTMETA, KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 10 */  KEY_RESERVED, KEY_RIGHTALT,  KEY_RESERVED,  KEY_RESERVED,  KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 18 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 20 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 28 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 30 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 38 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 40 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 48 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 50 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 58 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 60 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 68 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 70 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 78 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 80 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 88 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 90 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 98 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* a0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* a8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* b0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* b8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* c0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* c8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* d0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* d8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* e0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* e8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* f0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* f8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED
+
+#undef STANDARD_KEYBOARD
+#undef CONFLICT
+#undef C_07
+#undef C_11
+#undef C_14
+#undef C_58
+#undef C_61
 
-};
--- diff/drivers/input/keyboard/sunkbd.c	2003-08-20 14:16:09.000000000 +0100
+++ source/drivers/input/keyboard/sunkbd.c	2004-03-09 11:51:49.000000000 +0000
@@ -77,6 +77,7 @@ struct sunkbd {
 	struct input_dev dev;
 	struct serio *serio;
 	struct work_struct tq;
+	wait_queue_head_t wait;
 	char name[64];
 	char phys[32];
 	char type;
@@ -96,11 +97,13 @@ static irqreturn_t sunkbd_interrupt(stru
 
 	if (sunkbd->reset <= -1) {		/* If cp[i] is 0xff, sunkbd->reset will stay -1. */
 		sunkbd->reset = data;		/* The keyboard sends 0xff 0xff 0xID on powerup */
+		wake_up_interruptible(&sunkbd->wait);
 		goto out;
 	}
 
 	if (sunkbd->layout == -1) {
 		sunkbd->layout = data;
+		wake_up_interruptible(&sunkbd->wait);
 		goto out;
 	}
 
@@ -176,22 +179,19 @@ static int sunkbd_event(struct input_dev
 
 static int sunkbd_initialize(struct sunkbd *sunkbd)
 {
-	int t;
-
-	t = 1000;
 	sunkbd->reset = -2;
 	sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET);
-	while (sunkbd->reset < 0 && --t) mdelay(1);
-	if (!t) return -1;
+	wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
+	if (sunkbd->reset <0)
+		return -1;
 
 	sunkbd->type = sunkbd->reset;
 
 	if (sunkbd->type == 4) {	/* Type 4 keyboard */
-		t = 250;
 		sunkbd->layout = -2;
 		sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT);
-		while (sunkbd->layout < 0 && --t) mdelay(1);
-		if (!t) return -1;
+		wait_event_interruptible_timeout(sunkbd->wait, sunkbd->layout >= 0, HZ/4);
+		if (sunkbd->layout < 0) return -1;
 		if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5;
 	}
 
@@ -206,9 +206,8 @@ static int sunkbd_initialize(struct sunk
 static void sunkbd_reinit(void *data)
 {
 	struct sunkbd *sunkbd = data;
-	int t = 1000;
 
-	while (sunkbd->reset < 0 && --t) mdelay(1);
+	wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
 
 	sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED);
 	sunkbd->serio->write(sunkbd->serio, 
@@ -239,6 +238,7 @@ static void sunkbd_connect(struct serio 
 	memset(sunkbd, 0, sizeof(struct sunkbd));
 
 	init_input_dev(&sunkbd->dev);
+	init_waitqueue_head(&sunkbd->wait);
 
 	sunkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP);
 	sunkbd->dev.ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML);
@@ -275,7 +275,7 @@ static void sunkbd_connect(struct serio 
 		set_bit(sunkbd->keycode[i], sunkbd->dev.keybit);
 	clear_bit(0, sunkbd->dev.keybit);
 
-	sprintf(sunkbd->name, "%s/input", serio->phys);
+	sprintf(sunkbd->phys, "%s/input0", serio->phys);
 
 	sunkbd->dev.name = sunkbd->name;
 	sunkbd->dev.phys = sunkbd->phys;
--- diff/drivers/input/misc/Kconfig	2003-09-30 15:46:14.000000000 +0100
+++ source/drivers/input/misc/Kconfig	2004-03-09 11:51:49.000000000 +0000
@@ -54,12 +54,3 @@ config INPUT_UINPUT
 	  To compile this driver as a module, choose M here: the
 	  module will be called uinput.
 
-config INPUT_GSC
-	tristate "PA-RISC GSC PS/2 keyboard/mouse support"
-	depends on GSC && INPUT && INPUT_MISC
-	help
-	  Say Y here if you have a PS/2 keyboard and/or mouse attached
-	  to your PA-RISC box.	HP run the keyboard in AT mode rather than
-	  XT mode like everyone else, so we need our own driver.
-	  Furthermore, the GSC PS/2 controller shares IRQ between mouse and
-	  keyboard.
--- diff/drivers/input/misc/Makefile	2003-02-26 16:00:54.000000000 +0000
+++ source/drivers/input/misc/Makefile	2004-03-09 11:51:49.000000000 +0000
@@ -9,4 +9,3 @@ obj-$(CONFIG_INPUT_PCSPKR)		+= pcspkr.o
 obj-$(CONFIG_INPUT_M68K_BEEP)		+= m68kspkr.o
 obj-$(CONFIG_INPUT_98SPKR)		+= 98spkr.o
 obj-$(CONFIG_INPUT_UINPUT)		+= uinput.o
-obj-$(CONFIG_INPUT_GSC)			+= gsc_ps2.o
--- diff/drivers/input/mouse/98busmouse.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/input/mouse/98busmouse.c	2004-03-09 11:51:49.000000000 +0000
@@ -74,6 +74,8 @@ static int pc98bm_irq = PC98BM_IRQ;
 module_param_named(irq, pc98bm_irq, uint, 0);
 MODULE_PARM_DESC(irq, "IRQ number (13=default)");
 
+__obsolete_setup("pc98bm_irq=");
+
 static int pc98bm_used = 0;
 
 static irqreturn_t pc98bm_interrupt(int irq, void *dev_id, struct pt_regs *regs);
--- diff/drivers/input/mouse/Kconfig	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/input/mouse/Kconfig	2004-03-09 11:51:49.000000000 +0000
@@ -17,6 +17,7 @@ config MOUSE_PS2
 	depends on INPUT && INPUT_MOUSE
 	select SERIO
 	select SERIO_I8042 if PC
+	select SERIO_GSCPS2 if GSC
 	---help---
 	  Say Y here if you have a PS/2 mouse connected to your system. This
 	  includes the standard 2 or 3-button PS/2 mouse, as well as PS/2
@@ -117,6 +118,19 @@ config MOUSE_RISCPC
 	  To compile this driver as a module, choose M here: the
 	  module will be called rpcmouse.
 
+config MOUSE_VSXXXAA
+	tristate "DEC VSXXX-AA/GA mouse and tablet"
+	depends on INPUT && INPUT_MOUSE
+	select SERIO
+	help
+	  Say Y (or M) if you want to use a DEC VSXXX-AA (hockey
+	  puck) or a VSXXX-GA (rectangular) mouse. Theses mice are
+	  typically used on DECstations or VAXstations, but can also
+	  be used on any box capable of RS232 (with some adaptor
+	  described in the source file). This driver should, in theory,
+	  also work with the digitizer DEC produced, but it isn't tested
+	  with that (I don't have the hardware yet).
+
 config MOUSE_PC9800
 	tristate "NEC PC-9800 busmouse"
 	depends on X86_PC9800 && INPUT && INPUT_MOUSE && ISA
--- diff/drivers/input/mouse/Makefile	2003-06-30 10:07:33.000000000 +0100
+++ source/drivers/input/mouse/Makefile	2004-03-09 11:51:49.000000000 +0000
@@ -13,5 +13,6 @@ obj-$(CONFIG_MOUSE_PC110PAD)	+= pc110pad
 obj-$(CONFIG_MOUSE_PC9800)	+= 98busmouse.o
 obj-$(CONFIG_MOUSE_PS2)		+= psmouse.o
 obj-$(CONFIG_MOUSE_SERIAL)	+= sermouse.o
+obj-$(CONFIG_MOUSE_VSXXXAA)	+= vsxxxaa.o
 
 psmouse-objs  := psmouse-base.o logips2pp.o synaptics.o
--- diff/drivers/input/mouse/inport.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/input/mouse/inport.c	2004-03-09 11:51:49.000000000 +0000
@@ -85,6 +85,8 @@ static int inport_irq = INPORT_IRQ;
 module_param_named(irq, inport_irq, uint, 0);
 MODULE_PARM_DESC(irq, "IRQ number (5=default)");
 
+__obsolete_setup("inport_irq=");
+
 static int inport_used;
 
 static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
--- diff/drivers/input/mouse/logibm.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/input/mouse/logibm.c	2004-03-09 11:51:49.000000000 +0000
@@ -75,6 +75,8 @@ static int logibm_irq = LOGIBM_IRQ;
 module_param_named(irq, logibm_irq, uint, 0);
 MODULE_PARM_DESC(irq, "IRQ number (5=default)");
 
+__obsolete_setup("logibm_irq=");
+
 static int logibm_used = 0;
 
 static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs);
--- diff/drivers/input/mouse/psmouse-base.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/input/mouse/psmouse-base.c	2004-03-09 11:51:49.000000000 +0000
@@ -47,6 +47,12 @@ unsigned int psmouse_resetafter;
 module_param_named(resetafter, psmouse_resetafter, uint, 0);
 MODULE_PARM_DESC(resetafter, "Reset Synaptics Touchpad after so many bad packets (0 = never).");
 
+__obsolete_setup("psmouse_noext");
+__obsolete_setup("psmouse_resolution=");
+__obsolete_setup("psmouse_smartscroll=");
+__obsolete_setup("psmouse_resetafter=");
+__obsolete_setup("psmouse_rate=");
+
 static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2"};
 
 /*
@@ -163,14 +169,14 @@ static irqreturn_t psmouse_interrupt(str
 		       psmouse->name, psmouse->phys, psmouse->pktcnt);
 		psmouse->pktcnt = 0;
 	}
-	
+
 	psmouse->last = jiffies;
 	psmouse->packet[psmouse->pktcnt++] = data;
 
 	if (psmouse->packet[0] == PSMOUSE_RET_BAT) {
 		if (psmouse->pktcnt == 1)
 			goto out;
-		
+
 		if (psmouse->pktcnt == 2) {
 			if (psmouse->packet[1] == PSMOUSE_RET_ID) {
 				psmouse->state = PSMOUSE_IGNORE;
@@ -258,7 +264,7 @@ int psmouse_command(struct psmouse *psmo
 			return (psmouse->cmdcnt = 0) - 1;
 
 	while (psmouse->cmdcnt && timeout--) {
-	
+
 		if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_RESET_BAT &&
 				timeout > 100000) /* do not run in a endless loop */
 			timeout = 100000; /* 1 sec */
@@ -442,7 +448,7 @@ static int psmouse_probe(struct psmouse 
  */
 
 	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS))
-		return -1;
+		printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", psmouse->serio->phys);
 
 /*
  * And here we try to determine if it has any extensions over the
@@ -497,7 +503,7 @@ static void psmouse_set_rate(struct psmo
 static void psmouse_initialize(struct psmouse *psmouse)
 {
 	unsigned char param[2];
-	
+
 /*
  * We set the mouse report rate, resolution and scaling.
  */
@@ -571,7 +577,7 @@ static void psmouse_disconnect(struct se
 static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
 {
 	struct psmouse *psmouse;
-	
+
 	if ((serio->type & SERIO_TYPE) != SERIO_8042 &&
 	    (serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU)
 		return;
@@ -603,7 +609,7 @@ static void psmouse_connect(struct serio
 		serio->private = NULL;
 		return;
 	}
-	
+
 	sprintf(psmouse->devname, "%s %s %s",
 		psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
 	sprintf(psmouse->phys, "%s/input0",
@@ -617,7 +623,7 @@ static void psmouse_connect(struct serio
 	psmouse->dev.id.version = psmouse->model;
 
 	input_register_device(&psmouse->dev);
-	
+
 	printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
 
 	psmouse_initialize(psmouse);
--- diff/drivers/input/mouse/synaptics.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/input/mouse/synaptics.c	2004-03-09 11:51:49.000000000 +0000
@@ -435,6 +435,8 @@ int synaptics_init(struct psmouse *psmou
 		goto init_fail;
 	}
 
+	priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
+
 	if (SYN_CAP_EXTENDED(priv->capabilities) && SYN_CAP_PASS_THROUGH(priv->capabilities))
        		synaptics_pt_create(psmouse);
 
@@ -602,19 +604,42 @@ static void synaptics_process_packet(str
 	input_sync(dev);
 }
 
-static int synaptics_validate_byte(struct psmouse *psmouse)
+static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type)
 {
-	static unsigned char newabs_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
-	static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
-	static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
-	static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
-	struct synaptics_data *priv = psmouse->private;
-	int idx = psmouse->pktcnt - 1;
+	static unsigned char newabs_mask[]	= { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
+	static unsigned char newabs_rel_mask[]	= { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
+	static unsigned char newabs_rslt[]	= { 0x80, 0x00, 0x00, 0xC0, 0x00 };
+	static unsigned char oldabs_mask[]	= { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
+	static unsigned char oldabs_rslt[]	= { 0xC0, 0x00, 0x00, 0x80, 0x00 };
+
+	switch (pkt_type) {
+		case SYN_NEWABS:
+		case SYN_NEWABS_RELAXED:
+			return (packet[idx] & newabs_rel_mask[idx]) == newabs_rslt[idx];
+
+		case SYN_NEWABS_STRICT:
+			return (packet[idx] & newabs_mask[idx]) == newabs_rslt[idx];
+
+		case SYN_OLDABS:
+			return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx];
 
-	if (SYN_MODEL_NEWABS(priv->model_id))
-		return (psmouse->packet[idx] & newabs_mask[idx]) == newabs_rslt[idx];
-	else
-		return (psmouse->packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx];
+		default:
+			printk(KERN_ERR "synaptics: unknown packet type %d\n", pkt_type);
+			return 0;
+	}
+}
+
+static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse)
+{
+	int i;
+
+	for (i = 0; i < 5; i++)
+		if (!synaptics_validate_byte(psmouse->packet, i, SYN_NEWABS_STRICT)) {
+			printk(KERN_INFO "synaptics: using relaxed packet validation\n");
+			return SYN_NEWABS_RELAXED;
+		}
+
+	return SYN_NEWABS_STRICT;
 }
 
 void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
@@ -630,13 +655,17 @@ void synaptics_process_byte(struct psmou
 			printk(KERN_NOTICE "Synaptics driver resynced.\n");
 		}
 
+		if (unlikely(priv->pkt_type == SYN_NEWABS))
+			priv->pkt_type = synaptics_detect_pkt_type(psmouse);
+
 		if (psmouse->ptport && psmouse->ptport->serio.dev && synaptics_is_pt_packet(psmouse->packet))
 			synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet);
 		else
 			synaptics_process_packet(psmouse);
 		psmouse->pktcnt = 0;
 
-	} else if (psmouse->pktcnt && !synaptics_validate_byte(psmouse)) {
+	} else if (psmouse->pktcnt &&
+		   !synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type)) {
 		printk(KERN_WARNING "Synaptics driver lost sync at byte %d\n", psmouse->pktcnt);
 		psmouse->pktcnt = 0;
 		if (++priv->out_of_sync == psmouse_resetafter) {
--- diff/drivers/input/mouse/synaptics.h	2004-01-19 10:22:56.000000000 +0000
+++ source/drivers/input/mouse/synaptics.h	2004-03-09 11:51:49.000000000 +0000
@@ -70,6 +70,12 @@ extern int synaptics_init(struct psmouse
 #define SYN_PS_SET_MODE2		0x14
 #define SYN_PS_CLIENT_CMD		0x28
 
+/* synaptics packet types */
+#define SYN_NEWABS			0
+#define SYN_NEWABS_STRICT		1
+#define SYN_NEWABS_RELAXED		2
+#define SYN_OLDABS			3
+
 /*
  * A structure to describe the state of the touchpad hardware (buttons and pad)
  */
@@ -103,6 +109,7 @@ struct synaptics_data {
 	/* Data for normal processing */
 	unsigned int out_of_sync;		/* # of packets out of sync */
 	int old_w;				/* Previous w value */
+	unsigned char pkt_type;			/* packet type - old, new, etc */
 };
 
 #endif /* _SYNAPTICS_H */
--- diff/drivers/input/serio/Kconfig	2003-09-30 15:46:14.000000000 +0100
+++ source/drivers/input/serio/Kconfig	2004-03-09 11:51:49.000000000 +0000
@@ -20,6 +20,7 @@ config SERIO_I8042
 	tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86
 	default y
 	select SERIO
+	depends on !PARISC
 	---help---
 	  i8042 is the chip over which the standard AT keyboard and PS/2
 	  mouse are connected to the computer. If you use these devices,
@@ -48,6 +49,7 @@ config SERIO_SERPORT
 config SERIO_CT82C710
 	tristate "ct82c710 Aux port controller"
 	depends on SERIO
+	depends on !PARISC
 	---help---
 	  Say Y here if you have a Texas Instruments TravelMate notebook
 	  equipped with the ct82c710 chip and want to use a mouse connected
@@ -105,6 +107,20 @@ config SERIO_98KBD
 	  To compile this driver as a module, choose M here: the
 	  module will be called 98kbd-io.
 
+config SERIO_GSCPS2
+	tristate "HP GSC PS/2 keyboard and PS/2 mouse controller"
+	depends on GSC && SERIO
+	default y
+	help
+	  This driver provides support for the PS/2 ports on PA-RISC machines
+	  over which HP PS/2 keyboards and PS/2 mice may be connected.
+	  If you use these devices, you'll need to say Y here.
+
+	  It's safe to enable this driver, so if unsure, say Y.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gscps2.
+
 config SERIO_PCIPS2
 	tristate "PCI PS/2 keyboard and PS/2 mouse controller"
 	depends on PCI && SERIO
--- diff/drivers/input/serio/Makefile	2003-06-30 10:07:29.000000000 +0100
+++ source/drivers/input/serio/Makefile	2004-03-09 11:51:49.000000000 +0000
@@ -14,4 +14,5 @@ obj-$(CONFIG_SERIO_SA1111)	+= sa1111ps2.
 obj-$(CONFIG_SERIO_AMBAKMI)	+= ambakmi.o
 obj-$(CONFIG_SERIO_Q40KBD)	+= q40kbd.o
 obj-$(CONFIG_SERIO_98KBD)	+= 98kbd-io.o
+obj-$(CONFIG_SERIO_GSCPS2)	+= gscps2.o
 obj-$(CONFIG_SERIO_PCIPS2)	+= pcips2.o
--- diff/drivers/input/serio/i8042.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/input/serio/i8042.c	2004-03-09 11:51:49.000000000 +0000
@@ -52,6 +52,13 @@ static unsigned int i8042_dumbkbd;
 module_param_named(dumbkbd, i8042_dumbkbd, bool, 0);
 MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard");
 
+__obsolete_setup("i8042_noaux");
+__obsolete_setup("i8042_nomux");
+__obsolete_setup("i8042_unlock");
+__obsolete_setup("i8042_reset");
+__obsolete_setup("i8042_direct");
+__obsolete_setup("i8042_dumbkbd");
+
 #undef DEBUG
 #include "i8042.h"
 
@@ -379,6 +386,8 @@ static irqreturn_t i8042_interrupt(int i
 	unsigned int dfl;
 	int ret;
 
+	mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
+
 	spin_lock_irqsave(&i8042_lock, flags);
 	str = i8042_read_status();
 	if (str & I8042_STR_OBF)
@@ -433,7 +442,6 @@ static irqreturn_t i8042_interrupt(int i
 irq_ret:
 	ret = 1;
 out:
-	mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
 	return IRQ_RETVAL(ret);
 }
 
@@ -522,6 +530,11 @@ static int __init i8042_check_mux(struct
 
 	if (i8042_enable_mux_mode(values, &mux_version))
 		return -1;
+	
+	/* Workaround for broken chips which seem to support MUX, but in reality don't. */
+	/* They all report version 12.10 */
+	if (mux_version == 0xCA)
+		return -1;
 
 	printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",
 		(mux_version >> 4) & 0xf, mux_version & 0xf);
@@ -709,14 +722,6 @@ static int i8042_controller_init(void)
 	}
 
 /*
- * If the chip is configured into nontranslated mode by the BIOS, don't
- * bother enabling translating and be happy.
- */
-
-	if (~i8042_ctr & I8042_CTR_XLATE)
-		i8042_direct = 1;
-
-/*
  * Set nontranslated mode for the kbd interface if requested by an option.
  * After this the kbd interface becomes a simple serial in/out, like the aux
  * interface is. We don't do this by default, since it can confuse notebook
--- diff/drivers/input/serio/serio.c	2004-01-19 10:22:56.000000000 +0000
+++ source/drivers/input/serio/serio.c	2004-03-09 11:51:49.000000000 +0000
@@ -195,6 +195,9 @@ irqreturn_t serio_interrupt(struct serio
                 ret = serio->dev->interrupt(serio, data, flags, regs);
 	} else {
 		if (!flags) {
+			if ((serio->type == SERIO_8042 ||
+				serio->type == SERIO_8042_XL) && (data != 0xaa))
+					return ret;
 			serio_rescan(serio);
 			ret = IRQ_HANDLED;
 		}
--- diff/drivers/macintosh/mediabay.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/macintosh/mediabay.c	2004-03-09 11:51:50.000000000 +0000
@@ -10,8 +10,6 @@
  *  as published by the Free Software Foundation; either version
  *  2 of the License, or (at your option) any later version.
  */
-#define __KERNEL_SYSCALLS__
-
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -21,7 +19,6 @@
 #include <linux/timer.h>
 #include <linux/hdreg.h>
 #include <linux/stddef.h>
-#include <linux/unistd.h>
 #include <linux/init.h>
 #include <linux/ide.h>
 #include <asm/prom.h>
--- diff/drivers/mca/mca-bus.c	2003-08-26 10:00:52.000000000 +0100
+++ source/drivers/mca/mca-bus.c	2004-03-09 11:51:50.000000000 +0000
@@ -106,6 +106,7 @@ int __init mca_register_device(int bus, 
 	sprintf (mca_dev->dev.bus_id, "%02d:%02X", bus, mca_dev->slot);
 	mca_dev->dma_mask = mca_bus->default_dma_mask;
 	mca_dev->dev.dma_mask = &mca_dev->dma_mask;
+	mca_dev->dev.coherent_dma_mask = mca_dev->dma_mask;
 
 	if (device_register(&mca_dev->dev))
 		return 0;
--- diff/drivers/md/Kconfig	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/md/Kconfig	2004-03-09 11:51:50.000000000 +0000
@@ -162,14 +162,6 @@ config BLK_DEV_DM
 
 	  If unsure, say N.
 
-config DM_IOCTL_V4
-	bool "ioctl interface version 4"
-	depends on BLK_DEV_DM
-	default y
-	---help---
-	  Recent tools use a new version of the ioctl interface, only
-          select this option if you intend using such tools.
-
 config DM_CRYPT
 	tristate "Crypt target support"
 	depends on BLK_DEV_DM && EXPERIMENTAL
--- diff/drivers/md/dm-crypt.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/md/dm-crypt.c	2004-03-09 11:51:50.000000000 +0000
@@ -621,7 +621,8 @@ crypt_clone(struct crypt_config *cc, str
 	return clone;
 }
 
-static int crypt_map(struct dm_target *ti, struct bio *bio)
+static int crypt_map(struct dm_target *ti, struct bio *bio,
+		     union map_info *map_context)
 {
 	struct crypt_config *cc = (struct crypt_config *) ti->private;
 	struct crypt_io *io = mempool_alloc(cc->io_pool, GFP_NOIO);
@@ -739,6 +740,7 @@ static int crypt_status(struct dm_target
 
 static struct target_type crypt_target = {
 	.name   = "crypt",
+	.version= {1, 0, 0},
 	.module = THIS_MODULE,
 	.ctr    = crypt_ctr,
 	.dtr    = crypt_dtr,
--- diff/drivers/md/dm-ioctl.c	2003-08-20 14:16:09.000000000 +0100
+++ source/drivers/md/dm-ioctl.c	2004-03-09 11:51:50.000000000 +0000
@@ -1,13 +1,1343 @@
 /*
- * Copyright (C) 2003 Sistina Software (UK) Limited.
+ * Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
  *
  * This file is released under the GPL.
  */
 
+#include "dm.h"
+
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/devfs_fs_kernel.h>
 #include <linux/dm-ioctl.h>
 
-#ifdef CONFIG_DM_IOCTL_V4
-#include "dm-ioctl-v4.c"
-#else
-#include "dm-ioctl-v1.c"
-#endif
+#include <asm/uaccess.h>
+
+#define DM_DRIVER_EMAIL "dm@uk.sistina.com"
+
+/*-----------------------------------------------------------------
+ * The ioctl interface needs to be able to look up devices by
+ * name or uuid.
+ *---------------------------------------------------------------*/
+struct hash_cell {
+	struct list_head name_list;
+	struct list_head uuid_list;
+
+	char *name;
+	char *uuid;
+	struct mapped_device *md;
+	struct dm_table *new_map;
+};
+
+struct vers_iter {
+    size_t param_size;
+    struct dm_target_versions *vers, *old_vers;
+    char *end;
+    uint32_t flags;
+};
+
+
+#define NUM_BUCKETS 64
+#define MASK_BUCKETS (NUM_BUCKETS - 1)
+static struct list_head _name_buckets[NUM_BUCKETS];
+static struct list_head _uuid_buckets[NUM_BUCKETS];
+
+void dm_hash_remove_all(void);
+
+/*
+ * Guards access to both hash tables.
+ */
+static DECLARE_RWSEM(_hash_lock);
+
+static void init_buckets(struct list_head *buckets)
+{
+	unsigned int i;
+
+	for (i = 0; i < NUM_BUCKETS; i++)
+		INIT_LIST_HEAD(buckets + i);
+}
+
+int dm_hash_init(void)
+{
+	init_buckets(_name_buckets);
+	init_buckets(_uuid_buckets);
+	devfs_mk_dir(DM_DIR);
+	return 0;
+}
+
+void dm_hash_exit(void)
+{
+	dm_hash_remove_all();
+	devfs_remove(DM_DIR);
+}
+
+/*-----------------------------------------------------------------
+ * Hash function:
+ * We're not really concerned with the str hash function being
+ * fast since it's only used by the ioctl interface.
+ *---------------------------------------------------------------*/
+static unsigned int hash_str(const char *str)
+{
+	const unsigned int hash_mult = 2654435387U;
+	unsigned int h = 0;
+
+	while (*str)
+		h = (h + (unsigned int) *str++) * hash_mult;
+
+	return h & MASK_BUCKETS;
+}
+
+/*-----------------------------------------------------------------
+ * Code for looking up a device by name
+ *---------------------------------------------------------------*/
+static struct hash_cell *__get_name_cell(const char *str)
+{
+	struct hash_cell *hc;
+	unsigned int h = hash_str(str);
+
+	list_for_each_entry (hc, _name_buckets + h, name_list)
+		if (!strcmp(hc->name, str))
+			return hc;
+
+	return NULL;
+}
+
+static struct hash_cell *__get_uuid_cell(const char *str)
+{
+	struct hash_cell *hc;
+	unsigned int h = hash_str(str);
+
+	list_for_each_entry (hc, _uuid_buckets + h, uuid_list)
+		if (!strcmp(hc->uuid, str))
+			return hc;
+
+	return NULL;
+}
+
+/*-----------------------------------------------------------------
+ * Inserting, removing and renaming a device.
+ *---------------------------------------------------------------*/
+static inline char *kstrdup(const char *str)
+{
+	char *r = kmalloc(strlen(str) + 1, GFP_KERNEL);
+	if (r)
+		strcpy(r, str);
+	return r;
+}
+
+static struct hash_cell *alloc_cell(const char *name, const char *uuid,
+				    struct mapped_device *md)
+{
+	struct hash_cell *hc;
+
+	hc = kmalloc(sizeof(*hc), GFP_KERNEL);
+	if (!hc)
+		return NULL;
+
+	hc->name = kstrdup(name);
+	if (!hc->name) {
+		kfree(hc);
+		return NULL;
+	}
+
+	if (!uuid)
+		hc->uuid = NULL;
+
+	else {
+		hc->uuid = kstrdup(uuid);
+		if (!hc->uuid) {
+			kfree(hc->name);
+			kfree(hc);
+			return NULL;
+		}
+	}
+
+	INIT_LIST_HEAD(&hc->name_list);
+	INIT_LIST_HEAD(&hc->uuid_list);
+	hc->md = md;
+	hc->new_map = NULL;
+	return hc;
+}
+
+static void free_cell(struct hash_cell *hc)
+{
+	if (hc) {
+		kfree(hc->name);
+		kfree(hc->uuid);
+		kfree(hc);
+	}
+}
+
+/*
+ * devfs stuff.
+ */
+static int register_with_devfs(struct hash_cell *hc)
+{
+	struct gendisk *disk = dm_disk(hc->md);
+
+	devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
+		      S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
+		      DM_DIR "/%s", hc->name);
+	return 0;
+}
+
+static int unregister_with_devfs(struct hash_cell *hc)
+{
+	devfs_remove(DM_DIR"/%s", hc->name);
+	return 0;
+}
+
+/*
+ * The kdev_t and uuid of a device can never change once it is
+ * initially inserted.
+ */
+int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md)
+{
+	struct hash_cell *cell;
+
+	/*
+	 * Allocate the new cells.
+	 */
+	cell = alloc_cell(name, uuid, md);
+	if (!cell)
+		return -ENOMEM;
+
+	/*
+	 * Insert the cell into both hash tables.
+	 */
+	down_write(&_hash_lock);
+	if (__get_name_cell(name))
+		goto bad;
+
+	list_add(&cell->name_list, _name_buckets + hash_str(name));
+
+	if (uuid) {
+		if (__get_uuid_cell(uuid)) {
+			list_del(&cell->name_list);
+			goto bad;
+		}
+		list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid));
+	}
+	register_with_devfs(cell);
+	dm_get(md);
+	up_write(&_hash_lock);
+
+	return 0;
+
+ bad:
+	up_write(&_hash_lock);
+	free_cell(cell);
+	return -EBUSY;
+}
+
+void __hash_remove(struct hash_cell *hc)
+{
+	/* remove from the dev hash */
+	list_del(&hc->uuid_list);
+	list_del(&hc->name_list);
+	unregister_with_devfs(hc);
+	dm_put(hc->md);
+	if (hc->new_map)
+		dm_table_put(hc->new_map);
+	free_cell(hc);
+}
+
+void dm_hash_remove_all(void)
+{
+	int i;
+	struct hash_cell *hc;
+	struct list_head *tmp, *n;
+
+	down_write(&_hash_lock);
+	for (i = 0; i < NUM_BUCKETS; i++) {
+		list_for_each_safe (tmp, n, _name_buckets + i) {
+			hc = list_entry(tmp, struct hash_cell, name_list);
+			__hash_remove(hc);
+		}
+	}
+	up_write(&_hash_lock);
+}
+
+int dm_hash_rename(const char *old, const char *new)
+{
+	char *new_name, *old_name;
+	struct hash_cell *hc;
+
+	/*
+	 * duplicate new.
+	 */
+	new_name = kstrdup(new);
+	if (!new_name)
+		return -ENOMEM;
+
+	down_write(&_hash_lock);
+
+	/*
+	 * Is new free ?
+	 */
+	hc = __get_name_cell(new);
+	if (hc) {
+		DMWARN("asked to rename to an already existing name %s -> %s",
+		       old, new);
+		up_write(&_hash_lock);
+		kfree(new_name);
+		return -EBUSY;
+	}
+
+	/*
+	 * Is there such a device as 'old' ?
+	 */
+	hc = __get_name_cell(old);
+	if (!hc) {
+		DMWARN("asked to rename a non existent device %s -> %s",
+		       old, new);
+		up_write(&_hash_lock);
+		kfree(new_name);
+		return -ENXIO;
+	}
+
+	/*
+	 * rename and move the name cell.
+	 */
+	unregister_with_devfs(hc);
+
+	list_del(&hc->name_list);
+	old_name = hc->name;
+	hc->name = new_name;
+	list_add(&hc->name_list, _name_buckets + hash_str(new_name));
+
+	/* rename the device node in devfs */
+	register_with_devfs(hc);
+
+	up_write(&_hash_lock);
+	kfree(old_name);
+	return 0;
+}
+
+/*-----------------------------------------------------------------
+ * Implementation of the ioctl commands
+ *---------------------------------------------------------------*/
+/*
+ * All the ioctl commands get dispatched to functions with this
+ * prototype.
+ */
+typedef int (*ioctl_fn)(struct dm_ioctl *param, size_t param_size);
+
+static int remove_all(struct dm_ioctl *param, size_t param_size)
+{
+	dm_hash_remove_all();
+	param->data_size = 0;
+	return 0;
+}
+
+/*
+ * Round up the ptr to an 8-byte boundary.
+ */
+#define ALIGN_MASK 7
+static inline void *align_ptr(void *ptr)
+{
+	return (void *) (((size_t) (ptr + ALIGN_MASK)) & ~ALIGN_MASK);
+}
+
+/*
+ * Retrieves the data payload buffer from an already allocated
+ * struct dm_ioctl.
+ */
+static void *get_result_buffer(struct dm_ioctl *param, size_t param_size,
+			       size_t *len)
+{
+	param->data_start = align_ptr(param + 1) - (void *) param;
+
+	if (param->data_start < param_size)
+		*len = param_size - param->data_start;
+	else
+		*len = 0;
+
+	return ((void *) param) + param->data_start;
+}
+
+static int list_devices(struct dm_ioctl *param, size_t param_size)
+{
+	unsigned int i;
+	struct hash_cell *hc;
+	size_t len, needed = 0;
+	struct gendisk *disk;
+	struct dm_name_list *nl, *old_nl = NULL;
+
+	down_write(&_hash_lock);
+
+	/*
+	 * Loop through all the devices working out how much
+	 * space we need.
+	 */
+	for (i = 0; i < NUM_BUCKETS; i++) {
+		list_for_each_entry (hc, _name_buckets + i, name_list) {
+			needed += sizeof(struct dm_name_list);
+			needed += strlen(hc->name);
+			needed += ALIGN_MASK;
+		}
+	}
+
+	/*
+	 * Grab our output buffer.
+	 */
+	nl = get_result_buffer(param, param_size, &len);
+	if (len < needed) {
+		param->flags |= DM_BUFFER_FULL_FLAG;
+		goto out;
+	}
+	param->data_size = param->data_start + needed;
+
+	nl->dev = 0;	/* Flags no data */
+
+	/*
+	 * Now loop through filling out the names.
+	 */
+	for (i = 0; i < NUM_BUCKETS; i++) {
+		list_for_each_entry (hc, _name_buckets + i, name_list) {
+			if (old_nl)
+				old_nl->next = (uint32_t) ((void *) nl -
+							   (void *) old_nl);
+			disk = dm_disk(hc->md);
+			nl->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor));
+			nl->next = 0;
+			strcpy(nl->name, hc->name);
+
+			old_nl = nl;
+			nl = align_ptr(((void *) ++nl) + strlen(hc->name) + 1);
+		}
+	}
+
+ out:
+	up_write(&_hash_lock);
+	return 0;
+}
+
+static void list_version_get_needed(struct target_type *tt, void *param)
+{
+    int *needed = param;
+
+    *needed += strlen(tt->name);
+    *needed += sizeof(tt->version);
+    *needed += ALIGN_MASK;
+}
+
+static void list_version_get_info(struct target_type *tt, void *param)
+{
+    struct vers_iter *info = param;
+
+    /* Check space - it might have changed since the first iteration */
+    if ((char *)info->vers + sizeof(tt->version) + strlen(tt->name) + 1 >
+	info->end) {
+
+	info->flags = DM_BUFFER_FULL_FLAG;
+	return;
+    }
+
+    if (info->old_vers)
+	info->old_vers->next = (uint32_t) ((void *)info->vers -
+					   (void *)info->old_vers);
+    info->vers->version[0] = tt->version[0];
+    info->vers->version[1] = tt->version[1];
+    info->vers->version[2] = tt->version[2];
+    info->vers->next = 0;
+    strcpy(info->vers->name, tt->name);
+
+    info->old_vers = info->vers;
+    info->vers = align_ptr(((void *) ++info->vers) + strlen(tt->name) + 1);
+}
+
+static int list_versions(struct dm_ioctl *param, size_t param_size)
+{
+	size_t len, needed = 0;
+	struct dm_target_versions *vers;
+	struct vers_iter iter_info;
+
+	/*
+	 * Loop through all the devices working out how much
+	 * space we need.
+	 */
+	dm_target_iterate(list_version_get_needed, &needed);
+
+	/*
+	 * Grab our output buffer.
+	 */
+	vers = get_result_buffer(param, param_size, &len);
+	if (len < needed) {
+		param->flags |= DM_BUFFER_FULL_FLAG;
+		goto out;
+	}
+	param->data_size = param->data_start + needed;
+
+	iter_info.param_size = param_size;
+	iter_info.old_vers = NULL;
+	iter_info.vers = vers;
+	iter_info.flags = 0;
+	iter_info.end = (char *)vers+len;
+
+	/*
+	 * Now loop through filling out the names & versions.
+	 */
+	dm_target_iterate(list_version_get_info, &iter_info);
+	param->flags |= iter_info.flags;
+
+ out:
+	return 0;
+}
+
+
+
+static int check_name(const char *name)
+{
+	if (strchr(name, '/')) {
+		DMWARN("invalid device name");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Fills in a dm_ioctl structure, ready for sending back to
+ * userland.
+ */
+static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
+{
+	struct gendisk *disk = dm_disk(md);
+	struct dm_table *table;
+	struct block_device *bdev;
+
+	param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG |
+			  DM_ACTIVE_PRESENT_FLAG);
+
+	if (dm_suspended(md))
+		param->flags |= DM_SUSPEND_FLAG;
+
+	bdev = bdget_disk(disk, 0);
+	if (!bdev)
+		return -ENXIO;
+
+	param->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor));
+
+	/*
+	 * Yes, this will be out of date by the time it gets back
+	 * to userland, but it is still very useful ofr
+	 * debugging.
+	 */
+	param->open_count = bdev->bd_openers;
+	bdput(bdev);
+
+	if (disk->policy)
+		param->flags |= DM_READONLY_FLAG;
+
+	param->event_nr = dm_get_event_nr(md);
+
+	table = dm_get_table(md);
+	if (table) {
+		param->flags |= DM_ACTIVE_PRESENT_FLAG;
+		param->target_count = dm_table_get_num_targets(table);
+		dm_table_put(table);
+	} else
+		param->target_count = 0;
+
+	return 0;
+}
+
+static int dev_create(struct dm_ioctl *param, size_t param_size)
+{
+	int r;
+	struct mapped_device *md;
+
+	r = check_name(param->name);
+	if (r)
+		return r;
+
+	if (param->flags & DM_PERSISTENT_DEV_FLAG)
+		r = dm_create_with_minor(MINOR(huge_decode_dev(param->dev)), &md);
+	else
+		r = dm_create(&md);
+
+	if (r)
+		return r;
+
+	r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md);
+	if (r) {
+		dm_put(md);
+		return r;
+	}
+
+	param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
+
+	r = __dev_status(md, param);
+	dm_put(md);
+
+	return r;
+}
+
+/*
+ * Always use UUID for lookups if it's present, otherwise use name.
+ */
+static inline struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param)
+{
+	return *param->uuid ?
+	    __get_uuid_cell(param->uuid) : __get_name_cell(param->name);
+}
+
+static inline struct mapped_device *find_device(struct dm_ioctl *param)
+{
+	struct hash_cell *hc;
+	struct mapped_device *md = NULL;
+
+	down_read(&_hash_lock);
+	hc = __find_device_hash_cell(param);
+	if (hc) {
+		md = hc->md;
+
+		/*
+		 * Sneakily write in both the name and the uuid
+		 * while we have the cell.
+		 */
+		strncpy(param->name, hc->name, sizeof(param->name));
+		if (hc->uuid)
+			strncpy(param->uuid, hc->uuid, sizeof(param->uuid)-1);
+		else
+			param->uuid[0] = '\0';
+
+		if (hc->new_map)
+			param->flags |= DM_INACTIVE_PRESENT_FLAG;
+		else
+			param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
+
+		dm_get(md);
+	}
+	up_read(&_hash_lock);
+
+	return md;
+}
+
+static int dev_remove(struct dm_ioctl *param, size_t param_size)
+{
+	struct hash_cell *hc;
+
+	down_write(&_hash_lock);
+	hc = __find_device_hash_cell(param);
+
+	if (!hc) {
+		DMWARN("device doesn't appear to be in the dev hash table.");
+		up_write(&_hash_lock);
+		return -ENXIO;
+	}
+
+	__hash_remove(hc);
+	up_write(&_hash_lock);
+	param->data_size = 0;
+	return 0;
+}
+
+/*
+ * Check a string doesn't overrun the chunk of
+ * memory we copied from userland.
+ */
+static int invalid_str(char *str, void *end)
+{
+	while ((void *) str < end)
+		if (!*str++)
+			return 0;
+
+	return -EINVAL;
+}
+
+static int dev_rename(struct dm_ioctl *param, size_t param_size)
+{
+	int r;
+	char *new_name = (char *) param + param->data_start;
+
+	if (new_name < (char *) (param + 1) ||
+	    invalid_str(new_name, (void *) param + param_size)) {
+		DMWARN("Invalid new logical volume name supplied.");
+		return -EINVAL;
+	}
+
+	r = check_name(new_name);
+	if (r)
+		return r;
+
+	param->data_size = 0;
+	return dm_hash_rename(param->name, new_name);
+}
+
+static int do_suspend(struct dm_ioctl *param)
+{
+	int r = 0;
+	struct mapped_device *md;
+
+	md = find_device(param);
+	if (!md)
+		return -ENXIO;
+
+	if (!dm_suspended(md))
+		r = dm_suspend(md);
+
+	if (!r)
+		r = __dev_status(md, param);
+
+	dm_put(md);
+	return r;
+}
+
+static int do_resume(struct dm_ioctl *param)
+{
+	int r = 0;
+	struct hash_cell *hc;
+	struct mapped_device *md;
+	struct dm_table *new_map;
+
+	down_write(&_hash_lock);
+
+	hc = __find_device_hash_cell(param);
+	if (!hc) {
+		DMWARN("device doesn't appear to be in the dev hash table.");
+		up_write(&_hash_lock);
+		return -ENXIO;
+	}
+
+	md = hc->md;
+	dm_get(md);
+
+	new_map = hc->new_map;
+	hc->new_map = NULL;
+	param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
+
+	up_write(&_hash_lock);
+
+	/* Do we need to load a new map ? */
+	if (new_map) {
+		/* Suspend if it isn't already suspended */
+		if (!dm_suspended(md))
+			dm_suspend(md);
+
+		r = dm_swap_table(md, new_map);
+		if (r) {
+			dm_put(md);
+			dm_table_put(new_map);
+			return r;
+		}
+
+		if (dm_table_get_mode(new_map) & FMODE_WRITE)
+			set_disk_ro(dm_disk(md), 0);
+		else
+			set_disk_ro(dm_disk(md), 1);
+
+		dm_table_put(new_map);
+	}
+
+	if (dm_suspended(md))
+		r = dm_resume(md);
+
+	if (!r)
+		r = __dev_status(md, param);
+
+	dm_put(md);
+	return r;
+}
+
+/*
+ * Set or unset the suspension state of a device.
+ * If the device already is in the requested state we just return its status.
+ */
+static int dev_suspend(struct dm_ioctl *param, size_t param_size)
+{
+	if (param->flags & DM_SUSPEND_FLAG)
+		return do_suspend(param);
+
+	return do_resume(param);
+}
+
+/*
+ * Copies device info back to user space, used by
+ * the create and info ioctls.
+ */
+static int dev_status(struct dm_ioctl *param, size_t param_size)
+{
+	int r;
+	struct mapped_device *md;
+
+	md = find_device(param);
+	if (!md)
+		return -ENXIO;
+
+	r = __dev_status(md, param);
+	dm_put(md);
+	return r;
+}
+
+/*
+ * Build up the status struct for each target
+ */
+static void retrieve_status(struct dm_table *table,
+			    struct dm_ioctl *param, size_t param_size)
+{
+	unsigned int i, num_targets;
+	struct dm_target_spec *spec;
+	char *outbuf, *outptr;
+	status_type_t type;
+	size_t remaining, len, used = 0;
+
+	outptr = outbuf = get_result_buffer(param, param_size, &len);
+
+	if (param->flags & DM_STATUS_TABLE_FLAG)
+		type = STATUSTYPE_TABLE;
+	else
+		type = STATUSTYPE_INFO;
+
+	/* Get all the target info */
+	num_targets = dm_table_get_num_targets(table);
+	for (i = 0; i < num_targets; i++) {
+		struct dm_target *ti = dm_table_get_target(table, i);
+
+		remaining = len - (outptr - outbuf);
+		if (remaining < sizeof(struct dm_target_spec)) {
+			param->flags |= DM_BUFFER_FULL_FLAG;
+			break;
+		}
+
+		spec = (struct dm_target_spec *) outptr;
+
+		spec->status = 0;
+		spec->sector_start = ti->begin;
+		spec->length = ti->len;
+		strncpy(spec->target_type, ti->type->name,
+			sizeof(spec->target_type));
+
+		outptr += sizeof(struct dm_target_spec);
+		remaining = len - (outptr - outbuf);
+
+		/* Get the status/table string from the target driver */
+		if (ti->type->status) {
+			if (ti->type->status(ti, type, outptr, remaining)) {
+				param->flags |= DM_BUFFER_FULL_FLAG;
+				break;
+			}
+		} else
+			outptr[0] = '\0';
+
+		outptr += strlen(outptr) + 1;
+		used = param->data_start + (outptr - outbuf);
+
+		align_ptr(outptr);
+		spec->next = outptr - outbuf;
+	}
+
+	if (used)
+		param->data_size = used;
+
+	param->target_count = num_targets;
+}
+
+/*
+ * Wait for a device to report an event
+ */
+static int dev_wait(struct dm_ioctl *param, size_t param_size)
+{
+	int r;
+	struct mapped_device *md;
+	struct dm_table *table;
+	DECLARE_WAITQUEUE(wq, current);
+
+	md = find_device(param);
+	if (!md)
+		return -ENXIO;
+
+	/*
+	 * Wait for a notification event
+	 */
+	set_current_state(TASK_INTERRUPTIBLE);
+	if (!dm_add_wait_queue(md, &wq, param->event_nr)) {
+		schedule();
+		dm_remove_wait_queue(md, &wq);
+	}
+ 	set_current_state(TASK_RUNNING);
+
+	/*
+	 * The userland program is going to want to know what
+	 * changed to trigger the event, so we may as well tell
+	 * him and save an ioctl.
+	 */
+	r = __dev_status(md, param);
+	if (r)
+		goto out;
+
+	table = dm_get_table(md);
+	if (table) {
+		retrieve_status(table, param, param_size);
+		dm_table_put(table);
+	}
+
+ out:
+	dm_put(md);
+	return r;
+}
+
+static inline int get_mode(struct dm_ioctl *param)
+{
+	int mode = FMODE_READ | FMODE_WRITE;
+
+	if (param->flags & DM_READONLY_FLAG)
+		mode = FMODE_READ;
+
+	return mode;
+}
+
+static int next_target(struct dm_target_spec *last, uint32_t next, void *end,
+		       struct dm_target_spec **spec, char **target_params)
+{
+	*spec = (struct dm_target_spec *) ((unsigned char *) last + next);
+	*target_params = (char *) (*spec + 1);
+
+	if (*spec < (last + 1))
+		return -EINVAL;
+
+	return invalid_str(*target_params, end);
+}
+
+static int populate_table(struct dm_table *table,
+			  struct dm_ioctl *param, size_t param_size)
+{
+	int r;
+	unsigned int i = 0;
+	struct dm_target_spec *spec = (struct dm_target_spec *) param;
+	uint32_t next = param->data_start;
+	void *end = (void *) param + param_size;
+	char *target_params;
+
+	if (!param->target_count) {
+		DMWARN("populate_table: no targets specified");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < param->target_count; i++) {
+
+		r = next_target(spec, next, end, &spec, &target_params);
+		if (r) {
+			DMWARN("unable to find target");
+			return r;
+		}
+
+		r = dm_table_add_target(table, spec->target_type,
+					(sector_t) spec->sector_start,
+					(sector_t) spec->length,
+					target_params);
+		if (r) {
+			DMWARN("error adding target to table");
+			return r;
+		}
+
+		next = spec->next;
+	}
+
+	return dm_table_complete(table);
+}
+
+static int table_load(struct dm_ioctl *param, size_t param_size)
+{
+	int r;
+	struct hash_cell *hc;
+	struct dm_table *t;
+
+	r = dm_table_create(&t, get_mode(param), param->target_count);
+	if (r)
+		return r;
+
+	r = populate_table(t, param, param_size);
+	if (r) {
+		dm_table_put(t);
+		return r;
+	}
+
+	down_write(&_hash_lock);
+	hc = __find_device_hash_cell(param);
+	if (!hc) {
+		DMWARN("device doesn't appear to be in the dev hash table.");
+		up_write(&_hash_lock);
+		return -ENXIO;
+	}
+
+	if (hc->new_map)
+		dm_table_put(hc->new_map);
+	hc->new_map = t;
+	param->flags |= DM_INACTIVE_PRESENT_FLAG;
+
+	r = __dev_status(hc->md, param);
+	up_write(&_hash_lock);
+	return r;
+}
+
+static int table_clear(struct dm_ioctl *param, size_t param_size)
+{
+	int r;
+	struct hash_cell *hc;
+
+	down_write(&_hash_lock);
+
+	hc = __find_device_hash_cell(param);
+	if (!hc) {
+		DMWARN("device doesn't appear to be in the dev hash table.");
+		up_write(&_hash_lock);
+		return -ENXIO;
+	}
+
+	if (hc->new_map) {
+		dm_table_put(hc->new_map);
+		hc->new_map = NULL;
+	}
+
+	param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
+
+	r = __dev_status(hc->md, param);
+	up_write(&_hash_lock);
+	return r;
+}
+
+/*
+ * Retrieves a list of devices used by a particular dm device.
+ */
+static void retrieve_deps(struct dm_table *table,
+			  struct dm_ioctl *param, size_t param_size)
+{
+	unsigned int count = 0;
+	struct list_head *tmp;
+	size_t len, needed;
+	struct dm_dev *dd;
+	struct dm_target_deps *deps;
+
+	deps = get_result_buffer(param, param_size, &len);
+
+	/*
+	 * Count the devices.
+	 */
+	list_for_each (tmp, dm_table_get_devices(table))
+		count++;
+
+	/*
+	 * Check we have enough space.
+	 */
+	needed = sizeof(*deps) + (sizeof(*deps->dev) * count);
+	if (len < needed) {
+		param->flags |= DM_BUFFER_FULL_FLAG;
+		return;
+	}
+
+	/*
+	 * Fill in the devices.
+	 */
+	deps->count = count;
+	count = 0;
+	list_for_each_entry (dd, dm_table_get_devices(table), list)
+		deps->dev[count++] = huge_encode_dev(dd->bdev->bd_dev);
+
+	param->data_size = param->data_start + needed;
+}
+
+static int table_deps(struct dm_ioctl *param, size_t param_size)
+{
+	int r = 0;
+	struct mapped_device *md;
+	struct dm_table *table;
+
+	md = find_device(param);
+	if (!md)
+		return -ENXIO;
+
+	r = __dev_status(md, param);
+	if (r)
+		goto out;
+
+	table = dm_get_table(md);
+	if (table) {
+		retrieve_deps(table, param, param_size);
+		dm_table_put(table);
+	}
+
+ out:
+	dm_put(md);
+	return r;
+}
+
+/*
+ * Return the status of a device as a text string for each
+ * target.
+ */
+static int table_status(struct dm_ioctl *param, size_t param_size)
+{
+	int r;
+	struct mapped_device *md;
+	struct dm_table *table;
+
+	md = find_device(param);
+	if (!md)
+		return -ENXIO;
+
+	r = __dev_status(md, param);
+	if (r)
+		goto out;
+
+	table = dm_get_table(md);
+	if (table) {
+		retrieve_status(table, param, param_size);
+		dm_table_put(table);
+	}
+
+ out:
+	dm_put(md);
+	return r;
+}
+
+/*-----------------------------------------------------------------
+ * Implementation of open/close/ioctl on the special char
+ * device.
+ *---------------------------------------------------------------*/
+static ioctl_fn lookup_ioctl(unsigned int cmd)
+{
+	static struct {
+		int cmd;
+		ioctl_fn fn;
+	} _ioctls[] = {
+		{DM_VERSION_CMD, NULL},	/* version is dealt with elsewhere */
+		{DM_REMOVE_ALL_CMD, remove_all},
+		{DM_LIST_DEVICES_CMD, list_devices},
+
+		{DM_DEV_CREATE_CMD, dev_create},
+		{DM_DEV_REMOVE_CMD, dev_remove},
+		{DM_DEV_RENAME_CMD, dev_rename},
+		{DM_DEV_SUSPEND_CMD, dev_suspend},
+		{DM_DEV_STATUS_CMD, dev_status},
+		{DM_DEV_WAIT_CMD, dev_wait},
+
+		{DM_TABLE_LOAD_CMD, table_load},
+		{DM_TABLE_CLEAR_CMD, table_clear},
+		{DM_TABLE_DEPS_CMD, table_deps},
+		{DM_TABLE_STATUS_CMD, table_status},
+
+		{DM_LIST_VERSIONS_CMD, list_versions}
+	};
+
+	return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn;
+}
+
+/*
+ * As well as checking the version compatibility this always
+ * copies the kernel interface version out.
+ */
+static int check_version(unsigned int cmd, struct dm_ioctl *user)
+{
+	uint32_t version[3];
+	int r = 0;
+
+	if (copy_from_user(version, user->version, sizeof(version)))
+		return -EFAULT;
+
+	if ((DM_VERSION_MAJOR != version[0]) ||
+	    (DM_VERSION_MINOR < version[1])) {
+		DMWARN("ioctl interface mismatch: "
+		       "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)",
+		       DM_VERSION_MAJOR, DM_VERSION_MINOR,
+		       DM_VERSION_PATCHLEVEL,
+		       version[0], version[1], version[2], cmd);
+		r = -EINVAL;
+	}
+
+	/*
+	 * Fill in the kernel version.
+	 */
+	version[0] = DM_VERSION_MAJOR;
+	version[1] = DM_VERSION_MINOR;
+	version[2] = DM_VERSION_PATCHLEVEL;
+	if (copy_to_user(user->version, version, sizeof(version)))
+		return -EFAULT;
+
+	return r;
+}
+
+static void free_params(struct dm_ioctl *param)
+{
+	vfree(param);
+}
+
+static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param)
+{
+	struct dm_ioctl tmp, *dmi;
+
+	if (copy_from_user(&tmp, user, sizeof(tmp)))
+		return -EFAULT;
+
+	if (tmp.data_size < sizeof(tmp))
+		return -EINVAL;
+
+	dmi = (struct dm_ioctl *) vmalloc(tmp.data_size);
+	if (!dmi)
+		return -ENOMEM;
+
+	if (copy_from_user(dmi, user, tmp.data_size)) {
+		vfree(dmi);
+		return -EFAULT;
+	}
+
+	*param = dmi;
+	return 0;
+}
+
+static int validate_params(uint cmd, struct dm_ioctl *param)
+{
+	/* Always clear this flag */
+	param->flags &= ~DM_BUFFER_FULL_FLAG;
+
+	/* Ignores parameters */
+	if (cmd == DM_REMOVE_ALL_CMD ||
+	    cmd == DM_LIST_DEVICES_CMD ||
+	    cmd == DM_LIST_VERSIONS_CMD)
+		return 0;
+
+	/* Unless creating, either name or uuid but not both */
+	if (cmd != DM_DEV_CREATE_CMD) {
+		if ((!*param->uuid && !*param->name) ||
+		    (*param->uuid && *param->name)) {
+			DMWARN("one of name or uuid must be supplied, cmd(%u)",
+			       cmd);
+			return -EINVAL;
+		}
+	}
+
+	/* Ensure strings are terminated */
+	param->name[DM_NAME_LEN - 1] = '\0';
+	param->uuid[DM_UUID_LEN - 1] = '\0';
+
+	return 0;
+}
+
+static int ctl_ioctl(struct inode *inode, struct file *file,
+		     uint command, ulong u)
+{
+	int r = 0;
+	unsigned int cmd;
+	struct dm_ioctl *param;
+	struct dm_ioctl *user = (struct dm_ioctl *) u;
+	ioctl_fn fn = NULL;
+	size_t param_size;
+
+	/* only root can play with this */
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	if (_IOC_TYPE(command) != DM_IOCTL)
+		return -ENOTTY;
+
+	cmd = _IOC_NR(command);
+
+	/*
+	 * Check the interface version passed in.  This also
+	 * writes out the kernel's interface version.
+	 */
+	r = check_version(cmd, user);
+	if (r)
+		return r;
+
+	/*
+	 * Nothing more to do for the version command.
+	 */
+	if (cmd == DM_VERSION_CMD)
+		return 0;
+
+	fn = lookup_ioctl(cmd);
+	if (!fn) {
+		DMWARN("dm_ctl_ioctl: unknown command 0x%x", command);
+		return -ENOTTY;
+	}
+
+	/*
+	 * Trying to avoid low memory issues when a device is
+	 * suspended.
+	 */
+	current->flags |= PF_MEMALLOC;
+
+	/*
+	 * Copy the parameters into kernel space.
+	 */
+	r = copy_params(user, &param);
+	if (r) {
+		current->flags &= ~PF_MEMALLOC;
+		return r;
+	}
+
+	/*
+	 * FIXME: eventually we will remove the PF_MEMALLOC flag
+	 * here.  However the tools still do nasty things like
+	 * 'load' while a device is suspended.
+	 */
+
+	r = validate_params(cmd, param);
+	if (r)
+		goto out;
+
+	param_size = param->data_size;
+	param->data_size = sizeof(*param);
+	r = fn(param, param_size);
+
+	/*
+	 * Copy the results back to userland.
+	 */
+	if (!r && copy_to_user(user, param, param->data_size))
+		r = -EFAULT;
+
+ out:
+	free_params(param);
+	current->flags &= ~PF_MEMALLOC;
+	return r;
+}
+
+static struct file_operations _ctl_fops = {
+	.ioctl	 = ctl_ioctl,
+	.owner	 = THIS_MODULE,
+};
+
+static struct miscdevice _dm_misc = {
+	.minor 		= MISC_DYNAMIC_MINOR,
+	.name  		= DM_NAME,
+	.devfs_name 	= "mapper/control",
+	.fops  		= &_ctl_fops
+};
+
+/*
+ * Create misc character device and link to DM_DIR/control.
+ */
+int __init dm_interface_init(void)
+{
+	int r;
+
+	r = dm_hash_init();
+	if (r)
+		return r;
+
+	r = misc_register(&_dm_misc);
+	if (r) {
+		DMERR("misc_register failed for control device");
+		dm_hash_exit();
+		return r;
+	}
+
+	DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR,
+	       DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA,
+	       DM_DRIVER_EMAIL);
+	return 0;
+}
+
+void dm_interface_exit(void)
+{
+	if (misc_deregister(&_dm_misc) < 0)
+		DMERR("misc_deregister failed for control device");
+
+	dm_hash_exit();
+}
--- diff/drivers/md/dm-linear.c	2003-09-30 15:46:14.000000000 +0100
+++ source/drivers/md/dm-linear.c	2004-03-09 11:51:50.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001 Sistina Software (UK) Limited.
+ * Copyright (C) 2001-2003 Sistina Software (UK) Limited.
  *
  * This file is released under the GPL.
  */
@@ -65,7 +65,8 @@ static void linear_dtr(struct dm_target 
 	kfree(lc);
 }
 
-static int linear_map(struct dm_target *ti, struct bio *bio)
+static int linear_map(struct dm_target *ti, struct bio *bio,
+		      union map_info *map_context)
 {
 	struct linear_c *lc = (struct linear_c *) ti->private;
 
@@ -96,6 +97,7 @@ static int linear_status(struct dm_targe
 
 static struct target_type linear_target = {
 	.name   = "linear",
+	.version= {1, 0, 1},
 	.module = THIS_MODULE,
 	.ctr    = linear_ctr,
 	.dtr    = linear_dtr,
--- diff/drivers/md/dm-stripe.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/md/dm-stripe.c	2004-03-09 11:51:50.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001 Sistina Software (UK) Limited.
+ * Copyright (C) 2001-2003 Sistina Software (UK) Limited.
  *
  * This file is released under the GPL.
  */
@@ -97,7 +97,8 @@ static int stripe_ctr(struct dm_target *
 	/*
 	 * chunk_size is a power of two
 	 */
-	if (!chunk_size || (chunk_size & (chunk_size - 1))) {
+	if (!chunk_size || (chunk_size & (chunk_size - 1)) ||
+	    (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) {
 		ti->error = "dm-stripe: Invalid chunk size";
 		return -EINVAL;
 	}
@@ -166,7 +167,8 @@ static void stripe_dtr(struct dm_target 
 	kfree(sc);
 }
 
-static int stripe_map(struct dm_target *ti, struct bio *bio)
+static int stripe_map(struct dm_target *ti, struct bio *bio,
+		      union map_info *map_context)
 {
 	struct stripe_c *sc = (struct stripe_c *) ti->private;
 
@@ -211,6 +213,7 @@ static int stripe_status(struct dm_targe
 
 static struct target_type stripe_target = {
 	.name   = "striped",
+	.version= {1, 0, 1},
 	.module = THIS_MODULE,
 	.ctr    = stripe_ctr,
 	.dtr    = stripe_dtr,
--- diff/drivers/md/dm-table.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/md/dm-table.c	2004-03-09 11:51:50.000000000 +0000
@@ -329,13 +329,11 @@ static int lookup_device(const char *pat
  */
 static struct dm_dev *find_device(struct list_head *l, dev_t dev)
 {
-	struct list_head *tmp;
+	struct dm_dev *dd;
 
-	list_for_each(tmp, l) {
-		struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
+	list_for_each_entry (dd, l, list)
 		if (dd->bdev->bd_dev == dev)
 			return dd;
-	}
 
 	return NULL;
 }
@@ -631,14 +629,20 @@ static int split_args(int *argc, char **
 	return 0;
 }
 
-static void set_default_limits(struct io_restrictions *rs)
+static void check_for_valid_limits(struct io_restrictions *rs)
 {
-	rs->max_sectors = MAX_SECTORS;
-	rs->max_phys_segments = MAX_PHYS_SEGMENTS;
-	rs->max_hw_segments = MAX_HW_SEGMENTS;
-	rs->hardsect_size = 1 << SECTOR_SHIFT;
-	rs->max_segment_size = MAX_SEGMENT_SIZE;
-	rs->seg_boundary_mask = -1;
+	if (!rs->max_sectors)
+		rs->max_sectors = MAX_SECTORS;
+	if (!rs->max_phys_segments)
+		rs->max_phys_segments = MAX_PHYS_SEGMENTS;
+	if (!rs->max_hw_segments)
+		rs->max_hw_segments = MAX_HW_SEGMENTS;
+	if (!rs->hardsect_size)
+		rs->hardsect_size = 1 << SECTOR_SHIFT;
+	if (!rs->max_segment_size)
+		rs->max_segment_size = MAX_SEGMENT_SIZE;
+	if (!rs->seg_boundary_mask)
+		rs->seg_boundary_mask = -1;
 }
 
 int dm_table_add_target(struct dm_table *t, const char *type,
@@ -653,7 +657,6 @@ int dm_table_add_target(struct dm_table 
 
 	tgt = t->targets + t->num_targets;
 	memset(tgt, 0, sizeof(*tgt));
-	set_default_limits(&tgt->limits);
 
 	if (!len) {
 		tgt->error = "zero-length target";
@@ -738,6 +741,8 @@ int dm_table_complete(struct dm_table *t
 	int r = 0;
 	unsigned int leaf_nodes;
 
+	check_for_valid_limits(&t->limits);
+
 	/* how many indexes will the btree have ? */
 	leaf_nodes = dm_div_up(t->num_targets, KEYS_PER_NODE);
 	t->depth = 1 + int_log(leaf_nodes, CHILDREN_PER_NODE);
@@ -862,6 +867,20 @@ void dm_table_resume_targets(struct dm_t
 	}
 }
 
+int dm_table_any_congested(struct dm_table *t, int bdi_bits)
+{
+	struct list_head *d, *devices;
+	int r = 0;
+
+	devices = dm_table_get_devices(t);
+	for (d = devices->next; d != devices; d = d->next) {
+		struct dm_dev *dd = list_entry(d, struct dm_dev, list);
+		request_queue_t *q = bdev_get_queue(dd->bdev);
+		r |= bdi_congested(&q->backing_dev_info, bdi_bits);
+	}
+
+	return r;
+}
 
 EXPORT_SYMBOL(dm_vcalloc);
 EXPORT_SYMBOL(dm_get_device);
--- diff/drivers/md/dm-target.c	2003-06-30 10:07:21.000000000 +0100
+++ source/drivers/md/dm-target.c	2004-03-09 11:51:50.000000000 +0000
@@ -25,15 +25,11 @@ static DECLARE_RWSEM(_lock);
 
 static inline struct tt_internal *__find_target_type(const char *name)
 {
-	struct list_head *tih;
 	struct tt_internal *ti;
 
-	list_for_each(tih, &_targets) {
-		ti = list_entry(tih, struct tt_internal, list);
-
+	list_for_each_entry (ti, &_targets, list)
 		if (!strcmp(name, ti->tt.name))
 			return ti;
-	}
 
 	return NULL;
 }
@@ -100,6 +96,20 @@ static struct tt_internal *alloc_target(
 	return ti;
 }
 
+
+int dm_target_iterate(void (*iter_func)(struct target_type *tt,
+					void *param), void *param)
+{
+	struct tt_internal *ti;
+
+	down_read(&_lock);
+	list_for_each_entry (ti, &_targets, list)
+		iter_func(&ti->tt, param);
+	up_read(&_lock);
+
+	return 0;
+}
+
 int dm_register_target(struct target_type *t)
 {
 	int rv = 0;
@@ -157,13 +167,15 @@ static void io_err_dtr(struct dm_target 
 	/* empty */
 }
 
-static int io_err_map(struct dm_target *ti, struct bio *bio)
+static int io_err_map(struct dm_target *ti, struct bio *bio,
+		      union map_info *map_context)
 {
 	return -EIO;
 }
 
 static struct target_type error_target = {
 	.name = "error",
+	.version = {1, 0, 1},
 	.ctr  = io_err_ctr,
 	.dtr  = io_err_dtr,
 	.map  = io_err_map,
--- diff/drivers/md/dm.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/md/dm.c	2004-03-09 11:51:50.000000000 +0000
@@ -21,6 +21,9 @@ static const char *_name = DM_NAME;
 static unsigned int major = 0;
 static unsigned int _major = 0;
 
+/*
+ * One of these is allocated per bio.
+ */
 struct dm_io {
 	struct mapped_device *md;
 	int error;
@@ -29,6 +32,16 @@ struct dm_io {
 };
 
 /*
+ * One of these is allocated per target within a bio.  Hopefully
+ * this will be simplified out one day.
+ */
+struct target_io {
+	struct dm_io *io;
+	struct dm_target *ti;
+	union map_info info;
+};
+
+/*
  * Bits for the md->flags field.
  */
 #define DMF_BLOCK_IO 0
@@ -36,6 +49,7 @@ struct dm_io {
 
 struct mapped_device {
 	struct rw_semaphore lock;
+	rwlock_t maplock;
 	atomic_t holders;
 
 	unsigned long flags;
@@ -59,6 +73,7 @@ struct mapped_device {
 	 * io objects are allocated from here.
 	 */
 	mempool_t *io_pool;
+	mempool_t *tio_pool;
 
 	/*
 	 * Event handling.
@@ -69,6 +84,7 @@ struct mapped_device {
 
 #define MIN_IOS 256
 static kmem_cache_t *_io_cache;
+static kmem_cache_t *_tio_cache;
 
 static __init int local_init(void)
 {
@@ -80,9 +96,18 @@ static __init int local_init(void)
 	if (!_io_cache)
 		return -ENOMEM;
 
+	/* allocate a slab for the target ios */
+	_tio_cache = kmem_cache_create("dm_tio", sizeof(struct target_io),
+				       0, 0, NULL, NULL);
+	if (!_tio_cache) {
+		kmem_cache_destroy(_io_cache);
+		return -ENOMEM;
+	}
+
 	_major = major;
 	r = register_blkdev(_major, _name);
 	if (r < 0) {
+		kmem_cache_destroy(_tio_cache);
 		kmem_cache_destroy(_io_cache);
 		return r;
 	}
@@ -95,6 +120,7 @@ static __init int local_init(void)
 
 static void local_exit(void)
 {
+	kmem_cache_destroy(_tio_cache);
 	kmem_cache_destroy(_io_cache);
 
 	if (unregister_blkdev(_major, _name) < 0)
@@ -184,6 +210,16 @@ static inline void free_io(struct mapped
 	mempool_free(io, md->io_pool);
 }
 
+static inline struct target_io *alloc_tio(struct mapped_device *md)
+{
+	return mempool_alloc(md->tio_pool, GFP_NOIO);
+}
+
+static inline void free_tio(struct mapped_device *md, struct target_io *tio)
+{
+	mempool_free(tio, md->tio_pool);
+}
+
 /*
  * Add the bio to the list of deferred io.
  */
@@ -232,17 +268,30 @@ static inline void dec_pending(struct dm
 
 static int clone_endio(struct bio *bio, unsigned int done, int error)
 {
-	struct dm_io *io = bio->bi_private;
+	int r = 0;
+	struct target_io *tio = bio->bi_private;
+	struct dm_io *io = tio->io;
+	dm_endio_fn endio = tio->ti->type->end_io;
 
 	if (bio->bi_size)
 		return 1;
 
+	if (endio) {
+		r = endio(tio->ti, bio, error, &tio->info);
+		if (r < 0)
+			error = r;
+
+		else if (r > 0)
+			/* the target wants another shot at the io */
+			return 1;
+	}
+
+	free_tio(io->md, tio);
 	dec_pending(io, error);
 	bio_put(bio);
-	return 0;
+	return r;
 }
 
-
 static sector_t max_io_len(struct mapped_device *md,
 			   sector_t sector, struct dm_target *ti)
 {
@@ -263,7 +312,8 @@ static sector_t max_io_len(struct mapped
 	return len;
 }
 
-static void __map_bio(struct dm_target *ti, struct bio *clone, struct dm_io *io)
+static void __map_bio(struct dm_target *ti, struct bio *clone,
+		      struct target_io *tio)
 {
 	int r;
 
@@ -273,22 +323,25 @@ static void __map_bio(struct dm_target *
 	BUG_ON(!clone->bi_size);
 
 	clone->bi_end_io = clone_endio;
-	clone->bi_private = io;
+	clone->bi_private = tio;
 
 	/*
 	 * Map the clone.  If r == 0 we don't need to do
 	 * anything, the target has assumed ownership of
 	 * this io.
 	 */
-	atomic_inc(&io->io_count);
-	r = ti->type->map(ti, clone);
+	atomic_inc(&tio->io->io_count);
+	r = ti->type->map(ti, clone, &tio->info);
 	if (r > 0)
 		/* the bio has been remapped so dispatch it */
 		generic_make_request(clone);
 
-	else if (r < 0)
+	else if (r < 0) {
 		/* error the io and bail out */
+		struct dm_io *io = tio->io;
+		free_tio(tio->io->md, tio);
 		dec_pending(io, -EIO);
+	}
 }
 
 struct clone_info {
@@ -348,6 +401,15 @@ static void __clone_and_map(struct clone
 	struct bio *clone, *bio = ci->bio;
 	struct dm_target *ti = dm_table_find_target(ci->md->map, ci->sector);
 	sector_t len = 0, max = max_io_len(ci->md, ci->sector, ti);
+	struct target_io *tio;
+
+	/*
+	 * Allocate a target io object.
+	 */
+	tio = alloc_tio(ci->md);
+	tio->io = ci->io;
+	tio->ti = ti;
+	memset(&tio->info, 0, sizeof(tio->info));
 
 	if (ci->sector_count <= max) {
 		/*
@@ -356,7 +418,7 @@ static void __clone_and_map(struct clone
 		 */
 		clone = clone_bio(bio, ci->sector, ci->idx,
 				  bio->bi_vcnt - ci->idx, ci->sector_count);
-		__map_bio(ti, clone, ci->io);
+		__map_bio(ti, clone, tio);
 		ci->sector_count = 0;
 
 	} else if (to_sector(bio->bi_io_vec[ci->idx].bv_len) <= max) {
@@ -379,7 +441,7 @@ static void __clone_and_map(struct clone
 		}
 
 		clone = clone_bio(bio, ci->sector, ci->idx, i - ci->idx, len);
-		__map_bio(ti, clone, ci->io);
+		__map_bio(ti, clone, tio);
 
 		ci->sector += len;
 		ci->sector_count -= len;
@@ -394,7 +456,7 @@ static void __clone_and_map(struct clone
 
 		clone = split_bvec(bio, ci->sector, ci->idx,
 				   bv->bv_offset, max);
-		__map_bio(ti, clone, ci->io);
+		__map_bio(ti, clone, tio);
 
 		ci->sector += max;
 		ci->sector_count -= max;
@@ -403,7 +465,11 @@ static void __clone_and_map(struct clone
 		len = to_sector(bv->bv_len) - max;
 		clone = split_bvec(bio, ci->sector, ci->idx,
 				   bv->bv_offset + to_bytes(max), len);
-		__map_bio(ti, clone, ci->io);
+		tio = alloc_tio(ci->md);
+		tio->io = ci->io;
+		tio->ti = ti;
+		memset(&tio->info, 0, sizeof(tio->info));
+		__map_bio(ti, clone, tio);
 
 		ci->sector += len;
 		ci->sector_count -= len;
@@ -441,6 +507,16 @@ static void __split_bio(struct mapped_de
  *---------------------------------------------------------------*/
 
 
+static inline void __dm_request(struct mapped_device *md, struct bio *bio)
+{
+	if (!md->map) {
+		bio_io_error(bio, bio->bi_size);
+		return;
+	}
+
+	__split_bio(md, bio);
+}
+
 /*
  * The request function that just remaps the bio built up by
  * dm_merge_bvec.
@@ -479,16 +555,26 @@ static int dm_request(request_queue_t *q
 		down_read(&md->lock);
 	}
 
-	if (!md->map) {
-		bio_io_error(bio, bio->bi_size);
-		return 0;
-	}
-
-	__split_bio(md, bio);
+	__dm_request(md, bio);
 	up_read(&md->lock);
 	return 0;
 }
 
+static int dm_any_congested(void *congested_data, int bdi_bits)
+{
+	int r;
+	struct mapped_device *md = congested_data;
+
+	read_lock(&md->maplock);
+	if (md->map == NULL || test_bit(DMF_BLOCK_IO, &md->flags))
+		r = bdi_bits;
+	else
+		r = dm_table_any_congested(md->map, bdi_bits);
+	read_unlock(&md->maplock);
+
+	return r;
+}
+
 /*-----------------------------------------------------------------
  * A bitset is used to keep track of allocated minor numbers.
  *---------------------------------------------------------------*/
@@ -560,6 +646,7 @@ static struct mapped_device *alloc_dev(u
 
 	memset(md, 0, sizeof(*md));
 	init_rwsem(&md->lock);
+	rwlock_init(&md->maplock);
 	atomic_set(&md->holders, 1);
 
 	md->queue = blk_alloc_queue(GFP_KERNEL);
@@ -567,6 +654,8 @@ static struct mapped_device *alloc_dev(u
 		goto bad1;
 
 	md->queue->queuedata = md;
+	md->queue->backing_dev_info.congested_fn = dm_any_congested;
+	md->queue->backing_dev_info.congested_data = md;
 	blk_queue_make_request(md->queue, dm_request);
 
 	md->io_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
@@ -574,9 +663,14 @@ static struct mapped_device *alloc_dev(u
  	if (!md->io_pool)
  		goto bad2;
 
+	md->tio_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
+				      mempool_free_slab, _tio_cache);
+	if (!md->tio_pool)
+		goto bad3;
+
 	md->disk = alloc_disk(1);
 	if (!md->disk)
-		goto bad3;
+		goto bad4;
 
 	md->disk->major = _major;
 	md->disk->first_minor = minor;
@@ -592,7 +686,8 @@ static struct mapped_device *alloc_dev(u
 
 	return md;
 
-
+ bad4:
+	mempool_destroy(md->tio_pool);
  bad3:
 	mempool_destroy(md->io_pool);
  bad2:
@@ -606,6 +701,7 @@ static struct mapped_device *alloc_dev(u
 static void free_dev(struct mapped_device *md)
 {
 	free_minor(md->disk->first_minor);
+	mempool_destroy(md->tio_pool);
 	mempool_destroy(md->io_pool);
 	del_gendisk(md->disk);
 	put_disk(md->disk);
@@ -644,13 +740,15 @@ static int __bind(struct mapped_device *
 {
 	request_queue_t *q = md->queue;
 	sector_t size;
-	md->map = t;
 
 	size = dm_table_get_size(t);
 	__set_size(md->disk, size);
 	if (size == 0)
 		return 0;
 
+	write_lock(&md->maplock);
+	md->map = t;
+	write_unlock(&md->maplock);
 	dm_table_event_callback(md->map, event_callback, md);
 
 	dm_table_get(t);
@@ -660,12 +758,16 @@ static int __bind(struct mapped_device *
 
 static void __unbind(struct mapped_device *md)
 {
-	if (!md->map)
+	struct dm_table *map = md->map;
+
+	if (!map)
 		return;
 
-	dm_table_event_callback(md->map, NULL, NULL);
-	dm_table_put(md->map);
+	dm_table_event_callback(map, NULL, NULL);
+	write_lock(&md->maplock);
 	md->map = NULL;
+	write_unlock(&md->maplock);
+	dm_table_put(map);
 }
 
 /*
@@ -710,16 +812,16 @@ void dm_put(struct mapped_device *md)
 }
 
 /*
- * Requeue the deferred bios by calling generic_make_request.
+ * Process the deferred bios
  */
-static void flush_deferred_io(struct bio *c)
+static void __flush_deferred_io(struct mapped_device *md, struct bio *c)
 {
 	struct bio *n;
 
 	while (c) {
 		n = c->bi_next;
 		c->bi_next = NULL;
-		generic_make_request(c);
+		__dm_request(md, c);
 		c = n;
 	}
 }
@@ -814,10 +916,11 @@ int dm_resume(struct mapped_device *md)
 	dm_table_resume_targets(md->map);
 	clear_bit(DMF_SUSPENDED, &md->flags);
 	clear_bit(DMF_BLOCK_IO, &md->flags);
+
 	def = bio_list_get(&md->deferred);
+	__flush_deferred_io(md, def);
 	up_write(&md->lock);
 
-	flush_deferred_io(def);
 	blk_run_queues();
 
 	return 0;
--- diff/drivers/md/dm.h	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/md/dm.h	2004-03-09 11:51:50.000000000 +0000
@@ -115,6 +115,7 @@ struct list_head *dm_table_get_devices(s
 int dm_table_get_mode(struct dm_table *t);
 void dm_table_suspend_targets(struct dm_table *t);
 void dm_table_resume_targets(struct dm_table *t);
+int dm_table_any_congested(struct dm_table *t, int bdi_bits);
 
 /*-----------------------------------------------------------------
  * A registry of target types.
@@ -123,6 +124,8 @@ int dm_target_init(void);
 void dm_target_exit(void);
 struct target_type *dm_get_target_type(const char *name);
 void dm_put_target_type(struct target_type *t);
+int dm_target_iterate(void (*iter_func)(struct target_type *tt,
+					void *param), void *param);
 
 
 /*-----------------------------------------------------------------
--- diff/drivers/md/md.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/md/md.c	2004-03-09 11:51:50.000000000 +0000
@@ -57,7 +57,7 @@
 
 
 #ifndef MODULE
-static void autostart_arrays (void);
+static void autostart_arrays (int part);
 #endif
 
 static mdk_personality_t *pers[MAX_PERSONALITY];
@@ -1792,7 +1792,7 @@ static void autorun_array(mddev_t *mddev
  *
  * If "unit" is allocated, then bump its reference count
  */
-static void autorun_devices(void)
+static void autorun_devices(int part)
 {
 	struct list_head candidates;
 	struct list_head *tmp;
@@ -1825,7 +1825,12 @@ static void autorun_devices(void)
 			       bdevname(rdev0->bdev, b), rdev0->preferred_minor);
 			break;
 		}
-		dev = MKDEV(MD_MAJOR, rdev0->preferred_minor);
+		if (part)
+			dev = MKDEV(mdp_major,
+				    rdev0->preferred_minor << MdpMinorShift);
+		else
+			dev = MKDEV(MD_MAJOR, rdev0->preferred_minor);
+
 		md_probe(dev, NULL, NULL);
 		mddev = mddev_find(dev);
 		if (!mddev) {
@@ -1922,7 +1927,7 @@ static int autostart_array(dev_t startde
 	/*
 	 * possibly return codes
 	 */
-	autorun_devices();
+	autorun_devices(0);
 	return 0;
 
 }
@@ -2407,7 +2412,7 @@ static int md_ioctl(struct inode *inode,
 #ifndef MODULE
 		case RAID_AUTORUN:
 			err = 0;
-			autostart_arrays();
+			autostart_arrays(arg);
 			goto done;
 #endif
 		default:;
@@ -3577,7 +3582,7 @@ void md_autodetect_dev(dev_t dev)
 }
 
 
-static void autostart_arrays(void)
+static void autostart_arrays(int part)
 {
 	char b[BDEVNAME_SIZE];
 	mdk_rdev_t *rdev;
@@ -3602,7 +3607,7 @@ static void autostart_arrays(void)
 	}
 	dev_cnt = 0;
 
-	autorun_devices();
+	autorun_devices(part);
 }
 
 #endif
--- diff/drivers/md/raid5.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/md/raid5.c	2004-03-09 11:51:50.000000000 +0000
@@ -1409,7 +1409,8 @@ static int sync_request (mddev_t *mddev,
 		/* make sure we don't swamp the stripe cache if someone else
 		 * is trying to get access 
 		 */
-		yield();
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(max(HZ/500, 1));
 	}
 	spin_lock(&sh->lock);	
 	set_bit(STRIPE_SYNCING, &sh->state);
--- diff/drivers/md/raid6main.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/md/raid6main.c	2004-03-09 11:51:50.000000000 +0000
@@ -1571,7 +1571,8 @@ static int sync_request (mddev_t *mddev,
 		/* make sure we don't swamp the stripe cache if someone else
 		 * is trying to get access
 		 */
-		yield();
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(max(HZ/500, 1));
 	}
 	spin_lock(&sh->lock);
 	set_bit(STRIPE_SYNCING, &sh->state);
--- diff/drivers/media/dvb/frontends/alps_tdlb7.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/media/dvb/frontends/alps_tdlb7.c	2004-03-09 11:51:50.000000000 +0000
@@ -29,8 +29,6 @@
 */  
 
 
-
-#define __KERNEL_SYSCALLS__
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/vmalloc.h>
@@ -58,8 +56,6 @@ static int debug = 0;
 #define SP8870_FIRMWARE_OFFSET 0x0A
 
 
-static int errno;
-
 static struct dvb_frontend_info tdlb7_info = {
 	.name			= "Alps TDLB7",
 	.type			= FE_OFDM,
@@ -174,13 +170,13 @@ static int sp8870_read_firmware_file (co
 	loff_t filesize;
 	char *dp;
 
-	fd = open(fn, 0, 0);
+	fd = sys_open(fn, 0, 0);
 	if (fd == -1) {
                 printk("%s: unable to open '%s'.\n", __FUNCTION__, fn);
 		return -EIO;
 	}
 
-	filesize = lseek(fd, 0L, 2);
+	filesize = sys_lseek(fd, 0L, 2);
 	if (filesize <= 0 || filesize < SP8870_FIRMWARE_OFFSET + SP8870_FIRMWARE_SIZE) {
 	        printk("%s: firmware filesize to small '%s'\n", __FUNCTION__, fn);
 		sys_close(fd);
@@ -194,8 +190,8 @@ static int sp8870_read_firmware_file (co
 		return -EIO;
 	}
 
-	lseek(fd, SP8870_FIRMWARE_OFFSET, 0);
-	if (read(fd, dp, SP8870_FIRMWARE_SIZE) != SP8870_FIRMWARE_SIZE) {
+	sys_lseek(fd, SP8870_FIRMWARE_OFFSET, 0);
+	if (sys_read(fd, dp, SP8870_FIRMWARE_SIZE) != SP8870_FIRMWARE_SIZE) {
 		printk("%s: failed to read '%s'.\n",__FUNCTION__, fn);
 		vfree(dp);
 		sys_close(fd);
--- diff/drivers/media/dvb/frontends/sp887x.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/media/dvb/frontends/sp887x.c	2004-03-09 11:51:50.000000000 +0000
@@ -12,7 +12,6 @@
    next 0x4000 loaded. This may change in future versions.
  */
 
-#define __KERNEL_SYSCALLS__
 #include <linux/kernel.h>
 #include <linux/vmalloc.h>
 #include <linux/module.h>
@@ -68,8 +67,6 @@ struct dvb_frontend_info sp887x_info = {
 		FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_RECOVER
 };
 
-static int errno;
-
 static
 int i2c_writebytes (struct dvb_frontend *fe, u8 addr, u8 *buf, u8 len)
 {
@@ -216,13 +213,13 @@ int sp887x_initial_setup (struct dvb_fro
 
 	// Load the firmware
 	set_fs(get_ds());
-	fd = open(sp887x_firmware, 0, 0);
+	fd = sys_open(sp887x_firmware, 0, 0);
 	if (fd < 0) {
 		printk(KERN_WARNING "%s: Unable to open firmware %s\n", __FUNCTION__,
 		       sp887x_firmware);
 		return -EIO;
 	}
-	filesize = lseek(fd, 0L, 2);
+	filesize = sys_lseek(fd, 0L, 2);
 	if (filesize <= 0) {
 		printk(KERN_WARNING "%s: Firmware %s is empty\n", __FUNCTION__,
 		       sp887x_firmware);
@@ -244,8 +241,8 @@ int sp887x_initial_setup (struct dvb_fro
 	// read it!
 	// read the first 16384 bytes from the file
 	// ignore the first 10 bytes
-	lseek(fd, 10, 0);
-	if (read(fd, firmware, fw_size) != fw_size) {
+	sys_lseek(fd, 10, 0);
+	if (sys_read(fd, firmware, fw_size) != fw_size) {
 		printk(KERN_WARNING "%s: Failed to read firmware\n", __FUNCTION__);
 		vfree(firmware);
 		sys_close(fd);
--- diff/drivers/media/dvb/frontends/tda1004x.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/media/dvb/frontends/tda1004x.c	2004-03-09 11:51:50.000000000 +0000
@@ -32,7 +32,6 @@
  */
 
 
-#define __KERNEL_SYSCALLS__
 #include <linux/kernel.h>
 #include <linux/vmalloc.h>
 #include <linux/module.h>
@@ -41,7 +40,6 @@
 #include <linux/slab.h>
 #include <linux/syscalls.h>
 #include <linux/fs.h>
-#include <linux/unistd.h>
 #include <linux/fcntl.h>
 #include <linux/errno.h>
 #include "dvb_frontend.h"
@@ -399,13 +397,13 @@ static int tda1004x_fwupload(struct dvb_
 
 	// Load the firmware
 	set_fs(get_ds());
-	fd = open(tda1004x_firmware, 0, 0);
+	fd = sys_open(tda1004x_firmware, 0, 0);
 	if (fd < 0) {
 		printk("%s: Unable to open firmware %s\n", __FUNCTION__,
 		       tda1004x_firmware);
 		return -EIO;
 	}
-	filesize = lseek(fd, 0L, 2);
+	filesize = sys_lseek(fd, 0L, 2);
 	if (filesize <= 0) {
 		printk("%s: Firmware %s is empty\n", __FUNCTION__,
 		       tda1004x_firmware);
@@ -436,8 +434,8 @@ static int tda1004x_fwupload(struct dvb_
 	}
 
 	// read it!
-        lseek(fd, fw_offset, 0);
-	if (read(fd, firmware, fw_size) != fw_size) {
+        sys_lseek(fd, fw_offset, 0);
+	if (sys_read(fd, firmware, fw_size) != fw_size) {
 		printk("%s: Failed to read firmware\n", __FUNCTION__);
 		vfree(firmware);
 		sys_close(fd);
--- diff/drivers/media/video/v4l1-compat.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/media/video/v4l1-compat.c	2004-03-09 11:51:50.000000000 +0000
@@ -503,10 +503,11 @@ v4l_compat_translate_ioctl(struct inode 
 		int *on = arg;
 
 		if (0 == *on) {
+			enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 			/* dirty hack time.  But v4l1 has no STREAMOFF
 			 * equivalent in the API, and this one at
 			 * least comes close ... */
-			drv(inode, file, VIDIOC_STREAMOFF, NULL);
+			drv(inode, file, VIDIOC_STREAMOFF, &type);
 		}
 		err = drv(inode, file, VIDIOC_OVERLAY, arg);
 		if (err < 0)
@@ -857,6 +858,7 @@ v4l_compat_translate_ioctl(struct inode 
 	case VIDIOCMCAPTURE: /*  capture a frame  */
 	{
 		struct video_mmap	*mm = arg;
+		enum v4l2_buf_type	type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
 		fmt2 = kmalloc(sizeof(*fmt2),GFP_KERNEL);
 		memset(&buf2,0,sizeof(buf2));
@@ -897,7 +899,7 @@ v4l_compat_translate_ioctl(struct inode 
 			dprintk("VIDIOCMCAPTURE / VIDIOC_QBUF: %d\n",err);
 			break;
 		}
-		err = drv(inode, file, VIDIOC_STREAMON, NULL);
+		err = drv(inode, file, VIDIOC_STREAMON, &type);
 		if (err < 0)
 			dprintk("VIDIOCMCAPTURE / VIDIOC_STREAMON: %d\n",err);
 		break;
--- diff/drivers/media/video/video-buf.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/media/video/video-buf.c	2004-03-09 11:51:50.000000000 +0000
@@ -215,7 +215,7 @@ int videobuf_dma_pci_sync(struct pci_dev
 		BUG();
 
 	if (!dma->bus_addr)
-		pci_dma_sync_sg(dev,dma->sglist,dma->nr_pages,dma->direction);
+		pci_dma_sync_sg_for_cpu(dev,dma->sglist,dma->nr_pages,dma->direction);
 	return 0;
 }
 
--- diff/drivers/message/fusion/Kconfig	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/message/fusion/Kconfig	2004-03-09 11:51:50.000000000 +0000
@@ -14,41 +14,6 @@ config FUSION
 
 	  [1] LAN is not supported on parallel SCSI medium.
 
-	  These drivers require a Fusion MPT compatible PCI adapter installed
-	  in the host system.  MPT adapters contain specialized I/O processors
-	  to handle I/O workload, and more importantly to offload this work
-	  from the host CPU(s).
-
-	  If you have Fusion MPT hardware and want to use it, you can say
-	  Y or M here to add MPT (base + ScsiHost) drivers.
-	  <Y> = build lib (fusion), and link [static] into the kernel [2]
-	  proper
-	  <M> = compiled as [dynamic] modules [3] named: (mptbase,
-	  mptscsih)
-
-	  [2] In order enable capability to boot the linux kernel
-	  natively from a Fusion MPT target device, you MUST
-	  answer Y here! (currently requires CONFIG_BLK_DEV_SD)
-	  [3] To compile this support as modules, choose M here.
-
-	  If unsure, say N.
-
-	  If you say Y or M here you will get a choice of these
-	  additional protocol and support module options:         Module Name:
-	  <M>   Enhanced SCSI error reporting                     (isense)
-	  <M>   Fusion MPT misc device (ioctl) driver             (mptctl)
-	  <M>   Fusion MPT LAN driver                             (mptlan)
-
-	  ---
-	  Fusion MPT is trademark of LSI Logic Corporation, and its
-	  architecture is based on LSI Logic's Message Passing Interface (MPI)
-	  specification.
-
-config FUSION_BOOT
-	bool
-	depends on FUSION=y
-	default y
-
 config FUSION_MAX_SGE
 	int "Maximum number of scatter gather entries"
 	depends on FUSION
@@ -62,7 +27,6 @@ config FUSION_MAX_SGE
 	  necessary (or recommended) unless the user will be running 
 	  large I/O's via the raw interface.
 
-#  How can we force these options to module or nothing?
 config FUSION_ISENSE
 	tristate "Enhanced SCSI error reporting"
 	depends on MODULES && FUSION && m
@@ -132,17 +96,4 @@ config FUSION_LAN
 
 	  If unsure whether you really want or need this, say N.
 
-	  NOTES: This feature is NOT available nor supported for linux-2.2.x
-	  kernels.  You must be building a linux-2.3.x or linux-2.4.x kernel
-	  in order to configure this option.
-	  Support for building this feature into the linux kernel is not
-	  yet available.
-
-#  if [ "$CONFIG_FUSION_LAN" != "n" ]; then
-#    define_bool CONFIG_NET_FC y
-#  fi
-# These <should> be define_tristate, but we leave them define_bool
-# for backward compatibility with pre-linux-2.2.15 kernels.
-# (Bugzilla:fibrebugs, #384)
 endmenu
-
--- diff/drivers/message/fusion/mptbase.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/message/fusion/mptbase.c	2004-03-09 11:51:50.000000000 +0000
@@ -1515,17 +1515,18 @@ mptbase_probe(struct pci_dev *pdev, cons
 			|| (ioc->chip_type == C1035) || (ioc->chip_type == FC929X))
 		mpt_detect_bound_ports(ioc, pdev);
 
-	if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) {
-		printk(KERN_WARNING MYNAM ": WARNING - %s did not initialize properly! (%d)\n",
-				ioc->name, r);
-	}
+	if ((r = mpt_do_ioc_recovery(ioc,
+	  MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) {
+		printk(KERN_WARNING MYNAM
+		  ": WARNING - %s did not initialize properly! (%d)\n",
+		  ioc->name, r);
 
-	if(r != 0 ) {
 		Q_DEL_ITEM(ioc);
 		mpt_adapters[ioc->id] = NULL;
 		free_irq(ioc->pci_irq, ioc);
 		iounmap(mem);
 		kfree(ioc);
+		pci_set_drvdata(pdev, NULL);
 		return r;
 	}
 
@@ -2508,10 +2509,10 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF
 			 * Set values for this IOC's request & reply frame sizes,
 			 * and request & reply queue depths...
 			 */
-			ioc->req_sz = MIN(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
-			ioc->req_depth = MIN(MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
+			ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
+			ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
 			ioc->reply_sz = ioc->req_sz;
-			ioc->reply_depth = MIN(MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
+			ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
 
 			dprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
 				ioc->name, ioc->reply_sz, ioc->reply_depth));
@@ -3992,7 +3993,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER
 		/*
 		 * Copy out the cached reply...
 		 */
-		for (ii=0; ii < MIN(replyBytes/2,mptReply->MsgLength*2); ii++)
+		for (ii=0; ii < min(replyBytes/2, mptReply->MsgLength*2); ii++)
 			u16reply[ii] = ioc->hs_reply[ii];
 	} else {
 		return -99;
@@ -4239,7 +4240,7 @@ GetLanConfigPages(MPT_ADAPTER *ioc)
 
 			if ((rc = mpt_config(ioc, &cfg)) == 0) {
 				/* save the data */
-				copy_sz = MIN(sizeof(LANPage0_t), data_sz);
+				copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
 				memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
 
 			}
@@ -4284,7 +4285,7 @@ GetLanConfigPages(MPT_ADAPTER *ioc)
 
 		if ((rc = mpt_config(ioc, &cfg)) == 0) {
 			/* save the data */
-			copy_sz = MIN(sizeof(LANPage1_t), data_sz);
+			copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
 			memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
 		}
 
@@ -4353,7 +4354,7 @@ GetFcPortPage0(MPT_ADAPTER *ioc, int por
 		if ((rc = mpt_config(ioc, &cfg)) == 0) {
 			/* save the data */
 			pp0dest = &ioc->fc_port_page0[portnum];
-			copy_sz = MIN(sizeof(FCPortPage0_t), data_sz);
+			copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz);
 			memcpy(pp0dest, ppage0_alloc, copy_sz);
 
 			/*
--- diff/drivers/message/fusion/mptbase.h	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/message/fusion/mptbase.h	2004-03-09 11:51:50.000000000 +0000
@@ -80,8 +80,8 @@
 #define COPYRIGHT	"Copyright (c) 1999-2003 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON	"3.00.03"
-#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.00.03"
+#define MPT_LINUX_VERSION_COMMON	"3.00.04"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.00.04"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -1057,13 +1057,6 @@ extern int		  mpt_ASCQ_TableSz;
 /*
  *  More (public) macros...
  */
-#ifndef MIN
-#define MIN(a, b)   (((a) < (b)) ? (a) : (b))
-#endif
-#ifndef MAX
-#define MAX(a, b)   (((a) > (b)) ? (a) : (b))
-#endif
-
 #ifndef offsetof
 #define offsetof(t, m)	((size_t) (&((t *)0)->m))
 #endif
--- diff/drivers/message/fusion/mptctl.c	2004-01-19 10:22:57.000000000 +0000
+++ source/drivers/message/fusion/mptctl.c	2004-03-09 11:51:50.000000000 +0000
@@ -283,7 +283,7 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME
 				dctlprintk((MYIOC_s_INFO_FMT ": Copying Reply Frame @%p to IOC!\n",
 						ioc->name, reply));
 				memcpy(ioc->ioctl->ReplyFrame, reply,
-					MIN(ioc->reply_sz, 4*reply->u.reply.MsgLength));
+					min(ioc->reply_sz, 4*reply->u.reply.MsgLength));
 				ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID;
 
 				/* Set the command status to GOOD if IOC Status is GOOD
@@ -334,7 +334,7 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME
 			// NOTE: Expects/requires non-Turbo reply!
 			dctlprintk((MYIOC_s_INFO_FMT ":Caching MPI_FUNCTION_FW_DOWNLOAD reply!\n",
 				ioc->name));
-			memcpy(fwReplyBuffer, reply, MIN(sizeof(fwReplyBuffer), 4*reply->u.reply.MsgLength));
+			memcpy(fwReplyBuffer, reply, min_t(int, sizeof(fwReplyBuffer), 4*reply->u.reply.MsgLength));
 			ReplyMsg = (pMPIDefaultReply_t) fwReplyBuffer;
 		}
 	}
@@ -992,7 +992,7 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i
 	MptSge_t	*sgl;
 	int		 numfrags = 0;
 	int		 fragcnt = 0;
-	int		 alloc_sz = MIN(bytes,MAX_KMALLOC_SZ);	// avoid kernel warning msg!
+	int		 alloc_sz = min(bytes, MAX_KMALLOC_SZ);	// avoid kernel warning msg!
 	int		 bytes_allocd = 0;
 	int		 this_alloc;
 	dma_addr_t	 pa;					// phys addr
@@ -1037,7 +1037,7 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i
 	sgl = sglbuf;
 	sg_spill = ((ioc->req_sz - sge_offset)/(sizeof(dma_addr_t) + sizeof(u32))) - 1;
 	while (bytes_allocd < bytes) {
-		this_alloc = MIN(alloc_sz, bytes-bytes_allocd);
+		this_alloc = min(alloc_sz, bytes-bytes_allocd);
 		buflist[buflist_ent].len = this_alloc;
 		buflist[buflist_ent].kptr = pci_alloc_consistent(ioc->pcidev,
 								 this_alloc,
@@ -2280,9 +2280,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 		 */
 		if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) {
 			if (karg.maxReplyBytes < ioc->reply_sz) {
-				 sz = MIN(karg.maxReplyBytes, 4*ioc->ioctl->ReplyFrame[2]);
+				 sz = min(karg.maxReplyBytes, 4*ioc->ioctl->ReplyFrame[2]);
 			} else {
-				 sz = MIN(ioc->reply_sz, 4*ioc->ioctl->ReplyFrame[2]);
+				 sz = min(ioc->reply_sz, 4*ioc->ioctl->ReplyFrame[2]);
 			}
 
 			if (sz > 0) {
@@ -2301,7 +2301,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 		/* If valid sense data, copy to user.
 		 */
 		if (ioc->ioctl->status & MPT_IOCTL_STATUS_SENSE_VALID) {
-			sz = MIN(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE);
+			sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE);
 			if (sz > 0) {
 				if (copy_to_user((char *)karg.senseDataPtr, ioc->ioctl->sense, sz)) {
 					printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
--- diff/drivers/message/fusion/mptlan.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/message/fusion/mptlan.c	2004-03-09 11:51:50.000000000 +0000
@@ -955,11 +955,13 @@ mpt_lan_receive_post_turbo(struct net_de
 			return -ENOMEM;
 		}
 
-		pci_dma_sync_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
-				    priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+		pci_dma_sync_single_for_cpu(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+					    priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
 
 		memcpy(skb_put(skb, len), old_skb->data, len);
 
+		pci_dma_sync_single_for_device(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+					       priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
 		goto out;
 	}
 
@@ -1113,12 +1115,17 @@ mpt_lan_receive_post_reply(struct net_de
 //					IOC_AND_NETDEV_NAMES_s_s(dev),
 //					i, l));
 
-			pci_dma_sync_single(mpt_dev->pcidev,
-					    priv->RcvCtl[ctx].dma,
-					    priv->RcvCtl[ctx].len,
-					    PCI_DMA_FROMDEVICE);
+			pci_dma_sync_single_for_cpu(mpt_dev->pcidev,
+						    priv->RcvCtl[ctx].dma,
+						    priv->RcvCtl[ctx].len,
+						    PCI_DMA_FROMDEVICE);
 			memcpy(skb_put(skb, l), old_skb->data, l);
 
+			pci_dma_sync_single_for_device(mpt_dev->pcidev,
+						       priv->RcvCtl[ctx].dma,
+						       priv->RcvCtl[ctx].len,
+						       PCI_DMA_FROMDEVICE);
+
 			priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
 			szrem -= l;
 		}
@@ -1136,11 +1143,18 @@ mpt_lan_receive_post_reply(struct net_de
 			return -ENOMEM;
 		}
 
-		pci_dma_sync_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
-				    priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+		pci_dma_sync_single_for_cpu(mpt_dev->pcidev,
+					    priv->RcvCtl[ctx].dma,
+					    priv->RcvCtl[ctx].len,
+					    PCI_DMA_FROMDEVICE);
 
 		memcpy(skb_put(skb, len), old_skb->data, len);
 
+		pci_dma_sync_single_for_device(mpt_dev->pcidev,
+					       priv->RcvCtl[ctx].dma,
+					       priv->RcvCtl[ctx].len,
+					       PCI_DMA_FROMDEVICE);
+
 		spin_lock_irqsave(&priv->rxfidx_lock, flags);
 		priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
 		spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
--- diff/drivers/message/fusion/mptscsih.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/message/fusion/mptscsih.c	2004-03-09 11:51:50.000000000 +0000
@@ -200,8 +200,8 @@ static int	mptscsih_setup(char *str);
 static int  __init   mptscsih_init  (void);
 static void __exit   mptscsih_exit  (void);
 
-static int  __devinit mptscsih_probe (struct pci_dev *, const struct pci_device_id *);
-static void __devexit mptscsih_remove(struct pci_dev *);
+static int  mptscsih_probe (struct pci_dev *, const struct pci_device_id *);
+static void mptscsih_remove(struct pci_dev *);
 static void mptscsih_shutdown(struct device *);
 #ifdef CONFIG_PM
 static int mptscsih_suspend(struct pci_dev *pdev, u32 state);
@@ -1405,7 +1405,7 @@ static char *info_kbuf = NULL;
  *
  */
 
-static int  __devinit
+static int
 mptscsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	struct Scsi_Host	*sh = NULL;
@@ -1718,7 +1718,7 @@ mptscsih_probe_failed:
  *
  *
  */
-static void __devexit
+static void
 mptscsih_remove(struct pci_dev *pdev)
 {
 	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);
@@ -1920,7 +1920,7 @@ mptscsih_resume(struct pci_dev *pdev)
 
 static struct mpt_pci_driver mptscsih_driver = {
 	.probe		= mptscsih_probe,
-	.remove		= __devexit_p(mptscsih_remove),
+	.remove		= mptscsih_remove,
 	.shutdown	= mptscsih_shutdown,
 #ifdef CONFIG_PM
 	.suspend	= mptscsih_suspend,
@@ -3658,7 +3658,7 @@ mptscsih_target_settings(MPT_SCSI_HOST *
 				if (nfactor < pspi_data->minSyncFactor )
 					nfactor = pspi_data->minSyncFactor;
 
-				factor = MAX (factor, nfactor);
+				factor = max(factor, nfactor);
 				if (factor == MPT_ASYNC)
 					offset = 0;
 			} else {
@@ -4716,7 +4716,7 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, in
 		maxid = ioc->sh->max_id - 1;
 	} else if (ioc->sh) {
 		id = target_id;
-		maxid = MIN(id, ioc->sh->max_id - 1);
+		maxid = min_t(int, id, ioc->sh->max_id - 1);
 	}
 
 	for (; id <= maxid; id++) {
@@ -5049,7 +5049,7 @@ mptscsih_scandv_complete(MPT_ADAPTER *io
 				sense_data = ((u8 *)hd->ioc->sense_buf_pool +
 					(req_idx * MPT_SENSE_BUFFER_ALLOC));
 
-				sz = MIN (pReq->SenseBufferLength,
+				sz = min_t(int, pReq->SenseBufferLength,
 							SCSI_STD_SENSE_BYTES);
 				memcpy(hd->pLocal->sense, sense_data, sz);
 
@@ -5698,7 +5698,7 @@ mptscsih_domainValidation(void *arg)
 				ioc->spi_data.forceDv &= ~MPT_SCSICFG_RELOAD_IOC_PG3;
 			}
 
-			maxid = MIN (ioc->sh->max_id, MPT_MAX_SCSI_DEVICES);
+			maxid = min_t(int, ioc->sh->max_id, MPT_MAX_SCSI_DEVICES);
 
 			for (id = 0; id < maxid; id++) {
 				spin_lock_irqsave(&dvtaskQ_lock, flags);
@@ -6374,7 +6374,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int por
 	if (echoBufSize > 0) {
 		iocmd.flags |= MPT_ICFLAG_ECHO;
 		if (dataBufSize > 0)
-			bufsize = MIN(echoBufSize, dataBufSize);
+			bufsize = min(echoBufSize, dataBufSize);
 		else
 			bufsize = echoBufSize;
 	} else if (dataBufSize == 0)
@@ -6385,7 +6385,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int por
 
 	/* Data buffers for write-read-compare test max 1K.
 	 */
-	sz = MIN(bufsize, 1024);
+	sz = min(bufsize, 1024);
 
 	/* --- loop ----
 	 * On first pass, always issue a reserve.
@@ -6740,9 +6740,9 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVP
 		}
 
 		/* limit by adapter capabilities */
-		width = MIN(width, hd->ioc->spi_data.maxBusWidth);
-		offset = MIN(offset, hd->ioc->spi_data.maxSyncOffset);
-		factor = MAX(factor, hd->ioc->spi_data.minSyncFactor);
+		width = min(width, hd->ioc->spi_data.maxBusWidth);
+		offset = min(offset, hd->ioc->spi_data.maxSyncOffset);
+		factor = max(factor, hd->ioc->spi_data.minSyncFactor);
 
 		/* Check Consistency */
 		if (offset && (factor < MPT_ULTRA2) && !width)
--- diff/drivers/message/i2o/Kconfig	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/message/i2o/Kconfig	2004-03-09 11:51:50.000000000 +0000
@@ -39,7 +39,10 @@ config I2O_BLOCK
 	depends on I2O
 	help
 	  Include support for the I2O Block OSM. The Block OSM presents disk
-	  and other structured block devices to the operating system.
+	  and other structured block devices to the operating system. If you
+	  are using an RAID controller, you could access the array only by
+	  the Block OSM driver. But it is possible to access the single disks
+	  by the SCSI OSM driver, for example to monitor the disks.
 
 	  To compile this support as a module, choose M here: the
 	  module will be called i2o_block.
@@ -50,7 +53,8 @@ config I2O_SCSI
 	help
 	  Allows direct SCSI access to SCSI devices on a SCSI or FibreChannel
 	  I2O controller. You can use both the SCSI and Block OSM together if
-	  you wish.
+	  you wish. To access a RAID array, you must use the Block OSM driver.
+	  But you could use the SCSI OSM driver to monitor the single disks.
 
 	  To compile this support as a module, choose M here: the
 	  module will be called i2o_scsi.
--- diff/drivers/message/i2o/i2o_block.c	2003-08-20 14:16:29.000000000 +0100
+++ source/drivers/message/i2o/i2o_block.c	2004-03-09 11:51:50.000000000 +0000
@@ -50,9 +50,11 @@
  *		Properly attach/detach I2O gendisk structure from the system
  *		gendisk list. The I2O block devices now appear in 
  * 		/proc/partitions.
+ *	Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ *		Minor bugfixes for 2.6.
  *
- *	To do:
- *		Serial number scanning to find duplicates for FC multipathing
+ * To do:
+ *	Serial number scanning to find duplicates for FC multipathing
  */
 
 #include <linux/major.h>
@@ -109,25 +111,6 @@
 				 I2O_EVT_IND_BSA_SCSI_SMART )
 
 
-/*
- * I2O Block Error Codes - should be in a header file really...
- */
-#define I2O_BSA_DSC_SUCCESS             0x0000
-#define I2O_BSA_DSC_MEDIA_ERROR         0x0001
-#define I2O_BSA_DSC_ACCESS_ERROR        0x0002
-#define I2O_BSA_DSC_DEVICE_FAILURE      0x0003
-#define I2O_BSA_DSC_DEVICE_NOT_READY    0x0004
-#define I2O_BSA_DSC_MEDIA_NOT_PRESENT   0x0005
-#define I2O_BSA_DSC_MEDIA_LOCKED        0x0006
-#define I2O_BSA_DSC_MEDIA_FAILURE       0x0007
-#define I2O_BSA_DSC_PROTOCOL_FAILURE    0x0008
-#define I2O_BSA_DSC_BUS_FAILURE         0x0009
-#define I2O_BSA_DSC_ACCESS_VIOLATION    0x000A
-#define I2O_BSA_DSC_WRITE_PROTECTED     0x000B
-#define I2O_BSA_DSC_DEVICE_RESET        0x000C
-#define I2O_BSA_DSC_VOLUME_CHANGED      0x000D
-#define I2O_BSA_DSC_TIMEOUT             0x000E
-
 #define I2O_LOCK(unit)	(i2ob_dev[(unit)].req_queue->queue_lock)
 
 /*
@@ -1091,6 +1074,28 @@ static int i2ob_install_device(struct i2
 			d->lct_data.tid, unit);	
 
 	/*
+	 * If this is the first I2O block device found on this IOP,
+	 * we need to initialize all the queue data structures
+	 * before any I/O can be performed. If it fails, this
+	 * device is useless.
+	 */
+	if(!i2ob_queues[unit]) {
+		if(i2ob_init_iop(unit))
+			return 1;
+	}
+
+	/*
+	 * This will save one level of lookup/indirection in critical
+	 * code so that we can directly get the queue ptr from the
+	 * device instead of having to go the IOP data structure.
+	 */
+	dev->req_queue = i2ob_queues[unit]->req_queue;
+
+	/* initialize gendik structure */
+	i2ob_disk[unit>>4]->private_data = dev;
+	i2ob_disk[unit>>4]->queue = dev->req_queue;
+
+	/*
 	 *	Ask for the current media data. If that isn't supported
 	 *	then we ask for the device capacity data
 	 */
@@ -1148,6 +1153,7 @@ static int i2ob_install_device(struct i2
 	}
 
 	strcpy(d->dev_name, i2ob_disk[unit>>4]->disk_name);
+	strcpy(i2ob_disk[unit>>4]->devfs_name, i2ob_disk[unit>>4]->disk_name);
 
 	printk(KERN_INFO "%s: Max segments %d, queue depth %d, byte limit %d.\n",
 		 d->dev_name, i2ob_dev[unit].max_segments, i2ob_dev[unit].depth, i2ob_max_sectors[unit]<<9);
@@ -1193,28 +1199,6 @@ static int i2ob_install_device(struct i2
 	printk(KERN_INFO "%s: Maximum sectors/read set to %d.\n", 
 		d->dev_name, i2ob_max_sectors[unit]);
 
-	/* 
-	 * If this is the first I2O block device found on this IOP,
-	 * we need to initialize all the queue data structures
-	 * before any I/O can be performed. If it fails, this
-	 * device is useless.
-	 */
-	if(!i2ob_queues[c->unit]) {
-		if(i2ob_init_iop(c->unit))
-			return 1;
-	}
-
-	/* 
-	 * This will save one level of lookup/indirection in critical 
-	 * code so that we can directly get the queue ptr from the
-	 * device instead of having to go the IOP data structure.
-	 */
-	dev->req_queue = i2ob_queues[c->unit]->req_queue;
-
-	/* Register a size before we register for events - otherwise we
-	   might miss and overwrite an event */
-	set_capacity(i2ob_disk[unit>>4], size>>9);
-
 	/*
 	 * Register for the events we're interested in and that the
 	 * device actually supports.
@@ -1251,6 +1235,7 @@ static int i2ob_init_iop(unsigned int un
 	i2ob_queues[unit]->i2ob_qhead = &i2ob_queues[unit]->request_queue[0];
 	atomic_set(&i2ob_queues[unit]->queue_depth, 0);
 
+	i2ob_queues[unit]->lock = SPIN_LOCK_UNLOCKED;
 	i2ob_queues[unit]->req_queue = blk_init_queue(i2ob_request, &i2ob_queues[unit]->lock);
 	if (!i2ob_queues[unit]->req_queue) {
 		kfree(i2ob_queues[unit]);
@@ -1336,6 +1321,8 @@ static void i2ob_scan(int bios)
 				continue;
 			}
 
+			i2o_release_device(d, &i2o_block_handler);
+
 			if(scan_unit<MAX_I2OB<<4)
 			{
  				/*
@@ -1365,7 +1352,6 @@ static void i2ob_scan(int bios)
 				if(!warned++)
 					printk(KERN_WARNING "i2o_block: too many device, registering only %d.\n", scan_unit>>4);
 			}
-			i2o_release_device(d, &i2o_block_handler);
 		}
 		i2o_unlock_controller(c);
 	}
@@ -1699,9 +1685,9 @@ static void i2o_block_exit(void)
 	
 	if(evt_running) {
 		printk(KERN_INFO "Killing I2O block threads...");
-		i = kill_proc(evt_pid, SIGTERM, 1);
+		i = kill_proc(evt_pid, SIGKILL, 1);
 		if(!i) {
-			printk("waiting...");
+			printk("waiting...\n");
 		}
 		/* Be sure it died */
 		wait_for_completion(&i2ob_thread_dead);
--- diff/drivers/message/i2o/i2o_core.c	2003-06-30 10:07:21.000000000 +0100
+++ source/drivers/message/i2o/i2o_core.c	2004-03-09 11:51:50.000000000 +0000
@@ -13,15 +13,16 @@
  * A lot of the I2O message side code from this is taken from the 
  * Red Creek RCPCI45 adapter driver by Red Creek Communications 
  * 
- * Fixes by: 
- *		Philipp Rumpf 
- *		Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI> 
- *		Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI> 
- *		Deepak Saxena <deepak@plexity.net> 
- *		Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
- *
- * Ported to Linux 2.5 by
- *		Alan Cox	<alan@redhat.com>
+ * Fixes/additions:
+ *	Philipp Rumpf
+ *	Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ *	Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ *	Deepak Saxena <deepak@plexity.net>
+ *	Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
+ *	Alan Cox <alan@redhat.com>:
+ *		Ported to Linux 2.5.
+ *	Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ *		Minor fixes for 2.6.
  * 
  */
 
@@ -502,6 +503,7 @@ int i2o_install_controller(struct i2o_co
 			c->unit = i;
 			c->page_frame = NULL;
 			c->hrt = NULL;
+			c->hrt_len = 0;
 			c->lct = NULL;
 			c->status_block = NULL;
 			sprintf(c->name, "i2o/iop%d", i);
@@ -564,7 +566,7 @@ int i2o_delete_controller(struct i2o_con
 	 * If this is shutdown time, the thread's already been killed
 	 */
 	if(c->lct_running) {
-		stat = kill_proc(c->lct_pid, SIGTERM, 1);
+		stat = kill_proc(c->lct_pid, SIGKILL, 1);
 		if(!stat) {
 			int count = 10 * 100;
 			while(c->lct_running && --count) {
@@ -1177,7 +1179,7 @@ void i2o_run_queue(struct i2o_controller
 		 *	the processor 
 	 	 */
 
-		pci_dma_sync_single(c->pdev, c->page_frame_map, MSG_FRAME_SIZE, PCI_DMA_FROMDEVICE);
+		pci_dma_sync_single_for_cpu(c->pdev, c->page_frame_map, MSG_FRAME_SIZE, PCI_DMA_FROMDEVICE);
 	
 		/*
 		 *	Despatch it
@@ -1861,31 +1863,36 @@ int i2o_hrt_get(struct i2o_controller *c
 {
 	u32 msg[6];
 	int ret, size = sizeof(i2o_hrt);
+	int loops = 3;	/* we only try 3 times to get the HRT, this should be
+			   more then enough. Worst case should be 2 times.*/
 
 	/* First read just the header to figure out the real size */
 
 	do  {
+		/* first we allocate the memory for the HRT */
 		if (c->hrt == NULL) {
 			c->hrt=pci_alloc_consistent(c->pdev, size, &c->hrt_phys);
 			if (c->hrt == NULL) {
 				printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", c->name);
 				return -ENOMEM;
 			}
+			c->hrt_len = size;
 		}
 
 		msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4;
 		msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID;
 		msg[3]= 0;
-		msg[4]= (0xD0000000 | size);	/* Simple transaction */
+		msg[4]= (0xD0000000 | c->hrt_len);	/* Simple transaction */
 		msg[5]= c->hrt_phys;		/* Dump it here */
 
-		ret = i2o_post_wait_mem(c, msg, sizeof(msg), 20, c->hrt, NULL, c->hrt_phys, 0, size, 0);
+		ret = i2o_post_wait_mem(c, msg, sizeof(msg), 20, c->hrt, NULL, c->hrt_phys, 0, c->hrt_len, 0);
 		
 		if(ret == -ETIMEDOUT)
 		{
 			/* The HRT block we used is in limbo somewhere. When the iop wakes up
 			   we will recover it */
 			c->hrt = NULL;
+			c->hrt_len = 0;
 			return ret;
 		}
 		
@@ -1896,13 +1903,20 @@ int i2o_hrt_get(struct i2o_controller *c
 			return ret;
 		}
 
-		if (c->hrt->num_entries * c->hrt->entry_len << 2 > size) {
-			int new_size = c->hrt->num_entries * c->hrt->entry_len << 2;
-			pci_free_consistent(c->pdev, size, c->hrt, c->hrt_phys);
-			size = new_size;
+		if (c->hrt->num_entries * c->hrt->entry_len << 2 > c->hrt_len) {
+			size = c->hrt->num_entries * c->hrt->entry_len << 2;
+			pci_free_consistent(c->pdev, c->hrt_len, c->hrt, c->hrt_phys);
+			c->hrt_len = 0;
 			c->hrt = NULL;
 		}
-	} while (c->hrt == NULL);
+		loops --;
+	} while (c->hrt == NULL && loops > 0);
+
+	if(c->hrt == NULL)
+	{
+		printk(KERN_ERR "%s: Unable to get HRT after three tries, giving up\n", c->name);
+		return -1;
+	}
 
 	i2o_parse_hrt(c); // just for debugging
 
@@ -3628,8 +3642,6 @@ int __init i2o_pci_install(struct pci_de
 	return 0;	
 }
 
-static int dpt;
-
 /**
  *	i2o_pci_scan	-	Scan the pci bus for controllers
  *	
@@ -3654,14 +3666,7 @@ int __init i2o_pci_scan(void)
 	{
 		if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O)
 			continue;
-		if(dev->vendor == PCI_VENDOR_ID_DPT && !dpt)
-		{
-			if(dev->device == 0xA501 || dev->device == 0xA511)
-			{
-				printk(KERN_INFO "i2o: Skipping Adaptec/DPT I2O raid with preferred native driver.\n");
-				continue;
-			}
-		}
+
 		if((dev->class&0xFF)>1)
 		{
 			printk(KERN_INFO "i2o: I2O Controller found but does not support I2O 1.5 (skipping).\n");
@@ -3735,22 +3740,19 @@ static void i2o_core_exit(void)
 	 */
 	if(evt_running) {
 		printk("Terminating i2o threads...");
-		stat = kill_proc(evt_pid, SIGTERM, 1);
+		stat = kill_proc(evt_pid, SIGKILL, 1);
 		if(!stat) {
-			printk("waiting...");
+			printk("waiting...\n");
 			wait_for_completion(&evt_dead);
 		}
 		printk("done.\n");
 	}
 	i2o_remove_handler(&i2o_core_handler);
-	unregister_reboot_notifier(&i2o_reboot_notifier);
 }
 
 module_init(i2o_core_init);
 module_exit(i2o_core_exit);
 
-MODULE_PARM(dpt, "i");
-MODULE_PARM_DESC(dpt, "Set this if you want to drive DPT cards normally handled by dpt_i2o");
 MODULE_PARM(verbose, "i");
 MODULE_PARM_DESC(verbose, "Verbose diagnostics");
 
--- diff/drivers/message/i2o/i2o_scsi.c	2003-08-20 14:16:09.000000000 +0100
+++ source/drivers/message/i2o/i2o_scsi.c	2004-03-09 11:51:50.000000000 +0000
@@ -29,12 +29,15 @@
  *	In general the firmware wants to help. Where its help isn't performance
  *	useful we just ignore the aid. Its not worth the code in truth.
  *
- *	Fixes:
- *		Steve Ralston	:	Scatter gather now works
+ * Fixes/additions:
+ *	Steve Ralston:
+ *		Scatter gather now works
+ *	Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ *		Minor fixes for 2.6.
  *
- *	To Do
- *		64bit cleanups
- *		Fix the resource management problems.
+ * To Do:
+ *	64bit cleanups
+ *	Fix the resource management problems.
  */
 
 
@@ -66,7 +69,13 @@
 
 #define VERSION_STRING        "Version 0.1.2"
 
-#define dprintk(x)
+//#define DRIVERDEBUG
+
+#ifdef DRIVERDEBUG
+#define dprintk(s, args...) printk(s, ## args)
+#else
+#define dprintk(s, args...)
+#endif
 
 #define I2O_SCSI_CAN_QUEUE	4
 #define MAXHOSTS		32
@@ -252,15 +261,15 @@ static void i2o_scsi_reply(struct i2o_ha
 	as=(u8)le32_to_cpu(m[4]>>8);
 	st=(u8)le32_to_cpu(m[4]>>24);
 	
-	dprintk(("i2o got a scsi reply %08X: ", m[0]));
-	dprintk(("m[2]=%08X: ", m[2]));
-	dprintk(("m[4]=%08X\n", m[4]));
+	dprintk(KERN_INFO "i2o got a scsi reply %08X: ", m[0]);
+	dprintk(KERN_INFO "m[2]=%08X: ", m[2]);
+	dprintk(KERN_INFO "m[4]=%08X\n", m[4]);
  
 	if(m[2]&0x80000000)
 	{
 		if(m[2]&0x40000000)
 		{
-			dprintk(("Event.\n"));
+			dprintk(KERN_INFO "Event.\n");
 			lun_done=1;
 			return;
 		}
@@ -280,12 +289,12 @@ static void i2o_scsi_reply(struct i2o_ha
 	if(current_command==NULL)
 	{
 		if(st)
-			dprintk(("SCSI abort: %08X", m[4]));
-		dprintk(("SCSI abort completed.\n"));
+			dprintk(KERN_WARNING "SCSI abort: %08X", m[4]);
+		dprintk(KERN_INFO "SCSI abort completed.\n");
 		return;
 	}
 	
-	dprintk(("Completed %ld\n", current_command->serial_number));
+	dprintk(KERN_INFO "Completed %ld\n", current_command->serial_number);
 	
 	atomic_dec(&queue_depth);
 	
@@ -308,7 +317,7 @@ static void i2o_scsi_reply(struct i2o_ha
 	{
 		/* An error has occurred */
 
-		dprintk((KERN_DEBUG "SCSI error %08X", m[4]));
+		dprintk(KERN_WARNING "SCSI error %08X", m[4]);
 			
 		if (as == 0x0E) 
 			/* SCSI Reset */
@@ -368,7 +377,7 @@ static int i2o_find_lun(struct i2o_contr
 
 	*lun=reply[1];
 
-	dprintk(("SCSI (%d,%d)\n", *target, *lun));
+	dprintk(KERN_INFO "SCSI (%d,%d)\n", *target, *lun);
 	return 0;
 }
 
@@ -401,8 +410,8 @@ static void i2o_scsi_init(struct i2o_con
 			
 	for(unit=c->devices;unit!=NULL;unit=unit->next)
 	{
-		dprintk(("Class %03X, parent %d, want %d.\n",
-			unit->lct_data.class_id, unit->lct_data.parent_tid, d->lct_data.tid));
+		dprintk(KERN_INFO "Class %03X, parent %d, want %d.\n",
+			unit->lct_data.class_id, unit->lct_data.parent_tid, d->lct_data.tid);
 			
 		/* Only look at scsi and fc devices */
 		if (    (unit->lct_data.class_id != I2O_CLASS_SCSI_PERIPHERAL)
@@ -411,19 +420,19 @@ static void i2o_scsi_init(struct i2o_con
 			continue;
 
 		/* On our bus ? */
-		dprintk(("Found a disk (%d).\n", unit->lct_data.tid));
+		dprintk(KERN_INFO "Found a disk (%d).\n", unit->lct_data.tid);
 		if ((unit->lct_data.parent_tid == d->lct_data.tid)
 		     || (unit->lct_data.parent_tid == d->lct_data.parent_tid)
 		   )
 		{
 			u16 limit;
-			dprintk(("Its ours.\n"));
+			dprintk(KERN_INFO "Its ours.\n");
 			if(i2o_find_lun(c, unit, &target, &lun)==-1)
 			{
 				printk(KERN_ERR "i2o_scsi: Unable to get lun for tid %d.\n", unit->lct_data.tid);
 				continue;
 			}
-			dprintk(("Found disk %d %d.\n", target, lun));
+			dprintk(KERN_INFO "Found disk %d %d.\n", target, lun);
 			h->task[target][lun]=unit->lct_data.tid;
 			h->tagclock[target][lun]=jiffies;
 
@@ -439,8 +448,8 @@ static void i2o_scsi_init(struct i2o_con
 			
 			shpnt->sg_tablesize = limit;
 
-			dprintk(("i2o_scsi: set scatter-gather to %d.\n", 
-				shpnt->sg_tablesize));
+			dprintk(KERN_INFO "i2o_scsi: set scatter-gather to %d.\n",
+				shpnt->sg_tablesize);
 		}
 	}		
 }
@@ -558,6 +567,9 @@ static int i2o_scsi_release(struct Scsi_
 		del_timer(&retry_timer);
 		i2o_remove_handler(&i2o_scsi_handler);
 	}
+
+	scsi_unregister(host);
+
 	return 0;
 }
 
@@ -624,7 +636,7 @@ static int i2o_scsi_queuecommand(Scsi_Cm
 	
 	tid = hostdata->task[SCpnt->device->id][SCpnt->device->lun];
 	
-	dprintk(("qcmd: Tid = %d\n", tid));
+	dprintk(KERN_INFO "qcmd: Tid = %d\n", tid);
 	
 	current_command = SCpnt;		/* set current command                */
 	current_command->scsi_done = done;	/* set ptr to done function           */
@@ -641,7 +653,7 @@ static int i2o_scsi_queuecommand(Scsi_Cm
 		return 0;
 	}
 	
-	dprintk(("Real scsi messages.\n"));
+	dprintk(KERN_INFO "Real scsi messages.\n");
 
 	/*
 	 *	Obtain an I2O message. If there are none free then 
@@ -821,8 +833,8 @@ static int i2o_scsi_queuecommand(Scsi_Cm
 	}
 	else
 	{
-		dprintk(("non sg for %p, %d\n", SCpnt->request_buffer,
-				SCpnt->request_bufflen));
+		dprintk(KERN_INFO "non sg for %p, %d\n", SCpnt->request_buffer,
+				SCpnt->request_bufflen);
 		i2o_raw_writel(len = SCpnt->request_bufflen, lenptr);
 		if(len == 0)
 		{
@@ -861,7 +873,7 @@ static int i2o_scsi_queuecommand(Scsi_Cm
 	}
 	
 	mb();
-	dprintk(("Issued %ld\n", current_command->serial_number));
+	dprintk(KERN_INFO "Issued %ld\n", current_command->serial_number);
 	
 	return 0;
 }
--- diff/drivers/mtd/chips/cfi_cmdset_0020.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/mtd/chips/cfi_cmdset_0020.c	2004-03-09 11:51:50.000000000 +0000
@@ -1460,3 +1460,5 @@ static void __exit cfi_staa_exit(void)
 
 module_init(cfi_staa_init);
 module_exit(cfi_staa_exit);
+
+MODULE_LICENSE("GPL");
--- diff/drivers/mtd/maps/map_funcs.c	2003-06-30 10:07:21.000000000 +0100
+++ source/drivers/mtd/maps/map_funcs.c	2004-03-09 11:51:50.000000000 +0000
@@ -93,3 +93,4 @@ void simple_map_init(struct map_info *ma
 }
 
 EXPORT_SYMBOL(simple_map_init);
+MODULE_LICENSE("GPL");
--- diff/drivers/net/3c503.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/3c503.c	2004-03-09 11:51:50.000000000 +0000
@@ -337,6 +337,9 @@ el2_probe1(struct net_device *dev, int i
     dev->open = &el2_open;
     dev->stop = &el2_close;
     dev->ethtool_ops = &netdev_ethtool_ops;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+    dev->poll_controller = ei_poll;
+#endif
 
     if (dev->mem_start)
 	printk("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n",
--- diff/drivers/net/3c59x.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/net/3c59x.c	2004-03-09 11:51:50.000000000 +0000
@@ -927,6 +927,18 @@ static struct net_device *compaq_net_dev
 
 static int vortex_cards_found;
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void poll_vortex(struct net_device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	unsigned long flags;
+	local_save_flags(flags);
+	local_irq_disable();
+	(vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev,NULL);
+	local_irq_restore(flags);
+} 
+#endif
+
 #ifdef CONFIG_PM
 
 static int vortex_suspend (struct pci_dev *pdev, u32 state)
@@ -1463,6 +1475,9 @@ static int __devinit vortex_probe1(struc
 	dev->set_multicast_list = set_rx_mode;
 	dev->tx_timeout = vortex_tx_timeout;
 	dev->watchdog_timeo = (watchdog * HZ) / 1000;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = poll_vortex; 
+#endif
 	if (pdev && vp->enable_wol) {
 		vp->pm_state_valid = 1;
  		pci_save_state(VORTEX_PCI(vp), vp->power_state);
@@ -2562,11 +2577,12 @@ boomerang_rx(struct net_device *dev)
 			if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-				pci_dma_sync_single(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+				pci_dma_sync_single_for_cpu(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 				/* 'skb_put()' points to the start of sk_buff data area. */
 				memcpy(skb_put(skb, pkt_len),
 					   vp->rx_skbuff[entry]->tail,
 					   pkt_len);
+				pci_dma_sync_single_for_device(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 				vp->rx_copy++;
 			} else {
 				/* Pass up the skbuff already on the Rx ring. */
--- diff/drivers/net/8390.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/net/8390.c	2004-03-09 11:51:50.000000000 +0000
@@ -516,6 +516,15 @@ irqreturn_t ei_interrupt(int irq, void *
 	return IRQ_RETVAL(nr_serviced > 0);
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+void ei_poll(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	ei_interrupt(dev->irq, dev, NULL);
+	enable_irq(dev->irq);
+}
+#endif
+
 /**
  * ei_tx_err - handle transmitter error
  * @dev: network device which threw the exception
@@ -1124,6 +1133,9 @@ static void NS8390_trigger_send(struct n
 EXPORT_SYMBOL(ei_open);
 EXPORT_SYMBOL(ei_close);
 EXPORT_SYMBOL(ei_interrupt);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+EXPORT_SYMBOL(ei_poll);
+#endif
 EXPORT_SYMBOL(ei_tx_timeout);
 EXPORT_SYMBOL(NS8390_init);
 EXPORT_SYMBOL(__alloc_ei_netdev);
--- diff/drivers/net/8390.h	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/8390.h	2004-03-09 11:51:50.000000000 +0000
@@ -39,6 +39,10 @@ extern int ei_debug;
 #define ei_debug 1
 #endif
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+extern void ei_poll(struct net_device *dev);
+#endif
+
 extern void NS8390_init(struct net_device *dev, int startp);
 extern int ei_open(struct net_device *dev);
 extern int ei_close(struct net_device *dev);
--- diff/drivers/net/Kconfig	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/net/Kconfig	2004-03-09 11:51:50.000000000 +0000
@@ -2495,6 +2495,13 @@ config SHAPER
 	  To compile this driver as a module, choose M here: the module
 	  will be called shaper.  If unsure, say N.
 
+config NETCONSOLE
+	tristate "Network console logging support (EXPERIMENTAL)"
+	depends on NETDEVICES && EXPERIMENTAL
+	---help---
+	If you want to log kernel messages over the network, enable this.
+	See Documentation/networking/netconsole.txt for details.
+
 source "drivers/net/wan/Kconfig"
 
 source "drivers/net/pcmcia/Kconfig"
--- diff/drivers/net/Makefile	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/net/Makefile	2004-03-09 11:51:50.000000000 +0000
@@ -188,3 +188,6 @@ obj-$(CONFIG_NET_TULIP) += tulip/
 obj-$(CONFIG_HAMRADIO) += hamradio/
 obj-$(CONFIG_IRDA) += irda/
 
+# Must come after all NICs that might use them
+obj-$(CONFIG_NETCONSOLE) += netconsole.o
+obj-$(CONFIG_KGDB) += kgdb_eth.o
--- diff/drivers/net/ac3200.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/ac3200.c	2004-03-09 11:51:50.000000000 +0000
@@ -276,6 +276,9 @@ static int __init ac_probe1(int ioaddr, 
 
 	dev->open = &ac_open;
 	dev->stop = &ac_close_card;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 	return 0;
 out1:
--- diff/drivers/net/acenic.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/net/acenic.c	2004-03-09 11:51:50.000000000 +0000
@@ -131,7 +131,6 @@
 #define PCI_DEVICE_ID_SGI_ACENIC	0x0009
 #endif
 
-#if LINUX_VERSION_CODE >= 0x20400
 static struct pci_device_id acenic_pci_tbl[] = {
 	{ PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE,
 	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
@@ -156,37 +155,6 @@ static struct pci_device_id acenic_pci_t
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, acenic_pci_tbl);
-#endif
-
-
-#ifndef MODULE_LICENSE
-#define MODULE_LICENSE(a)
-#endif
-
-#ifndef wmb
-#define wmb()	mb()
-#endif
-
-#ifndef __exit
-#define __exit
-#endif
-
-#ifndef __devinit
-#define __devinit	__init
-#endif
-
-#ifndef SMP_CACHE_BYTES
-#define SMP_CACHE_BYTES	L1_CACHE_BYTES
-#endif
-
-#ifndef SET_MODULE_OWNER
-#define SET_MODULE_OWNER(dev)		do{} while(0)
-#define ACE_MOD_INC_USE_COUNT		MOD_INC_USE_COUNT
-#define ACE_MOD_DEC_USE_COUNT		MOD_DEC_USE_COUNT
-#else
-#define ACE_MOD_INC_USE_COUNT		do{} while(0)
-#define ACE_MOD_DEC_USE_COUNT		do{} while(0)
-#endif
 
 #ifndef SET_NETDEV_DEV
 #define SET_NETDEV_DEV(net, pdev)	do{} while(0)
@@ -198,151 +166,8 @@ MODULE_DEVICE_TABLE(pci, acenic_pci_tbl)
 #define ace_sync_irq(irq)	synchronize_irq()
 #endif
 
-#if LINUX_VERSION_CODE < 0x2051e
-#define local_irq_save(flags)		do{__save_flags(flags) ; \
-					   __cli();} while(0)
-#define local_irq_restore(flags)	__restore_flags(flags)
-#endif
-
-#if (LINUX_VERSION_CODE < 0x02030d)
-#define pci_resource_start(dev, bar)	dev->base_address[bar]
-#elif (LINUX_VERSION_CODE < 0x02032c)
-#define pci_resource_start(dev, bar)	dev->resource[bar].start
-#endif
-
-#if (LINUX_VERSION_CODE < 0x02030e)
-#define net_device device
-#endif
-
-
-#if (LINUX_VERSION_CODE < 0x02032a)
-typedef u32 dma_addr_t;
-
-static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
-					 dma_addr_t *dma_handle)
-{
-	void *virt_ptr;
-
-	virt_ptr = kmalloc(size, GFP_KERNEL);
-	if (!virt_ptr)
-		return NULL;
-	*dma_handle = virt_to_bus(virt_ptr);
-	return virt_ptr;
-}
-
-#define pci_free_consistent(cookie, size, ptr, dma_ptr)	kfree(ptr)
-#define pci_map_page(cookie, page, off, size, dir)	\
-	virt_to_bus(page_address(page)+(off))
-#define pci_unmap_page(cookie, address, size, dir)
-#define pci_set_dma_mask(dev, mask)		\
-	(((u64)(mask) & 0xffffffff00000000) == 0 ? 0 : -EIO)
-#define pci_dma_supported(dev, mask)		\
-	(((u64)(mask) & 0xffffffff00000000) == 0 ? 1 : 0)
-
-#elif (LINUX_VERSION_CODE < 0x02040d)
-
-/*
- * 2.4.13 introduced pci_map_page()/pci_unmap_page() - for 2.4.12 and prior,
- * fall back on pci_map_single()/pci_unnmap_single().
- *
- * We are guaranteed that the page is mapped at this point since
- * pci_map_page() is only used upon valid struct skb's.
- */
-static inline dma_addr_t
-pci_map_page(struct pci_dev *cookie, struct page *page, unsigned long off,
-	     size_t size, int dir)
-{
-	void *page_virt;
-
-	page_virt = page_address(page);
-	if (!page_virt)
-		BUG();
-	return pci_map_single(cookie, (page_virt + off), size, dir);
-}
-#define pci_unmap_page(cookie, dma_addr, size, dir)	\
-	pci_unmap_single(cookie, dma_addr, size, dir)
-#endif
-
-#if (LINUX_VERSION_CODE < 0x020412)
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
-#define pci_unmap_addr(PTR, ADDR_NAME)		0
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do{} while(0)
-#define pci_unmap_len(PTR, LEN_NAME)		0
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do{} while(0)
-#endif
-
-
-#if (LINUX_VERSION_CODE < 0x02032b)
-/*
- * SoftNet
- *
- * For pre-softnet kernels we need to tell the upper layer not to
- * re-enter start_xmit() while we are in there. However softnet
- * guarantees not to enter while we are in there so there is no need
- * to do the netif_stop_queue() dance unless the transmit queue really
- * gets stuck. This should also improve performance according to tests
- * done by Aman Singla.
- */
-#define dev_kfree_skb_irq(a)			dev_kfree_skb(a)
-#define netif_wake_queue(dev)			clear_bit(0, &dev->tbusy)
-#define netif_stop_queue(dev)			set_bit(0, &dev->tbusy)
-#define late_stop_netif_stop_queue(dev)		do{} while(0)
-#define early_stop_netif_stop_queue(dev)	test_and_set_bit(0,&dev->tbusy)
-#define early_stop_netif_wake_queue(dev)	netif_wake_queue(dev)
-
-static inline void netif_start_queue(struct net_device *dev)
-{
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
-}
-
-#define ace_mark_net_bh()			mark_bh(NET_BH)
-#define netif_queue_stopped(dev)		dev->tbusy
-#define netif_running(dev)			dev->start
-#define ace_if_down(dev)			do{dev->start = 0;} while(0)
-
-#define tasklet_struct				tq_struct
-static inline void tasklet_schedule(struct tasklet_struct *tasklet)
-{
-	queue_task(tasklet, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-}
-
-static inline void tasklet_init(struct tasklet_struct *tasklet,
-				void (*func)(unsigned long),
-				unsigned long data)
-{
-	tasklet->next = NULL;
-	tasklet->sync = 0;
-	tasklet->routine = (void (*)(void *))func;
-	tasklet->data = (void *)data;
-}
-#define tasklet_kill(tasklet)			do{} while(0)
-#else
-#define late_stop_netif_stop_queue(dev)		netif_stop_queue(dev)
-#define early_stop_netif_stop_queue(dev)	0
-#define early_stop_netif_wake_queue(dev)	do{} while(0)
-#define ace_mark_net_bh()			do{} while(0)
-#define ace_if_down(dev)			do{} while(0)
-#endif
-
-#if (LINUX_VERSION_CODE >= 0x02031b)
-#define NEW_NETINIT
-#define ACE_PROBE_ARG				void
-#else
-#define ACE_PROBE_ARG				struct net_device *dev
-#endif
-
-#ifndef min_t
-#define min_t(type,a,b)	(((a)<(b))?(a):(b))
-#endif
-
-#ifndef ARCH_HAS_PREFETCHW
-#ifndef prefetchw
-#define prefetchw(x)				do{} while(0)
-#endif
+#ifndef offset_in_page
+#define offset_in_page(ptr)	((unsigned long)(ptr) & ~PAGE_MASK)
 #endif
 
 #define ACE_MAX_MOD_PARMS	8
@@ -595,407 +420,323 @@ static int max_rx_desc[ACE_MAX_MOD_PARMS
 static int tx_ratio[ACE_MAX_MOD_PARMS];
 static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1};
 
+MODULE_AUTHOR("Jes Sorensen <jes@trained-monkey.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver");
+MODULE_PARM(link, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(trace, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(tx_coal_tick, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(max_tx_desc, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(rx_coal_tick, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(tx_ratio, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM_DESC(link, "AceNIC/3C985/NetGear link state");
+MODULE_PARM_DESC(trace, "AceNIC/3C985/NetGear firmware trace level");
+MODULE_PARM_DESC(tx_coal_tick, "AceNIC/3C985/GA620 max clock ticks to wait from first tx descriptor arrives");
+MODULE_PARM_DESC(max_tx_desc, "AceNIC/3C985/GA620 max number of transmit descriptors to wait");
+MODULE_PARM_DESC(rx_coal_tick, "AceNIC/3C985/GA620 max clock ticks to wait from first rx descriptor arrives");
+MODULE_PARM_DESC(max_rx_desc, "AceNIC/3C985/GA620 max number of receive descriptors to wait");
+MODULE_PARM_DESC(tx_ratio, "AceNIC/3C985/GA620 ratio of NIC memory used for TX/RX descriptors (range 0-63)");
+
+
 static char version[] __initdata = 
   "acenic.c: v0.92 08/05/2002  Jes Sorensen, linux-acenic@SunSITE.dk\n"
   "                            http://home.cern.ch/~jes/gige/acenic.html\n";
 
-static struct net_device *root_dev;
-
-static int probed __initdata = 0;
-
-
-int __devinit acenic_probe (ACE_PROBE_ARG)
+static int __devinit acenic_probe_one(struct pci_dev *pdev,
+		const struct pci_device_id *id)
 {
-#ifdef NEW_NETINIT
 	struct net_device *dev;
-#endif
 	struct ace_private *ap;
-	struct pci_dev *pdev = NULL;
-	int boards_found = 0;
-	int version_disp;
-
-	if (probed)
-		return -ENODEV;
-	probed++;
-
-	version_disp = 0;
-
-	while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET<<8, pdev))) {
-
-		if (!((pdev->vendor == PCI_VENDOR_ID_ALTEON) &&
-		      ((pdev->device == PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE) ||
-		       (pdev->device == PCI_DEVICE_ID_ALTEON_ACENIC_COPPER)))&&
-		    !((pdev->vendor == PCI_VENDOR_ID_3COM) &&
-		      (pdev->device == PCI_DEVICE_ID_3COM_3C985)) &&
-		    !((pdev->vendor == PCI_VENDOR_ID_NETGEAR) &&
-		      ((pdev->device == PCI_DEVICE_ID_NETGEAR_GA620) || 
-		       (pdev->device == PCI_DEVICE_ID_NETGEAR_GA620T))) &&
-		/*
-		 * Farallon used the DEC vendor ID on their cards by
-		 * mistake for a while
-		 */
-		    !((pdev->vendor == PCI_VENDOR_ID_DEC) &&
-		      (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX)) &&
-		    !((pdev->vendor == PCI_VENDOR_ID_ALTEON) &&
-		      (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T)) &&
-		    !((pdev->vendor == PCI_VENDOR_ID_SGI) &&
-		      (pdev->device == PCI_DEVICE_ID_SGI_ACENIC)))
-			continue;
-
-		dev = alloc_etherdev(sizeof(struct ace_private));
-		if (dev == NULL) {
-			printk(KERN_ERR "acenic: Unable to allocate "
-			       "net_device structure!\n");
-			break;
-		}
+	static int boards_found;
 
-		SET_MODULE_OWNER(dev);
-		SET_NETDEV_DEV(dev, &pdev->dev);
+	dev = alloc_etherdev(sizeof(struct ace_private));
+	if (dev == NULL) {
+		printk(KERN_ERR "acenic: Unable to allocate "
+		       "net_device structure!\n");
+		return -ENOMEM;
+	}
 
-		ap = dev->priv;
-		ap->pdev = pdev;
+	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
-		dev->open = &ace_open;
-		dev->hard_start_xmit = &ace_start_xmit;
-		dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+	ap = dev->priv;
+	ap->pdev = pdev;
+
+	dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
 #if ACENIC_DO_VLAN
-		dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-		dev->vlan_rx_register = ace_vlan_rx_register;
-		dev->vlan_rx_kill_vid = ace_vlan_rx_kill_vid;
-#endif
-		if (1) {
-			static void ace_watchdog(struct net_device *dev);
-			dev->tx_timeout = &ace_watchdog;
-			dev->watchdog_timeo = 5*HZ;
-		}
-		dev->stop = &ace_close;
-		dev->get_stats = &ace_get_stats;
-		dev->set_multicast_list = &ace_set_multicast_list;
-		dev->do_ioctl = &ace_ioctl;
-		dev->set_mac_address = &ace_set_mac_addr;
-		dev->change_mtu = &ace_change_mtu;
+	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+	dev->vlan_rx_register = ace_vlan_rx_register;
+	dev->vlan_rx_kill_vid = ace_vlan_rx_kill_vid;
+#endif
+	if (1) {
+		static void ace_watchdog(struct net_device *dev);
+		dev->tx_timeout = &ace_watchdog;
+		dev->watchdog_timeo = 5*HZ;
+	}
 
-		/* display version info if adapter is found */
-		if (!version_disp)
-		{
-			/* set display flag to TRUE so that */
-			/* we only display this string ONCE */
-			version_disp = 1;
-			printk(version);
-		}
+	dev->open = &ace_open;
+	dev->stop = &ace_close;
+	dev->hard_start_xmit = &ace_start_xmit;
+	dev->get_stats = &ace_get_stats;
+	dev->set_multicast_list = &ace_set_multicast_list;
+	dev->do_ioctl = &ace_ioctl;
+	dev->set_mac_address = &ace_set_mac_addr;
+	dev->change_mtu = &ace_change_mtu;
 
-		if (pci_enable_device(pdev)) {
-			free_netdev(dev);
-			continue;
-		}
+	/* we only display this string ONCE */
+	if (!boards_found)
+		printk(version);
 
-		/*
-		 * Enable master mode before we start playing with the
-		 * pci_command word since pci_set_master() will modify
-		 * it.
-		 */
-		pci_set_master(pdev);
+	if (pci_enable_device(pdev))
+		goto fail_free_netdev;
 
-		pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command);
+	/*
+	 * Enable master mode before we start playing with the
+	 * pci_command word since pci_set_master() will modify
+	 * it.
+	 */
+	pci_set_master(pdev);
 
-		/* OpenFirmware on Mac's does not set this - DOH.. */ 
-		if (!(ap->pci_command & PCI_COMMAND_MEMORY)) {
-			printk(KERN_INFO "%s: Enabling PCI Memory Mapped "
-			       "access - was not enabled by BIOS/Firmware\n",
-			       dev->name);
-			ap->pci_command = ap->pci_command | PCI_COMMAND_MEMORY;
-			pci_write_config_word(ap->pdev, PCI_COMMAND,
-					      ap->pci_command);
-			wmb();
-		}
+	pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command);
 
-		pci_read_config_byte(pdev, PCI_LATENCY_TIMER,
-				     &ap->pci_latency);
-		if (ap->pci_latency <= 0x40) {
-			ap->pci_latency = 0x40;
-			pci_write_config_byte(pdev, PCI_LATENCY_TIMER,
-					      ap->pci_latency);
-		}
+	/* OpenFirmware on Mac's does not set this - DOH.. */ 
+	if (!(ap->pci_command & PCI_COMMAND_MEMORY)) {
+		printk(KERN_INFO "%s: Enabling PCI Memory Mapped "
+		       "access - was not enabled by BIOS/Firmware\n",
+		       dev->name);
+		ap->pci_command = ap->pci_command | PCI_COMMAND_MEMORY;
+		pci_write_config_word(ap->pdev, PCI_COMMAND,
+				      ap->pci_command);
+		wmb();
+	}
 
-		/*
-		 * Remap the regs into kernel space - this is abuse of
-		 * dev->base_addr since it was means for I/O port
-		 * addresses but who gives a damn.
-		 */
-		dev->base_addr = pci_resource_start(pdev, 0);
-		ap->regs = (struct ace_regs *)ioremap(dev->base_addr, 0x4000);
-		if (!ap->regs) {
-			printk(KERN_ERR "%s:  Unable to map I/O register, "
-			       "AceNIC %i will be disabled.\n",
-			       dev->name, boards_found);
-			break;
-		}
+	pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &ap->pci_latency);
+	if (ap->pci_latency <= 0x40) {
+		ap->pci_latency = 0x40;
+		pci_write_config_byte(pdev, PCI_LATENCY_TIMER, ap->pci_latency);
+	}
 
-		switch(pdev->vendor) {
-		case PCI_VENDOR_ID_ALTEON:
-			if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T) {
-				strncpy(ap->name, "Farallon PN9100-T "
-					"Gigabit Ethernet", sizeof (ap->name));
-				printk(KERN_INFO "%s: Farallon PN9100-T ",
-				       dev->name);
-			} else {
-				strncpy(ap->name, "AceNIC Gigabit Ethernet",
-					sizeof (ap->name));
-				printk(KERN_INFO "%s: Alteon AceNIC ",
-				       dev->name);
-			}
-			break;
-		case PCI_VENDOR_ID_3COM:
-			strncpy(ap->name, "3Com 3C985 Gigabit Ethernet",
-				sizeof (ap->name));
-			printk(KERN_INFO "%s: 3Com 3C985 ", dev->name);
-			break;
-		case PCI_VENDOR_ID_NETGEAR:
-			strncpy(ap->name, "NetGear GA620 Gigabit Ethernet",
-				sizeof (ap->name));
-			printk(KERN_INFO "%s: NetGear GA620 ", dev->name);
-			break;
-		case PCI_VENDOR_ID_DEC:
-			if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX) {
-				strncpy(ap->name, "Farallon PN9000-SX "
-					"Gigabit Ethernet", sizeof (ap->name));
-				printk(KERN_INFO "%s: Farallon PN9000-SX ",
-				       dev->name);
-				break;
-			}
-		case PCI_VENDOR_ID_SGI:
-			strncpy(ap->name, "SGI AceNIC Gigabit Ethernet",
+	/*
+	 * Remap the regs into kernel space - this is abuse of
+	 * dev->base_addr since it was means for I/O port
+	 * addresses but who gives a damn.
+	 */
+	dev->base_addr = pci_resource_start(pdev, 0);
+	ap->regs = (struct ace_regs *)ioremap(dev->base_addr, 0x4000);
+	if (!ap->regs) {
+		printk(KERN_ERR "%s:  Unable to map I/O register, "
+		       "AceNIC %i will be disabled.\n",
+		       dev->name, boards_found);
+		goto fail_free_netdev;
+	}
+
+	switch(pdev->vendor) {
+	case PCI_VENDOR_ID_ALTEON:
+		if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T) {
+			strncpy(ap->name, "Farallon PN9100-T "
+				"Gigabit Ethernet", sizeof (ap->name));
+			printk(KERN_INFO "%s: Farallon PN9100-T ",
+			       dev->name);
+		} else {
+			strncpy(ap->name, "AceNIC Gigabit Ethernet",
 				sizeof (ap->name));
-			printk(KERN_INFO "%s: SGI AceNIC ", dev->name);
-			break;
-		default:
- 			strncpy(ap->name, "Unknown AceNIC based Gigabit "
-				"Ethernet", sizeof (ap->name));
-			printk(KERN_INFO "%s: Unknown AceNIC ", dev->name);
+			printk(KERN_INFO "%s: Alteon AceNIC ",
+			       dev->name);
+		}
+		break;
+	case PCI_VENDOR_ID_3COM:
+		strncpy(ap->name, "3Com 3C985 Gigabit Ethernet",
+			sizeof (ap->name));
+		printk(KERN_INFO "%s: 3Com 3C985 ", dev->name);
+		break;
+	case PCI_VENDOR_ID_NETGEAR:
+		strncpy(ap->name, "NetGear GA620 Gigabit Ethernet",
+			sizeof (ap->name));
+		printk(KERN_INFO "%s: NetGear GA620 ", dev->name);
+		break;
+	case PCI_VENDOR_ID_DEC:
+		if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX) {
+			strncpy(ap->name, "Farallon PN9000-SX "
+				"Gigabit Ethernet", sizeof (ap->name));
+			printk(KERN_INFO "%s: Farallon PN9000-SX ",
+			       dev->name);
 			break;
 		}
-		ap->name [sizeof (ap->name) - 1] = '\0';
-		printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr);
+	case PCI_VENDOR_ID_SGI:
+		strncpy(ap->name, "SGI AceNIC Gigabit Ethernet",
+			sizeof (ap->name));
+		printk(KERN_INFO "%s: SGI AceNIC ", dev->name);
+		break;
+	default:
+ 		strncpy(ap->name, "Unknown AceNIC based Gigabit "
+			"Ethernet", sizeof (ap->name));
+		printk(KERN_INFO "%s: Unknown AceNIC ", dev->name);
+		break;
+	}
+
+	ap->name [sizeof (ap->name) - 1] = '\0';
+	printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr);
 #ifdef __sparc__
-		printk("irq %s\n", __irq_itoa(pdev->irq));
+	printk("irq %s\n", __irq_itoa(pdev->irq));
 #else
-		printk("irq %i\n", pdev->irq);
+	printk("irq %i\n", pdev->irq);
 #endif
 
 #ifdef CONFIG_ACENIC_OMIT_TIGON_I
-		if ((readl(&ap->regs->HostCtrl) >> 28) == 4) {
-			printk(KERN_ERR "%s: Driver compiled without Tigon I"
-			       " support - NIC disabled\n", dev->name);
-			ace_init_cleanup(dev);
-			free_netdev(dev);
-			continue;
-		}
+	if ((readl(&ap->regs->HostCtrl) >> 28) == 4) {
+		printk(KERN_ERR "%s: Driver compiled without Tigon I"
+		       " support - NIC disabled\n", dev->name);
+		goto fail_uninit;
+	}
 #endif
 
-		if (ace_allocate_descriptors(dev)) {
-			/*
-			 * ace_allocate_descriptors() calls
-			 * ace_init_cleanup() on error.
-			 */
-			free_netdev(dev);
-			continue;
-		}
+	if (ace_allocate_descriptors(dev))
+		goto fail_free_netdev;
 
 #ifdef MODULE
-		if (boards_found >= ACE_MAX_MOD_PARMS)
-			ap->board_idx = BOARD_IDX_OVERFLOW;
-		else
-			ap->board_idx = boards_found;
+	if (boards_found >= ACE_MAX_MOD_PARMS)
+		ap->board_idx = BOARD_IDX_OVERFLOW;
+	else
+		ap->board_idx = boards_found;
 #else
-		ap->board_idx = BOARD_IDX_STATIC;
+	ap->board_idx = BOARD_IDX_STATIC;
 #endif
 
-		if (ace_init(dev)) {
-			/*
-			 * ace_init() calls ace_init_cleanup() on error.
-			 */
-			free_netdev(dev);
-			continue;
-		}
+	if (ace_init(dev))
+		goto fail_free_netdev;
 
-		if (register_netdev(dev)) {
-			printk(KERN_ERR "acenic: device registration failed\n");
-			ace_init_cleanup(dev);
-			free_netdev(dev);
-			continue;
-		}
-
-		if (ap->pci_using_dac)
-			dev->features |= NETIF_F_HIGHDMA;
-
-		boards_found++;
+	if (register_netdev(dev)) {
+		printk(KERN_ERR "acenic: device registration failed\n");
+		goto fail_uninit;
 	}
 
-	/*
-	 * If we're at this point we're going through ace_probe() for
-	 * the first time.  Return success (0) if we've initialized 1
-	 * or more boards. Otherwise, return failure (-ENODEV).
-	 */
-
-	if (boards_found > 0)
-		return 0;
-	else
-		return -ENODEV;
-}
+	if (ap->pci_using_dac)
+		dev->features |= NETIF_F_HIGHDMA;
 
+	pci_set_drvdata(pdev, dev);
 
-#ifdef MODULE
-MODULE_AUTHOR("Jes Sorensen <jes@trained-monkey.org>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver");
-MODULE_PARM(link, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(trace, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(tx_coal_tick, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(max_tx_desc, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(rx_coal_tick, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(tx_ratio, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM_DESC(link, "AceNIC/3C985/NetGear link state");
-MODULE_PARM_DESC(trace, "AceNIC/3C985/NetGear firmware trace level");
-MODULE_PARM_DESC(tx_coal_tick, "AceNIC/3C985/GA620 max clock ticks to wait from first tx descriptor arrives");
-MODULE_PARM_DESC(max_tx_desc, "AceNIC/3C985/GA620 max number of transmit descriptors to wait");
-MODULE_PARM_DESC(rx_coal_tick, "AceNIC/3C985/GA620 max clock ticks to wait from first rx descriptor arrives");
-MODULE_PARM_DESC(max_rx_desc, "AceNIC/3C985/GA620 max number of receive descriptors to wait");
-MODULE_PARM_DESC(tx_ratio, "AceNIC/3C985/GA620 ratio of NIC memory used for TX/RX descriptors (range 0-63)");
-#endif
+	boards_found++;
+	return 0;
 
+ fail_uninit:
+	ace_init_cleanup(dev);
+ fail_free_netdev:
+	free_netdev(dev);
+	return -ENODEV;
+}
 
-static void __exit ace_module_cleanup(void)
+static void __devexit acenic_remove_one(struct pci_dev *pdev)
 {
-	struct ace_private *ap;
-	struct ace_regs *regs;
-	struct net_device *next;
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct ace_private *ap = dev->priv;
+	struct ace_regs *regs = ap->regs;
 	short i;
 
-	while (root_dev) {
-		ap = root_dev->priv;
-		next = ap->next;
-		unregister_netdev(root_dev);
+	unregister_netdev(dev);
 
-		regs = ap->regs;
-
-		writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
-		if (ap->version >= 2)
-			writel(readl(&regs->CpuBCtrl) | CPU_HALT,
-			       &regs->CpuBCtrl);
-		/*
-		 * This clears any pending interrupts
-		 */
-		writel(1, &regs->Mb0Lo);
-		readl(&regs->CpuCtrl);	/* flush */
+	writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
+	if (ap->version >= 2)
+		writel(readl(&regs->CpuBCtrl) | CPU_HALT, &regs->CpuBCtrl);
+	
+	/*
+	 * This clears any pending interrupts
+	 */
+	writel(1, &regs->Mb0Lo);
+	readl(&regs->CpuCtrl);	/* flush */
 
-		/*
-		 * Make sure no other CPUs are processing interrupts
-		 * on the card before the buffers are being released.
-		 * Otherwise one might experience some `interesting'
-		 * effects.
-		 *
-		 * Then release the RX buffers - jumbo buffers were
-		 * already released in ace_close().
-		 */
-		ace_sync_irq(root_dev->irq);
+	/*
+	 * Make sure no other CPUs are processing interrupts
+	 * on the card before the buffers are being released.
+	 * Otherwise one might experience some `interesting'
+	 * effects.
+	 *
+	 * Then release the RX buffers - jumbo buffers were
+	 * already released in ace_close().
+	 */
+	ace_sync_irq(dev->irq);
 
-		for (i = 0; i < RX_STD_RING_ENTRIES; i++) {
-			struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb;
+	for (i = 0; i < RX_STD_RING_ENTRIES; i++) {
+		struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb;
 
-			if (skb) {
-				struct ring_info *ringp;
-				dma_addr_t mapping;
+		if (skb) {
+			struct ring_info *ringp;
+			dma_addr_t mapping;
 
-				ringp = &ap->skb->rx_std_skbuff[i];
-				mapping = pci_unmap_addr(ringp, mapping);
-				pci_unmap_page(ap->pdev, mapping,
-					       ACE_STD_BUFSIZE - (2 + 16),
-					       PCI_DMA_FROMDEVICE);
+			ringp = &ap->skb->rx_std_skbuff[i];
+			mapping = pci_unmap_addr(ringp, mapping);
+			pci_unmap_page(ap->pdev, mapping,
+				       ACE_STD_BUFSIZE - (2 + 16),
+				       PCI_DMA_FROMDEVICE);
 
-				ap->rx_std_ring[i].size = 0;
-				ap->skb->rx_std_skbuff[i].skb = NULL;
-				dev_kfree_skb(skb);
-			}
-		}
-		if (ap->version >= 2) {
-			for (i = 0; i < RX_MINI_RING_ENTRIES; i++) {
-				struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb;
-
-				if (skb) {
-					struct ring_info *ringp;
-					dma_addr_t mapping;
-
-					ringp = &ap->skb->rx_mini_skbuff[i];
-					mapping = pci_unmap_addr(ringp,mapping);
-					pci_unmap_page(ap->pdev, mapping,
-						       ACE_MINI_BUFSIZE - (2 + 16),
-						       PCI_DMA_FROMDEVICE);
-
-					ap->rx_mini_ring[i].size = 0;
-					ap->skb->rx_mini_skbuff[i].skb = NULL;
-					dev_kfree_skb(skb);
-				}
-			}
+			ap->rx_std_ring[i].size = 0;
+			ap->skb->rx_std_skbuff[i].skb = NULL;
+			dev_kfree_skb(skb);
 		}
-		for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) {
-			struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb;
+	}
+
+	if (ap->version >= 2) {
+		for (i = 0; i < RX_MINI_RING_ENTRIES; i++) {
+			struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb;
+
 			if (skb) {
 				struct ring_info *ringp;
 				dma_addr_t mapping;
 
-				ringp = &ap->skb->rx_jumbo_skbuff[i];
-				mapping = pci_unmap_addr(ringp, mapping);
+				ringp = &ap->skb->rx_mini_skbuff[i];
+				mapping = pci_unmap_addr(ringp,mapping);
 				pci_unmap_page(ap->pdev, mapping,
-					       ACE_JUMBO_BUFSIZE - (2 + 16),
+					       ACE_MINI_BUFSIZE - (2 + 16),
 					       PCI_DMA_FROMDEVICE);
 
-				ap->rx_jumbo_ring[i].size = 0;
-				ap->skb->rx_jumbo_skbuff[i].skb = NULL;
+				ap->rx_mini_ring[i].size = 0;
+				ap->skb->rx_mini_skbuff[i].skb = NULL;
 				dev_kfree_skb(skb);
 			}
 		}
-
-		ace_init_cleanup(root_dev);
-		free_netdev(root_dev);
-		root_dev = next;
 	}
-}
 
+	for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) {
+		struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb;
+		if (skb) {
+			struct ring_info *ringp;
+			dma_addr_t mapping;
 
-int __init ace_module_init(void)
-{
-	int status;
+			ringp = &ap->skb->rx_jumbo_skbuff[i];
+			mapping = pci_unmap_addr(ringp, mapping);
+			pci_unmap_page(ap->pdev, mapping,
+				       ACE_JUMBO_BUFSIZE - (2 + 16),
+				       PCI_DMA_FROMDEVICE);
 
-	root_dev = NULL;
+			ap->rx_jumbo_ring[i].size = 0;
+			ap->skb->rx_jumbo_skbuff[i].skb = NULL;
+			dev_kfree_skb(skb);
+		}
+	}
 
-#ifdef NEW_NETINIT
-	status = acenic_probe();
-#else
-	status = acenic_probe(NULL);
-#endif
-	return status;
+	ace_init_cleanup(dev);
+	free_netdev(dev);
 }
 
+static struct pci_driver acenic_pci_driver = {
+	.name		= "acenic",
+	.id_table	= acenic_pci_tbl,
+	.probe		= acenic_probe_one,
+	.remove		= __devexit_p(acenic_remove_one),
+};
 
-#if (LINUX_VERSION_CODE < 0x02032a)
-#ifdef MODULE
-int init_module(void)
+static int __init acenic_init(void)
 {
-	return ace_module_init();
+	return pci_module_init(&acenic_pci_driver);
 }
 
-
-void cleanup_module(void)
+static void __exit acenic_exit(void)
 {
-	ace_module_cleanup();
+	pci_unregister_driver(&acenic_pci_driver);
 }
-#endif
-#else
-module_init(ace_module_init);
-module_exit(ace_module_cleanup);
-#endif
 
+module_init(acenic_init);
+module_exit(acenic_exit);
 
 static void ace_free_descriptors(struct net_device *dev)
 {
@@ -1462,13 +1203,6 @@ static int __init ace_init(struct net_de
 	} else
 		dev->irq = pdev->irq;
 
-	/*
-	 * Register the device here to be able to catch allocated
-	 * interrupt handlers in case the firmware doesn't come up.
-	 */
-	ap->next = root_dev;
-	root_dev = dev;
-
 #ifdef INDEX_DEBUG
 	spin_lock_init(&ap->debug_lock);
 	ap->last_tx = ACE_TX_RING_ENTRIES(ap) - 1;
@@ -2642,8 +2376,6 @@ static int ace_open(struct net_device *d
 
 	netif_start_queue(dev);
 
-	ACE_MOD_INC_USE_COUNT;
-
 	/*
 	 * Setup the bottom half rx ring refill handler
 	 */
@@ -2660,8 +2392,6 @@ static int ace_close(struct net_device *
 	unsigned long flags;
 	short i;
 
-	ace_if_down(dev);
-
 	/*
 	 * Without (or before) releasing irq and stopping hardware, this
 	 * is an absolute non-sense, by the way. It will be reset instantly
@@ -2733,7 +2463,6 @@ static int ace_close(struct net_device *
 	ace_unmask_irq(dev);
 	local_irq_restore(flags);
 
-	ACE_MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -2790,12 +2519,6 @@ static int ace_start_xmit(struct sk_buff
 	struct tx_desc *desc;
 	u32 idx, flagsize;
 
- 	/*
-	 * This only happens with pre-softnet, ie. 2.2.x kernels.
- 	 */
-	if (early_stop_netif_stop_queue(dev))
- 		return 1;
-
 restart:
 	idx = ap->tx_prd;
 
--- diff/drivers/net/amd8111e.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/net/amd8111e.c	2004-03-09 11:51:50.000000000 +0000
@@ -1153,6 +1153,17 @@ err_no_interrupt:
 	return IRQ_RETVAL(handled);
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void amd8111e_poll(struct net_device *dev)
+{ 
+	unsigned long flags;
+	local_save_flags(flags); 
+	local_irq_disable();
+	amd8111e_interrupt(0, dev, NULL);
+	local_irq_restore(flags); 
+} 
+#endif
+
 /*
 This function closes the network interface and updates the statistics so that most recent statistics will be available after the interface is down.
 */
@@ -1884,6 +1895,9 @@ static int __devinit amd8111e_probe_one(
 	dev->irq =pdev->irq;
 	dev->tx_timeout = amd8111e_tx_timeout; 
 	dev->watchdog_timeo = AMD8111E_TX_TIMEOUT; 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = amd8111e_poll; 
+#endif
 
 #if AMD8111E_VLAN_TAG_USED
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
--- diff/drivers/net/apne.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/net/apne.c	2004-03-09 11:51:50.000000000 +0000
@@ -333,6 +333,9 @@ static int __init apne_probe1(struct net
     ei_status.get_8390_hdr = &apne_get_8390_hdr;
     dev->open = &apne_open;
     dev->stop = &apne_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+    dev->poll_controller = ei_poll;
+#endif
     NS8390_init(dev, 0);
 
     pcmcia_ack_int(pcmcia_get_intreq());		/* ack PCMCIA int req */
--- diff/drivers/net/b44.c	2003-11-25 15:24:58.000000000 +0000
+++ source/drivers/net/b44.c	2004-03-09 11:51:50.000000000 +0000
@@ -667,6 +667,10 @@ static void b44_recycle_rx(struct b44 *b
 	dest_desc->ctrl = ctrl;
 	dest_desc->addr = src_desc->addr;
 	src_map->skb = NULL;
+
+	pci_dma_sync_single_for_device(bp->pdev, src_desc->addr,
+				       RX_PKT_BUF_SZ,
+				       PCI_DMA_FROMDEVICE);
 }
 
 static int b44_rx(struct b44 *bp, int budget)
@@ -686,9 +690,9 @@ static int b44_rx(struct b44 *bp, int bu
 		struct rx_header *rh;
 		u16 len;
 
-		pci_dma_sync_single(bp->pdev, map,
-				    RX_PKT_BUF_SZ,
-				    PCI_DMA_FROMDEVICE);
+		pci_dma_sync_single_for_cpu(bp->pdev, map,
+					    RX_PKT_BUF_SZ,
+					    PCI_DMA_FROMDEVICE);
 		rh = (struct rx_header *) skb->data;
 		len = cpu_to_le16(rh->len);
 		if ((len > (RX_PKT_BUF_SZ - bp->rx_offset)) ||
--- diff/drivers/net/dl2k.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/dl2k.c	2004-03-09 11:51:50.000000000 +0000
@@ -874,8 +874,6 @@ receive_packet (struct net_device *dev)
 		frame_status = le64_to_cpu (desc->status);
 		if (--cnt < 0)
 			break;
-		pci_dma_sync_single (np->pdev, desc->fraginfo, np->rx_buf_sz,
-				     PCI_DMA_FROMDEVICE);
 		/* Update rx error statistics, drop packet. */
 		if (frame_status & RFS_Errors) {
 			np->stats.rx_errors++;
@@ -898,6 +896,10 @@ receive_packet (struct net_device *dev)
 				skb_put (skb = np->rx_skbuff[entry], pkt_len);
 				np->rx_skbuff[entry] = NULL;
 			} else if ((skb = dev_alloc_skb (pkt_len + 2)) != NULL) {
+				pci_dma_sync_single_for_cpu(np->pdev,
+							    desc->fraginfo,
+							    np->rx_buf_sz,
+							    PCI_DMA_FROMDEVICE);
 				skb->dev = dev;
 				/* 16 byte align the IP header */
 				skb_reserve (skb, 2);
@@ -905,6 +907,10 @@ receive_packet (struct net_device *dev)
 						  np->rx_skbuff[entry]->tail,
 						  pkt_len, 0);
 				skb_put (skb, pkt_len);
+				pci_dma_sync_single_for_device(np->pdev,
+							       desc->fraginfo,
+							       np->rx_buf_sz,
+							       PCI_DMA_FROMDEVICE);
 			}
 			skb->protocol = eth_type_trans (skb, dev);
 #if 0			
--- diff/drivers/net/e100.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/net/e100.c	2004-03-09 11:51:50.000000000 +0000
@@ -158,7 +158,7 @@
 
 
 #define DRV_NAME		"e100"
-#define DRV_VERSION		"3.0.15"
+#define DRV_VERSION		"3.0.16"
 #define DRV_DESCRIPTION		"Intel(R) PRO/100 Network Driver"
 #define DRV_COPYRIGHT		"Copyright(c) 1999-2004 Intel Corporation"
 #define PFX			DRV_NAME ": "
@@ -1032,8 +1032,9 @@ static int e100_phy_init(struct nic *nic
 	nic->phy = (u32)id_hi << 16 | (u32)id_lo;
 	DPRINTK(HW, DEBUG, "phy ID = 0x%08X\n", nic->phy);
 
-	/* Handle National tx phy */
-	if(nic->phy == phy_nsc_tx) {
+	/* Handle National tx phys */
+#define NCS_PHY_MODEL_MASK	0xFFF0FFFF
+	if((nic->phy & NCS_PHY_MODEL_MASK) == phy_nsc_tx) {
 		/* Disable congestion control */
 		cong = mdio_read(netdev, nic->mii.phy_id, MII_NSC_CONG);
 		cong |= NSC_CONG_TXREADY;
@@ -1386,8 +1387,8 @@ static inline int e100_rx_alloc_skb(stru
 			(u32 *)&prev_rfd->link);
 		wmb();
 		prev_rfd->command &= ~cpu_to_le16(cb_el);
-		pci_dma_sync_single(nic->pdev, rx->prev->dma_addr,
-			sizeof(struct rfd), PCI_DMA_TODEVICE);
+		pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,
+					       sizeof(struct rfd), PCI_DMA_TODEVICE);
 	}
 
 	return 0;
@@ -1404,8 +1405,8 @@ static inline int e100_rx_indicate(struc
 		return -EAGAIN;
 
 	/* Need to sync before taking a peek at cb_complete bit */
-	pci_dma_sync_single(nic->pdev, rx->dma_addr,
-		sizeof(struct rfd), PCI_DMA_FROMDEVICE);
+	pci_dma_sync_single_for_cpu(nic->pdev, rx->dma_addr,
+				    sizeof(struct rfd), PCI_DMA_FROMDEVICE);
 	rfd_status = le16_to_cpu(rfd->status);
 
 	DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status);
@@ -1420,11 +1421,8 @@ static inline int e100_rx_indicate(struc
 		actual_size = RFD_BUF_LEN - sizeof(struct rfd);
 
 	/* Get data */
-	pci_dma_sync_single(nic->pdev, rx->dma_addr,
-		sizeof(struct rfd) + actual_size,
-		PCI_DMA_FROMDEVICE);
 	pci_unmap_single(nic->pdev, rx->dma_addr,
-		RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
+			 RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
 
 	/* Pull off the RFD and put the actual data (minus eth hdr) */
 	skb_reserve(skb, sizeof(struct rfd));
--- diff/drivers/net/e1000/e1000_ethtool.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/e1000/e1000_ethtool.c	2004-03-09 11:51:50.000000000 +0000
@@ -1191,16 +1191,16 @@ e1000_run_loopback_test(struct e1000_ada
 
 	for(i = 0; i < 64; i++) {
 		e1000_create_lbtest_frame(txdr->buffer_info[i].skb, 1024);
-		pci_dma_sync_single(pdev, txdr->buffer_info[i].dma,
-				    txdr->buffer_info[i].length,
-				    PCI_DMA_TODEVICE);
+		pci_dma_sync_single_for_device(pdev, txdr->buffer_info[i].dma,
+					       txdr->buffer_info[i].length,
+					       PCI_DMA_TODEVICE);
 	}
 	E1000_WRITE_REG(&adapter->hw, TDT, i);
 
 	msec_delay(200);
 
-	pci_dma_sync_single(pdev, rxdr->buffer_info[0].dma,
-			    rxdr->buffer_info[0].length, PCI_DMA_FROMDEVICE);
+	pci_dma_sync_single_for_cpu(pdev, rxdr->buffer_info[0].dma,
+				    rxdr->buffer_info[0].length, PCI_DMA_FROMDEVICE);
 
 	return e1000_check_lbtest_frame(rxdr->buffer_info[0].skb, 1024);
 }
--- diff/drivers/net/e2100.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/e2100.c	2004-03-09 11:51:50.000000000 +0000
@@ -269,6 +269,9 @@ static int __init e21_probe1(struct net_
 	ei_status.get_8390_hdr = &e21_get_8390_hdr;
 	dev->open = &e21_open;
 	dev->stop = &e21_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 
 	return 0;
--- diff/drivers/net/eepro100.c	2003-10-09 09:47:16.000000000 +0100
+++ source/drivers/net/eepro100.c	2004-03-09 11:51:50.000000000 +0000
@@ -654,6 +654,23 @@ err_out_none:
 	return -ENODEV;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+
+static void poll_speedo (struct net_device *dev)
+{
+	/* disable_irq is not very nice, but with the funny lockless design
+	   we have no other choice. */
+	disable_irq(dev->irq);
+	speedo_interrupt (dev->irq, dev, NULL);
+	enable_irq(dev->irq);
+}
+#endif
+
 static int __devinit speedo_found1(struct pci_dev *pdev,
 		long ioaddr, int card_idx, int acpi_idle_state)
 {
@@ -885,6 +902,9 @@ static int __devinit speedo_found1(struc
 	dev->get_stats = &speedo_get_stats;
 	dev->set_multicast_list = &set_rx_mode;
 	dev->do_ioctl = &speedo_ioctl;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = &poll_speedo;
+#endif
 
 	if (register_netdevice(dev))
 		goto err_free_unlock;
@@ -1306,8 +1326,8 @@ speedo_init_rx_ring(struct net_device *d
 		skb_reserve(skb, sizeof(struct RxFD));
 		if (last_rxf) {
 			last_rxf->link = cpu_to_le32(sp->rx_ring_dma[i]);
-			pci_dma_sync_single(sp->pdev, last_rxf_dma,
-					sizeof(struct RxFD), PCI_DMA_TODEVICE);
+			pci_dma_sync_single_for_device(sp->pdev, last_rxf_dma,
+										   sizeof(struct RxFD), PCI_DMA_TODEVICE);
 		}
 		last_rxf = rxf;
 		last_rxf_dma = sp->rx_ring_dma[i];
@@ -1316,14 +1336,14 @@ speedo_init_rx_ring(struct net_device *d
 		/* This field unused by i82557. */
 		rxf->rx_buf_addr = 0xffffffff;
 		rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
-		pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[i],
-				sizeof(struct RxFD), PCI_DMA_TODEVICE);
+		pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[i],
+									   sizeof(struct RxFD), PCI_DMA_TODEVICE);
 	}
 	sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
 	/* Mark the last entry as end-of-list. */
 	last_rxf->status = cpu_to_le32(0xC0000002);	/* '2' is flag value only. */
-	pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[RX_RING_SIZE-1],
-			sizeof(struct RxFD), PCI_DMA_TODEVICE);
+	pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[RX_RING_SIZE-1],
+								   sizeof(struct RxFD), PCI_DMA_TODEVICE);
 	sp->last_rxf = last_rxf;
 	sp->last_rxf_dma = last_rxf_dma;
 }
@@ -1696,8 +1716,8 @@ static inline struct RxFD *speedo_rx_all
 	skb->dev = dev;
 	skb_reserve(skb, sizeof(struct RxFD));
 	rxf->rx_buf_addr = 0xffffffff;
-	pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry],
-			sizeof(struct RxFD), PCI_DMA_TODEVICE);
+	pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry],
+								   sizeof(struct RxFD), PCI_DMA_TODEVICE);
 	return rxf;
 }
 
@@ -1710,8 +1730,8 @@ static inline void speedo_rx_link(struct
 	rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
 	sp->last_rxf->link = cpu_to_le32(rxf_dma);
 	sp->last_rxf->status &= cpu_to_le32(~0xC0000000);
-	pci_dma_sync_single(sp->pdev, sp->last_rxf_dma,
-			sizeof(struct RxFD), PCI_DMA_TODEVICE);
+	pci_dma_sync_single_for_device(sp->pdev, sp->last_rxf_dma,
+								   sizeof(struct RxFD), PCI_DMA_TODEVICE);
 	sp->last_rxf = rxf;
 	sp->last_rxf_dma = rxf_dma;
 }
@@ -1783,8 +1803,8 @@ speedo_rx(struct net_device *dev)
 		int status;
 		int pkt_len;
 
-		pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry],
-			sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
+		pci_dma_sync_single_for_cpu(sp->pdev, sp->rx_ring_dma[entry],
+									sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
 		status = le32_to_cpu(sp->rx_ringp[entry]->status);
 		pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff;
 
@@ -1830,8 +1850,9 @@ speedo_rx(struct net_device *dev)
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 				/* 'skb_put()' points to the start of sk_buff data area. */
-				pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry],
-					sizeof(struct RxFD) + pkt_len, PCI_DMA_FROMDEVICE);
+				pci_dma_sync_single_for_cpu(sp->pdev, sp->rx_ring_dma[entry],
+											sizeof(struct RxFD) + pkt_len,
+											PCI_DMA_FROMDEVICE);
 
 #if 1 || USE_IP_CSUM
 				/* Packet is in one chunk -- we can copy + cksum. */
@@ -1841,6 +1862,9 @@ speedo_rx(struct net_device *dev)
 				memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->tail,
 					   pkt_len);
 #endif
+				pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry],
+											   sizeof(struct RxFD) + pkt_len,
+											   PCI_DMA_FROMDEVICE);
 				npkts++;
 			} else {
 				/* Pass up the already-filled skbuff. */
@@ -1855,7 +1879,8 @@ speedo_rx(struct net_device *dev)
 				npkts++;
 				sp->rx_ringp[entry] = NULL;
 				pci_unmap_single(sp->pdev, sp->rx_ring_dma[entry],
-						PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
+								 PKT_BUF_SZ + sizeof(struct RxFD),
+								 PCI_DMA_FROMDEVICE);
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
@@ -2287,8 +2312,8 @@ static void set_rx_mode(struct net_devic
 		mc_setup_frm->link =
 			cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE));
 
-		pci_dma_sync_single(sp->pdev, mc_blk->frame_dma,
-				mc_blk->len, PCI_DMA_TODEVICE);
+		pci_dma_sync_single_for_device(sp->pdev, mc_blk->frame_dma,
+									   mc_blk->len, PCI_DMA_TODEVICE);
 
 		wait_for_cmd_done(dev);
 		clear_suspend(last_cmd);
--- diff/drivers/net/epic100.c	2003-09-17 12:28:07.000000000 +0100
+++ source/drivers/net/epic100.c	2004-03-09 11:51:50.000000000 +0000
@@ -1199,8 +1199,6 @@ static int epic_rx(struct net_device *de
 			short pkt_len = (status >> 16) - 4;
 			struct sk_buff *skb;
 
-			pci_dma_sync_single(ep->pci_dev, ep->rx_ring[entry].bufaddr, 
-					    ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
 			if (pkt_len > PKT_BUF_SZ - 4) {
 				printk(KERN_ERR "%s: Oversized Ethernet frame, status %x "
 					   "%d bytes.\n",
@@ -1213,6 +1211,10 @@ static int epic_rx(struct net_device *de
 				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
+				pci_dma_sync_single_for_cpu(ep->pci_dev,
+							    ep->rx_ring[entry].bufaddr,
+							    ep->rx_buf_sz,
+							    PCI_DMA_FROMDEVICE);
 #if 1 /* HAS_IP_COPYSUM */
 				eth_copy_and_sum(skb, ep->rx_skbuff[entry]->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
@@ -1220,6 +1222,10 @@ static int epic_rx(struct net_device *de
 				memcpy(skb_put(skb, pkt_len), ep->rx_skbuff[entry]->tail,
 					   pkt_len);
 #endif
+				pci_dma_sync_single_for_device(ep->pci_dev,
+							       ep->rx_ring[entry].bufaddr,
+							       ep->rx_buf_sz,
+							       PCI_DMA_FROMDEVICE);
 			} else {
 				pci_unmap_single(ep->pci_dev, 
 					ep->rx_ring[entry].bufaddr, 
--- diff/drivers/net/es3210.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/es3210.c	2004-03-09 11:51:50.000000000 +0000
@@ -298,6 +298,9 @@ static int __init es_probe1(struct net_d
 
 	dev->open = &es_open;
 	dev->stop = &es_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 	return 0;
 out1:
--- diff/drivers/net/fealnx.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/fealnx.c	2004-03-09 11:51:50.000000000 +0000
@@ -1647,10 +1647,6 @@ static int netdev_rx(struct net_device *
 				printk(KERN_DEBUG "  netdev_rx() normal Rx pkt length %d"
 				       " status %x.\n", pkt_len, rx_status);
 #endif
-			pci_dma_sync_single(np->pci_dev, np->cur_rx->buffer,
-				np->rx_buf_sz, PCI_DMA_FROMDEVICE);
-			pci_unmap_single(np->pci_dev, np->cur_rx->buffer,
-				np->rx_buf_sz, PCI_DMA_FROMDEVICE);
 
 			/* Check if the packet is long enough to accept without copying
 			   to a minimally-sized skbuff. */
@@ -1658,6 +1654,10 @@ static int netdev_rx(struct net_device *
 			    (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
+				pci_dma_sync_single_for_cpu(np->pci_dev,
+							    np->cur_rx->buffer,
+							    np->rx_buf_sz,
+							    PCI_DMA_FROMDEVICE);
 				/* Call copy + cksum if available. */
 
 #if ! defined(__alpha__)
@@ -1668,7 +1668,15 @@ static int netdev_rx(struct net_device *
 				memcpy(skb_put(skb, pkt_len),
 					np->cur_rx->skbuff->tail, pkt_len);
 #endif
+				pci_dma_sync_single_for_device(np->pci_dev,
+							       np->cur_rx->buffer,
+							       np->rx_buf_sz,
+							       PCI_DMA_FROMDEVICE);
 			} else {
+				pci_unmap_single(np->pci_dev,
+						 np->cur_rx->buffer,
+						 np->rx_buf_sz,
+						 PCI_DMA_FROMDEVICE);
 				skb_put(skb = np->cur_rx->skbuff, pkt_len);
 				np->cur_rx->skbuff = NULL;
 				if (np->really_rx_count == RX_RING_SIZE)
@@ -1689,8 +1697,10 @@ static int netdev_rx(struct net_device *
 
 			if (skb != NULL) {
 				skb->dev = dev;	/* Mark as being used by this device. */
-				np->cur_rx->buffer = pci_map_single(np->pci_dev, skb->tail,
-					np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+				np->cur_rx->buffer = pci_map_single(np->pci_dev,
+								    skb->tail,
+								    np->rx_buf_sz,
+								    PCI_DMA_FROMDEVICE);
 				np->cur_rx->skbuff = skb;
 				++np->really_rx_count;
 			}
--- diff/drivers/net/hamachi.c	2003-09-30 15:46:15.000000000 +0100
+++ source/drivers/net/hamachi.c	2004-03-09 11:51:50.000000000 +0000
@@ -1498,8 +1498,10 @@ static int hamachi_rx(struct net_device 
 		
 		if (desc_status & DescOwn)
 			break;
-		pci_dma_sync_single(hmp->pci_dev, desc->addr, hmp->rx_buf_sz, 
-			PCI_DMA_FROMDEVICE);
+		pci_dma_sync_single_for_cpu(hmp->pci_dev,
+					    desc->addr,
+					    hmp->rx_buf_sz,
+					    PCI_DMA_FROMDEVICE);
 		buf_addr = desc_to_virt(desc->addr);
 		frame_status = le32_to_cpu(get_unaligned((s32*)&(buf_addr[data_size - 12])));
 		if (hamachi_debug > 4)
@@ -1563,6 +1565,10 @@ static int hamachi_rx(struct net_device 
 #endif
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
+				pci_dma_sync_single_for_cpu(hmp->pci_dev,
+							    hmp->rx_ring[entry].addr,
+							    hmp->rx_buf_sz,
+							    PCI_DMA_FROMDEVICE);
 				/* Call copy + cksum if available. */
 #if 1 || USE_IP_COPYSUM
 				eth_copy_and_sum(skb, 
@@ -1572,10 +1578,14 @@ static int hamachi_rx(struct net_device 
 				memcpy(skb_put(skb, pkt_len), hmp->rx_ring_dma
 					+ entry*sizeof(*desc), pkt_len);
 #endif
+				pci_dma_sync_single_for_device(hmp->pci_dev,
+							       hmp->rx_ring[entry].addr,
+							       hmp->rx_buf_sz,
+							       PCI_DMA_FROMDEVICE);
 			} else {
 				pci_unmap_single(hmp->pci_dev, 
-					hmp->rx_ring[entry].addr, 
-					hmp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+						 hmp->rx_ring[entry].addr,
+						 hmp->rx_buf_sz, PCI_DMA_FROMDEVICE);
 				skb_put(skb = hmp->rx_skbuff[entry], pkt_len);
 				hmp->rx_skbuff[entry] = NULL;
 			}
--- diff/drivers/net/hp-plus.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/hp-plus.c	2004-03-09 11:51:50.000000000 +0000
@@ -236,6 +236,9 @@ static int __init hpp_probe1(struct net_
 
 	dev->open = &hpp_open;
 	dev->stop = &hpp_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 
 	ei_status.name = name;
 	ei_status.word16 = 0;		/* Agggghhhhh! Debug time: 2 days! */
--- diff/drivers/net/hp.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/hp.c	2004-03-09 11:51:50.000000000 +0000
@@ -207,6 +207,9 @@ static int __init hp_probe1(struct net_d
 	dev->base_addr = ioaddr + NIC_OFFSET;
 	dev->open = &hp_open;
 	dev->stop = &hp_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 
 	ei_status.name = name;
 	ei_status.word16 = wordmode;
--- diff/drivers/net/hydra.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/net/hydra.c	2004-03-09 11:51:50.000000000 +0000
@@ -142,6 +142,10 @@ static int __devinit hydra_init(struct z
     ei_status.reg_offset = hydra_offsets;
     dev->open = &hydra_open;
     dev->stop = &hydra_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+    dev->poll_controller = ei_poll;
+#endif
+
     NS8390_init(dev, 0);
 
     err = register_netdev(dev);
--- diff/drivers/net/irda/stir4200.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/net/irda/stir4200.c	2004-03-09 11:51:50.000000000 +0000
@@ -49,12 +49,14 @@
 #include <linux/suspend.h>
 #include <linux/slab.h>
 #include <linux/usb.h>
+#include <linux/crc32.h>
 #include <net/irda/irda.h>
 #include <net/irda/irlap.h>
 #include <net/irda/irda_device.h>
 #include <net/irda/wrapper.h>
 #include <net/irda/crc.h>
-#include <linux/crc32.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
 
 MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>");
 MODULE_DESCRIPTION("IrDA-USB Dongle Driver for SigmaTel STIr4200");
@@ -72,15 +74,11 @@ static int tx_power = 0;	/* 0 = highest 
 module_param(tx_power, int, 0);
 MODULE_PARM_DESC(tx_power, "Set Transmitter power (0-3, 0 is highest power)");
 
-static int rx_interval = 5;  /* milliseconds */
-module_param(rx_interval, int, 0);
-MODULE_PARM_DESC(rx_interval, "Receive polling interval (ms)");
-
 #define STIR_IRDA_HEADER  	4
 #define CTRL_TIMEOUT		100	   /* milliseconds */
 #define TRANSMIT_TIMEOUT	200	   /* milliseconds */
 #define STIR_FIFO_SIZE		4096
-#define NUM_RX_URBS		2
+#define FIFO_REGS_SIZE		3
 
 enum FirChars {
 	FIR_CE   = 0x7d,
@@ -167,36 +165,26 @@ enum StirTestMask {
 	TEST_TSTOSC = 0x0F,
 };
 
-enum StirState {
-	STIR_STATE_RECEIVING=0,
-	STIR_STATE_TXREADY,
-};
-
 struct stir_cb {
         struct usb_device *usbdev;      /* init: probe_irda */
         struct net_device *netdev;      /* network layer */
         struct irlap_cb   *irlap;       /* The link layer we are binded to */
         struct net_device_stats stats;	/* network statistics */
         struct qos_info   qos;
-	unsigned long     state;
 	unsigned 	  speed;	/* Current speed */
 
 	wait_queue_head_t thr_wait;	/* transmit thread wakeup */
 	struct completion thr_exited;
 	pid_t		  thr_pid;
 
-	unsigned int	  tx_bulkpipe;
-	void		 *tx_data;	/* wrapped data out */
-	unsigned	  tx_len;
-	unsigned	  tx_newspeed;
-	unsigned	  tx_mtt;
+	struct sk_buff	  *tx_pending;
+	void		  *io_buf;	/* transmit/receive buffer */
+	__u8		  *fifo_status;
 
-	unsigned int	  rx_intpipe;
 	iobuff_t  	  rx_buff;	/* receive unwrap state machine */
-	struct timespec	  rx_time;
-
-	struct urb	 *rx_urbs[NUM_RX_URBS];
-	void		 *rx_data[NUM_RX_URBS];
+	struct timeval	  rx_time;
+	int		  receiving;
+	struct urb	 *rx_urb;
 };
 
 
@@ -209,9 +197,6 @@ static struct usb_device_id dongles[] = 
 
 MODULE_DEVICE_TABLE(usb, dongles);
 
-static int fifo_txwait(struct stir_cb *stir, unsigned space);
-static void stir_usb_receive(struct urb *urb, struct pt_regs *regs);
-
 /* Send control message to set dongle register */
 static int write_reg(struct stir_cb *stir, __u16 reg, __u8 value)
 {
@@ -239,6 +224,11 @@ static inline int read_reg(struct stir_c
 			       MSECS_TO_JIFFIES(CTRL_TIMEOUT));
 }
 
+static inline int isfir(u32 speed)
+{
+	return (speed == 4000000);
+}
+
 /*
  * Prepare a FIR IrDA frame for transmission to the USB dongle.  The
  * FIR transmit frame is documented in the datasheet.  It consists of
@@ -333,8 +323,8 @@ static void fir_eof(struct stir_cb *stir
 {
 	iobuff_t *rx_buff = &stir->rx_buff;
 	int len = rx_buff->len - 4;
+	struct sk_buff *skb, *nskb;
 	__u32 fcs;
-	struct sk_buff *nskb;
 
 	if (unlikely(len <= 0)) {
 		pr_debug("%s: short frame len %d\n",
@@ -345,41 +335,46 @@ static void fir_eof(struct stir_cb *stir
 		return;
 	}
 
-	fcs = rx_buff->data[len] |
-		rx_buff->data[len+1] << 8 |
-		rx_buff->data[len+2] << 16 |
-		rx_buff->data[len+3] << 24;
-
-	if (unlikely(fcs != ~(crc32_le(~0, rx_buff->data, len)))) {
-		pr_debug("%s: crc error\n", stir->netdev->name);
-		irda_device_set_media_busy(stir->netdev, TRUE);
+	fcs = ~(crc32_le(~0, rx_buff->data, len));
+	if (fcs != le32_to_cpu(get_unaligned((u32 *)(rx_buff->data+len)))) {
+		pr_debug("crc error calc 0x%x len %d\n", fcs, len);
 		stir->stats.rx_errors++;
 		stir->stats.rx_crc_errors++;
 		return;
 	}
 
-	/* If can't get new buffer, just drop and reuse */
-	nskb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
-	if (unlikely(!nskb))
-		++stir->stats.rx_dropped;
-	else {
-		struct sk_buff *oskb = rx_buff->skb;
+	/* if frame is short then just copy it */
+	if (len < IRDA_RX_COPY_THRESHOLD) {
+		nskb = dev_alloc_skb(len + 1);
+		if (unlikely(!nskb)) {
+			++stir->stats.rx_dropped;
+			return;
+		}
+		skb_reserve(nskb, 1);
+		skb = nskb;
+		memcpy(nskb->data, rx_buff->data, len);
+	} else {
+		nskb = dev_alloc_skb(rx_buff->truesize);
+		if (unlikely(!nskb)) {
+			++stir->stats.rx_dropped;
+			return;
+		}
 		skb_reserve(nskb, 1);
+		skb = rx_buff->skb;
+		rx_buff->skb = nskb;
+		rx_buff->head = nskb->data;
+	}
 
-		/* Set correct length in socket buffer */
-		skb_put(oskb, len);
+	skb_put(skb, len);
 
-		oskb->mac.raw  = oskb->data;
-		oskb->protocol = htons(ETH_P_IRDA);
-		oskb->dev = stir->netdev;
+	skb->mac.raw  = skb->data;
+	skb->protocol = htons(ETH_P_IRDA);
+	skb->dev = stir->netdev;
 
-		netif_rx(oskb);
+	netif_rx(skb);
 
-		stir->stats.rx_packets++;
-		stir->stats.rx_bytes += len;
-		rx_buff->skb = nskb;
-		rx_buff->head = nskb->data;
-	}
+	stir->stats.rx_packets++;
+	stir->stats.rx_bytes += len;
 
 	rx_buff->data = rx_buff->head;
 	rx_buff->len = 0;
@@ -402,7 +397,6 @@ static void stir_fir_chars(struct stir_c
 				continue;
 			/* Now receiving frame */
 			rx_buff->state = BEGIN_FRAME;
-			rx_buff->in_frame = TRUE;
 
 			/* Time to initialize receive buffer */
 			rx_buff->data = rx_buff->head;
@@ -424,6 +418,7 @@ static void stir_fir_chars(struct stir_c
 			if (byte == FIR_EOF)
 				continue;
 			rx_buff->state = INSIDE_FRAME;
+			rx_buff->in_frame = TRUE;
 
 			/* fall through */
 		case INSIDE_FRAME:
@@ -461,7 +456,6 @@ static void stir_fir_chars(struct stir_c
 
 	error_recovery:
 		++stir->stats.rx_errors;
-		irda_device_set_media_busy(stir->netdev, TRUE);
 		rx_buff->state = OUTSIDE_FRAME;
 		rx_buff->in_frame = FALSE;
 	}
@@ -478,11 +472,6 @@ static void stir_sir_chars(struct stir_c
 				  &stir->rx_buff, bytes[i]);
 }
 
-static inline int isfir(u32 speed)
-{
-	return (speed == 4000000);
-}
-
 static inline void unwrap_chars(struct stir_cb *stir,
 				const __u8 *bytes, int length)
 {
@@ -519,25 +508,31 @@ static int change_speed(struct stir_cb *
 	int i, err;
 	__u8 mode;
 
-	pr_debug("%s: change speed %d\n", stir->netdev->name, speed);
 	for (i = 0; i < ARRAY_SIZE(stir_modes); ++i) {
 		if (speed == stir_modes[i].speed)
 			goto found;
 	}
 
-	ERROR("%s: invalid speed %d\n", stir->netdev->name, speed);
+	warn("%s: invalid speed %d", stir->netdev->name, speed);
 	return -EINVAL;
 
  found:
-	pr_debug("%s: speed change from %d to %d\n",
-		 stir->netdev->name, stir->speed, speed);
+	pr_debug("speed change from %d to %d\n", stir->speed, speed);
+
+	/* sometimes needed to get chip out of stuck state */
+	err = usb_reset_device(stir->usbdev);
+	if (err)
+		goto out;
+
+	/* Reset modulator */
+	err = write_reg(stir, REG_CTRL1, CTRL1_SRESET);
+	if (err)
+		goto out;
 
-	/* Make sure any previous Tx is really finished. This happens
-	 * when we answer an incomming request ; the ua:rsp and the
-	 * speed change are bundled together, so we need to wait until
-	 * the packet we just submitted has been sent. Jean II */
-	if (fifo_txwait(stir, 0))
-		return -EIO;
+	/* Undocumented magic to tweak the DPLL */
+	err = write_reg(stir, REG_DPLL, 0x15);
+	if (err)
+		goto out;
 
 	/* Set clock */
 	err = write_reg(stir, REG_PDCLK, stir_modes[i].pdclk);
@@ -564,33 +559,13 @@ static int change_speed(struct stir_cb *
 		goto out;
 
 	err = write_reg(stir, REG_CTRL1, (tx_power & 3) << 1);
-
- out:
-	stir->speed = speed;
-	return err;
-}
-
-static int stir_reset(struct stir_cb *stir)
-{
-	int err;
-
-	/* reset state */
-	stir->rx_buff.in_frame = FALSE;
-	stir->rx_buff.state = OUTSIDE_FRAME;
-	stir->speed = -1;
-
-	/* Undocumented magic to tweak the DPLL */
-	err = write_reg(stir, REG_DPLL, 0x15);
 	if (err)
 		goto out;
 
 	/* Reset sensitivity */
 	err = write_reg(stir, REG_CTRL2, (rx_sensitivity & 7) << 5);
-	if (err)
-		goto out;
-
-	err = change_speed(stir, 9600);
  out:
+	stir->speed = speed;
 	return err;
 }
 
@@ -606,48 +581,62 @@ static int stir_hard_xmit(struct sk_buff
 	/* the IRDA wrapping routines don't deal with non linear skb */
 	SKB_LINEAR_ASSERT(skb);
 
-	if (unlikely(skb->len) == 0) 		/* speed change only */
-		stir->tx_len = 0;
-	else if (isfir(stir->speed))
-		stir->tx_len = wrap_fir_skb(skb, stir->tx_data);
-	else
-		stir->tx_len = wrap_sir_skb(skb, stir->tx_data);
-
-	stir->stats.tx_packets++;
-	stir->stats.tx_bytes += skb->len;
-
-	stir->tx_mtt = irda_get_mtt(skb);
-	stir->tx_newspeed = irda_get_next_speed(skb);
-
-	if (!test_and_set_bit(STIR_STATE_TXREADY, &stir->state))
-		wake_up(&stir->thr_wait);
+	skb = xchg(&stir->tx_pending, skb);
+	wake_up(&stir->thr_wait);
+	
+	/* this should never happen unless stop/wakeup problem */
+	if (unlikely(skb)) {
+		WARN_ON(1);
+		dev_kfree_skb(skb);
+	}
 
-	dev_kfree_skb(skb);
 	return 0;
 }
 
 /*
  * Wait for the transmit FIFO to have space for next data
+ *
+ * If space < 0 then wait till FIFO completely drains.
+ * FYI: can take up to 13 seconds at 2400baud.
  */
-static int fifo_txwait(struct stir_cb *stir, unsigned space)
+static int fifo_txwait(struct stir_cb *stir, int space)
 {
 	int err;
-	unsigned count;
-	__u8 regs[3];
-	unsigned long timeout = jiffies + HZ/10;
+	unsigned long count, status;
 
+	/* Read FIFO status and count */
 	for(;;) {
-		/* Read FIFO status and count */
-		err = read_reg(stir, REG_FIFOCTL, regs, 3);
-		if (unlikely(err != 3)) {
-			WARNING("%s: FIFO register read error: %d\n",
-				stir->netdev->name, err);
+		err = read_reg(stir, REG_FIFOCTL, stir->fifo_status, 
+				   FIFO_REGS_SIZE);
+		if (unlikely(err != FIFO_REGS_SIZE)) {
+			warn("%s: FIFO register read error: %d", 
+			     stir->netdev->name, err);
+
 			return err;
 		}
 
+		status = stir->fifo_status[0];
+		count = (unsigned)(stir->fifo_status[2] & 0x1f) << 8 
+			| stir->fifo_status[1];
+
+		pr_debug("fifo status 0x%lx count %lu\n", status, count);
+
+		/* error when receive/transmit fifo gets confused */
+		if (status & FIFOCTL_RXERR) {
+			stir->stats.rx_fifo_errors++;
+			stir->stats.rx_errors++;
+			break;
+		}
+
+		if (status & FIFOCTL_TXERR) {
+			stir->stats.tx_fifo_errors++;
+			stir->stats.tx_errors++;
+			break;
+		}
+
 		/* is fifo receiving already, or empty */
-		if (!(regs[0] & FIFOCTL_DIR)
-		    || (regs[0] & FIFOCTL_EMPTY))
+		if (!(status & FIFOCTL_DIR)
+		    || (status & FIFOCTL_EMPTY))
 			return 0;
 
 		if (signal_pending(current))
@@ -658,40 +647,37 @@ static int fifo_txwait(struct stir_cb *s
 		    || !netif_device_present(stir->netdev))
 			return -ESHUTDOWN;
 
-		count = (unsigned)(regs[2] & 0x1f) << 8 | regs[1];
-
-		pr_debug("%s: fifo status 0x%x count %u\n",
-			 stir->netdev->name, regs[0], count);
-
 		/* only waiting for some space */
-		if (space && STIR_FIFO_SIZE - 4 > space + count)
+		if (space >= 0 && STIR_FIFO_SIZE - 4 > space + count)
 			return 0;
 
-		if (time_after(jiffies, timeout)) {
-			WARNING("%s: transmit fifo timeout status=0x%x count=%d\n",
-				stir->netdev->name, regs[0], count);
-			++stir->stats.tx_errors;
-			irda_device_set_media_busy(stir->netdev, TRUE);
-			return -ETIMEDOUT;
-		}
-
 		/* estimate transfer time for remaining chars */
 		wait_ms((count * 8000) / stir->speed);
 	}
+			
+	err = write_reg(stir, REG_FIFOCTL, FIFOCTL_CLR);
+	if (err) 
+		return err;
+	err = write_reg(stir, REG_FIFOCTL, 0);
+	if (err)
+		return err;
+
+	return 0;
 }
 
 
 /* Wait for turnaround delay before starting transmit.  */
-static void turnaround_delay(long us, const struct timespec *last)
+static void turnaround_delay(const struct stir_cb *stir, long us)
 {
 	long ticks;
-	struct timespec now = CURRENT_TIME;
+	struct timeval now;
 
 	if (us <= 0)
 		return;
 
-	us -= (now.tv_sec - last->tv_sec) * USEC_PER_SEC;
-	us -= (now.tv_nsec - last->tv_nsec) / NSEC_PER_USEC;
+	do_gettimeofday(&now);
+	us -= (now.tv_sec - stir->rx_time.tv_sec) * USEC_PER_SEC;
+	us -= now.tv_usec - stir->rx_time.tv_usec;
 	if (us < 10)
 		return;
 
@@ -707,77 +693,60 @@ static void turnaround_delay(long us, co
  * Start receiver by submitting a request to the receive pipe.
  * If nothing is available it will return after rx_interval.
  */
-static void receive_start(struct stir_cb *stir)
+static int receive_start(struct stir_cb *stir)
 {
-	int i;
-
-	if (test_and_set_bit(STIR_STATE_RECEIVING, &stir->state))
-		return;
-
-	if (fifo_txwait(stir, 0))
-		return;
-
-	for (i = 0; i < NUM_RX_URBS; i++) {
-		struct urb *urb = stir->rx_urbs[i];
-
-		usb_fill_int_urb(urb, stir->usbdev, stir->rx_intpipe,
-				 stir->rx_data[i], STIR_FIFO_SIZE,
-				 stir_usb_receive, stir, rx_interval);
-
-		if (usb_submit_urb(urb, GFP_KERNEL))
-			urb->status = -EINVAL;
-	}
+	/* reset state */
+	stir->receiving = 1;
 
-	if (i == 0) {
-		/* if nothing got queued, then just retry next time */
-		if (net_ratelimit())
-			WARNING("%s: no receive buffers avaiable\n",
-				stir->netdev->name);
+	stir->rx_buff.in_frame = FALSE;
+	stir->rx_buff.state = OUTSIDE_FRAME;
 
-		clear_bit(STIR_STATE_RECEIVING, &stir->state);
-	}
+	stir->rx_urb->status = 0;
+	return usb_submit_urb(stir->rx_urb, GFP_KERNEL);
 }
 
 /* Stop all pending receive Urb's */
 static void receive_stop(struct stir_cb *stir)
 {
-	int i;
+	stir->receiving = 0;
+	usb_unlink_urb(stir->rx_urb);
 
-	for (i = 0; i < NUM_RX_URBS; i++) {
-		struct urb *urb = stir->rx_urbs[i];
-		usb_unlink_urb(urb);
-	}
+	if (stir->rx_buff.in_frame) 
+		stir->stats.collisions++;
 }
-
-/* Send wrapped data (in tx_data) to device */
-static void stir_send(struct stir_cb *stir)
+/*
+ * Wrap data in socket buffer and send it.
+ */
+static void stir_send(struct stir_cb *stir, struct sk_buff *skb)
 {
-	int rc;
+	unsigned wraplen;
+	int first_frame = 0;
 
-	if (test_and_clear_bit(STIR_STATE_RECEIVING, &stir->state)) {
+	/* if receiving, need to turnaround */
+	if (stir->receiving) {
 		receive_stop(stir);
-
-		turnaround_delay(stir->tx_mtt, &stir->rx_time);
-
-		if (stir->rx_buff.in_frame)
-			++stir->stats.collisions;
+		turnaround_delay(stir, irda_get_mtt(skb));
+		first_frame = 1;
 	}
-	else if (fifo_txwait(stir, stir->tx_len))
-		return; /* shutdown or major errors */
 
+	if (isfir(stir->speed))
+		wraplen = wrap_fir_skb(skb, stir->io_buf);
+	else
+		wraplen = wrap_sir_skb(skb, stir->io_buf);
+		
+	/* check for space available in fifo */
+	if (!first_frame)
+		fifo_txwait(stir, wraplen);
+
+	stir->stats.tx_packets++;
+	stir->stats.tx_bytes += skb->len;
 	stir->netdev->trans_start = jiffies;
+	pr_debug("send %d (%d)\n", skb->len, wraplen);
 
-	pr_debug("%s: send %d\n", stir->netdev->name, stir->tx_len);
-	rc = usb_bulk_msg(stir->usbdev,
-			  stir->tx_bulkpipe,
-			  stir->tx_data, stir->tx_len,
-			  NULL, MSECS_TO_JIFFIES(TRANSMIT_TIMEOUT));
-
-	if (unlikely(rc)) {
-		WARNING("%s: usb bulk message failed %d\n",
-			stir->netdev->name, rc);
+	if (usb_bulk_msg(stir->usbdev, usb_sndbulkpipe(stir->usbdev, 1),
+			 stir->io_buf, wraplen,
+			 NULL, MSECS_TO_JIFFIES(TRANSMIT_TIMEOUT))) 
 		stir->stats.tx_errors++;
-	}
 }
 
 /*
@@ -787,7 +756,7 @@ static int stir_transmit_thread(void *ar
 {
 	struct stir_cb *stir = arg;
 	struct net_device *dev = stir->netdev;
-	DECLARE_WAITQUEUE(wait, current);
+	struct sk_buff *skb;
 
 	daemonize("%s", dev->name);
 	allow_signal(SIGTERM);
@@ -796,44 +765,58 @@ static int stir_transmit_thread(void *ar
 	       && netif_device_present(dev)
 	       && !signal_pending(current))
 	{
-		/* make swsusp happy with our thread */
+		/* if suspending, then power off and wait */
 		if (current->flags & PF_FREEZE) {
-			receive_stop(stir);
+			if (stir->receiving)
+				receive_stop(stir);
+			else
+				fifo_txwait(stir, -1);
 
 			write_reg(stir, REG_CTRL1, CTRL1_TXPWD|CTRL1_RXPWD);
 
 			refrigerator(PF_IOTHREAD);
 
-			stir_reset(stir);
+			if (change_speed(stir, stir->speed))
+				break;
 		}
 
 		/* if something to send? */
-		if (test_and_clear_bit(STIR_STATE_TXREADY, &stir->state)) {
-			unsigned new_speed = stir->tx_newspeed;
-
-			/* Note that we may both send a packet and
-			 * change speed in some cases. Jean II */
-
-			if (stir->tx_len != 0)
-				stir_send(stir);
-
-			if (stir->speed != new_speed)
-				change_speed(stir, new_speed);
-
-			netif_wake_queue(stir->netdev);
+		skb = xchg(&stir->tx_pending, NULL);
+		if (skb) {
+			unsigned new_speed = irda_get_next_speed(skb);
+			netif_wake_queue(dev);
+
+			if (skb->len > 0)
+				stir_send(stir, skb);
+			dev_kfree_skb(skb);
+
+			if (stir->speed != new_speed) {
+				if (fifo_txwait(stir, -1) ||
+				    change_speed(stir, new_speed))
+					break;
+			}
 			continue;
 		}
 
-		if (irda_device_txqueue_empty(dev))
-			receive_start(stir);
+		/* nothing to send? start receiving */
+		if (!stir->receiving 
+		    && irda_device_txqueue_empty(dev)) {
+			/* Wait otherwise chip gets confused. */
+			if (fifo_txwait(stir, -1))
+				break;
+
+			if (unlikely(receive_start(stir))) {
+				if (net_ratelimit())
+					info("%s: receive usb submit failed",
+					     stir->netdev->name);
+				stir->receiving = 0;
+				wait_ms(10);
+				continue;
+			}
+		}
 
-		set_task_state(current, TASK_INTERRUPTIBLE);
-		add_wait_queue(&stir->thr_wait, &wait);
-		if (test_bit(STIR_STATE_TXREADY, &stir->state))
-			__set_task_state(current, TASK_RUNNING);
-		else
-			schedule_timeout(HZ/10);
-		remove_wait_queue(&stir->thr_wait, &wait);
+		/* sleep if nothing to send */
+		wait_event_interruptible(stir->thr_wait, stir->tx_pending);
 	}
 
 	complete_and_exit (&stir->thr_exited, 0);
@@ -841,48 +824,34 @@ static int stir_transmit_thread(void *ar
 
 
 /*
- * Receive wrapped data into rx_data buffer.
- * This chip doesn't block until data is available, we just have
- * to read the FIFO perodically (ugh).
+ * USB bulk receive completion callback.
+ * Wakes up every ms (usb round trip) with wrapped 
+ * data.
  */
-static void stir_usb_receive(struct urb *urb, struct pt_regs *regs)
+static void stir_rcv_irq(struct urb *urb, struct pt_regs *regs)
 {
 	struct stir_cb *stir = urb->context;
 	int err;
 
+	/* in process of stopping, just drop data */
 	if (!netif_running(stir->netdev))
 		return;
 
-	switch (urb->status) {
-	case 0:
-		if(urb->actual_length > 0) {
-			pr_debug("%s: receive %d\n",
-				 stir->netdev->name, urb->actual_length);
-			unwrap_chars(stir, urb->transfer_buffer,
-				     urb->actual_length);
-
-			stir->netdev->last_rx = jiffies;
-			stir->rx_time = CURRENT_TIME;
-		}
-		break;
-
-	case -ECONNRESET:	/* killed but pending */
-	case -ENOENT:		/* killed but not in use */
-	case -ESHUTDOWN:
-		/* These are normal errors when URB is cancelled */
-		stir->rx_buff.in_frame = FALSE;
-		stir->rx_buff.state = OUTSIDE_FRAME;
+	/* unlink, shutdown, unplug, other nasties */
+	if (urb->status != 0) 
 		return;
 
-	default:
-		WARNING("%s: received status %d\n", stir->netdev->name,
-			urb->status);
-		stir->stats.rx_errors++;
-		urb->status = 0;
+	if (urb->actual_length > 0) {
+		pr_debug("receive %d\n", urb->actual_length);
+		unwrap_chars(stir, urb->transfer_buffer,
+			     urb->actual_length);
+		
+		stir->netdev->last_rx = jiffies;
+		do_gettimeofday(&stir->rx_time);
 	}
 
 	/* kernel thread is stopping receiver don't resubmit */
-	if (!test_bit(STIR_STATE_RECEIVING, &stir->state))
+	if (!stir->receiving)
 		return;
 
 	/* resubmit existing urb */
@@ -890,14 +859,13 @@ static void stir_usb_receive(struct urb 
 
 	/* in case of error, the kernel thread will restart us */
 	if (err) {
-		WARNING("%s: usb receive submit error: %d\n",
+		warn("%s: usb receive submit error: %d",
 			stir->netdev->name, err);
-		urb->status = -ENOENT;
+		stir->receiving = 0;
 		wake_up(&stir->thr_wait);
 	}
 }
 
-
 /*
  * Function stir_net_open (dev)
  *
@@ -906,50 +874,50 @@ static void stir_usb_receive(struct urb 
 static int stir_net_open(struct net_device *netdev)
 {
 	struct stir_cb *stir = netdev->priv;
-	int i, err;
-	char	hwname[16];
+	int err;
+	char hwname[16];
 
-	err = stir_reset(stir);
+	err = usb_clear_halt(stir->usbdev, usb_sndbulkpipe(stir->usbdev, 1));
+	if (err)
+		goto err_out1;
+	err = usb_clear_halt(stir->usbdev, usb_rcvbulkpipe(stir->usbdev, 2));
 	if (err)
 		goto err_out1;
 
-	err = -ENOMEM;
-
-	/* Note: Max SIR frame possible is 4273 */
-	stir->tx_data = kmalloc(STIR_FIFO_SIZE, GFP_KERNEL);
-	if (!stir->tx_data) {
-		ERROR("%s(), alloc failed for rxbuf!\n", __FUNCTION__);
+	err = change_speed(stir, 9600);
+	if (err)
 		goto err_out1;
-	}
+
+	err = -ENOMEM;
 
 	/* Initialize for SIR/FIR to copy data directly into skb.  */
+	stir->receiving = 0;
 	stir->rx_buff.truesize = IRDA_SKB_MAX_MTU;
 	stir->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
-	if (!stir->rx_buff.skb) {
-		ERROR("%s(), dev_alloc_skb() failed for rxbuf!\n",
-		      __FUNCTION__);
-		goto err_out2;
-	}
+	if (!stir->rx_buff.skb) 
+		goto err_out1;
+
 	skb_reserve(stir->rx_buff.skb, 1);
 	stir->rx_buff.head = stir->rx_buff.skb->data;
-	stir->rx_time = CURRENT_TIME;
+	do_gettimeofday(&stir->rx_time);
 
-	/* Allocate N receive buffer's and urbs */
-	for (i = 0; i < NUM_RX_URBS; i++) {
-		stir->rx_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
-		if (!stir->rx_urbs[i]){
-			ERROR("%s(), usb_alloc_urb failed\n", __FUNCTION__);
-			goto err_out3;
-		}
+	stir->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!stir->rx_urb) 
+		goto err_out2;
 
-		stir->rx_data[i] = kmalloc(STIR_FIFO_SIZE, GFP_KERNEL);
-		if (!stir->rx_data) {
-			usb_free_urb(stir->rx_urbs[i]);
-			ERROR("%s(), alloc failed for rxbuf!\n", __FUNCTION__);
-			goto err_out3;
-		}
-	}
+	stir->io_buf = kmalloc(STIR_FIFO_SIZE, GFP_KERNEL);
+	if (!stir->io_buf)
+		goto err_out3;
 
+	usb_fill_bulk_urb(stir->rx_urb, stir->usbdev,
+			  usb_rcvbulkpipe(stir->usbdev, 2),
+			  stir->io_buf, STIR_FIFO_SIZE,
+			  stir_rcv_irq, stir);
+
+	stir->fifo_status = kmalloc(FIFO_REGS_SIZE, GFP_KERNEL);
+	if (!stir->fifo_status) 
+		goto err_out4;
+		
 	/*
 	 * Now that everything should be initialized properly,
 	 * Open new IrLAP layer instance to take care of us...
@@ -958,8 +926,8 @@ static int stir_net_open(struct net_devi
 	sprintf(hwname, "usb#%d", stir->usbdev->devnum);
 	stir->irlap = irlap_open(netdev, &stir->qos, hwname);
 	if (!stir->irlap) {
-		ERROR("%s(): irlap_open failed\n", __FUNCTION__);
-		goto err_out3;
+		err("irlap_open failed");
+		goto err_out5;
 	}
 
 	/** Start kernel thread for transmit.  */
@@ -967,25 +935,24 @@ static int stir_net_open(struct net_devi
 				      CLONE_FS|CLONE_FILES);
 	if (stir->thr_pid < 0) {
 		err = stir->thr_pid;
-		WARNING("%s: unable to start kernel thread\n",
-			stir->netdev->name);
-		goto err_out4;
+		err("unable to start kernel thread");
+		goto err_out6;
 	}
 
 	netif_start_queue(netdev);
 
 	return 0;
 
- err_out4:
+ err_out6:
 	irlap_close(stir->irlap);
+ err_out5:
+	kfree(stir->fifo_status);
+ err_out4:
+	kfree(stir->io_buf);
  err_out3:
-	while(--i >= 0) {
-		usb_free_urb(stir->rx_urbs[i]);
-		kfree(stir->rx_data[i]);
-	}
-	kfree_skb(stir->rx_buff.skb);
+	usb_free_urb(stir->rx_urb);
  err_out2:
-	kfree(stir->tx_data);
+	kfree_skb(stir->rx_buff.skb);
  err_out1:
 	return err;
 }
@@ -999,7 +966,6 @@ static int stir_net_open(struct net_devi
 static int stir_net_close(struct net_device *netdev)
 {
 	struct stir_cb *stir = netdev->priv;
-	int i;
 
 	/* Stop transmit processing */
 	netif_stop_queue(netdev);
@@ -1007,15 +973,13 @@ static int stir_net_close(struct net_dev
 	/* Kill transmit thread */
 	kill_proc(stir->thr_pid, SIGTERM, 1);
 	wait_for_completion(&stir->thr_exited);
-	kfree(stir->tx_data);
-
-	clear_bit(STIR_STATE_RECEIVING, &stir->state);
-	receive_stop(stir);
+	kfree(stir->fifo_status);
 
-	for (i = 0; i < NUM_RX_URBS; i++) {
-		usb_free_urb(stir->rx_urbs[i]);
-		kfree(stir->rx_data[i]);
-	}
+	/* Mop up receive urb's */
+	usb_unlink_urb(stir->rx_urb);
+	
+	kfree(stir->io_buf);
+	usb_free_urb(stir->rx_urb);
 	kfree_skb(stir->rx_buff.skb);
 
 	/* Stop and remove instance of IrLAP */
@@ -1057,7 +1021,7 @@ static int stir_net_ioctl(struct net_dev
 
 	case SIOCGRECEIVING:
 		/* Only approximately true */
-		irq->ifr_receiving = test_bit(STIR_STATE_RECEIVING, &stir->state);
+		irq->ifr_receiving = stir->receiving;
 		break;
 
 	default:
@@ -1077,53 +1041,6 @@ static struct net_device_stats *stir_net
 }
 
 /*
- *    Parse the various endpoints and find the one we need.
- *
- * The endpoint are the pipes used to communicate with the USB device.
- * The spec defines 2 endpoints of type bulk transfer, one in, and one out.
- * These are used to pass frames back and forth with the dongle.
- */
-static int stir_setup_usb(struct stir_cb *stir, struct usb_interface *intf)
-{
-	struct usb_device *usbdev = interface_to_usbdev(intf);
-	const struct usb_host_interface *interface
-		= &intf->altsetting[intf->act_altsetting];
-	const struct usb_endpoint_descriptor *ep_in = NULL;
-	const struct usb_endpoint_descriptor *ep_out = NULL;
-	int i;
-
-	if (interface->desc.bNumEndpoints != 2) {
-		WARNING("%s: expected two endpoints\n", __FUNCTION__);
-		return -ENODEV;
-	}
-
-	for(i = 0; i < interface->desc.bNumEndpoints; i++) {
-		const struct usb_endpoint_descriptor *ep
-			= &interface->endpoint[i].desc;
-
-		if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-		    == USB_ENDPOINT_XFER_BULK) {
-			/* We need to find an IN and an OUT */
-			if ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
-				ep_in = ep;
-			else
-				ep_out = ep;
-		} else
-			WARNING("%s: unknown endpoint type 0x%x\n",
-				__FUNCTION__, ep->bmAttributes);
-	}
-
-	if (!ep_in || !ep_out)
-		return -EIO;
-
-	stir->tx_bulkpipe = usb_sndbulkpipe(usbdev,
-			    ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
-	stir->rx_intpipe = usb_rcvintpipe(usbdev,
-			    ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
-	return 0;
-}
-
-/*
  * This routine is called by the USB subsystem for each new device
  * in the system. We need to check if the device is ours, and in
  * this case start handling it.
@@ -1149,9 +1066,9 @@ static int stir_probe(struct usb_interfa
 	stir->netdev = net;
 	stir->usbdev = dev;
 
-	ret = stir_setup_usb(stir, intf);
+	ret = usb_reset_configuration(dev);
 	if (ret != 0) {
-		ERROR("%s(), Bogus endpoints...\n", __FUNCTION__);
+		err("usb reset configuration failed");
 		goto err_out2;
 	}
 
@@ -1180,10 +1097,6 @@ static int stir_probe(struct usb_interfa
 	net->get_stats	     = stir_net_get_stats;
 	net->do_ioctl        = stir_net_ioctl;
 
-	ret = stir_reset(stir);
-	if (ret)
-		goto err_out2;
-
 	ret = register_netdev(net);
 	if (ret != 0)
 		goto err_out2;
@@ -1206,23 +1119,14 @@ err_out1:
 static void stir_disconnect(struct usb_interface *intf)
 {
 	struct stir_cb *stir = usb_get_intfdata(intf);
-	struct net_device *net;
 
-	usb_set_intfdata(intf, NULL);
 	if (!stir)
 		return;
 
-	/* Stop transmitter */
-	net = stir->netdev;
-	netif_device_detach(net);
-
-	/* Remove netdevice */
-	unregister_netdev(net);
-
-	/* No longer attached to USB bus */
-	stir->usbdev = NULL;
+	unregister_netdev(stir->netdev);
+	free_netdev(stir->netdev);
 
-	free_netdev(net);
+	usb_set_intfdata(intf, NULL);
 }
 
 
--- diff/drivers/net/irda/vlsi_ir.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/net/irda/vlsi_ir.c	2004-03-09 11:51:50.000000000 +0000
@@ -173,7 +173,7 @@ static int vlsi_proc_pdev(struct pci_dev
 			PCIDEV_NAME(pdev), (int)pdev->vendor, (int)pdev->device);
 	out += sprintf(out, "pci-power-state: %u\n", (unsigned) pdev->current_state);
 	out += sprintf(out, "resources: irq=%u / io=0x%04x / dma_mask=0x%016Lx\n",
-			pdev->irq, (unsigned)pci_resource_start(pdev, 0), (u64)pdev->dma_mask);
+			pdev->irq, (unsigned)pci_resource_start(pdev, 0), (unsigned long long)pdev->dma_mask);
 	out += sprintf(out, "hw registers: ");
 	for (i = 0; i < 0x20; i++)
 		out += sprintf(out, "%02x", (unsigned)inb((iobase+i)));
@@ -566,7 +566,6 @@ static struct vlsi_ring *vlsi_alloc_ring
 			return NULL;
 		}
 		rd_set_addr_status(rd, busaddr, 0);
-		pci_dma_sync_single(pdev, busaddr, len, dir);
 		/* initially, the dma buffer is owned by the CPU */
 		rd->skb = NULL;
 	}
@@ -660,7 +659,7 @@ static int vlsi_process_rx(struct vlsi_r
 	struct net_device *ndev = (struct net_device *)pci_get_drvdata(r->pdev);
 	vlsi_irda_dev_t *idev = ndev->priv;
 
-	pci_dma_sync_single(r->pdev, rd_get_addr(rd), r->len, r->dir);
+	pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir);
 	/* dma buffer now owned by the CPU */
 	status = rd_get_status(rd);
 	if (status & RD_RX_ERROR) {
@@ -746,7 +745,7 @@ static void vlsi_fill_rx(struct vlsi_rin
 				break;	/* probably not worth logging? */
 		}
 		/* give dma buffer back to busmaster */
-		pci_dma_prep_single(r->pdev, rd_get_addr(rd), r->len, r->dir);
+		pci_dma_sync_single_for_device(r->pdev, rd_get_addr(rd), r->len, r->dir);
 		rd_activate(rd);
 	}
 }
@@ -816,7 +815,7 @@ static void vlsi_unarm_rx(vlsi_irda_dev_
 				ret = -VLSI_RX_DROP;
 			}
 			rd_set_count(rd, 0);
-			pci_dma_sync_single(r->pdev, rd_get_addr(rd), r->len, r->dir);
+			pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir);
 			if (rd->skb) {
 				dev_kfree_skb_any(rd->skb);
 				rd->skb = NULL;
@@ -854,7 +853,7 @@ static int vlsi_process_tx(struct vlsi_r
 	int		len;
 	int		ret;
 
-	pci_dma_sync_single(r->pdev, rd_get_addr(rd), r->len, r->dir);
+	pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir);
 	/* dma buffer now owned by the CPU */
 	status = rd_get_status(rd);
 	if (status & RD_TX_UNDRN)
@@ -1077,8 +1076,8 @@ static int vlsi_hard_start_xmit(struct s
 		}
 	}
 
-	/* tx buffer already owned by CPU due to pci_dma_sync_single() either
-	 * after initial pci_map_single or after subsequent tx-completion
+	/* tx buffer already owned by CPU due to pci_dma_sync_single_for_cpu()
+	 * after subsequent tx-completion
 	 */
 
 	if (idev->mode == IFF_SIR) {
@@ -1120,7 +1119,7 @@ static int vlsi_hard_start_xmit(struct s
 	 * CPU-driven changes visible from the pci bus).
 	 */
 
-	pci_dma_prep_single(r->pdev, rd_get_addr(rd), r->len, r->dir);
+	pci_dma_sync_single_for_device(r->pdev, rd_get_addr(rd), r->len, r->dir);
 
 /*	Switching to TX mode here races with the controller
  *	which may stop TX at any time when fetching an inactive descriptor
@@ -1248,7 +1247,7 @@ static void vlsi_unarm_tx(vlsi_irda_dev_
 		if (rd_is_active(rd)) {
 			rd_set_status(rd, 0);
 			rd_set_count(rd, 0);
-			pci_dma_sync_single(r->pdev, rd_get_addr(rd), r->len, r->dir);
+			pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir);
 			if (rd->skb) {
 				dev_kfree_skb_any(rd->skb);
 				rd->skb = NULL;
--- diff/drivers/net/lasi_82596.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/net/lasi_82596.c	2004-03-09 11:51:50.000000000 +0000
@@ -802,9 +802,10 @@ memory_squeeze:
 				skb->dev = dev;
 				if (!rx_in_place) {
 					/* 16 byte align the data fields */
-					dma_sync_single(lp->dev, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE);
+					dma_sync_single_for_cpu(lp->dev, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE);
 					skb_reserve(skb, 2);
 					memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len);
+					dma_sync_single_for_device(lp->dev, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE);
 				}
 				skb->len = pkt_len;
 				skb->protocol=eth_type_trans(skb,dev);
--- diff/drivers/net/lne390.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/lne390.c	2004-03-09 11:51:50.000000000 +0000
@@ -299,6 +299,9 @@ static int __init lne390_probe1(struct n
 
 	dev->open = &lne390_open;
 	dev->stop = &lne390_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 	return 0;
 cleanup:
--- diff/drivers/net/mac8390.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/mac8390.c	2004-03-09 11:51:50.000000000 +0000
@@ -442,6 +442,9 @@ static int __init mac8390_initdev(struct
 	/* Now fill in our stuff */
 	dev->open = &mac8390_open;
 	dev->stop = &mac8390_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 
 	/* GAR, ei_status is actually a macro even though it looks global */
 	ei_status.name = cardname[type];
--- diff/drivers/net/myri_sbus.c	2003-10-27 09:20:38.000000000 +0000
+++ source/drivers/net/myri_sbus.c	2004-03-09 11:51:50.000000000 +0000
@@ -435,9 +435,9 @@ static void myri_rx(struct myri_eth *mp,
 
 		/* Check for errors. */
 		DRX(("rxd[%d]: %p len[%d] csum[%08x] ", entry, rxd, len, csum));
-		sbus_dma_sync_single(mp->myri_sdev,
-				     sbus_readl(&rxd->myri_scatters[0].addr),
-				     RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
+		sbus_dma_sync_single_for_cpu(mp->myri_sdev,
+					     sbus_readl(&rxd->myri_scatters[0].addr),
+					     RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
 		if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) {
 			DRX(("ERROR["));
 			mp->enet_stats.rx_errors++;
@@ -454,6 +454,10 @@ static void myri_rx(struct myri_eth *mp,
 			drops++;
 			DRX(("DROP "));
 			mp->enet_stats.rx_dropped++;
+			sbus_dma_sync_single_for_device(mp->myri_sdev,
+							sbus_readl(&rxd->myri_scatters[0].addr),
+							RX_ALLOC_SIZE,
+							SBUS_DMA_FROMDEVICE);
 			sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len);
 			sbus_writel(index, &rxd->ctx);
 			sbus_writel(1, &rxd->num_sg);
@@ -508,6 +512,10 @@ static void myri_rx(struct myri_eth *mp,
 
 			/* Reuse original ring buffer. */
 			DRX(("reuse "));
+			sbus_dma_sync_single_for_device(mp->myri_sdev,
+							sbus_readl(&rxd->myri_scatters[0].addr),
+							RX_ALLOC_SIZE,
+							SBUS_DMA_FROMDEVICE);
 			sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len);
 			sbus_writel(index, &rxd->ctx);
 			sbus_writel(1, &rxd->num_sg);
--- diff/drivers/net/natsemi.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/net/natsemi.c	2004-03-09 11:51:50.000000000 +0000
@@ -1789,7 +1789,7 @@ static void netdev_rx(struct net_device 
 				skb->dev = dev;
 				/* 16 byte align the IP header */
 				skb_reserve(skb, 2);
-				pci_dma_sync_single(np->pci_dev,
+				pci_dma_sync_single_for_cpu(np->pci_dev,
 					np->rx_dma[entry],
 					np->rx_skbuff[entry]->len,
 					PCI_DMA_FROMDEVICE);
@@ -1801,6 +1801,10 @@ static void netdev_rx(struct net_device 
 				memcpy(skb_put(skb, pkt_len),
 					np->rx_skbuff[entry]->tail, pkt_len);
 #endif
+				pci_dma_sync_single_for_device(np->pci_dev,
+					np->rx_dma[entry],
+					np->rx_skbuff[entry]->len,
+					PCI_DMA_FROMDEVICE);
 			} else {
 				pci_unmap_single(np->pci_dev, np->rx_dma[entry],
 					np->rx_skbuff[entry]->len,
--- diff/drivers/net/ne.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/net/ne.c	2004-03-09 11:51:50.000000000 +0000
@@ -498,6 +498,9 @@ static int __init ne_probe1(struct net_d
 	ei_status.priv = 0;
 	dev->open = &ne_open;
 	dev->stop = &ne_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 	return 0;
 
--- diff/drivers/net/ne2.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/ne2.c	2004-03-09 11:51:50.000000000 +0000
@@ -509,6 +509,9 @@ static int __init ne2_probe1(struct net_
 	
 	dev->open = &ne_open;
 	dev->stop = &ne_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 	return 0;
 out:
--- diff/drivers/net/ne2k-pci.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/ne2k-pci.c	2004-03-09 11:51:50.000000000 +0000
@@ -359,6 +359,9 @@ static int __devinit ne2k_pci_init_one (
 	dev->open = &ne2k_pci_open;
 	dev->stop = &ne2k_pci_close;
 	dev->ethtool_ops = &ne2k_pci_ethtool_ops;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 
 	i = register_netdev(dev);
--- diff/drivers/net/ne2k_cbus.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/ne2k_cbus.c	2004-03-09 11:51:50.000000000 +0000
@@ -534,6 +534,9 @@ static int __init ne_probe1(struct net_d
 	ei_status.priv = 0;
 	dev->open = &ne_open;
 	dev->stop = &ne_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 	return 0;
 
--- diff/drivers/net/ne3210.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/ne3210.c	2004-03-09 11:51:50.000000000 +0000
@@ -205,6 +205,9 @@ static int __init ne3210_eisa_probe (str
 
 	dev->open = &ne3210_open;
 	dev->stop = &ne3210_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	dev->if_port = ifmap_val[port_index];
 
 	if ((retval = register_netdev (dev)))
--- diff/drivers/net/ns83820.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/ns83820.c	2004-03-09 11:51:50.000000000 +0000
@@ -598,7 +598,7 @@ static inline int rx_refill(struct net_d
 }
 
 static void FASTCALL(rx_refill_atomic(struct net_device *ndev));
-static void rx_refill_atomic(struct net_device *ndev)
+static void fastcall rx_refill_atomic(struct net_device *ndev)
 {
 	rx_refill(ndev, GFP_ATOMIC);
 }
@@ -620,7 +620,7 @@ static inline void clear_rx_desc(struct 
 }
 
 static void FASTCALL(phy_intr(struct net_device *ndev));
-static void phy_intr(struct net_device *ndev)
+static void fastcall phy_intr(struct net_device *ndev)
 {
 	struct ns83820 *dev = PRIV(ndev);
 	static char *speeds[] = { "10", "100", "1000", "1000(?)", "1000F" };
@@ -807,7 +807,7 @@ static void ns83820_cleanup_rx(struct ns
 }
 
 static void FASTCALL(ns83820_rx_kick(struct net_device *ndev));
-static void ns83820_rx_kick(struct net_device *ndev)
+static void fastcall ns83820_rx_kick(struct net_device *ndev)
 {
 	struct ns83820 *dev = PRIV(ndev);
 	/*if (nr_rx_empty(dev) >= NR_RX_DESC/4)*/ {
@@ -829,7 +829,7 @@ static void ns83820_rx_kick(struct net_d
  *	
  */
 static void FASTCALL(rx_irq(struct net_device *ndev));
-static void rx_irq(struct net_device *ndev)
+static void fastcall rx_irq(struct net_device *ndev)
 {
 	struct ns83820 *dev = PRIV(ndev);
 	struct rx_info *info = &dev->rx_info;
--- diff/drivers/net/oaknet.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/oaknet.c	2004-03-09 11:51:50.000000000 +0000
@@ -192,6 +192,9 @@ static int __init oaknet_init(void)
 
 	dev->open = oaknet_open;
 	dev->stop = oaknet_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 
 	NS8390_init(dev, FALSE);
 	ret = register_netdev(dev);
--- diff/drivers/net/pcmcia/3c574_cs.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/pcmcia/3c574_cs.c	2004-03-09 11:51:50.000000000 +0000
@@ -384,6 +384,8 @@ static void tc574_detach(dev_link_t *lin
 #define CS_CHECK(fn, ret) \
   do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
+static char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+
 static void tc574_config(dev_link_t *link)
 {
 	client_handle_t handle = link->handle;
@@ -396,6 +398,7 @@ static void tc574_config(dev_link_t *lin
 	ioaddr_t ioaddr;
 	u16 *phys_addr;
 	char *cardname;
+	union wn3_config config;
 
 	phys_addr = (u16 *)dev->dev_addr;
 
@@ -431,15 +434,7 @@ static void tc574_config(dev_link_t *lin
 	dev->irq = link->irq.AssignedIRQ;
 	dev->base_addr = link->io.BasePort1;
 
-	if (register_netdev(dev) != 0) {
-		printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n");
-		goto failed;
-	}
-
 	ioaddr = dev->base_addr;
-	strcpy(lp->node.dev_name, dev->name);
-	link->dev = &lp->node;
-	link->state &= ~DEV_CONFIG_PENDING;
 
 	/* The 3c574 normally uses an EEPROM for configuration info, including
 	   the hardware address.  The future products may include a modem chip
@@ -467,24 +462,14 @@ static void tc574_config(dev_link_t *lin
 	} else
 		cardname = "3Com 3c574";
 
-	printk(KERN_INFO "%s: %s at io %#3lx, irq %d, hw_addr ",
-		   dev->name, cardname, dev->base_addr, dev->irq);
-
-	for (i = 0; i < 6; i++)
-		printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : ".\n"));
-
 	{
-		u_char mcr, *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
-		union wn3_config config;
+		u_char mcr;
 		outw(2<<11, ioaddr + RunnerRdCtrl);
 		mcr = inb(ioaddr + 2);
 		outw(0<<11, ioaddr + RunnerRdCtrl);
 		printk(KERN_INFO "  ASIC rev %d,", mcr>>3);
 		EL3WINDOW(3);
 		config.i = inl(ioaddr + Wn3_Config);
-		printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n",
-			   8 << config.u.ram_size, ram_split[config.u.ram_split],
-			   config.u.autoselect ? "autoselect " : "");
 		lp->default_media = config.u.xcvr;
 		lp->autoselect = config.u.autoselect;
 	}
@@ -531,6 +516,25 @@ static void tc574_config(dev_link_t *lin
 		}
 	}
 
+	link->state &= ~DEV_CONFIG_PENDING;
+	link->dev = &lp->node;
+
+	if (register_netdev(dev) != 0) {
+		printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n");
+		link->dev = NULL;
+		goto failed;
+	}
+
+	strcpy(lp->node.dev_name, dev->name);
+
+	printk(KERN_INFO "%s: %s at io %#3lx, irq %d, hw_addr ",
+		   dev->name, cardname, dev->base_addr, dev->irq);
+	for (i = 0; i < 6; i++)
+		printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : ".\n"));
+	printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n",
+		   8 << config.u.ram_size, ram_split[config.u.ram_split],
+		   config.u.autoselect ? "autoselect " : "");
+
 	return;
 
 cs_failed:
--- diff/drivers/net/pcmcia/3c589_cs.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/pcmcia/3c589_cs.c	2004-03-09 11:51:50.000000000 +0000
@@ -308,7 +308,7 @@ static void tc589_config(dev_link_t *lin
     tuple_t tuple;
     cisparse_t parse;
     u16 buf[32], *phys_addr;
-    int last_fn, last_ret, i, j, multi = 0;
+    int last_fn, last_ret, i, j, multi = 0, fifo;
     ioaddr_t ioaddr;
     char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
     
@@ -357,11 +357,6 @@ static void tc589_config(dev_link_t *lin
 	
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
-    if (register_netdev(dev) != 0) {
-	printk(KERN_ERR "3c589_cs: register_netdev() failed\n");
-	goto failed;
-    }
-    
     ioaddr = dev->base_addr;
     EL3WINDOW(0);
 
@@ -382,13 +377,10 @@ static void tc589_config(dev_link_t *lin
 	}
     }
 
-    strcpy(lp->node.dev_name, dev->name);
-    link->dev = &lp->node;
-    link->state &= ~DEV_CONFIG_PENDING;
-    
     /* The address and resource configuration register aren't loaded from
        the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */
     outw(0x3f00, ioaddr + 8);
+    fifo = inl(ioaddr);
 
     /* The if_port symbol can be set when the module is loaded */
     if ((if_port >= 0) && (if_port <= 3))
@@ -396,14 +388,24 @@ static void tc589_config(dev_link_t *lin
     else
 	printk(KERN_ERR "3c589_cs: invalid if_port requested\n");
     
+    link->dev = &lp->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+
+    if (register_netdev(dev) != 0) {
+	printk(KERN_ERR "3c589_cs: register_netdev() failed\n");
+	link->dev = NULL;
+	goto failed;
+    }
+
+    strcpy(lp->node.dev_name, dev->name);
+
     printk(KERN_INFO "%s: 3Com 3c%s, io %#3lx, irq %d, hw_addr ",
 	   dev->name, (multi ? "562" : "589"), dev->base_addr,
 	   dev->irq);
     for (i = 0; i < 6; i++)
 	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
-    i = inl(ioaddr);
     printk(KERN_INFO "  %dK FIFO split %s Rx:Tx, %s xcvr\n",
-	   (i & 7) ? 32 : 8, ram_split[(i >> 16) & 3],
+	   (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3],
 	   if_names[dev->if_port]);
     return;
 
--- diff/drivers/net/pcmcia/axnet_cs.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/pcmcia/axnet_cs.c	2004-03-09 11:51:50.000000000 +0000
@@ -430,19 +430,11 @@ static void axnet_config(dev_link_t *lin
     ei_status.block_input = &block_input;
     ei_status.block_output = &block_output;
 
-    strcpy(info->node.dev_name, dev->name);
-
     if (inb(dev->base_addr + AXNET_TEST) != 0)
 	info->flags |= IS_AX88790;
     else
 	info->flags |= IS_AX88190;
 
-    printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, hw_addr ",
-	   dev->name, ((info->flags & IS_AX88790) ? 7 : 1),
-	   dev->base_addr, dev->irq);
-    for (i = 0; i < 6; i++)
-	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
-
     if (info->flags & IS_AX88790)
 	outb(0x10, dev->base_addr + AXNET_GPIO);  /* select Internal PHY */
 
@@ -463,19 +455,27 @@ static void axnet_config(dev_link_t *lin
     }
 
     info->phy_id = (i < 32) ? i : -1;
-    if (i < 32) {
-	DEBUG(0, "  MII transceiver at index %d, status %x.\n", i, j);
-    } else {
-	printk(KERN_NOTICE "  No MII transceivers found!\n");
-    }
+    link->dev = &info->node;
+    link->state &= ~DEV_CONFIG_PENDING;
 
     if (register_netdev(dev) != 0) {
 	printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n");
+	link->dev = NULL;
 	goto failed;
     }
 
-    link->dev = &info->node;
-    link->state &= ~DEV_CONFIG_PENDING;
+    strcpy(info->node.dev_name, dev->name);
+
+    printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, hw_addr ",
+	   dev->name, ((info->flags & IS_AX88790) ? 7 : 1),
+	   dev->base_addr, dev->irq);
+    for (i = 0; i < 6; i++)
+	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+    if (info->phy_id != -1) {
+	DEBUG(0, "  MII transceiver at index %d, status %x.\n", info->phy_id, j);
+    } else {
+	printk(KERN_NOTICE "  No MII transceivers found!\n");
+    }
     return;
 
 cs_failed:
--- diff/drivers/net/pcmcia/com20020_cs.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/pcmcia/com20020_cs.c	2004-03-09 11:51:50.000000000 +0000
@@ -141,7 +141,6 @@ static dev_link_t *dev_list;
 
 typedef struct com20020_dev_t {
     struct net_device       *dev;
-    int dev_configured;
     dev_node_t          node;
 } com20020_dev_t;
 
@@ -277,13 +276,10 @@ static void com20020_detach(dev_link_t *
 	dev = info->dev;
 	if (dev)
 	{
-	    if (info->dev_configured)
+	    if (link->dev)
 	    {
 		DEBUG(1,"unregister...\n");
 
-		if (netif_running(dev))
-		    dev->stop(dev);
-
 		unregister_netdev(dev);
 	    
 		/*
@@ -398,17 +394,18 @@ static void com20020_config(dev_link_t *
     lp->card_name = "PCMCIA COM20020";
     lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
 
+    link->dev = &info->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+
     i = com20020_found(dev, 0);	/* calls register_netdev */
     
     if (i != 0) {
 	DEBUG(1,KERN_NOTICE "com20020_cs: com20020_found() failed\n");
+	link->dev = NULL;
 	goto failed;
     }
 
-    info->dev_configured = 1;
     strcpy(info->node.dev_name, dev->name);
-    link->dev = &info->node;
-    link->state &= ~DEV_CONFIG_PENDING;
 
     DEBUG(1,KERN_INFO "%s: port %#3lx, irq %d\n",
            dev->name, dev->base_addr, dev->irq);
--- diff/drivers/net/pcmcia/fmvj18x_cs.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/pcmcia/fmvj18x_cs.c	2004-03-09 11:51:50.000000000 +0000
@@ -510,10 +510,6 @@ static void fmvj18x_config(dev_link_t *l
     CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
-    if (register_netdev(dev) != 0) {
-	printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n");
-	goto failed;
-    }
 
     if (link->io.BasePort2 != 0)
 	fmvj18x_setup_mfc(link);
@@ -575,7 +571,6 @@ static void fmvj18x_config(dev_link_t *l
 	/* Read MACID from Buggy CIS */
 	if (fmvj18x_get_hwinfo(link, tuple.TupleData) == -1) {
 	    printk(KERN_NOTICE "fmvj18x_cs: unable to read hardware net address.\n");
-	    unregister_netdev(dev);
 	    goto failed;
 	}
 	for (i = 0 ; i < 6; i++) {
@@ -592,10 +587,18 @@ static void fmvj18x_config(dev_link_t *l
 	break;
     }
 
-    strcpy(lp->node.dev_name, dev->name);
+    lp->cardtype = cardtype;
     link->dev = &lp->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+
+    if (register_netdev(dev) != 0) {
+	printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n");
+	link->dev = NULL;
+	goto failed;
+    }
+
+    strcpy(lp->node.dev_name, dev->name);
 
-    lp->cardtype = cardtype;
     /* print current configuration */
     printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, hw_addr ", 
 	   dev->name, card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2", 
@@ -603,7 +606,6 @@ static void fmvj18x_config(dev_link_t *l
     for (i = 0; i < 6; i++)
 	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
 
-    link->state &= ~DEV_CONFIG_PENDING;
     return;
     
 cs_failed:
--- diff/drivers/net/pcmcia/ibmtr_cs.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/pcmcia/ibmtr_cs.c	2004-03-09 11:51:50.000000000 +0000
@@ -317,13 +317,10 @@ static void ibmtr_config(dev_link_t *lin
     /* Try PRIMARY card at 0xA20-0xA23 */
     link->io.BasePort1 = 0xA20;
     i = pcmcia_request_io(link->handle, &link->io);
-    if (i == CS_SUCCESS) {
-	memcpy(info->node.dev_name, "tr0\0", 4);
-    } else {
+    if (i != CS_SUCCESS) {
 	/* Couldn't get 0xA20-0xA23.  Try ALTERNATE at 0xA24-0xA27. */
 	link->io.BasePort1 = 0xA24;
 	CS_CHECK(RequestIO, pcmcia_request_io(link->handle, &link->io));
-	memcpy(info->node.dev_name, "tr1\0", 4);
     }
     dev->base_addr = link->io.BasePort1;
 
@@ -367,15 +364,17 @@ static void ibmtr_config(dev_link_t *lin
         Adapters Technical Reference"  SC30-3585 for this info.  */
     ibmtr_hw_setup(dev, mmiobase);
 
+    link->dev = &info->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+
     i = ibmtr_probe_card(dev);
-    
     if (i != 0) {
 	printk(KERN_NOTICE "ibmtr_cs: register_netdev() failed\n");
+	link->dev = NULL;
 	goto failed;
     }
 
-    link->dev = &info->node;
-    link->state &= ~DEV_CONFIG_PENDING;
+    strcpy(info->node.dev_name, dev->name);
 
     printk(KERN_INFO "%s: port %#3lx, irq %d,",
            dev->name, dev->base_addr, dev->irq);
--- diff/drivers/net/pcmcia/nmclan_cs.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/pcmcia/nmclan_cs.c	2004-03-09 11:51:50.000000000 +0000
@@ -734,11 +734,6 @@ static void nmclan_config(dev_link_t *li
   CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
   dev->irq = link->irq.AssignedIRQ;
   dev->base_addr = link->io.BasePort1;
-  i = register_netdev(dev);
-  if (i != 0) {
-    printk(KERN_NOTICE "nmclan_cs: register_netdev() failed\n");
-    goto failed;
-  }
 
   ioaddr = dev->base_addr;
 
@@ -777,10 +772,18 @@ static void nmclan_config(dev_link_t *li
   else
     printk(KERN_NOTICE "nmclan_cs: invalid if_port requested\n");
 
-  strcpy(lp->node.dev_name, dev->name);
   link->dev = &lp->node;
   link->state &= ~DEV_CONFIG_PENDING;
 
+  i = register_netdev(dev);
+  if (i != 0) {
+    printk(KERN_NOTICE "nmclan_cs: register_netdev() failed\n");
+    link->dev = NULL;
+    goto failed;
+  }
+
+  strcpy(lp->node.dev_name, dev->name);
+
   printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port, hw_addr ",
 	 dev->name, dev->base_addr, dev->irq, if_names[dev->if_port]);
   for (i = 0; i < 6; i++)
--- diff/drivers/net/pcmcia/smc91c92_cs.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/pcmcia/smc91c92_cs.c	2004-03-09 11:51:50.000000000 +0000
@@ -901,6 +901,7 @@ static void smc91c92_config(dev_link_t *
     char *name;
     int i, j, rev;
     ioaddr_t ioaddr;
+    u_long mir;
 
     DEBUG(0, "smc91c92_config(0x%p)\n", link);
 
@@ -952,11 +953,6 @@ static void smc91c92_config(dev_link_t *
     else
 	printk(KERN_NOTICE "smc91c92_cs: invalid if_port requested\n");
 
-    if (register_netdev(dev) != 0) {
-	printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n");
-	goto config_undo;
-    }
-
     switch (smc->manfid) {
     case MANFID_OSITECH:
     case MANFID_PSION:
@@ -977,8 +973,6 @@ static void smc91c92_config(dev_link_t *
 	goto config_undo;
     }
 
-    strcpy(smc->node.dev_name, dev->name);
-    link->dev = &smc->node;
     smc->duplex = 0;
     smc->rx_ovrn = 0;
 
@@ -993,25 +987,16 @@ static void smc91c92_config(dev_link_t *
 	case 8: name = "100-FD"; break;
 	case 9: name = "110"; break;
 	}
-    printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, "
-	   "hw_addr ", dev->name, name, (rev & 0x0f), dev->base_addr,
-	   dev->irq);
-    for (i = 0; i < 6; i++)
-	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
 
     ioaddr = dev->base_addr;
     if (rev > 0) {
-	u_long mir, mcr;
+	u_long mcr;
 	SMC_SELECT_BANK(0);
 	mir = inw(ioaddr + MEMINFO) & 0xff;
 	if (mir == 0xff) mir++;
 	/* Get scale factor for memory size */
 	mcr = ((rev >> 4) > 3) ? inw(ioaddr + MEMCFG) : 0x0200;
 	mir *= 128 * (1<<((mcr >> 9) & 7));
-	if (mir & 0x3ff)
-	    printk(KERN_INFO "  %lu byte", mir);
-	else
-	    printk(KERN_INFO "  %lu kb", mir>>10);
 	SMC_SELECT_BANK(1);
 	smc->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT;
 	smc->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC;
@@ -1019,9 +1004,8 @@ static void smc91c92_config(dev_link_t *
 	    smc->cfg |= CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0;
 	if ((rev >> 4) >= 7)
 	    smc->cfg |= CFG_MII_SELECT;
-	printk(" buffer, %s xcvr\n", (smc->cfg & CFG_MII_SELECT) ?
-	       "MII" : if_names[dev->if_port]);
-    }
+    } else
+	mir = 0;
 
     if (smc->cfg & CFG_MII_SELECT) {
 	SMC_SELECT_BANK(3);
@@ -1031,16 +1015,45 @@ static void smc91c92_config(dev_link_t *
 	    if ((j != 0) && (j != 0xffff)) break;
 	}
 	smc->mii_if.phy_id = (i < 32) ? i : -1;
-	if (i < 32) {
-	    DEBUG(0, "  MII transceiver at index %d, status %x.\n", i, j);
-	} else {
-    	    printk(KERN_NOTICE "  No MII transceivers found!\n");
-	}
 
 	SMC_SELECT_BANK(0);
     }
 
+    link->dev = &smc->node;
     link->state &= ~DEV_CONFIG_PENDING;
+
+    if (register_netdev(dev) != 0) {
+	printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n");
+	link->dev = NULL;
+	goto config_undo;
+    }
+
+    strcpy(smc->node.dev_name, dev->name);
+
+    printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, "
+	   "hw_addr ", dev->name, name, (rev & 0x0f), dev->base_addr,
+	   dev->irq);
+    for (i = 0; i < 6; i++)
+	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+
+    if (rev > 0) {
+	if (mir & 0x3ff)
+	    printk(KERN_INFO "  %lu byte", mir);
+	else
+	    printk(KERN_INFO "  %lu kb", mir>>10);
+	printk(" buffer, %s xcvr\n", (smc->cfg & CFG_MII_SELECT) ?
+	       "MII" : if_names[dev->if_port]);
+    }
+
+    if (smc->cfg & CFG_MII_SELECT) {
+	if (smc->mii_if.phy_id != -1) {
+	    DEBUG(0, "  MII transceiver at index %d, status %x.\n",
+		  smc->mii_if.phy_id, j);
+	} else {
+    	    printk(KERN_NOTICE "  No MII transceivers found!\n");
+	}
+    }
+
     return;
 
 config_undo:
--- diff/drivers/net/pcmcia/xirc2ps_cs.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/pcmcia/xirc2ps_cs.c	2004-03-09 11:51:50.000000000 +0000
@@ -1114,17 +1114,20 @@ xirc2ps_config(dev_link_t * link)
     /* we can now register the device with the net subsystem */
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
+
+    if (local->dingo)
+	do_reset(dev, 1); /* a kludge to make the cem56 work */
+
+    link->dev = &local->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+
     if ((err=register_netdev(dev))) {
 	printk(KNOT_XIRC "register_netdev() failed\n");
+	link->dev = NULL;
 	goto config_error;
     }
 
     strcpy(local->node.dev_name, dev->name);
-    link->dev = &local->node;
-    link->state &= ~DEV_CONFIG_PENDING;
-
-    if (local->dingo)
-	do_reset(dev, 1); /* a kludge to make the cem56 work */
 
     /* give some infos about the hardware */
     printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr",
--- diff/drivers/net/pcnet32.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/net/pcnet32.c	2004-03-09 11:51:50.000000000 +0000
@@ -479,6 +479,14 @@ static struct pcnet32_access pcnet32_dwi
     .reset	= pcnet32_dwio_reset
 };
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void pcnet32_poll_controller(struct net_device *dev)
+{ 
+	disable_irq(dev->irq);
+	pcnet32_interrupt(0, dev, NULL);
+	enable_irq(dev->irq);
+} 
+#endif
 
 
 static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -1106,6 +1114,10 @@ pcnet32_probe1(unsigned long ioaddr, uns
     dev->tx_timeout = pcnet32_tx_timeout;
     dev->watchdog_timeo = (5*HZ);
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+    dev->poll_controller = pcnet32_poll_controller;
+#endif    
+
     /* Fill in the generic fields of the device structure. */
     if (register_netdev(dev))
 	goto err_free_consistent;
@@ -1732,13 +1744,17 @@ pcnet32_rx(struct net_device *dev)
 		if (!rx_in_place) {
 		    skb_reserve(skb,2); /* 16 byte align */
 		    skb_put(skb,pkt_len);	/* Make room */
-		    pci_dma_sync_single(lp->pci_dev,
-		                        lp->rx_dma_addr[entry],
-		                        PKT_BUF_SZ-2,
-		                        PCI_DMA_FROMDEVICE);
+		    pci_dma_sync_single_for_cpu(lp->pci_dev,
+						lp->rx_dma_addr[entry],
+						PKT_BUF_SZ-2,
+						PCI_DMA_FROMDEVICE);
 		    eth_copy_and_sum(skb,
 			    (unsigned char *)(lp->rx_skbuff[entry]->tail),
 			    pkt_len,0);
+		    pci_dma_sync_single_for_device(lp->pci_dev,
+						   lp->rx_dma_addr[entry],
+						   PKT_BUF_SZ-2,
+						   PCI_DMA_FROMDEVICE);
 		}
 		lp->stats.rx_bytes += skb->len;
 		skb->protocol=eth_type_trans(skb,dev);
--- diff/drivers/net/r8169.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/net/r8169.c	2004-03-09 11:51:50.000000000 +0000
@@ -56,9 +56,11 @@ VERSION 1.2	<2002/11/30>
 	        printk( "Assertion failed! %s,%s,%s,line=%d\n",	\
         	#expr,__FILE__,__FUNCTION__,__LINE__);		\
         }
+#define dprintk(fmt, args...)	do { printk(PFX fmt, ## args) } while (0)
 #else
 #define assert(expr) do {} while (0)
-#endif
+#define dprintk(fmt, args...)	do {} while (0)
+#endif /* RTL8169_DEBUG */
 
 /* media options */
 #define MAX_UNITS 8
@@ -89,9 +91,12 @@ static int multicast_filter_limit = 32;
 #define NUM_TX_DESC	64	/* Number of Tx descriptor registers */
 #define NUM_RX_DESC	64	/* Number of Rx descriptor registers */
 #define RX_BUF_SIZE	1536	/* Rx Buffer size */
+#define R8169_TX_RING_BYTES	(NUM_TX_DESC * sizeof(struct TxDesc))
+#define R8169_RX_RING_BYTES	(NUM_RX_DESC * sizeof(struct RxDesc))
 
 #define RTL_MIN_IO_SIZE 0x80
-#define TX_TIMEOUT  (6*HZ)
+#define RTL8169_TX_TIMEOUT	(6*HZ)
+#define RTL8169_PHY_TIMEOUT	(HZ) 
 
 /* write/read MMIO register */
 #define RTL_W8(reg, val8)	writeb ((val8), ioaddr + (reg))
@@ -101,11 +106,35 @@ static int multicast_filter_limit = 32;
 #define RTL_R16(reg)		readw (ioaddr + (reg))
 #define RTL_R32(reg)		((unsigned long) readl (ioaddr + (reg)))
 
-static struct {
+enum mac_version {
+	RTL_GIGA_MAC_VER_B = 0x00,
+	/* RTL_GIGA_MAC_VER_C = 0x03, */
+	RTL_GIGA_MAC_VER_D = 0x01,
+	RTL_GIGA_MAC_VER_E = 0x02
+};
+
+enum phy_version {
+	RTL_GIGA_PHY_VER_C = 0x03, /* PHY Reg 0x03 bit0-3 == 0x0000 */
+	RTL_GIGA_PHY_VER_D = 0x04, /* PHY Reg 0x03 bit0-3 == 0x0000 */
+	RTL_GIGA_PHY_VER_E = 0x05, /* PHY Reg 0x03 bit0-3 == 0x0000 */
+	RTL_GIGA_PHY_VER_F = 0x06, /* PHY Reg 0x03 bit0-3 == 0x0001 */
+	RTL_GIGA_PHY_VER_G = 0x07, /* PHY Reg 0x03 bit0-3 == 0x0002 */
+};
+
+
+#define _R(NAME,MAC,MASK) \
+	{ .name = NAME, .mac_version = MAC, .RxConfigMask = MASK }
+
+const static struct {
 	const char *name;
-} board_info[] __devinitdata = {
-	{
-"RealTek RTL8169 Gigabit Ethernet"},};
+	u8 mac_version;
+	u32 RxConfigMask;	/* Clears the bits supported by this chip */
+} rtl_chip_info[] = {
+	_R("RTL8169",		RTL_GIGA_MAC_VER_B, 0xff7e1880),
+	_R("RTL8169s/8110s",	RTL_GIGA_MAC_VER_D, 0xff7e1880),
+	_R("RTL8169s/8110s",	RTL_GIGA_MAC_VER_E, 0xff7e1880)
+};
+#undef _R
 
 static struct pci_device_id rtl8169_pci_tbl[] = {
 	{0x10ec, 0x8169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
@@ -114,6 +143,8 @@ static struct pci_device_id rtl8169_pci_
 
 MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl);
 
+static int rx_copybreak = 200;
+
 enum RTL8169_registers {
 	MAC0 = 0,		/* Ethernet hardware address. */
 	MAR0 = 8,		/* Multicast filter. */
@@ -242,14 +273,6 @@ enum RTL8169_register_content {
 	TBILinkOK = 0x02000000,
 };
 
-const static struct {
-	const char *name;
-	u8 version;		/* depend on RTL8169 docs */
-	u32 RxConfigMask;	/* should clear the bits supported by this chip */
-} rtl_chip_info[] = {
-	{
-"RTL-8169", 0x00, 0xff7e1880,},};
-
 enum _DescStatusBit {
 	OWNbit = 0x80000000,
 	EORbit = 0x40000000,
@@ -257,6 +280,8 @@ enum _DescStatusBit {
 	LSbit = 0x10000000,
 };
 
+#define RsvdMask	0x3fffc000
+
 struct TxDesc {
 	u32 status;
 	u32 vlan_tag;
@@ -277,28 +302,33 @@ struct rtl8169_private {
 	struct net_device_stats stats;	/* statistics of net device */
 	spinlock_t lock;	/* spin lock flag */
 	int chipset;
-	unsigned long cur_rx;	/* Index into the Rx descriptor buffer of next Rx pkt. */
-	unsigned long cur_tx;	/* Index into the Tx descriptor buffer of next Rx pkt. */
-	unsigned long dirty_tx;
-	unsigned char *TxDescArrays;	/* Index of Tx Descriptor buffer */
-	unsigned char *RxDescArrays;	/* Index of Rx Descriptor buffer */
+	int mac_version;
+	int phy_version;
+	u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
+	u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
+	u32 dirty_rx;
+	u32 dirty_tx;
 	struct TxDesc *TxDescArray;	/* Index of 256-alignment Tx Descriptor buffer */
 	struct RxDesc *RxDescArray;	/* Index of 256-alignment Rx Descriptor buffer */
-	unsigned char *RxBufferRings;	/* Index of Rx Buffer  */
-	unsigned char *RxBufferRing[NUM_RX_DESC];	/* Index of Rx Buffer array */
+	dma_addr_t TxPhyAddr;
+	dma_addr_t RxPhyAddr;
+	struct sk_buff *Rx_skbuff[NUM_RX_DESC];	/* Rx data buffers */
 	struct sk_buff *Tx_skbuff[NUM_TX_DESC];	/* Index of Transmit data buffer */
+	struct timer_list timer;
+	unsigned long phy_link_down_cnt;
 };
 
 MODULE_AUTHOR("Realtek");
 MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");
 MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(rx_copybreak, "i");
 MODULE_LICENSE("GPL");
 
 static int rtl8169_open(struct net_device *dev);
 static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance,
 			      struct pt_regs *regs);
-static void rtl8169_init_ring(struct net_device *dev);
+static int rtl8169_init_ring(struct net_device *dev);
 static void rtl8169_hw_start(struct net_device *dev);
 static int rtl8169_close(struct net_device *dev);
 static void rtl8169_set_rx_mode(struct net_device *dev);
@@ -306,11 +336,15 @@ static void rtl8169_tx_timeout(struct ne
 static struct net_device_stats *rtl8169_get_stats(struct net_device *netdev);
 
 static const u16 rtl8169_intr_mask =
-    SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK |
-    RxErr | RxOK;
+    RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK;
 static const unsigned int rtl8169_rx_config =
     (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
 
+#define PHY_Cap_10_Half_Or_Less PHY_Cap_10_Half
+#define PHY_Cap_10_Full_Or_Less PHY_Cap_10_Full | PHY_Cap_10_Half_Or_Less
+#define PHY_Cap_100_Half_Or_Less PHY_Cap_100_Half | PHY_Cap_10_Full_Or_Less
+#define PHY_Cap_100_Full_Or_Less PHY_Cap_100_Full | PHY_Cap_100_Half_Or_Less
+
 void
 mdio_write(void *ioaddr, int RegAddr, int value)
 {
@@ -342,13 +376,258 @@ mdio_read(void *ioaddr, int RegAddr)
 		if (RTL_R32(PHYAR) & 0x80000000) {
 			value = (int) (RTL_R32(PHYAR) & 0xFFFF);
 			break;
-		} else {
-			udelay(100);
 		}
+		udelay(100);
 	}
 	return value;
 }
 
+static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg, int bitnum,
+				       int bitval)
+{
+	int val;
+
+	val = mdio_read(ioaddr, reg);
+	val = (bitval == 1) ?
+		val | (bitval << bitnum) :  val & ~(0x0001 << bitnum);
+	mdio_write(ioaddr, reg, val & 0xffff); 
+}
+
+static void rtl8169_get_mac_version(struct rtl8169_private *tp, void *ioaddr)
+{
+	const struct {
+		u32 mask;
+		int mac_version;
+	} mac_info[] = {
+		{ 0x1 << 26,	RTL_GIGA_MAC_VER_E },
+		{ 0x1 << 23,	RTL_GIGA_MAC_VER_D }, 
+		{ 0x00000000,	RTL_GIGA_MAC_VER_B } /* Catch-all */
+	}, *p = mac_info;
+	u32 reg;
+
+	reg = RTL_R32(TxConfig) & 0x7c800000;
+	while ((reg & p->mask) != p->mask)
+		p++;
+	tp->mac_version = p->mac_version;
+}
+
+static void rtl8169_print_mac_version(struct rtl8169_private *tp)
+{
+	struct {
+		int version;
+		char *msg;
+	} mac_print[] = {
+		{ RTL_GIGA_MAC_VER_E, "RTL_GIGA_MAC_VER_E" },
+		{ RTL_GIGA_MAC_VER_D, "RTL_GIGA_MAC_VER_D" },
+		{ RTL_GIGA_MAC_VER_B, "RTL_GIGA_MAC_VER_B" },
+		{ 0, NULL }
+	}, *p;
+
+	for (p = mac_print; p->msg; p++) {
+		if (tp->mac_version == p->version) {
+			dprintk("mac_version == %s (%04d)\n", p->msg,
+				  p->version);
+			return;
+		}
+	}
+	dprintk("mac_version == Unknown\n");
+}
+
+static void rtl8169_get_phy_version(struct rtl8169_private *tp, void *ioaddr)
+{
+	const struct {
+		u16 mask;
+		u16 set;
+		int phy_version;
+	} phy_info[] = {
+		{ 0x000f, 0x0002, RTL_GIGA_PHY_VER_G },
+		{ 0x000f, 0x0001, RTL_GIGA_PHY_VER_F },
+		{ 0x000f, 0x0000, RTL_GIGA_PHY_VER_E },
+		{ 0x0000, 0x0000, RTL_GIGA_PHY_VER_D } /* Catch-all */
+	}, *p = phy_info;
+	u16 reg;
+
+	reg = mdio_read(ioaddr, 3) & 0xffff;
+	while ((reg & p->mask) != p->set)
+		p++;
+	tp->phy_version = p->phy_version;
+}
+
+static void rtl8169_print_phy_version(struct rtl8169_private *tp)
+{
+	struct {
+		int version;
+		char *msg;
+		u32 reg;
+	} phy_print[] = {
+		{ RTL_GIGA_PHY_VER_G, "RTL_GIGA_PHY_VER_G", 0x0002 },
+		{ RTL_GIGA_PHY_VER_F, "RTL_GIGA_PHY_VER_F", 0x0001 },
+		{ RTL_GIGA_PHY_VER_E, "RTL_GIGA_PHY_VER_E", 0x0000 },
+		{ RTL_GIGA_PHY_VER_D, "RTL_GIGA_PHY_VER_D", 0x0000 },
+		{ 0, NULL, 0x0000 }
+	}, *p;
+
+	for (p = phy_print; p->msg; p++) {
+		if (tp->phy_version == p->version) {
+			dprintk("phy_version == %s (%04x)\n", p->msg, p->reg);
+			return;
+		}
+	}
+	dprintk("phy_version == Unknown\n");
+}
+
+static void rtl8169_hw_phy_config(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	struct {
+		u16 regs[5]; /* Beware of bit-sign propagation */
+	} phy_magic[5] = { {
+		{ 0x0000,	//w 4 15 12 0
+		  0x00a1,	//w 3 15 0 00a1
+		  0x0008,	//w 2 15 0 0008
+		  0x1020,	//w 1 15 0 1020
+		  0x1000 } },{	//w 0 15 0 1000
+		{ 0x7000,	//w 4 15 12 7
+		  0xff41,	//w 3 15 0 ff41
+		  0xde60,	//w 2 15 0 de60
+		  0x0140,	//w 1 15 0 0140
+		  0x0077 } },{	//w 0 15 0 0077
+		{ 0xa000,	//w 4 15 12 a
+		  0xdf01,	//w 3 15 0 df01
+		  0xdf20,	//w 2 15 0 df20
+		  0xff95,	//w 1 15 0 ff95
+		  0xfa00 } },{	//w 0 15 0 fa00
+		{ 0xb000,	//w 4 15 12 b
+		  0xff41,	//w 3 15 0 ff41
+		  0xde20,	//w 2 15 0 de20
+		  0x0140,	//w 1 15 0 0140
+		  0x00bb } },{	//w 0 15 0 00bb
+		{ 0xf000,	//w 4 15 12 f
+		  0xdf01,	//w 3 15 0 df01
+		  0xdf20,	//w 2 15 0 df20
+		  0xff95,	//w 1 15 0 ff95
+		  0xbf00 }	//w 0 15 0 bf00
+		}
+	}, *p = phy_magic;
+	int i;
+
+	rtl8169_print_mac_version(tp);
+	rtl8169_print_phy_version(tp);
+
+	if (tp->mac_version <= RTL_GIGA_MAC_VER_B)
+		return;
+	if (tp->phy_version >= RTL_GIGA_PHY_VER_F) 
+		return;
+
+	dprintk("MAC version != 0 && PHY version == 0 or 1\n");
+	dprintk("Do final_reg2.cfg\n");
+
+	/* Shazam ! */
+
+	// phy config for RTL8169s mac_version C chip
+	mdio_write(ioaddr, 31, 0x0001);			//w 31 2 0 1
+	mdio_write(ioaddr, 21, 0x1000);			//w 21 15 0 1000
+	mdio_write(ioaddr, 24, 0x65c7);			//w 24 15 0 65c7
+	rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0);	//w 4 11 11 0
+
+	for (i = 0; i < ARRAY_SIZE(phy_magic); i++, p++) {
+		int val, pos = 4;
+
+		val = (mdio_read(ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff);
+		mdio_write(ioaddr, pos, val);
+		while (--pos >= 0)
+			mdio_write(ioaddr, pos, p->regs[4 - pos] & 0xffff);
+		rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1
+		rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0
+	}
+	mdio_write(ioaddr, 31, 0x0000); //w 31 2 0 0
+}
+
+static void rtl8169_hw_phy_reset(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	int i, val;
+
+	printk(KERN_WARNING PFX "%s: Reset RTL8169s PHY\n", dev->name);
+
+	val = (mdio_read(ioaddr, 0) | 0x8000) & 0xffff;
+	mdio_write(ioaddr, 0, val);
+
+	for (i = 50; i >= 0; i--) {
+		if (!(mdio_read(ioaddr, 0) & 0x8000))
+			break;
+		udelay(100); /* Gross */
+	}
+
+	if (i < 0) {
+		printk(KERN_WARNING PFX "%s: no PHY Reset ack. Giving up.\n",
+		       dev->name);
+	}
+}
+
+static void rtl8169_phy_timer(unsigned long __opaque)
+{
+	struct net_device *dev = (struct net_device *)__opaque;
+	struct rtl8169_private *tp = dev->priv;
+	struct timer_list *timer = &tp->timer;
+	void *ioaddr = tp->mmio_addr;
+
+	assert(tp->mac_version > RTL_GIGA_MAC_VER_B);
+	assert(tp->phy_version < RTL_GIGA_PHY_VER_G);
+
+	if (RTL_R8(PHYstatus) & LinkStatus)
+		tp->phy_link_down_cnt = 0;
+	else {
+		tp->phy_link_down_cnt++;
+		if (tp->phy_link_down_cnt >= 12) {
+			int reg;
+
+			// If link on 1000, perform phy reset.
+			reg = mdio_read(ioaddr, PHY_1000_CTRL_REG);
+			if (reg & PHY_Cap_1000_Full) 
+				rtl8169_hw_phy_reset(dev);
+
+			tp->phy_link_down_cnt = 0;
+		}
+	}
+
+	mod_timer(timer, RTL8169_PHY_TIMEOUT);
+}
+
+static inline void rtl8169_delete_timer(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	struct timer_list *timer = &tp->timer;
+
+	if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) ||
+	    (tp->phy_version >= RTL_GIGA_PHY_VER_G))
+		return;
+
+	del_timer_sync(timer);
+
+	tp->phy_link_down_cnt = 0;
+}
+
+static inline void rtl8169_request_timer(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	struct timer_list *timer = &tp->timer;
+
+	if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) ||
+	    (tp->phy_version >= RTL_GIGA_PHY_VER_G))
+		return;
+
+	tp->phy_link_down_cnt = 0;
+
+	init_timer(timer);
+	timer->expires = jiffies + RTL8169_PHY_TIMEOUT;
+	timer->data = (unsigned long)(dev);
+	timer->function = rtl8169_phy_timer;
+	add_timer(timer);
+}
+
 static int __devinit
 rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
 		   void **ioaddr_out)
@@ -356,9 +635,9 @@ rtl8169_init_board(struct pci_dev *pdev,
 	void *ioaddr = NULL;
 	struct net_device *dev;
 	struct rtl8169_private *tp;
-	int rc, i;
 	unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
-	u32 tmp;
+	int rc, i, acpi_idle_state = 0, pm_cap;
+
 
 	assert(pdev != NULL);
 	assert(ioaddr_out != NULL);
@@ -379,8 +658,22 @@ rtl8169_init_board(struct pci_dev *pdev,
 
 	// enable device (incl. PCI PM wakeup and hotplug setup)
 	rc = pci_enable_device(pdev);
-	if (rc)
+	if (rc) {
+		printk(KERN_ERR PFX "%s: unable to enable device\n", pdev->slot_name);
 		goto err_out;
+	}
+
+	/* save power state before pci_enable_device overwrites it */
+	pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+	if (pm_cap) {
+		u16 pwr_command;
+
+		pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command);
+		acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
+	} else {
+		printk(KERN_ERR PFX "Cannot find PowerManagement capability, aborting.\n");
+		goto err_out_free_res;
+	}
 
 	mmio_start = pci_resource_start(pdev, 1);
 	mmio_end = pci_resource_end(pdev, 1);
@@ -402,8 +695,10 @@ rtl8169_init_board(struct pci_dev *pdev,
 	}
 
 	rc = pci_request_regions(pdev, dev->name);
-	if (rc)
+	if (rc) {
+		printk(KERN_ERR PFX "%s: Could not request regions.\n", pdev->slot_name);
 		goto err_out_disable;
+	}
 
 	// enable PCI bus-mastering
 	pci_set_master(pdev);
@@ -420,30 +715,32 @@ rtl8169_init_board(struct pci_dev *pdev,
 	RTL_W8(ChipCmd, CmdReset);
 
 	// Check that the chip has finished the reset.
-	for (i = 1000; i > 0; i--)
+	for (i = 1000; i > 0; i--) {
 		if ((RTL_R8(ChipCmd) & CmdReset) == 0)
 			break;
-		else
-			udelay(10);
+		udelay(10);
+	}
 
-	// identify chip attached to board
-	tmp = RTL_R32(TxConfig);
-	tmp = ((tmp & 0x7c000000) + ((tmp & 0x00800000) << 2)) >> 24;
-
-	for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--)
-		if (tmp == rtl_chip_info[i].version) {
-			tp->chipset = i;
-			goto match;
-		}
-	//if unknown chip, assume array element #0, original RTL-8169 in this case
-	printk(KERN_DEBUG PFX
-	       "PCI device %s: unknown chip version, assuming RTL-8169\n",
-	       pci_name(pdev));
-	printk(KERN_DEBUG PFX "PCI device %s: TxConfig = 0x%lx\n",
-	       pci_name(pdev), (unsigned long) RTL_R32(TxConfig));
-	tp->chipset = 0;
+	// Identify chip attached to board
+	rtl8169_get_mac_version(tp, ioaddr);
+	rtl8169_get_phy_version(tp, ioaddr);
+
+	rtl8169_print_mac_version(tp);
+	rtl8169_print_phy_version(tp);
+
+	for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) {
+		if (tp->mac_version == rtl_chip_info[i].mac_version)
+			break;
+	}
+	if (i < 0) {
+		/* Unknown chip: assume array element #0, original RTL-8169 */
+		printk(KERN_DEBUG PFX
+		       "PCI device %s: unknown chip version, assuming %s\n",
+		       pci_name(pdev), rtl_chip_info[0].name);
+		i++;
+	}
+	tp->chipset = i;
 
-match:
 	*ioaddr_out = ioaddr;
 	*dev_out = dev;
 	return 0;
@@ -499,7 +796,7 @@ rtl8169_init_one(struct pci_dev *pdev, c
 	dev->stop = rtl8169_close;
 	dev->tx_timeout = rtl8169_tx_timeout;
 	dev->set_multicast_list = rtl8169_set_rx_mode;
-	dev->watchdog_timeo = TX_TIMEOUT;
+	dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
 	dev->irq = pdev->irq;
 	dev->base_addr = (unsigned long) ioaddr;
 //      dev->do_ioctl           = mii_ioctl;
@@ -528,12 +825,29 @@ rtl8169_init_one(struct pci_dev *pdev, c
 	       "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
 	       "IRQ %d\n",
 	       dev->name,
-	       board_info[ent->driver_data].name,
+	       rtl_chip_info[ent->driver_data].name,
 	       dev->base_addr,
 	       dev->dev_addr[0], dev->dev_addr[1],
 	       dev->dev_addr[2], dev->dev_addr[3],
 	       dev->dev_addr[4], dev->dev_addr[5], dev->irq);
 
+	rtl8169_hw_phy_config(dev);
+
+	dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
+	RTL_W8(0x82, 0x01);
+
+	if (tp->mac_version < RTL_GIGA_MAC_VER_E) {
+		dprintk("Set PCI Latency=0x40\n");
+		pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40);
+	}
+
+	if (tp->mac_version == RTL_GIGA_MAC_VER_D) {
+		dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
+		RTL_W8(0x82, 0x01);
+		dprintk("Set PHY Reg 0x0bh = 0x00h\n");
+		mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
+	}
+
 	// if TBI is not endbled
 	if (!(RTL_R8(PHYstatus) & TBI_Enable)) {
 		int val = mdio_read(ioaddr, PHY_AUTO_NEGO_REG);
@@ -546,23 +860,23 @@ rtl8169_init_one(struct pci_dev *pdev, c
 			Cap10_100 = 0, Cap1000 = 0;
 			switch (option) {
 			case _10_Half:
-				Cap10_100 = PHY_Cap_10_Half;
+				Cap10_100 = PHY_Cap_10_Half_Or_Less;
 				Cap1000 = PHY_Cap_Null;
 				break;
 			case _10_Full:
-				Cap10_100 = PHY_Cap_10_Full;
+				Cap10_100 = PHY_Cap_10_Full_Or_Less;
 				Cap1000 = PHY_Cap_Null;
 				break;
 			case _100_Half:
-				Cap10_100 = PHY_Cap_100_Half;
+				Cap10_100 = PHY_Cap_100_Half_Or_Less;
 				Cap1000 = PHY_Cap_Null;
 				break;
 			case _100_Full:
-				Cap10_100 = PHY_Cap_100_Full;
+				Cap10_100 = PHY_Cap_100_Full_Or_Less;
 				Cap1000 = PHY_Cap_Null;
 				break;
 			case _1000_Full:
-				Cap10_100 = PHY_Cap_Null;
+				Cap10_100 = PHY_Cap_100_Full_Or_Less;
 				Cap1000 = PHY_Cap_1000_Full;
 				break;
 			default:
@@ -576,9 +890,7 @@ rtl8169_init_one(struct pci_dev *pdev, c
 
 			// enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged
 			mdio_write(ioaddr, PHY_AUTO_NEGO_REG,
-				   PHY_Cap_10_Half | PHY_Cap_10_Full |
-				   PHY_Cap_100_Half | PHY_Cap_100_Full | (val &
-									  0x1F));
+				   PHY_Cap_100_Full_Or_Less | (val & 0x1f));
 
 			// enable 1000 Full Mode
 			mdio_write(ioaddr, PHY_1000_CTRL_REG,
@@ -647,56 +959,96 @@ rtl8169_remove_one(struct pci_dev *pdev)
 	pci_set_drvdata(pdev, NULL);
 }
 
+#ifdef CONFIG_PM
+
+static int rtl8169_suspend(struct pci_dev *pdev, u32 state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct rtl8169_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	unsigned long flags;
+
+	if (!netif_running(dev))
+		return 0;
+	
+	netif_device_detach(dev);
+	netif_stop_queue(dev);
+	spin_lock_irqsave(&tp->lock, flags);
+
+	/* Disable interrupts, stop Rx and Tx */
+	RTL_W16(IntrMask, 0);
+	RTL_W8(ChipCmd, 0);
+		
+	/* Update the error counts. */
+	tp->stats.rx_missed_errors += RTL_R32(RxMissed);
+	RTL_W32(RxMissed, 0);
+	spin_unlock_irqrestore(&tp->lock, flags);
+	
+	return 0;
+}
+
+static int rtl8169_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+
+	if (!netif_running(dev))
+	    return 0;
+
+	netif_device_attach(dev);
+	rtl8169_hw_start(dev);
+
+	return 0;
+}
+                                                                                
+#endif /* CONFIG_PM */
+
 static int
 rtl8169_open(struct net_device *dev)
 {
 	struct rtl8169_private *tp = dev->priv;
+	struct pci_dev *pdev = tp->pci_dev;
 	int retval;
-	u8 diff;
-	u32 TxPhyAddr, RxPhyAddr;
 
 	retval =
 	    request_irq(dev->irq, rtl8169_interrupt, SA_SHIRQ, dev->name, dev);
-	if (retval) {
-		return retval;
-	}
+	if (retval < 0)
+		goto out;
 
-	tp->TxDescArrays =
-	    kmalloc(NUM_TX_DESC * sizeof (struct TxDesc) + 256, GFP_KERNEL);
-	// Tx Desscriptor needs 256 bytes alignment;
-	TxPhyAddr = virt_to_bus(tp->TxDescArrays);
-	diff = 256 - (TxPhyAddr - ((TxPhyAddr >> 8) << 8));
-	TxPhyAddr += diff;
-	tp->TxDescArray = (struct TxDesc *) (tp->TxDescArrays + diff);
-
-	tp->RxDescArrays =
-	    kmalloc(NUM_RX_DESC * sizeof (struct RxDesc) + 256, GFP_KERNEL);
-	// Rx Desscriptor needs 256 bytes alignment;
-	RxPhyAddr = virt_to_bus(tp->RxDescArrays);
-	diff = 256 - (RxPhyAddr - ((RxPhyAddr >> 8) << 8));
-	RxPhyAddr += diff;
-	tp->RxDescArray = (struct RxDesc *) (tp->RxDescArrays + diff);
+	retval = -ENOMEM;
 
-	if (tp->TxDescArrays == NULL || tp->RxDescArrays == NULL) {
-		printk(KERN_INFO
-		       "Allocate RxDescArray or TxDescArray failed\n");
-		free_irq(dev->irq, dev);
-		if (tp->TxDescArrays)
-			kfree(tp->TxDescArrays);
-		if (tp->RxDescArrays)
-			kfree(tp->RxDescArrays);
-		return -ENOMEM;
-	}
-	tp->RxBufferRings = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL);
-	if (tp->RxBufferRings == NULL) {
-		printk(KERN_INFO "Allocate RxBufferRing failed\n");
-	}
+	/*
+	 * Rx and Tx desscriptors needs 256 bytes alignment.
+	 * pci_alloc_consistent provides more.
+	 */
+	tp->TxDescArray = pci_alloc_consistent(pdev, R8169_TX_RING_BYTES,
+					       &tp->TxPhyAddr);
+	if (!tp->TxDescArray)
+		goto err_free_irq;
+
+	tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES,
+					       &tp->RxPhyAddr);
+	if (!tp->RxDescArray)
+		goto err_free_tx;
+
+	retval = rtl8169_init_ring(dev);
+	if (retval < 0)
+		goto err_free_rx;
 
-	rtl8169_init_ring(dev);
 	rtl8169_hw_start(dev);
 
-	return 0;
-
+	rtl8169_request_timer(dev);
+out:
+	return retval;
+
+err_free_rx:
+	pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray,
+			    tp->RxPhyAddr);
+err_free_tx:
+	pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray,
+			    tp->TxPhyAddr);
+err_free_irq:
+	free_irq(dev->irq, dev);
+	goto out;
 }
 
 static void
@@ -733,11 +1085,17 @@ rtl8169_hw_start(struct net_device *dev)
 	RTL_W32(TxConfig,
 		(TX_DMA_BURST << TxDMAShift) | (InterFrameGap <<
 						TxInterFrameGapShift));
+	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd));
+
+	if (tp->mac_version == RTL_GIGA_MAC_VER_D) {
+		dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14 MUST be 1\n");
+		RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | (1 << 14) | (1 << 3));
+	}
 
 	tp->cur_rx = 0;
 
-	RTL_W32(TxDescStartAddr, virt_to_bus(tp->TxDescArray));
-	RTL_W32(RxDescStartAddr, virt_to_bus(tp->RxDescArray));
+	RTL_W32(TxDescStartAddr, tp->TxPhyAddr);
+	RTL_W32(RxDescStartAddr, tp->RxPhyAddr);
 	RTL_W8(Cfg9346, Cfg9346_Lock);
 	udelay(10);
 
@@ -755,31 +1113,131 @@ rtl8169_hw_start(struct net_device *dev)
 
 }
 
-static void
-rtl8169_init_ring(struct net_device *dev)
+static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc)
+{
+	desc->buf_addr = 0xdeadbeef;
+	desc->status &= ~cpu_to_le32(OWNbit | RsvdMask);
+}
+
+static void rtl8169_free_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
+				struct RxDesc *desc)
+{
+	pci_unmap_single(pdev, le32_to_cpu(desc->buf_addr), RX_BUF_SIZE,
+			 PCI_DMA_FROMDEVICE);
+	dev_kfree_skb(*sk_buff);
+	*sk_buff = NULL;
+	rtl8169_make_unusable_by_asic(desc);
+}
+
+static inline void rtl8169_return_to_asic(struct RxDesc *desc)
+{
+	desc->status |= cpu_to_le32(OWNbit + RX_BUF_SIZE);
+}
+
+static inline void rtl8169_give_to_asic(struct RxDesc *desc, dma_addr_t mapping)
+{
+	desc->buf_addr = cpu_to_le32(mapping);
+	desc->status |= cpu_to_le32(OWNbit + RX_BUF_SIZE);
+}
+
+static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct net_device *dev,
+				struct sk_buff **sk_buff, struct RxDesc *desc)
+{
+	struct sk_buff *skb;
+	dma_addr_t mapping;
+	int ret = 0;
+
+	skb = dev_alloc_skb(RX_BUF_SIZE);
+	if (!skb)
+		goto err_out;
+
+	skb->dev = dev;
+	skb_reserve(skb, 2);
+	*sk_buff = skb;
+
+	mapping = pci_map_single(pdev, skb->tail, RX_BUF_SIZE,
+				 PCI_DMA_FROMDEVICE);
+
+	rtl8169_give_to_asic(desc, mapping);
+
+out:
+	return ret;
+
+err_out:
+	ret = -ENOMEM;
+	rtl8169_make_unusable_by_asic(desc);
+	goto out;
+}
+
+static void rtl8169_rx_clear(struct rtl8169_private *tp)
 {
-	struct rtl8169_private *tp = dev->priv;
 	int i;
 
-	tp->cur_rx = 0;
-	tp->cur_tx = 0;
-	tp->dirty_tx = 0;
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		if (tp->Rx_skbuff[i]) {
+			rtl8169_free_rx_skb(tp->pci_dev, tp->Rx_skbuff + i,
+					    tp->RxDescArray + i);
+		}
+	}
+}
+
+static u32 rtl8169_rx_fill(struct rtl8169_private *tp, struct net_device *dev,
+			   u32 start, u32 end)
+{
+	u32 cur;
+	
+	for (cur = start; end - cur > 0; cur++) {
+		int ret, i = cur % NUM_RX_DESC;
+
+		if (tp->Rx_skbuff[i])
+			continue;
+			
+		ret = rtl8169_alloc_rx_skb(tp->pci_dev, dev, tp->Rx_skbuff + i,
+					   tp->RxDescArray + i);
+		if (ret < 0)
+			break;
+	}
+	return cur - start;
+}
+
+static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc)
+{
+	desc->status |= cpu_to_le32(EORbit);
+}
+
+static int rtl8169_init_ring(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+
+	tp->cur_rx = tp->dirty_rx = 0;
+	tp->cur_tx = tp->dirty_tx = 0;
 	memset(tp->TxDescArray, 0x0, NUM_TX_DESC * sizeof (struct TxDesc));
 	memset(tp->RxDescArray, 0x0, NUM_RX_DESC * sizeof (struct RxDesc));
 
-	for (i = 0; i < NUM_TX_DESC; i++) {
-		tp->Tx_skbuff[i] = NULL;
-	}
-	for (i = 0; i < NUM_RX_DESC; i++) {
-		if (i == (NUM_RX_DESC - 1))
-			tp->RxDescArray[i].status =
-			    (OWNbit | EORbit) + RX_BUF_SIZE;
-		else
-			tp->RxDescArray[i].status = OWNbit + RX_BUF_SIZE;
+	memset(tp->Tx_skbuff, 0x0, NUM_TX_DESC * sizeof(struct sk_buff *));
+	memset(tp->Rx_skbuff, 0x0, NUM_RX_DESC * sizeof(struct sk_buff *));
 
-		tp->RxBufferRing[i] = &(tp->RxBufferRings[i * RX_BUF_SIZE]);
-		tp->RxDescArray[i].buf_addr = virt_to_bus(tp->RxBufferRing[i]);
-	}
+	if (rtl8169_rx_fill(tp, dev, 0, NUM_RX_DESC) != NUM_RX_DESC)
+		goto err_out;
+
+	rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1);
+
+	return 0;
+
+err_out:
+	rtl8169_rx_clear(tp);
+	return -ENOMEM;
+}
+
+static void rtl8169_unmap_tx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
+				 struct TxDesc *desc)
+{
+	u32 len = sk_buff[0]->len;
+
+	pci_unmap_single(pdev, le32_to_cpu(desc->buf_addr),
+			 len < ETH_ZLEN ? ETH_ZLEN : len, PCI_DMA_TODEVICE);
+	desc->buf_addr = 0x00;
+	*sk_buff = NULL;
 }
 
 static void
@@ -789,9 +1247,12 @@ rtl8169_tx_clear(struct rtl8169_private 
 
 	tp->cur_tx = 0;
 	for (i = 0; i < NUM_TX_DESC; i++) {
-		if (tp->Tx_skbuff[i] != NULL) {
-			dev_kfree_skb(tp->Tx_skbuff[i]);
-			tp->Tx_skbuff[i] = NULL;
+		struct sk_buff *skb = tp->Tx_skbuff[i];
+
+		if (skb) {
+			rtl8169_unmap_tx_skb(tp->pci_dev, tp->Tx_skbuff + i,
+					     tp->TxDescArray + i);
+			dev_kfree_skb(skb);
 			tp->stats.tx_dropped++;
 		}
 	}
@@ -829,48 +1290,58 @@ rtl8169_start_xmit(struct sk_buff *skb, 
 	struct rtl8169_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 	int entry = tp->cur_tx % NUM_TX_DESC;
+	u32 len = skb->len;
 
-	if (skb->len < ETH_ZLEN) {
+	if (unlikely(skb->len < ETH_ZLEN)) {
 		skb = skb_padto(skb, ETH_ZLEN);
-		if (skb == NULL)
-			return 0;
+		if (!skb)
+			goto err_update_stats;
+		len = ETH_ZLEN;
 	}
 	
 	spin_lock_irq(&tp->lock);
 
-	if ((tp->TxDescArray[entry].status & OWNbit) == 0) {
+	if (!(le32_to_cpu(tp->TxDescArray[entry].status) & OWNbit)) {
+		dma_addr_t mapping;
+
+		mapping = pci_map_single(tp->pci_dev, skb->data, len,
+					 PCI_DMA_TODEVICE);
+
 		tp->Tx_skbuff[entry] = skb;
-		tp->TxDescArray[entry].buf_addr = virt_to_bus(skb->data);
-		if (entry != (NUM_TX_DESC - 1))
-			tp->TxDescArray[entry].status =
-			    (OWNbit | FSbit | LSbit) | ((skb->len > ETH_ZLEN) ?
-							skb->len : ETH_ZLEN);
-		else
-			tp->TxDescArray[entry].status =
-			    (OWNbit | EORbit | FSbit | LSbit) |
-			    ((skb->len > ETH_ZLEN) ? skb->len : ETH_ZLEN);
+		tp->TxDescArray[entry].buf_addr = cpu_to_le32(mapping);
 
+		tp->TxDescArray[entry].status = cpu_to_le32(OWNbit | FSbit |
+			LSbit | len | (EORbit * !((entry + 1) % NUM_TX_DESC)));
+			
 		RTL_W8(TxPoll, 0x40);	//set polling bit
 
 		dev->trans_start = jiffies;
 
 		tp->cur_tx++;
-	}
+	} else
+		goto err_drop;
 
-	spin_unlock_irq(&tp->lock);
 
 	if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) {
 		netif_stop_queue(dev);
 	}
+out:
+	spin_unlock_irq(&tp->lock);
 
 	return 0;
+
+err_drop:
+	dev_kfree_skb(skb);
+err_update_stats:
+	tp->stats.tx_dropped++;
+	goto out;
 }
 
 static void
 rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
 		     void *ioaddr)
 {
-	unsigned long dirty_tx, tx_left = 0;
+	unsigned long dirty_tx, tx_left;
 
 	assert(dev != NULL);
 	assert(tp != NULL);
@@ -882,12 +1353,15 @@ rtl8169_tx_interrupt(struct net_device *
 	while (tx_left > 0) {
 		int entry = dirty_tx % NUM_TX_DESC;
 
-		if ((tp->TxDescArray[entry].status & OWNbit) == 0) {
+		if (!(le32_to_cpu(tp->TxDescArray[entry].status) & OWNbit)) {
 			struct sk_buff *skb = tp->Tx_skbuff[entry];
 
+			/* FIXME: is it really accurate for TxErr ? */
 			tp->stats.tx_bytes += skb->len >= ETH_ZLEN ?
 					      skb->len : ETH_ZLEN;
 			tp->stats.tx_packets++;
+			rtl8169_unmap_tx_skb(tp->pci_dev, tp->Tx_skbuff + entry,
+					     tp->TxDescArray + entry);
 			dev_kfree_skb_irq(skb);
 			tp->Tx_skbuff[entry] = NULL;
 			dirty_tx++;
@@ -902,70 +1376,102 @@ rtl8169_tx_interrupt(struct net_device *
 	}
 }
 
+static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
+				      struct RxDesc *desc,
+				      struct net_device *dev)
+{
+	int ret = -1;
+
+	if (pkt_size < rx_copybreak) {
+		struct sk_buff *skb;
+
+		skb = dev_alloc_skb(pkt_size + 2);
+		if (skb) {
+			skb->dev = dev;
+			skb_reserve(skb, 2);
+			eth_copy_and_sum(skb, sk_buff[0]->tail, pkt_size, 0);
+			*sk_buff = skb;
+			rtl8169_return_to_asic(desc);
+			ret = 0;
+		}
+	}
+	return ret;
+}
+
 static void
 rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
 		     void *ioaddr)
 {
-	int cur_rx;
-	struct sk_buff *skb;
-	int pkt_size = 0;
+	unsigned long cur_rx, rx_left;
+	int delta;
 
 	assert(dev != NULL);
 	assert(tp != NULL);
 	assert(ioaddr != NULL);
 
 	cur_rx = tp->cur_rx;
+	rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
 
-	while ((tp->RxDescArray[cur_rx].status & OWNbit) == 0) {
+	while (rx_left > 0) {
+		int entry = cur_rx % NUM_RX_DESC;
+		u32 status = le32_to_cpu(tp->RxDescArray[entry].status);
 
-		if (tp->RxDescArray[cur_rx].status & RxRES) {
+		if (status & OWNbit)
+			break;
+		if (status & RxRES) {
 			printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name);
 			tp->stats.rx_errors++;
-			if (tp->RxDescArray[cur_rx].status & (RxRWT | RxRUNT))
+			if (status & (RxRWT | RxRUNT))
 				tp->stats.rx_length_errors++;
-			if (tp->RxDescArray[cur_rx].status & RxCRC)
+			if (status & RxCRC)
 				tp->stats.rx_crc_errors++;
 		} else {
-			pkt_size =
-			    (int) (tp->RxDescArray[cur_rx].
-				   status & 0x00001FFF) - 4;
-			skb = dev_alloc_skb(pkt_size + 2);
-			if (skb != NULL) {
-				skb->dev = dev;
-				skb_reserve(skb, 2);	// 16 byte align the IP fields. //
-				eth_copy_and_sum(skb, tp->RxBufferRing[cur_rx],
-						 pkt_size, 0);
-				skb_put(skb, pkt_size);
-				skb->protocol = eth_type_trans(skb, dev);
-				netif_rx(skb);
-
-				if (cur_rx == (NUM_RX_DESC - 1))
-					tp->RxDescArray[cur_rx].status =
-					    (OWNbit | EORbit) + RX_BUF_SIZE;
-				else
-					tp->RxDescArray[cur_rx].status =
-					    OWNbit + RX_BUF_SIZE;
-
-				tp->RxDescArray[cur_rx].buf_addr =
-				    virt_to_bus(tp->RxBufferRing[cur_rx]);
-				dev->last_rx = jiffies;
-				tp->stats.rx_bytes += pkt_size;
-				tp->stats.rx_packets++;
-			} else {
-				printk(KERN_WARNING
-				       "%s: Memory squeeze, deferring packet.\n",
-				       dev->name);
-				/* We should check that some rx space is free.
-				   If not, free one and mark stats->rx_dropped++. */
-				tp->stats.rx_dropped++;
+			struct RxDesc *desc = tp->RxDescArray + entry;
+			struct sk_buff *skb = tp->Rx_skbuff[entry];
+			int pkt_size = (status & 0x00001FFF) - 4;
+
+			pci_dma_sync_single(tp->pci_dev,
+					    le32_to_cpu(desc->buf_addr),
+					    RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+
+			if (rtl8169_try_rx_copy(&skb, pkt_size, desc, dev)) {
+				pci_unmap_single(tp->pci_dev,
+						 le32_to_cpu(desc->buf_addr),
+						 RX_BUF_SIZE,
+						 PCI_DMA_FROMDEVICE);
+				tp->Rx_skbuff[entry] = NULL;
 			}
-		}
-
-		cur_rx = (cur_rx + 1) % NUM_RX_DESC;
 
+			skb_put(skb, pkt_size);
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_rx(skb);
+
+			dev->last_rx = jiffies;
+			tp->stats.rx_bytes += pkt_size;
+			tp->stats.rx_packets++;
+		}
+		
+		cur_rx++; 
+		rx_left--;
 	}
 
 	tp->cur_rx = cur_rx;
+
+	delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx);
+	if (delta > 0)
+		tp->dirty_rx += delta;
+	else if (delta < 0)
+		printk(KERN_INFO "%s: no Rx buffer allocated\n", dev->name);
+
+	/*
+	 * FIXME: until there is periodic timer to try and refill the ring,
+	 * a temporary shortage may definitely kill the Rx process.
+	 * - disable the asic to try and avoid an overflow and kick it again
+	 *   after refill ?
+	 * - how do others driver handle this condition (Uh oh...).
+	 */
+	if (tp->dirty_rx + NUM_RX_DESC == tp->cur_rx)
+		printk(KERN_EMERG "%s: Rx buffers exhausted\n", dev->name);
 }
 
 /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */
@@ -994,9 +1500,7 @@ rtl8169_interrupt(int irq, void *dev_ins
 		RTL_W16(IntrStatus,
 			(status & RxFIFOOver) ? (status | RxOverflow) : status);
 
-		if ((status &
-		     (SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
-		      | TxErr | TxOK | RxErr | RxOK)) == 0)
+		if (!(status & rtl8169_intr_mask))
 			break;
 
 		// Rx interrupt 
@@ -1026,11 +1530,13 @@ static int
 rtl8169_close(struct net_device *dev)
 {
 	struct rtl8169_private *tp = dev->priv;
+	struct pci_dev *pdev = tp->pci_dev;
 	void *ioaddr = tp->mmio_addr;
-	int i;
 
 	netif_stop_queue(dev);
 
+	rtl8169_delete_timer(dev);
+
 	spin_lock_irq(&tp->lock);
 
 	/* Stop the chip's Tx and Rx DMA processes. */
@@ -1049,16 +1555,15 @@ rtl8169_close(struct net_device *dev)
 	free_irq(dev->irq, dev);
 
 	rtl8169_tx_clear(tp);
-	kfree(tp->TxDescArrays);
-	kfree(tp->RxDescArrays);
-	tp->TxDescArrays = NULL;
-	tp->RxDescArrays = NULL;
+
+	rtl8169_rx_clear(tp);
+
+	pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray,
+			    tp->RxPhyAddr);
+	pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray,
+			    tp->TxPhyAddr);
 	tp->TxDescArray = NULL;
 	tp->RxDescArray = NULL;
-	kfree(tp->RxBufferRings);
-	for (i = 0; i < NUM_RX_DESC; i++) {
-		tp->RxBufferRing[i] = NULL;
-	}
 
 	return 0;
 }
@@ -1112,11 +1617,26 @@ rtl8169_set_rx_mode(struct net_device *d
 	spin_unlock_irqrestore(&tp->lock, flags);
 }
 
+/**
+ *  rtl8169_get_stats - Get rtl8169 read/write statistics
+ *  @dev: The Ethernet Device to get statistics for
+ *
+ *  Get TX/RX statistics for rtl8169
+ */
 struct net_device_stats *
 rtl8169_get_stats(struct net_device *dev)
 {
 	struct rtl8169_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	unsigned long flags;
 
+	if (netif_running(dev)) {
+		spin_lock_irqsave(&tp->lock, flags);
+		tp->stats.rx_missed_errors += RTL_R32(RxMissed);
+		RTL_W32(RxMissed, 0);
+		spin_unlock_irqrestore(&tp->lock, flags);
+	}
+		
 	return &tp->stats;
 }
 
@@ -1125,8 +1645,10 @@ static struct pci_driver rtl8169_pci_dri
 	.id_table	= rtl8169_pci_tbl,
 	.probe		= rtl8169_init_one,
 	.remove		= __devexit_p(rtl8169_remove_one),
-	.suspend	= NULL,
-	.resume		= NULL,
+#ifdef CONFIG_PM
+	.suspend	= rtl8169_suspend,
+	.resume		= rtl8169_resume,
+#endif
 };
 
 static int __init
--- diff/drivers/net/rrunner.c	2003-09-30 15:46:15.000000000 +0100
+++ source/drivers/net/rrunner.c	2004-03-09 11:51:50.000000000 +0000
@@ -983,18 +983,26 @@ static void rx_int(struct net_device *de
 
 			rx_skb = rrpriv->rx_skbuff[index];
 
-	        	pci_dma_sync_single(rrpriv->pci_dev, desc->addr.addrlo,
-				pkt_len, PCI_DMA_FROMDEVICE);
-
 			if (pkt_len < PKT_COPY_THRESHOLD) {
 				skb = alloc_skb(pkt_len, GFP_ATOMIC);
 				if (skb == NULL){
 					printk(KERN_WARNING "%s: Unable to allocate skb (%i bytes), deferring packet\n", dev->name, pkt_len);
 					rrpriv->stats.rx_dropped++;
 					goto defer;
-				}else
+				} else {
+					pci_dma_sync_single_for_cpu(rrpriv->pci_dev,
+								    desc->addr.addrlo,
+								    pkt_len,
+								    PCI_DMA_FROMDEVICE);
+
 					memcpy(skb_put(skb, pkt_len),
 					       rx_skb->data, pkt_len);
+
+					pci_dma_sync_single_for_device(rrpriv->pci_dev,
+								       desc->addr.addrlo,
+								       pkt_len,
+								       PCI_DMA_FROMDEVICE);
+				}
 			}else{
 				struct sk_buff *newskb;
 
--- diff/drivers/net/sis190.c	2004-03-04 11:41:47.000000000 +0000
+++ source/drivers/net/sis190.c	2004-03-09 11:51:50.000000000 +0000
@@ -1016,14 +1016,20 @@ SiS190_rx_interrupt(struct net_device *d
 			int pkt_size;
 
 			pkt_size = (int) (desc->PSize & 0x0000FFFF) - 4;
-			pci_dma_sync_single(tp->pci_dev, desc->buf_addr,
-				RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
 			skb = dev_alloc_skb(pkt_size + 2);
 			if (skb != NULL) {
 				skb->dev = dev;
 				skb_reserve(skb, 2);	// 16 byte align the IP fields. //
+				pci_dma_sync_single_for_cpu(tp->pci_dev,
+							    desc->buf_addr,
+							    RX_BUF_SIZE,
+							    PCI_DMA_FROMDEVICE);
 				eth_copy_and_sum(skb, tp->RxBufferRing[cur_rx],
 						 pkt_size, 0);
+				pci_dma_sync_single_for_device(tp->pci_dev,
+							    desc->buf_addr,
+							    RX_BUF_SIZE,
+							    PCI_DMA_FROMDEVICE);
 				skb_put(skb, pkt_size);
 				skb->protocol = eth_type_trans(skb, dev);
 				netif_rx(skb);
--- diff/drivers/net/sis900.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/net/sis900.c	2004-03-09 11:51:50.000000000 +0000
@@ -1650,9 +1650,6 @@ static int sis900_rx(struct net_device *
 				break;
 			}
 
-			pci_dma_sync_single(sis_priv->pci_dev, 
-				sis_priv->rx_ring[entry].bufptr, RX_BUF_SIZE, 
-				PCI_DMA_FROMDEVICE);
 			pci_unmap_single(sis_priv->pci_dev, 
 				sis_priv->rx_ring[entry].bufptr, RX_BUF_SIZE, 
 				PCI_DMA_FROMDEVICE);
--- diff/drivers/net/sk98lin/skge.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/net/sk98lin/skge.c	2004-03-09 11:51:50.000000000 +0000
@@ -2533,12 +2533,6 @@ rx_start:	
 				"Control: %x\nRxStat: %x\n",
 				Control, FrameStat));
 
-			PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
-			PhysAddr |= (SK_U64) pRxd->VDataLow;
-			pci_dma_sync_single(pAC->PciDev,
-						(dma_addr_t) PhysAddr,
-						FrameLength,
-						PCI_DMA_FROMDEVICE);
 			ReQueueRxBuffer(pAC, pRxPort, pMsg,
 				pRxd->VDataHigh, pRxd->VDataLow);
 
@@ -2559,12 +2553,16 @@ rx_start:	
 			PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
 			PhysAddr |= (SK_U64) pRxd->VDataLow;
 
-			pci_dma_sync_single(pAC->PciDev,
-						(dma_addr_t) PhysAddr,
-						FrameLength,
-						PCI_DMA_FROMDEVICE);
+			pci_dma_sync_single_for_cpu(pAC->PciDev,
+						    (dma_addr_t) PhysAddr,
+						    FrameLength,
+						    PCI_DMA_FROMDEVICE);
 			eth_copy_and_sum(pNewMsg, pMsg->data,
 				FrameLength, 0);
+			pci_dma_sync_single_for_device(pAC->PciDev,
+						       (dma_addr_t) PhysAddr,
+						       FrameLength,
+						       PCI_DMA_FROMDEVICE);
 			ReQueueRxBuffer(pAC, pRxPort, pMsg,
 				pRxd->VDataHigh, pRxd->VDataLow);
 
--- diff/drivers/net/smc-mca.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/smc-mca.c	2004-03-09 11:51:50.000000000 +0000
@@ -324,6 +324,9 @@ int __init ultramca_probe(struct device 
 
 	dev->open = &ultramca_open;
 	dev->stop = &ultramca_close_card;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 
 	NS8390_init(dev, 0);
 
--- diff/drivers/net/smc-ultra.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/smc-ultra.c	2004-03-09 11:51:50.000000000 +0000
@@ -121,6 +121,14 @@ MODULE_DEVICE_TABLE(isapnp, ultra_device
 #define ULTRA_IO_EXTENT 32
 #define EN0_ERWCNT		0x08	/* Early receive warning count. */
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void ultra_poll(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	ei_interrupt(dev->irq, dev, NULL);
+	enable_irq(dev->irq);
+}
+#endif
 /*	Probe for the Ultra.  This looks like a 8013 with the station
 	address PROM at I/O ports <base>+8 to <base>+13, with a checksum
 	following.
@@ -134,6 +142,9 @@ static int __init do_ultra_probe(struct 
 
 	SET_MODULE_OWNER(dev);
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = &ultra_poll;
+#endif
 	if (base_addr > 0x1ff)		/* Check a single specified location. */
 		return ultra_probe1(dev, base_addr);
 	else if (base_addr != 0)	/* Don't probe at all. */
@@ -301,6 +312,9 @@ static int __init ultra_probe1(struct ne
 	ei_status.reset_8390 = &ultra_reset_8390;
 	dev->open = &ultra_open;
 	dev->stop = &ultra_close_card;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 
 	return 0;
--- diff/drivers/net/smc-ultra32.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/smc-ultra32.c	2004-03-09 11:51:50.000000000 +0000
@@ -268,6 +268,9 @@ static int __init ultra32_probe1(struct 
 	ei_status.reset_8390 = &ultra32_reset_8390;
 	dev->open = &ultra32_open;
 	dev->stop = &ultra32_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 
 	return 0;
--- diff/drivers/net/starfire.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/net/starfire.c	2004-03-09 11:51:50.000000000 +0000
@@ -1637,10 +1637,13 @@ static int __netdev_rx(struct net_device
 		    && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 			skb->dev = dev;
 			skb_reserve(skb, 2);	/* 16 byte align the IP header */
-			pci_dma_sync_single(np->pci_dev,
-					    np->rx_info[entry].mapping,
-					    pkt_len, PCI_DMA_FROMDEVICE);
+			pci_dma_sync_single_for_cpu(np->pci_dev,
+						    np->rx_info[entry].mapping,
+						    pkt_len, PCI_DMA_FROMDEVICE);
 			eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0);
+			pci_dma_sync_single_for_device(np->pci_dev,
+						       np->rx_info[entry].mapping,
+						       pkt_len, PCI_DMA_FROMDEVICE);
 			skb_put(skb, pkt_len);
 		} else {
 			pci_unmap_single(np->pci_dev, np->rx_info[entry].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
--- diff/drivers/net/stnic.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/stnic.c	2004-03-09 11:51:50.000000000 +0000
@@ -124,6 +124,9 @@ static int __init stnic_probe(void)
   dev->irq = IRQ_STNIC;
   dev->open = &stnic_open;
   dev->stop = &stnic_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+  dev->poll_controller = ei_poll;
+#endif
 
   /* Snarf the interrupt now.  There's no point in waiting since we cannot
      share and the board will usually be enabled. */
--- diff/drivers/net/sunbmac.c	2003-10-27 09:20:38.000000000 +0000
+++ source/drivers/net/sunbmac.c	2004-03-09 11:51:50.000000000 +0000
@@ -849,9 +849,13 @@ static void bigmac_rx(struct bigmac *bp)
 			copy_skb->dev = bp->dev;
 			skb_reserve(copy_skb, 2);
 			skb_put(copy_skb, len);
-			sbus_dma_sync_single(bp->bigmac_sdev,
-					     this->rx_addr, len, SBUS_DMA_FROMDEVICE);
+			sbus_dma_sync_single_for_cpu(bp->bigmac_sdev,
+						     this->rx_addr, len,
+						     SBUS_DMA_FROMDEVICE);
 			eth_copy_and_sum(copy_skb, (unsigned char *)skb->data, len, 0);
+			sbus_dma_sync_single_for_device(bp->bigmac_sdev,
+							this->rx_addr, len,
+							SBUS_DMA_FROMDEVICE);
 
 			/* Reuse original ring buffer. */
 			this->rx_flags =
--- diff/drivers/net/sundance.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/net/sundance.c	2004-03-09 11:51:50.000000000 +0000
@@ -1331,9 +1331,6 @@ static void rx_poll(unsigned long data)
 		if (netif_msg_rx_status(np))
 			printk(KERN_DEBUG "  netdev_rx() status was %8.8x.\n",
 				   frame_status);
-		pci_dma_sync_single(np->pci_dev, desc->frag[0].addr,
-			np->rx_buf_sz, PCI_DMA_FROMDEVICE);
-
 		if (frame_status & 0x001f4000) {
 			/* There was a error. */
 			if (netif_msg_rx_err(np))
@@ -1363,7 +1360,16 @@ static void rx_poll(unsigned long data)
 				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
+				pci_dma_sync_single_for_cpu(np->pci_dev,
+							    desc->frag[0].addr,
+							    np->rx_buf_sz,
+							    PCI_DMA_FROMDEVICE);
+
 				eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
+				pci_dma_sync_single_for_device(np->pci_dev,
+							       desc->frag[0].addr,
+							       np->rx_buf_sz,
+							       PCI_DMA_FROMDEVICE);
 				skb_put(skb, pkt_len);
 			} else {
 				pci_unmap_single(np->pci_dev,
--- diff/drivers/net/sungem.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/net/sungem.c	2004-03-09 11:51:50.000000000 +0000
@@ -763,8 +763,9 @@ static void gem_rx(struct gem *gp)
 			copy_skb->dev = gp->dev;
 			skb_reserve(copy_skb, 2);
 			skb_put(copy_skb, len);
-			pci_dma_sync_single(gp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
+			pci_dma_sync_single_for_cpu(gp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
 			memcpy(copy_skb->data, skb->data, len);
+			pci_dma_sync_single_for_device(gp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
 
 			/* We'll reuse the original ring buffer. */
 			skb = copy_skb;
--- diff/drivers/net/sunhme.c	2003-10-27 09:20:38.000000000 +0000
+++ source/drivers/net/sunhme.c	2004-03-09 11:51:50.000000000 +0000
@@ -273,8 +273,10 @@ static u32 pci_hme_read_desc32(u32 *p)
 	((__hp)->dma_map((__hp)->happy_dev, (__ptr), (__size), (__dir)))
 #define hme_dma_unmap(__hp, __addr, __size, __dir) \
 	((__hp)->dma_unmap((__hp)->happy_dev, (__addr), (__size), (__dir)))
-#define hme_dma_sync(__hp, __addr, __size, __dir) \
-	((__hp)->dma_sync((__hp)->happy_dev, (__addr), (__size), (__dir)))
+#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \
+	((__hp)->dma_sync_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir)))
+#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \
+	((__hp)->dma_sync_for_device((__hp)->happy_dev, (__addr), (__size), (__dir)))
 #else
 #ifdef CONFIG_SBUS
 /* SBUS only compilation */
@@ -297,8 +299,10 @@ do {	(__txd)->tx_addr = (__addr); \
 	sbus_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))
 #define hme_dma_unmap(__hp, __addr, __size, __dir) \
 	sbus_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir))
-#define hme_dma_sync(__hp, __addr, __size, __dir) \
-	sbus_dma_sync_single((__hp)->happy_dev, (__addr), (__size), (__dir))
+#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \
+	sbus_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir))
+#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \
+	sbus_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir))
 #else
 /* PCI only compilation */
 #define hme_write32(__hp, __reg, __val) \
@@ -320,8 +324,10 @@ do {	(__txd)->tx_addr = cpu_to_le32(__ad
 	pci_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))
 #define hme_dma_unmap(__hp, __addr, __size, __dir) \
 	pci_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir))
-#define hme_dma_sync(__hp, __addr, __size, __dir) \
-	pci_dma_sync_single((__hp)->happy_dev, (__addr), (__size), (__dir))
+#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \
+	pci_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir))
+#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \
+	pci_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir))
 #endif
 #endif
 
@@ -2069,8 +2075,9 @@ static void happy_meal_rx(struct happy_m
 			copy_skb->dev = dev;
 			skb_reserve(copy_skb, 2);
 			skb_put(copy_skb, len);
-			hme_dma_sync(hp, dma_addr, len, DMA_FROMDEVICE);
+			hme_dma_sync_for_cpu(hp, dma_addr, len, DMA_FROMDEVICE);
 			memcpy(copy_skb->data, skb->data, len);
+			hme_dma_sync_for_device(hp, dma_addr, len, DMA_FROMDEVICE);
 
 			/* Reuse original ring buffer. */
 			hme_write_rxd(hp, this,
@@ -2838,7 +2845,10 @@ static int __init happy_meal_sbus_init(s
 	hp->write_rxd = sbus_hme_write_rxd;
 	hp->dma_map = (u32 (*)(void *, void *, long, int))sbus_map_single;
 	hp->dma_unmap = (void (*)(void *, u32, long, int))sbus_unmap_single;
-	hp->dma_sync = (void (*)(void *, u32, long, int))sbus_dma_sync_single;
+	hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int))
+		sbus_dma_sync_single_for_cpu;
+	hp->dma_sync_for_device = (void (*)(void *, u32, long, int))
+		sbus_dma_sync_single_for_device;
 	hp->read32 = sbus_hme_read32;
 	hp->write32 = sbus_hme_write32;
 #endif
@@ -3182,7 +3192,10 @@ static int __init happy_meal_pci_init(st
 	hp->write_rxd = pci_hme_write_rxd;
 	hp->dma_map = (u32 (*)(void *, void *, long, int))pci_map_single;
 	hp->dma_unmap = (void (*)(void *, u32, long, int))pci_unmap_single;
-	hp->dma_sync = (void (*)(void *, u32, long, int))pci_dma_sync_single;
+	hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int))
+		pci_dma_sync_single_for_cpu;
+	hp->dma_sync_for_device = (void (*)(void *, u32, long, int))
+		pci_dma_sync_single_for_device;
 	hp->read32 = pci_hme_read32;
 	hp->write32 = pci_hme_write32;
 #endif
--- diff/drivers/net/sunhme.h	2003-05-21 11:49:45.000000000 +0100
+++ source/drivers/net/sunhme.h	2004-03-09 11:51:50.000000000 +0000
@@ -406,7 +406,8 @@ struct happy_meal {
 	void (*write_rxd)(struct happy_meal_rxd *, u32, u32);
 	u32 (*dma_map)(void *, void *, long, int);
 	void (*dma_unmap)(void *, u32, long, int);
-	void (*dma_sync)(void *, u32, long, int);
+	void (*dma_sync_for_cpu)(void *, u32, long, int);
+	void (*dma_sync_for_device)(void *, u32, long, int);
 #endif
 
 	/* This is either a sbus_dev or a pci_dev. */
--- diff/drivers/net/tg3.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/net/tg3.c	2004-03-09 11:51:50.000000000 +0000
@@ -2327,8 +2327,9 @@ static int tg3_rx(struct tg3 *tp, int bu
 			copy_skb->dev = tp->dev;
 			skb_reserve(copy_skb, 2);
 			skb_put(copy_skb, len);
-			pci_dma_sync_single(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
+			pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
 			memcpy(copy_skb->data, skb->data, len);
+			pci_dma_sync_single_for_device(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
 
 			/* We'll reuse the original ring buffer. */
 			skb = copy_skb;
@@ -2513,6 +2514,13 @@ static irqreturn_t tg3_interrupt(int irq
 static int tg3_init_hw(struct tg3 *);
 static int tg3_halt(struct tg3 *);
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void tg3_poll_controller(struct net_device *dev)
+{
+	tg3_interrupt(dev->irq, dev, NULL);
+}
+#endif
+
 static void tg3_reset_task(void *_data)
 {
 	struct tg3 *tp = _data;
@@ -7708,6 +7716,9 @@ static int __devinit tg3_init_one(struct
 	dev->watchdog_timeo = TG3_TX_TIMEOUT;
 	dev->change_mtu = tg3_change_mtu;
 	dev->irq = pdev->irq;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = tg3_poll_controller;
+#endif
 
 	err = tg3_get_invariants(tp);
 	if (err) {
--- diff/drivers/net/tlan.c	2003-11-25 15:24:58.000000000 +0000
+++ source/drivers/net/tlan.c	2004-03-09 11:51:50.000000000 +0000
@@ -814,6 +814,14 @@ static void  __init TLan_EisaProbe (void
 
 } /* TLan_EisaProbe */
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void TLan_Poll(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	TLan_HandleInterrupt(dev->irq, dev, NULL);
+	enable_irq(dev->irq);
+}
+#endif
 
 	
 
@@ -893,6 +901,9 @@ static int TLan_Init( struct net_device 
 	dev->get_stats = &TLan_GetStats;
 	dev->set_multicast_list = &TLan_SetMulticastList;
 	dev->do_ioctl = &TLan_ioctl;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = &TLan_Poll;
+#endif
 	dev->tx_timeout = &TLan_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 
--- diff/drivers/net/tokenring/3c359.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/net/tokenring/3c359.c	2004-03-09 11:51:50.000000000 +0000
@@ -937,15 +937,17 @@ static void xl_rx(struct net_device *dev
 			while (xl_priv->rx_ring_tail != temp_ring_loc) { 
 				copy_len = xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfraglen & 0x7FFF ; 
 				frame_length -= copy_len ;  
-				pci_dma_sync_single(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; 
+				pci_dma_sync_single_for_cpu(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ;
 				memcpy(skb_put(skb,copy_len), xl_priv->rx_ring_skb[xl_priv->rx_ring_tail]->data, copy_len) ; 
+				pci_dma_sync_single_for_device(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ;
 				adv_rx_ring(dev) ; 
 			} 
 
 			/* Now we have found the last fragment */
-			pci_dma_sync_single(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; 
+			pci_dma_sync_single_for_cpu(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ;
 			memcpy(skb_put(skb,copy_len), xl_priv->rx_ring_skb[xl_priv->rx_ring_tail]->data, frame_length) ; 
 /*			memcpy(skb_put(skb,frame_length), bus_to_virt(xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr), frame_length) ; */
+			pci_dma_sync_single_for_device(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ;
 			adv_rx_ring(dev) ; 
 			skb->protocol = tr_type_trans(skb,dev) ; 
 			netif_rx(skb) ; 
--- diff/drivers/net/tokenring/olympic.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/tokenring/olympic.c	2004-03-09 11:51:50.000000000 +0000
@@ -842,10 +842,13 @@ static void olympic_rx(struct net_device
 							olympic_priv->rx_ring_skb[rx_ring_last_received] = skb ; 
 							netif_rx(skb2) ; 
 						} else { 
-							pci_dma_sync_single(olympic_priv->pdev,
+							pci_dma_sync_single_for_cpu(olympic_priv->pdev,
 								le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer),
 								olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; 
 							memcpy(skb_put(skb,length-4),olympic_priv->rx_ring_skb[rx_ring_last_received]->data,length-4) ; 
+							pci_dma_sync_single_for_device(olympic_priv->pdev,
+								le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer),
+								olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ;
 							skb->protocol = tr_type_trans(skb,dev) ; 
 							netif_rx(skb) ; 
 						} 
@@ -854,12 +857,15 @@ static void olympic_rx(struct net_device
 							olympic_priv->rx_ring_last_received++ ; 
 							olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1);
 							rx_ring_last_received = olympic_priv->rx_ring_last_received ; 
-							pci_dma_sync_single(olympic_priv->pdev,
+							pci_dma_sync_single_for_cpu(olympic_priv->pdev,
 								le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer),
 								olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; 
 							rx_desc = &(olympic_priv->olympic_rx_ring[rx_ring_last_received]);
 							cpy_length = (i == 1 ? frag_len : le32_to_cpu(rx_desc->res_length)); 
 							memcpy(skb_put(skb, cpy_length), olympic_priv->rx_ring_skb[rx_ring_last_received]->data, cpy_length) ;
+							pci_dma_sync_single_for_device(olympic_priv->pdev,
+								le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer),
+								olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ;
 						} while (--i) ; 
 						skb_trim(skb,skb->len-4) ; 
 						skb->protocol = tr_type_trans(skb,dev);
--- diff/drivers/net/tulip/de2104x.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/tulip/de2104x.c	2004-03-09 11:51:50.000000000 +0000
@@ -457,10 +457,12 @@ static void de_rx (struct de_private *de
 					       buflen, PCI_DMA_FROMDEVICE);
 			de->rx_skb[rx_tail].skb = copy_skb;
 		} else {
-			pci_dma_sync_single(de->pdev, mapping, len, PCI_DMA_FROMDEVICE);
+			pci_dma_sync_single_for_cpu(de->pdev, mapping, len, PCI_DMA_FROMDEVICE);
 			skb_reserve(copy_skb, RX_OFFSET);
 			memcpy(skb_put(copy_skb, len), skb->tail, len);
 
+			pci_dma_sync_single_for_device(de->pdev, mapping, len, PCI_DMA_FROMDEVICE);
+
 			/* We'll reuse the original ring buffer. */
 			skb = copy_skb;
 		}
--- diff/drivers/net/tulip/interrupt.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/net/tulip/interrupt.c	2004-03-09 11:51:50.000000000 +0000
@@ -191,9 +191,9 @@ int tulip_poll(struct net_device *dev, i
                                    && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
                                        skb->dev = dev;
                                        skb_reserve(skb, 2);    /* 16 byte align the IP header */
-                                       pci_dma_sync_single(tp->pdev,
-                                                           tp->rx_buffers[entry].mapping,
-                                                           pkt_len, PCI_DMA_FROMDEVICE);
+                                       pci_dma_sync_single_for_cpu(tp->pdev,
+								   tp->rx_buffers[entry].mapping,
+								   pkt_len, PCI_DMA_FROMDEVICE);
 #if ! defined(__alpha__)
                                        eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail,
                                                         pkt_len, 0);
@@ -203,6 +203,9 @@ int tulip_poll(struct net_device *dev, i
                                               tp->rx_buffers[entry].skb->tail,
                                               pkt_len);
 #endif
+                                       pci_dma_sync_single_for_device(tp->pdev,
+								      tp->rx_buffers[entry].mapping,
+								      pkt_len, PCI_DMA_FROMDEVICE);
                                } else {        /* Pass up the skb already on the Rx ring. */
                                        char *temp = skb_put(skb = tp->rx_buffers[entry].skb,
                                                             pkt_len);
@@ -211,7 +214,7 @@ int tulip_poll(struct net_device *dev, i
                                        if (tp->rx_buffers[entry].mapping !=
                                            le32_to_cpu(tp->rx_ring[entry].buffer1)) {
                                                printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
-                                                      "do not match in tulip_rx: %08x vs. %llx %p / %p.\n",
+                                                      "do not match in tulip_rx: %08x vs. %08llx %p / %p.\n",
                                                       dev->name,
                                                       le32_to_cpu(tp->rx_ring[entry].buffer1),
                                                       (unsigned long long)tp->rx_buffers[entry].mapping,
@@ -412,9 +415,9 @@ static int tulip_rx(struct net_device *d
 				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
-				pci_dma_sync_single(tp->pdev,
-						    tp->rx_buffers[entry].mapping,
-						    pkt_len, PCI_DMA_FROMDEVICE);
+				pci_dma_sync_single_for_cpu(tp->pdev,
+							    tp->rx_buffers[entry].mapping,
+							    pkt_len, PCI_DMA_FROMDEVICE);
 #if ! defined(__alpha__)
 				eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail,
 						 pkt_len, 0);
@@ -424,6 +427,9 @@ static int tulip_rx(struct net_device *d
 				       tp->rx_buffers[entry].skb->tail,
 				       pkt_len);
 #endif
+				pci_dma_sync_single_for_device(tp->pdev,
+							       tp->rx_buffers[entry].mapping,
+							       pkt_len, PCI_DMA_FROMDEVICE);
 			} else { 	/* Pass up the skb already on the Rx ring. */
 				char *temp = skb_put(skb = tp->rx_buffers[entry].skb,
 						     pkt_len);
--- diff/drivers/net/tulip/tulip_core.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/tulip/tulip_core.c	2004-03-09 11:51:50.000000000 +0000
@@ -253,7 +253,7 @@ static void tulip_down(struct net_device
 static struct net_device_stats *tulip_get_stats(struct net_device *dev);
 static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void set_rx_mode(struct net_device *dev);
-
+static void poll_tulip(struct net_device *dev);
 
 
 static void tulip_set_power_state (struct tulip_private *tp,
@@ -1512,7 +1512,7 @@ static int __devinit tulip_init_one (str
 		}
 	}
 	/* Lite-On boards have the address byte-swapped. */
-	if ((dev->dev_addr[0] == 0xA0  ||  dev->dev_addr[0] == 0xC0)
+	if ((dev->dev_addr[0] == 0xA0  ||  dev->dev_addr[0] == 0xC0 || dev->dev_addr[0] == 0x02)
 		&&  dev->dev_addr[1] == 0x00)
 		for (i = 0; i < 6; i+=2) {
 			char tmp = dev->dev_addr[i];
@@ -1618,6 +1618,9 @@ static int __devinit tulip_init_one (str
 	dev->get_stats = tulip_get_stats;
 	dev->do_ioctl = private_ioctl;
 	dev->set_multicast_list = set_rx_mode;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = &poll_tulip;
+#endif
 
 	if (register_netdev(dev))
 		goto err_out_free_ring;
@@ -1774,6 +1777,22 @@ static void __devexit tulip_remove_one (
 	/* pci_power_off (pdev, -1); */
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+
+static void poll_tulip (struct net_device *dev)
+{
+	/* disable_irq here is not very nice, but with the lockless
+	   interrupt handler we have no other choice. */
+	disable_irq(dev->irq);
+	tulip_interrupt (dev->irq, dev, NULL);
+	enable_irq(dev->irq);
+}
+#endif
 
 static struct pci_driver tulip_driver = {
 	.name		= DRV_NAME,
--- diff/drivers/net/tulip/winbond-840.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/tulip/winbond-840.c	2004-03-09 11:51:50.000000000 +0000
@@ -1289,9 +1289,9 @@ static int netdev_rx(struct net_device *
 				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
-				pci_dma_sync_single(np->pci_dev,np->rx_addr[entry],
-							np->rx_skbuff[entry]->len,
-							PCI_DMA_FROMDEVICE);
+				pci_dma_sync_single_for_cpu(np->pci_dev,np->rx_addr[entry],
+							    np->rx_skbuff[entry]->len,
+							    PCI_DMA_FROMDEVICE);
 				/* Call copy + cksum if available. */
 #if HAS_IP_COPYSUM
 				eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
@@ -1300,6 +1300,9 @@ static int netdev_rx(struct net_device *
 				memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
 					   pkt_len);
 #endif
+				pci_dma_sync_single_for_device(np->pci_dev,np->rx_addr[entry],
+							       np->rx_skbuff[entry]->len,
+							       PCI_DMA_FROMDEVICE);
 			} else {
 				pci_unmap_single(np->pci_dev,np->rx_addr[entry],
 							np->rx_skbuff[entry]->len,
--- diff/drivers/net/typhoon.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/typhoon.c	2004-03-09 11:51:50.000000000 +0000
@@ -1701,9 +1701,13 @@ typhoon_rx(struct typhoon *tp, struct ba
 		   (new_skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 			new_skb->dev = tp->dev;
 			skb_reserve(new_skb, 2);
-			pci_dma_sync_single(tp->pdev, dma_addr, PKT_BUF_SZ,
-					    PCI_DMA_FROMDEVICE);
+			pci_dma_sync_single_for_cpu(tp->pdev, dma_addr,
+						    PKT_BUF_SZ,
+						    PCI_DMA_FROMDEVICE);
 			eth_copy_and_sum(new_skb, skb->tail, pkt_len, 0);
+			pci_dma_sync_single_for_device(tp->pdev, dma_addr,
+						       PKT_BUF_SZ,
+						       PCI_DMA_FROMDEVICE);
 			skb_put(new_skb, pkt_len);
 			typhoon_recycle_rx_skb(tp, idx);
 		} else {
--- diff/drivers/net/via-rhine.c	2003-09-17 12:28:08.000000000 +0100
+++ source/drivers/net/via-rhine.c	2004-03-09 11:51:50.000000000 +0000
@@ -615,6 +615,15 @@ static void __devinit reload_eeprom(long
 			break;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void via_rhine_poll(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	via_rhine_interrupt(dev->irq, (void *)dev, NULL);
+	enable_irq(dev->irq);
+}
+#endif
+
 static int __devinit via_rhine_init_one (struct pci_dev *pdev,
 					 const struct pci_device_id *ent)
 {
@@ -784,6 +793,9 @@ static int __devinit via_rhine_init_one 
 	dev->ethtool_ops = &netdev_ethtool_ops;
 	dev->tx_timeout = via_rhine_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = via_rhine_poll;
+#endif
 	if (np->drv_flags & ReqTxAlign)
 		dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
 
@@ -1524,7 +1536,7 @@ static void via_rhine_rx(struct net_devi
 				(skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
-				pci_dma_sync_single(np->pdev, np->rx_skbuff_dma[entry],
+				pci_dma_sync_single_for_cpu(np->pdev, np->rx_skbuff_dma[entry],
 						    np->rx_buf_sz, PCI_DMA_FROMDEVICE);
 
 				/* *_IP_COPYSUM isn't defined anywhere and eth_copy_and_sum
@@ -1537,6 +1549,8 @@ static void via_rhine_rx(struct net_devi
 				memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
 					   pkt_len);
 #endif
+				pci_dma_sync_single_for_device(np->pdev, np->rx_skbuff_dma[entry],
+						    np->rx_buf_sz, PCI_DMA_FROMDEVICE);
 			} else {
 				skb = np->rx_skbuff[entry];
 				if (skb == NULL) {
--- diff/drivers/net/wan/dscc4.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/net/wan/dscc4.c	2004-03-09 11:51:50.000000000 +0000
@@ -652,7 +652,6 @@ static inline void dscc4_rx_skb(struct d
 		goto refill;
 	}
 	pkt_len = TO_SIZE(rx_fd->state2);
-	pci_dma_sync_single(pdev, rx_fd->data, pkt_len, PCI_DMA_FROMDEVICE);
 	pci_unmap_single(pdev, rx_fd->data, RX_MAX(HDLC_MAX_MRU), PCI_DMA_FROMDEVICE);
 	if ((skb->data[--pkt_len] & FrameOk) == FrameOk) {
 		stats->rx_packets++;
--- diff/drivers/net/wan/wanxl.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/net/wan/wanxl.c	2004-03-09 11:51:50.000000000 +0000
@@ -31,7 +31,7 @@
 
 #include "wanxl.h"
 
-static const char* version = "wanXL serial card driver version: 0.47";
+static const char* version = "wanXL serial card driver version: 0.48";
 
 #define PLX_CTL_RESET   0x40000000 /* adapter reset */
 
@@ -73,12 +73,11 @@ typedef struct card_t {
 
 	u8 *plx;		/* PLX PCI9060 virtual base address */
 	struct pci_dev *pdev;	/* for pdev->slot_name */
-	port_t *ports[4];
 	int rx_in;
 	struct sk_buff *rx_skbs[RX_QUEUE_LENGTH];
 	card_status_t *status;	/* shared between host and card */
 	dma_addr_t status_address;
-	port_t __ports[0];
+	port_t ports[0];	/* 1 - 4 port_t structures follow */
 }card_t;
 
 
@@ -89,18 +88,6 @@ static inline port_t* dev_to_port(struct
 }
 
 
-static inline struct net_device *port_to_dev(port_t* port)
-{
-        return port->dev;
-}
-
-
-static inline const char* port_name(port_t *port)
-{
-	return port_to_dev(port)->name;
-}
-
-
 static inline const char* card_name(struct pci_dev *pdev)
 {
 	return pdev->slot_name;
@@ -165,9 +152,9 @@ static inline void wanxl_cable_intr(port
 		dte = (value & STATUS_CABLE_DCE) ? " DCE" : " DTE";
 	}
 	printk(KERN_INFO "%s: %s%s module, %s cable%s%s\n",
-	       port_name(port), pm, dte, cable, dsr, dcd);
+	       port->dev->name, pm, dte, cable, dsr, dcd);
 
-	hdlc_set_carrier(value & STATUS_CABLE_DCD, port_to_dev(port));
+	hdlc_set_carrier(value & STATUS_CABLE_DCD, port->dev);
 }
 
 
@@ -175,7 +162,7 @@ static inline void wanxl_cable_intr(port
 /* Transmit complete interrupt service */
 static inline void wanxl_tx_intr(port_t *port)
 {
-	struct net_device *dev = port_to_dev(port);
+	struct net_device *dev = port->dev;
 	struct net_device_stats *stats = hdlc_stats(dev);
 	while (1) {
                 desc_t *desc = &get_status(port)->tx_descs[port->tx_in];
@@ -210,47 +197,49 @@ static inline void wanxl_tx_intr(port_t 
 static inline void wanxl_rx_intr(card_t *card)
 {
 	desc_t *desc;
-	while(desc = &card->status->rx_descs[card->rx_in],
-	      desc->stat != PACKET_EMPTY) {
-		struct sk_buff *skb = card->rx_skbs[card->rx_in];
-		port_t *port = card->ports[desc->stat & PACKET_PORT_MASK];
-		struct net_device *dev = port_to_dev(port);
-		struct net_device_stats *stats = hdlc_stats(dev);
-
+	while (desc = &card->status->rx_descs[card->rx_in],
+	       desc->stat != PACKET_EMPTY) {
 		if ((desc->stat & PACKET_PORT_MASK) > card->n_ports)
 			printk(KERN_CRIT "wanXL %s: received packet for"
 			       " nonexistent port\n", card_name(card->pdev));
-
-		else if (!skb)
-			stats->rx_dropped++;
-
 		else {
-			pci_unmap_single(card->pdev, desc->address,
-					 BUFFER_LENGTH, PCI_DMA_FROMDEVICE);
-			skb_put(skb, desc->length);
+			struct sk_buff *skb = card->rx_skbs[card->rx_in];
+			port_t *port = &card->ports[desc->stat &
+						    PACKET_PORT_MASK];
+			struct net_device *dev = port->dev;
+			struct net_device_stats *stats = hdlc_stats(dev);
+
+			if (!skb)
+				stats->rx_dropped++;
+			else {
+				pci_unmap_single(card->pdev, desc->address,
+						 BUFFER_LENGTH,
+						 PCI_DMA_FROMDEVICE);
+				skb_put(skb, desc->length);
 
 #ifdef DEBUG_PKT
-			printk(KERN_DEBUG "%s RX(%i):", port_name(port),
-			       skb->len);
-			debug_frame(skb);
-#endif
-			stats->rx_packets++;
-			stats->rx_bytes += skb->len;
-			skb->mac.raw = skb->data;
-			skb->dev = dev;
-			dev->last_rx = jiffies;
-			skb->protocol = hdlc_type_trans(skb, dev);
-			netif_rx(skb);
-			skb = NULL;
-		}
-
-		if (!skb) {
-			skb = dev_alloc_skb(BUFFER_LENGTH);
-			desc->address = skb ?
-				pci_map_single(card->pdev, skb->data,
-					       BUFFER_LENGTH,
-					       PCI_DMA_FROMDEVICE) : 0;
-			card->rx_skbs[card->rx_in] = skb;
+				printk(KERN_DEBUG "%s RX(%i):", dev->name,
+				       skb->len);
+				debug_frame(skb);
+#endif
+				stats->rx_packets++;
+				stats->rx_bytes += skb->len;
+				skb->mac.raw = skb->data;
+				skb->dev = dev;
+				dev->last_rx = jiffies;
+				skb->protocol = hdlc_type_trans(skb, dev);
+				netif_rx(skb);
+				skb = NULL;
+			}
+
+			if (!skb) {
+				skb = dev_alloc_skb(BUFFER_LENGTH);
+				desc->address = skb ?
+					pci_map_single(card->pdev, skb->data,
+						       BUFFER_LENGTH,
+						       PCI_DMA_FROMDEVICE) : 0;
+				card->rx_skbs[card->rx_in] = skb;
+			}
 		}
 		desc->stat = PACKET_EMPTY; /* Free descriptor */
 		card->rx_in = (card->rx_in + 1) % RX_QUEUE_LENGTH;
@@ -273,9 +262,9 @@ static irqreturn_t wanxl_intr(int irq, v
 
                 for (i = 0; i < card->n_ports; i++) {
 			if (stat & (1 << (DOORBELL_FROM_CARD_TX_0 + i)))
-				wanxl_tx_intr(card->ports[i]);
+				wanxl_tx_intr(&card->ports[i]);
 			if (stat & (1 << (DOORBELL_FROM_CARD_CABLE_0 + i)))
-				wanxl_cable_intr(card->ports[i]);
+				wanxl_cable_intr(&card->ports[i]);
 		}
 		if (stat & (1 << DOORBELL_FROM_CARD_RX))
 			wanxl_rx_intr(card);
@@ -297,8 +286,7 @@ static int wanxl_xmit(struct sk_buff *sk
         if (desc->stat != PACKET_EMPTY) {
                 /* should never happen - previous xmit should stop queue */
 #ifdef DEBUG_PKT
-                printk(KERN_DEBUG "%s: transmitter buffer full\n",
-		       port_name(port));
+                printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name);
 #endif
 		netif_stop_queue(dev);
 		spin_unlock_irq(&port->lock);
@@ -306,7 +294,7 @@ static int wanxl_xmit(struct sk_buff *sk
 	}
 
 #ifdef DEBUG_PKT
-	printk(KERN_DEBUG "%s TX(%i):", port_name(port), skb->len);
+	printk(KERN_DEBUG "%s TX(%i):", dev->name, skb->len);
 	debug_frame(skb);
 #endif
 
@@ -324,8 +312,7 @@ static int wanxl_xmit(struct sk_buff *sk
 	if (get_status(port)->tx_descs[port->tx_out].stat != PACKET_EMPTY) {
 		netif_stop_queue(dev);
 #ifdef DEBUG_PKT
-		printk(KERN_DEBUG "%s: transmitter buffer full\n",
-		       port_name(port));
+		printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name);
 #endif
 	}
 
@@ -417,7 +404,7 @@ static int wanxl_open(struct net_device 
 	int i;
 
 	if (get_status(port)->open) {
-		printk(KERN_ERR "%s: port already open\n", port_name(port));
+		printk(KERN_ERR "%s: port already open\n", dev->name);
 		return -EIO;
 	}
 	if ((i = hdlc_open(dev)) != 0)
@@ -435,7 +422,7 @@ static int wanxl_open(struct net_device 
 			return 0;
 	while (time_after(timeout, jiffies));
 
-	printk(KERN_ERR "%s: unable to open port\n", port_name(port));
+	printk(KERN_ERR "%s: unable to open port\n", dev->name);
 	/* ask the card to close the port, should it be still alive */
 	writel(1 << (DOORBELL_TO_CARD_CLOSE_0 + port->node), dbr);
 	return -EFAULT;
@@ -461,7 +448,7 @@ static int wanxl_close(struct net_device
 	while (time_after(timeout, jiffies));
 
 	if (get_status(port)->open)
-		printk(KERN_ERR "%s: unable to close port\n", port_name(port));
+		printk(KERN_ERR "%s: unable to close port\n", dev->name);
 
 	for (i = 0; i < TX_BUFFERS; i++) {
 		desc_t *desc = &get_status(port)->tx_descs[i];
@@ -528,11 +515,10 @@ static void wanxl_pci_remove_one(struct 
 	card_t *card = pci_get_drvdata(pdev);
 	int i;
 
-	for (i = 0; i < 4; i++)
-		if (card->ports[i]) {
-			struct net_device *dev = port_to_dev(card->ports[i]);
-			unregister_hdlc_device(dev);
-		}
+	for (i = 0; i < card->n_ports; i++) {
+		unregister_hdlc_device(card->ports[i].dev);
+		free_netdev(card->ports[i].dev);
+	}
 
 	/* unregister and free all host resources */
 	if (card->irq)
@@ -555,13 +541,10 @@ static void wanxl_pci_remove_one(struct 
 		pci_free_consistent(pdev, sizeof(card_status_t),
 				    card->status, card->status_address);
 
-	for (i = 0; i < card->n_ports; i++)
-		if (card->__ports[i].dev)
-			free_netdev(card->__ports[i].dev);
-
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
 	kfree(card);
-	pci_release_regions(pdev);
 }
 
 
@@ -599,13 +582,15 @@ static int __devinit wanxl_pci_init_one(
 	   work on most platforms */
 	if (pci_set_consistent_dma_mask(pdev, 0x0FFFFFFF) ||
 	    pci_set_dma_mask(pdev, 0x0FFFFFFF)) {
-		printk(KERN_ERR "No usable DMA configuration\n");
+		printk(KERN_ERR "wanXL: No usable DMA configuration\n");
 		return -EIO;
 	}
 
 	i = pci_request_regions(pdev, "wanXL");
-	if (i)
+	if (i) {
+		pci_disable_device(pdev);
 		return i;
+	}
 
 	switch (pdev->device) {
 	case PCI_DEVICE_ID_SBE_WANXL100: ports = 1; break;
@@ -619,23 +604,13 @@ static int __devinit wanxl_pci_init_one(
 		printk(KERN_ERR "wanXL %s: unable to allocate memory\n",
 		       card_name(pdev));
 		pci_release_regions(pdev);
+		pci_disable_device(pdev);
 		return -ENOBUFS;
 	}
 	memset(card, 0, alloc_size);
 
 	pci_set_drvdata(pdev, card);
 	card->pdev = pdev;
-	card->n_ports = ports;
-
-	for (i = 0; i < ports; i++) {
-		card->__ports[i].dev = alloc_hdlcdev(&card->__ports[i]);
-		if (!card->__ports[i].dev) {
-			printk(KERN_ERR "wanXL %s: unable to allocate memory\n",
-			       card_name(pdev));
-			wanxl_pci_remove_one(pdev);
-			return -ENOMEM;
-		}
-	}
 
 	card->status = pci_alloc_consistent(pdev, sizeof(card_status_t),
 					    &card->status_address);
@@ -655,7 +630,7 @@ static int __devinit wanxl_pci_init_one(
 	   to indicate the card can do 32-bit DMA addressing */
 	if (pci_set_consistent_dma_mask(pdev, 0xFFFFFFFF) ||
 	    pci_set_dma_mask(pdev, 0xFFFFFFFF)) {
-		printk(KERN_ERR "No usable DMA configuration\n");
+		printk(KERN_ERR "wanXL: No usable DMA configuration\n");
 		wanxl_pci_remove_one(pdev);
 		return -EIO;
 	}
@@ -767,17 +742,11 @@ static int __devinit wanxl_pci_init_one(
 	ramsize = stat;
 #endif
 
-	printk(KERN_INFO "wanXL %s: at 0x%X, %u KB of RAM at 0x%X, irq"
-	       " %u\n" KERN_INFO "wanXL %s: port", card_name(pdev),
-	       plx_phy, ramsize / 1024, mem_phy, pdev->irq, card_name(pdev));
-
-	for (i = 0; i < ports; i++)
-		printk("%s #%i: %s", i ? "," : "", i,
-		       port_name(card->ports[i]));
-	printk("\n");
+	printk(KERN_INFO "wanXL %s: at 0x%X, %u KB of RAM at 0x%X, irq %u\n",
+	       card_name(pdev), plx_phy, ramsize / 1024, mem_phy, pdev->irq);
 
 	/* Allocate IRQ */
-	if(request_irq(pdev->irq, wanxl_intr, SA_SHIRQ, "wanXL", card)) {
+	if (request_irq(pdev->irq, wanxl_intr, SA_SHIRQ, "wanXL", card)) {
 		printk(KERN_WARNING "wanXL %s: could not allocate IRQ%i.\n",
 		       card_name(pdev), pdev->irq);
 		wanxl_pci_remove_one(pdev);
@@ -786,9 +755,18 @@ static int __devinit wanxl_pci_init_one(
 	card->irq = pdev->irq;
 
 	for (i = 0; i < ports; i++) {
-		port_t *port = &card->__ports[i];
-		struct net_device *dev = port_to_dev(port);
-		hdlc_device *hdlc = dev_to_hdlc(dev);
+		hdlc_device *hdlc;
+		port_t *port = &card->ports[i];
+		struct net_device *dev = alloc_hdlcdev(port);
+		if (!dev) {
+			printk(KERN_ERR "wanXL %s: unable to allocate"
+			       " memory\n", card_name(pdev));
+			wanxl_pci_remove_one(pdev);
+			return -ENOMEM;
+		}
+
+		port->dev = dev;
+		hdlc = dev_to_hdlc(dev);
 		spin_lock_init(&port->lock);
 		SET_MODULE_OWNER(dev);
 		dev->tx_queue_len = 50;
@@ -797,7 +775,6 @@ static int __devinit wanxl_pci_init_one(
 		dev->stop = wanxl_close;
 		hdlc->attach = wanxl_attach;
 		hdlc->xmit = wanxl_xmit;
-		card->ports[i] = port;
 		dev->get_stats = wanxl_get_stats;
 		port->card = card;
 		port->node = i;
@@ -805,12 +782,22 @@ static int __devinit wanxl_pci_init_one(
 		if (register_hdlc_device(dev)) {
 			printk(KERN_ERR "wanXL %s: unable to register hdlc"
 			       " device\n", card_name(pdev));
-			card->ports[i] = NULL;
+			free_netdev(dev);
 			wanxl_pci_remove_one(pdev);
 			return -ENOBUFS;
 		}
+		card->n_ports++;
 	}
 
+	printk(KERN_INFO "wanXL %s: port", card_name(pdev));
+	for (i = 0; i < ports; i++)
+		printk("%s #%i: %s", i ? "," : "", i,
+		       card->ports[i].dev->name);
+	printk("\n");
+
+	for (i = 0; i < ports; i++)
+		wanxl_cable_intr(&card->ports[i]); /* get carrier status etc.*/
+
 	return 0;
 }
 
--- diff/drivers/net/wd.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/wd.c	2004-03-09 11:51:50.000000000 +0000
@@ -333,6 +333,9 @@ static int __init wd_probe1(struct net_d
 	ei_status.get_8390_hdr = &wd_get_8390_hdr;
 	dev->open = &wd_open;
 	dev->stop = &wd_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 
 #if 1
--- diff/drivers/net/yellowfin.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/yellowfin.c	2004-03-09 11:51:50.000000000 +0000
@@ -1124,7 +1124,7 @@ static int yellowfin_rx(struct net_devic
 
 		if(!desc->result_status)
 			break;
-		pci_dma_sync_single(yp->pci_dev, desc->addr, 
+		pci_dma_sync_single_for_cpu(yp->pci_dev, desc->addr,
 			yp->rx_buf_sz, PCI_DMA_FROMDEVICE);
 		desc_status = le32_to_cpu(desc->result_status) >> 16;
 		buf_addr = rx_skb->tail;
@@ -1208,6 +1208,9 @@ static int yellowfin_rx(struct net_devic
 				memcpy(skb_put(skb, pkt_len), 
 					rx_skb->tail, pkt_len);
 #endif
+				pci_dma_sync_single_for_device(yp->pci_dev, desc->addr,
+											   yp->rx_buf_sz,
+											   PCI_DMA_FROMDEVICE);
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
--- diff/drivers/net/zorro8390.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/net/zorro8390.c	2004-03-09 11:51:50.000000000 +0000
@@ -227,6 +227,10 @@ static int __devinit zorro8390_init(stru
     ei_status.reg_offset = zorro8390_offsets;
     dev->open = &zorro8390_open;
     dev->stop = &zorro8390_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+    dev->poll_controller = ei_poll;
+#endif
+
     NS8390_init(dev, 0);
     err = register_netdev(dev);
     if (err)
--- diff/drivers/parisc/ccio-dma.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/parisc/ccio-dma.c	2004-03-09 11:51:50.000000000 +0000
@@ -1149,8 +1149,10 @@ static struct hppa_dma_ops ccio_ops = {
 	.unmap_single =		ccio_unmap_single,
 	.map_sg = 		ccio_map_sg,
 	.unmap_sg = 		ccio_unmap_sg,
-	.dma_sync_single =	NULL,	/* NOP for U2/Uturn */
-	.dma_sync_sg =		NULL,	/* ditto */
+	.dma_sync_single_for_cpu =	NULL,	/* NOP for U2/Uturn */
+	.dma_sync_single_for_device =	NULL,	/* NOP for U2/Uturn */
+	.dma_sync_sg_for_cpu =		NULL,	/* ditto */
+	.dma_sync_sg_for_device =		NULL,	/* ditto */
 };
 
 #ifdef CONFIG_PROC_FS
--- diff/drivers/parisc/ccio-rm-dma.c	2003-02-13 11:46:53.000000000 +0000
+++ source/drivers/parisc/ccio-rm-dma.c	2004-03-09 11:51:50.000000000 +0000
@@ -151,8 +151,10 @@ static struct pci_dma_ops ccio_ops = {
 	ccio_unmap_single,
 	ccio_map_sg,
 	ccio_unmap_sg,
-	NULL,                   /* dma_sync_single : NOP for U2 */
-	NULL,                   /* dma_sync_sg     : ditto */
+	NULL,                   /* dma_sync_single_for_cpu : NOP for U2 */
+	NULL,                   /* dma_sync_single_for_device : NOP for U2 */
+	NULL,                   /* dma_sync_sg_for_cpu     : ditto */
+	NULL,                   /* dma_sync_sg_for_device     : ditto */
 };
 
 
--- diff/drivers/parisc/sba_iommu.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/parisc/sba_iommu.c	2004-03-09 11:51:50.000000000 +0000
@@ -1410,8 +1410,10 @@ static struct hppa_dma_ops sba_ops = {
 	.unmap_single =		sba_unmap_single,
 	.map_sg =		sba_map_sg,
 	.unmap_sg =		sba_unmap_sg,
-	.dma_sync_single =	NULL,
-	.dma_sync_sg =		NULL,
+	.dma_sync_single_for_cpu =	NULL,
+	.dma_sync_single_for_device =	NULL,
+	.dma_sync_sg_for_cpu =		NULL,
+	.dma_sync_sg_for_device =	NULL,
 };
 
 
--- diff/drivers/parport/parport_sunbpp.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/parport/parport_sunbpp.c	2004-03-09 11:51:50.000000000 +0000
@@ -44,9 +44,10 @@
 #define dprintk(x)
 #endif
 
-static void parport_sunbpp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t parport_sunbpp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	parport_generic_irq(irq, (struct parport *) dev_id, regs);
+	return IRQ_HANDLED;
 }
 
 static void parport_sunbpp_disable_irq(struct parport *p)
@@ -384,7 +385,7 @@ static int __init parport_sunbpp_init(vo
 
 static void __exit parport_sunbpp_exit(void)
 {
-	while (!list_empty(port_list)) {
+	while (!list_empty(&port_list)) {
 		Node *node = list_entry(port_list.next, Node, list);
 		struct parport *p = node->port;
 		struct parport_operations *ops = p->ops;
--- diff/drivers/pci/pci.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/pci/pci.c	2004-03-09 11:51:50.000000000 +0000
@@ -205,6 +205,8 @@ pci_set_power_state(struct pci_dev *dev,
 	int pm;
 	u16 pmcsr;
 
+	might_sleep();
+
 	/* bound the state we're entering */
 	if (state > 3) state = 3;
 
@@ -686,7 +688,7 @@ pci_set_consistent_dma_mask(struct pci_d
 	if (!pci_dma_supported(dev, mask))
 		return -EIO;
 
-	dev->consistent_dma_mask = mask;
+	dev->dev.coherent_dma_mask = mask;
 
 	return 0;
 }
--- diff/drivers/pci/pci.ids	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/pci/pci.ids	2004-03-09 11:51:50.000000000 +0000
@@ -5601,6 +5601,8 @@
 14da  National Aerospace Laboratories
 14db  AFAVLAB Technology Inc
 	2120  TK9902
+	2180  P028
+	2182  P030
 14dc  Amplicon Liveline Ltd
 	0000  PCI230
 	0001  PCI242
--- diff/drivers/pci/probe.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/pci/probe.c	2004-03-09 11:51:50.000000000 +0000
@@ -570,7 +570,6 @@ pci_scan_device(struct pci_bus *bus, int
 	/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
 	   set this higher, assuming the system even supports it.  */
 	dev->dma_mask = 0xffffffff;
-	dev->consistent_dma_mask = 0xffffffff;
 	if (pci_setup_device(dev) < 0) {
 		kfree(dev);
 		return NULL;
@@ -582,6 +581,7 @@ pci_scan_device(struct pci_bus *bus, int
 	pci_name_device(dev);
 
 	dev->dev.dma_mask = &dev->dma_mask;
+	dev->dev.coherent_dma_mask = 0xffffffffull;
 
 	return dev;
 }
--- diff/drivers/pcmcia/au1000_generic.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/pcmcia/au1000_generic.c	2004-03-09 11:51:50.000000000 +0000
@@ -26,6 +26,7 @@
  * 
  */
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/config.h>
 #include <linux/delay.h>
@@ -54,8 +55,17 @@
 #include <asm/au1000.h>
 #include <asm/au1000_pcmcia.h>
 
-#ifdef PCMCIA_DEBUG
+#ifdef DEBUG
 static int pc_debug;
+
+module_param(pc_debug, int, 0644);
+
+#define debug(lvl,fmt) do {			\
+	if (pc_debug > (lvl))			\
+		printk(KERN_DEBUG fmt);		\
+} while (0)
+#else
+#define debug(lvl,fmt) do { } while (0)
 #endif
 
 MODULE_LICENSE("GPL");
@@ -209,7 +219,7 @@ static int __init au1000_pcmcia_driver_i
 	 */
 	au1000_pcmcia_poll_event(0);
 
-	DEBUG(1, "au1000: initialization complete\n");
+	debug(1, "au1000: initialization complete\n");
 	return 0;
 
 }  /* au1000_pcmcia_driver_init() */
@@ -228,7 +238,7 @@ static void __exit au1000_pcmcia_driver_
 		if (pcmcia_socket[i].virt_io) 
 			iounmap((void *)pcmcia_socket[i].virt_io);
 	}
-	DEBUG(1, "au1000: shutdown complete\n");
+	debug(1, "au1000: shutdown complete\n");
 }
 
 module_exit(au1000_pcmcia_driver_shutdown);
@@ -249,14 +259,14 @@ au1000_pcmcia_events(struct pcmcia_state
 	unsigned int events=0;
 
 	if(state->detect!=prev_state->detect){
-		DEBUG(2, "%s(): card detect value %u\n", 
+		debug(2, "%s(): card detect value %u\n",
 				__FUNCTION__, state->detect);
 		events |= mask&SS_DETECT;
 	}
 
 
 	if(state->ready!=prev_state->ready){
-		DEBUG(2, "%s(): card ready value %u\n", 
+		debug(2, "%s(): card ready value %u\n",
 				__FUNCTION__, state->ready);
 		events |= mask&((flags&SS_IOCARD)?0:SS_READY);
 	}
@@ -429,7 +439,7 @@ au1000_pcmcia_get_status(unsigned int so
 
 	*status|=state.vs_Xv?SS_XVCARD:0;
 
-	DEBUG(2, "\tstatus: %s%s%s%s%s%s%s%s\n",
+	debug(2, "\tstatus: %s%s%s%s%s%s%s%s\n",
 	(*status&SS_DETECT)?"DETECT ":"",
 	(*status&SS_READY)?"READY ":"", 
 	(*status&SS_BATDEAD)?"BATDEAD ":"",
@@ -457,7 +467,7 @@ au1000_pcmcia_set_socket(unsigned int so
 {
 	struct pcmcia_configure configure;
 
-	DEBUG(2, "\tmask:  %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n"
+	debug(2, "\tmask:  %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n"
 	"\tVcc %d  Vpp %d  irq %d\n",
 	(state->csc_mask==0)?"<NONE>":"",
 	(state->csc_mask&SS_DETECT)?"DETECT ":"",
@@ -494,7 +504,7 @@ au1000_pcmcia_set_socket(unsigned int so
 static int 
 au1000_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *map)
 {
-	DEBUG(1, "au1000_pcmcia_get_io_map: sock %d\n", sock);
+	debug(1, "au1000_pcmcia_get_io_map: sock %d\n", sock);
 	if(map->map>=MAX_IO_WIN){
 		printk(KERN_ERR "%s(): map (%d) out of range\n", 
 				__FUNCTION__, map->map);
@@ -531,7 +541,7 @@ au1000_pcmcia_set_io_map(unsigned int so
 	map->start=pcmcia_socket[sock].virt_io;
 	map->stop=map->start+(map->stop-start);
 	pcmcia_socket[sock].io_map[map->map]=*map;
-	DEBUG(3, "set_io_map %d start %x stop %x\n", 
+	debug(3, "set_io_map %d start %x stop %x\n",
 			map->map, map->start, map->stop);
 	return 0;
 
@@ -595,7 +605,7 @@ au1000_pcmcia_set_mem_map(unsigned int s
 	map->sys_stop=map->sys_start+(map->sys_stop-start);
 	pcmcia_socket[sock].mem_map[map->map]=*map;
 	spin_unlock_irqrestore(&pcmcia_lock, flags);
-	DEBUG(3, "set_mem_map %d start %x stop %x card_start %x\n", 
+	debug(3, "set_mem_map %d start %x stop %x card_start %x\n",
 			map->map, map->sys_start, map->sys_stop, 
 			map->card_start);
 	return 0;
--- diff/drivers/pcmcia/au1000_pb1x00.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/pcmcia/au1000_pb1x00.c	2004-03-09 11:51:50.000000000 +0000
@@ -48,6 +48,8 @@
 #include <asm/au1000.h>
 #include <asm/au1000_pcmcia.h>
 
+#define debug(fmt, arg...) do { } while (0)
+
 #ifdef CONFIG_MIPS_PB1000
 #include <asm/pb1000.h>
 #define PCMCIA_IRQ AU1000_GPIO_15
@@ -213,7 +215,7 @@ pb1x00_pcmcia_configure_socket(const str
 	}
 
 	pcr &= ~PCR_SLOT_0_RST;
-	DEBUG(KERN_INFO "Vcc %dV Vpp %dV, pcr %x\n", 
+	debug("Vcc %dV Vpp %dV, pcr %x\n",
 			configure->vcc, configure->vpp, pcr);
 	switch(configure->vcc){
 		case 0:  /* Vcc 0 */
@@ -324,7 +326,7 @@ pb1x00_pcmcia_configure_socket(const str
 
 	pcr = au_readw(PB1100_MEM_PCMCIA) & ~0xf;
 
-	DEBUG(KERN_INFO "Vcc %dV Vpp %dV, pcr %x, reset %d\n", 
+	debug("Vcc %dV Vpp %dV, pcr %x, reset %d\n",
 			configure->vcc, configure->vpp, pcr, configure->reset);
 
 
--- diff/drivers/pcmcia/bulkmem.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/pcmcia/bulkmem.c	2004-03-09 11:51:50.000000000 +0000
@@ -48,6 +48,8 @@
 #include <pcmcia/cistpl.h>
 #include "cs_internal.h"
 
+static void retry_erase_list(erase_busy_t *list, u_int cause);
+
 /*======================================================================
 
     This function handles submitting an MTD request, and retrying
@@ -108,18 +110,18 @@ static int do_mtd_request(memory_handle_
 
 ======================================================================*/
 
-static void insert_queue(erase_busy_t *head, erase_busy_t *entry)
+static void insert_queue(struct pcmcia_socket *s, erase_busy_t *head, erase_busy_t *entry)
 {
-    DEBUG(2, "cs: adding 0x%p to queue 0x%p\n", entry, head);
+    cs_dbg(s, 2, "adding 0x%p to queue 0x%p\n", entry, head);
     entry->next = head;
     entry->prev = head->prev;
     head->prev->next = entry;
     head->prev = entry;
 }
 
-static void remove_queue(erase_busy_t *entry)
+static void remove_queue(struct pcmcia_socket *s, erase_busy_t *entry)
 {
-    DEBUG(2, "cs: unqueueing 0x%p\n", entry);
+    cs_dbg(s, 2, "unqueueing 0x%p\n", entry);
     entry->next->prev = entry->prev;
     entry->prev->next = entry->next;
 }
@@ -132,34 +134,35 @@ static void retry_erase(erase_busy_t *bu
     struct pcmcia_socket *s;
     int ret;
 
-    DEBUG(2, "cs: trying erase request 0x%p...\n", busy);
+    mtd = erase->Handle->mtd;
+    s = SOCKET(mtd);
+
+    cs_dbg(s, 2, "trying erase request 0x%p...\n", busy);
     if (busy->next)
-	remove_queue(busy);
+	remove_queue(s, busy);
     req.Function = MTD_REQ_ERASE | cause;
     req.TransferLength = erase->Size;
     req.DestCardOffset = erase->Offset + erase->Handle->info.CardOffset;
     req.MediaID = erase->Handle->MediaID;
-    mtd = erase->Handle->mtd;
-    s = SOCKET(mtd);
     mtd->event_callback_args.mtdrequest = &req;
     ret = EVENT(mtd, CS_EVENT_MTD_REQUEST, CS_EVENT_PRI_LOW);
     if (ret == CS_BUSY) {
-	DEBUG(2, "  Status = %d, requeueing.\n", req.Status);
+	cs_dbg(s, 2, "  Status = %d, requeueing.\n", req.Status);
 	switch (req.Status) {
 	case MTD_WAITREQ:
 	case MTD_WAITPOWER:
-	    insert_queue(&mtd->erase_busy, busy);
+	    insert_queue(s, &mtd->erase_busy, busy);
 	    break;
 	case MTD_WAITTIMER:
 	case MTD_WAITRDY:
 	    if (req.Status == MTD_WAITRDY)
-		insert_queue(&s->erase_busy, busy);
+		insert_queue(s, &s->erase_busy, busy);
 	    mod_timer(&busy->timeout, jiffies + req.Timeout*HZ/1000);
 	    break;
 	}
     } else {
 	/* update erase queue status */
-	DEBUG(2, "  Ret = %d\n", ret);
+	cs_dbg(s, 2, "  Ret = %d\n", ret);
 	switch (ret) {
 	case CS_SUCCESS:
 	    erase->State = ERASE_PASSED; break;
@@ -183,11 +186,11 @@ static void retry_erase(erase_busy_t *bu
     }
 } /* retry_erase */
 
-void retry_erase_list(erase_busy_t *list, u_int cause)
+static void retry_erase_list(erase_busy_t *list, u_int cause)
 {
     erase_busy_t tmp = *list;
 
-    DEBUG(2, "cs: rescanning erase queue list 0x%p\n", list);
+    cs_dbg(SOCKET(list->client), 2, "rescanning erase queue list 0x%p\n", list);
     if (list->next == list)
 	return;
     /* First, truncate the original list */
@@ -204,8 +207,9 @@ void retry_erase_list(erase_busy_t *list
 
 static void handle_erase_timeout(u_long arg)
 {
-    DEBUG(0, "cs: erase timeout for entry 0x%lx\n", arg);
-    retry_erase((erase_busy_t *)arg, MTD_REQ_TIMEOUT);
+    erase_busy_t *busy = (erase_busy_t *)arg;
+    cs_dbg(SOCKET(busy->client), 0, "erase timeout for entry 0x%lx\n", arg);
+    retry_erase(busy, MTD_REQ_TIMEOUT);
 }
 
 static void setup_erase_request(client_handle_t handle, eraseq_entry_t *erase)
@@ -333,8 +337,8 @@ static void setup_regions(client_handle_
     cistpl_device_geo_t geo;
     memory_handle_t r;
 
-    DEBUG(1, "cs: setup_regions(0x%p, %d, 0x%p)\n",
-	  handle, attr, list);
+    cs_dbg(SOCKET(handle), 1, "setup_regions(0x%p, %d, 0x%p)\n",
+	   handle, attr, list);
 
     code = (attr) ? CISTPL_DEVICE_A : CISTPL_DEVICE;
     if (read_tuple(handle, code, &device) != CS_SUCCESS)
@@ -342,17 +346,13 @@ static void setup_regions(client_handle_
     code = (attr) ? CISTPL_JEDEC_A : CISTPL_JEDEC_C;
     has_jedec = (read_tuple(handle, code, &jedec) == CS_SUCCESS);
     if (has_jedec && (device.ndev != jedec.nid)) {
-#ifdef PCMCIA_DEBUG
-	printk(KERN_DEBUG "cs: Device info does not match JEDEC info.\n");
-#endif
+	cs_dbg(SOCKET(handle), 0, "Device info does not match JEDEC info.\n");
 	has_jedec = 0;
     }
     code = (attr) ? CISTPL_DEVICE_GEO_A : CISTPL_DEVICE_GEO;
     has_geo = (read_tuple(handle, code, &geo) == CS_SUCCESS);
     if (has_geo && (device.ndev != geo.ngeo)) {
-#ifdef PCMCIA_DEBUG
-	printk(KERN_DEBUG "cs: Device info does not match geometry tuple.\n");
-#endif
+	cs_dbg(SOCKET(handle), 0, "Device info does not match geometry tuple.\n");
 	has_geo = 0;
     }
     
@@ -458,7 +458,7 @@ int pcmcia_register_mtd(client_handle_t 
 	list = s->a_region;
     else
 	list = s->c_region;
-    DEBUG(1, "cs: register_mtd(0x%p, '%s', 0x%x)\n",
+    cs_dbg(s, 1, "register_mtd(0x%p, '%s', 0x%x)\n",
 	  handle, handle->dev_info, reg->Offset);
     while (list) {
 	if (list->info.CardOffset == reg->Offset) break;
@@ -548,8 +548,8 @@ int pcmcia_open_memory(client_handle_t *
     }
     if (region && region->mtd) {
 	*mh = region;
-	DEBUG(1, "cs: open_memory(0x%p, 0x%x) = 0x%p\n",
-	      handle, open->Offset, region);
+	cs_dbg(s, 1, "open_memory(0x%p, 0x%x) = 0x%p\n",
+	       handle, open->Offset, region);
 	return CS_SUCCESS;
     } else
 	return CS_BAD_OFFSET;
@@ -565,7 +565,7 @@ int pcmcia_open_memory(client_handle_t *
 
 int pcmcia_close_memory(memory_handle_t handle)
 {
-    DEBUG(1, "cs: close_memory(0x%p)\n", handle);
+    cs_dbg(SOCKET(handle->mtd), 1, "cs: close_memory(0x%p)\n", handle);
     if (CHECK_REGION(handle))
 	return CS_BAD_HANDLE;
     return CS_SUCCESS;
--- diff/drivers/pcmcia/cardbus.c	2003-09-30 15:46:16.000000000 +0100
+++ source/drivers/pcmcia/cardbus.c	2004-03-09 11:51:50.000000000 +0000
@@ -58,10 +58,6 @@
 #include <pcmcia/cistpl.h>
 #include "cs_internal.h"
 
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-#endif
-
 /*====================================================================*/
 
 #define FIND_FIRST_BIT(n)	((n) - ((n) & ((n)-1)))
@@ -119,7 +115,7 @@ static u_int xlate_rom_addr(u_char * b, 
 static void cb_release_cis_mem(struct pcmcia_socket * s)
 {
 	if (s->cb_cis_virt) {
-		DEBUG(1, "cs: cb_release_cis_mem()\n");
+		cs_dbg(s, 1, "cb_release_cis_mem()\n");
 		iounmap(s->cb_cis_virt);
 		s->cb_cis_virt = NULL;
 		s->cb_cis_res = 0;
@@ -160,7 +156,7 @@ int read_cb_mem(struct pcmcia_socket * s
 	struct pci_dev *dev;
 	struct resource *res;
 
-	DEBUG(3, "cs: read_cb_mem(%d, %#x, %u)\n", space, addr, len);
+	cs_dbg(s, 3, "read_cb_mem(%d, %#x, %u)\n", space, addr, len);
 
 	dev = pci_find_slot(s->cb_dev->subordinate->number, 0);
 	if (!dev)
--- diff/drivers/pcmcia/cistpl.c	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/pcmcia/cistpl.c	2004-03-09 11:51:50.000000000 +0000
@@ -143,7 +143,7 @@ int read_cis_mem(struct pcmcia_socket *s
 {
     u_char *sys, *end, *buf = ptr;
     
-    DEBUG(3, "cs: read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
+    cs_dbg(s, 3, "read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
 
     if (attr & IS_INDIRECT) {
 	/* Indirect accesses use a bunch of special registers at fixed
@@ -195,7 +195,7 @@ int read_cis_mem(struct pcmcia_socket *s
 	    addr = 0;
 	}
     }
-    DEBUG(3, "cs:  %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
+    cs_dbg(s, 3, "  %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
 	  *(u_char *)(ptr+0), *(u_char *)(ptr+1),
 	  *(u_char *)(ptr+2), *(u_char *)(ptr+3));
     return 0;
@@ -206,7 +206,7 @@ void write_cis_mem(struct pcmcia_socket 
 {
     u_char *sys, *end, *buf = ptr;
     
-    DEBUG(3, "cs: write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
+    cs_dbg(s, 3, "write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
 
     if (attr & IS_INDIRECT) {
 	/* Indirect accesses use a bunch of special registers at fixed
@@ -578,8 +578,7 @@ int pcmcia_get_next_tuple(client_handle_
 	ofs += link[1] + 2;
     }
     if (i == MAX_TUPLES) {
-	DEBUG(1, "cs: overrun in pcmcia_get_next_tuple for socket %d\n",
-	      handle->Socket);
+	cs_dbg(s, 1, "cs: overrun in pcmcia_get_next_tuple\n");
 	return CS_NO_MORE_ITEMS;
     }
     
--- diff/drivers/pcmcia/cs.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/pcmcia/cs.c	2004-03-09 11:51:50.000000000 +0000
@@ -32,6 +32,7 @@
 ======================================================================*/
 
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/config.h>
@@ -110,12 +111,17 @@ INT_MODULE_PARM(cis_speed,	300);		/* ns 
 /* Access speed for IO windows */
 INT_MODULE_PARM(io_speed,	0);		/* ns */
 
-#ifdef PCMCIA_DEBUG
-INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
-static const char *version =
-"cs.c 1.279 2001/10/13 00:08:28 (David Hinds)";
+#ifdef DEBUG
+static int pc_debug;
+
+module_param(pc_debug, int, 0644);
+
+int cs_debug_level(int level)
+{
+	return pc_debug > level;
+}
 #endif
- 
+
 /*====================================================================*/
 
 socket_state_t dead_socket = {
@@ -306,7 +312,7 @@ int pcmcia_register_socket(struct pcmcia
 	if (!socket || !socket->ops || !socket->dev.dev)
 		return -EINVAL;
 
-	DEBUG(0, "cs: pcmcia_register_socket(0x%p)\n", socket->ops);
+	cs_dbg(socket, 0, "pcmcia_register_socket(0x%p)\n", socket->ops);
 
 	/* try to obtain a socket number [yes, it gets ugly if we
 	 * register more than 2^sizeof(unsigned int) pcmcia 
@@ -377,7 +383,7 @@ void pcmcia_unregister_socket(struct pcm
 	if (!socket)
 		return;
 
-	DEBUG(0, "cs: pcmcia_unregister_socket(0x%p)\n", socket->ops);
+	cs_dbg(socket, 0, "pcmcia_unregister_socket(0x%p)\n", socket->ops);
 
 	if (socket->thread) {
 		init_completion(&socket->thread_done);
@@ -443,7 +449,7 @@ static void shutdown_socket(struct pcmci
 {
     client_t **c;
     
-    DEBUG(1, "cs: shutdown_socket(%p)\n", s);
+    cs_dbg(s, 1, "shutdown_socket\n");
 
     /* Blank out the socket state */
     s->state &= SOCKET_PRESENT|SOCKET_INUSE;
@@ -499,8 +505,8 @@ static int send_event(struct pcmcia_sock
 {
     client_t *client = s->clients;
     int ret;
-    DEBUG(1, "cs: send_event(sock %d, event %d, pri %d)\n",
-	  s->sock, event, priority);
+    cs_dbg(s, 1, "send_event(event %d, pri %d)\n",
+	   event, priority);
     ret = 0;
     if (s->state & SOCKET_CARDBUS)
 	    return 0;
@@ -516,26 +522,14 @@ static int send_event(struct pcmcia_sock
     return ret;
 } /* send_event */
 
-static void pcmcia_error(struct pcmcia_socket *skt, const char *fmt, ...)
-{
-	static char buf[128];
-	va_list ap;
-	int len;
-
-	va_start(ap, fmt);
-	len = vsnprintf(buf, sizeof(buf), fmt, ap);
-	va_end(ap);
-	buf[len] = '\0';
-
-	printk(KERN_ERR "PCMCIA: socket %p: %s", skt, buf);
-}
-
 #define cs_to_timeout(cs) (((cs) * HZ + 99) / 100)
 
 static void socket_remove_drivers(struct pcmcia_socket *skt)
 {
 	client_t *client;
 
+	cs_dbg(skt, 4, "remove_drivers\n");
+
 	send_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);
 
 	for (client = skt->clients; client; client = client->next)
@@ -545,6 +539,8 @@ static void socket_remove_drivers(struct
 
 static void socket_shutdown(struct pcmcia_socket *skt)
 {
+	cs_dbg(skt, 4, "shutdown\n");
+
 	socket_remove_drivers(skt);
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(cs_to_timeout(shutdown_delay));
@@ -556,6 +552,8 @@ static int socket_reset(struct pcmcia_so
 {
 	int status, i;
 
+	cs_dbg(skt, 4, "reset\n");
+
 	skt->socket.flags |= SS_OUTPUT_ENA | SS_RESET;
 	skt->ops->set_socket(skt, &skt->socket);
 	udelay((long)reset_time);
@@ -578,7 +576,7 @@ static int socket_reset(struct pcmcia_so
 		schedule_timeout(cs_to_timeout(unreset_check));
 	}
 
-	pcmcia_error(skt, "time out after reset.\n");
+	cs_err(skt, "time out after reset.\n");
 	return CS_GENERAL_FAILURE;
 }
 
@@ -586,6 +584,8 @@ static int socket_setup(struct pcmcia_so
 {
 	int status, i;
 
+	cs_dbg(skt, 4, "setup\n");
+
 	skt->ops->get_status(skt, &status);
 	if (!(status & SS_DETECT))
 		return CS_NO_CARD;
@@ -606,14 +606,14 @@ static int socket_setup(struct pcmcia_so
 	}
 
 	if (status & SS_PENDING) {
-		pcmcia_error(skt, "voltage interrogation timed out.\n");
+		cs_err(skt, "voltage interrogation timed out.\n");
 		return CS_GENERAL_FAILURE;
 	}
 
 	if (status & SS_CARDBUS) {
 		skt->state |= SOCKET_CARDBUS;
 #ifndef CONFIG_CARDBUS
-		pcmcia_error(skt, "cardbus cards are not supported.\n");
+		cs_err(skt, "cardbus cards are not supported.\n");
 		return CS_BAD_TYPE;
 #endif
 	}
@@ -626,7 +626,7 @@ static int socket_setup(struct pcmcia_so
 	else if (!(status & SS_XVCARD))
 		skt->socket.Vcc = skt->socket.Vpp = 50;
 	else {
-		pcmcia_error(skt, "unsupported voltage key.\n");
+		cs_err(skt, "unsupported voltage key.\n");
 		return CS_BAD_TYPE;
 	}
 	skt->socket.flags = 0;
@@ -640,7 +640,7 @@ static int socket_setup(struct pcmcia_so
 
 	skt->ops->get_status(skt, &status);
 	if (!(status & SS_POWERON)) {
-		pcmcia_error(skt, "unable to apply power.\n");
+		cs_err(skt, "unable to apply power.\n");
 		return CS_BAD_TYPE;
 	}
 
@@ -655,6 +655,8 @@ static int socket_insert(struct pcmcia_s
 {
 	int ret;
 
+	cs_dbg(skt, 4, "insert\n");
+
 	if (!cs_socket_get(skt))
 		return CS_NO_CARD;
 
@@ -667,6 +669,8 @@ static int socket_insert(struct pcmcia_s
 			skt->state |= SOCKET_CARDBUS_CONFIG;
 		}
 #endif
+		cs_dbg(skt, 4, "insert done\n");
+
 		send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
 	} else {
 		socket_shutdown(skt);
@@ -832,6 +836,7 @@ static int pccardd(void *__skt)
  */
 void pcmcia_parse_events(struct pcmcia_socket *s, u_int events)
 {
+	cs_dbg(s, 4, "parse_events: events %08x\n", events);
 	if (s->thread) {
 		spin_lock(&s->thread_lock);
 		s->thread_events |= events;
@@ -857,15 +862,15 @@ static int alloc_io_space(struct pcmcia_
     align = (*base) ? (lines ? 1<<lines : 0) : 1;
     if (align && (align < num)) {
 	if (*base) {
-	    DEBUG(0, "odd IO request: num %04x align %04x\n",
-		  num, align);
+	    cs_dbg(s, 0, "odd IO request: num %04x align %04x\n",
+		   num, align);
 	    align = 0;
 	} else
 	    while (align && (align < num)) align <<= 1;
     }
     if (*base & ~(align-1)) {
-	DEBUG(0, "odd IO request: base %04x align %04x\n",
-	      *base, align);
+	cs_dbg(s, 0, "odd IO request: base %04x align %04x\n",
+	       *base, align);
 	align = 0;
     }
     if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) {
@@ -1010,8 +1015,8 @@ int pcmcia_bind_device(bind_req_t *req)
     init_waitqueue_head(&client->mtd_req);
     client->next = s->clients;
     s->clients = client;
-    DEBUG(1, "cs: bind_device(): client 0x%p, sock %p, dev %s\n",
-	  client, client->Socket, client->dev_info);
+    cs_dbg(s, 1, "bind_device(): client 0x%p, dev %s\n",
+	   client, client->dev_info);
     return CS_SUCCESS;
 } /* bind_device */
 
@@ -1046,8 +1051,8 @@ int pcmcia_bind_mtd(mtd_bind_t *req)
 	return CS_BAD_OFFSET;
     strlcpy(region->dev_info, (char *)req->dev_info, DEV_NAME_LEN);
     
-    DEBUG(1, "cs: bind_mtd(): attr 0x%x, offset 0x%x, dev %s\n",
-	  req->Attributes, req->CardOffset, (char *)req->dev_info);
+    cs_dbg(s, 1, "bind_mtd(): attr 0x%x, offset 0x%x, dev %s\n",
+	   req->Attributes, req->CardOffset, (char *)req->dev_info);
     return CS_SUCCESS;
 } /* bind_mtd */
 
@@ -1061,9 +1066,12 @@ int pcmcia_deregister_client(client_hand
     u_long flags;
     int i;
     
-    DEBUG(1, "cs: deregister_client(%p)\n", handle);
     if (CHECK_HANDLE(handle))
 	return CS_BAD_HANDLE;
+
+    s = SOCKET(handle);
+    cs_dbg(s, 1, "deregister_client(%p)\n", handle);
+
     if (handle->state &
 	(CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))
 	return CS_IN_USE;
@@ -1072,7 +1080,6 @@ int pcmcia_deregister_client(client_hand
 	    return CS_IN_USE;
 
     /* Disconnect all MTD links */
-    s = SOCKET(handle);
     if (handle->mtd_count) {
 	for (region = s->a_region; region; region = region->info.next)
 	    if (region->mtd == handle) region->mtd = NULL;
@@ -1543,8 +1550,8 @@ int pcmcia_register_client(client_handle
 	memset(s->config, 0, sizeof(config_t) * s->functions);
     }
     
-    DEBUG(1, "cs: register_client(): client 0x%p, sock %p, dev %s\n",
-	  client, client->Socket, client->dev_info);
+    cs_dbg(s, 1, "register_client(): client 0x%p, dev %s\n",
+	   client, client->dev_info);
     if (client->EventMask & CS_EVENT_REGISTRATION_COMPLETE)
 	EVENT(client, CS_EVENT_REGISTRATION_COMPLETE, CS_EVENT_PRI_LOW);
 
@@ -2077,8 +2084,8 @@ int pcmcia_reset_card(client_handle_t ha
     
 	if (CHECK_HANDLE(handle))
 		return CS_BAD_HANDLE;
-	DEBUG(1, "cs: resetting socket %p\n", handle->Socket);
 	skt = SOCKET(handle);
+	cs_dbg(skt, 1, "resetting socket\n");
 
 	down(&skt->skt_sem);
 	do {
@@ -2126,8 +2133,8 @@ int pcmcia_suspend_card(client_handle_t 
     
 	if (CHECK_HANDLE(handle))
 		return CS_BAD_HANDLE;
-	DEBUG(1, "cs: suspending socket %p\n", handle->Socket);
 	skt = SOCKET(handle);
+	cs_dbg(skt, 1, "suspending socket\n");
 
 	down(&skt->skt_sem);
 	do {
@@ -2153,8 +2160,8 @@ int pcmcia_resume_card(client_handle_t h
     
 	if (CHECK_HANDLE(handle))
 		return CS_BAD_HANDLE;
-	DEBUG(1, "cs: waking up socket %p\n", handle->Socket);
 	skt = SOCKET(handle);
+	cs_dbg(skt, 1, "waking up socket\n");
 
 	down(&skt->skt_sem);
 	do {
@@ -2186,8 +2193,8 @@ int pcmcia_eject_card(client_handle_t ha
     
 	if (CHECK_HANDLE(handle))
 		return CS_BAD_HANDLE;
-	DEBUG(1, "cs: user eject request on socket %p\n", handle->Socket);
 	skt = SOCKET(handle);
+	cs_dbg(skt, 1, "user eject request\n");
 
 	down(&skt->skt_sem);
 	do {
@@ -2215,8 +2222,8 @@ int pcmcia_insert_card(client_handle_t h
 
 	if (CHECK_HANDLE(handle))
 		return CS_BAD_HANDLE;
-	DEBUG(1, "cs: user insert request on socket %p\n", handle->Socket);
 	skt = SOCKET(handle);
+	cs_dbg(skt, 1, "user insert request\n");
 
 	down(&skt->skt_sem);
 	do {
@@ -2360,7 +2367,6 @@ static int __init init_pcmcia_cs(void)
 {
     printk(KERN_INFO "%s\n", release);
     printk(KERN_INFO "  %s\n", options);
-    DEBUG(0, "%s\n", version);
     class_register(&pcmcia_socket_class);
 
     return 0;
--- diff/drivers/pcmcia/cs_internal.h	2003-09-30 15:46:16.000000000 +0100
+++ source/drivers/pcmcia/cs_internal.h	2004-03-09 11:51:50.000000000 +0000
@@ -167,7 +167,6 @@ int replace_cis(client_handle_t handle, 
 int read_tuple(client_handle_t handle, cisdata_t code, void *parse);
 
 /* In bulkmem.c */
-void retry_erase_list(struct erase_busy_t *list, u_int cause);
 int get_first_region(client_handle_t handle, region_info_t *rgn);
 int get_next_region(client_handle_t handle, region_info_t *rgn);
 int register_mtd(client_handle_t handle, mtd_reg_t *reg);
@@ -195,10 +194,19 @@ extern struct rw_semaphore pcmcia_socket
 extern struct list_head pcmcia_socket_list;
 
 #ifdef PCMCIA_DEBUG
-extern int pc_debug;
-#define DEBUG(n, args...) do { if (pc_debug>(n)) printk(KERN_DEBUG args); } while (0)
+extern int cs_debug_level(int);
+
+#define cs_dbg(skt, lvl, fmt, arg...) do {		\
+	if (cs_debug_level(lvl))			\
+		printk(KERN_DEBUG "cs: %s: " fmt, 	\
+		       (skt)->dev.class_id, ## arg);	\
+} while (0)
+
 #else
-#define DEBUG(n, args...) do { } while (0)
+#define cs_dbg(skt, lvl, fmt, arg...) do { } while (0)
 #endif
 
+#define cs_err(skt, fmt, arg...) \
+	printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.class_id , ## arg)
+
 #endif /* _LINUX_CS_INTERNAL_H */
--- diff/drivers/pcmcia/ds.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/pcmcia/ds.c	2004-03-09 11:51:50.000000000 +0000
@@ -33,6 +33,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
@@ -69,13 +70,17 @@ MODULE_AUTHOR("David Hinds <dahinds@user
 MODULE_DESCRIPTION("PCMCIA Driver Services");
 MODULE_LICENSE("Dual MPL/GPL");
 
-#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
+#ifdef DEBUG
+static int pc_debug;
 
-#ifdef PCMCIA_DEBUG
-INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+module_param(pc_debug, int, 0644);
+
+#define debug(lvl, fmt, arg...) do {				\
+	if (pc_debug > (lvl))					\
+		printk(KERN_DEBUG "ds: " fmt, ## arg);		\
+} while (0)
 #else
-#define DEBUG(n, args...)
+#define debug(lvl, fmt, arg...) do { } while (0)
 #endif
 
 /*====================================================================*/
@@ -277,7 +282,7 @@ static int ds_event(event_t event, int p
 {
     struct pcmcia_bus_socket *s;
 
-    DEBUG(1, "ds: ds_event(0x%06x, %d, 0x%p)\n",
+    debug(1, "ds_event(0x%06x, %d, 0x%p)\n",
 	  event, priority, args->client_handle);
     s = args->client_data;
     
@@ -353,7 +358,7 @@ static int bind_request(struct pcmcia_bu
     if (!s)
 	    return -EINVAL;
 
-    DEBUG(2, "bind_request(%d, '%s')\n", s->parent->sock,
+    debug(2, "bind_request(%d, '%s')\n", s->parent->sock,
 	  (char *)bind_info->dev_info);
     driver = get_pcmcia_driver(&bind_info->dev_info);
     if (!driver)
@@ -484,7 +489,7 @@ static int unbind_request(struct pcmcia_
 {
     socket_bind_t **b, *c;
 
-    DEBUG(2, "unbind_request(%d, '%s')\n", s->parent->sock,
+    debug(2, "unbind_request(%d, '%s')\n", s->parent->sock,
 	  (char *)bind_info->dev_info);
     for (b = &s->bind; *b; b = &(*b)->next)
 	if ((strcmp((char *)(*b)->driver->drv.name,
@@ -518,7 +523,7 @@ static int ds_open(struct inode *inode, 
     struct pcmcia_bus_socket *s;
     user_info_t *user;
 
-    DEBUG(0, "ds_open(socket %d)\n", i);
+    debug(0, "ds_open(socket %d)\n", i);
 
     s = pcmcia_get_bus_socket(i);
     if (!s)
@@ -552,7 +557,7 @@ static int ds_release(struct inode *inod
     struct pcmcia_bus_socket *s;
     user_info_t *user, **link;
 
-    DEBUG(0, "ds_release(socket %d)\n", iminor(inode));
+    debug(0, "ds_release(socket %d)\n", iminor(inode));
 
     user = file->private_data;
     if (CHECK_USER(user))
@@ -588,7 +593,7 @@ static ssize_t ds_read(struct file *file
     user_info_t *user;
     int ret;
 
-    DEBUG(2, "ds_read(socket %d)\n", iminor(inode));
+    debug(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode));
     
     if (count < 4)
 	return -EINVAL;
@@ -616,7 +621,7 @@ static ssize_t ds_write(struct file *fil
     struct pcmcia_bus_socket *s;
     user_info_t *user;
 
-    DEBUG(2, "ds_write(socket %d)\n", iminor(inode));
+    debug(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
     
     if (count != 4)
 	return -EINVAL;
@@ -650,7 +655,7 @@ static u_int ds_poll(struct file *file, 
     struct pcmcia_bus_socket *s;
     user_info_t *user;
 
-    DEBUG(2, "ds_poll(socket %d)\n", iminor(inode));
+    debug(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode));
     
     user = file->private_data;
     if (CHECK_USER(user))
@@ -677,7 +682,7 @@ static int ds_ioctl(struct inode * inode
     ds_ioctl_arg_t buf;
     user_info_t *user;
 
-    DEBUG(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
+    debug(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
     
     user = file->private_data;
     if (CHECK_USER(user))
@@ -697,14 +702,14 @@ static int ds_ioctl(struct inode * inode
     if (cmd & IOC_IN) {
 	err = verify_area(VERIFY_READ, (char *)arg, size);
 	if (err) {
-	    DEBUG(3, "ds_ioctl(): verify_read = %d\n", err);
+	    debug(3, "ds_ioctl(): verify_read = %d\n", err);
 	    return err;
 	}
     }
     if (cmd & IOC_OUT) {
 	err = verify_area(VERIFY_WRITE, (char *)arg, size);
 	if (err) {
-	    DEBUG(3, "ds_ioctl(): verify_write = %d\n", err);
+	    debug(3, "ds_ioctl(): verify_write = %d\n", err);
 	    return err;
 	}
     }
@@ -806,7 +811,7 @@ static int ds_ioctl(struct inode * inode
     }
     
     if ((err == 0) && (ret != CS_SUCCESS)) {
-	DEBUG(2, "ds_ioctl: ret = %d\n", ret);
+	debug(2, "ds_ioctl: ret = %d\n", ret);
 	switch (ret) {
 	case CS_BAD_SOCKET: case CS_NO_CARD:
 	    err = -ENODEV; break;
--- diff/drivers/pcmcia/i82365.c	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/pcmcia/i82365.c	2004-03-09 11:51:50.000000000 +0000
@@ -32,6 +32,7 @@
 ======================================================================*/
 
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/config.h>
 #include <linux/types.h>
@@ -66,14 +67,20 @@
 #include "ricoh.h"
 #include "o2micro.h"
 
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+#ifdef DEBUG
 static const char *version =
 "i82365.c 1.265 1999/11/10 18:36:21 (David Hinds)";
+
+static int pc_debug;
+
+module_param(pc_debug, int, 0644);
+
+#define debug(lvl, fmt, arg...) do {				\
+	if (pc_debug > (lvl))					\
+		printk(KERN_DEBUG "i82365: " fmt, ## arg);	\
+} while (0)
 #else
-#define DEBUG(n, args...) do { } while (0)
+#define debug(lvl, fmt, arg...) do { } while (0)
 #endif
 
 static irqreturn_t i365_count_irq(int, void *, struct pt_regs *);
@@ -496,13 +503,13 @@ static irqreturn_t i365_count_irq(int ir
 {
     i365_get(irq_sock, I365_CSC);
     irq_hits++;
-    DEBUG(2, "-> hit on irq %d\n", irq);
+    debug(2, "-> hit on irq %d\n", irq);
     return IRQ_HANDLED;
 }
 
 static u_int __init test_irq(u_short sock, int irq)
 {
-    DEBUG(2, "  testing ISA irq %d\n", irq);
+    debug(2, "  testing ISA irq %d\n", irq);
     if (request_irq(irq, i365_count_irq, 0, "scan", i365_count_irq) != 0)
 	return 1;
     irq_hits = 0; irq_sock = sock;
@@ -510,7 +517,7 @@ static u_int __init test_irq(u_short soc
     schedule_timeout(HZ/100);
     if (irq_hits) {
 	free_irq(irq, i365_count_irq);
-	DEBUG(2, "    spurious hit!\n");
+	debug(2, "    spurious hit!\n");
 	return 1;
     }
 
@@ -523,7 +530,7 @@ static u_int __init test_irq(u_short soc
 
     /* mask all interrupts */
     i365_set(sock, I365_CSCINT, 0);
-    DEBUG(2, "    hits = %d\n", irq_hits);
+    debug(2, "    hits = %d\n", irq_hits);
     
     return (irq_hits != 1);
 }
@@ -850,7 +857,7 @@ static irqreturn_t pcic_interrupt(int ir
     u_long flags = 0;
     int handled = 0;
 
-    DEBUG(4, "i82365: pcic_interrupt(%d)\n", irq);
+    debug(4, "pcic_interrupt(%d)\n", irq);
 
     for (j = 0; j < 20; j++) {
 	active = 0;
@@ -874,7 +881,7 @@ static irqreturn_t pcic_interrupt(int ir
 		events |= (csc & I365_CSC_READY) ? SS_READY : 0;
 	    }
 	    ISA_UNLOCK(i, flags);
-	    DEBUG(2, "i82365: socket %d event 0x%02x\n", i, events);
+	    debug(2, "socket %d event 0x%02x\n", i, events);
 
 	    if (events)
 		pcmcia_parse_events(&socket[i].socket, events);
@@ -886,7 +893,7 @@ static irqreturn_t pcic_interrupt(int ir
     if (j == 20)
 	printk(KERN_NOTICE "i82365: infinite loop in interrupt handler\n");
 
-    DEBUG(4, "i82365: interrupt done\n");
+    debug(4, "interrupt done\n");
     return IRQ_RETVAL(handled);
 } /* pcic_interrupt */
 
@@ -928,7 +935,7 @@ static int i365_get_status(u_short sock,
 	}
     }
     
-    DEBUG(1, "i82365: GetStatus(%d) = %#4.4x\n", sock, *value);
+    debug(1, "GetStatus(%d) = %#4.4x\n", sock, *value);
     return 0;
 } /* i365_get_status */
 
@@ -998,7 +1005,7 @@ static int i365_get_socket(u_short sock,
 	state->csc_mask |= (reg & I365_CSC_READY) ? SS_READY : 0;
     }
     
-    DEBUG(1, "i82365: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
+    debug(1, "GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
 	  "io_irq %d, csc_mask %#2.2x\n", sock, state->flags,
 	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
     return 0;
@@ -1011,7 +1018,7 @@ static int i365_set_socket(u_short sock,
     struct i82365_socket *t = &socket[sock];
     u_char reg;
     
-    DEBUG(1, "i82365: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+    debug(1, "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
 	  "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
 	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
     
@@ -1120,7 +1127,7 @@ static int i365_set_io_map(u_short sock,
 {
     u_char map, ioctl;
     
-    DEBUG(1, "i82365: SetIOMap(%d, %d, %#2.2x, %d ns, "
+    debug(1, "SetIOMap(%d, %d, %#2.2x, %d ns, "
 	  "%#4.4x-%#4.4x)\n", sock, io->map, io->flags,
 	  io->speed, io->start, io->stop);
     map = io->map;
@@ -1150,7 +1157,7 @@ static int i365_set_mem_map(u_short sock
     u_short base, i;
     u_char map;
     
-    DEBUG(1, "i82365: SetMemMap(%d, %d, %#2.2x, %d ns, %#5.5lx-%#5.5"
+    debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, %#5.5lx-%#5.5"
 	  "lx, %#5.5x)\n", sock, mem->map, mem->flags, mem->speed,
 	  mem->sys_start, mem->sys_stop, mem->card_start);
 
--- diff/drivers/pcmcia/sa11xx_core.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/pcmcia/sa11xx_core.c	2004-03-09 11:51:50.000000000 +0000
@@ -35,6 +35,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/config.h>
 #include <linux/cpufreq.h>
@@ -54,8 +55,19 @@
 #include "sa11xx_core.h"
 #include "sa1100.h"
 
-#ifdef PCMCIA_DEBUG
+#ifdef DEBUG
 static int pc_debug;
+
+module_param(pc_debug, int, 0644);
+
+#define debug(skt, lvl, fmt, arg...) do {			\
+	if (pc_debug > (lvl))					\
+		printk(KERN_DEBUG "skt%u: %s: " fmt,		\
+		       (skt)->nr, __func__, ## arg);		\
+} while (0)
+
+#else
+#define debug(skt, lvl, fmt, arg...) do { } while (0)
 #endif
 
 #define to_sa1100_socket(x)	container_of(x, struct sa1100_pcmcia_socket, socket)
@@ -133,8 +145,8 @@ sa1100_pcmcia_set_mecr(struct sa1100_pcm
 
 	local_irq_restore(flags);
 
-	DEBUG(4, "%s(): sock %u FAST %X  BSM %X  BSA %X  BSIO %X\n",
-	      __FUNCTION__, skt->nr, MECR_FAST_GET(mecr, skt->nr),
+	debug(skt, 4, "FAST %X  BSM %X  BSA %X  BSIO %X\n",
+	      MECR_FAST_GET(mecr, skt->nr),
 	      MECR_BSM_GET(mecr, skt->nr), MECR_BSA_GET(mecr, skt->nr),
 	      MECR_BSIO_GET(mecr, skt->nr));
 
@@ -221,7 +233,7 @@ static int sa1100_pcmcia_sock_init(struc
 {
 	struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock);
 
-	DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, skt->nr);
+	debug(skt, 2, "initializing socket\n");
 
 	skt->ops->socket_init(skt);
 	return 0;
@@ -242,7 +254,7 @@ static int sa1100_pcmcia_suspend(struct 
 	struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock);
 	int ret;
 
-	DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, skt->nr);
+	debug(skt, 2, "suspending socket\n");
 
 	ret = sa1100_pcmcia_config_skt(skt, &dead_socket);
 	if (ret == 0)
@@ -260,7 +272,7 @@ static void sa1100_check_status(struct s
 {
 	unsigned int events;
 
-	DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__);
+	debug(skt, 4, "entering PCMCIA monitoring thread\n");
 
 	do {
 		unsigned int status;
@@ -273,7 +285,7 @@ static void sa1100_check_status(struct s
 		skt->status = status;
 		spin_unlock_irqrestore(&status_lock, flags);
 
-		DEBUG(2, "events: %s%s%s%s%s%s\n",
+		debug(skt, 4, "events: %s%s%s%s%s%s\n",
 			events == 0         ? "<NONE>"   : "",
 			events & SS_DETECT  ? "DETECT "  : "",
 			events & SS_READY   ? "READY "   : "",
@@ -293,7 +305,7 @@ static void sa1100_check_status(struct s
 static void sa1100_pcmcia_poll_event(unsigned long dummy)
 {
 	struct sa1100_pcmcia_socket *skt = (struct sa1100_pcmcia_socket *)dummy;
-	DEBUG(4, "%s(): polling for events\n", __FUNCTION__);
+	debug(skt, 4, "polling for events\n");
 
 	mod_timer(&skt->poll_timer, jiffies + SA1100_PCMCIA_POLL_PERIOD);
 
@@ -314,7 +326,7 @@ static irqreturn_t sa1100_pcmcia_interru
 {
 	struct sa1100_pcmcia_socket *skt = dev;
 
-	DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq);
+	debug(skt, 3, "servicing IRQ %d\n", irq);
 
 	sa1100_check_status(skt);
 
@@ -363,7 +375,7 @@ sa1100_pcmcia_get_socket(struct pcmcia_s
 {
   struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock);
 
-  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr);
+  debug(skt, 2, "\n");
 
   *state = skt->cs_state;
 
@@ -385,22 +397,19 @@ sa1100_pcmcia_set_socket(struct pcmcia_s
 {
   struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock);
 
-  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr);
-
-  DEBUG(3, "\tmask:  %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n",
-	(state->csc_mask==0)?"<NONE>":"",
+  debug(skt, 2, "mask: %s%s%s%s%s%sflags: %s%s%s%s%s%sVcc %d Vpp %d irq %d\n",
+	(state->csc_mask==0)?"<NONE> ":"",
 	(state->csc_mask&SS_DETECT)?"DETECT ":"",
 	(state->csc_mask&SS_READY)?"READY ":"",
 	(state->csc_mask&SS_BATDEAD)?"BATDEAD ":"",
 	(state->csc_mask&SS_BATWARN)?"BATWARN ":"",
 	(state->csc_mask&SS_STSCHG)?"STSCHG ":"",
-	(state->flags==0)?"<NONE>":"",
+	(state->flags==0)?"<NONE> ":"",
 	(state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"",
 	(state->flags&SS_IOCARD)?"IOCARD ":"",
 	(state->flags&SS_RESET)?"RESET ":"",
 	(state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"",
-	(state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"");
-  DEBUG(3, "\tVcc %d  Vpp %d  irq %d\n",
+	(state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"",
 	state->Vcc, state->Vpp, state->io_irq);
 
   return sa1100_pcmcia_config_skt(skt, state);
@@ -422,11 +431,9 @@ sa1100_pcmcia_set_io_map(struct pcmcia_s
 	struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock);
 	unsigned short speed = map->speed;
 
-	DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr);
-
-	DEBUG(3, "\tmap %u  speed %u\n\tstart 0x%08x  stop 0x%08x\n",
+	debug(skt, 2, "map %u  speed %u start 0x%08x stop 0x%08x\n",
 		map->map, map->speed, map->start, map->stop);
-	DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n",
+	debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n",
 		(map->flags==0)?"<NONE>":"",
 		(map->flags&MAP_ACTIVE)?"ACTIVE ":"",
 		(map->flags&MAP_16BIT)?"16BIT ":"",
@@ -479,11 +486,9 @@ sa1100_pcmcia_set_mem_map(struct pcmcia_
 	struct resource *res;
 	unsigned short speed = map->speed;
 
-	DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr);
-
-	DEBUG(3, "\tmap %u speed %u card_start %08x\n",
+	debug(skt, 2, "map %u speed %u card_start %08x\n",
 		map->map, map->speed, map->card_start);
-	DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n",
+	debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n",
 		(map->flags==0)?"<NONE>":"",
 		(map->flags&MAP_ACTIVE)?"ACTIVE ":"",
 		(map->flags&MAP_16BIT)?"16BIT ":"",
@@ -920,23 +925,13 @@ sa1100_pcmcia_notifier(struct notifier_b
 
 	switch (val) {
 	case CPUFREQ_PRECHANGE:
-		if (freqs->new > freqs->old) {
-			DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, "
-				"pre-updating\n", __FUNCTION__,
-			    freqs->new / 1000, (freqs->new / 100) % 10,
-			    freqs->old / 1000, (freqs->old / 100) % 10);
+		if (freqs->new > freqs->old)
 			sa1100_pcmcia_update_mecr(freqs->new);
-		}
 		break;
 
 	case CPUFREQ_POSTCHANGE:
-		if (freqs->new < freqs->old) {
-			DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, "
-				"post-updating\n", __FUNCTION__,
-			    freqs->new / 1000, (freqs->new / 100) % 10,
-			    freqs->old / 1000, (freqs->old / 100) % 10);
+		if (freqs->new < freqs->old)
 			sa1100_pcmcia_update_mecr(freqs->new);
-		}
 		break;
 	}
 
--- diff/drivers/pcmcia/tcic.c	2003-10-27 09:20:38.000000000 +0000
+++ source/drivers/pcmcia/tcic.c	2004-03-09 11:51:50.000000000 +0000
@@ -32,6 +32,7 @@
 ======================================================================*/
 
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
@@ -55,14 +56,20 @@
 #include <pcmcia/ss.h>
 #include "tcic.h"
 
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
+#ifdef DEBUG
+static int pc_debug;
+
+module_param(pc_debug, int, 0644);
 MODULE_PARM(pc_debug, "i");
 static const char *version =
 "tcic.c 1.111 2000/02/15 04:13:12 (David Hinds)";
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+
+#define debug(lvl, fmt, arg...) do {				\
+	if (pc_debug > (lvl))					\
+		printk(KERN_DEBUG "tcic: " fmt, ## arg);	\
+} while (0)
 #else
-#define DEBUG(n, args...)
+#define debug(lvl, fmt, arg...) do { } while (0)
 #endif
 
 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
@@ -133,7 +140,7 @@ static struct tcic_socket socket_table[2
    to map to irq 11, but is coded as 0 or 1 in the irq registers. */
 #define TCIC_IRQ(x) ((x) ? (((x) == 11) ? 1 : (x)) : 15)
 
-#ifdef PCMCIA_DEBUG_X
+#ifdef DEBUG_X
 static u_char tcic_getb(u_char reg)
 {
     u_char val = inb(tcic_base+reg);
@@ -168,7 +175,7 @@ static void tcic_setw(u_char reg, u_shor
 
 static void tcic_setl(u_char reg, u_int data)
 {
-#ifdef PCMCIA_DEBUG_X
+#ifdef DEBUG_X
     printk(KERN_DEBUG "tcic_setl(%#x, %#lx)\n", tcic_base+reg, data);
 #endif
     outw(data & 0xffff, tcic_base+reg);
@@ -573,7 +580,7 @@ static irqreturn_t tcic_interrupt(int ir
     } else
 	active = 1;
 
-    DEBUG(2, "tcic: tcic_interrupt()\n");
+    debug(2, "tcic_interrupt()\n");
     
     for (i = 0; i < sockets; i++) {
 	psock = socket_table[i].psock;
@@ -610,13 +617,13 @@ static irqreturn_t tcic_interrupt(int ir
     }
     active = 0;
     
-    DEBUG(2, "tcic: interrupt done\n");
+    debug(2, "interrupt done\n");
     return IRQ_HANDLED;
 } /* tcic_interrupt */
 
 static void tcic_timer(u_long data)
 {
-    DEBUG(2, "tcic: tcic_timer()\n");
+    debug(2, "tcic_timer()\n");
     tcic_timer_pending = 0;
     tcic_interrupt(0, NULL, NULL);
 } /* tcic_timer */
@@ -643,7 +650,7 @@ static int tcic_get_status(struct pcmcia
     reg = tcic_getb(TCIC_PWR);
     if (reg & (TCIC_PWR_VCC(psock)|TCIC_PWR_VPP(psock)))
 	*value |= SS_POWERON;
-    DEBUG(1, "tcic: GetStatus(%d) = %#2.2x\n", psock, *value);
+    debug(1, "GetStatus(%d) = %#2.2x\n", psock, *value);
     return 0;
 } /* tcic_get_status */
   
@@ -694,7 +701,7 @@ static int tcic_get_socket(struct pcmcia
 	state->csc_mask |= (scf2 & TCIC_SCF2_MRDY) ? 0 : SS_READY;
     }
 
-    DEBUG(1, "tcic: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
+    debug(1, "GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
 	  "io_irq %d, csc_mask %#2.2x\n", psock, state->flags,
 	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
     return 0;
@@ -708,7 +715,7 @@ static int tcic_set_socket(struct pcmcia
     u_char reg;
     u_short scf1, scf2;
 
-    DEBUG(1, "tcic: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+    debug(1, "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
 	  "io_irq %d, csc_mask %#2.2x)\n", psock, state->flags,
 	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
     tcic_setw(TCIC_ADDR+2, (psock << TCIC_SS_SHFT) | TCIC_ADR2_INDREG);
@@ -783,7 +790,7 @@ static int tcic_set_io_map(struct pcmcia
     u_int addr;
     u_short base, len, ioctl;
     
-    DEBUG(1, "tcic: SetIOMap(%d, %d, %#2.2x, %d ns, "
+    debug(1, "SetIOMap(%d, %d, %#2.2x, %d ns, "
 	  "%#4.4x-%#4.4x)\n", psock, io->map, io->flags,
 	  io->speed, io->start, io->stop);
     if ((io->map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
@@ -820,7 +827,7 @@ static int tcic_set_mem_map(struct pcmci
     u_short addr, ctl;
     u_long base, len, mmap;
 
-    DEBUG(1, "tcic: SetMemMap(%d, %d, %#2.2x, %d ns, "
+    debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, "
 	  "%#5.5lx-%#5.5lx, %#5.5x)\n", psock, mem->map, mem->flags,
 	  mem->speed, mem->sys_start, mem->sys_stop, mem->card_start);
     if ((mem->map > 3) || (mem->card_start > 0x3ffffff) ||
--- diff/drivers/pcmcia/yenta_socket.c	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/pcmcia/yenta_socket.c	2004-03-09 11:51:50.000000000 +0000
@@ -30,9 +30,9 @@
 
 
 #if 0
-#define DEBUG(x,args...)	printk(KERN_DEBUG "%s: " x, __FUNCTION__, ##args)
+#define debug(x,args...) printk(KERN_DEBUG "%s: " x, __FUNCTION__, ##args)
 #else
-#define DEBUG(x,args...)
+#define debug(x,args...)
 #endif
 
 /* Don't ask.. */
@@ -47,13 +47,13 @@
 static inline u32 cb_readl(struct yenta_socket *socket, unsigned reg)
 {
 	u32 val = readl(socket->base + reg);
-	DEBUG("%p %04x %08x\n", socket, reg, val);
+	debug("%p %04x %08x\n", socket, reg, val);
 	return val;
 }
 
 static inline void cb_writel(struct yenta_socket *socket, unsigned reg, u32 val)
 {
-	DEBUG("%p %04x %08x\n", socket, reg, val);
+	debug("%p %04x %08x\n", socket, reg, val);
 	writel(val, socket->base + reg);
 }
 
@@ -61,7 +61,7 @@ static inline u8 config_readb(struct yen
 {
 	u8 val;
 	pci_read_config_byte(socket->dev, offset, &val);
-	DEBUG("%p %04x %02x\n", socket, offset, val);
+	debug("%p %04x %02x\n", socket, offset, val);
 	return val;
 }
 
@@ -69,7 +69,7 @@ static inline u16 config_readw(struct ye
 {
 	u16 val;
 	pci_read_config_word(socket->dev, offset, &val);
-	DEBUG("%p %04x %04x\n", socket, offset, val);
+	debug("%p %04x %04x\n", socket, offset, val);
 	return val;
 }
 
@@ -77,32 +77,32 @@ static inline u32 config_readl(struct ye
 {
 	u32 val;
 	pci_read_config_dword(socket->dev, offset, &val);
-	DEBUG("%p %04x %08x\n", socket, offset, val);
+	debug("%p %04x %08x\n", socket, offset, val);
 	return val;
 }
 
 static inline void config_writeb(struct yenta_socket *socket, unsigned offset, u8 val)
 {
-	DEBUG("%p %04x %02x\n", socket, offset, val);
+	debug("%p %04x %02x\n", socket, offset, val);
 	pci_write_config_byte(socket->dev, offset, val);
 }
 
 static inline void config_writew(struct yenta_socket *socket, unsigned offset, u16 val)
 {
-	DEBUG("%p %04x %04x\n", socket, offset, val);
+	debug("%p %04x %04x\n", socket, offset, val);
 	pci_write_config_word(socket->dev, offset, val);
 }
 
 static inline void config_writel(struct yenta_socket *socket, unsigned offset, u32 val)
 {
-	DEBUG("%p %04x %08x\n", socket, offset, val);
+	debug("%p %04x %08x\n", socket, offset, val);
 	pci_write_config_dword(socket->dev, offset, val);
 }
 
 static inline u8 exca_readb(struct yenta_socket *socket, unsigned reg)
 {
 	u8 val = readb(socket->base + 0x800 + reg);
-	DEBUG("%p %04x %02x\n", socket, reg, val);
+	debug("%p %04x %02x\n", socket, reg, val);
 	return val;
 }
 
@@ -111,19 +111,19 @@ static inline u8 exca_readw(struct yenta
 	u16 val;
 	val = readb(socket->base + 0x800 + reg);
 	val |= readb(socket->base + 0x800 + reg + 1) << 8;
-	DEBUG("%p %04x %04x\n", socket, reg, val);
+	debug("%p %04x %04x\n", socket, reg, val);
 	return val;
 }
 
 static inline void exca_writeb(struct yenta_socket *socket, unsigned reg, u8 val)
 {
-	DEBUG("%p %04x %02x\n", socket, reg, val);
+	debug("%p %04x %02x\n", socket, reg, val);
 	writeb(val, socket->base + 0x800 + reg);
 }
 
 static void exca_writew(struct yenta_socket *socket, unsigned reg, u16 val)
 {
-	DEBUG("%p %04x %04x\n", socket, reg, val);
+	debug("%p %04x %04x\n", socket, reg, val);
 	writeb(val, socket->base + 0x800 + reg);
 	writeb(val >> 8, socket->base + 0x800 + reg + 1);
 }
--- diff/drivers/sbus/char/vfc_dev.c	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/sbus/char/vfc_dev.c	2004-03-09 11:51:50.000000000 +0000
@@ -24,6 +24,7 @@
 #include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
+#include <linux/mm.h>
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
--- diff/drivers/scsi/53c700.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/scsi/53c700.c	2004-03-09 11:51:50.000000000 +0000
@@ -321,7 +321,7 @@ NCR_700_detect(Scsi_Host_Template *tpnt,
 
 	hostdata->script = script;
 	hostdata->pScript = pScript;
-	dma_sync_single(hostdata->dev, pScript, sizeof(SCRIPT), DMA_TO_DEVICE);
+	dma_sync_single_for_device(hostdata->dev, pScript, sizeof(SCRIPT), DMA_TO_DEVICE);
 	hostdata->state = NCR_700_HOST_FREE;
 	hostdata->cmd = NULL;
 	host->max_id = 7;
@@ -982,8 +982,8 @@ process_script_interrupt(__u32 dsps, __u
 				SCp->cmnd[7] = hostdata->status[0];
 				SCp->use_sg = 0;
 				SCp->sc_data_direction = SCSI_DATA_READ;
-				dma_sync_single(hostdata->dev, slot->pCmd,
-						SCp->cmd_len, DMA_TO_DEVICE);
+				dma_sync_single_for_device(hostdata->dev, slot->pCmd,
+							   SCp->cmd_len, DMA_TO_DEVICE);
 				SCp->request_bufflen = sizeof(SCp->sense_buffer);
 				slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
 				slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer));
@@ -1007,7 +1007,7 @@ process_script_interrupt(__u32 dsps, __u
 			//   SCp->cmnd[0] == INQUIRY && SCp->use_sg == 0) {
 			//	/* Piggy back the tag queueing support
 			//	 * on this command */
-			//	dma_sync_single(hostdata->dev,
+			//	dma_sync_single_for_cpu(hostdata->dev,
 			//			    slot->dma_handle,
 			//			    SCp->request_bufflen,
 			//			    DMA_FROM_DEVICE);
--- diff/drivers/scsi/Kconfig	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/scsi/Kconfig	2004-03-09 11:51:50.000000000 +0000
@@ -196,6 +196,25 @@ config SCSI_LOGGING
 	  there should be no noticeable performance impact as long as you have
 	  logging turned off.
 
+menu "SCSI Transport Attributes"
+	depends on SCSI
+
+config SCSI_SPI_ATTRS
+	tristate "Parallel SCSI (SPI) Transport Attributes"
+	depends on SCSI
+	help
+	  If you wish to export transport-specific information about
+	  each attached SCSI device to sysfs, say Y.  Otherwise, say N.
+
+config SCSI_FC_ATTRS
+	tristate "FiberChannel Transport Attributes"
+	depends on SCSI
+	help
+	  If you wish to export transport-specific information about
+	  each attached FiberChannel device to sysfs, say Y.
+	  Otherwise, say N.
+
+endmenu
 
 menu "SCSI low-level drivers"
 	depends on SCSI!=n
--- diff/drivers/scsi/Makefile	2004-02-18 08:54:11.000000000 +0000
+++ source/drivers/scsi/Makefile	2004-03-09 11:51:50.000000000 +0000
@@ -22,6 +22,14 @@ subdir-$(CONFIG_PCMCIA)		+= pcmcia
 
 obj-$(CONFIG_SCSI)		+= scsi_mod.o
 
+# --- NOTE ORDERING HERE ---
+# For kernel non-modular link, transport attributes need to
+# be initialised before drivers
+# --------------------------
+obj-$(CONFIG_SCSI_SPI_ATTRS)	+= scsi_transport_spi.o
+obj-$(CONFIG_SCSI_FC_ATTRS) 	+= scsi_transport_fc.o
+
+
 obj-$(CONFIG_SCSI_AMIGA7XX)	+= amiga7xx.o	53c7xx.o
 obj-$(CONFIG_A3000_SCSI)	+= a3000.o	wd33c93.o
 obj-$(CONFIG_A2091_SCSI)	+= a2091.o	wd33c93.o
@@ -130,7 +138,7 @@ scsi_mod-y			+= scsi.o hosts.o scsi_ioct
 scsi_mod-$(CONFIG_SYSCTL)	+= scsi_sysctl.o
 scsi_mod-$(CONFIG_SCSI_PROC_FS)	+= scsi_proc.o
 scsi_mod-$(CONFIG_X86_PC9800)	+= scsi_pc98.o
-			
+
 sd_mod-objs	:= sd.o
 sr_mod-objs	:= sr.o sr_ioctl.o sr_vendor.o
 initio-objs	:= ini9100u.o i91uscsi.o
--- diff/drivers/scsi/aic7xxx/aic7xxx_osm.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/scsi/aic7xxx/aic7xxx_osm.c	2004-03-09 11:51:50.000000000 +0000
@@ -3969,11 +3969,10 @@ ahc_linux_alloc_device(struct ahc_softc 
 }
 
 static void
-ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
+__ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
 {
 	struct ahc_linux_target *targ;
 
-	del_timer_sync(&dev->timer);
 	targ = dev->target;
 	targ->devices[dev->lun] = NULL;
 	free(dev, M_DEVBUF);
@@ -3983,6 +3982,13 @@ ahc_linux_free_device(struct ahc_softc *
 		ahc_linux_free_target(ahc, targ);
 }
 
+static void
+ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
+{
+	del_timer_sync(&dev->timer);
+	__ahc_linux_free_device(ahc, dev);
+}
+
 void
 ahc_send_async(struct ahc_softc *ahc, char channel,
 	       u_int target, u_int lun, ac_code code, void *arg)
@@ -4693,7 +4699,7 @@ ahc_linux_dev_timed_unfreeze(u_long arg)
 		ahc_linux_run_device_queue(ahc, dev);
 	if (TAILQ_EMPTY(&dev->busyq)
 	 && dev->active == 0)
-		ahc_linux_free_device(ahc, dev);
+		__ahc_linux_free_device(ahc, dev);
 	ahc_unlock(ahc, &s);
 }
 
--- diff/drivers/scsi/cpqfcTSinit.c	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/scsi/cpqfcTSinit.c	2004-03-09 11:51:50.000000000 +0000
@@ -46,10 +46,6 @@
 #include <linux/ioport.h>  // request_region() prototype
 #include <linux/completion.h>
 
-#ifdef __alpha__
-#define __KERNEL_SYSCALLS__
-#endif
-#include <asm/unistd.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>   // ioctl related
 #include <asm/irq.h>
--- diff/drivers/scsi/dc395x.c	2003-09-17 12:28:09.000000000 +0100
+++ source/drivers/scsi/dc395x.c	2004-03-09 11:51:50.000000000 +0000
@@ -2419,13 +2419,13 @@ static void update_sg_list(struct ScsiRe
 				psge->length -= xferred;	/* residue data length  */
 				psge->address += xferred;	/* residue data pointer */
 				srb->sg_index = idx;
-				pci_dma_sync_single(srb->dcb->
-						    acb->dev,
-						    srb->sg_bus_addr,
-						    sizeof(struct SGentry)
-						    *
-						    DC395x_MAX_SG_LISTENTRY,
-						    PCI_DMA_TODEVICE);
+				pci_dma_sync_single_for_device(srb->dcb->
+							       acb->dev,
+							       srb->sg_bus_addr,
+							       sizeof(struct SGentry)
+							       *
+							       DC395x_MAX_SG_LISTENTRY,
+							       PCI_DMA_TODEVICE);
 				break;
 			}
 			psge++;
@@ -4298,11 +4298,11 @@ void srb_done(struct AdapterCtlBlk *acb,
 
 	if (dir != PCI_DMA_NONE) {
 		if (cmd->use_sg)
-			pci_dma_sync_sg(acb->dev,
+			pci_dma_sync_sg_for_cpu(acb->dev,
 					(struct scatterlist *) cmd->
 					request_buffer, cmd->use_sg, dir);
 		else if (cmd->request_buffer)
-			pci_dma_sync_single(acb->dev,
+			pci_dma_sync_single_for_cpu(acb->dev,
 					    srb->segment_x[0].address,
 					    cmd->request_bufflen, dir);
 	}
--- diff/drivers/scsi/eata.c	2003-08-20 14:16:12.000000000 +0100
+++ source/drivers/scsi/eata.c	2004-03-09 11:51:50.000000000 +0000
@@ -1598,17 +1598,17 @@ static void sync_dma(unsigned int i, uns
    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),
+      pci_dma_sync_single_for_cpu(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,
+      pci_dma_sync_sg_for_cpu(HD(j)->pdev, SCpnt->request_buffer,
                          SCpnt->use_sg, pci_dir);
 
    if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL;
 
    if (DEV2H(cpp->data_address))
-      pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address),
+      pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->data_address),
                        DEV2H(cpp->data_len), pci_dir);
 }
 
--- diff/drivers/scsi/hosts.c	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/scsi/hosts.c	2004-03-09 11:51:50.000000000 +0000
@@ -32,6 +32,7 @@
 #include <linux/unistd.h>
 
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
 #include "scsi.h"
 
 #include "scsi_priv.h"
@@ -222,6 +223,11 @@ struct Scsi_Host *scsi_host_alloc(struct
 	shost->max_id = 8;
 	shost->max_lun = 8;
 
+	/* Give each shost a default transportt if the driver
+	 * doesn't yet support Transport Attributes */
+	if (!shost->transportt) 
+		shost->transportt = &blank_transport_template;
+
 	/*
 	 * All drivers right now should be able to handle 12 byte
 	 * commands.  Every so often there are requests for 16 byte
--- diff/drivers/scsi/ide-scsi.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/scsi/ide-scsi.c	2004-03-09 11:51:50.000000000 +0000
@@ -78,6 +78,7 @@ typedef struct idescsi_pc_s {
 #define PC_DMA_IN_PROGRESS		0	/* 1 while DMA in progress */
 #define PC_WRITING			1	/* Data direction */
 #define PC_TRANSFORM			2	/* transform SCSI commands */
+#define PC_TIMEDOUT			3	/* command timed out */
 #define PC_DMA_OK			4	/* Use DMA */
 
 /*
@@ -307,6 +308,41 @@ static int idescsi_check_condition(ide_d
 	return ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
+ide_startstop_t idescsi_atapi_error (ide_drive_t *drive, const char *msg, byte stat)
+{
+	struct request *rq;
+	byte err;
+
+	err = ide_dump_atapi_status(drive, msg, stat);
+
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+
+	if (HWIF(drive)->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
+		/* force an abort */
+		HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
+
+	rq->errors++;
+	DRIVER(drive)->end_request(drive, 0, 0);
+	return ide_stopped;
+}
+
+ide_startstop_t idescsi_atapi_abort (ide_drive_t *drive, const char *msg)
+{
+	struct request *rq;
+
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+	       return ide_stopped;
+
+#if IDESCSI_DEBUG_LOG
+	printk(KERN_WARNING "idescsi_atapi_abort called for %lu\n",
+			((idescsi_pc_t *) rq->special)->scsi_cmd->serial_number);
+#endif
+	rq->errors |= ERROR_MAX;
+	DRIVER(drive)->end_request(drive, 0, 0);
+	return ide_stopped;
+}
+
 static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs)
 {
 	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
@@ -334,7 +370,13 @@ static int idescsi_end_request (ide_driv
 		kfree(rq);
 		pc = opc;
 		rq = pc->rq;
-		pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);
+		pc->scsi_cmd->result = (CHECK_CONDITION << 1) |
+					((test_bit(PC_TIMEDOUT, &pc->flags)?DID_TIME_OUT:DID_OK) << 16);
+	} else if (test_bit(PC_TIMEDOUT, &pc->flags)) {
+		if (log)
+			printk (KERN_WARNING "ide-scsi: %s: timed out for %lu\n",
+					drive->name, pc->scsi_cmd->serial_number);
+		pc->scsi_cmd->result = DID_TIME_OUT << 16;
 	} else if (rq->errors >= ERROR_MAX) {
 		pc->scsi_cmd->result = DID_ERROR << 16;
 		if (log)
@@ -374,6 +416,19 @@ static inline unsigned long get_timeout(
 	return IDE_MAX(WAIT_CMD, pc->timeout - jiffies);
 }
 
+static int idescsi_expiry(ide_drive_t *drive)
+{
+	idescsi_scsi_t *scsi = drive->driver_data;
+	idescsi_pc_t   *pc   = scsi->pc;
+
+#if IDESCSI_DEBUG_LOG
+	printk(KERN_WARNING "idescsi_expiry called for %lu at %lu\n", pc->scsi_cmd->serial_number, jiffies);
+#endif
+	set_bit(PC_TIMEDOUT, &pc->flags);
+
+	return 0;					/* we do not want the ide subsystem to retry */
+}
+
 /*
  *	Our interrupt handler.
  */
@@ -393,6 +448,15 @@ static ide_startstop_t idescsi_pc_intr (
 	printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n");
 #endif /* IDESCSI_DEBUG_LOG */
 
+	if (test_bit(PC_TIMEDOUT, &pc->flags)){
+#if IDESCSI_DEBUG_LOG
+		printk(KERN_WARNING "idescsi_pc_intr: got timed out packet  %lu at %lu\n",
+				pc->scsi_cmd->serial_number, jiffies);
+#endif
+		/* end this request now - scsi should retry it*/
+		idescsi_end_request (drive, 1, 0);
+		return ide_stopped;
+	}
 	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
 #if IDESCSI_DEBUG_LOG
 		printk ("ide-scsi: %s: DMA complete\n", drive->name);
@@ -442,7 +506,7 @@ static ide_startstop_t idescsi_pc_intr (
 				pc->actually_transferred += temp;
 				pc->current_position += temp;
 				idescsi_discard_data(drive, bcount.all - temp);
-				ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);
+				ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);
 				return ide_started;
 			}
 #if IDESCSI_DEBUG_LOG
@@ -467,7 +531,8 @@ static ide_startstop_t idescsi_pc_intr (
 	pc->actually_transferred += bcount.all;
 	pc->current_position += bcount.all;
 
-	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);	/* And set the interrupt handler again */
+	/* And set the interrupt handler again */
+	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);
 	return ide_started;
 }
 
@@ -492,7 +557,7 @@ static ide_startstop_t idescsi_transfer_
 	if (HWGROUP(drive)->handler != NULL)
 		BUG();
 	/* Set the interrupt routine */
-	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);
+	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);
 	/* Send the actual packet */
 	atapi_output_bytes(drive, scsi->pc->c, 12);
 	if (test_bit (PC_DMA_OK, &pc->flags)) {
@@ -540,7 +605,7 @@ static ide_startstop_t idescsi_issue_pc 
 		if (HWGROUP(drive)->handler != NULL)
 			BUG();
 		ide_set_handler(drive, &idescsi_transfer_pc,
-				get_timeout(pc), NULL);
+				get_timeout(pc), idescsi_expiry);
 		/* Issue the packet command */
 		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return ide_started;
@@ -633,6 +698,8 @@ static ide_driver_t idescsi_driver = {
 	.cleanup		= idescsi_cleanup,
 	.do_request		= idescsi_do_request,
 	.end_request		= idescsi_end_request,
+	.error                  = idescsi_atapi_error,
+	.abort                  = idescsi_atapi_abort,
 	.drives			= LIST_HEAD_INIT(idescsi_driver.drives),
 };
 
@@ -852,66 +919,132 @@ abort:
 	return 1;
 }
 
-static int idescsi_abort (Scsi_Cmnd *cmd)
+static int idescsi_eh_abort (Scsi_Cmnd *cmd)
 {
-	int countdown = 8;
-	unsigned long flags;
-	idescsi_scsi_t *scsi = scsihost_to_idescsi(cmd->device->host);
-	ide_drive_t *drive = scsi->drive;
+	idescsi_scsi_t *scsi  = scsihost_to_idescsi(cmd->device->host);
+	ide_drive_t    *drive = scsi->drive;
+	int		busy;
+	int             ret   = FAILED;
 
-	printk (KERN_ERR "ide-scsi: abort called for %lu\n", cmd->serial_number);
-	while (countdown--) {
-		/* is cmd active?
-		 *  need to lock so this stuff doesn't change under us */
-		spin_lock_irqsave(&ide_lock, flags);
-		if (scsi->pc && scsi->pc->scsi_cmd && 
-				scsi->pc->scsi_cmd->serial_number == cmd->serial_number) {
-			/* yep - let's give it some more time - 
-			 * we can do that, we're in _our_ error kernel thread */
-			spin_unlock_irqrestore(&ide_lock, flags);
-			scsi_sleep(HZ);
-			continue;
-		}
-		/* no, but is it queued in the ide subsystem? */
-		if (elv_queue_empty(drive->queue)) {
-			spin_unlock_irqrestore(&ide_lock, flags);
-			return SUCCESS;
-		}
-		spin_unlock_irqrestore(&ide_lock, flags);
-		schedule_timeout(HZ/10);
+	/* In idescsi_eh_abort we try to gently pry our command from the ide subsystem */
+
+	if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
+		printk (KERN_WARNING "ide-scsi: abort called for %lu\n", cmd->serial_number);
+
+	if (!drive) {
+		printk (KERN_WARNING "ide-scsi: Drive not set in idescsi_eh_abort\n");
+		WARN_ON(1);
+		goto no_drive;
+	}
+
+	/* First give it some more time, how much is "right" is hard to say :-( */
+
+	busy = ide_wait_not_busy(HWIF(drive), 100);	/* FIXME - uses mdelay which causes latency? */
+	if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
+		printk (KERN_WARNING "ide-scsi: drive did%s become ready\n", busy?" not":"");
+
+	spin_lock_irq(&ide_lock);
+
+	/* If there is no pc running we're done (our interrupt took care of it) */
+	if (!scsi->pc) {
+		ret = SUCCESS;
+		goto ide_unlock;
+	}
+
+	/* It's somewhere in flight. Does ide subsystem agree? */
+	if (scsi->pc->scsi_cmd->serial_number == cmd->serial_number && !busy &&
+	    elv_queue_empty(drive->queue) && HWGROUP(drive)->rq != scsi->pc->rq) {
+		/*
+		 * FIXME - not sure this condition can ever occur
+		 */
+		printk (KERN_ERR "ide-scsi: cmd aborted!\n");
+
+		idescsi_free_bio(scsi->pc->rq->bio);
+		if (scsi->pc->rq->flags & REQ_SENSE)
+			kfree(scsi->pc->buffer);
+		kfree(scsi->pc->rq);
+		kfree(scsi->pc);
+		scsi->pc = NULL;
+
+		ret = SUCCESS;
 	}
-	return FAILED;
+
+ide_unlock:
+	spin_unlock_irq(&ide_lock);
+no_drive:
+	if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
+		printk (KERN_WARNING "ide-scsi: abort returns %s\n", ret == SUCCESS?"success":"failed");
+
+	return ret;
 }
 
-static int idescsi_reset (Scsi_Cmnd *cmd)
+static int idescsi_eh_reset (Scsi_Cmnd *cmd)
 {
-	unsigned long flags;
 	struct request *req;
-	idescsi_scsi_t *idescsi = scsihost_to_idescsi(cmd->device->host);
-	ide_drive_t *drive = idescsi->drive;
+	idescsi_scsi_t *scsi  = scsihost_to_idescsi(cmd->device->host);
+	ide_drive_t    *drive = scsi->drive;
+	int             ready = 0;
+	int             ret   = SUCCESS;
+
+	/* In idescsi_eh_reset we forcefully remove the command from the ide subsystem and reset the device. */
+
+	if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
+		printk (KERN_WARNING "ide-scsi: reset called for %lu\n", cmd->serial_number);
+
+	if (!drive) {
+		printk (KERN_WARNING "ide-scsi: Drive not set in idescsi_eh_reset\n");
+		WARN_ON(1);
+		return FAILED;
+	}
+
+	spin_lock_irq(&ide_lock);
+
+	if (!scsi->pc || (req = scsi->pc->rq) != HWGROUP(drive)->rq || !HWGROUP(drive)->handler) {
+		printk (KERN_WARNING "ide-scsi: No active request in idescsi_eh_reset\n");
+		spin_unlock(&ide_lock);
+		return FAILED;
+	}
+
+	/* kill current request */
+	blkdev_dequeue_request(req);
+	end_that_request_last(req);
+	idescsi_free_bio(req->bio);
+	if (req->flags & REQ_SENSE)
+		kfree(scsi->pc->buffer);
+	kfree(scsi->pc);
+	scsi->pc = NULL;
+	kfree(req);
 
-	printk (KERN_ERR "ide-scsi: reset called for %lu\n", cmd->serial_number);
-	/* first null the handler for the drive and let any process
-	 * doing IO (on another CPU) run to (partial) completion
-	 * the lock prevents processing new requests */
-	spin_lock_irqsave(&ide_lock, flags);
-	while (HWGROUP(drive)->handler) {
-		HWGROUP(drive)->handler = NULL;
-		schedule_timeout(1);
-	}
 	/* now nuke the drive queue */
 	while ((req = elv_next_request(drive->queue))) {
 		blkdev_dequeue_request(req);
 		end_that_request_last(req);
 	}
-	/* FIXME - this will probably leak memory */
+
 	HWGROUP(drive)->rq = NULL;
-	if (drive_to_idescsi(drive))
-		drive_to_idescsi(drive)->pc = NULL;
-	spin_unlock_irqrestore(&ide_lock, flags);
-	/* finally, reset the drive (and its partner on the bus...) */
-	ide_do_reset (drive);	
-	return SUCCESS;
+	HWGROUP(drive)->handler = NULL;
+	HWGROUP(drive)->busy = 1;		/* will set this to zero when ide reset finished */
+	spin_unlock_irq(&ide_lock);
+
+	ide_do_reset(drive);
+
+	/* ide_do_reset starts a polling handler which restarts itself every 50ms until the reset finishes */
+
+	do {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		spin_unlock_irq(cmd->device->host->host_lock);
+		schedule_timeout(HZ/20);
+		spin_lock_irq(cmd->device->host->host_lock);
+	} while ( HWGROUP(drive)->handler );
+
+	ready = drive_is_ready(drive);
+	HWGROUP(drive)->busy--;
+	if (!ready) {
+		printk (KERN_ERR "ide-scsi: reset failed!\n");
+		ret = FAILED;
+	}
+
+	return ret;
 }
 
 static int idescsi_bios(struct scsi_device *sdev, struct block_device *bdev,
@@ -935,8 +1068,8 @@ static Scsi_Host_Template idescsi_templa
 	.slave_configure        = idescsi_slave_configure,
 	.ioctl			= idescsi_ioctl,
 	.queuecommand		= idescsi_queue,
-	.eh_abort_handler	= idescsi_abort,
-	.eh_device_reset_handler = idescsi_reset,
+	.eh_abort_handler	= idescsi_eh_abort,
+	.eh_host_reset_handler  = idescsi_eh_reset,
 	.bios_param		= idescsi_bios,
 	.can_queue		= 40,
 	.this_id		= -1,
--- diff/drivers/scsi/ini9100u.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/scsi/ini9100u.c	2004-03-09 11:51:50.000000000 +0000
@@ -180,15 +180,6 @@ static int setup_debug = 0;
 
 static char *setup_str = (char *) NULL;
 
-static irqreturn_t i91u_intr0(int irq, void *dev_id, struct pt_regs *);
-static irqreturn_t i91u_intr1(int irq, void *dev_id, struct pt_regs *);
-static irqreturn_t i91u_intr2(int irq, void *dev_id, struct pt_regs *);
-static irqreturn_t i91u_intr3(int irq, void *dev_id, struct pt_regs *);
-static irqreturn_t i91u_intr4(int irq, void *dev_id, struct pt_regs *);
-static irqreturn_t i91u_intr5(int irq, void *dev_id, struct pt_regs *);
-static irqreturn_t i91u_intr6(int irq, void *dev_id, struct pt_regs *);
-static irqreturn_t i91u_intr7(int irq, void *dev_id, struct pt_regs *);
-
 static void i91u_panic(char *msg);
 
 static void i91uSCBPost(BYTE * pHcb, BYTE * pScb);
@@ -278,7 +269,7 @@ static irqreturn_t i91u_intr(int irqno, 
 	unsigned long flags;
 	
 	spin_lock_irqsave(dev->host_lock, flags);
-	tul_isr((HCS *)hreg->base);
+	tul_isr((HCS *)dev->base);
 	spin_unlock_irqrestore(dev->host_lock, flags);
 	return IRQ_HANDLED;
 }
--- diff/drivers/scsi/megaraid.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/scsi/megaraid.c	2004-03-09 11:51:50.000000000 +0000
@@ -261,10 +261,6 @@ mega_query_adapter(adapter_t *adapter)
 			"megaraid: Product_info cmd failed with error: %d\n",
 				retval);
 
-		pci_dma_sync_single(adapter->dev, prod_info_dma_handle,
-				sizeof(mega_product_info),
-				PCI_DMA_FROMDEVICE);
-
 		pci_unmap_single(adapter->dev, prod_info_dma_handle,
 				sizeof(mega_product_info), PCI_DMA_FROMDEVICE);
 	}
@@ -1651,26 +1647,11 @@ mega_free_scb(adapter_t *adapter, scb_t 
 	case MEGA_BULK_DATA:
 		pci_unmap_page(adapter->dev, scb->dma_h_bulkdata,
 			scb->cmd->request_bufflen, scb->dma_direction);
-
-		if( scb->dma_direction == PCI_DMA_FROMDEVICE ) {
-			pci_dma_sync_single(adapter->dev,
-					scb->dma_h_bulkdata,
-					scb->cmd->request_bufflen,
-					PCI_DMA_FROMDEVICE);
-		}
-
 		break;
 
 	case MEGA_SGLIST:
 		pci_unmap_sg(adapter->dev, scb->cmd->request_buffer,
 			scb->cmd->use_sg, scb->dma_direction);
-
-		if( scb->dma_direction == PCI_DMA_FROMDEVICE ) {
-			pci_dma_sync_sg(adapter->dev,
-					scb->cmd->request_buffer,
-					scb->cmd->use_sg, PCI_DMA_FROMDEVICE);
-		}
-
 		break;
 
 	default:
@@ -1758,14 +1739,6 @@ mega_build_sglist(adapter_t *adapter, sc
 			*buf = (u32)scb->dma_h_bulkdata;
 			*len = (u32)cmd->request_bufflen;
 		}
-
-		if( scb->dma_direction == PCI_DMA_TODEVICE ) {
-			pci_dma_sync_single(adapter->dev,
-					scb->dma_h_bulkdata,
-					cmd->request_bufflen,
-					PCI_DMA_TODEVICE);
-		}
-
 		return 0;
 	}
 
@@ -1804,11 +1777,6 @@ mega_build_sglist(adapter_t *adapter, sc
 	 */
 	*len = (u32)cmd->request_bufflen;
 
-	if( scb->dma_direction == PCI_DMA_TODEVICE ) {
-		pci_dma_sync_sg(adapter->dev, sgl, cmd->use_sg,
-				PCI_DMA_TODEVICE);
-	}
-
 	/* Return count of SG requests */
 	return sgcnt;
 }
--- diff/drivers/scsi/ncr53c8xx.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/scsi/ncr53c8xx.c	2004-03-09 11:51:50.000000000 +0000
@@ -5140,9 +5140,10 @@ void ncr_complete (ncb_p np, ccb_p cp)
 		*/
 		if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) &&
 		    cmd->cmnd[4] >= 7 && !cmd->use_sg) {
-			sync_scsi_data(np, cmd);	/* SYNC the data */
+			sync_scsi_data_for_cpu(np, cmd);	/* SYNC the data */
 			ncr_setup_lcb (np, cmd->device->id, cmd->device->lun,
 				       (char *) cmd->request_buffer);
+			sync_scsi_data_for_device(np, cmd);	/* SYNC the data */
 		}
 
 		tp->bytes     += cp->data_len;
--- diff/drivers/scsi/oktagon_esp.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/scsi/oktagon_esp.c	2004-03-09 11:51:50.000000000 +0000
@@ -12,7 +12,6 @@
 #define USE_BOTTOM_HALF
 #endif
 
-#define __KERNEL_SYSCALLS__
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -43,8 +42,6 @@
 #include <linux/interrupt.h>
 #endif
 
-#include <linux/unistd.h>
-
 /* The controller registers can be found in the Z2 config area at these
  * offsets:
  */
--- diff/drivers/scsi/qlogicfc.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/scsi/qlogicfc.c	2004-03-09 11:51:50.000000000 +0000
@@ -411,7 +411,7 @@ static unsigned short risc_code_addr01 =
    if that mbox should be copied as input.  For example 0x2 would mean
    only copy mbox1. */
 
-const u_char mbox_param[] =
+static const u_char mbox_param[] =
 {
 	0x01,			/* MBOX_NO_OP */
 	0x1f,			/* MBOX_LOAD_RAM */
--- diff/drivers/scsi/qlogicpti.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/scsi/qlogicpti.c	2004-03-09 11:51:50.000000000 +0000
@@ -54,7 +54,7 @@ static int qptis_running = 0;
 
 #define PACKB(a, b)			(((a)<<4)|(b))
 
-const u_char mbox_param[] = {
+static const u_char mbox_param[] = {
 	PACKB(1, 1),	/* MBOX_NO_OP */
 	PACKB(5, 5),	/* MBOX_LOAD_RAM */
 	PACKB(2, 0),	/* MBOX_EXEC_FIRMWARE */
--- diff/drivers/scsi/scsi.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/scsi/scsi.c	2004-03-09 11:51:50.000000000 +0000
@@ -53,6 +53,8 @@
 #include <linux/spinlock.h>
 #include <linux/kmod.h>
 #include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
 
 #include <scsi/scsi_host.h>
 #include "scsi.h"
@@ -104,7 +106,7 @@ const char *const scsi_device_types[MAX_
 	"Communications   ",
 	"Unknown          ",
 	"Unknown          ",
-	"Unknown          ",
+	"RAID             ",
 	"Enclosure        ",
 };
 
@@ -1130,6 +1132,38 @@ int scsi_device_cancel(struct scsi_devic
 	return 0;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int scsi_cpu_notify(struct notifier_block *self,
+			   unsigned long action, void *hcpu)
+{
+	int cpu = (unsigned long)hcpu;
+
+	switch(action) {
+	case CPU_DEAD:
+		/* Drain scsi_done_q. */
+		local_irq_disable();
+		list_splice_init(&per_cpu(scsi_done_q, cpu),
+				 &__get_cpu_var(scsi_done_q));
+		raise_softirq_irqoff(SCSI_SOFTIRQ);
+		local_irq_enable();
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __devinitdata scsi_cpu_nb = {
+	.notifier_call	= scsi_cpu_notify,
+};
+
+#define register_scsi_cpu() register_cpu_notifier(&scsi_cpu_nb)
+#define unregister_scsi_cpu() unregister_cpu_notifier(&scsi_cpu_nb)
+#else
+#define register_scsi_cpu()
+#define unregister_scsi_cpu()
+#endif /* CONFIG_HOTPLUG_CPU */
+
 MODULE_DESCRIPTION("SCSI core");
 MODULE_LICENSE("GPL");
 
@@ -1164,6 +1198,7 @@ static int __init init_scsi(void)
 
 	devfs_mk_dir("scsi");
 	open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL);
+	register_scsi_cpu();
 	printk(KERN_NOTICE "SCSI subsystem initialized\n");
 	return 0;
 
@@ -1191,6 +1226,7 @@ static void __exit exit_scsi(void)
 	devfs_remove("scsi");
 	scsi_exit_procfs();
 	scsi_exit_queue();
+	unregister_scsi_cpu();
 }
 
 subsys_initcall(init_scsi);
--- diff/drivers/scsi/scsi_devinfo.c	2003-10-27 09:20:43.000000000 +0000
+++ source/drivers/scsi/scsi_devinfo.c	2004-03-09 11:51:50.000000000 +0000
@@ -94,95 +94,93 @@ static struct {
 	 * The following causes a failed REQUEST SENSE on lun 1 for
 	 * seagate controller, which causes SCSI code to reset bus.
 	 */
-	{"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN},
+	{"HP", "C1750A", "3226", BLIST_NOLUN},		/* scanjet iic */
+	{"HP", "C1790A", "", BLIST_NOLUN},		/* scanjet iip */
+	{"HP", "C2500A", "", BLIST_NOLUN},		/* scanjet iicx */
+	{"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN},	/* locks up */
+	{"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN},	/* responds to all lun */
+	{"MITSUMI", "CD-R CR-2201CS", "6119", BLIST_NOLUN},	/* locks up */
+	{"NEC", "D3856", "0009", BLIST_NOLUN},
 	{"QUANTUM", "LPS525S", "3110", BLIST_NOLUN},	/* locks up */
 	{"QUANTUM", "PD1225S", "3110", BLIST_NOLUN},	/* locks up */
 	{"QUANTUM", "FIREBALL ST4.3S", "0F0C", BLIST_NOLUN},	/* locks up */
-	{"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN},	/* locks up */
+	{"RELISYS", "Scorpio", NULL, BLIST_NOLUN},	/* responds to all lun */
 	{"SANKYO", "CP525", "6.64", BLIST_NOLUN},	/* causes failed REQ SENSE, extra reset */
-	{"HP", "C1750A", "3226", BLIST_NOLUN},		/* scanjet iic */
-	{"HP", "C1790A", "", BLIST_NOLUN},		/* scanjet iip */
-	{"HP", "C2500A", "", BLIST_NOLUN},		/* scanjet iicx */
+	{"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN},
 	{"YAMAHA", "CDR100", "1.00", BLIST_NOLUN},	/* locks up */
 	{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},	/* locks up */
 	{"YAMAHA", "CRW8424S", "1.0", BLIST_NOLUN},	/* locks up */
 	{"YAMAHA", "CRW6416S", "1.0c", BLIST_NOLUN},	/* locks up */
-	{"MITSUMI", "CD-R CR-2201CS", "6119", BLIST_NOLUN},	/* locks up */
-	{"RELISYS", "Scorpio", NULL, BLIST_NOLUN},	/* responds to all lun */
-	{"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN},	/* responds to all lun */
-	{"NEC", "D3856", "0009", BLIST_NOLUN},
 
 	/*
 	 * Other types of devices that have special flags.
 	 */
-	{"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN},
-	{"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN},
-	{"IOMEGA", "Io20S         *F", NULL, BLIST_KEY},
-	{"INSITE", "Floptical   F*8I", NULL, BLIST_KEY},
-	{"INSITE", "I325VM", NULL, BLIST_KEY},
-	{"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN},
-	{"MICROP", "4110", NULL, BLIST_NOTQ},
-	{"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN},
-	{"NAKAMICH", "MJ-4.8S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"EMULEX", "MD21/S2     ESDI", NULL, BLIST_SINGLELUN},
+	{"ADAPTEC", "AACRAID", NULL, BLIST_FORCELUN},
+	{"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN},
 	{"CANON", "IPUBJD", NULL, BLIST_SPARSELUN},
-	{"nCipher", "Fastness Crypto", NULL, BLIST_FORCELUN},
-	{"DEC", "HSG80", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
+	{"CMD", "CRA-7280", NULL, BLIST_SPARSELUN},	/* CMD RAID Controller */
+	{"CNSI", "G7324", NULL, BLIST_SPARSELUN},	/* Chaparral G7324 RAID */
+	{"CNSi", "G8324", NULL, BLIST_SPARSELUN},	/* Chaparral G8324 RAID */
 	{"COMPAQ", "LOGICAL VOLUME", NULL, BLIST_FORCELUN},
 	{"COMPAQ", "CR3500", NULL, BLIST_FORCELUN},
-	{"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
-	{"TOSHIBA", "CDROM", NULL, BLIST_ISROM},
-	{"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM},
-	{"MegaRAID", "LD", NULL, BLIST_FORCELUN},
-	{"DGC", "RAID", NULL, BLIST_SPARSELUN},	/* Dell PV 650F, storage on LUN 0 */
-	{"DGC", "DISK", NULL, BLIST_SPARSELUN},	/* Dell PV 650F, no storage on LUN 0 */
+	{"COMPAQ", "MSA1000", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
+	{"COMPAQ", "MSA1000 VOLUME", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
+	{"COMPAQ", "HSV110", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
+	{"DDN", "SAN DataDirector", "*", BLIST_SPARSELUN},
+	{"DEC", "HSG80", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
 	{"DELL", "PV660F", NULL, BLIST_SPARSELUN},
 	{"DELL", "PV660F   PSEUDO", NULL, BLIST_SPARSELUN},
 	{"DELL", "PSEUDO DEVICE .", NULL, BLIST_SPARSELUN},	/* Dell PV 530F */
 	{"DELL", "PV530F", NULL, BLIST_SPARSELUN},
+	{"DELL", "PERCRAID", NULL, BLIST_FORCELUN},
+	{"DGC", "RAID", NULL, BLIST_SPARSELUN},	/* Dell PV 650F, storage on LUN 0 */
+	{"DGC", "DISK", NULL, BLIST_SPARSELUN},	/* Dell PV 650F, no storage on LUN 0 */
 	{"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
+	{"EMULEX", "MD21/S2     ESDI", NULL, BLIST_SINGLELUN},
+	{"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+	{"Generic", "USB Storage-SMC", "0207", BLIST_FORCELUN},
+	{"HITACHI", "DF400", "*", BLIST_SPARSELUN},
+	{"HITACHI", "DF500", "*", BLIST_SPARSELUN},
+	{"HITACHI", "DF600", "*", BLIST_SPARSELUN},
 	{"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN},	/* HP VA7400 */
 	{"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP XP Arrays */
-	{"CMD", "CRA-7280", NULL, BLIST_SPARSELUN},	/* CMD RAID Controller */
-	{"CNSI", "G7324", NULL, BLIST_SPARSELUN},	/* Chaparral G7324 RAID */
-	{"CNSi", "G8324", NULL, BLIST_SPARSELUN},	/* Chaparral G8324 RAID */
-	{"Zzyzx", "RocketStor 500S", NULL, BLIST_SPARSELUN},
-	{"Zzyzx", "RocketStor 2000", NULL, BLIST_SPARSELUN},
-	{"SONY", "TSL", NULL, BLIST_FORCELUN},		/* DDS3 & DDS4 autoloaders */
-	{"DELL", "PERCRAID", NULL, BLIST_FORCELUN},
 	{"HP", "NetRAID-4M", NULL, BLIST_FORCELUN},
-	{"ADAPTEC", "AACRAID", NULL, BLIST_FORCELUN},
-	{"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN},
-	{"COMPAQ", "MSA1000", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
-	{"COMPAQ", "MSA1000 VOLUME", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
-	{"COMPAQ", "HSV110", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
 	{"HP", "HSV100", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
 	{"HP", "C1557A", NULL, BLIST_FORCELUN},
 	{"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN},
-	{"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-	{"DDN", "SAN DataDirector", "*", BLIST_SPARSELUN},
-	{"HITACHI", "DF400", "*", BLIST_SPARSELUN},
-	{"HITACHI", "DF500", "*", BLIST_SPARSELUN},
-	{"HITACHI", "DF600", "*", BLIST_SPARSELUN},
 	{"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-	{"SUN", "T300", "*", BLIST_SPARSELUN},
-	{"SUN", "T4", "*", BLIST_SPARSELUN},
+	{"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
+	{"IOMEGA", "Io20S         *F", NULL, BLIST_KEY},
+	{"INSITE", "Floptical   F*8I", NULL, BLIST_KEY},
+	{"INSITE", "I325VM", NULL, BLIST_KEY},
+	{"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN},
+	{"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"MegaRAID", "LD", NULL, BLIST_FORCELUN},
+	{"MICROP", "4110", NULL, BLIST_NOTQ},
+	{"MYLEX", "DACARMRB", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+	{"nCipher", "Fastness Crypto", NULL, BLIST_FORCELUN},
+	{"NAKAMICH", "MJ-4.8S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN},
 	{"SGI", "RAID3", "*", BLIST_SPARSELUN},
 	{"SGI", "RAID5", "*", BLIST_SPARSELUN},
 	{"SGI", "TP9100", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-	{"SGI", "TP9300", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-	{"SGI", "TP9400", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-	{"SGI", "TP9500", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-	{"MYLEX", "DACARMRB", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+	{"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN},
+	{"SONY", "TSL", NULL, BLIST_FORCELUN},		/* DDS3 & DDS4 autoloaders */
+	{"SUN", "T300", "*", BLIST_SPARSELUN},
+	{"SUN", "T4", "*", BLIST_SPARSELUN},
+	{"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN},
+	{"TOSHIBA", "CDROM", NULL, BLIST_ISROM},
+	{"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM},
 	{"XYRATEX", "RS", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+	{"Zzyzx", "RocketStor 500S", NULL, BLIST_SPARSELUN},
+	{"Zzyzx", "RocketStor 2000", NULL, BLIST_SPARSELUN},
 	{ NULL, NULL, NULL, 0 },
 };
 
--- diff/drivers/scsi/scsi_error.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/scsi/scsi_error.c	2004-03-09 11:51:50.000000000 +0000
@@ -37,6 +37,8 @@
 #define SENSE_TIMEOUT (10*HZ)
 #endif
 
+#define START_UNIT_TIMEOUT (30*HZ)
+
 /*
  * These should *probably* be handled by the host itself.
  * Since it is allowed to sleep, it probably should.
@@ -282,6 +284,15 @@ static int scsi_check_sense(struct scsi_
 			(scmd->sense_buffer[13] == 0x01)) {
 			return NEEDS_RETRY;
 		}
+		/*
+		 * if the device is not started, we need to wake
+		 * the error handler to start the motor
+		 */
+		if (scmd->device->allow_restart &&
+		    (scmd->sense_buffer[12] == 0x04) &&
+		    (scmd->sense_buffer[13] == 0x02)) {
+			return FAILED;
+		}
 		return SUCCESS;
 
 		/* these three are not supported */
@@ -829,6 +840,105 @@ static int scsi_try_bus_device_reset(str
 }
 
 /**
+ * scsi_eh_try_stu - Send START_UNIT to device.
+ * @scmd:	Scsi cmd to send START_UNIT
+ *
+ * Return value:
+ *    0 - Device is ready. 1 - Device NOT ready.
+ **/
+static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
+{
+	static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0};
+	int rtn;
+
+	if (!scmd->device->allow_restart)
+		return 1;
+
+	memcpy(scmd->cmnd, stu_command, sizeof(stu_command));
+
+	/*
+	 * zero the sense buffer.  the scsi spec mandates that any
+	 * untransferred sense data should be interpreted as being zero.
+	 */
+	memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
+
+	scmd->request_buffer = NULL;
+	scmd->request_bufflen = 0;
+	scmd->use_sg = 0;
+	scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
+	scmd->underflow = 0;
+	scmd->sc_data_direction = DMA_NONE;
+
+	rtn = scsi_send_eh_cmnd(scmd, START_UNIT_TIMEOUT);
+
+	/*
+	 * when we eventually call scsi_finish, we really wish to complete
+	 * the original request, so let's restore the original data. (db)
+	 */
+	scsi_setup_cmd_retry(scmd);
+
+	/*
+	 * hey, we are done.  let's look to see what happened.
+	 */
+	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n",
+		__FUNCTION__, scmd, rtn));
+	if (rtn == SUCCESS)
+		return 0;
+	return 1;
+}
+
+ /**
+ * scsi_eh_stu - send START_UNIT if needed
+ * @shost:	scsi host being recovered.
+ * @eh_done_q:	list_head for processed commands.
+ *
+ * Notes:
+ *    If commands are failing due to not ready, initializing command required,
+ *	try revalidating the device, which will end up sending a start unit. 
+ **/
+static int scsi_eh_stu(struct Scsi_Host *shost,
+			      struct list_head *work_q,
+			      struct list_head *done_q)
+{
+	struct list_head *lh, *lh_sf;
+	struct scsi_cmnd *scmd, *stu_scmd;
+	struct scsi_device *sdev;
+
+	shost_for_each_device(sdev, shost) {
+		stu_scmd = NULL;
+		list_for_each_entry(scmd, work_q, eh_entry)
+			if (scmd->device == sdev && SCSI_SENSE_VALID(scmd) &&
+			    scsi_check_sense(scmd) == FAILED ) {
+				stu_scmd = scmd;
+				break;
+			}
+
+		if (!stu_scmd)
+			continue;
+
+		SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending START_UNIT to sdev:"
+						  " 0x%p\n", current->comm, sdev));
+
+		if (!scsi_eh_try_stu(stu_scmd)) {
+			if (!sdev->online || !scsi_eh_tur(stu_scmd)) {
+				list_for_each_safe(lh, lh_sf, work_q) {
+					scmd = list_entry(lh, struct scsi_cmnd, eh_entry);
+					if (scmd->device == sdev)
+						scsi_eh_finish_cmd(scmd, done_q);
+				}
+			}
+		} else {
+			SCSI_LOG_ERROR_RECOVERY(3,
+						printk("%s: START_UNIT failed to sdev:"
+						       " 0x%p\n", current->comm, sdev));
+		}
+	}
+
+	return list_empty(work_q);
+}
+
+
+/**
  * scsi_eh_bus_device_reset - send bdr if needed
  * @shost:	scsi host being recovered.
  * @eh_done_q:	list_head for processed commands.
@@ -1033,7 +1143,9 @@ static int scsi_eh_host_reset(struct lis
 		if (rtn == SUCCESS) {
 			list_for_each_safe(lh, lh_sf, work_q) {
 				scmd = list_entry(lh, struct scsi_cmnd, eh_entry);
-				if (!scmd->device->online || !scsi_eh_tur(scmd)) 
+				if (!scmd->device->online ||
+				    (!scsi_eh_try_stu(scmd) && !scsi_eh_tur(scmd)) ||
+				    !scsi_eh_tur(scmd))
 					scsi_eh_finish_cmd(scmd, done_q);
 			}
 		} else {
@@ -1401,10 +1513,11 @@ static void scsi_eh_ready_devs(struct Sc
 			       struct list_head *work_q,
 			       struct list_head *done_q)
 {
-	if (!scsi_eh_bus_device_reset(shost, work_q, done_q))
-		if (!scsi_eh_bus_reset(shost, work_q, done_q))
-			if (!scsi_eh_host_reset(work_q, done_q))
-				scsi_eh_offline_sdevs(work_q, done_q);
+	if (!scsi_eh_stu(shost, work_q, done_q))
+		if (!scsi_eh_bus_device_reset(shost, work_q, done_q))
+			if (!scsi_eh_bus_reset(shost, work_q, done_q))
+				if (!scsi_eh_host_reset(work_q, done_q))
+					scsi_eh_offline_sdevs(work_q, done_q);
 }
 
 /**
--- diff/drivers/scsi/scsi_lib.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/scsi/scsi_lib.c	2004-03-09 11:51:50.000000000 +0000
@@ -917,6 +917,7 @@ static int scsi_init_io(struct scsi_cmnd
 			req->current_nr_sectors);
 
 	/* release the command and kill it */
+	scsi_release_buffers(cmd);
 	scsi_put_command(cmd);
 	return BLKPREP_KILL;
 }
--- diff/drivers/scsi/scsi_priv.h	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/scsi/scsi_priv.h	2004-03-09 11:51:50.000000000 +0000
@@ -155,6 +155,7 @@ extern int scsi_sysfs_add_sdev(struct sc
 extern int scsi_sysfs_add_host(struct Scsi_Host *);
 extern int scsi_sysfs_register(void);
 extern void scsi_sysfs_unregister(void);
+extern struct scsi_transport_template blank_transport_template;
 
 extern struct class sdev_class;
 extern struct bus_type scsi_bus_type;
--- diff/drivers/scsi/scsi_scan.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/scsi/scsi_scan.c	2004-03-09 11:51:50.000000000 +0000
@@ -35,6 +35,7 @@
 #include <scsi/scsi_driver.h>
 #include <scsi/scsi_devinfo.h>
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
 #include "scsi.h"
 
 #include "scsi_priv.h"
@@ -192,7 +193,7 @@ static struct scsi_device *scsi_alloc_sd
 	struct scsi_device *sdev, *device;
 	unsigned long flags;
 
-	sdev = kmalloc(sizeof(*sdev), GFP_ATOMIC);
+	sdev = kmalloc(sizeof(*sdev) + shost->transportt->size, GFP_ATOMIC);
 	if (!sdev)
 		goto out;
 
@@ -237,6 +238,11 @@ static struct scsi_device *scsi_alloc_sd
 			goto out_free_queue;
 	}
 
+	if (shost->transportt->setup) {
+		if (shost->transportt->setup(sdev))
+			goto out_cleanup_slave;
+	}
+
 	if (get_device(&sdev->host->shost_gendev)) {
 
 		device_initialize(&sdev->sdev_gendev);
@@ -253,8 +259,15 @@ static struct scsi_device *scsi_alloc_sd
 		snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE,
 			 "%d:%d:%d:%d", sdev->host->host_no,
 			 sdev->channel, sdev->id, sdev->lun);
+
+		class_device_initialize(&sdev->transport_classdev);
+		sdev->transport_classdev.dev = &sdev->sdev_gendev;
+		sdev->transport_classdev.class = sdev->host->transportt->class;
+		snprintf(sdev->transport_classdev.class_id, BUS_ID_SIZE,
+			 "%d:%d:%d:%d", sdev->host->host_no,
+			 sdev->channel, sdev->id, sdev->lun);
 	} else
-		goto out_cleanup_slave;
+		goto out_cleanup_transport;
 
 	/*
 	 * If there are any same target siblings, add this to the
@@ -283,6 +296,9 @@ static struct scsi_device *scsi_alloc_sd
 	spin_unlock_irqrestore(shost->host_lock, flags);
 	return sdev;
 
+out_cleanup_transport:
+	if (shost->transportt->cleanup)
+		shost->transportt->cleanup(sdev);
 out_cleanup_slave:
 	if (shost->hostt->slave_destroy)
 		shost->hostt->slave_destroy(sdev);
@@ -744,6 +760,8 @@ static int scsi_probe_and_add_lun(struct
 	} else {
 		if (sdev->host->hostt->slave_destroy)
 			sdev->host->hostt->slave_destroy(sdev);
+		if (sdev->host->transportt->cleanup)
+			sdev->host->transportt->cleanup(sdev);
 		put_device(&sdev->sdev_gendev);
 	}
  out:
@@ -1300,5 +1318,7 @@ void scsi_free_host_dev(struct scsi_devi
 
 	if (sdev->host->hostt->slave_destroy)
 		sdev->host->hostt->slave_destroy(sdev);
+	if (sdev->host->transportt->cleanup)
+		sdev->host->transportt->cleanup(sdev);
 	put_device(&sdev->sdev_gendev);
 }
--- diff/drivers/scsi/scsi_sysfs.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/scsi/scsi_sysfs.c	2004-03-09 11:51:50.000000000 +0000
@@ -13,6 +13,7 @@
 #include <linux/device.h>
 
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
 #include "scsi.h"
 
 #include "scsi_priv.h"
@@ -58,21 +59,24 @@ static int scsi_scan(struct Scsi_Host *s
  * shost_show_function: macro to create an attr function that can be used to
  * show a non-bit field.
  */
-#define shost_show_function(field, format_string)			\
+#define shost_show_function(name, field, format_string)			\
 static ssize_t								\
-show_##field (struct class_device *class_dev, char *buf)		\
+show_##name (struct class_device *class_dev, char *buf)			\
 {									\
 	struct Scsi_Host *shost = class_to_shost(class_dev);		\
-	return snprintf (buf, 20, format_string, shost->field);	\
+	return snprintf (buf, 20, format_string, shost->field);		\
 }
 
 /*
  * shost_rd_attr: macro to create a function and attribute variable for a
  * read only field.
  */
-#define shost_rd_attr(field, format_string)				\
-	shost_show_function(field, format_string)			\
-static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL)
+#define shost_rd_attr2(name, field, format_string)			\
+	shost_show_function(name, field, format_string)			\
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+
+#define shost_rd_attr(field, format_string) \
+shost_rd_attr2(field, field, format_string)
 
 /*
  * Create the actual show/store functions and data structures.
@@ -96,6 +100,7 @@ shost_rd_attr(host_busy, "%hu\n");
 shost_rd_attr(cmd_per_lun, "%hd\n");
 shost_rd_attr(sg_tablesize, "%hu\n");
 shost_rd_attr(unchecked_isa_dma, "%d\n");
+shost_rd_attr2(proc_name, hostt->proc_name, "%s\n");
 
 static struct class_device_attribute *scsi_sysfs_shost_attrs[] = {
 	&class_device_attr_unique_id,
@@ -103,6 +108,7 @@ static struct class_device_attribute *sc
 	&class_device_attr_cmd_per_lun,
 	&class_device_attr_sg_tablesize,
 	&class_device_attr_unchecked_isa_dma,
+	&class_device_attr_proc_name,
 	&class_device_attr_scan,
 	NULL
 };
@@ -344,6 +350,7 @@ static int attr_add(struct device *dev, 
  **/
 int scsi_sysfs_add_sdev(struct scsi_device *sdev)
 {
+	struct class_device_attribute **attrs;
 	int error = -EINVAL, i;
 
 	if (sdev->sdev_state != SDEV_CREATED)
@@ -363,6 +370,12 @@ int scsi_sysfs_add_sdev(struct scsi_devi
 		goto clean_device;
 	}
 
+	if (sdev->transport_classdev.class) {
+		error = class_device_add(&sdev->transport_classdev);
+		if (error)
+			goto clean_device2;
+	}
+
 	get_device(&sdev->sdev_gendev);
 
 	if (sdev->host->hostt->sdev_attrs) {
@@ -388,10 +401,24 @@ int scsi_sysfs_add_sdev(struct scsi_devi
 		}
 	}
 
+ 	if (sdev->transport_classdev.class) {
+ 		attrs = sdev->host->transportt->attrs;
+ 		for (i = 0; attrs[i]; i++) {
+ 			error = class_device_create_file(&sdev->transport_classdev,
+ 							 attrs[i]);
+ 			if (error) {
+ 				scsi_remove_device(sdev);
+				goto out;
+			}
+ 		}
+ 	}
+
  out:
 	return error;
 
-clean_device:
+ clean_device2:
+	class_device_del(&sdev->sdev_classdev);
+ clean_device:
 	sdev->sdev_state = SDEV_CANCEL;
 
 	device_del(&sdev->sdev_gendev);
@@ -409,9 +436,12 @@ void scsi_remove_device(struct scsi_devi
 	if (sdev->sdev_state == SDEV_RUNNING || sdev->sdev_state == SDEV_CANCEL) {
 		sdev->sdev_state = SDEV_DEL;
 		class_device_unregister(&sdev->sdev_classdev);
+		class_device_unregister(&sdev->transport_classdev);
 		device_del(&sdev->sdev_gendev);
 		if (sdev->host->hostt->slave_destroy)
 			sdev->host->hostt->slave_destroy(sdev);
+		if (sdev->host->transportt->cleanup)
+			sdev->host->transportt->cleanup(sdev);
 		put_device(&sdev->sdev_gendev);
 	}
 }
@@ -498,3 +528,7 @@ int scsi_sysfs_add_host(struct Scsi_Host
 
 	return 0;
 }
+
+/* A blank transport template that is used in drivers that don't
+ * yet implement Transport Attributes */
+struct scsi_transport_template blank_transport_template = { 0, };
--- diff/drivers/scsi/sd.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/scsi/sd.c	2004-03-09 11:51:50.000000000 +0000
@@ -19,6 +19,9 @@
  *	   not being read in sd_open. Fix problem where removable media 
  *	   could be ejected after sd_open.
  *	 - Douglas Gilbert <dgilbert@interlog.com> cleanup for lk 2.5.x
+ *	 - Badari Pulavarty <pbadari@us.ibm.com>, Matthew Wilcox 
+ *	   <willy@debian.org>, Kurt Garloff <garloff@suse.de>: 
+ *	   Support 32k/1M disks.
  *
  *	Logging policy (needs CONFIG_SCSI_LOGGING defined):
  *	 - setting up transfer: SCSI_LOG_HLQUEUE levels 1 and 2
@@ -61,7 +64,7 @@
  * Remaining dev_t-handling stuff
  */
 #define SD_MAJORS	16
-#define SD_DISKS	(SD_MAJORS << 4)
+#define SD_DISKS	32768	/* anything between 256 and 262144 */
 
 /*
  * Time out in seconds for disks and Magneto-opticals (which are slower).
@@ -121,6 +124,20 @@ static struct scsi_driver sd_template = 
 	.init_command		= sd_init_command,
 };
 
+/* Device no to disk mapping:
+ * 
+ *       major         disc2     disc  p1
+ *   |............|.............|....|....| <- dev_t
+ *    31        20 19          8 7  4 3  0
+ * 
+ * Inside a major, we have 16k disks, however mapped non-
+ * contiguously. The first 16 disks are for major0, the next
+ * ones with major1, ... Disk 256 is for major0 again, disk 272 
+ * for major1, ... 
+ * As we stay compatible with our numbering scheme, we can reuse 
+ * the well-know SCSI majors 8, 65--71, 136--143.
+ */
+
 static int sd_major(int major_idx)
 {
 	switch (major_idx) {
@@ -136,6 +153,14 @@ static int sd_major(int major_idx)
 	}
 }
 
+static unsigned int make_sd_dev(unsigned int sd_nr, unsigned int part)
+{
+	return  (part & 0xf) | ((sd_nr & 0xf) << 4) |
+		(sd_major((sd_nr & 0xf0) >> 4) << 20) | (sd_nr & 0xfff00);
+}
+
+/* reverse mapping dev -> (sd_nr, part) not currently needed */
+
 #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,kobj);
 
 static inline struct scsi_disk *scsi_disk(struct gendisk *disk)
@@ -1301,7 +1326,7 @@ static int sd_probe(struct device *dev)
 	struct scsi_disk *sdkp;
 	struct gendisk *gd;
 	u32 index;
-	int error;
+	int error, devno;
 
 	error = -ENODEV;
 	if ((sdp->type != TYPE_DISK) && (sdp->type != TYPE_MOD))
@@ -1319,6 +1344,12 @@ static int sd_probe(struct device *dev)
 	kobject_init(&sdkp->kobj);
 	sdkp->kobj.ktype = &scsi_disk_kobj_type;
 
+	/* Note: We can accomodate 64 partitions, but the genhd code
+	 * assumes partitions allocate consecutive minors, which they don't.
+	 * So for now stay with max 16 partitions and leave two spare bits. 
+	 * Later, we may change the genhd code and the alloc_disk() call
+	 * and the ->minors assignment here. 	KG, 2004-02-10
+	 */ 
 	gd = alloc_disk(16);
 	if (!gd)
 		goto out_free;
@@ -1339,16 +1370,23 @@ static int sd_probe(struct device *dev)
 	sdkp->index = index;
 	sdkp->openers = 0;
 
-	gd->major = sd_major(index >> 4);
-	gd->first_minor = (index & 15) << 4;
+	devno = make_sd_dev(index, 0);
+	gd->major = MAJOR(devno);
+	gd->first_minor = MINOR(devno);
 	gd->minors = 16;
 	gd->fops = &sd_fops;
 
-	if (index >= 26) {
+	if (index < 26) {
+		sprintf(gd->disk_name, "sd%c", 'a' + index % 26);
+	} else if (index < (26*27)) {
 		sprintf(gd->disk_name, "sd%c%c",
-			'a' + index/26-1,'a' + index % 26);
+			'a' + index / 26 - 1,'a' + index % 26);
 	} else {
-		sprintf(gd->disk_name, "sd%c", 'a' + index % 26);
+		const unsigned int m1 = (index / 26 - 1) / 26 - 1;
+		const unsigned int m2 = (index / 26 - 1) % 26;
+		const unsigned int m3 =  index % 26;
+		sprintf(gd->disk_name, "sd%c%c%c",
+			'a' + m1, 'a' + m2, 'a' + m3);
 	}
 
 	strcpy(gd->devfs_name, sdp->devfs_name);
--- diff/drivers/scsi/sr.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/scsi/sr.c	2004-03-09 11:51:50.000000000 +0000
@@ -566,14 +566,17 @@ static int sr_probe(struct device *dev)
 	snprintf(disk->devfs_name, sizeof(disk->devfs_name),
 			"%s/cd", sdev->devfs_name);
 	disk->driverfs_dev = &sdev->sdev_gendev;
-	register_cdrom(&cd->cdi);
 	set_capacity(disk, cd->capacity);
 	disk->private_data = &cd->driver;
 	disk->queue = sdev->request_queue;
+	cd->cdi.disk = disk;
 
 	dev_set_drvdata(dev, cd);
 	add_disk(disk);
 
+	if (register_cdrom(&cd->cdi))
+		goto fail_put;
+
 	printk(KERN_DEBUG
 	    "Attached scsi CD-ROM %s at scsi%d, channel %d, id %d, lun %d\n",
 	    cd->cdi.name, sdev->host->host_no, sdev->channel,
--- diff/drivers/scsi/st.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/scsi/st.c	2004-03-09 11:51:50.000000000 +0000
@@ -17,7 +17,7 @@
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
  */
 
-static char *verstr = "20040213";
+static char *verstr = "20040226";
 
 #include <linux/module.h>
 
@@ -121,7 +121,15 @@ static struct st_dev_parm {
 };
 #endif
 
-static char *st_formats[ST_NBR_MODES] ={"", "l", "m", "a"};
+/* Restrict the number of modes so that names for all are assigned */
+#if ST_NBR_MODES > 16
+#error "Maximum number of modes is 16"
+#endif
+/* Bit reversed order to get same names for same minors with all
+   mode counts */
+static char *st_formats[] = {
+	"",  "r", "k", "s", "l", "t", "o", "u",
+	"m", "v", "p", "x", "a", "y", "q", "z"}; 
 
 /* The default definitions have been moved to st_options.h */
 
@@ -3888,8 +3896,11 @@ static int st_probe(struct device *dev)
 				       dev_num);
 				goto out_free_tape;
 			}
-			snprintf(cdev->kobj.name, KOBJ_NAME_LEN, "%sm%d%s", disk->disk_name,
-				 mode, j ? "n" : "");
+			/* Make sure that the minor numbers corresponding to the four
+			   first modes always get the same names */
+			i = mode << (4 - ST_NBR_MODE_BITS);
+			snprintf(cdev->kobj.name, KOBJ_NAME_LEN, "%s%s%s", j ? "n" : "",
+				 disk->disk_name, st_formats[i]);
 			cdev->owner = THIS_MODULE;
 			cdev->ops = &st_fops;
 
@@ -3909,22 +3920,26 @@ static int st_probe(struct device *dev)
 	}
 
 	for (mode = 0; mode < ST_NBR_MODES; ++mode) {
+		/* Make sure that the minor numbers corresponding to the four
+		   first modes always get the same names */
+		i = mode << (4 - ST_NBR_MODE_BITS);
 		/*  Rewind entry  */
-		devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5)),
+		devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, 0)),
 			      S_IFCHR | S_IRUGO | S_IWUGO,
-			      "%s/mt%s", SDp->devfs_name, st_formats[mode]);
+			      "%s/mt%s", SDp->devfs_name, st_formats[i]);
 		/*  No-rewind entry  */
-		devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5) + 128),
+		devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, 1)),
 			      S_IFCHR | S_IRUGO | S_IWUGO,
-			      "%s/mt%sn", SDp->devfs_name, st_formats[mode]);
+			      "%s/mt%sn", SDp->devfs_name, st_formats[i]);
 	}
 	disk->number = devfs_register_tape(SDp->devfs_name);
 
 	printk(KERN_WARNING
 	"Attached scsi tape %s at scsi%d, channel %d, id %d, lun %d\n",
 	       tape_name(tpnt), SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
-	printk(KERN_WARNING "%s: try direct i/o: %s, max page reachable by HBA %lu\n",
-	       tape_name(tpnt), tpnt->try_dio ? "yes" : "no", tpnt->max_pfn);
+	printk(KERN_WARNING "%s: try direct i/o: %s (alignment %d B), max page reachable by HBA %lu\n",
+	       tape_name(tpnt), tpnt->try_dio ? "yes" : "no",
+	       queue_dma_alignment(SDp->request_queue) + 1, tpnt->max_pfn);
 
 	return 0;
 
@@ -3977,8 +3992,9 @@ static int st_remove(struct device *dev)
 			sysfs_remove_link(&tpnt->device->sdev_gendev.kobj,
 					  "tape");
 			for (mode = 0; mode < ST_NBR_MODES; ++mode) {
-				devfs_remove("%s/mt%s", SDp->devfs_name, st_formats[mode]);
-				devfs_remove("%s/mt%sn", SDp->devfs_name, st_formats[mode]);
+				j = mode << (4 - ST_NBR_MODE_BITS);
+				devfs_remove("%s/mt%s", SDp->devfs_name, st_formats[j]);
+				devfs_remove("%s/mt%sn", SDp->devfs_name, st_formats[j]);
 				for (j=0; j < 2; j++) {
 					class_simple_device_remove(MKDEV(SCSI_TAPE_MAJOR,
 									 TAPE_MINOR(i, mode, j)));
--- diff/drivers/scsi/st.h	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/scsi/st.h	2004-03-09 11:51:50.000000000 +0000
@@ -50,6 +50,8 @@ typedef struct {
 	struct cdev *cdevs[2];  /* Auto-rewind and non-rewind devices */
 } ST_mode;
 
+/* Number of modes can be changed by changing ST_NBR_MODE_BITS. The maximum
+   number of modes is 16 (ST_NBR_MODE_BITS 4) */
 #define ST_NBR_MODE_BITS 2
 #define ST_NBR_MODES (1 << ST_NBR_MODE_BITS)
 #define ST_MODE_SHIFT (7 - ST_NBR_MODE_BITS)
--- diff/drivers/scsi/sym53c8xx_2/sym_glue.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/scsi/sym53c8xx_2/sym_glue.c	2004-03-09 11:51:50.000000000 +0000
@@ -212,17 +212,32 @@ static int __map_scsi_sg_data(struct pci
 	return use_sg;
 }
 
-static void __sync_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
+static void __sync_scsi_data_for_cpu(struct pci_dev *pdev, struct scsi_cmnd *cmd)
 {
 	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
 
 	switch(SYM_UCMD_PTR(cmd)->data_mapped) {
 	case 2:
-		pci_dma_sync_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+		pci_dma_sync_sg_for_cpu(pdev, cmd->buffer, cmd->use_sg, dma_dir);
 		break;
 	case 1:
-		pci_dma_sync_single(pdev, SYM_UCMD_PTR(cmd)->data_mapping,
-				    cmd->request_bufflen, dma_dir);
+		pci_dma_sync_single_for_cpu(pdev, SYM_UCMD_PTR(cmd)->data_mapping,
+					    cmd->request_bufflen, dma_dir);
+		break;
+	}
+}
+
+static void __sync_scsi_data_for_device(struct pci_dev *pdev, struct scsi_cmnd *cmd)
+{
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+	switch(SYM_UCMD_PTR(cmd)->data_mapped) {
+	case 2:
+		pci_dma_sync_sg_for_device(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+		break;
+	case 1:
+		pci_dma_sync_single_for_device(pdev, SYM_UCMD_PTR(cmd)->data_mapping,
+					       cmd->request_bufflen, dma_dir);
 		break;
 	}
 }
@@ -233,8 +248,10 @@ static void __sync_scsi_data(struct pci_
 		__map_scsi_single_data(np->s.device, cmd)
 #define map_scsi_sg_data(np, cmd)	\
 		__map_scsi_sg_data(np->s.device, cmd)
-#define sync_scsi_data(np, cmd)		\
-		__sync_scsi_data(np->s.device, cmd)
+#define sync_scsi_data_for_cpu(np, cmd)		\
+		__sync_scsi_data_for_cpu(np->s.device, cmd)
+#define sync_scsi_data_for_device(np, cmd)		\
+		__sync_scsi_data_for_device(np->s.device, cmd)
 
 /*
  *  Complete a pending CAM CCB.
@@ -394,10 +411,11 @@ void sym_sniff_inquiry(struct sym_hcb *n
 	if (!cmd || cmd->use_sg)
 		return;
 
-	sync_scsi_data(np, cmd);
+	sync_scsi_data_for_cpu(np, cmd);
 	retv = __sym_sniff_inquiry(np, cmd->device->id, cmd->device->lun,
 				   (u_char *) cmd->request_buffer,
 				   cmd->request_bufflen - resid);
+	sync_scsi_data_for_device(np, cmd);
 	if (retv < 0)
 		return;
 	else if (retv)
--- diff/drivers/scsi/sym53c8xx_comm.h	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/scsi/sym53c8xx_comm.h	2004-03-09 11:51:50.000000000 +0000
@@ -703,7 +703,8 @@ static m_addr_t __vtobus(m_bush_t bush, 
 #define __unmap_scsi_data(dev, cmd)	do {; } while (0)
 #define __map_scsi_single_data(dev, cmd) (__vtobus(dev,(cmd)->request_buffer))
 #define __map_scsi_sg_data(dev, cmd)	((cmd)->use_sg)
-#define __sync_scsi_data(dev, cmd)	do {; } while (0)
+#define __sync_scsi_data_for_cpu(dev, cmd)	do {; } while (0)
+#define __sync_scsi_data_for_device(dev, cmd)	do {; } while (0)
 
 #define scsi_sg_dma_address(sc)		vtobus((sc)->address)
 #define scsi_sg_dma_len(sc)		((sc)->length)
@@ -767,18 +768,34 @@ static int __map_scsi_sg_data(struct dev
 	return use_sg;
 }
 
-static void __sync_scsi_data(struct device *dev, Scsi_Cmnd *cmd)
+static void __sync_scsi_data_for_cpu(struct device *dev, Scsi_Cmnd *cmd)
 {
 	enum dma_data_direction dma_dir = 
 		(enum dma_data_direction)scsi_to_pci_dma_dir(cmd->sc_data_direction);
 
 	switch(cmd->__data_mapped) {
 	case 2:
-		dma_sync_sg(dev, cmd->buffer, cmd->use_sg, dma_dir);
+		dma_sync_sg_for_cpu(dev, cmd->buffer, cmd->use_sg, dma_dir);
 		break;
 	case 1:
-		dma_sync_single(dev, cmd->__data_mapping,
-				cmd->request_bufflen, dma_dir);
+		dma_sync_single_for_cpu(dev, cmd->__data_mapping,
+					cmd->request_bufflen, dma_dir);
+		break;
+	}
+}
+
+static void __sync_scsi_data_for_device(struct device *dev, Scsi_Cmnd *cmd)
+{
+	enum dma_data_direction dma_dir =
+		(enum dma_data_direction)scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+	switch(cmd->__data_mapped) {
+	case 2:
+		dma_sync_sg_for_device(dev, cmd->buffer, cmd->use_sg, dma_dir);
+		break;
+	case 1:
+		dma_sync_single_for_device(dev, cmd->__data_mapping,
+					   cmd->request_bufflen, dma_dir);
 		break;
 	}
 }
@@ -791,7 +808,8 @@ static void __sync_scsi_data(struct devi
 #define unmap_scsi_data(np, cmd)	__unmap_scsi_data(np->dev, cmd)
 #define map_scsi_single_data(np, cmd)	__map_scsi_single_data(np->dev, cmd)
 #define map_scsi_sg_data(np, cmd)	__map_scsi_sg_data(np->dev, cmd)
-#define sync_scsi_data(np, cmd)		__sync_scsi_data(np->dev, cmd)
+#define sync_scsi_data_for_cpu(np, cmd)	__sync_scsi_data_for_cpu(np->dev, cmd)
+#define sync_scsi_data_for_device(np, cmd) __sync_scsi_data_for_device(np->dev, cmd)
 
 /*==========================================================
 **
--- diff/drivers/scsi/u14-34f.c	2003-08-20 14:16:13.000000000 +0100
+++ source/drivers/scsi/u14-34f.c	2004-03-09 11:51:50.000000000 +0000
@@ -1184,17 +1184,17 @@ static void sync_dma(unsigned int i, uns
    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),
+      pci_dma_sync_single_for_cpu(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,
+      pci_dma_sync_sg_for_cpu(HD(j)->pdev, SCpnt->request_buffer,
                          SCpnt->use_sg, pci_dir);
 
    if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL;
 
    if (DEV2H(cpp->data_address))
-      pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address),
+      pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->data_address),
                        DEV2H(cpp->data_len), pci_dir);
 }
 
--- diff/drivers/serial/8250.c	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/serial/8250.c	2004-03-09 11:51:50.000000000 +0000
@@ -16,12 +16,8 @@
  *
  * A note about mapbase / membase
  *
- *  mapbase is the physical address of the IO port.  Currently, we don't
- *  support this very well, and it may well be dropped from this driver
- *  in future.  As such, mapbase should be NULL.
- *
- *  membase is an 'ioremapped' cookie.  This is compatible with the old
- *  serial.c driver, and is currently the preferred form.
+ *  mapbase is the physical address of the IO port.
+ *  membase is an 'ioremapped' cookie.
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -837,7 +833,7 @@ receive_chars(struct uart_8250_port *up,
 		if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
 			tty->flip.work.func((void *)tty);
 			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-				return; // if TTY_DONT_FLIP is set
+				return;	/* if TTY_DONT_FLIP is set */
 		}
 		ch = serial_inp(up, UART_RX);
 		*tty->flip.char_buf_ptr = ch;
@@ -1198,12 +1194,21 @@ static void serial8250_break_ctl(struct 
 	spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
+#ifdef CONFIG_KGDB
+static int kgdb_irq = -1;
+#endif
+
 static int serial8250_startup(struct uart_port *port)
 {
 	struct uart_8250_port *up = (struct uart_8250_port *)port;
 	unsigned long flags;
 	int retval;
 
+#ifdef CONFIG_KGDB
+	if (up->port.irq == kgdb_irq)
+		return -EBUSY;
+#endif
+
 	up->capabilities = uart_config[up->port.type].flags;
 
 	if (up->port.type == PORT_16C950) {
@@ -1869,6 +1874,10 @@ static void __init serial8250_register_p
 	for (i = 0; i < UART_NR; i++) {
 		struct uart_8250_port *up = &serial8250_ports[i];
 
+#ifdef CONFIG_KGDB
+		if (up->port.irq == kgdb_irq)
+			up->port.kgdb = 1;
+#endif
 		up->port.line = i;
 		up->port.ops = &serial8250_pops;
 		init_timer(&up->timer);
@@ -1976,6 +1985,8 @@ static int __init serial8250_console_set
 	if (co->index >= UART_NR)
 		co->index = 0;
 	port = &serial8250_ports[co->index].port;
+	if (!port->ops)
+		return -ENODEV;
 
 	/*
 	 * Temporary fix.
@@ -2007,6 +2018,14 @@ static int __init serial8250_console_ini
 }
 console_initcall(serial8250_console_init);
 
+static int __init serial8250_late_console_init(void)
+{
+	if (!(serial8250_console.flags & CON_ENABLED))
+		register_console(&serial8250_console);
+	return 0;
+}
+late_initcall(serial8250_late_console_init);
+
 #define SERIAL8250_CONSOLE	&serial8250_console
 #else
 #define SERIAL8250_CONSOLE	NULL
@@ -2138,6 +2157,31 @@ void serial8250_resume_port(int line)
 	uart_resume_port(&serial8250_reg, &serial8250_ports[line].port);
 }
 
+#ifdef CONFIG_KGDB
+/*
+ * Find all the ports using the given irq and shut them down.
+ * Result should be that the irq will be released.
+ */
+void shutdown_for_kgdb(struct async_struct * info)
+{
+        int irq = info->state->irq;
+        struct uart_8250_port *up;
+	int ttyS;
+
+	kgdb_irq = irq;			/* save for later init */
+	for (ttyS = 0; ttyS < UART_NR; ttyS++){
+		up =  &serial8250_ports[ttyS];
+		if (up->port.irq == irq && (irq_lists + irq)->head) {
+#ifdef CONFIG_DEBUG_SPINLOCK   /* ugly business... */
+			if(up->port.lock.magic != SPINLOCK_MAGIC)
+				spin_lock_init(&up->port.lock);
+#endif
+			serial8250_shutdown(&up->port);
+		}
+        }
+}
+#endif	/* CONFIG_KGDB */
+
 static int __init serial8250_init(void)
 {
 	int ret, i;
--- diff/drivers/serial/8250_pci.c	2004-02-18 08:54:11.000000000 +0000
+++ source/drivers/serial/8250_pci.c	2004-03-09 11:51:50.000000000 +0000
@@ -145,8 +145,10 @@ afavlab_setup(struct pci_dev *dev, struc
 	bar = FL_GET_BASE(board->flags);
 	if (idx < 4)
 		bar += idx;
-	else
+	else {
+		bar = 4;
 		offset += (idx - 4) * board->uart_offset;
+	}
 
 	return setup_port(dev, req, bar, offset, board->reg_shift);
 }
@@ -1772,7 +1774,7 @@ static struct pci_device_id serial_pci_t
 		pbn_b0_4_115200 },
 	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
-		pbn_b0_2_115200 },
+		pbn_b0_bt_2_921600 },
 
 	/*
 	 * Digitan DS560-558, from jimd@esoft.com
@@ -1891,6 +1893,9 @@ static struct pci_device_id serial_pci_t
 	{	PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 		pbn_b0_bt_8_115200 },
+	{	PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P030,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_8_115200 },
 
 	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
--- diff/drivers/serial/Kconfig	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/serial/Kconfig	2004-03-09 11:51:50.000000000 +0000
@@ -250,12 +250,6 @@ config SERIAL_CLPS711X_CONSOLE
 	  your boot loader (lilo or loadlin) about how to pass options to the
 	  kernel at boot time.)
 
-config SERIAL_CLPS711X_OLD_NAME
-	bool "Use the old 2.4 names for CLPS711X serial port"
-	depends on SERIAL_CLPS711X=y
-	help
-	  ::: To be written :::
-
 config SERIAL_DZ
 	bool "DECstation DZ serial driver"
 	depends on DECSTATION
--- diff/drivers/serial/clps711x.c	2003-09-30 15:46:17.000000000 +0100
+++ source/drivers/serial/clps711x.c	2004-03-09 11:51:50.000000000 +0000
@@ -49,19 +49,10 @@
 
 #define UART_NR		2
 
-#ifndef CONFIG_SERIAL_CLPS711X_OLD_NAME
 #define SERIAL_CLPS711X_MAJOR	204
 #define SERIAL_CLPS711X_MINOR	40
 #define SERIAL_CLPS711X_NR	UART_NR
 
-#else
-#warning The old names/device number for this driver if compatabity is needed
-#define SERIAL_CLPS711X_MAJOR   204
-#define SERIAL_CLPS711X_MINOR   16
-#define SERIAL_CLPS711X_NR      UART_NR
-
-#endif
-
 /*
  * We use the relevant SYSCON register as a base address for these ports.
  */
--- diff/drivers/serial/serial_core.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/serial/serial_core.c	2004-03-09 11:51:50.000000000 +0000
@@ -175,8 +175,6 @@ static int uart_startup(struct uart_stat
 		uart_circ_clear(&info->xmit);
 	}
 
-	port->mctrl = 0;
-
 	retval = port->ops->startup(port);
 	if (retval == 0) {
 		if (init_hw) {
@@ -1874,9 +1872,6 @@ uart_set_options(struct uart_port *port,
 	if (flow == 'r')
 		termios.c_cflag |= CRTSCTS;
 
-	if (!port->ops)
-		return 0;	/* "console=" on ia64 */
-
 	port->ops->set_termios(port, &termios, NULL);
 	co->cflag = termios.c_cflag;
 
@@ -1990,6 +1985,11 @@ uart_configure_port(struct uart_driver *
 {
 	unsigned int flags;
 
+#ifdef CONFIG_KGDB
+	if (port->kgdb)
+		return;
+#endif
+
 	/*
 	 * If there isn't a port here, don't do anything further.
 	 */
--- diff/drivers/usb/Makefile	2004-02-18 08:54:11.000000000 +0000
+++ source/drivers/usb/Makefile	2004-03-09 11:51:50.000000000 +0000
@@ -20,10 +20,15 @@ obj-$(CONFIG_USB_PRINTER)	+= class/
 obj-$(CONFIG_USB_STORAGE)	+= storage/
 
 obj-$(CONFIG_USB_AIPTEK)	+= input/
+obj-$(CONFIG_USB_ATI_REMOTE)	+= input/
 obj-$(CONFIG_USB_HID)		+= input/
 obj-$(CONFIG_USB_KBD)		+= input/
+obj-$(CONFIG_USB_KBTAB)		+= input/
 obj-$(CONFIG_USB_MOUSE)		+= input/
+obj-$(CONFIG_USB_MTOUCH)	+= input/
+obj-$(CONFIG_USB_POWERMATE)	+= input/
 obj-$(CONFIG_USB_WACOM)		+= input/
+obj-$(CONFIG_USB_XPAD)		+= input/
 
 obj-$(CONFIG_USB_DABUSB)	+= media/
 obj-$(CONFIG_USB_DSBR)		+= media/
--- diff/drivers/usb/class/audio.c	2004-02-18 08:54:11.000000000 +0000
+++ source/drivers/usb/class/audio.c	2004-03-09 11:51:50.000000000 +0000
@@ -3,7 +3,7 @@
 /*
  *	audio.c  --  USB Audio Class driver
  *
- *	Copyright (C) 1999, 2000, 2001
+ *	Copyright (C) 1999, 2000, 2001, 2003, 2004
  *	    Alan Cox (alan@lxorguk.ukuu.org.uk)
  *	    Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
@@ -101,6 +101,8 @@
  *              Fix SNDCTL_DSP_STEREO API violation
  * 2003-04-08:	Oliver Neukum (oliver@neukum.name):
  *		Setting a configuration is done by usbcore and must not be overridden
+ * 2004-02-27:  Workaround for broken synch descriptors
+ * 
  */
 
 /*
@@ -1542,12 +1544,13 @@ static int set_format_in(struct usb_audi
 		    alts->endpoint[1].desc.bmAttributes != 0x01 ||
 		    alts->endpoint[1].desc.bSynchAddress != 0 ||
 		    alts->endpoint[1].desc.bEndpointAddress != (alts->endpoint[0].desc.bSynchAddress & 0x7f)) {
-			printk(KERN_ERR "usbaudio: device %d interface %d altsetting %d invalid synch pipe\n",
+			printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims adaptive in "
+			       "but has invalid synch pipe; treating as asynchronous in\n",
 			       dev->devnum, u->interface, fmt->altsetting);
-			return -1;
+		} else {
+			u->syncpipe = usb_sndisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf);
+			u->syncinterval = alts->endpoint[1].desc.bRefresh;
 		}
-		u->syncpipe = usb_sndisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf);
-		u->syncinterval = alts->endpoint[1].desc.bRefresh;
 	}
 	if (d->srate < fmt->sratelo)
 		d->srate = fmt->sratelo;
@@ -1637,12 +1640,13 @@ static int set_format_out(struct usb_aud
 		    alts->endpoint[1].desc.bmAttributes != 0x01 ||
 		    alts->endpoint[1].desc.bSynchAddress != 0 ||
 		    alts->endpoint[1].desc.bEndpointAddress != (alts->endpoint[0].desc.bSynchAddress | 0x80)) {
-			printk(KERN_ERR "usbaudio: device %d interface %d altsetting %d invalid synch pipe\n",
+			printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims asynch out "
+			       "but has invalid synch pipe; treating as adaptive out\n",
 			       dev->devnum, u->interface, fmt->altsetting);
-			return -1;
+		} else {
+			u->syncpipe = usb_rcvisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf);
+			u->syncinterval = alts->endpoint[1].desc.bRefresh;
 		}
-		u->syncpipe = usb_rcvisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf);
-		u->syncinterval = alts->endpoint[1].desc.bRefresh;
 	}
 	if (d->srate < fmt->sratelo)
 		d->srate = fmt->sratelo;
--- diff/drivers/usb/core/config.c	2003-09-30 15:46:17.000000000 +0100
+++ source/drivers/usb/core/config.c	2004-03-09 11:51:50.000000000 +0000
@@ -72,13 +72,10 @@ static int usb_parse_endpoint(struct usb
 	return buffer - buffer0;
 }
 
-static void usb_release_intf(struct device *dev)
+static void usb_free_intf(struct usb_interface *intf)
 {
-	struct usb_interface *intf;
 	int j;
 
-	intf = to_usb_interface(dev);
-
 	if (intf->altsetting) {
 		for (j = 0; j < intf->num_altsetting; j++) {
 			struct usb_host_interface *as = &intf->altsetting[j];
@@ -235,8 +232,6 @@ int usb_parse_configuration(struct usb_h
 			return -ENOMEM;
 		}
 		memset(interface, 0, sizeof(struct usb_interface));
-		interface->dev.release = usb_release_intf;
-		device_initialize(&interface->dev);
 	}
 
 	/* Go through the descriptors, checking their length and counting the
@@ -374,7 +369,7 @@ void usb_destroy_configuration(struct us
 			struct usb_interface *ifp = cf->interface[i];
 
 			if (ifp)
-				put_device(&ifp->dev);
+				usb_free_intf(ifp);
 		}
 	}
 	kfree(dev->config);
--- diff/drivers/usb/core/devio.c	2003-12-19 09:51:11.000000000 +0000
+++ source/drivers/usb/core/devio.c	2004-03-09 11:51:50.000000000 +0000
@@ -430,19 +430,14 @@ static int findintfep(struct usb_device 
 
 static int findintfif(struct usb_device *dev, unsigned int ifn)
 {
-	unsigned int i, j;
-        struct usb_interface *iface;
-	struct usb_host_interface *alts;
+	unsigned int i;
 
 	if (ifn & ~0xff)
 		return -EINVAL;
 	for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
-		iface = dev->actconfig->interface[i];
-		for (j = 0; j < iface->num_altsetting; j++) {
-                        alts = &iface->altsetting[j];
-			if (alts->desc.bInterfaceNumber == ifn)
-				return i;
-		}
+		if (dev->actconfig->interface[i]->
+				altsetting[0].desc.bInterfaceNumber == ifn)
+			return i;
 	}
 	return -ENOENT; 
 }
@@ -688,9 +683,7 @@ static int proc_getdriver(struct dev_sta
 		return -EFAULT;
 	if ((ret = findintfif(ps->dev, gd.interface)) < 0)
 		return ret;
-	interface = usb_ifnum_to_if(ps->dev, gd.interface);
-	if (!interface)
-		return -EINVAL;
+	interface = ps->dev->actconfig->interface[ret];
 	if (!interface->driver)
 		return -ENODATA;
 	strcpy(gd.driver, interface->driver->name);
@@ -744,9 +737,7 @@ static int proc_setintf(struct dev_state
 		return -EFAULT;
 	if ((ret = findintfif(ps->dev, setintf.interface)) < 0)
 		return ret;
-	interface = usb_ifnum_to_if(ps->dev, setintf.interface);
-	if (!interface)
-		return -EINVAL;
+	interface = ps->dev->actconfig->interface[ret];
 	if (interface->driver) {
 		if ((ret = checkintf(ps, ret)))
 			return ret;
--- diff/drivers/usb/core/driverfs.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/core/driverfs.c	2004-03-09 11:51:50.000000000 +0000
@@ -166,13 +166,9 @@ void usb_create_driverfs_dev_files (stru
 static ssize_t								\
 show_##field (struct device *dev, char *buf)				\
 {									\
-	struct usb_interface *intf;					\
-	int alt;							\
+	struct usb_interface *intf = to_usb_interface (dev);		\
 									\
-	intf = to_usb_interface (dev);					\
-	alt = intf->act_altsetting;					\
-									\
-	return sprintf (buf, format_string, intf->altsetting[alt].desc.field); \
+	return sprintf (buf, format_string, intf->cur_altsetting->desc.field); \
 }									\
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 
--- diff/drivers/usb/core/hcd-pci.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/usb/core/hcd-pci.c	2004-03-09 11:51:50.000000000 +0000
@@ -147,8 +147,12 @@ clean_2:
 	hcd->driver = driver;
 	hcd->description = driver->description;
 	hcd->self.bus_name = pci_name(dev);
+#ifdef CONFIG_PCI_NAMES
+	hcd->product_desc = dev->pretty_name;
+#else
 	if (hcd->product_desc == NULL)
 		hcd->product_desc = "USB Host Controller";
+#endif
 	hcd->self.controller = &dev->dev;
 
 	if ((retval = hcd_buffer_create (hcd)) != 0) {
--- diff/drivers/usb/core/hub.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/usb/core/hub.c	2004-03-09 11:51:50.000000000 +0000
@@ -560,7 +560,7 @@ static int hub_probe(struct usb_interfac
 	struct usb_hub *hub;
 	unsigned long flags;
 
-	desc = intf->altsetting + intf->act_altsetting;
+	desc = intf->cur_altsetting;
 	dev = interface_to_usbdev(intf);
 
 	/* Some hubs have a subclass of 1, which AFAICT according to the */
@@ -1344,15 +1344,15 @@ int usb_physical_reset_device(struct usb
 
 	for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
 		struct usb_interface *intf = dev->actconfig->interface[i];
-		struct usb_interface_descriptor *as;
+		struct usb_interface_descriptor *desc;
 
-		as = &intf->altsetting[intf->act_altsetting].desc;
-		ret = usb_set_interface(dev, as->bInterfaceNumber,
-			as->bAlternateSetting);
+		desc = &intf->cur_altsetting->desc;
+		ret = usb_set_interface(dev, desc->bInterfaceNumber,
+			desc->bAlternateSetting);
 		if (ret < 0) {
 			err("failed to set active alternate setting "
 				"for dev %s interface %d (error=%d)",
-				dev->devpath, i, ret);
+				dev->devpath, desc->bInterfaceNumber, ret);
 			return ret;
 		}
 	}
--- diff/drivers/usb/core/message.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/usb/core/message.c	2004-03-09 11:51:50.000000000 +0000
@@ -783,16 +783,22 @@ void usb_disable_endpoint(struct usb_dev
  */
 void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf)
 {
-	struct usb_host_interface *hintf =
-			&intf->altsetting[intf->act_altsetting];
+	struct usb_host_interface *alt = intf->cur_altsetting;
 	int i;
 
-	for (i = 0; i < hintf->desc.bNumEndpoints; ++i) {
+	for (i = 0; i < alt->desc.bNumEndpoints; ++i) {
 		usb_disable_endpoint(dev,
-				hintf->endpoint[i].desc.bEndpointAddress);
+				alt->endpoint[i].desc.bEndpointAddress);
 	}
 }
 
+static void release_interface(struct device *dev)
+{
+	struct usb_interface *interface = to_usb_interface(dev);
+
+	complete(interface->released);
+}
+
 /*
  * usb_disable_device - Disable all the endpoints for a USB device
  * @dev: the device whose endpoints are being disabled
@@ -822,12 +828,16 @@ void usb_disable_device(struct usb_devic
 	if (dev->actconfig) {
 		for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
 			struct usb_interface	*interface;
+			struct completion	intf_completion;
 
 			/* remove this interface */
 			interface = dev->actconfig->interface[i];
 			dev_dbg (&dev->dev, "unregistering interface %s\n",
 				interface->dev.bus_id);
-			device_del(&interface->dev);
+			init_completion (&intf_completion);
+			interface->released = &intf_completion;
+			device_unregister (&interface->dev);
+			wait_for_completion (&intf_completion);
 		}
 		dev->actconfig = 0;
 		if (dev->state == USB_STATE_CONFIGURED)
@@ -876,12 +886,11 @@ void usb_enable_endpoint(struct usb_devi
 void usb_enable_interface(struct usb_device *dev,
 		struct usb_interface *intf)
 {
-	struct usb_host_interface *hintf =
-			&intf->altsetting[intf->act_altsetting];
+	struct usb_host_interface *alt = intf->cur_altsetting;
 	int i;
 
-	for (i = 0; i < hintf->desc.bNumEndpoints; ++i)
-		usb_enable_endpoint(dev, &hintf->endpoint[i].desc);
+	for (i = 0; i < alt->desc.bNumEndpoints; ++i)
+		usb_enable_endpoint(dev, &alt->endpoint[i].desc);
 }
 
 /**
@@ -920,6 +929,7 @@ void usb_enable_interface(struct usb_dev
 int usb_set_interface(struct usb_device *dev, int interface, int alternate)
 {
 	struct usb_interface *iface;
+	struct usb_host_interface *alt;
 	int ret;
 	int manual = 0;
 
@@ -929,14 +939,15 @@ int usb_set_interface(struct usb_device 
 		return -EINVAL;
 	}
 
-	if (alternate < 0 || alternate >= iface->num_altsetting)
+	alt = usb_altnum_to_altsetting(iface, alternate);
+	if (!alt) {
+		warn("selecting invalid altsetting %d", alternate);
 		return -EINVAL;
+	}
 
 	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 				   USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE,
-				   iface->altsetting[alternate]
-				   	.desc.bAlternateSetting,
-				   interface, NULL, 0, HZ * 5);
+				   alternate, interface, NULL, 0, HZ * 5);
 
 	/* 9.4.10 says devices don't need this and are free to STALL the
 	 * request if the interface only has one alternate setting.
@@ -957,7 +968,7 @@ int usb_set_interface(struct usb_device 
 	/* prevent submissions using previous endpoint settings */
 	usb_disable_interface(dev, iface);
 
-	iface->act_altsetting = alternate;
+	iface->cur_altsetting = alt;
 
 	/* If the interface only has one altsetting and the device didn't
 	 * accept the request, we attempt to carry out the equivalent action
@@ -965,13 +976,11 @@ int usb_set_interface(struct usb_device 
 	 * new altsetting.
 	 */
 	if (manual) {
-		struct usb_host_interface *iface_as =
-				&iface->altsetting[alternate];
 		int i;
 
-		for (i = 0; i < iface_as->desc.bNumEndpoints; i++) {
+		for (i = 0; i < alt->desc.bNumEndpoints; i++) {
 			unsigned int epaddr =
-				iface_as->endpoint[i].desc.bEndpointAddress;
+				alt->endpoint[i].desc.bEndpointAddress;
 			unsigned int pipe =
 	__create_pipe(dev, USB_ENDPOINT_NUMBER_MASK & epaddr)
 	| (usb_endpoint_out(epaddr) ? USB_DIR_OUT : USB_DIR_IN);
@@ -1045,8 +1054,19 @@ int usb_reset_configuration(struct usb_d
 	/* re-init hc/hcd interface/endpoint state */
 	for (i = 0; i < config->desc.bNumInterfaces; i++) {
 		struct usb_interface *intf = config->interface[i];
+		struct usb_host_interface *alt;
+
+		alt = usb_altnum_to_altsetting(intf, 0);
 
-		intf->act_altsetting = 0;
+		/* No altsetting 0?  We'll assume the first altsetting.
+		 * We could use a GetInterface call, but if a device is
+		 * so non-compliant that it doesn't have altsetting 0
+		 * then I wouldn't trust its reply anyway.
+		 */
+		if (!alt)
+			alt = &intf->altsetting[0];
+
+		intf->cur_altsetting = alt;
 		usb_enable_interface(dev, intf);
 	}
 	return 0;
@@ -1135,25 +1155,34 @@ int usb_set_configuration(struct usb_dev
 		 */
 		for (i = 0; i < cp->desc.bNumInterfaces; ++i) {
 			struct usb_interface *intf = cp->interface[i];
-			struct usb_interface_descriptor *desc;
+			struct usb_host_interface *alt;
 
-			intf->act_altsetting = 0;
-			desc = &intf->altsetting [0].desc;
-			usb_enable_interface(dev, intf);
+			alt = usb_altnum_to_altsetting(intf, 0);
 
+			/* No altsetting 0?  We'll assume the first altsetting.
+			 * We could use a GetInterface call, but if a device is
+			 * so non-compliant that it doesn't have altsetting 0
+			 * then I wouldn't trust its reply anyway.
+			 */
+			if (!alt)
+				alt = &intf->altsetting[0];
+
+			intf->cur_altsetting = alt;
+			usb_enable_interface(dev, intf);
 			intf->dev.parent = &dev->dev;
 			intf->dev.driver = NULL;
 			intf->dev.bus = &usb_bus_type;
 			intf->dev.dma_mask = dev->dev.dma_mask;
+			intf->dev.release = release_interface;
 			sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
 				 dev->bus->busnum, dev->devpath,
 				 configuration,
-				 desc->bInterfaceNumber);
+				 alt->desc.bInterfaceNumber);
 			dev_dbg (&dev->dev,
 				"registering %s (config #%d, interface %d)\n",
 				intf->dev.bus_id, configuration,
-				desc->bInterfaceNumber);
-			device_add (&intf->dev);
+				alt->desc.bInterfaceNumber);
+			device_register (&intf->dev);
 			usb_create_driverfs_intf_files (intf);
 		}
 	}
--- diff/drivers/usb/core/usb.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/usb/core/usb.c	2004-03-09 11:51:50.000000000 +0000
@@ -189,7 +189,7 @@ void usb_deregister(struct usb_driver *d
 }
 
 /**
- * usb_ifnum_to_if - get the interface object with a given interface number (usbcore-internal)
+ * usb_ifnum_to_if - get the interface object with a given interface number
  * @dev: the device whose current configuration is considered
  * @ifnum: the desired interface
  *
@@ -220,6 +220,33 @@ struct usb_interface *usb_ifnum_to_if(st
 }
 
 /**
+ * usb_altnum_to_altsetting - get the altsetting structure with a given
+ *	alternate setting number.
+ * @intf: the interface containing the altsetting in question
+ * @altnum: the desired alternate setting number
+ *
+ * This searches the altsetting array of the specified interface for
+ * an entry with the correct bAlternateSetting value and returns a pointer
+ * to that entry, or null.
+ *
+ * Note that altsettings need not be stored sequentially by number, so
+ * it would be incorrect to assume that the first altsetting entry in
+ * the array corresponds to altsetting zero.  This routine helps device
+ * drivers avoid such mistakes.
+ */
+struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf,
+		unsigned int altnum)
+{
+	int i;
+
+	for (i = 0; i < intf->num_altsetting; i++) {
+		if (intf->altsetting[i].desc.bAlternateSetting == altnum)
+			return &intf->altsetting[i];
+	}
+	return NULL;
+}
+
+/**
  * usb_epnum_to_ep_desc - get the endpoint object with a given endpoint number
  * @dev: the device whose current configuration+altsettings is considered
  * @epnum: the desired endpoint, masked with USB_DIR_IN as appropriate.
@@ -247,7 +274,7 @@ usb_epnum_to_ep_desc(struct usb_device *
 
 		/* only endpoints in current altsetting are active */
 		intf = config->interface[i];
-		alt = intf->altsetting + intf->act_altsetting;
+		alt = intf->cur_altsetting;
 
 		for (k = 0; k < alt->desc.bNumEndpoints; k++)
 			if (epnum == alt->endpoint[k].desc.bEndpointAddress)
@@ -421,7 +448,7 @@ usb_match_id(struct usb_interface *inter
 	if (id == NULL)
 		return NULL;
 
-	intf = &interface->altsetting [interface->act_altsetting];
+	intf = interface->cur_altsetting;
 	dev = interface_to_usbdev(interface);
 
 	/* It is important to check that id->driver_info is nonzero,
@@ -624,7 +651,7 @@ static int usb_hotplug (struct device *d
 	scratch += length;
 
 	if (usb_dev->descriptor.bDeviceClass == 0) {
-		int alt = intf->act_altsetting;
+		struct usb_host_interface *alt = intf->cur_altsetting;
 
 		/* 2.4 only exposed interface zero.  in 2.5, hotplug
 		 * agents are called for all interfaces, and can use
@@ -633,9 +660,9 @@ static int usb_hotplug (struct device *d
 		envp [i++] = scratch;
 		length += snprintf (scratch, buffer_size - length,
 			    "INTERFACE=%d/%d/%d",
-			    intf->altsetting[alt].desc.bInterfaceClass,
-			    intf->altsetting[alt].desc.bInterfaceSubClass,
-			    intf->altsetting[alt].desc.bInterfaceProtocol);
+			    alt->desc.bInterfaceClass,
+			    alt->desc.bInterfaceSubClass,
+			    alt->desc.bInterfaceProtocol);
 		if ((buffer_size - length <= 0) || (i >= num_envp))
 			return -ENOMEM;
 		++length;
@@ -1297,6 +1324,13 @@ struct urb *usb_buffer_map (struct urb *
 	return urb;
 }
 
+/* XXX DISABLED, no users currently.  If you wish to re-enable this
+ * XXX please determine whether the sync is to transfer ownership of
+ * XXX the buffer from device to cpu or vice verse, and thusly use the
+ * XXX appropriate _for_{cpu,device}() method.  -DaveM
+ */
+#if 0
+
 /**
  * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s)
  * @urb: urb whose transfer_buffer/setup_packet will be synchronized
@@ -1325,6 +1359,7 @@ void usb_buffer_dmasync (struct urb *urb
 					DMA_TO_DEVICE);
 	}
 }
+#endif
 
 /**
  * usb_buffer_unmap - free DMA mapping(s) for an urb
@@ -1403,6 +1438,13 @@ int usb_buffer_map_sg (struct usb_device
 			usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
+/* XXX DISABLED, no users currently.  If you wish to re-enable this
+ * XXX please determine whether the sync is to transfer ownership of
+ * XXX the buffer from device to cpu or vice verse, and thusly use the
+ * XXX appropriate _for_{cpu,device}() method.  -DaveM
+ */
+#if 0
+
 /**
  * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s)
  * @dev: device to which the scatterlist will be mapped
@@ -1428,6 +1470,7 @@ void usb_buffer_dmasync_sg (struct usb_d
 	dma_sync_sg (controller, sg, n_hw_ents,
 			usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
+#endif
 
 /**
  * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
@@ -1582,6 +1625,7 @@ EXPORT_SYMBOL(usb_driver_release_interfa
 EXPORT_SYMBOL(usb_match_id);
 EXPORT_SYMBOL(usb_find_interface);
 EXPORT_SYMBOL(usb_ifnum_to_if);
+EXPORT_SYMBOL(usb_altnum_to_altsetting);
 
 EXPORT_SYMBOL(usb_reset_device);
 EXPORT_SYMBOL(usb_disconnect);
@@ -1595,11 +1639,15 @@ EXPORT_SYMBOL (usb_buffer_alloc);
 EXPORT_SYMBOL (usb_buffer_free);
 
 EXPORT_SYMBOL (usb_buffer_map);
+#if 0
 EXPORT_SYMBOL (usb_buffer_dmasync);
+#endif
 EXPORT_SYMBOL (usb_buffer_unmap);
 
 EXPORT_SYMBOL (usb_buffer_map_sg);
+#if 0
 EXPORT_SYMBOL (usb_buffer_dmasync_sg);
+#endif
 EXPORT_SYMBOL (usb_buffer_unmap_sg);
 
 MODULE_LICENSE("GPL");
--- diff/drivers/usb/gadget/Makefile	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/gadget/Makefile	2004-03-09 11:51:50.000000000 +0000
@@ -9,7 +9,7 @@ obj-$(CONFIG_USB_GOKU)		+= goku_udc.o
 # USB gadget drivers
 #
 g_zero-objs			:= zero.o usbstring.o
-g_ether-objs			:= ether.o usbstring.o
+g_ether-objs			:= ether.o usbstring.o config.o
 g_serial-objs			:= serial.o usbstring.o
 gadgetfs-objs			:= inode.o usbstring.o
 g_file_storage-objs		:= file_storage.o usbstring.o
--- diff/drivers/usb/gadget/ether.c	2004-02-18 08:54:11.000000000 +0000
+++ source/drivers/usb/gadget/ether.c	2004-03-09 11:51:50.000000000 +0000
@@ -607,6 +607,25 @@ fs_sink_desc = {
 	.wMaxPacketSize =	__constant_cpu_to_le16 (64),
 };
 
+static const struct usb_descriptor_header *fs_function [] = {
+#ifdef DEV_CONFIG_CDC
+	/* "cdc" mode descriptors */
+	(struct usb_descriptor_header *) &control_intf,
+	(struct usb_descriptor_header *) &header_desc,
+	(struct usb_descriptor_header *) &union_desc,
+	(struct usb_descriptor_header *) &ether_desc,
+#ifdef	EP_STATUS_NUM
+	(struct usb_descriptor_header *) &fs_status_desc,
+#endif
+	(struct usb_descriptor_header *) &data_nop_intf,
+#endif /* DEV_CONFIG_CDC */
+	/* minimalist core */
+	(struct usb_descriptor_header *) &data_intf,
+	(struct usb_descriptor_header *) &fs_source_desc,
+	(struct usb_descriptor_header *) &fs_sink_desc,
+	0,
+};
+
 #ifdef	HIGHSPEED
 
 /*
@@ -660,6 +679,25 @@ dev_qualifier = {
 	.bNumConfigurations =	1,
 };
 
+static const struct usb_descriptor_header *hs_function [] = {
+#ifdef DEV_CONFIG_CDC
+	/* "cdc" mode descriptors */
+	(struct usb_descriptor_header *) &control_intf,
+	(struct usb_descriptor_header *) &header_desc,
+	(struct usb_descriptor_header *) &union_desc,
+	(struct usb_descriptor_header *) &ether_desc,
+#ifdef	EP_STATUS_NUM
+	(struct usb_descriptor_header *) &hs_status_desc,
+#endif
+	(struct usb_descriptor_header *) &data_nop_intf,
+#endif /* DEV_CONFIG_CDC */
+	/* minimalist core */
+	(struct usb_descriptor_header *) &data_intf,
+	(struct usb_descriptor_header *) &hs_source_desc,
+	(struct usb_descriptor_header *) &hs_sink_desc,
+	0,
+};
+
 
 /* maxpacket and other transfer characteristics vary by speed. */
 #define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
@@ -704,86 +742,25 @@ static struct usb_gadget_strings	stringt
 static int
 config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index)
 {
-	const unsigned	config_len = USB_DT_CONFIG_SIZE
-#ifdef DEV_CONFIG_CDC
-				+ 2 * USB_DT_INTERFACE_SIZE
-				+ sizeof header_desc
-				+ sizeof union_desc
-				+ sizeof ether_desc
-#ifdef	EP_STATUS_NUM
-				+ USB_DT_ENDPOINT_SIZE
-#endif
-#endif /* DEV_CONFIG_CDC */
-				+ USB_DT_INTERFACE_SIZE
-				+ 2 * USB_DT_ENDPOINT_SIZE;
-
+	int				len;
+	const struct usb_descriptor_header **function = fs_function;
 #ifdef HIGHSPEED
-	int		hs;
-#endif
-	/* a single configuration must always be index 0 */
-	if (index > 0)
-		return -EINVAL;
-	if (config_len > USB_BUFSIZ)
-		return -EDOM;
+	int				hs = (speed == USB_SPEED_HIGH);
 
-	/* config (or other speed config) */
-	memcpy (buf, &eth_config, USB_DT_CONFIG_SIZE);
-	buf [1] = type;
-	((struct usb_config_descriptor *) buf)->wTotalLength
-		= __constant_cpu_to_le16 (config_len);
-	buf += USB_DT_CONFIG_SIZE;
-#ifdef	HIGHSPEED
-	hs = (speed == USB_SPEED_HIGH);
 	if (type == USB_DT_OTHER_SPEED_CONFIG)
 		hs = !hs;
-#endif
-
-#ifdef DEV_CONFIG_CDC
-	/* control interface, class descriptors, optional status endpoint */
-	memcpy (buf, &control_intf, USB_DT_INTERFACE_SIZE);
-	buf += USB_DT_INTERFACE_SIZE;
-
-	memcpy (buf, &header_desc, sizeof header_desc);
-	buf += sizeof header_desc;
-	memcpy (buf, &union_desc, sizeof union_desc);
-	buf += sizeof union_desc;
-	memcpy (buf, &ether_desc, sizeof ether_desc);
-	buf += sizeof ether_desc;
-
-#ifdef	EP_STATUS_NUM
-#ifdef	HIGHSPEED
 	if (hs)
-		memcpy (buf, &hs_status_desc, USB_DT_ENDPOINT_SIZE);
-	else
-#endif	/* HIGHSPEED */
-		memcpy (buf, &fs_status_desc, USB_DT_ENDPOINT_SIZE);
-	buf += USB_DT_ENDPOINT_SIZE;
-#endif	/* EP_STATUS_NUM */
-
-	/* default data altsetting has no endpoints */
-	memcpy (buf, &data_nop_intf, USB_DT_INTERFACE_SIZE);
-	buf += USB_DT_INTERFACE_SIZE;
-#endif /* DEV_CONFIG_CDC */
-
-	/* the "real" data interface has two endpoints */
-	memcpy (buf, &data_intf, USB_DT_INTERFACE_SIZE);
-	buf += USB_DT_INTERFACE_SIZE;
-#ifdef HIGHSPEED
-	if (hs) {
-		memcpy (buf, &hs_source_desc, USB_DT_ENDPOINT_SIZE);
-		buf += USB_DT_ENDPOINT_SIZE;
-		memcpy (buf, &hs_sink_desc, USB_DT_ENDPOINT_SIZE);
-		buf += USB_DT_ENDPOINT_SIZE;
-	} else
+		function = hs_function;
 #endif
-	{
-		memcpy (buf, &fs_source_desc, USB_DT_ENDPOINT_SIZE);
-		buf += USB_DT_ENDPOINT_SIZE;
-		memcpy (buf, &fs_sink_desc, USB_DT_ENDPOINT_SIZE);
-		buf += USB_DT_ENDPOINT_SIZE;
-	}
 
-	return config_len;
+	/* a single configuration must always be index 0 */
+	if (index > 0)
+		return -EINVAL;
+	len = usb_gadget_config_buf (&eth_config, buf, USB_BUFSIZ, function);
+	if (len < 0)
+		return len;
+	((struct usb_config_descriptor *) buf)->bDescriptorType = type;
+	return len;
 }
 
 /*-------------------------------------------------------------------------*/
--- diff/drivers/usb/gadget/inode.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/gadget/inode.c	2004-03-09 11:51:50.000000000 +0000
@@ -1812,7 +1812,6 @@ gadgetfs_fill_super (struct super_block 
 		return -ENOMEM;
 	inode->i_op = &simple_dir_inode_operations;
 	if (!(d = d_alloc_root (inode))) {
-enomem:
 		iput (inode);
 		return -ENOMEM;
 	}
@@ -1823,12 +1822,15 @@ enomem:
 	 */
 	dev = dev_new ();
 	if (!dev)
-		goto enomem;
+		return -ENOMEM;
+
 	dev->sb = sb;
 	if (!(inode = gadgetfs_create_file (sb, CHIP,
 				dev, &dev_init_operations,
-				&dev->dentry)))
-		goto enomem;
+				&dev->dentry))) {
+		put_dev(dev);
+		return -ENOMEM;
+	}
 
 	/* other endpoint files are available after hardware setup,
 	 * from binding to a controller.
@@ -1849,8 +1851,10 @@ static void
 gadgetfs_kill_sb (struct super_block *sb)
 {
 	kill_litter_super (sb);
-	put_dev (the_device);
-	the_device = 0;
+	if (the_device) {
+		put_dev (the_device);
+		the_device = 0;
+	}
 }
 
 /*----------------------------------------------------------------------*/
--- diff/drivers/usb/gadget/usbstring.c	2003-06-09 14:18:19.000000000 +0100
+++ source/drivers/usb/gadget/usbstring.c	2004-03-09 11:51:50.000000000 +0000
@@ -16,24 +16,89 @@
 #include <linux/usb_ch9.h>
 #include <linux/usb_gadget.h>
 
+#include <asm/unaligned.h>
+
+
+static int utf8_to_utf16le(const char *s, u16 *cp, unsigned len)
+{
+	int	count = 0;
+	u8	c;
+	u16	uchar;
+
+	/* this insists on correct encodings, though not minimal ones.
+	 * BUT it currently rejects legit 4-byte UTF-8 code points,
+	 * which need surrogate pairs.  (Unicode 3.1 can use them.)
+	 */
+	while (len != 0 && (c = (u8) *s++) != 0) {
+		if (unlikely(c & 0x80)) {
+			// 2-byte sequence:
+			// 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
+			if ((c & 0xe0) == 0xc0) {
+				uchar = (c & 0x1f) << 6;
+
+				c = (u8) *s++;
+				if ((c & 0xc0) != 0xc0)
+					goto fail;
+				c &= 0x3f;
+				uchar |= c;
+
+			// 3-byte sequence (most CJKV characters):
+			// zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
+			} else if ((c & 0xf0) == 0xe0) {
+				uchar = (c & 0x0f) << 12;
+
+				c = (u8) *s++;
+				if ((c & 0xc0) != 0xc0)
+					goto fail;
+				c &= 0x3f;
+				uchar |= c << 6;
+
+				c = (u8) *s++;
+				if ((c & 0xc0) != 0xc0)
+					goto fail;
+				c &= 0x3f;
+				uchar |= c;
+
+				/* no bogus surrogates */
+				if (0xd800 <= uchar && uchar <= 0xdfff)
+					goto fail;
+
+			// 4-byte sequence (surrogate pairs, currently rare):
+			// 11101110wwwwzzzzyy + 110111yyyyxxxxxx
+			//     = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
+			// (uuuuu = wwww + 1)
+			// FIXME accept the surrogate code points (only)
+
+			} else
+				goto fail;
+		} else
+			uchar = c;
+		put_unaligned (cpu_to_le16 (uchar), cp++);
+		count++;
+		len--;
+	}
+	return count;
+fail:
+	return -1;
+}
+
 
 /**
  * usb_gadget_get_string - fill out a string descriptor 
- * @table: of c strings using iso latin/1 characters
+ * @table: of c strings encoded using UTF-8
  * @id: string id, from low byte of wValue in get string descriptor
  * @buf: at least 256 bytes
  *
- * Finds the iso latin/1 string matching the ID, and converts it into a
+ * Finds the UTF-8 string matching the ID, and converts it into a
  * string descriptor in utf16-le.
  * Returns length of descriptor (always even) or negative errno
  *
- * If your driver needs stings in multiple languages, you'll need to
- * to use some alternate solution for languages where the ISO 8859/1
- * (latin/1) character set can't be used.  For example, they can't be
- * used with Chinese (Big5, GB2312, etc), Japanese, Korean, or many other
- * languages.  You'd likely "switch (wIndex) { ... }"  in your ep0
- * string descriptor logic, using this routine in cases where "western
- * european" characters suffice for the strings being returned.
+ * If your driver needs stings in multiple languages, you'll probably
+ * "switch (wIndex) { ... }"  in your ep0 string descriptor logic,
+ * using this routine after choosing which set of UTF-8 strings to use.
+ * Note that US-ASCII is a strict subset of UTF-8; any string bytes with
+ * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1
+ * characters (which are also widely used in C strings).
  */
 int
 usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
@@ -59,13 +124,12 @@ usb_gadget_get_string (struct usb_gadget
 
 	/* string descriptors have length, tag, then UTF16-LE text */
 	len = min ((size_t) 126, strlen (s->s));
+	memset (buf + 2, 0, 2 * len);	/* zero all the bytes */
+	len = utf8_to_utf16le(s->s, (u16 *)&buf[2], len);
+	if (len < 0)
+		return -EINVAL;
 	buf [0] = (len + 1) * 2;
 	buf [1] = USB_DT_STRING;
-	memset (buf + 2, 0, 2 * len);	/* zero all the high bytes */
-	while (len) {
-		buf [2 * len] = s->s [len - 1];
-		len--;
-	}
 	return buf [0];
 }
 
--- diff/drivers/usb/host/Kconfig	2003-09-30 15:46:17.000000000 +0100
+++ source/drivers/usb/host/Kconfig	2004-03-09 11:51:50.000000000 +0000
@@ -29,6 +29,15 @@ config USB_EHCI_HCD
 	  To compile this driver as a module, choose M here: the
 	  module will be called ehci-hcd.
 
+config USB_EHCI_SPLIT_ISO
+	bool "Full speed ISO transactions (EXPERIMENTAL)"
+	depends on USB_EHCI_HCD && EXPERIMENTAL
+	default n
+	---help---
+	  This code is new and hasn't been used with many different
+	  EHCI or USB 2.0 transaction translator implementations.
+	  It should work for ISO-OUT transfers, like audio.
+
 config USB_OHCI_HCD
 	tristate "OHCI HCD support"
 	depends on USB
--- diff/drivers/usb/host/ehci-dbg.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/usb/host/ehci-dbg.c	2004-03-09 11:51:50.000000000 +0000
@@ -579,7 +579,11 @@ show_periodic (struct class_device *clas
 				break;
 			case Q_TYPE_SITD:
 				temp = scnprintf (next, size,
-					" sitd/%p", p.sitd);
+					" sitd%d-%04x/%p",
+					p.sitd->stream->interval,
+					le32_to_cpup (&p.sitd->hw_uframe)
+						& 0x0000ffff,
+					p.sitd);
 				tag = Q_NEXT_TYPE (p.sitd->hw_next);
 				p = p.sitd->sitd_next;
 				break;
--- diff/drivers/usb/host/ehci-hcd.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/usb/host/ehci-hcd.c	2004-03-09 11:51:50.000000000 +0000
@@ -106,8 +106,6 @@ static const char	hcd_name [] = "ehci_hc
 #undef EHCI_VERBOSE_DEBUG
 #undef EHCI_URB_TRACE
 
-// #define have_split_iso
-
 #ifdef DEBUG
 #define EHCI_STATS
 #endif
@@ -676,6 +674,7 @@ static void ehci_work (struct ehci_hcd *
 
 	/* the IO watchdog guards against hardware or driver bugs that
 	 * misplace IRQs, and should let us run completely without IRQs.
+	 * such lossage has been observed on both VT6202 and VT8235. 
 	 */
 	if ((ehci->async->qh_next.ptr != 0) || (ehci->periodic_sched != 0))
 		timer_action (ehci, TIMER_IO_WATCHDOG);
@@ -796,13 +795,8 @@ static int ehci_urb_enqueue (
 	case PIPE_ISOCHRONOUS:
 		if (urb->dev->speed == USB_SPEED_HIGH)
 			return itd_submit (ehci, urb, mem_flags);
-#ifdef have_split_iso
 		else
 			return sitd_submit (ehci, urb, mem_flags);
-#else
-		dbg ("no split iso support yet");
-		return -ENOSYS;
-#endif /* have_split_iso */
 	}
 }
 
--- diff/drivers/usb/host/ehci-sched.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/usb/host/ehci-sched.c	2004-03-09 11:51:50.000000000 +0000
@@ -53,14 +53,10 @@ periodic_next_shadow (union ehci_shadow 
 		return &periodic->fstn->fstn_next;
 	case Q_TYPE_ITD:
 		return &periodic->itd->itd_next;
-#ifdef have_split_iso
-	case Q_TYPE_SITD:
+	// case Q_TYPE_SITD:
+	default:
 		return &periodic->sitd->sitd_next;
-#endif /* have_split_iso */
 	}
-	dbg ("BAD shadow %p tag %d", periodic->ptr, tag);
-	// BUG ();
-	return 0;
 }
 
 /* returns true after successful unlink */
@@ -133,7 +129,6 @@ periodic_usecs (struct ehci_hcd *ehci, u
 			hw_p = &q->itd->hw_next;
 			q = &q->itd->itd_next;
 			break;
-#ifdef have_split_iso
 		case Q_TYPE_SITD:
 			/* is it in the S-mask?  (count SPLIT, DATA) */
 			if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) {
@@ -154,7 +149,6 @@ periodic_usecs (struct ehci_hcd *ehci, u
 			hw_p = &q->sitd->hw_next;
 			q = &q->sitd->sitd_next;
 			break;
-#endif /* have_split_iso */
 		default:
 			BUG ();
 		}
@@ -229,7 +223,8 @@ static int tt_no_collision (
 				if (same_tt (dev, here.itd->urb->dev)) {
 					u16		mask;
 
-					mask = le32_to_cpu (here.sitd->hw_uframe);
+					mask = le32_to_cpu (here.sitd
+								->hw_uframe);
 					/* FIXME assumes no gap for IN! */
 					mask |= mask >> 8;
 					if (mask & uf_mask)
@@ -237,7 +232,7 @@ static int tt_no_collision (
 				}
 				type = Q_NEXT_TYPE (here.qh->hw_next);
 				here = here.sitd->sitd_next;
-				break;
+				continue;
 			// case Q_TYPE_FSTN:
 			default:
 				ehci_dbg (ehci,
@@ -698,12 +693,27 @@ iso_stream_put(struct ehci_hcd *ehci, st
 		// BUG_ON (!list_empty(&stream->td_list));
 
 		while (!list_empty (&stream->free_list)) {
-			struct ehci_itd	*itd;
+			struct list_head	*entry;
 
-			itd = list_entry (stream->free_list.next,
-				struct ehci_itd, itd_list);
-			list_del (&itd->itd_list);
-			dma_pool_free (ehci->itd_pool, itd, itd->itd_dma);
+			entry = stream->free_list.next;
+			list_del (entry);
+
+			/* knows about ITD vs SITD */
+			if (stream->highspeed) {
+				struct ehci_itd		*itd;
+
+				itd = list_entry (entry, struct ehci_itd,
+						itd_list);
+				dma_pool_free (ehci->itd_pool, itd,
+						itd->itd_dma);
+			} else {
+				struct ehci_sitd	*sitd;
+
+				sitd = list_entry (entry, struct ehci_sitd,
+						sitd_list);
+				dma_pool_free (ehci->sitd_pool, sitd,
+						sitd->sitd_dma);
+			}
 		}
 
 		is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0;
@@ -858,6 +868,7 @@ itd_urb_transaction (
 	int			i;
 	unsigned		num_itds;
 	struct ehci_iso_sched	*sched;
+	unsigned long		flags;
 
 	sched = iso_sched_alloc (urb->number_of_packets, mem_flags);
 	if (unlikely (sched == 0))
@@ -871,6 +882,7 @@ itd_urb_transaction (
 		num_itds = urb->number_of_packets;
 
 	/* allocate/init ITDs */
+	spin_lock_irqsave (&ehci->lock, flags);
 	for (i = 0; i < num_itds; i++) {
 
 		/* free_list.next might be cache-hot ... but maybe
@@ -884,8 +896,14 @@ itd_urb_transaction (
 			list_del (&itd->itd_list);
 			itd_dma = itd->itd_dma;
 		} else
+			itd = 0;
+
+		if (!itd) {
+			spin_unlock_irqrestore (&ehci->lock, flags);
 			itd = dma_pool_alloc (ehci->itd_pool, mem_flags,
 					&itd_dma);
+			spin_lock_irqsave (&ehci->lock, flags);
+		}
 
 		if (unlikely (0 == itd)) {
 			iso_sched_free (stream, sched);
@@ -895,6 +913,7 @@ itd_urb_transaction (
 		itd->itd_dma = itd_dma;
 		list_add (&itd->itd_list, &sched->td_list);
 	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
 
 	/* temporarily store schedule info in hcpriv */
 	urb->hcpriv = sched;
@@ -909,11 +928,11 @@ itd_slot_ok (
 	struct ehci_hcd		*ehci,
 	u32			mod,
 	u32			uframe,
-	u32			end,
 	u8			usecs,
 	u32			period
 )
 {
+	uframe %= period;
 	do {
 		/* can't commit more than 80% periodic == 100 usec */
 		if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7)
@@ -922,8 +941,7 @@ itd_slot_ok (
 
 		/* we know urb->interval is 2^N uframes */
 		uframe += period;
-		uframe %= mod;
-	} while (uframe != end);
+	} while (uframe < mod);
 	return 1;
 }
 
@@ -933,7 +951,6 @@ sitd_slot_ok (
 	u32			mod,
 	struct ehci_iso_stream	*stream,
 	u32			uframe,
-	u32			end,
 	struct ehci_iso_sched	*sched,
 	u32			period_uframes
 )
@@ -952,12 +969,20 @@ sitd_slot_ok (
 	 */
 
 	/* check bandwidth */
+	uframe %= period_uframes;
 	do {
 		u32		max_used;
 
 		frame = uframe >> 3;
 		uf = uframe & 7;
 
+		/* tt must be idle for start(s), any gap, and csplit.
+		 * assume scheduling slop leaves 10+% for control/bulk.
+		 */
+		if (!tt_no_collision (ehci, period_uframes << 3,
+				stream->udev, frame, mask))
+			return 0;
+
 		/* check starts (OUT uses more than one) */
 		max_used = 100 - stream->usecs;
 		for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) {
@@ -969,25 +994,19 @@ sitd_slot_ok (
 		if (stream->c_usecs) {
 			max_used = 100 - stream->c_usecs;
 			do {
-				/* tt is busy in the gap before CSPLIT */
 				tmp = 1 << uf;
-				mask |= tmp;
 				tmp <<= 8;
-				if (stream->raw_mask & tmp)
-					break;
+				if ((stream->raw_mask & tmp) == 0)
+					continue;
+				if (periodic_usecs (ehci, frame, uf)
+						> max_used)
+					return 0;
 			} while (++uf < 8);
-			if (periodic_usecs (ehci, frame, uf) > max_used)
-				return 0;
 		}
 
 		/* we know urb->interval is 2^N uframes */
 		uframe += period_uframes;
-		uframe %= mod;
-	} while (uframe != end);
-
-	/* tt must be idle for start(s), any gap, and csplit */
-	if (!tt_no_collision (ehci, period_uframes, stream->udev, frame, mask))
-		return 0;
+	} while (uframe < mod);
 
 	stream->splits = stream->raw_mask << (uframe & 7);
 	cpu_to_le32s (&stream->splits);
@@ -1014,7 +1033,7 @@ iso_stream_schedule (
 	struct ehci_iso_stream	*stream
 )
 {
-	u32			now, start, end, max, period;
+	u32			now, start, max, period;
 	int			status;
 	unsigned		mod = ehci->periodic_size << 3;
 	struct ehci_iso_sched	*sched = urb->hcpriv;
@@ -1036,8 +1055,6 @@ iso_stream_schedule (
 
 	/* when's the last uframe this urb could start? */
 	max = now + mod;
-	max -= sched->span;
-	max -= 8 * SCHEDULE_SLOP;
 
 	/* typical case: reuse current schedule. stream is still active,
 	 * and no gaps from host falling behind (irq delays etc)
@@ -1046,9 +1063,11 @@ iso_stream_schedule (
 		start = stream->next_uframe;
 		if (start < now)
 			start += mod;
-		if (likely (start < max))
+		if (likely ((start + sched->span) < max))
 			goto ready;
-		/* else fell behind; try to reschedule */
+		/* else fell behind; someday, try to reschedule */
+		status = -EL2NSYNC;
+		goto fail;
 	}
 
 	/* need to schedule; when's the next (u)frame we could start?
@@ -1059,63 +1078,40 @@ iso_stream_schedule (
 	 */
 	start = SCHEDULE_SLOP * 8 + (now & ~0x07);
 	start %= mod;
-	end = start;
+	stream->next_uframe = start;
 
 	/* NOTE:  assumes URB_ISO_ASAP, to limit complexity/bugs */
 
 	period = urb->interval;
 	if (!stream->highspeed)
 		period <<= 3;
-	if (max > (start + period))
-		max = start + period;
 
-	/* hack:  account for itds already scheduled to this endpoint */
-	if (list_empty (&stream->td_list))
-		end = max;
-
-	/* within [start..max] find a uframe slot with enough bandwidth */
-	end %= mod;
-	do {
+	/* find a uframe slot with enough bandwidth */
+	for (; start < (stream->next_uframe + period); start++) {
 		int		enough_space;
 
 		/* check schedule: enough space? */
 		if (stream->highspeed)
-			enough_space = itd_slot_ok (ehci, mod, start, end,
+			enough_space = itd_slot_ok (ehci, mod, start,
 					stream->usecs, period);
 		else {
 			if ((start % 8) >= 6)
 				continue;
 			enough_space = sitd_slot_ok (ehci, mod, stream,
-					start, end, sched, period);
+					start, sched, period);
 		}
 
-		/* (re)schedule it here if there's enough bandwidth */
+		/* schedule it here if there's enough bandwidth */
 		if (enough_space) {
-			start %= mod;
-			if (unlikely (!list_empty (&stream->td_list))) {
-				/* host fell behind ... maybe irq latencies
-				 * delayed this request queue for too long.
-				 */
-				stream->rescheduled++;
-				dev_dbg (&urb->dev->dev,
-					"iso%d%s %d.%d skip %d.%d\n",
-					stream->bEndpointAddress & 0x0f,
-					(stream->bEndpointAddress & USB_DIR_IN)
-						? "in" : "out",
-					stream->next_uframe >> 3,
-					stream->next_uframe & 0x7,
-					start >> 3, start & 0x7);
-			}
-			stream->next_uframe = start;
+			stream->next_uframe = start % mod;
 			goto ready;
 		}
-
-	} while (++start < max);
+	}
 
 	/* no room in the schedule */
-	ehci_dbg (ehci, "iso %ssched full %p (now %d end %d max %d)\n",
+	ehci_dbg (ehci, "iso %ssched full %p (now %d max %d)\n",
 		list_empty (&stream->td_list) ? "" : "re",
-		urb, now, end, max);
+		urb, now, max);
 	status = -ENOSPC;
 
 fail:
@@ -1260,6 +1256,7 @@ itd_link_urb (
 	iso_sched_free (stream, iso_sched);
 	urb->hcpriv = 0;
 
+	timer_action (ehci, TIMER_IO_WATCHDOG);
 	if (unlikely (!ehci->periodic_sched++))
 		return enable_periodic (ehci);
 	return 0;
@@ -1404,18 +1401,392 @@ done:
 	return status;
 }
 
-#ifdef have_split_iso
+#ifdef CONFIG_USB_EHCI_SPLIT_ISO
 
 /*-------------------------------------------------------------------------*/
 
 /*
- * "Split ISO TDs" ... used for USB 1.1 devices going through
- * the TTs in USB 2.0 hubs.
- *
- * FIXME not yet implemented
+ * "Split ISO TDs" ... used for USB 1.1 devices going through the
+ * TTs in USB 2.0 hubs.  These need microframe scheduling.
  */
 
-#endif /* have_split_iso */
+static inline void
+sitd_sched_init (
+	struct ehci_iso_sched	*iso_sched,
+	struct ehci_iso_stream	*stream,
+	struct urb		*urb
+)
+{
+	unsigned	i;
+	dma_addr_t	dma = urb->transfer_dma;
+
+	/* how many frames are needed for these transfers */
+	iso_sched->span = urb->number_of_packets * stream->interval;
+
+	/* figure out per-frame sitd fields that we'll need later
+	 * when we fit new sitds into the schedule.
+	 */
+	for (i = 0; i < urb->number_of_packets; i++) {
+		struct ehci_iso_packet	*packet = &iso_sched->packet [i];
+		unsigned		length;
+		dma_addr_t		buf;
+		u32			trans;
+
+		length = urb->iso_frame_desc [i].length & 0x03ff;
+		buf = dma + urb->iso_frame_desc [i].offset;
+
+		trans = SITD_STS_ACTIVE;
+		if (((i + 1) == urb->number_of_packets)
+				&& !(urb->transfer_flags & URB_NO_INTERRUPT))
+			trans |= SITD_IOC;
+		trans |= length << 16;
+		packet->transaction = cpu_to_le32 (trans);
+
+		/* might need to cross a buffer page within a td */
+		packet->bufp = buf;
+		buf += length;
+		packet->buf1 = buf & ~0x0fff;
+		if (packet->buf1 != (buf & ~(u64)0x0fff))
+			packet->cross = 1;
+
+		/* OUT uses multiple start-splits */ 
+		if (stream->bEndpointAddress & USB_DIR_IN)
+			continue;
+		length = 1 + (length / 188);
+		packet->buf1 |= length;
+		if (length > 1) /* BEGIN vs ALL */
+			packet->buf1 |= 1 << 3;
+	}
+}
+
+static int
+sitd_urb_transaction (
+	struct ehci_iso_stream	*stream,
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	int			mem_flags
+)
+{
+	struct ehci_sitd	*sitd;
+	dma_addr_t		sitd_dma;
+	int			i;
+	struct ehci_iso_sched	*iso_sched;
+	unsigned long		flags;
+
+	iso_sched = iso_sched_alloc (urb->number_of_packets, mem_flags);
+	if (iso_sched == 0)
+		return -ENOMEM;
+
+	sitd_sched_init (iso_sched, stream, urb);
+
+	/* allocate/init sITDs */
+	spin_lock_irqsave (&ehci->lock, flags);
+	for (i = 0; i < urb->number_of_packets; i++) {
+
+		/* NOTE:  for now, we don't try to handle wraparound cases
+		 * for IN (using sitd->hw_backpointer, like a FSTN), which
+		 * means we never need two sitds for full speed packets.
+		 */
+
+		/* free_list.next might be cache-hot ... but maybe
+		 * the HC caches it too. avoid that issue for now.
+		 */
+
+		/* prefer previously-allocated sitds */
+		if (!list_empty(&stream->free_list)) {
+			sitd = list_entry (stream->free_list.prev,
+					 struct ehci_sitd, sitd_list);
+			list_del (&sitd->sitd_list);
+			sitd_dma = sitd->sitd_dma;
+		} else
+			sitd = 0;
+
+		if (!sitd) {
+			spin_unlock_irqrestore (&ehci->lock, flags);
+			sitd = dma_pool_alloc (ehci->sitd_pool, mem_flags,
+					&sitd_dma);
+			spin_lock_irqsave (&ehci->lock, flags);
+		}
+
+		if (!sitd) {
+			iso_sched_free (stream, iso_sched);
+			spin_unlock_irqrestore (&ehci->lock, flags);
+			return -ENOMEM;
+		}
+		memset (sitd, 0, sizeof *sitd);
+		sitd->sitd_dma = sitd_dma;
+		list_add (&sitd->sitd_list, &iso_sched->td_list);
+	}
+
+	/* temporarily store schedule info in hcpriv */
+	urb->hcpriv = iso_sched;
+	urb->error_count = 0;
+
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline void
+sitd_patch (
+	struct ehci_iso_stream	*stream,
+	struct ehci_sitd	*sitd,
+	struct ehci_iso_sched	*iso_sched,
+	unsigned		index
+)
+{
+	struct ehci_iso_packet	*uf = &iso_sched->packet [index];
+	u64			bufp = uf->bufp;
+
+	sitd->hw_next = EHCI_LIST_END;
+	sitd->hw_fullspeed_ep = stream->address;
+	sitd->hw_uframe = stream->splits;
+	sitd->hw_results = uf->transaction;
+	sitd->hw_backpointer = EHCI_LIST_END;
+
+	bufp = uf->bufp;
+	sitd->hw_buf [0] = cpu_to_le32 (bufp);
+	sitd->hw_buf_hi [0] = cpu_to_le32 (bufp >> 32);
+
+	sitd->hw_buf [1] = cpu_to_le32 (uf->buf1);
+	if (uf->cross) {
+		bufp += 4096;
+		sitd->hw_buf_hi [1] = cpu_to_le32 (bufp >> 32);
+	}
+	sitd->index = index;
+}
+
+static inline void
+sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
+{
+	/* note: sitd ordering could matter (CSPLIT then SSPLIT) */
+	sitd->sitd_next = ehci->pshadow [frame];
+	sitd->hw_next = ehci->periodic [frame];
+	ehci->pshadow [frame].sitd = sitd;
+	sitd->frame = frame;
+	wmb ();
+	ehci->periodic [frame] = cpu_to_le32 (sitd->sitd_dma) | Q_TYPE_SITD;
+}
+
+/* fit urb's sitds into the selected schedule slot; activate as needed */
+static int
+sitd_link_urb (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	unsigned		mod,
+	struct ehci_iso_stream	*stream
+)
+{
+	int			packet;
+	unsigned		next_uframe;
+	struct ehci_iso_sched	*sched = urb->hcpriv;
+	struct ehci_sitd	*sitd;
+
+	next_uframe = stream->next_uframe;
+
+	if (list_empty(&stream->td_list)) {
+		/* usbfs ignores TT bandwidth */
+		hcd_to_bus (&ehci->hcd)->bandwidth_allocated
+				+= stream->bandwidth;
+		ehci_vdbg (ehci,
+			"sched dev%s ep%d%s-iso [%d] %dms/%04x\n",
+			urb->dev->devpath, stream->bEndpointAddress & 0x0f,
+			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
+			(next_uframe >> 3) % ehci->periodic_size,
+			stream->interval, le32_to_cpu (stream->splits));
+		stream->start = jiffies;
+	}
+	hcd_to_bus (&ehci->hcd)->bandwidth_isoc_reqs++;
+
+	/* fill sITDs frame by frame */
+	for (packet = 0, sitd = 0;
+			packet < urb->number_of_packets;
+			packet++) {
+
+		/* ASSERT:  we have all necessary sitds */
+		BUG_ON (list_empty (&sched->td_list));
+
+		/* ASSERT:  no itds for this endpoint in this frame */
+
+		sitd = list_entry (sched->td_list.next,
+				struct ehci_sitd, sitd_list);
+		list_move_tail (&sitd->sitd_list, &stream->td_list);
+		sitd->stream = iso_stream_get (stream);
+		sitd->urb = usb_get_urb (urb);
+
+		sitd_patch (stream, sitd, sched, packet);
+		sitd_link (ehci, (next_uframe >> 3) % ehci->periodic_size,
+				sitd);
+
+		next_uframe += stream->interval << 3;
+		stream->depth += stream->interval << 3;
+	}
+	stream->next_uframe = next_uframe % mod;
+
+	/* don't need that schedule data any more */
+	iso_sched_free (stream, sched);
+	urb->hcpriv = 0;
+
+	timer_action (ehci, TIMER_IO_WATCHDOG);
+	if (!ehci->periodic_sched++)
+		return enable_periodic (ehci);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define	SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \
+			| SITD_STS_XACT | SITD_STS_MMF | SITD_STS_STS)
+
+static unsigned
+sitd_complete (
+	struct ehci_hcd		*ehci,
+	struct ehci_sitd	*sitd,
+	struct pt_regs		*regs
+) {
+	struct urb				*urb = sitd->urb;
+	struct usb_iso_packet_descriptor	*desc;
+	u32					t;
+	int					urb_index = -1;
+	struct ehci_iso_stream			*stream = sitd->stream;
+	struct usb_device			*dev;
+
+	urb_index = sitd->index;
+	desc = &urb->iso_frame_desc [urb_index];
+	t = le32_to_cpup (&sitd->hw_results);
+
+	/* report transfer status */
+	if (t & SITD_ERRS) {
+		urb->error_count++;
+		if (t & SITD_STS_DBE)
+			desc->status = usb_pipein (urb->pipe)
+				? -ENOSR  /* hc couldn't read */
+				: -ECOMM; /* hc couldn't write */
+		else if (t & SITD_STS_BABBLE)
+			desc->status = -EOVERFLOW;
+		else /* XACT, MMF, etc */
+			desc->status = -EPROTO;
+	} else {
+		desc->status = 0;
+		desc->actual_length = desc->length - SITD_LENGTH (t);
+	}
+
+	usb_put_urb (urb);
+	sitd->urb = 0;
+	sitd->stream = 0;
+	list_move (&sitd->sitd_list, &stream->free_list);
+	stream->depth -= stream->interval << 3;
+	iso_stream_put (ehci, stream);
+
+	/* handle completion now? */
+	if ((urb_index + 1) != urb->number_of_packets)
+		return 0;
+
+	/* ASSERT: it's really the last sitd for this urb
+	list_for_each_entry (sitd, &stream->td_list, sitd_list)
+		BUG_ON (sitd->urb == urb);
+	 */
+
+	/* give urb back to the driver */
+	dev = usb_get_dev (urb->dev);
+	ehci_urb_done (ehci, urb, regs);
+	urb = 0;
+
+	/* defer stopping schedule; completion can submit */
+	ehci->periodic_sched--;
+	if (!ehci->periodic_sched)
+		(void) disable_periodic (ehci);
+	hcd_to_bus (&ehci->hcd)->bandwidth_isoc_reqs--;
+
+	if (list_empty (&stream->td_list)) {
+		hcd_to_bus (&ehci->hcd)->bandwidth_allocated
+				-= stream->bandwidth;
+		ehci_vdbg (ehci,
+			"deschedule devp %s ep%d%s-iso\n",
+			dev->devpath, stream->bEndpointAddress & 0x0f,
+			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
+	}
+	iso_stream_put (ehci, stream);
+	usb_put_dev (dev);
+
+	return 1;
+}
+
+
+static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
+{
+	int			status = -EINVAL;
+	unsigned long		flags;
+	struct ehci_iso_stream	*stream;
+
+	// FIXME remove when csplits behave
+	if (usb_pipein(urb->pipe)) {
+		ehci_dbg (ehci, "no iso-IN split transactions yet\n");
+		return -ENOMEM;
+	}
+
+	/* Get iso_stream head */
+	stream = iso_stream_find (ehci, urb);
+	if (stream == 0) {
+		ehci_dbg (ehci, "can't get iso stream\n");
+		return -ENOMEM;
+	}
+	if (urb->interval != stream->interval) {
+		ehci_dbg (ehci, "can't change iso interval %d --> %d\n",
+			stream->interval, urb->interval);
+		goto done;
+	}
+
+#ifdef EHCI_URB_TRACE
+	ehci_dbg (ehci,
+		"submit %p dev%s ep%d%s-iso len %d\n",
+		urb, urb->dev->devpath,
+		usb_pipeendpoint (urb->pipe),
+		usb_pipein (urb->pipe) ? "in" : "out",
+		urb->transfer_buffer_length);
+#endif
+
+	/* allocate SITDs */
+	status = sitd_urb_transaction (stream, ehci, urb, mem_flags);
+	if (status < 0) {
+		ehci_dbg (ehci, "can't init sitds\n");
+		goto done;
+	}
+
+	/* schedule ... need to lock */
+	spin_lock_irqsave (&ehci->lock, flags);
+	status = iso_stream_schedule (ehci, urb, stream);
+ 	if (status == 0)
+		sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+	spin_unlock_irqrestore (&ehci->lock, flags);
+
+done:
+	if (status < 0)
+		iso_stream_put (ehci, stream);
+	return status;
+}
+
+#else
+
+static inline int
+sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
+{
+	ehci_dbg (ehci, "split iso support is disabled\n");
+	return -ENOSYS;
+}
+
+static inline unsigned
+sitd_complete (
+	struct ehci_hcd		*ehci,
+	struct ehci_sitd	*sitd,
+	struct pt_regs		*regs
+) {
+	ehci_err (ehci, "sitd_complete %p?\n", sitd);
+	return 0;
+}
+
+#endif /* USB_EHCI_SPLIT_ISO */
 
 /*-------------------------------------------------------------------------*/
 
@@ -1513,7 +1884,6 @@ restart:
 				modified = itd_complete (ehci, q.itd, regs);
 				q = *q_p;
 				break;
-#ifdef have_split_iso
 			case Q_TYPE_SITD:
 				if (q.sitd->hw_results & SITD_ACTIVE) {
 					q_p = &q.sitd->sitd_next;
@@ -1529,7 +1899,6 @@ restart:
 				modified = sitd_complete (ehci, q.sitd, regs);
 				q = *q_p;
 				break;
-#endif /* have_split_iso */
 			default:
 				dbg ("corrupt type %d frame %d shadow %p",
 					type, frame, q.ptr);
--- diff/drivers/usb/host/ehci.h	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/usb/host/ehci.h	2004-03-09 11:51:50.000000000 +0000
@@ -492,16 +492,16 @@ struct ehci_itd {
 /*
  * EHCI Specification 0.95 Section 3.4 
  * siTD, aka split-transaction isochronous Transfer Descriptor
- *       ... describe low/full speed iso xfers through TT in hubs
+ *       ... describe 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_results;		/* see EHCI table 3-11 */
+	u32			hw_fullspeed_ep;	/* EHCI table 3-9 */
+	u32			hw_uframe;		/* EHCI table 3-10 */
+	u32			hw_results;		/* EHCI table 3-11 */
 #define	SITD_IOC	(1 << 31)	/* interrupt on completion */
 #define	SITD_PAGE	(1 << 30)	/* buffer 0/1 */
 #define	SITD_LENGTH(x)	(0x3ff & ((x)>>16))
@@ -515,8 +515,8 @@ struct ehci_sitd {
 
 #define SITD_ACTIVE	__constant_cpu_to_le32(SITD_STS_ACTIVE)
 
-	u32			hw_buf [2];		/* see EHCI table 3-12 */
-	u32			hw_backpointer;		/* see EHCI table 3-13 */
+	u32			hw_buf [2];		/* EHCI table 3-12 */
+	u32			hw_backpointer;		/* EHCI table 3-13 */
 	u32			hw_buf_hi [2];		/* Appendix B */
 
 	/* the rest is HCD-private */
@@ -552,8 +552,6 @@ struct ehci_fstn {
 
 /*-------------------------------------------------------------------------*/
 
-#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags)
-
 #ifndef DEBUG
 #define STUB_DEBUG_FILES
 #endif	/* DEBUG */
--- diff/drivers/usb/host/uhci-hcd.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/usb/host/uhci-hcd.c	2004-03-09 11:51:50.000000000 +0000
@@ -781,7 +781,8 @@ static void uhci_dec_fsbr(struct uhci_hc
 /*
  * Map status to standard result codes
  *
- * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)]
+ * <status> is (td->status & 0xF60000) [a.k.a. uhci_status_bits(td->status)]
+ * Note: status does not include the TD_CTRL_NAK bit.
  * <dir_out> is True for output TDs and False for input TDs.
  */
 static int uhci_map_status(int status, int dir_out)
@@ -792,22 +793,18 @@ static int uhci_map_status(int status, i
 		return -EPROTO;
 	if (status & TD_CTRL_CRCTIMEO) {		/* CRC/Timeout */
 		if (dir_out)
-			return -ETIMEDOUT;
+			return -EPROTO;
 		else
 			return -EILSEQ;
 	}
-	if (status & TD_CTRL_NAK)			/* NAK */
-		return -ETIMEDOUT;
 	if (status & TD_CTRL_BABBLE)			/* Babble */
 		return -EOVERFLOW;
 	if (status & TD_CTRL_DBUFERR)			/* Buffer error */
 		return -ENOSR;
 	if (status & TD_CTRL_STALLED)			/* Stalled */
 		return -EPIPE;
-	if (status & TD_CTRL_ACTIVE)			/* Active */
-		return 0;
-
-	return -EINVAL;
+	WARN_ON(status & TD_CTRL_ACTIVE);		/* Active */
+	return 0;
 }
 
 /*
@@ -832,7 +829,7 @@ static int uhci_submit_control(struct uh
 		status |= TD_CTRL_LS;
 
 	/*
-	 * Build the TD for the control request
+	 * Build the TD for the control request setup packet
 	 */
 	td = uhci_alloc_td(uhci, urb->dev);
 	if (!td)
@@ -990,13 +987,13 @@ static int uhci_result_control(struct uh
 
 	if (urbp->short_control_packet) {
 		tmp = head->prev;
-		goto status_phase;
+		goto status_stage;
 	}
 
 	tmp = head->next;
 	td = list_entry(tmp, struct uhci_td, list);
 
-	/* The first TD is the SETUP phase, check the status, but skip */
+	/* The first TD is the SETUP stage, check the status, but skip */
 	/*  the count */
 	status = uhci_status_bits(td_status(td));
 	if (status & TD_CTRL_ACTIVE)
@@ -1037,10 +1034,10 @@ static int uhci_result_control(struct uh
 		}
 	}
 
-status_phase:
+status_stage:
 	td = list_entry(tmp, struct uhci_td, list);
 
-	/* Control status phase */
+	/* Control status stage */
 	status = td_status(td);
 
 #ifdef I_HAVE_BUGGY_APC_BACKUPS
@@ -1053,10 +1050,11 @@ status_phase:
 		return 0;
 #endif
 
+	status = uhci_status_bits(status);
 	if (status & TD_CTRL_ACTIVE)
 		return -EINPROGRESS;
 
-	if (uhci_status_bits(status))
+	if (status)
 		goto td_error;
 
 	return 0;
@@ -1273,12 +1271,6 @@ static inline int uhci_submit_interrupt(
 }
 
 /*
- * Bulk and interrupt use common result
- */
-#define uhci_result_bulk uhci_result_common
-#define uhci_result_interrupt uhci_result_common
-
-/*
  * Isochronous transfers
  */
 static int isochronous_find_limits(struct uhci_hcd *uhci, struct urb *urb, unsigned int *start, unsigned int *end)
@@ -1403,7 +1395,8 @@ static int uhci_result_isochronous(struc
 		urb->iso_frame_desc[i].actual_length = actlength;
 		urb->actual_length += actlength;
 
-		status = uhci_map_status(uhci_status_bits(td_status(td)), usb_pipeout(urb->pipe));
+		status = uhci_map_status(uhci_status_bits(td_status(td)),
+				usb_pipeout(urb->pipe));
 		urb->iso_frame_desc[i].status = status;
 		if (status) {
 			urb->error_count++;
@@ -1508,12 +1501,9 @@ static int uhci_urb_enqueue(struct usb_h
 		struct urb_priv *urbp = urb->hcpriv;
 
 		list_del_init(&urbp->urb_list);
-		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-		uhci_destroy_urb_priv (uhci, urb);
-
-		return ret;
-	}
-	ret = 0;
+		uhci_destroy_urb_priv(uhci, urb);
+	} else
+		ret = 0;
 
 out:
 	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
@@ -1541,11 +1531,9 @@ static void uhci_transfer_result(struct 
 	case PIPE_CONTROL:
 		ret = uhci_result_control(uhci, urb);
 		break;
-	case PIPE_INTERRUPT:
-		ret = uhci_result_interrupt(uhci, urb);
-		break;
 	case PIPE_BULK:
-		ret = uhci_result_bulk(uhci, urb);
+	case PIPE_INTERRUPT:
+		ret = uhci_result_common(uhci, urb);
 		break;
 	case PIPE_ISOCHRONOUS:
 		ret = uhci_result_isochronous(uhci, urb);
@@ -1649,10 +1637,12 @@ static int uhci_urb_dequeue(struct usb_h
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 	unsigned long flags;
-	struct urb_priv *urbp = urb->hcpriv;
+	struct urb_priv *urbp;
 
 	spin_lock_irqsave(&uhci->urb_list_lock, flags);
-
+	urbp = urb->hcpriv;
+	if (!urbp)			/* URB was never linked! */
+		goto done;
 	list_del_init(&urbp->urb_list);
 
 	uhci_unlink_generic(uhci, urb);
@@ -1665,6 +1655,7 @@ static int uhci_urb_dequeue(struct usb_h
 	list_add_tail(&urbp->urb_list, &uhci->urb_remove_list);
 
 	spin_unlock(&uhci->urb_remove_list_lock);
+done:
 	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
 	return 0;
 }
@@ -1861,17 +1852,12 @@ static void uhci_finish_completion(struc
 
 static void uhci_remove_pending_urbps(struct uhci_hcd *uhci)
 {
-	struct list_head *tmp, *head;
-
 	spin_lock(&uhci->urb_remove_list_lock);
-	head = &uhci->urb_remove_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
+	spin_lock(&uhci->complete_list_lock);
 
-		tmp = tmp->next;
-		uhci_moveto_complete(uhci, urbp);
-	}
+	/* Splice the urb_remove_list onto the end of the complete_list */
+	list_splice_init(&uhci->urb_remove_list, uhci->complete_list.prev);
+	spin_unlock(&uhci->complete_list_lock);
 	spin_unlock(&uhci->urb_remove_list_lock);
 }
 
@@ -2471,9 +2457,16 @@ static int uhci_resume(struct usb_hcd *h
 
 	pci_set_master(to_pci_dev(uhci_dev(uhci)));
 
-	if (uhci->state == UHCI_SUSPENDED)
+	if (uhci->state == UHCI_SUSPENDED) {
+
+		/*
+		 * Some systems clear the Interrupt Enable register during
+		 * PM suspend/resume, so reinitialize it.
+		 */
+		outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC |
+				USBINTR_SP, uhci->io_addr + USBINTR);
 		uhci->resume_detect = 1;
-	else {
+	} else {
 		reset_hc(uhci);
 		start_hc(uhci);
 	}
--- diff/drivers/usb/host/uhci-hcd.h	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/usb/host/uhci-hcd.h	2004-03-09 11:51:50.000000000 +0000
@@ -141,7 +141,7 @@ struct uhci_qh {
 				 TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
 
 #define uhci_maxerr(err)		((err) << TD_CTRL_C_ERR_SHIFT)
-#define uhci_status_bits(ctrl_sts)	((ctrl_sts) & 0xFE0000)
+#define uhci_status_bits(ctrl_sts)	((ctrl_sts) & 0xF60000)
 #define uhci_actual_length(ctrl_sts)	(((ctrl_sts) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
 
 /*
--- diff/drivers/usb/input/Kconfig	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/input/Kconfig	2004-03-09 11:51:50.000000000 +0000
@@ -179,6 +179,18 @@ config USB_POWERMATE
 	  To compile this driver as a module, choose M here: the
 	  module will be called powermate.
 
+config USB_MTOUCH
+	tristate "MicroTouch USB Touchscreen Driver"
+	depends on USB && INPUT
+	---help---
+	  Say Y here if you want to use a MicroTouch (Now 3M) USB 
+	  Touchscreen controller.
+
+	  See <file:Documentation/usb/mtouch.txt> for additional information.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mtouchusb.
+
 config USB_XPAD
 	tristate "X-Box gamepad support"
 	depends on USB && INPUT
@@ -192,3 +204,17 @@ config USB_XPAD
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called xpad.
+	  
+config USB_ATI_REMOTE
+	tristate "ATI USB RF remote control"
+	depends on USB && INPUT
+	---help---
+	  Say Y here if you want to use one of ATI's USB remote controls.
+	  These are RF remotes with USB receivers. They come with many of ATI's 
+	  All-In-Wonder video cards.  This driver provides mouse pointer, left
+          and right mouse buttons, and maps all the other remote buttons to
+	  keypress events.
+	  
+	  To compile this driver as a module, choose M here: the module will be
+	  called ati_remote.
+
--- diff/drivers/usb/input/Makefile	2003-05-21 11:49:46.000000000 +0100
+++ source/drivers/usb/input/Makefile	2004-03-09 11:51:50.000000000 +0000
@@ -27,10 +27,12 @@ ifeq ($(CONFIG_HID_FF),y)
 endif
 
 obj-$(CONFIG_USB_AIPTEK)	+= aiptek.o
+obj-$(CONFIG_USB_ATI_REMOTE)	+= ati_remote.o
 obj-$(CONFIG_USB_HID)		+= hid.o
 obj-$(CONFIG_USB_KBD)		+= usbkbd.o
-obj-$(CONFIG_USB_MOUSE)		+= usbmouse.o
-obj-$(CONFIG_USB_WACOM)		+= wacom.o
 obj-$(CONFIG_USB_KBTAB)		+= kbtab.o
+obj-$(CONFIG_USB_MOUSE)		+= usbmouse.o
+obj-$(CONFIG_USB_MTOUCH)	+= mtouchusb.o
 obj-$(CONFIG_USB_POWERMATE)	+= powermate.o
+obj-$(CONFIG_USB_WACOM)		+= wacom.o
 obj-$(CONFIG_USB_XPAD)		+= xpad.o
--- diff/drivers/usb/input/hid-core.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/input/hid-core.c	2004-03-09 11:51:50.000000000 +0000
@@ -224,6 +224,9 @@ static int hid_add_field(struct hid_pars
 	offset = report->size;
 	report->size += parser->global.report_size * parser->global.report_count;
 
+	if (usages < parser->global.report_count)
+		usages = parser->global.report_count;
+
 	if (usages == 0)
 		return 0; /* ignore padding fields */
 
@@ -235,9 +238,13 @@ static int hid_add_field(struct hid_pars
 	field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
 
 	for (i = 0; i < usages; i++) {
-		field->usage[i].hid = parser->local.usage[i];
+		int j = i;
+		/* Duplicate the last usage we parsed if we have excess values */
+		if (i >= parser->local.usage_index)
+			j = parser->local.usage_index - 1;
+		field->usage[i].hid = parser->local.usage[j];
 		field->usage[i].collection_index =
-			parser->local.collection_index[i];
+			parser->local.collection_index[j];
 	}
 
 	field->maxusage = usages;
@@ -1317,7 +1324,6 @@ void hid_init_reports(struct hid_device 
 #define USB_VENDOR_ID_KBGEAR            0x084e
 #define USB_DEVICE_ID_KBGEAR_JAMSTUDIO  0x1001
 
-
 #define USB_VENDOR_ID_AIPTEK		0x08ca
 #define USB_DEVICE_ID_AIPTEK_6000	0x0020
 
@@ -1356,17 +1362,43 @@ void hid_init_reports(struct hid_device 
 #define USB_VENDOR_ID_A4TECH		0x09DA
 #define USB_DEVICE_ID_A4TECH_WCP32PU	0x0006
 
+#define USB_VENDOR_ID_CYPRESS		0x04b4
+#define USB_DEVICE_ID_CYPRESS_MOUSE	0x0001
+
 #define USB_VENDOR_ID_BERKSHIRE		0x0c98
 #define USB_DEVICE_ID_BERKSHIRE_PCWD	0x1140
 
 #define USB_VENDOR_ID_ALPS		0x0433
 #define USB_DEVICE_ID_IBM_GAMEPAD	0x1101
 
+#define USB_VENDOR_ID_SAITEK		0x06a3
+#define USB_DEVICE_ID_SAITEK_RUMBLEPAD	0xff17
+
+#define USB_VENDOR_ID_NEC		0x073e
+#define USB_DEVICE_ID_NEC_USB_GAME_PAD	0x0301
+
 struct hid_blacklist {
 	__u16 idVendor;
 	__u16 idProduct;
 	unsigned quirks;
 } hid_blacklist[] = {
+
+	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_6000, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE },
+
+	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
+
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PENPARTNER, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 1, HID_QUIRK_IGNORE },
@@ -1388,32 +1420,25 @@ struct hid_blacklist {
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 2, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 3, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 4, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_6000, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
+
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
-	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
-	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD|HID_QUIRK_MULTI_INPUT },
-	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD|HID_QUIRK_MULTI_INPUT },
-	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD|HID_QUIRK_MULTI_INPUT },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET },
-	{ USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK },
-	{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
+
+	{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_BACK },
+	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA },
+
 	{ USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
+	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
+	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
+	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
+	{ USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD, HID_QUIRK_BADPAD },
+	{ USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
+	{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
+
 	{ 0, 0 }
 };
 
@@ -1445,7 +1470,7 @@ static void hid_free_buffers(struct usb_
 
 static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 {
-	struct usb_host_interface *interface = intf->altsetting + intf->act_altsetting;
+	struct usb_host_interface *interface = intf->cur_altsetting;
 	struct usb_device *dev = interface_to_usbdev (intf);
 	struct hid_descriptor *hdesc;
 	struct hid_device *hid;
--- diff/drivers/usb/input/hid-input.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/input/hid-input.c	2004-03-09 11:51:50.000000000 +0000
@@ -377,7 +377,8 @@ static void hidinput_configure_usage(str
 
 	set_bit(usage->type, input->evbit);
 	if ((usage->type == EV_REL)
-			&& (device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK)
+			&& (device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_BACK
+				| HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA))
 			&& (usage->code == REL_WHEEL)) {
 		set_bit(REL_HWHEEL, bit);
 	}
@@ -431,21 +432,22 @@ void hidinput_hid_event(struct hid_devic
 
 	input_regs(input, regs);
 
-	if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK)
-			&& (usage->code == BTN_BACK)) {
+	if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA) && (usage->code == BTN_EXTRA))
+		|| ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_BACK) && (usage->code == BTN_BACK))) {
 		if (value)
 			hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
 		else
 			hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
 		return;
 	}
+
 	if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON)
 			&& (usage->code == REL_WHEEL)) {
 		input_event(input, usage->type, REL_HWHEEL, value);
 		return;
 	}
 
-	if (usage->hat_min != usage->hat_max) {
+	if (usage->hat_min != usage->hat_max ) { /* FIXME: hat_max can be 0 and hat_min 1 */
 		value = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
 		if (value < 0 || value > 8) value = 0;
 		input_event(input, usage->type, usage->code    , hid_hat_to_axis[value].x);
@@ -484,7 +486,7 @@ void hidinput_hid_event(struct hid_devic
 		return;
 	}
 
-	if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UKNOWN */
+	if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
 		return;
 
 	input_event(input, usage->type, usage->code, value);
--- diff/drivers/usb/input/hid.h	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/input/hid.h	2004-03-09 11:51:50.000000000 +0000
@@ -201,15 +201,16 @@ struct hid_item {
  * HID device quirks.
  */
 
-#define HID_QUIRK_INVERT		0x001
-#define HID_QUIRK_NOTOUCH		0x002
-#define HID_QUIRK_IGNORE		0x004
-#define HID_QUIRK_NOGET			0x008
-#define HID_QUIRK_HIDDEV		0x010
-#define HID_QUIRK_BADPAD		0x020
-#define HID_QUIRK_MULTI_INPUT		0x040
-#define HID_QUIRK_2WHEEL_MOUSE_HACK	0x080
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON	0x100
+#define HID_QUIRK_INVERT			0x001
+#define HID_QUIRK_NOTOUCH			0x002
+#define HID_QUIRK_IGNORE			0x004
+#define HID_QUIRK_NOGET				0x008
+#define HID_QUIRK_HIDDEV			0x010
+#define HID_QUIRK_BADPAD			0x020
+#define HID_QUIRK_MULTI_INPUT			0x040
+#define HID_QUIRK_2WHEEL_MOUSE_HACK_BACK	0x080
+#define HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA	0x100
+#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON		0x200
 
 /*
  * This is the global environment of the parser. This information is
--- diff/drivers/usb/input/hiddev.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/input/hiddev.c	2004-03-09 11:51:50.000000000 +0000
@@ -403,7 +403,8 @@ static int hiddev_ioctl(struct inode *in
 	struct hiddev_collection_info cinfo;
 	struct hiddev_report_info rinfo;
 	struct hiddev_field_info finfo;
-	struct hiddev_usage_ref uref;
+	struct hiddev_usage_ref_multi uref_multi;
+	struct hiddev_usage_ref *uref = &uref_multi.uref;
 	struct hiddev_devinfo dinfo;
 	struct hid_report *report;
 	struct hid_field *field;
@@ -575,68 +576,98 @@ static int hiddev_ioctl(struct inode *in
 		return 0;
 
 	case HIDIOCGUCODE:
-		if (copy_from_user(&uref, (void *) arg, sizeof(uref)))
+		if (copy_from_user(uref, (void *) arg, sizeof(*uref)))
 			return -EFAULT;
 
-		rinfo.report_type = uref.report_type;
-		rinfo.report_id = uref.report_id;
+		rinfo.report_type = uref->report_type;
+		rinfo.report_id = uref->report_id;
 		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
 			return -EINVAL;
 
-		if (uref.field_index >= report->maxfield)
+		if (uref->field_index >= report->maxfield)
 			return -EINVAL;
 
-		field = report->field[uref.field_index];
-		if (uref.usage_index >= field->maxusage)
+		field = report->field[uref->field_index];
+		if (uref->usage_index >= field->maxusage)
 			return -EINVAL;
 
-		uref.usage_code = field->usage[uref.usage_index].hid;
+		uref->usage_code = field->usage[uref->usage_index].hid;
 
-		if (copy_to_user((void *) arg, &uref, sizeof(uref)))
+		if (copy_to_user((void *) arg, uref, sizeof(*uref)))
 			return -EFAULT;
 
 		return 0;
 
 	case HIDIOCGUSAGE:
 	case HIDIOCSUSAGE:
+	case HIDIOCGUSAGES:
+	case HIDIOCSUSAGES:
 	case HIDIOCGCOLLECTIONINDEX:
-		if (copy_from_user(&uref, (void *) arg, sizeof(uref)))
-			return -EFAULT;
+		if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
+			if (copy_from_user(&uref_multi, (void *) arg, 
+					   sizeof(uref_multi)))
+				return -EFAULT;
+		} else {
+			if (copy_from_user(uref, (void *) arg, sizeof(*uref)))
+				return -EFAULT;
+		}
 
-		if (cmd != HIDIOCGUSAGE && uref.report_type == HID_REPORT_TYPE_INPUT)
-				return -EINVAL;
+		if (cmd != HIDIOCGUSAGE && 
+		    cmd != HIDIOCGUSAGES &&
+		    uref->report_type == HID_REPORT_TYPE_INPUT)
+			return -EINVAL;
 
-		if (uref.report_id == HID_REPORT_ID_UNKNOWN) {
-			field = hiddev_lookup_usage(hid, &uref);
+		if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
+			field = hiddev_lookup_usage(hid, uref);
 			if (field == NULL)
 				return -EINVAL;
 		} else {
-			rinfo.report_type = uref.report_type;
-			rinfo.report_id = uref.report_id;
+			rinfo.report_type = uref->report_type;
+			rinfo.report_id = uref->report_id;
 			if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
 				return -EINVAL;
 
-			if (uref.field_index >= report->maxfield)
+			if (uref->field_index >= report->maxfield)
 				return -EINVAL;
 
-			field = report->field[uref.field_index];
-			if (uref.usage_index >= field->maxusage)
+			field = report->field[uref->field_index];
+			if (uref->usage_index >= field->maxusage)
 				return -EINVAL;
+
+			if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
+				if (uref_multi.num_values >= HID_MAX_USAGES || 
+				    uref->usage_index >= field->maxusage || 
+				   (uref->usage_index + uref_multi.num_values) >= field->maxusage)
+					return -EINVAL;
+			}
 		}
 
 		switch (cmd) {
 			case HIDIOCGUSAGE:
-				uref.value = field->value[uref.usage_index];
-				if (copy_to_user((void *) arg, &uref, sizeof(uref)))
+				uref->value = field->value[uref->usage_index];
+				if (copy_to_user((void *) arg, uref, sizeof(*uref)))
 					return -EFAULT;
 				return 0;
 
 			case HIDIOCSUSAGE:
-				field->value[uref.usage_index] = uref.value;
+				field->value[uref->usage_index] = uref->value;
 				return 0;
 
 			case HIDIOCGCOLLECTIONINDEX:
-				return field->usage[uref.usage_index].collection_index;
+				return field->usage[uref->usage_index].collection_index;
+			case HIDIOCGUSAGES:
+				for (i = 0; i < uref_multi.num_values; i++)
+					uref_multi.values[i] = 
+					    field->value[uref->usage_index + i];
+				if (copy_to_user((void *) arg, &uref_multi, 
+						 sizeof(uref_multi)))
+					return -EFAULT;
+				return 0;
+			case HIDIOCSUSAGES:
+				for (i = 0; i < uref_multi.num_values; i++)
+					field->value[uref->usage_index + i] = 
+				  	    uref_multi.values[i];
+				return 0;
 		}
 
 		return 0;
--- diff/drivers/usb/input/kbtab.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/input/kbtab.c	2004-03-09 11:51:50.000000000 +0000
@@ -74,12 +74,15 @@ static void kbtab_irq(struct urb *urb, s
 
 	input_report_abs(dev, ABS_X, kbtab->x);
 	input_report_abs(dev, ABS_Y, kbtab->y);
-	/*input_report_abs(dev, ABS_PRESSURE, kbtab->pressure);*/
 
 	/*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/
 	input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
-	
-	input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0);
+
+	if( -1 == kb_pressure_click){ 
+		input_report_abs(dev, ABS_PRESSURE, kbtab->pressure);
+	} else {
+		input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0);
+	};
 	
 	input_sync(dev);
 
--- diff/drivers/usb/input/usbkbd.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/input/usbkbd.c	2004-03-09 11:51:50.000000000 +0000
@@ -240,7 +240,7 @@ static int usb_kbd_probe(struct usb_inte
 	char path[64];
 	char *buf;
 
-	interface = &iface->altsetting[iface->act_altsetting];
+	interface = iface->cur_altsetting;
 
 	if (interface->desc.bNumEndpoints != 1)
 		return -ENODEV;
--- diff/drivers/usb/input/usbmouse.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/input/usbmouse.c	2004-03-09 11:51:50.000000000 +0000
@@ -131,7 +131,7 @@ static int usb_mouse_probe(struct usb_in
 	char path[64];
 	char *buf;
 
-	interface = &intf->altsetting[intf->act_altsetting];
+	interface = intf->cur_altsetting;
 
 	if (interface->desc.bNumEndpoints != 1) 
 		return -ENODEV;
--- diff/drivers/usb/input/wacom.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/input/wacom.c	2004-03-09 11:51:50.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  *  USB Wacom Graphire and Wacom Intuos tablet support
  *
- *  Copyright (c) 2000-2002 Vojtech Pavlik	<vojtech@ucw.cz>
+ *  Copyright (c) 2000-2004 Vojtech Pavlik	<vojtech@ucw.cz>
  *  Copyright (c) 2000 Andreas Bach Aaen	<abach@stofanet.dk>
  *  Copyright (c) 2000 Clifford Wolf		<clifford@clifford.at>
  *  Copyright (c) 2000 Sam Mosel		<sam.mosel@computer.org>
@@ -9,6 +9,7 @@
  *  Copyright (c) 2000 Daniel Egger		<egger@suse.de>
  *  Copyright (c) 2001 Frederic Lepied		<flepied@mandrakesoft.com>
  *  Copyright (c) 2002 Ping Cheng		<pingc@wacom.com>
+ *  Copyright (c) 2004 Panagiotis Issaris	<panagiotis.issaris@mech.kuleuven.ac.be>
  *
  *  ChangeLog:
  *      v0.1 (vp)  - Initial release
@@ -48,6 +49,7 @@
  *	v1.30 (vp) - Merge 2.4 and 2.5 drivers
  *		   - Since 2.5 now has input_sync(), remove MSC_SERIAL abuse
  *		   - Cleanups here and there
+ *    v1.30.1 (pi) - Added Graphire3 support
  */
 
 /*
--- diff/drivers/usb/misc/usbtest.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/usb/misc/usbtest.c	2004-03-09 11:51:51.000000000 +0000
@@ -490,7 +490,7 @@ static int set_altsetting (struct usbtes
 	struct usb_interface		*iface = dev->intf;
 	struct usb_device		*udev;
 
-	if (alternate < 0 || alternate >= iface->num_altsetting)
+	if (alternate < 0 || alternate >= 256)
 		return -EINVAL;
 
 	udev = interface_to_usbdev (iface);
@@ -556,23 +556,19 @@ static int ch9_postconfig (struct usbtes
 {
 	struct usb_interface	*iface = dev->intf;
 	struct usb_device	*udev = interface_to_usbdev (iface);
-	int			i, retval;
+	int			i, alt, retval;
 
 	/* [9.2.3] if there's more than one altsetting, we need to be able to
 	 * set and get each one.  mostly trusts the descriptors from usbcore.
 	 */
 	for (i = 0; i < iface->num_altsetting; i++) {
 
-		/* 9.2.3 constrains the range here, and Linux ensures
-		 * they're ordered meaningfully in this array
-		 */
-		if (iface->altsetting [i].desc.bAlternateSetting != i) {
+		/* 9.2.3 constrains the range here */
+		alt = iface->altsetting [i].desc.bAlternateSetting;
+		if (alt < 0 || alt >= iface->num_altsetting) {
 			dev_dbg (&iface->dev,
 					"invalid alt [%d].bAltSetting = %d\n",
-					i, 
-					iface->altsetting [i].desc
-						.bAlternateSetting);
-			return -EDOM;
+					i, alt);
 		}
 
 		/* [real world] get/set unimplemented if there's only one */
@@ -580,18 +576,18 @@ static int ch9_postconfig (struct usbtes
 			continue;
 
 		/* [9.4.10] set_interface */
-		retval = set_altsetting (dev, i);
+		retval = set_altsetting (dev, alt);
 		if (retval) {
 			dev_dbg (&iface->dev, "can't set_interface = %d, %d\n",
-					i, retval);
+					alt, retval);
 			return retval;
 		}
 
 		/* [9.4.4] get_interface always works */
 		retval = get_altsetting (dev);
-		if (retval != i) {
+		if (retval != alt) {
 			dev_dbg (&iface->dev, "get alt should be %d, was %d\n",
-					i, retval);
+					alt, retval);
 			return (retval < 0) ? retval : -EDOM;
 		}
 
--- diff/drivers/usb/net/usbnet.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/usb/net/usbnet.c	2004-03-09 11:51:51.000000000 +0000
@@ -3009,7 +3009,7 @@ usbnet_probe (struct usb_interface *udev
 		return -ENODEV;
 	}
 	xdev = interface_to_usbdev (udev);
-	interface = &udev->altsetting [udev->act_altsetting];
+	interface = udev->cur_altsetting;
 
 	usb_get_dev (xdev);
 
@@ -3314,6 +3314,15 @@ static const struct usb_device_id	produc
 	.bInterfaceSubClass     = 0x0a,
 	.bInterfaceProtocol     = 0x00,
 	.driver_info =  (unsigned long) &zaurus_pxa_info,
+}, {
+	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+		 | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor               = 0x04DD,
+	.idProduct              = 0x9050,	/* C-860 */
+	.bInterfaceClass        = 0x02,
+	.bInterfaceSubClass     = 0x0a,
+	.bInterfaceProtocol     = 0x00,
+	.driver_info =  (unsigned long) &zaurus_pxa_info,
 },
 #endif
 
--- diff/drivers/usb/serial/ftdi_sio.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/usb/serial/ftdi_sio.c	2004-03-09 11:51:51.000000000 +0000
@@ -286,6 +286,7 @@ static struct usb_device_id id_table_sio
 
 
 static struct usb_device_id id_table_8U232AM [] = {
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0, 0x3ff) },
@@ -358,6 +359,7 @@ static struct usb_device_id id_table_8U2
 
 
 static struct usb_device_id id_table_FT232BM [] = {
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0x400, 0xffff) },
@@ -451,6 +453,7 @@ static struct usb_device_id id_table_HE_
 
 
 static struct usb_device_id id_table_combined [] = {
+	{ USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
--- diff/drivers/usb/serial/ftdi_sio.h	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/usb/serial/ftdi_sio.h	2004-03-09 11:51:51.000000000 +0000
@@ -30,6 +30,8 @@
 #define FTDI_NF_RIC_VID	0x0DCD	/* Vendor Id */
 #define FTDI_NF_RIC_PID	0x0001	/* Product Id */
 
+/* www.irtrans.de device */
+#define FTDI_IRTRANS_PID 0xFC60 /* Product Id */
 
 /* www.crystalfontz.com devices - thanx for providing free devices for evaluation ! */
 /* they use the ftdi chipset for the USB interface and the vendor id is the same */
--- diff/drivers/usb/serial/kl5kusb105.c	2003-09-17 12:28:11.000000000 +0100
+++ source/drivers/usb/serial/kl5kusb105.c	2004-03-09 11:51:51.000000000 +0000
@@ -273,6 +273,7 @@ static int klsi_105_startup (struct usb_
 
 	/* allocate the private data structure */
 	for (i=0; i<serial->num_ports; i++) {
+		int j;
 		priv = kmalloc(sizeof(struct klsi_105_private),
 						   GFP_KERNEL);
 		if (!priv) {
@@ -293,10 +294,10 @@ static int klsi_105_startup (struct usb_
 		usb_set_serial_port_data(serial->port[i], priv);
 
 		spin_lock_init (&priv->lock);
-		for (i=0; i<NUM_URBS; i++) {
+		for (j=0; j<NUM_URBS; j++) {
 			struct urb* urb = usb_alloc_urb(0, GFP_KERNEL);
 
-			priv->write_urb_pool[i] = urb;
+			priv->write_urb_pool[j] = urb;
 			if (urb == NULL) {
 				err("No more urbs???");
 				continue;
--- diff/drivers/usb/serial/safe_serial.c	2003-09-17 12:28:11.000000000 +0100
+++ source/drivers/usb/serial/safe_serial.c	2004-03-09 11:51:51.000000000 +0000
@@ -93,6 +93,7 @@ static int padded = CONFIG_USB_SAFE_PADD
 
 MODULE_AUTHOR (DRIVER_AUTHOR);
 MODULE_DESCRIPTION (DRIVER_DESC);
+MODULE_LICENSE("GPL");
 
 #if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT)
 #abort "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT"
--- diff/drivers/usb/serial/visor.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/serial/visor.c	2004-03-09 11:51:51.000000000 +0000
@@ -239,6 +239,8 @@ static struct usb_device_id id_table [] 
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID), 
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
+	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID), 
+		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID), 
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID),
@@ -275,6 +277,7 @@ static struct usb_device_id id_table_com
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_ID) },
 	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) },
+	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID) },
 	{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) },
 	{ USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) },
 	{ },					/* optional parameter entry */
--- diff/drivers/usb/serial/visor.h	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/serial/visor.h	2004-03-09 11:51:51.000000000 +0000
@@ -46,6 +46,7 @@
 
 #define SAMSUNG_VENDOR_ID		0x04E8
 #define SAMSUNG_SCH_I330_ID		0x8001
+#define SAMSUNG_SPH_I500_ID		0x6601
 
 #define GARMIN_VENDOR_ID		0x091E
 #define GARMIN_IQUE_3600_ID		0x0004
--- diff/drivers/usb/storage/scsiglue.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/storage/scsiglue.c	2004-03-09 11:51:51.000000000 +0000
@@ -64,8 +64,10 @@ static const char* host_info(struct Scsi
 	return "SCSI emulation for USB Mass Storage devices";
 }
 
-static int slave_configure (struct scsi_device *sdev)
+static int slave_configure(struct scsi_device *sdev)
 {
+	struct us_data *us = (struct us_data *) sdev->host->hostdata[0];
+
 	/* Scatter-gather buffers (all but the last) must have a length
 	 * divisible by the bulk maxpacket size.  Otherwise a data packet
 	 * would end up being short, causing a premature end to the data
@@ -76,6 +78,16 @@ static int slave_configure (struct scsi_
 	 * the end, scatter-gather buffers follow page boundaries. */
 	blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
 
+	/* Devices using Genesys Logic chips cause a lot of trouble for
+	 * high-speed transfers; they die unpredictably when given more
+	 * than 64 KB of data at a time.  If we detect such a device,
+	 * reduce the maximum transfer size to 64 KB = 128 sectors. */
+
+#define USB_VENDOR_ID_GENESYS	0x05e3		// Needs a standard location
+	if (us->pusb_dev->descriptor.idVendor == USB_VENDOR_ID_GENESYS &&
+			us->pusb_dev->speed == USB_SPEED_HIGH)
+		blk_queue_max_sectors(sdev->request_queue, 128);
+
 	/* this is to satisify the compiler, tho I don't think the 
 	 * return code is ever checked anywhere. */
 	return 0;
--- diff/drivers/usb/storage/transport.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/usb/storage/transport.c	2004-03-09 11:51:51.000000000 +0000
@@ -563,9 +563,9 @@ void usb_stor_invoke_transport(Scsi_Cmnd
 
 	/*
 	 * If we're running the CB transport, which is incapable
-	 * of determining status on its own, we need to auto-sense
+	 * of determining status on its own, we will auto-sense
 	 * unless the operation involved a data-in transfer.  Devices
-	 * can signal data-in errors by stalling the bulk-in pipe.
+	 * can signal most data-in errors by stalling the bulk-in pipe.
 	 */
 	if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) &&
 			srb->sc_data_direction != SCSI_DATA_READ) {
@@ -698,7 +698,11 @@ void usb_stor_invoke_transport(Scsi_Cmnd
 		 * out the sense buffer so the higher layers won't realize
 		 * we did an unsolicited auto-sense. */
 		if (result == USB_STOR_TRANSPORT_GOOD &&
-				(srb->sense_buffer[2] & 0xf) == 0x0) {
+			/* Filemark 0, ignore EOM, ILI 0, no sense */
+				(srb->sense_buffer[2] & 0xaf) == 0 &&
+			/* No ASC or ASCQ */
+				srb->sense_buffer[12] == 0 &&
+				srb->sense_buffer[13] == 0) {
 			srb->result = SAM_STAT_GOOD;
 			srb->sense_buffer[0] = 0x0;
 		}
@@ -809,15 +813,19 @@ int usb_stor_CBI_transport(Scsi_Cmnd *sr
 	}
 
 	/* If not UFI, we interpret the data as a result code 
-	 * The first byte should always be a 0x0
-	 * The second byte & 0x0F should be 0x0 for good, otherwise error 
+	 * The first byte should always be a 0x0.
+	 *
+	 * Some bogus devices don't follow that rule.  They stuff the ASC
+	 * into the first byte -- so if it's non-zero, call it a failure.
 	 */
 	if (us->iobuf[0]) {
-		US_DEBUGP("CBI IRQ data showed reserved bType %d\n",
+		US_DEBUGP("CBI IRQ data showed reserved bType 0x%x\n",
 				us->iobuf[0]);
-		return USB_STOR_TRANSPORT_ERROR;
+		goto Failed;
+
 	}
 
+	/* The second byte & 0x0F should be 0x0 for good, otherwise error */
 	switch (us->iobuf[1] & 0x0F) {
 		case 0x00: 
 			return USB_STOR_TRANSPORT_GOOD;
--- diff/drivers/usb/storage/unusual_devs.h	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/usb/storage/unusual_devs.h	2004-03-09 11:51:51.000000000 +0000
@@ -261,6 +261,14 @@ UNUSUAL_DEV(  0x054c, 0x0010, 0x0106, 0x
 		US_SC_SCSI, US_PR_DEVICE, NULL,
 		US_FL_SINGLE_LUN | US_FL_MODE_XLATE ),
 
+/* This entry is needed because the device reports Sub=ff */
+UNUSUAL_DEV(  0x054c, 0x0010, 0x0500, 0x0500, 
+               "Sony",
+               "DSC-T1", 
+               US_SC_8070, US_PR_DEVICE, NULL,
+               US_FL_SINGLE_LUN | US_FL_MODE_XLATE ),
+
+
 /* Reported by wim@geeks.nl */
 UNUSUAL_DEV(  0x054c, 0x0025, 0x0100, 0x0100, 
 		"Sony",
@@ -368,7 +376,7 @@ UNUSUAL_DEV(  0x05ab, 0x5701, 0x0100, 0x
 UNUSUAL_DEV(  0x05dc, 0x0001, 0x0000, 0x0001,
 		"Lexar",
 		"Jumpshot USB CF Reader",
-		US_SC_SCSI, US_PR_JUMPSHOT, NULL,
+		US_SC_DEVICE, US_PR_JUMPSHOT, NULL,
 		US_FL_MODE_XLATE ),
 #endif
 
@@ -440,12 +448,6 @@ UNUSUAL_DEV( 0x0686, 0x4006, 0x0001, 0x0
 		US_SC_SCSI, US_PR_DEVICE, NULL,
 		0 ),
 
-UNUSUAL_DEV( 0x0686, 0x400b, 0x0001, 0x0001,
-		"Minolta",
-		"DiMAGE 7i",
-		US_SC_SCSI, US_PR_DEVICE, NULL,
-		0 ),
-
 UNUSUAL_DEV( 0x0686, 0x400f, 0x0001, 0x0001,
 		"Minolta",
 		"DiMAGE 7Hi",
@@ -619,6 +621,9 @@ UNUSUAL_DEV(  0x07c4, 0xa400, 0x0000, 0x
  *   are using transport protocol CB.
  * - They don't like the INQUIRY command. So we must handle this command
  *   of the SCSI layer ourselves.
+ * - Some cameras with idProduct=0x1001 and bcdDevice=0x1000 have
+ *   bInterfaceProtocol=0x00 (US_PR_CBI) while others have 0x01 (US_PR_CB).
+ *   So don't remove the US_PR_CB override!
  */
 UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9009,
 		"Casio",
@@ -649,6 +654,17 @@ UNUSUAL_DEV(  0x08ca, 0x2011, 0x0000, 0x
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_MODE_XLATE ),
 
+/* Entry needed for flags. Moreover, all devices with this ID use
+ * bulk-only transport, but _some_ falsely report Control/Bulk instead.
+ * One example is "Trumpion Digital Research MYMP3".
+ * Submitted by Bjoern Brill <brill(at)fs.math.uni-frankfurt.de>
+ */
+UNUSUAL_DEV(  0x090a, 0x1001, 0x0100, 0x0100,
+		"Trumpion",
+		"t33520 USB Flash Card Controller",
+		US_SC_DEVICE, US_PR_BULK, NULL,
+		US_FL_MODE_XLATE),
+
 /* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */
 UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999,
 		"Trumpion",
@@ -688,15 +704,9 @@ UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1
                 US_SC_DEVICE, US_PR_DEVICE, NULL,
                 US_FL_FIX_INQUIRY ),
 
-/* This entry from <matthias@ma-c.de> in the Debian mailing list */
-UNUSUAL_DEV( 0x0a17, 0x0006, 0x0000, 0xffff,
-		"Pentax",
-		"Optio 330GS",
-		US_SC_8070, US_PR_CB, NULL,
-		US_FL_MODE_XLATE | US_FL_FIX_INQUIRY ),
 
 /* Submitted by Per Winkvist <per.winkvist@uk.com> */
-UNUSUAL_DEV( 0x0a17, 0x006, 0x1000, 0x9009,
+UNUSUAL_DEV( 0x0a17, 0x006, 0x0000, 0xffff,
                 "Pentax",
                 "Optio S/S4",
                 US_SC_DEVICE, US_PR_DEVICE, NULL,
--- diff/drivers/usb/storage/usb.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/storage/usb.c	2004-03-09 11:51:51.000000000 +0000
@@ -423,7 +423,7 @@ static int associate_dev(struct us_data 
 	/* Fill in the device-related fields */
 	us->pusb_dev = interface_to_usbdev(intf);
 	us->pusb_intf = intf;
-	us->ifnum = intf->altsetting->desc.bInterfaceNumber;
+	us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
 
 	/* Store our private data in the interface and increment the
 	 * device's reference count */
@@ -452,7 +452,7 @@ static void get_device_info(struct us_da
 {
 	struct usb_device *dev = us->pusb_dev;
 	struct usb_interface_descriptor *idesc =
-		&us->pusb_intf->altsetting[us->pusb_intf->act_altsetting].desc;
+		&us->pusb_intf->cur_altsetting->desc;
 	struct us_unusual_dev *unusual_dev = &us_unusual_dev_list[id_index];
 	struct usb_device_id *id = &storage_usb_ids[id_index];
 
@@ -686,7 +686,7 @@ static int get_protocol(struct us_data *
 static int get_pipes(struct us_data *us)
 {
 	struct usb_host_interface *altsetting =
-		&us->pusb_intf->altsetting[us->pusb_intf->act_altsetting];
+		us->pusb_intf->cur_altsetting;
 	int i;
 	struct usb_endpoint_descriptor *ep;
 	struct usb_endpoint_descriptor *ep_in = NULL;
@@ -877,8 +877,9 @@ static int storage_probe(struct usb_inte
 	int result;
 
 	US_DEBUGP("USB Mass Storage device detected\n");
-	US_DEBUGP("act_altsetting is %d, id_index is %d\n",
-			intf->act_altsetting, id_index);
+	US_DEBUGP("altsetting is %d, id_index is %d\n",
+			intf->cur_altsetting->desc.bAlternateSetting,
+			id_index);
 
 	/* Allocate the us_data structure and initialize the mutexes */
 	us = (struct us_data *) kmalloc(sizeof(*us), GFP_KERNEL);
@@ -954,8 +955,6 @@ static int storage_probe(struct usb_inte
 	scsi_scan_host(us->host);
 
 	printk(KERN_DEBUG 
-	       "WARNING: USB Mass Storage data integrity not assured\n");
-	printk(KERN_DEBUG 
 	       "USB Mass Storage device found at %d\n", us->pusb_dev->devnum);
 	return 0;
 
--- diff/drivers/usb/storage/usb.h	2003-09-17 12:28:11.000000000 +0100
+++ source/drivers/usb/storage/usb.h	2004-03-09 11:51:51.000000000 +0000
@@ -176,6 +176,5 @@ extern void fill_inquiry_response(struct
  * single queue element srb for write access */
 #define scsi_unlock(host)	spin_unlock_irq(host->host_lock)
 #define scsi_lock(host)		spin_lock_irq(host->host_lock)
-#define sg_address(psg)		(page_address((psg).page) + (psg).offset)
 
 #endif
--- diff/drivers/video/aty/radeon_base.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/video/aty/radeon_base.c	2004-03-09 11:51:51.000000000 +0000
@@ -135,7 +135,7 @@ static struct pci_device_id radeonfb_pci
 	CHIP_DEF(PCI_CHIP_R200_QM,	R200,	CHIP_HAS_CRTC2),
 	/* Mobility M7 */
 	CHIP_DEF(PCI_CHIP_RADEON_LW,	RV200,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
-	CHIP_DEF(PCI_CHIP_RADEON_LW,	RV200,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	CHIP_DEF(PCI_CHIP_RADEON_LX,	RV200,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
 	/* 7500 */
 	CHIP_DEF(PCI_CHIP_RV200_QW,	RV200,	CHIP_HAS_CRTC2),
 	CHIP_DEF(PCI_CHIP_RV200_QX,	RV200,	CHIP_HAS_CRTC2),
--- diff/drivers/video/console/fbcon.c	2004-03-04 11:41:48.000000000 +0000
+++ source/drivers/video/console/fbcon.c	2004-03-09 11:51:51.000000000 +0000
@@ -2345,6 +2345,7 @@ int __init fb_console_init(void)
 {
 	if (!num_registered_fb)
 		return -ENODEV;
+
 	take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default);
 	acquire_console_sem();
 	if (!fbcon_event_notifier_registered) {
@@ -2352,10 +2353,11 @@ int __init fb_console_init(void)
 		fbcon_event_notifier_registered = 1;
 	} 
 	release_console_sem();
-
 	return 0;
 }
 
+#ifdef MODULE
+
 void __exit fb_console_exit(void)
 {
 	acquire_console_sem();
@@ -2370,6 +2372,8 @@ void __exit fb_console_exit(void)
 module_init(fb_console_init);
 module_exit(fb_console_exit);
 
+#endif
+
 /*
  *  Visible symbols for modules
  */
--- diff/drivers/video/ffb.c	2003-08-26 10:00:54.000000000 +0100
+++ source/drivers/video/ffb.c	2004-03-09 11:51:51.000000000 +0000
@@ -466,6 +466,7 @@ static __inline__ void ffb_rop(struct ff
 static void ffb_switch_from_graph(struct ffb_par *par)
 {
 	struct ffb_fbc *fbc = par->fbc;
+	struct ffb_dac *dac = par->dac;
 	unsigned long flags;
 
 	spin_lock_irqsave(&par->lock, flags);
@@ -482,6 +483,14 @@ static void ffb_switch_from_graph(struct
 	upa_writel(par->fg_cache, &fbc->fg);
 	upa_writel(par->bg_cache, &fbc->bg);
 	FFBWait(par);
+
+	/* Disable cursor.  */
+	upa_writel(0x100, &dac->type2);
+	if (par->dac_rev <= 2)
+		upa_writel(0, &dac->value2);
+	else
+		upa_writel(3, &dac->value2);
+
 	spin_unlock_irqrestore(&par->lock, flags);
 }
 
--- diff/drivers/video/i810/i810_main.h	2003-09-30 15:46:18.000000000 +0100
+++ source/drivers/video/i810/i810_main.h	2004-03-09 11:51:51.000000000 +0000
@@ -84,7 +84,7 @@ extern void i810fb_init_ringbuffer(struc
 extern void i810fb_load_front     (u32 offset, struct fb_info *info);
 
 /* Conditionals */
-#if defined(__i386__)
+#ifdef CONFIG_X86
 inline void flush_cache(void)
 {
 	asm volatile ("wbinvd":::"memory");
--- diff/fs/Kconfig	2004-03-04 11:41:48.000000000 +0000
+++ source/fs/Kconfig	2004-03-09 11:51:51.000000000 +0000
@@ -780,6 +780,30 @@ config PROC_KCORE
 	bool
 	default y if !ARM
 
+config SYSFS
+	bool "sysfs file system support" if EMBEDDED
+	default y
+	help
+	The sysfs filesystem is a virtual filesystem that the kernel uses to export
+	internal kernel objects, their attributes, and their relationships to one
+	another.
+
+	Users can use sysfs to ascertain useful information about the running kernel,
+	such as the devices the kernel has discovered on each bus and which driver
+	each is bound to. sysfs can also be used to tune devices and other kernel
+	subsystems.
+
+	Some system agents rely on the information in sysfs to operate. /sbin/hotplug
+	uses device and object attributes in sysfs to assist in delegating policy
+	decisions, like persistantly naming devices.
+
+	sysfs is currently needed by the block subsystem to mount the root partition.
+	Therefore, you MUST say Y if you're booting from a hard drive. If you use any
+	type of hotpluggable device, you'll also need sysfs for /sbin/hotplug support.
+
+	However, designers of embedded systems may want to say N here to conserve
+	space.
+
 config DEVFS_FS
 	bool "/dev file system support (OBSOLETE)"
 	depends on EXPERIMENTAL
@@ -1227,6 +1251,9 @@ config UFS_FS
 	  experimental "UFS file system write support", below. Please read the
 	  file <file:Documentation/filesystems/ufs.txt> for more information.
 
+          The recently released UFS2 variant (used in FreeBSD 5.x) is
+          READ-ONLY supported.
+
 	  If you only intend to mount files from some other Unix over the
 	  network using NFS, you don't need the UFS file system support (but
 	  you need NFS file system support obviously).
@@ -1302,15 +1329,18 @@ config NFS_V3
 	  Say Y here if you want your NFS client to be able to speak the newer
 	  version 3 of the NFS protocol.
 
-	  If unsure, say N.
+	  If unsure, say Y.
 
 config NFS_V4
 	bool "Provide NFSv4 client support (EXPERIMENTAL)"
 	depends on NFS_FS && EXPERIMENTAL
+	select RPCSEC_GSS_KRB5
 	help
 	  Say Y here if you want your NFS client to be able to speak the newer
-	  version 4 of the NFS protocol.  This feature is experimental, and
-	  should only be used if you are interested in helping to test NFSv4.
+	  version 4 of the NFS protocol.
+
+	  Note: Requires auxiliary userspace daemons which may be found on
+		http://www.citi.umich.edu/projects/nfsv4/
 
 	  If unsure, say N.
 
@@ -1419,28 +1449,24 @@ config SUNRPC
 	tristate
 
 config SUNRPC_GSS
-	tristate "Provide RPCSEC_GSS authentication (EXPERIMENTAL)"
+	tristate
+
+config RPCSEC_GSS_KRB5
+	tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)"
 	depends on SUNRPC && EXPERIMENTAL
-	default SUNRPC if NFS_V4=y
+	select SUNRPC_GSS
+	select CRYPTO
+	select CRYPTO_MD5
+	select CRYPTO_DES
 	help
-	  Provides cryptographic authentication for NFS rpc requests.  To
-	  make this useful, you must also select at least one rpcsec_gss
-	  mechanism.
-	  Note: You should always select this option if you wish to use
+	  Provides for secure RPC calls by means of a gss-api
+	  mechanism based on Kerberos V5. This is required for
 	  NFSv4.
 
-config RPCSEC_GSS_KRB5
-	tristate "Kerberos V mechanism for RPCSEC_GSS (EXPERIMENTAL)"
-	depends on SUNRPC_GSS && CRYPTO_DES && CRYPTO_MD5
-	default SUNRPC_GSS if NFS_V4=y
-	help
-	  Provides a gss-api mechanism based on Kerberos V5 (this is
-	  mandatory for RFC3010-compliant NFSv4 implementations).
-	  Requires a userspace daemon;
-		see http://www.citi.umich.edu/projects/nfsv4/.
+	  Note: Requires an auxiliary userspace daemon which may be found on
+		http://www.citi.umich.edu/projects/nfsv4/
 
-	  Note: If you select this option, please ensure that you also
-	  enable the MD5 and DES crypto ciphers.
+	  If unsure, say N.
 
 config SMB_FS
 	tristate "SMB file system support (to mount Windows shares etc.)"
--- diff/fs/Makefile	2004-03-04 11:41:48.000000000 +0000
+++ source/fs/Makefile	2004-03-09 11:51:51.000000000 +0000
@@ -39,7 +39,7 @@ obj-$(CONFIG_QUOTACTL)		+= quota.o
 
 obj-$(CONFIG_PROC_FS)		+= proc/
 obj-y				+= partitions/
-obj-y				+= sysfs/
+obj-$(CONFIG_SYSFS)		+= sysfs/
 obj-y				+= devpts/
 
 obj-$(CONFIG_PROFILING)		+= dcookies.o
--- diff/fs/adfs/super.c	2003-10-09 09:47:34.000000000 +0100
+++ source/fs/adfs/super.c	2004-03-09 11:51:51.000000000 +0000
@@ -333,6 +333,9 @@ static int adfs_fill_super(struct super_
 	struct object_info root_obj;
 	unsigned char *b_data;
 	struct adfs_sb_info *asb;
+	struct inode *root;
+
+	sb->s_flags |= MS_NODIRATIME;
 
 	asb = kmalloc(sizeof(*asb), GFP_KERNEL);
 	if (!asb)
@@ -443,10 +446,11 @@ static int adfs_fill_super(struct super_
 		asb->s_namelen = ADFS_F_NAME_LEN;
 	}
 
-	sb->s_root = d_alloc_root(adfs_iget(sb, &root_obj));
+	root = adfs_iget(sb, &root_obj);
+	sb->s_root = d_alloc_root(root);
 	if (!sb->s_root) {
 		int i;
-
+		iput(root);
 		for (i = 0; i < asb->s_map_size; i++)
 			brelse(asb->s_map[i].dm_bh);
 		kfree(asb->s_map);
--- diff/fs/affs/super.c	2003-10-09 09:47:34.000000000 +0100
+++ source/fs/affs/super.c	2004-03-09 11:51:51.000000000 +0000
@@ -293,6 +293,7 @@ static int affs_fill_super(struct super_
 
 	sb->s_magic             = AFFS_SUPER_MAGIC;
 	sb->s_op                = &affs_sops;
+	sb->s_flags |= MS_NODIRATIME;
 
 	sbi = kmalloc(sizeof(struct affs_sb_info), GFP_KERNEL);
 	if (!sbi)
--- diff/fs/afs/inode.c	2004-03-04 11:41:48.000000000 +0000
+++ source/fs/afs/inode.c	2004-03-09 11:51:51.000000000 +0000
@@ -188,6 +188,7 @@ inline int afs_iget(struct super_block *
 #endif
 
 	/* okay... it's a new inode */
+	inode->i_flags |= S_NOATIME;
 	vnode->flags |= AFS_VNODE_CHANGED;
 	ret = afs_inode_fetch_status(inode);
 	if (ret<0)
--- diff/fs/afs/super.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/afs/super.c	2004-03-09 11:51:51.000000000 +0000
@@ -53,6 +53,7 @@ static struct file_system_type afs_fs_ty
 	.name		= "afs",
 	.get_sb		= afs_get_sb,
 	.kill_sb	= kill_anon_super,
+	.fs_flags	= FS_BINARY_MOUNTDATA,
 };
 
 static struct super_operations afs_super_ops = {
@@ -280,7 +281,6 @@ static int afs_fill_super(struct super_b
 	return 0;
 
  error:
-	dput(root);
 	iput(inode);
 	afs_put_volume(as->volume);
 	kfree(as);
--- diff/fs/aio.c	2003-11-25 15:24:58.000000000 +0000
+++ source/fs/aio.c	2004-03-09 11:51:51.000000000 +0000
@@ -312,7 +312,7 @@ void wait_for_all_aios(struct kioctx *ct
 /* wait_on_sync_kiocb:
  *	Waits on the given sync kiocb to complete.
  */
-ssize_t wait_on_sync_kiocb(struct kiocb *iocb)
+ssize_t fastcall wait_on_sync_kiocb(struct kiocb *iocb)
 {
 	while (iocb->ki_users) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
@@ -331,7 +331,7 @@ ssize_t wait_on_sync_kiocb(struct kiocb 
  * go away, they will call put_ioctx and release any pinned memory
  * associated with the request (held via struct page * references).
  */
-void exit_aio(struct mm_struct *mm)
+void fastcall exit_aio(struct mm_struct *mm)
 {
 	struct kioctx *ctx = mm->ioctx_list;
 	mm->ioctx_list = NULL;
@@ -356,7 +356,7 @@ void exit_aio(struct mm_struct *mm)
  *	Called when the last user of an aio context has gone away,
  *	and the struct needs to be freed.
  */
-void __put_ioctx(struct kioctx *ctx)
+void fastcall __put_ioctx(struct kioctx *ctx)
 {
 	unsigned nr_events = ctx->max_reqs;
 
@@ -383,7 +383,7 @@ void __put_ioctx(struct kioctx *ctx)
  * req (after submitting it) and aio_complete() freeing the req.
  */
 static struct kiocb *FASTCALL(__aio_get_req(struct kioctx *ctx));
-static struct kiocb *__aio_get_req(struct kioctx *ctx)
+static struct kiocb fastcall *__aio_get_req(struct kioctx *ctx)
 {
 	struct kiocb *req = NULL;
 	struct aio_ring *ring;
@@ -509,7 +509,7 @@ static int __aio_put_req(struct kioctx *
  *	Returns true if this put was the last user of the kiocb,
  *	false if the request is still in use.
  */
-int aio_put_req(struct kiocb *req)
+int fastcall aio_put_req(struct kiocb *req)
 {
 	struct kioctx *ctx = req->ki_ctx;
 	int ret;
@@ -596,7 +596,7 @@ static void aio_kick_handler(void *data)
 	unuse_mm(ctx->mm);
 }
 
-void kick_iocb(struct kiocb *iocb)
+void fastcall kick_iocb(struct kiocb *iocb)
 {
 	struct kioctx	*ctx = iocb->ki_ctx;
 
@@ -622,7 +622,7 @@ void kick_iocb(struct kiocb *iocb)
  *	Returns true if this is the last user of the request.  The 
  *	only other user of the request can be the cancellation code.
  */
-int aio_complete(struct kiocb *iocb, long res, long res2)
+int fastcall aio_complete(struct kiocb *iocb, long res, long res2)
 {
 	struct kioctx	*ctx = iocb->ki_ctx;
 	struct aio_ring_info	*info;
@@ -985,7 +985,7 @@ asmlinkage long sys_io_destroy(aio_conte
 	return -EINVAL;
 }
 
-int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
+int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
 			 struct iocb *iocb)
 {
 	struct kiocb *req;
--- diff/fs/autofs4/inode.c	2003-10-09 09:47:34.000000000 +0100
+++ source/fs/autofs4/inode.c	2004-03-09 11:51:51.000000000 +0000
@@ -213,6 +213,9 @@ int autofs4_fill_super(struct super_bloc
 	 * Get the root inode and dentry, but defer checking for errors.
 	 */
 	root_inode = autofs4_get_inode(s, autofs4_mkroot(sbi));
+	if (!root_inode)
+		goto fail_free;
+
 	root_inode->i_op = &autofs4_root_inode_operations;
 	root_inode->i_fop = &autofs4_root_operations;
 	root = d_alloc_root(root_inode);
@@ -264,22 +267,13 @@ int autofs4_fill_super(struct super_bloc
 	 */
 fail_fput:
 	printk("autofs: pipe file descriptor does not contain proper ops\n");
-	/*
-	 * fput() can block, so we clear the super block first.
-	 */
 	fput(pipe);
 	/* fall through */
 fail_dput:
-	/*
-	 * dput() can block, so we clear the super block first.
-	 */
 	dput(root);
 	goto fail_free;
 fail_iput:
 	printk("autofs: get root dentry failed\n");
-	/*
-	 * iput() can block, so we clear the super block first.
-	 */
 	iput(root_inode);
 fail_free:
 	kfree(sbi);
--- diff/fs/befs/linuxvfs.c	2003-10-27 09:20:44.000000000 +0000
+++ source/fs/befs/linuxvfs.c	2004-03-09 11:51:51.000000000 +0000
@@ -789,6 +789,7 @@ befs_fill_super(struct super_block *sb, 
 	struct buffer_head *bh;
 	befs_sb_info *befs_sb;
 	befs_super_block *disk_sb;
+	struct inode *root;
 
 	const unsigned long sb_block = 0;
 	const off_t x86_sb_off = 512;
@@ -863,9 +864,10 @@ befs_fill_super(struct super_block *sb, 
 	/* Set real blocksize of fs */
 	sb_set_blocksize(sb, (ulong) befs_sb->block_size);
 	sb->s_op = (struct super_operations *) &befs_sops;
-	sb->s_root =
-	    d_alloc_root(iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir))));
+	root = iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir)));
+	sb->s_root = d_alloc_root(root);
 	if (!sb->s_root) {
+		iput(root);
 		befs_error(sb, "get root inode failed");
 		goto unaquire_priv_sbp;
 	}
--- diff/fs/bfs/dir.c	2003-10-09 09:47:17.000000000 +0100
+++ source/fs/bfs/dir.c	2004-03-09 11:51:51.000000000 +0000
@@ -65,7 +65,6 @@ static int bfs_readdir(struct file * f, 
 		brelse(bh);
 	}
 
-	update_atime(dir);
 	unlock_kernel();
 	return 0;	
 }
--- diff/fs/binfmt_aout.c	2003-09-30 15:46:18.000000000 +0100
+++ source/fs/binfmt_aout.c	2004-03-09 11:51:51.000000000 +0000
@@ -309,7 +309,7 @@ static int load_aout_binary(struct linux
 		(current->mm->start_brk = N_BSSADDR(ex));
 	current->mm->free_area_cache = TASK_UNMAPPED_BASE;
 
-	current->mm->rss = 0;
+	zero_rss(current->mm);
 	current->mm->mmap = NULL;
 	compute_creds(bprm);
  	current->flags &= ~PF_FORKNOEXEC;
--- diff/fs/binfmt_elf.c	2004-03-04 11:41:48.000000000 +0000
+++ source/fs/binfmt_elf.c	2004-03-09 11:51:51.000000000 +0000
@@ -672,7 +672,7 @@ static int load_elf_binary(struct linux_
 
 	/* Do this so that we can load the interpreter, if need be.  We will
 	   change some of these later */
-	current->mm->rss = 0;
+	zero_rss(current->mm);
 	current->mm->free_area_cache = TASK_UNMAPPED_BASE;
 	retval = setup_arg_pages(bprm);
 	if (retval < 0) {
@@ -830,9 +830,8 @@ static int load_elf_binary(struct linux_
 		   and some applications "depend" upon this behavior.
 		   Since we do not have the power to recompile these, we
 		   emulate the SVr4 behavior.  Sigh.  */
-		/* N.B. Shouldn't the size here be PAGE_SIZE?? */
 		down_write(&current->mm->mmap_sem);
-		error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
+		error = do_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC,
 				MAP_FIXED | MAP_PRIVATE, 0);
 		up_write(&current->mm->mmap_sem);
 	}
--- diff/fs/binfmt_flat.c	2004-03-04 11:41:48.000000000 +0000
+++ source/fs/binfmt_flat.c	2004-03-09 11:51:51.000000000 +0000
@@ -651,7 +651,7 @@ static int load_flat_file(struct linux_b
 		current->mm->start_brk = datapos + data_len + bss_len;
 		current->mm->brk = (current->mm->start_brk + 3) & ~3;
 		current->mm->context.end_brk = memp + ksize((void *) memp) - stack_len;
-		current->mm->rss = 0;
+		zero_rss(current->mm);
 	}
 
 	if (flags & FLAT_FLAG_KTRACE)
--- diff/fs/binfmt_misc.c	2004-03-04 11:41:48.000000000 +0000
+++ source/fs/binfmt_misc.c	2004-03-09 11:51:51.000000000 +0000
@@ -39,6 +39,8 @@ static int enabled = 1;
 
 enum {Enabled, Magic};
 #define MISC_FMT_PRESERVE_ARGV0 (1<<31)
+#define MISC_FMT_OPEN_BINARY (1<<30)
+#define MISC_FMT_CREDENTIALS (1<<29)
 
 typedef struct {
 	struct list_head list;
@@ -102,10 +104,15 @@ static Node *check_file(struct linux_bin
 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 {
 	Node *fmt;
-	struct file * file;
+	struct file * interp_file = NULL;
+	struct file * binary_file = NULL;
 	char iname[BINPRM_BUF_SIZE];
 	char *iname_addr = iname;
 	int retval;
+	int fd_binary = -1;
+	char fd_str[32];
+	char * fdsp = fd_str;
+	int is_open_bin;
 
 	retval = -ENOEXEC;
 	if (!enabled)
@@ -120,33 +127,105 @@ static int load_misc_binary(struct linux
 	if (!fmt)
 		goto _ret;
 
-	allow_write_access(bprm->file);
-	fput(bprm->file);
-	bprm->file = NULL;
+	is_open_bin = (fmt->flags & MISC_FMT_OPEN_BINARY) ? 1 : 0;
+
+ 	if (is_open_bin) {
+		/* if the binary should be opened on behalf of the
+		 * interpreter than keep it open and assign descriptor
+		 * to it */
+ 		fd_binary = get_unused_fd ();
+ 		if (fd_binary < 0) {
+ 			retval = fd_binary;
+ 			goto _ret;
+ 		}
+ 		snprintf (fd_str, sizeof(fd_str) - 1, "%d", fd_binary);
+ 	} else {
+ 		allow_write_access (bprm->file);
+ 		fput (bprm->file);
+ 		bprm->file = NULL;
+ 	}
 
 	/* Build args for interpreter */
 	if (!(fmt->flags & MISC_FMT_PRESERVE_ARGV0)) {
 		remove_arg_zero(bprm);
 	}
-	retval = copy_strings_kernel(1, &bprm->interp, bprm);
-	if (retval < 0) goto _ret; 
-	bprm->argc++;
-	retval = copy_strings_kernel(1, &iname_addr, bprm);
-	if (retval < 0) goto _ret; 
-	bprm->argc++;
+
+ 	if (is_open_bin) {
+		/* make argv[1] be the file descriptor of the binary */
+ 		retval = copy_strings_kernel (1, &fdsp, bprm);
+ 	} else {
+		/* make argv[1] be the path to the binary */
+ 		retval = copy_strings_kernel (1, &bprm->interp, bprm);
+ 	}
+	if (retval < 0)
+		goto _error;
+	bprm->argc ++;
+	retval = copy_strings_kernel (1, &iname_addr, bprm);
+	if (retval < 0)
+		goto _error;
+	bprm->argc ++;
 	bprm->interp = iname;	/* for binfmt_script */
 
-	file = open_exec(iname);
-	retval = PTR_ERR(file);
-	if (IS_ERR(file))
-		goto _ret;
-	bprm->file = file;
+	interp_file = open_exec (iname);
+	retval = PTR_ERR (interp_file);
+	if (IS_ERR (interp_file))
+		goto _error;
+
+
+	binary_file = bprm->file;
+	if (fmt->flags & MISC_FMT_CREDENTIALS) {
+		/*
+		 * Call prepare_binprm before switching to interpreter's file
+		 * so that all security calculation will be done according to
+		 * binary and not interpreter
+		 */
+		retval = prepare_binprm(bprm);
+		if (retval < 0)
+			goto _error;
+		bprm->file = interp_file;
+		memset(bprm->buf, 0, BINPRM_BUF_SIZE);
+		retval = kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE);
+	} else {
+		bprm->file = interp_file;
+		retval = prepare_binprm (bprm);
+	}
+
+	if (retval < 0)
+		goto _error;
+
+	if (is_open_bin) {
+		/* if the binary is not readable than enforce mm->dumpable=0
+		   regardless of the interpreter's permissions */
+		if (permission (binary_file->f_dentry->d_inode, MAY_READ, NULL)) {
+			bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
+		}
+		/* install the binary's fd. it is done at the latest possible point
+	 	 * because once it is installed it will need to be sys_close()ed
+	 	 * in case of error.
+	 	 */
+ 		fd_install (fd_binary, binary_file);
+	}
+
+	retval = search_binary_handler (bprm, regs);
+
+	if (retval < 0)
+		goto _error_close_file;
 
-	retval = prepare_binprm(bprm);
-	if (retval >= 0)
-		retval = search_binary_handler(bprm, regs);
 _ret:
 	return retval;
+
+_error_close_file:
+	if (fd_binary > 0) {
+		sys_close (fd_binary);
+		fd_binary = -1;
+		bprm->file = NULL;
+	}
+_error:
+	if (fd_binary > 0)
+		put_unused_fd (fd_binary);
+	bprm->interp_flags = 0;
+	goto _ret;
+
 }
 
 /* Command parsers */
@@ -191,6 +270,36 @@ static int unquote(char *from)
 	return p - from;
 }
 
+static inline char * check_special_flags (char * sfs, Node * e)
+{
+	char * p = sfs;
+	int cont = 1;
+
+	/* special flags */
+	while (cont) {
+		switch (*p) {
+			case 'P':
+				p++;
+				e->flags |= MISC_FMT_PRESERVE_ARGV0;
+				break;
+			case 'O':
+				p++;
+				e->flags |= MISC_FMT_OPEN_BINARY;
+				break;
+			case 'C':
+				p++;
+				/* this flags also implies the
+				   open-binary flag */
+				e->flags |= (MISC_FMT_CREDENTIALS |
+						MISC_FMT_OPEN_BINARY);
+				break;
+			default:
+				cont = 0;
+		}
+	}
+
+	return p;
+}
 /*
  * This registers a new binary format, it recognises the syntax
  * ':name:type:offset:magic:mask:interpreter:'
@@ -293,10 +402,8 @@ static Node *create_entry(const char *bu
 	if (!e->interpreter[0])
 		goto Einval;
 
-	if (*p == 'P') {
-		p++;
-		e->flags |= MISC_FMT_PRESERVE_ARGV0;
-	}
+
+	p = check_special_flags (p, e);
 
 	if (*p == '\n')
 		p++;
@@ -346,6 +453,7 @@ static void entry_status(Node *e, char *
 {
 	char *dp;
 	char *status = "disabled";
+	const char * flags = "flags: ";
 
 	if (test_bit(Enabled, &e->flags))
 		status = "enabled";
@@ -357,6 +465,22 @@ static void entry_status(Node *e, char *
 
 	sprintf(page, "%s\ninterpreter %s\n", status, e->interpreter);
 	dp = page + strlen(page);
+
+	/* print the special flags */
+	sprintf (dp, "%s", flags);
+	dp += strlen (flags);
+	if (e->flags & MISC_FMT_PRESERVE_ARGV0) {
+		*dp ++ = 'P';
+	}
+	if (e->flags & MISC_FMT_OPEN_BINARY) {
+		*dp ++ = 'O';
+	}
+	if (e->flags & MISC_FMT_CREDENTIALS) {
+		*dp ++ = 'C';
+	}
+	*dp ++ = '\n';
+
+
 	if (!test_bit(Magic, &e->flags)) {
 		sprintf(dp, "extension .%s\n", e->magic);
 	} else {
--- diff/fs/binfmt_som.c	2004-01-19 10:22:59.000000000 +0000
+++ source/fs/binfmt_som.c	2004-03-09 11:51:51.000000000 +0000
@@ -259,7 +259,7 @@ load_som_binary(struct linux_binprm * bp
 	create_som_tables(bprm);
 
 	current->mm->start_stack = bprm->p;
-	current->mm->rss = 0;
+	zero_rss(current->mm);
 
 #if 0
 	printk("(start_brk) %08lx\n" , (unsigned long) current->mm->start_brk);
--- diff/fs/block_dev.c	2004-03-04 11:41:48.000000000 +0000
+++ source/fs/block_dev.c	2004-03-09 11:51:51.000000000 +0000
@@ -146,8 +146,8 @@ blkdev_direct_IO(int rw, struct kiocb *i
 	struct file *file = iocb->ki_filp;
 	struct inode *inode = file->f_mapping->host;
 
-	return blockdev_direct_IO(rw, iocb, inode, I_BDEV(inode), iov, offset,
-				nr_segs, blkdev_get_blocks, NULL);
+	return blockdev_direct_IO_no_locking(rw, iocb, inode, I_BDEV(inode),
+				iov, offset, nr_segs, blkdev_get_blocks, NULL);
 }
 
 static int blkdev_writepage(struct page *page, struct writeback_control *wbc)
@@ -522,7 +522,7 @@ int check_disk_change(struct block_devic
 
 EXPORT_SYMBOL(check_disk_change);
 
-static void bd_set_size(struct block_device *bdev, loff_t size)
+void bd_set_size(struct block_device *bdev, loff_t size)
 {
 	unsigned bsize = bdev_hardsect_size(bdev);
 
@@ -535,6 +535,7 @@ static void bd_set_size(struct block_dev
 	bdev->bd_block_size = bsize;
 	bdev->bd_inode->i_blkbits = blksize_bits(bsize);
 }
+EXPORT_SYMBOL(bd_set_size);
 
 static int do_open(struct block_device *bdev, struct file *file)
 {
@@ -786,7 +787,7 @@ struct file_operations def_blk_fops = {
 	.fsync		= block_fsync,
 	.ioctl		= block_ioctl,
 	.readv		= generic_file_readv,
-	.writev		= generic_file_writev,
+	.writev		= generic_file_write_nolock,
 	.sendfile	= generic_file_sendfile,
 };
 
--- diff/fs/buffer.c	2004-03-04 11:41:48.000000000 +0000
+++ source/fs/buffer.c	2004-03-09 11:51:51.000000000 +0000
@@ -97,7 +97,7 @@ void wake_up_buffer(struct buffer_head *
 }
 EXPORT_SYMBOL(wake_up_buffer);
 
-void unlock_buffer(struct buffer_head *bh)
+void fastcall unlock_buffer(struct buffer_head *bh)
 {
 	/*
 	 * unlock_buffer against a zero-count bh is a bug, if the page
@@ -404,7 +404,7 @@ __find_get_block_slow(struct block_devic
 	struct inode *bd_inode = bdev->bd_inode;
 	struct address_space *bd_mapping = bd_inode->i_mapping;
 	struct buffer_head *ret = NULL;
-	unsigned long index;
+	pgoff_t index;
 	struct buffer_head *bh;
 	struct buffer_head *head;
 	struct page *page;
@@ -431,6 +431,7 @@ __find_get_block_slow(struct block_devic
 	printk("block=%llu, b_blocknr=%llu\n",
 		(unsigned long long)block, (unsigned long long)bh->b_blocknr);
 	printk("b_state=0x%08lx, b_size=%u\n", bh->b_state, bh->b_size);
+	printk("device blocksize: %d\n", 1 << bd_inode->i_blkbits);
 out_unlock:
 	spin_unlock(&bd_mapping->private_lock);
 	page_cache_release(page);
@@ -857,10 +858,13 @@ int __set_page_dirty_buffers(struct page
 		struct buffer_head *bh = head;
 
 		do {
-			if (buffer_uptodate(bh))
+			if (buffer_uptodate(bh)) {
 				set_buffer_dirty(bh);
-			else
+				if (unlikely(block_dump))
+					printk("%s(%d): dirtied buffer\n", current->comm, current->pid);
+			} else {
 				buffer_error();
+			}
 			bh = bh->b_this_page;
 		} while (bh != head);
 	}
@@ -1093,7 +1097,7 @@ link_dev_buffers(struct page *page, stru
  */ 
 static void
 init_page_buffers(struct page *page, struct block_device *bdev,
-			int block, int size)
+			sector_t block, int size)
 {
 	struct buffer_head *head = page_buffers(page);
 	struct buffer_head *bh = head;
@@ -1121,8 +1125,8 @@ init_page_buffers(struct page *page, str
  * This is user purely for blockdev mappings.
  */
 static struct page *
-grow_dev_page(struct block_device *bdev, unsigned long block,
-			unsigned long index, int size)
+grow_dev_page(struct block_device *bdev, sector_t block,
+		pgoff_t index, int size)
 {
 	struct inode *inode = bdev->bd_inode;
 	struct page *page;
@@ -1178,10 +1182,10 @@ failed:
  * grow_dev_page() will go BUG() if this happens.
  */
 static inline int
-grow_buffers(struct block_device *bdev, unsigned long block, int size)
+grow_buffers(struct block_device *bdev, sector_t block, int size)
 {
 	struct page *page;
-	unsigned long index;
+	pgoff_t index;
 	int sizebits;
 
 	/* Size must be multiple of hard sectorsize */
@@ -1256,7 +1260,7 @@ __getblk_slow(struct block_device *bdev,
  * mark_buffer_dirty() is atomic.  It takes bh->b_page->mapping->private_lock,
  * mapping->page_lock and the global inode_lock.
  */
-void mark_buffer_dirty(struct buffer_head *bh)
+void fastcall mark_buffer_dirty(struct buffer_head *bh)
 {
 	if (!buffer_uptodate(bh))
 		buffer_error();
@@ -1738,8 +1742,8 @@ static int __block_write_full_page(struc
 			get_block_t *get_block, struct writeback_control *wbc)
 {
 	int err;
-	unsigned long block;
-	unsigned long last_block;
+	sector_t block;
+	sector_t last_block;
 	struct buffer_head *bh, *head;
 	int nr_underway = 0;
 
@@ -1806,23 +1810,23 @@ static int __block_write_full_page(struc
 
 	do {
 		get_bh(bh);
-		if (buffer_mapped(bh) && buffer_dirty(bh)) {
-			if (wbc->sync_mode != WB_SYNC_NONE) {
-				lock_buffer(bh);
-			} else {
-				if (test_set_buffer_locked(bh)) {
-					__set_page_dirty_nobuffers(page);
-					continue;
-				}
-			}
-			if (test_clear_buffer_dirty(bh)) {
-				if (!buffer_uptodate(bh))
-					buffer_error();
-				mark_buffer_async_write(bh);
-			} else {
-				unlock_buffer(bh);
+		if (!buffer_mapped(bh))
+			continue;
+		if (wbc->sync_mode != WB_SYNC_NONE) {
+			lock_buffer(bh);
+		} else {
+			if (test_set_buffer_locked(bh)) {
+				__set_page_dirty_nobuffers(page);
+				continue;
 			}
 		}
+		if (test_clear_buffer_dirty(bh)) {
+			if (!buffer_uptodate(bh))
+				buffer_error();
+			mark_buffer_async_write(bh);
+		} else {
+			unlock_buffer(bh);
+		}
 	} while ((bh = bh->b_this_page) != head);
 
 	BUG_ON(PageWriteback(page));
@@ -2207,7 +2211,7 @@ int cont_prepare_write(struct page *page
 	struct address_space *mapping = page->mapping;
 	struct inode *inode = mapping->host;
 	struct page *new_page;
-	unsigned long pgpos;
+	pgoff_t pgpos;
 	long status;
 	unsigned zerofrom;
 	unsigned blocksize = 1 << inode->i_blkbits;
@@ -2317,6 +2321,28 @@ int generic_commit_write(struct file *fi
 	return 0;
 }
 
+
+/*
+ * nobh_prepare_write()'s prereads are special: the buffer_heads are freed
+ * immediately, while under the page lock.  So it needs a special end_io
+ * handler which does not touch the bh after unlocking it.
+ *
+ * Note: unlock_buffer() sort-of does touch the bh after unlocking it, but
+ * a race there is benign: unlock_buffer() only use the bh's address for
+ * hashing after unlocking the buffer, so it doesn't actually touch the bh
+ * itself.
+ */
+static void end_buffer_read_nobh(struct buffer_head *bh, int uptodate)
+{
+	if (uptodate) {
+		set_buffer_uptodate(bh);
+	} else {
+		/* This happens, due to failed READA attempts. */
+		clear_buffer_uptodate(bh);
+	}
+	unlock_buffer(bh);
+}
+
 /*
  * On entry, the page is fully not uptodate.
  * On exit the page is fully uptodate in the areas outside (from,to)
@@ -2408,12 +2434,25 @@ int nobh_prepare_write(struct page *page
 	}
 
 	if (nr_reads) {
-		ll_rw_block(READ, nr_reads, read_bh);
+		struct buffer_head *bh;
+
+		/*
+		 * The page is locked, so these buffers are protected from
+		 * any VM or truncate activity.  Hence we don't need to care
+		 * for the buffer_head refcounts.
+		 */
 		for (i = 0; i < nr_reads; i++) {
-			wait_on_buffer(read_bh[i]);
-			if (!buffer_uptodate(read_bh[i]))
+			bh = read_bh[i];
+			lock_buffer(bh);
+			bh->b_end_io = end_buffer_read_nobh;
+			submit_bh(READ, bh);
+		}
+		for (i = 0; i < nr_reads; i++) {
+			bh = read_bh[i];
+			wait_on_buffer(bh);
+			if (!buffer_uptodate(bh))
 				ret = -EIO;
-			free_buffer_head(read_bh[i]);
+			free_buffer_head(bh);
 			read_bh[i] = NULL;
 		}
 		if (ret)
@@ -2512,9 +2551,11 @@ EXPORT_SYMBOL(nobh_truncate_page);
 int block_truncate_page(struct address_space *mapping,
 			loff_t from, get_block_t *get_block)
 {
-	unsigned long index = from >> PAGE_CACHE_SHIFT;
+	pgoff_t index = from >> PAGE_CACHE_SHIFT;
 	unsigned offset = from & (PAGE_CACHE_SIZE-1);
-	unsigned blocksize, iblock, length, pos;
+	unsigned blocksize;
+	pgoff_t iblock;
+	unsigned length, pos;
 	struct inode *inode = mapping->host;
 	struct page *page;
 	struct buffer_head *bh;
@@ -2594,7 +2635,7 @@ int block_write_full_page(struct page *p
 {
 	struct inode * const inode = page->mapping->host;
 	loff_t i_size = i_size_read(inode);
-	const unsigned long end_index = i_size >> PAGE_CACHE_SHIFT;
+	const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
 	unsigned offset;
 	void *kaddr;
 
@@ -2987,6 +3028,26 @@ init_buffer_head(void *data, kmem_cache_
 	}
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static void buffer_exit_cpu(int cpu)
+{
+	int i;
+	struct bh_lru *b = &per_cpu(bh_lrus, cpu);
+
+	for (i = 0; i < BH_LRU_SIZE; i++) {
+		brelse(b->bhs[i]);
+		b->bhs[i] = NULL;
+	}
+}
+
+static int buffer_cpu_notify(struct notifier_block *self,
+			      unsigned long action, void *hcpu)
+{
+	if (action == CPU_DEAD)
+		buffer_exit_cpu((unsigned long)hcpu);
+	return NOTIFY_OK;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
 
 void __init buffer_init(void)
 {
@@ -3004,6 +3065,7 @@ void __init buffer_init(void)
 	 */
 	nrpages = (nr_free_buffer_pages() * 10) / 100;
 	max_buffer_heads = nrpages * (PAGE_SIZE / sizeof(struct buffer_head));
+	hotcpu_notifier(buffer_cpu_notify, 0);
 }
 
 EXPORT_SYMBOL(__bforget);
--- diff/fs/cifs/cifsfs.c	2003-10-27 09:20:44.000000000 +0000
+++ source/fs/cifs/cifsfs.c	2004-03-09 11:51:51.000000000 +0000
@@ -77,6 +77,7 @@ cifs_read_super(struct super_block *sb, 
 	struct cifs_sb_info *cifs_sb;
 	int rc = 0;
 
+	sb->s_flags |= MS_NODIRATIME; /* and probably even noatime */
 	sb->s_fs_info = kmalloc(sizeof(struct cifs_sb_info),GFP_KERNEL);
 	cifs_sb = CIFS_SB(sb);
 	if(cifs_sb == NULL)
--- diff/fs/coda/dir.c	2003-09-30 15:46:18.000000000 +0100
+++ source/fs/coda/dir.c	2004-03-09 11:51:51.000000000 +0000
@@ -510,8 +510,10 @@ int coda_readdir(struct file *coda_file,
 			goto out;
 
 		ret = -ENOENT;
-		if (!IS_DEADDIR(host_inode))
+		if (!IS_DEADDIR(host_inode)) {
 			ret = host_file->f_op->readdir(host_file, filldir, dirent);
+			update_atime(host_inode);
+		}
 	}
 out:
 	coda_file->f_pos = host_file->f_pos;
--- diff/fs/coda/inode.c	2003-09-30 15:46:18.000000000 +0100
+++ source/fs/coda/inode.c	2004-03-09 11:51:51.000000000 +0000
@@ -171,6 +171,7 @@ static int coda_fill_super(struct super_
 	sbi->sbi_vcomm = vc;
 
         sb->s_fs_info = sbi;
+	sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
         sb->s_blocksize = 1024;	/* XXXXX  what do we put here?? */
         sb->s_blocksize_bits = 10;
         sb->s_magic = CODA_SUPER_MAGIC;
@@ -195,6 +196,8 @@ static int coda_fill_super(struct super_
 	printk("coda_read_super: rootinode is %ld dev %s\n", 
 	       root->i_ino, root->i_sb->s_id);
 	sb->s_root = d_alloc_root(root);
+	if (!sb->s_root)
+		goto error;
         return 0;
 
  error:
@@ -306,5 +309,6 @@ struct file_system_type coda_fs_type = {
 	.name		= "coda",
 	.get_sb		= coda_get_sb,
 	.kill_sb	= kill_anon_super,
+	.fs_flags	= FS_BINARY_MOUNTDATA,
 };
 
--- diff/fs/cramfs/inode.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/cramfs/inode.c	2004-03-09 11:51:51.000000000 +0000
@@ -199,6 +199,9 @@ static int cramfs_fill_super(struct supe
 	struct cramfs_super super;
 	unsigned long root_offset;
 	struct cramfs_sb_info *sbi;
+	struct inode *root;
+
+	sb->s_flags |= MS_RDONLY;
 
 	sbi = kmalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL);
 	if (!sbi)
@@ -263,7 +266,14 @@ static int cramfs_fill_super(struct supe
 
 	/* Set it all up.. */
 	sb->s_op = &cramfs_ops;
-	sb->s_root = d_alloc_root(get_cramfs_inode(sb, &super.root));
+	root = get_cramfs_inode(sb, &super.root);
+	if (!root)
+		goto out;
+	sb->s_root = d_alloc_root(root);
+	if (!sb->s_root) {
+		iput(root);
+		goto out;
+	}
 	return 0;
 out:
 	kfree(sbi);
--- diff/fs/direct-io.c	2004-01-19 10:22:59.000000000 +0000
+++ source/fs/direct-io.c	2004-03-09 11:51:51.000000000 +0000
@@ -52,6 +52,10 @@
  *
  * If blkfactor is zero then the user's request was aligned to the filesystem's
  * blocksize.
+ *
+ * needs_locking is set for regular files on direct-IO-naive filesystems.  It
+ * determines whether we need to do the fancy locking which prevents direct-IO
+ * from being able to read uninitialised disk blocks.
  */
 
 struct dio {
@@ -59,6 +63,7 @@ struct dio {
 	struct bio *bio;		/* bio under assembly */
 	struct inode *inode;
 	int rw;
+	int needs_locking;		/* doesn't change */
 	unsigned blkbits;		/* doesn't change */
 	unsigned blkfactor;		/* When we're using an alignment which
 					   is finer than the filesystem's soft
@@ -69,6 +74,7 @@ struct dio {
 					   been performed at the start of a
 					   write */
 	int pages_in_io;		/* approximate total IO pages */
+	size_t	size;			/* total request size (doesn't change)*/
 	sector_t block_in_file;		/* Current offset into the underlying
 					   file in dio_block units. */
 	unsigned blocks_available;	/* At block_in_file.  changes */
@@ -110,9 +116,9 @@ struct dio {
 	int page_errors;		/* errno from get_user_pages() */
 
 	/* BIO completion state */
-	atomic_t bio_count;		/* nr bios to be completed */
-	atomic_t bios_in_flight;	/* nr bios in flight */
-	spinlock_t bio_list_lock;	/* protects bio_list */
+	spinlock_t bio_lock;		/* protects BIO fields below */
+	int bio_count;			/* nr bios to be completed */
+	int bios_in_flight;		/* nr bios in flight */
 	struct bio *bio_list;		/* singly linked via bi_private */
 	struct task_struct *waiter;	/* waiting task (NULL if none) */
 
@@ -204,8 +210,10 @@ static struct page *dio_get_page(struct 
  */
 static void dio_complete(struct dio *dio, loff_t offset, ssize_t bytes)
 {
-	if (dio->end_io)
+	if (dio->end_io && dio->result)
 		dio->end_io(dio->inode, offset, bytes, dio->map_bh.b_private);
+	if (dio->needs_locking)
+		up_read(&dio->inode->i_alloc_sem);
 }
 
 /*
@@ -214,14 +222,38 @@ static void dio_complete(struct dio *dio
  */
 static void finished_one_bio(struct dio *dio)
 {
-	if (atomic_dec_and_test(&dio->bio_count)) {
+	unsigned long flags;
+
+	spin_lock_irqsave(&dio->bio_lock, flags);
+	if (dio->bio_count == 1) {
 		if (dio->is_async) {
+			/*
+			 * Last reference to the dio is going away.
+			 * Drop spinlock and complete the DIO.
+			 */
+			spin_unlock_irqrestore(&dio->bio_lock, flags);
 			dio_complete(dio, dio->block_in_file << dio->blkbits,
 					dio->result);
-			aio_complete(dio->iocb, dio->result, 0);
-			kfree(dio);
+			/* Complete AIO later if falling back to buffered i/o */
+			if (dio->result == dio->size || dio->rw == READ) {
+				aio_complete(dio->iocb, dio->result, 0);
+				kfree(dio);
+				return;
+			} else {
+				/*
+				 * Falling back to buffered
+				 */
+				spin_lock_irqsave(&dio->bio_lock, flags);
+				dio->bio_count--;
+				if (dio->waiter)
+					wake_up_process(dio->waiter);
+				spin_unlock_irqrestore(&dio->bio_lock, flags);
+				return;
+			}
 		}
 	}
+	dio->bio_count--;
+	spin_unlock_irqrestore(&dio->bio_lock, flags);
 }
 
 static int dio_bio_complete(struct dio *dio, struct bio *bio);
@@ -255,13 +287,13 @@ static int dio_bio_end_io(struct bio *bi
 	if (bio->bi_size)
 		return 1;
 
-	spin_lock_irqsave(&dio->bio_list_lock, flags);
+	spin_lock_irqsave(&dio->bio_lock, flags);
 	bio->bi_private = dio->bio_list;
 	dio->bio_list = bio;
-	atomic_dec(&dio->bios_in_flight);
-	if (dio->waiter && atomic_read(&dio->bios_in_flight) == 0)
+	dio->bios_in_flight--;
+	if (dio->waiter && dio->bios_in_flight == 0)
 		wake_up_process(dio->waiter);
-	spin_unlock_irqrestore(&dio->bio_list_lock, flags);
+	spin_unlock_irqrestore(&dio->bio_lock, flags);
 	return 0;
 }
 
@@ -294,10 +326,13 @@ dio_bio_alloc(struct dio *dio, struct bl
 static void dio_bio_submit(struct dio *dio)
 {
 	struct bio *bio = dio->bio;
+	unsigned long flags;
 
 	bio->bi_private = dio;
-	atomic_inc(&dio->bio_count);
-	atomic_inc(&dio->bios_in_flight);
+	spin_lock_irqsave(&dio->bio_lock, flags);
+	dio->bio_count++;
+	dio->bios_in_flight++;
+	spin_unlock_irqrestore(&dio->bio_lock, flags);
 	if (dio->is_async && dio->rw == READ)
 		bio_set_pages_dirty(bio);
 	submit_bio(dio->rw, bio);
@@ -323,22 +358,22 @@ static struct bio *dio_await_one(struct 
 	unsigned long flags;
 	struct bio *bio;
 
-	spin_lock_irqsave(&dio->bio_list_lock, flags);
+	spin_lock_irqsave(&dio->bio_lock, flags);
 	while (dio->bio_list == NULL) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		if (dio->bio_list == NULL) {
 			dio->waiter = current;
-			spin_unlock_irqrestore(&dio->bio_list_lock, flags);
+			spin_unlock_irqrestore(&dio->bio_lock, flags);
 			blk_run_queues();
 			io_schedule();
-			spin_lock_irqsave(&dio->bio_list_lock, flags);
+			spin_lock_irqsave(&dio->bio_lock, flags);
 			dio->waiter = NULL;
 		}
 		set_current_state(TASK_RUNNING);
 	}
 	bio = dio->bio_list;
 	dio->bio_list = bio->bi_private;
-	spin_unlock_irqrestore(&dio->bio_list_lock, flags);
+	spin_unlock_irqrestore(&dio->bio_lock, flags);
 	return bio;
 }
 
@@ -380,7 +415,12 @@ static int dio_await_completion(struct d
 	if (dio->bio)
 		dio_bio_submit(dio);
 
-	while (atomic_read(&dio->bio_count)) {
+	/*
+	 * The bio_lock is not held for the read of bio_count.
+	 * This is ok since it is the dio_bio_complete() that changes
+	 * bio_count.
+	 */
+	while (dio->bio_count) {
 		struct bio *bio = dio_await_one(dio);
 		int ret2;
 
@@ -407,10 +447,10 @@ static int dio_bio_reap(struct dio *dio)
 			unsigned long flags;
 			struct bio *bio;
 
-			spin_lock_irqsave(&dio->bio_list_lock, flags);
+			spin_lock_irqsave(&dio->bio_lock, flags);
 			bio = dio->bio_list;
 			dio->bio_list = bio->bi_private;
-			spin_unlock_irqrestore(&dio->bio_list_lock, flags);
+			spin_unlock_irqrestore(&dio->bio_lock, flags);
 			ret = dio_bio_complete(dio, bio);
 		}
 		dio->reap_counter = 0;
@@ -449,6 +489,7 @@ static int get_more_blocks(struct dio *d
 	unsigned long fs_count;	/* Number of filesystem-sized blocks */
 	unsigned long dio_count;/* Number of dio_block-sized blocks */
 	unsigned long blkmask;
+	int beyond_eof = 0;
 
 	/*
 	 * If there was a memory error and we've overwritten all the
@@ -466,8 +507,19 @@ static int get_more_blocks(struct dio *d
 		if (dio_count & blkmask)	
 			fs_count++;
 
+		if (dio->needs_locking) {
+			if (dio->block_in_file >= (i_size_read(dio->inode) >>
+							dio->blkbits))
+				beyond_eof = 1;
+		}
+		/*
+		 * For writes inside i_size we forbid block creations: only
+		 * overwrites are permitted.  We fall back to buffered writes
+		 * at a higher level for inside-i_size block-instantiating
+		 * writes.
+		 */
 		ret = (*dio->get_blocks)(dio->inode, fs_startblk, fs_count,
-				map_bh, dio->rw == WRITE);
+				map_bh, (dio->rw == WRITE) && beyond_eof);
 	}
 	return ret;
 }
@@ -774,6 +826,10 @@ do_holes:
 			if (!buffer_mapped(map_bh)) {
 				char *kaddr;
 
+				/* AKPM: eargh, -ENOTBLK is a hack */
+				if (dio->rw == WRITE)
+					return -ENOTBLK;
+
 				if (dio->block_in_file >=
 					i_size_read(dio->inode)>>blkbits) {
 					/* We hit eof */
@@ -839,32 +895,30 @@ out:
 	return ret;
 }
 
+/*
+ * Releases both i_sem and i_alloc_sem
+ */
 static int
 direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, 
 	const struct iovec *iov, loff_t offset, unsigned long nr_segs, 
-	unsigned blkbits, get_blocks_t get_blocks, dio_iodone_t end_io)
+	unsigned blkbits, get_blocks_t get_blocks, dio_iodone_t end_io,
+	struct dio *dio)
 {
 	unsigned long user_addr; 
 	int seg;
 	int ret = 0;
 	int ret2;
-	struct dio *dio;
 	size_t bytes;
 
-	dio = kmalloc(sizeof(*dio), GFP_KERNEL);
-	if (!dio)
-		return -ENOMEM;
-	dio->is_async = !is_sync_kiocb(iocb);
-
 	dio->bio = NULL;
 	dio->inode = inode;
 	dio->rw = rw;
 	dio->blkbits = blkbits;
 	dio->blkfactor = inode->i_blkbits - blkbits;
 	dio->start_zero_done = 0;
+	dio->size = 0;
 	dio->block_in_file = offset >> blkbits;
 	dio->blocks_available = 0;
-
 	dio->cur_page = NULL;
 
 	dio->boundary = 0;
@@ -887,9 +941,9 @@ direct_io_worker(int rw, struct kiocb *i
 	 * (or synchronous) device could take the count to zero while we're
 	 * still submitting BIOs.
 	 */
-	atomic_set(&dio->bio_count, 1);
-	atomic_set(&dio->bios_in_flight, 0);
-	spin_lock_init(&dio->bio_list_lock);
+	dio->bio_count = 1;
+	dio->bios_in_flight = 0;
+	spin_lock_init(&dio->bio_lock);
 	dio->bio_list = NULL;
 	dio->waiter = NULL;
 
@@ -899,7 +953,7 @@ direct_io_worker(int rw, struct kiocb *i
 
 	for (seg = 0; seg < nr_segs; seg++) {
 		user_addr = (unsigned long)iov[seg].iov_base;
-		bytes = iov[seg].iov_len;
+		dio->size += bytes = iov[seg].iov_len;
 
 		/* Index into the first page of the first block */
 		dio->first_block_in_page = (user_addr & ~PAGE_MASK) >> blkbits;
@@ -930,6 +984,13 @@ direct_io_worker(int rw, struct kiocb *i
 		}
 	} /* end iovec loop */
 
+	if (ret == -ENOTBLK && rw == WRITE) {
+		/*
+		 * The remaining part of the request will be
+		 * be handled by buffered I/O when we return
+		 */
+		ret = 0;
+	}
 	/*
 	 * There may be some unwritten disk at the end of a part-written
 	 * fs-block-sized block.  Go zero that now.
@@ -953,14 +1014,48 @@ direct_io_worker(int rw, struct kiocb *i
 	dio_cleanup(dio);
 
 	/*
+	 * All block lookups have been performed. For READ requests
+	 * we can let i_sem go now that its achieved its purpose
+	 * of protecting us from looking up uninitialized blocks.
+	 */
+	if ((rw == READ) && dio->needs_locking)
+		up(&dio->inode->i_sem);
+
+	/*
 	 * OK, all BIOs are submitted, so we can decrement bio_count to truly
 	 * reflect the number of to-be-processed BIOs.
 	 */
 	if (dio->is_async) {
+		int should_wait = 0;
+
+		if (dio->result < dio->size && rw == WRITE) {
+			dio->waiter = current;
+			should_wait = 1;
+		}
 		if (ret == 0)
-			ret = dio->result;	/* Bytes written */
+			ret = dio->result;
 		finished_one_bio(dio);		/* This can free the dio */
 		blk_run_queues();
+		if (should_wait) {
+			unsigned long flags;
+			/*
+			 * Wait for already issued I/O to drain out and
+			 * release its references to user-space pages
+			 * before returning to fallback on buffered I/O
+			 */
+
+			spin_lock_irqsave(&dio->bio_lock, flags);
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			while (dio->bio_count) {
+				spin_unlock_irqrestore(&dio->bio_lock, flags);
+				io_schedule();
+				spin_lock_irqsave(&dio->bio_lock, flags);
+				set_current_state(TASK_UNINTERRUPTIBLE);
+			}
+			spin_unlock_irqrestore(&dio->bio_lock, flags);
+			set_current_state(TASK_RUNNING);
+			kfree(dio);
+		}
 	} else {
 		finished_one_bio(dio);
 		ret2 = dio_await_completion(dio);
@@ -980,6 +1075,14 @@ direct_io_worker(int rw, struct kiocb *i
 				ret = i_size - offset;
 		}
 		dio_complete(dio, offset, ret);
+		/* We could have also come here on an AIO file extend */
+		if (!is_sync_kiocb(iocb) && rw == WRITE &&
+		    ret >= 0 && dio->result == dio->size)
+			/*
+			 * For AIO writes where we have completed the
+			 * i/o, we have to mark the the aio complete.
+			 */
+			aio_complete(iocb, ret, 0);
 		kfree(dio);
 	}
 	return ret;
@@ -987,11 +1090,17 @@ direct_io_worker(int rw, struct kiocb *i
 
 /*
  * This is a library function for use by filesystem drivers.
+ *
+ * For writes to S_ISREG files, we are called under i_sem and return with i_sem
+ * held, even though it is internally dropped.
+ *
+ * For writes to S_ISBLK files, i_sem is not held on entry; it is never taken.
  */
 int
-blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, 
+__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
 	struct block_device *bdev, const struct iovec *iov, loff_t offset, 
-	unsigned long nr_segs, get_blocks_t get_blocks, dio_iodone_t end_io)
+	unsigned long nr_segs, get_blocks_t get_blocks, dio_iodone_t end_io,
+	int needs_special_locking)
 {
 	int seg;
 	size_t size;
@@ -1000,6 +1109,9 @@ blockdev_direct_IO(int rw, struct kiocb 
 	unsigned bdev_blkbits = 0;
 	unsigned blocksize_mask = (1 << blkbits) - 1;
 	ssize_t retval = -EINVAL;
+	loff_t end = offset;
+	struct dio *dio;
+	int needs_locking;
 
 	if (bdev)
 		bdev_blkbits = blksize_bits(bdev_hardsect_size(bdev));
@@ -1016,6 +1128,7 @@ blockdev_direct_IO(int rw, struct kiocb 
 	for (seg = 0; seg < nr_segs; seg++) {
 		addr = (unsigned long)iov[seg].iov_base;
 		size = iov[seg].iov_len;
+		end += size;
 		if ((addr & blocksize_mask) || (size & blocksize_mask))  {
 			if (bdev)
 				 blkbits = bdev_blkbits;
@@ -1025,10 +1138,46 @@ blockdev_direct_IO(int rw, struct kiocb 
 		}
 	}
 
-	retval = direct_io_worker(rw, iocb, inode, iov, offset, 
-				nr_segs, blkbits, get_blocks, end_io);
+	dio = kmalloc(sizeof(*dio), GFP_KERNEL);
+	retval = -ENOMEM;
+	if (!dio)
+		goto out;
+
+	/*
+	 * For regular files,
+	 *	readers need to grab i_sem and i_alloc_sem
+	 *	writers need to grab i_alloc_sem only (i_sem is already held)
+	 */
+	needs_locking = 0;
+	if (S_ISREG(inode->i_mode) && needs_special_locking) {
+		needs_locking = 1;
+		if (rw == READ) {
+			struct address_space *mapping;
+
+			mapping = iocb->ki_filp->f_mapping;
+			down(&inode->i_sem);
+			retval = filemap_write_and_wait(mapping);
+			if (retval) {
+				up(&inode->i_sem);
+				kfree(dio);
+				goto out;
+			}
+		}
+		down_read(&inode->i_alloc_sem);
+	}
+	dio->needs_locking = needs_locking;
+	/*
+	 * For file extending writes updating i_size before data
+	 * writeouts complete can expose uninitialized blocks. So
+	 * even for AIO, we need to wait for i/o to complete before
+	 * returning in this case.
+	 */
+	dio->is_async = !is_sync_kiocb(iocb) && !((rw == WRITE) &&
+		(end > i_size_read(inode)));
+
+	retval = direct_io_worker(rw, iocb, inode, iov, offset,
+				nr_segs, blkbits, get_blocks, end_io, dio);
 out:
 	return retval;
 }
-
-EXPORT_SYMBOL(blockdev_direct_IO);
+EXPORT_SYMBOL(__blockdev_direct_IO);
--- diff/fs/dquot.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/dquot.c	2004-03-09 11:51:51.000000000 +0000
@@ -1,16 +1,13 @@
 /*
- * Implementation of the diskquota system for the LINUX operating
- * system. QUOTA is implemented using the BSD system call interface as
- * the means of communication with the user level. Currently only the
- * ext2 filesystem has support for disk quotas. Other filesystems may
- * be added in the future. This file contains the generic routines
- * called by the different filesystems on allocation of an inode or
- * block. These routines take care of the administration needed to
- * have a consistent diskquota tracking system. The ideas of both
- * user and group quotas are based on the Melbourne quota system as
- * used on BSD derived systems. The internal implementation is 
- * based on one of the several variants of the LINUX inode-subsystem
- * with added complexity of the diskquota system.
+ * Implementation of the diskquota system for the LINUX operating system. QUOTA
+ * is implemented using the BSD system call interface as the means of
+ * communication with the user level. This file contains the generic routines
+ * called by the different filesystems on allocation of an inode or block.
+ * These routines take care of the administration needed to have a consistent
+ * diskquota tracking system. The ideas of both user and group quotas are based
+ * on the Melbourne quota system as used on BSD derived systems. The internal
+ * implementation is based on one of the several variants of the LINUX
+ * inode-subsystem with added complexity of the diskquota system.
  * 
  * Version: $Id: dquot.c,v 6.3 1996/11/17 18:35:34 mvw Exp mvw $
  * 
@@ -52,6 +49,9 @@
  *		New SMP locking.
  *		Jan Kara, <jack@suse.cz>, 10/2002
  *
+ *		Added journalled quota support
+ *		Jan Kara, <jack@suse.cz>, 2003,2004
+ *
  * (C) Copyright 1994 - 1997 Marco van Wieringen 
  */
 
@@ -85,13 +85,36 @@
  * and quota formats and also dqstats structure containing statistics about the
  * lists. dq_data_lock protects data from dq_dqb and also mem_dqinfo structures
  * and also guards consistency of dquot->dq_dqb with inode->i_blocks, i_bytes.
- * Note that we don't have to do the locking of i_blocks and i_bytes when the
- * quota is disabled - i_sem should serialize the access. dq_data_lock should
- * be always grabbed before dq_list_lock.
+ * i_blocks and i_bytes updates itself are guarded by i_lock acquired directly
+ * in inode_add_bytes() and inode_sub_bytes().
+ *
+ * The spinlock ordering is hence: dq_data_lock > dq_list_lock > i_lock
  *
  * Note that some things (eg. sb pointer, type, id) doesn't change during
  * the life of the dquot structure and so needn't to be protected by a lock
+ *
+ * Any operation working on dquots via inode pointers must hold dqptr_sem.  If
+ * operation is just reading pointers from inode (or not using them at all) the
+ * read lock is enough. If pointers are altered function must hold write lock.
+ * If operation is holding reference to dquot in other way (e.g. quotactl ops)
+ * it must be guarded by dqonoff_sem.
+ * This locking assures that:
+ *   a) update/access to dquot pointers in inode is serialized
+ *   b) everyone is guarded against invalidate_dquots()
+ *
+ * Each dquot has its dq_lock semaphore. Locked dquots might not be referenced
+ * from inodes (dquot_alloc_space() and such don't check the dq_lock).
+ * Currently dquot is locked only when it is being read to memory (or space for
+ * it is being allocated) on the first dqget() and when it is being released on
+ * the last dqput(). The allocation and release oparations are serialized by
+ * the dq_lock and by checking the use count in dquot_release().  Write
+ * operations on dquots don't hold dq_lock as they copy data under dq_data_lock
+ * spinlock to internal buffers before writing.
+ *
+ * Lock ordering (including journal_lock) is following:
+ *  dqonoff_sem > journal_lock > dqptr_sem > dquot->dq_lock > dqio_sem
  */
+
 spinlock_t dq_list_lock = SPIN_LOCK_UNLOCKED;
 spinlock_t dq_data_lock = SPIN_LOCK_UNLOCKED;
 
@@ -169,23 +192,6 @@ static void put_quota_format(struct quot
  * mechanism to locate a specific dquot.
  */
 
-/*
- * Note that any operation which operates on dquot data (ie. dq_dqb) must
- * hold dq_data_lock.
- *
- * Any operation working with dquots must hold dqptr_sem. If operation is
- * just reading pointers from inodes than read lock is enough. If pointers
- * are altered function must hold write lock.
- *
- * Locked dquots might not be referenced in inodes. Currently dquot it locked
- * only once in its existence - when it's being read to memory on first dqget()
- * and at that time it can't be referenced from inode. Write operations on
- * dquots don't hold dquot lock as they copy data to internal buffers before
- * writing anyway and copying as well as any data update should be atomic. Also
- * nobody can change used entries in dquot structure as this is done only when
- * quota is destroyed and invalidate_dquots() is called only when dq_count == 0.
- */
-
 static LIST_HEAD(inuse_list);
 static LIST_HEAD(free_dquots);
 static struct list_head dquot_hash[NR_DQHASH];
@@ -254,6 +260,9 @@ static inline void remove_inuse(struct d
 	dqstats.allocated_dquots--;
 	list_del(&dquot->dq_inuse);
 }
+/*
+ * End of list functions needing dq_list_lock
+ */
 
 static void wait_on_dquot(struct dquot *dquot)
 {
@@ -261,34 +270,98 @@ static void wait_on_dquot(struct dquot *
 	up(&dquot->dq_lock);
 }
 
-static int read_dqblk(struct dquot *dquot)
+#define mark_dquot_dirty(dquot) ((dquot)->dq_sb->dq_op->mark_dirty(dquot))
+
+/* No locks needed here as ANY_DQUOT_DIRTY is used just by sync and so the
+ * worst what can happen is that dquot is not written by concurrent sync... */
+int dquot_mark_dquot_dirty(struct dquot *dquot)
+{
+	set_bit(DQ_MOD_B, &(dquot)->dq_flags);
+	set_bit(DQF_ANY_DQUOT_DIRTY_B, &(sb_dqopt((dquot)->dq_sb)->
+		info[(dquot)->dq_type].dqi_flags));
+	return 0;
+}
+
+void mark_info_dirty(struct super_block *sb, int type)
 {
-	int ret;
+	set_bit(DQF_INFO_DIRTY_B, &sb_dqopt(sb)->info[type].dqi_flags);
+}
+
+
+/*
+ *	Read dquot from disk and alloc space for it
+ */
+
+int dquot_acquire(struct dquot *dquot)
+{
+	int ret = 0;
 	struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
 
 	down(&dquot->dq_lock);
 	down(&dqopt->dqio_sem);
-	ret = dqopt->ops[dquot->dq_type]->read_dqblk(dquot);
+	if (!test_bit(DQ_READ_B, &dquot->dq_flags))
+		ret = dqopt->ops[dquot->dq_type]->read_dqblk(dquot);
+	if (ret < 0)
+		goto out_iolock;
+	set_bit(DQ_READ_B, &dquot->dq_flags);
+	/* Instantiate dquot if needed */
+	if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && !dquot->dq_off) {
+		ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+		if (ret < 0)
+			goto out_iolock;
+	}
+	set_bit(DQ_ACTIVE_B, &dquot->dq_flags);
+out_iolock:
 	up(&dqopt->dqio_sem);
 	up(&dquot->dq_lock);
 	return ret;
 }
 
-static int commit_dqblk(struct dquot *dquot)
+/*
+ *	Write dquot to disk
+ */
+int dquot_commit(struct dquot *dquot)
 {
-	int ret;
+	int ret = 0;
 	struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
 
 	down(&dqopt->dqio_sem);
-	ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+	clear_bit(DQ_MOD_B, &dquot->dq_flags);
+	/* Inactive dquot can be only if there was error during read/init
+	 * => we have better not writing it */
+	if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags))
+		ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+	up(&dqopt->dqio_sem);
+	if (info_dirty(&dqopt->info[dquot->dq_type]))
+		dquot->dq_sb->dq_op->write_info(dquot->dq_sb, dquot->dq_type);
+	return ret;
+}
+
+/*
+ *	Release dquot
+ */
+int dquot_release(struct dquot *dquot)
+{
+	int ret = 0;
+	struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
+
+	down(&dquot->dq_lock);
+	/* Check whether we are not racing with some other dqget() */
+	if (atomic_read(&dquot->dq_count) > 1)
+		goto out_dqlock;
+	down(&dqopt->dqio_sem);
+	ret = dqopt->ops[dquot->dq_type]->release_dqblk(dquot);
+	clear_bit(DQ_ACTIVE_B, &dquot->dq_flags);
 	up(&dqopt->dqio_sem);
+out_dqlock:
+	up(&dquot->dq_lock);
 	return ret;
 }
 
 /* Invalidate all dquots on the list. Note that this function is called after
- * quota is disabled so no new quota might be created. Because we hold dqptr_sem
- * for writing and pointers were already removed from inodes we actually know that
- * no quota for this sb+type should be held. */
+ * quota is disabled and pointers from inodes removed so there cannot be new
+ * quota users. Also because we hold dqonoff_sem there can be no quota users
+ * for this sb+type at all. */
 static void invalidate_dquots(struct super_block *sb, int type)
 {
 	struct dquot *dquot;
@@ -302,12 +375,11 @@ static void invalidate_dquots(struct sup
 			continue;
 		if (dquot->dq_type != type)
 			continue;
-#ifdef __DQUOT_PARANOIA	
-		/* There should be no users of quota - we hold dqptr_sem for writing */
+#ifdef __DQUOT_PARANOIA
 		if (atomic_read(&dquot->dq_count))
 			BUG();
 #endif
-		/* Quota now have no users and it has been written on last dqput() */
+		/* Quota now has no users and it has been written on last dqput() */
 		remove_dquot_hash(dquot);
 		remove_free_dquot(dquot);
 		remove_inuse(dquot);
@@ -316,20 +388,22 @@ static void invalidate_dquots(struct sup
 	spin_unlock(&dq_list_lock);
 }
 
-static int vfs_quota_sync(struct super_block *sb, int type)
+int vfs_quota_sync(struct super_block *sb, int type)
 {
 	struct list_head *head;
 	struct dquot *dquot;
 	struct quota_info *dqopt = sb_dqopt(sb);
 	int cnt;
 
-	down_read(&dqopt->dqptr_sem);
+	down(&dqopt->dqonoff_sem);
 restart:
 	/* At this point any dirty dquot will definitely be written so we can clear
 	   dirty flag from info */
+	spin_lock(&dq_data_lock);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
 		if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt))
 			clear_bit(DQF_ANY_DQUOT_DIRTY_B, &dqopt->info[cnt].dqi_flags);
+	spin_unlock(&dq_data_lock);
 	spin_lock(&dq_list_lock);
 	list_for_each(head, &inuse_list) {
 		dquot = list_entry(head, struct dquot, dq_inuse);
@@ -337,10 +411,13 @@ restart:
 			continue;
                 if (type != -1 && dquot->dq_type != type)
 			continue;
-		if (!dquot->dq_sb)	/* Invalidated? */
-			continue;
 		if (!dquot_dirty(dquot))
 			continue;
+		/* Dirty and inactive can be only bad dquot... */
+		if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags))
+			continue;
+		/* Now we have active dquot from which someone is holding reference so we
+		 * can safely just increase use count */
 		atomic_inc(&dquot->dq_count);
 		dqstats.lookups++;
 		spin_unlock(&dq_list_lock);
@@ -351,15 +428,13 @@ restart:
 	spin_unlock(&dq_list_lock);
 
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-		if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt) && info_dirty(&dqopt->info[cnt])) {
-			down(&dqopt->dqio_sem);
-			dqopt->ops[cnt]->write_file_info(sb, cnt);
-			up(&dqopt->dqio_sem);
-		}
+		if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt)
+			&& info_dirty(&dqopt->info[cnt]))
+			sb->dq_op->write_info(sb, cnt);
 	spin_lock(&dq_list_lock);
 	dqstats.syncs++;
 	spin_unlock(&dq_list_lock);
-	up_read(&dqopt->dqptr_sem);
+	up(&dqopt->dqonoff_sem);
 
 	return 0;
 }
@@ -402,7 +477,7 @@ static int shrink_dqcache_memory(int nr,
 /*
  * Put reference to dquot
  * NOTE: If you change this function please check whether dqput_blocks() works right...
- * MUST be called with dqptr_sem held
+ * MUST be called with either dqptr_sem or dqonoff_sem
  */
 static void dqput(struct dquot *dquot)
 {
@@ -430,11 +505,20 @@ we_slept:
 		spin_unlock(&dq_list_lock);
 		return;
 	}
-	if (dquot_dirty(dquot)) {
+	/* Need to release dquot? */
+	if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && dquot_dirty(dquot)) {
 		spin_unlock(&dq_list_lock);
+		/* Commit dquot before releasing */
 		dquot->dq_sb->dq_op->write_dquot(dquot);
 		goto we_slept;
 	}
+	/* Clear flag in case dquot was inactive (something bad happened) */
+	clear_bit(DQ_MOD_B, &dquot->dq_flags);
+	if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {
+		spin_unlock(&dq_list_lock);
+		dquot_release(dquot);
+		goto we_slept;
+	}
 	atomic_dec(&dquot->dq_count);
 #ifdef __DQUOT_PARANOIA
 	/* sanity check */
@@ -467,7 +551,7 @@ static struct dquot *get_empty_dquot(str
 
 /*
  * Get reference to dquot
- * MUST be called with dqptr_sem held
+ * MUST be called with dqptr_sem or dqonoff_sem held
  */
 static struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
 {
@@ -493,7 +577,6 @@ we_slept:
 		insert_dquot_hash(dquot);
 		dqstats.lookups++;
 		spin_unlock(&dq_list_lock);
-		read_dqblk(dquot);
 	} else {
 		if (!atomic_read(&dquot->dq_count))
 			remove_free_dquot(dquot);
@@ -501,11 +584,17 @@ we_slept:
 		dqstats.cache_hits++;
 		dqstats.lookups++;
 		spin_unlock(&dq_list_lock);
-		wait_on_dquot(dquot);
 		if (empty)
 			kmem_cache_free(dquot_cachep, empty);
 	}
-
+	/* Wait for dq_lock - after this we know that either dquot_release() is already
+	 * finished or it will be canceled due to dq_count > 1 test */
+	wait_on_dquot(dquot);
+	/* Read the dquot and instantiate it (everything done only if needed) */
+	if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && dquot_acquire(dquot) < 0) {
+		dqput(dquot);
+		return NODQUOT;
+	}
 #ifdef __DQUOT_PARANOIA
 	if (!dquot->dq_sb)	/* Has somebody invalidated entry under us? */
 		BUG();
@@ -528,7 +617,7 @@ static int dqinit_needed(struct inode *i
 	return 0;
 }
 
-/* This routine is guarded by dqptr_sem semaphore */
+/* This routine is guarded by dqonoff_sem semaphore */
 static void add_dquot_ref(struct super_block *sb, int type)
 {
 	struct list_head *p;
@@ -539,12 +628,10 @@ restart:
 		struct file *filp = list_entry(p, struct file, f_list);
 		struct inode *inode = filp->f_dentry->d_inode;
 		if (filp->f_mode & FMODE_WRITE && dqinit_needed(inode, type)) {
-			struct vfsmount *mnt = mntget(filp->f_vfsmnt);
 			struct dentry *dentry = dget(filp->f_dentry);
 			file_list_unlock();
 			sb->dq_op->initialize(inode, type);
 			dput(dentry);
-			mntput(mnt);
 			/* As we may have blocked we had better restart... */
 			goto restart;
 		}
@@ -594,7 +681,7 @@ put_it:
 
 /* Free list of dquots - called from inode.c */
 /* dquots are removed from inodes, no new references can be got so we are the only ones holding reference */
-void put_dquot_list(struct list_head *tofree_head)
+static void put_dquot_list(struct list_head *tofree_head)
 {
 	struct list_head *act_head;
 	struct dquot *dquot;
@@ -609,16 +696,28 @@ void put_dquot_list(struct list_head *to
 	}
 }
 
+/* Function in inode.c - remove pointers to dquots in icache */
+extern void remove_dquot_ref(struct super_block *, int, struct list_head *);
+
+/* Gather all references from inodes and drop them */
+static void drop_dquot_ref(struct super_block *sb, int type)
+{
+	LIST_HEAD(tofree_head);
+
+	down_write(&sb_dqopt(sb)->dqptr_sem);
+	remove_dquot_ref(sb, type, &tofree_head);
+	up_write(&sb_dqopt(sb)->dqptr_sem);
+	put_dquot_list(&tofree_head);
+}
+
 static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number)
 {
 	dquot->dq_dqb.dqb_curinodes += number;
-	mark_dquot_dirty(dquot);
 }
 
 static inline void dquot_incr_space(struct dquot *dquot, qsize_t number)
 {
 	dquot->dq_dqb.dqb_curspace += number;
-	mark_dquot_dirty(dquot);
 }
 
 static inline void dquot_decr_inodes(struct dquot *dquot, unsigned long number)
@@ -630,7 +729,6 @@ static inline void dquot_decr_inodes(str
 	if (dquot->dq_dqb.dqb_curinodes < dquot->dq_dqb.dqb_isoftlimit)
 		dquot->dq_dqb.dqb_itime = (time_t) 0;
 	clear_bit(DQ_INODES_B, &dquot->dq_flags);
-	mark_dquot_dirty(dquot);
 }
 
 static inline void dquot_decr_space(struct dquot *dquot, qsize_t number)
@@ -642,7 +740,6 @@ static inline void dquot_decr_space(stru
 	if (toqb(dquot->dq_dqb.dqb_curspace) < dquot->dq_dqb.dqb_bsoftlimit)
 		dquot->dq_dqb.dqb_btime = (time_t) 0;
 	clear_bit(DQ_BLKS_B, &dquot->dq_flags);
-	mark_dquot_dirty(dquot);
 }
 
 static inline int need_print_warning(struct dquot *dquot)
@@ -795,22 +892,22 @@ static int check_bdq(struct dquot *dquot
 }
 
 /*
- * Externally referenced functions through dquot_operations in inode.
- *
- * Note: this is a blocking operation.
+ *	Initialize quota pointers in inode
+ *	Transaction must be started at entry
  */
-void dquot_initialize(struct inode *inode, int type)
+int dquot_initialize(struct inode *inode, int type)
 {
 	unsigned int id = 0;
-	int cnt;
+	int cnt, ret = 0;
 
+	/* First test before acquiring semaphore - solves deadlocks when we
+         * re-enter the quota code and are already holding the semaphore */
+	if (IS_NOQUOTA(inode))
+		return 0;
 	down_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
 	/* Having dqptr_sem we know NOQUOTA flags can't be altered... */
-	if (IS_NOQUOTA(inode)) {
-		up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
-		return;
-	}
-	/* Build list of quotas to initialize... */
+	if (IS_NOQUOTA(inode))
+		goto out_err;
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		if (type != -1 && cnt != type)
 			continue;
@@ -828,54 +925,39 @@ void dquot_initialize(struct inode *inod
 				inode->i_flags |= S_QUOTA;
 		}
 	}
+out_err:
 	up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
+	return ret;
 }
 
 /*
- *	Remove references to quota from inode
- *	This function needs dqptr_sem for writing
+ * 	Release all quotas referenced by inode
+ *	Transaction must be started at entry
  */
-static void dquot_drop_iupdate(struct inode *inode, struct dquot **to_drop)
+int dquot_drop(struct inode *inode)
 {
 	int cnt;
 
+	down_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
 	inode->i_flags &= ~S_QUOTA;
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-		to_drop[cnt] = inode->i_dquot[cnt];
-		inode->i_dquot[cnt] = NODQUOT;
+		if (inode->i_dquot[cnt]) {
+			dqput(inode->i_dquot[cnt]);
+			inode->i_dquot[cnt] = NODQUOT;
+		}
 	}
-}
-
-/*
- * 	Release all quotas referenced by inode
- */
-void dquot_drop(struct inode *inode)
-{
-	struct dquot *to_drop[MAXQUOTAS];
-	int cnt;
-
-	down_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
-	dquot_drop_iupdate(inode, to_drop);
 	up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
-	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-		if (to_drop[cnt] != NODQUOT)
-			dqput(to_drop[cnt]);
+	return 0;
 }
 
 /*
- *	Release all quotas referenced by inode.
- *	This function assumes dqptr_sem for writing
+ * Following four functions update i_blocks+i_bytes fields and
+ * quota information (together with appropriate checks)
+ * NOTE: We absolutely rely on the fact that caller dirties
+ * the inode (usually macros in quotaops.h care about this) and
+ * holds a handle for the current transaction so that dquot write and
+ * inode write go into the same transaction.
  */
-void dquot_drop_nolock(struct inode *inode)
-{
-	struct dquot *to_drop[MAXQUOTAS];
-	int cnt;
-
-	dquot_drop_iupdate(inode, to_drop);
-	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-		if (to_drop[cnt] != NODQUOT)
-			dqput(to_drop[cnt]);
-}
 
 /*
  * This operation can block, but only after everything is updated
@@ -885,13 +967,22 @@ int dquot_alloc_space(struct inode *inod
 	int cnt, ret = NO_QUOTA;
 	char warntype[MAXQUOTAS];
 
+	/* First test before acquiring semaphore - solves deadlocks when we
+         * re-enter the quota code and are already holding the semaphore */
+	if (IS_NOQUOTA(inode)) {
+out_add:
+		inode_add_bytes(inode, number);
+		return QUOTA_OK;
+	}
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
 		warntype[cnt] = NOWARN;
 
 	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+	if (IS_NOQUOTA(inode)) {	/* Now we can do reliable test... */
+		up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+		goto out_add;
+	}
 	spin_lock(&dq_data_lock);
-	if (IS_NOQUOTA(inode))
-		goto add_bytes;
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		if (inode->i_dquot[cnt] == NODQUOT)
 			continue;
@@ -903,11 +994,15 @@ int dquot_alloc_space(struct inode *inod
 			continue;
 		dquot_incr_space(inode->i_dquot[cnt], number);
 	}
-add_bytes:
 	inode_add_bytes(inode, number);
 	ret = QUOTA_OK;
 warn_put_all:
 	spin_unlock(&dq_data_lock);
+	if (ret == QUOTA_OK)
+		/* Dirtify all the dquots - this can block when journalling */
+		for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+			if (inode->i_dquot[cnt])
+				mark_dquot_dirty(inode->i_dquot[cnt]);
 	flush_warnings(inode->i_dquot, warntype);
 	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
 	return ret;
@@ -921,6 +1016,10 @@ int dquot_alloc_inode(const struct inode
 	int cnt, ret = NO_QUOTA;
 	char warntype[MAXQUOTAS];
 
+	/* First test before acquiring semaphore - solves deadlocks when we
+         * re-enter the quota code and are already holding the semaphore */
+	if (IS_NOQUOTA(inode))
+		return QUOTA_OK;
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
 		warntype[cnt] = NOWARN;
 	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
@@ -944,6 +1043,11 @@ int dquot_alloc_inode(const struct inode
 	ret = QUOTA_OK;
 warn_put_all:
 	spin_unlock(&dq_data_lock);
+	if (ret == QUOTA_OK)
+		/* Dirtify all the dquots - this can block when journalling */
+		for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+			if (inode->i_dquot[cnt])
+				mark_dquot_dirty(inode->i_dquot[cnt]);
 	flush_warnings((struct dquot **)inode->i_dquot, warntype);
 	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
 	return ret;
@@ -952,36 +1056,53 @@ warn_put_all:
 /*
  * This is a non-blocking operation.
  */
-void dquot_free_space(struct inode *inode, qsize_t number)
+int dquot_free_space(struct inode *inode, qsize_t number)
 {
 	unsigned int cnt;
 
+	/* First test before acquiring semaphore - solves deadlocks when we
+         * re-enter the quota code and are already holding the semaphore */
+	if (IS_NOQUOTA(inode)) {
+out_sub:
+		inode_sub_bytes(inode, number);
+		return QUOTA_OK;
+	}
 	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+	if (IS_NOQUOTA(inode)) {
+		up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+		goto out_sub;
+	}
 	spin_lock(&dq_data_lock);
-	if (IS_NOQUOTA(inode))
-		goto sub_bytes;
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		if (inode->i_dquot[cnt] == NODQUOT)
 			continue;
 		dquot_decr_space(inode->i_dquot[cnt], number);
 	}
-sub_bytes:
 	inode_sub_bytes(inode, number);
 	spin_unlock(&dq_data_lock);
+	/* Dirtify all the dquots - this can block when journalling */
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+		if (inode->i_dquot[cnt])
+			mark_dquot_dirty(inode->i_dquot[cnt]);
 	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+	return QUOTA_OK;
 }
 
 /*
  * This is a non-blocking operation.
  */
-void dquot_free_inode(const struct inode *inode, unsigned long number)
+int dquot_free_inode(const struct inode *inode, unsigned long number)
 {
 	unsigned int cnt;
 
+	/* First test before acquiring semaphore - solves deadlocks when we
+         * re-enter the quota code and are already holding the semaphore */
+	if (IS_NOQUOTA(inode))
+		return QUOTA_OK;
 	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
 	if (IS_NOQUOTA(inode)) {
 		up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-		return;
+		return QUOTA_OK;
 	}
 	spin_lock(&dq_data_lock);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -990,7 +1111,12 @@ void dquot_free_inode(const struct inode
 		dquot_decr_inodes(inode->i_dquot[cnt], number);
 	}
 	spin_unlock(&dq_data_lock);
+	/* Dirtify all the dquots - this can block when journalling */
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+		if (inode->i_dquot[cnt])
+			mark_dquot_dirty(inode->i_dquot[cnt]);
 	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+	return QUOTA_OK;
 }
 
 /*
@@ -1007,6 +1133,10 @@ int dquot_transfer(struct inode *inode, 
 	    chgid = (iattr->ia_valid & ATTR_GID) && inode->i_gid != iattr->ia_gid;
 	char warntype[MAXQUOTAS];
 
+	/* First test before acquiring semaphore - solves deadlocks when we
+         * re-enter the quota code and are already holding the semaphore */
+	if (IS_NOQUOTA(inode))
+		return QUOTA_OK;
 	/* Clear the arrays */
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		transfer_to[cnt] = transfer_from[cnt] = NODQUOT;
@@ -1017,7 +1147,9 @@ int dquot_transfer(struct inode *inode, 
 		up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
 		return QUOTA_OK;
 	}
-	/* First build the transfer_to list - here we can block on reading of dquots... */
+	/* First build the transfer_to list - here we can block on
+	 * reading/instantiating of dquots.  We know that the transaction for
+	 * us was already started so we don't violate lock ranking here */
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		switch (cnt) {
 			case USRQUOTA:
@@ -1065,6 +1197,13 @@ int dquot_transfer(struct inode *inode, 
 	ret = QUOTA_OK;
 warn_put_all:
 	spin_unlock(&dq_data_lock);
+	/* Dirtify all the dquots - this can block when journalling */
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		if (transfer_from[cnt])
+			mark_dquot_dirty(transfer_from[cnt]);
+		if (transfer_to[cnt])
+			mark_dquot_dirty(transfer_to[cnt]);
+	}
 	flush_warnings(transfer_to, warntype);
 	
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -1078,25 +1217,35 @@ warn_put_all:
 }
 
 /*
+ * Write info of quota file to disk
+ */
+int dquot_commit_info(struct super_block *sb, int type)
+{
+	int ret;
+	struct quota_info *dqopt = sb_dqopt(sb);
+
+	down(&dqopt->dqio_sem);
+	ret = dqopt->ops[type]->write_file_info(sb, type);
+	up(&dqopt->dqio_sem);
+	return ret;
+}
+
+/*
  * Definitions of diskquota operations.
  */
 struct dquot_operations dquot_operations = {
-	.initialize	= dquot_initialize,		/* mandatory */
-	.drop		= dquot_drop,			/* mandatory */
+	.initialize	= dquot_initialize,
+	.drop		= dquot_drop,
 	.alloc_space	= dquot_alloc_space,
 	.alloc_inode	= dquot_alloc_inode,
 	.free_space	= dquot_free_space,
 	.free_inode	= dquot_free_inode,
 	.transfer	= dquot_transfer,
-	.write_dquot	= commit_dqblk
+	.write_dquot	= dquot_commit,
+	.mark_dirty	= dquot_mark_dquot_dirty,
+	.write_info	= dquot_commit_info
 };
 
-/* Function used by filesystems for initializing the dquot_operations structure */
-void init_dquot_operations(struct dquot_operations *fsdqops)
-{
-	memcpy(fsdqops, &dquot_operations, sizeof(dquot_operations));
-}
-
 static inline void set_enable_flags(struct quota_info *dqopt, int type)
 {
 	switch (type) {
@@ -1121,9 +1270,6 @@ static inline void reset_enable_flags(st
 	}
 }
 
-/* Function in inode.c - remove pointers to dquots in icache */
-extern void remove_dquot_ref(struct super_block *, int);
-
 /*
  * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
  */
@@ -1137,7 +1283,6 @@ int vfs_quota_off(struct super_block *sb
 
 	/* We need to serialize quota_off() for device */
 	down(&dqopt->dqonoff_sem);
-	down_write(&dqopt->dqptr_sem);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		if (type != -1 && cnt != type)
 			continue;
@@ -1146,63 +1291,56 @@ int vfs_quota_off(struct super_block *sb
 		reset_enable_flags(dqopt, cnt);
 
 		/* Note: these are blocking operations */
-		remove_dquot_ref(sb, cnt);
+		drop_dquot_ref(sb, cnt);
 		invalidate_dquots(sb, cnt);
 		/*
 		 * Now all dquots should be invalidated, all writes done so we should be only
 		 * users of the info. No locks needed.
 		 */
-		if (info_dirty(&dqopt->info[cnt])) {
-			down(&dqopt->dqio_sem);
-			dqopt->ops[cnt]->write_file_info(sb, cnt);
-			up(&dqopt->dqio_sem);
-		}
+		if (info_dirty(&dqopt->info[cnt]))
+			sb->dq_op->write_info(sb, cnt);
 		if (dqopt->ops[cnt]->free_file_info)
 			dqopt->ops[cnt]->free_file_info(sb, cnt);
 		put_quota_format(dqopt->info[cnt].dqi_format);
 
 		fput(dqopt->files[cnt]);
-		dqopt->files[cnt] = (struct file *)NULL;
+		dqopt->files[cnt] = NULL;
 		dqopt->info[cnt].dqi_flags = 0;
 		dqopt->info[cnt].dqi_igrace = 0;
 		dqopt->info[cnt].dqi_bgrace = 0;
 		dqopt->ops[cnt] = NULL;
 	}
-	up_write(&dqopt->dqptr_sem);
 	up(&dqopt->dqonoff_sem);
 out:
 	return 0;
 }
 
-int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path)
+/*
+ *	Turn quotas on on a device
+ */
+
+/* Helper function when we already have file open */
+static int vfs_quota_on_file(struct file *f, int type, int format_id)
 {
-	struct file *f;
+	struct quota_format_type *fmt = find_quota_format(format_id);
 	struct inode *inode;
+	struct super_block *sb = f->f_dentry->d_sb;
 	struct quota_info *dqopt = sb_dqopt(sb);
-	struct quota_format_type *fmt = find_quota_format(format_id);
-	int error;
+	struct dquot *to_drop[MAXQUOTAS];
+	int error, cnt;
 	unsigned int oldflags;
 
 	if (!fmt)
 		return -ESRCH;
-	f = filp_open(path, O_RDWR, 0600);
-	if (IS_ERR(f)) {
-		error = PTR_ERR(f);
-		goto out_fmt;
-	}
 	error = -EIO;
 	if (!f->f_op || !f->f_op->read || !f->f_op->write)
-		goto out_f;
-	error = security_quota_on(f);
-	if (error)
-		goto out_f;
+		goto out_fmt;
 	inode = f->f_dentry->d_inode;
 	error = -EACCES;
 	if (!S_ISREG(inode->i_mode))
-		goto out_f;
+		goto out_fmt;
 
 	down(&dqopt->dqonoff_sem);
-	down_write(&dqopt->dqptr_sem);
 	if (sb_has_quota_enabled(sb, type)) {
 		error = -EBUSY;
 		goto out_lock;
@@ -1213,8 +1351,20 @@ int vfs_quota_on(struct super_block *sb,
 	if (!fmt->qf_ops->check_quota_file(sb, type))
 		goto out_file_init;
 	/* We don't want quota and atime on quota files (deadlocks possible) */
-	dquot_drop_nolock(inode);
+	down_write(&dqopt->dqptr_sem);
 	inode->i_flags |= S_NOQUOTA | S_NOATIME;
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		to_drop[cnt] = inode->i_dquot[cnt];
+		inode->i_dquot[cnt] = NODQUOT;
+	}
+	inode->i_flags &= ~S_QUOTA;
+	up_write(&dqopt->dqptr_sem);
+	/* We must put dquots outside of dqptr_sem because we may need to
+	 * start transaction for dquot_release() */
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		if (to_drop[cnt])
+			dqput(to_drop[cnt]);
+	}
 
 	dqopt->ops[type] = fmt->qf_ops;
 	dqopt->info[type].dqi_format = fmt;
@@ -1225,7 +1375,6 @@ int vfs_quota_on(struct super_block *sb,
 	}
 	up(&dqopt->dqio_sem);
 	set_enable_flags(dqopt, type);
-	up_write(&dqopt->dqptr_sem);
 
 	add_dquot_ref(sb, type);
 	up(&dqopt->dqonoff_sem);
@@ -1238,14 +1387,58 @@ out_file_init:
 out_lock:
 	up_write(&dqopt->dqptr_sem);
 	up(&dqopt->dqonoff_sem);
-out_f:
-	filp_close(f, NULL);
 out_fmt:
 	put_quota_format(fmt);
 
 	return error; 
 }
 
+/* Actual function called from quotactl() */
+int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path)
+{
+	struct file *f;
+	int error;
+
+	f = filp_open(path, O_RDWR, 0600);
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+	error = security_quota_on(f);
+	if (error)
+		goto out_f;
+	error = vfs_quota_on_file(f, type, format_id);
+	if (!error)
+		return 0;
+out_f:
+	filp_close(f, NULL);
+	return error;
+}
+
+/*
+ * Function used by filesystems when filp_open() would fail (filesystem is
+ * being mounted now). We will use a private file structure. Caller is
+ * responsible that it's IO functions won't need vfsmnt structure or
+ * some dentry tricks...
+ */
+int vfs_quota_on_mount(int type, int format_id, struct dentry *dentry)
+{
+	struct file *f;
+	int error;
+
+	dget(dentry);	/* Get a reference for struct file */
+	f = dentry_open(dentry, NULL, O_RDWR);
+	if (IS_ERR(f)) {
+		error = PTR_ERR(f);
+		goto out_dentry;
+	}
+	error = vfs_quota_on_file(f, type, format_id);
+	if (!error)
+		return 0;
+	fput(f);
+out_dentry:
+	dput(dentry);
+	return error;
+}
+
 /* Generic routine for getting common part of quota structure */
 static void do_get_dqblk(struct dquot *dquot, struct if_dqblk *di)
 {
@@ -1268,14 +1461,14 @@ int vfs_get_dqblk(struct super_block *sb
 {
 	struct dquot *dquot;
 
-	down_read(&sb_dqopt(sb)->dqptr_sem);
+	down(&sb_dqopt(sb)->dqonoff_sem);
 	if (!(dquot = dqget(sb, id, type))) {
-		up_read(&sb_dqopt(sb)->dqptr_sem);
+		up(&sb_dqopt(sb)->dqonoff_sem);
 		return -ESRCH;
 	}
 	do_get_dqblk(dquot, di);
 	dqput(dquot);
-	up_read(&sb_dqopt(sb)->dqptr_sem);
+	up(&sb_dqopt(sb)->dqonoff_sem);
 	return 0;
 }
 
@@ -1329,22 +1522,22 @@ static void do_set_dqblk(struct dquot *d
 		clear_bit(DQ_FAKE_B, &dquot->dq_flags);
 	else
 		set_bit(DQ_FAKE_B, &dquot->dq_flags);
-	mark_dquot_dirty(dquot);
 	spin_unlock(&dq_data_lock);
+	mark_dquot_dirty(dquot);
 }
 
 int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di)
 {
 	struct dquot *dquot;
 
-	down_read(&sb_dqopt(sb)->dqptr_sem);
+	down(&sb_dqopt(sb)->dqonoff_sem);
 	if (!(dquot = dqget(sb, id, type))) {
-		up_read(&sb_dqopt(sb)->dqptr_sem);
+		up(&sb_dqopt(sb)->dqonoff_sem);
 		return -ESRCH;
 	}
 	do_set_dqblk(dquot, di);
 	dqput(dquot);
-	up_read(&sb_dqopt(sb)->dqptr_sem);
+	up(&sb_dqopt(sb)->dqonoff_sem);
 	return 0;
 }
 
@@ -1353,9 +1546,9 @@ int vfs_get_dqinfo(struct super_block *s
 {
 	struct mem_dqinfo *mi;
   
-	down_read(&sb_dqopt(sb)->dqptr_sem);
+	down(&sb_dqopt(sb)->dqonoff_sem);
 	if (!sb_has_quota_enabled(sb, type)) {
-		up_read(&sb_dqopt(sb)->dqptr_sem);
+		up(&sb_dqopt(sb)->dqonoff_sem);
 		return -ESRCH;
 	}
 	mi = sb_dqopt(sb)->info + type;
@@ -1365,7 +1558,7 @@ int vfs_get_dqinfo(struct super_block *s
 	ii->dqi_flags = mi->dqi_flags & DQF_MASK;
 	ii->dqi_valid = IIF_ALL;
 	spin_unlock(&dq_data_lock);
-	up_read(&sb_dqopt(sb)->dqptr_sem);
+	up(&sb_dqopt(sb)->dqonoff_sem);
 	return 0;
 }
 
@@ -1374,9 +1567,9 @@ int vfs_set_dqinfo(struct super_block *s
 {
 	struct mem_dqinfo *mi;
 
-	down_read(&sb_dqopt(sb)->dqptr_sem);
+	down(&sb_dqopt(sb)->dqonoff_sem);
 	if (!sb_has_quota_enabled(sb, type)) {
-		up_read(&sb_dqopt(sb)->dqptr_sem);
+		up(&sb_dqopt(sb)->dqonoff_sem);
 		return -ESRCH;
 	}
 	mi = sb_dqopt(sb)->info + type;
@@ -1387,9 +1580,11 @@ int vfs_set_dqinfo(struct super_block *s
 		mi->dqi_igrace = ii->dqi_igrace;
 	if (ii->dqi_valid & IIF_FLAGS)
 		mi->dqi_flags = (mi->dqi_flags & ~DQF_MASK) | (ii->dqi_flags & DQF_MASK);
-	mark_info_dirty(mi);
 	spin_unlock(&dq_data_lock);
-	up_read(&sb_dqopt(sb)->dqptr_sem);
+	mark_info_dirty(sb, type);
+	/* Force write to disk */
+	sb->dq_op->write_info(sb, type);
+	up(&sb_dqopt(sb)->dqonoff_sem);
 	return 0;
 }
 
@@ -1520,4 +1715,21 @@ EXPORT_SYMBOL(unregister_quota_format);
 EXPORT_SYMBOL(dqstats);
 EXPORT_SYMBOL(dq_list_lock);
 EXPORT_SYMBOL(dq_data_lock);
-EXPORT_SYMBOL(init_dquot_operations);
+EXPORT_SYMBOL(vfs_quota_on);
+EXPORT_SYMBOL(vfs_quota_on_mount);
+EXPORT_SYMBOL(vfs_quota_off);
+EXPORT_SYMBOL(vfs_quota_sync);
+EXPORT_SYMBOL(vfs_get_dqinfo);
+EXPORT_SYMBOL(vfs_set_dqinfo);
+EXPORT_SYMBOL(vfs_get_dqblk);
+EXPORT_SYMBOL(vfs_set_dqblk);
+EXPORT_SYMBOL(dquot_commit);
+EXPORT_SYMBOL(dquot_commit_info);
+EXPORT_SYMBOL(dquot_mark_dquot_dirty);
+EXPORT_SYMBOL(dquot_initialize);
+EXPORT_SYMBOL(dquot_drop);
+EXPORT_SYMBOL(dquot_alloc_space);
+EXPORT_SYMBOL(dquot_alloc_inode);
+EXPORT_SYMBOL(dquot_free_space);
+EXPORT_SYMBOL(dquot_free_inode);
+EXPORT_SYMBOL(dquot_transfer);
--- diff/fs/efs/super.c	2003-10-09 09:47:34.000000000 +0100
+++ source/fs/efs/super.c	2004-03-09 11:51:51.000000000 +0000
@@ -210,6 +210,7 @@ int efs_fill_super(struct super_block *s
 {
 	struct efs_sb_info *sb;
 	struct buffer_head *bh;
+	struct inode *root;
 
  	sb = kmalloc(sizeof(struct efs_sb_info), GFP_KERNEL);
 	if (!sb)
@@ -266,10 +267,12 @@ int efs_fill_super(struct super_block *s
 		s->s_flags |= MS_RDONLY;
 	}
 	s->s_op   = &efs_superblock_operations;
-	s->s_root = d_alloc_root(iget(s, EFS_ROOTINODE));
+	root = iget(s, EFS_ROOTINODE);
+	s->s_root = d_alloc_root(root);
  
 	if (!(s->s_root)) {
 		printk(KERN_ERR "EFS: get root inode failed\n");
+		iput(root);
 		goto out_no_fs;
 	}
 
--- diff/fs/exec.c	2004-03-04 11:41:48.000000000 +0000
+++ source/fs/exec.c	2004-03-09 11:51:51.000000000 +0000
@@ -327,7 +327,7 @@ void put_dirty_page(struct task_struct *
 	set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, prot))));
 	pte_chain = page_add_rmap(page, pte, pte_chain);
 	pte_unmap(pte);
-	tsk->mm->rss++;
+	inc_rss(tsk->mm, page);
 	spin_unlock(&tsk->mm->page_table_lock);
 
 	/* no need for flush_tlb */
@@ -833,7 +833,8 @@ int flush_old_exec(struct linux_binprm *
 	flush_thread();
 
 	if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || 
-	    permission(bprm->file->f_dentry->d_inode,MAY_READ, NULL))
+	    permission(bprm->file->f_dentry->d_inode,MAY_READ, NULL) ||
+	    (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP))
 		current->mm->dumpable = 0;
 
 	/* An exec changes our domain. We are no longer part of the thread
@@ -1106,6 +1107,7 @@ int do_execve(char * filename,
 	bprm.file = file;
 	bprm.filename = filename;
 	bprm.interp = filename;
+	bprm.interp_flags = 0;
 	bprm.sh_bang = 0;
 	bprm.loader = 0;
 	bprm.exec = 0;
--- diff/fs/ext2/acl.c	2004-03-04 11:41:48.000000000 +0000
+++ source/fs/ext2/acl.c	2004-03-09 11:51:51.000000000 +0000
@@ -154,10 +154,9 @@ ext2_iset_acl(struct inode *inode, struc
 static struct posix_acl *
 ext2_get_acl(struct inode *inode, int type)
 {
-	const size_t max_size = ext2_acl_size(EXT2_ACL_MAX_ENTRIES);
 	struct ext2_inode_info *ei = EXT2_I(inode);
 	int name_index;
-	char *value;
+	char *value = NULL;
 	struct posix_acl *acl;
 	int retval;
 
@@ -182,17 +181,21 @@ ext2_get_acl(struct inode *inode, int ty
 		default:
 			return ERR_PTR(-EINVAL);
 	}
-	value = kmalloc(max_size, GFP_KERNEL);
-	if (!value)
-		return ERR_PTR(-ENOMEM);
-
-	retval = ext2_xattr_get(inode, name_index, "", value, max_size);
-	acl = ERR_PTR(retval);
-	if (retval >= 0)
+	retval = ext2_xattr_get(inode, name_index, "", NULL, 0);
+	if (retval > 0) {
+		value = kmalloc(retval, GFP_KERNEL);
+		if (!value)
+			return ERR_PTR(-ENOMEM);
+		retval = ext2_xattr_get(inode, name_index, "", value, retval);
+	}
+	if (retval > 0)
 		acl = ext2_acl_from_disk(value, retval);
 	else if (retval == -ENODATA || retval == -ENOSYS)
 		acl = NULL;
-	kfree(value);
+	else
+		acl = ERR_PTR(retval);
+	if (value)
+		kfree(value);
 
 	if (!IS_ERR(acl)) {
 		switch(type) {
--- diff/fs/ext2/dir.c	2003-06-09 14:18:20.000000000 +0100
+++ source/fs/ext2/dir.c	2004-03-09 11:51:51.000000000 +0000
@@ -310,7 +310,6 @@ ext2_readdir (struct file * filp, void *
 done:
 	filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
 	filp->f_version = inode->i_version;
-	update_atime(inode);
 	return 0;
 }
 
--- diff/fs/ext2/ialloc.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/ext2/ialloc.c	2004-03-09 11:51:51.000000000 +0000
@@ -431,8 +431,8 @@ static int find_group_other(struct super
 	 * That failed: try linear search for a free inode, even if that group
 	 * has no free blocks.
 	 */
-	group = parent_group + 1;
-	for (i = 2; i < ngroups; i++) {
+	group = parent_group;
+	for (i = 0; i < ngroups; i++) {
 		if (++group >= ngroups)
 			group = 0;
 		desc = ext2_get_group_desc (sb, group, &bh);
--- diff/fs/ext2/super.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/ext2/super.c	2004-03-09 11:51:51.000000000 +0000
@@ -563,6 +563,7 @@ static int ext2_fill_super(struct super_
 	struct buffer_head * bh;
 	struct ext2_sb_info * sbi;
 	struct ext2_super_block * es;
+	struct inode *root;
 	unsigned long block, sb_block = 1;
 	unsigned long logic_sb_block = get_sb_block(&data);
 	unsigned long offset = 0;
@@ -815,15 +816,17 @@ static int ext2_fill_super(struct super_
 	 */
 	sb->s_op = &ext2_sops;
 	sb->s_export_op = &ext2_export_ops;
-	sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO));
-	if (!sb->s_root || !S_ISDIR(sb->s_root->d_inode->i_mode) ||
-	    !sb->s_root->d_inode->i_blocks || !sb->s_root->d_inode->i_size) {
-		if (sb->s_root) {
-			dput(sb->s_root);
-			sb->s_root = NULL;
-			printk(KERN_ERR "EXT2-fs: corrupt root inode, run e2fsck\n");
-		} else
-			printk(KERN_ERR "EXT2-fs: get root inode failed\n");
+	root = iget(sb, EXT2_ROOT_INO);
+	sb->s_root = d_alloc_root(root);
+	if (!sb->s_root) {
+		iput(root);
+		printk(KERN_ERR "EXT2-fs: get root inode failed\n");
+		goto failed_mount2;
+	}
+	if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
+		dput(sb->s_root);
+		sb->s_root = NULL;
+		printk(KERN_ERR "EXT2-fs: corrupt root inode, run e2fsck\n");
 		goto failed_mount2;
 	}
 	if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL))
--- diff/fs/ext3/acl.c	2004-03-04 11:41:48.000000000 +0000
+++ source/fs/ext3/acl.c	2004-03-09 11:51:51.000000000 +0000
@@ -157,10 +157,9 @@ ext3_iset_acl(struct inode *inode, struc
 static struct posix_acl *
 ext3_get_acl(struct inode *inode, int type)
 {
-	const size_t max_size = ext3_acl_size(EXT3_ACL_MAX_ENTRIES);
 	struct ext3_inode_info *ei = EXT3_I(inode);
 	int name_index;
-	char *value;
+	char *value = NULL;
 	struct posix_acl *acl;
 	int retval;
 
@@ -185,17 +184,21 @@ ext3_get_acl(struct inode *inode, int ty
 		default:
 			return ERR_PTR(-EINVAL);
 	}
-	value = kmalloc(max_size, GFP_KERNEL);
-	if (!value)
-		return ERR_PTR(-ENOMEM);
-
-	retval = ext3_xattr_get(inode, name_index, "", value, max_size);
-	acl = ERR_PTR(retval);
+	retval = ext3_xattr_get(inode, name_index, "", NULL, 0);
+	if (retval > 0) {
+		value = kmalloc(retval, GFP_KERNEL);
+		if (!value)
+			return ERR_PTR(-ENOMEM);
+		retval = ext3_xattr_get(inode, name_index, "", value, retval);
+	}
 	if (retval > 0)
 		acl = ext3_acl_from_disk(value, retval);
 	else if (retval == -ENODATA || retval == -ENOSYS)
 		acl = NULL;
-	kfree(value);
+	else
+		acl = ERR_PTR(retval);
+	if (value)
+		kfree(value);
 
 	if (!IS_ERR(acl)) {
 		switch(type) {
--- diff/fs/ext3/dir.c	2003-06-30 10:07:34.000000000 +0100
+++ source/fs/ext3/dir.c	2004-03-09 11:51:51.000000000 +0000
@@ -224,7 +224,6 @@ revalidate:
 		offset = 0;
 		brelse (bh);
 	}
-       update_atime(inode);
 out:
 	return ret;
 }
@@ -506,7 +505,6 @@ static int ext3_dx_readdir(struct file *
 	}
 finished:
 	info->last_pos = filp->f_pos;
-	update_atime(inode);
 	return 0;
 }
 
--- diff/fs/ext3/ialloc.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/ext3/ialloc.c	2004-03-09 11:51:51.000000000 +0000
@@ -398,8 +398,8 @@ static int find_group_other(struct super
 	 * That failed: try linear search for a free inode, even if that group
 	 * has no free blocks.
 	 */
-	group = parent_group + 1;
-	for (i = 2; i < ngroups; i++) {
+	group = parent_group;
+	for (i = 0; i < ngroups; i++) {
 		if (++group >= ngroups)
 			group = 0;
 		desc = ext3_get_group_desc (sb, group, &bh);
--- diff/fs/ext3/inode.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/ext3/inode.c	2004-03-09 11:51:51.000000000 +0000
@@ -2772,9 +2772,28 @@ int ext3_setattr(struct dentry *dentry, 
 
 	if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
 		(ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
+		handle_t *handle;
+
+		/* (user+group)*(old+new) structure, inode write (sb,
+		 * inode block, ? - but truncate inode update has it) */
+		handle = ext3_journal_start(inode, 4*EXT3_QUOTA_INIT_BLOCKS+3);
+		if (IS_ERR(handle)) {
+			error = PTR_ERR(handle);
+			goto err_out;
+		}
 		error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
-		if (error)
+		if (error) {
+			ext3_journal_stop(handle);
 			return error;
+		}
+		/* Update corresponding info in inode so that everything is in
+		 * one transaction */
+		if (attr->ia_valid & ATTR_UID)
+			inode->i_uid = attr->ia_uid;
+		if (attr->ia_valid & ATTR_GID)
+			inode->i_gid = attr->ia_gid;
+		error = ext3_mark_inode_dirty(handle, inode);
+		ext3_journal_stop(handle);
 	}
 
 	if (S_ISREG(inode->i_mode) &&
@@ -2853,7 +2872,9 @@ int ext3_writepage_trans_blocks(struct i
 		ret = 2 * (bpp + indirects) + 2;
 
 #ifdef CONFIG_QUOTA
-	ret += 2 * EXT3_SINGLEDATA_TRANS_BLOCKS;
+	/* We know that structure was already allocated during DQUOT_INIT so
+	 * we will be updating only the data blocks + inodes */
+	ret += 2*EXT3_QUOTA_TRANS_BLOCKS;
 #endif
 
 	return ret;
--- diff/fs/ext3/namei.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/ext3/namei.c	2004-03-09 11:51:51.000000000 +0000
@@ -1633,7 +1633,8 @@ static int ext3_create (struct inode * d
 	int err;
 
 	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
-					EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3);
+					EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
+					2*EXT3_QUOTA_INIT_BLOCKS);
 	if (IS_ERR(handle))
 		return PTR_ERR(handle);
 
@@ -1663,7 +1664,8 @@ static int ext3_mknod (struct inode * di
 		return -EINVAL;
 
 	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
-			 		EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3);
+			 		EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
+					2*EXT3_QUOTA_INIT_BLOCKS);
 	if (IS_ERR(handle))
 		return PTR_ERR(handle);
 
@@ -1695,7 +1697,8 @@ static int ext3_mkdir(struct inode * dir
 		return -EMLINK;
 
 	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
-					EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3);
+					EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
+					2*EXT3_QUOTA_INIT_BLOCKS);
 	if (IS_ERR(handle))
 		return PTR_ERR(handle);
 
@@ -1974,6 +1977,9 @@ static int ext3_rmdir (struct inode * di
 	struct ext3_dir_entry_2 * de;
 	handle_t *handle;
 
+	/* Initialize quotas before so that eventual writes go in
+	 * separate transaction */
+	DQUOT_INIT(dentry->d_inode);
 	handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);
 	if (IS_ERR(handle))
 		return PTR_ERR(handle);
@@ -1987,7 +1993,6 @@ static int ext3_rmdir (struct inode * di
 		handle->h_sync = 1;
 
 	inode = dentry->d_inode;
-	DQUOT_INIT(inode);
 
 	retval = -EIO;
 	if (le32_to_cpu(de->inode) != inode->i_ino)
@@ -2031,6 +2036,9 @@ static int ext3_unlink(struct inode * di
 	struct ext3_dir_entry_2 * de;
 	handle_t *handle;
 
+	/* Initialize quotas before so that eventual writes go
+	 * in separate transaction */
+	DQUOT_INIT(dentry->d_inode);
 	handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);
 	if (IS_ERR(handle))
 		return PTR_ERR(handle);
@@ -2044,7 +2052,6 @@ static int ext3_unlink(struct inode * di
 		goto end_unlink;
 
 	inode = dentry->d_inode;
-	DQUOT_INIT(inode);
 
 	retval = -EIO;
 	if (le32_to_cpu(de->inode) != inode->i_ino)
@@ -2087,7 +2094,8 @@ static int ext3_symlink (struct inode * 
 		return -ENAMETOOLONG;
 
 	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
-			 		EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5);
+			 		EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 +
+					2*EXT3_QUOTA_INIT_BLOCKS);
 	if (IS_ERR(handle))
 		return PTR_ERR(handle);
 
@@ -2172,6 +2180,10 @@ static int ext3_rename (struct inode * o
 
 	old_bh = new_bh = dir_bh = NULL;
 
+	/* Initialize quotas before so that eventual writes go
+	 * in separate transaction */
+	if (new_dentry->d_inode)
+		DQUOT_INIT(new_dentry->d_inode);
 	handle = ext3_journal_start(old_dir, 2 * EXT3_DATA_TRANS_BLOCKS +
 			 		EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2);
 	if (IS_ERR(handle))
@@ -2198,8 +2210,6 @@ static int ext3_rename (struct inode * o
 		if (!new_inode) {
 			brelse (new_bh);
 			new_bh = NULL;
-		} else {
-			DQUOT_INIT(new_inode);
 		}
 	}
 	if (S_ISDIR(old_inode->i_mode)) {
--- diff/fs/ext3/super.c	2004-03-04 11:41:48.000000000 +0000
+++ source/fs/ext3/super.c	2004-03-09 11:51:51.000000000 +0000
@@ -32,6 +32,9 @@
 #include <linux/buffer_head.h>
 #include <linux/vfs.h>
 #include <linux/random.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/quotaops.h>
 #include <asm/uaccess.h>
 #include "xattr.h"
 #include "acl.h"
@@ -504,7 +507,43 @@ static void ext3_clear_inode(struct inod
 # define ext3_clear_inode NULL
 #endif
 
-static struct dquot_operations ext3_qops;
+#ifdef CONFIG_QUOTA
+
+#define QTYPE2NAME(t) ((t)==USRQUOTA?"user":"group")
+#define QTYPE2MOPT(on, t) ((t)==USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA))
+
+static int ext3_dquot_initialize(struct inode *inode, int type);
+static int ext3_dquot_drop(struct inode *inode);
+static int ext3_write_dquot(struct dquot *dquot);
+static int ext3_mark_dquot_dirty(struct dquot *dquot);
+static int ext3_write_info(struct super_block *sb, int type);
+static int ext3_quota_on(struct super_block *sb, int type, int format_id, char *path);
+static int ext3_quota_on_mount(struct super_block *sb, int type);
+static int ext3_quota_off_mount(struct super_block *sb, int type);
+
+static struct dquot_operations ext3_quota_operations = {
+	.initialize	= ext3_dquot_initialize,
+	.drop		= ext3_dquot_drop,
+	.alloc_space	= dquot_alloc_space,
+	.alloc_inode	= dquot_alloc_inode,
+	.free_space	= dquot_free_space,
+	.free_inode	= dquot_free_inode,
+	.transfer	= dquot_transfer,
+	.write_dquot	= ext3_write_dquot,
+	.mark_dirty	= ext3_mark_dquot_dirty,
+	.write_info	= ext3_write_info
+};
+
+static struct quotactl_ops ext3_qctl_operations = {
+	.quota_on	= ext3_quota_on,
+	.quota_off	= vfs_quota_off,
+	.quota_sync	= vfs_quota_sync,
+	.get_info	= vfs_get_dqinfo,
+	.set_info	= vfs_set_dqinfo,
+	.get_dqblk	= vfs_get_dqblk,
+	.set_dqblk	= vfs_set_dqblk
+};
+#endif
 
 static struct super_operations ext3_sops = {
 	.alloc_inode	= ext3_alloc_inode,
@@ -536,6 +575,8 @@ enum {
 	Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_noload,
 	Opt_commit, Opt_journal_update, Opt_journal_inum,
 	Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
+	Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
+	Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0,
 	Opt_ignore, Opt_err,
 };
 
@@ -571,6 +612,12 @@ static match_table_t tokens = {
 	{Opt_data_journal, "data=journal"},
 	{Opt_data_ordered, "data=ordered"},
 	{Opt_data_writeback, "data=writeback"},
+	{Opt_offusrjquota, "usrjquota="},
+	{Opt_usrjquota, "usrjquota=%s"},
+	{Opt_offgrpjquota, "grpjquota="},
+	{Opt_grpjquota, "grpjquota=%s"},
+	{Opt_jqfmt_vfsold, "jqfmt=vfsold"},
+	{Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
 	{Opt_ignore, "grpquota"},
 	{Opt_ignore, "noquota"},
 	{Opt_ignore, "quota"},
@@ -598,13 +645,17 @@ static unsigned long get_sb_block(void *
 	return sb_block;
 }
 
-static int parse_options (char * options, struct ext3_sb_info *sbi,
+static int parse_options (char * options, struct super_block *sb,
 			  unsigned long * inum, int is_remount)
 {
+	struct ext3_sb_info *sbi = EXT3_SB(sb);
 	char * p;
 	substring_t args[MAX_OPT_ARGS];
 	int data_opt = 0;
 	int option;
+#ifdef CONFIG_QUOTA
+	int qtype;
+#endif
 
 	if (!options)
 		return 1;
@@ -759,6 +810,76 @@ static int parse_options (char * options
 				sbi->s_mount_opt |= data_opt;
 			}
 			break;
+#ifdef CONFIG_QUOTA
+		case Opt_usrjquota:
+			qtype = USRQUOTA;
+			goto set_qf_name;
+		case Opt_grpjquota:
+			qtype = GRPQUOTA;
+set_qf_name:
+			if (sb_any_quota_enabled(sb)) {
+				printk(KERN_ERR
+					"EXT3-fs: Cannot change journalled "
+					"quota options when quota turned on.\n");
+				return 0;
+			}
+			if (sbi->s_qf_names[qtype]) {
+				printk(KERN_ERR
+					"EXT3-fs: %s quota file already "
+					"specified.\n", QTYPE2NAME(qtype));
+				return 0;
+			}
+			sbi->s_qf_names[qtype] = match_strdup(&args[0]);
+			if (!sbi->s_qf_names[qtype]) {
+				printk(KERN_ERR
+					"EXT3-fs: not enough memory for "
+					"storing quotafile name.\n");
+				return 0;
+			}
+			if (strchr(sbi->s_qf_names[qtype], '/')) {
+				printk(KERN_ERR
+					"EXT3-fs: quotafile must be on "
+					"filesystem root.\n");
+				kfree(sbi->s_qf_names[qtype]);
+				sbi->s_qf_names[qtype] = NULL;
+				return 0;
+			}
+			break;
+		case Opt_offusrjquota:
+			qtype = USRQUOTA;
+			goto clear_qf_name;
+		case Opt_offgrpjquota:
+			qtype = GRPQUOTA;
+clear_qf_name:
+			if (sb_any_quota_enabled(sb)) {
+				printk(KERN_ERR "EXT3-fs: Cannot change "
+					"journalled quota options when "
+					"quota turned on.\n");
+				return 0;
+			}
+			if (sbi->s_qf_names[qtype]) {
+				kfree(sbi->s_qf_names[qtype]);
+				sbi->s_qf_names[qtype] = NULL;
+			}
+			break;
+		case Opt_jqfmt_vfsold:
+			sbi->s_jquota_fmt = QFMT_VFS_OLD;
+			break;
+		case Opt_jqfmt_vfsv0:
+			sbi->s_jquota_fmt = QFMT_VFS_V0;
+			break;
+#else
+		case Opt_usrjquota:
+		case Opt_grpjquota:
+		case Opt_offusrjquota:
+		case Opt_offgrpjquota:
+		case Opt_jqfmt_vfsold:
+		case Opt_jqfmt_vfsv0:
+			printk(KERN_ERR
+				"EXT3-fs: journalled quota options not "
+				"supported.\n");
+			break;
+#endif
 		case Opt_abort:
 			set_opt(sbi->s_mount_opt, ABORT);
 			break;
@@ -771,6 +892,13 @@ static int parse_options (char * options
 			return 0;
 		}
 	}
+#ifdef CONFIG_QUOTA
+	if (!sbi->s_jquota_fmt && (sbi->s_qf_names[0] || sbi->s_qf_names[1])) {
+		printk(KERN_ERR
+			"EXT3-fs: journalled quota format not specified.\n");
+		return 0;
+	}
+#endif
 
 	return 1;
 }
@@ -930,6 +1058,9 @@ static void ext3_orphan_cleanup (struct 
 {
 	unsigned int s_flags = sb->s_flags;
 	int nr_orphans = 0, nr_truncates = 0;
+#ifdef CONFIG_QUOTA
+	int i;
+#endif
 	if (!es->s_last_orphan) {
 		jbd_debug(4, "no orphan inodes to clean up\n");
 		return;
@@ -949,6 +1080,20 @@ static void ext3_orphan_cleanup (struct 
 		       sb->s_id);
 		sb->s_flags &= ~MS_RDONLY;
 	}
+#ifdef CONFIG_QUOTA
+	/* Needed for iput() to work correctly and not trash data */
+	sb->s_flags |= MS_ACTIVE;
+	/* Turn on quotas so that they are updated correctly */
+	for (i = 0; i < MAXQUOTAS; i++) {
+		if (EXT3_SB(sb)->s_qf_names[i]) {
+			int ret = ext3_quota_on_mount(sb, i);
+			if (ret < 0)
+				printk(KERN_ERR
+					"EXT3-fs: Cannot turn on journalled "
+					"quota: error %d\n", ret);
+		}
+	}
+#endif
 
 	while (es->s_last_orphan) {
 		struct inode *inode;
@@ -960,6 +1105,7 @@ static void ext3_orphan_cleanup (struct 
 		}
 
 		list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan);
+		DQUOT_INIT(inode);
 		if (inode->i_nlink) {
 			printk(KERN_DEBUG
 				"%s: truncating inode %ld to %Ld bytes\n",
@@ -987,6 +1133,13 @@ static void ext3_orphan_cleanup (struct 
 	if (nr_truncates)
 		printk(KERN_INFO "EXT3-fs: %s: %d truncate%s cleaned up\n",
 		       sb->s_id, PLURAL(nr_truncates));
+#ifdef CONFIG_QUOTA
+	/* Turn quotas off */
+	for (i = 0; i < MAXQUOTAS; i++) {
+		if (sb_dqopt(sb)->files[i])
+			ext3_quota_off_mount(sb, i);
+	}
+#endif
 	sb->s_flags = s_flags; /* Restore MS_RDONLY status */
 }
 
@@ -1040,6 +1193,7 @@ static int ext3_fill_super (struct super
 	unsigned long offset = 0;
 	unsigned long journal_inum = 0;
 	unsigned long def_mount_opts;
+	struct inode *root;
 	int blocksize;
 	int hblock;
 	int db_count;
@@ -1116,7 +1270,7 @@ static int ext3_fill_super (struct super
 	sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
 	sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
 
-	if (!parse_options ((char *) data, sbi, &journal_inum, 0))
+	if (!parse_options ((char *) data, sb, &journal_inum, 0))
 		goto failed_mount;
 
 	sb->s_flags |= MS_ONE_SECOND;
@@ -1295,7 +1449,10 @@ static int ext3_fill_super (struct super
 	 */
 	sb->s_op = &ext3_sops;
 	sb->s_export_op = &ext3_export_ops;
-	sb->dq_op = &ext3_qops;
+#ifdef CONFIG_QUOTA
+	sb->s_qcop = &ext3_qctl_operations;
+	sb->dq_op = &ext3_quota_operations;
+#endif
 	INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
 
 	sb->s_root = 0;
@@ -1354,16 +1511,17 @@ static int ext3_fill_super (struct super
 	 * so we can safely mount the rest of the filesystem now.
 	 */
 
-	sb->s_root = d_alloc_root(iget(sb, EXT3_ROOT_INO));
-	if (!sb->s_root || !S_ISDIR(sb->s_root->d_inode->i_mode) ||
-	    !sb->s_root->d_inode->i_blocks || !sb->s_root->d_inode->i_size) {
-		if (sb->s_root) {
-			dput(sb->s_root);
-			sb->s_root = NULL;
-			printk(KERN_ERR
-			       "EXT3-fs: corrupt root inode, run e2fsck\n");
-		} else
-			printk(KERN_ERR "EXT3-fs: get root inode failed\n");
+	root = iget(sb, EXT3_ROOT_INO);
+	sb->s_root = d_alloc_root(root);
+	if (!sb->s_root) {
+		printk(KERN_ERR "EXT3-fs: get root inode failed\n");
+		iput(root);
+		goto failed_mount3;
+	}
+	if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
+		dput(sb->s_root);
+		sb->s_root = NULL;
+		printk(KERN_ERR "EXT3-fs: corrupt root inode, run e2fsck\n");
 		goto failed_mount3;
 	}
 
@@ -1404,6 +1562,12 @@ failed_mount2:
 		brelse(sbi->s_group_desc[i]);
 	kfree(sbi->s_group_desc);
 failed_mount:
+#ifdef CONFIG_QUOTA
+	for (i = 0; i < MAXQUOTAS; i++) {
+		if (sbi->s_qf_names[i])
+			kfree(sbi->s_qf_names[i]);
+	}
+#endif
 	ext3_blkdev_remove(sbi);
 	brelse(bh);
 out_fail:
@@ -1830,7 +1994,7 @@ int ext3_remount (struct super_block * s
 	/*
 	 * Allow the "check" option to be passed as a remount option.
 	 */
-	if (!parse_options(data, sbi, &tmp, 1))
+	if (!parse_options(data, sb, &tmp, 1))
 		return -EINVAL;
 
 	if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
@@ -1950,45 +2114,152 @@ int ext3_statfs (struct super_block * sb
 
 #ifdef CONFIG_QUOTA
 
-/* Blocks: (2 data blocks) * (3 indirect + 1 descriptor + 1 bitmap) + superblock */
-#define EXT3_OLD_QFMT_BLOCKS 11
-/* Blocks: quota info + (4 pointer blocks + 1 entry block) * (3 indirect + 1 descriptor + 1 bitmap) + superblock */
-#define EXT3_V0_QFMT_BLOCKS 27
+static inline struct inode *dquot_to_inode(struct dquot *dquot)
+{
+	return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]->f_dentry->d_inode;
+}
+
+static int ext3_dquot_initialize(struct inode *inode, int type)
+{
+	handle_t *handle;
+	int ret, err;
+
+	/* We may create quota structure so we need to reserve enough blocks */
+	handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS);
+	if (IS_ERR(handle))
+		return PTR_ERR(handle);
+	ret = dquot_initialize(inode, type);
+	err = ext3_journal_stop(handle);
+	if (!ret)
+		ret = err;
+	return ret;
+}
 
-static int (*old_write_dquot)(struct dquot *dquot);
+static int ext3_dquot_drop(struct inode *inode)
+{
+	handle_t *handle;
+	int ret, err;
+
+	/* We may delete quota structure so we need to reserve enough blocks */
+	handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS);
+	if (IS_ERR(handle))
+		return PTR_ERR(handle);
+	ret = dquot_drop(inode);
+	err = ext3_journal_stop(handle);
+	if (!ret)
+		ret = err;
+	return ret;
+}
 
 static int ext3_write_dquot(struct dquot *dquot)
 {
-	int nblocks;
-	int ret;
-	int err;
+	int ret, err;
 	handle_t *handle;
-	struct quota_info *dqops = sb_dqopt(dquot->dq_sb);
-	struct inode *qinode;
 
-	switch (dqops->info[dquot->dq_type].dqi_format->qf_fmt_id) {
-		case QFMT_VFS_OLD:
-			nblocks = EXT3_OLD_QFMT_BLOCKS;
-			break;
-		case QFMT_VFS_V0:
-			nblocks = EXT3_V0_QFMT_BLOCKS;
-			break;
-		default:
-			nblocks = EXT3_MAX_TRANS_DATA;
-	}
-	qinode = dqops->files[dquot->dq_type]->f_dentry->d_inode;
-	handle = ext3_journal_start(qinode, nblocks);
-	if (IS_ERR(handle)) {
-		ret = PTR_ERR(handle);
-		goto out;
-	}
-	ret = old_write_dquot(dquot);
+	handle = ext3_journal_start(dquot_to_inode(dquot),
+					EXT3_QUOTA_TRANS_BLOCKS);
+	if (IS_ERR(handle))
+		return PTR_ERR(handle);
+	ret = dquot_commit(dquot);
 	err = ext3_journal_stop(handle);
-	if (ret == 0)
+	if (!ret)
+		ret = err;
+	return ret;
+}
+
+static int ext3_mark_dquot_dirty(struct dquot * dquot)
+{
+	/* Are we journalling quotas? */
+	if (EXT3_SB(dquot->dq_sb)->s_qf_names[0] ||
+	    EXT3_SB(dquot->dq_sb)->s_qf_names[1])
+		return ext3_write_dquot(dquot);
+	else
+		return dquot_mark_dquot_dirty(dquot);
+}
+
+static int ext3_write_info(struct super_block *sb, int type)
+{
+	int ret, err;
+	handle_t *handle;
+
+	/* Data block + inode block */
+	handle = ext3_journal_start(sb->s_root->d_inode, 2);
+	if (IS_ERR(handle))
+		return PTR_ERR(handle);
+	ret = dquot_commit_info(sb, type);
+	err = ext3_journal_stop(handle);
+	if (!ret)
 		ret = err;
-out:
 	return ret;
 }
+
+/*
+ * Turn on quotas during mount time - we need to find
+ * the quota file and such...
+ */
+static int ext3_quota_on_mount(struct super_block *sb, int type)
+{
+	int err;
+	struct dentry *dentry;
+	struct qstr name = { .name = EXT3_SB(sb)->s_qf_names[type],
+			     .hash = 0,
+			     .len = strlen(EXT3_SB(sb)->s_qf_names[type])};
+
+	dentry = lookup_hash(&name, sb->s_root);
+	if (IS_ERR(dentry))
+		return PTR_ERR(dentry);
+	err = vfs_quota_on_mount(type, EXT3_SB(sb)->s_jquota_fmt, dentry);
+	if (err)
+		dput(dentry);
+	/* We keep the dentry reference if everything went ok - we drop it
+	 * on quota_off time */
+	return err;
+}
+
+/* Turn quotas off during mount time */
+static int ext3_quota_off_mount(struct super_block *sb, int type)
+{
+	int err;
+	struct dentry *dentry;
+
+	dentry = sb_dqopt(sb)->files[type]->f_dentry;
+	err = vfs_quota_off_mount(sb, type);
+	/* We invalidate dentry - it has at least wrong hash... */
+	d_invalidate(dentry);
+	dput(dentry);
+	return err;
+}
+
+/*
+ * Standard function to be called on quota_on
+ */
+static int ext3_quota_on(struct super_block *sb, int type, int format_id,
+			 char *path)
+{
+	int err;
+	struct nameidata nd;
+
+	/* Not journalling quota? */
+	if (!EXT3_SB(sb)->s_qf_names[0] && !EXT3_SB(sb)->s_qf_names[1])
+		return vfs_quota_on(sb, type, format_id, path);
+	err = path_lookup(path, LOOKUP_FOLLOW, &nd);
+	if (err)
+		return err;
+	/* Quotafile not on the same filesystem? */
+	if (nd.mnt->mnt_sb != sb)
+		return -EXDEV;
+	/* Quotafile not of fs root? */
+	if (nd.dentry->d_parent->d_inode != sb->s_root->d_inode)
+		printk(KERN_WARNING
+			"EXT3-fs: Quota file not on filesystem root. "
+			"Journalled quota will not work.\n");
+	if (!ext3_should_journal_data(nd.dentry->d_inode))
+		printk(KERN_WARNING "EXT3-fs: Quota file does not have "
+			"data-journalling. Journalled quota will not work.\n");
+	path_release(&nd);
+	return vfs_quota_on(sb, type, format_id, path);
+}
+
 #endif
 
 static struct super_block *ext3_get_sb(struct file_system_type *fs_type,
@@ -2013,11 +2284,6 @@ static int __init init_ext3_fs(void)
 	err = init_inodecache();
 	if (err)
 		goto out1;
-#ifdef CONFIG_QUOTA
-	init_dquot_operations(&ext3_qops);
-	old_write_dquot = ext3_qops.write_dquot;
-	ext3_qops.write_dquot = ext3_write_dquot;
-#endif
         err = register_filesystem(&ext3_fs_type);
 	if (err)
 		goto out;
--- diff/fs/fat/inode.c	2004-01-19 10:22:59.000000000 +0000
+++ source/fs/fat/inode.c	2004-03-09 11:51:51.000000000 +0000
@@ -778,6 +778,7 @@ int fat_fill_super(struct super_block *s
 	sb->s_fs_info = sbi;
 	memset(sbi, 0, sizeof(struct msdos_sb_info));
 
+	sb->s_flags |= MS_NODIRATIME;
 	sb->s_magic = MSDOS_SUPER_MAGIC;
 	sb->s_op = &fat_sops;
 	sb->s_export_op = &fat_export_ops;
--- diff/fs/fcntl.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/fcntl.c	2004-03-09 11:51:51.000000000 +0000
@@ -19,7 +19,7 @@
 #include <asm/siginfo.h>
 #include <asm/uaccess.h>
 
-void set_close_on_exec(unsigned int fd, int flag)
+void fastcall set_close_on_exec(unsigned int fd, int flag)
 {
 	struct files_struct *files = current->files;
 	spin_lock(&files->file_lock);
--- diff/fs/file_table.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/file_table.c	2004-03-09 11:51:51.000000000 +0000
@@ -152,7 +152,7 @@ void close_private_file(struct file *fil
 
 EXPORT_SYMBOL(close_private_file);
 
-void fput(struct file *file)
+void fastcall fput(struct file *file)
 {
 	if (atomic_dec_and_test(&file->f_count))
 		__fput(file);
@@ -163,7 +163,7 @@ EXPORT_SYMBOL(fput);
 /* __fput is called from task context when aio completion releases the last
  * last use of a struct file *.  Do not use otherwise.
  */
-void __fput(struct file *file)
+void fastcall __fput(struct file *file)
 {
 	struct dentry *dentry = file->f_dentry;
 	struct vfsmount *mnt = file->f_vfsmnt;
@@ -192,7 +192,7 @@ void __fput(struct file *file)
 	mntput(mnt);
 }
 
-struct file *fget(unsigned int fd)
+struct file fastcall *fget(unsigned int fd)
 {
 	struct file *file;
 	struct files_struct *files = current->files;
@@ -214,7 +214,7 @@ EXPORT_SYMBOL(fget);
  * and a flag is returned to be passed to the corresponding fput_light().
  * There must not be a cloning between an fget_light/fput_light pair.
  */
-struct file *fget_light(unsigned int fd, int *fput_needed)
+struct file fastcall *fget_light(unsigned int fd, int *fput_needed)
 {
 	struct file *file;
 	struct files_struct *files = current->files;
--- diff/fs/freevxfs/vxfs_super.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/freevxfs/vxfs_super.c	2004-03-09 11:51:51.000000000 +0000
@@ -143,6 +143,9 @@ static int vxfs_fill_super(struct super_
 	struct vxfs_sb		*rsbp;
 	struct buffer_head	*bp = NULL;
 	u_long			bsize;
+	struct inode *root;
+
+	sbp->s_flags |= MS_RDONLY;
 
 	infp = kmalloc(sizeof(*infp), GFP_KERNEL);
 	if (!infp) {
@@ -208,8 +211,10 @@ static int vxfs_fill_super(struct super_
 	}
 
 	sbp->s_op = &vxfs_super_ops;
-	sbp->s_root = d_alloc_root(iget(sbp, VXFS_ROOT_INO));
+	root = iget(sbp, VXFS_ROOT_INO);
+	sbp->s_root = d_alloc_root(root);
 	if (!sbp->s_root) {
+		iput(root);
 		printk(KERN_WARNING "vxfs: unable to get root dentry.\n");
 		goto out_free_ilist;
 	}
--- diff/fs/fs-writeback.c	2004-03-04 11:41:48.000000000 +0000
+++ source/fs/fs-writeback.c	2004-03-09 11:51:51.000000000 +0000
@@ -22,6 +22,7 @@
 #include <linux/blkdev.h>
 #include <linux/backing-dev.h>
 #include <linux/buffer_head.h>
+#include <linux/ext3_fs_i.h>
 
 extern struct super_block *blockdev_superblock;
 
@@ -138,6 +139,7 @@ __sync_single_inode(struct inode *inode,
 	struct address_space *mapping = inode->i_mapping;
 	struct super_block *sb = inode->i_sb;
 	int wait = wbc->sync_mode == WB_SYNC_ALL;
+	int blkdev = inode->i_sb == blockdev_superblock;
 
 	BUG_ON(inode->i_state & I_LOCK);
 
@@ -145,6 +147,26 @@ __sync_single_inode(struct inode *inode,
 	dirty = inode->i_state & I_DIRTY;
 	inode->i_state |= I_LOCK;
 	inode->i_state &= ~I_DIRTY;
+	spin_unlock(&inode_lock);
+
+	/*
+	 * Serialize writebacks except for blockdevs
+	 */
+	if (!blkdev) {
+		/*
+		 * Only allow 1 SYNC writeback at a time, to be able to wait
+		 * for all i/o without worrying about racing WB_SYNC_NONE
+		 * writers.
+		 */
+		if (wait) {
+			down_write(&mapping->wb_rwsema);
+		} else {
+			if (!down_read_trylock(&mapping->wb_rwsema)) {
+				wbc->encountered_congestion = 1;
+				goto skip_writeback;
+			}
+		}
+	}
 
 	/*
 	 * smp_rmb(); note: if you remove write_lock below, you must add this.
@@ -156,10 +178,17 @@ __sync_single_inode(struct inode *inode,
 	if (wait || !wbc->for_kupdate || list_empty(&mapping->io_pages))
 		list_splice_init(&mapping->dirty_pages, &mapping->io_pages);
 	spin_unlock(&mapping->page_lock);
-	spin_unlock(&inode_lock);
 
 	do_writepages(mapping, wbc);
 
+	if (!blkdev) {
+		if (wait)
+			up_write(&mapping->wb_rwsema);
+		else
+			up_read(&mapping->wb_rwsema);
+	}
+
+skip_writeback:
 	/* Don't write the inode if only I_DIRTY_PAGES was set */
 	if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC))
 		write_inode(inode, wait);
@@ -185,6 +214,14 @@ __sync_single_inode(struct inode *inode,
 		} else if (atomic_read(&inode->i_count)) {
 			list_move(&inode->i_list, &inode_in_use);
 		} else {
+			if (!strcmp(inode->i_sb->s_type->name, "ext3")) {
+				struct ext3_inode_info *ext3_i;
+				ext3_i = container_of(inode,
+						struct ext3_inode_info,
+						vfs_inode);
+				if (!list_empty(&ext3_i->i_orphan))
+					WARN_ON(1);
+			}
 			list_move(&inode->i_list, &inode_unused);
 		}
 	}
@@ -276,7 +313,12 @@ sync_sb_inodes(struct super_block *sb, s
 			break;
 		}
 
-		if (wbc->nonblocking && bdi_write_congested(bdi)) {
+		/*
+		 * wbc->encountered_congestion is set if we cannot get
+		 * the wb_rwsema.
+		 */
+		if (wbc->nonblocking &&
+		    (bdi_write_congested(bdi) || wbc->encountered_congestion)) {
 			wbc->encountered_congestion = 1;
 			if (sb != blockdev_superblock)
 				break;		/* Skip a congested fs */
--- diff/fs/hfs/super.c	2004-03-04 11:41:49.000000000 +0000
+++ source/fs/hfs/super.c	2004-03-09 11:51:51.000000000 +0000
@@ -268,6 +268,7 @@ static int hfs_fill_super(struct super_b
 	}
 
 	sb->s_op = &hfs_super_operations;
+	sb->s_flags |= MS_NODIRATIME;
 	init_MUTEX(&sbi->bitmap_lock);
 
 	res = hfs_mdb_get(sb);
@@ -294,13 +295,15 @@ static int hfs_fill_super(struct super_b
 
 	sb->s_root = d_alloc_root(root_inode);
 	if (!sb->s_root)
-		goto bail_no_root;
+		goto bail_iput;
 
 	sb->s_root->d_op = &hfs_dentry_operations;
 
 	/* everything's okay */
 	return 0;
 
+bail_iput:
+	iput(root_inode);
 bail_no_root:
 	hfs_warn("hfs_fs: get root inode failed.\n");
 	hfs_mdb_put(sb);
--- diff/fs/hfsplus/dir.c	2004-03-04 11:41:49.000000000 +0000
+++ source/fs/hfsplus/dir.c	2004-03-09 11:51:51.000000000 +0000
@@ -399,6 +399,7 @@ int hfsplus_symlink(struct inode *dir, s
 	res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
 
 	if (!res) {
+		dentry->d_fsdata = (void *)inode->i_ino;
 		d_instantiate(dentry, inode);
 		mark_inode_dirty(inode);
 	}
@@ -424,6 +425,7 @@ int hfsplus_mknod(struct inode *dir, str
 		return res;
 	}
 	init_special_inode(inode, mode, rdev);
+	dentry->d_fsdata = (void *)inode->i_ino;
 	d_instantiate(dentry, inode);
 	mark_inode_dirty(inode);
 
--- diff/fs/hfsplus/inode.c	2004-03-04 11:41:49.000000000 +0000
+++ source/fs/hfsplus/inode.c	2004-03-09 11:51:51.000000000 +0000
@@ -335,6 +335,14 @@ struct inode *hfsplus_new_inode(struct s
 	init_MUTEX(&HFSPLUS_I(inode).extents_lock);
 	atomic_set(&HFSPLUS_I(inode).opencnt, 0);
 	HFSPLUS_I(inode).flags = 0;
+	memset(HFSPLUS_I(inode).first_extents, 0, sizeof(hfsplus_extent_rec));
+	memset(HFSPLUS_I(inode).cached_extents, 0, sizeof(hfsplus_extent_rec));
+	HFSPLUS_I(inode).alloc_blocks = 0;
+	HFSPLUS_I(inode).first_blocks = 0;
+	HFSPLUS_I(inode).cached_start = 0;
+	HFSPLUS_I(inode).cached_blocks = 0;
+	HFSPLUS_I(inode).phys_size = 0;
+	HFSPLUS_I(inode).rsrc_inode = 0;
 	if (S_ISDIR(inode->i_mode)) {
 		inode->i_size = 2;
 		HFSPLUS_SB(sb).folder_count++;
@@ -346,14 +354,6 @@ struct inode *hfsplus_new_inode(struct s
 		inode->i_fop = &hfsplus_file_operations;
 		inode->i_mapping->a_ops = &hfsplus_aops;
 		HFSPLUS_I(inode).clump_blocks = HFSPLUS_SB(sb).data_clump_blocks;
-		memset(HFSPLUS_I(inode).first_extents, 0, sizeof(hfsplus_extent_rec));
-		memset(HFSPLUS_I(inode).cached_extents, 0, sizeof(hfsplus_extent_rec));
-		HFSPLUS_I(inode).alloc_blocks = 0;
-		HFSPLUS_I(inode).first_blocks = 0;
-		HFSPLUS_I(inode).cached_start = 0;
-		HFSPLUS_I(inode).cached_blocks = 0;
-		HFSPLUS_I(inode).phys_size = 0;
-		HFSPLUS_I(inode).rsrc_inode = 0;
 	} else if (S_ISLNK(inode->i_mode)) {
 		HFSPLUS_SB(sb).file_count++;
 		inode->i_op = &page_symlink_inode_operations;
--- diff/fs/hfsplus/super.c	2004-03-04 11:41:49.000000000 +0000
+++ source/fs/hfsplus/super.c	2004-03-09 11:51:51.000000000 +0000
@@ -278,6 +278,7 @@ static int hfsplus_fill_super(struct sup
 	struct hfsplus_sb_info *sbi;
 	hfsplus_cat_entry entry;
 	struct hfs_find_data fd;
+	struct inode *root;
 	struct qstr str;
 	int err = -EINVAL;
 
@@ -364,10 +365,12 @@ static int hfsplus_fill_super(struct sup
 	}
 
 	/* Load the root directory */
-	sb->s_root = d_alloc_root(iget(sb, HFSPLUS_ROOT_CNID));
+	root = iget(sb, HFSPLUS_ROOT_CNID);
+	sb->s_root = d_alloc_root(root);
 	if (!sb->s_root) {
 		if (!silent)
 			printk("HFS+-fs: failed to load root directory\n");
+		iput(root);
 		goto cleanup;
 	}
 
--- diff/fs/hpfs/buffer.c	2004-03-04 11:41:49.000000000 +0000
+++ source/fs/hpfs/buffer.c	2004-03-09 11:51:51.000000000 +0000
@@ -60,74 +60,6 @@ void hpfs_unlock_inode(struct inode *i)
 	}
 }
 
-void hpfs_lock_2inodes(struct inode *i1, struct inode *i2)
-{
-	if (!i2 || i1 == i2) {
-		hpfs_lock_inode(i1);
-	} else if (!i1) {
-		hpfs_lock_inode(i2);
-	} else {
-		struct hpfs_inode_info *hpfs_i1 = hpfs_i(i1);
-		struct hpfs_inode_info *hpfs_i2 = hpfs_i(i2);
-		if (i1->i_ino < i2->i_ino) {
-			down(&hpfs_i1->i_sem);
-			down(&hpfs_i2->i_sem);
-		} else {
-			down(&hpfs_i2->i_sem);
-			down(&hpfs_i1->i_sem);
-		}
-	}
-}
-
-void hpfs_unlock_2inodes(struct inode *i1, struct inode *i2)
-{
-	/* order of up() doesn't matter here */
-	hpfs_unlock_inode(i1);
-	hpfs_unlock_inode(i2);
-}
-
-void hpfs_lock_3inodes(struct inode *i1, struct inode *i2, struct inode *i3)
-{
-	if (!i1) { hpfs_lock_2inodes(i2, i3); return; }
-	if (!i2) { hpfs_lock_2inodes(i1, i3); return; }
-	if (!i3) { hpfs_lock_2inodes(i1, i2); return; }
-	if (i1->i_ino < i2->i_ino && i1->i_ino < i3->i_ino) {
-		struct hpfs_inode_info *hpfs_i1 = hpfs_i(i1);
-		down(&hpfs_i1->i_sem);
-		hpfs_lock_2inodes(i2, i3);
-	} else if (i2->i_ino < i1->i_ino && i2->i_ino < i3->i_ino) {
-		struct hpfs_inode_info *hpfs_i2 = hpfs_i(i2);
-		down(&hpfs_i2->i_sem);
-		hpfs_lock_2inodes(i1, i3);
-	} else if (i3->i_ino < i1->i_ino && i3->i_ino < i2->i_ino) {
-		struct hpfs_inode_info *hpfs_i3 = hpfs_i(i3);
-		down(&hpfs_i3->i_sem);
-		hpfs_lock_2inodes(i1, i2);
-	} else if (i1->i_ino != i2->i_ino) hpfs_lock_2inodes(i1, i2);
-	else hpfs_lock_2inodes(i1, i3);
-}
-		
-void hpfs_unlock_3inodes(struct inode *i1, struct inode *i2, struct inode *i3)
-{
-	if (!i1) { hpfs_unlock_2inodes(i2, i3); return; }
-	if (!i2) { hpfs_unlock_2inodes(i1, i3); return; }
-	if (!i3) { hpfs_unlock_2inodes(i1, i2); return; }
-	if (i1->i_ino < i2->i_ino && i1->i_ino < i3->i_ino) {
-		struct hpfs_inode_info *hpfs_i1 = hpfs_i(i1);
-		hpfs_unlock_2inodes(i2, i3);
-		up(&hpfs_i1->i_sem);
-	} else if (i2->i_ino < i1->i_ino && i2->i_ino < i3->i_ino) {
-		struct hpfs_inode_info *hpfs_i2 = hpfs_i(i2);
-		hpfs_unlock_2inodes(i1, i3);
-		up(&hpfs_i2->i_sem);
-	} else if (i3->i_ino < i1->i_ino && i3->i_ino < i2->i_ino) {
-		struct hpfs_inode_info *hpfs_i3 = hpfs_i(i3);
-		hpfs_unlock_2inodes(i1, i2);
-		up(&hpfs_i3->i_sem);
-	} else if (i1->i_ino != i2->i_ino) hpfs_unlock_2inodes(i1, i2);
-	else hpfs_unlock_2inodes(i1, i3);
-}
-
 /* Map a sector into a buffer and return pointers to it and to the buffer. */
 
 void *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head **bhp,
--- diff/fs/hpfs/hpfs_fn.h	2003-10-09 09:47:34.000000000 +0100
+++ source/fs/hpfs/hpfs_fn.h	2004-03-09 11:51:51.000000000 +0000
@@ -196,10 +196,6 @@ void hpfs_lock_iget(struct super_block *
 void hpfs_unlock_iget(struct super_block *);
 void hpfs_lock_inode(struct inode *);
 void hpfs_unlock_inode(struct inode *);
-void hpfs_lock_2inodes(struct inode *, struct inode *);
-void hpfs_unlock_2inodes(struct inode *, struct inode *);
-void hpfs_lock_3inodes(struct inode *, struct inode *, struct inode *);
-void hpfs_unlock_3inodes(struct inode *, struct inode *, struct inode *);
 void *hpfs_map_sector(struct super_block *, unsigned, struct buffer_head **, int);
 void *hpfs_get_sector(struct super_block *, unsigned, struct buffer_head **);
 void *hpfs_map_4sectors(struct super_block *, unsigned, struct quad_buffer_head *, int);
--- diff/fs/hpfs/namei.c	2003-10-09 09:47:17.000000000 +0100
+++ source/fs/hpfs/namei.c	2004-03-09 11:51:51.000000000 +0000
@@ -28,8 +28,13 @@ int hpfs_mkdir(struct inode *dir, struct
 	int err;
 	if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err;
 	lock_kernel();
-	if (!(fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh))) goto bail;
-	if (!(dnode = hpfs_alloc_dnode(dir->i_sb, fno, &dno, &qbh0, 1))) goto bail1;
+	err = -ENOSPC;
+	fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh);
+	if (!fnode)
+		goto bail;
+	dnode = hpfs_alloc_dnode(dir->i_sb, fno, &dno, &qbh0, 1);
+	if (!dnode)
+		goto bail1;
 	memset(&dee, 0, sizeof dee);
 	dee.directory = 1;
 	if (!(mode & 0222)) dee.read_only = 1;
@@ -39,15 +44,11 @@ int hpfs_mkdir(struct inode *dir, struct
 	dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds());
 	hpfs_lock_inode(dir);
 	r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
-	if (r == 1) goto bail2;
+	if (r == 1)
+		goto bail2;
 	if (r == -1) {
-		brelse(bh);
-		hpfs_brelse4(&qbh0);
-		hpfs_free_sectors(dir->i_sb, fno, 1);
-		hpfs_free_dnode(dir->i_sb, dno);
-		hpfs_unlock_inode(dir);
-		unlock_kernel();
-		return -EEXIST;
+		err = -EEXIST;
+		goto bail2;
 	}
 	fnode->len = len;
 	memcpy(fnode->name, name, len > 15 ? 15 : len);
@@ -103,7 +104,7 @@ bail1:
 	hpfs_free_sectors(dir->i_sb, fno, 1);
 bail:
 	unlock_kernel();
-	return -ENOSPC;
+	return err;
 }
 
 int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd)
@@ -120,7 +121,10 @@ int hpfs_create(struct inode *dir, struc
 	if ((err = hpfs_chk_name((char *)name, &len)))
 		return err==-ENOENT ? -EINVAL : err;
 	lock_kernel();
-	if (!(fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh))) goto bail;
+	err = -ENOSPC;
+	fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh);
+	if (!fnode)
+		goto bail;
 	memset(&dee, 0, sizeof dee);
 	if (!(mode & 0222)) dee.read_only = 1;
 	dee.archive = 1;
@@ -129,13 +133,11 @@ int hpfs_create(struct inode *dir, struc
 	dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds());
 	hpfs_lock_inode(dir);
 	r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
-	if (r == 1) goto bail1;
+	if (r == 1)
+		goto bail1;
 	if (r == -1) {
-		brelse(bh);
-		hpfs_free_sectors(dir->i_sb, fno, 1);
-		hpfs_unlock_inode(dir);
-		unlock_kernel();
-		return -EEXIST;
+		err = -EEXIST;
+		goto bail1;
 	}
 	fnode->len = len;
 	memcpy(fnode->name, name, len > 15 ? 15 : len);
@@ -178,7 +180,7 @@ bail1:
 	hpfs_unlock_inode(dir);
 bail:
 	unlock_kernel();
-	return -ENOSPC;
+	return err;
 }
 
 int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
@@ -197,7 +199,10 @@ int hpfs_mknod(struct inode *dir, struct
 	if (!new_valid_dev(rdev))
 		return -EINVAL;
 	lock_kernel();
-	if (!(fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh))) goto bail;
+	err = -ENOSPC;
+	fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh);
+	if (!fnode)
+		goto bail;
 	memset(&dee, 0, sizeof dee);
 	if (!(mode & 0222)) dee.read_only = 1;
 	dee.archive = 1;
@@ -206,13 +211,11 @@ int hpfs_mknod(struct inode *dir, struct
 	dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds());
 	hpfs_lock_inode(dir);
 	r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
-	if (r == 1) goto bail1;
+	if (r == 1)
+		goto bail1;
 	if (r == -1) {
-		brelse(bh);
-		hpfs_free_sectors(dir->i_sb, fno, 1);
-		hpfs_unlock_inode(dir);
-		unlock_kernel();
-		return -EEXIST;
+		err = -EEXIST;
+		goto bail1;
 	}
 	fnode->len = len;
 	memcpy(fnode->name, name, len > 15 ? 15 : len);
@@ -248,7 +251,7 @@ bail1:
 	hpfs_unlock_inode(dir);
 bail:
 	unlock_kernel();
-	return -ENOSPC;
+	return err;
 }
 
 extern struct address_space_operations hpfs_symlink_aops;
@@ -270,7 +273,10 @@ int hpfs_symlink(struct inode *dir, stru
 		unlock_kernel();
 		return -EPERM;
 	}
-	if (!(fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh))) goto bail;
+	err = -ENOSPC;
+	fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh);
+	if (!fnode)
+		goto bail;
 	memset(&dee, 0, sizeof dee);
 	dee.archive = 1;
 	dee.hidden = name[0] == '.';
@@ -278,13 +284,11 @@ int hpfs_symlink(struct inode *dir, stru
 	dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds());
 	hpfs_lock_inode(dir);
 	r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
-	if (r == 1) goto bail1;
+	if (r == 1)
+		goto bail1;
 	if (r == -1) {
-		brelse(bh);
-		hpfs_free_sectors(dir->i_sb, fno, 1);
-		hpfs_unlock_inode(dir);
-		unlock_kernel();
-		return -EEXIST;
+		err = -EEXIST;
+		goto bail1;
 	}
 	fnode->len = len;
 	memcpy(fnode->name, name, len > 15 ? 15 : len);
@@ -326,7 +330,7 @@ bail1:
 	hpfs_unlock_inode(dir);
 bail:
 	unlock_kernel();
-	return -ENOSPC;
+	return err;
 }
 
 int hpfs_unlink(struct inode *dir, struct dentry *dentry)
@@ -340,39 +344,41 @@ int hpfs_unlink(struct inode *dir, struc
 	fnode_secno fno;
 	int r;
 	int rep = 0;
+	int err;
 
 	lock_kernel();
 	hpfs_adjust_length((char *)name, &len);
 again:
-	hpfs_lock_2inodes(dir, inode);
-	if (!(de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh))) {
-		hpfs_unlock_2inodes(dir, inode);
-		unlock_kernel();
-		return -ENOENT;
-	}
-	if (de->first) {
-		hpfs_brelse4(&qbh);
-		hpfs_unlock_2inodes(dir, inode);
-		unlock_kernel();
-		return -EPERM;
-	}
-	if (de->directory) {
-		hpfs_brelse4(&qbh);
-		hpfs_unlock_2inodes(dir, inode);
-		unlock_kernel();
-		return -EISDIR;
-	}
+	hpfs_lock_inode(dir);
+	hpfs_lock_inode(inode);
+	de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh);
+	err = -ENOENT;
+	if (!de)
+		goto out;
+
+	err = -EPERM;
+	if (de->first)
+		goto out1;
+
+	err = -EISDIR;
+	if (de->directory)
+		goto out1;
+
 	fno = de->fnode;
-	if ((r = hpfs_remove_dirent(dir, dno, de, &qbh, 1)) == 1) hpfs_error(dir->i_sb, "there was error when removing dirent");
-	if (r != 2) {
-		inode->i_nlink--;
-		hpfs_unlock_2inodes(dir, inode);
-	} else {	/* no space for deleting, try to truncate file */
-		struct iattr newattrs;
-		int err;
-		hpfs_unlock_2inodes(dir, inode);
-		if (rep)
-			goto ret;
+	r = hpfs_remove_dirent(dir, dno, de, &qbh, 1);
+	switch (r) {
+	case 1:
+		hpfs_error(dir->i_sb, "there was error when removing dirent");
+		err = -EFSERROR;
+		break;
+	case 2:		/* no space for deleting, try to truncate file */
+
+		err = -ENOSPC;
+		if (rep++)
+			break;
+
+		hpfs_unlock_inode(inode);
+		hpfs_unlock_inode(dir);
 		d_drop(dentry);
 		spin_lock(&dentry->d_lock);
 		if (atomic_read(&dentry->d_count) > 1 ||
@@ -381,22 +387,32 @@ again:
 		    get_write_access(inode)) {
 			spin_unlock(&dentry->d_lock);
 			d_rehash(dentry);
-			goto ret;
+		} else {
+			struct iattr newattrs;
+			spin_unlock(&dentry->d_lock);
+			/*printk("HPFS: truncating file before delete.\n");*/
+			newattrs.ia_size = 0;
+			newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
+			err = notify_change(dentry, &newattrs);
+			put_write_access(inode);
+			if (!err)
+				goto again;
 		}
-		spin_unlock(&dentry->d_lock);
-		/*printk("HPFS: truncating file before delete.\n");*/
-		newattrs.ia_size = 0;
-		newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
-		err = notify_change(dentry, &newattrs);
-		put_write_access(inode);
-		if (err)
-			goto ret;
-		rep = 1;
-		goto again;
+		unlock_kernel();
+		return -ENOSPC;
+	default:
+		inode->i_nlink--;
+		err = 0;
 	}
-ret:
+	goto out;
+
+out1:
+	hpfs_brelse4(&qbh);
+out:
+	hpfs_unlock_inode(inode);
+	hpfs_unlock_inode(dir);
 	unlock_kernel();
-	return r == 2 ? -ENOSPC : r == 1 ? -EFSERROR : 0;
+	return err;
 }
 
 int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
@@ -409,44 +425,54 @@ int hpfs_rmdir(struct inode *dir, struct
 	dnode_secno dno;
 	fnode_secno fno;
 	int n_items = 0;
+	int err;
 	int r;
+
 	hpfs_adjust_length((char *)name, &len);
 	lock_kernel();
-	hpfs_lock_2inodes(dir, inode);
-	if (!(de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh))) {
-		hpfs_unlock_2inodes(dir, inode);
-		unlock_kernel();
-		return -ENOENT;
-	}	
-	if (de->first) {
-		hpfs_brelse4(&qbh);
-		hpfs_unlock_2inodes(dir, inode);
-		unlock_kernel();
-		return -EPERM;
-	}
-	if (!de->directory) {
-		hpfs_brelse4(&qbh);
-		hpfs_unlock_2inodes(dir, inode);
-		unlock_kernel();
-		return -ENOTDIR;
-	}
+	hpfs_lock_inode(dir);
+	hpfs_lock_inode(inode);
+	err = -ENOENT;
+	de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh);
+	if (!de)
+		goto out;
+
+	err = -EPERM;
+	if (de->first)
+		goto out1;
+
+	err = -ENOTDIR;
+	if (!de->directory)
+		goto out1;
+
 	hpfs_count_dnodes(dir->i_sb, hpfs_i(inode)->i_dno, NULL, NULL, &n_items);
-	if (n_items) {
-		hpfs_brelse4(&qbh);
-		hpfs_unlock_2inodes(dir, inode);
-		unlock_kernel();
-		return -ENOTEMPTY;
-	}
+	err = -ENOTEMPTY;
+	if (n_items)
+		goto out1;
+
 	fno = de->fnode;
-	if ((r = hpfs_remove_dirent(dir, dno, de, &qbh, 1)) == 1)
+	r = hpfs_remove_dirent(dir, dno, de, &qbh, 1);
+	switch (r) {
+	case 1:
 		hpfs_error(dir->i_sb, "there was error when removing dirent");
-	if (r != 2) {
+		err = -EFSERROR;
+		break;
+	case 2:
+		err = -ENOSPC;
+		break;
+	default:
 		dir->i_nlink--;
 		inode->i_nlink = 0;
-		hpfs_unlock_2inodes(dir, inode);
-	} else hpfs_unlock_2inodes(dir, inode);
+		err = 0;
+	}
+	goto out;
+out1:
+	hpfs_brelse4(&qbh);
+out:
+	hpfs_unlock_inode(inode);
+	hpfs_unlock_inode(dir);
 	unlock_kernel();
-	return r == 2 ? -ENOSPC : r == 1 ? -EFSERROR : 0;
+	return err;
 }
 
 int hpfs_symlink_readpage(struct file *file, struct page *page)
@@ -501,7 +527,10 @@ int hpfs_rename(struct inode *old_dir, s
 	hpfs_adjust_length((char *)old_name, &old_len);
 
 	lock_kernel();
-	hpfs_lock_3inodes(old_dir, new_dir, i);
+	hpfs_lock_inode(old_dir);
+	if (new_dir != old_dir)
+		hpfs_lock_inode(new_dir);
+	hpfs_lock_inode(i);
 	
 	/* Erm? Moving over the empty non-busy directory is perfectly legal */
 	if (new_inode && S_ISDIR(new_inode->i_mode)) {
@@ -580,7 +609,10 @@ int hpfs_rename(struct inode *old_dir, s
 	hpfs_i(i)->i_conv = hpfs_sb(i->i_sb)->sb_conv;
 	hpfs_decide_conv(i, (char *)new_name, new_len);
 	end1:
-	hpfs_unlock_3inodes(old_dir, new_dir, i);
+	hpfs_unlock_inode(i);
+	if (old_dir != new_dir)
+		hpfs_unlock_inode(new_dir);
+	hpfs_unlock_inode(old_dir);
 	unlock_kernel();
 	return err;
 }
--- diff/fs/hpfs/super.c	2003-10-09 09:47:34.000000000 +0100
+++ source/fs/hpfs/super.c	2004-03-09 11:51:51.000000000 +0000
@@ -448,6 +448,7 @@ static int hpfs_fill_super(struct super_
 	struct hpfs_super_block *superblock;
 	struct hpfs_spare_block *spareblock;
 	struct hpfs_sb_info *sbi;
+	struct inode *root;
 
 	uid_t uid;
 	gid_t gid;
@@ -613,10 +614,11 @@ static int hpfs_fill_super(struct super_
 	brelse(bh0);
 
 	hpfs_lock_iget(s, 1);
-	s->s_root = d_alloc_root(iget(s, sbi->sb_root));
+	root = iget(s, sbi->sb_root);
 	hpfs_unlock_iget(s);
-	if (!s->s_root || !s->s_root->d_inode) {
-		printk("HPFS: iget failed. Why???\n");
+	s->s_root = d_alloc_root(root);
+	if (!s->s_root) {
+		iput(root);
 		goto bail0;
 	}
 	hpfs_set_dentry_operations(s->s_root);
@@ -627,22 +629,24 @@ static int hpfs_fill_super(struct super_
 
 	root_dno = hpfs_fnode_dno(s, sbi->sb_root);
 	if (root_dno)
-		de = map_dirent(s->s_root->d_inode, root_dno, "\001\001", 2, NULL, &qbh);
-	if (!root_dno || !de) hpfs_error(s, "unable to find root dir");
+		de = map_dirent(root, root_dno, "\001\001", 2, NULL, &qbh);
+	if (!de)
+		hpfs_error(s, "unable to find root dir");
 	else {
-		s->s_root->d_inode->i_atime.tv_sec = local_to_gmt(s, de->read_date);
-		s->s_root->d_inode->i_atime.tv_nsec = 0;
-		s->s_root->d_inode->i_mtime.tv_sec = local_to_gmt(s, de->write_date);
-		s->s_root->d_inode->i_mtime.tv_nsec = 0;
-		s->s_root->d_inode->i_ctime.tv_sec = local_to_gmt(s, de->creation_date);
-		s->s_root->d_inode->i_ctime.tv_nsec = 0;
-		hpfs_i(s->s_root->d_inode)->i_ea_size = de->ea_size;
-		hpfs_i(s->s_root->d_inode)->i_parent_dir = s->s_root->d_inode->i_ino;
-		if (s->s_root->d_inode->i_size == -1) s->s_root->d_inode->i_size = 2048;
-		if (s->s_root->d_inode->i_blocks == -1) s->s_root->d_inode->i_blocks = 5;
+		root->i_atime.tv_sec = local_to_gmt(s, de->read_date);
+		root->i_atime.tv_nsec = 0;
+		root->i_mtime.tv_sec = local_to_gmt(s, de->write_date);
+		root->i_mtime.tv_nsec = 0;
+		root->i_ctime.tv_sec = local_to_gmt(s, de->creation_date);
+		root->i_ctime.tv_nsec = 0;
+		hpfs_i(root)->i_ea_size = de->ea_size;
+		hpfs_i(root)->i_parent_dir = root->i_ino;
+		if (root->i_size == -1)
+			root->i_size = 2048;
+		if (root->i_blocks == -1)
+			root->i_blocks = 5;
+		hpfs_brelse4(&qbh);
 	}
-	if (de) hpfs_brelse4(&qbh);
-
 	return 0;
 
 bail4:	brelse(bh2);
--- diff/fs/hugetlbfs/inode.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/hugetlbfs/inode.c	2004-03-09 11:51:51.000000000 +0000
@@ -194,6 +194,7 @@ static void hugetlbfs_delete_inode(struc
 
 	hlist_del_init(&inode->i_hash);
 	list_del_init(&inode->i_list);
+	list_del_init(&inode->i_sb_list);
 	inode->i_state |= I_FREEING;
 	inodes_stat.nr_inodes--;
 	spin_unlock(&inode_lock);
@@ -236,6 +237,7 @@ static void hugetlbfs_forget_inode(struc
 	hlist_del_init(&inode->i_hash);
 out_truncate:
 	list_del_init(&inode->i_list);
+	list_del_init(&inode->i_sb_list);
 	inode->i_state |= I_FREEING;
 	inodes_stat.nr_inodes--;
 	spin_unlock(&inode_lock);
--- diff/fs/inode.c	2004-03-04 11:41:49.000000000 +0000
+++ source/fs/inode.c	2004-03-09 11:51:51.000000000 +0000
@@ -20,6 +20,7 @@
 #include <linux/security.h>
 #include <linux/pagemap.h>
 #include <linux/cdev.h>
+#include <linux/ext3_fs_i.h>
 
 /*
  * This is needed for the following functions:
@@ -183,6 +184,7 @@ void inode_init_once(struct inode *inode
 	INIT_LIST_HEAD(&inode->i_dentry);
 	INIT_LIST_HEAD(&inode->i_devices);
 	sema_init(&inode->i_sem, 1);
+	init_rwsem(&inode->i_alloc_sem);
 	INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC);
 	spin_lock_init(&inode->i_data.page_lock);
 	init_MUTEX(&inode->i_data.i_shared_sem);
@@ -193,6 +195,7 @@ void inode_init_once(struct inode *inode
 	INIT_LIST_HEAD(&inode->i_data.i_mmap_shared);
 	spin_lock_init(&inode->i_lock);
 	i_size_ordered_init(inode);
+	init_rwsem(&inode->i_data.wb_rwsema);
 }
 
 EXPORT_SYMBOL(inode_init_once);
@@ -285,7 +288,7 @@ static void dispose_list(struct list_hea
 /*
  * Invalidate all inodes for a device.
  */
-static int invalidate_list(struct list_head *head, struct super_block * sb, struct list_head * dispose)
+static int invalidate_list(struct list_head *head, struct list_head *dispose)
 {
 	struct list_head *next;
 	int busy = 0, count = 0;
@@ -298,13 +301,12 @@ static int invalidate_list(struct list_h
 		next = next->next;
 		if (tmp == head)
 			break;
-		inode = list_entry(tmp, struct inode, i_list);
-		if (inode->i_sb != sb)
-			continue;
+		inode = list_entry(tmp, struct inode, i_sb_list);
 		invalidate_inode_buffers(inode);
 		if (!atomic_read(&inode->i_count)) {
 			hlist_del_init(&inode->i_hash);
 			list_del(&inode->i_list);
+			list_del(&inode->i_sb_list);
 			list_add(&inode->i_list, dispose);
 			inode->i_state |= I_FREEING;
 			count++;
@@ -340,10 +342,7 @@ int invalidate_inodes(struct super_block
 
 	down(&iprune_sem);
 	spin_lock(&inode_lock);
-	busy = invalidate_list(&inode_in_use, sb, &throw_away);
-	busy |= invalidate_list(&inode_unused, sb, &throw_away);
-	busy |= invalidate_list(&sb->s_dirty, sb, &throw_away);
-	busy |= invalidate_list(&sb->s_io, sb, &throw_away);
+	busy = invalidate_list(&sb->s_inodes, &throw_away);
 	spin_unlock(&inode_lock);
 
 	dispose_list(&throw_away);
@@ -443,6 +442,7 @@ static void prune_icache(int nr_to_scan)
 				continue;
 		}
 		hlist_del_init(&inode->i_hash);
+		list_del_init(&inode->i_sb_list);
 		list_move(&inode->i_list, &freeable);
 		inode->i_state |= I_FREEING;
 		nr_pruned++;
@@ -553,6 +553,7 @@ struct inode *new_inode(struct super_blo
 		spin_lock(&inode_lock);
 		inodes_stat.nr_inodes++;
 		list_add(&inode->i_list, &inode_in_use);
+		list_add(&inode->i_sb_list, &sb->s_inodes);
 		inode->i_ino = ++last_ino;
 		inode->i_state = 0;
 		spin_unlock(&inode_lock);
@@ -601,6 +602,7 @@ static struct inode * get_new_inode(stru
 
 			inodes_stat.nr_inodes++;
 			list_add(&inode->i_list, &inode_in_use);
+			list_add(&inode->i_sb_list, &sb->s_inodes);
 			hlist_add_head(&inode->i_hash, head);
 			inode->i_state = I_LOCK|I_NEW;
 			spin_unlock(&inode_lock);
@@ -649,6 +651,7 @@ static struct inode * get_new_inode_fast
 			inode->i_ino = ino;
 			inodes_stat.nr_inodes++;
 			list_add(&inode->i_list, &inode_in_use);
+			list_add(&inode->i_sb_list, &sb->s_inodes);
 			hlist_add_head(&inode->i_hash, head);
 			inode->i_state = I_LOCK|I_NEW;
 			spin_unlock(&inode_lock);
@@ -984,6 +987,7 @@ void generic_delete_inode(struct inode *
 	struct super_operations *op = inode->i_sb->s_op;
 
 	list_del_init(&inode->i_list);
+	list_del_init(&inode->i_sb_list);
 	inode->i_state|=I_FREEING;
 	inodes_stat.nr_inodes--;
 	spin_unlock(&inode_lock);
@@ -1018,6 +1022,14 @@ static void generic_forget_inode(struct 
 
 	if (!hlist_unhashed(&inode->i_hash)) {
 		if (!(inode->i_state & (I_DIRTY|I_LOCK))) {
+			if (!strcmp(inode->i_sb->s_type->name, "ext3")) {
+				struct ext3_inode_info *ext3_i;
+				ext3_i = container_of(inode,
+						struct ext3_inode_info,
+						vfs_inode);
+				if (!list_empty(&ext3_i->i_orphan))
+					WARN_ON(1);
+			}
 			list_del(&inode->i_list);
 			list_add(&inode->i_list, &inode_unused);
 		}
@@ -1031,6 +1043,7 @@ static void generic_forget_inode(struct 
 		hlist_del_init(&inode->i_hash);
 	}
 	list_del_init(&inode->i_list);
+	list_del_init(&inode->i_sb_list);
 	inode->i_state|=I_FREEING;
 	inodes_stat.nr_inodes--;
 	spin_unlock(&inode_lock);
@@ -1064,7 +1077,7 @@ static void generic_drop_inode(struct in
  * held, and the drop function is supposed to release
  * the lock!
  */
-static inline void iput_final(struct inode *inode)
+static void iput_final(struct inode *inode)
 {
 	struct super_operations *op = inode->i_sb->s_op;
 	void (*drop)(struct inode *) = generic_drop_inode;
@@ -1178,6 +1191,8 @@ void inode_update_time(struct inode *ino
 	struct timespec now;
 	int sync_it = 0;
 
+	if (IS_NOCMTIME(inode))
+		return;
 	if (IS_RDONLY(inode))
 		return;
 
@@ -1214,44 +1229,27 @@ EXPORT_SYMBOL(inode_needs_sync);
  */
 #ifdef CONFIG_QUOTA
 
-/* Functions back in dquot.c */
-void put_dquot_list(struct list_head *);
+/* Function back in dquot.c */
 int remove_inode_dquot_ref(struct inode *, int, struct list_head *);
 
-void remove_dquot_ref(struct super_block *sb, int type)
+void remove_dquot_ref(struct super_block *sb, int type,
+			struct list_head *tofree_head)
 {
 	struct inode *inode;
-	struct list_head *act_head;
-	LIST_HEAD(tofree_head);
 
 	if (!sb->dq_op)
 		return;	/* nothing to do */
 	spin_lock(&inode_lock);	/* This lock is for inodes code */
-	/* We don't have to lock against quota code - test IS_QUOTAINIT is just for speedup... */
- 
-	list_for_each(act_head, &inode_in_use) {
-		inode = list_entry(act_head, struct inode, i_list);
-		if (inode->i_sb == sb && IS_QUOTAINIT(inode))
-			remove_inode_dquot_ref(inode, type, &tofree_head);
-	}
-	list_for_each(act_head, &inode_unused) {
-		inode = list_entry(act_head, struct inode, i_list);
-		if (inode->i_sb == sb && IS_QUOTAINIT(inode))
-			remove_inode_dquot_ref(inode, type, &tofree_head);
-	}
-	list_for_each(act_head, &sb->s_dirty) {
-		inode = list_entry(act_head, struct inode, i_list);
-		if (IS_QUOTAINIT(inode))
-			remove_inode_dquot_ref(inode, type, &tofree_head);
-	}
-	list_for_each(act_head, &sb->s_io) {
-		inode = list_entry(act_head, struct inode, i_list);
+	/*
+	 * We don't have to lock against quota code - test IS_QUOTAINIT is
+	 * just for speedup...
+	 */
+
+	list_for_each_entry(inode, &sb->s_inodes, i_sb_list)
 		if (IS_QUOTAINIT(inode))
-			remove_inode_dquot_ref(inode, type, &tofree_head);
-	}
-	spin_unlock(&inode_lock);
+			remove_inode_dquot_ref(inode, type, tofree_head);
 
-	put_dquot_list(&tofree_head);
+	spin_unlock(&inode_lock);
 }
 
 #endif
--- diff/fs/jffs/inode-v23.c	2004-03-04 11:41:49.000000000 +0000
+++ source/fs/jffs/inode-v23.c	2004-03-09 11:51:51.000000000 +0000
@@ -70,6 +70,8 @@ static int jffs_fill_super(struct super_
 	struct inode *root_inode;
 	struct jffs_control *c;
 
+	sb->s_flags |= MS_NODIRATIME;
+
 	D1(printk(KERN_NOTICE "JFFS: Trying to mount device %s.\n",
 		  sb->s_id));
 
--- diff/fs/jffs2/super.c	2003-10-27 09:20:38.000000000 +0000
+++ source/fs/jffs2/super.c	2004-03-09 11:51:51.000000000 +0000
@@ -129,6 +129,7 @@ static struct super_block *jffs2_get_sb_
 		  mtd->index, mtd->name));
 
 	sb->s_op = &jffs2_super_operations;
+	sb->s_flags |= MS_NODIRATIME;
 
 	ret = jffs2_do_fill_super(sb, data, (flags&MS_VERBOSE)?1:0);
 
--- diff/fs/libfs.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/libfs.c	2004-03-09 11:51:51.000000000 +0000
@@ -155,7 +155,6 @@ int dcache_readdir(struct file * filp, v
 			}
 			spin_unlock(&dcache_lock);
 	}
-	update_atime(dentry->d_inode);
 	return 0;
 }
 
--- diff/fs/lockd/clntproc.c	2003-02-13 11:46:54.000000000 +0000
+++ source/fs/lockd/clntproc.c	2004-03-09 11:51:51.000000000 +0000
@@ -195,19 +195,6 @@ done:
 }
 
 /*
- * Wait while server is in grace period
- */
-static inline int
-nlmclnt_grace_wait(struct nlm_host *host)
-{
-	if (!host->h_reclaiming)
-		interruptible_sleep_on_timeout(&host->h_gracewait, 10*HZ);
-	else
-		interruptible_sleep_on(&host->h_gracewait);
-	return signalled()? -ERESTARTSYS : 0;
-}
-
-/*
  * Allocate an NLM RPC call struct
  */
 struct nlm_rqst *
@@ -456,7 +443,7 @@ nlmclnt_lock(struct nlm_rqst *req, struc
 		}
 		if (status < 0)
 			return status;
-	} while (resp->status == NLM_LCK_BLOCKED);
+	} while (resp->status == NLM_LCK_BLOCKED && req->a_args.block);
 
 	if (resp->status == NLM_LCK_GRANTED) {
 		fl->fl_u.nfs_fl.state = host->h_state;
--- diff/fs/lockd/host.c	2003-06-09 14:18:20.000000000 +0100
+++ source/fs/lockd/host.c	2004-03-09 11:51:51.000000000 +0000
@@ -188,14 +188,14 @@ nlm_bind_host(struct nlm_host *host)
 		}
 	} else {
 		xprt = xprt_create_proto(host->h_proto, &host->h_addr, NULL);
-		if (xprt == NULL)
+		if (IS_ERR(xprt))
 			goto forgetit;
 
 		xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout);
 
 		clnt = rpc_create_client(xprt, host->h_name, &nlm_program,
 					host->h_version, host->h_authflavor);
-		if (clnt == NULL) {
+		if (IS_ERR(clnt)) {
 			xprt_destroy(xprt);
 			goto forgetit;
 		}
--- diff/fs/lockd/mon.c	2003-06-09 14:18:20.000000000 +0100
+++ source/fs/lockd/mon.c	2004-03-09 11:51:51.000000000 +0000
@@ -36,10 +36,11 @@ nsm_mon_unmon(struct nlm_host *host, u32
 	int		status;
 	struct nsm_args	args;
 
-	status = -EACCES;
 	clnt = nsm_create();
-	if (!clnt)
+	if (IS_ERR(clnt)) {
+		status = PTR_ERR(clnt);
 		goto out;
+	}
 
 	args.addr = host->h_addr.sin_addr.s_addr;
 	args.proto= (host->h_proto<<1) | host->h_server;
@@ -104,7 +105,7 @@ static struct rpc_clnt *
 nsm_create(void)
 {
 	struct rpc_xprt		*xprt;
-	struct rpc_clnt		*clnt = NULL;
+	struct rpc_clnt		*clnt;
 	struct sockaddr_in	sin;
 
 	sin.sin_family = AF_INET;
@@ -112,24 +113,23 @@ nsm_create(void)
 	sin.sin_port = 0;
 
 	xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL);
-	if (!xprt)
-		goto out;
+	if (IS_ERR(xprt))
+		return (struct rpc_clnt *)xprt;
 
 	clnt = rpc_create_client(xprt, "localhost",
 				&nsm_program, SM_VERSION,
 				RPC_AUTH_NULL);
-	if (!clnt)
+	if (IS_ERR(clnt))
 		goto out_destroy;
 	clnt->cl_softrtry = 1;
 	clnt->cl_chatty   = 1;
 	clnt->cl_oneshot  = 1;
 	xprt->resvport = 1;	/* NSM requires a reserved port */
-out:
 	return clnt;
 
 out_destroy:
 	xprt_destroy(xprt);
-	goto out;
+	return clnt;
 }
 
 /*
--- diff/fs/lockd/svc4proc.c	2002-10-16 04:27:53.000000000 +0100
+++ source/fs/lockd/svc4proc.c	2004-03-09 11:51:51.000000000 +0000
@@ -453,6 +453,24 @@ nlm4svc_proc_sm_notify(struct svc_rqst *
 }
 
 /*
+ * client sent a GRANTED_RES, let's remove the associated block
+ */
+static int
+nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res  *argp,
+                                                void            *resp)
+{
+        if (!nlmsvc_ops)
+                return rpc_success;
+
+        dprintk("lockd: GRANTED_RES   called\n");
+
+        nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status);
+        return rpc_success;
+}
+
+
+
+/*
  * This is the generic lockd callback for async RPC calls
  */
 static u32
@@ -515,7 +533,6 @@ nlm4svc_callback_exit(struct rpc_task *t
 #define nlm4svc_proc_lock_res	nlm4svc_proc_null
 #define nlm4svc_proc_cancel_res	nlm4svc_proc_null
 #define nlm4svc_proc_unlock_res	nlm4svc_proc_null
-#define nlm4svc_proc_granted_res	nlm4svc_proc_null
 
 struct nlm_void			{ int dummy; };
 
@@ -548,7 +565,7 @@ struct svc_procedure		nlmsvc_procedures4
   PROC(lock_res,	lockres,	norep,		res,	void, 1),
   PROC(cancel_res,	cancelres,	norep,		res,	void, 1),
   PROC(unlock_res,	unlockres,	norep,		res,	void, 1),
-  PROC(granted_res,	grantedres,	norep,		res,	void, 1),
+  PROC(granted_res,	res,		norep,		res,	void, 1),
   /* statd callback */
   PROC(sm_notify,	reboot,		void,		reboot,	void, 1),
   PROC(none,		void,		void,		void,	void, 0),
--- diff/fs/lockd/svclock.c	2003-05-21 11:49:50.000000000 +0100
+++ source/fs/lockd/svclock.c	2004-03-09 11:51:51.000000000 +0000
@@ -64,7 +64,7 @@ nlmsvc_insert_block(struct nlm_block *bl
 	if (when != NLM_NEVER) {
 		if ((when += jiffies) == NLM_NEVER)
 			when ++;
-		while ((b = *bp) && time_before_eq(b->b_when,when))
+		while ((b = *bp) && time_before_eq(b->b_when,when) && b->b_when != NLM_NEVER)
 			bp = &b->b_next;
 	} else
 		while ((b = *bp))
@@ -143,14 +143,15 @@ static inline int nlm_cookie_match(struc
  * Find a block with a given NLM cookie.
  */
 static inline struct nlm_block *
-nlmsvc_find_block(struct nlm_cookie *cookie)
+nlmsvc_find_block(struct nlm_cookie *cookie,  struct sockaddr_in *sin)
 {
 	struct nlm_block *block;
 
 	for (block = nlm_blocked; block; block = block->b_next) {
 		dprintk("cookie: head of blocked queue %p, block %p\n", 
 			nlm_blocked, block);
-		if (nlm_cookie_match(&block->b_call.a_args.cookie,cookie))
+		if (nlm_cookie_match(&block->b_call.a_args.cookie,cookie)
+				&& nlm_cmp_addr(sin, &block->b_host->h_addr))
 			break;
 	}
 
@@ -566,12 +567,16 @@ nlmsvc_grant_callback(struct rpc_task *t
 	struct nlm_rqst		*call = (struct nlm_rqst *) task->tk_calldata;
 	struct nlm_block	*block;
 	unsigned long		timeout;
+	struct sockaddr_in	*peer_addr = RPC_PEERADDR(task->tk_client);
 
 	dprintk("lockd: GRANT_MSG RPC callback\n");
-	dprintk("callback: looking for cookie %x \n", 
-		*(unsigned int *)(call->a_args.cookie.data));
-	if (!(block = nlmsvc_find_block(&call->a_args.cookie))) {
-		dprintk("lockd: no block for cookie %x\n", *(u32 *)(call->a_args.cookie.data));
+	dprintk("callback: looking for cookie %x, host (%08x)\n",
+		*(unsigned int *)(call->a_args.cookie.data),
+		ntohl(peer_addr->sin_addr.s_addr));
+	if (!(block = nlmsvc_find_block(&call->a_args.cookie, peer_addr))) {
+		dprintk("lockd: no block for cookie %x, host (%08x)\n",
+			*(u32 *)(call->a_args.cookie.data),
+			ntohl(peer_addr->sin_addr.s_addr));
 		return;
 	}
 
@@ -600,18 +605,21 @@ nlmsvc_grant_callback(struct rpc_task *t
  * block.
  */
 void
-nlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status)
+nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status)
 {
 	struct nlm_block	*block;
 	struct nlm_file		*file;
 
-	if (!(block = nlmsvc_find_block(cookie)))
+	dprintk("grant_reply: looking for cookie %x, host (%08x), s=%d \n",
+		*(unsigned int *)(cookie->data),
+		ntohl(rqstp->rq_addr.sin_addr.s_addr), status);
+	if (!(block = nlmsvc_find_block(cookie, &rqstp->rq_addr)))
 		return;
 	file = block->b_file;
 
 	file->f_count++;
 	down(&file->f_sema);
-	if ((block = nlmsvc_find_block(cookie)) != NULL) {
+	if ((block = nlmsvc_find_block(cookie,&rqstp->rq_addr)) != NULL) {
 		if (status == NLM_LCK_DENIED_GRACE_PERIOD) {
 			/* Try again in a couple of seconds */
 			nlmsvc_insert_block(block, 10 * HZ);
--- diff/fs/lockd/svcproc.c	2002-10-16 04:28:28.000000000 +0100
+++ source/fs/lockd/svcproc.c	2004-03-09 11:51:51.000000000 +0000
@@ -479,6 +479,22 @@ nlmsvc_proc_sm_notify(struct svc_rqst *r
 }
 
 /*
+ * client sent a GRANTED_RES, let's remove the associated block
+ */
+static int
+nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res  *argp,
+                                                void            *resp)
+{
+	if (!nlmsvc_ops)
+		return rpc_success;
+
+	dprintk("lockd: GRANTED_RES   called\n");
+
+	nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status);
+	return rpc_success;
+}
+
+/*
  * This is the generic lockd callback for async RPC calls
  */
 static u32
@@ -541,7 +557,6 @@ nlmsvc_callback_exit(struct rpc_task *ta
 #define nlmsvc_proc_lock_res	nlmsvc_proc_null
 #define nlmsvc_proc_cancel_res	nlmsvc_proc_null
 #define nlmsvc_proc_unlock_res	nlmsvc_proc_null
-#define nlmsvc_proc_granted_res	nlmsvc_proc_null
 
 struct nlm_void			{ int dummy; };
 
@@ -576,7 +591,7 @@ struct svc_procedure		nlmsvc_procedures[
   PROC(lock_res,	lockres,	norep,		res,	void, 1),
   PROC(cancel_res,	cancelres,	norep,		res,	void, 1),
   PROC(unlock_res,	unlockres,	norep,		res,	void, 1),
-  PROC(granted_res,	grantedres,	norep,		res,	void, 1),
+  PROC(granted_res,	res,		norep,		res,	void, 1),
   /* statd callback */
   PROC(sm_notify,	reboot,		void,		reboot,	void, 1),
   PROC(none,		void,		void,		void,	void, 1),
--- diff/fs/minix/dir.c	2003-06-09 14:18:20.000000000 +0100
+++ source/fs/minix/dir.c	2004-03-09 11:51:51.000000000 +0000
@@ -127,7 +127,6 @@ static int minix_readdir(struct file * f
 
 done:
 	filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
-	update_atime(inode);
 	unlock_kernel();
 	return 0;
 }
--- diff/fs/namei.c	2004-03-04 11:41:49.000000000 +0000
+++ source/fs/namei.c	2004-03-09 11:51:51.000000000 +0000
@@ -571,7 +571,7 @@ fail:
  *
  * We expect 'base' to be positive and a directory.
  */
-int link_path_walk(const char * name, struct nameidata *nd)
+int fastcall link_path_walk(const char * name, struct nameidata *nd)
 {
 	struct path next;
 	struct inode *inode;
@@ -771,7 +771,7 @@ return_err:
 	return err;
 }
 
-int path_walk(const char * name, struct nameidata *nd)
+int fastcall path_walk(const char * name, struct nameidata *nd)
 {
 	current->total_link_count = 0;
 	return link_path_walk(name, nd);
@@ -858,7 +858,7 @@ walk_init_root(const char *name, struct 
 	return 1;
 }
 
-int path_lookup(const char *name, unsigned int flags, struct nameidata *nd)
+int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata *nd)
 {
 	nd->last_type = LAST_ROOT; /* if there are only slashes... */
 	nd->flags = flags;
@@ -971,7 +971,7 @@ access:
  * that namei follows links, while lnamei does not.
  * SMP-safe
  */
-int __user_walk(const char __user *name, unsigned flags, struct nameidata *nd)
+int fastcall __user_walk(const char __user *name, unsigned flags, struct nameidata *nd)
 {
 	char *tmp = getname(name);
 	int err = PTR_ERR(tmp);
--- diff/fs/namespace.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/namespace.c	2004-03-09 11:51:51.000000000 +0000
@@ -24,7 +24,15 @@
 #include <asm/uaccess.h>
 
 extern int __init init_rootfs(void);
+
+#ifdef CONFIG_SYSFS
 extern int __init sysfs_init(void);
+#else
+static inline int sysfs_init(void)
+{
+	return 0;
+}
+#endif
 
 /* spinlock for vfsmount related operations, inplace of dcache_lock */
 spinlock_t vfsmount_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
--- diff/fs/ncpfs/inode.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/ncpfs/inode.c	2004-03-09 11:51:51.000000000 +0000
@@ -479,6 +479,7 @@ static int ncp_fill_super(struct super_b
 	else
 		default_bufsize = 1024;
 
+	sb->s_flags |= MS_NODIRATIME;	/* probably even noatime */
 	sb->s_maxbytes = 0xFFFFFFFFU;
 	sb->s_blocksize = 1024;	/* Eh...  Is this correct? */
 	sb->s_blocksize_bits = 10;
--- diff/fs/nfs/dir.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/nfs/dir.c	2004-03-09 11:51:51.000000000 +0000
@@ -139,11 +139,13 @@ int nfs_readdir_filler(nfs_readdir_descr
 	struct file	*file = desc->file;
 	struct inode	*inode = file->f_dentry->d_inode;
 	struct rpc_cred	*cred = nfs_file_cred(file);
+	unsigned long	timestamp;
 	int		error;
 
 	dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index);
 
  again:
+	timestamp = jiffies;
 	error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, desc->entry->cookie, page,
 					  NFS_SERVER(inode)->dtsize, desc->plus);
 	if (error < 0) {
@@ -157,18 +159,21 @@ int nfs_readdir_filler(nfs_readdir_descr
 		goto error;
 	}
 	SetPageUptodate(page);
+	NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME;
 	/* Ensure consistent page alignment of the data.
 	 * Note: assumes we have exclusive access to this mapping either
 	 *	 throught inode->i_sem or some other mechanism.
 	 */
-	if (page->index == 0)
+	if (page->index == 0) {
 		invalidate_inode_pages(inode->i_mapping);
+		NFS_I(inode)->readdir_timestamp = timestamp;
+	}
 	unlock_page(page);
 	return 0;
  error:
 	SetPageError(page);
 	unlock_page(page);
-	invalidate_inode_pages(inode->i_mapping);
+	nfs_zap_caches(inode);
 	desc->error = error;
 	return -EIO;
 }
@@ -381,6 +386,7 @@ int uncached_readdir(nfs_readdir_descrip
 						page,
 						NFS_SERVER(inode)->dtsize,
 						desc->plus);
+	NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME;
 	desc->page = page;
 	desc->ptr = kmap(page);		/* matching kunmap in nfs_do_filldir */
 	if (desc->error >= 0) {
@@ -459,7 +465,15 @@ static int nfs_readdir(struct file *filp
 			}
 			res = 0;
 			break;
-		} else if (res < 0)
+		}
+		if (res == -ETOOSMALL && desc->plus) {
+			NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;
+			nfs_zap_caches(inode);
+			desc->plus = 0;
+			desc->entry->eof = 0;
+			continue;
+		}
+		if (res < 0)
 			break;
 
 		res = nfs_do_filldir(desc, dirent, filldir);
@@ -481,14 +495,19 @@ static int nfs_readdir(struct file *filp
  * In the case it has, we assume that the dentries are untrustworthy
  * and may need to be looked up again.
  */
-static inline
-int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
+static inline int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
 {
 	if (IS_ROOT(dentry))
 		return 1;
-	if (nfs_revalidate_inode(NFS_SERVER(dir), dir))
+	if ((NFS_FLAGS(dir) & NFS_INO_INVALID_ATTR) != 0
+			|| nfs_attribute_timeout(dir))
 		return 0;
-	return time_after(dentry->d_time, NFS_MTIME_UPDATE(dir));
+	return nfs_verify_change_attribute(dir, (unsigned long)dentry->d_fsdata);
+}
+
+static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf)
+{
+	dentry->d_fsdata = (void *)verf;
 }
 
 /*
@@ -528,9 +547,7 @@ int nfs_neg_need_reval(struct inode *dir
 	/* Don't revalidate a negative dentry if we're creating a new file */
 	if ((ndflags & LOOKUP_CREATE) && !(ndflags & LOOKUP_CONTINUE))
 		return 0;
-	if (!nfs_check_verifier(dir, dentry))
-		return 1;
-	return time_after(jiffies, dentry->d_time + NFS_ATTRTIMEO(dir));
+	return !nfs_check_verifier(dir, dentry);
 }
 
 /*
@@ -552,6 +569,7 @@ static int nfs_lookup_revalidate(struct 
 	int error;
 	struct nfs_fh fhandle;
 	struct nfs_fattr fattr;
+	unsigned long verifier;
 	int isopen = 0;
 
 	parent = dget_parent(dentry);
@@ -574,6 +592,9 @@ static int nfs_lookup_revalidate(struct 
 		goto out_bad;
 	}
 
+	/* Revalidate parent directory attribute cache */
+	nfs_revalidate_inode(NFS_SERVER(dir), dir);
+
 	/* Force a full look up iff the parent directory has changed */
 	if (nfs_check_verifier(dir, dentry)) {
 		if (nfs_lookup_verify_inode(inode, isopen))
@@ -581,6 +602,12 @@ static int nfs_lookup_revalidate(struct 
 		goto out_valid;
 	}
 
+	/*
+	 * Note: we're not holding inode->i_sem and so may be racing with
+	 * operations that change the directory. We therefore save the
+	 * change attribute *before* we do the RPC call.
+	 */
+	verifier = nfs_save_change_attribute(dir);
 	error = nfs_cached_lookup(dir, dentry, &fhandle, &fattr);
 	if (!error) {
 		if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0)
@@ -603,6 +630,7 @@ static int nfs_lookup_revalidate(struct 
 
  out_valid_renew:
 	nfs_renew_times(dentry);
+	nfs_set_verifier(dentry, verifier);
  out_valid:
 	unlock_kernel();
 	dput(parent);
@@ -638,6 +666,11 @@ static int nfs_dentry_delete(struct dent
 		/* Unhash it, so that ->d_iput() would be called */
 		return 1;
 	}
+	if (!(dentry->d_sb->s_flags & MS_ACTIVE)) {
+		/* Unhash it, so that ancestors of killed async unlink
+		 * files will be cleaned up during umount */
+		return 1;
+	}
 	return 0;
 
 }
@@ -693,6 +726,8 @@ static struct dentry *nfs_lookup(struct 
 	dentry->d_op = NFS_PROTO(dir)->dentry_ops;
 
 	lock_kernel();
+	/* Revalidate parent directory attribute cache */
+	nfs_revalidate_inode(NFS_SERVER(dir), dir);
 
 	/* If we're doing an exclusive create, optimize away the lookup */
 	if (nfs_is_exclusive_create(dir, nd))
@@ -715,6 +750,7 @@ no_entry:
 	error = 0;
 	d_add(dentry, inode);
 	nfs_renew_times(dentry);
+	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
 out_unlock:
 	unlock_kernel();
 out:
@@ -768,7 +804,15 @@ static struct dentry *nfs_atomic_lookup(
 
 	/* Open the file on the server */
 	lock_kernel();
-	inode = nfs4_atomic_open(dir, dentry, nd);
+	/* Revalidate parent directory attribute cache */
+	nfs_revalidate_inode(NFS_SERVER(dir), dir);
+
+	if (nd->intent.open.flags & O_CREAT) {
+		nfs_begin_data_update(dir);
+		inode = nfs4_atomic_open(dir, dentry, nd);
+		nfs_end_data_update(dir);
+	} else
+		inode = nfs4_atomic_open(dir, dentry, nd);
 	unlock_kernel();
 	if (IS_ERR(inode)) {
 		error = PTR_ERR(inode);
@@ -790,6 +834,7 @@ static struct dentry *nfs_atomic_lookup(
 no_entry:
 	d_add(dentry, inode);
 	nfs_renew_times(dentry);
+	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
 out:
 	BUG_ON(error > 0);
 	return ERR_PTR(error);
@@ -801,13 +846,16 @@ static int nfs_open_revalidate(struct de
 {
 	struct dentry *parent = NULL;
 	struct inode *inode = dentry->d_inode;
+	struct inode *dir;
+	unsigned long verifier;
 	int openflags, ret = 0;
 
 	/* NFS only supports OPEN for regular files */
 	if (inode && !S_ISREG(inode->i_mode))
 		goto no_open;
 	parent = dget_parent(dentry);
-	if (!is_atomic_open(parent->d_inode, nd))
+	dir = parent->d_inode;
+	if (!is_atomic_open(dir, nd))
 		goto no_open;
 	openflags = nd->intent.open.flags;
 	if (openflags & O_CREAT) {
@@ -821,8 +869,16 @@ static int nfs_open_revalidate(struct de
 	/* We can't create new files, or truncate existing ones here */
 	openflags &= ~(O_CREAT|O_TRUNC);
 
+	/*
+	 * Note: we're not holding inode->i_sem and so may be racing with
+	 * operations that change the directory. We therefore save the
+	 * change attribute *before* we do the RPC call.
+	 */
 	lock_kernel();
-	ret = nfs4_open_revalidate(parent->d_inode, dentry, openflags);
+	verifier = nfs_save_change_attribute(dir);
+	ret = nfs4_open_revalidate(dir, dentry, openflags);
+	if (!ret)
+		nfs_set_verifier(dentry, verifier);
 	unlock_kernel();
 out:
 	dput(parent);
@@ -869,15 +925,20 @@ int nfs_cached_lookup(struct inode *dir,
 	struct nfs_server *server;
 	struct nfs_entry entry;
 	struct page *page;
-	unsigned long timestamp = NFS_MTIME_UPDATE(dir);
+	unsigned long timestamp;
 	int res;
 
 	if (!NFS_USE_READDIRPLUS(dir))
 		return -ENOENT;
 	server = NFS_SERVER(dir);
-	if (server->flags & NFS_MOUNT_NOAC)
+	/* Don't use readdirplus unless the cache is stable */
+	if ((server->flags & NFS_MOUNT_NOAC) != 0
+			|| nfs_caches_unstable(dir)
+			|| nfs_attribute_timeout(dir))
+		return -ENOENT;
+	if ((NFS_FLAGS(dir) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA)) != 0)
 		return -ENOENT;
-	nfs_revalidate_inode(server, dir);
+	timestamp = NFS_I(dir)->readdir_timestamp;
 
 	entry.fh = fh;
 	entry.fattr = fattr;
@@ -931,9 +992,10 @@ static int nfs_instantiate(struct dentry
 	if (inode) {
 		d_instantiate(dentry, inode);
 		nfs_renew_times(dentry);
-		error = 0;
+		nfs_set_verifier(dentry, nfs_save_change_attribute(dentry->d_parent->d_inode));
+		return 0;
 	}
-	return error;
+	error = -ENOMEM;
 out_err:
 	d_drop(dentry);
 	return error;
@@ -969,11 +1031,13 @@ static int nfs_create(struct inode *dir,
 	 * does not pass the create flags.
 	 */
 	lock_kernel();
-	nfs_zap_caches(dir);
+	nfs_begin_data_update(dir);
 	inode = NFS_PROTO(dir)->create(dir, &dentry->d_name, &attr, open_flags);
+	nfs_end_data_update(dir);
 	if (!IS_ERR(inode)) {
 		d_instantiate(dentry, inode);
 		nfs_renew_times(dentry);
+		nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
 		error = 0;
 	} else {
 		error = PTR_ERR(inode);
@@ -1004,9 +1068,10 @@ nfs_mknod(struct inode *dir, struct dent
 	attr.ia_valid = ATTR_MODE;
 
 	lock_kernel();
-	nfs_zap_caches(dir);
+	nfs_begin_data_update(dir);
 	error = NFS_PROTO(dir)->mknod(dir, &dentry->d_name, &attr, rdev,
 					&fhandle, &fattr);
+	nfs_end_data_update(dir);
 	if (!error)
 		error = nfs_instantiate(dentry, &fhandle, &fattr);
 	else
@@ -1041,9 +1106,10 @@ static int nfs_mkdir(struct inode *dir, 
 	 */
 	d_drop(dentry);
 #endif
-	nfs_zap_caches(dir);
+	nfs_begin_data_update(dir);
 	error = NFS_PROTO(dir)->mkdir(dir, &dentry->d_name, &attr, &fhandle,
 					&fattr);
+	nfs_end_data_update(dir);
 	if (!error)
 		error = nfs_instantiate(dentry, &fhandle, &fattr);
 	else
@@ -1060,10 +1126,12 @@ static int nfs_rmdir(struct inode *dir, 
 		dir->i_ino, dentry->d_name.name);
 
 	lock_kernel();
-	nfs_zap_caches(dir);
+	nfs_begin_data_update(dir);
 	error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
-	if (!error)
+	/* Ensure the VFS deletes this inode */
+	if (error == 0 && dentry->d_inode != NULL)
 		dentry->d_inode->i_nlink = 0;
+	nfs_end_data_update(dir);
 	unlock_kernel();
 
 	return error;
@@ -1119,12 +1187,21 @@ dentry->d_parent->d_name.name, dentry->d
 			goto out;
 	} while(sdentry->d_inode != NULL); /* need negative lookup */
 
-	nfs_zap_caches(dir);
 	qsilly.name = silly;
 	qsilly.len  = strlen(silly);
-	error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, dir, &qsilly);
+	nfs_begin_data_update(dir);
+	if (dentry->d_inode) {
+		nfs_begin_data_update(dentry->d_inode);
+		error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
+				dir, &qsilly);
+		nfs_end_data_update(dentry->d_inode);
+	} else
+		error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
+				dir, &qsilly);
+	nfs_end_data_update(dir);
 	if (!error) {
 		nfs_renew_times(dentry);
+		nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
 		d_move(dentry, sdentry);
 		error = nfs_async_unlink(dentry);
  		/* If we return 0 we don't unlink */
@@ -1156,14 +1233,17 @@ static int nfs_safe_remove(struct dentry
 		goto out;
 	}
 
-	nfs_zap_caches(dir);
-	if (inode)
-		NFS_CACHEINV(inode);
-	error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
-	if (error < 0)
-		goto out;
-	if (inode)
-		inode->i_nlink--;
+	nfs_begin_data_update(dir);
+	if (inode != NULL) {
+		nfs_begin_data_update(inode);
+		error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
+		/* The VFS may want to delete this inode */
+		if (error == 0)
+			inode->i_nlink--;
+		nfs_end_data_update(inode);
+	} else
+		error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
+	nfs_end_data_update(dir);
 out:
 	return error;
 }
@@ -1198,9 +1278,10 @@ static int nfs_unlink(struct inode *dir,
 	spin_unlock(&dentry->d_lock);
 	spin_unlock(&dcache_lock);
 	error = nfs_safe_remove(dentry);
-	if (!error)
+	if (!error) {
 		nfs_renew_times(dentry);
-	else if (need_rehash)
+		nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+	} else if (need_rehash)
 		d_rehash(dentry);
 	unlock_kernel();
 	return error;
@@ -1247,9 +1328,10 @@ dentry->d_parent->d_name.name, dentry->d
 	qsymname.len  = strlen(symname);
 
 	lock_kernel();
-	nfs_zap_caches(dir);
+	nfs_begin_data_update(dir);
 	error = NFS_PROTO(dir)->symlink(dir, &dentry->d_name, &qsymname,
 					  &attr, &sym_fh, &sym_attr);
+	nfs_end_data_update(dir);
 	if (!error) {
 		error = nfs_instantiate(dentry, &sym_fh, &sym_attr);
 	} else {
@@ -1281,9 +1363,12 @@ nfs_link(struct dentry *old_dentry, stru
 	 */
 	lock_kernel();
 	d_drop(dentry);
-	nfs_zap_caches(dir);
-	NFS_CACHEINV(inode);
+
+	nfs_begin_data_update(dir);
+	nfs_begin_data_update(inode);
 	error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
+	nfs_end_data_update(inode);
+	nfs_end_data_update(dir);
 	unlock_kernel();
 	return error;
 }
@@ -1388,16 +1473,23 @@ go_ahead:
 	if (new_inode)
 		d_delete(new_dentry);
 
-	nfs_zap_caches(new_dir);
-	nfs_zap_caches(old_dir);
+	nfs_begin_data_update(old_dir);
+	nfs_begin_data_update(new_dir);
+	nfs_begin_data_update(old_inode);
 	error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
 					   new_dir, &new_dentry->d_name);
+	nfs_end_data_update(old_inode);
+	nfs_end_data_update(new_dir);
+	nfs_end_data_update(old_dir);
 out:
 	if (rehash)
 		d_rehash(rehash);
-	if (!error && !S_ISDIR(old_inode->i_mode))
-		d_move(old_dentry, new_dentry);
-	nfs_renew_times(new_dentry);
+	if (!error) {
+		if (!S_ISDIR(old_inode->i_mode))
+			d_move(old_dentry, new_dentry);
+		nfs_renew_times(new_dentry);
+		nfs_set_verifier(new_dentry, nfs_save_change_attribute(new_dir));
+	}
 
 	/* new dentry created? */
 	if (dentry)
@@ -1451,7 +1543,8 @@ nfs_permission(struct inode *inode, int 
 
 	cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
 	if (cache->cred == cred
-	    && time_before(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode))) {
+	    && time_before(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode))
+	    && !(NFS_FLAGS(inode) & NFS_INO_INVALID_ATTR)) {
 		if (!(res = cache->err)) {
 			/* Is the mask a subset of an accepted mask? */
 			if ((cache->mask & mask) == mask)
--- diff/fs/nfs/direct.c	2003-10-27 09:20:39.000000000 +0000
+++ source/fs/nfs/direct.c	2004-03-09 11:51:51.000000000 +0000
@@ -269,6 +269,7 @@ nfs_direct_write_seg(struct inode *inode
 	if (IS_SYNC(inode) || NFS_PROTO(inode)->version == 2 || count <= wsize)
 		wdata.args.stable = NFS_FILE_SYNC;
 
+	nfs_begin_data_update(inode);
 retry:
 	need_commit = 0;
 	tot_bytes = 0;
@@ -334,6 +335,8 @@ retry:
 						VERF_SIZE) != 0)
 			goto sync_retry;
 	}
+	nfs_end_data_update(inode);
+	NFS_FLAGS(inode) |= NFS_INO_INVALID_DATA;
 
 	return tot_bytes;
 
--- diff/fs/nfs/file.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/nfs/file.c	2004-03-09 11:51:51.000000000 +0000
@@ -104,11 +104,16 @@ nfs_file_flush(struct file *file)
 
 	dfprintk(VFS, "nfs: flush(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
 
+	if ((file->f_mode & FMODE_WRITE) == 0)
+		return 0;
 	lock_kernel();
-	status = nfs_wb_file(inode, file);
+	/* Ensure that data+attribute caches are up to date after close() */
+	status = nfs_wb_all(inode);
 	if (!status) {
 		status = file->f_error;
 		file->f_error = 0;
+		if (!status)
+			__nfs_revalidate_inode(NFS_SERVER(inode), inode);
 	}
 	unlock_kernel();
 	return status;
@@ -179,7 +184,7 @@ nfs_fsync(struct file *file, struct dent
 	dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
 
 	lock_kernel();
-	status = nfs_wb_file(inode, file);
+	status = nfs_wb_all(inode);
 	if (!status) {
 		status = file->f_error;
 		file->f_error = 0;
--- diff/fs/nfs/inode.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/nfs/inode.c	2004-03-09 11:51:51.000000000 +0000
@@ -47,14 +47,11 @@
  *        their needs. People that do NFS over a slow network, might for
  *        instance want to reduce it to something closer to 1 for improved
  *        interactive response.
- *
- *        For the moment, though, we instead set it to RPC_MAXREQS, which
- *        is the maximum number of simultaneous RPC requests on the wire.
  */
-#define NFS_MAX_READAHEAD	RPC_MAXREQS
+#define NFS_MAX_READAHEAD	(RPC_DEF_SLOT_TABLE - 1)
 
-void nfs_zap_caches(struct inode *);
 static void nfs_invalidate_inode(struct inode *);
+static int nfs_update_inode(struct inode *, struct nfs_fattr *, unsigned long);
 
 static struct inode *nfs_alloc_inode(struct super_block *sb);
 static void nfs_destroy_inode(struct inode *);
@@ -118,7 +115,7 @@ nfs_write_inode(struct inode *inode, int
 {
 	int flags = sync ? FLUSH_WAIT : 0;
 
-	nfs_commit_file(inode, NULL, 0, 0, flags);
+	nfs_commit_inode(inode, 0, 0, flags);
 }
 
 static void
@@ -151,6 +148,7 @@ nfs_clear_inode(struct inode *inode)
 	cred = nfsi->cache_access.cred;
 	if (cred)
 		put_rpccred(cred);
+	BUG_ON(atomic_read(&nfsi->data_updates) != 0);
 }
 
 void
@@ -230,50 +228,23 @@ nfs_block_size(unsigned long bsize, unsi
 /*
  * Obtain the root inode of the file system.
  */
-static int
-nfs_get_root(struct inode **rooti, rpc_authflavor_t authflavor, struct super_block *sb, struct nfs_fh *rootfh)
+static struct inode *
+nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo)
 {
 	struct nfs_server	*server = NFS_SB(sb);
-	struct nfs_fattr	fattr = { };
+	struct inode *rooti;
 	int			error;
 
-	error = server->rpc_ops->getroot(server, rootfh, &fattr);
-	if (error == -EACCES && authflavor > RPC_AUTH_MAXFLAVOR) {
-		/*
-		 * Some authentication types (gss/krb5, most notably)
-		 * are such that root won't be able to present a
-		 * credential for GETATTR (ie, getroot()).
-		 *
-		 * We still want the mount to succeed.
-		 * 
-		 * So we fake the attr values and mark the inode as such.
-		 * On the first succesful traversal, we fix everything.
-		 * The auth type test isn't quite correct, but whatever.
-		 */
-		dfprintk(VFS, "NFS: faking root inode\n");
-
-		fattr.fileid = 1;
-		fattr.nlink = 2;	/* minimum for a dir */
-		fattr.type = NFDIR;
-		fattr.mode = S_IFDIR|S_IRUGO|S_IXUGO;
-		fattr.size = 4096;
-		fattr.du.nfs3.used = 1;
-		fattr.valid = NFS_ATTR_FATTR|NFS_ATTR_FATTR_V3;
-	} else if (error < 0) {
+	error = server->rpc_ops->getroot(server, rootfh, fsinfo);
+	if (error < 0) {
 		printk(KERN_NOTICE "nfs_get_root: getattr error = %d\n", -error);
-		*rooti = NULL;	/* superfluous ... but safe */
-		return error;
+		return ERR_PTR(error);
 	}
 
-	*rooti = nfs_fhget(sb, rootfh, &fattr);
-	if (error == -EACCES && authflavor > RPC_AUTH_MAXFLAVOR) {
-		if (*rooti) {
-			NFS_FLAGS(*rooti) |= NFS_INO_FAKE_ROOT;
-			NFS_CACHEINV((*rooti));
-			error = 0;
-		}
-	}
-	return error;
+	rooti = nfs_fhget(sb, rootfh, fsinfo->fattr);
+	if (!rooti)
+		return ERR_PTR(-ENOMEM);
+	return rooti;
 }
 
 /*
@@ -283,7 +254,7 @@ static int
 nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
 {
 	struct nfs_server	*server;
-	struct inode		*root_inode = NULL;
+	struct inode		*root_inode;
 	struct nfs_fattr	fattr;
 	struct nfs_fsinfo	fsinfo = {
 					.fattr = &fattr,
@@ -299,8 +270,9 @@ nfs_sb_init(struct super_block *sb, rpc_
 
 	sb->s_magic      = NFS_SUPER_MAGIC;
 
+	root_inode = nfs_get_root(sb, &server->fh, &fsinfo);
 	/* Did getting the root inode fail? */
-	if (nfs_get_root(&root_inode, authflavor, sb, &server->fh) < 0)
+	if (IS_ERR(root_inode))
 		goto out_no_root;
 	sb->s_root = d_alloc_root(root_inode);
 	if (!sb->s_root)
@@ -309,10 +281,6 @@ nfs_sb_init(struct super_block *sb, rpc_
 	sb->s_root->d_op = server->rpc_ops->dentry_ops;
 
 	/* Get some general file system info */
-        if (server->rpc_ops->fsinfo(server, &server->fh, &fsinfo) < 0) {
-		printk(KERN_NOTICE "NFS: cannot retrieve file system info.\n");
-		goto out_no_root;
-        }
 	if (server->namelen == 0 &&
 	    server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0)
 		server->namelen = pathinfo.max_namelen;
@@ -368,13 +336,11 @@ nfs_sb_init(struct super_block *sb, rpc_
 	rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
 	return 0;
 	/* Yargs. It didn't work out. */
-out_free_all:
-	if (root_inode)
-		iput(root_inode);
-	return -EINVAL;
 out_no_root:
 	printk("nfs_read_super: get root inode failed\n");
-	goto out_free_all;
+	if (!IS_ERR(root_inode))
+		iput(root_inode);
+	return -EINVAL;
 }
 
 /*
@@ -402,13 +368,13 @@ nfs_create_client(struct nfs_server *ser
 	/* create transport and client */
 	xprt = xprt_create_proto(tcp ? IPPROTO_TCP : IPPROTO_UDP,
 				 &server->addr, &timeparms);
-	if (xprt == NULL) {
+	if (IS_ERR(xprt)) {
 		printk(KERN_WARNING "NFS: cannot create RPC transport.\n");
-		goto out_fail;
+		return (struct rpc_clnt *)xprt;
 	}
 	clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
 				 server->rpc_ops->version, data->pseudoflavor);
-	if (clnt == NULL) {
+	if (IS_ERR(clnt)) {
 		printk(KERN_WARNING "NFS: cannot create RPC client.\n");
 		goto out_fail;
 	}
@@ -421,9 +387,8 @@ nfs_create_client(struct nfs_server *ser
 	return clnt;
 
 out_fail:
-	if (xprt)
-		xprt_destroy(xprt);
-	return NULL;
+	xprt_destroy(xprt);
+	return clnt;
 }
 
 /*
@@ -627,13 +592,17 @@ static int nfs_show_options(struct seq_f
 void
 nfs_zap_caches(struct inode *inode)
 {
+	struct nfs_inode *nfsi = NFS_I(inode);
+	int mode = inode->i_mode;
+
 	NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
 	NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
 
-	invalidate_remote_inode(inode);
-
 	memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
-	NFS_CACHEINV(inode);
+	if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))
+		nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
+	else
+		nfsi->flags |= NFS_INO_INVALID_ATTR;
 }
 
 /*
@@ -673,9 +642,6 @@ nfs_find_actor(struct inode *inode, void
 		return 0;
 	if (is_bad_inode(inode))
 		return 0;
-	/* Force an attribute cache update if inode->i_count == 0 */
-	if (!atomic_read(&inode->i_count))
-		NFS_CACHEINV(inode);
 	return 1;
 }
 
@@ -729,7 +695,7 @@ nfs_fhget(struct super_block *sb, struct
 		inode->i_ino = hash;
 
 		/* We can't support update_atime(), since the server will reset it */
-		inode->i_flags |= S_NOATIME;
+		inode->i_flags |= S_NOATIME|S_NOCMTIME;
 		inode->i_mode = fattr->mode;
 		/* Why so? Because we want revalidate for devices/FIFOs, and
 		 * that's precisely what we have in nfs_file_inode_operations.
@@ -754,10 +720,6 @@ nfs_fhget(struct super_block *sb, struct
 		inode->i_atime = fattr->atime;
 		inode->i_mtime = fattr->mtime;
 		inode->i_ctime = fattr->ctime;
-		nfsi->read_cache_ctime = fattr->ctime;
-		nfsi->read_cache_mtime = fattr->mtime;
-		nfsi->cache_mtime_jiffies = fattr->timestamp;
-		nfsi->read_cache_isize = fattr->size;
 		if (fattr->valid & NFS_ATTR_FATTR_V4)
 			nfsi->change_attr = fattr->change_attr;
 		inode->i_size = nfs_size_to_loff_t(fattr->size);
@@ -804,70 +766,50 @@ nfs_setattr(struct dentry *dentry, struc
 	struct nfs_fattr fattr;
 	int error;
 
+	if (attr->ia_valid & ATTR_SIZE) {
+		if (!S_ISREG(inode->i_mode) || attr->ia_size == i_size_read(inode))
+			attr->ia_valid &= ~ATTR_SIZE;
+	}
+
 	/* Optimization: if the end result is no change, don't RPC */
 	attr->ia_valid &= NFS_VALID_ATTRS;
 	if (attr->ia_valid == 0)
 		return 0;
 
 	lock_kernel();
-
-	/*
-	 * Make sure the inode is up-to-date.
-	 */
-	error = nfs_revalidate_inode(NFS_SERVER(inode),inode);
-	if (error) {
-#ifdef NFS_PARANOIA
-printk("nfs_setattr: revalidate failed, error=%d\n", error);
-#endif
-		goto out;
+	nfs_begin_data_update(inode);
+	/* Write all dirty data if we're changing file permissions or size */
+	if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE)) != 0) {
+		if (filemap_fdatawrite(inode->i_mapping) == 0)
+			filemap_fdatawait(inode->i_mapping);
+		nfs_wb_all(inode);
 	}
-
-	if (!S_ISREG(inode->i_mode)) {
-		attr->ia_valid &= ~ATTR_SIZE;
-		if (attr->ia_valid == 0)
-			goto out;
-	} else {
-		filemap_fdatawrite(inode->i_mapping);
-		error = nfs_wb_all(inode);
-		filemap_fdatawait(inode->i_mapping);
-		if (error)
-			goto out;
-		/* Optimize away unnecessary truncates */
-		if ((attr->ia_valid & ATTR_SIZE) && i_size_read(inode) == attr->ia_size)
-			attr->ia_valid &= ~ATTR_SIZE;
-	}
-	if (!attr->ia_valid)
-		goto out;
-
 	error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr);
-	if (error)
-		goto out;
-	/*
-	 * If we changed the size or mtime, update the inode
-	 * now to avoid invalidating the page cache.
-	 */
-	if (attr->ia_valid & ATTR_SIZE) {
-		if (attr->ia_size != fattr.size)
-			printk("nfs_setattr: attr=%Ld, fattr=%Ld??\n",
-			       (long long) attr->ia_size, (long long)fattr.size);
-		vmtruncate(inode, attr->ia_size);
+	if (error == 0) {
+		nfs_refresh_inode(inode, &fattr);
+		if ((attr->ia_valid & ATTR_MODE) != 0) {
+			int mode;
+			mode = inode->i_mode & ~S_IALLUGO;
+			mode |= attr->ia_mode & S_IALLUGO;
+			inode->i_mode = mode;
+		}
+		if ((attr->ia_valid & ATTR_UID) != 0)
+			inode->i_uid = attr->ia_uid;
+		if ((attr->ia_valid & ATTR_GID) != 0)
+			inode->i_gid = attr->ia_gid;
+		if ((attr->ia_valid & ATTR_SIZE) != 0) {
+			inode->i_size = attr->ia_size;
+			vmtruncate(inode, attr->ia_size);
+		}
 	}
-
-	/*
-	 * If we changed the size or mtime, update the inode
-	 * now to avoid invalidating the page cache.
-	 */
-	if (!(fattr.valid & NFS_ATTR_WCC)) {
-		struct nfs_inode *nfsi = NFS_I(inode);
-		fattr.pre_size = nfsi->read_cache_isize;
-		fattr.pre_mtime = nfsi->read_cache_mtime;
-		fattr.pre_ctime = nfsi->read_cache_ctime;
-		fattr.valid |= NFS_ATTR_WCC;
-	}
-	/* Force an attribute cache update */
-	NFS_CACHEINV(inode);
-	error = nfs_refresh_inode(inode, &fattr);
-out:
+	if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) {
+		struct rpc_cred **cred = &NFS_I(inode)->cache_access.cred;
+		if (*cred) {
+			put_rpccred(*cred);
+			*cred = NULL;
+		}
+	}
+	nfs_end_data_update(inode);
 	unlock_kernel();
 	return error;
 }
@@ -895,7 +837,19 @@ nfs_wait_on_inode(struct inode *inode, i
 int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
 {
 	struct inode *inode = dentry->d_inode;
-	int err = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+	struct nfs_inode *nfsi = NFS_I(inode);
+	int need_atime = nfsi->flags & NFS_INO_INVALID_ATIME;
+	int err;
+
+	if (__IS_FLG(inode, MS_NOATIME))
+		need_atime = 0;
+	else if (__IS_FLG(inode, MS_NODIRATIME) && S_ISDIR(inode->i_mode))
+		need_atime = 0;
+	/* We may force a getattr if the user cares about atime */
+	if (need_atime)
+		err = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
+	else
+		err = nfs_revalidate_inode(NFS_SERVER(inode), inode);
 	if (!err)
 		generic_fillattr(inode, stat);
 	return err;
@@ -930,8 +884,10 @@ int nfs_open(struct inode *inode, struct
 	auth = NFS_CLIENT(inode)->cl_auth;
 	cred = rpcauth_lookupcred(auth, 0);
 	filp->private_data = cred;
-	if (filp->f_mode & FMODE_WRITE)
+	if ((filp->f_mode & FMODE_WRITE) != 0) {
 		nfs_set_mmcred(inode, cred);
+		nfs_begin_data_update(inode);
+	}
 	return 0;
 }
 
@@ -940,6 +896,8 @@ int nfs_release(struct inode *inode, str
 	struct rpc_cred *cred;
 
 	lock_kernel();
+	if ((filp->f_mode & FMODE_WRITE) != 0)
+		nfs_end_data_update(inode);
 	cred = nfs_file_cred(filp);
 	if (cred)
 		put_rpccred(cred);
@@ -956,6 +914,9 @@ __nfs_revalidate_inode(struct nfs_server
 {
 	int		 status = -ESTALE;
 	struct nfs_fattr fattr;
+	struct nfs_inode *nfsi = NFS_I(inode);
+	unsigned long verifier;
+	unsigned int flags;
 
 	dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n",
 		inode->i_sb->s_id, (long long)NFS_FILEID(inode));
@@ -965,23 +926,22 @@ __nfs_revalidate_inode(struct nfs_server
  		goto out_nowait;
 	if (NFS_STALE(inode) && inode != inode->i_sb->s_root->d_inode)
  		goto out_nowait;
-	if (NFS_FAKE_ROOT(inode)) {
-		dfprintk(VFS, "NFS: not revalidating fake root\n");
-		status = 0;
-		goto out_nowait;
-	}
 
 	while (NFS_REVALIDATING(inode)) {
 		status = nfs_wait_on_inode(inode, NFS_INO_REVALIDATING);
 		if (status < 0)
 			goto out_nowait;
-		if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode))) {
-			status = NFS_STALE(inode) ? -ESTALE : 0;
-			goto out_nowait;
-		}
+		if (NFS_SERVER(inode)->flags & NFS_MOUNT_NOAC)
+			continue;
+		if (NFS_FLAGS(inode) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ATIME))
+			continue;
+		status = NFS_STALE(inode) ? -ESTALE : 0;
+		goto out_nowait;
 	}
 	NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
 
+	/* Protect against RPC races by saving the change attribute */
+	verifier = nfs_save_change_attribute(inode);
 	status = NFS_PROTO(inode)->getattr(inode, &fattr);
 	if (status) {
 		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
@@ -995,13 +955,36 @@ __nfs_revalidate_inode(struct nfs_server
 		goto out;
 	}
 
-	status = nfs_refresh_inode(inode, &fattr);
+	status = nfs_update_inode(inode, &fattr, verifier);
 	if (status) {
 		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n",
 			 inode->i_sb->s_id,
 			 (long long)NFS_FILEID(inode), status);
 		goto out;
 	}
+	flags = nfsi->flags;
+	/*
+	 * We may need to keep the attributes marked as invalid if
+	 * we raced with nfs_end_attr_update().
+	 */
+	if (verifier == nfsi->cache_change_attribute)
+		nfsi->flags &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME);
+	/* Do the page cache invalidation */
+	if (flags & NFS_INO_INVALID_DATA) {
+		if (S_ISREG(inode->i_mode)) {
+			if (filemap_fdatawrite(inode->i_mapping) == 0)
+				filemap_fdatawait(inode->i_mapping);
+			nfs_wb_all(inode);
+		}
+		nfsi->flags &= ~NFS_INO_INVALID_DATA;
+		invalidate_inode_pages2(inode->i_mapping);
+		memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
+		dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
+				inode->i_sb->s_id,
+				(long long)NFS_FILEID(inode));
+		/* This ensures we revalidate dentries */
+		nfsi->cache_change_attribute++;
+	}
 	dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n",
 		inode->i_sb->s_id,
 		(long long)NFS_FILEID(inode));
@@ -1009,41 +992,104 @@ __nfs_revalidate_inode(struct nfs_server
 	NFS_FLAGS(inode) &= ~NFS_INO_STALE;
 out:
 	NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING;
-	wake_up(&NFS_I(inode)->nfs_i_wait);
+	wake_up(&nfsi->nfs_i_wait);
  out_nowait:
 	unlock_kernel();
 	return status;
 }
 
-/*
- * nfs_fattr_obsolete - Test if attribute data is newer than cached data
- * @inode: inode
- * @fattr: attributes to test
+/**
+ * nfs_begin_data_update
+ * @inode - pointer to inode
+ * Declare that a set of operations will update file data on the server
+ */
+void nfs_begin_data_update(struct inode *inode)
+{
+	atomic_inc(&NFS_I(inode)->data_updates);
+}
+
+/**
+ * nfs_end_data_update
+ * @inode - pointer to inode
+ * Declare end of the operations that will update file data
+ */
+void nfs_end_data_update(struct inode *inode)
+{
+	struct nfs_inode *nfsi = NFS_I(inode);
+
+	if (atomic_dec_and_test(&nfsi->data_updates)) {
+		nfsi->cache_change_attribute ++;
+		/* Mark the attribute cache for revalidation */
+		nfsi->flags |= NFS_INO_INVALID_ATTR;
+		/* Directories and symlinks: invalidate page cache too */
+		if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
+			nfsi->flags |= NFS_INO_INVALID_DATA;
+	}
+}
+
+/**
+ * nfs_refresh_inode - verify consistency of the inode attribute cache
+ * @inode - pointer to inode
+ * @fattr - updated attributes
  *
- * 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.
+ * Verifies the attribute cache. If we have just changed the attributes,
+ * so that fattr carries weak cache consistency data, then it may
+ * also update the ctime/mtime/change_attribute.
  */
-static inline
-int nfs_fattr_obsolete(struct inode *inode, struct nfs_fattr *fattr)
+int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
-	long cdif;
+	loff_t cur_size, new_isize;
+	int data_unstable;
+
+	/* Are we in the process of updating data on the server? */
+	data_unstable = nfs_caches_unstable(inode);
 
-	if (time_after(jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo))
-		goto out_valid;
-	cdif = fattr->ctime.tv_sec - nfsi->read_cache_ctime.tv_sec;
-	if (cdif == 0)
-		cdif = fattr->ctime.tv_nsec - nfsi->read_cache_ctime.tv_nsec;
-	if (cdif > 0)
-		goto out_valid;
-	/* Ugh... */
-	if (cdif == 0 && fattr->size > nfsi->read_cache_isize)
-		goto out_valid;
-	return -1;
- out_valid:
+	if (fattr->valid & NFS_ATTR_FATTR_V4) {
+		if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0
+				&& nfsi->change_attr == fattr->pre_change_attr)
+			nfsi->change_attr = fattr->change_attr;
+		if (!data_unstable && nfsi->change_attr != fattr->change_attr)
+			nfsi->flags |= NFS_INO_INVALID_ATTR;
+	}
+
+	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
+		return 0;
+
+	/* Has the inode gone and changed behind our back? */
+	if (nfsi->fileid != fattr->fileid
+			|| (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
+		return -EIO;
+
+	cur_size = i_size_read(inode);
+ 	new_isize = nfs_size_to_loff_t(fattr->size);
+
+	/* If we have atomic WCC data, we may update some attributes */
+	if ((fattr->valid & NFS_ATTR_WCC) != 0) {
+		if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
+			memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
+		if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime))
+			memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
+	}
+
+	/* Verify a few of the more important attributes */
+	if (!data_unstable) {
+		if (!timespec_equal(&inode->i_mtime, &fattr->mtime)
+				|| cur_size != new_isize)
+			nfsi->flags |= NFS_INO_INVALID_ATTR;
+	} else if (S_ISREG(inode->i_mode) && new_isize > cur_size)
+			nfsi->flags |= NFS_INO_INVALID_ATTR;
+
+	/* Have any file permissions changed? */
+	if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)
+			|| inode->i_uid != fattr->uid
+			|| inode->i_gid != fattr->gid)
+		nfsi->flags |= NFS_INO_INVALID_ATTR;
+
+	if (!timespec_equal(&inode->i_atime, &fattr->atime))
+		nfsi->flags |= NFS_INO_INVALID_ATIME;
+
+	nfsi->read_cache_jiffies = fattr->timestamp;
 	return 0;
 }
 
@@ -1059,65 +1105,66 @@ int nfs_fattr_obsolete(struct inode *ino
  *
  * A very similar scenario holds for the dir cache.
  */
-int
-__nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
+static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsigned long verifier)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
 	__u64		new_size;
 	loff_t		new_isize;
-	int		invalid = 0;
-	int		mtime_update = 0;
+	unsigned int	invalid = 0;
 	loff_t		cur_isize;
+	int data_unstable;
 
-	dfprintk(VFS, "NFS: refresh_inode(%s/%ld ct=%d info=0x%x)\n",
-			inode->i_sb->s_id, inode->i_ino,
+	dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n",
+			__FUNCTION__, inode->i_sb->s_id, inode->i_ino,
 			atomic_read(&inode->i_count), fattr->valid);
 
-	/* First successful call after mount, fill real data. */
-	if (NFS_FAKE_ROOT(inode)) {
-		dfprintk(VFS, "NFS: updating fake root\n");
-		nfsi->fileid = fattr->fileid;
-		NFS_FLAGS(inode) &= ~NFS_INO_FAKE_ROOT;
-	}
+	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
+		return 0;
 
 	if (nfsi->fileid != fattr->fileid) {
-		printk(KERN_ERR "nfs_refresh_inode: inode number mismatch\n"
+		printk(KERN_ERR "%s: inode number mismatch\n"
 		       "expected (%s/0x%Lx), got (%s/0x%Lx)\n",
+		       __FUNCTION__,
 		       inode->i_sb->s_id, (long long)nfsi->fileid,
 		       inode->i_sb->s_id, (long long)fattr->fileid);
 		goto out_err;
 	}
 
-	/* Throw out obsolete READDIRPLUS attributes */
-	if (time_before(fattr->timestamp, NFS_READTIME(inode)))
-		return 0;
 	/*
 	 * Make sure the inode's type hasn't changed.
 	 */
 	if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
 		goto out_changed;
 
-	new_size = fattr->size;
- 	new_isize = nfs_size_to_loff_t(fattr->size);
-
-	/* Avoid races */
-	if (nfs_fattr_obsolete(inode, fattr))
-		goto out_nochange;
-
 	/*
 	 * Update the read time so we don't revalidate too often.
 	 */
 	nfsi->read_cache_jiffies = fattr->timestamp;
 
-	/*
-	 * Note: NFS_CACHE_ISIZE(inode) reflects the state of the cache.
-	 *       NOT inode->i_size!!!
-	 */
-	if (nfsi->read_cache_isize != new_size) {
+	/* Are we racing with known updates of the metadata on the server? */
+	data_unstable = ! nfs_verify_change_attribute(inode, verifier);
+
+	/* Check if the file size agrees */
+	new_size = fattr->size;
+ 	new_isize = nfs_size_to_loff_t(fattr->size);
+	cur_isize = i_size_read(inode);
+	if (cur_isize != new_size) {
 #ifdef NFS_DEBUG_VERBOSE
 		printk(KERN_DEBUG "NFS: isize change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino);
 #endif
-		invalid = 1;
+		/*
+		 * If we have pending writebacks, things can get
+		 * messy.
+		 */
+		if (S_ISREG(inode->i_mode) && data_unstable) {
+			if (new_isize > cur_isize) {
+				inode->i_size = new_isize;
+				invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
+			}
+		} else {
+			inode->i_size = new_isize;
+			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
+		}
 	}
 
 	/*
@@ -1125,12 +1172,13 @@ __nfs_refresh_inode(struct inode *inode,
 	 *       can change this value in VFS without requiring a
 	 *	 cache revalidation.
 	 */
-	if (!timespec_equal(&nfsi->read_cache_mtime, &fattr->mtime)) {
+	if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
+		memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
 #ifdef NFS_DEBUG_VERBOSE
 		printk(KERN_DEBUG "NFS: mtime change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino);
 #endif
-		invalid = 1;
-		mtime_update = 1;
+		if (!data_unstable)
+			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
 	}
 
 	if ((fattr->valid & NFS_ATTR_FATTR_V4)
@@ -1139,47 +1187,15 @@ __nfs_refresh_inode(struct inode *inode,
 		printk(KERN_DEBUG "NFS: change_attr change on %s/%ld\n",
 		       inode->i_sb->s_id, inode->i_ino);
 #endif
-		invalid = 1;
-	}
-
-	/* Check Weak Cache Consistency data.
-	 * If size and mtime match the pre-operation values, we can
-	 * assume that any attribute changes were caused by our NFS
-         * operation, so there's no need to invalidate the caches.
-         */
-	if ((fattr->valid & NFS_ATTR_PRE_CHANGE)
-	    && nfsi->change_attr == fattr->pre_change_attr) {
-		invalid = 0;
-	}
-	else if ((fattr->valid & NFS_ATTR_WCC)
-	    && nfsi->read_cache_isize == fattr->pre_size
-	    && timespec_equal(&nfsi->read_cache_mtime, &fattr->pre_mtime)) {
-		invalid = 0;
-	}
-
-	/*
-	 * If we have pending writebacks, things can get
-	 * messy.
-	 */
-	cur_isize = i_size_read(inode);
-	if (nfs_have_writebacks(inode) && new_isize < cur_isize)
-		new_isize = cur_isize;
-
-	nfsi->read_cache_ctime = fattr->ctime;
-	inode->i_ctime = fattr->ctime;
-	inode->i_atime = fattr->atime;
-
-	if (mtime_update) {
-		if (invalid)
-			nfsi->cache_mtime_jiffies = fattr->timestamp;
-		nfsi->read_cache_mtime = fattr->mtime;
-		inode->i_mtime = fattr->mtime;
+		nfsi->change_attr = fattr->change_attr;
+		if (!data_unstable)
+			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
 	}
 
-	nfsi->read_cache_isize = new_size;
-	i_size_write(inode, new_isize);
+	memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
+	memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
 
-	if (inode->i_mode != fattr->mode ||
+	if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) ||
 	    inode->i_uid != fattr->uid ||
 	    inode->i_gid != fattr->gid) {
 		struct rpc_cred **cred = &NFS_I(inode)->cache_access.cred;
@@ -1187,11 +1203,9 @@ __nfs_refresh_inode(struct inode *inode,
 			put_rpccred(*cred);
 			*cred = NULL;
 		}
+		invalid |= NFS_INO_INVALID_ATTR;
 	}
 
-	if (fattr->valid & NFS_ATTR_FATTR_V4)
-		nfsi->change_attr = fattr->change_attr;
-
 	inode->i_mode = fattr->mode;
 	inode->i_nlink = fattr->nlink;
 	inode->i_uid = fattr->uid;
@@ -1207,31 +1221,30 @@ __nfs_refresh_inode(struct inode *inode,
  		inode->i_blocks = fattr->du.nfs2.blocks;
  		inode->i_blksize = fattr->du.nfs2.blocksize;
  	}
- 
-	/* Update attrtimeo value */
-	if (invalid) {
+
+	/* Update attrtimeo value if we're out of the unstable period */
+	if (invalid & NFS_INO_INVALID_ATTR) {
 		nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
 		nfsi->attrtimeo_timestamp = jiffies;
-		invalidate_remote_inode(inode);
-		memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
 	} else if (time_after(jiffies, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) {
 		if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode))
 			nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
 		nfsi->attrtimeo_timestamp = jiffies;
 	}
+	/* Don't invalidate the data if we were to blame */
+	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
+				|| S_ISLNK(inode->i_mode)))
+		invalid &= ~NFS_INO_INVALID_DATA;
+	nfsi->flags |= invalid;
 
 	return 0;
- out_nochange:
-	if (!timespec_equal(&fattr->atime, &inode->i_atime))
-		inode->i_atime = fattr->atime;
-	return 0;
  out_changed:
 	/*
 	 * Big trouble! The inode has become a different object.
 	 */
 #ifdef NFS_PARANOIA
-	printk(KERN_DEBUG "nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n",
-	       inode->i_ino, inode->i_mode, fattr->mode);
+	printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n",
+			__FUNCTION__, inode->i_ino, inode->i_mode, fattr->mode);
 #endif
 	/*
 	 * No need to worry about unhashing the dentry, as the
@@ -1352,7 +1365,7 @@ static struct file_system_type nfs_fs_ty
 	.name		= "nfs",
 	.get_sb		= nfs_get_sb,
 	.kill_sb	= nfs_kill_super,
-	.fs_flags	= FS_ODD_RENAME|FS_REVAL_DOT,
+	.fs_flags	= FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
 };
 
 #ifdef CONFIG_NFS_V4
@@ -1472,17 +1485,19 @@ static int nfs4_fill_super(struct super_
 	down_write(&clp->cl_sem);
 	if (clp->cl_rpcclient == NULL) {
 		xprt = xprt_create_proto(proto, &server->addr, &timeparms);
-		if (xprt == NULL) {
+		if (IS_ERR(xprt)) {
 			up_write(&clp->cl_sem);
 			printk(KERN_WARNING "NFS: cannot create RPC transport.\n");
+			err = PTR_ERR(xprt);
 			goto out_fail;
 		}
 		clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
 				server->rpc_ops->version, authflavour);
-		if (clnt == NULL) {
+		if (IS_ERR(clnt)) {
 			up_write(&clp->cl_sem);
 			printk(KERN_WARNING "NFS: cannot create RPC client.\n");
 			xprt_destroy(xprt);
+			err = PTR_ERR(clnt);
 			goto out_fail;
 		}
 		clnt->cl_chatty   = 1;
@@ -1495,14 +1510,17 @@ static int nfs4_fill_super(struct super_
 		clear_bit(NFS4CLNT_OK, &clp->cl_state);
 	list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
 	clnt = rpc_clone_client(clp->cl_rpcclient);
-	server->nfs4_state = clp;
+	if (!IS_ERR(clnt))
+			server->nfs4_state = clp;
 	up_write(&clp->cl_sem);
 	clp = NULL;
 
-	if (clnt == NULL) {
+	if (IS_ERR(clnt)) {
 		printk(KERN_WARNING "NFS: cannot create RPC client.\n");
+		err = PTR_ERR(clnt);
 		goto out_remove_list;
 	}
+	err = -ENOMEM;
 	if (server->nfs4_state->cl_idmap == NULL) {
 		printk(KERN_WARNING "NFS: failed to create idmapper.\n");
 		goto out_shutdown;
@@ -1601,7 +1619,7 @@ static struct super_block *nfs4_get_sb(s
 
 	if (data->version != NFS4_MOUNT_VERSION) {
 		printk("nfs warning: mount version %s than kernel\n",
-			data->version < NFS_MOUNT_VERSION ? "older" : "newer");
+			data->version < NFS4_MOUNT_VERSION ? "older" : "newer");
 	}
 
 	p = nfs_copy_user_string(NULL, &data->hostname, 256);
@@ -1666,7 +1684,7 @@ static struct file_system_type nfs4_fs_t
 	.name		= "nfs4",
 	.get_sb		= nfs4_get_sb,
 	.kill_sb	= nfs_kill_super,
-	.fs_flags	= FS_ODD_RENAME|FS_REVAL_DOT,
+	.fs_flags	= FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
 };
 
 #define nfs4_zero_state(nfsi) \
@@ -1718,6 +1736,7 @@ static void init_once(void * foo, kmem_c
 		INIT_LIST_HEAD(&nfsi->dirty);
 		INIT_LIST_HEAD(&nfsi->commit);
 		INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
+		atomic_set(&nfsi->data_updates, 0);
 		nfsi->ndirty = 0;
 		nfsi->ncommit = 0;
 		nfsi->npages = 0;
--- diff/fs/nfs/mount_clnt.c	2003-02-13 11:46:54.000000000 +0000
+++ source/fs/nfs/mount_clnt.c	2004-03-09 11:51:51.000000000 +0000
@@ -57,8 +57,9 @@ nfsroot_mount(struct sockaddr_in *addr, 
 			(unsigned)ntohl(addr->sin_addr.s_addr), path);
 
 	sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr->sin_addr.s_addr));
-	if (!(mnt_clnt = mnt_create(hostname, addr, version, protocol)))
-		return -EACCES;
+	mnt_clnt = mnt_create(hostname, addr, version, protocol);
+	if (IS_ERR(mnt_clnt))
+		return PTR_ERR(mnt_clnt);
 
 	call = (version == NFS_MNT3_VERSION) ? MOUNTPROC3_MNT : MNTPROC_MNT;
 	status = rpc_call(mnt_clnt, call, path, &result, 0);
@@ -72,13 +73,14 @@ mnt_create(char *hostname, struct sockad
 	struct rpc_xprt	*xprt;
 	struct rpc_clnt	*clnt;
 
-	if (!(xprt = xprt_create_proto(protocol, srvaddr, NULL)))
-		return NULL;
+	xprt = xprt_create_proto(protocol, srvaddr, NULL);
+	if (IS_ERR(xprt))
+		return (struct rpc_clnt *)xprt;
 
 	clnt = rpc_create_client(xprt, hostname,
 				&mnt_program, version,
-				RPC_AUTH_NULL);
-	if (!clnt) {
+				RPC_AUTH_UNIX);
+	if (IS_ERR(clnt)) {
 		xprt_destroy(xprt);
 	} else {
 		clnt->cl_softrtry = 1;
--- diff/fs/nfs/nfs2xdr.c	2003-09-30 15:46:18.000000000 +0100
+++ source/fs/nfs/nfs2xdr.c	2004-03-09 11:51:51.000000000 +0000
@@ -36,33 +36,33 @@ extern int			nfs_stat_to_errno(int stat)
  * Declare the space requirements for NFS arguments and replies as
  * number of 32bit-words
  */
-#define NFS_fhandle_sz		8
-#define NFS_sattr_sz		8
-#define NFS_filename_sz		1+(NFS2_MAXNAMLEN>>2)
-#define NFS_path_sz		1+(NFS2_MAXPATHLEN>>2)
-#define NFS_fattr_sz		17
-#define NFS_info_sz		5
-#define NFS_entry_sz		NFS_filename_sz+3
-
-#define NFS_diropargs_sz	NFS_fhandle_sz+NFS_filename_sz
-#define NFS_sattrargs_sz	NFS_fhandle_sz+NFS_sattr_sz
-#define NFS_readlinkargs_sz	NFS_fhandle_sz
-#define NFS_readargs_sz		NFS_fhandle_sz+3
-#define NFS_writeargs_sz	NFS_fhandle_sz+4
-#define NFS_createargs_sz	NFS_diropargs_sz+NFS_sattr_sz
-#define NFS_renameargs_sz	NFS_diropargs_sz+NFS_diropargs_sz
-#define NFS_linkargs_sz		NFS_fhandle_sz+NFS_diropargs_sz
-#define NFS_symlinkargs_sz	NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz
-#define NFS_readdirargs_sz	NFS_fhandle_sz+2
-
-#define NFS_attrstat_sz		1+NFS_fattr_sz
-#define NFS_diropres_sz		1+NFS_fhandle_sz+NFS_fattr_sz
-#define NFS_readlinkres_sz	1
-#define NFS_readres_sz		1+NFS_fattr_sz+1
-#define NFS_writeres_sz         NFS_attrstat_sz
-#define NFS_stat_sz		1
-#define NFS_readdirres_sz	1
-#define NFS_statfsres_sz	1+NFS_info_sz
+#define NFS_fhandle_sz		(8)
+#define NFS_sattr_sz		(8)
+#define NFS_filename_sz		(1+(NFS2_MAXNAMLEN>>2))
+#define NFS_path_sz		(1+(NFS2_MAXPATHLEN>>2))
+#define NFS_fattr_sz		(17)
+#define NFS_info_sz		(5)
+#define NFS_entry_sz		(NFS_filename_sz+3)
+
+#define NFS_diropargs_sz	(NFS_fhandle_sz+NFS_filename_sz)
+#define NFS_sattrargs_sz	(NFS_fhandle_sz+NFS_sattr_sz)
+#define NFS_readlinkargs_sz	(NFS_fhandle_sz)
+#define NFS_readargs_sz		(NFS_fhandle_sz+3)
+#define NFS_writeargs_sz	(NFS_fhandle_sz+4)
+#define NFS_createargs_sz	(NFS_diropargs_sz+NFS_sattr_sz)
+#define NFS_renameargs_sz	(NFS_diropargs_sz+NFS_diropargs_sz)
+#define NFS_linkargs_sz		(NFS_fhandle_sz+NFS_diropargs_sz)
+#define NFS_symlinkargs_sz	(NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz)
+#define NFS_readdirargs_sz	(NFS_fhandle_sz+2)
+
+#define NFS_attrstat_sz		(1+NFS_fattr_sz)
+#define NFS_diropres_sz		(1+NFS_fhandle_sz+NFS_fattr_sz)
+#define NFS_readlinkres_sz	(1)
+#define NFS_readres_sz		(1+NFS_fattr_sz+1)
+#define NFS_writeres_sz         (NFS_attrstat_sz)
+#define NFS_stat_sz		(1)
+#define NFS_readdirres_sz	(1)
+#define NFS_statfsres_sz	(1+NFS_info_sz)
 
 /*
  * Common NFS XDR functions as inlines
--- diff/fs/nfs/nfs3proc.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/nfs/nfs3proc.c	2004-03-09 11:51:51.000000000 +0000
@@ -68,20 +68,6 @@ nfs3_async_handle_jukebox(struct rpc_tas
 	return 1;
 }
 
-static void
-nfs3_write_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
-{
-	if (fattr->valid & NFS_ATTR_FATTR) {
-		if (!(fattr->valid & NFS_ATTR_WCC)) {
-			fattr->pre_size  = NFS_CACHE_ISIZE(inode);
-			fattr->pre_mtime = NFS_CACHE_MTIME(inode);
-			fattr->pre_ctime = NFS_CACHE_CTIME(inode);
-			fattr->valid |= NFS_ATTR_WCC;
-		}
-		nfs_refresh_inode(inode, fattr);
-	}
-}
-
 static struct rpc_cred *
 nfs_cred(struct inode *inode, struct file *filp)
 {
@@ -99,14 +85,18 @@ nfs_cred(struct inode *inode, struct fil
  */
 static int
 nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
-		   struct nfs_fattr *fattr)
+		   struct nfs_fsinfo *info)
 {
 	int	status;
 
-	dprintk("NFS call  getroot\n");
-	fattr->valid = 0;
-	status = rpc_call(server->client, NFS3PROC_GETATTR, fhandle, fattr, 0);
-	dprintk("NFS reply getroot\n");
+	dprintk("%s: call  fsinfo\n", __FUNCTION__);
+	info->fattr->valid = 0;
+	status = rpc_call(server->client_sys, NFS3PROC_FSINFO, fhandle, info, 0);
+	dprintk("%s: reply fsinfo %d\n", __FUNCTION__, status);
+	if (!(info->fattr->valid & NFS_ATTR_FATTR)) {
+		status = rpc_call(server->client_sys, NFS3PROC_GETATTR, fhandle, info->fattr, 0);
+		dprintk("%s: reply getattr %d\n", __FUNCTION__, status);
+	}
 	return status;
 }
 
@@ -280,7 +270,7 @@ nfs3_proc_write(struct nfs_write_data *w
 	msg.rpc_cred = nfs_cred(inode, filp);
 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags);
 	if (status >= 0)
-		nfs3_write_refresh_inode(inode, fattr);
+		nfs_refresh_inode(inode, fattr);
 	dprintk("NFS reply write: %d\n", status);
 	return status < 0? status : wdata->res.count;
 }
@@ -303,7 +293,7 @@ nfs3_proc_commit(struct nfs_write_data *
 	msg.rpc_cred = nfs_cred(inode, filp);
 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
 	if (status >= 0)
-		nfs3_write_refresh_inode(inode, fattr);
+		nfs_refresh_inode(inode, fattr);
 	dprintk("NFS reply commit: %d\n", status);
 	return status;
 }
@@ -777,12 +767,13 @@ nfs3_proc_read_setup(struct nfs_read_dat
 static void
 nfs3_write_done(struct rpc_task *task)
 {
-	struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
+	struct nfs_write_data *data;
 
 	if (nfs3_async_handle_jukebox(task))
 		return;
+	data = (struct nfs_write_data *)task->tk_calldata;
 	if (task->tk_status >= 0)
-		nfs3_write_refresh_inode(data->inode, data->res.fattr);
+		nfs_refresh_inode(data->inode, data->res.fattr);
 	nfs_writeback_done(task);
 }
 
@@ -835,12 +826,13 @@ nfs3_proc_write_setup(struct nfs_write_d
 static void
 nfs3_commit_done(struct rpc_task *task)
 {
-	struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
+	struct nfs_write_data *data;
 
 	if (nfs3_async_handle_jukebox(task))
 		return;
+	data = (struct nfs_write_data *)task->tk_calldata;
 	if (task->tk_status >= 0)
-		nfs3_write_refresh_inode(data->inode, data->res.fattr);
+		nfs_refresh_inode(data->inode, data->res.fattr);
 	nfs_commit_done(task);
 }
 
--- diff/fs/nfs/nfs3xdr.c	2003-09-30 15:46:18.000000000 +0100
+++ source/fs/nfs/nfs3xdr.c	2004-03-09 11:51:51.000000000 +0000
@@ -33,51 +33,51 @@ extern int			nfs_stat_to_errno(int);
  * Declare the space requirements for NFS arguments and replies as
  * number of 32bit-words
  */
-#define NFS3_fhandle_sz		1+16
-#define NFS3_fh_sz		NFS3_fhandle_sz	/* shorthand */
-#define NFS3_sattr_sz		15
-#define NFS3_filename_sz	1+(NFS3_MAXNAMLEN>>2)
-#define NFS3_path_sz		1+(NFS3_MAXPATHLEN>>2)
-#define NFS3_fattr_sz		21
-#define NFS3_wcc_attr_sz		6
-#define NFS3_pre_op_attr_sz	1+NFS3_wcc_attr_sz
-#define NFS3_post_op_attr_sz	1+NFS3_fattr_sz
-#define NFS3_wcc_data_sz		NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz
+#define NFS3_fhandle_sz		(1+16)
+#define NFS3_fh_sz		(NFS3_fhandle_sz)	/* shorthand */
+#define NFS3_sattr_sz		(15)
+#define NFS3_filename_sz	(1+(NFS3_MAXNAMLEN>>2))
+#define NFS3_path_sz		(1+(NFS3_MAXPATHLEN>>2))
+#define NFS3_fattr_sz		(21)
+#define NFS3_wcc_attr_sz		(6)
+#define NFS3_pre_op_attr_sz	(1+NFS3_wcc_attr_sz)
+#define NFS3_post_op_attr_sz	(1+NFS3_fattr_sz)
+#define NFS3_wcc_data_sz		(NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
 #define NFS3_fsstat_sz		
 #define NFS3_fsinfo_sz		
 #define NFS3_pathconf_sz		
-#define NFS3_entry_sz		NFS3_filename_sz+3
+#define NFS3_entry_sz		(NFS3_filename_sz+3)
 
-#define NFS3_sattrargs_sz	NFS3_fh_sz+NFS3_sattr_sz+3
-#define NFS3_diropargs_sz	NFS3_fh_sz+NFS3_filename_sz
-#define NFS3_accessargs_sz	NFS3_fh_sz+1
-#define NFS3_readlinkargs_sz	NFS3_fh_sz
-#define NFS3_readargs_sz	NFS3_fh_sz+3
-#define NFS3_writeargs_sz	NFS3_fh_sz+5
-#define NFS3_createargs_sz	NFS3_diropargs_sz+NFS3_sattr_sz
-#define NFS3_mkdirargs_sz	NFS3_diropargs_sz+NFS3_sattr_sz
-#define NFS3_symlinkargs_sz	NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz
-#define NFS3_mknodargs_sz	NFS3_diropargs_sz+2+NFS3_sattr_sz
-#define NFS3_renameargs_sz	NFS3_diropargs_sz+NFS3_diropargs_sz
-#define NFS3_linkargs_sz		NFS3_fh_sz+NFS3_diropargs_sz
-#define NFS3_readdirargs_sz	NFS3_fh_sz+2
-#define NFS3_commitargs_sz	NFS3_fh_sz+3
-
-#define NFS3_attrstat_sz	1+NFS3_fattr_sz
-#define NFS3_wccstat_sz		1+NFS3_wcc_data_sz
-#define NFS3_lookupres_sz	1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)
-#define NFS3_accessres_sz	1+NFS3_post_op_attr_sz+1
-#define NFS3_readlinkres_sz	1+NFS3_post_op_attr_sz
-#define NFS3_readres_sz		1+NFS3_post_op_attr_sz+3
-#define NFS3_writeres_sz	1+NFS3_wcc_data_sz+4
-#define NFS3_createres_sz	1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
-#define NFS3_renameres_sz	1+(2 * NFS3_wcc_data_sz)
-#define NFS3_linkres_sz		1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
-#define NFS3_readdirres_sz	1+NFS3_post_op_attr_sz+2
-#define NFS3_fsstatres_sz	1+NFS3_post_op_attr_sz+13
-#define NFS3_fsinfores_sz	1+NFS3_post_op_attr_sz+12
-#define NFS3_pathconfres_sz	1+NFS3_post_op_attr_sz+6
-#define NFS3_commitres_sz	1+NFS3_wcc_data_sz+2
+#define NFS3_sattrargs_sz	(NFS3_fh_sz+NFS3_sattr_sz+3)
+#define NFS3_diropargs_sz	(NFS3_fh_sz+NFS3_filename_sz)
+#define NFS3_accessargs_sz	(NFS3_fh_sz+1)
+#define NFS3_readlinkargs_sz	(NFS3_fh_sz)
+#define NFS3_readargs_sz	(NFS3_fh_sz+3)
+#define NFS3_writeargs_sz	(NFS3_fh_sz+5)
+#define NFS3_createargs_sz	(NFS3_diropargs_sz+NFS3_sattr_sz)
+#define NFS3_mkdirargs_sz	(NFS3_diropargs_sz+NFS3_sattr_sz)
+#define NFS3_symlinkargs_sz	(NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz)
+#define NFS3_mknodargs_sz	(NFS3_diropargs_sz+2+NFS3_sattr_sz)
+#define NFS3_renameargs_sz	(NFS3_diropargs_sz+NFS3_diropargs_sz)
+#define NFS3_linkargs_sz		(NFS3_fh_sz+NFS3_diropargs_sz)
+#define NFS3_readdirargs_sz	(NFS3_fh_sz+2)
+#define NFS3_commitargs_sz	(NFS3_fh_sz+3)
+
+#define NFS3_attrstat_sz	(1+NFS3_fattr_sz)
+#define NFS3_wccstat_sz		(1+NFS3_wcc_data_sz)
+#define NFS3_lookupres_sz	(1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
+#define NFS3_accessres_sz	(1+NFS3_post_op_attr_sz+1)
+#define NFS3_readlinkres_sz	(1+NFS3_post_op_attr_sz)
+#define NFS3_readres_sz		(1+NFS3_post_op_attr_sz+3)
+#define NFS3_writeres_sz	(1+NFS3_wcc_data_sz+4)
+#define NFS3_createres_sz	(1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
+#define NFS3_renameres_sz	(1+(2 * NFS3_wcc_data_sz))
+#define NFS3_linkres_sz		(1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
+#define NFS3_readdirres_sz	(1+NFS3_post_op_attr_sz+2)
+#define NFS3_fsstatres_sz	(1+NFS3_post_op_attr_sz+13)
+#define NFS3_fsinfores_sz	(1+NFS3_post_op_attr_sz+12)
+#define NFS3_pathconfres_sz	(1+NFS3_post_op_attr_sz+6)
+#define NFS3_commitres_sz	(1+NFS3_wcc_data_sz+2)
 
 /*
  * Map file type to S_IFMT bits
@@ -103,9 +103,7 @@ static struct {
 static inline u32 *
 xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
 {
-	*p++ = htonl(fh->size);
-	memcpy(p, fh->data, fh->size);
-	return p + XDR_QUADLEN(fh->size);
+	return xdr_encode_array(p, fh->data, fh->size);
 }
 
 static inline u32 *
--- diff/fs/nfs/nfs4proc.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/nfs/nfs4proc.c	2004-03-09 11:51:51.000000000 +0000
@@ -54,6 +54,7 @@
 #define GET_OP(cp,name)		&cp->ops[cp->req_nops].u.name
 #define OPNUM(cp)		cp->ops[cp->req_nops].opnum
 
+static int nfs4_proc_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
 static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *);
 extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
 extern struct rpc_procinfo nfs4_procedures[];
@@ -505,6 +506,8 @@ nfs4_open_reclaim(struct nfs4_state_owne
 
 	status = rpc_call_sync(server->client, &msg, 0);
 	nfs4_increment_seqid(status, sp);
+	if (status == 0)
+		memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid));
 	/* Update the inode attributes */
 	nfs_refresh_inode(inode, &fattr);
 	return status;
@@ -689,12 +692,12 @@ nfs4_do_setattr(struct nfs_server *serve
 retry:
         fattr->valid = 0;
 
-	if (state)
+	if (sattr->ia_valid & ATTR_SIZE)
 		nfs4_copy_stateid(&arg.stateid, state, 0);
-        else
+	else
 		memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid));
 
-        status = rpc_call_sync(server->client, &msg, 0);
+	status = rpc_call_sync(server->client, &msg, 0);
 	if (status) {
 		status = nfs4_handle_error(server, status);
 		if (!status)
@@ -822,10 +825,11 @@ nfs4_open_revalidate(struct inode *dir, 
 
 static int
 nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
-		   struct nfs_fattr *fattr)
+		   struct nfs_fsinfo *info)
 {
 	struct nfs4_compound	compound;
 	struct nfs4_op		ops[4];
+	struct nfs_fattr *	fattr = info->fattr;
 	unsigned char *		p;
 	struct qstr		q;
 	int			status;
@@ -869,7 +873,9 @@ nfs4_proc_get_root(struct nfs_server *se
 		break;
 	}
 out:
-	return status;
+	if (status)
+		return status;
+	return nfs4_proc_fsinfo(server, fhandle, info);
 }
 
 static int
@@ -1088,12 +1094,8 @@ nfs4_proc_read(struct nfs_read_data *rda
 
 	fattr->valid = 0;
 	status = rpc_call_sync(server->client, &msg, flags);
-	if (!status) {
+	if (!status)
 		renew_lease(server, timestamp);
-		/* Check cache consistency */
-		if (fattr->change_attr != NFS_CHANGE_ATTR(inode))
-			nfs_zap_caches(inode);
-	}
 	dprintk("NFS reply read: %d\n", status);
 	return status;
 }
@@ -1130,7 +1132,6 @@ nfs4_proc_write(struct nfs_write_data *w
 
 	fattr->valid = 0;
 	status = rpc_call_sync(server->client, &msg, rpcflags);
-	NFS_CACHEINV(inode);
 	dprintk("NFS reply write: %d\n", status);
 	return status;
 }
@@ -1421,6 +1422,8 @@ nfs4_proc_readdir(struct dentry *dentry,
 	nfs4_setup_putfh(&compound, NFS_FH(dir));
 	nfs4_setup_readdir(&compound, cookie, NFS_COOKIEVERF(dir), &page, count, dentry);
 	status = nfs4_call_compound(&compound, cred, 0);
+	if (status == 0)
+		memcpy(NFS_COOKIEVERF(dir), ops[1].u.readdir.rd_resp_verifier.data, NFS4_VERIFIER_SIZE);
 
 	unlock_kernel();
 	return status;
@@ -1463,7 +1466,6 @@ nfs4_proc_statfs(struct nfs_server *serv
 	struct nfs4_compound compound;
 	struct nfs4_op ops[2];
 
-	memset(fsstat, 0, sizeof(*fsstat));
 	nfs4_setup_compound(&compound, ops, server, "statfs");
 	nfs4_setup_putfh(&compound, fhandle);
 	nfs4_setup_statfs(&compound, fsstat);
@@ -1480,7 +1482,6 @@ nfs4_proc_fsinfo(struct nfs_server *serv
 		.rpc_resp = fsinfo,
 	};
 
-	memset(fsinfo, 0, sizeof(*fsinfo));
 	return rpc_call_sync(server->client, &msg, 0);
 }
 
@@ -1491,7 +1492,6 @@ nfs4_proc_pathconf(struct nfs_server *se
 	struct nfs4_compound compound;
 	struct nfs4_op ops[2];
 
-	memset(pathconf, 0, sizeof(*pathconf));
 	nfs4_setup_compound(&compound, ops, server, "statfs");
 	nfs4_setup_putfh(&compound, fhandle);
 	nfs4_setup_pathconf(&compound, pathconf);
@@ -1517,7 +1517,6 @@ nfs4_read_done(struct rpc_task *task)
 {
 	struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata;
 	struct inode *inode = data->inode;
-	struct nfs_fattr *fattr = data->res.fattr;
 
 	if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) {
 		task->tk_action = nfs4_restart_read;
@@ -1525,11 +1524,6 @@ nfs4_read_done(struct rpc_task *task)
 	}
 	if (task->tk_status > 0)
 		renew_lease(NFS_SERVER(inode), data->timestamp);
-	/* Check cache consistency */
-	if (fattr->change_attr != NFS_CHANGE_ATTR(inode))
-		nfs_zap_caches(inode);
-	if (fattr->bitmap[1] & FATTR4_WORD1_TIME_ACCESS)
-		inode->i_atime = fattr->atime;
 	/* Call back common NFS readpage processing */
 	nfs_readpage_result(task);
 }
@@ -1577,21 +1571,6 @@ nfs4_proc_read_setup(struct nfs_read_dat
 }
 
 static void
-nfs4_write_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
-{
-	/* Check cache consistency */
-	if (fattr->pre_change_attr != NFS_CHANGE_ATTR(inode))
-		nfs_zap_caches(inode);
-	NFS_CHANGE_ATTR(inode) = fattr->change_attr;
-	if (fattr->bitmap[1] & FATTR4_WORD1_SPACE_USED)
-		inode->i_blocks = (fattr->du.nfs3.used + 511) >> 9;
-	if (fattr->bitmap[1] & FATTR4_WORD1_TIME_METADATA)
-		inode->i_ctime = fattr->ctime;
-	if (fattr->bitmap[1] & FATTR4_WORD1_TIME_MODIFY)
-		inode->i_mtime = fattr->mtime;
-}
-
-static void
 nfs4_restart_write(struct rpc_task *task)
 {
 	struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata;
@@ -1617,7 +1596,6 @@ nfs4_write_done(struct rpc_task *task)
 	}
 	if (task->tk_status >= 0)
 		renew_lease(NFS_SERVER(inode), data->timestamp);
-	nfs4_write_refresh_inode(inode, data->res.fattr);
 	/* Call back common NFS writeback processing */
 	nfs_writeback_done(task);
 }
@@ -1684,7 +1662,6 @@ nfs4_commit_done(struct rpc_task *task)
 		task->tk_action = nfs4_restart_write;
 		return;
 	}
-	nfs4_write_refresh_inode(inode, data->res.fattr);
 	/* Call back common NFS writeback processing */
 	nfs_commit_done(task);
 }
@@ -1807,6 +1784,7 @@ nfs4_proc_file_open(struct inode *inode,
 	if (filp->f_mode & FMODE_WRITE) {
 		lock_kernel();
 		nfs_set_mmcred(inode, state->owner->so_cred);
+		nfs_begin_data_update(inode);
 		unlock_kernel();
 	}
 	filp->private_data = state;
@@ -1823,6 +1801,11 @@ nfs4_proc_file_release(struct inode *ino
 
 	if (state)
 		nfs4_close_state(state, filp->f_mode);
+	if (filp->f_mode & FMODE_WRITE) {
+		lock_kernel();
+		nfs_end_data_update(inode);
+		unlock_kernel();
+	}
 	return 0;
 }
 
--- diff/fs/nfs/nfs4state.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/nfs/nfs4state.c	2004-03-09 11:51:51.000000000 +0000
@@ -790,7 +790,7 @@ reclaimer(void *ptr)
 restart_loop:
 	spin_lock(&clp->cl_lock);
 	list_for_each_entry(sp, &clp->cl_state_owners, so_list) {
-		if (sp->so_generation - generation <= 0)
+		if (sp->so_generation - generation >= 0)
 			continue;
 		atomic_inc(&sp->so_count);
 		spin_unlock(&clp->cl_lock);
--- diff/fs/nfs/nfs4xdr.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/nfs/nfs4xdr.c	2004-03-09 11:51:51.000000000 +0000
@@ -69,84 +69,84 @@ static int nfs_stat_to_errno(int);
 /* lock,open owner id: 
  * we currently use size 1 (u32) out of (NFS4_OPAQUE_LIMIT  >> 2)
  */
-#define owner_id_maxsz          1 + 1
-#define compound_encode_hdr_maxsz	3 + (NFS4_MAXTAGLEN >> 2)
-#define compound_decode_hdr_maxsz	2 + (NFS4_MAXTAGLEN >> 2)
-#define op_encode_hdr_maxsz	1
-#define op_decode_hdr_maxsz	2
-#define encode_putfh_maxsz	op_encode_hdr_maxsz + 1 + \
-				(NFS4_FHSIZE >> 2)
-#define decode_putfh_maxsz	op_decode_hdr_maxsz
-#define encode_putrootfh_maxsz	op_encode_hdr_maxsz
-#define decode_putrootfh_maxsz	op_decode_hdr_maxsz
-#define encode_getfh_maxsz      op_encode_hdr_maxsz
-#define decode_getfh_maxsz      op_decode_hdr_maxsz + 1 + \
-                                (NFS4_FHSIZE >> 2)
-#define encode_getattr_maxsz    op_encode_hdr_maxsz + 3
-#define nfs4_fattr_bitmap_maxsz 26 + 2 * ((NFS4_MAXNAMLEN +1) >> 2)
-#define decode_getattr_maxsz    op_decode_hdr_maxsz + 3 + \
-                                nfs4_fattr_bitmap_maxsz
-#define encode_savefh_maxsz     op_encode_hdr_maxsz
-#define decode_savefh_maxsz     op_decode_hdr_maxsz
-#define encode_restorefh_maxsz  op_encode_hdr_maxsz
-#define decode_restorefh_maxsz  op_decode_hdr_maxsz
-#define encode_read_getattr_maxsz	op_encode_hdr_maxsz + 2
-#define decode_read_getattr_maxsz	op_decode_hdr_maxsz + 8
-#define encode_pre_write_getattr_maxsz	op_encode_hdr_maxsz + 2
-#define decode_pre_write_getattr_maxsz	op_decode_hdr_maxsz + 5
-#define encode_post_write_getattr_maxsz	op_encode_hdr_maxsz + 2
-#define decode_post_write_getattr_maxsz	op_decode_hdr_maxsz + 13
-#define encode_fsinfo_maxsz	op_encode_hdr_maxsz + 2
-#define decode_fsinfo_maxsz	op_decode_hdr_maxsz + 11
-#define encode_renew_maxsz	op_encode_hdr_maxsz + 3
-#define decode_renew_maxsz	op_decode_hdr_maxsz
+#define owner_id_maxsz          (1 + 1)
+#define compound_encode_hdr_maxsz	(3 + (NFS4_MAXTAGLEN >> 2))
+#define compound_decode_hdr_maxsz	(3 + (NFS4_MAXTAGLEN >> 2))
+#define op_encode_hdr_maxsz	(1)
+#define op_decode_hdr_maxsz	(2)
+#define encode_putfh_maxsz	(op_encode_hdr_maxsz + 1 + \
+				(NFS4_FHSIZE >> 2))
+#define decode_putfh_maxsz	(op_decode_hdr_maxsz)
+#define encode_putrootfh_maxsz	(op_encode_hdr_maxsz)
+#define decode_putrootfh_maxsz	(op_decode_hdr_maxsz)
+#define encode_getfh_maxsz      (op_encode_hdr_maxsz)
+#define decode_getfh_maxsz      (op_decode_hdr_maxsz + 1 + \
+                                (NFS4_FHSIZE >> 2))
+#define encode_getattr_maxsz    (op_encode_hdr_maxsz + 3)
+#define nfs4_fattr_bitmap_maxsz (26 + 2 * ((NFS4_MAXNAMLEN +1) >> 2))
+#define decode_getattr_maxsz    (op_decode_hdr_maxsz + 3 + \
+                                nfs4_fattr_bitmap_maxsz)
+#define encode_savefh_maxsz     (op_encode_hdr_maxsz)
+#define decode_savefh_maxsz     (op_decode_hdr_maxsz)
+#define encode_restorefh_maxsz  (op_encode_hdr_maxsz)
+#define decode_restorefh_maxsz  (op_decode_hdr_maxsz)
+#define encode_read_getattr_maxsz	(op_encode_hdr_maxsz + 2)
+#define decode_read_getattr_maxsz	(op_decode_hdr_maxsz + 8)
+#define encode_pre_write_getattr_maxsz	(op_encode_hdr_maxsz + 2)
+#define decode_pre_write_getattr_maxsz	(op_decode_hdr_maxsz + 5)
+#define encode_post_write_getattr_maxsz	(op_encode_hdr_maxsz + 2)
+#define decode_post_write_getattr_maxsz	(op_decode_hdr_maxsz + 13)
+#define encode_fsinfo_maxsz	(op_encode_hdr_maxsz + 2)
+#define decode_fsinfo_maxsz	(op_decode_hdr_maxsz + 11)
+#define encode_renew_maxsz	(op_encode_hdr_maxsz + 3)
+#define decode_renew_maxsz	(op_decode_hdr_maxsz)
 #define encode_setclientid_maxsz \
-				op_encode_hdr_maxsz + \
+				(op_encode_hdr_maxsz + \
 				4 /*server->ip_addr*/ + \
 				1 /*Netid*/ + \
 				6 /*uaddr*/ + \
-				6 + (NFS4_VERIFIER_SIZE >> 2)
+				6 + (NFS4_VERIFIER_SIZE >> 2))
 #define decode_setclientid_maxsz \
-				op_decode_hdr_maxsz + \
+				(op_decode_hdr_maxsz + \
 				2 + \
-				1024 /* large value for CLID_INUSE */
+				1024) /* large value for CLID_INUSE */
 #define encode_setclientid_confirm_maxsz \
-				op_encode_hdr_maxsz + \
-				3 + (NFS4_VERIFIER_SIZE >> 2)
+				(op_encode_hdr_maxsz + \
+				3 + (NFS4_VERIFIER_SIZE >> 2))
 #define decode_setclientid_confirm_maxsz \
-				op_decode_hdr_maxsz
+				(op_decode_hdr_maxsz)
 
-#define NFS4_enc_compound_sz	1024  /* XXX: large enough? */
-#define NFS4_dec_compound_sz	1024  /* XXX: large enough? */
-#define NFS4_enc_read_sz	compound_encode_hdr_maxsz + \
+#define NFS4_enc_compound_sz	(1024)  /* XXX: large enough? */
+#define NFS4_dec_compound_sz	(1024)  /* XXX: large enough? */
+#define NFS4_enc_read_sz	(compound_encode_hdr_maxsz + \
 				encode_putfh_maxsz + \
 				encode_read_getattr_maxsz + \
-				op_encode_hdr_maxsz + 7
-#define NFS4_dec_read_sz	compound_decode_hdr_maxsz + \
+				op_encode_hdr_maxsz + 7)
+#define NFS4_dec_read_sz	(compound_decode_hdr_maxsz + \
 				decode_putfh_maxsz + \
 				decode_read_getattr_maxsz + \
-				op_decode_hdr_maxsz + 2
-#define NFS4_enc_write_sz	compound_encode_hdr_maxsz + \
+				op_decode_hdr_maxsz + 2)
+#define NFS4_enc_write_sz	(compound_encode_hdr_maxsz + \
 				encode_putfh_maxsz + \
 				encode_pre_write_getattr_maxsz + \
 				op_encode_hdr_maxsz + 8 + \
-				encode_post_write_getattr_maxsz
-#define NFS4_dec_write_sz	compound_decode_hdr_maxsz + \
+				encode_post_write_getattr_maxsz)
+#define NFS4_dec_write_sz	(compound_decode_hdr_maxsz + \
 				decode_putfh_maxsz + \
 				decode_pre_write_getattr_maxsz + \
 				op_decode_hdr_maxsz + 4 + \
-				decode_post_write_getattr_maxsz
-#define NFS4_enc_commit_sz	compound_encode_hdr_maxsz + \
+				decode_post_write_getattr_maxsz)
+#define NFS4_enc_commit_sz	(compound_encode_hdr_maxsz + \
 				encode_putfh_maxsz + \
 				encode_pre_write_getattr_maxsz + \
 				op_encode_hdr_maxsz + 3 + \
-				encode_post_write_getattr_maxsz
-#define NFS4_dec_commit_sz	compound_decode_hdr_maxsz + \
+				encode_post_write_getattr_maxsz)
+#define NFS4_dec_commit_sz	(compound_decode_hdr_maxsz + \
 				decode_putfh_maxsz + \
 				decode_pre_write_getattr_maxsz + \
 				op_decode_hdr_maxsz + 2 + \
-				decode_post_write_getattr_maxsz
-#define NFS4_enc_open_sz        compound_encode_hdr_maxsz + \
+				decode_post_write_getattr_maxsz)
+#define NFS4_enc_open_sz        (compound_encode_hdr_maxsz + \
                                 encode_putfh_maxsz + \
                                 encode_savefh_maxsz + \
                                 op_encode_hdr_maxsz + \
@@ -154,107 +154,107 @@ static int nfs_stat_to_errno(int);
                                 encode_getattr_maxsz + \
                                 encode_getfh_maxsz + \
                                 encode_restorefh_maxsz + \
-                                encode_getattr_maxsz
-#define NFS4_dec_open_sz        compound_decode_hdr_maxsz + \
+                                encode_getattr_maxsz)
+#define NFS4_dec_open_sz        (compound_decode_hdr_maxsz + \
                                 decode_putfh_maxsz + \
                                 decode_savefh_maxsz + \
                                 op_decode_hdr_maxsz + 4 + 5 + 2 + 3 + \
                                 decode_getattr_maxsz + \
                                 decode_getfh_maxsz + \
                                 decode_restorefh_maxsz + \
-                                decode_getattr_maxsz
+                                decode_getattr_maxsz)
 #define NFS4_enc_open_confirm_sz      \
-                                compound_encode_hdr_maxsz + \
+                                (compound_encode_hdr_maxsz + \
                                 encode_putfh_maxsz + \
-                                op_encode_hdr_maxsz + 5
-#define NFS4_dec_open_confirm_sz        compound_decode_hdr_maxsz + \
+                                op_encode_hdr_maxsz + 5)
+#define NFS4_dec_open_confirm_sz        (compound_decode_hdr_maxsz + \
                                         decode_putfh_maxsz + \
-                                        op_decode_hdr_maxsz + 4
-#define NFS4_enc_open_reclaim_sz	compound_encode_hdr_maxsz + \
+                                        op_decode_hdr_maxsz + 4)
+#define NFS4_enc_open_reclaim_sz	(compound_encode_hdr_maxsz + \
 					encode_putfh_maxsz + \
 					op_encode_hdr_maxsz + \
 					11 + \
-					encode_getattr_maxsz
-#define NFS4_dec_open_reclaim_sz	compound_decode_hdr_maxsz + \
+					encode_getattr_maxsz)
+#define NFS4_dec_open_reclaim_sz	(compound_decode_hdr_maxsz + \
 					decode_putfh_maxsz + \
 					op_decode_hdr_maxsz + \
 					4 + 5 + 2 + 3 + \
-					decode_getattr_maxsz
+					decode_getattr_maxsz)
 #define NFS4_enc_open_downgrade_sz \
-				compound_encode_hdr_maxsz + \
+				(compound_encode_hdr_maxsz + \
                                 encode_putfh_maxsz + \
-                                op_encode_hdr_maxsz + 7
+                                op_encode_hdr_maxsz + 7)
 #define NFS4_dec_open_downgrade_sz \
-				compound_decode_hdr_maxsz + \
+				(compound_decode_hdr_maxsz + \
                                 decode_putfh_maxsz + \
-                                op_decode_hdr_maxsz + 4
-#define NFS4_enc_close_sz       compound_encode_hdr_maxsz + \
+                                op_decode_hdr_maxsz + 4)
+#define NFS4_enc_close_sz       (compound_encode_hdr_maxsz + \
                                 encode_putfh_maxsz + \
-                                op_encode_hdr_maxsz + 5
-#define NFS4_dec_close_sz       compound_decode_hdr_maxsz + \
+                                op_encode_hdr_maxsz + 5)
+#define NFS4_dec_close_sz       (compound_decode_hdr_maxsz + \
                                 decode_putfh_maxsz + \
-                                op_decode_hdr_maxsz + 4
-#define NFS4_enc_setattr_sz     compound_encode_hdr_maxsz + \
+                                op_decode_hdr_maxsz + 4)
+#define NFS4_enc_setattr_sz     (compound_encode_hdr_maxsz + \
                                 encode_putfh_maxsz + \
                                 op_encode_hdr_maxsz + 4 + \
                                 nfs4_fattr_bitmap_maxsz + \
-                                encode_getattr_maxsz
-#define NFS4_dec_setattr_sz     compound_decode_hdr_maxsz + \
+                                encode_getattr_maxsz)
+#define NFS4_dec_setattr_sz     (compound_decode_hdr_maxsz + \
                                 decode_putfh_maxsz + \
-                                op_decode_hdr_maxsz + 3
-#define NFS4_enc_fsinfo_sz	compound_encode_hdr_maxsz + \
+                                op_decode_hdr_maxsz + 3)
+#define NFS4_enc_fsinfo_sz	(compound_encode_hdr_maxsz + \
 				encode_putfh_maxsz + \
-				encode_fsinfo_maxsz
-#define NFS4_dec_fsinfo_sz	compound_decode_hdr_maxsz + \
+				encode_fsinfo_maxsz)
+#define NFS4_dec_fsinfo_sz	(compound_decode_hdr_maxsz + \
 				decode_putfh_maxsz + \
-				decode_fsinfo_maxsz
-#define NFS4_enc_renew_sz	compound_encode_hdr_maxsz + \
-				encode_renew_maxsz
-#define NFS4_dec_renew_sz	compound_decode_hdr_maxsz + \
-				decode_renew_maxsz
-#define NFS4_enc_setclientid_sz	compound_encode_hdr_maxsz + \
-				encode_setclientid_maxsz
-#define NFS4_dec_setclientid_sz	compound_decode_hdr_maxsz + \
-				decode_setclientid_maxsz
+				decode_fsinfo_maxsz)
+#define NFS4_enc_renew_sz	(compound_encode_hdr_maxsz + \
+				encode_renew_maxsz)
+#define NFS4_dec_renew_sz	(compound_decode_hdr_maxsz + \
+				decode_renew_maxsz)
+#define NFS4_enc_setclientid_sz	(compound_encode_hdr_maxsz + \
+				encode_setclientid_maxsz)
+#define NFS4_dec_setclientid_sz	(compound_decode_hdr_maxsz + \
+				decode_setclientid_maxsz)
 #define NFS4_enc_setclientid_confirm_sz \
-				compound_encode_hdr_maxsz + \
+				(compound_encode_hdr_maxsz + \
 				encode_setclientid_confirm_maxsz + \
 				encode_putrootfh_maxsz + \
-				encode_fsinfo_maxsz
+				encode_fsinfo_maxsz)
 #define NFS4_dec_setclientid_confirm_sz \
-				compound_decode_hdr_maxsz + \
+				(compound_decode_hdr_maxsz + \
 				decode_setclientid_confirm_maxsz + \
 				decode_putrootfh_maxsz + \
-				decode_fsinfo_maxsz
-#define NFS4_enc_lock_sz        compound_encode_hdr_maxsz + \
+				decode_fsinfo_maxsz)
+#define NFS4_enc_lock_sz        (compound_encode_hdr_maxsz + \
 				encode_putfh_maxsz + \
 				encode_getattr_maxsz + \
 				op_encode_hdr_maxsz + \
 				1 + 1 + 2 + 2 + \
 				1 + 4 + 1 + 2 + \
-				owner_id_maxsz
-#define NFS4_dec_lock_sz        compound_decode_hdr_maxsz + \
+				owner_id_maxsz)
+#define NFS4_dec_lock_sz        (compound_decode_hdr_maxsz + \
 				decode_putfh_maxsz + \
 				decode_getattr_maxsz + \
 				op_decode_hdr_maxsz + \
 				2 + 2 + 1 + 2 + \
-				owner_id_maxsz
-#define NFS4_enc_lockt_sz       compound_encode_hdr_maxsz + \
+				owner_id_maxsz)
+#define NFS4_enc_lockt_sz       (compound_encode_hdr_maxsz + \
 				encode_putfh_maxsz + \
 				encode_getattr_maxsz + \
 				op_encode_hdr_maxsz + \
 				1 + 2 + 2 + 2 + \
-				owner_id_maxsz
-#define NFS4_dec_lockt_sz       NFS4_dec_lock_sz
-#define NFS4_enc_locku_sz       compound_encode_hdr_maxsz + \
+				owner_id_maxsz)
+#define NFS4_dec_lockt_sz       (NFS4_dec_lock_sz)
+#define NFS4_enc_locku_sz       (compound_encode_hdr_maxsz + \
 				encode_putfh_maxsz + \
 				encode_getattr_maxsz + \
 				op_encode_hdr_maxsz + \
-				1 + 1 + 4 + 2 + 2
-#define NFS4_dec_locku_sz       compound_decode_hdr_maxsz + \
+				1 + 1 + 4 + 2 + 2)
+#define NFS4_dec_locku_sz       (compound_decode_hdr_maxsz + \
 				decode_putfh_maxsz + \
 				decode_getattr_maxsz + \
-				op_decode_hdr_maxsz + 4
+				op_decode_hdr_maxsz + 4)
 
 
 
@@ -324,7 +324,7 @@ encode_compound_hdr(struct xdr_stream *x
 
 	dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag);
 	BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
-	RESERVE_SPACE(12+XDR_QUADLEN(hdr->taglen));
+	RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2));
 	WRITE32(hdr->taglen);
 	WRITEMEM(hdr->tag, hdr->taglen);
 	WRITE32(NFS4_MINOR_VERSION);
@@ -3165,6 +3165,10 @@ static struct {
 	{ NFS4ERR_SYMLINK,	ELOOP		},
 	{ NFS4ERR_OP_ILLEGAL,	EOPNOTSUPP	},
 	{ NFS4ERR_DEADLOCK,	EDEADLK		},
+	{ NFS4ERR_WRONGSEC,	EPERM		}, /* FIXME: this needs
+						    * to be handled by a
+						    * middle-layer.
+						    */
 	{ -1,			EIO		}
 };
 
--- diff/fs/nfs/nfsroot.c	2003-08-26 10:00:54.000000000 +0100
+++ source/fs/nfs/nfsroot.c	2004-03-09 11:51:51.000000000 +0000
@@ -166,37 +166,6 @@ static struct nfs_bool_opts {
 
 
 /*
- *  Extract IP address from the parameter string if needed. Note that we
- *  need to have root_server_addr set _before_ IPConfig gets called as it
- *  can override it.
- */
-static void __init root_nfs_parse_addr(char *name)
-{
-	int octets = 0;
-	char *cp, *cq;
-
-	cp = cq = name;
-	while (octets < 4) {
-		while (*cp >= '0' && *cp <= '9')
-			cp++;
-		if (cp == cq || cp - cq > 3)
-			break;
-		if (*cp == '.' || octets == 3)
-			octets++;
-		if (octets < 4)
-			cp++;
-		cq = cp;
-	}
-	if (octets == 4 && (*cp == ':' || *cp == '\0')) {
-		if (*cp == ':')
-			*cp++ = '\0';
-		root_server_addr = in_aton(name);
-		strcpy(name, cp);
-	}
-}
-
-
-/*
  *  Parse option string.
  */
 static void __init root_nfs_parse(char *name, char *buf)
@@ -345,7 +314,7 @@ int __init nfs_root_setup(char *line)
 			line[sizeof(nfs_root_name) - strlen(NFS_ROOT) - 1] = '\0';
 		sprintf(nfs_root_name, NFS_ROOT, line);
 	}
-	root_nfs_parse_addr(nfs_root_name);
+	root_server_addr = root_nfs_parse_addr(nfs_root_name);
 	return 1;
 }
 
--- diff/fs/nfs/pagelist.c	2003-10-27 09:20:39.000000000 +0000
+++ source/fs/nfs/pagelist.c	2004-03-09 11:51:51.000000000 +0000
@@ -246,7 +246,6 @@ nfs_coalesce_requests(struct list_head *
  * nfs_scan_list - Scan a list for matching requests
  * @head: One of the NFS inode request lists
  * @dst: Destination list
- * @file: if set, ensure we match requests from this file
  * @idx_start: lower bound of page->index to scan
  * @npages: idx_start + npages sets the upper bound to scan.
  *
@@ -258,7 +257,6 @@ nfs_coalesce_requests(struct list_head *
  */
 int
 nfs_scan_list(struct list_head *head, struct list_head *dst,
-	      struct file *file,
 	      unsigned long idx_start, unsigned int npages)
 {
 	struct list_head	*pos, *tmp;
@@ -276,9 +274,6 @@ nfs_scan_list(struct list_head *head, st
 
 		req = nfs_list_entry(pos);
 
-		if (file && req->wb_file != file)
-			continue;
-
 		if (req->wb_index < idx_start)
 			continue;
 		if (req->wb_index > idx_end)
--- diff/fs/nfs/proc.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/nfs/proc.c	2004-03-09 11:51:51.000000000 +0000
@@ -49,18 +49,6 @@
 
 extern struct rpc_procinfo nfs_procedures[];
 
-static void
-nfs_write_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
-{
-	if (!(fattr->valid & NFS_ATTR_WCC)) {
-		fattr->pre_size  = NFS_CACHE_ISIZE(inode);
-		fattr->pre_mtime = NFS_CACHE_MTIME(inode);
-		fattr->pre_ctime = NFS_CACHE_CTIME(inode);
-		fattr->valid |= NFS_ATTR_WCC;
-	}
-	nfs_refresh_inode(inode, fattr);
-}
-
 static struct rpc_cred *
 nfs_cred(struct inode *inode, struct file *filp)
 {
@@ -78,15 +66,33 @@ nfs_cred(struct inode *inode, struct fil
  */
 static int
 nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
-		  struct nfs_fattr *fattr)
+		  struct nfs_fsinfo *info)
 {
-	int		status;
+	struct nfs_fattr *fattr = info->fattr;
+	struct nfs2_fsstat fsinfo;
+	int status;
 
-	dprintk("NFS call  getroot\n");
+	dprintk("%s: call getattr\n", __FUNCTION__);
 	fattr->valid = 0;
-	status = rpc_call(server->client, NFSPROC_GETATTR, fhandle, fattr, 0);
-	dprintk("NFS reply getroot\n");
-	return status;
+	status = rpc_call(server->client_sys, NFSPROC_GETATTR, fhandle, fattr, 0);
+	dprintk("%s: reply getattr %d\n", __FUNCTION__, status);
+	if (status)
+		return status;
+	dprintk("%s: call statfs\n", __FUNCTION__);
+	status = rpc_call(server->client_sys, NFSPROC_STATFS, fhandle, &fsinfo, 0);
+	dprintk("%s: reply statfs %d\n", __FUNCTION__, status);
+	if (status)
+		return status;
+	info->rtmax  = NFS_MAXDATA;
+	info->rtpref = fsinfo.tsize;
+	info->rtmult = fsinfo.bsize;
+	info->wtmax  = NFS_MAXDATA;
+	info->wtpref = fsinfo.tsize;
+	info->wtmult = fsinfo.bsize;
+	info->dtpref = fsinfo.tsize;
+	info->maxfilesize = 0x7FFFFFFF;
+	info->lease_time = 0;
+	return 0;
 }
 
 /*
@@ -180,8 +186,14 @@ nfs_proc_read(struct nfs_read_data *rdat
 	msg.rpc_cred = nfs_cred(inode, filp);
 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
 
-	if (status >= 0)
+	if (status >= 0) {
 		nfs_refresh_inode(inode, fattr);
+		/* Emulate the eof flag, which isn't normally needed in NFSv2
+		 * as it is guaranteed to always return the file attributes
+		 */
+		if (rdata->args.offset + rdata->args.count >= fattr->size)
+			rdata->res.eof = 1;
+	}
 	dprintk("NFS reply read: %d\n", status);
 	return status;
 }
@@ -205,7 +217,7 @@ nfs_proc_write(struct nfs_write_data *wd
 	msg.rpc_cred = nfs_cred(inode, filp);
 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
 	if (status >= 0) {
-		nfs_write_refresh_inode(inode, fattr);
+		nfs_refresh_inode(inode, fattr);
 		wdata->res.count = wdata->args.count;
 		wdata->verf.committed = NFS_FILE_SYNC;
 	}
@@ -331,10 +343,8 @@ nfs_proc_unlink_done(struct dentry *dir,
 {
 	struct rpc_message *msg = &task->tk_msg;
 	
-	if (msg->rpc_argp) {
-		NFS_CACHEINV(dir->d_inode);
+	if (msg->rpc_argp)
 		kfree(msg->rpc_argp);
-	}
 	return 0;
 }
 
@@ -537,8 +547,14 @@ nfs_read_done(struct rpc_task *task)
 {
 	struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata;
 
-	if (task->tk_status >= 0)
+	if (task->tk_status >= 0) {
 		nfs_refresh_inode(data->inode, data->res.fattr);
+		/* Emulate the eof flag, which isn't normally needed in NFSv2
+		 * as it is guaranteed to always return the file attributes
+		 */
+		if (data->args.offset + data->args.count >= data->res.fattr->size)
+			data->res.eof = 1;
+	}
 	nfs_readpage_result(task);
 }
 
@@ -584,7 +600,7 @@ nfs_write_done(struct rpc_task *task)
 	struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
 
 	if (task->tk_status >= 0)
-		nfs_write_refresh_inode(data->inode, data->res.fattr);
+		nfs_refresh_inode(data->inode, data->res.fattr);
 	nfs_writeback_done(task);
 }
 
--- diff/fs/nfs/read.c	2003-10-09 09:47:34.000000000 +0100
+++ source/fs/nfs/read.c	2004-03-09 11:51:51.000000000 +0000
@@ -121,9 +121,13 @@ nfs_readpage_sync(struct file *file, str
 		}
 		count -= result;
 		rdata.args.pgbase += result;
-		if (result < rdata.args.count)	/* NFSv2ism */
+		/* Note: result == 0 should only happen if we're caching
+		 * a write that extends the file and punches a hole.
+		 */
+		if (rdata.res.eof != 0 || result == 0)
 			break;
 	} while (count);
+	NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME;
 
 	if (count)
 		memclear_highpage_flush(page, rdata.args.pgbase, count);
@@ -266,6 +270,7 @@ nfs_readpage_result(struct rpc_task *tas
 	dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
 		task->tk_pid, task->tk_status);
 
+	NFS_FLAGS(data->inode) |= NFS_INO_INVALID_ATIME;
 	while (!list_empty(&data->pages)) {
 		struct nfs_page *req = nfs_list_entry(data->pages.next);
 		struct page *page = req->wb_page;
--- diff/fs/nfs/unlink.c	2003-06-30 10:07:24.000000000 +0100
+++ source/fs/nfs/unlink.c	2004-03-09 11:51:51.000000000 +0000
@@ -104,6 +104,7 @@ nfs_async_unlink_init(struct rpc_task *t
 	status = NFS_PROTO(dir->d_inode)->unlink_setup(&msg, dir, &data->name);
 	if (status < 0)
 		goto out_err;
+	nfs_begin_data_update(dir->d_inode);
 	rpc_call_setup(task, &msg, 0);
 	return;
  out_err:
@@ -126,7 +127,7 @@ nfs_async_unlink_done(struct rpc_task *t
 	if (!dir)
 		return;
 	dir_i = dir->d_inode;
-	nfs_zap_caches(dir_i);
+	nfs_end_data_update(dir_i);
 	if (NFS_PROTO(dir_i)->unlink_done(dir, task))
 		return;
 	put_rpccred(data->cred);
--- diff/fs/nfs/write.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/nfs/write.c	2004-03-09 11:51:51.000000000 +0000
@@ -74,7 +74,6 @@
 static struct nfs_page * nfs_update_request(struct file*, struct inode *,
 					    struct page *,
 					    unsigned int, unsigned int);
-static void	nfs_strategy(struct inode *inode);
 
 static kmem_cache_t *nfs_wdata_cachep;
 static mempool_t *nfs_wdata_mempool;
@@ -124,6 +123,52 @@ void nfs_commit_release(struct rpc_task 
 	nfs_commit_free(wdata);
 }
 
+/* Adjust the file length if we're writing beyond the end */
+static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count)
+{
+	struct inode *inode = page->mapping->host;
+	loff_t end, i_size = i_size_read(inode);
+	unsigned long end_index = (i_size - 1) >> PAGE_CACHE_SHIFT;
+
+	if (i_size > 0 && page->index < end_index)
+		return;
+	end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + ((loff_t)offset+count);
+	if (i_size >= end)
+		return;
+	i_size_write(inode, end);
+}
+
+/* We can set the PG_uptodate flag if we see that a write request
+ * covers the full page.
+ */
+static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int count)
+{
+	loff_t end_offs;
+
+	if (PageUptodate(page))
+		return;
+	if (base != 0)
+		return;
+	if (count == PAGE_CACHE_SIZE) {
+		SetPageUptodate(page);
+		return;
+	}
+
+	end_offs = i_size_read(page->mapping->host) - 1;
+	if (end_offs < 0)
+		return;
+	/* Is this the last page? */
+	if (page->index != (unsigned long)(end_offs >> PAGE_CACHE_SHIFT))
+		return;
+	/* This is the last page: set PG_uptodate if we cover the entire
+	 * extent of the data, then zero the rest of the page.
+	 */
+	if (count == (unsigned int)(end_offs & (PAGE_CACHE_SIZE - 1)) + 1) {
+		memclear_highpage_flush(page, count, PAGE_CACHE_SIZE - count);
+		SetPageUptodate(page);
+	}
+}
+
 /*
  * Write a page synchronously.
  * Offset is the data offset within the page.
@@ -157,6 +202,7 @@ nfs_writepage_sync(struct file *file, st
 		(long long)NFS_FILEID(inode),
 		count, (long long)(page_offset(page) + offset));
 
+	nfs_begin_data_update(inode);
 	do {
 		if (count < wsize && !swapfile)
 			wdata.args.count = count;
@@ -177,14 +223,12 @@ nfs_writepage_sync(struct file *file, st
 	        wdata.args.pgbase += result;
 		written += result;
 		count -= result;
-
-		/*
-		 * If we've extended the file, update the inode
-		 * now so we don't invalidate the cache.
-		 */
-		if (wdata.args.offset > i_size_read(inode))
-			i_size_write(inode, wdata.args.offset);
 	} while (count);
+	/* Update file length */
+	nfs_grow_file(page, offset, written);
+	/* Set the PG_uptodate flag? */
+	nfs_mark_uptodate(page, offset, written);
+	nfs_end_data_update(inode);
 
 	if (PageError(page))
 		ClearPageError(page);
@@ -201,18 +245,19 @@ nfs_writepage_async(struct file *file, s
 		    unsigned int offset, unsigned int count)
 {
 	struct nfs_page	*req;
-	loff_t		end;
 	int		status;
 
+	nfs_begin_data_update(inode);
 	req = nfs_update_request(file, inode, page, offset, count);
 	status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
 	if (status < 0)
 		goto out;
+	/* Update file length */
+	nfs_grow_file(page, offset, count);
+	/* Set the PG_uptodate flag? */
+	nfs_mark_uptodate(page, offset, count);
 	nfs_unlock_request(req);
-	nfs_strategy(inode);
-	end = ((loff_t)page->index<<PAGE_CACHE_SHIFT) + (loff_t)(offset + count);
-	if (i_size_read(inode) < end)
-		i_size_write(inode, end);
+	nfs_end_data_update(inode);
 
  out:
 	return status;
@@ -286,7 +331,7 @@ nfs_writepages(struct address_space *map
 	err = generic_writepages(mapping, wbc);
 	if (err)
 		goto out;
-	err = nfs_flush_file(inode, NULL, 0, 0, 0);
+	err = nfs_flush_inode(inode, 0, 0, 0);
 	if (err < 0)
 		goto out;
 	if (wbc->sync_mode == WB_SYNC_HOLD)
@@ -294,7 +339,7 @@ nfs_writepages(struct address_space *map
 	if (is_sync && wbc->sync_mode == WB_SYNC_ALL) {
 		err = nfs_wb_all(inode);
 	} else
-		nfs_commit_file(inode, NULL, 0, 0, 0);
+		nfs_commit_inode(inode, 0, 0, 0);
 out:
 	return err;
 }
@@ -312,8 +357,10 @@ nfs_inode_add_request(struct inode *inod
 	BUG_ON(error == -EEXIST);
 	if (error)
 		return error;
-	if (!nfsi->npages)
+	if (!nfsi->npages) {
 		igrab(inode);
+		nfs_begin_data_update(inode);
+	}
 	nfsi->npages++;
 	req->wb_count++;
 	return 0;
@@ -336,6 +383,7 @@ nfs_inode_remove_request(struct nfs_page
 	nfsi->npages--;
 	if (!nfsi->npages) {
 		spin_unlock(&nfs_wreq_lock);
+		nfs_end_data_update(inode);
 		iput(inode);
 	} else
 		spin_unlock(&nfs_wreq_lock);
@@ -421,7 +469,7 @@ nfs_mark_request_commit(struct nfs_page 
  * Interruptible by signals only if mounted with intr flag.
  */
 static int
-nfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long idx_start, unsigned int npages)
+nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, unsigned int npages)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
 	struct nfs_page *req;
@@ -441,8 +489,6 @@ nfs_wait_on_requests(struct inode *inode
 			break;
 
 		next = req->wb_index + 1;
-		if (file && req->wb_file != file)
-			continue;
 		if (!NFS_WBACK_BUSY(req))
 			continue;
 
@@ -453,7 +499,6 @@ nfs_wait_on_requests(struct inode *inode
 		if (error < 0)
 			return error;
 		spin_lock(&nfs_wreq_lock);
-		next = idx_start;
 		res++;
 	}
 	spin_unlock(&nfs_wreq_lock);
@@ -464,7 +509,6 @@ nfs_wait_on_requests(struct inode *inode
  * nfs_scan_dirty - Scan an inode for dirty requests
  * @inode: NFS inode to scan
  * @dst: destination list
- * @file: if set, ensure we match requests from this file
  * @idx_start: lower bound of page->index to scan.
  * @npages: idx_start + npages sets the upper bound to scan.
  *
@@ -472,11 +516,11 @@ nfs_wait_on_requests(struct inode *inode
  * The requests are *not* checked to ensure that they form a contiguous set.
  */
 static int
-nfs_scan_dirty(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
+nfs_scan_dirty(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
 	int	res;
-	res = nfs_scan_list(&nfsi->dirty, dst, file, idx_start, npages);
+	res = nfs_scan_list(&nfsi->dirty, dst, idx_start, npages);
 	nfsi->ndirty -= res;
 	sub_page_state(nr_dirty,res);
 	if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty))
@@ -489,7 +533,6 @@ nfs_scan_dirty(struct inode *inode, stru
  * nfs_scan_commit - Scan an inode for commit requests
  * @inode: NFS inode to scan
  * @dst: destination list
- * @file: if set, ensure we collect requests from this file only.
  * @idx_start: lower bound of page->index to scan.
  * @npages: idx_start + npages sets the upper bound to scan.
  *
@@ -497,11 +540,11 @@ nfs_scan_dirty(struct inode *inode, stru
  * The requests are *not* checked to ensure that they form a contiguous set.
  */
 static int
-nfs_scan_commit(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
+nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
 	int	res;
-	res = nfs_scan_list(&nfsi->commit, dst, file, idx_start, npages);
+	res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages);
 	nfsi->ncommit -= res;
 	if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit))
 		printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");
@@ -600,46 +643,6 @@ nfs_update_request(struct file* file, st
 	return req;
 }
 
-/*
- * This is the strategy routine for NFS.
- * It is called by nfs_updatepage whenever the user wrote up to the end
- * of a page.
- *
- * We always try to submit a set of requests in parallel so that the
- * server's write code can gather writes. This is mainly for the benefit
- * of NFSv2.
- *
- * We never submit more requests than we think the remote can handle.
- * For UDP sockets, we make sure we don't exceed the congestion window;
- * for TCP, we limit the number of requests to 8.
- *
- * NFS_STRATEGY_PAGES gives the minimum number of requests for NFSv2 that
- * should be sent out in one go. This is for the benefit of NFSv2 servers
- * that perform write gathering.
- *
- * FIXME: Different servers may have different sweet spots.
- * Record the average congestion window in server struct?
- */
-#define NFS_STRATEGY_PAGES      8
-static void
-nfs_strategy(struct inode *inode)
-{
-	unsigned int	dirty, wpages;
-
-	dirty  = NFS_I(inode)->ndirty;
-	wpages = NFS_SERVER(inode)->wpages;
-#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
-	if (NFS_PROTO(inode)->version == 2) {
-		if (dirty >= NFS_STRATEGY_PAGES * wpages)
-			nfs_flush_file(inode, NULL, 0, 0, 0);
-	} else if (dirty >= wpages)
-		nfs_flush_file(inode, NULL, 0, 0, 0);
-#else
-	if (dirty >= NFS_STRATEGY_PAGES * wpages)
-		nfs_flush_file(inode, NULL, 0, 0, 0);
-#endif
-}
-
 int
 nfs_flush_incompatible(struct file *file, struct page *page)
 {
@@ -675,7 +678,6 @@ nfs_updatepage(struct file *file, struct
 	struct dentry	*dentry = file->f_dentry;
 	struct inode	*inode = page->mapping->host;
 	struct nfs_page	*req;
-	loff_t		end;
 	int		status = 0;
 
 	dprintk("NFS:      nfs_updatepage(%s/%s %d@%Ld)\n",
@@ -696,6 +698,30 @@ nfs_updatepage(struct file *file, struct
 		return status;
 	}
 
+	nfs_begin_data_update(inode);
+
+
+	/* If we're not using byte range locks, and we know the page
+	 * is entirely in cache, it may be more efficient to avoid
+	 * fragmenting write requests.
+	 */
+	if (PageUptodate(page) && inode->i_flock == NULL) {
+		loff_t end_offs = i_size_read(inode) - 1;
+		unsigned long end_index = end_offs >> PAGE_CACHE_SHIFT;
+
+		count += offset;
+		offset = 0;
+		if (end_offs < 0) {
+			/* Do nothing */
+		} else if (page->index == end_index) {
+			unsigned int pglen;
+			pglen = (unsigned int)(end_offs & (PAGE_CACHE_SIZE-1)) + 1;
+			if (count < pglen)
+				count = pglen;
+		} else if (page->index < end_index)
+			count = PAGE_CACHE_SIZE;
+	}
+
 	/*
 	 * Try to find an NFS request corresponding to this page
 	 * and update it.
@@ -714,21 +740,14 @@ nfs_updatepage(struct file *file, struct
 		goto done;
 
 	status = 0;
-	end = ((loff_t)page->index<<PAGE_CACHE_SHIFT) + (loff_t)(offset + count);
-	if (i_size_read(inode) < end)
-		i_size_write(inode, end);
-
-	/* If we wrote past the end of the page.
-	 * Call the strategy routine so it can send out a bunch
-	 * of requests.
-	 */
-	if (req->wb_pgbase == 0 && req->wb_bytes == PAGE_CACHE_SIZE) {
-		SetPageUptodate(page);
-		nfs_unlock_request(req);
-		nfs_strategy(inode);
-	} else
-		nfs_unlock_request(req);
+
+	/* Update file length */
+	nfs_grow_file(page, offset, count);
+	/* Set the PG_uptodate flag? */
+	nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes);
+	nfs_unlock_request(req);
 done:
+	nfs_end_data_update(inode);
         dprintk("NFS:      nfs_updatepage returns %d (isize %Ld)\n",
 			status, (long long)i_size_read(inode));
 	if (status < 0)
@@ -891,10 +910,7 @@ nfs_writeback_done(struct rpc_task *task
 #endif
 
 	/*
-	 * Update attributes as result of writeback.
-	 * FIXME: There is an inherent race with invalidate_inode_pages and
-	 *	  writebacks since the page->count is kept > 1 for as long
-	 *	  as the page has a write request pending.
+	 * Process the nfs_page list
 	 */
 	while (!list_empty(&data->pages)) {
 		req = nfs_list_entry(data->pages.next);
@@ -1061,7 +1077,7 @@ nfs_commit_done(struct rpc_task *task)
 }
 #endif
 
-int nfs_flush_file(struct inode *inode, struct file *file, unsigned long idx_start,
+int nfs_flush_inode(struct inode *inode, unsigned long idx_start,
 		   unsigned int npages, int how)
 {
 	LIST_HEAD(head);
@@ -1069,7 +1085,7 @@ int nfs_flush_file(struct inode *inode, 
 				error = 0;
 
 	spin_lock(&nfs_wreq_lock);
-	res = nfs_scan_dirty(inode, &head, file, idx_start, npages);
+	res = nfs_scan_dirty(inode, &head, idx_start, npages);
 	spin_unlock(&nfs_wreq_lock);
 	if (res)
 		error = nfs_flush_list(&head, NFS_SERVER(inode)->wpages, how);
@@ -1079,7 +1095,7 @@ int nfs_flush_file(struct inode *inode, 
 }
 
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
-int nfs_commit_file(struct inode *inode, struct file *file, unsigned long idx_start,
+int nfs_commit_inode(struct inode *inode, unsigned long idx_start,
 		    unsigned int npages, int how)
 {
 	LIST_HEAD(head);
@@ -1087,9 +1103,9 @@ int nfs_commit_file(struct inode *inode,
 				error = 0;
 
 	spin_lock(&nfs_wreq_lock);
-	res = nfs_scan_commit(inode, &head, file, idx_start, npages);
+	res = nfs_scan_commit(inode, &head, idx_start, npages);
 	if (res) {
-		res += nfs_scan_commit(inode, &head, NULL, 0, 0);
+		res += nfs_scan_commit(inode, &head, 0, 0);
 		spin_unlock(&nfs_wreq_lock);
 		error = nfs_commit_list(&head, how);
 	} else
@@ -1100,7 +1116,7 @@ int nfs_commit_file(struct inode *inode,
 }
 #endif
 
-int nfs_sync_file(struct inode *inode, struct file *file, unsigned long idx_start,
+int nfs_sync_inode(struct inode *inode, unsigned long idx_start,
 		  unsigned int npages, int how)
 {
 	int	error,
@@ -1109,18 +1125,15 @@ int nfs_sync_file(struct inode *inode, s
 	wait = how & FLUSH_WAIT;
 	how &= ~FLUSH_WAIT;
 
-	if (!inode && file)
-		inode = file->f_dentry->d_inode;
-
 	do {
 		error = 0;
 		if (wait)
-			error = nfs_wait_on_requests(inode, file, idx_start, npages);
+			error = nfs_wait_on_requests(inode, idx_start, npages);
 		if (error == 0)
-			error = nfs_flush_file(inode, file, idx_start, npages, how);
+			error = nfs_flush_inode(inode, idx_start, npages, how);
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 		if (error == 0)
-			error = nfs_commit_file(inode, file, idx_start, npages, how);
+			error = nfs_commit_inode(inode, idx_start, npages, how);
 #endif
 	} while (error > 0);
 	return error;
--- diff/fs/nfsd/export.c	2004-03-04 11:41:49.000000000 +0000
+++ source/fs/nfsd/export.c	2004-03-09 11:51:51.000000000 +0000
@@ -56,11 +56,6 @@ static int		exp_verify_string(char *cp, 
 #define	EXPKEY_HASHMASK		(EXPKEY_HASHMAX -1)
 static struct cache_head *expkey_table[EXPKEY_HASHMAX];
 
-static inline int key_len(int type)
-{
-	return type == 0 ? 8 : type == 1 ? 4 : 12;
-}
-
 static inline int svc_expkey_hash(struct svc_expkey *item)
 {
 	int hash = item->ek_fsidtype;
@@ -547,8 +542,8 @@ exp_get_key(svc_client *clp, dev_t dev, 
 		mk_fsid_v0(fsidv, dev, ino);
 		return exp_find_key(clp, 0, fsidv, NULL);
 	}
-	mk_fsid_v2(fsidv, dev, ino);
-	return exp_find_key(clp, 2, fsidv, NULL);
+	mk_fsid_v3(fsidv, dev, ino);
+	return exp_find_key(clp, 3, fsidv, NULL);
 }
 
 /*
@@ -684,8 +679,8 @@ static int exp_hash(struct auth_domain *
 		mk_fsid_v0(fsid, dev, inode->i_ino);
 		return exp_set_key(clp, 0, fsid, exp);
 	}
-	mk_fsid_v2(fsid, dev, inode->i_ino);
-	return exp_set_key(clp, 2, fsid, exp);
+	mk_fsid_v3(fsid, dev, inode->i_ino);
+	return exp_set_key(clp, 3, fsid, exp);
 }
 
 static void exp_unhash(struct svc_export *exp)
--- diff/fs/nfsd/nfsfh.c	2004-03-04 11:41:49.000000000 +0000
+++ source/fs/nfsd/nfsfh.c	2004-03-09 11:51:51.000000000 +0000
@@ -117,19 +117,14 @@ fh_verify(struct svc_rqst *rqstp, struct
 			case 0: break;
 			default: goto out;
 			}
-
-			switch (fh->fh_fsid_type) {
-			case 0:
-				len = 2;
-				break;
-			case 1:
-				len = 1;
-				break;
-			case 2:
+			len = key_len(fh->fh_fsid_type) / 4;
+			if (len == 0) goto out;
+			if  (fh->fh_fsid_type == 2) {
+				/* deprecated, convert to type 3 */
 				len = 3;
-				break;
-			default:
-				goto out;
+				fh->fh_fsid_type = 3;
+				fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1])));
+				fh->fh_fsid[1] = fh->fh_fsid[2];
 			}
 			if ((data_left -= len)<0) goto out;
 			exp = exp_find(rqstp->rq_client, fh->fh_fsid_type, datap, &rqstp->rq_chandle);
@@ -336,19 +331,31 @@ fh_compose(struct svc_fh *fhp, struct sv
 		parent->d_name.name, dentry->d_name.name,
 		(inode ? inode->i_ino : 0));
 
-	/* for large devnums rules are simple */
-	if (!old_valid_dev(ex_dev)) {
-		ref_fh_version = 1;
-		if (exp->ex_flags & NFSEXP_FSID)
-			ref_fh_fsid_type = 1;
-		else
-			ref_fh_fsid_type = 2;
-	} else if (ref_fh) {
+	if (ref_fh) {
 		ref_fh_version = ref_fh->fh_handle.fh_version;
-		ref_fh_fsid_type = ref_fh->fh_handle.fh_fsid_type;
-		if (!(exp->ex_flags & NFSEXP_FSID) || ref_fh_fsid_type == 2)
+		if (ref_fh_version == 0xca)
+			ref_fh_fsid_type = 0;
+		else
+			ref_fh_fsid_type = ref_fh->fh_handle.fh_fsid_type;
+		if (ref_fh_fsid_type > 3)
 			ref_fh_fsid_type = 0;
 	}
+	/* make sure ref_fh type works for given export */
+	if (ref_fh_fsid_type == 1 &&
+	    !(exp->ex_flags & NFSEXP_FSID)) {
+		/* if we don't have an fsid, we cannot provide one... */
+		ref_fh_fsid_type = 0;
+	}
+	if (!old_valid_dev(ex_dev) && ref_fh_fsid_type == 0) {
+		/* for newer device numbers, we must use a newer fsid format */
+		ref_fh_version = 1;
+		ref_fh_fsid_type = 3;
+	}
+	if (old_valid_dev(ex_dev) &&
+	    (ref_fh_fsid_type == 2 || ref_fh_fsid_type == 3))
+		/* must use type1 for smaller device numbers */
+		ref_fh_fsid_type = 0;
+
 	if (ref_fh == fhp)
 		fh_put(ref_fh);
 
@@ -376,16 +383,23 @@ fh_compose(struct svc_fh *fhp, struct sv
 		if (inode)
 			_fh_update_old(dentry, exp, &fhp->fh_handle);
 	} else {
+		int len;
 		fhp->fh_handle.fh_version = 1;
 		fhp->fh_handle.fh_auth_type = 0;
 		datap = fhp->fh_handle.fh_auth+0;
 		fhp->fh_handle.fh_fsid_type = ref_fh_fsid_type;
 		switch (ref_fh_fsid_type) {
+			case 0:
+				/*
+				 * fsid_type 0:
+				 * 2byte major, 2byte minor, 4byte inode
+				 */
+				mk_fsid_v0(datap, ex_dev,
+					exp->ex_dentry->d_inode->i_ino);
+				break;
 			case 1:
 				/* fsid_type 1 == 4 bytes filesystem id */
 				mk_fsid_v1(datap, exp->ex_fsid);
-				datap += 1;
-				fhp->fh_handle.fh_size = 2*4;
 				break;
 			case 2:
 				/*
@@ -394,21 +408,22 @@ fh_compose(struct svc_fh *fhp, struct sv
 				 */
 				mk_fsid_v2(datap, ex_dev,
 					exp->ex_dentry->d_inode->i_ino);
-				datap += 3;
-				fhp->fh_handle.fh_size = 4*4;
 				break;
-			default:
+			case 3:
 				/*
-				 * fsid_type 0:
-				 * 2byte major, 2byte minor, 4byte inode
+				 * fsid_type 3:
+				 * 4byte devicenumber, 4byte inode
 				 */
-				mk_fsid_v0(datap, ex_dev,
+				mk_fsid_v3(datap, ex_dev,
 					exp->ex_dentry->d_inode->i_ino);
-				datap += 2;
-				fhp->fh_handle.fh_size = 3*4;
+				break;
 		}
+		len = key_len(ref_fh_fsid_type);
+		datap += len/4;
+		fhp->fh_handle.fh_size = 4 + len;
+
 		if (inode) {
-			int size = fhp->fh_maxsize/4 - 3;
+			int size = (fhp->fh_maxsize-len-4)/4;
 			fhp->fh_handle.fh_fileid_type =
 				_fh_update(dentry, exp, datap, &size);
 			fhp->fh_handle.fh_size += size*4;
--- diff/fs/open.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/open.c	2004-03-09 11:51:51.000000000 +0000
@@ -192,7 +192,9 @@ int do_truncate(struct dentry *dentry, l
 	newattrs.ia_size = length;
 	newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
 	down(&dentry->d_inode->i_sem);
+	down_write(&dentry->d_inode->i_alloc_sem);
 	err = notify_change(dentry, &newattrs);
+	up_write(&dentry->d_inode->i_alloc_sem);
 	up(&dentry->d_inode->i_sem);
 	return err;
 }
@@ -890,7 +892,7 @@ static inline void __put_unused_fd(struc
 		files->next_fd = fd;
 }
 
-void put_unused_fd(unsigned int fd)
+void fastcall put_unused_fd(unsigned int fd)
 {
 	struct files_struct *files = current->files;
 	spin_lock(&files->file_lock);
@@ -913,7 +915,7 @@ EXPORT_SYMBOL(put_unused_fd);
  * will follow.
  */
 
-void fd_install(unsigned int fd, struct file * file)
+void fastcall fd_install(unsigned int fd, struct file * file)
 {
 	struct files_struct *files = current->files;
 	spin_lock(&files->file_lock);
--- diff/fs/proc/generic.c	2004-01-19 10:22:59.000000000 +0000
+++ source/fs/proc/generic.c	2004-03-09 11:51:51.000000000 +0000
@@ -661,6 +661,7 @@ void remove_proc_entry(const char *name,
 			  proc_alloc_map);
 		proc_kill_inodes(de);
 		de->nlink = 0;
+		BUG_ON(de->subdir);
 		if (!atomic_read(&de->count))
 			free_proc_entry(de);
 		else {
--- diff/fs/proc/inode.c	2003-10-09 09:47:34.000000000 +0100
+++ source/fs/proc/inode.c	2004-03-09 11:51:51.000000000 +0000
@@ -231,6 +231,7 @@ int proc_fill_super(struct super_block *
 {
 	struct inode * root_inode;
 
+	s->s_flags |= MS_NODIRATIME;
 	s->s_blocksize = 1024;
 	s->s_blocksize_bits = 10;
 	s->s_magic = PROC_SUPER_MAGIC;
--- diff/fs/proc/kmsg.c	2003-09-30 15:46:19.000000000 +0100
+++ source/fs/proc/kmsg.c	2004-03-09 11:51:51.000000000 +0000
@@ -33,6 +33,8 @@ static int kmsg_release(struct inode * i
 static ssize_t kmsg_read(struct file *file, char __user *buf,
 			 size_t count, loff_t *ppos)
 {
+	if ((file->f_flags & O_NONBLOCK) && !do_syslog(9, 0, 0))
+		return -EAGAIN;
 	return do_syslog(2, buf, count);
 }
 
--- diff/fs/proc/proc_misc.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/proc/proc_misc.c	2004-03-09 11:51:51.000000000 +0000
@@ -389,7 +389,7 @@ int show_stat(struct seq_file *p, void *
 		jiffies_to_clock_t(iowait),
 		jiffies_to_clock_t(irq),
 		jiffies_to_clock_t(softirq));
-	for_each_online_cpu(i) {
+	for_each_cpu(i) {
 		seq_printf(p, "cpu%d %u %u %u %u %u %u %u\n",
 			i,
 			jiffies_to_clock_t(kstat_cpu(i).cpustat.user),
@@ -424,7 +424,7 @@ int show_stat(struct seq_file *p, void *
 
 static int stat_open(struct inode *inode, struct file *file)
 {
-	unsigned size = 4096 * (1 + num_online_cpus() / 32);
+	unsigned size = 4096 * (1 + num_possible_cpus() / 32);
 	char *buf;
 	struct seq_file *m;
 	int res;
@@ -641,6 +641,36 @@ static void create_seq_entry(char *name,
 		entry->proc_fops = f;
 }
 
+#ifdef CONFIG_LOCKMETER
+extern ssize_t get_lockmeter_info(char *, size_t, loff_t *);
+extern ssize_t put_lockmeter_info(const char *, size_t);
+extern int get_lockmeter_info_size(void);
+
+/*
+ * This function accesses lock metering information.
+ */
+static ssize_t read_lockmeter(struct file *file, char *buf,
+			      size_t count, loff_t *ppos)
+{
+	return get_lockmeter_info(buf, count, ppos);
+}
+
+/*
+ * Writing to /proc/lockmeter resets the counters
+ */
+static ssize_t write_lockmeter(struct file * file, const char * buf,
+			       size_t count, loff_t *ppos)
+{
+	return put_lockmeter_info(buf, count);
+}
+
+static struct file_operations proc_lockmeter_operations = {
+	NULL,           /* lseek */
+	read:		read_lockmeter,
+	write:		write_lockmeter,
+};
+#endif  /* CONFIG_LOCKMETER */
+
 void __init proc_misc_init(void)
 {
 	struct proc_dir_entry *entry;
@@ -708,6 +738,13 @@ void __init proc_misc_init(void)
 	if (entry)
 		entry->proc_fops = &proc_sysrq_trigger_operations;
 #endif
+#ifdef CONFIG_LOCKMETER
+	entry = create_proc_entry("lockmeter", S_IWUSR | S_IRUGO, NULL);
+	if (entry) {
+		entry->proc_fops = &proc_lockmeter_operations;
+		entry->size = get_lockmeter_info_size();
+	}
+#endif
 #ifdef CONFIG_PPC32
 	{
 		extern struct file_operations ppc_htab_operations;
--- diff/fs/proc/task_mmu.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/proc/task_mmu.c	2004-03-09 11:51:51.000000000 +0000
@@ -4,6 +4,22 @@
 #include <asm/elf.h>
 #include <asm/uaccess.h>
 
+#ifdef CONFIG_NUMA
+char *task_mem_pernode(struct mm_struct *mm, char *buffer)
+{
+	int nid;
+
+	for (nid = 0; nid < MAX_NUMNODES; nid++){
+		buffer += sprintf(buffer, "VmRSS-node_%d:\t%8lu kb\n",
+			nid, mm->pernode_rss[nid] << (PAGE_SHIFT-10));
+	}
+
+	return buffer;
+}
+#else /* !CONFIG_NUMA */
+#define task_mem_pernode(mm, buffer)	(buffer)
+#endif /* CONFIG_NUMA */
+
 char *task_mem(struct mm_struct *mm, char *buffer)
 {
 	unsigned long data = 0, stack = 0, exec = 0, lib = 0;
@@ -40,6 +56,7 @@ char *task_mem(struct mm_struct *mm, cha
 		mm->rss << (PAGE_SHIFT-10),
 		data - stack, stack,
 		exec - lib, lib);
+	buffer = task_mem_pernode(mm, buffer);
 	up_read(&mm->mmap_sem);
 	return buffer;
 }
--- diff/fs/qnx4/dir.c	2003-06-09 14:18:20.000000000 +0100
+++ source/fs/qnx4/dir.c	2004-03-09 11:51:51.000000000 +0000
@@ -76,8 +76,6 @@ static int qnx4_readdir(struct file *fil
 		}
 		brelse(bh);
 	}
-	update_atime(inode);
-
 out:
 	unlock_kernel();
 	return 0;
--- diff/fs/quota_v1.c	2003-10-09 09:47:34.000000000 +0100
+++ source/fs/quota_v1.c	2004-03-09 11:51:51.000000000 +0000
@@ -60,7 +60,7 @@ static int v1_read_dqblk(struct dquot *d
 	v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk);
 	if (dquot->dq_dqb.dqb_bhardlimit == 0 && dquot->dq_dqb.dqb_bsoftlimit == 0 &&
 	    dquot->dq_dqb.dqb_ihardlimit == 0 && dquot->dq_dqb.dqb_isoftlimit == 0)
-		dquot->dq_flags |= DQ_FAKE;
+		set_bit(DQ_FAKE_B, &dquot->dq_flags);
 	dqstats.reads++;
 
 	return 0;
@@ -80,12 +80,7 @@ static int v1_commit_dqblk(struct dquot 
 	fs = get_fs();
 	set_fs(KERNEL_DS);
 
-	/*
-	 * Note: clear the DQ_MOD flag unconditionally,
-	 * so we don't loop forever on failure.
-	 */
 	v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb);
-	dquot->dq_flags &= ~DQ_MOD;
 	if (dquot->dq_id == 0) {
 		dqblk.dqb_btime = sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace;
 		dqblk.dqb_itime = sb_dqopt(dquot->dq_sb)->info[type].dqi_igrace;
--- diff/fs/quota_v2.c	2003-05-21 11:50:00.000000000 +0100
+++ source/fs/quota_v2.c	2004-03-09 11:51:51.000000000 +0000
@@ -65,7 +65,7 @@ static int v2_read_file_info(struct supe
 	set_fs(fs);
 	if (size != sizeof(struct v2_disk_dqinfo)) {
 		printk(KERN_WARNING "Can't read info structure on device %s.\n",
-			f->f_vfsmnt->mnt_sb->s_id);
+			f->f_dentry->d_sb->s_id);
 		return -1;
 	}
 	info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
@@ -87,10 +87,12 @@ static int v2_write_file_info(struct sup
 	ssize_t size;
 	loff_t offset = V2_DQINFOOFF;
 
+	spin_lock(&dq_data_lock);
 	info->dqi_flags &= ~DQF_INFO_DIRTY;
 	dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
 	dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
 	dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
+	spin_unlock(&dq_data_lock);
 	dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.dqi_blocks);
 	dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.dqi_free_blk);
 	dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.dqi_free_entry);
@@ -100,7 +102,7 @@ static int v2_write_file_info(struct sup
 	set_fs(fs);
 	if (size != sizeof(struct v2_disk_dqinfo)) {
 		printk(KERN_WARNING "Can't write info structure on device %s.\n",
-			f->f_vfsmnt->mnt_sb->s_id);
+			f->f_dentry->d_sb->s_id);
 		return -1;
 	}
 	return 0;
@@ -173,9 +175,10 @@ static ssize_t write_blk(struct file *fi
 }
 
 /* Remove empty block from list and return it */
-static int get_free_dqblk(struct file *filp, struct mem_dqinfo *info)
+static int get_free_dqblk(struct file *filp, int type)
 {
 	dqbuf_t buf = getdqbuf();
+	struct mem_dqinfo *info = sb_dqinfo(filp->f_dentry->d_sb, type);
 	struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
 	int ret, blk;
 
@@ -193,7 +196,7 @@ static int get_free_dqblk(struct file *f
 			goto out_buf;
 		blk = info->u.v2_i.dqi_blocks++;
 	}
-	mark_info_dirty(info);
+	mark_info_dirty(filp->f_dentry->d_sb, type);
 	ret = blk;
 out_buf:
 	freedqbuf(buf);
@@ -201,8 +204,9 @@ out_buf:
 }
 
 /* Insert empty block to the list */
-static int put_free_dqblk(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk)
+static int put_free_dqblk(struct file *filp, int type, dqbuf_t buf, uint blk)
 {
+	struct mem_dqinfo *info = sb_dqinfo(filp->f_dentry->d_sb, type);
 	struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
 	int err;
 
@@ -210,16 +214,17 @@ static int put_free_dqblk(struct file *f
 	dh->dqdh_prev_free = cpu_to_le32(0);
 	dh->dqdh_entries = cpu_to_le16(0);
 	info->u.v2_i.dqi_free_blk = blk;
-	mark_info_dirty(info);
+	mark_info_dirty(filp->f_dentry->d_sb, type);
 	if ((err = write_blk(filp, blk, buf)) < 0)	/* Some strange block. We had better leave it... */
 		return err;
 	return 0;
 }
 
 /* Remove given block from the list of blocks with free entries */
-static int remove_free_dqentry(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk)
+static int remove_free_dqentry(struct file *filp, int type, dqbuf_t buf, uint blk)
 {
 	dqbuf_t tmpbuf = getdqbuf();
+	struct mem_dqinfo *info = sb_dqinfo(filp->f_dentry->d_sb, type);
 	struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
 	uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free);
 	int err;
@@ -242,7 +247,7 @@ static int remove_free_dqentry(struct fi
 	}
 	else {
 		info->u.v2_i.dqi_free_entry = nextblk;
-		mark_info_dirty(info);
+		mark_info_dirty(filp->f_dentry->d_sb, type);
 	}
 	freedqbuf(tmpbuf);
 	dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
@@ -255,9 +260,10 @@ out_buf:
 }
 
 /* Insert given block to the beginning of list with free entries */
-static int insert_free_dqentry(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk)
+static int insert_free_dqentry(struct file *filp, int type, dqbuf_t buf, uint blk)
 {
 	dqbuf_t tmpbuf = getdqbuf();
+	struct mem_dqinfo *info = sb_dqinfo(filp->f_dentry->d_sb, type);
 	struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
 	int err;
 
@@ -276,7 +282,7 @@ static int insert_free_dqentry(struct fi
 	}
 	freedqbuf(tmpbuf);
 	info->u.v2_i.dqi_free_entry = blk;
-	mark_info_dirty(info);
+	mark_info_dirty(filp->f_dentry->d_sb, type);
 	return 0;
 out_buf:
 	freedqbuf(tmpbuf);
@@ -307,7 +313,7 @@ static uint find_free_dqentry(struct dqu
 			goto out_buf;
 	}
 	else {
-		blk = get_free_dqblk(filp, info);
+		blk = get_free_dqblk(filp, dquot->dq_type);
 		if ((int)blk < 0) {
 			*err = blk;
 			freedqbuf(buf);
@@ -315,10 +321,10 @@ static uint find_free_dqentry(struct dqu
 		}
 		memset(buf, 0, V2_DQBLKSIZE);
 		info->u.v2_i.dqi_free_entry = blk;	/* This is enough as block is already zeroed and entry list is empty... */
-		mark_info_dirty(info);
+		mark_info_dirty(dquot->dq_sb, dquot->dq_type);
 	}
 	if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK)	/* Block will be full? */
-		if ((*err = remove_free_dqentry(filp, info, buf, blk)) < 0) {
+		if ((*err = remove_free_dqentry(filp, dquot->dq_type, buf, blk)) < 0) {
 			printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
 			goto out_buf;
 		}
@@ -349,7 +355,6 @@ out_buf:
 static int do_insert_tree(struct dquot *dquot, uint *treeblk, int depth)
 {
 	struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
-	struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type;
 	dqbuf_t buf;
 	int ret = 0, newson = 0, newact = 0;
 	u32 *ref;
@@ -358,7 +363,7 @@ static int do_insert_tree(struct dquot *
 	if (!(buf = getdqbuf()))
 		return -ENOMEM;
 	if (!*treeblk) {
-		ret = get_free_dqblk(filp, info);
+		ret = get_free_dqblk(filp, dquot->dq_type);
 		if (ret < 0)
 			goto out_buf;
 		*treeblk = ret;
@@ -392,7 +397,7 @@ static int do_insert_tree(struct dquot *
 		ret = write_blk(filp, *treeblk, buf);
 	}
 	else if (newact && ret < 0)
-		put_free_dqblk(filp, info, buf, *treeblk);
+		put_free_dqblk(filp, dquot->dq_type, buf, *treeblk);
 out_buf:
 	freedqbuf(buf);
 	return ret;
@@ -417,6 +422,7 @@ static int v2_write_dquot(struct dquot *
 	ssize_t ret;
 	struct v2_disk_dqblk ddquot;
 
+	/* dq_off is guarded by dqio_sem */
 	if (!dquot->dq_off)
 		if ((ret = dq_insert_tree(dquot)) < 0) {
 			printk(KERN_ERR "VFS: Error %Zd occurred while creating quota.\n", ret);
@@ -424,7 +430,9 @@ static int v2_write_dquot(struct dquot *
 		}
 	filp = sb_dqopt(dquot->dq_sb)->files[type];
 	offset = dquot->dq_off;
+	spin_lock(&dq_data_lock);
 	mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
+	spin_unlock(&dq_data_lock);
 	fs = get_fs();
 	set_fs(KERNEL_DS);
 	ret = filp->f_op->write(filp, (char *)&ddquot, sizeof(struct v2_disk_dqblk), &offset);
@@ -445,7 +453,6 @@ static int v2_write_dquot(struct dquot *
 static int free_dqentry(struct dquot *dquot, uint blk)
 {
 	struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
-	struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type;
 	struct v2_disk_dqdbheader *dh;
 	dqbuf_t buf = getdqbuf();
 	int ret = 0;
@@ -463,8 +470,8 @@ static int free_dqentry(struct dquot *dq
 	dh = (struct v2_disk_dqdbheader *)buf;
 	dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)-1);
 	if (!le16_to_cpu(dh->dqdh_entries)) {	/* Block got free? */
-		if ((ret = remove_free_dqentry(filp, info, buf, blk)) < 0 ||
-		    (ret = put_free_dqblk(filp, info, buf, blk)) < 0) {
+		if ((ret = remove_free_dqentry(filp, dquot->dq_type, buf, blk)) < 0 ||
+		    (ret = put_free_dqblk(filp, dquot->dq_type, buf, blk)) < 0) {
 			printk(KERN_ERR "VFS: Can't move quota data block (%u) to free list.\n", blk);
 			goto out_buf;
 		}
@@ -473,7 +480,7 @@ static int free_dqentry(struct dquot *dq
 		memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0, sizeof(struct v2_disk_dqblk));
 		if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
 			/* Insert will write block itself */
-			if ((ret = insert_free_dqentry(filp, info, buf, blk)) < 0) {
+			if ((ret = insert_free_dqentry(filp, dquot->dq_type, buf, blk)) < 0) {
 				printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
 				goto out_buf;
 			}
@@ -494,7 +501,6 @@ out_buf:
 static int remove_tree(struct dquot *dquot, uint *blk, int depth)
 {
 	struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
-	struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type;
 	dqbuf_t buf = getdqbuf();
 	int ret = 0;
 	uint newblk;
@@ -518,7 +524,7 @@ static int remove_tree(struct dquot *dqu
 		ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
 		for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++);	/* Block got empty? */
 		if (i == V2_DQBLKSIZE) {
-			put_free_dqblk(filp, info, buf, *blk);
+			put_free_dqblk(filp, dquot->dq_type, buf, *blk);
 			*blk = 0;
 		}
 		else
@@ -632,7 +638,7 @@ static int v2_read_dquot(struct dquot *d
 		if (offset < 0)
 			printk(KERN_ERR "VFS: Can't read quota structure for id %u.\n", dquot->dq_id);
 		dquot->dq_off = 0;
-		dquot->dq_flags |= DQ_FAKE;
+		set_bit(DQ_FAKE_B, &dquot->dq_flags);
 		memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
 		ret = offset;
 	}
@@ -650,21 +656,24 @@ static int v2_read_dquot(struct dquot *d
 			ret = 0;
 		set_fs(fs);
 		disk2memdqb(&dquot->dq_dqb, &ddquot);
+		if (!dquot->dq_dqb.dqb_bhardlimit &&
+			!dquot->dq_dqb.dqb_bsoftlimit &&
+			!dquot->dq_dqb.dqb_ihardlimit &&
+			!dquot->dq_dqb.dqb_isoftlimit)
+			set_bit(DQ_FAKE_B, &dquot->dq_flags);
 	}
 	dqstats.reads++;
 
 	return ret;
 }
 
-/* Commit changes of dquot to disk - it might also mean deleting it when quota became fake one and user has no blocks... */
-static int v2_commit_dquot(struct dquot *dquot)
+/* Check whether dquot should not be deleted. We know we are
+ * the only one operating on dquot (thanks to dq_lock) */
+static int v2_release_dquot(struct dquot *dquot)
 {
-	/* We clear the flag everytime so we don't loop when there was an IO error... */
-	dquot->dq_flags &= ~DQ_MOD;
-	if (dquot->dq_flags & DQ_FAKE && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace))
+	if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace))
 		return v2_delete_dquot(dquot);
-	else
-		return v2_write_dquot(dquot);
+	return 0;
 }
 
 static struct quota_format_ops v2_format_ops = {
@@ -673,7 +682,8 @@ static struct quota_format_ops v2_format
 	.write_file_info	= v2_write_file_info,
 	.free_file_info		= NULL,
 	.read_dqblk		= v2_read_dquot,
-	.commit_dqblk		= v2_commit_dquot,
+	.commit_dqblk		= v2_write_dquot,
+	.release_dqblk		= v2_release_dquot,
 };
 
 static struct quota_format_type v2_quota_format = {
--- diff/fs/readdir.c	2004-03-04 11:41:49.000000000 +0000
+++ source/fs/readdir.c	2004-03-09 11:51:51.000000000 +0000
@@ -32,6 +32,7 @@ int vfs_readdir(struct file *file, filld
 	res = -ENOENT;
 	if (!IS_DEADDIR(inode)) {
 		res = file->f_op->readdir(file, buf, filler);
+		update_atime(inode);
 	}
 	up(&inode->i_sem);
 out:
--- diff/fs/reiserfs/dir.c	2003-06-09 14:18:20.000000000 +0100
+++ source/fs/reiserfs/dir.c	2004-03-09 11:51:51.000000000 +0000
@@ -186,7 +186,6 @@ static int reiserfs_readdir (struct file
     filp->f_pos = next_pos;
     pathrelse (&path_to_entry);
     reiserfs_check_path(&path_to_entry) ;
-    update_atime(inode) ;
  out:
     reiserfs_write_unlock(inode->i_sb);
     return ret;
--- diff/fs/romfs/inode.c	2003-09-17 12:28:11.000000000 +0100
+++ source/fs/romfs/inode.c	2004-03-09 11:51:51.000000000 +0000
@@ -115,6 +115,7 @@ static int romfs_fill_super(struct super
 {
 	struct buffer_head *bh;
 	struct romfs_super_block *rsb;
+	struct inode *root;
 	int sz;
 
 	/* I would parse the options here, but there are none.. :) */
@@ -154,23 +155,25 @@ static int romfs_fill_super(struct super
 	      strnlen(rsb->name, ROMFS_MAXFN) + 1 + ROMFH_PAD)
 	     & ROMFH_MASK;
 
-	brelse(bh);
-
 	s->s_op	= &romfs_ops;
+	root = iget(s, sz);
+	if (!root)
+		goto out;
+
 	s->s_root = d_alloc_root(iget(s, sz));
 
 	if (!s->s_root)
-		goto outnobh;
+		goto outiput;
 
-	/* Ehrhm; sorry.. :)  And thanks to Hans-Joachim Widmaier  :) */
-	if (0) {
+	brelse(bh);
+	return 0;
+
+outiput:
+	iput(root);
 out:
-		brelse(bh);
+	brelse(bh);
 outnobh:
-		return -EINVAL;
-	}
-
-	return 0;
+	return -EINVAL;
 }
 
 /* That's simple too. */
--- diff/fs/select.c	2003-10-09 09:47:34.000000000 +0100
+++ source/fs/select.c	2004-03-09 11:51:51.000000000 +0000
@@ -291,8 +291,6 @@ static void select_bits_free(void *bits,
  * Update: ERESTARTSYS breaks at least the xview clock binary, so
  * I'm trying ERESTARTNOHAND which restart only when you want to.
  */
-#define MAX_SELECT_SECONDS \
-	((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
 
 asmlinkage long
 sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, struct timeval __user *tvp)
@@ -315,9 +313,11 @@ sys_select(int n, fd_set __user *inp, fd
 		if (sec < 0 || usec < 0)
 			goto out_nofds;
 
-		if ((unsigned long) sec < MAX_SELECT_SECONDS) {
+		if ((unsigned long) sec < (MAX_SCHEDULE_TIMEOUT-1) / HZ - 1) {
 			timeout = ROUND_UP(usec, 1000000/HZ);
 			timeout += sec * (unsigned long) HZ;
+		} else {
+			timeout = MAX_SCHEDULE_TIMEOUT-1;
 		}
 	}
 
@@ -469,11 +469,17 @@ asmlinkage long sys_poll(struct pollfd _
 		return -EINVAL;
 
 	if (timeout) {
-		/* Careful about overflow in the intermediate values */
-		if ((unsigned long) timeout < MAX_SCHEDULE_TIMEOUT / HZ)
-			timeout = (unsigned long)(timeout*HZ+999)/1000+1;
-		else /* Negative or overflow */
+                if (timeout < 0) {
 			timeout = MAX_SCHEDULE_TIMEOUT;
+		} else {
+			/* Careful about overflow in the intermediate values */
+			long seconds = timeout/1000;
+			timeout = ((timeout - 1000*seconds)*HZ + 999)/1000 + 1;
+			if (seconds <= (MAX_SCHEDULE_TIMEOUT-2) / HZ - 1)
+				timeout += seconds*HZ;
+			else
+				timeout = MAX_SCHEDULE_TIMEOUT-1;
+		}
 	}
 
 	poll_initwait(&table);
--- diff/fs/smbfs/inode.c	2003-10-09 09:47:34.000000000 +0100
+++ source/fs/smbfs/inode.c	2004-03-09 11:51:51.000000000 +0000
@@ -499,6 +499,7 @@ int smb_fill_super(struct super_block *s
 	if (ver != SMB_MOUNT_OLDVERSION && cpu_to_be32(ver) != SMB_MOUNT_ASCII)
 		goto out_wrong_data;
 
+	sb->s_flags |= MS_NODIRATIME;
 	sb->s_blocksize = 1024;	/* Eh...  Is this correct? */
 	sb->s_blocksize_bits = 10;
 	sb->s_magic = SMB_SUPER_MAGIC;
@@ -778,6 +779,7 @@ static struct file_system_type smb_fs_ty
 	.name		= "smbfs",
 	.get_sb		= smb_get_sb,
 	.kill_sb	= kill_anon_super,
+	.fs_flags	= FS_BINARY_MOUNTDATA,
 };
 
 static int __init init_smb_fs(void)
--- diff/fs/stat.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/stat.c	2004-03-09 11:51:51.000000000 +0000
@@ -397,6 +397,8 @@ EXPORT_SYMBOL(inode_get_bytes);
 
 void inode_set_bytes(struct inode *inode, loff_t bytes)
 {
+	/* Caller is here responsible for sufficient locking
+	 * (ie. inode->i_lock) */
 	inode->i_blocks = bytes >> 9;
 	inode->i_bytes = bytes & 511;
 }
--- diff/fs/super.c	2004-03-04 11:41:49.000000000 +0000
+++ source/fs/super.c	2004-03-09 11:51:51.000000000 +0000
@@ -68,6 +68,7 @@ static struct super_block *alloc_super(v
 		INIT_LIST_HEAD(&s->s_files);
 		INIT_LIST_HEAD(&s->s_instances);
 		INIT_HLIST_HEAD(&s->s_anon);
+		INIT_LIST_HEAD(&s->s_inodes);
 		init_rwsem(&s->s_umount);
 		sema_init(&s->s_lock, 1);
 		down_write(&s->s_umount);
@@ -745,7 +746,7 @@ do_kern_mount(const char *fstype, int fl
 			goto out_mnt;
 		}
 
-		error = security_sb_copy_data(fstype, data, secdata);
+		error = security_sb_copy_data(type, data, secdata);
 		if (error) {
 			sb = ERR_PTR(error);
 			goto out_free_secdata;
--- diff/fs/sysfs/dir.c	2004-01-19 10:22:59.000000000 +0000
+++ source/fs/sysfs/dir.c	2004-03-09 11:51:51.000000000 +0000
@@ -20,6 +20,18 @@ static int init_dir(struct inode * inode
 	return 0;
 }
 
+static void sysfs_d_iput(struct dentry * dentry, struct inode * inode)
+{
+	struct kobject * kobj = dentry->d_fsdata;
+
+	if (kobj)
+		kobject_put(kobj);
+	iput(inode);
+}
+
+static struct dentry_operations sysfs_dentry_operations = {
+	.d_iput	= &sysfs_d_iput,
+};
 
 static int create_dir(struct kobject * k, struct dentry * p,
 		      const char * n, struct dentry ** d)
@@ -33,7 +45,8 @@ static int create_dir(struct kobject * k
 					 S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO,
 					 init_dir);
 		if (!error) {
-			(*d)->d_fsdata = k;
+			(*d)->d_op = &sysfs_dentry_operations;
+			(*d)->d_fsdata = kobject_get(k);
 			p->d_inode->i_nlink++;
 		}
 		dput(*d);
@@ -96,6 +109,8 @@ static void remove_dir(struct dentry * d
 void sysfs_remove_subdir(struct dentry * d)
 {
 	remove_dir(d);
+	/* release the "extra" ref taken during sysfs_create() */
+	dput(d);
 }
 
 
@@ -120,13 +135,14 @@ void sysfs_remove_dir(struct kobject * k
 	down(&dentry->d_inode->i_sem);
 
 	spin_lock(&dcache_lock);
+restart:
 	node = dentry->d_subdirs.next;
 	while (node != &dentry->d_subdirs) {
 		struct dentry * d = list_entry(node,struct dentry,d_child);
-		list_del_init(node);
 
+		node = node->next;
 		pr_debug(" o %s (%d): ",d->d_name.name,atomic_read(&d->d_count));
-		if (d->d_inode) {
+		if (!d_unhashed(d) && (d->d_inode)) {
 			d = dget_locked(d);
 			pr_debug("removing");
 
@@ -137,12 +153,12 @@ void sysfs_remove_dir(struct kobject * k
 			d_delete(d);
 			simple_unlink(dentry->d_inode,d);
 			dput(d);
+			pr_debug(" done\n");
 			spin_lock(&dcache_lock);
+			/* re-acquired dcache_lock, need to restart */
+			goto restart;
 		}
-		pr_debug(" done\n");
-		node = dentry->d_subdirs.next;
 	}
-	list_del_init(&dentry->d_child);
 	spin_unlock(&dcache_lock);
 	up(&dentry->d_inode->i_sem);
 
--- diff/fs/sysfs/group.c	2003-09-30 15:46:19.000000000 +0100
+++ source/fs/sysfs/group.c	2004-03-09 11:51:51.000000000 +0000
@@ -68,12 +68,13 @@ void sysfs_remove_group(struct kobject *
 	if (grp->name)
 		dir = sysfs_get_dentry(kobj->dentry,grp->name);
 	else
-		dir = kobj->dentry;
+		dir = dget(kobj->dentry);
 
 	remove_files(dir,grp);
-	dput(dir);
 	if (grp->name)
 		sysfs_remove_subdir(dir);
+	/* release the ref. taken in this routine */
+	dput(dir);
 }
 
 
--- diff/fs/sysv/dir.c	2003-06-09 14:18:20.000000000 +0100
+++ source/fs/sysv/dir.c	2004-03-09 11:51:51.000000000 +0000
@@ -116,7 +116,6 @@ static int sysv_readdir(struct file * fi
 
 done:
 	filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
-	update_atime(inode);
 	unlock_kernel();
 	return 0;
 }
--- diff/fs/udf/dir.c	2003-06-09 14:18:20.000000000 +0100
+++ source/fs/udf/dir.c	2004-03-09 11:51:51.000000000 +0000
@@ -15,7 +15,7 @@
  *		ftp://prep.ai.mit.edu/pub/gnu/GPL
  *	Each contributing author retains all rights to their own work.
  *
- *  (C) 1998-2001 Ben Fennema
+ *  (C) 1998-2004 Ben Fennema
  *
  * HISTORY
  *
@@ -98,7 +98,6 @@ int udf_readdir(struct file *filp, void 
 	}
 
 	result = do_udf_readdir(dir, filp, filldir, dirent);
-	update_atime(dir);
 	unlock_kernel();
  	return result;
 }
@@ -112,7 +111,7 @@ do_udf_readdir(struct inode * dir, struc
 	int block, iblock;
 	loff_t nf_pos = filp->f_pos - 1;
 	int flen;
-	char fname[255];
+	char fname[UDF_NAME_LEN];
 	char *nameptr;
 	uint16_t liu;
 	uint8_t lfi;
--- diff/fs/udf/file.c	2003-07-11 09:39:50.000000000 +0100
+++ source/fs/udf/file.c	2004-03-09 11:51:51.000000000 +0000
@@ -16,7 +16,7 @@
  *  Each contributing author retains all rights to their own work.
  *
  *  (C) 1998-1999 Dave Boynton
- *  (C) 1998-2001 Ben Fennema
+ *  (C) 1998-2004 Ben Fennema
  *  (C) 1999-2000 Stelias Computing Inc
  *
  * HISTORY
@@ -247,9 +247,9 @@ static int udf_release_file(struct inode
 {
 	if (filp->f_mode & FMODE_WRITE)
 	{
-		lock_kernel();
+		down(&inode->i_sem);
 		udf_discard_prealloc(inode);
-		unlock_kernel();
+		up(&inode->i_sem);
 	}
 	return 0;
 }
--- diff/fs/udf/inode.c	2003-10-09 09:47:34.000000000 +0100
+++ source/fs/udf/inode.c	2004-03-09 11:51:51.000000000 +0000
@@ -16,7 +16,7 @@
  *  Each contributing author retains all rights to their own work.
  *
  *  (C) 1998 Dave Boynton
- *  (C) 1998-2001 Ben Fennema
+ *  (C) 1998-2004 Ben Fennema
  *  (C) 1999-2000 Stelias Computing Inc
  *
  * HISTORY
@@ -84,9 +84,9 @@ void udf_put_inode(struct inode * inode)
 {
 	if (!(inode->i_sb->s_flags & MS_RDONLY))
 	{
-		lock_kernel();
+		down(&inode->i_sem);
 		udf_discard_prealloc(inode);
-		unlock_kernel();
+		up(&inode->i_sem);
 	}
 }
 
@@ -130,15 +130,6 @@ void udf_clear_inode(struct inode *inode
 	UDF_I_DATA(inode) = NULL;
 }
 
-void udf_discard_prealloc(struct inode * inode)
-{
-	if (inode->i_size && inode->i_size != UDF_I_LENEXTENTS(inode) &&
-		UDF_I_ALLOCTYPE(inode) != ICBTAG_FLAG_AD_IN_ICB)
-	{
-		udf_truncate_extents(inode);
-	}
-}
-
 static int udf_writepage(struct page *page, struct writeback_control *wbc)
 {
 	return block_write_full_page(page, udf_get_block, wbc);
@@ -516,11 +507,8 @@ static struct buffer_head * inode_getblk
 		else
 			lastblock = 1;
 	}
+	udf_release_data(cbh);
 	udf_release_data(nbh);
-	if (!pbh)
-		pbh = cbh;
-	else
-		udf_release_data(cbh);
 
 	/* if the current extent is not recorded but allocated, get the
 		block in the extent corresponding to the requested block */
@@ -595,7 +583,7 @@ static void udf_split_extents(struct ino
 		int curr = *c;
 		int blen = ((laarr[curr].extLength & UDF_EXTENT_LENGTH_MASK) +
 			inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
-		int type = laarr[curr].extLength & ~UDF_EXTENT_LENGTH_MASK;
+		int8_t etype = (laarr[curr].extLength >> 30);
 
 		if (blen == 1)
 			;
@@ -612,7 +600,7 @@ static void udf_split_extents(struct ino
 
 		if (offset)
 		{
-			if ((type >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30))
+			if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
 			{
 				udf_free_blocks(inode->i_sb, inode, laarr[curr].extLocation, 0, offset);
 				laarr[curr].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
@@ -621,7 +609,7 @@ static void udf_split_extents(struct ino
 				laarr[curr].extLocation.partitionReferenceNum = 0;
 			}
 			else
-				laarr[curr].extLength = type |
+				laarr[curr].extLength = (etype << 30) |
 					(offset << inode->i_sb->s_blocksize_bits);
 			curr ++;
 			(*c) ++;
@@ -629,7 +617,7 @@ static void udf_split_extents(struct ino
 		}
 		
 		laarr[curr].extLocation.logicalBlockNum = newblocknum;
-		if ((type >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
+		if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
 			laarr[curr].extLocation.partitionReferenceNum =
 				UDF_I_LOCATION(inode).partitionReferenceNum;
 		laarr[curr].extLength = EXT_RECORDED_ALLOCATED |
@@ -638,9 +626,9 @@ static void udf_split_extents(struct ino
 
 		if (blen != offset + 1)
 		{
-			if ((type >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30))
+			if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
 				laarr[curr].extLocation.logicalBlockNum += (offset + 1);
-			laarr[curr].extLength = type |
+			laarr[curr].extLength = (etype << 30) |
 				((blen - (offset + 1)) << inode->i_sb->s_blocksize_bits);
 			curr ++;
 			(*endnum) ++;
@@ -761,8 +749,8 @@ static void udf_merge_extents(struct ino
 					laarr[i+1].extLength = (laarr[i+1].extLength -
 						(laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
 						UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize-1);
-					laarr[i].extLength = (UDF_EXTENT_LENGTH_MASK + 1) -
-						inode->i_sb->s_blocksize;
+					laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_FLAG_MASK) +
+						(UDF_EXTENT_LENGTH_MASK + 1) - inode->i_sb->s_blocksize;
 					laarr[i+1].extLocation.logicalBlockNum =
 						laarr[i].extLocation.logicalBlockNum +
 						((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) >>
@@ -781,6 +769,47 @@ static void udf_merge_extents(struct ino
 				}
 			}
 		}
+		else if (((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) &&
+			((laarr[i+1].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)))
+		{
+			udf_free_blocks(inode->i_sb, inode, laarr[i].extLocation, 0,
+				((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+				inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+			laarr[i].extLocation.logicalBlockNum = 0;
+			laarr[i].extLocation.partitionReferenceNum = 0;
+
+			if (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+				(laarr[i+1].extLength & UDF_EXTENT_LENGTH_MASK) +
+				inode->i_sb->s_blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK)
+			{
+				laarr[i+1].extLength = (laarr[i+1].extLength -
+					(laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+					UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize-1);
+				laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_FLAG_MASK) +
+					(UDF_EXTENT_LENGTH_MASK + 1) - inode->i_sb->s_blocksize;
+			}
+			else
+			{
+				laarr[i].extLength = laarr[i+1].extLength +
+					(((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+					inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize-1));
+				if (*endnum > (i+2))
+					memmove(&laarr[i+1], &laarr[i+2],
+						sizeof(long_ad) * (*endnum - (i+2)));
+				i --;
+				(*endnum) --;
+			}
+		}
+		else if ((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30))
+		{
+			udf_free_blocks(inode->i_sb, inode, laarr[i].extLocation, 0,
+				((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+			       inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+			laarr[i].extLocation.logicalBlockNum = 0;
+			laarr[i].extLocation.partitionReferenceNum = 0;
+			laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) |
+				EXT_NOT_RECORDED_NOT_ALLOCATED;
+		}
 	}
 }
 
@@ -1014,7 +1043,7 @@ static void udf_fill_inode(struct inode 
 	struct extendedFileEntry *efe;
 	time_t convtime;
 	long convtime_usec;
-	int offset, alen;
+	int offset;
 
 	fe = (struct fileEntry *)bh->b_data;
 	efe = (struct extendedFileEntry *)bh->b_data;
@@ -1115,7 +1144,6 @@ static void udf_fill_inode(struct inode 
 		UDF_I_LENEATTR(inode) = le32_to_cpu(fe->lengthExtendedAttr);
 		UDF_I_LENALLOC(inode) = le32_to_cpu(fe->lengthAllocDescs);
 		offset = sizeof(struct fileEntry) + UDF_I_LENEATTR(inode);
-		alen = offset + UDF_I_LENALLOC(inode);
 	}
 	else
 	{
@@ -1170,7 +1198,6 @@ static void udf_fill_inode(struct inode 
 		UDF_I_LENEATTR(inode) = le32_to_cpu(efe->lengthExtendedAttr);
 		UDF_I_LENALLOC(inode) = le32_to_cpu(efe->lengthAllocDescs);
 		offset = sizeof(struct extendedFileEntry) + UDF_I_LENEATTR(inode);
-		alen = offset + UDF_I_LENALLOC(inode);
 	}
 
 	switch (fe->icbTag.fileType)
@@ -1211,6 +1238,11 @@ static void udf_fill_inode(struct inode 
 			init_special_inode(inode, inode->i_mode | S_IFIFO, 0);
 			break;
 		}
+		case ICBTAG_FILE_TYPE_SOCKET:
+		{
+			init_special_inode(inode, inode->i_mode | S_IFSOCK, 0);
+			break;
+		}
 		case ICBTAG_FILE_TYPE_SYMLINK:
 		{
 			inode->i_data.a_ops = &udf_symlink_aops;
@@ -1228,19 +1260,16 @@ static void udf_fill_inode(struct inode 
 	}
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
 	{
-		struct buffer_head *tbh = NULL;
 		struct deviceSpec *dsea =
 			(struct deviceSpec *)
-				udf_get_extendedattr(inode, 12, 1, &tbh);
+				udf_get_extendedattr(inode, 12, 1);
 
 		if (dsea)
 		{
 			init_special_inode(inode, inode->i_mode, MKDEV(
 				le32_to_cpu(dsea->majorDeviceIdent),
-				le32_to_cpu(dsea->minorDeviceIdent)
-			));
+				le32_to_cpu(dsea->minorDeviceIdent)));
 			/* Developer ID ??? */
-			udf_release_data(tbh);
 		}
 		else
 		{
@@ -1372,17 +1401,16 @@ udf_update_inode(struct inode *inode, in
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
 	{
 		regid *eid;
-		struct buffer_head *tbh = NULL;
 		struct deviceSpec *dsea =
 			(struct deviceSpec *)
-				udf_get_extendedattr(inode, 12, 1, &tbh);	
+				udf_get_extendedattr(inode, 12, 1);
 
 		if (!dsea)
 		{
 			dsea = (struct deviceSpec *)
 				udf_add_extendedattr(inode,
 					sizeof(struct deviceSpec) +
-					sizeof(regid), 12, 0x3, &tbh);
+					sizeof(regid), 12, 0x3);
 			dsea->attrType = 12;
 			dsea->attrSubtype = 1;
 			dsea->attrLength = sizeof(struct deviceSpec) +
@@ -1396,8 +1424,6 @@ udf_update_inode(struct inode *inode, in
 		eid->identSuffix[1] = UDF_OS_ID_LINUX;
 		dsea->majorDeviceIdent = cpu_to_le32(imajor(inode));
 		dsea->minorDeviceIdent = cpu_to_le32(iminor(inode));
-		mark_buffer_dirty_inode(tbh, inode);
-		udf_release_data(tbh);
 	}
 
 	if (UDF_I_EFE(inode) == 0)
@@ -1493,6 +1519,8 @@ udf_update_inode(struct inode *inode, in
 		fe->icbTag.fileType = ICBTAG_FILE_TYPE_CHAR;
 	else if (S_ISFIFO(inode->i_mode))
 		fe->icbTag.fileType = ICBTAG_FILE_TYPE_FIFO;
+	else if (S_ISSOCK(inode->i_mode))
+		fe->icbTag.fileType = ICBTAG_FILE_TYPE_SOCKET;
 
 	icbflags =	UDF_I_ALLOCTYPE(inode) |
 			((inode->i_mode & S_ISUID) ? ICBTAG_FLAG_SETUID : 0) |
@@ -1625,7 +1653,7 @@ int8_t udf_add_aext(struct inode *inode,
 		int err, loffset;
 		lb_addr obloc = *bloc;
 
-		if (!(bloc->logicalBlockNum = udf_new_block(inode->i_sb, inode,
+		if (!(bloc->logicalBlockNum = udf_new_block(inode->i_sb, NULL,
 			obloc.partitionReferenceNum, obloc.logicalBlockNum, &err)))
 		{
 			return -1;
@@ -1833,7 +1861,7 @@ int8_t udf_current_aext(struct inode *in
 		if (!(*extoffset))
 			*extoffset = sizeof(struct allocExtDesc);
 		ptr = (*bh)->b_data + *extoffset;
-		alen = le32_to_cpu(((struct allocExtDesc *)(*bh)->b_data)->lengthAllocDescs);
+		alen = sizeof(struct allocExtDesc) + le32_to_cpu(((struct allocExtDesc *)(*bh)->b_data)->lengthAllocDescs);
 	}
 
 	switch (UDF_I_ALLOCTYPE(inode))
--- diff/fs/udf/misc.c	2002-11-18 10:11:55.000000000 +0000
+++ source/fs/udf/misc.c	2004-03-09 11:51:51.000000000 +0000
@@ -16,7 +16,7 @@
  *	Each contributing author retains all rights to their own work.
  *
  *  (C) 1998 Dave Boynton
- *  (C) 1998-2001 Ben Fennema
+ *  (C) 1998-2004 Ben Fennema
  *  (C) 1999-2000 Stelias Computing Inc
  *
  * HISTORY
@@ -34,18 +34,6 @@
 #include "udf_i.h"
 #include "udf_sb.h"
 
-uint32_t
-udf64_low32(uint64_t indat)
-{
-	return indat & 0x00000000FFFFFFFFULL;
-}
-
-uint32_t
-udf64_high32(uint64_t indat)
-{
-	return indat >> 32;
-}
-
 extern struct buffer_head *
 udf_tgetblk(struct super_block *sb, int block)
 {
@@ -66,42 +54,24 @@ udf_tread(struct super_block *sb, int bl
 
 extern struct genericFormat *
 udf_add_extendedattr(struct inode * inode, uint32_t size, uint32_t type,
-	uint8_t loc, struct buffer_head **bh)
+	uint8_t loc)
 {
 	uint8_t *ea = NULL, *ad = NULL;
-	long_ad eaicb;
 	int offset;
+	uint16_t crclen;
+	int i;
 
-	*bh = udf_tread(inode->i_sb, inode->i_ino);
-
-	if (UDF_I_EFE(inode) == 0)
-	{
-		struct fileEntry *fe;
-
-		fe = (struct fileEntry *)(*bh)->b_data;
-		eaicb = lela_to_cpu(fe->extendedAttrICB);
-		offset = sizeof(struct fileEntry);
-	}
-	else
-	{
-		struct extendedFileEntry *efe;
-
-		efe = (struct extendedFileEntry *)(*bh)->b_data;
-		eaicb = lela_to_cpu(efe->extendedAttrICB);
-		offset = sizeof(struct extendedFileEntry);
-	}
-
-	ea = &(*bh)->b_data[offset];
+	ea = UDF_I_DATA(inode);
 	if (UDF_I_LENEATTR(inode))
-		offset += UDF_I_LENEATTR(inode);
+		ad = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode);
 	else
+	{
+		ad = ea;
 		size += sizeof(struct extendedAttrHeaderDesc);
+	}
 
-	ad = &(*bh)->b_data[offset];
-	if (UDF_I_LENALLOC(inode))
-		offset += UDF_I_LENALLOC(inode);
-
-	offset = inode->i_sb->s_blocksize - offset;
+	offset = inode->i_sb->s_blocksize - udf_file_entry_alloc_offset(inode) -
+		UDF_I_LENALLOC(inode);
 
 	/* TODO - Check for FreeEASpace */
 
@@ -121,7 +91,6 @@ udf_add_extendedattr(struct inode * inod
 			if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD ||
 				le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
 			{
-				udf_release_data(*bh);
 				return NULL;
 			}
 		}
@@ -130,8 +99,11 @@ udf_add_extendedattr(struct inode * inod
 			size -= sizeof(struct extendedAttrHeaderDesc);
 			UDF_I_LENEATTR(inode) += sizeof(struct extendedAttrHeaderDesc);
 			eahd->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EAHD);
-			eahd->descTag.descVersion = cpu_to_le16(2);
-			eahd->descTag.tagSerialNum = cpu_to_le16(1);
+			if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200)
+				eahd->descTag.descVersion = cpu_to_le16(3);
+			else
+				eahd->descTag.descVersion = cpu_to_le16(2);
+			eahd->descTag.tagSerialNum = cpu_to_le16(UDF_SB_SERIALNUM(inode->i_sb));
 			eahd->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
 			eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF);
 			eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF);
@@ -169,45 +141,30 @@ udf_add_extendedattr(struct inode * inod
 			}
 		}
 		/* rewrite CRC + checksum of eahd */
+		crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(tag);
+		eahd->descTag.descCRCLength = cpu_to_le16(crclen);
+		eahd->descTag.descCRC = cpu_to_le16(udf_crc((char *)eahd + sizeof(tag), crclen, 0));
+		eahd->descTag.tagChecksum = 0;
+		for (i=0; i<16; i++)
+			if (i != 4)
+				eahd->descTag.tagChecksum += ((uint8_t *)&(eahd->descTag))[i];
 		UDF_I_LENEATTR(inode) += size;
 		return (struct genericFormat *)&ea[offset];
 	}
 	if (loc & 0x02)
 	{
 	}
-	udf_release_data(*bh);
 	return NULL;
 }
 
 extern struct genericFormat *
-udf_get_extendedattr(struct inode * inode, uint32_t type, uint8_t subtype,
-	struct buffer_head **bh)
+udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype)
 {
 	struct genericFormat *gaf;
 	uint8_t *ea = NULL;
-	long_ad eaicb;
 	uint32_t offset;
 
-	*bh = udf_tread(inode->i_sb, inode->i_ino);
-
-	if (UDF_I_EFE(inode) == 0)
-	{
-		struct fileEntry *fe;
-
-		fe = (struct fileEntry *)(*bh)->b_data;
-		eaicb = lela_to_cpu(fe->extendedAttrICB);
-		if (UDF_I_LENEATTR(inode))
-			ea = fe->extendedAttr;
-	}
-	else
-	{
-		struct extendedFileEntry *efe;
-
-		efe = (struct extendedFileEntry *)(*bh)->b_data;
-		eaicb = lela_to_cpu(efe->extendedAttrICB);
-		if (UDF_I_LENEATTR(inode))
-			ea = efe->extendedAttr;
-	}
+	ea = UDF_I_DATA(inode);
 
 	if (UDF_I_LENEATTR(inode))
 	{
@@ -218,7 +175,6 @@ udf_get_extendedattr(struct inode * inod
 		if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD ||
 			le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
 		{
-			udf_release_data(*bh);
 			return NULL;
 		}
 	
@@ -238,12 +194,6 @@ udf_get_extendedattr(struct inode * inod
 				offset += le32_to_cpu(gaf->attrLength);
 		}
 	}
-
-	udf_release_data(*bh);
-	if (eaicb.extLength)
-	{
-		/* TODO */
-	}
 	return NULL;
 }
 
--- diff/fs/udf/namei.c	2003-10-09 09:47:17.000000000 +0100
+++ source/fs/udf/namei.c	2004-03-09 11:51:51.000000000 +0000
@@ -15,7 +15,7 @@
  *              ftp://prep.ai.mit.edu/pub/gnu/GPL
  *      Each contributing author retains all rights to their own work.
  *
- *  (C) 1998-2001 Ben Fennema
+ *  (C) 1998-2004 Ben Fennema
  *  (C) 1999-2000 Stelias Computing Inc
  *
  * HISTORY
@@ -36,11 +36,11 @@
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 
-static inline int udf_match(int len, const char * const name, struct qstr *qs)
+static inline int udf_match(int len1, const char *name1, int len2, const char *name2)
 {
-	if (len != qs->len)
+	if (len1 != len2)
 		return 0;
-	return !memcmp(name, qs->name, len);
+	return !memcmp(name1, name2, len1);
 }
 
 int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
@@ -154,8 +154,8 @@ udf_find_entry(struct inode *dir, struct
 {
 	struct fileIdentDesc *fi=NULL;
 	loff_t f_pos;
-	int block, flen;
-	char fname[255];
+	int block, namelen;
+	char name[UDF_NAME_LEN], fname[UDF_NAME_LEN];
 	char *nameptr;
 	uint8_t lfi;
 	uint16_t liu;
@@ -167,6 +167,9 @@ udf_find_entry(struct inode *dir, struct
 	if (!dir)
 		return NULL;
 
+	if ( !(namelen = udf_put_filename(dir->i_sb, dentry->d_name.name, name, dentry->d_name.len)))
+		return NULL;
+
 	f_pos = (udf_ext0_offset(dir) >> 2);
 
 	fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
@@ -250,13 +253,10 @@ udf_find_entry(struct inode *dir, struct
 		if (!lfi)
 			continue;
 
-		if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)))
+		if (udf_match(namelen, name, lfi, nameptr))
 		{
-			if (udf_match(flen, fname, &(dentry->d_name)))
-			{
-				udf_release_data(bh);
-				return fi;
-			}
+			udf_release_data(bh);
+			return fi;
 		}
 	}
 	if (fibh->sbh != fibh->ebh)
@@ -306,7 +306,7 @@ udf_lookup(struct inode *dir, struct den
 	struct fileIdentDesc cfi, *fi;
 	struct udf_fileident_bh fibh;
 
-	if (dentry->d_name.len > UDF_NAME_LEN)
+	if (dentry->d_name.len > UDF_NAME_LEN-2)
 		return ERR_PTR(-ENAMETOOLONG);
 
 	lock_kernel();
@@ -353,7 +353,6 @@ udf_add_entry(struct inode *dir, struct 
 	char name[UDF_NAME_LEN], fname[UDF_NAME_LEN];
 	int namelen;
 	loff_t f_pos;
-	int flen;
 	char *nameptr;
 	loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
 	int nfidlen;
@@ -481,8 +480,7 @@ udf_add_entry(struct inode *dir, struct 
 		if (!lfi || !dentry)
 			continue;
 
-		if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)) &&
-			udf_match(flen, fname, &(dentry->d_name)))
+		if (udf_match(namelen, name, lfi, nameptr))
 		{
 			if (fibh->sbh != fibh->ebh)
 				udf_release_data(fibh->ebh);
@@ -674,8 +672,8 @@ static int udf_mknod(struct inode * dir,
 {
 	struct inode * inode;
 	struct udf_fileident_bh fibh;
-	int err;
 	struct fileIdentDesc cfi, *fi;
+	int err;
 
 	if (!old_valid_dev(rdev))
 		return -EINVAL;
@@ -721,8 +719,8 @@ static int udf_mkdir(struct inode * dir,
 {
 	struct inode * inode;
 	struct udf_fileident_bh fibh;
-	int err;
 	struct fileIdentDesc cfi, *fi;
+	int err;
 
 	lock_kernel();
 	err = -EMLINK;
@@ -1119,8 +1117,8 @@ static int udf_link(struct dentry * old_
 {
 	struct inode *inode = old_dentry->d_inode;
 	struct udf_fileident_bh fibh;
-	int err;
 	struct fileIdentDesc cfi, *fi;
+	int err;
 
 	lock_kernel();
 	if (inode->i_nlink >= (256<<sizeof(inode->i_nlink))-1)
--- diff/fs/udf/osta_udf.h	2002-11-18 10:11:55.000000000 +0000
+++ source/fs/udf/osta_udf.h	2004-03-09 11:51:51.000000000 +0000
@@ -1,10 +1,10 @@
 /*
  * osta_udf.h
  *
- * This file is based on OSTA UDF(tm) 2.01 (March 15, 2000)
+ * This file is based on OSTA UDF(tm) 2.50 (April 30, 2003)
  * http://www.osta.org
  *
- * Copyright (c) 2001-2002  Ben Fennema <bfennema@falcon.csc.calpoly.edu>
+ * Copyright (c) 2001-2004  Ben Fennema <bfennema@falcon.csc.calpoly.edu>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -37,12 +37,12 @@
 #ifndef _OSTA_UDF_H
 #define _OSTA_UDF_H 1
 
-/* OSTA CS0 Charspec (UDF 2.01 2.1.2) */
+/* OSTA CS0 Charspec (UDF 2.50 2.1.2) */
 #define UDF_CHAR_SET_TYPE		0
 #define UDF_CHAR_SET_INFO		"OSTA Compressed Unicode"
 
-/* Entity Identifier (UDF 2.01 2.1.5) */
-/* Identifiers (UDF 2.01 2.1.5.2) */
+/* Entity Identifier (UDF 2.50 2.1.5) */
+/* Identifiers (UDF 2.50 2.1.5.2) */
 #define UDF_ID_DEVELOPER		"*Linux UDFFS"
 #define	UDF_ID_COMPLIANT		"*OSTA UDF Compliant"
 #define UDF_ID_LV_INFO			"*UDF LV Info"
@@ -59,8 +59,9 @@
 #define UDF_ID_SPARABLE			"*UDF Sparable Partition"
 #define UDF_ID_ALLOC			"*UDF Virtual Alloc Tbl"
 #define UDF_ID_SPARING			"*UDF Sparing Table"
+#define UDF_ID_METADATA			"*UDF Metadata Partition"
 
-/* Identifier Suffix (UDF 2.01 2.1.5.3) */
+/* Identifier Suffix (UDF 2.50 2.1.5.3) */
 #define IS_DF_HARD_WRITE_PROTECT	0x01
 #define IS_DF_SOFT_WRITE_PROTECT	0x02
 
@@ -84,8 +85,8 @@ struct appIdentSuffix
 	uint8_t		impUse[8];
 } __attribute__ ((packed));
 
-/* Logical Volume Integrity Descriptor (UDF 2.01 2.2.6) */
-/* Implementation Use (UDF 2.01 2.2.6.4) */
+/* Logical Volume Integrity Descriptor (UDF 2.50 2.2.6) */
+/* Implementation Use (UDF 2.50 2.2.6.4) */
 struct logicalVolIntegrityDescImpUse
 {
 	regid		impIdent;
@@ -97,8 +98,8 @@ struct logicalVolIntegrityDescImpUse
 	uint8_t		impUse[0];
 } __attribute__ ((packed));
 
-/* Implementation Use Volume Descriptor (UDF 2.01 2.2.7) */
-/* Implementation Use (UDF 2.01 2.2.7.2) */
+/* Implementation Use Volume Descriptor (UDF 2.50 2.2.7) */
+/* Implementation Use (UDF 2.50 2.2.7.2) */
 struct impUseVolDescImpUse
 {
 	charspec	LVICharset;
@@ -120,7 +121,7 @@ struct udfPartitionMap2
 	uint16_t	partitionNum;
 } __attribute__ ((packed));
 
-/* Virtual Partition Map (UDF 2.01 2.2.8) */
+/* Virtual Partition Map (UDF 2.50 2.2.8) */
 struct virtualPartitionMap
 {
 	uint8_t		partitionMapType;
@@ -132,7 +133,7 @@ struct virtualPartitionMap
 	uint8_t		reserved2[24];
 } __attribute__ ((packed));
 
-/* Sparable Partition Map (UDF 2.01 2.2.9) */
+/* Sparable Partition Map (UDF 2.50 2.2.9) */
 struct sparablePartitionMap
 {
 	uint8_t		partitionMapType;
@@ -148,25 +149,43 @@ struct sparablePartitionMap
 	uint32_t	locSparingTable[4];
 } __attribute__ ((packed));
 
+/* Metadata Partition Map (UDF 2.4.0 2.2.10) */
+struct metadataPartitionMap
+{
+	uint8_t		partitionMapType;
+	uint8_t		partitionMapLength;
+	uint8_t		reserved1[2];
+	regid		partIdent;
+	uint16_t	volSeqNum;
+	uint16_t	partitionNum;
+	uint32_t	metadataFileLoc;
+	uint32_t	metadataMirrorFileLoc;
+	uint32_t	metadataBitmapFileLoc;
+	uint32_t	allocUnitSize;
+	uint16_t	alignUnitSize;
+	uint8_t		flags;
+	uint8_t		reserved2[5];
+} __attribute__ ((packed));
+
 /* Virtual Allocation Table (UDF 1.5 2.2.10) */
 struct virtualAllocationTable15
 {
 	uint32_t	VirtualSector[0];
-	regid		ident;
-	uint32_t	previousVATICB;
+	regid		vatIdent;
+	uint32_t	previousVATICBLoc;
 } __attribute__ ((packed));  
 
 #define ICBTAG_FILE_TYPE_VAT15		0x00U
 
-/* Virtual Allocation Table (UDF 2.01 2.2.10) */
+/* Virtual Allocation Table (UDF 2.50 2.2.11) */
 struct virtualAllocationTable20
 {
 	uint16_t	lengthHeader;
 	uint16_t	lengthImpUse;
 	dstring		logicalVolIdent[128];
-	uint32_t	previousVatICBLoc;
-	uint32_t	numFIDSFiles;
-	uint32_t	numFIDSDirectories;
+	uint32_t	previousVATICBLoc;
+	uint32_t	numFiles;
+	uint32_t	numDirs;
 	uint16_t	minReadRevision;
 	uint16_t	minWriteRevision;
 	uint16_t	maxWriteRevision;
@@ -177,7 +196,7 @@ struct virtualAllocationTable20
 
 #define ICBTAG_FILE_TYPE_VAT20		0xF8U
 
-/* Sparing Table (UDF 2.01 2.2.11) */
+/* Sparing Table (UDF 2.50 2.2.12) */
 struct sparingEntry
 {
 	uint32_t	origLocation;
@@ -195,7 +214,12 @@ struct sparingTable
 			mapEntry[0];
 } __attribute__ ((packed));
 
-/* struct long_ad ICB - ADImpUse (UDF 2.01 2.2.4.3) */
+/* Metadata File (and Metadata Mirror File) (UDF 2.50 2.2.13.1) */
+#define ICBTAG_FILE_TYPE_MAIN		0xFA
+#define ICBTAG_FILE_TYPE_MIRROR		0xFB
+#define ICBTAG_FILE_TYPE_BITMAP		0xFC
+
+/* struct long_ad ICB - ADImpUse (UDF 2.50 2.2.4.3) */
 struct allocDescImpUse
 {
 	uint16_t	flags;
@@ -204,18 +228,18 @@ struct allocDescImpUse
 
 #define AD_IU_EXT_ERASED		0x0001
 
-/* Real-Time Files (UDF 2.01 6.11) */
+/* Real-Time Files (UDF 2.50 6.11) */
 #define ICBTAG_FILE_TYPE_REALTIME	0xF9U
 
-/* Implementation Use Extended Attribute (UDF 2.01 3.3.4.5) */
-/* FreeEASpace (UDF 2.01 3.3.4.5.1.1) */
+/* Implementation Use Extended Attribute (UDF 2.50 3.3.4.5) */
+/* FreeEASpace (UDF 2.50 3.3.4.5.1.1) */
 struct freeEaSpace
 {
 	uint16_t	headerChecksum;
 	uint8_t		freeEASpace[0];
 } __attribute__ ((packed));
 
-/* DVD Copyright Management Information (UDF 2.01 3.3.4.5.1.2) */
+/* DVD Copyright Management Information (UDF 2.50 3.3.4.5.1.2) */
 struct DVDCopyrightImpUse 
 {
 	uint16_t	headerChecksum;
@@ -224,21 +248,21 @@ struct DVDCopyrightImpUse 
 	uint8_t		protectionSystemInfo[4];
 } __attribute__ ((packed));
 
-/* Application Use Extended Attribute (UDF 2.01 3.3.4.6) */
-/* FreeAppEASpace (UDF 2.01 3.3.4.6.1) */
+/* Application Use Extended Attribute (UDF 2.50 3.3.4.6) */
+/* FreeAppEASpace (UDF 2.50 3.3.4.6.1) */
 struct freeAppEASpace
 {
 	uint16_t	headerChecksum;
 	uint8_t		freeEASpace[0];
 } __attribute__ ((packed));
 
-/* UDF Defined System Stream (UDF 2.01 3.3.7) */
+/* UDF Defined System Stream (UDF 2.50 3.3.7) */
 #define UDF_ID_UNIQUE_ID		"*UDF Unique ID Mapping Data"
 #define UDF_ID_NON_ALLOC		"*UDF Non-Allocatable Space"
 #define UDF_ID_POWER_CAL		"*UDF Power Cal Table"
 #define UDF_ID_BACKUP			"*UDF Backup"
 
-/* Operating System Identifiers (UDF 2.01 6.3) */
+/* Operating System Identifiers (UDF 2.50 6.3) */
 #define UDF_OS_CLASS_UNDEF		0x00U
 #define UDF_OS_CLASS_DOS		0x01U
 #define UDF_OS_CLASS_OS2		0x02U
@@ -254,6 +278,7 @@ struct freeAppEASpace
 #define UDF_OS_ID_DOS			0x00U
 #define UDF_OS_ID_OS2			0x00U
 #define UDF_OS_ID_MAC			0x00U
+#define UDF_OS_ID_MAX_OSX		0x01U
 #define UDF_OS_ID_UNIX			0x00U
 #define UDF_OS_ID_AIX			0x01U
 #define UDF_OS_ID_SOLARIS		0x02U
--- diff/fs/udf/super.c	2004-01-19 10:22:59.000000000 +0000
+++ source/fs/udf/super.c	2004-03-09 11:51:51.000000000 +0000
@@ -26,7 +26,7 @@
  *  Each contributing author retains all rights to their own work.
  *
  *  (C) 1998 Dave Boynton
- *  (C) 1998-2001 Ben Fennema
+ *  (C) 1998-2004 Ben Fennema
  *  (C) 2000 Stelias Computing Inc
  *
  * HISTORY
@@ -133,7 +133,8 @@ static void init_once(void * foo, kmem_c
 	struct udf_inode_info *ei = (struct udf_inode_info *) foo;
 
 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	    SLAB_CTOR_CONSTRUCTOR)
+	{
 		ei->i_ext.i_data = NULL;
 		inode_init_once(&ei->vfs_inode);
 	}
@@ -324,106 +325,106 @@ udf_parse_options(char *options, struct 
 	if (!options)
 		return 1;
 
-	while ((p = strsep(&options, ",")) != NULL) {
+	while ((p = strsep(&options, ",")) != NULL)
+	{
 		substring_t args[MAX_OPT_ARGS];
 		int token;
 		if (!*p)
 			continue;
 
 		token = match_token(p, tokens, args);
-		switch (token) {
-		case Opt_novrs:
-			uopt->novrs = 1;
-			break;
-		case Opt_bs:
-			if (match_int(&args[0], &option))
-				return 0;
-			uopt->blocksize = option;
-			break;
-		case Opt_unhide:
-			uopt->flags |= (1 << UDF_FLAG_UNHIDE);
-			break;
-		case Opt_undelete:
-			uopt->flags |= (1 << UDF_FLAG_UNDELETE);
-			break;
-		case Opt_noadinicb:
-			uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB);
-			break;
-		case Opt_adinicb:
-			uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB);
-			break;
-		case Opt_shortad:
-			uopt->flags |= (1 << UDF_FLAG_USE_SHORT_AD);
-			break;
-		case Opt_longad:
-			uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD);
-			break;
-		case Opt_gid:
-			if (match_int(args, &option))
-				return 0;
-			uopt->gid = option;
-			break;
-		case Opt_uid:
-			if (match_int(args, &option))
-				return 0;
-			uopt->uid = option;
-			break;
-		case Opt_umask:
-			if (match_octal(args, &option))
-				return 0;
-			uopt->umask = option;
-			break;
-		case Opt_nostrict:
-			uopt->flags &= ~(1 << UDF_FLAG_STRICT);
-			break;
-		case Opt_session:
-			if (match_int(args, &option))
-				return 0;
-			uopt->session = option;
-			break;
-		case Opt_lastblock:
-			if (match_int(args, &option))
-				return 0;
-			uopt->lastblock = option;
-			break;
-		case Opt_anchor:
-			if (match_int(args, &option))
-				return 0;
-			uopt->anchor = option;
-			break;
-		case Opt_volume:
-			if (match_int(args, &option))
-				return 0;
-			uopt->volume = option;
-			break;
-		case Opt_partition:
-			if (match_int(args, &option))
-				return 0;
-			uopt->partition = option;
-			break;
-		case Opt_fileset:
-			if (match_int(args, &option))
-				return 0;
-			uopt->fileset = option;
-			break;
-		case Opt_rootdir:
-			if (match_int(args, &option))
-				return 0;
-			uopt->rootdir = option;
-			break;
-		case Opt_utf8:
-			uopt->flags |= (1 << UDF_FLAG_UTF8);
-			break;
+		switch (token)
+		{
+			case Opt_novrs:
+				uopt->novrs = 1;
+			case Opt_bs:
+				if (match_int(&args[0], &option))
+					return 0;
+				uopt->blocksize = option;
+				break;
+			case Opt_unhide:
+				uopt->flags |= (1 << UDF_FLAG_UNHIDE);
+				break;
+			case Opt_undelete:
+				uopt->flags |= (1 << UDF_FLAG_UNDELETE);
+				break;
+			case Opt_noadinicb:
+				uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB);
+				break;
+			case Opt_adinicb:
+				uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB);
+				break;
+			case Opt_shortad:
+				uopt->flags |= (1 << UDF_FLAG_USE_SHORT_AD);
+				break;
+			case Opt_longad:
+				uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD);
+				break;
+			case Opt_gid:
+				if (match_int(args, &option))
+					return 0;
+				uopt->gid = option;
+				break;
+			case Opt_uid:
+				if (match_int(args, &option))
+					return 0;
+				uopt->uid = option;
+				break;
+			case Opt_umask:
+				if (match_octal(args, &option))
+					return 0;
+				uopt->umask = option;
+				break;
+			case Opt_nostrict:
+				uopt->flags &= ~(1 << UDF_FLAG_STRICT);
+				break;
+			case Opt_session:
+				if (match_int(args, &option))
+					return 0;
+				uopt->session = option;
+				break;
+			case Opt_lastblock:
+				if (match_int(args, &option))
+					return 0;
+				uopt->lastblock = option;
+				break;
+			case Opt_anchor:
+				if (match_int(args, &option))
+					return 0;
+				uopt->anchor = option;
+				break;
+			case Opt_volume:
+				if (match_int(args, &option))
+					return 0;
+				uopt->volume = option;
+				break;
+			case Opt_partition:
+				if (match_int(args, &option))
+					return 0;
+				uopt->partition = option;
+				break;
+			case Opt_fileset:
+				if (match_int(args, &option))
+					return 0;
+				uopt->fileset = option;
+				break;
+			case Opt_rootdir:
+				if (match_int(args, &option))
+					return 0;
+				uopt->rootdir = option;
+				break;
+			case Opt_utf8:
+				uopt->flags |= (1 << UDF_FLAG_UTF8);
+				break;
 #if defined(CONFIG_NLS) || defined(CONFIG_NLS_MODULE)
-		case Opt_iocharset:
-			uopt->nls_map = load_nls(args[0].from);
-			uopt->flags |= (1 << UDF_FLAG_NLS_MAP);
-			break;
+			case Opt_iocharset:
+				uopt->nls_map = load_nls(args[0].from);
+				uopt->flags |= (1 << UDF_FLAG_NLS_MAP);
+				break;
 #endif
-		default:
-			printk(KERN_ERR "udf: bad mount option \"%s\" "
-					"or missing value\n",
-				p);
+			default:
+				printk(KERN_ERR "udf: bad mount option \"%s\" "
+						"or missing value\n", p);
 			return 0;
 		}
 	}
@@ -1651,23 +1652,9 @@ error_out:
 		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE)
 			iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
 		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP)
-		{
-			for (i=0; i<UDF_SB_BITMAP_NR_GROUPS(sb,UDF_SB_PARTITION(sb),s_uspace); i++)
-			{
-				if (UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace,i))
-					udf_release_data(UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace,i));
-			}
-			kfree(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_bitmap);
-		}
+			UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace);
 		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
-		{
-			for (i=0; i<UDF_SB_BITMAP_NR_GROUPS(sb,UDF_SB_PARTITION(sb),s_fspace); i++)
-			{
-				if (UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace,i))
-					udf_release_data(UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace,i));
-			}
-			kfree(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_bitmap);
-		}
+			UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace);
 		if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15)
 		{
 			for (i=0; i<4; i++)
@@ -1743,23 +1730,9 @@ udf_put_super(struct super_block *sb)
 		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE)
 			iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
 		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP)
-		{
-			for (i=0; i<UDF_SB_BITMAP_NR_GROUPS(sb,UDF_SB_PARTITION(sb),s_uspace); i++)
-			{
-				if (UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace,i))
-					udf_release_data(UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace,i));
-			}
-			kfree(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_bitmap);
-		}
+			UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace);
 		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
-		{
-			for (i=0; i<UDF_SB_BITMAP_NR_GROUPS(sb,UDF_SB_PARTITION(sb),s_fspace); i++)
-			{
-				if (UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace,i))
-					udf_release_data(UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace,i));
-			}
-			kfree(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_bitmap);
-		}
+			UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace);
 		if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15)
 		{
 			for (i=0; i<4; i++)
@@ -1804,7 +1777,7 @@ udf_statfs(struct super_block *sb, struc
 		le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)) : 0) + buf->f_bfree;
 	buf->f_ffree = buf->f_bfree;
 	/* __kernel_fsid_t f_fsid */
-	buf->f_namelen = UDF_NAME_LEN;
+	buf->f_namelen = UDF_NAME_LEN-2;
 
 	return 0;
 }
--- diff/fs/udf/truncate.c	2002-11-18 10:11:55.000000000 +0000
+++ source/fs/udf/truncate.c	2004-03-09 11:51:51.000000000 +0000
@@ -15,7 +15,7 @@
  *		ftp://prep.ai.mit.edu/pub/gnu/GPL
  *	Each contributing author retains all rights to their own work.
  *
- *  (C) 1999-2001 Ben Fennema
+ *  (C) 1999-2004 Ben Fennema
  *  (C) 1999 Stelias Computing Inc
  *
  * HISTORY
@@ -66,6 +66,67 @@ static void extent_trunc(struct inode * 
 	}
 }
 
+void udf_discard_prealloc(struct inode * inode)
+{
+	lb_addr bloc, eloc;
+	uint32_t extoffset = 0, elen, nelen;
+	uint64_t lbcount = 0;
+	int8_t etype = -1, netype;
+	struct buffer_head *bh = NULL;
+	int adsize;
+
+	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB ||
+		inode->i_size == UDF_I_LENEXTENTS(inode))
+	{
+		return;
+	}
+
+	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
+		adsize = sizeof(short_ad);
+	else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
+		adsize = sizeof(long_ad);
+	else
+		adsize = 0;
+
+	bloc = UDF_I_LOCATION(inode);
+
+	while ((netype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
+	{
+		etype = netype;
+		lbcount += elen;
+		if (lbcount > inode->i_size && lbcount - inode->i_size < inode->i_sb->s_blocksize)
+		{
+			nelen = elen - (lbcount - inode->i_size);
+			extent_trunc(inode, bloc, extoffset-adsize, eloc, etype, elen, bh, nelen);
+			lbcount = inode->i_size;
+		}
+	}
+	if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
+	{
+		extoffset -= adsize;
+		lbcount -= elen;
+		extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0);
+		if (!bh)
+		{
+			UDF_I_LENALLOC(inode) = extoffset - udf_file_entry_alloc_offset(inode);
+			mark_inode_dirty(inode);
+		}
+		else
+		{
+			struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data);
+			aed->lengthAllocDescs = cpu_to_le32(extoffset - sizeof(struct allocExtDesc));
+			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+				udf_update_tag(bh->b_data, extoffset);
+			else
+				udf_update_tag(bh->b_data, sizeof(struct allocExtDesc));
+			mark_buffer_dirty_inode(bh, inode);
+		}
+	}
+	UDF_I_LENEXTENTS(inode) = lbcount;
+
+	udf_release_data(bh);
+}
+
 void udf_truncate_extents(struct inode * inode)
 {
 	lb_addr bloc, eloc, neloc = { 0, 0 };
--- diff/fs/udf/udf_sb.h	2002-10-16 04:27:48.000000000 +0100
+++ source/fs/udf/udf_sb.h	2004-03-09 11:51:51.000000000 +0000
@@ -64,13 +64,14 @@ static inline struct udf_sb_info *UDF_SB
 {\
 	int nr_groups = ((UDF_SB_PARTLEN((X),(Y)) + (sizeof(struct spaceBitmapDesc) << 3) +\
 		((X)->s_blocksize * 8) - 1) / ((X)->s_blocksize * 8));\
-	UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = kmalloc(sizeof(struct udf_bitmap) +\
-		sizeof(struct buffer_head *) * nr_groups,\
-		GFP_KERNEL);\
+	int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) * nr_groups);\
+	if (size <= PAGE_SIZE)\
+		UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = kmalloc(size, GFP_KERNEL);\
+	else\
+		UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = vmalloc(size);\
 	if (UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap != NULL)\
 	{\
-		memset(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap, 0x00,\
-			sizeof(struct udf_bitmap) + sizeof(struct buffer_head *) * nr_groups);\
+		memset(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap, 0x00, size);\
 		UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_block_bitmap =\
 			(struct buffer_head **)(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap + 1);\
 		UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups = nr_groups;\
@@ -81,6 +82,21 @@ static inline struct udf_sb_info *UDF_SB
 	}\
 }
 
+#define UDF_SB_FREE_BITMAP(X,Y,Z)\
+{\
+	int i;\
+	int nr_groups = UDF_SB_BITMAP_NR_GROUPS(X,Y,Z);\
+	int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) * nr_groups);\
+	for (i=0; i<nr_groups; i++)\
+	{\
+		if (UDF_SB_BITMAP(X,Y,Z,i))\
+			udf_release_data(UDF_SB_BITMAP(X,Y,Z,i));\
+	}\
+	if (size <= PAGE_SIZE)\
+		kfree(UDF_SB_PARTMAPS(X)[Y].Z.s_bitmap);\
+	else\
+		vfree(UDF_SB_PARTMAPS(X)[Y].Z.s_bitmap);\
+}
 
 #define UDF_QUERY_FLAG(X,Y)			( UDF_SB(X)->s_flags & ( 1 << (Y) ) )
 #define UDF_SET_FLAG(X,Y)			( UDF_SB(X)->s_flags |= ( 1 << (Y) ) )
@@ -99,7 +115,7 @@ static inline struct udf_sb_info *UDF_SB
 #define UDF_SB_PARTFUNC(X,Y)			( UDF_SB_PARTMAPS(X)[(Y)].s_partition_func )
 #define UDF_SB_PARTFLAGS(X,Y)			( UDF_SB_PARTMAPS(X)[(Y)].s_partition_flags )
 #define UDF_SB_BITMAP(X,Y,Z,I)			( UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_block_bitmap[I] )
-#define UDF_SB_BITMAP_NR_GROUPS(X,Y,Z)	( UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups )
+#define UDF_SB_BITMAP_NR_GROUPS(X,Y,Z)		( UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups )
 
 #define UDF_SB_VOLIDENT(X)			( UDF_SB(X)->s_volident )
 #define UDF_SB_NUMPARTS(X)			( UDF_SB(X)->s_partitions )
--- diff/fs/udf/udfdecl.h	2003-09-17 12:28:12.000000000 +0100
+++ source/fs/udf/udfdecl.h	2004-03-09 11:51:51.000000000 +0000
@@ -21,7 +21,7 @@
 #define UDF_EXTENT_FLAG_MASK	0xC0000000
 
 #define UDF_NAME_PAD		4
-#define UDF_NAME_LEN		255
+#define UDF_NAME_LEN		256
 #define UDF_PATH_LEN		1023
 
 #define udf_file_entry_alloc_offset(inode)\
@@ -59,13 +59,6 @@ struct udf_fileident_bh
 	int eoffset;
 };
 
-struct udf_directory_record
-{
-	uint32_t	d_parent;
-	uint32_t	d_inode;
-	uint32_t	d_name[255];
-};
-
 struct udf_vds_record
 {
 	uint32_t block;
@@ -81,7 +74,7 @@ struct generic_desc
 struct ustr
 {
 	uint8_t u_cmpID;
-	uint8_t u_name[UDF_NAME_LEN];
+	uint8_t u_name[UDF_NAME_LEN-2];
 	uint8_t u_len;
 };
 
@@ -116,19 +109,16 @@ extern int8_t udf_insert_aext(struct ino
 extern int8_t udf_delete_aext(struct inode *, lb_addr, int, lb_addr, uint32_t, struct buffer_head *);
 extern int8_t udf_next_aext(struct inode *, lb_addr *, int *, lb_addr *, uint32_t *, struct buffer_head **, int);
 extern int8_t udf_current_aext(struct inode *, lb_addr *, int *, lb_addr *, uint32_t *, struct buffer_head **, int);
-extern void udf_discard_prealloc(struct inode *);
 
 /* misc.c */
 extern int udf_read_tagged_data(char *, int size, int fd, int block, int partref);
 extern struct buffer_head *udf_tgetblk(struct super_block *, int);
 extern struct buffer_head *udf_tread(struct super_block *, int);
-extern struct genericFormat *udf_add_extendedattr(struct inode *, uint32_t, uint32_t, uint8_t, struct buffer_head **);
-extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t, uint8_t, struct buffer_head **);
+extern struct genericFormat *udf_add_extendedattr(struct inode *, uint32_t, uint32_t, uint8_t);
+extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t, uint8_t);
 extern struct buffer_head *udf_read_tagged(struct super_block *, uint32_t, uint32_t, uint16_t *);
 extern struct buffer_head *udf_read_ptagged(struct super_block *, lb_addr, uint32_t, uint16_t *);
 extern void udf_release_data(struct buffer_head *);
-extern uint32_t udf64_low32(uint64_t);
-extern uint32_t udf64_high32(uint64_t);
 extern void udf_update_tag(char *, int);
 extern void udf_new_tag(char *, uint16_t, uint16_t, uint16_t, uint32_t, int);
 
@@ -154,6 +144,7 @@ extern void udf_free_inode(struct inode 
 extern struct inode * udf_new_inode (struct inode *, int, int *);
 
 /* truncate.c */
+extern void udf_discard_prealloc(struct inode *);
 extern void udf_truncate_extents(struct inode *);
 
 /* balloc.c */
--- diff/fs/udf/unicode.c	2002-11-18 10:11:55.000000000 +0000
+++ source/fs/udf/unicode.c	2004-03-09 11:51:51.000000000 +0000
@@ -36,7 +36,7 @@ static int udf_translate_to_linux(uint8_
 
 static int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen)
 {
-	if ( (!dest) || (!src) || (!strlen) || (strlen >= UDF_NAME_LEN) )
+	if ( (!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN-2) )
 		return 0;
 	memset(dest, 0, sizeof(struct ustr));
 	memcpy(dest->u_name, src, strlen);
@@ -181,14 +181,14 @@ int udf_CS0toUTF8(struct ustr *utf_o, st
 static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length)
 {
 	unsigned c, i, max_val, utf_char;
-	int utf_cnt;
-	int u_len = 0;
+	int utf_cnt, u_len;
 
 	memset(ocu, 0, sizeof(dstring) * length);
 	ocu[0] = 8;
 	max_val = 0xffU;
 
 try_again:
+	u_len = 0U;
 	utf_char = 0U;
 	utf_cnt = 0U;
 	for (i = 0U; i < utf->u_len; i++)
@@ -264,8 +264,8 @@ try_again:
 	if (utf_cnt)
 	{
 error_out:
-		printk(KERN_ERR "udf: bad UTF-8 character\n");
-		return 0;
+		ocu[++u_len] = '?';
+		printk(KERN_DEBUG "udf: bad UTF-8 character\n");
 	}
 
 	ocu[length - 1] = (uint8_t)u_len + 1;
@@ -318,21 +318,21 @@ static int udf_NLStoCS0(struct nls_table
 {
 	unsigned len, i, max_val;
 	uint16_t uni_char;
-	int uni_cnt;
-	int u_len = 0;
+	int u_len;
 
 	memset(ocu, 0, sizeof(dstring) * length);
 	ocu[0] = 8;
 	max_val = 0xffU;
 
 try_again:
-	uni_char = 0U;
-	uni_cnt = 0U;
+	u_len = 0U;
 	for (i = 0U; i < uni->u_len; i++)
 	{
 		len = nls->char2uni(&uni->u_name[i], uni->u_len-i, &uni_char);
+		if (len <= 0)
+			continue;
 
-		if (len == 2 && max_val == 0xff)
+		if (uni_char > max_val)
 		{
 			max_val = 0xffffU;
 			ocu[0] = (uint8_t)0x10U;
@@ -340,11 +340,9 @@ try_again:
 		}
 		
 		if (max_val == 0xffffU)
-		{
 			ocu[++u_len] = (uint8_t)(uni_char >> 8);
-			i++;
-		}
 		ocu[++u_len] = (uint8_t)(uni_char & 0xffU);
+		i += len - 1;
 	}
 
 	ocu[length - 1] = (uint8_t)u_len + 1;
--- diff/fs/ufs/dir.c	2003-06-09 14:18:20.000000000 +0100
+++ source/fs/ufs/dir.c	2004-03-09 11:51:51.000000000 +0000
@@ -166,7 +166,6 @@ revalidate:
 		offset = 0;
 		brelse (bh);
 	}
-	update_atime(inode);
 	unlock_kernel();
 	return 0;
 }
--- diff/fs/ufs/inode.c	2003-09-17 12:28:12.000000000 +0100
+++ source/fs/ufs/inode.c	2004-03-09 11:51:51.000000000 +0000
@@ -82,7 +82,12 @@ static int ufs_block_to_path(struct inod
 	return n;
 }
 
-int ufs_frag_map(struct inode *inode, int frag)
+/*
+ * Returns the location of the fragment from
+ * the begining of the filesystem.
+ */
+
+u64  ufs_frag_map(struct inode *inode, int frag)
 {
 	struct ufs_inode_info *ufsi = UFS_I(inode);
 	struct super_block *sb = inode->i_sb;
@@ -93,6 +98,9 @@ int ufs_frag_map(struct inode *inode, in
 	int depth = ufs_block_to_path(inode, frag >> uspi->s_fpbshift, offsets);
 	int ret = 0;
 	u32 block;
+	u64 u2_block = 0;
+	unsigned flags = UFS_SB(sb)->s_flags;
+	u64 temp = 0;
 
 	if (depth == 0)
 		return 0;
@@ -100,6 +108,9 @@ int ufs_frag_map(struct inode *inode, in
 	p = offsets;
 
 	lock_kernel();
+	if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
+		goto ufs2;
+
 	block = ufsi->i_u1.i_data[*p++];
 	if (!block)
 		goto out;
@@ -116,6 +127,28 @@ int ufs_frag_map(struct inode *inode, in
 			goto out;
 	}
 	ret = uspi->s_sbbase + fs32_to_cpu(sb, block) + (frag & uspi->s_fpbmask);
+	goto out;
+ufs2:
+	u2_block = ufsi->i_u1.u2_i_data[*p++];
+	if (!u2_block)
+		goto out;
+
+	temp = (u64)uspi->s_sbbase + fs64_to_cpu(sb, u2_block);
+
+	while (--depth) {
+		struct buffer_head *bh;
+		u64 n = *p++;
+
+		bh = sb_bread(sb, temp +(n>>shift));
+		if (!bh)
+			goto out;
+		u2_block = ((u64*)bh->b_data)[n & mask];
+		brelse(bh);
+		if (!u2_block)
+			goto out;
+	}
+	ret = temp + (frag & uspi->s_fpbmask);
+
 out:
 	unlock_kernel();
 	return ret;
@@ -132,12 +165,20 @@ static struct buffer_head * ufs_inode_ge
 	unsigned block, blockoff, lastfrag, lastblock, lastblockoff;
 	unsigned tmp, goal;
 	u32 * p, * p2;
+	unsigned flags = 0;
 
 	UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u, required %u\n",
 		inode->i_ino, fragment, new_fragment, required))         
 
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
+
+	flags = UFS_SB(sb)->s_flags;
+        /* TODO : to be done for write support
+        if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
+             goto ufs2;
+         */
+
 	block = ufs_fragstoblks (fragment);
 	blockoff = ufs_fragnum (fragment);
 	p = ufsi->i_u1.i_data + block;
@@ -230,6 +271,21 @@ repeat:
 	mark_inode_dirty(inode);
 	UFSD(("EXIT, result %u\n", tmp + blockoff))
 	return result;
+
+     /* This part : To be implemented ....
+        Required only for writing, not required for READ-ONLY.
+ufs2:
+
+	u2_block = ufs_fragstoblks(fragment);
+	u2_blockoff = ufs_fragnum(fragment);
+	p = ufsi->i_u1.u2_i_data + block;
+	goal = 0;
+
+repeat2:
+	tmp = fs32_to_cpu(sb, *p);
+	lastfrag = ufsi->i_lastfrag;
+
+     */
 }
 
 static struct buffer_head * ufs_block_getfrag (struct inode *inode,
@@ -308,21 +364,28 @@ out:
 	return result;
 }
 
+/*
+ * This function gets the block which contains the fragment.
+ */
+
 static int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create)
 {
 	struct super_block * sb = inode->i_sb;
 	struct ufs_sb_private_info * uspi = UFS_SB(sb)->s_uspi;
 	struct buffer_head * bh;
 	int ret, err, new;
-	unsigned long ptr, phys;
+	unsigned long ptr,phys;
+	u64 phys64 = 0;
 	
 	if (!create) {
-		phys = ufs_frag_map(inode, fragment);
-		if (phys)
-			map_bh(bh_result, sb, phys);
+		phys64 = ufs_frag_map(inode, fragment);
+		if (phys64)
+			map_bh(bh_result, sb, phys64);
 		return 0;
 	}
 
+        /* This code entered only while writing ....? */
+
 	err = -EIO;
 	new = 0;
 	ret = 0;
@@ -474,6 +537,7 @@ void ufs_read_inode (struct inode * inod
 	struct super_block * sb;
 	struct ufs_sb_private_info * uspi;
 	struct ufs_inode * ufs_inode;	
+	struct ufs2_inode *ufs2_inode;
 	struct buffer_head * bh;
 	mode_t mode;
 	unsigned i;
@@ -496,6 +560,9 @@ void ufs_read_inode (struct inode * inod
 		ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino);
 		goto bad_inode;
 	}
+	if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
+		goto ufs2_inode;
+
 	ufs_inode = (struct ufs_inode *) (bh->b_data + sizeof(struct ufs_inode) * ufs_inotofsbo(inode->i_ino));
 
 	/*
@@ -564,6 +631,78 @@ void ufs_read_inode (struct inode * inod
 bad_inode:
 	make_bad_inode(inode);
 	return;
+
+ufs2_inode :
+	UFSD(("Reading ufs2 inode, ino %lu\n", inode->i_ino))
+
+	ufs2_inode = (struct ufs2_inode *)(bh->b_data + sizeof(struct ufs2_inode) * ufs_inotofsbo(inode->i_ino));
+
+	/*
+	 * Copy data to the in-core inode.
+	 */
+	inode->i_mode = mode = fs16_to_cpu(sb, ufs2_inode->ui_mode);
+	inode->i_nlink = fs16_to_cpu(sb, ufs2_inode->ui_nlink);
+	if (inode->i_nlink == 0)
+		ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink\n", inode->i_ino);
+
+        /*
+         * Linux now has 32-bit uid and gid, so we can support EFT.
+         */
+	inode->i_uid = fs32_to_cpu(sb, ufs2_inode->ui_uid);
+	inode->i_gid = fs32_to_cpu(sb, ufs2_inode->ui_gid);
+
+	inode->i_size = fs64_to_cpu(sb, ufs2_inode->ui_size);
+	inode->i_atime.tv_sec = fs32_to_cpu(sb, ufs2_inode->ui_atime.tv_sec);
+	inode->i_ctime.tv_sec = fs32_to_cpu(sb, ufs2_inode->ui_ctime.tv_sec);
+	inode->i_mtime.tv_sec = fs32_to_cpu(sb, ufs2_inode->ui_mtime.tv_sec);
+	inode->i_mtime.tv_nsec = 0;
+	inode->i_atime.tv_nsec = 0;
+	inode->i_ctime.tv_nsec = 0;
+	inode->i_blocks = fs64_to_cpu(sb, ufs2_inode->ui_blocks);
+	inode->i_blksize = PAGE_SIZE; /*This is the optimal IO size(for stat)*/
+
+	inode->i_version++;
+	ufsi->i_flags = fs32_to_cpu(sb, ufs2_inode->ui_flags);
+	ufsi->i_gen = fs32_to_cpu(sb, ufs2_inode->ui_gen);
+	/*
+	ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow);
+	ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag);
+	*/
+	ufsi->i_lastfrag= (inode->i_size + uspi->s_fsize- 1) >> uspi->s_fshift;
+
+	if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) {
+		for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++)
+			ufsi->i_u1.u2_i_data[i] =
+				ufs2_inode->ui_u2.ui_addr.ui_db[i];
+	}
+	else {
+		for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++)
+			ufsi->i_u1.i_symlink[i] = ufs2_inode->ui_u2.ui_symlink[i];
+	}
+	ufsi->i_osync = 0;
+
+	if (S_ISREG(inode->i_mode)) {
+		inode->i_op = &ufs_file_inode_operations;
+		inode->i_fop = &ufs_file_operations;
+		inode->i_mapping->a_ops = &ufs_aops;
+	} else if (S_ISDIR(inode->i_mode)) {
+		inode->i_op = &ufs_dir_inode_operations;
+		inode->i_fop = &ufs_dir_operations;
+	} else if (S_ISLNK(inode->i_mode)) {
+		if (!inode->i_blocks)
+			inode->i_op = &ufs_fast_symlink_inode_operations;
+		else {
+			inode->i_op = &page_symlink_inode_operations;
+			inode->i_mapping->a_ops = &ufs_aops;
+		}
+	} else   /* TODO  : here ...*/
+		init_special_inode(inode, inode->i_mode,
+			old_decode_dev(fs32_to_cpu(sb, ufsi->i_u1.i_data[0])));
+
+	brelse(bh);
+
+	UFSD(("EXIT\n"))
+	return;
 }
 
 static int ufs_update_inode(struct inode * inode, int do_sync)
--- diff/fs/ufs/namei.c	2003-09-30 15:46:19.000000000 +0100
+++ source/fs/ufs/namei.c	2004-03-09 11:51:51.000000000 +0000
@@ -31,7 +31,10 @@
 #include <linux/buffer_head.h>
 #include "swab.h"	/* will go away - see comment in mknod() */
 
+/*
 #undef UFS_NAMEI_DEBUG
+*/
+#define UFS_NAMEI_DEBUG
 
 #ifdef UFS_NAMEI_DEBUG
 #define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
--- diff/fs/ufs/super.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/ufs/super.c	2004-03-09 11:51:51.000000000 +0000
@@ -58,6 +58,9 @@
  * HP/UX hfs filesystem support added by
  * Martin K. Petersen <mkp@mkp.net>, August 1999
  *
+ * UFS2 (of FreeBSD 5.x) support added by
+ * Niraj Kumar <niraj17@iitbombay.org>, Jan 2004
+ *
  */
 
 
@@ -142,6 +145,28 @@ void ufs_print_super_stuff(struct super_
 	printk("\n");
 }
 
+/*
+ * Print contents of ufs2 ufs_super_block, useful for debugging
+ */
+void ufs2_print_super_stuff(
+     struct super_block *sb,
+      struct ufs_super_block *usb)
+{
+	printk("ufs_print_super_stuff\n");
+	printk("size of usb:     %u\n", sizeof(struct ufs_super_block));
+	printk("  magic:         0x%x\n", fs32_to_cpu(sb, usb->fs_magic));
+	printk("  fs_size:   %u\n",fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_size));
+	printk("  fs_dsize:  %u\n",fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize));
+	printk("  fs_volname:  %s\n", usb->fs_u11.fs_u2.fs_volname);
+	printk("  fs_fsmnt:  %s\n", usb->fs_u11.fs_u2.fs_fsmnt);
+	printk("  fs_sblockloc: %u\n",fs64_to_cpu(sb,
+			usb->fs_u11.fs_u2.fs_sblockloc));
+	printk("  cs_ndir(No of dirs):  %u\n",fs64_to_cpu(sb,
+			usb->fs_u11.fs_u2.fs_cstotal.cs_ndir));
+	printk("  cs_nbfree(No of free blocks):  %u\n",fs64_to_cpu(sb,
+			usb->fs_u11.fs_u2.fs_cstotal.cs_nbfree));
+	printk("\n");
+}
 
 /*
  * Print contents of ufs_cylinder_group, useful for debugging
@@ -253,7 +278,7 @@ void ufs_warning (struct super_block * s
 
 enum {
 	Opt_type_old, Opt_type_sunx86, Opt_type_sun, Opt_type_44bsd,
-	Opt_type_hp, Opt_type_nextstepcd, Opt_type_nextstep,
+	Opt_type_ufs2, Opt_type_hp, Opt_type_nextstepcd, Opt_type_nextstep,
 	Opt_type_openstep, Opt_onerror_panic, Opt_onerror_lock,
 	Opt_onerror_umount, Opt_onerror_repair, Opt_err
 };
@@ -263,6 +288,8 @@ static match_table_t tokens = {
 	{Opt_type_sunx86, "ufstype=sunx86"},
 	{Opt_type_sun, "ufstype=sun"},
 	{Opt_type_44bsd, "ufstype=44bsd"},
+	{Opt_type_ufs2, "ufstype=ufs2"},
+	{Opt_type_ufs2, "ufstype=5xbsd"},
 	{Opt_type_hp, "ufstype=hp"},
 	{Opt_type_nextstepcd, "ufstype=nextstep-cd"},
 	{Opt_type_nextstep, "ufstype=nextstep"},
@@ -307,6 +334,10 @@ static int ufs_parse_options (char * opt
 			ufs_clear_opt (*mount_options, UFSTYPE);
 			ufs_set_opt (*mount_options, UFSTYPE_44BSD);
 			break;
+		case Opt_type_ufs2:
+			ufs_clear_opt(*mount_options, UFSTYPE);
+			ufs_set_opt(*mount_options, UFSTYPE_UFS2);
+			break;
 		case Opt_type_hp:
 			ufs_clear_opt (*mount_options, UFSTYPE);
 			ufs_set_opt (*mount_options, UFSTYPE_HP);
@@ -356,13 +387,20 @@ static int ufs_parse_options (char * opt
 int ufs_read_cylinder_structures (struct super_block * sb) {
 	struct ufs_sb_info * sbi = UFS_SB(sb);
 	struct ufs_sb_private_info * uspi;
+	struct ufs_super_block *usb;
 	struct ufs_buffer_head * ubh;
 	unsigned char * base, * space;
 	unsigned size, blks, i;
+	unsigned flags = 0;
 	
 	UFSD(("ENTER\n"))
 	
 	uspi = sbi->s_uspi;
+
+	usb  = (struct ufs_super_block *)
+		((struct ufs_buffer_head *)uspi)->bh[0]->b_data;
+
+        flags = UFS_SB(sb)->s_flags;
 	
 	/*
 	 * Read cs structures from (usually) first data block
@@ -377,11 +415,22 @@ int ufs_read_cylinder_structures (struct
 		size = uspi->s_bsize;
 		if (i + uspi->s_fpb > blks)
 			size = (blks - i) * uspi->s_fsize;
-		ubh = ubh_bread(sb, uspi->s_csaddr + i, size);
-		if (!ubh)
-			goto failed;
-		ubh_ubhcpymem (space, ubh, size);
-		sbi->s_csp[ufs_fragstoblks(i)] = (struct ufs_csum *)space;
+
+		if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+			ubh = ubh_bread(sb,
+				fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_csaddr) + i, size);
+			if (!ubh)
+				goto failed;
+			ubh_ubhcpymem (space, ubh, size);
+			sbi->s_csp[ufs_fragstoblks(i)]=(struct ufs_csum *)space;
+		}
+		else {
+			ubh = ubh_bread(sb, uspi->s_csaddr + i, size);
+			if (!ubh)
+				goto failed;
+			ubh_ubhcpymem(space, ubh, size);
+			sbi->s_csp[ufs_fragstoblks(i)]=(struct ufs_csum *)space;
+		}
 		space += size;
 		ubh_brelse (ubh);
 		ubh = NULL;
@@ -480,6 +529,7 @@ static int ufs_fill_super(struct super_b
 	struct ufs_super_block_first * usb1;
 	struct ufs_super_block_second * usb2;
 	struct ufs_super_block_third * usb3;
+	struct ufs_super_block *usb;
 	struct ufs_buffer_head * ubh;	
 	struct inode *inode;
 	unsigned block_size, super_block_size;
@@ -520,7 +570,7 @@ static int ufs_fill_super(struct super_b
 		if (!silent)
 			printk("You didn't specify the type of your ufs filesystem\n\n"
 			"mount -t ufs -o ufstype="
-			"sun|sunx86|44bsd|old|hp|nextstep|netxstep-cd|openstep ...\n\n"
+			"sun|sunx86|44bsd|ufs2|5xbsd|old|hp|nextstep|netxstep-cd|openstep ...\n\n"
 			">>>WARNING<<< Wrong ufstype may corrupt your filesystem, "
 			"default is ufstype=old\n");
 		ufs_set_opt (sbi->s_mount_opt, UFSTYPE_OLD);
@@ -545,6 +595,19 @@ static int ufs_fill_super(struct super_b
 		uspi->s_sbbase = 0;
 		flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD;
 		break;
+	case UFS_MOUNT_UFSTYPE_UFS2:
+		UFSD(("ufstype=ufs2\n"))
+		uspi->s_fsize = block_size = 512;
+		uspi->s_fmask = ~(512 - 1);
+		uspi->s_fshift = 9;
+		uspi->s_sbsize = super_block_size = 1536;
+		uspi->s_sbbase =  0;
+		flags |= UFS_TYPE_UFS2 | UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD;
+		if (!(sb->s_flags & MS_RDONLY)) {
+			printk(KERN_INFO "ufstype=ufs2 is supported read-only\n");
+			sb->s_flags |= MS_RDONLY;
+ 		}
+		break;
 		
 	case UFS_MOUNT_UFSTYPE_SUN:
 		UFSD(("ufstype=sun\n"))
@@ -657,27 +720,37 @@ again:	
 	/*
 	 * read ufs super block from device
 	 */
-	ubh = ubh_bread_uspi (uspi, sb, uspi->s_sbbase + UFS_SBLOCK/block_size, super_block_size);
+	if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+		ubh = ubh_bread_uspi(uspi, sb, uspi->s_sbbase + SBLOCK_UFS2/block_size, super_block_size);
+	}
+	else {
+		ubh = ubh_bread_uspi(uspi, sb, uspi->s_sbbase + UFS_SBLOCK/block_size, super_block_size);
+	}
 	if (!ubh) 
-		goto failed;
+            goto failed;
+
 	
 	usb1 = ubh_get_usb_first(USPI_UBH);
 	usb2 = ubh_get_usb_second(USPI_UBH);
 	usb3 = ubh_get_usb_third(USPI_UBH);
+	usb  = (struct ufs_super_block *)
+		((struct ufs_buffer_head *)uspi)->bh[0]->b_data ;
 
 	/*
 	 * Check ufs magic number
 	 */
-	switch (__constant_le32_to_cpu(usb3->fs_magic)) {
+	switch ((uspi->fs_magic = __constant_le32_to_cpu(usb3->fs_magic))) {
 		case UFS_MAGIC:
+		case UFS2_MAGIC:
 		case UFS_MAGIC_LFN:
 	        case UFS_MAGIC_FEA:
 	        case UFS_MAGIC_4GB:
 			sbi->s_bytesex = BYTESEX_LE;
 			goto magic_found;
 	}
-	switch (__constant_be32_to_cpu(usb3->fs_magic)) {
+	switch ((uspi->fs_magic = __constant_be32_to_cpu(usb3->fs_magic))) {
 		case UFS_MAGIC:
+		case UFS2_MAGIC:
 		case UFS_MAGIC_LFN:
 	        case UFS_MAGIC_FEA:
 	        case UFS_MAGIC_4GB:
@@ -748,7 +821,10 @@ magic_found:
 	}
 
 #ifdef UFS_SUPER_DEBUG_MORE
-	ufs_print_super_stuff(sb, usb1, usb2, usb3);
+        if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
+		ufs2_print_super_stuff(sb,usb);
+        else
+		ufs_print_super_stuff(sb, usb1, usb2, usb3);
 #endif
 
 	/*
@@ -802,8 +878,16 @@ magic_found:
 	uspi->s_dblkno = fs32_to_cpu(sb, usb1->fs_dblkno);
 	uspi->s_cgoffset = fs32_to_cpu(sb, usb1->fs_cgoffset);
 	uspi->s_cgmask = fs32_to_cpu(sb, usb1->fs_cgmask);
-	uspi->s_size = fs32_to_cpu(sb, usb1->fs_size);
-	uspi->s_dsize = fs32_to_cpu(sb, usb1->fs_dsize);
+
+	if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+		uspi->s_u2_size  = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_size);
+		uspi->s_u2_dsize = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize);
+	}
+	else {
+		uspi->s_size  =  fs32_to_cpu(sb, usb1->fs_size);
+		uspi->s_dsize =  fs32_to_cpu(sb, usb1->fs_dsize);
+	}
+
 	uspi->s_ncg = fs32_to_cpu(sb, usb1->fs_ncg);
 	/* s_bsize already set */
 	/* s_fsize already set */
@@ -1021,21 +1105,36 @@ int ufs_statfs (struct super_block * sb,
 {
 	struct ufs_sb_private_info * uspi;
 	struct ufs_super_block_first * usb1;
+	struct ufs_super_block * usb;
+	unsigned  flags = 0;
 
 	lock_kernel();
 
 	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first (USPI_UBH);
+	usb  = (struct ufs_super_block *)
+		((struct ufs_buffer_head *)uspi)->bh[0]->b_data ;
 	
-	buf->f_type = UFS_MAGIC;
+	flags = UFS_SB(sb)->s_flags;
+	if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+		buf->f_type = UFS2_MAGIC;
+		buf->f_blocks = usb->fs_u11.fs_u2.fs_dsize;
+		buf->f_bfree = ufs_blkstofrags(fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_cstotal.cs_nbfree)) +
+			fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_cstotal.cs_nffree);
+		buf->f_ffree = fs64_to_cpu(sb,
+        		usb->fs_u11.fs_u2.fs_cstotal.cs_nifree);
+	}
+	else {
+		buf->f_type = UFS_MAGIC;
+		buf->f_blocks = uspi->s_dsize;
+		buf->f_bfree = ufs_blkstofrags(fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree)) +
+			fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree);
+		buf->f_ffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree);
+	}
 	buf->f_bsize = sb->s_blocksize;
-	buf->f_blocks = uspi->s_dsize;
-	buf->f_bfree = ufs_blkstofrags(fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree)) +
-		fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree);
 	buf->f_bavail = (buf->f_bfree > (((long)buf->f_blocks / 100) * uspi->s_minfree))
 		? (buf->f_bfree - (((long)buf->f_blocks / 100) * uspi->s_minfree)) : 0;
 	buf->f_files = uspi->s_ncg * uspi->s_ipg;
-	buf->f_ffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree);
 	buf->f_namelen = UFS_MAXNAMLEN;
 
 	unlock_kernel();
--- diff/fs/ufs/util.c	2003-05-21 11:49:55.000000000 +0100
+++ source/fs/ufs/util.c	2004-03-09 11:51:51.000000000 +0000
@@ -24,10 +24,11 @@
 
 
 struct ufs_buffer_head * _ubh_bread_ (struct ufs_sb_private_info * uspi,
-	struct super_block *sb, unsigned fragment, unsigned size)
+	struct super_block *sb, u64 fragment, u64 size)
 {
 	struct ufs_buffer_head * ubh;
-	unsigned i, j, count;
+	unsigned i, j ;
+	u64  count = 0;
 	if (size & ~uspi->s_fmask)
 		return NULL;
 	count = size >> uspi->s_fshift;
@@ -53,9 +54,10 @@ failed:
 }
 
 struct ufs_buffer_head * ubh_bread_uspi (struct ufs_sb_private_info * uspi,
-	struct super_block *sb, unsigned fragment, unsigned size)
+	struct super_block *sb, u64 fragment, u64 size)
 {
-	unsigned i, j, count;
+	unsigned i, j;
+	u64 count = 0;
 	if (size & ~uspi->s_fmask)
 		return NULL;
 	count = size >> uspi->s_fshift;
--- diff/fs/ufs/util.h	2003-05-21 11:49:46.000000000 +0100
+++ source/fs/ufs/util.h	2004-03-09 11:51:51.000000000 +0000
@@ -228,8 +228,8 @@ ufs_set_inode_gid(struct super_block *sb
  * These functions manipulate ufs buffers
  */
 #define ubh_bread(sb,fragment,size) _ubh_bread_(uspi,sb,fragment,size)  
-extern struct ufs_buffer_head * _ubh_bread_(struct ufs_sb_private_info *, struct super_block *, unsigned, unsigned);
-extern struct ufs_buffer_head * ubh_bread_uspi(struct ufs_sb_private_info *, struct super_block *, unsigned, unsigned);
+extern struct ufs_buffer_head * _ubh_bread_(struct ufs_sb_private_info *, struct super_block *, u64 , u64);
+extern struct ufs_buffer_head * ubh_bread_uspi(struct ufs_sb_private_info *, struct super_block *, u64, u64);
 extern void ubh_brelse (struct ufs_buffer_head *);
 extern void ubh_brelse_uspi (struct ufs_sb_private_info *);
 extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *);
--- diff/fs/xfs/linux/xfs_aops.c	2004-03-04 11:41:49.000000000 +0000
+++ source/fs/xfs/linux/xfs_aops.c	2004-03-09 11:51:51.000000000 +0000
@@ -1032,7 +1032,8 @@ linvfs_direct_IO(
 	if (error)
 		return -error;
 
-	return blockdev_direct_IO(rw, iocb, inode, iomap.iomap_target->pbr_bdev,
+	return blockdev_direct_IO_no_locking(rw, iocb, inode,
+		iomap.iomap_target->pbr_bdev,
 		iov, offset, nr_segs,
 		linvfs_get_blocks_direct,
 		linvfs_unwritten_convert_direct);
--- diff/fs/xfs/linux/xfs_super.c	2004-03-04 11:41:49.000000000 +0000
+++ source/fs/xfs/linux/xfs_super.c	2004-03-09 11:51:51.000000000 +0000
@@ -247,7 +247,7 @@ xfs_flush_inode(
 {
 	struct inode	*inode = LINVFS_GET_IP(XFS_ITOV(ip));
 
-	filemap_fdatawrite(inode->i_mapping);
+	filemap_flush(inode->i_mapping);
 }
 
 void
--- diff/fs/xfs/xfs_log.c	2004-03-04 11:41:49.000000000 +0000
+++ source/fs/xfs/xfs_log.c	2004-03-09 11:51:51.000000000 +0000
@@ -1227,7 +1227,7 @@ xlog_alloc_log(xfs_mount_t	*mp,
 			  kmem_zalloc(sizeof(xlog_in_core_t), KM_SLEEP);
 		iclog = *iclogp;
 		iclog->hic_data = (xlog_in_core_2_t *)
-			  kmem_alloc(iclogsize, KM_SLEEP);
+			  kmem_zalloc(iclogsize, KM_SLEEP);
 
 		iclog->ic_prev = prev_iclog;
 		prev_iclog = iclog;
--- diff/include/acpi/acconfig.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/acpi/acconfig.h	2004-03-09 11:51:51.000000000 +0000
@@ -64,7 +64,7 @@
 
 /* Version string */
 
-#define ACPI_CA_VERSION                 0x20040211
+#define ACPI_CA_VERSION                 0x20040220
 
 /* Maximum objects in the various object caches */
 
--- diff/include/acpi/acglobal.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/acpi/acglobal.h	2004-03-09 11:51:51.000000000 +0000
@@ -57,6 +57,12 @@
 #define ACPI_EXTERN extern
 #endif
 
+/*
+ * Keep local copies of these FADT-based registers.  NOTE: These globals
+ * are first in this file for alignment reasons on 64-bit systems.
+ */
+ACPI_EXTERN struct acpi_generic_address         acpi_gbl_xpm1a_enable;
+ACPI_EXTERN struct acpi_generic_address         acpi_gbl_xpm1b_enable;
 
 /*****************************************************************************
  *
@@ -97,6 +103,11 @@ ACPI_EXTERN FADT_DESCRIPTOR            *
 ACPI_EXTERN struct acpi_table_header           *acpi_gbl_DSDT;
 ACPI_EXTERN FACS_DESCRIPTOR            *acpi_gbl_FACS;
 ACPI_EXTERN struct acpi_common_facs             acpi_gbl_common_fACS;
+/*
+ * Since there may be multiple SSDTs and PSDTS, a single pointer is not
+ * sufficient; Therefore, there isn't one!
+ */
+
 
 /*
  * Handle both ACPI 1.0 and ACPI 2.0 Integer widths
@@ -107,17 +118,6 @@ ACPI_EXTERN u8                          
 ACPI_EXTERN u8                                  acpi_gbl_integer_byte_width;
 ACPI_EXTERN u8                                  acpi_gbl_integer_nybble_width;
 
-/* Keep local copies of these FADT-based registers */
-
-ACPI_EXTERN struct acpi_generic_address         acpi_gbl_xpm1a_enable;
-ACPI_EXTERN struct acpi_generic_address         acpi_gbl_xpm1b_enable;
-
-/*
- * Since there may be multiple SSDTs and PSDTS, a single pointer is not
- * sufficient; Therefore, there isn't one!
- */
-
-
 /*
  * ACPI Table info arrays
  */
@@ -165,7 +165,8 @@ ACPI_EXTERN u8                          
 extern u8                                       acpi_gbl_shutdown;
 extern u32                                      acpi_gbl_startup_flags;
 extern const u8                                 acpi_gbl_decode_to8bit[8];
-extern const char                              *acpi_gbl_db_sleep_states[ACPI_S_STATE_COUNT];
+extern const char                              *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT];
+extern const char                              *acpi_gbl_highest_dstate_names[4];
 extern const struct acpi_opcode_info            acpi_gbl_aml_op_info[AML_NUM_OPCODES];
 extern const char                              *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS];
 
--- diff/include/acpi/acpixf.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/acpi/acpixf.h	2004-03-09 11:51:51.000000000 +0000
@@ -450,7 +450,7 @@ acpi_status asmlinkage
 acpi_enter_sleep_state (
 	u8                              sleep_state);
 
-acpi_status
+acpi_status asmlinkage
 acpi_enter_sleep_state_s4bios (
 	void);
 
--- diff/include/acpi/actypes.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/acpi/actypes.h	2004-03-09 11:51:51.000000000 +0000
@@ -880,7 +880,8 @@ struct acpi_device_info
 {
 	ACPI_COMMON_OBJ_INFO;
 
-	u32                                 valid;              /* Indicates which fields are valid */
+	u8                                  highest_dstates[4]; /* _sx_d values 0xFF indicates not valid */
+	u32                                 valid;              /* Indicates which fields below are valid */
 	u32                                 current_status;     /* _STA value */
 	acpi_integer                        address;            /* _ADR value if any */
 	struct acpi_device_id               hardware_id;        /* _HID value if any */
--- diff/include/acpi/acutils.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/acpi/acutils.h	2004-03-09 11:51:51.000000000 +0000
@@ -508,6 +508,10 @@ acpi_ut_execute_UID (
 	struct acpi_namespace_node      *device_node,
 	struct acpi_device_id           *uid);
 
+acpi_status
+acpi_ut_execute_sxds (
+	struct acpi_namespace_node      *device_node,
+	u8                              *highest);
 
 /*
  * ut_mutex - mutual exclusion interfaces
--- diff/include/asm-alpha/irq.h	2003-08-20 14:16:33.000000000 +0100
+++ source/include/asm-alpha/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -93,5 +93,8 @@ extern void enable_irq(unsigned int);
 struct pt_regs;
 extern void (*perf_irq)(unsigned long, struct pt_regs *);
 
+struct irqaction;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+
 
 #endif /* _ALPHA_IRQ_H */
--- diff/include/asm-alpha/pci.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-alpha/pci.h	2004-03-09 11:51:51.000000000 +0000
@@ -88,7 +88,7 @@ extern void pci_free_consistent(struct p
 /* Map a single buffer of the indicate size for PCI DMA in streaming
    mode.  The 32-bit PCI bus mastering address to use is returned.
    Once the device is given the dma address, the device owns this memory
-   until either pci_unmap_single or pci_dma_sync_single is performed.  */
+   until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed.  */
 
 extern dma_addr_t pci_map_single(struct pci_dev *, void *, size_t, int);
 
@@ -142,28 +142,44 @@ extern int pci_map_sg(struct pci_dev *, 
 extern void pci_unmap_sg(struct pci_dev *, struct scatterlist *, int, int);
 
 /* Make physical memory consistent for a single streaming mode DMA
-   translation after a transfer.
+   translation after a transfer and device currently has ownership
+   of the buffer.
 
    If you perform a pci_map_single() but wish to interrogate the
    buffer using the cpu, yet do not wish to teardown the PCI dma
    mapping, you must call this function before doing so.  At the next
-   point you give the PCI dma address back to the card, the device
-   again owns the buffer.  */
+   point you give the PCI dma address back to the card, you must first
+   perform a pci_dma_sync_for_device, and then the device again owns
+   the buffer.  */
 
 static inline void
-pci_dma_sync_single(struct pci_dev *dev, dma_addr_t dma_addr, long size,
-		    int direction)
+pci_dma_sync_single_for_cpu(struct pci_dev *dev, dma_addr_t dma_addr, long size,
+			    int direction)
+{
+	/* Nothing to do.  */
+}
+
+static inline void
+pci_dma_sync_single_for_device(struct pci_dev *dev, dma_addr_t dma_addr, long size,
+			       int direction)
 {
 	/* Nothing to do.  */
 }
 
 /* Make physical memory consistent for a set of streaming mode DMA
-   translations after a transfer.  The same as pci_dma_sync_single but
-   for a scatter-gather list, same rules and usage.  */
+   translations after a transfer.  The same as pci_dma_sync_single_*
+   but for a scatter-gather list, same rules and usage.  */
+
+static inline void
+pci_dma_sync_sg_for_cpu(struct pci_dev *dev, struct scatterlist *sg, int nents,
+			int direction)
+{
+	/* Nothing to do.  */
+}
 
 static inline void
-pci_dma_sync_sg(struct pci_dev *dev, struct scatterlist *sg, int nents,
-	        int direction)
+pci_dma_sync_sg_for_device(struct pci_dev *dev, struct scatterlist *sg, int nents,
+			int direction)
 {
 	/* Nothing to do.  */
 }
@@ -184,8 +200,14 @@ extern dma64_addr_t pci_dac_page_to_dma(
 extern struct page *pci_dac_dma_to_page(struct pci_dev *, dma64_addr_t);
 extern unsigned long pci_dac_dma_to_offset(struct pci_dev *, dma64_addr_t);
 
-static __inline__ void
-pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
+static inline void
+pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
+{
+	/* Nothing to do. */
+}
+
+static inline void
+pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
 {
 	/* Nothing to do. */
 }
--- diff/include/asm-alpha/spinlock.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-alpha/spinlock.h	2004-03-09 11:51:51.000000000 +0000
@@ -6,6 +6,10 @@
 #include <linux/kernel.h>
 #include <asm/current.h>
 
+#ifdef CONFIG_LOCKMETER
+#undef DEBUG_SPINLOCK
+#undef DEBUG_RWLOCK
+#endif
 
 /*
  * Simple spin lock operations.  There are two variants, one clears IRQ's
@@ -95,9 +99,18 @@ static inline int _raw_spin_trylock(spin
 
 typedef struct {
 	volatile int write_lock:1, read_counter:31;
+#ifdef CONFIG_LOCKMETER
+	/* required for LOCKMETER since all bits in lock are used */
+	/* need this storage for CPU and lock INDEX ............. */
+	unsigned magic;
+#endif
 } /*__attribute__((aligned(32)))*/ rwlock_t;
 
+#ifdef CONFIG_LOCKMETER
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0 }
+#else
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
+#endif
 
 #define rwlock_init(x)	do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 #define rwlock_is_locked(x)	(*(volatile int *)(x) != 0)
@@ -169,4 +182,41 @@ static inline void _raw_read_unlock(rwlo
 	: "m" (*lock) : "memory");
 }
 
+#ifdef CONFIG_LOCKMETER
+static inline int _raw_write_trylock(rwlock_t *lock)
+{
+	long temp,result;
+
+	__asm__ __volatile__(
+	"	ldl_l %1,%0\n"
+	"	mov $31,%2\n"
+	"	bne %1,1f\n"
+	"	or $31,1,%2\n"
+	"	stl_c %2,%0\n"
+	"1:	mb\n"
+	: "=m" (*(volatile int *)lock), "=&r" (temp), "=&r" (result)
+	: "m" (*(volatile int *)lock)
+	);
+
+	return (result);
+}
+
+static inline int _raw_read_trylock(rwlock_t *lock)
+{
+	unsigned long temp,result;
+
+	__asm__ __volatile__(
+	"	ldl_l %1,%0\n"
+	"	mov $31,%2\n"
+	"	blbs %1,1f\n"
+	"	subl %1,2,%2\n"
+	"	stl_c %2,%0\n"
+	"1:	mb\n"
+	: "=m" (*(volatile int *)lock), "=&r" (temp), "=&r" (result)
+	: "m" (*(volatile int *)lock)
+	);
+	return (result);
+}
+#endif /* CONFIG_LOCKMETER */
+
 #endif /* _ALPHA_SPINLOCK_H */
--- diff/include/asm-arm/dma-mapping.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-arm/dma-mapping.h	2004-03-09 11:51:51.000000000 +0000
@@ -26,8 +26,10 @@ dma_addr_t sa1111_map_single(struct devi
 void sa1111_unmap_single(struct device *dev, dma_addr_t, size_t, enum dma_data_direction);
 int sa1111_map_sg(struct device *dev, struct scatterlist *, int, enum dma_data_direction);
 void sa1111_unmap_sg(struct device *dev, struct scatterlist *, int, enum dma_data_direction);
-void sa1111_dma_sync_single(struct device *dev, dma_addr_t, size_t, enum dma_data_direction);
-void sa1111_dma_sync_sg(struct device *dev, struct scatterlist *, int, enum dma_data_direction);
+void sa1111_dma_sync_single_for_cpu(struct device *dev, dma_addr_t, size_t, enum dma_data_direction);
+void sa1111_dma_sync_single_for_device(struct device *dev, dma_addr_t, size_t, enum dma_data_direction);
+void sa1111_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *, int, enum dma_data_direction);
+void sa1111_dma_sync_sg_for_device(struct device *dev, struct scatterlist *, int, enum dma_data_direction);
 
 #ifdef CONFIG_SA1111
 
@@ -115,7 +117,8 @@ dma_free_coherent(struct device *dev, si
  * or written back.
  *
  * The device owns this memory once this call has completed.  The CPU
- * can regain ownership by calling dma_unmap_single() or dma_sync_single().
+ * can regain ownership by calling dma_unmap_single() or
+ * dma_sync_single_for_cpu().
  */
 static inline dma_addr_t
 dma_map_single(struct device *dev, void *cpu_addr, size_t size,
@@ -140,7 +143,8 @@ dma_map_single(struct device *dev, void 
  * or written back.
  *
  * The device owns this memory once this call has completed.  The CPU
- * can regain ownership by calling dma_unmap_page() or dma_sync_single().
+ * can regain ownership by calling dma_unmap_page() or
+ * dma_sync_single_for_cpu().
  */
 static inline dma_addr_t
 dma_map_page(struct device *dev, struct page *page,
@@ -204,7 +208,7 @@ dma_unmap_page(struct device *dev, dma_a
  *
  * Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scatter-gather version of the
- * above pci_map_single interface.  Here the scatter gather list
+ * above dma_map_single interface.  Here the scatter gather list
  * elements are each tagged with the appropriate dma address
  * and length.  They are obtained via sg_dma_{address,length}(SG).
  *
@@ -214,7 +218,7 @@ dma_unmap_page(struct device *dev, dma_a
  *       The routine returns the number of addr/length pairs actually
  *       used, at most nents.
  *
- * Device ownership issues as mentioned above for pci_map_single are
+ * Device ownership issues as mentioned above for dma_map_single are
  * the same here.
  */
 static inline int
@@ -246,7 +250,7 @@ dma_map_sg(struct device *dev, struct sc
  *
  * Unmap a set of streaming mode DMA translations.
  * Again, CPU read rules concerning calls here are the same as for
- * pci_unmap_single() above.
+ * dma_unmap_single() above.
  */
 static inline void
 dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
@@ -261,7 +265,7 @@ dma_unmap_sg(struct device *dev, struct 
 }
 
 /**
- * dma_sync_single
+ * dma_sync_single_for_cpu
  * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
  * @handle: DMA address of buffer
  * @size: size of buffer to map
@@ -270,18 +274,31 @@ dma_unmap_sg(struct device *dev, struct 
  * Make physical memory consistent for a single streaming mode DMA
  * translation after a transfer.
  *
- * If you perform a pci_map_single() but wish to interrogate the
+ * If you perform a dma_map_single() but wish to interrogate the
  * buffer using the cpu, yet do not wish to teardown the PCI dma
  * mapping, you must call this function before doing so.  At the
- * next point you give the PCI dma address back to the card, the
+ * next point you give the PCI dma address back to the card, you
+ * must first the perform a dma_sync_for_device, and then the
  * device again owns the buffer.
  */
 static inline void
-dma_sync_single(struct device *dev, dma_addr_t handle, size_t size,
-		enum dma_data_direction dir)
+dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle, size_t size,
+			enum dma_data_direction dir)
 {
 	if (dmadev_is_sa1111(dev)) {
-		sa1111_dma_sync_single(dev, handle, size, dir);
+		sa1111_dma_sync_single_for_cpu(dev, handle, size, dir);
+		return;
+	}
+
+	consistent_sync((void *)__bus_to_virt(handle), size, dir);
+}
+
+static inline void
+dma_sync_single_for_device(struct device *dev, dma_addr_t handle, size_t size,
+			   enum dma_data_direction dir)
+{
+	if (dmadev_is_sa1111(dev)) {
+		sa1111_dma_sync_single_for_device(dev, handle, size, dir);
 		return;
 	}
 
@@ -289,7 +306,7 @@ dma_sync_single(struct device *dev, dma_
 }
 
 /**
- * dma_sync_sg
+ * dma_sync_sg_for_cpu
  * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
  * @sg: list of buffers
  * @nents: number of buffers to map
@@ -298,17 +315,34 @@ dma_sync_single(struct device *dev, dma_
  * Make physical memory consistent for a set of streaming
  * mode DMA translations after a transfer.
  *
- * The same as pci_dma_sync_single but for a scatter-gather list,
+ * The same as dma_sync_single_for_* but for a scatter-gather list,
  * same rules and usage.
  */
 static inline void
-dma_sync_sg(struct device *dev, struct scatterlist *sg, int nents,
-	    enum dma_data_direction dir)
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents,
+		    enum dma_data_direction dir)
+{
+	int i;
+
+	if (dmadev_is_sa1111(dev)) {
+		sa1111_dma_sync_sg_for_cpu(dev, sg, nents, dir);
+		return;
+	}
+
+	for (i = 0; i < nents; i++, sg++) {
+		char *virt = page_address(sg->page) + sg->offset;
+		consistent_sync(virt, sg->length, dir);
+	}
+}
+
+static inline void
+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
+		       enum dma_data_direction dir)
 {
 	int i;
 
 	if (dmadev_is_sa1111(dev)) {
-		sa1111_dma_sync_sg(dev, sg, nents, dir);
+		sa1111_dma_sync_sg_for_device(dev, sg, nents, dir);
 		return;
 	}
 
--- diff/include/asm-arm/irq.h	2003-05-21 11:50:16.000000000 +0100
+++ source/include/asm-arm/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -44,5 +44,9 @@ void disable_irq_wake(unsigned int irq);
 void enable_irq_wake(unsigned int irq);
 int setup_irq(unsigned int, struct irqaction *);
 
+struct irqaction;
+struct pt_regs;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+
 #endif
 
--- diff/include/asm-arm26/irq.h	2003-06-30 10:07:24.000000000 +0100
+++ source/include/asm-arm26/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -45,6 +45,8 @@ extern void enable_irq(unsigned int);
 int set_irq_type(unsigned int irq, unsigned int type);
 
 int setup_irq(unsigned int, struct irqaction *);
+struct pt_regs;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
 
 #endif
 
--- diff/include/asm-cris/irq.h	2003-07-11 09:39:50.000000000 +0100
+++ source/include/asm-cris/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -14,6 +14,10 @@ extern void enable_irq(unsigned int);
 #define disable_irq_nosync      disable_irq
 #define enable_irq_nosync       enable_irq
 
+struct irqaction;
+struct pt_regs;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+
 #endif  /* _ASM_IRQ_H */
 
 
--- diff/include/asm-generic/dma-mapping.h	2003-01-16 11:30:40.000000000 +0000
+++ source/include/asm-generic/dma-mapping.h	2004-03-09 11:51:51.000000000 +0000
@@ -103,21 +103,41 @@ dma_unmap_sg(struct device *dev, struct 
 }
 
 static inline void
-dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size,
-		enum dma_data_direction direction)
+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
+			enum dma_data_direction direction)
 {
 	BUG_ON(dev->bus != &pci_bus_type);
 
-	pci_dma_sync_single(to_pci_dev(dev), dma_handle, size, (int)direction);
+	pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle,
+				    size, (int)direction);
 }
 
 static inline void
-dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems,
-	    enum dma_data_direction direction)
+dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
+			   enum dma_data_direction direction)
 {
 	BUG_ON(dev->bus != &pci_bus_type);
 
-	pci_dma_sync_sg(to_pci_dev(dev), sg, nelems, (int)direction);
+	pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle,
+				       size, (int)direction);
+}
+
+static inline void
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
+		    enum dma_data_direction direction)
+{
+	BUG_ON(dev->bus != &pci_bus_type);
+
+	pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, nelems, (int)direction);
+}
+
+static inline void
+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
+		       enum dma_data_direction direction)
+{
+	BUG_ON(dev->bus != &pci_bus_type);
+
+	pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, nelems, (int)direction);
 }
 
 /* Now for the API extensions over the pci_ one */
@@ -135,12 +155,21 @@ dma_get_cache_alignment(void)
 }
 
 static inline void
-dma_sync_single_range(struct device *dev, dma_addr_t dma_handle,
-		      unsigned long offset, size_t size,
-		      enum dma_data_direction direction)
+dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+			      unsigned long offset, size_t size,
+			      enum dma_data_direction direction)
+{
+	/* just sync everything, that's all the pci API can do */
+	dma_sync_single_for_cpu(dev, dma_handle, offset+size, direction);
+}
+
+static inline void
+dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
+				 unsigned long offset, size_t size,
+				 enum dma_data_direction direction)
 {
 	/* just sync everything, that's all the pci API can do */
-	dma_sync_single(dev, dma_handle, offset+size, direction);
+	dma_sync_single_for_device(dev, dma_handle, offset+size, direction);
 }
 
 static inline void
--- diff/include/asm-generic/pci-dma-compat.h	2003-01-16 11:30:40.000000000 +0000
+++ source/include/asm-generic/pci-dma-compat.h	2004-03-09 11:51:51.000000000 +0000
@@ -71,17 +71,31 @@ pci_unmap_sg(struct pci_dev *hwdev, stru
 }
 
 static inline void
-pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle,
+pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle,
 		    size_t size, int direction)
 {
-	dma_sync_single(hwdev == NULL ? NULL : &hwdev->dev, dma_handle, size, (enum dma_data_direction)direction);
+	dma_sync_single_for_cpu(hwdev == NULL ? NULL : &hwdev->dev, dma_handle, size, (enum dma_data_direction)direction);
 }
 
 static inline void
-pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle,
+		    size_t size, int direction)
+{
+	dma_sync_single_for_device(hwdev == NULL ? NULL : &hwdev->dev, dma_handle, size, (enum dma_data_direction)direction);
+}
+
+static inline void
+pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg,
+		int nelems, int direction)
+{
+	dma_sync_sg_for_cpu(hwdev == NULL ? NULL : &hwdev->dev, sg, nelems, (enum dma_data_direction)direction);
+}
+
+static inline void
+pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg,
 		int nelems, int direction)
 {
-	dma_sync_sg(hwdev == NULL ? NULL : &hwdev->dev, sg, nelems, (enum dma_data_direction)direction);
+	dma_sync_sg_for_device(hwdev == NULL ? NULL : &hwdev->dev, sg, nelems, (enum dma_data_direction)direction);
 }
 
 #endif
--- diff/include/asm-generic/siginfo.h	2003-08-26 10:00:54.000000000 +0100
+++ source/include/asm-generic/siginfo.h	2004-03-09 11:51:51.000000000 +0000
@@ -118,6 +118,7 @@ typedef struct siginfo {
 #define __SI_FAULT	(3 << 16)
 #define __SI_CHLD	(4 << 16)
 #define __SI_RT		(5 << 16)
+#define __SI_MESGQ	(6 << 16)
 #define __SI_CODE(T,N)	((T) | ((N) & 0xffff))
 #else
 #define __SI_KILL	0
@@ -126,6 +127,7 @@ typedef struct siginfo {
 #define __SI_FAULT	0
 #define __SI_CHLD	0
 #define __SI_RT		0
+#define __SI_MESGQ	0
 #define __SI_CODE(T,N)	(N)
 #endif
 
@@ -137,7 +139,7 @@ typedef struct siginfo {
 #define SI_KERNEL	0x80		/* sent by the kernel from somewhere */
 #define SI_QUEUE	-1		/* sent by sigqueue */
 #define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
-#define SI_MESGQ	-3		/* sent by real time mesq state change */
+#define SI_MESGQ __SI_CODE(__SI_MESGQ,-3) /* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
 #define SI_TKILL	-6		/* sent by tkill system call */
--- diff/include/asm-generic/tlb.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-generic/tlb.h	2004-03-09 11:51:51.000000000 +0000
@@ -39,7 +39,6 @@ struct mmu_gather {
 	unsigned int		nr;	/* set to ~0U means fast mode */
 	unsigned int		need_flush;/* Really unmapped some ptes? */
 	unsigned int		fullmm; /* non-zero means full mm flush */
-	unsigned long		freed;
 	struct page *		pages[FREE_PTE_NR];
 };
 
@@ -60,7 +59,6 @@ tlb_gather_mmu(struct mm_struct *mm, uns
 	tlb->nr = num_online_cpus() > 1 ? 0U : ~0U;
 
 	tlb->fullmm = full_mm_flush;
-	tlb->freed = 0;
 
 	return tlb;
 }
@@ -85,13 +83,6 @@ tlb_flush_mmu(struct mmu_gather *tlb, un
 static inline void
 tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
 {
-	int freed = tlb->freed;
-	struct mm_struct *mm = tlb->mm;
-	int rss = mm->rss;
-
-	if (rss < freed)
-		freed = rss;
-	mm->rss = rss - freed;
 	tlb_flush_mmu(tlb, start, end);
 
 	/* keep the page table cache within bounds */
@@ -146,4 +137,6 @@ static inline void tlb_remove_page(struc
 		__pmd_free_tlb(tlb, pmdp);			\
 	} while (0)
 
+#define tlb_migrate_prepare(mm) do { } while(0)
+
 #endif /* _ASM_GENERIC__TLB_H */
--- diff/include/asm-h8300/irq.h	2003-09-17 12:28:12.000000000 +0100
+++ source/include/asm-h8300/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -48,4 +48,8 @@ extern void disable_irq(unsigned int);
 #define enable_irq_nosync(x)	enable_irq(x)
 #define disable_irq_nosync(x)	disable_irq(x)
 
+struct irqaction;
+struct pt_regs;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+
 #endif /* _H8300_IRQ_H_ */
--- diff/include/asm-h8300/unistd.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-h8300/unistd.h	2004-03-09 11:51:51.000000000 +0000
@@ -490,7 +490,6 @@ asmlinkage int sys_execve(char *name, ch
 			int dummy, ...);
 asmlinkage int sys_pipe(unsigned long *fildes);
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data);
-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
 struct sigaction;
 asmlinkage long sys_rt_sigaction(int sig,
 				const struct sigaction __user *act,
--- diff/include/asm-i386/acpi.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-i386/acpi.h	2004-03-09 11:51:51.000000000 +0000
@@ -61,33 +61,36 @@
  *  Immediate values in the assembly are preceded by "$" as in "$0x1"
  *  The final asm parameter are the operation altered non-output registers.
  */
+
+static inline int
+__acpi_acquire_global_lock (unsigned int *lock)
+{
+	unsigned int old, new, val;
+	do {
+		old = *lock;
+		new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1));
+		val = cmpxchg(lock, old, new);
+	} while (unlikely (val != old));
+	return (new < 3) ? -1 : 0;
+}
+
+static inline int
+__acpi_release_global_lock (unsigned int *lock)
+{
+	unsigned int old, new, val;
+	do {
+		old = *lock;
+		new = old & ~0x3;
+		val = cmpxchg(lock, old, new);
+	} while (unlikely (val != old));
+	return old & 0x1;
+}
+
 #define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
-    do { \
-        int dummy; \
-        asm("1:     movl (%1),%%eax;" \
-            "movl   %%eax,%%edx;" \
-            "andl   %2,%%edx;" \
-            "btsl   $0x1,%%edx;" \
-            "adcl   $0x0,%%edx;" \
-            "lock;  cmpxchgl %%edx,(%1);" \
-            "jnz    1b;" \
-            "cmpb   $0x3,%%dl;" \
-            "sbbl   %%eax,%%eax" \
-            :"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~1L):"dx"); \
-    } while(0)
+	((Acq) = __acpi_acquire_global_lock((unsigned int *) GLptr))
 
 #define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \
-    do { \
-        int dummy; \
-        asm("1:     movl (%1),%%eax;" \
-            "movl   %%eax,%%edx;" \
-            "andl   %2,%%edx;" \
-            "lock;  cmpxchgl %%edx,(%1);" \
-            "jnz    1b;" \
-            "andl   $0x1,%%eax" \
-            :"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~3L):"dx"); \
-    } while(0)
-
+	((Acq) = __acpi_release_global_lock((unsigned int *) GLptr))
 
 /*
  * Math helper asm macros
@@ -110,6 +113,7 @@
 extern int acpi_lapic;
 extern int acpi_ioapic;
 extern int acpi_noirq;
+extern int acpi_strict;
 
 /* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */
 #define FIX_ACPI_PAGES 4
--- diff/include/asm-i386/bugs.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/bugs.h	2004-03-09 11:51:51.000000000 +0000
@@ -1,11 +1,11 @@
 /*
  *  include/asm-i386/bugs.h
  *
- *  Copyright (C) 1994  Linus Torvalds
+ *  Copyright (C) 1994	Linus Torvalds
  *
  *  Cyrix stuff, June 1998 by:
  *	- Rafael R. Reilova (moved everything from head.S),
- *        <rreilova@ececs.uc.edu>
+ *	  <rreilova@ececs.uc.edu>
  *	- Channing Corn (tests & fixes),
  *	- Andrew D. Balsa (code cleanup).
  *
@@ -25,7 +25,20 @@
 #include <asm/processor.h>
 #include <asm/i387.h>
 #include <asm/msr.h>
-
+#ifdef CONFIG_KGDB
+/*
+ * Provied the command line "gdb" initial break
+ */
+int __init kgdb_initial_break(char * str)
+{
+	if (*str == '\0'){
+		breakpoint();
+		return 1;
+	}
+	return 0;
+}
+__setup("gdb",kgdb_initial_break);
+#endif
 static int __init no_halt(char *s)
 {
 	boot_cpu_data.hlt_works_ok = 0;
@@ -140,7 +153,7 @@ static void __init check_popad(void)
 	  : "ecx", "edi" );
 	/* If this fails, it means that any user program may lock the CPU hard. Too bad. */
 	if (res != 12345678) printk( "Buggy.\n" );
-		        else printk( "OK.\n" );
+			else printk( "OK.\n" );
 #endif
 }
 
--- diff/include/asm-i386/checksum.h	2003-11-25 15:24:59.000000000 +0000
+++ source/include/asm-i386/checksum.h	2004-03-09 11:51:51.000000000 +0000
@@ -25,7 +25,7 @@ asmlinkage unsigned int csum_partial(con
  * better 64-bit) boundary
  */
 
-asmlinkage unsigned int csum_partial_copy_generic( const char *src, char *dst, int len, int sum,
+asmlinkage unsigned int direct_csum_partial_copy_generic( const char *src, char *dst, int len, int sum,
 						   int *src_err_ptr, int *dst_err_ptr);
 
 /*
@@ -39,14 +39,19 @@ static __inline__
 unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
 					int len, int sum)
 {
-	return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
+	/*
+	 * The direct function is OK for kernel-space => kernel-space copies:
+	 */
+	return direct_csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
 }
 
 static __inline__
 unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
 						int len, int sum, int *err_ptr)
 {
-	return csum_partial_copy_generic ( src, dst, len, sum, err_ptr, NULL);
+	if (copy_from_user(dst, src, len))
+		*err_ptr = -EFAULT;
+	return csum_partial(dst, len, sum);
 }
 
 /*
@@ -172,11 +177,26 @@ static __inline__ unsigned short int csu
  *	Copy and checksum to user
  */
 #define HAVE_CSUM_COPY_USER
-static __inline__ unsigned int csum_and_copy_to_user(const char *src, char *dst,
+static __inline__ unsigned int direct_csum_and_copy_to_user(const char *src, char *dst,
 				    int len, int sum, int *err_ptr)
 {
 	if (access_ok(VERIFY_WRITE, dst, len))
-		return csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr);
+		return direct_csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr);
+
+	if (len)
+		*err_ptr = -EFAULT;
+
+	return -1; /* invalid checksum */
+}
+
+static __inline__ unsigned int csum_and_copy_to_user(const char *src, char *dst,
+				    int len, int sum, int *err_ptr)
+{
+	if (access_ok(VERIFY_WRITE, dst, len)) {
+		if (copy_to_user(dst, src, len))
+			*err_ptr = -EFAULT;
+		return csum_partial(src, len, sum);
+	}
 
 	if (len)
 		*err_ptr = -EFAULT;
--- diff/include/asm-i386/cpufeature.h	2003-09-30 15:46:19.000000000 +0100
+++ source/include/asm-i386/cpufeature.h	2004-03-09 11:51:51.000000000 +0000
@@ -76,6 +76,9 @@
 
 /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
 #define X86_FEATURE_XSTORE	(5*32+ 2) /* on-CPU RNG present (xstore insn) */
+#define X86_FEATURE_XSTORE_EN	(5*32+ 3) /* on-CPU RNG enabled */
+#define X86_FEATURE_XCRYPT	(5*32+ 6) /* on-CPU crypto (xcrypt insn) */
+#define X86_FEATURE_XCRYPT_EN	(5*32+ 7) /* on-CPU crypto enabled */
 
 
 #define cpu_has(c, bit)		test_bit(bit, (c)->x86_capability)
@@ -101,6 +104,7 @@
 #define cpu_has_cyrix_arr	boot_cpu_has(X86_FEATURE_CYRIX_ARR)
 #define cpu_has_centaur_mcr	boot_cpu_has(X86_FEATURE_CENTAUR_MCR)
 #define cpu_has_xstore		boot_cpu_has(X86_FEATURE_XSTORE)
+#define cpu_has_xcrypt		boot_cpu_has(X86_FEATURE_XCRYPT)
 
 #endif /* __ASM_I386_CPUFEATURE_H */
 
--- diff/include/asm-i386/desc.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/desc.h	2004-03-09 11:51:51.000000000 +0000
@@ -21,6 +21,13 @@ struct Xgt_desc_struct {
 
 extern struct Xgt_desc_struct idt_descr, cpu_gdt_descr[NR_CPUS];
 
+extern void trap_init_virtual_IDT(void);
+extern void trap_init_virtual_GDT(void);
+
+asmlinkage int system_call(void);
+asmlinkage void lcall7(void);
+asmlinkage void lcall27(void);
+
 #define load_TR_desc() __asm__ __volatile__("ltr %%ax"::"a" (GDT_ENTRY_TSS*8))
 #define load_LDT_desc() __asm__ __volatile__("lldt %%ax"::"a" (GDT_ENTRY_LDT*8))
 
@@ -30,6 +37,7 @@ extern struct Xgt_desc_struct idt_descr,
  */
 extern struct desc_struct default_ldt[];
 extern void set_intr_gate(unsigned int irq, void * addr);
+extern void set_trap_gate(unsigned int n, void *addr);
 
 #define _set_tssldt_desc(n,addr,limit,type) \
 __asm__ __volatile__ ("movw %w3,0(%2)\n\t" \
@@ -90,31 +98,8 @@ static inline void load_TLS(struct threa
 #undef C
 }
 
-static inline void clear_LDT(void)
-{
-	int cpu = get_cpu();
-
-	set_ldt_desc(cpu, &default_ldt[0], 5);
-	load_LDT_desc();
-	put_cpu();
-}
-
-/*
- * load one particular LDT into the current CPU
- */
-static inline void load_LDT_nolock(mm_context_t *pc, int cpu)
-{
-	void *segments = pc->ldt;
-	int count = pc->size;
-
-	if (likely(!count)) {
-		segments = &default_ldt[0];
-		count = 5;
-	}
-		
-	set_ldt_desc(cpu, segments, count);
-	load_LDT_desc();
-}
+extern struct page *default_ldt_page;
+extern void load_LDT_nolock(mm_context_t *pc, int cpu);
 
 static inline void load_LDT(mm_context_t *pc)
 {
@@ -123,6 +108,6 @@ static inline void load_LDT(mm_context_t
 	put_cpu();
 }
 
-#endif /* !__ASSEMBLY__ */
 
+#endif /* !__ASSEMBLY__ */
 #endif
--- diff/include/asm-i386/dma-mapping.h	2003-01-16 11:30:40.000000000 +0000
+++ source/include/asm-i386/dma-mapping.h	2004-03-09 11:51:51.000000000 +0000
@@ -70,24 +70,42 @@ dma_unmap_sg(struct device *dev, struct 
 }
 
 static inline void
-dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size,
-		enum dma_data_direction direction)
+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
+			enum dma_data_direction direction)
+{
+}
+
+static inline void
+dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
+			enum dma_data_direction direction)
 {
 	flush_write_buffers();
 }
 
 static inline void
-dma_sync_single_range(struct device *dev, dma_addr_t dma_handle,
-		      unsigned long offset, size_t size,
-		      enum dma_data_direction direction)
+dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+			      unsigned long offset, size_t size,
+			      enum dma_data_direction direction)
+{
+}
+
+static inline void
+dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
+				 unsigned long offset, size_t size,
+				 enum dma_data_direction direction)
 {
 	flush_write_buffers();
 }
 
+static inline void
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
+		    enum dma_data_direction direction)
+{
+}
 
 static inline void
-dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems,
-		 enum dma_data_direction direction)
+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
+		    enum dma_data_direction direction)
 {
 	flush_write_buffers();
 }
--- diff/include/asm-i386/fixmap.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/fixmap.h	2004-03-09 11:51:51.000000000 +0000
@@ -18,17 +18,15 @@
 #include <asm/acpi.h>
 #include <asm/apicdef.h>
 #include <asm/page.h>
-#ifdef CONFIG_HIGHMEM
 #include <linux/threads.h>
 #include <asm/kmap_types.h>
-#endif
 
 /*
  * Here we define all the compile-time 'special' virtual
  * addresses. The point is to have a constant address at
  * compile time, but to set the physical address only
- * in the boot process. We allocate these special addresses
- * from the end of virtual memory (0xfffff000) backwards.
+ * in the boot process. We allocate these special  addresses
+ * from the end of virtual memory (0xffffe000) backwards.
  * Also this lets us do fail-safe vmalloc(), we
  * can guarantee that these special addresses and
  * vmalloc()-ed addresses never overlap.
@@ -41,11 +39,20 @@
  * TLB entries of such buffers will not be flushed across
  * task switches.
  */
+
+/*
+ * on UP currently we will have no trace of the fixmap mechanizm,
+ * no page table allocations, etc. This might change in the
+ * future, say framebuffers for the console driver(s) could be
+ * fix-mapped?
+ */
 enum fixed_addresses {
 	FIX_HOLE,
 	FIX_VSYSCALL,
 #ifdef CONFIG_X86_LOCAL_APIC
 	FIX_APIC_BASE,	/* local (CPU) APIC) -- required for SMP or not */
+#else
+	FIX_VSTACK_HOLE_1,
 #endif
 #ifdef CONFIG_X86_IO_APIC
 	FIX_IO_APIC_BASE_0,
@@ -57,20 +64,28 @@ enum fixed_addresses {
 	FIX_LI_PCIA,	/* Lithium PCI Bridge A */
 	FIX_LI_PCIB,	/* Lithium PCI Bridge B */
 #endif
-#ifdef CONFIG_X86_F00F_BUG
-	FIX_F00F_IDT,	/* Virtual mapping for IDT */
-#endif
+	FIX_IDT,
+	FIX_GDT_1,
+	FIX_GDT_0,
+	FIX_TSS_3,
+	FIX_TSS_2,
+	FIX_TSS_1,
+	FIX_TSS_0,
+	FIX_ENTRY_TRAMPOLINE_1,
+	FIX_ENTRY_TRAMPOLINE_0,
 #ifdef CONFIG_X86_CYCLONE_TIMER
 	FIX_CYCLONE_TIMER, /*cyclone timer register*/
+	FIX_VSTACK_HOLE_2,
 #endif 
-#ifdef CONFIG_HIGHMEM
 	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings */
 	FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
-#endif
 #ifdef CONFIG_ACPI_BOOT
 	FIX_ACPI_BEGIN,
 	FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
 #endif
+#ifdef CONFIG_PCI_MMCONFIG
+	FIX_PCIE_MCFG,
+#endif
 	__end_of_permanent_fixed_addresses,
 	/* temporary boot-time mappings, used before ioremap() is functional */
 #define NR_FIX_BTMAPS	16
@@ -95,12 +110,15 @@ extern void __set_fixmap (enum fixed_add
 		__set_fixmap(idx, 0, __pgprot(0))
 
 /*
- * used by vmalloc.c.
+ * used by vmalloc.c and various other places.
  *
  * Leave one empty page between vmalloc'ed areas and
  * the start of the fixmap.
+ *
+ * IMPORTANT: dont change FIXADDR_TOP without adjusting KM_VSTACK0
+ * and KM_VSTACK1 so that the virtual stack is 8K aligned.
  */
-#define FIXADDR_TOP	(0xfffff000UL)
+#define FIXADDR_TOP	(0xffffe000UL)
 #define __FIXADDR_SIZE	(__end_of_permanent_fixed_addresses << PAGE_SHIFT)
 #define FIXADDR_START	(FIXADDR_TOP - __FIXADDR_SIZE)
 
--- diff/include/asm-i386/highmem.h	2003-10-09 09:47:34.000000000 +0100
+++ source/include/asm-i386/highmem.h	2004-03-09 11:51:51.000000000 +0000
@@ -25,26 +25,19 @@
 #include <linux/threads.h>
 #include <asm/kmap_types.h>
 #include <asm/tlbflush.h>
+#include <asm/atomic_kmap.h>
 
 /* declarations for highmem.c */
 extern unsigned long highstart_pfn, highend_pfn;
 
-extern pte_t *kmap_pte;
-extern pgprot_t kmap_prot;
 extern pte_t *pkmap_page_table;
-
-extern void kmap_init(void);
+extern void kmap_init(void) __init;
 
 /*
  * Right now we initialize only a single pte table. It can be extended
  * easily, subsequent pte tables have to be allocated in one physical
  * chunk of RAM.
  */
-#if NR_CPUS <= 32
-#define PKMAP_BASE (0xff800000UL)
-#else
-#define PKMAP_BASE (0xff600000UL)
-#endif
 #ifdef CONFIG_X86_PAE
 #define LAST_PKMAP 512
 #else
--- diff/include/asm-i386/io.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-i386/io.h	2004-03-09 11:51:51.000000000 +0000
@@ -45,17 +45,6 @@
 
 #include <linux/vmalloc.h>
 
-/*
- * Temporary debugging check to catch old code using
- * unmapped ISA addresses. Will be removed in 2.4.
- */
-#ifdef CONFIG_DEBUG_IOVIRT
-  extern void *__io_virt_debug(unsigned long x, const char *file, int line);
-  #define __io_virt(x) __io_virt_debug((unsigned long)(x), __FILE__, __LINE__)
-#else
-  #define __io_virt(x) ((void *)(x))
-#endif
-
 /**
  *	virt_to_phys	-	map virtual addresses to physical
  *	@address: address to remap
@@ -150,9 +139,9 @@ extern void bt_iounmap(void *addr, unsig
  * memory location directly.
  */
 
-#define readb(addr) (*(volatile unsigned char *) __io_virt(addr))
-#define readw(addr) (*(volatile unsigned short *) __io_virt(addr))
-#define readl(addr) (*(volatile unsigned int *) __io_virt(addr))
+#define readb(addr) (*(volatile unsigned char *) (addr))
+#define readw(addr) (*(volatile unsigned short *) (addr))
+#define readl(addr) (*(volatile unsigned int *) (addr))
 #define readb_relaxed(addr) readb(addr)
 #define readw_relaxed(addr) readw(addr)
 #define readl_relaxed(addr) readl(addr)
@@ -160,16 +149,16 @@ extern void bt_iounmap(void *addr, unsig
 #define __raw_readw readw
 #define __raw_readl readl
 
-#define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b))
-#define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b))
-#define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b))
+#define writeb(b,addr) (*(volatile unsigned char *) (addr) = (b))
+#define writew(b,addr) (*(volatile unsigned short *) (addr) = (b))
+#define writel(b,addr) (*(volatile unsigned int *) (addr) = (b))
 #define __raw_writeb writeb
 #define __raw_writew writew
 #define __raw_writel writel
 
-#define memset_io(a,b,c)	memset(__io_virt(a),(b),(c))
-#define memcpy_fromio(a,b,c)	__memcpy((a),__io_virt(b),(c))
-#define memcpy_toio(a,b,c)	__memcpy(__io_virt(a),(b),(c))
+#define memset_io(a,b,c)	memset((void *)(a),(b),(c))
+#define memcpy_fromio(a,b,c)	__memcpy((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c)	__memcpy((void *)(a),(b),(c))
 
 /*
  * ISA space is 'always mapped' on a typical x86 system, no need to
@@ -196,8 +185,8 @@ extern void bt_iounmap(void *addr, unsig
  * Again, i386 does not require mem IO specific function.
  */
 
-#define eth_io_copy_and_sum(a,b,c,d)		eth_copy_and_sum((a),__io_virt(b),(c),(d))
-#define isa_eth_io_copy_and_sum(a,b,c,d)	eth_copy_and_sum((a),__io_virt(__ISA_IO_base + (b)),(c),(d))
+#define eth_io_copy_and_sum(a,b,c,d)		eth_copy_and_sum((a),(void *)(b),(c),(d))
+#define isa_eth_io_copy_and_sum(a,b,c,d)	eth_copy_and_sum((a),(void *)(__ISA_IO_base + (b)),(c),(d))
 
 /**
  *	check_signature		-	find BIOS signatures
--- diff/include/asm-i386/irq.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/asm-i386/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -14,6 +14,7 @@
 #include <linux/sched.h>
 /* include comes from machine specific directory */
 #include "irq_vectors.h"
+#include <asm/thread_info.h>
 
 static __inline__ int irq_canonicalize(int irq)
 {
@@ -30,4 +31,28 @@ extern int can_request_irq(unsigned int,
 #define ARCH_HAS_NMI_WATCHDOG		/* See include/linux/nmi.h */
 #endif
 
+#ifdef CONFIG_4KSTACKS
+/*
+ * per-CPU IRQ handling contexts (thread information and stack)
+ */
+union irq_ctx {
+	struct thread_info      tinfo;
+	u32                     stack[THREAD_SIZE/sizeof(u32)];
+};
+
+extern union irq_ctx *hardirq_ctx[NR_CPUS];
+extern union irq_ctx *softirq_ctx[NR_CPUS];
+
+extern void irq_ctx_init(int cpu);
+
+#define __ARCH_HAS_DO_SOFTIRQ
+#else
+#define irq_ctx_init(cpu) do { ; } while (0)
+#endif
+
+struct irqaction;
+struct pt_regs;
+asmlinkage int handle_IRQ_event(unsigned int, struct pt_regs *,
+				struct irqaction *);
+
 #endif /* _ASM_IRQ_H */
--- diff/include/asm-i386/kmap_types.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/kmap_types.h	2004-03-09 11:51:51.000000000 +0000
@@ -3,30 +3,36 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_DEBUG_HIGHMEM
-# define D(n) __KM_FENCE_##n ,
-#else
-# define D(n)
-#endif
-
 enum km_type {
-D(0)	KM_BOUNCE_READ,
-D(1)	KM_SKB_SUNRPC_DATA,
-D(2)	KM_SKB_DATA_SOFTIRQ,
-D(3)	KM_USER0,
-D(4)	KM_USER1,
-D(5)	KM_BIO_SRC_IRQ,
-D(6)	KM_BIO_DST_IRQ,
-D(7)	KM_PTE0,
-D(8)	KM_PTE1,
-D(9)	KM_PTE2,
-D(10)	KM_IRQ0,
-D(11)	KM_IRQ1,
-D(12)	KM_SOFTIRQ0,
-D(13)	KM_SOFTIRQ1,
-D(14)	KM_TYPE_NR
-};
-
-#undef D
+	/*
+	 * IMPORTANT: don't move these 3 entries, and only add entries in
+	 * pairs: the 4G/4G virtual stack must be 8K aligned on each cpu.
+	 */
+	KM_BOUNCE_READ,
+	KM_VSTACK1,
+	KM_VSTACK0,
 
+	KM_LDT_PAGE15,
+	KM_LDT_PAGE0 = KM_LDT_PAGE15 + 16-1,
+	KM_USER_COPY,
+	KM_VSTACK_HOLE,
+	KM_SKB_SUNRPC_DATA,
+	KM_SKB_DATA_SOFTIRQ,
+	KM_USER0,
+	KM_USER1,
+	KM_BIO_SRC_IRQ,
+	KM_BIO_DST_IRQ,
+	KM_PTE0,
+	KM_PTE1,
+	KM_PTE2,
+	KM_IRQ0,
+	KM_IRQ1,
+	KM_SOFTIRQ0,
+	KM_SOFTIRQ1,
+	/*
+	 * Add new entries in pairs:
+	 * the 4G/4G virtual stack must be 8K aligned on each cpu.
+	 */
+	KM_TYPE_NR
+};
 #endif
--- diff/include/asm-i386/linkage.h	2002-10-16 04:28:22.000000000 +0100
+++ source/include/asm-i386/linkage.h	2004-03-09 11:51:51.000000000 +0000
@@ -3,6 +3,7 @@
 
 #define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
 #define FASTCALL(x)	x __attribute__((regparm(3)))
+#define fastcall	__attribute__((regparm(3)))
 
 #ifdef CONFIG_X86_ALIGNMENT_16
 #define __ALIGN .align 16,0x90
--- diff/include/asm-i386/mman.h	2003-10-09 09:47:34.000000000 +0100
+++ source/include/asm-i386/mman.h	2004-03-09 11:51:51.000000000 +0000
@@ -22,6 +22,7 @@
 #define MAP_NORESERVE	0x4000		/* don't check for reservations */
 #define MAP_POPULATE	0x8000		/* populate (prefault) pagetables */
 #define MAP_NONBLOCK	0x10000		/* do not block on IO */
+#define MAP_INHERIT	0x20000		/* inherit the protection bits of the underlying vma*/
 
 #define MS_ASYNC	1		/* sync memory asynchronously */
 #define MS_INVALIDATE	2		/* invalidate the caches */
--- diff/include/asm-i386/mmu.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/mmu.h	2004-03-09 11:51:51.000000000 +0000
@@ -8,10 +8,13 @@
  *
  * cpu_vm_mask is used to optimize ldt flushing.
  */
+
+#define MAX_LDT_PAGES 16
+
 typedef struct { 
 	int size;
 	struct semaphore sem;
-	void *ldt;
+	struct page *ldt_pages[MAX_LDT_PAGES];
 } mm_context_t;
 
 #endif
--- diff/include/asm-i386/mmu_context.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/mmu_context.h	2004-03-09 11:51:51.000000000 +0000
@@ -29,6 +29,10 @@ static inline void switch_mm(struct mm_s
 {
 	int cpu = smp_processor_id();
 
+#ifdef CONFIG_X86_SWITCH_PAGETABLES
+	if (tsk->mm)
+		tsk->thread_info->user_pgd = (void *)__pa(tsk->mm->pgd);
+#endif
 	if (likely(prev != next)) {
 		/* stop flush ipis for the previous mm */
 		cpu_clear(cpu, prev->cpu_vm_mask);
@@ -39,12 +43,14 @@ static inline void switch_mm(struct mm_s
 		cpu_set(cpu, next->cpu_vm_mask);
 
 		/* Re-load page tables */
+#if !defined(CONFIG_X86_SWITCH_PAGETABLES)
 		load_cr3(next->pgd);
+#endif
 
 		/*
 		 * load the LDT, if the LDT is different:
 		 */
-		if (unlikely(prev->context.ldt != next->context.ldt))
+		if (unlikely(prev->context.size + next->context.size))
 			load_LDT_nolock(&next->context, cpu);
 	}
 #ifdef CONFIG_SMP
@@ -56,7 +62,9 @@ static inline void switch_mm(struct mm_s
 			/* We were in lazy tlb mode and leave_mm disabled 
 			 * tlb flush IPI delivery. We must reload %cr3.
 			 */
+#if !defined(CONFIG_X86_SWITCH_PAGETABLES)
 			load_cr3(next->pgd);
+#endif
 			load_LDT_nolock(&next->context, cpu);
 		}
 	}
@@ -67,6 +75,6 @@ static inline void switch_mm(struct mm_s
 	asm("movl %0,%%fs ; movl %0,%%gs": :"r" (0))
 
 #define activate_mm(prev, next) \
-	switch_mm((prev),(next),NULL)
+	switch_mm((prev),(next),current)
 
 #endif
--- diff/include/asm-i386/module.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-i386/module.h	2004-03-09 11:51:51.000000000 +0000
@@ -36,7 +36,7 @@ struct mod_arch_specific
 #define MODULE_PROC_FAMILY "K7 "
 #elif defined CONFIG_MK8
 #define MODULE_PROC_FAMILY "K8 "
-#elif defined CONFIG_MELAN
+#elif defined CONFIG_X86_ELAN
 #define MODULE_PROC_FAMILY "ELAN "
 #elif defined CONFIG_MCRUSOE
 #define MODULE_PROC_FAMILY "CRUSOE "
@@ -60,6 +60,12 @@ struct mod_arch_specific
 #define MODULE_REGPARM ""
 #endif
 
-#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY MODULE_REGPARM
+#ifdef CONFIG_4KSTACKS
+#define MODULE_STACKSIZE "4KSTACKS "
+#else
+#define MODULE_STACKSIZE ""
+#endif
+
+#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY MODULE_REGPARM MODULE_STACKSIZE
 
 #endif /* _ASM_I386_MODULE_H */
--- diff/include/asm-i386/page.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/page.h	2004-03-09 11:51:51.000000000 +0000
@@ -1,6 +1,8 @@
 #ifndef _I386_PAGE_H
 #define _I386_PAGE_H
 
+#include <linux/config.h>
+
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT	12
 #define PAGE_SIZE	(1UL << PAGE_SHIFT)
@@ -9,11 +11,10 @@
 #define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1))
 #define LARGE_PAGE_SIZE (1UL << PMD_SHIFT)
 
-#ifdef __KERNEL__
-#ifndef __ASSEMBLY__
-
 #include <linux/config.h>
 
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
 #ifdef CONFIG_X86_USE_3DNOW
 
 #include <asm/mmx.h>
@@ -88,8 +89,19 @@ typedef struct { unsigned long pgprot; }
  *
  * If you want more physical memory than this then see the CONFIG_HIGHMEM4G
  * and CONFIG_HIGHMEM64G options in the kernel configuration.
+ *
+ * Note: on PAE the kernel must never go below 32 MB, we use the
+ * first 8 entries of the 2-level boot pgd for PAE magic.
  */
 
+#ifdef CONFIG_X86_4G_VM_LAYOUT
+#define __PAGE_OFFSET		(0x02000000)
+#define TASK_SIZE		(0xff000000)
+#else
+#define __PAGE_OFFSET		(0xc0000000)
+#define TASK_SIZE		(0xc0000000)
+#endif
+
 /*
  * This much address space is reserved for vmalloc() and iomap()
  * as well as fixmap mappings.
@@ -114,16 +126,10 @@ static __inline__ int get_order(unsigned
 
 #endif /* __ASSEMBLY__ */
 
-#ifdef __ASSEMBLY__
-#define __PAGE_OFFSET		(0xC0000000)
-#else
-#define __PAGE_OFFSET		(0xC0000000UL)
-#endif
-
-
 #define PAGE_OFFSET		((unsigned long)__PAGE_OFFSET)
 #define VMALLOC_RESERVE		((unsigned long)__VMALLOC_RESERVE)
-#define MAXMEM			(-__PAGE_OFFSET-__VMALLOC_RESERVE)
+#define __MAXMEM		(-__PAGE_OFFSET-__VMALLOC_RESERVE)
+#define MAXMEM			((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE))
 #define __pa(x)			((unsigned long)(x)-PAGE_OFFSET)
 #define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
 #define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
--- diff/include/asm-i386/pci.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-i386/pci.h	2004-03-09 11:51:51.000000000 +0000
@@ -60,27 +60,32 @@ struct pci_dev;
 /* This is always fine. */
 #define pci_dac_dma_supported(pci_dev, mask)	(1)
 
-static __inline__ dma64_addr_t
+static inline dma64_addr_t
 pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction)
 {
 	return ((dma64_addr_t) page_to_phys(page) +
 		(dma64_addr_t) offset);
 }
 
-static __inline__ struct page *
+static inline struct page *
 pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
 {
 	return pfn_to_page(dma_addr >> PAGE_SHIFT);
 }
 
-static __inline__ unsigned long
+static inline unsigned long
 pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
 {
 	return (dma_addr & ~PAGE_MASK);
 }
 
-static __inline__ void
-pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
+static inline void
+pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
+{
+}
+
+static inline void
+pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
 {
 	flush_write_buffers();
 }
--- diff/include/asm-i386/pgtable-2level.h	2003-05-21 11:49:56.000000000 +0100
+++ source/include/asm-i386/pgtable-2level.h	2004-03-09 11:51:51.000000000 +0000
@@ -64,15 +64,20 @@ static inline pmd_t * pmd_offset(pgd_t *
 #define pfn_pmd(pfn, prot)	__pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
 
 /*
- * Bits 0, 6 and 7 are taken, split up the 29 bits of offset
+ * Bits 0, 1, 6 and 7 are taken, split up the 28 bits of offset
  * into this range:
  */
-#define PTE_FILE_MAX_BITS	29
+#define PTE_FILE_MAX_BITS	28
 
 #define pte_to_pgoff(pte) \
-	((((pte).pte_low >> 1) & 0x1f ) + (((pte).pte_low >> 8) << 5 ))
+	((((pte).pte_low >> 2) & 0xf ) + (((pte).pte_low >> 8) << 4 ))
+#define pte_to_pgprot(pte) \
+	__pgprot(((pte).pte_low & (_PAGE_RW | _PAGE_PROTNONE)) \
+		| (((pte).pte_low & _PAGE_PROTNONE) ? 0 : \
+			(_PAGE_USER | _PAGE_PRESENT)) | _PAGE_ACCESSED)
 
-#define pgoff_to_pte(off) \
-	((pte_t) { (((off) & 0x1f) << 1) + (((off) >> 5) << 8) + _PAGE_FILE })
+#define pgoff_prot_to_pte(off, prot) \
+	((pte_t) { (((off) & 0xf) << 2) + (((off) >> 4) << 8) + \
+	 (pgprot_val(prot) & (_PAGE_RW | _PAGE_PROTNONE)) + _PAGE_FILE })
 
 #endif /* _I386_PGTABLE_2LEVEL_H */
--- diff/include/asm-i386/pgtable-3level.h	2003-08-20 14:16:33.000000000 +0100
+++ source/include/asm-i386/pgtable-3level.h	2004-03-09 11:51:51.000000000 +0000
@@ -120,7 +120,16 @@ static inline pmd_t pfn_pmd(unsigned lon
  * put the 32 bits of offset into the high part.
  */
 #define pte_to_pgoff(pte) ((pte).pte_high)
-#define pgoff_to_pte(off) ((pte_t) { _PAGE_FILE, (off) })
+
+#define pte_to_pgprot(pte) \
+	__pgprot(((pte).pte_low & (_PAGE_RW | _PAGE_PROTNONE)) \
+		| (((pte).pte_low & _PAGE_PROTNONE) ? 0 : \
+			(_PAGE_USER | _PAGE_PRESENT)) | _PAGE_ACCESSED)
+
+#define pgoff_prot_to_pte(off, prot) \
+	((pte_t) { _PAGE_FILE + \
+		(pgprot_val(prot) & (_PAGE_RW | _PAGE_PROTNONE)) , (off) })
+
 #define PTE_FILE_MAX_BITS       32
 
 #endif /* _I386_PGTABLE_3LEVEL_H */
--- diff/include/asm-i386/pgtable.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-i386/pgtable.h	2004-03-09 11:51:51.000000000 +0000
@@ -32,16 +32,17 @@
 #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
 extern unsigned long empty_zero_page[1024];
 extern pgd_t swapper_pg_dir[1024];
-extern kmem_cache_t *pgd_cache;
-extern kmem_cache_t *pmd_cache;
+extern kmem_cache_t *pgd_cache, *pmd_cache, *kpmd_cache;
 extern spinlock_t pgd_lock;
 extern struct list_head pgd_list;
 
 void pmd_ctor(void *, kmem_cache_t *, unsigned long);
+void kpmd_ctor(void *, kmem_cache_t *, unsigned long);
 void pgd_ctor(void *, kmem_cache_t *, unsigned long);
 void pgd_dtor(void *, kmem_cache_t *, unsigned long);
 void pgtable_cache_init(void);
 void paging_init(void);
+void setup_identity_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end);
 
 #endif /* !__ASSEMBLY__ */
 
@@ -51,6 +52,11 @@ void paging_init(void);
  * newer 3-level PAE-mode page tables.
  */
 #ifndef __ASSEMBLY__
+
+extern void set_system_gate(unsigned int n, void *addr);
+extern void init_entry_mappings(void);
+extern void entry_trampoline_setup(void);
+
 #ifdef CONFIG_X86_PAE
 # include <asm/pgtable-3level.h>
 #else
@@ -63,7 +69,12 @@ void paging_init(void);
 #define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
 #define PGDIR_MASK	(~(PGDIR_SIZE-1))
 
-#define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
+#if defined(CONFIG_X86_PAE) && defined(CONFIG_X86_4G_VM_LAYOUT)
+# define USER_PTRS_PER_PGD	4
+#else
+# define USER_PTRS_PER_PGD	((TASK_SIZE/PGDIR_SIZE) + ((TASK_SIZE % PGDIR_SIZE) + PGDIR_SIZE-1)/PGDIR_SIZE)
+#endif
+
 #define FIRST_USER_PGD_NR	0
 
 #define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
@@ -173,8 +184,8 @@ extern unsigned long __PAGE_KERNEL;
  */
 #undef TEST_VERIFY_AREA
 
-/* page table for 0-4MB for everybody */
-extern unsigned long pg0[1024];
+/* The boot page tables (all created as a single array) */
+extern unsigned long pg0[];
 
 #define pte_present(x)	((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE))
 #define pte_clear(xp)	do { set_pte(xp, __pte(0)); } while (0)
@@ -233,6 +244,7 @@ static inline void ptep_mkdirty(pte_t *p
 
 #define mk_pte(page, pgprot)	pfn_pte(page_to_pfn(page), (pgprot))
 #define mk_pte_huge(entry) ((entry).pte_low |= _PAGE_PRESENT | _PAGE_PSE)
+#define mk_pte_phys(physpage, pgprot) pfn_pte((physpage) >> PAGE_SHIFT, pgprot)
 
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
--- diff/include/asm-i386/processor.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-i386/processor.h	2004-03-09 11:51:51.000000000 +0000
@@ -291,11 +291,6 @@ extern unsigned int machine_submodel_id;
 extern unsigned int BIOS_revision;
 extern unsigned int mca_pentium_flag;
 
-/*
- * User space process size: 3GB (default).
- */
-#define TASK_SIZE	(PAGE_OFFSET)
-
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
@@ -406,6 +401,7 @@ struct tss_struct {
 struct thread_struct {
 /* cached TLS descriptors. */
 	struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES];
+	void *stack_page0, *stack_page1;
 	unsigned long	esp0;
 	unsigned long	sysenter_cs;
 	unsigned long	eip;
@@ -449,7 +445,8 @@ struct thread_struct {
 	.io_bitmap	= { [ 0 ... IO_BITMAP_LONGS] = ~0 },		\
 }
 
-static inline void load_esp0(struct tss_struct *tss, struct thread_struct *thread)
+static inline void
+load_esp0(struct tss_struct *tss, struct thread_struct *thread)
 {
 	tss->esp0 = thread->esp0;
 	/* This can only happen when SEP is enabled, no need to test "SEP"arately */
@@ -485,6 +482,23 @@ extern void prepare_to_copy(struct task_
  */
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
+#ifdef CONFIG_X86_HIGH_ENTRY
+#define virtual_esp0(tsk) \
+	((unsigned long)(tsk)->thread_info->virtual_stack + ((tsk)->thread.esp0 - (unsigned long)(tsk)->thread_info->real_stack))
+#else
+# define virtual_esp0(tsk) ((tsk)->thread.esp0)
+#endif
+
+#define load_virtual_esp0(tss, task)					\
+	do {								\
+		tss->esp0 = virtual_esp0(task);				\
+		if (likely(cpu_has_sep) && unlikely(tss->ss1 != task->thread.sysenter_cs)) {	\
+			tss->ss1 = task->thread.sysenter_cs;		\
+			wrmsr(MSR_IA32_SYSENTER_CS,			\
+				task->thread.sysenter_cs, 0);		\
+		}							\
+	} while (0)
+
 extern unsigned long thread_saved_pc(struct task_struct *tsk);
 void show_trace(struct task_struct *task, unsigned long *stack);
 
@@ -646,4 +660,9 @@ extern inline void prefetchw(const void 
 
 extern void select_idle_routine(const struct cpuinfo_x86 *c);
 
+#ifdef CONFIG_SCHED_SMT
+#define ARCH_HAS_SCHED_DOMAIN
+#define ARCH_HAS_SCHED_WAKE_BALANCE
+#endif
+
 #endif /* __ASM_I386_PROCESSOR_H */
--- diff/include/asm-i386/rwlock.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/rwlock.h	2004-03-09 11:51:51.000000000 +0000
@@ -20,28 +20,52 @@
 #define RW_LOCK_BIAS		 0x01000000
 #define RW_LOCK_BIAS_STR	"0x01000000"
 
-#define __build_read_lock_ptr(rw, helper)   \
-	asm volatile(LOCK "subl $1,(%0)\n\t" \
-		     "js 2f\n" \
-		     "1:\n" \
-		     LOCK_SECTION_START("") \
-		     "2:\tcall " helper "\n\t" \
-		     "jmp 1b\n" \
-		     LOCK_SECTION_END \
-		     ::"a" (rw) : "memory")
-
-#define __build_read_lock_const(rw, helper)   \
-	asm volatile(LOCK "subl $1,%0\n\t" \
-		     "js 2f\n" \
-		     "1:\n" \
-		     LOCK_SECTION_START("") \
-		     "2:\tpushl %%eax\n\t" \
-		     "leal %0,%%eax\n\t" \
-		     "call " helper "\n\t" \
-		     "popl %%eax\n\t" \
-		     "jmp 1b\n" \
-		     LOCK_SECTION_END \
-		     :"=m" (*(volatile int *)rw) : : "memory")
+#ifdef CONFIG_SPINLINE
+
+	#define __build_read_lock_ptr(rw, helper)   \
+		asm volatile(LOCK "subl $1,(%0)\n\t" \
+			     "jns 1f\n\t" \
+			     "call " helper "\n\t" \
+			     "1:\t" \
+			     ::"a" (rw) : "memory")
+
+	#define __build_read_lock_const(rw, helper)   \
+		asm volatile(LOCK "subl $1,%0\n\t" \
+			     "jns 1f\n\t" \
+			     "pushl %%eax\n\t" \
+			     "leal %0,%%eax\n\t" \
+			     "call " helper "\n\t" \
+			     "popl %%eax\n\t" \
+			     "1:\t" \
+			     :"=m" (*(volatile int *)rw) : : "memory")
+
+#else /* !CONFIG_SPINLINE */
+
+	#define __build_read_lock_ptr(rw, helper)   \
+		asm volatile(LOCK "subl $1,(%0)\n\t" \
+			     "js 2f\n" \
+			     "1:\n" \
+			     LOCK_SECTION_START("") \
+			     "2:\tcall " helper "\n\t" \
+			     "jmp 1b\n" \
+			     LOCK_SECTION_END \
+			     ::"a" (rw) : "memory")
+
+	#define __build_read_lock_const(rw, helper)   \
+		asm volatile(LOCK "subl $1,%0\n\t" \
+			     "js 2f\n" \
+			     "1:\n" \
+			     LOCK_SECTION_START("") \
+			     "2:\tpushl %%eax\n\t" \
+			     "leal %0,%%eax\n\t" \
+			     "call " helper "\n\t" \
+			     "popl %%eax\n\t" \
+			     "jmp 1b\n" \
+			     LOCK_SECTION_END \
+			     :"=m" (*(volatile int *)rw) : : "memory")
+
+#endif /* CONFIG_SPINLINE */
+
 
 #define __build_read_lock(rw, helper)	do { \
 						if (__builtin_constant_p(rw)) \
@@ -50,28 +74,51 @@
 							__build_read_lock_ptr(rw, helper); \
 					} while (0)
 
-#define __build_write_lock_ptr(rw, helper) \
-	asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
-		     "jnz 2f\n" \
-		     "1:\n" \
-		     LOCK_SECTION_START("") \
-		     "2:\tcall " helper "\n\t" \
-		     "jmp 1b\n" \
-		     LOCK_SECTION_END \
-		     ::"a" (rw) : "memory")
-
-#define __build_write_lock_const(rw, helper) \
-	asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
-		     "jnz 2f\n" \
-		     "1:\n" \
-		     LOCK_SECTION_START("") \
-		     "2:\tpushl %%eax\n\t" \
-		     "leal %0,%%eax\n\t" \
-		     "call " helper "\n\t" \
-		     "popl %%eax\n\t" \
-		     "jmp 1b\n" \
-		     LOCK_SECTION_END \
-		     :"=m" (*(volatile int *)rw) : : "memory")
+#ifdef CONFIG_SPINLINE
+
+	#define __build_write_lock_ptr(rw, helper) \
+		asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
+			     "jz 1f\n\t" \
+			     "call " helper "\n\t" \
+			     "1:\n" \
+			     ::"a" (rw) : "memory")
+
+	#define __build_write_lock_const(rw, helper) \
+		asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
+			     "jz 1f\n\t" \
+			     "pushl %%eax\n\t" \
+			     "leal %0,%%eax\n\t" \
+			     "call " helper "\n\t" \
+			     "popl %%eax\n\t" \
+			     "1:\n" \
+			     :"=m" (*(volatile int *)rw) : : "memory")
+
+#else /* !CONFIG_SPINLINE */
+
+	#define __build_write_lock_ptr(rw, helper) \
+		asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
+			     "jnz 2f\n" \
+			     "1:\n" \
+			     LOCK_SECTION_START("") \
+			     "2:\tcall " helper "\n\t" \
+			     "jmp 1b\n" \
+			     LOCK_SECTION_END \
+			     ::"a" (rw) : "memory")
+
+	#define __build_write_lock_const(rw, helper) \
+		asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
+			     "jnz 2f\n" \
+			     "1:\n" \
+			     LOCK_SECTION_START("") \
+			     "2:\tpushl %%eax\n\t" \
+			     "leal %0,%%eax\n\t" \
+			     "call " helper "\n\t" \
+			     "popl %%eax\n\t" \
+			     "jmp 1b\n" \
+			     LOCK_SECTION_END \
+			     :"=m" (*(volatile int *)rw) : : "memory")
+
+#endif /* CONFIG_SPINLINE */
 
 #define __build_write_lock(rw, helper)	do { \
 						if (__builtin_constant_p(rw)) \
--- diff/include/asm-i386/smp.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-i386/smp.h	2004-03-09 11:51:51.000000000 +0000
@@ -34,11 +34,10 @@
 extern void smp_alloc_memory(void);
 extern int pic_mode;
 extern int smp_num_siblings;
-extern int cpu_sibling_map[];
+extern cpumask_t 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);
 extern void smp_invalidate_rcv(void);		/* Process an NMI */
 extern void (*mtrr_hook) (void);
 extern void zap_low_mappings (void);
--- diff/include/asm-i386/spinlock.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-i386/spinlock.h	2004-03-09 11:51:51.000000000 +0000
@@ -43,18 +43,35 @@ typedef struct {
 #define spin_is_locked(x)	(*(volatile signed char *)(&(x)->lock) <= 0)
 #define spin_unlock_wait(x)	do { barrier(); } while(spin_is_locked(x))
 
-#define spin_lock_string \
-	"\n1:\t" \
-	"lock ; decb %0\n\t" \
-	"js 2f\n" \
-	LOCK_SECTION_START("") \
-	"2:\t" \
-	"rep;nop\n\t" \
-	"cmpb $0,%0\n\t" \
-	"jle 2b\n\t" \
-	"jmp 1b\n" \
-	LOCK_SECTION_END
+#ifdef CONFIG_SPINLINE
 
+	#define spin_lock_string \
+		"\n1:\t" \
+		"lock ; decb %0\n\t" \
+		"js 2f\n" \
+		"jmp 3f\n" \
+		"2:\t" \
+		"rep;nop\n\t" \
+		"cmpb $0,%0\n\t" \
+		"jle 2b\n\t" \
+		"jmp 1b\n" \
+		"3:\t"
+
+#else /* !CONFIG_SPINLINE */
+
+	#define spin_lock_string \
+		"\n1:\t" \
+		"lock ; decb %0\n\t" \
+		"js 2f\n" \
+		LOCK_SECTION_START("") \
+		"2:\t" \
+		"rep;nop\n\t" \
+		"cmpb $0,%0\n\t" \
+		"jle 2b\n\t" \
+		"jmp 1b\n" \
+		LOCK_SECTION_END
+
+#endif /* CONFIG_SPINLINE */
 /*
  * This works. Despite all the confusion.
  * (except on PPro SMP or if we are using OOSTORE)
@@ -138,6 +155,11 @@ here:
  */
 typedef struct {
 	volatile unsigned int lock;
+#ifdef CONFIG_LOCKMETER
+	/* required for LOCKMETER since all bits in lock are used */
+	/* and we need this storage for CPU and lock INDEX        */
+	unsigned lockmeter_magic;
+#endif
 #ifdef CONFIG_DEBUG_SPINLOCK
 	unsigned magic;
 #endif
@@ -145,11 +167,19 @@ typedef struct {
 
 #define RWLOCK_MAGIC	0xdeaf1eed
 
+#ifdef CONFIG_LOCKMETER
+#ifdef CONFIG_DEBUG_SPINLOCK
+#define RWLOCK_MAGIC_INIT	, 0, RWLOCK_MAGIC
+#else
+#define RWLOCK_MAGIC_INIT	, 0
+#endif
+#else /* !CONFIG_LOCKMETER */
 #ifdef CONFIG_DEBUG_SPINLOCK
 #define RWLOCK_MAGIC_INIT	, RWLOCK_MAGIC
 #else
 #define RWLOCK_MAGIC_INIT	/* */
 #endif
+#endif /* !CONFIG_LOCKMETER */
 
 #define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS RWLOCK_MAGIC_INIT }
 
@@ -196,4 +226,60 @@ static inline int _raw_write_trylock(rwl
 	return 0;
 }
 
+#ifdef CONFIG_LOCKMETER
+static inline int _raw_read_trylock(rwlock_t *lock)
+{
+/* FIXME -- replace with assembler */
+	atomic_t *count = (atomic_t *)lock;
+	atomic_dec(count);
+	if (count->counter > 0)
+		return 1;
+	atomic_inc(count);
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_LOCKMETER) && defined(CONFIG_HAVE_DEC_LOCK)
+extern void _metered_spin_lock  (spinlock_t *lock);
+extern void _metered_spin_unlock(spinlock_t *lock);
+
+/*
+ *  Matches what is in arch/i386/lib/dec_and_lock.c, except this one is
+ *  "static inline" so that the spin_lock(), if actually invoked, is charged
+ *  against the real caller, not against the catch-all atomic_dec_and_lock
+ */
+static inline int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+{
+	int counter;
+	int newcount;
+
+repeat:
+	counter = atomic_read(atomic);
+	newcount = counter-1;
+
+	if (!newcount)
+		goto slow_path;
+
+	asm volatile("lock; cmpxchgl %1,%2"
+		:"=a" (newcount)
+		:"r" (newcount), "m" (atomic->counter), "0" (counter));
+
+	/* If the above failed, "eax" will have changed */
+	if (newcount != counter)
+		goto repeat;
+	return 0;
+
+slow_path:
+	preempt_disable();
+	_metered_spin_lock(lock);
+	if (atomic_dec_and_test(atomic))
+		return 1;
+	_metered_spin_unlock(lock);
+	preempt_enable();
+	return 0;
+}
+
+#define ATOMIC_DEC_AND_LOCK
+#endif
+
 #endif /* __ASM_SPINLOCK_H */
--- diff/include/asm-i386/string.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-i386/string.h	2004-03-09 11:51:51.000000000 +0000
@@ -58,6 +58,29 @@ __asm__ __volatile__(
 return dest;
 }
 
+/*
+ * This is a more generic variant of strncpy_count() suitable for
+ * implementing string-access routines with all sorts of return
+ * code semantics. It's used by mm/usercopy.c.
+ */
+static inline size_t strncpy_count(char * dest,const char *src,size_t count)
+{
+	__asm__ __volatile__(
+
+	"1:\tdecl %0\n\t"
+	"js 2f\n\t"
+	"lodsb\n\t"
+	"stosb\n\t"
+	"testb %%al,%%al\n\t"
+	"jne 1b\n\t"
+	"2:"
+	"incl %0"
+	: "=c" (count)
+	:"S" (src),"D" (dest),"0" (count) : "memory");
+
+	return count;
+}
+
 static inline char * strcat(char * dest,const char * src)
 {
 int d0, d1, d2, d3;
--- diff/include/asm-i386/thread_info.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-i386/thread_info.h	2004-03-09 11:51:51.000000000 +0000
@@ -9,6 +9,9 @@
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
+#include <asm/page.h>
+
 #ifndef __ASSEMBLY__
 #include <asm/processor.h>
 #endif
@@ -29,31 +32,30 @@ struct thread_info {
 	__u32			cpu;		/* current CPU */
 	__s32			preempt_count; /* 0 => preemptable, <0 => BUG */
 
+	unsigned long           previous_esp;   /* ESP of the previous stack in case
+						   of nested (IRQ) stacks
+						*/
+
 	mm_segment_t		addr_limit;	/* thread address space:
 					 	   0-0xBFFFFFFF for user-thead
 						   0-0xFFFFFFFF for kernel-thread
 						*/
-	struct restart_block    restart_block;
+	void *real_stack, *virtual_stack, *user_pgd;
 
+	struct restart_block    restart_block;
 	__u8			supervisor_stack[0];
 };
 
-#else /* !__ASSEMBLY__ */
-
-/* offsets into the thread_info struct for assembly code access */
-#define TI_TASK		0x00000000
-#define TI_EXEC_DOMAIN	0x00000004
-#define TI_FLAGS	0x00000008
-#define TI_STATUS	0x0000000C
-#define TI_CPU		0x00000010
-#define TI_PRE_COUNT	0x00000014
-#define TI_ADDR_LIMIT	0x00000018
-#define TI_RESTART_BLOCK 0x000001C
-
 #endif
 
 #define PREEMPT_ACTIVE		0x4000000
+#ifdef CONFIG_4KSTACKS
+#define THREAD_SIZE            (4096)
+#else
+#define THREAD_SIZE		(8192)
+#endif
 
+#define STACK_WARN             (THREAD_SIZE/8)
 /*
  * macros/functions for gaining access to the thread information structure
  *
@@ -61,7 +63,7 @@ struct thread_info {
  */
 #ifndef __ASSEMBLY__
 
-#define INIT_THREAD_INFO(tsk)			\
+#define INIT_THREAD_INFO(tsk, thread_info)	\
 {						\
 	.task		= &tsk,			\
 	.exec_domain	= &default_exec_domain,	\
@@ -72,12 +74,12 @@ struct thread_info {
 	.restart_block = {			\
 		.fn = do_no_restart_syscall,	\
 	},					\
+	.real_stack	= &thread_info,		\
 }
 
 #define init_thread_info	(init_thread_union.thread_info)
 #define init_stack		(init_thread_union.stack)
 
-#define THREAD_SIZE (2*PAGE_SIZE)
 
 /* how to get the thread information struct from C */
 static inline struct thread_info *current_thread_info(void)
@@ -87,6 +89,14 @@ static inline struct thread_info *curren
 	return ti;
 }
 
+/* how to get the current stack pointer from C */
+static inline unsigned long current_stack_pointer(void)
+{
+	unsigned long ti;
+	__asm__("movl %%esp,%0; ":"=r" (ti) : );
+	return ti;
+}
+
 /* thread information allocation */
 #ifdef CONFIG_DEBUG_STACK_USAGE
 #define alloc_thread_info(tsk)					\
@@ -108,8 +118,6 @@ static inline struct thread_info *curren
 
 #else /* !__ASSEMBLY__ */
 
-#define THREAD_SIZE	8192
-
 /* how to get the thread information struct from ASM */
 #define GET_THREAD_INFO(reg) \
 	movl $-THREAD_SIZE, reg; \
@@ -133,6 +141,7 @@ static inline struct thread_info *curren
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_SINGLESTEP		4	/* restore singlestep on return to user mode */
 #define TIF_IRET		5	/* return with iret */
+#define TIF_DB7			6	/* has debug registers */
 #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
@@ -141,6 +150,7 @@ static inline struct thread_info *curren
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
 #define _TIF_IRET		(1<<TIF_IRET)
+#define _TIF_DB7		(1<<TIF_DB7)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 
 #define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
--- diff/include/asm-i386/tlbflush.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/tlbflush.h	2004-03-09 11:51:51.000000000 +0000
@@ -85,22 +85,28 @@ extern unsigned long pgkern_mask;
 
 static inline void flush_tlb_mm(struct mm_struct *mm)
 {
+#ifndef CONFIG_X86_SWITCH_PAGETABLES
 	if (mm == current->active_mm)
 		__flush_tlb();
+#endif
 }
 
 static inline void flush_tlb_page(struct vm_area_struct *vma,
 	unsigned long addr)
 {
+#ifndef CONFIG_X86_SWITCH_PAGETABLES
 	if (vma->vm_mm == current->active_mm)
 		__flush_tlb_one(addr);
+#endif
 }
 
 static inline void flush_tlb_range(struct vm_area_struct *vma,
 	unsigned long start, unsigned long end)
 {
+#ifndef CONFIG_X86_SWITCH_PAGETABLES
 	if (vma->vm_mm == current->active_mm)
 		__flush_tlb();
+#endif
 }
 
 #else
@@ -111,11 +117,10 @@ static inline void flush_tlb_range(struc
 	__flush_tlb()
 
 extern void flush_tlb_all(void);
-extern void flush_tlb_current_task(void);
 extern void flush_tlb_mm(struct mm_struct *);
 extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
 
-#define flush_tlb()	flush_tlb_current_task()
+#define flush_tlb()	flush_tlb_all()
 
 static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long start, unsigned long end)
 {
--- diff/include/asm-i386/topology.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-i386/topology.h	2004-03-09 11:51:51.000000000 +0000
@@ -66,6 +66,9 @@ static inline cpumask_t pcibus_to_cpumas
 	return node_to_cpumask(mp_bus_id_to_node[bus]);
 }
 
+/* Node-to-Node distance */
+#define node_distance(from, to) (from != to)
+
 /* Cross-node load balancing interval. */
 #define NODE_BALANCE_RATE 100
 
--- diff/include/asm-i386/uaccess.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/uaccess.h	2004-03-09 11:51:51.000000000 +0000
@@ -26,7 +26,7 @@
 
 
 #define KERNEL_DS	MAKE_MM_SEG(0xFFFFFFFFUL)
-#define USER_DS		MAKE_MM_SEG(PAGE_OFFSET)
+#define USER_DS		MAKE_MM_SEG(TASK_SIZE)
 
 #define get_ds()	(KERNEL_DS)
 #define get_fs()	(current_thread_info()->addr_limit)
@@ -149,6 +149,45 @@ extern void __get_user_4(void);
 		:"=a" (ret),"=d" (x) \
 		:"0" (ptr))
 
+extern int get_user_size(unsigned int size, void *val, const void *ptr);
+extern int put_user_size(unsigned int size, const void *val, void *ptr);
+extern int zero_user_size(unsigned int size, void *ptr);
+extern int copy_str_fromuser_size(unsigned int size, void *val, const void *ptr);
+extern int strlen_fromuser_size(unsigned int size, const void *ptr);
+
+
+# define indirect_get_user(x,ptr)					\
+({	int __ret_gu,__val_gu;						\
+	__typeof__(ptr) __ptr_gu = (ptr);				\
+	__ret_gu = get_user_size(sizeof(*__ptr_gu), &__val_gu,__ptr_gu) ? -EFAULT : 0;\
+	(x) = (__typeof__(*__ptr_gu))__val_gu;				\
+	__ret_gu;							\
+})
+#define indirect_put_user(x,ptr)					\
+({									\
+	__typeof__(*(ptr)) *__ptr_pu = (ptr), __x_pu = (x);		\
+	put_user_size(sizeof(*__ptr_pu), &__x_pu, __ptr_pu) ? -EFAULT : 0; \
+})
+#define __indirect_put_user indirect_put_user
+#define __indirect_get_user indirect_get_user
+
+#define indirect_copy_from_user(to,from,n) get_user_size(n,to,from)
+#define indirect_copy_to_user(to,from,n) put_user_size(n,from,to)
+
+#define __indirect_copy_from_user indirect_copy_from_user
+#define __indirect_copy_to_user indirect_copy_to_user
+
+#define indirect_strncpy_from_user(dst, src, count) \
+		copy_str_fromuser_size(count, dst, src)
+
+extern int strlen_fromuser_size(unsigned int size, const void *ptr);
+#define indirect_strnlen_user(str, n) strlen_fromuser_size(n, str)
+#define indirect_strlen_user(str) indirect_strnlen_user(str, ~0UL >> 1)
+
+extern int zero_user_size(unsigned int size, void *ptr);
+
+#define indirect_clear_user(mem, len) zero_user_size(len, mem)
+#define __indirect_clear_user clear_user
 
 /* Careful: we have to cast the result to the type of the pointer for sign reasons */
 /**
@@ -168,7 +207,7 @@ extern void __get_user_4(void);
  * Returns zero on success, or -EFAULT on error.
  * On error, the variable @x is set to zero.
  */
-#define get_user(x,ptr)							\
+#define direct_get_user(x,ptr)						\
 ({	int __ret_gu,__val_gu;						\
 	switch(sizeof (*(ptr))) {					\
 	case 1:  __get_user_x(1,__ret_gu,__val_gu,ptr); break;		\
@@ -198,7 +237,7 @@ extern void __put_user_bad(void);
  *
  * Returns zero on success, or -EFAULT on error.
  */
-#define put_user(x,ptr)							\
+#define direct_put_user(x,ptr)						\
   __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
 
 
@@ -222,7 +261,7 @@ extern void __put_user_bad(void);
  * Returns zero on success, or -EFAULT on error.
  * On error, the variable @x is set to zero.
  */
-#define __get_user(x,ptr) \
+#define __direct_get_user(x,ptr) \
   __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
 
 
@@ -245,7 +284,7 @@ extern void __put_user_bad(void);
  *
  * Returns zero on success, or -EFAULT on error.
  */
-#define __put_user(x,ptr) \
+#define __direct_put_user(x,ptr) \
   __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
 
 #define __put_user_nocheck(x,ptr,size)				\
@@ -396,7 +435,7 @@ unsigned long __copy_from_user_ll(void *
  * On success, this will be zero.
  */
 static inline unsigned long
-__copy_to_user(void __user *to, const void *from, unsigned long n)
+__direct_copy_to_user(void __user *to, const void *from, unsigned long n)
 {
 	if (__builtin_constant_p(n)) {
 		unsigned long ret;
@@ -434,7 +473,7 @@ __copy_to_user(void __user *to, const vo
  * data to the requested size using zero bytes.
  */
 static inline unsigned long
-__copy_from_user(void *to, const void __user *from, unsigned long n)
+__direct_copy_from_user(void *to, const void __user *from, unsigned long n)
 {
 	if (__builtin_constant_p(n)) {
 		unsigned long ret;
@@ -468,11 +507,11 @@ __copy_from_user(void *to, const void __
  * On success, this will be zero.
  */
 static inline unsigned long
-copy_to_user(void __user *to, const void *from, unsigned long n)
+direct_copy_to_user(void __user *to, const void *from, unsigned long n)
 {
 	might_sleep();
 	if (access_ok(VERIFY_WRITE, to, n))
-		n = __copy_to_user(to, from, n);
+		n = __direct_copy_to_user(to, from, n);
 	return n;
 }
 
@@ -493,11 +532,11 @@ copy_to_user(void __user *to, const void
  * data to the requested size using zero bytes.
  */
 static inline unsigned long
-copy_from_user(void *to, const void __user *from, unsigned long n)
+direct_copy_from_user(void *to, const void __user *from, unsigned long n)
 {
 	might_sleep();
 	if (access_ok(VERIFY_READ, from, n))
-		n = __copy_from_user(to, from, n);
+		n = __direct_copy_from_user(to, from, n);
 	else
 		memset(to, 0, n);
 	return n;
@@ -520,10 +559,68 @@ long __strncpy_from_user(char *dst, cons
  * If there is a limit on the length of a valid string, you may wish to
  * consider using strnlen_user() instead.
  */
-#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
 
-long strnlen_user(const char __user *str, long n);
-unsigned long clear_user(void __user *mem, unsigned long len);
-unsigned long __clear_user(void __user *mem, unsigned long len);
+long direct_strncpy_from_user(char *dst, const char *src, long count);
+long __direct_strncpy_from_user(char *dst, const char *src, long count);
+#define direct_strlen_user(str) direct_strnlen_user(str, ~0UL >> 1)
+long direct_strnlen_user(const char *str, long n);
+unsigned long direct_clear_user(void *mem, unsigned long len);
+unsigned long __direct_clear_user(void *mem, unsigned long len);
+
+extern int indirect_uaccess;
+
+#ifdef CONFIG_X86_UACCESS_INDIRECT
+
+/*
+ * Return code and zeroing semantics:
+
+ __clear_user          0                      <-> bytes not done
+ clear_user            0                      <-> bytes not done
+ __copy_to_user        0                      <-> bytes not done
+ copy_to_user          0                      <-> bytes not done
+ __copy_from_user      0                      <-> bytes not done, zero rest
+ copy_from_user        0                      <-> bytes not done, zero rest
+ __get_user            0                      <-> -EFAULT
+ get_user              0                      <-> -EFAULT
+ __put_user            0                      <-> -EFAULT
+ put_user              0                      <-> -EFAULT
+ strlen_user           strlen + 1             <-> 0
+ strnlen_user          strlen + 1 (or n+1)    <-> 0
+ strncpy_from_user     strlen (or n)          <-> -EFAULT
+
+ */
+
+#define __clear_user(mem,len) __indirect_clear_user(mem,len)
+#define clear_user(mem,len) indirect_clear_user(mem,len)
+#define __copy_to_user(to,from,n) __indirect_copy_to_user(to,from,n)
+#define copy_to_user(to,from,n) indirect_copy_to_user(to,from,n)
+#define __copy_from_user(to,from,n) __indirect_copy_from_user(to,from,n)
+#define copy_from_user(to,from,n) indirect_copy_from_user(to,from,n)
+#define __get_user(val,ptr) __indirect_get_user(val,ptr)
+#define get_user(val,ptr) indirect_get_user(val,ptr)
+#define __put_user(val,ptr) __indirect_put_user(val,ptr)
+#define put_user(val,ptr) indirect_put_user(val,ptr)
+#define strlen_user(str) indirect_strlen_user(str)
+#define strnlen_user(src,count) indirect_strnlen_user(src,count)
+#define strncpy_from_user(dst,src,count) \
+			indirect_strncpy_from_user(dst,src,count)
+
+#else
+
+#define __clear_user __direct_clear_user
+#define clear_user direct_clear_user
+#define __copy_to_user __direct_copy_to_user
+#define copy_to_user direct_copy_to_user
+#define __copy_from_user __direct_copy_from_user
+#define copy_from_user direct_copy_from_user
+#define __get_user __direct_get_user
+#define get_user direct_get_user
+#define __put_user __direct_put_user
+#define put_user direct_put_user
+#define strlen_user direct_strlen_user
+#define strnlen_user direct_strnlen_user
+#define strncpy_from_user direct_strncpy_from_user
+
+#endif /* CONFIG_X86_UACCESS_INDIRECT */
 
 #endif /* __i386_UACCESS_H */
--- diff/include/asm-i386/unistd.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-i386/unistd.h	2004-03-09 11:51:51.000000000 +0000
@@ -262,7 +262,7 @@
 #define __NR_epoll_create	254
 #define __NR_epoll_ctl		255
 #define __NR_epoll_wait		256
-#define __NR_remap_file_pages	257
+#define __NR_old_remap_file_pages	257
 #define __NR_set_tid_address	258
 #define __NR_timer_create	259
 #define __NR_timer_settime	(__NR_timer_create+1)
@@ -279,8 +279,15 @@
 #define __NR_utimes		271
 #define __NR_fadvise64_64	272
 #define __NR_vserver		273
+#define __NR_mq_open 		274
+#define __NR_mq_unlink		(__NR_mq_open+1)
+#define __NR_mq_timedsend	(__NR_mq_open+2)
+#define __NR_mq_timedreceive	(__NR_mq_open+3)
+#define __NR_mq_notify		(__NR_mq_open+4)
+#define __NR_mq_getsetattr	(__NR_mq_open+5)
+#define __NR_remap_file_pages	280
 
-#define NR_syscalls 274
+#define NR_syscalls 281
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
@@ -375,6 +382,7 @@ __syscall_return(type,__res); \
 
 #include <linux/compiler.h>
 #include <linux/types.h>
+#include <linux/linkage.h>
 #include <asm/ptrace.h>
 
 /*
--- diff/include/asm-ia64/acpi.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ia64/acpi.h	2004-03-09 11:51:51.000000000 +0000
@@ -88,6 +88,8 @@ ia64_acpi_release_global_lock (unsigned 
 #define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq)				\
 	((Acq) = ia64_acpi_release_global_lock((unsigned int *) GLptr))
 
+#define acpi_strict 1	/* no ACPI spec workarounds on IA64 */
+
 const char *acpi_get_sysname (void);
 int acpi_request_vector (u32 int_type);
 int acpi_register_irq (u32 gsi, u32 polarity, u32 trigger);
--- diff/include/asm-ia64/compat.h	2003-08-20 14:16:33.000000000 +0100
+++ source/include/asm-ia64/compat.h	2004-03-09 11:51:51.000000000 +0000
@@ -26,6 +26,8 @@ typedef u16		compat_ipc_pid_t;
 typedef s32		compat_daddr_t;
 typedef u32		compat_caddr_t;
 typedef __kernel_fsid_t	compat_fsid_t;
+typedef s32		compat_key_t;
+typedef u32		compat_timer_t;
 
 typedef s32		compat_int_t;
 typedef s32		compat_long_t;
@@ -116,6 +118,64 @@ typedef u32		compat_sigset_word;
 #define COMPAT_OFF_T_MAX	0x7fffffff
 #define COMPAT_LOFF_T_MAX	0x7fffffffffffffffL
 
+struct compat_ipc64_perm {
+	compat_key_t key;
+	compat_uid32_t uid;
+	compat_gid32_t gid;
+	compat_uid32_t cuid;
+	compat_gid32_t cgid;
+	unsigned short mode;
+	unsigned short __pad1;
+	unsigned short seq;
+	unsigned short __pad2;
+	compat_ulong_t unused1;
+	compat_ulong_t unused2;
+};
+
+struct compat_semid64_ds {
+	struct compat_ipc64_perm sem_perm;
+	compat_time_t  sem_otime;
+	compat_ulong_t __unused1;
+	compat_time_t  sem_ctime;
+	compat_ulong_t __unused2;
+	compat_ulong_t sem_nsems;
+	compat_ulong_t __unused3;
+	compat_ulong_t __unused4;
+};
+
+struct compat_msqid64_ds {
+	struct compat_ipc64_perm msg_perm;
+	compat_time_t  msg_stime;
+	compat_ulong_t __unused1;
+	compat_time_t  msg_rtime;
+	compat_ulong_t __unused2;
+	compat_time_t  msg_ctime;
+	compat_ulong_t __unused3;
+	compat_ulong_t msg_cbytes;
+	compat_ulong_t msg_qnum;
+	compat_ulong_t msg_qbytes;
+	compat_pid_t   msg_lspid;
+	compat_pid_t   msg_lrpid;
+	compat_ulong_t __unused4;
+	compat_ulong_t __unused5;
+};
+
+struct compat_shmid64_ds {
+	struct compat_ipc64_perm shm_perm;
+	compat_size_t  shm_segsz;
+	compat_time_t  shm_atime;
+	compat_ulong_t __unused1;
+	compat_time_t  shm_dtime;
+	compat_ulong_t __unused2;
+	compat_time_t  shm_ctime;
+	compat_ulong_t __unused3;
+	compat_pid_t   shm_cpid;
+	compat_pid_t   shm_lpid;
+	compat_ulong_t shm_nattch;
+	compat_ulong_t __unused4;
+	compat_ulong_t __unused5;
+};
+
 /*
  * A pointer passed in from user mode. This should not be used for syscall parameters,
  * just declare them as pointers because the syscall entry code will have appropriately
--- diff/include/asm-ia64/dma-mapping.h	2003-06-09 14:18:20.000000000 +0100
+++ source/include/asm-ia64/dma-mapping.h	2004-03-09 11:51:51.000000000 +0000
@@ -14,8 +14,10 @@
 #define dma_map_sg		platform_dma_map_sg
 #define dma_unmap_single	platform_dma_unmap_single
 #define dma_unmap_sg		platform_dma_unmap_sg
-#define dma_sync_single		platform_dma_sync_single
-#define dma_sync_sg		platform_dma_sync_sg
+#define dma_sync_single_for_cpu	platform_dma_sync_single_for_cpu
+#define dma_sync_sg_for_cpu	platform_dma_sync_sg_for_cpu
+#define dma_sync_single_for_device platform_dma_sync_single_for_device
+#define dma_sync_sg_for_device	platform_dma_sync_sg_for_device
 
 #define dma_map_page(dev, pg, off, size, dir)				\
 	dma_map_single(dev, page_address(pg) + (off), (size), (dir))
@@ -27,8 +29,10 @@
  * See Documentation/DMA-API.txt for details.
  */
 
-#define dma_sync_single_range(dev, dma_handle, offset, size, dir)	\
-	dma_sync_single(dev, dma_handle, size, dir)
+#define dma_sync_single_range_for_cpu(dev, dma_handle, offset, size, dir)	\
+	dma_sync_single_for_cpu(dev, dma_handle, size, dir)
+#define dma_sync_single_range_for_device(dev, dma_handle, offset, size, dir)	\
+	dma_sync_single_for_device(dev, dma_handle, size, dir)
 
 #define dma_supported		platform_dma_supported
 
--- diff/include/asm-ia64/irq.h	2003-05-21 11:50:16.000000000 +0100
+++ source/include/asm-ia64/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -29,4 +29,8 @@ extern void disable_irq_nosync (unsigned
 extern void enable_irq (unsigned int);
 extern void set_irq_affinity_info (unsigned int irq, int dest, int redir);
 
+struct irqaction;
+struct pt_regs;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+
 #endif /* _ASM_IA64_IRQ_H */
--- diff/include/asm-ia64/machvec.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-ia64/machvec.h	2004-03-09 11:51:51.000000000 +0000
@@ -42,8 +42,10 @@ typedef dma_addr_t ia64_mv_dma_map_singl
 typedef void ia64_mv_dma_unmap_single (struct device *, dma_addr_t, size_t, int);
 typedef int ia64_mv_dma_map_sg (struct device *, struct scatterlist *, int, int);
 typedef void ia64_mv_dma_unmap_sg (struct device *, struct scatterlist *, int, int);
-typedef void ia64_mv_dma_sync_single (struct device *, dma_addr_t, size_t, int);
-typedef void ia64_mv_dma_sync_sg (struct device *, struct scatterlist *, int, int);
+typedef void ia64_mv_dma_sync_single_for_cpu (struct device *, dma_addr_t, size_t, int);
+typedef void ia64_mv_dma_sync_sg_for_cpu (struct device *, struct scatterlist *, int, int);
+typedef void ia64_mv_dma_sync_single_for_device (struct device *, dma_addr_t, size_t, int);
+typedef void ia64_mv_dma_sync_sg_for_device (struct device *, struct scatterlist *, int, int);
 typedef int ia64_mv_dma_supported (struct device *, u64);
 
 /*
@@ -104,8 +106,10 @@ extern void machvec_memory_fence (void);
 #  define platform_dma_unmap_single	ia64_mv.dma_unmap_single
 #  define platform_dma_map_sg		ia64_mv.dma_map_sg
 #  define platform_dma_unmap_sg		ia64_mv.dma_unmap_sg
-#  define platform_dma_sync_single	ia64_mv.dma_sync_single
-#  define platform_dma_sync_sg		ia64_mv.dma_sync_sg
+#  define platform_dma_sync_single_for_cpu ia64_mv.dma_sync_single_for_cpu
+#  define platform_dma_sync_sg_for_cpu	ia64_mv.dma_sync_sg_for_cpu
+#  define platform_dma_sync_single_for_device ia64_mv.dma_sync_single_for_device
+#  define platform_dma_sync_sg_for_device ia64_mv.dma_sync_sg_for_device
 #  define platform_dma_supported	ia64_mv.dma_supported
 #  define platform_irq_desc		ia64_mv.irq_desc
 #  define platform_irq_to_vector	ia64_mv.irq_to_vector
@@ -150,8 +154,10 @@ struct ia64_machine_vector {
 	ia64_mv_dma_unmap_single *dma_unmap_single;
 	ia64_mv_dma_map_sg *dma_map_sg;
 	ia64_mv_dma_unmap_sg *dma_unmap_sg;
-	ia64_mv_dma_sync_single *dma_sync_single;
-	ia64_mv_dma_sync_sg *dma_sync_sg;
+	ia64_mv_dma_sync_single *dma_sync_single_for_cpu;
+	ia64_mv_dma_sync_sg *dma_sync_sg_for_cpu;
+	ia64_mv_dma_sync_single *dma_sync_single_for_device;
+	ia64_mv_dma_sync_sg *dma_sync_sg_for_device;
 	ia64_mv_dma_supported *dma_supported;
 	ia64_mv_irq_desc *irq_desc;
 	ia64_mv_irq_to_vector *irq_to_vector;
@@ -192,8 +198,10 @@ struct ia64_machine_vector {
 	platform_dma_unmap_single,		\
 	platform_dma_map_sg,			\
 	platform_dma_unmap_sg,			\
-	platform_dma_sync_single,		\
-	platform_dma_sync_sg,			\
+	platform_dma_sync_single_for_cpu,	\
+	platform_dma_sync_sg_for_cpu,		\
+	platform_dma_sync_single_for_device,	\
+	platform_dma_sync_sg_for_device,	\
 	platform_dma_supported,			\
 	platform_irq_desc,			\
 	platform_irq_to_vector,			\
@@ -231,8 +239,10 @@ extern ia64_mv_dma_map_single		swiotlb_m
 extern ia64_mv_dma_unmap_single		swiotlb_unmap_single;
 extern ia64_mv_dma_map_sg		swiotlb_map_sg;
 extern ia64_mv_dma_unmap_sg		swiotlb_unmap_sg;
-extern ia64_mv_dma_sync_single		swiotlb_sync_single;
-extern ia64_mv_dma_sync_sg		swiotlb_sync_sg;
+extern ia64_mv_dma_sync_single_for_cpu	swiotlb_sync_single_for_cpu;
+extern ia64_mv_dma_sync_sg_for_cpu	swiotlb_sync_sg_for_cpu;
+extern ia64_mv_dma_sync_single_for_device swiotlb_sync_single_for_device;
+extern ia64_mv_dma_sync_sg_for_device	swiotlb_sync_sg_for_device;
 extern ia64_mv_dma_supported		swiotlb_dma_supported;
 
 /*
@@ -290,11 +300,17 @@ extern ia64_mv_dma_supported		swiotlb_dm
 #ifndef platform_dma_unmap_sg
 # define platform_dma_unmap_sg		swiotlb_unmap_sg
 #endif
-#ifndef platform_dma_sync_single
-# define platform_dma_sync_single	swiotlb_sync_single
+#ifndef platform_dma_sync_single_for_cpu
+# define platform_dma_sync_single_for_cpu	swiotlb_sync_single_for_cpu
 #endif
-#ifndef platform_dma_sync_sg
-# define platform_dma_sync_sg		swiotlb_sync_sg
+#ifndef platform_dma_sync_sg_for_cpu
+# define platform_dma_sync_sg_for_cpu		swiotlb_sync_sg_for_cpu
+#endif
+#ifndef platform_dma_sync_single_for_device
+# define platform_dma_sync_single_for_device	swiotlb_sync_single_for_device
+#endif
+#ifndef platform_dma_sync_sg_for_device
+# define platform_dma_sync_sg_for_device	swiotlb_sync_sg_for_device
 #endif
 #ifndef platform_dma_supported
 # define  platform_dma_supported	swiotlb_dma_supported
--- diff/include/asm-ia64/machvec_hpzx1.h	2003-06-09 14:18:20.000000000 +0100
+++ source/include/asm-ia64/machvec_hpzx1.h	2004-03-09 11:51:51.000000000 +0000
@@ -26,8 +26,10 @@ extern ia64_mv_dma_supported		sba_dma_su
 #define platform_dma_unmap_single	sba_unmap_single
 #define platform_dma_map_sg		sba_map_sg
 #define platform_dma_unmap_sg		sba_unmap_sg
-#define platform_dma_sync_single	((ia64_mv_dma_sync_single *) machvec_memory_fence)
-#define platform_dma_sync_sg		((ia64_mv_dma_sync_sg *) machvec_memory_fence)
+#define platform_dma_sync_single_for_cpu ((ia64_mv_dma_sync_single_for_cpu *) machvec_memory_fence)
+#define platform_dma_sync_sg_for_cpu	((ia64_mv_dma_sync_sg_for_cpu *) machvec_memory_fence)
+#define platform_dma_sync_single_for_device ((ia64_mv_dma_sync_single_for_device *) machvec_memory_fence)
+#define platform_dma_sync_sg_for_device	((ia64_mv_dma_sync_sg_for_device *) machvec_memory_fence)
 #define platform_dma_supported		sba_dma_supported
 
 #endif /* _ASM_IA64_MACHVEC_HPZX1_h */
--- diff/include/asm-ia64/machvec_sn2.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-ia64/machvec_sn2.h	2004-03-09 11:51:51.000000000 +0000
@@ -62,8 +62,10 @@ extern ia64_mv_dma_map_single		sn_dma_ma
 extern ia64_mv_dma_unmap_single		sn_dma_unmap_single;
 extern ia64_mv_dma_map_sg		sn_dma_map_sg;
 extern ia64_mv_dma_unmap_sg		sn_dma_unmap_sg;
-extern ia64_mv_dma_sync_single		sn_dma_sync_single;
-extern ia64_mv_dma_sync_sg		sn_dma_sync_sg;
+extern ia64_mv_dma_sync_single_for_cpu	sn_dma_sync_single_for_cpu;
+extern ia64_mv_dma_sync_sg_for_cpu	sn_dma_sync_sg_for_cpu;
+extern ia64_mv_dma_sync_single_for_device sn_dma_sync_single_for_device;
+extern ia64_mv_dma_sync_sg_for_device	sn_dma_sync_sg_for_device;
 extern ia64_mv_dma_supported		sn_dma_supported;
 
 /*
@@ -105,8 +107,10 @@ extern ia64_mv_dma_supported		sn_dma_sup
 #define platform_dma_unmap_single	sn_dma_unmap_single
 #define platform_dma_map_sg		sn_dma_map_sg
 #define platform_dma_unmap_sg		sn_dma_unmap_sg
-#define platform_dma_sync_single	sn_dma_sync_single
-#define platform_dma_sync_sg		sn_dma_sync_sg
+#define platform_dma_sync_single_for_cpu sn_dma_sync_single_for_cpu
+#define platform_dma_sync_sg_for_cpu	sn_dma_sync_sg_for_cpu
+#define platform_dma_sync_single_for_device sn_dma_sync_single_for_device
+#define platform_dma_sync_sg_for_device	sn_dma_sync_sg_for_device
 #define platform_dma_supported		sn_dma_supported
 
 #include <asm/sn/sn2/io.h>
--- diff/include/asm-ia64/pci.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-ia64/pci.h	2004-03-09 11:51:51.000000000 +0000
@@ -76,7 +76,8 @@ extern int pcibios_prep_mwi (struct pci_
 #define pci_dac_page_to_dma(dev,pg,off,dir)		((dma_addr_t) page_to_bus(pg) + (off))
 #define pci_dac_dma_to_page(dev,dma_addr)		(virt_to_page(bus_to_virt(dma_addr)))
 #define pci_dac_dma_to_offset(dev,dma_addr)		offset_in_page(dma_addr)
-#define pci_dac_dma_sync_single(dev,dma_addr,len,dir)	do { mb(); } while (0)
+#define pci_dac_dma_sync_single_for_cpu(dev,dma_addr,len,dir)	do { } while (0)
+#define pci_dac_dma_sync_single_for_device(dev,dma_addr,len,dir)	do { mb(); } while (0)
 
 #define sg_dma_len(sg)		((sg)->dma_length)
 #define sg_dma_address(sg)	((sg)->dma_address)
--- diff/include/asm-ia64/spinlock.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/asm-ia64/spinlock.h	2004-03-09 11:51:51.000000000 +0000
@@ -110,8 +110,18 @@ do {											\
 typedef struct {
 	volatile int read_counter	: 31;
 	volatile int write_lock		:  1;
+#ifdef CONFIG_LOCKMETER
+	/* required for LOCKMETER since all bits in lock are used */
+	/* and we need this storage for CPU and lock INDEX        */
+	unsigned lockmeter_magic;
+#endif
 } rwlock_t;
+
+#ifdef CONFIG_LOCKMETER
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0 }
+#else
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
+#endif
 
 #define rwlock_init(x)		do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 #define rwlock_is_locked(x)	(*(volatile int *) (x) != 0)
@@ -127,6 +137,48 @@ do {											\
 	}										\
 } while (0)
 
+#ifdef CONFIG_LOCKMETER
+/*
+ * HACK: This works, but still have a timing window that affects performance:
+ * we see that no one owns the Write lock, then someone * else grabs for Write
+ * lock before we do a read_lock().
+ * This means that on rare occasions our read_lock() will stall and spin-wait
+ * until we acquire for Read, instead of simply returning a trylock failure.
+ */
+static inline int _raw_read_trylock(rwlock_t *rw)
+{
+	if (rw->write_lock) {
+		return 0;
+	} else {
+		_raw_read_lock(rw);
+		return 1;
+	}
+}
+
+static inline int _raw_write_trylock(rwlock_t *rw)
+{
+	if (!(rw->write_lock)) {
+	    /* isn't currently write-locked... that looks promising... */
+	    if (test_and_set_bit(31, rw) == 0) {
+		/* now it is write-locked by me... */
+		if (rw->read_counter) {
+		    /* really read-locked, so release write-lock and fail */
+		    clear_bit(31, rw);
+		} else {
+		    /* we've the the write-lock, no read-lockers... success! */
+		    barrier();
+		    return 1;
+		}
+
+	    }
+	}
+
+	/* falls through ... fails to write-lock */
+	barrier();
+	return 0;
+}
+#endif
+
 #define _raw_read_unlock(rw)					\
 do {								\
 	rwlock_t *__read_lock_ptr = (rw);			\
@@ -190,4 +242,25 @@ do {										\
 	clear_bit(31, (x));								\
 })
 
+#ifdef CONFIG_LOCKMETER
+extern void _metered_spin_lock  (spinlock_t *lock);
+extern void _metered_spin_unlock(spinlock_t *lock);
+
+/*
+ *  Use a less efficient, and inline, atomic_dec_and_lock() if lockmetering
+ *  so we can see the callerPC of who is actually doing the spin_lock().
+ *  Otherwise, all we see is the generic rollup of all locks done by
+ *  atomic_dec_and_lock().
+ */
+static inline int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+{
+	_metered_spin_lock(lock);
+	if (atomic_dec_and_test(atomic))
+		return 1;
+	_metered_spin_unlock(lock);
+	return 0;
+}
+#define ATOMIC_DEC_AND_LOCK
+#endif
+
 #endif /*  _ASM_IA64_SPINLOCK_H */
--- diff/include/asm-ia64/tlb.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-ia64/tlb.h	2004-03-09 11:51:51.000000000 +0000
@@ -211,6 +211,8 @@ __tlb_remove_tlb_entry (struct mmu_gathe
 	tlb->end_addr = address + PAGE_SIZE;
 }
 
+#define tlb_migrate_prepare(mm) flush_tlb_mm(mm)
+
 #define tlb_start_vma(tlb, vma)			do { } while (0)
 #define tlb_end_vma(tlb, vma)			do { } while (0)
 
--- diff/include/asm-m68k/irq.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-m68k/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -76,10 +76,10 @@ extern void (*disable_irq)(unsigned int)
 
 struct pt_regs;
 
-extern int sys_request_irq(unsigned int,
-	irqreturn_t (*)(int, void *, struct pt_regs *),
-	unsigned long, const char *, void *);
-extern void sys_free_irq(unsigned int, void *);
+extern int cpu_request_irq(unsigned int,
+			   irqreturn_t (*)(int, void *, struct pt_regs *),
+			   unsigned long, const char *, void *);
+extern void cpu_free_irq(unsigned int, void *);
 
 /*
  * various flags for request_irq() - the Amiga now uses the standard
@@ -124,4 +124,8 @@ extern volatile unsigned int num_spuriou
  */
 extern irq_node_t *new_irq_node(void);
 
+struct irqaction;
+struct pt_regs;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+
 #endif /* _M68K_IRQ_H_ */
--- diff/include/asm-m68k/unistd.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-m68k/unistd.h	2004-03-09 11:51:51.000000000 +0000
@@ -374,7 +374,6 @@ asmlinkage long sys_mmap2(
 asmlinkage int sys_execve(char *name, char **argv, char **envp);
 asmlinkage int sys_pipe(unsigned long *fildes);
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data);
-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
 struct pt_regs;
 struct sigaction;
 asmlinkage long sys_rt_sigaction(int sig,
--- diff/include/asm-m68knommu/irq.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-m68knommu/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -121,4 +121,8 @@ extern irq_node_t *new_irq_node(void);
 #define enable_irq_nosync(x)	enable_irq(x)
 #define disable_irq_nosync(x)	disable_irq(x)
 
+struct irqaction;
+struct pt_regs;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+
 #endif /* _M68K_IRQ_H_ */
--- diff/include/asm-m68knommu/unistd.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-m68knommu/unistd.h	2004-03-09 11:51:51.000000000 +0000
@@ -416,7 +416,6 @@ asmlinkage long sys_mmap2(unsigned long 
 asmlinkage int sys_execve(char *name, char **argv, char **envp);
 asmlinkage int sys_pipe(unsigned long *fildes);
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data);
-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
 struct pt_regs;
 int sys_request_irq(unsigned int,
 			irqreturn_t (*)(int, void *, struct pt_regs *),
--- diff/include/asm-mips/dma-mapping.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-mips/dma-mapping.h	2004-03-09 11:51:51.000000000 +0000
@@ -29,11 +29,17 @@ extern void dma_unmap_page(struct device
 	size_t size, enum dma_data_direction direction);
 extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
 	int nhwentries, enum dma_data_direction direction);
-extern void dma_sync_single(struct device *dev, dma_addr_t dma_handle,
+extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
 	size_t size, enum dma_data_direction direction);
-extern void dma_sync_single_range(struct device *dev, dma_addr_t dma_handle,
+extern void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
+	size_t size, enum dma_data_direction direction);
+extern void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+	unsigned long offset, size_t size, enum dma_data_direction direction);
+extern void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
 	unsigned long offset, size_t size, enum dma_data_direction direction);
-extern void dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems,
+extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
+	enum dma_data_direction direction);
+extern void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
 	enum dma_data_direction direction);
 
 extern int dma_supported(struct device *dev, u64 mask);
--- diff/include/asm-mips/irq.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-mips/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -31,4 +31,7 @@ extern asmlinkage unsigned int do_IRQ(in
 
 extern void init_generic_irq(void);
 
+struct irqaction;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+
 #endif /* _ASM_IRQ_H */
--- diff/include/asm-mips/pci.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-mips/pci.h	2004-03-09 11:51:51.000000000 +0000
@@ -82,7 +82,9 @@ extern struct page *pci_dac_dma_to_page(
 	dma64_addr_t dma_addr);
 extern unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev,
 	dma64_addr_t dma_addr);
-extern void pci_dac_dma_sync_single(struct pci_dev *pdev,
+extern void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev,
+	dma64_addr_t dma_addr, size_t len, int direction);
+extern void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev,
 	dma64_addr_t dma_addr, size_t len, int direction);
 
 #endif /* __KERNEL__ */
--- diff/include/asm-mips/spinlock.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-mips/spinlock.h	2004-03-09 11:51:51.000000000 +0000
@@ -91,9 +91,18 @@ static inline unsigned int _raw_spin_try
 
 typedef struct {
 	volatile unsigned int lock;
+#ifdef CONFIG_LOCKMETER
+	/* required for LOCKMETER since all bits in lock are used */
+	/* and we need this storage for CPU and lock INDEX        */
+	unsigned lockmeter_magic;
+#endif
 } rwlock_t;
 
+#ifdef CONFIG_LOCKMETER
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
+#else
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
+#endif
 
 #define rwlock_init(x)  do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 
--- diff/include/asm-parisc/dma-mapping.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/asm-parisc/dma-mapping.h	2004-03-09 11:51:51.000000000 +0000
@@ -15,8 +15,10 @@ struct hppa_dma_ops {
 	void (*unmap_single)(struct device *dev, dma_addr_t iova, size_t size, enum dma_data_direction direction);
 	int  (*map_sg)(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction);
 	void (*unmap_sg)(struct device *dev, struct scatterlist *sg, int nhwents, enum dma_data_direction direction);
-	void (*dma_sync_single)(struct device *dev, dma_addr_t iova, unsigned long offset, size_t size, enum dma_data_direction direction);
-	void (*dma_sync_sg)(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction direction);
+	void (*dma_sync_single_for_cpu)(struct device *dev, dma_addr_t iova, unsigned long offset, size_t size, enum dma_data_direction direction);
+	void (*dma_sync_single_for_device)(struct device *dev, dma_addr_t iova, unsigned long offset, size_t size, enum dma_data_direction direction);
+	void (*dma_sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction direction);
+	void (*dma_sync_sg_for_device)(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction direction);
 };
 
 /*
@@ -116,28 +118,53 @@ dma_unmap_page(struct device *dev, dma_a
 
 
 static inline void
-dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size,
+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
 		enum dma_data_direction direction)
 {
-	if(hppa_dma_ops->dma_sync_single)
-		hppa_dma_ops->dma_sync_single(dev, dma_handle, 0, size, direction);
+	if(hppa_dma_ops->dma_sync_single_for_cpu)
+		hppa_dma_ops->dma_sync_single_for_cpu(dev, dma_handle, 0, size, direction);
 }
 
 static inline void
-dma_sync_single_range(struct device *dev, dma_addr_t dma_handle,
+dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
+		enum dma_data_direction direction)
+{
+	if(hppa_dma_ops->dma_sync_single_for_device)
+		hppa_dma_ops->dma_sync_single_for_device(dev, dma_handle, 0, size, direction);
+}
+
+static inline void
+dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+		      unsigned long offset, size_t size,
+		      enum dma_data_direction direction)
+{
+	if(hppa_dma_ops->dma_sync_single_for_cpu)
+		hppa_dma_ops->dma_sync_single_for_cpu(dev, dma_handle, offset, size, direction);
+}
+
+static inline void
+dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
 		      unsigned long offset, size_t size,
 		      enum dma_data_direction direction)
 {
-	if(hppa_dma_ops->dma_sync_single)
-		hppa_dma_ops->dma_sync_single(dev, dma_handle, offset, size, direction);
+	if(hppa_dma_ops->dma_sync_single_for_device)
+		hppa_dma_ops->dma_sync_single_for_device(dev, dma_handle, offset, size, direction);
+}
+
+static inline void
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
+		 enum dma_data_direction direction)
+{
+	if(hppa_dma_ops->dma_sync_sg_for_cpu)
+		hppa_dma_ops->dma_sync_sg_for_cpu(dev, sg, nelems, direction);
 }
 
 static inline void
-dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems,
+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
 		 enum dma_data_direction direction)
 {
-	if(hppa_dma_ops->dma_sync_sg)
-		hppa_dma_ops->dma_sync_sg(dev, sg, nelems, direction);
+	if(hppa_dma_ops->dma_sync_sg_for_device)
+		hppa_dma_ops->dma_sync_sg_for_device(dev, sg, nelems, direction);
 }
 
 static inline int
@@ -166,14 +193,14 @@ dma_get_cache_alignment(void)
 static inline int
 dma_is_consistent(dma_addr_t dma_addr)
 {
-	return (hppa_dma_ops->dma_sync_single == NULL);
+	return (hppa_dma_ops->dma_sync_single_for_cpu == NULL);
 }
 
 static inline void
 dma_cache_sync(void *vaddr, size_t size,
 	       enum dma_data_direction direction)
 {
-	if(hppa_dma_ops->dma_sync_single)
+	if(hppa_dma_ops->dma_sync_single_for_cpu)
 		flush_kernel_dcache_range((unsigned long)vaddr, size);
 }
 
--- diff/include/asm-parisc/irq.h	2003-10-09 09:47:34.000000000 +0100
+++ source/include/asm-parisc/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -96,4 +96,7 @@ extern unsigned long txn_alloc_addr(int)
 /* soft power switch support (power.c) */
 extern struct tasklet_struct power_tasklet;
 
+struct irqaction;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+
 #endif	/* _ASM_PARISC_IRQ_H */
--- diff/include/asm-parisc/unistd.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-parisc/unistd.h	2004-03-09 11:51:51.000000000 +0000
@@ -909,7 +909,6 @@ int sys_clone(unsigned long clone_flags,
 int sys_vfork(struct pt_regs *regs);
 int sys_pipe(int *fildes);
 long sys_ptrace(long request, pid_t pid, long addr, long data);
-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on);
 struct sigaction;
 asmlinkage long sys_rt_sigaction(int sig,
 				const struct sigaction __user *act,
--- diff/include/asm-ppc/irq.h	2003-09-30 15:46:19.000000000 +0100
+++ source/include/asm-ppc/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -211,5 +211,9 @@ extern unsigned long ppc_cached_irq_mask
 extern unsigned long ppc_lost_interrupts[NR_MASK_WORDS];
 extern atomic_t ppc_n_lost_interrupts;
 
+struct irqaction;
+struct pt_regs;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+
 #endif /* _ASM_IRQ_H */
 #endif /* __KERNEL__ */
--- diff/include/asm-ppc/mman.h	2003-09-30 15:46:19.000000000 +0100
+++ source/include/asm-ppc/mman.h	2004-03-09 11:51:51.000000000 +0000
@@ -23,6 +23,7 @@
 #define MAP_EXECUTABLE	0x1000		/* mark it as an executable */
 #define MAP_POPULATE	0x8000		/* populate (prefault) pagetables */
 #define MAP_NONBLOCK	0x10000		/* do not block on IO */
+#define MAP_INHERIT	0x20000		/* inherit prot of underlying vma */
 
 #define MS_ASYNC	1		/* sync memory asynchronously */
 #define MS_INVALIDATE	2		/* invalidate the caches */
--- diff/include/asm-ppc/pci.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-ppc/pci.h	2004-03-09 11:51:51.000000000 +0000
@@ -91,7 +91,7 @@ extern void pci_free_consistent(struct p
  * The 32-bit bus address to use is returned.
  *
  * Once the device is given the dma address, the device owns this memory
- * until either pci_unmap_single or pci_dma_sync_single is performed.
+ * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed.
  */
 static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
 					size_t size, int direction)
@@ -190,35 +190,58 @@ static inline void pci_unmap_sg(struct p
  * If you perform a pci_map_single() but wish to interrogate the
  * buffer using the cpu, yet do not wish to teardown the PCI dma
  * mapping, you must call this function before doing so.  At the
- * next point you give the PCI dma address back to the card, the
- * device again owns the buffer.
+ * next point you give the PCI dma address back to the card, you
+ * must first perform a pci_dma_sync_for_device, and then the device
+ * again owns the buffer.
  */
-static inline void pci_dma_sync_single(struct pci_dev *hwdev,
-				       dma_addr_t dma_handle,
-				       size_t size, int direction)
+static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev,
+					       dma_addr_t dma_handle,
+					       size_t size, int direction)
 {
 	BUG_ON(direction == PCI_DMA_NONE);
 
-	consistent_sync(bus_to_virt(dma_handle), size, direction);
+	consistent_sync_for_cpu(bus_to_virt(dma_handle), size, direction);
+}
+
+static inline void pci_dma_sync_single_for_device(struct pci_dev *hwdev,
+						  dma_addr_t dma_handle,
+						  size_t size, int direction)
+{
+	BUG_ON(direction == PCI_DMA_NONE);
+
+	consistent_sync_for_device(bus_to_virt(dma_handle), size, direction);
 }
 
 /* Make physical memory consistent for a set of streaming
  * mode DMA translations after a transfer.
  *
- * The same as pci_dma_sync_single but for a scatter-gather list,
+ * The same as pci_dma_sync_single_for_* but for a scatter-gather list,
  * same rules and usage.
  */
-static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
-				   struct scatterlist *sg,
-				   int nelems, int direction)
+static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev,
+					   struct scatterlist *sg,
+					   int nelems, int direction)
 {
 	int i;
 
 	BUG_ON(direction == PCI_DMA_NONE);
 
 	for (i = 0; i < nelems; i++, sg++)
-		consistent_sync_page(sg->page, sg->offset,
-				     sg->length, direction);
+		consistent_sync_page_for_cpu(sg->page, sg->offset,
+					     sg->length, direction);
+}
+
+static inline void pci_dma_sync_sg_for_device(struct pci_dev *hwdev,
+					      struct scatterlist *sg,
+					      int nelems, int direction)
+{
+	int i;
+
+	BUG_ON(direction == PCI_DMA_NONE);
+
+	for (i = 0; i < nelems; i++, sg++)
+		consistent_sync_page_for_device(sg->page, sg->offset,
+						sg->length, direction);
 }
 
 /* Return whether the given PCI device DMA address mask can
@@ -237,26 +260,32 @@ static inline int pci_dma_supported(stru
  */
 #define pci_dac_dma_supported(pci_dev, mask)	(0)
 
-static __inline__ dma64_addr_t
+static inline dma64_addr_t
 pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction)
 {
 	return (dma64_addr_t) page_to_bus(page) + offset;
 }
 
-static __inline__ struct page *
+static inline struct page *
 pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
 {
 	return mem_map + (unsigned long)(dma_addr >> PAGE_SHIFT);
 }
 
-static __inline__ unsigned long
+static inline unsigned long
 pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
 {
 	return (dma_addr & ~PAGE_MASK);
 }
 
-static __inline__ void
-pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
+static inline void
+pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
+{
+	/* Nothing to do. */
+}
+
+static inline void
+pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
 {
 	/* Nothing to do. */
 }
--- diff/include/asm-ppc/pgtable.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-ppc/pgtable.h	2004-03-09 11:51:51.000000000 +0000
@@ -264,8 +264,8 @@ extern unsigned long ioremap_bot, iorema
 /* Definitions for 60x, 740/750, etc. */
 #define _PAGE_PRESENT	0x001	/* software: pte contains a translation */
 #define _PAGE_HASHPTE	0x002	/* hash_page has made an HPTE for this pte */
-#define _PAGE_FILE	0x004	/* when !present: nonlinear file mapping */
 #define _PAGE_USER	0x004	/* usermode access allowed */
+#define _PAGE_FILE	0x008	/* when !present: nonlinear file mapping */
 #define _PAGE_GUARDED	0x008	/* G: prohibit speculative access */
 #define _PAGE_COHERENT	0x010	/* M: enforce memory coherence (SMP systems) */
 #define _PAGE_NO_CACHE	0x020	/* I: cache inhibit */
@@ -628,9 +628,16 @@ extern void add_hash_page(unsigned conte
 #define __swp_entry_to_pte(x)		((pte_t) { (x).val << 3 })
 
 /* Encode and decode a nonlinear file mapping entry */
-#define PTE_FILE_MAX_BITS	29
-#define pte_to_pgoff(pte)	(pte_val(pte) >> 3)
-#define pgoff_to_pte(off)	((pte_t) { ((off) << 3) | _PAGE_FILE })
+#define PTE_FILE_MAX_BITS	27
+#define pte_to_pgoff(pte)	(((pte_val(pte) & ~0x7ff) >> 5)		\
+				 | ((pte_val(pte) & 0x3f0) >> 4))
+#define pte_to_pgprot(pte)	\
+__pgprot((pte_val(pte) & (_PAGE_USER|_PAGE_RW|_PAGE_PRESENT)) | _PAGE_ACCESSED)
+
+#define pgoff_prot_to_pte(off, prot)					\
+	((pte_t) { (((off) << 5) & ~0x7ff) | (((off) << 4) & 0x3f0)	\
+		   | (pgprot_val(prot) & (_PAGE_USER|_PAGE_RW))		\
+		   | _PAGE_FILE })
 
 /* CONFIG_APUS */
 /* For virtual address to physical address conversion */
--- diff/include/asm-ppc64/compat.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ppc64/compat.h	2004-03-09 11:51:51.000000000 +0000
@@ -25,6 +25,7 @@ typedef u16		compat_ipc_pid_t;
 typedef s32		compat_daddr_t;
 typedef u32		compat_caddr_t;
 typedef __kernel_fsid_t	compat_fsid_t;
+typedef u32		compat_timer_t;
 
 typedef s32		compat_int_t;
 typedef s32		compat_long_t;
--- diff/include/asm-ppc64/iSeries/vio.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-ppc64/iSeries/vio.h	2004-03-09 11:51:51.000000000 +0000
@@ -127,4 +127,8 @@ enum viorc {
 	viorc_openRejected = 0x0301
 };
 
+struct device;
+
+extern struct device *iSeries_vio_dev;
+
 #endif /* _ISERIES_VIO_H */
--- diff/include/asm-ppc64/irq.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-ppc64/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -48,5 +48,9 @@ static __inline__ int irq_canonicalize(i
 
 #define NR_MASK_WORDS	((NR_IRQS + 63) / 64)
 
+struct irqaction;
+struct pt_regs;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+
 #endif /* _ASM_IRQ_H */
 #endif /* __KERNEL__ */
--- diff/include/asm-ppc64/mmu.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ppc64/mmu.h	2004-03-09 11:51:51.000000000 +0000
@@ -18,15 +18,25 @@
 
 #ifndef __ASSEMBLY__
 
-/* Default "unsigned long" context */
-typedef unsigned long mm_context_t;
+/* Time to allow for more things here */
+typedef unsigned long mm_context_id_t;
+typedef struct {
+	mm_context_id_t id;
+#ifdef CONFIG_HUGETLB_PAGE
+	int low_hpages;
+#endif
+} mm_context_t;
 
 #ifdef CONFIG_HUGETLB_PAGE
-#define CONTEXT_LOW_HPAGES	(1UL<<63)
+#define KERNEL_LOW_HPAGES	.low_hpages = 0,
 #else
-#define CONTEXT_LOW_HPAGES	0
+#define KERNEL_LOW_HPAGES
 #endif
 
+#define KERNEL_CONTEXT(ea) ({ \
+		mm_context_t ctx = { .id = REGION_ID(ea), KERNEL_LOW_HPAGES}; \
+		ctx; })
+
 /*
  * Hardware Segment Lookaside Buffer Entry
  * This structure has been padded out to two 64b doublewords (actual SLBE's are
--- diff/include/asm-ppc64/mmu_context.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-ppc64/mmu_context.h	2004-03-09 11:51:51.000000000 +0000
@@ -52,7 +52,7 @@ struct mmu_context_queue_t {
 	long head;
 	long tail;
 	long size;
-	mm_context_t elements[LAST_USER_CONTEXT];
+	mm_context_id_t elements[LAST_USER_CONTEXT];
 };
 
 extern struct mmu_context_queue_t mmu_context_queue;
@@ -83,7 +83,6 @@ init_new_context(struct task_struct *tsk
 	long head;
 	unsigned long flags;
 	/* This does the right thing across a fork (I hope) */
-	unsigned long low_hpages = mm->context & CONTEXT_LOW_HPAGES;
 
 	spin_lock_irqsave(&mmu_context_queue.lock, flags);
 
@@ -93,8 +92,7 @@ init_new_context(struct task_struct *tsk
 	}
 
 	head = mmu_context_queue.head;
-	mm->context = mmu_context_queue.elements[head];
-	mm->context |= low_hpages;
+	mm->context.id = mmu_context_queue.elements[head];
 
 	head = (head < LAST_USER_CONTEXT-1) ? head+1 : 0;
 	mmu_context_queue.head = head;
@@ -132,8 +130,7 @@ destroy_context(struct mm_struct *mm)
 #endif
 
 	mmu_context_queue.size++;
-	mmu_context_queue.elements[index] =
-		mm->context & ~CONTEXT_LOW_HPAGES;
+	mmu_context_queue.elements[index] = mm->context.id;
 
 	spin_unlock_irqrestore(&mmu_context_queue.lock, flags);
 }
@@ -212,8 +209,6 @@ get_vsid( unsigned long context, unsigne
 {
 	unsigned long ordinal, vsid;
 
-	context &= ~CONTEXT_LOW_HPAGES;
-
 	ordinal = (((ea >> 28) & 0x1fffff) * LAST_USER_CONTEXT) | context;
 	vsid = (ordinal * VSID_RANDOMIZER) & VSID_MASK;
 
--- diff/include/asm-ppc64/page.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-ppc64/page.h	2004-03-09 11:51:51.000000000 +0000
@@ -32,6 +32,7 @@
 /* For 64-bit processes the hugepage range is 1T-1.5T */
 #define TASK_HPAGE_BASE 	(0x0000010000000000UL)
 #define TASK_HPAGE_END 	(0x0000018000000000UL)
+
 /* For 32-bit processes the hugepage range is 2-3G */
 #define TASK_HPAGE_BASE_32	(0x80000000UL)
 #define TASK_HPAGE_END_32	(0xc0000000UL)
@@ -39,7 +40,7 @@
 #define ARCH_HAS_HUGEPAGE_ONLY_RANGE
 #define is_hugepage_only_range(addr, len) \
 	( ((addr > (TASK_HPAGE_BASE-len)) && (addr < TASK_HPAGE_END)) || \
-	  ((current->mm->context & CONTEXT_LOW_HPAGES) && \
+	  (current->mm->context.low_hpages && \
 	   (addr > (TASK_HPAGE_BASE_32-len)) && (addr < TASK_HPAGE_END_32)) )
 #define hugetlb_free_pgtables free_pgtables
 #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
@@ -47,7 +48,7 @@
 #define in_hugepage_area(context, addr) \
 	((cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) && \
 	 ((((addr) >= TASK_HPAGE_BASE) && ((addr) < TASK_HPAGE_END)) || \
-	  (((context) & CONTEXT_LOW_HPAGES) && \
+	  ((context).low_hpages && \
 	   (((addr) >= TASK_HPAGE_BASE_32) && ((addr) < TASK_HPAGE_END_32)))))
 
 #else /* !CONFIG_HUGETLB_PAGE */
--- diff/include/asm-ppc64/pci.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-ppc64/pci.h	2004-03-09 11:51:51.000000000 +0000
@@ -112,17 +112,33 @@ static inline void pci_unmap_sg(struct p
 	pci_dma_ops.pci_unmap_sg(hwdev, sg, nents, direction);
 }
 
-static inline void pci_dma_sync_single(struct pci_dev *hwdev,
-				       dma_addr_t dma_handle,
-				       size_t size, int direction)
+static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev,
+					       dma_addr_t dma_handle,
+					       size_t size, int direction)
 {
 	BUG_ON(direction == PCI_DMA_NONE);
 	/* nothing to do */
 }
 
-static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
-				   struct scatterlist *sg,
-				   int nelems, int direction)
+static inline void pci_dma_sync_single_for_device(struct pci_dev *hwdev,
+						  dma_addr_t dma_handle,
+						  size_t size, int direction)
+{
+	BUG_ON(direction == PCI_DMA_NONE);
+	/* nothing to do */
+}
+
+static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev,
+					   struct scatterlist *sg,
+					   int nelems, int direction)
+{
+	BUG_ON(direction == PCI_DMA_NONE);
+	/* nothing to do */
+}
+
+static inline void pci_dma_sync_sg_for_device(struct pci_dev *hwdev,
+					      struct scatterlist *sg,
+					      int nelems, int direction)
 {
 	BUG_ON(direction == PCI_DMA_NONE);
 	/* nothing to do */
--- diff/include/asm-ppc64/ppc32.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ppc64/ppc32.h	2004-03-09 11:51:51.000000000 +0000
@@ -2,6 +2,7 @@
 #define _PPC64_PPC32_H
 
 #include <linux/compat.h>
+#include <linux/compat_siginfo.h>
 #include <asm/siginfo.h>
 #include <asm/signal.h>
 
@@ -40,55 +41,6 @@
 
 /* These are here to support 32-bit syscalls on a 64-bit kernel. */
 
-typedef struct compat_siginfo {
-	int si_signo;
-	int si_errno;
-	int si_code;
-
-	union {
-		int _pad[SI_PAD_SIZE32];
-
-		/* kill() */
-		struct {
-			compat_pid_t _pid;		/* sender's pid */
-			compat_uid_t _uid;		/* sender's uid */
-		} _kill;
-
-		/* POSIX.1b timers */
-		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
-		} _timer;
-
-		/* POSIX.1b signals */
-		struct {
-			compat_pid_t _pid;		/* sender's pid */
-			compat_uid_t _uid;		/* sender's uid */
-			compat_sigval_t _sigval;
-		} _rt;
-
-		/* SIGCHLD */
-		struct {
-			compat_pid_t _pid;		/* which child */
-			compat_uid_t _uid;		/* sender's uid */
-			int _status;			/* exit code */
-			compat_clock_t _utime;
-			compat_clock_t _stime;
-		} _sigchld;
-
-		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */
-		struct {
-			unsigned int _addr; /* faulting insn/memory ref. */
-		} _sigfault;
-
-		/* SIGPOLL */
-		struct {
-			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
-			int _fd;
-		} _sigpoll;
-	} _sifields;
-} compat_siginfo_t;
-
 #define __old_sigaction32	old_sigaction32
 
 struct __old_sigaction32 {
@@ -141,20 +93,6 @@ struct ucontext32 { 
 	struct mcontext32	uc_mcontext;
 };
 
-typedef struct compat_sigevent {
-	compat_sigval_t sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE];
-		int _tid;
-		struct {
-			compat_uptr_t _function;
-			compat_uptr_t _attribute;
-		} _sigev_thread;
-	} _sigev_un;
-} compat_sigevent_t;
-
 struct ipc_kludge_32 {
 	unsigned int msgp;
 	int msgtyp;
--- diff/include/asm-s390/compat.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-s390/compat.h	2004-03-09 11:51:51.000000000 +0000
@@ -15,6 +15,8 @@ typedef s32		compat_clock_t;
 typedef s32		compat_pid_t;
 typedef u16		compat_uid_t;
 typedef u16		compat_gid_t;
+typedef u32		compat_uid32_t;
+typedef u32		compat_gid32_t;
 typedef u16		compat_mode_t;
 typedef u32		compat_ino_t;
 typedef u16		compat_dev_t;
@@ -25,6 +27,7 @@ typedef u16		compat_ipc_pid_t;
 typedef s32		compat_daddr_t;
 typedef u32		compat_caddr_t;
 typedef __kernel_fsid_t	compat_fsid_t;
+typedef s32		compat_key_t;
 typedef s32		compat_timer_t;
 
 typedef s32		compat_int_t;
@@ -135,4 +138,61 @@ static inline void *compat_alloc_user_sp
 	return (void *) (stack - len);
 }
 
+struct compat_ipc64_perm {
+	compat_key_t key;
+	compat_uid32_t uid;
+	compat_gid32_t gid;
+	compat_uid32_t cuid;
+	compat_gid32_t cgid;
+	compat_mode_t mode;
+	unsigned short __pad1;
+	unsigned short seq;
+	unsigned short __pad2;
+	unsigned int __unused1;
+	unsigned int __unused2;
+};
+
+struct compat_semid64_ds {
+	struct compat_ipc64_perm sem_perm;
+	compat_time_t  sem_otime;
+	compat_ulong_t __pad1;
+	compat_time_t  sem_ctime;
+	compat_ulong_t __pad2;
+	compat_ulong_t sem_nsems;
+	compat_ulong_t __unused1;
+	compat_ulong_t __unused2;
+};
+
+struct compat_msqid64_ds {
+	struct compat_ipc64_perm msg_perm;
+	compat_time_t   msg_stime;
+	compat_ulong_t __pad1;
+	compat_time_t   msg_rtime;
+	compat_ulong_t __pad2;
+	compat_time_t   msg_ctime;
+	compat_ulong_t __pad3;
+	compat_ulong_t msg_cbytes;
+	compat_ulong_t msg_qnum;
+	compat_ulong_t msg_qbytes;
+	compat_pid_t   msg_lspid;
+	compat_pid_t   msg_lrpid;
+	compat_ulong_t __unused1;
+	compat_ulong_t __unused2;
+};
+
+struct compat_shmid64_ds {
+	struct compat_ipc64_perm shm_perm;
+	compat_size_t  shm_segsz;
+	compat_time_t  shm_atime;
+	compat_ulong_t __pad1;
+	compat_time_t  shm_dtime;
+	compat_ulong_t __pad2;
+	compat_time_t  shm_ctime;
+	compat_ulong_t __pad3;
+	compat_pid_t   shm_cpid;
+	compat_pid_t   shm_lpid;
+	compat_ulong_t shm_nattch;
+	compat_ulong_t __unused1;
+	compat_ulong_t __unused2;
+};
 #endif /* _ASM_S390X_COMPAT_H */
--- diff/include/asm-s390/irq.h	2003-08-20 14:16:14.000000000 +0100
+++ source/include/asm-s390/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -21,6 +21,10 @@ enum interruption_class {
 
 #define touch_nmi_watchdog() do { } while(0)
 
+struct irqaction;
+struct pt_regs;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+
 #endif /* __KERNEL__ */
 #endif
 
--- diff/include/asm-s390/unistd.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-s390/unistd.h	2004-03-09 11:51:51.000000000 +0000
@@ -553,7 +553,6 @@ asmlinkage int sys_vfork(struct pt_regs 
 #endif /* CONFIG_ARCH_S390X */
 asmlinkage __SYS_RETTYPE sys_pipe(unsigned long *fildes);
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data);
-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
 struct sigaction;
 asmlinkage long sys_rt_sigaction(int sig,
 				const struct sigaction __user *act,
--- diff/include/asm-sh/irq.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-sh/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -324,4 +324,8 @@ static inline int generic_irq_demux(int 
 #define irq_canonicalize(irq)	(irq)
 #define irq_demux(irq)		__irq_demux(sh_mv.mv_irq_demux(irq))
 
+struct irqaction;
+struct pt_regs;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+
 #endif /* __ASM_SH_IRQ_H */
--- diff/include/asm-sh/pci.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-sh/pci.h	2004-03-09 11:51:51.000000000 +0000
@@ -84,7 +84,7 @@ extern void pci_free_consistent(struct p
  * The 32-bit bus address to use is returned.
  *
  * Once the device is given the dma address, the device owns this memory
- * until either pci_unmap_single or pci_dma_sync_single is performed.
+ * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed.
  */
 static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
 					size_t size, int direction)
@@ -184,12 +184,21 @@ static inline void pci_unmap_sg(struct p
  * If you perform a pci_map_single() but wish to interrogate the
  * buffer using the cpu, yet do not wish to teardown the PCI dma
  * mapping, you must call this function before doing so.  At the
- * next point you give the PCI dma address back to the card, the
- * device again owns the buffer.
- */
-static inline void pci_dma_sync_single(struct pci_dev *hwdev,
-				       dma_addr_t dma_handle,
-				       size_t size, int direction)
+ * next point you give the PCI dma address back to the card, you
+ * must first perform a pci_dma_sync_for_device, and then the device
+ * again owns the buffer.
+ */
+static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev,
+					       dma_addr_t dma_handle,
+					       size_t size, int direction)
+{
+	if (direction == PCI_DMA_NONE)
+                BUG();
+}
+
+static inline void pci_dma_sync_single_for_device(struct pci_dev *hwdev,
+						  dma_addr_t dma_handle,
+						  size_t size, int direction)
 {
 	if (direction == PCI_DMA_NONE)
                 BUG();
@@ -203,12 +212,20 @@ static inline void pci_dma_sync_single(s
 /* Make physical memory consistent for a set of streaming
  * mode DMA translations after a transfer.
  *
- * The same as pci_dma_sync_single but for a scatter-gather list,
+ * The same as pci_dma_sync_single_* but for a scatter-gather list,
  * same rules and usage.
  */
-static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
-				   struct scatterlist *sg,
-				   int nelems, int direction)
+static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev,
+					   struct scatterlist *sg,
+					   int nelems, int direction)
+{
+	if (direction == PCI_DMA_NONE)
+                BUG();
+}
+
+static inline void pci_dma_sync_sg_for_device(struct pci_dev *hwdev,
+					      struct scatterlist *sg,
+					      int nelems, int direction)
 {
 	if (direction == PCI_DMA_NONE)
                 BUG();
--- diff/include/asm-sparc/irq.h	2003-10-27 09:20:39.000000000 +0000
+++ source/include/asm-sparc/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -184,4 +184,8 @@ extern struct sun4m_intregs *sun4m_inter
 #define SUN4M_INT_SBUS(x)	(1 << (x+7))
 #define SUN4M_INT_VME(x)	(1 << (x))
 
+struct irqaction;
+struct pt_regs;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+
 #endif
--- diff/include/asm-sparc/pci.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/asm-sparc/pci.h	2004-03-09 11:51:51.000000000 +0000
@@ -52,7 +52,7 @@ extern void pci_free_consistent(struct p
  * The 32-bit bus address to use is returned.
  *
  * Once the device is given the dma address, the device owns this memory
- * until either pci_unmap_single or pci_dma_sync_single is performed.
+ * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed.
  */
 extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction);
 
@@ -116,18 +116,21 @@ extern void pci_unmap_sg(struct pci_dev 
  * If you perform a pci_map_single() but wish to interrogate the
  * buffer using the cpu, yet do not wish to teardown the PCI dma
  * mapping, you must call this function before doing so.  At the
- * next point you give the PCI dma address back to the card, the
- * device again owns the buffer.
+ * next point you give the PCI dma address back to the card, you
+ * must first perform a pci_dma_sync_for_device, and then the device
+ * again owns the buffer.
  */
-extern void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction);
+extern void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction);
+extern void pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction);
 
 /* Make physical memory consistent for a set of streaming
  * mode DMA translations after a transfer.
  *
- * The same as pci_dma_sync_single but for a scatter-gather list,
+ * The same as pci_dma_sync_single_* but for a scatter-gather list,
  * same rules and usage.
  */
-extern void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction);
+extern void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction);
+extern void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction);
 
 /* Return whether the given PCI device DMA address mask can
  * be supported properly.  For example, if your device can
--- diff/include/asm-sparc/sbus.h	2003-05-21 11:50:16.000000000 +0100
+++ source/include/asm-sparc/sbus.h	2004-03-09 11:51:51.000000000 +0000
@@ -118,8 +118,12 @@ extern int sbus_map_sg(struct sbus_dev *
 extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int, int);
 
 /* Finally, allow explicit synchronization of streamable mappings. */
-extern void sbus_dma_sync_single(struct sbus_dev *, dma_addr_t, size_t, int);
-extern void sbus_dma_sync_sg(struct sbus_dev *, struct scatterlist *, int, int);
+extern void sbus_dma_sync_single_for_cpu(struct sbus_dev *, dma_addr_t, size_t, int);
+#define sbus_dma_sync_single sbus_dma_sync_single_for_cpu
+extern void sbus_dma_sync_single_for_device(struct sbus_dev *, dma_addr_t, size_t, int);
+extern void sbus_dma_sync_sg_for_cpu(struct sbus_dev *, struct scatterlist *, int, int);
+#define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu
+extern void sbus_dma_sync_sg_for_device(struct sbus_dev *, struct scatterlist *, int, int);
 
 /* Eric Brower (ebrower@usa.net)
  * Translate SBus interrupt levels to ino values--
--- diff/include/asm-sparc/system.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/asm-sparc/system.h	2004-03-09 11:51:51.000000000 +0000
@@ -75,7 +75,7 @@ extern void fpsave(unsigned long *fpregs
 #ifdef CONFIG_SMP
 #define SWITCH_ENTER(prv) \
 	do {			\
-	if (test_tsk_thread_flag(prv, TIF_USEDFPU) { \
+	if (test_tsk_thread_flag(prv, TIF_USEDFPU)) { \
 		put_psr(get_psr() | PSR_EF); \
 		fpsave(&(prv)->thread.float_regs[0], &(prv)->thread.fsr, \
 		       &(prv)->thread.fpqueue[0], &(prv)->thread.fpqdepth); \
--- diff/include/asm-sparc/thread_info.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-sparc/thread_info.h	2004-03-09 11:51:51.000000000 +0000
@@ -79,9 +79,9 @@ register struct thread_info *current_thr
 /*
  * thread information allocation
  */
-#ifdef CONFIG_SUN4
+#if PAGE_SHIFT == 13
 #define THREAD_INFO_ORDER  0
-#else
+#else /* PAGE_SHIFT */
 #define THREAD_INFO_ORDER  1
 #endif
 
--- diff/include/asm-sparc/unistd.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-sparc/unistd.h	2004-03-09 11:51:51.000000000 +0000
@@ -461,7 +461,6 @@ asmlinkage unsigned long sys_mmap2(
 				unsigned long addr, unsigned long len,
 				unsigned long prot, unsigned long flags,
 				unsigned long fd, unsigned long pgoff);
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
 struct sigaction;
 asmlinkage long sys_rt_sigaction(int sig,
 				const struct sigaction __user *act,
--- diff/include/asm-sparc64/irq.h	2003-08-26 10:00:54.000000000 +0100
+++ source/include/asm-sparc64/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -150,4 +150,8 @@ static __inline__ unsigned long get_soft
 	return retval;
 }
 
+struct irqaction;
+struct pt_regs;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+
 #endif
--- diff/include/asm-sparc64/pci.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/asm-sparc64/pci.h	2004-03-09 11:51:51.000000000 +0000
@@ -60,7 +60,7 @@ extern void pci_free_consistent(struct p
  * The 32-bit bus address to use is returned.
  *
  * Once the device is given the dma address, the device owns this memory
- * until either pci_unmap_single or pci_dma_sync_single is performed.
+ * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed.
  */
 extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction);
 
@@ -123,19 +123,36 @@ extern void pci_unmap_sg(struct pci_dev 
  * If you perform a pci_map_single() but wish to interrogate the
  * buffer using the cpu, yet do not wish to teardown the PCI dma
  * mapping, you must call this function before doing so.  At the
- * next point you give the PCI dma address back to the card, the
+ * next point you give the PCI dma address back to the card, you
+ * must first perform a pci_dma_sync_for_device, and then the
  * device again owns the buffer.
  */
-extern void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle,
-				size_t size, int direction);
+extern void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle,
+					size_t size, int direction);
+
+static inline void
+pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle,
+			       size_t size, int direction)
+{
+	/* No flushing needed to sync cpu writes to the device.  */
+	BUG_ON(direction == PCI_DMA_NONE);
+}
 
 /* Make physical memory consistent for a set of streaming
  * mode DMA translations after a transfer.
  *
- * The same as pci_dma_sync_single but for a scatter-gather list,
+ * The same as pci_dma_sync_single_* but for a scatter-gather list,
  * same rules and usage.
  */
-extern void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction);
+extern void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction);
+
+static inline void
+pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg,
+			int nelems, int direction)
+{
+	/* No flushing needed to sync cpu writes to the device.  */
+	BUG_ON(direction == PCI_DMA_NONE);
+}
 
 /* Return whether the given PCI device DMA address mask can
  * be supported properly.  For example, if your device can
@@ -159,14 +176,14 @@ extern int pci_dma_supported(struct pci_
 #define pci_dac_dma_supported(pci_dev, mask) \
 	((((mask) & PCI64_REQUIRED_MASK) == PCI64_REQUIRED_MASK) ? 1 : 0)
 
-static __inline__ dma64_addr_t
+static inline dma64_addr_t
 pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction)
 {
 	return (PCI64_ADDR_BASE +
 		__pa(page_address(page)) + offset);
 }
 
-static __inline__ struct page *
+static inline struct page *
 pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
 {
 	unsigned long paddr = (dma_addr & PAGE_MASK) - PCI64_ADDR_BASE;
@@ -174,14 +191,22 @@ pci_dac_dma_to_page(struct pci_dev *pdev
 	return virt_to_page(__va(paddr));
 }
 
-static __inline__ unsigned long
+static inline unsigned long
 pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
 {
 	return (dma_addr & ~PAGE_MASK);
 }
 
-static __inline__ void
-pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
+static inline void
+pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
+{
+	/* DAC cycle addressing does not make use of the
+	 * PCI controller's streaming cache, so nothing to do.
+	 */
+}
+
+static inline void
+pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
 {
 	/* DAC cycle addressing does not make use of the
 	 * PCI controller's streaming cache, so nothing to do.
--- diff/include/asm-sparc64/sbus.h	2002-10-16 04:27:19.000000000 +0100
+++ source/include/asm-sparc64/sbus.h	2004-03-09 11:51:51.000000000 +0000
@@ -111,7 +111,11 @@ extern int sbus_map_sg(struct sbus_dev *
 extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int, int);
 
 /* Finally, allow explicit synchronization of streamable mappings. */
-extern void sbus_dma_sync_single(struct sbus_dev *, dma_addr_t, size_t, int);
-extern void sbus_dma_sync_sg(struct sbus_dev *, struct scatterlist *, int, int);
+extern void sbus_dma_sync_single_for_cpu(struct sbus_dev *, dma_addr_t, size_t, int);
+#define sbus_dma_sync_single sbus_dma_sync_single_for_cpu
+extern void sbus_dma_sync_single_for_device(struct sbus_dev *, dma_addr_t, size_t, int);
+extern void sbus_dma_sync_sg_for_cpu(struct sbus_dev *, struct scatterlist *, int, int);
+#define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu
+extern void sbus_dma_sync_sg_for_device(struct sbus_dev *, struct scatterlist *, int, int);
 
 #endif /* !(_SPARC64_SBUS_H) */
--- diff/include/asm-sparc64/smp.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-sparc64/smp.h	2004-03-09 11:51:51.000000000 +0000
@@ -35,11 +35,6 @@ extern unsigned char boot_cpu_id;
 extern cpumask_t phys_cpu_present_map;
 #define cpu_possible_map phys_cpu_present_map
 
-#define cpu_online(cpu)		cpu_isset(cpu, cpu_online_map)
-
-extern atomic_t sparc64_num_cpus_possible;
-#define num_possible_cpus()	(atomic_read(&sparc64_num_cpus_possible))
-
 /*
  *	General functions that each host system must provide.
  */
@@ -75,10 +70,6 @@ static __inline__ int hard_smp_processor
 
 #endif /* !(__ASSEMBLY__) */
 
-#else
-
-#define num_possible_cpus()	(1)
-
 #endif /* !(CONFIG_SMP) */
 
 #define NO_PROC_ID		0xFF
--- diff/include/asm-sparc64/spinlock.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-sparc64/spinlock.h	2004-03-09 11:51:51.000000000 +0000
@@ -31,15 +31,23 @@
 
 #ifndef CONFIG_DEBUG_SPINLOCK
 
-typedef unsigned char spinlock_t;
-#define SPIN_LOCK_UNLOCKED	0
+typedef struct {
+	unsigned char lock;
+	unsigned int  index;
+} spinlock_t;
 
-#define spin_lock_init(lock)	(*((unsigned char *)(lock)) = 0)
-#define spin_is_locked(lock)	(*((volatile unsigned char *)(lock)) != 0)
+#ifdef CONFIG_LOCKMETER
+#define SPIN_LOCK_UNLOCKED	(spinlock_t) {0, 0}
+#else
+#define SPIN_LOCK_UNLOCKED	(spinlock_t) { 0 }
+#endif
 
-#define spin_unlock_wait(lock)	\
+#define spin_lock_init(__lock)	do { *(__lock) = SPIN_LOCK_UNLOCKED; } while(0)
+#define spin_is_locked(__lock)	(*((volatile unsigned char *)(&((__lock)->lock))) != 0)
+
+#define spin_unlock_wait(__lock)	\
 do {	membar("#LoadLoad");	\
-} while(*((volatile unsigned char *)lock))
+} while(*((volatile unsigned char *)(&(((spinlock_t *)__lock)->lock))))
 
 static __inline__ void _raw_spin_lock(spinlock_t *lock)
 {
@@ -110,17 +118,31 @@ extern int _spin_trylock (spinlock_t *lo
 
 #ifndef CONFIG_DEBUG_SPINLOCK
 
-typedef unsigned int rwlock_t;
-#define RW_LOCK_UNLOCKED	0
-#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
-#define rwlock_is_locked(x) (*(x) != RW_LOCK_UNLOCKED)
+#ifdef CONFIG_LOCKMETER
+typedef struct {
+	unsigned int lock;
+	unsigned int index;
+	unsigned int cpu;
+} rwlock_t;
+#define RW_LOCK_UNLOCKED       (rwlock_t) { 0, 0, 0xff }
+#else
+typedef struct {
+	unsigned int lock;
+} rwlock_t;
+#define RW_LOCK_UNLOCKED        (rwlock_t) { 0 }
+#endif
+
+#define rwlock_init(lp)		do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
+#define rwlock_is_locked(x)	((x)->lock != 0)
 
+extern int __read_trylock(rwlock_t *);
 extern void __read_lock(rwlock_t *);
 extern void __read_unlock(rwlock_t *);
 extern void __write_lock(rwlock_t *);
 extern void __write_unlock(rwlock_t *);
 extern int __write_trylock(rwlock_t *);
 
+#define _raw_read_trylock(p)	__read_trylock(p)
 #define _raw_read_lock(p)	__read_lock(p)
 #define _raw_read_unlock(p)	__read_unlock(p)
 #define _raw_write_lock(p)	__write_lock(p)
--- diff/include/asm-sparc64/unistd.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-sparc64/unistd.h	2004-03-09 11:51:51.000000000 +0000
@@ -447,7 +447,6 @@ asmlinkage unsigned long sys_mmap(
 				unsigned long addr, unsigned long len,
 				unsigned long prot, unsigned long flags,
 				unsigned long fd, unsigned long off);
-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
 struct sigaction;
 asmlinkage long sys_rt_sigaction(int sig,
 				const struct sigaction __user *act,
--- diff/include/asm-um/irq.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-um/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -32,4 +32,9 @@ extern int um_request_irq(unsigned int i
 			  void (*handler)(int, void *, struct pt_regs *),
 			  unsigned long irqflags,  const char * devname,
 			  void *dev_id);
+
+struct irqaction;
+struct pt_regs;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+
 #endif
--- diff/include/asm-um/linkage.h	2002-10-16 04:29:02.000000000 +0100
+++ source/include/asm-um/linkage.h	2004-03-09 11:51:51.000000000 +0000
@@ -2,5 +2,6 @@
 #define __ASM_LINKAGE_H
 
 #define FASTCALL(x)	x __attribute__((regparm(3)))
+#define fastcall        __attribute__((regparm(3)))
 
 #endif
--- diff/include/asm-v850/irq.h	2003-05-21 11:50:16.000000000 +0100
+++ source/include/asm-v850/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -65,4 +65,8 @@ extern void disable_irq_nosync (unsigned
 
 #endif /* !__ASSEMBLY__ */
 
+struct irqaction;
+struct pt_regs;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+
 #endif /* __V850_IRQ_H__ */
--- diff/include/asm-v850/pci.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/asm-v850/pci.h	2004-03-09 11:51:51.000000000 +0000
@@ -27,7 +27,7 @@ extern void pcibios_set_master (struct p
 
 /* `Grant' to PDEV the memory block at CPU_ADDR, for doing DMA.  The
    32-bit PCI bus mastering address to use is returned.  the device owns
-   this memory until either pci_unmap_single or pci_dma_sync_single is
+   this memory until either pci_unmap_single or pci_dma_sync_single_for_cpu is
    performed.  */
 extern dma_addr_t
 pci_map_single (struct pci_dev *pdev, void *cpu_addr, size_t size, int dir);
@@ -44,10 +44,15 @@ pci_unmap_single (struct pci_dev *pdev, 
    If you perform a pci_map_single() but wish to interrogate the
    buffer using the cpu, yet do not wish to teardown the PCI dma
    mapping, you must call this function before doing so.  At the next
-   point you give the PCI dma address back to the card, the device
-   again owns the buffer.  */
+   point you give the PCI dma address back to the card, you must first
+   perform a pci_dma_sync_for_device, and then the device again owns
+   the buffer.  */
 extern void
-pci_dma_sync_single (struct pci_dev *dev, dma_addr_t dma_addr, size_t size,
+pci_dma_sync_single_for_cpu (struct pci_dev *dev, dma_addr_t dma_addr, size_t size,
+		     int dir);
+
+extern void
+pci_dma_sync_single_for_device (struct pci_dev *dev, dma_addr_t dma_addr, size_t size,
 		     int dir);
 
 
--- diff/include/asm-x86_64/acpi.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-x86_64/acpi.h	2004-03-09 11:51:51.000000000 +0000
@@ -60,7 +60,7 @@ __acpi_acquire_global_lock (unsigned int
 	do {
 		old = *lock;
 		new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1));
-		val = cmpxchg4_locked(lock, new, old);
+		val = cmpxchg(lock, old, new);
 	} while (unlikely (val != old));
 	return (new < 3) ? -1 : 0;
 }
@@ -72,7 +72,7 @@ __acpi_release_global_lock (unsigned int
 	do {
 		old = *lock;
 		new = old & ~0x3;
-		val = cmpxchg4_locked(lock, new, old);
+		val = cmpxchg(lock, old, new);
 	} while (unlikely (val != old));
 	return old & 0x1;
 }
@@ -104,6 +104,7 @@ __acpi_release_global_lock (unsigned int
 extern int acpi_lapic;
 extern int acpi_ioapic;
 extern int acpi_noirq;
+extern int acpi_strict;
 
 /* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */
 #define FIX_ACPI_PAGES 4
--- diff/include/asm-x86_64/compat.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-x86_64/compat.h	2004-03-09 11:51:51.000000000 +0000
@@ -29,6 +29,7 @@ typedef s32		compat_daddr_t;
 typedef u32		compat_caddr_t;
 typedef __kernel_fsid_t	compat_fsid_t;
 typedef u32		compat_timer_t;
+typedef s32		compat_key_t;
 
 typedef s32		compat_int_t;
 typedef s32		compat_long_t;
@@ -119,6 +120,64 @@ typedef u32               compat_sigset_
 #define COMPAT_OFF_T_MAX	0x7fffffff
 #define COMPAT_LOFF_T_MAX	0x7fffffffffffffff
 
+struct compat_ipc64_perm {
+	compat_key_t key;
+	compat_uid32_t uid;
+	compat_gid32_t gid;
+	compat_uid32_t cuid;
+	compat_gid32_t cgid;
+	unsigned short mode;
+	unsigned short __pad1;
+	unsigned short seq;
+	unsigned short __pad2;
+	compat_ulong_t unused1;
+	compat_ulong_t unused2;
+};
+
+struct compat_semid64_ds {
+	struct compat_ipc64_perm sem_perm;
+	compat_time_t  sem_otime;
+	compat_ulong_t __unused1;
+	compat_time_t  sem_ctime;
+	compat_ulong_t __unused2;
+	compat_ulong_t sem_nsems;
+	compat_ulong_t __unused3;
+	compat_ulong_t __unused4;
+};
+
+struct compat_msqid64_ds {
+	struct compat_ipc64_perm msg_perm;
+	compat_time_t  msg_stime;
+	compat_ulong_t __unused1;
+	compat_time_t  msg_rtime;
+	compat_ulong_t __unused2;
+	compat_time_t  msg_ctime;
+	compat_ulong_t __unused3;
+	compat_ulong_t msg_cbytes;
+	compat_ulong_t msg_qnum;
+	compat_ulong_t msg_qbytes;
+	compat_pid_t   msg_lspid;
+	compat_pid_t   msg_lrpid;
+	compat_ulong_t __unused4;
+	compat_ulong_t __unused5;
+};
+
+struct compat_shmid64_ds {
+	struct compat_ipc64_perm shm_perm;
+	compat_size_t  shm_segsz;
+	compat_time_t  shm_atime;
+	compat_ulong_t __unused1;
+	compat_time_t  shm_dtime;
+	compat_ulong_t __unused2;
+	compat_time_t  shm_ctime;
+	compat_ulong_t __unused3;
+	compat_pid_t   shm_cpid;
+	compat_pid_t   shm_lpid;
+	compat_ulong_t shm_nattch;
+	compat_ulong_t __unused4;
+	compat_ulong_t __unused5;
+};
+
 /*
  * A pointer passed in from user mode. This should not
  * be used for syscall parameters, just declare them
--- diff/include/asm-x86_64/ia32_unistd.h	2003-09-17 12:28:12.000000000 +0100
+++ source/include/asm-x86_64/ia32_unistd.h	2004-03-09 11:51:51.000000000 +0000
@@ -262,7 +262,7 @@
 #define __NR_ia32_sys_epoll_create	254
 #define __NR_ia32_sys_epoll_ctl	255
 #define __NR_ia32_sys_epoll_wait	256
-#define __NR_ia32_remap_file_pages	257
+#define __NR_ia32_old_remap_file_pages	257
 #define __NR_ia32_set_tid_address	258
 #define __NR_ia32_timer_create		259
 #define __NR_ia32_timer_settime	(__NR_ia32_timer_create+1)
--- diff/include/asm-x86_64/io.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/asm-x86_64/io.h	2004-03-09 11:51:51.000000000 +0000
@@ -109,17 +109,6 @@ __OUTS(l)
 
 #include <linux/vmalloc.h>
 
-/*
- * Temporary debugging check to catch old code using
- * unmapped ISA addresses. Will be removed in 2.4.
- */
-#ifdef CONFIG_IO_DEBUG
-  extern void *__io_virt_debug(unsigned long x, const char *file, int line);
-  #define __io_virt(x) __io_virt_debug((unsigned long)(x), __FILE__, __LINE__)
-#else
-  #define __io_virt(x) ((void *)(x))
-#endif
-
 #ifndef __i386__
 /*
  * Change virtual addresses to physical addresses and vv.
@@ -184,10 +173,10 @@ extern void iounmap(void *addr);
  * memory location directly.
  */
 
-#define readb(addr) (*(volatile unsigned char *) __io_virt(addr))
-#define readw(addr) (*(volatile unsigned short *) __io_virt(addr))
-#define readl(addr) (*(volatile unsigned int *) __io_virt(addr))
-#define readq(addr) (*(volatile unsigned long *) __io_virt(addr))
+#define readb(addr) (*(volatile unsigned char *) (addr))
+#define readw(addr) (*(volatile unsigned short *) (addr))
+#define readl(addr) (*(volatile unsigned int *) (addr))
+#define readq(addr) (*(volatile unsigned long *) (addr))
 #define readb_relaxed(a) readb(a)
 #define readw_relaxed(a) readw(a)
 #define readl_relaxed(a) readl(a)
@@ -197,10 +186,10 @@ extern void iounmap(void *addr);
 #define __raw_readl readl
 #define __raw_readq readq
 
-#define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b))
-#define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b))
-#define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b))
-#define writeq(b,addr) (*(volatile unsigned long *) __io_virt(addr) = (b))
+#define writeb(b,addr) (*(volatile unsigned char *) (addr) = (b))
+#define writew(b,addr) (*(volatile unsigned short *) (addr) = (b))
+#define writel(b,addr) (*(volatile unsigned int *) (addr) = (b))
+#define writeq(b,addr) (*(volatile unsigned long *) (addr) = (b))
 #define __raw_writeb writeb
 #define __raw_writew writew
 #define __raw_writel writel
@@ -208,7 +197,7 @@ extern void iounmap(void *addr);
 
 void *memcpy_fromio(void*,const void*,unsigned); 
 void *memcpy_toio(void*,const void*,unsigned); 
-#define memset_io(a,b,c)	memset(__io_virt(a),(b),(c))
+#define memset_io(a,b,c)	memset((void *)(a),(b),(c))
 
 /*
  * ISA space is 'always mapped' on a typical x86 system, no need to
@@ -235,8 +224,8 @@ void *memcpy_toio(void*,const void*,unsi
  * Again, x86-64 does not require mem IO specific function.
  */
 
-#define eth_io_copy_and_sum(a,b,c,d)		eth_copy_and_sum((a),__io_virt(b),(c),(d))
-#define isa_eth_io_copy_and_sum(a,b,c,d)	eth_copy_and_sum((a),__io_virt(__ISA_IO_base + (b)),(c),(d))
+#define eth_io_copy_and_sum(a,b,c,d)		eth_copy_and_sum((a),(void *)(b),(c),(d))
+#define isa_eth_io_copy_and_sum(a,b,c,d)	eth_copy_and_sum((a),(void *)(__ISA_IO_base + (b)),(c),(d))
 
 /**
  *	check_signature		-	find BIOS signatures
--- diff/include/asm-x86_64/irq.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/asm-x86_64/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -53,4 +53,8 @@ extern int can_request_irq(unsigned int,
 #define ARCH_HAS_NMI_WATCHDOG		/* See include/linux/nmi.h */
 #endif
 
+struct irqaction;
+struct pt_regs;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+
 #endif /* _ASM_IRQ_H */
--- diff/include/asm-x86_64/mman.h	2003-09-30 15:46:20.000000000 +0100
+++ source/include/asm-x86_64/mman.h	2004-03-09 11:51:51.000000000 +0000
@@ -23,6 +23,7 @@
 #define MAP_NORESERVE	0x4000		/* don't check for reservations */
 #define MAP_POPULATE	0x8000		/* populate (prefault) pagetables */
 #define MAP_NONBLOCK	0x10000		/* do not block on IO */
+#define MAP_INHERIT	0x20000		/* inherit the protection bits of the underlying vma*/
 
 #define MS_ASYNC	1		/* sync memory asynchronously */
 #define MS_INVALIDATE	2		/* invalidate the caches */
--- diff/include/asm-x86_64/pci.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-x86_64/pci.h	2004-03-09 11:51:51.000000000 +0000
@@ -78,10 +78,18 @@ extern dma_addr_t swiotlb_map_single (st
 				      int dir);
 extern void swiotlb_unmap_single (struct device *hwdev, dma_addr_t dev_addr,
 				  size_t size, int dir);
-extern void swiotlb_sync_single (struct device *hwdev, dma_addr_t dev_addr, 
-				 size_t size, int dir);
-extern void swiotlb_sync_sg (struct device *hwdev, struct scatterlist *sg, int nelems, 
-			     int dir);
+extern void swiotlb_sync_single_for_cpu (struct device *hwdev,
+					 dma_addr_t dev_addr,
+					 size_t size, int dir);
+extern void swiotlb_sync_single_for_device (struct device *hwdev,
+					    dma_addr_t dev_addr,
+					    size_t size, int dir);
+extern void swiotlb_sync_sg_for_cpu (struct device *hwdev,
+				     struct scatterlist *sg, int nelems,
+				     int dir);
+extern void swiotlb_sync_sg_for_device (struct device *hwdev,
+					struct scatterlist *sg, int nelems,
+					int dir);
 extern int swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg,
 		      int nents, int direction);
 extern void swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg,
@@ -95,7 +103,7 @@ extern void swiotlb_unmap_sg(struct devi
  * The 32-bit bus address to use is returned.
  *
  * Once the device is given the dma address, the device owns this memory
- * until either pci_unmap_single or pci_dma_sync_single is performed.
+ * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed.
  */
 extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, 
 				 int direction);
@@ -125,29 +133,56 @@ void pci_unmap_single(struct pci_dev *hw
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
 	(((PTR)->LEN_NAME) = (VAL))
 
-static inline void pci_dma_sync_single(struct pci_dev *hwdev, 
-				       dma_addr_t dma_handle,
-				       size_t size, int direction)
+static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev,
+					       dma_addr_t dma_handle,
+					       size_t size, int direction)
 {
 	BUG_ON(direction == PCI_DMA_NONE); 
 
 #ifdef CONFIG_SWIOTLB
 	if (swiotlb)
-		return swiotlb_sync_single(&hwdev->dev,dma_handle,size,direction);
+		return swiotlb_sync_single_for_cpu(&hwdev->dev,dma_handle,size,direction);
 #endif
 
 	flush_write_buffers();
 } 
 
-static inline void pci_dma_sync_sg(struct pci_dev *hwdev, 
-				   struct scatterlist *sg,
-				   int nelems, int direction)
+static inline void pci_dma_sync_single_for_device(struct pci_dev *hwdev,
+						  dma_addr_t dma_handle,
+						  size_t size, int direction)
+{
+	BUG_ON(direction == PCI_DMA_NONE);
+
+#ifdef CONFIG_SWIOTLB
+	if (swiotlb)
+		return swiotlb_sync_single_for_device(&hwdev->dev,dma_handle,size,direction);
+#endif
+
+	flush_write_buffers();
+}
+
+static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev,
+					   struct scatterlist *sg,
+					   int nelems, int direction)
+{
+	BUG_ON(direction == PCI_DMA_NONE);
+
+#ifdef CONFIG_SWIOTLB
+	if (swiotlb)
+		return swiotlb_sync_sg_for_cpu(&hwdev->dev,sg,nelems,direction);
+#endif
+	flush_write_buffers();
+}
+
+static inline void pci_dma_sync_sg_for_device(struct pci_dev *hwdev,
+					      struct scatterlist *sg,
+					      int nelems, int direction)
 { 
 	BUG_ON(direction == PCI_DMA_NONE); 
 
 #ifdef CONFIG_SWIOTLB
 	if (swiotlb)
-		return swiotlb_sync_sg(&hwdev->dev,sg,nelems,direction);
+		return swiotlb_sync_sg_for_device(&hwdev->dev,sg,nelems,direction);
 #endif
 	flush_write_buffers();
 } 
@@ -218,12 +253,21 @@ static inline dma_addr_t pci_map_page(st
  * If you perform a pci_map_single() but wish to interrogate the
  * buffer using the cpu, yet do not wish to teardown the PCI dma
  * mapping, you must call this function before doing so.  At the
- * next point you give the PCI dma address back to the card, the
+ * next point you give the PCI dma address back to the card, you
+ * must first perform a pci_dma_sync_for_device, and then the
  * device again owns the buffer.
  */
-static inline void pci_dma_sync_single(struct pci_dev *hwdev,
-				       dma_addr_t dma_handle,
-				       size_t size, int direction)
+static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev,
+					       dma_addr_t dma_handle,
+					       size_t size, int direction)
+{
+	if (direction == PCI_DMA_NONE)
+		out_of_line_bug();
+}
+
+static inline void pci_dma_sync_single_for_device(struct pci_dev *hwdev,
+						  dma_addr_t dma_handle,
+						  size_t size, int direction)
 {
 	if (direction == PCI_DMA_NONE)
 		out_of_line_bug();
@@ -233,12 +277,20 @@ static inline void pci_dma_sync_single(s
 /* Make physical memory consistent for a set of streaming
  * mode DMA translations after a transfer.
  *
- * The same as pci_dma_sync_single but for a scatter-gather list,
+ * The same as pci_dma_sync_single_* but for a scatter-gather list,
  * same rules and usage.
  */
-static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
-				   struct scatterlist *sg,
-				   int nelems, int direction)
+static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev,
+					   struct scatterlist *sg,
+					   int nelems, int direction)
+{
+	if (direction == PCI_DMA_NONE)
+		out_of_line_bug();
+}
+
+static inline void pci_dma_sync_sg_for_device(struct pci_dev *hwdev,
+					      struct scatterlist *sg,
+					      int nelems, int direction)
 {
 	if (direction == PCI_DMA_NONE)
 		out_of_line_bug();
@@ -264,27 +316,32 @@ extern void pci_unmap_sg(struct pci_dev 
  */
 extern int pci_dma_supported(struct pci_dev *hwdev, u64 mask);
 
-static __inline__ dma64_addr_t
+static inline dma64_addr_t
 pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction)
 {
 	return ((dma64_addr_t) page_to_phys(page) +
 		(dma64_addr_t) offset);
 }
 
-static __inline__ struct page *
+static inline struct page *
 pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
 {
 	return virt_to_page(__va(dma_addr)); 	
 }
 
-static __inline__ unsigned long
+static inline unsigned long
 pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
 {
 	return (dma_addr & ~PAGE_MASK);
 }
 
-static __inline__ void
-pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
+static inline void
+pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
+{
+}
+
+static inline void
+pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
 {
 	flush_write_buffers();
 }
--- diff/include/asm-x86_64/pgtable.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-x86_64/pgtable.h	2004-03-09 11:51:51.000000000 +0000
@@ -344,9 +344,19 @@ static inline pgd_t *current_pgd_offset_
 #define pmd_pfn(x)  ((pmd_val(x) >> PAGE_SHIFT) & __PHYSICAL_MASK)
 
 #define pte_to_pgoff(pte) ((pte_val(pte) & PHYSICAL_PAGE_MASK) >> PAGE_SHIFT)
-#define pgoff_to_pte(off) ((pte_t) { ((off) << PAGE_SHIFT) | _PAGE_FILE })
 #define PTE_FILE_MAX_BITS __PHYSICAL_MASK_SHIFT
 
+#define pte_to_pgprot(pte) \
+	__pgprot((pte_val(pte) & (_PAGE_RW | _PAGE_PROTNONE)) \
+		| ((pte_val(pte) & _PAGE_PROTNONE) ? 0 : \
+			(_PAGE_USER | _PAGE_PRESENT)) | _PAGE_ACCESSED)
+
+#define pgoff_prot_to_pte(off, prot) \
+	((pte_t) { _PAGE_FILE + \
+		(pgprot_val(prot) & (_PAGE_RW | _PAGE_PROTNONE)) + \
+			((off) << PAGE_SHIFT) })
+
+
 /* PTE - Level 1 access. */
 
 /* page, protection -> pte */
--- diff/include/asm-x86_64/system.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-x86_64/system.h	2004-03-09 11:51:51.000000000 +0000
@@ -276,13 +276,6 @@ static inline unsigned long __cmpxchg(vo
 	((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
 					(unsigned long)(n),sizeof(*(ptr))))
 
-static inline __u32 cmpxchg4_locked(__u32 *ptr, __u32 old, __u32 new) 
-{
-	asm volatile("lock ; cmpxchgl %k1,%2" :
-		     "=r" (new) : "0" (old), "m" (*(__u32 *)ptr) : "memory");
-	return new; 
-}
-
 #ifdef CONFIG_SMP
 #define smp_mb()	mb()
 #define smp_rmb()	rmb()
--- diff/include/asm-x86_64/unistd.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/asm-x86_64/unistd.h	2004-03-09 11:51:51.000000000 +0000
@@ -490,8 +490,8 @@ __SYSCALL(__NR_epoll_create, sys_epoll_c
 __SYSCALL(__NR_epoll_ctl_old, sys_ni_syscall)
 #define __NR_epoll_wait_old	215
 __SYSCALL(__NR_epoll_wait_old, sys_ni_syscall)
-#define __NR_remap_file_pages	216
-__SYSCALL(__NR_remap_file_pages, sys_remap_file_pages)
+#define __NR_old_remap_file_pages	216
+__SYSCALL(__NR_old_remap_file_pages, old_remap_file_pages)
 #define __NR_getdents64	217
 __SYSCALL(__NR_getdents64, sys_getdents64)
 #define __NR_set_tid_address	218
--- diff/include/linux/acpi.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/acpi.h	2004-03-09 11:51:51.000000000 +0000
@@ -233,8 +233,27 @@ struct acpi_table_hpet {
 } __attribute__ ((packed));
 
 /*
+ * Simple Boot Flags
+ * http://www.microsoft.com/whdc/hwdev/resources/specs/simp_bios.mspx
+ */
+struct acpi_table_sbf
+{
+	u8 sbf_signature[4];
+	u32 sbf_len;
+	u8 sbf_revision;
+	u8 sbf_csum;
+	u8 sbf_oemid[6];
+	u8 sbf_oemtable[8];
+	u8 sbf_revdata[4];
+	u8 sbf_creator[4];
+	u8 sbf_crearev[4];
+	u8 sbf_cmos;
+	u8 sbf_spare[3];
+} __attribute__ ((packed));
+
+/*
  * System Resource Affinity Table (SRAT)
- *   see http://www.microsoft.com/hwdev/design/srat.htm
+ * http://www.microsoft.com/whdc/hwdev/platform/proc/SRAT.mspx
  */
 
 struct acpi_table_srat {
@@ -317,6 +336,15 @@ struct acpi_table_ecdt {
 	char				ec_id[0];
 } __attribute__ ((packed));
 
+/* PCI MMCONFIG */
+
+struct acpi_table_mcfg {
+	struct acpi_table_header	header;
+	u8				reserved[8];
+	u32				base_address;
+	u32				base_reserved;
+} __attribute__ ((packed));
+
 /* Table Handlers */
 
 enum acpi_table_id {
@@ -338,6 +366,7 @@ enum acpi_table_id {
 	ACPI_SSDT,
 	ACPI_SPMI,
 	ACPI_HPET,
+	ACPI_MCFG,
 	ACPI_TABLE_COUNT
 };
 
@@ -369,6 +398,10 @@ void acpi_numa_arch_fixup(void);
 
 extern int acpi_mp_config;
 
+extern u32 pci_mmcfg_base_addr;
+
+extern int sbf_port ;
+
 #else	/*!CONFIG_ACPI_BOOT*/
 
 #define acpi_mp_config	0
--- diff/include/linux/backing-dev.h	2003-05-21 11:49:56.000000000 +0100
+++ source/include/linux/backing-dev.h	2004-03-09 11:51:51.000000000 +0000
@@ -20,10 +20,14 @@ enum bdi_state {
 	BDI_unused,		/* Available bits start here */
 };
 
+typedef int (congested_fn)(void *, int);
+
 struct backing_dev_info {
 	unsigned long ra_pages;	/* max readahead in PAGE_CACHE_SIZE units */
 	unsigned long state;	/* Always use atomic bitops on this */
 	int memory_backed;	/* Cannot clean pages with writepage */
+	congested_fn *congested_fn; /* Function pointer if device is md/dm */
+	void *congested_data;	/* Pointer to aux data for congested func */
 };
 
 extern struct backing_dev_info default_backing_dev_info;
@@ -32,14 +36,27 @@ int writeback_acquire(struct backing_dev
 int writeback_in_progress(struct backing_dev_info *bdi);
 void writeback_release(struct backing_dev_info *bdi);
 
+static inline int bdi_congested(struct backing_dev_info *bdi, int bdi_bits)
+{
+	if (bdi->congested_fn)
+		return bdi->congested_fn(bdi->congested_data, bdi_bits);
+	return (bdi->state & bdi_bits);
+}
+
 static inline int bdi_read_congested(struct backing_dev_info *bdi)
 {
-	return test_bit(BDI_read_congested, &bdi->state);
+	return bdi_congested(bdi, 1 << BDI_read_congested);
 }
 
 static inline int bdi_write_congested(struct backing_dev_info *bdi)
 {
-	return test_bit(BDI_write_congested, &bdi->state);
+	return bdi_congested(bdi, 1 << BDI_write_congested);
+}
+
+static inline int bdi_rw_congested(struct backing_dev_info *bdi)
+{
+	return bdi_congested(bdi, (1 << BDI_read_congested)|
+				  (1 << BDI_write_congested));
 }
 
 #endif		/* _LINUX_BACKING_DEV_H */
--- diff/include/linux/binfmts.h	2003-08-20 14:16:34.000000000 +0100
+++ source/include/linux/binfmts.h	2004-03-09 11:51:51.000000000 +0000
@@ -35,9 +35,13 @@ struct linux_binprm{
 	char * interp;		/* Name of the binary really executed. Most
 				   of the time same as filename, but could be
 				   different for binfmt_{misc,script} */
+	unsigned long interp_flags;
 	unsigned long loader, exec;
 };
 
+#define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0
+#define BINPRM_FLAGS_ENFORCE_NONDUMP (1 << BINPRM_FLAGS_ENFORCE_NONDUMP_BIT)
+
 /*
  * This structure defines the functions that are used to load the binary formats that
  * linux accepts.
--- diff/include/linux/blkdev.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/blkdev.h	2004-03-09 11:51:51.000000000 +0000
@@ -372,6 +372,8 @@ struct request_queue
 
 #define blk_queue_plugged(q)	!list_empty(&(q)->plug_list)
 #define blk_queue_tagged(q)	test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags)
+#define blk_queue_stopped(q)	test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags)
+
 #define blk_fs_request(rq)	((rq)->flags & REQ_CMD)
 #define blk_pc_request(rq)	((rq)->flags & REQ_BLOCK_PC)
 #define blk_noretry_request(rq)	((rq)->flags & REQ_FAILFAST)
@@ -514,6 +516,9 @@ extern void blk_stop_queue(request_queue
 extern void __blk_stop_queue(request_queue_t *q);
 extern void blk_run_queue(request_queue_t *q);
 extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *);
+extern struct request *blk_rq_map_user(request_queue_t *, int, void __user *, unsigned int);
+extern int blk_rq_unmap_user(struct request *, void __user *, unsigned int, int);
+extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *);
 
 static inline request_queue_t *bdev_get_queue(struct block_device *bdev)
 {
@@ -586,7 +591,7 @@ extern int blk_queue_init_tags(request_q
 extern void blk_queue_free_tags(request_queue_t *);
 extern int blk_queue_resize_tags(request_queue_t *, int);
 extern void blk_queue_invalidate_tags(request_queue_t *);
-extern void blk_congestion_wait(int rw, long timeout);
+extern long blk_congestion_wait(int rw, long timeout);
 
 extern void blk_rq_bio_prep(request_queue_t *, struct request *, struct bio *);
 extern void blk_rq_prep_restart(struct request *);
--- diff/include/linux/cdrom.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/cdrom.h	2004-03-09 11:51:51.000000000 +0000
@@ -877,10 +877,15 @@ struct mode_page_header {
 #include <linux/fs.h>		/* not really needed, later.. */
 #include <linux/device.h>
 
+#define CDDA_OLD		0	/* old style */
+#define CDDA_BPC_SINGLE		1	/* block_pc, but single frame  */
+#define CDDA_BPC_FULL		2	/* full speed block pc */
+
 /* Uniform cdrom data structures for cdrom.c */
 struct cdrom_device_info {
 	struct cdrom_device_ops  *ops;  /* link to device_ops */
 	struct cdrom_device_info *next; /* next device_info for this major */
+	struct gendisk *disk;		/* matching block layer disk */
 	void *handle;		        /* driver-dependent data */
 /* specifications */
 	int mask;                       /* mask of capability: disables them */
@@ -894,6 +899,7 @@ struct cdrom_device_info {
 /* per-device flags */
         __u8 sanyo_slot		: 2;	/* Sanyo 3 CD changer support */
         __u8 reserved		: 6;	/* not used yet */
+	int cdda_method;		/* see flags */
 	int for_data;
 	int (*exit)(struct cdrom_device_info *);
 	int mrw_mode_page;
--- diff/include/linux/compat.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/compat.h	2004-03-09 11:51:51.000000000 +0000
@@ -6,15 +6,27 @@
  */
 #include <linux/config.h>
 
-#ifdef CONFIG_COMPAT
+#ifndef CONFIG_COMPAT
+
+/* Non-native task requiring compat... doesn't exist */
+#define is_compat_task(x) 0
+
+#else
 
 #include <linux/stat.h>
 #include <linux/param.h>	/* for HZ */
+#include <linux/sem.h>
+#include <linux/personality.h>  /* Conditional process compat */
 #include <asm/compat.h>
 
 #define compat_jiffies_to_clock_t(x)	\
 		(((unsigned long)(x) * COMPAT_USER_HZ) / HZ)
 
+/* Non-native task requiring compat */
+#ifndef HAVE_ARCH_IS_COMPAT_TASK
+#define is_compat_task(x) (x->personality == PER_LINUX32)
+#endif
+
 struct compat_itimerspec { 
 	struct compat_timespec it_interval;
 	struct compat_timespec it_value;
@@ -45,7 +57,7 @@ typedef struct {
 
 extern int cp_compat_stat(struct kstat *, struct compat_stat *);
 extern int get_compat_timespec(struct timespec *, const struct compat_timespec *);
-extern int put_compat_timespec(struct timespec *, const struct compat_timespec *);
+extern int put_compat_timespec(const struct timespec *, struct compat_timespec *);
 
 struct compat_iovec {
 	compat_uptr_t	iov_base;
@@ -83,10 +95,15 @@ struct compat_dirent {
 	char		d_name[256];
 };
 
-typedef union compat_sigval {
-	compat_int_t	sival_int;
-	compat_uptr_t	sival_ptr;
-} compat_sigval_t;
-
+long compat_sys_semctl(int first, int second, int third, void __user *uptr);
+long compat_sys_msgsnd(int first, int second, int third, void __user *uptr);
+long compat_sys_msgrcv(int first, int second, int msgtyp, int third,
+		int version, void __user *uptr);
+long compat_sys_msgctl(int first, int second, void __user *uptr);
+long compat_sys_shmat(int first, int second, compat_uptr_t third, int version,
+		void __user *uptr);
+long compat_sys_shmctl(int first, int second, void __user *uptr);
+long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
+		unsigned nsems, const struct compat_timespec __user *timeout);
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */
--- diff/include/linux/compat_ioctl.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/compat_ioctl.h	2004-03-09 11:51:51.000000000 +0000
@@ -122,7 +122,6 @@ COMPATIBLE_IOCTL(STOP_ARRAY)
 COMPATIBLE_IOCTL(STOP_ARRAY_RO)
 COMPATIBLE_IOCTL(RESTART_ARRAY_RW)
 /* DM */
-#ifdef CONFIG_DM_IOCTL_V4
 COMPATIBLE_IOCTL(DM_VERSION)
 COMPATIBLE_IOCTL(DM_LIST_DEVICES)
 COMPATIBLE_IOCTL(DM_DEV_CREATE)
@@ -135,19 +134,7 @@ COMPATIBLE_IOCTL(DM_TABLE_LOAD)
 COMPATIBLE_IOCTL(DM_TABLE_CLEAR)
 COMPATIBLE_IOCTL(DM_TABLE_DEPS)
 COMPATIBLE_IOCTL(DM_TABLE_STATUS)
-#else
-COMPATIBLE_IOCTL(DM_VERSION)
-COMPATIBLE_IOCTL(DM_REMOVE_ALL)
-COMPATIBLE_IOCTL(DM_DEV_CREATE)
-COMPATIBLE_IOCTL(DM_DEV_REMOVE)
-COMPATIBLE_IOCTL(DM_DEV_RELOAD)
-COMPATIBLE_IOCTL(DM_DEV_SUSPEND)
-COMPATIBLE_IOCTL(DM_DEV_RENAME)
-COMPATIBLE_IOCTL(DM_DEV_DEPS)
-COMPATIBLE_IOCTL(DM_DEV_STATUS)
-COMPATIBLE_IOCTL(DM_TARGET_STATUS)
-COMPATIBLE_IOCTL(DM_TARGET_WAIT)
-#endif
+COMPATIBLE_IOCTL(DM_LIST_VERSIONS)
 /* Big K */
 COMPATIBLE_IOCTL(PIO_FONT)
 COMPATIBLE_IOCTL(GIO_FONT)
--- diff/include/linux/compiler-gcc.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/linux/compiler-gcc.h	2004-03-09 11:51:51.000000000 +0000
@@ -13,5 +13,5 @@
    shouldn't recognize the original var, and make assumptions about it */
 #define RELOC_HIDE(ptr, off)					\
   ({ unsigned long __ptr;					\
-    __asm__ ("" : "=g"(__ptr) : "0"(ptr));		\
+	__asm__ ("" : "=r"(__ptr) : "0"(ptr));			\
     (typeof(ptr)) (__ptr + (off)); })
--- diff/include/linux/compiler-gcc3.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/compiler-gcc3.h	2004-03-09 11:51:51.000000000 +0000
@@ -3,7 +3,7 @@
 /* These definitions are for GCC v3.x.  */
 #include <linux/compiler-gcc.h>
 
-#if __GNUC_MINOR__ >= 1
+#if __GNUC_MINOR__ >= 1  && __GNUC_MINOR__ < 4
 # define inline		__inline__ __attribute__((always_inline))
 # define __inline__	__inline__ __attribute__((always_inline))
 # define __inline	__inline__ __attribute__((always_inline))
--- diff/include/linux/compiler.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/compiler.h	2004-03-09 11:51:51.000000000 +0000
@@ -39,6 +39,20 @@
 #define likely(x)	__builtin_expect(!!(x), 1)
 #define unlikely(x)	__builtin_expect(!!(x), 0)
 
+/* Optimization barrier */
+#ifndef barrier
+# define barrier() __memory_barrier()
+#endif
+
+#ifndef RELOC_HIDE
+# define RELOC_HIDE(ptr, off)					\
+  ({ unsigned long __ptr;					\
+     __ptr = (unsigned long) (ptr);				\
+    (typeof(ptr)) (__ptr + (off)); })
+#endif
+
+#endif /* __KERNEL__ */
+
 /*
  * Allow us to mark functions as 'deprecated' and have gcc emit a nice
  * warning for each use, in hopes of speeding the functions removal.
@@ -100,18 +114,4 @@
 #define noinline
 #endif
 
-/* Optimization barrier */
-#ifndef barrier
-# define barrier() __memory_barrier()
-#endif
-
-#ifndef RELOC_HIDE
-# define RELOC_HIDE(ptr, off)					\
-  ({ unsigned long __ptr;					\
-     __ptr = (unsigned long) (ptr);				\
-    (typeof(ptr)) (__ptr + (off)); })
-#endif
-
-#endif /* __KERNEL__ */
-
 #endif /* __LINUX_COMPILER_H */
--- diff/include/linux/config.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/linux/config.h	2004-03-09 11:51:51.000000000 +0000
@@ -2,5 +2,8 @@
 #define _LINUX_CONFIG_H
 
 #include <linux/autoconf.h>
+#ifdef CONFIG_X86
+#include <asm/kgdb.h>
+#endif
 
 #endif
--- diff/include/linux/cpu.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/cpu.h	2004-03-09 11:51:51.000000000 +0000
@@ -21,6 +21,8 @@
 
 #include <linux/sysdev.h>
 #include <linux/node.h>
+#include <linux/compiler.h>
+#include <linux/cpumask.h>
 #include <asm/semaphore.h>
 
 struct cpu {
@@ -56,9 +58,21 @@ extern struct sysdev_class cpu_sysdev_cl
 extern struct semaphore cpucontrol;
 #define lock_cpu_hotplug()	down(&cpucontrol)
 #define unlock_cpu_hotplug()	up(&cpucontrol)
+#define lock_cpu_hotplug_interruptible() down_interruptible(&cpucontrol)
+int cpu_down(unsigned int cpu);
+#define hotcpu_notifier(fn, pri) {				\
+	static struct notifier_block fn##_nb = { fn, pri };	\
+	register_cpu_notifier(&fn##_nb);			\
+}
+#define cpu_is_offline(cpu) unlikely(!cpu_online(cpu))
 #else
 #define lock_cpu_hotplug()	do { } while (0)
 #define unlock_cpu_hotplug()	do { } while (0)
+#define lock_cpu_hotplug_interruptible() 0
+#define hotcpu_notifier(fn, pri)
+
+/* CPUs don't go offline once they're online w/o CONFIG_HOTPLUG_CPU */
+#define cpu_is_offline(cpu) 0
 #endif
 
 #endif /* _LINUX_CPU_H_ */
--- diff/include/linux/cpumask.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/cpumask.h	2004-03-09 11:51:51.000000000 +0000
@@ -12,6 +12,7 @@ extern cpumask_t cpu_online_map;
 extern cpumask_t cpu_possible_map;
 
 #define num_online_cpus()		cpus_weight(cpu_online_map)
+#define num_possible_cpus()		cpus_weight(cpu_possible_map)
 #define cpu_online(cpu)			cpu_isset(cpu, cpu_online_map)
 #define cpu_possible(cpu)		cpu_isset(cpu, cpu_possible_map)
 
@@ -24,7 +25,9 @@ extern cpumask_t cpu_possible_map;
 #define for_each_online_cpu(cpu) for_each_cpu_mask(cpu, cpu_online_map)
 #else
 #define	cpu_online_map			cpumask_of_cpu(0)
+#define	cpu_possible_map		cpumask_of_cpu(0)
 #define num_online_cpus()		1
+#define num_possible_cpus()		1
 #define cpu_online(cpu)			({ BUG_ON((cpu) != 0); 1; })
 #define cpu_possible(cpu)		({ BUG_ON((cpu) != 0); 1; })
 
--- diff/include/linux/device-mapper.h	2003-06-30 10:07:24.000000000 +0100
+++ source/include/linux/device-mapper.h	2004-03-09 11:51:51.000000000 +0000
@@ -13,6 +13,11 @@ struct dm_dev;
 
 typedef enum { STATUSTYPE_INFO, STATUSTYPE_TABLE } status_type_t;
 
+union map_info {
+	void *ptr;
+	unsigned long long ll;
+};
+
 /*
  * In the constructor the target parameter will already have the
  * table, type, begin and len fields filled in.
@@ -32,7 +37,19 @@ typedef void (*dm_dtr_fn) (struct dm_tar
  * = 0: The target will handle the io by resubmitting it later
  * > 0: simple remap complete
  */
-typedef int (*dm_map_fn) (struct dm_target *ti, struct bio *bio);
+typedef int (*dm_map_fn) (struct dm_target *ti, struct bio *bio,
+			  union map_info *map_context);
+
+/*
+ * Returns:
+ * < 0 : error (currently ignored)
+ * 0   : ended successfully
+ * 1   : for some reason the io has still not completed (eg,
+ *       multipath target might want to requeue a failed io).
+ */
+typedef int (*dm_endio_fn) (struct dm_target *ti,
+			    struct bio *bio, int error,
+			    union map_info *map_context);
 
 typedef void (*dm_suspend_fn) (struct dm_target *ti);
 typedef void (*dm_resume_fn) (struct dm_target *ti);
@@ -57,9 +74,11 @@ void dm_put_device(struct dm_target *ti,
 struct target_type {
 	const char *name;
 	struct module *module;
+        unsigned version[3];
 	dm_ctr_fn ctr;
 	dm_dtr_fn dtr;
 	dm_map_fn map;
+	dm_endio_fn end_io;
 	dm_suspend_fn suspend;
 	dm_resume_fn resume;
 	dm_status_fn status;
@@ -86,7 +105,7 @@ struct dm_target {
 	sector_t split_io;
 
 	/*
-	 * These are automaticall filled in by
+	 * These are automatically filled in by
 	 * dm_table_get_device.
 	 */
 	struct io_restrictions limits;
--- diff/include/linux/device.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/device.h	2004-03-09 11:51:51.000000000 +0000
@@ -285,6 +285,12 @@ struct device {
 					   detached from its driver. */
 
 	u64		*dma_mask;	/* dma mask (if dma'able device) */
+	u64		coherent_dma_mask;/* Like dma_mask, but for
+					     alloc_coherent mappings as
+					     not all hardware supports
+					     64 bit addresses for consistent
+					     allocations such descriptors. */
+
 	struct list_head	dma_pools;	/* dma pools (if dma'ble) */
 
 	void	(*release)(struct device * dev);
--- diff/include/linux/dm-ioctl.h	2003-08-20 14:16:14.000000000 +0100
+++ source/include/linux/dm-ioctl.h	2004-03-09 11:51:51.000000000 +0000
@@ -1,18 +1,252 @@
 /*
- * Copyright (C) 2003 Sistina Software (UK) Limited.
+ * Copyright (C) 2001 - 2003 Sistina Software (UK) Limited.
  *
  * This file is released under the LGPL.
  */
 
-#ifndef _LINUX_DM_IOCTL_H
-#define _LINUX_DM_IOCTL_H
+#ifndef _LINUX_DM_IOCTL_V4_H
+#define _LINUX_DM_IOCTL_V4_H
 
-#include <linux/config.h>
+#include <linux/types.h>
 
-#ifdef CONFIG_DM_IOCTL_V4
-#include "dm-ioctl-v4.h"
-#else
-#include "dm-ioctl-v1.h"
-#endif
+#define DM_DIR "mapper"		/* Slashes not supported */
+#define DM_MAX_TYPE_NAME 16
+#define DM_NAME_LEN 128
+#define DM_UUID_LEN 129
 
-#endif
+/*
+ * A traditional ioctl interface for the device mapper.
+ *
+ * Each device can have two tables associated with it, an
+ * 'active' table which is the one currently used by io passing
+ * through the device, and an 'inactive' one which is a table
+ * that is being prepared as a replacement for the 'active' one.
+ *
+ * DM_VERSION:
+ * Just get the version information for the ioctl interface.
+ *
+ * DM_REMOVE_ALL:
+ * Remove all dm devices, destroy all tables.  Only really used
+ * for debug.
+ *
+ * DM_LIST_DEVICES:
+ * Get a list of all the dm device names.
+ *
+ * DM_DEV_CREATE:
+ * Create a new device, neither the 'active' or 'inactive' table
+ * slots will be filled.  The device will be in suspended state
+ * after creation, however any io to the device will get errored
+ * since it will be out-of-bounds.
+ *
+ * DM_DEV_REMOVE:
+ * Remove a device, destroy any tables.
+ *
+ * DM_DEV_RENAME:
+ * Rename a device.
+ *
+ * DM_SUSPEND:
+ * This performs both suspend and resume, depending which flag is
+ * passed in.
+ * Suspend: This command will not return until all pending io to
+ * the device has completed.  Further io will be deferred until
+ * the device is resumed.
+ * Resume: It is no longer an error to issue this command on an
+ * unsuspended device.  If a table is present in the 'inactive'
+ * slot, it will be moved to the active slot, then the old table
+ * from the active slot will be _destroyed_.  Finally the device
+ * is resumed.
+ *
+ * DM_DEV_STATUS:
+ * Retrieves the status for the table in the 'active' slot.
+ *
+ * DM_DEV_WAIT:
+ * Wait for a significant event to occur to the device.  This
+ * could either be caused by an event triggered by one of the
+ * targets of the table in the 'active' slot, or a table change.
+ *
+ * DM_TABLE_LOAD:
+ * Load a table into the 'inactive' slot for the device.  The
+ * device does _not_ need to be suspended prior to this command.
+ *
+ * DM_TABLE_CLEAR:
+ * Destroy any table in the 'inactive' slot (ie. abort).
+ *
+ * DM_TABLE_DEPS:
+ * Return a set of device dependencies for the 'active' table.
+ *
+ * DM_TABLE_STATUS:
+ * Return the targets status for the 'active' table.
+ */
+
+/*
+ * All ioctl arguments consist of a single chunk of memory, with
+ * this structure at the start.  If a uuid is specified any
+ * lookup (eg. for a DM_INFO) will be done on that, *not* the
+ * name.
+ */
+struct dm_ioctl {
+	/*
+	 * The version number is made up of three parts:
+	 * major - no backward or forward compatibility,
+	 * minor - only backwards compatible,
+	 * patch - both backwards and forwards compatible.
+	 *
+	 * All clients of the ioctl interface should fill in the
+	 * version number of the interface that they were
+	 * compiled with.
+	 *
+	 * All recognised ioctl commands (ie. those that don't
+	 * return -ENOTTY) fill out this field, even if the
+	 * command failed.
+	 */
+	uint32_t version[3];	/* in/out */
+	uint32_t data_size;	/* total size of data passed in
+				 * including this struct */
+
+	uint32_t data_start;	/* offset to start of data
+				 * relative to start of this struct */
+
+	uint32_t target_count;	/* in/out */
+	int32_t open_count;	/* out */
+	uint32_t flags;		/* in/out */
+	uint32_t event_nr;      	/* in/out */
+	uint32_t padding;
+
+	uint64_t dev;		/* in/out */
+
+	char name[DM_NAME_LEN];	/* device name */
+	char uuid[DM_UUID_LEN];	/* unique identifier for
+				 * the block device */
+};
+
+/*
+ * Used to specify tables.  These structures appear after the
+ * dm_ioctl.
+ */
+struct dm_target_spec {
+	uint64_t sector_start;
+	uint64_t length;
+	int32_t status;		/* used when reading from kernel only */
+
+	/*
+	 * Offset in bytes (from the start of this struct) to
+	 * next target_spec.
+	 */
+	uint32_t next;
+
+	char target_type[DM_MAX_TYPE_NAME];
+
+	/*
+	 * Parameter string starts immediately after this object.
+	 * Be careful to add padding after string to ensure correct
+	 * alignment of subsequent dm_target_spec.
+	 */
+};
+
+/*
+ * Used to retrieve the target dependencies.
+ */
+struct dm_target_deps {
+	uint32_t count;	/* Array size */
+	uint32_t padding;	/* unused */
+	uint64_t dev[0];	/* out */
+};
+
+/*
+ * Used to get a list of all dm devices.
+ */
+struct dm_name_list {
+	uint64_t dev;
+	uint32_t next;		/* offset to the next record from
+				   the _start_ of this */
+	char name[0];
+};
+
+/*
+ * Used to retrieve the target versions
+ */
+struct dm_target_versions {
+        uint32_t next;
+        uint32_t version[3];
+
+        char name[0];
+};
+
+/*
+ * If you change this make sure you make the corresponding change
+ * to dm-ioctl.c:lookup_ioctl()
+ */
+enum {
+	/* Top level cmds */
+	DM_VERSION_CMD = 0,
+	DM_REMOVE_ALL_CMD,
+	DM_LIST_DEVICES_CMD,
+
+	/* device level cmds */
+	DM_DEV_CREATE_CMD,
+	DM_DEV_REMOVE_CMD,
+	DM_DEV_RENAME_CMD,
+	DM_DEV_SUSPEND_CMD,
+	DM_DEV_STATUS_CMD,
+	DM_DEV_WAIT_CMD,
+
+	/* Table level cmds */
+	DM_TABLE_LOAD_CMD,
+	DM_TABLE_CLEAR_CMD,
+	DM_TABLE_DEPS_CMD,
+	DM_TABLE_STATUS_CMD,
+
+	/* Added later */
+	DM_LIST_VERSIONS_CMD,
+};
+
+#define DM_IOCTL 0xfd
+
+#define DM_VERSION       _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl)
+#define DM_REMOVE_ALL    _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl)
+#define DM_LIST_DEVICES  _IOWR(DM_IOCTL, DM_LIST_DEVICES_CMD, struct dm_ioctl)
+
+#define DM_DEV_CREATE    _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl)
+#define DM_DEV_REMOVE    _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl)
+#define DM_DEV_RENAME    _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl)
+#define DM_DEV_SUSPEND   _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl)
+#define DM_DEV_STATUS    _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl)
+#define DM_DEV_WAIT      _IOWR(DM_IOCTL, DM_DEV_WAIT_CMD, struct dm_ioctl)
+
+#define DM_TABLE_LOAD    _IOWR(DM_IOCTL, DM_TABLE_LOAD_CMD, struct dm_ioctl)
+#define DM_TABLE_CLEAR   _IOWR(DM_IOCTL, DM_TABLE_CLEAR_CMD, struct dm_ioctl)
+#define DM_TABLE_DEPS    _IOWR(DM_IOCTL, DM_TABLE_DEPS_CMD, struct dm_ioctl)
+#define DM_TABLE_STATUS  _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, struct dm_ioctl)
+
+#define DM_LIST_VERSIONS _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, struct dm_ioctl)
+
+#define DM_VERSION_MAJOR	4
+#define DM_VERSION_MINOR	1
+#define DM_VERSION_PATCHLEVEL	0
+#define DM_VERSION_EXTRA	"-ioctl (2003-12-10)"
+
+/* Status bits */
+#define DM_READONLY_FLAG	(1 << 0) /* In/Out */
+#define DM_SUSPEND_FLAG		(1 << 1) /* In/Out */
+#define DM_PERSISTENT_DEV_FLAG	(1 << 3) /* In */
+
+/*
+ * Flag passed into ioctl STATUS command to get table information
+ * rather than current status.
+ */
+#define DM_STATUS_TABLE_FLAG	(1 << 4) /* In */
+
+/*
+ * Flags that indicate whether a table is present in either of
+ * the two table slots that a device has.
+ */
+#define DM_ACTIVE_PRESENT_FLAG   (1 << 5) /* Out */
+#define DM_INACTIVE_PRESENT_FLAG (1 << 6) /* Out */
+
+/*
+ * Indicates that the buffer passed in wasn't big enough for the
+ * results.
+ */
+#define DM_BUFFER_FULL_FLAG	(1 << 8) /* Out */
+
+#endif				/* _LINUX_DM_IOCTL_H */
--- diff/include/linux/dma-mapping.h	2002-12-30 10:17:13.000000000 +0000
+++ source/include/linux/dma-mapping.h	2004-03-09 11:51:51.000000000 +0000
@@ -12,6 +12,10 @@ enum dma_data_direction {
 
 #include <asm/dma-mapping.h>
 
+/* Backwards compat, remove in 2.7.x */
+#define dma_sync_single		dma_sync_single_for_cpu
+#define dma_sync_sg		dma_sync_sg_for_cpu
+
 #endif
 
 
--- diff/include/linux/elevator.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/elevator.h	2004-03-09 11:51:51.000000000 +0000
@@ -94,6 +94,11 @@ extern elevator_t iosched_deadline;
  */
 extern elevator_t iosched_as;
 
+/*
+ * completely fair queueing I/O scheduler
+ */
+extern elevator_t iosched_cfq;
+
 extern int elevator_init(request_queue_t *, elevator_t *);
 extern void elevator_exit(request_queue_t *);
 extern int elv_rq_merge_ok(struct request *, struct bio *);
--- diff/include/linux/ext3_fs_sb.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/ext3_fs_sb.h	2004-03-09 11:51:51.000000000 +0000
@@ -69,6 +69,10 @@ struct ext3_sb_info {
 	struct timer_list turn_ro_timer;	/* For turning read-only (crash simulation) */
 	wait_queue_head_t ro_wait_queue;	/* For people waiting for the fs to go read-only */
 #endif
+#ifdef CONFIG_QUOTA
+	char *s_qf_names[MAXQUOTAS];		/* Names of quota files with journalled quota */
+	int s_jquota_fmt;			/* Format of quota to use */
+#endif
 };
 
 #endif	/* _LINUX_EXT3_FS_SB */
--- diff/include/linux/ext3_jbd.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/ext3_jbd.h	2004-03-09 11:51:51.000000000 +0000
@@ -42,8 +42,9 @@
  * superblock only gets updated once, of course, so don't bother
  * counting that again for the quota updates. */
 
-#define EXT3_DATA_TRANS_BLOCKS		(3 * EXT3_SINGLEDATA_TRANS_BLOCKS + \
-					 EXT3_XATTR_TRANS_BLOCKS - 2)
+#define EXT3_DATA_TRANS_BLOCKS		(EXT3_SINGLEDATA_TRANS_BLOCKS + \
+					 EXT3_XATTR_TRANS_BLOCKS - 2 + \
+					 2*EXT3_QUOTA_TRANS_BLOCKS)
 
 extern int ext3_writepage_trans_blocks(struct inode *inode);
 
@@ -72,6 +73,19 @@ extern int ext3_writepage_trans_blocks(s
 
 #define EXT3_INDEX_EXTRA_TRANS_BLOCKS	8
 
+#ifdef CONFIG_QUOTA
+/* Amount of blocks needed for quota update - we know that the structure was
+ * allocated so we need to update only inode+data */
+#define EXT3_QUOTA_TRANS_BLOCKS 2
+/* Amount of blocks needed for quota insert/delete - we do some block writes
+ * but inode, sb and group updates are done only once */
+#define EXT3_QUOTA_INIT_BLOCKS (DQUOT_MAX_WRITES*\
+				(EXT3_SINGLEDATA_TRANS_BLOCKS-3)+3)
+#else
+#define EXT3_QUOTA_TRANS_BLOCKS 0
+#define EXT3_QUOTA_INIT_BLOCKS 0
+#endif
+
 int
 ext3_mark_iloc_dirty(handle_t *handle, 
 		     struct inode *inode,
--- diff/include/linux/fs.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/fs.h	2004-03-09 11:51:51.000000000 +0000
@@ -89,6 +89,7 @@ extern int leases_enable, dir_notify_ena
 
 /* public flags for file_system_type */
 #define FS_REQUIRES_DEV 1 
+#define FS_BINARY_MOUNTDATA 2
 #define FS_REVAL_DOT	16384	/* Check the paths ".", ".." for staleness */
 #define FS_ODD_RENAME	32768	/* Temporary stuff; will go away as soon
 				  * as nfs_rename() will be cleaned up
@@ -137,6 +138,7 @@ extern int leases_enable, dir_notify_ena
 #define S_DEAD		32	/* removed, but still open directory */
 #define S_NOQUOTA	64	/* Inode is not counted to quota */
 #define S_DIRSYNC	128	/* Directory modifications are synchronous */
+#define S_NOCMTIME	256	/* Do not update file c/mtime */
 
 /*
  * Note that nosuid etc flags are inode-specific: setting some file-system
@@ -170,6 +172,7 @@ extern int leases_enable, dir_notify_ena
 #define IS_ONE_SECOND(inode)	__IS_FLG(inode, MS_ONE_SECOND)
 
 #define IS_DEADDIR(inode)	((inode)->i_flags & S_DEAD)
+#define IS_NOCMTIME(inode)	((inode)->i_flags & S_NOCMTIME)
 
 /* the read-only stuff doesn't really belong here, but any other place is
    probably as bad and I don't want to create yet another include file. */
@@ -336,6 +339,7 @@ struct address_space {
 	spinlock_t		private_lock;	/* for use by the address_space */
 	struct list_head	private_list;	/* ditto */
 	struct address_space	*assoc_mapping;	/* ditto */
+	struct rw_semaphore	wb_rwsema;	/* serialize SYNC writebacks */
 };
 
 struct block_device {
@@ -376,6 +380,7 @@ struct block_device {
 struct inode {
 	struct hlist_node	i_hash;
 	struct list_head	i_list;
+	struct list_head	i_sb_list;
 	struct list_head	i_dentry;
 	unsigned long		i_ino;
 	atomic_t		i_count;
@@ -395,6 +400,7 @@ struct inode {
 	unsigned short          i_bytes;
 	spinlock_t		i_lock;	/* i_blocks, i_bytes, maybe i_size */
 	struct semaphore	i_sem;
+	struct rw_semaphore	i_alloc_sem;
 	struct inode_operations	*i_op;
 	struct file_operations	*i_fop;	/* former ->i_op->default_file_ops */
 	struct super_block	*i_sb;
@@ -507,6 +513,8 @@ struct file_ra_state {
 	unsigned long prev_page;	/* Cache last read() position */
 	unsigned long ahead_start;	/* Ahead window */
 	unsigned long ahead_size;
+	unsigned long serial_cnt;	/* measure of sequentiality */
+	unsigned long average;		/* another measure of sequentiality */
 	unsigned long ra_pages;		/* Maximum readahead window */
 	unsigned long mmap_hit;		/* Cache hit stat for mmap accesses */
 	unsigned long mmap_miss;	/* Cache miss stat for mmap accesses */
@@ -700,6 +708,7 @@ struct super_block {
 	atomic_t		s_active;
 	void                    *s_security;
 
+	struct list_head	s_inodes;	/* all inodes */
 	struct list_head	s_dirty;	/* dirty inodes */
 	struct list_head	s_io;		/* parked for writeback */
 	struct hlist_head	s_anon;		/* anonymous dentries for (nfs) exporting */
@@ -1133,6 +1142,7 @@ extern void vfs_caches_init(unsigned lon
 extern int register_blkdev(unsigned int, const char *);
 extern int unregister_blkdev(unsigned int, const char *);
 extern struct block_device *bdget(dev_t);
+extern void bd_set_size(struct block_device *, loff_t size);
 extern void bd_forget(struct inode *inode);
 extern void bdput(struct block_device *);
 extern int blkdev_open(struct inode *, struct file *);
@@ -1210,6 +1220,7 @@ extern void write_inode_now(struct inode
 extern int filemap_fdatawrite(struct address_space *);
 extern int filemap_flush(struct address_space *);
 extern int filemap_fdatawait(struct address_space *);
+extern int filemap_write_and_wait(struct address_space *mapping);
 extern void sync_supers(void);
 extern void sync_filesystems(int wait);
 extern void emergency_sync(void);
@@ -1321,9 +1332,6 @@ extern void
 file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping);
 extern ssize_t generic_file_direct_IO(int rw, struct kiocb *iocb,
 	const struct iovec *iov, loff_t offset, unsigned long nr_segs);
-extern int blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, 
-	struct block_device *bdev, const struct iovec *iov, loff_t offset, 
-	unsigned long nr_segs, get_blocks_t *get_blocks, dio_iodone_t *end_io);
 extern ssize_t generic_file_readv(struct file *filp, const struct iovec *iov, 
 	unsigned long nr_segs, loff_t *ppos);
 ssize_t generic_file_writev(struct file *filp, const struct iovec *iov, 
@@ -1345,6 +1353,32 @@ static inline void do_generic_file_read(
 				actor);
 }
 
+int __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
+	struct block_device *bdev, const struct iovec *iov, loff_t offset,
+	unsigned long nr_segs, get_blocks_t get_blocks, dio_iodone_t end_io,
+	int needs_special_locking);
+
+/*
+ * For filesystems which need locking between buffered and direct access
+ */
+static inline int blockdev_direct_IO(int rw, struct kiocb *iocb,
+	struct inode *inode, struct block_device *bdev, const struct iovec *iov,
+	loff_t offset, unsigned long nr_segs, get_blocks_t get_blocks,
+	dio_iodone_t end_io)
+{
+	return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
+				nr_segs, get_blocks, end_io, 1);
+}
+
+static inline int blockdev_direct_IO_no_locking(int rw, struct kiocb *iocb,
+	struct inode *inode, struct block_device *bdev, const struct iovec *iov,
+	loff_t offset, unsigned long nr_segs, get_blocks_t get_blocks,
+	dio_iodone_t end_io)
+{
+	return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
+				nr_segs, get_blocks, end_io, 0);
+}
+
 extern struct file_operations generic_ro_fops;
 
 #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
--- diff/include/linux/hiddev.h	2003-09-17 12:28:12.000000000 +0100
+++ source/include/linux/hiddev.h	2004-03-09 11:51:51.000000000 +0000
@@ -39,33 +39,33 @@ struct hiddev_event {
 };
 
 struct hiddev_devinfo {
-	unsigned int bustype;
-	unsigned int busnum;
-	unsigned int devnum;
-	unsigned int ifnum;
-	short vendor;
-	short product;
-	short version;
-	unsigned num_applications;
+	__u32 bustype;
+	__u32 busnum;
+	__u32 devnum;
+	__u32 ifnum;
+	__s16 vendor;
+	__s16 product;
+	__s16 version;
+	__u32 num_applications;
 };
 
 struct hiddev_collection_info {
-	unsigned index;
-	unsigned type;
-	unsigned usage;
-	unsigned level;
+	__u32 index;
+	__u32 type;
+	__u32 usage;
+	__u32 level;
 };
 
 #define HID_STRING_SIZE 256
 struct hiddev_string_descriptor {
-	int index;
+	__s32 index;
 	char value[HID_STRING_SIZE];
 };
 
 struct hiddev_report_info {
-	unsigned report_type;
-	unsigned report_id;
-	unsigned num_fields;
+	__u32 report_type;
+	__u32 report_id;
+	__u32 num_fields;
 };
 
 /* To do a GUSAGE/SUSAGE, fill in at least usage_code,  report_type and 
@@ -88,20 +88,20 @@ struct hiddev_report_info {
 #define HID_REPORT_TYPE_MAX     3
 
 struct hiddev_field_info {
-	unsigned report_type;
-	unsigned report_id;
-	unsigned field_index;
-	unsigned maxusage;
-	unsigned flags;
-	unsigned physical;		/* physical usage for this field */
-	unsigned logical;		/* logical usage for this field */
-	unsigned application;		/* application usage for this field */
+	__u32 report_type;
+	__u32 report_id;
+	__u32 field_index;
+	__u32 maxusage;
+	__u32 flags;
+	__u32 physical;		/* physical usage for this field */
+	__u32 logical;		/* logical usage for this field */
+	__u32 application;		/* application usage for this field */
 	__s32 logical_minimum;
 	__s32 logical_maximum;
 	__s32 physical_minimum;
 	__s32 physical_maximum;
-	unsigned unit_exponent;
-	unsigned unit;
+	__u32 unit_exponent;
+	__u32 unit;
 };
 
 /* Fill in report_type, report_id and field_index to get the information on a
@@ -118,14 +118,22 @@ struct hiddev_field_info {
 #define HID_FIELD_BUFFERED_BYTE		0x100
 
 struct hiddev_usage_ref {
-	unsigned report_type;
-	unsigned report_id;
-	unsigned field_index;
-	unsigned usage_index;
-	unsigned usage_code;
+	__u32 report_type;
+	__u32 report_id;
+	__u32 field_index;
+	__u32 usage_index;
+	__u32 usage_code;
 	__s32 value;
 };
 
+/* hiddev_usage_ref_multi is used for sending multiple bytes to a control.
+ * It really manifests itself as setting the value of consecutive usages */
+struct hiddev_usage_ref_multi {
+	struct hiddev_usage_ref uref;
+	__u32 num_values;
+	__s32 values[HID_MAX_USAGES];
+};
+
 /* FIELD_INDEX_NONE is returned in read() data from the kernel when flags
  * is set to (HIDDEV_FLAG_UREF | HIDDEV_FLAG_REPORT) and a new report has
  * been sent by the device 
@@ -161,6 +169,10 @@ struct hiddev_usage_ref {
 #define HIDIOCGCOLLECTIONINFO	_IOWR('H', 0x11, struct hiddev_collection_info)
 #define HIDIOCGPHYS(len)	_IOC(_IOC_READ, 'H', 0x12, len)
 
+/* For writing/reading to multiple/consecutive usages */
+#define HIDIOCGUSAGES		_IOWR('H', 0x13, struct hiddev_usage_ref_multi)
+#define HIDIOCSUSAGES		_IOW('H', 0x14, struct hiddev_usage_ref_multi)
+
 /* 
  * Flags to be used in HIDIOCSFLAG
  */
--- diff/include/linux/i2o-dev.h	2002-10-16 04:27:18.000000000 +0100
+++ source/include/linux/i2o-dev.h	2004-03-09 11:51:51.000000000 +0000
@@ -182,7 +182,7 @@ typedef struct _i2o_hrt_entry
 {
 	u32	adapter_id;
 	u32	parent_tid:12;
-	u32 	tate:4;
+	u32 	state:4;
 	u32	bus_num:8;
 	u32	bus_type:8;
 	union
--- diff/include/linux/i2o.h	2003-05-21 11:49:56.000000000 +0100
+++ source/include/linux/i2o.h	2004-03-09 11:51:51.000000000 +0000
@@ -544,6 +544,25 @@ extern int i2o_delete_controller(struct 
 #define I2O_DSC_DEVICE_BUSY                    0x001B
 #define I2O_DSC_DEVICE_NOT_AVAILABLE           0x001C
 
+/* DetailedStatusCode defines for Block Storage Operation: Table 6-7 Detailed
+   Status Codes.*/
+
+#define I2O_BSA_DSC_SUCCESS               0x0000
+#define I2O_BSA_DSC_MEDIA_ERROR           0x0001
+#define I2O_BSA_DSC_ACCESS_ERROR          0x0002
+#define I2O_BSA_DSC_DEVICE_FAILURE        0x0003
+#define I2O_BSA_DSC_DEVICE_NOT_READY      0x0004
+#define I2O_BSA_DSC_MEDIA_NOT_PRESENT     0x0005
+#define I2O_BSA_DSC_MEDIA_LOCKED          0x0006
+#define I2O_BSA_DSC_MEDIA_FAILURE         0x0007
+#define I2O_BSA_DSC_PROTOCOL_FAILURE      0x0008
+#define I2O_BSA_DSC_BUS_FAILURE           0x0009
+#define I2O_BSA_DSC_ACCESS_VIOLATION      0x000A
+#define I2O_BSA_DSC_WRITE_PROTECTED       0x000B
+#define I2O_BSA_DSC_DEVICE_RESET          0x000C
+#define I2O_BSA_DSC_VOLUME_CHANGED        0x000D
+#define I2O_BSA_DSC_TIMEOUT               0x000E
+
 /* FailureStatusCodes, Table 3-3 Message Failure Codes */
 
 #define I2O_FSC_TRANSPORT_SERVICE_SUSPENDED             0x81
--- diff/include/linux/ide.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/ide.h	2004-03-09 11:51:51.000000000 +0000
@@ -143,17 +143,8 @@ typedef unsigned char	byte;	/* used ever
 #define IDE_FEATURE_OFFSET	IDE_ERROR_OFFSET
 #define IDE_COMMAND_OFFSET	IDE_STATUS_OFFSET
 
-#define IDE_DATA_OFFSET_HOB	(0)
-#define IDE_ERROR_OFFSET_HOB	(1)
-#define IDE_NSECTOR_OFFSET_HOB	(2)
-#define IDE_SECTOR_OFFSET_HOB	(3)
-#define IDE_LCYL_OFFSET_HOB	(4)
-#define IDE_HCYL_OFFSET_HOB	(5)
-#define IDE_SELECT_OFFSET_HOB	(6)
 #define IDE_CONTROL_OFFSET_HOB	(7)
 
-#define IDE_FEATURE_OFFSET_HOB	IDE_ERROR_OFFSET_HOB
-
 #define IDE_DATA_REG		(HWIF(drive)->io_ports[IDE_DATA_OFFSET])
 #define IDE_ERROR_REG		(HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
 #define IDE_NSECTOR_REG		(HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
@@ -165,16 +156,6 @@ typedef unsigned char	byte;	/* used ever
 #define IDE_CONTROL_REG		(HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
 #define IDE_IRQ_REG		(HWIF(drive)->io_ports[IDE_IRQ_OFFSET])
 
-#define IDE_DATA_REG_HOB	(HWIF(drive)->io_ports[IDE_DATA_OFFSET])
-#define IDE_ERROR_REG_HOB	(HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
-#define IDE_NSECTOR_REG_HOB	(HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
-#define IDE_SECTOR_REG_HOB	(HWIF(drive)->io_ports[IDE_SECTOR_OFFSET])
-#define IDE_LCYL_REG_HOB	(HWIF(drive)->io_ports[IDE_LCYL_OFFSET])
-#define IDE_HCYL_REG_HOB	(HWIF(drive)->io_ports[IDE_HCYL_OFFSET])
-#define IDE_SELECT_REG_HOB	(HWIF(drive)->io_ports[IDE_SELECT_OFFSET])
-#define IDE_STATUS_REG_HOB	(HWIF(drive)->io_ports[IDE_STATUS_OFFSET])
-#define IDE_CONTROL_REG_HOB	(HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
-
 #define IDE_FEATURE_REG		IDE_ERROR_REG
 #define IDE_COMMAND_REG		IDE_STATUS_REG
 #define IDE_ALTSTATUS_REG	IDE_CONTROL_REG
@@ -991,6 +972,7 @@ typedef struct hwif_s {
 	unsigned dma;
 
 	void (*led_act)(void *data, int rw);
+	unsigned int (*max_rqsize)(ide_drive_t *);
 } ide_hwif_t;
 
 /*
@@ -998,7 +980,6 @@ typedef struct hwif_s {
  */
 typedef ide_startstop_t (ide_pre_handler_t)(ide_drive_t *, struct request *);
 typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
-typedef ide_startstop_t (ide_post_handler_t)(ide_drive_t *);
 typedef int (ide_expiry_t)(ide_drive_t *);
 
 typedef struct hwgroup_s {
@@ -1360,7 +1341,6 @@ typedef struct ide_task_s {
 	int			command_type;
 	ide_pre_handler_t	*prehandler;
 	ide_handler_t		*handler;
-	ide_post_handler_t	*posthandler;
 	struct request		*rq;		/* copy of request */
 	void			*special;	/* valid_t generally */
 } ide_task_t;
@@ -1459,15 +1439,6 @@ extern void ide_init_drive_taskfile(stru
 
 extern int ide_raw_taskfile(ide_drive_t *, ide_task_t *, u8 *);
 
-extern ide_pre_handler_t * ide_pre_handler_parser(struct hd_drive_task_hdr *, struct hd_drive_hob_hdr *);
-
-extern ide_handler_t * ide_handler_parser(struct hd_drive_task_hdr *, struct hd_drive_hob_hdr *);
-
-extern ide_post_handler_t * ide_post_handler_parser(struct hd_drive_task_hdr *, struct hd_drive_hob_hdr *);
-
-/* Expects args is a full set of TF registers and parses the command type */
-extern int ide_cmd_type_parser(ide_task_t *);
-
 int ide_taskfile_ioctl(ide_drive_t *, unsigned int, unsigned long);
 int ide_cmd_ioctl(ide_drive_t *, unsigned int, unsigned long);
 int ide_task_ioctl(ide_drive_t *, unsigned int, unsigned long);
@@ -1643,6 +1614,7 @@ extern int ide_dma_enable(ide_drive_t *d
 extern char *ide_xfer_verbose(u8 xfer_rate);
 extern void ide_toggle_bounce(ide_drive_t *drive, int on);
 extern int ide_set_xfer_rate(ide_drive_t *drive, u8 rate);
+extern byte ide_dump_atapi_status(ide_drive_t *drive, const char *msg, byte stat);
 
 typedef struct ide_pio_timings_s {
 	int	setup_time;	/* Address setup (ns) minimum */
--- diff/include/linux/init.h	2003-11-25 15:24:59.000000000 +0000
+++ source/include/linux/init.h	2004-03-09 11:51:51.000000000 +0000
@@ -110,12 +110,21 @@ struct obs_kernel_param {
 };
 
 /* OBSOLETE: see moduleparam.h for the right way. */
-#define __setup(str, fn)					\
-	static char __setup_str_##fn[] __initdata = str;	\
-	static struct obs_kernel_param __setup_##fn		\
+#define __setup_param(str, unique_id, fn)			\
+	static char __setup_str_##unique_id[] __initdata = str;	\
+	static struct obs_kernel_param __setup_##unique_id	\
 		 __attribute_used__				\
 		 __attribute__((__section__(".init.setup")))	\
-		= { __setup_str_##fn, fn }
+		= { __setup_str_##unique_id, fn }
+
+#define __setup_null_param(str, unique_id)			\
+	__setup_param(str, unique_id, NULL)
+
+#define __setup(str, fn)					\
+	__setup_param(str, fn, fn)
+
+#define __obsolete_setup(str)					\
+	__setup_null_param(str, __LINE__)
 
 #endif /* __ASSEMBLY__ */
 
@@ -172,7 +181,10 @@ struct obs_kernel_param {
 	{ return exitfn; }					\
 	void cleanup_module(void) __attribute__((alias(#exitfn)));
 
-#define __setup(str,func) /* nothing */
+#define __setup_param(str, unique_id, fn)	/* nothing */
+#define __setup_null_param(str, unique_id) 	/* nothing */
+#define __setup(str, func) 			/* nothing */
+#define __obsolete_setup(str) 			/* nothing */
 #endif
 
 /* Data marked not to be saved by software_suspend() */
--- diff/include/linux/interrupt.h	2003-09-30 15:46:20.000000000 +0100
+++ source/include/linux/interrupt.h	2004-03-09 11:51:51.000000000 +0000
@@ -211,6 +211,7 @@ static inline void tasklet_hi_enable(str
 }
 
 extern void tasklet_kill(struct tasklet_struct *t);
+extern void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu);
 extern void tasklet_init(struct tasklet_struct *t,
 			 void (*func)(unsigned long), unsigned long data);
 
--- diff/include/linux/ipmi.h	2003-05-21 11:49:46.000000000 +0100
+++ source/include/linux/ipmi.h	2004-03-09 11:51:51.000000000 +0000
@@ -109,6 +109,35 @@ struct ipmi_ipmb_addr
 	unsigned char lun;
 };
 
+/*
+ * A LAN Address.  This is an address to/from a LAN interface bridged
+ * by the BMC, not an address actually out on the LAN.
+ *
+ * A concious decision was made here to deviate slightly from the IPMI
+ * spec.  We do not use rqSWID and rsSWID like it shows in the
+ * message.  Instead, we use remote_SWID and local_SWID.  This means
+ * that any message (a request or response) from another device will
+ * always have exactly the same address.  If you didn't do this,
+ * requests and responses from the same device would have different
+ * addresses, and that's not too cool.
+ *
+ * In this address, the remote_SWID is always the SWID the remote
+ * message came from, or the SWID we are sending the message to.
+ * local_SWID is always our SWID.  Note that having our SWID in the
+ * message is a little wierd, but this is required.
+ */
+#define IPMI_LAN_ADDR_TYPE		0x04
+struct ipmi_lan_addr
+{
+	int           addr_type;
+	short         channel;
+	unsigned char privilege;
+	unsigned char session_handle;
+	unsigned char remote_SWID;
+	unsigned char local_SWID;
+	unsigned char lun;
+};
+
 
 /*
  * Channel for talking directly with the BMC.  When using this
@@ -145,10 +174,20 @@ struct ipmi_msg
  * Receive types for messages coming from the receive interface.  This
  * is used for the receive in-kernel interface and in the receive
  * IOCTL.
+ *
+ * The "IPMI_RESPONSE_RESPNOSE_TYPE" is a little strange sounding, but
+ * it allows you to get the message results when you send a response
+ * message.
  */
 #define IPMI_RESPONSE_RECV_TYPE		1 /* A response to a command */
 #define IPMI_ASYNC_EVENT_RECV_TYPE	2 /* Something from the event queue */
 #define IPMI_CMD_RECV_TYPE		3 /* A command from somewhere else */
+#define IPMI_RESPONSE_RESPONSE_TYPE	4 /* The response for
+					      a sent response, giving any
+					      error status for sending the
+					      response.  When you send a
+					      response message, this will
+					      be returned. */
 /* Note that async events and received commands do not have a completion
    code as the first byte of the incoming data, unlike a response. */
 
@@ -160,6 +199,7 @@ struct ipmi_msg
  * The in-kernel interface.
  */
 #include <linux/list.h>
+#include <linux/module.h>
 
 /* Opaque type for a IPMI message user.  One of these is needed to
    send and receive messages. */
@@ -185,6 +225,12 @@ struct ipmi_recv_msg
 	long             msgid;
 	struct ipmi_msg  msg;
 
+	/* The user_msg_data is the data supplied when a message was
+	   sent, if this is a response to a sent message.  If this is
+	   not a response to a sent message, then user_msg_data will
+	   be NULL. */
+	void             *user_msg_data;
+
 	/* Call this when done with the message.  It will presumably free
 	   the message and do any other necessary cleanup. */
 	void (*done)(struct ipmi_recv_msg *msg);
@@ -206,9 +252,10 @@ struct ipmi_user_hndl
         /* Routine type to call when a message needs to be routed to
 	   the upper layer.  This will be called with some locks held,
 	   the only IPMI routines that can be called are ipmi_request
-	   and the alloc/free operations. */
+	   and the alloc/free operations.  The handler_data is the
+	   variable supplied when the receive handler was registered. */
 	void (*ipmi_recv_hndl)(struct ipmi_recv_msg *msg,
-			       void                 *handler_data);
+			       void                 *user_msg_data);
 
 	/* Called when the interface detects a watchdog pre-timeout.  If
 	   this is NULL, it will be ignored for the user. */
@@ -221,7 +268,12 @@ int ipmi_create_user(unsigned int       
 		     void                  *handler_data,
 		     ipmi_user_t           *user);
 
-/* Destroy the given user of the IPMI layer. */
+/* Destroy the given user of the IPMI layer.  Note that after this
+   function returns, the system is guaranteed to not call any
+   callbacks for the user.  Thus as long as you destroy all the users
+   before you unload a module, you will be safe.  And if you destroy
+   the users before you destroy the callback structures, it should be
+   safe, too. */
 int ipmi_destroy_user(ipmi_user_t user);
 
 /* Get the IPMI version of the BMC we are talking to. */
@@ -253,20 +305,51 @@ unsigned char ipmi_get_my_LUN(ipmi_user_
  * in the msgid field of the received command.  If the priority is >
  * 0, the message will go into a high-priority queue and be sent
  * first.  Otherwise, it goes into a normal-priority queue.
+ * The user_msg_data field will be returned in any response to this
+ * message.
+ *
+ * Note that if you send a response (with the netfn lower bit set),
+ * you *will* get back a SEND_MSG response telling you what happened
+ * when the response was sent.  You will not get back a response to
+ * the message itself.
  */
 int ipmi_request(ipmi_user_t      user,
 		 struct ipmi_addr *addr,
 		 long             msgid,
 		 struct ipmi_msg  *msg,
+		 void             *user_msg_data,
 		 int              priority);
 
 /*
+ * Like ipmi_request, but lets you specify the number of retries and
+ * the retry time.  The retries is the number of times the message
+ * will be resent if no reply is received.  If set to -1, the default
+ * value will be used.  The retry time is the time in milliseconds
+ * between retries.  If set to zero, the default value will be
+ * used.
+ *
+ * Don't use this unless you *really* have to.  It's primarily for the
+ * IPMI over LAN converter; since the LAN stuff does its own retries,
+ * it makes no sense to do it here.  However, this can be used if you
+ * have unusual requirements.
+ */
+int ipmi_request_settime(ipmi_user_t      user,
+			 struct ipmi_addr *addr,
+			 long             msgid,
+			 struct ipmi_msg  *msg,
+			 void             *user_msg_data,
+			 int              priority,
+			 int              max_retries,
+			 unsigned int     retry_time_ms);
+
+/*
  * Like ipmi_request, but lets you specify the slave return address.
  */
 int ipmi_request_with_source(ipmi_user_t      user,
 			     struct ipmi_addr *addr,
 			     long             msgid,
 			     struct ipmi_msg  *msg,
+			     void             *user_msg_data,
 			     int              priority,
 			     unsigned char    source_address,
 			     unsigned char    source_lun);
@@ -284,6 +367,7 @@ int ipmi_request_supply_msgs(ipmi_user_t
 			     struct ipmi_addr     *addr,
 			     long                 msgid,
 			     struct ipmi_msg      *msg,
+			     void                 *user_msg_data,
 			     void                 *supplied_smi,
 			     struct ipmi_recv_msg *supplied_recv,
 			     int                  priority);
@@ -331,6 +415,10 @@ struct ipmi_smi_watcher
 {
 	struct list_head link;
 
+	/* You must set the owner to the current module, if you are in
+	   a module (generally just set it to "THIS_MODULE"). */
+	struct module *owner;
+
 	/* These two are called with read locks held for the interface
 	   the watcher list.  So you can add and remove users from the
 	   IPMI interface, send messages, etc., but you cannot add
@@ -422,6 +510,29 @@ struct ipmi_req
 #define IPMICTL_SEND_COMMAND		_IOR(IPMI_IOC_MAGIC, 13,	\
 					     struct ipmi_req)
 
+/* Messages sent to the interface with timing parameters are this
+   format. */
+struct ipmi_req_settime
+{
+	struct ipmi_req req;
+
+	/* See ipmi_request_settime() above for details on these
+           values. */
+	int          retries;
+	unsigned int retry_time_ms;
+};
+/*
+ * Send a message to the interfaces with timing parameters.  error values
+ * are:
+ *   - EFAULT - an address supplied was invalid.
+ *   - EINVAL - The address supplied was not valid, or the command
+ *              was not allowed.
+ *   - EMSGSIZE - The message to was too large.
+ *   - ENOMEM - Buffers could not be allocated for the command.
+ */
+#define IPMICTL_SEND_COMMAND_SETTIME	_IOR(IPMI_IOC_MAGIC, 21,	\
+					     struct ipmi_req_settime)
+
 /* Messages received from the interface are this format. */
 struct ipmi_recv
 {
@@ -513,4 +624,18 @@ struct ipmi_cmdspec
 #define IPMICTL_SET_MY_LUN_CMD		_IOR(IPMI_IOC_MAGIC, 19, unsigned int)
 #define IPMICTL_GET_MY_LUN_CMD		_IOR(IPMI_IOC_MAGIC, 20, unsigned int)
 
+/*
+ * Get/set the default timing values for an interface.  You shouldn't
+ * generally mess with these.
+ */
+struct ipmi_timing_parms
+{
+	int          retries;
+	unsigned int retry_time_ms;
+};
+#define IPMICTL_SET_TIMING_PARMS_CMD	_IOR(IPMI_IOC_MAGIC, 22, \
+					     struct ipmi_timing_parms)
+#define IPMICTL_GET_TIMING_PARMS_CMD	_IOR(IPMI_IOC_MAGIC, 23, \
+					     struct ipmi_timing_parms)
+
 #endif /* __LINUX_IPMI_H */
--- diff/include/linux/ipmi_msgdefs.h	2003-10-27 09:20:39.000000000 +0000
+++ source/include/linux/ipmi_msgdefs.h	2004-03-09 11:51:51.000000000 +0000
@@ -53,6 +53,7 @@
 #define IPMI_SET_BMC_GLOBAL_ENABLES_CMD	0x2e
 #define IPMI_GET_BMC_GLOBAL_ENABLES_CMD	0x2f
 #define IPMI_READ_EVENT_MSG_BUFFER_CMD	0x35
+#define IPMI_GET_CHANNEL_INFO_CMD	0x42
 
 #define IPMI_NETFN_STORAGE_REQUEST		0x0a
 #define IPMI_NETFN_STORAGE_RESPONSE		0x0b
@@ -61,8 +62,39 @@
 /* The default slave address */
 #define IPMI_BMC_SLAVE_ADDR	0x20
 
-#define IPMI_MAX_MSG_LENGTH	80
+/* The BT interface on high-end HP systems supports up to 255 bytes in
+ * one transfer.  Its "virtual" BMC supports some commands that are longer
+ * than 128 bytes.  Use the full 256, plus NetFn/LUN, Cmd, cCode, plus
+ * some overhead.  It would be nice to base this on the "BT Capabilities"
+ * but that's too hard to propogate to the rest of the driver. */
+#define IPMI_MAX_MSG_LENGTH	272	/* multiple of 16 */
 
-#define IPMI_CC_NO_ERROR	0
+#define IPMI_CC_NO_ERROR		0x00
+#define IPMI_NODE_BUSY_ERR		0xc0
+#define IPMI_ERR_MSG_TRUNCATED		0xc6
+#define IPMI_LOST_ARBITRATION_ERR	0x81
+#define IPMI_ERR_UNSPECIFIED		0xff
+
+#define IPMI_CHANNEL_PROTOCOL_IPMB	1
+#define IPMI_CHANNEL_PROTOCOL_ICMB	2
+#define IPMI_CHANNEL_PROTOCOL_SMBUS	4
+#define IPMI_CHANNEL_PROTOCOL_KCS	5
+#define IPMI_CHANNEL_PROTOCOL_SMIC	6
+#define IPMI_CHANNEL_PROTOCOL_BT10	7
+#define IPMI_CHANNEL_PROTOCOL_BT15	8
+#define IPMI_CHANNEL_PROTOCOL_TMODE	9
+
+#define IPMI_CHANNEL_MEDIUM_IPMB	1
+#define IPMI_CHANNEL_MEDIUM_ICMB10	2
+#define IPMI_CHANNEL_MEDIUM_ICMB09	3
+#define IPMI_CHANNEL_MEDIUM_8023LAN	4
+#define IPMI_CHANNEL_MEDIUM_ASYNC	5
+#define IPMI_CHANNEL_MEDIUM_OTHER_LAN	6
+#define IPMI_CHANNEL_MEDIUM_PCI_SMBUS	7
+#define IPMI_CHANNEL_MEDIUM_SMBUS1	8
+#define IPMI_CHANNEL_MEDIUM_SMBUS2	9
+#define IPMI_CHANNEL_MEDIUM_USB1	10
+#define IPMI_CHANNEL_MEDIUM_USB2	11
+#define IPMI_CHANNEL_MEDIUM_SYSINTF	12
 
 #endif /* __LINUX_IPMI_MSGDEFS_H */
--- diff/include/linux/ipmi_smi.h	2003-02-26 16:01:09.000000000 +0000
+++ source/include/linux/ipmi_smi.h	2004-03-09 11:51:51.000000000 +0000
@@ -35,6 +35,8 @@
 #define __LINUX_IPMI_SMI_H
 
 #include <linux/ipmi_msgdefs.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
 
 /* This files describes the interface for IPMI system management interface
    drivers to bind into the IPMI message handler. */
@@ -48,7 +50,7 @@ typedef struct ipmi_smi *ipmi_smi_t;
  * been received, it will report this same data structure back up to
  * the upper layer.  If an error occurs, it should fill in the
  * response with an error code in the completion code location. When
- * asyncronous data is received, one of these is allocated, the
+ * asynchronous data is received, one of these is allocated, the
  * data_size is set to zero and the response holds the data from the
  * get message or get event command that the interface initiated.
  * Note that it is the interfaces responsibility to detect
@@ -62,9 +64,6 @@ struct ipmi_smi_msg
 	long    msgid;
 	void    *user_data;
 
-	/* If 0, add to the end of the queue.  If 1, add to the beginning. */
-	int     prio;
-
 	int           data_size;
 	unsigned char data[IPMI_MAX_MSG_LENGTH];
 
@@ -134,4 +133,11 @@ static inline void ipmi_free_smi_msg(str
 	msg->done(msg);
 }
 
+/* Allow the lower layer to add things to the proc filesystem
+   directory for this interface.  Note that the entry will
+   automatically be dstroyed when the interface is destroyed. */
+int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
+			    read_proc_t *read_proc, write_proc_t *write_proc,
+			    void *data, struct module *owner);
+
 #endif /* __LINUX_IPMI_SMI_H */
--- diff/include/linux/irq.h	2003-08-26 10:00:54.000000000 +0100
+++ source/include/linux/irq.h	2004-03-09 11:51:51.000000000 +0000
@@ -71,7 +71,6 @@ extern irq_desc_t irq_desc [NR_IRQS];
 
 #include <asm/hw_irq.h> /* the arch dependent stuff */
 
-extern int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
 extern int setup_irq(unsigned int , struct irqaction * );
 
 extern hw_irq_controller no_irq_type;  /* needed in every arch ? */
--- diff/include/linux/kmalloc_sizes.h	2003-05-21 11:50:00.000000000 +0100
+++ source/include/linux/kmalloc_sizes.h	2004-03-09 11:51:51.000000000 +0000
@@ -12,6 +12,9 @@
 	CACHE(256)
 	CACHE(512)
 	CACHE(1024)
+#if (PAGE_SIZE != 4096)	/* special cache for eth skbs - 5 fit into one 8 kB page */
+	CACHE(1620)
+#endif
 	CACHE(2048)
 	CACHE(4096)
 	CACHE(8192)
--- diff/include/linux/linkage.h	2002-10-16 04:28:24.000000000 +0100
+++ source/include/linux/linkage.h	2004-03-09 11:51:51.000000000 +0000
@@ -37,6 +37,7 @@
 
 #ifndef FASTCALL
 #define FASTCALL(x)	x
+#define fastcall
 #endif
 
 #endif
--- diff/include/linux/list.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/list.h	2004-03-09 11:51:51.000000000 +0000
@@ -142,8 +142,11 @@ static inline void __list_del(struct lis
  * Note: list_empty on entry does not return true after this, the entry is
  * in an undefined state.
  */
+#include <linux/kernel.h>	/* BUG_ON */
 static inline void list_del(struct list_head *entry)
 {
+	BUG_ON(entry->prev->next != entry);
+	BUG_ON(entry->next->prev != entry);
 	__list_del(entry->prev, entry->next);
 	entry->next = LIST_POISON1;
 	entry->prev = LIST_POISON2;
--- diff/include/linux/lockd/debug.h	2002-11-18 10:11:55.000000000 +0000
+++ source/include/linux/lockd/debug.h	2004-03-09 11:51:51.000000000 +0000
@@ -23,7 +23,7 @@
 
 #undef ifdebug
 #if defined(RPC_DEBUG) && defined(LOCKD_DEBUG)
-# define ifdebug(flag)		if (nlm_debug & NLMDBG_##flag)
+# define ifdebug(flag)		if (unlikely(nlm_debug & NLMDBG_##flag))
 #else
 # define ifdebug(flag)		if (0)
 #endif
--- diff/include/linux/lockd/lockd.h	2003-08-26 10:00:54.000000000 +0100
+++ source/include/linux/lockd/lockd.h	2004-03-09 11:51:51.000000000 +0000
@@ -165,6 +165,7 @@ u32		  nlmsvc_cancel_blocked(struct nlm_
 unsigned long	  nlmsvc_retry_blocked(void);
 int		  nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *,
 					int action);
+void	  nlmsvc_grant_reply(struct svc_rqst *, struct nlm_cookie *, u32);
 
 /*
  * File handling for the server personality
--- diff/include/linux/loop.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/loop.h	2004-03-09 11:51:51.000000000 +0000
@@ -153,5 +153,6 @@ int loop_unregister_transfer(int number)
 #define LOOP_GET_STATUS		0x4C03
 #define LOOP_SET_STATUS64	0x4C04
 #define LOOP_GET_STATUS64	0x4C05
+#define LOOP_CHANGE_FD		0x4C06
 
 #endif
--- diff/include/linux/miscdevice.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/miscdevice.h	2004-03-09 11:51:51.000000000 +0000
@@ -3,7 +3,6 @@
 #include <linux/module.h>
 #include <linux/major.h>
 
-#define BUSMOUSE_MINOR 0
 #define PSMOUSE_MINOR  1
 #define MS_BUSMOUSE_MINOR 2
 #define ATIXL_BUSMOUSE_MINOR 3
--- diff/include/linux/mm.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/mm.h	2004-03-09 11:51:51.000000000 +0000
@@ -415,10 +415,11 @@ static inline int page_mapped(struct pag
  * Used to decide whether a process gets delivered SIGBUS or
  * just gets major/minor fault counters bumped up.
  */
-#define VM_FAULT_OOM	(-1)
-#define VM_FAULT_SIGBUS	0
-#define VM_FAULT_MINOR	1
-#define VM_FAULT_MAJOR	2
+#define VM_FAULT_OOM		(-1)
+#define VM_FAULT_SIGBUS		0
+#define VM_FAULT_MINOR		1
+#define VM_FAULT_MAJOR		2
+#define VM_FAULT_SIGSEGV	3
 
 #define offset_in_page(p)	((unsigned long)(p) & ~PAGE_MASK)
 
@@ -451,9 +452,10 @@ extern pmd_t *FASTCALL(__pmd_alloc(struc
 extern pte_t *FASTCALL(pte_alloc_kernel(struct mm_struct *mm, pmd_t *pmd, unsigned long address));
 extern pte_t *FASTCALL(pte_alloc_map(struct mm_struct *mm, pmd_t *pmd, unsigned long address));
 extern int install_page(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr, struct page *page, pgprot_t prot);
-extern int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr, unsigned long pgoff, pgprot_t prot);
+extern int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr, unsigned long pgoff, pgprot_t prot, int linear);
 extern int handle_mm_fault(struct mm_struct *mm,struct vm_area_struct *vma, unsigned long address, int write_access);
 extern int make_pages_present(unsigned long addr, unsigned long end);
+extern long __remap_file_pages(struct mm_struct *mm, unsigned long start, unsigned long size, unsigned long prot, unsigned long pgoff, unsigned long flags);
 extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
 void put_dirty_page(struct task_struct *tsk, struct page *page,
 			unsigned long address, pgprot_t prot);
@@ -530,7 +532,8 @@ extern void si_meminfo_node(struct sysin
 
 /* mmap.c */
 extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *);
-extern void build_mmap_rb(struct mm_struct *);
+extern void __vma_link_rb(struct mm_struct *, struct vm_area_struct *,
+	struct rb_node **, struct rb_node *);
 extern void exit_mmap(struct mm_struct *);
 
 extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
@@ -633,6 +636,30 @@ extern struct page * follow_page(struct 
 extern int remap_page_range(struct vm_area_struct *vma, unsigned long from,
 		unsigned long to, unsigned long size, pgprot_t prot);
 
+#ifdef CONFIG_NUMA
+static inline void zero_rss(struct mm_struct *mm)
+{
+	mm->rss = 0;
+	memset(mm->pernode_rss, 0, MAX_NUMNODES * sizeof(*mm->pernode_rss));
+}
+
+static inline void inc_rss(struct mm_struct *mm, struct page *page)
+{
+	mm->rss++;
+	mm->pernode_rss[page_nodenum(page)]++;
+}
+
+static inline void dec_rss(struct mm_struct *mm, struct page *page)
+{
+	mm->rss--;
+	mm->pernode_rss[page_nodenum(page)]--;
+}
+#else /* !CONFIG_NUMA */
+#define zero_rss(mm)		((mm)->rss = 0)
+#define inc_rss(mm, page)	((mm)->rss++)
+#define dec_rss(mm, page)	((mm)->rss--)
+#endif /* CONFIG_NUMA */
+
 #ifndef CONFIG_DEBUG_PAGEALLOC
 static inline void
 kernel_map_pages(struct page *page, int numpages, int enable)
--- diff/include/linux/mmzone.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/mmzone.h	2004-03-09 11:51:51.000000000 +0000
@@ -76,7 +76,8 @@ struct zone {
 	spinlock_t		lru_lock;	
 	struct list_head	active_list;
 	struct list_head	inactive_list;
-	atomic_t		refill_counter;
+	atomic_t		nr_scan_active;
+	atomic_t		nr_scan_inactive;
 	unsigned long		nr_active;
 	unsigned long		nr_inactive;
 	int			all_unreclaimable; /* All pages pinned */
@@ -213,6 +214,7 @@ typedef struct pglist_data {
 	int node_id;
 	struct pglist_data *pgdat_next;
 	wait_queue_head_t       kswapd_wait;
+	struct task_struct *kswapd;
 } pg_data_t;
 
 #define node_present_pages(nid)	(NODE_DATA(nid)->node_present_pages)
@@ -288,6 +290,11 @@ static inline int is_highmem(struct zone
 	return (zone - zone->zone_pgdat->node_zones == ZONE_HIGHMEM);
 }
 
+static inline int is_normal(struct zone *zone)
+{
+	return (zone - zone->zone_pgdat->node_zones == ZONE_NORMAL);
+}
+
 /* These two functions are used to setup the per zone pages min values */
 struct ctl_table;
 struct file;
--- diff/include/linux/moduleparam.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/moduleparam.h	2004-03-09 11:51:51.000000000 +0000
@@ -126,13 +126,16 @@ extern int param_get_invbool(char *buffe
 #define param_check_invbool(name, p) __param_check(name, p, int)
 
 /* Comma-separated array: num is set to number they actually specified. */
-#define module_param_array(name, type, num, perm)			\
+#define module_param_array_named(name, array, type, num, perm)		\
 	static struct kparam_array __param_arr_##name			\
-	= { ARRAY_SIZE(name), &num, param_set_##type, param_get_##type,	\
-	    sizeof(name[0]), name };					\
+	= { ARRAY_SIZE(array), &num, param_set_##type, param_get_##type,\
+	    sizeof(array[0]), array };					\
 	module_param_call(name, param_array_set, param_array_get, 	\
 			  &__param_arr_##name, perm)
 
+#define module_param_array(name, type, num, perm)		\
+	module_param_array_named(name, name, type, num, perm)
+
 extern int param_array_set(const char *val, struct kernel_param *kp);
 extern int param_array_get(char *buffer, struct kernel_param *kp);
 
--- diff/include/linux/msg.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/msg.h	2004-03-09 11:51:51.000000000 +0000
@@ -74,9 +74,6 @@ struct msg_msg {
 	/* the actual message follows immediately */
 };
 
-#define DATALEN_MSG	(PAGE_SIZE-sizeof(struct msg_msg))
-#define DATALEN_SEG	(PAGE_SIZE-sizeof(struct msg_msgseg))
-
 /* one msq_queue structure for each present queue on the system */
 struct msg_queue {
 	struct kern_ipc_perm q_perm;
--- diff/include/linux/net.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/net.h	2004-03-09 11:51:51.000000000 +0000
@@ -25,7 +25,7 @@
 struct poll_table_struct;
 struct inode;
 
-#define NPROTO		32		/* should be enough for now..	*/
+#define NPROTO		64		/* should be enough for now..	*/
 
 #define SYS_SOCKET	1		/* sys_socket(2)		*/
 #define SYS_BIND	2		/* sys_bind(2)			*/
--- diff/include/linux/netdevice.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/netdevice.h	2004-03-09 11:51:51.000000000 +0000
@@ -456,6 +456,12 @@ struct net_device
 						     unsigned char *haddr);
 	int			(*neigh_setup)(struct net_device *dev, struct neigh_parms *);
 	int			(*accept_fastpath)(struct net_device *, struct dst_entry*);
+#ifdef CONFIG_NETPOLL_RX
+	int			netpoll_rx;
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	void                    (*poll_controller)(struct net_device *dev);
+#endif
 
 	/* bridge stuff */
 	struct net_bridge_port	*br_port;
@@ -540,6 +546,9 @@ extern int		dev_new_index(void);
 extern struct net_device	*dev_get_by_index(int ifindex);
 extern struct net_device	*__dev_get_by_index(int ifindex);
 extern int		dev_restart(struct net_device *dev);
+#ifdef CONFIG_NETPOLL_TRAP
+extern int		netpoll_trap(void);
+#endif
 
 typedef int gifconf_func_t(struct net_device * dev, char * bufptr, int len);
 extern int		register_gifconf(unsigned int family, gifconf_func_t * gifconf);
@@ -598,12 +607,20 @@ static inline void netif_start_queue(str
 
 static inline void netif_wake_queue(struct net_device *dev)
 {
+#ifdef CONFIG_NETPOLL_TRAP
+	if (netpoll_trap())
+		return;
+#endif
 	if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state))
 		__netif_schedule(dev);
 }
 
 static inline void netif_stop_queue(struct net_device *dev)
 {
+#ifdef CONFIG_NETPOLL_TRAP
+	if (netpoll_trap())
+		return;
+#endif
 	set_bit(__LINK_STATE_XOFF, &dev->state);
 }
 
--- diff/include/linux/nfs_fs.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/nfs_fs.h	2004-03-09 11:51:51.000000000 +0000
@@ -99,7 +99,7 @@ struct nfs_inode {
 	/*
 	 * Various flags
 	 */
-	unsigned short		flags;
+	unsigned int		flags;
 
 	/*
 	 * read_cache_jiffies is when we started read-caching this inode,
@@ -118,19 +118,22 @@ struct nfs_inode {
 	 *
 	 *	mtime != read_cache_mtime
 	 */
+	unsigned long		readdir_timestamp;
 	unsigned long		read_cache_jiffies;
-	struct timespec		read_cache_ctime;
-	struct timespec		read_cache_mtime;
-	__u64			read_cache_isize;
 	unsigned long		attrtimeo;
 	unsigned long		attrtimeo_timestamp;
 	__u64			change_attr;		/* v4 only */
 
+	/* "Generation counter" for the attribute cache. This is
+	 * bumped whenever we update the metadata on the
+	 * server.
+	 */
+	unsigned long		cache_change_attribute;
 	/*
-	 * Timestamp that dates the change made to read_cache_mtime.
-	 * This is of use for dentry revalidation
+	 * Counter indicating the number of outstanding requests that
+	 * will cause a file data update.
 	 */
-	unsigned long		cache_mtime_jiffies;
+	atomic_t		data_updates;
 
 	struct nfs_access_cache	cache_access;
 
@@ -170,8 +173,9 @@ struct nfs_inode {
 #define NFS_INO_STALE		0x0001		/* possible stale inode */
 #define NFS_INO_ADVISE_RDPLUS   0x0002          /* advise readdirplus */
 #define NFS_INO_REVALIDATING	0x0004		/* revalidating attrs */
-#define NFS_INO_FLUSH		0x0008		/* inode is due for flushing */
-#define NFS_INO_FAKE_ROOT	0x0080		/* root inode placeholder */
+#define NFS_INO_INVALID_ATTR	0x0008		/* cached attrs are invalid */
+#define NFS_INO_INVALID_DATA	0x0010		/* cached data is invalid */
+#define NFS_INO_INVALID_ATIME	0x0020		/* cached atime is invalid */
 
 static inline struct nfs_inode *NFS_I(struct inode *inode)
 {
@@ -186,15 +190,7 @@ static inline struct nfs_inode *NFS_I(st
 #define NFS_ADDR(inode)			(RPC_PEERADDR(NFS_CLIENT(inode)))
 #define NFS_COOKIEVERF(inode)		(NFS_I(inode)->cookieverf)
 #define NFS_READTIME(inode)		(NFS_I(inode)->read_cache_jiffies)
-#define NFS_MTIME_UPDATE(inode)		(NFS_I(inode)->cache_mtime_jiffies)
-#define NFS_CACHE_CTIME(inode)		(NFS_I(inode)->read_cache_ctime)
-#define NFS_CACHE_MTIME(inode)		(NFS_I(inode)->read_cache_mtime)
-#define NFS_CACHE_ISIZE(inode)		(NFS_I(inode)->read_cache_isize)
 #define NFS_CHANGE_ATTR(inode)		(NFS_I(inode)->change_attr)
-#define NFS_CACHEINV(inode) \
-do { \
-	NFS_READTIME(inode) = jiffies - NFS_MAXATTRTIMEO(inode) - 1; \
-} while (0)
 #define NFS_ATTRTIMEO(inode)		(NFS_I(inode)->attrtimeo)
 #define NFS_MINATTRTIMEO(inode) \
 	(S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmin \
@@ -207,10 +203,20 @@ do { \
 #define NFS_FLAGS(inode)		(NFS_I(inode)->flags)
 #define NFS_REVALIDATING(inode)		(NFS_FLAGS(inode) & NFS_INO_REVALIDATING)
 #define NFS_STALE(inode)		(NFS_FLAGS(inode) & NFS_INO_STALE)
-#define NFS_FAKE_ROOT(inode)		(NFS_FLAGS(inode) & NFS_INO_FAKE_ROOT)
 
 #define NFS_FILEID(inode)		(NFS_I(inode)->fileid)
 
+static inline int nfs_caches_unstable(struct inode *inode)
+{
+	return atomic_read(&NFS_I(inode)->data_updates) != 0;
+}
+
+static inline void NFS_CACHEINV(struct inode *inode)
+{
+	if (!nfs_caches_unstable(inode))
+		NFS_FLAGS(inode) |= NFS_INO_INVALID_ATTR;
+}
+
 static inline int nfs_server_capable(struct inode *inode, int cap)
 {
 	return NFS_SERVER(inode)->caps & cap;
@@ -227,13 +233,37 @@ loff_t page_offset(struct page *page)
 	return ((loff_t)page->index) << PAGE_CACHE_SHIFT;
 }
 
+/**
+ * nfs_save_change_attribute - Returns the inode attribute change cookie
+ * @inode - pointer to inode
+ * The "change attribute" is updated every time we finish an operation
+ * that will result in a metadata change on the server.
+ */
+static inline long nfs_save_change_attribute(struct inode *inode)
+{
+	return NFS_I(inode)->cache_change_attribute;
+}
+
+/**
+ * nfs_verify_change_attribute - Detects NFS inode cache updates
+ * @inode - pointer to inode
+ * @chattr - previously saved change attribute
+ * Return "false" if metadata has been updated (or is in the process of
+ * being updated) since the change attribute was saved.
+ */
+static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long chattr)
+{
+	return !nfs_caches_unstable(inode)
+		&& chattr == NFS_I(inode)->cache_change_attribute;
+}
+
 /*
  * linux/fs/nfs/inode.c
  */
 extern void nfs_zap_caches(struct inode *);
 extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
 				struct nfs_fattr *);
-extern int __nfs_refresh_inode(struct inode *, struct nfs_fattr *);
+extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
 extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 extern int nfs_permission(struct inode *, int, struct nameidata *);
 extern void nfs_set_mmcred(struct inode *, struct rpc_cred *);
@@ -241,6 +271,13 @@ extern int nfs_open(struct inode *, stru
 extern int nfs_release(struct inode *, struct file *);
 extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
 extern int nfs_setattr(struct dentry *, struct iattr *);
+extern void nfs_begin_attr_update(struct inode *);
+extern void nfs_end_attr_update(struct inode *);
+extern void nfs_begin_data_update(struct inode *);
+extern void nfs_end_data_update(struct inode *);
+
+/* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
+extern u32 root_nfs_parse_addr(char *name); /*__init*/
 
 /*
  * linux/fs/nfs/file.c
@@ -309,16 +346,15 @@ extern void nfs_commit_done(struct rpc_t
  * Try to write back everything synchronously (but check the
  * return value!)
  */
-extern int  nfs_sync_file(struct inode *, struct file *, unsigned long, unsigned int, int);
-extern int  nfs_flush_file(struct inode *, struct file *, unsigned long, unsigned int, int);
+extern int  nfs_sync_inode(struct inode *, unsigned long, unsigned int, int);
+extern int  nfs_flush_inode(struct inode *, unsigned long, unsigned int, int);
 extern int  nfs_flush_list(struct list_head *, int, int);
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
-extern int  nfs_commit_file(struct inode *, struct file *, unsigned long, unsigned int, int);
+extern int  nfs_commit_inode(struct inode *, unsigned long, unsigned int, int);
 extern int  nfs_commit_list(struct list_head *, int);
 #else
 static inline int
-nfs_commit_file(struct inode *inode, struct file *file, unsigned long offset,
-		unsigned int len, int flags)
+nfs_commit_inode(struct inode *inode, unsigned long idx_start, unsigned int npages, int how)
 {
 	return 0;
 }
@@ -333,7 +369,7 @@ nfs_have_writebacks(struct inode *inode)
 static inline int
 nfs_wb_all(struct inode *inode)
 {
-	int error = nfs_sync_file(inode, 0, 0, 0, FLUSH_WAIT);
+	int error = nfs_sync_inode(inode, 0, 0, FLUSH_WAIT);
 	return (error < 0) ? error : 0;
 }
 
@@ -343,21 +379,11 @@ nfs_wb_all(struct inode *inode)
 static inline int
 nfs_wb_page(struct inode *inode, struct page* page)
 {
-	int error = nfs_sync_file(inode, 0, page->index, 1,
+	int error = nfs_sync_inode(inode, page->index, 1,
 						FLUSH_WAIT | FLUSH_STABLE);
 	return (error < 0) ? error : 0;
 }
 
-/*
- * Write back all pending writes for one user.. 
- */
-static inline int
-nfs_wb_file(struct inode *inode, struct file *file)
-{
-	int error = nfs_sync_file(inode, file, 0, 0, FLUSH_WAIT);
-	return (error < 0) ? error : 0;
-}
-
 /* Hack for future NFS swap support */
 #ifndef IS_SWAPFILE
 # define IS_SWAPFILE(inode)	(0)
@@ -383,20 +409,27 @@ extern int  nfsroot_mount(struct sockadd
 /*
  * inline functions
  */
-static inline int
-nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
+
+static inline int nfs_attribute_timeout(struct inode *inode)
 {
-	if (time_before(jiffies, NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
-		return NFS_STALE(inode) ? -ESTALE : 0;
-	return __nfs_revalidate_inode(server, inode);
+	struct nfs_inode *nfsi = NFS_I(inode);
+
+	return time_after(jiffies, nfsi->read_cache_jiffies+nfsi->attrtimeo);
 }
 
-static inline int
-nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
+/**
+ * nfs_revalidate_inode - Revalidate the inode attributes
+ * @server - pointer to nfs_server struct
+ * @inode - pointer to inode struct
+ *
+ * Updates inode attribute information by retrieving the data from the server.
+ */
+static inline int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 {
-	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
-		return 0;
-	return __nfs_refresh_inode(inode,fattr);
+	if (!(NFS_FLAGS(inode) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))
+			&& !nfs_attribute_timeout(inode))
+		return NFS_STALE(inode) ? -ESTALE : 0;
+	return __nfs_revalidate_inode(server, inode);
 }
 
 static inline loff_t
@@ -661,7 +694,7 @@ struct nfs4_mount_data;
 #ifdef __KERNEL__
 # undef ifdebug
 # ifdef NFS_DEBUG
-#  define ifdebug(fac)		if (nfs_debug & NFSDBG_##fac)
+#  define ifdebug(fac)		if (unlikely(nfs_debug & NFSDBG_##fac))
 # else
 #  define ifdebug(fac)		if (0)
 # endif
--- diff/include/linux/nfs_page.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/nfs_page.h	2004-03-09 11:51:51.000000000 +0000
@@ -53,7 +53,7 @@ extern	void nfs_release_request(struct n
 extern	void nfs_list_add_request(struct nfs_page *, struct list_head *);
 
 extern	int nfs_scan_list(struct list_head *, struct list_head *,
-			  struct file *, unsigned long, unsigned int);
+			  unsigned long, unsigned int);
 extern	int nfs_coalesce_requests(struct list_head *, struct list_head *,
 				  unsigned int);
 extern  int nfs_wait_on_request(struct nfs_page *);
--- diff/include/linux/nfs_xdr.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/nfs_xdr.h	2004-03-09 11:51:51.000000000 +0000
@@ -700,7 +700,7 @@ struct nfs_rpc_ops {
 	struct inode_operations *dir_inode_ops;
 
 	int	(*getroot) (struct nfs_server *, struct nfs_fh *,
-			    struct nfs_fattr *);
+			    struct nfs_fsinfo *);
 	int	(*getattr) (struct inode *, struct nfs_fattr *);
 	int	(*setattr) (struct dentry *, struct nfs_fattr *,
 			    struct iattr *);
--- diff/include/linux/nfsd/nfsfh.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/nfsd/nfsfh.h	2004-03-09 11:51:51.000000000 +0000
@@ -66,8 +66,9 @@ struct nfs_fhbase_old {
  *     0  - 4 byte device id (ms-2-bytes major, ls-2-bytes minor), 4byte inode number
  *        NOTE: we cannot use the kdev_t device id value, because kdev_t.h
  *              says we mustn't.  We must break it up and reassemble.
- *  Possible future encodings:
  *     1  - 4 byte user specified identifier
+ *     2  - 4 byte major, 4 byte minor, 4 byte inode number - DEPRECATED
+ *     3  - 4 byte device id, encoded for user-space, 4 byte inode number
  *
  * The fileid_type identified how the file within the filesystem is encoded.
  * This is (will be) passed to, and set by, the underlying filesystem if it supports
@@ -114,6 +115,7 @@ struct knfsd_fh {
 #define	fh_auth_type		fh_base.fh_new.fb_auth_type
 #define	fh_fileid_type		fh_base.fh_new.fb_fileid_type
 #define	fh_auth			fh_base.fh_new.fb_auth
+#define	fh_fsid			fh_base.fh_new.fb_auth
 
 #ifdef __KERNEL__
 
@@ -183,6 +185,23 @@ static inline void mk_fsid_v2(u32 *fsidv
 	fsidv[2] = ino_t_to_u32(ino);
 }
 
+static inline void mk_fsid_v3(u32 *fsidv, dev_t dev, ino_t ino)
+{
+	fsidv[0] = new_encode_dev(dev);
+	fsidv[1] = ino_t_to_u32(ino);
+}
+
+static inline int key_len(int type)
+{
+	switch(type) {
+	case 0: return 8;
+	case 1: return 4;
+	case 2: return 12;
+	case 3: return 8;
+	default: return 0;
+	}
+}
+
 /*
  * Shorthand for dprintk()'s
  */
--- diff/include/linux/notifier.h	2002-11-11 11:09:38.000000000 +0000
+++ source/include/linux/notifier.h	2004-03-09 11:51:51.000000000 +0000
@@ -63,7 +63,6 @@ extern int notifier_call_chain(struct no
 #define CPU_ONLINE	0x0002 /* CPU (unsigned)v is up */
 #define CPU_UP_PREPARE	0x0003 /* CPU (unsigned)v coming up */
 #define CPU_UP_CANCELED	0x0004 /* CPU (unsigned)v NOT coming up */
-#define CPU_OFFLINE	0x0005 /* CPU (unsigned)v offline (still scheduling) */
 #define CPU_DEAD	0x0006 /* CPU (unsigned)v dead */
 
 #endif /* __KERNEL__ */
--- diff/include/linux/page-flags.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/linux/page-flags.h	2004-03-09 11:51:51.000000000 +0000
@@ -98,23 +98,38 @@ struct page_state {
 	unsigned long pgpgout;		/* Disk writes */
 	unsigned long pswpin;		/* swap reads */
 	unsigned long pswpout;		/* swap writes */
-	unsigned long pgalloc;		/* page allocations */
+	unsigned long pgalloc_high;	/* page allocations */
 
+	unsigned long pgalloc_normal;
+	unsigned long pgalloc_dma;
 	unsigned long pgfree;		/* page freeings */
 	unsigned long pgactivate;	/* pages moved inactive->active */
 	unsigned long pgdeactivate;	/* pages moved active->inactive */
+
 	unsigned long pgfault;		/* faults (major+minor) */
 	unsigned long pgmajfault;	/* faults (major only) */
-
-	unsigned long pgscan;		/* pages scanned by page reclaim */
-	unsigned long pgrefill;		/* inspected in refill_inactive_zone */
-	unsigned long pgsteal;		/* total pages reclaimed */
+	unsigned long pgrefill_high;	/* inspected in refill_inactive_zone */
+	unsigned long pgrefill_normal;
+	unsigned long pgrefill_dma;
+
+	unsigned long pgsteal_high;	/* total highmem pages reclaimed */
+	unsigned long pgsteal_normal;
+	unsigned long pgsteal_dma;
+	unsigned long pgscan_kswapd_high;/* total highmem pages scanned */
+	unsigned long pgscan_kswapd_normal;
+
+	unsigned long pgscan_kswapd_dma;
+	unsigned long pgscan_direct_high;/* total highmem pages scanned */
+	unsigned long pgscan_direct_normal;
+	unsigned long pgscan_direct_dma;
 	unsigned long pginodesteal;	/* pages reclaimed via inode freeing */
-	unsigned long kswapd_steal;	/* pages reclaimed by kswapd */
 
+	unsigned long slabs_scanned;	/* slab objects scanned */
+	unsigned long kswapd_steal;	/* pages reclaimed by kswapd */
 	unsigned long kswapd_inodesteal;/* reclaimed via kswapd inode freeing */
 	unsigned long pageoutrun;	/* kswapd's calls to page reclaim */
 	unsigned long allocstall;	/* direct reclaim calls */
+
 	unsigned long pgrotated;	/* pages rotated to tail of the LRU */
 } ____cacheline_aligned;
 
@@ -131,11 +146,24 @@ extern void get_full_page_state(struct p
 		local_irq_restore(flags);				\
 	} while (0)
 
+
 #define inc_page_state(member)	mod_page_state(member, 1UL)
 #define dec_page_state(member)	mod_page_state(member, 0UL - 1)
 #define add_page_state(member,delta) mod_page_state(member, (delta))
 #define sub_page_state(member,delta) mod_page_state(member, 0UL - (delta))
 
+#define mod_page_state_zone(zone, member, delta)			\
+	do {								\
+		unsigned long flags;					\
+		local_irq_save(flags);					\
+		if (is_highmem(zone))					\
+			__get_cpu_var(page_states).member##_high += (delta);\
+		else if (is_normal(zone))				\
+			__get_cpu_var(page_states).member##_normal += (delta);\
+		else							\
+			__get_cpu_var(page_states).member##_dma += (delta);\
+		local_irq_restore(flags);				\
+	} while (0)
 
 /*
  * Manipulation of page state flags
--- diff/include/linux/pci.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/pci.h	2004-03-09 11:51:51.000000000 +0000
@@ -393,11 +393,6 @@ struct pci_dev {
 					   this if your device has broken DMA
 					   or supports 64-bit transfers.  */
 
-	u64		consistent_dma_mask;/* Like dma_mask, but for
-					       pci_alloc_consistent mappings as
-					       not all hardware supports
-					       64 bit addresses for consistent
-					       allocations such descriptors. */
 	u32             current_state;  /* Current operating state. In ACPI-speak,
 					   this is D0-D3, D0 being fully functional,
 					   and D3 being off. */
@@ -724,6 +719,10 @@ extern int msi_free_vectors(struct pci_d
 
 #include <asm/pci.h>
 
+/* Backwards compat, remove in 2.7.x */
+#define pci_dma_sync_single	pci_dma_sync_single_for_cpu
+#define pci_dma_sync_sg		pci_dma_sync_sg_for_cpu
+
 /*
  *  If the system does not have PCI, clearly these return errors.  Define
  *  these as simple inline functions to avoid hair in drivers.
--- diff/include/linux/pci_ids.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/pci_ids.h	2004-03-09 11:51:51.000000000 +0000
@@ -342,6 +342,8 @@
 #define PCI_DEVICE_ID_ATI_RS300_133	0x5831
 #define PCI_DEVICE_ID_ATI_RS300_166	0x5832
 #define PCI_DEVICE_ID_ATI_RS300_200	0x5833
+/* ATI IXP Chipset */
+#define PCI_DEVICE_ID_ATI_IXP_IDE	0x4349
 
 #define PCI_VENDOR_ID_VLSI		0x1004
 #define PCI_DEVICE_ID_VLSI_82C592	0x0005
@@ -1808,6 +1810,7 @@
 
 #define PCI_VENDOR_ID_AFAVLAB		0x14db
 #define PCI_DEVICE_ID_AFAVLAB_P028	0x2180
+#define PCI_DEVICE_ID_AFAVLAB_P030	0x2182
 
 #define PCI_VENDOR_ID_BROADCOM		0x14e4
 #define PCI_DEVICE_ID_TIGON3_5700	0x1644
--- diff/include/linux/quota.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/linux/quota.h	2004-03-09 11:51:51.000000000 +0000
@@ -138,6 +138,10 @@ struct if_dqinfo {
 #include <linux/dqblk_v1.h>
 #include <linux/dqblk_v2.h>
 
+/* Maximal numbers of writes for quota operation (insert/delete/update)
+ * (over all formats) - info block, 4 pointer blocks, data block */
+#define DQUOT_MAX_WRITES	6
+
 /*
  * Data for one user/group kept in memory
  */
@@ -168,22 +172,21 @@ struct mem_dqinfo {
 	} u;
 };
 
+struct super_block;
+
 #define DQF_MASK 0xffff		/* Mask for format specific flags */
 #define DQF_INFO_DIRTY_B 16
 #define DQF_ANY_DQUOT_DIRTY_B 17
 #define DQF_INFO_DIRTY (1 << DQF_INFO_DIRTY_B)	/* Is info dirty? */
 #define DQF_ANY_DQUOT_DIRTY (1 << DQF_ANY_DQUOT_DIRTY_B) /* Is any dquot dirty? */
 
-extern inline void mark_info_dirty(struct mem_dqinfo *info)
-{
-	set_bit(DQF_INFO_DIRTY_B, &info->dqi_flags);
-}
-
+extern void mark_info_dirty(struct super_block *sb, int type);
 #define info_dirty(info) test_bit(DQF_INFO_DIRTY_B, &(info)->dqi_flags)
 #define info_any_dquot_dirty(info) test_bit(DQF_ANY_DQUOT_DIRTY_B, &(info)->dqi_flags)
 #define info_any_dirty(info) (info_dirty(info) || info_any_dquot_dirty(info))
 
 #define sb_dqopt(sb) (&(sb)->s_dquot)
+#define sb_dqinfo(sb, type) (sb_dqopt(sb)->info+(type))
 
 struct dqstats {
 	int lookups;
@@ -200,15 +203,13 @@ extern struct dqstats dqstats;
 
 #define NR_DQHASH 43            /* Just an arbitrary number */
 
-#define DQ_MOD_B	0
-#define DQ_BLKS_B	1
-#define DQ_INODES_B	2
-#define DQ_FAKE_B	3
-
-#define DQ_MOD        (1 << DQ_MOD_B)	/* dquot modified since read */
-#define DQ_BLKS       (1 << DQ_BLKS_B)	/* uid/gid has been warned about blk limit */
-#define DQ_INODES     (1 << DQ_INODES_B)	/* uid/gid has been warned about inode limit */
-#define DQ_FAKE       (1 << DQ_FAKE_B)	/* no limits only usage */
+#define DQ_MOD_B	0	/* dquot modified since read */
+#define DQ_BLKS_B	1	/* uid/gid has been warned about blk limit */
+#define DQ_INODES_B	2	/* uid/gid has been warned about inode limit */
+#define DQ_FAKE_B	3	/* no limits only usage */
+#define DQ_READ_B	4	/* dquot was read into memory */
+#define DQ_ACTIVE_B	5	/* dquot is active (dquot_release not called) */
+#define DQ_WAITFREE_B	6	/* dquot being waited (by invalidate_dquots) */
 
 struct dquot {
 	struct list_head dq_hash;	/* Hash list in memory */
@@ -216,8 +217,7 @@ struct dquot {
 	struct list_head dq_free;	/* Free list element */
 	struct semaphore dq_lock;	/* dquot IO lock */
 	atomic_t dq_count;		/* Use count */
-
-	/* fields after this point are cleared when invalidating */
+	wait_queue_head_t dq_wait_unused;	/* Wait queue for dquot to become unused */
 	struct super_block *dq_sb;	/* superblock this applies to */
 	unsigned int dq_id;		/* ID this applies to (uid, gid) */
 	loff_t dq_off;			/* Offset of dquot on disk */
@@ -238,19 +238,22 @@ struct quota_format_ops {
 	int (*write_file_info)(struct super_block *sb, int type);	/* Write main info about file */
 	int (*free_file_info)(struct super_block *sb, int type);	/* Called on quotaoff() */
 	int (*read_dqblk)(struct dquot *dquot);		/* Read structure for one user */
-	int (*commit_dqblk)(struct dquot *dquot);	/* Write (or delete) structure for one user */
+	int (*commit_dqblk)(struct dquot *dquot);	/* Write structure for one user */
+	int (*release_dqblk)(struct dquot *dquot);	/* Called when last reference to dquot is being dropped */
 };
 
 /* Operations working with dquots */
 struct dquot_operations {
-	void (*initialize) (struct inode *, int);
-	void (*drop) (struct inode *);
+	int (*initialize) (struct inode *, int);
+	int (*drop) (struct inode *);
 	int (*alloc_space) (struct inode *, qsize_t, int);
 	int (*alloc_inode) (const struct inode *, unsigned long);
-	void (*free_space) (struct inode *, qsize_t);
-	void (*free_inode) (const struct inode *, unsigned long);
+	int (*free_space) (struct inode *, qsize_t);
+	int (*free_inode) (const struct inode *, unsigned long);
 	int (*transfer) (struct inode *, struct iattr *);
-	int (*write_dquot) (struct dquot *);
+	int (*write_dquot) (struct dquot *);		/* Ordinary dquot write */
+	int (*mark_dirty) (struct dquot *);		/* Dquot is marked dirty */
+	int (*write_info) (struct super_block *, int);	/* Write of quota "superblock" */
 };
 
 /* Operations handling requests from userspace */
@@ -289,10 +292,7 @@ struct quota_info {
 };
 
 /* Inline would be better but we need to dereference super_block which is not defined yet */
-#define mark_dquot_dirty(dquot) do {\
-	set_bit(DQF_ANY_DQUOT_DIRTY_B, &(sb_dqopt((dquot)->dq_sb)->info[(dquot)->dq_type].dqi_flags));\
-	set_bit(DQ_MOD_B, &(dquot)->dq_flags);\
-} while (0)
+int mark_dquot_dirty(struct dquot *dquot);
 
 #define dquot_dirty(dquot) test_bit(DQ_MOD_B, &(dquot)->dq_flags)
 
@@ -304,7 +304,6 @@ struct quota_info {
 
 int register_quota_format(struct quota_format_type *fmt);
 void unregister_quota_format(struct quota_format_type *fmt);
-void init_dquot_operations(struct dquot_operations *fsdqops);
 
 struct quota_module_name {
 	int qm_fmt_id;
--- diff/include/linux/quotaops.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/quotaops.h	2004-03-09 11:51:51.000000000 +0000
@@ -22,16 +22,31 @@
  */
 extern void sync_dquots(struct super_block *sb, int type);
 
-extern void dquot_initialize(struct inode *inode, int type);
-extern void dquot_drop(struct inode *inode);
+extern int dquot_initialize(struct inode *inode, int type);
+extern int dquot_drop(struct inode *inode);
 
-extern int  dquot_alloc_space(struct inode *inode, qsize_t number, int prealloc);
-extern int  dquot_alloc_inode(const struct inode *inode, unsigned long number);
+extern int dquot_alloc_space(struct inode *inode, qsize_t number, int prealloc);
+extern int dquot_alloc_inode(const struct inode *inode, unsigned long number);
 
-extern void dquot_free_space(struct inode *inode, qsize_t number);
-extern void dquot_free_inode(const struct inode *inode, unsigned long number);
+extern int dquot_free_space(struct inode *inode, qsize_t number);
+extern int dquot_free_inode(const struct inode *inode, unsigned long number);
 
-extern int  dquot_transfer(struct inode *inode, struct iattr *iattr);
+extern int dquot_transfer(struct inode *inode, struct iattr *iattr);
+extern int dquot_commit(struct dquot *dquot);
+extern int dquot_acquire(struct dquot *dquot);
+extern int dquot_release(struct dquot *dquot);
+extern int dquot_commit_info(struct super_block *sb, int type);
+extern int dquot_mark_dquot_dirty(struct dquot *dquot);
+
+extern int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path);
+extern int vfs_quota_on_mount(int type, int format_id, struct dentry *dentry);
+extern int vfs_quota_off(struct super_block *sb, int type);
+#define vfs_quota_off_mount(sb, type) vfs_quota_off(sb, type)
+extern int vfs_quota_sync(struct super_block *sb, int type);
+extern int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
+extern int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
+extern int vfs_get_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di);
+extern int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di);
 
 /*
  * Operations supported for diskquotas.
@@ -42,6 +57,8 @@ extern struct quotactl_ops vfs_quotactl_
 #define sb_dquot_ops (&dquot_operations)
 #define sb_quotactl_ops (&vfs_quotactl_ops)
 
+/* It is better to call this function outside of any transaction as it might
+ * need a lot of space in journal for dquot structure allocation. */
 static __inline__ void DQUOT_INIT(struct inode *inode)
 {
 	BUG_ON(!inode->i_sb);
@@ -49,6 +66,7 @@ static __inline__ void DQUOT_INIT(struct
 		inode->i_sb->dq_op->initialize(inode, -1);
 }
 
+/* The same as with DQUOT_INIT */
 static __inline__ void DQUOT_DROP(struct inode *inode)
 {
 	if (IS_QUOTAINIT(inode)) {
@@ -57,6 +75,8 @@ static __inline__ void DQUOT_DROP(struct
 	}
 }
 
+/* The following allocation/freeing/transfer functions *must* be called inside
+ * a transaction (deadlocks possible otherwise) */
 static __inline__ int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
 {
 	if (sb_any_quota_enabled(inode->i_sb)) {
@@ -64,11 +84,8 @@ static __inline__ int DQUOT_PREALLOC_SPA
 		if (inode->i_sb->dq_op->alloc_space(inode, nr, 1) == NO_QUOTA)
 			return 1;
 	}
-	else {
-		spin_lock(&dq_data_lock);
+	else
 		inode_add_bytes(inode, nr);
-		spin_unlock(&dq_data_lock);
-	}
 	return 0;
 }
 
@@ -87,11 +104,8 @@ static __inline__ int DQUOT_ALLOC_SPACE_
 		if (inode->i_sb->dq_op->alloc_space(inode, nr, 0) == NO_QUOTA)
 			return 1;
 	}
-	else {
-		spin_lock(&dq_data_lock);
+	else
 		inode_add_bytes(inode, nr);
-		spin_unlock(&dq_data_lock);
-	}
 	return 0;
 }
 
@@ -117,11 +131,8 @@ static __inline__ void DQUOT_FREE_SPACE_
 {
 	if (sb_any_quota_enabled(inode->i_sb))
 		inode->i_sb->dq_op->free_space(inode, nr);
-	else {
-		spin_lock(&dq_data_lock);
+	else
 		inode_sub_bytes(inode, nr);
-		spin_unlock(&dq_data_lock);
-	}
 }
 
 static __inline__ void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr)
@@ -146,6 +157,7 @@ static __inline__ int DQUOT_TRANSFER(str
 	return 0;
 }
 
+/* The following two functions cannot be called inside a transaction */
 #define DQUOT_SYNC(sb)	sync_dquots(sb, -1)
 
 static __inline__ int DQUOT_OFF(struct super_block *sb)
--- diff/include/linux/sched.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/sched.h	2004-03-09 11:51:51.000000000 +0000
@@ -147,6 +147,7 @@ extern spinlock_t mmlist_lock;
 typedef struct task_struct task_t;
 
 extern void sched_init(void);
+extern void sched_init_smp(void);
 extern void init_idle(task_t *idle, int cpu);
 
 extern void show_state(void);
@@ -193,7 +194,7 @@ struct mm_struct {
 	atomic_t mm_count;			/* How many references to "struct mm_struct" (users count as 1) */
 	int map_count;				/* number of VMAs */
 	struct rw_semaphore mmap_sem;
-	spinlock_t page_table_lock;		/* Protects task page tables and mm->rss */
+	spinlock_t page_table_lock;		/* Protects task page tables and RSS data */
 
 	struct list_head mmlist;		/* List of all active mm's.  These are globally strung
 						 * together off init_mm.mmlist, and are protected
@@ -203,7 +204,11 @@ struct mm_struct {
 	unsigned long start_code, end_code, start_data, end_data;
 	unsigned long start_brk, brk, start_stack;
 	unsigned long arg_start, arg_end, env_start, env_end;
-	unsigned long rss, total_vm, locked_vm;
+	unsigned long total_vm, locked_vm;
+	unsigned long rss;
+#ifdef CONFIG_NUMA
+	unsigned long pernode_rss[MAX_NUMNODES];
+#endif
 	unsigned long def_flags;
 
 	unsigned long saved_auxv[40]; /* for /proc/PID/auxv */
@@ -527,8 +532,111 @@ do { if (atomic_dec_and_test(&(tsk)->usa
 #define PF_SWAPOFF	0x00080000	/* I am in swapoff */
 #define PF_LESS_THROTTLE 0x00100000	/* Throttle me less: I clean memory */
 #define PF_SYNCWRITE	0x00200000	/* I am doing a sync write */
+#define PF_FUTEX_DEBUG	0x00400000
 
 #ifdef CONFIG_SMP
+#define SCHED_LOAD_SHIFT 7	/* increase resolution of load calculations */
+#define SCHED_LOAD_SCALE (1UL << SCHED_LOAD_SHIFT)
+
+#define SD_FLAG_NEWIDLE		1	/* Balance when about to become idle */
+#define SD_FLAG_EXEC		2	/* Balance on exec */
+#define SD_FLAG_WAKE		4	/* Balance on task wakeup */
+#define SD_FLAG_FASTMIGRATE	8	/* Sync wakes put task on waking CPU */
+#define SD_FLAG_SHARE_CPUPOWER	16	/* Domain members share cpu power */
+
+struct sched_group {
+	struct sched_group *next;	/* Must be a circular list */
+	cpumask_t cpumask;
+
+	/*
+	 * CPU power of this group, SCHED_LOAD_SCALE being max power for a
+	 * single CPU. This should be read only (except for setup). Although
+	 * it will need to be written to at cpu hot(un)plug time, perhaps the
+	 * cpucontrol semaphore will provide enough exclusion?
+	 */
+	unsigned long cpu_power;
+};
+
+struct sched_domain {
+	/* These fields must be setup */
+	struct sched_domain *parent;	/* top domain must be null terminated */
+	struct sched_group *groups;	/* the balancing groups of the domain */
+	cpumask_t span;			/* span of all CPUs in this domain */
+	unsigned long min_interval;	/* Minimum balance interval ms */
+	unsigned long max_interval;	/* Maximum balance interval ms */
+	unsigned int busy_factor;	/* less balancing by factor if busy */
+	unsigned int imbalance_pct;	/* No balance until over watermark */
+	unsigned long long cache_hot_time; /* Task considered cache hot (ns) */
+	unsigned int cache_nice_tries;	/* Leave cache hot tasks for # tries */
+	unsigned int per_cpu_gain;	/* CPU % gained by adding domain cpus */
+	int flags;			/* See SD_FLAG_* */
+
+	/* Runtime fields. */
+	unsigned long last_balance;	/* init to jiffies. units in jiffies */
+	unsigned int balance_interval;	/* initialise to 1. units in ms. */
+	unsigned int nr_balance_failed; /* initialise to 0 */
+};
+
+/* Common values for SMT siblings */
+#define SD_SIBLING_INIT (struct sched_domain) {		\
+	.span			= CPU_MASK_NONE,	\
+	.parent			= NULL,			\
+	.groups			= NULL,			\
+	.min_interval		= 1,			\
+	.max_interval		= 2,			\
+	.busy_factor		= 8,			\
+	.imbalance_pct		= 110,			\
+	.cache_hot_time		= 0,			\
+	.cache_nice_tries	= 0,			\
+	.per_cpu_gain		= 15,			\
+	.flags			= SD_FLAG_FASTMIGRATE | SD_FLAG_NEWIDLE | SD_FLAG_WAKE,\
+	.last_balance		= jiffies,		\
+	.balance_interval	= 1,			\
+	.nr_balance_failed	= 0,			\
+}
+
+/* Common values for CPUs */
+#define SD_CPU_INIT (struct sched_domain) {		\
+	.span			= CPU_MASK_NONE,	\
+	.parent			= NULL,			\
+	.groups			= NULL,			\
+	.min_interval		= 1,			\
+	.max_interval		= 4,			\
+	.busy_factor		= 64,			\
+	.imbalance_pct		= 125,			\
+	.cache_hot_time		= (5*1000000/2),	\
+	.cache_nice_tries	= 1,			\
+	.per_cpu_gain		= 100,			\
+	.flags			= SD_FLAG_FASTMIGRATE | SD_FLAG_NEWIDLE,\
+	.last_balance		= jiffies,		\
+	.balance_interval	= 1,			\
+	.nr_balance_failed	= 0,			\
+}
+
+#ifdef CONFIG_NUMA
+/* Common values for NUMA nodes */
+#define SD_NODE_INIT (struct sched_domain) {		\
+	.span			= CPU_MASK_NONE,	\
+	.parent			= NULL,			\
+	.groups			= NULL,			\
+	.min_interval		= 8,			\
+	.max_interval		= 256*fls(num_online_cpus()),\
+	.busy_factor		= 8,			\
+	.imbalance_pct		= 125,			\
+	.cache_hot_time		= (10*1000000),		\
+	.cache_nice_tries	= 1,			\
+	.per_cpu_gain		= 100,			\
+	.flags			= SD_FLAG_EXEC,		\
+	.last_balance		= jiffies,		\
+	.balance_interval	= 1,			\
+	.nr_balance_failed	= 0,			\
+}
+#endif
+
+DECLARE_PER_CPU(struct sched_domain, base_domains);
+#define cpu_sched_domain(cpu)	(&per_cpu(base_domains, (cpu)))
+#define this_sched_domain()	(&__get_cpu_var(base_domains))
+
 extern int set_cpus_allowed(task_t *p, cpumask_t new_mask);
 #else
 static inline int set_cpus_allowed(task_t *p, cpumask_t new_mask)
@@ -541,12 +649,14 @@ extern unsigned long long sched_clock(vo
 
 #ifdef CONFIG_NUMA
 extern void sched_balance_exec(void);
-extern void node_nr_running_init(void);
 #else
 #define sched_balance_exec()   {}
-#define node_nr_running_init() {}
 #endif
 
+/* Move tasks off this (offline) CPU onto another. */
+extern void migrate_all_tasks(void);
+/* Try to move me here, if possible. */
+void migrate_to_cpu(int dest_cpu);
 extern void set_user_nice(task_t *p, long nice);
 extern int task_prio(task_t *p);
 extern int task_nice(task_t *p);
@@ -602,7 +712,7 @@ extern void do_timer(struct pt_regs *);
 extern int FASTCALL(wake_up_state(struct task_struct * tsk, unsigned int state));
 extern int FASTCALL(wake_up_process(struct task_struct * tsk));
 #ifdef CONFIG_SMP
- extern void FASTCALL(kick_process(struct task_struct * tsk));
+ extern void kick_process(struct task_struct *tsk);
 #else
  static inline void kick_process(struct task_struct *tsk) { }
 #endif
--- diff/include/linux/security.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/security.h	2004-03-09 11:51:51.000000000 +0000
@@ -177,7 +177,7 @@ struct swap_info_struct;
  *	options cleanly (a filesystem may modify the data e.g. with strsep()).
  *	This also allows the original mount data to be stripped of security-
  *	specific options to avoid having to make filesystems aware of them.
- *	@fstype the type of filesystem being mounted.
+ *	@type the type of filesystem being mounted.
  *	@orig the original mount data copied from userspace.
  *	@copy copied data which will be passed to the security module.
  *	Returns 0 if the copy was successful.
@@ -1033,7 +1033,8 @@ struct security_operations {
 
 	int (*sb_alloc_security) (struct super_block * sb);
 	void (*sb_free_security) (struct super_block * sb);
-	int (*sb_copy_data)(const char *fstype, void *orig, void *copy);
+	int (*sb_copy_data)(struct file_system_type *type,
+			    void *orig, void *copy);
 	int (*sb_kern_mount) (struct super_block *sb, void *data);
 	int (*sb_statfs) (struct super_block * sb);
 	int (*sb_mount) (char *dev_name, struct nameidata * nd,
@@ -1318,9 +1319,10 @@ static inline void security_sb_free (str
 	security_ops->sb_free_security (sb);
 }
 
-static inline int security_sb_copy_data (const char *fstype, void *orig, void *copy)
+static inline int security_sb_copy_data (struct file_system_type *type,
+					 void *orig, void *copy)
 {
-	return security_ops->sb_copy_data (fstype, orig, copy);
+	return security_ops->sb_copy_data (type, orig, copy);
 }
 
 static inline int security_sb_kern_mount (struct super_block *sb, void *data)
@@ -1988,7 +1990,8 @@ static inline int security_sb_alloc (str
 static inline void security_sb_free (struct super_block *sb)
 { }
 
-static inline int security_sb_copy_data (const char *fstype, void *orig, void *copy)
+static inline int security_sb_copy_data (struct file_system_type *type,
+					 void *orig, void *copy)
 {
 	return 0;
 }
--- diff/include/linux/sem.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/sem.h	2004-03-09 11:51:51.000000000 +0000
@@ -134,7 +134,22 @@ struct sysv_sem {
 	struct sem_undo_list *undo_list;
 };
 
-void exit_sem(struct task_struct *p);
+#ifdef CONFIG_SYSVIPC
+
+extern int copy_semundo(unsigned long clone_flags, struct task_struct *tsk);
+extern void exit_sem(struct task_struct *tsk);
+
+#else
+static inline int copy_semundo(unsigned long clone_flags, struct task_struct *tsk)
+{
+	return 0;
+}
+
+static inline void exit_sem(struct task_struct *tsk)
+{
+	return;
+}
+#endif
 
 #endif /* __KERNEL__ */
 
--- diff/include/linux/serial_core.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/serial_core.h	2004-03-09 11:51:51.000000000 +0000
@@ -84,6 +84,7 @@
 #include <linux/interrupt.h>
 #include <linux/circ_buf.h>
 #include <linux/spinlock.h>
+#include <linux/sched.h>
 
 struct uart_port;
 struct uart_info;
@@ -159,7 +160,9 @@ struct uart_port {
 	unsigned char		x_char;			/* xon/xoff char */
 	unsigned char		regshift;		/* reg offset shift */
 	unsigned char		iotype;			/* io access style */
-
+#ifdef CONFIG_KGDB
+	int			kgdb;			/* in use by kgdb */
+#endif
 #define UPIO_PORT		(0)
 #define UPIO_HUB6		(1)
 #define UPIO_MEM		(2)
--- diff/include/linux/serio.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/linux/serio.h	2004-03-09 11:51:51.000000000 +0000
@@ -117,6 +117,7 @@ static __inline__ void serio_cleanup(str
 #define SERIO_MZ	0x05
 #define SERIO_MZP	0x06
 #define SERIO_MZPP	0x07
+#define SERIO_VSXXXAA	0x08
 #define SERIO_SUNKBD	0x10
 #define SERIO_WARRIOR	0x18
 #define SERIO_SPACEORB	0x19
@@ -134,6 +135,7 @@ static __inline__ void serio_cleanup(str
 #define SERIO_HIL	0x25
 #define SERIO_SNES232	0x26
 #define SERIO_SEMTECH	0x27
+#define SERIO_LKKBD	0x28
 
 #define SERIO_ID	0xff00UL
 #define SERIO_EXTRA	0xff0000UL
--- diff/include/linux/smp.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/smp.h	2004-03-09 11:51:51.000000000 +0000
@@ -30,7 +30,7 @@ extern void smp_send_stop(void);
 /*
  * sends a 'reschedule' event to another CPU:
  */
-extern void FASTCALL(smp_send_reschedule(int cpu));
+extern void smp_send_reschedule(int cpu);
 
 
 /*
--- diff/include/linux/socket.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/socket.h	2004-03-09 11:51:51.000000000 +0000
@@ -178,7 +178,8 @@ struct ucred {
 #define AF_WANPIPE	25	/* Wanpipe API Sockets */
 #define AF_LLC		26	/* Linux LLC			*/
 #define AF_BLUETOOTH	31	/* Bluetooth sockets 		*/
-#define AF_MAX		32	/* For now.. */
+#define AF_IPMI		32	/* IPMI sockers 		*/
+#define AF_MAX		33	/* For now.. */
 
 /* Protocol families, same as address families. */
 #define PF_UNSPEC	AF_UNSPEC
@@ -210,6 +211,7 @@ struct ucred {
 #define PF_WANPIPE	AF_WANPIPE
 #define PF_LLC		AF_LLC
 #define PF_BLUETOOTH	AF_BLUETOOTH
+#define PF_IPMI		AF_IPMI
 #define PF_MAX		AF_MAX
 
 /* Maximum queue length specifiable by listen.  */
--- diff/include/linux/spinlock.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/linux/spinlock.h	2004-03-09 11:51:51.000000000 +0000
@@ -15,6 +15,12 @@
 
 #include <asm/processor.h>	/* for cpu relax */
 #include <asm/system.h>
+#ifdef CONFIG_KGDB
+#include <asm/current.h>
+#define SET_WHO(x, him) (x)->who = him;
+#else
+#define SET_WHO(x, him)
+#endif
 
 /*
  * Must define these before including other files, inline functions need them
@@ -55,6 +61,9 @@ typedef struct {
 	const char *module;
 	char *owner;
 	int oline;
+#ifdef CONFIG_KGDB
+	struct task_struct *who;
+#endif
 } spinlock_t;
 #define SPIN_LOCK_UNLOCKED (spinlock_t) { SPINLOCK_MAGIC, 0, 10, __FILE__ , NULL, 0}
 
@@ -66,6 +75,7 @@ typedef struct {
 		(x)->module = __FILE__; \
 		(x)->owner = NULL; \
 		(x)->oline = 0; \
+                SET_WHO(x, NULL) \
 	} while (0)
 
 #define CHECK_LOCK(x) \
@@ -88,6 +98,7 @@ typedef struct {
 		(x)->lock = 1; \
 		(x)->owner = __FILE__; \
 		(x)->oline = __LINE__; \
+                SET_WHO(x, current)       \
 	} while (0)
 
 /* without debugging, spin_is_locked on UP always says
@@ -118,6 +129,7 @@ typedef struct {
 		(x)->lock = 1; \
 		(x)->owner = __FILE__; \
 		(x)->oline = __LINE__; \
+                SET_WHO(x, current)       \
 		1; \
 	})
 
@@ -184,6 +196,17 @@ typedef struct {
 
 #endif /* !SMP */
 
+#ifdef CONFIG_LOCKMETER
+extern void _metered_spin_lock   (spinlock_t *lock);
+extern void _metered_spin_unlock (spinlock_t *lock);
+extern int  _metered_spin_trylock(spinlock_t *lock);
+extern void _metered_read_lock    (rwlock_t *lock);
+extern void _metered_read_unlock  (rwlock_t *lock);
+extern void _metered_write_lock   (rwlock_t *lock);
+extern void _metered_write_unlock (rwlock_t *lock);
+extern int  _metered_write_trylock(rwlock_t *lock);
+#endif
+
 /*
  * Define the various spin_lock and rw_lock methods.  Note we define these
  * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various
@@ -389,6 +412,141 @@ do { \
 				_raw_spin_trylock(lock) ? 1 : \
 				({preempt_enable(); local_bh_enable(); 0;});})
 
+#ifdef CONFIG_LOCKMETER
+#undef spin_lock
+#undef spin_trylock
+#undef spin_unlock
+#undef spin_lock_irqsave
+#undef spin_lock_irq
+#undef spin_lock_bh
+#undef read_lock
+#undef read_unlock
+#undef write_lock
+#undef write_unlock
+#undef write_trylock
+#undef spin_unlock_bh
+#undef read_lock_irqsave
+#undef read_lock_irq
+#undef read_lock_bh
+#undef read_unlock_bh
+#undef write_lock_irqsave
+#undef write_lock_irq
+#undef write_lock_bh
+#undef write_unlock_bh
+
+#define spin_lock(lock) \
+do { \
+	preempt_disable(); \
+	_metered_spin_lock(lock); \
+} while(0)
+
+#define spin_trylock(lock)     ({preempt_disable(); _metered_spin_trylock(lock) ? \
+				1 : ({preempt_enable(); 0;});})
+#define spin_unlock(lock) \
+do { \
+	_metered_spin_unlock(lock); \
+	preempt_enable(); \
+} while (0)
+
+#define spin_lock_irqsave(lock, flags) \
+do { \
+	local_irq_save(flags); \
+	preempt_disable(); \
+	_metered_spin_lock(lock); \
+} while (0)
+
+#define spin_lock_irq(lock) \
+do { \
+	local_irq_disable(); \
+	preempt_disable(); \
+	_metered_spin_lock(lock); \
+} while (0)
+
+#define spin_lock_bh(lock) \
+do { \
+	local_bh_disable(); \
+	preempt_disable(); \
+	_metered_spin_lock(lock); \
+} while (0)
+
+#define spin_unlock_bh(lock) \
+do { \
+	_metered_spin_unlock(lock); \
+	preempt_enable(); \
+	local_bh_enable(); \
+} while (0)
+
+
+#define read_lock(lock)                ({preempt_disable(); _metered_read_lock(lock);})
+#define read_unlock(lock)      ({_metered_read_unlock(lock); preempt_enable();})
+#define write_lock(lock)       ({preempt_disable(); _metered_write_lock(lock);})
+#define write_unlock(lock)     ({_metered_write_unlock(lock); preempt_enable();})
+#define write_trylock(lock)    ({preempt_disable();_metered_write_trylock(lock) ? \
+				1 : ({preempt_enable(); 0;});})
+#define spin_unlock_no_resched(lock) \
+do { \
+	_metered_spin_unlock(lock); \
+	preempt_enable_no_resched(); \
+} while (0)
+
+#define read_lock_irqsave(lock, flags) \
+do { \
+	local_irq_save(flags); \
+	preempt_disable(); \
+	_metered_read_lock(lock); \
+} while (0)
+
+#define read_lock_irq(lock) \
+do { \
+	local_irq_disable(); \
+	preempt_disable(); \
+	_metered_read_lock(lock); \
+} while (0)
+
+#define read_lock_bh(lock) \
+do { \
+	local_bh_disable(); \
+	preempt_disable(); \
+	_metered_read_lock(lock); \
+} while (0)
+
+#define read_unlock_bh(lock) \
+do { \
+	_metered_read_unlock(lock); \
+	preempt_enable(); \
+	local_bh_enable(); \
+} while (0)
+
+#define write_lock_irqsave(lock, flags) \
+do { \
+	local_irq_save(flags); \
+	preempt_disable(); \
+	_metered_write_lock(lock); \
+} while (0)
+
+#define write_lock_irq(lock) \
+do { \
+	local_irq_disable(); \
+	preempt_disable(); \
+	_metered_write_lock(lock); \
+} while (0)
+
+#define write_lock_bh(lock) \
+do { \
+	local_bh_disable(); \
+	preempt_disable(); \
+	_metered_write_lock(lock); \
+} while (0)
+
+#define write_unlock_bh(lock) \
+do { \
+	_metered_write_unlock(lock); \
+	preempt_enable(); \
+	local_bh_enable(); \
+} while (0)
+
+#endif /* !CONFIG_LOCKMETER */
+
 /* "lock on reference count zero" */
 #ifndef ATOMIC_DEC_AND_LOCK
 #include <asm/atomic.h>
--- diff/include/linux/sunrpc/debug.h	2003-07-08 09:55:19.000000000 +0100
+++ source/include/linux/sunrpc/debug.h	2004-03-09 11:51:51.000000000 +0000
@@ -54,7 +54,7 @@ extern unsigned int		nlm_debug;
 
 #undef ifdebug
 #ifdef RPC_DEBUG			
-# define ifdebug(fac)		if (rpc_debug & RPCDBG_##fac)
+# define ifdebug(fac)		if (unlikely(rpc_debug & RPCDBG_##fac))
 # define dfprintk(fac, args...)	do { ifdebug(fac) printk(args); } while(0)
 # define RPC_IFDEBUG(x)		x
 #else
@@ -92,6 +92,8 @@ enum {
 	CTL_NFSDEBUG,
 	CTL_NFSDDEBUG,
 	CTL_NLMDEBUG,
+	CTL_SLOTTABLE_UDP,
+	CTL_SLOTTABLE_TCP,
 };
 
 #endif /* _LINUX_SUNRPC_DEBUG_H_ */
--- diff/include/linux/sunrpc/timer.h	2003-10-09 09:47:34.000000000 +0100
+++ source/include/linux/sunrpc/timer.h	2004-03-09 11:51:51.000000000 +0000
@@ -25,9 +25,18 @@ extern unsigned long rpc_calc_rto(struct
 
 static inline void rpc_set_timeo(struct rpc_rtt *rt, int timer, int ntimeo)
 {
+	int *t;
 	if (!timer)
 		return;
-	rt->ntimeouts[timer-1] = ntimeo;
+	t = &rt->ntimeouts[timer-1];
+	if (ntimeo < *t) {
+		if (*t > 0)
+			(*t)--;
+	} else {
+		if (ntimeo > 8)
+			ntimeo = 8;
+		*t = ntimeo;
+	}
 }
 
 static inline int rpc_ntimeo(struct rpc_rtt *rt, int timer)
--- diff/include/linux/sunrpc/xdr.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/sunrpc/xdr.h	2004-03-09 11:51:51.000000000 +0000
@@ -87,7 +87,7 @@ struct xdr_buf {
 /*
  * Miscellaneous XDR helper functions
  */
-u32 *	xdr_encode_array(u32 *p, const char *s, unsigned int len);
+u32 *	xdr_encode_array(u32 *p, const void *s, unsigned int len);
 u32 *	xdr_encode_string(u32 *p, const char *s);
 u32 *	xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen);
 u32 *	xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen);
--- diff/include/linux/sunrpc/xprt.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/sunrpc/xprt.h	2004-03-09 11:51:51.000000000 +0000
@@ -28,16 +28,18 @@
  *
  * Upper procedures may check whether a request would block waiting for
  * a free RPC slot by using the RPC_CONGESTED() macro.
- *
- * Note: on machines with low memory we should probably use a smaller
- * MAXREQS value: At 32 outstanding reqs with 8 megs of RAM, fragment
- * reassembly will frequently run out of memory.
- */
-#define RPC_MAXCONG		(16)
-#define RPC_MAXREQS		RPC_MAXCONG
-#define RPC_CWNDSCALE		(256)
-#define RPC_MAXCWND		(RPC_MAXCONG * RPC_CWNDSCALE)
+ */
+extern unsigned int xprt_udp_slot_table_entries;
+extern unsigned int xprt_tcp_slot_table_entries;
+
+#define RPC_MIN_SLOT_TABLE	(2U)
+#define RPC_DEF_SLOT_TABLE	(16U)
+#define RPC_MAX_SLOT_TABLE	(128U)
+
+#define RPC_CWNDSHIFT		(8U)
+#define RPC_CWNDSCALE		(1U << RPC_CWNDSHIFT)
 #define RPC_INITCWND		RPC_CWNDSCALE
+#define RPC_MAXCWND(xprt)	((xprt)->max_reqs << RPC_CWNDSHIFT)
 #define RPCXPRT_CONGESTED(xprt) ((xprt)->cong >= (xprt)->cwnd)
 
 /* Default timeout values */
@@ -92,7 +94,6 @@ struct rpc_rqst {
 	 */
 	struct rpc_task *	rq_task;	/* RPC task data */
 	__u32			rq_xid;		/* request XID */
-	struct rpc_rqst *	rq_next;	/* free list */
 	int			rq_cong;	/* has incremented xprt->cong */
 	int			rq_received;	/* receive completed */
 	u32			rq_seqno;	/* gss seq no. used on req. */
@@ -102,7 +103,6 @@ struct rpc_rqst {
 	struct xdr_buf		rq_private_buf;		/* The receive buffer
 							 * used in the softirq.
 							 */
-
 	/*
 	 * For authentication (e.g. auth_des)
 	 */
@@ -146,8 +146,9 @@ struct rpc_xprt {
 	struct rpc_wait_queue	resend;		/* requests waiting to resend */
 	struct rpc_wait_queue	pending;	/* requests in flight */
 	struct rpc_wait_queue	backlog;	/* waiting for slot */
-	struct rpc_rqst *	free;		/* free slots */
-	struct rpc_rqst		slot[RPC_MAXREQS];
+	struct list_head	free;		/* free slots */
+	struct rpc_rqst *	slot;		/* slot table storage */
+	unsigned int		max_reqs;	/* total slots */
 	unsigned long		sockstate;	/* Socket state */
 	unsigned char		shutdown   : 1,	/* being shut down */
 				nocong	   : 1,	/* no congestion control */
@@ -155,6 +156,11 @@ struct rpc_xprt {
 				stream     : 1;	/* TCP */
 
 	/*
+	 * XID
+	 */
+	__u32			xid;		/* Next XID value to use */
+
+	/*
 	 * State of TCP reply receive stuff
 	 */
 	u32			tcp_recm,	/* Fragment header */
@@ -164,6 +170,11 @@ struct rpc_xprt {
 	unsigned long		tcp_copied,	/* copied to request */
 				tcp_flags;
 	/*
+	 * Connection of sockets
+	 */
+	struct work_struct	sock_connect;
+	unsigned short		port;
+	/*
 	 * Disconnection of idle sockets
 	 */
 	struct work_struct	task_cleanup;
--- diff/include/linux/syscalls.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/syscalls.h	2004-03-09 11:51:51.000000000 +0000
@@ -48,6 +48,8 @@ struct timex;
 struct timezone;
 struct tms;
 struct utimbuf;
+typedef int mqd_t;
+struct mq_attr;
 
 #include <linux/config.h>
 #include <linux/types.h>
@@ -252,7 +254,10 @@ asmlinkage long sys_mprotect(unsigned lo
 asmlinkage unsigned long sys_mremap(unsigned long addr,
 				unsigned long old_len, unsigned long new_len,
 				unsigned long flags, unsigned long new_addr);
-long sys_remap_file_pages(unsigned long start, unsigned long size,
+asmlinkage long old_remap_file_pages(unsigned long start, unsigned long size,
+			unsigned long __prot, unsigned long pgoff,
+			unsigned long flags);
+asmlinkage long sys_remap_file_pages(unsigned long start, unsigned long size,
 			unsigned long prot, unsigned long pgoff,
 			unsigned long flags);
 asmlinkage long sys_msync(unsigned long start, size_t len, int flags);
@@ -386,24 +391,24 @@ asmlinkage long sys_getdents64(unsigned 
 				unsigned int count);
 
 asmlinkage long sys_setsockopt(int fd, int level, int optname,
-				char *optval, int optlen);
+				char __user *optval, int optlen);
 asmlinkage long sys_getsockopt(int fd, int level, int optname,
 				char __user *optval, int __user *optlen);
-asmlinkage long sys_bind(int, struct sockaddr *, int);
-asmlinkage long sys_connect(int, struct sockaddr *, int);
-asmlinkage long sys_accept(int, struct sockaddr *, int *);
-asmlinkage long sys_getsockname(int, struct sockaddr *, int *);
-asmlinkage long sys_getpeername(int, struct sockaddr *, int *);
-asmlinkage long sys_send(int, void *, size_t, unsigned);
-asmlinkage long sys_sendto(int, void *, size_t, unsigned,
-				struct sockaddr *, int);
+asmlinkage long sys_bind(int, struct sockaddr __user *, int);
+asmlinkage long sys_connect(int, struct sockaddr __user *, int);
+asmlinkage long sys_accept(int, struct sockaddr __user *, int __user *);
+asmlinkage long sys_getsockname(int, struct sockaddr __user *, int __user *);
+asmlinkage long sys_getpeername(int, struct sockaddr __user *, int __user *);
+asmlinkage long sys_send(int, void __user *, size_t, unsigned);
+asmlinkage long sys_sendto(int, void __user *, size_t, unsigned,
+				struct sockaddr __user *, int);
 asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags);
-asmlinkage long sys_recv(int, void *, size_t, unsigned);
-asmlinkage long sys_recvfrom(int, void *, size_t, unsigned,
-				struct sockaddr *, int *);
+asmlinkage long sys_recv(int, void __user *, size_t, unsigned);
+asmlinkage long sys_recvfrom(int, void __user *, size_t, unsigned,
+				struct sockaddr __user *, int __user *);
 asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags);
 asmlinkage long sys_socket(int, int, int);
-asmlinkage long sys_socketpair(int, int, int, int [2]);
+asmlinkage long sys_socketpair(int, int, int, int __user *);
 asmlinkage long sys_socketcall(int call, unsigned long __user *args);
 asmlinkage long sys_listen(int, int);
 asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,
@@ -450,6 +455,13 @@ asmlinkage long sys_shmget(key_t key, si
 asmlinkage long sys_shmdt(char __user *shmaddr);
 asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf);
 
+asmlinkage long sys_mq_open(const char __user *name, int oflag, mode_t mode, struct mq_attr __user *attr);
+asmlinkage long sys_mq_unlink(const char __user *name);
+asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec __user *abs_timeout);
+asmlinkage ssize_t sys_mq_timedreceive(mqd_t mqdes, char __user *msg_ptr, size_t msg_len, unsigned int __user *msg_prio, const struct timespec __user *abs_timeout);
+asmlinkage long sys_mq_notify(mqd_t mqdes, const struct sigevent __user *notification);
+asmlinkage long sys_mq_getsetattr(mqd_t mqdes, const struct mq_attr __user *mqstat, struct mq_attr __user *omqstat);
+
 asmlinkage long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn);
 asmlinkage long sys_pciconfig_read(unsigned long bus, unsigned long dfn,
 				unsigned long off, unsigned long len,
--- diff/include/linux/sysctl.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/sysctl.h	2004-03-09 11:51:51.000000000 +0000
@@ -158,6 +158,8 @@ enum
 	VM_SWAPPINESS=19,	/* Tendency to steal mapped memory */
 	VM_LOWER_ZONE_PROTECTION=20,/* Amount of protection of lower zones */
 	VM_MIN_FREE_KBYTES=21,	/* Minimum free kilobytes to maintain */
+	VM_LAPTOP_MODE=22,      /* vm laptop mode */
+	VM_BLOCK_DUMP=23,       /* block dump mode */
 };
 
 
@@ -321,6 +323,7 @@ enum
 	NET_TCP_LOW_LATENCY=93,
 	NET_IPV4_IPFRAG_SECRET_INTERVAL=94,
 	NET_TCP_WESTWOOD=95,
+	NET_IPV4_IGMP_MAX_MSF=96,
 };
 
 enum {
--- diff/include/linux/sysfs.h	2003-08-26 10:00:54.000000000 +0100
+++ source/include/linux/sysfs.h	2004-03-09 11:51:51.000000000 +0000
@@ -18,6 +18,12 @@ struct attribute {
 	mode_t			mode;
 };
 
+struct attribute_group {
+	char			* name;
+	struct attribute	** attrs;
+};
+
+
 struct bin_attribute {
 	struct attribute	attr;
 	size_t			size;
@@ -25,14 +31,13 @@ struct bin_attribute {
 	ssize_t (*write)(struct kobject *, char *, loff_t, size_t);
 };
 
-int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr);
-int sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr);
-
 struct sysfs_ops {
 	ssize_t	(*show)(struct kobject *, struct attribute *,char *);
 	ssize_t	(*store)(struct kobject *,struct attribute *,const char *, size_t);
 };
 
+#ifdef CONFIG_SYSFS
+
 extern int
 sysfs_create_dir(struct kobject *);
 
@@ -57,13 +62,75 @@ sysfs_create_link(struct kobject * kobj,
 extern void
 sysfs_remove_link(struct kobject *, char * name);
 
-
-struct attribute_group {
-	char			* name;
-	struct attribute	** attrs;
-};
+int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr);
+int sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr);
 
 int sysfs_create_group(struct kobject *, const struct attribute_group *);
 void sysfs_remove_group(struct kobject *, const struct attribute_group *);
 
+#else /* CONFIG_SYSFS */
+
+static inline int sysfs_create_dir(struct kobject * k)
+{
+	return 0;
+}
+
+static inline void sysfs_remove_dir(struct kobject * k)
+{
+	;
+}
+
+static inline void sysfs_rename_dir(struct kobject * k, const char *new_name)
+{
+	;
+}
+
+static inline int sysfs_create_file(struct kobject * k, const struct attribute * a)
+{
+	return 0;
+}
+
+static inline int sysfs_update_file(struct kobject * k, const struct attribute * a)
+{
+	return 0;
+}
+
+static inline void sysfs_remove_file(struct kobject * k, const struct attribute * a)
+{
+	;
+}
+
+static inline int sysfs_create_link(struct kobject * k, struct kobject * t, char * n)
+{
+	return 0;
+}
+
+static inline void sysfs_remove_link(struct kobject * k, char * name)
+{
+	;
+}
+
+
+static inline int sysfs_create_bin_file(struct kobject * k, struct bin_attribute * a)
+{
+	return 0;
+}
+
+static inline int sysfs_remove_bin_file(struct kobject * k, struct bin_attribute * a)
+{
+	return 0;
+}
+
+static inline int sysfs_create_group(struct kobject * k, const struct attribute_group *g)
+{
+	return 0;
+}
+
+static inline void sysfs_remove_group(struct kobject * k, const struct attribute_group * g)
+{
+	;
+}
+
+#endif /* CONFIG_SYSFS */
+
 #endif /* _SYSFS_H_ */
--- diff/include/linux/topology.h	2003-08-26 10:00:54.000000000 +0100
+++ source/include/linux/topology.h	2004-03-09 11:51:51.000000000 +0000
@@ -54,4 +54,11 @@ static inline int __next_node_with_cpus(
 #define for_each_node_with_cpus(node) \
 	for (node = 0; node < numnodes; node = __next_node_with_cpus(node))
 
+#ifndef node_distance
+#define node_distance(from,to)	(from != to)
+#endif
+#ifndef PENALTY_FOR_NODE_WITH_CPUS
+#define PENALTY_FOR_NODE_WITH_CPUS	(1)
+#endif
+
 #endif /* _LINUX_TOPOLOGY_H */
--- diff/include/linux/udf_fs.h	2002-11-18 10:11:55.000000000 +0000
+++ source/include/linux/udf_fs.h	2004-03-09 11:51:51.000000000 +0000
@@ -8,7 +8,7 @@
  *  OSTA-UDF(tm) = Optical Storage Technology Association
  *  Universal Disk Format.
  *
- *  This code is based on version 2.00 of the UDF specification,
+ *  This code is based on version 2.50 of the UDF specification,
  *  and revision 3 of the ECMA 167 standard [equivalent to ISO 13346].
  *    http://www.osta.org/ *    http://www.ecma.ch/
  *    http://www.iso.org/
@@ -24,7 +24,7 @@
  *		ftp://prep.ai.mit.edu/pub/gnu/GPL
  *	Each contributing author retains all rights to their own work.
  *
- *  (C) 1999-2000 Ben Fennema
+ *  (C) 1999-2004 Ben Fennema
  *  (C) 1999-2000 Stelias Computing Inc
  *
  * HISTORY
@@ -37,8 +37,8 @@
 #define UDF_PREALLOCATE
 #define UDF_DEFAULT_PREALLOC_BLOCKS	8
 
-#define UDFFS_DATE			"2002/11/15"
-#define UDFFS_VERSION			"0.9.7"
+#define UDFFS_DATE			"2004/29/09"
+#define UDFFS_VERSION			"0.9.8.1"
 
 #define UDFFS_DEBUG
 
--- diff/include/linux/ufs_fs.h	2002-10-16 04:28:33.000000000 +0100
+++ source/include/linux/ufs_fs.h	2004-03-09 11:51:51.000000000 +0000
@@ -22,6 +22,9 @@
  * HP/UX hfs filesystem support added by
  * Martin K. Petersen <mkp@mkp.net>, August 1999
  *
+ * UFS2 (of FreeBSD 5.x) support added by
+ * Niraj Kumar <niraj17@iitbombay.org>  , Jan 2004
+ *
  */
 
 #ifndef __LINUX_UFS_FS_H
@@ -43,8 +46,50 @@
 
 #define UFS_SECTOR_SIZE 512
 #define UFS_SECTOR_BITS 9
-#define UFS_MAGIC 0x00011954
-#define UFS_CIGAM 0x54190100 /* byteswapped MAGIC */
+#define UFS_MAGIC  0x00011954
+#define UFS2_MAGIC 0x19540119
+#define UFS_CIGAM  0x54190100 /* byteswapped MAGIC */
+
+/* Copied from FreeBSD */
+/*
+ * Each disk drive contains some number of filesystems.
+ * A filesystem consists of a number of cylinder groups.
+ * Each cylinder group has inodes and data.
+ *
+ * A filesystem is described by its super-block, which in turn
+ * describes the cylinder groups.  The super-block is critical
+ * data and is replicated in each cylinder group to protect against
+ * catastrophic loss.  This is done at `newfs' time and the critical
+ * super-block data does not change, so the copies need not be
+ * referenced further unless disaster strikes.
+ *
+ * For filesystem fs, the offsets of the various blocks of interest
+ * are given in the super block as:
+ *      [fs->fs_sblkno]         Super-block
+ *      [fs->fs_cblkno]         Cylinder group block
+ *      [fs->fs_iblkno]         Inode blocks
+ *      [fs->fs_dblkno]         Data blocks
+ * The beginning of cylinder group cg in fs, is given by
+ * the ``cgbase(fs, cg)'' macro.
+ *
+ * Depending on the architecture and the media, the superblock may
+ * reside in any one of four places. For tiny media where every block
+ * counts, it is placed at the very front of the partition. Historically,
+ * UFS1 placed it 8K from the front to leave room for the disk label and
+ * a small bootstrap. For UFS2 it got moved to 64K from the front to leave
+ * room for the disk label and a bigger bootstrap, and for really piggy
+ * systems we check at 256K from the front if the first three fail. In
+ * all cases the size of the superblock will be SBLOCKSIZE. All values are
+ * given in byte-offset form, so they do not imply a sector size. The
+ * SBLOCKSEARCH specifies the order in which the locations should be searched.
+ */
+#define SBLOCK_FLOPPY        0
+#define SBLOCK_UFS1       8192
+#define SBLOCK_UFS2      65536
+#define SBLOCK_PIGGY    262144
+#define SBLOCKSIZE        8192
+#define SBLOCKSEARCH \
+        { SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 }
 
 
 /* HP specific MAGIC values */
@@ -120,6 +165,11 @@
 #define UFS_CG_OLD		0x00000000
 #define UFS_CG_44BSD		0x00002000
 #define UFS_CG_SUN		0x00001000
+/* filesystem type encoding */
+#define UFS_TYPE_MASK		0x00010000	/* mask for the following */
+#define UFS_TYPE_UFS1		0x00000000
+#define UFS_TYPE_UFS2		0x00010000
+
 
 /* fs_inodefmt options */
 #define UFS_42INODEFMT	-1
@@ -132,7 +182,7 @@
 #define UFS_MOUNT_ONERROR_UMOUNT	0x00000004
 #define UFS_MOUNT_ONERROR_REPAIR	0x00000008
 
-#define UFS_MOUNT_UFSTYPE		0x00000FF0
+#define UFS_MOUNT_UFSTYPE		0x0000FFF0
 #define UFS_MOUNT_UFSTYPE_OLD		0x00000010
 #define UFS_MOUNT_UFSTYPE_44BSD		0x00000020
 #define UFS_MOUNT_UFSTYPE_SUN		0x00000040
@@ -141,6 +191,7 @@
 #define UFS_MOUNT_UFSTYPE_OPENSTEP	0x00000200
 #define UFS_MOUNT_UFSTYPE_SUNx86	0x00000400
 #define UFS_MOUNT_UFSTYPE_HP	        0x00000800
+#define UFS_MOUNT_UFSTYPE_UFS2		0x00001000
 
 #define ufs_clear_opt(o,opt)	o &= ~UFS_MOUNT_##opt
 #define ufs_set_opt(o,opt)	o |= UFS_MOUNT_##opt
@@ -173,7 +224,8 @@
  * They calc file system addresses of cylinder group data structures.
  */
 #define	ufs_cgbase(c)	(uspi->s_fpg * (c))
-#define ufs_cgstart(c)	(ufs_cgbase(c)  + uspi->s_cgoffset * ((c) & ~uspi->s_cgmask))
+#define ufs_cgstart(c)	((uspi)->fs_magic == UFS2_MAGIC ?  ufs_cgbase(c) : \
+	(ufs_cgbase(c)  + uspi->s_cgoffset * ((c) & ~uspi->s_cgmask)))
 #define	ufs_cgsblock(c)	(ufs_cgstart(c) + uspi->s_sblkno)	/* super blk */
 #define	ufs_cgcmin(c)	(ufs_cgstart(c) + uspi->s_cblkno)	/* cg block */
 #define	ufs_cgimin(c)	(ufs_cgstart(c) + uspi->s_iblkno)	/* inode blk */
@@ -227,8 +279,14 @@
 
 #define	UFS_MAXNAMLEN 255
 #define UFS_MAXMNTLEN 512
+#define UFS2_MAXMNTLEN 468
+#define UFS2_MAXVOLLEN 32
 /* #define UFS_MAXCSBUFS 31 */
 #define UFS_LINK_MAX 32000
+/*
+#define	UFS2_NOCSPTRS	((128 / sizeof(void *)) - 4)
+*/
+#define	UFS2_NOCSPTRS	28
 
 /*
  * UFS_DIR_PAD defines the directory entries boundaries
@@ -262,6 +320,14 @@ struct ufs_csum {
 	__u32	cs_nifree;	/* number of free inodes */
 	__u32	cs_nffree;	/* number of free frags */
 };
+struct ufs2_csum_total {
+	__u64	cs_ndir;	/* number of directories */
+	__u64	cs_nbfree;	/* number of free blocks */
+	__u64	cs_nifree;	/* number of free inodes */
+	__u64	cs_nffree;	/* number of free frags */
+	__u64   cs_numclusters;	/* number of free clusters */
+	__u64   cs_spare[3];	/* future expansion */
+};
 
 /*
  * This is the actual superblock, as it is laid out on the disk.
@@ -333,7 +399,7 @@ struct ufs_super_block {
 	__u32	fs_ncyl;	/* cylinders in file system */
 /* these fields can be computed from the others */
 	__u32	fs_cpg;		/* cylinders per group */
-	__u32	fs_ipg;		/* inodes per group */
+	__u32	fs_ipg;		/* inodes per cylinder group */
 	__u32	fs_fpg;		/* blocks per group * fs_frag */
 /* this data must be re-computed after crashes */
 	struct ufs_csum fs_cstotal;	/* cylinder summary information */
@@ -342,13 +408,39 @@ struct ufs_super_block {
 	__s8	fs_clean;	/* file system is clean flag */
 	__s8	fs_ronly;	/* mounted read-only flag */
 	__s8	fs_flags;	/* currently unused flag */
-	__s8	fs_fsmnt[UFS_MAXMNTLEN];	/* name mounted on */
-/* these fields retain the current block allocation info */
-	__u32	fs_cgrotor;	/* last cg searched */
-	__u32	fs_csp[UFS_MAXCSBUFS];	/* list of fs_cs info buffers */
-	__u32	fs_maxcluster;
-	__u32	fs_cpc;		/* cyl per cycle in postbl */
-	__u16	fs_opostbl[16][8];	/* old rotation block list head */	
+	union {
+		struct {
+			__s8	fs_fsmnt[UFS_MAXMNTLEN];/* name mounted on */
+			__u32	fs_cgrotor;	/* last cg searched */
+			__u32	fs_csp[UFS_MAXCSBUFS];/*list of fs_cs info buffers */
+			__u32	fs_maxcluster;
+			__u32	fs_cpc;		/* cyl per cycle in postbl */
+			__u16	fs_opostbl[16][8]; /* old rotation block list head */
+		} fs_u1;
+		struct {
+			__s8  fs_fsmnt[UFS2_MAXMNTLEN];	/* name mounted on */
+			__u8   fs_volname[UFS2_MAXVOLLEN]; /* volume name */
+			__u64  fs_swuid;		/* system-wide uid */
+			__s32  fs_pad;	/* due to alignment of fs_swuid */
+			__u32   fs_cgrotor;     /* last cg searched */
+			__u32   fs_ocsp[UFS2_NOCSPTRS]; /*list of fs_cs info buffers */
+			__u32   fs_contigdirs;/*# of contiguously allocated dirs */
+			__u32   fs_csp;	/* cg summary info buffer for fs_cs */
+			__u32   fs_maxcluster;
+			__u32   fs_active;/* used by snapshots to track fs */
+			__s32   fs_old_cpc;	/* cyl per cycle in postbl */
+			__s32   fs_maxbsize;/*maximum blocking factor permitted */
+			__s64   fs_sparecon64[17];/*old rotation block list head */
+			__s64   fs_sblockloc; /* byte offset of standard superblock */
+			struct  ufs2_csum_total fs_cstotal;/*cylinder summary information*/
+			struct  ufs_timeval    fs_time;		/* last time written */
+			__s64    fs_size;		/* number of blocks in fs */
+			__s64    fs_dsize;	/* number of data blocks in fs */
+			__u64    fs_csaddr;	/* blk addr of cyl grp summary area */
+			__s64    fs_pendingblocks;/* blocks in process of being freed */
+			__s32    fs_pendinginodes;/*inodes in process of being freed */
+		} fs_u2;
+	}  fs_u11;
 	union {
 		struct {
 			__s32	fs_sparecon[53];/* reserved for future constants */
@@ -441,6 +533,16 @@ struct	ufs_cylinder_group {
 			__u32	cg_nclusterblks;	/* number of clusters this cg */
 			__u32	cg_sparecon[13];	/* reserved for future use */
 		} cg_44;
+		struct {
+			__u32	cg_clustersumoff;/* (u_int32) counts of avail clusters */
+			__u32	cg_clusteroff;	/* (u_int8) free cluster map */
+			__u32	cg_nclusterblks;/* number of clusters this cg */
+			__u32   cg_niblk; /* number of inode blocks this cg */
+			__u32   cg_initediblk;	/* last initialized inode */
+			__u32   cg_sparecon32[3];/* reserved for future use */
+			__u64   cg_time;	/* time last written */
+			__u64	cg_sparecon[3];	/* reserved for future use */
+		} cg_u2;
 		__u32	cg_sparecon[16];	/* reserved for future use */
 	} cg_u;
 	__u8	cg_space[1];		/* space for cylinder group maps */
@@ -497,6 +599,39 @@ struct ufs_inode {
 	} ui_u3;
 };
 
+#define UFS_NXADDR  2            /* External addresses in inode. */
+struct ufs2_inode {
+	__u16     ui_mode;        /*   0: IFMT, permissions; see below. */
+	__s16     ui_nlink;       /*   2: File link count. */
+	__u32     ui_uid;         /*   4: File owner. */
+	__u32     ui_gid;         /*   8: File group. */
+	__u32     ui_blksize;     /*  12: Inode blocksize. */
+	__u64     ui_size;        /*  16: File byte count. */
+	__u64     ui_blocks;      /*  24: Bytes actually held. */
+	struct ufs_timeval   ui_atime;       /*  32: Last access time. */
+	struct ufs_timeval   ui_mtime;       /*  40: Last modified time. */
+	struct ufs_timeval   ui_ctime;       /*  48: Last inode change time. */
+	struct ufs_timeval   ui_birthtime;   /*  56: Inode creation time. */
+	__s32     ui_mtimensec;   /*  64: Last modified time. */
+	__s32     ui_atimensec;   /*  68: Last access time. */
+	__s32     ui_ctimensec;   /*  72: Last inode change time. */
+	__s32     ui_birthnsec;   /*  76: Inode creation time. */
+	__s32     ui_gen;         /*  80: Generation number. */
+	__u32     ui_kernflags;   /*  84: Kernel flags. */
+	__u32     ui_flags;       /*  88: Status flags (chflags). */
+	__s32     ui_extsize;     /*  92: External attributes block. */
+	__s64     ui_extb[UFS_NXADDR];/*  96: External attributes block. */
+	union {
+		struct {
+			__s64     ui_db[UFS_NDADDR]; /* 112: Direct disk blocks. */
+			__s64     ui_ib[UFS_NINDIR];/* 208: Indirect disk blocks.*/
+		} ui_addr;
+	__u8	ui_symlink[2*4*(UFS_NDADDR+UFS_NINDIR)];/* 0x28 fast symlink */
+	} ui_u2;
+	__s64     ui_spare[3];    /* 232: Reserved; currently unused */
+};
+
+
 /* FreeBSD has these in sys/stat.h */
 /* ui_flags that can be set by a file owner */
 #define UFS_UF_SETTABLE   0x0000ffff
@@ -517,8 +652,8 @@ struct ufs_inode {
  * than the size of fragment.
  */
 struct ufs_buffer_head {
-	unsigned fragment;			/* first fragment */
-	unsigned count;				/* number of fragments */
+	__u64 fragment;			/* first fragment */
+	__u64 count;				/* number of fragments */
 	struct buffer_head * bh[UFS_MAXFRAG];	/* buffers */
 };
 
@@ -551,6 +686,8 @@ struct ufs_sb_private_info {
 	__u32	s_cgmask;	/* used to calc mod fs_ntrak */
 	__u32	s_size;		/* number of blocks (fragments) in fs */
 	__u32	s_dsize;	/* number of data blocks in fs */
+	__u64	s_u2_size;	/* ufs2: number of blocks (fragments) in fs */
+	__u64	s_u2_dsize;	/*ufs2:  number of data blocks in fs */
 	__u32	s_ncg;		/* number of cylinder groups */
 	__u32	s_bsize;	/* size of basic blocks */
 	__u32	s_fsize;	/* size of fragments */
@@ -577,7 +714,7 @@ struct ufs_sb_private_info {
 	__u32	s_ntrak;	/* tracks per cylinder */
 	__u32	s_nsect;	/* sectors per track */
 	__u32	s_spc;		/* sectors per cylinder */
-	__u32	s_ipg;		/* inodes per group */
+	__u32	s_ipg;		/* inodes per cylinder group */
 	__u32	s_fpg;		/* fragments per group */
 	__u32	s_cpc;		/* cyl per cycle in postbl */
 	__s32	s_contigsumsize;/* size of cluster summary array, 44bsd */
@@ -605,6 +742,7 @@ struct ufs_sb_private_info {
 	__u32	s_bpfmask;	/* bits per fragment mask */
 
 	__u32	s_maxsymlinklen;/* upper limit on fast symlinks' size */
+	__s32	fs_magic;       /* filesystem magic */
 };
 
 /*
@@ -758,7 +896,7 @@ extern void ufs_free_inode (struct inode
 extern struct inode * ufs_new_inode (struct inode *, int);
 
 /* inode.c */
-extern int ufs_frag_map (struct inode *, int);
+extern u64  ufs_frag_map (struct inode *, int);
 extern void ufs_read_inode (struct inode *);
 extern void ufs_put_inode (struct inode *);
 extern void ufs_write_inode (struct inode *, int);
--- diff/include/linux/ufs_fs_i.h	2002-10-16 04:27:08.000000000 +0100
+++ source/include/linux/ufs_fs_i.h	2004-03-09 11:51:51.000000000 +0000
@@ -17,6 +17,7 @@ struct ufs_inode_info {
 	union {
 		__u32	i_data[15];
 		__u8	i_symlink[4*15];
+		__u64	u2_i_data[15];
 	} i_u1;
 	__u32	i_flags;
 	__u32	i_gen;
--- diff/include/linux/usb.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/usb.h	2004-03-09 11:51:51.000000000 +0000
@@ -72,14 +72,11 @@ struct usb_host_interface {
 
 /**
  * struct usb_interface - what usb device drivers talk to
- * @altsetting: array of interface descriptors, one for each alternate
+ * @altsetting: array of interface structures, one for each alternate
  * 	setting that may be selected.  Each one includes a set of
- * 	endpoint configurations and will be in numberic order,
- * 	0..num_altsetting.
+ * 	endpoint configurations.  They will be in no particular order.
  * @num_altsetting: number of altsettings defined.
- * @act_altsetting: index of current altsetting.  this number is always
- *	less than num_altsetting.  after the device is configured, each
- *	interface uses its default setting of zero.
+ * @cur_altsetting: the current altsetting.
  * @driver: the USB driver that is bound to this interface.
  * @minor: the minor number assigned to this interface, if this
  *	interface is bound to a driver that uses the USB major number.
@@ -89,6 +86,8 @@ struct usb_host_interface {
  *	number from the USB core by calling usb_register_dev().
  * @dev: driver model's view of this device
  * @class_dev: driver model's class view of this device.
+ * @released: wait for the interface to be released when changing
+ *	configurations.
  *
  * USB device drivers attach to interfaces on a physical device.  Each
  * interface encapsulates a single high level function, such as feeding
@@ -102,26 +101,33 @@ struct usb_host_interface {
  * calls such as dev_get_drvdata() on the dev member of this structure.
  *
  * Each interface may have alternate settings.  The initial configuration
- * of a device sets the first of these, but the device driver can change
+ * of a device sets altsetting 0, but the device driver can change
  * that setting using usb_set_interface().  Alternate settings are often
  * used to control the the use of periodic endpoints, such as by having
  * different endpoints use different amounts of reserved USB bandwidth.
  * All standards-conformant USB devices that use isochronous endpoints
  * will use them in non-default settings.
+ *
+ * The USB specification says that alternate setting numbers must run from
+ * 0 to one less than the total number of alternate settings.  But some
+ * devices manage to mess this up, and the structures aren't necessarily
+ * stored in numerical order anyhow.  Use usb_altnum_to_altsetting() to
+ * look up an alternate setting in the altsetting array based on its number.
  */
 struct usb_interface {
-	/* array of alternate settings for this interface.
-	 * these will be in numeric order, 0..num_altsettting
-	 */
+	/* array of alternate settings for this interface,
+	 * stored in no particular order */
 	struct usb_host_interface *altsetting;
 
-	unsigned act_altsetting;	/* active alternate setting */
+	struct usb_host_interface *cur_altsetting;	/* the currently
+					 * active alternate setting */
 	unsigned num_altsetting;	/* number of alternate settings */
 
 	struct usb_driver *driver;	/* driver */
 	int minor;			/* minor number this interface is bound to */
 	struct device dev;		/* interface specific device info */
 	struct class_device *class_dev;
+	struct completion *released;	/* wait for release */
 };
 #define	to_usb_interface(d) container_of(d, struct usb_interface, dev)
 #define	interface_to_usbdev(intf) \
@@ -140,19 +146,43 @@ static inline void usb_set_intfdata (str
 /* this maximum is arbitrary */
 #define USB_MAXINTERFACES	32
 
-/* USB_DT_CONFIG: Configuration descriptor information.
- *
- * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the
- * descriptor type is different.  Highspeed-capable devices can look
- * different depending on what speed they're currently running.  Only
- * devices with a USB_DT_DEVICE_QUALIFIER have an OTHER_SPEED_CONFIG.
+/**
+ * struct usb_host_config - representation of a device's configuration
+ * @desc: the device's configuration descriptor.
+ * @interface: array of usb_interface structures, one for each interface
+ *	in the configuration.  The number of interfaces is stored in
+ *	desc.bNumInterfaces.
+ * @extra: pointer to buffer containing all extra descriptors associated
+ *	with this configuration (those preceding the first interface
+ *	descriptor).
+ * @extralen: length of the extra descriptors buffer.
+ *
+ * USB devices may have multiple configurations, but only one can be active
+ * at any time.  Each encapsulates a different operational environment;
+ * for example, a dual-speed device would have separate configurations for
+ * full-speed and high-speed operation.  The number of configurations
+ * available is stored in the device descriptor as bNumConfigurations.
+ *
+ * A configuration can contain multiple interfaces.  Each corresponds to
+ * a different function of the USB device, and all are available whenever
+ * the configuration is active.  The USB standard says that interfaces
+ * are supposed to be numbered from 0 to desc.bNumInterfaces-1, but a lot
+ * of devices get this wrong.  In addition, the interface array is not
+ * guaranteed to be sorted in numerical order.  Use usb_ifnum_to_if() to
+ * look up an interface entry based on its number.
+ *
+ * Device drivers should not attempt to activate configurations.  The choice
+ * of which configuration to install is a policy decision based on such
+ * considerations as available power, functionality provided, and the user's
+ * desires (expressed through hotplug scripts).  However, drivers can call
+ * usb_reset_configuration() to reinitialize the current configuration and
+ * all its interfaces.
  */
 struct usb_host_config {
 	struct usb_config_descriptor	desc;
 
-	/* the interfaces associated with this configuration
-	 * these will be in numeric order, 0..desc.bNumInterfaces
-	 */
+	/* the interfaces associated with this configuration,
+	 * stored in no particular order */
 	struct usb_interface *interface[USB_MAXINTERFACES];
 
 	unsigned char *extra;   /* Extra descriptors */
@@ -294,8 +324,12 @@ extern void usb_driver_release_interface
 const struct usb_device_id *usb_match_id(struct usb_interface *interface,
 					 const struct usb_device_id *id);
 
-extern struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor);
-extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum);
+extern struct usb_interface *usb_find_interface(struct usb_driver *drv,
+		int minor);
+extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev,
+		unsigned ifnum);
+extern struct usb_host_interface *usb_altnum_to_altsetting(
+		struct usb_interface *intf, unsigned int altnum);
 
 
 /**
@@ -830,14 +864,18 @@ void usb_buffer_free (struct usb_device 
 	void *addr, dma_addr_t dma);
 
 struct urb *usb_buffer_map (struct urb *urb);
+#if 0
 void usb_buffer_dmasync (struct urb *urb);
+#endif
 void usb_buffer_unmap (struct urb *urb);
 
 struct scatterlist;
 int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
 		struct scatterlist *sg, int nents);
+#if 0
 void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
 		struct scatterlist *sg, int n_hw_ents);
+#endif
 void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
 		struct scatterlist *sg, int n_hw_ents);
 
--- diff/include/linux/usb_gadget.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/linux/usb_gadget.h	2004-03-09 11:51:51.000000000 +0000
@@ -117,7 +117,7 @@ struct usb_ep_ops {
 	void (*free_buffer) (struct usb_ep *ep, void *buf, dma_addr_t dma,
 		unsigned bytes);
 	// NOTE:  on 2.5, drivers may also use dma_map() and
-	// dma_sync_single() to manage dma overhead. 
+	// dma_sync_single_*() to manage dma overhead.
 
 	int (*queue) (struct usb_ep *ep, struct usb_request *req,
 		int gfp_flags);
@@ -690,7 +690,7 @@ int usb_gadget_unregister_driver (struct
 /**
  * struct usb_string - wraps a C string and its USB id
  * @id:the (nonzero) ID for this string
- * @s:the string, in ISO-8859/1 characters
+ * @s:the string, in UTF-8 encoding
  *
  * If you're using usb_gadget_get_string(), use this to wrap a string
  * together with its ID.
@@ -716,6 +716,17 @@ struct usb_gadget_strings {
 /* put descriptor for string with that id into buf (buflen >= 256) */
 int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf);
 
+/*-------------------------------------------------------------------------*/
+
+/* utility to simplify managing config descriptors */
+
+/* write vector of descriptors into buffer */
+int usb_descriptor_fillbuf(void *, unsigned,
+		const struct usb_descriptor_header **);
+
+/* build config descriptor from single descriptor vector */
+int usb_gadget_config_buf(const struct usb_config_descriptor *config,
+	void *buf, unsigned buflen, const struct usb_descriptor_header **desc);
 
 #endif  /* __KERNEL__ */
 
--- diff/include/linux/workqueue.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/linux/workqueue.h	2004-03-09 11:51:51.000000000 +0000
@@ -52,7 +52,9 @@ struct work_struct {
 extern struct workqueue_struct *create_workqueue(const char *name);
 extern void destroy_workqueue(struct workqueue_struct *wq);
 
-extern int FASTCALL(queue_work(struct workqueue_struct *wq, struct work_struct *work));
+int queue_work(struct workqueue_struct *wq, struct work_struct *work);
+int queue_work_on_cpu(struct workqueue_struct *wq,
+			struct work_struct *work, int cpu);
 extern int FASTCALL(queue_delayed_work(struct workqueue_struct *wq, struct work_struct *work, unsigned long delay));
 extern void FASTCALL(flush_workqueue(struct workqueue_struct *wq));
 
--- diff/include/linux/writeback.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/linux/writeback.h	2004-03-09 11:51:51.000000000 +0000
@@ -71,12 +71,15 @@ static inline void wait_on_inode(struct 
  * mm/page-writeback.c
  */
 int wakeup_bdflush(long nr_pages);
+void disk_is_spun_up(int postpone_writeback);
 
-/* These 5 are exported to sysctl. */
+/* These are exported to sysctl. */
 extern int dirty_background_ratio;
 extern int vm_dirty_ratio;
 extern int dirty_writeback_centisecs;
 extern int dirty_expire_centisecs;
+extern int block_dump;
+extern int laptop_mode;
 
 struct ctl_table;
 struct file;
--- diff/include/net/bluetooth/hci.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/net/bluetooth/hci.h	2004-03-09 11:51:51.000000000 +0000
@@ -35,21 +35,31 @@
 #define HCI_MAX_FRAME_SIZE	(HCI_MAX_ACL_SIZE + 4)
 
 /* HCI dev events */
-#define HCI_DEV_REG	1
-#define HCI_DEV_UNREG   2
-#define HCI_DEV_UP	3
-#define HCI_DEV_DOWN	4
-#define HCI_DEV_SUSPEND 5
-#define HCI_DEV_RESUME  6
+#define HCI_DEV_REG			1
+#define HCI_DEV_UNREG			2
+#define HCI_DEV_UP			3
+#define HCI_DEV_DOWN			4
+#define HCI_DEV_SUSPEND			5
+#define HCI_DEV_RESUME			6
+
+/* HCI notify events */
+#define HCI_NOTIFY_CONN_ADD		1
+#define HCI_NOTIFY_CONN_DEL		2
+#define HCI_NOTIFY_VOICE_SETTING	3
 
 /* HCI device types */
 #define HCI_VHCI	0
 #define HCI_USB		1
 #define HCI_PCCARD	2
-#define HCI_UART 	3
-#define HCI_RS232 	4
+#define HCI_UART	3
+#define HCI_RS232	4
 #define HCI_PCI		5
 
+/* HCI device quirks */
+enum {
+	HCI_QUIRK_RESET_ON_INIT
+};
+
 /* HCI device flags */
 enum {
 	HCI_UP,
@@ -90,24 +100,24 @@ enum {
 #define HCIINQUIRY	_IOR('H', 240, int)
 
 /* HCI timeouts */
-#define HCI_CONN_TIMEOUT 	(HZ * 40)
-#define HCI_DISCONN_TIMEOUT 	(HZ * 2)
+#define HCI_CONN_TIMEOUT	(HZ * 40)
+#define HCI_DISCONN_TIMEOUT	(HZ * 2)
 #define HCI_CONN_IDLE_TIMEOUT	(HZ * 60)
 
 /* HCI Packet types */
 #define HCI_COMMAND_PKT		0x01
-#define HCI_ACLDATA_PKT 	0x02
-#define HCI_SCODATA_PKT 	0x03
+#define HCI_ACLDATA_PKT		0x02
+#define HCI_SCODATA_PKT		0x03
 #define HCI_EVENT_PKT		0x04
 #define HCI_UNKNOWN_PKT		0xff
 
 /* HCI Packet types */
-#define HCI_DM1 	0x0008
-#define HCI_DM3 	0x0400
-#define HCI_DM5 	0x4000
-#define HCI_DH1 	0x0010
-#define HCI_DH3 	0x0800
-#define HCI_DH5 	0x8000
+#define HCI_DM1		0x0008
+#define HCI_DM3		0x0400
+#define HCI_DM5		0x4000
+#define HCI_DH1		0x0010
+#define HCI_DH3		0x0800
+#define HCI_DH5		0x8000
 
 #define HCI_HV1		0x0020
 #define HCI_HV2		0x0040
--- diff/include/net/bluetooth/hci_core.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/net/bluetooth/hci_core.h	2004-03-09 11:51:51.000000000 +0000
@@ -77,6 +77,8 @@ struct hci_dev {
 	__u16		link_policy;
 	__u16		link_mode;
 
+	unsigned long	quirks;
+
 	atomic_t 	cmd_cnt;
 	unsigned int 	acl_cnt;
 	unsigned int 	sco_cnt;
@@ -128,6 +130,7 @@ struct hci_dev {
 	int (*flush)(struct hci_dev *hdev);
 	int (*send)(struct sk_buff *skb);
 	void (*destruct)(struct hci_dev *hdev);
+	void (*notify)(struct hci_dev *hdev, unsigned int evt);
 	int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
 };
 
--- diff/include/net/irda/vlsi_ir.h	2003-09-17 12:28:12.000000000 +0100
+++ source/include/net/irda/vlsi_ir.h	2004-03-09 11:51:51.000000000 +0000
@@ -41,19 +41,6 @@
 #define PCI_CLASS_SUBCLASS_MASK		0xffff
 #endif
 
-/* missing pci-dma api call to give streaming dma buffer back to hw
- * patch was floating on lkml around 2.5.2x and might be present later.
- * Defining it this way is ok, since the vlsi-ir is only
- * used on two oldish x86-based notebooks which are cache-coherent
- * (and flush_write_buffers also handles PPro errata and C3 OOstore)
- */
-#ifdef CONFIG_X86
-#include <asm-i386/io.h>
-#define pci_dma_prep_single(dev, addr, size, direction)	flush_write_buffers()
-#else
-#error missing pci dma api call
-#endif
-
 /* in recent 2.5 interrupt handlers have non-void return value */
 #ifndef IRQ_RETVAL
 typedef void irqreturn_t;
--- diff/include/scsi/scsi.h	2004-03-04 11:41:49.000000000 +0000
+++ source/include/scsi/scsi.h	2004-03-09 11:51:51.000000000 +0000
@@ -200,6 +200,7 @@ static inline int scsi_status_is_good(in
 #define TYPE_MEDIUM_CHANGER 0x08
 #define TYPE_COMM           0x09    /* Communications device */
 #define TYPE_ENCLOSURE      0x0d    /* Enclosure Services Device */
+#define TYPE_RAID           0x0c
 #define TYPE_NO_LUN         0x7f
 
 /*
--- diff/include/scsi/scsi_device.h	2003-12-19 09:51:02.000000000 +0000
+++ source/include/scsi/scsi_device.h	2004-03-09 11:51:51.000000000 +0000
@@ -94,6 +94,7 @@ struct scsi_device {
 	unsigned skip_ms_page_8:1;	/* do not use MODE SENSE page 0x08 */
 	unsigned skip_ms_page_3f:1;	/* do not use MODE SENSE page 0x3f */
 	unsigned no_start_on_add:1;	/* do not issue start on add */
+	unsigned allow_restart:1; /* issue START_UNIT in error handler */
 
 	unsigned int device_blocked;	/* Device returned QUEUE_FULL. */
 
@@ -103,12 +104,17 @@ struct scsi_device {
 	struct device		sdev_gendev;
 	struct class_device	sdev_classdev;
 
+	struct class_device	transport_classdev;
+
 	enum scsi_device_state sdev_state;
-};
+	unsigned long		transport_data[0];
+} __attribute__((aligned(sizeof(unsigned long))));
 #define	to_scsi_device(d)	\
 	container_of(d, struct scsi_device, sdev_gendev)
 #define	class_to_sdev(d)	\
 	container_of(d, struct scsi_device, sdev_classdev)
+#define transport_class_to_sdev(class_dev) \
+	container_of(class_dev, struct scsi_device, transport_classdev)
 
 extern struct scsi_device *scsi_add_device(struct Scsi_Host *,
 		uint, uint, uint);
--- diff/include/scsi/scsi_host.h	2003-11-25 15:24:59.000000000 +0000
+++ source/include/scsi/scsi_host.h	2004-03-09 11:51:51.000000000 +0000
@@ -11,6 +11,7 @@ struct scsi_cmnd;
 struct scsi_device;
 struct Scsi_Host;
 struct scsi_host_cmd_pool;
+struct scsi_transport_template;
 
 
 /*
@@ -395,6 +396,7 @@ struct Scsi_Host {
 	unsigned int            eh_kill:1; /* set when killing the eh thread */
 	wait_queue_head_t       host_wait;
 	struct scsi_host_template *hostt;
+	struct scsi_transport_template *transportt;
 	volatile unsigned short host_busy;   /* commands actually active on low-level */
 	volatile unsigned short host_failed; /* commands that failed. */
     
--- diff/include/sound/ac97_codec.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/sound/ac97_codec.h	2004-03-09 11:51:51.000000000 +0000
@@ -484,7 +484,8 @@ enum {
 	AC97_TUNE_HP_ONLY,	/* headphone (true line-out) control as master only */
 	AC97_TUNE_SWAP_HP,	/* swap headphone and master controls */
 	AC97_TUNE_SWAP_SURROUND, /* swap master and surround controls */
-	AC97_TUNE_AD_SHARING	/* for AD1985, turn on OMS bit and use headphone */
+	AC97_TUNE_AD_SHARING,	/* for AD1985, turn on OMS bit and use headphone */
+	AC97_TUNE_ALC_JACK,	/* for Realtek, enable JACK detection */
 };
 
 struct ac97_quirk {
--- diff/include/sound/asequencer.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/sound/asequencer.h	2004-03-09 11:51:51.000000000 +0000
@@ -594,6 +594,7 @@ struct sndrv_seq_remove_events {
 #define SNDRV_SEQ_PORT_TYPE_MIDI_GS	(1<<3)	/* GS compatible device */
 #define SNDRV_SEQ_PORT_TYPE_MIDI_XG	(1<<4)	/* XG compatible device */
 #define SNDRV_SEQ_PORT_TYPE_MIDI_MT32	(1<<5)	/* MT-32 compatible device */
+#define SNDRV_SEQ_PORT_TYPE_MIDI_GM2	(1<<6)	/* General MIDI 2 compatible device */
 
 /* other standards...*/
 #define SNDRV_SEQ_PORT_TYPE_SYNTH	(1<<10)	/* Synth device (no MIDI compatible - direct wavetable) */
@@ -605,7 +606,7 @@ struct sndrv_seq_remove_events {
 /* misc. conditioning flags */
 #define SNDRV_SEQ_PORT_FLG_GIVEN_PORT	(1<<0)
 #define SNDRV_SEQ_PORT_FLG_TIMESTAMP	(1<<1)
-#define SNDRV_SEQ_PORT_FLG_TIME_REAL	(1<<1)
+#define SNDRV_SEQ_PORT_FLG_TIME_REAL	(1<<2)
 
 struct sndrv_seq_port_info {
 	struct sndrv_seq_addr addr;	/* client/port numbers */
--- diff/include/sound/asound.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/sound/asound.h	2004-03-09 11:51:51.000000000 +0000
@@ -153,7 +153,7 @@ enum {
  *                                                                           *
  *****************************************************************************/
 
-#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 5)
+#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 6)
 
 typedef unsigned long sndrv_pcm_uframes_t;
 typedef long sndrv_pcm_sframes_t;
--- diff/include/sound/cs46xx.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/sound/cs46xx.h	2004-03-09 11:51:51.000000000 +0000
@@ -1646,9 +1646,7 @@
 typedef struct _snd_cs46xx cs46xx_t;
 
 typedef struct _snd_cs46xx_pcm_t {
-	unsigned char *hw_area;
-	dma_addr_t hw_addr;	/* PCI bus address, not accessible */
-	unsigned long hw_size;
+	struct snd_dma_buffer hw_buf;
   
 	unsigned int ctl;
 	unsigned int shift;	/* Shift count to trasform frames in bytes */
@@ -1693,9 +1691,7 @@ struct _snd_cs46xx {
 	unsigned int mode;
 	
 	struct {
-		unsigned char *hw_area;
-		dma_addr_t hw_addr;	/* PCI bus address, not accessible */
-		unsigned long hw_size;
+		struct snd_dma_buffer hw_buf;
 
 		unsigned int ctl;
 		unsigned int shift;	/* Shift count to trasform frames in bytes */
@@ -1727,6 +1723,8 @@ struct _snd_cs46xx {
 	unsigned int midcr;
 	unsigned int uartm;
 
+	struct snd_dma_device dma_dev;
+
 	int amplifier;
 	void (*amplifier_ctrl)(cs46xx_t *, int);
 	void (*active_ctrl)(cs46xx_t *, int);
--- diff/include/sound/emu10k1.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/sound/emu10k1.h	2004-03-09 11:51:51.000000000 +0000
@@ -644,9 +644,13 @@
 #define SOLEH			0x5d		/* Stop on loop enable high register		*/
 
 #define SPBYPASS		0x5e		/* SPDIF BYPASS mode register			*/
-#define SPBYPASS_ENABLE		0x00000001	/* Enable SPDIF bypass mode			*/
+#define SPBYPASS_SPDIF0_MASK	0x00000003	/* SPDIF 0 bypass mode				*/
+#define SPBYPASS_SPDIF1_MASK	0x0000000c	/* SPDIF 1 bypass mode				*/
+/* bypass mode: 0 - DSP; 1 - SPDIF A, 2 - SPDIF B, 3 - SPDIF C					*/
+#define SPBYPASS_FORMAT		0x00000f00      /* If 1, SPDIF XX uses 24 bit, if 0 - 20 bit	*/
 
 #define AC97SLOT		0x5f            /* additional AC97 slots enable bits		*/
+#define AC97SLOT_10K2		0x03
 #define AC97SLOT_CNTR		0x10            /* Center enable */
 #define AC97SLOT_LFE		0x20            /* LFE enable */
 
@@ -837,7 +841,7 @@ typedef struct {
 typedef struct snd_emu10k1_memblk {
 	snd_util_memblk_t mem;
 	/* private part */
-	short first_page, last_page, pages, mapped_page;
+	int first_page, last_page, pages, mapped_page;
 	unsigned int map_locked;
 	struct list_head mapped_link;
 	struct list_head mapped_order_link;
@@ -897,9 +901,7 @@ typedef struct {
 	unsigned short extout_mask;	/* used external outputs (bitmask) */
 	unsigned short pad1;
 	unsigned int itram_size;	/* internal TRAM size in samples */
-	unsigned int etram_size;	/* external TRAM size in samples */
-	void *etram_pages;		/* allocated pages for external TRAM */
-	dma_addr_t etram_pages_dmaaddr;
+	struct snd_dma_buffer etram_pages; /* external TRAM pages and size */
 	unsigned int dbg;		/* FX debugger register */
 	unsigned char name[128];
 	int gpr_size;			/* size of allocated GPR controls */
@@ -943,11 +945,10 @@ struct _snd_emu10k1 {
 	unsigned int card_type;			/* EMU10K1_CARD_* */
 	unsigned int ecard_ctrl;		/* ecard control bits */
 	unsigned long dma_mask;			/* PCI DMA mask */
+	struct snd_dma_device dma_dev;		/* DMA device description */
 	int max_cache_pages;			/* max memory size / PAGE_SIZE */
-	void *silent_page;			/* silent page */
-	dma_addr_t silent_page_dmaaddr;
-	volatile u32 *ptb_pages;		/* page table pages */
-	dma_addr_t ptb_pages_dmaaddr;
+	struct snd_dma_buffer silent_page;	/* silent page */
+	struct snd_dma_buffer ptb_pages;	/* page table pages */
 	snd_util_memhdr_t *memhdr;		/* page allocation list */
 	emu10k1_memblk_t *reserved_page;	/* reserved page */
 
--- diff/include/sound/info.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/sound/info.h	2004-03-09 11:51:51.000000000 +0000
@@ -171,7 +171,7 @@ static inline void snd_remove_proc_entry
 					 struct proc_dir_entry *de) { ; }
 
 #define snd_card_proc_new(card,name,entryp)  0 /* always success */
-#define snd_info_set_text_ops(entry,private_data,read) /*NOP*/
+#define snd_info_set_text_ops(entry,private_data,read_size,read) /*NOP*/
 
 #endif
 
--- diff/include/sound/memalloc.h	2003-05-21 11:50:10.000000000 +0100
+++ source/include/sound/memalloc.h	2004-03-09 11:51:51.000000000 +0000
@@ -24,49 +24,33 @@
 #ifndef __SOUND_MEMALLOC_H
 #define __SOUND_MEMALLOC_H
 
-#include <linux/pci.h>
-#ifdef CONFIG_SBUS
-#include <asm/sbus.h>
-#endif
+struct device;
 
 /*
  * buffer device info
  */
 struct snd_dma_device {
 	int type;			/* SNDRV_MEM_TYPE_XXX */
-	union {
-		struct pci_dev *pci;	/* for PCI and PCI-SG types */
-		unsigned int flags;	/* GFP_XXX for continous and ISA types */
-#ifdef CONFIG_SBUS
-		struct sbus_dev *sbus;	/* for SBUS type */
-#endif
-	} dev;
+	struct device *dev;		/* generic device */
 	unsigned int id;		/* a unique ID */
 };
 
+#ifndef snd_dma_pci_data
+#define snd_dma_pci_data(pci)	(&(pci)->dev)
+#define snd_dma_isa_data()	NULL
+#define snd_dma_sbus_data(sbus)	((struct device *)(sbus))
+#define snd_dma_continuous_data(x)	((struct device *)(unsigned long)(x))
+#endif
+
+
 /*
  * buffer types
  */
 #define SNDRV_DMA_TYPE_UNKNOWN		0	/* not defined */
 #define SNDRV_DMA_TYPE_CONTINUOUS	1	/* continuous no-DMA memory */
-#define SNDRV_DMA_TYPE_ISA		2	/* ISA continuous */
-#define SNDRV_DMA_TYPE_PCI		3	/* PCI continuous */
+#define SNDRV_DMA_TYPE_DEV		2	/* generic device continuous */
+#define SNDRV_DMA_TYPE_DEV_SG		3	/* generic device SG-buffer */
 #define SNDRV_DMA_TYPE_SBUS		4	/* SBUS continuous */
-#define SNDRV_DMA_TYPE_PCI_SG		5	/* PCI SG-buffer */
-
-#ifdef CONFIG_PCI
-/*
- * compose a snd_dma_device struct for the PCI device
- */
-static inline void snd_dma_device_pci(struct snd_dma_device *dev, struct pci_dev *pci, unsigned int id)
-{
-	memset(dev, 0, sizeof(*dev));
-	dev->type = SNDRV_DMA_TYPE_PCI;
-	dev->dev.pci = pci;
-	dev->id = id;
-}
-#endif
-
 
 /*
  * info for buffer allocation
@@ -78,67 +62,8 @@ struct snd_dma_buffer {
 	void *private_data;	/* private for allocator; don't touch */
 };
 
-/* allocate/release a buffer */
-int snd_dma_alloc_pages(const struct snd_dma_device *dev, size_t size, struct snd_dma_buffer *dmab);
-void snd_dma_free_pages(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab);
-
-/* buffer-preservation managements */
-size_t snd_dma_get_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab);
-int snd_dma_free_reserved(const struct snd_dma_device *dev);
-int snd_dma_set_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab);
-
-
-/*
- * Generic memory allocators
- */
-
-/*
- * continuous pages
- */
-void *snd_malloc_pages(size_t size, unsigned int gfp_flags);
-void *snd_malloc_pages_fallback(size_t size, unsigned int gfp_flags, size_t *res_size);
-void snd_free_pages(void *ptr, size_t size);
-
-#ifdef CONFIG_PCI
-/*
- * PCI continuous pages
- */
-void *snd_malloc_pci_pages(struct pci_dev *pci, size_t size, dma_addr_t *dma_addr);
-void *snd_malloc_pci_pages_fallback(struct pci_dev *pci, size_t size, dma_addr_t *dma_addr, size_t *res_size);
-void snd_free_pci_pages(struct pci_dev *pci, size_t size, void *ptr, dma_addr_t dma_addr);
-/* one page allocation */
-void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *dma_addr);
-#define snd_free_pci_page(pci,ptr,addr) snd_free_pci_pages(pci,PAGE_SIZE,ptr,addr)
-#endif
-
-#ifdef CONFIG_SBUS
-/*
- * SBUS continuous pages
- */
-void *snd_malloc_sbus_pages(struct sbus_dev *sdev, size_t size, dma_addr_t *dma_addr);
-void *snd_malloc_sbus_pages_fallback(struct sbus_dev *sdev, size_t size, dma_addr_t *dma_addr, size_t *res_size);
-void snd_free_sbus_pages(struct sbus_dev *sdev, size_t size, void *ptr, dma_addr_t dma_addr);
-#endif
-
-#ifdef CONFIG_ISA
 /*
- * ISA continuous pages
- */
-void *snd_malloc_isa_pages(size_t size, dma_addr_t *dma_addr);
-void *snd_malloc_isa_pages_fallback(size_t size, dma_addr_t *dma_addr, size_t *res_size);
-void snd_free_isa_pages(size_t size, void *ptr, dma_addr_t addr);
-#ifdef CONFIG_PCI
-#define snd_malloc_isa_pages(size, dma_addr) snd_malloc_pci_pages(NULL, size, dma_addr)
-#define snd_malloc_isa_pages_fallback(size, dma_addr, res_size) snd_malloc_pci_pages_fallback(NULL, size, dma_addr, res_size)
-#define snd_free_isa_pages(size, ptr, dma_addr) snd_free_pci_pages(NULL, size, ptr, dma_addr)
-#else /* !CONFIG_PCI */
-#define snd_free_isa_pages(size, ptr, dma_addr) snd_free_pages(ptr, size)
-#endif /* CONFIG_PCI */
-#endif /* CONFIG_ISA */
-
-#ifdef CONFIG_PCI
-/*
- * Scatter-Gather PCI pages
+ * Scatter-Gather generic device pages
  */
 struct snd_sg_page {
 	void *buf;
@@ -151,12 +76,9 @@ struct snd_sg_buf {
 	int tblsize;	/* allocated table size */
 	struct snd_sg_page *table;	/* address table */
 	struct page **page_table;	/* page table (for vmap/vunmap) */
-	struct pci_dev *pci;
+	struct snd_dma_device dev;
 };
 
-void *snd_malloc_sgbuf_pages(struct pci_dev *pci, size_t size, struct snd_dma_buffer *dmab);
-int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab);
-
 /*
  * return the pages matching with the given byte size
  */
@@ -172,6 +94,24 @@ static inline dma_addr_t snd_sgbuf_get_a
 {
 	return sgbuf->table[offset >> PAGE_SHIFT].addr + offset % PAGE_SIZE;
 }
-#endif /* CONFIG_PCI */
+
+
+/* allocate/release a buffer */
+int snd_dma_alloc_pages(const struct snd_dma_device *dev, size_t size,
+			struct snd_dma_buffer *dmab);
+int snd_dma_alloc_pages_fallback(const struct snd_dma_device *dev, size_t size,
+                                 struct snd_dma_buffer *dmab);
+void snd_dma_free_pages(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab);
+
+/* buffer-preservation managements */
+size_t snd_dma_get_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab);
+int snd_dma_free_reserved(const struct snd_dma_device *dev);
+int snd_dma_set_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab);
+
+/* basic memory allocation functions */
+void *snd_malloc_pages(size_t size, unsigned int gfp_flags);
+void *snd_malloc_pages_fallback(size_t size, unsigned int gfp_flags, size_t *res_size);
+void snd_free_pages(void *ptr, size_t size);
 
 #endif /* __SOUND_MEMALLOC_H */
+
--- diff/include/sound/pcm.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/sound/pcm.h	2004-03-09 11:51:51.000000000 +0000
@@ -889,6 +889,9 @@ snd_pcm_sframes_t snd_pcm_lib_writev(snd
 snd_pcm_sframes_t snd_pcm_lib_readv(snd_pcm_substream_t *substream,
 				    void **bufs, snd_pcm_uframes_t frames);
 
+int snd_pcm_limit_hw_rates(snd_pcm_runtime_t *runtime);
+
+
 /*
  *  Timer interface
  */
@@ -904,49 +907,18 @@ void snd_pcm_timer_done(snd_pcm_substrea
 int snd_pcm_lib_preallocate_free(snd_pcm_substream_t *substream);
 int snd_pcm_lib_preallocate_free_for_all(snd_pcm_t *pcm);
 int snd_pcm_lib_preallocate_pages(snd_pcm_substream_t *substream,
-				  size_t size, size_t max,
-				  unsigned int flags);
+				  int type, struct device *data,
+				  size_t size, size_t max);
 int snd_pcm_lib_preallocate_pages_for_all(snd_pcm_t *pcm,
-					  size_t size, size_t max,
-					  unsigned int flags);
+					  int type, void *data,
+					  size_t size, size_t max);
 int snd_pcm_lib_malloc_pages(snd_pcm_substream_t *substream, size_t size);
 int snd_pcm_lib_free_pages(snd_pcm_substream_t *substream);
 
-#ifdef CONFIG_ISA
-int snd_pcm_lib_preallocate_isa_pages(snd_pcm_substream_t *substream,
-				      size_t size, size_t max);
-int snd_pcm_lib_preallocate_isa_pages_for_all(snd_pcm_t *pcm,
-					      size_t size, size_t max);
-#endif
-#ifdef CONFIG_PCI
-int snd_pcm_lib_preallocate_pci_pages(struct pci_dev *pci,
-				      snd_pcm_substream_t *substream,
-				      size_t size, size_t max);
-int snd_pcm_lib_preallocate_pci_pages_for_all(struct pci_dev *pci,
-					      snd_pcm_t *pcm,
-					      size_t size,
-					      size_t max);
-int snd_pcm_lib_preallocate_sg_pages(struct pci_dev *pci,
-				     snd_pcm_substream_t *substream,
-				     size_t size, size_t max);
-int snd_pcm_lib_preallocate_sg_pages_for_all(struct pci_dev *pci,
-					     snd_pcm_t *pcm,
-					     size_t size, size_t max);
 #define snd_pcm_substream_sgbuf(substream) ((substream)->runtime->dma_private)
 #define snd_pcm_sgbuf_pages(size) snd_sgbuf_aligned_pages(size)
 #define snd_pcm_sgbuf_get_addr(sgbuf,ofs) snd_sgbuf_get_addr(sgbuf,ofs)
 struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset);
-#endif
-
-#ifdef CONFIG_SBUS
-int snd_pcm_lib_preallocate_sbus_pages(struct sbus_dev *sdev,
-				       snd_pcm_substream_t *substream,
-				       size_t size, size_t max);
-int snd_pcm_lib_preallocate_sbus_pages_for_all(struct sbus_dev *sdev,
-					       snd_pcm_t *pcm,
-					       size_t size,
-					       size_t max);
-#endif
 
 static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max)
 {
--- diff/include/sound/pcm_oss.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/sound/pcm_oss.h	2004-03-09 11:51:51.000000000 +0000
@@ -50,6 +50,7 @@ typedef struct _snd_pcm_oss_runtime {
 	unsigned int maxfrags;
 	unsigned int subdivision;		/* requested subdivision */
 	size_t period_bytes;			/* requested period size */
+	size_t period_frames;			/* period frames for poll */
 	size_t period_ptr;			/* actual write pointer to period */
 	unsigned int periods;
 	size_t buffer_bytes;			/* requested buffer size */
--- diff/include/sound/sndmagic.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/sound/sndmagic.h	2004-03-09 11:51:51.000000000 +0000
@@ -200,6 +200,7 @@ static inline int _snd_magic_bad(void *o
 #define azf3328_t_magic				0xa15a4200
 #define snd_card_harmony_t_magic		0xa15a4300
 #define bt87x_t_magic				0xa15a4400
+#define pdacf_t_magic				0xa15a4500
 
 #else
 
--- diff/include/sound/trident.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/sound/trident.h	2004-03-09 11:51:51.000000000 +0000
@@ -308,11 +308,9 @@ typedef struct {
 	unsigned int * entries;		/* 16k-aligned TLB table */
 	dma_addr_t entries_dmaaddr;	/* 16k-aligned PCI address to TLB table */
 	unsigned long * shadow_entries;	/* shadow entries with virtual addresses */
-	void * buffer;			/* pointer for table calloc */
-	dma_addr_t buffer_dmaaddr;	/* not accessible PCI BUS physical address */
+	struct snd_dma_buffer buffer;
 	snd_util_memhdr_t * memhdr;	/* page allocation list */
-	void * silent_page;		/* silent page */
-	dma_addr_t silent_page_dmaaddr; /* not accessible PCI BUS physical address */
+	struct snd_dma_buffer silent_page;
 } snd_trident_tlb_t;
 
 struct _snd_trident_voice {
@@ -435,6 +433,8 @@ struct _snd_trident {
 	spinlock_t event_lock;
 	spinlock_t voice_alloc;
 
+	struct snd_dma_device dma_dev;
+
 	struct pci_dev *pci;
 	snd_card_t *card;
 	snd_pcm_t *pcm;		/* ADC/DAC PCM */
--- diff/include/sound/version.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/sound/version.h	2004-03-09 11:51:51.000000000 +0000
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated by configure.  */
-#define CONFIG_SND_VERSION "1.0.2c"
-#define CONFIG_SND_DATE " (Thu Feb 05 15:41:49 2004 UTC)"
+#define CONFIG_SND_VERSION "1.0.3"
+#define CONFIG_SND_DATE " (Mon Mar 01 10:12:14 2004 UTC)"
--- diff/include/sound/ymfpci.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/sound/ymfpci.h	2004-03-09 11:51:51.000000000 +0000
@@ -316,9 +316,8 @@ struct _snd_ymfpci {
 	struct gameport gameport;
 #endif
 
-	void *work_ptr;
-	dma_addr_t work_ptr_addr;
-	unsigned long work_ptr_size;
+	struct snd_dma_device dma_dev;
+	struct snd_dma_buffer work_ptr;
 
 	unsigned int bank_size_playback;
 	unsigned int bank_size_capture;
@@ -333,8 +332,7 @@ struct _snd_ymfpci {
 	dma_addr_t bank_base_capture_addr;
 	dma_addr_t bank_base_effect_addr;
 	dma_addr_t work_base_addr;
-	void *ac3_tmp_base;
-	dma_addr_t ac3_tmp_base_addr;
+	struct snd_dma_buffer ac3_tmp_base;
 
 	u32 *ctrl_playback;
 	snd_ymfpci_playback_bank_t *bank_playback[YDSXG_PLAYBACK_VOICES][2];
--- diff/init/Kconfig	2004-03-04 11:41:49.000000000 +0000
+++ source/init/Kconfig	2004-03-09 11:51:51.000000000 +0000
@@ -43,7 +43,7 @@ config CLEAN_COMPILE
 
 config STANDALONE
 	bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL
-	default y
+	default n
 	help
 	  Select this option if you don't have magic firmware for drivers that
 	  need it.
@@ -91,6 +91,24 @@ config SYSVIPC
 	  section 6.4 of the Linux Programmer's Guide, available from
 	  <http://www.tldp.org/docs.html#guide>.
 
+config POSIX_MQUEUE
+	bool "POSIX Message Queues"
+	depends on EXPERIMENTAL
+	---help---
+	  POSIX variant of message queues is a part of IPC. In POSIX message
+	  queues every message has a priority which decides about succession
+	  of receiving it by a process. If you want to compile and run
+	  programs written e.g. for Solaris with use of its POSIX message
+	  queues (functions mq_*) say Y here. To use this feature you will
+	  also need mqueue library, available from
+	  <http://www.mat.uni.torun.pl/~wrona/posix_ipc/>
+
+	  POSIX message queues are visible as a filesystem called 'mqueue'
+	  and can be mounted somewhere if you want to do filesystem
+	  operations on message queues.
+
+	  If unsure, say Y.
+
 config BSD_PROCESS_ACCT
 	bool "BSD Process Accounting"
 	help
@@ -304,4 +322,10 @@ config KMOD
 	  runs modprobe with the appropriate arguments, thereby
 	  loading the module if it is available.  If unsure, say Y.
 
+config STOP_MACHINE
+	bool
+	default y
+	depends on (SMP && MODULE_UNLOAD) || HOTPLUG_CPU
+	help
+	  Need stop_machine() primitive.
 endmenu
--- diff/init/do_mounts.c	2004-01-19 10:22:59.000000000 +0000
+++ source/init/do_mounts.c	2004-03-09 11:51:51.000000000 +0000
@@ -66,11 +66,11 @@ static dev_t __init try_name(char *name,
 	/* read device number from .../dev */
 
 	sprintf(path, "/sys/block/%s/dev", name);
-	fd = open(path, 0, 0);
+	fd = sys_open(path, 0, 0);
 	if (fd < 0)
 		goto fail;
-	len = read(fd, buf, 32);
-	close(fd);
+	len = sys_read(fd, buf, 32);
+	sys_close(fd);
 	if (len <= 0 || len == 32 || buf[len - 1] != '\n')
 		goto fail;
 	buf[len - 1] = '\0';
@@ -96,11 +96,11 @@ static dev_t __init try_name(char *name,
 
 	/* otherwise read range from .../range */
 	sprintf(path, "/sys/block/%s/range", name);
-	fd = open(path, 0, 0);
+	fd = sys_open(path, 0, 0);
 	if (fd < 0)
 		goto fail;
-	len = read(fd, buf, 32);
-	close(fd);
+	len = sys_read(fd, buf, 32);
+	sys_close(fd);
 	if (len <= 0 || len == 32 || buf[len - 1] != '\n')
 		goto fail;
 	buf[len - 1] = '\0';
@@ -141,9 +141,11 @@ dev_t __init name_to_dev_t(char *name)
 	dev_t res = 0;
 	int part;
 
+#ifdef CONFIG_SYSFS
 	sys_mkdir("/sys", 0700);
 	if (sys_mount("sysfs", "/sys", "sysfs", 0, NULL) < 0)
 		goto out;
+#endif
 
 	if (strncmp(name, "/dev/", 5) != 0) {
 		unsigned maj, min;
@@ -285,7 +287,7 @@ retry:
 				continue;
 		}
 	        /*
-		 * Allow the user to distinguish between failed open
+		 * Allow the user to distinguish between failed sys_open
 		 * and bad superblock on root device.
 		 */
 		__bdevname(ROOT_DEV, b);
@@ -324,21 +326,21 @@ void __init change_floppy(char *fmt, ...
 	va_start(args, fmt);
 	vsprintf(buf, fmt, args);
 	va_end(args);
-	fd = open("/dev/root", O_RDWR | O_NDELAY, 0);
+	fd = sys_open("/dev/root", O_RDWR | O_NDELAY, 0);
 	if (fd >= 0) {
 		sys_ioctl(fd, FDEJECT, 0);
-		close(fd);
+		sys_close(fd);
 	}
 	printk(KERN_NOTICE "VFS: Insert %s and press ENTER\n", buf);
-	fd = open("/dev/console", O_RDWR, 0);
+	fd = sys_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);
+		sys_read(fd, &c, 1);
 		termios.c_lflag |= ICANON;
 		sys_ioctl(fd, TCSETSF, (long)&termios);
-		close(fd);
+		sys_close(fd);
 	}
 }
 #endif
--- diff/init/do_mounts.h	2004-03-04 11:41:49.000000000 +0000
+++ source/init/do_mounts.h	2004-03-09 11:51:51.000000000 +0000
@@ -1,4 +1,3 @@
-#define __KERNEL_SYSCALLS__
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/devfs_fs_kernel.h>
--- diff/init/do_mounts_devfs.c	2004-03-04 11:41:49.000000000 +0000
+++ source/init/do_mounts_devfs.c	2004-03-09 11:51:51.000000000 +0000
@@ -24,7 +24,7 @@ static int __init do_read_dir(int fd, vo
 {
 	long bytes, n;
 	char *p = buf;
-	lseek(fd, 0, 0);
+	sys_lseek(fd, 0, 0);
 
 	for (bytes = 0; bytes < len; bytes += n) {
 		n = sys_getdents64(fd, (struct linux_dirent64 *)(p + bytes),
@@ -45,7 +45,7 @@ static int __init do_read_dir(int fd, vo
 static void * __init read_dir(char *path, int *len)
 {
 	int size;
-	int fd = open(path, 0, 0);
+	int fd = sys_open(path, 0, 0);
 
 	*len = 0;
 	if (fd < 0)
@@ -58,7 +58,7 @@ static void * __init read_dir(char *path
 			break;
 		n = do_read_dir(fd, p, size);
 		if (n > 0) {
-			close(fd);
+			sys_close(fd);
 			*len = n;
 			return p;
 		}
@@ -68,7 +68,7 @@ static void * __init read_dir(char *path
 		if (n < 0)
 			break;
 	}
-	close(fd);
+	sys_close(fd);
 	return NULL;
 }
 
--- diff/init/do_mounts_initrd.c	2003-10-27 09:20:44.000000000 +0000
+++ source/init/do_mounts_initrd.c	2004-03-09 11:51:51.000000000 +0000
@@ -1,4 +1,5 @@
-
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/minix_fs.h>
@@ -28,12 +29,12 @@ static int __init do_linuxrc(void * shel
 	static char *argv[] = { "linuxrc", NULL, };
 	extern char * envp_init[];
 
-	close(old_fd);close(root_fd);
-	close(0);close(1);close(2);
-	setsid();
-	(void) open("/dev/console",O_RDWR,0);
-	(void) dup(0);
-	(void) dup(0);
+	sys_close(old_fd);sys_close(root_fd);
+	sys_close(0);sys_close(1);sys_close(2);
+	sys_setsid();
+	(void) sys_open("/dev/console",O_RDWR,0);
+	(void) sys_dup(0);
+	(void) sys_dup(0);
 	return execve(shell, argv, envp_init);
 }
 
@@ -47,8 +48,8 @@ static void __init handle_initrd(void)
 	/* mount initrd on rootfs' /root */
 	mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY);
 	sys_mkdir("/old", 0700);
-	root_fd = open("/", 0, 0);
-	old_fd = open("/old", 0, 0);
+	root_fd = sys_open("/", 0, 0);
+	old_fd = sys_open("/old", 0, 0);
 	/* move initrd over / and chdir/chroot in initrd root */
 	sys_chdir("/root");
 	sys_mount(".", "/", NULL, MS_MOVE, NULL);
@@ -57,7 +58,7 @@ static void __init handle_initrd(void)
 
 	pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
 	if (pid > 0) {
-		while (pid != waitpid(-1, &i, 0))
+		while (pid != sys_wait4(-1, &i, 0, 0))
 			yield();
 	}
 
@@ -67,8 +68,8 @@ static void __init handle_initrd(void)
 	/* switch root and cwd back to / of rootfs */
 	sys_fchdir(root_fd);
 	sys_chroot(".");
-	close(old_fd);
-	close(root_fd);
+	sys_close(old_fd);
+	sys_close(root_fd);
 	umount_devfs("/old/dev");
 
 	if (new_decode_dev(real_root_dev) == Root_RAM0) {
@@ -84,7 +85,7 @@ static void __init handle_initrd(void)
 	if (!error)
 		printk("okay\n");
 	else {
-		int fd = open("/dev/root.old", O_RDWR, 0);
+		int fd = sys_open("/dev/root.old", O_RDWR, 0);
 		printk("failed\n");
 		printk(KERN_NOTICE "Unmounting old root\n");
 		sys_umount("/old", MNT_DETACH);
@@ -93,7 +94,7 @@ static void __init handle_initrd(void)
 			error = fd;
 		} else {
 			error = sys_ioctl(fd, BLKFLSBUF, 0);
-			close(fd);
+			sys_close(fd);
 		}
 		printk(!error ? "okay\n" : "failed\n");
 	}
--- diff/init/do_mounts_md.c	2003-09-30 15:46:21.000000000 +0100
+++ source/init/do_mounts_md.c	2004-03-09 11:51:51.000000000 +0000
@@ -12,14 +12,17 @@
  * The code for that is here.
  */
 
-static int __initdata raid_noautodetect;
+static int __initdata raid_noautodetect, raid_autopart;
 
 static struct {
-	char device_set [MAX_MD_DEVS];
-	int pers[MAX_MD_DEVS];
-	int chunk[MAX_MD_DEVS];
-	char *device_names[MAX_MD_DEVS];
-} md_setup_args __initdata;
+	int minor;
+	int partitioned;
+	int pers;
+	int chunk;
+	char *device_names;
+} md_setup_args[MAX_MD_DEVS] __initdata;
+
+static int md_setup_ents __initdata;
 
 /*
  * Parse the command-line parameters given our kernel, but do not
@@ -43,21 +46,37 @@ static struct {
  */
 static int __init md_setup(char *str)
 {
-	int minor, level, factor, fault, pers;
+	int minor, level, factor, fault, pers, partitioned = 0;
 	char *pername = "";
-	char *str1 = str;
+	char *str1;
+	int ent;
 
+	if (*str == 'd') {
+		partitioned = 1;
+		str++;
+	}
 	if (get_option(&str, &minor) != 2) {	/* MD Number */
 		printk(KERN_WARNING "md: Too few arguments supplied to md=.\n");
 		return 0;
 	}
+	str1 = str;
 	if (minor >= MAX_MD_DEVS) {
 		printk(KERN_WARNING "md: md=%d, Minor device number too high.\n", minor);
 		return 0;
-	} else if (md_setup_args.device_names[minor]) {
-		printk(KERN_WARNING "md: md=%d, Specified more than once. "
-		       "Replacing previous definition.\n", minor);
 	}
+	for (ent=0 ; ent< md_setup_ents ; ent++)
+		if (md_setup_args[ent].minor == minor &&
+		    md_setup_args[ent].partitioned == partitioned) {
+			printk(KERN_WARNING "md: md=%s%d, Specified more than once. "
+			       "Replacing previous definition.\n", partitioned?"d":"", minor);
+			break;
+		}
+	if (ent >= MAX_MD_DEVS) {
+		printk(KERN_WARNING "md: md=%s%d - too many md initialisations\n", partitioned?"d":"", minor);
+		return 0;
+	}
+	if (ent >= md_setup_ents)
+		md_setup_ents++;
 	switch (get_option(&str, &level)) {	/* RAID Personality */
 	case 2: /* could be 0 or -1.. */
 		if (level == 0 || level == LEVEL_LINEAR) {
@@ -66,24 +85,16 @@ static int __init md_setup(char *str)
 				printk(KERN_WARNING "md: Too few arguments supplied to md=.\n");
 				return 0;
 			}
-			md_setup_args.pers[minor] = level;
-			md_setup_args.chunk[minor] = 1 << (factor+12);
-			switch(level) {
-			case LEVEL_LINEAR:
+			md_setup_args[ent].pers = level;
+			md_setup_args[ent].chunk = 1 << (factor+12);
+			if (level ==  LEVEL_LINEAR) {
 				pers = LINEAR;
 				pername = "linear";
-				break;
-			case 0:
+			} else {
 				pers = RAID0;
 				pername = "raid0";
-				break;
-			default:
-				printk(KERN_WARNING
-				       "md: The kernel has not been configured for raid%d support!\n",
-				       level);
-				return 0;
 			}
-			md_setup_args.pers[minor] = pers;
+			md_setup_args[ent].pers = pers;
 			break;
 		}
 		/* FALL THROUGH */
@@ -91,35 +102,38 @@ static int __init md_setup(char *str)
 		str = str1;
 		/* FALL THROUGH */
 	case 0:
-		md_setup_args.pers[minor] = 0;
+		md_setup_args[ent].pers = 0;
 		pername="super-block";
 	}
 
 	printk(KERN_INFO "md: Will configure md%d (%s) from %s, below.\n",
 		minor, pername, str);
-	md_setup_args.device_names[minor] = str;
+	md_setup_args[ent].device_names = str;
+	md_setup_args[ent].partitioned = partitioned;
+	md_setup_args[ent].minor = minor;
 
 	return 1;
 }
 
 static void __init md_setup_drive(void)
 {
-	int minor, i;
+	int minor, i, ent, partitioned;
 	dev_t dev;
 	dev_t devices[MD_SB_DISKS+1];
 
-	for (minor = 0; minor < MAX_MD_DEVS; minor++) {
+	for (ent = 0; ent < md_setup_ents ; ent++) {
 		int fd;
 		int err = 0;
 		char *devname;
 		mdu_disk_info_t dinfo;
 		char name[16], devfs_name[16];
 
-		if (!(devname = md_setup_args.device_names[minor]))
-			continue;
-		
-		sprintf(name, "/dev/md%d", minor);
-		sprintf(devfs_name, "/dev/md/%d", minor);
+		minor = md_setup_args[ent].minor;
+		partitioned = md_setup_args[ent].partitioned;
+		devname = md_setup_args[ent].device_names;
+
+		sprintf(name, "/dev/md%s%d", partitioned?"_d":"", minor);
+		sprintf(devfs_name, "/dev/md/%s%d", partitioned?"d":"", minor);
 		create_dev(name, MKDEV(MD_MAJOR, minor), devfs_name);
 		for (i = 0; i < MD_SB_DISKS && devname != 0; i++) {
 			char *p;
@@ -143,34 +157,36 @@ static void __init md_setup_drive(void)
 			}
 
 			devices[i] = dev;
-			md_setup_args.device_set[minor] = 1;
 
 			devname = p;
 		}
 		devices[i] = 0;
 
-		if (!md_setup_args.device_set[minor])
+		if (!i)
 			continue;
 
-		printk(KERN_INFO "md: Loading md%d: %s\n", minor, md_setup_args.device_names[minor]);
+		printk(KERN_INFO "md: Loading md%s%d: %s\n",
+			partitioned ? "_d" : "", minor,
+			md_setup_args[ent].device_names);
 
-		fd = open(name, 0, 0);
+		fd = sys_open(name, 0, 0);
 		if (fd < 0) {
-			printk(KERN_ERR "md: open failed - cannot start array %d\n", minor);
+			printk(KERN_ERR "md: open failed - cannot start "
+					"array %s\n", name);
 			continue;
 		}
 		if (sys_ioctl(fd, SET_ARRAY_INFO, 0) == -EBUSY) {
 			printk(KERN_WARNING
 			       "md: Ignoring md=%d, already autodetected. (Use raid=noautodetect)\n",
 			       minor);
-			close(fd);
+			sys_close(fd);
 			continue;
 		}
 
-		if (md_setup_args.pers[minor]) {
+		if (md_setup_args[ent].pers) {
 			/* non-persistent */
 			mdu_array_info_t ainfo;
-			ainfo.level = pers_to_level(md_setup_args.pers[minor]);
+			ainfo.level = pers_to_level(md_setup_args[ent].pers);
 			ainfo.size = 0;
 			ainfo.nr_disks =0;
 			ainfo.raid_disks =0;
@@ -181,7 +197,7 @@ static void __init md_setup_drive(void)
 
 			ainfo.state = (1 << MD_SB_CLEAN);
 			ainfo.layout = 0;
-			ainfo.chunk_size = md_setup_args.chunk[minor];
+			ainfo.chunk_size = md_setup_args[ent].chunk;
 			err = sys_ioctl(fd, SET_ARRAY_INFO, (long)&ainfo);
 			for (i = 0; !err && i <= MD_SB_DISKS; i++) {
 				dev = devices[i];
@@ -209,7 +225,7 @@ static void __init md_setup_drive(void)
 			err = sys_ioctl(fd, RUN_ARRAY, 0);
 		if (err)
 			printk(KERN_WARNING "md: starting md%d failed\n", minor);
-		close(fd);
+		sys_close(fd);
 	}
 }
 
@@ -229,6 +245,10 @@ static int __init raid_setup(char *str)
 
 		if (!strncmp(str, "noautodetect", wlen))
 			raid_noautodetect = 1;
+		if (strncmp(str, "partitionable", wlen)==0)
+			raid_autopart = 1;
+		if (strncmp(str, "part", wlen)==0)
+			raid_autopart = 1;
 		pos += wlen+1;
 	}
 	return 1;
@@ -243,10 +263,10 @@ void __init md_run_setup(void)
 	if (raid_noautodetect)
 		printk(KERN_INFO "md: Skipping autodetection of RAID arrays. (raid=noautodetect)\n");
 	else {
-		int fd = open("/dev/md0", 0, 0);
+		int fd = sys_open("/dev/md0", 0, 0);
 		if (fd >= 0) {
-			sys_ioctl(fd, RAID_AUTORUN, 0);
-			close(fd);
+			sys_ioctl(fd, RAID_AUTORUN, raid_autopart);
+			sys_close(fd);
 		}
 	}
 	md_setup_drive();
--- diff/init/do_mounts_rd.c	2004-02-18 08:54:13.000000000 +0000
+++ source/init/do_mounts_rd.c	2004-03-09 11:51:51.000000000 +0000
@@ -69,8 +69,8 @@ identify_ramdisk_image(int fd, int start
 	/*
 	 * Read block 0 to test for gzipped kernel
 	 */
-	lseek(fd, start_block * BLOCK_SIZE, 0);
-	read(fd, buf, size);
+	sys_lseek(fd, start_block * BLOCK_SIZE, 0);
+	sys_read(fd, buf, size);
 
 	/*
 	 * If it matches the gzip magic numbers, return -1
@@ -104,8 +104,8 @@ identify_ramdisk_image(int fd, int start
 	/*
 	 * Read block 1 to test for minix and ext2 superblock
 	 */
-	lseek(fd, (start_block+1) * BLOCK_SIZE, 0);
-	read(fd, buf, size);
+	sys_lseek(fd, (start_block+1) * BLOCK_SIZE, 0);
+	sys_read(fd, buf, size);
 
 	/* Try minix */
 	if (minixsb->s_magic == MINIX_SUPER_MAGIC ||
@@ -131,7 +131,7 @@ identify_ramdisk_image(int fd, int start
 	       start_block);
 	
 done:
-	lseek(fd, start_block * BLOCK_SIZE, 0);
+	sys_lseek(fd, start_block * BLOCK_SIZE, 0);
 	kfree(buf);
 	return nblocks;
 }
@@ -148,11 +148,11 @@ int __init rd_load_image(char *from)
 	char rotator[4] = { '|' , '/' , '-' , '\\' };
 #endif
 
-	out_fd = open("/dev/ram", O_RDWR, 0);
+	out_fd = sys_open("/dev/ram", O_RDWR, 0);
 	if (out_fd < 0)
 		goto out;
 
-	in_fd = open(from, O_RDONLY, 0);
+	in_fd = sys_open(from, O_RDONLY, 0);
 	if (in_fd < 0)
 		goto noclose_input;
 
@@ -217,20 +217,20 @@ int __init rd_load_image(char *from)
 		if (i && (i % devblocks == 0)) {
 			printk("done disk #%d.\n", disk++);
 			rotate = 0;
-			if (close(in_fd)) {
+			if (sys_close(in_fd)) {
 				printk("Error closing the disk.\n");
 				goto noclose_input;
 			}
 			change_floppy("disk #%d", disk);
-			in_fd = open(from, O_RDONLY, 0);
+			in_fd = sys_open(from, O_RDONLY, 0);
 			if (in_fd < 0)  {
 				printk("Error opening disk.\n");
 				goto noclose_input;
 			}
 			printk("Loading disk #%d... ", disk);
 		}
-		read(in_fd, buf, BLOCK_SIZE);
-		write(out_fd, buf, BLOCK_SIZE);
+		sys_read(in_fd, buf, BLOCK_SIZE);
+		sys_write(out_fd, buf, BLOCK_SIZE);
 #if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES)
 		if (!(i % 16)) {
 			printk("%c\b", rotator[rotate & 0x3]);
@@ -243,9 +243,9 @@ int __init rd_load_image(char *from)
 successful_load:
 	res = 1;
 done:
-	close(in_fd);
+	sys_close(in_fd);
 noclose_input:
-	close(out_fd);
+	sys_close(out_fd);
 out:
 	kfree(buf);
 	sys_unlink("/dev/ram");
@@ -342,7 +342,7 @@ static int __init fill_inbuf(void)
 {
 	if (exit_code) return -1;
 	
-	insize = read(crd_infd, inbuf, INBUFSIZ);
+	insize = sys_read(crd_infd, inbuf, INBUFSIZ);
 	if (insize == 0) {
 		error("RAMDISK: ran out of compressed data");
 		return -1;
@@ -363,7 +363,7 @@ static void __init flush_window(void)
     unsigned n, written;
     uch *in, ch;
     
-    written = write(crd_outfd, window, outcnt);
+    written = sys_write(crd_outfd, window, outcnt);
     if (written != outcnt && unzip_error == 0) {
 	printk(KERN_ERR "RAMDISK: incomplete write (%d != %d) %ld\n",
 	       written, outcnt, bytes_out);
--- diff/init/initramfs.c	2004-03-04 11:41:49.000000000 +0000
+++ source/init/initramfs.c	2004-03-09 11:51:51.000000000 +0000
@@ -1,10 +1,8 @@
-#define __KERNEL_SYSCALLS__
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
-#include <linux/unistd.h>
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/syscalls.h>
--- diff/init/main.c	2004-03-04 11:41:49.000000000 +0000
+++ source/init/main.c	2004-03-09 11:51:51.000000000 +0000
@@ -18,7 +18,6 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/kernel.h>
 #include <linux/syscalls.h>
-#include <linux/unistd.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
 #include <linux/delay.h>
@@ -41,6 +40,7 @@
 #include <linux/writeback.h>
 #include <linux/cpu.h>
 #include <linux/efi.h>
+#include <linux/unistd.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -155,8 +155,11 @@ static int __init obsolete_checksetup(ch
 	p = &__setup_start;
 	do {
 		int n = strlen(p->str);
-		if (!strncmp(line,p->str,n)) {
-			if (p->setup_func(line+n))
+		if (!strncmp(line, p->str, n)) {
+			if (!p->setup_func) {
+				printk(KERN_WARNING "Parameter %s is obsolete, ignored\n", p->str);
+				return 1;
+			} else if (p->setup_func(line + n))
 				return 1;
 		}
 		p++;
@@ -417,12 +420,12 @@ asmlinkage void __init start_kernel(void
 
 	build_all_zonelists();
 	page_alloc_init();
+	trap_init();
 	printk("Kernel command line: %s\n", saved_command_line);
 	parse_args("Booting kernel", command_line, __start___param,
 		   __stop___param - __start___param,
 		   &unknown_bootoption);
 	sort_main_extable();
-	trap_init();
 	rcu_init();
 	init_IRQ();
 	pidhash_init();
@@ -564,7 +567,6 @@ static void do_pre_smp_initcalls(void)
 
 	migration_init();
 #endif
-	node_nr_running_init();
 	spawn_ksoftirqd();
 }
 
@@ -595,8 +597,16 @@ static int init(void * unused)
 	do_pre_smp_initcalls();
 
 	smp_init();
+	sched_init_smp();
 	do_basic_setup();
 
+       /*
+        * check if there is an early userspace init, if yes
+        * let it do all the work
+        */
+       if (sys_access("/init", 0) == 0)
+               execute_command = "/init";
+       else
 	prepare_namespace();
 
 	/*
@@ -608,11 +618,11 @@ static int init(void * unused)
 	unlock_kernel();
 	system_running = 1;
 
-	if (open("/dev/console", O_RDWR, 0) < 0)
+	if (sys_open("/dev/console", O_RDWR, 0) < 0)
 		printk("Warning: unable to open an initial console.\n");
 
-	(void) dup(0);
-	(void) dup(0);
+	(void) sys_dup(0);
+	(void) sys_dup(0);
 	
 	/*
 	 * We try each of these until one succeeds.
--- diff/ipc/Makefile	2002-12-16 09:26:07.000000000 +0000
+++ source/ipc/Makefile	2004-03-09 11:51:51.000000000 +0000
@@ -2,6 +2,7 @@
 # Makefile for the linux ipc.
 #
 
-obj-y   := util.o
+obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o
+obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o
+obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o
 
-obj-$(CONFIG_SYSVIPC) += msg.o sem.o shm.o
--- diff/ipc/msg.c	2004-02-09 10:36:12.000000000 +0000
+++ source/ipc/msg.c	2004-03-09 11:51:51.000000000 +0000
@@ -51,11 +51,6 @@ struct msg_sender {
 	struct task_struct* tsk;
 };
 
-struct msg_msgseg {
-	struct msg_msgseg* next;
-	/* the next part of the message follows immediately */
-};
-
 #define SEARCH_ANY		1
 #define SEARCH_EQUAL		2
 #define SEARCH_NOTEQUAL		3
@@ -129,106 +124,6 @@ static int newque (key_t key, int msgflg
 	return msg_buildid(id,msq->q_perm.seq);
 }
 
-static void free_msg(struct msg_msg* msg)
-{
-	struct msg_msgseg* seg;
-
-	security_msg_msg_free(msg);
-
-	seg = msg->next;
-	kfree(msg);
-	while(seg != NULL) {
-		struct msg_msgseg* tmp = seg->next;
-		kfree(seg);
-		seg = tmp;
-	}
-}
-
-static struct msg_msg* load_msg(void* src, int len)
-{
-	struct msg_msg* msg;
-	struct msg_msgseg** pseg;
-	int err;
-	int alen;
-
-	alen = len;
-	if(alen > DATALEN_MSG)
-		alen = DATALEN_MSG;
-
-	msg = (struct msg_msg *) kmalloc (sizeof(*msg) + alen, GFP_KERNEL);
-	if(msg==NULL)
-		return ERR_PTR(-ENOMEM);
-
-	msg->next = NULL;
-	msg->security = NULL;
-
-	if (copy_from_user(msg+1, src, alen)) {
-		err = -EFAULT;
-		goto out_err;
-	}
-
-	len -= alen;
-	src = ((char*)src)+alen;
-	pseg = &msg->next;
-	while(len > 0) {
-		struct msg_msgseg* seg;
-		alen = len;
-		if(alen > DATALEN_SEG)
-			alen = DATALEN_SEG;
-		seg = (struct msg_msgseg *) kmalloc (sizeof(*seg) + alen, GFP_KERNEL);
-		if(seg==NULL) {
-			err=-ENOMEM;
-			goto out_err;
-		}
-		*pseg = seg;
-		seg->next = NULL;
-		if(copy_from_user (seg+1, src, alen)) {
-			err = -EFAULT;
-			goto out_err;
-		}
-		pseg = &seg->next;
-		len -= alen;
-		src = ((char*)src)+alen;
-	}
-	
-	err = security_msg_msg_alloc(msg);
-	if (err)
-		goto out_err;
-
-	return msg;
-
-out_err:
-	free_msg(msg);
-	return ERR_PTR(err);
-}
-
-static int store_msg(void* dest, struct msg_msg* msg, int len)
-{
-	int alen;
-	struct msg_msgseg *seg;
-
-	alen = len;
-	if(alen > DATALEN_MSG)
-		alen = DATALEN_MSG;
-	if(copy_to_user (dest, msg+1, alen))
-		return -1;
-
-	len -= alen;
-	dest = ((char*)dest)+alen;
-	seg = msg->next;
-	while(len > 0) {
-		alen = len;
-		if(alen > DATALEN_SEG)
-			alen = DATALEN_SEG;
-		if(copy_to_user (dest, seg+1, alen))
-			return -1;
-		len -= alen;
-		dest = ((char*)dest)+alen;
-		seg=seg->next;
-	}
-	return 0;
-}
-
 static inline void ss_add(struct msg_queue* msq, struct msg_sender* mss)
 {
 	mss->tsk=current;
--- diff/ipc/sem.c	2004-03-04 11:41:49.000000000 +0000
+++ source/ipc/sem.c	2004-03-09 11:51:51.000000000 +0000
@@ -993,7 +993,6 @@ static struct sem_undo *find_undo(int se
 	}
 	error = sem_revalidate(semid, sma, nsems, 0);
 	if (error) {
-		sem_unlock(sma);
 		unlock_semundo();
 		kfree(new);
 		un = ERR_PTR(error);
--- diff/ipc/util.c	2004-03-04 11:41:49.000000000 +0000
+++ source/ipc/util.c	2004-03-09 11:51:51.000000000 +0000
@@ -25,8 +25,6 @@
 #include <linux/rcupdate.h>
 #include <linux/workqueue.h>
 
-#if defined(CONFIG_SYSVIPC)
-
 #include "util.h"
 
 /**
@@ -531,20 +529,3 @@ int ipc_parse_version (int *cmd)
 }
 
 #endif /* __ia64__ */
-
-#else
-/*
- * Dummy functions when SYSV IPC isn't configured
- */
-
-int copy_semundo(unsigned long clone_flags, struct task_struct *tsk)
-{
-	return 0;
-}
-
-void exit_sem(struct task_struct *tsk)
-{
-	return;
-}
-
-#endif /* CONFIG_SYSVIPC */
--- diff/ipc/util.h	2004-02-18 08:54:13.000000000 +0000
+++ source/ipc/util.h	2004-03-09 11:51:51.000000000 +0000
@@ -4,6 +4,10 @@
  *
  * ipc helper functions (c) 1999 Manfred Spraul <manfreds@colorfullife.com>
  */
+
+#ifndef _IPC_UTIL_H
+#define _IPC_UTIL_H
+
 #define USHRT_MAX 0xffff
 #define SEQ_MULTIPLIER	(IPCMNI)
 
@@ -62,3 +66,9 @@ void ipc64_perm_to_ipc_perm(struct ipc64
 #else
 int ipc_parse_version (int *cmd);
 #endif
+
+extern void free_msg(struct msg_msg *msg);
+extern struct msg_msg *load_msg(void __user *src, int len);
+extern int store_msg(void __user *dest, struct msg_msg *msg, int len);
+
+#endif
--- diff/kernel/Makefile	2004-03-04 11:41:49.000000000 +0000
+++ source/kernel/Makefile	2004-03-09 11:51:51.000000000 +0000
@@ -12,14 +12,16 @@ obj-y     = sched.o fork.o exec_domain.o
 obj-$(CONFIG_FUTEX) += futex.o
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += cpu.o
+obj-$(CONFIG_LOCKMETER) += lockmeter.o
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_PM) += power/
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
-obj-$(CONFIG_COMPAT) += compat.o
+obj-$(CONFIG_COMPAT) += compat.o compat_signal.o
 obj-$(CONFIG_IKCONFIG) += configs.o
 obj-$(CONFIG_IKCONFIG_PROC) += configs.o
+obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
 
 ifneq ($(CONFIG_IA64),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
--- diff/kernel/compat.c	2004-03-04 11:41:49.000000000 +0000
+++ source/kernel/compat.c	2004-03-09 11:51:51.000000000 +0000
@@ -30,7 +30,7 @@ int get_compat_timespec(struct timespec 
 			__get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
 }
 
-int put_compat_timespec(struct timespec *ts, const struct compat_timespec *cts)
+int put_compat_timespec(const struct timespec *ts, struct compat_timespec *cts)
 {
 	return (verify_area(VERIFY_WRITE, cts, sizeof(*cts)) ||
 			__put_user(ts->tv_sec, &cts->tv_sec) ||
--- diff/kernel/cpu.c	2004-02-18 08:54:13.000000000 +0000
+++ source/kernel/cpu.c	2004-03-09 11:51:51.000000000 +0000
@@ -1,14 +1,19 @@
 /* CPU control.
- * (C) 2001 Rusty Russell
+ * (C) 2001, 2002, 2003, 2004 Rusty Russell
+ *
  * This code is licenced under the GPL.
  */
 #include <linux/proc_fs.h>
 #include <linux/smp.h>
 #include <linux/init.h>
-#include <linux/notifier.h>
 #include <linux/sched.h>
 #include <linux/unistd.h>
+#include <linux/kmod.h>		/* for hotplug_path */
 #include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/kthread.h>
+#include <linux/stop_machine.h>
 #include <asm/semaphore.h>
 
 /* This protects CPUs going up and down... */
@@ -19,20 +24,149 @@ static struct notifier_block *cpu_chain;
 /* Need to know about CPUs going up/down? */
 int register_cpu_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_register(&cpu_chain, nb);
+	int ret;
+
+	if ((ret = down_interruptible(&cpucontrol)) != 0)
+		return ret;
+	ret = notifier_chain_register(&cpu_chain, nb);
+	up(&cpucontrol);
+	return ret;
 }
+EXPORT_SYMBOL(register_cpu_notifier);
 
 void unregister_cpu_notifier(struct notifier_block *nb)
 {
-	notifier_chain_unregister(&cpu_chain,nb);
+	down(&cpucontrol);
+	notifier_chain_unregister(&cpu_chain, nb);
+	up(&cpucontrol);
+}
+EXPORT_SYMBOL(unregister_cpu_notifier);
+
+#ifdef CONFIG_HOTPLUG_CPU
+static inline void check_for_tasks(int cpu, struct task_struct *k)
+{
+	struct task_struct *p;
+
+	write_lock_irq(&tasklist_lock);
+	for_each_process(p) {
+		if (task_cpu(p) == cpu && p != k)
+			printk(KERN_WARNING "Task %s is on cpu %d\n",
+				p->comm, cpu);
+	}
+	write_unlock_irq(&tasklist_lock);
+}
+
+/* Notify userspace when a cpu event occurs, by running '/sbin/hotplug
+ * cpu' with certain environment variables set.  */
+static int cpu_run_sbin_hotplug(unsigned int cpu, const char *action)
+{
+	char *argv[3], *envp[5], cpu_str[12], action_str[32];
+	int i;
+
+	sprintf(cpu_str, "CPU=%d", cpu);
+	sprintf(action_str, "ACTION=%s", action);
+	/* FIXME: Add DEVPATH. --RR */
+
+	i = 0;
+	argv[i++] = hotplug_path;
+	argv[i++] = "cpu";
+	argv[i] = NULL;
+
+	i = 0;
+	/* minimal command environment */
+	envp [i++] = "HOME=/";
+	envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+	envp [i++] = cpu_str;
+	envp [i++] = action_str;
+	envp [i] = NULL;
+
+	return call_usermodehelper(argv[0], argv, envp, 0);
+}
+
+/* Take this CPU down. */
+static int take_cpu_down(void *unused)
+{
+	int err;
+
+	/* Take offline: makes arch_cpu_down somewhat easier. */
+	cpu_clear(smp_processor_id(), cpu_online_map);
+
+	/* Ensure this CPU doesn't handle any more interrupts. */
+	err = __cpu_disable();
+	if (err < 0)
+		cpu_set(smp_processor_id(), cpu_online_map);
+	else
+		/* Everyone else gets kicked off. */
+		migrate_all_tasks();
+
+	return err;
+}
+
+int cpu_down(unsigned int cpu)
+{
+	int err;
+	struct task_struct *p;
+
+	if ((err = lock_cpu_hotplug_interruptible()) != 0)
+		return err;
+
+	if (num_online_cpus() == 1) {
+		err = -EBUSY;
+		goto out;
+	}
+
+	if (!cpu_online(cpu)) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	p = __stop_machine_run(take_cpu_down, NULL, cpu);
+	if (IS_ERR(p)) {
+		err = PTR_ERR(p);
+		goto out;
+	}
+
+	if (cpu_online(cpu))
+		goto out_thread;
+
+	check_for_tasks(cpu, p);
+
+	/* Wait for it to sleep (leaving idle task). */
+	while (!idle_cpu(cpu))
+		yield();
+
+	/* This actually kills the CPU. */
+	__cpu_die(cpu);
+
+	/* Move it here so it can run. */
+	kthread_bind(p, smp_processor_id());
+
+	/* CPU is completely dead: tell everyone.  Too late to complain. */
+	if (notifier_call_chain(&cpu_chain, CPU_DEAD, (void *)(long)cpu)
+	    == NOTIFY_BAD)
+		BUG();
+
+	cpu_run_sbin_hotplug(cpu, "offline");
+
+out_thread:
+	err = kthread_stop(p);
+out:
+	unlock_cpu_hotplug();
+	return err;
+}
+#else
+static inline int cpu_run_sbin_hotplug(unsigned int cpu, const char *action)
+{
+	return 0;
 }
+#endif /*CONFIG_HOTPLUG_CPU*/
 
 int __devinit cpu_up(unsigned int cpu)
 {
 	int ret;
 	void *hcpu = (void *)(long)cpu;
 
-	if ((ret = down_interruptible(&cpucontrol)) != 0)
+	if ((ret = lock_cpu_hotplug_interruptible()) != 0)
 		return ret;
 
 	if (cpu_online(cpu)) {
@@ -61,6 +195,6 @@ out_notify:
 	if (ret != 0)
 		notifier_call_chain(&cpu_chain, CPU_UP_CANCELED, hcpu);
 out:
-	up(&cpucontrol);
+	unlock_cpu_hotplug();
 	return ret;
 }
--- diff/kernel/exit.c	2004-03-04 11:41:49.000000000 +0000
+++ source/kernel/exit.c	2004-03-09 11:51:51.000000000 +0000
@@ -386,7 +386,7 @@ static inline void close_files(struct fi
 	}
 }
 
-void put_files_struct(struct files_struct *files)
+void fastcall put_files_struct(struct files_struct *files)
 {
 	if (atomic_dec_and_test(&files->count)) {
 		close_files(files);
@@ -810,7 +810,7 @@ asmlinkage long sys_exit(int error_code)
 	do_exit((error_code&0xff)<<8);
 }
 
-task_t *next_thread(task_t *p)
+task_t fastcall *next_thread(task_t *p)
 {
 	struct pid_link *link = p->pids + PIDTYPE_TGID;
 	struct list_head *tmp, *head = &link->pidptr->task_list;
--- diff/kernel/fork.c	2004-03-04 11:41:49.000000000 +0000
+++ source/kernel/fork.c	2004-03-09 11:51:51.000000000 +0000
@@ -31,6 +31,7 @@
 #include <linux/futex.h>
 #include <linux/ptrace.h>
 #include <linux/mount.h>
+#include <linux/sem.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -39,9 +40,6 @@
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
-extern int copy_semundo(unsigned long clone_flags, struct task_struct *tsk);
-extern void exit_sem(struct task_struct *tsk);
-
 /* The idle threads do not count..
  * Protected by write_lock_irq(&tasklist_lock)
  */
@@ -91,7 +89,7 @@ void __put_task_struct(struct task_struc
 	free_task(tsk);
 }
 
-void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
+void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
 {
 	unsigned long flags;
 
@@ -103,7 +101,7 @@ void add_wait_queue(wait_queue_head_t *q
 
 EXPORT_SYMBOL(add_wait_queue);
 
-void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait)
+void fastcall add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait)
 {
 	unsigned long flags;
 
@@ -115,7 +113,7 @@ void add_wait_queue_exclusive(wait_queue
 
 EXPORT_SYMBOL(add_wait_queue_exclusive);
 
-void remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
+void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
 {
 	unsigned long flags;
 
@@ -139,7 +137,7 @@ EXPORT_SYMBOL(remove_wait_queue);
  * stops them from bleeding out - it would still allow subsequent
  * loads to move into the the critical region).
  */
-void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
+void fastcall prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
 {
 	unsigned long flags;
 
@@ -153,7 +151,7 @@ void prepare_to_wait(wait_queue_head_t *
 
 EXPORT_SYMBOL(prepare_to_wait);
 
-void
+void fastcall
 prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
 {
 	unsigned long flags;
@@ -168,7 +166,7 @@ prepare_to_wait_exclusive(wait_queue_hea
 
 EXPORT_SYMBOL(prepare_to_wait_exclusive);
 
-void finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
+void fastcall finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
 {
 	unsigned long flags;
 
@@ -265,6 +263,7 @@ static struct task_struct *dup_task_stru
 static inline int dup_mmap(struct mm_struct * mm, struct mm_struct * oldmm)
 {
 	struct vm_area_struct * mpnt, *tmp, **pprev;
+	struct rb_node **rb_link, *rb_parent;
 	int retval;
 	unsigned long charge = 0;
 
@@ -275,8 +274,11 @@ static inline int dup_mmap(struct mm_str
 	mm->mmap_cache = NULL;
 	mm->free_area_cache = TASK_UNMAPPED_BASE;
 	mm->map_count = 0;
-	mm->rss = 0;
+	zero_rss(mm);
 	cpus_clear(mm->cpu_vm_mask);
+	mm->mm_rb = RB_ROOT;
+	rb_link = &mm->mm_rb.rb_node;
+	rb_parent = NULL;
 	pprev = &mm->mmap;
 
 	/*
@@ -324,11 +326,17 @@ static inline int dup_mmap(struct mm_str
 
 		/*
 		 * Link in the new vma and copy the page table entries:
-		 * link in first so that swapoff can see swap entries.
+		 * link in first so that swapoff can see swap entries,
+		 * and try_to_unmap_one's find_vma find the new vma.
 		 */
 		spin_lock(&mm->page_table_lock);
 		*pprev = tmp;
 		pprev = &tmp->vm_next;
+
+		__vma_link_rb(mm, tmp, rb_link, rb_parent);
+		rb_link = &tmp->vm_rb.rb_right;
+		rb_parent = &tmp->vm_rb;
+
 		mm->map_count++;
 		retval = copy_page_range(mm, current->mm, tmp);
 		spin_unlock(&mm->page_table_lock);
@@ -340,7 +348,6 @@ static inline int dup_mmap(struct mm_str
 			goto fail;
 	}
 	retval = 0;
-	build_mmap_rb(mm);
 
 out:
 	flush_tlb_mm(current->mm);
@@ -418,7 +425,7 @@ struct mm_struct * mm_alloc(void)
  * is dropped: either by a lazy thread or by
  * mmput. Free the page directory and the mm.
  */
-void __mmdrop(struct mm_struct *mm)
+void fastcall __mmdrop(struct mm_struct *mm)
 {
 	BUG_ON(mm == &init_mm);
 	mm_free_pgd(mm);
--- diff/kernel/futex.c	2004-02-18 08:54:13.000000000 +0000
+++ source/kernel/futex.c	2004-03-09 11:51:51.000000000 +0000
@@ -269,7 +269,11 @@ static void wake_futex(struct futex_q *q
 	 * The lock in wake_up_all() is a crucial memory barrier after the
 	 * list_del_init() and also before assigning to q->lock_ptr.
 	 */
+
+	current->flags |= PF_FUTEX_DEBUG;
 	wake_up_all(&q->waiters);
+	current->flags &= ~PF_FUTEX_DEBUG;
+
 	/*
 	 * The waiting task can free the futex_q as soon as this is written,
 	 * without taking any locks.  This must come last.
@@ -490,8 +494,11 @@ static int futex_wait(unsigned long uadd
 	 * !list_empty() is safe here without any lock.
 	 * q.lock_ptr != 0 is not safe, because of ordering against wakeup.
 	 */
-	if (likely(!list_empty(&q.list)))
+	if (likely(!list_empty(&q.list))) {
+		current->flags |= PF_FUTEX_DEBUG;
 		time = schedule_timeout(time);
+		current->flags &= ~PF_FUTEX_DEBUG;
+	}
 	__set_current_state(TASK_RUNNING);
 
 	/*
@@ -505,7 +512,11 @@ static int futex_wait(unsigned long uadd
 	if (time == 0)
 		return -ETIMEDOUT;
 	/* A spurious wakeup should never happen. */
-	WARN_ON(!signal_pending(current));
+	if (!signal_pending(current)) {
+		printk("futex_wait woken: %lu %i %lu\n",
+		       uaddr, val, time);
+		WARN_ON(1);
+	}
 	return -EINTR;
 
  out_unqueue:
--- diff/kernel/kthread.c	2004-03-04 11:41:49.000000000 +0000
+++ source/kernel/kthread.c	2004-03-09 11:51:51.000000000 +0000
@@ -91,7 +91,6 @@ static void keventd_create_kthread(void 
 	} else {
 		wait_for_completion(&create->started);
 		create->result = find_task_by_pid(pid);
-		wait_task_inactive(create->result);
 	}
 	complete(&create->done);
 }
@@ -131,7 +130,9 @@ struct task_struct *kthread_create(int (
 void kthread_bind(struct task_struct *k, unsigned int cpu)
 {
 	BUG_ON(k->state != TASK_INTERRUPTIBLE);
-	k->thread_info->cpu = cpu;
+	/* Must have done schedule() in kthread() before we set_task_cpu */
+	wait_task_inactive(k);
+	set_task_cpu(k, cpu);
 	k->cpus_allowed = cpumask_of_cpu(cpu);
 }
 
--- diff/kernel/module.c	2004-03-04 11:41:49.000000000 +0000
+++ source/kernel/module.c	2004-03-09 11:51:51.000000000 +0000
@@ -33,7 +33,7 @@
 #include <linux/err.h>
 #include <linux/vermagic.h>
 #include <linux/notifier.h>
-#include <linux/kthread.h>
+#include <linux/stop_machine.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 #include <asm/pgalloc.h>
@@ -474,190 +474,36 @@ static inline int try_force(unsigned int
 }
 #endif /* CONFIG_MODULE_FORCE_UNLOAD */
 
-static int try_stop_module_local(struct module *mod, int flags, int *forced)
-{
-	local_irq_disable();
-
-	/* If it's not unused, quit unless we are told to block. */
-	if ((flags & O_NONBLOCK) && module_refcount(mod) != 0) {
-		if (!(*forced = try_force(flags))) {
-			local_irq_enable();
-			return -EWOULDBLOCK;
-		}
-	}
-
-	/* Mark it as dying. */
-	mod->waiter = current;
-	mod->state = MODULE_STATE_GOING;
-	local_irq_enable();
-	return 0;
-}
-
-#ifdef CONFIG_SMP
-/* Thread to stop each CPU in user context. */
-enum stopref_state {
-	STOPREF_WAIT,
-	STOPREF_PREPARE,
-	STOPREF_DISABLE_IRQ,
-	STOPREF_EXIT,
-};
-
-static enum stopref_state stopref_state;
-static unsigned int stopref_num_threads;
-static atomic_t stopref_thread_ack;
-
-static int stopref(void *cpu)
-{
-	int irqs_disabled = 0;
-	int prepared = 0;
-
-	set_cpus_allowed(current, cpumask_of_cpu((int)(long)cpu));
-
-	/* Ack: we are alive */
-	mb(); /* Theoretically the ack = 0 might not be on this CPU yet. */
-	atomic_inc(&stopref_thread_ack);
-
-	/* Simple state machine */
-	while (stopref_state != STOPREF_EXIT) {
-		if (stopref_state == STOPREF_DISABLE_IRQ && !irqs_disabled) {
-			local_irq_disable();
-			irqs_disabled = 1;
-			/* Ack: irqs disabled. */
-			mb(); /* Must read state first. */
-			atomic_inc(&stopref_thread_ack);
-		} else if (stopref_state == STOPREF_PREPARE && !prepared) {
-			/* Everyone is in place, hold CPU. */
-			preempt_disable();
-			prepared = 1;
-			mb(); /* Must read state first. */
-			atomic_inc(&stopref_thread_ack);
-		}
-		if (irqs_disabled || prepared)
-			cpu_relax();
-		else
-			yield();
-	}
-
-	/* Ack: we are exiting. */
-	mb(); /* Must read state first. */
-	atomic_inc(&stopref_thread_ack);
-
-	if (irqs_disabled)
-		local_irq_enable();
-	if (prepared)
-		preempt_enable();
-
-	return 0;
-}
-
-/* Change the thread state */
-static void stopref_set_state(enum stopref_state state, int sleep)
-{
-	atomic_set(&stopref_thread_ack, 0);
-	wmb();
-	stopref_state = state;
-	while (atomic_read(&stopref_thread_ack) != stopref_num_threads) {
-		if (sleep)
-			yield();
-		else
-			cpu_relax();
-	}
-}
-
 struct stopref
 {
 	struct module *mod;
 	int flags;
 	int *forced;
-	struct completion started;
 };
 
-static int spawn_stopref(void *data)
+/* Whole machine is stopped with interrupts off when this runs. */
+static inline int __try_stop_module(void *_sref)
 {
-	struct stopref *sref = data;
-	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
-	unsigned int i, cpu = smp_processor_id();
-	int ret = 0;
+	struct stopref *sref = _sref;
 
-	complete(&sref->started);
-
-	/* One high-prio thread per cpu.  We'll do one (any one). */
-	set_cpus_allowed(current, cpumask_of_cpu(cpu));
-	sys_sched_setscheduler(current->pid, SCHED_FIFO, &param);
-
-	atomic_set(&stopref_thread_ack, 0);
-	stopref_num_threads = 0;
-	stopref_state = STOPREF_WAIT;
-
-	for_each_online_cpu(i) {
-		if (i == cpu)
-			continue;
-		ret = kernel_thread(stopref, (void *)(long)i, CLONE_KERNEL);
-		if (ret < 0)
-			break;
-		stopref_num_threads++;
-	}
-
-	/* Wait for them all to come to life. */
-	while (atomic_read(&stopref_thread_ack) != stopref_num_threads)
-		yield();
-
-	/* If some failed, kill them all. */
-	if (ret < 0) {
-		stopref_set_state(STOPREF_EXIT, 1);
-		goto out;
+	/* If it's not unused, quit unless we are told to block. */
+	if ((sref->flags & O_NONBLOCK) && module_refcount(sref->mod) != 0) {
+		if (!(*sref->forced = try_force(sref->flags)))
+			return -EWOULDBLOCK;
 	}
 
-	/* Don't schedule us away at this point, please. */
-	preempt_disable();
-
-	/* Now they are all started, make them hold the CPUs, ready. */
-	stopref_set_state(STOPREF_PREPARE, 0);
-
-	/* Make them disable irqs. */
-	stopref_set_state(STOPREF_DISABLE_IRQ, 0);
-
-	/* Atomically disable module if possible */
-	ret = try_stop_module_local(sref->mod, sref->flags, sref->forced);
-
-	stopref_set_state(STOPREF_EXIT, 0);
-	preempt_enable();
-
-out:
-	/* Wait for kthread_stop */
-	while (!kthread_should_stop()) {
-		__set_current_state(TASK_INTERRUPTIBLE);
-		schedule();
-	}
-	return ret;
+	/* Mark it as dying. */
+	sref->mod->waiter = current;
+	sref->mod->state = MODULE_STATE_GOING;
+	return 0;
 }
 
 static int try_stop_module(struct module *mod, int flags, int *forced)
 {
-	struct task_struct *p;
 	struct stopref sref = { mod, flags, forced };
-	int ret;
-
-	init_completion(&sref.started);
 
-	/* No CPUs can come up or down during this. */
-	lock_cpu_hotplug();
-	p = kthread_run(spawn_stopref, &sref, "krmmod");
-	if (IS_ERR(p))
-		ret = PTR_ERR(p);
-	else {
-		wait_for_completion(&sref.started);
-		ret = kthread_stop(p);
-	}
-	unlock_cpu_hotplug();
-	return ret;
-}
-#else /* ...!SMP */
-static inline int try_stop_module(struct module *mod, int flags, int *forced)
-{
-	return try_stop_module_local(mod, flags, forced);
+	return stop_machine_run(__try_stop_module, &sref, NR_CPUS);
 }
-#endif
 
 unsigned int module_refcount(struct module *mod)
 {
@@ -750,7 +596,9 @@ sys_delete_module(const char __user *nam
 		wait_for_zero_refcount(mod);
 
 	/* Final destruction now noone is using it. */
+	up(&module_mutex);
 	mod->exit();
+	down(&module_mutex);
 	free_module(mod);
 
  out:
--- diff/kernel/pid.c	2003-10-27 09:20:39.000000000 +0000
+++ source/kernel/pid.c	2004-03-09 11:51:51.000000000 +0000
@@ -57,7 +57,7 @@ static pidmap_t *map_limit = pidmap_arra
 
 static spinlock_t pidmap_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
-inline void free_pidmap(int pid)
+fastcall void free_pidmap(int pid)
 {
 	pidmap_t *map = pidmap_array + pid / BITS_PER_PAGE;
 	int offset = pid & BITS_PER_PAGE_MASK;
@@ -122,6 +122,8 @@ return_pid:
 	}
 	
 	if (!offset || !atomic_read(&map->nr_free)) {
+		if (!offset)
+			map--;
 next_map:
 		map = next_free_map(map, &max_steps);
 		if (!map)
@@ -146,7 +148,7 @@ failure:
 	return -1;
 }
 
-inline struct pid *find_pid(enum pid_type type, int nr)
+fastcall struct pid *find_pid(enum pid_type type, int nr)
 {
 	struct list_head *elem, *bucket = &pid_hash[type][pid_hashfn(nr)];
 	struct pid *pid;
@@ -159,14 +161,14 @@ inline struct pid *find_pid(enum pid_typ
 	return NULL;
 }
 
-void link_pid(task_t *task, struct pid_link *link, struct pid *pid)
+void fastcall link_pid(task_t *task, struct pid_link *link, struct pid *pid)
 {
 	atomic_inc(&pid->count);
 	list_add_tail(&link->pid_chain, &pid->task_list);
 	link->pidptr = pid;
 }
 
-int attach_pid(task_t *task, enum pid_type type, int nr)
+int fastcall attach_pid(task_t *task, enum pid_type type, int nr)
 {
 	struct pid *pid = find_pid(type, nr);
 
@@ -209,7 +211,7 @@ static void _detach_pid(task_t *task, en
 	__detach_pid(task, type);
 }
 
-void detach_pid(task_t *task, enum pid_type type)
+void fastcall detach_pid(task_t *task, enum pid_type type)
 {
 	int nr = __detach_pid(task, type);
 
@@ -268,6 +270,9 @@ void switch_exec_pids(task_t *leader, ta
  * machine.  From a minimum of 16 slots up to 4096 slots at one gigabyte or
  * more.
  */
+#ifdef CONFIG_KGDB
+int kgdb_pid_init_done; /* so we don't call prior to... */
+#endif
 void __init pidhash_init(void)
 {
 	int i, j, pidhash_size;
@@ -289,6 +294,9 @@ void __init pidhash_init(void)
 		for (j = 0; j < pidhash_size; j++)
 			INIT_LIST_HEAD(&pid_hash[i][j]);
 	}
+#ifdef CONFIG_KGDB
+	kgdb_pid_init_done++;
+#endif
 }
 
 void __init pidmap_init(void)
--- diff/kernel/printk.c	2004-03-04 11:41:49.000000000 +0000
+++ source/kernel/printk.c	2004-03-09 11:51:51.000000000 +0000
@@ -522,7 +522,7 @@ asmlinkage int printk(const char *fmt, .
 			log_level_unknown = 1;
 	}
 
-	if (!cpu_online(smp_processor_id())) {
+	if (!cpu_online(smp_processor_id()) && !system_running) {
 		/*
 		 * Some console drivers may assume that per-cpu resources have
 		 * been allocated.  So don't allow them to be called by this
--- diff/kernel/rcupdate.c	2003-10-09 09:47:34.000000000 +0100
+++ source/kernel/rcupdate.c	2004-03-09 11:51:51.000000000 +0000
@@ -66,7 +66,7 @@ static DEFINE_PER_CPU(struct tasklet_str
  * The read-side of critical section that use call_rcu() for updation must 
  * be protected by rcu_read_lock()/rcu_read_unlock().
  */
-void call_rcu(struct rcu_head *head, void (*func)(void *arg), void *arg)
+void fastcall call_rcu(struct rcu_head *head, void (*func)(void *arg), void *arg)
 {
 	int cpu;
 	unsigned long flags;
@@ -110,6 +110,7 @@ static void rcu_start_batch(long newbatc
 	    !cpus_empty(rcu_ctrlblk.rcu_cpu_mask)) {
 		return;
 	}
+	/* Can't change, since spin lock held. */
 	rcu_ctrlblk.rcu_cpu_mask = cpu_online_map;
 }
 
@@ -154,6 +155,60 @@ out_unlock:
 }
 
 
+#ifdef CONFIG_HOTPLUG_CPU
+
+/* warning! helper for rcu_offline_cpu. do not use elsewhere without reviewing
+ * locking requirements, the list it's pulling from has to belong to a cpu
+ * which is dead and hence not processing interrupts.
+ */
+static void rcu_move_batch(struct list_head *list)
+{
+	struct list_head *entry;
+	int cpu = smp_processor_id();
+
+	local_irq_disable();
+	while (!list_empty(list)) {
+		entry = list->next;
+		list_del(entry);
+		list_add_tail(entry, &RCU_nxtlist(cpu));
+	}
+	local_irq_enable();
+}
+
+static void rcu_offline_cpu(int cpu)
+{
+	/* if the cpu going offline owns the grace period
+	 * we can block indefinitely waiting for it, so flush
+	 * it here
+	 */
+	spin_lock_irq(&rcu_ctrlblk.mutex);
+	if (cpus_empty(rcu_ctrlblk.rcu_cpu_mask))
+		goto unlock;
+
+	cpu_clear(cpu, rcu_ctrlblk.rcu_cpu_mask);
+	if (cpus_empty(rcu_ctrlblk.rcu_cpu_mask)) {
+		rcu_ctrlblk.curbatch++;
+		/* We may avoid calling start batch if
+		 * we are starting the batch only
+		 * because of the DEAD CPU (the current
+		 * CPU will start a new batch anyway for
+		 * the callbacks we will move to current CPU).
+		 * However, we will avoid this optimisation
+		 * for now.
+		 */
+		rcu_start_batch(rcu_ctrlblk.maxbatch);
+	}
+unlock:
+	spin_unlock_irq(&rcu_ctrlblk.mutex);
+
+	rcu_move_batch(&RCU_curlist(cpu));
+	rcu_move_batch(&RCU_nxtlist(cpu));
+
+	tasklet_kill_immediate(&RCU_tasklet(cpu), cpu);
+}
+
+#endif
+
 /*
  * This does the RCU processing work from tasklet context. 
  */
@@ -214,7 +269,11 @@ static int __devinit rcu_cpu_notify(stru
 	case CPU_UP_PREPARE:
 		rcu_online_cpu(cpu);
 		break;
-	/* Space reserved for CPU_OFFLINE :) */
+#ifdef CONFIG_HOTPLUG_CPU
+	case CPU_DEAD:
+		rcu_offline_cpu(cpu);
+		break;
+#endif
 	default:
 		break;
 	}
--- diff/kernel/sched.c	2004-03-04 11:41:49.000000000 +0000
+++ source/kernel/sched.c	2004-03-09 11:51:51.000000000 +0000
@@ -25,6 +25,7 @@
 #include <linux/highmem.h>
 #include <linux/smp_lock.h>
 #include <asm/mmu_context.h>
+#include <asm/tlb.h>
 #include <linux/interrupt.h>
 #include <linux/completion.h>
 #include <linux/kernel_stat.h>
@@ -33,6 +34,7 @@
 #include <linux/suspend.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
+#include <linux/smp.h>
 #include <linux/timer.h>
 #include <linux/rcupdate.h>
 #include <linux/cpu.h>
@@ -90,7 +92,6 @@
 #define MAX_SLEEP_AVG		(AVG_TIMESLICE * MAX_BONUS)
 #define STARVATION_LIMIT	(MAX_SLEEP_AVG)
 #define NS_MAX_SLEEP_AVG	(JIFFIES_TO_NS(MAX_SLEEP_AVG))
-#define NODE_THRESHOLD		125
 #define CREDIT_LIMIT		100
 
 /*
@@ -186,7 +187,7 @@ static inline unsigned int task_timeslic
 typedef struct runqueue runqueue_t;
 
 struct prio_array {
-	int nr_active;
+	unsigned int nr_active;
 	unsigned long bitmap[BITMAP_SIZE];
 	struct list_head queue[MAX_PRIO];
 };
@@ -201,23 +202,32 @@ struct prio_array {
 struct runqueue {
 	spinlock_t lock;
 	unsigned long nr_running, nr_switches, expired_timestamp,
-		      nr_uninterruptible, timestamp_last_tick;
+		      nr_uninterruptible;
+	unsigned long long timestamp_last_tick;
 	task_t *curr, *idle;
 	struct mm_struct *prev_mm;
 	prio_array_t *active, *expired, arrays[2];
-	int best_expired_prio, prev_cpu_load[NR_CPUS];
-#ifdef CONFIG_NUMA
-	atomic_t *node_nr_running;
-	int prev_node_load[MAX_NUMNODES];
+	int best_expired_prio;
+	int cpu;
+	atomic_t nr_iowait;
+#ifdef CONFIG_SMP
+	unsigned long cpu_load[NR_CPUS];
 #endif
+	/* For active balancing */
+	int active_balance;
+	int push_cpu;
+
 	task_t *migration_thread;
 	struct list_head migration_queue;
-
-	atomic_t nr_iowait;
 };
 
 static DEFINE_PER_CPU(struct runqueue, runqueues);
 
+#ifdef CONFIG_SMP
+/* Mandatory scheduling domains */
+DEFINE_PER_CPU(struct sched_domain, base_domains);
+#endif
+
 #define cpu_rq(cpu)		(&per_cpu(runqueues, (cpu)))
 #define this_rq()		(&__get_cpu_var(runqueues))
 #define task_rq(p)		cpu_rq(task_cpu(p))
@@ -232,51 +242,16 @@ static DEFINE_PER_CPU(struct runqueue, r
 # define task_running(rq, p)		((rq)->curr == (p))
 #endif
 
-#ifdef CONFIG_NUMA
-
-/*
- * Keep track of running tasks.
- */
-
-static atomic_t node_nr_running[MAX_NUMNODES] ____cacheline_maxaligned_in_smp =
-	{[0 ...MAX_NUMNODES-1] = ATOMIC_INIT(0)};
-
-static inline void nr_running_init(struct runqueue *rq)
-{
-	rq->node_nr_running = &node_nr_running[0];
-}
-
 static inline void nr_running_inc(runqueue_t *rq)
 {
-	atomic_inc(rq->node_nr_running);
 	rq->nr_running++;
 }
 
 static inline void nr_running_dec(runqueue_t *rq)
 {
-	atomic_dec(rq->node_nr_running);
 	rq->nr_running--;
 }
 
-__init void node_nr_running_init(void)
-{
-	int i;
-
-	for (i = 0; i < NR_CPUS; i++) {
-		if (cpu_possible(i))
-			cpu_rq(i)->node_nr_running =
-				&node_nr_running[cpu_to_node(i)];
-	}
-}
-
-#else /* !CONFIG_NUMA */
-
-# define nr_running_init(rq)	do { } while (0)
-# define nr_running_inc(rq)	do { (rq)->nr_running++; } while (0)
-# define nr_running_dec(rq)	do { (rq)->nr_running--; } while (0)
-
-#endif /* CONFIG_NUMA */
-
 /*
  * task_rq_lock - lock the runqueue a given task resides on and disable
  * interrupts.  Note the ordering: we can safely lookup the task_rq without
@@ -544,37 +519,30 @@ inline int task_curr(task_t *p)
 typedef struct {
 	struct list_head list;
 	task_t *task;
+	int dest_cpu;
 	struct completion done;
 } migration_req_t;
 
 /*
- * The task's runqueue lock must be held, and the new mask must be valid.
+ * The task's runqueue lock must be held.
  * Returns true if you have to wait for migration thread.
  */
-static int __set_cpus_allowed(task_t *p, cpumask_t new_mask,
-				migration_req_t *req)
+static int migrate_task(task_t *p, int dest_cpu, migration_req_t *req)
 {
 	runqueue_t *rq = task_rq(p);
 
-	p->cpus_allowed = new_mask;
-	/*
-	 * Can the task run on the task's current CPU? If not then
-	 * migrate the thread off to a proper CPU.
-	 */
-	if (cpu_isset(task_cpu(p), new_mask))
-		return 0;
-
 	/*
 	 * If the task is not on a runqueue (and not running), then
 	 * it is sufficient to simply update the task's cpu field.
 	 */
 	if (!p->array && !task_running(rq, p)) {
-		set_task_cpu(p, any_online_cpu(p->cpus_allowed));
+		set_task_cpu(p, dest_cpu);
 		return 0;
 	}
 
 	init_completion(&req->done);
 	req->task = p;
+	req->dest_cpu = dest_cpu;
 	list_add(&req->list, &rq->migration_queue);
 	return 1;
 }
@@ -635,9 +603,78 @@ void kick_process(task_t *p)
 }
 
 EXPORT_SYMBOL_GPL(kick_process);
+/*
+ * Return a low guess at the load of cpu. Update previous history if update
+ * is true
+ */
+static inline unsigned long get_low_cpu_load(int cpu, int update)
+{
+	runqueue_t *rq = cpu_rq(cpu);
+	runqueue_t *this_rq = this_rq();
+	unsigned long nr = rq->nr_running << SCHED_LOAD_SHIFT;
+	unsigned long load = this_rq->cpu_load[cpu];
+	unsigned long ret = min(nr, load);
+
+	if (update)
+		this_rq->cpu_load[cpu] = (nr + load) / 2;
+
+	return ret;
+}
+
+static inline unsigned long get_high_cpu_load(int cpu, int update)
+{
+	runqueue_t *rq = cpu_rq(cpu);
+	runqueue_t *this_rq = this_rq();
+	unsigned long nr = rq->nr_running << SCHED_LOAD_SHIFT;
+	unsigned long load = this_rq->cpu_load[cpu];
+	unsigned long ret = max(nr, load);
+
+	if (update)
+		this_rq->cpu_load[cpu] = (nr + load) / 2;
+
+	return ret;
+}
 
 #endif
 
+/*
+ * sched_balance_wake can be used with SMT architectures to wake a
+ * task onto an idle sibling if cpu is not idle. Returns cpu if
+ * cpu is idle or no siblings are idle, otherwise returns an idle
+ * sibling.
+ */
+#if defined(CONFIG_SMP) && defined(ARCH_HAS_SCHED_WAKE_BALANCE)
+static int sched_balance_wake(int cpu, task_t *p)
+{
+	cpumask_t tmp;
+	struct sched_domain *domain;
+	int i;
+
+	if (idle_cpu(cpu))
+		return cpu;
+
+	domain = cpu_sched_domain(cpu);
+	if (!(domain->flags & SD_FLAG_WAKE))
+		return cpu;
+
+	cpus_and(tmp, domain->span, cpu_online_map);
+	for_each_cpu_mask(i, tmp) {
+		if (!cpu_isset(i, p->cpus_allowed))
+			continue;
+
+		if (idle_cpu(i))
+			return i;
+	}
+
+	return cpu;
+}
+#else
+static inline int sched_balance_wake(int cpu, task_t *p)
+{
+	return cpu;
+}
+#endif
+
 /***
  * try_to_wake_up - wake up a thread
  * @p: the to-be-woken-up thread
@@ -658,49 +695,122 @@ static int try_to_wake_up(task_t * p, un
 	int success = 0;
 	long old_state;
 	runqueue_t *rq;
+	int cpu, this_cpu;
+#ifdef CONFIG_SMP
+	unsigned long long now;
+	unsigned long load, this_load;
+	int new_cpu;
+	struct sched_domain *sd;
+	runqueue_t *this_rq;
+#endif
 
-repeat_lock_task:
 	rq = task_rq_lock(p, &flags);
 	old_state = p->state;
-	if (old_state & state) {
-		if (!p->array) {
-			/*
-			 * Fast-migrate the task if it's not running or runnable
-			 * currently. Do not violate hard affinity.
-			 */
-			if (unlikely(sync && !task_running(rq, p) &&
-				(task_cpu(p) != smp_processor_id()) &&
-					cpu_isset(smp_processor_id(),
-							p->cpus_allowed))) {
-
-				set_task_cpu(p, smp_processor_id());
-				task_rq_unlock(rq, &flags);
-				goto repeat_lock_task;
-			}
-			if (old_state == TASK_UNINTERRUPTIBLE) {
-				rq->nr_uninterruptible--;
-				/*
-				 * Tasks on involuntary sleep don't earn
-				 * sleep_avg beyond just interactive state.
-				 */
-				p->activated = -1;
-			}
-			if (sync && (task_cpu(p) == smp_processor_id()))
-				__activate_task(p, rq);
-			else {
-				activate_task(p, rq);
-				if (TASK_PREEMPTS_CURR(p, rq))
-					resched_task(rq->curr);
-			}
-			success = 1;
+	if (!(old_state & state))
+		goto out;
+
+	if (p->array)
+		goto out_running;
+
+	this_cpu = smp_processor_id();
+	cpu = task_cpu(p);
+
+#ifdef CONFIG_SMP
+	if (cpu == this_cpu)
+		goto out_activate;
+
+	if (unlikely(!cpu_isset(this_cpu, p->cpus_allowed)
+		     || task_running(rq, p)
+		     || cpu_is_offline(this_cpu)))
+		goto out_activate;
+
+	/* Passive load balancing */
+	load = get_low_cpu_load(cpu, 1);
+	this_load = get_high_cpu_load(this_cpu, 1) + SCHED_LOAD_SCALE;
+	if (load > this_load) {
+		new_cpu = sched_balance_wake(this_cpu, p);
+		set_task_cpu(p, new_cpu);
+		goto repeat_lock_task;
+	}
+
+	this_rq = this_rq();
+	now = sched_clock();
+	sd = cpu_sched_domain(this_cpu);
+
+	/*
+	 * Fast-migrate the task if it's not running or
+	 * runnable currently. Do not violate hard affinity.
+	 */
+	do {
+		if (!(sd->flags & SD_FLAG_FASTMIGRATE))
+			break;
+		if (now - p->timestamp < sd->cache_hot_time)
+			break;
+
+		if (cpu_isset(cpu, sd->span)) {
+			new_cpu = sched_balance_wake(this_cpu, p);
+			set_task_cpu(p, new_cpu);
+			goto repeat_lock_task;
 		}
-		p->state = TASK_RUNNING;
+		sd = sd->parent;
+	} while (sd);
+
+	new_cpu = sched_balance_wake(cpu, p);
+	if (new_cpu != cpu) {
+		set_task_cpu(p, new_cpu);
+		goto repeat_lock_task;
+	}
+	goto out_activate;
+
+	if ((p->flags & PF_FUTEX_DEBUG)
+	    && !(current->flags & PF_FUTEX_DEBUG)) {
+		printk("%s %i waking %s: %i %i\n",
+		       current->comm, (int)in_interrupt(),
+		       p->comm, p->tgid, p->pid);
+		WARN_ON(1);
 	}
+
+repeat_lock_task:
+	task_rq_unlock(rq, &flags);
+	rq = task_rq_lock(p, &flags);
+	old_state = p->state;
+	if (!(old_state & state))
+		goto out;
+
+	if (p->array)
+		goto out_running;
+
+	this_cpu = smp_processor_id();
+	cpu = task_cpu(p);
+
+out_activate:
+#endif /* CONFIG_SMP */
+	if (old_state == TASK_UNINTERRUPTIBLE) {
+		rq->nr_uninterruptible--;
+		/*
+		 * Tasks on involuntary sleep don't earn
+		 * sleep_avg beyond just interactive state.
+		 */
+		p->activated = -1;
+	}
+
+	if (sync && cpu == this_cpu) {
+		__activate_task(p, rq);
+	} else {
+		activate_task(p, rq);
+		if (TASK_PREEMPTS_CURR(p, rq))
+			resched_task(rq->curr);
+	}
+	success = 1;
+
+out_running:
+	p->state = TASK_RUNNING;
+out:
 	task_rq_unlock(rq, &flags);
 
 	return success;
 }
-int wake_up_process(task_t * p)
+int fastcall wake_up_process(task_t * p)
 {
 	return try_to_wake_up(p, TASK_STOPPED |
 		       		 TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 0);
@@ -708,7 +818,7 @@ int wake_up_process(task_t * p)
 
 EXPORT_SYMBOL(wake_up_process);
 
-int wake_up_state(task_t *p, unsigned int state)
+int fastcall wake_up_state(task_t *p, unsigned int state)
 {
 	return try_to_wake_up(p, state, 0);
 }
@@ -717,7 +827,7 @@ int wake_up_state(task_t *p, unsigned in
  * Perform scheduler related setup for a newly forked process p.
  * p is forked by current.
  */
-void sched_fork(task_t *p)
+void fastcall sched_fork(task_t *p)
 {
 	/*
 	 * We mark the process as running here, but have not actually
@@ -754,8 +864,8 @@ void sched_fork(task_t *p)
 	p->timestamp = sched_clock();
 	if (!current->time_slice) {
 		/*
-	 	 * This case is rare, it happens when the parent has only
-	 	 * a single jiffy left from its timeslice. Taking the
+		 * This case is rare, it happens when the parent has only
+		 * a single jiffy left from its timeslice. Taking the
 		 * runqueue lock is not a problem.
 		 */
 		current->time_slice = 1;
@@ -773,7 +883,7 @@ void sched_fork(task_t *p)
  * This function will do some initial scheduler statistics housekeeping
  * that must be done for every newly created process.
  */
-void wake_up_forked_process(task_t * p)
+void fastcall wake_up_forked_process(task_t * p)
 {
 	unsigned long flags;
 	runqueue_t *rq = task_rq_lock(current, &flags);
@@ -817,7 +927,7 @@ void wake_up_forked_process(task_t * p)
  * artificially, because any timeslice recovered here
  * was given away by the parent in the first place.)
  */
-void sched_exit(task_t * p)
+void fastcall sched_exit(task_t * p)
 {
 	unsigned long flags;
 	runqueue_t *rq;
@@ -871,7 +981,7 @@ static inline void finish_task_switch(ta
 	 * still held, otherwise prev could be scheduled on another cpu, die
 	 * there before we look at prev->state, and then the reference would
 	 * be dropped twice.
-	 * 		Manfred Spraul <manfred@colorfullife.com>
+	 *		Manfred Spraul <manfred@colorfullife.com>
 	 */
 	prev_task_flags = prev->flags;
 	finish_arch_switch(rq, prev);
@@ -933,7 +1043,7 @@ unsigned long nr_running(void)
 {
 	unsigned long i, sum = 0;
 
-	for (i = 0; i < NR_CPUS; i++)
+	for_each_cpu(i)
 		sum += cpu_rq(i)->nr_running;
 
 	return sum;
@@ -1003,40 +1113,44 @@ static inline void double_rq_unlock(runq
 		spin_unlock(&rq2->lock);
 }
 
+enum idle_type
+{
+	IDLE,
+	NOT_IDLE,
+	NEWLY_IDLE,
+};
+
+#ifdef CONFIG_SMP
+
 #ifdef CONFIG_NUMA
 /*
- * If dest_cpu is allowed for this process, migrate the task to it.
- * This is accomplished by forcing the cpu_allowed mask to only
- * allow dest_cpu, which will force the cpu onto dest_cpu.  Then
- * the cpu_allowed mask is restored.
+ * If dest_cpu is allowed for this process, migrate us to it.
  */
-static void sched_migrate_task(task_t *p, int dest_cpu)
+void migrate_to_cpu(int dest_cpu)
 {
 	runqueue_t *rq;
 	migration_req_t req;
 	unsigned long flags;
-	cpumask_t old_mask, new_mask = cpumask_of_cpu(dest_cpu);
 
-	rq = task_rq_lock(p, &flags);
-	old_mask = p->cpus_allowed;
-	if (!cpu_isset(dest_cpu, old_mask) || !cpu_online(dest_cpu))
+	rq = task_rq_lock(current, &flags);
+	if (!cpu_isset(dest_cpu, current->cpus_allowed))
 		goto out;
 
 	/* force the process onto the specified CPU */
-	if (__set_cpus_allowed(p, new_mask, &req)) {
+	if (migrate_task(current, dest_cpu, &req)) {
 		/* Need to wait for migration thread. */
 		task_rq_unlock(rq, &flags);
 		wake_up_process(rq->migration_thread);
 		wait_for_completion(&req.done);
 
-		/* If we raced with sys_sched_setaffinity, don't
-		 * restore mask. */
-		rq = task_rq_lock(p, &flags);
-		if (likely(cpus_equal(p->cpus_allowed, new_mask))) {
-			/* Restore old mask: won't need migration
-			 * thread, since current cpu is allowed. */
-			BUG_ON(__set_cpus_allowed(p, old_mask, NULL));
-		}
+		/*
+		 * we want a new context here. This eliminates TLB
+		 * flushes on the cpus where the process executed prior to
+		 * the migration.
+		 */
+		tlb_migrate_prepare(current->mm);
+
+		return;
 	}
 out:
 	task_rq_unlock(rq, &flags);
@@ -1046,215 +1160,81 @@ out:
  * Find the least loaded CPU.  Slightly favor the current CPU by
  * setting its runqueue length as the minimum to start.
  */
-static int sched_best_cpu(struct task_struct *p)
+static int sched_best_cpu(struct task_struct *p, struct sched_domain *domain)
 {
-	int i, minload, load, best_cpu, node = 0;
-	cpumask_t cpumask;
+	cpumask_t tmp;
+	int i, min_load, this_cpu, best_cpu;
 
-	best_cpu = task_cpu(p);
-	if (cpu_rq(best_cpu)->nr_running <= 2)
-		return best_cpu;
+	best_cpu = this_cpu = task_cpu(p);
+	min_load = INT_MAX;
 
-	minload = 10000000;
-	for_each_node_with_cpus(i) {
-		/*
-		 * Node load is always divided by nr_cpus_node to normalise
-		 * load values in case cpu count differs from node to node.
-		 * We first multiply node_nr_running by 10 to get a little
-		 * better resolution.
-		 */
-		load = 10 * atomic_read(&node_nr_running[i]) / nr_cpus_node(i);
-		if (load < minload) {
-			minload = load;
-			node = i;
-		}
-	}
+	cpus_and(tmp, domain->span, cpu_online_map);
+	for_each_cpu_mask(i, tmp) {
+		unsigned long load;
+		if (i == this_cpu)
+			load = get_low_cpu_load(i, 0);
+		else
+			load = get_high_cpu_load(i, 0) + SCHED_LOAD_SCALE;
 
-	minload = 10000000;
-	cpumask = node_to_cpumask(node);
-	for (i = 0; i < NR_CPUS; ++i) {
-		if (!cpu_isset(i, cpumask))
-			continue;
-		if (cpu_rq(i)->nr_running < minload) {
+		if (min_load > load) {
 			best_cpu = i;
-			minload = cpu_rq(i)->nr_running;
+			min_load = load;
 		}
+
 	}
 	return best_cpu;
 }
 
 void sched_balance_exec(void)
 {
+	struct sched_domain *domain = this_sched_domain();
 	int new_cpu;
+	int this_cpu = smp_processor_id();
+	if (numnodes == 1)
+		return;
 
-	if (numnodes > 1) {
-		new_cpu = sched_best_cpu(current);
-		if (new_cpu != smp_processor_id())
-			sched_migrate_task(current, new_cpu);
-	}
-}
+	if (this_rq()->nr_running <= 1)
+		return;
 
-/*
- * Find the busiest node. All previous node loads contribute with a
- * geometrically deccaying weight to the load measure:
- *      load_{t} = load_{t-1}/2 + nr_node_running_{t}
- * This way sudden load peaks are flattened out a bit.
- * Node load is divided by nr_cpus_node() in order to compare nodes
- * of different cpu count but also [first] multiplied by 10 to
- * provide better resolution.
- */
-static int find_busiest_node(int this_node)
-{
-	int i, node = -1, load, this_load, maxload;
-
-	if (!nr_cpus_node(this_node))
-		return node;
-	this_load = maxload = (this_rq()->prev_node_load[this_node] >> 1)
-		+ (10 * atomic_read(&node_nr_running[this_node])
-		/ nr_cpus_node(this_node));
-	this_rq()->prev_node_load[this_node] = this_load;
-	for_each_node_with_cpus(i) {
-		if (i == this_node)
-			continue;
-		load = (this_rq()->prev_node_load[i] >> 1)
-			+ (10 * atomic_read(&node_nr_running[i])
-			/ nr_cpus_node(i));
-		this_rq()->prev_node_load[i] = load;
-		if (load > maxload && (100*load > NODE_THRESHOLD*this_load)) {
-			maxload = load;
-			node = i;
-		}
+	while (domain->parent && !(domain->flags & SD_FLAG_EXEC))
+		domain = domain->parent;
+
+	if (domain->flags & SD_FLAG_EXEC) {
+		new_cpu = sched_best_cpu(current, domain);
+		if (new_cpu != this_cpu)
+			migrate_to_cpu(new_cpu);
 	}
-	return node;
 }
-
 #endif /* CONFIG_NUMA */
 
-#ifdef CONFIG_SMP
-
 /*
- * double_lock_balance - lock the busiest runqueue
- *
- * this_rq is locked already. Recalculate nr_running if we have to
- * drop the runqueue lock.
+ * double_lock_balance - lock the busiest runqueue, this_rq is locked already.
  */
-static inline
-unsigned int double_lock_balance(runqueue_t *this_rq, runqueue_t *busiest,
-				 int this_cpu, int idle,
-				 unsigned int nr_running)
+static inline void double_lock_balance(runqueue_t *this_rq, runqueue_t *busiest)
 {
 	if (unlikely(!spin_trylock(&busiest->lock))) {
 		if (busiest < this_rq) {
 			spin_unlock(&this_rq->lock);
 			spin_lock(&busiest->lock);
 			spin_lock(&this_rq->lock);
-			/* Need to recalculate nr_running */
-			if (idle || (this_rq->nr_running >
-					this_rq->prev_cpu_load[this_cpu]))
-				nr_running = this_rq->nr_running;
-			else
-				nr_running = this_rq->prev_cpu_load[this_cpu];
 		} else
 			spin_lock(&busiest->lock);
 	}
-	return nr_running;
-}
-
-/*
- * find_busiest_queue - find the busiest runqueue among the cpus in cpumask.
- */
-static inline
-runqueue_t *find_busiest_queue(runqueue_t *this_rq, int this_cpu, int idle,
-			       int *imbalance, cpumask_t cpumask)
-{
-	int nr_running, load, max_load, i;
-	runqueue_t *busiest, *rq_src;
-
-	/*
-	 * We search all runqueues to find the most busy one.
-	 * We do this lockless to reduce cache-bouncing overhead,
-	 * we re-check the 'best' source CPU later on again, with
-	 * the lock held.
-	 *
-	 * We fend off statistical fluctuations in runqueue lengths by
-	 * saving the runqueue length (as seen by the balancing CPU) during
-	 * the previous load-balancing operation and using the smaller one
-	 * of the current and saved lengths. If a runqueue is long enough
-	 * for a longer amount of time then we recognize it and pull tasks
-	 * from it.
-	 *
-	 * The 'current runqueue length' is a statistical maximum variable,
-	 * for that one we take the longer one - to avoid fluctuations in
-	 * the other direction. So for a load-balance to happen it needs
-	 * stable long runqueue on the target CPU and stable short runqueue
-	 * on the local runqueue.
-	 *
-	 * We make an exception if this CPU is about to become idle - in
-	 * that case we are less picky about moving a task across CPUs and
-	 * take what can be taken.
-	 */
-	if (idle || (this_rq->nr_running > this_rq->prev_cpu_load[this_cpu]))
-		nr_running = this_rq->nr_running;
-	else
-		nr_running = this_rq->prev_cpu_load[this_cpu];
-
-	busiest = NULL;
-	max_load = 1;
-	for (i = 0; i < NR_CPUS; i++) {
-		if (!cpu_isset(i, cpumask))
-			continue;
-
-		rq_src = cpu_rq(i);
-		if (idle || (rq_src->nr_running < this_rq->prev_cpu_load[i]))
-			load = rq_src->nr_running;
-		else
-			load = this_rq->prev_cpu_load[i];
-		this_rq->prev_cpu_load[i] = rq_src->nr_running;
-
-		if ((load > max_load) && (rq_src != this_rq)) {
-			busiest = rq_src;
-			max_load = load;
-		}
-	}
-
-	if (likely(!busiest))
-		goto out;
-
-	*imbalance = max_load - nr_running;
-
-	/* It needs an at least ~25% imbalance to trigger balancing. */
-	if (!idle && ((*imbalance)*4 < max_load)) {
-		busiest = NULL;
-		goto out;
-	}
-
-	nr_running = double_lock_balance(this_rq, busiest, this_cpu,
-					 idle, nr_running);
-	/*
-	 * Make sure nothing changed since we checked the
-	 * runqueue length.
-	 */
-	if (busiest->nr_running <= nr_running) {
-		spin_unlock(&busiest->lock);
-		busiest = NULL;
-	}
-out:
-	return busiest;
 }
 
 /*
  * pull_task - move a task from a remote runqueue to the local runqueue.
  * Both runqueues must be locked.
  */
-static inline
-void pull_task(runqueue_t *src_rq, prio_array_t *src_array, task_t *p,
-	       runqueue_t *this_rq, int this_cpu)
+static inline void pull_task(runqueue_t *src_rq, prio_array_t *src_array,
+		task_t *p, runqueue_t *this_rq, prio_array_t *this_array,
+		int this_cpu)
 {
 	dequeue_task(p, src_array);
 	nr_running_dec(src_rq);
 	set_task_cpu(p, this_cpu);
 	nr_running_inc(this_rq);
-	enqueue_task(p, this_rq->active);
+	enqueue_task(p, this_array);
 	p->timestamp = sched_clock() -
 				(src_rq->timestamp_last_tick - p->timestamp);
 	/*
@@ -1262,69 +1242,71 @@ void pull_task(runqueue_t *src_rq, prio_
 	 * to be always true for them.
 	 */
 	if (TASK_PREEMPTS_CURR(p, this_rq))
-		set_need_resched();
+		resched_task(this_rq->curr);
 }
 
 /*
  * can_migrate_task - may task p from runqueue rq be migrated to this_cpu?
  */
 static inline
-int can_migrate_task(task_t *tsk, runqueue_t *rq, int this_cpu, int idle)
+int can_migrate_task(task_t *p, runqueue_t *rq, int this_cpu,
+		struct sched_domain *domain, enum idle_type idle)
 {
-	unsigned long delta = rq->timestamp_last_tick - tsk->timestamp;
-
 	/*
 	 * We do not migrate tasks that are:
 	 * 1) running (obviously), or
 	 * 2) cannot be migrated to this CPU due to cpus_allowed, or
 	 * 3) are cache-hot on their current CPU.
 	 */
-	if (task_running(rq, tsk))
-		return 0;
-	if (!cpu_isset(this_cpu, tsk->cpus_allowed))
+	if (task_running(rq, p))
 		return 0;
-	if (!idle && (delta <= JIFFIES_TO_NS(cache_decay_ticks)))
+	if (!cpu_isset(this_cpu, p->cpus_allowed))
 		return 0;
+
+	/* Aggressive migration if we've failed balancing */
+	if (idle == NEWLY_IDLE ||
+			domain->nr_balance_failed < domain->cache_nice_tries) {
+		if ((rq->timestamp_last_tick - p->timestamp)
+						< domain->cache_hot_time)
+			return 0;
+	}
+
 	return 1;
 }
 
 /*
- * Current runqueue is empty, or rebalance tick: if there is an
- * inbalance (current runqueue is too short) then pull from
- * busiest runqueue(s).
- *
- * We call this with the current runqueue locked,
- * irqs disabled.
- */
-static void load_balance(runqueue_t *this_rq, int idle, cpumask_t cpumask)
+ * move_tasks tries to move up to max_nr_move tasks from busiest to this_rq,
+ * as part of a balancing operation within "domain". Returns the number of
+ * tasks moved.
+ *
+ * Called with both runqueues locked.
+ */
+static int move_tasks(runqueue_t *this_rq, int this_cpu, runqueue_t *busiest,
+			unsigned long max_nr_move, struct sched_domain *domain,
+			enum idle_type idle)
 {
-	int imbalance, idx, this_cpu = smp_processor_id();
-	runqueue_t *busiest;
-	prio_array_t *array;
+	int idx;
+	int pulled = 0;
+	prio_array_t *array, *dst_array;
 	struct list_head *head, *curr;
 	task_t *tmp;
 
-	busiest = find_busiest_queue(this_rq, this_cpu, idle,
-				     &imbalance, cpumask);
-	if (!busiest)
+	if (max_nr_move <= 0 || busiest->nr_running <= 1)
 		goto out;
 
 	/*
-	 * We only want to steal a number of tasks equal to 1/2 the imbalance,
-	 * otherwise we'll just shift the imbalance to the new queue:
-	 */
-	imbalance /= 2;
-
-	/*
 	 * We first consider expired tasks. Those will likely not be
 	 * executed in the near future, and they are most likely to
 	 * be cache-cold, thus switching CPUs has the least effect
 	 * on them.
 	 */
-	if (busiest->expired->nr_active)
+	if (busiest->expired->nr_active) {
 		array = busiest->expired;
-	else
+		dst_array = this_rq->expired;
+	} else {
 		array = busiest->active;
+		dst_array = this_rq->active;
+	}
 
 new_array:
 	/* Start searching at priority 0: */
@@ -1337,9 +1319,10 @@ skip_bitmap:
 	if (idx >= MAX_PRIO) {
 		if (array == busiest->expired) {
 			array = busiest->active;
+			dst_array = this_rq->active;
 			goto new_array;
 		}
-		goto out_unlock;
+		goto out;
 	}
 
 	head = array->queue + idx;
@@ -1349,104 +1332,478 @@ skip_queue:
 
 	curr = curr->prev;
 
-	if (!can_migrate_task(tmp, busiest, this_cpu, idle)) {
+	if (!can_migrate_task(tmp, busiest, this_cpu, domain, idle)) {
 		if (curr != head)
 			goto skip_queue;
 		idx++;
 		goto skip_bitmap;
 	}
-	pull_task(busiest, array, tmp, this_rq, this_cpu);
+	pull_task(busiest, array, tmp, this_rq, dst_array, this_cpu);
+	pulled++;
 
-	/* Only migrate one task if we are idle */
-	if (!idle && --imbalance) {
+	/* We only want to steal up to the prescribed number of tasks. */
+	if (pulled < max_nr_move) {
 		if (curr != head)
 			goto skip_queue;
 		idx++;
 		goto skip_bitmap;
 	}
-out_unlock:
-	spin_unlock(&busiest->lock);
 out:
-	;
+	return pulled;
+}
+
+/*
+ * find_busiest_group finds and returns the busiest CPU group within the
+ * domain. It calculates and returns the number of tasks which should be
+ * moved to restore balance via the imbalance parameter.
+ */
+static struct sched_group *
+find_busiest_group(struct sched_domain *domain, int this_cpu,
+				unsigned long *imbalance, enum idle_type idle)
+{
+	unsigned long max_load, avg_load, total_load, this_load;
+	unsigned int total_pwr;
+	int modify;
+	struct sched_group *busiest = NULL, *this = NULL, *group = domain->groups;
+
+	max_load = 0;
+	this_load = 0;
+	total_load = 0;
+	total_pwr = 0;
+
+	if (group == NULL)
+		goto out_balanced;
+
+	/*
+	 * Don't modify when we newly become idle because that ruins our
+	 * statistics: its triggered by some value of nr_running (ie. 0).
+	 * Timer based balancing is a good statistic though.
+	 */
+	if (idle == NEWLY_IDLE)
+		modify = 0;
+	else
+		modify = 1;
+
+	do {
+		cpumask_t tmp;
+		unsigned long load;
+		int local_group;
+		int i, nr_cpus = 0;
+
+		local_group = cpu_isset(this_cpu, group->cpumask);
+
+		/* Tally up the load of all CPUs in the group */
+		avg_load = 0;
+		cpus_and(tmp, group->cpumask, cpu_online_map);
+		for_each_cpu_mask(i, tmp) {
+			/* Bias balancing toward cpus of our domain */
+			if (local_group) {
+				load = get_high_cpu_load(i, modify);
+			} else
+				load = get_low_cpu_load(i, modify);
+
+			nr_cpus++;
+			avg_load += load;
+		}
+
+		if (!nr_cpus)
+			goto nextgroup;
+
+		total_load += avg_load;
+		total_pwr += group->cpu_power;
+
+		/* Adjust by relative CPU power of the group */
+		avg_load = (avg_load << SCHED_LOAD_SHIFT) / group->cpu_power;
+
+		if (local_group) {
+			this_load = avg_load;
+			this = group;
+			goto nextgroup;
+		}
+		if (avg_load > max_load) {
+			max_load = avg_load;
+			busiest = group;
+		}
+nextgroup:
+		group = group->next;
+	} while (group != domain->groups);
+
+	if (!busiest || this_load >= max_load)
+		goto out_balanced;
+
+	avg_load = (SCHED_LOAD_SCALE * total_load) / total_pwr;
+
+	if (idle == NOT_IDLE) {
+		if (this_load >= avg_load ||
+			100*max_load <= domain->imbalance_pct*this_load)
+		goto out_balanced;
+	}
+
+	/*
+	 * We're trying to get all the cpus to the average_load, so we don't
+	 * want to push ourselves above the average load, nor do we wish to
+	 * reduce the max loaded cpu below the average load, as either of these
+	 * actions would just result in more rebalancing later, and ping-pong
+	 * tasks around. Thus we look for the minimum possible imbalance.
+	 * Negative imbalances (*we* are more loaded than anyone else) will
+	 * be counted as no imbalance for these purposes -- we can't fix that
+	 * by pulling tasks to us.  Be careful of negative numbers as they'll
+	 * appear as very large values with unsigned longs.
+	 */
+	*imbalance = (min(max_load - avg_load, avg_load - this_load) + 1) / 2;
+
+	if (*imbalance <= SCHED_LOAD_SCALE/2) {
+		unsigned long pwr_now = 0, pwr_move = 0;
+		unsigned long tmp;
+
+		/*
+		 * OK, we don't have enough imbalance to justify moving tasks,
+		 * however we may be able to increase total CPU power used by
+		 * moving them.
+		 */
+
+		pwr_now += busiest->cpu_power*min(SCHED_LOAD_SCALE, max_load);
+		pwr_now += this->cpu_power*min(SCHED_LOAD_SCALE, this_load);
+		pwr_now >>= SCHED_LOAD_SHIFT;
+
+		/* Amount of load we'd subtract */
+		tmp = SCHED_LOAD_SCALE*SCHED_LOAD_SCALE/busiest->cpu_power;
+		if (max_load > tmp)
+			pwr_move += busiest->cpu_power*min(SCHED_LOAD_SCALE,
+							max_load - tmp);
+
+		/* Amount of load we'd add */
+		tmp = SCHED_LOAD_SCALE*SCHED_LOAD_SCALE/this->cpu_power;
+		pwr_move += this->cpu_power*min(this->cpu_power, this_load + tmp);
+		pwr_move >>= SCHED_LOAD_SHIFT;
+
+		/* Move if we gain another 8th of a CPU worth of throughput */
+		if (pwr_move < pwr_now + SCHED_LOAD_SCALE / 8)
+			goto out_balanced;
+		*imbalance = 1;
+		return busiest;
+	}
+
+	/* How many tasks to actually move to equalise the imbalance */
+	*imbalance = (*imbalance * min(busiest->cpu_power, this->cpu_power))
+				>> SCHED_LOAD_SHIFT;
+	/* Get rid of the scaling factor, rounding *up* as we divide */
+	*imbalance = (*imbalance + SCHED_LOAD_SCALE/2) >> SCHED_LOAD_SHIFT;
+
+	return busiest;
+
+out_balanced:
+	if (busiest && idle == NEWLY_IDLE) {
+		*imbalance = 1;
+		return busiest;
+	}
+
+	*imbalance = 0;
+	return NULL;
 }
 
 /*
- * One of the idle_cpu_tick() and busy_cpu_tick() functions will
- * get called every timer tick, on every CPU. Our balancing action
- * frequency and balancing agressivity depends on whether the CPU is
- * idle or not.
+ * find_busiest_queue - find the busiest runqueue among the cpus in group.
+ */
+static runqueue_t *find_busiest_queue(struct sched_group *group)
+{
+	cpumask_t tmp;
+	int i;
+	unsigned long max_load = 0;
+	runqueue_t *busiest = NULL;
+
+	cpus_and(tmp, group->cpumask, cpu_online_map);
+	for_each_cpu_mask(i, tmp) {
+		unsigned long load;
+
+		load = get_low_cpu_load(i, 0);
+
+		if (load >= max_load) {
+			max_load = load;
+			busiest = cpu_rq(i);
+		}
+	}
+
+	return busiest;
+}
+
+/*
+ * Check this_cpu to ensure it is balanced within domain. Attempt to move
+ * tasks if there is an imbalance.
  *
- * busy-rebalance every 200 msecs. idle-rebalance every 1 msec. (or on
- * systems with HZ=100, every 10 msecs.)
+ * Called with this_rq unlocked.
+ */
+static int load_balance(int this_cpu, runqueue_t *this_rq,
+			struct sched_domain *domain, enum idle_type idle)
+{
+	struct sched_group *group;
+	runqueue_t *busiest = NULL;
+	unsigned long imbalance;
+	int balanced = 0, failed = 0;
+	int nr_moved = 0;
+
+	spin_lock(&this_rq->lock);
+
+	group = find_busiest_group(domain, this_cpu, &imbalance, idle);
+	if (!group) {
+		balanced = 1;
+		goto out;
+	}
+
+	busiest = find_busiest_queue(group);
+	if (!busiest || busiest == this_rq) {
+		balanced = 1;
+		goto out;
+	}
+
+	/* Attempt to move tasks */
+	double_lock_balance(this_rq, busiest);
+
+	nr_moved = move_tasks(this_rq, this_cpu, busiest,
+					imbalance, domain, idle);
+	spin_unlock(&busiest->lock);
+out:
+	spin_unlock(&this_rq->lock);
+
+	if (!balanced && nr_moved == 0)
+		failed = 1;
+
+	if (failed && busiest &&
+	   		domain->nr_balance_failed > domain->cache_nice_tries) {
+		int wake = 0;
+
+		spin_lock(&busiest->lock);
+		if (!busiest->active_balance) {
+			busiest->active_balance = 1;
+			busiest->push_cpu = this_cpu;
+			wake = 1;
+		}
+		spin_unlock(&busiest->lock);
+		if (wake)
+			wake_up_process(busiest->migration_thread);
+	}
+
+	if (failed)
+		domain->nr_balance_failed++;
+	else
+		domain->nr_balance_failed = 0;
+
+	if (balanced) {
+		if (domain->balance_interval < domain->max_interval)
+			domain->balance_interval *= 2;
+	} else {
+		domain->balance_interval = domain->min_interval;
+	}
+
+	return nr_moved;
+}
+
+/*
+ * Check this_cpu to ensure it is balanced within domain. Attempt to move
+ * tasks if there is an imbalance.
  *
- * On NUMA, do a node-rebalance every 400 msecs.
+ * Called from schedule when this_rq is about to become idle (NEWLY_IDLE).
+ * this_rq is locked.
  */
-#define IDLE_REBALANCE_TICK (HZ/1000 ?: 1)
-#define BUSY_REBALANCE_TICK (HZ/5 ?: 1)
-#define IDLE_NODE_REBALANCE_TICK (IDLE_REBALANCE_TICK * 5)
-#define BUSY_NODE_REBALANCE_TICK (BUSY_REBALANCE_TICK * 2)
+static int load_balance_newidle(int this_cpu, runqueue_t *this_rq,
+			struct sched_domain *domain)
+{
+	struct sched_group *group;
+	runqueue_t *busiest = NULL;
+	unsigned long imbalance;
+	int nr_moved = 0;
 
-#ifdef CONFIG_NUMA
-static void balance_node(runqueue_t *this_rq, int idle, int this_cpu)
+	group = find_busiest_group(domain, this_cpu, &imbalance, NEWLY_IDLE);
+	if (!group)
+		goto out;
+
+	busiest = find_busiest_queue(group);
+	if (!busiest || busiest == this_rq)
+		goto out;
+
+	/* Attempt to move tasks */
+	double_lock_balance(this_rq, busiest);
+
+	nr_moved = move_tasks(this_rq, this_cpu, busiest,
+					imbalance, domain, NEWLY_IDLE);
+
+	spin_unlock(&busiest->lock);
+
+out:
+	return nr_moved;
+}
+
+/*
+ * idle_balance is called by schedule() if this_cpu is about to become
+ * idle. Attempts to pull tasks from other CPUs.
+ */
+static inline void idle_balance(int this_cpu, runqueue_t *this_rq)
 {
-	int node = find_busiest_node(cpu_to_node(this_cpu));
+	struct sched_domain *domain = this_sched_domain();
 
-	if (node >= 0) {
-		cpumask_t cpumask = node_to_cpumask(node);
-		cpu_set(this_cpu, cpumask);
-		spin_lock(&this_rq->lock);
-		load_balance(this_rq, idle, cpumask);
-		spin_unlock(&this_rq->lock);
-	}
+	if (cpu_is_offline(this_cpu))
+		return;
+
+	do {
+		if (unlikely(!domain->groups))
+			/* hasn't been setup yet */
+			break;
+
+		if (domain->flags & SD_FLAG_NEWIDLE) {
+			if (load_balance_newidle(this_cpu, this_rq, domain)) {
+				/* We've pulled tasks over so stop searching */
+				break;
+			}
+		}
+
+		domain = domain->parent;
+	} while (domain);
 }
-#endif
 
-static void rebalance_tick(runqueue_t *this_rq, int idle)
+/*
+ * active_load_balance is run by migration threads. It pushes a running
+ * task off the cpu. It can be required to correctly have at least 1 task
+ * running on each physical CPU where possible, and not have a physical /
+ * logical imbalance.
+ *
+ * Called with busiest locked.
+ */
+static void active_load_balance(runqueue_t *busiest, int busiest_cpu)
 {
-#ifdef CONFIG_NUMA
-	int this_cpu = smp_processor_id();
-#endif
-	unsigned long j = jiffies;
+	int i;
+	struct sched_domain *sd = cpu_sched_domain(busiest_cpu);
+	struct sched_group *group, *busy_group;
 
-	/*
-	 * First do inter-node rebalancing, then intra-node rebalancing,
-	 * if both events happen in the same tick. The inter-node
-	 * rebalancing does not necessarily have to create a perfect
-	 * balance within the node, since we load-balance the most loaded
-	 * node with the current CPU. (ie. other CPUs in the local node
-	 * are not balanced.)
-	 */
-	if (idle) {
-#ifdef CONFIG_NUMA
-		if (!(j % IDLE_NODE_REBALANCE_TICK))
-			balance_node(this_rq, idle, this_cpu);
-#endif
-		if (!(j % IDLE_REBALANCE_TICK)) {
-			spin_lock(&this_rq->lock);
-			load_balance(this_rq, idle, cpu_to_node_mask(this_cpu));
-			spin_unlock(&this_rq->lock);
+	if (busiest->nr_running <= 1)
+		return;
+
+	/* sd->parent should never cause a NULL dereference, if it did so,
+ 	 * then push_cpu was set to a buggy value */
+	while (!cpu_isset(busiest->push_cpu, sd->span)) {
+ 		sd = sd->parent;
+		if (!sd->parent && !cpu_isset(busiest->push_cpu, sd->span)) {
+			WARN_ON(1);
+			return;
 		}
+	}
+
+	if (!sd->groups) {
+		WARN_ON(1);
 		return;
 	}
-#ifdef CONFIG_NUMA
-	if (!(j % BUSY_NODE_REBALANCE_TICK))
-		balance_node(this_rq, idle, this_cpu);
-#endif
-	if (!(j % BUSY_REBALANCE_TICK)) {
-		spin_lock(&this_rq->lock);
-		load_balance(this_rq, idle, cpu_to_node_mask(this_cpu));
-		spin_unlock(&this_rq->lock);
+
+ 	group = sd->groups;
+	while (!cpu_isset(busiest_cpu, group->cpumask)) {
+ 		group = group->next;
+		if (group == sd->groups) {
+			WARN_ON(1);
+			return;
+		}
 	}
+ 	busy_group = group;
+
+ 	group = sd->groups;
+ 	do {
+		cpumask_t tmp;
+		runqueue_t *rq;
+ 		int push_cpu = 0, nr = 0;
+
+ 		if (group == busy_group)
+ 			goto next_group;
+
+		cpus_and(tmp, group->cpumask, cpu_online_map);
+ 		for_each_cpu_mask(i, tmp) {
+			if (!idle_cpu(i))
+				goto next_group;
+ 			push_cpu = i;
+ 			nr++;
+ 		}
+ 		if (nr == 0)
+ 			goto next_group;
+
+		rq = cpu_rq(push_cpu);
+		double_lock_balance(busiest, rq);
+		move_tasks(rq, push_cpu, busiest, 1, sd, IDLE);
+		spin_unlock(&rq->lock);
+next_group:
+		group = group->next;
+	} while (group != sd->groups);
+}
+
+/*
+ * rebalance_tick will get called every timer tick, on every CPU.
+ *
+ * It checks each scheduling domain to see if it is due to be balanced,
+ * and initiates a balancing operation if so.
+ *
+ * Balancing parameters are set up in arch_init_sched_domains.
+ */
+
+/* Don't have all balancing operations going off at once */
+#define CPU_OFFSET(cpu) (HZ * cpu / NR_CPUS)
+
+static void rebalance_tick(int this_cpu, runqueue_t *this_rq, enum idle_type idle)
+{
+	unsigned long j = jiffies + CPU_OFFSET(this_cpu);
+	struct sched_domain *domain = this_sched_domain();
+
+	BUG_ON(cpu_is_offline(this_cpu) && system_running);
+
+	/* Run through all this CPU's domains */
+	do {
+		unsigned long interval;
+
+		if (unlikely(!domain->groups))
+			break;
+
+		interval = domain->balance_interval;
+		if (idle != IDLE)
+			interval *= domain->busy_factor;
+
+		/* scale ms to jiffies */
+		interval = interval * HZ / 1000;
+		if (unlikely(interval == 0))
+			interval = 1;
+
+		if (j - domain->last_balance >= interval) {
+			if (load_balance(this_cpu, this_rq, domain, idle)) {
+				/* We've pulled tasks over so no longer idle */
+				idle = NOT_IDLE;
+			}
+			domain->last_balance += interval;
+		}
+
+		domain = domain->parent;
+	} while (domain);
 }
 #else
 /*
  * on UP we do not need to balance between CPUs:
  */
-static inline void rebalance_tick(runqueue_t *this_rq, int idle)
+static inline void rebalance_tick(int this_cpu, runqueue_t *this_rq, enum idle_type idle)
 {
 }
 #endif
 
+#ifdef CONFIG_SCHED_SMT
+static inline int wake_priority_sleeper(runqueue_t *rq)
+{	/*
+	 * If an SMT sibling task has been put to sleep for priority
+	 * reasons reschedule the idle task to see if it can now run.
+	 */
+	if (rq->nr_running) {
+		resched_task(rq->idle);
+		return 1;
+	}
+	return 0;
+}
+#else
+static inline int wake_priority_sleeper(runqueue_t *rq)
+{
+	return 0;
+}
+#endif
+
 DEFINE_PER_CPU(struct kernel_stat, kstat);
 
 EXPORT_PER_CPU_SYMBOL(kstat);
@@ -1500,7 +1857,9 @@ void scheduler_tick(int user_ticks, int 
 			cpustat->iowait += sys_ticks;
 		else
 			cpustat->idle += sys_ticks;
-		rebalance_tick(rq, 1);
+		if (wake_priority_sleeper(rq))
+			goto out;
+		rebalance_tick(cpu, rq, IDLE);
 		return;
 	}
 	if (TASK_NICE(p) > 0)
@@ -1584,9 +1943,94 @@ void scheduler_tick(int user_ticks, int 
 out_unlock:
 	spin_unlock(&rq->lock);
 out:
-	rebalance_tick(rq, 0);
+	rebalance_tick(cpu, rq, NOT_IDLE);
+}
+
+#ifdef CONFIG_SCHED_SMT
+static inline void wake_sleeping_dependent(runqueue_t *rq)
+{
+	int i, this_cpu = rq->cpu;
+	struct sched_domain *sd = cpu_sched_domain(this_cpu);
+	cpumask_t sibling_map;
+
+	if (!(sd->flags & SD_FLAG_SHARE_CPUPOWER)) {
+		/* Not SMT */
+		return;
+	}
+
+	cpus_and(sibling_map, sd->span, cpu_online_map);
+	cpu_clear(this_cpu, sibling_map);
+	for_each_cpu_mask(i, sibling_map) {
+		runqueue_t *smt_rq;
+
+		smt_rq = cpu_rq(i);
+
+		/*
+		 * If an SMT sibling task is sleeping due to priority
+		 * reasons wake it up now.
+		 */
+		if (smt_rq->curr == smt_rq->idle && smt_rq->nr_running)
+			resched_task(smt_rq->idle);
+	}
 }
 
+static inline int dependent_sleeper(runqueue_t *rq, task_t *p)
+{
+	int ret = 0, i, this_cpu = rq->cpu;
+	struct sched_domain *sd = cpu_sched_domain(this_cpu);
+	cpumask_t sibling_map;
+
+	if (!(sd->flags & SD_FLAG_SHARE_CPUPOWER)) {
+		/* Not SMT */
+		return 0;
+	}
+
+	cpus_and(sibling_map, sd->span, cpu_online_map);
+	cpu_clear(this_cpu, sibling_map);
+	for_each_cpu_mask(i, sibling_map) {
+		runqueue_t *smt_rq;
+		task_t *smt_curr;
+
+		smt_rq = cpu_rq(i);
+		smt_curr = smt_rq->curr;
+
+		/*
+		 * If a user task with lower static priority than the
+		 * running task on the SMT sibling is trying to schedule,
+		 * delay it till there is proportionately less timeslice
+		 * left of the sibling task to prevent a lower priority
+		 * task from using an unfair proportion of the
+		 * physical cpu's resources. -ck
+		 */
+		if (((smt_curr->time_slice * (100 - sd->per_cpu_gain) / 100) >
+			task_timeslice(p) || rt_task(smt_curr)) &&
+			p->mm && smt_curr->mm && !rt_task(p))
+				ret |= 1;
+
+		/*
+		 * Reschedule a lower priority task on the SMT sibling,
+		 * or wake it up if it has been put to sleep for priority
+		 * reasons.
+		 */
+		if ((((p->time_slice * (100 - sd->per_cpu_gain) / 100) >
+			task_timeslice(smt_curr) || rt_task(p)) &&
+			smt_curr->mm && p->mm && !rt_task(smt_curr)) ||
+			(smt_curr == smt_rq->idle && smt_rq->nr_running))
+				resched_task(smt_curr);
+	}
+	return ret;
+}
+#else
+static inline void wake_sleeping_dependent(runqueue_t *rq)
+{
+}
+
+static inline int dependent_sleeper(runqueue_t *rq, task_t *p)
+{
+	return 0;
+}
+#endif
+
 void scheduling_functions_start_here(void) { }
 
 /*
@@ -1653,11 +2097,12 @@ need_resched:
 
 	if (unlikely(!rq->nr_running)) {
 #ifdef CONFIG_SMP
-		load_balance(rq, 1, cpu_to_node_mask(smp_processor_id()));
+		idle_balance(smp_processor_id(), rq);
 #endif
 		if (!rq->nr_running) {
 			next = rq->idle;
 			rq->expired_timestamp = 0;
+			wake_sleeping_dependent(rq);
 			goto switch_tasks;
 		}
 	}
@@ -1678,6 +2123,11 @@ need_resched:
 	queue = array->queue + idx;
 	next = list_entry(queue->next, task_t, run_list);
 
+	if (dependent_sleeper(rq, next)) {
+		next = rq->idle;
+		goto switch_tasks;
+	}
+
 	if (next->activated > 0) {
 		unsigned long long delta = now - next->timestamp;
 
@@ -1796,7 +2246,7 @@ static void __wake_up_common(wait_queue_
  * @mode: which threads
  * @nr_exclusive: how many wake-one or wake-many threads to wake up
  */
-void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr_exclusive)
+void fastcall __wake_up(wait_queue_head_t *q, unsigned int mode, int nr_exclusive)
 {
 	unsigned long flags;
 
@@ -1810,7 +2260,7 @@ EXPORT_SYMBOL(__wake_up);
 /*
  * Same as __wake_up but called with the spinlock in wait_queue_head_t held.
  */
-void __wake_up_locked(wait_queue_head_t *q, unsigned int mode)
+void fastcall __wake_up_locked(wait_queue_head_t *q, unsigned int mode)
 {
 	__wake_up_common(q, mode, 1, 0);
 }
@@ -1828,7 +2278,7 @@ void __wake_up_locked(wait_queue_head_t 
  *
  * On UP it can prevent extra preemption.
  */
-void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive)
+void fastcall __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive)
 {
 	unsigned long flags;
 
@@ -1845,7 +2295,7 @@ void __wake_up_sync(wait_queue_head_t *q
 
 EXPORT_SYMBOL_GPL(__wake_up_sync);	/* For internal use only */
 
-void complete(struct completion *x)
+void fastcall complete(struct completion *x)
 {
 	unsigned long flags;
 
@@ -1858,7 +2308,7 @@ void complete(struct completion *x)
 
 EXPORT_SYMBOL(complete);
 
-void complete_all(struct completion *x)
+void fastcall complete_all(struct completion *x)
 {
 	unsigned long flags;
 
@@ -1869,7 +2319,7 @@ void complete_all(struct completion *x)
 	spin_unlock_irqrestore(&x->wait.lock, flags);
 }
 
-void wait_for_completion(struct completion *x)
+void fastcall wait_for_completion(struct completion *x)
 {
 	might_sleep();
 	spin_lock_irq(&x->wait.lock);
@@ -1907,7 +2357,7 @@ EXPORT_SYMBOL(wait_for_completion);
 	__remove_wait_queue(q, &wait);			\
 	spin_unlock_irqrestore(&q->lock, flags);
 
-void interruptible_sleep_on(wait_queue_head_t *q)
+void fastcall interruptible_sleep_on(wait_queue_head_t *q)
 {
 	SLEEP_ON_VAR
 
@@ -1920,7 +2370,7 @@ void interruptible_sleep_on(wait_queue_h
 
 EXPORT_SYMBOL(interruptible_sleep_on);
 
-long interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout)
+long fastcall interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout)
 {
 	SLEEP_ON_VAR
 
@@ -1935,7 +2385,7 @@ long interruptible_sleep_on_timeout(wait
 
 EXPORT_SYMBOL(interruptible_sleep_on_timeout);
 
-void sleep_on(wait_queue_head_t *q)
+void fastcall sleep_on(wait_queue_head_t *q)
 {
 	SLEEP_ON_VAR
 
@@ -1948,7 +2398,7 @@ void sleep_on(wait_queue_head_t *q)
 
 EXPORT_SYMBOL(sleep_on);
 
-long sleep_on_timeout(wait_queue_head_t *q, long timeout)
+long fastcall sleep_on_timeout(wait_queue_head_t *q, long timeout)
 {
 	SLEEP_ON_VAR
 
@@ -2014,6 +2464,13 @@ out_unlock:
 
 EXPORT_SYMBOL(set_user_nice);
 
+#if defined( CONFIG_KGDB)
+struct task_struct * kgdb_get_idle(int this_cpu)
+{
+        return cpu_rq(this_cpu)->idle;
+}
+#endif
+
 #ifndef __alpha__
 
 /*
@@ -2311,11 +2768,13 @@ asmlinkage long sys_sched_setaffinity(pi
 	if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask)))
 		return -EFAULT;
 
+	lock_cpu_hotplug();
 	read_lock(&tasklist_lock);
 
 	p = find_process_by_pid(pid);
 	if (!p) {
 		read_unlock(&tasklist_lock);
+		unlock_cpu_hotplug();
 		return -ESRCH;
 	}
 
@@ -2336,6 +2795,7 @@ asmlinkage long sys_sched_setaffinity(pi
 
 out_unlock:
 	put_task_struct(p);
+	unlock_cpu_hotplug();
 	return retval;
 }
 
@@ -2365,7 +2825,7 @@ asmlinkage long sys_sched_getaffinity(pi
 		goto out_unlock;
 
 	retval = 0;
-	cpus_and(mask, p->cpus_allowed, cpu_online_map);
+	cpus_and(mask, p->cpus_allowed, cpu_possible_map);
 
 out_unlock:
 	read_unlock(&tasklist_lock);
@@ -2712,7 +3172,12 @@ int set_cpus_allowed(task_t *p, cpumask_
 		goto out;
 	}
 
-	if (__set_cpus_allowed(p, new_mask, &req)) {
+	p->cpus_allowed = new_mask;
+	/* Can the task run on the task's current CPU? If so, we're done */
+	if (cpu_isset(task_cpu(p), new_mask))
+		goto out;
+
+	if (migrate_task(p, any_online_cpu(new_mask), &req)) {
 		/* Need help from migration thread: drop lock and wait. */
 		task_rq_unlock(rq, &flags);
 		wake_up_process(rq->migration_thread);
@@ -2726,8 +3191,16 @@ out:
 
 EXPORT_SYMBOL_GPL(set_cpus_allowed);
 
-/* Move (not current) task off this cpu, onto dest cpu. */
-static void move_task_away(struct task_struct *p, int dest_cpu)
+/*
+ * Move (not current) task off this cpu, onto dest cpu.  We're doing
+ * this because either it can't run here any more (set_cpus_allowed()
+ * away from this CPU, or CPU going down), or because we're
+ * attempting to rebalance this task on exec (sched_balance_exec).
+ *
+ * So we race with normal scheduler movements, but that's OK, as long
+ * as the task is no longer on this CPU.
+ */
+static void __migrate_task(struct task_struct *p, int dest_cpu)
 {
 	runqueue_t *rq_dest;
 	unsigned long flags;
@@ -2736,14 +3209,21 @@ static void move_task_away(struct task_s
 
 	local_irq_save(flags);
 	double_rq_lock(this_rq(), rq_dest);
+	/* Already moved. */
 	if (task_cpu(p) != smp_processor_id())
-		goto out; /* Already moved */
+		goto out;
+	/* Affinity changed (again). */
+	if (!cpu_isset(dest_cpu, p->cpus_allowed))
+		goto out;
+	/* CPU went down. */
+	if (cpu_is_offline(dest_cpu))
+		goto out;
 
 	set_task_cpu(p, dest_cpu);
 	if (p->array) {
 		deactivate_task(p, this_rq());
 		activate_task(p, rq_dest);
-		if (p->prio < rq_dest->curr->prio)
+		if (TASK_PREEMPTS_CURR(p, rq_dest))
 			resched_task(rq_dest->curr);
 	}
 	p->timestamp = rq_dest->timestamp_last_tick;
@@ -2766,10 +3246,9 @@ static int migration_thread(void * data)
 	int cpu = (long)data;
 	int ret;
 
-	BUG_ON(smp_processor_id() != cpu);
 	ret = setscheduler(0, SCHED_FIFO, &param);
 
-	rq = this_rq();
+	rq = cpu_rq(cpu);
 	BUG_ON(rq->migration_thread != current);
 
 	while (!kthread_should_stop()) {
@@ -2780,7 +3259,13 @@ static int migration_thread(void * data)
 			refrigerator(PF_IOTHREAD);
 
 		spin_lock_irq(&rq->lock);
+		if (rq->active_balance) {
+			active_load_balance(rq, cpu);
+			rq->active_balance = 0;
+		}
+
 		head = &rq->migration_queue;
+
 		current->state = TASK_INTERRUPTIBLE;
 		if (list_empty(head)) {
 			spin_unlock_irq(&rq->lock);
@@ -2791,13 +3276,69 @@ static int migration_thread(void * data)
 		list_del_init(head->next);
 		spin_unlock_irq(&rq->lock);
 
-		move_task_away(req->task,
-			       any_online_cpu(req->task->cpus_allowed));
+		__migrate_task(req->task, req->dest_cpu);
 		complete(&req->done);
 	}
 	return 0;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+/* migrate_all_tasks - function to migrate all the tasks from the
+ * current cpu caller must have already scheduled this to the target
+ * cpu via set_cpus_allowed.  Machine is stopped.  */
+void migrate_all_tasks(void)
+{
+	struct task_struct *tsk, *t;
+	int dest_cpu, src_cpu;
+	unsigned int node;
+
+	/* We're nailed to this CPU. */
+	src_cpu = smp_processor_id();
+
+	/* Not required, but here for neatness. */
+	write_lock(&tasklist_lock);
+
+	/* watch out for per node tasks, let's stay on this node */
+	node = cpu_to_node(src_cpu);
+
+	do_each_thread(t, tsk) {
+		cpumask_t mask;
+		if (tsk == current)
+			continue;
+
+		if (task_cpu(tsk) != src_cpu)
+			continue;
+
+		/* Figure out where this task should go (attempting to
+		 * keep it on-node), and check if it can be migrated
+		 * as-is.  NOTE that kernel threads bound to more than
+		 * one online cpu will be migrated. */
+		mask = node_to_cpumask(node);
+		cpus_and(mask, mask, tsk->cpus_allowed);
+		dest_cpu = any_online_cpu(mask);
+		if (dest_cpu == NR_CPUS)
+			dest_cpu = any_online_cpu(tsk->cpus_allowed);
+		if (dest_cpu == NR_CPUS) {
+			cpus_clear(tsk->cpus_allowed);
+			cpus_complement(tsk->cpus_allowed);
+			dest_cpu = any_online_cpu(tsk->cpus_allowed);
+
+			/* Don't tell them about moving exiting tasks
+			   or kernel threads (both mm NULL), since
+			   they never leave kernel. */
+			if (tsk->mm && printk_ratelimit())
+				printk(KERN_INFO "process %d (%s) no "
+				       "longer affine to cpu%d\n",
+				       tsk->pid, tsk->comm, src_cpu);
+		}
+
+		__migrate_task(tsk, dest_cpu);
+	} while_each_thread(t, tsk);
+
+	write_unlock(&tasklist_lock);
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 /*
  * migration_call - callback that gets triggered when a CPU is added.
  * Here we can start up the necessary migration thread for the new CPU.
@@ -2820,17 +3361,22 @@ static int migration_call(struct notifie
 		/* Strictly unneccessary, as first user will wake it. */
 		wake_up_process(cpu_rq(cpu)->migration_thread);
 		break;
+#ifdef CONFIG_HOTPLUG_CPU
+	case CPU_UP_CANCELED:
+		/* Unbind it from offline cpu so it can run.  Fall thru. */
+		kthread_bind(cpu_rq(cpu)->migration_thread,smp_processor_id());
+	case CPU_DEAD:
+		kthread_stop(cpu_rq(cpu)->migration_thread);
+		cpu_rq(cpu)->migration_thread = NULL;
+ 		BUG_ON(cpu_rq(cpu)->nr_running != 0);
+ 		break;
+#endif
 	}
 	return NOTIFY_OK;
 }
 
-/*
- * We want this after the other threads, so they can use set_cpus_allowed
- * from their CPU_OFFLINE callback
- */
 static struct notifier_block __devinitdata migration_notifier = {
 	.notifier_call = migration_call,
-	.priority = -10,
 };
 
 int __init migration_init(void)
@@ -2859,6 +3405,210 @@ int __init migration_init(void)
 spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 EXPORT_SYMBOL(kernel_flag);
 
+#ifdef CONFIG_SMP
+#ifdef ARCH_HAS_SCHED_DOMAIN
+extern void __init arch_init_sched_domains(void);
+#else
+static struct sched_group sched_group_cpus[NR_CPUS];
+#ifdef CONFIG_NUMA
+static struct sched_group sched_group_nodes[MAX_NUMNODES];
+DEFINE_PER_CPU(struct sched_domain, node_domains);
+static void __init arch_init_sched_domains(void)
+{
+	int i;
+	struct sched_group *first_node = NULL, *last_node = NULL;
+
+	/* Set up domains */
+	for_each_cpu(i) {
+		int node = cpu_to_node(i);
+		cpumask_t nodemask = node_to_cpumask(node);
+		struct sched_domain *node_domain = &per_cpu(node_domains, i);
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+
+		*node_domain = SD_NODE_INIT;
+		node_domain->span = cpu_possible_map;
+
+		*cpu_domain = SD_CPU_INIT;
+		cpus_and(cpu_domain->span, nodemask, cpu_possible_map);
+		cpu_domain->parent = node_domain;
+	}
+
+	/* Set up groups */
+	for (i = 0; i < MAX_NUMNODES; i++) {
+		struct sched_group *first_cpu = NULL, *last_cpu = NULL;
+		int j;
+		cpumask_t nodemask;
+		struct sched_group *node = &sched_group_nodes[i];
+		cpumask_t tmp = node_to_cpumask(i);
+
+		cpus_and(nodemask, tmp, cpu_possible_map);
+
+		if (cpus_empty(nodemask))
+			continue;
+
+		node->cpumask = nodemask;
+		node->cpu_power = SCHED_LOAD_SCALE * cpus_weight(node->cpumask);
+
+		for_each_cpu_mask(j, node->cpumask) {
+			struct sched_group *cpu = &sched_group_cpus[j];
+
+			cpus_clear(cpu->cpumask);
+			cpu_set(j, cpu->cpumask);
+			cpu->cpu_power = SCHED_LOAD_SCALE;
+
+			if (!first_cpu)
+				first_cpu = cpu;
+			if (last_cpu)
+				last_cpu->next = cpu;
+			last_cpu = cpu;
+		}
+		last_cpu->next = first_cpu;
+
+		if (!first_node)
+			first_node = node;
+		if (last_node)
+			last_node->next = node;
+		last_node = node;
+	}
+	last_node->next = first_node;
+
+	mb();
+	for_each_cpu(i) {
+		struct sched_domain *node_domain = &per_cpu(node_domains, i);
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+		node_domain->groups = &sched_group_nodes[cpu_to_node(i)];
+		cpu_domain->groups = &sched_group_cpus[i];
+	}
+}
+
+#else /* CONFIG_NUMA */
+static void __init arch_init_sched_domains(void)
+{
+	int i;
+	struct sched_group *first_cpu = NULL, *last_cpu = NULL;
+
+	/* Set up domains */
+	for_each_cpu(i) {
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+
+		*cpu_domain = SD_CPU_INIT;
+		cpu_domain->span = cpu_possible_map;
+	}
+
+	/* Set up CPU groups */
+	for_each_cpu_mask(i, cpu_possible_map) {
+		struct sched_group *cpu = &sched_group_cpus[i];
+
+		cpus_clear(cpu->cpumask);
+		cpu_set(i, cpu->cpumask);
+		cpu->cpu_power = SCHED_LOAD_SCALE;
+
+		if (!first_cpu)
+			first_cpu = cpu;
+		if (last_cpu)
+			last_cpu->next = cpu;
+		last_cpu = cpu;
+	}
+	last_cpu->next = first_cpu;
+
+	mb();
+	for_each_cpu(i) {
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+		cpu_domain->groups = &sched_group_cpus[i];
+	}
+}
+
+#endif /* CONFIG_NUMA */
+#endif /* ARCH_HAS_SCHED_DOMAIN */
+
+#undef SCHED_DOMAIN_DEBUG
+#ifdef SCHED_DOMAIN_DEBUG
+void sched_domain_debug(void)
+{
+	int i;
+
+	for_each_cpu(i) {
+		int level = 0;
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+
+		printk(KERN_DEBUG "CPU%d: %s\n",
+				i, (cpu_online(i) ? " online" : "offline"));
+
+		do {
+			int j;
+			char str[NR_CPUS];
+			struct sched_group *group = cpu_domain->groups;
+			cpumask_t groupmask, tmp;
+
+			cpumask_snprintf(str, NR_CPUS, cpu_domain->span);
+			cpus_clear(groupmask);
+
+			printk(KERN_DEBUG);
+			for (j = 0; j < level + 1; j++)
+				printk(" ");
+			printk("domain %d: span %s\n", level, str);
+
+			if (!cpu_isset(i, cpu_domain->span))
+				printk(KERN_DEBUG "ERROR domain->span does not contain CPU%d\n", i);
+			if (!cpu_isset(i, group->cpumask))
+				printk(KERN_DEBUG "ERROR domain->groups does not contain CPU%d\n", i);
+
+			printk(KERN_DEBUG);
+			for (j = 0; j < level + 2; j++)
+				printk(" ");
+			printk("groups:");
+			do {
+				if (group == NULL) {
+					printk(" ERROR: NULL");
+					break;
+				}
+
+				if (cpus_weight(group->cpumask) == 0)
+					printk(" ERROR empty group:");
+
+				cpus_and(tmp, groupmask, group->cpumask);
+				if (cpus_weight(tmp) > 0)
+					printk(" ERROR repeated CPUs:");
+
+				cpus_or(groupmask, groupmask, group->cpumask);
+
+				cpumask_snprintf(str, NR_CPUS, group->cpumask);
+				printk(" %s", str);
+
+				group = group->next;
+			} while (group != cpu_domain->groups);
+			printk("\n");
+
+			if (!cpus_equal(cpu_domain->span, groupmask))
+				printk(KERN_DEBUG "ERROR groups don't span domain->span\n");
+
+			level++;
+			cpu_domain = cpu_domain->parent;
+
+			if (cpu_domain) {
+				cpus_and(tmp, groupmask, cpu_domain->span);
+				if (!cpus_equal(tmp, groupmask))
+					printk(KERN_DEBUG "ERROR parent span is not a superset of domain->span\n");
+			}
+
+		} while (cpu_domain);
+	}
+}
+#else
+#define sched_domain_debug() {}
+#endif
+
+void __init sched_init_smp(void)
+{
+	arch_init_sched_domains();
+	sched_domain_debug();
+}
+#else
+void __init sched_init_smp(void)
+{
+}
+#endif /* CONFIG_SMP */
+
 void __init sched_init(void)
 {
 	runqueue_t *rq;
@@ -2866,8 +3616,14 @@ void __init sched_init(void)
 
 	for (i = 0; i < NR_CPUS; i++) {
 		prio_array_t *array;
+#ifdef CONFIG_SMP
+		struct sched_domain *domain;
+		domain = cpu_sched_domain(i);
+		memset(domain, 0, sizeof(struct sched_domain));
+#endif
 
 		rq = cpu_rq(i);
+		rq->cpu = i;
 		rq->active = rq->arrays;
 		rq->expired = rq->arrays + 1;
 		rq->best_expired_prio = MAX_PRIO;
@@ -2875,7 +3631,6 @@ void __init sched_init(void)
 		spin_lock_init(&rq->lock);
 		INIT_LIST_HEAD(&rq->migration_queue);
 		atomic_set(&rq->nr_iowait, 0);
-		nr_running_init(rq);
 
 		for (j = 0; j < 2; j++) {
 			array = rq->arrays + j;
--- diff/kernel/signal.c	2004-03-04 11:41:49.000000000 +0000
+++ source/kernel/signal.c	2004-03-09 11:51:51.000000000 +0000
@@ -21,6 +21,7 @@
 #include <linux/binfmts.h>
 #include <linux/security.h>
 #include <linux/ptrace.h>
+#include <linux/compat_siginfo.h>
 #include <asm/param.h>
 #include <asm/uaccess.h>
 #include <asm/siginfo.h>
@@ -213,7 +214,7 @@ static inline int has_pending_signals(si
 
 #define PENDING(p,b) has_pending_signals(&(p)->signal, (b))
 
-inline void recalc_sigpending_tsk(struct task_struct *t)
+fastcall void recalc_sigpending_tsk(struct task_struct *t)
 {
 	if (t->signal->group_stop_count > 0 ||
 	    PENDING(&t->pending, &t->blocked) ||
@@ -2003,6 +2004,12 @@ int copy_siginfo_to_user(siginfo_t __use
 	if (from->si_code < 0)
 		return __copy_to_user(to, from, sizeof(siginfo_t))
 			? -EFAULT : 0;
+
+	/* Use compat_siginfo_t with 32-bit signals */
+	if(is_compat_task(current)){
+		return compat_copy_siginfo_to_user((compat_siginfo_t __user *)to,from);
+	}
+
 	/*
 	 * If you change siginfo_t structure, please be sure
 	 * this code is fixed accordingly.
@@ -2041,6 +2048,7 @@ int copy_siginfo_to_user(siginfo_t __use
 		err |= __put_user(from->si_stime, &to->si_stime);
 		break;
 	case __SI_RT: /* This is not generated by the kernel as of now. */
+	case __SI_MESGQ: /* But this is */
 		err |= __put_user(from->si_pid, &to->si_pid);
 		err |= __put_user(from->si_uid, &to->si_uid);
 		err |= __put_user(from->si_int, &to->si_int);
--- diff/kernel/softirq.c	2004-03-04 11:41:49.000000000 +0000
+++ source/kernel/softirq.c	2004-03-09 11:51:51.000000000 +0000
@@ -16,6 +16,7 @@
 #include <linux/cpu.h>
 #include <linux/kthread.h>
 
+#include <asm/irq.h>
 /*
    - No shared variables, all the data are CPU local.
    - If a softirq needs serialization, let it serialize itself
@@ -69,60 +70,84 @@ static inline void wakeup_softirqd(void)
  */
 #define MAX_SOFTIRQ_RESTART 10
 
-asmlinkage void do_softirq(void)
+asmlinkage void __do_softirq(void)
 {
-	int max_restart = MAX_SOFTIRQ_RESTART;
+	struct softirq_action *h;
 	__u32 pending;
-	unsigned long flags;
+	int max_restart = MAX_SOFTIRQ_RESTART;
 
-	if (in_interrupt())
-		return;
+	pending = local_softirq_pending();
 
-	local_irq_save(flags);
+	local_bh_disable();
+restart:
+	/* Reset the pending bitmask before enabling irqs */
+	local_softirq_pending() = 0;
+
+	local_irq_enable();
+
+	h = softirq_vec;
+
+	do {
+		if (pending & 1)
+			h->action(h);
+		h++;
+		pending >>= 1;
+	} while (pending);
+
+	local_irq_disable();
 
 	pending = local_softirq_pending();
+	if (pending && --max_restart)
+		goto restart;
 
-	if (pending) {
-		struct softirq_action *h;
+	if (pending)
+		wakeup_softirqd();
 
-		local_bh_disable();
-restart:
-		/* Reset the pending bitmask before enabling irqs */
-		local_softirq_pending() = 0;
+	__local_bh_enable();
+}
 
-		local_irq_enable();
+#ifndef __ARCH_HAS_DO_SOFTIRQ
 
-		h = softirq_vec;
+asmlinkage void do_softirq(void)
+{
+	__u32 pending;
+	unsigned long flags;
 
-		do {
-			if (pending & 1)
-				h->action(h);
-			h++;
-			pending >>= 1;
-		} while (pending);
+	if (in_interrupt())
+		return;
 
-		local_irq_disable();
+	local_irq_save(flags);
 
-		pending = local_softirq_pending();
-		if (pending && --max_restart)
-			goto restart;
-		if (pending)
-			wakeup_softirqd();
-		__local_bh_enable();
-	}
+	pending = local_softirq_pending();
+
+	if (pending)
+		__do_softirq();
 
 	local_irq_restore(flags);
 }
 
 EXPORT_SYMBOL(do_softirq);
 
+#endif
+
 void local_bh_enable(void)
 {
+	if (in_irq()) {
+		printk("local_bh_enable() was called in hard irq context.   "
+			"This is probably a bug\n");
+		dump_stack();
+	}
+
 	__local_bh_enable();
-	WARN_ON(irqs_disabled());
-	if (unlikely(!in_interrupt() &&
-		     local_softirq_pending()))
+	if (unlikely(!in_interrupt() && local_softirq_pending())) {
+		if (irqs_disabled()) {
+			printk("local_bh_enable() was called with local "
+				"interrupts disabled.  This is probably a"
+				" bug\n");
+			dump_stack();
+		}
 		invoke_softirq();
+	}
 	preempt_check_resched();
 }
 EXPORT_SYMBOL(local_bh_enable);
@@ -130,7 +155,7 @@ EXPORT_SYMBOL(local_bh_enable);
 /*
  * This function must run with irqs disabled!
  */
-inline void raise_softirq_irqoff(unsigned int nr)
+inline fastcall void raise_softirq_irqoff(unsigned int nr)
 {
 	__raise_softirq_irqoff(nr);
 
@@ -149,7 +174,7 @@ inline void raise_softirq_irqoff(unsigne
 
 EXPORT_SYMBOL(raise_softirq_irqoff);
 
-void raise_softirq(unsigned int nr)
+void fastcall raise_softirq(unsigned int nr)
 {
 	unsigned long flags;
 
@@ -179,7 +204,7 @@ struct tasklet_head
 static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec) = { NULL };
 static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec) = { NULL };
 
-void __tasklet_schedule(struct tasklet_struct *t)
+void fastcall __tasklet_schedule(struct tasklet_struct *t)
 {
 	unsigned long flags;
 
@@ -192,7 +217,7 @@ void __tasklet_schedule(struct tasklet_s
 
 EXPORT_SYMBOL(__tasklet_schedule);
 
-void __tasklet_hi_schedule(struct tasklet_struct *t)
+void fastcall __tasklet_hi_schedule(struct tasklet_struct *t)
 {
 	unsigned long flags;
 
@@ -308,13 +333,9 @@ void __init softirq_init(void)
 
 static int ksoftirqd(void * __bind_cpu)
 {
-	int cpu = (int) (long) __bind_cpu;
-
 	set_user_nice(current, 19);
 	current->flags |= PF_IOTHREAD;
 
-	BUG_ON(smp_processor_id() != cpu);
-
 	set_current_state(TASK_INTERRUPTIBLE);
 
 	while (!kthread_should_stop()) {
@@ -324,15 +345,83 @@ static int ksoftirqd(void * __bind_cpu)
 		__set_current_state(TASK_RUNNING);
 
 		while (local_softirq_pending()) {
+			/* Preempt disable stops cpu going offline.
+			   If already offline, we'll be on wrong CPU:
+			   don't process */
+			preempt_disable();
+			if (cpu_is_offline((long)__bind_cpu))
+				goto wait_to_die;
 			do_softirq();
+			preempt_enable();
 			cond_resched();
 		}
 
 		__set_current_state(TASK_INTERRUPTIBLE);
 	}
 	return 0;
+
+wait_to_die:
+	preempt_enable();
+	/* Wait for kthread_stop */
+	while (!kthread_should_stop()) {
+		__set_current_state(TASK_INTERRUPTIBLE);
+		schedule();
+	}
+	return 0;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * tasklet_kill_immediate is called to remove a tasklet which can already be
+ * scheduled for execution on @cpu.
+ *
+ * Unlike tasklet_kill, this function removes the tasklet
+ * _immediately_, even if the tasklet is in TASKLET_STATE_SCHED state.
+ *
+ * When this function is called, @cpu must be in the CPU_DEAD state.
+ */
+void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu)
+{
+	struct tasklet_struct **i;
+
+	BUG_ON(cpu_online(cpu));
+	BUG_ON(test_bit(TASKLET_STATE_RUN, &t->state));
+
+	if (!test_bit(TASKLET_STATE_SCHED, &t->state))
+		return;
+
+	/* CPU is dead, so no lock needed. */
+	for (i = &per_cpu(tasklet_vec, cpu).list; *i; i = &(*i)->next) {
+		if (*i == t) {
+			*i = t->next;
+			return;
+		}
+	}
+	BUG();
 }
 
+static void takeover_tasklets(unsigned int cpu)
+{
+	struct tasklet_struct **i;
+
+	/* CPU is dead, so no lock needed. */
+	local_irq_disable();
+
+	/* Find end, append list for that CPU. */
+	for (i = &__get_cpu_var(tasklet_vec).list; *i; i = &(*i)->next);
+	*i = per_cpu(tasklet_vec, cpu).list;
+	per_cpu(tasklet_vec, cpu).list = NULL;
+	raise_softirq_irqoff(TASKLET_SOFTIRQ);
+
+	for (i = &__get_cpu_var(tasklet_hi_vec).list; *i; i = &(*i)->next);
+	*i = per_cpu(tasklet_hi_vec, cpu).list;
+	per_cpu(tasklet_hi_vec, cpu).list = NULL;
+	raise_softirq_irqoff(HI_SOFTIRQ);
+
+	local_irq_enable();
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 static int __devinit cpu_callback(struct notifier_block *nfb,
 				  unsigned long action,
 				  void *hcpu)
@@ -349,13 +438,23 @@ static int __devinit cpu_callback(struct
 			printk("ksoftirqd for %i failed\n", hotcpu);
 			return NOTIFY_BAD;
 		}
-		per_cpu(ksoftirqd, hotcpu) = p;
 		kthread_bind(p, hotcpu);
   		per_cpu(ksoftirqd, hotcpu) = p;
  		break;
 	case CPU_ONLINE:
 		wake_up_process(per_cpu(ksoftirqd, hotcpu));
 		break;
+#ifdef CONFIG_HOTPLUG_CPU
+	case CPU_UP_CANCELED:
+		/* Unbind so it can run.  Fall thru. */
+		kthread_bind(per_cpu(ksoftirqd, hotcpu), smp_processor_id());
+	case CPU_DEAD:
+		p = per_cpu(ksoftirqd, hotcpu);
+		per_cpu(ksoftirqd, hotcpu) = NULL;
+		kthread_stop(p);
+		takeover_tasklets(hotcpu);
+		break;
+#endif /* CONFIG_HOTPLUG_CPU */
  	}
 	return NOTIFY_OK;
 }
--- diff/kernel/sys.c	2004-03-04 11:41:49.000000000 +0000
+++ source/kernel/sys.c	2004-03-09 11:51:51.000000000 +0000
@@ -260,6 +260,12 @@ cond_syscall(sys_msgctl)
 cond_syscall(sys_shmget)
 cond_syscall(sys_shmdt)
 cond_syscall(sys_shmctl)
+cond_syscall(sys_mq_open)
+cond_syscall(sys_mq_unlink)
+cond_syscall(sys_mq_timedsend)
+cond_syscall(sys_mq_timedreceive)
+cond_syscall(sys_mq_notify)
+cond_syscall(sys_mq_getsetattr)
 
 /* arch-specific weak syscall entries */
 cond_syscall(sys_pciconfig_read)
--- diff/kernel/sysctl.c	2004-03-04 11:41:49.000000000 +0000
+++ source/kernel/sysctl.c	2004-03-09 11:51:51.000000000 +0000
@@ -736,6 +736,26 @@ static ctl_table vm_table[] = {
 		.strategy	= &sysctl_intvec,
 		.extra1		= &zero,
 	},
+	{
+		.ctl_name	= VM_LAPTOP_MODE,
+		.procname	= "laptop_mode",
+		.data		= &laptop_mode,
+		.maxlen		= sizeof(laptop_mode),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+		.strategy	= &sysctl_intvec,
+		.extra1		= &zero,
+	},
+	{
+		.ctl_name	= VM_BLOCK_DUMP,
+		.procname	= "block_dump",
+		.data		= &block_dump,
+		.maxlen		= sizeof(block_dump),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+		.strategy	= &sysctl_intvec,
+		.extra1		= &zero,
+	},
 	{ .ctl_name = 0 }
 };
 
--- diff/kernel/timer.c	2004-03-04 11:41:49.000000000 +0000
+++ source/kernel/timer.c	2004-03-09 11:51:52.000000000 +0000
@@ -677,7 +677,6 @@ static void update_wall_time(unsigned lo
 	if (xtime.tv_nsec >= 1000000000) {
 	    xtime.tv_nsec -= 1000000000;
 	    xtime.tv_sec++;
-	    time_interpolator_update(NSEC_PER_SEC);
 	    second_overflow();
 	}
 }
@@ -971,6 +970,13 @@ static void process_timeout(unsigned lon
 	wake_up_process((task_t *)__data);
 }
 
+static void futex_timeout(unsigned long __data)
+{
+	current->flags |= PF_FUTEX_DEBUG;
+	wake_up_process((task_t *)__data);
+	current->flags &= ~PF_FUTEX_DEBUG;
+}
+
 /**
  * schedule_timeout - sleep until timeout
  * @timeout: timeout value in jiffies
@@ -997,7 +1003,7 @@ static void process_timeout(unsigned lon
  *
  * In all cases the return value is guaranteed to be non-negative.
  */
-signed long schedule_timeout(signed long timeout)
+fastcall signed long schedule_timeout(signed long timeout)
 {
 	struct timer_list timer;
 	unsigned long expire;
@@ -1037,7 +1043,10 @@ signed long schedule_timeout(signed long
 	init_timer(&timer);
 	timer.expires = expire;
 	timer.data = (unsigned long) current;
-	timer.function = process_timeout;
+	if (current->flags & PF_FUTEX_DEBUG)
+		timer.function = futex_timeout;
+	else
+		timer.function = process_timeout;
 
 	add_timer(&timer);
 	schedule();
@@ -1223,7 +1232,73 @@ static void __devinit init_timers_cpu(in
 
 	base->timer_jiffies = jiffies;
 }
-	
+
+#ifdef CONFIG_HOTPLUG_CPU
+static int migrate_timer_list(tvec_base_t *new_base, struct list_head *head)
+{
+	struct timer_list *timer;
+
+	while (!list_empty(head)) {
+		timer = list_entry(head->next, struct timer_list, entry);
+		/* We're locking backwards from __mod_timer order here,
+		   beware deadlock. */
+		if (!spin_trylock(&timer->lock))
+			return 0;
+		list_del(&timer->entry);
+		internal_add_timer(new_base, timer);
+		timer->base = new_base;
+		spin_unlock(&timer->lock);
+	}
+	return 1;
+}
+
+static void __devinit migrate_timers(int cpu)
+{
+	tvec_base_t *old_base;
+	tvec_base_t *new_base;
+	int i;
+
+	BUG_ON(cpu_online(cpu));
+	old_base = &per_cpu(tvec_bases, cpu);
+	new_base = &get_cpu_var(tvec_bases);
+
+	local_irq_disable();
+again:
+	/* Prevent deadlocks via ordering by old_base < new_base. */
+	if (old_base < new_base) {
+		spin_lock(&new_base->lock);
+		spin_lock(&old_base->lock);
+	} else {
+		spin_lock(&old_base->lock);
+		spin_lock(&new_base->lock);
+	}
+
+	if (old_base->running_timer)
+		BUG();
+	for (i = 0; i < TVR_SIZE; i++)
+		if (!migrate_timer_list(new_base, old_base->tv1.vec + i))
+			goto unlock_again;
+	for (i = 0; i < TVN_SIZE; i++)
+		if (!migrate_timer_list(new_base, old_base->tv2.vec + i)
+		    || !migrate_timer_list(new_base, old_base->tv3.vec + i)
+		    || !migrate_timer_list(new_base, old_base->tv4.vec + i)
+		    || !migrate_timer_list(new_base, old_base->tv5.vec + i))
+			goto unlock_again;
+	spin_unlock(&old_base->lock);
+	spin_unlock(&new_base->lock);
+	local_irq_enable();
+	put_cpu_var(tvec_bases);
+	return;
+
+unlock_again:
+	/* Avoid deadlock with __mod_timer, by backing off. */
+	spin_unlock(&old_base->lock);
+	spin_unlock(&new_base->lock);
+	cpu_relax();
+	goto again;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 static int __devinit timer_cpu_notify(struct notifier_block *self, 
 				unsigned long action, void *hcpu)
 {
@@ -1232,6 +1307,11 @@ static int __devinit timer_cpu_notify(st
 	case CPU_UP_PREPARE:
 		init_timers_cpu(cpu);
 		break;
+#ifdef CONFIG_HOTPLUG_CPU
+	case CPU_DEAD:
+		migrate_timers(cpu);
+		break;
+#endif
 	default:
 		break;
 	}
--- diff/kernel/workqueue.c	2004-03-04 11:41:49.000000000 +0000
+++ source/kernel/workqueue.c	2004-03-09 11:51:52.000000000 +0000
@@ -22,6 +22,8 @@
 #include <linux/completion.h>
 #include <linux/workqueue.h>
 #include <linux/slab.h>
+#include <linux/cpu.h>
+#include <linux/notifier.h>
 #include <linux/kthread.h>
 
 /*
@@ -55,8 +57,22 @@ struct cpu_workqueue_struct {
  */
 struct workqueue_struct {
 	struct cpu_workqueue_struct cpu_wq[NR_CPUS];
+	const char *name;
+	struct list_head list;
 };
 
+#ifdef CONFIG_HOTPLUG_CPU
+/* All the workqueues on the system, for hotplug cpu to add/remove
+   threads to each one as cpus come/go.  Protected by cpucontrol
+   sem. */
+static LIST_HEAD(workqueues);
+#define add_workqueue(wq) list_add(&(wq)->list, &workqueues)
+#define del_workqueue(wq) list_del(&(wq)->list)
+#else
+#define add_workqueue(wq)
+#define del_workqueue(wq)
+#endif /* CONFIG_HOTPLUG_CPU */
+
 /* Preempt must be disabled. */
 static void __queue_work(struct cpu_workqueue_struct *cwq,
 			 struct work_struct *work)
@@ -78,18 +94,29 @@ static void __queue_work(struct cpu_work
  * We queue the work to the CPU it was submitted, but there is no
  * guarantee that it will be processed by that CPU.
  */
-int queue_work(struct workqueue_struct *wq, struct work_struct *work)
+int queue_work_on_cpu(struct workqueue_struct *wq,
+			struct work_struct *work, int cpu)
 {
-	int ret = 0, cpu = get_cpu();
+	int ret = 0;
 
 	if (!test_and_set_bit(0, &work->pending)) {
 		BUG_ON(!list_empty(&work->entry));
 		__queue_work(wq->cpu_wq + cpu, work);
 		ret = 1;
 	}
+	return ret;
+}
+EXPORT_SYMBOL_GPL(queue_work);
+
+int queue_work(struct workqueue_struct *wq, struct work_struct *work)
+{
+	int ret;
+
+	ret = queue_work_on_cpu(wq, work, get_cpu());
 	put_cpu();
 	return ret;
 }
+EXPORT_SYMBOL_GPL(queue_work_on_cpu);
 
 static void delayed_work_timer_fn(unsigned long __data)
 {
@@ -99,7 +126,7 @@ static void delayed_work_timer_fn(unsign
 	__queue_work(wq->cpu_wq + smp_processor_id(), work);
 }
 
-int queue_delayed_work(struct workqueue_struct *wq,
+int fastcall queue_delayed_work(struct workqueue_struct *wq,
 			struct work_struct *work, unsigned long delay)
 {
 	int ret = 0;
@@ -152,7 +179,6 @@ static inline void run_workqueue(struct 
 static int worker_thread(void *__cwq)
 {
 	struct cpu_workqueue_struct *cwq = __cwq;
-	int cpu = cwq - cwq->wq->cpu_wq;
 	DECLARE_WAITQUEUE(wait, current);
 	struct k_sigaction sa;
 	sigset_t blocked;
@@ -160,7 +186,6 @@ static int worker_thread(void *__cwq)
 	current->flags |= PF_IOTHREAD;
 
 	set_user_nice(current, -10);
-	BUG_ON(smp_processor_id() != cpu);
 
 	/* Block and flush all signals */
 	sigfillset(&blocked);
@@ -203,13 +228,14 @@ static int worker_thread(void *__cwq)
  * This function used to run the workqueues itself.  Now we just wait for the
  * helper threads to do it.
  */
-void flush_workqueue(struct workqueue_struct *wq)
+void fastcall flush_workqueue(struct workqueue_struct *wq)
 {
 	struct cpu_workqueue_struct *cwq;
 	int cpu;
 
 	might_sleep();
 
+	lock_cpu_hotplug();
 	for (cpu = 0; cpu < NR_CPUS; cpu++) {
 		DEFINE_WAIT(wait);
 		long sequence_needed;
@@ -231,11 +257,10 @@ void flush_workqueue(struct workqueue_st
 		finish_wait(&cwq->work_done, &wait);
 		spin_unlock_irq(&cwq->lock);
 	}
+	unlock_cpu_hotplug();
 }
 
-static int create_workqueue_thread(struct workqueue_struct *wq,
-				   const char *name,
-				   int cpu)
+static int create_workqueue_thread(struct workqueue_struct *wq, int cpu)
 {
 	struct cpu_workqueue_struct *cwq = wq->cpu_wq + cpu;
 	struct task_struct *p;
@@ -249,7 +274,7 @@ static int create_workqueue_thread(struc
 	init_waitqueue_head(&cwq->more_work);
 	init_waitqueue_head(&cwq->work_done);
 
-	p = kthread_create(worker_thread, cwq, "%s/%d", name, cpu);
+	p = kthread_create(worker_thread, cwq, "%s/%d", wq->name, cpu);
 	if (IS_ERR(p))
 		return PTR_ERR(p);
 	cwq->thread = p;
@@ -268,14 +293,19 @@ struct workqueue_struct *create_workqueu
 	if (!wq)
 		return NULL;
 
+	wq->name = name;
+	/* We don't need the distraction of CPUs appearing and vanishing. */
+	lock_cpu_hotplug();
 	for (cpu = 0; cpu < NR_CPUS; cpu++) {
 		if (!cpu_online(cpu))
 			continue;
-		if (create_workqueue_thread(wq, name, cpu) < 0)
+		if (create_workqueue_thread(wq, cpu) < 0)
 			destroy = 1;
 		else
 			wake_up_process(wq->cpu_wq[cpu].thread);
 	}
+	add_workqueue(wq);
+
 	/*
 	 * Was there any error during startup? If yes then clean up:
 	 */
@@ -283,16 +313,23 @@ struct workqueue_struct *create_workqueu
 		destroy_workqueue(wq);
 		wq = NULL;
 	}
+	unlock_cpu_hotplug();
 	return wq;
 }
 
 static void cleanup_workqueue_thread(struct workqueue_struct *wq, int cpu)
 {
 	struct cpu_workqueue_struct *cwq;
+	unsigned long flags;
+	struct task_struct *p;
 
 	cwq = wq->cpu_wq + cpu;
-	if (cwq->thread)
-		kthread_stop(cwq->thread);
+	spin_lock_irqsave(&cwq->lock, flags);
+	p = cwq->thread;
+	cwq->thread = NULL;
+	spin_unlock_irqrestore(&cwq->lock, flags);
+	if (p)
+		kthread_stop(p);
 }
 
 void destroy_workqueue(struct workqueue_struct *wq)
@@ -301,21 +338,25 @@ void destroy_workqueue(struct workqueue_
 
 	flush_workqueue(wq);
 
+	/* We don't need the distraction of CPUs appearing and vanishing. */
+	lock_cpu_hotplug();
 	for (cpu = 0; cpu < NR_CPUS; cpu++) {
 		if (cpu_online(cpu))
 			cleanup_workqueue_thread(wq, cpu);
 	}
+	del_workqueue(wq);
+	unlock_cpu_hotplug();
 	kfree(wq);
 }
 
 static struct workqueue_struct *keventd_wq;
 
-int schedule_work(struct work_struct *work)
+int fastcall schedule_work(struct work_struct *work)
 {
 	return queue_work(keventd_wq, work);
 }
 
-int schedule_delayed_work(struct work_struct *work, unsigned long delay)
+int fastcall schedule_delayed_work(struct work_struct *work, unsigned long delay)
 {
 	return queue_delayed_work(keventd_wq, work, delay);
 }
@@ -345,14 +386,80 @@ int current_is_keventd(void)
 	return 0;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+/* Take the work from this (downed) CPU. */
+static void take_over_work(struct workqueue_struct *wq, unsigned int cpu)
+{
+	struct cpu_workqueue_struct *cwq = wq->cpu_wq + cpu;
+	LIST_HEAD(list);
+	struct work_struct *work;
+
+	spin_lock_irq(&cwq->lock);
+	list_splice_init(&cwq->worklist, &list);
+
+	while (!list_empty(&list)) {
+		printk("Taking work for %s\n", wq->name);
+		work = list_entry(list.next,struct work_struct,entry);
+		list_del(&work->entry);
+		__queue_work(wq->cpu_wq + smp_processor_id(), work);
+	}
+	spin_unlock_irq(&cwq->lock);
+}
+
+/* We're holding the cpucontrol mutex here */
+static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
+				  unsigned long action,
+				  void *hcpu)
+{
+	unsigned int hotcpu = (unsigned long)hcpu;
+	struct workqueue_struct *wq;
+
+	switch (action) {
+	case CPU_UP_PREPARE:
+		/* Create a new workqueue thread for it. */
+		list_for_each_entry(wq, &workqueues, list) {
+			if (create_workqueue_thread(wq, hotcpu) < 0) {
+				printk("workqueue for %i failed\n", hotcpu);
+				return NOTIFY_BAD;
+			}
+		}
+		break;
+
+	case CPU_ONLINE:
+		/* Kick off worker threads. */
+		list_for_each_entry(wq, &workqueues, list)
+			wake_up_process(wq->cpu_wq[hotcpu].thread);
+		break;
+
+	case CPU_UP_CANCELED:
+		list_for_each_entry(wq, &workqueues, list) {
+			/* Unbind so it can run. */
+			kthread_bind(wq->cpu_wq[hotcpu].thread,
+				     smp_processor_id());
+			cleanup_workqueue_thread(wq, hotcpu);
+		}
+		break;
+
+	case CPU_DEAD:
+		list_for_each_entry(wq, &workqueues, list)
+			cleanup_workqueue_thread(wq, hotcpu);
+		list_for_each_entry(wq, &workqueues, list)
+			take_over_work(wq, hotcpu);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+#endif
+
 void init_workqueues(void)
 {
+	hotcpu_notifier(workqueue_cpu_callback, 0);
 	keventd_wq = create_workqueue("events");
 	BUG_ON(!keventd_wq);
 }
 
 EXPORT_SYMBOL_GPL(create_workqueue);
-EXPORT_SYMBOL_GPL(queue_work);
 EXPORT_SYMBOL_GPL(queue_delayed_work);
 EXPORT_SYMBOL_GPL(flush_workqueue);
 EXPORT_SYMBOL_GPL(destroy_workqueue);
--- diff/lib/rwsem-spinlock.c	2002-11-11 11:09:43.000000000 +0000
+++ source/lib/rwsem-spinlock.c	2004-03-09 11:51:52.000000000 +0000
@@ -29,7 +29,7 @@ void rwsemtrace(struct rw_semaphore *sem
 /*
  * initialise the semaphore
  */
-void init_rwsem(struct rw_semaphore *sem)
+void fastcall init_rwsem(struct rw_semaphore *sem)
 {
 	sem->activity = 0;
 	spin_lock_init(&sem->wait_lock);
@@ -117,7 +117,7 @@ static inline struct rw_semaphore *__rws
 /*
  * get a read lock on the semaphore
  */
-void __down_read(struct rw_semaphore *sem)
+void fastcall __down_read(struct rw_semaphore *sem)
 {
 	struct rwsem_waiter waiter;
 	struct task_struct *tsk;
@@ -162,7 +162,7 @@ void __down_read(struct rw_semaphore *se
 /*
  * trylock for reading -- returns 1 if successful, 0 if contention
  */
-int __down_read_trylock(struct rw_semaphore *sem)
+int fastcall __down_read_trylock(struct rw_semaphore *sem)
 {
 	int ret = 0;
 	rwsemtrace(sem,"Entering __down_read_trylock");
@@ -185,7 +185,7 @@ int __down_read_trylock(struct rw_semaph
  * get a write lock on the semaphore
  * - note that we increment the waiting count anyway to indicate an exclusive lock
  */
-void __down_write(struct rw_semaphore *sem)
+void fastcall __down_write(struct rw_semaphore *sem)
 {
 	struct rwsem_waiter waiter;
 	struct task_struct *tsk;
@@ -230,7 +230,7 @@ void __down_write(struct rw_semaphore *s
 /*
  * trylock for writing -- returns 1 if successful, 0 if contention
  */
-int __down_write_trylock(struct rw_semaphore *sem)
+int fastcall __down_write_trylock(struct rw_semaphore *sem)
 {
 	int ret = 0;
 	rwsemtrace(sem,"Entering __down_write_trylock");
@@ -252,7 +252,7 @@ int __down_write_trylock(struct rw_semap
 /*
  * release a read lock on the semaphore
  */
-void __up_read(struct rw_semaphore *sem)
+void fastcall __up_read(struct rw_semaphore *sem)
 {
 	rwsemtrace(sem,"Entering __up_read");
 
@@ -269,7 +269,7 @@ void __up_read(struct rw_semaphore *sem)
 /*
  * release a write lock on the semaphore
  */
-void __up_write(struct rw_semaphore *sem)
+void fastcall __up_write(struct rw_semaphore *sem)
 {
 	rwsemtrace(sem,"Entering __up_write");
 
@@ -288,7 +288,7 @@ void __up_write(struct rw_semaphore *sem
  * downgrade a write lock into a read lock
  * - just wake up any readers at the front of the queue
  */
-void __downgrade_write(struct rw_semaphore *sem)
+void fastcall __downgrade_write(struct rw_semaphore *sem)
 {
 	rwsemtrace(sem,"Entering __downgrade_write");
 
--- diff/lib/rwsem.c	2002-10-16 04:27:09.000000000 +0100
+++ source/lib/rwsem.c	2004-03-09 11:51:52.000000000 +0000
@@ -162,7 +162,7 @@ static inline struct rw_semaphore *rwsem
 /*
  * wait for the read lock to be granted
  */
-struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem)
+struct rw_semaphore fastcall *rwsem_down_read_failed(struct rw_semaphore *sem)
 {
 	struct rwsem_waiter waiter;
 
@@ -178,7 +178,7 @@ struct rw_semaphore *rwsem_down_read_fai
 /*
  * wait for the write lock to be granted
  */
-struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem)
+struct rw_semaphore fastcall *rwsem_down_write_failed(struct rw_semaphore *sem)
 {
 	struct rwsem_waiter waiter;
 
@@ -195,7 +195,7 @@ struct rw_semaphore *rwsem_down_write_fa
  * handle waking up a waiter on the semaphore
  * - up_read has decremented the active part of the count if we come here
  */
-struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem)
+struct rw_semaphore fastcall *rwsem_wake(struct rw_semaphore *sem)
 {
 	rwsemtrace(sem,"Entering rwsem_wake");
 
@@ -217,7 +217,7 @@ struct rw_semaphore *rwsem_wake(struct r
  * - caller incremented waiting part of count, and discovered it to be still negative
  * - just wake up any readers at the front of the queue
  */
-struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem)
+struct rw_semaphore fastcall *rwsem_downgrade_wake(struct rw_semaphore *sem)
 {
 	rwsemtrace(sem,"Entering rwsem_downgrade_wake");
 
--- diff/mm/Makefile	2003-10-09 09:47:17.000000000 +0100
+++ source/mm/Makefile	2004-03-09 11:51:52.000000000 +0000
@@ -12,3 +12,4 @@ obj-y			:= bootmem.o filemap.o mempool.o
 			   slab.o swap.o truncate.o vmscan.o $(mmu-y)
 
 obj-$(CONFIG_SWAP)	+= page_io.o swap_state.o swapfile.o
+obj-$(CONFIG_X86_4G)	+= usercopy.o
--- diff/mm/filemap.c	2004-02-18 08:54:13.000000000 +0000
+++ source/mm/filemap.c	2004-03-09 11:51:52.000000000 +0000
@@ -39,6 +39,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/mman.h>
+#include <asm/tlbflush.h>
 
 /*
  * Shared mappings implemented 30.11.1994. It's not fully working yet,
@@ -73,6 +74,9 @@
  *  ->mmap_sem
  *    ->i_sem			(msync)
  *
+ *  ->i_sem
+ *    ->i_alloc_sem             (various)
+ *
  *  ->inode_lock
  *    ->sb_lock			(fs/fs-writeback.c)
  *    ->mapping->page_lock	(__sync_single_inode)
@@ -125,6 +129,8 @@ static inline int sync_page(struct page 
 	return 0;
 }
 
+extern struct super_block *blockdev_superblock;
+
 /**
  * filemap_fdatawrite - start writeback against all of a mapping's dirty pages
  * @mapping: address space structure to write
@@ -141,14 +147,30 @@ static int __filemap_fdatawrite(struct a
 		.sync_mode = sync_mode,
 		.nr_to_write = mapping->nrpages * 2,
 	};
+	int blkdev = mapping->host->i_sb == blockdev_superblock;
 
 	if (mapping->backing_dev_info->memory_backed)
 		return 0;
 
+	if (!blkdev) {
+		if (sync_mode == WB_SYNC_NONE) {
+			if (!down_read_trylock(&mapping->wb_rwsema))
+				return 0;
+		} else
+			down_write(&mapping->wb_rwsema);
+	}
+
 	spin_lock(&mapping->page_lock);
 	list_splice_init(&mapping->dirty_pages, &mapping->io_pages);
 	spin_unlock(&mapping->page_lock);
 	ret = do_writepages(mapping, &wbc);
+
+	if (!blkdev) {
+		if (sync_mode == WB_SYNC_NONE)
+			up_read(&mapping->wb_rwsema);
+		else
+			up_write(&mapping->wb_rwsema);
+	}
 	return ret;
 }
 
@@ -161,12 +183,13 @@ EXPORT_SYMBOL(filemap_fdatawrite);
 
 /*
  * This is a mostly non-blocking flush.  Not suitable for data-integrity
- * purposes.
+ * purposes - I/O may not be started against all dirty pages.
  */
 int filemap_flush(struct address_space *mapping)
 {
 	return __filemap_fdatawrite(mapping, WB_SYNC_NONE);
 }
+EXPORT_SYMBOL(filemap_flush);
 
 /**
  * filemap_fdatawait - walk the list of locked pages of the given address
@@ -185,13 +208,24 @@ restart:
 		struct page *page;
 
 		page = list_entry(mapping->locked_pages.next,struct page,list);
-		list_del(&page->list);
-		if (PageDirty(page))
-			list_add(&page->list, &mapping->dirty_pages);
-		else
+		/*
+		 * Leave page on locked list until i/o has finished
+		 * so parallel filemap_fdatawait()s will all see the page.
+		 */
+
+		if (!PageDirty(page) && !PageLocked(page) &&
+		    !PageWriteback(page)) {
+
+			/*
+			 * The page is checked if locked because it might
+			 * be in process of being setup for writeback with
+			 * PG_dirty cleared and PG_writeback not set yet.
+			 * The page is not dirty and i/o has finished
+			 * so we can move it to the clean list.
+			 */
+			list_del(&page->list);
 			list_add(&page->list, &mapping->clean_pages);
 
-		if (!PageWriteback(page)) {
 			if (++progress > 32) {
 				if (need_resched()) {
 					spin_unlock(&mapping->page_lock);
@@ -206,10 +240,15 @@ restart:
 		page_cache_get(page);
 		spin_unlock(&mapping->page_lock);
 
-		wait_on_page_writeback(page);
-		if (PageError(page))
-			ret = -EIO;
-
+		lock_page(page);
+		if (PageDirty(page) && mapping->a_ops->writepage) {
+			write_one_page(page, 1);
+		} else {
+			wait_on_page_writeback(page);
+			unlock_page(page);
+		}
+ 		if (PageError(page))
+ 			ret = -EIO;
 		page_cache_release(page);
 		spin_lock(&mapping->page_lock);
 	}
@@ -226,6 +265,18 @@ restart:
 
 EXPORT_SYMBOL(filemap_fdatawait);
 
+int filemap_write_and_wait(struct address_space *mapping)
+{
+	int retval = 0;
+
+	if (mapping->nrpages) {
+		retval = filemap_fdatawrite(mapping);
+		if (retval == 0)
+			retval = filemap_fdatawait(mapping);
+	}
+	return retval;
+}
+
 /*
  * This adds a page to the page cache, starting out as locked, unreferenced,
  * not uptodate and with no errors.
@@ -292,7 +343,7 @@ static wait_queue_head_t *page_waitqueue
 	return &zone->wait_table[hash_ptr(page, zone->wait_table_bits)];
 }
 
-void wait_on_page_bit(struct page *page, int bit_nr)
+void fastcall wait_on_page_bit(struct page *page, int bit_nr)
 {
 	wait_queue_head_t *waitqueue = page_waitqueue(page);
 	DEFINE_WAIT(wait);
@@ -324,7 +375,7 @@ EXPORT_SYMBOL(wait_on_page_bit);
  * the clear_bit and the read of the waitqueue (to avoid SMP races with a
  * parallel wait_on_page_locked()).
  */
-void unlock_page(struct page *page)
+void fastcall unlock_page(struct page *page)
 {
 	wait_queue_head_t *waitqueue = page_waitqueue(page);
 	smp_mb__before_clear_bit();
@@ -365,7 +416,7 @@ EXPORT_SYMBOL(end_page_writeback);
  * chances are that on the second loop, the block layer's plug list is empty,
  * so sync_page() will then return in state TASK_UNINTERRUPTIBLE.
  */
-void __lock_page(struct page *page)
+void fastcall __lock_page(struct page *page)
 {
 	wait_queue_head_t *wqh = page_waitqueue(page);
 	DEFINE_WAIT(wait);
@@ -953,7 +1004,7 @@ asmlinkage ssize_t sys_readahead(int fd,
  * and schedules an I/O to read in its contents from disk.
  */
 static int FASTCALL(page_cache_read(struct file * file, unsigned long offset));
-static int page_cache_read(struct file * file, unsigned long offset)
+static int fastcall page_cache_read(struct file * file, unsigned long offset)
 {
 	struct address_space *mapping = file->f_mapping;
 	struct page *page; 
@@ -1198,8 +1249,13 @@ retry_find:
 	 * Ok, found a page in the page cache, now we need to check
 	 * that it's up-to-date.
 	 */
-	if (!PageUptodate(page))
+	if (!PageUptodate(page)) {
+		if (nonblock) {
+			page_cache_release(page);
+			return NULL;
+		}
 		goto page_not_uptodate;
+	}
 
 success:
 	/*
@@ -1292,12 +1348,22 @@ static int filemap_populate(struct vm_ar
 {
 	struct file *file = vma->vm_file;
 	struct address_space *mapping = file->f_mapping;
+	int linear = !(vma->vm_flags & VM_NONLINEAR);
 	struct inode *inode = mapping->host;
 	unsigned long size;
 	struct mm_struct *mm = vma->vm_mm;
 	struct page *page;
 	int err;
 
+	/*
+	 * mapping-removal fastpath:
+	 */
+	if ((vma->vm_flags & VM_SHARED) &&
+			(pgprot_val(prot) == pgprot_val(PAGE_NONE))) {
+		zap_page_range(vma, addr, len);
+		return 0;
+	}
+
 	if (!nonblock)
 		force_page_cache_readahead(mapping, vma->vm_file,
 					pgoff, len >> PAGE_CACHE_SHIFT);
@@ -1317,19 +1383,9 @@ repeat:
 			return err;
 		}
 	} else {
-	    	/*
-		 * If a nonlinear mapping then store the file page offset
-		 * in the pte.
-		 */
-	    	unsigned long pgidx;
-		pgidx = (addr - vma->vm_start) >> PAGE_SHIFT;
-		pgidx += vma->vm_pgoff;
-		pgidx >>= PAGE_CACHE_SHIFT - PAGE_SHIFT;
-		if (pgoff != pgidx) {
-	    		err = install_file_pte(mm, vma, addr, pgoff, prot);
-			if (err)
-		    		return err;
-		}
+    		err = install_file_pte(mm, vma, addr, pgoff, prot, linear);
+		if (err)
+	    		return err;
 	}
 
 	len -= PAGE_SIZE;
@@ -1713,6 +1769,7 @@ EXPORT_SYMBOL(generic_write_checks);
 
 /*
  * Write to a file through the page cache. 
+ * Called under i_sem for S_ISREG files.
  *
  * We put everything into the page cache prior to writing it. This is not a
  * problem when writing full pages. With partial pages, however, we first have
@@ -1801,12 +1858,21 @@ generic_file_aio_write_nolock(struct kio
 		/*
 		 * Sync the fs metadata but not the minor inode changes and
 		 * of course not the data as we did direct DMA for the IO.
+		 * i_sem is held, which protects generic_osync_inode() from
+		 * livelocking.
 		 */
 		if (written >= 0 && file->f_flags & O_SYNC)
 			status = generic_osync_inode(inode, mapping, OSYNC_METADATA);
-		if (written >= 0 && !is_sync_kiocb(iocb))
+		if (written == count && !is_sync_kiocb(iocb))
 			written = -EIOCBQUEUED;
-		goto out_status;
+		if (written < 0 || written == count)
+			goto out_status;
+		/*
+		 * direct-io write to a hole: fall through to buffered I/O
+		 * for completing the rest of the request.
+		 */
+		pos += written;
+		count -= written;
 	}
 
 	buf = iov->iov_base;
@@ -1895,6 +1961,14 @@ generic_file_aio_write_nolock(struct kio
 					OSYNC_METADATA|OSYNC_DATA);
 	}
 	
+	/*
+	 * If we get here for O_DIRECT writes then we must have fallen through
+	 * to buffered writes (block instantiation inside i_size).  So we sync
+	 * the file data here, to try to honour O_DIRECT expectations.
+	 */
+	if (unlikely(file->f_flags & O_DIRECT) && written)
+		status = filemap_write_and_wait(mapping);
+
 out_status:	
 	err = written ? written : status;
 out:
@@ -1986,6 +2060,9 @@ ssize_t generic_file_writev(struct file 
 
 EXPORT_SYMBOL(generic_file_writev);
 
+/*
+ * Called under i_sem for writes to S_ISREG files
+ */
 ssize_t
 generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
 	loff_t offset, unsigned long nr_segs)
@@ -1994,18 +2071,13 @@ generic_file_direct_IO(int rw, struct ki
 	struct address_space *mapping = file->f_mapping;
 	ssize_t retval;
 
-	if (mapping->nrpages) {
-		retval = filemap_fdatawrite(mapping);
-		if (retval == 0)
-			retval = filemap_fdatawait(mapping);
-		if (retval)
-			goto out;
+	retval = filemap_write_and_wait(mapping);
+	if (retval == 0) {
+		retval = mapping->a_ops->direct_IO(rw, iocb, iov,
+						offset, nr_segs);
+		if (rw == WRITE && mapping->nrpages)
+			invalidate_inode_pages2(mapping);
 	}
-
-	retval = mapping->a_ops->direct_IO(rw, iocb, iov, offset, nr_segs);
-	if (rw == WRITE && mapping->nrpages)
-		invalidate_inode_pages2(mapping);
-out:
 	return retval;
 }
 
--- diff/mm/fremap.c	2004-03-04 11:41:49.000000000 +0000
+++ source/mm/fremap.c	2004-03-09 11:51:52.000000000 +0000
@@ -38,7 +38,7 @@ static inline void zap_pte(struct mm_str
 					set_page_dirty(page);
 				page_remove_rmap(page, ptep);
 				page_cache_release(page);
-				mm->rss--;
+				dec_rss(mm, page);
 			}
 		}
 	} else {
@@ -53,7 +53,7 @@ static inline void zap_pte(struct mm_str
  * previously existing mapping.
  */
 int install_page(struct mm_struct *mm, struct vm_area_struct *vma,
-		unsigned long addr, struct page *page, pgprot_t prot)
+		unsigned long addr, struct page *page, pgprot_t pgprot)
 {
 	int err = -ENOMEM;
 	pte_t *pte;
@@ -75,12 +75,19 @@ int install_page(struct mm_struct *mm, s
 	pte = pte_alloc_map(mm, pmd, addr);
 	if (!pte)
 		goto err_unlock;
+	/*
+	 * Only install a new page for a non-shared mapping if it's
+	 * not existent yet:
+	 */
+	err = -EEXIST;
+	if (!pte_none(*pte) && !(vma->vm_flags & VM_SHARED))
+		goto err_unlock;
 
 	zap_pte(mm, vma, addr, pte);
 
-	mm->rss++;
+	inc_rss(mm, page);
 	flush_icache_page(vma, page);
-	set_pte(pte, mk_pte(page, prot));
+	set_pte(pte, mk_pte(page, pgprot));
 	pte_chain = page_add_rmap(page, pte, pte_chain);
 	pte_val = *pte;
 	pte_unmap(pte);
@@ -103,7 +110,7 @@ EXPORT_SYMBOL(install_page);
  * previously existing mapping.
  */
 int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma,
-		unsigned long addr, unsigned long pgoff, pgprot_t prot)
+	unsigned long addr, unsigned long pgoff, pgprot_t pgprot, int linear)
 {
 	int err = -ENOMEM;
 	pte_t *pte;
@@ -111,6 +118,8 @@ int install_file_pte(struct mm_struct *m
 	pmd_t *pmd;
 	pte_t pte_val;
 
+	BUG_ON(!linear && !(vma->vm_flags & VM_SHARED));
+
 	pgd = pgd_offset(mm, addr);
 	spin_lock(&mm->page_table_lock);
 
@@ -121,10 +130,23 @@ int install_file_pte(struct mm_struct *m
 	pte = pte_alloc_map(mm, pmd, addr);
 	if (!pte)
 		goto err_unlock;
+	/*
+	 * Skip linear non-existent ptes:
+	 */
+	err = 0;
+	if (linear && pte_none(*pte))
+		goto err_unlock;
+	/*
+	 * Only install a new page for a non-shared mapping if it's
+	 * not existent yet:
+	 */
+	err = -EEXIST;
+	if (!pte_none(*pte) && !(vma->vm_flags & VM_SHARED))
+		goto err_unlock;
 
 	zap_pte(mm, vma, addr, pte);
 
-	set_pte(pte, pgoff_to_pte(pgoff));
+	set_pte(pte, pgoff_prot_to_pte(pgoff, pgprot));
 	pte_val = *pte;
 	pte_unmap(pte);
 	update_mmu_cache(vma, addr, pte_val);
@@ -144,27 +166,22 @@ err_unlock:
  * @size: size of the remapped virtual memory range
  * @prot: new protection bits of the range
  * @pgoff: to be mapped page of the backing store file
- * @flags: 0 or MAP_NONBLOCKED - the later will cause no IO.
+ * @flags: bits MAP_INHERIT or MAP_NONBLOCKED - the later will cause no IO.
  *
  * this syscall works purely via pagetables, so it's the most efficient
  * way to map the same (large) file into a given virtual window. Unlike
  * mmap()/mremap() it does not create any new vmas. The new mappings are
  * also safe across swapout.
- *
- * NOTE: the 'prot' parameter right now is ignored, and the vma's default
- * protection is used. Arbitrary protections might be implemented in the
- * future.
  */
-asmlinkage long sys_remap_file_pages(unsigned long start, unsigned long size,
-	unsigned long __prot, unsigned long pgoff, unsigned long flags)
+long __remap_file_pages(struct mm_struct *mm, unsigned long start,
+			unsigned long size, unsigned long prot,
+			unsigned long pgoff, unsigned long flags)
 {
-	struct mm_struct *mm = current->mm;
+	pgprot_t pgprot = protection_map[calc_vm_prot_bits(prot) | VM_SHARED];
 	unsigned long end = start + size;
 	struct vm_area_struct *vma;
 	int err = -EINVAL;
 
-	if (__prot)
-		return err;
 	/*
 	 * Sanitize the syscall parameters:
 	 */
@@ -184,37 +201,71 @@ asmlinkage long sys_remap_file_pages(uns
 	/* We need down_write() to change vma->vm_flags. */
 	down_write(&mm->mmap_sem);
 	vma = find_vma(mm, start);
-
 	/*
-	 * Make sure the vma is shared, that it supports prefaulting,
-	 * and that the remapped range is valid and fully within
-	 * the single existing vma:
-	 */
-	if (vma && (vma->vm_flags & VM_SHARED) &&
-		vma->vm_ops && vma->vm_ops->populate &&
-			end > start && start >= vma->vm_start &&
-				end <= vma->vm_end) {
-
-		/* Must set VM_NONLINEAR before any pages are populated. */
-		if (pgoff != ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff)
-			vma->vm_flags |= VM_NONLINEAR;
-
-		/* ->populate can take a long time, so downgrade the lock. */
-		downgrade_write(&mm->mmap_sem);
-		err = vma->vm_ops->populate(vma, start, size,
-					    vma->vm_page_prot,
-					    pgoff, flags & MAP_NONBLOCK);
-
-		/*
-		 * We can't clear VM_NONLINEAR because we'd have to do
-		 * it after ->populate completes, and that would prevent
-		 * downgrading the lock.  (Locks can't be upgraded).
-		 */
-		up_read(&mm->mmap_sem);
-	} else {
-		up_write(&mm->mmap_sem);
+	 * Make sure the permissions are right, the vma is shared
+	 * (or linearly remapped - ie. prefaulted), that it supports
+	 * prefaulting, and that the remapped range is valid and fully
+	 * within the single existing vma:
+	 */
+	if (!vma)
+		goto out_unlock;
+	if (unlikely(flags & MAP_INHERIT))
+		pgprot = vma->vm_page_prot;
+	else {
+		err = -EPERM;
+		if (((prot & PROT_READ) && !(vma->vm_flags & VM_MAYREAD)))
+			goto out_unlock;
+		if (((prot & PROT_WRITE) && !(vma->vm_flags & VM_MAYWRITE)))
+			goto out_unlock;
+		if (((prot & PROT_EXEC) && !(vma->vm_flags & VM_MAYEXEC)))
+			goto out_unlock;
+	}
+
+	if (!vma->vm_ops || !vma->vm_ops->populate || end <= start ||
+				start < vma->vm_start || end > vma->vm_end)
+		goto out_unlock;
+
+	if (pgoff != ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff) {
+		if (!(vma->vm_flags & VM_SHARED))
+			goto out_unlock;
+		vma->vm_flags |= VM_NONLINEAR;
 	}
 
+	/*
+	 * ->populate can take a long time, so downgrade the lock:
+	 */
+	downgrade_write(&mm->mmap_sem);
+	err = vma->vm_ops->populate(vma, start, size,
+				pgprot, pgoff, flags & MAP_NONBLOCK);
+
+	/*
+	 * We can't clear VM_NONLINEAR because we'd have to do
+	 * it after ->populate completes, and that would prevent
+	 * downgrading the lock.  (Locks can't be upgraded).
+	 */
+	up_read(&mm->mmap_sem);
+	return err;
+
+out_unlock:
+	up_write(&mm->mmap_sem);
 	return err;
 }
 
+asmlinkage long sys_remap_file_pages(unsigned long start, unsigned long size,
+	unsigned long prot, unsigned long pgoff, unsigned long flags)
+{
+	return __remap_file_pages(current->mm, start, size, prot, pgoff, flags);
+}
+
+/*
+ * sys_remap_file_pages - the old API. Implies MAP_INHERIT.
+ */
+asmlinkage long old_remap_file_pages(unsigned long start, unsigned long size,
+	unsigned long __prot, unsigned long pgoff, unsigned long flags)
+{
+	if (__prot)
+		return -EINVAL;
+
+	return __remap_file_pages(current->mm, start, size, PROT_NONE,
+						pgoff, flags | MAP_INHERIT);
+}
--- diff/mm/highmem.c	2004-03-04 11:41:49.000000000 +0000
+++ source/mm/highmem.c	2004-03-09 11:51:52.000000000 +0000
@@ -147,7 +147,7 @@ start:
 	return vaddr;
 }
 
-void *kmap_high(struct page *page)
+void fastcall *kmap_high(struct page *page)
 {
 	unsigned long vaddr;
 
@@ -170,7 +170,7 @@ void *kmap_high(struct page *page)
 
 EXPORT_SYMBOL(kmap_high);
 
-void kunmap_high(struct page *page)
+void fastcall kunmap_high(struct page *page)
 {
 	unsigned long vaddr;
 	unsigned long nr;
--- diff/mm/memory.c	2004-03-04 11:41:49.000000000 +0000
+++ source/mm/memory.c	2004-03-09 11:51:52.000000000 +0000
@@ -109,7 +109,8 @@ static inline void free_one_pmd(struct m
 	pte_free_tlb(tlb, page);
 }
 
-static inline void free_one_pgd(struct mmu_gather *tlb, pgd_t * dir)
+static inline void free_one_pgd(struct mmu_gather *tlb, pgd_t * dir,
+							int pgd_idx)
 {
 	int j;
 	pmd_t * pmd;
@@ -123,8 +124,11 @@ static inline void free_one_pgd(struct m
 	}
 	pmd = pmd_offset(dir, 0);
 	pgd_clear(dir);
-	for (j = 0; j < PTRS_PER_PMD ; j++)
+	for (j = 0; j < PTRS_PER_PMD ; j++) {
+		if (pgd_idx * PGDIR_SIZE + j * PMD_SIZE >= TASK_SIZE)
+			break;
 		free_one_pmd(tlb, pmd+j);
+	}
 	pmd_free_tlb(tlb, pmd);
 }
 
@@ -137,15 +141,17 @@ static inline void free_one_pgd(struct m
 void clear_page_tables(struct mmu_gather *tlb, unsigned long first, int nr)
 {
 	pgd_t * page_dir = tlb->mm->pgd;
+	int pgd_idx = first;
 
 	page_dir += first;
 	do {
-		free_one_pgd(tlb, page_dir);
+		free_one_pgd(tlb, page_dir, pgd_idx);
 		page_dir++;
+		pgd_idx++;
 	} while (--nr);
 }
 
-pte_t * pte_alloc_map(struct mm_struct *mm, pmd_t *pmd, unsigned long address)
+pte_t fastcall * pte_alloc_map(struct mm_struct *mm, pmd_t *pmd, unsigned long address)
 {
 	if (!pmd_present(*pmd)) {
 		struct page *new;
@@ -171,7 +177,7 @@ out:
 	return pte_offset_map(pmd, address);
 }
 
-pte_t * pte_alloc_kernel(struct mm_struct *mm, pmd_t *pmd, unsigned long address)
+pte_t fastcall * pte_alloc_kernel(struct mm_struct *mm, pmd_t *pmd, unsigned long address)
 {
 	if (!pmd_present(*pmd)) {
 		pte_t *new;
@@ -328,7 +334,7 @@ skip_copy_pte_range:
 					pte = pte_mkclean(pte);
 				pte = pte_mkold(pte);
 				get_page(page);
-				dst->rss++;
+				inc_rss(dst, page);
 
 				set_pte(dst_pte, pte);
 				pte_chain = page_add_rmap(page, dst_pte,
@@ -420,7 +426,14 @@ zap_pte_range(struct mmu_gather *tlb, pm
 					if (page->mapping && pte_young(pte) &&
 							!PageSwapCache(page))
 						mark_page_accessed(page);
-					tlb->freed++;
+					/*
+					 * While we have the page that is being
+					 * freed handy, make sure we decrement
+					 * the mm's RSS accordingly.  This is
+					 * only important for NUMA per-node
+					 * RSS accounting.
+					 */
+					dec_rss(tlb->mm, page);
 					page_remove_rmap(page, ptep);
 					tlb_remove_page(tlb, page);
 				}
@@ -439,7 +452,7 @@ zap_pmd_range(struct mmu_gather *tlb, pg
 		unsigned long address, unsigned long size)
 {
 	pmd_t * pmd;
-	unsigned long end;
+	unsigned long end, pgd_boundary;
 
 	if (pgd_none(*dir))
 		return;
@@ -450,8 +463,9 @@ zap_pmd_range(struct mmu_gather *tlb, pg
 	}
 	pmd = pmd_offset(dir, address);
 	end = address + size;
-	if (end > ((address + PGDIR_SIZE) & PGDIR_MASK))
-		end = ((address + PGDIR_SIZE) & PGDIR_MASK);
+	pgd_boundary = ((address + PGDIR_SIZE) & PGDIR_MASK);
+	if (pgd_boundary && (end > pgd_boundary))
+		end = pgd_boundary;
 	do {
 		zap_pte_range(tlb, pmd, address, end - address);
 		address = (address + PMD_SIZE) & PMD_MASK; 
@@ -606,6 +620,11 @@ void zap_page_range(struct vm_area_struc
 	might_sleep();
 
 	if (is_vm_hugetlb_page(vma)) {
+		static int x;
+		if (x < 10) {
+			x++;
+			dump_stack();
+		}
 		zap_hugepage_range(vma, address, size);
 		return;
 	}
@@ -693,6 +712,7 @@ int get_user_pages(struct task_struct *t
 		struct page **pages, struct vm_area_struct **vmas)
 {
 	int i;
+	int vm_io;
 	unsigned int flags;
 
 	/* 
@@ -736,8 +756,10 @@ int get_user_pages(struct task_struct *t
 			continue;
 		}
 
-		if (!vma || (pages && (vma->vm_flags & VM_IO))
-				|| !(flags & vma->vm_flags))
+		if (!vma)
+			return i ? : -EFAULT;
+		vm_io = vma->vm_flags & VM_IO;
+		if ((pages && vm_io) || !(flags & vma->vm_flags))
 			return i ? : -EFAULT;
 
 		if (is_vm_hugetlb_page(vma)) {
@@ -747,8 +769,15 @@ int get_user_pages(struct task_struct *t
 		}
 		spin_lock(&mm->page_table_lock);
 		do {
-			struct page *map;
+			struct page *map = NULL;
 			int lookup_write = write;
+
+			/*
+			 * We don't follow pagetables for VM_IO regions - they
+			 * may have no pageframes.
+			 */
+			if (vm_io)
+				goto no_follow;
 			while (!(map = follow_page(mm, start, lookup_write))) {
 				spin_unlock(&mm->page_table_lock);
 				switch (handle_mm_fault(mm,vma,start,write)) {
@@ -788,6 +817,7 @@ int get_user_pages(struct task_struct *t
 				if (!PageReserved(pages[i]))
 					page_cache_get(pages[i]);
 			}
+no_follow:
 			if (vmas)
 				vmas[i] = vma;
 			i++;
@@ -1068,7 +1098,7 @@ static int do_wp_page(struct mm_struct *
 	page_table = pte_offset_map(pmd, address);
 	if (pte_same(*page_table, pte)) {
 		if (PageReserved(old_page))
-			++mm->rss;
+			inc_rss(mm, new_page);
 		page_remove_rmap(old_page, page_table);
 		break_cow(vma, new_page, address, page_table);
 		pte_chain = page_add_rmap(new_page, page_table, pte_chain);
@@ -1302,7 +1332,7 @@ static int do_swap_page(struct mm_struct
 	if (vm_swap_full())
 		remove_exclusive_swap_page(page);
 
-	mm->rss++;
+	inc_rss(mm, page);
 	pte = mk_pte(page, vma->vm_page_prot);
 	if (write_access && can_share_swap_page(page))
 		pte = maybe_mkwrite(pte_mkdirty(pte), vma);
@@ -1371,7 +1401,7 @@ do_anonymous_page(struct mm_struct *mm, 
 			ret = VM_FAULT_MINOR;
 			goto out;
 		}
-		mm->rss++;
+		inc_rss(mm, page);
 		entry = maybe_mkwrite(pte_mkdirty(mk_pte(page,
 							 vma->vm_page_prot)),
 				      vma);
@@ -1486,7 +1516,7 @@ retry:
 	/* Only go through if we didn't race with anybody else... */
 	if (pte_none(*page_table)) {
 		if (!PageReserved(new_page))
-			++mm->rss;
+			inc_rss(mm, new_page);
 		flush_icache_page(vma, new_page);
 		entry = mk_pte(new_page, vma->vm_page_prot);
 		if (write_access)
@@ -1523,6 +1553,7 @@ static int do_file_page(struct mm_struct
 	unsigned long address, int write_access, pte_t *pte, pmd_t *pmd)
 {
 	unsigned long pgoff;
+	pgprot_t pgprot;
 	int err;
 
 	BUG_ON(!vma->vm_ops || !vma->vm_ops->nopage);
@@ -1537,11 +1568,12 @@ static int do_file_page(struct mm_struct
 	}
 
 	pgoff = pte_to_pgoff(*pte);
+	pgprot = pte_to_pgprot(*pte);
 
 	pte_unmap(pte);
 	spin_unlock(&mm->page_table_lock);
 
-	err = vma->vm_ops->populate(vma, address & PAGE_MASK, PAGE_SIZE, vma->vm_page_prot, pgoff, 0);
+	err = vma->vm_ops->populate(vma, address & PAGE_MASK, PAGE_SIZE, pgprot, pgoff, 0);
 	if (err == -ENOMEM)
 		return VM_FAULT_OOM;
 	if (err)
@@ -1590,6 +1622,15 @@ static inline int handle_pte_fault(struc
 		return do_swap_page(mm, vma, address, pte, pmd, entry, write_access);
 	}
 
+	/*
+	 * Generate a SIGSEGV if a PROT_NONE page is accessed:
+	 */
+	if (pgprot_val(pte_to_pgprot(entry)) == pgprot_val(__P000)) {
+		pte_unmap(pte);
+		spin_unlock(&mm->page_table_lock);
+		return VM_FAULT_SIGSEGV;
+	}
+
 	if (write_access) {
 		if (!pte_write(entry))
 			return do_wp_page(mm, vma, address, pte, pmd, entry);
@@ -1646,7 +1687,7 @@ int handle_mm_fault(struct mm_struct *mm
  * On a two-level page table, this ends up actually being entirely
  * optimized away.
  */
-pmd_t *__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address)
+pmd_t fastcall *__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address)
 {
 	pmd_t *new;
 
--- diff/mm/mmap.c	2004-03-04 11:41:49.000000000 +0000
+++ source/mm/mmap.c	2004-03-09 11:51:52.000000000 +0000
@@ -222,8 +222,8 @@ __vma_link_list(struct mm_struct *mm, st
 	}
 }
 
-static void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma,
-			struct rb_node **rb_link, struct rb_node *rb_parent)
+void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma,
+		struct rb_node **rb_link, struct rb_node *rb_parent)
 {
 	rb_link_node(&vma->vm_rb, rb_parent, rb_link);
 	rb_insert_color(&vma->vm_rb, &mm->mm_rb);
@@ -691,8 +691,12 @@ out:	
 	}
 	if (flags & MAP_POPULATE) {
 		up_write(&mm->mmap_sem);
-		sys_remap_file_pages(addr, len, prot,
-					pgoff, flags & MAP_NONBLOCK);
+		/*
+		 * remap_file_pages() works even if the mapping is private,
+		 * in the linearly-mapped case:
+		 */
+		__remap_file_pages(mm, addr, len, PROT_NONE, pgoff,
+					MAP_INHERIT | (flags & MAP_NONBLOCK));
 		down_write(&mm->mmap_sem);
 	}
 	return addr;
@@ -1404,22 +1408,6 @@ out:
 
 EXPORT_SYMBOL(do_brk);
 
-/* Build the RB tree corresponding to the VMA list. */
-void build_mmap_rb(struct mm_struct * mm)
-{
-	struct vm_area_struct * vma;
-	struct rb_node ** rb_link, * rb_parent;
-
-	mm->mm_rb = RB_ROOT;
-	rb_link = &mm->mm_rb.rb_node;
-	rb_parent = NULL;
-	for (vma = mm->mmap; vma; vma = vma->vm_next) {
-		__vma_link_rb(mm, vma, rb_link, rb_parent);
-		rb_parent = &vma->vm_rb;
-		rb_link = &rb_parent->rb_right;
-	}
-}
-
 /* Release all mmaps. */
 void exit_mmap(struct mm_struct *mm)
 {
@@ -1446,7 +1434,7 @@ void exit_mmap(struct mm_struct *mm)
 	vma = mm->mmap;
 	mm->mmap = mm->mmap_cache = NULL;
 	mm->mm_rb = RB_ROOT;
-	mm->rss = 0;
+	zero_rss(mm);
 	mm->total_vm = 0;
 	mm->locked_vm = 0;
 
--- diff/mm/page-writeback.c	2004-02-09 10:36:12.000000000 +0000
+++ source/mm/page-writeback.c	2004-03-09 11:51:52.000000000 +0000
@@ -28,6 +28,7 @@
 #include <linux/smp.h>
 #include <linux/sysctl.h>
 #include <linux/cpu.h>
+#include <linux/quotaops.h>
 
 /*
  * The maximum number of pages to writeout in a single bdflush/kupdate
@@ -81,6 +82,16 @@ int dirty_writeback_centisecs = 5 * 100;
  */
 int dirty_expire_centisecs = 30 * 100;
 
+/*
+ * Flag that makes the machine dump writes/reads and block dirtyings.
+ */
+int block_dump;
+
+/*
+ * Flag that puts the machine in "laptop mode".
+ */
+int laptop_mode;
+
 /* End of sysctl-exported parameters */
 
 
@@ -195,7 +206,7 @@ static void balance_dirty_pages(struct a
 	if (nr_reclaimable + ps.nr_writeback <= dirty_thresh)
 		dirty_exceeded = 0;
 
-	if (!writeback_in_progress(bdi) && nr_reclaimable > background_thresh)
+	if (!unlikely(laptop_mode) && !writeback_in_progress(bdi) && nr_reclaimable > background_thresh)
 		pdflush_operation(background_writeout, 0);
 }
 
@@ -289,7 +300,17 @@ int wakeup_bdflush(long nr_pages)
 	return pdflush_operation(background_writeout, nr_pages);
 }
 
-static struct timer_list wb_timer;
+
+static void wb_timer_fn(unsigned long unused);
+
+/*
+ * Both timers share the same handler
+ */
+static struct timer_list wb_timer =
+			TIMER_INITIALIZER(wb_timer_fn, 0, 0);
+static struct timer_list laptop_mode_wb_timer =
+			TIMER_INITIALIZER(wb_timer_fn, 0, 0);
+
 
 /*
  * Periodic writeback of "old" data.
@@ -328,6 +349,8 @@ static void wb_kupdate(unsigned long arg
 	oldest_jif = jiffies - (dirty_expire_centisecs * HZ) / 100;
 	start_jif = jiffies;
 	next_jif = start_jif + (dirty_writeback_centisecs * HZ) / 100;
+	if (laptop_mode)
+		wbc.older_than_this = NULL;
 	nr_to_write = ps.nr_dirty + ps.nr_unstable +
 			(inodes_stat.nr_inodes - inodes_stat.nr_unused);
 	while (nr_to_write > 0) {
@@ -346,8 +369,10 @@ static void wb_kupdate(unsigned long arg
 		next_jif = jiffies + HZ;
 	if (dirty_writeback_centisecs)
 		mod_timer(&wb_timer, next_jif);
+	del_timer(&laptop_mode_wb_timer); /* May have been set as a result of our writes. */
 }
 
+
 /*
  * sysctl handler for /proc/sys/vm/dirty_writeback_centisecs
  */
@@ -364,13 +389,31 @@ int dirty_writeback_centisecs_handler(ct
 	return 0;
 }
 
+/*
+ * We've spun up the disk and we're in laptop mode: schedule writeback
+ * of all dirty data in 5 seconds.
+ *
+ * Laptop mode writeback will be delayed if it has previously been
+ * scheduled to occur within 5 seconds. That way, the writeback will
+ * only be triggered if the system is truly quiet again.
+ */
+void disk_is_spun_up(int postpone_writeback)
+{
+	if (postpone_writeback || !timer_pending(&laptop_mode_wb_timer))
+		mod_timer(&laptop_mode_wb_timer, jiffies + 5 * HZ);
+}
+
+
+/*
+ * Handler for wb_timer and laptop_mode_wb_timer.
+ */
 static void wb_timer_fn(unsigned long unused)
 {
 	if (pdflush_operation(wb_kupdate, 0) < 0)
 		mod_timer(&wb_timer, jiffies + HZ); /* delay 1 second */
-
 }
 
+
 /*
  * If ratelimit_pages is too high then we can get into dirty-data overload
  * if a large number of processes all perform writes at the same time.
@@ -430,11 +473,9 @@ void __init page_writeback_init(void)
 		vm_dirty_ratio /= 100;
 	}
 
-	init_timer(&wb_timer);
 	wb_timer.expires = jiffies + (dirty_writeback_centisecs * HZ) / 100;
-	wb_timer.data = 0;
-	wb_timer.function = wb_timer_fn;
 	add_timer(&wb_timer);
+
 	set_ratelimit();
 	register_cpu_notifier(&ratelimit_nb);
 }
@@ -526,6 +567,8 @@ int __set_page_dirty_nobuffers(struct pa
 				__mark_inode_dirty(mapping->host,
 							I_DIRTY_PAGES);
 		}
+		if (unlikely(block_dump))
+			printk("%s(%d): dirtied page\n", current->comm, current->pid);
 	}
 	return ret;
 }
--- diff/mm/page_alloc.c	2004-03-04 11:41:49.000000000 +0000
+++ source/mm/page_alloc.c	2004-03-09 11:51:52.000000000 +0000
@@ -390,6 +390,27 @@ static int rmqueue_bulk(struct zone *zon
 	return allocated;
 }
 
+#if defined(CONFIG_PM) || defined(CONFIG_HOTPLUG_CPU)
+static void __drain_pages(unsigned int cpu)
+{
+	struct zone *zone;
+	int i;
+
+	for_each_zone(zone) {
+		struct per_cpu_pageset *pset;
+
+		pset = &zone->pageset[cpu];
+		for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
+			struct per_cpu_pages *pcp;
+
+			pcp = &pset->pcp[i];
+			pcp->count -= free_pages_bulk(zone, pcp->count,
+						&pcp->list, 0);
+		}
+	}
+}
+#endif /* CONFIG_PM || CONFIG_HOTPLUG_CPU */
+
 #ifdef CONFIG_PM
 int is_head_of_free_region(struct page *page)
 {
@@ -419,22 +440,9 @@ int is_head_of_free_region(struct page *
 void drain_local_pages(void)
 {
 	unsigned long flags;
-	struct zone *zone;
-	int i;
 
 	local_irq_save(flags);	
-	for_each_zone(zone) {
-		struct per_cpu_pageset *pset;
-
-		pset = &zone->pageset[smp_processor_id()];
-		for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
-			struct per_cpu_pages *pcp;
-
-			pcp = &pset->pcp[i];
-			pcp->count -= free_pages_bulk(zone, pcp->count,
-						&pcp->list, 0);
-		}
-	}
+	__drain_pages(smp_processor_id());
 	local_irq_restore(flags);	
 }
 #endif /* CONFIG_PM */
@@ -443,7 +451,7 @@ void drain_local_pages(void)
  * Free a 0-order page
  */
 static void FASTCALL(free_hot_cold_page(struct page *page, int cold));
-static void free_hot_cold_page(struct page *page, int cold)
+static void fastcall free_hot_cold_page(struct page *page, int cold)
 {
 	struct zone *zone = page_zone(page);
 	struct per_cpu_pages *pcp;
@@ -462,12 +470,12 @@ static void free_hot_cold_page(struct pa
 	put_cpu();
 }
 
-void free_hot_page(struct page *page)
+void fastcall free_hot_page(struct page *page)
 {
 	free_hot_cold_page(page, 0);
 }
 	
-void free_cold_page(struct page *page)
+void fastcall free_cold_page(struct page *page)
 {
 	free_hot_cold_page(page, 1);
 }
@@ -510,7 +518,7 @@ static struct page *buffered_rmqueue(str
 
 	if (page != NULL) {
 		BUG_ON(bad_range(zone, page));
-		mod_page_state(pgalloc, 1 << order);
+		mod_page_state_zone(zone, pgalloc, 1 << order);
 		prep_new_page(page, order);
 	}
 	return page;
@@ -532,7 +540,7 @@ static struct page *buffered_rmqueue(str
  * sized machine, GFP_HIGHMEM and GFP_KERNEL requests basically leave the DMA
  * zone untouched.
  */
-struct page *
+struct page * fastcall
 __alloc_pages(unsigned int gfp_mask, unsigned int order,
 		struct zonelist *zonelist)
 {
@@ -682,13 +690,53 @@ got_pg:
 
 EXPORT_SYMBOL(__alloc_pages);
 
+#ifdef CONFIG_NUMA
+/* Early boot: Everything is done by one cpu, but the data structures will be
+ * used by all cpus - spread them on all nodes.
+ */
+static __init unsigned long get_boot_pages(unsigned int gfp_mask, unsigned int order)
+{
+static int nodenr;
+	int i = nodenr;
+	struct page *page;
+
+	for (;;) {
+		if (i > nodenr + numnodes)
+			return 0;
+		if (node_present_pages(i%numnodes)) {
+			struct zone **z;
+			/* The node contains memory. Check that there is
+			 * memory in the intended zonelist.
+			 */
+			z = NODE_DATA(i%numnodes)->node_zonelists[gfp_mask & GFP_ZONEMASK].zones;
+			while (*z) {
+				if ( (*z)->free_pages > (1UL<<order))
+					goto found_node;
+				z++;
+			}
+		}
+		i++;
+	}
+found_node:
+	nodenr = i+1;
+	page = alloc_pages_node(i%numnodes, gfp_mask, order);
+	if (!page)
+		return 0;
+	return (unsigned long) page_address(page);
+}
+#endif
+
 /*
  * Common helper functions.
  */
-unsigned long __get_free_pages(unsigned int gfp_mask, unsigned int order)
+fastcall unsigned long __get_free_pages(unsigned int gfp_mask, unsigned int order)
 {
 	struct page * page;
 
+#ifdef CONFIG_NUMA
+	if (unlikely(!system_running))
+		return get_boot_pages(gfp_mask, order);
+#endif
 	page = alloc_pages(gfp_mask, order);
 	if (!page)
 		return 0;
@@ -697,7 +745,7 @@ unsigned long __get_free_pages(unsigned 
 
 EXPORT_SYMBOL(__get_free_pages);
 
-unsigned long get_zeroed_page(unsigned int gfp_mask)
+fastcall unsigned long get_zeroed_page(unsigned int gfp_mask)
 {
 	struct page * page;
 
@@ -726,7 +774,7 @@ void __pagevec_free(struct pagevec *pvec
 		free_hot_cold_page(pvec->pages[i], pvec->cold);
 }
 
-void __free_pages(struct page *page, unsigned int order)
+fastcall void __free_pages(struct page *page, unsigned int order)
 {
 	if (!PageReserved(page) && put_page_testzero(page)) {
 		if (order == 0)
@@ -738,7 +786,7 @@ void __free_pages(struct page *page, uns
 
 EXPORT_SYMBOL(__free_pages);
 
-void free_pages(unsigned long addr, unsigned int order)
+fastcall void free_pages(unsigned long addr, unsigned int order)
 {
 	if (addr != 0) {
 		BUG_ON(!virt_addr_valid(addr));
@@ -1013,6 +1061,7 @@ void show_free_areas(void)
 			" high:%lukB"
 			" active:%lukB"
 			" inactive:%lukB"
+			" present:%lukB"
 			"\n",
 			zone->name,
 			K(zone->free_pages),
@@ -1020,7 +1069,8 @@ void show_free_areas(void)
 			K(zone->pages_low),
 			K(zone->pages_high),
 			K(zone->nr_active),
-			K(zone->nr_inactive)
+			K(zone->nr_inactive),
+			K(zone->present_pages)
 			);
 	}
 
@@ -1080,6 +1130,109 @@ static int __init build_zonelists_node(p
 	return j;
 }
 
+#ifdef CONFIG_NUMA
+#define MAX_NODE_LOAD (numnodes)
+static int __initdata node_load[MAX_NUMNODES];
+/**
+ * find_next_best_node - find the next node that should appear in a given
+ *    node's fallback list
+ * @node: node whose fallback list we're appending
+ * @used_node_mask: pointer to the bitmap of already used nodes
+ *
+ * We use a number of factors to determine which is the next node that should
+ * appear on a given node's fallback list.  The node should not have appeared
+ * already in @node's fallback list, and it should be the next closest node
+ * according to the distance array (which contains arbitrary distance values
+ * from each node to each node in the system), and should also prefer nodes
+ * with no CPUs, since presumably they'll have very little allocation pressure
+ * on them otherwise.
+ * It returns -1 if no node is found.
+ */
+static int __init find_next_best_node(int node, void *used_node_mask)
+{
+	int i, n, val;
+	int min_val = INT_MAX;
+	int best_node = -1;
+
+	for (i = 0; i < numnodes; i++) {
+		/* Start from local node */
+		n = (node+i)%numnodes;
+
+		/* Don't want a node to appear more than once */
+		if (test_bit(n, used_node_mask))
+			continue;
+
+		/* Use the distance array to find the distance */
+		val = node_distance(node, n);
+
+		/* Give preference to headless and unused nodes */
+		if (!cpus_empty(node_to_cpumask(n)))
+			val += PENALTY_FOR_NODE_WITH_CPUS;
+
+		/* Slight preference for less loaded node */
+		val *= (MAX_NODE_LOAD*MAX_NUMNODES);
+		val += node_load[n];
+
+		if (val < min_val) {
+			min_val = val;
+			best_node = n;
+		}
+	}
+
+	if (best_node >= 0)
+		set_bit(best_node, used_node_mask);
+
+	return best_node;
+}
+
+static void __init build_zonelists(pg_data_t *pgdat)
+{
+	int i, j, k, node, local_node;
+	int prev_node, load;
+	struct zonelist *zonelist;
+	DECLARE_BITMAP(used_mask, MAX_NUMNODES);
+
+	/* initialize zonelists */
+	for (i = 0; i < MAX_NR_ZONES; i++) {
+		zonelist = pgdat->node_zonelists + i;
+		memset(zonelist, 0, sizeof(*zonelist));
+		zonelist->zones[0] = NULL;
+	}
+
+	/* NUMA-aware ordering of nodes */
+	local_node = pgdat->node_id;
+	load = numnodes;
+	prev_node = local_node;
+	CLEAR_BITMAP(used_mask, MAX_NUMNODES);
+	while ((node = find_next_best_node(local_node, used_mask)) >= 0) {
+		/*
+		 * We don't want to pressure a particular node.
+		 * So adding penalty to the first node in same
+		 * distance group to make it round-robin.
+		 */
+		if (node_distance(local_node, node) !=
+				node_distance(local_node, prev_node))
+			node_load[node] += load;
+		prev_node = node;
+		load--;
+		for (i = 0; i < MAX_NR_ZONES; i++) {
+			zonelist = pgdat->node_zonelists + i;
+			for (j = 0; zonelist->zones[j] != NULL; j++);
+
+			k = ZONE_NORMAL;
+			if (i & __GFP_HIGHMEM)
+				k = ZONE_HIGHMEM;
+			if (i & __GFP_DMA)
+				k = ZONE_DMA;
+
+	 		j = build_zonelists_node(NODE_DATA(node), zonelist, j, k);
+			zonelist->zones[j] = NULL;
+		}
+	}
+}
+
+#else	/* CONFIG_NUMA */
+
 static void __init build_zonelists(pg_data_t *pgdat)
 {
 	int i, j, k, node, local_node;
@@ -1116,6 +1269,8 @@ static void __init build_zonelists(pg_da
 	} 
 }
 
+#endif	/* CONFIG_NUMA */
+
 void __init build_all_zonelists(void)
 {
 	int i;
@@ -1290,7 +1445,8 @@ static void __init free_area_init_core(s
 				zone_names[j], realsize, batch);
 		INIT_LIST_HEAD(&zone->active_list);
 		INIT_LIST_HEAD(&zone->inactive_list);
-		atomic_set(&zone->refill_counter, 0);
+		atomic_set(&zone->nr_scan_active, 0);
+		atomic_set(&zone->nr_scan_inactive, 0);
 		zone->nr_active = 0;
 		zone->nr_inactive = 0;
 		if (!size)
@@ -1473,23 +1629,38 @@ static char *vmstat_text[] = {
 	"pgpgout",
 	"pswpin",
 	"pswpout",
-	"pgalloc",
+	"pgalloc_high",
 
+	"pgalloc_normal",
+	"pgalloc_dma",
 	"pgfree",
 	"pgactivate",
 	"pgdeactivate",
+
 	"pgfault",
 	"pgmajfault",
-
-	"pgscan",
-	"pgrefill",
-	"pgsteal",
+	"pgrefill_high",
+	"pgrefill_normal",
+	"pgrefill_dma",
+
+	"pgsteal_high",
+	"pgsteal_normal",
+	"pgsteal_dma",
+	"pgscan_kswapd_high",
+	"pgscan_kswapd_normal",
+
+	"pgscan_kswapd_dma",
+	"pgscan_direct_high",
+	"pgscan_direct_normal",
+	"pgscan_direct_dma",
 	"pginodesteal",
-	"kswapd_steal",
 
+	"slabs_scanned",
+	"kswapd_steal",
 	"kswapd_inodesteal",
 	"pageoutrun",
 	"allocstall",
+
 	"pgrotated",
 };
 
@@ -1542,9 +1713,27 @@ struct seq_operations vmstat_op = {
 
 #endif /* CONFIG_PROC_FS */
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int page_alloc_cpu_notify(struct notifier_block *self,
+				 unsigned long action, void *hcpu)
+{
+	int cpu = (unsigned long)hcpu;
+	long *count;
+
+	if (action == CPU_DEAD) {
+		/* Drain local pagecache count. */
+		count = &per_cpu(nr_pagecache_local, cpu);
+		atomic_add(*count, &nr_pagecache);
+		*count = 0;
+		__drain_pages(cpu);
+	}
+	return NOTIFY_OK;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
 
 void __init page_alloc_init(void)
 {
+	hotcpu_notifier(page_alloc_cpu_notify, 0);
 }
 
 /*
--- diff/mm/pdflush.c	2004-03-04 11:41:49.000000000 +0000
+++ source/mm/pdflush.c	2004-03-09 11:51:52.000000000 +0000
@@ -88,6 +88,8 @@ struct pdflush_work {
 	unsigned long when_i_went_to_sleep;
 };
 
+static int wakeup_count = 100;
+
 static int __pdflush(struct pdflush_work *my_work)
 {
 	current->flags |= PF_FLUSHER;
@@ -114,7 +116,10 @@ static int __pdflush(struct pdflush_work
 
 		spin_lock_irq(&pdflush_lock);
 		if (!list_empty(&my_work->list)) {
-			printk("pdflush: bogus wakeup!\n");
+			if (wakeup_count > 0) {
+				wakeup_count--;
+				printk("pdflush: bogus wakeup!\n");
+			}
 			my_work->fn = NULL;
 			continue;
 		}
@@ -184,6 +189,7 @@ int pdflush_operation(void (*fn)(unsigne
 {
 	unsigned long flags;
 	int ret = 0;
+	static int poke_count = 0;
 
 	if (fn == NULL)
 		BUG();		/* Hard to diagnose if it's deferred */
@@ -192,9 +198,19 @@ int pdflush_operation(void (*fn)(unsigne
 	if (list_empty(&pdflush_list)) {
 		spin_unlock_irqrestore(&pdflush_lock, flags);
 		ret = -1;
+		if (wakeup_count < 100 && poke_count < 10) {
+			printk("%s: no threads\n", __FUNCTION__);
+			dump_stack();
+			poke_count++;
+		}
 	} else {
 		struct pdflush_work *pdf;
 
+		if (wakeup_count < 100 && poke_count < 10) {
+			printk("%s: found a thread\n", __FUNCTION__);
+			dump_stack();
+			poke_count++;
+		}
 		pdf = list_entry(pdflush_list.next, struct pdflush_work, list);
 		list_del_init(&pdf->list);
 		if (list_empty(&pdflush_list))
--- diff/mm/readahead.c	2004-02-09 10:36:12.000000000 +0000
+++ source/mm/readahead.c	2004-03-09 11:51:52.000000000 +0000
@@ -30,6 +30,7 @@ file_ra_state_init(struct file_ra_state 
 {
 	memset(ra, 0, sizeof(*ra));
 	ra->ra_pages = mapping->backing_dev_info->ra_pages;
+	ra->average = ra->ra_pages / 2;
 }
 
 EXPORT_SYMBOL(file_ra_state_init);
@@ -380,9 +381,18 @@ page_cache_readahead(struct address_spac
 		 */
 		first_access=1;
 		ra->next_size = max / 2;
+		ra->prev_page = offset;
+		ra->serial_cnt++;
 		goto do_io;
 	}
 
+	if (offset == ra->prev_page + 1) {
+		if (ra->serial_cnt <= (max * 2))
+			ra->serial_cnt++;
+	} else {
+		ra->average = (ra->average + ra->serial_cnt) / 2;
+		ra->serial_cnt = 1;
+	}
 	preoffset = ra->prev_page;
 	ra->prev_page = offset;
 
@@ -449,8 +459,12 @@ do_io:
 			  * accessed in the current window, there
 			  * is a high probability that around 'n' pages
 			  * shall be used in the next current window.
+			  *
+			  * To minimize lazy-readahead triggered
+			  * in the next current window, read in
+			  * an extra page.
 			  */
-			ra->next_size = preoffset - ra->start + 1;
+			ra->next_size = preoffset - ra->start + 2;
 		}
 		ra->start = offset;
 		ra->size = ra->next_size;
@@ -468,17 +482,34 @@ do_io:
 		}
 	} else {
 		/*
-		 * This read request is within the current window.  It is time
-		 * to submit I/O for the ahead window while the application is
-		 * crunching through the current window.
+		 * This read request is within the current window.  It may be
+		 * time to submit I/O for the ahead window while the
+		 * application is about to step into the ahead window.
 		 */
 		if (ra->ahead_start == 0) {
-			ra->ahead_start = ra->start + ra->size;
-			ra->ahead_size = ra->next_size;
-			actual = do_page_cache_readahead(mapping, filp,
+			/*
+			 * if the average io-size is less than maximum
+			 * readahead size of the file the io pattern is
+			 * sequential. Hence  bring in the readahead window
+			 * immediately.
+			 * Else the i/o pattern is random. Bring
+			 * in the readahead window only if the last page of
+			 * the current window is accessed (lazy readahead).
+			 */
+			unsigned long average = ra->average;
+
+			if (ra->serial_cnt > average)
+				average = (ra->serial_cnt + ra->average) / 2;
+
+			if ((average >= max) || (offset == (ra->start +
+							ra->size - 1))) {
+				ra->ahead_start = ra->start + ra->size;
+				ra->ahead_size = ra->next_size;
+				actual = do_page_cache_readahead(mapping, filp,
 					ra->ahead_start, ra->ahead_size);
-			check_ra_success(ra, ra->ahead_size,
-					actual, orig_next_size);
+				check_ra_success(ra, ra->ahead_size,
+						actual, orig_next_size);
+			}
 		}
 	}
 out:
--- diff/mm/rmap.c	2004-03-04 11:41:49.000000000 +0000
+++ source/mm/rmap.c	2004-03-09 11:51:52.000000000 +0000
@@ -112,7 +112,7 @@ pte_chain_encode(struct pte_chain *pte_c
  * If the page has a single-entry pte_chain, collapse that back to a PageDirect
  * representation.  This way, it's only done under memory pressure.
  */
-int page_referenced(struct page * page)
+int fastcall page_referenced(struct page * page)
 {
 	struct pte_chain *pc;
 	int referenced = 0;
@@ -165,7 +165,7 @@ int page_referenced(struct page * page)
  * Add a new pte reverse mapping to a page.
  * The caller needs to hold the mm->page_table_lock.
  */
-struct pte_chain *
+struct pte_chain * fastcall
 page_add_rmap(struct page *page, pte_t *ptep, struct pte_chain *pte_chain)
 {
 	pte_addr_t pte_paddr = ptep_to_paddr(ptep);
@@ -221,7 +221,7 @@ out:
  * the page.
  * Caller needs to hold the mm->page_table_lock.
  */
-void page_remove_rmap(struct page *page, pte_t *ptep)
+void fastcall page_remove_rmap(struct page *page, pte_t *ptep)
 {
 	pte_addr_t pte_paddr = ptep_to_paddr(ptep);
 	struct pte_chain *pc;
@@ -293,7 +293,7 @@ out_unlock:
  *		    mm->page_table_lock	try_to_unmap_one(), trylock
  */
 static int FASTCALL(try_to_unmap_one(struct page *, pte_addr_t));
-static int try_to_unmap_one(struct page * page, pte_addr_t paddr)
+static int fastcall try_to_unmap_one(struct page * page, pte_addr_t paddr)
 {
 	pte_t *ptep = rmap_ptep_map(paddr);
 	unsigned long address = ptep_to_address(ptep);
@@ -343,6 +343,7 @@ static int try_to_unmap_one(struct page 
 		BUG_ON(pte_file(*ptep));
 	} else {
 		unsigned long pgidx;
+		pgprot_t pgprot = pte_to_pgprot(pte);
 		/*
 		 * If a nonlinear mapping then store the file page offset
 		 * in the pte.
@@ -350,8 +351,10 @@ static int try_to_unmap_one(struct page 
 		pgidx = (address - vma->vm_start) >> PAGE_SHIFT;
 		pgidx += vma->vm_pgoff;
 		pgidx >>= PAGE_CACHE_SHIFT - PAGE_SHIFT;
-		if (page->index != pgidx) {
-			set_pte(ptep, pgoff_to_pte(page->index));
+		if (page->index != pgidx ||
+			pgprot_val(pgprot) != pgprot_val(vma->vm_page_prot)) {
+
+			set_pte(ptep, pgoff_prot_to_pte(page->index, pgprot));
 			BUG_ON(!pte_file(*ptep));
 		}
 	}
@@ -360,7 +363,7 @@ static int try_to_unmap_one(struct page 
 	if (pte_dirty(pte))
 		set_page_dirty(page);
 
-	mm->rss--;
+	dec_rss(mm, page);
 	page_cache_release(page);
 	ret = SWAP_SUCCESS;
 
@@ -382,7 +385,7 @@ out_unlock:
  * SWAP_AGAIN	- we missed a trylock, try again later
  * SWAP_FAIL	- the page is unswappable
  */
-int try_to_unmap(struct page * page)
+int fastcall try_to_unmap(struct page * page)
 {
 	struct pte_chain *pc, *next_pc, *start;
 	int ret = SWAP_SUCCESS;
--- diff/mm/shmem.c	2004-02-09 10:36:12.000000000 +0000
+++ source/mm/shmem.c	2004-03-09 11:51:52.000000000 +0000
@@ -1002,6 +1002,7 @@ static int shmem_populate(struct vm_area
 	struct mm_struct *mm = vma->vm_mm;
 	enum sgp_type sgp = nonblock? SGP_QUICK: SGP_CACHE;
 	unsigned long size;
+	int linear = !(vma->vm_flags & VM_NONLINEAR);
 
 	size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	if (pgoff >= size || pgoff + (len >> PAGE_SHIFT) > size)
@@ -1023,20 +1024,14 @@ static int shmem_populate(struct vm_area
 				page_cache_release(page);
 				return err;
 			}
-		} else if (nonblock) {
+		} else {
 	    		/*
-		 	 * If a nonlinear mapping then store the file page
-			 * offset in the pte.
+		 	 * Store the file page offset in the pte:
 			 */
-	    		unsigned long pgidx;
-			pgidx = (addr - vma->vm_start) >> PAGE_SHIFT;
-			pgidx += vma->vm_pgoff;
-			pgidx >>= PAGE_CACHE_SHIFT - PAGE_SHIFT;
-			if (pgoff != pgidx) {
-	    			err = install_file_pte(mm, vma, addr, pgoff, prot);
-				if (err)
-		    			return err;
-			}
+			err = install_file_pte(mm, vma, addr,
+						pgoff, prot, linear);
+			if (err)
+	    			return err;
 		}
 
 		len -= PAGE_SIZE;
--- diff/mm/slab.c	2004-03-04 11:41:49.000000000 +0000
+++ source/mm/slab.c	2004-03-09 11:51:52.000000000 +0000
@@ -445,8 +445,8 @@ static inline void **dbg_userword(kmem_c
 /*
  * Do not go above this order unless 0 objects fit into the slab.
  */
-#define	BREAK_GFP_ORDER_HI	2
-#define	BREAK_GFP_ORDER_LO	1
+#define	BREAK_GFP_ORDER_HI	1
+#define	BREAK_GFP_ORDER_LO	0
 static int slab_break_gfp_order = BREAK_GFP_ORDER_LO;
 
 /* Macros for storing/retrieving the cachep and or slab from the
@@ -521,9 +521,19 @@ enum {
 static DEFINE_PER_CPU(struct timer_list, reap_timers);
 
 static void reap_timer_fnc(unsigned long data);
-
+static void free_block (kmem_cache_t* cachep, void** objpp, int len);
 static void enable_cpucache (kmem_cache_t *cachep);
 
+static inline void ** ac_entry(struct array_cache *ac)
+{
+	return (void**)(ac+1);
+}
+
+static inline struct array_cache *ac_data(kmem_cache_t *cachep)
+{
+	return cachep->array[smp_processor_id()];
+}
+
 /* Cal the num objs, wastage, and bytes left over for a given slab size. */
 static void cache_estimate (unsigned long gfporder, size_t size,
 		 int flags, size_t *left_over, unsigned int *num)
@@ -573,32 +583,39 @@ static void start_cpu_timer(int cpu)
 	if (rt->function == NULL) {
 		init_timer(rt);
 		rt->expires = jiffies + HZ + 3*cpu;
+		rt->data = cpu;
 		rt->function = reap_timer_fnc;
 		add_timer_on(rt, cpu);
 	}
 }
 
-/*
- * Note: if someone calls kmem_cache_alloc() on the new
- * cpu before the cpuup callback had a chance to allocate
- * the head arrays, it will oops.
- * Is CPU_ONLINE early enough?
- */
+#ifdef CONFIG_HOTPLUG_CPU
+static void stop_cpu_timer(int cpu)
+{
+	struct timer_list *rt = &per_cpu(reap_timers, cpu);
+
+	if (rt->function) {
+		del_timer_sync(rt);
+		WARN_ON(timer_pending(rt));
+		rt->function = NULL;
+	}
+}
+#endif
+
 static int __devinit cpuup_callback(struct notifier_block *nfb,
 				  unsigned long action,
 				  void *hcpu)
 {
 	long cpu = (long)hcpu;
-	struct list_head *p;
+	kmem_cache_t* cachep;
 
 	switch (action) {
 	case CPU_UP_PREPARE:
 		down(&cache_chain_sem);
-		list_for_each(p, &cache_chain) {
+		list_for_each_entry(cachep, &cache_chain, next) {
 			int memsize;
 			struct array_cache *nc;
 
-			kmem_cache_t* cachep = list_entry(p, kmem_cache_t, next);
 			memsize = sizeof(void*)*cachep->limit+sizeof(struct array_cache);
 			nc = kmalloc(memsize, GFP_KERNEL);
 			if (!nc)
@@ -618,22 +635,30 @@ static int __devinit cpuup_callback(stru
 		up(&cache_chain_sem);
 		break;
 	case CPU_ONLINE:
-		if (g_cpucache_up == FULL)
-			start_cpu_timer(cpu);
+		start_cpu_timer(cpu);
 		break;
+
+#ifdef CONFIG_HOTPLUG_CPU
+	case CPU_DEAD:
+		stop_cpu_timer(cpu);
+		/* fall thru */
 	case CPU_UP_CANCELED:
 		down(&cache_chain_sem);
-
-		list_for_each(p, &cache_chain) {
+		list_for_each_entry(cachep, &cache_chain, next) {
 			struct array_cache *nc;
-			kmem_cache_t* cachep = list_entry(p, kmem_cache_t, next);
 
+			spin_lock_irq(&cachep->spinlock);
+			/* cpu is dead; no one can alloc from it. */
 			nc = cachep->array[cpu];
 			cachep->array[cpu] = NULL;
+			cachep->free_limit -= cachep->batchcount;
+			free_block(cachep, ac_entry(nc), nc->avail);
+			spin_unlock_irq(&cachep->spinlock);
 			kfree(nc);
 		}
 		up(&cache_chain_sem);
 		break;
+#endif /* CONFIG_HOTPLUG_CPU */
 	}
 	return NOTIFY_OK;
 bad:
@@ -643,16 +668,6 @@ bad:
 
 static struct notifier_block cpucache_notifier = { &cpuup_callback, NULL, 0 };
 
-static inline void ** ac_entry(struct array_cache *ac)
-{
-	return (void**)(ac+1);
-}
-
-static inline struct array_cache *ac_data(kmem_cache_t *cachep)
-{
-	return cachep->array[smp_processor_id()];
-}
-
 /* Initialisation.
  * Called after the gfp() functions have been enabled, and before smp_init().
  */
@@ -1228,7 +1243,8 @@ next:
 		cachep = NULL;
 		goto opps;
 	}
-	slab_size = L1_CACHE_ALIGN(cachep->num*sizeof(kmem_bufctl_t)+sizeof(struct slab));
+	slab_size = L1_CACHE_ALIGN(cachep->num*sizeof(kmem_bufctl_t) +
+			sizeof(struct slab));
 
 	/*
 	 * If the slab has been placed off-slab, and we have enough space then
@@ -1272,10 +1288,13 @@ next:
 			 * the cache that's used by kmalloc(24), otherwise
 			 * the creation of further caches will BUG().
 			 */
-			cachep->array[smp_processor_id()] = &initarray_generic.cache;
+			cachep->array[smp_processor_id()] =
+					&initarray_generic.cache;
 			g_cpucache_up = PARTIAL;
 		} else {
-			cachep->array[smp_processor_id()] = kmalloc(sizeof(struct arraycache_init),GFP_KERNEL);
+			cachep->array[smp_processor_id()] =
+				kmalloc(sizeof(struct arraycache_init),
+					GFP_KERNEL);
 		}
 		BUG_ON(!ac_data(cachep));
 		ac_data(cachep)->avail = 0;
@@ -1289,7 +1308,7 @@ next:
 	} 
 
 	cachep->lists.next_reap = jiffies + REAPTIMEOUT_LIST3 +
-					((unsigned long)cachep)%REAPTIMEOUT_LIST3;
+				((unsigned long)cachep)%REAPTIMEOUT_LIST3;
 
 	/* Need the semaphore to access the chain. */
 	down(&cache_chain_sem);
@@ -1302,16 +1321,24 @@ next:
 		list_for_each(p, &cache_chain) {
 			kmem_cache_t *pc = list_entry(p, kmem_cache_t, next);
 			char tmp;
-			/* This happens when the module gets unloaded and doesn't
-			   destroy its slab cache and noone else reuses the vmalloc
-			   area of the module. Print a warning. */
-			if (__get_user(tmp,pc->name)) { 
-				printk("SLAB: cache with size %d has lost its name\n", 
-					pc->objsize); 
+
+			/*
+			 * This happens when the module gets unloaded and
+			 * doesn't destroy its slab cache and noone else reuses
+			 * the vmalloc area of the module. Print a warning.
+			 */
+#ifdef CONFIG_X86_UACCESS_INDIRECT
+			if (__direct_get_user(tmp,pc->name)) {
+#else
+			if (__get_user(tmp,pc->name)) {
+#endif
+				printk("SLAB: cache with size %d has lost its "
+						"name\n", pc->objsize);
 				continue; 
 			} 	
 			if (!strcmp(pc->name,name)) { 
-				printk("kmem_cache_create: duplicate cache %s\n",name); 
+				printk("kmem_cache_create: duplicate "
+						"cache %s\n",name);
 				up(&cache_chain_sem); 
 				BUG(); 
 			}	
@@ -1368,7 +1395,6 @@ static void smp_call_function_all_cpus(v
 	preempt_enable();
 }
 
-static void free_block (kmem_cache_t* cachep, void** objpp, int len);
 static void drain_array_locked(kmem_cache_t* cachep,
 				struct array_cache *ac, int force);
 
@@ -1489,6 +1515,9 @@ int kmem_cache_destroy (kmem_cache_t * c
 		return 1;
 	}
 
+	/* no cpu_online check required here since we clear the percpu
+	 * array on cpu offline and set this to NULL.
+	 */
 	for (i = 0; i < NR_CPUS; i++)
 		kfree(cachep->array[i]);
 
@@ -1937,6 +1966,15 @@ cache_alloc_debugcheck_after(kmem_cache_
 		*dbg_redzone1(cachep, objp) = RED_ACTIVE;
 		*dbg_redzone2(cachep, objp) = RED_ACTIVE;
 	}
+	{
+		int objnr;
+		struct slab *slabp;
+
+		slabp = GET_PAGE_SLAB(virt_to_page(objp));
+
+		objnr = (objp - slabp->s_mem) / cachep->objsize;
+		slab_bufctl(slabp)[objnr] = (unsigned long)caller;
+	}
 	objp += obj_dbghead(cachep);
 	if (cachep->ctor && cachep->flags & SLAB_POISON) {
 		unsigned long	ctor_flags = SLAB_CTOR_CONSTRUCTOR;
@@ -1998,12 +2036,14 @@ static void free_block(kmem_cache_t *cac
 		objnr = (objp - slabp->s_mem) / cachep->objsize;
 		check_slabp(cachep, slabp);
 #if DEBUG
+#if 0
 		if (slab_bufctl(slabp)[objnr] != BUFCTL_FREE) {
 			printk(KERN_ERR "slab: double free detected in cache '%s', objp %p.\n",
 						cachep->name, objp);
 			BUG();
 		}
 #endif
+#endif
 		slab_bufctl(slabp)[objnr] = slabp->free;
 		slabp->free = objnr;
 		STATS_DEC_ACTIVE(cachep);
@@ -2134,7 +2174,7 @@ EXPORT_SYMBOL(kmem_cache_alloc);
  *
  * Currently only used for dentry validation.
  */
-int kmem_ptr_validate(kmem_cache_t *cachep, void *ptr)
+int fastcall kmem_ptr_validate(kmem_cache_t *cachep, void *ptr)
 {
 	unsigned long addr = (unsigned long) ptr;
 	unsigned long min_addr = PAGE_OFFSET;
@@ -2601,17 +2641,19 @@ next:
 }
 
 /*
- * This is a timer handler.  There is on per CPU.  It is called periodially
+ * This is a timer handler.  There is one per CPU.  It is called periodially
  * to shrink this CPU's caches.  Otherwise there could be memory tied up
  * for long periods (or for ever) due to load changes.
  */
-static void reap_timer_fnc(unsigned long data)
+static void reap_timer_fnc(unsigned long cpu)
 {
-	int cpu = smp_processor_id();
 	struct timer_list *rt = &__get_cpu_var(reap_timers);
 
-	cache_reap();
-	mod_timer(rt, jiffies + REAPTIMEOUT_CPUC + cpu);
+	/* CPU hotplug can drag us off cpu: don't run on wrong CPU */
+	if (!cpu_is_offline(cpu)) {
+		cache_reap();
+		mod_timer(rt, jiffies + REAPTIMEOUT_CPUC + cpu);
+	}
 }
 
 #ifdef CONFIG_PROC_FS
@@ -2782,6 +2824,29 @@ struct seq_operations slabinfo_op = {
 	.show	= s_show,
 };
 
+static void do_dump_slabp(kmem_cache_t *cachep)
+{
+#if DEBUG
+	struct list_head *q;
+
+	check_irq_on();
+	spin_lock_irq(&cachep->spinlock);
+	list_for_each(q,&cachep->lists.slabs_full) {
+		struct slab *slabp;
+		int i;
+		slabp = list_entry(q, struct slab, list);
+		for (i = 0; i < cachep->num; i++) {
+			unsigned long sym = slab_bufctl(slabp)[i];
+
+			printk("obj %p/%d: %p", slabp, i, (void *)sym);
+			print_symbol(" <%s>", sym);
+			printk("\n");
+		}
+	}
+	spin_unlock_irq(&cachep->spinlock);
+#endif
+}
+
 #define MAX_SLABINFO_WRITE 128
 /**
  * slabinfo_write - Tuning for the slab allocator
@@ -2822,9 +2887,11 @@ ssize_t slabinfo_write(struct file *file
 			    batchcount < 1 ||
 			    batchcount > limit ||
 			    shared < 0) {
-				res = -EINVAL;
+				do_dump_slabp(cachep);
+				res = 0;
 			} else {
-				res = do_tune_cpucache(cachep, limit, batchcount, shared);
+				res = do_tune_cpucache(cachep, limit,
+							batchcount, shared);
 			}
 			break;
 		}
--- diff/mm/swap.c	2004-01-19 10:22:59.000000000 +0000
+++ source/mm/swap.c	2004-03-09 11:51:52.000000000 +0000
@@ -27,6 +27,9 @@
 #include <linux/module.h>
 #include <linux/percpu_counter.h>
 #include <linux/percpu.h>
+#include <linux/cpu.h>
+#include <linux/notifier.h>
+#include <linux/init.h>
 
 /* How many pages do we try to swap or page in/out together? */
 int page_cluster;
@@ -76,7 +79,7 @@ int rotate_reclaimable_page(struct page 
 /*
  * FIXME: speed this up?
  */
-void activate_page(struct page *page)
+void fastcall activate_page(struct page *page)
 {
 	struct zone *zone = page_zone(page);
 
@@ -97,7 +100,7 @@ void activate_page(struct page *page)
  * inactive,referenced		->	active,unreferenced
  * active,unreferenced		->	active,referenced
  */
-void mark_page_accessed(struct page *page)
+void fastcall mark_page_accessed(struct page *page)
 {
 	if (!PageActive(page) && PageReferenced(page) && PageLRU(page)) {
 		activate_page(page);
@@ -116,7 +119,7 @@ EXPORT_SYMBOL(mark_page_accessed);
 static DEFINE_PER_CPU(struct pagevec, lru_add_pvecs) = { 0, };
 static DEFINE_PER_CPU(struct pagevec, lru_add_active_pvecs) = { 0, };
 
-void lru_cache_add(struct page *page)
+void fastcall lru_cache_add(struct page *page)
 {
 	struct pagevec *pvec = &get_cpu_var(lru_add_pvecs);
 
@@ -126,7 +129,7 @@ void lru_cache_add(struct page *page)
 	put_cpu_var(lru_add_pvecs);
 }
 
-void lru_cache_add_active(struct page *page)
+void fastcall lru_cache_add_active(struct page *page)
 {
 	struct pagevec *pvec = &get_cpu_var(lru_add_active_pvecs);
 
@@ -152,7 +155,7 @@ void lru_add_drain(void)
  * This path almost never happens for VM activity - pages are normally
  * freed via pagevecs.  But it gets used by networking.
  */
-void __page_cache_release(struct page *page)
+void fastcall __page_cache_release(struct page *page)
 {
 	unsigned long flags;
 	struct zone *zone = page_zone(page);
@@ -381,7 +384,37 @@ void vm_acct_memory(long pages)
 	preempt_enable();
 }
 EXPORT_SYMBOL(vm_acct_memory);
-#endif
+
+#ifdef CONFIG_HOTPLUG_CPU
+static void lru_drain_cache(unsigned int cpu)
+{
+	struct pagevec *pvec = &per_cpu(lru_add_pvecs, cpu);
+
+	/* CPU is dead, so no locking needed. */
+	if (pagevec_count(pvec))
+		__pagevec_lru_add(pvec);
+	pvec = &per_cpu(lru_add_active_pvecs, cpu);
+	if (pagevec_count(pvec))
+		__pagevec_lru_add_active(pvec);
+}
+
+/* Drop the CPU's cached committed space back into the central pool. */
+static int cpu_swap_callback(struct notifier_block *nfb,
+			     unsigned long action,
+			     void *hcpu)
+{
+	long *committed;
+
+	committed = &per_cpu(committed_space, (long)hcpu);
+	if (action == CPU_DEAD) {
+		atomic_add(*committed, &vm_committed_space);
+		*committed = 0;
+		lru_drain_cache((long)hcpu);
+	}
+	return NOTIFY_OK;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+#endif /* CONFIG_SMP */
 
 #ifdef CONFIG_SMP
 void percpu_counter_mod(struct percpu_counter *fbc, long amount)
@@ -420,4 +453,5 @@ void __init swap_setup(void)
 	 * Right now other parts of the system means that we
 	 * _really_ don't want to cluster much more
 	 */
+	hotcpu_notifier(cpu_swap_callback, 0);
 }
--- diff/mm/swap_state.c	2003-08-20 14:16:34.000000000 +0100
+++ source/mm/swap_state.c	2004-03-09 11:51:52.000000000 +0000
@@ -38,6 +38,7 @@ struct address_space swapper_space = {
 	.truncate_count  = ATOMIC_INIT(0),
 	.private_lock	= SPIN_LOCK_UNLOCKED,
 	.private_list	= LIST_HEAD_INIT(swapper_space.private_list),
+	.wb_rwsema	= __RWSEM_INITIALIZER(swapper_space.wb_rwsema)
 };
 
 #define INC_CACHE_INFO(x)	do { swap_cache_info.x++; } while (0)
--- diff/mm/swapfile.c	2004-02-18 08:54:13.000000000 +0000
+++ source/mm/swapfile.c	2004-03-09 11:51:52.000000000 +0000
@@ -387,7 +387,7 @@ static void
 unuse_pte(struct vm_area_struct *vma, unsigned long address, pte_t *dir,
 	swp_entry_t entry, struct page *page, struct pte_chain **pte_chainp)
 {
-	vma->vm_mm->rss++;
+	inc_rss(vma->vm_mm, page);
 	get_page(page);
 	set_pte(dir, pte_mkold(mk_pte(page, vma->vm_page_prot)));
 	*pte_chainp = page_add_rmap(page, dir, *pte_chainp);
--- diff/mm/truncate.c	2003-10-09 09:47:34.000000000 +0100
+++ source/mm/truncate.c	2004-03-09 11:51:52.000000000 +0000
@@ -174,6 +174,14 @@ void truncate_inode_pages(struct address
 		}
 		pagevec_release(&pvec);
 	}
+
+	if (lstart == 0) {
+		WARN_ON(mapping->nrpages);
+		WARN_ON(!list_empty(&mapping->clean_pages));
+		WARN_ON(!list_empty(&mapping->dirty_pages));
+		WARN_ON(!list_empty(&mapping->locked_pages));
+		WARN_ON(!list_empty(&mapping->io_pages));
+	}
 }
 
 EXPORT_SYMBOL(truncate_inode_pages);
--- diff/mm/vmscan.c	2004-02-18 08:54:13.000000000 +0000
+++ source/mm/vmscan.c	2004-03-09 11:51:52.000000000 +0000
@@ -30,6 +30,8 @@
 #include <linux/backing-dev.h>
 #include <linux/rmap-locking.h>
 #include <linux/topology.h>
+#include <linux/cpu.h>
+#include <linux/notifier.h>
 
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
@@ -135,7 +137,7 @@ EXPORT_SYMBOL(remove_shrinker);
  *
  * We do weird things to avoid (scanned*seeks*entries) overflowing 32 bits.
  */
-static int shrink_slab(long scanned, unsigned int gfp_mask)
+static int shrink_slab(unsigned long scanned, unsigned int gfp_mask)
 {
 	struct shrinker *shrinker;
 	long pages;
@@ -147,7 +149,7 @@ static int shrink_slab(long scanned, uns
 	list_for_each_entry(shrinker, &shrinker_list, list) {
 		unsigned long long delta;
 
-		delta = 4 * (scanned / shrinker->seeks);
+		delta = 4 * scanned / shrinker->seeks;
 		delta *= (*shrinker->shrinker)(0, gfp_mask);
 		do_div(delta, pages + 1);
 		shrinker->nr += delta;
@@ -155,6 +157,7 @@ static int shrink_slab(long scanned, uns
 			long nr_to_scan = shrinker->nr;
 
 			shrinker->nr = 0;
+			mod_page_state(slabs_scanned, nr_to_scan);
 			while (nr_to_scan) {
 				long this_scan = nr_to_scan;
 
@@ -243,8 +246,7 @@ static void handle_write_error(struct ad
  * shrink_list returns the number of reclaimed pages
  */
 static int
-shrink_list(struct list_head *page_list, unsigned int gfp_mask,
-		int *max_scan, int *nr_mapped)
+shrink_list(struct list_head *page_list, unsigned int gfp_mask, int *nr_scanned)
 {
 	struct address_space *mapping;
 	LIST_HEAD(ret_pages);
@@ -268,7 +270,7 @@ shrink_list(struct list_head *page_list,
 
 		/* Double the slab pressure for mapped and swapcache pages */
 		if (page_mapped(page) || PageSwapCache(page))
-			(*nr_mapped)++;
+			(*nr_scanned)++;
 
 		BUG_ON(PageActive(page));
 
@@ -459,9 +461,6 @@ keep:
 	list_splice(&ret_pages, page_list);
 	if (pagevec_count(&freed_pvec))
 		__pagevec_release_nonlru(&freed_pvec);
-	mod_page_state(pgsteal, ret);
-	if (current_is_kswapd())
-		mod_page_state(kswapd_steal, ret);
 	mod_page_state(pgactivate, pgactivate);
 	return ret;
 }
@@ -471,39 +470,31 @@ keep:
  * a batch of pages and working on them outside the lock.  Any pages which were
  * not freed will be added back to the LRU.
  *
- * shrink_cache() is passed the number of pages to try to free, and returns
- * the number of pages which were reclaimed.
+ * shrink_cache() is passed the number of pages to scan and returns the number
+ * of pages which were reclaimed.
  *
  * For pagecache intensive workloads, the first loop here is the hottest spot
  * in the kernel (apart from the copy_*_user functions).
  */
 static int
-shrink_cache(const int nr_pages, struct zone *zone,
-		unsigned int gfp_mask, int max_scan, int *nr_mapped)
+shrink_cache(struct zone *zone, unsigned int gfp_mask,
+		int max_scan, int *total_scanned)
 {
 	LIST_HEAD(page_list);
 	struct pagevec pvec;
-	int nr_to_process;
 	int ret = 0;
 
-	/*
-	 * Try to ensure that we free `nr_pages' pages in one pass of the loop.
-	 */
-	nr_to_process = nr_pages;
-	if (nr_to_process < SWAP_CLUSTER_MAX)
-		nr_to_process = SWAP_CLUSTER_MAX;
-
 	pagevec_init(&pvec, 1);
 
 	lru_add_drain();
 	spin_lock_irq(&zone->lru_lock);
-	while (max_scan > 0 && ret < nr_pages) {
+	while (max_scan > 0) {
 		struct page *page;
 		int nr_taken = 0;
 		int nr_scan = 0;
 		int nr_freed;
 
-		while (nr_scan++ < nr_to_process &&
+		while (nr_scan++ < SWAP_CLUSTER_MAX &&
 				!list_empty(&zone->inactive_list)) {
 			page = list_entry(zone->inactive_list.prev,
 						struct page, lru);
@@ -532,9 +523,16 @@ shrink_cache(const int nr_pages, struct 
 			goto done;
 
 		max_scan -= nr_scan;
-		mod_page_state(pgscan, nr_scan);
-		nr_freed = shrink_list(&page_list, gfp_mask,
-					&max_scan, nr_mapped);
+		if (current_is_kswapd())
+			mod_page_state_zone(zone, pgscan_kswapd, nr_scan);
+		else
+			mod_page_state_zone(zone, pgscan_direct, nr_scan);
+		nr_freed = shrink_list(&page_list, gfp_mask, total_scanned);
+		*total_scanned += nr_taken;
+		if (current_is_kswapd())
+			mod_page_state(kswapd_steal, nr_freed);
+		mod_page_state_zone(zone, pgsteal, nr_freed);
+
 		ret += nr_freed;
 		if (nr_freed <= 0 && list_empty(&page_list))
 			goto done;
@@ -584,7 +582,7 @@ done:
  */
 static void
 refill_inactive_zone(struct zone *zone, const int nr_pages_in,
-			struct page_state *ps, int priority)
+			struct page_state *ps)
 {
 	int pgmoved;
 	int pgdeactivate = 0;
@@ -657,17 +655,17 @@ refill_inactive_zone(struct zone *zone, 
 		page = list_entry(l_hold.prev, struct page, lru);
 		list_del(&page->lru);
 		if (page_mapped(page)) {
-			pte_chain_lock(page);
-			if (page_mapped(page) && page_referenced(page)) {
-				pte_chain_unlock(page);
+			if (!reclaim_mapped) {
 				list_add(&page->lru, &l_active);
 				continue;
 			}
-			pte_chain_unlock(page);
-			if (!reclaim_mapped) {
+			pte_chain_lock(page);
+			if (page_referenced(page)) {
+				pte_chain_unlock(page);
 				list_add(&page->lru, &l_active);
 				continue;
 			}
+			pte_chain_unlock(page);
 		}
 		/*
 		 * FIXME: need to consider page_count(page) here if/when we
@@ -733,20 +731,20 @@ refill_inactive_zone(struct zone *zone, 
 	spin_unlock_irq(&zone->lru_lock);
 	pagevec_release(&pvec);
 
-	mod_page_state(pgrefill, nr_pages_in - nr_pages);
+	mod_page_state_zone(zone, pgrefill, nr_pages_in - nr_pages);
 	mod_page_state(pgdeactivate, pgdeactivate);
 }
 
 /*
- * Try to reclaim `nr_pages' from this zone.  Returns the number of reclaimed
- * pages.  This is a basic per-zone page freer.  Used by both kswapd and
- * direct reclaim.
+ * Scan `nr_pages' from this zone.  Returns the number of reclaimed pages.
+ * This is a basic per-zone page freer.  Used by both kswapd and direct reclaim.
  */
 static int
 shrink_zone(struct zone *zone, int max_scan, unsigned int gfp_mask,
-	const int nr_pages, int *nr_mapped, struct page_state *ps, int priority)
+		int *total_scanned, struct page_state *ps)
 {
 	unsigned long ratio;
+	int count;
 
 	/*
 	 * Try to keep the active list 2/3 of the size of the cache.  And
@@ -758,26 +756,23 @@ shrink_zone(struct zone *zone, int max_s
 	 * just to make sure that the kernel will slowly sift through the
 	 * active list.
 	 */
-	ratio = (unsigned long)nr_pages * zone->nr_active /
+	ratio = (unsigned long)SWAP_CLUSTER_MAX * zone->nr_active /
 				((zone->nr_inactive | 1) * 2);
-	atomic_add(ratio+1, &zone->refill_counter);
-	if (atomic_read(&zone->refill_counter) > SWAP_CLUSTER_MAX) {
-		int count;
 
-		/*
-		 * Don't try to bring down too many pages in one attempt.
-		 * If this fails, the caller will increase `priority' and
-		 * we'll try again, with an increased chance of reclaiming
-		 * mapped memory.
-		 */
-		count = atomic_read(&zone->refill_counter);
-		if (count > SWAP_CLUSTER_MAX * 4)
-			count = SWAP_CLUSTER_MAX * 4;
-		atomic_set(&zone->refill_counter, 0);
-		refill_inactive_zone(zone, count, ps, priority);
+	atomic_add(ratio+1, &zone->nr_scan_active);
+	count = atomic_read(&zone->nr_scan_active);
+	if (count >= SWAP_CLUSTER_MAX) {
+		atomic_set(&zone->nr_scan_active, 0);
+		refill_inactive_zone(zone, count, ps);
+	}
+
+	atomic_add(max_scan, &zone->nr_scan_inactive);
+	count = atomic_read(&zone->nr_scan_inactive);
+	if (count >= SWAP_CLUSTER_MAX) {
+		atomic_set(&zone->nr_scan_inactive, 0);
+		return shrink_cache(zone, gfp_mask, count, total_scanned);
 	}
-	return shrink_cache(nr_pages, zone, gfp_mask,
-				max_scan, nr_mapped);
+	return 0;
 }
 
 /*
@@ -798,15 +793,13 @@ shrink_zone(struct zone *zone, int max_s
  */
 static int
 shrink_caches(struct zone **zones, int priority, int *total_scanned,
-		int gfp_mask, int nr_pages, struct page_state *ps)
+		int gfp_mask, struct page_state *ps)
 {
 	int ret = 0;
 	int i;
 
 	for (i = 0; zones[i] != NULL; i++) {
-		int to_reclaim = max(nr_pages, SWAP_CLUSTER_MAX);
 		struct zone *zone = zones[i];
-		int nr_mapped = 0;
 		int max_scan;
 
 		if (zone->free_pages < zone->pages_high)
@@ -815,18 +808,8 @@ shrink_caches(struct zone **zones, int p
 		if (zone->all_unreclaimable && priority != DEF_PRIORITY)
 			continue;	/* Let kswapd poll it */
 
-		/*
-		 * If we cannot reclaim `nr_pages' pages by scanning twice
-		 * that many pages then fall back to the next zone.
-		 */
 		max_scan = zone->nr_inactive >> priority;
-		if (max_scan < to_reclaim * 2)
-			max_scan = to_reclaim * 2;
-		ret += shrink_zone(zone, max_scan, gfp_mask,
-				to_reclaim, &nr_mapped, ps, priority);
-		*total_scanned += max_scan + nr_mapped;
-		if (ret >= nr_pages)
-			break;
+		ret += shrink_zone(zone, max_scan, gfp_mask, total_scanned, ps);
 	}
 	return ret;
 }
@@ -853,7 +836,6 @@ int try_to_free_pages(struct zone **zone
 {
 	int priority;
 	int ret = 0;
-	const int nr_pages = SWAP_CLUSTER_MAX;
 	int nr_reclaimed = 0;
 	struct reclaim_state *reclaim_state = current->reclaim_state;
 	int i;
@@ -869,8 +851,13 @@ int try_to_free_pages(struct zone **zone
 
 		get_page_state(&ps);
 		nr_reclaimed += shrink_caches(zones, priority, &total_scanned,
-						gfp_mask, nr_pages, &ps);
-		if (nr_reclaimed >= nr_pages) {
+						gfp_mask, &ps);
+		shrink_slab(total_scanned, gfp_mask);
+		if (reclaim_state) {
+			nr_reclaimed += reclaim_state->reclaimed_slab;
+			reclaim_state->reclaimed_slab = 0;
+		}
+		if (nr_reclaimed >= SWAP_CLUSTER_MAX) {
 			ret = 1;
 			goto out;
 		}
@@ -884,14 +871,8 @@ int try_to_free_pages(struct zone **zone
 		wakeup_bdflush(total_scanned);
 
 		/* Take a nap, wait for some writeback to complete */
-		blk_congestion_wait(WRITE, HZ/10);
-		if (zones[0] - zones[0]->zone_pgdat->node_zones < ZONE_HIGHMEM) {
-			shrink_slab(total_scanned, gfp_mask);
-			if (reclaim_state) {
-				nr_reclaimed += reclaim_state->reclaimed_slab;
-				reclaim_state->reclaimed_slab = 0;
-			}
-		}
+		if (total_scanned && priority < DEF_PRIORITY - 2)
+			blk_congestion_wait(WRITE, HZ/10);
 	}
 	if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY))
 		out_of_memory();
@@ -918,6 +899,13 @@ out:
  * scanned twice and there has been zero successful reclaim.  Mark the zone as
  * dead and from now on, only perform a short scan.  Basically we're polling
  * the zone for when the problem goes away.
+ *
+ * kswapd scans the zones in the highmem->normal->dma direction.  It skips
+ * zones which have free_pages > pages_high, but once a zone is found to have
+ * free_pages <= pages_high, we scan that zone and the lower zones regardless
+ * of the number of free pages in the lower zones.  This interoperates with
+ * the page allocator fallback scheme to ensure that aging of pages is balanced
+ * across the zones.
  */
 static int balance_pgdat(pg_data_t *pgdat, int nr_pages, struct page_state *ps)
 {
@@ -936,48 +924,80 @@ static int balance_pgdat(pg_data_t *pgda
 
 	for (priority = DEF_PRIORITY; priority; priority--) {
 		int all_zones_ok = 1;
+		int pages_scanned = 0;
+		int end_zone = 0;	/* Inclusive.  0 = ZONE_DMA */
 
-		for (i = 0; i < pgdat->nr_zones; i++) {
+
+		if (nr_pages == 0) {
+			/*
+			 * Scan in the highmem->dma direction for the highest
+			 * zone which needs scanning
+			 */
+			for (i = pgdat->nr_zones - 1; i >= 0; i--) {
+				struct zone *zone = pgdat->node_zones + i;
+
+				if (zone->all_unreclaimable &&
+						priority != DEF_PRIORITY)
+					continue;
+
+				if (zone->free_pages <= zone->pages_high) {
+					end_zone = i;
+					goto scan;
+				}
+			}
+			goto out;
+		} else {
+			end_zone = pgdat->nr_zones - 1;
+		}
+scan:
+		/*
+		 * Now scan the zone in the dma->highmem direction, stopping
+		 * at the last zone which needs scanning.
+		 *
+		 * We do this because the page allocator works in the opposite
+		 * direction.  This prevents the page allocator from allocating
+		 * pages behind kswapd's direction of progress, which would
+		 * cause too much scanning of the lower zones.
+		 */
+		for (i = 0; i <= end_zone; i++) {
 			struct zone *zone = pgdat->node_zones + i;
-			int nr_mapped = 0;
+			int total_scanned = 0;
 			int max_scan;
-			int to_reclaim;
+			int reclaimed;
 
 			if (zone->all_unreclaimable && priority != DEF_PRIORITY)
 				continue;
 
-			if (nr_pages && to_free > 0) {	/* Software suspend */
-				to_reclaim = min(to_free, SWAP_CLUSTER_MAX*8);
-			} else {			/* Zone balancing */
-				to_reclaim = zone->pages_high-zone->free_pages;
-				if (to_reclaim <= 0)
-					continue;
+			if (nr_pages == 0) {	/* Not software suspend */
+				if (zone->free_pages <= zone->pages_high)
+					all_zones_ok = 0;
 			}
 			zone->temp_priority = priority;
-			all_zones_ok = 0;
 			max_scan = zone->nr_inactive >> priority;
-			if (max_scan < to_reclaim * 2)
-				max_scan = to_reclaim * 2;
-			if (max_scan < SWAP_CLUSTER_MAX)
-				max_scan = SWAP_CLUSTER_MAX;
-			to_free -= shrink_zone(zone, max_scan, GFP_KERNEL,
-					to_reclaim, &nr_mapped, ps, priority);
-			if (i < ZONE_HIGHMEM) {
-				reclaim_state->reclaimed_slab = 0;
-				shrink_slab(max_scan + nr_mapped, GFP_KERNEL);
-				to_free -= reclaim_state->reclaimed_slab;
-			}
+			reclaimed = shrink_zone(zone, max_scan, GFP_KERNEL,
+					&total_scanned, ps);
+			total_scanned += pages_scanned;
+			reclaim_state->reclaimed_slab = 0;
+			shrink_slab(total_scanned, GFP_KERNEL);
+			reclaimed += reclaim_state->reclaimed_slab;
+			to_free -= reclaimed;
 			if (zone->all_unreclaimable)
 				continue;
 			if (zone->pages_scanned > zone->present_pages * 2)
 				zone->all_unreclaimable = 1;
 		}
+		if (nr_pages && to_free > 0)
+			continue;	/* swsusp: need to do more work */
 		if (all_zones_ok)
-			break;
-		if (to_free > 0)
+			break;		/* kswapd: all done */
+		/*
+		 * OK, kswapd is getting into trouble.  Take a nap, then take
+		 * another pass across the zones.
+		 */
+		if (pages_scanned && priority < DEF_PRIORITY - 2)
 			blk_congestion_wait(WRITE, HZ/10);
 	}
-
+out:
 	for (i = 0; i < pgdat->nr_zones; i++) {
 		struct zone *zone = pgdat->node_zones + i;
 
@@ -1085,13 +1105,39 @@ int shrink_all_memory(int nr_pages)
 }
 #endif
 
+#ifdef CONFIG_HOTPLUG_CPU
+/* It's optimal to keep kswapds on the same CPUs as their memory, but
+   not required for correctness.  So if the last cpu in a node goes
+   away, we get changed to run anywhere: as the first one comes back,
+   restore their cpu bindings. */
+static int __devinit cpu_callback(struct notifier_block *nfb,
+				  unsigned long action,
+				  void *hcpu)
+{
+	pg_data_t *pgdat;
+	cpumask_t mask;
+
+	if (action == CPU_ONLINE) {
+		for_each_pgdat(pgdat) {
+			mask = node_to_cpumask(pgdat->node_id);
+			if (any_online_cpu(mask) != NR_CPUS)
+				/* One of our CPUs online: restore mask */
+				set_cpus_allowed(pgdat->kswapd, mask);
+		}
+	}
+	return NOTIFY_OK;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 static int __init kswapd_init(void)
 {
 	pg_data_t *pgdat;
 	swap_setup();
 	for_each_pgdat(pgdat)
-		kernel_thread(kswapd, pgdat, CLONE_KERNEL);
+		pgdat->kswapd
+		= find_task_by_pid(kernel_thread(kswapd, pgdat, CLONE_KERNEL));
 	total_memory = nr_free_pagecache_pages();
+	hotcpu_notifier(cpu_callback, 0);
 	return 0;
 }
 
--- diff/net/Kconfig	2004-03-04 11:41:49.000000000 +0000
+++ source/net/Kconfig	2004-03-09 11:51:52.000000000 +0000
@@ -71,6 +71,17 @@ config UNIX
 
 	  Say Y unless you know what you are doing.
 
+config IPMI_SOCKET
+	tristate "IPMI sockets"
+	depends on IPMI_HANDLER
+	---help---
+	  If you say Y here, you will include support for IPMI sockets;
+	  This way you don't have to use devices to access IPMI.  You
+	  must also enable the IPMI message handler and a low-level
+	  driver in the Character Drivers if you enable this.
+
+	  If unsure, say N.
+
 config NET_KEY
 	tristate "PF_KEY sockets"
 	select XFRM
@@ -658,4 +669,19 @@ source "net/irda/Kconfig"
 
 source "net/bluetooth/Kconfig"
 
+config KGDBOE
+	def_bool X86 && KGDB
+
+config NETPOLL
+	def_bool NETCONSOLE || KGDBOE
+
+config NETPOLL_RX
+	def_bool KGDBOE
+
+config NETPOLL_TRAP
+	def_bool KGDBOE
+
+config NET_POLL_CONTROLLER
+	def_bool NETPOLL
+
 endmenu
--- diff/net/Makefile	2003-10-09 09:47:34.000000000 +0100
+++ source/net/Makefile	2004-03-09 11:51:52.000000000 +0000
@@ -38,6 +38,7 @@ obj-$(CONFIG_DECNET)		+= decnet/
 obj-$(CONFIG_ECONET)		+= econet/
 obj-$(CONFIG_VLAN_8021Q)	+= 8021q/
 obj-$(CONFIG_IP_SCTP)		+= sctp/
+obj-$(CONFIG_IPMI_SOCKET)	+= ipmi/
 
 ifeq ($(CONFIG_NET),y)
 obj-$(CONFIG_SYSCTL)		+= sysctl_net.o
--- diff/net/bluetooth/hci_conn.c	2004-02-18 08:54:13.000000000 +0000
+++ source/net/bluetooth/hci_conn.c	2004-03-09 11:51:52.000000000 +0000
@@ -170,6 +170,9 @@ struct hci_conn *hci_conn_add(struct hci
 	hci_conn_hash_add(hdev, conn);
 	tasklet_enable(&hdev->tx_task);
 
+	if (hdev->notify)
+		hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);
+
 	return conn;
 }
 
@@ -196,6 +199,9 @@ int hci_conn_del(struct hci_conn *conn)
 		hdev->acl_cnt += conn->sent;
 	}
 
+	if (hdev->notify)
+		hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
+
 	tasklet_disable(&hdev->tx_task);
 	hci_conn_hash_del(hdev, conn);
 	tasklet_enable(&hdev->tx_task);
--- diff/net/bluetooth/hci_core.c	2004-03-04 11:41:49.000000000 +0000
+++ source/net/bluetooth/hci_core.c	2004-03-09 11:51:52.000000000 +0000
@@ -189,6 +189,10 @@ static void hci_init_req(struct hci_dev 
 
 	/* Mandatory initialization */
 
+	/* Reset */
+	if (test_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks))
+			hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL);
+
 	/* Read Local Supported Features */
 	hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES, 0, NULL);
 
--- diff/net/bluetooth/hci_event.c	2004-02-18 08:54:13.000000000 +0000
+++ source/net/bluetooth/hci_event.c	2004-03-09 11:51:52.000000000 +0000
@@ -232,6 +232,9 @@ static void hci_cc_host_ctl(struct hci_d
 			hdev->voice_setting = setting;
 
 			BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);
+
+			if (hdev->notify)
+				hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
 		}
 		break;
 
@@ -247,6 +250,9 @@ static void hci_cc_host_ctl(struct hci_d
 			hdev->voice_setting = setting;
 
 			BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);
+
+			if (hdev->notify)
+				hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
 		}
 		hci_req_complete(hdev, status);
 		break;
--- diff/net/bluetooth/rfcomm/core.c	2004-03-04 11:41:49.000000000 +0000
+++ source/net/bluetooth/rfcomm/core.c	2004-03-09 11:51:52.000000000 +0000
@@ -50,7 +50,7 @@
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/rfcomm.h>
 
-#define VERSION "1.1"
+#define VERSION "1.2"
 
 #ifndef CONFIG_BT_RFCOMM_DEBUG
 #undef  BT_DBG
@@ -409,7 +409,7 @@ int rfcomm_dlc_send(struct rfcomm_dlc *d
 	return len;
 }
 
-void __rfcomm_dlc_throttle(struct rfcomm_dlc *d)
+void fastcall __rfcomm_dlc_throttle(struct rfcomm_dlc *d)
 {
 	BT_DBG("dlc %p state %ld", d, d->state);
 
@@ -420,7 +420,7 @@ void __rfcomm_dlc_throttle(struct rfcomm
 	rfcomm_schedule(RFCOMM_SCHED_TX);
 }
 
-void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
+void fastcall __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
 {
 	BT_DBG("dlc %p state %ld", d, d->state);
 
--- diff/net/bluetooth/rfcomm/tty.c	2004-02-18 08:54:13.000000000 +0000
+++ source/net/bluetooth/rfcomm/tty.c	2004-03-09 11:51:52.000000000 +0000
@@ -50,6 +50,8 @@
 #define RFCOMM_TTY_MAJOR 216		/* device node major id of the usb/bluetooth.c driver */
 #define RFCOMM_TTY_MINOR 0
 
+static struct tty_driver *rfcomm_tty_driver;
+
 struct rfcomm_dev {
 	struct list_head	list;
 	atomic_t		refcnt;
@@ -98,6 +100,8 @@ static void rfcomm_dev_destruct(struct r
 
 	rfcomm_dlc_put(dlc);
 
+	tty_unregister_device(rfcomm_tty_driver, dev->id);
+
 	/* Refcount should only hit zero when called from rfcomm_dev_del()
 	   which will have taken us off the list. Everything else are
 	   refcounting bugs. */
@@ -239,8 +243,11 @@ out:
 	if (err) {
 		kfree(dev);
 		return err;
-	} else
-		return dev->id;
+	}
+
+	tty_register_device(rfcomm_tty_driver, dev->id, NULL);
+
+	return dev->id;
 }
 
 static void rfcomm_dev_del(struct rfcomm_dev *dev)
@@ -871,8 +878,6 @@ static int rfcomm_tty_tiocmset(struct tt
 
 /* ---- TTY structure ---- */
 
-static struct tty_driver *rfcomm_tty_driver;
-
 static struct tty_operations rfcomm_ops = {
 	.open			= rfcomm_tty_open,
 	.close			= rfcomm_tty_close,
@@ -906,7 +911,7 @@ int rfcomm_init_ttys(void)
 	rfcomm_tty_driver->minor_start	= RFCOMM_TTY_MINOR;
 	rfcomm_tty_driver->type		= TTY_DRIVER_TYPE_SERIAL;
 	rfcomm_tty_driver->subtype	= SERIAL_TYPE_NORMAL;
-	rfcomm_tty_driver->flags	= TTY_DRIVER_REAL_RAW;
+	rfcomm_tty_driver->flags	= TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
 	rfcomm_tty_driver->init_termios	= tty_std_termios;
 	rfcomm_tty_driver->init_termios.c_cflag	= B9600 | CS8 | CREAD | HUPCL | CLOCAL;
 	tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);
--- diff/net/core/Makefile	2003-09-17 12:28:12.000000000 +0100
+++ source/net/core/Makefile	2004-03-09 11:51:52.000000000 +0000
@@ -13,3 +13,4 @@ obj-$(CONFIG_NETFILTER) += netfilter.o
 obj-$(CONFIG_NET_DIVERT) += dv.o
 obj-$(CONFIG_NET_PKTGEN) += pktgen.o
 obj-$(CONFIG_NET_RADIO) += wireless.o
+obj-$(CONFIG_NETPOLL) += netpoll.o
--- diff/net/core/dev.c	2004-03-04 11:41:49.000000000 +0000
+++ source/net/core/dev.c	2004-03-09 11:51:52.000000000 +0000
@@ -105,6 +105,8 @@
 #include <linux/kmod.h>
 #include <linux/module.h>
 #include <linux/kallsyms.h>
+#include <linux/cpu.h>
+#include <linux/netpoll.h>
 #ifdef CONFIG_NET_RADIO
 #include <linux/wireless.h>		/* Note : will define WIRELESS_EXT */
 #include <net/iw_handler.h>
@@ -1513,7 +1515,6 @@ static void sample_queue(unsigned long d
 }
 #endif
 
-
 /**
  *	netif_rx	-	post buffer to the network code
  *	@skb: buffer to post
@@ -1538,6 +1539,13 @@ int netif_rx(struct sk_buff *skb)
 	struct softnet_data *queue;
 	unsigned long flags;
 
+#ifdef CONFIG_NETPOLL_RX
+	if (skb->dev->netpoll_rx && netpoll_rx(skb)) {
+		kfree_skb(skb);
+		return NET_RX_DROP;
+	}
+#endif
+
 	if (!skb->stamp.tv_sec)
 		do_gettimeofday(&skb->stamp);
 
@@ -1693,6 +1701,13 @@ int netif_receive_skb(struct sk_buff *sk
 	int ret = NET_RX_DROP;
 	unsigned short type;
 
+#ifdef CONFIG_NETPOLL_RX
+	if (skb->dev->netpoll_rx && skb->dev->poll && netpoll_rx(skb)) {
+		kfree_skb(skb);
+		return NET_RX_DROP;
+	}
+#endif
+
 	if (!skb->stamp.tv_sec)
 		do_gettimeofday(&skb->stamp);
 
@@ -1819,7 +1834,6 @@ static void net_rx_action(struct softirq
 	unsigned long start_time = jiffies;
 	int budget = netdev_max_backlog;
 
-	
 	preempt_disable();
 	local_irq_disable();
 
@@ -1846,6 +1860,10 @@ static void net_rx_action(struct softirq
 			dev_put(dev);
 			local_irq_disable();
 		}
+
+#ifdef CONFIG_KGDBOE
+		kgdb_process_breakpoint();
+#endif
 	}
 out:
 	local_irq_enable();
@@ -3116,6 +3134,52 @@ int unregister_netdevice(struct net_devi
 	return 0;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int dev_cpu_callback(struct notifier_block *nfb,
+			    unsigned long action,
+			    void *ocpu)
+{
+	struct sk_buff **list_skb;
+	struct net_device **list_net;
+	struct sk_buff *skb;
+	unsigned int cpu, oldcpu = (unsigned long)ocpu;
+	struct softnet_data *sd, *oldsd;
+
+	if (action != CPU_DEAD)
+		return NOTIFY_OK;
+
+	local_irq_disable();
+	cpu = smp_processor_id();
+	sd = &per_cpu(softnet_data, cpu);
+	oldsd = &per_cpu(softnet_data, oldcpu);
+
+	/* Find end of our completion_queue. */
+	list_skb = &sd->completion_queue;
+	while (*list_skb)
+		list_skb = &(*list_skb)->next;
+	/* Append completion queue from offline CPU. */
+	*list_skb = oldsd->completion_queue;
+	oldsd->completion_queue = NULL;
+
+	/* Find end of our output_queue. */
+	list_net = &sd->output_queue;
+	while (*list_net)
+		list_net = &(*list_net)->next_sched;
+	/* Append output queue from offline CPU. */
+	*list_net = oldsd->output_queue;
+	oldsd->output_queue = NULL;
+
+	raise_softirq_irqoff(NET_TX_SOFTIRQ);
+	local_irq_enable();
+
+	/* Process offline CPU's input_pkt_queue */
+	while ((skb = __skb_dequeue(&oldsd->input_pkt_queue)))
+		netif_rx(skb);
+
+	return NOTIFY_OK;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 
 /*
  *	Initialize the DEV module. At boot time this walks the device list and
@@ -3182,6 +3246,7 @@ static int __init net_dev_init(void)
 
 	dst_init();
 	dev_mcast_init();
+	hotcpu_notifier(dev_cpu_callback, 0);
 	rc = 0;
 out:
 	return rc;
--- diff/net/core/flow.c	2004-02-18 08:54:13.000000000 +0000
+++ source/net/core/flow.c	2004-03-09 11:51:52.000000000 +0000
@@ -326,6 +326,17 @@ static void __devinit flow_cache_cpu_pre
 	tasklet_init(tasklet, flow_cache_flush_tasklet, 0);
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int flow_cache_cpu(struct notifier_block *nfb,
+			  unsigned long action,
+			  void *hcpu)
+{
+	if (action == CPU_DEAD)
+		__flow_cache_shrink((unsigned long)hcpu, 0);
+	return NOTIFY_OK;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 static int __init flow_cache_init(void)
 {
 	int i;
@@ -350,6 +361,7 @@ static int __init flow_cache_init(void)
 	for_each_cpu(i)
 		flow_cache_cpu_prepare(i);
 
+	hotcpu_notifier(flow_cache_cpu, 0);
 	return 0;
 }
 
--- diff/net/ipv4/igmp.c	2004-02-18 08:54:13.000000000 +0000
+++ source/net/ipv4/igmp.c	2004-03-09 11:51:52.000000000 +0000
@@ -105,7 +105,8 @@
 #include <linux/seq_file.h>
 #endif
 
-#define IP_MAX_MEMBERSHIPS 20
+#define IP_MAX_MEMBERSHIPS	20
+#define IP_MAX_MSF		10
 
 #ifdef CONFIG_IP_MULTICAST
 /* Parameter names and values are taken from igmp-v2-06 draft */
@@ -1325,6 +1326,7 @@ static struct in_device * ip_mc_find_dev
  *	Join a socket to a group
  */
 int sysctl_igmp_max_memberships = IP_MAX_MEMBERSHIPS;
+int sysctl_igmp_max_msf = IP_MAX_MSF;
 
 
 static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode,
@@ -1790,6 +1792,10 @@ int ip_mc_source(int add, int omode, str
 	}
 	/* else, add a new source to the filter */
 
+	if (psl && psl->sl_count >= sysctl_igmp_max_msf) {
+		err = -ENOBUFS;
+		goto done;
+	}
 	if (!psl || psl->sl_count == psl->sl_max) {
 		struct ip_sf_socklist *newpsl;
 		int count = IP_SFBLOCK;
--- diff/net/ipv4/ip_sockglue.c	2004-03-04 11:41:49.000000000 +0000
+++ source/net/ipv4/ip_sockglue.c	2004-03-09 11:51:52.000000000 +0000
@@ -618,6 +618,7 @@ int ip_setsockopt(struct sock *sk, int l
 		case IP_MSFILTER:
 		{
 			extern int sysctl_optmem_max;
+			extern int sysctl_igmp_max_msf;
 			struct ip_msfilter *msf;
 
 			if (optlen < IP_MSFILTER_SIZE(0))
@@ -636,9 +637,14 @@ int ip_setsockopt(struct sock *sk, int l
 				kfree(msf);
 				break;
 			}
-			if (IP_MSFILTER_SIZE(msf->imsf_numsrc) < 
-			    IP_MSFILTER_SIZE(0) ||
-			    IP_MSFILTER_SIZE(msf->imsf_numsrc) > optlen) {
+			/* numsrc >= (1G-4) overflow in 32 bits */
+			if (msf->imsf_numsrc >= 0x3ffffffcU ||
+			    msf->imsf_numsrc > sysctl_igmp_max_msf) {
+				kfree(msf);
+				err = -ENOBUFS;
+				break;
+			}
+			if (IP_MSFILTER_SIZE(msf->imsf_numsrc) > optlen) {
 				kfree(msf);
 				err = -EINVAL;
 				break;
--- diff/net/ipv4/ipconfig.c	2004-03-04 11:41:49.000000000 +0000
+++ source/net/ipv4/ipconfig.c	2004-03-09 11:51:52.000000000 +0000
@@ -1189,12 +1189,47 @@ static struct file_operations pnp_seq_fo
 #endif /* CONFIG_PROC_FS */
 
 /*
+ *  Extract IP address from the parameter string if needed. Note that we
+ *  need to have root_server_addr set _before_ IPConfig gets called as it
+ *  can override it.
+ */
+u32 __init root_nfs_parse_addr(char *name)
+{
+	u32 addr;
+	int octets = 0;
+	char *cp, *cq;
+
+	cp = cq = name;
+	while (octets < 4) {
+		while (*cp >= '0' && *cp <= '9')
+			cp++;
+		if (cp == cq || cp - cq > 3)
+			break;
+		if (*cp == '.' || octets == 3)
+			octets++;
+		if (octets < 4)
+			cp++;
+		cq = cp;
+	}
+	if (octets == 4 && (*cp == ':' || *cp == '\0')) {
+		if (*cp == ':')
+			*cp++ = '\0';
+		addr = in_aton(name);
+		strcpy(name, cp);
+	} else
+		addr = INADDR_NONE;
+
+	return addr;
+}
+
+/*
  *	IP Autoconfig dispatcher.
  */
 
 static int __init ip_auto_config(void)
 {
 	unsigned long jiff;
+	u32 addr;
 
 #ifdef CONFIG_PROC_FS
 	proc_net_fops_create("pnp", S_IRUGO, &pnp_seq_fops);
@@ -1283,6 +1318,10 @@ static int __init ip_auto_config(void)
 		ic_dev = ic_first_dev->dev;
 	}
 
+	addr = root_nfs_parse_addr(root_server_path);
+	if (root_server_addr == INADDR_NONE)
+		root_server_addr = addr;
+
 	/*
 	 * Use defaults whereever applicable.
 	 */
--- diff/net/ipv4/sysctl_net_ipv4.c	2004-02-18 08:54:13.000000000 +0000
+++ source/net/ipv4/sysctl_net_ipv4.c	2004-03-09 11:51:52.000000000 +0000
@@ -39,6 +39,7 @@ extern int sysctl_icmp_ratemask;
 
 /* From igmp.c */
 extern int sysctl_igmp_max_memberships;
+extern int sysctl_igmp_max_msf;
 
 /* From inetpeer.c */
 extern int inet_peer_threshold;
@@ -412,6 +413,14 @@ ctl_table ipv4_table[] = {
 
 #endif
 	{
+		.ctl_name	= NET_IPV4_IGMP_MAX_MSF,
+		.procname	= "igmp_max_msf",
+		.data		= &sysctl_igmp_max_msf,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec
+	},
+	{
 		.ctl_name	= NET_IPV4_INET_PEER_THRESHOLD,
 		.procname	= "inet_peer_threshold",
 		.data		= &inet_peer_threshold,
--- diff/net/sunrpc/auth_gss/svcauth_gss.c	2004-03-04 11:41:49.000000000 +0000
+++ source/net/sunrpc/auth_gss/svcauth_gss.c	2004-03-09 11:51:52.000000000 +0000
@@ -594,12 +594,13 @@ gss_write_verf(struct svc_rqst *rqstp, s
 	iov.iov_len = sizeof(xdr_seq);
 	xdr_buf_from_iov(&iov, &verf_data);
 	p = rqstp->rq_res.head->iov_base + rqstp->rq_res.head->iov_len;
+	mic.data = (u8 *)(p + 1);
 	maj_stat = gss_get_mic(ctx_id, 0, &verf_data, &mic);
 	if (maj_stat != GSS_S_COMPLETE)
 		return -1;
-	p = xdr_encode_netobj(rqstp->rq_res.head->iov_base
-				+ rqstp->rq_res.head->iov_len, &mic);
-	kfree(mic.data);
+	*p++ = htonl(mic.len);
+	memset((u8 *)p + mic.len, 0, round_up_to_quad(mic.len) - mic.len);
+	p += XDR_QUADLEN(mic.len);
 	if (!xdr_ressize_check(rqstp, p))
 		return -1;
 	return 0;
--- diff/net/sunrpc/auth_unix.c	2004-03-04 11:41:49.000000000 +0000
+++ source/net/sunrpc/auth_unix.c	2004-03-09 11:51:52.000000000 +0000
@@ -149,7 +149,7 @@ unx_marshal(struct rpc_task *task, u32 *
 	struct rpc_clnt	*clnt = task->tk_client;
 	struct unx_cred	*cred = (struct unx_cred *) task->tk_msg.rpc_cred;
 	u32		*base, *hold;
-	int		i, n;
+	int		i;
 
 	*p++ = htonl(RPC_AUTH_UNIX);
 	base = p++;
@@ -158,10 +158,7 @@ unx_marshal(struct rpc_task *task, u32 *
 	/*
 	 * Copy the UTS nodename captured when the client was created.
 	 */
-	n = clnt->cl_nodelen;
-	*p++ = htonl(n);
-	memcpy(p, clnt->cl_nodename, n);
-	p += (n + 3) >> 2;
+	p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen);
 
 	/* Note: we don't use real uid if it involves raising privilege */
 	if (ruid && cred->uc_puid != 0 && cred->uc_pgid != 0) {
--- diff/net/sunrpc/clnt.c	2004-02-18 08:54:13.000000000 +0000
+++ source/net/sunrpc/clnt.c	2004-03-09 11:51:52.000000000 +0000
@@ -102,19 +102,22 @@ rpc_create_client(struct rpc_xprt *xprt,
 {
 	struct rpc_version	*version;
 	struct rpc_clnt		*clnt = NULL;
+	int err;
 	int len;
 
 	dprintk("RPC: creating %s client for %s (xprt %p)\n",
 		program->name, servname, xprt);
 
+	err = -EINVAL;
 	if (!xprt)
-		goto out;
+		goto out_err;
 	if (vers >= program->nrvers || !(version = program->version[vers]))
-		goto out;
+		goto out_err;
 
+	err = -ENOMEM;
 	clnt = (struct rpc_clnt *) kmalloc(sizeof(*clnt), GFP_KERNEL);
 	if (!clnt)
-		goto out_no_clnt;
+		goto out_err;
 	memset(clnt, 0, sizeof(*clnt));
 	atomic_set(&clnt->cl_users, 0);
 	atomic_set(&clnt->cl_count, 1);
@@ -149,9 +152,11 @@ rpc_create_client(struct rpc_xprt *xprt,
 	clnt->cl_rtt = &clnt->cl_rtt_default;
 	rpc_init_rtt(&clnt->cl_rtt_default, xprt->timeout.to_initval);
 
-	if (rpc_setup_pipedir(clnt, program->pipe_dir_name) < 0)
+	err = rpc_setup_pipedir(clnt, program->pipe_dir_name);
+	if (err < 0)
 		goto out_no_path;
 
+	err = -ENOMEM;
 	if (!rpcauth_create(flavor, clnt)) {
 		printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %u)\n",
 				flavor);
@@ -163,20 +168,16 @@ rpc_create_client(struct rpc_xprt *xprt,
 	if (clnt->cl_nodelen > UNX_MAXNODENAME)
 		clnt->cl_nodelen = UNX_MAXNODENAME;
 	memcpy(clnt->cl_nodename, system_utsname.nodename, clnt->cl_nodelen);
-out:
 	return clnt;
 
-out_no_clnt:
-	printk(KERN_INFO "RPC: out of memory in rpc_create_client\n");
-	goto out;
 out_no_auth:
 	rpc_rmdir(clnt->cl_pathname);
 out_no_path:
 	if (clnt->cl_server != clnt->cl_inline_name)
 		kfree(clnt->cl_server);
 	kfree(clnt);
-	clnt = NULL;
-	goto out;
+out_err:
+	return ERR_PTR(err);
 }
 
 /*
@@ -198,11 +199,10 @@ rpc_clone_client(struct rpc_clnt *clnt)
 	atomic_inc(&new->cl_parent->cl_count);
 	if (new->cl_auth)
 		atomic_inc(&new->cl_auth->au_count);
-out:
 	return new;
 out_no_clnt:
 	printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__);
-	goto out;
+	return ERR_PTR(-ENOMEM);
 }
 
 /*
@@ -611,9 +611,6 @@ call_encode(struct rpc_task *task)
 	rcvbuf->page_len	 = 0;
 	rcvbuf->len		 = bufsiz;
 
-	/* Zero buffer so we have automatic zero-padding of opaque & string */
-	memset(task->tk_buffer, 0, bufsiz);
-
 	/* Encode header and provided arguments */
 	encode = task->tk_msg.rpc_proc->p_encode;
 	if (!(p = call_header(task))) {
--- diff/net/sunrpc/pmap_clnt.c	2004-02-18 08:54:13.000000000 +0000
+++ source/net/sunrpc/pmap_clnt.c	2004-03-09 11:51:52.000000000 +0000
@@ -65,9 +65,11 @@ rpc_getport(struct rpc_task *task, struc
 	map->pm_binding = 1;
 	spin_unlock(&pmap_lock);
 
-	task->tk_status = -EACCES; /* why set this? returns -EIO below */
-	if (!(pmap_clnt = pmap_create(clnt->cl_server, sap, map->pm_prot)))
+	pmap_clnt = pmap_create(clnt->cl_server, sap, map->pm_prot);
+	if (IS_ERR(pmap_clnt)) {
+		task->tk_status = PTR_ERR(pmap_clnt);
 		goto bailout;
+	}
 	task->tk_status = 0;
 
 	/*
@@ -110,8 +112,9 @@ rpc_getport_external(struct sockaddr_in 
 			NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
 
 	sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr));
-	if (!(pmap_clnt = pmap_create(hostname, sin, prot)))
-		return -EACCES;
+	pmap_clnt = pmap_create(hostname, sin, prot);
+	if (IS_ERR(pmap_clnt))
+		return PTR_ERR(pmap_clnt);
 
 	/* Setup the call info struct */
 	status = rpc_call(pmap_clnt, PMAP_GETPORT, &map, &map.pm_port, 0);
@@ -161,16 +164,18 @@ rpc_register(u32 prog, u32 vers, int pro
 	struct sockaddr_in	sin;
 	struct rpc_portmap	map;
 	struct rpc_clnt		*pmap_clnt;
-	unsigned int		error = 0;
+	int error = 0;
 
 	dprintk("RPC: registering (%d, %d, %d, %d) with portmapper.\n",
 			prog, vers, prot, port);
 
 	sin.sin_family = AF_INET;
 	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-	if (!(pmap_clnt = pmap_create("localhost", &sin, IPPROTO_UDP))) {
-		dprintk("RPC: couldn't create pmap client\n");
-		return -EACCES;
+	pmap_clnt = pmap_create("localhost", &sin, IPPROTO_UDP);
+	if (IS_ERR(pmap_clnt)) {
+		error = PTR_ERR(pmap_clnt);
+		dprintk("RPC: couldn't create pmap client. Error = %d\n", error);
+		return error;
 	}
 
 	map.pm_prog = prog;
@@ -199,15 +204,16 @@ pmap_create(char *hostname, struct socka
 	struct rpc_clnt	*clnt;
 
 	/* printk("pmap: create xprt\n"); */
-	if (!(xprt = xprt_create_proto(proto, srvaddr, NULL)))
-		return NULL;
+	xprt = xprt_create_proto(proto, srvaddr, NULL);
+	if (IS_ERR(xprt))
+		return (struct rpc_clnt *)xprt;
 	xprt->addr.sin_port = htons(RPC_PMAP_PORT);
 
 	/* printk("pmap: create clnt\n"); */
 	clnt = rpc_create_client(xprt, hostname,
 				&pmap_program, RPC_PMAP_VERSION,
 				RPC_AUTH_NULL);
-	if (!clnt) {
+	if (IS_ERR(clnt)) {
 		xprt_destroy(xprt);
 	} else {
 		clnt->cl_softrtry = 1;
--- diff/net/sunrpc/sched.c	2004-03-04 11:41:49.000000000 +0000
+++ source/net/sunrpc/sched.c	2004-03-09 11:51:52.000000000 +0000
@@ -530,6 +530,9 @@ __rpc_execute(struct rpc_task *task)
 			if (!task->tk_action)
 				break;
 			task->tk_action(task);
+			/* micro-optimization to avoid spinlock */
+			if (RPC_IS_RUNNING(task))
+				continue;
 		}
 
 		/*
@@ -545,29 +548,31 @@ __rpc_execute(struct rpc_task *task)
 		}
 		spin_unlock_bh(&rpc_queue_lock);
 
-		while (RPC_IS_SLEEPING(task)) {
-			/* sync task: sleep here */
-			dprintk("RPC: %4d sync task going to sleep\n",
-							task->tk_pid);
-			if (current->pid == rpciod_pid)
-				printk(KERN_ERR "RPC: rpciod waiting on sync task!\n");
+		if (!RPC_IS_SLEEPING(task))
+			continue;
+		/* sync task: sleep here */
+		dprintk("RPC: %4d sync task going to sleep\n", task->tk_pid);
+		if (current->pid == rpciod_pid)
+			printk(KERN_ERR "RPC: rpciod waiting on sync task!\n");
 
+		if (!task->tk_client->cl_intr) {
 			__wait_event(task->tk_wait, !RPC_IS_SLEEPING(task));
-			dprintk("RPC: %4d sync task resuming\n", task->tk_pid);
-
+		} else {
+			__wait_event_interruptible(task->tk_wait, !RPC_IS_SLEEPING(task), status);
 			/*
 			 * When a sync task receives a signal, it exits with
 			 * -ERESTARTSYS. In order to catch any callbacks that
 			 * clean up after sleeping on some queue, we don't
 			 * break the loop here, but go around once more.
 			 */
-			if (task->tk_client->cl_intr && signalled()) {
+			if (status == -ERESTARTSYS) {
 				dprintk("RPC: %4d got signal\n", task->tk_pid);
 				task->tk_flags |= RPC_TASK_KILLED;
 				rpc_exit(task, -ERESTARTSYS);
 				rpc_wake_up_task(task);
 			}
 		}
+		dprintk("RPC: %4d sync task resuming\n", task->tk_pid);
 	}
 
 	if (task->tk_exit) {
--- diff/net/sunrpc/sunrpc_syms.c	2004-03-04 11:41:49.000000000 +0000
+++ source/net/sunrpc/sunrpc_syms.c	2004-03-09 11:51:52.000000000 +0000
@@ -63,6 +63,8 @@ EXPORT_SYMBOL(rpc_mkpipe);
 EXPORT_SYMBOL(xprt_create_proto);
 EXPORT_SYMBOL(xprt_destroy);
 EXPORT_SYMBOL(xprt_set_timeout);
+EXPORT_SYMBOL(xprt_udp_slot_table_entries);
+EXPORT_SYMBOL(xprt_tcp_slot_table_entries);
 
 /* Client credential cache */
 EXPORT_SYMBOL(rpcauth_register);
--- diff/net/sunrpc/sysctl.c	2004-02-09 10:36:12.000000000 +0000
+++ source/net/sunrpc/sysctl.c	2004-03-09 11:51:52.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * linux/net/sunrpc/sysctl.c
  *
- * Sysctl interface to sunrpc module. This is for debugging only now.
+ * Sysctl interface to sunrpc module.
  *
  * I would prefer to register the sunrpc table below sys/net, but that's
  * impossible at the moment.
@@ -19,6 +19,7 @@
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/sched.h>
 #include <linux/sunrpc/stats.h>
+#include <linux/sunrpc/xprt.h>
 
 /*
  * Declare the debug flags here
@@ -117,6 +118,9 @@ done:
 	return 0;
 }
 
+static unsigned int min_slot_table_size = RPC_MIN_SLOT_TABLE;
+static unsigned int max_slot_table_size = RPC_MAX_SLOT_TABLE;
+
 static ctl_table debug_table[] = {
 	{
 		.ctl_name	= CTL_RPCDEBUG,
@@ -150,6 +154,28 @@ static ctl_table debug_table[] = {
 		.mode		= 0644,
 		.proc_handler	= &proc_dodebug
 	}, 
+	{
+		.ctl_name	= CTL_SLOTTABLE_UDP,
+		.procname	= "udp_slot_table_entries",
+		.data		= &xprt_udp_slot_table_entries,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_minmax,
+		.strategy	= &sysctl_intvec,
+		.extra1		= &min_slot_table_size,
+		.extra2		= &max_slot_table_size
+	},
+	{
+		.ctl_name	= CTL_SLOTTABLE_TCP,
+		.procname	= "tcp_slot_table_entries",
+		.data		= &xprt_tcp_slot_table_entries,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_minmax,
+		.strategy	= &sysctl_intvec,
+		.extra1		= &min_slot_table_size,
+		.extra2		= &max_slot_table_size
+	},
 	{ .ctl_name = 0 }
 };
 
--- diff/net/sunrpc/xdr.c	2004-02-18 08:54:13.000000000 +0000
+++ source/net/sunrpc/xdr.c	2004-03-09 11:51:52.000000000 +0000
@@ -54,7 +54,7 @@ xdr_decode_netobj(u32 *p, struct xdr_net
 }
 
 u32 *
-xdr_encode_array(u32 *p, const char *array, unsigned int len)
+xdr_encode_array(u32 *p, const void *array, unsigned int len)
 {
 	int quadlen = XDR_QUADLEN(len);
 
--- diff/net/sunrpc/xprt.c	2004-03-04 11:41:49.000000000 +0000
+++ source/net/sunrpc/xprt.c	2004-03-09 11:51:52.000000000 +0000
@@ -57,6 +57,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/file.h>
 #include <linux/workqueue.h>
+#include <linux/random.h>
 
 #include <net/sock.h>
 #include <net/checksum.h>
@@ -74,6 +75,7 @@
 
 #define XPRT_MAX_BACKOFF	(8)
 #define XPRT_IDLE_TIMEOUT	(5*60*HZ)
+#define XPRT_MAX_RESVPORT	(800)
 
 /*
  * Local functions
@@ -84,7 +86,7 @@ static void	xprt_disconnect(struct rpc_x
 static void	xprt_connect_status(struct rpc_task *task);
 static struct rpc_xprt * xprt_setup(int proto, struct sockaddr_in *ap,
 						struct rpc_timeout *to);
-static struct socket *xprt_create_socket(int, struct rpc_timeout *, int);
+static struct socket *xprt_create_socket(struct rpc_xprt *, int, int);
 static void	xprt_bind_socket(struct rpc_xprt *, struct socket *);
 static int      __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
 
@@ -336,8 +338,8 @@ xprt_adjust_cwnd(struct rpc_xprt *xprt, 
 		/* The (cwnd >> 1) term makes sure
 		 * the result gets rounded properly. */
 		cwnd += (RPC_CWNDSCALE * RPC_CWNDSCALE + (cwnd >> 1)) / cwnd;
-		if (cwnd > RPC_MAXCWND)
-			cwnd = RPC_MAXCWND;
+		if (cwnd > RPC_MAXCWND(xprt))
+			cwnd = RPC_MAXCWND(xprt);
 		__xprt_lock_write_next(xprt);
 	} else if (result == -ETIMEDOUT) {
 		cwnd >>= 1;
@@ -452,6 +454,68 @@ out_abort:
 	spin_unlock(&xprt->sock_lock);
 }
 
+static void
+xprt_socket_connect(void *args)
+{
+	struct rpc_xprt *xprt = (struct rpc_xprt *)args;
+	struct socket *sock = xprt->sock;
+	int status = -EIO;
+
+	if (xprt->shutdown) {
+		rpc_wake_up_status(&xprt->pending, -EIO);
+		return;
+	}
+	if (!xprt->addr.sin_port)
+		goto out_err;
+
+	/*
+	 * Start by resetting any existing state
+	 */
+	xprt_close(xprt);
+	sock = xprt_create_socket(xprt, xprt->prot, xprt->resvport);
+	if (sock == NULL) {
+		/* couldn't create socket or bind to reserved port;
+		 * this is likely a permanent error, so cause an abort */
+		goto out_err;
+		return;
+	}
+	xprt_bind_socket(xprt, sock);
+	xprt_sock_setbufsize(xprt);
+
+	if (!xprt->stream)
+		goto out;
+
+	/*
+	 * Tell the socket layer to start connecting...
+	 */
+	status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr,
+			sizeof(xprt->addr), O_NONBLOCK);
+	dprintk("RPC: %p  connect status %d connected %d sock state %d\n",
+			xprt, -status, xprt_connected(xprt), sock->sk->sk_state);
+	if (status >= 0)
+		goto out;
+	switch (status) {
+		case -EINPROGRESS:
+		case -EALREADY:
+			return;
+		default:
+			goto out_err;
+	}
+out:
+	spin_lock_bh(&xprt->sock_lock);
+	if (xprt->snd_task)
+		rpc_wake_up_task(xprt->snd_task);
+	spin_unlock_bh(&xprt->sock_lock);
+	return;
+out_err:
+	spin_lock_bh(&xprt->sock_lock);
+	if (xprt->snd_task) {
+		xprt->snd_task->tk_status = status;
+		rpc_wake_up_task(xprt->snd_task);
+	}
+	spin_unlock_bh(&xprt->sock_lock);
+}
+
 /*
  * Attempt to connect a TCP socket.
  *
@@ -460,9 +524,6 @@ void
 xprt_connect(struct rpc_task *task)
 {
 	struct rpc_xprt	*xprt = task->tk_xprt;
-	struct socket	*sock = xprt->sock;
-	struct sock	*inet;
-	int		status;
 
 	dprintk("RPC: %4d xprt_connect xprt %p %s connected\n", task->tk_pid,
 			xprt, (xprt_connected(xprt) ? "is" : "is not"));
@@ -483,79 +544,9 @@ xprt_connect(struct rpc_task *task)
 	if (task->tk_rqstp)
 		task->tk_rqstp->rq_bytes_sent = 0;
 
-	/*
-	 * We're here because the xprt was marked disconnected.
-	 * Start by resetting any existing state.
-	 */
-	xprt_close(xprt);
-	if (!(sock = xprt_create_socket(xprt->prot, &xprt->timeout, xprt->resvport))) {
-		/* couldn't create socket or bind to reserved port;
-		 * this is likely a permanent error, so cause an abort */
-		task->tk_status = -EIO;
-		goto out_write;
-	}
-	xprt_bind_socket(xprt, sock);
-	xprt_sock_setbufsize(xprt);
-
-	if (!xprt->stream)
-		goto out_write;
-
-	inet = sock->sk;
-
-	/*
-	 * Tell the socket layer to start connecting...
-	 */
-	status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr,
-				sizeof(xprt->addr), O_NONBLOCK);
-	dprintk("RPC: %4d  connect status %d connected %d sock state %d\n",
-		task->tk_pid, -status, xprt_connected(xprt), inet->sk_state);
-
-	if (status >= 0)
-		return;
-
-	switch (status) {
-	case -EINPROGRESS:
-	case -EALREADY:
-		/* Protect against TCP socket state changes */
-		lock_sock(inet);
-		if (inet->sk_state != TCP_ESTABLISHED) {
-			dprintk("RPC: %4d  waiting for connection\n",
-					task->tk_pid);
-			task->tk_timeout = RPC_CONNECT_TIMEOUT;
-			/* if the socket is already closing, delay briefly */
-			if ((1 << inet->sk_state) &
-			    ~(TCPF_SYN_SENT | TCPF_SYN_RECV))
-				task->tk_timeout = RPC_REESTABLISH_TIMEOUT;
-			rpc_sleep_on(&xprt->pending, task, xprt_connect_status,
-									NULL);
-		}
-		release_sock(inet);
-		break;
-	case -ECONNREFUSED:
-	case -ECONNRESET:
-	case -ENOTCONN:
-		if (!RPC_IS_SOFT(task)) {
-			rpc_delay(task, RPC_REESTABLISH_TIMEOUT);
-			task->tk_status = -ENOTCONN;
-			break;
-		}
-	default:
-		/* Report myriad other possible returns.  If this file
-		 * system is soft mounted, just error out, like Solaris.  */
-		if (RPC_IS_SOFT(task)) {
-			printk(KERN_WARNING
-			"RPC: error %d connecting to server %s, exiting\n",
-					-status, task->tk_client->cl_server);
-			task->tk_status = -EIO;
-			goto out_write;
-		}
-		printk(KERN_WARNING "RPC: error %d connecting to server %s\n",
-				-status, task->tk_client->cl_server);
-		/* This will prevent anybody else from reconnecting */
-		rpc_delay(task, RPC_REESTABLISH_TIMEOUT);
-		task->tk_status = status;
-		break;
-	}
+	task->tk_timeout = RPC_CONNECT_TIMEOUT;
+	rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL);
+	schedule_work(&xprt->sock_connect);
 	return;
  out_write:
 	xprt_release_write(xprt, task);
@@ -580,6 +571,8 @@ xprt_connect_status(struct rpc_task *tas
 		task->tk_status = -EIO;
 
 	switch (task->tk_status) {
+	case -ECONNREFUSED:
+	case -ECONNRESET:
 	case -ENOTCONN:
 		rpc_delay(task, RPC_REESTABLISH_TIMEOUT);
 		return;
@@ -1313,10 +1306,9 @@ do_xprt_reserve(struct rpc_task *task)
 	task->tk_status = 0;
 	if (task->tk_rqstp)
 		return;
-	if (xprt->free) {
-		struct rpc_rqst	*req = xprt->free;
-		xprt->free = req->rq_next;
-		req->rq_next = NULL;
+	if (!list_empty(&xprt->free)) {
+		struct rpc_rqst	*req = list_entry(xprt->free.next, struct rpc_rqst, rq_list);
+		list_del_init(&req->rq_list);
 		task->tk_rqstp = req;
 		xprt_request_init(task, xprt);
 		return;
@@ -1330,22 +1322,14 @@ do_xprt_reserve(struct rpc_task *task)
 /*
  * Allocate a 'unique' XID
  */
-static u32
-xprt_alloc_xid(void)
+static inline u32 xprt_alloc_xid(struct rpc_xprt *xprt)
+{
+	return xprt->xid++;
+}
+
+static inline void xprt_init_xid(struct rpc_xprt *xprt)
 {
-	static spinlock_t xid_lock = SPIN_LOCK_UNLOCKED;
-	static int need_init = 1;
-	static u32 xid;
-	u32 ret;
-
-	spin_lock(&xid_lock);
-	if (unlikely(need_init)) {
-		xid = get_seconds() << 12;
-		need_init = 0;
-	}
-	ret = xid++;
-	spin_unlock(&xid_lock);
-	return ret;
+	get_random_bytes(&xprt->xid, sizeof(xprt->xid));
 }
 
 /*
@@ -1359,8 +1343,7 @@ xprt_request_init(struct rpc_task *task,
 	req->rq_timeout = xprt->timeout;
 	req->rq_task	= task;
 	req->rq_xprt    = xprt;
-	req->rq_xid     = xprt_alloc_xid();
-	INIT_LIST_HEAD(&req->rq_list);
+	req->rq_xid     = xprt_alloc_xid(xprt);
 	dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid,
 			req, req->rq_xid);
 }
@@ -1391,9 +1374,7 @@ xprt_release(struct rpc_task *task)
 	dprintk("RPC: %4d release request %p\n", task->tk_pid, req);
 
 	spin_lock(&xprt->xprt_lock);
-	req->rq_next = xprt->free;
-	xprt->free   = req;
-
+	list_add(&req->rq_list, &xprt->free);
 	xprt_clear_backlog(xprt);
 	spin_unlock(&xprt->xprt_lock);
 }
@@ -1424,6 +1405,9 @@ xprt_set_timeout(struct rpc_timeout *to,
 	to->to_exponential = 0;
 }
 
+unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE;
+unsigned int xprt_tcp_slot_table_entries = RPC_DEF_SLOT_TABLE << 2;
+
 /*
  * Initialize an RPC client
  */
@@ -1431,21 +1415,33 @@ static struct rpc_xprt *
 xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to)
 {
 	struct rpc_xprt	*xprt;
+	unsigned int entries;
+	size_t slot_table_size;
 	struct rpc_rqst	*req;
-	int		i;
 
 	dprintk("RPC:      setting up %s transport...\n",
 				proto == IPPROTO_UDP? "UDP" : "TCP");
 
+	entries = (proto == IPPROTO_TCP)?
+		xprt_tcp_slot_table_entries : xprt_udp_slot_table_entries;
+
 	if ((xprt = kmalloc(sizeof(struct rpc_xprt), GFP_KERNEL)) == NULL)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 	memset(xprt, 0, sizeof(*xprt)); /* Nnnngh! */
+	xprt->max_reqs = entries;
+	slot_table_size = entries * sizeof(xprt->slot[0]);
+	xprt->slot = kmalloc(slot_table_size, GFP_KERNEL);
+	if (xprt->slot == NULL) {
+		kfree(xprt);
+		return ERR_PTR(-ENOMEM);
+	}
+	memset(xprt->slot, 0, slot_table_size);
 
 	xprt->addr = *ap;
 	xprt->prot = proto;
 	xprt->stream = (proto == IPPROTO_TCP)? 1 : 0;
 	if (xprt->stream) {
-		xprt->cwnd = RPC_MAXCWND;
+		xprt->cwnd = RPC_MAXCWND(xprt);
 		xprt->nocong = 1;
 	} else
 		xprt->cwnd = RPC_INITCWND;
@@ -1453,12 +1449,15 @@ xprt_setup(int proto, struct sockaddr_in
 	spin_lock_init(&xprt->xprt_lock);
 	init_waitqueue_head(&xprt->cong_wait);
 
+	INIT_LIST_HEAD(&xprt->free);
 	INIT_LIST_HEAD(&xprt->recv);
+	INIT_WORK(&xprt->sock_connect, xprt_socket_connect, xprt);
 	INIT_WORK(&xprt->task_cleanup, xprt_socket_autoclose, xprt);
 	init_timer(&xprt->timer);
 	xprt->timer.function = xprt_init_autodisconnect;
 	xprt->timer.data = (unsigned long) xprt;
 	xprt->last_used = jiffies;
+	xprt->port = XPRT_MAX_RESVPORT;
 
 	/* Set timeout parameters */
 	if (to) {
@@ -1473,15 +1472,16 @@ xprt_setup(int proto, struct sockaddr_in
 	INIT_RPC_WAITQ(&xprt->backlog, "xprt_backlog");
 
 	/* initialize free list */
-	for (i = 0, req = xprt->slot; i < RPC_MAXREQS-1; i++, req++)
-		req->rq_next = req + 1;
-	req->rq_next = NULL;
-	xprt->free = xprt->slot;
+	for (req = &xprt->slot[entries-1]; req >= &xprt->slot[0]; req--)
+		list_add(&req->rq_list, &xprt->free);
+
+	xprt_init_xid(xprt);
 
 	/* Check whether we want to use a reserved port */
 	xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
 
-	dprintk("RPC:      created transport %p\n", xprt);
+	dprintk("RPC:      created transport %p with %u slots\n", xprt,
+			xprt->max_reqs);
 	
 	return xprt;
 }
@@ -1490,30 +1490,28 @@ xprt_setup(int proto, struct sockaddr_in
  * Bind to a reserved port
  */
 static inline int
-xprt_bindresvport(struct socket *sock)
+xprt_bindresvport(struct rpc_xprt *xprt, struct socket *sock)
 {
-	struct sockaddr_in myaddr;
+	struct sockaddr_in myaddr = {
+		.sin_family = AF_INET,
+	};
 	int		err, port;
-	kernel_cap_t saved_cap = current->cap_effective;
 
-	/* Override capabilities.
-	 * They were checked in xprt_create_proto i.e. at mount time
-	 */
-	cap_raise(current->cap_effective, CAP_NET_BIND_SERVICE);
-
-	memset(&myaddr, 0, sizeof(myaddr));
-	myaddr.sin_family = AF_INET;
-	port = 800;
+	/* Were we already bound to a given port? Try to reuse it */
+	port = xprt->port;
 	do {
 		myaddr.sin_port = htons(port);
 		err = sock->ops->bind(sock, (struct sockaddr *) &myaddr,
 						sizeof(myaddr));
-	} while (err == -EADDRINUSE && --port > 0);
-	current->cap_effective = saved_cap;
-
-	if (err < 0)
-		printk("RPC: Can't bind to reserved port (%d).\n", -err);
+		if (err == 0) {
+			xprt->port = port;
+			return 0;
+		}
+		if (--port == 0)
+			port = XPRT_MAX_RESVPORT;
+	} while (err == -EADDRINUSE && port != xprt->port);
 
+	printk("RPC: Can't bind to reserved port (%d).\n", -err);
 	return err;
 }
 
@@ -1563,11 +1561,11 @@ xprt_sock_setbufsize(struct rpc_xprt *xp
 		return;
 	if (xprt->rcvsize) {
 		sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
-		sk->sk_rcvbuf = xprt->rcvsize * RPC_MAXCONG * 2;
+		sk->sk_rcvbuf = xprt->rcvsize * xprt->max_reqs *  2;
 	}
 	if (xprt->sndsize) {
 		sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
-		sk->sk_sndbuf = xprt->sndsize * RPC_MAXCONG * 2;
+		sk->sk_sndbuf = xprt->sndsize * xprt->max_reqs * 2;
 		sk->sk_write_space(sk);
 	}
 }
@@ -1577,7 +1575,7 @@ xprt_sock_setbufsize(struct rpc_xprt *xp
  * and connect stream sockets.
  */
 static struct socket *
-xprt_create_socket(int proto, struct rpc_timeout *to, int resvport)
+xprt_create_socket(struct rpc_xprt *xprt, int proto, int resvport)
 {
 	struct socket	*sock;
 	int		type, err;
@@ -1593,7 +1591,7 @@ xprt_create_socket(int proto, struct rpc
 	}
 
 	/* If the caller has the capability, bind to a reserved port */
-	if (resvport && xprt_bindresvport(sock) < 0) {
+	if (resvport && xprt_bindresvport(xprt, sock) < 0) {
 		printk("RPC: can't bind to reserved port.\n");
 		goto failed;
 	}
@@ -1614,16 +1612,11 @@ xprt_create_proto(int proto, struct sock
 	struct rpc_xprt	*xprt;
 
 	xprt = xprt_setup(proto, sap, to);
-	if (!xprt)
-		goto out_bad;
-
-	dprintk("RPC:      xprt_create_proto created xprt %p\n", xprt);
+	if (IS_ERR(xprt))
+		dprintk("RPC:      xprt_create_proto failed\n");
+	else
+		dprintk("RPC:      xprt_create_proto created xprt %p\n", xprt);
 	return xprt;
- out_bad:
-	dprintk("RPC:      xprt_create_proto failed\n");
-	if (xprt)
-		kfree(xprt);
-	return NULL;
 }
 
 /*
@@ -1662,6 +1655,7 @@ xprt_destroy(struct rpc_xprt *xprt)
 	dprintk("RPC:      destroying transport %p\n", xprt);
 	xprt_shutdown(xprt);
 	xprt_close(xprt);
+	kfree(xprt->slot);
 	kfree(xprt);
 
 	return 0;
--- diff/scripts/modpost.c	2004-03-04 11:41:49.000000000 +0000
+++ source/scripts/modpost.c	2004-03-09 11:51:52.000000000 +0000
@@ -64,17 +64,20 @@ new_module(char *modname)
 {
 	struct module *mod;
 	char *p;
+	size_t len;
 	
 	mod = NOFAIL(malloc(sizeof(*mod)));
 	memset(mod, 0, sizeof(*mod));
-	mod->name = NOFAIL(strdup(modname));
+	p = NOFAIL(strdup(modname));
+
+	len = strlen(p);
 
 	/* strip trailing .o */
-	p = strstr(mod->name, ".o");
-	if (p)
-		*p = 0;
+	if (len > 2 && p[len-2] == '.' && p[len-1] == 'o')
+		p[len -2] = '\0';
 
 	/* add to list */
+	mod->name = NOFAIL(strdup(p));
 	mod->next = modules;
 	modules = mod;
 
--- diff/security/dummy.c	2004-03-04 11:41:49.000000000 +0000
+++ source/security/dummy.c	2004-03-09 11:51:52.000000000 +0000
@@ -194,7 +194,8 @@ static void dummy_sb_free_security (stru
 	return;
 }
 
-static int dummy_sb_copy_data (const char *fstype, void *orig, void *copy)
+static int dummy_sb_copy_data (struct file_system_type *type,
+			       void *orig, void *copy)
 {
 	return 0;
 }
--- diff/security/selinux/hooks.c	2004-03-04 11:41:49.000000000 +0000
+++ source/security/selinux/hooks.c	2004-03-09 11:51:52.000000000 +0000
@@ -331,25 +331,24 @@ static int try_context_mount(struct supe
 
 	name = sb->s_type->name;
 
-	/* Ignore these fileystems with binary mount option data. */
-	if (!strcmp(name, "coda") ||
-	    !strcmp(name, "afs") || !strcmp(name, "smbfs"))
-		goto out;
+	if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) {
 
-	/* NFS we understand. */
-	if (!strcmp(name, "nfs")) {
-		struct nfs_mount_data *d = data;
+		/* NFS we understand. */
+		if (!strcmp(name, "nfs")) {
+			struct nfs_mount_data *d = data;
 
-		if (d->version <  NFS_MOUNT_VERSION)
-			goto out;
+			if (d->version <  NFS_MOUNT_VERSION)
+				goto out;
 
-		if (d->context[0]) {
-			context = d->context;
-			seen |= Opt_context;
-		}
+			if (d->context[0]) {
+				context = d->context;
+				seen |= Opt_context;
+			}
+		} else
+			goto out;
 
-	/* Standard string-based options. */
 	} else {
+		/* Standard string-based options. */
 		char *p, *options = data;
 
 		while ((p = strsep(&options, ",")) != NULL) {
@@ -751,6 +750,7 @@ static int inode_doinit_with_dentry(stru
 			       inode->i_ino);
 			goto out;
 		}
+               BUG_ON(inode != dentry->d_inode);
 
 		len = INITCONTEXTLEN;
 		context = kmalloc(len, GFP_KERNEL);
@@ -1885,7 +1885,7 @@ static inline void take_option(char **to
 	*to += len;
 }
 
-static int selinux_sb_copy_data(const char *fstype, void *orig, void *copy)
+static int selinux_sb_copy_data(struct file_system_type *type, void *orig, void *copy)
 {
 	int fnosec, fsec, rc = 0;
 	char *in_save, *in_curr, *in_end;
@@ -1895,8 +1895,7 @@ static int selinux_sb_copy_data(const ch
 	sec_curr = copy;
 
 	/* Binary mount data: just copy */
-	if (!strcmp(fstype, "nfs") || !strcmp(fstype, "coda") ||
-	    !strcmp(fstype, "smbfs") || !strcmp(fstype, "afs")) {
+	if (type->fs_flags & FS_BINARY_MOUNTDATA) {
 		copy_page(sec_curr, in_curr);
 		goto out;
 	}
--- diff/sound/arm/Kconfig	2002-11-11 11:09:38.000000000 +0000
+++ source/sound/arm/Kconfig	2004-03-09 11:51:52.000000000 +0000
@@ -6,6 +6,7 @@ menu "ALSA ARM devices"
 config SND_SA11XX_UDA1341
 	tristate "SA11xx UDA1341TS driver (H3600)"
 	depends on ARCH_SA1100 && SND && L3
+	select SND_PCM
 	help
 	  Say Y or M if you have a Compaq iPaq H3x00 handheld computer and want
 	  to use its Philips UDA 1341 audio chip.
--- diff/sound/arm/sa11xx-uda1341.c	2003-08-26 10:00:55.000000000 +0100
+++ source/sound/arm/sa11xx-uda1341.c	2004-03-09 11:51:52.000000000 +0000
@@ -21,7 +21,7 @@
  *                              merged HAL layer (patches from Brian)
  */
 
-/* $Id: sa11xx-uda1341.c,v 1.12 2003/08/13 13:14:31 tiwai Exp $ */
+/* $Id: sa11xx-uda1341.c,v 1.13 2004/03/02 15:32:35 perex Exp $ */
 
 /***************************************************************************************************
 *
@@ -840,7 +840,9 @@ static int __init snd_card_sa11xx_uda134
 	 * isa works but I'm not sure why (or if) it's the right choice
 	 * this may be too large, trying it for now
 	 */
-	snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, 64*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_ISA, 
+					      snd_pcm_dma_flags(0),
+					      64*1024, 64*1024);
 
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_sa11xx_uda1341_playback_ops);
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_sa11xx_uda1341_capture_ops);
--- diff/sound/core/Kconfig	2003-06-30 10:07:24.000000000 +0100
+++ source/sound/core/Kconfig	2004-03-09 11:51:52.000000000 +0000
@@ -3,9 +3,23 @@ config SND_BIT32_EMUL
 	tristate "Emulation for 32-bit applications"
 	depends on SND && (SPARC64 || PPC64 || X86_64 && IA32_EMULATION)
 
+config SND_TIMER
+	tristate
+
+config SND_PCM
+	tristate
+	select SND_TIMER
+
+config SND_HWDEP
+	tristate
+
+config SND_RAWMIDI
+	tristate
+
 config SND_SEQUENCER
 	tristate "Sequencer support"
 	depends on SND
+	select SND_TIMER
 	help
 	  Say 'Y' or 'M' to enable MIDI sequencer and router support. This feature
 	  allows routing and enqueing MIDI events. Events can be processed at given
@@ -20,26 +34,27 @@ config SND_SEQ_DUMMY
 	  immediately.
 
 config SND_OSSEMUL
-	bool "OSS API emulation"
-	depends on SND
-	help
-	  Say 'Y' to enable OSS (Open Sound System) API emulation code.
+	bool
 
 config SND_MIXER_OSS
 	tristate "OSS Mixer API"
-	depends on SND_OSSEMUL && SND
+	depends on SND
+	select SND_OSSEMUL
 	help
 	  Say 'Y' or 'M' to enable mixer OSS API emulation (/dev/mixer*).
 
 config SND_PCM_OSS
 	tristate "OSS PCM (digital audio) API"
-	depends on SND_OSSEMUL && SND
+	depends on SND
+	select SND_OSSEMUL
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to enable digital audio (PCM) OSS API emulation (/dev/dsp*).
 
 config SND_SEQUENCER_OSS
 	bool "OSS Sequencer API"
-	depends on SND_OSSEMUL && SND_SEQUENCER
+	depends on SND_SEQUENCER
+	select SND_OSSEMUL
 	help
 	  Say 'Y' to enable OSS sequencer emulation (both /dev/sequencer and
 	  /dev/music interfaces).
@@ -47,6 +62,7 @@ config SND_SEQUENCER_OSS
 config SND_RTCTIMER
 	tristate "RTC Timer support"
 	depends on SND && RTC
+	select SND_TIMER
 	help
 	  Say 'Y' or 'M' to enable RTC timer support for ALSA. ALSA code uses RTC
 	  timer as precise timing source and maps the RTC timer to the ALSA's timer
--- diff/sound/core/Makefile	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/core/Makefile	2004-03-09 11:51:52.000000000 +0000
@@ -15,97 +15,20 @@ endif
 snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
 		pcm_memory.o
 
-snd-page-alloc-objs := memalloc.o
-ifeq ($(CONFIG_PCI),y)
-snd-page-alloc-objs += sgbuf.o
-endif
+snd-page-alloc-objs := memalloc.o sgbuf.o
 
 snd-rawmidi-objs  := rawmidi.o
 snd-timer-objs    := timer.o
 snd-rtctimer-objs := rtctimer.o
 snd-hwdep-objs    := hwdep.o
 
-obj-$(CONFIG_SND) += snd.o
-ifeq ($(subst m,y,$(CONFIG_RTC)),y)
-  obj-$(CONFIG_SND_RTCTIMER) += snd-timer.o
-  obj-$(CONFIG_SND_RTCTIMER) += snd-rtctimer.o
-endif
-obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o
+obj-$(CONFIG_SND) 		+= snd.o
+obj-$(CONFIG_SND_HWDEP)		+= snd-hwdep.o
+obj-$(CONFIG_SND_TIMER)		+= snd-timer.o
+obj-$(CONFIG_SND_RTCTIMER)	+= snd-rtctimer.o
+obj-$(CONFIG_SND_PCM)		+= snd-pcm.o snd-page-alloc.o
+obj-$(CONFIG_SND_RAWMIDI)	+= snd-rawmidi.o
 
-obj-$(CONFIG_SND_MIXER_OSS) += oss/
-obj-$(CONFIG_SND_PCM_OSS) += snd-pcm.o snd-timer.o snd-page-alloc.o oss/
-obj-$(CONFIG_SND_SEQUENCER) += snd-timer.o seq/
+obj-$(CONFIG_SND_OSSEMUL)	+= oss/
+obj-$(CONFIG_SND_SEQUENCER)	+= seq/
 obj-$(CONFIG_SND_BIT32_EMUL) += ioctl32/
-
-# Toplevel Module Dependency
-obj-$(CONFIG_SND_DUMMY) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
-obj-$(CONFIG_SND_VIRMIDI) += snd-rawmidi.o snd.o snd-timer.o
-obj-$(CONFIG_SND_SERIAL_U16550) += snd-rawmidi.o snd.o snd-timer.o
-obj-$(CONFIG_SND_MTPAV) += snd-rawmidi.o snd.o snd-timer.o
-obj-$(CONFIG_SND_MPU401) += snd-rawmidi.o snd.o snd-timer.o
-obj-$(CONFIG_SND_ALS100) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_AZT2320) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_AZT3328) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_CMI8330) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
-obj-$(CONFIG_SND_DT019X) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_ES18XX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_OPL3SA2) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_SGALAXY) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
-obj-$(CONFIG_SND_AD1816A) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_AD1848) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
-obj-$(CONFIG_SND_CS4231) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_CS4232) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_CS4236) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_ES1688) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_GUSCLASSIC) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_GUSMAX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_GUSEXTREME) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_INTERWAVE) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_INTERWAVE_STB) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_OPTI93X) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_SB8) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_SB16) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_SBAWE) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_ES968) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_WAVEFRONT) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_SSCAPE) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_ALS4000) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_CMIPCI) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_CS4281) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_ENS1370) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_ENS1371) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_ES1938) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o snd-rawmidi.o
-obj-$(CONFIG_SND_ES1968) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_FM801) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_ICE1712) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_ICE1724) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_INTEL8X0) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_MAESTRO3) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
-obj-$(CONFIG_SND_RME32) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
-obj-$(CONFIG_SND_RME96) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
-obj-$(CONFIG_SND_SONICVIBES) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_VIA82XX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_ALI5451) += snd.o snd-rawmidi.o snd-timer.o snd-page-alloc.o snd-pcm.o
-obj-$(CONFIG_SND_CS46XX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_EMU10K1) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_KORG1212) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
-obj-$(CONFIG_SND_NM256) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
-obj-$(CONFIG_SND_RME9652) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
-obj-$(CONFIG_SND_HDSP) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_TRIDENT) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_YMFPCI) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_POWERMAC) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
-obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
-obj-$(CONFIG_SND_PC98_CS4232) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_USB_AUDIO) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_SUN_AMD7930) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
-obj-$(CONFIG_SND_SUN_CS4231) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
-obj-$(CONFIG_SND_HARMONY) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
-obj-$(CONFIG_SND_VXPOCKET) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o
-obj-$(CONFIG_SND_VXP440) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o
-obj-$(CONFIG_SND_VX222) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o
-obj-$(CONFIG_SND_BT87X) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
-
-obj-m := $(sort $(obj-m))
--- diff/sound/core/init.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/core/init.c	2004-03-09 11:51:52.000000000 +0000
@@ -79,6 +79,7 @@ snd_card_t *snd_card_new(int idx, const 
 			goto __error;
 		strlcpy(card->id, xid, sizeof(card->id));
 	}
+	err = 0;
 	write_lock(&snd_card_rwlock);
 	if (idx < 0) {
 		int idx2;
@@ -94,15 +95,14 @@ snd_card_t *snd_card_new(int idx, const 
 			idx = snd_ecards_limit++;
 	} else if (idx < snd_ecards_limit) {
 		if (snd_cards_lock & (1 << idx))
-			idx = -1;	/* invalid */
+			err = -ENODEV;	/* invalid */
 	} else if (idx < SNDRV_CARDS)
 		snd_ecards_limit = idx + 1; /* increase the limit */
 	else
-		idx = -1;
-	if (idx < 0) {
+		err = -ENODEV;
+	if (idx < 0 || err < 0) {
 		write_unlock(&snd_card_rwlock);
-		if (idx >= snd_ecards_limit)
-			snd_printk(KERN_ERR "card %i is out of range (0-%i)\n", idx, snd_ecards_limit-1);
+		snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i)\n", idx, snd_ecards_limit - 1);
 		goto __error;
 	}
 	snd_cards_lock |= 1 << idx;		/* lock it */
--- diff/sound/core/memalloc.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/core/memalloc.c	2004-03-09 11:51:52.000000000 +0000
@@ -25,10 +25,15 @@
 #include <linux/module.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
+#include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
+#include <linux/dma-mapping.h>
 #include <asm/semaphore.h>
 #include <sound/memalloc.h>
+#ifdef CONFIG_SBUS
+#include <asm/sbus.h>
+#endif
 
 
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@suse.cz>");
@@ -43,6 +48,13 @@ static int enable[SNDRV_CARDS] = {[0 ...
 MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(enable, "Enable cards to allocate buffers.");
 
+/*
+ */
+
+void *snd_malloc_sgbuf_pages(const struct snd_dma_device *dev,
+                             size_t size, struct snd_dma_buffer *dmab,
+			     size_t *res_size);
+int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab);
 
 /*
  */
@@ -73,14 +85,40 @@ struct snd_mem_list {
 #define snd_assert(expr, args...) /**/
 #endif
 
-#ifdef CONFIG_PCI
+/*
+ *  Hacks
+ */
+
+static void *snd_dma_alloc_coherent1(struct device *dev, size_t size,
+				     dma_addr_t *dma_handle, int flags)
+{
+	if (dev)
+		return dma_alloc_coherent(dev, size, dma_handle, flags);
+	else /* FIXME: dma_alloc_coherent does't always accept dev=NULL */
+		return pci_alloc_consistent(NULL, size, dma_handle);
+}
+
+static void snd_dma_free_coherent1(struct device *dev, size_t size, void *dma_addr,
+				   dma_addr_t dma_handle)
+{
+	if (dev)
+		return dma_free_coherent(dev, size, dma_addr, dma_handle);
+	else
+		return pci_free_consistent(NULL, size, dma_addr, dma_handle);
+}
+
+#undef dma_alloc_coherent
+#define dma_alloc_coherent snd_dma_alloc_coherent1
+#undef dma_free_coherent
+#define dma_free_coherent snd_dma_free_coherent1
+
+
 #if defined(__i386__) || defined(__ppc__) || defined(__x86_64__)
-#define HACK_PCI_ALLOC_CONSISTENT
 
 /*
- * A hack to allocate large buffers via pci_alloc_consistent()
+ * A hack to allocate large buffers via dma_alloc_coherent()
  *
- * since pci_alloc_consistent always tries GFP_DMA when the requested
+ * since dma_alloc_coherent always tries GFP_DMA when the requested
  * pci memory region is below 32bit, it happens quite often that even
  * 2 order of pages cannot be allocated.
  *
@@ -88,46 +126,248 @@ struct snd_mem_list {
  * allocation will be done without GFP_DMA.  if the area doesn't match
  * with the requested region, then realloate with the original dma_mask
  * again.
+ *
+ * Really, we want to move this type of thing into dma_alloc_coherent()
+ * so dma_mask doesn't have to be messed with.
  */
 
-static void *snd_pci_hack_alloc_consistent(struct pci_dev *hwdev, size_t size,
-				    dma_addr_t *dma_handle)
+static void *snd_dma_hack_alloc_coherent(struct device *dev, size_t size,
+					 dma_addr_t *dma_handle, int flags)
 {
 	void *ret;
-	u64 dma_mask, cdma_mask;
-	unsigned long mask;
+	u64 dma_mask;
 
-	if (hwdev == NULL)
-		return pci_alloc_consistent(hwdev, size, dma_handle);
-	dma_mask = hwdev->dma_mask;
-	cdma_mask = hwdev->consistent_dma_mask;
-	mask = (unsigned long)dma_mask && (unsigned long)cdma_mask;
-	hwdev->dma_mask = 0xffffffff; /* do without masking */
-	hwdev->consistent_dma_mask = 0xffffffff; /* do without masking */
-	ret = pci_alloc_consistent(hwdev, size, dma_handle);
-	hwdev->dma_mask = dma_mask; /* restore */
-	hwdev->consistent_dma_mask = cdma_mask; /* restore */
+	if (dev == NULL || !dev->dma_mask)
+		return dma_alloc_coherent(dev, size, dma_handle, flags);
+	dma_mask = *dev->dma_mask;
+	*dev->dma_mask = 0xffffffff; 	/* do without masking */
+	ret = dma_alloc_coherent(dev, size, dma_handle, flags);
+	*dev->dma_mask = dma_mask;	/* restore */
 	if (ret) {
 		/* obtained address is out of range? */
-		if (((unsigned long)*dma_handle + size - 1) & ~mask) {
+		if (((unsigned long)*dma_handle + size - 1) & ~dma_mask) {
 			/* reallocate with the proper mask */
-			pci_free_consistent(hwdev, size, ret, *dma_handle);
-			ret = pci_alloc_consistent(hwdev, size, dma_handle);
+			dma_free_coherent(dev, size, ret, *dma_handle);
+			ret = dma_alloc_coherent(dev, size, dma_handle, flags);
 		}
 	} else {
 		/* wish to success now with the proper mask... */
-		if (mask != 0xffffffffUL)
-			ret = pci_alloc_consistent(hwdev, size, dma_handle);
+		if (dma_mask != 0xffffffffUL)
+			ret = dma_alloc_coherent(dev, size, dma_handle, flags);
 	}
 	return ret;
 }
 
-/* redefine pci_alloc_consistent for some architectures */
-#undef pci_alloc_consistent
-#define pci_alloc_consistent snd_pci_hack_alloc_consistent
+/* redefine dma_alloc_coherent for some architectures */
+#undef dma_alloc_coherent
+#define dma_alloc_coherent snd_dma_hack_alloc_coherent
 
 #endif /* arch */
-#endif /* CONFIG_PCI */
+
+/*
+ *
+ *  Generic memory allocators
+ *
+ */
+
+static long snd_allocated_pages; /* holding the number of allocated pages */
+
+static void mark_pages(void *res, int order)
+{
+	struct page *page = virt_to_page(res);
+	struct page *last_page = page + (1 << order);
+	while (page < last_page)
+		SetPageReserved(page++);
+	snd_allocated_pages += 1 << order;
+}
+
+static void unmark_pages(void *res, int order)
+{
+	struct page *page = virt_to_page(res);
+	struct page *last_page = page + (1 << order);
+	while (page < last_page)
+		ClearPageReserved(page++);
+	snd_allocated_pages -= 1 << order;
+}
+
+/**
+ * snd_malloc_pages - allocate pages with the given size
+ * @size: the size to allocate in bytes
+ * @gfp_flags: the allocation conditions, GFP_XXX
+ *
+ * Allocates the physically contiguous pages with the given size.
+ *
+ * Returns the pointer of the buffer, or NULL if no enoguh memory.
+ */
+void *snd_malloc_pages(size_t size, unsigned int gfp_flags)
+{
+	int pg;
+	void *res;
+
+	snd_assert(size > 0, return NULL);
+	snd_assert(gfp_flags != 0, return NULL);
+	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
+	if ((res = (void *) __get_free_pages(gfp_flags, pg)) != NULL) {
+		mark_pages(res, pg);
+	}
+	return res;
+}
+
+/**
+ * snd_malloc_pages_fallback - allocate pages with the given size with fallback
+ * @size: the requested size to allocate in bytes
+ * @gfp_flags: the allocation conditions, GFP_XXX
+ * @res_size: the pointer to store the size of buffer actually allocated
+ *
+ * Allocates the physically contiguous pages with the given request
+ * size.  When no space is left, this function reduces the size and
+ * tries to allocate again.  The size actually allocated is stored in
+ * res_size argument.
+ *
+ * Returns the pointer of the buffer, or NULL if no enoguh memory.
+ */            
+void *snd_malloc_pages_fallback(size_t size, unsigned int gfp_flags, size_t *res_size)
+{
+	void *res;
+
+	snd_assert(size > 0, return NULL);
+	snd_assert(res_size != NULL, return NULL);
+	do {
+		if ((res = snd_malloc_pages(size, gfp_flags)) != NULL) {
+			*res_size = size;
+			return res;
+		}
+		size >>= 1;
+	} while (size >= PAGE_SIZE);
+	return NULL;
+}
+
+/**
+ * snd_free_pages - release the pages
+ * @ptr: the buffer pointer to release
+ * @size: the allocated buffer size
+ *
+ * Releases the buffer allocated via snd_malloc_pages().
+ */
+void snd_free_pages(void *ptr, size_t size)
+{
+	int pg;
+
+	if (ptr == NULL)
+		return;
+	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
+	unmark_pages(ptr, pg);
+	free_pages((unsigned long) ptr, pg);
+}
+
+/*
+ *
+ *  Bus-specific memory allocators
+ *
+ */
+
+static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma)
+{
+	int pg;
+	void *res;
+	unsigned int gfp_flags;
+
+	snd_assert(size > 0, return NULL);
+	snd_assert(dma != NULL, return NULL);
+	pg = get_order(size);
+	gfp_flags = GFP_KERNEL;
+	if (pg > 0)
+		gfp_flags |= __GFP_NOWARN;
+	res = dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags);
+	if (res != NULL)
+		mark_pages(res, pg);
+
+	return res;
+}
+
+static void *snd_malloc_dev_pages_fallback(struct device *dev, size_t size,
+					   dma_addr_t *dma, size_t *res_size)
+{
+	void *res;
+
+	snd_assert(res_size != NULL, return NULL);
+	do {
+		if ((res = snd_malloc_dev_pages(dev, size, dma)) != NULL) {
+			*res_size = size;
+			return res;
+		}
+		size >>= 1;
+	} while (size >= PAGE_SIZE);
+	return NULL;
+}
+
+static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr,
+			       dma_addr_t dma)
+{
+	int pg;
+
+	if (ptr == NULL)
+		return;
+	pg = get_order(size);
+	unmark_pages(ptr, pg);
+	dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma);
+}
+
+#ifdef CONFIG_SBUS
+
+static void *snd_malloc_sbus_pages(struct device *dev, size_t size,
+				   dma_addr_t *dma_addr)
+{
+	struct sbus_dev *sdev = (struct sbus_dev *)dev;
+	int pg;
+	void *res;
+
+	snd_assert(size > 0, return NULL);
+	snd_assert(dma_addr != NULL, return NULL);
+	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
+	res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr);
+	if (res != NULL) {
+		mark_pages(res, pg);
+	}
+	return res;
+}
+
+static void *snd_malloc_sbus_pages_fallback(struct device *dev, size_t size,
+					    dma_addr_t *dma_addr, size_t *res_size)
+{
+	void *res;
+
+	snd_assert(res_size != NULL, return NULL);
+	do {
+		if ((res = snd_malloc_sbus_pages(dev, size, dma_addr)) != NULL) {
+			*res_size = size;
+			return res;
+		}
+		size >>= 1;
+	} while (size >= PAGE_SIZE);
+	return NULL;
+}
+
+static void snd_free_sbus_pages(struct device *dev, size_t size,
+				void *ptr, dma_addr_t dma_addr)
+{
+	struct sbus_dev *sdev = (struct sbus_dev *)dev;
+	int pg;
+
+	if (ptr == NULL)
+		return;
+	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
+	unmark_pages(ptr, pg);
+	sbus_free_consistent(sdev, PAGE_SIZE * (1 << pg), ptr, dma_addr);
+}
+
+#endif /* CONFIG_SBUS */
+
+/*
+ *
+ *  ALSA generic memory management
+ *
+ */
 
 
 /*
@@ -142,23 +382,7 @@ static int compare_device(const struct s
 		if (! allow_unused || (a->id != SNDRV_DMA_DEVICE_UNUSED && b->id != SNDRV_DMA_DEVICE_UNUSED))
 			return 0;
 	}
-	switch (a->type) {
-	case SNDRV_DMA_TYPE_CONTINUOUS:
-#ifdef CONFIG_ISA
-	case SNDRV_DMA_TYPE_ISA:
-#endif
-		return a->dev.flags == b->dev.flags;
-#ifdef CONFIG_PCI
-	case SNDRV_DMA_TYPE_PCI:
-	case SNDRV_DMA_TYPE_PCI_SG:
-		return a->dev.pci == b->dev.pci;
-#endif
-#ifdef CONFIG_SBUS
-	case SNDRV_DMA_TYPE_SBUS:
-		return a->dev.sbus == b->dev.sbus;
-#endif
-	}
-	return 0;
+	return a->dev == b->dev;
 }
 
 /**
@@ -183,27 +407,70 @@ int snd_dma_alloc_pages(const struct snd
 	dmab->bytes = 0;
 	switch (dev->type) {
 	case SNDRV_DMA_TYPE_CONTINUOUS:
-		dmab->area = snd_malloc_pages(size, dev->dev.flags);
+		dmab->area = snd_malloc_pages(size, (unsigned long)dev->dev);
 		dmab->addr = 0;
 		break;
-#ifdef CONFIG_ISA
-	case SNDRV_DMA_TYPE_ISA:
-		dmab->area = snd_malloc_isa_pages(size, &dmab->addr);
+#ifdef CONFIG_SBUS
+	case SNDRV_DMA_TYPE_SBUS:
+		dmab->area = snd_malloc_sbus_pages(dev->dev, size, &dmab->addr);
 		break;
 #endif
-#ifdef CONFIG_PCI
-	case SNDRV_DMA_TYPE_PCI:
-		dmab->area = snd_malloc_pci_pages(dev->dev.pci, size, &dmab->addr);
+	case SNDRV_DMA_TYPE_DEV:
+		dmab->area = snd_malloc_dev_pages(dev->dev, size, &dmab->addr);
 		break;
-	case SNDRV_DMA_TYPE_PCI_SG:
-		snd_malloc_sgbuf_pages(dev->dev.pci, size, dmab);
+	case SNDRV_DMA_TYPE_DEV_SG:
+		snd_malloc_sgbuf_pages(dev, size, dmab, NULL);
+		break;
+	default:
+		printk(KERN_ERR "snd-malloc: invalid device type %d\n", dev->type);
+		dmab->area = NULL;
+		dmab->addr = 0;
+		return -ENXIO;
+	}
+	if (! dmab->area)
+		return -ENOMEM;
+	dmab->bytes = size;
+	return 0;
+}
+
+/**
+ * snd_dma_alloc_pages_fallback - allocate the buffer area according to the given type with fallback
+ * @dev: the buffer device info
+ * @size: the buffer size to allocate
+ * @dmab: buffer allocation record to store the allocated data
+ *
+ * Calls the memory-allocator function for the corresponding
+ * buffer type.  When no space is left, this function reduces the size and
+ * tries to allocate again.  The size actually allocated is stored in
+ * res_size argument.
+ * 
+ * Returns zero if the buffer with the given size is allocated successfuly,
+ * other a negative value at error.
+ */
+int snd_dma_alloc_pages_fallback(const struct snd_dma_device *dev, size_t size,
+				 struct snd_dma_buffer *dmab)
+{
+	snd_assert(dev != NULL, return -ENXIO);
+	snd_assert(size > 0, return -ENXIO);
+	snd_assert(dmab != NULL, return -ENXIO);
+
+	dmab->bytes = 0;
+	switch (dev->type) {
+	case SNDRV_DMA_TYPE_CONTINUOUS:
+		dmab->area = snd_malloc_pages_fallback(size, (unsigned long)dev->dev, &dmab->bytes);
+		dmab->addr = 0;
 		break;
-#endif
 #ifdef CONFIG_SBUS
 	case SNDRV_DMA_TYPE_SBUS:
-		dmab->area = snd_malloc_sbus_pages(dev->dev.sbus, size, &dmab->addr);
+		dmab->area = snd_malloc_sbus_pages_fallback(dev->dev, size, &dmab->addr, &dmab->bytes);
 		break;
 #endif
+	case SNDRV_DMA_TYPE_DEV:
+		dmab->area = snd_malloc_dev_pages_fallback(dev->dev, size, &dmab->addr, &dmab->bytes);
+		break;
+	case SNDRV_DMA_TYPE_DEV_SG:
+		snd_malloc_sgbuf_pages(dev, size, dmab, &dmab->bytes);
+		break;
 	default:
 		printk(KERN_ERR "snd-malloc: invalid device type %d\n", dev->type);
 		dmab->area = NULL;
@@ -212,7 +479,6 @@ int snd_dma_alloc_pages(const struct snd
 	}
 	if (! dmab->area)
 		return -ENOMEM;
-	dmab->bytes = size;
 	return 0;
 }
 
@@ -230,24 +496,17 @@ void snd_dma_free_pages(const struct snd
 	case SNDRV_DMA_TYPE_CONTINUOUS:
 		snd_free_pages(dmab->area, dmab->bytes);
 		break;
-#ifdef CONFIG_ISA
-	case SNDRV_DMA_TYPE_ISA:
-		snd_free_isa_pages(dmab->bytes, dmab->area, dmab->addr);
+#ifdef CONFIG_SBUS
+	case SNDRV_DMA_TYPE_SBUS:
+		snd_free_sbus_pages(dev->dev, dmab->bytes, dmab->area, dmab->addr);
 		break;
 #endif
-#ifdef CONFIG_PCI
-	case SNDRV_DMA_TYPE_PCI:
-		snd_free_pci_pages(dev->dev.pci, dmab->bytes, dmab->area, dmab->addr);
+	case SNDRV_DMA_TYPE_DEV:
+		snd_free_dev_pages(dev->dev, dmab->bytes, dmab->area, dmab->addr);
 		break;
-	case SNDRV_DMA_TYPE_PCI_SG:
+	case SNDRV_DMA_TYPE_DEV_SG:
 		snd_free_sgbuf_pages(dmab);
 		break;
-#endif
-#ifdef CONFIG_SBUS
-	case SNDRV_DMA_TYPE_SBUS:
-		snd_free_sbus_pages(dev->dev.sbus, dmab->bytes, dmab->area, dmab->addr);
-		break;
-#endif
 	default:
 		printk(KERN_ERR "snd-malloc: invalid device type %d\n", dev->type);
 	}
@@ -394,395 +653,7 @@ static void free_all_reserved_pages(void
 	}
 	up(&list_mutex);
 }
-
-
-/*
- *
- *  Generic memory allocators
- *
- */
-
-static long snd_allocated_pages; /* holding the number of allocated pages */
-
-static void mark_pages(void *res, int order)
-{
-	struct page *page = virt_to_page(res);
-	struct page *last_page = page + (1 << order);
-	while (page < last_page)
-		SetPageReserved(page++);
-	snd_allocated_pages += 1 << order;
-}
-
-static void unmark_pages(void *res, int order)
-{
-	struct page *page = virt_to_page(res);
-	struct page *last_page = page + (1 << order);
-	while (page < last_page)
-		ClearPageReserved(page++);
-	snd_allocated_pages -= 1 << order;
-}
-
-/**
- * snd_malloc_pages - allocate pages with the given size
- * @size: the size to allocate in bytes
- * @gfp_flags: the allocation conditions, GFP_XXX
- *
- * Allocates the physically contiguous pages with the given size.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_pages(size_t size, unsigned int gfp_flags)
-{
-	int pg;
-	void *res;
-
-	snd_assert(size > 0, return NULL);
-	snd_assert(gfp_flags != 0, return NULL);
-	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-	if ((res = (void *) __get_free_pages(gfp_flags, pg)) != NULL) {
-		mark_pages(res, pg);
-	}
-	return res;
-}
-
-/**
- * snd_malloc_pages_fallback - allocate pages with the given size with fallback
- * @size: the requested size to allocate in bytes
- * @gfp_flags: the allocation conditions, GFP_XXX
- * @res_size: the pointer to store the size of buffer actually allocated
- *
- * Allocates the physically contiguous pages with the given request
- * size.  When no space is left, this function reduces the size and
- * tries to allocate again.  The size actually allocated is stored in
- * res_size argument.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_pages_fallback(size_t size, unsigned int gfp_flags, size_t *res_size)
-{
-	void *res;
-
-	snd_assert(size > 0, return NULL);
-	snd_assert(res_size != NULL, return NULL);
-	do {
-		if ((res = snd_malloc_pages(size, gfp_flags)) != NULL) {
-			*res_size = size;
-			return res;
-		}
-		size >>= 1;
-	} while (size >= PAGE_SIZE);
-	return NULL;
-}
-
-/**
- * snd_free_pages - release the pages
- * @ptr: the buffer pointer to release
- * @size: the allocated buffer size
- *
- * Releases the buffer allocated via snd_malloc_pages().
- */
-void snd_free_pages(void *ptr, size_t size)
-{
-	int pg;
-
-	if (ptr == NULL)
-		return;
-	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-	unmark_pages(ptr, pg);
-	free_pages((unsigned long) ptr, pg);
-}
-
-#if defined(CONFIG_ISA) && ! defined(CONFIG_PCI)
-
-/**
- * snd_malloc_isa_pages - allocate pages for ISA bus with the given size
- * @size: the size to allocate in bytes
- * @dma_addr: the pointer to store the physical address of the buffer
- *
- * Allocates the physically contiguous pages with the given size for
- * ISA bus.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_isa_pages(size_t size, dma_addr_t *dma_addr)
-{
-	void *dma_area;
-	dma_area = snd_malloc_pages(size, GFP_ATOMIC|GFP_DMA);
-	*dma_addr = dma_area ? isa_virt_to_bus(dma_area) : 0UL;
-	return dma_area;
-}
-
-/**
- * snd_malloc_isa_pages_fallback - allocate pages with the given size with fallback for ISA bus
- * @size: the requested size to allocate in bytes
- * @dma_addr: the pointer to store the physical address of the buffer
- * @res_size: the pointer to store the size of buffer actually allocated
- *
- * Allocates the physically contiguous pages with the given request
- * size for PCI bus.  When no space is left, this function reduces the size and
- * tries to allocate again.  The size actually allocated is stored in
- * res_size argument.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_isa_pages_fallback(size_t size,
-				    dma_addr_t *dma_addr,
-				    size_t *res_size)
-{
-	void *dma_area;
-	dma_area = snd_malloc_pages_fallback(size, GFP_ATOMIC|GFP_DMA, res_size);
-	*dma_addr = dma_area ? isa_virt_to_bus(dma_area) : 0UL;
-	return dma_area;
-}
-
-#endif /* CONFIG_ISA && !CONFIG_PCI */
-
-#ifdef CONFIG_PCI
-
-/**
- * snd_malloc_pci_pages - allocate pages for PCI bus with the given size
- * @pci: the pci device pointer
- * @size: the size to allocate in bytes
- * @dma_addr: the pointer to store the physical address of the buffer
- *
- * Allocates the physically contiguous pages with the given size for
- * PCI bus.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_pci_pages(struct pci_dev *pci,
-			   size_t size,
-			   dma_addr_t *dma_addr)
-{
-	int pg;
-	void *res;
-
-	snd_assert(size > 0, return NULL);
-	snd_assert(dma_addr != NULL, return NULL);
-	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-	res = pci_alloc_consistent(pci, PAGE_SIZE * (1 << pg), dma_addr);
-	if (res != NULL) {
-		mark_pages(res, pg);
-	}
-	return res;
-}
-
-/**
- * snd_malloc_pci_pages_fallback - allocate pages with the given size with fallback for PCI bus
- * @pci: pci device pointer
- * @size: the requested size to allocate in bytes
- * @dma_addr: the pointer to store the physical address of the buffer
- * @res_size: the pointer to store the size of buffer actually allocated
- *
- * Allocates the physically contiguous pages with the given request
- * size for PCI bus.  When no space is left, this function reduces the size and
- * tries to allocate again.  The size actually allocated is stored in
- * res_size argument.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_pci_pages_fallback(struct pci_dev *pci,
-				    size_t size,
-				    dma_addr_t *dma_addr,
-				    size_t *res_size)
-{
-	void *res;
-
-	snd_assert(res_size != NULL, return NULL);
-	do {
-		if ((res = snd_malloc_pci_pages(pci, size, dma_addr)) != NULL) {
-			*res_size = size;
-			return res;
-		}
-		size >>= 1;
-	} while (size >= PAGE_SIZE);
-	return NULL;
-}
-
-/**
- * snd_free_pci_pages - release the pages
- * @pci: pci device pointer
- * @size: the allocated buffer size
- * @ptr: the buffer pointer to release
- * @dma_addr: the physical address of the buffer
- *
- * Releases the buffer allocated via snd_malloc_pci_pages().
- */
-void snd_free_pci_pages(struct pci_dev *pci,
-			size_t size,
-			void *ptr,
-			dma_addr_t dma_addr)
-{
-	int pg;
-
-	if (ptr == NULL)
-		return;
-	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-	unmark_pages(ptr, pg);
-	pci_free_consistent(pci, PAGE_SIZE * (1 << pg), ptr, dma_addr);
-}
-
-
-#if defined(__i386__)
-/*
- * on ix86, we allocate a page with GFP_KERNEL to assure the
- * allocation.  the code is almost same with kernel/i386/pci-dma.c but
- * it allocates only a single page and checks the validity of the
- * page address with the given pci dma mask.
- */
-
-/**
- * snd_malloc_pci_page - allocate a page in the valid pci dma mask
- * @pci: pci device pointer
- * @addrp: the pointer to store the physical address of the buffer
- *
- * Allocates a single page for the given PCI device and returns
- * the virtual address and stores the physical address on addrp.
- * 
- * This function cannot be called from interrupt handlers or
- * within spinlocks.
- */
-void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *addrp)
-{
-	void *ptr;
-	dma_addr_t addr;
-	unsigned long mask;
-
-	mask = pci ? (unsigned long)pci->consistent_dma_mask : 0x00ffffffUL;
-	ptr = (void *)__get_free_page(GFP_KERNEL);
-	if (ptr) {
-		addr = virt_to_phys(ptr);
-		if (((unsigned long)addr + PAGE_SIZE - 1) & ~mask) {
-			/* try to reallocate with the GFP_DMA */
-			free_page((unsigned long)ptr);
-			/* use GFP_ATOMIC for the DMA zone to avoid stall */
-			ptr = (void *)__get_free_page(GFP_ATOMIC | GFP_DMA);
-			if (ptr) /* ok, the address must be within lower 16MB... */
-				addr = virt_to_phys(ptr);
-			else
-				addr = 0;
-		}
-	} else
-		addr = 0;
-	if (ptr) {
-		memset(ptr, 0, PAGE_SIZE);
-		mark_pages(ptr, 0);
-	}
-	*addrp = addr;
-	return ptr;
-}
-#else
-
-/* on other architectures, call snd_malloc_pci_pages() helper function
- * which uses pci_alloc_consistent().
- */
-void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *addrp)
-{
-	return snd_malloc_pci_pages(pci, PAGE_SIZE, addrp);
-}
-
-#endif
-
-#if 0 /* for kernel-doc */
-/**
- * snd_free_pci_page - release a page
- * @pci: pci device pointer
- * @ptr: the buffer pointer to release
- * @dma_addr: the physical address of the buffer
- *
- * Releases the buffer allocated via snd_malloc_pci_page().
- */
-void snd_free_pci_page(struct pci_dev *pci, void *ptr, dma_addr_t dma_addr);
-#endif /* for kernel-doc */
-
-#endif /* CONFIG_PCI */
-
-#ifdef CONFIG_SBUS
-
-/**
- * snd_malloc_sbus_pages - allocate pages for SBUS with the given size
- * @sdev: sbus device pointer
- * @size: the size to allocate in bytes
- * @dma_addr: the pointer to store the physical address of the buffer
- *
- * Allocates the physically contiguous pages with the given size for
- * SBUS.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_sbus_pages(struct sbus_dev *sdev,
-			    size_t size,
-			    dma_addr_t *dma_addr)
-{
-	int pg;
-	void *res;
-
-	snd_assert(size > 0, return NULL);
-	snd_assert(dma_addr != NULL, return NULL);
-	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-	res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr);
-	if (res != NULL) {
-		mark_pages(res, pg);
-	}
-	return res;
-}
-
-/**
- * snd_malloc_pci_pages_fallback - allocate pages with the given size with fallback for SBUS
- * @sdev: sbus device pointer
- * @size: the requested size to allocate in bytes
- * @dma_addr: the pointer to store the physical address of the buffer
- * @res_size: the pointer to store the size of buffer actually allocated
- *
- * Allocates the physically contiguous pages with the given request
- * size for SBUS.  When no space is left, this function reduces the size and
- * tries to allocate again.  The size actually allocated is stored in
- * res_size argument.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_sbus_pages_fallback(struct sbus_dev *sdev,
-				     size_t size,
-				     dma_addr_t *dma_addr,
-				     size_t *res_size)
-{
-	void *res;
-
-	snd_assert(res_size != NULL, return NULL);
-	do {
-		if ((res = snd_malloc_sbus_pages(sdev, size, dma_addr)) != NULL) {
-			*res_size = size;
-			return res;
-		}
-		size >>= 1;
-	} while (size >= PAGE_SIZE);
-	return NULL;
-}
-
-/**
- * snd_free_sbus_pages - release the pages
- * @sdev: sbus device pointer
- * @size: the allocated buffer size
- * @ptr: the buffer pointer to release
- * @dma_addr: the physical address of the buffer
- *
- * Releases the buffer allocated via snd_malloc_pci_pages().
- */
-void snd_free_sbus_pages(struct sbus_dev *sdev,
-			 size_t size,
-			 void *ptr,
-			 dma_addr_t dma_addr)
-{
-	int pg;
-
-	if (ptr == NULL)
-		return;
-	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-	unmark_pages(ptr, pg);
-	sbus_free_consistent(sdev, PAGE_SIZE * (1 << pg), ptr, dma_addr);
-}
-
-#endif /* CONFIG_SBUS */
+
 
 
 /*
@@ -821,6 +692,17 @@ static struct prealloc_dev prealloc_devi
 	{ }, /* terminator */
 };
 
+/*
+ * compose a snd_dma_device struct for the PCI device
+ */
+static inline void snd_dma_device_pci(struct snd_dma_device *dev, struct pci_dev *pci, unsigned int id)
+{
+	memset(dev, 0, sizeof(*dev));
+	dev->type = SNDRV_DMA_TYPE_DEV;
+	dev->dev = snd_dma_pci_data(pci);
+	dev->id = id;
+}
+
 static void __init preallocate_cards(void)
 {
 	struct pci_dev *pci = NULL;
@@ -902,29 +784,25 @@ static int snd_mem_proc_read(char *page,
 		len += sprintf(page + len, " : type ");
 		switch (mem->dev.type) {
 		case SNDRV_DMA_TYPE_CONTINUOUS:
-			len += sprintf(page + len, "CONT [%x]", mem->dev.dev.flags);
+			len += sprintf(page + len, "CONT [%p]", mem->dev.dev);
 			break;
-#ifdef CONFIG_PCI
-		case SNDRV_DMA_TYPE_PCI:
-		case SNDRV_DMA_TYPE_PCI_SG:
-			if (mem->dev.dev.pci) {
-				len += sprintf(page + len, "%s [%04x:%04x]",
-					       mem->dev.type == SNDRV_DMA_TYPE_PCI ? "PCI" : "PCI-SG",
-					       mem->dev.dev.pci->vendor,
-					       mem->dev.dev.pci->device);
-			}
-			break;
-#endif
-#ifdef CONFIG_ISA
-		case SNDRV_DMA_TYPE_ISA:
-			len += sprintf(page + len, "ISA [%x]", mem->dev.dev.flags);
-			break;
-#endif
 #ifdef CONFIG_SBUS
 		case SNDRV_DMA_TYPE_SBUS:
-			len += sprintf(page + len, "SBUS [%x]", mem->dev.dev.sbus->slot);
+			{
+				struct sbus_dev *sdev = (struct sbus_dev *)(mem->dev.dev);
+				len += sprintf(page + len, "SBUS [%x]", sbus->slot);
+			}
 			break;
 #endif
+		case SNDRV_DMA_TYPE_DEV:
+		case SNDRV_DMA_TYPE_DEV_SG:
+			if (mem->dev.dev) {
+				len += sprintf(page + len, "%s [%s]",
+					       mem->dev.type == SNDRV_DMA_TYPE_DEV_SG ? "DEV-SG" : "DEV",
+					       mem->dev.dev->bus_id);
+			} else
+				len += sprintf(page + len, "ISA");
+			break;
 		default:
 			len += sprintf(page + len, "UNKNOWN");
 			break;
@@ -987,7 +865,9 @@ __setup("snd-page-alloc=", snd_mem_setup
  * exports
  */
 EXPORT_SYMBOL(snd_dma_alloc_pages);
+EXPORT_SYMBOL(snd_dma_alloc_pages_fallback);
 EXPORT_SYMBOL(snd_dma_free_pages);
+
 EXPORT_SYMBOL(snd_dma_get_reserved);
 EXPORT_SYMBOL(snd_dma_free_reserved);
 EXPORT_SYMBOL(snd_dma_set_reserved);
@@ -995,20 +875,3 @@ EXPORT_SYMBOL(snd_dma_set_reserved);
 EXPORT_SYMBOL(snd_malloc_pages);
 EXPORT_SYMBOL(snd_malloc_pages_fallback);
 EXPORT_SYMBOL(snd_free_pages);
-#if defined(CONFIG_ISA) && ! defined(CONFIG_PCI)
-EXPORT_SYMBOL(snd_malloc_isa_pages);
-EXPORT_SYMBOL(snd_malloc_isa_pages_fallback);
-#endif
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL(snd_malloc_pci_pages);
-EXPORT_SYMBOL(snd_malloc_pci_pages_fallback);
-EXPORT_SYMBOL(snd_malloc_pci_page);
-EXPORT_SYMBOL(snd_free_pci_pages);
-EXPORT_SYMBOL(snd_malloc_sgbuf_pages);
-EXPORT_SYMBOL(snd_free_sgbuf_pages);
-#endif
-#ifdef CONFIG_SBUS
-EXPORT_SYMBOL(snd_malloc_sbus_pages);
-EXPORT_SYMBOL(snd_malloc_sbus_pages_fallback);
-EXPORT_SYMBOL(snd_free_sbus_pages);
-#endif
--- diff/sound/core/oss/pcm_oss.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/core/oss/pcm_oss.c	2004-03-09 11:51:52.000000000 +0000
@@ -133,6 +133,15 @@ static long snd_pcm_oss_bytes(snd_pcm_su
 	return (runtime->oss.buffer_bytes * frames) / buffer_size;
 }
 
+static long snd_pcm_alsa_frames(snd_pcm_substream_t *substream, long bytes)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream);
+	if (buffer_size == runtime->oss.buffer_bytes)
+		return bytes_to_frames(runtime, bytes);
+	return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes);
+}
+
 static int snd_pcm_oss_format_from(int format)
 {
 	switch (format) {
@@ -254,6 +263,7 @@ static int snd_pcm_oss_period_size(snd_p
 
 	snd_assert(oss_period_size >= 16, return -EINVAL);
 	runtime->oss.period_bytes = oss_period_size;
+	runtime->oss.period_frames = 1;
 	runtime->oss.periods = oss_periods;
 	return 0;
 }
@@ -511,6 +521,8 @@ static int snd_pcm_oss_change_params(snd
 	if (runtime->dma_area)
 		snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes));
 
+	runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size);
+
 	err = 0;
 failure:
 	if (sw_params)
@@ -2098,7 +2110,7 @@ static int snd_pcm_oss_playback_ready(sn
 	if (atomic_read(&runtime->mmap_count))
 		return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
 	else
-		return snd_pcm_playback_ready(substream);
+		return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames;
 }
 
 static int snd_pcm_oss_capture_ready(snd_pcm_substream_t *substream)
@@ -2107,7 +2119,7 @@ static int snd_pcm_oss_capture_ready(snd
 	if (atomic_read(&runtime->mmap_count))
 		return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
 	else
-		return snd_pcm_capture_ready(substream);
+		return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames;
 }
 
 static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait)
--- diff/sound/core/pcm.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/core/pcm.c	2004-03-09 11:51:52.000000000 +0000
@@ -327,8 +327,9 @@ static void snd_pcm_substream_proc_hw_pa
 		snd_iprintf(buffer, "OSS format: %s\n", snd_pcm_oss_format_name(runtime->oss.format));
 		snd_iprintf(buffer, "OSS channels: %u\n", runtime->oss.channels);	
 		snd_iprintf(buffer, "OSS rate: %u\n", runtime->oss.rate);
-		snd_iprintf(buffer, "OSS period bytes: %lu\n", (unsigned long)runtime->oss.period_bytes);	
+		snd_iprintf(buffer, "OSS period bytes: %lu\n", (unsigned long)runtime->oss.period_bytes);
 		snd_iprintf(buffer, "OSS periods: %u\n", runtime->oss.periods);
+		snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames);
 	}
 #endif
 	snd_pcm_stream_unlock_irq(substream);
@@ -1060,3 +1061,4 @@ EXPORT_SYMBOL(snd_pcm_format_size);
 EXPORT_SYMBOL(snd_pcm_format_silence_64);
 EXPORT_SYMBOL(snd_pcm_format_set_silence);
 EXPORT_SYMBOL(snd_pcm_build_linear_format);
+EXPORT_SYMBOL(snd_pcm_limit_hw_rates);
--- diff/sound/core/pcm_lib.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/core/pcm_lib.c	2004-03-09 11:51:52.000000000 +0000
@@ -67,8 +67,11 @@ void snd_pcm_playback_silence(snd_pcm_su
 			frames = runtime->silence_size;
 	} else {
 		if (new_hw_ptr == ULONG_MAX) {	/* initialization */
-			runtime->silence_filled = 0;
-			runtime->silence_start = runtime->control->appl_ptr;
+			snd_pcm_sframes_t avail = snd_pcm_playback_hw_avail(runtime);
+			runtime->silence_filled = avail > 0 ? avail : 0;
+			runtime->silence_start = (runtime->status->hw_ptr +
+						  runtime->silence_filled) %
+						 runtime->boundary;
 		} else {
 			ofs = runtime->status->hw_ptr;
 			frames = new_hw_ptr - ofs;
@@ -2659,20 +2662,6 @@ EXPORT_SYMBOL(snd_pcm_lib_preallocate_fr
 EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all);
 EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages);
 EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all);
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
 EXPORT_SYMBOL(snd_pcm_lib_malloc_pages);
 EXPORT_SYMBOL(snd_pcm_lib_free_pages);
-#ifdef CONFIG_ISA
-EXPORT_SYMBOL(snd_pcm_lib_preallocate_isa_pages);
-EXPORT_SYMBOL(snd_pcm_lib_preallocate_isa_pages_for_all);
-#endif
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL(snd_pcm_lib_preallocate_pci_pages);
-EXPORT_SYMBOL(snd_pcm_lib_preallocate_pci_pages_for_all);
-EXPORT_SYMBOL(snd_pcm_lib_preallocate_sg_pages);
-EXPORT_SYMBOL(snd_pcm_lib_preallocate_sg_pages_for_all);
-EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
-#endif
-#ifdef CONFIG_SBUS
-EXPORT_SYMBOL(snd_pcm_lib_preallocate_sbus_pages);
-EXPORT_SYMBOL(snd_pcm_lib_preallocate_sbus_pages_for_all);
-#endif
--- diff/sound/core/pcm_memory.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/core/pcm_memory.c	2004-03-09 11:51:52.000000000 +0000
@@ -229,97 +229,71 @@ static inline void setup_pcm_id(snd_pcm_
 }
 
 /**
- * snd_pcm_lib_preallocate_pages - pre-allocation for the continuous memory type
+ * snd_pcm_lib_preallocate_pages - pre-allocation for the given DMA type
  * @substream: the pcm substream instance
+ * @type: DMA type (SNDRV_DMA_TYPE_*)
+ * @data: DMA type dependant data
  * @size: the requested pre-allocation size in bytes
  * @max: the max. allowed pre-allocation size
- * @flags: allocation condition, GFP_XXX
  *
- * Do pre-allocation for the continuous memory type.
+ * Do pre-allocation for the given DMA type.
  *
  * Returns zero if successful, or a negative error code on failure.
  */
 int snd_pcm_lib_preallocate_pages(snd_pcm_substream_t *substream,
-				      size_t size, size_t max,
-				      unsigned int flags)
+				  int type, struct device *data,
+				  size_t size, size_t max)
 {
-	substream->dma_device.type = SNDRV_DMA_TYPE_CONTINUOUS;
-	substream->dma_device.dev.flags = flags;
+	substream->dma_device.type = type;
+	substream->dma_device.dev = data;
 	setup_pcm_id(substream);
 	return snd_pcm_lib_preallocate_pages1(substream, size, max);
 }
 
 /**
  * snd_pcm_lib_preallocate_pages_for_all - pre-allocation for continous memory type (all substreams)
- * @pcm: pcm to assign the buffer
+ * @substream: the pcm substream instance
+ * @type: DMA type (SNDRV_DMA_TYPE_*)
+ * @data: DMA type dependant data
  * @size: the requested pre-allocation size in bytes
- * @max: max. buffer size acceptable for the changes via proc file
- * @flags: allocation condition, GFP_XXX
+ * @max: the max. allowed pre-allocation size
  *
  * Do pre-allocation to all substreams of the given pcm for the
- * continuous memory type.
+ * specified DMA type.
  *
  * Returns zero if successful, or a negative error code on failure.
  */
 int snd_pcm_lib_preallocate_pages_for_all(snd_pcm_t *pcm,
-					  size_t size, size_t max,
-					  unsigned int flags)
+					  int type, void *data,
+					  size_t size, size_t max)
 {
 	snd_pcm_substream_t *substream;
 	int stream, err;
 
 	for (stream = 0; stream < 2; stream++)
 		for (substream = pcm->streams[stream].substream; substream; substream = substream->next)
-			if ((err = snd_pcm_lib_preallocate_pages(substream, size, max, flags)) < 0)
+			if ((err = snd_pcm_lib_preallocate_pages(substream, type, data, size, max)) < 0)
 				return err;
 	return 0;
 }
 
-#ifdef CONFIG_ISA
 /**
- * snd_pcm_lib_preallocate_isa_pages - pre-allocation for the ISA bus
- * @substream: substream to assign the buffer
- * @size: the requested pre-allocation size in bytes
- * @max: max. buffer size acceptable for the changes via proc file
- *
- * Do pre-allocation for the ISA bus.
- *
- * Returns zero if successful, or a negative error code on failure.
- */
-int snd_pcm_lib_preallocate_isa_pages(snd_pcm_substream_t *substream,
-				      size_t size, size_t max)
-{
-	substream->dma_device.type = SNDRV_DMA_TYPE_ISA;
-	substream->dma_device.dev.flags = 0; /* FIXME: any good identifier? */
-	setup_pcm_id(substream);
-	return snd_pcm_lib_preallocate_pages1(substream, size, max);
-}
-
-/*
- * FIXME: the function name is too long for docbook!
- *
- * snd_pcm_lib_preallocate_isa_pages_for_all - pre-allocation for the ISA bus (all substreams)
- * @pcm: pcm to assign the buffer
- * @max: max. buffer size acceptable for the changes via proc file
- *
- * Do pre-allocation to all substreams of the given pcm for the
- * ISA bus.
+ * snd_pcm_sgbuf_ops_page - get the page struct at the given offset
+ * @substream: the pcm substream instance
+ * @offset: the buffer offset
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Returns the page struct at the given buffer offset.
+ * Used as the page callback of PCM ops.
  */
-int snd_pcm_lib_preallocate_isa_pages_for_all(snd_pcm_t *pcm,
-					      size_t size, size_t max)
+struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset)
 {
-	snd_pcm_substream_t *substream;
-	int stream, err;
+	struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
 
-	for (stream = 0; stream < 2; stream++)
-		for (substream = pcm->streams[stream].substream; substream; substream = substream->next)
-			if ((err = snd_pcm_lib_preallocate_isa_pages(substream, size, max)) < 0)
-				return err;
-	return 0;
+	unsigned int idx = offset >> PAGE_SHIFT;
+	if (idx >= (unsigned int)sgbuf->pages)
+		return NULL;
+	return sgbuf->page_table[idx];
 }
-#endif /* CONFIG_ISA */
 
 /**
  * snd_pcm_lib_malloc_pages - allocate the DMA buffer
@@ -398,183 +372,6 @@ int snd_pcm_lib_free_pages(snd_pcm_subst
 	return 0;
 }
 
-#ifdef CONFIG_PCI
-/**
- * snd_pcm_lib_preallocate_pci_pages - pre-allocation for the PCI bus
- *
- * @pci: pci device
- * @substream: substream to assign the buffer
- * @size: the requested pre-allocation size in bytes
- * @max: max. buffer size acceptable for the changes via proc file
- *
- * Do pre-allocation for the PCI bus.
- *
- * Returns zero if successful, or a negative error code on failure.
- */
-int snd_pcm_lib_preallocate_pci_pages(struct pci_dev *pci,
-				      snd_pcm_substream_t *substream,
-				      size_t size, size_t max)
-{
-	substream->dma_device.type = SNDRV_DMA_TYPE_PCI;
-	substream->dma_device.dev.pci = pci;
-	setup_pcm_id(substream);
-	return snd_pcm_lib_preallocate_pages1(substream, size, max);
-}
-
-/*
- * FIXME: the function name is too long for docbook!
- *
- * snd_pcm_lib_preallocate_pci_pages_for_all - pre-allocation for the PCI bus (all substreams)
- * @pci: pci device
- * @pcm: pcm to assign the buffer
- * @size: the requested pre-allocation size in bytes
- * @max: max. buffer size acceptable for the changes via proc file
- *
- * Do pre-allocation to all substreams of the given pcm for the
- * PCI bus.
- *
- * Returns zero if successful, or a negative error code on failure.
- */
-int snd_pcm_lib_preallocate_pci_pages_for_all(struct pci_dev *pci,
-					      snd_pcm_t *pcm,
-					      size_t size, size_t max)
-{
-	snd_pcm_substream_t *substream;
-	int stream, err;
-
-	for (stream = 0; stream < 2; stream++)
-		for (substream = pcm->streams[stream].substream; substream; substream = substream->next)
-			if ((err = snd_pcm_lib_preallocate_pci_pages(pci, substream, size, max)) < 0)
-				return err;
-	return 0;
-}
-
-#endif /* CONFIG_PCI */
-
-#ifdef CONFIG_SBUS
-/**
- * snd_pcm_lib_preallocate_sbus_pages - pre-allocation for the SBUS bus
- *
- * @sbus: SBUS device
- * @substream: substream to assign the buffer
- * @max: max. buffer size acceptable for the changes via proc file
- *
- * Do pre-allocation for the SBUS.
- *
- * Returns zero if successful, or a negative error code on failure.
- */
-int snd_pcm_lib_preallocate_sbus_pages(struct sbus_dev *sdev,
-				       snd_pcm_substream_t *substream,
-				       size_t size, size_t max)
-{
-	substream->dma_device.type = SNDRV_DMA_TYPE_SBUS;
-	substream->dma_device.dev.sbus = sdev;
-	setup_pcm_id(substream);
-	return snd_pcm_lib_preallocate_pages1(substream, size, max);
-}
-
-/*
- * FIXME: the function name is too long for docbook!
- *
- * snd_pcm_lib_preallocate_sbus_pages_for_all - pre-allocation for the SBUS bus (all substreams)
- * @sbus: SBUS device
- * @pcm: pcm to assign the buffer
- * @size: the requested pre-allocation size in bytes
- * @max: max. buffer size acceptable for the changes via proc file
- *
- * Do pre-allocation to all substreams of the given pcm for the
- * SUBS.
- *
- * Returns zero if successful, or a negative error code on failure.
- */
-int snd_pcm_lib_preallocate_sbus_pages_for_all(struct sbus_dev *sdev,
-					       snd_pcm_t *pcm,
-					       size_t size, size_t max)
-{
-	snd_pcm_substream_t *substream;
-	int stream, err;
-
-	for (stream = 0; stream < 2; stream++)
-		for (substream = pcm->streams[stream].substream; substream; substream = substream->next)
-			if ((err = snd_pcm_lib_preallocate_sbus_pages(sdev, substream, size, max)) < 0)
-				return err;
-	return 0;
-}
-
-#endif /* CONFIG_SBUS */
-
-
-#ifdef CONFIG_PCI
-/**
- * snd_pcm_lib_preallocate_sg_pages - initialize SG-buffer for the PCI bus
- *
- * @pci: pci device
- * @substream: substream to assign the buffer
- * @size: the requested pre-allocation size in bytes
- * @max: max. buffer size acceptable for the changes via proc file
- *
- * Initializes SG-buffer for the PCI bus.
- *
- * Returns zero if successful, or a negative error code on failure.
- */
-int snd_pcm_lib_preallocate_sg_pages(struct pci_dev *pci,
-				     snd_pcm_substream_t *substream,
-				     size_t size, size_t max)
-{
-	substream->dma_device.type = SNDRV_DMA_TYPE_PCI_SG;
-	substream->dma_device.dev.pci = pci;
-	setup_pcm_id(substream);
-	return snd_pcm_lib_preallocate_pages1(substream, size, max);
-}
-
-/*
- * FIXME: the function name is too long for docbook!
- *
- * snd_pcm_lib_preallocate_sg_pages_for_all - initialize SG-buffer for the PCI bus (all substreams)
- * @pci: pci device
- * @pcm: pcm to assign the buffer
- * @size: the requested pre-allocation size in bytes
- * @max: max. buffer size acceptable for the changes via proc file
- *
- * Initialize the SG-buffer to all substreams of the given pcm for the
- * PCI bus.
- *
- * Returns zero if successful, or a negative error code on failure.
- */
-int snd_pcm_lib_preallocate_sg_pages_for_all(struct pci_dev *pci,
-					     snd_pcm_t *pcm,
-					     size_t size, size_t max)
-{
-	snd_pcm_substream_t *substream;
-	int stream, err;
-
-	for (stream = 0; stream < 2; stream++)
-		for (substream = pcm->streams[stream].substream; substream; substream = substream->next)
-			if ((err = snd_pcm_lib_preallocate_sg_pages(pci, substream, size, max)) < 0)
-				return err;
-	return 0;
-}
-
-/**
- * snd_pcm_sgbuf_ops_page - get the page struct at the given offset
- * @substream: the pcm substream instance
- * @offset: the buffer offset
- *
- * Returns the page struct at the given buffer offset.
- * Used as the page callback of PCM ops.
- */
-struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset)
-{
-	struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
-
-	unsigned int idx = offset >> PAGE_SHIFT;
-	if (idx >= (unsigned int)sgbuf->pages)
-		return NULL;
-	return sgbuf->page_table[idx];
-}
-
-#endif /* CONFIG_PCI */
-
 #ifndef MODULE
 
 /* format is: snd-pcm=preallocate_dma,maximum_substreams */
--- diff/sound/core/pcm_misc.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/core/pcm_misc.c	2004-03-09 11:51:52.000000000 +0000
@@ -654,3 +654,35 @@ snd_pcm_format_t snd_pcm_build_linear_fo
 	}
 	return snd_int_to_enum(((int(*)[2][2])linear_formats)[width][!!unsignd][!!big_endian]);
 }
+
+/**
+ * snd_pcm_limit_hw_rates - determine rate_min/rate_max fields
+ * @runtime: the runtime instance
+ *
+ * Determines the rate_min and rate_max fields from the rates bits of
+ * the given runtime->hw.
+ *
+ * Returns zero if successful.
+ */
+int snd_pcm_limit_hw_rates(snd_pcm_runtime_t *runtime)
+{
+	static unsigned rates[] = {
+		/* ATTENTION: these values depend on the definition in pcm.h! */
+		5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
+		64000, 88200, 96000, 176400, 192000
+	};
+	int i;
+	for (i = 0; i < (int)ARRAY_SIZE(rates); i++) {
+		if (runtime->hw.rates & (1 << i)) {
+			runtime->hw.rate_min = rates[i];
+			break;
+		}
+	}
+	for (i = (int)ARRAY_SIZE(rates) - 1; i >= 0; i--) {
+		if (runtime->hw.rates & (1 << i)) {
+			runtime->hw.rate_max = rates[i];
+			break;
+		}
+	}
+	return 0;
+}
--- diff/sound/core/seq/oss/seq_oss_midi.c	2003-06-09 14:18:21.000000000 +0100
+++ source/sound/core/seq/oss/seq_oss_midi.c	2004-03-09 11:51:52.000000000 +0000
@@ -491,7 +491,7 @@ snd_seq_oss_midi_reset(seq_oss_devinfo_t
 			}
 		}
 	}
-	snd_seq_oss_midi_close(dp, dev);
+	// snd_seq_oss_midi_close(dp, dev);
 	snd_use_lock_free(&mdev->use_lock);
 }
 
@@ -578,6 +578,7 @@ send_synth_event(seq_oss_devinfo_t *dp, 
 		ossev.v.code = EV_CHN_VOICE;
 		ossev.v.note = ev->data.note.note;
 		ossev.v.parm = ev->data.note.velocity;
+		ossev.v.chn = ev->data.note.channel;
 		break;
 	case SNDRV_SEQ_EVENT_CONTROLLER:
 	case SNDRV_SEQ_EVENT_PGMCHANGE:
@@ -585,10 +586,12 @@ send_synth_event(seq_oss_devinfo_t *dp, 
 		ossev.l.code = EV_CHN_COMMON;
 		ossev.l.p1 = ev->data.control.param;
 		ossev.l.val = ev->data.control.value;
+		ossev.l.chn = ev->data.control.channel;
 		break;
 	case SNDRV_SEQ_EVENT_PITCHBEND:
 		ossev.l.code = EV_CHN_COMMON;
 		ossev.l.val = ev->data.control.value + 8192;
+		ossev.l.chn = ev->data.control.channel;
 		break;
 	}
 	
--- diff/sound/core/seq/oss/seq_oss_synth.c	2003-06-09 14:18:21.000000000 +0100
+++ source/sound/core/seq/oss/seq_oss_synth.c	2004-03-09 11:51:52.000000000 +0000
@@ -410,6 +410,8 @@ snd_seq_oss_synth_reset(seq_oss_devinfo_
 		if (midi_synth_dev.opened <= 0)
 			return;
 		snd_seq_oss_midi_reset(dp, info->midi_mapped);
+		/* reopen the device */
+		snd_seq_oss_midi_close(dp, dev);
 		if (snd_seq_oss_midi_open(dp, info->midi_mapped,
 					  dp->file_mode) < 0) {
 			midi_synth_dev.opened--;
--- diff/sound/core/seq/seq_clientmgr.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/core/seq/seq_clientmgr.c	2004-03-09 11:51:52.000000000 +0000
@@ -547,6 +547,36 @@ static int update_timestamp_of_queue(snd
 
 
 /*
+ * expand a quoted event.
+ */
+static int expand_quoted_event(snd_seq_event_t *event)
+{
+	snd_seq_event_t *quoted;
+
+	quoted = event->data.quote.event;
+	if (quoted == NULL) {
+		snd_printd("seq: quoted event is NULL\n");
+		return -EINVAL;
+	}
+
+	event->type = quoted->type;
+	event->tag = quoted->tag;
+	event->source = quoted->source;
+	/* don't use quoted destination */
+	event->data = quoted->data;
+	/* use quoted timestamp only if subscription/port didn't update it */
+	if (event->queue == SNDRV_SEQ_QUEUE_DIRECT) {
+		event->flags = quoted->flags;
+		event->queue = quoted->queue;
+		event->time = quoted->time;
+	} else {
+		event->flags = (event->flags & SNDRV_SEQ_TIME_STAMP_MASK)
+			| (quoted->flags & ~SNDRV_SEQ_TIME_STAMP_MASK);
+	}
+	return 0;
+}
+
+/*
  * deliver an event to the specified destination.
  * if filter is non-zero, client filter bitmap is tested.
  *
@@ -581,12 +611,9 @@ static int snd_seq_deliver_single_event(
 		update_timestamp_of_queue(event, dest_port->time_queue,
 					  dest_port->time_real);
 
-	/* expand the quoted event */
 	if (event->type == SNDRV_SEQ_EVENT_KERNEL_QUOTE) {
 		quoted = 1;
-		event = event->data.quote.event;
-		if (event == NULL) {
-			snd_printd("seq: quoted event is NULL\n");
+		if (expand_quoted_event(event) < 0) {
 			result = 0; /* do not send bounce error */
 			goto __skip;
 		}
@@ -694,8 +721,8 @@ static int port_broadcast_event(client_t
 	if (dest_client == NULL)
 		return 0; /* no matching destination */
 
-	read_lock(&client->ports_lock);
-	list_for_each(p, &client->ports_list_head) {
+	read_lock(&dest_client->ports_lock);
+	list_for_each(p, &dest_client->ports_list_head) {
 		client_port_t *port = list_entry(p, client_port_t, list);
 		event->dest.port = port->addr.port;
 		/* pass NULL as source client to avoid error bounce */
@@ -706,7 +733,7 @@ static int port_broadcast_event(client_t
 			break;
 		num_ev++;
 	}
-	read_unlock(&client->ports_lock);
+	read_unlock(&dest_client->ports_lock);
 	snd_seq_client_unlock(dest_client);
 	event->dest.port = SNDRV_SEQ_ADDRESS_BROADCAST; /* restore */
 	return (err < 0) ? err : num_ev;
--- diff/sound/core/seq/seq_fifo.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/core/seq/seq_fifo.c	2004-03-09 11:51:52.000000000 +0000
@@ -171,10 +171,12 @@ int snd_seq_fifo_cell_out(fifo_t *f, snd
 {
 	snd_seq_event_cell_t *cell;
 	unsigned long flags;
+	wait_queue_t wait;
 
 	snd_assert(f != NULL, return -EINVAL);
 
 	*cellp = NULL;
+	init_waitqueue_entry(&wait, current);
 	spin_lock_irqsave(&f->lock, flags);
 	while ((cell = fifo_cell_out(f)) == NULL) {
 		if (nonblock) {
@@ -182,17 +184,19 @@ int snd_seq_fifo_cell_out(fifo_t *f, snd
 			spin_unlock_irqrestore(&f->lock, flags);
 			return -EAGAIN;
 		}
-		spin_unlock(&f->lock);
-		interruptible_sleep_on(&f->input_sleep);
-		spin_lock(&f->lock);
-
+		set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&f->input_sleep, &wait);
+		spin_unlock_irq(&f->lock);
+		schedule();
+		spin_lock_irq(&f->lock);
+		remove_wait_queue(&f->input_sleep, &wait);
 		if (signal_pending(current)) {
 			spin_unlock_irqrestore(&f->lock, flags);
 			return -ERESTARTSYS;
 		}
 	}
-	*cellp = cell;
 	spin_unlock_irqrestore(&f->lock, flags);
+	*cellp = cell;
 
 	return 0;
 }
--- diff/sound/core/seq/seq_memory.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/core/seq/seq_memory.c	2004-03-09 11:51:52.000000000 +0000
@@ -220,12 +220,14 @@ int snd_seq_cell_alloc(pool_t *pool, snd
 	snd_seq_event_cell_t *cell;
 	unsigned long flags;
 	int err = -EAGAIN;
+	wait_queue_t wait;
 
 	if (pool == NULL)
 		return -EINVAL;
 
 	*cellp = NULL;
 
+	init_waitqueue_entry(&wait, current);
 	spin_lock_irqsave(&pool->lock, flags);
 	if (pool->ptr == NULL) {	/* not initialized */
 		snd_printd("seq: pool is not initialized\n");
@@ -234,9 +236,12 @@ int snd_seq_cell_alloc(pool_t *pool, snd
 	}
 	while (pool->free == NULL && ! nonblock && ! pool->closing) {
 
-		spin_unlock(&pool->lock);
-		interruptible_sleep_on(&pool->output_sleep);
-		spin_lock(&pool->lock);
+		set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&pool->output_sleep, &wait);
+		spin_unlock_irq(&pool->lock);
+		schedule();
+		spin_lock_irq(&pool->lock);
+		remove_wait_queue(&pool->output_sleep, &wait);
 		/* interrupted? */
 		if (signal_pending(current)) {
 			err = -ERESTARTSYS;
--- diff/sound/core/seq/seq_midi.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/core/seq/seq_midi.c	2004-03-09 11:51:52.000000000 +0000
@@ -285,7 +285,7 @@ static int set_client_name(seq_midisynth
 	cinfo.client = client->seq_client;
 	cinfo.type = KERNEL_CLIENT;
 	name = rmidi->name[0] ? (const char *)rmidi->name : "External MIDI";
-	snprintf(cinfo.name, sizeof(cinfo.name), "Rawmidi %d - %s", card->number, name);
+	snprintf(cinfo.name, sizeof(cinfo.name), "%s - Rawmidi %d", name, card->number);
 	return snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &cinfo);
 }
 
--- diff/sound/core/sgbuf.c	2003-06-30 10:07:24.000000000 +0100
+++ source/sound/core/sgbuf.c	2004-03-09 11:51:52.000000000 +0000
@@ -20,7 +20,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
@@ -31,27 +30,42 @@
 #define SGBUF_TBL_ALIGN		32
 #define sgbuf_align_table(tbl)	((((tbl) + SGBUF_TBL_ALIGN - 1) / SGBUF_TBL_ALIGN) * SGBUF_TBL_ALIGN)
 
+int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
+{
+	struct snd_sg_buf *sgbuf = dmab->private_data;
+	struct snd_dma_buffer tmpb;
+	int i;
 
-/**
- * snd_malloc_sgbuf_pages - allocate the pages for the PCI SG buffer
- * @pci: the pci device pointer
- * @size: the requested buffer size in bytes
- * @dmab: the buffer record to store
- *
- * Initializes the SG-buffer table and allocates the buffer pages
- * for the given size.
- * The pages are mapped to the virtually continuous memory.
- *
- * This function is usually called from the middle-level functions such as
- * snd_pcm_lib_malloc_pages().
- *
- * Returns the mapped virtual address of the buffer if allocation was
- * successful, or NULL at error.
- */
-void *snd_malloc_sgbuf_pages(struct pci_dev *pci, size_t size, struct snd_dma_buffer *dmab)
+	if (! sgbuf)
+		return -EINVAL;
+
+	for (i = 0; i < sgbuf->pages; i++) {
+		tmpb.area = sgbuf->table[i].buf;
+		tmpb.addr = sgbuf->table[i].addr;
+		tmpb.bytes = PAGE_SIZE;
+		snd_dma_free_pages(&sgbuf->dev, &tmpb);
+	}
+	if (dmab->area)
+		vunmap(dmab->area);
+	dmab->area = NULL;
+
+	if (sgbuf->table)
+		kfree(sgbuf->table);
+	if (sgbuf->page_table)
+		kfree(sgbuf->page_table);
+	kfree(sgbuf);
+	dmab->private_data = NULL;
+	
+	return 0;
+}
+
+void *snd_malloc_sgbuf_pages(const struct snd_dma_device *dev,
+			     size_t size, struct snd_dma_buffer *dmab,
+			     size_t *res_size)
 {
 	struct snd_sg_buf *sgbuf;
 	unsigned int i, pages;
+	struct snd_dma_buffer tmpb;
 
 	dmab->area = NULL;
 	dmab->addr = 0;
@@ -59,7 +73,8 @@ void *snd_malloc_sgbuf_pages(struct pci_
 	if (! sgbuf)
 		return NULL;
 	memset(sgbuf, 0, sizeof(*sgbuf));
-	sgbuf->pci = pci;
+	sgbuf->dev = *dev;
+	sgbuf->dev.type = SNDRV_DMA_TYPE_DEV;
 	pages = snd_sgbuf_aligned_pages(size);
 	sgbuf->tblsize = sgbuf_align_table(pages);
 	sgbuf->table = kmalloc(sizeof(*sgbuf->table) * sgbuf->tblsize, GFP_KERNEL);
@@ -73,14 +88,15 @@ void *snd_malloc_sgbuf_pages(struct pci_
 
 	/* allocate each page */
 	for (i = 0; i < pages; i++) {
-		void *ptr;
-		dma_addr_t addr;
-		ptr = snd_malloc_pci_page(sgbuf->pci, &addr);
-		if (! ptr)
-			goto _failed;
-		sgbuf->table[i].buf = ptr;
-		sgbuf->table[i].addr = addr;
-		sgbuf->page_table[i] = virt_to_page(ptr);
+		if (snd_dma_alloc_pages(&sgbuf->dev, PAGE_SIZE, &tmpb) < 0) {
+			if (res_size == NULL)
+				goto _failed;
+			*res_size = size = sgbuf->pages * PAGE_SIZE;
+			break;
+		}
+		sgbuf->table[i].buf = tmpb.area;
+		sgbuf->table[i].addr = tmpb.addr;
+		sgbuf->page_table[i] = virt_to_page(tmpb.area);
 		sgbuf->pages++;
 	}
 
@@ -94,38 +110,3 @@ void *snd_malloc_sgbuf_pages(struct pci_
 	snd_free_sgbuf_pages(dmab); /* free the table */
 	return NULL;
 }
-
-/**
- * snd_free_sgbuf_pages - free the sg buffer
- * @dmab: buffer record
- *
- * Releases the pages and the SG-buffer table.
- *
- * This function is called usually from the middle-level function
- * such as snd_pcm_lib_free_pages().
- *
- * Returns zero if successful, or a negative error code on failure.
- */
-int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
-{
-	struct snd_sg_buf *sgbuf = dmab->private_data;
-	int i;
-
-	if (! sgbuf)
-		return -EINVAL;
-
-	for (i = 0; i < sgbuf->pages; i++)
-		snd_free_pci_page(sgbuf->pci, sgbuf->table[i].buf, sgbuf->table[i].addr);
-	if (dmab->area)
-		vunmap(dmab->area);
-	dmab->area = NULL;
-
-	if (sgbuf->table)
-		kfree(sgbuf->table);
-	if (sgbuf->page_table)
-		kfree(sgbuf->page_table);
-	kfree(sgbuf);
-	dmab->private_data = NULL;
-	
-	return 0;
-}
--- diff/sound/drivers/Kconfig	2002-11-11 11:09:38.000000000 +0000
+++ source/sound/drivers/Kconfig	2004-03-09 11:51:52.000000000 +0000
@@ -3,17 +3,41 @@
 menu "Generic devices"
 	depends on SND!=n
 
+
+config SND_MPU401_UART
+        tristate
+	select SND_TIMER
+        select SND_RAWMIDI
+
+config SND_OPL3_LIB
+	tristate
+	select SND_TIMER
+	select SND_HWDEP
+
+config SND_OPL4_LIB
+	tristate
+	select SND_TIMER
+	select SND_HWDEP
+
+config SND_VX_LIB
+	tristate
+	select SND_HWDEP
+	select SND_PCM
+
+
 config SND_DUMMY
 	tristate "Dummy (/dev/null) soundcard"
 	depends on SND
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include dummy driver. This driver does nothing, but
 	  emulates various mixer controls and PCM devices.
-	  
 
 config SND_VIRMIDI
 	tristate "Virtual MIDI soundcard"
 	depends on SND_SEQUENCER
+	select SND_TIMER
+	select SND_RAWMIDI
 	help
 	  Say 'Y' or 'M' to include virtual MIDI driver. This driver allows to
 	  connect applications using raw MIDI devices to sequencer.
@@ -21,6 +45,8 @@ config SND_VIRMIDI
 config SND_MTPAV
 	tristate "MOTU MidiTimePiece AV multiport MIDI"
 	depends on SND
+	select SND_TIMER
+	select SND_RAWMIDI
 	help
 	  Say 'Y' or 'M' to include support for MOTU MidiTimePiece AV multiport
 	  MIDI adapter.
@@ -28,6 +54,8 @@ config SND_MTPAV
 config SND_SERIAL_U16550
 	tristate "UART16550 - MIDI only driver"
 	depends on SND
+	select SND_TIMER
+	select SND_RAWMIDI
 	help
 	  Say 'Y' or 'M' to include support for MIDI serial port driver. It works
 	  with serial UARTs 16550 and better.
@@ -35,8 +63,8 @@ config SND_SERIAL_U16550
 config SND_MPU401
 	tristate "Generic MPU-401 UART driver"
 	depends on SND
+	select SND_MPU401_UART
 	help
 	  Say 'Y' or 'M' to include support for MPU401 hardware using UART access.
 
 endmenu
-
--- diff/sound/drivers/mpu401/Makefile	2003-06-30 10:07:24.000000000 +0100
+++ source/sound/drivers/mpu401/Makefile	2004-03-09 11:51:52.000000000 +0000
@@ -6,40 +6,7 @@
 snd-mpu401-objs := mpu401.o
 snd-mpu401-uart-objs := mpu401_uart.o
 
-# Toplevel Module Dependency
-obj-$(CONFIG_SND_MPU401) += snd-mpu401.o snd-mpu401-uart.o
-obj-$(CONFIG_SND_ALS100) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_AZT2320) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_AZT3328) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_DT019X) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_ES18XX) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_OPL3SA2) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_AD1816A) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_CS4231) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_CS4232) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_CS4236) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_ES1688) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_GUSEXTREME) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_OPTI93X) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_SB16) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_SBAWE) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_WAVEFRONT) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_ALS4000) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_CMIPCI) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_ES1938) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_ES1968) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_FM801) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_ICE1712) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_ICE1724) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_INTEL8X0) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_SONICVIBES) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_VIA82XX) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_ALI5451) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_TRIDENT) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_YMFPCI) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_PC98_CS4232) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_SSCAPE) += snd-mpu401-uart.o
+obj-$(CONFIG_SND_MPU401_UART) += snd-mpu401-uart.o
 
-obj-m := $(sort $(obj-m))
+# Toplevel Module Dependency
+obj-$(CONFIG_SND_MPU401) += snd-mpu401.o
--- diff/sound/drivers/mpu401/mpu401_uart.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/drivers/mpu401/mpu401_uart.c	2004-03-09 11:51:52.000000000 +0000
@@ -528,9 +528,9 @@ int snd_mpu401_uart_new(snd_card_t * car
 	mpu->irq = irq;
 	mpu->irq_flags = irq_flags;
 	if (card->shortname[0])
-		snprintf(rmidi->name, sizeof(rmidi->name), "%s MPU-401", card->shortname);
+		snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI", card->shortname);
 	else
-		sprintf(rmidi->name, "MPU-401 (UART) %d-%d", card->number, device);
+		sprintf(rmidi->name, "MPU-401 MIDI %d-%d", card->number, device);
 	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_mpu401_uart_output);
 	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_mpu401_uart_input);
 	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
--- diff/sound/drivers/opl3/Makefile	2003-06-30 10:07:24.000000000 +0100
+++ source/sound/drivers/opl3/Makefile	2004-03-09 11:51:52.000000000 +0000
@@ -9,37 +9,13 @@ ifeq ($(CONFIG_SND_SEQUENCER_OSS),y)
 snd-opl3-synth-objs += opl3_oss.o
 endif
 
-OPL3_OBJS = snd-opl3-lib.o
-ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
-OPL3_OBJS += snd-opl3-synth.o
-endif
-
-# Toplevel Module Dependency
-obj-$(CONFIG_SND_ALS100) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_AZT2320) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_AZT3328) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_DT019X) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_ES18XX) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_OPL3SA2) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_AD1816A) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_CS4232) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_PC98_CS4232) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_CS4236) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_ES1688) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_GUSEXTREME) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_OPTI92X_AD1848) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_OPTI92X_CS4231) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_OPTI93X) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_SB8) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_SB16) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_SBAWE) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_WAVEFRONT) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_ALS4000) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_CMIPCI) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_CS4281) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_ES1938) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_FM801) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_SONICVIBES) += $(OPL3_OBJS)
-obj-$(CONFIG_SND_YMFPCI) += $(OPL3_OBJS)
+#
+# this function returns:
+#   "m" - CONFIG_SND_SEQUENCER is m
+#   <empty string> - CONFIG_SND_SEQUENCER is undefined
+#   otherwise parameter #1 value
+#
+sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
 
-obj-m := $(sort $(obj-m))
+obj-$(CONFIG_SND_OPL3_LIB) += snd-opl3-lib.o
+obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-opl3-synth.o
--- diff/sound/drivers/opl4/Makefile	2003-06-30 10:07:24.000000000 +0100
+++ source/sound/drivers/opl4/Makefile	2004-03-09 11:51:52.000000000 +0000
@@ -6,10 +6,13 @@
 snd-opl4-lib-objs := opl4_lib.o opl4_mixer.o opl4_proc.o
 snd-opl4-synth-objs := opl4_seq.o opl4_synth.o yrw801.o
 
-OPL4_OBJS := snd-opl4-lib.o
-ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
-  OPL4_OBJS += snd-opl4-synth.o
-endif
+#
+# this function returns:
+#   "m" - CONFIG_SND_SEQUENCER is m
+#   <empty string> - CONFIG_SND_SEQUENCER is undefined
+#   otherwise parameter #1 value
+#
+sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
 
-obj-$(CONFIG_SND_OPTI92X_AD1848) += $(OPL4_OBJS)
-obj-$(CONFIG_SND_OPTI92X_CS4231) += $(OPL4_OBJS)
+obj-$(CONFIG_SND_OPL4_LIB) += snd-opl4-lib.o
+obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-opl4-synth.o
\ No newline at end of file
--- diff/sound/drivers/vx/Makefile	2003-06-30 10:07:24.000000000 +0100
+++ source/sound/drivers/vx/Makefile	2004-03-09 11:51:52.000000000 +0000
@@ -5,7 +5,4 @@
 
 snd-vx-lib-objs := vx_core.o vx_hwdep.o vx_pcm.o vx_mixer.o vx_cmd.o vx_uer.o
 
-obj-$(CONFIG_SND_VXPOCKET) += snd-vx-lib.o
-obj-$(CONFIG_SND_VXP440) += snd-vx-lib.o
-obj-$(CONFIG_SND_VX222) += snd-vx-lib.o
-
+obj-$(CONFIG_SND_VX_LIB) += snd-vx-lib.o
--- diff/sound/drivers/vx/vx_core.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/drivers/vx/vx_core.c	2004-03-09 11:51:52.000000000 +0000
@@ -355,11 +355,12 @@ int vx_send_msg_nolock(vx_core_t *chip, 
  */
 int vx_send_msg(vx_core_t *chip, struct vx_rmh *rmh)
 {
+	unsigned long flags;
 	int err;
 
-	spin_lock_bh(&chip->lock);
+	spin_lock_irqsave(&chip->lock, flags);
 	err = vx_send_msg_nolock(chip, rmh);
-	spin_unlock_bh(&chip->lock);
+	spin_unlock_irqrestore(&chip->lock, flags);
 	return err;
 }
 
@@ -414,11 +415,12 @@ int vx_send_rih_nolock(vx_core_t *chip, 
  */
 int vx_send_rih(vx_core_t *chip, int cmd)
 {
+	unsigned long flags;
 	int err;
 
-	spin_lock_bh(&chip->lock);
+	spin_lock_irqsave(&chip->lock, flags);
 	err = vx_send_rih_nolock(chip, cmd);
-	spin_unlock_bh(&chip->lock);
+	spin_unlock_irqrestore(&chip->lock, flags);
 	return err;
 }
 
--- diff/sound/drivers/vx/vx_mixer.c	2003-06-30 10:07:24.000000000 +0100
+++ source/sound/drivers/vx/vx_mixer.c	2004-03-09 11:51:52.000000000 +0000
@@ -919,7 +919,7 @@ int snd_vx_mixer_new(vx_core_t *chip)
 	if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958, chip))) < 0)
 		return err;
 	/* VU, peak, saturation meters */
-	for (c = 0; c < 1; c++) {
+	for (c = 0; c < 2; c++) {
 		static char *dir[2] = { "Output", "Input" };
 		for (i = 0; i < chip->hw->num_ins; i++) {
 			int val = (i * 2) | (c << 8);
--- diff/sound/drivers/vx/vx_pcm.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/drivers/vx/vx_pcm.c	2004-03-09 11:51:52.000000000 +0000
@@ -561,7 +561,7 @@ static snd_pcm_hardware_t vx_pcm_playbac
 	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
 	.rate_min =		5000,
 	.rate_max =		48000,
-	.channels_min =		2,
+	.channels_min =		1,
 	.channels_max =		2,
 	.buffer_bytes_max =	(128*1024),
 	.period_bytes_min =	126,
@@ -958,7 +958,7 @@ static snd_pcm_hardware_t vx_pcm_capture
 	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
 	.rate_min =		5000,
 	.rate_max =		48000,
-	.channels_min =		2,
+	.channels_min =		1,
 	.channels_max =		2,
 	.buffer_bytes_max =	(128*1024),
 	.period_bytes_min =	126,
--- diff/sound/i2c/other/Makefile	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/i2c/other/Makefile	2004-03-09 11:51:52.000000000 +0000
@@ -3,10 +3,12 @@
 # Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz>
 #
 
+snd-ak4117-objs := ak4117.o
 snd-ak4xxx-adda-objs := ak4xxx-adda.o
 snd-tea575x-tuner-objs := tea575x-tuner.o
 
 # Module Dependency
+obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o
 obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o
 obj-$(CONFIG_SND_ICE1724) += snd-ak4xxx-adda.o
 obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o
--- diff/sound/isa/Kconfig	2003-06-30 10:07:24.000000000 +0100
+++ source/sound/isa/Kconfig	2004-03-09 11:51:52.000000000 +0000
@@ -6,6 +6,9 @@ menu "ISA devices"
 config SND_AD1816A
 	tristate "Analog Devices SoundPort AD1816A"
 	depends on SND && ISAPNP
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Analog Devices SoundPort AD1816A or
 	  compatible sound chips.
@@ -13,6 +16,7 @@ config SND_AD1816A
 config SND_AD1848
 	tristate "Generic AD1848/CS4248 driver"
 	depends on SND
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for AD1848 (Analog Devices) or CS4248 
 	  (Cirrus Logic - Crystal Semiconductors) chips. Please, for newer chips
@@ -21,6 +25,8 @@ config SND_AD1848
 config SND_CS4231
 	tristate "Generic Cirrus Logic CS4231 driver"
 	depends on SND
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for CS4231 chips from Cirrus Logic -
 	  Crystal Semiconductors.
@@ -28,6 +34,9 @@ config SND_CS4231
 config SND_CS4232
 	tristate "Generic Cirrus Logic CS4232 driver"
 	depends on SND
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for CS4232 chips from Cirrus Logic -
 	  Crystal Semiconductors.
@@ -35,6 +44,9 @@ config SND_CS4232
 config SND_CS4236
 	tristate "Generic Cirrus Logic CS4236+ driver"
 	depends on SND
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for CS4235,CS4236,CS4237B,CS4238B,CS4239
 	  chips from Cirrus Logic - Crystal Semiconductors.
@@ -42,6 +54,9 @@ config SND_CS4236
 config SND_PC98_CS4232
 	tristate "NEC PC9800 CS4232 driver"
 	depends on SND && X86_PC9800
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for NEC PC-9801/PC-9821 on-board
 	  soundchip based on CS4232.
@@ -49,42 +64,59 @@ config SND_PC98_CS4232
 config SND_ES968
 	tristate "Generic ESS ES968 driver"
 	depends on SND && ISAPNP
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for ESS AudioDrive ES968 chip.
 
 config SND_ES1688
 	tristate "Generic ESS ES688/ES1688 driver"
 	depends on SND
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for ESS AudioDrive ES688 or ES1688 chips.
 
 config SND_ES18XX
 	tristate "Generic ESS ES18xx driver"
 	depends on SND
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for ESS AudioDrive ES18xx chips.
 
 config SND_GUSCLASSIC
 	tristate "Gravis UltraSound Classic"
 	depends on SND
+	select SND_RAWMIDI
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Gravis UltraSound Classic soundcard.
 
 config SND_GUSEXTREME
 	tristate "Gravis UltraSound Extreme"
 	depends on SND
+	select SND_HWDEP
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Gravis UltraSound Extreme soundcard.
 
 config SND_GUSMAX
 	tristate "Gravis UltraSound MAX"
 	depends on SND
+	select SND_RAWMIDI
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Gravis UltraSound MAX soundcard.
 
 config SND_INTERWAVE
 	tristate "AMD InterWave, Gravis UltraSound PnP"
 	depends on SND
+	select SND_RAWMIDI
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for AMD InterWave based soundcards
 	  (Gravis UltraSound Plug & Play, STB SoundRage32, MED3210, Dynasonic Pro,
@@ -93,6 +125,8 @@ config SND_INTERWAVE
 config SND_INTERWAVE_STB
 	tristate "AMD InterWave + TEA6330T (UltraSound 32-Pro)"
 	depends on SND
+	select SND_RAWMIDI
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for AMD InterWave based soundcards
 	  with TEA6330T bass and treble regulator (UltraSound 32-Pro).
@@ -100,6 +134,10 @@ config SND_INTERWAVE_STB
 config SND_OPTI92X_AD1848
 	tristate "OPTi 82C92x - AD1848"
 	depends on SND
+	select SND_OPL3_LIB
+	select SND_OPL4_LIB
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Opti92x soundcards equiped with
 	  AD1848 codec.
@@ -107,6 +145,10 @@ config SND_OPTI92X_AD1848
 config SND_OPTI92X_CS4231
 	tristate "OPTi 82C92x - CS4231"
 	depends on SND
+	select SND_OPL3_LIB
+	select SND_OPL4_LIB
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Opti92x soundcards equiped with
 	  CS4231 codec.
@@ -114,12 +156,18 @@ config SND_OPTI92X_CS4231
 config SND_OPTI93X
 	tristate "OPTi 82C93x"
 	depends on SND
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Opti93x soundcards.
 
 config SND_SB8
 	tristate "Sound Blaster 1.0/2.0/Pro (8-bit)"
 	depends on SND
+	select SND_OPL3_LIB
+	select SND_RAWMIDI
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Sound Blaster 1.0/2.0/Pro (8-bit)
 	  soundcards or 100% compatible from Creative.
@@ -127,6 +175,9 @@ config SND_SB8
 config SND_SB16
 	tristate "Sound Blaster 16 (PnP)"
 	depends on SND
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Sound Blaster 16 (including
 	  Plug and Play version).
@@ -134,6 +185,9 @@ config SND_SB16
 config SND_SBAWE
 	tristate "Sound Blaster AWE (32,64) (PnP)"
 	depends on SND
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Sound Blaster AWE (including
 	  Plug and Play version).
@@ -149,6 +203,9 @@ config SND_SB16_CSP
 config SND_WAVEFRONT
 	tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)"
 	depends on SND
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Turtle Beach Maui, Tropez
 	  and Tropez+ soundcards based on Wavefront chip.
@@ -156,6 +213,9 @@ config SND_WAVEFRONT
 config SND_ALS100
 	tristate "Avance Logic ALS100/ALS120"
 	depends on SND && ISAPNP
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Avance Logic ALS100, ALS110,
 	  ALS120 and ALS200 soundcards.
@@ -163,18 +223,25 @@ config SND_ALS100
 config SND_AZT2320
 	tristate "Aztech Systems AZT2320"
 	depends on SND && ISAPNP
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Aztech Systems AZT2320 soundcard.
 
 config SND_CMI8330
 	tristate "C-Media CMI8330"
 	depends on SND
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for C-Media CMI8330 based soundcards.
 
 config SND_DT019X
 	tristate "Diamond Technologies DT-019X, Avance Logic ALS-007"
 	depends on SND && ISAPNP
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Diamond Technologies DT-019X and
 	  Avance Logic ALS-007 soundcards.
@@ -182,18 +249,25 @@ config SND_DT019X
 config SND_OPL3SA2
 	tristate "Yamaha OPL3-SA2/SA3"
 	depends on SND
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Yamaha OPL3SA2 or OPL3SA3 chips.
 
 config SND_SGALAXY
 	tristate "Aztech Sound Galaxy"
 	depends on SND
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Aztech Sound Galaxy.
 
 config SND_SSCAPE
 	tristate "Ensoniq SoundScape PnP driver"
 	depends on SND
+	select SND_HWDEP
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Ensoniq SoundScape PnP
 	  soundcard.
--- diff/sound/isa/ad1816a/ad1816a_lib.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/isa/ad1816a/ad1816a_lib.c	2004-03-09 11:51:52.000000000 +0000
@@ -684,7 +684,9 @@ int snd_ad1816a_pcm(ad1816a_t *chip, int
 	strcpy(pcm->name, snd_ad1816a_chip_id(chip));
 	snd_ad1816a_init(chip);
 
-	snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_isa_data(),
+					      64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
 
 	chip->pcm = pcm;
 	if (rpcm)
--- diff/sound/isa/ad1848/ad1848_lib.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/isa/ad1848/ad1848_lib.c	2004-03-09 11:51:52.000000000 +0000
@@ -1043,7 +1043,9 @@ int snd_ad1848_pcm(ad1848_t *chip, int d
 	pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
 	strcpy(pcm->name, snd_ad1848_chip_id(chip));
 
-	snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, chip->dma > 3 ? 128*1024 : 64*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_isa_data(),
+					      64*1024, chip->dma > 3 ? 128*1024 : 64*1024);
 
 	chip->pcm = pcm;
 	if (rpcm)
--- diff/sound/isa/cmi8330.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/isa/cmi8330.c	2004-03-09 11:51:52.000000000 +0000
@@ -438,7 +438,9 @@ static int __devinit snd_cmi8330_pcm(snd
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &chip->streams[SNDRV_PCM_STREAM_PLAYBACK].ops);
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &chip->streams[SNDRV_PCM_STREAM_CAPTURE].ops);
 
-	snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, 128*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_isa_data(),
+					      64*1024, 128*1024);
 	chip->pcm = pcm;
 
 	return 0;
--- diff/sound/isa/cs423x/cs4231_lib.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/isa/cs423x/cs4231_lib.c	2004-03-09 11:51:52.000000000 +0000
@@ -1653,17 +1653,21 @@ int snd_cs4231_pcm(cs4231_t *chip, int d
 	strcpy(pcm->name, snd_cs4231_chip_id(chip));
 
 #ifdef LEGACY_SUPPORT
-	snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_isa_data(),
+					      64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
 #else
 #  ifdef EBUS_SUPPORT
         if (chip->ebus_flag) {
-                snd_pcm_lib_preallocate_pci_pages_for_all(chip->dev_u.pdev, pcm,
-                                                          64*1024, 128*1024);
+                snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_PCI,
+                				      chip->dev_u.pdev,
+						      64*1024, 128*1024);
         } else {
 #  endif
 #  ifdef SBUS_SUPPORT
-                snd_pcm_lib_preallocate_sbus_pages_for_all(chip->dev_u.sdev, pcm,
-                                                           64*1024, 128*1024);
+                snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS,
+                				      chip->dev_u.sdev,
+						      64*1024, 128*1024);
 #  endif
 #  ifdef EBUS_SUPPORT
         }
--- diff/sound/isa/es1688/es1688_lib.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/isa/es1688/es1688_lib.c	2004-03-09 11:51:52.000000000 +0000
@@ -752,7 +752,9 @@ int snd_es1688_pcm(es1688_t * chip, int 
 	sprintf(pcm->name, snd_es1688_chip_id(chip));
 	chip->pcm = pcm;
 
-	snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, 64*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_isa_data(),
+					      64*1024, 64*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
--- diff/sound/isa/es18xx.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/isa/es18xx.c	2004-03-09 11:51:52.000000000 +0000
@@ -1598,7 +1598,10 @@ int __devinit snd_es18xx_pcm(es18xx_t *c
 	sprintf(pcm->name, "ESS AudioDrive ES%x", chip->version);
         chip->pcm = pcm;
 
-	snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_isa_data(),
+					      64*1024,
+					      chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
 
         if (rpcm)
         	*rpcm = pcm;
--- diff/sound/isa/gus/gus_pcm.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/isa/gus/gus_pcm.c	2004-03-09 11:51:52.000000000 +0000
@@ -874,7 +874,9 @@ int snd_gf1_pcm_new(snd_gus_card_t * gus
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_gf1_pcm_playback_ops);
 
 	for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next)
-		snd_pcm_lib_preallocate_isa_pages(substream, 64*1024, gus->gf1.dma1 > 3 ? 128*1024 : 64*1024);
+		snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_isa_data(),
+					      64*1024, gus->gf1.dma1 > 3 ? 128*1024 : 64*1024);
 	
 	pcm->info_flags = 0;
 	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
@@ -882,7 +884,9 @@ int snd_gf1_pcm_new(snd_gus_card_t * gus
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_gf1_pcm_capture_ops);
 		if (gus->gf1.dma2 == gus->gf1.dma1)
 			pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX;
-		snd_pcm_lib_preallocate_isa_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, 64*1024, gus->gf1.dma2 > 3 ? 128*1024 : 64*1024);
+		snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
+					      SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(),
+					      64*1024, gus->gf1.dma2 > 3 ? 128*1024 : 64*1024);
 	}
 	strcpy(pcm->name, pcm->id);
 	if (gus->interwave) {
--- diff/sound/isa/opti9xx/opti92x-ad1848.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/isa/opti9xx/opti92x-ad1848.c	2004-03-09 11:51:52.000000000 +0000
@@ -311,8 +311,12 @@ static char * snd_opti9xx_names[] = {
 static long snd_legacy_find_free_ioport(long *port_table, long size)
 {
 	while (*port_table != -1) {
-		if (!check_region(*port_table, size))
+		struct resource *res;
+		if ((res = request_region(*port_table, size, "ALSA test")) != NULL) {
+			release_resource(res);
+			kfree_nocheck(res);
 			return *port_table;
+		}
 		port_table++;
 	}
 	return -1;
@@ -1399,7 +1403,9 @@ int snd_opti93x_pcm(opti93x_t *codec, in
 
 	strcpy(pcm->name, snd_opti93x_chip_id(codec));
 
-	snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, codec->dma1 > 3 || codec->dma2 > 3 ? 128*1024 : 64*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_isa_data(),
+					      64*1024, codec->dma1 > 3 || codec->dma2 > 3 ? 128*1024 : 64*1024);
 
 	codec->pcm = pcm;
 	if (rpcm)
@@ -1672,13 +1678,18 @@ static int __devinit snd_card_opti9xx_de
 		if ((err = snd_opti9xx_init(chip, i)) < 0)
 			return err;
 
-		if (check_region(chip->mc_base, chip->mc_base_size))
+		if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL)
 			continue;
 
 		value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(1));
 		if ((value != 0xff) && (value != inb(chip->mc_base + 1)))
 			if (value == snd_opti9xx_read(chip, OPTi9XX_MC_REG(1)))
 				return 1;
+
+		release_resource(chip->res_mc_base);
+		kfree_nocheck(chip->res_mc_base);
+		chip->res_mc_base = NULL;
+
 	}
 #else	/* OPTi93X */
 	for (i = OPTi9XX_HW_82C931; i >= OPTi9XX_HW_82C930; i--) {
@@ -1688,7 +1699,7 @@ static int __devinit snd_card_opti9xx_de
 		if ((err = snd_opti9xx_init(chip, i)) < 0)
 			return err;
 
-		if (check_region(chip->mc_base, chip->mc_base_size))
+		if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL)
 			continue;
 
 		spin_lock_irqsave(&chip->lock, flags);
@@ -1701,6 +1712,10 @@ static int __devinit snd_card_opti9xx_de
 		snd_opti9xx_write(chip, OPTi9XX_MC_REG(7), 0xff - value);
 		if (snd_opti9xx_read(chip, OPTi9XX_MC_REG(7)) == 0xff - value)
 			return 1;
+
+		release_resource(chip->res_mc_base);
+		kfree_nocheck(chip->res_mc_base);
+		chip->res_mc_base = NULL;
 	}
 #endif	/* OPTi93X */
 
@@ -1984,7 +1999,8 @@ static int __devinit snd_card_opti9xx_pr
 	}
 #endif	/* CONFIG_PNP */
 
-	if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL) {
+	if (! chip->res_mc_base &&
+	    (chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL) {
 		snd_card_free(card);
 		return -ENOMEM;
 	}
--- diff/sound/isa/sb/sb16_main.c	2003-05-21 11:50:17.000000000 +0100
+++ source/sound/isa/sb/sb16_main.c	2004-03-09 11:51:52.000000000 +0000
@@ -881,7 +881,9 @@ int snd_sb16dsp_pcm(sb_t * chip, int dev
 	else
 		pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
 
-	snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, 128*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_isa_data(),
+					      64*1024, 128*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
--- diff/sound/isa/sb/sb8_main.c	2003-06-30 10:07:24.000000000 +0100
+++ source/sound/isa/sb/sb8_main.c	2004-03-09 11:51:52.000000000 +0000
@@ -535,7 +535,9 @@ int snd_sb8dsp_pcm(sb_t *chip, int devic
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops);
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops);
 
-	snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, 64*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_isa_data(),
+					      64*1024, 64*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
--- diff/sound/isa/sscape.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/isa/sscape.c	2004-03-09 11:51:52.000000000 +0000
@@ -168,23 +168,20 @@ static inline struct soundscape *get_hwd
 }
 
 
-struct dmabuf {
-	size_t size;
-	unsigned char *data;
-	dma_addr_t addr;
-};
-
 /*
  * Allocates some kernel memory that we can use for DMA.
  * I think this means that the memory has to map to
  * contiguous pages of physical memory.
  */
-static struct dmabuf *get_dmabuf(struct dmabuf *buf, unsigned long s)
+static struct snd_dma_buffer *get_dmabuf(struct snd_dma_buffer *buf, unsigned long size)
 {
 	if (buf) {
-		buf->data = snd_malloc_isa_pages_fallback(s, &buf->addr, &buf->size);
-		if (!buf->data) {
-			snd_printk(KERN_ERR "sscape: Failed to allocate %lu bytes for DMA\n", s);
+		struct snd_dma_device dev;
+		memset(&dev, 0, sizeof(dev));
+		dev.type = SNDRV_DMA_TYPE_DEV;
+		dev.dev = snd_dma_isa_data();
+		if (snd_dma_alloc_pages_fallback(&dev, size, buf) < 0) {
+			snd_printk(KERN_ERR "sscape: Failed to allocate %lu bytes for DMA\n", size);
 			return NULL;
 		}
 	}
@@ -195,10 +192,15 @@ static struct dmabuf *get_dmabuf(struct 
 /*
  * Release the DMA-able kernel memory ...
  */
-static void free_dmabuf(struct dmabuf *buf)
+static void free_dmabuf(struct snd_dma_buffer *buf)
 {
-	if (buf && buf->data)
-		snd_free_isa_pages(buf->size, buf->data, buf->addr);
+	if (buf && buf->area) {
+		struct snd_dma_device dev;
+		memset(&dev, 0, sizeof(dev));
+		dev.type = SNDRV_DMA_TYPE_DEV;
+		dev.dev = snd_dma_isa_data();
+		snd_dma_free_pages(&dev, buf);
+	}
 }
 
 
@@ -456,7 +458,7 @@ static int upload_dma_data(struct sounds
                            size_t size)
 {
 	unsigned long flags;
-	struct dmabuf dma;
+	struct snd_dma_buffer dma;
 	int ret;
 
 	if (!get_dmabuf(&dma, PAGE_ALIGN(size)))
@@ -500,8 +502,8 @@ static int upload_dma_data(struct sounds
 		 * comes from USERSPACE. We have already verified
 		 * the userspace pointer ...
 		 */
-		len = min(size, dma.size);
-		__copy_from_user(dma.data, data, len);
+		len = min(size, dma.bytes);
+		__copy_from_user(dma.area, data, len);
 		data += len;
 		size -= len;
 
--- diff/sound/isa/wavefront/wavefront_synth.c	2003-05-21 11:49:46.000000000 +0100
+++ source/sound/isa/wavefront/wavefront_synth.c	2004-03-09 11:51:52.000000000 +0000
@@ -1913,11 +1913,11 @@ wavefront_reset_to_cleanliness (snd_wave
 	return (1);
 }
 
-#define __KERNEL_SYSCALLS__
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/unistd.h>
+#include <linux/syscalls.h>
 #include <asm/uaccess.h>
 
 static int errno;
@@ -1947,7 +1947,7 @@ wavefront_download_firmware (snd_wavefro
 	fs = get_fs();
 	set_fs (get_ds());
 
-	if ((fd = open (path, 0, 0)) < 0) {
+	if ((fd = sys_open (path, 0, 0)) < 0) {
 		snd_printk ("Unable to load \"%s\".\n",
 			path);
 		return 1;
@@ -1956,7 +1956,7 @@ wavefront_download_firmware (snd_wavefro
 	while (1) {
 		int x;
 
-		if ((x = read (fd, &section_length, sizeof (section_length))) !=
+		if ((x = sys_read (fd, &section_length, sizeof (section_length))) !=
 		    sizeof (section_length)) {
 			snd_printk ("firmware read error.\n");
 			goto failure;
@@ -1966,7 +1966,7 @@ wavefront_download_firmware (snd_wavefro
 			break;
 		}
 
-		if (read (fd, section, section_length) != section_length) {
+		if (sys_read (fd, section, section_length) != section_length) {
 			snd_printk ("firmware section "
 				"read error.\n");
 			goto failure;
@@ -2005,12 +2005,12 @@ wavefront_download_firmware (snd_wavefro
 
 	}
 
-	close (fd);
+	sys_close (fd);
 	set_fs (fs);
 	return 0;
 
  failure:
-	close (fd);
+	sys_close (fd);
 	set_fs (fs);
 	snd_printk ("firmware download failed!!!\n");
 	return 1;
--- diff/sound/oss/Makefile	2003-08-20 14:16:14.000000000 +0100
+++ source/sound/oss/Makefile	2004-03-09 11:51:52.000000000 +0000
@@ -68,7 +68,7 @@ obj-$(CONFIG_SOUND_RME96XX)     += rme96
 obj-$(CONFIG_SOUND_BT878)	+= btaudio.o
 obj-$(CONFIG_SOUND_ALI5455)	+= ali5455.o ac97_codec.o
 obj-$(CONFIG_SOUND_IT8172)	+= ite8172.o ac97_codec.o
-obj-$(CONFIG_SOUND_FORTE)	+= forte.o
+obj-$(CONFIG_SOUND_FORTE)	+= forte.o ac97_codec.o
 
 obj-$(CONFIG_SOUND_AD1980)	+= ac97_plugin_ad1980.o
 obj-$(CONFIG_SOUND_WM97XX)	+= ac97_plugin_wm97xx.o
--- diff/sound/oss/ac97_plugin_ad1980.c	2003-10-09 09:47:34.000000000 +0100
+++ source/sound/oss/ac97_plugin_ad1980.c	2004-03-09 11:51:52.000000000 +0000
@@ -123,3 +123,4 @@ static int ad1980_init(void)
 
 module_init(ad1980_init);
 module_exit(ad1980_exit);
+MODULE_LICENSE("GPL");
--- diff/sound/oss/cs46xx_wrapper-24.h	2003-07-22 18:54:27.000000000 +0100
+++ source/sound/oss/cs46xx_wrapper-24.h	2004-03-09 11:51:52.000000000 +0000
@@ -28,7 +28,7 @@
 
 #include <linux/spinlock.h>
 
-#define CS_OWNER owner:
+#define CS_OWNER .owner =
 #define CS_THIS_MODULE THIS_MODULE,
 void cs46xx_null(struct pci_dev *pcidev) { return; }
 #define cs4x_mem_map_reserve(page) SetPageReserved(page)
--- diff/sound/oss/emu10k1/cardwi.c	2003-05-21 11:49:56.000000000 +0100
+++ source/sound/oss/emu10k1/cardwi.c	2004-03-09 11:51:52.000000000 +0000
@@ -164,7 +164,6 @@ int emu10k1_wavein_open(struct emu10k1_w
 
 	if (alloc_buffer(card, &wiinst->buffer) < 0) {
 		ERROR();
-		emu10k1_wavein_close(wave_dev);
 		return -1;
 	}
 
--- diff/sound/oss/sb_audio.c	2003-05-21 11:50:10.000000000 +0100
+++ source/sound/oss/sb_audio.c	2004-03-09 11:51:52.000000000 +0000
@@ -882,7 +882,7 @@ sb16_copy_from_user(int dev,
 			c -= locallen; p += locallen;
 		}
 		/* used = ( samples * 16 bits size ) */
-		*used = len << 1;
+		*used =  max_in  > ( max_out << 1) ? (max_out << 1) : max_in;
 		/* returned = ( samples * 8 bits size ) */
 		*returned = len;
 	}
--- diff/sound/oss/wavfront.c	2003-05-21 11:50:17.000000000 +0100
+++ source/sound/oss/wavfront.c	2004-03-09 11:51:52.000000000 +0000
@@ -2489,11 +2489,9 @@ static int __init detect_wavefront (int 
 }
 
 #include "os.h"
-#define __KERNEL_SYSCALLS__
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/unistd.h>
 #include <asm/uaccess.h>
 
 static int errno; 
@@ -2523,7 +2521,7 @@ wavefront_download_firmware (char *path)
 	fs = get_fs();
 	set_fs (get_ds());
 
-	if ((fd = open (path, 0, 0)) < 0) {
+	if ((fd = sys_open (path, 0, 0)) < 0) {
 		printk (KERN_WARNING LOGNAME "Unable to load \"%s\".\n",
 			path);
 		return 1;
@@ -2532,7 +2530,7 @@ wavefront_download_firmware (char *path)
 	while (1) {
 		int x;
 
-		if ((x = read (fd, &section_length, sizeof (section_length))) !=
+		if ((x = sys_read (fd, &section_length, sizeof (section_length))) !=
 		    sizeof (section_length)) {
 			printk (KERN_ERR LOGNAME "firmware read error.\n");
 			goto failure;
@@ -2542,7 +2540,7 @@ wavefront_download_firmware (char *path)
 			break;
 		}
 
-		if (read (fd, section, section_length) != section_length) {
+		if (sys_read (fd, section, section_length) != section_length) {
 			printk (KERN_ERR LOGNAME "firmware section "
 				"read error.\n");
 			goto failure;
@@ -2581,12 +2579,12 @@ wavefront_download_firmware (char *path)
 
 	}
 
-	close (fd);
+	sys_close (fd);
 	set_fs (fs);
 	return 0;
 
  failure:
-	close (fd);
+	sys_close (fd);
 	set_fs (fs);
 	printk (KERN_ERR "\nWaveFront: firmware download failed!!!\n");
 	return 1;
--- diff/sound/parisc/Kconfig	2003-06-30 10:07:25.000000000 +0100
+++ source/sound/parisc/Kconfig	2004-03-09 11:51:52.000000000 +0000
@@ -6,6 +6,7 @@ menu "ALSA PA-RISC devices"
 config SND_HARMONY
 	tristate "Harmony/Vivace sound chip"
 	depends on SND
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Harmony/Vivace soundchip
 	  on HP712s, 715/new and many other GSC based machines.
--- diff/sound/parisc/harmony.c	2003-10-09 09:47:34.000000000 +0100
+++ source/sound/parisc/harmony.c	2004-03-09 11:51:52.000000000 +0000
@@ -205,6 +205,7 @@ typedef struct snd_card_harmony {
 	unsigned char *silence_addr;
 	dma_addr_t silence_dma;
 	int silence_count;
+	struct snd_dma_device dma_dev;
 
 	/* alsa stuff */
 	snd_card_t *card;
@@ -844,22 +845,27 @@ static int snd_card_harmony_pcm_init(snd
 	harmony->pcm = pcm;
 	
 	/* initialize graveyard buffer */
-	harmony->graveyard_addr = snd_malloc_pci_pages(harmony->fake_pci_dev, 
+	harmony->dma_dev.type = SNDRV_DMA_TYPE_PCI;
+	harmony->dma_dev.dev = snd_dma_pci_data(harmony->fake_pci_dev); 
+	harmony->graveyard_addr = snd_dma_alloc_pages(&chip->dma_dev,
 			HARMONY_BUF_SIZE*GRAVEYARD_BUFS, &harmony->graveyard_dma);
 	harmony->graveyard_count = 0;
 	
 	/* initialize silence buffers */
-	harmony->silence_addr = snd_malloc_pci_pages(harmony->fake_pci_dev,
+	harmony->silence_addr = snd_dma_alloc_pages(&chip->dma_dev,
 			HARMONY_BUF_SIZE*SILENCE_BUFS, &harmony->silence_dma);
 	harmony->silence_count = 0;
 
-
 	harmony->ply_stopped = harmony->cap_stopped = 1;
 	
 	harmony->playback_substream = NULL;
 	harmony->capture_substream = NULL;
 	harmony->graveyard_count = 0;
 	
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(harmony->fake_pci_dev),
+					      64 * 1024, 128 * 1024);
+
 	return 0;
 }
 
--- diff/sound/pci/Kconfig	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/Kconfig	2004-03-09 11:51:52.000000000 +0000
@@ -3,21 +3,31 @@
 menu "PCI devices"
 	depends on SND!=n && PCI
 
+config SND_AC97_CODEC
+	tristate
+	select SND_PCM
+
 config SND_ALI5451
 	tristate "ALi PCI Audio M5451"
 	depends on SND
+	select SND_MPU401_UART
+	select SND_AC97_CODEC
 	help
 	  Say 'Y' or 'M' to include support for ALI PCI Audio M5451 sound core.
 
 config SND_AZT3328
 	tristate "Aztech AZF3328 / PCI168 (EXPERIMENTAL)"
 	depends on SND && EXPERIMENTAL
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Aztech AZF3328 (PCI168) soundcards.
 
 config SND_BT87X
         tristate "Bt87x Audio Capture"
         depends on SND
+	select SND_PCM
         help
           Say 'Y' or 'M' to include support for recording audio from TV cards
           based on Brooktree Bt878/Bt879 chips.
@@ -25,7 +35,8 @@ config SND_BT87X
 config SND_CS46XX
 	tristate "Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x"
 	depends on SND
-	select GAMEPORT
+	select SND_RAWMIDI
+	select SND_AC97_CODEC
 	help
 	  Say 'Y' or 'M' to include support for Cirrus Logic CS4610 / CS4612 /
 	  CS4614 / CS4615 / CS4622 / CS4624 / CS4630 / CS4280 chips.
@@ -39,12 +50,18 @@ config SND_CS46XX_NEW_DSP
 config SND_CS4281
 	tristate "Cirrus Logic (Sound Fusion) CS4281"
 	depends on SND
+	select SND_OPL3_LIB
+	select SND_RAWMIDI
+	select SND_AC97_CODEC
 	help
 	  Say 'Y' or 'M' to include support for Cirrus Logic CS4281.
 
 config SND_EMU10K1
 	tristate "EMU10K1 (SB Live! & Audigy, E-mu APS)"
 	depends on SND
+	select SND_HWDEP
+	select SND_RAWMIDI
+	select SND_AC97_CODEC
 	help
 	  Say 'Y' or 'M' to include support for Sound Blaster PCI 512, Live!,
 	  Audigy and E-mu APS (partially supported).
@@ -52,18 +69,29 @@ config SND_EMU10K1
 config SND_KORG1212
 	tristate "Korg 1212 IO"
 	depends on SND
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Korg 1212IO.
 
+config SND_MIXART
+	tristate "Digigram miXart"
+	depends on SND
+	select SND_HWDEP
+	select SND_PCM
+	help
+	  Say 'Y' or 'M' to include support for Digigram miXart soundcard.
+
 config SND_NM256
 	tristate "NeoMagic NM256AV/ZX"
 	depends on SND
+	select SND_AC97_CODEC
 	help
 	  Say 'Y' or 'M' to include support for NeoMagic NM256AV/ZX chips.
 
 config SND_RME32
 	tristate "RME Digi32, 32/8, 32 PRO"
 	depends on SND
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for RME Digi32, Digi32 PRO and
 	  Digi32/8 (Sek'd Prodif32, Prodif96 and Prodif Gold) audio devices.
@@ -71,6 +99,7 @@ config SND_RME32
 config SND_RME96
 	tristate "RME Digi96, 96/8, 96/8 PRO"
 	depends on SND
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for RME Digi96, Digi96/8 and
 	  Digi96/8 PRO/PAD/PST.
@@ -78,6 +107,7 @@ config SND_RME96
 config SND_RME9652
 	tristate "RME Digi9652 (Hammerfall)"
 	depends on SND
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for RME Hammerfall (RME Digi9652 /
 	  Digi9636) soundcards.
@@ -85,6 +115,9 @@ config SND_RME9652
 config SND_HDSP
 	tristate "RME Hammerfall DSP Audio"
 	depends on SND
+	select SND_HWDEP
+	select SND_RAWMIDI
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for RME Hammerfall DSP Audio
 	  soundcards.
@@ -92,6 +125,8 @@ config SND_HDSP
 config SND_TRIDENT
 	tristate "Trident 4D-Wave DX/NX; SiS 7018"
 	depends on SND
+	select SND_MPU401_UART
+	select SND_AC97_CODEC
 	help
 	  Say 'Y' or 'M' to include support for Trident 4D-Wave DX/NX and
 	  SiS 7018 soundcards.
@@ -99,6 +134,9 @@ config SND_TRIDENT
 config SND_YMFPCI
 	tristate "Yamaha YMF724/740/744/754"
 	depends on SND
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_AC97_CODEC
 	help
 	  Say 'Y' or 'M' to include support for Yamaha PCI audio chips - 
 	  YMF724, YMF724F, YMF740, YMF740C, YMF744, YMF754.
@@ -106,12 +144,18 @@ config SND_YMFPCI
 config SND_ALS4000
 	tristate "Avance Logic ALS4000"
 	depends on SND
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Avance Logic ALS4000.
 
 config SND_CMIPCI
 	tristate "C-Media 8738, 8338"
 	depends on SND
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for C-Media CMI8338 and 8738 PCI
 	  soundcards.
@@ -119,12 +163,16 @@ config SND_CMIPCI
 config SND_ENS1370
 	tristate "(Creative) Ensoniq AudioPCI 1370"
 	depends on SND
+	select SND_RAWMIDI
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Ensoniq AudioPCI ES1370.
 
 config SND_ENS1371
 	tristate "(Creative) Ensoniq AudioPCI 1371/1373"
 	depends on SND
+	select SND_RAWMIDI
+	select SND_AC97_CODEC
 	help
 	  Say 'Y' or 'M' to include support for Ensoniq AudioPCI ES1371 and
 	  Sound Blaster PCI 64 or 128 soundcards.
@@ -132,6 +180,9 @@ config SND_ENS1371
 config SND_ES1938
 	tristate "ESS ES1938/1946/1969 (Solo-1)"
 	depends on SND
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_AC97_CODEC
 	help
 	  Say 'Y' or 'M' to include support for ESS Solo-1 (ES1938, ES1946, ES1969)
 	  soundcard.
@@ -139,24 +190,31 @@ config SND_ES1938
 config SND_ES1968
 	tristate "ESS ES1968/1978 (Maestro-1/2/2E)"
 	depends on SND
+	select SND_MPU401_UART
+	select SND_AC97_CODEC
 	help
 	  Say 'Y' or 'M' to include support for ESS Maestro 1/2/2E.
 
 config SND_MAESTRO3
 	tristate "ESS Allegro/Maestro3"
 	depends on SND
+	select SND_AC97_CODEC
 	help
 	  Say 'Y' or 'M' to include support for ESS Maestro 3 (Allegro) soundcard.
 
 config SND_FM801
 	tristate "ForteMedia FM801"
 	depends on SND
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_AC97_CODEC
 	help
 	  Say 'Y' or 'M' to include support for ForteMedia FM801 based soundcards.
 
-config CONFIG_SND_FM801_TEA575X
+config SND_FM801_TEA575X
 	tristate "ForteMedia FM801 + TEA5757 tuner"
-	depends on SND_FM801 && CONFIG_VIDEO_DEV
+	depends on SND_FM801
+        select VIDEO_DEV
 	help
 	  Say 'Y' or 'M' to include support for ForteMedia FM801 based soundcards
           with TEA5757 tuner connected to GPIO1-3 pins (Media Forte SF256-PCS-02).
@@ -164,6 +222,8 @@ config CONFIG_SND_FM801_TEA575X
 config SND_ICE1712
 	tristate "ICEnsemble ICE1712 (Envy24)"
 	depends on SND
+	select SND_MPU401_UART
+	select SND_AC97_CODEC
 	help
 	  Say 'Y' or 'M' to include support for ICE1712 (Envy24) based soundcards.
 	  Currently supported hardware is: MidiMan M Audio - Delta 1010(LT), Dio 2496,
@@ -173,6 +233,8 @@ config SND_ICE1712
 config SND_ICE1724
 	tristate "ICE/VT1724 (Envy24HT)"
 	depends on SND
+	select SND_MPU401_UART
+	select SND_AC97_CODEC
 	help
 	  Say 'Y' or 'M' to include support for ICE/VT1724 (Envy24HT) based
 	  soundcards.
@@ -182,6 +244,8 @@ config SND_ICE1724
 config SND_INTEL8X0
 	tristate "Intel i8x0/MX440, SiS 7012; Ali 5455; NForce Audio; AMD768/8111"
 	depends on SND
+	select SND_MPU401_UART
+	select SND_AC97_CODEC
 	help
 	  Say 'Y' or 'M' to include support for Intel8x0 based soundcards,
 	  SiS 7012, AMD768/8111, NVidia NForce and ALi 5455 chips.
@@ -189,18 +253,24 @@ config SND_INTEL8X0
 config SND_SONICVIBES
 	tristate "S3 SonicVibes"
 	depends on SND
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	select SND_AC97_CODEC
 	help
 	  Say 'Y' or 'M' to include support for S3 SonicVibes based soundcards.
 
 config SND_VIA82XX
 	tristate "VIA 82C686A/B, 8233 South Bridge"
 	depends on SND
+	select SND_MPU401_UART
+	select SND_AC97_CODEC
 	help
 	  Say 'Y' or 'M' to include support for VIA VT82C686A/B, VT8233 South Bridge.
 
 config SND_VX222
 	tristate "Digigram VX222"
 	depends on SND
+	select SND_VX_LIB
 	help
 	  Say 'Y' or 'M' to include support for Digigram VX222 soundcards.
 
--- diff/sound/pci/Makefile	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/Makefile	2004-03-09 11:51:52.000000000 +0000
@@ -38,4 +38,16 @@ obj-$(CONFIG_SND_RME96) += snd-rme96.o
 obj-$(CONFIG_SND_SONICVIBES) += snd-sonicvibes.o
 obj-$(CONFIG_SND_VIA82XX) += snd-via82xx.o
 
-obj-$(CONFIG_SND) += ac97/ ali5451/ cs46xx/ emu10k1/ korg1212/ nm256/ rme9652/ trident/ ymfpci/ ice1712/ vx222/
+obj-$(CONFIG_SND) += \
+	ac97/ \
+	ali5451/ \
+	cs46xx/ \
+	emu10k1/ \
+	ice1712/ \
+	korg1212/ \
+	mixart/ \
+	nm256/ \
+	rme9652/ \
+	trident/ \
+	ymfpci/ \
+	vx222/
--- diff/sound/pci/ac97/Makefile	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/ac97/Makefile	2004-03-09 11:51:52.000000000 +0000
@@ -7,21 +7,7 @@ snd-ac97-codec-objs := ac97_codec.o ac97
 snd-ak4531-codec-objs := ak4531_codec.o
 
 # Toplevel Module Dependency
-obj-$(CONFIG_SND_CS4281) += snd-ac97-codec.o
+obj-$(CONFIG_SND_AC97_CODEC) += snd-ac97-codec.o
 obj-$(CONFIG_SND_ENS1370) += snd-ak4531-codec.o
-obj-$(CONFIG_SND_ENS1371) += snd-ac97-codec.o
-obj-$(CONFIG_SND_ES1968) += snd-ac97-codec.o
-obj-$(CONFIG_SND_FM801) += snd-ac97-codec.o
-obj-$(CONFIG_SND_ICE1712) += snd-ac97-codec.o
-obj-$(CONFIG_SND_ICE1724) += snd-ac97-codec.o
-obj-$(CONFIG_SND_INTEL8X0) += snd-ac97-codec.o
-obj-$(CONFIG_SND_MAESTRO3) += snd-ac97-codec.o
-obj-$(CONFIG_SND_VIA82XX) += snd-ac97-codec.o
-obj-$(CONFIG_SND_ALI5451) += snd-ac97-codec.o
-obj-$(CONFIG_SND_CS46XX) += snd-ac97-codec.o
-obj-$(CONFIG_SND_EMU10K1) += snd-ac97-codec.o
-obj-$(CONFIG_SND_NM256) += snd-ac97-codec.o
-obj-$(CONFIG_SND_TRIDENT) += snd-ac97-codec.o
-obj-$(CONFIG_SND_YMFPCI) += snd-ac97-codec.o
 
 obj-m := $(sort $(obj-m))
--- diff/sound/pci/ac97/ac97_codec.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/ac97/ac97_codec.c	2004-03-09 11:51:52.000000000 +0000
@@ -100,13 +100,12 @@ static const ac97_codec_id_t snd_ac97_co
 { 0x41445361, 0xffffffff, "AD1886",		patch_ad1886,	NULL },
 { 0x41445362, 0xffffffff, "AD1887",		patch_ad1881,	NULL },
 { 0x41445363, 0xffffffff, "AD1886A",		patch_ad1881,	NULL },
+{ 0x41445368, 0xffffffff, "AD1888",		patch_ad1888,	NULL },
 { 0x41445370, 0xffffffff, "AD1980",		patch_ad1980,	NULL },
 { 0x41445372, 0xffffffff, "AD1981A",		patch_ad1981a,	NULL },
 { 0x41445374, 0xffffffff, "AD1981B",		patch_ad1981b,	NULL },
 { 0x41445375, 0xffffffff, "AD1985",		patch_ad1985,	NULL },
-{ 0x414c4300, 0xfffffff0, "RL5306",	 	NULL,		NULL },
-{ 0x414c4310, 0xfffffff0, "RL5382", 		NULL,		NULL },
-{ 0x414c4320, 0xfffffff0, "RL5383", 		NULL,		NULL },
+{ 0x414c4300, 0xffffff00, "ALC100/100P", 	NULL,		NULL },
 { 0x414c4710, 0xfffffff0, "ALC200/200P",	NULL,		NULL },
 { 0x414c4720, 0xfffffff0, "ALC650",		patch_alc650,	NULL },
 { 0x414c4721, 0xfffffff0, "ALC650D",		patch_alc650,	NULL },
@@ -273,6 +272,11 @@ void snd_ac97_write(ac97_t *ac97, unsign
 {
 	if (!snd_ac97_valid_reg(ac97, reg))
 		return;
+	if ((ac97->id & 0xffffff00) == 0x414c4300) {
+		/* Fix H/W bug of ALC100/100P */
+		if (reg == AC97_MASTER || reg == AC97_HEADPHONE)
+			ac97->bus->write(ac97, AC97_RESET, 0);	/* reset audio codec */
+	}
 	ac97->bus->write(ac97, reg, value);
 }
 
@@ -688,7 +692,7 @@ AC97_DOUBLE("Surround Playback Volume", 
 };
 
 static const snd_kcontrol_new_t snd_ac97_control_eapd =
-AC97_SINGLE("External Amplifier Power Down", AC97_POWERDOWN, 15, 1, 0);
+AC97_SINGLE("External Amplifier", AC97_POWERDOWN, 15, 1, 1);
 
 static int snd_ac97_spdif_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
@@ -1526,38 +1530,40 @@ static int snd_ac97_modem_build(snd_card
 	return 0;
 }
 
-static int snd_ac97_test_rate(ac97_t *ac97, int reg, int rate)
+static int snd_ac97_test_rate(ac97_t *ac97, int reg, int shadow_reg, int rate)
 {
 	unsigned short val;
 	unsigned int tmp;
 
 	tmp = ((unsigned int)rate * ac97->bus->clock) / 48000;
 	snd_ac97_write_cache(ac97, reg, tmp & 0xffff);
+	if (shadow_reg)
+		snd_ac97_write_cache(ac97, shadow_reg, tmp & 0xffff);
 	val = snd_ac97_read(ac97, reg);
 	return val == (tmp & 0xffff);
 }
 
-static void snd_ac97_determine_rates(ac97_t *ac97, int reg, unsigned int *r_result)
+static void snd_ac97_determine_rates(ac97_t *ac97, int reg, int shadow_reg, unsigned int *r_result)
 {
 	unsigned int result = 0;
 
 	/* test a non-standard rate */
-	if (snd_ac97_test_rate(ac97, reg, 11000))
+	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 11000))
 		result |= SNDRV_PCM_RATE_CONTINUOUS;
 	/* let's try to obtain standard rates */
-	if (snd_ac97_test_rate(ac97, reg, 8000))
+	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 8000))
 		result |= SNDRV_PCM_RATE_8000;
-	if (snd_ac97_test_rate(ac97, reg, 11025))
+	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 11025))
 		result |= SNDRV_PCM_RATE_11025;
-	if (snd_ac97_test_rate(ac97, reg, 16000))
+	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 16000))
 		result |= SNDRV_PCM_RATE_16000;
-	if (snd_ac97_test_rate(ac97, reg, 22050))
+	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 22050))
 		result |= SNDRV_PCM_RATE_22050;
-	if (snd_ac97_test_rate(ac97, reg, 32000))
+	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 32000))
 		result |= SNDRV_PCM_RATE_32000;
-	if (snd_ac97_test_rate(ac97, reg, 44100))
+	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 44100))
 		result |= SNDRV_PCM_RATE_44100;
-	if (snd_ac97_test_rate(ac97, reg, 48000))
+	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 48000))
 		result |= SNDRV_PCM_RATE_48000;
 	*r_result = result;
 }
@@ -1866,8 +1872,8 @@ int snd_ac97_mixer(ac97_bus_t * bus, ac9
 	if (ac97->ext_id & 0x0189)	/* L/R, MIC, SDAC, LDAC VRA support */
 		snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, ac97->ext_id & 0x0189);
 	if (ac97->ext_id & AC97_EI_VRA) {	/* VRA support */
-		snd_ac97_determine_rates(ac97, AC97_PCM_FRONT_DAC_RATE, &ac97->rates[AC97_RATES_FRONT_DAC]);
-		snd_ac97_determine_rates(ac97, AC97_PCM_LR_ADC_RATE, &ac97->rates[AC97_RATES_ADC]);
+		snd_ac97_determine_rates(ac97, AC97_PCM_FRONT_DAC_RATE, 0, &ac97->rates[AC97_RATES_FRONT_DAC]);
+		snd_ac97_determine_rates(ac97, AC97_PCM_LR_ADC_RATE, 0, &ac97->rates[AC97_RATES_ADC]);
 	} else {
 		ac97->rates[AC97_RATES_FRONT_DAC] = SNDRV_PCM_RATE_48000;
 		ac97->rates[AC97_RATES_ADC] = SNDRV_PCM_RATE_48000;
@@ -1884,16 +1890,16 @@ int snd_ac97_mixer(ac97_bus_t * bus, ac9
 						SNDRV_PCM_RATE_32000;
 	}
 	if (ac97->ext_id & AC97_EI_VRM) {	/* MIC VRA support */
-		snd_ac97_determine_rates(ac97, AC97_PCM_MIC_ADC_RATE, &ac97->rates[AC97_RATES_MIC_ADC]);
+		snd_ac97_determine_rates(ac97, AC97_PCM_MIC_ADC_RATE, 0, &ac97->rates[AC97_RATES_MIC_ADC]);
 	} else {
 		ac97->rates[AC97_RATES_MIC_ADC] = SNDRV_PCM_RATE_48000;
 	}
 	if (ac97->ext_id & AC97_EI_SDAC) {	/* SDAC support */
-		snd_ac97_determine_rates(ac97, AC97_PCM_SURR_DAC_RATE, &ac97->rates[AC97_RATES_SURR_DAC]);
+		snd_ac97_determine_rates(ac97, AC97_PCM_SURR_DAC_RATE, AC97_PCM_FRONT_DAC_RATE, &ac97->rates[AC97_RATES_SURR_DAC]);
 		ac97->scaps |= AC97_SCAP_SURROUND_DAC;
 	}
 	if (ac97->ext_id & AC97_EI_LDAC) {	/* LDAC support */
-		snd_ac97_determine_rates(ac97, AC97_PCM_LFE_DAC_RATE, &ac97->rates[AC97_RATES_LFE_DAC]);
+		snd_ac97_determine_rates(ac97, AC97_PCM_LFE_DAC_RATE, AC97_PCM_FRONT_DAC_RATE, &ac97->rates[AC97_RATES_LFE_DAC]);
 		ac97->scaps |= AC97_SCAP_CENTER_LFE_DAC;
 	}
 	/* additional initializations */
@@ -1937,6 +1943,15 @@ int snd_ac97_mixer(ac97_bus_t * bus, ac9
 			return -ENOMEM;
 		}
 	}
+	/* make sure the proper powerdown bits are cleared */
+	if (ac97->scaps) {
+		reg = snd_ac97_read(ac97, AC97_EXTENDED_ID);
+		if (ac97->scaps & AC97_SCAP_SURROUND_DAC) 
+			reg &= ~AC97_EA_PRJ;
+		if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) 
+			reg &= ~(AC97_EA_PRI | AC97_EA_PRK);
+		snd_ac97_write_cache(ac97, AC97_EXTENDED_ID, reg);
+	}
 	snd_ac97_proc_init(ac97);
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ac97, &ops)) < 0) {
 		snd_ac97_free(ac97);
@@ -1991,11 +2006,18 @@ void snd_ac97_resume(ac97_t *ac97)
 	snd_ac97_write(ac97, AC97_GENERAL_PURPOSE, 0);
 
 	snd_ac97_write(ac97, AC97_POWERDOWN, ac97->regs[AC97_POWERDOWN]);
-	snd_ac97_write(ac97, AC97_MASTER, 0x8101);
+	ac97->bus->write(ac97, AC97_MASTER, 0x8101);
 	for (i = 0; i < 10; i++) {
 		if (snd_ac97_read(ac97, AC97_MASTER) == 0x8101)
 			break;
-		mdelay(1);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+	/* FIXME: extra delay */
+	ac97->bus->write(ac97, AC97_MASTER, 0x8000);
+	if (snd_ac97_read(ac97, AC97_MASTER) != 0x8000) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ/4);
 	}
 __reset_ready:
 
@@ -2112,6 +2134,8 @@ static int swap_headphone(ac97_t *ac97, 
 {
 	/* FIXME: error checks.. */
 	if (remove_master) {
+		if (ctl_find(ac97, "Headphone Playback Switch") == NULL)
+			return 0;
 		snd_ac97_remove_ctl(ac97, "Master Playback Switch");
 		snd_ac97_remove_ctl(ac97, "Master Playback Volume");
 	} else {
@@ -2134,12 +2158,30 @@ static int swap_surround(ac97_t *ac97)
 static int tune_ad_sharing(ac97_t *ac97)
 {
 	unsigned short scfg;
+	if ((ac97->id & 0xffffff00) != 0x41445300) {
+		snd_printk(KERN_ERR "ac97_quirk AD_SHARING is only for AD codecs\n");
+		return -EINVAL;
+	}
 	/* Turn on OMS bit to route microphone to back panel */
 	scfg = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG);
 	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, scfg | 0x0200);
 	return 0;
 }
 
+static const snd_kcontrol_new_t snd_ac97_alc_jack_detect = 
+AC97_SINGLE("Jack Detect", AC97_ALC650_CLOCK, 5, 1, 0);
+
+static int tune_alc_jack(ac97_t *ac97)
+{
+	if ((ac97->id & 0xffffff00) != 0x414c4700) {
+		snd_printk(KERN_ERR "ac97_quirk ALC_JACK is only for Realtek codecs\n");
+		return -EINVAL;
+	}
+	snd_ac97_update_bits(ac97, 0x7a, 0x20, 0x20); /* select jack detect function */
+	snd_ac97_update_bits(ac97, 0x7a, 0x01, 0x01); /* Line-out auto mute */
+	return snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&snd_ac97_alc_jack_detect, ac97));
+}
+
 static int apply_quirk(ac97_t *ac97, int quirk)
 {
 	switch (quirk) {
@@ -2153,6 +2195,8 @@ static int apply_quirk(ac97_t *ac97, int
 		return swap_surround(ac97);
 	case AC97_TUNE_AD_SHARING:
 		return tune_ad_sharing(ac97);
+	case AC97_TUNE_ALC_JACK:
+		return tune_alc_jack(ac97);
 	}
 	return -EINVAL;
 }
--- diff/sound/pci/ac97/ac97_patch.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/ac97/ac97_patch.c	2004-03-09 11:51:52.000000000 +0000
@@ -292,6 +292,9 @@ int patch_wolfson11(ac97_t * ac97)
 	return 0;
 }
 
+/*
+ * Tritech codec
+ */
 int patch_tritech_tr28028(ac97_t * ac97)
 {
 	snd_ac97_write_cache(ac97, 0x26, 0x0300);
@@ -301,6 +304,9 @@ int patch_tritech_tr28028(ac97_t * ac97)
 	return 0;
 }
 
+/*
+ * Sigmatel STAC97xx codecs
+ */
 static int patch_sigmatel_stac9700_3d(ac97_t * ac97)
 {
 	snd_kcontrol_t *kctl;
@@ -441,6 +447,9 @@ int patch_sigmatel_stac9756(ac97_t * ac9
 	return 0;
 }
 
+/*
+ * Cirrus Logic CS42xx codecs
+ */
 static const snd_kcontrol_new_t snd_ac97_cirrus_controls_spdif[2] = {
 	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), AC97_CSR_SPDIF, 15, 1, 0),
 	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "AC97-SPSA", AC97_CSR_ACMODE, 0, 3, 0)
@@ -499,6 +508,9 @@ int patch_cirrus_cs4299(ac97_t * ac97)
 	return patch_cirrus_spdif(ac97);
 }
 
+/*
+ * Conexant codecs
+ */
 static const snd_kcontrol_new_t snd_ac97_conexant_controls_spdif[1] = {
 	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), AC97_CXR_AUDIO_MISC, 3, 1, 0),
 };
@@ -530,6 +542,9 @@ int patch_conexant(ac97_t * ac97)
 	return 0;
 }
 
+/*
+ * Analog Device AD18xx, AD19xx codecs
+ */
 int patch_ad1819(ac97_t * ac97)
 {
 	// patch for Analog Devices
@@ -652,7 +667,7 @@ int patch_ad1881(ac97_t * ac97)
 
 static const snd_kcontrol_new_t snd_ac97_controls_ad1885[] = {
 	AC97_SINGLE("Digital Mono Direct", AC97_AD_MISC, 11, 1, 0),
-	AC97_SINGLE("Digital Audio Mode", AC97_AD_MISC, 12, 1, 0),
+	/* AC97_SINGLE("Digital Audio Mode", AC97_AD_MISC, 12, 1, 0), */ /* seems problematic */
 	AC97_SINGLE("Low Power Mixer", AC97_AD_MISC, 14, 1, 0),
 	AC97_SINGLE("Zero Fill DAC", AC97_AD_MISC, 15, 1, 0),
 };
@@ -682,6 +697,9 @@ int patch_ad1885(ac97_t * ac97)
 	jack = snd_ac97_read(ac97, AC97_AD_JACK_SPDIF);
 	snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, jack | 0x0300);
 
+	/* set default */
+	snd_ac97_write_cache(ac97, AC97_AD_MISC, 0x0404);
+
 	ac97->build_ops = &patch_ad1885_build_ops;
 	return 0;
 }
@@ -799,7 +817,7 @@ int patch_ad1981b(ac97_t *ac97)
 	return 0;
 }
 
-static int snd_ac97_ad1980_lohpsel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+static int snd_ac97_ad1888_lohpsel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 	uinfo->count = 1;
@@ -808,7 +826,7 @@ static int snd_ac97_ad1980_lohpsel_info(
 	return 0;
 }
 
-static int snd_ac97_ad1980_lohpsel_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol)
+static int snd_ac97_ad1888_lohpsel_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol)
 {
 	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
 	unsigned short val;
@@ -818,7 +836,7 @@ static int snd_ac97_ad1980_lohpsel_get(s
 	return 0;
 }
 
-static int snd_ac97_ad1980_lohpsel_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+static int snd_ac97_ad1888_lohpsel_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
 	unsigned short val;
@@ -829,7 +847,7 @@ static int snd_ac97_ad1980_lohpsel_put(s
 				    AC97_AD198X_LOSEL | AC97_AD198X_HPSEL, val);
 }
 
-static int snd_ac97_ad1980_downmix_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+static int snd_ac97_ad1888_downmix_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
 	static char *texts[3] = {"Off", "6 -> 4", "6 -> 2"};
 
@@ -842,7 +860,7 @@ static int snd_ac97_ad1980_downmix_info(
 	return 0;
 }
 
-static int snd_ac97_ad1980_downmix_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol)
+static int snd_ac97_ad1888_downmix_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol)
 {
 	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
 	unsigned short val;
@@ -855,7 +873,7 @@ static int snd_ac97_ad1980_downmix_get(s
 	return 0;
 }
 
-static int snd_ac97_ad1980_downmix_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+static int snd_ac97_ad1888_downmix_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
 	unsigned short val;
@@ -871,51 +889,47 @@ static int snd_ac97_ad1980_downmix_put(s
 				    AC97_AD198X_DMIX0 | AC97_AD198X_DMIX1, val);
 }
 
-static const snd_kcontrol_new_t snd_ac97_ad1980_controls[] = {
+static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Exchange Front/Surround",
-		.info = snd_ac97_ad1980_lohpsel_info,
-		.get = snd_ac97_ad1980_lohpsel_get,
-		.put = snd_ac97_ad1980_lohpsel_put
+		.info = snd_ac97_ad1888_lohpsel_info,
+		.get = snd_ac97_ad1888_lohpsel_get,
+		.put = snd_ac97_ad1888_lohpsel_put
 	},
 	AC97_SINGLE("Spread Front to Surround and Center/LFE", AC97_AD_MISC, 7, 1, 0),
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Downmix",
-		.info = snd_ac97_ad1980_downmix_info,
-		.get = snd_ac97_ad1980_downmix_get,
-		.put = snd_ac97_ad1980_downmix_put
+		.info = snd_ac97_ad1888_downmix_info,
+		.get = snd_ac97_ad1888_downmix_get,
+		.put = snd_ac97_ad1888_downmix_put
 	},
 	AC97_SINGLE("Surround Jack as Input", AC97_AD_MISC, 12, 1, 0),
 	AC97_SINGLE("Center/LFE Jack as Input", AC97_AD_MISC, 11, 1, 0),
 };
 
-static int patch_ad1980_specific(ac97_t *ac97)
+static int patch_ad1888_specific(ac97_t *ac97)
 {
-	int err;
-
 	/* rename 0x04 as "Master" and 0x02 as "Master Surround" */
 	snd_ac97_rename_ctl(ac97, "Master Playback Switch", "Master Surround Playback Switch");
 	snd_ac97_rename_ctl(ac97, "Master Playback Volume", "Master Surround Playback Volume");
 	snd_ac97_rename_ctl(ac97, "Headphone Playback Switch", "Master Playback Switch");
 	snd_ac97_rename_ctl(ac97, "Headphone Playback Volume", "Master Playback Volume");
-	if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0)
-		return err;
-	return patch_build_controls(ac97, snd_ac97_ad1980_controls, ARRAY_SIZE(snd_ac97_ad1980_controls));
+	return patch_build_controls(ac97, snd_ac97_ad1888_controls, ARRAY_SIZE(snd_ac97_ad1888_controls));
 }
 
-static struct snd_ac97_build_ops patch_ad1980_build_ops = {
+static struct snd_ac97_build_ops patch_ad1888_build_ops = {
 	.build_post_spdif = patch_ad198x_post_spdif,
-	.build_specific = patch_ad1980_specific
+	.build_specific = patch_ad1888_specific
 };
 
-int patch_ad1980(ac97_t * ac97)
+int patch_ad1888(ac97_t * ac97)
 {
 	unsigned short misc;
 	
 	patch_ad1881(ac97);
-	ac97->build_ops = &patch_ad1980_build_ops;
+	ac97->build_ops = &patch_ad1888_build_ops;
 	/* Switch FRONT/SURROUND LINE-OUT/HP-OUT default connection */
 	/* it seems that most vendors connect line-out connector to headphone out of AC'97 */
 	/* AD-compatible mode */
@@ -930,6 +944,27 @@ int patch_ad1980(ac97_t * ac97)
 	return 0;
 }
 
+static int patch_ad1980_specific(ac97_t *ac97)
+{
+	int err;
+
+	if ((err = patch_ad1888_specific(ac97)) < 0)
+		return err;
+	return patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1);
+}
+
+static struct snd_ac97_build_ops patch_ad1980_build_ops = {
+	.build_post_spdif = patch_ad198x_post_spdif,
+	.build_specific = patch_ad1980_specific
+};
+
+int patch_ad1980(ac97_t * ac97)
+{
+	patch_ad1888(ac97);
+	ac97->build_ops = &patch_ad1980_build_ops;
+	return 0;
+}
+
 static const snd_kcontrol_new_t snd_ac97_ad1985_controls[] = {
 	AC97_SINGLE("Center/LFE Jack as Mic", AC97_AD_SERIAL_CFG, 9, 1, 0),
 	AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0)
@@ -972,6 +1007,36 @@ int patch_ad1985(ac97_t * ac97)
 	return 0;
 }
 
+/*
+ * realtek ALC65x codecs
+ */
+static int snd_ac97_alc650_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+        ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+        ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1;
+        return 0;
+}
+
+static int snd_ac97_alc650_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+        ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	int change, val;
+	val = !!(snd_ac97_read(ac97, AC97_ALC650_MULTICH) & (1 << 10));
+	change = (ucontrol->value.integer.value[0] != val);
+	if (change) {
+		/* disable/enable vref */
+		snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
+				     ucontrol->value.integer.value[0] ? (1 << 12) : 0);
+		/* turn on/off center-on-mic */
+		snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10,
+				     ucontrol->value.integer.value[0] ? (1 << 10) : 0);
+		/* GPIO0 high for mic */
+		snd_ac97_update_bits(ac97, AC97_ALC650_GPIO_STATUS, 0x100,
+				     ucontrol->value.integer.value[0] ? 0 : 0x100);
+        }
+        return change;
+}
+
 static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = {
 	AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0),
 	AC97_SINGLE("Surround Down Mix", AC97_ALC650_MULTICH, 1, 1, 0),
@@ -994,42 +1059,13 @@ static const snd_kcontrol_new_t snd_ac97
 	AC97_SINGLE("Center/LFE DAC Switch", AC97_ALC650_LFE_DAC_VOL, 15, 1, 1),
 	AC97_DOUBLE("Center/LFE DAC Volume", AC97_ALC650_LFE_DAC_VOL, 8, 0, 31, 1),
 #endif
-};
-
-static const snd_kcontrol_new_t snd_ac97_control_alc650_mic =
-AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0);
-
-static int snd_ac97_alc650_mic_gpio_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
-        ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-        ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1;
-        return 0;
-}
-
-static int snd_ac97_alc650_mic_gpio_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
-        ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-        int change;
-        change = snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10,
-                                      ucontrol->value.integer.value[0] ? (1 << 10) : 0);
-        if (change) {
-                /* GPIO0 write for mic */
-                snd_ac97_update_bits(ac97, 0x76, 0x01,
-                                     ucontrol->value.integer.value[0] ? 0 : 0x01);
-                /* GPIO0 high for mic */
-                snd_ac97_update_bits(ac97, 0x78, 0x100,
-                                     ucontrol->value.integer.value[0] ? 0 : 0x100);
-        }
-        return change;
-}
-
-static const snd_kcontrol_new_t snd_ac97_control_alc650_mic_gpio = {
-        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-        .name = "Mic As Center/LFE",
-        .info = snd_ac97_info_single,
-        .get = snd_ac97_alc650_mic_gpio_get,
-        .put = snd_ac97_alc650_mic_gpio_put,
-        .private_value = (1 << 16), /* for info */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Mic As Center/LFE",
+		.info = snd_ac97_info_single,
+		.get = snd_ac97_alc650_mic_get,
+		.put = snd_ac97_alc650_mic_put,
+	},
 };
 
 static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = {
@@ -1044,11 +1080,6 @@ static int patch_alc650_specific(ac97_t 
 
 	if ((err = patch_build_controls(ac97, snd_ac97_controls_alc650, ARRAY_SIZE(snd_ac97_controls_alc650))) < 0)
 		return err;
-	if ((err = patch_build_controls(ac97,
-					ac97->spec.dev_flags ?
-						&snd_ac97_control_alc650_mic :
-						&snd_ac97_control_alc650_mic_gpio, 1)) < 0)
-		return err;
 	if (ac97->ext_id & AC97_EI_SPDIF) {
 		if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc650, ARRAY_SIZE(snd_ac97_spdif_controls_alc650))) < 0)
 			return err;
@@ -1076,34 +1107,25 @@ int patch_alc650(ac97_t * ac97)
 		snd_ac97_read(ac97, AC97_ALC650_GPIO_STATUS) | 0x8000);
 
 	/* Enable SPDIF-IN only on Rev.E and above */
-	if (ac97->spec.dev_flags) {
-		/* enable spdif in */
-		snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK,
-				     snd_ac97_read(ac97, AC97_ALC650_CLOCK) | 0x03);
-	}
+	val = snd_ac97_read(ac97, AC97_ALC650_CLOCK);
+	/* SPDIF IN with pin 47 */
+	if (ac97->spec.dev_flags)
+		val |= 0x03; /* enable */
+	else
+		val &= ~0x03; /* disable */
+	snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK, val);
 
 	val = snd_ac97_read(ac97, AC97_ALC650_MULTICH);
 	val &= ~0xc000; /* slot: 3,4,7,8,6,9 */
+	val &= ~(1 << 10); /* center-on-mic off */
 	snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, val);
 
-	if (! ac97->spec.dev_flags) {
-		/* set GPIO */
-		int mic_off;
-		mic_off = snd_ac97_read(ac97, AC97_ALC650_MULTICH) & (1 << 10);
-		/* GPIO0 direction */
-		val = snd_ac97_read(ac97, AC97_ALC650_GPIO_SETUP);
-		if (mic_off)
-			val &= ~0x01;
-		else
-			val |= 0x01;
-		snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_SETUP, val);
-		val = snd_ac97_read(ac97, AC97_ALC650_GPIO_STATUS);
-		if (mic_off)
-			val &= ~0x100;
-		else
-			val = val | 0x100;
-		snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_STATUS, val);
-	}
+	/* set GPIO0 for mic bias */
+	/* GPIO0 pin output, no interrupt, high */
+	snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_SETUP,
+			     snd_ac97_read(ac97, AC97_ALC650_GPIO_SETUP) | 0x01);
+	snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_STATUS,
+			     (snd_ac97_read(ac97, AC97_ALC650_GPIO_STATUS) | 0x100) & ~0x10);
 
 	/* full DAC volume */
 	snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808);
@@ -1111,10 +1133,37 @@ int patch_alc650(ac97_t * ac97)
 	return 0;
 }
 
+static int snd_ac97_alc655_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+        ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+        ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1;
+        return 0;
+}
+
+static int snd_ac97_alc655_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+        ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+        int change;
+
+	/* misc control; vrefout disable */
+	snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
+			     ucontrol->value.integer.value[0] ? (1 << 12) : 0);
+	change = snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10,
+				      ucontrol->value.integer.value[0] ? (1 << 10) : 0);
+	return change;
+}
+
+
 static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = {
 	AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0),
 	AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0),
-	AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Mic As Center/LFE",
+		.info = snd_ac97_info_single,
+		.get = snd_ac97_alc655_mic_get,
+		.put = snd_ac97_alc655_mic_put,
+	},
 };
 
 static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
@@ -1187,15 +1236,21 @@ static struct snd_ac97_build_ops patch_a
 
 int patch_alc655(ac97_t * ac97)
 {
+	unsigned int val;
+
 	ac97->spec.dev_flags = (ac97->id == 0x414c4780); /* ALC658 */
 
 	ac97->build_ops = &patch_alc655_ops;
 
-	/* enable spdif in */
-	snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK,
-			     snd_ac97_read(ac97, AC97_ALC650_MULTICH) | 0x8000);
-	snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK,
-			     snd_ac97_read(ac97, AC97_ALC650_CLOCK) | 0x02);
+	/* adjust default values */
+	val = snd_ac97_read(ac97, 0x7a); /* misc control */
+	val |= (1 << 1); /* spdif input pin */
+	val &= ~(1 << 12); /* vref enable */
+	snd_ac97_write_cache(ac97, 0x7a, val);
+	val = snd_ac97_read(ac97, AC97_ALC650_MULTICH);
+	val |= (1 << 15); /* enable spdif in */
+	val &= ~(1 << 10); /* disable center on mic */
+	snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, val);
 
 	/* full DAC volume */
 	snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808);
@@ -1203,6 +1258,9 @@ int patch_alc655(ac97_t * ac97)
 	return 0;
 }
 
+/*
+ * C-Media CM97xx codecs
+ */
 static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = {
 	AC97_SINGLE("Line-In As Surround", AC97_CM9738_VENDOR_CTRL, 10, 1, 0),
 	AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0),
@@ -1312,7 +1370,10 @@ int patch_cm9739(ac97_t * ac97)
 	/* bit 13: enable internal vref output for mic */
 	/* bit 12: enable center/lfe */
 	/* bit 14: 0 = SPDIF, 1 = EAPD */
-	snd_ac97_write_cache(ac97, AC97_CM9739_MULTI_CHAN, 0x3000);
+	val = (1 << 12) | (1 << 13);
+	if (! (ac97->ext_id & AC97_EI_SPDIF))
+		val |= (1 << 14);
+	snd_ac97_write_cache(ac97, AC97_CM9739_MULTI_CHAN, val);
 
 	/* FIXME: set up GPIO */
 	snd_ac97_write_cache(ac97, 0x70, 0x0100);
@@ -1321,6 +1382,9 @@ int patch_cm9739(ac97_t * ac97)
 	return 0;
 }
 
+/*
+ * VIA VT1616 codec
+ */
 static const snd_kcontrol_new_t snd_ac97_controls_vt1616[] = {
 AC97_SINGLE("DC Offset removal", 0x5a, 10, 1, 0),
 AC97_SINGLE("Alternate Level to Surround Out", 0x5a, 15, 1, 0),
--- diff/sound/pci/ac97/ac97_patch.h	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/ac97/ac97_patch.h	2004-03-09 11:51:52.000000000 +0000
@@ -41,6 +41,7 @@ int patch_ad1819(ac97_t * ac97);
 int patch_ad1881(ac97_t * ac97);
 int patch_ad1885(ac97_t * ac97);
 int patch_ad1886(ac97_t * ac97);
+int patch_ad1888(ac97_t * ac97);
 int patch_ad1980(ac97_t * ac97);
 int patch_ad1981a(ac97_t * ac97);
 int patch_ad1981b(ac97_t * ac97);
--- diff/sound/pci/ac97/ac97_pcm.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/ac97/ac97_pcm.c	2004-03-09 11:51:52.000000000 +0000
@@ -31,6 +31,7 @@
 #include <sound/pcm.h>
 #include <sound/control.h>
 #include <sound/ac97_codec.h>
+#include <sound/asoundef.h>
 #include "ac97_patch.h"
 #include "ac97_id.h"
 #include "ac97_local.h"
@@ -176,6 +177,7 @@ static unsigned char get_slot_reg(struct
 static int set_spdif_rate(ac97_t *ac97, unsigned short rate)
 {
 	unsigned short old, bits, reg, mask;
+	unsigned int sbits;
 
 	if (! (ac97->ext_id & AC97_EI_SPDIF))
 		return -ENODEV;
@@ -213,6 +215,26 @@ static int set_spdif_rate(ac97_t *ac97, 
 	if (old != bits) {
 		snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0);
 		snd_ac97_update_bits(ac97, reg, mask, bits);
+		/* update the internal spdif bits */
+		spin_lock(&ac97->reg_lock);
+		sbits = ac97->spdif_status;
+		if (sbits & IEC958_AES0_PROFESSIONAL) {
+			sbits &= ~IEC958_AES0_PRO_FS;
+			switch (rate) {
+			case 44100: sbits |= IEC958_AES0_PRO_FS_44100; break;
+			case 48000: sbits |= IEC958_AES0_PRO_FS_48000; break;
+			case 32000: sbits |= IEC958_AES0_PRO_FS_32000; break;
+			}
+		} else {
+			sbits &= ~(IEC958_AES3_CON_FS << 24);
+			switch (rate) {
+			case 44100: sbits |= IEC958_AES3_CON_FS_44100<<24; break;
+			case 48000: sbits |= IEC958_AES3_CON_FS_48000<<24; break;
+			case 32000: sbits |= IEC958_AES3_CON_FS_32000<<24; break;
+			}
+		}
+		ac97->spdif_status = sbits;
+		spin_unlock(&ac97->reg_lock);
 	}
 	snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF);
 	return 0;
--- diff/sound/pci/ac97/ak4531_codec.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/ac97/ak4531_codec.c	2004-03-09 11:51:52.000000000 +0000
@@ -285,7 +285,7 @@ AK4531_INPUT_SW("Line Capture Route", 0,
 AK4531_DOUBLE("Aux Switch", 0, AK4531_LAUXA, AK4531_RAUXA, 7, 7, 1, 1),
 AK4531_DOUBLE("Aux Volume", 0, AK4531_LAUXA, AK4531_RAUXA, 0, 0, 0x1f, 1),
 AK4531_DOUBLE("Aux Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 5, 4, 1, 0),
-AK4531_INPUT_SW("Aux Input Route", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 4, 3),
+AK4531_INPUT_SW("Aux Capture Route", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 4, 3),
 
 AK4531_SINGLE("Mono Switch", 0, AK4531_MONO1, 7, 1, 1),
 AK4531_SINGLE("Mono Volume", 0, AK4531_MONO1, 0, 0x1f, 1),
--- diff/sound/pci/ali5451/ali5451.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/ali5451/ali5451.c	2004-03-09 11:51:52.000000000 +0000
@@ -1742,7 +1742,8 @@ static int __devinit snd_ali_pcm(ali_t *
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ali_playback_ops);
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ali_capture_ops);
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(codec->pci, pcm, 64*1024, 128*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(codec->pci), 64*1024, 128*1024);
 
 	pcm->info_flags = 0;
 	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
--- diff/sound/pci/als4000.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/als4000.c	2004-03-09 11:51:52.000000000 +0000
@@ -99,9 +99,11 @@ MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
 MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(enable, "Enable ALS4000 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_INDEX_DESC);
+#ifdef SUPPORT_JOYSTICK
 MODULE_PARM(joystick_port, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(joystick_port, "Joystick port address for ALS4000 soundcard. (0 = disabled)");
 MODULE_PARM_SYNTAX(joystick_port, SNDRV_ENABLED);
+#endif
 
 #define chip_t sb_t
 
@@ -521,7 +523,8 @@ static int __devinit snd_als4000_pcm(sb_
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_als4000_playback_ops);
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_als4000_capture_ops);
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 64*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
+					      64*1024, 64*1024);
 
 	chip->pcm = pcm;
 
--- diff/sound/pci/azt3328.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/azt3328.c	2004-03-09 11:51:52.000000000 +0000
@@ -1253,7 +1253,8 @@ static int __devinit snd_azf3328_pcm(azf
 	strcpy(pcm->name, chip->card->shortname);
 	chip->pcm = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 64*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(chip->pci), 64*1024, 64*1024);
 
 	snd_azf3328_dbgcallleave();
 	return 0;
--- diff/sound/pci/bt87x.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/bt87x.c	2004-03-09 11:51:52.000000000 +0000
@@ -167,8 +167,8 @@ struct snd_bt87x {
 	long opened;
 	snd_pcm_substream_t *substream;
 
-	u32 *risc;
-	dma_addr_t risc_dma;
+	struct snd_dma_device dma_dev;
+	struct snd_dma_buffer dma_risc;
 	unsigned int line_bytes;
 	unsigned int lines;
 
@@ -195,13 +195,14 @@ static int snd_bt87x_create_risc(bt87x_t
 	unsigned int i, offset;
 	u32 *risc;
 
-	if (!chip->risc) {
-		chip->risc = (u32*)snd_malloc_pci_pages
-			(chip->pci, PAGE_ALIGN(MAX_RISC_SIZE), &chip->risc_dma);
-		if (!chip->risc)
+	if (chip->dma_risc.area == NULL) {
+		memset(&chip->dma_dev, 0, sizeof(chip->dma_dev));
+		chip->dma_dev.type = SNDRV_DMA_TYPE_DEV;
+		chip->dma_dev.dev = snd_dma_pci_data(chip->pci);
+		if (snd_dma_alloc_pages(&chip->dma_dev, PAGE_ALIGN(MAX_RISC_SIZE), &chip->dma_risc) < 0)
 			return -ENOMEM;
 	}
-	risc = chip->risc;
+	risc = (u32 *)chip->dma_risc.area;
 	offset = 0;
 	*risc++ = cpu_to_le32(RISC_SYNC | RISC_SYNC_FM1);
 	*risc++ = cpu_to_le32(0);
@@ -233,7 +234,7 @@ static int snd_bt87x_create_risc(bt87x_t
 	*risc++ = cpu_to_le32(RISC_SYNC | RISC_SYNC_VRO);
 	*risc++ = cpu_to_le32(0);
 	*risc++ = cpu_to_le32(RISC_JUMP);
-	*risc++ = cpu_to_le32(chip->risc_dma);
+	*risc++ = cpu_to_le32(chip->dma_risc.addr);
 	chip->line_bytes = period_bytes;
 	chip->lines = periods;
 	return 0;
@@ -241,10 +242,9 @@ static int snd_bt87x_create_risc(bt87x_t
 
 static void snd_bt87x_free_risc(bt87x_t *chip)
 {
-	if (chip->risc) {
-		snd_free_pci_pages(chip->pci, PAGE_ALIGN(MAX_RISC_SIZE),
-				   chip->risc, chip->risc_dma);
-		chip->risc = NULL;
+	if (chip->dma_risc.area) {
+		snd_dma_free_pages(&chip->dma_dev, &chip->dma_risc);
+		chip->dma_risc.area = NULL;
 	}
 }
 
@@ -459,7 +459,7 @@ static int snd_bt87x_start(bt87x_t *chip
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	chip->current_line = 0;
 	chip->reg_control |= CTL_FIFO_ENABLE | CTL_RISC_ENABLE | CTL_ACAP_EN;
-	snd_bt87x_writel(chip, REG_RISC_STRT_ADD, chip->risc_dma);
+	snd_bt87x_writel(chip, REG_RISC_STRT_ADD, chip->dma_risc.addr);
 	snd_bt87x_writel(chip, REG_PACKET_LEN,
 			 chip->line_bytes | (chip->lines << 16));
 	snd_bt87x_writel(chip, REG_INT_MASK, MY_INTERRUPTS);
@@ -681,7 +681,9 @@ static int __devinit snd_bt87x_pcm(bt87x
 	pcm->private_data = chip;
 	strcpy(pcm->name, name);
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_bt87x_pcm_ops);
-	return snd_pcm_lib_preallocate_sg_pages_for_all(chip->pci, pcm,
+	return snd_pcm_lib_preallocate_pages_for_all(pcm,
+						     SNDRV_DMA_TYPE_DEV_SG,
+						     snd_dma_pci_data(chip->pci),
 							128 * 1024,
 							(255 * 4092 + 1023) & ~1023);
 }
--- diff/sound/pci/cmipci.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/cmipci.c	2004-03-09 11:51:52.000000000 +0000
@@ -2087,7 +2087,8 @@ static int __devinit snd_cmipci_pcm_new(
 	strcpy(pcm->name, "C-Media PCI DAC/ADC");
 	cm->pcm = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(cm->pci, pcm, 64*1024, 128*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(cm->pci), 64*1024, 128*1024);
 
 	return 0;
 }
@@ -2109,7 +2110,8 @@ static int __devinit snd_cmipci_pcm2_new
 	strcpy(pcm->name, "C-Media PCI 2nd DAC");
 	cm->pcm2 = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(cm->pci, pcm, 64*1024, 128*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(cm->pci), 64*1024, 128*1024);
 
 	return 0;
 }
@@ -2139,7 +2141,8 @@ static int __devinit snd_cmipci_pcm_spdi
 	strcpy(pcm->name, "C-Media PCI IEC958");
 	cm->pcm_spdif = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(cm->pci, pcm, 64*1024, 128*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(cm->pci), 64*1024, 128*1024);
 
 	return 0;
 }
@@ -3151,7 +3154,7 @@ static int __devinit snd_cmipci_create(s
 #ifdef SUPPORT_JOYSTICK
 	if (joystick_port[dev] > 0) {
 		if (joystick_port[dev] == 1) { /* auto-detect */
-			static int ports[] = { 0x200, 0x201, 0 };
+			static int ports[] = { 0x201, 0x200, 0 }; /* FIXME: majority is 0x201? */
 			int i;
 			for (i = 0; ports[i]; i++) {
 				joystick_port[dev] = ports[i];
--- diff/sound/pci/cs4281.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/cs4281.c	2004-03-09 11:51:52.000000000 +0000
@@ -1039,7 +1039,8 @@ static int __devinit snd_cs4281_pcm(cs42
 	strcpy(pcm->name, "CS4281");
 	chip->pcm = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 512*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(chip->pci), 64*1024, 512*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
--- diff/sound/pci/cs46xx/cs46xx_lib.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/cs46xx/cs46xx_lib.c	2004-03-09 11:51:52.000000000 +0000
@@ -66,6 +66,8 @@
 #include "cs46xx_lib.h"
 #include "dsp_spos.h"
 
+static void amp_voyetra(cs46xx_t *chip, int change);
+
 static unsigned short snd_cs46xx_codec_read(cs46xx_t *chip,
 					    unsigned short reg,
 					    int codec_index)
@@ -203,6 +205,13 @@ static unsigned short snd_cs46xx_ac97_re
 	chip->active_ctrl(chip, 1);
 	val = snd_cs46xx_codec_read(chip, reg, codec_index);
 	chip->active_ctrl(chip, -1);
+
+	/* HACK: voyetra uses EAPD bit in the reverse way.
+	 * we flip the bit to show the mixer status correctly
+	 */
+	if (reg == AC97_POWERDOWN && chip->amplifier_ctrl == amp_voyetra)
+		val ^= 0x8000;
+
 	return val;
 }
 
@@ -284,6 +293,12 @@ static void snd_cs46xx_ac97_write(ac97_t
 	else
 		snd_assert(0,return);
 
+	/* HACK: voyetra uses EAPD bit in the reverse way.
+	 * we flip the bit to show the mixer status correctly
+	 */
+	if (reg == AC97_POWERDOWN && chip->amplifier_ctrl == amp_voyetra)
+		val ^= 0x8000;
+
 	chip->active_ctrl(chip, 1);
 	snd_cs46xx_codec_write(chip, reg, val, codec_index);
 	chip->active_ctrl(chip, -1);
@@ -699,7 +714,7 @@ static int snd_cs46xx_playback_transfer(
 			bytes = hw_to_end;
 		if (sw_to_end < bytes)
 			bytes = sw_to_end;
-		memcpy(cpcm->hw_area + cpcm->hw_data,
+		memcpy(cpcm->hw_buf.area + cpcm->hw_data,
 		       runtime->dma_area + cpcm->sw_data,
 		       bytes);
 		cpcm->hw_data += bytes;
@@ -740,7 +755,7 @@ static int snd_cs46xx_capture_transfer(s
 		if (sw_to_end < bytes)
 			bytes = sw_to_end;
 		memcpy(runtime->dma_area + chip->capt.sw_data,
-		       chip->capt.hw_area + chip->capt.hw_data,
+		       chip->capt.hw_buf.area + chip->capt.hw_data,
 		       bytes);
 		chip->capt.hw_data += bytes;
 		if ((int)chip->capt.hw_data == buffer_size)
@@ -766,7 +781,7 @@ static snd_pcm_uframes_t snd_cs46xx_play
 #else
 	ptr = snd_cs46xx_peek(chip, BA1_PBA);
 #endif
-	ptr -= cpcm->hw_addr;
+	ptr -= cpcm->hw_buf.addr;
 	return ptr >> cpcm->shift;
 }
 
@@ -784,7 +799,7 @@ static snd_pcm_uframes_t snd_cs46xx_play
 #else
 	ptr = snd_cs46xx_peek(chip, BA1_PBA);
 #endif
-	ptr -= cpcm->hw_addr;
+	ptr -= cpcm->hw_buf.addr;
 
 	bytes = ptr - cpcm->hw_io;
 
@@ -802,14 +817,14 @@ static snd_pcm_uframes_t snd_cs46xx_play
 static snd_pcm_uframes_t snd_cs46xx_capture_direct_pointer(snd_pcm_substream_t * substream)
 {
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
-	size_t ptr = snd_cs46xx_peek(chip, BA1_CBA) - chip->capt.hw_addr;
+	size_t ptr = snd_cs46xx_peek(chip, BA1_CBA) - chip->capt.hw_buf.addr;
 	return ptr >> chip->capt.shift;
 }
 
 static snd_pcm_uframes_t snd_cs46xx_capture_indirect_pointer(snd_pcm_substream_t * substream)
 {
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
-	size_t ptr = snd_cs46xx_peek(chip, BA1_CBA) - chip->capt.hw_addr;
+	size_t ptr = snd_cs46xx_peek(chip, BA1_CBA) - chip->capt.hw_buf.addr;
 	ssize_t bytes = ptr - chip->capt.hw_io;
 	int buffer_size = substream->runtime->period_size * CS46XX_FRAGS << chip->capt.shift;
 
@@ -933,7 +948,7 @@ static int _cs46xx_adjust_sample_rate (c
 	/* If PCMReaderSCB and SrcTaskSCB not created yet ... */
 	if ( cpcm->pcm_channel == NULL) {
 		cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, 
-								   cpcm, cpcm->hw_addr,cpcm->pcm_channel_id);
+								   cpcm, cpcm->hw_buf.addr,cpcm->pcm_channel_id);
 		if (cpcm->pcm_channel == NULL) {
 			snd_printk(KERN_ERR "cs46xx: failed to create virtual PCM channel\n");
 			return -ENOMEM;
@@ -946,7 +961,7 @@ static int _cs46xx_adjust_sample_rate (c
 		cs46xx_dsp_destroy_pcm_channel (chip,cpcm->pcm_channel);
 
 		if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, cpcm, 
-									 cpcm->hw_addr,
+									 cpcm->hw_buf.addr,
 									 cpcm->pcm_channel_id)) == NULL) {
 			snd_printk(KERN_ERR "cs46xx: failed to re-create virtual PCM channel\n");
 			return -ENOMEM;
@@ -1002,11 +1017,11 @@ static int snd_cs46xx_playback_hw_params
 #endif
 
 	if (params_periods(hw_params) == CS46XX_FRAGS) {
-		if (runtime->dma_area != cpcm->hw_area)
+		if (runtime->dma_area != cpcm->hw_buf.area)
 			snd_pcm_lib_free_pages(substream);
-		runtime->dma_area = cpcm->hw_area;
-		runtime->dma_addr = cpcm->hw_addr;
-		runtime->dma_bytes = cpcm->hw_size;
+		runtime->dma_area = cpcm->hw_buf.area;
+		runtime->dma_addr = cpcm->hw_buf.addr;
+		runtime->dma_bytes = cpcm->hw_buf.bytes;
 
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
@@ -1026,7 +1041,7 @@ static int snd_cs46xx_playback_hw_params
 #endif
 
 	} else {
-		if (runtime->dma_area == cpcm->hw_area) {
+		if (runtime->dma_area == cpcm->hw_buf.area) {
 			runtime->dma_area = NULL;
 			runtime->dma_addr = 0;
 			runtime->dma_bytes = 0;
@@ -1075,7 +1090,7 @@ static int snd_cs46xx_playback_hw_free(s
 	   is called and cpcm can actually be NULL here */
 	if (!cpcm) return -ENXIO;
 
-	if (runtime->dma_area != cpcm->hw_area)
+	if (runtime->dma_area != cpcm->hw_buf.area)
 		snd_pcm_lib_free_pages(substream);
     
 	runtime->dma_area = NULL;
@@ -1144,7 +1159,7 @@ static int snd_cs46xx_playback_prepare(s
 	/* playback format && interrupt enable */
 	snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 1) << 2, pfie | cpcm->pcm_channel->pcm_slot);
 #else
-	snd_cs46xx_poke(chip, BA1_PBA, cpcm->hw_addr);
+	snd_cs46xx_poke(chip, BA1_PBA, cpcm->hw_buf.addr);
 	tmp = snd_cs46xx_peek(chip, BA1_PDTC);
 	tmp &= ~0x000003ff;
 	tmp |= (4 << cpcm->shift) - 1;
@@ -1167,14 +1182,14 @@ static int snd_cs46xx_capture_hw_params(
 	cs46xx_dsp_pcm_ostream_set_period (chip, params_period_bytes(hw_params));
 #endif
 	if (runtime->periods == CS46XX_FRAGS) {
-		if (runtime->dma_area != chip->capt.hw_area)
+		if (runtime->dma_area != chip->capt.hw_buf.area)
 			snd_pcm_lib_free_pages(substream);
-		runtime->dma_area = chip->capt.hw_area;
-		runtime->dma_addr = chip->capt.hw_addr;
-		runtime->dma_bytes = chip->capt.hw_size;
+		runtime->dma_area = chip->capt.hw_buf.area;
+		runtime->dma_addr = chip->capt.hw_buf.addr;
+		runtime->dma_bytes = chip->capt.hw_buf.bytes;
 		substream->ops = &snd_cs46xx_capture_ops;
 	} else {
-		if (runtime->dma_area == chip->capt.hw_area) {
+		if (runtime->dma_area == chip->capt.hw_buf.area) {
 			runtime->dma_area = NULL;
 			runtime->dma_addr = 0;
 			runtime->dma_bytes = 0;
@@ -1192,7 +1207,7 @@ static int snd_cs46xx_capture_hw_free(sn
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
 
-	if (runtime->dma_area != chip->capt.hw_area)
+	if (runtime->dma_area != chip->capt.hw_buf.area)
 		snd_pcm_lib_free_pages(substream);
 	runtime->dma_area = NULL;
 	runtime->dma_addr = 0;
@@ -1206,7 +1221,7 @@ static int snd_cs46xx_capture_prepare(sn
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
 
-	snd_cs46xx_poke(chip, BA1_CBA, chip->capt.hw_addr);
+	snd_cs46xx_poke(chip, BA1_CBA, chip->capt.hw_buf.addr);
 	chip->capt.shift = 2;
 	chip->capt.sw_bufsize = snd_pcm_lib_buffer_bytes(substream);
 	chip->capt.sw_data = chip->capt.sw_io = chip->capt.sw_ready = 0;
@@ -1382,8 +1397,7 @@ static int _cs46xx_playback_open_channel
 	cpcm = snd_magic_kcalloc(cs46xx_pcm_t, 0, GFP_KERNEL);
 	if (cpcm == NULL)
 		return -ENOMEM;
-	cpcm->hw_size = PAGE_SIZE;
-	if ((cpcm->hw_area = snd_malloc_pci_pages(chip->pci, cpcm->hw_size, &cpcm->hw_addr)) == NULL) {
+	if (snd_dma_alloc_pages(&chip->dma_dev, PAGE_SIZE, &cpcm->hw_buf) < 0) {
 		snd_magic_kfree(cpcm);
 		return -ENOMEM;
 	}
@@ -1472,7 +1486,7 @@ static int snd_cs46xx_capture_open(snd_p
 {
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
 
-	if ((chip->capt.hw_area = snd_malloc_pci_pages(chip->pci, chip->capt.hw_size, &chip->capt.hw_addr)) == NULL)
+	if (snd_dma_alloc_pages(&chip->dma_dev, PAGE_SIZE, &chip->capt.hw_buf) < 0)
 		return -ENOMEM;
 	chip->capt.substream = substream;
 	substream->runtime->hw = snd_cs46xx_capture;
@@ -1513,7 +1527,7 @@ static int snd_cs46xx_playback_close(snd
 #endif
 
 	cpcm->substream = NULL;
-	snd_free_pci_pages(chip->pci, cpcm->hw_size, cpcm->hw_area, cpcm->hw_addr);
+	snd_dma_free_pages(&chip->dma_dev, &cpcm->hw_buf);
 	chip->active_ctrl(chip, -1);
 
 	return 0;
@@ -1524,7 +1538,7 @@ static int snd_cs46xx_capture_close(snd_
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
 
 	chip->capt.substream = NULL;
-	snd_free_pci_pages(chip->pci, chip->capt.hw_size, chip->capt.hw_area, chip->capt.hw_addr);
+	snd_dma_free_pages(&chip->dma_dev, &chip->capt.hw_buf);
 	chip->active_ctrl(chip, -1);
 
 	return 0;
@@ -1703,7 +1717,8 @@ int __devinit snd_cs46xx_pcm(cs46xx_t *c
 	strcpy(pcm->name, "CS46xx");
 	chip->pcm = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
@@ -1734,7 +1749,8 @@ int __devinit snd_cs46xx_pcm_rear(cs46xx
 	strcpy(pcm->name, "CS46xx - Rear");
 	chip->pcm_rear = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
@@ -1763,7 +1779,8 @@ int __devinit snd_cs46xx_pcm_center_lfe(
 	strcpy(pcm->name, "CS46xx - Center LFE");
 	chip->pcm_center_lfe = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
@@ -1792,7 +1809,8 @@ int __devinit snd_cs46xx_pcm_iec958(cs46
 	strcpy(pcm->name, "CS46xx - IEC958");
 	chip->pcm_rear = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
@@ -2547,7 +2565,7 @@ int __devinit snd_cs46xx_mixer(cs46xx_t 
 	/* get EAPD mixer switch (for voyetra hack) */
 	memset(&id, 0, sizeof(id));
 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-	strcpy(id.name, "External Amplifier Power Down");
+	strcpy(id.name, "External Amplifier");
 	chip->eapd_switch = snd_ctl_find_id(chip->card, &id);
     
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
@@ -3877,7 +3895,6 @@ int __devinit snd_cs46xx_create(snd_card
 #endif
 	chip->card = card;
 	chip->pci = pci;
-	chip->capt.hw_size = PAGE_SIZE;
 	chip->irq = -1;
 	chip->ba0_addr = pci_resource_start(pci, 0);
 	chip->ba1_addr = pci_resource_start(pci, 1);
@@ -3913,6 +3930,10 @@ int __devinit snd_cs46xx_create(snd_card
 	region->base = chip->ba1_addr + BA1_SP_REG;
 	region->size = CS46XX_BA1_REG_SIZE;
 
+	memset(&chip->dma_dev, 0, sizeof(chip->dma_dev));
+	chip->dma_dev.type = SNDRV_DMA_TYPE_DEV;
+	chip->dma_dev.dev = snd_dma_pci_data(pci);
+
 	/* set up amp and clkrun hack */
 	pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor);
 	pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &ss_card);
--- diff/sound/pci/emu10k1/emu10k1_callback.c	2002-10-16 04:27:49.000000000 +0100
+++ source/sound/pci/emu10k1/emu10k1_callback.c	2004-03-09 11:51:52.000000000 +0000
@@ -405,7 +405,7 @@ start_voice(snd_emux_voice_t *vp)
 	snd_emu10k1_ptr_write(hw, Z2, ch, 0);
 
 	/* invalidate maps */
-	temp = (hw->silent_page_dmaaddr << 1) | MAP_PTI_MASK;
+	temp = (hw->silent_page.addr << 1) | MAP_PTI_MASK;
 	snd_emu10k1_ptr_write(hw, MAPA, ch, temp);
 	snd_emu10k1_ptr_write(hw, MAPB, ch, temp);
 #if 0
--- diff/sound/pci/emu10k1/emu10k1_main.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/emu10k1/emu10k1_main.c	2004-03-09 11:51:52.000000000 +0000
@@ -97,7 +97,8 @@ static int __devinit snd_emu10k1_init(em
 	unsigned int silent_page;
 
 	emu->fx8010.itram_size = (16 * 1024)/2;
-	emu->fx8010.etram_size = 0;
+	emu->fx8010.etram_pages.area = NULL;
+	emu->fx8010.etram_pages.bytes = 0;
 
 	/* disable audio and lock cache */
 	outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, emu->port + HCFG);
@@ -184,15 +185,15 @@ static int __devinit snd_emu10k1_init(em
 	/*
 	 *  Clear page with silence & setup all pointers to this page
 	 */
-	memset(emu->silent_page, 0, PAGE_SIZE);
-	silent_page = emu->silent_page_dmaaddr << 1;
+	memset(emu->silent_page.area, 0, PAGE_SIZE);
+	silent_page = emu->silent_page.addr << 1;
 	for (idx = 0; idx < MAXPAGES; idx++)
-		emu->ptb_pages[idx] = cpu_to_le32(silent_page | idx);
-	snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages_dmaaddr);
+		((u32 *)emu->ptb_pages.area)[idx] = cpu_to_le32(silent_page | idx);
+	snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr);
 	snd_emu10k1_ptr_write(emu, TCB, 0, 0);	/* taken from original driver */
 	snd_emu10k1_ptr_write(emu, TCBS, 0, 4);	/* taken from original driver */
 
-	silent_page = (emu->silent_page_dmaaddr << 1) | MAP_PTI_MASK;
+	silent_page = (emu->silent_page.addr << 1) | MAP_PTI_MASK;
 	for (ch = 0; ch < NUM_G; ch++) {
 		snd_emu10k1_ptr_write(emu, MAPA, ch, silent_page);
 		snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page);
@@ -546,10 +547,10 @@ static int snd_emu10k1_free(emu10k1_t *e
        	}
 	if (emu->memhdr)
 		snd_util_memhdr_free(emu->memhdr);
-	if (emu->silent_page)
-		snd_free_pci_pages(emu->pci, EMUPAGESIZE, emu->silent_page, emu->silent_page_dmaaddr);
-	if (emu->ptb_pages)
-		snd_free_pci_pages(emu->pci, 32 * 1024, (void *)emu->ptb_pages, emu->ptb_pages_dmaaddr);
+	if (emu->silent_page.area)
+		snd_dma_free_pages(&emu->dma_dev, &emu->silent_page);
+	if (emu->ptb_pages.area)
+		snd_dma_free_pages(&emu->dma_dev, &emu->ptb_pages);
 	if (emu->page_ptr_table)
 		vfree(emu->page_ptr_table);
 	if (emu->page_addr_table)
@@ -638,9 +639,12 @@ int __devinit snd_emu10k1_create(snd_car
 	}
 	emu->irq = pci->irq;
 
+	memset(&emu->dma_dev, 0, sizeof(emu->dma_dev));
+	emu->dma_dev.type = SNDRV_DMA_TYPE_DEV;
+	emu->dma_dev.dev = snd_dma_pci_data(pci);
+
 	emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT;
-	emu->ptb_pages = snd_malloc_pci_pages(pci, 32 * 1024, &emu->ptb_pages_dmaaddr);
-	if (emu->ptb_pages == NULL) {
+	if (snd_dma_alloc_pages(&emu->dma_dev, 32 * 1024, &emu->ptb_pages) < 0) {
 		snd_emu10k1_free(emu);
 		return -ENOMEM;
 	}
@@ -652,8 +656,7 @@ int __devinit snd_emu10k1_create(snd_car
 		return -ENOMEM;
 	}
 
-	emu->silent_page = snd_malloc_pci_pages(pci, EMUPAGESIZE, &emu->silent_page_dmaaddr);
-	if (emu->silent_page == NULL) {
+	if (snd_dma_alloc_pages(&emu->dma_dev, EMUPAGESIZE, &emu->silent_page) < 0) {
 		snd_emu10k1_free(emu);
 		return -ENOMEM;
 	}
--- diff/sound/pci/emu10k1/emufx.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/emu10k1/emufx.c	2004-03-09 11:51:52.000000000 +0000
@@ -26,6 +26,7 @@
  */
 
 #include <sound/driver.h>
+#include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/init.h>
@@ -506,16 +507,16 @@ static void snd_emu10k1_fx8010_playback_
 
 	while (frames > *tram_pos) {
 		count = *tram_pos + 1;
-		snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages + *tram_pos,
-						       (unsigned short *)emu->fx8010.etram_pages + *tram_pos + tram_size / 2,
+		snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages.area + *tram_pos,
+						       (unsigned short *)emu->fx8010.etram_pages.area + *tram_pos + tram_size / 2,
 						       src, count, *tram_shift);
 		src += count * 2;
 		frames -= count;
 		*tram_pos = (tram_size / 2) - 1;
 		(*tram_shift)++;
 	}
-	snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages + *tram_pos,
-					       (unsigned short *)emu->fx8010.etram_pages + *tram_pos + tram_size / 2,
+	snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages.area + *tram_pos,
+					       (unsigned short *)emu->fx8010.etram_pages.area + *tram_pos + tram_size / 2,
 					       src, frames, *tram_shift++);
 	*tram_pos -= frames;
 }
@@ -760,7 +761,7 @@ int snd_emu10k1_fx8010_pcm(emu10k1_t * e
 	strcpy(pcm->name, "EMU10K1 FX8010");
 	emu->pcm_fx8010 = pcm;
 	
-	snd_pcm_lib_preallocate_pci_pages_for_all(emu->pci, pcm, 64*1024, 0);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 0);
 
 	if (rpcm)
 		*rpcm = pcm;
@@ -2218,32 +2219,30 @@ int snd_emu10k1_fx8010_tram_setup(emu10k
 		}
 		size = 0x2000 << size_reg;
 	}
-	if (emu->fx8010.etram_size == size)
+	if (emu->fx8010.etram_pages.bytes == size)
 		return 0;
 	spin_lock_irq(&emu->emu_lock);
 	outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
 	spin_unlock_irq(&emu->emu_lock);
 	snd_emu10k1_ptr_write(emu, TCB, 0, 0);
 	snd_emu10k1_ptr_write(emu, TCBS, 0, 0);
-	if (emu->fx8010.etram_pages != NULL) {
-		snd_free_pci_pages(emu->pci, emu->fx8010.etram_size * 2, emu->fx8010.etram_pages, emu->fx8010.etram_pages_dmaaddr);
-		emu->fx8010.etram_pages = NULL;
-		emu->fx8010.etram_size = 0;
+	if (emu->fx8010.etram_pages.area != NULL) {
+		snd_dma_free_pages(&emu->dma_dev, &emu->fx8010.etram_pages);
+		emu->fx8010.etram_pages.area = NULL;
+		emu->fx8010.etram_pages.bytes = 0;
 	}
 
 	if (size > 0) {
-		emu->fx8010.etram_pages = snd_malloc_pci_pages(emu->pci, size * 2, &emu->fx8010.etram_pages_dmaaddr);
-		if (emu->fx8010.etram_pages == NULL)
+		if (snd_dma_alloc_pages(&emu->dma_dev, size * 2, &emu->fx8010.etram_pages) < 0)
 			return -ENOMEM;
-		memset(emu->fx8010.etram_pages, 0, size * 2);
-		snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages_dmaaddr);
+		memset(emu->fx8010.etram_pages.area, 0, size * 2);
+		snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
 		snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
 		spin_lock_irq(&emu->emu_lock);
 		outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
 		spin_unlock_irq(&emu->emu_lock);	
 	}
 
-	emu->fx8010.etram_size = size;
 	return 0;
 }
 
@@ -2269,7 +2268,7 @@ static int snd_emu10k1_fx8010_info(emu10
 	memset(info, 0, sizeof(info));
 	info->card = emu->card_type;
 	info->internal_tram_size = emu->fx8010.itram_size;
-	info->external_tram_size = emu->fx8010.etram_size;
+	info->external_tram_size = emu->fx8010.etram_pages.bytes;
 	fxbus = fxbuses;
 	extin = emu->audigy ? audigy_ins : creative_ins;
 	extout = emu->audigy ? audigy_outs : creative_outs;
--- diff/sound/pci/emu10k1/emupcm.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/emu10k1/emupcm.c	2004-03-09 11:51:52.000000000 +0000
@@ -26,6 +26,7 @@
  */
 
 #include <sound/driver.h>
+#include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/time.h>
@@ -323,7 +324,7 @@ static void snd_emu10k1_pcm_init_voice(e
 	snd_emu10k1_ptr_write(emu, Z1, voice, 0);
 	snd_emu10k1_ptr_write(emu, Z2, voice, 0);
 	// invalidate maps
-	silent_page = ((unsigned int)emu->silent_page_dmaaddr << 1) | MAP_PTI_MASK;
+	silent_page = ((unsigned int)emu->silent_page.addr << 1) | MAP_PTI_MASK;
 	snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page);
 	snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page);
 	// modulation envelope
@@ -998,11 +999,11 @@ int __devinit snd_emu10k1_pcm(emu10k1_t 
 	emu->pcm = pcm;
 
 	for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next)
-		if ((err = snd_pcm_lib_preallocate_sg_pages(emu->pci, substream, 64*1024, 64*1024)) < 0)
+		if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(emu->pci), 64*1024, 64*1024)) < 0)
 			return err;
 
 	for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next)
-		snd_pcm_lib_preallocate_pci_pages(emu->pci, substream, 64*1024, 64*1024);
+		snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
@@ -1048,7 +1049,7 @@ int __devinit snd_emu10k1_pcm_mic(emu10k
 	strcpy(pcm->name, "EMU10K1 MIC");
 	emu->pcm_mic = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(emu->pci, pcm, 64*1024, 64*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
@@ -1157,7 +1158,7 @@ int __devinit snd_emu10k1_pcm_efx(emu10k
 	emu->efx_voices_mask[1] = 0;
 	snd_ctl_add(emu->card, snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu));
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(emu->pci, pcm, 64*1024, 64*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024);
 
 	return 0;
 }
--- diff/sound/pci/emu10k1/emuproc.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/emu10k1/emuproc.c	2004-03-09 11:51:52.000000000 +0000
@@ -117,7 +117,7 @@ static void snd_emu10k1_proc_read(snd_in
 	snd_iprintf(buffer, "Card                  : %s\n",
 		    emu->audigy ? "Audigy" : (emu->APS ? "EMU APS" : "Creative"));
 	snd_iprintf(buffer, "Internal TRAM (words) : 0x%x\n", emu->fx8010.itram_size);
-	snd_iprintf(buffer, "External TRAM (words) : 0x%x\n", emu->fx8010.etram_size);
+	snd_iprintf(buffer, "External TRAM (words) : 0x%x\n", emu->fx8010.etram_pages.bytes);
 	snd_iprintf(buffer, "\n");
 	if (emu->audigy) {
 		snd_iprintf(buffer, "Effect Send Routing   : A=%i, B=%i, C=%i, D=%i\n",
--- diff/sound/pci/emu10k1/memory.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/emu10k1/memory.c	2004-03-09 11:51:52.000000000 +0000
@@ -30,7 +30,7 @@
  * aligned pages in others
  */
 #define __set_ptb_entry(emu,page,addr) \
-	((emu)->ptb_pages[page] = cpu_to_le32(((addr) << 1) | (page)))
+	(((u32 *)(emu)->ptb_pages.area)[page] = cpu_to_le32(((addr) << 1) | (page)))
 
 #define UNIT_PAGES		(PAGE_SIZE / EMUPAGESIZE)
 #define MAX_ALIGN_PAGES		(MAXPAGES / UNIT_PAGES)
@@ -44,7 +44,7 @@
 /* fill PTB entrie(s) corresponding to page with addr */
 #define set_ptb_entry(emu,page,addr)	__set_ptb_entry(emu,page,addr)
 /* fill PTB entrie(s) corresponding to page with silence pointer */
-#define set_silent_ptb(emu,page)	__set_ptb_entry(emu,page,emu->silent_page_dmaaddr)
+#define set_silent_ptb(emu,page)	__set_ptb_entry(emu,page,emu->silent_page.addr)
 #else
 /* fill PTB entries -- we need to fill UNIT_PAGES entries */
 static inline void set_ptb_entry(emu10k1_t *emu, int page, dma_addr_t addr)
@@ -297,7 +297,6 @@ snd_emu10k1_alloc_pages(emu10k1_t *emu, 
 	int page, err, idx;
 
 	snd_assert(emu, return NULL);
-	snd_assert(substream->dma_device.type == SNDRV_DMA_TYPE_PCI_SG, return NULL);
 	snd_assert(runtime->dma_bytes > 0 && runtime->dma_bytes < MAXPAGES * EMUPAGESIZE, return NULL);
 	hdr = emu->memhdr;
 	snd_assert(hdr, return NULL);
@@ -436,22 +435,20 @@ static void get_single_page_range(snd_ut
 static int synth_alloc_pages(emu10k1_t *emu, emu10k1_memblk_t *blk)
 {
 	int page, first_page, last_page;
-	void *ptr;
-	dma_addr_t addr;
+	struct snd_dma_buffer dmab;
 
 	emu10k1_memblk_init(blk);
 	get_single_page_range(emu->memhdr, blk, &first_page, &last_page);
 	/* allocate kernel pages */
 	for (page = first_page; page <= last_page; page++) {
-		ptr = snd_malloc_pci_page(emu->pci, &addr);
-		if (ptr == NULL)
+		if (snd_dma_alloc_pages(&emu->dma_dev, PAGE_SIZE, &dmab) < 0)
 			goto __fail;
-		if (! is_valid_page(emu, addr)) {
-			snd_free_pci_page(emu->pci, ptr, addr);
+		if (! is_valid_page(emu, dmab.addr)) {
+			snd_dma_free_pages(&emu->dma_dev, &dmab);
 			goto __fail;
 		}
-		emu->page_addr_table[page] = addr;
-		emu->page_ptr_table[page] = ptr;
+		emu->page_addr_table[page] = dmab.addr;
+		emu->page_ptr_table[page] = dmab.area;
 	}
 	return 0;
 
@@ -459,7 +456,10 @@ __fail:
 	/* release allocated pages */
 	last_page = page - 1;
 	for (page = first_page; page <= last_page; page++) {
-		snd_free_pci_page(emu->pci, emu->page_ptr_table[page], emu->page_addr_table[page]);
+		dmab.area = emu->page_ptr_table[page];
+		dmab.addr = emu->page_addr_table[page];
+		dmab.bytes = PAGE_SIZE;
+		snd_dma_free_pages(&emu->dma_dev, &dmab);
 		emu->page_addr_table[page] = 0;
 		emu->page_ptr_table[page] = NULL;
 	}
@@ -473,11 +473,16 @@ __fail:
 static int synth_free_pages(emu10k1_t *emu, emu10k1_memblk_t *blk)
 {
 	int page, first_page, last_page;
+	struct snd_dma_buffer dmab;
 
 	get_single_page_range(emu->memhdr, blk, &first_page, &last_page);
 	for (page = first_page; page <= last_page; page++) {
-		if (emu->page_ptr_table[page])
-			snd_free_pci_page(emu->pci, emu->page_ptr_table[page], emu->page_addr_table[page]);
+		if (emu->page_ptr_table[page] == NULL)
+			continue;
+		dmab.area = emu->page_ptr_table[page];
+		dmab.addr = emu->page_addr_table[page];
+		dmab.bytes = PAGE_SIZE;
+		snd_dma_free_pages(&emu->dma_dev, &dmab);
 		emu->page_addr_table[page] = 0;
 		emu->page_ptr_table[page] = NULL;
 	}
--- diff/sound/pci/ens1370.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/ens1370.c	2004-03-09 11:51:52.000000000 +0000
@@ -434,8 +434,8 @@ struct _snd_ensoniq {
 	unsigned int spdif_stream;
 
 #ifdef CHIP1370
-	unsigned char *bugbuf;
-	dma_addr_t bugbuf_addr;
+	struct snd_dma_device dma_dev;
+	struct snd_dma_buffer dma_bug;
 #endif
 
 #ifdef SUPPORT_JOYSTICK
@@ -1250,7 +1250,8 @@ static int __devinit snd_ensoniq_pcm(ens
 #endif
 	ensoniq->pcm1 = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(ensoniq->pci, pcm, 64*1024, 128*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(ensoniq->pci), 64*1024, 128*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
@@ -1294,7 +1295,8 @@ static int __devinit snd_ensoniq_pcm2(en
 #endif
 	ensoniq->pcm2 = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(ensoniq->pci, pcm, 64*1024, 128*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(ensoniq->pci), 64*1024, 128*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
@@ -1829,8 +1831,8 @@ static int snd_ensoniq_free(ensoniq_t *e
 	pci_set_power_state(ensoniq->pci, 3);
       __hw_end:
 #ifdef CHIP1370
-	if (ensoniq->bugbuf)
-		snd_free_pci_pages(ensoniq->pci, 16, ensoniq->bugbuf, ensoniq->bugbuf_addr);
+	if (ensoniq->dma_bug.area)
+		snd_dma_free_pages(&ensoniq->dma_dev, &ensoniq->dma_bug);
 #endif
 	if (ensoniq->res_port) {
 		release_resource(ensoniq->res_port);
@@ -1911,8 +1913,11 @@ static int __devinit snd_ensoniq_create(
 	}
 	ensoniq->irq = pci->irq;
 #ifdef CHIP1370
-	if ((ensoniq->bugbuf = snd_malloc_pci_pages(pci, 16, &ensoniq->bugbuf_addr)) == NULL) {
-		snd_printk("unable to allocate space for phantom area - bugbuf\n");
+	memset(&ensoniq->dma_dev, 0, sizeof(ensoniq->dma_dev));
+	ensoniq->dma_dev.type = SNDRV_DMA_TYPE_DEV;
+	ensoniq->dma_dev.dev = snd_dma_pci_data(pci);
+	if (snd_dma_alloc_pages(&ensoniq->dma_dev, 16, &ensoniq->dma_bug) < 0) {
+		snd_printk("unable to allocate space for phantom area - dma_bug\n");
 		snd_ensoniq_free(ensoniq);
 		return -EBUSY;
 	}
@@ -1936,7 +1941,7 @@ static int __devinit snd_ensoniq_create(
 	outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
 	outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL));
 	outl(ES_MEM_PAGEO(ES_PAGE_ADC), ES_REG(ensoniq, MEM_PAGE));
-	outl(ensoniq->bugbuf_addr, ES_REG(ensoniq, PHANTOM_FRAME));
+	outl(ensoniq->dma_bug.addr, ES_REG(ensoniq, PHANTOM_FRAME));
 	outl(0, ES_REG(ensoniq, PHANTOM_COUNT));
 #else
 	ensoniq->ctrl = 0;
--- diff/sound/pci/es1938.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/es1938.c	2004-03-09 11:51:52.000000000 +0000
@@ -946,17 +946,14 @@ static int snd_es1938_playback_open(snd_
 static int snd_es1938_capture_close(snd_pcm_substream_t * substream)
 {
 	es1938_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
 
 	chip->capture_substream = NULL;
-	snd_free_pci_pages(chip->pci, runtime->dma_bytes, runtime->dma_area, runtime->dma_addr);
 	return 0;
 }
 
 static int snd_es1938_playback_close(snd_pcm_substream_t * substream)
 {
 	es1938_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
 
 	switch (substream->number) {
 	case 0:
@@ -969,7 +966,6 @@ static int snd_es1938_playback_close(snd
 		snd_BUG();
 		return -EINVAL;
 	}
-	snd_free_pci_pages(chip->pci, runtime->dma_bytes, runtime->dma_area, runtime->dma_addr);
 	return 0;
 }
 
@@ -1018,7 +1014,8 @@ static int __devinit snd_es1938_new_pcm(
 	pcm->info_flags = 0;
 	strcpy(pcm->name, "ESS Solo-1");
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 64*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(chip->pci), 64*1024, 64*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
--- diff/sound/pci/es1968.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/es1968.c	2004-03-09 11:51:52.000000000 +0000
@@ -1495,13 +1495,15 @@ static void snd_es1968_free_dmabuf(es196
 static int __devinit
 snd_es1968_init_dmabuf(es1968_t *chip)
 {
+	int err;
 	esm_memory_t *chunk;
 
-	snd_dma_device_pci(&chip->dma_dev, chip->pci, 0);
+	chip->dma_dev.type = SNDRV_DMA_TYPE_DEV;
+	chip->dma_dev.dev = snd_dma_pci_data(chip->pci);
+	chip->dma_dev.id = 0;
 	if (! snd_dma_get_reserved(&chip->dma_dev, &chip->dma)) {
-		chip->dma.area = snd_malloc_pci_pages_fallback(chip->pci, chip->total_bufsize,
-							       &chip->dma.addr, &chip->dma.bytes);
-		if (chip->dma.area == NULL) {
+		err = snd_dma_alloc_pages_fallback(&chip->dma_dev, chip->total_bufsize, &chip->dma);
+		if (err < 0 || ! chip->dma.area) {
 			snd_printk("es1968: can't allocate dma pages for size %d\n",
 				   chip->total_bufsize);
 			return -ENOMEM;
--- diff/sound/pci/fm801.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/fm801.c	2004-03-09 11:51:52.000000000 +0000
@@ -35,7 +35,7 @@
 
 #include <asm/io.h>
 
-#if defined(CONFIG_SND_FM801_TEA575X) && (defined(CONFIG_VIDEO_DEV) || defined(CONFIG_VIDEO_DEV_MODULE))
+#if (defined(CONFIG_SND_FM801_TEA575X) || defined(CONFIG_SND_FM801_TEA575X_MODULE)) && (defined(CONFIG_VIDEO_DEV) || defined(CONFIG_VIDEO_DEV_MODULE))
 #include <sound/tea575x-tuner.h>
 #define TEA575X_RADIO 1
 #endif
@@ -703,7 +703,9 @@ static int __devinit snd_fm801_pcm(fm801
 	strcpy(pcm->name, "FM801");
 	chip->pcm = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, chip->multichannel ? 128*1024 : 64*1024, 128*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(chip->pci),
+					      chip->multichannel ? 128*1024 : 64*1024, 128*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
--- diff/sound/pci/ice1712/amp.c	2003-02-13 11:46:57.000000000 +0000
+++ source/sound/pci/ice1712/amp.c	2004-03-09 11:51:52.000000000 +0000
@@ -38,6 +38,7 @@ static int __devinit snd_vt1724_amp_init
 	/* only use basic functionality for now */
 
 	ice->num_total_dacs = 2;	/* only PSDOUT0 is connected */
+	ice->num_total_adcs = 2;
 
 	return 0;
 }
--- diff/sound/pci/ice1712/aureon.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/ice1712/aureon.c	2004-03-09 11:51:52.000000000 +0000
@@ -409,10 +409,13 @@ static int __devinit aureon_init(ice1712
 	unsigned int tmp;
 	unsigned int i;
 
-	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY)
+	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
 		ice->num_total_dacs = 6;
-	else
+		ice->num_total_adcs = 6;
+	} else {
 		ice->num_total_dacs = 8;
+		ice->num_total_adcs = 8;
+	}
 
 	/* to remeber the register values */
 	ice->akm = snd_kcalloc(sizeof(akm4xxx_t), GFP_KERNEL);
--- diff/sound/pci/ice1712/delta.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/ice1712/delta.c	2004-03-09 11:51:52.000000000 +0000
@@ -511,20 +511,25 @@ static int __devinit snd_ice1712_delta_i
 	switch (ice->eeprom.subvendor) {
 	case ICE1712_SUBDEVICE_AUDIOPHILE:
 		ice->num_total_dacs = 2;
+		ice->num_total_adcs = 2;
 		break;
 	case ICE1712_SUBDEVICE_DELTA410:
 		ice->num_total_dacs = 8;
+		ice->num_total_adcs = 2;
 		break;
 	case ICE1712_SUBDEVICE_DELTA44:
 	case ICE1712_SUBDEVICE_DELTA66:
 		ice->num_total_dacs = ice->omni ? 8 : 4;
+		ice->num_total_adcs = ice->omni ? 8 : 4;
 		break;
 	case ICE1712_SUBDEVICE_DELTA1010:
 	case ICE1712_SUBDEVICE_DELTA1010LT:
 		ice->num_total_dacs = 8;
+		ice->num_total_adcs = 8;
 		break;
 	case ICE1712_SUBDEVICE_VX442:
 		ice->num_total_dacs = 4;
+		ice->num_total_adcs = 4;
 		break;
 	}
 
--- diff/sound/pci/ice1712/ews.c	2003-08-20 14:16:35.000000000 +0100
+++ source/sound/pci/ice1712/ews.c	2004-03-09 11:51:52.000000000 +0000
@@ -406,15 +406,18 @@ static int __devinit snd_ice1712_ews_ini
 	switch (ice->eeprom.subvendor) {
 	case ICE1712_SUBDEVICE_EWX2496:
 		ice->num_total_dacs = 2;
+		ice->num_total_adcs = 2;
 		break;	
 	case ICE1712_SUBDEVICE_EWS88MT:
 	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 		ice->num_total_dacs = 8;
+		ice->num_total_adcs = 8;
 		break;
 	case ICE1712_SUBDEVICE_EWS88D:
 		break; /* no analog */
 	case ICE1712_SUBDEVICE_DMX6FIRE:
 		ice->num_total_dacs = 6;
+		ice->num_total_adcs = 6;
 		break;
 	}
 
--- diff/sound/pci/ice1712/hoontech.c	2002-12-30 10:17:14.000000000 +0000
+++ source/sound/pci/ice1712/hoontech.c	2004-03-09 11:51:52.000000000 +0000
@@ -153,6 +153,7 @@ static int __devinit snd_ice1712_hoontec
 	int box, chn;
 
 	ice->num_total_dacs = 8;
+	ice->num_total_adcs = 8;
 
 	ice->hoontech_boxbits[0] = 
 	ice->hoontech_boxbits[1] = 
--- diff/sound/pci/ice1712/ice1712.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/ice1712/ice1712.c	2004-03-09 11:51:52.000000000 +0000
@@ -886,7 +886,8 @@ static int __devinit snd_ice1712_pcm(ice
 	strcpy(pcm->name, "ICE1712 consumer");
 	ice->pcm = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(ice->pci, pcm, 64*1024, 64*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(ice->pci), 64*1024, 64*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
@@ -922,7 +923,8 @@ static int __devinit snd_ice1712_pcm_ds(
 	strcpy(pcm->name, "ICE1712 consumer (DS)");
 	ice->pcm_ds = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(ice->pci, pcm, 64*1024, 128*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(ice->pci), 64*1024, 128*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
@@ -1269,7 +1271,8 @@ static int __devinit snd_ice1712_pcm_pro
 	pcm->info_flags = 0;
 	strcpy(pcm->name, "ICE1712 multi");
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(ice->pci, pcm, 256*1024, 256*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(ice->pci), 256*1024, 256*1024);
 
 	ice->pcm_pro = pcm;
 	if (rpcm)
@@ -1381,7 +1384,7 @@ static int snd_ice1712_pro_mixer_volume_
 }
 
 
-static snd_kcontrol_new_t snd_ice1712_multi_ctrls[] __devinitdata = {
+static snd_kcontrol_new_t snd_ice1712_multi_playback_ctrls[] __devinitdata = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Multi Playback Switch",
@@ -1400,24 +1403,44 @@ static snd_kcontrol_new_t snd_ice1712_mu
 		.private_value = 0,
 		.count = 10,
 	},
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Multi Capture Switch",
-		.info = snd_ice1712_pro_mixer_switch_info,
-		.get = snd_ice1712_pro_mixer_switch_get,
-		.put = snd_ice1712_pro_mixer_switch_put,
-		.private_value = 10,
-		.count = 10,
-	},
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Multi Capture Volume",
-		.info = snd_ice1712_pro_mixer_volume_info,
-		.get = snd_ice1712_pro_mixer_volume_get,
-		.put = snd_ice1712_pro_mixer_volume_put,
-		.private_value = 10,
-		.count = 10,
-	},
+};
+
+static snd_kcontrol_new_t snd_ice1712_multi_capture_analog_switch __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "H/W Multi Capture Switch",
+	.info = snd_ice1712_pro_mixer_switch_info,
+	.get = snd_ice1712_pro_mixer_switch_get,
+	.put = snd_ice1712_pro_mixer_switch_put,
+	.private_value = 10,
+};
+
+static snd_kcontrol_new_t snd_ice1712_multi_capture_spdif_switch __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "IEC958 Multi Capture Switch",
+	.info = snd_ice1712_pro_mixer_switch_info,
+	.get = snd_ice1712_pro_mixer_switch_get,
+	.put = snd_ice1712_pro_mixer_switch_put,
+	.private_value = 18,
+	.count = 2,
+};
+
+static snd_kcontrol_new_t snd_ice1712_multi_capture_analog_volume __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "H/W Multi Capture Volume",
+	.info = snd_ice1712_pro_mixer_volume_info,
+	.get = snd_ice1712_pro_mixer_volume_get,
+	.put = snd_ice1712_pro_mixer_volume_put,
+	.private_value = 10,
+};
+
+static snd_kcontrol_new_t snd_ice1712_multi_capture_spdif_volume __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "IEC958 Multi Capture Volume",
+	.info = snd_ice1712_pro_mixer_volume_info,
+	.get = snd_ice1712_pro_mixer_volume_get,
+	.put = snd_ice1712_pro_mixer_volume_put,
+	.private_value = 18,
+	.count = 2,
 };
 
 static int __devinit snd_ice1712_build_pro_mixer(ice1712_t *ice)
@@ -1427,14 +1450,46 @@ static int __devinit snd_ice1712_build_p
 	int err;
 
 	/* multi-channel mixer */
-	for (idx = 0; idx < ARRAY_SIZE(snd_ice1712_multi_ctrls); idx++) {
-		err = snd_ctl_add(card, snd_ctl_new1(&snd_ice1712_multi_ctrls[idx], ice));
+	for (idx = 0; idx < ARRAY_SIZE(snd_ice1712_multi_playback_ctrls); idx++) {
+		err = snd_ctl_add(card, snd_ctl_new1(&snd_ice1712_multi_playback_ctrls[idx], ice));
 		if (err < 0)
 			return err;
 	}
 	
+	if (ice->num_total_adcs > 0) {
+		snd_kcontrol_new_t tmp = snd_ice1712_multi_capture_analog_switch;
+		tmp.count = ice->num_total_adcs;
+		err = snd_ctl_add(card, snd_ctl_new1(&tmp, ice));
+		if (err < 0)
+			return err;
+	}
+
+	err = snd_ctl_add(card, snd_ctl_new1(&snd_ice1712_multi_capture_spdif_switch, ice));
+	if (err < 0)
+		return err;
+
+	if (ice->num_total_adcs > 0) {
+		snd_kcontrol_new_t tmp = snd_ice1712_multi_capture_analog_volume;
+		tmp.count = ice->num_total_adcs;
+		err = snd_ctl_add(card, snd_ctl_new1(&tmp, ice));
+		if (err < 0)
+			return err;
+	}
+
+	err = snd_ctl_add(card, snd_ctl_new1(&snd_ice1712_multi_capture_spdif_volume, ice));
+	if (err < 0)
+		return err;
+
 	/* initialize volumes */
-	for (idx = 0; idx < 20; idx++) {
+	for (idx = 0; idx < 10; idx++) {
+		ice->pro_volumes[idx] = 0x80008000;	/* mute */
+		snd_ice1712_update_volume(ice, idx);
+	}
+	for (idx = 10; idx < 10 + ice->num_total_adcs; idx++) {
+		ice->pro_volumes[idx] = 0x80008000;	/* mute */
+		snd_ice1712_update_volume(ice, idx);
+	}
+	for (idx = 18; idx < 20; idx++) {
 		ice->pro_volumes[idx] = 0x80008000;	/* mute */
 		snd_ice1712_update_volume(ice, idx);
 	}
@@ -2375,6 +2430,7 @@ static int __devinit snd_ice1712_create(
 	ice->omni = omni ? 1 : 0;
 	spin_lock_init(&ice->reg_lock);
 	init_MUTEX(&ice->gpio_mutex);
+	init_MUTEX(&ice->open_mutex);
 	ice->gpio.set_mask = snd_ice1712_set_gpio_mask;
 	ice->gpio.set_dir = snd_ice1712_set_gpio_dir;
 	ice->gpio.set_data = snd_ice1712_set_gpio_data;
--- diff/sound/pci/ice1712/ice1712.h	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/ice1712/ice1712.h	2004-03-09 11:51:52.000000000 +0000
@@ -330,11 +330,15 @@ struct _snd_ice1712 {
 	unsigned int omni: 1;		/* Delta Omni I/O */
 	unsigned int vt1724: 1;
 	unsigned int num_total_dacs;	/* total DACs */
+	unsigned int num_total_adcs;	/* total ADCs */
 	unsigned char hoontech_boxbits[4];
 	unsigned int hoontech_config;
 	unsigned short hoontech_boxconfig[4];
 	unsigned int cur_rate;		/* current rate */
 
+	struct semaphore open_mutex;
+	snd_pcm_substream_t *pcm_reserved[4];
+
 	unsigned int akm_codecs;
 	akm4xxx_t *akm;
 	struct snd_ice1712_spdif spdif;
--- diff/sound/pci/ice1712/ice1724.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/ice1712/ice1724.c	2004-03-09 11:51:52.000000000 +0000
@@ -237,6 +237,18 @@ static irqreturn_t snd_vt1724_interrupt(
 				if (ice->capture_pro_substream)
 					snd_pcm_period_elapsed(ice->capture_pro_substream);
 			}
+			if (mtstat & VT1724_MULTI_PDMA1) {
+				if (ice->playback_con_substream_ds[0])
+					snd_pcm_period_elapsed(ice->playback_con_substream_ds[0]);
+			}
+			if (mtstat & VT1724_MULTI_PDMA2) {
+				if (ice->playback_con_substream_ds[1])
+					snd_pcm_period_elapsed(ice->playback_con_substream_ds[1]);
+			}
+			if (mtstat & VT1724_MULTI_PDMA3) {
+				if (ice->playback_con_substream_ds[2])
+					snd_pcm_period_elapsed(ice->playback_con_substream_ds[2]);
+			}
 			if (mtstat & VT1724_MULTI_PDMA4) {
 				if (ice->playback_con_substream)
 					snd_pcm_period_elapsed(ice->playback_con_substream);
@@ -282,16 +294,6 @@ static snd_pcm_hw_constraint_list_t hw_c
 	.mask = 0,
 };
 
-static unsigned int hw_channels[] = {
-	2, 4, 6, 8
-};
-
-static snd_pcm_hw_constraint_list_t hw_constraints_channels = {
-	.count = ARRAY_SIZE(hw_channels),
-	.list = hw_channels,
-	.mask = 0,
-};
-
 static int snd_vt1724_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
 {
 	ice1712_t *ice = snd_pcm_substream_chip(substream);
@@ -300,21 +302,16 @@ static int snd_vt1724_pcm_trigger(snd_pc
 	struct list_head *pos;
 	snd_pcm_substream_t *s;
 
+	what = 0;
+	snd_pcm_group_for_each(pos, substream) {
+		s = snd_pcm_group_substream_entry(pos);
+		what |= (unsigned long)(s->runtime->private_data);
+		snd_pcm_trigger_done(s, substream);
+	}
+
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		what = 0;
-		snd_pcm_group_for_each(pos, substream) {
-			s = snd_pcm_group_substream_entry(pos);
-			if (s == ice->playback_pro_substream)
-				what |= VT1724_PDMA0_PAUSE;
-			else if (s == ice->capture_pro_substream)
-				what |= VT1724_RDMA0_PAUSE;
-			else if (s == ice->playback_con_substream)
-				what |= VT1724_PDMA4_PAUSE;
-			else if (s == ice->capture_con_substream)
-				what |= VT1724_RDMA1_PAUSE;
-		}
 		spin_lock(&ice->reg_lock);
 		old = inb(ICEMT1724(ice, DMA_PAUSE));
 		if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)
@@ -327,24 +324,6 @@ static int snd_vt1724_pcm_trigger(snd_pc
 
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_STOP:
-		what = 0;
-		s = substream;
-		snd_pcm_group_for_each(pos, substream) {
-			s = snd_pcm_group_substream_entry(pos);
-			if (s == ice->playback_pro_substream) {
-				what |= VT1724_PDMA0_START;
-				snd_pcm_trigger_done(s, substream);
-			} else if (s == ice->capture_pro_substream) {
-				what |= VT1724_RDMA0_START;
-				snd_pcm_trigger_done(s, substream);
-			} else if (s == ice->playback_con_substream) {
-				what |= VT1724_PDMA4_START;
-				snd_pcm_trigger_done(s, substream);
-			} else if (s == ice->capture_con_substream) {
-				what |= VT1724_RDMA1_START;
-				snd_pcm_trigger_done(s, substream);
-			}
-		}
 		spin_lock(&ice->reg_lock);
 		old = inb(ICEMT1724(ice, DMA_CONTROL));
 		if (cmd == SNDRV_PCM_TRIGGER_START)
@@ -364,8 +343,10 @@ static int snd_vt1724_pcm_trigger(snd_pc
 /*
  */
 
-#define DMA_STARTS	(VT1724_RDMA0_START|VT1724_PDMA0_START|VT1724_RDMA1_START|VT1724_PDMA4_START)
-#define DMA_PAUSES	(VT1724_RDMA0_PAUSE|VT1724_PDMA0_PAUSE|VT1724_RDMA1_PAUSE|VT1724_PDMA4_PAUSE)
+#define DMA_STARTS	(VT1724_RDMA0_START|VT1724_PDMA0_START|VT1724_RDMA1_START|\
+	VT1724_PDMA1_START|VT1724_PDMA2_START|VT1724_PDMA3_START|VT1724_PDMA4_START)
+#define DMA_PAUSES	(VT1724_RDMA0_PAUSE|VT1724_PDMA0_PAUSE|VT1724_RDMA1_PAUSE|\
+	VT1724_PDMA1_PAUSE|VT1724_PDMA2_PAUSE|VT1724_PDMA3_PAUSE|VT1724_PDMA4_PAUSE)
 
 static void snd_vt1724_set_pro_rate(ice1712_t *ice, unsigned int rate, int force)
 {
@@ -448,13 +429,52 @@ static int snd_vt1724_pcm_hw_params(snd_
 				    snd_pcm_hw_params_t * hw_params)
 {
 	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	int i, chs;
 
+	chs = params_channels(hw_params);
+	down(&ice->open_mutex);
+	/* mark surround channels */
+	if (substream == ice->playback_pro_substream) {
+		chs = chs / 2 - 1;
+		for (i = 0; i < chs; i++) {
+			if (ice->pcm_reserved[i] && ice->pcm_reserved[i] != substream) {
+				up(&ice->open_mutex);
+				return -EBUSY;
+			}
+			ice->pcm_reserved[i] = substream;
+		}
+		for (; i < 3; i++) {
+			if (ice->pcm_reserved[i] == substream)
+				ice->pcm_reserved[i] = NULL;
+		}
+	} else {
+		for (i = 0; i < 3; i++) {
+			if (ice->playback_con_substream_ds[i] == substream) {
+				if (ice->pcm_reserved[i] && ice->pcm_reserved[i] != substream) {
+					up(&ice->open_mutex);
+					return -EBUSY;
+				}
+				ice->pcm_reserved[i] = substream;
+				break;
+			}
+		}
+	}
+	up(&ice->open_mutex);
 	snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0);
 	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
 }
 
 static int snd_vt1724_pcm_hw_free(snd_pcm_substream_t * substream)
 {
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	int i;
+
+	down(&ice->open_mutex);
+	/* unmark surround channels */
+	for (i = 0; i < 3; i++)
+		if (ice->pcm_reserved[i] == substream)
+			ice->pcm_reserved[i] = NULL;
+	up(&ice->open_mutex);
 	return snd_pcm_lib_free_pages(substream);
 }
 
@@ -593,14 +613,14 @@ static snd_pcm_hardware_t snd_vt1724_pla
 	.rate_max =		192000,
 	.channels_min =		2,
 	.channels_max =		8,
-	.buffer_bytes_max =	(1UL << 21),	/* 18bits dword */
+	.buffer_bytes_max =	(1UL << 21),	/* 19bits dword */
 	.period_bytes_min =	8 * 4 * 2,	/* FIXME: constraints needed */
 	.period_bytes_max =	(1UL << 21),
-	.periods_min =		1,
+	.periods_min =		2,
 	.periods_max =		1024,
 };
 
-static snd_pcm_hardware_t snd_vt1724_capture_pro =
+static snd_pcm_hardware_t snd_vt1724_2ch_stereo =
 {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -612,10 +632,10 @@ static snd_pcm_hardware_t snd_vt1724_cap
 	.rate_max =		192000,
 	.channels_min =		2,
 	.channels_max =		2,
-	.buffer_bytes_max =	(256*1024),
+	.buffer_bytes_max =	(1UL << 18),	/* 16bits dword */
 	.period_bytes_min =	2 * 4 * 2,
-	.period_bytes_max =	(256*1024),
-	.periods_min =		1,
+	.period_bytes_max =	(1UL << 18),
+	.periods_min =		2,
 	.periods_max =		1024,
 };
 
@@ -628,7 +648,9 @@ static int snd_vt1724_playback_pro_open(
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	int chs;
 
+	runtime->private_data = (void*)VT1724_PDMA0_START; /* irq/status/trigger bit */
 	ice->playback_pro_substream = substream;
 	runtime->hw = snd_vt1724_playback_pro;
 	snd_pcm_set_sync(substream);
@@ -639,7 +661,17 @@ static int snd_vt1724_playback_pro_open(
 	else
 		snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_96);
 
-	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels);
+	down(&ice->open_mutex);
+	/* calculate the currently available channels */
+	for (chs = 0; chs < 3; chs++) {
+		if (ice->pcm_reserved[chs])
+			break;
+	}
+	chs = (chs + 1) * 2;
+	runtime->hw.channels_max = chs;
+	if (chs > 2) /* channels must be even */
+		snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+	up(&ice->open_mutex);
 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
 				   VT1724_BUFFER_ALIGN);
 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
@@ -652,8 +684,9 @@ static int snd_vt1724_capture_pro_open(s
 	ice1712_t *ice = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
 
+	runtime->private_data = (void*)VT1724_RDMA0_START; /* irq/status/trigger bit */
 	ice->capture_pro_substream = substream;
-	runtime->hw = snd_vt1724_capture_pro;
+	runtime->hw = snd_vt1724_2ch_stereo;
 	snd_pcm_set_sync(substream);
 	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
 	if ((ice->eeprom.data[ICE_EEP2_ACLINK] & 0x80) &&
@@ -723,7 +756,8 @@ static int __devinit snd_vt1724_pcm_prof
 	pcm->info_flags = 0;
 	strcpy(pcm->name, "ICE1724");
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(ice->pci, pcm, 256*1024, 256*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(ice->pci), 256*1024, 256*1024);
 
 	ice->pcm_pro = pcm;
 
@@ -735,25 +769,6 @@ static int __devinit snd_vt1724_pcm_prof
  * SPDIF PCM
  */
 
-static snd_pcm_hardware_t snd_vt1724_playback_spdif =
-{
-	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
-				 SNDRV_PCM_INFO_MMAP_VALID |
-				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START),
-	.formats =		SNDRV_PCM_FMTBIT_S32_LE,
-	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_192000,
-	.rate_min =		4000,
-	.rate_max =		192000,
-	.channels_min =		2,
-	.channels_max =		2,
-	.buffer_bytes_max =	(256*1024),
-	.period_bytes_min =	2 * 4 * 2,
-	.period_bytes_max =	(256*1024),
-	.periods_min =		1,
-	.periods_max =		1024,
-};
-
 const static struct vt1724_pcm_reg vt1724_playback_spdif_reg = {
 	.addr = VT1724_MT_PDMA4_ADDR,
 	.size = VT1724_MT_PDMA4_SIZE,
@@ -795,8 +810,9 @@ static int snd_vt1724_playback_spdif_ope
 	ice1712_t *ice = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
 
+	runtime->private_data = (void*)VT1724_PDMA4_START; /* irq/status/trigger bit */
 	ice->playback_con_substream = substream;
-	runtime->hw = snd_vt1724_playback_spdif;
+	runtime->hw = snd_vt1724_2ch_stereo;
 	snd_pcm_set_sync(substream);
 	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
 
@@ -820,8 +836,9 @@ static int snd_vt1724_capture_spdif_open
 	ice1712_t *ice = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
 
+	runtime->private_data = (void*)VT1724_RDMA1_START; /* irq/status/trigger bit */
 	ice->capture_con_substream = substream;
-	runtime->hw = snd_vt1724_playback_spdif;
+	runtime->hw = snd_vt1724_2ch_stereo;
 	snd_pcm_set_sync(substream);
 	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_96);
@@ -894,7 +911,8 @@ static int __devinit snd_vt1724_pcm_spdi
 	pcm->info_flags = 0;
 	strcpy(pcm->name, "ICE1724 IEC958");
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(ice->pci, pcm, 64*1024, 64*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(ice->pci), 64*1024, 64*1024);
 
 	ice->pcm = pcm;
 
@@ -903,6 +921,128 @@ static int __devinit snd_vt1724_pcm_spdi
 
 
 /*
+ * independent surround PCMs
+ */
+
+const static struct vt1724_pcm_reg vt1724_playback_dma_regs[3] = {
+	{
+		.addr = VT1724_MT_PDMA1_ADDR,
+		.size = VT1724_MT_PDMA1_SIZE,
+		.count = VT1724_MT_PDMA1_COUNT,
+		.start = VT1724_PDMA1_START,
+		.pause = VT1724_PDMA1_PAUSE,
+	},
+	{
+		.addr = VT1724_MT_PDMA2_ADDR,
+		.size = VT1724_MT_PDMA2_SIZE,
+		.count = VT1724_MT_PDMA2_COUNT,
+		.start = VT1724_PDMA2_START,
+		.pause = VT1724_PDMA2_PAUSE,
+	},
+	{
+		.addr = VT1724_MT_PDMA3_ADDR,
+		.size = VT1724_MT_PDMA3_SIZE,
+		.count = VT1724_MT_PDMA3_COUNT,
+		.start = VT1724_PDMA3_START,
+		.pause = VT1724_PDMA3_PAUSE,
+	},
+};
+
+static int snd_vt1724_playback_indep_prepare(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	unsigned char val;
+
+	spin_lock(&ice->reg_lock);
+	val = 3 - substream->number;
+	if (inb(ICEMT1724(ice, BURST)) < val)
+		outb(val, ICEMT1724(ice, BURST));
+	spin_unlock(&ice->reg_lock);
+	return snd_vt1724_pcm_prepare(substream, &vt1724_playback_dma_regs[substream->number]);
+}
+
+static snd_pcm_uframes_t snd_vt1724_playback_indep_pointer(snd_pcm_substream_t * substream)
+{
+	return snd_vt1724_pcm_pointer(substream, &vt1724_playback_dma_regs[substream->number]);
+}
+
+static int snd_vt1724_playback_indep_open(snd_pcm_substream_t *substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	down(&ice->open_mutex);
+	/* already used by PDMA0? */
+	if (ice->pcm_reserved[substream->number]) {
+		up(&ice->open_mutex);
+		return -EBUSY; /* FIXME: should handle blocking mode properly */
+	}
+	up(&ice->open_mutex);
+	runtime->private_data = (void*)(1 << (substream->number + 4));
+	ice->playback_con_substream_ds[substream->number] = substream;
+	runtime->hw = snd_vt1724_2ch_stereo;
+	snd_pcm_set_sync(substream);
+	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
+
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_192);
+	return 0;
+}
+
+static int snd_vt1724_playback_indep_close(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	if (PRO_RATE_RESET)
+		snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
+	ice->playback_con_substream_ds[substream->number] = NULL;
+	ice->pcm_reserved[substream->number] = NULL;
+
+	return 0;
+}
+
+static snd_pcm_ops_t snd_vt1724_playback_indep_ops = {
+	.open =		snd_vt1724_playback_indep_open,
+	.close =	snd_vt1724_playback_indep_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_vt1724_pcm_hw_params,
+	.hw_free =	snd_vt1724_pcm_hw_free,
+	.prepare =	snd_vt1724_playback_indep_prepare,
+	.trigger =	snd_vt1724_pcm_trigger,
+	.pointer =	snd_vt1724_playback_indep_pointer,
+};
+
+
+static int __devinit snd_vt1724_pcm_indep(ice1712_t * ice, int device)
+{
+	snd_pcm_t *pcm;
+	int play;
+	int err;
+
+	play = ice->num_total_dacs / 2 - 1;
+	if (play <= 0)
+		return 0;
+
+	err = snd_pcm_new(ice->card, "ICE1724 Surrounds", device, play, 0, &pcm);
+	if (err < 0)
+		return err;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+			&snd_vt1724_playback_indep_ops);
+
+	pcm->private_data = ice;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, "ICE1724 Surround PCM");
+
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(ice->pci), 64*1024, 64*1024);
+
+	ice->pcm_ds = pcm;
+
+	return 0;
+}
+
+
+/*
  *  Mixer section
  */
 
@@ -1808,6 +1948,7 @@ static int __devinit snd_vt1724_create(s
 	ice->vt1724 = 1;
 	spin_lock_init(&ice->reg_lock);
 	init_MUTEX(&ice->gpio_mutex);
+	init_MUTEX(&ice->open_mutex);
 	ice->gpio.set_mask = snd_vt1724_set_gpio_mask;
 	ice->gpio.set_dir = snd_vt1724_set_gpio_dir;
 	ice->gpio.set_data = snd_vt1724_set_gpio_data;
@@ -1932,6 +2073,11 @@ static int __devinit snd_vt1724_probe(st
 		return err;
 	}
 	
+	if ((err = snd_vt1724_pcm_indep(ice, pcm_dev++)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
 	if ((err = snd_vt1724_ac97_mixer(ice)) < 0) {
 		snd_card_free(card);
 		return err;
--- diff/sound/pci/ice1712/prodigy.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/ice1712/prodigy.c	2004-03-09 11:51:52.000000000 +0000
@@ -585,6 +585,7 @@ static int __devinit prodigy_init(ice171
 	printk(KERN_INFO "ice1724:   Apostolos Dimitromanolakis <apostol@cs.utoronto.ca>\n");
 
 	ice->num_total_dacs = 8;
+	ice->num_total_adcs = 8;
 
 	/* to remeber the register values */
 	ice->akm = snd_kcalloc(sizeof(akm4xxx_t), GFP_KERNEL);
--- diff/sound/pci/ice1712/revo.c	2003-09-30 15:46:21.000000000 +0100
+++ source/sound/pci/ice1712/revo.c	2004-03-09 11:51:52.000000000 +0000
@@ -128,6 +128,7 @@ static int __devinit revo_init(ice1712_t
 	switch (ice->eeprom.subvendor) {
 	case VT1724_SUBDEVICE_REVOLUTION71:
 		ice->num_total_dacs = 8;
+		ice->num_total_adcs = 4;
 		break;
 	default:
 		snd_BUG();
--- diff/sound/pci/intel8x0.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/intel8x0.c	2004-03-09 11:51:52.000000000 +0000
@@ -143,6 +143,9 @@ MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABL
 #ifndef PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO
 #define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO	0x00da
 #endif
+#ifndef PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO
+#define PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO	0x00ea
+#endif
 
 enum { DEVICE_INTEL, DEVICE_INTEL_ICH4, DEVICE_SIS, DEVICE_ALI, DEVICE_NFORCE };
 
@@ -396,6 +399,8 @@ struct _snd_intel8x0 {
 	unsigned long remap_bmaddr;
 	struct resource *res_bm;
 
+	struct snd_dma_device dma_dev;
+
 	struct pci_dev *pci;
 	snd_card_t *card;
 
@@ -420,8 +425,7 @@ struct _snd_intel8x0 {
 	spinlock_t ac97_lock;
 	
 	u32 bdbars_count;
-	u32 *bdbars;
-	dma_addr_t bdbars_addr;
+	struct snd_dma_buffer bdbars;
 	u32 int_sta_reg;		/* interrupt status register */
 	u32 int_sta_mask;		/* interrupt status mask */
 	unsigned int pcm_pos_shift;
@@ -443,6 +447,7 @@ static struct pci_device_id snd_intel8x0
 	{ 0x10de, 0x01b1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },	/* NFORCE */
 	{ 0x10de, 0x006a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },	/* NFORCE2 */
 	{ 0x10de, 0x00da, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },	/* NFORCE3 */
+	{ 0x10de, 0x00ea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },	/* CK8S */
 	{ 0x1022, 0x746d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* AMD8111 */
 	{ 0x1022, 0x7445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* AMD768 */
 	{ 0x10b9, 0x5455, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALI },   /* Ali5455 */
@@ -804,10 +809,20 @@ static irqreturn_t snd_intel8x0_interrup
 	spin_lock(&chip->reg_lock);
 	status = igetdword(chip, chip->int_sta_reg);
 	if ((status & chip->int_sta_mask) == 0) {
-		if (status)
+		static int err_count = 10;
+		if (status) {
+			/* ack */
 			iputdword(chip, chip->int_sta_reg, status);
+			if (chip->device_type != DEVICE_NFORCE)
+				status ^= igetdword(chip, chip->int_sta_reg);
+		}
 		spin_unlock(&chip->reg_lock);
-		return IRQ_NONE;
+		if (chip->device_type != DEVICE_NFORCE && status && err_count) {
+			err_count--;
+			snd_printd("intel8x0: unknown IRQ bits 0x%x (sta_mask=0x%x)\n",
+				   status, chip->int_sta_mask);
+		}
+		return IRQ_RETVAL(status);
 	}
 
 	for (i = 0; i < chip->bdbars_count; i++) {
@@ -1017,6 +1032,7 @@ static snd_pcm_uframes_t snd_intel8x0_pc
 {
 	intel8x0_t *chip = snd_pcm_substream_chip(substream);
 	ichdev_t *ichdev = get_ichdev(substream);
+	unsigned long flags;
 	size_t ptr1, ptr;
 
 	ptr1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << chip->pcm_pos_shift;
@@ -1024,7 +1040,9 @@ static snd_pcm_uframes_t snd_intel8x0_pc
 		ptr = ichdev->fragsize1 - ptr1;
 	else
 		ptr = 0;
+	spin_lock_irqsave(&chip->reg_lock, flags);
 	ptr += ichdev->position;
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
 	if (ptr >= ichdev->size)
 		return 0;
 	return bytes_to_frames(substream->runtime, ptr);
@@ -1079,21 +1097,12 @@ static int snd_intel8x0_pcm_open(snd_pcm
 {
 	intel8x0_t *chip = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	static unsigned int i, rates[] = {
-		/* ATTENTION: these values depend on the definition in pcm.h! */
-		5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000
-	};
 	int err;
 
 	ichdev->substream = substream;
 	runtime->hw = snd_intel8x0_stream;
 	runtime->hw.rates = ichdev->pcm->rates;
-	for (i = 0; i < ARRAY_SIZE(rates); i++) {
-		if (runtime->hw.rates & (1 << i)) {
-			runtime->hw.rate_min = rates[i];
-			break;
-		}
-	}
+	snd_pcm_limit_hw_rates(runtime);
 	if (chip->device_type == DEVICE_SIS) {
 		runtime->hw.buffer_bytes_max = 64*1024;
 		runtime->hw.period_bytes_max = 64*1024;
@@ -1443,8 +1452,8 @@ static int __devinit snd_intel8x0_pcm1(i
 		strcpy(pcm->name, chip->card->shortname);
 	chip->pcm[device] = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, rec->prealloc_size,
-						  rec->prealloc_max_size);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
+					      rec->prealloc_size, rec->prealloc_max_size);
 
 	return 0;
 }
@@ -1666,6 +1675,12 @@ static struct ac97_pcm ac97_pcm_defs[] _
 
 static struct ac97_quirk ac97_quirks[] __devinitdata = {
 	{
+		.vendor = 0x1014,
+		.device = 0x1f00,
+		.name = "MS-9128",
+		.type = AC97_TUNE_ALC_JACK
+	},
+	{
 		.vendor = 0x1028,
 		.device = 0x00d8,
 		.name = "Dell Precision 530",	/* AD1885 */
@@ -1741,6 +1756,12 @@ static struct ac97_quirk ac97_quirks[] _
 	},
 	{
 		.vendor = 0x8086,
+		.device = 0x4856,
+		.name = "Intel D845WN (82801BA)",
+		.type = AC97_TUNE_SWAP_HP
+	},
+	{
+		.vendor = 0x8086,
 		.device = 0x4d44,
 		.name = "Intel D850EMV2",	/* AD1885 */
 		.type = AC97_TUNE_HP_ONLY
@@ -1759,6 +1780,7 @@ static struct ac97_quirk ac97_quirks[] _
 		.name = "Intel ICH5/AD1985",
 		.type = AC97_TUNE_AD_SHARING
 	},
+#if 0 /* FIXME: this seems wrong on most boards */
 	{
 		.vendor = 0x8086,
 		.device = 0xa000,
@@ -1766,6 +1788,7 @@ static struct ac97_quirk ac97_quirks[] _
 		.name = "Intel ICH5/AD1985",
 		.type = AC97_TUNE_HP_ONLY
 	},
+#endif
 	{ } /* terminator */
 };
 
@@ -2116,10 +2139,10 @@ static int snd_intel8x0_free(intel8x0_t 
 	/* --- */
 	synchronize_irq(chip->irq);
       __hw_end:
-	if (chip->bdbars) {
+	if (chip->bdbars.area) {
 		if (chip->fix_nocache)
-			fill_nocache(chip->bdbars, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, 0);
-		snd_free_pci_pages(chip->pci, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, chip->bdbars, chip->bdbars_addr);
+			fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 0);
+		snd_dma_free_pages(&chip->dma_dev, &chip->bdbars);
 	}
 	if (chip->remap_addr)
 		iounmap((void *) chip->remap_addr);
@@ -2509,23 +2532,27 @@ static int __devinit snd_intel8x0_create
 	/* SIS7012 handles the pcm data in bytes, others are in words */
 	chip->pcm_pos_shift = (device_type == DEVICE_SIS) ? 0 : 1;
 
+	memset(&chip->dma_dev, 0, sizeof(chip->dma_dev));
+	chip->dma_dev.type = SNDRV_DMA_TYPE_DEV;
+	chip->dma_dev.dev = snd_dma_pci_data(pci);
+
 	/* allocate buffer descriptor lists */
 	/* the start of each lists must be aligned to 8 bytes */
-	chip->bdbars = (u32 *)snd_malloc_pci_pages(pci, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, &chip->bdbars_addr);
-	if (chip->bdbars == NULL) {
+	if (snd_dma_alloc_pages(&chip->dma_dev, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, &chip->bdbars) < 0) {
 		snd_intel8x0_free(chip);
+		snd_printk(KERN_ERR "intel8x0: cannot allocate buffer descriptors\n");
 		return -ENOMEM;
 	}
 	/* tables must be aligned to 8 bytes here, but the kernel pages
 	   are much bigger, so we don't care (on i386) */
 	/* workaround for 440MX */
 	if (chip->fix_nocache)
-		fill_nocache(chip->bdbars, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, 1);
+		fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1);
 	int_sta_masks = 0;
 	for (i = 0; i < chip->bdbars_count; i++) {
 		ichdev = &chip->ichd[i];
-		ichdev->bdbar = chip->bdbars + (i * ICH_MAX_FRAGS * 2);
-		ichdev->bdbar_addr = chip->bdbars_addr + (i * sizeof(u32) * ICH_MAX_FRAGS * 2);
+		ichdev->bdbar = ((u32 *)chip->bdbars.area) + (i * ICH_MAX_FRAGS * 2);
+		ichdev->bdbar_addr = chip->bdbars.addr + (i * sizeof(u32) * ICH_MAX_FRAGS * 2);
 		int_sta_masks |= ichdev->int_sta_mask;
 	}
 	chip->int_sta_reg = device_type == DEVICE_ALI ? ICH_REG_ALI_INTERRUPTSR : ICH_REG_GLOB_STA;
@@ -2567,6 +2594,7 @@ static struct shortname_table {
 	{ PCI_DEVICE_ID_NVIDIA_MCP_AUDIO, "NVidia nForce" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO, "NVidia nForce2" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO, "NVidia nForce3" },
+	{ PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO, "NVidia CK8S" },
 	{ 0x746d, "AMD AMD8111" },
 	{ 0x7445, "AMD AMD768" },
 	{ 0x5455, "ALi M5455" },
--- diff/sound/pci/korg1212/korg1212.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/korg1212/korg1212.c	2004-03-09 11:51:52.000000000 +0000
@@ -347,9 +347,14 @@ struct _snd_korg1212 {
 	struct resource *res_ioport;
 	struct resource *res_iomem2;
 
+	struct snd_dma_device dma_dev;
+
+	struct snd_dma_buffer dma_dsp;
+        struct snd_dma_buffer dma_play;
+        struct snd_dma_buffer dma_rec;
+	struct snd_dma_buffer dma_shared;
+
         u32 dspCodeSize;
-        u32 dspMemPhy;          // DSP memory block handle (Physical Address)
-        void * dspMemPtr;       //            block memory (Virtual Address)
 
 	u32 DataBufsSize;
 
@@ -357,6 +362,7 @@ struct _snd_korg1212 {
         KorgAudioBuffer  * recordDataBufsPtr;
 
 	KorgSharedBuffer * sharedBufferPtr;
+
 	u32 RecDataPhy;
 	u32 PlayDataPhy;
 	unsigned long sharedBufferPhy;
@@ -1238,10 +1244,10 @@ static int snd_korg1212_downloadDSPCode(
 
         snd_korg1212_setCardState(korg1212, K1212_STATE_DSP_IN_PROCESS);
 
-        memcpy(korg1212->dspMemPtr, dspCode, korg1212->dspCodeSize);
+        memcpy(korg1212->dma_dsp.area, dspCode, korg1212->dspCodeSize);
 
         rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_StartDSPDownload,
-                                     UpperWordSwap(korg1212->dspMemPhy),
+                                     UpperWordSwap(korg1212->dma_dsp.addr),
                                      0, 0, 0);
 
 #if K1212_DEBUG_LEVEL > 0
@@ -2134,12 +2140,9 @@ snd_korg1212_free(korg1212_t *korg1212)
         // ----------------------------------------------------
         // free up memory resources used for the DSP download.
         // ----------------------------------------------------
-        if (korg1212->dspMemPtr) {
-                snd_free_pci_pages(korg1212->pci, korg1212->dspCodeSize,
-                                   korg1212->dspMemPtr, (dma_addr_t)korg1212->dspMemPhy);
-                korg1212->dspMemPhy = 0;
-                korg1212->dspMemPtr = 0;
-                korg1212->dspCodeSize = 0;
+        if (korg1212->dma_dsp.area) {
+        	snd_dma_free_pages(&korg1212->dma_dev, &korg1212->dma_dsp);
+        	korg1212->dma_dsp.area = NULL;
         }
 
 #ifndef K1212_LARGEALLOC
@@ -2147,18 +2150,14 @@ snd_korg1212_free(korg1212_t *korg1212)
         // ------------------------------------------------------
         // free up memory resources used for the Play/Rec Buffers
         // ------------------------------------------------------
-	if (korg1212->playDataBufsPtr) {
-                snd_free_pci_pages(korg1212->pci, korg1212->DataBufsSize,
-                                   korg1212->playDataBufsPtr, (dma_addr_t)korg1212->PlayDataPhy);
-		korg1212->PlayDataPhy = 0;
-		korg1212->playDataBufsPtr = NULL;
+	if (korg1212->dma_play.area) {
+		snd_dma_free_pages(&korg1212->dma_dev, &korg1212->dma_play);
+		korg1212->dma_play.area = NULL;
         }
 
-	if (korg1212->recordDataBufsPtr) {
-                snd_free_pci_pages(korg1212->pci, korg1212->DataBufsSize,
-                                   korg1212->recordDataBufsPtr, (dma_addr_t)korg1212->RecDataPhy);
-		korg1212->RecDataPhy = 0;
-		korg1212->recordDataBufsPtr = NULL;
+	if (korg1212->dma_rec.area) {
+		snd_dma_free_pages(&korg1212->dma_dev, &korg1212->dma_rec);
+		korg1212->dma_rec.area = NULL;
         }
 
 #endif
@@ -2166,11 +2165,9 @@ snd_korg1212_free(korg1212_t *korg1212)
         // ----------------------------------------------------
         // free up memory resources used for the Shared Buffers
         // ----------------------------------------------------
-	if (korg1212->sharedBufferPtr) {
-                snd_free_pci_pages(korg1212->pci, (u32) sizeof(KorgSharedBuffer),
-                                   korg1212->sharedBufferPtr, (dma_addr_t)korg1212->sharedBufferPhy);
-		korg1212->sharedBufferPhy = 0;
-		korg1212->sharedBufferPtr = NULL;
+	if (korg1212->dma_shared.area) {
+		snd_dma_free_pages(&korg1212->dma_dev, &korg1212->dma_shared);
+		korg1212->dma_shared.area = NULL;
         }
         
         snd_magic_kfree(korg1212);
@@ -2193,7 +2190,6 @@ static int __devinit snd_korg1212_create
         int err;
         unsigned int i;
 	unsigned ioport_size, iomem_size, iomem2_size;
-	dma_addr_t phys_addr;
         korg1212_t * korg1212;
 
         static snd_device_ops_t ops = {
@@ -2332,13 +2328,16 @@ static int __devinit snd_korg1212_create
 		   stateName[korg1212->cardState]);
 #endif
 
-	korg1212->sharedBufferPtr = (KorgSharedBuffer *) snd_malloc_pci_pages(korg1212->pci, sizeof(KorgSharedBuffer), &phys_addr);
-	korg1212->sharedBufferPhy = (unsigned long)phys_addr;
+	memset(&korg1212->dma_dev, 0, sizeof(korg1212->dma_dev));
+	korg1212->dma_dev.type = SNDRV_DMA_TYPE_DEV;
+	korg1212->dma_dev.dev = snd_dma_pci_data(korg1212->pci);
 
-        if (korg1212->sharedBufferPtr == NULL) {
+	if (snd_dma_alloc_pages(&korg1212->dma_dev, sizeof(KorgSharedBuffer), &korg1212->dma_shared) < 0) {
 		snd_printk(KERN_ERR "can not allocate shared buffer memory (%Zd bytes)\n", sizeof(KorgSharedBuffer));
                 return -ENOMEM;
         }
+        korg1212->sharedBufferPtr = (KorgSharedBuffer *)korg1212->dma_shared.area;
+        korg1212->sharedBufferPhy = korg1212->dma_shared.addr;
 
 #if K1212_DEBUG_LEVEL > 0
         K1212_DEBUG_PRINTK("K1212_DEBUG: Shared Buffer Area = 0x%p (0x%08lx), %d bytes\n", korg1212->sharedBufferPtr, korg1212->sharedBufferPhy, sizeof(KorgSharedBuffer));
@@ -2348,30 +2347,28 @@ static int __devinit snd_korg1212_create
 
         korg1212->DataBufsSize = sizeof(KorgAudioBuffer) * kNumBuffers;
 
-	korg1212->playDataBufsPtr = (KorgAudioBuffer *) snd_malloc_pci_pages(korg1212->pci, korg1212->DataBufsSize, &phys_addr);
-	korg1212->PlayDataPhy = (u32)phys_addr;
-
-        if (korg1212->playDataBufsPtr == NULL) {
+	if (snd_dma_alloc_pages(&korg1212->dma_dev, korg1212->DataBufsSize, &korg1212->dma_play) < 0) {
 		snd_printk(KERN_ERR "can not allocate play data buffer memory (%d bytes)\n", korg1212->DataBufsSize);
                 return -ENOMEM;
         }
+	korg1212->playDataBufsPtr = (KorgAudioBuffer *)korg1212->dma_play.area;
+	korg1212->PlayDataPhy = korg1212->dma_play.addr;
 
 #if K1212_DEBUG_LEVEL > 0
         K1212_DEBUG_PRINTK("K1212_DEBUG: Play Data Area = 0x%p (0x%08x), %d bytes\n",
 		korg1212->playDataBufsPtr, korg1212->PlayDataPhy, korg1212->DataBufsSize);
 #endif
 
-	korg1212->recordDataBufsPtr = (KorgAudioBuffer *) snd_malloc_pci_pages(korg1212->pci, korg1212->DataBufsSize, &phys_addr);
-	korg1212->RecDataPhy = (u32)phys_addr;
-
-        if (korg1212->recordDataBufsPtr == NULL) {
+	if (snd_dma_alloc_pages(&korg1212->dma_dev, korg1212->DataBufsSize, &korg1212->dma_rec) < 0) {
 		snd_printk(KERN_ERR "can not allocate record data buffer memory (%d bytes)\n", korg1212->DataBufsSize);
                 return -ENOMEM;
         }
+        korg1212->recordDataBufsPtr = (KorgAudioBuffer *)korg1212->dma_rec.area;
+        korg1212->RecDataPhy = korg1212->dma_rec.addr;
 
 #if K1212_DEBUG_LEVEL > 0
         K1212_DEBUG_PRINTK("K1212_DEBUG: Record Data Area = 0x%p (0x%08x), %d bytes\n",
-		korg1212->recordDataBufsPtr, korg1212->RecDataPhy, korg1212->DataBufsSize);
+		korg1212->recordDataBufsPtr, korg1212->RecDataBufsPhy, korg1212->DataBufsSize);
 #endif
 
 #else // K1212_LARGEALLOC
@@ -2392,17 +2389,14 @@ static int __devinit snd_korg1212_create
         korg1212->AdatTimeCodePhy = korg1212->sharedBufferPhy +
 		offsetof(KorgSharedBuffer, AdatTimeCode);
 
-        korg1212->dspMemPtr = snd_malloc_pci_pages(korg1212->pci, korg1212->dspCodeSize, &phys_addr);
-	korg1212->dspMemPhy = (u32)phys_addr;
-
-        if (korg1212->dspMemPtr == NULL) {
+	if (snd_dma_alloc_pages(&korg1212->dma_dev, korg1212->dspCodeSize, &korg1212->dma_dsp) < 0) {
 		snd_printk(KERN_ERR "can not allocate dsp code memory (%d bytes)\n", korg1212->dspCodeSize);
                 return -ENOMEM;
         }
 
 #if K1212_DEBUG_LEVEL > 0
         K1212_DEBUG_PRINTK("K1212_DEBUG: DSP Code area = 0x%p (0x%08x) %d bytes [%s]\n",
-		   korg1212->dspMemPtr, korg1212->dspMemPhy, korg1212->dspCodeSize,
+		   korg1212->dma_dsp.area, korg1212->dma_dsp.addr, korg1212->dspCodeSize,
 		   stateName[korg1212->cardState]);
 #endif
 
@@ -2425,7 +2419,7 @@ static int __devinit snd_korg1212_create
                "VolumeTablePhy  = %08x L[%08x]\n"
                "RoutingTablePhy = %08x L[%08x]\n"
                "AdatTimeCodePhy = %08x L[%08x]\n",
-	       korg1212->dspMemPhy,       UpperWordSwap(korg1212->dspMemPhy),
+	       korg1212->dma_dsp.addr,    UpperWordSwap(korg1212->dma_dsp.addr),
                korg1212->PlayDataPhy,     LowerWordSwap(korg1212->PlayDataPhy),
                korg1212->RecDataPhy,      LowerWordSwap(korg1212->RecDataPhy),
                korg1212->VolumeTablePhy,  LowerWordSwap(korg1212->VolumeTablePhy),
--- diff/sound/pci/maestro3.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/maestro3.c	2004-03-09 11:51:52.000000000 +0000
@@ -1816,7 +1816,8 @@ snd_m3_pcm(m3_t * chip, int device)
 	strcpy(pcm->name, chip->card->driver);
 	chip->pcm = pcm;
 	
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 64*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(chip->pci), 64*1024, 64*1024);
 
 	return 0;
 }
--- diff/sound/pci/rme32.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/rme32.c	2004-03-09 11:51:52.000000000 +0000
@@ -1378,9 +1378,10 @@ static int __devinit snd_rme32_create(rm
 	rme32->spdif_pcm->info_flags = 0;
 
 	snd_pcm_lib_preallocate_pages_for_all(rme32->spdif_pcm,
+					      SNDRV_DMA_TYPE_CONTINUOUS,
+					      snd_dma_continuous_data(GFP_KERNEL),
 					      RME32_BUFFER_SIZE,
-					      RME32_BUFFER_SIZE,
-					      GFP_KERNEL);
+					      RME32_BUFFER_SIZE);
 
 	/* set up ALSA pcm device for ADAT */
 	if ((pci->device == PCI_DEVICE_ID_DIGI32) ||
@@ -1405,9 +1406,10 @@ static int __devinit snd_rme32_create(rm
 		rme32->adat_pcm->info_flags = 0;
 
 		snd_pcm_lib_preallocate_pages_for_all(rme32->adat_pcm, 
+						      SNDRV_DMA_TYPE_CONTINUOUS,
+						      snd_dma_continuous_data(GFP_KERNEL),
 						      RME32_BUFFER_SIZE, 
-						      RME32_BUFFER_SIZE, 
-						      GFP_KERNEL);
+						      RME32_BUFFER_SIZE);
 	}
 
 
--- diff/sound/pci/rme96.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/rme96.c	2004-03-09 11:51:52.000000000 +0000
@@ -1718,7 +1718,11 @@ snd_rme96_create(rme96_t *rme96)
 
 	rme96->spdif_pcm->info_flags = 0;
 
-	snd_pcm_lib_preallocate_pages_for_all(rme96->spdif_pcm, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE, GFP_KERNEL);
+	snd_pcm_lib_preallocate_pages_for_all(rme96->spdif_pcm,
+					      SNDRV_DMA_TYPE_CONTINUOUS,
+					      snd_dma_continuous_data(GFP_KERNEL),
+					      RME96_BUFFER_SIZE,
+					      RME96_BUFFER_SIZE);
 
 	/* set up ALSA pcm device for ADAT */
 	if (pci->device == PCI_DEVICE_ID_DIGI96) {
@@ -1738,7 +1742,11 @@ snd_rme96_create(rme96_t *rme96)
 		
 		rme96->adat_pcm->info_flags = 0;
 
-		snd_pcm_lib_preallocate_pages_for_all(rme96->adat_pcm, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE, GFP_KERNEL);
+		snd_pcm_lib_preallocate_pages_for_all(rme96->adat_pcm,
+						      SNDRV_DMA_TYPE_CONTINUOUS,
+						      snd_dma_continuous_data(GFP_KERNEL),
+						      RME96_BUFFER_SIZE,
+						      RME96_BUFFER_SIZE);
 	}
 
 	rme96->playback_periodsize = 0;
--- diff/sound/pci/rme9652/hdsp.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/rme9652/hdsp.c	2004-03-09 11:51:52.000000000 +0000
@@ -568,7 +568,10 @@ static void *snd_hammerfall_get_buffer(s
 	struct snd_dma_device pdev;
 	struct snd_dma_buffer dmbuf;
 
-	snd_dma_device_pci(&pdev, pci, capture);
+	memset(&pdev, 0, sizeof(pdev));
+	pdev.type = SNDRV_DMA_TYPE_DEV;
+	pdev.dev = snd_dma_pci_data(pci);
+	pdev.id = capture;
 	dmbuf.bytes = 0;
 	if (! snd_dma_get_reserved(&pdev, &dmbuf)) {
 		if (snd_dma_alloc_pages(&pdev, size, &dmbuf) < 0)
@@ -581,9 +584,13 @@ static void *snd_hammerfall_get_buffer(s
 
 static void snd_hammerfall_free_buffer(struct pci_dev *pci, size_t size, void *ptr, dma_addr_t addr, int capture)
 {
-	struct snd_dma_device dev;
-	snd_dma_device_pci(&dev, pci, capture);
-	snd_dma_free_reserved(&dev);
+	struct snd_dma_device pdev;
+
+	memset(&pdev, 0, sizeof(pdev));
+	pdev.type = SNDRV_DMA_TYPE_DEV;
+	pdev.dev = snd_dma_pci_data(pci);
+	pdev.id = capture;
+	snd_dma_free_reserved(&pdev);
 }
 
 #else
@@ -3810,7 +3817,7 @@ static char *hdsp_channel_buffer_locatio
 {
 	int mapped_channel;
 
-        snd_assert(channel >= 0 || channel < hdsp->max_channels, return NULL);
+        snd_assert(channel >= 0 && channel < hdsp->max_channels, return NULL);
         
 	if ((mapped_channel = hdsp->channel_map[channel]) < 0) {
 		return NULL;
@@ -3833,7 +3840,8 @@ static int snd_hdsp_playback_copy(snd_pc
 
 	channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
 	snd_assert(channel_buf != NULL, return -EIO);
-	copy_from_user(channel_buf + pos * 4, src, count * 4);
+	if (copy_from_user(channel_buf + pos * 4, src, count * 4))
+		return -EFAULT;
 	return count;
 }
 
@@ -3847,7 +3855,8 @@ static int snd_hdsp_capture_copy(snd_pcm
 
 	channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
 	snd_assert(channel_buf != NULL, return -EIO);
-	copy_to_user(dst, channel_buf + pos * 4, count * 4);
+	if (copy_to_user(dst, channel_buf + pos * 4, count * 4))
+		return -EFAULT;
 	return count;
 }
 
--- diff/sound/pci/rme9652/rme9652.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/rme9652/rme9652.c	2004-03-09 11:51:52.000000000 +0000
@@ -314,7 +314,10 @@ static void *snd_hammerfall_get_buffer(s
 	struct snd_dma_device pdev;
 	struct snd_dma_buffer dmbuf;
 
-	snd_dma_device_pci(&pdev, pci, capture);
+	memset(&pdev, 0, sizeof(pdev));
+	pdev.type = SNDRV_DMA_TYPE_DEV;
+	pdev.dev = snd_dma_pci_data(pci);
+	pdev.id = capture;
 	dmbuf.bytes = 0;
 	if (! snd_dma_get_reserved(&pdev, &dmbuf)) {
 		if (snd_dma_alloc_pages(&pdev, size, &dmbuf) < 0)
@@ -327,9 +330,13 @@ static void *snd_hammerfall_get_buffer(s
 
 static void snd_hammerfall_free_buffer(struct pci_dev *pci, size_t size, void *ptr, dma_addr_t addr, int capture)
 {
-	struct snd_dma_device dev;
-	snd_dma_device_pci(&dev, pci, capture);
-	snd_dma_free_reserved(&dev);
+	struct snd_dma_device pdev;
+
+	memset(&pdev, 0, sizeof(pdev));
+	pdev.type = SNDRV_DMA_TYPE_DEV;
+	pdev.dev = snd_dma_pci_data(pci);
+	pdev.id = capture;
+	snd_dma_free_reserved(&pdev);
 }
 
 #else
--- diff/sound/pci/sonicvibes.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/sonicvibes.c	2004-03-09 11:51:52.000000000 +0000
@@ -886,7 +886,8 @@ static int __devinit snd_sonicvibes_pcm(
 	strcpy(pcm->name, "S3 SonicVibes");
 	sonic->pcm = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(sonic->pci, pcm, 64*1024, 128*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(sonic->pci), 64*1024, 128*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
--- diff/sound/pci/trident/trident_main.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/trident/trident_main.c	2004-03-09 11:51:52.000000000 +0000
@@ -1009,8 +1009,6 @@ static int snd_trident_capture_prepare(s
 	snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
 	unsigned int val, ESO_bytes;
 
-	snd_assert(substream->dma_device.type == SNDRV_DMA_TYPE_PCI, return -EIO);
-
 	spin_lock(&trident->reg_lock);
 
 	// Initilize the channel and set channel Mode
@@ -2189,10 +2187,15 @@ int __devinit snd_trident_pcm(trident_t 
 	if (trident->tlb.entries) {
 		snd_pcm_substream_t *substream;
 		for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next)
-			snd_pcm_lib_preallocate_sg_pages(trident->pci, substream, 64*1024, 128*1024);
-		snd_pcm_lib_preallocate_pci_pages(trident->pci, pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, 64*1024, 128*1024);
+			snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG,
+						      snd_dma_pci_data(trident->pci),
+						      64*1024, 128*1024);
+		snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
+					      SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci),
+					      64*1024, 128*1024);
 	} else {
-		snd_pcm_lib_preallocate_pci_pages_for_all(trident->pci, pcm, 64*1024, 128*1024);
+		snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+						      snd_dma_pci_data(trident->pci), 64*1024, 128*1024);
 	}
 
 	if (rpcm)
@@ -2246,9 +2249,11 @@ int __devinit snd_trident_foldback_pcm(t
 	trident->foldback = foldback;
 
 	if (trident->tlb.entries)
-		snd_pcm_lib_preallocate_sg_pages_for_all(trident->pci, foldback, 0, 128*1024);
+		snd_pcm_lib_preallocate_pages_for_all(foldback, SNDRV_DMA_TYPE_DEV_SG,
+						      snd_dma_pci_data(trident->pci), 0, 128*1024);
 	else
-		snd_pcm_lib_preallocate_pci_pages_for_all(trident->pci, foldback, 64*1024, 128*1024);
+		snd_pcm_lib_preallocate_pages_for_all(foldback, SNDRV_DMA_TYPE_DEV,
+						      snd_dma_pci_data(trident->pci), 64*1024, 128*1024);
 
 	if (rpcm)
 		*rpcm = foldback;
@@ -2287,7 +2292,7 @@ int __devinit snd_trident_spdif_pcm(trid
 	strcpy(spdif->name, "Trident 4DWave IEC958");
 	trident->spdif = spdif;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(trident->pci, spdif, 64*1024, 128*1024);
+	snd_pcm_lib_preallocate_pages_for_all(spdif, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), 64*1024, 128*1024);
 
 	if (rpcm)
 		*rpcm = spdif;
@@ -3052,29 +3057,49 @@ static int __devinit snd_trident_mixer(t
 	}
 	if (trident->device == TRIDENT_DEVICE_ID_NX || trident->device == TRIDENT_DEVICE_ID_SI7018) {
 
-		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_spdif_control, trident))) < 0)
+		kctl = snd_ctl_new1(&snd_trident_spdif_control, trident);
+		if (kctl == NULL) {
+			err = -ENOMEM;
 			goto __out;
+		}
 		if (trident->ac97->ext_id & AC97_EI_SPDIF)
 			kctl->id.index++;
 		if (trident->ac97_sec && (trident->ac97_sec->ext_id & AC97_EI_SPDIF))
 			kctl->id.index++;
 		idx = kctl->id.index;
+		if ((err = snd_ctl_add(card, kctl)) < 0)
+			goto __out;
 		kctl->put(kctl, uctl);
 
-		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_spdif_default, trident))) < 0)
+		kctl = snd_ctl_new1(&snd_trident_spdif_default, trident);
+		if (kctl == NULL) {
+			err = -ENOMEM;
 			goto __out;
+		}
 		kctl->id.index = idx;
 		kctl->id.device = pcm_spdif_device;
+		if ((err = snd_ctl_add(card, kctl)) < 0)
+			goto __out;
 
-		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_spdif_mask, trident))) < 0)
+		kctl = snd_ctl_new1(&snd_trident_spdif_mask, trident);
+		if (kctl == NULL) {
+			err = -ENOMEM;
 			goto __out;
+		}
 		kctl->id.index = idx;
 		kctl->id.device = pcm_spdif_device;
+		if ((err = snd_ctl_add(card, kctl)) < 0)
+			goto __out;
 
-		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_spdif_stream, trident))) < 0)
+		kctl = snd_ctl_new1(&snd_trident_spdif_stream, trident);
+		if (kctl == NULL) {
+			err = -ENOMEM;
 			goto __out;
+		}
 		kctl->id.index = idx;
 		kctl->id.device = pcm_spdif_device;
+		if ((err = snd_ctl_add(card, kctl)) < 0)
+			goto __out;
 		trident->spdif_pcm_ctl = kctl;
 	}
 
@@ -3328,13 +3353,12 @@ static int __devinit snd_trident_tlb_all
 	/* TLB array must be aligned to 16kB !!! so we allocate
 	   32kB region and correct offset when necessary */
 
-	trident->tlb.buffer = snd_malloc_pci_pages(trident->pci, 2 * SNDRV_TRIDENT_MAX_PAGES * 4, &trident->tlb.buffer_dmaaddr);
-	if (trident->tlb.buffer == NULL) {
+	if (snd_dma_alloc_pages(&trident->dma_dev, 2 * SNDRV_TRIDENT_MAX_PAGES * 4, &trident->tlb.buffer) < 0) {
 		snd_printk(KERN_ERR "trident: unable to allocate TLB buffer\n");
 		return -ENOMEM;
 	}
-	trident->tlb.entries = (unsigned int*)(((unsigned long)trident->tlb.buffer + SNDRV_TRIDENT_MAX_PAGES * 4 - 1) & ~(SNDRV_TRIDENT_MAX_PAGES * 4 - 1));
-	trident->tlb.entries_dmaaddr = (trident->tlb.buffer_dmaaddr + SNDRV_TRIDENT_MAX_PAGES * 4 - 1) & ~(SNDRV_TRIDENT_MAX_PAGES * 4 - 1);
+	trident->tlb.entries = (unsigned int*)(((unsigned long)trident->tlb.buffer.area + SNDRV_TRIDENT_MAX_PAGES * 4 - 1) & ~(SNDRV_TRIDENT_MAX_PAGES * 4 - 1));
+	trident->tlb.entries_dmaaddr = (trident->tlb.buffer.addr + SNDRV_TRIDENT_MAX_PAGES * 4 - 1) & ~(SNDRV_TRIDENT_MAX_PAGES * 4 - 1);
 	/* allocate shadow TLB page table (virtual addresses) */
 	trident->tlb.shadow_entries = (unsigned long *)vmalloc(SNDRV_TRIDENT_MAX_PAGES*sizeof(unsigned long));
 	if (trident->tlb.shadow_entries == NULL) {
@@ -3342,15 +3366,14 @@ static int __devinit snd_trident_tlb_all
 		return -ENOMEM;
 	}
 	/* allocate and setup silent page and initialise TLB entries */
-	trident->tlb.silent_page = snd_malloc_pci_pages(trident->pci, SNDRV_TRIDENT_PAGE_SIZE, &trident->tlb.silent_page_dmaaddr);
-	if (trident->tlb.silent_page == 0UL) {
+	if (snd_dma_alloc_pages(&trident->dma_dev, SNDRV_TRIDENT_PAGE_SIZE, &trident->tlb.silent_page) < 0) {
 		snd_printk(KERN_ERR "trident: unable to allocate silent page\n");
 		return -ENOMEM;
 	}
-	memset(trident->tlb.silent_page, 0, SNDRV_TRIDENT_PAGE_SIZE);
+	memset(trident->tlb.silent_page.area, 0, SNDRV_TRIDENT_PAGE_SIZE);
 	for (i = 0; i < SNDRV_TRIDENT_MAX_PAGES; i++) {
-		trident->tlb.entries[i] = cpu_to_le32(trident->tlb.silent_page_dmaaddr & ~(SNDRV_TRIDENT_PAGE_SIZE-1));
-		trident->tlb.shadow_entries[i] = (unsigned long)trident->tlb.silent_page;
+		trident->tlb.entries[i] = cpu_to_le32(trident->tlb.silent_page.addr & ~(SNDRV_TRIDENT_PAGE_SIZE-1));
+		trident->tlb.shadow_entries[i] = (unsigned long)trident->tlb.silent_page.area;
 	}
 
 	/* use emu memory block manager code to manage tlb page allocation */
@@ -3565,9 +3588,13 @@ int __devinit snd_trident_create(snd_car
 	}
 	trident->irq = pci->irq;
 
+	memset(&trident->dma_dev, 0, sizeof(trident->dma_dev));
+	trident->dma_dev.type = SNDRV_DMA_TYPE_DEV;
+	trident->dma_dev.dev = snd_dma_pci_data(pci);
+
 	/* allocate 16k-aligned TLB for NX cards */
 	trident->tlb.entries = NULL;
-	trident->tlb.buffer = NULL;
+	trident->tlb.buffer.area = NULL;
 	if (trident->device == TRIDENT_DEVICE_ID_NX) {
 		if ((err = snd_trident_tlb_alloc(trident)) < 0) {
 			snd_trident_free(trident);
@@ -3661,15 +3688,15 @@ int snd_trident_free(trident_t *trident)
 	else if (trident->device == TRIDENT_DEVICE_ID_SI7018) {
 		outl(0, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
 	}
-	if (trident->tlb.buffer) {
+	if (trident->tlb.buffer.area) {
 		outl(0, TRID_REG(trident, NX_TLBC));
 		if (trident->tlb.memhdr)
 			snd_util_memhdr_free(trident->tlb.memhdr);
-		if (trident->tlb.silent_page)
-			snd_free_pci_pages(trident->pci, SNDRV_TRIDENT_PAGE_SIZE, trident->tlb.silent_page, trident->tlb.silent_page_dmaaddr);
+		if (trident->tlb.silent_page.area)
+			snd_dma_free_pages(&trident->dma_dev, &trident->tlb.silent_page);
 		if (trident->tlb.shadow_entries)
 			vfree(trident->tlb.shadow_entries);
-		snd_free_pci_pages(trident->pci, 2 * SNDRV_TRIDENT_MAX_PAGES * 4, trident->tlb.buffer, trident->tlb.buffer_dmaaddr);
+		snd_dma_free_pages(&trident->dma_dev, &trident->tlb.buffer);
 	}
 	if (trident->irq >= 0)
 		free_irq(trident->irq, (void *)trident);
--- diff/sound/pci/trident/trident_memory.c	2003-05-21 11:49:56.000000000 +0100
+++ source/sound/pci/trident/trident_memory.c	2004-03-09 11:51:52.000000000 +0000
@@ -47,7 +47,7 @@
 /* fill TLB entrie(s) corresponding to page with ptr */
 #define set_tlb_bus(trident,page,ptr,addr) __set_tlb_bus(trident,page,ptr,addr)
 /* fill TLB entrie(s) corresponding to page with silence pointer */
-#define set_silent_tlb(trident,page)	__set_tlb_bus(trident, page, (unsigned long)trident->tlb.silent_page, trident->tlb.silent_page_dmaaddr)
+#define set_silent_tlb(trident,page)	__set_tlb_bus(trident, page, (unsigned long)trident->tlb.silent_page.area, trident->tlb.silent_page.addr)
 /* get aligned page from offset address */
 #define get_aligned_page(offset)	((offset) >> 12)
 /* get offset address from aligned page */
@@ -191,7 +191,6 @@ snd_trident_alloc_sg_pages(trident_t *tr
 	int idx, page;
 	struct snd_sg_buf *sgbuf = runtime->dma_private;
 
-	snd_assert(substream->dma_device.type == SNDRV_DMA_TYPE_PCI_SG, return NULL);
 	snd_assert(runtime->dma_bytes > 0 && runtime->dma_bytes <= SNDRV_TRIDENT_MAX_PAGES * SNDRV_TRIDENT_PAGE_SIZE, return NULL);
 	hdr = trident->tlb.memhdr;
 	snd_assert(hdr != NULL, return NULL);
@@ -240,7 +239,6 @@ snd_trident_alloc_cont_pages(trident_t *
 	dma_addr_t addr;
 	unsigned long ptr;
 
-	snd_assert(substream->dma_device.type == SNDRV_DMA_TYPE_PCI, return NULL);
 	snd_assert(runtime->dma_bytes> 0 && runtime->dma_bytes <= SNDRV_TRIDENT_MAX_PAGES * SNDRV_TRIDENT_PAGE_SIZE, return NULL);
 	hdr = trident->tlb.memhdr;
 	snd_assert(hdr != NULL, return NULL);
@@ -276,7 +274,7 @@ snd_trident_alloc_pages(trident_t *tride
 {
 	snd_assert(trident != NULL, return NULL);
 	snd_assert(substream != NULL, return NULL);
-	if (substream->dma_device.type == SNDRV_DMA_TYPE_PCI_SG)
+	if (substream->dma_device.type == SNDRV_DMA_TYPE_DEV_SG)
 		return snd_trident_alloc_sg_pages(trident, substream);
 	else
 		return snd_trident_alloc_cont_pages(trident, substream);
@@ -367,8 +365,13 @@ static void clear_tlb(trident_t *trident
 	void *ptr = page_to_ptr(trident, page);
 	dma_addr_t addr = page_to_addr(trident, page);
 	set_silent_tlb(trident, page);
-	if (ptr)
-		snd_free_pci_pages(trident->pci, ALIGN_PAGE_SIZE, ptr, addr);
+	if (ptr) {
+		struct snd_dma_buffer dmab;
+		dmab.area = ptr;
+		dmab.addr = addr;
+		dmab.bytes = ALIGN_PAGE_SIZE;
+		snd_dma_free_pages(&trident->dma_dev, &dmab);
+	}
 }
 
 /* check new allocation range */
@@ -399,8 +402,7 @@ static void get_single_page_range(snd_ut
 static int synth_alloc_pages(trident_t *hw, snd_util_memblk_t *blk)
 {
 	int page, first_page, last_page;
-	void *ptr;
-	dma_addr_t addr;
+	struct snd_dma_buffer dmab;
 
 	firstpg(blk) = get_aligned_page(blk->offset);
 	lastpg(blk) = get_aligned_page(blk->offset + blk->size - 1);
@@ -410,14 +412,13 @@ static int synth_alloc_pages(trident_t *
 	 * fortunately Trident page size and kernel PAGE_SIZE is identical!
 	 */
 	for (page = first_page; page <= last_page; page++) {
-		ptr = snd_malloc_pci_pages(hw->pci, ALIGN_PAGE_SIZE, &addr);
-		if (ptr == NULL)
+		if (snd_dma_alloc_pages(&hw->dma_dev, ALIGN_PAGE_SIZE, &dmab) < 0)
 			goto __fail;
-		if (! is_valid_page(addr)) {
-			snd_free_pci_pages(hw->pci, ALIGN_PAGE_SIZE, ptr, addr);
+		if (! is_valid_page(dmab.addr)) {
+			snd_dma_free_pages(&hw->dma_dev, &dmab);
 			goto __fail;
 		}
-		set_tlb_bus(hw, page, (unsigned long)ptr, addr);
+		set_tlb_bus(hw, page, (unsigned long)dmab.area, dmab.addr);
 	}
 	return 0;
 
--- diff/sound/pci/trident/trident_synth.c	2003-06-30 10:07:25.000000000 +0100
+++ source/sound/pci/trident/trident_synth.c	2004-03-09 11:51:52.000000000 +0000
@@ -507,7 +507,6 @@ static int snd_trident_simple_put_sample
 					 char *data, long len, int atomic)
 {
 	trident_t *trident = snd_magic_cast(trident_t, private_data, return -ENXIO);
-	unsigned char *block = NULL;
 	int size = instr->size;
 	int shift = 0;
 
@@ -530,7 +529,7 @@ static int snd_trident_simple_put_sample
 
 	if (trident->tlb.entries) {
 		snd_util_memblk_t *memblk;
-		memblk = snd_trident_synth_alloc(trident,size); 
+		memblk = snd_trident_synth_alloc(trident, size); 
 		if (memblk == NULL)
 			return -ENOMEM;
 		if (snd_trident_synth_copy_from_user(trident, memblk, 0, data, size) ) {
@@ -540,17 +539,17 @@ static int snd_trident_simple_put_sample
 		instr->address.ptr = (unsigned char*)memblk;
 		instr->address.memory = memblk->offset;
 	} else {
-		dma_addr_t addr;
-		block = (unsigned char *) snd_malloc_pci_pages(trident->pci, size, &addr);
-		if (block == NULL)
+		struct snd_dma_buffer dmab;
+
+		if (snd_dma_alloc_pages(&trident->dma_dev, size, &dmab) < 0)
 			return -ENOMEM;
 
-		if (copy_from_user(block, data, size)) {
-			snd_free_pci_pages(trident->pci, size, block, addr);
+		if (copy_from_user(dmab.area, data, size)) {
+			snd_dma_free_pages(&trident->dma_dev, &dmab);
 			return -EFAULT;
 		}
-		instr->address.ptr = block;
-		instr->address.memory = addr;
+		instr->address.ptr = dmab.area;
+		instr->address.memory = dmab.addr;
 	}
 
 	trident->synth.current_size += size;
--- diff/sound/pci/via82xx.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/via82xx.c	2004-03-09 11:51:52.000000000 +0000
@@ -337,8 +337,7 @@ struct via_dev {
         snd_pcm_substream_t *substream;
 	int running;
 	unsigned int tbl_entries; /* # descriptors */
-	u32 *table; /* physical address + flag */
-	dma_addr_t table_addr;
+	struct snd_dma_buffer table;
 	struct snd_via_sg_table *idx_table;
 	/* for recovery from the unexpected pointer */
 	unsigned int lastpos;
@@ -347,6 +346,73 @@ struct via_dev {
 };
 
 
+enum { TYPE_CARD_VIA686 = 1, TYPE_CARD_VIA8233 };
+enum { TYPE_VIA686, TYPE_VIA8233, TYPE_VIA8233A };
+
+#define VIA_MAX_DEVS	7	/* 4 playback, 1 multi, 2 capture */
+
+struct via_rate_lock {
+	spinlock_t lock;
+	int rate;
+	int used;
+};
+
+struct _snd_via82xx {
+	int irq;
+
+	unsigned long port;
+	struct resource *res_port;
+	struct resource *mpu_res;
+	int chip_type;
+	unsigned char revision;
+
+	unsigned char old_legacy;
+	unsigned char old_legacy_cfg;
+
+	unsigned char playback_volume[4][2]; /* for VIA8233/C/8235; default = 0 */
+
+	unsigned int intr_mask; /* SGD_SHADOW mask to check interrupts */
+
+	struct pci_dev *pci;
+	snd_card_t *card;
+
+	unsigned int num_devs;
+	unsigned int playback_devno, multi_devno, capture_devno;
+	viadev_t devs[VIA_MAX_DEVS];
+	struct via_rate_lock rates[2]; /* playback and capture */
+	unsigned int dxs_fixed: 1;	/* DXS channel accepts only 48kHz */
+	unsigned int no_vra: 1;		/* no need to set VRA on DXS channels */
+
+	snd_rawmidi_t *rmidi;
+
+	ac97_bus_t *ac97_bus;
+	ac97_t *ac97;
+	unsigned int ac97_clock;
+	unsigned int ac97_secondary;	/* secondary AC'97 codec is present */
+
+	spinlock_t reg_lock;
+	spinlock_t ac97_lock;
+	snd_info_entry_t *proc_entry;
+
+	struct snd_dma_device dma_dev;
+
+#ifdef SUPPORT_JOYSTICK
+	struct gameport gameport;
+	struct resource *res_joystick;
+#endif
+};
+
+static struct pci_device_id snd_via82xx_ids[] = {
+	{ 0x1106, 0x3058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA686, },	/* 686A */
+	{ 0x1106, 0x3059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA8233, },	/* VT8233 */
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, snd_via82xx_ids);
+
+/*
+ */
+
 /*
  * allocate and initialize the descriptor buffers
  * periods = number of periods
@@ -357,14 +423,14 @@ static int build_via_table(viadev_t *dev
 			   unsigned int periods, unsigned int fragsize)
 {
 	unsigned int i, idx, ofs, rest;
+	via82xx_t *chip = snd_pcm_substream_chip(substream);
 	struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
 
-	if (! dev->table) {
+	if (dev->table.area == NULL) {
 		/* the start of each lists must be aligned to 8 bytes,
 		 * but the kernel pages are much bigger, so we don't care
 		 */
-		dev->table = (u32*)snd_malloc_pci_pages(pci, PAGE_ALIGN(VIA_TABLE_SIZE * 2 * 8), &dev->table_addr);
-		if (! dev->table)
+		if (snd_dma_alloc_pages(&chip->dma_dev, PAGE_ALIGN(VIA_TABLE_SIZE * 2 * 8), &dev->table) < 0)
 			return -ENOMEM;
 	}
 	if (! dev->idx_table) {
@@ -390,7 +456,7 @@ static int build_via_table(viadev_t *dev
 				snd_printk(KERN_ERR "via82xx: too much table size!\n");
 				return -EINVAL;
 			}
-			dev->table[idx << 1] = cpu_to_le32((u32)snd_pcm_sgbuf_get_addr(sgbuf, ofs));
+			((u32 *)dev->table.area)[idx << 1] = cpu_to_le32((u32)snd_pcm_sgbuf_get_addr(sgbuf, ofs));
 			r = PAGE_SIZE - (ofs % PAGE_SIZE);
 			if (rest < r)
 				r = rest;
@@ -403,7 +469,7 @@ static int build_via_table(viadev_t *dev
 			} else
 				flag = 0; /* period continues to the next */
 			// printk("via: tbl %d: at %d  size %d (rest %d)\n", idx, ofs, r, rest);
-			dev->table[(idx<<1) + 1] = cpu_to_le32(r | flag);
+			((u32 *)dev->table.area)[(idx<<1) + 1] = cpu_to_le32(r | flag);
 			dev->idx_table[idx].offset = ofs;
 			dev->idx_table[idx].size = r;
 			ofs += r;
@@ -417,85 +483,21 @@ static int build_via_table(viadev_t *dev
 }
 
 
-static void clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
-			    struct pci_dev *pci)
+static int clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
+			   struct pci_dev *pci)
 {
-	if (dev->table) {
-		snd_free_pci_pages(pci, PAGE_ALIGN(VIA_TABLE_SIZE * 2 * 8), dev->table, dev->table_addr);
-		dev->table = NULL;
+	via82xx_t *chip = snd_pcm_substream_chip(substream);
+	if (dev->table.area) {
+		snd_dma_free_pages(&chip->dma_dev, &dev->table);
+		dev->table.area = NULL;
 	}
 	if (dev->idx_table) {
 		kfree(dev->idx_table);
 		dev->idx_table = NULL;
 	}
+	return 0;
 }
 
-
-/*
- */
-
-enum { TYPE_CARD_VIA686 = 1, TYPE_CARD_VIA8233 };
-enum { TYPE_VIA686, TYPE_VIA8233, TYPE_VIA8233A };
-
-#define VIA_MAX_DEVS	7	/* 4 playback, 1 multi, 2 capture */
-
-struct via_rate_lock {
-	spinlock_t lock;
-	int rate;
-	int used;
-};
-
-struct _snd_via82xx {
-	int irq;
-
-	unsigned long port;
-	struct resource *res_port;
-	struct resource *mpu_res;
-	int chip_type;
-	unsigned char revision;
-
-	unsigned char old_legacy;
-	unsigned char old_legacy_cfg;
-
-	unsigned char playback_volume[4][2]; /* for VIA8233/C/8235; default = 0 */
-
-	unsigned int intr_mask; /* SGD_SHADOW mask to check interrupts */
-
-	struct pci_dev *pci;
-	snd_card_t *card;
-
-	unsigned int num_devs;
-	unsigned int playback_devno, multi_devno, capture_devno;
-	viadev_t devs[VIA_MAX_DEVS];
-	struct via_rate_lock rates[2]; /* playback and capture */
-	unsigned int dxs_fixed: 1;	/* DXS channel accepts only 48kHz */
-	unsigned int no_vra: 1;		/* no need to set VRA on DXS channels */
-
-	snd_rawmidi_t *rmidi;
-
-	ac97_bus_t *ac97_bus;
-	ac97_t *ac97;
-	unsigned int ac97_clock;
-	unsigned int ac97_secondary;	/* secondary AC'97 codec is present */
-
-	spinlock_t reg_lock;
-	spinlock_t ac97_lock;
-	snd_info_entry_t *proc_entry;
-
-#ifdef SUPPORT_JOYSTICK
-	struct gameport gameport;
-	struct resource *res_joystick;
-#endif
-};
-
-static struct pci_device_id snd_via82xx_ids[] = {
-	{ 0x1106, 0x3058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA686, },	/* 686A */
-	{ 0x1106, 0x3059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA8233, },	/* VT8233 */
-	{ 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, snd_via82xx_ids);
-
 /*
  *  Basic I/O
  */
@@ -756,10 +758,10 @@ static snd_pcm_uframes_t snd_via686_pcm_
 	 * so we need to calculate the index from CURR_PTR.
 	 */
 	ptr = inl(VIADEV_REG(viadev, OFFSET_CURR_PTR));
-	if (ptr <= (unsigned int)viadev->table_addr)
+	if (ptr <= (unsigned int)viadev->table.addr)
 		idx = 0;
 	else /* CURR_PTR holds the address + 8 */
-		idx = ((ptr - (unsigned int)viadev->table_addr) / 8 - 1) % viadev->tbl_entries;
+		idx = ((ptr - (unsigned int)viadev->table.addr) / 8 - 1) % viadev->tbl_entries;
 	res = calc_linear_pos(viadev, idx, count);
 	spin_unlock(&chip->reg_lock);
 
@@ -840,7 +842,7 @@ static int snd_via82xx_hw_free(snd_pcm_s
 static void snd_via82xx_set_table_ptr(via82xx_t *chip, viadev_t *viadev)
 {
 	snd_via82xx_codec_ready(chip, 0);
-	outl((u32)viadev->table_addr, VIADEV_REG(viadev, OFFSET_TABLE_PTR));
+	outl((u32)viadev->table.addr, VIADEV_REG(viadev, OFFSET_TABLE_PTR));
 	udelay(20);
 	snd_via82xx_codec_ready(chip, 0);
 }
@@ -922,12 +924,10 @@ static int snd_via8233_playback_prepare(
 				  chip->no_vra ? 48000 : runtime->rate);
 		snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate);
 	}
-#if 0
-	if (chip->revision == VIA_REV_8233A)
-		rbits = 0;
+	if (runtime->rate == 48000)
+		rbits = 0xfffff;
 	else
-#endif
-		rbits = (0xfffff / 48000) * runtime->rate + ((0xfffff % 48000) * runtime->rate) / 48000;
+		rbits = (0x100000 / 48000) * runtime->rate + ((0x100000 % 48000) * runtime->rate) / 48000;
 	snd_assert((rbits & ~0xfffff) == 0, return -EINVAL);
 	snd_via82xx_channel_reset(chip, viadev);
 	snd_via82xx_set_table_ptr(chip, viadev);
@@ -1290,7 +1290,8 @@ static int __devinit snd_via8233_pcm_new
 	/* capture */
 	init_viadev(chip, chip->capture_devno, VIA_REG_CAPTURE_8233_STATUS, 1);
 
-	if ((err = snd_pcm_lib_preallocate_sg_pages_for_all(chip->pci, pcm, 64*1024, 128*1024)) < 0)
+	if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+							 snd_dma_pci_data(chip->pci), 64*1024, 128*1024)) < 0)
 		return err;
 
 	/* PCM #1:  multi-channel playback and 2nd capture */
@@ -1306,7 +1307,8 @@ static int __devinit snd_via8233_pcm_new
 	/* set up capture */
 	init_viadev(chip, chip->capture_devno + 1, VIA_REG_CAPTURE_8233_STATUS + 0x10, 1);
 
-	if ((err = snd_pcm_lib_preallocate_sg_pages_for_all(chip->pci, pcm, 64*1024, 128*1024)) < 0)
+	if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+						         snd_dma_pci_data(chip->pci), 64*1024, 128*1024)) < 0)
 		return err;
 
 	return 0;
@@ -1339,7 +1341,8 @@ static int __devinit snd_via8233a_pcm_ne
 	/* capture */
 	init_viadev(chip, chip->capture_devno, VIA_REG_CAPTURE_8233_STATUS, 1);
 
-	if ((err = snd_pcm_lib_preallocate_sg_pages_for_all(chip->pci, pcm, 64*1024, 128*1024)) < 0)
+	if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+							 snd_dma_pci_data(chip->pci), 64*1024, 128*1024)) < 0)
 		return err;
 
 	/* PCM #1:  DXS3 playback (for spdif) */
@@ -1352,7 +1355,8 @@ static int __devinit snd_via8233a_pcm_ne
 	/* set up playback */
 	init_viadev(chip, chip->playback_devno, 0x30, 0);
 
-	if ((err = snd_pcm_lib_preallocate_sg_pages_for_all(chip->pci, pcm, 64*1024, 128*1024)) < 0)
+	if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+							 snd_dma_pci_data(chip->pci), 64*1024, 128*1024)) < 0)
 		return err;
 
 	return 0;
@@ -1381,7 +1385,8 @@ static int __devinit snd_via686_pcm_new(
 	init_viadev(chip, 0, VIA_REG_PLAYBACK_STATUS, 0);
 	init_viadev(chip, 1, VIA_REG_CAPTURE_STATUS, 1);
 
-	if ((err = snd_pcm_lib_preallocate_sg_pages_for_all(chip->pci, pcm, 64*1024, 128*1024)) < 0)
+	if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+							 snd_dma_pci_data(chip->pci), 64*1024, 128*1024)) < 0)
 		return err;
 
 	return 0;
@@ -1560,6 +1565,18 @@ static struct ac97_quirk ac97_quirks[] =
 		.name = "ASRock K7VM2",
 		.type = AC97_TUNE_HP_ONLY	/* VT1616 */
 	},
+	{
+		.vendor = 0x14cd,
+		.device = 0x7002,
+		.name = "Unknown",
+		.type = AC97_TUNE_ALC_JACK
+	},
+	{
+		.vendor = 0x1071,
+		.device = 0x8590,
+		.name = "Mitac Mobo",
+		.type = AC97_TUNE_ALC_JACK
+	},
 	{ } /* terminator */
 };
 
@@ -1913,6 +1930,10 @@ static int __devinit snd_via82xx_create(
 	chip->pci = pci;
 	chip->irq = -1;
 
+	memset(&chip->dma_dev, 0, sizeof(chip->dma_dev));
+	chip->dma_dev.type = SNDRV_DMA_TYPE_DEV;
+	chip->dma_dev.dev = snd_dma_pci_data(pci);
+
 	pci_read_config_byte(pci, VIA_FUNC_ENABLE, &chip->old_legacy);
 	pci_read_config_byte(pci, VIA_PNP_CONTROL, &chip->old_legacy_cfg);
 
@@ -1987,13 +2008,16 @@ static int __devinit check_dxs_list(stru
 		{ .vendor = 0x1043, .device = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ 
 		{ .vendor = 0x10cf, .device = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */
 		{ .vendor = 0x1106, .device = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */
+		{ .vendor = 0x1106, .device = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */
 		{ .vendor = 0x1297, .device = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */
 		{ .vendor = 0x1297, .device = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */
-		{ .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */
+		{ .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_NO_VRA }, /* Gigabyte GA-7VAXP (FIXME: or DXS_ENABLE?) */
 		{ .vendor = 0x147b, .device = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */
 		{ .vendor = 0x14ff, .device = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */
 		{ .vendor = 0x1462, .device = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */
 		{ .vendor = 0x1462, .device = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */
+		{ .vendor = 0x1462, .device = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */
+		{ .vendor = 0x1584, .device = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */
 		{ .vendor = 0x1631, .device = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */
 		{ .vendor = 0x1695, .device = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */
 		{ .vendor = 0x1849, .device = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */
--- diff/sound/pci/ymfpci/ymfpci_main.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pci/ymfpci/ymfpci_main.c	2004-03-09 11:51:52.000000000 +0000
@@ -541,20 +541,15 @@ static void snd_ymfpci_pcm_init_voice(ym
 
 static int __devinit snd_ymfpci_ac3_init(ymfpci_t *chip)
 {
-	unsigned char *ptr;
-	dma_addr_t ptr_addr;
-
-	if ((ptr = snd_malloc_pci_pages(chip->pci, 4096, &ptr_addr)) == NULL)
+	if (snd_dma_alloc_pages(&chip->dma_dev, 4096, &chip->ac3_tmp_base) < 0)
 		return -ENOMEM;
 
-	chip->ac3_tmp_base = ptr;
-	chip->ac3_tmp_base_addr = ptr_addr;
 	chip->bank_effect[3][0]->base =
-	chip->bank_effect[3][1]->base = cpu_to_le32(chip->ac3_tmp_base_addr);
+	chip->bank_effect[3][1]->base = cpu_to_le32(chip->ac3_tmp_base.addr);
 	chip->bank_effect[3][0]->loop_end =
 	chip->bank_effect[3][1]->loop_end = cpu_to_le32(1024);
 	chip->bank_effect[4][0]->base =
-	chip->bank_effect[4][1]->base = cpu_to_le32(chip->ac3_tmp_base_addr + 2048);
+	chip->bank_effect[4][1]->base = cpu_to_le32(chip->ac3_tmp_base.addr + 2048);
 	chip->bank_effect[4][0]->loop_end =
 	chip->bank_effect[4][1]->loop_end = cpu_to_le32(1024);
 
@@ -572,9 +567,9 @@ static int snd_ymfpci_ac3_done(ymfpci_t 
 			  snd_ymfpci_readl(chip, YDSXGR_MAPOFEFFECT) & ~(3 << 3));
 	spin_unlock_irq(&chip->reg_lock);
 	// snd_ymfpci_irq_wait(chip);
-	if (chip->ac3_tmp_base) {
-		snd_free_pci_pages(chip->pci, 4096, chip->ac3_tmp_base, chip->ac3_tmp_base_addr);
-		chip->ac3_tmp_base = NULL;
+	if (chip->ac3_tmp_base.area) {
+		snd_dma_free_pages(&chip->dma_dev, &chip->ac3_tmp_base);
+		chip->ac3_tmp_base.area = NULL;
 	}
 	return 0;
 }
@@ -1104,7 +1099,8 @@ int __devinit snd_ymfpci_pcm(ymfpci_t *c
 	strcpy(pcm->name, "YMFPCI");
 	chip->pcm = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
@@ -1149,7 +1145,8 @@ int __devinit snd_ymfpci_pcm2(ymfpci_t *
 		chip->device_id == PCI_DEVICE_ID_YAMAHA_754 ? "Direct Recording" : "AC'97");
 	chip->pcm2 = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
@@ -1193,7 +1190,8 @@ int __devinit snd_ymfpci_pcm_spdif(ymfpc
 	strcpy(pcm->name, "YMFPCI - IEC958");
 	chip->pcm_spdif = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
@@ -1237,7 +1235,8 @@ int __devinit snd_ymfpci_pcm_4ch(ymfpci_
 	strcpy(pcm->name, "YMFPCI - Rear PCM");
 	chip->pcm_4ch = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
@@ -1976,12 +1975,11 @@ static int __devinit snd_ymfpci_memalloc
 	       chip->work_size;
 	/* work_ptr must be aligned to 256 bytes, but it's already
 	   covered with the kernel page allocation mechanism */
-	if ((ptr = snd_malloc_pci_pages(chip->pci, size, &ptr_addr)) == NULL)
+	if (snd_dma_alloc_pages(&chip->dma_dev, size, &chip->work_ptr) < 0) 
 		return -ENOMEM;
+	ptr = chip->work_ptr.area;
+	ptr_addr = chip->work_ptr.addr;
 	memset(ptr, 0, size);	/* for sure */
-	chip->work_ptr = ptr;
-	chip->work_ptr_addr = ptr_addr;
-	chip->work_ptr_size = size;
 
 	chip->bank_base_playback = ptr;
 	chip->bank_base_playback_addr = ptr_addr;
@@ -2024,7 +2022,7 @@ static int __devinit snd_ymfpci_memalloc
 	chip->work_base = ptr;
 	chip->work_base_addr = ptr_addr;
 	
-	snd_assert(ptr + chip->work_size == chip->work_ptr + chip->work_ptr_size, );
+	snd_assert(ptr + chip->work_size == chip->work_ptr.area + chip->work_ptr.bytes, );
 
 	snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, chip->bank_base_playback_addr);
 	snd_ymfpci_writel(chip, YDSXGR_RECCTRLBASE, chip->bank_base_capture_addr);
@@ -2107,8 +2105,8 @@ static int snd_ymfpci_free(ymfpci_t *chi
 #endif
 	if (chip->reg_area_virt)
 		iounmap((void *)chip->reg_area_virt);
-	if (chip->work_ptr)
-		snd_free_pci_pages(chip->pci, chip->work_ptr_size, chip->work_ptr, chip->work_ptr_addr);
+	if (chip->work_ptr.area)
+		snd_dma_free_pages(&chip->dma_dev, &chip->work_ptr);
 	
 	if (chip->irq >= 0)
 		free_irq(chip->irq, (void *)chip);
@@ -2276,6 +2274,10 @@ int __devinit snd_ymfpci_create(snd_card
 	}
 	chip->irq = pci->irq;
 
+	memset(&chip->dma_dev, 0, sizeof(chip->dma_dev));
+	chip->dma_dev.type = SNDRV_DMA_TYPE_DEV;
+	chip->dma_dev.dev = snd_dma_pci_data(pci);
+
 	snd_ymfpci_aclink_reset(pci);
 	if (snd_ymfpci_codec_ready(chip, 0) < 0) {
 		snd_ymfpci_free(chip);
--- diff/sound/pcmcia/Kconfig	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/pcmcia/Kconfig	2004-03-09 11:51:52.000000000 +0000
@@ -6,13 +6,21 @@ menu "PCMCIA devices"
 config SND_VXPOCKET
 	tristate "Digigram VXpocket"
 	depends on SND && PCMCIA && ISA
+	select SND_VX_LIB
 	help
 	  Say 'Y' or 'M' to include support for Digigram VXpocket soundcard.
 
 config SND_VXP440
 	tristate "Digigram VXpocket 440"
 	depends on SND && PCMCIA && ISA
+	select SND_VX_LIB
 	help
 	  Say 'Y' or 'M' to include support for Digigram VXpocket 440 soundcard.
 
+config SND_PDAUDIOCF
+	tristate "Sound Core PDAudioCF"
+	depends on SND && PCMCIA && ISA
+	help
+	  Say 'Y' or 'M' to include support for Sound Core PDAudioCF soundcard.
+
 endmenu
--- diff/sound/pcmcia/Makefile	2003-06-30 10:07:25.000000000 +0100
+++ source/sound/pcmcia/Makefile	2004-03-09 11:51:52.000000000 +0000
@@ -3,6 +3,4 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
 #
 
-obj-$(CONFIG_SND) += vx/
-
-
+obj-$(CONFIG_SND) += vx/ pdaudiocf/
--- diff/sound/ppc/Kconfig	2002-11-11 11:09:38.000000000 +0000
+++ source/sound/ppc/Kconfig	2004-03-09 11:51:52.000000000 +0000
@@ -6,6 +6,7 @@ menu "ALSA PowerMac devices"
 config SND_POWERMAC
 	tristate "PowerMac (AWACS, DACA, Burgundy, Tumbler, Keywest)"
 	depends on SND
+	select SND_PCM
 
 endmenu
 
--- diff/sound/ppc/pmac.c	2003-09-30 15:46:21.000000000 +0100
+++ source/sound/ppc/pmac.c	2004-03-09 11:51:52.000000000 +0000
@@ -664,7 +664,9 @@ int __init snd_pmac_pcm_new(pmac_t *chip
 	chip->capture.cur_freqs = chip->freqs_ok;
 
 	/* preallocate 64k buffer */
-	snd_pcm_lib_preallocate_pages_for_all(pcm, 64 * 1024, 64 * 1024, GFP_KERNEL);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, 
+					      snd_pcm_dma_flags(GFP_KERNEL),
+					      64 * 1024, 64 * 1024);
 
 	return 0;
 }
--- diff/sound/ppc/tumbler.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/ppc/tumbler.c	2004-03-09 11:51:52.000000000 +0000
@@ -136,7 +136,7 @@ static int snapper_init_client(pmac_keyw
 		/* normal operation, all-pass mode */
 		TAS_REG_MCS2, (1<<1),
 		/* normal output, no deemphasis, A input, power-up */
-		TAS_REG_ACS, 0,
+		TAS_REG_ACS, 2,
 		0, /* terminator */
 	};
 	return send_init_client(i2c, regs);
@@ -929,8 +929,8 @@ static void tumbler_resume(pmac_t *chip)
 		snapper_set_mix_vol(mix, VOL_IDX_PCM);
 		snapper_set_mix_vol(mix, VOL_IDX_PCM2);
 		snapper_set_mix_vol(mix, VOL_IDX_ADC);
-		tumbler_set_mono_volume(mix, &tumbler_bass_vol_info);
-		tumbler_set_mono_volume(mix, &tumbler_treble_vol_info);
+		tumbler_set_mono_volume(mix, &snapper_bass_vol_info);
+		tumbler_set_mono_volume(mix, &snapper_treble_vol_info);
 		snapper_set_drc(mix);
 	}
 	tumbler_set_master_volume(mix);
--- diff/sound/sparc/Kconfig	2002-11-11 11:09:38.000000000 +0000
+++ source/sound/sparc/Kconfig	2004-03-09 11:51:52.000000000 +0000
@@ -6,11 +6,13 @@ menu "ALSA Sparc devices"
 config SND_SUN_AMD7930
 	tristate "Sun AMD7930"
 	depends on SBUS && SND
+	select SND_PCM
 
 #  dep_tristate 'Sun DBRI' CONFIG_SND_SUN_DBRI $CONFIG_SND
 config SND_SUN_CS4231
 	tristate "Sun CS4231"
 	depends on SND
+	select SND_PCM
 
 endmenu
 
--- diff/sound/sparc/amd7930.c	2003-08-26 10:00:55.000000000 +0100
+++ source/sound/sparc/amd7930.c	2004-03-09 11:51:52.000000000 +0000
@@ -791,7 +791,9 @@ static int __init snd_amd7930_pcm(amd793
 	strcpy(pcm->name, amd->card->shortname);
 	amd->pcm = pcm;
 
-	snd_pcm_lib_preallocate_pages_for_all(pcm, 64*1024, 64*1024, GFP_KERNEL);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+					      snd_dma_continuous_data(GFP_KERNEL),
+					      64*1024, 64*1024);
 
 	return 0;
 }
--- diff/sound/sparc/cs4231.c	2003-08-26 10:00:55.000000000 +0100
+++ source/sound/sparc/cs4231.c	2004-03-09 11:51:52.000000000 +0000
@@ -1570,13 +1570,15 @@ int snd_cs4231_pcm(cs4231_t *chip)
 
 #ifdef EBUS_SUPPORT
 	if (chip->flags & CS4231_FLAG_EBUS) {
-		snd_pcm_lib_preallocate_pci_pages_for_all(chip->dev_u.pdev, pcm,
-							  64*1024, 128*1024);
+		snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_PCI,
+						      snd_dma_pci_data(chip->dev_u.pdev)
+						      64*1024, 128*1024);
 	} else {
 #endif
 #ifdef SBUS_SUPPORT
-		snd_pcm_lib_preallocate_sbus_pages_for_all(chip->dev_u.sdev, pcm,
-							   64*1024, 128*1024);
+		snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS,
+						      snd_dma_sbus_data(chip->dev_u.sdev),
+						      64*1024, 128*1024);
 #endif
 #ifdef EBUS_SUPPORT
 	}
--- diff/sound/synth/Makefile	2003-02-13 11:46:57.000000000 +0000
+++ source/sound/synth/Makefile	2004-03-09 11:51:52.000000000 +0000
@@ -5,10 +5,16 @@
 
 snd-util-mem-objs := util_mem.o
 
+#
+# this function returns:
+#   "m" - CONFIG_SND_SEQUENCER is m
+#   <empty string> - CONFIG_SND_SEQUENCER is undefined
+#   otherwise parameter #1 value
+#
+sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
+
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_EMU10K1) += snd-util-mem.o
 obj-$(CONFIG_SND_TRIDENT) += snd-util-mem.o
-ifdef CONFIG_SND_SEQUENCER
-  obj-$(CONFIG_SND_SBAWE) += snd-util-mem.o
-  obj-$(CONFIG_SND) += emux/
-endif
+obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-util-mem.o
+obj-$(call sequencer,$(CONFIG_SND)) += emux/
--- diff/sound/usb/Kconfig	2002-12-30 10:17:14.000000000 +0000
+++ source/sound/usb/Kconfig	2004-03-09 11:51:52.000000000 +0000
@@ -6,6 +6,8 @@ menu "ALSA USB devices"
 config SND_USB_AUDIO
 	tristate "USB Audio/MIDI driver"
 	depends on SND && USB
+	select SND_RAWMIDI
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for USB audio and USB MIDI devices.
 
--- diff/sound/usb/usbaudio.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/usb/usbaudio.c	2004-03-09 11:51:52.000000000 +0000
@@ -45,7 +45,6 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/usb.h>
-#include <linux/usb_ch9.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/pcm.h>
@@ -117,7 +116,7 @@ struct audioformat {
 	struct list_head list;
 	snd_pcm_format_t format;	/* format type */
 	unsigned int channels;		/* # channels */
-	unsigned int nonaudio: 1;	/* non-audio (type II) */
+	unsigned int fmt_type;		/* USB audio format type (1-3) */
 	unsigned int frame_size;	/* samples per frame for non-audio */
 	int iface;			/* interface number */
 	unsigned char altsetting;	/* corresponding alternate setting */
@@ -171,7 +170,7 @@ struct snd_usb_substream {
 	unsigned int curpacksize;	/* current packet size in bytes (for capture) */
 	unsigned int curframesize;	/* current packet size in frames (for capture) */
 	unsigned int fill_max: 1;	/* fill max packet size always */
-	unsigned int nonaudio: 1;	/* Type II format (MPEG, AC3) */
+	unsigned int fmt_type;		/* USB audio format type (1-3) */
 
 	unsigned int running: 1;	/* running status */
 
@@ -201,6 +200,7 @@ struct snd_usb_stream {
 	snd_usb_audio_t *chip;
 	snd_pcm_t *pcm;
 	int pcm_index;
+	unsigned int fmt_type;		/* USB audio format type (1-3) */
 	snd_usb_substream_t substream[2];
 	struct list_head list;
 };
@@ -477,7 +477,7 @@ static int prepare_playback_urb(snd_usb_
 		subs->transfer_sched += counts;
 		if (subs->transfer_sched >= runtime->period_size) {
 			subs->transfer_sched -= runtime->period_size;
-			if (subs->nonaudio) {
+			if (subs->fmt_type == USB_FORMAT_TYPE_II) {
 				if (subs->transfer_sched > 0) {
 					/* FIXME: fill-max mode is not supported yet */
 					offs -= subs->transfer_sched;
@@ -894,7 +894,7 @@ static int init_substream_urbs(snd_usb_s
 		u->subs = subs;
 		u->transfer = 0;
 		u->packets = npacks[i];
-		if (subs->nonaudio)
+		if (subs->fmt_type == USB_FORMAT_TYPE_II)
 			u->packets++; /* for transfer delimiter */
 		if (! is_playback) {
 			/* allocate a capture buffer per urb */
@@ -1129,15 +1129,20 @@ static int set_format(snd_usb_substream_
 	     (! is_playback && attr == EP_ATTR_ADAPTIVE)) &&
 	    altsd->bNumEndpoints >= 2) {
 		/* check sync-pipe endpoint */
-		if (get_endpoint(alts, 1)->bmAttributes != 0x01 ||
-		    get_endpoint(alts, 1)->bSynchAddress != 0) {
+		/* ... and check descriptor size before accessing bSynchAddress
+		   because there is a version of the SB Audigy 2 NX firmware lacking
+		   the audio fields in the endpoint descriptors */
+		if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != 0x01 ||
+		    (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
+		     get_endpoint(alts, 1)->bSynchAddress != 0)) {
 			snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n",
 				   dev->devnum, fmt->iface, fmt->altsetting);
 			return -EINVAL;
 		}
 		ep = get_endpoint(alts, 1)->bEndpointAddress;
-		if ((is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) ||
-		    (! is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN))) {
+		if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
+		    (( is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) ||
+		     (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) {
 			snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n",
 				   dev->devnum, fmt->iface, fmt->altsetting);
 			return -EINVAL;
@@ -1588,7 +1593,7 @@ static int setup_hw_info(snd_pcm_runtime
 			runtime->hw.channels_min = fp->channels;
 		if (runtime->hw.channels_max < fp->channels)
 			runtime->hw.channels_max = fp->channels;
-		if (fp->nonaudio && fp->frame_size > 0) {
+		if (fp->fmt_type == USB_FORMAT_TYPE_II && fp->frame_size > 0) {
 			/* FIXME: there might be more than one audio formats... */
 			runtime->hw.period_bytes_min = runtime->hw.period_bytes_max =
 				fp->frame_size;
@@ -1886,7 +1891,9 @@ static void init_substream(snd_usb_strea
 	subs->dev = as->chip->dev;
 	subs->ops = audio_urb_ops[stream];
 	snd_pcm_lib_preallocate_pages(as->pcm->streams[stream].substream,
-				      64 * 1024, 128 * 1024, GFP_ATOMIC);
+				      SNDRV_DMA_TYPE_CONTINUOUS,
+				      snd_dma_continuous_data(GFP_KERNEL),
+				      64 * 1024, 128 * 1024);
 	snd_pcm_set_ops(as->pcm, stream,
 			stream == SNDRV_PCM_STREAM_PLAYBACK ?
 			&snd_usb_playback_ops : &snd_usb_capture_ops);
@@ -1895,7 +1902,7 @@ static void init_substream(snd_usb_strea
 	subs->formats |= 1ULL << fp->format;
 	subs->endpoint = fp->endpoint;
 	subs->num_formats++;
-	subs->nonaudio = fp->nonaudio;
+	subs->fmt_type = fp->fmt_type;
 }
 
 
@@ -1954,17 +1961,12 @@ static int add_audio_endpoint(snd_usb_au
 
 	list_for_each(p, &chip->pcm_list) {
 		as = list_entry(p, snd_usb_stream_t, list);
+		if (as->fmt_type != fp->fmt_type)
+			continue;
 		subs = &as->substream[stream];
 		if (! subs->endpoint)
-			break;
+			continue;
 		if (subs->endpoint == fp->endpoint) {
-			if (fp->nonaudio) {
-				if (!subs->nonaudio || subs->formats != (1ULL << fp->format))
-					continue; /* non-linear formats are handled exclusively */
-			} else {
-				if (subs->nonaudio)
-					continue;
-			}
 			list_add_tail(&fp->list, &subs->fmt_list);
 			subs->num_formats++;
 			subs->formats |= 1ULL << fp->format;
@@ -1974,6 +1976,8 @@ static int add_audio_endpoint(snd_usb_au
 	/* look for an empty stream */
 	list_for_each(p, &chip->pcm_list) {
 		as = list_entry(p, snd_usb_stream_t, list);
+		if (as->fmt_type != fp->fmt_type)
+			continue;
 		subs = &as->substream[stream];
 		if (subs->endpoint)
 			continue;
@@ -1991,6 +1995,7 @@ static int add_audio_endpoint(snd_usb_au
 	memset(as, 0, sizeof(*as));
 	as->pcm_index = chip->pcm_devs;
 	as->chip = chip;
+	as->fmt_type = fp->fmt_type;
 	err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs,
 			  stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0,
 			  stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1,
@@ -2216,7 +2221,6 @@ static int parse_audio_format_ii(struct 
 		break;
 	}
 	fp->channels = 1;
-	fp->nonaudio = 1;
 	brate = combine_word(&fmt[4]); 	/* fmt[4,5] : wMaxBitRate (in kbps) */
 	framesize = combine_word(&fmt[6]); /* fmt[6,7]: wSamplesPerFrame */
 	snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize);
@@ -2242,6 +2246,7 @@ static int parse_audio_format(struct usb
 			   dev->devnum, fp->iface, fp->altsetting, fmt[3]);
 		return -1;
 	}
+	fp->fmt_type = fmt[3];
 	if (err < 0)
 		return err;
 #if 1
@@ -2326,6 +2331,9 @@ static int parse_audio_endpoints(snd_usb
 		}
 
 		csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT);
+		/* Creamware Noah has this descriptor after the 2nd endpoint */
+		if (!csep && altsd->bNumEndpoints >= 2)
+			csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT);
 		if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) {
 			snd_printk(KERN_ERR "%d:%u:%d : no or invalid class specific endpoint descriptor\n", 
 				   dev->devnum, iface_no, altno);
--- diff/sound/usb/usbmidi.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/usb/usbmidi.c	2004-03-09 11:51:52.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * usbmidi.c - ALSA USB MIDI driver
  *
- * Copyright (c) 2002 Clemens Ladisch
+ * Copyright (c) 2002-2004 Clemens Ladisch
  * All rights reserved.
  *
  * Based on the OSS usb-midi driver by NAGANO Daisuke,
@@ -727,18 +727,118 @@ static snd_rawmidi_substream_t* snd_usbm
 	return NULL;
 }
 
+/*
+ * This list specifies names for ports that do not fit into the standard
+ * "(product) MIDI (n)" schema because they aren't external MIDI ports,
+ * such as internal control or synthesizer ports.
+ */
+static struct {
+	__u16 vendor;
+	__u16 product;
+	int port;
+	const char *name_format;
+} snd_usbmidi_port_names[] = {
+	/* Roland UA-100 */
+	{0x0582, 0x0000, 2, "%s Control"},
+	/* Roland SC-8850 */
+	{0x0582, 0x0003, 0, "%s Part A"},
+	{0x0582, 0x0003, 1, "%s Part B"},
+	{0x0582, 0x0003, 2, "%s Part C"},
+	{0x0582, 0x0003, 3, "%s Part D"},
+	{0x0582, 0x0003, 4, "%s MIDI 1"},
+	{0x0582, 0x0003, 5, "%s MIDI 2"},
+	/* Roland U-8 */
+	{0x0582, 0x0004, 0, "%s MIDI"},
+	{0x0582, 0x0004, 1, "%s Control"},
+	/* Roland SC-8820 */
+	{0x0582, 0x0007, 0, "%s Part A"},
+	{0x0582, 0x0007, 1, "%s Part B"},
+	{0x0582, 0x0007, 2, "%s MIDI"},
+	/* Roland SK-500 */
+	{0x0582, 0x000b, 0, "%s Part A"},
+	{0x0582, 0x000b, 1, "%s Part B"},
+	{0x0582, 0x000b, 2, "%s MIDI"},
+	/* Roland SC-D70 */
+	{0x0582, 0x000c, 0, "%s Part A"},
+	{0x0582, 0x000c, 1, "%s Part B"},
+	{0x0582, 0x000c, 2, "%s MIDI"},
+	/* Edirol UM-880 */
+	{0x0582, 0x0014, 8, "%s Control"},
+	/* Edirol SD-90 */
+	{0x0582, 0x0016, 0, "%s Part A"},
+	{0x0582, 0x0016, 1, "%s Part B"},
+	{0x0582, 0x0016, 2, "%s MIDI 1"},
+	{0x0582, 0x0016, 3, "%s MIDI 2"},
+	/* Edirol UM-550 */
+	{0x0582, 0x0023, 5, "%s Control"},
+	/* Edirol SD-20 */
+	{0x0582, 0x0027, 0, "%s Part A"},
+	{0x0582, 0x0027, 1, "%s Part B"},
+	{0x0582, 0x0027, 2, "%s MIDI"},
+	/* Edirol SD-80 */
+	{0x0582, 0x0029, 0, "%s Part A"},
+	{0x0582, 0x0029, 1, "%s Part B"},
+	{0x0582, 0x0029, 2, "%s MIDI 1"},
+	{0x0582, 0x0029, 3, "%s MIDI 2"},
+	/* Edirol UA-700 */
+	{0x0582, 0x002b, 0, "%s MIDI"},
+	{0x0582, 0x002b, 1, "%s Control"},
+	/* Roland VariOS */
+	{0x0582, 0x002f, 0, "%s MIDI"},
+	{0x0582, 0x002f, 1, "%s External MIDI"},
+	{0x0582, 0x002f, 2, "%s Sync"},
+	/* Edirol PCR */
+	{0x0582, 0x0033, 0, "%s MIDI"},
+	{0x0582, 0x0033, 1, "%s 1"},
+	{0x0582, 0x0033, 2, "%s 2"},
+	/* BOSS GS-10 */
+	{0x0582, 0x003b, 0, "%s MIDI"},
+	{0x0582, 0x003b, 1, "%s Control"},
+	/* Edirol UA-1000 */
+	{0x0582, 0x0044, 0, "%s MIDI"},
+	{0x0582, 0x0044, 1, "%s Control"},
+	/* Edirol UR-80 */
+	{0x0582, 0x0048, 0, "%s MIDI"},
+	{0x0582, 0x0048, 1, "%s 1"},
+	{0x0582, 0x0048, 2, "%s 2"},
+	/* Edirol PCR-A */
+	{0x0582, 0x004d, 0, "%s MIDI"},
+	{0x0582, 0x004d, 1, "%s 1"},
+	{0x0582, 0x004d, 2, "%s 2"},
+	/* M-Audio MidiSport 8x8 */
+	{0x0763, 0x1031, 8, "%s Control"},
+	{0x0763, 0x1033, 8, "%s Control"},
+};
+
 static void snd_usbmidi_init_substream(snd_usb_midi_t* umidi,
 				       int stream, int number,
 				       snd_rawmidi_substream_t** rsubstream)
 {
+	int i;
+	__u16 vendor, product;
+	const char *name_format;
+
 	snd_rawmidi_substream_t* substream = snd_usbmidi_find_substream(umidi, stream, number);
 	if (!substream) {
 		snd_printd(KERN_ERR "substream %d:%d not found\n", stream, number);
 		return;
 	}
+
 	/* TODO: read port name from jack descriptor */
+	name_format = "%s MIDI %d";
+	vendor = umidi->chip->dev->descriptor.idVendor;
+	product = umidi->chip->dev->descriptor.idProduct;
+	for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_names); ++i) {
+		if (snd_usbmidi_port_names[i].vendor == vendor &&
+		    snd_usbmidi_port_names[i].product == product &&
+		    snd_usbmidi_port_names[i].port == number) {
+			name_format = snd_usbmidi_port_names[i].name_format;
+			break;
+		}
+	}
 	snprintf(substream->name, sizeof(substream->name),
-		 "%s Port %d", umidi->chip->card->shortname, number);
+		 name_format, umidi->chip->card->shortname, number + 1);
+
 	*rsubstream = substream;
 }
 
--- diff/sound/usb/usbquirks.h	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/usb/usbquirks.h	2004-03-09 11:51:52.000000000 +0000
@@ -104,7 +104,7 @@ YAMAHA_DEVICE(0x5008, "01V96"),
 #undef YAMAHA_INTERFACE
 
 /*
- * Roland/RolandED/Edirol devices
+ * Roland/RolandED/Edirol/BOSS devices
  */
 {
 	USB_DEVICE(0x0582, 0x0000),
@@ -196,8 +196,8 @@ YAMAHA_DEVICE(0x5008, "01V96"),
 		.ifnum = 2,
 		.type = QUIRK_MIDI_FIXED_ENDPOINT,
 		.data = & (const snd_usb_midi_endpoint_info_t) {
-			.out_cables = 0x0003,
-			.in_cables  = 0x0003
+			.out_cables = 0x0005,
+			.in_cables  = 0x0005
 		}
 	}
 },
@@ -393,6 +393,32 @@ YAMAHA_DEVICE(0x5008, "01V96"),
 	}
 },
 {
+	USB_DEVICE(0x0582, 0x001b),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Roland",
+		.product_name = "MMP-2",
+		.ifnum = 2,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x0001,
+			.in_cables  = 0x0001
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x001d),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Roland",
+		.product_name = "V-SYNTH",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x0001,
+			.in_cables  = 0x0001
+		}
+	}
+},
+{
 	USB_DEVICE(0x0582, 0x0023),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "EDIROL",
@@ -489,6 +515,19 @@ YAMAHA_DEVICE(0x5008, "01V96"),
 	}
 },
 {
+	USB_DEVICE(0x0582, 0x002f),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Roland",
+		.product_name = "VariOS",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x0007,
+			.in_cables  = 0x0007
+		}
+	}
+},
+{
 	USB_DEVICE(0x0582, 0x0033),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "EDIROL",
@@ -502,6 +541,110 @@ YAMAHA_DEVICE(0x5008, "01V96"),
 	}
 },
 {
+	USB_DEVICE(0x0582, 0x0037),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Roland",
+		.product_name = "Digital Piano",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x0001,
+			.in_cables  = 0x0001
+		}
+	}
+},
+{
+	USB_DEVICE_VENDOR_SPEC(0x0582, 0x003b),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "BOSS",
+		.product_name = "GS-10",
+		.ifnum = 3,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x0003,
+			.in_cables  = 0x0003
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x0040),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Roland",
+		.product_name = "GI-20",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x0001,
+			.in_cables  = 0x0001
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x0048),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "EDIROL",
+		.product_name = "UR-80",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x0003,
+			.in_cables  = 0x0007
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x004d),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "EDIROL",
+		.product_name = "PCR-A",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x0003,
+			.in_cables  = 0x0007
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x0065),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "EDIROL",
+		.product_name = "PCR-1",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x0001,
+			.in_cables  = 0x0003
+		}
+	}
+},
+{
+	/*
+	 * This quirk is for the "Advanced Driver" mode. If off, the UA-3FX
+	 * is standard compliant, but has only 16-bit PCM.
+	 */
+	USB_DEVICE(0x0582, 0x0050),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "EDIROL",
+		.product_name = "UA-3FX",
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = & (const snd_usb_audio_quirk_t[]) {
+			{
+				.ifnum = 1,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
+{
 	USB_DEVICE(0x0582, 0x0052),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "EDIROL",
@@ -688,4 +831,14 @@ YAMAHA_DEVICE(0x5008, "01V96"),
 	
 },
 
+{
+	USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0013),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Terratec",
+		.product_name = "PHASE 26",
+		.ifnum = 3,
+		.type = QUIRK_MIDI_STANDARD_INTERFACE
+	}
+},
+
 #undef USB_DEVICE_VENDOR_SPEC
--- diff/Documentation/i386/kgdb/andthen	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/andthen	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,100 @@
+
+define	set_andthen
+	set var $thp=0
+	set var $thp=(struct kgdb_and_then_struct *)&kgdb_data[0]
+	set var $at_size = (sizeof kgdb_data)/(sizeof *$thp)
+	set var $at_oc=kgdb_and_then_count
+	set var $at_cc=$at_oc
+end
+
+define andthen_next
+	set var $at_cc=$arg0
+end
+
+define andthen
+	andthen_set_edge
+	if ($at_cc >= $at_oc)
+		printf "Outside window.  Window size is %d\n",($at_oc-$at_low)
+	else
+		printf "%d: ",$at_cc
+		output *($thp+($at_cc++ % $at_size ))
+		printf "\n"
+	end
+end
+define andthen_set_edge
+	set var $at_oc=kgdb_and_then_count
+	set var $at_low = $at_oc - $at_size
+	if ($at_low < 0 )
+		set var $at_low = 0
+	end
+	if (( $at_cc > $at_oc) || ($at_cc < $at_low))
+		printf "Count outside of window, setting count to "
+		if ($at_cc >= $at_oc)
+			set var $at_cc = $at_oc
+		else
+			set var $at_cc = $at_low
+		end
+		printf "%d\n",$at_cc
+	end
+end
+
+define beforethat
+	andthen_set_edge
+	if ($at_cc <= $at_low)
+		printf "Outside window.  Window size is %d\n",($at_oc-$at_low)
+	else
+		printf "%d: ",$at_cc-1
+		output *($thp+(--$at_cc % $at_size ))
+		printf "\n"
+	end
+end
+
+document andthen_next
+	andthen_next <count>
+	.	sets the number of the event to display next. If this event
+	.	is not in the event pool, either andthen or beforethat will
+	.	correct it to the nearest event pool edge.  The event pool
+	.	ends at the last event recorded and begins <number of events>
+	.	prior to that.  If beforethat is used next, it will display
+	.	event <count> -1.
+.
+	andthen commands are: set_andthen, andthen_next, andthen and beforethat
+end
+
+
+document andthen
+	andthen
+.	displays the next event in the list.  <set_andthen> sets up to display
+.	the oldest saved event first.
+.	<count> (optional) count of the event to display.
+.	note the number of events saved is specified at configure time.
+.	if events are saved between calls to andthen the index will change
+.	but the displayed event will be the next one (unless the event buffer
+.	is overrun).
+.
+.	andthen commands are: set_andthen, andthen_next, andthen and beforethat
+end
+
+document set_andthen
+	set_andthen
+.	sets up to use the <andthen> and <beforethat> commands.
+.		if you have defined your own struct, use the above and
+.		then enter the following:
+.		p $thp=(struct kgdb_and_then_structX *)&kgdb_data[0]
+.		where <kgdb_and_then_structX> is the name of your structure.
+.
+.	andthen commands are: set_andthen, andthen_next, andthen and beforethat
+end
+
+document beforethat
+	beforethat
+.	displays the next prior event in the list. <set_andthen> sets up to
+.	display the last occuring event first.
+.
+.	note the number of events saved is specified at configure time.
+.	if events are saved between calls to beforethat the index will change
+.	but the displayed event will be the next one (unless the event buffer
+.	is overrun).
+.
+.	andthen commands are: set_andthen, andthen_next, andthen and beforethat
+end
--- diff/Documentation/i386/kgdb/debug-nmi.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/debug-nmi.txt	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,37 @@
+Subject: Debugging with NMI
+Date: Mon, 12 Jul 1999 11:28:31 -0500
+From: David Grothe <dave@gcom.com>
+Organization: Gcom, Inc
+To: David Grothe <dave@gcom.com>
+
+Kernel hackers:
+
+Maybe this is old hat, but it is new to me --
+
+On an ISA bus machine, if you short out the A1 and B1 pins of an ISA
+slot you will generate an NMI to the CPU.  This interrupts even a
+machine that is hung in a loop with interrupts disabled.  Used in
+conjunction with kgdb <
+ftp://ftp.gcom.com/pub/linux/src/kgdb-2.3.35/kgdb-2.3.35.tgz > you can
+gain debugger control of a machine that is hung in the kernel!  Even
+without kgdb the kernel will print a stack trace so you can find out
+where it was hung.
+
+The A1/B1 pins are directly opposite one another and the farthest pins
+towards the bracket end of the ISA bus socket.  You can stick a paper
+clip or multi-meter probe between them to short them out.
+
+I had a spare ISA bus to PC104 bus adapter around.  The PC104 end of the
+board consists of two rows of wire wrap pins.  So I wired a push button
+between the A1/B1 pins and now have an ISA board that I can stick into
+any ISA bus slot for debugger entry.
+
+Microsoft has a circuit diagram of a PCI card at
+http://www.microsoft.com/hwdev/DEBUGGING/DMPSW.HTM.  If you want to
+build one you will have to mail them and ask for the PAL equations.
+Nobody makes one comercially.
+
+[THIS TIP COMES WITH NO WARRANTY WHATSOEVER.  It works for me, but if
+your machine catches fire, it is your problem, not mine.]
+
+-- Dave (the kgdb guy)
--- diff/Documentation/i386/kgdb/gdb-globals.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/gdb-globals.txt	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,71 @@
+Sender: akale@veritas.com
+Date: Fri, 23 Jun 2000 19:26:35 +0530
+From: "Amit S. Kale" <akale@veritas.com>
+Organization: Veritas Software (India)
+To: Dave Grothe <dave@gcom.com>, linux-kernel@vger.rutgers.edu
+CC: David Milburn <dmilburn@wirespeed.com>,
+        "Edouard G. Parmelan" <Edouard.Parmelan@quadratec.fr>,
+        ezannoni@cygnus.com, Keith Owens <kaos@ocs.com.au>
+Subject: Re: Module debugging using kgdb
+
+Dave Grothe wrote:
+>
+> Amit:
+>
+> There is a 2.4.0 version of kgdb on our ftp site:
+> ftp://ftp.gcom.com/pub/linux/src/kgdb.  I mirrored your version of gdb
+> and loadmodule.sh there.
+>
+> Have a look at the README file and see if I go it right.  If not, send
+> me some corrections and I will update it.
+>
+> Does your version of gdb solve the global variable problem?
+
+Yes.
+Thanks to Elena Zanoni, gdb (developement version) can now calculate
+correctly addresses  of dynamically loaded object files. I have not been
+following gdb developement for sometime and am not sure when symbol
+address calculation fix is going to appear in a gdb stable version.
+
+Elena, any idea when the fix will make it to a prebuilt gdb from a
+redhat release?
+
+For the time being I have built a gdb developement version. It can be
+used for module debugging with loadmodule.sh script.
+
+The problem with calculating of module addresses with previous versions
+of gdb was as follows:
+gdb did not use base address of a section while calculating address of
+a symbol in the section in an object file loaded via 'add-symbol-file'.
+It used address of .text segment instead. Due to this addresses of
+symbols in .data, .bss etc. (e.g. global variables) were calculated incorrectly.
+
+Above mentioned fix allow gdb to use base address of a segment while
+calculating address of a symbol in it. It adds a parameter '-s' to
+'add-symbol-file' command for specifying base address of a segment.
+
+loadmodule.sh script works as follows.
+
+1. Copy a module file to target machine.
+2. Load the module on the target machine using insmod with -m parameter.
+insmod produces a module load map which contains base addresses of all
+sections in the module and addresses of symbols in the module file.
+3. Find all sections and their base addresses in the module from
+the module map.
+4. Generate a script that loads the module file. The script uses
+'add-symbol-file' and specifies address of text segment followed by
+addresses of all segments in the module.
+
+Here is an example gdb script produced by loadmodule.sh script.
+
+add-symbol-file foo 0xd082c060 -s .text.lock 0xd08cbfb5
+-s .fixup 0xd08cfbdf -s .rodata 0xd08cfde0 -s __ex_table 0xd08e3b38
+-s .data 0xd08e3d00 -s .bss 0xd08ec8c0 -s __ksymtab 0xd08ee838
+
+With this command gdb can calculate addresses of symbols in ANY segment
+in a module file.
+
+Regards.
+--
+Amit Kale
+Veritas Software ( http://www.veritas.com )
--- diff/Documentation/i386/kgdb/gdbinit	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/gdbinit	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,14 @@
+shell echo -e "\003" >/dev/ttyS0
+set remotebaud 38400
+target remote /dev/ttyS0
+define si
+stepi
+printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx
+printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp
+x/i $eip
+end
+define ni
+nexti
+printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx
+printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp
+x/i $eip
--- diff/Documentation/i386/kgdb/gdbinit-modules	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/gdbinit-modules	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,146 @@
+#
+# Usefull GDB user-command to debug Linux Kernel Modules with gdbstub.
+#
+# This don't work for Linux-2.0 or older.
+#
+# Author Edouard G. Parmelan <Edouard.Parmelan@quadratec.fr>
+#
+#
+# Fri Apr 30 20:33:29 CEST 1999
+#   First public release.
+#
+#   Major cleanup after experiment Linux-2.0 kernel without success.
+#   Symbols of a module are not in the correct order, I can't explain
+#   why :(
+#
+# Fri Mar 19 15:41:40 CET 1999
+#   Initial version.
+#
+# Thu Jan  6 16:29:03 CST 2000
+#   A little fixing by Dave Grothe <dave@gcom.com>
+#
+# Mon Jun 19 09:33:13 CDT 2000
+#   Alignment changes from Edouard Parmelan
+#
+# The basic idea is to find where insmod load the module and inform
+# GDB to load the symbol table of the module with the GDB command
+# ``add-symbol-file <object> <address>''.
+#
+# The Linux kernel holds the list of all loaded modules in module_list,
+# this list end with &kernel_module (exactly with module->next == NULL,
+# but the last module is not a real module).
+#
+# Insmod allocates the struct module before the object file.  Since
+# Linux-2.1, this structure contain his size.  The real address of
+# the object file is then (char*)module + module->size_of_struct.
+#
+# You can use three user functions ``mod-list'', ``mod-print-symbols''
+# and ``add-module-symbols''.
+#
+# mod-list list all loaded modules with the format:
+#    <module-address> <module-name>
+#
+# As soon as you have found the address of your module, you can
+# print its exported symbols (mod-print-symbols) or inform GDB to add
+# symbols from your module file (mod-add-symbols).
+#
+# The argument that you give to mod-print-symbols or mod-add-symbols
+# is the <module-address> from the mod-list command.
+#
+# When using the mod-add-symbols command you must also give the full
+# pathname of the modules object code file.
+#
+# The command mod-add-lis is an example of how to make this easier.
+# You can edit this macro to contain the path name of your own
+# favorite module and then use it as a shorthand to load it.  You
+# still need the module-address, however.
+#
+# The internal function ``mod-validate'' set the GDB variable $mod
+# as a ``struct module*'' if the kernel known the module otherwise
+# $mod is set to NULL.  This ensure to not add symbols for a wrong
+# address.
+#
+# Have a nice hacking day !
+#
+#
+define mod-list
+    set $mod = (struct module*)module_list
+    # the last module is the kernel, ignore it
+    while $mod != &kernel_module
+    	printf "%p\t%s\n", (long)$mod, ($mod)->name
+	set $mod = $mod->next
+    end
+end
+document mod-list
+List all modules in the form: <module-address> <module-name>
+Use the <module-address> as the argument for the other
+mod-commands: mod-print-symbols, mod-add-symbols.
+end
+
+define mod-validate
+    set $mod = (struct module*)module_list
+    while ($mod != $arg0) && ($mod != &kernel_module)
+    	set $mod = $mod->next
+    end
+    if $mod == &kernel_module
+	set $mod = 0
+    	printf "%p is not a module\n", $arg0
+    end
+end
+document mod-validate
+mod-validate <module-address>
+Internal user-command used to validate the module parameter.
+If <module> is a real loaded module, set $mod to it otherwise set $mod to 0.
+end
+
+
+define mod-print-symbols
+    mod-validate $arg0
+    if $mod != 0
+	set $i = 0
+	while $i < $mod->nsyms
+	    set $sym = $mod->syms[$i]
+	    printf "%p\t%s\n", $sym->value, $sym->name
+	    set $i = $i + 1
+	end
+    end
+end
+document mod-print-symbols
+mod-print-symbols <module-address>
+Print all exported symbols of the module.  see mod-list
+end
+
+
+define mod-add-symbols-align
+    mod-validate $arg0
+    if $mod != 0
+	set $mod_base = ($mod->size_of_struct + (long)$mod)
+	if ($arg2 != 0) && (($mod_base & ($arg2 - 1)) != 0)
+	    set $mod_base = ($mod_base | ($arg2 - 1)) + 1
+	end
+	add-symbol-file $arg1 $mod_base
+    end
+end
+document mod-add-symbols-align
+mod-add-symbols-align <module-address> <object file path name> <align>
+Load the symbols table of the module from the object file where
+first section aligment is <align>.
+To retreive alignment, use `objdump -h <object file path name>'.
+end
+
+define mod-add-symbols
+    mod-add-symbols-align $arg0 $arg1 sizeof(long)
+end
+document mod-add-symbols
+mod-add-symbols <module-address> <object file path name>
+Load the symbols table of the module from the object file.
+Default alignment is 4.  See mod-add-symbols-align.
+end
+
+define mod-add-lis
+    mod-add-symbols-align $arg0 /usr/src/LiS/streams.o 16
+end
+document mod-add-lis
+mod-add-lis <module-address>
+Does mod-add-symbols <module-address> /usr/src/LiS/streams.o
+end
--- diff/Documentation/i386/kgdb/gdbinit.hw	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/gdbinit.hw	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,117 @@
+
+#Using ia-32 hardware breakpoints.
+#
+#4 hardware breakpoints are available in ia-32 processors. These breakpoints
+#do not need code modification. They are set using debug registers.
+#
+#Each hardware breakpoint can be of one of the
+#three types: execution, write, access.
+#1. An Execution breakpoint is triggered when code at the breakpoint address is
+#executed.
+#2. A write breakpoint ( aka watchpoints ) is triggered when memory location
+#at the breakpoint address is written.
+#3. An access breakpoint is triggered when memory location at the breakpoint
+#address is either read or written.
+#
+#As hardware breakpoints are available in limited number, use software
+#breakpoints ( br command in gdb ) instead of execution hardware breakpoints.
+#
+#Length of an access or a write breakpoint defines length of the datatype to
+#be watched. Length is 1 for char, 2 short , 3 int.
+#
+#For placing execution, write and access breakpoints, use commands
+#hwebrk, hwwbrk, hwabrk
+#To remove a breakpoint use hwrmbrk command.
+#
+#These commands take following types of arguments. For arguments associated
+#with each command, use help command.
+#1. breakpointno: 0 to 3
+#2. length: 1 to 3
+#3. address: Memory location in hex ( without 0x ) e.g c015e9bc
+#
+#Use the command exinfo to find which hardware breakpoint occured.
+
+#hwebrk breakpointno address
+define hwebrk
+	maintenance packet Y$arg0,0,0,$arg1
+end
+document hwebrk
+	hwebrk <breakpointno> <address>
+	Places a hardware execution breakpoint
+	<breakpointno> = 0 - 3
+	<address> = Hex digits without leading "0x".
+end
+
+#hwwbrk breakpointno length address
+define hwwbrk
+	maintenance packet Y$arg0,1,$arg1,$arg2
+end
+document hwwbrk
+	hwwbrk <breakpointno> <length> <address>
+	Places a hardware write breakpoint
+	<breakpointno> = 0 - 3
+	<length> = 1 (1 byte), 2 (2 byte), 3 (4 byte)
+	<address> = Hex digits without leading "0x".
+end
+
+#hwabrk breakpointno length address
+define hwabrk
+	maintenance packet Y$arg0,1,$arg1,$arg2
+end
+document hwabrk
+	hwabrk <breakpointno> <length> <address>
+	Places a hardware access breakpoint
+	<breakpointno> = 0 - 3
+	<length> = 1 (1 byte), 2 (2 byte), 3 (4 byte)
+	<address> = Hex digits without leading "0x".
+end
+
+#hwrmbrk breakpointno
+define hwrmbrk
+	maintenance packet y$arg0
+end
+document hwrmbrk
+	hwrmbrk <breakpointno>
+	<breakpointno> = 0 - 3
+	Removes a hardware breakpoint
+end
+
+define reboot
+        maintenance packet r
+end
+#exinfo
+define exinfo
+	maintenance packet qE
+end
+document exinfo
+	exinfo
+	Gives information about a breakpoint.
+end
+define get_th
+	p $th=(struct thread_info *)((int)$esp & ~8191)
+end
+document get_th
+	get_tu
+	Gets and prints the current thread_info pointer, Defines th to be it.
+end
+define get_cu
+	p $cu=((struct thread_info *)((int)$esp & ~8191))->task
+end
+document get_cu
+	get_cu
+	Gets and print the "current" value.  Defines $cu to be it.
+end
+define int_off
+	set var $flags=$eflags
+	set $eflags=$eflags&~0x200
+	end
+define int_on
+	set var $eflags|=$flags&0x200
+	end
+document int_off
+	saves the current interrupt state and clears the processor interrupt
+	flag.  Use int_on to restore the saved flag.
+end
+document int_on
+	Restores the interrupt flag saved by int_off.
+end
--- diff/Documentation/i386/kgdb/kgdb.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/kgdb.txt	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,775 @@
+Last edit: <20030806.1637.12>
+This file has information specific to the i386 kgdb option.  Other
+platforms with the kgdb option may behave in a similar fashion.
+
+New features:
+============
+20030806.1557.37
+This version was made against the 2.6.0-test2 kernel. We have made the
+following changes:
+
+- The getthread() code in the stub calls find_task_by_pid().  It fails
+  if we are early in the bring up such that the pid arrays have yet to
+  be allocated.  We have added a line to kernel/pid.c to make
+  "kgdb_pid_init_done" true once the arrays are allocated.  This way the
+  getthread() code knows not to call.  This is only used by the thread
+  debugging stuff and threads will not yet exist at this point in the
+  boot.
+
+- For some reason, gdb was not asking for a new thread list when the
+  "info thread" command was given.  We changed to the newer version of
+  the thread info command and gdb now seems to ask when needed.  Result,
+  we now get all threads in the thread list.
+
+- We now respond to the ThreadExtraInfo request from gdb with the thread
+  name from task_struct .comm.  This then appears in the thread list.
+  Thoughts on additional options for this are welcome.  Things such as
+  "has BKL" and "Preempted" come to mind.  I think we could have a flag
+  word that could enable different bits of info here.
+
+- We now honor, sort of, the C and S commands.  These are continue and
+  single set after delivering a signal.  We ignore the signal and do the
+  requested action.  This only happens when we told gdb that a signal
+  was the reason for entry, which is only done on memory faults.  The
+  result is that you can now continue into the Oops.
+
+- We changed the -g to -gdwarf-2.  This seems to be the same as -ggdb,
+  but it is more exact on what language to use.
+
+- We added two dwarf2 include files and a bit of code at the end of
+  entry.S.  This does not yet work, so it is disabled.  Still we want to
+  keep track of the code and "maybe" someone out there can fix it.
+
+- Randy Dunlap sent some fix ups for this file which are now merged.
+
+- Hugh Dickins sent a fix to a bit of code in traps.c that prevents a
+  compiler warning if CONFIG_KGDB is off (now who would do that :).
+
+- Andrew Morton sent a fix for the serial driver which is now merged.
+
+- Andrew also sent a change to the stub around the cpu managment code
+  which is also merged.
+
+- Andrew also sent a patch to make "f" as well as "g" work as SysRq
+  commands to enter kgdb, merged.
+
+- If CONFIG_KGDB and CONFIG_DEBUG_SPINLOCKS are both set we added a
+  "who" field to the spinlock data struct.  This is filled with
+  "current" when ever the spinlock suceeds.  Useful if you want to know
+  who has the lock.
+
+_ And last, but not least, we fixed the "get_cu" macro to properly get
+  the current value of "current".
+
+New features:
+============
+20030505.1827.27
+We are starting to align with the sourceforge version, at least in
+commands.  To this end, the boot command string to start kgdb at
+boot time has been changed from "kgdb" to "gdb".
+
+Andrew Morton sent a couple of patches which are now included as follows:
+1.) We now return a flag to the interrupt handler.
+2.) We no longer use smp_num_cpus (a conflict with the lock meter).
+3.) And from William Lee Irwin III <wli@holomorphy.com> code to make
+    sure high-mem is set up before we attempt to register our interrupt
+    handler.
+We now include asm/kgdb.h from config.h so you will most likely never
+have to include it.  It also 'NULLS' the kgdb macros you might have in
+your code when CONFIG_KGDB is not defined.  This allows you to just
+turn off CONFIG_KGDB to turn off all the kgdb_ts() calls and such.
+This include is conditioned on the machine being an x86 so as to not
+mess with other archs.
+
+20020801.1129.03
+This is currently the version for the 2.4.18 (and beyond?) kernel.
+
+We have several new "features" beginning with this version:
+
+1.) Kgdb now syncs the "other" CPUs with a cross-CPU NMI.  No more
+    waiting and it will pull that guy out of an IRQ off spin lock :)
+
+2.) We doctored up the code that tells where a task is waiting and
+    included it so that the "info thread" command will show a bit more
+    than "schedule()".  Try it...
+
+3.) Added the ability to call a function from gdb.  All the standard gdb
+    issues apply, i.e. if you hit a breakpoint in the function, you are
+    not allowed to call another (gdb limitation, not kgdb).  To help
+    this capability we added a memory allocation function.  Gdb does not
+    return this memory (it is used for strings that you pass to that function
+    you are calling from gdb) so we fixed up a way to allow you to
+    manually return the memory (see below).
+
+4.) Kgdb time stamps (kgdb_ts()) are enhanced to expand what was the
+    interrupt flag to now also include the preemption count and the
+    "in_interrupt" info.  The flag is now called "with_pif" to indicate
+    the order, preempt_count, in_interrupt, flag.  The preempt_count is
+    shifted left by 4 bits so you can read the count in hex by dropping
+    the low order digit.  In_interrupt is in bit 1, and the flag is in
+    bit 0.
+
+5.) The command: "p kgdb_info" is now expanded and prints something
+    like:
+(gdb) p kgdb_info
+$2 = {used_malloc = 0, called_from = 0xc0107506, entry_tsc = 67468627259,
+  errcode = 0, vector = 3, print_debug_info = 0, hold_on_sstep = 1,
+  cpus_waiting = {{task = 0xc027a000, pid = 32768, hold = 0,
+      regs = 0xc027bf84}, {task = 0x0, pid = 0, hold = 0, regs = 0x0}}}
+
+    Things to note here: a.) used_malloc is the amount of memory that
+    has been malloc'ed to do calls from gdb.  You can reclaim this
+    memory like this: "p kgdb_info.used_malloc=0" Cool, huh?  b.)
+    cpus_waiting is now "sized" by the number of CPUs you enter at
+    configure time in the kgdb configure section.  This is NOT used
+    anywhere else in the system, but it is "nice" here.  c.)  The task's
+    "pid" is now in the structure.  This is the pid you will need to use
+    to decode to the thread id to get gdb to look at that thread.
+    Remember that the "info thread" command prints a list of threads
+    wherein it numbers each thread with its reference number followed
+    by the thread's pid.  Note that the per-CPU idle threads actually
+    have pids of 0 (yes, there is more than one pid 0 in an SMP system).
+    To avoid confusion, kgdb numbers these threads with numbers beyond
+    the MAX_PID.  That is why you see 32768 and above.
+
+6.) A subtle change, we now provide the complete register set for tasks
+    that are active on the other CPUs.  This allows better trace back on
+    those tasks.
+
+    And, let's mention what we could not fix.  Back-trace from all but the
+    thread that we trapped will, most likely, have a bogus entry in it.
+    The problem is that gdb does not recognize the entry code for
+    functions that use "current" near (at all?) the entry.  The compiler
+    is putting the "current" decode as the first two instructions of the
+    function where gdb expects to find %ebp changing code.  Back trace
+    also has trouble with interrupt frames.  I am talking with Daniel
+    Jacobowitz about some way to fix this, but don't hold your breath.
+
+20011220.0050.35
+Major enhancement with this version is the ability to hold one or more
+CPUs in an SMP system while allowing the others to continue.  Also, by
+default only the current CPU is enabled on single-step commands (please
+note that gdb issues single-step commands at times other than when you
+use the si command).
+
+Another change is to collect some useful information in
+a global structure called "kgdb_info".  You should be able to just:
+
+p kgdb_info
+
+although I have seen cases where the first time this is done gdb just
+prints the first member but prints the whole structure if you then enter
+CR (carriage return or enter).  This also works:
+
+p *&kgdb_info
+
+Here is a sample:
+(gdb) p kgdb_info
+$4 = {called_from = 0xc010732c, entry_tsc = 32804123790856, errcode = 0,
+  vector = 3, print_debug_info = 0}
+
+"Called_from" is the return address from the current entry into kgdb.
+Sometimes it is useful to know why you are in kgdb, for example, was
+it an NMI or a real breakpoint?  The simple way to interrogate this
+return address is:
+
+l *0xc010732c
+
+which will print the surrounding few lines of source code.
+
+"Entry_tsc" is the CPU TSC on entry to kgdb (useful to compare to the
+kgdb_ts entries).
+
+"errcode" and "vector" are other entry parameters which may be helpful on
+some traps.
+
+"print_debug_info" is the internal debugging kgdb print enable flag.  Yes,
+you can modify it.
+
+In SMP systems kgdb_info also includes the "cpus_waiting" structure and
+"hold_on_step":
+
+(gdb) p kgdb_info
+$7 = {called_from = 0xc0112739, entry_tsc = 1034936624074, errcode = 0,
+  vector = 2, print_debug_info = 0, hold_on_sstep = 1, cpus_waiting = {{
+      task = 0x0, hold = 0, regs = 0x0}, {task = 0xc71b8000, hold = 0,
+      regs = 0xc71b9f70}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
+      hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
+      hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
+      hold = 0, regs = 0x0}}}
+
+"Cpus_waiting" has an entry for each CPU other than the current one that
+has been stopped.  Each entry contains the task_struct address for that
+CPU, the address of the regs for that task and a hold flag.  All these
+have the proper typing so that, for example:
+
+p *kgdb_info.cpus_waiting[1].regs
+
+will print the registers for CPU 1.
+
+"Hold_on_sstep" is a new feature with this version and comes up set or
+true.  What this means is that whenever kgdb is asked to single-step all
+other CPUs are held (i.e. not allowed to execute).  The flag applies to
+all but the current CPU and, again, can be changed:
+
+p kgdb_info.hold_on_sstep=0
+
+restores the old behavior of letting all CPUs run during single-stepping.
+
+Likewise, each CPU has a "hold" flag, which if set, locks that CPU out
+of execution.  Note that this has some risk in cases where the CPUs need
+to communicate with each other.  If kgdb finds no CPU available on exit,
+it will push a message thru gdb and stay in kgdb.  Note that it is legal
+to hold the current CPU as long as at least one CPU can execute.
+
+20010621.1117.09
+This version implements an event queue.  Events are signaled by calling
+a function in the kgdb stub and may be examined from gdb.  See EVENTS
+below for details.  This version also tightens up the interrupt and SMP
+handling to not allow interrupts on the way to kgdb from a breakpoint
+trap.  It is fine to allow these interrupts for user code, but not
+system debugging.
+
+Version
+=======
+
+This version of the kgdb package was developed and tested on
+kernel version 2.4.16.  It will not install on any earlier kernels.
+It is possible that it will continue to work on later versions
+of 2.4 and then versions of 2.5 (I hope).
+
+
+Debugging Setup
+===============
+
+Designate one machine as the "development" machine.  This is the
+machine on which you run your compiles and which has your source
+code for the kernel.  Designate a second machine as the "target"
+machine.  This is the machine that will run your experimental
+kernel.
+
+The two machines will be connected together via a serial line out
+one or the other of the COM ports of the PC.  You will need the
+appropriate modem eliminator (null modem) cable(s) for this.
+
+Decide on which tty port you want the machines to communicate, then
+connect them up back-to-back using the null modem cable.  COM1 is
+/dev/ttyS0 and COM2 is /dev/ttyS1. You should test this connection
+with the two machines prior to trying to debug a kernel.  Once you
+have it working, on the TARGET machine, enter:
+
+setserial /dev/ttyS0 (or what ever tty you are using)
+
+and record the port address and the IRQ number.
+
+On the DEVELOPMENT machine you need to apply the patch for the kgdb
+hooks.  You have probably already done that if you are reading this
+file.
+
+On your DEVELOPMENT machine, go to your kernel source directory and do
+"make Xconfig" where X is one of "x", "menu", or "".  If you are
+configuring in the standard serial driver, it must not be a module.
+Either yes or no is ok, but making the serial driver a module means it
+will initialize after kgdb has set up the UART interrupt code and may
+cause a failure of the control-C option discussed below.  The configure
+question for the serial driver is under the "Character devices" heading
+and is:
+
+"Standard/generic (8250/16550 and compatible UARTs) serial support"
+
+Go down to the kernel debugging menu item and open it up.  Enable the
+kernel kgdb stub code by selecting that item.  You can also choose to
+turn on the "-ggdb -O1" compile options.  The -ggdb causes the compiler
+to put more debug info (like local symbols) in the object file.  On the
+i386 -g and -ggdb are the same so this option just reduces to "O1".  The
+-O1 reduces the optimization level.  This may be helpful in some cases,
+be aware, however, that this may also mask the problem you are looking
+for.
+
+The baud rate.  Default is 115200.  What ever you choose be sure that
+the host machine is set to the same speed.  I recommend the default.
+
+The port.  This is the I/O address of the serial UART that you should
+have gotten using setserial as described above.  The standard COM1 port
+(3f8) using IRQ 4 is default.  COM2 is 2f8 which by convention uses IRQ
+3.
+
+The port IRQ (see above).
+
+Stack overflow test.  This option makes a minor change in the trap,
+system call and interrupt code to detect stack overflow and transfer
+control to kgdb if it happens.  (Some platforms have this in the
+baseline code, but the i386 does not.)
+
+You can also configure the system to recognize the boot option
+"console=kgdb" which if given will cause all console output during
+booting to be put thru gdb as well as other consoles.  This option
+requires that gdb and kgdb be connected prior to sending console output
+so, if they are not, a breakpoint is executed to force the connection.
+This will happen before any kernel output (it is going thru gdb, right),
+and will stall the boot until the connection is made.
+
+You can also configure in a patch to SysRq to enable the kGdb SysRq.
+This request generates a breakpoint.  Since the serial port IRQ line is
+set up after any serial drivers, it is possible that this command will
+work when the control-C will not.
+
+Save and exit the Xconfig program.  Then do "make clean" , "make dep"
+and "make bzImage" (or whatever target you want to make).  This gets the
+kernel compiled with the "-g" option set -- necessary for debugging.
+
+You have just built the kernel on your DEVELOPMENT machine that you
+intend to run on your TARGET machine.
+
+To install this new kernel, use the following installation procedure.
+Remember, you are on the DEVELOPMENT machine patching the kernel source
+for the kernel that you intend to run on the TARGET machine.
+
+Copy this kernel to your target machine using your usual procedures.  I
+usually arrange to copy development:
+/usr/src/linux/arch/i386/boot/bzImage to /vmlinuz on the TARGET machine
+via a LAN based NFS access.  That is, I run the cp command on the target
+and copy from the development machine via the LAN.  Run Lilo (see "man
+lilo" for details on how to set this up) on the new kernel on the target
+machine so that it will boot!  Then boot the kernel on the target
+machine.
+
+On the DEVELOPMENT machine, create a file called .gdbinit in the
+directory /usr/src/linux.  An example .gdbinit file looks like this:
+
+shell echo -e "\003" >/dev/ttyS0
+set remotebaud 38400 (or what ever speed you have chosen)
+target remote /dev/ttyS0
+
+
+Change the "echo" and "target" definition so that it specifies the tty
+port that you intend to use.  Change the "remotebaud" definition to
+match the data rate that you are going to use for the com line.
+
+You are now ready to try it out.
+
+Boot your target machine with "kgdb" in the boot command i.e. something
+like:
+
+lilo> test kgdb
+
+or if you also want console output thru gdb:
+
+lilo> test kgdb console=kgdb
+
+You should see the lilo message saying it has loaded the kernel and then
+all output stops.  The kgdb stub is trying to connect with gdb.  Start
+gdb something like this:
+
+
+On your DEVELOPMENT machine, cd /usr/src/linux and enter "gdb vmlinux".
+When gdb gets the symbols loaded it will read your .gdbinit file and, if
+everything is working correctly, you should see gdb print out a few
+lines indicating that a breakpoint has been taken.  It will actually
+show a line of code in the target kernel inside the kgdb activation
+code.
+
+The gdb interaction should look something like this:
+
+    linux-dev:/usr/src/linux# gdb vmlinux
+    GDB is free software and you are welcome to distribute copies of it
+     under certain conditions; type "show copying" to see the conditions.
+    There is absolutely no warranty for GDB; type "show warranty" for details.
+    GDB 4.15.1 (i486-slackware-linux),
+    Copyright 1995 Free Software Foundation, Inc...
+    breakpoint () at i386-stub.c:750
+    750     }
+    (gdb)
+
+You can now use whatever gdb commands you like to set breakpoints.
+Enter "continue" to start your target machine executing again.  At this
+point the target system will run at full speed until it encounters
+your breakpoint or gets a segment violation in the kernel, or whatever.
+
+If you have the kgdb console enabled when you continue, gdb will print
+out all the console messages.
+
+The above example caused a breakpoint relatively early in the boot
+process.  For the i386 kgdb it is possible to code a break instruction
+as the first C-language point in init/main.c, i.e. as the first instruction
+in start_kernel().  This could be done as follows:
+
+#include <asm/kgdb.h>
+	 breakpoint();
+
+This breakpoint() is really a function that sets up the breakpoint and
+single-step hardware trap cells and then executes a breakpoint.  Any
+early hard coded breakpoint will need to use this function.  Once the
+trap cells are set up they need not be set again, but doing it again
+does not hurt anything, so you don't need to be concerned about which
+breakpoint is hit first.  Once the trap cells are set up (and the kernel
+sets them up in due course even if breakpoint() is never called) the
+macro:
+
+BREAKPOINT;
+
+will generate an inline breakpoint.  This may be more useful as it stops
+the processor at the instruction instead of in a function a step removed
+from the location of interest.  In either case <asm/kgdb.h> must be
+included to define both breakpoint() and BREAKPOINT.
+
+Triggering kgdbstub at other times
+==================================
+
+Often you don't need to enter the debugger until much later in the boot
+or even after the machine has been running for some time.  Once the
+kernel is booted and interrupts are on, you can force the system to
+enter the debugger by sending a control-C to the debug port. This is
+what the first line of the recommended .gdbinit file does.  This allows
+you to start gdb any time after the system is up as well as when the
+system is already at a breakpoint.  (In the case where the system is
+already at a breakpoint the control-C is not needed, however, it will
+be ignored by the target so no harm is done.  Also note the the echo
+command assumes that the port speed is already set.  This will be true
+once gdb has connected, but it is best to set the port speed before you
+run gdb.)
+
+Another simple way to do this is to put the following file in you ~/bin
+directory:
+
+#!/bin/bash
+echo  -e "\003"  > /dev/ttyS0
+
+Here, the ttyS0 should be replaced with what ever port you are using.
+The "\003" is control-C.  Once you are connected with gdb, you can enter
+control-C at the command prompt.
+
+An alternative way to get control to the debugger is to enable the kGdb
+SysRq command.  Then you would enter Alt-SysRq-g (all three keys at the
+same time, but push them down in the order given).  To refresh your
+memory of the available SysRq commands try Alt-SysRq-=.  Actually any
+undefined command could replace the "=", but I like to KNOW that what I
+am pushing will never be defined.
+
+Debugging hints
+===============
+
+You can break into the target machine at any time from the development
+machine by typing ^C (see above paragraph).  If the target machine has
+interrupts enabled this will stop it in the kernel and enter the
+debugger.
+
+There is unfortunately no way of breaking into the kernel if it is
+in a loop with interrupts disabled, so if this happens to you then
+you need to place exploratory breakpoints or printk's into the kernel
+to find out where it is looping.  The exploratory breakpoints can be
+entered either thru gdb or hard coded into the source.  This is very
+handy if you do something like:
+
+if (<it hurts>) BREAKPOINT;
+
+
+There is a copy of an e-mail in the Documentation/i386/kgdb/ directory
+(debug-nmi.txt) which describes how to create an NMI on an ISA bus
+machine using a paper clip.  I have a sophisticated version of this made
+by wiring a push button switch into a PC104/ISA bus adapter card.  The
+adapter card nicely furnishes wire wrap pins for all the ISA bus
+signals.
+
+When you are done debugging the kernel on the target machine it is a
+good idea to leave it in a running state.  This makes reboots faster,
+bypassing the fsck.  So do a gdb "continue" as the last gdb command if
+this is possible.  To terminate gdb itself on the development machine
+and leave the target machine running, first clear all breakpoints and
+continue, then type ^Z to suspend gdb and then kill it with "kill %1" or
+something similar.
+
+If gdbstub Does Not Work
+========================
+
+If it doesn't work, you will have to troubleshoot it.  Do the easy
+things first like double checking your cabling and data rates.  You
+might try some non-kernel based programs to see if the back-to-back
+connection works properly.  Just something simple like cat /etc/hosts
+>/dev/ttyS0 on one machine and cat /dev/ttyS0 on the other will tell you
+if you can send data from one machine to the other.  Make sure it works
+in both directions.  There is no point in tearing out your hair in the
+kernel if the line doesn't work.
+
+All of the real action takes place in the file
+/usr/src/linux/arch/i386/kernel/kgdb_stub.c.  That is the code on the target
+machine that interacts with gdb on the development machine.  In gdb you can
+turn on a debug switch with the following command:
+
+	set remotedebug
+
+This will print out the protocol messages that gdb is exchanging with
+the target machine.
+
+Another place to look is /usr/src/arch/i386/lib/kgdb_serial.c. This is
+the code that talks to the serial port on the target side.  There might
+be a problem there.  In particular there is a section of this code that
+tests the UART which will tell you what UART you have if you define
+"PRNT" (just remove "_off" from the #define PRNT_off).  To view this
+report you will need to boot the system without any beakpoints.  This
+allows the kernel to run to the point where it calls kgdb to set up
+interrupts.  At this time kgdb will test the UART and print out the type
+it finds.  (You need to wait so that the printks are actually being
+printed.  Early in the boot they are cached, waiting for the console to
+be enabled.  Also, if kgdb is entered thru a breakpoint it is possible
+to cause a dead lock by calling printk when the console is locked.  The
+stub thus avoids doing printks from breakpoints, especially in the
+serial code.)  At this time, if the UART fails to do the expected thing,
+kgdb will print out (using printk) information on what failed.  (These
+messages will be buried in all the other boot up messages.  Look for
+lines that start with "gdb_hook_interrupt:".  You may want to use dmesg
+once the system is up to view the log.  If this fails or if you still
+don't connect, review your answers for the port address.  Use:
+
+setserial /dev/ttyS0
+
+to get the current port and IRQ information.  This command will also
+tell you what the system found for the UART type. The stub recognizes
+the following UART types:
+
+16450, 16550, and 16550A
+
+If you are really desperate you can use printk debugging in the
+kgdbstub code in the target kernel until you get it working.  In particular,
+there is a global variable in /usr/src/linux/arch/i386/kernel/kgdb_stub.c
+named "remote_debug".  Compile your kernel with this set to 1, rather
+than 0 and the debug stub will print out lots of stuff as it does
+what it does.  Likewise there are debug printks in the kgdb_serial.c
+code that can be turned on with simple changes in the macro defines.
+
+
+Debugging Loadable Modules
+==========================
+
+This technique comes courtesy of Edouard Parmelan
+<Edouard.Parmelan@quadratec.fr>
+
+When you run gdb, enter the command
+
+source gdbinit-modules
+
+This will read in a file of gdb macros that was installed in your
+kernel source directory when kgdb was installed.  This file implements
+the following commands:
+
+mod-list
+    Lists the loaded modules in the form <module-address> <module-name>
+
+mod-print-symbols <module-address>
+    Prints all the symbols in the indicated module.
+
+mod-add-symbols <module-address> <object-file-path-name>
+    Loads the symbols from the object file and associates them
+    with the indicated module.
+
+After you have loaded the module that you want to debug, use the command
+mod-list to find the <module-address> of your module.  Then use that
+address in the mod-add-symbols command to load your module's symbols.
+From that point onward you can debug your module as if it were a part
+of the kernel.
+
+The file gdbinit-modules also contains a command named mod-add-lis as
+an example of how to construct a command of your own to load your
+favorite module.  The idea is to "can" the pathname of the module
+in the command so you don't have to type so much.
+
+Threads
+=======
+
+Each process in a target machine is seen as a gdb thread. gdb thread
+related commands (info threads, thread n) can be used.
+
+ia-32 hardware breakpoints
+==========================
+
+kgdb stub contains support for hardware breakpoints using debugging features
+of ia-32(x86) processors. These breakpoints do not need code modification.
+They use debugging registers. 4 hardware breakpoints are available in ia-32
+processors.
+
+Each hardware breakpoint can be of one of the following three types.
+
+1. Execution breakpoint - An Execution breakpoint is triggered when code
+	at the breakpoint address is executed.
+
+	As limited number of hardware breakpoints are available, it is
+	advisable to use software breakpoints ( break command ) instead
+	of execution hardware breakpoints, unless modification of code
+	is to be avoided.
+
+2. Write breakpoint - A write breakpoint is triggered when memory
+	location at the breakpoint address is written.
+
+	A write or can be placed for data of variable length. Length of
+	a write breakpoint indicates length of the datatype to be
+	watched. Length is 1 for 1 byte data , 2 for 2 byte data, 3 for
+	4 byte data.
+
+3. Access breakpoint - An access breakpoint is triggered when memory
+	location at the breakpoint address is either read or written.
+
+	Access breakpoints also have lengths similar to write breakpoints.
+
+IO breakpoints in ia-32 are not supported.
+
+Since gdb stub at present does not use the protocol used by gdb for hardware
+breakpoints, hardware breakpoints are accessed through gdb macros. gdb macros
+for hardware breakpoints are described below.
+
+hwebrk	- Places an execution breakpoint
+	hwebrk breakpointno address
+hwwbrk	- Places a write breakpoint
+	hwwbrk breakpointno length address
+hwabrk	- Places an access breakpoint
+	hwabrk breakpointno length address
+hwrmbrk	- Removes a breakpoint
+	hwrmbrk breakpointno
+exinfo	- Tells whether a software or hardware breakpoint has occurred.
+	Prints number of the hardware breakpoint if a hardware breakpoint has
+	occurred.
+
+Arguments required by these commands are as follows
+breakpointno	- 0 to 3
+length		- 1 to 3
+address		- Memory location in hex digits ( without 0x ) e.g c015e9bc
+
+SMP support
+==========
+
+When a breakpoint occurs or user issues a break ( Ctrl + C ) to gdb
+client, all the processors are forced to enter the debugger. Current
+thread corresponds to the thread running on the processor where
+breakpoint occurred.  Threads running on other processor(s) appear
+similar to other non-running threads in the 'info threads' output.
+Within the kgdb stub there is a structure "waiting_cpus" in which kgdb
+records the values of "current" and "regs" for each CPU other than the
+one that hit the breakpoint.  "current" is a pointer to the task
+structure for the task that CPU is running, while "regs" points to the
+saved registers for the task.  This structure can be examined with the
+gdb "p" command.
+
+ia-32 hardware debugging registers on all processors are set to same
+values.  Hence any hardware breakpoints may occur on any processor.
+
+gdb troubleshooting
+===================
+
+1. gdb hangs
+Kill it. restart gdb. Connect to target machine.
+
+2. gdb cannot connect to target machine (after killing a gdb and
+restarting another) If the target machine was not inside debugger when
+you killed gdb, gdb cannot connect because the target machine won't
+respond.  In this case echo "Ctrl+C"(ASCII 3) to the serial line.
+e.g. echo -e "\003" > /dev/ttyS1
+This forces that target machine into the debugger, after which you
+can connect.
+
+3. gdb cannot connect even after echoing Ctrl+C into serial line
+Try changing serial line settings min to 1 and time to 0
+e.g. stty min 1 time 0 < /dev/ttyS1
+Try echoing again
+
+Check serial line speed and set it to correct value if required
+e.g. stty ispeed 115200 ospeed 115200 < /dev/ttyS1
+
+EVENTS
+======
+
+Ever want to know the order of things happening?  Which CPU did what and
+when?  How did the spinlock get the way it is?  Then events are for
+you.  Events are defined by calls to an event collection interface and
+saved for later examination.  In this case, kgdb events are saved by a
+very fast bit of code in kgdb which is fully SMP and interrupt protected
+and they are examined by using gdb to display them.  Kgdb keeps only
+the last N events, where N must be a power of two and is defined at
+configure time.
+
+
+Events are signaled to kgdb by calling:
+
+kgdb_ts(data0,data1)
+
+For each call kgdb records each call in an array along with other info.
+Here is the array definition:
+
+struct kgdb_and_then_struct {
+#ifdef CONFIG_SMP
+	int	on_cpu;
+#endif
+	long long at_time;
+	int  	from_ln;
+	char	* in_src;
+	void	*from;
+        int     with_if;
+	int	data0;
+	int	data1;
+};
+
+For SMP machines the CPU is recorded, for all machines the TSC is
+recorded (gets a time stamp) as well as the line number and source file
+the call was made from.  The address of the (from), the "if" (interrupt
+flag) and the two data items are also recorded.  The macro kgdb_ts casts
+the types to int, so you can put any 32-bit values here.  There is a
+configure option to select the number of events you want to keep.  A
+nice number might be 128, but you can keep up to 1024 if you want.  The
+number must be a power of two.  An "andthen" macro library is provided
+for gdb to help you look at these events.  It is also possible to define
+a different structure for the event storage and cast the data to this
+structure.  For example the following structure is defined in kgdb:
+
+struct kgdb_and_then_struct2 {
+#ifdef CONFIG_SMP
+	int	on_cpu;
+#endif
+	long long at_time;
+	int  	from_ln;
+	char	* in_src;
+	void	*from;
+        int     with_if;
+	struct task_struct *t1;
+	struct task_struct *t2;
+};
+
+If you use this for display, the data elements will be displayed as
+pointers to task_struct entries.  You may want to define your own
+structure to use in casting.  You should only change the last two items
+and you must keep the structure size the same.  Kgdb will handle these
+as 32-bit ints, but within that constraint you can define a structure to
+cast to any 32-bit quantity.  This need only be available to gdb and is
+only used for casting in the display code.
+
+Final Items
+===========
+
+I picked up this code from Amit S. Kale and enhanced it.
+
+If you make some really cool modification to this stuff, or if you
+fix a bug, please let me know.
+
+George Anzinger
+<george@mvista.com>
+
+Amit S. Kale
+<akale@veritas.com>
+
+(First kgdb by David Grothe <dave@gcom.com>)
+
+(modified by Tigran Aivazian <tigran@sco.com>)
+    Putting gdbstub into the kernel config menu.
+
+(modified by Scott Foehner <sfoehner@engr.sgi.com>)
+    Hooks for entering gdbstub at boot time.
+
+(modified by Amit S. Kale <akale@veritas.com>)
+    Threads, ia-32 hw debugging, mp support, console support,
+    nmi watchdog handling.
+
+(modified by George Anzinger <george@mvista.com>)
+    Extended threads to include the idle threads.
+    Enhancements to allow breakpoint() at first C code.
+    Use of module_init() and __setup() to automate the configure.
+    Enhanced the cpu "collection" code to work in early bring-up.
+    Added ability to call functions from gdb
+    Print info thread stuff without going back to schedule()
+    Now collect the "other" cpus with an IPI/ NMI.
--- diff/Documentation/i386/kgdb/kgdbeth.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/kgdbeth.txt	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,92 @@
+KGDB over ethernet
+==================
+
+Authors
+-------
+
+Robert Walsh <rjwalsh@durables.org>  (2.6 port)
+wangdi <wangdi@clusterfs.com>        (2.6 port)
+Matt Mackall <mpm@selenic.com>       (netpoll api)
+San Mehat                            (original 2.4 code)
+
+
+Introduction
+------------
+
+KGDB supports debugging over ethernet (kgdboe) via polling of a given
+network interface. Most cards should be supported automatically.
+Debugging facilities are available as soon as the network driver and
+kgdboe have initialized. Unfortunately, this is too late in the boot
+process for debugging some issues, but works quite well for many
+others. This should not interfere with normal network usage and
+doesn't require a dedicated NIC.
+
+Terminology
+-----------
+
+This document uses the following terms:
+
+  TARGET: the machine being debugged.
+  HOST:   the machine running gdb.
+
+
+Usage
+-----
+
+You need to use the following command-line option on the TARGET kernel:
+
+  kgdboe=[tgt-port]@<tgt-ip>/[dev],[host-port]@<host-ip>/[host-macaddr]
+
+    where
+        tgt-port      source for UDP packets (defaults to 6443)
+        tgt-ip        source IP to use (interface address)
+        dev           network interface (eth0)
+        host-port     HOST UDP port (6442) (not really used)
+        host-ip       IP address for HOST machine
+        host-macaddr  ethernet MAC address for HOST (ff:ff:ff:ff:ff:ff)
+
+  examples:
+
+    kgdboe=7000@192.168.0.1/eth1,7001@192.168.0.2/00:05:3C:04:47:5D
+        this machine is 192.168.0.1 on eth1
+        remote machine is 192.168.0.2 with MAC address 00:05:3C:04:47:5D
+        listen for gdb packets on port 7000
+        send unsolicited gdb packets to port 7001
+
+    kgdboe=@192.168.0.1/,@192.168.0.2/
+        this machine is 192.168.0.1 on default interface eth0
+        remote machine is 192.168.0.2, use default broadcast MAC address
+        listen for gdb packets on default port 6443
+        send unsolicited gdb packets to port 6442
+
+Only packets originating from the configured HOST IP address will be
+accepted by the debugger.
+
+On the HOST side, run gdb as normal and use a remote UDP host as the
+target:
+
+   % gdb ./vmlinux
+   GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
+   Copyright 2003 Free Software Foundation, Inc.
+   GDB is free software, covered by the GNU General Public License, and you are
+   welcome to change it and/or distribute copies of it under certain conditions.
+   Type "show copying" to see the conditions.
+   There is absolutely no warranty for GDB.  Type "show warranty" for details.
+   This GDB was configured as "i386-redhat-linux-gnu"...
+   (gdb) target remote udp:HOSTNAME:6443
+
+You can now continue as if you were debugging over a serial line.
+
+Limitations
+-----------
+
+The current release of this code is exclusive of using kgdb on a
+serial interface, so you must boot without the kgdboe option to use
+serial debugging. Trying to debug the network driver while using it
+will prove interesting.
+
+Bug reports
+-----------
+
+Send bug reports to Robert Walsh <rjwalsh@durables.org> and Matt
+Mackall <mpm@selenic.com>.
--- diff/Documentation/i386/kgdb/loadmodule.sh	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/loadmodule.sh	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,78 @@
+#/bin/sh
+# This script loads a module on a target machine and generates a gdb script.
+# source generated gdb script to load the module file at appropriate addresses
+# in gdb.
+#
+# Usage:
+# Loading the module on target machine and generating gdb script)
+#	[foo]$ loadmodule.sh <modulename>
+#
+# Loading the module file into gdb
+#	(gdb) source <gdbscriptpath>
+#
+# Modify following variables according to your setup.
+#	TESTMACHINE - Name of the target machine
+#	GDBSCRIPTS - The directory where a gdb script will be generated
+#
+# Author: Amit S. Kale (akale@veritas.com).
+#
+# If you run into problems, please check files pointed to by following
+# variables.
+#	ERRFILE - /tmp/<modulename>.errs contains stderr output of insmod
+#	MAPFILE - /tmp/<modulename>.map contains stdout output of insmod
+#	GDBSCRIPT - $GDBSCRIPTS/load<modulename> gdb script.
+
+TESTMACHINE=foo
+GDBSCRIPTS=/home/bar
+
+if [ $# -lt 1 ] ; then {
+	echo Usage: $0 modulefile
+	exit
+} ; fi
+
+MODULEFILE=$1
+MODULEFILEBASENAME=`basename $1`
+
+if [ $MODULEFILE = $MODULEFILEBASENAME ] ; then {
+	MODULEFILE=`pwd`/$MODULEFILE
+} fi
+
+ERRFILE=/tmp/$MODULEFILEBASENAME.errs
+MAPFILE=/tmp/$MODULEFILEBASENAME.map
+GDBSCRIPT=$GDBSCRIPTS/load$MODULEFILEBASENAME
+
+function findaddr() {
+	local ADDR=0x$(echo "$SEGMENTS" | \
+		grep "$1" | sed 's/^[^ ]*[ ]*[^ ]*[ ]*//' | \
+		sed 's/[ ]*[^ ]*$//')
+	echo $ADDR
+}
+
+function checkerrs() {
+	if [ "`cat $ERRFILE`" != "" ] ; then {
+		cat $ERRFILE
+		exit
+	} fi
+}
+
+#load the module
+echo Copying $MODULEFILE to $TESTMACHINE
+rcp $MODULEFILE root@${TESTMACHINE}:
+
+echo Loading module $MODULEFILE
+rsh -l root $TESTMACHINE  /sbin/insmod -m ./`basename $MODULEFILE` \
+	> $MAPFILE 2> $ERRFILE
+checkerrs
+
+SEGMENTS=`head -n 11 $MAPFILE | tail -n 10`
+TEXTADDR=$(findaddr "\\.text[^.]")
+LOADSTRING="add-symbol-file $MODULEFILE $TEXTADDR"
+SEGADDRS=`echo "$SEGMENTS" | awk '//{
+	if ($1 != ".text" && $1 != ".this" &&
+	    $1 != ".kstrtab" && $1 != ".kmodtab") {
+		print " -s " $1 " 0x" $3 " "
+	}
+}'`
+LOADSTRING="$LOADSTRING $SEGADDRS"
+echo Generating script $GDBSCRIPT
+echo $LOADSTRING > $GDBSCRIPT
--- diff/Documentation/laptop-mode.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/laptop-mode.txt	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,480 @@
+How to conserve battery power using laptop-mode
+-----------------------------------------------
+
+Document Author: Bart Samwel (bart@samwel.tk)
+Date created: January 2, 2004
+
+Introduction
+------------
+
+Laptopmode is used to minimize the time that the hard disk needs to be spun up,
+to conserve battery power on laptops. It has been reported to cause significant
+power savings.
+
+Contents
+--------
+
+* Introduction
+* The short story
+* Caveats
+* The details
+* Tips & Tricks
+* Control script
+* ACPI integration
+* Monitoring tool
+
+
+The short story
+---------------
+
+If you just want to use it, run the laptop_mode control script (which is included
+at the end of this document) as follows:
+
+# laptop_mode start
+
+Then set your harddisk spindown time to a relatively low value with hdparm:
+
+hdparm -S 4 /dev/hda
+
+The value -S 4 means 20 seconds idle time before spindown. Your harddisk will
+now only spin up when a disk cache miss occurs, or at least once every 10
+minutes to write back any pending changes.
+
+To stop laptop_mode, remount your filesystems with regular commit intervals
+(e.g., 5 seconds), and run "laptop_mode stop".
+
+
+Caveats
+-------
+
+* The downside of laptop mode is that you have a chance of losing up
+  to 10 minutes of work. If you cannot afford this, don't use it!
+
+* Most desktop hard drives have a very limited lifetime measured in spindown
+  cycles, typically about 50.000 times (it's usually listed on the spec sheet).
+  Check your drive's rating, and don't wear down your drive's lifetime if you
+  don't need to.
+
+* If you mount some of your ext3/reiserfs filesystems with the -n option, then
+  the control script will not be able to remount them correctly. You must set
+  DO_REMOUNTS=0 in the control script, otherwise it will remount them with the
+  wrong options -- or it will fail because it cannot write to /etc/mtab.
+
+* If you have your filesystems listed as type "auto" in fstab, like I did, then
+  the control script will not recognize them as filesystems that need remounting.
+
+The details
+-----------
+
+Laptop-mode is controlled by the flag /proc/sys/vm/laptop_mode. When this
+flag is set, any physical disk read operation (that might have caused the
+hard disk to spin up) causes Linux to flush all dirty blocks. The result
+of this is that after a disk has spun down, it will not be spun up anymore
+to write dirty blocks, because those blocks had already been written
+immediately after the most recent read operation
+
+To increase the effectiveness of the laptop_mode strategy, the laptop_mode
+control script increases dirty_expire_centisecs and dirty_writeback_centisecs in
+/proc/sys/vm to about 10 minutes (by default), which means that pages that are
+dirtied are not forced to be written to disk as often. The control script also
+changes the dirty background ratio, so that background writeback of dirty pages
+is not done anymore. Combined with a higher commit value (also 10 minutes) for
+ext3 or ReiserFS filesystems (also done automatically by the control script),
+this results in concentration of disk activity in a small time interval which
+occurs only once every 10 minutes, or whenever the disk is forced to spin up by
+a cache miss. The disk can then be spun down in the periods of inactivity.
+
+If you want to find out which process caused the disk to spin up, you can
+gather information by setting the flag /proc/sys/vm/block_dump. When this flag
+is set, Linux reports all disk read and write operations that take place, and
+all block dirtyings done to files. This makes it possible to debug why a disk
+needs to spin up, and to increase battery life even more.
+
+If 10 minutes is too much or too little downtime for you, you can configure
+this downtime as follows. In the control script, set the MAX_AGE value to the
+maximum number of seconds of disk downtime that you would like. You should
+then set your filesystem's commit interval to the same value. The dirty ratio
+is also configurable from the control script.
+
+If you don't like the idea of the control script remounting your filesystems
+for you, you can change DO_REMOUNTS to 0 in the script.
+
+Thanks to Kiko Piris, the control script can be used to enable laptop mode on
+both the Linux 2.4 and 2.6 series.
+
+
+Tips & Tricks
+-------------
+
+* Bartek Kania reports getting up to 50 minutes of extra battery life (on top
+  of his regular 3 to 3.5 hours) using very aggressive power management (hdparm
+  -B1) and a spindown time of 5 seconds (hdparm -S1).
+
+* You can spin down the disk while playing MP3, by setting the disk readahead
+  to 8MB (hdparm -a 16384). Effectively, the disk will read a complete MP3 at
+  once, and will then spin down while the MP3 is playing. (Thanks to Bartek
+  Kania.)
+
+* Drew Scott Daniels observed: "I don't know why, but when I decrease the number
+  of colours that my display uses it consumes less battery power. I've seen
+  this on powerbooks too. I hope that this is a piece of information that
+  might be useful to the Laptop Mode patch or it's users."
+
+
+Control script
+--------------
+
+Please note that this control script works for the Linux 2.4 and 2.6 series.
+
+--------------------CONTROL SCRIPT BEGIN------------------------------------------
+#!/bin/sh
+
+# start or stop laptop_mode, best run by a power management daemon when
+# ac gets connected/disconnected from a laptop
+#
+# install as /sbin/laptop_mode
+#
+# Contributors to this script:   Kiko Piris
+#				 Bart Samwel
+#				 Dax Kelson
+# Original Linux 2.4 version by: Jens Axboe
+
+parse_mount_opts () {
+	echo "$*"			| \
+	sed 's/commit=[0-9]*//g'	| \
+	sed 's/,,*/,/g'			| \
+	sed 's/^,//'			| \
+	sed 's/,$//'			| \
+	cat -
+}
+
+KLEVEL="$(uname -r | cut -c1-3)"
+case "$KLEVEL" in
+	"2.4")
+		true
+		;;
+	"2.6")
+		true
+		;;
+	*)
+		echo "Unhandled kernel level: $KLEVEL ('uname -r' = '$(uname -r)')"
+		exit 1
+		;;
+esac
+
+# Shall we remount journaled fs. with appropiate commit interval? (1=yes)
+DO_REMOUNTS=1
+
+# age time, in seconds. should be put into a sysconfig file
+MAX_AGE=600
+
+# Allowed dirty ratio, in pct. should be put into a sysconfig file as well.
+DIRTY_RATIO=40
+
+# kernel default dirty buffer age
+DEF_AGE=30
+DEF_UPDATE=5
+DEF_DIRTY_BACKGROUND_RATIO=10
+DEF_DIRTY_RATIO=40
+
+
+if [ ! -e /proc/sys/vm/laptop_mode ]; then
+	echo "Kernel is not patched with laptop_mode patch."
+	exit 1
+fi
+
+if [ ! -w /proc/sys/vm/laptop_mode ]; then
+	echo "You do not have enough privileges to enable laptop_mode."
+	exit 1
+fi
+
+case "$1" in
+	start)
+		AGE=$((100*$MAX_AGE))
+		echo -n "Starting laptop_mode"
+		case "$KLEVEL" in
+			"2.4")
+				echo "1"				> /proc/sys/vm/laptop_mode
+				echo "30 500 0 0 $AGE $AGE 60 20 0"	> /proc/sys/vm/bdflush
+				;;
+			"2.6")
+				echo "1"				> /proc/sys/vm/laptop_mode
+				echo "$AGE"				> /proc/sys/vm/dirty_writeback_centisecs
+				echo "$AGE"				> /proc/sys/vm/dirty_expire_centisecs
+				echo "$DIRTY_RATIO"			> /proc/sys/vm/dirty_ratio
+				echo "$DIRTY_RATIO"			> /proc/sys/vm/dirty_background_ratio
+				;;
+		esac
+		if [ $DO_REMOUNTS -eq 1 ]; then
+			cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
+				PARSEDOPTS="$(parse_mount_opts "$OPTS")"
+				case "$FST" in
+					"ext3")		mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE ;;
+					"reiserfs")	mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE ;;
+					"xfs")		mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE ;;
+				esac
+			done
+		fi
+		echo "."
+		;;
+	stop)
+		U_AGE=$((100*$DEF_UPDATE))
+		B_AGE=$((100*$DEF_AGE))
+		echo -n "Stopping laptop_mode"
+		case "$KLEVEL" in
+			"2.4")
+				echo "0"				> /proc/sys/vm/laptop_mode
+				echo "30 500 0 0 $U_AGE $B_AGE 60 20 0"	> /proc/sys/vm/bdflush
+				;;
+			"2.6")
+				echo "0"				> /proc/sys/vm/laptop_mode
+				echo "$U_AGE"				> /proc/sys/vm/dirty_writeback_centisecs
+				echo "$B_AGE"				> /proc/sys/vm/dirty_expire_centisecs
+				echo "$DEF_DIRTY_RATIO"			> /proc/sys/vm/dirty_ratio
+				echo "$DEF_DIRTY_BACKGROUND_RATIO"	> /proc/sys/vm/dirty_background_ratio
+				;;
+		esac
+		if [ $DO_REMOUNTS -eq 1 ]; then
+			cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
+				PARSEDOPTS="$(parse_mount_opts "$OPTS")"
+				case "$FST" in
+					"ext3")		mount $DEV -t $FST $MP -o remount,$PARSEDOPTS ;;
+					"reiserfs")	mount $DEV -t $FST $MP -o remount,$PARSEDOPTS ;;
+					"xfs")		mount $DEV -t $FST $MP -o remount,$PARSEDOPTS ;;
+				esac
+			done
+		fi
+		echo "."
+		;;
+	*)
+		echo "$0 {start|stop}"
+		;;
+
+esac
+
+exit 0
+
+--------------------CONTROL SCRIPT END--------------------------------------------
+
+
+ACPI integration
+----------------
+
+Dax Kelson submitted this so that the ACPI acpid daemon will
+kick off the laptop_mode script and run hdparm.
+
+---------------------------/etc/acpi/events/ac_adapter BEGIN-------------------------------------------
+event=ac_adapter
+action=/etc/acpi/actions/battery.sh
+---------------------------/etc/acpi/events/ac_adapter END-------------------------------------------
+
+---------------------------/etc/acpi/actions/battery.sh BEGIN-------------------------------------------
+#!/bin/sh
+
+# cpu throttling
+# cat /proc/acpi/processor/CPU0/throttling for more info
+ACAD_THR=0
+BATT_THR=2
+
+# spindown time for HD (man hdparm for valid values)
+# I prefer 2 hours for acad and 20 seconds for batt
+ACAD_HD=244
+BATT_HD=4
+
+# ac/battery event handler
+
+status=`awk '/^state: / { print $2 }' /proc/acpi/ac_adapter/AC/state`
+
+case $status in
+        "on-line")
+                echo "Setting HD spindown to 2 hours"
+                /sbin/laptop-mode stop
+                /sbin/hdparm -S $ACAD_HD /dev/hda > /dev/null 2>&1
+                /sbin/hdparm -B 255 /dev/hda > /dev/null 2>&1
+                #echo -n $ACAD_CPU:$ACAD_THR > /proc/acpi/processor/CPU0/limit
+                exit 0
+        ;;
+        "off-line")
+                echo "Setting HD spindown to 20 seconds"
+                /sbin/laptop-mode start
+                /sbin/hdparm -S $BATT_HD /dev/hda > /dev/null 2>&1
+                /sbin/hdparm -B 1 /dev/hda > /dev/null 2>&1
+                #echo -n $BATT_CPU:$BATT_THR > /proc/acpi/processor/CPU0/limit
+                exit 0
+        ;;
+esac
+---------------------------/etc/acpi/actions/battery.sh END-------------------------------------------
+
+Monitoring tool
+---------------
+
+Bartek Kania submitted this, it can be used to measure how much time your disk
+spends spun up/down.
+
+---------------------------dslm.c BEGIN-------------------------------------------
+/*
+ * Simple Disk SLeep Monitor
+ *  by Bartek Kania
+ * Licenced under the GPL
+ */
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <linux/hdreg.h>
+
+#ifdef DEBUG
+#define D(x) x
+#else
+#define D(x)
+#endif
+
+int endit = 0;
+
+/* Check if the disk is in powersave-mode
+ * Most of the code is stolen from hdparm.
+ * 1 = active, 0 = standby/sleep, -1 = unknown */
+int check_powermode(int fd)
+{
+    unsigned char args[4] = {WIN_CHECKPOWERMODE1,0,0,0};
+    int state;
+
+    if (ioctl(fd, HDIO_DRIVE_CMD, &args)
+	&& (args[0] = WIN_CHECKPOWERMODE2) /* try again with 0x98 */
+	&& ioctl(fd, HDIO_DRIVE_CMD, &args)) {
+	if (errno != EIO || args[0] != 0 || args[1] != 0) {
+	    state = -1; /* "unknown"; */
+	} else
+	    state = 0; /* "sleeping"; */
+    } else {
+	state = (args[2] == 255) ? 1 : 0;
+    }
+    D(printf(" drive state is:  %s\n", state));
+
+    return state;
+}
+
+char *state_name(int i)
+{
+    if (i == -1) return "unknown";
+    if (i == 0) return "sleeping";
+    if (i == 1) return "active";
+
+    return "internal error";
+}
+
+char *myctime(time_t time)
+{
+    char *ts = ctime(&time);
+    ts[strlen(ts) - 1] = 0;
+
+    return ts;
+}
+
+void measure(int fd)
+{
+    time_t start_time;
+    int last_state;
+    time_t last_time;
+    int curr_state;
+    time_t curr_time = 0;
+    time_t time_diff;
+    time_t active_time = 0;
+    time_t sleep_time = 0;
+    time_t unknown_time = 0;
+    time_t total_time = 0;
+    int changes = 0;
+    float tmp;
+
+    printf("Starting measurements\n");
+
+    last_state = check_powermode(fd);
+    start_time = last_time = time(0);
+    printf("  System is in state %s\n\n", state_name(last_state));
+
+    while(!endit) {
+	sleep(1);
+	curr_state = check_powermode(fd);
+
+	if (curr_state != last_state || endit) {
+	    changes++;
+	    curr_time = time(0);
+	    time_diff = curr_time - last_time;
+
+	    if (last_state == 1) active_time += time_diff;
+	    else if (last_state == 0) sleep_time += time_diff;
+	    else unknown_time += time_diff;
+
+	    last_state = curr_state;
+	    last_time = curr_time;
+
+	    printf("%s: State-change to %s\n", myctime(curr_time),
+		   state_name(curr_state));
+	}
+    }
+    changes--; /* Compensate for SIGINT */
+
+    total_time = time(0) - start_time;
+    printf("\nTotal running time:  %lus\n", curr_time - start_time);
+    printf(" State changed %d times\n", changes);
+
+    tmp = (float)sleep_time / (float)total_time * 100;
+    printf(" Time in sleep state:   %lus (%.2f%%)\n", sleep_time, tmp);
+    tmp = (float)active_time / (float)total_time * 100;
+    printf(" Time in active state:  %lus (%.2f%%)\n", active_time, tmp);
+    tmp = (float)unknown_time / (float)total_time * 100;
+    printf(" Time in unknown state: %lus (%.2f%%)\n", unknown_time, tmp);
+}
+
+void ender(int s)
+{
+    endit = 1;
+}
+
+void usage()
+{
+    puts("usage: dslm [-w <time>] <disk>");
+    exit(0);
+}
+
+int main(int ac, char **av)
+{
+    int fd;
+    char *disk = 0;
+    int settle_time = 60;
+
+    /* Parse the simple command-line */
+    if (ac == 2)
+	disk = av[1];
+    else if (ac == 4) {
+	settle_time = atoi(av[2]);
+	disk = av[3];
+    } else
+	usage();
+
+    if (!(fd = open(disk, O_RDONLY|O_NONBLOCK))) {
+	printf("Can't open %s, because: %s\n", disk, strerror(errno));
+	exit(-1);
+    }
+
+    if (settle_time) {
+	printf("Waiting %d seconds for the system to settle down to "
+	       "'normal'\n", settle_time);
+	sleep(settle_time);
+    } else
+	puts("Not waiting for system to settle down");
+
+    signal(SIGINT, ender);
+
+    measure(fd);
+
+    close(fd);
+
+    return 0;
+}
+---------------------------dslm.c END---------------------------------------------
--- diff/Documentation/must-fix.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/must-fix.txt	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,288 @@
+
+Must-fix bugs
+=============
+
+drivers/char/
+~~~~~~~~~~~~~
+
+o TTY locking is broken.
+
+  o see FIXME in do_tty_hangup().  This causes ppp BUGs in local_bh_enable()
+
+  o Other problems: aviro, dipankar, Alan have details.
+
+  o somebody will have to document the tty driver and ldisc API
+
+drivers/tty
+~~~~~~~~~~~
+
+o viro: tty_driver refcounting, tty/misc/upper levels of sound still not
+  completely fixed.
+
+drivers/block/
+~~~~~~~~~~~~~~
+
+o loop.c: Concurrent write access on block devices might cause a deadlock
+  of the complete system. See:
+  http://marc.theaimsgroup.com/?l=linux-kernel&m=106275365925769&w==
+  http://bugzilla.kernel.org/show_bug.cgi?id=1198
+  Thread of possible fix:
+  http://www.kerneli.org/pipermail/cryptoapi-devel/2003-October/000676.html
+
+  (Fruhwirth Clemens)
+
+o ideraid hasn't been ported to 2.5 at all yet.
+
+  We need to understand whether the proposed BIO split code will suffice
+  for this.
+
+drivers/input/
+~~~~~~~~~~~~~~
+
+o rmk: unconverted keyboard/mouse drivers (there's a deadline of 2.6.0
+  currently on these remaining in my/Linus' tree.)
+
+o viro: large absence of locking.
+
+o viro: parport is nearly as bad as that and there the code is more hairy.
+  IMO parport is more of "figure out what API changes are needed for its
+  users, get them done ASAP, then fix generic layer at leisure"
+
+o (Albert Cahalan) Lots of people (check Google) get this message from the
+  kernel:
+
+  psmouse.c: Lost synchronization, throwing 2 bytes away.
+
+  (the number of bytes will be 1, 2, or 3)
+
+  At work, I get it when there is heavy NFS traffic.  The mouse goes crazy,
+  jumping around and doing random cut-and-paste all over everything.  This
+  is with a decently fast and modern PC.
+
+o There seem to be too many reports of keyboards and mice failing or acting
+  strangely.
+
+
+drivers/misc/
+~~~~~~~~~~~~~
+
+o rmk: UCB1[23]00 drivers, currently sitting in drivers/misc in the ARM
+  tree.  (touchscreen, audio, gpio, type device.)
+
+  These need to be moved out of drivers/misc/ and into real places
+
+o viro: actually, misc.c has a good chance to die.  With cdev-cidr that's
+  trivial.
+
+drivers/net/
+~~~~~~~~~~~~
+
+drivers/net/irda/
+~~~~~~~~~~~~~~~~~
+
+  (Jean Tourrilhes)
+
+o irport need to be converted to sir-kthread
+
+o dongle drivers need to be converted to sir-dev (in progress)
+
+o new drivers (irtty-sir/smsc-ircc2/donauboe) need more testing (in progress)
+
+
+drivers/pci/
+~~~~~~~~~~~~
+
+o alan: Some cardbus crashes the system
+
+  (bugzilla, please?)
+
+drivers/pcmcia/
+~~~~~~~~~~~~~~~
+
+o alan: This is a locking disaster.
+
+  (rmk, brodo: in progress)
+
+drivers/pld/
+~~~~~~~~~~~~
+
+o rmk: EPXA (ARM platform) PLD hotswap drivers (drivers/pld)
+
+  (rmk: will work out what to do here.  maybe drivers/arm/)
+
+drivers/video/
+~~~~~~~~~~~~~~
+
+o Lots of drivers don't compile, others do but don't work.
+
+drivers/scsi/
+~~~~~~~~~~~~~
+
+o Convert am53c974, dpt_i2o, initio and pci2220i to DMA-mapping
+
+o Make inia100, cpqfc, pci2000 and dc390t compile
+
+o Convert
+
+   wd33c99 based: a2091 a3000 gpv11 mvme174 sgiwd93
+
+   53c7xx based: amiga7xxx bvme6000 mvme16x initio am53c974 pci2000
+   pci2220i dc390t
+
+  To new error handling
+
+  It also might be possible to shift the 53c7xx based drivers over to
+  53c700 which does the new EH stuff, but I don't have the hardware to check
+  such a shift.
+
+  For the non-compiling stuff, I've probably missed a few that just aren't
+  compilable on my platforms, so any updates would be welcome.  Also, are
+  some of our non-compiling or unconverted drivers obsolete?
+
+fs/
+~~~
+
+o AIO/direct-IO writes can race with truncate and wreck filesystems.
+  (Badari has a patch)
+
+o viro: fs/char_dev.c needs removal of aeb stuff and merge of cdev-cidr.
+  In progress.
+
+o forward-port sct's O_DIRECT fixes (Badari has a patch)
+
+o viro: there is some generic stuff for namei/namespace/super, but that's a
+  slow-merge and can go in 2.6 just fine
+
+o trond: NFS has a mmap-versus-truncate problem (fixed? needs testing)
+
+o trond: NFSv4 client, bugs in lockd, RPSEC_GSS for NFSv[23], some atomic open
+  bits. more info: http://www.fys.uio.no/~trondmy/src/Linux-2.6.x/2.6.0-test11/
+
+kernel/sched.c
+~~~~~~~~~~~~~~
+
+o Starvation, general interactivity need close monitoring.
+
+o SMT aware scheduler (Ingo, Rusty, Nick have implementations)
+
+kernel/
+~~~~~~~
+
+o Alan: 32bit uid support is *still* broken for process accounting.
+
+  Create a 32bit uid, turn accounting on.  Shock horror it doesn't work
+  because the field is 16bit.  We need an acct structure flag day for 2.6
+  IMHO
+
+  (alan has patch)
+
+o viro: core sysctl code is racy.  And its interaction wiuth sysfs
+
+o (ingo) rwsems (on x86) are limited to 32766 waiting processes.  This
+  means that setting pid_max to above 32K is unsafe :-(
+
+  An option is to use CONFIG_RWSEM_GENERIC_SPINLOCK variant all the time,
+  for all archs, and not inline any part of the ops.
+
+lib/kobject.c
+~~~~~~~~~~~~~
+
+o kobject refcounting (comments from Al Viro):
+
+  _anything_ can grab a temporary reference to kobject.  IOW, if kobject is
+  embedded into something that could be freed - it _MUST_ have a destructor
+  and that destructor _MUST_ be the destructor for containing object.
+
+  Any violation of the above (and we already have a bunch of those) is a
+  user-triggerable memory corruption.
+
+  We can tolerate it for a while in 2.5 (e.g.  during work on susbsystem we
+  can decide to switch to that way of handling objects and have subsystem
+  vulnerable for a while), but all such windows must be closed before 2.6
+  and during 2.6 we can't open them at all.
+
+o All block drivers which control multiple gendisks with a single
+  request_queue are broken, due to one-to-one assumptions in the request
+  queue sysfs hookup.
+
+mm/
+~~~
+
+o GFP_DMA32 (or something like that).  Lots of ideas.  jejb, zaitcev,
+  willy, arjan, wli.
+
+  Specifically, 64-bit systems need to be able to enforce 32-bit addressing
+  limits for device metadata like network cards' ring buffers and SCSI
+  command descriptors.
+
+o access_process_vm() doesn't flush right.  We probably need new flushing
+  primitives to do this (davem?)
+
+
+modules
+~~~~~~~
+
+  (Rusty)
+
+net/
+~~~~
+
+  (davem)
+
+o UDP apps can in theory deadlock, because the ip_append_data path can end
+  up sleeping while the socket lock is held.
+
+  It is OK to sleep with the socket held held, normally.  But in this case
+  the sleep happens while waiting for socket memory/space to become
+  available, if another context needs to take the socket lock to free up the
+  space we could hang.
+
+  I sent a rough patch on how to fix this to Alexey, and he is analyzing
+  the situation.  I expect a final fix from him next week or so.
+
+o Semantics for IPSEC during operations such as TCP connect suck currently.
+
+  When we first try to connect to a destination, we may need to ask the
+  IPSEC key management daemon to resolve the IPSEC routes for us.  For the
+  purposes of what the kernel needs to do, you can think of it like ARP.  We
+  can't send the packet out properly until we resolve the path.
+
+  What happens now for IPSEC is basically this:
+
+  O_NONBLOCK: returns -EAGAIN over and over until route is resolved
+
+  !O_NONBLOCK: Sleeps until route is resolved
+
+  These semantics are total crap.  The solution, which Alexey is working
+  on, is to allow incomplete routes to exist.  These "incomplete" routes
+  merely put the packet onto a "resolution queue", and once the key manager
+  does it's thing we finish the output of the packet.  This is precisely how
+  ARP works.
+
+  I don't know when Alexey will be done with this.
+
+net/*/netfilter/
+~~~~~~~~~~~~~~~~
+
+  (Rusty)
+
+sound/
+~~~~~~
+
+global
+~~~~~~
+
+o viro: 64-bit dev_t (not a mustfix for 2.6.0). 32-bit dev_t is done, 64-bit
+  means extra work on nfsd/raid/etc.
+
+o alan: Forward port 2.4 fixes
+  - Chris Wright: Security fixes including execve holes, execve vs proc races
+
+o There are about 60 or 70 security related checks that need doing
+  (copy_user etc) from Stanford tools.  (badari is looking into this, and
+  hollisb)
+
+o A couple of hundred real looking bugzilla bugs
+
+o viro: cdev rework. Mostly done.
+
--- diff/Documentation/networking/netconsole.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/networking/netconsole.txt	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,57 @@
+
+started by Ingo Molnar <mingo@redhat.com>, 2001.09.17
+2.6 port and netpoll api by Matt Mackall <mpm@selenic.com>, Sep 9 2003
+
+Please send bug reports to Matt Mackall <mpm@selenic.com>
+
+This module logs kernel printk messages over UDP allowing debugging of
+problem where disk logging fails and serial consoles are impractical.
+
+It can be used either built-in or as a module. As a built-in,
+netconsole initializes immediately after NIC cards and will bring up
+the specified interface as soon as possible. While this doesn't allow
+capture of early kernel panics, it does capture most of the boot
+process.
+
+It takes a string configuration parameter "netconsole" in the
+following format:
+
+ netconsole=[src-port]@[src-ip]/[<dev>],[tgt-port]@<tgt-ip>/[tgt-macaddr]
+
+   where
+        src-port      source for UDP packets (defaults to 6665)
+        src-ip        source IP to use (interface address)
+        dev           network interface (eth0)
+        tgt-port      port for logging agent (6666)
+        tgt-ip        IP address for logging agent
+        tgt-macaddr   ethernet MAC address for logging agent (broadcast)
+
+Examples:
+
+ linux netconsole=4444@10.0.0.1/eth1,9353@10.0.0.2/12:34:56:78:9a:bc
+
+  or
+
+ insmod netconsole netconsole=@/,@10.0.0.2/
+
+Built-in netconsole starts immediately after the TCP stack is
+initialized and attempts to bring up the supplied dev at the supplied
+address.
+
+The remote host can run either 'netcat -u -l -p <port>' or syslogd.
+
+WARNING: the default target ethernet setting uses the broadcast
+ethernet address to send packets, which can cause increased load on
+other systems on the same ethernet segment.
+
+NOTE: the network device (eth1 in the above case) can run any kind
+of other network traffic, netconsole is not intrusive. Netconsole
+might cause slight delays in other traffic if the volume of kernel
+messages is high, but should have no other impact.
+
+Netconsole was designed to be as instantaneous as possible, to
+enable the logging of even the most critical kernel bugs. It works
+from IRQ contexts as well, and does not enable interrupts while
+sending packets. Due to these unique needs, configuration can not
+be more automatic, and some fundamental limitations will remain:
+only IP networks, UDP packets and ethernet devices are supported.
--- diff/Documentation/sched-domains.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/sched-domains.txt	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,55 @@
+Each CPU has a "base" scheduling domain (struct sched_domain). These are
+accessed via cpu_sched_domain(i) and this_sched_domain() macros. The domain
+hierarchy is built from these base domains via the ->parent pointer. ->parent
+MUST be NULL terminated, and domain structures should be per-CPU as they
+are locklessly updated.
+
+Each scheduling domain spans a number of CPUs (stored in the ->span field).
+A domain's span MUST be a superset of it child's span, and a base domain
+for CPU i MUST span at least i. The top domain for each CPU will generally
+span all CPUs in the system although strictly it doesn't have to, but this
+could lead to a case where some CPUs will never be given tasks to run unless
+the CPUs allowed mask is explicitly set. A sched domain's span means "balance
+process load among these CPUs".
+
+Each scheduling domain must have one or more CPU groups (struct sched_group)
+which are organised as a circular one way linked list from the ->groups
+pointer. The union of cpumasks of these groups MUST be the same as the
+domain's span. The intersection of cpumasks from any two of these groups
+MUST be the empty set. The group pointed to by the ->groups pointer MUST
+contain the CPU to which the domain belongs. Groups may be shared among
+CPUs as they contain read only data after they have been set up.
+
+Balancing within a sched domain occurs between groups. That is, each group
+is treated as one entity. The load of a group is defined as the sum of the
+load of each of its member CPUs, and only when the load of a group becomes
+out of balance are tasks moved between groups.
+
+In kernel/sched.c, rebalance_tick is run periodically on each CPU. This
+function takes its CPU's base sched domain and checks to see if has reached
+its rebalance interval. If so, then it will run load_balance on that domain.
+rebalance_tick then checks the parent sched_domain (if it exists), and the
+parent of the parent and so forth.
+
+*** Implementing sched domains ***
+The "base" domain will "span" the first level of the hierarchy. In the case
+of SMT, you'll span all siblings of the physical CPU, with each group being
+a single virtual CPU.
+
+In SMP, the parent of the base domain will span all physical CPUs in the
+node. Each group being a single physical CPU. Then with NUMA, the parent
+of the SMP domain will span the entire machine, with each group having the
+cpumask of a node. Or, you could do multi-level NUMA or Opteron, for example,
+might have just one domain covering its one NUMA level.
+
+The implementor should read comments in include/linux/sched.h:
+struct sched_domain fields, SD_FLAG_*, SD_*_INIT to get an idea of
+the specifics and what to tune.
+
+Implementors should change the line
+#undef SCHED_DOMAIN_DEBUG
+to
+#define SCHED_DOMAIN_DEBUG
+in kernel/sched.c as this enables an error checking parse of the sched domains
+which should catch most possible errors (described above). It also prints out
+the domain structure in a visual format.
--- diff/Documentation/should-fix.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/should-fix.txt	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,545 @@
+Not-ready features and speedups
+===============================
+
+Legend:
+
+PRI1:	We're totally lame if this doesn't get in
+PRI2:	Would be nice
+PRI3:	Not very important
+
+drivers/block/
+~~~~~~~~~~~~~~
+
+o viro: paride drivers need a big cleanup. Partially done, but ATAPI drivers
+  need serious work and bug fixing.
+
+  PRI2
+
+drivers/char/rtc/
+~~~~~~~~~~~~~~~~~
+
+o rmk, trini: add support for alarms to the existing generic rtc driver.
+
+  PRI2
+
+console drivers
+~~~~~~~~~~~~~~~
+  (Pavel Machek <pavel@ucw.cz>)
+
+o There are few must-fix bugs in cursor handling.
+
+o Play with gpm selection for a while and your cursor gets corrupted with
+  random dots. Ouch.
+
+device mapper
+~~~~~~~~~~~~~
+
+o ioctl interface cleanup patch is ready (redo the structure layouts)
+
+  PRI1
+
+o A port of the 2.4 snapshot and mirror targets is in progress
+
+  PRI1
+
+o the fs interface to dm needs to be redone.  gregkh was going to work on
+  this.  viro is interested in seeing work thus-far.
+
+  PRI2
+
+drivers/net/wireless/
+~~~~~~~~~~~~~~~~~~~~~
+
+  (Jean Tourrilhes <jt@bougret.hpl.hp.com>)
+
+o get HostAP driver in the kernel.  No consolidation of the 802.11
+  management across driver can happen until this one is in (which is probably
+  2.7.X material).  I think Jouni is mostly ready but didn't find time for
+  it.
+
+  PRI2
+
+o get more wireless drivers into the kernel.  The most "integrable" drivers
+  at this point seem the NWN driver, Pavel's Spectrum driver.
+
+  PRI1
+
+drivers/usb/gadget/
+~~~~~~~~~~~~~~~~~~~
+
+o rmk: SA11xx USB client/gadget code (David B has been doing some work on
+  this, and keeps trying to prod me, but unfortunately I haven't had the time
+  to look at his work, sorry David.)
+
+  PRI3
+
+fs/
+~~~
+
+o ext3 and ext2 block allocators have serious failure modes - interleaved
+  allocations.
+
+  PRI3
+
+o Integrate Chris Mason's 2.4 reiserfs ordered data and data journaling
+  patches.  They make reiserfs a lot safer.
+
+  Ordered: PRI2
+  data journalled: PRI3
+
+o viro: convert more filesystems to use lib/parser.c for options.
+
+  PRI2
+
+o aio: fs IO isn't async at present.  suparna has restart patches, they're
+  in -mm.  Need to get Ben to review/comment.
+
+  PRI1.
+
+o drepper: various filesystems use ->pid wrongly
+
+  PRI1
+
+o hch: devfs: there's a fundamental lookup vs devfsd race that's only
+  fixable by introducing a lookup vs devfs deadlock.  I can't see how this is
+  fixable without getting rid of the current devfsd design.  Mandrake seems
+  to have a workaround for this so this is at least not triggered so easily,
+  but that's not what I'd consider a fix..
+
+  PRI2
+
+kernel/
+~~~~~~~
+
+o rusty: Zippel's Reference count simplification.  Tricky code, but cuts
+  about 120 lines from module.c.  Patch exists, needs stressing.
+
+  PRI3
+
+o rusty: Fix module-failed-init races by starting module "disabled".  Patch
+  exists, requires some subsystems (ie.  add_partition) to explicitly say
+  "make module live now".  Without patch we are no worse off than 2.4 etc.
+
+  PRI1
+
+o Integrate userspace irq balancing daemon.
+
+  PRI2
+
+o kexec.  Seems to work, was in -mm.
+
+  PRI3
+
+o rmk: lib/inflate.c must not use static variables (causes these to be
+  referenced via GOTOFF relocations in PIC decompressor.  We have a PIC
+  decompressor to avoid having to hard code a per platform zImage link
+  address into the makefiles.)
+
+  PRI2
+
+o klibc merge?
+
+  PRI2
+
+mm/
+~~~
+
+o dropbehind for large files
+
+  PRI2
+
+net/
+~~~~
+
+  (davem)
+
+o Real serious use of IPSEC is hampered by lack of MPLS support.  MPLS is a
+  switching technology that works by switching based upon fixed length labels
+  prepended to packets.  Many people use this and IPSEC to implement VPNs
+  over public networks, it is also used for things like traffic engineering.
+
+  A good reference site is:
+
+	http://www.mplsrc.com/
+
+  Anyways, an existing (crappy) implementation exists.  I've almost
+  completed a rewrite, I should have something in the tree next week.
+
+  PRI1
+
+o Sometimes we generate IP fragments when it truly isn't necessary.
+
+  The way IP fragmentation is specified, each fragment must be modulo 8
+  bytes in length.  So suppose the device has an MTU that is not 0 modulo 8,
+  ethernet even classifies in this way.  1500 == (8 * 187) + 4
+
+  Our IP fragmenting engine can fragment on packets that are sized within
+  the last modulo 8 bytes of the MTU.  This happens in obscure cases, but it
+  does happen.
+
+  I've proposed a fix to Alexey, whereby very late in the output path we
+  check the packet, if we fragmented but the data length would fit into the
+  MTU we unfragment the packet.
+
+  This is low priority, because technically it creates suboptimal behavior
+  rather than mis-operation.
+
+  PRI1
+
+net/*/netfilter/
+~~~~~~~~~~~~~~~~
+
+o Lots of misc. cleanups, which are happening slowly.
+
+  PRI2
+
+power management
+~~~~~~~~~~~~~~~~
+
+o Pat and Pavel disagree over swsusp. Need to sort that out.
+
+  PRI2
+
+o Frame buffer restore codepaths (that requires some deep PCI magic)
+
+  PRI2
+
+o XFree86 hooks
+
+  PRI2
+
+o AGP restoration
+
+  PRI2
+
+o DRI restoration
+
+  (davej/Alan: not super-critical, can crash laptop on restore.  davej
+  looking into it.)
+
+  PRI2
+
+o IDE suspend/resume without races (Ben is looking at this a little)
+
+  PRI2
+
+o Pat: There are already CPU device structures; MTRRs should be a
+  dynamically registered interface of CPUs, which implies there needs
+  to be some other glue to know that there are MTRRs that need to be
+  saved/restored.
+
+  PRI1
+
+global
+~~~~~~
+
+o We need a kernel side API for reporting error events to userspace (could
+  be async to 2.6 itself)
+
+  (Prototype core based on netlink exists)
+
+  PRI2
+
+o Kai: Introduce a sane, easy and standard way to build external modules
+  - make clean and make modules_install are both broken
+
+  PRI2
+
+drivers
+~~~~~~~
+
+o Alan: Cardbus/PCMCIA requires all Russell's stuff is merged to do
+  multiheader right and so on
+
+  PRI1
+
+drivers/acpi/
+~~~~~~~~~~~~~
+
+o Fix acpi for all newer IBM Thinkpads see
+  http://bugme.osdl.org/show_bug.cgi?id=1038 for more information
+
+o alan: VIA APIC stuff is one bit of this, there are also some other
+  reports that were caused by ACPI not setting level v edge trigger some
+  times
+
+  PRI1
+
+o mochel: it seems the acpi irq routing code could use a serious rewrite.
+
+  grover: The problem is the ACPI irq routing code is trying to piggyback
+  on the existing MPS-specific data structures, and it's generally a hack.
+  So yes mochel is right, but it is also purging MPS-ities from common code
+  as well.  I've done some preliminary work in this area and it doesn't seem
+  to break anything (yet) but a rewrite in this area imho should not be
+  rushed out the door.  And, I think the above bugs can be fixed w/o the
+  rewrite.
+
+  PRI2
+
+o mochel: ACPI suspend doesn't work.  Important, not cricital.  Pat is
+  working it.
+
+  PRI2
+
+drivers/block/
+~~~~~~~~~~~~~~
+
+o More testing of floppy
+
+  PRI3
+
+drivers/char/
+~~~~~~~~~~~~~
+
+
+drivers/ide/
+~~~~~~~~~~~~
+
+  (Alan)
+
+o IDE PIO has occasional unexplained PIO disk eating reports
+
+  PRI1
+
+o IDE has multiple zillions of races/hangs in 2.5 still
+
+  PRI1
+
+o IDE scsi needs rewriting
+
+  PRI2
+
+o IDE needs significant reworking to handle Simplex right
+
+  PRI2
+
+o IDE hotplug handling for 2.5 is completely broken still
+
+  PRI2
+
+o There are lots of other IDE bugs that wont go away until the taskfile
+  stuff is included, the locking bugs that allow any user to hang the IDE
+  layer in 2.5, and some other updates are forward ported.  (esp.  HPT372N).
+
+  PRI1
+
+drivers/isdn/
+~~~~~~~~~~~~~
+
+  (Kai, rmk)
+
+o isdn_tty locking is completely broken (cli() and friends)
+
+  PRI2
+
+o fix other drivers
+
+  PRI2
+
+o lots more cleanups, adaption to recent APIs etc
+
+  PRI3
+
+o fixup tty-based ISDN drivers which provide TIOCM* ioctls (see my recent
+  3-set patch for serial stuff)
+
+  Alternatively, we could re-introduce the fallback to driver ioctl parsing
+  for these if not enough drivers get updated.
+
+  PRI3
+
+drivers/net/
+~~~~~~~~~~~~
+
+o davej: Either Wireless network drivers or PCMCIA broke somewhen.  A
+  configuration that worked fine under 2.4 doesn't receive any packets.  Need
+  to look into this more to make sure I don't have any misconfiguration that
+  just 'happened to work' under 2.4
+
+  PRI1
+
+drivers/scsi/
+~~~~~~~~~~~~~
+
+o jejb: qlogic -
+
+  o Merge the feral driver.  It covers all qlogic chips: 1020 all the way
+    up to 23xxx. http://linux-scsi.bkbits.net/scsi-isp-2.5
+
+  o qla2xxx: only for FC chips.  Has significant build issues.  hch
+    promises to send me a "must fix" list for this.
+    http://linux-scsi.bkbits.net/scsi-qla2xxx-2.5
+
+  PRI2
+
+o hch, Mike Anderson, Badari Pulavarty: scsi locking issues
+
+  o there are lots of members of struct Scsi_Host/scsi_device/scsi_cmnd
+    with very unclear locking, many of them probably want to become
+    atomic_t's or bitmaps (for the 1bit bitfields).
+
+  o there's lots of volatile abuse in the scsi code that needs to be
+    thought about.
+
+  o there's some global variables incremented without any locks
+
+  PRI2
+
+sound/
+~~~~~~
+
+o rmk: several OSS drivers for SA11xx-based hardware in need of
+  ALSA-ification and L3 bus support code for these.
+
+o rmk: need to complete ALSA-ification of the WaveArtist driver for both
+  NetWinder and other stuff (there's some fairly fundamental differences in
+  the way the mixer needs to be handled for the NetWinder.)
+
+  (Issues with forward-porting 2.4 bugfixes.)
+  (Killing off OSS is 2.7 material)
+
+PRI2
+
+arch/i386/
+~~~~~~~~~~
+
+o Also PC9800 merge needs finishing to the point we want for 2.6 (not all).
+
+  PRI3
+
+o davej: PAT support (for mtrr exhaustion w/ AGP)
+
+  PRI2
+
+o 2.5.x won't boot on some 440GX
+
+  alan: Problem understood now, feasible fix in 2.4/2.4-ac.  (440GX has two
+  IRQ routers, we use the $PIR table with the PIIX, but the 440GX doesnt use
+  the PIIX for its IRQ routing).  Fall back to BIOS for 440GX works and Intel
+  concurs.
+
+  PRI1
+
+o 2.5.x doesn't handle VIA APIC right yet.
+
+  1. We must write the PCI_INTERRUPT_LINE
+
+  2. We have quirk handlers that seem to trash it.
+
+  PRI1
+
+o ECC driver questions are not yet sorted (DaveJ is working on this) (Dan
+  Hollis)
+
+  alan: ECC - I have some test bits from Dan's stuff - they need no kernel
+  core changes for most platforms.  That means we can treat it as a random
+  driver merge.
+
+  PRI3
+
+o alan: 2.4 has some fixes for tsc handling bugs.  One where some bioses in
+  SMM mode mess up our toggle on the time high/low or mangle the counter and
+  one where a few chips need religious use of _p for timer access and we
+  don't do that.  This is forward porting little bits of fixup.
+
+  ACPI HZ stuff we can't trap - a lot of ACPI is implemented as outb's
+  triggering SMM traps
+
+  PRI1
+
+arch/x86_64/
+~~~~~~~~~~~~
+
+  (Andi)
+
+o time handling is broken. Need to move up 2.4 time.c code.
+
+  PRI1
+
+o NMI watchdog seems to tick too fast
+
+  PRI2
+
+o need to coredump 64bit vsyscall code with dwarf2
+
+  PRI2
+
+o move 64bit signal trampolines into vsyscall code and add dwarf2 for it.
+  (in progress)
+
+  PRI1
+
+o describe kernel assembly with dwarf2 annotations for kgdb
+
+  PRI3
+
+arch/alpha/
+~~~~~~~~~~~
+
+o rth: Ptrace writes are broken.  This means we can't (reliably) set
+  breakpoints or modify variables from gdb.
+
+  PRI1
+
+arch/arm/
+~~~~~~~~~
+
+o rmk: missing raw keyboard translation tables for all ARM machines.
+  Haven't even looked into this at all.  This could be messy since there
+  isn't an ARM architecture standard.  I'm presently hoping that it won't be
+  an issue.  If it does, I guess we'll see drivers/char/keyboard.c explode.
+
+  PRI2
+
+arch/others/
+~~~~~~~~~~~~
+
+o SH needs resyncing, as do some other ports. SH64 needs merging.
+  No impact on mainstream platforms hopefully.
+
+  PRI2
+
+arch/s390/
+~~~~~~~~~
+
+o A nastly memory management problem causes random crashes.  These appear
+  to be fixed/hidden by the objrmap patch, more investigation is needed.
+
+  PRI1
+
+drivers/s390/
+~~~~~~~~~~~~~
+
+o Early userspace and 64 bit dev_t will allow the removal of most of
+  dasd_devmap.c and dasd_genhd.c.
+
+  PRI2
+
+o The 3270 console driver needs to be replaced with a working one
+  (prototype is there, needs to be finished).
+
+  PRI2
+
+o Minor interface changes are pending in cio/ when the z990 machines are
+  out.
+
+  PRI2
+
+o Jan Glauber is working on a fix for the timer issues related to running
+  on virtualized CPUs (wall-clock vs.  cpu time).
+
+  PRI1
+
+o a block device driver for ramdisks shared among virtual machines
+
+  PRI3
+
+o driver for crypto hardware
+
+  PRI3
+
+o 'claw' network device driver
+
+  PRI3
+
--- diff/Documentation/sound/alsa/MIXART.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/sound/alsa/MIXART.txt	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,96 @@
+    Alsa driver for Digigram miXart8 and miXart8AES/EBU soundcards
+	    Digigram <alsa@digigram.com>
+
+
+GENERAL
+=======
+
+The miXart8 is a multichannel audio processing and mixing soundcard
+that has 4 stereo audio inputs and 4 stereo audio outputs.
+The miXart8AES/EBU is the same with a add-on card that offers further
+4 digital stereo audio inputs and outputs.
+Furthermore the add-on card offers external clock synchronisation
+(AES/EBU, Word Clock, Time Code and Video Synchro)
+
+The mainboard has a PowerPC that offers onboard mpeg encoding and
+decoding, samplerate conversions and various effects.
+
+The driver don't work properly at all until the certain firmwares
+are loaded, i.e. no PCM nor mixer devices will appear.
+Use the mixartloader that can be found in the alsa-tools package.
+
+
+VERSION 0.1.0
+=============
+
+One miXart8 board will be represented as 4 alsa cards, each with 1
+stereo analog capture 'pcm0c' and 1 stereo analog playback 'pcm0p' device.
+With a miXart8AES/EBU there is in addition 1 stereo digital input
+'pcm1c' and 1 stereo digital output 'pcm1p' per card.
+
+Formats
+-------
+U8, S16_LE, S16_BE, S24_3LE, S24_3BE, FLOAT_LE, FLOAT_BE
+Sample rates : 8000 - 48000 Hz continously
+
+Playback
+--------
+For instance the playback devices are configured to have max. 4
+substreams performing hardware mixing. This could be changed to a
+maximum of 24 substreams if wished.
+Mono files will be played on the left and right channel. Each channel
+can be muted for each stream to use 8 analog/digital outputs seperately.
+
+Capture
+-------
+There is one substream per capture device. For instance only stereo
+formats are supported.
+
+Mixer
+-----
+<Master> and <Master Capture> : analog volume control of playback and capture PCM.
+<PCM 0-3> and <PCM Capture> : digital volume control of each analog substream.
+<AES 0-3> and <AES Capture> : digital volume control of each AES/EBU substream.
+<Monitoring> : Loopback from 'pcm0c' to 'pcm0p' with digital volume
+and mute control.
+
+Rem : for best audio quality try to keep a 0 attenuation on the PCM
+and AES volume controls which is set by 219 in the range from 0 to 255
+(about 86% with alsamixer)
+
+
+NOT YET IMPLEMENTED
+===================
+
+- external clock support (AES/EBU, Word Clock, Time Code, Video Sync)
+- MPEG audio formats
+- mono record
+- on-board effects and samplerate conversions
+- linked streams
+
+
+FIRMWARE
+========
+
+For loading the firmware automatically after the module is loaded, use
+the post-install command.  For example, add the following entry to
+/etc/modprobe.conf for miXart driver:
+
+	install snd-mixart /sbin/modprobe --first-time -i snd-mixart && \
+			   /usr/bin/mixartloader
+(for 2.2/2.4 kernels, add "post-install snd-mixart /usr/bin/vxloader" to
+ /etc/modules.conf, instead.)
+
+The firmware binaries are installed on /usr/share/alsa/firmware
+(or /usr/local/share/alsa/firmware, depending to the prefix option of
+configure).  There will be a miXart.conf file, which define the dsp image
+files.
+
+The firmware files are copyright by Digigram SA
+
+
+COPYRIGHT
+=========
+
+Copyright (c) 2003 Digigram SA <alsa@digigram.com>
+Distributalbe under GPL.
--- diff/Documentation/usb/mtouchusb.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/usb/mtouchusb.txt	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,85 @@
+CHANGES
+
+- Created based off of scanner & INSTALL from the original touchscreen
+  driver on freshmeat (http://freshmeat.net/projects/3mtouchscreendriver)
+- Amended for linux-2.4.18, then 2.4.19
+
+- Complete rewrite using Linux Input in 2.6.3
+   Unfortunately no calibration support at this time
+
+
+DRIVER NOTES:
+
+Installation is simple, you only need to add Linux Input, Linux USB, and the 
+driver to the kernel.  The driver can also be optionally built as a module.
+
+If you have another MicroTouch device that you wish to experiment with
+or try using this driver with, but the Vendor and Product ID's are not 
+coded in, don't despair.  If the driver was compiled as a module, you can 
+pass options to the driver.  Simply try:
+
+  /sbin/modprobe mtouchusb vendor=0x#### product=0x****
+
+If it works, send me the iVendor & iProduct (or a patch) and I will add...
+
+This driver appears to be one of possible 2 Linux USB Input Touchscreen
+drivers.  Although 3M produces a binary only driver available for
+download, I persist in updating this driver since I would like to use the
+touchscreen for embedded apps using QTEmbedded, DirectFB, etc. So I feel the
+logical choice is to use Linux Imput.
+
+A little info about the MicroTouch USB controller (14-206):
+
+Y is inverted, and the device has a total possible resolution of 0 - 65535.
+
+Y is inverted by the driver by:
+
+        input.absmin[ABS_Y] =  MTOUCHUSB_MAX_YC;
+        input.absmax[ABS_Y] =  MTOUCHUSB_MIN_YC;
+
+absmin & absmax are also used to scale the data, sine it is rather high 
+resolution.
+
+    ---------------touch screen area-----------------
+    I                        MicroTouch (xmax,ymax) @I
+    I                      X                         I
+    I   ########visible monitor area##############   I
+    I   #@ (xmin,ymin)                           #   I
+    I   #                                        #   I
+    I   #                                        #   I
+    I   #                                        #   I
+    I   #                                        #   I
+    I   #                                        #   I
+    I Y #                                        #   I
+    I   #                                        #   I
+    I   #                                        #   I
+    I   #                                        #   I
+    I   #                                        #   I
+    I   #                                        #   I
+    I   #                           (xmax,ymax) @#   I
+    I   ##########################################   I
+    I                                                I
+    I@ MicroTouch (xmin,ymin)                        I
+    -------------------------------------------------
+
+Currently there is no way to calibrate the device via this driver.  Perhaps 
+at some point an abstract function will be placed into evdev so generic 
+functions like calibrations, resets, and vendor information can be requested 
+(And the drivers would handle the vendor specific tasks).
+
+ADDITIONAL INFORMATION/UPDATES:
+
+http://groomlakelabs.com/grandamp/code/microtouch/
+
+TODO:
+
+Implement a control urb again to handle requests to and from the device
+such as calibration, etc.
+
+DISCLAMER:
+
+I am not a MicroTouch/3M employee, nor have I ever been.  3M does not support 
+this driver!  If you want touch drivers only supported within X, please go to:
+
+http://www.3m.com/3MTouchSystems/downloads/
+
--- diff/arch/i386/kernel/entry_trampoline.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/i386/kernel/entry_trampoline.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,73 @@
+/*
+ * linux/arch/i386/kernel/entry_trampoline.c
+ *
+ * (C) Copyright 2003 Ingo Molnar
+ *
+ * This file contains the needed support code for 4GB userspace
+ */
+
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/highmem.h>
+#include <asm/desc.h>
+#include <asm/atomic_kmap.h>
+
+extern char __entry_tramp_start, __entry_tramp_end, __start___entry_text;
+
+void __init init_entry_mappings(void)
+{
+#ifdef CONFIG_X86_HIGH_ENTRY
+	void *tramp;
+
+	/*
+	 * We need a high IDT and GDT for the 4G/4G split:
+	 */
+	trap_init_virtual_IDT();
+
+	__set_fixmap(FIX_ENTRY_TRAMPOLINE_0, __pa((unsigned long)&__entry_tramp_start), PAGE_KERNEL);
+	__set_fixmap(FIX_ENTRY_TRAMPOLINE_1, __pa((unsigned long)&__entry_tramp_start) + PAGE_SIZE, PAGE_KERNEL);
+	tramp = (void *)fix_to_virt(FIX_ENTRY_TRAMPOLINE_0);
+
+	printk("mapped 4G/4G trampoline to %p.\n", tramp);
+	BUG_ON((void *)&__start___entry_text != tramp);
+	/*
+	 * Virtual kernel stack:
+	 */
+	BUG_ON(__kmap_atomic_vaddr(KM_VSTACK0) & (THREAD_SIZE-1));
+	BUG_ON(sizeof(struct desc_struct)*NR_CPUS*GDT_ENTRIES > 2*PAGE_SIZE);
+	BUG_ON((unsigned int)&__entry_tramp_end - (unsigned int)&__entry_tramp_start > 2*PAGE_SIZE);
+
+	/*
+	 * set up the initial thread's virtual stack related
+	 * fields:
+	 */
+	current->thread.stack_page0 = virt_to_page((char *)current->thread_info);
+	current->thread.stack_page1 = virt_to_page((char *)current->thread_info + PAGE_SIZE);
+	current->thread_info->virtual_stack = (void *)__kmap_atomic_vaddr(KM_VSTACK0);
+
+	__kunmap_atomic_type(KM_VSTACK0);
+	__kunmap_atomic_type(KM_VSTACK1);
+        __kmap_atomic(current->thread.stack_page0, KM_VSTACK0);
+        __kmap_atomic(current->thread.stack_page1, KM_VSTACK1);
+
+#endif
+	current->thread_info->real_stack = (void *)current->thread_info;
+	current->thread_info->user_pgd = NULL;
+	current->thread.esp0 = (unsigned long)current->thread_info->real_stack + THREAD_SIZE;
+}
+
+
+
+void __init entry_trampoline_setup(void)
+{
+	/*
+	 * old IRQ entries set up by the boot code will still hang
+	 * around - they are a sign of hw trouble anyway, now they'll
+	 * produce a double fault message.
+	 */
+	trap_init_virtual_GDT();
+}
--- diff/arch/i386/kernel/kgdb_stub.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/i386/kernel/kgdb_stub.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,2458 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * General Public License for more details.
+ *
+ */
+
+/*
+ * Copyright (c) 2000 VERITAS Software Corporation.
+ *
+ */
+/****************************************************************************
+ *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ *  Module name: remcom.c $
+ *  Revision: 1.34 $
+ *  Date: 91/03/09 12:29:49 $
+ *  Contributor:     Lake Stevens Instrument Division$
+ *
+ *  Description:     low level support for gdb debugger. $
+ *
+ *  Considerations:  only works on target hardware $
+ *
+ *  Written by:	     Glenn Engel $
+ *  Updated by:	     David Grothe <dave@gcom.com>
+ *  Updated by:	     Robert Walsh <rjwalsh@durables.org>
+ *  Updated by:	     wangdi <wangdi@clusterfs.com>
+ *  ModuleState:     Experimental $
+ *
+ *  NOTES:	     See Below $
+ *
+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
+ *  Compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
+ *
+ *  Changes to allow auto initilization.  All that is needed is that it
+ *  be linked with the kernel and a break point (int 3) be executed.
+ *  The header file <asm/kgdb.h> defines BREAKPOINT to allow one to do
+ *  this. It should also be possible, once the interrupt system is up, to
+ *  call putDebugChar("+").  Once this is done, the remote debugger should
+ *  get our attention by sending a ^C in a packet. George Anzinger
+ *  <george@mvista.com>
+ *  Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
+ *  Added thread support, support for multiple processors,
+ *	support for ia-32(x86) hardware debugging.
+ *	Amit S. Kale ( akale@veritas.com )
+ *
+ *  Modified to support debugging over ethernet by Robert Walsh
+ *  <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ *  code by San Mehat.
+ *
+ *
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
+ *  simulates a breakpoint by executing an int 3.
+ *
+ *************
+ *
+ *    The following gdb commands are supported:
+ *
+ * command	    function				   Return value
+ *
+ *    g		    return the value of the CPU registers  hex data or ENN
+ *    G		    set the value of the CPU registers	   OK or ENN
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA	   hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA	   OK or ENN
+ *
+ *    c		    Resume at current address		   SNN	 ( signal NN)
+ *    cAA..AA	    Continue at address AA..AA		   SNN
+ *
+ *    s		    Step one instruction		   SNN
+ *    sAA..AA	    Step one instruction from AA..AA	   SNN
+ *
+ *    k		    kill
+ *
+ *    ?		    What was the last sigval ?		   SNN	 (signal NN)
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>	 :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.	 '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:		  Reply:
+ * $m0,10#2a		   +$00010203040506070809101112131415#42
+ *
+ ****************************************************************************/
+#define KGDB_VERSION "<20030915.1651.33>"
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/string.h>		/* for strcpy */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/vm86.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>		/* for linux pt_regs struct */
+#include <asm/kgdb_local.h>
+#include <linux/list.h>
+#include <asm/atomic.h>
+#include <asm/processor.h>
+#include <linux/irq.h>
+#include <asm/desc.h>
+#include <linux/inet.h>
+#include <linux/netpoll.h>
+
+/************************************************************************
+ *
+ * external low-level support routines
+ */
+typedef void (*Function) (void);	/* pointer to a function */
+
+/* Thread reference */
+typedef unsigned char threadref[8];
+
+extern int tty_putDebugChar(int);     /* write a single character      */
+extern int tty_getDebugChar(void);    /* read and return a single char */
+extern void tty_flushDebugChar(void); /* flush pending characters      */
+extern int eth_putDebugChar(int);     /* write a single character      */
+extern int eth_getDebugChar(void);    /* read and return a single char */
+extern void eth_flushDebugChar(void); /* flush pending characters      */
+
+/************************************************************************/
+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
+/* at least NUMREGBYTES*2 are needed for register packets */
+/* Longer buffer is needed to list all threads */
+#define BUFMAX 400
+
+char *kgdb_version = KGDB_VERSION;
+
+/*  debug >  0 prints ill-formed commands in valid packets & checksum errors */
+int debug_regs = 0;		/* set to non-zero to print registers */
+
+/* filled in by an external module */
+char *gdb_module_offsets;
+
+static const char hexchars[] = "0123456789abcdef";
+
+/* Number of bytes of registers.  */
+#define NUMREGBYTES 64
+/*
+ * Note that this register image is in a different order than
+ * the register image that Linux produces at interrupt time.
+ *
+ * Linux's register image is defined by struct pt_regs in ptrace.h.
+ * Just why GDB uses a different order is a historical mystery.
+ */
+enum regnames { _EAX,		/* 0 */
+	_ECX,			/* 1 */
+	_EDX,			/* 2 */
+	_EBX,			/* 3 */
+	_ESP,			/* 4 */
+	_EBP,			/* 5 */
+	_ESI,			/* 6 */
+	_EDI,			/* 7 */
+	_PC /* 8 also known as eip */ ,
+	_PS /* 9 also known as eflags */ ,
+	_CS,			/* 10 */
+	_SS,			/* 11 */
+	_DS,			/* 12 */
+	_ES,			/* 13 */
+	_FS,			/* 14 */
+	_GS			/* 15 */
+};
+
+/***************************  ASSEMBLY CODE MACROS *************************/
+/*
+ * Put the error code here just in case the user cares.
+ * Likewise, the vector number here (since GDB only gets the signal
+ * number through the usual means, and that's not very specific).
+ * The called_from is the return address so he can tell how we entered kgdb.
+ * This will allow him to seperate out the various possible entries.
+ */
+#define REMOTE_DEBUG 0		/* set != to turn on printing (also available in info) */
+
+#define PID_MAX PID_MAX_DEFAULT
+
+#ifdef CONFIG_SMP
+void smp_send_nmi_allbutself(void);
+#define IF_SMP(x) x
+#undef MAX_NO_CPUS
+#ifndef CONFIG_NO_KGDB_CPUS
+#define CONFIG_NO_KGDB_CPUS 2
+#endif
+#if CONFIG_NO_KGDB_CPUS > NR_CPUS
+#define MAX_NO_CPUS NR_CPUS
+#else
+#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS
+#endif
+#define hold_init hold_on_sstep: 1,
+#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL)
+#define NUM_CPUS num_online_cpus()
+#else
+#define IF_SMP(x)
+#define hold_init
+#undef MAX_NO_CPUS
+#define MAX_NO_CPUS 1
+#define NUM_CPUS 1
+#endif
+#define NOCPU (struct task_struct *)0xbad1fbad
+/* *INDENT-OFF*	 */
+struct kgdb_info {
+	int used_malloc;
+	void *called_from;
+	long long entry_tsc;
+	int errcode;
+	int vector;
+	int print_debug_info;
+#ifdef CONFIG_SMP
+	int hold_on_sstep;
+	struct {
+		volatile struct task_struct *task;
+		int pid;
+		int hold;
+		struct pt_regs *regs;
+	} cpus_waiting[MAX_NO_CPUS];
+#endif
+} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1};
+
+/* *INDENT-ON*	*/
+
+#define used_m kgdb_info.used_malloc
+/*
+ * This is little area we set aside to contain the stack we
+ * need to build to allow gdb to call functions.  We use one
+ * per cpu to avoid locking issues.  We will do all this work
+ * with interrupts off so that should take care of the protection
+ * issues.
+ */
+#define LOOKASIDE_SIZE 200	/* should be more than enough */
+#define MALLOC_MAX   200	/* Max malloc size */
+struct {
+	unsigned int esp;
+	int array[LOOKASIDE_SIZE];
+} fn_call_lookaside[MAX_NO_CPUS];
+
+static int trap_cpu;
+static unsigned int OLD_esp;
+
+#define END_OF_LOOKASIDE  &fn_call_lookaside[trap_cpu].array[LOOKASIDE_SIZE]
+#define IF_BIT 0x200
+#define TF_BIT 0x100
+
+#define MALLOC_ROUND 8-1
+
+static char malloc_array[MALLOC_MAX];
+IF_SMP(static void to_gdb(const char *mess));
+void *
+malloc(int size)
+{
+
+	if (size <= (MALLOC_MAX - used_m)) {
+		int old_used = used_m;
+		used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND));
+		return &malloc_array[old_used];
+	} else {
+		return NULL;
+	}
+}
+
+/*
+ * I/O dispatch functions...
+ * Based upon kgdboe, either call the ethernet
+ * handler or the serial one..
+ */
+void
+putDebugChar(int c)
+{
+	if (!kgdboe) {
+		tty_putDebugChar(c);
+	} else {
+		eth_putDebugChar(c);
+	}
+}
+
+int
+getDebugChar(void)
+{
+	if (!kgdboe) {
+		return tty_getDebugChar();
+	} else {
+		return eth_getDebugChar();
+	}
+}
+
+void
+flushDebugChar(void)
+{
+	if (!kgdboe) {
+		tty_flushDebugChar();
+	} else {
+		eth_flushDebugChar();
+	}
+}
+
+/*
+ * Gdb calls functions by pushing agruments, including a return address
+ * on the stack and the adjusting EIP to point to the function.	 The
+ * whole assumption in GDB is that we are on a different stack than the
+ * one the "user" i.e. code that hit the break point, is on.  This, of
+ * course is not true in the kernel.  Thus various dodges are needed to
+ * do the call without directly messing with EIP (which we can not change
+ * as it is just a location and not a register.	 To adjust it would then
+ * require that we move every thing below EIP up or down as needed.  This
+ * will not work as we may well have stack relative pointer on the stack
+ * (such as the pointer to regs, for example).
+
+ * So here is what we do:
+ * We detect gdb attempting to store into the stack area and instead, store
+ * into the fn_call_lookaside.array at the same relative location as if it
+ * were the area ESP pointed at.  We also trap ESP modifications
+ * and uses these to adjust fn_call_lookaside.esp.  On entry
+ * fn_call_lookaside.esp will be set to point at the last entry in
+ * fn_call_lookaside.array.  This allows us to check if it has changed, and
+ * if so, on exit, we add the registers we will use to do the move and a
+ * trap/ interrupt return exit sequence.  We then adjust the eflags in the
+ * regs array (remember we now have a copy in the fn_call_lookaside.array) to
+ * kill the interrupt bit, AND we change EIP to point at our set up stub.
+ * As part of the register set up we preset the registers to point at the
+ * begining and end of the fn_call_lookaside.array, so all the stub needs to
+ * do is move words from the array to the stack until ESP= the desired value
+ * then do the rti.  This will then transfer to the desired function with
+ * all the correct registers.  Nifty huh?
+ */
+extern asmlinkage void fn_call_stub(void);
+extern asmlinkage void fn_rtn_stub(void);
+/*					   *INDENT-OFF*	 */
+__asm__("fn_rtn_stub:\n\t"
+	"movl %eax,%esp\n\t"
+	"fn_call_stub:\n\t"
+	"1:\n\t"
+	"addl $-4,%ebx\n\t"
+	"movl (%ebx), %eax\n\t"
+	"pushl %eax\n\t"
+	"cmpl %esp,%ecx\n\t"
+	"jne  1b\n\t"
+	"popl %eax\n\t"
+	"popl %ebx\n\t"
+	"popl %ecx\n\t"
+	"iret \n\t");
+/*					     *INDENT-ON*  */
+#define gdb_i386vector	kgdb_info.vector
+#define gdb_i386errcode kgdb_info.errcode
+#define waiting_cpus	kgdb_info.cpus_waiting
+#define remote_debug	kgdb_info.print_debug_info
+#define hold_cpu(cpu)	kgdb_info.cpus_waiting[cpu].hold
+/* gdb locks */
+
+#ifdef CONFIG_SMP
+static int in_kgdb_called;
+static spinlock_t waitlocks[MAX_NO_CPUS] =
+    {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED };
+/*
+ * The following array has the thread pointer of each of the "other"
+ * cpus.  We make it global so it can be seen by gdb.
+ */
+volatile int in_kgdb_entry_log[MAX_NO_CPUS];
+volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS];
+/*
+static spinlock_t continuelocks[MAX_NO_CPUS];
+*/
+spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED;
+/* waiters on our spinlock plus us */
+static atomic_t spinlock_waiters = ATOMIC_INIT(1);
+static int spinlock_count = 0;
+static int spinlock_cpu = 0;
+/*
+ * Note we use nested spin locks to account for the case where a break
+ * point is encountered when calling a function by user direction from
+ * kgdb. Also there is the memory exception recursion to account for.
+ * Well, yes, but this lets other cpus thru too.  Lets add a
+ * cpu id to the lock.
+ */
+#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \
+			      spinlock_cpu != smp_processor_id()){\
+				      atomic_inc(&spinlock_waiters); \
+				      while (! spin_trylock(x)) {\
+					    in_kgdb(&regs);\
+				      }\
+				      atomic_dec(&spinlock_waiters); \
+				      spinlock_count = 1; \
+				      spinlock_cpu = smp_processor_id(); \
+			  }else{  \
+				      spinlock_count++; \
+			  }
+#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x)
+#else
+unsigned kgdb_spinlock = 0;
+#define KGDB_SPIN_LOCK(x) --*x
+#define KGDB_SPIN_UNLOCK(x) ++*x
+#endif
+
+int
+hex(char ch)
+{
+	if ((ch >= 'a') && (ch <= 'f'))
+		return (ch - 'a' + 10);
+	if ((ch >= '0') && (ch <= '9'))
+		return (ch - '0');
+	if ((ch >= 'A') && (ch <= 'F'))
+		return (ch - 'A' + 10);
+	return (-1);
+}
+
+/* scan for the sequence $<data>#<checksum>	*/
+void
+getpacket(char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	char ch;
+
+	do {
+		/* wait around for the start character, ignore all other characters */
+		while ((ch = (getDebugChar() & 0x7f)) != '$') ;
+		checksum = 0;
+		xmitcsum = -1;
+
+		count = 0;
+
+		/* now, read until a # or end of buffer is found */
+		while (count < BUFMAX) {
+			ch = getDebugChar() & 0x7f;
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+		buffer[count] = 0;
+
+		if (ch == '#') {
+			xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+			xmitcsum += hex(getDebugChar() & 0x7f);
+			if ((remote_debug) && (checksum != xmitcsum)) {
+				printk
+				    ("bad checksum.	My count = 0x%x, sent=0x%x. buf=%s\n",
+				     checksum, xmitcsum, buffer);
+			}
+
+			if (checksum != xmitcsum)
+				putDebugChar('-');	/* failed checksum */
+			else {
+				putDebugChar('+');	/* successful transfer */
+				/* if a sequence char is present, reply the sequence ID */
+				if (buffer[2] == ':') {
+					putDebugChar(buffer[0]);
+					putDebugChar(buffer[1]);
+					/* remove sequence chars from buffer */
+					count = strlen(buffer);
+					for (i = 3; i <= count; i++)
+						buffer[i - 3] = buffer[i];
+				}
+			}
+		}
+	} while (checksum != xmitcsum);
+
+	if (remote_debug)
+		printk("R:%s\n", buffer);
+	flushDebugChar();
+}
+
+/* send the packet in buffer.  */
+
+void
+putpacket(char *buffer)
+{
+	unsigned char checksum;
+	int count;
+	char ch;
+
+	/*  $<packet info>#<checksum>. */
+
+	if (!kgdboe) {
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+
+			while ((ch = buffer[count])) {
+				putDebugChar(ch);
+				checksum += ch;
+				count += 1;
+			}
+
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+
+		} while ((getDebugChar() & 0x7f) != '+');
+	} else {
+		/*
+		 * For udp, we can not transfer too much bytes once.
+		 * We only transfer MAX_SEND_COUNT size bytes each time
+		 */
+
+#define MAX_SEND_COUNT 30
+
+		int send_count = 0, i = 0;
+		char send_buf[MAX_SEND_COUNT];
+
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+			send_count = 0;
+			while ((ch = buffer[count])) {
+				if (send_count >= MAX_SEND_COUNT) {
+					for(i = 0; i < MAX_SEND_COUNT; i++) {
+						putDebugChar(send_buf[i]);
+					}
+					flushDebugChar();
+					send_count = 0;
+				} else {
+					send_buf[send_count] = ch;
+					checksum += ch;
+					count ++;
+					send_count++;
+				}
+			}
+			for(i = 0; i < send_count; i++)
+				putDebugChar(send_buf[i]);
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+		} while ((getDebugChar() & 0x7f) != '+');
+	}
+}
+
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+static short error;
+
+void
+debug_error(char *format, char *parm)
+{
+	if (remote_debug)
+		printk(format, parm);
+}
+
+static void
+print_regs(struct pt_regs *regs)
+{
+	printk("EAX=%08lx ", regs->eax);
+	printk("EBX=%08lx ", regs->ebx);
+	printk("ECX=%08lx ", regs->ecx);
+	printk("EDX=%08lx ", regs->edx);
+	printk("\n");
+	printk("ESI=%08lx ", regs->esi);
+	printk("EDI=%08lx ", regs->edi);
+	printk("EBP=%08lx ", regs->ebp);
+	printk("ESP=%08lx ", (long) &regs->esp);
+	printk("\n");
+	printk(" DS=%08x ", regs->xds);
+	printk(" ES=%08x ", regs->xes);
+	printk(" SS=%08x ", __KERNEL_DS);
+	printk(" FL=%08lx ", regs->eflags);
+	printk("\n");
+	printk(" CS=%08x ", regs->xcs);
+	printk(" IP=%08lx ", regs->eip);
+#if 0
+	printk(" FS=%08x ", regs->fs);
+	printk(" GS=%08x ", regs->gs);
+#endif
+	printk("\n");
+
+}				/* print_regs */
+
+#define NEW_esp fn_call_lookaside[trap_cpu].esp
+
+static void
+regs_to_gdb_regs(int *gdb_regs, struct pt_regs *regs)
+{
+	gdb_regs[_EAX] = regs->eax;
+	gdb_regs[_EBX] = regs->ebx;
+	gdb_regs[_ECX] = regs->ecx;
+	gdb_regs[_EDX] = regs->edx;
+	gdb_regs[_ESI] = regs->esi;
+	gdb_regs[_EDI] = regs->edi;
+	gdb_regs[_EBP] = regs->ebp;
+	gdb_regs[_DS] = regs->xds;
+	gdb_regs[_ES] = regs->xes;
+	gdb_regs[_PS] = regs->eflags;
+	gdb_regs[_CS] = regs->xcs;
+	gdb_regs[_PC] = regs->eip;
+	/* Note, as we are a debugging the kernel, we will always
+	 * trap in kernel code, this means no priviledge change,
+	 * and so the pt_regs structure is not completely valid.  In a non
+	 * privilege change trap, only EFLAGS, CS and EIP are put on the stack,
+	 * SS and ESP are not stacked, this means that the last 2 elements of
+	 * pt_regs is not valid (they would normally refer to the user stack)
+	 * also, using regs+1 is no good because you end up will a value that is
+	 * 2 longs (8) too high.  This used to cause stepping over functions
+	 * to fail, so my fix is to use the address of regs->esp, which
+	 * should point at the end of the stack frame.	Note I have ignored
+	 * completely exceptions that cause an error code to be stacked, such
+	 * as double fault.  Stuart Hughes, Zentropix.
+	 * original code: gdb_regs[_ESP] =  (int) (regs + 1) ;
+
+	 * this is now done on entry and moved to OLD_esp (as well as NEW_esp).
+	 */
+	gdb_regs[_ESP] = NEW_esp;
+	gdb_regs[_SS] = __KERNEL_DS;
+	gdb_regs[_FS] = 0xFFFF;
+	gdb_regs[_GS] = 0xFFFF;
+}				/* regs_to_gdb_regs */
+
+static void
+gdb_regs_to_regs(int *gdb_regs, struct pt_regs *regs)
+{
+	regs->eax = gdb_regs[_EAX];
+	regs->ebx = gdb_regs[_EBX];
+	regs->ecx = gdb_regs[_ECX];
+	regs->edx = gdb_regs[_EDX];
+	regs->esi = gdb_regs[_ESI];
+	regs->edi = gdb_regs[_EDI];
+	regs->ebp = gdb_regs[_EBP];
+	regs->xds = gdb_regs[_DS];
+	regs->xes = gdb_regs[_ES];
+	regs->eflags = gdb_regs[_PS];
+	regs->xcs = gdb_regs[_CS];
+	regs->eip = gdb_regs[_PC];
+	NEW_esp = gdb_regs[_ESP];	/* keep the value */
+#if 0				/* can't change these */
+	regs->esp = gdb_regs[_ESP];
+	regs->xss = gdb_regs[_SS];
+	regs->fs = gdb_regs[_FS];
+	regs->gs = gdb_regs[_GS];
+#endif
+
+}				/* gdb_regs_to_regs */
+extern void scheduling_functions_start_here(void);
+extern void scheduling_functions_end_here(void);
+#define first_sched	((unsigned long) scheduling_functions_start_here)
+#define last_sched	((unsigned long) scheduling_functions_end_here)
+
+int thread_list = 0;
+
+void
+get_gdb_regs(struct task_struct *p, struct pt_regs *regs, int *gdb_regs)
+{
+	unsigned long stack_page;
+	int count = 0;
+	IF_SMP(int i);
+	if (!p || p == current) {
+		regs_to_gdb_regs(gdb_regs, regs);
+		return;
+	}
+#ifdef CONFIG_SMP
+	for (i = 0; i < MAX_NO_CPUS; i++) {
+		if (p == kgdb_info.cpus_waiting[i].task) {
+			regs_to_gdb_regs(gdb_regs,
+					 kgdb_info.cpus_waiting[i].regs);
+			gdb_regs[_ESP] =
+			    (int) &kgdb_info.cpus_waiting[i].regs->esp;
+
+			return;
+		}
+	}
+#endif
+	memset(gdb_regs, 0, NUMREGBYTES);
+	gdb_regs[_ESP] = p->thread.esp;
+	gdb_regs[_PC] = p->thread.eip;
+	gdb_regs[_EBP] = *(int *) gdb_regs[_ESP];
+	gdb_regs[_EDI] = *(int *) (gdb_regs[_ESP] + 4);
+	gdb_regs[_ESI] = *(int *) (gdb_regs[_ESP] + 8);
+
+/*
+ * This code is to give a more informative notion of where a process
+ * is waiting.	It is used only when the user asks for a thread info
+ * list.  If he then switches to the thread, s/he will find the task
+ * is in schedule, but a back trace should show the same info we come
+ * up with.  This code was shamelessly purloined from process.c.  It was
+ * then enhanced to provide more registers than simply the program
+ * counter.
+ */
+
+	if (!thread_list) {
+		return;
+	}
+
+	if (p->state == TASK_RUNNING)
+		return;
+	stack_page = (unsigned long) p->thread_info;
+	if (gdb_regs[_ESP] < stack_page || gdb_regs[_ESP] >
+	    THREAD_SIZE - sizeof(long) + stack_page)
+		return;
+	/* include/asm-i386/system.h:switch_to() pushes ebp last. */
+	do {
+		if (gdb_regs[_EBP] < stack_page ||
+		    gdb_regs[_EBP] > THREAD_SIZE - 2*sizeof(long) + stack_page)
+			return;
+		gdb_regs[_PC] = *(unsigned long *) (gdb_regs[_EBP] + 4);
+		gdb_regs[_ESP] = gdb_regs[_EBP] + 8;
+		gdb_regs[_EBP] = *(unsigned long *) gdb_regs[_EBP];
+		if (gdb_regs[_PC] < first_sched || gdb_regs[_PC] >= last_sched)
+			return;
+	} while (count++ < 16);
+	return;
+}
+
+/* Indicate to caller of mem2hex or hex2mem that there has been an
+   error.  */
+static volatile int mem_err = 0;
+static volatile int mem_err_expected = 0;
+static volatile int mem_err_cnt = 0;
+static int garbage_loc = -1;
+
+int
+get_char(char *addr)
+{
+	return *addr;
+}
+
+void
+set_char(char *addr, int val, int may_fault)
+{
+	/*
+	 * This code traps references to the area mapped to the kernel
+	 * stack as given by the regs and, instead, stores to the
+	 * fn_call_lookaside[cpu].array
+	 */
+	if (may_fault &&
+	    (unsigned int) addr < OLD_esp &&
+	    ((unsigned int) addr > (OLD_esp - (unsigned int) LOOKASIDE_SIZE))) {
+		addr = (char *) END_OF_LOOKASIDE - ((char *) OLD_esp - addr);
+	}
+	*addr = val;
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf */
+/* return a pointer to the last char put in buf (null) */
+/* If MAY_FAULT is non-zero, then we should set mem_err in response to
+   a fault; if zero treat a fault like any other fault in the stub.  */
+char *
+mem2hex(char *mem, char *buf, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+	for (i = 0; i < count; i++) {
+		/* printk("%lx = ", mem) ; */
+
+		ch = get_char(mem++);
+
+		/* printk("%02x\n", ch & 0xFF) ; */
+		if (may_fault && mem_err) {
+			if (remote_debug)
+				printk("Mem fault fetching from addr %lx\n",
+				       (long) (mem - 1));
+			*buf = 0;	/* truncate buffer */
+			return (buf);
+		}
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch % 16];
+	}
+	*buf = 0;
+	if (may_fault)
+		mem_err_expected = 0;
+	return (buf);
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem */
+/* return a pointer to the character AFTER the last byte written */
+/* NOTE: We use the may fault flag to also indicate if the write is to
+ * the registers (0) or "other" memory (!=0)
+ */
+char *
+hex2mem(char *buf, char *mem, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+	for (i = 0; i < count; i++) {
+		ch = hex(*buf++) << 4;
+		ch = ch + hex(*buf++);
+		set_char(mem++, ch, may_fault);
+
+		if (may_fault && mem_err) {
+			if (remote_debug)
+				printk("Mem fault storing to addr %lx\n",
+				       (long) (mem - 1));
+			return (mem);
+		}
+	}
+	if (may_fault)
+		mem_err_expected = 0;
+	return (mem);
+}
+
+/**********************************************/
+/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
+/* RETURN NUMBER OF CHARS PROCESSED	      */
+/**********************************************/
+int
+hexToInt(char **ptr, int *intValue)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*intValue = 0;
+
+	while (**ptr) {
+		hexValue = hex(**ptr);
+		if (hexValue >= 0) {
+			*intValue = (*intValue << 4) | hexValue;
+			numChars++;
+		} else
+			break;
+
+		(*ptr)++;
+	}
+
+	return (numChars);
+}
+
+#define stubhex(h) hex(h)
+#ifdef old_thread_list
+
+static int
+stub_unpack_int(char *buff, int fieldlength)
+{
+	int nibble;
+	int retval = 0;
+
+	while (fieldlength) {
+		nibble = stubhex(*buff++);
+		retval |= nibble;
+		fieldlength--;
+		if (fieldlength)
+			retval = retval << 4;
+	}
+	return retval;
+}
+#endif
+static char *
+pack_hex_byte(char *pkt, int byte)
+{
+	*pkt++ = hexchars[(byte >> 4) & 0xf];
+	*pkt++ = hexchars[(byte & 0xf)];
+	return pkt;
+}
+
+#define BUF_THREAD_ID_SIZE 16
+
+static char *
+pack_threadid(char *pkt, threadref * id)
+{
+	char *limit;
+	unsigned char *altid;
+
+	altid = (unsigned char *) id;
+	limit = pkt + BUF_THREAD_ID_SIZE;
+	while (pkt < limit)
+		pkt = pack_hex_byte(pkt, *altid++);
+	return pkt;
+}
+
+#ifdef old_thread_list
+static char *
+unpack_byte(char *buf, int *value)
+{
+	*value = stub_unpack_int(buf, 2);
+	return buf + 2;
+}
+
+static char *
+unpack_threadid(char *inbuf, threadref * id)
+{
+	char *altref;
+	char *limit = inbuf + BUF_THREAD_ID_SIZE;
+	int x, y;
+
+	altref = (char *) id;
+
+	while (inbuf < limit) {
+		x = stubhex(*inbuf++);
+		y = stubhex(*inbuf++);
+		*altref++ = (x << 4) | y;
+	}
+	return inbuf;
+}
+#endif
+void
+int_to_threadref(threadref * id, int value)
+{
+	unsigned char *scan;
+
+	scan = (unsigned char *) id;
+	{
+		int i = 4;
+		while (i--)
+			*scan++ = 0;
+	}
+	*scan++ = (value >> 24) & 0xff;
+	*scan++ = (value >> 16) & 0xff;
+	*scan++ = (value >> 8) & 0xff;
+	*scan++ = (value & 0xff);
+}
+int
+int_to_hex_v(unsigned char * id, int value)
+{
+	unsigned char *start = id;
+	int shift;
+	int ch;
+
+	for (shift = 28; shift >= 0; shift -= 4) {
+		if ((ch = (value >> shift) & 0xf) || (id != start)) {
+			*id = hexchars[ch];
+			id++;
+		}
+	}
+	if (id == start)
+		*id++ = '0';
+	return id - start;
+}
+#ifdef old_thread_list
+
+static int
+threadref_to_int(threadref * ref)
+{
+	int i, value = 0;
+	unsigned char *scan;
+
+	scan = (char *) ref;
+	scan += 4;
+	i = 4;
+	while (i-- > 0)
+		value = (value << 8) | ((*scan++) & 0xff);
+	return value;
+}
+#endif
+static int
+cmp_str(char *s1, char *s2, int count)
+{
+	while (count--) {
+		if (*s1++ != *s2++)
+			return 0;
+	}
+	return 1;
+}
+
+#if 1				/* this is a hold over from 2.4 where O(1) was "sometimes" */
+extern struct task_struct *kgdb_get_idle(int cpu);
+#define idle_task(cpu) kgdb_get_idle(cpu)
+#else
+#define idle_task(cpu) init_tasks[cpu]
+#endif
+
+extern int kgdb_pid_init_done;
+
+struct task_struct *
+getthread(int pid)
+{
+	struct task_struct *thread;
+	if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) {
+
+		return idle_task(pid - PID_MAX);
+	} else {
+		/*
+		 * find_task_by_pid is relatively safe all the time
+		 * Other pid functions require lock downs which imply
+		 * that we may be interrupting them (as we get here
+		 * in the middle of most any lock down).
+		 * Still we don't want to call until the table exists!
+		 */
+		if (kgdb_pid_init_done){
+			thread = find_task_by_pid(pid);
+			if (thread) {
+				return thread;
+			}
+		}
+	}
+	return NULL;
+}
+/* *INDENT-OFF*	 */
+struct hw_breakpoint {
+	unsigned enabled;
+	unsigned type;
+	unsigned len;
+	unsigned addr;
+} breakinfo[4] = { {enabled:0},
+		   {enabled:0},
+		   {enabled:0},
+		   {enabled:0}};
+/* *INDENT-ON*	*/
+unsigned hw_breakpoint_status;
+void
+correct_hw_break(void)
+{
+	int breakno;
+	int correctit;
+	int breakbit;
+	unsigned dr7;
+
+	asm volatile ("movl %%db7, %0\n":"=r" (dr7)
+		      :);
+	/* *INDENT-OFF*	 */
+	do {
+		unsigned addr0, addr1, addr2, addr3;
+		asm volatile ("movl %%db0, %0\n"
+			      "movl %%db1, %1\n"
+			      "movl %%db2, %2\n"
+			      "movl %%db3, %3\n"
+			      :"=r" (addr0), "=r"(addr1),
+			      "=r"(addr2), "=r"(addr3)
+			      :);
+	} while (0);
+	/* *INDENT-ON*	*/
+	correctit = 0;
+	for (breakno = 0; breakno < 3; breakno++) {
+		breakbit = 2 << (breakno << 1);
+		if (!(dr7 & breakbit) && breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 |= breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+			dr7 |= (((breakinfo[breakno].len << 2) |
+				 breakinfo[breakno].type) << 16) <<
+			    (breakno << 2);
+			switch (breakno) {
+			case 0:
+				asm volatile ("movl %0, %%dr0\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 1:
+				asm volatile ("movl %0, %%dr1\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 2:
+				asm volatile ("movl %0, %%dr2\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 3:
+				asm volatile ("movl %0, %%dr3\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+			}
+		} else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 &= ~breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+		}
+	}
+	if (correctit) {
+		asm volatile ("movl %0, %%db7\n"::"r" (dr7));
+	}
+}
+
+int
+remove_hw_break(unsigned breakno)
+{
+	if (!breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 0;
+	return 0;
+}
+
+int
+set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr)
+{
+	if (breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 1;
+	breakinfo[breakno].type = type;
+	breakinfo[breakno].len = len;
+	breakinfo[breakno].addr = addr;
+	return 0;
+}
+
+#ifdef CONFIG_SMP
+static int in_kgdb_console = 0;
+
+int
+in_kgdb(struct pt_regs *regs)
+{
+	unsigned flags;
+	int cpu = smp_processor_id();
+	in_kgdb_called = 1;
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		if (in_kgdb_here_log[cpu] ||	/* we are holding this cpu */
+		    in_kgdb_console) {	/* or we are doing slow i/o */
+			return 1;
+		}
+		return 0;
+	}
+
+	/* As I see it the only reason not to let all cpus spin on
+	 * the same spin_lock is to allow selected ones to proceed.
+	 * This would be a good thing, so we leave it this way.
+	 * Maybe someday....  Done !
+
+	 * in_kgdb() is called from an NMI so we don't pretend
+	 * to have any resources, like printk() for example.
+	 */
+
+	kgdb_local_irq_save(flags);	/* only local here, to avoid hanging */
+	/*
+	 * log arival of this cpu
+	 * The NMI keeps on ticking.  Protect against recurring more
+	 * than once, and ignor the cpu that has the kgdb lock
+	 */
+	in_kgdb_entry_log[cpu]++;
+	in_kgdb_here_log[cpu] = regs;
+	if (cpu == spinlock_cpu || waiting_cpus[cpu].task)
+		goto exit_in_kgdb;
+
+	/*
+	 * For protection of the initilization of the spin locks by kgdb
+	 * it locks the kgdb spinlock before it gets the wait locks set
+	 * up.	We wait here for the wait lock to be taken.  If the
+	 * kgdb lock goes away first??	Well, it could be a slow exit
+	 * sequence where the wait lock is removed prior to the kgdb lock
+	 * so if kgdb gets unlocked, we just exit.
+	 */
+
+	while (spin_is_locked(&kgdb_spinlock) &&
+	       !spin_is_locked(waitlocks + cpu)) ;
+	if (!spin_is_locked(&kgdb_spinlock))
+		goto exit_in_kgdb;
+
+	waiting_cpus[cpu].task = current;
+	waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu);
+	waiting_cpus[cpu].regs = regs;
+
+	spin_unlock_wait(waitlocks + cpu);
+
+	/*
+	 * log departure of this cpu
+	 */
+	waiting_cpus[cpu].task = 0;
+	waiting_cpus[cpu].pid = 0;
+	waiting_cpus[cpu].regs = 0;
+	correct_hw_break();
+      exit_in_kgdb:
+	in_kgdb_here_log[cpu] = 0;
+	kgdb_local_irq_restore(flags);
+	return 1;
+	/*
+	   spin_unlock(continuelocks + smp_processor_id());
+	 */
+}
+
+void
+smp__in_kgdb(struct pt_regs regs)
+{
+	ack_APIC_irq();
+	in_kgdb(&regs);
+}
+#else
+int
+in_kgdb(struct pt_regs *regs)
+{
+	return (kgdb_spinlock);
+}
+#endif
+
+void
+printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
+{
+	unsigned dr6;
+	int i;
+	switch (exceptionNo) {
+	case 1:		/* debug exception */
+		break;
+	case 3:		/* breakpoint */
+		sprintf(buffer, "Software breakpoint");
+		return;
+	default:
+		sprintf(buffer, "Details not available");
+		return;
+	}
+	asm volatile ("movl %%db6, %0\n":"=r" (dr6)
+		      :);
+	if (dr6 & 0x4000) {
+		sprintf(buffer, "Single step");
+		return;
+	}
+	for (i = 0; i < 4; ++i) {
+		if (dr6 & (1 << i)) {
+			sprintf(buffer, "Hardware breakpoint %d", i);
+			return;
+		}
+	}
+	sprintf(buffer, "Unknown trap");
+	return;
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ *
+ * NOTE:  The INT nn instruction leaves the state of the interrupt
+ *	  enable flag UNCHANGED.  That means that when this routine
+ *	  is entered via a breakpoint (INT 3) instruction from code
+ *	  that has interrupts enabled, then interrupts will STILL BE
+ *	  enabled when this routine is entered.	 The first thing that
+ *	  we do here is disable interrupts so as to prevent recursive
+ *	  entries and bothersome serial interrupts while we are
+ *	  trying to run the serial port in polled mode.
+ *
+ * For kernel version 2.1.xx the kgdb_cli() actually gets a spin lock so
+ * it is always necessary to do a restore_flags before returning
+ * so as to let go of that lock.
+ */
+int
+kgdb_handle_exception(int exceptionVector,
+		      int signo, int err_code, struct pt_regs *linux_regs)
+{
+	struct task_struct *usethread = NULL;
+	struct task_struct *thread_list_start = 0, *thread = NULL;
+	int addr, length;
+	int breakno, breaktype;
+	char *ptr;
+	int newPC;
+	threadref thref;
+	int threadid;
+	int thread_min = PID_MAX + MAX_NO_CPUS;
+#ifdef old_thread_list
+	int maxthreads;
+#endif
+	int nothreads;
+	unsigned long flags;
+	int gdb_regs[NUMREGBYTES / 4];
+	int dr6;
+	IF_SMP(int entry_state = 0);	/* 0, ok, 1, no nmi, 2 sync failed */
+#define NO_NMI 1
+#define NO_SYNC 2
+#define	regs	(*linux_regs)
+#define NUMREGS NUMREGBYTES/4
+	/*
+	 * If the entry is not from the kernel then return to the Linux
+	 * trap handler and let it process the interrupt normally.
+	 */
+	if ((linux_regs->eflags & VM_MASK) || (3 & linux_regs->xcs)) {
+		printk("ignoring non-kernel exception\n");
+		print_regs(&regs);
+		return (0);
+	}
+	/*
+	 * If we're using eth mode, set the 'mode' in the netdevice.
+	 */
+
+	if (kgdboe)
+		netpoll_set_trap(1);
+
+	kgdb_local_irq_save(flags);
+
+	/* Get kgdb spinlock */
+
+	KGDB_SPIN_LOCK(&kgdb_spinlock);
+	rdtscll(kgdb_info.entry_tsc);
+	/*
+	 * We depend on this spinlock and the NMI watch dog to control the
+	 * other cpus.	They will arrive at "in_kgdb()" as a result of the
+	 * NMI and will wait there for the following spin locks to be
+	 * released.
+	 */
+#ifdef CONFIG_SMP
+
+#if 0
+	if (cpu_callout_map & ~MAX_CPU_MASK) {
+		printk("kgdb : too many cpus, possibly not mapped"
+		       " in contiguous space, change MAX_NO_CPUS"
+		       " in kgdb_stub and make new kernel.\n"
+		       " cpu_callout_map is %lx\n", cpu_callout_map);
+		goto exit_just_unlock;
+	}
+#endif
+	if (spinlock_count == 1) {
+		int time = 0, end_time, dum = 0;
+		int i;
+		int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0)
+		};
+		if (remote_debug) {
+			printk("kgdb : cpu %d entry, syncing others\n",
+			       smp_processor_id());
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			/*
+			 * Use trylock as we may already hold the lock if
+			 * we are holding the cpu.  Net result is all
+			 * locked.
+			 */
+			spin_trylock(&waitlocks[i]);
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++)
+			cpu_logged_in[i] = 0;
+		/*
+		 * Wait for their arrival.  We know the watch dog is active if
+		 * in_kgdb() has ever been called, as it is always called on a
+		 * watchdog tick.
+		 */
+		rdtsc(dum, time);
+		end_time = time + 2;	/* Note: we use the High order bits! */
+		i = 1;
+		if (num_online_cpus() > 1) {
+			int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()];
+			smp_send_nmi_allbutself();
+
+			while (i < num_online_cpus() && time != end_time) {
+				int j;
+				for (j = 0; j < MAX_NO_CPUS; j++) {
+					if (waiting_cpus[j].task &&
+					    waiting_cpus[j].task != NOCPU &&
+					    !cpu_logged_in[j]) {
+						i++;
+						cpu_logged_in[j] = 1;
+						if (remote_debug) {
+							printk
+							    ("kgdb : cpu %d arrived at kgdb\n",
+							     j);
+						}
+						break;
+					} else if (!waiting_cpus[j].task &&
+						   !cpu_online(j)) {
+						waiting_cpus[j].task = NOCPU;
+						cpu_logged_in[j] = 1;
+						waiting_cpus[j].hold = 1;
+						break;
+					}
+					if (!waiting_cpus[j].task &&
+					    in_kgdb_here_log[j]) {
+
+						int wait = 100000;
+						while (wait--) ;
+						if (!waiting_cpus[j].task &&
+						    in_kgdb_here_log[j]) {
+							printk
+							    ("kgdb : cpu %d stall"
+							     " in in_kgdb\n",
+							     j);
+							i++;
+							cpu_logged_in[j] = 1;
+							waiting_cpus[j].task =
+							    (struct task_struct
+							     *) 1;
+						}
+					}
+				}
+
+				if (in_kgdb_entry_log[smp_processor_id()] >
+				    (me_in_kgdb + 10)) {
+					break;
+				}
+
+				rdtsc(dum, time);
+			}
+			if (i < num_online_cpus()) {
+				printk
+				    ("kgdb : time out, proceeding without sync\n");
+#if 0
+				printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n",
+				       waiting_cpus[0].task != 0,
+				       waiting_cpus[1].task != 0);
+				printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n",
+				       cpu_logged_in[0], cpu_logged_in[1]);
+				printk
+				    ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n",
+				     in_kgdb_here_log[0] != 0,
+				     in_kgdb_here_log[1] != 0);
+#endif
+				entry_state = NO_SYNC;
+			} else {
+#if 0
+				int ent =
+				    in_kgdb_entry_log[smp_processor_id()] -
+				    me_in_kgdb;
+				printk("kgdb : sync after %d entries\n", ent);
+#endif
+			}
+		} else {
+			if (remote_debug) {
+				printk
+				    ("kgdb : %d cpus, but watchdog not active\n"
+				     "proceeding without locking down other cpus\n",
+				     num_online_cpus());
+				entry_state = NO_NMI;
+			}
+		}
+	}
+#endif
+
+	if (remote_debug) {
+		unsigned long *lp = (unsigned long *) &linux_regs;
+
+		printk("handle_exception(exceptionVector=%d, "
+		       "signo=%d, err_code=%d, linux_regs=%p)\n",
+		       exceptionVector, signo, err_code, linux_regs);
+		if (debug_regs) {
+			print_regs(&regs);
+			printk("Stk: %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[0], lp[1], lp[2], lp[3],
+			       lp[4], lp[5], lp[6], lp[7]);
+			printk("     %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[8], lp[9], lp[10], lp[11],
+			       lp[12], lp[13], lp[14], lp[15]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[16], lp[17], lp[18], lp[19],
+			       lp[20], lp[21], lp[22], lp[23]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[24], lp[25], lp[26], lp[27],
+			       lp[28], lp[29], lp[30], lp[31]);
+		}
+	}
+
+	/* Disable hardware debugging while we are in kgdb */
+	/* Get the debug register status register */
+/*				       *INDENT-OFF*  */
+      __asm__("movl %0,%%db7"
+	      :	/* no output */
+	      :"r"(0));
+
+	asm volatile ("movl %%db6, %0\n"
+		      :"=r" (hw_breakpoint_status)
+		      :);
+
+/*				       *INDENT-ON*  */
+	switch (exceptionVector) {
+	case 0:		/* divide error */
+	case 1:		/* debug exception */
+	case 2:		/* NMI */
+	case 3:		/* breakpoint */
+	case 4:		/* overflow */
+	case 5:		/* bounds check */
+	case 6:		/* invalid opcode */
+	case 7:		/* device not available */
+	case 8:		/* double fault (errcode) */
+	case 10:		/* invalid TSS (errcode) */
+	case 12:		/* stack fault (errcode) */
+	case 16:		/* floating point error */
+	case 17:		/* alignment check (errcode) */
+	default:		/* any undocumented */
+		break;
+	case 11:		/* segment not present (errcode) */
+	case 13:		/* general protection (errcode) */
+	case 14:		/* page fault (special errcode) */
+	case 19:		/* cache flush denied */
+		if (mem_err_expected) {
+			/*
+			 * This fault occured because of the
+			 * get_char or set_char routines.  These
+			 * two routines use either eax of edx to
+			 * indirectly reference the location in
+			 * memory that they are working with.
+			 * For a page fault, when we return the
+			 * instruction will be retried, so we
+			 * have to make sure that these
+			 * registers point to valid memory.
+			 */
+			mem_err = 1;	/* set mem error flag */
+			mem_err_expected = 0;
+			mem_err_cnt++;	/* helps in debugging */
+			/* make valid address */
+			regs.eax = (long) &garbage_loc;
+			/* make valid address */
+			regs.edx = (long) &garbage_loc;
+			if (remote_debug)
+				printk("Return after memory error: "
+				       "mem_err_cnt=%d\n", mem_err_cnt);
+			if (debug_regs)
+				print_regs(&regs);
+			goto exit_kgdb;
+		}
+		break;
+	}
+	if (remote_debug)
+		printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id());
+
+	gdb_i386vector = exceptionVector;
+	gdb_i386errcode = err_code;
+	kgdb_info.called_from = __builtin_return_address(0);
+#ifdef CONFIG_SMP
+	/*
+	 * OK, we can now communicate, lets tell gdb about the sync.
+	 * but only if we had a problem.
+	 */
+	switch (entry_state) {
+	case NO_NMI:
+		to_gdb("NMI not active, other cpus not stopped\n");
+		break;
+	case NO_SYNC:
+		to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n");
+	default:;
+	}
+
+#endif
+/*
+ * Set up the gdb function call area.
+ */
+	trap_cpu = smp_processor_id();
+	OLD_esp = NEW_esp = (int) (&linux_regs->esp);
+
+      IF_SMP(once_again:)
+	    /* reply to host that an exception has occurred */
+	    remcomOutBuffer[0] = 'S';
+	remcomOutBuffer[1] = hexchars[signo >> 4];
+	remcomOutBuffer[2] = hexchars[signo % 16];
+	remcomOutBuffer[3] = 0;
+
+	putpacket(remcomOutBuffer);
+
+	while (1 == 1) {
+		error = 0;
+		remcomOutBuffer[0] = 0;
+		getpacket(remcomInBuffer);
+		switch (remcomInBuffer[0]) {
+		case '?':
+			remcomOutBuffer[0] = 'S';
+			remcomOutBuffer[1] = hexchars[signo >> 4];
+			remcomOutBuffer[2] = hexchars[signo % 16];
+			remcomOutBuffer[3] = 0;
+			break;
+		case 'd':
+			remote_debug = !(remote_debug);	/* toggle debug flag */
+			printk("Remote debug %s\n",
+			       remote_debug ? "on" : "off");
+			break;
+		case 'g':	/* return the value of the CPU registers */
+			get_gdb_regs(usethread, &regs, gdb_regs);
+			mem2hex((char *) gdb_regs,
+				remcomOutBuffer, NUMREGBYTES, 0);
+			break;
+		case 'G':	/* set the value of the CPU registers - return OK */
+			hex2mem(&remcomInBuffer[1],
+				(char *) gdb_regs, NUMREGBYTES, 0);
+			if (!usethread || usethread == current) {
+				gdb_regs_to_regs(gdb_regs, &regs);
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "E00");
+			}
+			break;
+
+		case 'P':{	/* set the value of a single CPU register -
+				   return OK */
+				/*
+				 * For some reason, gdb wants to talk about psudo
+				 * registers (greater than 15).	 These may have
+				 * meaning for ptrace, but for us it is safe to
+				 * ignor them.	We do this by dumping them into
+				 * _GS which we also ignor, but do have memory for.
+				 */
+				int regno;
+
+				ptr = &remcomInBuffer[1];
+				regs_to_gdb_regs(gdb_regs, &regs);
+				if ((!usethread || usethread == current) &&
+				    hexToInt(&ptr, &regno) &&
+				    *ptr++ == '=' && (regno >= 0)) {
+					regno =
+					    (regno >= NUMREGS ? _GS : regno);
+					hex2mem(ptr, (char *) &gdb_regs[regno],
+						4, 0);
+					gdb_regs_to_regs(gdb_regs, &regs);
+					strcpy(remcomOutBuffer, "OK");
+					break;
+				}
+				strcpy(remcomOutBuffer, "E01");
+				break;
+			}
+
+			/* mAA..AA,LLLL	 Read LLLL bytes at address AA..AA */
+		case 'm':
+			/* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToInt(&ptr, &addr) &&
+			    (*(ptr++) == ',') && (hexToInt(&ptr, &length))) {
+				ptr = 0;
+				/*
+				 * hex doubles the byte count
+				 */
+				if (length > (BUFMAX / 2))
+					length = BUFMAX / 2;
+				mem2hex((char *) addr,
+					remcomOutBuffer, length, 1);
+				if (mem_err) {
+					strcpy(remcomOutBuffer, "E03");
+					debug_error("memory fault\n", NULL);
+				}
+			}
+
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E01");
+				debug_error
+				    ("malformed read memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+
+			/* MAA..AA,LLLL:
+			   Write LLLL bytes at address AA.AA return OK */
+		case 'M':
+			/* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToInt(&ptr, &addr) &&
+			    (*(ptr++) == ',') &&
+			    (hexToInt(&ptr, &length)) && (*(ptr++) == ':')) {
+				hex2mem(ptr, (char *) addr, length, 1);
+
+				if (mem_err) {
+					strcpy(remcomOutBuffer, "E03");
+					debug_error("memory fault\n", NULL);
+				} else {
+					strcpy(remcomOutBuffer, "OK");
+				}
+
+				ptr = 0;
+			}
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E02");
+				debug_error
+				    ("malformed write memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+		case 'S':
+			remcomInBuffer[0] = 's';
+		case 'C':
+			/* Csig;AA..AA where ;AA..AA is optional
+			 * continue with signal
+			 * Since signals are meaning less to us, delete that
+			 * part and then fall into the 'c' code.
+			 */
+			ptr = &remcomInBuffer[1];
+			length = 2;
+			while (*ptr && *ptr != ';') {
+				length++;
+				ptr++;
+			}
+			if (*ptr) {
+				do {
+					ptr++;
+					*(ptr - length++) = *ptr;
+				} while (*ptr);
+			} else {
+				remcomInBuffer[1] = 0;
+			}
+
+			/* cAA..AA  Continue at address AA..AA(optional) */
+			/* sAA..AA  Step one instruction from AA..AA(optional) */
+			/* D	    detach, reply OK and then continue */
+		case 'c':
+		case 's':
+		case 'D':
+
+			/* try to read optional parameter,
+			   pc unchanged if no parm */
+			ptr = &remcomInBuffer[1];
+			if (hexToInt(&ptr, &addr)) {
+				if (remote_debug)
+					printk("Changing EIP to 0x%x\n", addr);
+
+				regs.eip = addr;
+			}
+
+			newPC = regs.eip;
+
+			/* clear the trace bit */
+			regs.eflags &= 0xfffffeff;
+
+			/* set the trace bit if we're stepping */
+			if (remcomInBuffer[0] == 's')
+				regs.eflags |= 0x100;
+
+			/* detach is a friendly version of continue. Note that
+			   debugging is still enabled (e.g hit control C)
+			 */
+			if (remcomInBuffer[0] == 'D') {
+				strcpy(remcomOutBuffer, "OK");
+				putpacket(remcomOutBuffer);
+			}
+
+			if (remote_debug) {
+				printk("Resuming execution\n");
+				print_regs(&regs);
+			}
+			asm volatile ("movl %%db6, %0\n":"=r" (dr6)
+				      :);
+			if (!(dr6 & 0x4000)) {
+				for (breakno = 0; breakno < 4; ++breakno) {
+					if (dr6 & (1 << breakno) &&
+					    (breakinfo[breakno].type == 0)) {
+						/* Set restore flag */
+						regs.eflags |= 0x10000;
+						break;
+					}
+				}
+			}
+
+			if (kgdboe)
+				netpoll_set_trap(0);
+
+			correct_hw_break();
+			asm volatile ("movl %0, %%db6\n"::"r" (0));
+			goto exit_kgdb;
+
+			/* kill the program */
+		case 'k':	/* do nothing */
+			break;
+
+			/* query */
+		case 'q':
+			nothreads = 0;
+			switch (remcomInBuffer[1]) {
+			case 'f':
+				threadid = 1;
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+			case 's':
+				if (!cmp_str(&remcomInBuffer[2],
+					     "ThreadInfo", 10))
+					break;
+
+				remcomOutBuffer[nothreads++] = 'm';
+				for (; threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						nothreads += int_to_hex_v(
+							&remcomOutBuffer[
+								nothreads],
+							threadid);
+						if (thread_min > threadid)
+							thread_min = threadid;
+						remcomOutBuffer[
+							nothreads] = ',';
+						nothreads++;
+						if (nothreads > BUFMAX - 10)
+							break;
+					}
+				}
+				if (remcomOutBuffer[nothreads - 1] == 'm') {
+					remcomOutBuffer[nothreads - 1] = 'l';
+				} else {
+					nothreads--;
+				}
+				remcomOutBuffer[nothreads] = 0;
+				break;
+
+#ifdef old_thread_list /* Old thread info request */
+			case 'L':
+				/* List threads */
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+				unpack_byte(remcomInBuffer + 3, &maxthreads);
+				unpack_threadid(remcomInBuffer + 5, &thref);
+				do {
+					int buf_thread_limit =
+					    (BUFMAX - 22) / BUF_THREAD_ID_SIZE;
+					if (maxthreads > buf_thread_limit) {
+						maxthreads = buf_thread_limit;
+					}
+				} while (0);
+				remcomOutBuffer[0] = 'q';
+				remcomOutBuffer[1] = 'M';
+				remcomOutBuffer[4] = '0';
+				pack_threadid(remcomOutBuffer + 5, &thref);
+
+				threadid = threadref_to_int(&thref);
+				for (nothreads = 0;
+				     nothreads < maxthreads &&
+				     threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						int_to_threadref(&thref,
+								 threadid);
+						pack_threadid(remcomOutBuffer +
+							      21 +
+							      nothreads * 16,
+							      &thref);
+						nothreads++;
+						if (thread_min > threadid)
+							thread_min = threadid;
+					}
+				}
+
+				if (threadid == PID_MAX + MAX_NO_CPUS) {
+					remcomOutBuffer[4] = '1';
+				}
+				pack_hex_byte(remcomOutBuffer + 2, nothreads);
+				remcomOutBuffer[21 + nothreads * 16] = '\0';
+				break;
+#endif
+			case 'C':
+				/* Current thread id */
+				remcomOutBuffer[0] = 'Q';
+				remcomOutBuffer[1] = 'C';
+				threadid = current->pid;
+				if (!threadid) {
+					/*
+					 * idle thread
+					 */
+					for (threadid = PID_MAX;
+					     threadid < PID_MAX + MAX_NO_CPUS;
+					     threadid++) {
+						if (current ==
+						    idle_task(threadid -
+							      PID_MAX))
+							break;
+					}
+				}
+				int_to_threadref(&thref, threadid);
+				pack_threadid(remcomOutBuffer + 2, &thref);
+				remcomOutBuffer[18] = '\0';
+				break;
+
+			case 'E':
+				/* Print exception info */
+				printexceptioninfo(exceptionVector,
+						   err_code, remcomOutBuffer);
+				break;
+			case 'T':{
+				char * nptr;
+				/* Thread extra info */
+				if (!cmp_str(&remcomInBuffer[2],
+					    "hreadExtraInfo,", 15)) {
+					break;
+				}
+				ptr = &remcomInBuffer[17];
+				hexToInt(&ptr, &threadid);
+				thread = getthread(threadid);
+				nptr = &thread->comm[0];
+				length = 0;
+				ptr = &remcomOutBuffer[0];
+				do {
+					length++;
+					ptr = pack_hex_byte(ptr, *nptr++);
+				 } while (*nptr && length < 16);
+				/*
+				 * would like that 16 to be the size of
+				 * task_struct.comm but don't know the
+				 * syntax..
+				 */
+				*ptr = 0;
+			}
+			}
+			break;
+
+			/* task related */
+		case 'H':
+			switch (remcomInBuffer[1]) {
+			case 'g':
+				ptr = &remcomInBuffer[2];
+				hexToInt(&ptr, &threadid);
+				thread = getthread(threadid);
+				if (!thread) {
+					remcomOutBuffer[0] = 'E';
+					remcomOutBuffer[1] = '\0';
+					break;
+				}
+				/*
+				 * Just in case I forget what this is all about,
+				 * the "thread info" command to gdb causes it
+				 * to ask for a thread list.  It then switches
+				 * to each thread and asks for the registers.
+				 * For this (and only this) usage, we want to
+				 * fudge the registers of tasks not on the run
+				 * list (i.e. waiting) to show the routine that
+				 * called schedule. Also, gdb, is a minimalist
+				 * in that if the current thread is the last
+				 * it will not re-read the info when done.
+				 * This means that in this case we must show
+				 * the real registers. So here is how we do it:
+				 * Each entry we keep track of the min
+				 * thread in the list (the last that gdb will)
+				 * get info for.  We also keep track of the
+				 * starting thread.
+				 * "thread_list" is cleared when switching back
+				 * to the min thread if it is was current, or
+				 * if it was not current, thread_list is set
+				 * to 1.  When the switch to current comes,
+				 * if thread_list is 1, clear it, else do
+				 * nothing.
+				 */
+				usethread = thread;
+				if ((thread_list == 1) &&
+				    (thread == thread_list_start)) {
+					thread_list = 0;
+				}
+				if (thread_list && (threadid == thread_min)) {
+					if (thread == thread_list_start) {
+						thread_list = 0;
+					} else {
+						thread_list = 1;
+					}
+				}
+				/* follow through */
+			case 'c':
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				break;
+			}
+			break;
+
+			/* Query thread status */
+		case 'T':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &threadid);
+			thread = getthread(threadid);
+			if (thread) {
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				if (thread_min > threadid)
+					thread_min = threadid;
+			} else {
+				remcomOutBuffer[0] = 'E';
+				remcomOutBuffer[1] = '\0';
+			}
+			break;
+
+		case 'Y': /* set up a hardware breakpoint */
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &breakno);
+			ptr++;
+			hexToInt(&ptr, &breaktype);
+			ptr++;
+			hexToInt(&ptr, &length);
+			ptr++;
+			hexToInt(&ptr, &addr);
+			if (set_hw_break(breakno & 0x3,
+					 breaktype & 0x3,
+					 length & 0x3, addr) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+			/* Remove hardware breakpoint */
+		case 'y':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &breakno);
+			if (remove_hw_break(breakno & 0x3) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+		case 'r':	/* reboot */
+			strcpy(remcomOutBuffer, "OK");
+			putpacket(remcomOutBuffer);
+			/*to_gdb("Rebooting\n"); */
+			/* triplefault	 no return from here */
+			{
+				static long no_idt[2];
+				__asm__ __volatile__("lidt %0"::"m"(no_idt[0]));
+				BREAKPOINT;
+			}
+
+		}		/* switch */
+
+		/* reply to the request */
+		putpacket(remcomOutBuffer);
+	}			/* while(1==1) */
+	/*
+	 *  reached by goto only.
+	 */
+      exit_kgdb:
+	/*
+	 * Here is where we set up to trap a gdb function call.	 NEW_esp
+	 * will be changed if we are trying to do this.	 We handle both
+	 * adding and subtracting, thus allowing gdb to put grung on
+	 * the stack which it removes later.
+	 */
+	if (NEW_esp != OLD_esp) {
+		int *ptr = END_OF_LOOKASIDE;
+		if (NEW_esp < OLD_esp)
+			ptr -= (OLD_esp - NEW_esp) / sizeof (int);
+		*--ptr = linux_regs->eflags;
+		*--ptr = linux_regs->xcs;
+		*--ptr = linux_regs->eip;
+		*--ptr = linux_regs->ecx;
+		*--ptr = linux_regs->ebx;
+		*--ptr = linux_regs->eax;
+		linux_regs->ecx = NEW_esp - (sizeof (int) * 6);
+		linux_regs->ebx = (unsigned int) END_OF_LOOKASIDE;
+		if (NEW_esp < OLD_esp) {
+			linux_regs->eip = (unsigned int) fn_call_stub;
+		} else {
+			linux_regs->eip = (unsigned int) fn_rtn_stub;
+			linux_regs->eax = NEW_esp;
+		}
+		linux_regs->eflags &= ~(IF_BIT | TF_BIT);
+	}
+#ifdef CONFIG_SMP
+	/*
+	 * Release gdb wait locks
+	 * Sanity check time.  Must have at least one cpu to run.  Also single
+	 * step must not be done if the current cpu is on hold.
+	 */
+	if (spinlock_count == 1) {
+		int ss_hold = (regs.eflags & 0x100) && kgdb_info.hold_on_sstep;
+		int cpu_avail = 0;
+		int i;
+
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			if (!cpu_online(i))
+				break;
+			if (!hold_cpu(i)) {
+				cpu_avail = 1;
+			}
+		}
+		/*
+		 * Early in the bring up there will be NO cpus on line...
+		 */
+		if (!cpu_avail && !cpus_empty(cpu_online_map)) {
+			to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n");
+			goto once_again;
+		}
+		if (hold_cpu(smp_processor_id()) && (regs.eflags & 0x100)) {
+			to_gdb
+			    ("Current cpu must be unblocked to single step\n");
+			goto once_again;
+		}
+		if (!(ss_hold)) {
+			int i;
+			for (i = 0; i < MAX_NO_CPUS; i++) {
+				if (!hold_cpu(i)) {
+					spin_unlock(&waitlocks[i]);
+				}
+			}
+		} else {
+			spin_unlock(&waitlocks[smp_processor_id()]);
+		}
+		/* Release kgdb spinlock */
+		KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+		/*
+		 * If this cpu is on hold, this is where we
+		 * do it.  Note, the NMI will pull us out of here,
+		 * but will return as the above lock is not held.
+		 * We will stay here till another cpu releases the lock for us.
+		 */
+		spin_unlock_wait(waitlocks + smp_processor_id());
+		kgdb_local_irq_restore(flags);
+		return (0);
+	}
+#if 0
+exit_just_unlock:
+#endif
+#endif
+	/* Release kgdb spinlock */
+	KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+	kgdb_local_irq_restore(flags);
+	return (0);
+}
+
+/* this function is used to set up exception handlers for tracing and
+ * breakpoints.
+ * This function is not needed as the above line does all that is needed.
+ * We leave it for backward compatitability...
+ */
+void
+set_debug_traps(void)
+{
+	/*
+	 * linux_debug_hook is defined in traps.c.  We store a pointer
+	 * to our own exception handler into it.
+
+	 * But really folks, every hear of labeled common, an old Fortran
+	 * concept.  Lots of folks can reference it and it is define if
+	 * anyone does.	 Only one can initialize it at link time.  We do
+	 * this with the hook.	See the statement above.  No need for any
+	 * executable code and it is ready as soon as the kernel is
+	 * loaded.  Very desirable in kernel debugging.
+
+	 linux_debug_hook = handle_exception ;
+	 */
+
+	/* In case GDB is started before us, ack any packets (presumably
+	   "$?#xx") sitting there.
+	   putDebugChar ('+');
+
+	   initialized = 1;
+	 */
+}
+
+/* This function will generate a breakpoint exception.	It is used at the
+   beginning of a program to sync up with a debugger and can be used
+   otherwise as a quick means to stop program execution and "break" into
+   the debugger. */
+/* But really, just use the BREAKPOINT macro.  We will handle the int stuff
+ */
+
+#ifdef later
+/*
+ * possibly we should not go thru the traps.c code at all?  Someday.
+ */
+void
+do_kgdb_int3(struct pt_regs *regs, long error_code)
+{
+	kgdb_handle_exception(3, 5, error_code, regs);
+	return;
+}
+#endif
+#undef regs
+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
+asmlinkage void
+bad_sys_call_exit(int stuff)
+{
+	struct pt_regs *regs = (struct pt_regs *) &stuff;
+	printk("Sys call %d return with %x preempt_count\n",
+	       (int) regs->orig_eax, preempt_count());
+}
+#endif
+#ifdef CONFIG_STACK_OVERFLOW_TEST
+#include <asm/kgdb.h>
+asmlinkage void
+stack_overflow(void)
+{
+#ifdef BREAKPOINT
+	BREAKPOINT;
+#else
+	printk("Kernel stack overflow, looping forever\n");
+#endif
+	while (1) {
+	}
+}
+#endif
+
+#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE)
+char gdbconbuf[BUFMAX];
+
+static void
+kgdb_gdb_message(const char *s, unsigned count)
+{
+	int i;
+	int wcount;
+	char *bufptr;
+	/*
+	 * This takes care of NMI while spining out chars to gdb
+	 */
+	IF_SMP(in_kgdb_console = 1);
+	gdbconbuf[0] = 'O';
+	bufptr = gdbconbuf + 1;
+	while (count > 0) {
+		if ((count << 1) > (BUFMAX - 2)) {
+			wcount = (BUFMAX - 2) >> 1;
+		} else {
+			wcount = count;
+		}
+		count -= wcount;
+		for (i = 0; i < wcount; i++) {
+			bufptr = pack_hex_byte(bufptr, s[i]);
+		}
+		*bufptr = '\0';
+		s += wcount;
+
+		putpacket(gdbconbuf);
+
+	}
+	IF_SMP(in_kgdb_console = 0);
+}
+#endif
+#ifdef CONFIG_SMP
+static void
+to_gdb(const char *s)
+{
+	int count = 0;
+	while (s[count] && (count++ < BUFMAX)) ;
+	kgdb_gdb_message(s, count);
+}
+#endif
+#ifdef CONFIG_KGDB_CONSOLE
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+
+void
+kgdb_console_write(struct console *co, const char *s, unsigned count)
+{
+
+	if (gdb_i386vector == -1) {
+		/*
+		 * We have not yet talked to gdb.  What to do...
+		 * lets break, on continue we can do the write.
+		 * But first tell him whats up. Uh, well no can do,
+		 * as this IS the console.  Oh well...
+		 * We do need to wait or the messages will be lost.
+		 * Other option would be to tell the above code to
+		 * ignore this breakpoint and do an auto return,
+		 * but that might confuse gdb.	Also this happens
+		 * early enough in boot up that we don't have the traps
+		 * set up yet, so...
+		 */
+		breakpoint();
+	}
+	kgdb_gdb_message(s, count);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Serial KGDB driver
+ * ------------------------------------------------------------
+ */
+
+static struct console kgdbcons = {
+	name:"kgdb",
+	write:kgdb_console_write,
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	device:kgdb_console_device,
+#endif
+	flags:CON_PRINTBUFFER | CON_ENABLED,
+	index:-1,
+};
+
+/*
+ * The trick here is that this file gets linked before printk.o
+ * That means we get to peer at the console info in the command
+ * line before it does.	 If we are up, we register, otherwise,
+ * do nothing.	By returning 0, we allow printk to look also.
+ */
+static int kgdb_console_enabled;
+
+int __init
+kgdb_console_init(char *str)
+{
+	if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) {
+		register_console(&kgdbcons);
+		kgdb_console_enabled = 1;
+	}
+	return 0;		/* let others look at the string */
+}
+
+__setup("console=", kgdb_console_init);
+
+#ifdef CONFIG_KGDB_USER_CONSOLE
+static kdev_t kgdb_console_device(struct console *c);
+/* This stuff sort of works, but it knocks out telnet devices
+ * we are leaving it here in case we (or you) find time to figure it out
+ * better..
+ */
+
+/*
+ * We need a real char device as well for when the console is opened for user
+ * space activities.
+ */
+
+static int
+kgdb_consdev_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t
+kgdb_consdev_write(struct file *file, const char *buf,
+		   size_t count, loff_t * ppos)
+{
+	int size, ret = 0;
+	static char kbuf[128];
+	static DECLARE_MUTEX(sem);
+
+	/* We are not reentrant... */
+	if (down_interruptible(&sem))
+		return -ERESTARTSYS;
+
+	while (count > 0) {
+		/* need to copy the data from user space */
+		size = count;
+		if (size > sizeof (kbuf))
+			size = sizeof (kbuf);
+		if (copy_from_user(kbuf, buf, size)) {
+			ret = -EFAULT;
+			break;;
+		}
+		kgdb_console_write(&kgdbcons, kbuf, size);
+		count -= size;
+		ret += size;
+		buf += size;
+	}
+
+	up(&sem);
+
+	return ret;
+}
+
+struct file_operations kgdb_consdev_fops = {
+	open:kgdb_consdev_open,
+	write:kgdb_consdev_write
+};
+static kdev_t
+kgdb_console_device(struct console *c)
+{
+	return MKDEV(TTYAUX_MAJOR, 1);
+}
+
+/*
+ * This routine gets called from the serial stub in the i386/lib
+ * This is so it is done late in bring up (just before the console open).
+ */
+void
+kgdb_console_finit(void)
+{
+	if (kgdb_console_enabled) {
+		char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1));
+		char *cp = cptr;
+		while (*cptr && *cptr != '(')
+			cptr++;
+		*cptr = 0;
+		unregister_chrdev(TTYAUX_MAJOR, cp);
+		register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops);
+	}
+}
+#endif
+#endif
+#ifdef CONFIG_KGDB_TS
+#include <asm/msr.h>		/* time stamp code */
+#include <asm/hardirq.h>	/* in_interrupt */
+#ifdef CONFIG_KGDB_TS_64
+#define DATA_POINTS 64
+#endif
+#ifdef CONFIG_KGDB_TS_128
+#define DATA_POINTS 128
+#endif
+#ifdef CONFIG_KGDB_TS_256
+#define DATA_POINTS 256
+#endif
+#ifdef CONFIG_KGDB_TS_512
+#define DATA_POINTS 512
+#endif
+#ifdef CONFIG_KGDB_TS_1024
+#define DATA_POINTS 1024
+#endif
+#ifndef DATA_POINTS
+#define DATA_POINTS 128		/* must be a power of two */
+#endif
+#define INDEX_MASK (DATA_POINTS - 1)
+#if (INDEX_MASK & DATA_POINTS)
+#error "CONFIG_KGDB_TS_COUNT must be a power of 2"
+#endif
+struct kgdb_and_then_struct {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	int data0;
+	int data1;
+};
+struct kgdb_and_then_struct2 {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	struct task_struct *t1;
+	struct task_struct *t2;
+};
+struct kgdb_and_then_struct kgdb_data[DATA_POINTS];
+
+struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0];
+int kgdb_and_then_count;
+
+void
+kgdb_tstamp(int line, char *source, int data0, int data1)
+{
+	static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED;
+	int flags;
+	kgdb_local_irq_save(flags);
+	spin_lock(&ts_spin);
+	rdtscll(kgdb_and_then->at_time);
+#ifdef CONFIG_SMP
+	kgdb_and_then->on_cpu = smp_processor_id();
+#endif
+	kgdb_and_then->task = current;
+	kgdb_and_then->from_ln = line;
+	kgdb_and_then->in_src = source;
+	kgdb_and_then->from = __builtin_return_address(0);
+	kgdb_and_then->with_shpf = (int *) (((flags & IF_BIT) >> 9) |
+					    (preempt_count() << 8));
+	kgdb_and_then->data0 = data0;
+	kgdb_and_then->data1 = data1;
+	kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK];
+	spin_unlock(&ts_spin);
+	kgdb_local_irq_restore(flags);
+#ifdef CONFIG_PREEMPT
+
+#endif
+	return;
+}
+#endif
+typedef int gdb_debug_hook(int exceptionVector,
+			   int signo, int err_code, struct pt_regs *linux_regs);
+gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception;	/* histerical reasons... */
+
+static int kgdb_need_breakpoint[NR_CPUS];
+
+void kgdb_schedule_breakpoint(void)
+{
+	kgdb_need_breakpoint[smp_processor_id()] = 1;
+}
+
+void kgdb_process_breakpoint(void)
+{
+	/*
+	 * Handle a breakpoint queued from inside network driver code
+         * to avoid reentrancy issues
+	 */
+	if (kgdb_need_breakpoint[smp_processor_id()]) {
+		kgdb_need_breakpoint[smp_processor_id()] = 0;
+		BREAKPOINT;
+	}
+}
+
--- diff/arch/i386/lib/kgdb_serial.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/i386/lib/kgdb_serial.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,499 @@
+/*
+ * Serial interface GDB stub
+ *
+ * Written (hacked together) by David Grothe (dave@gcom.com)
+ * Modified to allow invokation early in boot see also
+ * kgdb.h for instructions by George Anzinger(george@mvista.com)
+ * Modified to handle debugging over ethernet by Robert Walsh
+ * <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ * code by San Mehat.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/kgdb_local.h>
+#ifdef CONFIG_KGDB_USER_CONSOLE
+extern void kgdb_console_finit(void);
+#endif
+#define PRNT_off
+#define TEST_EXISTANCE
+#ifdef PRNT
+#define dbprintk(s) printk s
+#else
+#define dbprintk(s)
+#endif
+#define TEST_INTERRUPT_off
+#ifdef TEST_INTERRUPT
+#define intprintk(s) printk s
+#else
+#define intprintk(s)
+#endif
+
+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+
+#define	GDB_BUF_SIZE	512	/* power of 2, please */
+
+static char gdb_buf[GDB_BUF_SIZE];
+static int gdb_buf_in_inx;
+static atomic_t gdb_buf_in_cnt;
+static int gdb_buf_out_inx;
+
+struct async_struct *gdb_async_info;
+static int gdb_async_irq;
+
+#define outb_px(a,b) outb_p(b,a)
+
+static void program_uart(struct async_struct *info);
+static void write_char(struct async_struct *info, int chr);
+/*
+ * Get a byte from the hardware data buffer and return it
+ */
+static int
+read_data_bfr(struct async_struct *info)
+{
+	char it = inb_p(info->port + UART_LSR);
+
+	if (it & UART_LSR_DR)
+		return (inb_p(info->port + UART_RX));
+	/*
+	 * If we have a framing error assume somebody messed with
+	 * our uart.  Reprogram it and send '-' both ways...
+	 */
+	if (it & 0xc) {
+		program_uart(info);
+		write_char(info, '-');
+		return ('-');
+	}
+	return (-1);
+
+}				/* read_data_bfr */
+
+/*
+ * Get a char if available, return -1 if nothing available.
+ * Empty the receive buffer first, then look at the interface hardware.
+
+ * Locking here is a bit of a problem.	We MUST not lock out communication
+ * if we are trying to talk to gdb about a kgdb entry.	ON the other hand
+ * we can loose chars in the console pass thru if we don't lock.  It is also
+ * possible that we could hold the lock or be waiting for it when kgdb
+ * NEEDS to talk.  Since kgdb locks down the world, it does not need locks.
+ * We do, of course have possible issues with interrupting a uart operation,
+ * but we will just depend on the uart status to help keep that straight.
+
+ */
+static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED;
+#ifdef CONFIG_SMP
+extern spinlock_t kgdb_spinlock;
+#endif
+
+static int
+read_char(struct async_struct *info)
+{
+	int chr;
+	unsigned long flags;
+	local_irq_save(flags);
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_lock(&uart_interrupt_lock);
+	}
+#endif
+	if (atomic_read(&gdb_buf_in_cnt) != 0) {	/* intr routine has q'd chars */
+		chr = gdb_buf[gdb_buf_out_inx++];
+		gdb_buf_out_inx &= (GDB_BUF_SIZE - 1);
+		atomic_dec(&gdb_buf_in_cnt);
+	} else {
+		chr = read_data_bfr(info);
+	}
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_unlock(&uart_interrupt_lock);
+	}
+#endif
+	local_irq_restore(flags);
+	return (chr);
+}
+
+/*
+ * Wait until the interface can accept a char, then write it.
+ */
+static void
+write_char(struct async_struct *info, int chr)
+{
+	while (!(inb_p(info->port + UART_LSR) & UART_LSR_THRE)) ;
+
+	outb_p(chr, info->port + UART_TX);
+
+}				/* write_char */
+
+/*
+ * Mostly we don't need a spinlock, but since the console goes
+ * thru here with interrutps on, well, we need to catch those
+ * chars.
+ */
+/*
+ * This is the receiver interrupt routine for the GDB stub.
+ * It will receive a limited number of characters of input
+ * from the gdb  host machine and save them up in a buffer.
+ *
+ * When the gdb stub routine tty_getDebugChar() is called it
+ * draws characters out of the buffer until it is empty and
+ * then reads directly from the serial port.
+ *
+ * We do not attempt to write chars from the interrupt routine
+ * since the stubs do all of that via tty_putDebugChar() which
+ * writes one byte after waiting for the interface to become
+ * ready.
+ *
+ * The debug stubs like to run with interrupts disabled since,
+ * after all, they run as a consequence of a breakpoint in
+ * the kernel.
+ *
+ * Perhaps someone who knows more about the tty driver than I
+ * care to learn can make this work for any low level serial
+ * driver.
+ */
+static irqreturn_t
+gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct async_struct *info;
+	unsigned long flags;
+
+	info = gdb_async_info;
+	if (!info || !info->tty || irq != gdb_async_irq)
+		return IRQ_NONE;
+
+	local_irq_save(flags);
+	spin_lock(&uart_interrupt_lock);
+	do {
+		int chr = read_data_bfr(info);
+		intprintk(("Debug char on int: %x hex\n", chr));
+		if (chr < 0)
+			continue;
+
+		if (chr == 3) {	/* Ctrl-C means remote interrupt */
+			BREAKPOINT;
+			continue;
+		}
+
+		if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) {
+			/* buffer overflow tosses early char */
+			read_char(info);
+		}
+		gdb_buf[gdb_buf_in_inx++] = chr;
+		gdb_buf_in_inx &= (GDB_BUF_SIZE - 1);
+	} while (inb_p(info->port + UART_IIR) & UART_IIR_RDI);
+	spin_unlock(&uart_interrupt_lock);
+	local_irq_restore(flags);
+	return IRQ_HANDLED;
+}				/* gdb_interrupt */
+
+/*
+ * Just a NULL routine for testing.
+ */
+void
+gdb_null(void)
+{
+}				/* gdb_null */
+
+/* These structure are filled in with values defined in asm/kgdb_local.h
+ */
+static struct serial_state state = SB_STATE;
+static struct async_struct local_info = SB_INFO;
+static int ok_to_enable_ints = 0;
+static void kgdb_enable_ints_now(void);
+
+extern char *kgdb_version;
+/*
+ * Hook an IRQ for KGDB.
+ *
+ * This routine is called from tty_putDebugChar, below.
+ */
+static int ints_disabled = 1;
+int
+gdb_hook_interrupt(struct async_struct *info, int verb)
+{
+	struct serial_state *state = info->state;
+	unsigned long flags;
+	int port;
+#ifdef TEST_EXISTANCE
+	int scratch, scratch2;
+#endif
+
+	/* The above fails if memory managment is not set up yet.
+	 * Rather than fail the set up, just keep track of the fact
+	 * and pick up the interrupt thing later.
+	 */
+	gdb_async_info = info;
+	port = gdb_async_info->port;
+	gdb_async_irq = state->irq;
+	if (verb) {
+		printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n",
+		       kgdb_version,
+		       port,
+		       gdb_async_irq, gdb_async_info->state->custom_divisor);
+	}
+	local_irq_save(flags);
+#ifdef TEST_EXISTANCE
+	/* Existance test */
+	/* Should not need all this, but just in case.... */
+
+	scratch = inb_p(port + UART_IER);
+	outb_px(port + UART_IER, 0);
+	outb_px(0xff, 0x080);
+	scratch2 = inb_p(port + UART_IER);
+	outb_px(port + UART_IER, scratch);
+	if (scratch2) {
+		printk
+		    ("gdb_hook_interrupt: Could not clear IER, not a UART!\n");
+		local_irq_restore(flags);
+		return 1;	/* We failed; there's nothing here */
+	}
+	scratch2 = inb_p(port + UART_LCR);
+	outb_px(port + UART_LCR, 0xBF);	/* set up for StarTech test */
+	outb_px(port + UART_EFR, 0);	/* EFR is the same as FCR */
+	outb_px(port + UART_LCR, 0);
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO);
+	scratch = inb_p(port + UART_IIR) >> 6;
+	if (scratch == 1) {
+		printk("gdb_hook_interrupt: Undefined UART type!"
+		       "  Not a UART! \n");
+		local_irq_restore(flags);
+		return 1;
+	} else {
+		dbprintk(("gdb_hook_interrupt: UART type "
+			  "is %d where 0=16450, 2=16550 3=16550A\n", scratch));
+	}
+	scratch = inb_p(port + UART_MCR);
+	outb_px(port + UART_MCR, UART_MCR_LOOP | scratch);
+	outb_px(port + UART_MCR, UART_MCR_LOOP | 0x0A);
+	scratch2 = inb_p(port + UART_MSR) & 0xF0;
+	outb_px(port + UART_MCR, scratch);
+	if (scratch2 != 0x90) {
+		printk("gdb_hook_interrupt: "
+		       "Loop back test failed! Not a UART!\n");
+		local_irq_restore(flags);
+		return scratch2 + 1000;	/* force 0 to fail */
+	}
+#endif				/* test existance */
+	program_uart(info);
+	local_irq_restore(flags);
+
+	return (0);
+
+}				/* gdb_hook_interrupt */
+
+static void
+program_uart(struct async_struct *info)
+{
+	int port = info->port;
+
+	(void) inb_p(port + UART_RX);
+	outb_px(port + UART_IER, 0);
+
+	(void) inb_p(port + UART_RX);	/* serial driver comments say */
+	(void) inb_p(port + UART_IIR);	/* this clears the interrupt regs */
+	(void) inb_p(port + UART_MSR);
+	outb_px(port + UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
+	outb_px(port + UART_DLL, info->state->custom_divisor & 0xff);	/* LS */
+	outb_px(port + UART_DLM, info->state->custom_divisor >> 8);	/* MS  */
+	outb_px(port + UART_MCR, info->MCR);
+
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR);	/* set fcr */
+	outb_px(port + UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1);	/* set fcr */
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
+	}
+	return;
+}
+
+/*
+ * tty_getDebugChar
+ *
+ * This is a GDB stub routine.	It waits for a character from the
+ * serial interface and then returns it.  If there is no serial
+ * interface connection then it returns a bogus value which will
+ * almost certainly cause the system to hang.  In the
+ */
+int kgdb_in_isr = 0;
+int kgdb_in_lsr = 0;
+extern spinlock_t kgdb_spinlock;
+
+/* Caller takes needed protections */
+
+int
+tty_getDebugChar(void)
+{
+	volatile int chr, dum, time, end_time;
+
+	dbprintk(("tty_getDebugChar(port %x): ", gdb_async_info->port));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+	/*
+	 * This trick says if we wait a very long time and get
+	 * no char, return the -1 and let the upper level deal
+	 * with it.
+	 */
+	rdtsc(dum, time);
+	end_time = time + 2;
+	while (((chr = read_char(gdb_async_info)) == -1) &&
+	       (end_time - time) > 0) {
+		rdtsc(dum, time);
+	};
+	/*
+	 * This covers our butts if some other code messes with
+	 * our uart, hay, it happens :o)
+	 */
+	if (chr == -1)
+		program_uart(gdb_async_info);
+
+	dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' '));
+	return (chr);
+
+}				/* tty_getDebugChar */
+
+static int count = 3;
+static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED;
+
+static int __init
+kgdb_enable_ints(void)
+{
+	if (kgdboe) {
+		return 0;
+	}
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 1);
+	}
+	ok_to_enable_ints = 1;
+	kgdb_enable_ints_now();
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	kgdb_console_finit();
+#endif
+	return 0;
+}
+
+#ifdef CONFIG_SERIAL_8250
+void shutdown_for_kgdb(struct async_struct *gdb_async_info);
+#endif
+
+#ifdef CONFIG_DISCONTIGMEM
+static inline int kgdb_mem_init_done(void)
+{
+	return highmem_start_page != NULL;
+}
+#else
+static inline int kgdb_mem_init_done(void)
+{
+	return max_mapnr != 0;
+}
+#endif
+
+static void
+kgdb_enable_ints_now(void)
+{
+	if (!spin_trylock(&one_at_atime))
+		return;
+	if (!ints_disabled)
+		goto exit;
+	if (kgdb_mem_init_done() &&
+			ints_disabled) {	/* don't try till mem init */
+#ifdef CONFIG_SERIAL_8250
+		/*
+		 * The ifdef here allows the system to be configured
+		 * without the serial driver.
+		 * Don't make it a module, however, it will steal the port
+		 */
+		shutdown_for_kgdb(gdb_async_info);
+#endif
+		ints_disabled = request_irq(gdb_async_info->state->irq,
+					    gdb_interrupt,
+					    IRQ_T(gdb_async_info),
+					    "KGDB-stub", NULL);
+		intprintk(("KGDB: request_irq returned %d\n", ints_disabled));
+	}
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
+	}
+      exit:
+	spin_unlock(&one_at_atime);
+}
+
+/*
+ * tty_putDebugChar
+ *
+ * This is a GDB stub routine.	It waits until the interface is ready
+ * to transmit a char and then sends it.  If there is no serial
+ * interface connection then it simply returns to its caller, having
+ * pretended to send the char.	Caller takes needed protections.
+ */
+void
+tty_putDebugChar(int chr)
+{
+	dbprintk(("tty_putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n",
+		  gdb_async_info->port,
+		  chr,
+		  chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+
+	write_char(gdb_async_info, chr);	/* this routine will wait */
+	count = (chr == '#') ? 0 : count + 1;
+	if ((count == 2)) {	/* try to enable after */
+		if (ints_disabled & ok_to_enable_ints)
+			kgdb_enable_ints_now();	/* try to enable after */
+
+		/* We do this a lot because, well we really want to get these
+		 * interrupts.	The serial driver will clear these bits when it
+		 * initializes the chip.  Every thing else it does is ok,
+		 * but this.
+		 */
+		if (!ints_disabled) {
+			outb_px(gdb_async_info->port + UART_IER,
+				gdb_async_info->IER);
+		}
+	}
+
+}				/* tty_putDebugChar */
+
+/*
+ * This does nothing for the serial port, since it doesn't buffer.
+ */
+
+void tty_flushDebugChar(void)
+{
+}
+
+module_init(kgdb_enable_ints);
--- diff/arch/i386/pci/mmconfig.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/i386/pci/mmconfig.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,109 @@
+/*
+ * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
+ */
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include "pci.h"
+
+/* The physical address of the MMCONFIG aperture.  Set from ACPI tables. */
+u32 pci_mmcfg_base_addr;
+
+#define mmcfg_virt_addr (fix_to_virt(FIX_PCIE_MCFG))
+
+/* The base address of the last MMCONFIG device accessed */
+static u32 mmcfg_last_accessed_device;
+
+/*
+ * Functions for accessing PCI configuration space with MMCONFIG accesses
+ */
+
+static inline void pci_exp_set_dev_base(int bus, int devfn)
+{
+	u32 dev_base = pci_mmcfg_base_addr | (bus << 20) | (devfn << 12);
+	if (dev_base != mmcfg_last_accessed_device) {
+		mmcfg_last_accessed_device = dev_base;
+		set_fixmap(FIX_PCIE_MCFG, dev_base);
+	}
+}
+
+static int pci_mmcfg_read(int seg, int bus, int devfn, int reg, int len, u32 *value)
+{
+	unsigned long flags;
+
+	if (!value || (bus > 255) || (devfn > 255) || (reg > 4095))
+		return -EINVAL;
+
+	spin_lock_irqsave(&pci_config_lock, flags);
+
+	pci_exp_set_dev_base(bus, devfn);
+
+	switch (len) {
+	case 1:
+		*value = readb(mmcfg_virt_addr + reg);
+		break;
+	case 2:
+		*value = readw(mmcfg_virt_addr + reg);
+		break;
+	case 4:
+		*value = readl(mmcfg_virt_addr + reg);
+		break;
+	}
+
+	spin_unlock_irqrestore(&pci_config_lock, flags);
+
+	return 0;
+}
+
+static int pci_mmcfg_write(int seg, int bus, int devfn, int reg, int len, u32 value)
+{
+	unsigned long flags;
+
+	if ((bus > 255) || (devfn > 255) || (reg > 4095)) 
+		return -EINVAL;
+
+	spin_lock_irqsave(&pci_config_lock, flags);
+
+	pci_exp_set_dev_base(bus, devfn);
+
+	switch (len) {
+	case 1:
+		writeb(value, mmcfg_virt_addr + reg);
+		break;
+	case 2:
+		writew(value, mmcfg_virt_addr + reg);
+		break;
+	case 4:
+		writel(value, mmcfg_virt_addr + reg);
+		break;
+	}
+
+	/* Dummy read to flush PCI write */
+	readl(mmcfg_virt_addr);
+
+	spin_unlock_irqrestore(&pci_config_lock, flags);
+
+	return 0;
+}
+
+static struct pci_raw_ops pci_mmcfg = {
+	.read =		pci_mmcfg_read,
+	.write =	pci_mmcfg_write,
+};
+
+static int __init pci_mmcfg_init(void)
+{
+	if ((pci_probe & PCI_PROBE_MMCONF) == 0)
+		goto out;
+	if (!pci_mmcfg_base_addr)
+		goto out;
+
+	printk(KERN_INFO "PCI: Using MMCONFIG\n");
+	raw_pci_ops = &pci_mmcfg;
+	pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
+
+ out:
+	return 0;
+}
+
+arch_initcall(pci_mmcfg_init);
--- diff/arch/x86_64/Kconfig.kgdb	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/x86_64/Kconfig.kgdb	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,176 @@
+config KGDB
+	bool "Include kgdb kernel debugger"
+	depends on DEBUG_KERNEL
+	select DEBUG_INFO
+	help
+	  If you say Y here, the system will be compiled with the debug
+	  option (-g) and a debugging stub will be included in the
+	  kernel.  This stub communicates with gdb on another (host)
+	  computer via a serial port.  The host computer should have
+	  access to the kernel binary file (vmlinux) and a serial port
+	  that is connected to the target machine.  Gdb can be made to
+	  configure the serial port or you can use stty and setserial to
+	  do this. See the 'target' command in gdb. This option also
+	  configures in the ability to request a breakpoint early in the
+	  boot process.  To request the breakpoint just include 'kgdb'
+	  as a boot option when booting the target machine.  The system
+	  will then break as soon as it looks at the boot options.  This
+	  option also installs a breakpoint in panic and sends any
+	  kernel faults to the debugger. For more information see the
+	  Documentation/i386/kgdb.txt file.
+
+choice
+	depends on KGDB
+    	prompt "Debug serial port BAUD"
+	default KGDB_115200BAUD
+	help
+	  Gdb and the kernel stub need to agree on the baud rate to be
+	  used.  Some systems (x86 family at this writing) allow this to
+	  be configured.
+
+config KGDB_9600BAUD
+	bool "9600"
+
+config KGDB_19200BAUD
+	bool "19200"
+
+config KGDB_38400BAUD
+	bool "38400"
+
+config KGDB_57600BAUD
+	bool "57600"
+
+config KGDB_115200BAUD
+	bool "115200"
+endchoice
+
+config KGDB_PORT
+	hex "hex I/O port address of the debug serial port"
+	depends on KGDB
+	default  3f8
+	help
+	  Some systems (x86 family at this writing) allow the port
+	  address to be configured.  The number entered is assumed to be
+	  hex, don't put 0x in front of it.  The standard address are:
+	  COM1 3f8 , irq 4 and COM2 2f8 irq 3.  Setserial /dev/ttySx
+	  will tell you what you have.  It is good to test the serial
+	  connection with a live system before trying to debug.
+
+config KGDB_IRQ
+	int "IRQ of the debug serial port"
+	depends on KGDB
+	default 4
+	help
+	  This is the irq for the debug port.  If everything is working
+	  correctly and the kernel has interrupts on a control C to the
+	  port should cause a break into the kernel debug stub.
+
+config DEBUG_INFO
+	bool
+	depends on KGDB
+	default y
+
+config KGDB_MORE
+	bool "Add any additional compile options"
+	depends on KGDB
+	default n
+	help
+	  Saying yes here turns on the ability to enter additional
+	  compile options.
+
+
+config KGDB_OPTIONS
+	depends on KGDB_MORE
+	string "Additional compile arguments"
+	default "-O1"
+	help
+	  This option allows you enter additional compile options for
+	  the whole kernel compile.  Each platform will have a default
+	  that seems right for it.  For example on PPC "-ggdb -O1", and
+	  for i386 "-O1".  Note that by configuring KGDB "-g" is already
+	  turned on.  In addition, on i386 platforms
+	  "-fomit-frame-pointer" is deleted from the standard compile
+	  options.
+
+config NO_KGDB_CPUS
+	int "Number of CPUs"
+	depends on KGDB && SMP
+	default NR_CPUS
+	help
+
+	  This option sets the number of cpus for kgdb ONLY.  It is used
+	  to prune some internal structures so they look "nice" when
+	  displayed with gdb.  This is to overcome possibly larger
+	  numbers that may have been entered above.  Enter the real
+	  number to get nice clean kgdb_info displays.
+
+config KGDB_TS
+	bool "Enable kgdb time stamp macros?"
+	depends on KGDB
+	default n
+	help
+	  Kgdb event macros allow you to instrument your code with calls
+	  to the kgdb event recording function.  The event log may be
+	  examined with gdb at a break point.  Turning on this
+	  capability also allows you to choose how many events to
+	  keep. Kgdb always keeps the lastest events.
+
+choice
+	depends on KGDB_TS
+	prompt "Max number of time stamps to save?"
+	default KGDB_TS_128
+
+config KGDB_TS_64
+	bool "64"
+
+config KGDB_TS_128
+	bool "128"
+
+config KGDB_TS_256
+	bool "256"
+
+config KGDB_TS_512
+	bool "512"
+
+config KGDB_TS_1024
+	bool "1024"
+
+endchoice
+
+config STACK_OVERFLOW_TEST
+	bool "Turn on kernel stack overflow testing?"
+	depends on KGDB
+	default n
+	help
+	  This option enables code in the front line interrupt handlers
+	  to check for kernel stack overflow on interrupts and system
+	  calls.  This is part of the kgdb code on x86 systems.
+
+config KGDB_CONSOLE
+	bool "Enable serial console thru kgdb port"
+	depends on KGDB
+	default n
+	help
+	  This option enables the command line "console=kgdb" option.
+	  When the system is booted with this option in the command line
+	  all kernel printk output is sent to gdb (as well as to other
+	  consoles).  For this to work gdb must be connected.  For this
+	  reason, this command line option will generate a breakpoint if
+	  gdb has not yet connected.  After the gdb continue command is
+	  given all pent up console output will be printed by gdb on the
+	  host machine.  Neither this option, nor KGDB require the
+	  serial driver to be configured.
+
+config KGDB_SYSRQ
+	bool "Turn on SysRq 'G' command to do a break?"
+	depends on KGDB
+	default y
+	help
+	  This option includes an option in the SysRq code that allows
+	  you to enter SysRq G which generates a breakpoint to the KGDB
+	  stub.  This will work if the keyboard is alive and can
+	  interrupt the system.  Because of constraints on when the
+	  serial port interrupt can be enabled, this code may allow you
+	  to interrupt the system before the serial port control C is
+	  available.  Just say yes here.
+
--- diff/arch/x86_64/kernel/kgdb_stub.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/x86_64/kernel/kgdb_stub.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,2595 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * General Public License for more details.
+ *
+ */
+
+/*
+ * Copyright (c) 2000 VERITAS Software Corporation.
+ *
+ */
+/****************************************************************************
+ *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ *  Module name: remcom.c $
+ *  Revision: 1.34 $
+ *  Date: 91/03/09 12:29:49 $
+ *  Contributor:     Lake Stevens Instrument Division$
+ *
+ *  Description:     low level support for gdb debugger. $
+ *
+ *  Considerations:  only works on target hardware $
+ *
+ *  Written by:	     Glenn Engel $
+ *  Updated by:	     David Grothe <dave@gcom.com>
+ *  Updated by:	     Robert Walsh <rjwalsh@durables.org>
+ *  Updated by:	     wangdi <wangdi@clusterfs.com>
+ *  ModuleState:     Experimental $
+ *
+ *  NOTES:	     See Below $
+ *
+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
+ *  Compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
+ *
+ *  Changes to allow auto initilization.  All that is needed is that it
+ *  be linked with the kernel and a break point (int 3) be executed.
+ *  The header file <asm/kgdb.h> defines BREAKPOINT to allow one to do
+ *  this. It should also be possible, once the interrupt system is up, to
+ *  call putDebugChar("+").  Once this is done, the remote debugger should
+ *  get our attention by sending a ^C in a packet. George Anzinger
+ *  <george@mvista.com>
+ *  Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
+ *  Added thread support, support for multiple processors,
+ *	support for ia-32(x86) hardware debugging.
+ *	Amit S. Kale ( akale@veritas.com )
+ *
+ *  Modified to support debugging over ethernet by Robert Walsh
+ *  <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ *  code by San Mehat.
+ *
+ *  X86_64 changes from Andi Kleen's patch merged by Jim Houston
+ * 	(jim.houston@ccur.com).  If it works thank Andi if its broken
+ * 	blame me.
+ *
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
+ *  simulates a breakpoint by executing an int 3.
+ *
+ *************
+ *
+ *    The following gdb commands are supported:
+ *
+ * command	    function				   Return value
+ *
+ *    g		    return the value of the CPU registers  hex data or ENN
+ *    G		    set the value of the CPU registers	   OK or ENN
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA	   hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA	   OK or ENN
+ *
+ *    c		    Resume at current address		   SNN	 ( signal NN)
+ *    cAA..AA	    Continue at address AA..AA		   SNN
+ *
+ *    s		    Step one instruction		   SNN
+ *    sAA..AA	    Step one instruction from AA..AA	   SNN
+ *
+ *    k		    kill
+ *
+ *    ?		    What was the last sigval ?		   SNN	 (signal NN)
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>	 :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.	 '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:		  Reply:
+ * $m0,10#2a		   +$00010203040506070809101112131415#42
+ *
+ ****************************************************************************/
+#define KGDB_VERSION "<20030915.1651.33>"
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/string.h>		/* for strcpy */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>		/* for linux pt_regs struct */
+#include <asm/kgdb_local.h>
+#include <linux/list.h>
+#include <asm/atomic.h>
+#include <asm/processor.h>
+#include <linux/irq.h>
+#include <asm/desc.h>
+#include <linux/inet.h>
+#include <linux/netpoll.h>
+#include <linux/cpumask.h>
+#include <linux/bitops.h>
+#include <linux/notifier.h>
+#include <asm/kdebug.h>
+#include <asm/uaccess.h>
+#include <linux/ptrace.h>
+
+#define Dearly_printk(x...)
+int kgdb_enabled = 0;
+
+/************************************************************************
+ *
+ * external low-level support routines
+ */
+typedef void (*Function) (void);	/* pointer to a function */
+
+/* Thread reference */
+typedef unsigned char threadref[8];
+
+extern int tty_putDebugChar(int);     /* write a single character      */
+extern int tty_getDebugChar(void);    /* read and return a single char */
+extern void tty_flushDebugChar(void); /* flush pending characters      */
+extern int eth_putDebugChar(int);     /* write a single character      */
+extern int eth_getDebugChar(void);    /* read and return a single char */
+extern void eth_flushDebugChar(void); /* flush pending characters      */
+
+/************************************************************************/
+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
+/* at least NUMREGBYTES*2 are needed for register packets */
+/* Longer buffer is needed to list all threads */
+#define BUFMAX 400
+
+char *kgdb_version = KGDB_VERSION;
+
+/*  debug >  0 prints ill-formed commands in valid packets & checksum errors */
+int debug_regs = 0;		/* set to non-zero to print registers */
+
+/* filled in by an external module */
+char *gdb_module_offsets;
+
+static const char hexchars[] = "0123456789abcdef";
+
+/* Number of bytes of registers.  */
+#define NUMREGBYTES (NUMREGS * sizeof(unsigned long))
+/*
+ * Note that this register image is in a different order than
+ * the register image that Linux produces at interrupt time.
+ *
+ * Linux's register image is defined by struct pt_regs in ptrace.h.
+ * Just why GDB uses a different order is a historical mystery.
+ *
+ * Could add XMM and segment registers here.
+ */
+enum regnames {_RAX,
+	       _RBX,
+	       _RCX,
+	       _RDX,
+	       _RSI,
+	       _RDI,
+	       _RBP,
+	       _RSP,
+	       _R8,
+	       _R9,
+	       _R10,
+	       _R11,
+	       _R12,
+	       _R13,
+	       _R14,
+	       _R15,
+	       _PC,
+	       _PS,
+	       NUMREGS };
+
+
+/***************************  ASSEMBLY CODE MACROS *************************/
+/*
+ * Put the error code here just in case the user cares.
+ * Likewise, the vector number here (since GDB only gets the signal
+ * number through the usual means, and that's not very specific).
+ * The called_from is the return address so he can tell how we entered kgdb.
+ * This will allow him to seperate out the various possible entries.
+ */
+#define REMOTE_DEBUG 0		/* set != to turn on printing (also available in info) */
+
+#define PID_MAX PID_MAX_DEFAULT
+
+#ifdef CONFIG_SMP
+void smp_send_nmi_allbutself(void);
+#define IF_SMP(x) x
+#undef MAX_NO_CPUS
+#ifndef CONFIG_NO_KGDB_CPUS
+#define CONFIG_NO_KGDB_CPUS 2
+#endif
+#if CONFIG_NO_KGDB_CPUS > NR_CPUS
+#define MAX_NO_CPUS NR_CPUS
+#else
+#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS
+#endif
+#define hold_init hold_on_sstep: 1,
+#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL)
+#define NUM_CPUS num_online_cpus()
+#else
+#define IF_SMP(x)
+#define hold_init
+#undef MAX_NO_CPUS
+#define MAX_NO_CPUS 1
+#define NUM_CPUS 1
+#endif
+#define NOCPU (struct task_struct *)0xbad1fbad
+/* *INDENT-OFF*	 */
+struct kgdb_info {
+	int used_malloc;
+	void *called_from;
+	long long entry_tsc;
+	int errcode;
+	int vector;
+	int print_debug_info;
+#ifdef CONFIG_SMP
+	int hold_on_sstep;
+	struct {
+		volatile struct task_struct *task;
+		int pid;
+		int hold;
+		struct pt_regs *regs;
+	} cpus_waiting[MAX_NO_CPUS];
+#endif
+} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1};
+
+/* *INDENT-ON*	*/
+
+#define used_m kgdb_info.used_malloc
+/*
+ * This is little area we set aside to contain the stack we
+ * need to build to allow gdb to call functions.  We use one
+ * per cpu to avoid locking issues.  We will do all this work
+ * with interrupts off so that should take care of the protection
+ * issues.
+ */
+#define LOOKASIDE_SIZE 200	/* should be more than enough */
+#define MALLOC_MAX   200	/* Max malloc size */
+struct {
+	unsigned long rsp;
+	unsigned long array[LOOKASIDE_SIZE];
+} fn_call_lookaside[MAX_NO_CPUS];
+
+static int trap_cpu;
+static unsigned long OLD_esp;
+
+#define END_OF_LOOKASIDE  &fn_call_lookaside[trap_cpu].array[LOOKASIDE_SIZE]
+#define IF_BIT 0x200
+#define TF_BIT 0x100
+
+#define MALLOC_ROUND 8-1
+
+static char malloc_array[MALLOC_MAX];
+IF_SMP(static void to_gdb(const char *mess));
+void *
+malloc(int size)
+{
+
+	if (size <= (MALLOC_MAX - used_m)) {
+		int old_used = used_m;
+		used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND));
+		return &malloc_array[old_used];
+	} else {
+		return NULL;
+	}
+}
+
+/*
+ * I/O dispatch functions...
+ * Based upon kgdboe, either call the ethernet
+ * handler or the serial one..
+ */
+void
+putDebugChar(int c)
+{
+	if (!kgdboe) {
+		tty_putDebugChar(c);
+	} else {
+		eth_putDebugChar(c);
+	}
+}
+
+int
+getDebugChar(void)
+{
+	if (!kgdboe) {
+		return tty_getDebugChar();
+	} else {
+		return eth_getDebugChar();
+	}
+}
+
+void
+flushDebugChar(void)
+{
+	if (!kgdboe) {
+		tty_flushDebugChar();
+	} else {
+		eth_flushDebugChar();
+	}
+}
+
+/*
+ * Gdb calls functions by pushing agruments, including a return address
+ * on the stack and the adjusting EIP to point to the function.	 The
+ * whole assumption in GDB is that we are on a different stack than the
+ * one the "user" i.e. code that hit the break point, is on.  This, of
+ * course is not true in the kernel.  Thus various dodges are needed to
+ * do the call without directly messing with EIP (which we can not change
+ * as it is just a location and not a register.	 To adjust it would then
+ * require that we move every thing below EIP up or down as needed.  This
+ * will not work as we may well have stack relative pointer on the stack
+ * (such as the pointer to regs, for example).
+
+ * So here is what we do:
+ * We detect gdb attempting to store into the stack area and instead, store
+ * into the fn_call_lookaside.array at the same relative location as if it
+ * were the area ESP pointed at.  We also trap ESP modifications
+ * and uses these to adjust fn_call_lookaside.esp.  On entry
+ * fn_call_lookaside.esp will be set to point at the last entry in
+ * fn_call_lookaside.array.  This allows us to check if it has changed, and
+ * if so, on exit, we add the registers we will use to do the move and a
+ * trap/ interrupt return exit sequence.  We then adjust the eflags in the
+ * regs array (remember we now have a copy in the fn_call_lookaside.array) to
+ * kill the interrupt bit, AND we change EIP to point at our set up stub.
+ * As part of the register set up we preset the registers to point at the
+ * begining and end of the fn_call_lookaside.array, so all the stub needs to
+ * do is move words from the array to the stack until ESP= the desired value
+ * then do the rti.  This will then transfer to the desired function with
+ * all the correct registers.  Nifty huh?
+ */
+extern asmlinkage void fn_call_stub(void);
+extern asmlinkage void fn_rtn_stub(void);
+/*					   *INDENT-OFF*	 */
+__asm__("fn_rtn_stub:\n\t"
+	"movq %rax,%rsp\n\t"
+	"fn_call_stub:\n\t"
+	"1:\n\t"
+	"addq $-8,%rbx\n\t"
+	"movq (%rbx), %rax\n\t"
+	"pushq %rax\n\t"
+	"cmpq %rsp,%rcx\n\t"
+	"jne  1b\n\t"
+	"popq %rax\n\t"
+	"popq %rbx\n\t"
+	"popq %rcx\n\t"
+	"iret \n\t");
+/*					     *INDENT-ON*  */
+#define gdb_i386vector	kgdb_info.vector
+#define gdb_i386errcode kgdb_info.errcode
+#define waiting_cpus	kgdb_info.cpus_waiting
+#define remote_debug	kgdb_info.print_debug_info
+#define hold_cpu(cpu)	kgdb_info.cpus_waiting[cpu].hold
+/* gdb locks */
+
+#ifdef CONFIG_SMP
+static int in_kgdb_called;
+static spinlock_t waitlocks[MAX_NO_CPUS] =
+    {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED };
+/*
+ * The following array has the thread pointer of each of the "other"
+ * cpus.  We make it global so it can be seen by gdb.
+ */
+volatile int in_kgdb_entry_log[MAX_NO_CPUS];
+volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS];
+/*
+static spinlock_t continuelocks[MAX_NO_CPUS];
+*/
+spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED;
+/* waiters on our spinlock plus us */
+static atomic_t spinlock_waiters = ATOMIC_INIT(1);
+static int spinlock_count = 0;
+static int spinlock_cpu = 0;
+/*
+ * Note we use nested spin locks to account for the case where a break
+ * point is encountered when calling a function by user direction from
+ * kgdb. Also there is the memory exception recursion to account for.
+ * Well, yes, but this lets other cpus thru too.  Lets add a
+ * cpu id to the lock.
+ */
+#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \
+			      spinlock_cpu != smp_processor_id()){\
+				      atomic_inc(&spinlock_waiters); \
+				      while (! spin_trylock(x)) {\
+					    in_kgdb(&regs);\
+				      }\
+				      atomic_dec(&spinlock_waiters); \
+				      spinlock_count = 1; \
+				      spinlock_cpu = smp_processor_id(); \
+			  }else{  \
+				      spinlock_count++; \
+			  }
+#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x)
+#else
+unsigned kgdb_spinlock = 0;
+#define KGDB_SPIN_LOCK(x) --*x
+#define KGDB_SPIN_UNLOCK(x) ++*x
+#endif
+
+int
+hex(char ch)
+{
+	if ((ch >= 'a') && (ch <= 'f'))
+		return (ch - 'a' + 10);
+	if ((ch >= '0') && (ch <= '9'))
+		return (ch - '0');
+	if ((ch >= 'A') && (ch <= 'F'))
+		return (ch - 'A' + 10);
+	return (-1);
+}
+
+/* scan for the sequence $<data>#<checksum>	*/
+void
+getpacket(char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	char ch;
+
+	do {
+		/* wait around for the start character, ignore all other characters */
+		while ((ch = (getDebugChar() & 0x7f)) != '$') ;
+		checksum = 0;
+		xmitcsum = -1;
+
+		count = 0;
+
+		/* now, read until a # or end of buffer is found */
+		while (count < BUFMAX) {
+			ch = getDebugChar() & 0x7f;
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+		buffer[count] = 0;
+
+		if (ch == '#') {
+			xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+			xmitcsum += hex(getDebugChar() & 0x7f);
+			if ((remote_debug) && (checksum != xmitcsum)) {
+				printk
+				    ("bad checksum.	My count = 0x%x, sent=0x%x. buf=%s\n",
+				     checksum, xmitcsum, buffer);
+			}
+
+			if (checksum != xmitcsum)
+				putDebugChar('-');	/* failed checksum */
+			else {
+				putDebugChar('+');	/* successful transfer */
+				/* if a sequence char is present, reply the sequence ID */
+				if (buffer[2] == ':') {
+					putDebugChar(buffer[0]);
+					putDebugChar(buffer[1]);
+					/* remove sequence chars from buffer */
+					count = strlen(buffer);
+					for (i = 3; i <= count; i++)
+						buffer[i - 3] = buffer[i];
+				}
+			}
+		}
+	} while (checksum != xmitcsum);
+
+	if (remote_debug)
+		printk("R:%s\n", buffer);
+	flushDebugChar();
+}
+
+/* send the packet in buffer.  */
+
+void
+putpacket(char *buffer)
+{
+	unsigned char checksum;
+	int count;
+	char ch;
+
+	/*  $<packet info>#<checksum>. */
+
+	if (!kgdboe) {
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+
+			while ((ch = buffer[count])) {
+				putDebugChar(ch);
+				checksum += ch;
+				count += 1;
+			}
+
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+
+		} while ((getDebugChar() & 0x7f) != '+');
+	} else {
+		/*
+		 * For udp, we can not transfer too much bytes once.
+		 * We only transfer MAX_SEND_COUNT size bytes each time
+		 */
+
+#define MAX_SEND_COUNT 30
+
+		int send_count = 0, i = 0;
+		char send_buf[MAX_SEND_COUNT];
+
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+			send_count = 0;
+			while ((ch = buffer[count])) {
+				if (send_count >= MAX_SEND_COUNT) {
+					for(i = 0; i < MAX_SEND_COUNT; i++) {
+						putDebugChar(send_buf[i]);
+					}
+					flushDebugChar();
+					send_count = 0;
+				} else {
+					send_buf[send_count] = ch;
+					checksum += ch;
+					count ++;
+					send_count++;
+				}
+			}
+			for(i = 0; i < send_count; i++)
+				putDebugChar(send_buf[i]);
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+		} while ((getDebugChar() & 0x7f) != '+');
+	}
+}
+
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+static char lbuf[BUFMAX];
+static short error;
+
+void
+debug_error(char *format, char *parm)
+{
+	if (remote_debug)
+		printk(format, parm);
+}
+
+static void
+print_regs(struct pt_regs *regs)
+{
+	printk("RAX=%016lx RBX=%016lx RCX=%016lx\n",
+		regs->rax, regs->rbx, regs->rcx);
+	printk("RDX=%016lx RSI=%016lx RDI=%016lx\n",
+		regs->rdx, regs->rsi, regs->rdi);
+	printk("RBP=%016lx PS=%016lx PC=%016lx\n",
+		regs->rbp, regs->eflags, regs->rip);
+ 	printk("R8=%016lx R9=%016lx R10=%016lx\n",
+		regs->r8, regs->r9, regs->r10);
+	printk("R11=%016lx R12=%016lx R13=%016lx\n",
+		regs->r11, regs->r12, regs->r13);
+	printk("R14=%016lx R15=%016lx RSP=%016lx\n",
+		regs->r14, regs->r15, regs->rsp);
+}
+
+#define NEW_esp fn_call_lookaside[trap_cpu].rsp
+
+static void
+regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	gdb_regs[_RAX] =  regs->rax;
+	gdb_regs[_RBX] =  regs->rbx;
+	gdb_regs[_RCX] =  regs->rcx;
+	gdb_regs[_RDX] =  regs->rdx;
+	gdb_regs[_RSI] =  regs->rsi;
+	gdb_regs[_RDI] =  regs->rdi;
+	gdb_regs[_RBP] =  regs->rbp;
+	gdb_regs[ _PS] =  regs->eflags;
+	gdb_regs[ _PC] =  regs->rip;
+	gdb_regs[ _R8] =  regs->r8;
+	gdb_regs[ _R9] =  regs->r9;
+	gdb_regs[_R10] = regs->r10;
+	gdb_regs[_R11] = regs->r11;
+	gdb_regs[_R12] = regs->r12;
+	gdb_regs[_R13] = regs->r13;
+	gdb_regs[_R14] = regs->r14;
+	gdb_regs[_R15] = regs->r15;
+	gdb_regs[_RSP] =  regs->rsp;
+
+	/* Note, as we are a debugging the kernel, we will always
+	 * trap in kernel code, this means no priviledge change,
+	 * and so the pt_regs structure is not completely valid.  In a non
+	 * privilege change trap, only EFLAGS, CS and EIP are put on the stack,
+	 * SS and ESP are not stacked, this means that the last 2 elements of
+	 * pt_regs is not valid (they would normally refer to the user stack)
+	 * also, using regs+1 is no good because you end up will a value that is
+	 * 2 longs (8) too high.  This used to cause stepping over functions
+	 * to fail, so my fix is to use the address of regs->esp, which
+	 * should point at the end of the stack frame.	Note I have ignored
+	 * completely exceptions that cause an error code to be stacked, such
+	 * as double fault.  Stuart Hughes, Zentropix.
+	 * original code: gdb_regs[_ESP] =  (int) (regs + 1) ;
+
+	 * this is now done on entry and moved to OLD_esp (as well as NEW_esp).
+	 */
+}
+
+static void
+gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	regs->rax	=     gdb_regs[_RAX] ;
+	regs->rbx	=     gdb_regs[_RBX] ;
+	regs->rcx	=     gdb_regs[_RCX] ;
+	regs->rdx	=     gdb_regs[_RDX] ;
+	regs->rsi	=     gdb_regs[_RSI] ;
+	regs->rdi	=     gdb_regs[_RDI] ;
+	regs->rbp	=     gdb_regs[_RBP] ;
+	regs->eflags	=     gdb_regs[ _PS] ;
+	regs->rip	=     gdb_regs[ _PC] ;
+	regs->r8	=     gdb_regs[ _R8] ;
+	regs->r9	=     gdb_regs[ _R9] ;
+	regs->r10	=     gdb_regs[ _R10] ;
+	regs->r11	=     gdb_regs[ _R11] ;
+	regs->r12	=     gdb_regs[ _R12] ;
+	regs->r13	=     gdb_regs[ _R13] ;
+	regs->r14	=     gdb_regs[ _R14] ;
+	regs->r15	=     gdb_regs[ _R15] ;
+ #if 0					/* can't change these */
+	regs->rsp	=     gdb_regs[_RSP] ;
+	regs->ss	=     gdb_regs[ _SS] ;
+	regs->fs = gdb_regs[_FS];
+	regs->gs = gdb_regs[_GS];
+#endif
+}				/* gdb_regs_to_regs */
+
+extern void scheduling_functions_start_here(void);
+extern void scheduling_functions_end_here(void);
+#define first_sched	((unsigned long) scheduling_functions_start_here)
+#define last_sched	((unsigned long) scheduling_functions_end_here)
+
+int thread_list = 0;
+extern void thread_return(void);
+
+void
+get_gdb_regs(struct task_struct *p, struct pt_regs *regs, unsigned long *gdb_regs)
+{
+	unsigned long **rbp, *rsp, *rsp0, pc;
+	int count = 0;
+	IF_SMP(int i);
+	if (!p || p == current) {
+		regs_to_gdb_regs(gdb_regs, regs);
+		return;
+	}
+#ifdef CONFIG_SMP
+	for (i = 0; i < MAX_NO_CPUS; i++) {
+		if (p == kgdb_info.cpus_waiting[i].task) {
+			regs_to_gdb_regs(gdb_regs,
+					 kgdb_info.cpus_waiting[i].regs);
+			gdb_regs[_RSP] =
+			    (unsigned long)&kgdb_info.cpus_waiting[i].regs->rsp;
+
+			return;
+		}
+	}
+#endif
+	memset(gdb_regs, 0, NUMREGBYTES);
+	rsp = (unsigned long *)p->thread.rsp;
+	rbp = (unsigned long **)rsp[0];
+	rsp += 2;
+	gdb_regs[_PC] =  (unsigned long)thread_return;
+	gdb_regs[_RBP] = (unsigned long)rbp;
+	gdb_regs[_RSP] = (unsigned long)rsp;
+
+/*
+ * This code is to give a more informative notion of where a process
+ * is waiting.	It is used only when the user asks for a thread info
+ * list.  If he then switches to the thread, s/he will find the task
+ * is in schedule, but a back trace should show the same info we come
+ * up with.  This code was shamelessly purloined from process.c.  It was
+ * then enhanced to provide more registers than simply the program
+ * counter.
+ */
+
+	if (!thread_list) {
+		return;
+	}
+
+	if (p->state == TASK_RUNNING)
+		return;
+	rsp0 = (unsigned long *)p->thread.rsp0;
+	if (rsp < (unsigned long *) p->thread_info || rsp > rsp0)
+		return;
+	/* include/asm-i386/system.h:switch_to() pushes ebp last. */
+	do {
+		if (*rbp < rsp || *rbp > rsp0)
+			break;
+		rbp = (unsigned long **)*rbp;
+		rsp = (unsigned long *)rbp;
+		pc = rsp[1];
+
+		if (pc < first_sched || pc >= last_sched)
+			break;
+		gdb_regs[_PC] = (unsigned long)pc;
+		gdb_regs[_RSP] = (unsigned long)rsp;
+		gdb_regs[_RBP] = (unsigned long)rbp;
+	} while (count++ < 16);
+	return;
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf */
+/* returns nonzero if any memory access fails. */
+int mem2hex( char* mem, char* buf, int   count)
+{
+	int i;
+	unsigned char ch;
+	int ret = 0;
+
+	for (i=0;i<count;i++) {
+		ch = 0;
+		ret |= __get_user(ch, mem);
+		mem++;
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch % 16];
+	}
+	*buf = 0;
+	if (ret) {
+		Dearly_printk("mem2hex: fault at accessing %p\n", mem);
+	}
+	return(ret);
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem */
+/* return nonzero if any memory access fails. */
+int hex2mem( char* buf, char* mem, int count)
+{
+	int i;
+	unsigned char ch;
+	int ret = 0;
+
+	for (i=0;i<count;i++) {
+		ch = hex(*buf++) << 4;
+		ch = ch + hex(*buf++);
+		ret |= __put_user(ch, mem);
+		mem++;
+	}
+	if (ret) {
+		Dearly_printk("hex2mem: fault at %p\n", mem);
+	}
+	return(ret);
+}
+
+#if 0
+/* Indicate to caller of mem2hex or hex2mem that there has been an
+   error.  */
+static volatile int mem_err = 0;
+static volatile int mem_err_expected = 0;
+static volatile int mem_err_cnt = 0;
+static int garbage_loc = -1;
+
+int
+get_char(char *addr)
+{
+	return *addr;
+}
+
+void
+set_char(char *addr, int val, int may_fault)
+{
+	/*
+	 * This code traps references to the area mapped to the kernel
+	 * stack as given by the regs and, instead, stores to the
+	 * fn_call_lookaside[cpu].array
+	 */
+	if (may_fault &&
+	    (unsigned int) addr < OLD_esp &&
+	    ((unsigned int) addr > (OLD_esp - (unsigned int) LOOKASIDE_SIZE))) {
+		addr = (char *) END_OF_LOOKASIDE - ((char *) OLD_esp - addr);
+	}
+	*addr = val;
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf */
+/* return a pointer to the last char put in buf (null) */
+/* If MAY_FAULT is non-zero, then we should set mem_err in response to
+   a fault; if zero treat a fault like any other fault in the stub.  */
+char *
+mem2hex(char *mem, char *buf, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+	for (i = 0; i < count; i++) {
+		/* printk("%lx = ", mem) ; */
+
+		ch = get_char(mem++);
+
+		/* printk("%02x\n", ch & 0xFF) ; */
+		if (may_fault && mem_err) {
+			if (remote_debug)
+				printk("Mem fault fetching from addr %lx\n",
+				       (long) (mem - 1));
+			*buf = 0;	/* truncate buffer */
+			return (buf);
+		}
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch % 16];
+	}
+	*buf = 0;
+	if (may_fault)
+		mem_err_expected = 0;
+	return (buf);
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem */
+/* return a pointer to the character AFTER the last byte written */
+/* NOTE: We use the may fault flag to also indicate if the write is to
+ * the registers (0) or "other" memory (!=0)
+ */
+char *
+hex2mem(char *buf, char *mem, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+	for (i = 0; i < count; i++) {
+		ch = hex(*buf++) << 4;
+		ch = ch + hex(*buf++);
+		set_char(mem++, ch, may_fault);
+
+		if (may_fault && mem_err) {
+			if (remote_debug)
+				printk("Mem fault storing to addr %lx\n",
+				       (long) (mem - 1));
+			return (mem);
+		}
+	}
+	if (may_fault)
+		mem_err_expected = 0;
+	return (mem);
+}
+#endif
+
+/**********************************************/
+/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
+/* RETURN NUMBER OF CHARS PROCESSED	      */
+/**********************************************/
+int
+hexToLong(char **ptr, unsigned long *value)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*value = 0;
+
+	while (**ptr) {
+		hexValue = hex(**ptr);
+		if (hexValue >= 0) {
+			*value = (*value << 4) | hexValue;
+			numChars++;
+		} else
+			break;
+
+		(*ptr)++;
+	}
+
+	return (numChars);
+}
+
+#define stubhex(h) hex(h)
+#ifdef old_thread_list
+
+static int
+stub_unpack_int(char *buff, int fieldlength)
+{
+	int nibble;
+	int retval = 0;
+
+	while (fieldlength) {
+		nibble = stubhex(*buff++);
+		retval |= nibble;
+		fieldlength--;
+		if (fieldlength)
+			retval = retval << 4;
+	}
+	return retval;
+}
+#endif
+static char *
+pack_hex_byte(char *pkt, int byte)
+{
+	*pkt++ = hexchars[(byte >> 4) & 0xf];
+	*pkt++ = hexchars[(byte & 0xf)];
+	return pkt;
+}
+
+#define BUF_THREAD_ID_SIZE 16
+
+static char *
+pack_threadid(char *pkt, threadref * id)
+{
+	char *limit;
+	unsigned char *altid;
+
+	altid = (unsigned char *) id;
+	limit = pkt + BUF_THREAD_ID_SIZE;
+	while (pkt < limit)
+		pkt = pack_hex_byte(pkt, *altid++);
+	return pkt;
+}
+
+#ifdef old_thread_list
+static char *
+unpack_byte(char *buf, int *value)
+{
+	*value = stub_unpack_int(buf, 2);
+	return buf + 2;
+}
+
+static char *
+unpack_threadid(char *inbuf, threadref * id)
+{
+	char *altref;
+	char *limit = inbuf + BUF_THREAD_ID_SIZE;
+	int x, y;
+
+	altref = (char *) id;
+
+	while (inbuf < limit) {
+		x = stubhex(*inbuf++);
+		y = stubhex(*inbuf++);
+		*altref++ = (x << 4) | y;
+	}
+	return inbuf;
+}
+#endif
+void
+int_to_threadref(threadref * id, int value)
+{
+	unsigned char *scan;
+
+	scan = (unsigned char *) id;
+	{
+		int i = 4;
+		while (i--)
+			*scan++ = 0;
+	}
+	*scan++ = (value >> 24) & 0xff;
+	*scan++ = (value >> 16) & 0xff;
+	*scan++ = (value >> 8) & 0xff;
+	*scan++ = (value & 0xff);
+}
+int
+int_to_hex_v(unsigned char * id, int value)
+{
+	unsigned char *start = id;
+	int shift;
+	int ch;
+
+	for (shift = 28; shift >= 0; shift -= 4) {
+		if ((ch = (value >> shift) & 0xf) || (id != start)) {
+			*id = hexchars[ch];
+			id++;
+		}
+	}
+	if (id == start)
+		*id++ = '0';
+	return id - start;
+}
+#ifdef old_thread_list
+
+static int
+threadref_to_int(threadref * ref)
+{
+	int i, value = 0;
+	unsigned char *scan;
+
+	scan = (char *) ref;
+	scan += 4;
+	i = 4;
+	while (i-- > 0)
+		value = (value << 8) | ((*scan++) & 0xff);
+	return value;
+}
+#endif
+static int
+cmp_str(char *s1, char *s2, int count)
+{
+	while (count--) {
+		if (*s1++ != *s2++)
+			return 0;
+	}
+	return 1;
+}
+
+#if 1				/* this is a hold over from 2.4 where O(1) was "sometimes" */
+extern struct task_struct *kgdb_get_idle(int cpu);
+#define idle_task(cpu) kgdb_get_idle(cpu)
+#else
+#define idle_task(cpu) init_tasks[cpu]
+#endif
+
+extern int kgdb_pid_init_done;
+
+struct task_struct *
+getthread(int pid)
+{
+	struct task_struct *thread;
+	if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) {
+		if (!cpu_online(pid - PID_MAX))
+			return NULL;
+
+		return idle_task(pid - PID_MAX);
+	} else {
+		/*
+		 * find_task_by_pid is relatively safe all the time
+		 * Other pid functions require lock downs which imply
+		 * that we may be interrupting them (as we get here
+		 * in the middle of most any lock down).
+		 * Still we don't want to call until the table exists!
+		 */
+		if (kgdb_pid_init_done){
+			thread = find_task_by_pid(pid);
+			if (thread) {
+				return thread;
+			}
+		}
+	}
+	return NULL;
+}
+/* *INDENT-OFF*	 */
+struct hw_breakpoint {
+	unsigned enabled;
+	unsigned type;
+	unsigned len;
+	unsigned long addr;
+} breakinfo[4] = { {enabled:0},
+		   {enabled:0},
+		   {enabled:0},
+		   {enabled:0}};
+/* *INDENT-ON*	*/
+unsigned long hw_breakpoint_status;
+void
+correct_hw_break(void)
+{
+	int breakno;
+	int correctit;
+	int breakbit;
+	unsigned long dr7;
+
+	asm volatile ("movq %%db7, %0\n":"=r" (dr7)
+		      :);
+	/* *INDENT-OFF*	 */
+	do {
+		unsigned long addr0, addr1, addr2, addr3;
+		asm volatile ("movq %%db0, %0\n"
+			      "movq %%db1, %1\n"
+			      "movq %%db2, %2\n"
+			      "movq %%db3, %3\n"
+			      :"=r" (addr0), "=r"(addr1),
+			      "=r"(addr2), "=r"(addr3)
+			      :);
+	} while (0);
+	/* *INDENT-ON*	*/
+	correctit = 0;
+	for (breakno = 0; breakno < 3; breakno++) {
+		breakbit = 2 << (breakno << 1);
+		if (!(dr7 & breakbit) && breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 |= breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+			dr7 |= (((breakinfo[breakno].len << 2) |
+				 breakinfo[breakno].type) << 16) <<
+			    (breakno << 2);
+			switch (breakno) {
+			case 0:
+				asm volatile ("movq %0, %%dr0\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 1:
+				asm volatile ("movq %0, %%dr1\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 2:
+				asm volatile ("movq %0, %%dr2\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 3:
+				asm volatile ("movq %0, %%dr3\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+			}
+		} else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 &= ~breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+		}
+	}
+	if (correctit) {
+		asm volatile ("movq %0, %%db7\n"::"r" (dr7));
+	}
+}
+
+int
+remove_hw_break(unsigned breakno)
+{
+	if (!breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 0;
+	return 0;
+}
+
+int
+set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr)
+{
+	if (breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 1;
+	breakinfo[breakno].type = type;
+	breakinfo[breakno].len = len;
+	breakinfo[breakno].addr = addr;
+	return 0;
+}
+
+#ifdef CONFIG_SMP
+static int in_kgdb_console = 0;
+
+int
+in_kgdb(struct pt_regs *regs)
+{
+	unsigned long flags;
+	int cpu;
+	if (!kgdb_enabled)
+		return 0;
+	cpu = smp_processor_id();
+	in_kgdb_called = 1;
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		if (in_kgdb_here_log[cpu] ||	/* we are holding this cpu */
+		    in_kgdb_console) {	/* or we are doing slow i/o */
+			return 1;
+		}
+		return 0;
+	}
+
+	/* As I see it the only reason not to let all cpus spin on
+	 * the same spin_lock is to allow selected ones to proceed.
+	 * This would be a good thing, so we leave it this way.
+	 * Maybe someday....  Done !
+
+	 * in_kgdb() is called from an NMI so we don't pretend
+	 * to have any resources, like printk() for example.
+	 */
+
+	local_irq_save(flags);	/* only local here, to avoid hanging */
+	/*
+	 * log arival of this cpu
+	 * The NMI keeps on ticking.  Protect against recurring more
+	 * than once, and ignor the cpu that has the kgdb lock
+	 */
+	in_kgdb_entry_log[cpu]++;
+	in_kgdb_here_log[cpu] = regs;
+	if (cpu == spinlock_cpu || waiting_cpus[cpu].task)
+		goto exit_in_kgdb;
+
+	/*
+	 * For protection of the initilization of the spin locks by kgdb
+	 * it locks the kgdb spinlock before it gets the wait locks set
+	 * up.	We wait here for the wait lock to be taken.  If the
+	 * kgdb lock goes away first??	Well, it could be a slow exit
+	 * sequence where the wait lock is removed prior to the kgdb lock
+	 * so if kgdb gets unlocked, we just exit.
+	 */
+
+	while (spin_is_locked(&kgdb_spinlock) &&
+	       !spin_is_locked(waitlocks + cpu)) ;
+	if (!spin_is_locked(&kgdb_spinlock))
+		goto exit_in_kgdb;
+
+	waiting_cpus[cpu].task = current;
+	waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu);
+	waiting_cpus[cpu].regs = regs;
+
+	spin_unlock_wait(waitlocks + cpu);
+
+	/*
+	 * log departure of this cpu
+	 */
+	waiting_cpus[cpu].task = 0;
+	waiting_cpus[cpu].pid = 0;
+	waiting_cpus[cpu].regs = 0;
+	correct_hw_break();
+      exit_in_kgdb:
+	in_kgdb_here_log[cpu] = 0;
+	local_irq_restore(flags);
+	return 1;
+	/*
+	   spin_unlock(continuelocks + smp_processor_id());
+	 */
+}
+
+void
+smp__in_kgdb(struct pt_regs regs)
+{
+	ack_APIC_irq();
+	in_kgdb(&regs);
+}
+#else
+int
+in_kgdb(struct pt_regs *regs)
+{
+	return (kgdb_spinlock);
+}
+#endif
+
+void
+printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
+{
+	unsigned long dr6;
+	int i;
+	switch (exceptionNo) {
+	case 1:		/* debug exception */
+		break;
+	case 3:		/* breakpoint */
+		sprintf(buffer, "Software breakpoint");
+		return;
+	default:
+		sprintf(buffer, "Details not available");
+		return;
+	}
+	asm volatile ("movq %%db6, %0\n":"=r" (dr6)
+		      :);
+	if (dr6 & 0x4000) {
+		sprintf(buffer, "Single step");
+		return;
+	}
+	for (i = 0; i < 4; ++i) {
+		if (dr6 & (1 << i)) {
+			sprintf(buffer, "Hardware breakpoint %d", i);
+			return;
+		}
+	}
+	sprintf(buffer, "Unknown trap");
+	return;
+}
+
+/*
+ * The ThreadExtraInfo query allows us to pass an arbitrary string
+ * for display with the "info threads" command.
+ */
+
+void
+print_extra_info(task_t *p, char *buf)
+{
+	if (!p) {
+		sprintf(buf, "Invalid thread");
+		return;
+	}
+	sprintf(buf, "0x%p %8d %4d  %c  %s",
+		   (void *)p,  p->parent->pid,
+		   task_cpu(p),
+		   (p->state == 0) ? (task_curr(p)?'R':'r') :
+		     (p->state < 0) ? 'U' :
+		     (p->state & TASK_UNINTERRUPTIBLE) ? 'D' :
+		     (p->state & TASK_STOPPED || p->ptrace & PT_PTRACED) ? 'T' :
+		     (p->state & (TASK_ZOMBIE | TASK_DEAD)) ? 'Z' :
+		     (p->state & TASK_INTERRUPTIBLE) ? 'S' : '?',
+		   p->comm);
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ *
+ * NOTE:  The INT nn instruction leaves the state of the interrupt
+ *	  enable flag UNCHANGED.  That means that when this routine
+ *	  is entered via a breakpoint (INT 3) instruction from code
+ *	  that has interrupts enabled, then interrupts will STILL BE
+ *	  enabled when this routine is entered.	 The first thing that
+ *	  we do here is disable interrupts so as to prevent recursive
+ *	  entries and bothersome serial interrupts while we are
+ *	  trying to run the serial port in polled mode.
+ *
+ * For kernel version 2.1.xx the kgdb_cli() actually gets a spin lock so
+ * it is always necessary to do a restore_flags before returning
+ * so as to let go of that lock.
+ */
+int
+kgdb_handle_exception(int exceptionVector,
+		      int signo, int err_code, struct pt_regs *linux_regs)
+{
+	struct task_struct *usethread = NULL;
+	struct task_struct *thread_list_start = 0, *thread = NULL;
+	struct task_struct *p;
+	unsigned long addr, length;
+	unsigned long breakno, breaktype;
+	char *ptr;
+	unsigned long newPC;
+	threadref thref;
+	unsigned long threadid, tmpid;
+	int thread_min = PID_MAX + MAX_NO_CPUS;
+#ifdef old_thread_list
+	int maxthreads;
+#endif
+	int nothreads;
+	unsigned long flags;
+	unsigned long gdb_regs[NUMREGS];
+	unsigned long dr6;
+	IF_SMP(int entry_state = 0);	/* 0, ok, 1, no nmi, 2 sync failed */
+#define NO_NMI 1
+#define NO_SYNC 2
+#define	regs	(*linux_regs)
+	/*
+	 * If the entry is not from the kernel then return to the Linux
+	 * trap handler and let it process the interrupt normally.
+	 */
+	if ((linux_regs->eflags & VM_MASK) || (3 & linux_regs->cs)) {
+		printk("ignoring non-kernel exception\n");
+		print_regs(&regs);
+		return (0);
+	}
+	/*
+	 * If we're using eth mode, set the 'mode' in the netdevice.
+	 */
+
+	if (kgdboe)
+		netpoll_set_trap(1);
+
+	local_irq_save(flags);
+
+	/* Get kgdb spinlock */
+
+	KGDB_SPIN_LOCK(&kgdb_spinlock);
+	rdtscll(kgdb_info.entry_tsc);
+	/*
+	 * We depend on this spinlock and the NMI watch dog to control the
+	 * other cpus.	They will arrive at "in_kgdb()" as a result of the
+	 * NMI and will wait there for the following spin locks to be
+	 * released.
+	 */
+#ifdef CONFIG_SMP
+
+#if 0
+	if (cpu_callout_map & ~MAX_CPU_MASK) {
+		printk("kgdb : too many cpus, possibly not mapped"
+		       " in contiguous space, change MAX_NO_CPUS"
+		       " in kgdb_stub and make new kernel.\n"
+		       " cpu_callout_map is %lx\n", cpu_callout_map);
+		goto exit_just_unlock;
+	}
+#endif
+	if (spinlock_count == 1) {
+		int time, end_time, dum;
+		int i;
+		int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0)
+		};
+		if (remote_debug) {
+			printk("kgdb : cpu %d entry, syncing others\n",
+			       smp_processor_id());
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			/*
+			 * Use trylock as we may already hold the lock if
+			 * we are holding the cpu.  Net result is all
+			 * locked.
+			 */
+			spin_trylock(&waitlocks[i]);
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++)
+			cpu_logged_in[i] = 0;
+		/*
+		 * Wait for their arrival.  We know the watch dog is active if
+		 * in_kgdb() has ever been called, as it is always called on a
+		 * watchdog tick.
+		 */
+		rdtsc(dum, time);
+		end_time = time + 2;	/* Note: we use the High order bits! */
+		i = 1;
+		if (num_online_cpus() > 1) {
+			int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()];
+			smp_send_nmi_allbutself();
+
+			while (i < num_online_cpus() && time != end_time) {
+				int j;
+				for (j = 0; j < MAX_NO_CPUS; j++) {
+					if (waiting_cpus[j].task &&
+					    waiting_cpus[j].task != NOCPU &&
+					    !cpu_logged_in[j]) {
+						i++;
+						cpu_logged_in[j] = 1;
+						if (remote_debug) {
+							printk
+							    ("kgdb : cpu %d arrived at kgdb\n",
+							     j);
+						}
+						break;
+					} else if (!waiting_cpus[j].task &&
+						   !cpu_online(j)) {
+						waiting_cpus[j].task = NOCPU;
+						cpu_logged_in[j] = 1;
+						waiting_cpus[j].hold = 1;
+						break;
+					}
+					if (!waiting_cpus[j].task &&
+					    in_kgdb_here_log[j]) {
+
+						int wait = 100000;
+						while (wait--) ;
+						if (!waiting_cpus[j].task &&
+						    in_kgdb_here_log[j]) {
+							printk
+							    ("kgdb : cpu %d stall"
+							     " in in_kgdb\n",
+							     j);
+							i++;
+							cpu_logged_in[j] = 1;
+							waiting_cpus[j].task =
+							    (struct task_struct
+							     *) 1;
+						}
+					}
+				}
+
+				if (in_kgdb_entry_log[smp_processor_id()] >
+				    (me_in_kgdb + 10)) {
+					break;
+				}
+
+				rdtsc(dum, time);
+			}
+			if (i < num_online_cpus()) {
+				printk
+				    ("kgdb : time out, proceeding without sync\n");
+#if 0
+				printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n",
+				       waiting_cpus[0].task != 0,
+				       waiting_cpus[1].task != 0);
+				printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n",
+				       cpu_logged_in[0], cpu_logged_in[1]);
+				printk
+				    ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n",
+				     in_kgdb_here_log[0] != 0,
+				     in_kgdb_here_log[1] != 0);
+#endif
+				entry_state = NO_SYNC;
+			} else {
+#if 0
+				int ent =
+				    in_kgdb_entry_log[smp_processor_id()] -
+				    me_in_kgdb;
+				printk("kgdb : sync after %d entries\n", ent);
+#endif
+			}
+		} else {
+			if (remote_debug) {
+				printk
+				    ("kgdb : %d cpus, but watchdog not active\n"
+				     "proceeding without locking down other cpus\n",
+				     num_online_cpus());
+				entry_state = NO_NMI;
+			}
+		}
+	}
+#endif
+
+	if (remote_debug) {
+		unsigned long *lp = (unsigned long *) &linux_regs;
+
+		printk("handle_exception(exceptionVector=%d, "
+		       "signo=%d, err_code=%d, linux_regs=%p)\n",
+		       exceptionVector, signo, err_code, linux_regs);
+		if (debug_regs) {
+			print_regs(&regs);
+			printk("Stk: %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[0], lp[1], lp[2], lp[3],
+			       lp[4], lp[5], lp[6], lp[7]);
+			printk("     %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[8], lp[9], lp[10], lp[11],
+			       lp[12], lp[13], lp[14], lp[15]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[16], lp[17], lp[18], lp[19],
+			       lp[20], lp[21], lp[22], lp[23]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[24], lp[25], lp[26], lp[27],
+			       lp[28], lp[29], lp[30], lp[31]);
+		}
+	}
+
+	/* Disable hardware debugging while we are in kgdb */
+	/* Get the debug register status register */
+/*				       *INDENT-OFF*  */
+      __asm__("movq %0,%%db7"
+	      :	/* no output */
+	      :"r"(0UL));
+
+	asm volatile ("movq %%db6, %0\n"
+		      :"=r" (hw_breakpoint_status)
+		      :);
+
+#if 0
+/*				       *INDENT-ON*  */
+	switch (exceptionVector) {
+	case 0:		/* divide error */
+	case 1:		/* debug exception */
+	case 2:		/* NMI */
+	case 3:		/* breakpoint */
+	case 4:		/* overflow */
+	case 5:		/* bounds check */
+	case 6:		/* invalid opcode */
+	case 7:		/* device not available */
+	case 8:		/* double fault (errcode) */
+	case 10:		/* invalid TSS (errcode) */
+	case 12:		/* stack fault (errcode) */
+	case 16:		/* floating point error */
+	case 17:		/* alignment check (errcode) */
+	default:		/* any undocumented */
+		break;
+	case 11:		/* segment not present (errcode) */
+	case 13:		/* general protection (errcode) */
+	case 14:		/* page fault (special errcode) */
+	case 19:		/* cache flush denied */
+		if (mem_err_expected) {
+			/*
+			 * This fault occured because of the
+			 * get_char or set_char routines.  These
+			 * two routines use either eax of edx to
+			 * indirectly reference the location in
+			 * memory that they are working with.
+			 * For a page fault, when we return the
+			 * instruction will be retried, so we
+			 * have to make sure that these
+			 * registers point to valid memory.
+			 */
+			mem_err = 1;	/* set mem error flag */
+			mem_err_expected = 0;
+			mem_err_cnt++;	/* helps in debugging */
+			/* make valid address */
+			regs.eax = (long) &garbage_loc;
+			/* make valid address */
+			regs.edx = (long) &garbage_loc;
+			if (remote_debug)
+				printk("Return after memory error: "
+				       "mem_err_cnt=%d\n", mem_err_cnt);
+			if (debug_regs)
+				print_regs(&regs);
+			goto exit_kgdb;
+		}
+		break;
+	}
+#endif
+	if (remote_debug)
+		printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id());
+
+	gdb_i386vector = exceptionVector;
+	gdb_i386errcode = err_code;
+	kgdb_info.called_from = __builtin_return_address(0);
+#ifdef CONFIG_SMP
+	/*
+	 * OK, we can now communicate, lets tell gdb about the sync.
+	 * but only if we had a problem.
+	 */
+	switch (entry_state) {
+	case NO_NMI:
+		to_gdb("NMI not active, other cpus not stopped\n");
+		break;
+	case NO_SYNC:
+		to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n");
+	default:;
+	}
+
+#endif
+/*
+ * Set up the gdb function call area.
+ */
+	trap_cpu = smp_processor_id();
+	OLD_esp = NEW_esp = (unsigned long) (&linux_regs->rsp);
+
+      IF_SMP(once_again:)
+	    /* reply to host that an exception has occurred */
+	    remcomOutBuffer[0] = 'S';
+	remcomOutBuffer[1] = hexchars[signo >> 4];
+	remcomOutBuffer[2] = hexchars[signo % 16];
+	remcomOutBuffer[3] = 0;
+
+	putpacket(remcomOutBuffer);
+
+	while (1 == 1) {
+		error = 0;
+		remcomOutBuffer[0] = 0;
+		getpacket(remcomInBuffer);
+		switch (remcomInBuffer[0]) {
+		case '?':
+			remcomOutBuffer[0] = 'S';
+			remcomOutBuffer[1] = hexchars[signo >> 4];
+			remcomOutBuffer[2] = hexchars[signo % 16];
+			remcomOutBuffer[3] = 0;
+			break;
+		case 'd':
+			remote_debug = !(remote_debug);	/* toggle debug flag */
+			printk("Remote debug %s\n",
+			       remote_debug ? "on" : "off");
+			break;
+		case 'g':	/* return the value of the CPU registers */
+			get_gdb_regs(usethread, &regs, gdb_regs);
+			mem2hex((char *) gdb_regs,
+				remcomOutBuffer, NUMREGBYTES);
+			break;
+		case 'G':	/* set the value of the CPU registers - return OK */
+			hex2mem(&remcomInBuffer[1],
+				(char *) gdb_regs, NUMREGBYTES);
+			if (!usethread || usethread == current) {
+				gdb_regs_to_regs(gdb_regs, &regs);
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "E00");
+			}
+			break;
+
+		case 'P':{	/* set the value of a single CPU register -
+				   return OK */
+				/*
+				 * For some reason, gdb wants to talk about psudo
+				 * registers (greater than 15).
+				 */
+				unsigned long regno;
+
+				ptr = &remcomInBuffer[1];
+				regs_to_gdb_regs(gdb_regs, &regs);
+				if ((!usethread || usethread == current) &&
+				    hexToLong(&ptr, &regno) &&
+				    *ptr++ == '=' && (regno >= 0)) {
+					if (regno >= NUMREGS)
+						break;
+					hex2mem(ptr, (char *) &gdb_regs[regno],
+						8);
+					gdb_regs_to_regs(gdb_regs, &regs);
+					strcpy(remcomOutBuffer, "OK");
+					break;
+				}
+				strcpy(remcomOutBuffer, "E01");
+				break;
+			}
+
+			/* mAA..AA,LLLL	 Read LLLL bytes at address AA..AA */
+		case 'm':
+			/* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToLong(&ptr, &addr) &&
+			    (*(ptr++) == ',') && (hexToLong(&ptr, &length))) {
+				ptr = 0;
+				/*
+				 * hex doubles the byte count
+				 */
+				if (length > (BUFMAX / 2))
+					length = BUFMAX / 2;
+				if (mem2hex((char *) addr,
+					remcomOutBuffer, length)) {
+					strcpy(remcomOutBuffer, "E03");
+					debug_error("memory fault\n", NULL);
+				}
+			}
+
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E01");
+				debug_error
+				    ("malformed read memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+
+			/* MAA..AA,LLLL:
+			   Write LLLL bytes at address AA.AA return OK */
+		case 'M':
+			/* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToLong(&ptr, &addr) &&
+			    (*(ptr++) == ',') &&
+			    (hexToLong(&ptr, &length)) && (*(ptr++) == ':')) {
+				if (hex2mem(ptr, (char *) addr, length)) {
+					strcpy(remcomOutBuffer, "E03");
+					debug_error("memory fault\n", NULL);
+				} else {
+					strcpy(remcomOutBuffer, "OK");
+				}
+
+				ptr = 0;
+			}
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E02");
+				debug_error
+				    ("malformed write memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+		case 'S':
+			remcomInBuffer[0] = 's';
+		case 'C':
+			/* Csig;AA..AA where ;AA..AA is optional
+			 * continue with signal
+			 * Since signals are meaning less to us, delete that
+			 * part and then fall into the 'c' code.
+			 */
+			ptr = &remcomInBuffer[1];
+			length = 2;
+			while (*ptr && *ptr != ';') {
+				length++;
+				ptr++;
+			}
+			if (*ptr) {
+				do {
+					ptr++;
+					*(ptr - length++) = *ptr;
+				} while (*ptr);
+			} else {
+				remcomInBuffer[1] = 0;
+			}
+
+			/* cAA..AA  Continue at address AA..AA(optional) */
+			/* sAA..AA  Step one instruction from AA..AA(optional) */
+			/* D	    detach, reply OK and then continue */
+		case 'c':
+		case 's':
+		case 'D':
+
+			/* try to read optional parameter,
+			   pc unchanged if no parm */
+			ptr = &remcomInBuffer[1];
+			if (hexToLong(&ptr, &addr)) {
+				if (remote_debug)
+					printk("Changing EIP to 0x%lx\n", addr);
+
+				regs.rip = addr;
+			}
+
+			newPC = regs.rip;
+
+			/* clear the trace bit */
+			regs.eflags &= 0xfffffeff;
+
+			/* set the trace bit if we're stepping */
+			if (remcomInBuffer[0] == 's')
+				regs.eflags |= 0x100;
+
+			/* detach is a friendly version of continue. Note that
+			   debugging is still enabled (e.g hit control C)
+			 */
+			if (remcomInBuffer[0] == 'D') {
+				strcpy(remcomOutBuffer, "OK");
+				putpacket(remcomOutBuffer);
+			}
+
+			if (remote_debug) {
+				printk("Resuming execution\n");
+				print_regs(&regs);
+			}
+			asm volatile ("movq %%db6, %0\n":"=r" (dr6)
+				      :);
+			if (!(dr6 & 0x4000)) {
+				for (breakno = 0; breakno < 4; ++breakno) {
+					if (dr6 & (1 << breakno) &&
+					    (breakinfo[breakno].type == 0)) {
+						/* Set restore flag */
+						regs.eflags |= 0x10000;
+						break;
+					}
+				}
+			}
+
+			if (kgdboe)
+				netpoll_set_trap(0);
+
+			correct_hw_break();
+			asm volatile ("movq %0, %%db6\n"::"r" (0UL));
+			goto exit_kgdb;
+
+			/* kill the program */
+		case 'k':	/* do nothing */
+			break;
+
+			/* query */
+		case 'q':
+			nothreads = 0;
+			switch (remcomInBuffer[1]) {
+			case 'f':
+				threadid = 1;
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+			case 's':
+				if (!cmp_str(&remcomInBuffer[2],
+					     "ThreadInfo", 10))
+					break;
+
+				remcomOutBuffer[nothreads++] = 'm';
+				for (; threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						nothreads += int_to_hex_v(
+							&remcomOutBuffer[
+								nothreads],
+							threadid);
+						if (thread_min > threadid)
+							thread_min = threadid;
+						remcomOutBuffer[
+							nothreads] = ',';
+						nothreads++;
+						if (nothreads > BUFMAX - 10)
+							break;
+					}
+				}
+				if (remcomOutBuffer[nothreads - 1] == 'm') {
+					remcomOutBuffer[nothreads - 1] = 'l';
+				} else {
+					nothreads--;
+				}
+				remcomOutBuffer[nothreads] = 0;
+				break;
+
+#ifdef old_thread_list /* Old thread info request */
+			case 'L':
+				/* List threads */
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+				unpack_byte(remcomInBuffer + 3, &maxthreads);
+				unpack_threadid(remcomInBuffer + 5, &thref);
+				do {
+					int buf_thread_limit =
+					    (BUFMAX - 22) / BUF_THREAD_ID_SIZE;
+					if (maxthreads > buf_thread_limit) {
+						maxthreads = buf_thread_limit;
+					}
+				} while (0);
+				remcomOutBuffer[0] = 'q';
+				remcomOutBuffer[1] = 'M';
+				remcomOutBuffer[4] = '0';
+				pack_threadid(remcomOutBuffer + 5, &thref);
+
+				/* If start flag set start at 0. */
+				if (remcomInBuffer[2] == '1')
+					threadid = 0;
+				else
+					threadid = threadref_to_int(&thref);
+				for (nothreads = 0;
+				     nothreads < maxthreads &&
+				     threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						int_to_threadref(&thref,
+								 threadid);
+						pack_threadid(remcomOutBuffer +
+							      21 +
+							      nothreads * 16,
+							      &thref);
+						nothreads++;
+						if (thread_min > threadid)
+							thread_min = threadid;
+					}
+				}
+
+				if (threadid == PID_MAX + MAX_NO_CPUS) {
+					remcomOutBuffer[4] = '1';
+				}
+				pack_hex_byte(remcomOutBuffer + 2, nothreads);
+				remcomOutBuffer[21 + nothreads * 16] = '\0';
+				break;
+#endif
+			case 'C':
+				/* Current thread id */
+				remcomOutBuffer[0] = 'Q';
+				remcomOutBuffer[1] = 'C';
+				threadid = current->pid;
+				if (!threadid) {
+					/*
+					 * idle thread
+					 */
+					for (threadid = PID_MAX;
+					     threadid < PID_MAX + MAX_NO_CPUS;
+					     threadid++) {
+						if (current ==
+						    idle_task(threadid -
+							      PID_MAX))
+							break;
+					}
+				}
+				int_to_threadref(&thref, threadid);
+				pack_threadid(remcomOutBuffer + 2, &thref);
+				remcomOutBuffer[18] = '\0';
+				break;
+
+			case 'E':
+				/* Print exception info */
+				printexceptioninfo(exceptionVector,
+						   err_code, remcomOutBuffer);
+				break;
+			case 'T':
+				ptr = &remcomInBuffer[0];
+				if (strncmp(ptr, "qThreadExtraInfo,",
+					strlen("qThreadExtraInfo,")) == 0) {
+					ptr += strlen("qThreadExtraInfo,");
+					hexToLong(&ptr, &tmpid);
+					p = getthread(tmpid);
+					print_extra_info(p, lbuf);
+					mem2hex(lbuf, remcomOutBuffer,
+						strlen(lbuf));
+				}
+				break;
+#if 0
+			case 'T':{
+				char * nptr;
+				/* Thread extra info */
+				if (!cmp_str(&remcomInBuffer[2],
+					    "hreadExtraInfo,", 15)) {
+					break;
+				}
+				ptr = &remcomInBuffer[17];
+				hexToLong(&ptr, &threadid);
+				thread = getthread(threadid);
+				nptr = &thread->comm[0];
+				length = 0;
+				ptr = &remcomOutBuffer[0];
+				do {
+					length++;
+					ptr = pack_hex_byte(ptr, *nptr++);
+				 } while (*nptr && length < 16);
+				/*
+				 * would like that 16 to be the size of
+				 * task_struct.comm but don't know the
+				 * syntax..
+				 */
+				*ptr = 0;
+			}
+#endif
+			}
+			break;
+
+			/* task related */
+		case 'H':
+			switch (remcomInBuffer[1]) {
+			case 'g':
+				ptr = &remcomInBuffer[2];
+				hexToLong(&ptr, &threadid);
+				thread = getthread(threadid);
+				if (!thread) {
+					remcomOutBuffer[0] = 'E';
+					remcomOutBuffer[1] = '\0';
+					break;
+				}
+				/*
+				 * Just in case I forget what this is all about,
+				 * the "thread info" command to gdb causes it
+				 * to ask for a thread list.  It then switches
+				 * to each thread and asks for the registers.
+				 * For this (and only this) usage, we want to
+				 * fudge the registers of tasks not on the run
+				 * list (i.e. waiting) to show the routine that
+				 * called schedule. Also, gdb, is a minimalist
+				 * in that if the current thread is the last
+				 * it will not re-read the info when done.
+				 * This means that in this case we must show
+				 * the real registers. So here is how we do it:
+				 * Each entry we keep track of the min
+				 * thread in the list (the last that gdb will)
+				 * get info for.  We also keep track of the
+				 * starting thread.
+				 * "thread_list" is cleared when switching back
+				 * to the min thread if it is was current, or
+				 * if it was not current, thread_list is set
+				 * to 1.  When the switch to current comes,
+				 * if thread_list is 1, clear it, else do
+				 * nothing.
+				 */
+				usethread = thread;
+				if ((thread_list == 1) &&
+				    (thread == thread_list_start)) {
+					thread_list = 0;
+				}
+				if (thread_list && (threadid == thread_min)) {
+					if (thread == thread_list_start) {
+						thread_list = 0;
+					} else {
+						thread_list = 1;
+					}
+				}
+				/* follow through */
+			case 'c':
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				break;
+			}
+			break;
+
+			/* Query thread status */
+		case 'T':
+			ptr = &remcomInBuffer[1];
+			hexToLong(&ptr, &threadid);
+			thread = getthread(threadid);
+			if (thread) {
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				if (thread_min > threadid)
+					thread_min = threadid;
+			} else {
+				remcomOutBuffer[0] = 'E';
+				remcomOutBuffer[1] = '\0';
+			}
+			break;
+
+		case 'Y': /* set up a hardware breakpoint */
+			ptr = &remcomInBuffer[1];
+			hexToLong(&ptr, &breakno);
+			ptr++;
+			hexToLong(&ptr, &breaktype);
+			ptr++;
+			hexToLong(&ptr, &length);
+			ptr++;
+			hexToLong(&ptr, &addr);
+			if (set_hw_break(breakno & 0x3,
+					 breaktype & 0x3,
+					 length & 0x3, addr) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+			/* Remove hardware breakpoint */
+		case 'y':
+			ptr = &remcomInBuffer[1];
+			hexToLong(&ptr, &breakno);
+			if (remove_hw_break(breakno & 0x3) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+		case 'r':	/* reboot */
+			strcpy(remcomOutBuffer, "OK");
+			putpacket(remcomOutBuffer);
+			/*to_gdb("Rebooting\n"); */
+			/* triplefault	 no return from here */
+			{
+				static long no_idt[2];
+				__asm__ __volatile__("lidt %0"::"m"(no_idt[0]));
+				BREAKPOINT;
+			}
+
+		}		/* switch */
+
+		/* reply to the request */
+		putpacket(remcomOutBuffer);
+	}			/* while(1==1) */
+	/*
+	 *  reached by goto only.
+	 */
+      exit_kgdb:
+	/*
+	 * Here is where we set up to trap a gdb function call.	 NEW_esp
+	 * will be changed if we are trying to do this.	 We handle both
+	 * adding and subtracting, thus allowing gdb to put grung on
+	 * the stack which it removes later.
+	 */
+	if (NEW_esp != OLD_esp) {
+		unsigned long *ptr = END_OF_LOOKASIDE;
+		if (NEW_esp < OLD_esp)
+			ptr -= (OLD_esp - NEW_esp) / sizeof (unsigned long);
+		*--ptr = linux_regs->eflags;
+		*--ptr = linux_regs->cs;
+		*--ptr = linux_regs->rip;
+		*--ptr = linux_regs->rcx;
+		*--ptr = linux_regs->rbx;
+		*--ptr = linux_regs->rax;
+		linux_regs->rcx = NEW_esp - (sizeof (unsigned long) * 6);
+		linux_regs->rbx = (unsigned long) END_OF_LOOKASIDE;
+		if (NEW_esp < OLD_esp) {
+			linux_regs->rip = (unsigned long) fn_call_stub;
+		} else {
+			linux_regs->rip = (unsigned long) fn_rtn_stub;
+			linux_regs->rax = NEW_esp;
+		}
+		linux_regs->eflags &= ~(IF_BIT | TF_BIT);
+	}
+#ifdef CONFIG_SMP
+	/*
+	 * Release gdb wait locks
+	 * Sanity check time.  Must have at least one cpu to run.  Also single
+	 * step must not be done if the current cpu is on hold.
+	 */
+	if (spinlock_count == 1) {
+		int ss_hold = (regs.eflags & 0x100) && kgdb_info.hold_on_sstep;
+		int cpu_avail = 0;
+		int i;
+
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			if (!cpu_online(i))
+				break;
+			if (!hold_cpu(i)) {
+				cpu_avail = 1;
+			}
+		}
+		/*
+		 * Early in the bring up there will be NO cpus on line...
+		 */
+		if (!cpu_avail && !cpus_empty(cpu_online_map)) {
+			to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n");
+			goto once_again;
+		}
+		if (hold_cpu(smp_processor_id()) && (regs.eflags & 0x100)) {
+			to_gdb
+			    ("Current cpu must be unblocked to single step\n");
+			goto once_again;
+		}
+		if (!(ss_hold)) {
+			int i;
+			for (i = 0; i < MAX_NO_CPUS; i++) {
+				if (!hold_cpu(i)) {
+					spin_unlock(&waitlocks[i]);
+				}
+			}
+		} else {
+			spin_unlock(&waitlocks[smp_processor_id()]);
+		}
+		/* Release kgdb spinlock */
+		KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+		/*
+		 * If this cpu is on hold, this is where we
+		 * do it.  Note, the NMI will pull us out of here,
+		 * but will return as the above lock is not held.
+		 * We will stay here till another cpu releases the lock for us.
+		 */
+		spin_unlock_wait(waitlocks + smp_processor_id());
+		local_irq_restore(flags);
+		return (1);
+	}
+#if 0
+exit_just_unlock:
+#endif
+#endif
+	/* Release kgdb spinlock */
+	KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+	local_irq_restore(flags);
+	return (1);
+}
+
+#undef regs
+static int kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
+{
+	struct die_args *d = ptr;
+
+	if (!kgdb_enabled || (cmd == DIE_DEBUG && user_mode(d->regs)))
+		return NOTIFY_DONE;
+	if (cmd == DIE_NMI_IPI) {
+		if (in_kgdb(d->regs))
+			return NOTIFY_BAD;
+	} else if (kgdb_handle_exception(d->trapnr, d->signr, d->err, d->regs))
+		return NOTIFY_BAD; /* skip */
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block kgdb_notifier = {
+	.notifier_call = kgdb_notify,
+	.priority = 0,
+};
+
+void set_debug_traps(void)
+{
+	static int initialized = 0;
+
+	if (!initialized) {
+		initialized = 1;
+		notifier_chain_register(&die_chain, &kgdb_notifier);
+	}
+}
+
+/*
+ * Provide the command line "gdb" initial break
+ */
+int __init kgdb_initial_break(char * str)
+{
+	if (*str == '\0'){
+		breakpoint();
+		return 1;
+	}
+	return 0;
+}
+__setup("gdb",kgdb_initial_break);
+
+/* This function will generate a breakpoint exception.	It is used at the
+   beginning of a program to sync up with a debugger and can be used
+   otherwise as a quick means to stop program execution and "break" into
+   the debugger. */
+/* But really, just use the BREAKPOINT macro.  We will handle the int stuff
+ */
+
+void breakpoint(void)
+{
+
+	set_debug_traps();
+	kgdb_enabled = 1;
+#if 0
+	/*
+	 * These calls were not enough to allow breakpoint to be
+	 * called before trap_init().  I moved the argument parsing
+	 * after trap_init() and it seems to work.
+	 */
+	set_intr_usr_gate(3,&int3); /* disable ints on trap */
+	set_intr_gate(1,&debug);
+	set_intr_gate(14,&page_fault);
+#endif
+
+        BREAKPOINT;
+}
+
+#ifdef later
+/*
+ * possibly we should not go thru the traps.c code at all?  Someday.
+ */
+void
+do_kgdb_int3(struct pt_regs *regs, long error_code)
+{
+	kgdb_handle_exception(3, 5, error_code, regs);
+	return;
+}
+#endif
+#undef regs
+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
+asmlinkage void
+bad_sys_call_exit(int stuff)
+{
+	struct pt_regs *regs = (struct pt_regs *) &stuff;
+	printk("Sys call %d return with %x preempt_count\n",
+	       (int) regs->orig_eax, preempt_count());
+}
+#endif
+#ifdef CONFIG_STACK_OVERFLOW_TEST
+#include <asm/kgdb.h>
+asmlinkage void
+stack_overflow(void)
+{
+#ifdef BREAKPOINT
+	BREAKPOINT;
+#else
+	printk("Kernel stack overflow, looping forever\n");
+#endif
+	while (1) {
+	}
+}
+#endif
+
+#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE)
+char gdbconbuf[BUFMAX];
+
+static void
+kgdb_gdb_message(const char *s, unsigned count)
+{
+	int i;
+	int wcount;
+	char *bufptr;
+	/*
+	 * This takes care of NMI while spining out chars to gdb
+	 */
+	IF_SMP(in_kgdb_console = 1);
+	gdbconbuf[0] = 'O';
+	bufptr = gdbconbuf + 1;
+	while (count > 0) {
+		if ((count << 1) > (BUFMAX - 2)) {
+			wcount = (BUFMAX - 2) >> 1;
+		} else {
+			wcount = count;
+		}
+		count -= wcount;
+		for (i = 0; i < wcount; i++) {
+			bufptr = pack_hex_byte(bufptr, s[i]);
+		}
+		*bufptr = '\0';
+		s += wcount;
+
+		putpacket(gdbconbuf);
+
+	}
+	IF_SMP(in_kgdb_console = 0);
+}
+#endif
+#ifdef CONFIG_SMP
+static void
+to_gdb(const char *s)
+{
+	int count = 0;
+	while (s[count] && (count++ < BUFMAX)) ;
+	kgdb_gdb_message(s, count);
+}
+#endif
+#ifdef CONFIG_KGDB_CONSOLE
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <asm/semaphore.h>
+
+void
+kgdb_console_write(struct console *co, const char *s, unsigned count)
+{
+
+	if (gdb_i386vector == -1) {
+		/*
+		 * We have not yet talked to gdb.  What to do...
+		 * lets break, on continue we can do the write.
+		 * But first tell him whats up. Uh, well no can do,
+		 * as this IS the console.  Oh well...
+		 * We do need to wait or the messages will be lost.
+		 * Other option would be to tell the above code to
+		 * ignore this breakpoint and do an auto return,
+		 * but that might confuse gdb.	Also this happens
+		 * early enough in boot up that we don't have the traps
+		 * set up yet, so...
+		 */
+		breakpoint();
+	}
+	kgdb_gdb_message(s, count);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Serial KGDB driver
+ * ------------------------------------------------------------
+ */
+
+static struct console kgdbcons = {
+	name:"kgdb",
+	write:kgdb_console_write,
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	device:kgdb_console_device,
+#endif
+	flags:CON_PRINTBUFFER | CON_ENABLED,
+	index:-1,
+};
+
+/*
+ * The trick here is that this file gets linked before printk.o
+ * That means we get to peer at the console info in the command
+ * line before it does.	 If we are up, we register, otherwise,
+ * do nothing.	By returning 0, we allow printk to look also.
+ */
+static int kgdb_console_enabled;
+
+int __init
+kgdb_console_init(char *str)
+{
+	if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) {
+		register_console(&kgdbcons);
+		kgdb_console_enabled = 1;
+	}
+	return 0;		/* let others look at the string */
+}
+
+__setup("console=", kgdb_console_init);
+
+#ifdef CONFIG_KGDB_USER_CONSOLE
+static kdev_t kgdb_console_device(struct console *c);
+/* This stuff sort of works, but it knocks out telnet devices
+ * we are leaving it here in case we (or you) find time to figure it out
+ * better..
+ */
+
+/*
+ * We need a real char device as well for when the console is opened for user
+ * space activities.
+ */
+
+static int
+kgdb_consdev_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t
+kgdb_consdev_write(struct file *file, const char *buf,
+		   size_t count, loff_t * ppos)
+{
+	int size, ret = 0;
+	static char kbuf[128];
+	static DECLARE_MUTEX(sem);
+
+	/* We are not reentrant... */
+	if (down_interruptible(&sem))
+		return -ERESTARTSYS;
+
+	while (count > 0) {
+		/* need to copy the data from user space */
+		size = count;
+		if (size > sizeof (kbuf))
+			size = sizeof (kbuf);
+		if (copy_from_user(kbuf, buf, size)) {
+			ret = -EFAULT;
+			break;;
+		}
+		kgdb_console_write(&kgdbcons, kbuf, size);
+		count -= size;
+		ret += size;
+		buf += size;
+	}
+
+	up(&sem);
+
+	return ret;
+}
+
+struct file_operations kgdb_consdev_fops = {
+	open:kgdb_consdev_open,
+	write:kgdb_consdev_write
+};
+static kdev_t
+kgdb_console_device(struct console *c)
+{
+	return MKDEV(TTYAUX_MAJOR, 1);
+}
+
+/*
+ * This routine gets called from the serial stub in the i386/lib
+ * This is so it is done late in bring up (just before the console open).
+ */
+void
+kgdb_console_finit(void)
+{
+	if (kgdb_console_enabled) {
+		char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1));
+		char *cp = cptr;
+		while (*cptr && *cptr != '(')
+			cptr++;
+		*cptr = 0;
+		unregister_chrdev(TTYAUX_MAJOR, cp);
+		register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops);
+	}
+}
+#endif
+#endif
+#ifdef CONFIG_KGDB_TS
+#include <asm/msr.h>		/* time stamp code */
+#include <asm/hardirq.h>	/* in_interrupt */
+#ifdef CONFIG_KGDB_TS_64
+#define DATA_POINTS 64
+#endif
+#ifdef CONFIG_KGDB_TS_128
+#define DATA_POINTS 128
+#endif
+#ifdef CONFIG_KGDB_TS_256
+#define DATA_POINTS 256
+#endif
+#ifdef CONFIG_KGDB_TS_512
+#define DATA_POINTS 512
+#endif
+#ifdef CONFIG_KGDB_TS_1024
+#define DATA_POINTS 1024
+#endif
+#ifndef DATA_POINTS
+#define DATA_POINTS 128		/* must be a power of two */
+#endif
+#define INDEX_MASK (DATA_POINTS - 1)
+#if (INDEX_MASK & DATA_POINTS)
+#error "CONFIG_KGDB_TS_COUNT must be a power of 2"
+#endif
+struct kgdb_and_then_struct {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	int data0;
+	int data1;
+};
+struct kgdb_and_then_struct2 {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	struct task_struct *t1;
+	struct task_struct *t2;
+};
+struct kgdb_and_then_struct kgdb_data[DATA_POINTS];
+
+struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0];
+int kgdb_and_then_count;
+
+void
+kgdb_tstamp(int line, char *source, int data0, int data1)
+{
+	static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED;
+	int flags;
+	local_irq_save(flags);
+	spin_lock(&ts_spin);
+	rdtscll(kgdb_and_then->at_time);
+#ifdef CONFIG_SMP
+	kgdb_and_then->on_cpu = smp_processor_id();
+#endif
+	kgdb_and_then->task = current;
+	kgdb_and_then->from_ln = line;
+	kgdb_and_then->in_src = source;
+	kgdb_and_then->from = __builtin_return_address(0);
+	kgdb_and_then->with_shpf = (int *) (((flags & IF_BIT) >> 9) |
+					    (preempt_count() << 8));
+	kgdb_and_then->data0 = data0;
+	kgdb_and_then->data1 = data1;
+	kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK];
+	spin_unlock(&ts_spin);
+	local_irq_restore(flags);
+#ifdef CONFIG_PREEMPT
+
+#endif
+	return;
+}
+#endif
+typedef int gdb_debug_hook(int exceptionVector,
+			   int signo, int err_code, struct pt_regs *linux_regs);
+gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception;	/* histerical reasons... */
+
+static int kgdb_need_breakpoint[NR_CPUS];
+
+void kgdb_schedule_breakpoint(void)
+{
+	kgdb_need_breakpoint[smp_processor_id()] = 1;
+}
+
+void kgdb_process_breakpoint(void)
+{
+	/*
+	 * Handle a breakpoint queued from inside network driver code
+         * to avoid reentrancy issues
+	 */
+	if (kgdb_need_breakpoint[smp_processor_id()]) {
+		kgdb_need_breakpoint[smp_processor_id()] = 0;
+		kgdb_enabled = 1;
+		BREAKPOINT;
+	}
+}
+
--- diff/arch/x86_64/lib/kgdb_serial.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/x86_64/lib/kgdb_serial.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,490 @@
+/*
+ * Serial interface GDB stub
+ *
+ * Written (hacked together) by David Grothe (dave@gcom.com)
+ * Modified to allow invokation early in boot see also
+ * kgdb.h for instructions by George Anzinger(george@mvista.com)
+ * Modified to handle debugging over ethernet by Robert Walsh
+ * <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ * code by San Mehat.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/kgdb_local.h>
+#ifdef CONFIG_KGDB_USER_CONSOLE
+extern void kgdb_console_finit(void);
+#endif
+#define PRNT_off
+#define TEST_EXISTANCE
+#ifdef PRNT
+#define dbprintk(s) printk s
+#else
+#define dbprintk(s)
+#endif
+#define TEST_INTERRUPT_off
+#ifdef TEST_INTERRUPT
+#define intprintk(s) printk s
+#else
+#define intprintk(s)
+#endif
+
+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+
+#define	GDB_BUF_SIZE	512	/* power of 2, please */
+
+static char gdb_buf[GDB_BUF_SIZE];
+static int gdb_buf_in_inx;
+static atomic_t gdb_buf_in_cnt;
+static int gdb_buf_out_inx;
+
+struct async_struct *gdb_async_info;
+static int gdb_async_irq;
+
+#define outb_px(a,b) outb_p(b,a)
+
+static void program_uart(struct async_struct *info);
+static void write_char(struct async_struct *info, int chr);
+/*
+ * Get a byte from the hardware data buffer and return it
+ */
+static int
+read_data_bfr(struct async_struct *info)
+{
+	char it = inb_p(info->port + UART_LSR);
+
+	if (it & UART_LSR_DR)
+		return (inb_p(info->port + UART_RX));
+	/*
+	 * If we have a framing error assume somebody messed with
+	 * our uart.  Reprogram it and send '-' both ways...
+	 */
+	if (it & 0xc) {
+		program_uart(info);
+		write_char(info, '-');
+		return ('-');
+	}
+	return (-1);
+
+}				/* read_data_bfr */
+
+/*
+ * Get a char if available, return -1 if nothing available.
+ * Empty the receive buffer first, then look at the interface hardware.
+
+ * Locking here is a bit of a problem.	We MUST not lock out communication
+ * if we are trying to talk to gdb about a kgdb entry.	ON the other hand
+ * we can loose chars in the console pass thru if we don't lock.  It is also
+ * possible that we could hold the lock or be waiting for it when kgdb
+ * NEEDS to talk.  Since kgdb locks down the world, it does not need locks.
+ * We do, of course have possible issues with interrupting a uart operation,
+ * but we will just depend on the uart status to help keep that straight.
+
+ */
+static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED;
+#ifdef CONFIG_SMP
+extern spinlock_t kgdb_spinlock;
+#endif
+
+static int
+read_char(struct async_struct *info)
+{
+	int chr;
+	unsigned long flags;
+	local_irq_save(flags);
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_lock(&uart_interrupt_lock);
+	}
+#endif
+	if (atomic_read(&gdb_buf_in_cnt) != 0) {	/* intr routine has q'd chars */
+		chr = gdb_buf[gdb_buf_out_inx++];
+		gdb_buf_out_inx &= (GDB_BUF_SIZE - 1);
+		atomic_dec(&gdb_buf_in_cnt);
+	} else {
+		chr = read_data_bfr(info);
+	}
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_unlock(&uart_interrupt_lock);
+	}
+#endif
+	local_irq_restore(flags);
+	return (chr);
+}
+
+/*
+ * Wait until the interface can accept a char, then write it.
+ */
+static void
+write_char(struct async_struct *info, int chr)
+{
+	while (!(inb_p(info->port + UART_LSR) & UART_LSR_THRE)) ;
+
+	outb_p(chr, info->port + UART_TX);
+
+}				/* write_char */
+
+/*
+ * Mostly we don't need a spinlock, but since the console goes
+ * thru here with interrutps on, well, we need to catch those
+ * chars.
+ */
+/*
+ * This is the receiver interrupt routine for the GDB stub.
+ * It will receive a limited number of characters of input
+ * from the gdb  host machine and save them up in a buffer.
+ *
+ * When the gdb stub routine tty_getDebugChar() is called it
+ * draws characters out of the buffer until it is empty and
+ * then reads directly from the serial port.
+ *
+ * We do not attempt to write chars from the interrupt routine
+ * since the stubs do all of that via tty_putDebugChar() which
+ * writes one byte after waiting for the interface to become
+ * ready.
+ *
+ * The debug stubs like to run with interrupts disabled since,
+ * after all, they run as a consequence of a breakpoint in
+ * the kernel.
+ *
+ * Perhaps someone who knows more about the tty driver than I
+ * care to learn can make this work for any low level serial
+ * driver.
+ */
+static irqreturn_t
+gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct async_struct *info;
+	unsigned long flags;
+
+	info = gdb_async_info;
+	if (!info || !info->tty || irq != gdb_async_irq)
+		return IRQ_NONE;
+
+	local_irq_save(flags);
+	spin_lock(&uart_interrupt_lock);
+	do {
+		int chr = read_data_bfr(info);
+		intprintk(("Debug char on int: %x hex\n", chr));
+		if (chr < 0)
+			continue;
+
+		if (chr == 3) {	/* Ctrl-C means remote interrupt */
+			BREAKPOINT;
+			continue;
+		}
+
+		if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) {
+			/* buffer overflow tosses early char */
+			read_char(info);
+		}
+		gdb_buf[gdb_buf_in_inx++] = chr;
+		gdb_buf_in_inx &= (GDB_BUF_SIZE - 1);
+	} while (inb_p(info->port + UART_IIR) & UART_IIR_RDI);
+	spin_unlock(&uart_interrupt_lock);
+	local_irq_restore(flags);
+	return IRQ_HANDLED;
+}				/* gdb_interrupt */
+
+/*
+ * Just a NULL routine for testing.
+ */
+void
+gdb_null(void)
+{
+}				/* gdb_null */
+
+/* These structure are filled in with values defined in asm/kgdb_local.h
+ */
+static struct serial_state state = SB_STATE;
+static struct async_struct local_info = SB_INFO;
+static int ok_to_enable_ints = 0;
+static void kgdb_enable_ints_now(void);
+
+extern char *kgdb_version;
+/*
+ * Hook an IRQ for KGDB.
+ *
+ * This routine is called from tty_putDebugChar, below.
+ */
+static int ints_disabled = 1;
+int
+gdb_hook_interrupt(struct async_struct *info, int verb)
+{
+	struct serial_state *state = info->state;
+	unsigned long flags;
+	int port;
+#ifdef TEST_EXISTANCE
+	int scratch, scratch2;
+#endif
+
+	/* The above fails if memory managment is not set up yet.
+	 * Rather than fail the set up, just keep track of the fact
+	 * and pick up the interrupt thing later.
+	 */
+	gdb_async_info = info;
+	port = gdb_async_info->port;
+	gdb_async_irq = state->irq;
+	if (verb) {
+		printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n",
+		       kgdb_version,
+		       port,
+		       gdb_async_irq, gdb_async_info->state->custom_divisor);
+	}
+	local_irq_save(flags);
+#ifdef TEST_EXISTANCE
+	/* Existance test */
+	/* Should not need all this, but just in case.... */
+
+	scratch = inb_p(port + UART_IER);
+	outb_px(port + UART_IER, 0);
+	outb_px(0xff, 0x080);
+	scratch2 = inb_p(port + UART_IER);
+	outb_px(port + UART_IER, scratch);
+	if (scratch2) {
+		printk
+		    ("gdb_hook_interrupt: Could not clear IER, not a UART!\n");
+		local_irq_restore(flags);
+		return 1;	/* We failed; there's nothing here */
+	}
+	scratch2 = inb_p(port + UART_LCR);
+	outb_px(port + UART_LCR, 0xBF);	/* set up for StarTech test */
+	outb_px(port + UART_EFR, 0);	/* EFR is the same as FCR */
+	outb_px(port + UART_LCR, 0);
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO);
+	scratch = inb_p(port + UART_IIR) >> 6;
+	if (scratch == 1) {
+		printk("gdb_hook_interrupt: Undefined UART type!"
+		       "  Not a UART! \n");
+		local_irq_restore(flags);
+		return 1;
+	} else {
+		dbprintk(("gdb_hook_interrupt: UART type "
+			  "is %d where 0=16450, 2=16550 3=16550A\n", scratch));
+	}
+	scratch = inb_p(port + UART_MCR);
+	outb_px(port + UART_MCR, UART_MCR_LOOP | scratch);
+	outb_px(port + UART_MCR, UART_MCR_LOOP | 0x0A);
+	scratch2 = inb_p(port + UART_MSR) & 0xF0;
+	outb_px(port + UART_MCR, scratch);
+	if (scratch2 != 0x90) {
+		printk("gdb_hook_interrupt: "
+		       "Loop back test failed! Not a UART!\n");
+		local_irq_restore(flags);
+		return scratch2 + 1000;	/* force 0 to fail */
+	}
+#endif				/* test existance */
+	program_uart(info);
+	local_irq_restore(flags);
+
+	return (0);
+
+}				/* gdb_hook_interrupt */
+
+static void
+program_uart(struct async_struct *info)
+{
+	int port = info->port;
+
+	(void) inb_p(port + UART_RX);
+	outb_px(port + UART_IER, 0);
+
+	(void) inb_p(port + UART_RX);	/* serial driver comments say */
+	(void) inb_p(port + UART_IIR);	/* this clears the interrupt regs */
+	(void) inb_p(port + UART_MSR);
+	outb_px(port + UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
+	outb_px(port + UART_DLL, info->state->custom_divisor & 0xff);	/* LS */
+	outb_px(port + UART_DLM, info->state->custom_divisor >> 8);	/* MS  */
+	outb_px(port + UART_MCR, info->MCR);
+
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR);	/* set fcr */
+	outb_px(port + UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1);	/* set fcr */
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
+	}
+	return;
+}
+
+/*
+ * tty_getDebugChar
+ *
+ * This is a GDB stub routine.	It waits for a character from the
+ * serial interface and then returns it.  If there is no serial
+ * interface connection then it returns a bogus value which will
+ * almost certainly cause the system to hang.  In the
+ */
+int kgdb_in_isr = 0;
+int kgdb_in_lsr = 0;
+extern spinlock_t kgdb_spinlock;
+
+/* Caller takes needed protections */
+
+int
+tty_getDebugChar(void)
+{
+	volatile int chr, dum, time, end_time;
+
+	dbprintk(("tty_getDebugChar(port %x): ", gdb_async_info->port));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+	/*
+	 * This trick says if we wait a very long time and get
+	 * no char, return the -1 and let the upper level deal
+	 * with it.
+	 */
+	rdtsc(dum, time);
+	end_time = time + 2;
+	while (((chr = read_char(gdb_async_info)) == -1) &&
+	       (end_time - time) > 0) {
+		rdtsc(dum, time);
+	};
+	/*
+	 * This covers our butts if some other code messes with
+	 * our uart, hay, it happens :o)
+	 */
+	if (chr == -1)
+		program_uart(gdb_async_info);
+
+	dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' '));
+	return (chr);
+
+}				/* tty_getDebugChar */
+
+static int count = 3;
+static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED;
+
+static int __init
+kgdb_enable_ints(void)
+{
+	set_debug_traps();
+	if (kgdboe) {
+		return 0;
+	}
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 1);
+	}
+	ok_to_enable_ints = 1;
+	kgdb_enable_ints_now();
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	kgdb_console_finit();
+#endif
+	return 0;
+}
+
+#ifdef CONFIG_SERIAL_8250
+void shutdown_for_kgdb(struct async_struct *gdb_async_info);
+#endif
+
+#define kgdb_mem_init_done()    (1)
+
+static void
+kgdb_enable_ints_now(void)
+{
+	if (!spin_trylock(&one_at_atime))
+		return;
+	if (!ints_disabled)
+		goto exit;
+	if (kgdb_mem_init_done() &&
+			ints_disabled) {	/* don't try till mem init */
+#ifdef CONFIG_SERIAL_8250
+		/*
+		 * The ifdef here allows the system to be configured
+		 * without the serial driver.
+		 * Don't make it a module, however, it will steal the port
+		 */
+		shutdown_for_kgdb(gdb_async_info);
+#endif
+		ints_disabled = request_irq(gdb_async_info->state->irq,
+					    gdb_interrupt,
+					    IRQ_T(gdb_async_info),
+					    "KGDB-stub", NULL);
+		intprintk(("KGDB: request_irq returned %d\n", ints_disabled));
+	}
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
+	}
+      exit:
+	spin_unlock(&one_at_atime);
+}
+
+/*
+ * tty_putDebugChar
+ *
+ * This is a GDB stub routine.	It waits until the interface is ready
+ * to transmit a char and then sends it.  If there is no serial
+ * interface connection then it simply returns to its caller, having
+ * pretended to send the char.	Caller takes needed protections.
+ */
+void
+tty_putDebugChar(int chr)
+{
+	dbprintk(("tty_putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n",
+		  gdb_async_info->port,
+		  chr,
+		  chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+
+	write_char(gdb_async_info, chr);	/* this routine will wait */
+	count = (chr == '#') ? 0 : count + 1;
+	if ((count == 2)) {	/* try to enable after */
+		if (ints_disabled & ok_to_enable_ints)
+			kgdb_enable_ints_now();	/* try to enable after */
+
+		/* We do this a lot because, well we really want to get these
+		 * interrupts.	The serial driver will clear these bits when it
+		 * initializes the chip.  Every thing else it does is ok,
+		 * but this.
+		 */
+		if (!ints_disabled) {
+			outb_px(gdb_async_info->port + UART_IER,
+				gdb_async_info->IER);
+		}
+	}
+
+}				/* tty_putDebugChar */
+
+/*
+ * This does nothing for the serial port, since it doesn't buffer.
+ */
+
+void tty_flushDebugChar(void)
+{
+}
+
+module_init(kgdb_enable_ints);
--- diff/crypto/arc4.c	1970-01-01 01:00:00.000000000 +0100
+++ source/crypto/arc4.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,107 @@
+/* 
+ * Cryptographic API
+ *
+ * ARC4 Cipher Algorithm
+ *
+ * Jon Oberheide <jon@focalhost.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/module.h>
+#include <linux/init.h>
+#include <linux/crypto.h>
+
+#define ARC4_MIN_KEY_SIZE	1
+#define ARC4_MAX_KEY_SIZE	256
+#define ARC4_BLOCK_SIZE		1
+
+struct arc4_ctx {
+	u8 S[256];
+	u8 x, y;
+};
+
+static int arc4_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, u32 *flags)
+{
+	struct arc4_ctx *ctx = ctx_arg;
+	int i, j = 0, k = 0;
+
+	ctx->x = 1;
+	ctx->y = 0;
+
+	for(i = 0; i < 256; i++)
+		ctx->S[i] = i;
+
+	for(i = 0; i < 256; i++)
+	{
+		u8 a = ctx->S[i];
+		j = (j + in_key[k] + a) & 0xff;
+		ctx->S[i] = ctx->S[j];
+		ctx->S[j] = a;
+		if(++k >= key_len)
+			k = 0;
+	}
+
+	/* TODO: dump the first 768 bytes generated as recommended
+	   by Ilya Mironov (http://eprint.iacr.org/2002/067/) to 
+	   increase the statistical strength of the state table */
+
+	return 0;
+}
+
+static void arc4_crypt(void *ctx_arg, u8 *out, const u8 *in)
+{
+	struct arc4_ctx *ctx = ctx_arg;
+
+	u8 *const S = ctx->S;
+	u8 x = ctx->x;
+	u8 y = ctx->y;
+	u8 a, b;
+
+	a = S[x];
+	y = (y + a) & 0xff;
+	b = S[y];
+	S[x] = b;
+	S[y] = a;
+	x = (x + 1) & 0xff;
+	*out++ = *in ^ S[(a + b) & 0xff];
+
+	ctx->x = x;
+	ctx->y = y;
+}
+
+static struct crypto_alg arc4_alg = {
+	.cra_name		=	"arc4",
+	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize		=	ARC4_BLOCK_SIZE,
+	.cra_ctxsize		=	sizeof(struct arc4_ctx),
+	.cra_module		=	THIS_MODULE,
+	.cra_list		=	LIST_HEAD_INIT(arc4_alg.cra_list),
+	.cra_u			=	{ .cipher = {
+	.cia_min_keysize	=	ARC4_MIN_KEY_SIZE,
+	.cia_max_keysize	=	ARC4_MAX_KEY_SIZE,
+	.cia_setkey	   	= 	arc4_set_key,
+	.cia_encrypt	 	=	arc4_crypt,
+	.cia_decrypt	  	=	arc4_crypt } }
+};
+
+static int __init arc4_init(void)
+{
+	return crypto_register_alg(&arc4_alg);
+}
+
+
+static void __exit arc4_exit(void)
+{
+	crypto_unregister_alg(&arc4_alg);
+}
+
+module_init(arc4_init);
+module_exit(arc4_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ARC4 Cipher Algorithm");
+MODULE_AUTHOR("Jon Oberheide <jon@focalhost.com>");
--- diff/drivers/block/cfq-iosched.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/block/cfq-iosched.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,707 @@
+/*
+ *  linux/drivers/block/cfq-iosched.c
+ *
+ *  CFQ, or complete fairness queueing, disk scheduler.
+ *
+ *  Based on ideas from a previously unfinished io
+ *  scheduler (round robin per-process disk scheduling) and Andrea Arcangeli.
+ *
+ *  Copyright (C) 2003 Jens Axboe <axboe@suse.de>
+ */
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/blkdev.h>
+#include <linux/elevator.h>
+#include <linux/bio.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/compiler.h>
+#include <linux/hash.h>
+#include <linux/rbtree.h>
+#include <linux/mempool.h>
+
+/*
+ * tunables
+ */
+static int cfq_quantum = 4;
+static int cfq_queued = 8;
+
+#define CFQ_QHASH_SHIFT		6
+#define CFQ_QHASH_ENTRIES	(1 << CFQ_QHASH_SHIFT)
+#define list_entry_qhash(entry)	list_entry((entry), struct cfq_queue, cfq_hash)
+
+#define CFQ_MHASH_SHIFT		8
+#define CFQ_MHASH_BLOCK(sec)	((sec) >> 3)
+#define CFQ_MHASH_ENTRIES	(1 << CFQ_MHASH_SHIFT)
+#define CFQ_MHASH_FN(sec)	(hash_long(CFQ_MHASH_BLOCK((sec)),CFQ_MHASH_SHIFT))
+#define ON_MHASH(crq)		!list_empty(&(crq)->hash)
+#define rq_hash_key(rq)		((rq)->sector + (rq)->nr_sectors)
+#define list_entry_hash(ptr)	list_entry((ptr), struct cfq_rq, hash)
+
+#define list_entry_cfqq(ptr)	list_entry((ptr), struct cfq_queue, cfq_list)
+
+#define RQ_DATA(rq)		((struct cfq_rq *) (rq)->elevator_private)
+
+static kmem_cache_t *crq_pool;
+static kmem_cache_t *cfq_pool;
+static mempool_t *cfq_mpool;
+
+struct cfq_data {
+	struct list_head rr_list;
+	struct list_head *dispatch;
+	struct list_head *cfq_hash;
+
+	struct list_head *crq_hash;
+
+	unsigned int busy_queues;
+	unsigned int max_queued;
+
+	mempool_t *crq_pool;
+};
+
+struct cfq_queue {
+	struct list_head cfq_hash;
+	struct list_head cfq_list;
+	struct rb_root sort_list;
+	int pid;
+	int queued[2];
+#if 0
+	/*
+	 * with a simple addition like this, we can do io priorities. almost.
+	 * does need a split request free list, too.
+	 */
+	int io_prio
+#endif
+};
+
+struct cfq_rq {
+	struct rb_node rb_node;
+	sector_t rb_key;
+
+	struct request *request;
+
+	struct cfq_queue *cfq_queue;
+
+	struct list_head hash;
+};
+
+static void cfq_put_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq);
+static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *cfqd, int pid);
+static void cfq_dispatch_sort(struct list_head *head, struct cfq_rq *crq);
+
+/*
+ * lots of deadline iosched dupes, can be abstracted later...
+ */
+static inline void __cfq_del_crq_hash(struct cfq_rq *crq)
+{
+	list_del_init(&crq->hash);
+}
+
+static inline void cfq_del_crq_hash(struct cfq_rq *crq)
+{
+	if (ON_MHASH(crq))
+		__cfq_del_crq_hash(crq);
+}
+
+static void cfq_remove_merge_hints(request_queue_t *q, struct cfq_rq *crq)
+{
+	cfq_del_crq_hash(crq);
+
+	if (q->last_merge == crq->request)
+		q->last_merge = NULL;
+}
+
+static inline void cfq_add_crq_hash(struct cfq_data *cfqd, struct cfq_rq *crq)
+{
+	struct request *rq = crq->request;
+
+	BUG_ON(ON_MHASH(crq));
+
+	list_add(&crq->hash, &cfqd->crq_hash[CFQ_MHASH_FN(rq_hash_key(rq))]);
+}
+
+static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset)
+{
+	struct list_head *hash_list = &cfqd->crq_hash[CFQ_MHASH_FN(offset)];
+	struct list_head *entry, *next = hash_list->next;
+
+	while ((entry = next) != hash_list) {
+		struct cfq_rq *crq = list_entry_hash(entry);
+		struct request *__rq = crq->request;
+
+		next = entry->next;
+
+		BUG_ON(!ON_MHASH(crq));
+
+		if (!rq_mergeable(__rq)) {
+			__cfq_del_crq_hash(crq);
+			continue;
+		}
+
+		if (rq_hash_key(__rq) == offset)
+			return __rq;
+	}
+
+	return NULL;
+}
+
+/*
+ * rb tree support functions
+ */
+#define RB_NONE		(2)
+#define RB_EMPTY(node)	((node)->rb_node == NULL)
+#define RB_CLEAR(node)	((node)->rb_color = RB_NONE)
+#define RB_CLEAR_ROOT(root)	((root)->rb_node = NULL)
+#define ON_RB(node)	((node)->rb_color != RB_NONE)
+#define rb_entry_crq(node)	rb_entry((node), struct cfq_rq, rb_node)
+#define rq_rb_key(rq)		(rq)->sector
+
+static inline void cfq_del_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq)
+{
+	if (ON_RB(&crq->rb_node)) {
+		cfqq->queued[rq_data_dir(crq->request)]--;
+		rb_erase(&crq->rb_node, &cfqq->sort_list);
+		crq->cfq_queue = NULL;
+	}
+}
+
+static struct cfq_rq *
+__cfq_add_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq)
+{
+	struct rb_node **p = &cfqq->sort_list.rb_node;
+	struct rb_node *parent = NULL;
+	struct cfq_rq *__crq;
+
+	while (*p) {
+		parent = *p;
+		__crq = rb_entry_crq(parent);
+
+		if (crq->rb_key < __crq->rb_key)
+			p = &(*p)->rb_left;
+		else if (crq->rb_key > __crq->rb_key)
+			p = &(*p)->rb_right;
+		else
+			return __crq;
+	}
+
+	rb_link_node(&crq->rb_node, parent, p);
+	return 0;
+}
+
+static void
+cfq_add_crq_rb(struct cfq_data *cfqd, struct cfq_queue *cfqq,struct cfq_rq *crq)
+{
+	struct request *rq = crq->request;
+	struct cfq_rq *__alias;
+
+	crq->rb_key = rq_rb_key(rq);
+	cfqq->queued[rq_data_dir(rq)]++;
+retry:
+	__alias = __cfq_add_crq_rb(cfqq, crq);
+	if (!__alias) {
+		rb_insert_color(&crq->rb_node, &cfqq->sort_list);
+		crq->cfq_queue = cfqq;
+		return;
+	}
+
+	cfq_del_crq_rb(cfqq, __alias);
+	cfq_dispatch_sort(cfqd->dispatch, __alias);
+	goto retry;
+}
+
+static struct request *
+cfq_find_rq_rb(struct cfq_data *cfqd, sector_t sector)
+{
+	struct cfq_queue *cfqq = cfq_find_cfq_hash(cfqd, current->tgid);
+	struct rb_node *n;
+
+	if (!cfqq)
+		goto out;
+
+	n = cfqq->sort_list.rb_node;
+	while (n) {
+		struct cfq_rq *crq = rb_entry_crq(n);
+
+		if (sector < crq->rb_key)
+			n = n->rb_left;
+		else if (sector > crq->rb_key)
+			n = n->rb_right;
+		else
+			return crq->request;
+	}
+
+out:
+	return NULL;
+}
+
+static void cfq_remove_request(request_queue_t *q, struct request *rq)
+{
+	struct cfq_data *cfqd = q->elevator.elevator_data;
+	struct cfq_rq *crq = RQ_DATA(rq);
+
+	if (crq) {
+		struct cfq_queue *cfqq = crq->cfq_queue;
+
+		cfq_remove_merge_hints(q, crq);
+		list_del_init(&rq->queuelist);
+
+		if (cfqq) {
+			cfq_del_crq_rb(cfqq, crq);
+
+			if (RB_EMPTY(&cfqq->sort_list))
+				cfq_put_queue(cfqd, cfqq);
+		}
+	}
+}
+
+static int
+cfq_merge(request_queue_t *q, struct request **req, struct bio *bio)
+{
+	struct cfq_data *cfqd = q->elevator.elevator_data;
+	struct request *__rq;
+	int ret;
+
+	ret = elv_try_last_merge(q, bio);
+	if (ret != ELEVATOR_NO_MERGE) {
+		__rq = q->last_merge;
+		goto out_insert;
+	}
+
+	__rq = cfq_find_rq_hash(cfqd, bio->bi_sector);
+	if (__rq) {
+		BUG_ON(__rq->sector + __rq->nr_sectors != bio->bi_sector);
+
+		if (elv_rq_merge_ok(__rq, bio)) {
+			ret = ELEVATOR_BACK_MERGE;
+			goto out;
+		}
+	}
+
+	__rq = cfq_find_rq_rb(cfqd, bio->bi_sector + bio_sectors(bio));
+	if (__rq) {
+		if (elv_rq_merge_ok(__rq, bio)) {
+			ret = ELEVATOR_FRONT_MERGE;
+			goto out;
+		}
+	}
+
+	return ELEVATOR_NO_MERGE;
+out:
+	q->last_merge = __rq;
+out_insert:
+	*req = __rq;
+	return ret;
+}
+
+static void cfq_merged_request(request_queue_t *q, struct request *req)
+{
+	struct cfq_data *cfqd = q->elevator.elevator_data;
+	struct cfq_rq *crq = RQ_DATA(req);
+
+	cfq_del_crq_hash(crq);
+	cfq_add_crq_hash(cfqd, crq);
+
+	if (ON_RB(&crq->rb_node) && (rq_rb_key(req) != crq->rb_key)) {
+		struct cfq_queue *cfqq = crq->cfq_queue;
+
+		cfq_del_crq_rb(cfqq, crq);
+		cfq_add_crq_rb(cfqd, cfqq, crq);
+	}
+
+	q->last_merge = req;
+}
+
+static void
+cfq_merged_requests(request_queue_t *q, struct request *req,
+		    struct request *next)
+{
+	cfq_merged_request(q, req);
+	cfq_remove_request(q, next);
+}
+
+static void cfq_dispatch_sort(struct list_head *head, struct cfq_rq *crq)
+{
+	struct list_head *entry = head;
+	struct request *__rq;
+
+	if (!list_empty(head)) {
+		__rq = list_entry_rq(head->next);
+
+		if (crq->request->sector < __rq->sector) {
+			entry = head->prev;
+			goto link;
+		}
+	}
+
+	while ((entry = entry->prev) != head) {
+		__rq = list_entry_rq(entry);
+
+		if (crq->request->sector <= __rq->sector)
+			break;
+	}
+
+link:
+	list_add_tail(&crq->request->queuelist, entry);
+}
+
+static inline void
+__cfq_dispatch_requests(request_queue_t *q, struct cfq_data *cfqd,
+			struct cfq_queue *cfqq)
+{
+	struct cfq_rq *crq = rb_entry_crq(rb_first(&cfqq->sort_list));
+
+	cfq_del_crq_rb(cfqq, crq);
+	cfq_remove_merge_hints(q, crq);
+	cfq_dispatch_sort(cfqd->dispatch, crq);
+}
+
+static int cfq_dispatch_requests(request_queue_t *q, struct cfq_data *cfqd)
+{
+	struct cfq_queue *cfqq;
+	struct list_head *entry, *tmp;
+	int ret, queued, good_queues;
+
+	if (list_empty(&cfqd->rr_list))
+		return 0;
+
+	queued = ret = 0;
+restart:
+	good_queues = 0;
+	list_for_each_safe(entry, tmp, &cfqd->rr_list) {
+		cfqq = list_entry_cfqq(cfqd->rr_list.next);
+
+		BUG_ON(RB_EMPTY(&cfqq->sort_list));
+
+		__cfq_dispatch_requests(q, cfqd, cfqq);
+
+		if (RB_EMPTY(&cfqq->sort_list))
+			cfq_put_queue(cfqd, cfqq);
+		else
+			good_queues++;
+
+		queued++;
+		ret = 1;
+	}
+
+	if ((queued < cfq_quantum) && good_queues)
+		goto restart;
+
+	return ret;
+}
+
+static struct request *cfq_next_request(request_queue_t *q)
+{
+	struct cfq_data *cfqd = q->elevator.elevator_data;
+	struct request *rq;
+
+	if (!list_empty(cfqd->dispatch)) {
+		struct cfq_rq *crq;
+dispatch:
+		rq = list_entry_rq(cfqd->dispatch->next);
+
+		BUG_ON(q->last_merge == rq);
+		crq = RQ_DATA(rq);
+		if (crq)
+			BUG_ON(ON_MHASH(crq));
+
+		return rq;
+	}
+
+	if (cfq_dispatch_requests(q, cfqd))
+		goto dispatch;
+
+	return NULL;
+}
+
+static inline struct cfq_queue *
+__cfq_find_cfq_hash(struct cfq_data *cfqd, int pid, const int hashval)
+{
+	struct list_head *hash_list = &cfqd->cfq_hash[hashval];
+	struct list_head *entry;
+
+	list_for_each(entry, hash_list) {
+		struct cfq_queue *__cfqq = list_entry_qhash(entry);
+
+		if (__cfqq->pid == pid)
+			return __cfqq;
+	}
+
+	return NULL;
+}
+
+static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *cfqd, int pid)
+{
+	const int hashval = hash_long(current->tgid, CFQ_QHASH_SHIFT);
+
+	return __cfq_find_cfq_hash(cfqd, pid, hashval);
+}
+
+static void cfq_put_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+	cfqd->busy_queues--;
+	list_del(&cfqq->cfq_list);
+	list_del(&cfqq->cfq_hash);
+	mempool_free(cfqq, cfq_mpool);
+}
+
+static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, int pid)
+{
+	const int hashval = hash_long(current->tgid, CFQ_QHASH_SHIFT);
+	struct cfq_queue *cfqq = __cfq_find_cfq_hash(cfqd, pid, hashval);
+
+	if (!cfqq) {
+		cfqq = mempool_alloc(cfq_mpool, GFP_NOIO);
+
+		INIT_LIST_HEAD(&cfqq->cfq_hash);
+		INIT_LIST_HEAD(&cfqq->cfq_list);
+		RB_CLEAR_ROOT(&cfqq->sort_list);
+
+		cfqq->pid = pid;
+		cfqq->queued[0] = cfqq->queued[1] = 0;
+		list_add(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
+	}
+
+	return cfqq;
+}
+
+static void cfq_enqueue(struct cfq_data *cfqd, struct cfq_rq *crq)
+{
+	struct cfq_queue *cfqq;
+
+	cfqq = cfq_get_queue(cfqd, current->tgid);
+
+	cfq_add_crq_rb(cfqd, cfqq, crq);
+
+	if (list_empty(&cfqq->cfq_list)) {
+		list_add(&cfqq->cfq_list, &cfqd->rr_list);
+		cfqd->busy_queues++;
+	}
+}
+
+static void
+cfq_insert_request(request_queue_t *q, struct request *rq, int where)
+{
+	struct cfq_data *cfqd = q->elevator.elevator_data;
+	struct cfq_rq *crq = RQ_DATA(rq);
+
+	switch (where) {
+		case ELEVATOR_INSERT_BACK:
+			while (cfq_dispatch_requests(q, cfqd))
+				;
+			list_add_tail(&rq->queuelist, cfqd->dispatch);
+			break;
+		case ELEVATOR_INSERT_FRONT:
+			list_add(&rq->queuelist, cfqd->dispatch);
+			break;
+		case ELEVATOR_INSERT_SORT:
+			BUG_ON(!blk_fs_request(rq));
+			cfq_enqueue(cfqd, crq);
+			break;
+		default:
+			printk("%s: bad insert point %d\n", __FUNCTION__,where);
+			return;
+	}
+
+	if (rq_mergeable(rq)) {
+		cfq_add_crq_hash(cfqd, crq);
+
+		if (!q->last_merge)
+			q->last_merge = rq;
+	}
+}
+
+static int cfq_queue_empty(request_queue_t *q)
+{
+	struct cfq_data *cfqd = q->elevator.elevator_data;
+
+	if (list_empty(cfqd->dispatch) && list_empty(&cfqd->rr_list))
+		return 1;
+
+	return 0;
+}
+
+static struct request *
+cfq_former_request(request_queue_t *q, struct request *rq)
+{
+	struct cfq_rq *crq = RQ_DATA(rq);
+	struct rb_node *rbprev = rb_prev(&crq->rb_node);
+
+	if (rbprev)
+		return rb_entry_crq(rbprev)->request;
+
+	return NULL;
+}
+
+static struct request *
+cfq_latter_request(request_queue_t *q, struct request *rq)
+{
+	struct cfq_rq *crq = RQ_DATA(rq);
+	struct rb_node *rbnext = rb_next(&crq->rb_node);
+
+	if (rbnext)
+		return rb_entry_crq(rbnext)->request;
+
+	return NULL;
+}
+
+static int cfq_may_queue(request_queue_t *q, int rw)
+{
+	struct cfq_data *cfqd = q->elevator.elevator_data;
+	struct cfq_queue *cfqq;
+	int ret = 1;
+
+	if (!cfqd->busy_queues)
+		goto out;
+
+	cfqq = cfq_find_cfq_hash(cfqd, current->tgid);
+	if (cfqq) {
+		int limit = (q->nr_requests - cfq_queued) / cfqd->busy_queues;
+
+		if (limit < 3)
+			limit = 3;
+		else if (limit > cfqd->max_queued)
+			limit = cfqd->max_queued;
+
+		if (cfqq->queued[rw] > limit)
+			ret = 0;
+	}
+out:
+	return ret;
+}
+
+static void cfq_put_request(request_queue_t *q, struct request *rq)
+{
+	struct cfq_data *cfqd = q->elevator.elevator_data;
+	struct cfq_rq *crq = RQ_DATA(rq);
+
+	if (crq) {
+		BUG_ON(q->last_merge == rq);
+		BUG_ON(ON_MHASH(crq));
+
+		mempool_free(crq, cfqd->crq_pool);
+		rq->elevator_private = NULL;
+	}
+}
+
+static int cfq_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+{
+	struct cfq_data *cfqd = q->elevator.elevator_data;
+	struct cfq_rq *crq = mempool_alloc(cfqd->crq_pool, gfp_mask);
+
+	if (crq) {
+		RB_CLEAR(&crq->rb_node);
+		crq->request = rq;
+		crq->cfq_queue = NULL;
+		INIT_LIST_HEAD(&crq->hash);
+		rq->elevator_private = crq;
+		return 0;
+	}
+
+	return 1;
+}
+
+static void cfq_exit(request_queue_t *q, elevator_t *e)
+{
+	struct cfq_data *cfqd = e->elevator_data;
+
+	e->elevator_data = NULL;
+	mempool_destroy(cfqd->crq_pool);
+	kfree(cfqd->crq_hash);
+	kfree(cfqd->cfq_hash);
+	kfree(cfqd);
+}
+
+static int cfq_init(request_queue_t *q, elevator_t *e)
+{
+	struct cfq_data *cfqd;
+	int i;
+
+	cfqd = kmalloc(sizeof(*cfqd), GFP_KERNEL);
+	if (!cfqd)
+		return -ENOMEM;
+
+	memset(cfqd, 0, sizeof(*cfqd));
+	INIT_LIST_HEAD(&cfqd->rr_list);
+
+	cfqd->crq_hash = kmalloc(sizeof(struct list_head) * CFQ_MHASH_ENTRIES, GFP_KERNEL);
+	if (!cfqd->crq_hash)
+		goto out_crqhash;
+
+	cfqd->cfq_hash = kmalloc(sizeof(struct list_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL);
+	if (!cfqd->cfq_hash)
+		goto out_cfqhash;
+
+	cfqd->crq_pool = mempool_create(BLKDEV_MIN_RQ, mempool_alloc_slab, mempool_free_slab, crq_pool);
+	if (!cfqd->crq_pool)
+		goto out_crqpool;
+
+	for (i = 0; i < CFQ_MHASH_ENTRIES; i++)
+		INIT_LIST_HEAD(&cfqd->crq_hash[i]);
+	for (i = 0; i < CFQ_QHASH_ENTRIES; i++)
+		INIT_LIST_HEAD(&cfqd->cfq_hash[i]);
+
+	cfqd->dispatch = &q->queue_head;
+	e->elevator_data = cfqd;
+
+	/*
+	 * just set it to some high value, we want anyone to be able to queue
+	 * some requests. fairness is handled differently
+	 */
+	cfqd->max_queued = q->nr_requests;
+	q->nr_requests = 8192;
+
+	return 0;
+out_crqpool:
+	kfree(cfqd->cfq_hash);
+out_cfqhash:
+	kfree(cfqd->crq_hash);
+out_crqhash:
+	kfree(cfqd);
+	return -ENOMEM;
+}
+
+static int __init cfq_slab_setup(void)
+{
+	crq_pool = kmem_cache_create("crq_pool", sizeof(struct cfq_rq), 0, 0,
+					NULL, NULL);
+
+	if (!crq_pool)
+		panic("cfq_iosched: can't init crq pool\n");
+
+	cfq_pool = kmem_cache_create("cfq_pool", sizeof(struct cfq_queue), 0, 0,
+					NULL, NULL);
+
+	if (!cfq_pool)
+		panic("cfq_iosched: can't init cfq pool\n");
+
+	cfq_mpool = mempool_create(64, mempool_alloc_slab, mempool_free_slab, cfq_pool);
+
+	if (!cfq_mpool)
+		panic("cfq_iosched: can't init cfq mpool\n");
+
+	return 0;
+}
+
+subsys_initcall(cfq_slab_setup);
+
+elevator_t iosched_cfq = {
+	.elevator_name =		"cfq",
+	.elevator_merge_fn = 		cfq_merge,
+	.elevator_merged_fn =		cfq_merged_request,
+	.elevator_merge_req_fn =	cfq_merged_requests,
+	.elevator_next_req_fn =		cfq_next_request,
+	.elevator_add_req_fn =		cfq_insert_request,
+	.elevator_remove_req_fn =	cfq_remove_request,
+	.elevator_queue_empty_fn =	cfq_queue_empty,
+	.elevator_former_req_fn =	cfq_former_request,
+	.elevator_latter_req_fn =	cfq_latter_request,
+	.elevator_set_req_fn =		cfq_set_request,
+	.elevator_put_req_fn =		cfq_put_request,
+	.elevator_may_queue_fn =	cfq_may_queue,
+	.elevator_init_fn =		cfq_init,
+	.elevator_exit_fn =		cfq_exit,
+};
+
+EXPORT_SYMBOL(iosched_cfq);
--- diff/drivers/cdrom/viocd.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/cdrom/viocd.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,656 @@
+/* -*- linux-c -*-
+ *  drivers/cdrom/viocd.c
+ *
+ *  iSeries Virtual CD Rom
+ *
+ *  Authors: Dave Boutcher <boutcher@us.ibm.com>
+ *           Ryan Arnold <ryanarn@us.ibm.com>
+ *           Colin Devilbiss <devilbis@us.ibm.com>
+ *           Stephen Rothwell <sfr@au1.ibm.com>
+ *
+ * (C) Copyright 2000-2004 IBM Corporation
+ *
+ * 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) anyu later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * This routine provides access to CD ROM drives owned and managed by an
+ * OS/400 partition running on the same box as this Linux partition.
+ *
+ * All operations are performed by sending messages back and forth to
+ * the OS/400 partition.
+ */
+
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <linux/cdrom.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+
+#include <asm/bug.h>
+
+#include <asm/scatterlist.h>
+#include <asm/iSeries/HvTypes.h>
+#include <asm/iSeries/HvLpEvent.h>
+#include <asm/iSeries/vio.h>
+
+#define VIOCD_DEVICE			"iseries/vcd"
+#define VIOCD_DEVICE_DEVFS		"iseries/vcd"
+
+#define VIOCD_VERS "1.06"
+
+#define VIOCD_KERN_WARNING		KERN_WARNING "viocd: "
+#define VIOCD_KERN_INFO			KERN_INFO "viocd: "
+
+struct viocdlpevent {
+	struct HvLpEvent	event;
+	u32			reserved;
+	u16			version;
+	u16			sub_result;
+	u16			disk;
+	u16			flags;
+	u32			token;
+	u64			offset;		/* On open, max number of disks */
+	u64			len;		/* On open, size of the disk */
+	u32			block_size;	/* Only set on open */
+	u32			media_size;	/* Only set on open */
+};
+
+enum viocdsubtype {
+	viocdopen = 0x0001,
+	viocdclose = 0x0002,
+	viocdread = 0x0003,
+	viocdwrite = 0x0004,
+	viocdlockdoor = 0x0005,
+	viocdgetinfo = 0x0006,
+	viocdcheck = 0x0007
+};
+
+/*
+ * Should probably make this a module parameter....sigh
+ */
+#define VIOCD_MAX_CD 8
+
+static const struct vio_error_entry viocd_err_table[] = {
+	{0x0201, EINVAL, "Invalid Range"},
+	{0x0202, EINVAL, "Invalid Token"},
+	{0x0203, EIO, "DMA Error"},
+	{0x0204, EIO, "Use Error"},
+	{0x0205, EIO, "Release Error"},
+	{0x0206, EINVAL, "Invalid CD"},
+	{0x020C, EROFS, "Read Only Device"},
+	{0x020D, ENOMEDIUM, "Changed or Missing Volume (or Varied Off?)"},
+	{0x020E, EIO, "Optical System Error (Varied Off?)"},
+	{0x02FF, EIO, "Internal Error"},
+	{0x3010, EIO, "Changed Volume"},
+	{0xC100, EIO, "Optical System Error"},
+	{0x0000, 0, NULL},
+};
+
+/*
+ * This is the structure we use to exchange info between driver and interrupt
+ * handler
+ */
+struct viocd_waitevent {
+	struct completion	com;
+	int			rc;
+	u16			sub_result;
+	int			changed;
+};
+
+/* this is a lookup table for the true capabilities of a device */
+struct capability_entry {
+	char	*type;
+	int	capability;
+};
+
+static struct capability_entry capability_table[] __initdata = {
+	{ "6330", CDC_LOCK | CDC_DVD_RAM },
+	{ "6321", CDC_LOCK },
+	{ "632B", 0 },
+	{ NULL  , CDC_LOCK },
+};
+
+/* These are our internal structures for keeping track of devices */
+static int viocd_numdev;
+
+struct cdrom_info {
+	char	rsrcname[10];
+	char	type[4];
+	char	model[3];
+};
+static struct cdrom_info viocd_unitinfo[VIOCD_MAX_CD];
+
+struct disk_info {
+	struct gendisk			*viocd_disk;
+	struct cdrom_device_info	viocd_info;
+};
+static struct disk_info viocd_diskinfo[VIOCD_MAX_CD];
+
+#define DEVICE_NR(di)	((di) - &viocd_diskinfo[0])
+#define VIOCDI		viocd_diskinfo[deviceno].viocd_info
+
+static request_queue_t *viocd_queue;
+static spinlock_t viocd_reqlock;
+
+#define MAX_CD_REQ	1
+
+static int viocd_blk_open(struct inode *inode, struct file *file)
+{
+	struct disk_info *di = inode->i_bdev->bd_disk->private_data;
+	return cdrom_open(&di->viocd_info, inode, file);
+}
+
+static int viocd_blk_release(struct inode *inode, struct file *file)
+{
+	struct disk_info *di = inode->i_bdev->bd_disk->private_data;
+	return cdrom_release(&di->viocd_info, file);
+}
+
+static int viocd_blk_ioctl(struct inode *inode, struct file *file,
+		unsigned cmd, unsigned long arg)
+{
+	struct disk_info *di = inode->i_bdev->bd_disk->private_data;
+	return cdrom_ioctl(&di->viocd_info, inode, cmd, arg);
+}
+
+static int viocd_blk_media_changed(struct gendisk *disk)
+{
+	struct disk_info *di = disk->private_data;
+	return cdrom_media_changed(&di->viocd_info);
+}
+
+struct block_device_operations viocd_fops = {
+	.owner =		THIS_MODULE,
+	.open =			viocd_blk_open,
+	.release =		viocd_blk_release,
+	.ioctl =		viocd_blk_ioctl,
+	.media_changed =	viocd_blk_media_changed,
+};
+
+/* Get info on CD devices from OS/400 */
+static void __init get_viocd_info(void)
+{
+	dma_addr_t dmaaddr;
+	HvLpEvent_Rc hvrc;
+	int i;
+	struct viocd_waitevent we;
+
+	dmaaddr = dma_map_single(iSeries_vio_dev, viocd_unitinfo,
+			sizeof(viocd_unitinfo), DMA_FROM_DEVICE);
+	if (dmaaddr == (dma_addr_t)-1) {
+		printk(VIOCD_KERN_WARNING "error allocating tce\n");
+		return;
+	}
+
+	init_completion(&we.com);
+
+	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+			HvLpEvent_Type_VirtualIo,
+			viomajorsubtype_cdio | viocdgetinfo,
+			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
+			viopath_sourceinst(viopath_hostLp),
+			viopath_targetinst(viopath_hostLp),
+			(u64)&we, VIOVERSION << 16, dmaaddr, 0,
+			sizeof(viocd_unitinfo), 0);
+	if (hvrc != HvLpEvent_Rc_Good) {
+		printk(VIOCD_KERN_WARNING "cdrom error sending event. rc %d\n",
+				(int)hvrc);
+		return;
+	}
+
+	wait_for_completion(&we.com);
+
+	dma_unmap_single(iSeries_vio_dev, dmaaddr, sizeof(viocd_unitinfo),
+			DMA_FROM_DEVICE);
+
+	if (we.rc) {
+		const struct vio_error_entry *err =
+			vio_lookup_rc(viocd_err_table, we.sub_result);
+		printk(VIOCD_KERN_WARNING "bad rc %d:0x%04X on getinfo: %s\n",
+				we.rc, we.sub_result, err->msg);
+		return;
+	}
+
+	for (i = 0; (i < VIOCD_MAX_CD) && viocd_unitinfo[i].rsrcname[0]; i++)
+		viocd_numdev++;
+}
+
+static int viocd_open(struct cdrom_device_info *cdi, int purpose)
+{
+        struct disk_info *diskinfo = cdi->handle;
+	int device_no = DEVICE_NR(diskinfo);
+	HvLpEvent_Rc hvrc;
+	struct viocd_waitevent we;
+
+	init_completion(&we.com);
+	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+			HvLpEvent_Type_VirtualIo,
+			viomajorsubtype_cdio | viocdopen,
+			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
+			viopath_sourceinst(viopath_hostLp),
+			viopath_targetinst(viopath_hostLp),
+			(u64)&we, VIOVERSION << 16, ((u64)device_no << 48),
+			0, 0, 0);
+	if (hvrc != 0) {
+		printk(VIOCD_KERN_WARNING
+				"bad rc on HvCallEvent_signalLpEventFast %d\n",
+				(int)hvrc);
+		return -EIO;
+	}
+
+	wait_for_completion(&we.com);
+
+	if (we.rc) {
+		const struct vio_error_entry *err =
+			vio_lookup_rc(viocd_err_table, we.sub_result);
+		printk(VIOCD_KERN_WARNING "bad rc %d:0x%04X on open: %s\n",
+				we.rc, we.sub_result, err->msg);
+		return -err->errno;
+	}
+
+	return 0;
+}
+
+static void viocd_release(struct cdrom_device_info *cdi)
+{
+	int device_no = DEVICE_NR((struct disk_info *)cdi->handle);
+	HvLpEvent_Rc hvrc;
+
+	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+			HvLpEvent_Type_VirtualIo,
+			viomajorsubtype_cdio | viocdclose,
+			HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck,
+			viopath_sourceinst(viopath_hostLp),
+			viopath_targetinst(viopath_hostLp), 0,
+			VIOVERSION << 16, ((u64)device_no << 48), 0, 0, 0);
+	if (hvrc != 0)
+		printk(VIOCD_KERN_WARNING
+				"bad rc on HvCallEvent_signalLpEventFast %d\n",
+				(int)hvrc);
+}
+
+/* Send a read or write request to OS/400 */
+static int send_request(struct request *req)
+{
+	HvLpEvent_Rc hvrc;
+	struct disk_info *diskinfo = req->rq_disk->private_data;
+	u64 len;
+	dma_addr_t dmaaddr;
+	struct scatterlist sg;
+
+	BUG_ON(req->nr_phys_segments > 1);
+	BUG_ON(rq_data_dir(req) != READ);
+
+        if (blk_rq_map_sg(req->q, req, &sg) == 0) {
+		printk(VIOCD_KERN_WARNING
+				"error setting up scatter/gather list\n");
+		return -1;
+	}
+
+	if (dma_map_sg(iSeries_vio_dev, &sg, 1, DMA_FROM_DEVICE) == 0) {
+		printk(VIOCD_KERN_WARNING "error allocating sg tce\n");
+		return -1;
+	}
+	dmaaddr = sg_dma_address(&sg);
+	len = sg_dma_len(&sg);
+	if (dmaaddr == (dma_addr_t)-1) {
+		printk(VIOCD_KERN_WARNING "error allocating tce\n");
+		return -1;
+	}
+
+	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+			HvLpEvent_Type_VirtualIo,
+			viomajorsubtype_cdio | viocdread,
+			HvLpEvent_AckInd_DoAck,
+			HvLpEvent_AckType_ImmediateAck,
+			viopath_sourceinst(viopath_hostLp),
+			viopath_targetinst(viopath_hostLp),
+			(u64)req, VIOVERSION << 16,
+			((u64)DEVICE_NR(diskinfo) << 48) | dmaaddr,
+			(u64)req->sector * 512, len, 0);
+	if (hvrc != HvLpEvent_Rc_Good) {
+		printk(VIOCD_KERN_WARNING "hv error on op %d\n", (int)hvrc);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int rwreq;
+
+static void do_viocd_request(request_queue_t *q)
+{
+	struct request *req;
+
+	while ((rwreq == 0) && ((req = elv_next_request(q)) != NULL)) {
+		/* check for any kind of error */
+		if (send_request(req) < 0) {
+			printk(VIOCD_KERN_WARNING
+					"unable to send message to OS/400!");
+			end_request(req, 0);
+		} else
+			rwreq++;
+	}
+}
+
+static int viocd_media_changed(struct cdrom_device_info *cdi, int disc_nr)
+{
+	struct viocd_waitevent we;
+	HvLpEvent_Rc hvrc;
+	int device_no = DEVICE_NR((struct disk_info *)cdi->handle);
+
+	init_completion(&we.com);
+
+	/* Send the open event to OS/400 */
+	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+			HvLpEvent_Type_VirtualIo,
+			viomajorsubtype_cdio | viocdcheck,
+			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
+			viopath_sourceinst(viopath_hostLp),
+			viopath_targetinst(viopath_hostLp),
+			(u64)&we, VIOVERSION << 16, ((u64)device_no << 48),
+			0, 0, 0);
+	if (hvrc != 0) {
+		printk(VIOCD_KERN_WARNING "bad rc on HvCallEvent_signalLpEventFast %d\n",
+				(int)hvrc);
+		return -EIO;
+	}
+
+	wait_for_completion(&we.com);
+
+	/* Check the return code.  If bad, assume no change */
+	if (we.rc) {
+		const struct vio_error_entry *err =
+			vio_lookup_rc(viocd_err_table, we.sub_result);
+		printk(VIOCD_KERN_WARNING
+				"bad rc %d:0x%04X on check_change: %s; Assuming no change\n",
+				we.rc, we.sub_result, err->msg);
+		return 0;
+	}
+
+	return we.changed;
+}
+
+static int viocd_lock_door(struct cdrom_device_info *cdi, int locking)
+{
+	HvLpEvent_Rc hvrc;
+	u64 device_no = DEVICE_NR((struct disk_info *)cdi->handle);
+	/* NOTE: flags is 1 or 0 so it won't overwrite the device_no */
+	u64 flags = !!locking;
+	struct viocd_waitevent we;
+
+	init_completion(&we.com);
+
+	/* Send the lockdoor event to OS/400 */
+	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+			HvLpEvent_Type_VirtualIo,
+			viomajorsubtype_cdio | viocdlockdoor,
+			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
+			viopath_sourceinst(viopath_hostLp),
+			viopath_targetinst(viopath_hostLp),
+			(u64)&we, VIOVERSION << 16,
+			(device_no << 48) | (flags << 32), 0, 0, 0);
+	if (hvrc != 0) {
+		printk(VIOCD_KERN_WARNING "bad rc on HvCallEvent_signalLpEventFast %d\n",
+				(int)hvrc);
+		return -EIO;
+	}
+
+	wait_for_completion(&we.com);
+
+	if (we.rc != 0)
+		return -EIO;
+	return 0;
+}
+
+/* This routine handles incoming CD LP events */
+static void vio_handle_cd_event(struct HvLpEvent *event)
+{
+	struct viocdlpevent *bevent;
+	struct viocd_waitevent *pwe;
+	struct disk_info *di;
+	unsigned long flags;
+	struct request *req;
+
+
+	if (event == NULL)
+		/* Notification that a partition went away! */
+		return;
+	/* First, we should NEVER get an int here...only acks */
+	if (event->xFlags.xFunction == HvLpEvent_Function_Int) {
+		printk(VIOCD_KERN_WARNING
+				"Yikes! got an int in viocd event handler!\n");
+		if (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck) {
+			event->xRc = HvLpEvent_Rc_InvalidSubtype;
+			HvCallEvent_ackLpEvent(event);
+		}
+	}
+
+	bevent = (struct viocdlpevent *)event;
+
+	switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
+	case viocdopen:
+		if (event->xRc == 0) {
+			di = &viocd_diskinfo[bevent->disk];
+			blk_queue_hardsect_size(viocd_queue,
+					bevent->block_size);
+			set_capacity(di->viocd_disk,
+					bevent->media_size *
+					bevent->block_size / 512);
+		}
+		/* FALLTHROUGH !! */
+	case viocdgetinfo:
+	case viocdlockdoor:
+		pwe = (struct viocd_waitevent *)event->xCorrelationToken;
+return_complete:
+		pwe->rc = event->xRc;
+		pwe->sub_result = bevent->sub_result;
+		complete(&pwe->com);
+		break;
+
+	case viocdcheck:
+		pwe = (struct viocd_waitevent *)event->xCorrelationToken;
+		pwe->changed = bevent->flags;
+		goto return_complete;
+
+	case viocdclose:
+		break;
+
+	case viocdread:
+		/*
+		 * Since this is running in interrupt mode, we need to
+		 * make sure we're not stepping on any global I/O operations
+		 */
+		spin_lock_irqsave(&viocd_reqlock, flags);
+		dma_unmap_single(iSeries_vio_dev, bevent->token, bevent->len,
+				DMA_FROM_DEVICE);
+		req = (struct request *)bevent->event.xCorrelationToken;
+		rwreq--;
+
+		if (event->xRc != HvLpEvent_Rc_Good) {
+			const struct vio_error_entry *err =
+				vio_lookup_rc(viocd_err_table,
+						bevent->sub_result);
+			printk(VIOCD_KERN_WARNING "request %p failed "
+					"with rc %d:0x%04X: %s\n",
+					req, event->xRc,
+					bevent->sub_result, err->msg);
+			end_request(req, 0);
+		} else
+			end_request(req, 1);
+
+		/* restart handling of incoming requests */
+		spin_unlock_irqrestore(&viocd_reqlock, flags);
+		blk_run_queue(viocd_queue);
+		break;
+
+	default:
+		printk(VIOCD_KERN_WARNING
+				"message with invalid subtype %0x04X!\n",
+				event->xSubtype & VIOMINOR_SUBTYPE_MASK);
+		if (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck) {
+			event->xRc = HvLpEvent_Rc_InvalidSubtype;
+			HvCallEvent_ackLpEvent(event);
+		}
+	}
+}
+
+static struct cdrom_device_ops viocd_dops = {
+	.open = viocd_open,
+	.release = viocd_release,
+	.media_changed = viocd_media_changed,
+	.lock_door = viocd_lock_door,
+	.capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM
+};
+
+static int __init find_capability(const char *type)
+{
+	struct capability_entry *entry;
+
+	for(entry = capability_table; entry->type; ++entry)
+		if(!strncmp(entry->type, type, 4))
+			break;
+	return entry->capability;
+}
+
+static int __init viocd_init(void)
+{
+	struct gendisk *gendisk;
+	int deviceno;
+	int ret = 0;
+
+	if (viopath_hostLp == HvLpIndexInvalid) {
+		vio_set_hostlp();
+		/* If we don't have a host, bail out */
+		if (viopath_hostLp == HvLpIndexInvalid)
+			return -ENODEV;
+	}
+
+	printk(VIOCD_KERN_INFO "vers " VIOCD_VERS ", hosting partition %d\n",
+			viopath_hostLp);
+
+	if (register_blkdev(VIOCD_MAJOR, VIOCD_DEVICE) != 0) {
+		printk(VIOCD_KERN_WARNING
+				"Unable to get major %d for %s\n",
+				VIOCD_MAJOR, VIOCD_DEVICE);
+		return -EIO;
+	}
+
+	ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio,
+			MAX_CD_REQ + 2);
+	if (ret) {
+		printk(VIOCD_KERN_WARNING
+				"error opening path to host partition %d\n",
+				viopath_hostLp);
+		goto out_unregister;
+	}
+
+	/* Initialize our request handler */
+	vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event);
+
+	get_viocd_info();
+	if (viocd_numdev == 0)
+		goto out_undo_vio;
+
+	ret = -ENOMEM;
+	spin_lock_init(&viocd_reqlock);
+	viocd_queue = blk_init_queue(do_viocd_request, &viocd_reqlock);
+	if (viocd_queue == NULL)
+		goto out_unregister;
+	blk_queue_max_hw_segments(viocd_queue, 1);
+	blk_queue_max_phys_segments(viocd_queue, 1);
+	blk_queue_max_sectors(viocd_queue, 4096 / 512);
+
+	/* initialize units */
+	for (deviceno = 0; deviceno < viocd_numdev; deviceno++) {
+		struct disk_info *d = &viocd_diskinfo[deviceno];
+		struct cdrom_device_info *c = &d->viocd_info;
+		struct cdrom_info *ci = &viocd_unitinfo[deviceno];
+
+		c->ops = &viocd_dops;
+		c->speed = 4;
+		c->capacity = 1;
+		c->handle = d;
+		c->mask = ~find_capability(ci->type);
+		sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno);
+
+		if (register_cdrom(c) != 0) {
+			printk(VIOCD_KERN_WARNING
+					"Cannot register viocd CD-ROM %s!\n",
+					c->name);
+			continue;
+		}
+		printk(VIOCD_KERN_INFO "cd %s is iSeries resource %10.10s "
+				"type %4.4s, model %3.3s\n",
+				c->name, ci->rsrcname, ci->type, ci->model);
+		gendisk = alloc_disk(1);
+		if (gendisk == NULL) {
+			printk(VIOCD_KERN_WARNING
+					"Cannot create gendisk for %s!\n",
+					c->name);
+			unregister_cdrom(&VIOCDI);
+			continue;
+		}
+		gendisk->major = VIOCD_MAJOR;
+		gendisk->first_minor = deviceno;
+		strncpy(gendisk->disk_name, c->name,
+				sizeof(gendisk->disk_name));
+		snprintf(gendisk->devfs_name, sizeof(gendisk->devfs_name),
+				VIOCD_DEVICE_DEVFS "%d", deviceno);
+		gendisk->queue = viocd_queue;
+		gendisk->fops = &viocd_fops;
+		gendisk->flags = GENHD_FL_CD;
+		set_capacity(gendisk, 0);
+		gendisk->private_data = d;
+		d->viocd_disk = gendisk;
+		add_disk(gendisk);
+	}
+
+	return 0;
+
+out_undo_vio:
+	vio_clearHandler(viomajorsubtype_cdio);
+	viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2);
+out_unregister:
+	unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE);
+	return ret;
+}
+
+static void __exit viocd_exit(void)
+{
+	int deviceno;
+
+	for (deviceno = 0; deviceno < viocd_numdev; deviceno++) {
+		struct disk_info *d = &viocd_diskinfo[deviceno];
+		if (unregister_cdrom(&d->viocd_info) != 0)
+			printk(VIOCD_KERN_WARNING
+					"Cannot unregister viocd CD-ROM %s!\n",
+					d->viocd_info.name);
+		del_gendisk(d->viocd_disk);
+		put_disk(d->viocd_disk);
+	}
+	blk_cleanup_queue(viocd_queue);
+
+	viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2);
+	vio_clearHandler(viomajorsubtype_cdio);
+	unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE);
+}
+
+module_init(viocd_init);
+module_exit(viocd_exit);
+MODULE_LICENSE("GPL");
--- diff/drivers/char/drm/drm_irq.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/char/drm/drm_irq.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,377 @@
+/**
+ * \file drm_irq.h 
+ * IRQ support
+ *
+ * \author Rickard E. (Rik) Faith <faith@valinux.com>
+ * \author Gareth Hughes <gareth@valinux.com>
+ */
+
+/*
+ * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com
+ *
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "drmP.h"
+
+#include <linux/interrupt.h>	/* For task queue support */
+
+#ifndef __HAVE_SHARED_IRQ
+#define __HAVE_SHARED_IRQ	0
+#endif
+
+#if __HAVE_SHARED_IRQ
+#define DRM_IRQ_TYPE		SA_SHIRQ
+#else
+#define DRM_IRQ_TYPE		0
+#endif
+
+/**
+ * Get interrupt from bus id.
+ * 
+ * \param inode device inode.
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument, pointing to a drm_irq_busid structure.
+ * \return zero on success or a negative number on failure.
+ * 
+ * Finds the PCI device with the specified bus id and gets its IRQ number.
+ * This IOCTL is deprecated, and will now return EINVAL for any busid not equal
+ * to that of the device that this DRM instance attached to.
+ */
+int DRM(irq_by_busid)(struct inode *inode, struct file *filp,
+		   unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_irq_busid_t p;
+
+	if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p)))
+		return -EFAULT;
+
+	if ((p.busnum >> 8) != dev->pci_domain ||
+	    (p.busnum & 0xff) != dev->pci_bus ||
+	    p.devnum != dev->pci_slot ||
+	    p.funcnum != dev->pci_func)
+		return -EINVAL;
+
+	p.irq = dev->irq;
+
+	DRM_DEBUG("%d:%d:%d => IRQ %d\n",
+		  p.busnum, p.devnum, p.funcnum, p.irq);
+	if (copy_to_user((drm_irq_busid_t *)arg, &p, sizeof(p)))
+		return -EFAULT;
+	return 0;
+}
+
+#if __HAVE_IRQ
+
+/**
+ * Install IRQ handler.
+ *
+ * \param dev DRM device.
+ * \param irq IRQ number.
+ *
+ * Initializes the IRQ related data, and setups drm_device::vbl_queue. Installs the handler, calling the driver
+ * \c DRM(driver_irq_preinstall)() and \c DRM(driver_irq_postinstall)() functions
+ * before and after the installation.
+ */
+int DRM(irq_install)( drm_device_t *dev )
+{
+	int ret;
+ 
+	if ( dev->irq == 0 )
+		return -EINVAL;
+
+	down( &dev->struct_sem );
+
+	/* Driver must have been initialized */
+	if ( !dev->dev_private ) {
+		up( &dev->struct_sem );
+		return -EINVAL;
+	}
+
+	if ( dev->irq_enabled ) {
+		up( &dev->struct_sem );
+		return -EBUSY;
+	}
+	dev->irq_enabled = 1;
+	up( &dev->struct_sem );
+
+	DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
+
+#if 0 /* this is already done in DRM(setup) - why do it here ?? */
+	dev->context_flag = 0;
+	dev->interrupt_flag = 0;
+	dev->dma_flag = 0;
+#endif
+
+#if __HAVE_DMA
+	dev->dma->next_buffer = NULL;
+	dev->dma->next_queue = NULL;
+	dev->dma->this_buffer = NULL;
+#endif
+
+#if __HAVE_IRQ_BH
+	INIT_WORK(&dev->work, DRM(irq_immediate_bh), dev);
+#endif
+
+#if __HAVE_VBL_IRQ
+	init_waitqueue_head(&dev->vbl_queue);
+
+	spin_lock_init( &dev->vbl_lock );
+
+	INIT_LIST_HEAD( &dev->vbl_sigs.head );
+
+	dev->vbl_pending = 0;
+#endif
+
+				/* Before installing handler */
+	DRM(driver_irq_preinstall)(dev);
+
+				/* Install handler */
+	ret = request_irq( dev->irq, DRM(irq_handler),
+			   DRM_IRQ_TYPE, dev->devname, dev );
+	if ( ret < 0 ) {
+		down( &dev->struct_sem );
+		dev->irq_enabled = 0;
+		up( &dev->struct_sem );
+		return ret;
+	}
+
+				/* After installing handler */
+	DRM(driver_irq_postinstall)(dev);
+
+	return 0;
+}
+
+/**
+ * Uninstall the IRQ handler.
+ *
+ * \param dev DRM device.
+ *
+ * Calls the driver's \c DRM(driver_irq_uninstall)() function, and stops the irq.
+ */
+int DRM(irq_uninstall)( drm_device_t *dev )
+{
+	int irq_enabled;
+
+	down( &dev->struct_sem );
+	irq_enabled = dev->irq_enabled;
+	dev->irq_enabled = 0;
+	up( &dev->struct_sem );
+
+	if ( !irq_enabled )
+		return -EINVAL;
+
+	DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
+
+	DRM(driver_irq_uninstall)( dev );
+
+	free_irq( dev->irq, dev );
+
+	return 0;
+}
+
+/**
+ * IRQ control ioctl.
+ *
+ * \param inode device inode.
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument, pointing to a drm_control structure.
+ * \return zero on success or a negative number on failure.
+ *
+ * Calls irq_install() or irq_uninstall() according to \p arg.
+ */
+int DRM(control)( struct inode *inode, struct file *filp,
+		  unsigned int cmd, unsigned long arg )
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_control_t ctl;
+
+	if ( copy_from_user( &ctl, (drm_control_t *)arg, sizeof(ctl) ) )
+		return -EFAULT;
+
+	switch ( ctl.func ) {
+	case DRM_INST_HANDLER:
+		if (dev->if_version < DRM_IF_VERSION(1, 2) &&
+		    ctl.irq != dev->irq)
+			return -EINVAL;
+		return DRM(irq_install)( dev );
+	case DRM_UNINST_HANDLER:
+		return DRM(irq_uninstall)( dev );
+	default:
+		return -EINVAL;
+	}
+}
+
+#if __HAVE_VBL_IRQ
+
+/**
+ * Wait for VBLANK.
+ *
+ * \param inode device inode.
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param data user argument, pointing to a drm_wait_vblank structure.
+ * \return zero on success or a negative number on failure.
+ *
+ * Verifies the IRQ is installed. 
+ *
+ * If a signal is requested checks if this task has already scheduled the same signal
+ * for the same vblank sequence number - nothing to be done in
+ * that case. If the number of tasks waiting for the interrupt exceeds 100 the
+ * function fails. Otherwise adds a new entry to drm_device::vbl_sigs for this
+ * task.
+ *
+ * If a signal is not requested, then calls vblank_wait().
+ */
+int DRM(wait_vblank)( DRM_IOCTL_ARGS )
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_wait_vblank_t vblwait;
+	struct timeval now;
+	int ret = 0;
+	unsigned int flags;
+
+	if (!dev->irq)
+		return -EINVAL;
+
+	DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data,
+				  sizeof(vblwait) );
+
+	switch ( vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK ) {
+	case _DRM_VBLANK_RELATIVE:
+		vblwait.request.sequence += atomic_read( &dev->vbl_received );
+		vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
+	case _DRM_VBLANK_ABSOLUTE:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
+	
+	if ( flags & _DRM_VBLANK_SIGNAL ) {
+		unsigned long irqflags;
+		drm_vbl_sig_t *vbl_sig;
+		
+		vblwait.reply.sequence = atomic_read( &dev->vbl_received );
+
+		spin_lock_irqsave( &dev->vbl_lock, irqflags );
+
+		/* Check if this task has already scheduled the same signal
+		 * for the same vblank sequence number; nothing to be done in
+		 * that case
+		 */
+		list_for_each_entry( vbl_sig, &dev->vbl_sigs.head, head ) {
+			if (vbl_sig->sequence == vblwait.request.sequence
+			    && vbl_sig->info.si_signo == vblwait.request.signal
+			    && vbl_sig->task == current)
+			{
+				spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
+				goto done;
+			}
+		}
+
+		if ( dev->vbl_pending >= 100 ) {
+			spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
+			return -EBUSY;
+		}
+
+		dev->vbl_pending++;
+
+		spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
+
+		if ( !( vbl_sig = DRM_MALLOC( sizeof( drm_vbl_sig_t ) ) ) ) {
+			return -ENOMEM;
+		}
+
+		memset( (void *)vbl_sig, 0, sizeof(*vbl_sig) );
+
+		vbl_sig->sequence = vblwait.request.sequence;
+		vbl_sig->info.si_signo = vblwait.request.signal;
+		vbl_sig->task = current;
+
+		spin_lock_irqsave( &dev->vbl_lock, irqflags );
+
+		list_add_tail( (struct list_head *) vbl_sig, &dev->vbl_sigs.head );
+
+		spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
+	} else {
+		ret = DRM(vblank_wait)( dev, &vblwait.request.sequence );
+
+		do_gettimeofday( &now );
+		vblwait.reply.tval_sec = now.tv_sec;
+		vblwait.reply.tval_usec = now.tv_usec;
+	}
+
+done:
+	DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait,
+				sizeof(vblwait) );
+
+	return ret;
+}
+
+/**
+ * Send the VBLANK signals.
+ *
+ * \param dev DRM device.
+ *
+ * Sends a signal for each task in drm_device::vbl_sigs and empties the list.
+ *
+ * If a signal is not requested, then calls vblank_wait().
+ */
+void DRM(vbl_send_signals)( drm_device_t *dev )
+{
+	struct list_head *list, *tmp;
+	drm_vbl_sig_t *vbl_sig;
+	unsigned int vbl_seq = atomic_read( &dev->vbl_received );
+	unsigned long flags;
+
+	spin_lock_irqsave( &dev->vbl_lock, flags );
+
+	list_for_each_safe( list, tmp, &dev->vbl_sigs.head ) {
+		vbl_sig = list_entry( list, drm_vbl_sig_t, head );
+		if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) {
+			vbl_sig->info.si_code = vbl_seq;
+			send_sig_info( vbl_sig->info.si_signo, &vbl_sig->info, vbl_sig->task );
+
+			list_del( list );
+
+			DRM_FREE( vbl_sig, sizeof(*vbl_sig) );
+
+			dev->vbl_pending--;
+		}
+	}
+
+	spin_unlock_irqrestore( &dev->vbl_lock, flags );
+}
+
+#endif	/* __HAVE_VBL_IRQ */
+
+#endif /* __HAVE_IRQ */
--- diff/drivers/char/ipmi/ipmi_bt_sm.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/char/ipmi/ipmi_bt_sm.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,515 @@
+/*
+ *  ipmi_bt_sm.c
+ *
+ *  The state machine for an Open IPMI BT sub-driver under ipmi_si.c, part
+ *  of the driver architecture at http://sourceforge.net/project/openipmi
+ *
+ *  Author:	Rocky Craig <first.last@hp.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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/types.h>
+
+#include <linux/kernel.h> /* For printk. */
+#include <linux/string.h>
+#include <linux/ipmi_msgdefs.h>		/* for completion codes */
+#include "ipmi_si_sm.h"
+
+#define IPMI_BT_VERSION "v31"
+
+static int bt_debug = 0x00;	/* Production value 0, see following flags */
+
+#define	BT_DEBUG_ENABLE	1
+#define BT_DEBUG_MSG	2
+#define BT_DEBUG_STATES	4
+
+/* Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds,
+   and 64 byte buffers.  However, one HP implementation wants 255 bytes of
+   buffer (with a documented message of 160 bytes) so go for the max.
+   Since the Open IPMI architecture is single-message oriented at this
+   stage, the queue depth of BT is of no concern. */
+
+#define BT_NORMAL_TIMEOUT	2000000	/* seconds in microseconds */
+#define BT_RETRY_LIMIT		2
+#define BT_RESET_DELAY		6000000	/* 6 seconds after warm reset */
+
+enum bt_states {
+	BT_STATE_IDLE,
+	BT_STATE_XACTION_START,
+	BT_STATE_WRITE_BYTES,
+	BT_STATE_WRITE_END,
+	BT_STATE_WRITE_CONSUME,
+	BT_STATE_B2H_WAIT,
+	BT_STATE_READ_END,
+	BT_STATE_RESET1,		/* These must come last */
+	BT_STATE_RESET2,
+	BT_STATE_RESET3,
+	BT_STATE_RESTART,
+	BT_STATE_HOSED
+};
+
+struct si_sm_data {
+	enum bt_states	state;
+	enum bt_states	last_state;	/* assist printing and resets */
+	unsigned char	seq;		/* BT sequence number */
+	struct si_sm_io	*io;
+        unsigned char	write_data[IPMI_MAX_MSG_LENGTH];
+        int		write_count;
+        unsigned char	read_data[IPMI_MAX_MSG_LENGTH];
+        int		read_count;
+        int		truncated;
+        long		timeout;
+        unsigned int	error_retries;	/* end of "common" fields */
+	int		nonzero_status;	/* hung BMCs stay all 0 */
+};
+
+#define BT_CLR_WR_PTR	0x01	/* See IPMI 1.5 table 11.6.4 */
+#define BT_CLR_RD_PTR	0x02
+#define BT_H2B_ATN	0x04
+#define BT_B2H_ATN	0x08
+#define BT_SMS_ATN	0x10
+#define BT_OEM0		0x20
+#define BT_H_BUSY	0x40
+#define BT_B_BUSY	0x80
+
+/* Some bits are toggled on each write: write once to set it, once
+   more to clear it; writing a zero does nothing.  To absolutely
+   clear it, check its state and write if set.  This avoids the "get
+   current then use as mask" scheme to modify one bit.  Note that the
+   variable "bt" is hardcoded into these macros. */
+
+#define BT_STATUS	bt->io->inputb(bt->io, 0)
+#define BT_CONTROL(x)	bt->io->outputb(bt->io, 0, x)
+
+#define BMC2HOST	bt->io->inputb(bt->io, 1)
+#define HOST2BMC(x)	bt->io->outputb(bt->io, 1, x)
+
+#define BT_INTMASK_R	bt->io->inputb(bt->io, 2)
+#define BT_INTMASK_W(x)	bt->io->outputb(bt->io, 2, x)
+
+/* Convenience routines for debugging.  These are not multi-open safe!
+   Note the macros have hardcoded variables in them. */
+
+static char *state2txt(unsigned char state)
+{
+	switch (state) {
+		case BT_STATE_IDLE:		return("IDLE");
+		case BT_STATE_XACTION_START:	return("XACTION");
+		case BT_STATE_WRITE_BYTES:	return("WR_BYTES");
+		case BT_STATE_WRITE_END:	return("WR_END");
+		case BT_STATE_WRITE_CONSUME:	return("WR_CONSUME");
+		case BT_STATE_B2H_WAIT:		return("B2H_WAIT");
+		case BT_STATE_READ_END:		return("RD_END");
+		case BT_STATE_RESET1:		return("RESET1");
+		case BT_STATE_RESET2:		return("RESET2");
+		case BT_STATE_RESET3:		return("RESET3");
+		case BT_STATE_RESTART:		return("RESTART");
+		case BT_STATE_HOSED:		return("HOSED");
+	}
+	return("BAD STATE");
+}
+#define STATE2TXT state2txt(bt->state)
+
+static char *status2txt(unsigned char status, char *buf)
+{
+	strcpy(buf, "[ ");
+	if (status & BT_B_BUSY) strcat(buf, "B_BUSY ");
+	if (status & BT_H_BUSY) strcat(buf, "H_BUSY ");
+	if (status & BT_OEM0) strcat(buf, "OEM0 ");
+	if (status & BT_SMS_ATN) strcat(buf, "SMS ");
+	if (status & BT_B2H_ATN) strcat(buf, "B2H ");
+	if (status & BT_H2B_ATN) strcat(buf, "H2B ");
+	strcat(buf, "]");
+	return buf;
+}
+#define STATUS2TXT(buf) status2txt(status, buf)
+
+/* This will be called from within this module on a hosed condition */
+#define FIRST_SEQ	0
+static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io)
+{
+	bt->state = BT_STATE_IDLE;
+	bt->last_state = BT_STATE_IDLE;
+	bt->seq = FIRST_SEQ;
+	bt->io = io;
+	bt->write_count = 0;
+	bt->read_count = 0;
+	bt->error_retries = 0;
+	bt->nonzero_status = 0;
+	bt->truncated = 0;
+	bt->timeout = BT_NORMAL_TIMEOUT;
+	return 3; /* We claim 3 bytes of space; ought to check SPMI table */
+}
+
+static int bt_start_transaction(struct si_sm_data *bt,
+				unsigned char *data,
+				unsigned int size)
+{
+	unsigned int i;
+
+	if ((size < 2) || (size > IPMI_MAX_MSG_LENGTH)) return -1;
+
+	if ((bt->state != BT_STATE_IDLE) && (bt->state != BT_STATE_HOSED))
+		return -2;
+
+	if (bt_debug & BT_DEBUG_MSG) {
+    		printk(KERN_WARNING "+++++++++++++++++++++++++++++++++++++\n");
+		printk(KERN_WARNING "BT: write seq=0x%02X:", bt->seq);
+		for (i = 0; i < size; i ++) printk (" %02x", data[i]);
+		printk("\n");
+	}
+	bt->write_data[0] = size + 1;	/* all data plus seq byte */
+	bt->write_data[1] = *data;	/* NetFn/LUN */
+	bt->write_data[2] = bt->seq;
+	memcpy(bt->write_data + 3, data + 1, size - 1);
+	bt->write_count = size + 2;
+
+	bt->error_retries = 0;
+	bt->nonzero_status = 0;
+	bt->read_count = 0;
+	bt->truncated = 0;
+	bt->state = BT_STATE_XACTION_START;
+	bt->last_state = BT_STATE_IDLE;
+	bt->timeout = BT_NORMAL_TIMEOUT;
+	return 0;
+}
+
+/* After the upper state machine has been told SI_SM_TRANSACTION_COMPLETE
+   it calls this.  Strip out the length and seq bytes. */
+
+static int bt_get_result(struct si_sm_data *bt,
+			   unsigned char *data,
+			   unsigned int length)
+{
+	int i, msg_len;
+
+	msg_len = bt->read_count - 2;		/* account for length & seq */
+	/* Always NetFn, Cmd, cCode */
+	if (msg_len < 3 || msg_len > IPMI_MAX_MSG_LENGTH) {
+		printk(KERN_WARNING "BT results: bad msg_len = %d\n", msg_len);
+		data[0] = bt->write_data[1] | 0x4;	/* Kludge a response */
+		data[1] = bt->write_data[3];
+		data[2] = IPMI_ERR_UNSPECIFIED;
+		msg_len = 3;
+	} else {
+		data[0] = bt->read_data[1];
+		data[1] = bt->read_data[3];
+		if (length < msg_len) bt->truncated = 1;
+		if (bt->truncated) {	/* can be set in read_all_bytes() */
+			data[2] = IPMI_ERR_MSG_TRUNCATED;
+			msg_len = 3;
+		} else memcpy(data + 2, bt->read_data + 4, msg_len - 2);
+
+		if (bt_debug & BT_DEBUG_MSG) {
+			printk (KERN_WARNING "BT: res (raw)");
+			for (i = 0; i < msg_len; i++) printk(" %02x", data[i]);
+			printk ("\n");
+		}
+	}
+	bt->read_count = 0;	/* paranoia */
+	return msg_len;
+}
+
+/* This bit's functionality is optional */
+#define BT_BMC_HWRST	0x80
+
+static void reset_flags(struct si_sm_data *bt)
+{
+	if (BT_STATUS & BT_H_BUSY) BT_CONTROL(BT_H_BUSY);
+	if (BT_STATUS & BT_B_BUSY) BT_CONTROL(BT_B_BUSY);
+	BT_CONTROL(BT_CLR_WR_PTR);
+	BT_CONTROL(BT_SMS_ATN);
+	BT_INTMASK_W(BT_BMC_HWRST);
+#ifdef DEVELOPMENT_ONLY_NOT_FOR_PRODUCTION
+	if (BT_STATUS & BT_B2H_ATN) {
+		int i;
+		BT_CONTROL(BT_H_BUSY);
+		BT_CONTROL(BT_B2H_ATN);
+		BT_CONTROL(BT_CLR_RD_PTR);
+		for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++) BMC2HOST;
+		BT_CONTROL(BT_H_BUSY);
+	}
+#endif
+}
+
+static inline void write_all_bytes(struct si_sm_data *bt)
+{
+	int i;
+
+	if (bt_debug & BT_DEBUG_MSG) {
+    		printk(KERN_WARNING "BT: write %d bytes seq=0x%02X",
+			bt->write_count, bt->seq);
+		for (i = 0; i < bt->write_count; i++)
+			printk (" %02x", bt->write_data[i]);
+		printk ("\n");
+	}
+	for (i = 0; i < bt->write_count; i++) HOST2BMC(bt->write_data[i]);
+}
+
+static inline int read_all_bytes(struct si_sm_data *bt)
+{
+	unsigned char i;
+
+	bt->read_data[0] = BMC2HOST;
+	bt->read_count = bt->read_data[0];
+	if (bt_debug & BT_DEBUG_MSG)
+    		printk(KERN_WARNING "BT: read %d bytes:", bt->read_count);
+
+	/* minimum: length, NetFn, Seq, Cmd, cCode == 5 total, or 4 more
+	   following the length byte. */
+	if (bt->read_count < 4 || bt->read_count >= IPMI_MAX_MSG_LENGTH) {
+		if (bt_debug & BT_DEBUG_MSG)
+			printk("bad length %d\n", bt->read_count);
+		bt->truncated = 1;
+		return 1;	/* let next XACTION START clean it up */
+	}
+	for (i = 1; i <= bt->read_count; i++) bt->read_data[i] = BMC2HOST;
+	bt->read_count++;	/* account for the length byte */
+
+	if (bt_debug & BT_DEBUG_MSG) {
+	    	for (i = 0; i < bt->read_count; i++)
+			printk (" %02x", bt->read_data[i]);
+	    	printk ("\n");
+	}
+	if (bt->seq != bt->write_data[2])	/* idiot check */
+		printk(KERN_WARNING "BT: internal error: sequence mismatch\n");
+
+	/* per the spec, the (NetFn, Seq, Cmd) tuples should match */
+	if ((bt->read_data[3] == bt->write_data[3]) &&		/* Cmd */
+        	(bt->read_data[2] == bt->write_data[2]) &&	/* Sequence */
+        	((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8)))
+			return 1;
+
+	if (bt_debug & BT_DEBUG_MSG) printk(KERN_WARNING "BT: bad packet: "
+		"want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n",
+		bt->write_data[1], bt->write_data[2], bt->write_data[3],
+		bt->read_data[1],  bt->read_data[2],  bt->read_data[3]);
+	return 0;
+}
+
+/* Modifies bt->state appropriately, need to get into the bt_event() switch */
+
+static void error_recovery(struct si_sm_data *bt, char *reason)
+{
+	unsigned char status;
+	char buf[40]; /* For getting status */
+
+	bt->timeout = BT_NORMAL_TIMEOUT; /* various places want to retry */
+
+	status = BT_STATUS;
+	printk(KERN_WARNING "BT: %s in %s %s ", reason, STATE2TXT,
+	       STATUS2TXT(buf));
+
+	(bt->error_retries)++;
+	if (bt->error_retries > BT_RETRY_LIMIT) {
+		printk("retry limit (%d) exceeded\n", BT_RETRY_LIMIT);
+		bt->state = BT_STATE_HOSED;
+		if (!bt->nonzero_status)
+			printk(KERN_ERR "IPMI: BT stuck, try power cycle\n");
+		else if (bt->seq == FIRST_SEQ + BT_RETRY_LIMIT) {
+			/* most likely during insmod */
+			printk(KERN_WARNING "IPMI: BT reset (takes 5 secs)\n");
+        		bt->state = BT_STATE_RESET1;
+		}
+	return;
+	}
+
+	/* Sometimes the BMC queues get in an "off-by-one" state...*/
+	if ((bt->state == BT_STATE_B2H_WAIT) && (status & BT_B2H_ATN)) {
+    		printk("retry B2H_WAIT\n");
+		return;
+	}
+
+	printk("restart command\n");
+	bt->state = BT_STATE_RESTART;
+}
+
+/* Check the status and (possibly) advance the BT state machine.  The
+   default return is SI_SM_CALL_WITH_DELAY. */
+
+static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
+{
+	unsigned char status;
+	char buf[40]; /* For getting status */
+	int i;
+
+	status = BT_STATUS;
+	bt->nonzero_status |= status;
+
+	if ((bt_debug & BT_DEBUG_STATES) && (bt->state != bt->last_state))
+		printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n",
+			STATE2TXT,
+			STATUS2TXT(buf),
+			bt->timeout,
+			time);
+	bt->last_state = bt->state;
+
+	if (bt->state == BT_STATE_HOSED) return SI_SM_HOSED;
+
+	if (bt->state != BT_STATE_IDLE) {	/* do timeout test */
+
+		/* Certain states, on error conditions, can lock up a CPU
+		   because they are effectively in an infinite loop with
+		   CALL_WITHOUT_DELAY (right back here with time == 0).
+		   Prevent infinite lockup by ALWAYS decrementing timeout. */
+
+    	/* FIXME: bt_event is sometimes called with time > BT_NORMAL_TIMEOUT
+              (noticed in ipmi_smic_sm.c January 2004) */
+
+		if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT)) time = 100;
+		bt->timeout -= time;
+		if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) {
+			error_recovery(bt, "timed out");
+			return SI_SM_CALL_WITHOUT_DELAY;
+		}
+	}
+
+	switch (bt->state) {
+
+    	case BT_STATE_IDLE:	/* check for asynchronous messages */
+		if (status & BT_SMS_ATN) {
+			BT_CONTROL(BT_SMS_ATN);	/* clear it */
+			return SI_SM_ATTN;
+		}
+		return SI_SM_IDLE;
+
+	case BT_STATE_XACTION_START:
+		if (status & BT_H_BUSY) {
+			BT_CONTROL(BT_H_BUSY);
+			break;
+		}
+    		if (status & BT_B2H_ATN) break;
+		bt->state = BT_STATE_WRITE_BYTES;
+		return SI_SM_CALL_WITHOUT_DELAY;	/* for logging */
+
+	case BT_STATE_WRITE_BYTES:
+		if (status & (BT_B_BUSY | BT_H2B_ATN)) break;
+		BT_CONTROL(BT_CLR_WR_PTR);
+		write_all_bytes(bt);
+		BT_CONTROL(BT_H2B_ATN);	/* clears too fast to catch? */
+		bt->state = BT_STATE_WRITE_CONSUME;
+		return SI_SM_CALL_WITHOUT_DELAY; /* it MIGHT sail through */
+
+	case BT_STATE_WRITE_CONSUME: /* BMCs usually blow right thru here */
+        	if (status & (BT_H2B_ATN | BT_B_BUSY)) break;
+		bt->state = BT_STATE_B2H_WAIT;
+		/* fall through with status */
+
+	/* Stay in BT_STATE_B2H_WAIT until a packet matches.  However, spinning
+	   hard here, constantly reading status, seems to hold off the
+	   generation of B2H_ATN so ALWAYS return CALL_WITH_DELAY. */
+
+	case BT_STATE_B2H_WAIT:
+    		if (!(status & BT_B2H_ATN)) break;
+
+		/* Assume ordered, uncached writes: no need to wait */
+		if (!(status & BT_H_BUSY)) BT_CONTROL(BT_H_BUSY); /* set */
+		BT_CONTROL(BT_B2H_ATN);		/* clear it, ACK to the BMC */
+		BT_CONTROL(BT_CLR_RD_PTR);	/* reset the queue */
+		i = read_all_bytes(bt);
+		BT_CONTROL(BT_H_BUSY);		/* clear */
+		if (!i) break;			/* Try this state again */
+		bt->state = BT_STATE_READ_END;
+		return SI_SM_CALL_WITHOUT_DELAY;	/* for logging */
+
+    	case BT_STATE_READ_END:
+
+		/* I could wait on BT_H_BUSY to go clear for a truly clean
+		   exit.  However, this is already done in XACTION_START
+		   and the (possible) extra loop/status/possible wait affects
+		   performance.  So, as long as it works, just ignore H_BUSY */
+
+#ifdef MAKE_THIS_TRUE_IF_NECESSARY
+
+		if (status & BT_H_BUSY) break;
+#endif
+		bt->seq++;
+		bt->state = BT_STATE_IDLE;
+		return SI_SM_TRANSACTION_COMPLETE;
+
+	case BT_STATE_RESET1:
+    		reset_flags(bt);
+    		bt->timeout = BT_RESET_DELAY;;
+		bt->state = BT_STATE_RESET2;
+		break;
+
+	case BT_STATE_RESET2:		/* Send a soft reset */
+		BT_CONTROL(BT_CLR_WR_PTR);
+		HOST2BMC(3);		/* number of bytes following */
+		HOST2BMC(0x18);		/* NetFn/LUN == Application, LUN 0 */
+		HOST2BMC(42);		/* Sequence number */
+		HOST2BMC(3);		/* Cmd == Soft reset */
+		BT_CONTROL(BT_H2B_ATN);
+		bt->state = BT_STATE_RESET3;
+		break;
+
+	case BT_STATE_RESET3:
+		if (bt->timeout > 0) return SI_SM_CALL_WITH_DELAY;
+		bt->state = BT_STATE_RESTART;	/* printk in debug modes */
+		break;
+
+	case BT_STATE_RESTART:		/* don't reset retries! */
+		bt->write_data[2] = ++bt->seq;
+		bt->read_count = 0;
+		bt->nonzero_status = 0;
+		bt->timeout = BT_NORMAL_TIMEOUT;
+		bt->state = BT_STATE_XACTION_START;
+		break;
+
+	default:	/* HOSED is supposed to be caught much earlier */
+		error_recovery(bt, "internal logic error");
+		break;
+  	}
+  	return SI_SM_CALL_WITH_DELAY;
+}
+
+static int bt_detect(struct si_sm_data *bt)
+{
+	/* It's impossible for the BT status and interrupt registers to be
+	   all 1's, (assuming a properly functioning, self-initialized BMC)
+	   but that's what you get from reading a bogus address, so we
+	   test that first.  The calling routine uses negative logic. */
+
+	if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) return 1;
+	reset_flags(bt);
+	return 0;
+}
+
+static void bt_cleanup(struct si_sm_data *bt)
+{
+}
+
+static int bt_size(void)
+{
+	return sizeof(struct si_sm_data);
+}
+
+struct si_sm_handlers bt_smi_handlers =
+{
+	.version           = IPMI_BT_VERSION,
+	.init_data         = bt_init_data,
+	.start_transaction = bt_start_transaction,
+	.get_result        = bt_get_result,
+	.event             = bt_event,
+	.detect            = bt_detect,
+	.cleanup           = bt_cleanup,
+	.size              = bt_size,
+};
--- diff/drivers/char/ipmi/ipmi_si_intf.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/char/ipmi/ipmi_si_intf.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,2051 @@
+/*
+ * ipmi_si.c
+ *
+ * The interface to the IPMI driver for the system interfaces (KCS, SMIC,
+ * BT).
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ *  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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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 holds the "policy" for the interface to the SMI state
+ * machine.  It does the configuration, handles timers and interrupts,
+ * and drives the real SMI state machine.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <asm/system.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#ifdef CONFIG_HIGH_RES_TIMERS
+#include <linux/hrtime.h>
+# if defined(schedule_next_int)
+/* Old high-res timer code, do translations. */
+#  define get_arch_cycles(a) quick_update_jiffies_sub(a)
+#  define arch_cycles_per_jiffy cycles_per_jiffies
+# endif
+static inline void add_usec_to_timer(struct timer_list *t, long v)
+{
+	t->sub_expires += nsec_to_arch_cycle(v * 1000);
+	while (t->sub_expires >= arch_cycles_per_jiffy)
+	{
+		t->expires++;
+		t->sub_expires -= arch_cycles_per_jiffy;
+	}
+}
+#endif
+#include <linux/interrupt.h>
+#include <linux/rcupdate.h>
+#include <linux/ipmi_smi.h>
+#include <asm/io.h>
+#include "ipmi_si_sm.h"
+#include <linux/init.h>
+
+#define IPMI_SI_VERSION "v31"
+
+/* Measure times between events in the driver. */
+#undef DEBUG_TIMING
+
+/* Call every 10 ms. */
+#define SI_TIMEOUT_TIME_USEC	10000
+#define SI_USEC_PER_JIFFY	(1000000/HZ)
+#define SI_TIMEOUT_JIFFIES	(SI_TIMEOUT_TIME_USEC/SI_USEC_PER_JIFFY)
+#define SI_SHORT_TIMEOUT_USEC  250 /* .25ms when the SM request a
+                                       short timeout */
+
+enum si_intf_state {
+	SI_NORMAL,
+	SI_GETTING_FLAGS,
+	SI_GETTING_EVENTS,
+	SI_CLEARING_FLAGS,
+	SI_CLEARING_FLAGS_THEN_SET_IRQ,
+	SI_GETTING_MESSAGES,
+	SI_ENABLE_INTERRUPTS1,
+	SI_ENABLE_INTERRUPTS2
+	/* FIXME - add watchdog stuff. */
+};
+
+enum si_type {
+    SI_KCS, SI_SMIC, SI_BT
+};
+
+struct smi_info
+{
+	ipmi_smi_t             intf;
+	struct si_sm_data      *si_sm;
+	struct si_sm_handlers  *handlers;
+	enum si_type           si_type;
+	spinlock_t             si_lock;
+	spinlock_t             msg_lock;
+	struct list_head       xmit_msgs;
+	struct list_head       hp_xmit_msgs;
+	struct ipmi_smi_msg    *curr_msg;
+	enum si_intf_state     si_state;
+
+	/* Used to handle the various types of I/O that can occur with
+           IPMI */
+	struct si_sm_io io;
+	int (*io_setup)(struct smi_info *info);
+	void (*io_cleanup)(struct smi_info *info);
+	int (*irq_setup)(struct smi_info *info);
+	void (*irq_cleanup)(struct smi_info *info);
+	unsigned int io_size;
+
+	/* Flags from the last GET_MSG_FLAGS command, used when an ATTN
+	   is set to hold the flags until we are done handling everything
+	   from the flags. */
+#define RECEIVE_MSG_AVAIL	0x01
+#define EVENT_MSG_BUFFER_FULL	0x02
+#define WDT_PRE_TIMEOUT_INT	0x08
+	unsigned char       msg_flags;
+
+	/* If set to true, this will request events the next time the
+	   state machine is idle. */
+	atomic_t            req_events;
+
+	/* If true, run the state machine to completion on every send
+	   call.  Generally used after a panic to make sure stuff goes
+	   out. */
+	int                 run_to_completion;
+
+	/* The I/O port of an SI interface. */
+	int                 port;
+
+	/* zero if no irq; */
+	int                 irq;
+
+	/* The timer for this si. */
+	struct timer_list   si_timer;
+
+	/* The time (in jiffies) the last timeout occurred at. */
+	unsigned long       last_timeout_jiffies;
+
+	/* Used to gracefully stop the timer without race conditions. */
+	volatile int        stop_operation;
+	volatile int        timer_stopped;
+
+	/* The driver will disable interrupts when it gets into a
+	   situation where it cannot handle messages due to lack of
+	   memory.  Once that situation clears up, it will re-enable
+	   interrupts. */
+	int interrupt_disabled;
+
+	unsigned char ipmi_si_dev_rev;
+	unsigned char ipmi_si_fw_rev_major;
+	unsigned char ipmi_si_fw_rev_minor;
+	unsigned char ipmi_version_major;
+	unsigned char ipmi_version_minor;
+
+	/* Counters and things for the proc filesystem. */
+	spinlock_t count_lock;
+	unsigned long short_timeouts;
+	unsigned long long_timeouts;
+	unsigned long timeout_restarts;
+	unsigned long idles;
+	unsigned long interrupts;
+	unsigned long attentions;
+	unsigned long flag_fetches;
+	unsigned long hosed_count;
+	unsigned long complete_transactions;
+	unsigned long events;
+	unsigned long watchdog_pretimeouts;
+	unsigned long incoming_messages;
+};
+
+static void si_restart_short_timer(struct smi_info *smi_info);
+
+static void deliver_recv_msg(struct smi_info *smi_info,
+			     struct ipmi_smi_msg *msg)
+{
+	/* Deliver the message to the upper layer with the lock
+           released. */
+	spin_unlock(&(smi_info->si_lock));
+	ipmi_smi_msg_received(smi_info->intf, msg);
+	spin_lock(&(smi_info->si_lock));
+}
+
+static void return_hosed_msg(struct smi_info *smi_info)
+{
+	struct ipmi_smi_msg *msg = smi_info->curr_msg;
+
+	/* Make it a reponse */
+	msg->rsp[0] = msg->data[0] | 4;
+	msg->rsp[1] = msg->data[1];
+	msg->rsp[2] = 0xFF; /* Unknown error. */
+	msg->rsp_size = 3;
+
+	smi_info->curr_msg = NULL;
+	deliver_recv_msg(smi_info, msg);
+}
+
+static enum si_sm_result start_next_msg(struct smi_info *smi_info)
+{
+	int              rv;
+	struct list_head *entry = NULL;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+#endif
+
+	/* No need to save flags, we aleady have interrupts off and we
+	   already hold the SMI lock. */
+	spin_lock(&(smi_info->msg_lock));
+
+	/* Pick the high priority queue first. */
+	if (! list_empty(&(smi_info->hp_xmit_msgs))) {
+		entry = smi_info->hp_xmit_msgs.next;
+	} else if (! list_empty(&(smi_info->xmit_msgs))) {
+		entry = smi_info->xmit_msgs.next;
+	}
+
+	if (!entry) {
+		smi_info->curr_msg = NULL;
+		rv = SI_SM_IDLE;
+	} else {
+		int err;
+
+		list_del(entry);
+		smi_info->curr_msg = list_entry(entry,
+						struct ipmi_smi_msg,
+						link);
+#ifdef DEBUG_TIMING
+		do_gettimeofday(&t);
+		printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+		err = smi_info->handlers->start_transaction(
+			smi_info->si_sm,
+			smi_info->curr_msg->data,
+			smi_info->curr_msg->data_size);
+		if (err) {
+			return_hosed_msg(smi_info);
+		}
+
+		rv = SI_SM_CALL_WITHOUT_DELAY;
+	}
+	spin_unlock(&(smi_info->msg_lock));
+
+	return rv;
+}
+
+static void start_enable_irq(struct smi_info *smi_info)
+{
+	unsigned char msg[2];
+
+	/* If we are enabling interrupts, we have to tell the
+	   BMC to use them. */
+	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
+
+	smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
+	smi_info->si_state = SI_ENABLE_INTERRUPTS1;
+}
+
+static void start_clear_flags(struct smi_info *smi_info)
+{
+	unsigned char msg[3];
+
+	/* Make sure the watchdog pre-timeout flag is not set at startup. */
+	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
+	msg[2] = WDT_PRE_TIMEOUT_INT;
+
+	smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);
+	smi_info->si_state = SI_CLEARING_FLAGS;
+}
+
+/* When we have a situtaion where we run out of memory and cannot
+   allocate messages, we just leave them in the BMC and run the system
+   polled until we can allocate some memory.  Once we have some
+   memory, we will re-enable the interrupt. */
+static inline void disable_si_irq(struct smi_info *smi_info)
+{
+	if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
+		disable_irq_nosync(smi_info->irq);
+		smi_info->interrupt_disabled = 1;
+	}
+}
+
+static inline void enable_si_irq(struct smi_info *smi_info)
+{
+	if ((smi_info->irq) && (smi_info->interrupt_disabled)) {
+		enable_irq(smi_info->irq);
+		smi_info->interrupt_disabled = 0;
+	}
+}
+
+static void handle_flags(struct smi_info *smi_info)
+{
+	if (smi_info->msg_flags & WDT_PRE_TIMEOUT_INT) {
+		/* Watchdog pre-timeout */
+		spin_lock(&smi_info->count_lock);
+		smi_info->watchdog_pretimeouts++;
+		spin_unlock(&smi_info->count_lock);
+
+		start_clear_flags(smi_info);
+		smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
+		spin_unlock(&(smi_info->si_lock));
+		ipmi_smi_watchdog_pretimeout(smi_info->intf);
+		spin_lock(&(smi_info->si_lock));
+	} else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
+		/* Messages available. */
+		smi_info->curr_msg = ipmi_alloc_smi_msg();
+		if (!smi_info->curr_msg) {
+			disable_si_irq(smi_info);
+			smi_info->si_state = SI_NORMAL;
+			return;
+		}
+		enable_si_irq(smi_info);
+
+		smi_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		smi_info->curr_msg->data[1] = IPMI_GET_MSG_CMD;
+		smi_info->curr_msg->data_size = 2;
+
+		smi_info->handlers->start_transaction(
+			smi_info->si_sm,
+			smi_info->curr_msg->data,
+			smi_info->curr_msg->data_size);
+		smi_info->si_state = SI_GETTING_MESSAGES;
+	} else if (smi_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
+		/* Events available. */
+		smi_info->curr_msg = ipmi_alloc_smi_msg();
+		if (!smi_info->curr_msg) {
+			disable_si_irq(smi_info);
+			smi_info->si_state = SI_NORMAL;
+			return;
+		}
+		enable_si_irq(smi_info);
+
+		smi_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		smi_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
+		smi_info->curr_msg->data_size = 2;
+
+		smi_info->handlers->start_transaction(
+			smi_info->si_sm,
+			smi_info->curr_msg->data,
+			smi_info->curr_msg->data_size);
+		smi_info->si_state = SI_GETTING_EVENTS;
+	} else {
+		smi_info->si_state = SI_NORMAL;
+	}
+}
+
+static void handle_transaction_done(struct smi_info *smi_info)
+{
+	struct ipmi_smi_msg *msg;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+
+	do_gettimeofday(&t);
+	printk("**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+	switch (smi_info->si_state) {
+	case SI_NORMAL:
+		if (!smi_info->curr_msg)
+			break;
+
+		smi_info->curr_msg->rsp_size
+			= smi_info->handlers->get_result(
+				smi_info->si_sm,
+				smi_info->curr_msg->rsp,
+				IPMI_MAX_MSG_LENGTH);
+
+		/* Do this here becase deliver_recv_msg() releases the
+		   lock, and a new message can be put in during the
+		   time the lock is released. */
+		msg = smi_info->curr_msg;
+		smi_info->curr_msg = NULL;
+		deliver_recv_msg(smi_info, msg);
+		break;
+
+	case SI_GETTING_FLAGS:
+	{
+		unsigned char msg[4];
+		unsigned int  len;
+
+		/* We got the flags from the SMI, now handle them. */
+		len = smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
+		if (msg[2] != 0) {
+			/* Error fetching flags, just give up for
+			   now. */
+			smi_info->si_state = SI_NORMAL;
+		} else if (len < 3) {
+			/* Hmm, no flags.  That's technically illegal, but
+			   don't use uninitialized data. */
+			smi_info->si_state = SI_NORMAL;
+		} else {
+			smi_info->msg_flags = msg[3];
+			handle_flags(smi_info);
+		}
+		break;
+	}
+
+	case SI_CLEARING_FLAGS:
+	case SI_CLEARING_FLAGS_THEN_SET_IRQ:
+	{
+		unsigned char msg[3];
+
+		/* We cleared the flags. */
+		smi_info->handlers->get_result(smi_info->si_sm, msg, 3);
+		if (msg[2] != 0) {
+			/* Error clearing flags */
+			printk(KERN_WARNING
+			       "ipmi_si: Error clearing flags: %2.2x\n",
+			       msg[2]);
+		}
+		if (smi_info->si_state == SI_CLEARING_FLAGS_THEN_SET_IRQ)
+			start_enable_irq(smi_info);
+		else
+			smi_info->si_state = SI_NORMAL;
+		break;
+	}
+
+	case SI_GETTING_EVENTS:
+	{
+		smi_info->curr_msg->rsp_size
+			= smi_info->handlers->get_result(
+				smi_info->si_sm,
+				smi_info->curr_msg->rsp,
+				IPMI_MAX_MSG_LENGTH);
+
+		/* Do this here becase deliver_recv_msg() releases the
+		   lock, and a new message can be put in during the
+		   time the lock is released. */
+		msg = smi_info->curr_msg;
+		smi_info->curr_msg = NULL;
+		if (msg->rsp[2] != 0) {
+			/* Error getting event, probably done. */
+			msg->done(msg);
+
+			/* Take off the event flag. */
+			smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
+		} else {
+			spin_lock(&smi_info->count_lock);
+			smi_info->events++;
+			spin_unlock(&smi_info->count_lock);
+
+			deliver_recv_msg(smi_info, msg);
+		}
+		handle_flags(smi_info);
+		break;
+	}
+
+	case SI_GETTING_MESSAGES:
+	{
+		smi_info->curr_msg->rsp_size
+			= smi_info->handlers->get_result(
+				smi_info->si_sm,
+				smi_info->curr_msg->rsp,
+				IPMI_MAX_MSG_LENGTH);
+
+		/* Do this here becase deliver_recv_msg() releases the
+		   lock, and a new message can be put in during the
+		   time the lock is released. */
+		msg = smi_info->curr_msg;
+		smi_info->curr_msg = NULL;
+		if (msg->rsp[2] != 0) {
+			/* Error getting event, probably done. */
+			msg->done(msg);
+
+			/* Take off the msg flag. */
+			smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
+		} else {
+			spin_lock(&smi_info->count_lock);
+			smi_info->incoming_messages++;
+			spin_unlock(&smi_info->count_lock);
+
+			deliver_recv_msg(smi_info, msg);
+		}
+		handle_flags(smi_info);
+		break;
+	}
+
+	case SI_ENABLE_INTERRUPTS1:
+	{
+		unsigned char msg[4];
+
+		/* We got the flags from the SMI, now handle them. */
+		smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
+		if (msg[2] != 0) {
+			printk(KERN_WARNING
+			       "ipmi_si: Could not enable interrupts"
+			       ", failed get, using polled mode.\n");
+			smi_info->si_state = SI_NORMAL;
+		} else {
+			msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+			msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
+			msg[2] = msg[3] | 1; /* enable msg queue int */
+			smi_info->handlers->start_transaction(
+				smi_info->si_sm, msg, 3);
+			smi_info->si_state = SI_ENABLE_INTERRUPTS2;
+		}
+		break;
+	}
+
+	case SI_ENABLE_INTERRUPTS2:
+	{
+		unsigned char msg[4];
+
+		/* We got the flags from the SMI, now handle them. */
+		smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
+		if (msg[2] != 0) {
+			printk(KERN_WARNING
+			       "ipmi_si: Could not enable interrupts"
+			       ", failed set, using polled mode.\n");
+		}
+		smi_info->si_state = SI_NORMAL;
+		break;
+	}
+	}
+}
+
+/* Called on timeouts and events.  Timeouts should pass the elapsed
+   time, interrupts should pass in zero. */
+static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
+					   int time)
+{
+	enum si_sm_result si_sm_result;
+
+ restart:
+	/* There used to be a loop here that waited a little while
+	   (around 25us) before giving up.  That turned out to be
+	   pointless, the minimum delays I was seeing were in the 300us
+	   range, which is far too long to wait in an interrupt.  So
+	   we just run until the state machine tells us something
+	   happened or it needs a delay. */
+	si_sm_result = smi_info->handlers->event(smi_info->si_sm, time);
+	time = 0;
+	while (si_sm_result == SI_SM_CALL_WITHOUT_DELAY)
+	{
+		si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);
+	}
+
+	if (si_sm_result == SI_SM_TRANSACTION_COMPLETE)
+	{
+		spin_lock(&smi_info->count_lock);
+		smi_info->complete_transactions++;
+		spin_unlock(&smi_info->count_lock);
+
+		handle_transaction_done(smi_info);
+		si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);
+	}
+	else if (si_sm_result == SI_SM_HOSED)
+	{
+		spin_lock(&smi_info->count_lock);
+		smi_info->hosed_count++;
+		spin_unlock(&smi_info->count_lock);
+
+		if (smi_info->curr_msg != NULL) {
+			/* If we were handling a user message, format
+                           a response to send to the upper layer to
+                           tell it about the error. */
+			return_hosed_msg(smi_info);
+		}
+		si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);
+		smi_info->si_state = SI_NORMAL;
+	}
+
+	/* We prefer handling attn over new messages. */
+	if (si_sm_result == SI_SM_ATTN)
+	{
+		unsigned char msg[2];
+
+		spin_lock(&smi_info->count_lock);
+		smi_info->attentions++;
+		spin_unlock(&smi_info->count_lock);
+
+		/* Got a attn, send down a get message flags to see
+                   what's causing it.  It would be better to handle
+                   this in the upper layer, but due to the way
+                   interrupts work with the SMI, that's not really
+                   possible. */
+		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		msg[1] = IPMI_GET_MSG_FLAGS_CMD;
+
+		smi_info->handlers->start_transaction(
+			smi_info->si_sm, msg, 2);
+		smi_info->si_state = SI_GETTING_FLAGS;
+		goto restart;
+	}
+
+	/* If we are currently idle, try to start the next message. */
+	if (si_sm_result == SI_SM_IDLE) {
+		spin_lock(&smi_info->count_lock);
+		smi_info->idles++;
+		spin_unlock(&smi_info->count_lock);
+
+		si_sm_result = start_next_msg(smi_info);
+		if (si_sm_result != SI_SM_IDLE)
+			goto restart;
+        }
+
+	if ((si_sm_result == SI_SM_IDLE)
+	    && (atomic_read(&smi_info->req_events)))
+	{
+		/* We are idle and the upper layer requested that I fetch
+		   events, so do so. */
+		unsigned char msg[2];
+
+		spin_lock(&smi_info->count_lock);
+		smi_info->flag_fetches++;
+		spin_unlock(&smi_info->count_lock);
+
+		atomic_set(&smi_info->req_events, 0);
+		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		msg[1] = IPMI_GET_MSG_FLAGS_CMD;
+
+		smi_info->handlers->start_transaction(
+			smi_info->si_sm, msg, 2);
+		smi_info->si_state = SI_GETTING_FLAGS;
+		goto restart;
+	}
+
+	return si_sm_result;
+}
+
+static void sender(void                *send_info,
+		   struct ipmi_smi_msg *msg,
+		   int                 priority)
+{
+	struct smi_info   *smi_info = send_info;
+	enum si_sm_result result;
+	unsigned long     flags;
+#ifdef DEBUG_TIMING
+	struct timeval    t;
+#endif
+
+	spin_lock_irqsave(&(smi_info->msg_lock), flags);
+#ifdef DEBUG_TIMING
+	do_gettimeofday(&t);
+	printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+
+	if (smi_info->run_to_completion) {
+		/* If we are running to completion, then throw it in
+		   the list and run transactions until everything is
+		   clear.  Priority doesn't matter here. */
+		list_add_tail(&(msg->link), &(smi_info->xmit_msgs));
+
+		/* We have to release the msg lock and claim the smi
+		   lock in this case, because of race conditions. */
+		spin_unlock_irqrestore(&(smi_info->msg_lock), flags);
+
+		spin_lock_irqsave(&(smi_info->si_lock), flags);
+		result = smi_event_handler(smi_info, 0);
+		while (result != SI_SM_IDLE) {
+			udelay(SI_SHORT_TIMEOUT_USEC);
+			result = smi_event_handler(smi_info,
+						   SI_SHORT_TIMEOUT_USEC);
+		}
+		spin_unlock_irqrestore(&(smi_info->si_lock), flags);
+		return;
+	} else {
+		if (priority > 0) {
+			list_add_tail(&(msg->link), &(smi_info->hp_xmit_msgs));
+		} else {
+			list_add_tail(&(msg->link), &(smi_info->xmit_msgs));
+		}
+	}
+	spin_unlock_irqrestore(&(smi_info->msg_lock), flags);
+
+	spin_lock_irqsave(&(smi_info->si_lock), flags);
+	if ((smi_info->si_state == SI_NORMAL)
+	    && (smi_info->curr_msg == NULL))
+	{
+		start_next_msg(smi_info);
+		si_restart_short_timer(smi_info);
+	}
+	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
+}
+
+static void set_run_to_completion(void *send_info, int i_run_to_completion)
+{
+	struct smi_info   *smi_info = send_info;
+	enum si_sm_result result;
+	unsigned long     flags;
+
+	spin_lock_irqsave(&(smi_info->si_lock), flags);
+
+	smi_info->run_to_completion = i_run_to_completion;
+	if (i_run_to_completion) {
+		result = smi_event_handler(smi_info, 0);
+		while (result != SI_SM_IDLE) {
+			udelay(SI_SHORT_TIMEOUT_USEC);
+			result = smi_event_handler(smi_info,
+						   SI_SHORT_TIMEOUT_USEC);
+		}
+	}
+
+	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
+}
+
+static void request_events(void *send_info)
+{
+	struct smi_info *smi_info = send_info;
+
+	atomic_set(&smi_info->req_events, 1);
+}
+
+static int initialized = 0;
+
+/* Must be called with interrupts off and with the si_lock held. */
+static void si_restart_short_timer(struct smi_info *smi_info)
+{
+#if defined(CONFIG_HIGH_RES_TIMERS)
+	unsigned long flags;
+	unsigned long jiffies_now;
+
+	if (del_timer(&(smi_info->si_timer))) {
+		/* If we don't delete the timer, then it will go off
+		   immediately, anyway.  So we only process if we
+		   actually delete the timer. */
+
+		/* We already have irqsave on, so no need for it
+                   here. */
+		read_lock(&xtime_lock);
+		jiffies_now = jiffies;
+		smi_info->si_timer.expires = jiffies_now;
+		smi_info->si_timer.sub_expires = get_arch_cycles(jiffies_now);
+
+		add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
+
+		add_timer(&(smi_info->si_timer));
+		spin_lock_irqsave(&smi_info->count_lock, flags);
+		smi_info->timeout_restarts++;
+		spin_unlock_irqrestore(&smi_info->count_lock, flags);
+	}
+#endif
+}
+
+static void smi_timeout(unsigned long data)
+{
+	struct smi_info   *smi_info = (struct smi_info *) data;
+	enum si_sm_result smi_result;
+	unsigned long     flags;
+	unsigned long     jiffies_now;
+	unsigned long     time_diff;
+#ifdef DEBUG_TIMING
+	struct timeval    t;
+#endif
+
+	if (smi_info->stop_operation) {
+		smi_info->timer_stopped = 1;
+		return;
+	}
+
+	spin_lock_irqsave(&(smi_info->si_lock), flags);
+#ifdef DEBUG_TIMING
+	do_gettimeofday(&t);
+	printk("**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+	jiffies_now = jiffies;
+	time_diff = ((jiffies_now - smi_info->last_timeout_jiffies)
+		     * SI_USEC_PER_JIFFY);
+	smi_result = smi_event_handler(smi_info, time_diff);
+
+	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
+
+	smi_info->last_timeout_jiffies = jiffies_now;
+
+	if ((smi_info->irq) && (! smi_info->interrupt_disabled)) {
+		/* Running with interrupts, only do long timeouts. */
+		smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
+		spin_lock_irqsave(&smi_info->count_lock, flags);
+		smi_info->long_timeouts++;
+		spin_unlock_irqrestore(&smi_info->count_lock, flags);
+		goto do_add_timer;
+	}
+
+	/* If the state machine asks for a short delay, then shorten
+           the timer timeout. */
+	if (smi_result == SI_SM_CALL_WITH_DELAY) {
+		spin_lock_irqsave(&smi_info->count_lock, flags);
+		smi_info->short_timeouts++;
+		spin_unlock_irqrestore(&smi_info->count_lock, flags);
+#if defined(CONFIG_HIGH_RES_TIMERS)
+		read_lock(&xtime_lock);
+                smi_info->si_timer.expires = jiffies;
+                smi_info->si_timer.sub_expires
+                        = get_arch_cycles(smi_info->si_timer.expires);
+                read_unlock(&xtime_lock);
+		add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
+#else
+		smi_info->si_timer.expires = jiffies + 1;
+#endif
+	} else {
+		spin_lock_irqsave(&smi_info->count_lock, flags);
+		smi_info->long_timeouts++;
+		spin_unlock_irqrestore(&smi_info->count_lock, flags);
+		smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
+#if defined(CONFIG_HIGH_RES_TIMERS)
+		smi_info->si_timer.sub_expires = 0;
+#endif
+	}
+
+ do_add_timer:
+	add_timer(&(smi_info->si_timer));
+}
+
+static irqreturn_t si_irq_handler(int irq, void *data, struct pt_regs *regs)
+{
+	struct smi_info *smi_info = data;
+	unsigned long   flags;
+#ifdef DEBUG_TIMING
+	struct timeval  t;
+#endif
+
+	spin_lock_irqsave(&(smi_info->si_lock), flags);
+
+	spin_lock(&smi_info->count_lock);
+	smi_info->interrupts++;
+	spin_unlock(&smi_info->count_lock);
+
+	if (smi_info->stop_operation)
+		goto out;
+
+#ifdef DEBUG_TIMING
+	do_gettimeofday(&t);
+	printk("**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+	smi_event_handler(smi_info, 0);
+ out:
+	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
+	return IRQ_HANDLED;
+}
+
+static struct ipmi_smi_handlers handlers =
+{
+	.owner                  = THIS_MODULE,
+	.sender			= sender,
+	.request_events		= request_events,
+	.set_run_to_completion  = set_run_to_completion
+};
+
+/* There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
+   a default IO port, and 1 ACPI/SPMI address.  That sets SI_MAX_DRIVERS */
+
+#define SI_MAX_PARMS 4
+#define SI_MAX_DRIVERS ((SI_MAX_PARMS * 2) + 2)
+static struct smi_info *smi_infos[SI_MAX_DRIVERS] =
+{ NULL, NULL, NULL, NULL };
+
+#define DEVICE_NAME "ipmi_si"
+
+#define DEFAULT_KCS_IO_PORT 0xca2
+#define DEFAULT_SMIC_IO_PORT 0xca9
+#define DEFAULT_BT_IO_PORT   0xe4
+
+static int           si_trydefaults = 1;
+static char          *si_type[SI_MAX_PARMS] = { NULL, NULL, NULL, NULL };
+#define MAX_SI_TYPE_STR 30
+static char          si_type_str[MAX_SI_TYPE_STR];
+static unsigned long addrs[SI_MAX_PARMS] = { 0, 0, 0, 0 };
+static int num_addrs = 0;
+static unsigned int  ports[SI_MAX_PARMS] = { 0, 0, 0, 0 };
+static int num_ports = 0;
+static int           irqs[SI_MAX_PARMS] = { 0, 0, 0, 0 };
+static int num_irqs = 0;
+
+
+module_param_named(trydefaults, si_trydefaults, bool, 0);
+MODULE_PARM_DESC(trydefaults, "Setting this to 'false' will disable the"
+		 " default scan of the KCS and SMIC interface at the standard"
+		 " address");
+module_param_string(type, si_type_str, MAX_SI_TYPE_STR, 0);
+MODULE_PARM_DESC(type, "Defines the type of each interface, each"
+		 " interface separated by commas.  The types are 'kcs',"
+		 " 'smic', and 'bt'.  For example si_type=kcs,bt will set"
+		 " the first interface to kcs and the second to bt");
+module_param_array(addrs, long, num_addrs, 0);
+MODULE_PARM_DESC(addrs, "Sets the memory address of each interface, the"
+		 " addresses separated by commas.  Only use if an interface"
+		 " is in memory.  Otherwise, set it to zero or leave"
+		 " it blank.");
+module_param_array(ports, int, num_ports, 0);
+MODULE_PARM_DESC(ports, "Sets the port address of each interface, the"
+		 " addresses separated by commas.  Only use if an interface"
+		 " is a port.  Otherwise, set it to zero or leave"
+		 " it blank.");
+module_param_array(irqs, int, num_irqs, 0);
+MODULE_PARM_DESC(irqs, "Sets the interrupt of each interface, the"
+		 " addresses separated by commas.  Only use if an interface"
+		 " has an interrupt.  Otherwise, set it to zero or leave"
+		 " it blank.");
+
+
+#if defined(CONFIG_ACPI_INTERPETER) || defined(CONFIG_X86) || defined(CONFIG_PCI)
+#define IPMI_MEM_ADDR_SPACE 1
+#define IPMI_IO_ADDR_SPACE  2
+static int is_new_interface(int intf, u8 addr_space, unsigned long base_addr)
+{
+	int i;
+
+	for (i = 0; i < SI_MAX_PARMS; ++i) {
+		/* Don't check our address. */
+		if (i == intf)
+			continue;
+		if (si_type[i] != NULL) {
+			if ((addr_space == IPMI_MEM_ADDR_SPACE &&
+			     base_addr == addrs[i]) ||
+			    (addr_space == IPMI_IO_ADDR_SPACE &&
+			     base_addr == ports[i]))
+				return 0;
+		}
+		else
+			break;
+	}
+
+	return 1;
+}
+#endif
+
+static int std_irq_setup(struct smi_info *info)
+{
+	int rv;
+
+	if (!info->irq)
+		return 0;
+
+	rv = request_irq(info->irq,
+			 si_irq_handler,
+			 SA_INTERRUPT,
+			 DEVICE_NAME,
+			 info);
+	if (rv) {
+		printk(KERN_WARNING
+		       "ipmi_si: %s unable to claim interrupt %d,"
+		       " running polled\n",
+		       DEVICE_NAME, info->irq);
+		info->irq = 0;
+	} else {
+		printk("  Using irq %d\n", info->irq);
+	}
+
+	return rv;
+}
+
+static void std_irq_cleanup(struct smi_info *info)
+{
+	if (!info->irq)
+		return;
+
+	free_irq(info->irq, info);
+}
+
+static unsigned char port_inb(struct si_sm_io *io, unsigned int offset)
+{
+	unsigned int *addr = io->info;
+
+	return inb((*addr)+offset);
+}
+
+static void port_outb(struct si_sm_io *io, unsigned int offset,
+		      unsigned char b)
+{
+	unsigned int *addr = io->info;
+
+	outb(b, (*addr)+offset);
+}
+
+static int port_setup(struct smi_info *info)
+{
+	unsigned int *addr = info->io.info;
+
+	if (!addr || (!*addr))
+		return -ENODEV;
+
+	if (request_region(*addr, info->io_size, DEVICE_NAME) == NULL)
+		return -EIO;
+	return 0;
+}
+
+static void port_cleanup(struct smi_info *info)
+{
+	unsigned int *addr = info->io.info;
+
+	if (addr && (*addr))
+		release_region (*addr, info->io_size);
+	kfree(info);
+}
+
+static int try_init_port(int intf_num, struct smi_info **new_info)
+{
+	struct smi_info *info;
+
+	if (!ports[intf_num])
+		return -ENODEV;
+
+	if (!is_new_interface(intf_num, IPMI_IO_ADDR_SPACE,
+			      ports[intf_num]))
+		return -ENODEV;
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		printk(KERN_ERR "ipmi_si: Could not allocate SI data (1)\n");
+		return -ENOMEM;
+	}
+	memset(info, 0, sizeof(*info));
+
+	info->io_setup = port_setup;
+	info->io_cleanup = port_cleanup;
+	info->io.inputb = port_inb;
+	info->io.outputb = port_outb;
+	info->io.info = &(ports[intf_num]);
+	info->io.addr = NULL;
+	info->irq = 0;
+	info->irq_setup = NULL;
+	*new_info = info;
+
+	if (si_type[intf_num] == NULL)
+		si_type[intf_num] = "kcs";
+
+	printk("ipmi_si: Trying \"%s\" at I/O port 0x%x\n",
+	       si_type[intf_num], ports[intf_num]);
+	return 0;
+}
+
+static unsigned char mem_inb(struct si_sm_io *io, unsigned int offset)
+{
+	return readb((io->addr)+offset);
+}
+
+static void mem_outb(struct si_sm_io *io, unsigned int offset,
+		     unsigned char b)
+{
+	writeb(b, (io->addr)+offset);
+}
+
+static int mem_setup(struct smi_info *info)
+{
+	unsigned long *addr = info->io.info;
+
+	if (!addr || (!*addr))
+		return -ENODEV;
+
+	if (request_mem_region(*addr, info->io_size, DEVICE_NAME) == NULL)
+		return -EIO;
+
+	info->io.addr = ioremap(*addr, info->io_size);
+	if (info->io.addr == NULL) {
+		release_mem_region(*addr, info->io_size);
+		return -EIO;
+	}
+	return 0;
+}
+
+static void mem_cleanup(struct smi_info *info)
+{
+	unsigned long *addr = info->io.info;
+
+	if (info->io.addr) {
+		iounmap(info->io.addr);
+		release_mem_region(*addr, info->io_size);
+	}
+	kfree(info);
+}
+
+static int try_init_mem(int intf_num, struct smi_info **new_info)
+{
+	struct smi_info *info;
+
+	if (!addrs[intf_num])
+		return -ENODEV;
+
+	if (!is_new_interface(intf_num, IPMI_MEM_ADDR_SPACE,
+			      addrs[intf_num]))
+		return -ENODEV;
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		printk(KERN_ERR "ipmi_si: Could not allocate SI data (2)\n");
+		return -ENOMEM;
+	}
+	memset(info, 0, sizeof(*info));
+
+	info->io_setup = mem_setup;
+	info->io_cleanup = mem_cleanup;
+	info->io.inputb = mem_inb;
+	info->io.outputb = mem_outb;
+	info->io.info = (void *) addrs[intf_num];
+	info->io.addr = NULL;
+	info->irq = 0;
+	info->irq_setup = NULL;
+	*new_info = info;
+
+	if (si_type[intf_num] == NULL)
+		si_type[intf_num] = "kcs";
+
+	printk("ipmi_si: Trying \"%s\" at memory address 0x%lx\n",
+	       si_type[intf_num], addrs[intf_num]);
+	return 0;
+}
+
+
+#ifdef CONFIG_ACPI_INTERPRETER
+
+#include <linux/acpi.h>
+
+/* Once we get an ACPI failure, we don't try any more, because we go
+   through the tables sequentially.  Once we don't find a table, there
+   are no more. */
+static int acpi_failure = 0;
+
+/* For GPE-type interrupts. */
+void ipmi_acpi_gpe(void *context)
+{
+	struct smi_info *smi_info = context;
+	unsigned long   flags;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+#endif
+
+	spin_lock_irqsave(&(smi_info->si_lock), flags);
+
+	spin_lock(&smi_info->count_lock);
+	smi_info->interrupts++;
+	spin_unlock(&smi_info->count_lock);
+
+	if (smi_info->stop_operation)
+		goto out;
+
+#ifdef DEBUG_TIMING
+	do_gettimeofday(&t);
+	printk("**ACPI_GPE: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+	smi_event_handler(smi_info, 0);
+ out:
+	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
+}
+
+static int acpi_gpe_irq_setup(struct smi_info *info)
+{
+	acpi_status status;
+
+	if (!info->irq)
+		return 0;
+
+	/* FIXME - is level triggered right? */
+	status = acpi_install_gpe_handler(NULL,
+					  info->irq,
+					  ACPI_EVENT_LEVEL_TRIGGERED,
+					  ipmi_acpi_gpe,
+					  info);
+	if (status != AE_OK) {
+		printk(KERN_WARNING
+		       "ipmi_si: %s unable to claim ACPI GPE %d,"
+		       " running polled\n",
+		       DEVICE_NAME, info->irq);
+		info->irq = 0;
+		return -EINVAL;
+	} else {
+		printk("  Using ACPI GPE %d\n", info->irq);
+		return 0;
+	}
+
+}
+
+static void acpi_gpe_irq_cleanup(struct smi_info *info)
+{
+	if (!info->irq)
+		return;
+
+	acpi_remove_gpe_handler(NULL, info->irq, ipmi_acpi_gpe);
+}
+
+/*
+ * Defined at
+ * http://h21007.www2.hp.com/dspp/files/unprotected/devresource/Docs/TechPapers/IA64/hpspmi.pdf
+ */
+struct SPMITable {
+	s8	Signature[4];
+	u32	Length;
+	u8	Revision;
+	u8	Checksum;
+	s8	OEMID[6];
+	s8	OEMTableID[8];
+	s8	OEMRevision[4];
+	s8	CreatorID[4];
+	s8	CreatorRevision[4];
+	u8	InterfaceType;
+	u8	IPMIlegacy;
+	s16	SpecificationRevision;
+
+	/*
+	 * Bit 0 - SCI interrupt supported
+	 * Bit 1 - I/O APIC/SAPIC
+	 */
+	u8	InterruptType;
+
+	/* If bit 0 of InterruptType is set, then this is the SCI
+           interrupt in the GPEx_STS register. */
+	u8	GPE;
+
+	s16	Reserved;
+
+	/* If bit 1 of InterruptType is set, then this is the I/O
+           APIC/SAPIC interrupt. */
+	u32	GlobalSystemInterrupt;
+
+	/* The actual register address. */
+	struct acpi_generic_address addr;
+
+	u8	UID[4];
+
+	s8      spmi_id[1]; /* A '\0' terminated array starts here. */
+};
+
+static int try_init_acpi(int intf_num, struct smi_info **new_info)
+{
+	struct smi_info  *info;
+	acpi_status      status;
+	struct SPMITable *spmi;
+	char             *io_type;
+	u8 		 addr_space;
+
+	if (acpi_failure)
+		return -ENODEV;
+
+	status = acpi_get_firmware_table("SPMI", intf_num+1,
+					 ACPI_LOGICAL_ADDRESSING,
+					 (struct acpi_table_header **) &spmi);
+	if (status != AE_OK) {
+		acpi_failure = 1;
+		return -ENODEV;
+	}
+
+	if (spmi->IPMIlegacy != 1) {
+	    printk(KERN_INFO "IPMI: Bad SPMI legacy %d\n", spmi->IPMIlegacy);
+  	    return -ENODEV;
+	}
+
+	if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+		addr_space = IPMI_MEM_ADDR_SPACE;
+	else
+		addr_space = IPMI_IO_ADDR_SPACE;
+	if (!is_new_interface(-1, addr_space, spmi->addr.address))
+		return -ENODEV;
+
+	/* Figure out the interface type. */
+	switch (spmi->InterfaceType)
+	{
+	case 1:	/* KCS */
+		si_type[intf_num] = "kcs";
+		break;
+
+	case 2:	/* SMIC */
+		si_type[intf_num] = "smic";
+		break;
+
+	case 3:	/* BT */
+		si_type[intf_num] = "bt";
+		break;
+
+	default:
+		printk(KERN_INFO "ipmi_si: Unknown ACPI/SPMI SI type %d\n",
+			spmi->InterfaceType);
+		return -EIO;
+	}
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		printk(KERN_ERR "ipmi_si: Could not allocate SI data (3)\n");
+		return -ENOMEM;
+	}
+	memset(info, 0, sizeof(*info));
+
+	if (spmi->InterruptType & 1) {
+		/* We've got a GPE interrupt. */
+		info->irq = spmi->GPE;
+		info->irq_setup = acpi_gpe_irq_setup;
+		info->irq_cleanup = acpi_gpe_irq_cleanup;
+	} else if (spmi->InterruptType & 2) {
+		/* We've got an APIC/SAPIC interrupt. */
+		info->irq = spmi->GlobalSystemInterrupt;
+		info->irq_setup = std_irq_setup;
+		info->irq_cleanup = std_irq_cleanup;
+	} else {
+		/* Use the default interrupt setting. */
+		info->irq = 0;
+		info->irq_setup = NULL;
+	}
+
+	if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+		io_type = "memory";
+		info->io_setup = mem_setup;
+		info->io_cleanup = mem_cleanup;
+		addrs[intf_num] = spmi->addr.address;
+		info->io.inputb = mem_inb;
+		info->io.outputb = mem_outb;
+		info->io.info = &(addrs[intf_num]);
+	} else if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
+		io_type = "I/O";
+		info->io_setup = port_setup;
+		info->io_cleanup = port_cleanup;
+		ports[intf_num] = spmi->addr.address;
+		info->io.inputb = port_inb;
+		info->io.outputb = port_outb;
+		info->io.info = &(ports[intf_num]);
+	} else {
+		kfree(info);
+		printk("ipmi_si: Unknown ACPI I/O Address type\n");
+		return -EIO;
+	}
+
+	*new_info = info;
+
+	printk("ipmi_si: ACPI/SPMI specifies \"%s\" %s SI @ 0x%lx\n",
+	       si_type[intf_num], io_type, (unsigned long) spmi->addr.address);
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_X86
+
+typedef struct dmi_ipmi_data
+{
+	u8   		type;
+	u8   		addr_space;
+	unsigned long	base_addr;
+	u8   		irq;
+}dmi_ipmi_data_t;
+
+typedef struct dmi_header
+{
+	u8	type;
+	u8	length;
+	u16	handle;
+}dmi_header_t;
+
+static int decode_dmi(dmi_header_t *dm, dmi_ipmi_data_t *ipmi_data)
+{
+	u8		*data = (u8 *)dm;
+	unsigned long  	base_addr;
+
+	ipmi_data->type = data[0x04];
+
+	memcpy(&base_addr,&data[0x08],sizeof(unsigned long));
+	if (base_addr & 1) {
+		/* I/O */
+		base_addr &= 0xFFFE;
+		ipmi_data->addr_space = IPMI_IO_ADDR_SPACE;
+	}
+	else {
+		/* Memory */
+		ipmi_data->addr_space = IPMI_MEM_ADDR_SPACE;
+	}
+
+	ipmi_data->base_addr = base_addr;
+	ipmi_data->irq = data[0x11];
+
+	if (is_new_interface(-1, ipmi_data->addr_space,ipmi_data->base_addr))
+	    return 0;
+
+	memset(ipmi_data,0,sizeof(dmi_ipmi_data_t));
+
+	return -1;
+}
+
+static int dmi_table(u32 base, int len, int num,
+	dmi_ipmi_data_t *ipmi_data)
+{
+	u8 		  *buf;
+	struct dmi_header *dm;
+	u8 		  *data;
+	int 		  i=1;
+	int		  status=-1;
+
+	buf = ioremap(base, len);
+	if(buf==NULL)
+		return -1;
+
+	data = buf;
+
+	while(i<num && (data - buf) < len)
+	{
+		dm=(dmi_header_t *)data;
+
+		if((data-buf+dm->length) >= len)
+        		break;
+
+		if (dm->type == 38) {
+			if (decode_dmi(dm, ipmi_data) == 0) {
+				status = 0;
+				break;
+			}
+		}
+
+	        data+=dm->length;
+		while((data-buf) < len && (*data || data[1]))
+			data++;
+		data+=2;
+		i++;
+	}
+	iounmap(buf);
+
+	return status;
+}
+
+inline static int dmi_checksum(u8 *buf)
+{
+	u8   sum=0;
+	int  a;
+
+	for(a=0; a<15; a++)
+		sum+=buf[a];
+	return (sum==0);
+}
+
+static int dmi_iterator(dmi_ipmi_data_t *ipmi_data)
+{
+	u8   buf[15];
+	u32  fp=0xF0000;
+
+#ifdef CONFIG_SIMNOW
+	return -1;
+#endif
+
+	while(fp < 0xFFFFF)
+	{
+		isa_memcpy_fromio(buf, fp, 15);
+		if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf))
+		{
+			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];
+
+			if(dmi_table(base, len, num, ipmi_data) == 0)
+				return 0;
+		}
+		fp+=16;
+	}
+
+	return -1;
+}
+
+static int try_init_smbios(int intf_num, struct smi_info **new_info)
+{
+	struct smi_info   *info;
+	dmi_ipmi_data_t   ipmi_data;
+	char              *io_type;
+	int               status;
+
+	status = dmi_iterator(&ipmi_data);
+
+	if (status < 0)
+		return -ENODEV;
+
+	switch(ipmi_data.type) {
+		case 0x01: /* KCS */
+			si_type[intf_num] = "kcs";
+			break;
+		case 0x02: /* SMIC */
+			si_type[intf_num] = "smic";
+			break;
+		case 0x03: /* BT */
+			si_type[intf_num] = "bt";
+			break;
+		default:
+			printk("ipmi_si: Unknown SMBIOS SI type.\n");
+			return -EIO;
+	}
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		printk(KERN_ERR "ipmi_si: Could not allocate SI data (4)\n");
+		return -ENOMEM;
+	}
+	memset(info, 0, sizeof(*info));
+
+	if (ipmi_data.addr_space == 1) {
+		io_type = "memory";
+		info->io_setup = mem_setup;
+		info->io_cleanup = mem_cleanup;
+		addrs[intf_num] = ipmi_data.base_addr;
+		info->io.inputb = mem_inb;
+		info->io.outputb = mem_outb;
+		info->io.info = &(addrs[intf_num]);
+	} else if (ipmi_data.addr_space == 2) {
+		io_type = "I/O";
+		info->io_setup = port_setup;
+		info->io_cleanup = port_cleanup;
+		ports[intf_num] = ipmi_data.base_addr;
+		info->io.inputb = port_inb;
+		info->io.outputb = port_outb;
+		info->io.info = &(ports[intf_num]);
+	} else {
+		kfree(info);
+		printk("ipmi_si: Unknown SMBIOS I/O Address type.\n");
+		return -EIO;
+	}
+
+	irqs[intf_num] = ipmi_data.irq;
+
+	*new_info = info;
+
+	printk("ipmi_si: Found SMBIOS-specified state machine at %s"
+	       " address 0x%lx\n",
+	       io_type, (unsigned long)ipmi_data.base_addr);
+	return 0;
+}
+#endif /* CONFIG_X86 */
+
+#ifdef CONFIG_PCI
+
+#define PCI_ERMC_CLASSCODE  0x0C0700
+#define PCI_HP_VENDOR_ID    0x103C
+#define PCI_MMC_DEVICE_ID   0x121A
+#define PCI_MMC_ADDR_CW     0x10
+
+/* Avoid more than one attempt to probe pci smic. */
+static int pci_smic_checked = 0;
+
+static int find_pci_smic(int intf_num, struct smi_info **new_info)
+{
+	struct smi_info  *info;
+	int              error;
+	struct pci_dev   *pci_dev = NULL;
+	u16    		 base_addr;
+	int              fe_rmc = 0;
+
+	if (pci_smic_checked)
+		return -ENODEV;
+
+	pci_smic_checked = 1;
+
+	if ((pci_dev = pci_find_device(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID,
+				       NULL)))
+		;
+	else if ((pci_dev = pci_find_class(PCI_ERMC_CLASSCODE, NULL)) &&
+		 pci_dev->subsystem_vendor == PCI_HP_VENDOR_ID)
+		fe_rmc = 1;
+	else
+		return -ENODEV;
+
+	error = pci_read_config_word(pci_dev, PCI_MMC_ADDR_CW, &base_addr);
+	if (error)
+	{
+		printk(KERN_ERR
+		       "ipmi_si: pci_read_config_word() failed (%d).\n",
+		       error);
+		return -ENODEV;
+	}
+
+	/* Bit 0: 1 specifies programmed I/O, 0 specifies memory mapped I/O */
+	if (!(base_addr & 0x0001))
+	{
+		printk(KERN_ERR
+		       "ipmi_si: memory mapped I/O not supported for PCI"
+		       " smic.\n");
+		return -ENODEV;
+	}
+
+	base_addr &= 0xFFFE;
+	if (!fe_rmc)
+		/* Data register starts at base address + 1 in eRMC */
+		++base_addr;
+
+	if (!is_new_interface(-1, IPMI_IO_ADDR_SPACE, base_addr))
+	    return -ENODEV;
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		printk(KERN_ERR "ipmi_si: Could not allocate SI data (5)\n");
+		return -ENOMEM;
+	}
+	memset(info, 0, sizeof(*info));
+
+	info->io_setup = port_setup;
+	info->io_cleanup = port_cleanup;
+	ports[intf_num] = base_addr;
+	info->io.inputb = port_inb;
+	info->io.outputb = port_outb;
+	info->io.info = &(ports[intf_num]);
+
+	*new_info = info;
+
+	irqs[intf_num] = pci_dev->irq;
+	si_type[intf_num] = "smic";
+
+	printk("ipmi_si: Found PCI SMIC at I/O address 0x%lx\n",
+		(long unsigned int) base_addr);
+
+	return 0;
+}
+#endif /* CONFIG_PCI */
+
+static int try_init_plug_and_play(int intf_num, struct smi_info **new_info)
+{
+#ifdef CONFIG_PCI
+	if (find_pci_smic(intf_num, new_info)==0)
+		return 0;
+#endif
+	/* Include other methods here. */
+
+	return -ENODEV;
+}
+
+
+static int try_get_dev_id(struct smi_info *smi_info)
+{
+	unsigned char      msg[2];
+	unsigned char      *resp;
+	unsigned long      resp_len;
+	enum si_sm_result smi_result;
+	int               rv = 0;
+
+	resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
+	if (!resp)
+		return -ENOMEM;
+
+	/* Do a Get Device ID command, since it comes back with some
+	   useful info. */
+	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+	msg[1] = IPMI_GET_DEVICE_ID_CMD;
+	smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
+
+	smi_result = smi_info->handlers->event(smi_info->si_sm, 0);
+	for (;;)
+	{
+		if (smi_result == SI_SM_CALL_WITH_DELAY) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(1);
+			smi_result = smi_info->handlers->event(
+				smi_info->si_sm, 100);
+		}
+		else if (smi_result == SI_SM_CALL_WITHOUT_DELAY)
+		{
+			smi_result = smi_info->handlers->event(
+				smi_info->si_sm, 0);
+		}
+		else
+			break;
+	}
+	if (smi_result == SI_SM_HOSED) {
+		/* We couldn't get the state machine to run, so whatever's at
+		   the port is probably not an IPMI SMI interface. */
+		rv = -ENODEV;
+		goto out;
+	}
+
+	/* Otherwise, we got some data. */
+	resp_len = smi_info->handlers->get_result(smi_info->si_sm,
+						  resp, IPMI_MAX_MSG_LENGTH);
+	if (resp_len < 6) {
+		/* That's odd, it should be longer. */
+		rv = -EINVAL;
+		goto out;
+	}
+
+	if ((resp[1] != IPMI_GET_DEVICE_ID_CMD) || (resp[2] != 0)) {
+		/* That's odd, it shouldn't be able to fail. */
+		rv = -EINVAL;
+		goto out;
+	}
+
+	/* Record info from the get device id, in case we need it. */
+	smi_info->ipmi_si_dev_rev = resp[4] & 0xf;
+	smi_info->ipmi_si_fw_rev_major = resp[5] & 0x7f;
+	smi_info->ipmi_si_fw_rev_minor = resp[6];
+	smi_info->ipmi_version_major = resp[7] & 0xf;
+	smi_info->ipmi_version_minor = resp[7] >> 4;
+
+ out:
+	kfree(resp);
+	return rv;
+}
+
+static int type_file_read_proc(char *page, char **start, off_t off,
+			       int count, int *eof, void *data)
+{
+	char            *out = (char *) page;
+	struct smi_info *smi = data;
+
+	switch (smi->si_type) {
+	    case SI_KCS:
+		return sprintf(out, "kcs\n");
+	    case SI_SMIC:
+		return sprintf(out, "smic\n");
+	    case SI_BT:
+		return sprintf(out, "bt\n");
+	    default:
+		return 0;
+	}
+}
+
+static int stat_file_read_proc(char *page, char **start, off_t off,
+			       int count, int *eof, void *data)
+{
+	char            *out = (char *) page;
+	struct smi_info *smi = data;
+
+	out += sprintf(out, "interrupts_enabled:    %d\n",
+		       smi->irq && !smi->interrupt_disabled);
+	out += sprintf(out, "short_timeouts:        %ld\n",
+		       smi->short_timeouts);
+	out += sprintf(out, "long_timeouts:         %ld\n",
+		       smi->long_timeouts);
+	out += sprintf(out, "timeout_restarts:      %ld\n",
+		       smi->timeout_restarts);
+	out += sprintf(out, "idles:                 %ld\n",
+		       smi->idles);
+	out += sprintf(out, "interrupts:            %ld\n",
+		       smi->interrupts);
+	out += sprintf(out, "attentions:            %ld\n",
+		       smi->attentions);
+	out += sprintf(out, "flag_fetches:          %ld\n",
+		       smi->flag_fetches);
+	out += sprintf(out, "hosed_count:           %ld\n",
+		       smi->hosed_count);
+	out += sprintf(out, "complete_transactions: %ld\n",
+		       smi->complete_transactions);
+	out += sprintf(out, "events:                %ld\n",
+		       smi->events);
+	out += sprintf(out, "watchdog_pretimeouts:  %ld\n",
+		       smi->watchdog_pretimeouts);
+	out += sprintf(out, "incoming_messages:     %ld\n",
+		       smi->incoming_messages);
+
+	return (out - ((char *) page));
+}
+
+/* Returns 0 if initialized, or negative on an error. */
+static int init_one_smi(int intf_num, struct smi_info **smi)
+{
+	int		rv;
+	struct smi_info *new_smi;
+
+	rv = try_init_mem(intf_num, &new_smi);
+	if (rv)
+		rv = try_init_port(intf_num, &new_smi);
+#ifdef CONFIG_ACPI_INTERPRETER
+	if ((rv) && (si_trydefaults)) {
+		rv = try_init_acpi(intf_num, &new_smi);
+	}
+#endif
+#ifdef CONFIG_X86
+	if ((rv) && (si_trydefaults)) {
+		rv = try_init_smbios(intf_num, &new_smi);
+        }
+#endif
+	if ((rv) && (si_trydefaults)) {
+		rv = try_init_plug_and_play(intf_num, &new_smi);
+	}
+
+
+	if (rv)
+		return rv;
+
+	/* So we know not to free it unless we have allocated one. */
+	new_smi->intf = NULL;
+	new_smi->si_sm = NULL;
+	new_smi->handlers = 0;
+
+	if (!new_smi->irq_setup) {
+		new_smi->irq = irqs[intf_num];
+		new_smi->irq_setup = std_irq_setup;
+		new_smi->irq_cleanup = std_irq_cleanup;
+	}
+
+	/* Default to KCS if no type is specified. */
+	if (si_type[intf_num] == NULL) {
+		if (si_trydefaults)
+			si_type[intf_num] = "kcs";
+		else {
+			rv = -EINVAL;
+			goto out_err;
+		}
+	}
+
+	/* Set up the state machine to use. */
+	if (strcmp(si_type[intf_num], "kcs") == 0) {
+		new_smi->handlers = &kcs_smi_handlers;
+		new_smi->si_type = SI_KCS;
+	} else if (strcmp(si_type[intf_num], "smic") == 0) {
+		new_smi->handlers = &smic_smi_handlers;
+		new_smi->si_type = SI_SMIC;
+	} else if (strcmp(si_type[intf_num], "bt") == 0) {
+		new_smi->handlers = &bt_smi_handlers;
+		new_smi->si_type = SI_BT;
+	} else {
+		/* No support for anything else yet. */
+		rv = -EIO;
+		goto out_err;
+	}
+
+	/* Allocate the state machine's data and initialize it. */
+	new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL);
+	if (!new_smi->si_sm) {
+		printk(" Could not allocate state machine memory\n");
+		rv = -ENOMEM;
+		goto out_err;
+	}
+	new_smi->io_size = new_smi->handlers->init_data(new_smi->si_sm,
+							&new_smi->io);
+
+	/* Now that we know the I/O size, we can set up the I/O. */
+	rv = new_smi->io_setup(new_smi);
+	if (rv) {
+		printk(" Could not set up I/O space\n");
+		goto out_err;
+	}
+
+	spin_lock_init(&(new_smi->si_lock));
+	spin_lock_init(&(new_smi->msg_lock));
+	spin_lock_init(&(new_smi->count_lock));
+
+	/* Do low-level detection first. */
+	if (new_smi->handlers->detect(new_smi->si_sm)) {
+		rv = -ENODEV;
+		goto out_err;
+	}
+
+	/* Attempt a get device id command.  If it fails, we probably
+           don't have a SMI here. */
+	rv = try_get_dev_id(new_smi);
+	if (rv)
+		goto out_err;
+
+	/* Try to claim any interrupts. */
+	new_smi->irq_setup(new_smi);
+
+	INIT_LIST_HEAD(&(new_smi->xmit_msgs));
+	INIT_LIST_HEAD(&(new_smi->hp_xmit_msgs));
+	new_smi->curr_msg = NULL;
+	atomic_set(&new_smi->req_events, 0);
+	new_smi->run_to_completion = 0;
+
+	rv = ipmi_register_smi(&handlers,
+			       new_smi,
+			       new_smi->ipmi_version_major,
+			       new_smi->ipmi_version_minor,
+			       &(new_smi->intf));
+	if (rv) {
+		printk(KERN_ERR
+		       "ipmi_si: Unable to register device: error %d\n",
+		       rv);
+		goto out_err;
+	}
+
+	rv = ipmi_smi_add_proc_entry(new_smi->intf, "type",
+				     type_file_read_proc, NULL,
+				     new_smi, THIS_MODULE);
+	if (rv) {
+		printk(KERN_ERR
+		       "ipmi_si: Unable to create proc entry: %d\n",
+		       rv);
+		goto out_err;
+	}
+
+	rv = ipmi_smi_add_proc_entry(new_smi->intf, "si_stats",
+				     stat_file_read_proc, NULL,
+				     new_smi, THIS_MODULE);
+	if (rv) {
+		printk(KERN_ERR
+		       "ipmi_si: Unable to create proc entry: %d\n",
+		       rv);
+		goto out_err;
+	}
+
+	start_clear_flags(new_smi);
+
+	/* IRQ is defined to be set when non-zero. */
+	if (new_smi->irq)
+		new_smi->si_state = SI_CLEARING_FLAGS_THEN_SET_IRQ;
+
+	new_smi->interrupt_disabled = 0;
+	new_smi->timer_stopped = 0;
+	new_smi->stop_operation = 0;
+
+	init_timer(&(new_smi->si_timer));
+	new_smi->si_timer.data = (long) new_smi;
+	new_smi->si_timer.function = smi_timeout;
+	new_smi->last_timeout_jiffies = jiffies;
+	new_smi->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
+	add_timer(&(new_smi->si_timer));
+
+	*smi = new_smi;
+
+	printk(" IPMI %s interface initialized\n", si_type[intf_num]);
+
+	return 0;
+
+ out_err:
+	if (new_smi->intf)
+		ipmi_unregister_smi(new_smi->intf);
+
+	new_smi->irq_cleanup(new_smi);
+	if (new_smi->si_sm) {
+		if (new_smi->handlers)
+			new_smi->handlers->cleanup(new_smi->si_sm);
+		kfree(new_smi->si_sm);
+	}
+	new_smi->io_cleanup(new_smi);
+	return rv;
+}
+
+static __init int init_ipmi_si(void)
+{
+	int  rv = 0;
+	int  pos = 0;
+	int  i;
+	char *str;
+
+	if (initialized)
+		return 0;
+	initialized = 1;
+
+	/* Parse out the si_type string into its components. */
+	str = si_type_str;
+	if (*str != '\0') {
+		for (i=0; (i<SI_MAX_PARMS) && (*str != '\0'); i++) {
+			si_type[i] = str;
+			str = strchr(str, ',');
+			if (str) {
+				*str = '\0';
+				str++;
+			} else {
+				break;
+			}
+		}
+	}
+
+	printk(KERN_INFO "IPMI System Interface driver version "
+	       IPMI_SI_VERSION);
+	if (kcs_smi_handlers.version)
+		printk(", KCS version %s", kcs_smi_handlers.version);
+	if (smic_smi_handlers.version)
+		printk(", SMIC version %s", smic_smi_handlers.version);
+	if (bt_smi_handlers.version)
+   	        printk(", BT version %s", bt_smi_handlers.version);
+	printk("\n");
+
+	rv = init_one_smi(0, &(smi_infos[pos]));
+	if (rv && !ports[0] && si_trydefaults) {
+		/* If we are trying defaults and the initial port is
+                   not set, then set it. */
+		si_type[0] = "kcs";
+		ports[0] = DEFAULT_KCS_IO_PORT;
+		rv = init_one_smi(0, &(smi_infos[pos]));
+		if (rv) {
+			/* No KCS - try SMIC */
+			si_type[0] = "smic";
+			ports[0] = DEFAULT_SMIC_IO_PORT;
+			rv = init_one_smi(0, &(smi_infos[pos]));
+		}
+		if (rv) {
+			/* No SMIC - try BT */
+			si_type[0] = "bt";
+			ports[0] = DEFAULT_BT_IO_PORT;
+			rv = init_one_smi(0, &(smi_infos[pos]));
+		}
+	}
+	if (rv == 0)
+		pos++;
+
+	for (i=1; i < SI_MAX_PARMS; i++) {
+		rv = init_one_smi(i, &(smi_infos[pos]));
+		if (rv == 0)
+			pos++;
+	}
+
+	if (smi_infos[0] == NULL) {
+		printk("ipmi_si: Unable to find any System Interface(s)\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+module_init(init_ipmi_si);
+
+void __exit cleanup_one_si(struct smi_info *to_clean)
+{
+	int           rv;
+	unsigned long flags;
+
+	if (! to_clean)
+		return;
+
+	/* Tell the timer and interrupt handlers that we are shutting
+	   down. */
+	spin_lock_irqsave(&(to_clean->si_lock), flags);
+	spin_lock(&(to_clean->msg_lock));
+
+	to_clean->stop_operation = 1;
+
+	to_clean->irq_cleanup(to_clean);
+
+	spin_unlock(&(to_clean->msg_lock));
+	spin_unlock_irqrestore(&(to_clean->si_lock), flags);
+
+	/* Wait until we know that we are out of any interrupt
+	   handlers might have been running before we freed the
+	   interrupt. */
+	synchronize_kernel();
+
+	/* Wait for the timer to stop.  This avoids problems with race
+	   conditions removing the timer here. */
+	while (!to_clean->timer_stopped) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+
+	rv = ipmi_unregister_smi(to_clean->intf);
+	if (rv) {
+		printk(KERN_ERR
+		       "ipmi_si: Unable to unregister device: errno=%d\n",
+		       rv);
+	}
+
+	to_clean->handlers->cleanup(to_clean->si_sm);
+
+	kfree(to_clean->si_sm);
+
+	to_clean->io_cleanup(to_clean);
+}
+
+static __exit void cleanup_ipmi_si(void)
+{
+	int i;
+
+	if (!initialized)
+		return;
+
+	for (i=0; i<SI_MAX_DRIVERS; i++) {
+		cleanup_one_si(smi_infos[i]);
+	}
+}
+module_exit(cleanup_ipmi_si);
+
+MODULE_LICENSE("GPL");
--- diff/drivers/char/ipmi/ipmi_si_sm.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/char/ipmi/ipmi_si_sm.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,117 @@
+/*
+ * ipmi_si_sm.h
+ *
+ * State machine interface for low-level IPMI system management
+ * interface state machines.  This code is the interface between
+ * the ipmi_smi code (that handles the policy of a KCS, SMIC, or
+ * BT interface) and the actual low-level state machine.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ *  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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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 is defined by the state machines themselves, it is an opaque
+   data type for them to use. */
+struct si_sm_data;
+
+/* The structure for doing I/O in the state machine.  The state
+   machine doesn't have the actual I/O routines, they are done through
+   this interface. */
+struct si_sm_io
+{
+	unsigned char (*inputb)(struct si_sm_io *io, unsigned int offset);
+	void (*outputb)(struct si_sm_io *io,
+			unsigned int  offset,
+			unsigned char b);
+
+	/* Generic info used by the actual handling routines, the
+           state machine shouldn't touch these. */
+	void *info;
+	void *addr;
+};
+
+/* Results of SMI events. */
+enum si_sm_result
+{
+	SI_SM_CALL_WITHOUT_DELAY, /* Call the driver again immediately */
+	SI_SM_CALL_WITH_DELAY,	/* Delay some before calling again. */
+	SI_SM_TRANSACTION_COMPLETE, /* A transaction is finished. */
+	SI_SM_IDLE,		/* The SM is in idle state. */
+	SI_SM_HOSED,		/* The hardware violated the state machine. */
+	SI_SM_ATTN		/* The hardware is asserting attn and the
+				   state machine is idle. */
+};
+
+/* Handlers for the SMI state machine. */
+struct si_sm_handlers
+{
+	/* Put the version number of the state machine here so the
+           upper layer can print it. */
+	char *version;
+
+	/* Initialize the data and return the amount of I/O space to
+           reserve for the space. */
+	unsigned int (*init_data)(struct si_sm_data *smi,
+				  struct si_sm_io   *io);
+
+	/* Start a new transaction in the state machine.  This will
+	   return -2 if the state machine is not idle, -1 if the size
+	   is invalid (to large or too small), or 0 if the transaction
+	   is successfully completed. */
+	int (*start_transaction)(struct si_sm_data *smi,
+				 unsigned char *data, unsigned int size);
+
+	/* Return the results after the transaction.  This will return
+	   -1 if the buffer is too small, zero if no transaction is
+	   present, or the actual length of the result data. */
+	int (*get_result)(struct si_sm_data *smi,
+			  unsigned char *data, unsigned int length);
+
+	/* Call this periodically (for a polled interface) or upon
+	   receiving an interrupt (for a interrupt-driven interface).
+	   If interrupt driven, you should probably poll this
+	   periodically when not in idle state.  This should be called
+	   with the time that passed since the last call, if it is
+	   significant.  Time is in microseconds. */
+	enum si_sm_result (*event)(struct si_sm_data *smi, long time);
+
+	/* Attempt to detect an SMI.  Returns 0 on success or nonzero
+           on failure. */
+	int (*detect)(struct si_sm_data *smi);
+
+	/* The interface is shutting down, so clean it up. */
+	void (*cleanup)(struct si_sm_data *smi);
+
+	/* Return the size of the SMI structure in bytes. */
+	int (*size)(void);
+};
+
+/* Current state machines that we can use. */
+extern struct si_sm_handlers kcs_smi_handlers;
+extern struct si_sm_handlers smic_smi_handlers;
+extern struct si_sm_handlers bt_smi_handlers;
+
--- diff/drivers/char/ipmi/ipmi_smb.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/char/ipmi/ipmi_smb.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,1270 @@
+/*
+ * ipmi_smb_intf.c
+ *
+ * The interface to the IPMI driver for SMBus access to a SMBus compliant device.
+ *
+ * Author: Intel Corporation
+ *         Todd Davis <todd.c.davis@intel.com>
+  *
+ * Copyright 2003 Intel Corporation
+ *
+ *  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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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 holds the "policy" for the interface to the SMB state
+ * machine.  It does the configuration, handles timers and interrupts,
+ * and drives the real SMB state machine.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#if defined(MODVERSIONS)
+#include <linux/modversions.h>
+#endif
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <asm/system.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/ipmi_smi.h>
+#include <linux/init.h>
+
+
+#define IPMI_SMB_VERSION "v31"
+
+/* module feature switches */
+#define	REGISTER_SMI	1
+#define	SMB_KTHREAD	1
+
+#ifdef SMB_KTHREAD
+#include <linux/kernel.h>
+#include <linux/smp_lock.h>
+
+/* a structure to store all information we need
+   for our thread */
+typedef struct kthread_struct
+{
+        /* Linux task structure of thread */
+        struct task_struct *thread;
+
+       /* semaphore needed on start and creation of thread. */
+        struct semaphore startstop_sem;
+
+        /* queue thread is waiting on. Gets initialized by
+           init_kthread, can be used by thread itself.
+        */
+        wait_queue_head_t queue;
+        /* flag to tell thread whether to die or not.
+           When the thread receives a signal, it must check
+           the value of terminate and call exit_kthread and terminate
+           if set.
+        */
+	int terminate;
+} kthread_t;	/* the variable that contains the thread data */
+#endif
+
+#define	SMB_IPMI_REQUEST	2
+#define	SMB_IPMI_RESPONSE	3
+
+/* smb_debug is a bit-field
+ *	SMB_DEBUG_MSG -	commands and their responses
+ *	SMB_DEBUG_STATES -	message states
+ *	SMB_DEBUG_TIMING -	 Measure times between events in the driver
+ */
+#define SMB_DEBUG_TIMING	4
+#define SMB_DEBUG_STATE		2
+#define SMB_DEBUG_MSG		1
+#define SMB_NODEBUG		0
+#define SMB_DEFAULT_DEBUG	(SMB_NODEBUG)
+
+#ifdef CONFIG_IPMI_SMB
+/* This forces a dependency to the config file for this option. */
+#endif
+
+enum smb_intf_state {
+	SMB_NORMAL,
+	SMB_GETTING_FLAGS,
+	SMB_GETTING_EVENTS,
+	SMB_CLEARING_FLAGS,
+	SMB_CLEARING_FLAGS_THEN_SET_IRQ,
+	SMB_GETTING_MESSAGES,
+	SMB_ENABLE_INTERRUPTS1,
+	SMB_ENABLE_INTERRUPTS2
+	/* FIXME - add watchdog stuff. */
+};
+
+#define SMB_IDLE(smb)	 ((smb)->smb_state == SMB_NORMAL \
+			  && (smb)->curr_msg == NULL \
+			  && ! atomic_read(&(smb)->req_events))
+
+#define	SMB_MSG_RETRIES	10
+
+struct smb_info
+{
+	int                 pos;
+	ipmi_smi_t          intf;
+	spinlock_t          msg_lock;
+	struct list_head    xmit_msgs;
+	struct list_head    hp_xmit_msgs;
+	struct ipmi_smi_msg *curr_msg;
+	enum smb_intf_state smb_state;
+	unsigned long       smb_debug;
+
+	/* Flags from the last GET_MSG_FLAGS command, used when an ATTN
+	   is set to hold the flags until we are done handling everything
+	   from the flags. */
+#define RECEIVE_MSG_AVAIL	0x01
+#define EVENT_MSG_BUFFER_FULL	0x02
+#define WDT_PRE_TIMEOUT_INT	0x08
+	unsigned char       msg_flags;
+
+	/* If set to true, this will request events the next time the
+	   state machine is idle. */
+	atomic_t            req_events;
+
+#ifdef CONFIG_IPMI_PANIC_EVENT
+	/* If true, run the state machine to completion on every send
+	   call.  Generally used after a panic or shutdown to make
+	   sure stuff goes out. */
+	int                 run_to_completion;
+#endif
+
+#ifdef SMB_KTHREAD
+	kthread_t smb_thread;
+#endif
+	struct i2c_client client;
+	unsigned char ipmi_smb_dev_rev;
+	unsigned char ipmi_smb_fw_rev_major;
+	unsigned char ipmi_smb_fw_rev_minor;
+	unsigned char ipmi_version_major;
+	unsigned char ipmi_version_minor;
+};
+
+static int initialized = 0;
+static void return_hosed_msg(struct smb_info *smb_info);
+
+static void deliver_recv_msg(struct smb_info *smb_info,
+			     struct ipmi_smi_msg *msg)
+{
+	if (msg->rsp_size < 0) {
+		if (smb_info->curr_msg == NULL) {
+			smb_info->curr_msg = msg;
+			return_hosed_msg(smb_info);
+		} else {
+			printk(KERN_ERR
+			       "malformed message in deliver_recv_msg:"
+			       " rsp_size = %d\n", msg->rsp_size);
+			ipmi_free_smi_msg(msg);
+		}
+	} else {
+		ipmi_smi_msg_received(smb_info->intf, msg);
+	}
+}
+
+static void return_hosed_msg(struct smb_info *smb_info)
+{
+	struct ipmi_smi_msg *msg = smb_info->curr_msg;
+
+	/* Make it a reponse */
+	msg->rsp[0] = msg->data[0] | 4;
+	msg->rsp[1] = msg->data[1];
+	msg->rsp[2] = 0xFF; /* Unknown error. */
+	msg->rsp_size = 3;
+
+	smb_info->curr_msg = NULL;
+	deliver_recv_msg(smb_info, msg);
+}
+
+static s32 smbus_client_read_block_data(struct i2c_client *client, int debug,
+					u8 *values)
+{
+	s32 resp_len;
+	int retries = 0;
+
+	/* FIXME - is there a way to limit the read size?  This culd
+	 * be an overrun situation otherwise. */
+	while ((resp_len = i2c_smbus_read_block_data (client,
+						      SMB_IPMI_RESPONSE,
+						      values)) < 0)
+	{
+		if ((retries += 1) >= SMB_MSG_RETRIES) {
+			printk(KERN_ERR
+			       "smb_smbus_read_block_data failed: %d\n",
+			       resp_len);
+			break;
+#ifdef CONFIG_IPMI_PANIC_EVENT
+		} else if (retries >= SMB_MSG_RETRIES/2 && signal_pending(current)) {
+			i2c_set_spin_delay(1); /*  shutting down */
+#endif
+		} else if (debug & (SMB_DEBUG_MSG|SMB_DEBUG_TIMING)) {
+			printk(KERN_WARNING
+			       "smb_smbus_read_block_data: retry %d\n",
+			       retries);
+		}
+	}
+
+	if (debug & SMB_DEBUG_TIMING) {
+		struct timeval t;
+		do_gettimeofday(&t);
+		printk(KERN_INFO "**Response %02x %02x %02x: %ld.%6.6ld\n",
+		       values[0], values[1], values[2], t.tv_sec, t.tv_usec);
+	}
+
+	if (debug & SMB_DEBUG_MSG) {
+		int i;
+		printk(KERN_INFO "ipmi response:");
+		for (i = 0; i < resp_len; i ++) {
+			printk (" %02x", (unsigned char) (values[i]));
+		}
+		printk ("\n");
+	}
+
+	return resp_len;
+}
+
+static s32 smb_smbus_read_block_data(struct smb_info *smb_info, u8 *values)
+{
+	return smbus_client_read_block_data(&smb_info->client,
+					    smb_info->smb_debug, values);
+}
+
+static s32 smbus_client_write_block_data(struct i2c_client *client, int debug,
+					 u8 length, u8 *values)
+{
+	s32 ret;
+	int retries = 0;
+
+	if (debug & SMB_DEBUG_MSG) {
+		int i ;
+
+		printk(KERN_INFO "ipmi request:");
+		for (i = 0; i < length; i ++) {
+			printk (" %02x", (unsigned char) (values [i]));
+		}
+		printk ("\n");
+	}
+
+	if (debug & SMB_DEBUG_TIMING) {
+		struct timeval t;
+		do_gettimeofday(&t);
+		printk(KERN_INFO "**Request %02x %02x: %ld.%6.6ld\n",
+		       values [0],values [1], t.tv_sec, t.tv_usec);
+	}
+
+	while ((ret = i2c_smbus_write_block_data (client,
+						  SMB_IPMI_REQUEST,
+						  length, values)) < 0)
+	{
+		if ((retries += 1) >= SMB_MSG_RETRIES) {
+			printk(KERN_ERR
+			       "smb_smbus_write_block_data failed: %d\n", ret);
+			break;
+#ifdef CONFIG_IPMI_PANIC_EVENT
+		} else if (retries >= SMB_MSG_RETRIES/2 && signal_pending(current)) {
+			i2c_set_spin_delay(1); /* shutting down */
+#endif
+		} else if (debug & (SMB_DEBUG_MSG|SMB_DEBUG_TIMING)) {
+			printk(KERN_WARNING
+			       "smb_smbus_write_block_data: retry %d\n",
+			       retries);
+		}
+	}
+	return ret;
+}
+
+static s32 smb_smbus_write_block_data(struct smb_info *smb_info,
+                                      u8 length,  u8 *values)
+{
+	return smbus_client_write_block_data(&smb_info->client,
+					     smb_info->smb_debug,
+					     length,
+					     values);
+}
+
+static int send_next_msg(struct smb_info *smb_info)
+{
+	s32              rv;
+	struct list_head *entry = NULL;
+
+	spin_lock(&(smb_info->msg_lock));
+
+	/* Pick the high priority queue first. */
+	if (! list_empty(&(smb_info->hp_xmit_msgs))) {
+		entry = smb_info->hp_xmit_msgs.next;
+	} else if (! list_empty(&(smb_info->xmit_msgs))) {
+		entry = smb_info->xmit_msgs.next;
+	}
+
+	if (!entry) {
+		spin_unlock(&(smb_info->msg_lock));
+		smb_info->curr_msg = NULL;
+		return 0;
+	}
+	list_del(entry);
+	smb_info->curr_msg = list_entry(entry,
+					struct ipmi_smi_msg,
+					link);
+	spin_unlock(&(smb_info->msg_lock));
+	rv = smb_smbus_write_block_data(
+	    smb_info,
+	    smb_info->curr_msg->data_size,
+	    smb_info->curr_msg->data);
+	if (rv) {
+		return_hosed_msg(smb_info);
+	}
+	return 1;
+}
+
+static void start_enable_irq(struct smb_info *smb_info)
+{
+	unsigned char msg[2];
+
+	/* If we are enabling interrupts, we have to tell the
+	   IPMI device to use them. */
+	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
+
+	if (smb_smbus_write_block_data(smb_info, 2, msg) == 0) {
+		smb_info->smb_state = SMB_ENABLE_INTERRUPTS1;
+	} else {
+		smb_info->smb_state = SMB_NORMAL;
+	}
+}
+
+static void start_clear_flags(struct smb_info *smb_info)
+{
+	unsigned char msg[3];
+
+	/* Make sure the watchdog pre-timeout flag is not set at startup. */
+	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
+	msg[2] = WDT_PRE_TIMEOUT_INT;
+
+	if (smb_smbus_write_block_data(smb_info, 3, msg) == 0) {
+		smb_info->smb_state = SMB_CLEARING_FLAGS;
+	} else {
+		smb_info->smb_state = SMB_NORMAL;
+	}
+}
+
+static void handle_flags(struct smb_info *smb_info)
+{
+	if (smb_info->msg_flags & WDT_PRE_TIMEOUT_INT) {
+		/* Watchdog pre-timeout */
+		start_clear_flags(smb_info);
+		smb_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
+		ipmi_smi_watchdog_pretimeout(smb_info->intf);
+	} else if (smb_info->msg_flags & RECEIVE_MSG_AVAIL) {
+		/* Messages available. */
+		smb_info->curr_msg = ipmi_alloc_smi_msg();
+		if (!smb_info->curr_msg) {
+			smb_info->smb_state = SMB_NORMAL;
+			return;
+		}
+
+		smb_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		smb_info->curr_msg->data[1] = IPMI_GET_MSG_CMD;
+		smb_info->curr_msg->data_size = 2;
+
+		if (smb_smbus_write_block_data(
+		    smb_info,
+		    smb_info->curr_msg->data_size,
+		    smb_info->curr_msg->data) == 0) {
+			smb_info->smb_state = SMB_GETTING_MESSAGES;
+		} else {
+			ipmi_free_smi_msg(smb_info->curr_msg);
+			smb_info->curr_msg = NULL;
+			smb_info->smb_state = SMB_NORMAL;
+			return;
+		}
+	} else if (smb_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
+		/* Events available. */
+		smb_info->curr_msg = ipmi_alloc_smi_msg();
+		if (!smb_info->curr_msg) {
+			smb_info->smb_state = SMB_NORMAL;
+			return;
+		}
+
+		smb_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		smb_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
+		smb_info->curr_msg->data_size = 2;
+
+		if (smb_smbus_write_block_data(
+		    smb_info,
+		    smb_info->curr_msg->data_size,
+		    smb_info->curr_msg->data) == 0) {
+			smb_info->smb_state = SMB_GETTING_EVENTS;
+		} else {
+			ipmi_free_smi_msg(smb_info->curr_msg);
+			smb_info->curr_msg = NULL;
+			smb_info->smb_state = SMB_NORMAL;
+			return;
+		}
+	} else {
+		smb_info->smb_state = SMB_NORMAL;
+	}
+}
+
+static void handle_transaction_done(struct smb_info *smb_info)
+{
+	struct ipmi_smi_msg *msg;
+	unsigned int  len;
+
+	if (smb_info->smb_debug & SMB_DEBUG_STATE) {
+		printk(KERN_INFO "DONE 1: state = %d.\n", smb_info->smb_state);
+	}
+	switch (smb_info->smb_state) {
+	case SMB_NORMAL:
+		if (!smb_info->curr_msg)
+			break;
+
+		smb_info->curr_msg->rsp_size
+			= smb_smbus_read_block_data(
+			    smb_info,
+			    smb_info->curr_msg->rsp);
+
+		msg = smb_info->curr_msg;
+		smb_info->curr_msg = NULL;
+		deliver_recv_msg(smb_info, msg);
+		break;
+
+	case SMB_GETTING_FLAGS:
+	{
+		unsigned char msg[4];
+
+		/* We got the flags from the SMB, now handle them. */
+		len = smb_smbus_read_block_data(smb_info, msg);
+		if (len < 0) {
+			/* Error fetching flags, just give up for  now. */
+			smb_info->smb_state = SMB_NORMAL;
+		} else if (msg[2] != 0) {
+			/* Error fetching flags, just give up for  now. */
+			smb_info->smb_state = SMB_NORMAL;
+		} else if (len < 3) {
+			/* Hmm, no flags.  That's technically illegal, but
+			   don't use uninitialized data. */
+			smb_info->smb_state = SMB_NORMAL;
+		} else {
+			smb_info->msg_flags = msg[3];
+			handle_flags(smb_info);
+		}
+		break;
+	}
+
+	case SMB_CLEARING_FLAGS:
+	case SMB_CLEARING_FLAGS_THEN_SET_IRQ:
+	{
+		unsigned char msg[3];
+
+		/* We cleared the flags. */
+		len = smb_smbus_read_block_data(smb_info, msg);
+		if (len < 0 || msg[2] != 0) {
+			/* Error clearing flags */
+			printk(KERN_WARNING
+			       "ipmi_smb: Error clearing flags: %2.2x\n",
+			       msg[2]);
+		}
+		if (smb_info->smb_state == SMB_CLEARING_FLAGS_THEN_SET_IRQ)
+			start_enable_irq(smb_info);
+		else
+			smb_info->smb_state = SMB_NORMAL;
+		break;
+	}
+
+	case SMB_GETTING_EVENTS:
+	{
+		smb_info->curr_msg->rsp_size
+			= smb_smbus_read_block_data(smb_info,
+						    smb_info->curr_msg->rsp);
+
+		msg = smb_info->curr_msg;
+		smb_info->curr_msg = NULL;
+		if (msg->rsp_size < 0 || msg->rsp[2] != 0) {
+			/* Error getting event, probably done. */
+			msg->done(msg);
+
+			/* Take off the event flag. */
+			smb_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
+		} else {
+			deliver_recv_msg(smb_info, msg);
+		}
+		handle_flags(smb_info);
+		break;
+	}
+
+	case SMB_GETTING_MESSAGES:
+	{
+		smb_info->curr_msg->rsp_size
+			= smb_smbus_read_block_data(smb_info,
+						      smb_info->curr_msg->rsp);
+
+		msg = smb_info->curr_msg;
+		smb_info->curr_msg = NULL;
+		if (msg->rsp_size < 0 || msg->rsp[2] != 0) {
+			/* Error getting event, probably done. */
+			msg->done(msg);
+
+			/* Take off the msg flag. */
+			smb_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
+		} else {
+			deliver_recv_msg(smb_info, msg);
+		}
+		handle_flags(smb_info);
+		break;
+	}
+
+	case SMB_ENABLE_INTERRUPTS1:
+	{
+		unsigned char msg[4];
+
+		/* We got the flags from the SMB, now handle them. */
+		len = smb_smbus_read_block_data(smb_info, msg);
+		if (len < 0 || msg[2] != 0) {
+			printk(KERN_WARNING
+			       "ipmi_smb: Could not enable interrupts"
+			       ", failed get, using polled mode.\n");
+			smb_info->smb_state = SMB_NORMAL;
+		} else {
+			msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+			msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
+			msg[2] = msg[3] | 1; /* enable msg queue int */
+			if (smb_smbus_write_block_data(
+			    smb_info,3, msg) == 0) {
+				smb_info->smb_state = SMB_ENABLE_INTERRUPTS2;
+			} else
+				smb_info->smb_state = SMB_NORMAL;
+		}
+		break;
+	}
+
+	case SMB_ENABLE_INTERRUPTS2:
+	{
+		unsigned char msg[4];
+
+		/* We got the flags from the SMB, now handle them. */
+		len = smb_smbus_read_block_data(smb_info, msg);
+		if (len < 0 || msg[2] != 0) {
+			printk(KERN_WARNING
+			       "ipmi_smb: Could not enable interrupts"
+			       ", failed set, using polled mode.\n");
+		}
+		smb_info->smb_state = SMB_NORMAL;
+		break;
+	}
+	}
+	if (smb_info->smb_debug & SMB_DEBUG_STATE) {
+		printk(KERN_INFO "DONE 2: state = %d.\n", smb_info->smb_state);
+	}
+}
+
+/*
+ * smb_event_handler must have a user context for calls to lm_sensors'
+ * SMBus interface
+ */
+static void smb_event_handler(struct smb_info *smb_info)
+{
+	s32 rv;
+	if (smb_info->smb_debug & SMB_DEBUG_STATE) {
+		printk(KERN_INFO "smb_event_handler: state = %d.\n",
+		       smb_info->smb_state);
+	}
+	if (smb_info->smb_state == SMB_NORMAL) {
+		if (smb_info->curr_msg != NULL)
+		{
+			handle_transaction_done(smb_info);
+		} else {
+			/* If we are currently idle, try to start the
+			 * next message. */
+			send_next_msg(smb_info);
+		}
+	} else {
+		handle_transaction_done(smb_info);
+	}
+
+	if (smb_info->smb_state == SMB_NORMAL &&
+	    smb_info->curr_msg == NULL &&
+	     atomic_read(&smb_info->req_events))
+	{
+		/* We are idle and the upper layer requested that I fetch
+		   events, so do so. */
+		unsigned char msg[2];
+
+		atomic_set(&smb_info->req_events, 0);
+		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		msg[1] = IPMI_GET_MSG_FLAGS_CMD;
+
+		rv = smb_smbus_write_block_data(smb_info, 2, msg);
+		if(rv == 0) {
+			smb_info->smb_state = SMB_GETTING_FLAGS;
+		}
+	}
+}
+
+#ifdef REGISTER_SMI
+static void sender(void                *send_info,
+		   struct ipmi_smi_msg *msg,
+		   int                 priority)
+{
+	struct smb_info *smb_info = (struct smb_info *) send_info;
+
+#ifdef CONFIG_IPMI_PANIC_EVENT
+	if (smb_info->run_to_completion) {
+		/* If we are running to completion, then throw it in
+		   the list and run transactions until everything is
+		   clear.  Priority doesn't matter here. */
+		list_add_tail(&(msg->link), &(smb_info->xmit_msgs));
+
+		smb_event_handler(smb_info);
+		while  (! SMB_IDLE(smb_info)) {
+			smb_event_handler(smb_info);
+		}
+		return;
+	}
+#endif
+	if (smb_info->smb_debug & SMB_DEBUG_TIMING) {
+		struct timeval     t;
+		do_gettimeofday(&t);
+		printk(KERN_INFO
+		       "**Enqueue %02x %02x: %ld.%6.6ld\n",
+		       msg->data[0], msg->data[1], t.tv_sec, t.tv_usec);
+	}
+
+	spin_lock(&(smb_info->msg_lock));
+	if (priority > 0) {
+		list_add_tail(&(msg->link), &(smb_info->hp_xmit_msgs));
+	} else {
+		list_add_tail(&(msg->link), &(smb_info->xmit_msgs));
+	}
+	spin_unlock(&(smb_info->msg_lock));
+
+#ifdef SMB_KTHREAD
+	wake_up_interruptible(&smb_info->smb_thread.queue);
+#endif
+}
+
+static void request_events(void *send_info)
+{
+	struct smb_info *smb_info = (struct smb_info *) send_info;
+
+	atomic_set(&smb_info->req_events, 1);
+#ifdef SMB_KTHREAD
+	wake_up_interruptible(&smb_info->smb_thread.queue);
+#endif
+}
+
+static void set_run_to_completion(void *send_info, int i_run_to_completion)
+{
+#ifdef CONFIG_IPMI_PANIC_EVENT
+	struct smb_info *smb_info = (struct smb_info *) send_info;
+
+	smb_info->run_to_completion = i_run_to_completion;
+	/* Note that if this does not compile, there are some I2C
+	   changes that you need to handle this properly. */
+	i2c_set_spin_delay(i_run_to_completion);
+	if (i_run_to_completion) {
+		smb_event_handler(smb_info);
+		while  (! SMB_IDLE(smb_info)) {
+			smb_event_handler(smb_info);
+		}
+	}
+#endif
+}
+
+static struct ipmi_smi_handlers handlers =
+{
+	.owner                 = THIS_MODULE,
+	.sender		       = sender,
+	.request_events        = request_events,
+	.set_run_to_completion = set_run_to_completion
+};
+#endif	/* REGISTER_SMI */
+
+#ifdef SMB_KTHREAD
+/* initialize new created thread. Called by the new thread. */
+static void init_kthread(kthread_t *kthread, char *name)
+{
+        /* lock the kernel. A new kernel thread starts without
+           the big kernel lock, regardless of the lock state
+           of the creator (the lock level is *not* inheritated)
+        */
+        lock_kernel();
+
+        /* fill in thread structure */
+        kthread->thread = current;
+
+        /* set signal mask to what we want to respond */
+        siginitsetinv(&current->blocked,
+		      sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));
+
+        /* initialise wait queue */
+        init_waitqueue_head(&kthread->queue);
+
+        /* initialise termination flag */
+        kthread->terminate = 0;
+
+        /* set name of this process (max 15 chars + 0 !) */
+        sprintf(current->comm, name);
+
+        /* let others run */
+        unlock_kernel();
+
+        /* tell the creator that we are ready and let him continue */
+        up(&kthread->startstop_sem);
+
+}
+
+/* cleanup of thread. Called by the exiting thread. */
+static void exit_kthread(kthread_t *kthread)
+{
+        /* we are terminating */
+
+	/* lock the kernel, the exit will unlock it */
+        lock_kernel();
+        kthread->thread = NULL;
+        mb();
+
+        /* notify the stop_kthread() routine that we are terminating. */
+	up(&kthread->startstop_sem);
+	/* the kernel_thread that called clone() does a do_exit here. */
+
+	/* there is no race here between execution of the "killer" and
+	   real termination of the thread (race window between up and
+	   do_exit), since both the thread and the "killer" function
+	   are running with the kernel lock held.  The kernel lock
+	   will be freed after the thread exited, so the code is
+	   really not executed anymore as soon as the unload functions
+	   gets the kernel lock back.  The init process may not have
+	   made the cleanup of the process here, but the cleanup can
+	   be done safely with the module unloaded.
+ 	*/
+
+}
+
+/* this is the thread function for making SMBus function calls into
+ * the lm_sensors' i2c-core module */
+static int smb_thread(void *data)
+{
+	struct smb_info *smb_info = data;
+        kthread_t *kthread = &smb_info->smb_thread;
+	/* setup the thread environment */
+        init_kthread(kthread, "IPMI SMBus thread");
+
+        /* an endless loop in which we are doing our work */
+        for(;;)
+        {
+ 		smb_event_handler(smb_info);
+		while  (! SMB_IDLE(smb_info)) {
+			smb_event_handler(smb_info);
+		}
+
+                interruptible_sleep_on(&kthread->queue);
+		if (! send_next_msg(smb_info)) {
+			interruptible_sleep_on(&kthread->queue);
+		}
+
+                /* We need to do a memory barrier here to be sure that
+                   the flags are visible on all CPUs.
+                */
+                 mb();
+
+                /* here we are back from sleep, either due to the timeout
+                   (one second), or because we caught a signal.
+                */
+                if (kthread->terminate)
+                {
+                        /* we received a request to terminate ourself */
+                        break;
+                }
+         }
+
+        /* cleanup the thread, leave */
+        exit_kthread(kthread);
+
+	/* returning from the thread here calls the exit functions */
+	return 0;
+}
+
+/* create a new kernel thread. Called by the creator. */
+static void start_kthread(struct smb_info *smb_info)
+{
+       kthread_t *kthread = &smb_info->smb_thread;
+        /* initialize the semaphore:
+           we start with the semaphore locked. The new kernel
+           thread will setup its stuff and unlock it. This
+           control flow (the one that creates the thread) blocks
+           in the down operation below until the thread has reached
+           the up() operation.
+         */
+        init_MUTEX_LOCKED(&kthread->startstop_sem);
+
+        kernel_thread(smb_thread, smb_info, 0);
+
+        /* wait till it has reached the setup_thread routine */
+        down(&kthread->startstop_sem);
+
+}
+
+/* stop a kernel thread. Called by the removing instance */
+static void stop_kthread(kthread_t *kthread)
+{
+        if (kthread->thread == NULL)
+        {
+                printk(KERN_WARNING
+		       "stop_kthread: killing non existing thread!\n");
+                return;
+        }
+
+        /* this function needs to be protected with the big
+	   kernel lock (lock_kernel()). The lock must be
+           grabbed before changing the terminate
+	   flag and released after the down() call. */
+        lock_kernel();
+
+        /* initialize the semaphore. We lock it here, the
+           leave_thread call of the thread to be terminated
+           will unlock it. As soon as we see the semaphore
+           unlocked, we know that the thread has exited.
+	*/
+        init_MUTEX_LOCKED(&kthread->startstop_sem);
+
+        /* We need to do a memory barrier here to be sure that
+           the flags are visible on all CPUs.
+        */
+        mb();
+
+        /* set flag to request thread termination */
+        kthread->terminate = 1;
+	wake_up_interruptible(&kthread->queue);
+
+        /* We need to do a memory barrier here to be sure that
+           the flags are visible on all CPUs.
+        */
+        mb();
+        kill_proc(kthread->thread->pid, SIGKILL, 1);
+
+        /* block till thread terminated */
+        down(&kthread->startstop_sem);
+
+        /* release the big kernel lock */
+        unlock_kernel();
+
+        /* now we are sure the thread is in zombie state. We
+           notify keventd to clean the process up.
+        */
+        kill_proc(2, SIGCHLD, 1);
+
+}
+#endif
+
+static int ipmi_smb_detect_hardware(struct i2c_client *client, int debug,
+				    struct smb_info **smb_info)
+{
+	unsigned char   msg[2];
+	unsigned char   *resp;
+	unsigned long   resp_len;
+	s32             ret;
+	struct smb_info *info;
+	int             rv = 0;
+
+	resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
+	if (!resp)
+		return -ENOMEM;
+
+	/* Do a Get Device ID command, since it comes back with some
+	   useful info. */
+	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+	msg[1] = IPMI_GET_DEVICE_ID_CMD;
+
+	ret = smbus_client_write_block_data(client, debug, 2, msg);
+	if (ret) {
+		rv = -ENODEV;
+		goto out;
+	}
+
+	/* Otherwise, we got some data. */
+	resp_len = smbus_client_read_block_data(client, debug, resp);
+	if (resp_len < 6) {
+		/* That's odd, it should be longer. */
+		rv = -EINVAL;
+		goto out;
+	}
+
+	if ((resp[1] != IPMI_GET_DEVICE_ID_CMD) || (resp[2] != 0)) {
+		/* That's odd, it shouldn't be able to fail. */
+		rv = -EINVAL;
+		goto out;
+	}
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		rv = -ENOMEM;
+		goto out;
+	}
+	memset(info, 0, sizeof(*info));
+
+	info->ipmi_smb_dev_rev = resp[4] & 0xf;
+	info->ipmi_smb_fw_rev_major = resp[5] & 0x7f;
+	info->ipmi_smb_fw_rev_minor = resp[6];
+	info->ipmi_version_major = resp[7] & 0xf;
+	info->ipmi_version_minor = resp[7] >> 4;
+	info->client = *client;
+	i2c_set_clientdata(&info->client, info);
+	info->smb_debug = debug;
+
+	*smb_info = info;
+
+ out:
+	kfree(resp);
+	return rv;
+}
+
+#define MAX_SMB_BMCS 4
+/* no expressions allowed in __MODULE_STRING */
+#define MAX_SMB_ADDR_PAIRS	8
+
+/* An array of SMB interfaces. */
+static struct smb_info *smb_infos[MAX_SMB_BMCS];
+
+/*
+ * An array of pairs of numbers to specify where specific BMCs exist.
+ * Each pair specifies the adapter number and address on the adapter.
+ * A BMC will be forced at that position.
+ *
+ * Always provide the i2c address if it is known.
+ */
+/* force list has 3 entries - 0:bus/adapter no 1: i2c addr 2: unknown/unused */
+#define	FORCE_LIST_ENTRIES	3
+static unsigned short __initdata addr[MAX_SMB_BMCS*2];
+static int num_addrs = 0;
+static unsigned short smb_force_list[MAX_SMB_BMCS*FORCE_LIST_ENTRIES + FORCE_LIST_ENTRIES];
+
+module_param_array(addr, ushort, num_addrs, 0);
+
+/*
+ * If this is sent, don't probe for adapters anywhere but where the
+ * addr array gives.
+ */
+static int smb_defaultprobe = 1;
+module_param_named(defaultprobe, smb_defaultprobe, int, 0);
+
+/*
+ * Turn debugging on for specific BMCs.  This array is indexed by
+ * BMC number.
+ *
+ * Debug bit flags: IPMI messages: 1, driver state: 2, msg timing: 4
+ */
+static int dbg[MAX_SMB_BMCS];
+static int num_dbg = 0;
+module_param_array(dbg, int, num_dbg, 0);
+
+/*
+ * Debug the probing of adapters.
+ */
+static int smb_dbg_probe = 0;
+module_param_named(dbg_probe, smb_dbg_probe, int, 0);
+
+#define SMB_I2C_START_ADDR	0x20
+#define SMB_I2C_END_ADDR	0x4f
+static unsigned short normal_i2c[] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { SMB_I2C_START_ADDR,
+					     SMB_I2C_END_ADDR,
+					     I2C_CLIENT_END };
+/*
+static unsigned int normal_isa[] = { SENSORS_ISA_END };
+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
+*/
+static unsigned short reserved[] =
+{
+/* As defined by SMBus Spec. Appendix C */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x28,
+	0x37,
+/* As defined by SMBus Spec. Sect. 5.2 */
+	0x01, 0x02, 0x03, 0x04, 0x05,
+	0x06, 0x07, 0x78, 0x79, 0x7a, 0x7b,
+	0x7c, 0x7d, 0x7e, 0x7f,
+/* Common PC addresses (bad idea) */
+	0x2d, 0x48, 0x49, /* sensors */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* eeproms */
+	0x69, /* clock chips */
+
+	I2C_CLIENT_END
+};
+
+static unsigned short smb_empty_list[] = { I2C_CLIENT_END, I2C_CLIENT_END };
+
+static struct i2c_client_address_data smb_address_data = {
+	.normal_i2c 		= normal_i2c,
+	.normal_i2c_range	= normal_i2c_range,
+	.probe			= smb_empty_list,
+	.probe_range		= smb_empty_list,
+	.ignore			= reserved,
+	.ignore_range		= smb_empty_list,
+	.force			= smb_force_list,
+};
+
+static unsigned int pos_reserved_as(int pos)
+{
+	if (addr[pos*2+1] != 0)
+		return (addr[pos*2] << 16) | addr[pos*2+1];
+
+	return 0;
+}
+
+static int smb_found_addr_proc(struct i2c_adapter *adapter, int addr, int kind)
+{
+	int id = i2c_adapter_id(adapter);
+	int debug = dbg[id];
+	int rv;
+	int i;
+	int next_pos;
+	struct i2c_client client;
+	struct smb_info *smb_info;
+
+	if( id >= MAX_SMB_BMCS )
+		return 0;
+	memset(&client, 0, sizeof(&client));
+	strcpy(client.name, "IPMI");
+	client.addr = addr;
+	client.adapter = adapter;
+
+	rv = ipmi_smb_detect_hardware(&client, debug, &smb_info);
+	if (rv) {
+		if (smb_dbg_probe) {
+			printk(KERN_INFO
+			       "smb_found_addr_proc:No IPMI client 0x%x: %d\n",
+			       addr, rv);
+		}
+		return 0;
+	}
+
+	if (smb_dbg_probe) {
+		printk(KERN_INFO
+		       "smb_found_addr_proc: i2c_probe found device at"
+		       " i2c address %x\n", addr);
+	}
+
+	spin_lock_init(&(smb_info->msg_lock));
+	INIT_LIST_HEAD(&(smb_info->xmit_msgs));
+	INIT_LIST_HEAD(&(smb_info->hp_xmit_msgs));
+	smb_info->curr_msg = NULL;
+	atomic_set(&smb_info->req_events, 0);
+#ifdef CONFIG_IPMI_PANIC_EVENT
+	smb_info->run_to_completion = 0;
+#endif
+	smb_info->smb_state = SMB_NORMAL;
+
+	next_pos = -1;
+	for (i=0; i < MAX_SMB_BMCS; i++) {
+		unsigned int res = pos_reserved_as(i);
+
+		if (res == ((id << 16) | addr)) {
+			/* We have a reserved position, use it. */
+			next_pos = i;
+			break;
+		}
+
+		/* Claim the first unused position */
+		if (!res && (next_pos == -1) && (smb_infos[next_pos] == NULL))
+			next_pos = i;
+	}
+	if (next_pos == -1) {
+		rv = -EBUSY;
+		goto out_err;
+	}
+
+	rv = i2c_attach_client(&smb_info->client);
+	if (rv) {
+		printk(KERN_ERR
+		       "smb_found_one_addr_proc:"
+		       " Unable to attach i2c client: error %d\n",
+		       rv);
+		goto out_err;
+	}
+
+	smb_info->pos = next_pos;
+	smb_infos[next_pos] = smb_info;
+
+#ifdef SMB_KTHREAD
+	start_kthread(smb_info);
+#endif
+
+#ifdef REGISTER_SMI
+	rv = ipmi_register_smi(&handlers,
+			       smb_info,
+			       smb_info->ipmi_version_major,
+			       smb_info->ipmi_version_minor,
+			       &(smb_info->intf));
+	if (rv) {
+		i2c_detach_client(&smb_info->client);
+		smb_infos[next_pos] = NULL;
+		printk(KERN_ERR
+		       "ipmi_smb: Unable to register device: error %d\n",
+		       rv);
+		goto out_err;
+	}
+#endif
+
+	start_clear_flags(smb_info);
+	smb_event_handler(smb_info);
+
+	return addr;
+
+ out_err:
+	kfree(smb_info);
+	return 0;
+}
+
+static int attach_adapter(struct i2c_adapter *adapter)
+{
+	int id = i2c_adapter_id(adapter);
+
+	if (smb_dbg_probe) {
+		printk(KERN_INFO "init_one_smb: Checking SMBus adapter %d:"
+		       " %s\n", id, adapter->name);
+	}
+	if ((i2c_get_functionality(adapter) & (I2C_FUNC_SMBUS_BLOCK_DATA))
+	    == (I2C_FUNC_SMBUS_BLOCK_DATA))
+	{
+		if (smb_dbg_probe) {
+			printk(KERN_INFO "init_one_smb: found SMBus adapter:"
+			       " %s\n", adapter->name);
+		}
+		i2c_probe(adapter, &smb_address_data, smb_found_addr_proc);
+	}
+
+	return 0;
+}
+
+void cleanup_one_smb(struct smb_info *to_clean)
+{
+	int rv;
+
+	if (! to_clean)
+		return;
+
+#ifdef SMB_KTHREAD
+	stop_kthread(&to_clean->smb_thread);
+#endif
+
+#ifdef REGISTER_SMI
+	rv = ipmi_unregister_smi(to_clean->intf);
+	if (rv) {
+		printk(KERN_ERR
+		       "ipmi_smb: Unable to unregister device: errno=%d\n",
+		       rv);
+	}
+#endif
+
+	rv = i2c_detach_client(&to_clean->client);
+	if (rv) {
+		printk(KERN_ERR
+		       "ipmi_smb: Unable to detach SMBUS client: errno=%d\n",
+		       rv);
+	}
+
+	smb_infos[to_clean->pos] = NULL;
+	kfree(to_clean);
+}
+
+static int detach_client(struct i2c_client *client)
+{
+	struct smb_info *smb_info = i2c_get_clientdata(client);
+
+	cleanup_one_smb(smb_info);
+
+	return(0);
+}
+
+static struct i2c_driver smb_i2c_driver =
+{
+	.name = "IPMI",
+	.flags = I2C_DF_NOTIFY,
+	.attach_adapter = attach_adapter,
+	.detach_client = detach_client,
+	.command = NULL,
+};
+
+static __init int init_ipmi_smb(void)
+{
+	int i;
+	int rv;
+
+	if (initialized)
+		return 0;
+
+	printk(KERN_INFO "IPMI SMB Interface driver version "
+	       IPMI_SMB_VERSION "\n");
+
+	/* build force list from addr list */
+	for (i=0; i<MAX_SMB_BMCS; i++) {
+		if (addr[i*2+1] == 0)
+			break;
+		smb_force_list[i*FORCE_LIST_ENTRIES] = addr[i*2];
+		smb_force_list[i*FORCE_LIST_ENTRIES+1] = addr[i*2+1];
+	}
+	smb_force_list[i*FORCE_LIST_ENTRIES] = I2C_CLIENT_END;
+	smb_force_list[i*FORCE_LIST_ENTRIES+1] = I2C_CLIENT_END;
+
+	/* If the default probing is turned off, then disable the
+	 * range scanning. */
+	if (!smb_defaultprobe)
+		normal_i2c_range[0] = I2C_CLIENT_END;
+
+	rv = i2c_add_driver(&smb_i2c_driver);
+	if (!rv)
+		initialized = 1;
+
+	return rv;
+}
+module_init(init_ipmi_smb);
+
+static __exit void cleanup_ipmi_smb(void)
+{
+	int i;
+	int rv;
+
+	if (!initialized)
+		return;
+
+	for (i=0; i<MAX_SMB_BMCS; i++) {
+		cleanup_one_smb(smb_infos[i]);
+	}
+
+	initialized = 0;
+
+	rv = i2c_del_driver(&smb_i2c_driver);
+	if (!rv)
+		initialized = 0;
+}
+module_exit(cleanup_ipmi_smb);
+
+MODULE_AUTHOR("Todd C Davis <todd.c.davis@intel.com>");
+MODULE_DESCRIPTION("IPMI system interface driver for management controllers on a SMBus");
+MODULE_LICENSE("GPL");
--- diff/drivers/char/ipmi/ipmi_smic_sm.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/char/ipmi/ipmi_smic_sm.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,601 @@
+/*
+ * ipmi_smic_sm.c
+ *
+ * The state-machine driver for an IPMI SMIC driver
+ *
+ * It started as a copy of Corey Minyard's driver for the KSC interface
+ * and the kernel patch "mmcdev-patch-245" by HP
+ *
+ * modified by:	Hannes Schulz <schulz@schwaar.com>
+ *		ipmi@schwaar.com
+ *
+ *
+ * Corey Minyard's driver for the KSC interface has the following
+ * copyright notice:
+ *   Copyright 2002 MontaVista Software Inc.
+ *
+ * the kernel patch "mmcdev-patch-245" by HP has the following
+ * copyright notice:
+ * (c) Copyright 2001 Grant Grundler (c) Copyright
+ * 2001 Hewlett-Packard Company
+ *
+ *
+ *  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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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/types.h>
+
+#include <linux/kernel.h> /* For printk. */
+#include <linux/string.h>
+#include <linux/ipmi_msgdefs.h>		/* for completion codes */
+#include "ipmi_si_sm.h"
+
+#define IPMI_SMIC_VERSION "v31"
+
+/* smic_debug is a bit-field
+ *	SMIC_DEBUG_ENABLE -	turned on for now
+ *	SMIC_DEBUG_MSG -	commands and their responses
+ *	SMIC_DEBUG_STATES -	state machine
+*/
+#define SMIC_DEBUG_STATES	4
+#define SMIC_DEBUG_MSG		2
+#define	SMIC_DEBUG_ENABLE	1
+
+static int smic_debug = 1;
+
+enum smic_states {
+	SMIC_IDLE,
+	SMIC_START_OP,
+	SMIC_OP_OK,
+	SMIC_WRITE_START,
+	SMIC_WRITE_NEXT,
+	SMIC_WRITE_END,
+	SMIC_WRITE2READ,
+	SMIC_READ_START,
+	SMIC_READ_NEXT,
+	SMIC_READ_END,
+	SMIC_HOSED
+};
+
+#define MAX_SMIC_READ_SIZE 80
+#define MAX_SMIC_WRITE_SIZE 80
+#define SMIC_MAX_ERROR_RETRIES 3
+
+/* Timeouts in microseconds. */
+#define SMIC_RETRY_TIMEOUT 100000
+
+/* SMIC Flags Register Bits */
+#define SMIC_RX_DATA_READY	0x80
+#define SMIC_TX_DATA_READY	0x40
+#define SMIC_SMI		0x10
+#define SMIC_EVM_DATA_AVAIL	0x08
+#define SMIC_SMS_DATA_AVAIL	0x04
+#define SMIC_FLAG_BSY		0x01
+
+/* SMIC Error Codes */
+#define	EC_NO_ERROR		0x00
+#define	EC_ABORTED		0x01
+#define	EC_ILLEGAL_CONTROL	0x02
+#define	EC_NO_RESPONSE		0x03
+#define	EC_ILLEGAL_COMMAND	0x04
+#define	EC_BUFFER_FULL		0x05
+
+struct si_sm_data
+{
+	enum smic_states state;
+	struct si_sm_io *io;
+        unsigned char	 write_data[MAX_SMIC_WRITE_SIZE];
+        int		 write_pos;
+        int		 write_count;
+        int		 orig_write_count;
+        unsigned char	 read_data[MAX_SMIC_READ_SIZE];
+        int		 read_pos;
+        int		 truncated;
+        unsigned int	 error_retries;
+        long		 smic_timeout;
+};
+
+static unsigned int init_smic_data (struct si_sm_data *smic,
+				    struct si_sm_io *io)
+{
+	smic->state = SMIC_IDLE;
+	smic->io = io;
+	smic->write_pos = 0;
+	smic->write_count = 0;
+	smic->orig_write_count = 0;
+	smic->read_pos = 0;
+	smic->error_retries = 0;
+	smic->truncated = 0;
+	smic->smic_timeout = SMIC_RETRY_TIMEOUT;
+
+	/* We use 3 bytes of I/O. */
+	return 3;
+}
+
+static int start_smic_transaction(struct si_sm_data *smic,
+				  unsigned char *data, unsigned int size)
+{
+	unsigned int i;
+
+	if ((size < 2) || (size > MAX_SMIC_WRITE_SIZE)) {
+		return -1;
+	}
+	if ((smic->state != SMIC_IDLE) && (smic->state != SMIC_HOSED)) {
+		return -2;
+	}
+	if (smic_debug & SMIC_DEBUG_MSG) {
+		printk(KERN_INFO "start_smic_transaction -");
+		for (i = 0; i < size; i ++) {
+			printk (" %02x", (unsigned char) (data [i]));
+		}
+		printk ("\n");
+	}
+	smic->error_retries = 0;
+	memcpy(smic->write_data, data, size);
+	smic->write_count = size;
+	smic->orig_write_count = size;
+	smic->write_pos = 0;
+	smic->read_pos = 0;
+	smic->state = SMIC_START_OP;
+	smic->smic_timeout = SMIC_RETRY_TIMEOUT;
+	return 0;
+}
+
+static int smic_get_result(struct si_sm_data *smic,
+			   unsigned char *data, unsigned int length)
+{
+	int i;
+
+	if (smic_debug & SMIC_DEBUG_MSG) {
+		printk (KERN_INFO "smic_get result -");
+		for (i = 0; i < smic->read_pos; i ++) {
+			printk (" %02x", (smic->read_data [i]));
+		}
+		printk ("\n");
+	}
+	if (length < smic->read_pos) {
+		smic->read_pos = length;
+		smic->truncated = 1;
+	}
+	memcpy(data, smic->read_data, smic->read_pos);
+
+	if ((length >= 3) && (smic->read_pos < 3)) {
+		data[2] = IPMI_ERR_UNSPECIFIED;
+		smic->read_pos = 3;
+	}
+	if (smic->truncated) {
+		data[2] = IPMI_ERR_MSG_TRUNCATED;
+		smic->truncated = 0;
+	}
+	return smic->read_pos;
+}
+
+static inline unsigned char read_smic_flags(struct si_sm_data *smic)
+{
+	return smic->io->inputb(smic->io, 2);
+}
+
+static inline unsigned char read_smic_status(struct si_sm_data *smic)
+{
+	return smic->io->inputb(smic->io, 1);
+}
+
+static inline unsigned char read_smic_data(struct si_sm_data *smic)
+{
+	return smic->io->inputb(smic->io, 0);
+}
+
+static inline void write_smic_flags(struct si_sm_data *smic,
+				    unsigned char   flags)
+{
+	smic->io->outputb(smic->io, 2, flags);
+}
+
+static inline void write_smic_control(struct si_sm_data *smic,
+				      unsigned char   control)
+{
+	smic->io->outputb(smic->io, 1, control);
+}
+
+static inline void write_si_sm_data (struct si_sm_data *smic,
+				   unsigned char   data)
+{
+	smic->io->outputb(smic->io, 0, data);
+}
+
+static inline void start_error_recovery(struct si_sm_data *smic, char *reason)
+{
+	(smic->error_retries)++;
+	if (smic->error_retries > SMIC_MAX_ERROR_RETRIES) {
+		if (smic_debug & SMIC_DEBUG_ENABLE) {
+			printk(KERN_WARNING
+			       "ipmi_smic_drv: smic hosed: %s\n", reason);
+		}
+		smic->state = SMIC_HOSED;
+	} else {
+		smic->write_count = smic->orig_write_count;
+		smic->write_pos = 0;
+		smic->read_pos = 0;
+		smic->state = SMIC_START_OP;
+		smic->smic_timeout = SMIC_RETRY_TIMEOUT;
+	}
+}
+
+static inline void write_next_byte(struct si_sm_data *smic)
+{
+	write_si_sm_data(smic, smic->write_data[smic->write_pos]);
+	(smic->write_pos)++;
+	(smic->write_count)--;
+}
+
+static inline void read_next_byte (struct si_sm_data *smic)
+{
+	if (smic->read_pos >= MAX_SMIC_READ_SIZE) {
+		read_smic_data (smic);
+		smic->truncated = 1;
+	} else {
+		smic->read_data[smic->read_pos] = read_smic_data(smic);
+		(smic->read_pos)++;
+	}
+}
+
+/*  SMIC Control/Status Code Components */
+#define	SMIC_GET_STATUS		0x00	/* Control form's name */
+#define	SMIC_READY		0x00	/* Status  form's name */
+#define	SMIC_WR_START		0x01	/* Unified Control/Status names... */
+#define	SMIC_WR_NEXT		0x02
+#define	SMIC_WR_END		0x03
+#define	SMIC_RD_START		0x04
+#define	SMIC_RD_NEXT		0x05
+#define	SMIC_RD_END		0x06
+#define	SMIC_CODE_MASK		0x0f
+
+#define	SMIC_CONTROL		0x00
+#define	SMIC_STATUS		0x80
+#define	SMIC_CS_MASK		0x80
+
+#define	SMIC_SMS		0x40
+#define	SMIC_SMM		0x60
+#define	SMIC_STREAM_MASK	0x60
+
+/*  SMIC Control Codes */
+#define	SMIC_CC_SMS_GET_STATUS	(SMIC_CONTROL|SMIC_SMS|SMIC_GET_STATUS)
+#define	SMIC_CC_SMS_WR_START	(SMIC_CONTROL|SMIC_SMS|SMIC_WR_START)
+#define	SMIC_CC_SMS_WR_NEXT	(SMIC_CONTROL|SMIC_SMS|SMIC_WR_NEXT)
+#define	SMIC_CC_SMS_WR_END	(SMIC_CONTROL|SMIC_SMS|SMIC_WR_END)
+#define	SMIC_CC_SMS_RD_START	(SMIC_CONTROL|SMIC_SMS|SMIC_RD_START)
+#define	SMIC_CC_SMS_RD_NEXT	(SMIC_CONTROL|SMIC_SMS|SMIC_RD_NEXT)
+#define	SMIC_CC_SMS_RD_END	(SMIC_CONTROL|SMIC_SMS|SMIC_RD_END)
+
+#define	SMIC_CC_SMM_GET_STATUS	(SMIC_CONTROL|SMIC_SMM|SMIC_GET_STATUS)
+#define	SMIC_CC_SMM_WR_START	(SMIC_CONTROL|SMIC_SMM|SMIC_WR_START)
+#define	SMIC_CC_SMM_WR_NEXT	(SMIC_CONTROL|SMIC_SMM|SMIC_WR_NEXT)
+#define	SMIC_CC_SMM_WR_END	(SMIC_CONTROL|SMIC_SMM|SMIC_WR_END)
+#define	SMIC_CC_SMM_RD_START	(SMIC_CONTROL|SMIC_SMM|SMIC_RD_START)
+#define	SMIC_CC_SMM_RD_NEXT	(SMIC_CONTROL|SMIC_SMM|SMIC_RD_NEXT)
+#define	SMIC_CC_SMM_RD_END	(SMIC_CONTROL|SMIC_SMM|SMIC_RD_END)
+
+/*  SMIC Status Codes */
+#define	SMIC_SC_SMS_READY	(SMIC_STATUS|SMIC_SMS|SMIC_READY)
+#define	SMIC_SC_SMS_WR_START	(SMIC_STATUS|SMIC_SMS|SMIC_WR_START)
+#define	SMIC_SC_SMS_WR_NEXT	(SMIC_STATUS|SMIC_SMS|SMIC_WR_NEXT)
+#define	SMIC_SC_SMS_WR_END	(SMIC_STATUS|SMIC_SMS|SMIC_WR_END)
+#define	SMIC_SC_SMS_RD_START	(SMIC_STATUS|SMIC_SMS|SMIC_RD_START)
+#define	SMIC_SC_SMS_RD_NEXT	(SMIC_STATUS|SMIC_SMS|SMIC_RD_NEXT)
+#define	SMIC_SC_SMS_RD_END	(SMIC_STATUS|SMIC_SMS|SMIC_RD_END)
+
+#define	SMIC_SC_SMM_READY	(SMIC_STATUS|SMIC_SMM|SMIC_READY)
+#define	SMIC_SC_SMM_WR_START	(SMIC_STATUS|SMIC_SMM|SMIC_WR_START)
+#define	SMIC_SC_SMM_WR_NEXT	(SMIC_STATUS|SMIC_SMM|SMIC_WR_NEXT)
+#define	SMIC_SC_SMM_WR_END	(SMIC_STATUS|SMIC_SMM|SMIC_WR_END)
+#define	SMIC_SC_SMM_RD_START	(SMIC_STATUS|SMIC_SMM|SMIC_RD_START)
+#define	SMIC_SC_SMM_RD_NEXT	(SMIC_STATUS|SMIC_SMM|SMIC_RD_NEXT)
+#define	SMIC_SC_SMM_RD_END	(SMIC_STATUS|SMIC_SMM|SMIC_RD_END)
+
+/* these are the control/status codes we actually use
+	SMIC_CC_SMS_GET_STATUS	0x40
+	SMIC_CC_SMS_WR_START	0x41
+	SMIC_CC_SMS_WR_NEXT	0x42
+	SMIC_CC_SMS_WR_END	0x43
+	SMIC_CC_SMS_RD_START	0x44
+	SMIC_CC_SMS_RD_NEXT	0x45
+	SMIC_CC_SMS_RD_END	0x46
+
+	SMIC_SC_SMS_READY	0xC0
+	SMIC_SC_SMS_WR_START	0xC1
+	SMIC_SC_SMS_WR_NEXT	0xC2
+	SMIC_SC_SMS_WR_END	0xC3
+	SMIC_SC_SMS_RD_START	0xC4
+	SMIC_SC_SMS_RD_NEXT	0xC5
+	SMIC_SC_SMS_RD_END	0xC6
+*/
+
+static enum si_sm_result smic_event (struct si_sm_data *smic, long time)
+{
+	unsigned char status;
+	unsigned char flags;
+	unsigned char data;
+
+	if (smic->state == SMIC_HOSED) {
+		init_smic_data(smic, smic->io);
+		return SI_SM_HOSED;
+	}
+	if (smic->state != SMIC_IDLE) {
+		if (smic_debug & SMIC_DEBUG_STATES) {
+			printk(KERN_INFO
+			       "smic_event - smic->smic_timeout = %ld,"
+			       " time = %ld\n",
+			       smic->smic_timeout, time);
+		}
+/* FIXME: smic_event is sometimes called with time > SMIC_RETRY_TIMEOUT */
+		if (time < SMIC_RETRY_TIMEOUT) {
+			smic->smic_timeout -= time;
+			if (smic->smic_timeout < 0) {
+				start_error_recovery(smic, "smic timed out.");
+				return SI_SM_CALL_WITH_DELAY;
+			}
+		}
+	}
+	flags = read_smic_flags(smic);
+	if (flags & SMIC_FLAG_BSY)
+		return SI_SM_CALL_WITH_DELAY;
+
+	status = read_smic_status (smic);
+	if (smic_debug & SMIC_DEBUG_STATES)
+		printk(KERN_INFO
+		       "smic_event - state = %d, flags = 0x%02x,"
+		       " status = 0x%02x\n",
+		       smic->state, flags, status);
+
+	switch (smic->state) {
+	case SMIC_IDLE:
+		/* in IDLE we check for available messages */
+		if (flags & (SMIC_SMI |
+			     SMIC_EVM_DATA_AVAIL | SMIC_SMS_DATA_AVAIL))
+		{
+			return SI_SM_ATTN;
+		}
+		return SI_SM_IDLE;
+
+	case SMIC_START_OP:
+		/* sanity check whether smic is really idle */
+		write_smic_control(smic, SMIC_CC_SMS_GET_STATUS);
+		write_smic_flags(smic, flags | SMIC_FLAG_BSY);
+		smic->state = SMIC_OP_OK;
+		break;
+
+	case SMIC_OP_OK:
+		if (status != SMIC_SC_SMS_READY) {
+				/* this should not happen */
+			start_error_recovery(smic,
+					     "state = SMIC_OP_OK,"
+					     " status != SMIC_SC_SMS_READY");
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		/* OK so far; smic is idle let us start ... */
+		write_smic_control(smic, SMIC_CC_SMS_WR_START);
+		write_next_byte(smic);
+		write_smic_flags(smic, flags | SMIC_FLAG_BSY);
+		smic->state = SMIC_WRITE_START;
+		break;
+
+	case SMIC_WRITE_START:
+		if (status != SMIC_SC_SMS_WR_START) {
+			start_error_recovery(smic,
+					     "state = SMIC_WRITE_START, "
+					     "status != SMIC_SC_SMS_WR_START");
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		/* we must not issue WR_(NEXT|END) unless
+                   TX_DATA_READY is set */
+		if (flags & SMIC_TX_DATA_READY) {
+			if (smic->write_count == 1) {
+				/* last byte */
+				write_smic_control(smic, SMIC_CC_SMS_WR_END);
+				smic->state = SMIC_WRITE_END;
+			} else {
+				write_smic_control(smic, SMIC_CC_SMS_WR_NEXT);
+				smic->state = SMIC_WRITE_NEXT;
+			}
+			write_next_byte(smic);
+			write_smic_flags(smic, flags | SMIC_FLAG_BSY);
+		}
+		else {
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		break;
+
+	case SMIC_WRITE_NEXT:
+		if (status != SMIC_SC_SMS_WR_NEXT) {
+			start_error_recovery(smic,
+					     "state = SMIC_WRITE_NEXT, "
+					     "status != SMIC_SC_SMS_WR_NEXT");
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		/* this is the same code as in SMIC_WRITE_START */
+		if (flags & SMIC_TX_DATA_READY) {
+			if (smic->write_count == 1) {
+				write_smic_control(smic, SMIC_CC_SMS_WR_END);
+				smic->state = SMIC_WRITE_END;
+			}
+			else {
+				write_smic_control(smic, SMIC_CC_SMS_WR_NEXT);
+				smic->state = SMIC_WRITE_NEXT;
+			}
+			write_next_byte(smic);
+			write_smic_flags(smic, flags | SMIC_FLAG_BSY);
+		}
+		else {
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		break;
+
+	case SMIC_WRITE_END:
+		if (status != SMIC_SC_SMS_WR_END) {
+			start_error_recovery (smic,
+					      "state = SMIC_WRITE_END, "
+					      "status != SMIC_SC_SMS_WR_END");
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		/* data register holds an error code */
+		data = read_smic_data(smic);
+		if (data != 0) {
+			if (smic_debug & SMIC_DEBUG_ENABLE) {
+				printk(KERN_INFO
+				       "SMIC_WRITE_END: data = %02x\n", data);
+			}
+			start_error_recovery(smic,
+					     "state = SMIC_WRITE_END, "
+					     "data != SUCCESS");
+			return SI_SM_CALL_WITH_DELAY;
+		} else {
+			smic->state = SMIC_WRITE2READ;
+		}
+		break;
+
+	case SMIC_WRITE2READ:
+		/* we must wait for RX_DATA_READY to be set before we
+                   can continue */
+		if (flags & SMIC_RX_DATA_READY) {
+			write_smic_control(smic, SMIC_CC_SMS_RD_START);
+			write_smic_flags(smic, flags | SMIC_FLAG_BSY);
+			smic->state = SMIC_READ_START;
+		} else {
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		break;
+
+	case SMIC_READ_START:
+		if (status != SMIC_SC_SMS_RD_START) {
+			start_error_recovery(smic,
+					     "state = SMIC_READ_START, "
+					     "status != SMIC_SC_SMS_RD_START");
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		if (flags & SMIC_RX_DATA_READY) {
+			read_next_byte(smic);
+			write_smic_control(smic, SMIC_CC_SMS_RD_NEXT);
+			write_smic_flags(smic, flags | SMIC_FLAG_BSY);
+			smic->state = SMIC_READ_NEXT;
+		} else {
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		break;
+
+	case SMIC_READ_NEXT:
+		switch (status) {
+		/* smic tells us that this is the last byte to be read
+                   --> clean up */
+		case SMIC_SC_SMS_RD_END:
+			read_next_byte(smic);
+			write_smic_control(smic, SMIC_CC_SMS_RD_END);
+			write_smic_flags(smic, flags | SMIC_FLAG_BSY);
+			smic->state = SMIC_READ_END;
+			break;
+		case SMIC_SC_SMS_RD_NEXT:
+			if (flags & SMIC_RX_DATA_READY) {
+				read_next_byte(smic);
+				write_smic_control(smic, SMIC_CC_SMS_RD_NEXT);
+				write_smic_flags(smic, flags | SMIC_FLAG_BSY);
+				smic->state = SMIC_READ_NEXT;
+			} else {
+				return SI_SM_CALL_WITH_DELAY;
+			}
+			break;
+		default:
+			start_error_recovery(
+				smic,
+				"state = SMIC_READ_NEXT, "
+				"status != SMIC_SC_SMS_RD_(NEXT|END)");
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		break;
+
+	case SMIC_READ_END:
+		if (status != SMIC_SC_SMS_READY) {
+			start_error_recovery(smic,
+					     "state = SMIC_READ_END, "
+					     "status != SMIC_SC_SMS_READY");
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		data = read_smic_data(smic);
+		/* data register holds an error code */
+		if (data != 0) {
+			if (smic_debug & SMIC_DEBUG_ENABLE) {
+				printk(KERN_INFO
+				       "SMIC_READ_END: data = %02x\n", data);
+			}
+			start_error_recovery(smic,
+					     "state = SMIC_READ_END, "
+					     "data != SUCCESS");
+			return SI_SM_CALL_WITH_DELAY;
+		} else {
+			smic->state = SMIC_IDLE;
+			return SI_SM_TRANSACTION_COMPLETE;
+		}
+
+	case SMIC_HOSED:
+		init_smic_data(smic, smic->io);
+		return SI_SM_HOSED;
+
+	default:
+		if (smic_debug & SMIC_DEBUG_ENABLE) {
+			printk(KERN_WARNING "smic->state = %d\n", smic->state);
+			start_error_recovery(smic, "state = UNKNOWN");
+			return SI_SM_CALL_WITH_DELAY;
+		}
+	}
+	smic->smic_timeout = SMIC_RETRY_TIMEOUT;
+	return SI_SM_CALL_WITHOUT_DELAY;
+}
+
+static int smic_detect(struct si_sm_data *smic)
+{
+	/* It's impossible for the SMIC fnags register to be all 1's,
+	   (assuming a properly functioning, self-initialized BMC)
+	   but that's what you get from reading a bogus address, so we
+	   test that first. */
+	if (read_smic_flags(smic) == 0xff)
+		return 1;
+
+	return 0;
+}
+
+static void smic_cleanup(struct si_sm_data *kcs)
+{
+}
+
+static int smic_size(void)
+{
+	return sizeof(struct si_sm_data);
+}
+
+struct si_sm_handlers smic_smi_handlers =
+{
+	.version           = IPMI_SMIC_VERSION,
+	.init_data         = init_smic_data,
+	.start_transaction = start_smic_transaction,
+	.get_result        = smic_get_result,
+	.event             = smic_event,
+	.detect            = smic_detect,
+	.cleanup           = smic_cleanup,
+	.size              = smic_size,
+};
--- diff/drivers/ide/pci/atiixp.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/ide/pci/atiixp.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,512 @@
+/*
+ *  linux/drivers/ide/pci/atiixp.c	Version 0.01-bart2	Feb. 26, 2004
+ *
+ *  Copyright (C) 2003 ATI Inc. <hyu@ati.com>
+ *  Copyright (C) 2004 Bartlomiej Zolnierkiewicz
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#define ATIIXP_IDE_PIO_TIMING		0x40
+#define ATIIXP_IDE_MDMA_TIMING		0x44
+#define ATIIXP_IDE_PIO_CONTROL		0x48
+#define ATIIXP_IDE_PIO_MODE		0x4a
+#define ATIIXP_IDE_UDMA_CONTROL		0x54
+#define ATIIXP_IDE_UDMA_MODE		0x56
+
+typedef struct {
+	u8 command_width;
+	u8 recover_width;
+} atiixp_ide_timing;
+
+static atiixp_ide_timing pio_timing[] = {
+	{ 0x05, 0x0d },
+	{ 0x04, 0x07 },
+	{ 0x03, 0x04 },
+	{ 0x02, 0x02 },
+	{ 0x02, 0x00 },
+};
+
+static atiixp_ide_timing mdma_timing[] = {
+	{ 0x07, 0x07 },
+	{ 0x02, 0x01 },
+	{ 0x02, 0x00 },
+};
+
+static int save_mdma_mode[4];
+
+#define DISPLAY_ATIIXP_TIMINGS
+
+#if defined(DISPLAY_ATIIXP_TIMINGS) && defined(CONFIG_PROC_FS)
+
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 atiixp_proc;
+static struct pci_dev *bmide_dev;
+
+/**
+ *	atiixp_get_info		-	fill in /proc for ATIIXP IDE
+ *	@buffer: buffer to fill
+ *	@addr: address of user start in buffer
+ *	@offset: offset into 'file'
+ *	@count: buffer count
+ *
+ *	Output summary data on the tuning.
+ */
+
+static int atiixp_get_info(char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	struct pci_dev *dev = bmide_dev;
+	unsigned long bibma = pci_resource_start(dev, 4);
+	u32 mdma_timing = 0;
+	u16 udma_mode = 0, pio_mode = 0;
+	u8 c0, c1, udma_control = 0;
+
+	p += sprintf(p, "\n                          ATI ");
+	p += sprintf(p, "ATIIXP Ultra100 IDE Chipset.\n");
+
+	pci_read_config_byte(dev, ATIIXP_IDE_UDMA_CONTROL, &udma_control);
+	pci_read_config_word(dev, ATIIXP_IDE_UDMA_MODE, &udma_mode);
+	pci_read_config_word(dev, ATIIXP_IDE_PIO_MODE, &pio_mode);
+	pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &mdma_timing);
+
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte registers
+	 * to investigate:
+	 */
+	c0 = inb(bibma + 0x02);
+	c1 = inb(bibma + 0x0a);
+
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled "
+			"                        %sabled\n",
+			(c0 & 0x80) ? "dis" : " en",
+			(c1 & 0x80) ? "dis" : " en");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s "
+			"            %s               %s\n",
+			(c0 & 0x20) ? "yes" : "no ",
+			(c0 & 0x40) ? "yes" : "no ",
+			(c1 & 0x20) ? "yes" : "no ",
+			(c1 & 0x40) ? "yes" : "no " );
+	p += sprintf(p, "UDMA enabled:   %s              %s "
+			"            %s               %s\n",
+			(udma_control & 0x01) ? "yes" : "no ",
+			(udma_control & 0x02) ? "yes" : "no ",
+			(udma_control & 0x04) ? "yes" : "no ",
+			(udma_control & 0x08) ? "yes" : "no " );
+	p += sprintf(p, "UDMA mode:      %c                %c "
+			"              %c                 %c\n",
+			(udma_control & 0x01) ?
+			((udma_mode & 0x07) + 48) : 'X',
+			(udma_control & 0x02) ?
+			(((udma_mode >> 4) & 0x07) + 48) : 'X',
+			(udma_control & 0x04) ?
+			(((udma_mode >> 8) & 0x07) + 48) : 'X',
+			(udma_control & 0x08) ?
+			(((udma_mode >> 12) & 0x07) + 48) : 'X');
+	p += sprintf(p, "MDMA mode:      %c                %c "
+			"              %c                 %c\n",
+			(save_mdma_mode[0] && (c0 & 0x20)) ?
+			((save_mdma_mode[0] & 0xf) + 48) : 'X',
+			(save_mdma_mode[1] && (c0 & 0x40)) ?
+			((save_mdma_mode[1] & 0xf) + 48) : 'X',
+			(save_mdma_mode[2] && (c1 & 0x20)) ?
+			((save_mdma_mode[2] & 0xf) + 48) : 'X',
+			(save_mdma_mode[3] && (c1 & 0x40)) ?
+			((save_mdma_mode[3] & 0xf) + 48) : 'X');
+	p += sprintf(p, "PIO mode:       %c                %c "
+			"              %c                 %c\n",
+			(c0 & 0x20) ? 'X' : ((pio_mode & 0x07) + 48),
+			(c0 & 0x40) ? 'X' : (((pio_mode >> 4) & 0x07) + 48),
+			(c1 & 0x20) ? 'X' : (((pio_mode >> 8) & 0x07) + 48),
+			(c1 & 0x40) ? 'X' : (((pio_mode >> 12) & 0x07) + 48));
+
+	return p - buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_ATIIXP_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/**
+ *	atiixp_ratemask		-	compute rate mask for ATIIXP IDE
+ *	@drive: IDE drive to compute for
+ *
+ *	Returns the available modes for the ATIIXP IDE controller.
+ */
+
+static u8 atiixp_ratemask(ide_drive_t *drive)
+{
+	u8 mode = 3;
+
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+/**
+ *	atiixp_dma_2_pio		-	return the PIO mode matching DMA
+ *	@xfer_rate: transfer speed
+ *
+ *	Returns the nearest equivalent PIO timing for the PIO or DMA
+ *	mode requested by the controller.
+ */
+
+static u8 atiixp_dma_2_pio(u8 xfer_rate) {
+	switch(xfer_rate) {
+		case XFER_UDMA_6:
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
+}
+
+static int atiixp_ide_dma_host_on(ide_drive_t *drive)
+{
+	struct pci_dev *dev = drive->hwif->pci_dev;
+	unsigned long flags;
+	u16 tmp16;
+
+	spin_lock_irqsave(&ide_lock, flags);
+
+	pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
+	if (save_mdma_mode[drive->dn])
+		tmp16 &= ~(1 << drive->dn);
+	else
+		tmp16 |= (1 << drive->dn);
+	pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
+
+	spin_unlock_irqrestore(&ide_lock, flags);
+
+	return __ide_dma_host_on(drive);
+}
+
+static int atiixp_ide_dma_host_off(ide_drive_t *drive)
+{
+	struct pci_dev *dev = drive->hwif->pci_dev;
+	unsigned long flags;
+	u16 tmp16;
+
+	spin_lock_irqsave(&ide_lock, flags);
+
+	pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
+	tmp16 &= ~(1 << drive->dn);
+	pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
+
+	spin_unlock_irqrestore(&ide_lock, flags);
+
+	return __ide_dma_host_off(drive);
+}
+
+/**
+ *	atiixp_tune_drive		-	tune a drive attached to a ATIIXP
+ *	@drive: drive to tune
+ *	@pio: desired PIO mode
+ *
+ *	Set the interface PIO mode.
+ */
+
+static void atiixp_tuneproc(ide_drive_t *drive, u8 pio)
+{
+	struct pci_dev *dev = drive->hwif->pci_dev;
+	unsigned long flags;
+	int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
+	u32 pio_timing_data;
+	u16 pio_mode_data;
+
+	spin_lock_irqsave(&ide_lock, flags);
+
+	pci_read_config_word(dev, ATIIXP_IDE_PIO_MODE, &pio_mode_data);
+	pio_mode_data &= ~(0x07 << (drive->dn * 4));
+	pio_mode_data |= (pio << (drive->dn * 4));
+	pci_write_config_word(dev, ATIIXP_IDE_PIO_MODE, pio_mode_data);
+
+	pci_read_config_dword(dev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data);
+	pio_timing_data &= ~(0xff << timing_shift);
+	pio_timing_data |= (pio_timing[pio].recover_width << timing_shift) |
+		 (pio_timing[pio].command_width << (timing_shift + 4));
+	pci_write_config_dword(dev, ATIIXP_IDE_PIO_TIMING, pio_timing_data);
+
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/**
+ *	atiixp_tune_chipset	-	tune a ATIIXP interface
+ *	@drive: IDE drive to tune
+ *	@xferspeed: speed to configure
+ *
+ *	Set a ATIIXP interface channel to the desired speeds. This involves
+ *	requires the right timing data into the ATIIXP configuration space
+ *	then setting the drive parameters appropriately
+ */
+
+static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed)
+{
+	struct pci_dev *dev = drive->hwif->pci_dev;
+	unsigned long flags;
+	int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
+	u32 tmp32;
+	u16 tmp16;
+	u8 speed, pio;
+
+	speed = ide_rate_filter(atiixp_ratemask(drive), xferspeed);
+
+	spin_lock_irqsave(&ide_lock, flags);
+
+	save_mdma_mode[drive->dn] = 0;
+	if (speed >= XFER_UDMA_0) {
+		pci_read_config_word(dev, ATIIXP_IDE_UDMA_MODE, &tmp16);
+		tmp16 &= ~(0x07 << (drive->dn * 4));
+		tmp16 |= ((speed & 0x07) << (drive->dn * 4));
+		pci_write_config_word(dev, ATIIXP_IDE_UDMA_MODE, tmp16);
+	} else {
+		if ((speed >= XFER_MW_DMA_0) && (speed <= XFER_MW_DMA_2)) {
+			save_mdma_mode[drive->dn] = speed;
+			pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32);
+			tmp32 &= ~(0xff << timing_shift);
+			tmp32 |= (mdma_timing[speed & 0x03].recover_width << timing_shift) |
+				(mdma_timing[speed & 0x03].command_width << (timing_shift + 4));
+			pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32);
+		}
+	}
+
+	spin_unlock_irqrestore(&ide_lock, flags);
+
+	if (speed >= XFER_SW_DMA_0)
+		pio = atiixp_dma_2_pio(speed);
+	else
+		pio = speed - XFER_PIO_0;
+
+	atiixp_tuneproc(drive, pio);
+
+	return ide_config_drive_speed(drive, speed);
+}
+
+/**
+ *	atiixp_config_drive_for_dma	-	configure drive for DMA
+ *	@drive: IDE drive to configure
+ *
+ *	Set up a ATIIXP interface channel for the best available speed.
+ *	We prefer UDMA if it is available and then MWDMA. If DMA is
+ *	not available we switch to PIO and return 0.
+ */
+
+static int atiixp_config_drive_for_dma(ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, atiixp_ratemask(drive));
+
+	/* If no DMA speed was available then disable DMA and use PIO. */
+	if (!speed) {
+		u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
+		speed = atiixp_dma_2_pio(XFER_PIO_0 + tspeed) + XFER_PIO_0;
+	}
+
+	(void) atiixp_speedproc(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+/**
+ *	atiixp_dma_check	-	set up an IDE device
+ *	@drive: IDE drive to configure
+ *
+ *	Set up the ATIIXP interface for the best available speed on this
+ *	interface, preferring DMA to PIO.
+ */
+
+static int atiixp_dma_check(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+	u8 tspeed, speed;
+
+	drive->init_speed = 0;
+
+	if ((id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (__ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				if ((id->field_valid & 2) &&
+				    (!atiixp_config_drive_for_dma(drive)))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!atiixp_config_drive_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (__ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!atiixp_config_drive_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+		return hwif->ide_dma_on(drive);
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
+		speed = atiixp_dma_2_pio(XFER_PIO_0 + tspeed) + XFER_PIO_0;
+		hwif->speedproc(drive, speed);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	/* IORDY not supported */
+	return 0;
+}
+
+/**
+ *	init_chipset_atiixp	-	set up the ATIIXP chipset
+ *	@dev: PCI device to set up
+ *	@name: Name of the device
+ *
+ *	Initialize the PCI device as required. For the ATIIXP this turns
+ *	out to be nice and simple
+ */
+
+static unsigned int __devinit init_chipset_atiixp(struct pci_dev *dev, const char *name)
+{
+#if defined(DISPLAY_ATIIXP_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!atiixp_proc) {
+		atiixp_proc = 1;
+		bmide_dev = dev;
+		ide_pci_create_host_proc("atiixp", atiixp_get_info);
+	}
+#endif /* DISPLAY_ATIIXP_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+/**
+ *	init_hwif_atiixp		-	fill in the hwif for the ATIIXP
+ *	@hwif: IDE interface
+ *
+ *	Set up the ide_hwif_t for the ATIIXP interface according to the
+ *	capabilities of the hardware.
+ */
+
+static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
+{
+	if (!hwif->irq)
+		hwif->irq = hwif->channel ? 15 : 14;
+
+	hwif->autodma = 0;
+	hwif->tuneproc = &atiixp_tuneproc;
+	hwif->speedproc = &atiixp_speedproc;
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x06;
+	hwif->swdma_mask = 0x04;
+
+	/* FIXME: proper cable detection needed */
+	hwif->udma_four = 1;
+	hwif->ide_dma_host_on = &atiixp_ide_dma_host_on;
+	hwif->ide_dma_host_off = &atiixp_ide_dma_host_off;
+	hwif->ide_dma_check = &atiixp_dma_check;
+	if (!noautodma)
+		hwif->autodma = 1;
+
+	hwif->drives[1].autodma = hwif->autodma;
+	hwif->drives[0].autodma = hwif->autodma;
+}
+
+static ide_pci_device_t atiixp_pci_info[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_ATI,
+		.device		= PCI_DEVICE_ID_ATI_IXP_IDE,
+		.name		= "ATIIXP",
+		.init_chipset	= init_chipset_atiixp,
+		.init_hwif	= init_hwif_atiixp,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
+		.bootable	= ON_BOARD,
+	}
+};
+
+/**
+ *	atiixp_init_one	-	called when a ATIIXP is found
+ *	@dev: the atiixp device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+
+static int __devinit atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &atiixp_pci_info[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	return 0;
+}
+
+static struct pci_device_id atiixp_pci_tbl[] = {
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "ATIIXP IDE",
+	.id_table	= atiixp_pci_tbl,
+	.probe		= atiixp_init_one,
+};
+
+static int atiixp_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+module_init(atiixp_ide_init);
+
+MODULE_AUTHOR("HUI YU");
+MODULE_DESCRIPTION("PCI driver module for ATI IXP IDE");
+MODULE_LICENSE("GPL");
--- diff/drivers/input/keyboard/lkkbd.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/input/keyboard/lkkbd.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,625 @@
+/*
+ *  Copyright (C) 2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
+ */
+
+/*
+ * LK keyboard driver for Linux, based on sunkbd.c (C) by Vojtech Pavlik
+ */
+
+/*
+ * DEC LK201 and LK401 keyboard driver for Linux (primary for DECstations
+ * and VAXstations, but can also be used on any standard RS232 with an
+ * adaptor).
+ *
+ * DISCLAUNER: This works for _me_. If you break anything by using the
+ * information given below, I will _not_ be lieable!
+ *
+ * RJ11 pinout:		To DB9:		Or DB25:
+ * 	1 - RxD <---->	Pin 3 (TxD) <->	Pin 2 (TxD)
+ * 	2 - GND <---->	Pin 5 (GND) <->	Pin 7 (GND)
+ * 	4 - TxD <---->	Pin 2 (RxD) <->	Pin 3 (RxD)
+ * 	3 - +12V (from HDD drive connector), DON'T connect to DB9 or DB25!!!
+ *
+ * Pin numbers for DB9 and DB25 are noted on the plug (quite small:). For
+ * RJ11, it's like this:
+ *
+ *      __=__	Hold the plug in front of you, cable downwards,
+ *     /___/|	nose is hidden behind the plug. Now, pin 1 is at
+ *    |1234||	the left side, pin 4 at the right and 2 and 3 are
+ *    |IIII||	in between, of course:)
+ *    |    ||
+ *    |____|/
+ *      ||	So the adaptor consists of three connected cables
+ *      ||	for data transmission (RxD and TxD) and signal ground.
+ *		Additionally, you have to get +12V from somewhere.
+ * Most easily, you'll get that from a floppy or HDD power connector.
+ * It's the yellow cable there (black is ground and red is +5V).
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * email or by paper mail:
+ * Jan-Benedict Glaw, Lilienstraße 16, 33790 Hörste (near Halle/Westf.),
+ * Germany.
+ */
+
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/workqueue.h>
+
+
+MODULE_AUTHOR ("Jan-Benedict Glaw <jblaw@lug-owl.de>");
+MODULE_DESCRIPTION ("LK keyboard driver");
+MODULE_LICENSE ("GPL");
+
+/*
+ * Known parameters:
+ *	bell_volume
+ *	keyclick_volume
+ *	ctrlclick_volume
+ *
+ * Please notice that there's not yet an API to set these at runtime.
+ */
+static int bell_volume = 100; /* % */
+module_param (bell_volume, int, 0);
+MODULE_PARM_DESC (bell_volume, "Bell volume (in %). default is 100%");
+
+static int keyclick_volume = 100; /* % */
+module_param (keyclick_volume, int, 0);
+MODULE_PARM_DESC (keyclick_volume, "Keyclick volume (in %), default is 100%");
+
+static int ctrlclick_volume = 100; /* % */
+module_param (ctrlclick_volume, int, 0);
+MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%");
+
+
+
+#undef LKKBD_DEBUG
+#ifdef LKKBD_DEBUG
+#define DBG(x...) printk (x)
+#else
+#define DBG(x...) do {} while (0)
+#endif
+
+/* LED control */
+#define LK_LED_WAIT		0x81
+#define LK_LED_COMPOSE		0x82
+#define LK_LED_SHIFTLOCK	0x84
+#define LK_LED_SCROLLLOCK	0x88
+#define LK_CMD_LED_ON		0x13
+#define LK_CMD_LED_OFF		0x11
+
+/* Mode control */
+#define LK_MODE_DOWN		0x80
+#define LK_MODE_AUTODOWN	0x82
+#define LK_MODE_UPDOWN		0x86
+#define LK_CMD_SET_MODE(mode,div)	((mode) | ((div) << 3))
+
+/* Misc commands */
+#define LK_CMD_ENABLE_KEYCLICK	0x1b
+#define LK_CMD_DISABLE_KEYCLICK	0x99
+#define LK_CMD_DISABLE_BELL	0xa1
+#define LK_CMD_SOUND_BELL	0xa7
+#define LK_CMD_ENABLE_BELL	0x23
+#define LK_CMD_DISABLE_CTRCLICK	0xb9
+#define LK_CMD_ENABLE_CTRCLICK	0xbb
+#define LK_CMD_SET_DEFAULTS	0xd3
+#define LK_CMD_POWERCYCLE_RESET	0xfd
+#define LK_CMD_ENABLE_LK401	0xe9
+
+/* Misc responses from keyboard */
+#define LK_ALL_KEYS_UP		0xb3
+#define LK_METRONOME		0xb4
+#define LK_OUTPUT_ERROR		0xb5
+#define LK_INPUT_ERROR		0xb6
+#define LK_KBD_LOCKED		0xb7
+#define LK_KBD_TEST_MODE_ACK	0xb8
+#define LK_PREFIX_KEY_DOWN	0xb9
+#define LK_MODE_CHANGE_ACK	0xba
+#define LK_RESPONSE_RESERVED	0xbb
+
+#define LK_NUM_KEYCODES		256
+typedef u_int16_t lk_keycode_t;
+
+
+
+static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = {
+	[0x56] = KEY_F1,
+	[0x57] = KEY_F2,
+	[0x58] = KEY_F3,
+	[0x59] = KEY_F4,
+	[0x5a] = KEY_F5,
+	[0x64] = KEY_F6,
+	[0x65] = KEY_F7,
+	[0x66] = KEY_F8,
+	[0x67] = KEY_F9,
+	[0x68] = KEY_F10,
+	[0x71] = KEY_F11,
+	[0x72] = KEY_F12,
+	[0x73] = KEY_F13,
+	[0x74] = KEY_F14,
+	[0x7c] = KEY_F15,
+	[0x7d] = KEY_F16,
+	[0x80] = KEY_F17,
+	[0x81] = KEY_F18,
+	[0x82] = KEY_F19,
+	[0x83] = KEY_F20,
+	[0x8a] = KEY_FIND,
+	[0x8b] = KEY_INSERT,
+	[0x8c] = KEY_DELETE,
+	[0x8d] = KEY_SELECT,
+	[0x8e] = KEY_PAGEUP,
+	[0x8f] = KEY_PAGEDOWN,
+	[0x92] = KEY_KP0,
+	[0x94] = KEY_KPDOT,
+	[0x95] = KEY_KPENTER,
+	[0x96] = KEY_KP1,
+	[0x97] = KEY_KP2,
+	[0x98] = KEY_KP3,
+	[0x99] = KEY_KP4,
+	[0x9a] = KEY_KP5,
+	[0x9b] = KEY_KP6,
+	[0x9c] = KEY_KPCOMMA,
+	[0x9d] = KEY_KP7,
+	[0x9e] = KEY_KP8,
+	[0x9f] = KEY_KP9,
+	[0xa0] = KEY_KPMINUS,
+	[0xa1] = KEY_PROG1,
+	[0xa2] = KEY_PROG2,
+	[0xa3] = KEY_PROG3,
+	[0xa4] = KEY_PROG4,
+	[0xa7] = KEY_LEFT,
+	[0xa8] = KEY_RIGHT,
+	[0xa9] = KEY_DOWN,
+	[0xaa] = KEY_UP,
+	[0xab] = KEY_RIGHTSHIFT,
+	[0xac] = KEY_LEFTALT,
+	[0xad] = KEY_COMPOSE, /* Right Compose, that is. */
+	[0xae] = KEY_LEFTSHIFT, /* Same as KEY_RIGHTSHIFT on LK201 */
+	[0xaf] = KEY_LEFTCTRL,
+	[0xb0] = KEY_CAPSLOCK,
+	[0xb1] = KEY_COMPOSE, /* Left Compose, that is. */
+	[0xb2] = KEY_RIGHTALT,
+	[0xbc] = KEY_BACKSPACE,
+	[0xbd] = KEY_ENTER,
+	[0xbe] = KEY_TAB,
+	[0xbf] = KEY_ESC,
+	[0xc0] = KEY_1,
+	[0xc1] = KEY_Q,
+	[0xc2] = KEY_A,
+	[0xc3] = KEY_Z,
+	[0xc5] = KEY_2,
+	[0xc6] = KEY_W,
+	[0xc7] = KEY_S,
+	[0xc8] = KEY_X,
+	[0xc9] = KEY_102ND,
+	[0xcb] = KEY_3,
+	[0xcc] = KEY_E,
+	[0xcd] = KEY_D,
+	[0xce] = KEY_C,
+	[0xd0] = KEY_4,
+	[0xd1] = KEY_R,
+	[0xd2] = KEY_F,
+	[0xd3] = KEY_V,
+	[0xd4] = KEY_SPACE,
+	[0xd6] = KEY_5,
+	[0xd7] = KEY_T,
+	[0xd8] = KEY_G,
+	[0xd9] = KEY_B,
+	[0xdb] = KEY_6,
+	[0xdc] = KEY_Y,
+	[0xdd] = KEY_H,
+	[0xde] = KEY_N,
+	[0xe0] = KEY_7,
+	[0xe1] = KEY_U,
+	[0xe2] = KEY_J,
+	[0xe3] = KEY_M,
+	[0xe5] = KEY_8,
+	[0xe6] = KEY_I,
+	[0xe7] = KEY_K,
+	[0xe8] = KEY_COMMA,
+	[0xea] = KEY_9,
+	[0xeb] = KEY_O,
+	[0xec] = KEY_L,
+	[0xed] = KEY_DOT,
+	[0xef] = KEY_0,
+	[0xf0] = KEY_P,
+	[0xf2] = KEY_SEMICOLON,
+	[0xf3] = KEY_SLASH,
+	[0xf5] = KEY_EQUAL,
+	[0xf6] = KEY_RIGHTBRACE,
+	[0xf7] = KEY_BACKSLASH,
+	[0xf9] = KEY_MINUS,
+	[0xfa] = KEY_LEFTBRACE,
+	[0xfb] = KEY_APOSTROPHE,
+};
+
+#define CHECK_LED(LED, BITS) do {		\
+	if (test_bit (LED, lk->dev.led))	\
+		leds_on |= BITS;		\
+	else					\
+		leds_off |= BITS;		\
+	} while (0)
+
+/*
+ * Per-keyboard data
+ */
+struct lkkbd {
+	lk_keycode_t keycode[LK_NUM_KEYCODES];
+	int ignore_bytes;
+	struct input_dev dev;
+	struct serio *serio;
+	struct work_struct tq;
+	char name[64];
+	char phys[32];
+	char type;
+	int bell_volume;
+	int keyclick_volume;
+	int ctrlclick_volume;
+};
+
+/*
+ * Calculate volume parameter byte for a given volume.
+ */
+static unsigned char
+volume_to_hw (int volume_percent)
+{
+	unsigned char ret = 0;
+
+	if (volume_percent < 0)
+		volume_percent = 0;
+	if (volume_percent > 100)
+		volume_percent = 100;
+
+	if (volume_percent >= 0)
+		ret = 7;
+	if (volume_percent >= 13)	/* 12.5 */
+		ret = 6;
+	if (volume_percent >= 25)
+		ret = 5;
+	if (volume_percent >= 38)	/* 37.5 */
+		ret = 4;
+	if (volume_percent >= 50)
+		ret = 3;
+	if (volume_percent >= 63)	/* 62.5 */
+		ret = 2;		/* This is the default volume */
+	if (volume_percent >= 75)
+		ret = 1;
+	if (volume_percent >= 88)	/* 87.5 */
+		ret = 0;
+
+	ret |= 0x80;
+
+	return ret;
+}
+
+/*
+ * lkkbd_interrupt() is called by the low level driver when a character
+ * is received.
+ */
+static irqreturn_t
+lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags,
+		struct pt_regs *regs)
+{
+	struct lkkbd *lk = serio->private;
+	int i;
+
+	DBG (KERN_INFO "Got byte 0x%02x\n", data);
+
+	if (lk->ignore_bytes > 0) {
+		DBG (KERN_INFO "Ignoring a byte on %s\n",
+				lk->name);
+		lk->ignore_bytes--;
+		return IRQ_HANDLED;
+	}
+
+	switch (data) {
+		case LK_ALL_KEYS_UP:
+			input_regs (&lk->dev, regs);
+			for (i = 0; i < ARRAY_SIZE (lkkbd_keycode); i++)
+				if (lk->keycode[i] != KEY_RESERVED)
+					input_report_key (&lk->dev, lk->keycode[i], 0);
+			input_sync (&lk->dev);
+			break;
+		case LK_METRONOME:
+			DBG (KERN_INFO "Got LK_METRONOME and don't "
+					"know how to handle...\n");
+			break;
+		case LK_OUTPUT_ERROR:
+			DBG (KERN_INFO "Got LK_OUTPUT_ERROR and don't "
+					"know how to handle...\n");
+			break;
+		case LK_INPUT_ERROR:
+			DBG (KERN_INFO "Got LK_INPUT_ERROR and don't "
+					"know how to handle...\n");
+			break;
+		case LK_KBD_LOCKED:
+			DBG (KERN_INFO "Got LK_KBD_LOCKED and don't "
+					"know how to handle...\n");
+			break;
+		case LK_KBD_TEST_MODE_ACK:
+			DBG (KERN_INFO "Got LK_KBD_TEST_MODE_ACK and don't "
+					"know how to handle...\n");
+			break;
+		case LK_PREFIX_KEY_DOWN:
+			DBG (KERN_INFO "Got LK_PREFIX_KEY_DOWN and don't "
+					"know how to handle...\n");
+			break;
+		case LK_MODE_CHANGE_ACK:
+			DBG (KERN_INFO "Got LK_MODE_CHANGE_ACK and ignored "
+					"it properly...\n");
+			break;
+		case LK_RESPONSE_RESERVED:
+			DBG (KERN_INFO "Got LK_RESPONSE_RESERVED and don't "
+					"know how to handle...\n");
+			break;
+		case 0x01:
+			DBG (KERN_INFO "Got 0x01, scheduling re-initialization\n");
+			lk->ignore_bytes = 3;
+			schedule_work (&lk->tq);
+			break;
+
+		default:
+			if (lk->keycode[data] != KEY_RESERVED) {
+				input_regs (&lk->dev, regs);
+				if (!test_bit (lk->keycode[data], lk->dev.key))
+					input_report_key (&lk->dev, lk->keycode[data], 1);
+				else
+					input_report_key (&lk->dev, lk->keycode[data], 0);
+				input_sync (&lk->dev);
+                        } else
+                                printk (KERN_WARNING "%s: Unknown key with "
+						"scancode %02x on %s.\n",
+						__FILE__, data, lk->name);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * lkkbd_event() handles events from the input module.
+ */
+static int
+lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code,
+		int value)
+{
+	struct lkkbd *lk = dev->private;
+	unsigned char leds_on = 0;
+	unsigned char leds_off = 0;
+
+	switch (type) {
+		case EV_LED:
+			CHECK_LED (LED_CAPSL, LK_LED_SHIFTLOCK);
+			CHECK_LED (LED_COMPOSE, LK_LED_COMPOSE);
+			CHECK_LED (LED_SCROLLL, LK_LED_SCROLLLOCK);
+			CHECK_LED (LED_SLEEP, LK_LED_WAIT);
+			if (leds_on != 0) {
+				lk->serio->write (lk->serio, LK_CMD_LED_ON);
+				lk->serio->write (lk->serio, leds_on);
+			}
+			if (leds_off != 0) {
+				lk->serio->write (lk->serio, LK_CMD_LED_OFF);
+				lk->serio->write (lk->serio, leds_off);
+			}
+			return 0;
+
+		case EV_SND:
+			switch (code) {
+				case SND_CLICK:
+					if (value == 0) {
+						DBG ("%s: Deactivating key clicks\n", __FUNCTION__);
+						lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK);
+						lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK);
+					} else {
+						DBG ("%s: Activating key clicks\n", __FUNCTION__);
+						lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK);
+						lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume));
+						lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK);
+						lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume));
+					}
+					return 0;
+
+				case SND_BELL:
+					if (value != 0)
+						lk->serio->write (lk->serio, LK_CMD_SOUND_BELL);
+
+					return 0;
+			}
+			break;
+
+		default:
+			printk (KERN_ERR "%s (): Got unknown type %d, code %d, value %d\n",
+					__FUNCTION__, type, code, value);
+	}
+
+	return -1;
+}
+
+/*
+ * lkkbd_reinit() sets leds and beeps to a state the computer remembers they
+ * were in.
+ */
+static void
+lkkbd_reinit (void *data)
+{
+	struct lkkbd *lk = data;
+	int division;
+	unsigned char leds_on = 0;
+	unsigned char leds_off = 0;
+
+	/* Reset parameters */
+	lk->serio->write (lk->serio, LK_CMD_SET_DEFAULTS);
+
+	/* Set LEDs */
+	CHECK_LED (LED_CAPSL, LK_LED_SHIFTLOCK);
+	CHECK_LED (LED_COMPOSE, LK_LED_COMPOSE);
+	CHECK_LED (LED_SCROLLL, LK_LED_SCROLLLOCK);
+	CHECK_LED (LED_SLEEP, LK_LED_WAIT);
+	if (leds_on != 0) {
+		lk->serio->write (lk->serio, LK_CMD_LED_ON);
+		lk->serio->write (lk->serio, leds_on);
+	}
+	if (leds_off != 0) {
+		lk->serio->write (lk->serio, LK_CMD_LED_OFF);
+		lk->serio->write (lk->serio, leds_off);
+	}
+
+	/*
+	 * Try to activate extended LK401 mode. This command will
+	 * only work with a LK401 keyboard and grants access to
+	 * LAlt, RAlt, RCompose and RShift.
+	 */
+	lk->serio->write (lk->serio, LK_CMD_ENABLE_LK401);
+
+	/* Set all keys to UPDOWN mode */
+	for (division = 1; division <= 14; division++)
+		lk->serio->write (lk->serio, LK_CMD_SET_MODE (LK_MODE_UPDOWN,
+					division));
+
+	/* Enable bell and set volume */
+	lk->serio->write (lk->serio, LK_CMD_ENABLE_BELL);
+	lk->serio->write (lk->serio, volume_to_hw (lk->bell_volume));
+
+	/* Enable/disable keyclick (and possibly set volume) */
+	if (test_bit (SND_CLICK, lk->dev.snd)) {
+		lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK);
+		lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume));
+		lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK);
+		lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume));
+	} else {
+		lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK);
+		lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK);
+	}
+
+	/* Sound the bell if needed */
+	if (test_bit (SND_BELL, lk->dev.snd))
+		lk->serio->write (lk->serio, LK_CMD_SOUND_BELL);
+}
+
+/*
+ * lkkbd_connect() probes for a LK keyboard and fills the necessary structures.
+ */
+static void
+lkkbd_connect (struct serio *serio, struct serio_dev *dev)
+{
+	struct lkkbd *lk;
+	int i;
+
+	if ((serio->type & SERIO_TYPE) != SERIO_RS232)
+		return;
+	if (!(serio->type & SERIO_PROTO))
+		return;
+	if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_LKKBD)
+		return;
+
+	if (!(lk = kmalloc (sizeof (struct lkkbd), GFP_KERNEL)))
+		return;
+	memset (lk, 0, sizeof (struct lkkbd));
+
+	init_input_dev (&lk->dev);
+
+	lk->dev.evbit[0] = BIT (EV_KEY) | BIT (EV_LED) | BIT (EV_SND) | BIT (EV_REP);
+	lk->dev.ledbit[0] = BIT (LED_CAPSL) | BIT (LED_COMPOSE) | BIT (LED_SCROLLL) | BIT (LED_SLEEP);
+	lk->dev.sndbit[0] = BIT (SND_CLICK) | BIT (SND_BELL);
+
+	lk->serio = serio;
+
+	INIT_WORK (&lk->tq, lkkbd_reinit, lk);
+
+	lk->bell_volume = bell_volume;
+	lk->keyclick_volume = keyclick_volume;
+	lk->ctrlclick_volume = ctrlclick_volume;
+
+	lk->dev.keycode = lk->keycode;
+	lk->dev.keycodesize = sizeof (lk_keycode_t);
+	lk->dev.keycodemax = LK_NUM_KEYCODES;
+
+	lk->dev.event = lkkbd_event;
+	lk->dev.private = lk;
+
+	serio->private = lk;
+
+	if (serio_open (serio, dev)) {
+		kfree (lk);
+		return;
+	}
+
+	sprintf (lk->name, "LK keyboard");
+
+	memcpy (lk->keycode, lkkbd_keycode, sizeof (lk_keycode_t) * LK_NUM_KEYCODES);
+	for (i = 0; i < LK_NUM_KEYCODES; i++)
+		set_bit (lk->keycode[i], lk->dev.keybit);
+
+	sprintf (lk->name, "%s/input0", serio->phys);
+
+	lk->dev.name = lk->name;
+	lk->dev.phys = lk->phys;
+	lk->dev.id.bustype = BUS_RS232;
+	lk->dev.id.vendor = SERIO_LKKBD;
+	lk->dev.id.product = 0;
+	lk->dev.id.version = 0x0100;
+
+	input_register_device (&lk->dev);
+
+	printk (KERN_INFO "input: %s on %s, initiating reset\n", lk->name, serio->phys);
+	lk->serio->write (lk->serio, LK_CMD_POWERCYCLE_RESET);
+}
+
+/*
+ * lkkbd_disconnect() unregisters and closes behind us.
+ */
+static void
+lkkbd_disconnect (struct serio *serio)
+{
+	struct lkkbd *lk = serio->private;
+
+	input_unregister_device (&lk->dev);
+	serio_close (serio);
+	kfree (lk);
+}
+
+static struct serio_dev lkkbd_dev = {
+	.interrupt = lkkbd_interrupt,
+	.connect = lkkbd_connect,
+	.disconnect = lkkbd_disconnect,
+};
+
+/*
+ * The functions for insering/removing us as a module.
+ */
+int __init
+lkkbd_init (void)
+{
+	serio_register_device (&lkkbd_dev);
+	return 0;
+}
+
+void __exit
+lkkbd_exit (void)
+{
+	serio_unregister_device (&lkkbd_dev);
+}
+
+module_init (lkkbd_init);
+module_exit (lkkbd_exit);
+
--- diff/drivers/input/mouse/vsxxxaa.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/input/mouse/vsxxxaa.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,550 @@
+/*
+ * DEC VSXXX-AA and VSXXX-GA mouse driver.
+ *
+ * Copyright (C) 2003-2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
+ *
+ * The packet format was taken from a patch to GPM which is (C) 2001
+ * by	Karsten Merker <merker@linuxtag.org>
+ * and	Maciej W. Rozycki <macro@ds2.pg.gda.pl>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Building an adaptor to DB9 / DB25 RS232
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * DISCLAIMER: Use this description AT YOUR OWN RISK! I'll not pay for
+ * anything if you break your mouse, your computer or whatever!
+ *
+ * In theory, this mouse is a simple RS232 device. In practice, it has got
+ * a quite uncommon plug and the requirement to additionally get a power
+ * supply at +5V and -12V.
+ *
+ * If you look at the socket/jack (_not_ at the plug), we use this pin
+ * numbering:
+ *    _______
+ *   / 7 6 5 \
+ *  | 4 --- 3 |
+ *   \  2 1  /
+ *    -------
+ * 
+ *	DEC socket	DB9	DB25	Note
+ *	1 (GND)		5	7	-
+ *	2 (RxD)		3	3	-
+ *	3 (TxD)		2	2	-
+ *	4 (-12V)	-	-	Somewhere from the PSU. At ATX, it's
+ *					the blue wire at pin 12 of the ATX
+ *					power connector. Please note that the
+ *					docs say this should be +12V! However,
+ *					I measured -12V...
+ *	5 (+5V)		-	-	PSU (red wire of ATX power connector
+ *					on pin 4, 6, 19 or 20) or HDD power
+ *					connector (also red wire)
+ *	6 (not conn.)	-	-	-
+ *	7 (dev. avail.)	-	-	The mouse shorts this one to pin 1.
+ *					This way, the host computer can detect
+ *					the mouse. To use it with the adaptor,
+ *					simply don't connect this pin.
+ *
+ * So to get a working adaptor, you need to connect the mouse with three
+ * wires to a RS232 port and two additional wires for +5V and -12V to the
+ * PSU.
+ *
+ * Flow specification for the link is 4800, 8o1.
+ */
+
+/*
+ * TODO list:
+ * - Automatically attach to a given serial port (no need for inputattach).
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/config.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
+MODULE_DESCRIPTION ("Serial DEC VSXXX-AA/GA mouse / DEC tablet driver");
+MODULE_LICENSE ("GPL");
+
+#undef VSXXXAA_DEBUG
+#ifdef VSXXXAA_DEBUG
+#define DBG(x...) printk (x)
+#else
+#define DBG(x...) do {} while (0)
+#endif
+
+#define VSXXXAA_INTRO_MASK	0x80
+#define VSXXXAA_INTRO_HEAD	0x80
+#define IS_HDR_BYTE(x)		(((x) & VSXXXAA_INTRO_MASK)	\
+					== VSXXXAA_INTRO_HEAD)
+
+#define VSXXXAA_PACKET_MASK	0xe0
+#define VSXXXAA_PACKET_REL	0x80
+#define VSXXXAA_PACKET_ABS	0xc0
+#define VSXXXAA_PACKET_POR	0xa0
+#define MATCH_PACKET_TYPE(data, type)	(((data) & VSXXXAA_PACKET_MASK) == type)
+
+
+
+struct vsxxxaa {
+	struct input_dev dev;
+	struct serio *serio;
+#define BUFLEN 15 /* At least 5 is needed for a full tablet packet */
+	unsigned char buf[BUFLEN];
+	unsigned char count;
+	unsigned char version;
+	unsigned char country;
+	unsigned char type;
+	char phys[32];
+};
+
+static void
+vsxxxaa_drop_bytes (struct vsxxxaa *mouse, int num)
+{
+	if (num >= mouse->count)
+		mouse->count = 0;
+	else {
+		memmove (mouse->buf, mouse->buf + num - 1, BUFLEN - num);
+		mouse->count -= num;
+	}
+}
+
+static void
+vsxxxaa_queue_byte (struct vsxxxaa *mouse, unsigned char byte)
+{
+	if (mouse->count == BUFLEN) {
+		printk (KERN_ERR "%s on %s: Dropping a byte of full buffer.\n",
+				mouse->dev.name, mouse->dev.phys);
+		vsxxxaa_drop_bytes (mouse, 1);
+	}
+
+	mouse->buf[mouse->count++] = byte;
+}
+
+static void
+vsxxxaa_report_mouse (struct vsxxxaa *mouse)
+{
+	char *devtype;
+
+	switch (mouse->type) {
+		case 0x02:	devtype = "DEC mouse"; break;
+		case 0x04:	devtype = "DEC tablet"; break;
+		default:	devtype = "unknown DEC device"; break;
+	}
+
+	printk (KERN_INFO "Found %s version 0x%x from country 0x%x "
+			"on port %s\n", devtype, mouse->version,
+			mouse->country, mouse->dev.phys);
+}
+
+/*
+ * Returns number of bytes to be dropped, 0 if packet is okay.
+ */
+static int
+vsxxxaa_check_packet (struct vsxxxaa *mouse, int packet_len)
+{
+	int i;
+
+	/* First byte must be a header byte */
+	if (!IS_HDR_BYTE (mouse->buf[0])) {
+		DBG ("vsck: len=%d, 1st=0x%02x\n", packet_len, mouse->buf[0]);
+		return 1;
+	}
+
+	/* Check all following bytes */
+	if (packet_len > 1) {
+		for (i = 1; i < packet_len; i++) {
+			if (IS_HDR_BYTE (mouse->buf[i])) {
+				printk (KERN_ERR "Need to drop %d bytes "
+						"of a broken packet.\n",
+						i - 1);
+				DBG (KERN_INFO "check: len=%d, b[%d]=0x%02x\n",
+						packet_len, i, mouse->buf[i]);
+				return i - 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static __inline__ int
+vsxxxaa_smells_like_packet (struct vsxxxaa *mouse, unsigned char type, size_t len)
+{
+	return (mouse->count >= len) && MATCH_PACKET_TYPE (mouse->buf[0], type);
+}
+
+static void
+vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
+{
+	struct input_dev *dev = &mouse->dev;
+	unsigned char *buf = mouse->buf;
+	int left, middle, right;
+	int dx, dy;
+
+	/*
+	 * Check for normal stream packets. This is three bytes,
+	 * with the first byte's 3 MSB set to 100.
+	 *
+	 * [0]:	1	0	0	SignX	SignY	Left	Middle	Right
+	 * [1]: 0	dx	dx	dx	dx	dx	dx	dx
+	 * [2]:	0	dy	dy	dy	dy	dy	dy	dy
+	 */
+
+	/*
+	 * Low 7 bit of byte 1 are abs(dx), bit 7 is
+	 * 0, bit 4 of byte 0 is direction.
+	 */
+	dx = buf[1] & 0x7f;
+	dx *= ((buf[0] >> 4) & 0x01)? -1: 1;
+
+	/*
+	 * Low 7 bit of byte 2 are abs(dy), bit 7 is
+	 * 0, bit 3 of byte 0 is direction.
+	 */
+	dy = buf[2] & 0x7f;
+	dy *= ((buf[0] >> 3) & 0x01)? -1: 1;
+
+	/*
+	 * Get button state. It's the low three bits
+	 * (for three buttons) of byte 0.
+	 */
+	left	= (buf[0] & 0x04)? 1: 0;
+	middle	= (buf[0] & 0x02)? 1: 0;
+	right	= (buf[0] & 0x01)? 1: 0;
+
+	vsxxxaa_drop_bytes (mouse, 3);
+
+	DBG (KERN_INFO "%s on %s: dx=%d, dy=%d, buttons=%s%s%s\n",
+			mouse->dev.name, mouse->dev.phys, dx, dy,
+			left? "L": "l", middle? "M": "m", right? "R": "r");
+
+	/*
+	 * Report what we've found so far...
+	 */
+	input_regs (dev, regs);
+	input_report_key (dev, BTN_LEFT, left);
+	input_report_key (dev, BTN_MIDDLE, middle);
+	input_report_key (dev, BTN_RIGHT, right);
+	input_report_rel (dev, REL_X, dx);
+	input_report_rel (dev, REL_Y, dy);
+	input_sync (dev);
+}
+
+static void
+vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
+{
+	struct input_dev *dev = &mouse->dev;
+	unsigned char *buf = mouse->buf;
+	int left, middle, right, extra;
+	int x, y;
+
+	/*
+	 * Tablet position / button packet
+	 *
+	 * [0]:	1	1	0	B4	B3	B2	B1	Pr
+	 * [1]:	0	0	X5	X4	X3	X2	X1	X0
+	 * [2]:	0	0	X11	X10	X9	X8	X7	X6
+	 * [3]:	0	0	Y5	Y4	Y3	Y2	Y1	Y0
+	 * [4]:	0	0	Y11	Y10	Y9	Y8	Y7	Y6
+	 */
+
+	/*
+	 * Get X/Y position
+	 */
+	x = ((buf[2] & 0x3f) << 6) | (buf[1] & 0x3f);
+	y = ((buf[4] & 0x3f) << 6) | (buf[3] & 0x3f);
+
+	/*
+	 * Get button state. It's bits <4..1> of byte 0.
+	 */
+	left	= (buf[0] & 0x02)? 1: 0;
+	middle	= (buf[0] & 0x04)? 1: 0;
+	right	= (buf[0] & 0x08)? 1: 0;
+	extra	= (buf[0] & 0x10)? 1: 0;
+
+	vsxxxaa_drop_bytes (mouse, 5);
+
+	DBG (KERN_INFO "%s on %s: x=%d, y=%d, buttons=%s%s%s%s\n",
+			mouse->dev.name, mouse->dev.phys, x, y,
+			left? "L": "l", middle? "M": "m",
+			right? "R": "r", extra? "E": "e");
+
+	/*
+	 * Report what we've found so far...
+	 */
+	input_regs (dev, regs);
+	input_report_key (dev, BTN_LEFT, left);
+	input_report_key (dev, BTN_MIDDLE, middle);
+	input_report_key (dev, BTN_RIGHT, right);
+	input_report_key (dev, BTN_EXTRA, extra);
+	input_report_abs (dev, ABS_X, x);
+	input_report_abs (dev, ABS_Y, y);
+	input_sync (dev);
+}
+
+static void
+vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
+{
+	struct input_dev *dev = &mouse->dev;
+	unsigned char *buf = mouse->buf;
+	int left, middle, right;
+	unsigned char error;
+
+	/*
+	 * Check for Power-On-Reset packets. These are sent out
+	 * after plugging the mouse in, or when explicitely
+	 * requested by sending 'T'.
+	 *
+	 * [0]:	1	0	1	0	R3	R2	R1	R0
+	 * [1]:	0	M2	M1	M0	D3	D2	D1	D0
+	 * [2]:	0	E6	E5	E4	E3	E2	E1	E0
+	 * [3]:	0	0	0	0	0	Left	Middle	Right
+	 *
+	 * M: manufacturer location code
+	 * R: revision code
+	 * E: Error code. I'm not sure about these, but gpm's sources,
+	 *    which support this mouse, too, tell about them:
+	 *	E = [0x00 .. 0x1f]: no error, byte #3 is button state
+	 *	E = 0x3d: button error, byte #3 tells which one.
+	 *	E = <else>: other error
+	 * D: <0010> == mouse, <0100> == tablet
+	 *
+	 */
+
+	mouse->version = buf[0] & 0x0f;
+	mouse->country = (buf[1] >> 4) & 0x07;
+	mouse->type = buf[1] & 0x07;
+	error = buf[2] & 0x7f;
+
+	/*
+	 * Get button state. It's the low three bits
+	 * (for three buttons) of byte 0. Maybe even the bit <3>
+	 * has some meaning if a tablet is attached.
+	 */
+	left	= (buf[0] & 0x04)? 1: 0;
+	middle	= (buf[0] & 0x02)? 1: 0;
+	right	= (buf[0] & 0x01)? 1: 0;
+
+	vsxxxaa_drop_bytes (mouse, 4);
+	vsxxxaa_report_mouse (mouse);
+
+	if (error <= 0x1f) {
+		/* No error. Report buttons */
+		input_regs (dev, regs);
+		input_report_key (dev, BTN_LEFT, left);
+		input_report_key (dev, BTN_MIDDLE, middle);
+		input_report_key (dev, BTN_RIGHT, right);
+		input_sync (dev);
+	} else {
+		printk (KERN_ERR "Your %s on %s reports an undefined error, "
+				"please check it...\n", mouse->dev.name,
+				mouse->dev.phys);
+	}
+
+	/*
+	 * If the mouse was hot-plugged, we need to
+	 * force differential mode now...
+	 */
+	printk (KERN_NOTICE "%s on %s: Forceing standard packet format and "
+			"streaming mode\n", mouse->dev.name, mouse->dev.phys);
+	mouse->serio->write (mouse->serio, 'S');
+	mouse->serio->write (mouse->serio, 'R');
+}
+
+static void
+vsxxxaa_parse_buffer (struct vsxxxaa *mouse, struct pt_regs *regs)
+{
+	unsigned char *buf = mouse->buf;
+	int stray_bytes;
+
+	/*
+	 * Parse buffer to death...
+	 */
+	do {
+		/*
+		 * Out of sync? Throw away what we don't understand. Each
+		 * packet starts with a byte whose bit 7 is set. Unhandled
+		 * packets (ie. which we don't know about or simply b0rk3d
+		 * data...) will get shifted out of the buffer after some
+		 * activity on the mouse.
+		 */
+		while (mouse->count > 0 && !IS_HDR_BYTE(buf[0])) {
+			printk (KERN_ERR "%s on %s: Dropping a byte to regain "
+					"sync with mouse data stream...\n",
+					mouse->dev.name, mouse->dev.phys);
+			vsxxxaa_drop_bytes (mouse, 1);
+		}
+
+		/*
+		 * Check for packets we know about.
+		 */
+
+		if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_REL, 3)) {
+			/* Check for broken packet */
+			stray_bytes = vsxxxaa_check_packet (mouse, 3);
+			if (stray_bytes > 0) {
+				printk (KERN_ERR "Dropping %d bytes now...\n",
+						stray_bytes);
+				vsxxxaa_drop_bytes (mouse, stray_bytes);
+				continue;
+			}
+
+			vsxxxaa_handle_REL_packet (mouse, regs);
+			continue; /* More to parse? */
+		}
+
+		if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_ABS, 5)) {
+			/* Check for broken packet */
+			stray_bytes = vsxxxaa_check_packet (mouse, 5);
+			if (stray_bytes > 0) {
+				printk (KERN_ERR "Dropping %d bytes now...\n",
+						stray_bytes);
+				vsxxxaa_drop_bytes (mouse, stray_bytes);
+				continue;
+			}
+
+			vsxxxaa_handle_ABS_packet (mouse, regs);
+			continue; /* More to parse? */
+		}
+
+		if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_POR, 4)) {
+			/* Check for broken packet */
+			stray_bytes = vsxxxaa_check_packet (mouse, 4);
+			if (stray_bytes > 0) {
+				printk (KERN_ERR "Dropping %d bytes now...\n",
+						stray_bytes);
+				vsxxxaa_drop_bytes (mouse, stray_bytes);
+				continue;
+			}
+
+			vsxxxaa_handle_POR_packet (mouse, regs);
+			continue; /* More to parse? */
+		}
+
+		break; /* No REL, ABS or POR packet found */
+	} while (1);
+}
+
+static irqreturn_t
+vsxxxaa_interrupt (struct serio *serio, unsigned char data, unsigned int flags,
+		struct pt_regs *regs)
+{
+	struct vsxxxaa *mouse = serio->private;
+
+	vsxxxaa_queue_byte (mouse, data);
+	vsxxxaa_parse_buffer (mouse, regs);
+
+	return IRQ_HANDLED;
+}
+
+static void
+vsxxxaa_disconnect (struct serio *serio)
+{
+	struct vsxxxaa *mouse = serio->private;
+
+	input_unregister_device (&mouse->dev);
+	serio_close (serio);
+	kfree (mouse);
+}
+
+static void
+vsxxxaa_connect (struct serio *serio, struct serio_dev *dev)
+{
+	struct vsxxxaa *mouse;
+
+	if ((serio->type & SERIO_TYPE) != SERIO_RS232)
+		return;
+
+	if ((serio->type & SERIO_PROTO) != SERIO_VSXXXAA)
+		return;
+
+	if (!(mouse = kmalloc (sizeof (struct vsxxxaa), GFP_KERNEL)))
+		return;
+
+	memset (mouse, 0, sizeof (struct vsxxxaa));
+
+	init_input_dev (&mouse->dev);
+	set_bit (EV_KEY, mouse->dev.evbit);		/* We have buttons */
+	set_bit (EV_REL, mouse->dev.evbit);		/* We can move */
+	set_bit (BTN_LEFT, mouse->dev.keybit);		/* We have 3 buttons */
+	set_bit (BTN_MIDDLE, mouse->dev.keybit);
+	set_bit (BTN_RIGHT, mouse->dev.keybit);
+	set_bit (BTN_EXTRA, mouse->dev.keybit);		/* ...and Tablet */
+	set_bit (REL_X, mouse->dev.relbit);		/* We can move in */
+	set_bit (REL_Y, mouse->dev.relbit);		/* two dimensions */
+	set_bit (ABS_X, mouse->dev.absbit);		/* DEC tablet support */
+	set_bit (ABS_Y, mouse->dev.absbit);
+
+	mouse->dev.absmin[ABS_X] = 0;
+	mouse->dev.absmax[ABS_X] = 1023;
+	mouse->dev.absmin[ABS_Y] = 0;
+	mouse->dev.absmax[ABS_Y] = 1023;
+
+	mouse->dev.private = mouse;
+	serio->private = mouse;
+
+	sprintf (mouse->phys, "%s/input0", serio->phys);
+	mouse->dev.phys = mouse->phys;
+	mouse->dev.name = "DEC VSXXX-AA/GA mouse or DEC tablet";
+	mouse->dev.id.bustype = BUS_RS232;
+	mouse->serio = serio;
+
+	if (serio_open (serio, dev)) {
+		kfree (mouse);
+		return;
+	}
+
+	/*
+	 * Request selftest and differential stream mode.
+	 */
+	mouse->serio->write (mouse->serio, 'T'); /* Test */
+	mouse->serio->write (mouse->serio, 'R'); /* Differential stream */
+
+	input_register_device (&mouse->dev);
+
+	printk (KERN_INFO "input: %s on %s\n", mouse->dev.name, serio->phys);
+}
+
+static struct serio_dev vsxxxaa_dev = {
+	.interrupt =	vsxxxaa_interrupt,
+	.connect =	vsxxxaa_connect,
+	.disconnect =	vsxxxaa_disconnect
+};
+
+int __init
+vsxxxaa_init (void)
+{
+	serio_register_device (&vsxxxaa_dev);
+	return 0;
+}
+
+void __exit
+vsxxxaa_exit (void)
+{
+	serio_unregister_device (&vsxxxaa_dev);
+}
+
+module_init (vsxxxaa_init);
+module_exit (vsxxxaa_exit);
+
--- diff/drivers/input/serio/gscps2.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/input/serio/gscps2.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,470 @@
+/*
+ * drivers/input/serio/gscps2.c
+ *
+ * Copyright (c) 2004 Helge Deller <deller@gmx.de>
+ * Copyright (c) 2002 Laurent Canet <canetl@esiee.fr>
+ * Copyright (c) 2002 Thibaut Varene <varenet@esiee.fr>
+ *
+ * Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c
+ * 	Copyright (c) 1999 Alex deVries <adevries@thepuffingroup.com>
+ *	Copyright (c) 1999-2000 Philipp Rumpf <prumpf@tux.org>
+ *	Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr>
+ *	Copyright (c) 2000-2001 Thomas Marteau <marteaut@esiee.fr>
+ *
+ * HP GSC PS/2 port driver, found in PA/RISC Workstations
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ * 
+ * TODO:
+ * - Dino testing (did HP ever shipped a machine on which this port
+ *                 was usable/enabled ?)
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/serio.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/pci_ids.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/parisc-device.h>
+
+MODULE_AUTHOR("Laurent Canet <canetl@esiee.fr>, Thibaut Varene <varenet@esiee.fr>, Helge Deller <deller@gmx.de>");
+MODULE_DESCRIPTION("HP GSC PS/2 port driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl);
+
+#define PFX "gscps2.c: "
+
+/* 
+ * Driver constants
+ */
+
+/* various constants */
+#define ENABLE			1
+#define DISABLE			0
+
+#define GSC_DINO_OFFSET		0x0800	/* offset for DINO controller versus LASI one */
+
+/* PS/2 IO port offsets */
+#define GSC_ID			0x00	/* device ID offset (see: GSC_ID_XXX) */
+#define GSC_RESET		0x00	/* reset port offset */
+#define GSC_RCVDATA		0x04	/* receive port offset */
+#define GSC_XMTDATA		0x04	/* transmit port offset */
+#define GSC_CONTROL		0x08	/* see: Control register bits */
+#define GSC_STATUS		0x0C	/* see: Status register bits */
+
+/* Control register bits */
+#define GSC_CTRL_ENBL		0x01	/* enable interface */
+#define GSC_CTRL_LPBXR		0x02	/* loopback operation */
+#define GSC_CTRL_DIAG		0x20	/* directly control clock/data line */
+#define GSC_CTRL_DATDIR		0x40	/* data line direct control */
+#define GSC_CTRL_CLKDIR		0x80	/* clock line direct control */
+
+/* Status register bits */
+#define GSC_STAT_RBNE		0x01	/* Receive Buffer Not Empty */
+#define GSC_STAT_TBNE		0x02	/* Transmit Buffer Not Empty */
+#define GSC_STAT_TERR		0x04	/* Timeout Error */
+#define GSC_STAT_PERR		0x08	/* Parity Error */
+#define GSC_STAT_CMPINTR	0x10	/* Composite Interrupt = irq on any port */
+#define GSC_STAT_DATSHD		0x40	/* Data Line Shadow */
+#define GSC_STAT_CLKSHD		0x80	/* Clock Line Shadow */
+
+/* IDs returned by GSC_ID port register */
+#define GSC_ID_KEYBOARD		0	/* device ID values */
+#define GSC_ID_MOUSE		1
+
+
+static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs);
+
+#define BUFFER_SIZE 0x0f
+
+/* GSC PS/2 port device struct */
+struct gscps2port {
+	struct list_head node;
+	struct parisc_device *padev;
+	struct serio port;
+	spinlock_t lock;
+	char *addr;
+	u8 act, append; /* position in buffer[] */
+	struct {
+		u8 data;
+		u8 str;
+	} buffer[BUFFER_SIZE+1];
+	int id;
+	char name[32];
+};
+
+/*
+ * Various HW level routines
+ */
+
+#define gscps2_readb_input(x)		readb((x)+GSC_RCVDATA)
+#define gscps2_readb_control(x)		readb((x)+GSC_CONTROL)
+#define gscps2_readb_status(x)		readb((x)+GSC_STATUS)
+#define gscps2_writeb_control(x, y)	writeb((x), (y)+GSC_CONTROL)
+
+
+/*
+ * wait_TBE() - wait for Transmit Buffer Empty
+ */
+
+static int wait_TBE(char *addr)
+{
+	int timeout = 25000; /* device is expected to react within 250 msec */
+	while (gscps2_readb_status(addr) & GSC_STAT_TBNE) {
+		if (!--timeout)
+			return 0;	/* This should not happen */
+		udelay(10);
+	}
+	return 1;
+}
+
+
+/*
+ * gscps2_flush() - flush the receive buffer
+ */
+
+static void gscps2_flush(struct gscps2port *ps2port)
+{
+	while (gscps2_readb_status(ps2port->addr) & GSC_STAT_RBNE)
+		gscps2_readb_input(ps2port->addr);
+	ps2port->act = ps2port->append = 0;
+}
+
+/*
+ * gscps2_writeb_output() - write a byte to the port
+ *
+ * returns 1 on sucess, 0 on error
+ */
+
+static inline int gscps2_writeb_output(struct gscps2port *ps2port, u8 data)
+{
+	unsigned long flags;
+	char *addr = ps2port->addr;
+
+	if (!wait_TBE(addr)) {
+		printk(KERN_DEBUG PFX "timeout - could not write byte %#x\n", data);
+		return 0;
+	}
+
+	while (gscps2_readb_status(ps2port->addr) & GSC_STAT_RBNE)
+		/* wait */;
+
+	spin_lock_irqsave(&ps2port->lock, flags);
+	writeb(data, addr+GSC_XMTDATA);
+	spin_unlock_irqrestore(&ps2port->lock, flags);
+
+	/* this is ugly, but due to timing of the port it seems to be necessary. */
+	mdelay(6);
+
+	/* make sure any received data is returned as fast as possible */
+	/* this is important e.g. when we set the LEDs on the keyboard */
+	gscps2_interrupt(0, NULL, NULL);
+
+	return 1;
+}
+
+
+/*
+ * gscps2_enable() - enables or disables the port
+ */
+
+static void gscps2_enable(struct gscps2port *ps2port, int enable)
+{
+	unsigned long flags;
+	u8 data;
+
+	/* now enable/disable the port */
+	spin_lock_irqsave(&ps2port->lock, flags);
+	gscps2_flush(ps2port);
+	data = gscps2_readb_control(ps2port->addr);
+	if (enable)
+		data |= GSC_CTRL_ENBL;
+	else
+		data &= ~GSC_CTRL_ENBL;
+	gscps2_writeb_control(data, ps2port->addr);
+	spin_unlock_irqrestore(&ps2port->lock, flags);
+	wait_TBE(ps2port->addr);
+	gscps2_flush(ps2port);
+}
+
+/*
+ * gscps2_reset() - resets the PS/2 port
+ */
+
+static void gscps2_reset(struct gscps2port *ps2port)
+{
+	char *addr = ps2port->addr;
+	unsigned long flags;
+
+	/* reset the interface */
+	spin_lock_irqsave(&ps2port->lock, flags);
+	gscps2_flush(ps2port);
+	writeb(0xff, addr+GSC_RESET);
+	gscps2_flush(ps2port);
+	spin_unlock_irqrestore(&ps2port->lock, flags);
+
+	/* enable it */
+	gscps2_enable(ps2port, ENABLE);
+}
+
+static LIST_HEAD(ps2port_list);
+
+/**
+ * gscps2_interrupt() - Interruption service routine
+ *
+ * This function reads received PS/2 bytes and processes them on 
+ * all interfaces.
+ * The problematic part here is, that the keyboard and mouse PS/2 port
+ * share the same interrupt and it's not possible to send data if any
+ * one of them holds input data. To solve this problem we try to receive
+ * the data as fast as possible and handle the reporting to the upper layer
+ * later.
+ */
+
+static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+	struct gscps2port *ps2port;
+
+	list_for_each_entry(ps2port, &ps2port_list, node) {
+
+	  unsigned long flags;
+	  spin_lock_irqsave(&ps2port->lock, flags);
+
+	  while ( (ps2port->buffer[ps2port->append].str = 
+		   gscps2_readb_status(ps2port->addr)) & GSC_STAT_RBNE ) {
+		ps2port->buffer[ps2port->append].data = 
+				gscps2_readb_input(ps2port->addr);
+		ps2port->append = ((ps2port->append+1) & BUFFER_SIZE);
+	  }
+
+	  spin_unlock_irqrestore(&ps2port->lock, flags);
+
+	} /* list_for_each_entry */
+
+	/* all data was read from the ports - now report the data to upper layer */
+
+	list_for_each_entry(ps2port, &ps2port_list, node) {
+
+	  while (ps2port->act != ps2port->append) {
+
+	    unsigned int rxflags;
+	    u8 data, status;
+
+	    /* Did new data arrived while we read existing data ?
+	       If yes, exit now and let the new irq handler start over again */
+	    if (gscps2_readb_status(ps2port->addr) & GSC_STAT_CMPINTR)
+		return IRQ_HANDLED;
+
+	    status = ps2port->buffer[ps2port->act].str;
+	    data   = ps2port->buffer[ps2port->act].data;
+
+	    ps2port->act = ((ps2port->act+1) & BUFFER_SIZE);
+	    rxflags =	((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) |
+			((status & GSC_STAT_PERR) ? SERIO_PARITY  : 0 );
+
+	    serio_interrupt(&ps2port->port, data, rxflags, regs);
+
+	  } /* while() */
+
+	} /* list_for_each_entry */
+
+	return IRQ_HANDLED;
+}
+
+
+/*
+ * gscps2_write() - send a byte out through the aux interface.
+ */
+
+static int gscps2_write(struct serio *port, unsigned char data)
+{
+	struct gscps2port *ps2port = port->driver;
+
+	if (!gscps2_writeb_output(ps2port, data)) {
+		printk(KERN_DEBUG PFX "sending byte %#x failed.\n", data);
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * gscps2_open() is called when a port is opened by the higher layer.
+ * It resets and enables the port.
+ */
+
+static int gscps2_open(struct serio *port)
+{
+	struct gscps2port *ps2port = port->driver;
+
+	gscps2_reset(ps2port);
+
+	gscps2_interrupt(0, NULL, NULL);
+
+	return 0;
+}
+
+/*
+ * gscps2_close() disables the port
+ */
+
+static void gscps2_close(struct serio *port)
+{
+	struct gscps2port *ps2port = port->driver;
+	gscps2_enable(ps2port, DISABLE);
+}
+
+static struct serio gscps2_serio_port =
+{
+	.name =		"GSC PS/2",
+	.idbus =	BUS_GSC,
+	.idvendor =	PCI_VENDOR_ID_HP,
+	.idproduct =	0x0001,
+	.idversion =	0x0010,
+	.type =		SERIO_8042,
+	.write =	gscps2_write,
+	.open =		gscps2_open,
+	.close =	gscps2_close,
+};
+
+/**
+ * gscps2_probe() - Probes PS2 devices
+ * @return: success/error report
+ */
+
+static int __init gscps2_probe(struct parisc_device *dev)
+{
+        struct gscps2port *ps2port;
+	unsigned long hpa = dev->hpa;
+	int ret;
+
+	if (!dev->irq)
+		return -ENODEV;
+	
+	/* Offset for DINO PS/2. Works with LASI even */
+	if (dev->id.sversion == 0x96)
+		hpa += GSC_DINO_OFFSET;
+
+	ps2port = kmalloc(sizeof(struct gscps2port), GFP_KERNEL);
+	if (!ps2port)
+		return -ENOMEM;
+
+	dev_set_drvdata(&dev->dev, ps2port);
+
+	memset(ps2port, 0, sizeof(struct gscps2port));
+	ps2port->padev = dev;
+	ps2port->addr = ioremap(hpa, GSC_STATUS + 4);
+	spin_lock_init(&ps2port->lock);
+
+	gscps2_reset(ps2port);
+	ps2port->id = readb(ps2port->addr+GSC_ID) & 0x0f;
+	snprintf(ps2port->name, sizeof(ps2port->name)-1, "%s %s",
+		gscps2_serio_port.name, 
+		(ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse" );
+
+	memcpy(&ps2port->port, &gscps2_serio_port, sizeof(gscps2_serio_port));
+	ps2port->port.driver = ps2port;
+	ps2port->port.name = ps2port->name;
+	ps2port->port.phys = dev->dev.bus_id;
+
+	list_add_tail(&ps2port->node, &ps2port_list);
+
+	ret = -EBUSY;
+	if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->name, ps2port))
+		goto fail_miserably;
+
+	if ( (ps2port->id != GSC_ID_KEYBOARD) && (ps2port->id != GSC_ID_MOUSE) ) {
+		printk(KERN_WARNING PFX "Unsupported PS/2 port at 0x%08lx (id=%d) ignored\n",
+				hpa, ps2port->id);
+		ret = -ENODEV;
+		goto fail;
+	}
+
+#if 0
+	if (!request_mem_region(hpa, GSC_STATUS + 4, ps2port->port.name))
+		goto fail;
+#endif
+
+	printk(KERN_INFO "serio: %s port at 0x%p irq %d @ %s\n",
+		ps2port->name,
+		ps2port->addr,
+		ps2port->padev->irq,
+		ps2port->port.phys);
+
+	serio_register_port(&ps2port->port);
+	
+	return 0;
+	
+fail:
+	free_irq(dev->irq, ps2port);
+
+fail_miserably:
+	list_del(&ps2port->node);
+	iounmap(ps2port->addr);
+	release_mem_region(dev->hpa, GSC_STATUS + 4);
+	kfree(ps2port);
+	return ret;
+}
+
+/**
+ * gscps2_remove() - Removes PS2 devices
+ * @return: success/error report
+ */
+
+static int __devexit gscps2_remove(struct parisc_device *dev)
+{
+	struct gscps2port *ps2port = dev_get_drvdata(&dev->dev);
+
+	serio_unregister_port(&ps2port->port);
+	free_irq(dev->irq, ps2port);
+	gscps2_flush(ps2port);
+	list_del(&ps2port->node);
+	iounmap(ps2port->addr);
+#if 0
+	release_mem_region(dev->hpa, GSC_STATUS + 4); 
+#endif
+	dev_set_drvdata(&dev->dev, NULL);
+	kfree(ps2port);
+	return 0;
+}
+
+
+static struct parisc_device_id gscps2_device_tbl[] = {
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00084 }, /* LASI PS/2 */
+#ifdef DINO_TESTED
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00096 }, /* DINO PS/2 */ 
+#endif
+	{ 0, }	/* 0 terminated list */
+};
+
+static struct parisc_driver parisc_ps2_driver = {
+	.name		= "GSC PS/2",
+	.id_table	= gscps2_device_tbl,
+	.probe		= gscps2_probe,
+	.remove		= gscps2_remove,
+};
+
+static int __init gscps2_init(void)
+{
+	register_parisc_driver(&parisc_ps2_driver);
+	return 0;
+}
+
+static void __exit gscps2_exit(void)
+{
+	unregister_parisc_driver(&parisc_ps2_driver);
+}
+
+
+module_init(gscps2_init);
+module_exit(gscps2_exit);
+
--- diff/drivers/net/kgdb_eth.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/net/kgdb_eth.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,131 @@
+/*
+ * Network interface GDB stub
+ *
+ * Written by San Mehat (nettwerk@biodome.org)
+ * Based upon 'gdbserial' by David Grothe (dave@gcom.com)
+ * and Scott Foehner (sfoehner@engr.sgi.com)
+ *
+ * Twiddled for 2.6 by Robert Walsh <rjwalsh@durables.org>
+ * and wangdi <wangdi@clusterfs.com>.
+ *
+ * Refactored for netpoll API by Matt Mackall <mpm@selenic.com>
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/netpoll.h>
+
+#include <asm/system.h>
+#include <asm/kgdb.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+
+#define IN_BUF_SIZE 512 /* power of 2, please */
+#define OUT_BUF_SIZE 256
+
+static char in_buf[IN_BUF_SIZE], out_buf[OUT_BUF_SIZE];
+static int in_head, in_tail, out_count;
+static atomic_t in_count;
+int kgdboe = 0; /* Default to tty mode */
+
+extern void set_debug_traps(void);
+extern void breakpoint(void);
+static void rx_hook(struct netpoll *np, int port, char *msg, int len);
+
+static struct netpoll np = {
+	.name = "kgdboe",
+	.dev_name = "eth0",
+	.rx_hook = rx_hook,
+	.local_port = 6443,
+	.remote_port = 6442,
+	.remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+};
+
+int eth_getDebugChar(void)
+{
+	int chr;
+
+	while (atomic_read(&in_count) == 0)
+		netpoll_poll(&np);
+
+	chr = in_buf[in_tail++];
+	in_tail &= (IN_BUF_SIZE - 1);
+	atomic_dec(&in_count);
+	return chr;
+}
+
+void eth_flushDebugChar(void)
+{
+	if(out_count && np.dev) {
+		netpoll_send_udp(&np, out_buf, out_count);
+		out_count = 0;
+	}
+}
+
+void eth_putDebugChar(int chr)
+{
+	out_buf[out_count++] = chr;
+	if(out_count == OUT_BUF_SIZE)
+		eth_flushDebugChar();
+}
+
+static void rx_hook(struct netpoll *np, int port, char *msg, int len)
+{
+	int i;
+
+	np->remote_port = port;
+
+	/* Is this gdb trying to attach? */
+	if (!netpoll_trap() && len == 8 && !strncmp(msg, "$Hc-1#09", 8))
+		kgdb_schedule_breakpoint();
+
+	for (i = 0; i < len; i++) {
+		if (msg[i] == 3)
+			kgdb_schedule_breakpoint();
+
+		if (atomic_read(&in_count) >= IN_BUF_SIZE) {
+			/* buffer overflow, clear it */
+			in_head = in_tail = 0;
+			atomic_set(&in_count, 0);
+			break;
+		}
+		in_buf[in_head++] = msg[i];
+		in_head &= (IN_BUF_SIZE - 1);
+		atomic_inc(&in_count);
+	}
+}
+
+static int option_setup(char *opt)
+{
+	return netpoll_parse_options(&np, opt);
+}
+
+__setup("kgdboe=", option_setup);
+
+static int init_kgdboe(void)
+{
+#ifdef CONFIG_SMP
+	if (num_online_cpus() > CONFIG_NO_KGDB_CPUS) {
+		printk("kgdb: too manu cpus. Cannot enable debugger with more than %d cpus\n", CONFIG_NO_KGDB_CPUS);
+		return -1;
+	}
+#endif
+
+	set_debug_traps();
+
+	if(!np.remote_ip || netpoll_setup(&np))
+		return 1;
+
+	kgdboe = 1;
+	printk(KERN_INFO "kgdb: debugging over ethernet enabled\n");
+
+	return 0;
+}
+
+module_init(init_kgdboe);
--- diff/drivers/net/netconsole.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/net/netconsole.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,127 @@
+/*
+ *  linux/drivers/net/netconsole.c
+ *
+ *  Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
+ *
+ *  This file contains the implementation of an IRQ-safe, crash-safe
+ *  kernel console implementation that outputs kernel messages to the
+ *  network.
+ *
+ * Modification history:
+ *
+ * 2001-09-17    started by Ingo Molnar.
+ * 2003-08-11    2.6 port by Matt Mackall
+ *               simplified options
+ *               generic card hooks
+ *               works non-modular
+ * 2003-09-07    rewritten with netpoll api
+ */
+
+/****************************************************************
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2, or (at your option)
+ *      any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      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/mm.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/tty_driver.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/sysrq.h>
+#include <linux/smp.h>
+#include <linux/netpoll.h>
+
+MODULE_AUTHOR("Maintainer: Matt Mackall <mpm@selenic.com>");
+MODULE_DESCRIPTION("Console driver for network interfaces");
+MODULE_LICENSE("GPL");
+
+static char config[256];
+module_param_string(netconsole, config, 256, 0);
+MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]\n");
+
+static struct netpoll np = {
+	.name = "netconsole",
+	.dev_name = "eth0",
+	.local_port = 6665,
+	.remote_port = 6666,
+	.remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+};
+static int configured = 0;
+
+#define MAX_PRINT_CHUNK 1000
+
+static void write_msg(struct console *con, const char *msg, unsigned int len)
+{
+	int frag, left;
+	unsigned long flags;
+
+	if (!np.dev)
+		return;
+
+	local_irq_save(flags);
+
+	for(left = len; left; ) {
+		frag = min(left, MAX_PRINT_CHUNK);
+		netpoll_send_udp(&np, msg, frag);
+		msg += frag;
+		left -= frag;
+	}
+
+	local_irq_restore(flags);
+}
+
+static struct console netconsole = {
+	.flags = CON_ENABLED | CON_PRINTBUFFER,
+	.write = write_msg
+};
+
+static int option_setup(char *opt)
+{
+	configured = !netpoll_parse_options(&np, opt);
+	return 0;
+}
+
+__setup("netconsole=", option_setup);
+
+static int init_netconsole(void)
+{
+	if(strlen(config))
+		option_setup(config);
+
+	if(!configured) {
+		printk("netconsole: not configured, aborting\n");
+		return -EINVAL;
+	}
+
+	if(netpoll_setup(&np))
+		return -EINVAL;
+
+	register_console(&netconsole);
+	printk(KERN_INFO "netconsole: network logging started\n");
+	return 0;
+}
+
+static void cleanup_netconsole(void)
+{
+	unregister_console(&netconsole);
+	netpoll_cleanup(&np);
+}
+
+module_init(init_netconsole);
+module_exit(cleanup_netconsole);
--- diff/drivers/scsi/scsi_transport_fc.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/scsi/scsi_transport_fc.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,104 @@
+/* 
+ *  FiberChannel transport specific attributes exported to sysfs.
+ *
+ *  Copyright (c) 2003 Silicon Graphics, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_fc.h>
+
+static void transport_class_release(struct class_device *class_dev);
+
+struct class fc_transport_class = {
+	.name = "fc_transport",
+	.release = transport_class_release,
+};
+
+static __init int fc_transport_init(void)
+{
+	return class_register(&fc_transport_class);
+}
+
+static void __exit fc_transport_exit(void)
+{
+	class_unregister(&fc_transport_class);
+}
+
+static int fc_setup_transport_attrs(struct scsi_device *sdev)
+{
+	/* FIXME: Callback into the driver */
+	fc_node_name(sdev) = -1;
+	fc_port_name(sdev) = -1;
+	fc_port_id(sdev) = -1;
+
+	return 0;
+}
+
+static void transport_class_release(struct class_device *class_dev)
+{
+	struct scsi_device *sdev = transport_class_to_sdev(class_dev);
+	put_device(&sdev->sdev_gendev);
+}
+
+#define fc_transport_show_function(field, format_string, cast)			\
+static ssize_t									\
+show_fc_transport_##field (struct class_device *cdev, char *buf)		\
+{										\
+	struct scsi_device *sdev = transport_class_to_sdev(cdev);		\
+	struct fc_transport_attrs *tp;						\
+	tp = (struct fc_transport_attrs *)&sdev->transport_data;		\
+	return snprintf(buf, 20, format_string, cast tp->field);		\
+}
+
+#define fc_transport_rd_attr(field, format_string)				\
+	fc_transport_show_function(field, format_string, )			\
+static CLASS_DEVICE_ATTR( field, S_IRUGO, show_fc_transport_##field, NULL)
+
+#define fc_transport_rd_attr_cast(field, format_string, cast)			\
+	fc_transport_show_function(field, format_string, (cast))		\
+static CLASS_DEVICE_ATTR( field, S_IRUGO, show_fc_transport_##field, NULL)
+
+/* the FiberChannel Tranport Attributes: */
+fc_transport_rd_attr_cast(node_name, "0x%llx\n", unsigned long long);
+fc_transport_rd_attr_cast(port_name, "0x%llx\n", unsigned long long);
+fc_transport_rd_attr(port_id, "0x%06x\n");
+
+struct class_device_attribute *fc_transport_attrs[] = {
+	&class_device_attr_node_name,
+	&class_device_attr_port_name,
+	&class_device_attr_port_id,
+	NULL
+};
+
+struct scsi_transport_template fc_transport_template = {
+	.attrs = fc_transport_attrs,
+	.class = &fc_transport_class,
+	.setup = &fc_setup_transport_attrs,
+	.cleanup = NULL,
+	.size = sizeof(struct fc_transport_attrs) - sizeof(unsigned long),
+};
+EXPORT_SYMBOL(fc_transport_template);
+
+MODULE_AUTHOR("Martin Hicks");
+MODULE_DESCRIPTION("FC Transport Attributes");
+MODULE_LICENSE("GPL");
+
+module_init(fc_transport_init);
+module_exit(fc_transport_exit);
--- diff/drivers/scsi/scsi_transport_spi.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/scsi/scsi_transport_spi.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,97 @@
+/* 
+ *  Parallel SCSI (SPI) transport specific attributes exported to sysfs.
+ *
+ *  Copyright (c) 2003 Silicon Graphics, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
+
+static void transport_class_release(struct class_device *class_dev);
+
+struct class spi_transport_class = {
+	.name = "spi_transport",
+	.release = transport_class_release,
+};
+
+static __init int spi_transport_init(void)
+{
+	return class_register(&spi_transport_class);
+}
+
+static void __exit spi_transport_exit(void)
+{
+	class_unregister(&spi_transport_class);
+}
+
+static int spi_setup_transport_attrs(struct scsi_device *sdev)
+{
+	/* FIXME: should callback into the driver to get these values */
+	spi_period(sdev) = -1;
+	spi_offset(sdev) = -1;
+
+	return 0;
+}
+
+static void transport_class_release(struct class_device *class_dev)
+{
+	struct scsi_device *sdev = transport_class_to_sdev(class_dev);
+	put_device(&sdev->sdev_gendev);
+}
+
+#define spi_transport_show_function(field, format_string)			\
+static ssize_t									\
+show_spi_transport_##field (struct class_device *cdev, char *buf)		\
+{										\
+	struct scsi_device *sdev = transport_class_to_sdev(cdev);		\
+	struct spi_transport_attrs *tp;						\
+	tp = (struct spi_transport_attrs *)&sdev->transport_data;		\
+	return snprintf(buf, 20, format_string, tp->field);			\
+}
+
+#define spi_transport_rd_attr(field, format_string)				\
+	spi_transport_show_function(field, format_string)			\
+static CLASS_DEVICE_ATTR( field, S_IRUGO, show_spi_transport_##field, NULL)
+
+/* The Parallel SCSI Tranport Attributes: */
+spi_transport_rd_attr(period, "%d\n");
+spi_transport_rd_attr(offset, "%d\n");
+
+struct class_device_attribute *spi_transport_attrs[] = {
+	&class_device_attr_period,
+	&class_device_attr_offset,
+	NULL
+};
+
+struct scsi_transport_template spi_transport_template = {
+	.attrs = spi_transport_attrs,
+	.class = &spi_transport_class,
+	.setup = &spi_setup_transport_attrs,
+	.cleanup = NULL,
+	.size = sizeof(struct spi_transport_attrs) - sizeof(unsigned long),
+};
+EXPORT_SYMBOL(spi_transport_template);
+
+MODULE_AUTHOR("Martin Hicks");
+MODULE_DESCRIPTION("SPI Transport Attributes");
+MODULE_LICENSE("GPL");
+
+module_init(spi_transport_init);
+module_exit(spi_transport_exit);
--- diff/drivers/usb/gadget/config.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/usb/gadget/config.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,116 @@
+/*
+ * usb/gadget/config.c -- simplify building config descriptors
+ *
+ * Copyright (C) 2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/string.h>
+#include <linux/device.h>
+
+#include <linux/usb_ch9.h>
+
+
+/**
+ * usb_descriptor_fillbuf - fill buffer with descriptors
+ * @buf: Buffer to be filled
+ * @buflen: Size of buf
+ * @src: Array of descriptor pointers, terminated by null pointer.
+ *
+ * Copies descriptors into the buffer, returning the length or a
+ * negative error code if they can't all be copied.  Useful when
+ * assembling descriptors for an associated set of interfaces used
+ * as part of configuring a composite device; or in other cases where
+ * sets of descriptors need to be marshaled.
+ */
+int
+usb_descriptor_fillbuf(void *buf, unsigned buflen,
+		const struct usb_descriptor_header **src)
+{
+	u8	*dest = buf;
+
+	if (!src)
+		return -EINVAL;
+
+	/* fill buffer from src[] until null descriptor ptr */
+	for (; 0 != *src; src++) {
+		unsigned		len = (*src)->bLength;
+
+		if (len > buflen);
+			return -EINVAL;
+		memcpy(dest, *src, len);
+		buflen -= len;
+		dest += len;
+	}
+	return dest - (u8 *)buf;
+}
+
+
+/**
+ * usb_gadget_config_buf - builts a complete configuration descriptor
+ * @config: Header for the descriptor, including characteristics such
+ *	as power requirements and number of interfaces.
+ * @desc: Null-terminated vector of pointers to the descriptors (interface,
+ *	endpoint, etc) defining all functions in this device configuration.
+ * @buf: Buffer for the resulting configuration descriptor.
+ * @length: Length of buffer.  If this is not big enough to hold the
+ *	entire configuration descriptor, an error code will be returned.
+ *
+ * This copies descriptors into the response buffer, building a descriptor
+ * for that configuration.  It returns the buffer length or a negative
+ * status code.  The config.wTotalLength field is set to match the length
+ * of the result, but other descriptor fields (including power usage and
+ * interface count) must be set by the caller.
+ *
+ * Gadget drivers could use this when constructing a config descriptor
+ * in response to USB_REQ_GET_DESCRIPTOR.  They will need to patch the
+ * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed.
+ */
+int usb_gadget_config_buf(
+	const struct usb_config_descriptor	*config,
+	void					*buf,
+	unsigned				length,
+	const struct usb_descriptor_header	**desc
+)
+{
+	struct usb_config_descriptor		*cp = buf;
+	int					len;
+
+	/* config descriptor first */
+	if (length < USB_DT_CONFIG_SIZE || !desc)
+		return -EINVAL;
+	*cp = *config; 
+
+	/* then interface/endpoint/class/vendor/... */
+	len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
+			length - USB_DT_CONFIG_SIZE, desc);
+	if (len < 0)
+		return len;
+	len += USB_DT_CONFIG_SIZE;
+	if (len > 0xffff)
+		return -EINVAL;
+
+	/* patch up the config descriptor */
+	cp->bLength = USB_DT_CONFIG_SIZE;
+	cp->bDescriptorType = USB_DT_CONFIG;
+	cp->wTotalLength = cpu_to_le16(len);
+	cp->bmAttributes |= USB_CONFIG_ATT_ONE;
+	return len;
+}
+
--- diff/drivers/usb/input/ati_remote.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/usb/input/ati_remote.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,851 @@
+/* 
+ *  USB ATI Remote support
+ *
+ *  Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
+ *  Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev
+ *
+ *  This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including
+ *  porting to the 2.6 kernel interfaces, along with other modification 
+ *  to better match the style of the existing usb/input drivers.  However, the
+ *  protocol and hardware handling is essentially unchanged from 2.1.1.
+ *  
+ *  The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by 
+ *  Vojtech Pavlik.
+ *
+ *  Changes:
+ *
+ *  Feb 2004: Torrey Hoffman <thoffman@arnor.net>
+ *            Version 2.2.0
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+ *
+ * Hardware & software notes
+ *
+ * These remote controls are distributed by ATI as part of their 
+ * "All-In-Wonder" video card packages.  The receiver self-identifies as a 
+ * "USB Receiver" with manufacturer "X10 Wireless Technology Inc".
+ *
+ * It is possible to use multiple receivers and remotes on multiple computers 
+ * simultaneously by configuring them to use specific channels.
+ * 
+ * The RF protocol used by the remote supports 16 distinct channels, 1 to 16.  
+ * Actually, it may even support more, at least in some revisions of the 
+ * hardware.
+ *
+ * Each remote can be configured to transmit on one channel as follows:
+ *   - Press and hold the "hand icon" button.  
+ *   - When the red LED starts to blink, let go of the "hand icon" button. 
+ *   - When it stops blinking, input the channel code as two digits, from 01 
+ *     to 16, and press the hand icon again.
+ * 
+ * The timing can be a little tricky.  Try loading the module with debug=1
+ * to have the kernel print out messages about the remote control number
+ * and mask.  Note: debugging prints remote numbers as zero-based hexadecimal.
+ *
+ * The driver has a "channel_mask" parameter. This bitmask specifies which
+ * channels will be ignored by the module.  To mask out channels, just add 
+ * all the 2^channel_number values together.
+ *
+ * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote
+ * ignore signals coming from remote controls transmitting on channel 4, but 
+ * accept all other channels.
+ *
+ * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be 
+ * ignored.
+ *
+ * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this 
+ * parameter are unused.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+
+/*
+ * Module and Version Information, Module Parameters
+ */
+ 
+#define ATI_REMOTE_VENDOR_ID 	0x0bc7
+#define ATI_REMOTE_PRODUCT_ID 	0x004
+
+#define DRIVER_VERSION 	        "2.2.0"
+#define DRIVER_AUTHOR           "Torrey Hoffman <thoffman@arnor.net>"
+#define DRIVER_DESC             "ATI/X10 RF USB Remote Control"
+
+#define NAME_BUFSIZE      80    /* size of product name, path buffers */
+#define DATA_BUFSIZE      63    /* size of URB data buffers */
+#define ATI_INPUTNUM      1     /* Which input device to register as */
+
+unsigned long channel_mask = 0;
+module_param(channel_mask, ulong, 444);
+MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore");
+
+static int debug = 0;
+module_param(debug, int, 444);
+MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
+
+#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
+#undef err
+#define err(format, arg...) printk(KERN_ERR format , ## arg)
+ 
+static struct usb_device_id ati_remote_table[] = {
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) },
+	{}	/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, ati_remote_table);
+
+/* Get hi and low bytes of a 16-bits int */
+#define HI(a)	((unsigned char)((a) >> 8))
+#define LO(a)	((unsigned char)((a) & 0xff))
+
+#define SEND_FLAG_IN_PROGRESS	1
+#define SEND_FLAG_COMPLETE	2
+
+/* Device initialization strings */
+static char init1[] = { 0x01, 0x00, 0x20, 0x14 };
+static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
+
+/* Acceleration curve for directional control pad */
+static char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
+
+/* Duplicate event filtering time. 
+ * Sequential, identical KIND_FILTERED inputs with less than
+ * FILTER_TIME jiffies between them are dropped.  
+ * (HZ >> 4) == 1/16th of a second and works well for me.
+ */
+#define FILTER_TIME (HZ >> 4)
+
+struct ati_remote {
+	struct input_dev idev;		
+	struct usb_device *udev;
+	struct usb_interface *interface;
+		
+	struct urb *irq_urb;
+	struct urb *out_urb;
+	struct usb_endpoint_descriptor *endpoint_in;
+	struct usb_endpoint_descriptor *endpoint_out;
+	unsigned char *inbuf;
+	unsigned char *outbuf;
+	dma_addr_t inbuf_dma;
+	dma_addr_t outbuf_dma;
+
+	int open;                   /* open counter */
+	int present;                /* device plugged in? */
+	
+	unsigned char old_data[2];  /* Detect duplicate events */
+	unsigned long old_jiffies;
+	unsigned long acc_jiffies;  /* handle acceleration */
+	
+	char name[NAME_BUFSIZE];
+	char phys[NAME_BUFSIZE];
+
+	wait_queue_head_t wait;
+	int send_flags;
+};
+
+/* "Kinds" of messages sent from the hardware to the driver. */
+#define KIND_END        0
+#define KIND_LITERAL    1   /* Simply pass to input system */
+#define KIND_FILTERED   2   /* Add artificial key-up events, drop keyrepeats */
+#define KIND_LU         3   /* Directional keypad diagonals - left up, */
+#define KIND_RU         4   /*   right up,  */
+#define KIND_LD         5   /*   left down, */
+#define KIND_RD         6   /*   right down */
+#define KIND_ACCEL      7   /* Directional keypad - left, right, up, down.*/
+
+/* Translation table from hardware messages to input events. */
+static struct
+{
+	short kind;
+	unsigned char data1, data2;
+	int type;
+	unsigned int code;
+	int value;
+}  ati_remote_tbl[] = 
+{
+	/* Directional control pad axes */
+	{KIND_ACCEL,   0x35, 0x70, EV_REL, REL_X, -1},	 /* left */
+	{KIND_ACCEL,   0x36, 0x71, EV_REL, REL_X, 1},    /* right */
+	{KIND_ACCEL,   0x37, 0x72, EV_REL, REL_Y, -1},	 /* up */
+	{KIND_ACCEL,   0x38, 0x73, EV_REL, REL_Y, 1},    /* down */
+	/* Directional control pad diagonals */	
+	{KIND_LU,      0x39, 0x74, EV_REL, 0, 0},        /* left up */
+	{KIND_RU,      0x3a, 0x75, EV_REL, 0, 0},        /* right up */
+	{KIND_LD,      0x3c, 0x77, EV_REL, 0, 0},        /* left down */
+	{KIND_RD,      0x3b, 0x76, EV_REL, 0, 0},        /* right down */
+
+	/* "Mouse button" buttons */
+	{KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */
+	{KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */
+	{KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */
+	{KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */
+
+	/* Artificial "doubleclick" events are generated by the hardware. 
+	 * They are mapped to the "side" and "extra" mouse buttons here. */
+	{KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */
+	{KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */
+
+	/* keyboard. */
+	{KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1},
+	{KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1},
+	{KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1},
+	{KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1},
+	{KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1},
+	{KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1},
+	{KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1},
+	{KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1},
+	{KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1},
+	{KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1},
+	{KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1},
+	{KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_B, 1},
+	{KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_C, 1},
+	{KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1},
+	{KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1},
+	{KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1},
+
+	/* "special" keys */
+	{KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1},    /* "check" */
+	{KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1},       /* "menu" */
+	{KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1},      /* Power */
+	{KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_PROG1, 1},      /* TV */
+	{KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_PROG2, 1},      /* DVD */
+	{KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1},        /* WEB */
+	{KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1},  /* "book" */
+	{KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1},       /* "hand" */
+	{KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_COFFEE, 1},     /* "timer" */
+	{KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_FRONT, 1},      /* "max" */
+	{KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1},       /* left */
+	{KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1},      /* right */
+	{KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1},       /* down */
+	{KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1},         /* up */
+	{KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_ENTER, 1},      /* "OK" */
+	{KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */
+	{KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1},   /* VOL - */
+	{KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1},       /* MUTE  */
+	{KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELUP, 1},  /* CH + */
+	{KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */
+	{KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1},     /* ( o) red */
+	{KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAYCD, 1},     /* ( >) */
+	{KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1},     /* (<<) */
+	{KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1},    /* (>>) */
+	{KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1},       /* ([]) */ 
+	{KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1},      /* ('') */
+	
+	{KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
+};
+
+/* Local function prototypes */
+static void ati_remote_dump		(unsigned char *data, unsigned int actual_length);
+static void ati_remote_delete		(struct ati_remote *dev);
+static int ati_remote_open		(struct input_dev *inputdev);
+static void ati_remote_close		(struct input_dev *inputdev);
+static int ati_remote_sendpacket	(struct ati_remote *ati_remote, u16 cmd, unsigned char *data);
+static void ati_remote_irq_out		(struct urb *urb, struct pt_regs *regs);
+static void ati_remote_irq_in		(struct urb *urb, struct pt_regs *regs);
+static void ati_remote_input_report	(struct urb *urb, struct pt_regs *regs);
+static int ati_remote_initialize	(struct ati_remote *ati_remote);
+static int ati_remote_probe		(struct usb_interface *interface, const struct usb_device_id *id);
+static void ati_remote_disconnect	(struct usb_interface *interface);
+
+/* usb specific object to register with the usb subsystem */
+static struct usb_driver ati_remote_driver = {
+	.owner        = THIS_MODULE,
+	.name         = "ati_remote",
+	.probe        = ati_remote_probe,
+	.disconnect   = ati_remote_disconnect,
+	.id_table     = ati_remote_table,
+};
+
+/*
+ *	ati_remote_dump_input
+ */
+static void ati_remote_dump(unsigned char *data, unsigned int len)
+{
+	if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00))
+		warn("Weird byte 0x%02x\n", data[0]);
+	else if (len == 4)
+		warn("Weird key %02x %02x %02x %02x\n", 
+		     data[0], data[1], data[2], data[3]);
+	else
+		warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n",
+		     len, data[0], data[1], data[2], data[3], data[4], data[5]);
+}
+
+/*
+ *	ati_remote_open
+ */
+static int ati_remote_open(struct input_dev *inputdev)
+{
+	struct ati_remote *ati_remote = inputdev->private;
+
+	if (ati_remote->open++)
+		return 0;
+
+	/* On first open, submit the read urb which was set up previously. */
+	ati_remote->irq_urb->dev = ati_remote->udev;
+	if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) {
+		dev_err(&ati_remote->interface->dev, 
+			"%s: usb_submit_urb failed!\n", __FUNCTION__);
+		ati_remote->open--;
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ *	ati_remote_close
+ */
+static void ati_remote_close(struct input_dev *inputdev)
+{
+	struct ati_remote *ati_remote = inputdev->private;
+	
+	if (ati_remote == NULL) {
+		err("ati_remote: %s: object is NULL!\n", __FUNCTION__);
+		return;
+	}
+	
+	if (ati_remote->open <= 0)
+		dev_dbg(&ati_remote->interface->dev, "%s: Not open.\n", __FUNCTION__);
+	else
+		--ati_remote->open;
+	
+	/* If still present, disconnect will call delete. */
+	if (!ati_remote->present && !ati_remote->open)
+		ati_remote_delete(ati_remote);
+}
+
+/*
+ *		ati_remote_irq_out
+ */
+static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs)
+{
+	struct ati_remote *ati_remote = urb->context;
+	
+	if (urb->status) {
+		dev_dbg(&ati_remote->interface->dev, "%s: status %d\n",
+			__FUNCTION__, urb->status);
+		return;
+	}
+	
+	ati_remote->send_flags |= SEND_FLAG_COMPLETE;
+	wmb();
+	if (waitqueue_active(&ati_remote->wait))
+		wake_up(&ati_remote->wait);
+}
+
+/*
+ *	ati_remote_sendpacket
+ *		
+ *	Used to send device initialization strings
+ */
+static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int timeout = HZ;	/* 1 second */
+	int retval = 0;
+	
+	/* Set up out_urb */
+	memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd));
+	((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd);	
+
+	ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1;
+	ati_remote->out_urb->dev = ati_remote->udev;
+	ati_remote->send_flags = SEND_FLAG_IN_PROGRESS;
+
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&ati_remote->wait, &wait);
+
+	retval = usb_submit_urb(ati_remote->out_urb, GFP_KERNEL);
+	if (retval) {
+		set_current_state(TASK_RUNNING);
+		remove_wait_queue(&ati_remote->wait, &wait);
+		dev_dbg(&ati_remote->interface->dev, 
+			 "sendpacket: usb_submit_urb failed: %d\n", retval);
+		return retval;
+	}
+
+	while (timeout && (ati_remote->out_urb->status == -EINPROGRESS) 
+	       && !(ati_remote->send_flags & SEND_FLAG_COMPLETE)) {
+		timeout = schedule_timeout(timeout);
+		rmb();
+	}
+
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&ati_remote->wait, &wait);
+	usb_unlink_urb(ati_remote->out_urb);
+	
+	return retval;
+}
+
+/*
+ *	ati_remote_event_lookup
+ */
+static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
+{
+	int i;
+
+	for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) {
+		/* 
+		 * Decide if the table entry matches the remote input. 
+		 */
+		if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) &&
+		    ((((ati_remote_tbl[i].data1 >> 4) - 
+		       (d1 >> 4) + rem) & 0x0f) == 0x0f) && 
+		    (ati_remote_tbl[i].data2 == d2))
+			return i;
+		
+	}
+	return -1;
+}
+
+/*
+ *	ati_remote_report_input
+ */
+static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)	
+{
+	struct ati_remote *ati_remote = urb->context;
+	unsigned char *data= ati_remote->inbuf;
+	struct input_dev *dev = &ati_remote->idev; 
+	int index, acc;
+	int remote_num;
+	
+	/* Deal with strange looking inputs */
+	if ( (urb->actual_length != 4) || (data[0] != 0x14) || 
+		((data[3] & 0x0f) != 0x00) ) {
+		ati_remote_dump(data, urb->actual_length);
+		return;
+	}
+
+	/* Mask unwanted remote channels.  */
+	/* note: remote_num is 0-based, channel 1 on remote == 0 here */
+	remote_num = (data[3] >> 4) & 0x0f;
+        if (channel_mask & (1 << (remote_num + 1))) { 
+		dbginfo(&ati_remote->interface->dev,
+			"Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n",
+			remote_num, data[1], data[2], channel_mask);
+		return;
+	}
+
+	/* Look up event code index in translation table */
+	index = ati_remote_event_lookup(remote_num, data[1], data[2]);
+	if (index < 0) {
+		dev_warn(&ati_remote->interface->dev, 
+			 "Unknown input from channel 0x%02x: data %02x,%02x\n", 
+			 remote_num, data[1], data[2]);
+		return;
+	} 
+	dbginfo(&ati_remote->interface->dev, 
+		"channel 0x%02x; data %02x,%02x; index %d; keycode %d\n",
+		remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
+	
+	if (ati_remote_tbl[index].kind == KIND_LITERAL) {
+		input_regs(dev, regs);
+		input_event(dev, ati_remote_tbl[index].type,
+			ati_remote_tbl[index].code,
+			ati_remote_tbl[index].value);
+		input_sync(dev);
+		
+		ati_remote->old_jiffies = jiffies;
+		return;
+	}
+	
+	if (ati_remote_tbl[index].kind == KIND_FILTERED) {
+		/* Filter duplicate events which happen "too close" together. */
+		if ((ati_remote->old_data[0] == data[1]) && 
+	 		(ati_remote->old_data[1] == data[2]) && 
+	 		((ati_remote->old_jiffies + FILTER_TIME) > jiffies)) {
+			ati_remote->old_jiffies = jiffies;			
+			return;
+		}		
+
+		input_regs(dev, regs);
+		input_event(dev, ati_remote_tbl[index].type,
+			ati_remote_tbl[index].code, 1);
+		input_event(dev, ati_remote_tbl[index].type,
+			ati_remote_tbl[index].code, 0);
+		input_sync(dev);
+
+		ati_remote->old_data[0] = data[1];
+		ati_remote->old_data[1] = data[2];
+		ati_remote->old_jiffies = jiffies;
+		return;
+	}			
+	
+	/* 
+	 * Other event kinds are from the directional control pad, and have an
+	 * acceleration factor applied to them.  Without this acceleration, the
+	 * control pad is mostly unusable.
+	 * 
+	 * If elapsed time since last event is > 1/4 second, user "stopped",
+	 * so reset acceleration. Otherwise, user is probably holding the control
+	 * pad down, so we increase acceleration, ramping up over two seconds to
+	 * a maximum speed.  The acceleration curve is #defined above.
+	 */
+	if ((jiffies - ati_remote->old_jiffies) > (HZ >> 2)) {
+		acc = 1;
+		ati_remote->acc_jiffies = jiffies;
+	}
+	else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 3))  acc = accel[0];
+	else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 2))  acc = accel[1];
+	else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 1))  acc = accel[2];
+	else if ((jiffies - ati_remote->acc_jiffies) < HZ )        acc = accel[3];
+	else if ((jiffies - ati_remote->acc_jiffies) < HZ+(HZ>>1)) acc = accel[4];
+	else if ((jiffies - ati_remote->acc_jiffies) < (HZ << 1))  acc = accel[5];
+	else acc = accel[6];
+
+	input_regs(dev, regs);
+	switch (ati_remote_tbl[index].kind) {
+	case KIND_ACCEL:
+		input_event(dev, ati_remote_tbl[index].type,
+			ati_remote_tbl[index].code,
+			ati_remote_tbl[index].value * acc);
+		break;
+	case KIND_LU:
+		input_report_rel(dev, REL_X, -acc);
+		input_report_rel(dev, REL_Y, -acc);
+		break;
+	case KIND_RU:
+		input_report_rel(dev, REL_X, acc);
+		input_report_rel(dev, REL_Y, -acc);
+		break;
+	case KIND_LD:
+		input_report_rel(dev, REL_X, -acc);
+		input_report_rel(dev, REL_Y, acc);
+		break;
+	case KIND_RD:
+		input_report_rel(dev, REL_X, acc);
+		input_report_rel(dev, REL_Y, acc);
+		break;
+	default:
+		dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n", 
+			ati_remote_tbl[index].kind);
+	}
+	input_sync(dev);
+
+	ati_remote->old_jiffies = jiffies;
+	ati_remote->old_data[0] = data[1];
+	ati_remote->old_data[1] = data[2];
+}
+
+/*
+ *	ati_remote_irq_in
+ */
+static void ati_remote_irq_in(struct urb *urb, struct pt_regs *regs)
+{
+	struct ati_remote *ati_remote = urb->context;
+	int retval;
+
+	switch (urb->status) {
+	case 0:			/* success */
+		ati_remote_input_report(urb, regs);
+		break;
+	case -ECONNRESET:	/* unlink */
+	case -ENOENT:
+	case -ESHUTDOWN:
+		dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n",
+			__FUNCTION__);
+		return;	
+	default:		/* error */
+		dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n", 
+			__FUNCTION__, urb->status);
+	}
+	
+	retval = usb_submit_urb(urb, SLAB_ATOMIC);
+	if (retval)
+		dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n",
+			__FUNCTION__, retval);
+}
+
+/*
+ *	ati_remote_delete
+ */
+static void ati_remote_delete(struct ati_remote *ati_remote)
+{
+	if (!ati_remote) return;
+
+	if (ati_remote->irq_urb)
+		usb_unlink_urb(ati_remote->irq_urb);
+
+	if (ati_remote->out_urb)
+		usb_unlink_urb(ati_remote->out_urb);
+
+	if (ati_remote->irq_urb)
+		usb_free_urb(ati_remote->irq_urb);
+	
+	if (ati_remote->out_urb)
+		usb_free_urb(ati_remote->out_urb);
+
+	if (ati_remote->inbuf)
+		usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, 
+				ati_remote->inbuf, ati_remote->inbuf_dma);
+		
+	if (ati_remote->outbuf)
+		usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, 
+				ati_remote->inbuf, ati_remote->outbuf_dma);
+	
+	kfree(ati_remote);
+}
+
+static void ati_remote_input_init(struct ati_remote *ati_remote)
+{
+	struct input_dev *idev = &(ati_remote->idev);
+	int i;
+
+	idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+	idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) | 
+					  BIT(BTN_SIDE) | BIT(BTN_EXTRA) );
+	idev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+	for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++)
+		if (ati_remote_tbl[i].type == EV_KEY)
+			set_bit(ati_remote_tbl[i].code, idev->keybit);
+	
+	idev->private = ati_remote;
+	idev->open = ati_remote_open;
+	idev->close = ati_remote_close;
+	
+	idev->name = ati_remote->name;
+	idev->phys = ati_remote->phys;
+	
+	idev->id.bustype = BUS_USB;		
+	idev->id.vendor = ati_remote->udev->descriptor.idVendor;
+	idev->id.product = ati_remote->udev->descriptor.idProduct;
+	idev->id.version = ati_remote->udev->descriptor.bcdDevice;
+}
+
+static int ati_remote_initialize(struct ati_remote *ati_remote)
+{
+	struct usb_device *udev = ati_remote->udev;
+	int pipe, maxp;
+		
+	init_waitqueue_head(&ati_remote->wait);
+
+	/* Set up irq_urb */
+	pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress);
+	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+	maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
+	
+	usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf, 
+			 maxp, ati_remote_irq_in, ati_remote, 
+			 ati_remote->endpoint_in->bInterval);
+	ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma;
+	ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	
+	/* Set up out_urb */
+	pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress);
+	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+	maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
+
+	usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf, 
+			 maxp, ati_remote_irq_out, ati_remote, 
+			 ati_remote->endpoint_out->bInterval);
+	ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma;
+	ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	/* send initialization strings */
+	if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) ||
+	    (ati_remote_sendpacket(ati_remote, 0x8007, init2))) {
+		dev_err(&ati_remote->interface->dev, 
+			 "Initializing ati_remote hardware failed.\n");
+		return 1;
+	}
+	
+	return 0;
+}
+
+/*
+ *	ati_remote_probe
+ */
+static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(interface);
+	struct ati_remote *ati_remote = NULL;
+	struct usb_host_interface *iface_host;
+	int retval = -ENOMEM;
+	char path[64];
+	char *buf = NULL;
+
+	/* See if the offered device matches what we can accept */
+	if ((udev->descriptor.idVendor != ATI_REMOTE_VENDOR_ID) ||
+	    (udev->descriptor.idProduct != ATI_REMOTE_PRODUCT_ID)) {
+		return -ENODEV;
+	}
+
+	/* Allocate and clear an ati_remote struct */
+	if (!(ati_remote = kmalloc(sizeof (struct ati_remote), GFP_KERNEL)))
+		return -ENOMEM;
+	memset(ati_remote, 0x00, sizeof (struct ati_remote));
+
+	iface_host = interface->cur_altsetting;
+	if (iface_host->desc.bNumEndpoints != 2) {
+		err("%s: Unexpected desc.bNumEndpoints\n", __FUNCTION__);
+		retval = -ENODEV;
+		goto error;
+	}
+
+	ati_remote->endpoint_in = &(iface_host->endpoint[0].desc);
+	ati_remote->endpoint_out = &(iface_host->endpoint[1].desc);
+	ati_remote->udev = udev;
+	ati_remote->interface = interface;
+
+	if (!(ati_remote->endpoint_in->bEndpointAddress & 0x80)) {
+		err("%s: Unexpected endpoint_in->bEndpointAddress\n", __FUNCTION__);
+		retval = -ENODEV;
+		goto error;
+	}
+	if ((ati_remote->endpoint_in->bmAttributes & 3) != 3) {
+		err("%s: Unexpected endpoint_in->bmAttributes\n", __FUNCTION__);
+		retval = -ENODEV;
+		goto error;
+	}
+	if (ati_remote->endpoint_in->wMaxPacketSize == 0) {
+		err("%s: endpoint_in message size==0? \n", __FUNCTION__);
+		retval = -ENODEV;
+		goto error;
+	}
+	if (!(buf = kmalloc(NAME_BUFSIZE, GFP_KERNEL)))
+		goto error;
+
+	/* Allocate URB buffers, URBs */
+	ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC,
+					     &ati_remote->inbuf_dma);
+	if (!ati_remote->inbuf)
+		goto error;
+
+	ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC,
+					      &ati_remote->outbuf_dma);
+	if (!ati_remote->outbuf)
+		goto error;
+
+	ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!ati_remote->irq_urb)
+		goto error;
+
+	ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!ati_remote->out_urb)
+		goto error;
+
+	usb_make_path(udev, path, NAME_BUFSIZE);
+	sprintf(ati_remote->phys, "%s/input%d", path, ATI_INPUTNUM);
+	if (udev->descriptor.iManufacturer && 
+	    (usb_string(udev, udev->descriptor.iManufacturer, buf, 
+			NAME_BUFSIZE) > 0))
+		strcat(ati_remote->name, buf);
+
+	if (udev->descriptor.iProduct && 
+	    (usb_string(udev, udev->descriptor.iProduct, buf, NAME_BUFSIZE) > 0))
+		sprintf(ati_remote->name, "%s %s", ati_remote->name, buf);
+
+	if (!strlen(ati_remote->name))
+		sprintf(ati_remote->name, DRIVER_DESC "(%04x,%04x)",
+			ati_remote->udev->descriptor.idVendor, 
+			ati_remote->udev->descriptor.idProduct);
+
+	/* Device Hardware Initialization - fills in ati_remote->idev from udev. */
+	retval = ati_remote_initialize(ati_remote);
+	if (retval)
+		goto error;
+
+	/* Set up and register input device */
+	ati_remote_input_init(ati_remote);
+	input_register_device(&ati_remote->idev);
+
+	dev_info(&ati_remote->interface->dev, "Input registered: %s on %s\n", 
+		 ati_remote->name, path);
+
+	usb_set_intfdata(interface, ati_remote);
+	ati_remote->present = 1;	
+	kfree(buf);
+	return 0;
+	
+error:
+	if (buf)
+		kfree(buf);
+
+	ati_remote_delete(ati_remote);
+	return retval;
+}
+
+/*
+ *	ati_remote_disconnect
+ */
+static void ati_remote_disconnect(struct usb_interface *interface)
+{
+	struct ati_remote *ati_remote;
+	
+	ati_remote = usb_get_intfdata(interface);
+	usb_set_intfdata(interface, NULL);
+	if (!ati_remote) {
+		warn("%s - null device?\n", __FUNCTION__);
+		return;
+	}
+	
+	input_unregister_device(&ati_remote->idev);
+
+	/* Mark device as unplugged */
+	ati_remote->present = 0;
+
+	/* If device is still open, ati_remote_close will call delete. */
+	if (!ati_remote->open)
+		ati_remote_delete(ati_remote);
+}
+
+/*
+ *	ati_remote_init
+ */
+static int __init ati_remote_init(void)
+{
+	int result;
+	
+	result = usb_register(&ati_remote_driver);
+	if (result)
+		err("usb_register error #%d\n", result);
+	else
+		info("Registered USB driver " DRIVER_DESC " v. " DRIVER_VERSION);
+
+	return result;
+}
+
+/*
+ *	ati_remote_exit
+ */
+static void __exit ati_remote_exit(void)
+{
+	usb_deregister(&ati_remote_driver);
+}
+
+/* 
+ *	module specification 
+ */
+
+module_init(ati_remote_init);
+module_exit(ati_remote_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
--- diff/drivers/usb/input/mtouchusb.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/usb/input/mtouchusb.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,391 @@
+/******************************************************************************
+ * mtouchusb.c  --  Driver for Microtouch (Now 3M) USB Touchscreens
+ *
+ * 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.
+ *
+ * Based upon original work by Radoslaw Garbacz (usb-support@ite.pl)
+ *  (http://freshmeat.net/projects/3mtouchscreendriver)
+ *
+ * History
+ *
+ *  0.3 & 0.4  2002 (TEJ) tejohnson@yahoo.com
+ *    Updated to 2.4.18, then 2.4.19
+ *    Old version still relied on stealing a minor
+ *
+ *  0.5  02/26/2004 (TEJ) tejohnson@yahoo.com
+ *    Complete rewrite using Linux Input in 2.6.3
+ *    Unfortunately no calibration support at this time
+ *
+ *****************************************************************************/
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_DEBUG
+        #define DEBUG
+#else
+        #undef DEBUG
+#endif
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+
+#define MTOUCHUSB_MIN_XC                0xc8
+#define MTOUCHUSB_MAX_XC                0xff78
+#define MTOUCHUSB_XC_FUZZ               0x0
+#define MTOUCHUSB_XC_FLAT               0x0
+#define MTOUCHUSB_MIN_YC                0x0
+#define MTOUCHUSB_MAX_YC                0xff78
+#define MTOUCHUSB_YC_FUZZ               0x0
+#define MTOUCHUSB_YC_FLAT               0x0
+#define MTOUCHUSB_ASYC_REPORT           1
+#define MTOUCHUSB_REPORT_SIZE_DATA      11
+#define MTOUCHUSB_REQ_CTRLLR_ID         10
+
+#define MTOUCHUSB_GET_XC(data)          (data[4]<<8 | data[3])
+#define MTOUCHUSB_GET_YC(data)          (data[6]<<8 | data[5])
+#define MTOUCHUSB_GET_TOUCHED(data)     ((data[2] & 0x40) ? 1:0)
+
+#define DRIVER_VERSION "v0.1"
+#define DRIVER_AUTHOR "Todd E. Johnson, tejohnson@yahoo.com"
+#define DRIVER_DESC "Microtouch USB HID Touchscreen Driver"
+
+struct mtouch_usb {
+        unsigned char *data;
+        dma_addr_t data_dma;
+        struct urb *irq;
+        struct usb_device *udev;
+        struct input_dev input;
+        int open;
+        char name[128];
+        char phys[64];
+};
+
+static __s32 vendor=-1, product=-1;
+
+static struct usb_device_id mtouchusb_devices [] = {
+        { USB_DEVICE(0x0596, 0x0001) }, /* 3M (Formerly MicroTouch) 14-206 */
+        { }                             /* Terminating entry */
+};
+
+static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs)
+{
+        struct mtouch_usb *mtouch = urb->context;
+        int retval;
+
+        switch (urb->status) {
+                case 0:
+                        /* success */
+                        break;
+                case -ETIMEDOUT:
+                        /* this urb is timing out */
+                        dbg("%s - urb timed out - was the device unplugged?",
+                            __FUNCTION__);
+                        return;
+                case -ECONNRESET:
+                case -ENOENT:
+                case -ESHUTDOWN:
+                        /* this urb is terminated, clean up */
+                        dbg("%s - urb shutting down with status: %d",
+                            __FUNCTION__, urb->status);
+                        return;
+                default:
+                        dbg("%s - nonzero urb status received: %d",
+                            __FUNCTION__, urb->status);
+                        goto exit;
+        }
+
+        input_regs(&mtouch->input, regs);
+        input_report_key(&mtouch->input, BTN_TOUCH,
+                         MTOUCHUSB_GET_TOUCHED(mtouch->data));
+        input_report_abs(&mtouch->input, ABS_X,
+                         MTOUCHUSB_GET_XC(mtouch->data));
+        input_report_abs(&mtouch->input, ABS_Y,
+                         MTOUCHUSB_GET_YC(mtouch->data));
+        input_sync(&mtouch->input);
+
+exit:
+        retval = usb_submit_urb (urb, GFP_ATOMIC);
+        if (retval)
+                err ("%s - usb_submit_urb failed with result: %d",
+                     __FUNCTION__, retval);
+}
+
+static int mtouchusb_open (struct input_dev *input)
+{
+        struct mtouch_usb *mtouch = input->private;
+
+        if (mtouch->open++)
+                return 0;
+
+        mtouch->irq->dev = mtouch->udev;
+
+        if (usb_submit_urb (mtouch->irq, GFP_ATOMIC))
+                return -EIO;
+
+        return 0;
+}
+
+static void mtouchusb_close (struct input_dev *input)
+{
+        struct mtouch_usb *mtouch = input->private;
+
+        if (!--mtouch->open)
+                usb_unlink_urb (mtouch->irq);
+}
+
+static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *mtouch)
+{
+        dbg("%s - called", __FUNCTION__);
+
+        mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_SIZE_DATA,
+                                        SLAB_ATOMIC, &mtouch->data_dma);
+
+        if (!mtouch->data)
+                return -1;
+
+        return 0;
+}
+
+static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *mtouch)
+{
+        dbg("%s - called", __FUNCTION__);
+
+        if (mtouch->data)
+                usb_buffer_free(udev, MTOUCHUSB_REPORT_SIZE_DATA,
+                                mtouch->data, mtouch->data_dma);
+}
+
+static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+        struct mtouch_usb *mtouch;
+        struct usb_host_interface *interface;
+        struct usb_endpoint_descriptor *endpoint;
+        struct usb_device *udev = interface_to_usbdev (intf);
+        char path[64];
+        char *buf;
+        int nRet;
+        int ix;
+        char valid_device = 0;
+
+        dbg("%s - called", __FUNCTION__);
+        if (vendor != -1 && product != -1) {
+                info("%s - User specified USB Touch -- Vend:Prod - %x:%x",
+                     __FUNCTION__, vendor, product);
+        }
+
+        for (ix = 0; ix < sizeof (mtouchusb_devices) /
+             sizeof (struct usb_device_id); ix++) {
+                if ((udev->descriptor.idVendor ==
+                     mtouchusb_devices [ix].idVendor) &&
+                     (udev->descriptor.idProduct ==
+                     mtouchusb_devices [ix].idProduct)) {
+                        valid_device = 1;
+                        break;
+                }
+        }
+
+        if (udev->descriptor.idVendor == vendor &&
+            udev->descriptor.idProduct == product) {  /* User specified */
+                valid_device = 1;
+        }
+
+        if (!valid_device) {
+                err("%s - No valid device!", __FUNCTION__);
+                return -EIO;
+        }
+
+        if (udev->descriptor.bNumConfigurations != 1) {
+                err("%s -  Only one device configuration is supported.",
+                    __FUNCTION__);
+                return -EIO;
+        }
+
+        dbg("%s - setting interface", __FUNCTION__);
+        interface = intf->cur_altsetting;
+
+        dbg("%s - setting endpoint", __FUNCTION__);
+        endpoint = &interface->endpoint[0].desc;
+
+        if (interface->desc.bNumEndpoints != 1) {
+                err("%s - Only one endpoint is supported.", __FUNCTION__);
+                return -EIO;
+        }
+
+        if (!(mtouch = kmalloc (sizeof (struct mtouch_usb), GFP_KERNEL))) {
+                err("%s - Out of memory.", __FUNCTION__);
+                return -ENOMEM;
+        }
+
+        memset(mtouch, 0, sizeof(struct mtouch_usb));
+        mtouch->udev = udev;
+
+        dbg("%s - allocating buffers", __FUNCTION__);
+        if (mtouchusb_alloc_buffers(udev, mtouch)) {
+                mtouchusb_free_buffers(udev, mtouch);
+                kfree(mtouch);
+                return -ENOMEM;
+        }
+
+        mtouch->input.private = mtouch;
+        mtouch->input.open = mtouchusb_open;
+        mtouch->input.close = mtouchusb_close;
+
+        usb_make_path(udev, path, 64);
+        sprintf(mtouch->phys, "%s/input0", path);
+
+        mtouch->input.name = mtouch->name;
+        mtouch->input.phys = mtouch->phys;
+        mtouch->input.id.bustype = BUS_USB;
+        mtouch->input.id.vendor = udev->descriptor.idVendor;
+        mtouch->input.id.product = udev->descriptor.idProduct;
+        mtouch->input.id.version = udev->descriptor.bcdDevice;
+        mtouch->input.dev = &intf->dev;
+
+        mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+        mtouch->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+        mtouch->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+        /* Used to Scale Compensated Data and Flip Y */
+        mtouch->input.absmin[ABS_X] =  MTOUCHUSB_MIN_XC;
+        mtouch->input.absmax[ABS_X] =  MTOUCHUSB_MAX_XC;
+        mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ;
+        mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT;
+        mtouch->input.absmin[ABS_Y] =  MTOUCHUSB_MAX_YC;
+        mtouch->input.absmax[ABS_Y] =  MTOUCHUSB_MIN_YC;
+        mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ;
+        mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT;
+
+        if (!(buf = kmalloc(63, GFP_KERNEL))) {
+                kfree(mtouch);
+                return -ENOMEM;
+        }
+
+        if (udev->descriptor.iManufacturer &&
+            usb_string(udev, udev->descriptor.iManufacturer, buf, 63) > 0)
+                        strcat(mtouch->name, buf);
+        if (udev->descriptor.iProduct &&
+            usb_string(udev, udev->descriptor.iProduct, buf, 63) > 0)
+                        sprintf(mtouch->name, "%s %s", mtouch->name, buf);
+
+        if (!strlen(mtouch->name))
+                sprintf(mtouch->name, "USB Touchscreen %04x:%04x",
+                        mtouch->input.id.vendor, mtouch->input.id.product);
+
+        kfree(buf);
+
+        nRet = usb_control_msg(mtouch->udev,
+                               usb_rcvctrlpipe(udev, 0x80),
+                               USB_REQ_GET_CONFIGURATION,
+                               USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+                               0,
+                               0x81,
+                               NULL,
+                               0,
+                               HZ * USB_CTRL_SET_TIMEOUT);
+        dbg("%s - usb_control_msg - USB_REQ_GET_CONFIGURATION - bytes|err: %d",
+            __FUNCTION__, nRet);
+
+        dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__);
+        mtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
+        if (!mtouch->irq) {
+                dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__);
+                mtouchusb_free_buffers(udev, mtouch);
+                kfree(mtouch);
+                return -ENOMEM;
+        }
+
+        dbg("%s - usb_fill_int_urb", __FUNCTION__);
+        usb_fill_int_urb(mtouch->irq,
+                         mtouch->udev,
+                         usb_rcvintpipe(mtouch->udev, 0x81),
+                         mtouch->data,
+                         MTOUCHUSB_REPORT_SIZE_DATA,
+                         mtouchusb_irq,
+                         mtouch,
+                         endpoint->bInterval);
+
+        dbg("%s - input_register_device", __FUNCTION__);
+        input_register_device(&mtouch->input);
+
+        nRet = usb_control_msg(mtouch->udev,
+                               usb_rcvctrlpipe(udev, 0x80),
+                               MTOUCHUSB_ASYC_REPORT,
+                               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               MTOUCHUSB_ASYC_REPORT,
+                               MTOUCHUSB_ASYC_REPORT,
+                               NULL,
+                               0,
+                               HZ * USB_CTRL_SET_TIMEOUT);
+        dbg("%s - usb_control_msg - MTOUCHUSB_ASYC_REPORT - bytes|err: %d",
+            __FUNCTION__, nRet);
+
+        printk(KERN_INFO "input: %s on %s\n", mtouch->name, path);
+        usb_set_intfdata(intf, mtouch);
+
+        return 0;
+}
+
+static void mtouchusb_disconnect(struct usb_interface *intf)
+{
+        struct mtouch_usb *mtouch = usb_get_intfdata (intf);
+
+        dbg("%s - called", __FUNCTION__);
+        usb_set_intfdata(intf, NULL);
+        if (mtouch) {
+                dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__);
+                usb_unlink_urb(mtouch->irq);
+                input_unregister_device(&mtouch->input);
+                usb_free_urb(mtouch->irq);
+                mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch);
+                kfree(mtouch);
+        }
+}
+
+MODULE_DEVICE_TABLE (usb, mtouchusb_devices);
+
+static struct usb_driver mtouchusb_driver = {
+        .owner =      THIS_MODULE,
+        .name =       "mtouchusb",
+        .probe =      mtouchusb_probe,
+        .disconnect = mtouchusb_disconnect,
+        .id_table =   mtouchusb_devices,
+};
+
+static int __init mtouchusb_init(void) {
+        dbg("%s - called", __FUNCTION__);
+        return usb_register(&mtouchusb_driver);
+}
+
+static void __exit mtouchusb_cleanup(void) {
+        dbg("%s - called", __FUNCTION__);
+        usb_deregister(&mtouchusb_driver);
+}
+
+module_init(mtouchusb_init);
+module_exit(mtouchusb_cleanup);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+MODULE_PARM(vendor, "i");
+MODULE_PARM_DESC(vendor, "User specified USB idVendor");
+MODULE_PARM(product, "i");
+MODULE_PARM_DESC(product, "User specified USB idProduct");
+
+
--- diff/include/asm-alpha/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-alpha/lockmeter.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,84 @@
+/*
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ *
+ *  Modified by Peter Rival (frival@zk3.dec.com)
+ */
+
+#ifndef _ALPHA_LOCKMETER_H
+#define _ALPHA_LOCKMETER_H
+
+#include <asm/hwrpb.h>
+#define CPU_CYCLE_FREQUENCY	hwrpb->cycle_freq
+
+#define get_cycles64()		get_cycles()
+
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+#include <linux/version.h>
+
+#define SPINLOCK_MAGIC_INIT /**/
+
+/*
+ * Macros to cache and retrieve an index value inside of a lock
+ * these macros assume that there are less than 65536 simultaneous
+ * (read mode) holders of a rwlock.
+ * We also assume that the hash table has less than 32767 entries.
+ * the high order bit is used for write locking a rw_lock
+ * Note: although these defines and macros are the same as what is being used
+ *       in include/asm-i386/lockmeter.h, they are present here to easily
+ *	 allow an alternate Alpha implementation.
+ */
+/*
+ * instrumented spinlock structure -- never used to allocate storage
+ * only used in macros below to overlay a spinlock_t
+ */
+typedef struct inst_spinlock_s {
+	/* remember, Alpha is little endian */
+	unsigned short lock;
+	unsigned short index;
+} inst_spinlock_t;
+#define PUT_INDEX(lock_ptr,indexv)	((inst_spinlock_t *)(lock_ptr))->index = indexv
+#define GET_INDEX(lock_ptr)		((inst_spinlock_t *)(lock_ptr))->index
+
+/*
+ * macros to cache and retrieve an index value in a read/write lock
+ * as well as the cpu where a reader busy period started
+ * we use the 2nd word (the debug word) for this, so require the
+ * debug word to be present
+ */
+/*
+ * instrumented rwlock structure -- never used to allocate storage
+ * only used in macros below to overlay a rwlock_t
+ */
+typedef struct inst_rwlock_s {
+	volatile int lock;
+	unsigned short index;
+	unsigned short cpu;
+} inst_rwlock_t;
+#define PUT_RWINDEX(rwlock_ptr,indexv)	((inst_rwlock_t *)(rwlock_ptr))->index = indexv
+#define GET_RWINDEX(rwlock_ptr)		((inst_rwlock_t *)(rwlock_ptr))->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)	((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
+#define GET_RW_CPU(rwlock_ptr)		((inst_rwlock_t *)(rwlock_ptr))->cpu
+
+/*
+ * return true if rwlock is write locked
+ * (note that other lock attempts can cause the lock value to be negative)
+ */
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) (((inst_rwlock_t *)rwlock_ptr)->lock & 1)
+#define IABS(x) ((x) > 0 ? (x) : -(x))
+
+#define RWLOCK_READERS(rwlock_ptr)	rwlock_readers(rwlock_ptr)
+extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
+{
+	int tmp = (int) ((inst_rwlock_t *)rwlock_ptr)->lock;
+	/* readers subtract 2, so we have to:		*/
+	/* 	- andnot off a possible writer (bit 0)	*/
+	/*	- get the absolute value		*/
+	/*	- divide by 2 (right shift by one)	*/
+	/* to find the number of readers		*/
+	if (tmp == 0) return(0);
+	else return(IABS(tmp & ~1)>>1);
+}
+
+#endif /* _ALPHA_LOCKMETER_H */
--- diff/include/asm-generic/compat_signal.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-generic/compat_signal.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,25 @@
+#ifndef _ASM_GENERIC_COMPAT_SIGNAL_H
+#define _ASM_GENERIC_COMPAT_SIGNAL_H
+
+#ifndef __ASSEMBLY__
+#include <linux/compat.h>
+
+typedef compat_uptr_t compat_sighandler_t;
+
+typedef struct compat_sigaltstack {
+	compat_uptr_t ss_sp;
+	compat_int_t ss_flags;
+	compat_size_t ss_size;
+} compat_stack_t;
+
+/* Most things should be clean enough to redefine this at will, if care
+   is taken to make libc match.  */
+
+struct compat_sigaction {
+	compat_sighandler_t sa_handler;
+	compat_uint_t sa_flags;
+	compat_sigset_t sa_mask;		/* mask last for extensibility */
+};
+
+#endif /* !__ASSEMBLY__ */
+#endif /* !_ASM_GENERIC_COMPAT_SIGNAL_H */
--- diff/include/asm-i386/atomic_kmap.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-i386/atomic_kmap.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,95 @@
+/*
+ * atomic_kmap.h: temporary virtual kernel memory mappings
+ *
+ * Copyright (C) 2003 Ingo Molnar <mingo@redhat.com>
+ */
+
+#ifndef _ASM_ATOMIC_KMAP_H
+#define _ASM_ATOMIC_KMAP_H
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+#include <asm/tlbflush.h>
+
+#ifdef CONFIG_DEBUG_HIGHMEM
+#define HIGHMEM_DEBUG 1
+#else
+#define HIGHMEM_DEBUG 0
+#endif
+
+extern pte_t *kmap_pte;
+#define kmap_prot PAGE_KERNEL
+
+#define PKMAP_BASE (0xff000000UL)
+#define NR_SHARED_PMDS ((0xffffffff-PKMAP_BASE+1)/PMD_SIZE)
+
+static inline unsigned long __kmap_atomic_vaddr(enum km_type type)
+{
+	enum fixed_addresses idx;
+
+	idx = type + KM_TYPE_NR*smp_processor_id();
+	return __fix_to_virt(FIX_KMAP_BEGIN + idx);
+}
+
+static inline void *__kmap_atomic_noflush(struct page *page, enum km_type type)
+{
+	enum fixed_addresses idx;
+	unsigned long vaddr;
+
+	idx = type + KM_TYPE_NR*smp_processor_id();
+	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+	/*
+	 * NOTE: entries that rely on some secondary TLB-flush
+	 * effect must not be global:
+	 */
+	set_pte(kmap_pte-idx, mk_pte(page, PAGE_KERNEL));
+
+	return (void*) vaddr;
+}
+
+static inline void *__kmap_atomic(struct page *page, enum km_type type)
+{
+	enum fixed_addresses idx;
+	unsigned long vaddr;
+
+	idx = type + KM_TYPE_NR*smp_processor_id();
+	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+#if HIGHMEM_DEBUG
+	BUG_ON(!pte_none(*(kmap_pte-idx)));
+#else
+	/*
+	 * Performance optimization - do not flush if the new
+	 * pte is the same as the old one:
+	 */
+	if (pte_val(*(kmap_pte-idx)) == pte_val(mk_pte(page, kmap_prot)))
+		return (void *) vaddr;
+#endif
+	set_pte(kmap_pte-idx, mk_pte(page, kmap_prot));
+	__flush_tlb_one(vaddr);
+
+	return (void*) vaddr;
+}
+
+static inline void __kunmap_atomic(void *kvaddr, enum km_type type)
+{
+#if HIGHMEM_DEBUG
+	unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
+	enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
+
+	BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx));
+	/*
+	 * force other mappings to Oops if they'll try to access
+	 * this pte without first remap it
+	 */
+	pte_clear(kmap_pte-idx);
+	__flush_tlb_one(vaddr);
+#endif
+}
+
+#define __kunmap_atomic_type(type) \
+		__kunmap_atomic((void *)__kmap_atomic_vaddr(type), (type))
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_ATOMIC_KMAP_H */
--- diff/include/asm-i386/kgdb.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-i386/kgdb.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,69 @@
+#ifndef __KGDB
+#define __KGDB
+
+/*
+ * This file should not include ANY others.  This makes it usable
+ * most anywhere without the fear of include order or inclusion.
+ * Make it so!
+ *
+ * This file may be included all the time.  It is only active if
+ * CONFIG_KGDB is defined, otherwise it stubs out all the macros
+ * and entry points.
+ */
+#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__)
+
+extern void breakpoint(void);
+#define INIT_KGDB_INTS kgdb_enable_ints()
+
+#ifndef BREAKPOINT
+#define BREAKPOINT   asm("   int $3")
+#endif
+
+extern void kgdb_schedule_breakpoint(void);
+extern void kgdb_process_breakpoint(void);
+
+extern int kgdb_tty_hook(void);
+extern int kgdb_eth_hook(void);
+extern int kgdboe;
+
+/*
+ * GDB debug stub (or any debug stub) can point the 'linux_debug_hook'
+ * pointer to its routine and it will be entered as the first thing
+ * when a trap occurs.
+ *
+ * Return values are, at present, undefined.
+ *
+ * The debug hook routine does not necessarily return to its caller.
+ * It has the register image and thus may choose to resume execution
+ * anywhere it pleases.
+ */
+struct pt_regs;
+
+extern int kgdb_handle_exception(int trapno,
+				 int signo, int err_code, struct pt_regs *regs);
+extern int in_kgdb(struct pt_regs *regs);
+
+#ifdef CONFIG_KGDB_TS
+void kgdb_tstamp(int line, char *source, int data0, int data1);
+/*
+ * This is the time stamp function.  The macro adds the source info and
+ * does a cast on the data to allow most any 32-bit value.
+ */
+
+#define kgdb_ts(data0,data1) kgdb_tstamp(__LINE__,__FILE__,(int)data0,(int)data1)
+#else
+#define kgdb_ts(data0,data1)
+#endif
+#else				/* CONFIG_KGDB  && ! __ASSEMBLY__ ,stubs follow... */
+#ifndef BREAKPOINT
+#define BREAKPOINT
+#endif
+#define kgdb_ts(data0,data1)
+#define in_kgdb
+#define kgdb_handle_exception
+#define breakpoint
+#define INIT_KGDB_INTS
+#define kgdb_process_breakpoint() do {} while(0)
+
+#endif
+#endif				/* __KGDB */
--- diff/include/asm-i386/kgdb_local.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-i386/kgdb_local.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,102 @@
+#ifndef __KGDB_LOCAL
+#define ___KGDB_LOCAL
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/spinlock.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/kgdb.h>
+
+#define PORT 0x3f8
+#ifdef CONFIG_KGDB_PORT
+#undef PORT
+#define PORT CONFIG_KGDB_PORT
+#endif
+#define IRQ 4
+#ifdef CONFIG_KGDB_IRQ
+#undef IRQ
+#define IRQ CONFIG_KGDB_IRQ
+#endif
+#define SB_CLOCK 1843200
+#define SB_BASE (SB_CLOCK/16)
+#define SB_BAUD9600 SB_BASE/9600
+#define SB_BAUD192  SB_BASE/19200
+#define SB_BAUD384  SB_BASE/38400
+#define SB_BAUD576  SB_BASE/57600
+#define SB_BAUD1152 SB_BASE/115200
+#ifdef CONFIG_KGDB_9600BAUD
+#define SB_BAUD SB_BAUD9600
+#endif
+#ifdef CONFIG_KGDB_19200BAUD
+#define SB_BAUD SB_BAUD192
+#endif
+#ifdef CONFIG_KGDB_38400BAUD
+#define SB_BAUD SB_BAUD384
+#endif
+#ifdef CONFIG_KGDB_57600BAUD
+#define SB_BAUD SB_BAUD576
+#endif
+#ifdef CONFIG_KGDB_115200BAUD
+#define SB_BAUD SB_BAUD1152
+#endif
+#ifndef SB_BAUD
+#define SB_BAUD SB_BAUD1152	/* Start with this if not given */
+#endif
+
+#ifndef CONFIG_X86_TSC
+#undef rdtsc
+#define rdtsc(a,b) if (a++ > 10000){a = 0; b++;}
+#undef rdtscll
+#define rdtscll(s) s++
+#endif
+
+#ifdef _raw_read_unlock		/* must use a name that is "define"ed, not an inline */
+#undef spin_lock
+#undef spin_trylock
+#undef spin_unlock
+#define spin_lock	 _raw_spin_lock
+#define spin_trylock	 _raw_spin_trylock
+#define spin_unlock	 _raw_spin_unlock
+#else
+#endif
+#undef spin_unlock_wait
+#define spin_unlock_wait(x)  do { cpu_relax(); barrier();} \
+                                     while(spin_is_locked(x))
+
+#define SB_IER 1
+#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
+
+#define FLAGS 0
+#define SB_STATE { \
+     magic: SSTATE_MAGIC, \
+     baud_base: SB_BASE,  \
+     port:      PORT,     \
+     irq:       IRQ,      \
+     flags:     FLAGS,    \
+     custom_divisor:SB_BAUD}
+#define SB_INFO  { \
+      magic: SERIAL_MAGIC, \
+      port:  PORT,0,FLAGS, \
+      state: &state,       \
+      tty:   (struct tty_struct *)&state, \
+      IER:   SB_IER,       \
+      MCR:   SB_MCR}
+extern void putDebugChar(int);
+/* RTAI support needs us to really stop/start interrupts */
+
+#define kgdb_sti() __asm__ __volatile__("sti": : :"memory")
+#define kgdb_cli() __asm__ __volatile__("cli": : :"memory")
+#define kgdb_local_save_flags(x) __asm__ __volatile__(\
+                                   "pushfl ; popl %0":"=g" (x): /* no input */)
+#define kgdb_local_irq_restore(x) __asm__ __volatile__(\
+                                   "pushl %0 ; popfl": \
+                                     /* no output */ :"g" (x):"memory", "cc")
+#define kgdb_local_irq_save(x) kgdb_local_save_flags(x); kgdb_cli()
+
+#ifdef CONFIG_SERIAL
+extern void shutdown_for_kgdb(struct async_struct *info);
+#endif
+#define INIT_KDEBUG putDebugChar("+");
+#endif				/* __KGDB_LOCAL */
--- diff/include/asm-i386/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-i386/lockmeter.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,115 @@
+/*
+ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ *
+ *  Modified by Ray Bryant (raybry@us.ibm.com)
+ *  Changes Copyright (C) 2000 IBM, Inc.
+ *  Added save of index in spinlock_t to improve efficiency
+ *  of "hold" time reporting for spinlocks.
+ *  Added support for hold time statistics for read and write
+ *  locks.
+ *  Moved machine dependent code here from include/lockmeter.h.
+ *
+ */
+
+#ifndef _I386_LOCKMETER_H
+#define _I386_LOCKMETER_H
+
+#include <asm/spinlock.h>
+#include <asm/rwlock.h>
+
+#include <linux/version.h>
+
+#ifdef __KERNEL__
+extern unsigned long cpu_khz;
+#define CPU_CYCLE_FREQUENCY	(cpu_khz * 1000)
+#else
+#define CPU_CYCLE_FREQUENCY	450000000
+#endif
+
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+/*
+ * macros to cache and retrieve an index value inside of a spin lock
+ * these macros assume that there are less than 65536 simultaneous
+ * (read mode) holders of a rwlock.  Not normally a problem!!
+ * we also assume that the hash table has less than 65535 entries.
+ */
+/*
+ * instrumented spinlock structure -- never used to allocate storage
+ * only used in macros below to overlay a spinlock_t
+ */
+typedef struct inst_spinlock_s {
+	/* remember, Intel is little endian */
+	unsigned short lock;
+	unsigned short index;
+} inst_spinlock_t;
+#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t *)(lock_ptr))->index = indexv
+#define GET_INDEX(lock_ptr)        ((inst_spinlock_t *)(lock_ptr))->index
+
+/*
+ * macros to cache and retrieve an index value in a read/write lock
+ * as well as the cpu where a reader busy period started
+ * we use the 2nd word (the debug word) for this, so require the
+ * debug word to be present
+ */
+/*
+ * instrumented rwlock structure -- never used to allocate storage
+ * only used in macros below to overlay a rwlock_t
+ */
+typedef struct inst_rwlock_s {
+	volatile int lock;
+	unsigned short index;
+	unsigned short cpu;
+} inst_rwlock_t;
+#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv
+#define GET_RWINDEX(rwlock_ptr)        ((inst_rwlock_t *)(rwlock_ptr))->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)    ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
+#define GET_RW_CPU(rwlock_ptr)         ((inst_rwlock_t *)(rwlock_ptr))->cpu
+
+/*
+ * return the number of readers for a rwlock_t
+ */
+#define RWLOCK_READERS(rwlock_ptr)   rwlock_readers(rwlock_ptr)
+
+extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
+{
+	int tmp = (int) rwlock_ptr->lock;
+	/* read and write lock attempts may cause the lock value to temporarily */
+	/* be negative.  Until it is >= 0 we know nothing (i. e. can't tell if  */
+	/* is -1 because it was write locked and somebody tried to read lock it */
+	/* or if it is -1 because it was read locked and somebody tried to write*/
+	/* lock it. ........................................................... */
+	do {
+		tmp = (int) rwlock_ptr->lock;
+	} while (tmp < 0);
+	if (tmp == 0) return(0);
+	else return(RW_LOCK_BIAS-tmp);
+}
+
+/*
+ * return true if rwlock is write locked
+ * (note that other lock attempts can cause the lock value to be negative)
+ */
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->lock <= 0)
+#define IABS(x) ((x) > 0 ? (x) : -(x))
+#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)  ((IABS((rwlock_ptr)->lock) % RW_LOCK_BIAS) != 0)
+
+/* this is a lot of typing just to get gcc to emit "rdtsc" */
+static inline long long get_cycles64 (void)
+{
+	union longlong_u {
+		long long intlong;
+		struct intint_s {
+			uint32_t eax;
+			uint32_t edx;
+		} intint;
+	} longlong;
+
+	rdtsc(longlong.intint.eax,longlong.intint.edx);
+	return longlong.intlong;
+}
+
+#endif /* _I386_LOCKMETER_H */
--- diff/include/asm-ia64/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-ia64/lockmeter.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,72 @@
+/*
+ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ */
+
+#ifndef _IA64_LOCKMETER_H
+#define _IA64_LOCKMETER_H
+
+#ifdef local_cpu_data
+#define CPU_CYCLE_FREQUENCY	local_cpu_data->itc_freq
+#else
+#define CPU_CYCLE_FREQUENCY	my_cpu_data.itc_freq
+#endif
+#define get_cycles64()		get_cycles()
+
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+/*
+ * macros to cache and retrieve an index value inside of a lock
+ * these macros assume that there are less than 65536 simultaneous
+ * (read mode) holders of a rwlock.
+ * we also assume that the hash table has less than 32767 entries.
+ */
+/*
+ * instrumented spinlock structure -- never used to allocate storage
+ * only used in macros below to overlay a spinlock_t
+ */
+typedef struct inst_spinlock_s {
+	/* remember, Intel is little endian */
+	volatile unsigned short lock;
+	volatile unsigned short index;
+} inst_spinlock_t;
+#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t *)(lock_ptr))->index = indexv
+#define GET_INDEX(lock_ptr)        ((inst_spinlock_t *)(lock_ptr))->index
+
+/*
+ * macros to cache and retrieve an index value in a read/write lock
+ * as well as the cpu where a reader busy period started
+ * we use the 2nd word (the debug word) for this, so require the
+ * debug word to be present
+ */
+/*
+ * instrumented rwlock structure -- never used to allocate storage
+ * only used in macros below to overlay a rwlock_t
+ */
+typedef struct inst_rwlock_s {
+	volatile int read_counter:31;
+	volatile int write_lock:1;
+	volatile unsigned short index;
+	volatile unsigned short cpu;
+} inst_rwlock_t;
+#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv
+#define GET_RWINDEX(rwlock_ptr)        ((inst_rwlock_t *)(rwlock_ptr))->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)    ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
+#define GET_RW_CPU(rwlock_ptr)         ((inst_rwlock_t *)(rwlock_ptr))->cpu
+
+/*
+ * return the number of readers for a rwlock_t
+ */
+#define RWLOCK_READERS(rwlock_ptr)	((rwlock_ptr)->read_counter)
+
+/*
+ * return true if rwlock is write locked
+ * (note that other lock attempts can cause the lock value to be negative)
+ */
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->write_lock)
+#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)  ((rwlock_ptr)->read_counter)
+
+#endif /* _IA64_LOCKMETER_H */
+
--- diff/include/asm-mips/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-mips/lockmeter.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,126 @@
+/*
+ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ *  Ported to mips32 for Asita Technologies
+ *   by D.J. Barrow ( dj.barrow@asitatechnologies.com )
+ */
+#ifndef _ASM_LOCKMETER_H
+#define _ASM_LOCKMETER_H
+
+/* do_gettimeoffset is a function pointer on mips */
+/* & it is not included by <linux/time.h> */
+#include <asm/time.h>
+#include <linux/time.h>
+#include <asm/div64.h>
+
+#define SPINLOCK_MAGIC_INIT	/* */
+
+#define CPU_CYCLE_FREQUENCY	get_cpu_cycle_frequency()
+
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+static uint32_t cpu_cycle_frequency = 0;
+
+static uint32_t get_cpu_cycle_frequency(void)
+{
+    /* a total hack, slow and invasive, but ... it works */
+    int sec;
+    uint32_t start_cycles;
+    struct timeval tv;
+
+    if (cpu_cycle_frequency == 0) {	/* uninitialized */
+	do_gettimeofday(&tv);
+	sec = tv.tv_sec;	/* set up to catch the tv_sec rollover */
+	while (sec == tv.tv_sec) { do_gettimeofday(&tv); }
+	sec = tv.tv_sec;	/* rolled over to a new sec value */
+	start_cycles = get_cycles();
+	while (sec == tv.tv_sec) { do_gettimeofday(&tv); }
+	cpu_cycle_frequency = get_cycles() - start_cycles;
+    }
+
+    return cpu_cycle_frequency;
+}
+
+extern struct timeval xtime;
+
+static uint64_t get_cycles64(void)
+{
+    static uint64_t last_get_cycles64 = 0;
+    uint64_t ret;
+    unsigned long sec;
+    unsigned long usec, usec_offset;
+
+again:
+    sec  = xtime.tv_sec;
+    usec = xtime.tv_usec;
+    usec_offset = do_gettimeoffset();
+    if ((xtime.tv_sec != sec)  ||
+	(xtime.tv_usec != usec)||
+	(usec_offset >= 20000))
+	goto again;
+
+    ret = ((uint64_t)(usec + usec_offset) * cpu_cycle_frequency);
+    /* We can't do a normal 64 bit division on mips without libgcc.a */
+    do_div(ret,1000000);
+    ret +=  ((uint64_t)sec * cpu_cycle_frequency);
+
+    /* XXX why does time go backwards?  do_gettimeoffset?  general time adj? */
+    if (ret <= last_get_cycles64)
+	ret  = last_get_cycles64+1;
+    last_get_cycles64 = ret;
+
+    return ret;
+}
+
+/*
+ * macros to cache and retrieve an index value inside of a lock
+ * these macros assume that there are less than 65536 simultaneous
+ * (read mode) holders of a rwlock.
+ * we also assume that the hash table has less than 32767 entries.
+ * the high order bit is used for write locking a rw_lock
+ */
+#define INDEX_MASK   0x7FFF0000
+#define READERS_MASK 0x0000FFFF
+#define INDEX_SHIFT 16
+#define PUT_INDEX(lockp,index)   \
+        lockp->lock = (((lockp->lock) & ~INDEX_MASK) | (index) << INDEX_SHIFT)
+#define GET_INDEX(lockp) \
+        (((lockp->lock) & INDEX_MASK) >> INDEX_SHIFT)
+
+/*
+ * macros to cache and retrieve an index value in a read/write lock
+ * as well as the cpu where a reader busy period started
+ * we use the 2nd word (the debug word) for this, so require the
+ * debug word to be present
+ */
+/*
+ * instrumented rwlock structure -- never used to allocate storage
+ * only used in macros below to overlay a rwlock_t
+ */
+typedef struct inst_rwlock_s {
+	volatile int lock;
+	unsigned short index;
+	unsigned short cpu;
+} inst_rwlock_t;
+#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv
+#define GET_RWINDEX(rwlock_ptr)        ((inst_rwlock_t *)(rwlock_ptr))->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)    ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
+#define GET_RW_CPU(rwlock_ptr)         ((inst_rwlock_t *)(rwlock_ptr))->cpu
+
+/*
+ * return the number of readers for a rwlock_t
+ */
+#define RWLOCK_READERS(rwlock_ptr)   rwlock_readers(rwlock_ptr)
+
+extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
+{
+	int tmp = (int) rwlock_ptr->lock;
+	return (tmp >= 0) ? tmp : 0;
+}
+
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->lock < 0)
+#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)  ((rwlock_ptr)->lock > 0)
+
+#endif /* _ASM_LOCKMETER_H */
--- diff/include/asm-sparc64/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-sparc64/lockmeter.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com)
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ */
+
+#ifndef _SPARC64_LOCKMETER_H
+#define _SPARC64_LOCKMETER_H
+
+#include <linux/smp.h>
+#include <asm/spinlock.h>
+#include <asm/timer.h>
+#include <asm/timex.h>
+
+/* Actually, this is not the CPU frequency by the system tick
+ * frequency which is good enough for lock metering.
+ */
+#define CPU_CYCLE_FREQUENCY	(timer_tick_offset * HZ)
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+#define PUT_INDEX(lock_ptr,indexv)	(lock_ptr)->index = (indexv)
+#define GET_INDEX(lock_ptr)		(lock_ptr)->index
+
+#define PUT_RWINDEX(rwlock_ptr,indexv) (rwlock_ptr)->index = (indexv)
+#define GET_RWINDEX(rwlock_ptr)        (rwlock_ptr)->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)    (rwlock_ptr)->cpu = (cpuv)
+#define GET_RW_CPU(rwlock_ptr)         (rwlock_ptr)->cpu
+
+#define RWLOCK_READERS(rwlock_ptr)	rwlock_readers(rwlock_ptr)
+
+extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
+{
+	signed int tmp = rwlock_ptr->lock;
+
+	if (tmp > 0)
+		return tmp;
+	else
+		return 0;
+}
+
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr)	((signed int)((rwlock_ptr)->lock) < 0)
+#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)	((signed int)((rwlock_ptr)->lock) > 0)
+
+#define get_cycles64()	get_cycles()
+
+#endif /* _SPARC64_LOCKMETER_H */
--- diff/include/asm-x86_64/kgdb.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-x86_64/kgdb.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,71 @@
+#ifndef __KGDB
+#define __KGDB
+
+/*
+ * This file should not include ANY others.  This makes it usable
+ * most anywhere without the fear of include order or inclusion.
+ * Make it so!
+ *
+ * This file may be included all the time.  It is only active if
+ * CONFIG_KGDB is defined, otherwise it stubs out all the macros
+ * and entry points.
+ */
+#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__)
+
+extern void breakpoint(void);
+#define INIT_KGDB_INTS kgdb_enable_ints()
+
+#ifndef BREAKPOINT
+#define BREAKPOINT   asm("   int $3")
+#endif
+
+extern void kgdb_schedule_breakpoint(void);
+extern void kgdb_process_breakpoint(void);
+
+extern int kgdb_tty_hook(void);
+extern int kgdb_eth_hook(void);
+extern int kgdboe;
+
+/*
+ * GDB debug stub (or any debug stub) can point the 'linux_debug_hook'
+ * pointer to its routine and it will be entered as the first thing
+ * when a trap occurs.
+ *
+ * Return values are, at present, undefined.
+ *
+ * The debug hook routine does not necessarily return to its caller.
+ * It has the register image and thus may choose to resume execution
+ * anywhere it pleases.
+ */
+struct pt_regs;
+
+extern int kgdb_handle_exception(int trapno,
+				 int signo, int err_code, struct pt_regs *regs);
+extern int in_kgdb(struct pt_regs *regs);
+
+extern void set_debug_traps(void);
+
+#ifdef CONFIG_KGDB_TS
+void kgdb_tstamp(int line, char *source, int data0, int data1);
+/*
+ * This is the time stamp function.  The macro adds the source info and
+ * does a cast on the data to allow most any 32-bit value.
+ */
+
+#define kgdb_ts(data0,data1) kgdb_tstamp(__LINE__,__FILE__,(int)data0,(int)data1)
+#else
+#define kgdb_ts(data0,data1)
+#endif
+#else				/* CONFIG_KGDB  && ! __ASSEMBLY__ ,stubs follow... */
+#ifndef BREAKPOINT
+#define BREAKPOINT
+#endif
+#define kgdb_ts(data0,data1)
+#define in_kgdb	(0)
+#define kgdb_handle_exception
+#define breakpoint
+#define INIT_KGDB_INTS
+#define kgdb_process_breakpoint() do {} while(0)
+
+#endif
+#endif				/* __KGDB */
--- diff/include/asm-x86_64/kgdb_local.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-x86_64/kgdb_local.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,102 @@
+#ifndef __KGDB_LOCAL
+#define ___KGDB_LOCAL
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/spinlock.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/kgdb.h>
+
+#define PORT 0x3f8
+#ifdef CONFIG_KGDB_PORT
+#undef PORT
+#define PORT CONFIG_KGDB_PORT
+#endif
+#define IRQ 4
+#ifdef CONFIG_KGDB_IRQ
+#undef IRQ
+#define IRQ CONFIG_KGDB_IRQ
+#endif
+#define SB_CLOCK 1843200
+#define SB_BASE (SB_CLOCK/16)
+#define SB_BAUD9600 SB_BASE/9600
+#define SB_BAUD192  SB_BASE/19200
+#define SB_BAUD384  SB_BASE/38400
+#define SB_BAUD576  SB_BASE/57600
+#define SB_BAUD1152 SB_BASE/115200
+#ifdef CONFIG_KGDB_9600BAUD
+#define SB_BAUD SB_BAUD9600
+#endif
+#ifdef CONFIG_KGDB_19200BAUD
+#define SB_BAUD SB_BAUD192
+#endif
+#ifdef CONFIG_KGDB_38400BAUD
+#define SB_BAUD SB_BAUD384
+#endif
+#ifdef CONFIG_KGDB_57600BAUD
+#define SB_BAUD SB_BAUD576
+#endif
+#ifdef CONFIG_KGDB_115200BAUD
+#define SB_BAUD SB_BAUD1152
+#endif
+#ifndef SB_BAUD
+#define SB_BAUD SB_BAUD1152	/* Start with this if not given */
+#endif
+
+#ifndef CONFIG_X86_TSC
+#undef rdtsc
+#define rdtsc(a,b) if (a++ > 10000){a = 0; b++;}
+#undef rdtscll
+#define rdtscll(s) s++
+#endif
+
+#ifdef _raw_read_unlock		/* must use a name that is "define"ed, not an inline */
+#undef spin_lock
+#undef spin_trylock
+#undef spin_unlock
+#define spin_lock	 _raw_spin_lock
+#define spin_trylock	 _raw_spin_trylock
+#define spin_unlock	 _raw_spin_unlock
+#else
+#endif
+#undef spin_unlock_wait
+#define spin_unlock_wait(x)  do { cpu_relax(); barrier();} \
+                                     while(spin_is_locked(x))
+
+#define SB_IER 1
+#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
+
+#define FLAGS 0
+#define SB_STATE { \
+     magic: SSTATE_MAGIC, \
+     baud_base: SB_BASE,  \
+     port:      PORT,     \
+     irq:       IRQ,      \
+     flags:     FLAGS,    \
+     custom_divisor:SB_BAUD}
+#define SB_INFO  { \
+      magic: SERIAL_MAGIC, \
+      port:  PORT,0,FLAGS, \
+      state: &state,       \
+      tty:   (struct tty_struct *)&state, \
+      IER:   SB_IER,       \
+      MCR:   SB_MCR}
+extern void putDebugChar(int);
+/* RTAI support needs us to really stop/start interrupts */
+
+#define kgdb_sti() __asm__ __volatile__("sti": : :"memory")
+#define kgdb_cli() __asm__ __volatile__("cli": : :"memory")
+#define kgdb_local_save_flags(x) __asm__ __volatile__(\
+                                   "pushfl ; popl %0":"=g" (x): /* no input */)
+#define kgdb_local_irq_restore(x) __asm__ __volatile__(\
+                                   "pushl %0 ; popfl": \
+                                     /* no output */ :"g" (x):"memory", "cc")
+#define kgdb_local_irq_save(x) kgdb_local_save_flags(x); kgdb_cli()
+
+#ifdef CONFIG_SERIAL
+extern void shutdown_for_kgdb(struct async_struct *info);
+#endif
+#define INIT_KDEBUG putDebugChar("+");
+#endif				/* __KGDB_LOCAL */
--- diff/include/linux/compat_siginfo.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/compat_siginfo.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,170 @@
+#ifndef _ASM_GENERIC_COMPAT_SIGINFO_H
+#define _ASM_GENERIC_COMPAT_SIGINFO_H
+
+#include <linux/config.h>
+#include <linux/compat.h>
+
+#ifndef CONFIG_COMPAT
+
+/* No compatibility layer required, add empty definitions for the compiler */
+
+typedef struct compat_siginfo{
+} compat_siginfo_t;
+
+static inline int compat_copy_siginfo_to_user(compat_siginfo_t __user *to,
+						struct siginfo *from)
+{
+	return -1;
+}
+
+#else
+
+#include <linux/compiler.h>
+#include <asm/siginfo.h>
+
+/* compat view of sigval_t */
+typedef union compat_sigval {
+	compat_int_t sival_int;
+	compat_uptr_t sival_ptr;
+} compat_sigval_t;
+
+/*
+ * This is the size (including padding) of the part of the
+ * struct siginfo that is before the union.
+ */
+#ifndef __ARCH_SI_COMPAT_PREAMBLE_SIZE
+#define __ARCH_SI_COMPAT_PREAMBLE_SIZE	(3 * sizeof(int))
+#endif
+
+#define SI_COMPAT_MAX_SIZE	128
+#ifndef SI_COMPAT_PAD_SIZE
+#define SI_COMPAT_PAD_SIZE	((SI_COMPAT_MAX_SIZE - __ARCH_SI_COMPAT_PREAMBLE_SIZE) / sizeof(int))
+#endif
+
+/* 32-bit view of si.uid_t */
+#ifndef __ARCH_SI_COMPAT_UID_T
+#define __ARCH_SI_COMPAT_UID_T compat_uid_t
+#endif
+
+/* 32-bit view of si.band_t */
+#ifndef __ARCH_SI_COMPAT_BAND_T
+#define __ARCH_SI_COMPAT_BAND_T compat_int_t
+#endif
+
+#ifndef HAVE_ARCH_COMPAT_SIGINFO_T
+
+/* Compat view of siginfo_t */
+typedef struct compat_siginfo {
+	compat_int_t si_signo;
+	compat_int_t si_errno;
+	compat_int_t si_code;
+
+	union {
+		compat_int_t _pad[SI_COMPAT_PAD_SIZE];
+
+		/* kill() */
+		struct {
+			compat_pid_t _pid;	/* sender's pid */
+			__ARCH_SI_COMPAT_UID_T _uid;	/* sender's uid */
+		} _kill;
+
+		/* POSIX.1b timers */
+		struct {
+			compat_timer_t _tid;	/* timer id */
+			compat_int_t _overrun;		/* overrun count */
+			char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)];
+			compat_sigval_t _sigval;	/* same as below */
+			compat_int_t _sys_private;       /* not to be passed to user */
+		} _timer;
+
+		/* POSIX.1b signals */
+		struct {
+			compat_pid_t _pid;		/* sender's pid */
+			__ARCH_SI_COMPAT_UID_T _uid;	/* sender's uid */
+			compat_sigval_t _sigval;
+		} _rt;
+
+		/* SIGCHLD */
+		struct {
+			compat_pid_t _pid;		/* which child */
+			__ARCH_SI_COMPAT_UID_T _uid;	/* sender's uid */
+			compat_int_t _status;		/* exit code */
+			compat_clock_t _utime;
+			compat_clock_t _stime;
+		} _sigchld;
+
+		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+		struct {
+			compat_uptr_t _addr; /* faulting insn/memory ref. */
+#ifdef __ARCH_SI_COMPAT_TRAPNO
+			compat_int_t _trapno;	/* TRAP # which caused the signal */
+#endif
+		} _sigfault;
+
+		/* SIGPOLL */
+		struct {
+			__ARCH_SI_COMPAT_BAND_T _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
+			compat_int_t _fd;
+		} _sigpoll;
+	} _sifields;
+} compat_siginfo_t;
+#endif /* !HAVE_ARCH_COMPAT_SIGINFO_T */
+
+#ifdef __ARCH_SI_COMPAT_TRAPNO
+#define si_trapno	_sifields._sigfault._trapno
+#endif
+
+/*
+ * sigevent definitions
+ *
+ * It seems likely that SIGEV_THREAD will have to be handled from
+ * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
+ * thread manager then catches and does the appropriate nonsense.
+ * However, everything is written out here so as to not get lost.
+ */
+
+#define SIGEV_COMPAT_MAX_SIZE	64
+#ifndef SIGEV_COMPAT_PAD_SIZE
+#define SIGEV_COMPAT_PAD_SIZE	((SIGEV_COMPAT_MAX_SIZE/sizeof(int)) - 3)
+#endif
+
+#ifndef HAVE_ARCH_COMPAT_SIGEVENT_T
+
+/* 32-bit view of sigevent_t */
+typedef struct compat_sigevent {
+	compat_sigval_t sigev_value;
+	compat_int_t sigev_signo;
+	compat_int_t sigev_notify;
+	union {
+		compat_int_t _pad[SIGEV_COMPAT_PAD_SIZE];
+		compat_int_t _tid;
+
+		struct {
+			compat_uptr_t _function;
+			compat_uptr_t _attribute;	/* really pthread_attr_t */
+		} _sigev_thread;
+	} _sigev_un;
+} compat_sigevent_t;
+
+#endif /* HAVE_ARCH_COMPAT_SIGEVENT_T */
+
+#ifndef HAVE_ARCH_COMPAT_COPY_SIGINFO
+
+#include <linux/string.h>
+
+static inline void compat_copy_siginfo(struct compat_siginfo *to, struct compat_siginfo *from)
+{
+	if (from->si_code < 0)
+		memcpy(to, from, sizeof(*to));
+	else
+		/* _sigchld is currently the largest know union member */
+		memcpy(to, from, __ARCH_SI_COMPAT_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld));
+}
+
+#endif /* !HAVE_ARCH_COMPAT_COPY_SIGINFO */
+
+extern int compat_copy_siginfo_to_user(compat_siginfo_t __user *to, struct siginfo *from);
+
+#endif /* CONFIG_COMPAT */
+#endif /* _ASM_GENERIC_COMPAT_SIGINFO_H */
+
--- diff/include/linux/dwarf2-lang.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/dwarf2-lang.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,132 @@
+#ifndef DWARF2_LANG
+#define DWARF2_LANG
+#include <linux/dwarf2.h>
+
+/*
+ * This is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2, or (at your option) any later
+ * version.
+ */
+/*
+ * This file defines macros that allow generation of DWARF debug records
+ * for asm files.  This file is platform independent.  Register numbers
+ * (which are about the only thing that is platform dependent) are to be
+ * supplied by a platform defined file.
+ */
+#define DWARF_preamble()	.section	.debug_frame,"",@progbits
+/*
+ * This macro starts a debug frame section.  The debug_frame describes
+ * where to find the registers that the enclosing function saved on
+ * entry.
+ *
+ * ORD is use by the label generator and should be the same as what is
+ * passed to CFI_postamble.
+ *
+ * pc,	pc register gdb ordinal.
+ *
+ * code_align this is the factor used to define locations or regions
+ * where the given definitions apply.  If you use labels to define these
+ * this should be 1.
+ *
+ * data_align this is the factor used to define register offsets.  If
+ * you use struct offset, this should be the size of the register in
+ * bytes or the negative of that.  This is how it is used: you will
+ * define a register as the reference register, say the stack pointer,
+ * then you will say where a register is located relative to this
+ * reference registers value, say 40 for register 3 (the gdb register
+ * number).  The <40> will be multiplied by <data_align> to define the
+ * byte offset of the given register (3, in this example).  So if your
+ * <40> is the byte offset and the reference register points at the
+ * begining, you would want 1 for the data_offset.  If <40> was the 40th
+ * 4-byte element in that structure you would want 4.  And if your
+ * reference register points at the end of the structure you would want
+ * a negative data_align value(and you would have to do other math as
+ * well).
+ */
+
+#define CFI_preamble(ORD, pc, code_align, data_align)	\
+.section	.debug_frame,"",@progbits ;		\
+frame/**/_/**/ORD:						\
+	.long end/**/_/**/ORD-start/**/_/**/ORD;			\
+start/**/_/**/ORD:						\
+	.long	DW_CIE_ID;				\
+	.byte	DW_CIE_VERSION;			\
+	.byte 0	 ;				\
+	.uleb128 code_align;				\
+	.sleb128 data_align;				\
+	.byte pc;
+
+/*
+ * After the above macro and prior to the CFI_postamble, you need to
+ * define the initial state.  This starts with defining the reference
+ * register and, usually the pc.  Here are some helper macros:
+ */
+
+#define CFA_define_reference(reg, offset)	\
+	.byte DW_CFA_def_cfa;			\
+	.uleb128 reg;				\
+	.uleb128 (offset);
+
+#define CFA_define_offset(reg, offset)		\
+	.byte (DW_CFA_offset + reg);		\
+	.uleb128 (offset);
+
+#define CFI_postamble(ORD)			\
+	.align 4;				\
+end/**/_/**/ORD:
+/*
+ * So now your code pushs stuff on the stack, you need a new location
+ * and the rules for what to do.  This starts a running description of
+ * the call frame.  You need to describe what changes with respect to
+ * the call registers as the location of the pc moves through the code.
+ * The following builds an FDE (fram descriptor entry?).  Like the
+ * above, it has a preamble and a postamble.  It also is tied to the CFI
+ * above.
+ * The first entry after the preamble must be the location in the code
+ * that the call frame is being described for.
+ */
+#define FDE_preamble(ORD, fde_no, initial_address, length)	\
+	.long FDE_end/**/_/**/fde_no-FDE_start/**/_/**/fde_no;		\
+FDE_start/**/_/**/fde_no:						\
+	.long frame/**/_/**/ORD;					\
+	.long initial_address;					\
+	.long length;
+
+#define FDE_postamble(fde_no)			\
+	.align 4;				\
+FDE_end/**/_/**/fde_no:
+/*
+ * That done, you can now add registers, subtract registers, move the
+ * reference and even change the reference.  You can also define a new
+ * area of code the info applies to.  For discontinuous bits you should
+ * start a new FDE.  You may have as many as you like.
+ */
+
+/*
+ * To advance the address by <bytes>
+ */
+
+#define FDE_advance(bytes)			\
+	.byte DW_CFA_advance_loc4		\
+	.long bytes
+
+
+
+/*
+ * With the above you can define all the register locations.  But
+ * suppose the reference register moves... Takes the new offset NOT an
+ * increment.  This is how esp is tracked if it is not saved.
+ */
+
+#define CFA_define_cfa_offset(offset) \
+	.byte $DW_CFA_def_cfa_offset; \
+	.uleb128 (offset);
+/*
+ * Or suppose you want to use a different reference register...
+ */
+#define CFA_define_cfa_register(reg)		\
+	.byte DW_CFA_def_cfa_register;		\
+	.uleb128 reg;
+
+#endif
--- diff/include/linux/dwarf2.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/dwarf2.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,738 @@
+/* Declarations and definitions of codes relating to the DWARF2 symbolic
+   debugging information format.
+   Copyright (C) 1992, 1993, 1995, 1996, 1997, 1999, 2000, 2001, 2002
+   Free Software Foundation, Inc.
+
+   Written by Gary Funck (gary@intrepid.com) The Ada Joint Program
+   Office (AJPO), Florida State Unviversity and Silicon Graphics Inc.
+   provided support for this effort -- June 21, 1995.
+
+   Derived from the DWARF 1 implementation written by Ron Guilmette
+   (rfg@netcom.com), November 1990.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 2, or (at your option) any later
+   version.
+
+   GCC 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 GCC; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+/* This file is derived from the DWARF specification (a public document)
+   Revision 2.0.0 (July 27, 1993) developed by the UNIX International
+   Programming Languages Special Interest Group (UI/PLSIG) and distributed
+   by UNIX International.  Copies of this specification are available from
+   UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054.
+
+   This file also now contains definitions from the DWARF 3 specification.  */
+
+/* This file is shared between GCC and GDB, and should not contain
+   prototypes.	*/
+
+#ifndef _ELF_DWARF2_H
+#define _ELF_DWARF2_H
+
+/* Structure found in the .debug_line section.	*/
+#ifndef __ASSEMBLY__
+typedef struct
+{
+  unsigned char li_length	   [4];
+  unsigned char li_version	   [2];
+  unsigned char li_prologue_length [4];
+  unsigned char li_min_insn_length [1];
+  unsigned char li_default_is_stmt [1];
+  unsigned char li_line_base	   [1];
+  unsigned char li_line_range	   [1];
+  unsigned char li_opcode_base	   [1];
+}
+DWARF2_External_LineInfo;
+
+typedef struct
+{
+  unsigned long  li_length;
+  unsigned short li_version;
+  unsigned int	 li_prologue_length;
+  unsigned char  li_min_insn_length;
+  unsigned char  li_default_is_stmt;
+  int		 li_line_base;
+  unsigned char  li_line_range;
+  unsigned char  li_opcode_base;
+}
+DWARF2_Internal_LineInfo;
+
+/* Structure found in .debug_pubnames section.	*/
+typedef struct
+{
+  unsigned char pn_length  [4];
+  unsigned char pn_version [2];
+  unsigned char pn_offset  [4];
+  unsigned char pn_size    [4];
+}
+DWARF2_External_PubNames;
+
+typedef struct
+{
+  unsigned long  pn_length;
+  unsigned short pn_version;
+  unsigned long  pn_offset;
+  unsigned long  pn_size;
+}
+DWARF2_Internal_PubNames;
+
+/* Structure found in .debug_info section.  */
+typedef struct
+{
+  unsigned char  cu_length	  [4];
+  unsigned char  cu_version	  [2];
+  unsigned char  cu_abbrev_offset [4];
+  unsigned char  cu_pointer_size  [1];
+}
+DWARF2_External_CompUnit;
+
+typedef struct
+{
+  unsigned long  cu_length;
+  unsigned short cu_version;
+  unsigned long  cu_abbrev_offset;
+  unsigned char  cu_pointer_size;
+}
+DWARF2_Internal_CompUnit;
+
+typedef struct
+{
+  unsigned char  ar_length	 [4];
+  unsigned char  ar_version	 [2];
+  unsigned char  ar_info_offset  [4];
+  unsigned char  ar_pointer_size [1];
+  unsigned char  ar_segment_size [1];
+}
+DWARF2_External_ARange;
+
+typedef struct
+{
+  unsigned long  ar_length;
+  unsigned short ar_version;
+  unsigned long  ar_info_offset;
+  unsigned char  ar_pointer_size;
+  unsigned char  ar_segment_size;
+}
+DWARF2_Internal_ARange;
+
+#define ENUM(name) enum name {
+#define IF_NOT_ASM(a) a
+#define COMMA ,
+#else
+#define ENUM(name)
+#define IF_NOT_ASM(a)
+#define COMMA
+
+#endif
+
+/* Tag names and codes.  */
+ENUM(dwarf_tag)
+
+    DW_TAG_padding = 0x00 COMMA
+    DW_TAG_array_type = 0x01 COMMA
+    DW_TAG_class_type = 0x02 COMMA
+    DW_TAG_entry_point = 0x03 COMMA
+    DW_TAG_enumeration_type = 0x04 COMMA
+    DW_TAG_formal_parameter = 0x05 COMMA
+    DW_TAG_imported_declaration = 0x08 COMMA
+    DW_TAG_label = 0x0a COMMA
+    DW_TAG_lexical_block = 0x0b COMMA
+    DW_TAG_member = 0x0d COMMA
+    DW_TAG_pointer_type = 0x0f COMMA
+    DW_TAG_reference_type = 0x10 COMMA
+    DW_TAG_compile_unit = 0x11 COMMA
+    DW_TAG_string_type = 0x12 COMMA
+    DW_TAG_structure_type = 0x13 COMMA
+    DW_TAG_subroutine_type = 0x15 COMMA
+    DW_TAG_typedef = 0x16 COMMA
+    DW_TAG_union_type = 0x17 COMMA
+    DW_TAG_unspecified_parameters = 0x18 COMMA
+    DW_TAG_variant = 0x19 COMMA
+    DW_TAG_common_block = 0x1a COMMA
+    DW_TAG_common_inclusion = 0x1b COMMA
+    DW_TAG_inheritance = 0x1c COMMA
+    DW_TAG_inlined_subroutine = 0x1d COMMA
+    DW_TAG_module = 0x1e COMMA
+    DW_TAG_ptr_to_member_type = 0x1f COMMA
+    DW_TAG_set_type = 0x20 COMMA
+    DW_TAG_subrange_type = 0x21 COMMA
+    DW_TAG_with_stmt = 0x22 COMMA
+    DW_TAG_access_declaration = 0x23 COMMA
+    DW_TAG_base_type = 0x24 COMMA
+    DW_TAG_catch_block = 0x25 COMMA
+    DW_TAG_const_type = 0x26 COMMA
+    DW_TAG_constant = 0x27 COMMA
+    DW_TAG_enumerator = 0x28 COMMA
+    DW_TAG_file_type = 0x29 COMMA
+    DW_TAG_friend = 0x2a COMMA
+    DW_TAG_namelist = 0x2b COMMA
+    DW_TAG_namelist_item = 0x2c COMMA
+    DW_TAG_packed_type = 0x2d COMMA
+    DW_TAG_subprogram = 0x2e COMMA
+    DW_TAG_template_type_param = 0x2f COMMA
+    DW_TAG_template_value_param = 0x30 COMMA
+    DW_TAG_thrown_type = 0x31 COMMA
+    DW_TAG_try_block = 0x32 COMMA
+    DW_TAG_variant_part = 0x33 COMMA
+    DW_TAG_variable = 0x34 COMMA
+    DW_TAG_volatile_type = 0x35 COMMA
+    /* DWARF 3.  */
+    DW_TAG_dwarf_procedure = 0x36 COMMA
+    DW_TAG_restrict_type = 0x37 COMMA
+    DW_TAG_interface_type = 0x38 COMMA
+    DW_TAG_namespace = 0x39 COMMA
+    DW_TAG_imported_module = 0x3a COMMA
+    DW_TAG_unspecified_type = 0x3b COMMA
+    DW_TAG_partial_unit = 0x3c COMMA
+    DW_TAG_imported_unit = 0x3d COMMA
+    /* SGI/MIPS Extensions.  */
+    DW_TAG_MIPS_loop = 0x4081 COMMA
+    /* GNU extensions.	*/
+    DW_TAG_format_label = 0x4101 COMMA	/* For FORTRAN 77 and Fortran 90.  */
+    DW_TAG_function_template = 0x4102 COMMA	/* For C++.  */
+    DW_TAG_class_template = 0x4103 COMMA	/* For C++.  */
+    DW_TAG_GNU_BINCL = 0x4104 COMMA
+    DW_TAG_GNU_EINCL = 0x4105 COMMA
+    /* Extensions for UPC.  See: http://upc.gwu.edu/~upc.  */
+    DW_TAG_upc_shared_type = 0x8765 COMMA
+    DW_TAG_upc_strict_type = 0x8766 COMMA
+    DW_TAG_upc_relaxed_type = 0x8767
+IF_NOT_ASM(};)
+
+#define DW_TAG_lo_user	0x4080
+#define DW_TAG_hi_user	0xffff
+
+/* Flag that tells whether entry has a child or not.  */
+#define DW_children_no	 0
+#define	DW_children_yes  1
+
+/* Form names and codes.  */
+ENUM(dwarf_form)
+
+    DW_FORM_addr = 0x01 COMMA
+    DW_FORM_block2 = 0x03 COMMA
+    DW_FORM_block4 = 0x04 COMMA
+    DW_FORM_data2 = 0x05 COMMA
+    DW_FORM_data4 = 0x06 COMMA
+    DW_FORM_data8 = 0x07 COMMA
+    DW_FORM_string = 0x08 COMMA
+    DW_FORM_block = 0x09 COMMA
+    DW_FORM_block1 = 0x0a COMMA
+    DW_FORM_data1 = 0x0b COMMA
+    DW_FORM_flag = 0x0c COMMA
+    DW_FORM_sdata = 0x0d COMMA
+    DW_FORM_strp = 0x0e COMMA
+    DW_FORM_udata = 0x0f COMMA
+    DW_FORM_ref_addr = 0x10 COMMA
+    DW_FORM_ref1 = 0x11 COMMA
+    DW_FORM_ref2 = 0x12 COMMA
+    DW_FORM_ref4 = 0x13 COMMA
+    DW_FORM_ref8 = 0x14 COMMA
+    DW_FORM_ref_udata = 0x15 COMMA
+    DW_FORM_indirect = 0x16
+IF_NOT_ASM(};)
+
+/* Attribute names and codes.  */
+
+ENUM(dwarf_attribute)
+
+    DW_AT_sibling = 0x01 COMMA
+    DW_AT_location = 0x02 COMMA
+    DW_AT_name = 0x03 COMMA
+    DW_AT_ordering = 0x09 COMMA
+    DW_AT_subscr_data = 0x0a COMMA
+    DW_AT_byte_size = 0x0b COMMA
+    DW_AT_bit_offset = 0x0c COMMA
+    DW_AT_bit_size = 0x0d COMMA
+    DW_AT_element_list = 0x0f COMMA
+    DW_AT_stmt_list = 0x10 COMMA
+    DW_AT_low_pc = 0x11 COMMA
+    DW_AT_high_pc = 0x12 COMMA
+    DW_AT_language = 0x13 COMMA
+    DW_AT_member = 0x14 COMMA
+    DW_AT_discr = 0x15 COMMA
+    DW_AT_discr_value = 0x16 COMMA
+    DW_AT_visibility = 0x17 COMMA
+    DW_AT_import = 0x18 COMMA
+    DW_AT_string_length = 0x19 COMMA
+    DW_AT_common_reference = 0x1a COMMA
+    DW_AT_comp_dir = 0x1b COMMA
+    DW_AT_const_value = 0x1c COMMA
+    DW_AT_containing_type = 0x1d COMMA
+    DW_AT_default_value = 0x1e COMMA
+    DW_AT_inline = 0x20 COMMA
+    DW_AT_is_optional = 0x21 COMMA
+    DW_AT_lower_bound = 0x22 COMMA
+    DW_AT_producer = 0x25 COMMA
+    DW_AT_prototyped = 0x27 COMMA
+    DW_AT_return_addr = 0x2a COMMA
+    DW_AT_start_scope = 0x2c COMMA
+    DW_AT_stride_size = 0x2e COMMA
+    DW_AT_upper_bound = 0x2f COMMA
+    DW_AT_abstract_origin = 0x31 COMMA
+    DW_AT_accessibility = 0x32 COMMA
+    DW_AT_address_class = 0x33 COMMA
+    DW_AT_artificial = 0x34 COMMA
+    DW_AT_base_types = 0x35 COMMA
+    DW_AT_calling_convention = 0x36 COMMA
+    DW_AT_count = 0x37 COMMA
+    DW_AT_data_member_location = 0x38 COMMA
+    DW_AT_decl_column = 0x39 COMMA
+    DW_AT_decl_file = 0x3a COMMA
+    DW_AT_decl_line = 0x3b COMMA
+    DW_AT_declaration = 0x3c COMMA
+    DW_AT_discr_list = 0x3d COMMA
+    DW_AT_encoding = 0x3e COMMA
+    DW_AT_external = 0x3f COMMA
+    DW_AT_frame_base = 0x40 COMMA
+    DW_AT_friend = 0x41 COMMA
+    DW_AT_identifier_case = 0x42 COMMA
+    DW_AT_macro_info = 0x43 COMMA
+    DW_AT_namelist_items = 0x44 COMMA
+    DW_AT_priority = 0x45 COMMA
+    DW_AT_segment = 0x46 COMMA
+    DW_AT_specification = 0x47 COMMA
+    DW_AT_static_link = 0x48 COMMA
+    DW_AT_type = 0x49 COMMA
+    DW_AT_use_location = 0x4a COMMA
+    DW_AT_variable_parameter = 0x4b COMMA
+    DW_AT_virtuality = 0x4c COMMA
+    DW_AT_vtable_elem_location = 0x4d COMMA
+    /* DWARF 3 values.	*/
+    DW_AT_allocated	= 0x4e COMMA
+    DW_AT_associated	= 0x4f COMMA
+    DW_AT_data_location = 0x50 COMMA
+    DW_AT_stride	= 0x51 COMMA
+    DW_AT_entry_pc	= 0x52 COMMA
+    DW_AT_use_UTF8	= 0x53 COMMA
+    DW_AT_extension	= 0x54 COMMA
+    DW_AT_ranges	= 0x55 COMMA
+    DW_AT_trampoline	= 0x56 COMMA
+    DW_AT_call_column	= 0x57 COMMA
+    DW_AT_call_file	= 0x58 COMMA
+    DW_AT_call_line	= 0x59 COMMA
+    /* SGI/MIPS extensions.  */
+    DW_AT_MIPS_fde = 0x2001 COMMA
+    DW_AT_MIPS_loop_begin = 0x2002 COMMA
+    DW_AT_MIPS_tail_loop_begin = 0x2003 COMMA
+    DW_AT_MIPS_epilog_begin = 0x2004 COMMA
+    DW_AT_MIPS_loop_unroll_factor = 0x2005 COMMA
+    DW_AT_MIPS_software_pipeline_depth = 0x2006 COMMA
+    DW_AT_MIPS_linkage_name = 0x2007 COMMA
+    DW_AT_MIPS_stride = 0x2008 COMMA
+    DW_AT_MIPS_abstract_name = 0x2009 COMMA
+    DW_AT_MIPS_clone_origin = 0x200a COMMA
+    DW_AT_MIPS_has_inlines = 0x200b COMMA
+    /* GNU extensions.	*/
+    DW_AT_sf_names   = 0x2101 COMMA
+    DW_AT_src_info   = 0x2102 COMMA
+    DW_AT_mac_info   = 0x2103 COMMA
+    DW_AT_src_coords = 0x2104 COMMA
+    DW_AT_body_begin = 0x2105 COMMA
+    DW_AT_body_end   = 0x2106 COMMA
+    DW_AT_GNU_vector = 0x2107 COMMA
+    /* VMS extensions.	*/
+    DW_AT_VMS_rtnbeg_pd_address = 0x2201 COMMA
+    /* UPC extension.  */
+    DW_AT_upc_threads_scaled = 0x3210
+IF_NOT_ASM(};)
+
+#define DW_AT_lo_user	0x2000	/* Implementation-defined range start.	*/
+#define DW_AT_hi_user	0x3ff0	/* Implementation-defined range end.  */
+
+/* Location atom names and codes.  */
+ENUM(dwarf_location_atom)
+
+    DW_OP_addr = 0x03 COMMA
+    DW_OP_deref = 0x06 COMMA
+    DW_OP_const1u = 0x08 COMMA
+    DW_OP_const1s = 0x09 COMMA
+    DW_OP_const2u = 0x0a COMMA
+    DW_OP_const2s = 0x0b COMMA
+    DW_OP_const4u = 0x0c COMMA
+    DW_OP_const4s = 0x0d COMMA
+    DW_OP_const8u = 0x0e COMMA
+    DW_OP_const8s = 0x0f COMMA
+    DW_OP_constu = 0x10 COMMA
+    DW_OP_consts = 0x11 COMMA
+    DW_OP_dup = 0x12 COMMA
+    DW_OP_drop = 0x13 COMMA
+    DW_OP_over = 0x14 COMMA
+    DW_OP_pick = 0x15 COMMA
+    DW_OP_swap = 0x16 COMMA
+    DW_OP_rot = 0x17 COMMA
+    DW_OP_xderef = 0x18 COMMA
+    DW_OP_abs = 0x19 COMMA
+    DW_OP_and = 0x1a COMMA
+    DW_OP_div = 0x1b COMMA
+    DW_OP_minus = 0x1c COMMA
+    DW_OP_mod = 0x1d COMMA
+    DW_OP_mul = 0x1e COMMA
+    DW_OP_neg = 0x1f COMMA
+    DW_OP_not = 0x20 COMMA
+    DW_OP_or = 0x21 COMMA
+    DW_OP_plus = 0x22 COMMA
+    DW_OP_plus_uconst = 0x23 COMMA
+    DW_OP_shl = 0x24 COMMA
+    DW_OP_shr = 0x25 COMMA
+    DW_OP_shra = 0x26 COMMA
+    DW_OP_xor = 0x27 COMMA
+    DW_OP_bra = 0x28 COMMA
+    DW_OP_eq = 0x29 COMMA
+    DW_OP_ge = 0x2a COMMA
+    DW_OP_gt = 0x2b COMMA
+    DW_OP_le = 0x2c COMMA
+    DW_OP_lt = 0x2d COMMA
+    DW_OP_ne = 0x2e COMMA
+    DW_OP_skip = 0x2f COMMA
+    DW_OP_lit0 = 0x30 COMMA
+    DW_OP_lit1 = 0x31 COMMA
+    DW_OP_lit2 = 0x32 COMMA
+    DW_OP_lit3 = 0x33 COMMA
+    DW_OP_lit4 = 0x34 COMMA
+    DW_OP_lit5 = 0x35 COMMA
+    DW_OP_lit6 = 0x36 COMMA
+    DW_OP_lit7 = 0x37 COMMA
+    DW_OP_lit8 = 0x38 COMMA
+    DW_OP_lit9 = 0x39 COMMA
+    DW_OP_lit10 = 0x3a COMMA
+    DW_OP_lit11 = 0x3b COMMA
+    DW_OP_lit12 = 0x3c COMMA
+    DW_OP_lit13 = 0x3d COMMA
+    DW_OP_lit14 = 0x3e COMMA
+    DW_OP_lit15 = 0x3f COMMA
+    DW_OP_lit16 = 0x40 COMMA
+    DW_OP_lit17 = 0x41 COMMA
+    DW_OP_lit18 = 0x42 COMMA
+    DW_OP_lit19 = 0x43 COMMA
+    DW_OP_lit20 = 0x44 COMMA
+    DW_OP_lit21 = 0x45 COMMA
+    DW_OP_lit22 = 0x46 COMMA
+    DW_OP_lit23 = 0x47 COMMA
+    DW_OP_lit24 = 0x48 COMMA
+    DW_OP_lit25 = 0x49 COMMA
+    DW_OP_lit26 = 0x4a COMMA
+    DW_OP_lit27 = 0x4b COMMA
+    DW_OP_lit28 = 0x4c COMMA
+    DW_OP_lit29 = 0x4d COMMA
+    DW_OP_lit30 = 0x4e COMMA
+    DW_OP_lit31 = 0x4f COMMA
+    DW_OP_reg0 = 0x50 COMMA
+    DW_OP_reg1 = 0x51 COMMA
+    DW_OP_reg2 = 0x52 COMMA
+    DW_OP_reg3 = 0x53 COMMA
+    DW_OP_reg4 = 0x54 COMMA
+    DW_OP_reg5 = 0x55 COMMA
+    DW_OP_reg6 = 0x56 COMMA
+    DW_OP_reg7 = 0x57 COMMA
+    DW_OP_reg8 = 0x58 COMMA
+    DW_OP_reg9 = 0x59 COMMA
+    DW_OP_reg10 = 0x5a COMMA
+    DW_OP_reg11 = 0x5b COMMA
+    DW_OP_reg12 = 0x5c COMMA
+    DW_OP_reg13 = 0x5d COMMA
+    DW_OP_reg14 = 0x5e COMMA
+    DW_OP_reg15 = 0x5f COMMA
+    DW_OP_reg16 = 0x60 COMMA
+    DW_OP_reg17 = 0x61 COMMA
+    DW_OP_reg18 = 0x62 COMMA
+    DW_OP_reg19 = 0x63 COMMA
+    DW_OP_reg20 = 0x64 COMMA
+    DW_OP_reg21 = 0x65 COMMA
+    DW_OP_reg22 = 0x66 COMMA
+    DW_OP_reg23 = 0x67 COMMA
+    DW_OP_reg24 = 0x68 COMMA
+    DW_OP_reg25 = 0x69 COMMA
+    DW_OP_reg26 = 0x6a COMMA
+    DW_OP_reg27 = 0x6b COMMA
+    DW_OP_reg28 = 0x6c COMMA
+    DW_OP_reg29 = 0x6d COMMA
+    DW_OP_reg30 = 0x6e COMMA
+    DW_OP_reg31 = 0x6f COMMA
+    DW_OP_breg0 = 0x70 COMMA
+    DW_OP_breg1 = 0x71 COMMA
+    DW_OP_breg2 = 0x72 COMMA
+    DW_OP_breg3 = 0x73 COMMA
+    DW_OP_breg4 = 0x74 COMMA
+    DW_OP_breg5 = 0x75 COMMA
+    DW_OP_breg6 = 0x76 COMMA
+    DW_OP_breg7 = 0x77 COMMA
+    DW_OP_breg8 = 0x78 COMMA
+    DW_OP_breg9 = 0x79 COMMA
+    DW_OP_breg10 = 0x7a COMMA
+    DW_OP_breg11 = 0x7b COMMA
+    DW_OP_breg12 = 0x7c COMMA
+    DW_OP_breg13 = 0x7d COMMA
+    DW_OP_breg14 = 0x7e COMMA
+    DW_OP_breg15 = 0x7f COMMA
+    DW_OP_breg16 = 0x80 COMMA
+    DW_OP_breg17 = 0x81 COMMA
+    DW_OP_breg18 = 0x82 COMMA
+    DW_OP_breg19 = 0x83 COMMA
+    DW_OP_breg20 = 0x84 COMMA
+    DW_OP_breg21 = 0x85 COMMA
+    DW_OP_breg22 = 0x86 COMMA
+    DW_OP_breg23 = 0x87 COMMA
+    DW_OP_breg24 = 0x88 COMMA
+    DW_OP_breg25 = 0x89 COMMA
+    DW_OP_breg26 = 0x8a COMMA
+    DW_OP_breg27 = 0x8b COMMA
+    DW_OP_breg28 = 0x8c COMMA
+    DW_OP_breg29 = 0x8d COMMA
+    DW_OP_breg30 = 0x8e COMMA
+    DW_OP_breg31 = 0x8f COMMA
+    DW_OP_regx = 0x90 COMMA
+    DW_OP_fbreg = 0x91 COMMA
+    DW_OP_bregx = 0x92 COMMA
+    DW_OP_piece = 0x93 COMMA
+    DW_OP_deref_size = 0x94 COMMA
+    DW_OP_xderef_size = 0x95 COMMA
+    DW_OP_nop = 0x96 COMMA
+    /* DWARF 3 extensions.  */
+    DW_OP_push_object_address = 0x97 COMMA
+    DW_OP_call2 = 0x98 COMMA
+    DW_OP_call4 = 0x99 COMMA
+    DW_OP_call_ref = 0x9a COMMA
+    /* GNU extensions.	*/
+    DW_OP_GNU_push_tls_address = 0xe0
+IF_NOT_ASM(};)
+
+#define DW_OP_lo_user	0xe0	/* Implementation-defined range start.	*/
+#define DW_OP_hi_user	0xff	/* Implementation-defined range end.  */
+
+/* Type encodings.  */
+ENUM(dwarf_type)
+
+    DW_ATE_void = 0x0 COMMA
+    DW_ATE_address = 0x1 COMMA
+    DW_ATE_boolean = 0x2 COMMA
+    DW_ATE_complex_float = 0x3 COMMA
+    DW_ATE_float = 0x4 COMMA
+    DW_ATE_signed = 0x5 COMMA
+    DW_ATE_signed_char = 0x6 COMMA
+    DW_ATE_unsigned = 0x7 COMMA
+    DW_ATE_unsigned_char = 0x8 COMMA
+    /* DWARF 3.  */
+    DW_ATE_imaginary_float = 0x9
+IF_NOT_ASM(};)
+
+#define	DW_ATE_lo_user 0x80
+#define	DW_ATE_hi_user 0xff
+
+/* Array ordering names and codes.  */
+ENUM(dwarf_array_dim_ordering)
+
+    DW_ORD_row_major = 0 COMMA
+    DW_ORD_col_major = 1
+IF_NOT_ASM(};)
+
+/* Access attribute.  */
+ENUM(dwarf_access_attribute)
+
+    DW_ACCESS_public = 1 COMMA
+    DW_ACCESS_protected = 2 COMMA
+    DW_ACCESS_private = 3
+IF_NOT_ASM(};)
+
+/* Visibility.	*/
+ENUM(dwarf_visibility_attribute)
+
+    DW_VIS_local = 1 COMMA
+    DW_VIS_exported = 2 COMMA
+    DW_VIS_qualified = 3
+IF_NOT_ASM(};)
+
+/* Virtuality.	*/
+ENUM(dwarf_virtuality_attribute)
+
+    DW_VIRTUALITY_none = 0 COMMA
+    DW_VIRTUALITY_virtual = 1 COMMA
+    DW_VIRTUALITY_pure_virtual = 2
+IF_NOT_ASM(};)
+
+/* Case sensitivity.  */
+ENUM(dwarf_id_case)
+
+    DW_ID_case_sensitive = 0 COMMA
+    DW_ID_up_case = 1 COMMA
+    DW_ID_down_case = 2 COMMA
+    DW_ID_case_insensitive = 3
+IF_NOT_ASM(};)
+
+/* Calling convention.	*/
+ENUM(dwarf_calling_convention)
+
+    DW_CC_normal = 0x1 COMMA
+    DW_CC_program = 0x2 COMMA
+    DW_CC_nocall = 0x3
+IF_NOT_ASM(};)
+
+#define DW_CC_lo_user 0x40
+#define DW_CC_hi_user 0xff
+
+/* Inline attribute.  */
+ENUM(dwarf_inline_attribute)
+
+    DW_INL_not_inlined = 0 COMMA
+    DW_INL_inlined = 1 COMMA
+    DW_INL_declared_not_inlined = 2 COMMA
+    DW_INL_declared_inlined = 3
+IF_NOT_ASM(};)
+
+/* Discriminant lists.	*/
+ENUM(dwarf_discrim_list)
+
+    DW_DSC_label = 0 COMMA
+    DW_DSC_range = 1
+IF_NOT_ASM(};)
+
+/* Line number opcodes.  */
+ENUM(dwarf_line_number_ops)
+
+    DW_LNS_extended_op = 0 COMMA
+    DW_LNS_copy = 1 COMMA
+    DW_LNS_advance_pc = 2 COMMA
+    DW_LNS_advance_line = 3 COMMA
+    DW_LNS_set_file = 4 COMMA
+    DW_LNS_set_column = 5 COMMA
+    DW_LNS_negate_stmt = 6 COMMA
+    DW_LNS_set_basic_block = 7 COMMA
+    DW_LNS_const_add_pc = 8 COMMA
+    DW_LNS_fixed_advance_pc = 9 COMMA
+    /* DWARF 3.  */
+    DW_LNS_set_prologue_end = 10 COMMA
+    DW_LNS_set_epilogue_begin = 11 COMMA
+    DW_LNS_set_isa = 12
+IF_NOT_ASM(};)
+
+/* Line number extended opcodes.  */
+ENUM(dwarf_line_number_x_ops)
+
+    DW_LNE_end_sequence = 1 COMMA
+    DW_LNE_set_address = 2 COMMA
+    DW_LNE_define_file = 3
+IF_NOT_ASM(};)
+
+/* Call frame information.  */
+ENUM(dwarf_call_frame_info)
+
+    DW_CFA_advance_loc = 0x40 COMMA
+    DW_CFA_offset = 0x80 COMMA
+    DW_CFA_restore = 0xc0 COMMA
+    DW_CFA_nop = 0x00 COMMA
+    DW_CFA_set_loc = 0x01 COMMA
+    DW_CFA_advance_loc1 = 0x02 COMMA
+    DW_CFA_advance_loc2 = 0x03 COMMA
+    DW_CFA_advance_loc4 = 0x04 COMMA
+    DW_CFA_offset_extended = 0x05 COMMA
+    DW_CFA_restore_extended = 0x06 COMMA
+    DW_CFA_undefined = 0x07 COMMA
+    DW_CFA_same_value = 0x08 COMMA
+    DW_CFA_register = 0x09 COMMA
+    DW_CFA_remember_state = 0x0a COMMA
+    DW_CFA_restore_state = 0x0b COMMA
+    DW_CFA_def_cfa = 0x0c COMMA
+    DW_CFA_def_cfa_register = 0x0d COMMA
+    DW_CFA_def_cfa_offset = 0x0e COMMA
+
+    /* DWARF 3.  */
+    DW_CFA_def_cfa_expression = 0x0f COMMA
+    DW_CFA_expression = 0x10 COMMA
+    DW_CFA_offset_extended_sf = 0x11 COMMA
+    DW_CFA_def_cfa_sf = 0x12 COMMA
+    DW_CFA_def_cfa_offset_sf = 0x13 COMMA
+
+    /* SGI/MIPS specific.  */
+    DW_CFA_MIPS_advance_loc8 = 0x1d COMMA
+
+    /* GNU extensions.	*/
+    DW_CFA_GNU_window_save = 0x2d COMMA
+    DW_CFA_GNU_args_size = 0x2e COMMA
+    DW_CFA_GNU_negative_offset_extended = 0x2f
+IF_NOT_ASM(};)
+
+#define DW_CIE_ID	  0xffffffff
+#define DW_CIE_VERSION	  1
+
+#define DW_CFA_extended   0
+#define DW_CFA_lo_user	  0x1c
+#define DW_CFA_hi_user	  0x3f
+
+#define DW_CHILDREN_no		     0x00
+#define DW_CHILDREN_yes		     0x01
+
+#define DW_ADDR_none		0
+
+/* Source language names and codes.  */
+ENUM(dwarf_source_language)
+
+    DW_LANG_C89 = 0x0001 COMMA
+    DW_LANG_C = 0x0002 COMMA
+    DW_LANG_Ada83 = 0x0003 COMMA
+    DW_LANG_C_plus_plus = 0x0004 COMMA
+    DW_LANG_Cobol74 = 0x0005 COMMA
+    DW_LANG_Cobol85 = 0x0006 COMMA
+    DW_LANG_Fortran77 = 0x0007 COMMA
+    DW_LANG_Fortran90 = 0x0008 COMMA
+    DW_LANG_Pascal83 = 0x0009 COMMA
+    DW_LANG_Modula2 = 0x000a COMMA
+    DW_LANG_Java = 0x000b COMMA
+    /* DWARF 3.  */
+    DW_LANG_C99 = 0x000c COMMA
+    DW_LANG_Ada95 = 0x000d COMMA
+    DW_LANG_Fortran95 = 0x000e COMMA
+    /* MIPS.  */
+    DW_LANG_Mips_Assembler = 0x8001 COMMA
+    /* UPC.  */
+    DW_LANG_Upc = 0x8765
+IF_NOT_ASM(};)
+
+#define DW_LANG_lo_user 0x8000	/* Implementation-defined range start.	*/
+#define DW_LANG_hi_user 0xffff	/* Implementation-defined range start.	*/
+
+/* Names and codes for macro information.  */
+ENUM(dwarf_macinfo_record_type)
+
+    DW_MACINFO_define = 1 COMMA
+    DW_MACINFO_undef = 2 COMMA
+    DW_MACINFO_start_file = 3 COMMA
+    DW_MACINFO_end_file = 4 COMMA
+    DW_MACINFO_vendor_ext = 255
+IF_NOT_ASM(};)
+
+/* @@@ For use with GNU frame unwind information.  */
+
+#define DW_EH_PE_absptr		0x00
+#define DW_EH_PE_omit		0xff
+
+#define DW_EH_PE_uleb128	0x01
+#define DW_EH_PE_udata2		0x02
+#define DW_EH_PE_udata4		0x03
+#define DW_EH_PE_udata8		0x04
+#define DW_EH_PE_sleb128	0x09
+#define DW_EH_PE_sdata2		0x0A
+#define DW_EH_PE_sdata4		0x0B
+#define DW_EH_PE_sdata8		0x0C
+#define DW_EH_PE_signed		0x08
+
+#define DW_EH_PE_pcrel		0x10
+#define DW_EH_PE_textrel	0x20
+#define DW_EH_PE_datarel	0x30
+#define DW_EH_PE_funcrel	0x40
+#define DW_EH_PE_aligned	0x50
+
+#define DW_EH_PE_indirect	0x80
+
+#endif /* _ELF_DWARF2_H */
--- diff/include/linux/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/lockmeter.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,320 @@
+/*
+ *  Copyright (C) 1999-2002 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ *
+ *  Modified by Ray Bryant (raybry@us.ibm.com) Feb-Apr 2000
+ *  Changes Copyright (C) 2000 IBM, Inc.
+ *  Added save of index in spinlock_t to improve efficiency
+ *  of "hold" time reporting for spinlocks
+ *  Added support for hold time statistics for read and write
+ *  locks.
+ *  Moved machine dependent code to include/asm/lockmeter.h.
+ *
+ */
+
+#ifndef _LINUX_LOCKMETER_H
+#define _LINUX_LOCKMETER_H
+
+
+/*---------------------------------------------------
+ *	architecture-independent lockmeter.h
+ *-------------------------------------------------*/
+
+/*
+ * raybry -- version 2: added efficient hold time statistics
+ *           requires lstat recompile, so flagged as new version
+ * raybry -- version 3: added global reader lock data
+ * hawkes -- version 4: removed some unnecessary fields to simplify mips64 port
+ */
+#define LSTAT_VERSION	5
+
+int	lstat_update(void*, void*, int);
+int	lstat_update_time(void*, void*, int, uint32_t);
+
+/*
+ * Currently, the mips64 and sparc64 kernels talk to a 32-bit lockstat, so we
+ * need to force compatibility in the inter-communication data structure.
+ */
+
+#if defined(CONFIG_MIPS32_COMPAT)
+#define TIME_T		uint32_t
+#elif defined(CONFIG_SPARC) || defined(CONFIG_SPARC64)
+#define TIME_T		uint64_t
+#else
+#define TIME_T		time_t
+#endif
+
+#if defined(__KERNEL__) || (!defined(CONFIG_MIPS32_COMPAT) && !defined(CONFIG_SPARC) && !defined(CONFIG_SPARC64)) || (_MIPS_SZLONG==32)
+#define POINTER		void *
+#else
+#define	POINTER		int64_t
+#endif
+
+/*
+ * Values for the "action" parameter passed to lstat_update.
+ *	ZZZ - do we want a try-success status here???
+ */
+#define LSTAT_ACT_NO_WAIT	0
+#define LSTAT_ACT_SPIN		1
+#define LSTAT_ACT_REJECT	2
+#define LSTAT_ACT_WW_SPIN       3
+#define LSTAT_ACT_SLEPT		4 /* UNUSED */
+
+#define LSTAT_ACT_MAX_VALUES	4 /* NOTE: Increase to 5 if use ACT_SLEPT */
+
+/*
+ * Special values for the low 2 bits of an RA passed to
+ * lstat_update.
+ */
+/* we use these values to figure out what kind of lock data */
+/* is stored in the statistics table entry at index ....... */
+#define LSTAT_RA_SPIN           0  /* spin lock data */
+#define LSTAT_RA_READ           1  /* read lock statistics */
+#define LSTAT_RA_SEMA		2  /* RESERVED */
+#define LSTAT_RA_WRITE          3  /* write lock statistics*/
+
+#define LSTAT_RA(n)	\
+	((void*)( ((unsigned long)__builtin_return_address(0) & ~3) | n) )
+
+/*
+ * Constants used for lock addresses in the lstat_directory
+ * to indicate special values of the lock address.
+ */
+#define	LSTAT_MULTI_LOCK_ADDRESS	NULL
+
+/*
+ * Maximum size of the lockstats tables. Increase this value
+ * if its not big enough. (Nothing bad happens if its not
+ * big enough although some locks will not be monitored.)
+ * We record overflows of this quantity in lstat_control.dir_overflows
+ *
+ * Note:  The max value here must fit into the field set
+ * and obtained by the macro's PUT_INDEX() and GET_INDEX().
+ * This value depends on how many bits are available in the
+ * lock word in the particular machine implementation we are on.
+ */
+#define LSTAT_MAX_STAT_INDEX		2000
+
+/*
+ * Size and mask for the hash table into the directory.
+ */
+#define LSTAT_HASH_TABLE_SIZE		4096		/* must be 2**N */
+#define LSTAT_HASH_TABLE_MASK		(LSTAT_HASH_TABLE_SIZE-1)
+
+#define DIRHASH(ra)      ((unsigned long)(ra)>>2 & LSTAT_HASH_TABLE_MASK)
+
+/*
+ *	This defines an entry in the lockstat directory. It contains
+ *	information about a lock being monitored.
+ *	A directory entry only contains the lock identification -
+ *	counts on usage of the lock are kept elsewhere in a per-cpu
+ *	data structure to minimize cache line pinging.
+ */
+typedef struct {
+	POINTER	caller_ra;		  /* RA of code that set lock */
+	POINTER	lock_ptr;		  /* lock address */
+	ushort	next_stat_index;  /* Used to link multiple locks that have the same hash table value */
+} lstat_directory_entry_t;
+
+/*
+ *	A multi-dimensioned array used to contain counts for lock accesses.
+ *	The array is 3-dimensional:
+ *		- CPU number. Keep from thrashing cache lines between CPUs
+ *		- Directory entry index. Identifies the lock
+ *		- Action. Indicates what kind of contention occurred on an
+ *		  access to the lock.
+ *
+ *	The index of an entry in the directory is the same as the 2nd index
+ *	of the entry in the counts array.
+ */
+/*
+ *  This table contains data for spin_locks, write locks, and read locks
+ *  Not all data is used for all cases.  In particular, the hold time
+ *  information is not stored here for read locks since that is a global
+ *  (e. g. cannot be separated out by return address) quantity.
+ *  See the lstat_read_lock_counts_t structure for the global read lock
+ *  hold time.
+ */
+typedef struct {
+	uint64_t    cum_wait_ticks;	/* sum of wait times               */
+	                                /* for write locks, sum of time a  */
+					/* writer is waiting for a reader  */
+	int64_t	    cum_hold_ticks;	/* cumulative sum of holds         */
+	                                /* not used for read mode locks    */
+					/* must be signed. ............... */
+	uint32_t    max_wait_ticks;	/* max waiting time                */
+	uint32_t    max_hold_ticks;	/* max holding time                */
+	uint64_t    cum_wait_ww_ticks;  /* sum times writer waits on writer*/
+	uint32_t    max_wait_ww_ticks;  /* max wait time writer vs writer  */
+	                                /* prev 2 only used for write locks*/
+	uint32_t    acquire_time;       /* time lock acquired this CPU     */
+	uint32_t    count[LSTAT_ACT_MAX_VALUES];
+} lstat_lock_counts_t;
+
+typedef lstat_lock_counts_t	lstat_cpu_counts_t[LSTAT_MAX_STAT_INDEX];
+
+/*
+ * User request to:
+ *	- turn statistic collection on/off, or to reset
+ */
+#define LSTAT_OFF	 0
+#define LSTAT_ON	 1
+#define LSTAT_RESET      2
+#define LSTAT_RELEASE    3
+
+#define LSTAT_MAX_READ_LOCK_INDEX 1000
+typedef struct {
+	POINTER	    lock_ptr;            /* address of lock for output stats */
+	uint32_t    read_lock_count;
+	int64_t     cum_hold_ticks;       /* sum of read lock hold times over */
+	                                  /* all callers. ....................*/
+	uint32_t    write_index;          /* last write lock hash table index */
+	uint32_t    busy_periods;         /* count of busy periods ended this */
+	uint64_t    start_busy;           /* time this busy period started. ..*/
+	uint64_t    busy_ticks;           /* sum of busy periods this lock. ..*/
+	uint64_t    max_busy;             /* longest busy period for this lock*/
+	uint32_t    max_readers;          /* maximum number of readers ...... */
+#ifdef USER_MODE_TESTING
+	rwlock_t    entry_lock;           /* lock for this read lock entry... */
+	                                  /* avoid having more than one rdr at*/
+	                                  /* needed for user space testing... */
+	                                  /* not needed for kernel 'cause it  */
+					  /* is non-preemptive. ............. */
+#endif
+} lstat_read_lock_counts_t;
+typedef lstat_read_lock_counts_t	lstat_read_lock_cpu_counts_t[LSTAT_MAX_READ_LOCK_INDEX];
+
+#if defined(__KERNEL__) || defined(USER_MODE_TESTING)
+
+#ifndef USER_MODE_TESTING
+#include <asm/lockmeter.h>
+#else
+#include "asm_newlockmeter.h"
+#endif
+
+/*
+ * Size and mask for the hash table into the directory.
+ */
+#define LSTAT_HASH_TABLE_SIZE		4096		/* must be 2**N */
+#define LSTAT_HASH_TABLE_MASK		(LSTAT_HASH_TABLE_SIZE-1)
+
+#define DIRHASH(ra)      ((unsigned long)(ra)>>2 & LSTAT_HASH_TABLE_MASK)
+
+/*
+ * This version eliminates the per processor lock stack.  What we do is to
+ * store the index of the lock hash structure in unused bits in the lock
+ * itself.  Then on unlock we can find the statistics record without doing
+ * any additional hash or lock stack lookup.  This works for spin_locks.
+ * Hold time reporting is now basically as cheap as wait time reporting
+ * so we ignore the difference between LSTAT_ON_HOLD and LSTAT_ON_WAIT
+ * as in version 1.1.* of lockmeter.
+ *
+ * For rw_locks, we store the index of a global reader stats structure in
+ * the lock and the writer index is stored in the latter structure.
+ * For read mode locks we hash at the time of the lock to find an entry
+ * in the directory for reader wait time and the like.
+ * At unlock time for read mode locks, we update just the global structure
+ * so we don't need to know the reader directory index value at unlock time.
+ *
+ */
+
+/*
+ * Protocol to change lstat_control.state
+ *   This is complicated because we don't want the cum_hold_time for
+ * a rw_lock to be decremented in _read_lock_ without making sure it
+ * is incremented in _read_lock_ and vice versa.  So here is the
+ * way we change the state of lstat_control.state:
+ * I.  To Turn Statistics On
+ *     After allocating storage, set lstat_control.state non-zero.
+ * This works because we don't start updating statistics for in use
+ * locks until the reader lock count goes to zero.
+ * II. To Turn Statistics Off:
+ * (0)  Disable interrupts on this CPU
+ * (1)  Seize the lstat_control.directory_lock
+ * (2)  Obtain the current value of lstat_control.next_free_read_lock_index
+ * (3)  Store a zero in lstat_control.state.
+ * (4)  Release the lstat_control.directory_lock
+ * (5)  For each lock in the read lock list up to the saved value
+ *      (well, -1) of the next_free_read_lock_index, do the following:
+ *      (a)  Check validity of the stored lock address
+ *           by making sure that the word at the saved addr
+ *           has an index that matches this entry.  If not
+ *           valid, then skip this entry.
+ *      (b)  If there is a write lock already set on this lock,
+ *           skip to (d) below.
+ *      (c)  Set a non-metered write lock on the lock
+ *      (d)  set the cached INDEX in the lock to zero
+ *      (e)  Release the non-metered write lock.
+ * (6)  Re-enable interrupts
+ *
+ * These rules ensure that a read lock will not have its statistics
+ * partially updated even though the global lock recording state has
+ * changed.  See put_lockmeter_info() for implementation.
+ *
+ * The reason for (b) is that there may be write locks set on the
+ * syscall path to put_lockmeter_info() from user space.  If we do
+ * not do this check, then we can deadlock.  A similar problem would
+ * occur if the lock was read locked by the current CPU.  At the
+ * moment this does not appear to happen.
+ */
+
+/*
+ * Main control structure for lockstat. Used to turn statistics on/off
+ * and to maintain directory info.
+ */
+typedef struct {
+	int				state;
+	spinlock_t		control_lock;		/* used to serialize turning statistics on/off   */
+	spinlock_t		directory_lock;		/* for serialize adding entries to directory     */
+	volatile int	next_free_dir_index;/* next free entry in the directory */
+	/* FIXME not all of these fields are used / needed .............. */
+                /* the following fields represent data since     */
+		/* first "lstat on" or most recent "lstat reset" */
+	TIME_T      first_started_time;     /* time when measurement first enabled */
+	TIME_T      started_time;           /* time when measurement last started  */
+	TIME_T      ending_time;            /* time when measurement last disabled */
+	uint64_t    started_cycles64;       /* cycles when measurement last started          */
+	uint64_t    ending_cycles64;        /* cycles when measurement last disabled         */
+	uint64_t    enabled_cycles64;       /* total cycles with measurement enabled         */
+	int         intervals;              /* number of measurement intervals recorded      */
+	                                    /* i. e. number of times did lstat on;lstat off  */
+	lstat_directory_entry_t	*dir;		/* directory */
+	int         dir_overflow;           /* count of times ran out of space in directory  */
+	int         rwlock_overflow;        /* count of times we couldn't allocate a rw block*/
+	ushort		*hashtab;		 	    /* hash table for quick dir scans */
+	lstat_cpu_counts_t	*counts[NR_CPUS];	 /* Array of pointers to per-cpu stats */
+    int         next_free_read_lock_index;   /* next rwlock reader (global) stats block  */
+    lstat_read_lock_cpu_counts_t *read_lock_counts[NR_CPUS]; /* per cpu read lock stats  */
+} lstat_control_t;
+
+#endif	/* defined(__KERNEL__) || defined(USER_MODE_TESTING) */
+
+typedef struct {
+	short		lstat_version;		/* version of the data */
+	short		state;			/* the current state is returned */
+	int		maxcpus;		/* Number of cpus present */
+	int		next_free_dir_index;	/* index of the next free directory entry */
+	TIME_T          first_started_time;	/* when measurement enabled for first time */
+	TIME_T          started_time;		/* time in secs since 1969 when stats last turned on  */
+	TIME_T		ending_time;		/* time in secs since 1969 when stats last turned off */
+	uint32_t	cycleval;		/* cycles per second */
+#ifdef notyet
+	void		*kernel_magic_addr;	/* address of kernel_magic */
+	void		*kernel_end_addr;	/* contents of kernel magic (points to "end") */
+#endif
+	int              next_free_read_lock_index; /* index of next (global) read lock stats struct */
+	uint64_t         started_cycles64;	/* cycles when measurement last started        */
+	uint64_t         ending_cycles64;	/* cycles when stats last turned off           */
+	uint64_t         enabled_cycles64;	/* total cycles with measurement enabled       */
+	int              intervals;		/* number of measurement intervals recorded      */
+						/* i.e. number of times we did lstat on;lstat off*/
+	int              dir_overflow;		/* number of times we wanted more space in directory */
+	int              rwlock_overflow;	/* # of times we wanted more space in read_locks_count */
+	struct new_utsname   uts;		/* info about machine where stats are measured */
+						/* -T option of lockstat allows data to be     */
+						/* moved to another machine. ................. */
+} lstat_user_request_t;
+
+#endif /* _LINUX_LOCKMETER_H */
--- diff/include/linux/mqueue.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/mqueue.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,37 @@
+/* Copyright (C) 2003 Krzysztof Benedyczak & Michal Wronski
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   It 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this software; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _LINUX_MQUEUE_H
+#define _LINUX_MQUEUE_H
+
+#define MQ_PRIO_MAX 	32768
+
+typedef int mqd_t;
+
+struct mq_attr {
+	long	mq_flags;	/* message queue flags			*/
+	long	mq_maxmsg;	/* maximum number of messages		*/
+	long	mq_msgsize;	/* maximum message size			*/
+	long	mq_curmsgs;	/* number of messages currently queued	*/
+	long	__reserved[4];	/* ignored for input, zeroed for output */
+};
+
+#define NOTIFY_NONE	0
+#define NOTIFY_WOKENUP	1
+#define NOTIFY_REMOVED	2
+
+#endif
--- diff/include/linux/netpoll.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/netpoll.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,38 @@
+/*
+ * Common code for low-level network console, dump, and debugger code
+ *
+ * Derived from netconsole, kgdb-over-ethernet, and netdump patches
+ */
+
+#ifndef _LINUX_NETPOLL_H
+#define _LINUX_NETPOLL_H
+
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+
+struct netpoll;
+
+struct netpoll {
+	struct net_device *dev;
+	char dev_name[16], *name;
+	void (*rx_hook)(struct netpoll *, int, char *, int);
+	u32 local_ip, remote_ip;
+	u16 local_port, remote_port;
+	unsigned char local_mac[6], remote_mac[6];
+	struct list_head rx_list;
+};
+
+void netpoll_poll(struct netpoll *np);
+void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb);
+void netpoll_send_udp(struct netpoll *np, const char *msg, int len);
+int netpoll_parse_options(struct netpoll *np, char *opt);
+int netpoll_setup(struct netpoll *np);
+int netpoll_trap(void);
+void netpoll_set_trap(int trap);
+void netpoll_cleanup(struct netpoll *np);
+int netpoll_rx(struct sk_buff *skb);
+
+
+#endif
--- diff/include/linux/stop_machine.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/stop_machine.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,52 @@
+#ifndef _LINUX_STOP_MACHINE
+#define _LINUX_STOP_MACHINE
+/* "Bogolock": stop the entire machine, disable interrupts.  This is a
+   very heavy lock, which is equivalent to grabbing every spinlock
+   (and more).  So the "read" side to such a lock is anything which
+   diables preeempt. */
+#include <linux/config.h>
+#include <linux/cpu.h>
+#include <asm/system.h>
+
+#ifdef CONFIG_SMP
+/**
+ * stop_machine_run: freeze the machine on all CPUs and run this function
+ * @fn: the function to run
+ * @data: the data ptr for the @fn()
+ * @cpu: the cpu to run @fn() on (or any, if @cpu == NR_CPUS.
+ *
+ * Description: This causes a thread to be scheduled on every other cpu,
+ * each of which disables interrupts, and finally interrupts are disabled
+ * on the current CPU.  The result is that noone is holding a spinlock
+ * or inside any other preempt-disabled region when @fn() runs.
+ *
+ * This can be thought of as a very heavy write lock, equivalent to
+ * grabbing every spinlock in the kernel. */
+int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu);
+
+/**
+ * __stop_machine_run: freeze the machine on all CPUs and run this function
+ * @fn: the function to run
+ * @data: the data ptr for the @fn
+ * @cpu: the cpu to run @fn on (or any, if @cpu == NR_CPUS.
+ *
+ * Description: This is a special version of the above, which returns the
+ * thread which has run @fn(): kthread_stop will return the return value
+ * of @fn().  Used by hotplug cpu.
+ */
+struct task_struct *__stop_machine_run(int (*fn)(void *), void *data,
+				       unsigned int cpu);
+
+#else
+
+static inline int stop_machine_run(int (*fn)(void *), void *data,
+				   unsigned int cpu)
+{
+	int ret;
+	local_irq_disable();
+	ret = fn(data);
+	local_irq_enable();
+	return ret;
+}
+#endif /* CONFIG_SMP */
+#endif /* _LINUX_STOP_MACHINE */
--- diff/include/net/af_ipmi.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/net/af_ipmi.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,59 @@
+/*
+ * IPMI Socket Glue
+ *
+ * Author:	Louis Zhuang <louis.zhuang@linux.intel.com>
+ * Copyright by Intel Corp., 2003
+ */
+#ifndef _NET_IPMI_H
+#define _NET_IPMI_H
+
+#include <linux/ipmi.h>
+
+/*
+ * This is ipmi address for socket
+ */
+struct sockaddr_ipmi {
+	sa_family_t      sipmi_family; /* AF_IPMI */
+	int              if_num; /* IPMI interface number */
+	struct ipmi_addr ipmi_addr;
+};
+#define SOCKADDR_IPMI_OVERHEAD (sizeof(struct sockaddr_ipmi) \
+				- sizeof(struct ipmi_addr))
+
+/* A msg_control item, this takes a 'struct ipmi_timing_parms' */
+#define IPMI_CMSG_TIMING_PARMS	0x01
+
+/*
+ * This is ipmi message for socket
+ */
+struct ipmi_sock_msg {
+	int                   recv_type;
+	long                  msgid;
+
+	unsigned char         netfn;
+	unsigned char         cmd;
+	int                   data_len;
+	unsigned char         data[0];
+};
+
+#define IPMI_MAX_SOCK_MSG_LENGTH (sizeof(struct ipmi_sock_msg)+IPMI_MAX_MSG_LENGTH)
+
+/* Register/unregister to receive specific commands.  Uses struct
+   ipmi_cmdspec from linux/ipmi.h */
+#define SIOCIPMIREGCMD		(SIOCPROTOPRIVATE + 0)
+#define SIOCIPMIUNREGCMD	(SIOCPROTOPRIVATE + 1)
+
+/* Register to receive events.  Takes an integer */
+#define SIOCIPMIGETEVENT	(SIOCPROTOPRIVATE + 2)
+
+/* Set the default timing parameters for the socket.  Takes a struct
+   ipmi_timing_parms from linux/ipmi.h */
+#define SIOCIPMISETTIMING	(SIOCPROTOPRIVATE + 3)
+#define SIOCIPMIGETTIMING	(SIOCPROTOPRIVATE + 4)
+
+/* Set/Get the IPMB address of the MC we are connected to, takes an
+   unsigned int. */
+#define SIOCIPMISETADDR		(SIOCPROTOPRIVATE + 5)
+#define SIOCIPMIGETADDR		(SIOCPROTOPRIVATE + 6)
+
+#endif/*_NET_IPMI_H*/
--- diff/include/scsi/scsi_transport.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/scsi/scsi_transport.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,41 @@
+/* 
+ *  Transport specific attributes.
+ *
+ *  Copyright (c) 2003 Silicon Graphics, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef SCSI_TRANSPORT_H
+#define SCSI_TRANSPORT_H
+
+struct scsi_transport_template {
+	/* The NULL terminated list of transport attributes
+	 * that should be exported.
+	 */
+	struct class_device_attribute **attrs;
+
+	/* The transport class that the device is in */
+	struct class *class;
+
+	/* Constructor/Destructor functions */
+	int (* setup)(struct scsi_device *);
+	void (* cleanup)(struct scsi_device *);
+	/* The size of the specific transport attribute structure (a
+	 * space of this size will be left at the end of the
+	 * scsi_device structure */
+	int	size;
+};
+
+#endif /* SCSI_TRANSPORT_H */
--- diff/include/scsi/scsi_transport_fc.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/scsi/scsi_transport_fc.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,38 @@
+/* 
+ *  FiberChannel transport specific attributes exported to sysfs.
+ *
+ *  Copyright (c) 2003 Silicon Graphics, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef SCSI_TRANSPORT_FC_H
+#define SCSI_TRANSPORT_FC_H
+
+struct scsi_transport_template;
+
+struct fc_transport_attrs {
+	int port_id;
+	uint64_t node_name;
+	uint64_t port_name;
+};
+
+/* accessor functions */
+#define fc_port_id(x)	(((struct fc_transport_attrs *)&(x)->transport_data)->port_id)
+#define fc_node_name(x)	(((struct fc_transport_attrs *)&(x)->transport_data)->node_name)
+#define fc_port_name(x)	(((struct fc_transport_attrs *)&(x)->transport_data)->port_name)
+
+extern struct scsi_transport_template fc_transport_template;
+
+#endif /* SCSI_TRANSPORT_FC_H */
--- diff/include/scsi/scsi_transport_spi.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/scsi/scsi_transport_spi.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,38 @@
+/* 
+ *  Parallel SCSI (SPI) transport specific attributes exported to sysfs.
+ *
+ *  Copyright (c) 2003 Silicon Graphics, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef SCSI_TRANSPORT_SPI_H
+#define SCSI_TRANSPORT_SPI_H
+
+#include <linux/config.h>
+
+struct scsi_transport_template;
+
+struct spi_transport_attrs {
+	int period;
+	int offset;
+};
+
+/* accessor functions */
+#define spi_period(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->period)
+#define spi_offset(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->offset)
+
+extern struct scsi_transport_template spi_transport_template;
+
+#endif /* SCSI_TRANSPORT_SPI_H */
--- diff/include/sound/ak4117.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/sound/ak4117.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,191 @@
+#ifndef __SOUND_AK4117_H
+#define __SOUND_AK4117_H
+
+/*
+ *  Routines for Asahi Kasei AK4117
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>,
+ *
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#define AK4117_REG_PWRDN	0x00	/* power down */
+#define AK4117_REG_CLOCK	0x01	/* clock control */
+#define AK4117_REG_IO		0x02	/* input/output control */
+#define AK4117_REG_INT0_MASK	0x03	/* interrupt0 mask */
+#define AK4117_REG_INT1_MASK	0x04	/* interrupt1 mask */
+#define AK4117_REG_RCS0		0x05	/* receiver status 0 */
+#define AK4117_REG_RCS1		0x06	/* receiver status 1 */
+#define AK4117_REG_RCS2		0x07	/* receiver status 2 */
+#define AK4117_REG_RXCSB0	0x08	/* RX channel status byte 0 */
+#define AK4117_REG_RXCSB1	0x09	/* RX channel status byte 1 */
+#define AK4117_REG_RXCSB2	0x0a	/* RX channel status byte 2 */
+#define AK4117_REG_RXCSB3	0x0b	/* RX channel status byte 3 */
+#define AK4117_REG_RXCSB4	0x0c	/* RX channel status byte 4 */
+#define AK4117_REG_Pc0		0x0d	/* burst preamble Pc byte 0 */
+#define AK4117_REG_Pc1		0x0e	/* burst preamble Pc byte 1 */
+#define AK4117_REG_Pd0		0x0f	/* burst preamble Pd byte 0 */
+#define AK4117_REG_Pd1		0x10	/* burst preamble Pd byte 1 */
+#define AK4117_REG_QSUB_ADDR	0x11	/* Q-subcode address + control */
+#define AK4117_REG_QSUB_TRACK	0x12	/* Q-subcode track */
+#define AK4117_REG_QSUB_INDEX	0x13	/* Q-subcode index */
+#define AK4117_REG_QSUB_MINUTE	0x14	/* Q-subcode minute */
+#define AK4117_REG_QSUB_SECOND	0x15	/* Q-subcode second */
+#define AK4117_REG_QSUB_FRAME	0x16	/* Q-subcode frame */
+#define AK4117_REG_QSUB_ZERO	0x17	/* Q-subcode zero */
+#define AK4117_REG_QSUB_ABSMIN	0x18	/* Q-subcode absolute minute */
+#define AK4117_REG_QSUB_ABSSEC	0x19	/* Q-subcode absolute second */
+#define AK4117_REG_QSUB_ABSFRM	0x1a	/* Q-subcode absolute frame */
+
+/* sizes */
+#define AK4117_REG_RXCSB_SIZE	((AK4117_REG_RXCSB4-AK4117_REG_RXCSB0)+1)
+#define AK4117_REG_QSUB_SIZE	((AK4117_REG_QSUB_ABSFRM-AK4117_REG_QSUB_ADDR)+1)
+
+/* AK4117_REG_PWRDN bits */
+#define AK4117_EXCT		(1<<4)	/* 0 = X'tal mode, 1 = external clock mode */
+#define AK4117_XTL1		(1<<3)	/* XTL1=0,XTL0=0 -> 11.2896Mhz; XTL1=0,XTL0=1 -> 12.288Mhz */
+#define AK4117_XTL0		(1<<2)	/* XTL1=1,XTL0=0 -> 24.576Mhz; XTL1=1,XTL0=1 -> use channel status */
+#define AK4117_XTL_11_2896M	(0)
+#define AK4117_XTL_12_288M	AK4117_XTL0
+#define AK4117_XTL_24_576M	AK4117_XTL1
+#define AK4117_XTL_EXT		(AK4117_XTL1|AK4117_XTL0)
+#define AK4117_PWN		(1<<1)	/* 0 = power down, 1 = normal operation */
+#define AK4117_RST		(1<<0)	/* 0 = reset & initialize (except this register), 1 = normal operation */
+
+/* AK4117_REQ_CLOCK bits */
+#define AK4117_LP		(1<<7)	/* 0 = normal mode, 1 = low power mode (Fs up to 48kHz only) */
+#define AK4117_PKCS1		(1<<6)	/* master clock frequency at PLL mode (when LP == 0) */
+#define AK4117_PKCS0		(1<<5)
+#define AK4117_PKCS_512fs	(0)
+#define AK4117_PKCS_256fs	AK4117_PKCS0
+#define AK4117_PKCS_128fs	AK4117_PKCS1
+#define AK4117_DIV		(1<<4)	/* 0 = MCKO == Fs, 1 = MCKO == Fs / 2; X'tal mode only */
+#define AK4117_XCKS1		(1<<3)	/* master clock frequency at X'tal mode */
+#define AK4117_XCKS0		(1<<2)
+#define AK4117_XCKS_128fs	(0)
+#define AK4117_XCKS_256fs	AK4117_XCKS0
+#define AK4117_XCKS_512fs	AK4117_XCKS1
+#define AK4117_XCKS_1024fs	(AK4117_XCKS1|AK4117_XCKS0)
+#define AK4117_CM1		(1<<1)	/* MCKO operation mode select */
+#define AK4117_CM0		(1<<0)
+#define AK4117_CM_PLL		(0)		/* use RX input as master clock */
+#define AK4117_CM_XTAL		(AK4117_CM0)	/* use X'tal as master clock */
+#define AK4117_CM_PLL_XTAL	(AK4117_CM1)	/* use Rx input but X'tal when PLL loses lock */
+#define AK4117_CM_MONITOR	(AK4117_CM0|AK4117_CM1) /* use X'tal as master clock, but use PLL for monitoring */
+
+/* AK4117_REG_IO */
+#define AK4117_IPS		(1<<7)	/* Input Recovery Data Select, 0 = RX0, 1 = RX1 */
+#define AK4117_UOUTE		(1<<6)	/* U-bit output enable to UOUT, 0 = disable, 1 = enable */
+#define AK4117_CS12		(1<<5)	/* channel status select, 0 = channel1, 1 = channel2 */
+#define AK4117_EFH2		(1<<4)	/* INT0 pin hold count select */
+#define AK4117_EFH1		(1<<3)
+#define AK4117_EFH_512LRCLK	(0)
+#define AK4117_EFH_1024LRCLK	(AK4117_EFH1)
+#define AK4117_EFH_2048LRCLK	(AK4117_EFH2)
+#define AK4117_EFH_4096LRCLK	(AK4117_EFH1|AK4117_EFH2)
+#define AK4117_DIF2		(1<<2)	/* audio data format control */
+#define AK4117_DIF1		(1<<1)
+#define AK4117_DIF0		(1<<0)
+#define AK4117_DIF_16R		(0)				/* STDO: 16-bit, right justified */
+#define AK4117_DIF_18R		(AK4117_DIF0)			/* STDO: 18-bit, right justified */
+#define AK4117_DIF_20R		(AK4117_DIF1)			/* STDO: 20-bit, right justified */
+#define AK4117_DIF_24R		(AK4117_DIF1|AK4117_DIF0)	/* STDO: 24-bit, right justified */
+#define AK4117_DIF_24L		(AK4117_DIF2)			/* STDO: 24-bit, left justified */
+#define AK4117_DIF_24I2S	(AK4117_DIF2|AK4117_DIF0)	/* STDO: I2S */
+
+/* AK4117_REG_INT0_MASK & AK4117_INT1_MASK */
+#define AK4117_MULK		(1<<7)	/* mask enable for UNLOCK bit */
+#define AK4117_MPAR		(1<<6)	/* mask enable for PAR bit */
+#define AK4117_MAUTO		(1<<5)	/* mask enable for AUTO bit */
+#define AK4117_MV		(1<<4)	/* mask enable for V bit */
+#define AK4117_MAUD		(1<<3)	/* mask enable for AUDION bit */
+#define AK4117_MSTC		(1<<2)	/* mask enable for STC bit */
+#define AK4117_MCIT		(1<<1)	/* mask enable for CINT bit */
+#define AK4117_MQIT		(1<<0)	/* mask enable for QINT bit */
+
+/* AK4117_REG_RCS0 */
+#define AK4117_UNLCK		(1<<7)	/* PLL lock status, 0 = lock, 1 = unlock */
+#define AK4117_PAR		(1<<6)	/* parity error or biphase error status, 0 = no error, 1 = error */
+#define AK4117_AUTO		(1<<5)	/* Non-PCM or DTS stream auto detection, 0 = no detect, 1 = detect */
+#define AK4117_V		(1<<4)	/* Validity bit, 0 = valid, 1 = invalid */
+#define AK4117_AUDION		(1<<3)	/* audio bit output, 0 = audio, 1 = non-audio */
+#define AK4117_STC		(1<<2)	/* sampling frequency or Pre-emphasis change, 0 = no detect, 1 = detect */
+#define AK4117_CINT		(1<<1)	/* channel status buffer interrupt, 0 = no change, 1 = change */
+#define AK4117_QINT		(1<<0)	/* Q-subcode buffer interrupt, 0 = no change, 1 = changed */
+
+/* AK4117_REG_RCS1 */
+#define AK4117_DTSCD		(1<<6)	/* DTS-CD bit audio stream detect, 0 = no detect, 1 = detect */
+#define AK4117_NPCM		(1<<5)	/* Non-PCM bit stream detection, 0 = no detect, 1 = detect */
+#define AK4117_PEM		(1<<4)	/* Pre-emphasis detect, 0 = OFF, 1 = ON */
+#define AK4117_FS3		(1<<3)	/* sampling frequency detection */
+#define AK4117_FS2		(1<<2)
+#define AK4117_FS1		(1<<1)
+#define AK4117_FS0		(1<<0)
+#define AK4117_FS_44100HZ	(0)
+#define AK4117_FS_48000HZ	(AK4117_FS1)
+#define AK4117_FS_32000HZ	(AK4117_FS1|AK4117_FS0)
+#define AK4117_FS_88200HZ	(AK4117_FS3)
+#define AK4117_FS_96000HZ	(AK4117_FS3|AK4117_FS1)
+#define AK4117_FS_176400HZ	(AK4117_FS3|AK4117_FS2)
+#define AK4117_FS_192000HZ	(AK4117_FS3|AK4117_FS2|AK4117_FS1)
+
+/* AK4117_REG_RCS2 */
+#define AK4117_CCRC		(1<<1)	/* CRC for channel status, 0 = no error, 1 = error */
+#define AK4117_QCRC		(1<<0)	/* CRC for Q-subcode, 0 = no error, 1 = error */
+
+/* flags for snd_ak4117_check_rate_and_errors() */
+#define AK4117_CHECK_NO_STAT	(1<<0)	/* no statistics */
+#define AK4117_CHECK_NO_RATE	(1<<1)	/* no rate check */
+
+#define AK4117_CONTROLS		13
+
+typedef void (ak4117_write_t)(void *private_data, unsigned char addr, unsigned char data);
+typedef unsigned char (ak4117_read_t)(void *private_data, unsigned char addr);
+
+typedef struct ak4117 ak4117_t;
+
+struct ak4117 {
+	snd_card_t * card;
+	ak4117_write_t * write;
+	ak4117_read_t * read;
+	void * private_data;
+	unsigned int init: 1;
+	spinlock_t lock;
+	unsigned char regmap[5];
+	snd_kcontrol_t *kctls[AK4117_CONTROLS];
+	snd_pcm_substream_t *substream;
+	unsigned long parity_errors;
+	unsigned long v_bit_errors;
+	unsigned long qcrc_errors;
+	unsigned long ccrc_errors;
+	unsigned char rcs0;
+	unsigned char rcs1;
+	unsigned char rcs2;
+	struct timer_list timer;	/* statistic timer */
+	void *change_callback_private;
+	void (*change_callback)(ak4117_t *ak4117, unsigned char c0, unsigned char c1);
+};
+
+int snd_ak4117_create(snd_card_t *card, ak4117_read_t *read, ak4117_write_t *write,
+		      unsigned char pgm[5], void *private_data, ak4117_t **r_ak4117);
+void snd_ak4117_reg_write(ak4117_t *chip, unsigned char reg, unsigned char mask, unsigned char val);
+void snd_ak4117_reinit(ak4117_t *chip);
+int snd_ak4117_build(ak4117_t *ak4117, snd_pcm_substream_t *capture_substream);
+int snd_ak4117_external_rate(ak4117_t *ak4117);
+int snd_ak4117_check_rate_and_errors(ak4117_t *ak4117, unsigned int flags);
+
+#endif /* __SOUND_AK4117_H */
+
--- diff/ipc/compat.c	1970-01-01 01:00:00.000000000 +0100
+++ source/ipc/compat.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,734 @@
+/*
+ * 32 bit compatibility code for System V IPC
+ *
+ * Copyright (C) 1997,1998	Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997		David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1999		Arun Sharma <arun.sharma@intel.com>
+ * Copyright (C) 2000		VA Linux Co
+ * Copyright (C) 2000		Don Dugger <n0ano@valinux.com>
+ * Copyright (C) 2000           Hewlett-Packard Co.
+ * Copyright (C) 2000           David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 2000           Gerhard Tonn (ton@de.ibm.com)
+ * Copyright (C) 2000-2002      Andi Kleen, SuSE Labs (x86-64 port)
+ * Copyright (C) 2000		Silicon Graphics, Inc.
+ * Copyright (C) 2001		IBM
+ * Copyright (C) 2004		IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright (C) 2004		Arnd Bergmann (arnd@arndb.de)
+ *
+ * This code is collected from the versions for sparc64, mips64, s390x, ia64,
+ * ppc64 and x86_64, all of which are based on the original sparc64 version
+ * by Jakub Jelinek.
+ *
+ */
+#include <linux/compat.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/highuid.h>
+#include <linux/init.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include "util.h"
+
+struct compat_msgbuf {
+	compat_long_t mtype;
+	char mtext[1];
+};
+
+struct compat_ipc_perm {
+	key_t key;
+	compat_uid_t uid;
+	compat_gid_t gid;
+	compat_uid_t cuid;
+	compat_gid_t cgid;
+	compat_mode_t mode;
+	unsigned short seq;
+};
+
+struct compat_semid_ds {
+	struct compat_ipc_perm sem_perm;
+	compat_time_t sem_otime;
+	compat_time_t sem_ctime;
+	compat_uptr_t sem_base;
+	compat_uptr_t sem_pending;
+	compat_uptr_t sem_pending_last;
+	compat_uptr_t undo;
+	unsigned short sem_nsems;
+};
+
+struct compat_msqid_ds {
+	struct compat_ipc_perm msg_perm;
+	compat_uptr_t msg_first;
+	compat_uptr_t msg_last;
+	compat_time_t msg_stime;
+	compat_time_t msg_rtime;
+	compat_time_t msg_ctime;
+	compat_ulong_t msg_lcbytes;
+	compat_ulong_t msg_lqbytes;
+	unsigned short msg_cbytes;
+	unsigned short msg_qnum;
+	unsigned short msg_qbytes;
+	compat_ipc_pid_t msg_lspid;
+	compat_ipc_pid_t msg_lrpid;
+};
+
+struct compat_shmid_ds {
+	struct compat_ipc_perm shm_perm;
+	int shm_segsz;
+	compat_time_t shm_atime;
+	compat_time_t shm_dtime;
+	compat_time_t shm_ctime;
+	compat_ipc_pid_t shm_cpid;
+	compat_ipc_pid_t shm_lpid;
+	unsigned short shm_nattch;
+	unsigned short shm_unused;
+	compat_uptr_t shm_unused2;
+	compat_uptr_t shm_unused3;
+};
+
+struct compat_ipc_kludge {
+	compat_uptr_t msgp;
+	compat_long_t msgtyp;
+};
+
+struct compat_shminfo64 {
+	compat_ulong_t shmmax;
+	compat_ulong_t shmmin;
+	compat_ulong_t shmmni;
+	compat_ulong_t shmseg;
+	compat_ulong_t shmall;
+	compat_ulong_t __unused1;
+	compat_ulong_t __unused2;
+	compat_ulong_t __unused3;
+	compat_ulong_t __unused4;
+};
+
+struct compat_shm_info {
+	compat_int_t used_ids;
+	compat_ulong_t shm_tot, shm_rss, shm_swp;
+	compat_ulong_t swap_attempts, swap_successes;
+};
+
+extern int sem_ctls[];
+#define sc_semopm	(sem_ctls[2])
+#define MAXBUF (64*1024)
+
+static inline int compat_ipc_parse_version(int *cmd)
+{
+	int version = *cmd & IPC_64;
+
+	/* this is tricky: architectures that have support for the old
+	 * ipc structures in 64 bit binaries need to have IPC_64 set
+	 * in cmd, the others need to have it cleared */
+#ifndef ipc_parse_version
+	*cmd |= IPC_64;
+#else
+	*cmd &= ~IPC_64;
+#endif
+	return version;
+}
+
+static inline int __get_compat_ipc64_perm(struct ipc64_perm *p64,
+					  struct compat_ipc64_perm *up64)
+{
+	int err;
+
+	err  = __get_user(p64->uid, &up64->uid);
+	err |= __get_user(p64->gid, &up64->gid);
+	err |= __get_user(p64->mode, &up64->mode);
+	return err;
+}
+
+static inline int __get_compat_ipc_perm(struct ipc64_perm *p,
+					struct compat_ipc_perm *up)
+{
+	int err;
+
+	err  = __get_user(p->uid, &up->uid);
+	err |= __get_user(p->gid, &up->gid);
+	err |= __get_user(p->mode, &up->mode);
+	return err;
+}
+
+static inline int __put_compat_ipc64_perm(struct ipc64_perm *p64,
+					  struct compat_ipc64_perm *up64)
+{
+	int err;
+
+	err  = __put_user(p64->key, &up64->key);
+	err |= __put_user(p64->uid, &up64->uid);
+	err |= __put_user(p64->gid, &up64->gid);
+	err |= __put_user(p64->cuid, &up64->cuid);
+	err |= __put_user(p64->cgid, &up64->cgid);
+	err |= __put_user(p64->mode, &up64->mode);
+	err |= __put_user(p64->seq, &up64->seq);
+	return err;
+}
+
+static inline int __put_compat_ipc_perm(struct ipc64_perm *p,
+					struct compat_ipc_perm *up)
+{
+	int err;
+	compat_uid_t u;
+	compat_gid_t g;
+
+	err  = __put_user(p->key, &up->key);
+	SET_UID(u, p->uid);
+	err |= __put_user(u, &up->uid);
+	SET_GID(g, p->gid);
+	err |= __put_user(g, &up->gid);
+	SET_UID(u, p->cuid);
+	err |= __put_user(u, &up->cuid);
+	SET_GID(g, p->cgid);
+	err |= __put_user(g, &up->cgid);
+	err |= __put_user(p->mode, &up->mode);
+	err |= __put_user(p->seq, &up->seq);
+	return err;
+}
+
+static inline int get_compat_semid64_ds(struct semid64_ds *s64,
+					struct compat_semid64_ds *up64)
+{
+	if (!access_ok (VERIFY_READ, up64, sizeof(*up64)))
+		return -EFAULT;
+	return __get_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm);
+}
+
+static inline int get_compat_semid_ds(struct semid64_ds *s,
+				      struct compat_semid_ds *up)
+{
+	if (!access_ok (VERIFY_READ, up, sizeof(*up)))
+		return -EFAULT;
+	return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
+}
+
+static inline int put_compat_semid64_ds(struct semid64_ds *s64,
+					struct compat_semid64_ds *up64)
+{
+	int err;
+
+	if (!access_ok (VERIFY_WRITE, up64, sizeof(*up64)))
+		return -EFAULT;
+	err  = __put_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm);
+	err |= __put_user(s64->sem_otime, &up64->sem_otime);
+	err |= __put_user(s64->sem_ctime, &up64->sem_ctime);
+	err |= __put_user(s64->sem_nsems, &up64->sem_nsems);
+	return err;
+}
+
+static inline int put_compat_semid_ds(struct semid64_ds *s,
+				      struct compat_semid_ds *up)
+{
+	int err;
+
+	if (!access_ok (VERIFY_WRITE, up, sizeof(*up)))
+		err = -EFAULT;
+	err  = __put_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
+	err |= __put_user(s->sem_otime, &up->sem_otime);
+	err |= __put_user(s->sem_ctime, &up->sem_ctime);
+	err |= __put_user(s->sem_nsems, &up->sem_nsems);
+	return err;
+}
+
+static inline int do_semctl(int semid, int semnum, int cmd, union semun arg)
+{
+	mm_segment_t old_fs;
+	int err;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_semctl(semid, semnum, cmd, arg);
+	set_fs(old_fs);
+
+	return err;
+}
+long compat_sys_semctl(int first, int second, int third, void __user *uptr)
+{
+	union semun fourth;
+	u32 pad;
+	int err, err2;
+	struct semid64_ds s64;
+	int version = compat_ipc_parse_version(&third);
+
+	if (!uptr)
+		return -EINVAL;
+	if (get_user(pad, (u32 __user *) uptr))
+		return -EFAULT;
+	if ((third & (~IPC_64)) == SETVAL)
+		fourth.val = (int) pad;
+	else
+		fourth.__pad = compat_ptr(pad);
+	switch (third & (~IPC_64)) {
+	case IPC_INFO:
+	case IPC_RMID:
+	case SEM_INFO:
+	case GETVAL:
+	case GETPID:
+	case GETNCNT:
+	case GETZCNT:
+	case GETALL:
+	case SETVAL:
+	case SETALL:
+		err = sys_semctl(first, second, third, fourth);
+		break;
+
+	case IPC_STAT:
+	case SEM_STAT:
+		fourth.__pad = &s64;
+		err = do_semctl(first, second, third, fourth);
+		if (err < 0)
+			break;
+
+		if (version == IPC_64) {
+			err2 = put_compat_semid64_ds(&s64, compat_ptr(pad));
+		} else {
+			err2 = put_compat_semid_ds(&s64, compat_ptr(pad));
+		}
+		if (err2)
+			err = -EFAULT;
+		break;
+
+	case IPC_SET:
+		if (version == IPC_64) {
+			err = get_compat_semid64_ds(&s64, compat_ptr(pad));
+		} else {
+			err = get_compat_semid_ds(&s64, compat_ptr(pad));
+		}
+		if (err)
+			break;
+
+		fourth.__pad = &s64;
+		err = do_semctl(first, second, third, fourth);
+		break;
+
+	default:
+		err = -EINVAL;
+		break;
+	}
+	return err;
+}
+
+long compat_sys_msgsnd(int first, int second, int third, void __user *uptr)
+{
+	struct msgbuf *p;
+	struct compat_msgbuf __user *up;
+	mm_segment_t old_fs;
+	int err;
+
+	if (first < 0)
+		return -EINVAL;
+	if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf)))
+		return -EINVAL;
+
+	p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
+	if (!p)
+		return -ENOMEM;
+	err = -EFAULT;
+	up = uptr;
+	if (get_user(p->mtype, &up->mtype) ||
+	    copy_from_user(p->mtext, &up->mtext, second))
+		goto out;
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_msgsnd(first, p, second, third);
+	set_fs(old_fs);
+out:
+	kfree(p);
+	return err;
+}
+
+long compat_sys_msgrcv(int first, int second, int msgtyp, int third,
+			   int version, void __user *uptr)
+{
+	struct msgbuf *p;
+	struct compat_msgbuf __user *up;
+	mm_segment_t old_fs;
+	int err;
+
+	if (first < 0)
+		return -EINVAL;
+	if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf)))
+		return -EINVAL;
+
+	if (!version) {
+		struct compat_ipc_kludge __user *uipck = uptr;
+		struct compat_ipc_kludge ipck;
+
+		err = -EINVAL;
+		if (!uptr)
+			goto out;
+		err = -EFAULT;
+		if (copy_from_user (&ipck, uipck, sizeof(ipck)))
+			goto out;
+		uptr = compat_ptr(ipck.msgp);
+		msgtyp = ipck.msgtyp;
+	}
+	err = -ENOMEM;
+	p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
+	if (!p)
+		goto out;
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_msgrcv(first, p, second, msgtyp, third);
+	set_fs(old_fs);
+	if (err < 0)
+		goto free_then_out;
+	up = uptr;
+	if (put_user(p->mtype, &up->mtype) ||
+	    __copy_to_user(&up->mtext, p->mtext, err))
+		err = -EFAULT;
+free_then_out:
+	kfree(p);
+out:
+	return err;
+}
+
+static inline int get_compat_msqid64(struct msqid64_ds *m64,
+				     struct compat_msqid64_ds __user *up64)
+{
+	int err;
+
+	if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
+		return -EFAULT;
+	err  = __get_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
+	err |= __get_user(m64->msg_qbytes, &up64->msg_qbytes);
+	return err;
+}
+
+static inline int get_compat_msqid(struct msqid64_ds *m,
+				   struct compat_msqid_ds __user *up)
+{
+	int err;
+
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)))
+		return -EFAULT;
+	err  = __get_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
+	err |= __get_user(m->msg_qbytes, &up->msg_qbytes);
+	return err;
+}
+
+static inline int put_compat_msqid64_ds(struct msqid64_ds *m64,
+				 struct compat_msqid64_ds __user __user *up64)
+{
+	int err;
+
+	if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
+		return -EFAULT;
+	err  = __put_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
+	err |= __put_user(m64->msg_stime, &up64->msg_stime);
+	err |= __put_user(m64->msg_rtime, &up64->msg_rtime);
+	err |= __put_user(m64->msg_ctime, &up64->msg_ctime);
+	err |= __put_user(m64->msg_cbytes, &up64->msg_cbytes);
+	err |= __put_user(m64->msg_qnum, &up64->msg_qnum);
+	err |= __put_user(m64->msg_qbytes, &up64->msg_qbytes);
+	err |= __put_user(m64->msg_lspid, &up64->msg_lspid);
+	err |= __put_user(m64->msg_lrpid, &up64->msg_lrpid);
+	return err;
+}
+
+static inline int put_compat_msqid_ds(struct msqid64_ds *m,
+				      struct compat_msqid_ds __user *up)
+{
+	int err;
+
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
+		return -EFAULT;
+	err  = __put_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
+	err |= __put_user(m->msg_stime, &up->msg_stime);
+	err |= __put_user(m->msg_rtime, &up->msg_rtime);
+	err |= __put_user(m->msg_ctime, &up->msg_ctime);
+	err |= __put_user(m->msg_cbytes, &up->msg_cbytes);
+	err |= __put_user(m->msg_qnum, &up->msg_qnum);
+	err |= __put_user(m->msg_qbytes, &up->msg_qbytes);
+	err |= __put_user(m->msg_lspid, &up->msg_lspid);
+	err |= __put_user(m->msg_lrpid, &up->msg_lrpid);
+	return err;
+}
+
+static inline int do_msgctl(int first, int second, void __user *buf)
+{
+	mm_segment_t old_fs;
+	int err;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_msgctl(first, second, buf);
+	set_fs(old_fs);
+
+	return err;
+}
+
+long compat_sys_msgctl(int first, int second, void __user *uptr)
+{
+	int err, err2;
+	struct msqid64_ds m64;
+	int version = compat_ipc_parse_version(&second);
+
+	switch (second & (~IPC_64)) {
+	case IPC_INFO:
+	case IPC_RMID:
+	case MSG_INFO:
+		err = sys_msgctl(first, second, uptr);
+		break;
+
+	case IPC_SET:
+		if (version == IPC_64) {
+			err = get_compat_msqid64(&m64, uptr);
+		} else {
+			err = get_compat_msqid(&m64, uptr);
+		}
+		if (err)
+			break;
+
+		err = do_msgctl(first, second, &m64);
+		break;
+
+	case IPC_STAT:
+	case MSG_STAT:
+		err = do_msgctl(first, second, &m64);
+		if (err < 0)
+			break;
+
+		if (version == IPC_64) {
+			err2 = put_compat_msqid64_ds(&m64, uptr);
+		} else {
+			err2 = put_compat_msqid_ds(&m64, uptr);
+		}
+		if (err2)
+			err = -EFAULT;
+		break;
+
+	default:
+		err = -EINVAL;
+		break;
+	}
+	return err;
+}
+
+long compat_sys_shmat(int first, int second, compat_uptr_t third, int version,
+			void __user *uptr)
+{
+	int err;
+	unsigned long raddr;
+	compat_ulong_t __user *uaddr;
+
+	if (version == 1)
+		return -EINVAL;
+	err = do_shmat(first, uptr, second, &raddr);
+	if (err < 0)
+		return err;
+	uaddr = compat_ptr(third);
+	return put_user(raddr, uaddr);
+}
+
+static inline int get_compat_shmid64_ds(struct shmid64_ds *s64,
+					struct compat_shmid64_ds __user *up64)
+{
+	if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
+		return -EFAULT;
+	return __get_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm);
+}
+
+static inline int get_compat_shmid_ds(struct shmid64_ds *s,
+				      struct compat_shmid_ds __user *up)
+{
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)))
+		return -EFAULT;
+	return __get_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
+}
+
+static inline int put_compat_shmid64_ds(struct shmid64_ds *s64,
+					struct compat_shmid64_ds __user *up64)
+{
+	int err;
+
+	if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
+		return -EFAULT;
+	err  = __put_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm);
+	err |= __put_user(s64->shm_atime, &up64->shm_atime);
+	err |= __put_user(s64->shm_dtime, &up64->shm_dtime);
+	err |= __put_user(s64->shm_ctime, &up64->shm_ctime);
+	err |= __put_user(s64->shm_segsz, &up64->shm_segsz);
+	err |= __put_user(s64->shm_nattch, &up64->shm_nattch);
+	err |= __put_user(s64->shm_cpid, &up64->shm_cpid);
+	err |= __put_user(s64->shm_lpid, &up64->shm_lpid);
+	return err;
+}
+
+static inline int put_compat_shmid_ds(struct shmid64_ds *s,
+				      struct compat_shmid_ds __user *up)
+{
+	int err;
+
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
+		return -EFAULT;
+	err  = __put_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
+	err |= __put_user(s->shm_atime, &up->shm_atime);
+	err |= __put_user(s->shm_dtime, &up->shm_dtime);
+	err |= __put_user(s->shm_ctime, &up->shm_ctime);
+	err |= __put_user(s->shm_segsz, &up->shm_segsz);
+	err |= __put_user(s->shm_nattch, &up->shm_nattch);
+	err |= __put_user(s->shm_cpid, &up->shm_cpid);
+	err |= __put_user(s->shm_lpid, &up->shm_lpid);
+	return err;
+}
+
+static inline int put_compat_shminfo64(struct shminfo64 *smi,
+				       struct compat_shminfo64 __user *up64)
+{
+	int err;
+
+	if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
+		return -EFAULT;
+	err  = __put_user(smi->shmmax, &up64->shmmax);
+	err |= __put_user(smi->shmmin, &up64->shmmin);
+	err |= __put_user(smi->shmmni, &up64->shmmni);
+	err |= __put_user(smi->shmseg, &up64->shmseg);
+	err |= __put_user(smi->shmall, &up64->shmall);
+	return err;
+}
+
+static inline int put_compat_shminfo(struct shminfo64 *smi,
+				     struct shminfo __user *up)
+{
+	int err;
+
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
+		return -EFAULT;
+	err  = __put_user(smi->shmmax, &up->shmmax);
+	err |= __put_user(smi->shmmin, &up->shmmin);
+	err |= __put_user(smi->shmmni, &up->shmmni);
+	err |= __put_user(smi->shmseg, &up->shmseg);
+	err |= __put_user(smi->shmall, &up->shmall);
+}
+
+static inline int put_compat_shm_info(struct shm_info *si,
+				      struct compat_shm_info __user *uip)
+{
+	int err;
+
+	if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)))
+		return -EFAULT;
+	err  = __put_user(si->used_ids, &uip->used_ids);
+	err |= __put_user(si->shm_tot, &uip->shm_tot);
+	err |= __put_user(si->shm_rss, &uip->shm_rss);
+	err |= __put_user(si->shm_swp, &uip->shm_swp);
+	err |= __put_user(si->swap_attempts, &uip->swap_attempts);
+	err |= __put_user(si->swap_successes, &uip->swap_successes);
+	return err;
+}
+
+static inline int do_shmctl(int shmid, int cmd, void *buf)
+{
+	mm_segment_t old_fs;
+	int err;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_shmctl(shmid, cmd, buf);
+	set_fs(old_fs);
+
+	return err;
+}
+
+long compat_sys_shmctl(int first, int second, void __user *uptr)
+{
+	struct shmid64_ds s64;
+	struct shminfo64 smi;
+	struct shm_info si;
+	int err, err2;
+	int version = compat_ipc_parse_version(&second);
+
+	switch (second & (~IPC_64)) {
+	case IPC_RMID:
+	case SHM_LOCK:
+	case SHM_UNLOCK:
+		err = sys_shmctl(first, second, uptr);
+		break;
+
+	case IPC_INFO:
+		err = do_shmctl(first, second, &smi);
+		if (err < 0)
+			break;
+
+		if (version == IPC_64) {
+			err2 = put_compat_shminfo64(&smi, uptr);
+		} else {
+			err2 = put_compat_shminfo(&smi, uptr);
+		}
+		if (err2)
+			err = -EFAULT;
+		break;
+
+
+	case IPC_SET:
+		if (version == IPC_64) {
+			err = get_compat_shmid64_ds(&s64, uptr);
+		} else {
+			err = get_compat_shmid_ds(&s64, uptr);
+		}
+		if (err)
+			break;
+
+		err = do_shmctl(first, second, &s64);
+		break;
+
+	case IPC_STAT:
+	case SHM_STAT:
+		err = do_shmctl(first, second, &s64);
+		if (err < 0)
+			break;
+
+		if (version == IPC_64) {
+			err2 = put_compat_shmid64_ds(&s64, uptr);
+		} else {
+			err2 = put_compat_shmid_ds(&s64, uptr);
+		}
+		if (err2)
+			err = -EFAULT;
+		break;
+
+	case SHM_INFO:
+		err = do_shmctl(first, second, &si);
+		if (err < 0)
+			break;
+		err2 = put_compat_shm_info(&si, uptr);
+		if (err2)
+			err = -EFAULT;
+		break;
+
+	default:
+		err = -EINVAL;
+		break;
+	}
+	return err;
+}
+
+long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
+		unsigned nsops, const struct compat_timespec __user *timeout)
+{
+	struct timespec ts, __user *ts64;
+
+	/* parameter checking precedence should mirror sys_semtimedop() */
+	if (nsops < 1 || semid < 0)
+		return -EINVAL;
+	if (nsops > sc_semopm)
+		return -E2BIG;
+	if (!access_ok(VERIFY_READ, tsems, nsops * sizeof(struct sembuf)))
+		return -EFAULT;
+	if (!timeout)
+		return sys_semtimedop(semid, tsems, nsops, 0);
+
+	ts64 = compat_alloc_user_space(sizeof(*ts64));
+	if (get_compat_timespec(&ts, timeout))
+		return -EFAULT;
+	if (copy_to_user(ts64, &ts, sizeof(ts)))
+		return -EFAULT;
+
+	return sys_semtimedop(semid, tsems, nsops, ts64);
+}
--- diff/ipc/mqueue.c	1970-01-01 01:00:00.000000000 +0100
+++ source/ipc/mqueue.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,1256 @@
+/*
+ * POSIX message queues filesystem for Linux.
+ *
+ * Copyright (C) 2003,2004  Krzysztof Benedyczak    (golbi@mat.uni.torun.pl)
+ *                          Michal Wronski          (wrona@mat.uni.torun.pl)
+ *
+ * Spinlocks:               Mohamed Abbas           (abbas.mohamed@intel.com)
+ * Lockless receive & send, fd based notify:
+ * 			    Manfred Spraul	    (manfred@colorfullife.com)
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/init.h>
+#include <linux/pagemap.h>
+#include <linux/file.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/sysctl.h>
+#include <linux/poll.h>
+#include <linux/mqueue.h>
+#include <linux/msg.h>
+#include "util.h"
+
+#define MQUEUE_MAGIC	0x19800202
+#define DIRENT_SIZE	20
+#define FILENT_SIZE	80
+
+#define SEND		0
+#define RECV		1
+
+#define STATE_NONE	0
+#define STATE_PENDING	1
+#define STATE_READY	2
+
+#define NP_NONE		((void*)NOTIFY_NONE)
+#define NP_WOKENUP	((void*)NOTIFY_WOKENUP)
+#define NP_REMOVED	((void*)NOTIFY_REMOVED)
+/* used by sysctl */
+#define FS_MQUEUE 	1
+#define CTL_QUEUESMAX 	2
+#define CTL_MSGMAX 	3
+#define CTL_MSGSIZEMAX 	4
+
+/* default values */
+#define DFLT_QUEUESMAX	64	/* max number of message queues */
+#define DFLT_MSGMAX 	40	/* max number of messages in each queue */
+#define HARD_MSGMAX 	(131072/sizeof(void*))
+#define DFLT_MSGSIZEMAX 16384	/* max message size */
+
+struct ext_wait_queue {		/* queue of sleeping tasks */
+	struct task_struct *task;
+	struct list_head list;
+	struct msg_msg *msg;	/* ptr of loaded message */
+	int state;		/* one of STATE_* values */
+};
+
+struct mqueue_inode_info {
+	struct mq_attr attr;
+	struct msg_msg **messages;
+
+	pid_t notify_owner;	/* != 0 means notification registered */
+	struct sigevent notify;
+	struct file *notify_filp;
+
+	/* for tasks waiting for free space and messages, respectively */
+	struct ext_wait_queue e_wait_q[2];
+	wait_queue_head_t wait_q;
+
+	unsigned long qsize; /* size of queue in memory (sum of all msgs) */
+	spinlock_t lock;
+	struct inode vfs_inode;
+};
+
+static struct inode_operations mqueue_dir_inode_operations;
+static struct file_operations mqueue_file_operations;
+static struct file_operations mqueue_notify_fops;
+static struct super_operations mqueue_super_ops;
+static void remove_notification(struct mqueue_inode_info *info);
+
+static spinlock_t mq_lock;
+static kmem_cache_t *mqueue_inode_cachep;
+static struct vfsmount *mqueue_mnt;
+
+static unsigned int queues_count;
+static unsigned int queues_max 	= DFLT_QUEUESMAX;
+static unsigned int msg_max 	= DFLT_MSGMAX;
+static unsigned int msgsize_max = DFLT_MSGSIZEMAX;
+
+static struct ctl_table_header * mq_sysctl_table;
+
+static inline struct mqueue_inode_info *MQUEUE_I(struct inode *inode)
+{
+	return container_of(inode, struct mqueue_inode_info, vfs_inode);
+}
+
+static struct inode *mqueue_get_inode(struct super_block *sb, int mode)
+{
+	struct inode *inode;
+
+	inode = new_inode(sb);
+	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_mtime = inode->i_ctime = inode->i_atime =
+				CURRENT_TIME;
+
+		if (S_ISREG(mode)) {
+			struct mqueue_inode_info *info;
+
+			inode->i_fop = &mqueue_file_operations;
+			inode->i_size = FILENT_SIZE;
+			/* mqueue specific info */
+			info = MQUEUE_I(inode);
+			spin_lock_init(&info->lock);
+			init_waitqueue_head(&info->wait_q);
+			INIT_LIST_HEAD(&info->e_wait_q[0].list);
+			INIT_LIST_HEAD(&info->e_wait_q[1].list);
+			info->notify_owner = 0;
+			info->qsize = 0;
+			memset(&info->attr, 0, sizeof(info->attr));
+			info->attr.mq_maxmsg = DFLT_MSGMAX;
+			info->attr.mq_msgsize = DFLT_MSGSIZEMAX;
+			info->messages = kmalloc(DFLT_MSGMAX * sizeof(struct msg_msg *), GFP_KERNEL);
+			if (!info->messages) {
+				make_bad_inode(inode);
+				iput(inode);
+				inode = NULL;
+			}
+		} else if (S_ISDIR(mode)) {
+			inode->i_nlink++;
+			/* Some things misbehave if size == 0 on a directory */
+			inode->i_size = 2 * DIRENT_SIZE;
+			inode->i_op = &mqueue_dir_inode_operations;
+			inode->i_fop = &simple_dir_operations;
+		}
+	}
+	return inode;
+}
+
+static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
+{
+	struct inode *inode;
+
+	sb->s_blocksize = PAGE_CACHE_SIZE;
+	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+	sb->s_magic = MQUEUE_MAGIC;
+	sb->s_op = &mqueue_super_ops;
+
+	inode = mqueue_get_inode(sb, S_IFDIR | S_IRWXUGO);
+	if (!inode)
+		return -ENOMEM;
+
+	sb->s_root = d_alloc_root(inode);
+	if (!sb->s_root) {
+		iput(inode);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static struct super_block *mqueue_get_sb(struct file_system_type *fs_type,
+					 int flags, const char *dev_name,
+					 void *data)
+{
+	return get_sb_single(fs_type, flags, data, mqueue_fill_super);
+}
+
+static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct mqueue_inode_info *p = (struct mqueue_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
+		SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&p->vfs_inode);
+}
+
+static struct inode *mqueue_alloc_inode(struct super_block *sb)
+{
+	struct mqueue_inode_info *ei;
+
+	ei = kmem_cache_alloc(mqueue_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void mqueue_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(mqueue_inode_cachep, MQUEUE_I(inode));
+}
+
+static void mqueue_delete_inode(struct inode *inode)
+{
+	struct mqueue_inode_info *info;
+	int i;
+
+	if (S_ISDIR(inode->i_mode)) {
+		clear_inode(inode);
+		return;
+	}
+	info = MQUEUE_I(inode);
+	spin_lock(&info->lock);
+	for (i = 0; i < info->attr.mq_curmsgs; i++)
+		free_msg(info->messages[i]);
+	kfree(info->messages);
+	spin_unlock(&info->lock);
+
+	clear_inode(inode);
+
+	spin_lock(&mq_lock);
+	queues_count--;
+	spin_unlock(&mq_lock);
+}
+
+static int mqueue_create(struct inode *dir, struct dentry *dentry,
+				int mode, struct nameidata *nd)
+{
+	struct inode *inode;
+	int error;
+
+	spin_lock(&mq_lock);
+	if (queues_count >= queues_max && !capable(CAP_SYS_RESOURCE)) {
+		error = -ENOSPC;
+		goto out_lock;
+	}
+	queues_count++;
+	spin_unlock(&mq_lock);
+
+	inode = mqueue_get_inode(dir->i_sb, mode);
+	if (!inode) {
+		error = -ENOMEM;
+		spin_lock(&mq_lock);
+		queues_count--;
+		goto out_lock;
+	}
+
+	dir->i_size += DIRENT_SIZE;
+	dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
+
+	d_instantiate(dentry, inode);
+	dget(dentry);
+	return 0;
+out_lock:
+	spin_unlock(&mq_lock);
+	return error;
+}
+
+static int mqueue_unlink(struct inode *dir, struct dentry *dentry)
+{
+  	struct inode *inode = dentry->d_inode;
+
+	dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
+	dir->i_size -= DIRENT_SIZE;
+  	inode->i_nlink--;
+  	dput(dentry);
+  	return 0;
+}
+
+/*
+*	This is routine for system read from queue file.
+*	To avoid mess with doing here some sort of mq_receive we allow
+*	to read only queue size & notification info (the only values
+*	that are interesting from user point of view and aren't accessible
+*	through std routines)
+*/
+static ssize_t mqueue_read_file(struct file *filp, char __user *u_data,
+				size_t count, loff_t * off)
+{
+	struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
+	char buffer[FILENT_SIZE];
+	size_t slen;
+	loff_t o;
+
+	if (!count)
+		return 0;
+
+	spin_lock(&info->lock);
+	snprintf(buffer, sizeof(buffer),
+			"QSIZE:%-10lu NOTIFY:%-5d SIGNO:%-5d NOTIFY_PID:%-6d\n",
+			info->qsize,
+			info->notify_owner ? info->notify.sigev_notify : SIGEV_NONE,
+			(info->notify_owner && info->notify.sigev_notify == SIGEV_SIGNAL ) ?
+				info->notify.sigev_signo : 0,
+			info->notify_owner);
+	spin_unlock(&info->lock);
+	buffer[sizeof(buffer)-1] = '\0';
+	slen = strlen(buffer)+1;
+
+	o = *off;
+	if (o > slen)
+		return 0;
+
+	if (o + count > slen)
+		count = slen - o;
+
+	if (copy_to_user(u_data, buffer + o, count))
+       		return -EFAULT;
+
+	*off = o + count;
+	filp->f_dentry->d_inode->i_atime = filp->f_dentry->d_inode->i_ctime = CURRENT_TIME;
+	return count;
+}
+
+static int mqueue_flush_file(struct file *filp)
+{
+	struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
+
+	spin_lock(&info->lock);
+	if (current->tgid == info->notify_owner)
+		remove_notification(info);
+
+	spin_unlock(&info->lock);
+	return 0;
+}
+
+static unsigned int mqueue_poll_file(struct file *filp, struct poll_table_struct *poll_tab)
+{
+	struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
+	int retval = 0;
+
+	poll_wait(filp, &info->wait_q, poll_tab);
+
+	spin_lock(&info->lock);
+	if (info->attr.mq_curmsgs)
+		retval = POLLIN | POLLRDNORM;
+
+	if (info->attr.mq_curmsgs < info->attr.mq_maxmsg)
+		retval |= POLLOUT | POLLWRNORM;
+	spin_unlock(&info->lock);
+
+	return retval;
+}
+
+/* Adds current to info->e_wait_q[sr] before element with smaller prio */
+static void wq_add(struct mqueue_inode_info *info, int sr,
+			struct ext_wait_queue *ewp)
+{
+	struct ext_wait_queue *walk;
+
+	ewp->task = current;
+
+	list_for_each_entry(walk, &info->e_wait_q[sr].list, list) {
+		if (walk->task->static_prio <= current->static_prio) {
+			list_add_tail(&ewp->list, &walk->list);
+			return;
+		}
+	}
+	list_add_tail(&ewp->list, &info->e_wait_q[sr].list);
+}
+
+/*
+ * Puts current task to sleep. Caller must hold queue lock. After return
+ * lock isn't held.
+ * sr: SEND or RECV
+ */
+static int wq_sleep(struct mqueue_inode_info *info, int sr,
+			long timeout, struct ext_wait_queue *ewp)
+{
+	int retval;
+	signed long time;
+
+	wq_add(info, sr, ewp);
+
+	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		spin_unlock(&info->lock);
+		time = schedule_timeout(timeout);
+
+		while (ewp->state == STATE_PENDING)
+			cpu_relax();
+
+		if (ewp->state == STATE_READY) {
+			retval = 0;
+			goto out;
+		}
+		spin_lock(&info->lock);
+		if (ewp->state == STATE_READY) {
+			retval = 0;
+			goto out_unlock;
+		}
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+		if (time == 0) {
+			retval = -ETIMEDOUT;
+			break;
+		}
+	}
+	list_del(&ewp->list);
+out_unlock:
+	spin_unlock(&info->lock);
+out:
+	return retval;
+}
+
+/*
+ * Returns waiting task that should be serviced first or NULL if none exists
+ */
+static struct ext_wait_queue *wq_get_first_waiter(
+		struct mqueue_inode_info *info, int sr)
+{
+	struct list_head *ptr;
+
+	ptr = info->e_wait_q[sr].list.prev;
+	if (ptr == &info->e_wait_q[sr].list)
+		return NULL;
+	return list_entry(ptr, struct ext_wait_queue, list);
+}
+
+/* Auxiliary functions to manipulate messages' list */
+static void msg_insert(struct msg_msg *ptr, struct mqueue_inode_info *info)
+{
+	int k;
+
+	k = info->attr.mq_curmsgs - 1;
+	while (k >= 0 && info->messages[k]->m_type >= ptr->m_type) {
+		info->messages[k + 1] = info->messages[k];
+		k--;
+	}
+	info->attr.mq_curmsgs++;
+	info->qsize += ptr->m_ts;
+	info->messages[k + 1] = ptr;
+}
+
+static inline struct msg_msg *msg_get(struct mqueue_inode_info *info)
+{
+	info->qsize -= info->messages[--info->attr.mq_curmsgs]->m_ts;
+	return info->messages[info->attr.mq_curmsgs];
+}
+
+/*
+ * The next function is only to split too long sys_mq_timedsend
+ */
+static void __do_notify(struct mqueue_inode_info *info)
+{
+	/* notification
+	 * invoked when there is registered process and there isn't process
+	 * waiting synchronously for message AND state of queue changed from
+	 * empty to not empty. Here we are sure that no one is waiting
+	 * synchronously. */
+	if (info->notify_owner && info->attr.mq_curmsgs == 1) {
+		/* sends signal */
+		if (info->notify.sigev_notify == SIGEV_SIGNAL) {
+			struct siginfo sig_i;
+
+			sig_i.si_signo = info->notify.sigev_signo;
+			sig_i.si_errno = 0;
+			sig_i.si_code = SI_MESGQ;
+			sig_i.si_value = info->notify.sigev_value;
+			sig_i.si_pid = current->tgid;
+			sig_i.si_uid = current->uid;
+
+			kill_proc_info(info->notify.sigev_signo,
+				       &sig_i, info->notify_owner);
+		} else if (info->notify.sigev_notify == SIGEV_THREAD) {
+			info->notify_filp->private_data = (void*)NP_WOKENUP;
+		}
+		/* after notification unregisters process */
+		info->notify_owner = 0;
+	}
+	wake_up(&info->wait_q);
+}
+
+static long prepare_timeout(const struct timespec __user *u_arg)
+{
+	struct timespec ts, nowts;
+	long timeout;
+
+	if (u_arg) {
+		if (unlikely(copy_from_user(&ts, u_arg,
+					sizeof(struct timespec))))
+			return -EFAULT;
+
+		if (unlikely(ts.tv_nsec < 0 || ts.tv_sec < 0
+			|| ts.tv_nsec >= NSEC_PER_SEC))
+			return -EINVAL;
+		nowts = CURRENT_TIME;
+		/* first subtract as jiffies can't be too big */
+		ts.tv_sec -= nowts.tv_sec;
+		if (ts.tv_nsec < nowts.tv_nsec) {
+			ts.tv_nsec += NSEC_PER_SEC;
+			ts.tv_sec--;
+		}
+		ts.tv_nsec -= nowts.tv_nsec;
+		if (ts.tv_sec < 0)
+			return 0;
+
+		timeout = timespec_to_jiffies(&ts) + 1;
+	} else
+		return MAX_SCHEDULE_TIMEOUT;
+
+	return timeout;
+}
+
+/*
+ * File descriptor based notification, intended to be used to implement
+ * SIGEV_THREAD:
+ * SIGEV_THREAD means that a notification function should be called in the
+ * context of a new thread. The kernel can't do that. Therefore mq_notify
+ * calls with SIGEV_THREAD return a new file descriptor. A user space helper
+ * must create a new thread and then read from the given file descriptor.
+ * The read always returns one byte. If it's NOTIFY_WOKENUP, then it must
+ * call the notification function. If it's NOTIFY_REMOVED, then the
+ * notification was removed. The file descriptor supports poll, thus one
+ * supervisor thread can manage multiple message queue notifications.
+ *
+ * The implementation must support multiple outstanding notifications:
+ * It's possible that a new notification is added and signaled before user
+ * space calls mqueue_notify_read for the previous notification.
+ * Therefore the notification state is stored in the private_data field of
+ * the file descriptor.
+ */
+static unsigned int mqueue_notify_poll(struct file *filp,
+					struct poll_table_struct *poll_tab)
+{
+	struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
+	int retval;
+
+	poll_wait(filp, &info->wait_q, poll_tab);
+
+	if (filp->private_data == NP_NONE)
+		retval = 0;
+	else
+		retval = POLLIN | POLLRDNORM;
+	return retval;
+}
+
+static ssize_t mqueue_notify_read(struct file *filp, char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
+	char result;
+
+	if (!count)
+		return 0;
+	if (*ppos != 0)
+		return 0;
+	spin_lock(&info->lock);
+	while (filp->private_data == NP_NONE) {
+		DEFINE_WAIT(wait);
+		if (filp->f_flags & O_NONBLOCK) {
+			spin_unlock(&info->lock);
+			return -EAGAIN;
+		}
+		prepare_to_wait(&info->wait_q, &wait, TASK_INTERRUPTIBLE);
+		spin_unlock(&info->lock);
+		schedule();
+		finish_wait(&info->wait_q, &wait);
+		spin_lock(&info->lock);
+	}
+	spin_unlock(&info->lock);
+	result = (char)(unsigned long)filp->private_data;
+	if (put_user(result, buf))
+		return -EFAULT;
+	*ppos = 1;
+	return 1;
+}
+
+static int mqueue_notify_release(struct inode *inode, struct file *filp)
+{
+	struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
+
+	spin_lock(&info->lock);
+	if (info->notify_owner && info->notify_filp == filp)
+		info->notify_owner = 0;
+	filp->private_data = NP_REMOVED;
+	spin_unlock(&info->lock);
+
+	return 0;
+}
+
+static void remove_notification(struct mqueue_inode_info *info)
+{
+	if (info->notify.sigev_notify == SIGEV_THREAD) {
+		info->notify_filp->private_data = NP_REMOVED;
+		wake_up(&info->wait_q);
+	}
+	info->notify_owner = 0;
+}
+
+/*
+ * Invoked when creating a new queue via sys_mq_open
+ */
+static struct file *do_create(struct dentry *dir, struct dentry *dentry,
+			int oflag, mode_t mode, struct mq_attr __user *u_attr)
+{
+	struct file *filp;
+	struct inode *inode;
+	struct mqueue_inode_info *info;
+	struct msg_msg **msgs = NULL;
+	struct mq_attr attr;
+	int ret;
+
+	if (u_attr != NULL) {
+		if (copy_from_user(&attr, u_attr, sizeof(attr)))
+			return ERR_PTR(-EFAULT);
+
+		if (attr.mq_maxmsg <= 0 || attr.mq_msgsize <= 0)
+			return ERR_PTR(-EINVAL);
+		if (capable(CAP_SYS_RESOURCE)) {
+			if (attr.mq_maxmsg > HARD_MSGMAX)
+				return ERR_PTR(-EINVAL);
+		} else {
+			if (attr.mq_maxmsg > msg_max ||
+					attr.mq_msgsize > msgsize_max)
+				return ERR_PTR(-EINVAL);
+		}
+		msgs = kmalloc(attr.mq_maxmsg * sizeof(*msgs), GFP_KERNEL);
+		if (!msgs)
+			return ERR_PTR(-ENOMEM);
+	} else {
+		msgs = NULL;
+	}
+
+	ret = vfs_create(dir->d_inode, dentry, mode, NULL);
+	if (ret) {
+		kfree(msgs);
+		return ERR_PTR(ret);
+	}
+
+	inode = dentry->d_inode;
+	info = MQUEUE_I(inode);
+
+	if (msgs) {
+		info->attr.mq_maxmsg = attr.mq_maxmsg;
+		info->attr.mq_msgsize = attr.mq_msgsize;
+		kfree(info->messages);
+		info->messages = msgs;
+	}
+
+	filp = dentry_open(dentry, mqueue_mnt, oflag);
+	if (!IS_ERR(filp))
+		dget(dentry);
+
+	return filp;
+}
+
+/* Opens existing queue */
+static struct file *do_open(struct dentry *dentry, int oflag)
+{
+static int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
+					MAY_READ | MAY_WRITE };
+	struct file *filp;
+
+	if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY))
+		return ERR_PTR(-EINVAL);
+
+	if (permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE], NULL))
+		return ERR_PTR(-EACCES);
+
+	filp = dentry_open(dentry, mqueue_mnt, oflag);
+
+	if (!IS_ERR(filp))
+		dget(dentry);
+
+	return filp;
+}
+
+asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
+				struct mq_attr __user *u_attr)
+{
+	struct dentry *dentry;
+	struct file *filp;
+	char *name;
+	int fd, error;
+
+	if (IS_ERR(name = getname(u_name)))
+		return PTR_ERR(name);
+
+	fd = get_unused_fd();
+	if (fd < 0)
+		goto out_putname;
+
+	down(&mqueue_mnt->mnt_root->d_inode->i_sem);
+	dentry = lookup_one_len(name, mqueue_mnt->mnt_root, strlen(name));
+	if (IS_ERR(dentry)) {
+		error = PTR_ERR(dentry);
+		goto out_err;
+	}
+	mntget(mqueue_mnt);
+
+	if (oflag & O_CREAT) {
+		if (dentry->d_inode) {	/* entry already exists */
+			filp = (oflag & O_EXCL) ? ERR_PTR(-EEXIST) :
+					do_open(dentry, oflag);
+		} else {
+			filp = do_create(mqueue_mnt->mnt_root, dentry,
+						oflag, mode, u_attr);
+		}
+	} else
+		filp = (dentry->d_inode) ? do_open(dentry, oflag) :
+					ERR_PTR(-ENOENT);
+
+	dput(dentry);
+
+	if (IS_ERR(filp)) {
+		error = PTR_ERR(filp);
+		goto out_putfd;
+	}
+
+	fd_install(fd, filp);
+	goto out_upsem;
+
+out_putfd:
+	mntput(mqueue_mnt);
+	put_unused_fd(fd);
+out_err:
+	fd = error;
+out_upsem:
+	up(&mqueue_mnt->mnt_root->d_inode->i_sem);
+out_putname:
+	putname(name);
+	return fd;
+}
+
+asmlinkage long sys_mq_unlink(const char __user *u_name)
+{
+	int err;
+	char *name;
+	struct dentry *dentry;
+	struct inode *inode = NULL;
+
+	name = getname(u_name);
+	if (IS_ERR(name))
+		return PTR_ERR(name);
+
+	down(&mqueue_mnt->mnt_root->d_inode->i_sem);
+	dentry = lookup_one_len(name, mqueue_mnt->mnt_root, strlen(name));
+	if (IS_ERR(dentry)) {
+		err = PTR_ERR(dentry);
+		goto out_unlock;
+	}
+
+	if (!dentry->d_inode) {
+		err = -ENOENT;
+		goto out_err;
+	}
+
+	if (permission(dentry->d_inode, MAY_WRITE, NULL)) {
+		err = -EACCES;
+		goto out_err;
+	}
+	inode = dentry->d_inode;
+	if (inode)
+		atomic_inc(&inode->i_count);
+
+	err = vfs_unlink(dentry->d_parent->d_inode, dentry);
+out_err:
+	dput(dentry);
+
+out_unlock:
+	up(&mqueue_mnt->mnt_root->d_inode->i_sem);
+	putname(name);
+	if (inode)
+		iput(inode);
+
+	return err;
+}
+
+/* Pipelined send and receive functions.
+ *
+ * If a receiver finds no waiting message, then it registers itself in the
+ * list of waiting receivers. A sender checks that list before adding the new
+ * message into the message array. If there is a waiting receiver, then it
+ * bypasses the message array and directly hands the message over to the
+ * receiver.
+ * The receiver accepts the message and returns without grabbing the queue
+ * spinlock. Therefore an intermediate STATE_PENDING state and memory barriers
+ * are necessary. The same algorithm is used for sysv semaphores, see
+ * ipc/sem.c fore more details.
+ *
+ * The same algorithm is used for senders.
+ */
+
+/* pipelined_send() - send a message directly to the task waiting in
+ * sys_mq_timedreceive() (without inserting message into a queue). */
+static inline void pipelined_send(struct mqueue_inode_info *info,
+				  struct msg_msg *message,
+				  struct ext_wait_queue *receiver)
+{
+	receiver->msg = message;
+	list_del(&receiver->list);
+	receiver->state = STATE_PENDING;
+	wake_up_process(receiver->task);
+	wmb();
+	receiver->state = STATE_READY;
+}
+
+/* pipelined_receive() - if there is task waiting in sys_mq_timedsend()
+ * gets its message and put to the queue (we have one free place for sure). */
+static inline void pipelined_receive(struct mqueue_inode_info *info)
+{
+	struct ext_wait_queue *sender = wq_get_first_waiter(info, SEND);
+
+	if (!sender) {
+		/* for poll */
+		wake_up_interruptible(&info->wait_q);
+		return;
+	}
+	msg_insert(sender->msg, info);
+	list_del(&sender->list);
+	sender->state = STATE_PENDING;
+	wake_up_process(sender->task);
+	wmb();
+	sender->state = STATE_READY;
+}
+
+asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr,
+	size_t msg_len, unsigned int msg_prio,
+	const struct timespec __user *u_abs_timeout)
+{
+	struct file *filp;
+	struct inode *inode;
+	struct ext_wait_queue wait;
+	struct ext_wait_queue *receiver;
+	struct msg_msg *msg_ptr;
+	struct mqueue_inode_info *info;
+	long timeout;
+	int ret;
+
+	if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX))
+		return -EINVAL;
+
+	if (unlikely((timeout = prepare_timeout(u_abs_timeout)) < 0))
+		return timeout;
+
+	ret = -EBADF;
+	filp = fget(mqdes);
+	if (unlikely(!filp))
+		goto out;
+
+	inode = filp->f_dentry->d_inode;
+	if (unlikely(filp->f_op != &mqueue_file_operations))
+		goto out_fput;
+	info = MQUEUE_I(inode);
+
+	if (unlikely(!(filp->f_mode & FMODE_WRITE)))
+		goto out_fput;
+
+	if (unlikely(msg_len > info->attr.mq_msgsize)) {
+		ret = -EMSGSIZE;
+		goto out_fput;
+	}
+
+	/* First try to allocate memory, before doing anything with
+	 * existing queues. */
+	msg_ptr = load_msg((void *)u_msg_ptr, msg_len);
+	if (unlikely(IS_ERR(msg_ptr))) {
+		ret = PTR_ERR(msg_ptr);
+		goto out_fput;
+	}
+	msg_ptr->m_ts = msg_len;
+	msg_ptr->m_type = msg_prio;
+
+	spin_lock(&info->lock);
+
+	if (info->attr.mq_curmsgs == info->attr.mq_maxmsg) {
+		if (filp->f_flags & O_NONBLOCK) {
+			spin_unlock(&info->lock);
+			ret = -EAGAIN;
+		} else {
+			wait.task = current;
+			wait.msg = (void *) msg_ptr;
+			wait.state = STATE_NONE;
+			ret = wq_sleep(info, SEND, timeout, &wait);
+			if (ret < 0)
+				free_msg(msg_ptr);
+		}
+	} else {
+		receiver = wq_get_first_waiter(info, RECV);
+		if (receiver) {
+			pipelined_send(info, msg_ptr, receiver);
+		} else {
+			/* adds message to the queue */
+			msg_insert(msg_ptr, info);
+			__do_notify(info);
+		}
+		inode->i_atime = inode->i_mtime = inode->i_ctime =
+				CURRENT_TIME;
+		spin_unlock(&info->lock);
+		ret = 0;
+	}
+out_fput:
+	fput(filp);
+out:
+	return ret;
+}
+
+asmlinkage ssize_t sys_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr,
+	size_t msg_len, unsigned int __user *u_msg_prio,
+	const struct timespec __user *u_abs_timeout)
+{
+	long timeout;
+	ssize_t ret;
+	struct msg_msg *msg_ptr;
+	struct file *filp;
+	struct inode *inode;
+	struct mqueue_inode_info *info;
+	struct ext_wait_queue wait;
+
+
+	if (unlikely((timeout = prepare_timeout(u_abs_timeout)) < 0))
+		return timeout;
+
+	ret = -EBADF;
+	filp = fget(mqdes);
+	if (unlikely(!filp))
+		goto out;
+
+	inode = filp->f_dentry->d_inode;
+	if (unlikely(filp->f_op != &mqueue_file_operations))
+		goto out_fput;
+	info = MQUEUE_I(inode);
+
+	if (unlikely(!(filp->f_mode & FMODE_READ)))
+		goto out_fput;
+
+	/* checks if buffer is big enough */
+	if (unlikely(msg_len < info->attr.mq_msgsize)) {
+		ret = -EMSGSIZE;
+		goto out_fput;
+	}
+
+	spin_lock(&info->lock);
+	if (info->attr.mq_curmsgs == 0) {
+		if (filp->f_flags & O_NONBLOCK) {
+			spin_unlock(&info->lock);
+			ret = -EAGAIN;
+			msg_ptr = NULL;
+		} else {
+			wait.task = current;
+			wait.state = STATE_NONE;
+			ret = wq_sleep(info, RECV, timeout, &wait);
+			msg_ptr = wait.msg;
+		}
+	} else {
+		msg_ptr = msg_get(info);
+
+		inode->i_atime = inode->i_mtime = inode->i_ctime =
+				CURRENT_TIME;
+
+		/* There is now free space in queue. */
+		pipelined_receive(info);
+		spin_unlock(&info->lock);
+		ret = 0;
+	}
+	if (ret == 0) {
+		ret = msg_ptr->m_ts;
+
+		if ((u_msg_prio && put_user(msg_ptr->m_type, u_msg_prio)) ||
+			store_msg(u_msg_ptr, msg_ptr, msg_ptr->m_ts)) {
+			ret = -EFAULT;
+		}
+		free_msg(msg_ptr);
+	}
+out_fput:
+	fput(filp);
+out:
+	return ret;
+}
+
+/*
+ * Notes: the case when user wants us to deregister (with NULL as pointer
+ * or SIGEV_NONE) and he isn't currently owner of notification will be
+ * silently discarded. It isn't explicitly defined in the POSIX.
+ */
+asmlinkage long sys_mq_notify(mqd_t mqdes,
+				const struct sigevent __user *u_notification)
+{
+	int ret, fd;
+	struct file *filp, *nfilp;
+	struct inode *inode;
+	struct sigevent notification;
+	struct mqueue_inode_info *info;
+
+	if (u_notification == NULL) {
+		notification.sigev_notify = SIGEV_NONE;
+	} else {
+		if (copy_from_user(&notification, u_notification,
+					sizeof(struct sigevent)))
+			return -EFAULT;
+
+		if (unlikely(notification.sigev_notify != SIGEV_NONE &&
+			     notification.sigev_notify != SIGEV_SIGNAL &&
+			     notification.sigev_notify != SIGEV_THREAD))
+			return -EINVAL;
+		if (notification.sigev_notify == SIGEV_SIGNAL &&
+			(notification.sigev_signo < 0 ||
+			 notification.sigev_signo > _NSIG)) {
+			return -EINVAL;
+		}
+	}
+
+	ret = -EBADF;
+	filp = fget(mqdes);
+	if (!filp)
+		goto out;
+
+	inode = filp->f_dentry->d_inode;
+	if (unlikely(filp->f_op != &mqueue_file_operations))
+		goto out_fput;
+	info = MQUEUE_I(inode);
+
+	ret = 0;
+	if (notification.sigev_notify == SIGEV_THREAD) {
+		ret = get_unused_fd();
+		if (ret < 0)
+			goto out_fput;
+		fd = ret;
+		nfilp = get_empty_filp();
+		if (!nfilp) {
+			ret = -ENFILE;
+			goto out_dropfd;
+		}
+		nfilp->private_data = NP_NONE;
+		nfilp->f_op = &mqueue_notify_fops;
+		nfilp->f_vfsmnt = mntget(mqueue_mnt);
+		nfilp->f_dentry = dget(filp->f_dentry);
+		nfilp->f_mapping = filp->f_dentry->d_inode->i_mapping;
+		nfilp->f_flags = O_RDONLY;
+		nfilp->f_mode = FMODE_READ;
+	} else {
+		nfilp = NULL;
+		fd = -1;
+	}
+
+	spin_lock(&info->lock);
+
+	if (notification.sigev_notify == SIGEV_NONE) {
+		if (info->notify_owner == current->tgid) {
+			remove_notification(info);
+			inode->i_atime = inode->i_ctime = CURRENT_TIME;
+		}
+	} else if (info->notify_owner) {
+		ret = -EBUSY;
+	} else if (notification.sigev_notify == SIGEV_THREAD) {
+		info->notify_filp = nfilp;
+		fd_install(fd, nfilp);
+		ret = fd;
+		fd = -1;
+		nfilp = NULL;
+		info->notify.sigev_notify = SIGEV_THREAD;
+		info->notify_owner = current->tgid;
+		inode->i_atime = inode->i_ctime = CURRENT_TIME;
+	}  else {
+		info->notify.sigev_signo = notification.sigev_signo;
+		info->notify.sigev_value = notification.sigev_value;
+		info->notify.sigev_notify = SIGEV_SIGNAL;
+		info->notify_owner = current->tgid;
+		inode->i_atime = inode->i_ctime = CURRENT_TIME;
+	}
+	spin_unlock(&info->lock);
+out_dropfd:
+	if (fd != -1)
+		put_unused_fd(fd);
+out_fput:
+	fput(filp);
+out:
+	return ret;
+}
+
+asmlinkage long sys_mq_getsetattr(mqd_t mqdes,
+			const struct mq_attr __user *u_mqstat,
+			struct mq_attr __user *u_omqstat)
+{
+	int ret;
+	struct mq_attr mqstat, omqstat;
+	struct file *filp;
+	struct inode *inode;
+	struct mqueue_inode_info *info;
+
+	if (u_mqstat != NULL) {
+		if (copy_from_user(&mqstat, u_mqstat, sizeof(struct mq_attr)))
+			return -EFAULT;
+		if (mqstat.mq_flags & (~O_NONBLOCK))
+			return -EINVAL;
+	}
+
+	ret = -EBADF;
+	filp = fget(mqdes);
+	if (!filp)
+		goto out;
+
+	inode = filp->f_dentry->d_inode;
+	if (unlikely(filp->f_op != &mqueue_file_operations))
+		goto out_fput;
+	info = MQUEUE_I(inode);
+
+	spin_lock(&info->lock);
+
+	omqstat = info->attr;
+	omqstat.mq_flags = filp->f_flags & O_NONBLOCK;
+	if (u_mqstat) {
+		if (mqstat.mq_flags & O_NONBLOCK)
+			filp->f_flags |= O_NONBLOCK;
+		else
+			filp->f_flags &= ~O_NONBLOCK;
+
+		inode->i_atime = inode->i_ctime = CURRENT_TIME;
+	}
+
+	spin_unlock(&info->lock);
+
+	ret = 0;
+	if (u_omqstat != NULL && copy_to_user(u_omqstat, &omqstat,
+						sizeof(struct mq_attr)))
+		ret = -EFAULT;
+
+out_fput:
+	fput(filp);
+out:
+	return ret;
+}
+
+static struct inode_operations mqueue_dir_inode_operations = {
+	.lookup = simple_lookup,
+	.create = mqueue_create,
+	.unlink = mqueue_unlink,
+};
+
+static struct file_operations mqueue_file_operations = {
+	.flush = mqueue_flush_file,
+	.poll = mqueue_poll_file,
+	.read = mqueue_read_file,
+};
+
+static struct file_operations mqueue_notify_fops = {
+	.poll = mqueue_notify_poll,
+	.read = mqueue_notify_read,
+	.release = mqueue_notify_release,
+};
+
+
+static struct super_operations mqueue_super_ops = {
+	.alloc_inode = mqueue_alloc_inode,
+	.destroy_inode = mqueue_destroy_inode,
+	.statfs = simple_statfs,
+	.delete_inode = mqueue_delete_inode,
+	.drop_inode = generic_delete_inode,
+};
+
+static struct file_system_type mqueue_fs_type = {
+	.name = "mqueue",
+	.get_sb = mqueue_get_sb,
+	.kill_sb = kill_litter_super,
+};
+
+static int msg_max_limit_min = DFLT_MSGMAX;
+static int msg_max_limit_max = HARD_MSGMAX;
+
+static int msg_maxsize_limit_min = DFLT_MSGSIZEMAX;
+static int msg_maxsize_limit_max = INT_MAX;
+
+static ctl_table mq_sysctls[] = {
+	{
+		.ctl_name	= CTL_QUEUESMAX,
+		.procname	= "queues_max",
+		.data		= &queues_max,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+	{
+		.ctl_name	= CTL_MSGMAX,
+		.procname	= "msg_max",
+		.data		= &msg_max,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_minmax,
+		.extra1		= &msg_max_limit_min,
+		.extra2		= &msg_max_limit_max,
+	},
+	{
+		.ctl_name	= CTL_MSGSIZEMAX,
+		.procname	= "msgsize_max",
+		.data		= &msgsize_max,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_minmax,
+		.extra1		= &msg_maxsize_limit_min,
+		.extra2		= &msg_maxsize_limit_max,
+	},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table mq_sysctl_dir[] = {
+	{
+		.ctl_name	= FS_MQUEUE,
+		.procname	= "mqueue",
+		.mode		= 0555,
+		.child		= mq_sysctls,
+	},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table mq_sysctl_root[] = {
+	{
+		.ctl_name	= CTL_FS,
+		.procname	= "fs",
+		.mode		= 0555,
+		.child		= mq_sysctl_dir,
+	},
+	{ .ctl_name = 0 }
+};
+
+static int __init init_mqueue_fs(void)
+{
+	int error;
+
+	mqueue_inode_cachep = kmem_cache_create("mqueue_inode_cache",
+				sizeof(struct mqueue_inode_info), 0,
+				SLAB_HWCACHE_ALIGN, init_once, NULL);
+	if (mqueue_inode_cachep == NULL)
+		return -ENOMEM;
+
+	mq_sysctl_table = register_sysctl_table(mq_sysctl_root, 0);
+	if (!mq_sysctl_table) {
+		error = -ENOMEM;
+		goto out_cache;
+	}
+
+	error = register_filesystem(&mqueue_fs_type);
+	if (error)
+		goto out_sysctl;
+
+	if (IS_ERR(mqueue_mnt = kern_mount(&mqueue_fs_type))) {
+		error = PTR_ERR(mqueue_mnt);
+		goto out_filesystem;
+	}
+
+	/* internal initialization - not common for vfs */
+	queues_count = 0;
+	spin_lock_init(&mq_lock);
+
+	return 0;
+
+out_filesystem:
+	unregister_filesystem(&mqueue_fs_type);
+out_sysctl:
+	unregister_sysctl_table(mq_sysctl_table);
+out_cache:
+	if (kmem_cache_destroy(mqueue_inode_cachep)) {
+		printk(KERN_INFO
+			"mqueue_inode_cache: not all structures were freed\n");
+	}
+	return error;
+}
+
+__initcall(init_mqueue_fs);
--- diff/ipc/msgutil.c	1970-01-01 01:00:00.000000000 +0100
+++ source/ipc/msgutil.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,127 @@
+/*
+ * linux/ipc/util.c
+ * Copyright (C) 1999, 2004 Manfred Spraul
+ *
+ * This file is released under GNU General Public Licence version 2 or
+ * (at your option) any later version.
+ *
+ * See the file COPYING for more details.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/security.h>
+#include <linux/slab.h>
+#include <linux/ipc.h>
+#include <asm/uaccess.h>
+
+#include "util.h"
+
+struct msg_msgseg {
+	struct msg_msgseg* next;
+	/* the next part of the message follows immediately */
+};
+
+#define DATALEN_MSG	(PAGE_SIZE-sizeof(struct msg_msg))
+#define DATALEN_SEG	(PAGE_SIZE-sizeof(struct msg_msgseg))
+
+struct msg_msg *load_msg(void __user *src, int len)
+{
+	struct msg_msg *msg;
+	struct msg_msgseg **pseg;
+	int err;
+	int alen;
+
+	alen = len;
+	if (alen > DATALEN_MSG)
+		alen = DATALEN_MSG;
+
+	msg = (struct msg_msg *)kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
+	if (msg == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	msg->next = NULL;
+	msg->security = NULL;
+
+	if (copy_from_user(msg + 1, src, alen)) {
+		err = -EFAULT;
+		goto out_err;
+	}
+
+	len -= alen;
+	src = ((char *)src) + alen;
+	pseg = &msg->next;
+	while (len > 0) {
+		struct msg_msgseg *seg;
+		alen = len;
+		if (alen > DATALEN_SEG)
+			alen = DATALEN_SEG;
+		seg = (struct msg_msgseg *)kmalloc(sizeof(*seg) + alen,
+						 GFP_KERNEL);
+		if (seg == NULL) {
+			err = -ENOMEM;
+			goto out_err;
+		}
+		*pseg = seg;
+		seg->next = NULL;
+		if (copy_from_user(seg + 1, src, alen)) {
+			err = -EFAULT;
+			goto out_err;
+		}
+		pseg = &seg->next;
+		len -= alen;
+		src = ((char *)src) + alen;
+	}
+
+	err = security_msg_msg_alloc(msg);
+	if (err)
+		goto out_err;
+
+	return msg;
+
+out_err:
+	free_msg(msg);
+	return ERR_PTR(err);
+}
+
+int store_msg(void __user *dest, struct msg_msg *msg, int len)
+{
+	int alen;
+	struct msg_msgseg *seg;
+
+	alen = len;
+	if (alen > DATALEN_MSG)
+		alen = DATALEN_MSG;
+	if (copy_to_user(dest, msg + 1, alen))
+		return -1;
+
+	len -= alen;
+	dest = ((char *)dest) + alen;
+	seg = msg->next;
+	while (len > 0) {
+		alen = len;
+		if (alen > DATALEN_SEG)
+			alen = DATALEN_SEG;
+		if (copy_to_user(dest, seg + 1, alen))
+			return -1;
+		len -= alen;
+		dest = ((char *)dest) + alen;
+		seg = seg->next;
+	}
+	return 0;
+}
+
+void free_msg(struct msg_msg *msg)
+{
+	struct msg_msgseg *seg;
+
+	security_msg_msg_free(msg);
+
+	seg = msg->next;
+	kfree(msg);
+	while (seg != NULL) {
+		struct msg_msgseg *tmp = seg->next;
+		kfree(seg);
+		seg = tmp;
+	}
+}
--- diff/kernel/compat_signal.c	1970-01-01 01:00:00.000000000 +0100
+++ source/kernel/compat_signal.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,124 @@
+/*
+ *  Copyright (C) 2003 Carlos O'Donell
+ *
+ *  2003-12-20  Carlos O'Donell
+ *              Copied linux/kernel/compat_signal.c (copy_siginfo_to_user)
+ *              and modified to use compat_siginfo_t for thunking down to
+ *              32-bit userspace from a 64-bit kernel.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/compat_siginfo.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+#include <asm/siginfo.h>
+
+#ifndef HAVE_ARCH_COMPAT_COPY_SIGINFO_TO_USER
+
+int compat_copy_siginfo_to_user(compat_siginfo_t __user *to, siginfo_t *from)
+{
+	int err;
+	compat_siginfo_t compat_from;
+
+	if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
+		return -EFAULT;
+
+	/*
+	 * If you change compat_siginfo_t structure *or* siginfo_t,
+	 * please be sure this code is fixed accordingly.
+	 * It should never copy any pad contained in the structure
+	 * to avoid security leaks, but must copy the generic
+	 * 3 ints plus the relevant union member.
+	 */
+
+	/* Convert structure, don't leak anything in the copy */
+	memset(&compat_from,'\0',sizeof(compat_siginfo_t));
+	compat_from.si_signo = (compat_int_t)(from->si_signo);
+	compat_from.si_errno = (compat_int_t)(from->si_errno);
+	compat_from.si_code = (compat_int_t)(from->si_code);
+
+	if (from->si_code < 0)
+		return __copy_to_user(to, &compat_from, sizeof(compat_siginfo_t))
+			? -EFAULT : 0;
+
+	err = __put_user(compat_from.si_signo, &to->si_signo);
+	err |= __put_user(compat_from.si_errno, &to->si_errno);
+	err |= __put_user(compat_from.si_code, &to->si_code);
+
+	switch (from->si_code & __SI_MASK) {
+	case __SI_KILL:
+		compat_from.si_pid = (compat_pid_t)(from->si_pid);
+		compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
+		err |= __put_user(compat_from.si_pid, &to->si_pid);
+		err |= __put_user(compat_from.si_uid, &to->si_uid);
+		break;
+	case __SI_TIMER:
+		compat_from.si_pid = (compat_timer_t)(from->si_tid);
+		compat_from.si_overrun = (compat_int_t)(from->si_overrun);
+		compat_from.si_ptr = (compat_uptr_t)((u64)(from->si_ptr) & 0xffffffffUL);
+		err |= __put_user(compat_from.si_tid, &to->si_tid);
+		err |= __put_user(compat_from.si_overrun, &to->si_overrun);
+		err |= __put_user(compat_from.si_ptr, &to->si_ptr);
+		break;
+	case __SI_POLL:
+		compat_from.si_band = (__ARCH_SI_COMPAT_BAND_T)(from->si_band);
+		compat_from.si_fd = (compat_int_t)(from->si_fd);
+		err |= __put_user(compat_from.si_band, &to->si_band);
+		err |= __put_user(compat_from.si_fd, &to->si_fd);
+		break;
+	case __SI_FAULT:
+		compat_from.si_addr = (compat_uptr_t)((u64)(from->si_addr) & 0xffffffffUL);
+		err |= __put_user(compat_from.si_addr, &to->si_addr);
+#ifdef __ARCH_SI_COMPAT_TRAPNO
+		compat_from.si_trapno = (compat_int_t)(from->si_addr);
+		err |= __put_user(compat_from.si_trapno, &to->si_trapno);
+#endif
+		break;
+	case __SI_CHLD:
+		compat_from.si_pid = (compat_pid_t)(from->si_pid);
+		compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
+		compat_from.si_status = (compat_int_t)(from->si_status);
+		compat_from.si_utime = (compat_clock_t)(from->si_utime);
+		compat_from.si_stime = (compat_clock_t)(from->si_stime);
+		err |= __put_user(compat_from.si_pid, &to->si_pid);
+		err |= __put_user(compat_from.si_uid, &to->si_uid);
+		err |= __put_user(compat_from.si_status, &to->si_status);
+		err |= __put_user(compat_from.si_utime, &to->si_utime);
+		err |= __put_user(compat_from.si_stime, &to->si_stime);
+		break;
+	case __SI_RT: /* This is not generated by the kernel as of now. */
+		compat_from.si_pid = (compat_pid_t)(from->si_pid);
+		compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
+		compat_from.si_int = (compat_int_t)(from->si_int);
+		compat_from.si_ptr = (compat_uptr_t)((u64)(from->si_ptr) & 0xffffffffUL);
+		err |= __put_user(compat_from.si_pid, &to->si_pid);
+		err |= __put_user(compat_from.si_uid, &to->si_uid);
+		err |= __put_user(compat_from.si_int, &to->si_int);
+		err |= __put_user(compat_from.si_ptr, &to->si_ptr);
+		break;
+	default: /* this is just in case for now ... */
+		compat_from.si_pid = (compat_pid_t)(from->si_pid);
+		compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
+		err |= __put_user(compat_from.si_pid, &to->si_pid);
+		err |= __put_user(compat_from.si_uid, &to->si_uid);
+		break;
+	}
+	return err;
+}
+
+#endif
--- diff/kernel/lockmeter.c	1970-01-01 01:00:00.000000000 +0100
+++ source/kernel/lockmeter.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,1178 @@
+/*
+ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.c by Jack Steiner (steiner@sgi.com)
+ *
+ *  Modified by Ray Bryant (raybry@us.ibm.com)
+ *  Changes Copyright (C) 2000 IBM, Inc.
+ *  Added save of index in spinlock_t to improve efficiency
+ *  of "hold" time reporting for spinlocks
+ *  Added support for hold time statistics for read and write
+ *  locks.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <linux/spinlock.h>
+#include <linux/utsname.h>
+#include <linux/module.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <linux/lockmeter.h>
+
+#define ASSERT(cond)
+#define bzero(loc,size)		memset(loc,0,size)
+
+/*<---------------------------------------------------*/
+/*              lockmeter.c                           */
+/*>---------------------------------------------------*/
+
+static lstat_control_t lstat_control __cacheline_aligned =
+	{ LSTAT_OFF, SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED,
+	  19 * 0, NR_CPUS * 0, 0, NR_CPUS * 0 };
+
+static ushort lstat_make_dir_entry(void *, void *);
+
+/*
+ * lstat_lookup
+ *
+ * Given a RA, locate the directory entry for the lock.
+ */
+static ushort
+lstat_lookup(void *lock_ptr, void *caller_ra)
+{
+	ushort index;
+	lstat_directory_entry_t *dirp;
+
+	dirp = lstat_control.dir;
+
+	index = lstat_control.hashtab[DIRHASH(caller_ra)];
+	while (dirp[index].caller_ra != caller_ra) {
+		if (index == 0) {
+			return lstat_make_dir_entry(lock_ptr, caller_ra);
+		}
+		index = dirp[index].next_stat_index;
+	}
+
+	if (dirp[index].lock_ptr != NULL && dirp[index].lock_ptr != lock_ptr) {
+		dirp[index].lock_ptr = NULL;
+	}
+
+	return index;
+}
+
+/*
+ * lstat_make_dir_entry
+ * Called to add a new lock to the lock directory.
+ */
+static ushort
+lstat_make_dir_entry(void *lock_ptr, void *caller_ra)
+{
+	lstat_directory_entry_t *dirp;
+	ushort index, hindex;
+	unsigned long flags;
+
+	/* lock the table without recursively reentering this metering code */
+	local_irq_save(flags);
+	_raw_spin_lock(&lstat_control.directory_lock);
+
+	hindex = DIRHASH(caller_ra);
+	index = lstat_control.hashtab[hindex];
+	dirp = lstat_control.dir;
+	while (index && dirp[index].caller_ra != caller_ra)
+		index = dirp[index].next_stat_index;
+
+	if (index == 0) {
+		if (lstat_control.next_free_dir_index < LSTAT_MAX_STAT_INDEX) {
+			index = lstat_control.next_free_dir_index++;
+			lstat_control.dir[index].caller_ra = caller_ra;
+			lstat_control.dir[index].lock_ptr = lock_ptr;
+			lstat_control.dir[index].next_stat_index =
+				lstat_control.hashtab[hindex];
+			lstat_control.hashtab[hindex] = index;
+		} else {
+			lstat_control.dir_overflow++;
+		}
+	}
+	_raw_spin_unlock(&lstat_control.directory_lock);
+	local_irq_restore(flags);
+	return index;
+}
+
+int
+lstat_update(void *lock_ptr, void *caller_ra, int action)
+{
+	int index;
+	int cpu;
+
+	ASSERT(action < LSTAT_ACT_MAX_VALUES);
+
+	if (lstat_control.state == LSTAT_OFF)
+		return 0;
+
+	index = lstat_lookup(lock_ptr, caller_ra);
+	cpu = THIS_CPU_NUMBER;
+	(*lstat_control.counts[cpu])[index].count[action]++;
+	(*lstat_control.counts[cpu])[index].acquire_time = get_cycles();
+
+	return index;
+}
+
+int
+lstat_update_time(void *lock_ptr, void *caller_ra, int action, uint32_t ticks)
+{
+	ushort index;
+	int cpu;
+
+	ASSERT(action < LSTAT_ACT_MAX_VALUES);
+
+	if (lstat_control.state == LSTAT_OFF)
+		return 0;
+
+	index = lstat_lookup(lock_ptr, caller_ra);
+	cpu = THIS_CPU_NUMBER;
+	(*lstat_control.counts[cpu])[index].count[action]++;
+	(*lstat_control.counts[cpu])[index].cum_wait_ticks += (uint64_t) ticks;
+	if ((*lstat_control.counts[cpu])[index].max_wait_ticks < ticks)
+		(*lstat_control.counts[cpu])[index].max_wait_ticks = ticks;
+
+	(*lstat_control.counts[cpu])[index].acquire_time = get_cycles();
+
+	return index;
+}
+
+void
+_metered_spin_lock(spinlock_t * lock_ptr)
+{
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_spin_lock(lock_ptr);	/* do the real lock */
+		PUT_INDEX(lock_ptr, 0);	/* clean index in case lockmetering  */
+		/* gets turned on before unlock */
+	} else {
+		void *this_pc = LSTAT_RA(LSTAT_RA_SPIN);
+		int index;
+
+		if (_raw_spin_trylock(lock_ptr)) {
+			index = lstat_update(lock_ptr, this_pc,
+						LSTAT_ACT_NO_WAIT);
+		} else {
+			uint32_t start_cycles = get_cycles();
+			_raw_spin_lock(lock_ptr);	/* do the real lock */
+			index = lstat_update_time(lock_ptr, this_pc,
+				LSTAT_ACT_SPIN, get_cycles() - start_cycles);
+		}
+		/* save the index in the lock itself for use in spin unlock */
+		PUT_INDEX(lock_ptr, index);
+	}
+}
+
+int
+_metered_spin_trylock(spinlock_t * lock_ptr)
+{
+	if (lstat_control.state == LSTAT_OFF) {
+		return _raw_spin_trylock(lock_ptr);
+	} else {
+		int retval;
+		void *this_pc = LSTAT_RA(LSTAT_RA_SPIN);
+
+		if ((retval = _raw_spin_trylock(lock_ptr))) {
+			int index = lstat_update(lock_ptr, this_pc,
+						LSTAT_ACT_NO_WAIT);
+			/*
+			 * save the index in the lock itself for use in spin
+			 * unlock
+			 */
+			PUT_INDEX(lock_ptr, index);
+		} else {
+			lstat_update(lock_ptr, this_pc, LSTAT_ACT_REJECT);
+		}
+
+		return retval;
+	}
+}
+
+void
+_metered_spin_unlock(spinlock_t * lock_ptr)
+{
+	int index = -1;
+
+	if (lstat_control.state != LSTAT_OFF) {
+		index = GET_INDEX(lock_ptr);
+		/*
+		 * If statistics were turned off when we set the lock,
+		 * then the index can be zero.  If that is the case,
+		 * then collect no stats on this call.
+		 */
+		if (index > 0) {
+			uint32_t hold_time;
+			int cpu = THIS_CPU_NUMBER;
+			hold_time = get_cycles() -
+			 (*lstat_control.counts[cpu])[index].acquire_time;
+			(*lstat_control.counts[cpu])[index].cum_hold_ticks +=
+				(uint64_t) hold_time;
+			if ((*lstat_control.counts[cpu])[index].max_hold_ticks <
+			    hold_time)
+				(*lstat_control.counts[cpu])[index].
+				    max_hold_ticks = hold_time;
+		}
+	}
+
+	/* make sure we don't have a stale index value saved */
+	PUT_INDEX(lock_ptr, 0);
+	_raw_spin_unlock(lock_ptr);	/* do the real unlock */
+}
+
+/*
+ * allocate the next global read lock structure and store its index
+ * in the rwlock at "lock_ptr".
+ */
+uint32_t
+alloc_rwlock_struct(rwlock_t * rwlock_ptr)
+{
+	int index;
+	unsigned long flags;
+	int cpu = THIS_CPU_NUMBER;
+
+	/* If we've already overflowed, then do a quick exit */
+	if (lstat_control.next_free_read_lock_index >
+			LSTAT_MAX_READ_LOCK_INDEX) {
+		lstat_control.rwlock_overflow++;
+		return 0;
+	}
+
+	local_irq_save(flags);
+	_raw_spin_lock(&lstat_control.directory_lock);
+
+	/* It is possible this changed while we were waiting for the directory_lock */
+	if (lstat_control.state == LSTAT_OFF) {
+		index = 0;
+		goto unlock;
+	}
+
+	/* It is possible someone else got here first and set the index */
+	if ((index = GET_RWINDEX(rwlock_ptr)) == 0) {
+		/*
+		 * we can't turn on read stats for this lock while there are
+		 * readers (this would mess up the running hold time sum at
+		 * unlock time)
+		 */
+		if (RWLOCK_READERS(rwlock_ptr) != 0) {
+			index = 0;
+			goto unlock;
+		}
+
+		/*
+		 * if stats are turned on after being off, we may need to
+		 * return an old index from when the statistics were on last
+		 * time.
+		 */
+		for (index = 1; index < lstat_control.next_free_read_lock_index;
+				index++)
+			if ((*lstat_control.read_lock_counts[cpu])[index].
+					lock_ptr == rwlock_ptr)
+				goto put_index_and_unlock;
+
+		/* allocate the next global read lock structure */
+		if (lstat_control.next_free_read_lock_index >=
+		    LSTAT_MAX_READ_LOCK_INDEX) {
+			lstat_control.rwlock_overflow++;
+			index = 0;
+			goto unlock;
+		}
+		index = lstat_control.next_free_read_lock_index++;
+
+		/*
+		 * initialize the global read stats data structure for each
+		 * cpu
+		 */
+		for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+			(*lstat_control.read_lock_counts[cpu])[index].lock_ptr =
+				rwlock_ptr;
+		}
+put_index_and_unlock:
+		/* store the index for the read lock structure into the lock */
+		PUT_RWINDEX(rwlock_ptr, index);
+	}
+
+unlock:
+	_raw_spin_unlock(&lstat_control.directory_lock);
+	local_irq_restore(flags);
+	return index;
+}
+
+void
+_metered_read_lock(rwlock_t * rwlock_ptr)
+{
+	void *this_pc;
+	uint32_t start_cycles;
+	int index;
+	int cpu;
+	unsigned long flags;
+	int readers_before, readers_after;
+	uint64_t cycles64;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_read_lock(rwlock_ptr);
+		/* clean index in case lockmetering turns on before an unlock */
+		PUT_RWINDEX(rwlock_ptr, 0);
+		return;
+	}
+
+	this_pc = LSTAT_RA(LSTAT_RA_READ);
+	cpu = THIS_CPU_NUMBER;
+	index = GET_RWINDEX(rwlock_ptr);
+
+	/* allocate the global stats entry for this lock, if needed */
+	if (index == 0)
+		index = alloc_rwlock_struct(rwlock_ptr);
+
+	readers_before = RWLOCK_READERS(rwlock_ptr);
+	if (_raw_read_trylock(rwlock_ptr)) {
+		/*
+		 * We have decremented the lock to count a new reader,
+		 * and have confirmed that no writer has it locked.
+		 */
+		/* update statistics if enabled */
+		if (index > 0) {
+			local_irq_save(flags);
+			lstat_update((void *) rwlock_ptr, this_pc,
+					LSTAT_ACT_NO_WAIT);
+			/* preserve value of TSC so cum_hold_ticks and start_busy use same value */
+			cycles64 = get_cycles64();
+			(*lstat_control.read_lock_counts[cpu])[index].
+				cum_hold_ticks -= cycles64;
+
+			/* record time and cpu of start of busy period */
+			/* this is not perfect (some race conditions are possible) */
+			if (readers_before == 0) {
+				(*lstat_control.read_lock_counts[cpu])[index].
+					start_busy = cycles64;
+				PUT_RW_CPU(rwlock_ptr, cpu);
+			}
+			readers_after = RWLOCK_READERS(rwlock_ptr);
+			if (readers_after >
+				(*lstat_control.read_lock_counts[cpu])[index].
+					max_readers)
+				(*lstat_control.read_lock_counts[cpu])[index].
+					max_readers = readers_after;
+			local_irq_restore(flags);
+		}
+
+		return;
+	}
+	/* If we get here, then we could not quickly grab the read lock */
+
+	start_cycles = get_cycles();	/* start counting the wait time */
+
+	/* Now spin until read_lock is successful */
+	_raw_read_lock(rwlock_ptr);
+
+	lstat_update_time((void *) rwlock_ptr, this_pc, LSTAT_ACT_SPIN,
+			  get_cycles() - start_cycles);
+
+	/* update statistics if they are enabled for this lock */
+	if (index > 0) {
+		local_irq_save(flags);
+		cycles64 = get_cycles64();
+		(*lstat_control.read_lock_counts[cpu])[index].cum_hold_ticks -=
+				cycles64;
+
+		/* this is not perfect (some race conditions are possible) */
+		if (readers_before == 0) {
+			(*lstat_control.read_lock_counts[cpu])[index].
+				start_busy = cycles64;
+			PUT_RW_CPU(rwlock_ptr, cpu);
+		}
+		readers_after = RWLOCK_READERS(rwlock_ptr);
+		if (readers_after >
+		    (*lstat_control.read_lock_counts[cpu])[index].max_readers)
+			(*lstat_control.read_lock_counts[cpu])[index].
+				max_readers = readers_after;
+		local_irq_restore(flags);
+	}
+}
+
+void
+_metered_read_unlock(rwlock_t * rwlock_ptr)
+{
+	int index;
+	int cpu;
+	unsigned long flags;
+	uint64_t busy_length;
+	uint64_t cycles64;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_read_unlock(rwlock_ptr);
+		return;
+	}
+
+	index = GET_RWINDEX(rwlock_ptr);
+	cpu = THIS_CPU_NUMBER;
+
+	if (index > 0) {
+		local_irq_save(flags);
+		/*
+		 * preserve value of TSC so cum_hold_ticks and busy_ticks are
+		 * consistent.
+		 */
+		cycles64 = get_cycles64();
+		(*lstat_control.read_lock_counts[cpu])[index].cum_hold_ticks +=
+			cycles64;
+		(*lstat_control.read_lock_counts[cpu])[index].read_lock_count++;
+
+		/*
+		 * once again, this is not perfect (some race conditions are
+		 * possible)
+		 */
+		if (RWLOCK_READERS(rwlock_ptr) == 1) {
+			int cpu1 = GET_RW_CPU(rwlock_ptr);
+			uint64_t last_start_busy =
+				(*lstat_control.read_lock_counts[cpu1])[index].
+					start_busy;
+			(*lstat_control.read_lock_counts[cpu])[index].
+				busy_periods++;
+			if (cycles64 > last_start_busy) {
+				busy_length = cycles64 - last_start_busy;
+				(*lstat_control.read_lock_counts[cpu])[index].
+					busy_ticks += busy_length;
+				if (busy_length >
+					(*lstat_control.
+						read_lock_counts[cpu])[index].
+							max_busy)
+					(*lstat_control.
+					 read_lock_counts[cpu])[index].
+						max_busy = busy_length;
+			}
+		}
+		local_irq_restore(flags);
+	}
+	_raw_read_unlock(rwlock_ptr);
+}
+
+void
+_metered_write_lock(rwlock_t * rwlock_ptr)
+{
+	uint32_t start_cycles;
+	void *this_pc;
+	uint32_t spin_ticks = 0; /* in anticipation of a potential wait */
+	int index;
+	int write_index = 0;
+	int cpu;
+	enum {
+		writer_writer_conflict,
+		writer_reader_conflict
+	} why_wait = writer_writer_conflict;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_write_lock(rwlock_ptr);
+		/* clean index in case lockmetering turns on before an unlock */
+		PUT_RWINDEX(rwlock_ptr, 0);
+		return;
+	}
+
+	this_pc = LSTAT_RA(LSTAT_RA_WRITE);
+	cpu = THIS_CPU_NUMBER;
+	index = GET_RWINDEX(rwlock_ptr);
+
+	/* allocate the global stats entry for this lock, if needed */
+	if (index == 0) {
+		index = alloc_rwlock_struct(rwlock_ptr);
+	}
+
+	if (_raw_write_trylock(rwlock_ptr)) {
+		/* We acquired the lock on the first try */
+		write_index = lstat_update((void *) rwlock_ptr, this_pc,
+					LSTAT_ACT_NO_WAIT);
+		/* save the write_index for use in unlock if stats enabled */
+		if (index > 0)
+			(*lstat_control.read_lock_counts[cpu])[index].
+				write_index = write_index;
+		return;
+	}
+
+	/* If we get here, then we could not quickly grab the write lock */
+	start_cycles = get_cycles();	/* start counting the wait time */
+
+	why_wait = RWLOCK_READERS(rwlock_ptr) ?
+			writer_reader_conflict : writer_writer_conflict;
+
+	/* Now set the lock and wait for conflicts to disappear */
+	_raw_write_lock(rwlock_ptr);
+
+	spin_ticks = get_cycles() - start_cycles;
+
+	/* update stats -- if enabled */
+	if (index > 0 && spin_ticks) {
+		if (why_wait == writer_reader_conflict) {
+			/* waited due to a reader holding the lock */
+			write_index = lstat_update_time((void *)rwlock_ptr,
+					this_pc, LSTAT_ACT_SPIN, spin_ticks);
+		} else {
+			/*
+			 * waited due to another writer holding the lock
+			 */
+			write_index = lstat_update_time((void *)rwlock_ptr,
+				this_pc, LSTAT_ACT_WW_SPIN, spin_ticks);
+			(*lstat_control.counts[cpu])[write_index].
+				cum_wait_ww_ticks += spin_ticks;
+			if (spin_ticks >
+				(*lstat_control.counts[cpu])[write_index].
+					max_wait_ww_ticks) {
+				(*lstat_control.counts[cpu])[write_index].
+					max_wait_ww_ticks = spin_ticks;
+			}
+		}
+
+		/* save the directory index for use on write_unlock */
+		(*lstat_control.read_lock_counts[cpu])[index].
+			write_index = write_index;
+	}
+}
+
+void
+_metered_write_unlock(rwlock_t * rwlock_ptr)
+{
+	int index;
+	int cpu;
+	int write_index;
+	uint32_t hold_time;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_write_unlock(rwlock_ptr);
+		return;
+	}
+
+	cpu = THIS_CPU_NUMBER;
+	index = GET_RWINDEX(rwlock_ptr);
+
+	/* update statistics if stats enabled for this lock */
+	if (index > 0) {
+		write_index =
+		    (*lstat_control.read_lock_counts[cpu])[index].write_index;
+
+		hold_time = get_cycles() -
+			(*lstat_control.counts[cpu])[write_index].acquire_time;
+		(*lstat_control.counts[cpu])[write_index].cum_hold_ticks +=
+			(uint64_t) hold_time;
+		if ((*lstat_control.counts[cpu])[write_index].max_hold_ticks <
+				hold_time)
+			(*lstat_control.counts[cpu])[write_index].
+				max_hold_ticks = hold_time;
+	}
+	_raw_write_unlock(rwlock_ptr);
+}
+
+int
+_metered_write_trylock(rwlock_t * rwlock_ptr)
+{
+	int retval;
+	void *this_pc = LSTAT_RA(LSTAT_RA_WRITE);
+
+	if ((retval = _raw_write_trylock(rwlock_ptr))) {
+		lstat_update(rwlock_ptr, this_pc, LSTAT_ACT_NO_WAIT);
+	} else {
+		lstat_update(rwlock_ptr, this_pc, LSTAT_ACT_REJECT);
+	}
+
+	return retval;
+}
+
+static void
+init_control_space(void)
+{
+	/* Set all control space pointers to null and indices to "empty" */
+	int cpu;
+
+	/*
+	 * Access CPU_CYCLE_FREQUENCY at the outset, which in some
+	 * architectures may trigger a runtime calculation that uses a
+	 * spinlock.  Let's do this before lockmetering is turned on.
+	 */
+	if (CPU_CYCLE_FREQUENCY == 0)
+		BUG();
+
+	lstat_control.hashtab = NULL;
+	lstat_control.dir = NULL;
+	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+		lstat_control.counts[cpu] = NULL;
+		lstat_control.read_lock_counts[cpu] = NULL;
+	}
+}
+
+static int
+reset_lstat_data(void)
+{
+	int cpu, flags;
+
+	flags = 0;
+	lstat_control.next_free_dir_index = 1;	/* 0 is for overflows */
+	lstat_control.next_free_read_lock_index = 1;
+	lstat_control.dir_overflow = 0;
+	lstat_control.rwlock_overflow = 0;
+
+	lstat_control.started_cycles64 = 0;
+	lstat_control.ending_cycles64 = 0;
+	lstat_control.enabled_cycles64 = 0;
+	lstat_control.first_started_time = 0;
+	lstat_control.started_time = 0;
+	lstat_control.ending_time = 0;
+	lstat_control.intervals = 0;
+
+	/*
+	 * paranoia -- in case someone does a "lockstat reset" before
+	 * "lockstat on"
+	 */
+	if (lstat_control.hashtab) {
+		bzero(lstat_control.hashtab,
+			LSTAT_HASH_TABLE_SIZE * sizeof (short));
+		bzero(lstat_control.dir, LSTAT_MAX_STAT_INDEX *
+				sizeof (lstat_directory_entry_t));
+
+		for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+			bzero(lstat_control.counts[cpu],
+				sizeof (lstat_cpu_counts_t));
+			bzero(lstat_control.read_lock_counts[cpu],
+				sizeof (lstat_read_lock_cpu_counts_t));
+		}
+	}
+#ifdef NOTDEF
+	_raw_spin_unlock(&lstat_control.directory_lock);
+	local_irq_restore(flags);
+#endif
+	return 1;
+}
+
+static void
+release_control_space(void)
+{
+	/*
+	 * Called when either (1) allocation of kmem
+	 * or (2) when user writes LSTAT_RELEASE to /pro/lockmeter.
+	 * Assume that all pointers have been initialized to zero,
+	 * i.e., nonzero pointers are valid addresses.
+	 */
+	int cpu;
+
+	if (lstat_control.hashtab) {
+		kfree(lstat_control.hashtab);
+		lstat_control.hashtab = NULL;
+	}
+
+	if (lstat_control.dir) {
+		vfree(lstat_control.dir);
+		lstat_control.dir = NULL;
+	}
+
+	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+		if (lstat_control.counts[cpu]) {
+			vfree(lstat_control.counts[cpu]);
+			lstat_control.counts[cpu] = NULL;
+		}
+		if (lstat_control.read_lock_counts[cpu]) {
+			kfree(lstat_control.read_lock_counts[cpu]);
+			lstat_control.read_lock_counts[cpu] = NULL;
+		}
+	}
+}
+
+int
+get_lockmeter_info_size(void)
+{
+	return sizeof (lstat_user_request_t)
+		+ num_online_cpus() * sizeof (lstat_cpu_counts_t)
+		+ num_online_cpus() * sizeof (lstat_read_lock_cpu_counts_t)
+		+ (LSTAT_MAX_STAT_INDEX * sizeof (lstat_directory_entry_t));
+}
+
+ssize_t
+get_lockmeter_info(char *buffer, size_t max_len, loff_t * last_index)
+{
+	lstat_user_request_t req;
+	struct timeval tv;
+	ssize_t next_ret_bcount;
+	ssize_t actual_ret_bcount = 0;
+	int cpu;
+
+	*last_index = 0;	/* a one-shot read */
+
+	req.lstat_version = LSTAT_VERSION;
+	req.state = lstat_control.state;
+	req.maxcpus = num_online_cpus();
+	req.cycleval = CPU_CYCLE_FREQUENCY;
+#ifdef notyet
+	req.kernel_magic_addr = (void *) &_etext;
+	req.kernel_end_addr = (void *) &_etext;
+#endif
+	req.uts = system_utsname;
+	req.intervals = lstat_control.intervals;
+
+	req.first_started_time = lstat_control.first_started_time;
+	req.started_time = lstat_control.started_time;
+	req.started_cycles64 = lstat_control.started_cycles64;
+
+	req.next_free_dir_index = lstat_control.next_free_dir_index;
+	req.next_free_read_lock_index = lstat_control.next_free_read_lock_index;
+	req.dir_overflow = lstat_control.dir_overflow;
+	req.rwlock_overflow = lstat_control.rwlock_overflow;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		if (req.intervals == 0) {
+			/* mesasurement is off and no valid data present */
+			next_ret_bcount = sizeof (lstat_user_request_t);
+			req.enabled_cycles64 = 0;
+
+			if ((actual_ret_bcount + next_ret_bcount) > max_len)
+				return actual_ret_bcount;
+
+			copy_to_user(buffer, (void *) &req, next_ret_bcount);
+			actual_ret_bcount += next_ret_bcount;
+			return actual_ret_bcount;
+		} else {
+			/*
+			 * measurement is off but valid data present
+			 * fetch time info from lstat_control
+			 */
+			req.ending_time = lstat_control.ending_time;
+			req.ending_cycles64 = lstat_control.ending_cycles64;
+			req.enabled_cycles64 = lstat_control.enabled_cycles64;
+		}
+	} else {
+		/*
+		 * this must be a read while data active--use current time,
+		 * etc
+		 */
+		do_gettimeofday(&tv);
+		req.ending_time = tv.tv_sec;
+		req.ending_cycles64 = get_cycles64();
+		req.enabled_cycles64 = req.ending_cycles64 -
+			req.started_cycles64 + lstat_control.enabled_cycles64;
+	}
+
+	next_ret_bcount = sizeof (lstat_user_request_t);
+	if ((actual_ret_bcount + next_ret_bcount) > max_len)
+		return actual_ret_bcount;
+
+	copy_to_user(buffer, (void *) &req, next_ret_bcount);
+	actual_ret_bcount += next_ret_bcount;
+
+	if (!lstat_control.counts[0])	/* not initialized? */
+		return actual_ret_bcount;
+
+	next_ret_bcount = sizeof (lstat_cpu_counts_t);
+	for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+		if ((actual_ret_bcount + next_ret_bcount) > max_len)
+			return actual_ret_bcount;	/* leave early */
+		copy_to_user(buffer + actual_ret_bcount,
+				lstat_control.counts[cpu], next_ret_bcount);
+		actual_ret_bcount += next_ret_bcount;
+	}
+
+	next_ret_bcount = LSTAT_MAX_STAT_INDEX *
+			sizeof (lstat_directory_entry_t);
+	if (((actual_ret_bcount + next_ret_bcount) > max_len)
+			|| !lstat_control.dir)
+		return actual_ret_bcount;	/* leave early */
+
+	copy_to_user(buffer + actual_ret_bcount, lstat_control.dir,
+			next_ret_bcount);
+	actual_ret_bcount += next_ret_bcount;
+
+	next_ret_bcount = sizeof (lstat_read_lock_cpu_counts_t);
+	for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+		if (actual_ret_bcount + next_ret_bcount > max_len)
+			return actual_ret_bcount;
+		copy_to_user(buffer + actual_ret_bcount,
+				lstat_control.read_lock_counts[cpu],
+				next_ret_bcount);
+		actual_ret_bcount += next_ret_bcount;
+	}
+
+	return actual_ret_bcount;
+}
+
+/*
+ *  Writing to the /proc lockmeter node enables or disables metering.
+ *  based upon the first byte of the "written" data.
+ *  The following values are defined:
+ *  LSTAT_ON: 1st call: allocates storage, intializes and turns on measurement
+ *            subsequent calls just turn on measurement
+ *  LSTAT_OFF: turns off measurement
+ *  LSTAT_RESET: resets statistics
+ *  LSTAT_RELEASE: releases statistics storage
+ *
+ *  This allows one to accumulate statistics over several lockstat runs:
+ *
+ *  lockstat on
+ *  lockstat off
+ *  ...repeat above as desired...
+ *  lockstat get
+ *  ...now start a new set of measurements...
+ *  lockstat reset
+ *  lockstat on
+ *  ...
+ *
+ */
+ssize_t
+put_lockmeter_info(const char *buffer, size_t len)
+{
+	int error = 0;
+	int dirsize, countsize, read_lock_countsize, hashsize;
+	int cpu;
+	char put_char;
+	int i, read_lock_blocks;
+	unsigned long flags;
+	rwlock_t *lock_ptr;
+	struct timeval tv;
+
+	if (len <= 0)
+		return -EINVAL;
+
+	_raw_spin_lock(&lstat_control.control_lock);
+
+	get_user(put_char, buffer);
+	switch (put_char) {
+
+	case LSTAT_OFF:
+		if (lstat_control.state != LSTAT_OFF) {
+			/*
+			 * To avoid seeing read lock hold times in an
+			 * inconsisent state, we have to follow this protocol
+			 * to turn off statistics
+			 */
+			local_irq_save(flags);
+			/*
+			 * getting this lock will stop any read lock block
+			 * allocations
+			 */
+			_raw_spin_lock(&lstat_control.directory_lock);
+			/*
+			 * keep any more read lock blocks from being
+			 * allocated
+			 */
+			lstat_control.state = LSTAT_OFF;
+			/* record how may read lock blocks there are */
+			read_lock_blocks =
+				lstat_control.next_free_read_lock_index;
+			_raw_spin_unlock(&lstat_control.directory_lock);
+			/* now go through the list of read locks */
+			cpu = THIS_CPU_NUMBER;
+			for (i = 1; i < read_lock_blocks; i++) {
+				lock_ptr =
+				    (*lstat_control.read_lock_counts[cpu])[i].
+				    lock_ptr;
+				/* is this saved lock address still valid? */
+				if (GET_RWINDEX(lock_ptr) == i) {
+					/*
+					 * lock address appears to still be
+					 * valid because we only hold one lock
+					 * at a time, this can't cause a
+					 * deadlock unless this is a lock held
+					 * as part of the current system call
+					 * path. At the moment there
+					 * are no READ mode locks held to get
+					 * here from user space, so we solve
+					 * this by skipping locks held in
+					 * write mode.
+					 */
+					if (RWLOCK_IS_WRITE_LOCKED(lock_ptr)) {
+						PUT_RWINDEX(lock_ptr, 0);
+						continue;
+					}
+					/*
+					 * now we know there are no read
+					 * holders of this lock! stop
+					 * statistics collection for this
+					 * lock
+					 */
+					_raw_write_lock(lock_ptr);
+					PUT_RWINDEX(lock_ptr, 0);
+					_raw_write_unlock(lock_ptr);
+				}
+				/*
+				 * it may still be possible for the hold time
+				 * sum to be negative e.g. if a lock is
+				 * reallocated while "busy" we will have to fix
+				 * this up in the data reduction program.
+				 */
+			}
+			local_irq_restore(flags);
+			lstat_control.intervals++;
+			lstat_control.ending_cycles64 = get_cycles64();
+			lstat_control.enabled_cycles64 +=
+				lstat_control.ending_cycles64 -
+				lstat_control.started_cycles64;
+			do_gettimeofday(&tv);
+			lstat_control.ending_time = tv.tv_sec;
+			/*
+			 * don't deallocate the structures -- we may do a
+			 * lockstat on to add to the data that is already
+			 * there. Use LSTAT_RELEASE to release storage
+			 */
+		} else {
+			error = -EBUSY;	/* already OFF */
+		}
+		break;
+
+	case LSTAT_ON:
+		if (lstat_control.state == LSTAT_OFF) {
+#ifdef DEBUG_LOCKMETER
+			printk("put_lockmeter_info(cpu=%d): LSTAT_ON\n",
+				THIS_CPU_NUMBER);
+#endif
+			lstat_control.next_free_dir_index = 1;	/* 0 is for overflows */
+
+			dirsize = LSTAT_MAX_STAT_INDEX *
+					sizeof (lstat_directory_entry_t);
+			hashsize =
+				(1 + LSTAT_HASH_TABLE_SIZE) * sizeof (ushort);
+			countsize = sizeof (lstat_cpu_counts_t);
+			read_lock_countsize =
+				sizeof (lstat_read_lock_cpu_counts_t);
+#ifdef DEBUG_LOCKMETER
+			printk(" dirsize:%d", dirsize);
+			printk(" hashsize:%d", hashsize);
+			printk(" countsize:%d", countsize);
+			printk(" read_lock_countsize:%d\n",
+				read_lock_countsize);
+#endif
+#ifdef DEBUG_LOCKMETER
+			{
+				int secs;
+				unsigned long cycles;
+				uint64_t cycles64;
+
+				do_gettimeofday(&tv);
+				secs = tv.tv_sec;
+				do {
+					do_gettimeofday(&tv);
+				} while (secs == tv.tv_sec);
+				cycles = get_cycles();
+				cycles64 = get_cycles64();
+				secs = tv.tv_sec;
+				do {
+					do_gettimeofday(&tv);
+				} while (secs == tv.tv_sec);
+				cycles = get_cycles() - cycles;
+				cycles64 = get_cycles64() - cycles;
+				printk("lockmeter: cycleFrequency:%d "
+					"cycles:%d cycles64:%d\n",
+					CPU_CYCLE_FREQUENCY, cycles, cycles64);
+			}
+#endif
+
+			/*
+			 * if this is the first call, allocate storage and
+			 * initialize
+			 */
+			if (!lstat_control.hashtab) {
+
+				spin_lock_init(&lstat_control.directory_lock);
+
+				/* guarantee all pointers at zero */
+				init_control_space();
+
+				lstat_control.hashtab =
+				    kmalloc(hashsize, GFP_KERNEL);
+				if (!lstat_control.hashtab) {
+					error = -ENOSPC;
+#ifdef DEBUG_LOCKMETER
+					printk("!!error kmalloc of hashtab\n");
+#endif
+				}
+				lstat_control.dir = vmalloc(dirsize);
+				if (!lstat_control.dir) {
+					error = -ENOSPC;
+#ifdef DEBUG_LOCKMETER
+					printk("!!error kmalloc of dir\n");
+#endif
+				}
+
+				for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+					lstat_control.counts[cpu] =
+						vmalloc(countsize);
+					if (!lstat_control.counts[cpu]) {
+						error = -ENOSPC;
+#ifdef DEBUG_LOCKMETER
+						printk("!!error vmalloc of "
+							"counts[%d]\n", cpu);
+#endif
+					}
+					lstat_control.read_lock_counts[cpu] =
+						(lstat_read_lock_cpu_counts_t *)
+						kmalloc(read_lock_countsize,
+							GFP_KERNEL);
+					if (!lstat_control.
+							read_lock_counts[cpu]) {
+						error = -ENOSPC;
+#ifdef DEBUG_LOCKMETER
+						printk("!!error kmalloc of "
+						  "read_lock_counts[%d]\n",
+							cpu);
+#endif
+					}
+				}
+			}
+
+			if (error) {
+				/*
+				 * One or more kmalloc failures -- free
+				 * everything
+				 */
+				release_control_space();
+			} else {
+
+				if (!reset_lstat_data()) {
+					error = -EINVAL;
+					break;
+				};
+
+				/*
+				 * record starting and ending times and the
+				 * like
+				 */
+				if (lstat_control.intervals == 0) {
+					do_gettimeofday(&tv);
+					lstat_control.first_started_time =
+						tv.tv_sec;
+				}
+				lstat_control.started_cycles64 = get_cycles64();
+				do_gettimeofday(&tv);
+				lstat_control.started_time = tv.tv_sec;
+
+				lstat_control.state = LSTAT_ON;
+			}
+		} else {
+			error = -EBUSY;	/* already ON */
+		}
+		break;
+
+	case LSTAT_RESET:
+		if (lstat_control.state == LSTAT_OFF) {
+			if (!reset_lstat_data())
+				error = -EINVAL;
+		} else {
+			error = -EBUSY;	/* still on; can't reset */
+		}
+		break;
+
+	case LSTAT_RELEASE:
+		if (lstat_control.state == LSTAT_OFF) {
+			release_control_space();
+			lstat_control.intervals = 0;
+			lstat_control.enabled_cycles64 = 0;
+		} else {
+			error = -EBUSY;
+		}
+		break;
+
+	default:
+		error = -EINVAL;
+	}			/* switch */
+
+	_raw_spin_unlock(&lstat_control.control_lock);
+	return error ? error : len;
+}
+
+#ifdef USER_MODE_TESTING
+/* following used for user mode testing */
+void
+lockmeter_init()
+{
+	int dirsize, hashsize, countsize, read_lock_countsize, cpu;
+
+	printf("lstat_control is at %x size=%d\n", &lstat_control,
+		sizeof (lstat_control));
+	printf("sizeof(spinlock_t)=%d\n", sizeof (spinlock_t));
+	lstat_control.state = LSTAT_ON;
+
+	lstat_control.directory_lock = SPIN_LOCK_UNLOCKED;
+	lstat_control.next_free_dir_index = 1;	/* 0 is for overflows */
+	lstat_control.next_free_read_lock_index = 1;
+
+	dirsize = LSTAT_MAX_STAT_INDEX * sizeof (lstat_directory_entry_t);
+	hashsize = (1 + LSTAT_HASH_TABLE_SIZE) * sizeof (ushort);
+	countsize = sizeof (lstat_cpu_counts_t);
+	read_lock_countsize = sizeof (lstat_read_lock_cpu_counts_t);
+
+	lstat_control.hashtab = (ushort *) malloc(hashsize);
+
+	if (lstat_control.hashtab == 0) {
+		printf("malloc failure for at line %d in lockmeter.c\n",
+			__LINE__);
+		exit(0);
+	}
+
+	lstat_control.dir = (lstat_directory_entry_t *) malloc(dirsize);
+
+	if (lstat_control.dir == 0) {
+		printf("malloc failure for at line %d in lockmeter.c\n", cpu,
+			__LINE__);
+		exit(0);
+	}
+
+	for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+		int j, k;
+		j = (int) (lstat_control.counts[cpu] =
+			   (lstat_cpu_counts_t *) malloc(countsize));
+		k = (int) (lstat_control.read_lock_counts[cpu] =
+			   (lstat_read_lock_cpu_counts_t *)
+			   malloc(read_lock_countsize));
+		if (j * k == 0) {
+			printf("malloc failure for cpu=%d at line %d in "
+				"lockmeter.c\n", cpu, __LINE__);
+			exit(0);
+		}
+	}
+
+	memset(lstat_control.hashtab, 0, hashsize);
+	memset(lstat_control.dir, 0, dirsize);
+
+	for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+		memset(lstat_control.counts[cpu], 0, countsize);
+		memset(lstat_control.read_lock_counts[cpu], 0,
+			read_lock_countsize);
+	}
+}
+
+asm(" \
+.align	4 \
+.globl	__write_lock_failed \
+__write_lock_failed: \
+	" LOCK "addl	$" RW_LOCK_BIAS_STR ",(%eax) \
+1:	cmpl	$" RW_LOCK_BIAS_STR ",(%eax) \
+	jne	1b \
+\
+	" LOCK "subl	$" RW_LOCK_BIAS_STR ",(%eax) \
+	jnz	__write_lock_failed \
+	ret \
+\
+\
+.align	4 \
+.globl	__read_lock_failed \
+__read_lock_failed: \
+	lock ; incl	(%eax) \
+1:	cmpl	$1,(%eax) \
+	js	1b \
+\
+	lock ; decl	(%eax) \
+	js	__read_lock_failed \
+	ret \
+");
+#endif
+
+EXPORT_SYMBOL(_metered_spin_lock);
+EXPORT_SYMBOL(_metered_spin_unlock);
+EXPORT_SYMBOL(_metered_spin_trylock);
+EXPORT_SYMBOL(_metered_read_lock);
+EXPORT_SYMBOL(_metered_read_unlock);
+EXPORT_SYMBOL(_metered_write_lock);
+EXPORT_SYMBOL(_metered_write_unlock);
--- diff/kernel/stop_machine.c	1970-01-01 01:00:00.000000000 +0100
+++ source/kernel/stop_machine.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,200 @@
+#include <linux/stop_machine.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/syscalls.h>
+#include <asm/atomic.h>
+#include <asm/semaphore.h>
+
+/* Since we effect priority and affinity (both of which are visible
+ * to, and settable by outside processes) we do indirection via a
+ * kthread. */
+
+/* Thread to stop each CPU in user context. */
+enum stopmachine_state {
+	STOPMACHINE_WAIT,
+	STOPMACHINE_PREPARE,
+	STOPMACHINE_DISABLE_IRQ,
+	STOPMACHINE_EXIT,
+};
+
+static enum stopmachine_state stopmachine_state;
+static unsigned int stopmachine_num_threads;
+static atomic_t stopmachine_thread_ack;
+static DECLARE_MUTEX(stopmachine_mutex);
+
+static int stopmachine(void *cpu)
+{
+	int irqs_disabled = 0;
+	int prepared = 0;
+
+	set_cpus_allowed(current, cpumask_of_cpu((int)(long)cpu));
+
+	/* Ack: we are alive */
+	mb(); /* Theoretically the ack = 0 might not be on this CPU yet. */
+	atomic_inc(&stopmachine_thread_ack);
+
+	/* Simple state machine */
+	while (stopmachine_state != STOPMACHINE_EXIT) {
+		if (stopmachine_state == STOPMACHINE_DISABLE_IRQ
+		    && !irqs_disabled) {
+			local_irq_disable();
+			irqs_disabled = 1;
+			/* Ack: irqs disabled. */
+			mb(); /* Must read state first. */
+			atomic_inc(&stopmachine_thread_ack);
+		} else if (stopmachine_state == STOPMACHINE_PREPARE
+			   && !prepared) {
+			/* Everyone is in place, hold CPU. */
+			preempt_disable();
+			prepared = 1;
+			mb(); /* Must read state first. */
+			atomic_inc(&stopmachine_thread_ack);
+		}
+		cpu_relax();
+	}
+
+	/* Ack: we are exiting. */
+	mb(); /* Must read state first. */
+	atomic_inc(&stopmachine_thread_ack);
+
+	if (irqs_disabled)
+		local_irq_enable();
+	if (prepared)
+		preempt_enable();
+
+	return 0;
+}
+
+/* Change the thread state */
+static void stopmachine_set_state(enum stopmachine_state state)
+{
+	atomic_set(&stopmachine_thread_ack, 0);
+	wmb();
+	stopmachine_state = state;
+	while (atomic_read(&stopmachine_thread_ack) != stopmachine_num_threads)
+		cpu_relax();
+}
+
+static int stop_machine(void)
+{
+	int i, ret = 0;
+	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
+
+	/* One high-prio thread per cpu.  We'll do this one. */
+	sys_sched_setscheduler(current->pid, SCHED_FIFO, &param);
+
+	atomic_set(&stopmachine_thread_ack, 0);
+	stopmachine_num_threads = 0;
+	stopmachine_state = STOPMACHINE_WAIT;
+
+	for_each_online_cpu(i) {
+		if (i == smp_processor_id())
+			continue;
+		ret = kernel_thread(stopmachine, (void *)(long)i,CLONE_KERNEL);
+		if (ret < 0)
+			break;
+		stopmachine_num_threads++;
+	}
+
+	/* Wait for them all to come to life. */
+	while (atomic_read(&stopmachine_thread_ack) != stopmachine_num_threads)
+		yield();
+
+	/* If some failed, kill them all. */
+	if (ret < 0) {
+		stopmachine_set_state(STOPMACHINE_EXIT);
+		up(&stopmachine_mutex);
+		return ret;
+	}
+
+	/* Don't schedule us away at this point, please. */
+	local_irq_disable();
+
+	/* Now they are all started, make them hold the CPUs, ready. */
+	stopmachine_set_state(STOPMACHINE_PREPARE);
+
+	/* Make them disable irqs. */
+	stopmachine_set_state(STOPMACHINE_DISABLE_IRQ);
+
+	return 0;
+}
+
+static void restart_machine(void)
+{
+	stopmachine_set_state(STOPMACHINE_EXIT);
+	local_irq_enable();
+}
+
+struct stop_machine_data
+{
+	int (*fn)(void *);
+	void *data;
+	struct completion done;
+};
+
+static int do_stop(void *_smdata)
+{
+	struct stop_machine_data *smdata = _smdata;
+	int ret;
+
+	ret = stop_machine();
+	if (ret == 0) {
+		ret = smdata->fn(smdata->data);
+		restart_machine();
+	}
+
+	/* We're done: you can kthread_stop us now */
+	complete(&smdata->done);
+
+	/* Wait for kthread_stop */
+	while (!kthread_should_stop()) {
+		__set_current_state(TASK_INTERRUPTIBLE);
+		schedule();
+	}
+	return ret;
+}
+
+struct task_struct *__stop_machine_run(int (*fn)(void *), void *data,
+				       unsigned int cpu)
+{
+	struct stop_machine_data smdata;
+	struct task_struct *p;
+
+	smdata.fn = fn;
+	smdata.data = data;
+	init_completion(&smdata.done);
+
+	down(&stopmachine_mutex);
+
+	/* If they don't care which CPU fn runs on, bind to any online one. */
+	if (cpu == NR_CPUS)
+		cpu = smp_processor_id();
+
+	p = kthread_create(do_stop, &smdata, "kstopmachine");
+	if (!IS_ERR(p)) {
+		kthread_bind(p, cpu);
+		wake_up_process(p);
+		wait_for_completion(&smdata.done);
+	}
+	up(&stopmachine_mutex);
+	return p;
+}
+
+int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu)
+{
+	struct task_struct *p;
+	int ret;
+
+	/* No CPUs can come up or down during this. */
+	lock_cpu_hotplug();
+	p = __stop_machine_run(fn, data, cpu);
+	if (!IS_ERR(p))
+		ret = kthread_stop(p);
+	else
+		ret = PTR_ERR(p);
+	unlock_cpu_hotplug();
+
+	return ret;
+}
--- diff/mm/usercopy.c	1970-01-01 01:00:00.000000000 +0100
+++ source/mm/usercopy.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,291 @@
+/*
+ * linux/mm/usercopy.c
+ *
+ * (C) Copyright 2003 Ingo Molnar
+ *
+ * Generic implementation of all the user-VM access functions, without
+ * relying on being able to access the VM directly.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/smp_lock.h>
+#include <linux/ptrace.h>
+#include <linux/interrupt.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/atomic_kmap.h>
+
+/*
+ * Get kernel address of the user page and pin it.
+ */
+static inline struct page *pin_page(unsigned long addr, int write)
+{
+	struct mm_struct *mm = current->mm ? : &init_mm;
+	struct page *page = NULL;
+	int ret;
+
+	/*
+	 * Do a quick atomic lookup first - this is the fastpath.
+	 */
+retry:
+	page = follow_page(mm, addr, write);
+	if (likely(page != NULL)) {
+		if (!PageReserved(page))
+			get_page(page);
+		return page;
+	}
+
+	/*
+	 * No luck - bad address or need to fault in the page:
+	 */
+
+	/* Release the lock so get_user_pages can sleep */
+	spin_unlock(&mm->page_table_lock);
+
+	/*
+	 * In the context of filemap_copy_from_user(), we are not allowed
+	 * to sleep.  We must fail this usercopy attempt and allow
+	 * filemap_copy_from_user() to recover: drop its atomic kmap and use
+	 * a sleeping kmap instead.
+	 */
+	if (in_atomic()) {
+		spin_lock(&mm->page_table_lock);
+		return NULL;
+	}
+
+	down_read(&mm->mmap_sem);
+	ret = get_user_pages(current, mm, addr, 1, write, 0, NULL, NULL);
+	up_read(&mm->mmap_sem);
+	spin_lock(&mm->page_table_lock);
+
+	if (ret <= 0)
+		return NULL;
+
+	/*
+	 * Go try the follow_page again.
+	 */
+	goto retry;
+}
+
+static inline void unpin_page(struct page *page)
+{
+	put_page(page);
+}
+
+/*
+ * 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 rw_vm(unsigned long addr, void *buf, int len, int write)
+{
+	struct mm_struct *mm = current->mm ? : &init_mm;
+
+	if (!len)
+		return 0;
+
+	spin_lock(&mm->page_table_lock);
+
+	/* ignore errors, just check how much was sucessfully transfered */
+	while (len) {
+		struct page *page = NULL;
+		int bytes, offset;
+		void *maddr;
+
+		page = pin_page(addr, write);
+		if (!page)
+			break;
+
+		bytes = len;
+		offset = addr & (PAGE_SIZE-1);
+		if (bytes > PAGE_SIZE-offset)
+			bytes = PAGE_SIZE-offset;
+
+		maddr = kmap_atomic(page, KM_USER_COPY);
+
+#define HANDLE_TYPE(type) \
+	case sizeof(type): *(type *)(maddr+offset) = *(type *)(buf); break;
+
+		if (write) {
+			switch (bytes) {
+			HANDLE_TYPE(char);
+			HANDLE_TYPE(int);
+			HANDLE_TYPE(long long);
+			default:
+				memcpy(maddr + offset, buf, bytes);
+			}
+		} else {
+#undef HANDLE_TYPE
+#define HANDLE_TYPE(type) \
+	case sizeof(type): *(type *)(buf) = *(type *)(maddr+offset); break;
+			switch (bytes) {
+			HANDLE_TYPE(char);
+			HANDLE_TYPE(int);
+			HANDLE_TYPE(long long);
+			default:
+				memcpy(buf, maddr + offset, bytes);
+			}
+#undef HANDLE_TYPE
+		}
+		kunmap_atomic(maddr, KM_USER_COPY);
+		unpin_page(page);
+		len -= bytes;
+		buf += bytes;
+		addr += bytes;
+	}
+	spin_unlock(&mm->page_table_lock);
+
+	return len;
+}
+
+static int str_vm(unsigned long addr, void *buf0, int len, int copy)
+{
+	struct mm_struct *mm = current->mm ? : &init_mm;
+	struct page *page;
+	void *buf = buf0;
+
+	if (!len)
+		return len;
+
+	spin_lock(&mm->page_table_lock);
+
+	/* ignore errors, just check how much was sucessfully transfered */
+	while (len) {
+		int bytes, offset, left, copied;
+		char *maddr;
+
+		page = pin_page(addr, copy == 2);
+		if (!page) {
+			spin_unlock(&mm->page_table_lock);
+			return -EFAULT;
+		}
+		bytes = len;
+		offset = addr & (PAGE_SIZE-1);
+		if (bytes > PAGE_SIZE-offset)
+			bytes = PAGE_SIZE-offset;
+
+		maddr = kmap_atomic(page, KM_USER_COPY);
+		if (copy == 2) {
+			memset(maddr + offset, 0, bytes);
+			copied = bytes;
+			left = 0;
+		} else if (copy == 1) {
+			left = strncpy_count(buf, maddr + offset, bytes);
+			copied = bytes - left;
+		} else {
+			copied = strnlen(maddr + offset, bytes);
+			left = bytes - copied;
+		}
+		BUG_ON(bytes < 0 || copied < 0);
+		kunmap_atomic(maddr, KM_USER_COPY);
+		unpin_page(page);
+		len -= copied;
+		buf += copied;
+		addr += copied;
+		if (left)
+			break;
+	}
+	spin_unlock(&mm->page_table_lock);
+
+	return len;
+}
+
+/*
+ * Copies memory from userspace (ptr) into kernelspace (val).
+ *
+ * returns # of bytes not copied.
+ */
+int get_user_size(unsigned int size, void *val, const void *ptr)
+{
+	int ret;
+
+	if (unlikely(segment_eq(get_fs(), KERNEL_DS)))
+		ret = __direct_copy_from_user(val, ptr, size);
+	else
+		ret = rw_vm((unsigned long)ptr, val, size, 0);
+	if (ret)
+		/*
+		 * Zero the rest:
+		 */
+		memset(val + size - ret, 0, ret);
+	return ret;
+}
+
+/*
+ * Copies memory from kernelspace (val) into userspace (ptr).
+ *
+ * returns # of bytes not copied.
+ */
+int put_user_size(unsigned int size, const void *val, void *ptr)
+{
+	if (unlikely(segment_eq(get_fs(), KERNEL_DS)))
+		return __direct_copy_to_user(ptr, val, size);
+	else
+		return rw_vm((unsigned long)ptr, (void *)val, size, 1);
+}
+
+int copy_str_fromuser_size(unsigned int size, void *val, const void *ptr)
+{
+	int copied, left;
+
+	if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
+		left = strncpy_count(val, ptr, size);
+		copied = size - left;
+		BUG_ON(copied < 0);
+
+		return copied;
+	}
+	left = str_vm((unsigned long)ptr, val, size, 1);
+	if (left < 0)
+		return left;
+	copied = size - left;
+	BUG_ON(copied < 0);
+
+	return copied;
+}
+
+int strlen_fromuser_size(unsigned int size, const void *ptr)
+{
+	int copied, left;
+
+	if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
+		copied = strnlen(ptr, size) + 1;
+		BUG_ON(copied < 0);
+
+		return copied;
+	}
+	left = str_vm((unsigned long)ptr, NULL, size, 0);
+	if (left < 0)
+		return 0;
+	copied = size - left + 1;
+	BUG_ON(copied < 0);
+
+	return copied;
+}
+
+int zero_user_size(unsigned int size, void *ptr)
+{
+	int left;
+
+	if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
+		memset(ptr, 0, size);
+		return 0;
+	}
+	left = str_vm((unsigned long)ptr, NULL, size, 2);
+	if (left < 0)
+		return size;
+	return left;
+}
+
+EXPORT_SYMBOL(get_user_size);
+EXPORT_SYMBOL(put_user_size);
+EXPORT_SYMBOL(zero_user_size);
+EXPORT_SYMBOL(copy_str_fromuser_size);
+EXPORT_SYMBOL(strlen_fromuser_size);
+
--- diff/net/core/netpoll.c	1970-01-01 01:00:00.000000000 +0100
+++ source/net/core/netpoll.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,651 @@
+/*
+ * Common framework for low-level network console, dump, and debugger code
+ *
+ * Sep 8 2003  Matt Mackall <mpm@selenic.com>
+ */
+
+#include <linux/smp_lock.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/string.h>
+#include <linux/inetdevice.h>
+#include <linux/inet.h>
+#include <linux/interrupt.h>
+#include <linux/netpoll.h>
+#include <linux/sched.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+
+/*
+ * We maintain a small pool of fully-sized skbs, to make sure the
+ * message gets out even in extreme OOM situations.
+ */
+
+#define MAX_SKBS 32
+#define MAX_UDP_CHUNK 1460
+
+static spinlock_t skb_list_lock = SPIN_LOCK_UNLOCKED;
+static int nr_skbs;
+static struct sk_buff *skbs;
+
+static spinlock_t rx_list_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(rx_list);
+
+static int trapped;
+
+#define MAX_SKB_SIZE \
+		(MAX_UDP_CHUNK + sizeof(struct udphdr) + \
+				sizeof(struct iphdr) + sizeof(struct ethhdr))
+
+static void zap_completion_queue(void);
+
+static int checksum_udp(struct sk_buff *skb, struct udphdr *uh,
+			     unsigned short ulen, u32 saddr, u32 daddr)
+{
+	if (uh->check == 0)
+		return 0;
+
+	if (skb->ip_summed == CHECKSUM_HW)
+		return csum_tcpudp_magic(
+			saddr, daddr, ulen, IPPROTO_UDP, skb->csum);
+
+	skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);
+
+	return csum_fold(skb_checksum(skb, 0, skb->len, skb->csum));
+}
+
+void netpoll_poll(struct netpoll *np)
+{
+	int budget = 1;
+
+	if(!np->dev || !netif_running(np->dev) || !np->dev->poll_controller)
+		return;
+
+	/* Process pending work on NIC */
+	np->dev->poll_controller(np->dev);
+
+	/* If scheduling is stopped, tickle NAPI bits */
+	if(trapped && np->dev->poll &&
+	   test_bit(__LINK_STATE_RX_SCHED, &np->dev->state))
+		np->dev->poll(np->dev, &budget);
+	zap_completion_queue();
+}
+
+static void refill_skbs(void)
+{
+	struct sk_buff *skb;
+	unsigned long flags;
+
+	spin_lock_irqsave(&skb_list_lock, flags);
+	while (nr_skbs < MAX_SKBS) {
+		skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC);
+		if (!skb)
+			break;
+
+		skb->next = skbs;
+		skbs = skb;
+		nr_skbs++;
+	}
+	spin_unlock_irqrestore(&skb_list_lock, flags);
+}
+
+static void zap_completion_queue(void)
+{
+	unsigned long flags;
+	struct softnet_data *sd = &get_cpu_var(softnet_data);
+
+	if (sd->completion_queue) {
+		struct sk_buff *clist;
+
+		local_irq_save(flags);
+		clist = sd->completion_queue;
+		sd->completion_queue = NULL;
+		local_irq_restore(flags);
+
+		while (clist != NULL) {
+			struct sk_buff *skb = clist;
+			clist = clist->next;
+			__kfree_skb(skb);
+		}
+	}
+
+	put_cpu_var(softnet_data);
+}
+
+static struct sk_buff * find_skb(struct netpoll *np, int len, int reserve)
+{
+	int once = 1, count = 0;
+	unsigned long flags;
+	struct sk_buff *skb = NULL;
+
+	zap_completion_queue();
+repeat:
+	if (nr_skbs < MAX_SKBS)
+		refill_skbs();
+
+	skb = alloc_skb(len, GFP_ATOMIC);
+
+	if (!skb) {
+		spin_lock_irqsave(&skb_list_lock, flags);
+		skb = skbs;
+		if (skb)
+			skbs = skb->next;
+		skb->next = NULL;
+		nr_skbs--;
+		spin_unlock_irqrestore(&skb_list_lock, flags);
+	}
+
+	if(!skb) {
+		count++;
+		if (once && (count == 1000000)) {
+			printk("out of netpoll skbs!\n");
+			once = 0;
+		}
+		netpoll_poll(np);
+		goto repeat;
+	}
+
+	atomic_set(&skb->users, 1);
+	skb_reserve(skb, reserve);
+	return skb;
+}
+
+void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
+{
+	int status;
+
+repeat:
+	if(!np || !np->dev || !netif_running(np->dev)) {
+		__kfree_skb(skb);
+		return;
+	}
+
+	spin_lock(&np->dev->xmit_lock);
+	np->dev->xmit_lock_owner = smp_processor_id();
+
+	if (netif_queue_stopped(np->dev)) {
+		np->dev->xmit_lock_owner = -1;
+		spin_unlock(&np->dev->xmit_lock);
+
+		netpoll_poll(np);
+		goto repeat;
+	}
+
+	status = np->dev->hard_start_xmit(skb, np->dev);
+	np->dev->xmit_lock_owner = -1;
+	spin_unlock(&np->dev->xmit_lock);
+
+	/* transmit busy */
+	if(status)
+		goto repeat;
+}
+
+void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
+{
+	int total_len, eth_len, ip_len, udp_len;
+	struct sk_buff *skb;
+	struct udphdr *udph;
+	struct iphdr *iph;
+	struct ethhdr *eth;
+
+	udp_len = len + sizeof(*udph);
+	ip_len = eth_len = udp_len + sizeof(*iph);
+	total_len = eth_len + ETH_HLEN;
+
+	skb = find_skb(np, total_len, total_len - len);
+	if (!skb)
+		return;
+
+	memcpy(skb->data, msg, len);
+	skb->len += len;
+
+	udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
+	udph->source = htons(np->local_port);
+	udph->dest = htons(np->remote_port);
+	udph->len = htons(udp_len);
+	udph->check = 0;
+
+	iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
+
+	iph->version  = 4;
+	iph->ihl      = 5;
+	iph->tos      = 0;
+	iph->tot_len  = htons(ip_len);
+	iph->id       = 0;
+	iph->frag_off = 0;
+	iph->ttl      = 64;
+	iph->protocol = IPPROTO_UDP;
+	iph->check    = 0;
+	iph->saddr    = htonl(np->local_ip);
+	iph->daddr    = htonl(np->remote_ip);
+	iph->check    = ip_fast_csum((unsigned char *)iph, iph->ihl);
+
+	eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
+
+	eth->h_proto = htons(ETH_P_IP);
+	memcpy(eth->h_source, np->local_mac, 6);
+	memcpy(eth->h_dest, np->remote_mac, 6);
+
+	netpoll_send_skb(np, skb);
+}
+
+static void arp_reply(struct sk_buff *skb)
+{
+	struct in_device *in_dev = (struct in_device *) skb->dev->ip_ptr;
+	struct arphdr *arp;
+	unsigned char *arp_ptr, *sha, *tha;
+	int size, type = ARPOP_REPLY, ptype = ETH_P_ARP;
+	u32 sip, tip;
+	struct sk_buff *send_skb;
+	unsigned long flags;
+	struct list_head *p;
+	struct netpoll *np = 0;
+
+	spin_lock_irqsave(&rx_list_lock, flags);
+	list_for_each(p, &rx_list) {
+		np = list_entry(p, struct netpoll, rx_list);
+		if ( np->dev == skb->dev )
+			break;
+		np = 0;
+	}
+	spin_unlock_irqrestore(&rx_list_lock, flags);
+
+	if (!np) return;
+
+	/* No arp on this interface */
+	if (!in_dev || skb->dev->flags & IFF_NOARP)
+		return;
+
+	if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
+				 (2 * skb->dev->addr_len) +
+				 (2 * sizeof(u32)))))
+		return;
+
+	skb->h.raw = skb->nh.raw = skb->data;
+	arp = skb->nh.arph;
+
+	if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
+	     arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
+	    arp->ar_pro != htons(ETH_P_IP) ||
+	    arp->ar_op != htons(ARPOP_REQUEST))
+		return;
+
+	arp_ptr= (unsigned char *)(arp+1);
+	sha = arp_ptr;
+	arp_ptr += skb->dev->addr_len;
+	memcpy(&sip, arp_ptr, 4);
+	arp_ptr += 4;
+	tha = arp_ptr;
+	arp_ptr += skb->dev->addr_len;
+	memcpy(&tip, arp_ptr, 4);
+
+	/* Should we ignore arp? */
+	if (tip != in_dev->ifa_list->ifa_address ||
+	    LOOPBACK(tip) || MULTICAST(tip))
+		return;
+
+
+	size = sizeof(struct arphdr) + 2 * (skb->dev->addr_len + 4);
+	send_skb = find_skb(np, size + LL_RESERVED_SPACE(np->dev),
+			    LL_RESERVED_SPACE(np->dev));
+
+	if (!send_skb)
+		return;
+
+	send_skb->nh.raw = send_skb->data;
+	arp = (struct arphdr *) skb_put(send_skb, size);
+	send_skb->dev = skb->dev;
+	send_skb->protocol = htons(ETH_P_ARP);
+
+	/* Fill the device header for the ARP frame */
+
+	if (np->dev->hard_header &&
+	    np->dev->hard_header(send_skb, skb->dev, ptype,
+				       np->remote_mac, np->local_mac,
+				       send_skb->len) < 0) {
+		kfree_skb(send_skb);
+		return;
+	}
+
+	/*
+	 * Fill out the arp protocol part.
+	 *
+	 * we only support ethernet device type,
+	 * which (according to RFC 1390) should always equal 1 (Ethernet).
+	 */
+
+	arp->ar_hrd = htons(np->dev->type);
+	arp->ar_pro = htons(ETH_P_IP);
+	arp->ar_hln = np->dev->addr_len;
+	arp->ar_pln = 4;
+	arp->ar_op = htons(type);
+
+	arp_ptr=(unsigned char *)(arp + 1);
+	memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len);
+	arp_ptr += np->dev->addr_len;
+	memcpy(arp_ptr, &tip, 4);
+	arp_ptr += 4;
+	memcpy(arp_ptr, np->local_mac, np->dev->addr_len);
+	arp_ptr += np->dev->addr_len;
+	memcpy(arp_ptr, &sip, 4);
+
+	netpoll_send_skb(np, send_skb);
+}
+
+int netpoll_rx(struct sk_buff *skb)
+{
+	int proto, len, ulen;
+	struct iphdr *iph;
+	struct udphdr *uh;
+	struct netpoll *np;
+	struct list_head *p;
+	unsigned long flags;
+
+	if (skb->dev->type != ARPHRD_ETHER)
+		goto out;
+
+	/* check if netpoll clients need ARP */
+	if (skb->protocol == __constant_htons(ETH_P_ARP) && trapped) {
+		arp_reply(skb);
+		return 1;
+	}
+
+	proto = ntohs(skb->mac.ethernet->h_proto);
+	if (proto != ETH_P_IP)
+		goto out;
+	if (skb->pkt_type == PACKET_OTHERHOST)
+		goto out;
+	if (skb_shared(skb))
+		goto out;
+
+	iph = (struct iphdr *)skb->data;
+	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+		goto out;
+	if (iph->ihl < 5 || iph->version != 4)
+		goto out;
+	if (!pskb_may_pull(skb, iph->ihl*4))
+		goto out;
+	if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
+		goto out;
+
+	len = ntohs(iph->tot_len);
+	if (skb->len < len || len < iph->ihl*4)
+		goto out;
+
+	if (iph->protocol != IPPROTO_UDP)
+		goto out;
+
+	len -= iph->ihl*4;
+	uh = (struct udphdr *)(((char *)iph) + iph->ihl*4);
+	ulen = ntohs(uh->len);
+
+	if (ulen != len)
+		goto out;
+	if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr) < 0)
+		goto out;
+
+	spin_lock_irqsave(&rx_list_lock, flags);
+	list_for_each(p, &rx_list) {
+		np = list_entry(p, struct netpoll, rx_list);
+		if (np->dev && np->dev != skb->dev)
+			continue;
+		if (np->local_ip && np->local_ip != ntohl(iph->daddr))
+			continue;
+		if (np->remote_ip && np->remote_ip != ntohl(iph->saddr))
+			continue;
+		if (np->local_port && np->local_port != ntohs(uh->dest))
+			continue;
+
+		spin_unlock_irqrestore(&rx_list_lock, flags);
+
+		if (np->rx_hook)
+			np->rx_hook(np, ntohs(uh->source),
+				    (char *)(uh+1),
+				    ulen - sizeof(struct udphdr));
+
+		return 1;
+	}
+	spin_unlock_irqrestore(&rx_list_lock, flags);
+
+out:
+	return trapped;
+}
+
+int netpoll_parse_options(struct netpoll *np, char *opt)
+{
+	char *cur=opt, *delim;
+
+	if(*cur != '@') {
+		if ((delim = strchr(cur, '@')) == NULL)
+			goto parse_failed;
+		*delim=0;
+		np->local_port=simple_strtol(cur, 0, 10);
+		cur=delim;
+	}
+	cur++;
+	printk(KERN_INFO "%s: local port %d\n", np->name, np->local_port);
+
+	if(*cur != '/') {
+		if ((delim = strchr(cur, '/')) == NULL)
+			goto parse_failed;
+		*delim=0;
+		np->local_ip=ntohl(in_aton(cur));
+		cur=delim;
+
+		printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n",
+		       np->name, HIPQUAD(np->local_ip));
+	}
+	cur++;
+
+	if ( *cur != ',') {
+		/* parse out dev name */
+		if ((delim = strchr(cur, ',')) == NULL)
+			goto parse_failed;
+		*delim=0;
+		strlcpy(np->dev_name, cur, sizeof(np->dev_name));
+		cur=delim;
+	}
+	cur++;
+
+	printk(KERN_INFO "%s: interface %s\n", np->name, np->dev_name);
+
+	if ( *cur != '@' ) {
+		/* dst port */
+		if ((delim = strchr(cur, '@')) == NULL)
+			goto parse_failed;
+		*delim=0;
+		np->remote_port=simple_strtol(cur, 0, 10);
+		cur=delim;
+	}
+	cur++;
+	printk(KERN_INFO "%s: remote port %d\n", np->name, np->remote_port);
+
+	/* dst ip */
+	if ((delim = strchr(cur, '/')) == NULL)
+		goto parse_failed;
+	*delim=0;
+	np->remote_ip=ntohl(in_aton(cur));
+	cur=delim+1;
+
+	printk(KERN_INFO "%s: remote IP %d.%d.%d.%d\n",
+		       np->name, HIPQUAD(np->remote_ip));
+
+	if( *cur != 0 )
+	{
+		/* MAC address */
+		if ((delim = strchr(cur, ':')) == NULL)
+			goto parse_failed;
+		*delim=0;
+		np->remote_mac[0]=simple_strtol(cur, 0, 16);
+		cur=delim+1;
+		if ((delim = strchr(cur, ':')) == NULL)
+			goto parse_failed;
+		*delim=0;
+		np->remote_mac[1]=simple_strtol(cur, 0, 16);
+		cur=delim+1;
+		if ((delim = strchr(cur, ':')) == NULL)
+			goto parse_failed;
+		*delim=0;
+		np->remote_mac[2]=simple_strtol(cur, 0, 16);
+		cur=delim+1;
+		if ((delim = strchr(cur, ':')) == NULL)
+			goto parse_failed;
+		*delim=0;
+		np->remote_mac[3]=simple_strtol(cur, 0, 16);
+		cur=delim+1;
+		if ((delim = strchr(cur, ':')) == NULL)
+			goto parse_failed;
+		*delim=0;
+		np->remote_mac[4]=simple_strtol(cur, 0, 16);
+		cur=delim+1;
+		np->remote_mac[5]=simple_strtol(cur, 0, 16);
+	}
+
+	printk(KERN_INFO "%s: remote ethernet address "
+	       "%02x:%02x:%02x:%02x:%02x:%02x\n",
+	       np->name,
+	       np->remote_mac[0],
+	       np->remote_mac[1],
+	       np->remote_mac[2],
+	       np->remote_mac[3],
+	       np->remote_mac[4],
+	       np->remote_mac[5]);
+
+	return 0;
+
+ parse_failed:
+	printk(KERN_INFO "%s: couldn't parse config at %s!\n",
+	       np->name, cur);
+	return -1;
+}
+
+int netpoll_setup(struct netpoll *np)
+{
+	struct net_device *ndev = NULL;
+	struct in_device *in_dev;
+
+	if (np->dev_name)
+		ndev = dev_get_by_name(np->dev_name);
+	if (!ndev) {
+		printk(KERN_ERR "%s: %s doesn't exist, aborting.\n",
+		       np->name, np->dev_name);
+		return -1;
+	}
+	if (!ndev->poll_controller) {
+		printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n",
+		       np->name, np->dev_name);
+		goto release;
+	}
+
+	if (!(ndev->flags & IFF_UP)) {
+		unsigned short oflags;
+		unsigned long atmost, atleast;
+
+		printk(KERN_INFO "%s: device %s not up yet, forcing it\n",
+		       np->name, np->dev_name);
+
+		oflags = ndev->flags;
+
+		rtnl_shlock();
+		if (dev_change_flags(ndev, oflags | IFF_UP) < 0) {
+			printk(KERN_ERR "%s: failed to open %s\n",
+			       np->name, np->dev_name);
+			rtnl_shunlock();
+			goto release;
+		}
+		rtnl_shunlock();
+
+		atleast = jiffies + HZ/10;
+ 		atmost = jiffies + 10*HZ;
+		while (!netif_carrier_ok(ndev)) {
+			if (time_after(jiffies, atmost)) {
+				printk(KERN_NOTICE
+				       "%s: timeout waiting for carrier\n",
+				       np->name);
+				break;
+			}
+			cond_resched();
+		}
+
+		if (time_before(jiffies, atleast)) {
+			printk(KERN_NOTICE "%s: carrier detect appears flaky,"
+			       " waiting 10 seconds\n",
+			       np->name);
+			while (time_before(jiffies, atmost))
+				cond_resched();
+		}
+	}
+
+	if (!memcmp(np->local_mac, "\0\0\0\0\0\0", 6) && ndev->dev_addr)
+		memcpy(np->local_mac, ndev->dev_addr, 6);
+
+	if (!np->local_ip) {
+		in_dev = in_dev_get(ndev);
+
+		if (!in_dev) {
+			printk(KERN_ERR "%s: no IP address for %s, aborting\n",
+			       np->name, np->dev_name);
+			goto release;
+		}
+
+		np->local_ip = ntohl(in_dev->ifa_list->ifa_local);
+		in_dev_put(in_dev);
+		printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n",
+		       np->name, HIPQUAD(np->local_ip));
+	}
+
+	np->dev = ndev;
+
+	if(np->rx_hook) {
+		unsigned long flags;
+
+#ifdef CONFIG_NETPOLL_RX
+		np->dev->netpoll_rx = 1;
+#endif
+
+		spin_lock_irqsave(&rx_list_lock, flags);
+		list_add(&np->rx_list, &rx_list);
+		spin_unlock_irqrestore(&rx_list_lock, flags);
+	}
+
+	return 0;
+ release:
+	dev_put(ndev);
+	return -1;
+}
+
+void netpoll_cleanup(struct netpoll *np)
+{
+	if(np->rx_hook) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&rx_list_lock, flags);
+		list_del(&np->rx_list);
+#ifdef CONFIG_NETPOLL_RX
+		np->dev->netpoll_rx = 0;
+#endif
+		spin_unlock_irqrestore(&rx_list_lock, flags);
+	}
+
+	dev_put(np->dev);
+	np->dev = 0;
+}
+
+int netpoll_trap()
+{
+	return trapped;
+}
+
+void netpoll_set_trap(int trap)
+{
+	trapped = trap;
+}
+
+EXPORT_SYMBOL(netpoll_set_trap);
+EXPORT_SYMBOL(netpoll_trap);
+EXPORT_SYMBOL(netpoll_parse_options);
+EXPORT_SYMBOL(netpoll_setup);
+EXPORT_SYMBOL(netpoll_cleanup);
+EXPORT_SYMBOL(netpoll_send_skb);
+EXPORT_SYMBOL(netpoll_send_udp);
+EXPORT_SYMBOL(netpoll_poll);
--- diff/net/ipmi/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ source/net/ipmi/Makefile	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1 @@
+obj-$(CONFIG_IPMI_SOCKET) = af_ipmi.o
--- diff/net/ipmi/af_ipmi.c	1970-01-01 01:00:00.000000000 +0100
+++ source/net/ipmi/af_ipmi.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,612 @@
+/*
+ * IPMI Socket Glue
+ *
+ * Author:	Louis Zhuang <louis.zhuang@linux.intel.com>
+ * Copyright by Intel Corp., 2003
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/socket.h>
+#include <linux/fcntl.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/in.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+#include <linux/skbuff.h>
+#include <linux/tcp.h>
+#include <net/sock.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/smp_lock.h>
+#include <linux/mount.h>
+#include <linux/security.h>
+#include <linux/ipmi.h>
+#include <net/af_ipmi.h>
+
+#define IPMI_SOCKINTF_VERSION "v31"
+
+#ifdef CONFIG_DEBUG_KERNEL
+static int debug = 0;
+#define dbg(format, arg...)                                     \
+        do {                                                    \
+                if(debug)                                    \
+                        printk (KERN_DEBUG "%s: " format "\n",  \
+                                __FUNCTION__, ## arg);          \
+        } while(0)
+#else
+#define dbg(format, arg...)
+#endif /* CONFIG_DEBUG_KERNEL */
+
+#define err(format, arg...) \
+                printk(KERN_ERR "%s: " format "\n", \
+                       __FUNCTION__ , ## arg)
+#define info(format, arg...) \
+                printk(KERN_INFO "%s: " format "\n", \
+                       __FUNCTION__ , ## arg)
+#define warn(format, arg...) \
+                printk(KERN_WARNING "%s: " format "\n", \
+                       __FUNCTION__ , ## arg)
+#define trace(format, arg...) \
+                printk(KERN_INFO "%s(" format ")\n", \
+                       __FUNCTION__ , ## arg)
+
+struct ipmi_sock {
+	/* WARNING: sk has to be the first member */
+	struct sock sk;
+
+	ipmi_user_t user;
+	struct sockaddr_ipmi addr;
+	struct list_head msg_list;
+
+	wait_queue_head_t wait;
+	spinlock_t lock;
+
+	int          default_retries;
+	unsigned int default_retry_time_ms;
+};
+
+static kmem_cache_t *ipmi_sk_cachep = NULL;
+
+static atomic_t ipmi_nr_socks = ATOMIC_INIT(0);
+
+
+
+/*
+ * utility functions
+ */
+static inline struct ipmi_sock *to_ipmi_sock(struct sock *sk)
+{
+	return container_of(sk, struct ipmi_sock, sk);
+}
+
+static inline void ipmi_release_sock(struct sock *sk, int embrion)
+{
+	struct ipmi_sock *i = to_ipmi_sock(sk);
+	struct sk_buff   *skb;
+
+	if (i->user) {
+		ipmi_destroy_user(i->user);
+		i->user = NULL;
+	}
+
+	sock_orphan(&i->sk);
+	sk->sk_shutdown = SHUTDOWN_MASK;
+	sk->sk_state = TCP_CLOSE;
+
+	while((skb=skb_dequeue(&sk->sk_receive_queue))!=NULL)
+		kfree_skb(skb);
+
+	sock_put(sk);
+}
+
+static inline long ipmi_wait_for_queue(struct ipmi_sock *i, long timeo)
+{
+
+	DECLARE_WAITQUEUE(wait, current);
+
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue_exclusive(&i->wait, &wait);
+	timeo = schedule_timeout(timeo);
+	remove_wait_queue(&i->wait, &wait);
+	return timeo;
+}
+
+/*
+ * IPMI operation functions
+ */
+static void sock_receive_handler(struct ipmi_recv_msg *msg,
+				 void                 *handler_data)
+{
+	struct ipmi_sock *i = (struct ipmi_sock *)handler_data;
+	unsigned long    flags;
+
+	spin_lock_irqsave(&i->lock, flags);
+	list_add_tail(&msg->link, &i->msg_list);
+	spin_unlock_irqrestore(&i->lock, flags);
+
+	wake_up_interruptible(&i->wait);
+}
+
+/*
+ * protocol operation functions
+ */
+static int ipmi_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+
+	if (!sk)
+		return 0;
+
+	sock->sk=NULL;
+	ipmi_release_sock(sk, 0);
+	return 0;
+}
+
+static struct ipmi_user_hndl ipmi_hnd = {
+	.ipmi_recv_hndl = sock_receive_handler
+};
+
+static int ipmi_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+{
+	struct ipmi_sock *i = to_ipmi_sock(sock->sk);
+	struct sockaddr_ipmi *addr = (struct sockaddr_ipmi *)uaddr;
+	int err = -EINVAL;
+
+	if (i->user != NULL) {
+		dbg("Cannot bind twice: %p", i->user);
+		return -EINVAL;
+	}
+
+	err = ipmi_create_user(addr->if_num, &ipmi_hnd, i, &i->user);
+	if (err) {
+		dbg("Cannot create user for the socket: %p", i->user);
+		return err;
+	}
+
+	memcpy(&i->addr, addr, sizeof(i->addr));
+	return 0;
+}
+
+static int ipmi_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer)
+{
+	struct ipmi_sock *i = to_ipmi_sock(sock->sk);
+	memcpy(uaddr, &i->addr, sizeof(i->addr));
+	return 0;
+}
+
+static unsigned int ipmi_poll(struct file * file, struct socket *sock, poll_table *wait)
+{
+	unsigned int     has_msg = 0;
+	struct ipmi_sock *i = to_ipmi_sock(sock->sk);
+	unsigned long    flags;
+
+	poll_wait(file, &i->wait, wait);
+	spin_lock_irqsave(&i->lock, flags);
+	if (!list_empty(&i->msg_list))
+		has_msg = 1;
+	spin_unlock_irqrestore(&i->lock, flags);
+
+	if (has_msg)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+static int ipmi_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+	struct ipmi_sock    *i = to_ipmi_sock(sock->sk);
+	struct ipmi_cmdspec val;
+	int                 ival;
+	unsigned int        uival;
+	int                 err;
+
+	dbg("cmd=%#x, arg=%#lx", cmd, arg);
+	switch(cmd) {
+	case SIOCIPMIREGCMD:
+		err = copy_from_user((void *)&val, (void *)arg,
+				     sizeof(cmd));
+		if (err) {
+			err = -EFAULT;
+			break;
+		}
+
+		err = ipmi_register_for_cmd(i->user, val.netfn,
+					    val.cmd);
+		break;
+
+	case SIOCIPMIUNREGCMD:
+		err = copy_from_user((void *)&val, (void *)arg,
+				     sizeof(cmd));
+		if (err) {
+			err = -EFAULT;
+			break;
+		}
+
+		err = ipmi_unregister_for_cmd(i->user, val.netfn,
+					      val.cmd);
+		break;
+
+	case SIOCIPMIGETEVENT:
+		err = copy_from_user((void *)&ival, (void *)arg,
+				     sizeof(ival));
+		if (err) {
+			err = -EFAULT;
+			break;
+		}
+
+		err = ipmi_set_gets_events(i->user, ival);
+		break;
+
+	case SIOCIPMISETADDR:
+		err = copy_from_user((void *)&uival, (void *)arg,
+				     sizeof(uival));
+		if (err) {
+			err = -EFAULT;
+			break;
+		}
+
+		ipmi_set_my_address(i->user, uival);
+		break;
+
+	case SIOCIPMIGETADDR:
+		uival = ipmi_get_my_address(i->user);
+
+		if (copy_to_user((void *) arg, &uival, sizeof(uival))) {
+			err = -EFAULT;
+			break;
+		}
+		err = 0;
+		break;
+
+	case SIOCIPMISETTIMING:
+	{
+		struct ipmi_timing_parms parms;
+
+		if (copy_from_user(&parms, (void *) arg, sizeof(parms))) {
+			err = -EFAULT;
+			break;
+		}
+
+		i->default_retries = parms.retries;
+		i->default_retry_time_ms = parms.retry_time_ms;
+		err = 0;
+		break;
+	}
+
+	case SIOCIPMIGETTIMING:
+	{
+		struct ipmi_timing_parms parms;
+
+		parms.retries = i->default_retries;
+		parms.retry_time_ms = i->default_retry_time_ms;
+
+		if (copy_to_user((void *) arg, &parms, sizeof(parms))) {
+			err = -EFAULT;
+			break;
+		}
+
+		err = 0;
+		break;
+	}
+
+	default:
+		err = dev_ioctl(cmd, (void *)arg);
+		break;
+	}
+
+	return err;
+}
+
+static int ipmi_recvmsg(struct kiocb *iocb, struct socket *sock,
+			struct msghdr *msg, size_t size,
+			int rflags)
+{
+	struct ipmi_sock     *i = to_ipmi_sock(sock->sk);
+	long                 timeo;
+	struct ipmi_recv_msg *rcvmsg;
+	struct sockaddr_ipmi addr;
+	char                 buf[IPMI_MAX_SOCK_MSG_LENGTH];
+	struct ipmi_sock_msg *smsg = (struct ipmi_sock_msg *)buf;
+	int                  err;
+	unsigned long        flags;
+
+
+	timeo = sock_rcvtimeo(&i->sk, rflags & MSG_DONTWAIT);
+
+	while (1) {
+		spin_lock_irqsave(&i->lock, flags);
+		if (!list_empty(&i->msg_list))
+			break;
+		spin_unlock_irqrestore(&i->lock, flags);
+		if (!timeo) {
+			return -EAGAIN;
+		} else if (signal_pending (current)) {
+			dbg("Signal pending: %d", 1);
+			return -EINTR;
+		}
+
+		timeo = ipmi_wait_for_queue(i, timeo);
+	}
+
+	rcvmsg = list_entry(i->msg_list.next, struct ipmi_recv_msg, link);
+	list_del(&rcvmsg->link);
+	spin_unlock_irqrestore(&i->lock, flags);
+
+	memcpy(&addr.ipmi_addr, &rcvmsg->addr, sizeof(addr.ipmi_addr));
+	addr.if_num = i->addr.if_num;
+	addr.sipmi_family = i->addr.sipmi_family;
+	memcpy(msg->msg_name, &addr, sizeof(addr));
+	msg->msg_namelen = (SOCKADDR_IPMI_OVERHEAD
+			    + ipmi_addr_length(rcvmsg->addr.addr_type));
+
+	smsg->recv_type		= rcvmsg->recv_type;
+	smsg->msgid		= rcvmsg->msgid;
+	smsg->netfn		= rcvmsg->msg.netfn;
+	smsg->cmd		= rcvmsg->msg.cmd;
+	smsg->data_len		= rcvmsg->msg.data_len;
+	memcpy(smsg->data, rcvmsg->msg.data, smsg->data_len);
+
+	ipmi_free_recv_msg(rcvmsg);
+
+	err = memcpy_toiovec(msg->msg_iov, (void *)smsg,
+			     sizeof(struct ipmi_sock_msg) + smsg->data_len);
+	if (err) {
+		dbg("Cannot copy data to user: %p", i->user);
+		return err;
+	}
+
+	dbg("user=%p", i->user);
+	dbg("addr_type=%x, channel=%x",
+	    addr.ipmi_addr.addr_type, addr.ipmi_addr.channel);
+	dbg("netfn=%#02x, cmd=%#02x, data=%p, data_len=%x",
+	    smsg->netfn, smsg->cmd, smsg->data, smsg->data_len);
+
+	return (sizeof(struct ipmi_sock_msg) + smsg->data_len);
+}
+
+static int ipmi_sendmsg(struct kiocb *iocb, struct socket *sock,
+			struct msghdr *msg, size_t len)
+{
+	struct ipmi_sock         *i = to_ipmi_sock(sock->sk);
+	struct sockaddr_ipmi     *addr = (struct sockaddr_ipmi *)msg->msg_name;
+	struct ipmi_msg          imsg;
+	unsigned char            buf[IPMI_MAX_SOCK_MSG_LENGTH];
+	struct ipmi_sock_msg     *smsg = (struct ipmi_sock_msg *) buf;
+	int                      err;
+	struct ipmi_timing_parms tparms;
+	struct cmsghdr           *cmsg;
+
+	err = ipmi_validate_addr(&addr->ipmi_addr,
+				 msg->msg_namelen - SOCKADDR_IPMI_OVERHEAD);
+	if (err) {
+		dbg("Invalid IPMI address: %p", i->user);
+		goto err;
+	}
+
+	if (len > IPMI_MAX_SOCK_MSG_LENGTH) {
+		err = -EINVAL;
+		dbg("Message too long: %p", i->user);
+		goto err;
+	}
+
+	if (len < sizeof(struct ipmi_sock_msg)) {
+		err = -EINVAL;
+		dbg("Msg data too small for header: %p", i->user);
+		goto err;
+	}
+
+	err = memcpy_fromiovec((void *)smsg, msg->msg_iov, len);
+	if (err) {
+		dbg("Cannot copy data to kernel: %p", i->user);
+		goto err;
+	}
+
+	if (len < smsg->data_len+sizeof(struct ipmi_sock_msg)) {
+		err = -EINVAL;
+		dbg("Msg data is out of bound: %p", i->user);
+		goto err;
+	}
+
+	/* Set defaults. */
+	tparms.retries = i->default_retries;
+	tparms.retry_time_ms = i->default_retry_time_ms;
+
+	for (cmsg=CMSG_FIRSTHDR(msg);
+	     cmsg;
+	     cmsg = CMSG_NXTHDR(msg, cmsg))
+	{
+		if (cmsg->cmsg_len < sizeof(struct cmsghdr)) {
+			err = -EINVAL;
+			dbg("cmsg length too short: %p", i->user);
+			goto err;
+		}
+
+		if (cmsg->cmsg_level != SOL_SOCKET)
+			continue;
+
+		if (cmsg->cmsg_type == IPMI_CMSG_TIMING_PARMS) {
+			struct ipmi_timing_parms *pparms;
+
+			if (cmsg->cmsg_len != CMSG_LEN(sizeof(*pparms))) {
+				err = -EINVAL;
+				dbg("timing parms cmsg not right size: %p",
+				    i->user);
+				goto err;
+			}
+			pparms = (struct ipmi_timing_parms *) CMSG_DATA(cmsg);
+			tparms.retries = pparms->retries;
+			tparms.retry_time_ms = pparms->retry_time_ms;
+		}
+	}
+
+	imsg.netfn 	= smsg->netfn;
+	imsg.cmd	= smsg->cmd;
+	imsg.data 	= smsg->data;
+	imsg.data_len 	= smsg->data_len;
+
+	dbg("user=%p", i->user);
+	dbg("addr_type=%x, channel=%x",
+	    addr->ipmi_addr.addr_type, addr->ipmi_addr.channel);
+	dbg("netfn=%#02x, cmd=%#02x, data=%p, data_len=%x",
+	    imsg.netfn, imsg.cmd, imsg.data, imsg.data_len);
+	err = ipmi_request_settime(i->user, &addr->ipmi_addr,
+				   smsg->msgid, &imsg, NULL, 0,
+				   tparms.retries, tparms.retry_time_ms);
+	if (err) {
+		dbg("Cannot send message: %p", i->user);
+		goto err;
+	}
+
+err:
+	return err;
+}
+
+static struct proto_ops ipmi_ops = {
+	.family =	PF_IPMI,
+	.owner =	THIS_MODULE,
+	.release =	ipmi_release,
+	.bind =		ipmi_bind,
+	.connect =	sock_no_connect,
+	.socketpair =	sock_no_socketpair,
+	.accept =	sock_no_accept,
+	.getname =	ipmi_getname,
+	.poll =		ipmi_poll,
+	.ioctl =	ipmi_ioctl,
+	.listen =	sock_no_listen,
+	.shutdown =	sock_no_shutdown,
+	.setsockopt =	sock_no_setsockopt,
+	.getsockopt =	sock_no_getsockopt,
+	.sendmsg =	ipmi_sendmsg,
+	.recvmsg =	ipmi_recvmsg,
+	.mmap =		sock_no_mmap,
+	.sendpage =	sock_no_sendpage
+};
+
+
+static void ipmi_sock_destructor(struct sock *sk)
+{
+	skb_queue_purge(&sk->sk_receive_queue);
+
+	BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc));
+	BUG_TRAP(sk_unhashed(sk));
+	BUG_TRAP(!sk->sk_socket);
+	if (!sock_flag(sk, SOCK_DEAD)) {
+		printk("Attempt to release alive ipmi socket: %p\n", sk);
+		return;
+	}
+
+	atomic_dec(&ipmi_nr_socks);
+}
+
+/*
+ * net protocol functions
+ */
+static struct ipmi_sock *ipmi_socket_create1(struct socket *sock)
+{
+	struct ipmi_sock *i;
+
+	if (atomic_read(&ipmi_nr_socks) >= 2*files_stat.max_files)
+		return NULL;
+
+	i = (struct ipmi_sock *)sk_alloc(PF_IPMI, GFP_KERNEL,
+					 sizeof(struct ipmi_sock), ipmi_sk_cachep);
+	if (!i) {
+		return NULL;
+	}
+
+
+	sock_init_data(sock, &i->sk);
+	sk_set_owner(&i->sk, THIS_MODULE);
+	i->sk.sk_destruct = ipmi_sock_destructor;
+	i->sk.sk_rcvtimeo = 5*HZ;
+	spin_lock_init(&i->lock);
+	INIT_LIST_HEAD(&i->msg_list);
+	init_waitqueue_head(&i->wait);
+
+	/* Set to use default values. */
+	i->default_retries = -1;
+	i->default_retry_time_ms = 0;
+
+	atomic_inc(&ipmi_nr_socks);
+	return i;
+}
+
+static int ipmi_socket_create(struct socket *sock, int protocol)
+{
+	if (!capable(CAP_NET_RAW))
+		return -EPERM;
+	if (protocol && protocol != PF_IPMI)
+		return -EPROTONOSUPPORT;
+
+	sock->state = SS_UNCONNECTED;
+
+	switch (sock->type) {
+	case SOCK_RAW:
+		sock->type=SOCK_DGRAM;
+	case SOCK_DGRAM:
+		sock->ops = &ipmi_ops;
+		break;
+	default:
+		return -EPROTONOSUPPORT;
+	}
+
+	return ipmi_socket_create1(sock)? 0 : -ENOMEM;
+}
+
+static struct net_proto_family ipmi_family_ops = {
+	.family = PF_IPMI,
+	.create = ipmi_socket_create,
+	.owner	= THIS_MODULE,
+};
+
+
+/*
+ * init/exit functions
+ */
+static int __init ipmi_socket_init(void)
+{
+
+	int err=0;
+
+	printk(KERN_INFO "ipmi socket interface version "
+	       IPMI_SOCKINTF_VERSION "\n");
+
+	ipmi_sk_cachep = kmem_cache_create("ipmi_sock",
+					   sizeof(struct ipmi_sock), 0,
+					   SLAB_HWCACHE_ALIGN, 0, 0);
+	if (!ipmi_sk_cachep) {
+		printk(KERN_CRIT "%s: Unable to create ipmi_sock SLAB cache!\n", __func__);
+		err = -ENOMEM;
+		goto out;
+	}
+
+	err = sock_register(&ipmi_family_ops);
+	if (err)
+		kmem_cache_destroy(ipmi_sk_cachep);
+out:
+	return err;
+}
+
+static void __exit ipmi_socket_exit(void)
+{
+	sock_unregister(PF_IPMI);
+	kmem_cache_destroy(ipmi_sk_cachep);
+}
+
+#ifdef CONFIG_DEBUG_KERNEL
+module_param(debug, int, 0);
+#endif
+module_init(ipmi_socket_init);
+module_exit(ipmi_socket_exit);
+
+MODULE_LICENSE("GPL");
--- diff/sound/i2c/other/ak4117.c	1970-01-01 01:00:00.000000000 +0100
+++ source/sound/i2c/other/ak4117.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,561 @@
+/*
+ *  Routines for control of the AK4117 via 4-wire serial interface
+ *  IEC958 (S/PDIF) receiver by Asahi Kasei
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <sound/driver.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/ak4117.h>
+#include <sound/asoundef.h>
+
+MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_DESCRIPTION("AK4117 IEC958 (S/PDIF) receiver by Asahi Kasei");
+MODULE_LICENSE("GPL");
+
+#define chip_t ak4117_t
+
+#define AK4117_ADDR			0x00 /* fixed address */
+
+static void snd_ak4117_timer(unsigned long data);
+
+static void reg_write(ak4117_t *ak4117, unsigned char reg, unsigned char val)
+{
+	ak4117->write(ak4117->private_data, reg, val);
+	if (reg < sizeof(ak4117->regmap))
+		ak4117->regmap[reg] = val;
+}
+
+static inline unsigned char reg_read(ak4117_t *ak4117, unsigned char reg)
+{
+	return ak4117->read(ak4117->private_data, reg);
+}
+
+#if 0
+static void reg_dump(ak4117_t *ak4117)
+{
+	int i;
+
+	printk("AK4117 REG DUMP:\n");
+	for (i = 0; i < 0x1b; i++)
+		printk("reg[%02x] = %02x (%02x)\n", i, reg_read(ak4117, i), i < sizeof(ak4117->regmap) ? ak4117->regmap[i] : 0);
+}
+#endif
+
+static void snd_ak4117_free(ak4117_t *chip)
+{
+	del_timer(&chip->timer);
+	snd_magic_kfree(chip);
+}
+
+static int snd_ak4117_dev_free(snd_device_t *device)
+{
+	ak4117_t *chip = snd_magic_cast(ak4117_t, device->device_data, return -ENXIO);
+	snd_ak4117_free(chip);
+	return 0;
+}
+
+int snd_ak4117_create(snd_card_t *card, ak4117_read_t *read, ak4117_write_t *write,
+		      unsigned char pgm[5], void *private_data, ak4117_t **r_ak4117)
+{
+	ak4117_t *chip;
+	int err = 0;
+	unsigned char reg;
+	static snd_device_ops_t ops = {
+		.dev_free =     snd_ak4117_dev_free,
+	};
+
+	chip = (ak4117_t *)snd_magic_kcalloc(ak4117_t, 0, GFP_KERNEL);
+	if (chip == NULL)
+		return -ENOMEM;
+	spin_lock_init(&chip->lock);
+	chip->card = card;
+	chip->read = read;
+	chip->write = write;
+	chip->private_data = private_data;
+	init_timer(&chip->timer);
+	chip->timer.data = (unsigned long)chip;
+	chip->timer.function = snd_ak4117_timer;
+
+	for (reg = 0; reg < 5; reg++)
+		chip->regmap[reg] = pgm[reg];
+	snd_ak4117_reinit(chip);
+
+	chip->rcs0 = reg_read(chip, AK4117_REG_RCS0) & ~(AK4117_QINT | AK4117_CINT | AK4117_STC);
+	chip->rcs1 = reg_read(chip, AK4117_REG_RCS1);
+	chip->rcs2 = reg_read(chip, AK4117_REG_RCS2);
+
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0)
+		goto __fail;
+
+	if (r_ak4117)
+		*r_ak4117 = chip;
+	return 0;
+
+      __fail:
+	snd_ak4117_free(chip);
+	return err < 0 ? err : -EIO;
+}
+
+void snd_ak4117_reg_write(ak4117_t *chip, unsigned char reg, unsigned char mask, unsigned char val)
+{
+	if (reg >= 5)
+		return;
+	reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val);
+}
+
+void snd_ak4117_reinit(ak4117_t *chip)
+{
+	unsigned char old = chip->regmap[AK4117_REG_PWRDN], reg;
+
+	del_timer(&chip->timer);
+	chip->init = 1;
+	/* bring the chip to reset state and powerdown state */
+	reg_write(chip, AK4117_REG_PWRDN, 0);
+	udelay(200);
+	/* release reset, but leave powerdown */
+	reg_write(chip, AK4117_REG_PWRDN, (old | AK4117_RST) & ~AK4117_PWN);
+	udelay(200);
+	for (reg = 1; reg < 5; reg++)
+		reg_write(chip, reg, chip->regmap[reg]);
+	/* release powerdown, everything is initialized now */
+	reg_write(chip, AK4117_REG_PWRDN, old | AK4117_RST | AK4117_PWN);
+	chip->init = 0;
+	chip->timer.expires = 1 + jiffies;
+	add_timer(&chip->timer);
+}
+
+static unsigned int external_rate(unsigned char rcs1)
+{
+	switch (rcs1 & (AK4117_FS0|AK4117_FS1|AK4117_FS2|AK4117_FS3)) {
+	case AK4117_FS_32000HZ: return 32000;
+	case AK4117_FS_44100HZ: return 44100;
+	case AK4117_FS_48000HZ: return 48000;
+	case AK4117_FS_88200HZ: return 88200;
+	case AK4117_FS_96000HZ: return 96000;
+	case AK4117_FS_176400HZ: return 176400;
+	case AK4117_FS_192000HZ: return 192000;
+	default:		return 0;
+	}
+}
+
+static int snd_ak4117_in_error_info(snd_kcontrol_t *kcontrol,
+				    snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = LONG_MAX;
+	return 0;
+}
+
+static int snd_ak4117_in_error_get(snd_kcontrol_t *kcontrol,
+				   snd_ctl_elem_value_t *ucontrol)
+{
+	ak4117_t *chip = snd_kcontrol_chip(kcontrol);
+	long *ptr;
+
+	spin_lock_irq(&chip->lock);
+	ptr = (long *)(((char *)chip) + kcontrol->private_value);
+	ucontrol->value.integer.value[0] = *ptr;
+	*ptr = 0;
+	spin_unlock_irq(&chip->lock);
+	return 0;
+}
+
+static int snd_ak4117_in_bit_info(snd_kcontrol_t *kcontrol,
+				  snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_ak4117_in_bit_get(snd_kcontrol_t *kcontrol,
+				 snd_ctl_elem_value_t *ucontrol)
+{
+	ak4117_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned char reg = kcontrol->private_value & 0xff;
+	unsigned char bit = (kcontrol->private_value >> 8) & 0xff;
+	unsigned char inv = (kcontrol->private_value >> 31) & 1;
+
+	ucontrol->value.integer.value[0] = ((reg_read(chip, reg) & (1 << bit)) ? 1 : 0) ^ inv;
+	return 0;
+}
+
+static int snd_ak4117_rx_info(snd_kcontrol_t *kcontrol,
+			      snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_ak4117_rx_get(snd_kcontrol_t *kcontrol,
+			     snd_ctl_elem_value_t *ucontrol)
+{
+	ak4117_t *chip = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.integer.value[0] = (chip->regmap[AK4117_REG_IO] & AK4117_IPS) ? 1 : 0;
+	return 0;
+}
+
+static int snd_ak4117_rx_put(snd_kcontrol_t *kcontrol,
+			     snd_ctl_elem_value_t *ucontrol)
+{
+	ak4117_t *chip = snd_kcontrol_chip(kcontrol);
+	int change;
+	u8 old_val;
+	
+	spin_lock_irq(&chip->lock);
+	old_val = chip->regmap[AK4117_REG_IO];
+	change = !!ucontrol->value.integer.value[0] != ((old_val & AK4117_IPS) ? 1 : 0);
+	if (change)
+		reg_write(chip, AK4117_REG_IO, (old_val & ~AK4117_IPS) | (ucontrol->value.integer.value[0] ? AK4117_IPS : 0));
+	spin_unlock_irq(&chip->lock);
+	return change;
+}
+
+static int snd_ak4117_rate_info(snd_kcontrol_t *kcontrol,
+				snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 192000;
+	return 0;
+}
+
+static int snd_ak4117_rate_get(snd_kcontrol_t *kcontrol,
+			       snd_ctl_elem_value_t *ucontrol)
+{
+	ak4117_t *chip = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.integer.value[0] = external_rate(reg_read(chip, AK4117_REG_RCS1));
+	return 0;
+}
+
+static int snd_ak4117_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+	return 0;
+}
+
+static int snd_ak4117_spdif_get(snd_kcontrol_t * kcontrol,
+				snd_ctl_elem_value_t * ucontrol)
+{
+	ak4117_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned i;
+
+	for (i = 0; i < AK4117_REG_RXCSB_SIZE; i++)
+		ucontrol->value.iec958.status[i] = reg_read(chip, AK4117_REG_RXCSB0 + i);
+	return 0;
+}
+
+static int snd_ak4117_spdif_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+	return 0;
+}
+
+static int snd_ak4117_spdif_mask_get(snd_kcontrol_t * kcontrol,
+				      snd_ctl_elem_value_t * ucontrol)
+{
+	memset(ucontrol->value.iec958.status, 0xff, AK4117_REG_RXCSB_SIZE);
+	return 0;
+}
+
+static int snd_ak4117_spdif_pinfo(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xffff;
+	uinfo->count = 4;
+	return 0;
+}
+
+static int snd_ak4117_spdif_pget(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	ak4117_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned short tmp;
+
+	ucontrol->value.integer.value[0] = 0xf8f2;
+	ucontrol->value.integer.value[1] = 0x4e1f;
+	tmp = reg_read(chip, AK4117_REG_Pc0) | (reg_read(chip, AK4117_REG_Pc1) << 8);
+	ucontrol->value.integer.value[2] = tmp;
+	tmp = reg_read(chip, AK4117_REG_Pd0) | (reg_read(chip, AK4117_REG_Pd1) << 8);
+	ucontrol->value.integer.value[3] = tmp;
+	return 0;
+}
+
+static int snd_ak4117_spdif_qinfo(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = AK4117_REG_QSUB_SIZE;
+	return 0;
+}
+
+static int snd_ak4117_spdif_qget(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	ak4117_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned i;
+
+	for (i = 0; i < AK4117_REG_QSUB_SIZE; i++)
+		ucontrol->value.bytes.data[i] = reg_read(chip, AK4117_REG_QSUB_ADDR + i);
+	return 0;
+}
+
+/* Don't forget to change AK4117_CONTROLS define!!! */
+static snd_kcontrol_new_t snd_ak4117_iec958_controls[] = {
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 Parity Errors",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4117_in_error_info,
+	.get =		snd_ak4117_in_error_get,
+	.private_value = offsetof(ak4117_t, parity_errors),
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 V-Bit Errors",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4117_in_error_info,
+	.get =		snd_ak4117_in_error_get,
+	.private_value = offsetof(ak4117_t, v_bit_errors),
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 C-CRC Errors",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4117_in_error_info,
+	.get =		snd_ak4117_in_error_get,
+	.private_value = offsetof(ak4117_t, ccrc_errors),
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 Q-CRC Errors",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4117_in_error_info,
+	.get =		snd_ak4117_in_error_get,
+	.private_value = offsetof(ak4117_t, qcrc_errors),
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 External Rate",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4117_rate_info,
+	.get =		snd_ak4117_rate_get,
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK),
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
+	.info =		snd_ak4117_spdif_mask_info,
+	.get =		snd_ak4117_spdif_mask_get,
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT),
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4117_spdif_info,
+	.get =		snd_ak4117_spdif_get,
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 Preample Capture Default",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4117_spdif_pinfo,
+	.get =		snd_ak4117_spdif_pget,
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 Q-subcode Capture Default",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4117_spdif_qinfo,
+	.get =		snd_ak4117_spdif_qget,
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 Audio",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4117_in_bit_info,
+	.get =		snd_ak4117_in_bit_get,
+	.private_value = (1<<31) | (3<<8) | AK4117_REG_RCS0,
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 Non-PCM Bitstream",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4117_in_bit_info,
+	.get =		snd_ak4117_in_bit_get,
+	.private_value = (5<<8) | AK4117_REG_RCS1,
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"IEC958 DTS Bitstream",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info =		snd_ak4117_in_bit_info,
+	.get =		snd_ak4117_in_bit_get,
+	.private_value = (6<<8) | AK4117_REG_RCS1,
+},
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		"AK4117 Input Select",
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE,
+	.info =		snd_ak4117_rx_info,
+	.get =		snd_ak4117_rx_get,
+	.put =		snd_ak4117_rx_put,
+}
+};
+
+int snd_ak4117_build(ak4117_t *ak4117, snd_pcm_substream_t *cap_substream)
+{
+	snd_kcontrol_t *kctl;
+	unsigned int idx;
+	int err;
+
+	snd_assert(cap_substream, return -EINVAL);
+	ak4117->substream = cap_substream;
+	for (idx = 0; idx < AK4117_CONTROLS; idx++) {
+		kctl = snd_ctl_new1(&snd_ak4117_iec958_controls[idx], ak4117);
+		if (kctl == NULL)
+			return -ENOMEM;
+		kctl->id.device = cap_substream->pcm->device;
+		kctl->id.subdevice = cap_substream->number;
+		err = snd_ctl_add(ak4117->card, kctl);
+		if (err < 0)
+			return err;
+		ak4117->kctls[idx] = kctl;
+	}
+	return 0;
+}
+
+int snd_ak4117_external_rate(ak4117_t *ak4117)
+{
+	unsigned char rcs1;
+
+	rcs1 = reg_read(ak4117, AK4117_REG_RCS1);
+	return external_rate(rcs1);
+}
+
+int snd_ak4117_check_rate_and_errors(ak4117_t *ak4117, unsigned int flags)
+{
+	snd_pcm_runtime_t *runtime = ak4117->substream ? ak4117->substream->runtime : NULL;
+	unsigned long _flags;
+	int res = 0;
+	unsigned char rcs0, rcs1, rcs2;
+	unsigned char c0, c1;
+
+	rcs1 = reg_read(ak4117, AK4117_REG_RCS1);
+	if (flags & AK4117_CHECK_NO_STAT)
+		goto __rate;
+	rcs0 = reg_read(ak4117, AK4117_REG_RCS0);
+	rcs2 = reg_read(ak4117, AK4117_REG_RCS2);
+	// printk("AK IRQ: rcs0 = 0x%x, rcs1 = 0x%x, rcs2 = 0x%x\n", rcs0, rcs1, rcs2);
+	spin_lock_irqsave(&ak4117->lock, _flags);
+	if (rcs0 & AK4117_PAR)
+		ak4117->parity_errors++;
+	if (rcs0 & AK4117_V)
+		ak4117->v_bit_errors++;
+	if (rcs2 & AK4117_CCRC)
+		ak4117->ccrc_errors++;
+	if (rcs2 & AK4117_QCRC)
+		ak4117->qcrc_errors++;
+	c0 = (ak4117->rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)) ^
+                     (rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK));
+	c1 = (ak4117->rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f)) ^
+	             (rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f));
+	ak4117->rcs0 = rcs0 & ~(AK4117_QINT | AK4117_CINT | AK4117_STC);
+	ak4117->rcs1 = rcs1;
+	ak4117->rcs2 = rcs2;
+	spin_unlock_irqrestore(&ak4117->lock, _flags);
+
+	if (rcs0 & AK4117_PAR)
+		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[0]->id);
+	if (rcs0 & AK4117_V)
+		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[1]->id);
+	if (rcs2 & AK4117_CCRC)
+		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[2]->id);
+	if (rcs2 & AK4117_QCRC)
+		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[3]->id);
+
+	/* rate change */
+	if (c1 & 0x0f)
+		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[4]->id);
+
+	if ((c1 & AK4117_PEM) | (c0 & AK4117_CINT))
+		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[6]->id);
+	if (c0 & AK4117_QINT)
+		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[8]->id);
+
+	if (c0 & AK4117_AUDION)
+		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[9]->id);
+	if (c1 & AK4117_NPCM)
+		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[10]->id);
+	if (c1 & AK4117_DTSCD)
+		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[11]->id);
+		
+	if (ak4117->change_callback && (c0 | c1) != 0)
+		ak4117->change_callback(ak4117, c0, c1);
+
+      __rate:
+	/* compare rate */
+	res = external_rate(rcs1);
+	if (!(flags & AK4117_CHECK_NO_RATE) && runtime && runtime->rate != res) {
+		snd_pcm_stream_lock_irqsave(ak4117->substream, _flags);
+		if (snd_pcm_running(ak4117->substream)) {
+			// printk("rate changed (%i <- %i)\n", runtime->rate, res);
+			snd_pcm_stop(ak4117->substream, SNDRV_PCM_STATE_DRAINING);
+			wake_up(&runtime->sleep);
+			res = 1;
+		}
+		snd_pcm_stream_unlock_irqrestore(ak4117->substream, _flags);
+	}
+	return res;
+}
+
+static void snd_ak4117_timer(unsigned long data)
+{
+	ak4117_t *chip = snd_magic_cast(ak4117_t, (void *)data, return);
+
+	if (chip->init)
+		return;
+	snd_ak4117_check_rate_and_errors(chip, 0);
+	chip->timer.expires = 1 + jiffies;
+	add_timer(&chip->timer);
+}
+
+EXPORT_SYMBOL(snd_ak4117_create);
+EXPORT_SYMBOL(snd_ak4117_reg_write);
+EXPORT_SYMBOL(snd_ak4117_reinit);
+EXPORT_SYMBOL(snd_ak4117_build);
+EXPORT_SYMBOL(snd_ak4117_external_rate);
+EXPORT_SYMBOL(snd_ak4117_check_rate_and_errors);
--- diff/sound/pci/mixart/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ source/sound/pci/mixart/Makefile	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,8 @@
+#
+# Makefile for ALSA
+# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
+#
+
+snd-mixart-objs := mixart.o mixart_core.o mixart_hwdep.o mixart_mixer.o
+
+obj-$(CONFIG_SND_MIXART) += snd-mixart.o
--- diff/sound/pci/mixart/mixart.c	1970-01-01 01:00:00.000000000 +0100
+++ source/sound/pci/mixart/mixart.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,1473 @@
+/*
+ * Driver for Digigram miXart soundcards
+ *
+ * main file with alsa callbacks
+ *
+ * Copyright (c) 2003 by Digigram <alsa@digigram.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#define SNDRV_GET_ID
+#include <sound/initval.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include "mixart.h"
+#include "mixart_hwdep.h"
+#include "mixart_core.h"
+#include "mixart_mixer.h"
+
+#define CARD_NAME "miXart"
+
+MODULE_AUTHOR("Digigram <alsa@digigram.com>");
+MODULE_DESCRIPTION("Digigram " CARD_NAME);
+MODULE_LICENSE("GPL");
+MODULE_CLASSES("{sound}");
+MODULE_DEVICES("{{Digigram," CARD_NAME "}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;             /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;              /* ID for this card */
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
+
+#define chip_t mixart_t
+
+MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(index, "Index value for Digigram " CARD_NAME " soundcard.");
+MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
+MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+MODULE_PARM_DESC(id, "ID string for Digigram " CARD_NAME " soundcard.");
+MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
+MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(enable, "Enable Digigram " CARD_NAME " soundcard.");
+MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
+
+/*
+ */
+
+static struct pci_device_id snd_mixart_ids[] = {
+	{ 0x1057, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* MC8240 */
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, snd_mixart_ids);
+
+
+static int mixart_set_pipe_state(mixart_mgr_t *mgr, mixart_pipe_t* pipe, int start)
+{
+	mixart_group_state_req_t group_state;
+	mixart_group_state_resp_t group_state_resp;
+	mixart_msg_t request;
+	int err;
+	u32 system_msg_uid;
+
+	switch(pipe->status) {
+	case PIPE_RUNNING:
+	case PIPE_CLOCK_SET:
+		if(start) return 0; /* already started */
+		break;
+	case PIPE_STOPPED:
+		if(!start) return 0; /* already stopped */
+		break;
+	default:
+		snd_printk(KERN_ERR "error mixart_set_pipe_state called with wrong pipe->status!\n");
+		return -EINVAL;      /* function called with wrong pipe status */
+	}
+
+	system_msg_uid = 0x12345678; /* the event ! (take care: the MSB and two LSB's have to be 0) */
+
+	/* wait on the last MSG_SYSTEM_SEND_SYNCHRO_CMD command to be really finished */
+
+	request.message_id = MSG_SYSTEM_WAIT_SYNCHRO_CMD;
+	request.uid = (mixart_uid_t){0,0};
+	request.data = &system_msg_uid;
+	request.size = sizeof(system_msg_uid);
+
+	err = snd_mixart_send_msg_wait_notif(mgr, &request, system_msg_uid);
+	if(err) {
+		snd_printk(KERN_ERR "error : MSG_SYSTEM_WAIT_SYNCHRO_CMD was not notified !\n");
+		return err;
+	}
+
+	/* start or stop the pipe (1 pipe) */
+
+	memset(&group_state, 0, sizeof(group_state));
+	group_state.pipe_count = 1;
+	group_state.pipe_uid[0] = pipe->group_uid;
+
+	if(start)
+		request.message_id = MSG_STREAM_START_STREAM_GRP_PACKET;
+	else
+		request.message_id = MSG_STREAM_STOP_STREAM_GRP_PACKET;
+
+	request.uid = pipe->group_uid; /*(mixart_uid_t){0,0};*/
+	request.data = &group_state;
+	request.size = sizeof(group_state);
+
+	err = snd_mixart_send_msg(mgr, &request, sizeof(group_state_resp), &group_state_resp);
+	if (err < 0 || group_state_resp.txx_status != 0) {
+		snd_printk(KERN_ERR "error MSG_STREAM_ST***_STREAM_GRP_PACKET err=%x stat=%x !\n", err, group_state_resp.txx_status);
+		return -EINVAL;
+	}
+
+	if(start) {
+		u32 stat;
+
+		group_state.pipe_count = 0; /* in case of start same command once again with pipe_count=0 */
+
+		err = snd_mixart_send_msg(mgr, &request, sizeof(group_state_resp), &group_state_resp);
+		if (err < 0 || group_state_resp.txx_status != 0) {
+			snd_printk(KERN_ERR "error MSG_STREAM_START_STREAM_GRP_PACKET err=%x stat=%x !\n", err, group_state_resp.txx_status);
+ 			return -EINVAL;
+		}
+
+		/* in case of start send a synchro top */
+
+		request.message_id = MSG_SYSTEM_SEND_SYNCHRO_CMD;
+		request.uid = (mixart_uid_t){0,0};
+		request.data = NULL;
+		request.size = 0;
+
+		err = snd_mixart_send_msg(mgr, &request, sizeof(stat), &stat);
+		if (err < 0 || stat != 0) {
+			snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD err=%x stat=%x !\n", err, stat);
+			return -EINVAL;
+		}
+
+		pipe->status = PIPE_RUNNING;
+	}
+	else /* !start */
+		pipe->status = PIPE_STOPPED;
+
+	return 0;
+}
+
+
+static int mixart_set_clock(mixart_mgr_t *mgr, mixart_pipe_t *pipe, unsigned int rate)
+{
+	mixart_msg_t request;
+	mixart_clock_properties_t clock_properties;
+	mixart_clock_properties_resp_t clock_prop_resp;
+	int err;
+
+	switch(pipe->status) {
+	case PIPE_CLOCK_SET:
+		break;
+	case PIPE_RUNNING:
+		if(rate != 0)
+			break;
+	default:
+		if(rate == 0)
+			return 0; /* nothing to do */
+		else {
+			snd_printk(KERN_ERR "error mixart_set_clock(%d) called with wrong pipe->status !\n", rate);
+			return -EINVAL;
+		}
+	}
+
+	memset(&clock_properties, 0, sizeof(clock_properties));
+	clock_properties.clock_generic_type = (rate != 0) ? CGT_INTERNAL_CLOCK : CGT_NO_CLOCK;
+	clock_properties.clock_mode = CM_STANDALONE;
+	clock_properties.frequency = rate;
+	clock_properties.nb_callers = 1; /* only one entry in uid_caller ! */
+	clock_properties.uid_caller[0] = pipe->group_uid;
+
+	snd_printdd("mixart_set_clock to %d kHz\n", rate);
+
+	request.message_id = MSG_CLOCK_SET_PROPERTIES;
+	request.uid = mgr->uid_console_manager;
+	request.data = &clock_properties;
+	request.size = sizeof(clock_properties);
+
+	err = snd_mixart_send_msg(mgr, &request, sizeof(clock_prop_resp), &clock_prop_resp);
+	if (err < 0 || clock_prop_resp.status != 0 || clock_prop_resp.clock_mode != CM_STANDALONE) {
+		snd_printk(KERN_ERR "error MSG_CLOCK_SET_PROPERTIES err=%x stat=%x mod=%x !\n", err, clock_prop_resp.status, clock_prop_resp.clock_mode);
+		return -EINVAL;
+	}
+
+	if(rate)  pipe->status = PIPE_CLOCK_SET;
+	else      pipe->status = PIPE_RUNNING;
+
+	return 0;
+}
+
+
+/*
+ *  Allocate or reference output pipe for analog IOs (pcmp0/1)
+ */
+mixart_pipe_t* snd_mixart_add_ref_pipe( mixart_t *chip, int pcm_number, int capture, int monitoring)
+{
+	int stream_count;
+	mixart_pipe_t *pipe;
+	mixart_msg_t request;
+
+	if(capture) {
+		if (pcm_number == MIXART_PCM_ANALOG) {
+			pipe = &(chip->pipe_in_ana);  /* analog inputs */
+		} else {
+			pipe = &(chip->pipe_in_dig); /* digital inputs */
+		}
+		request.message_id = MSG_STREAM_ADD_OUTPUT_GROUP;
+		stream_count = MIXART_CAPTURE_STREAMS;
+	} else {
+		if (pcm_number == MIXART_PCM_ANALOG) {
+			pipe = &(chip->pipe_out_ana);  /* analog outputs */
+		} else {
+			pipe = &(chip->pipe_out_dig);  /* digital outputs */
+		}
+		request.message_id = MSG_STREAM_ADD_INPUT_GROUP;
+		stream_count = MIXART_PLAYBACK_STREAMS;
+	}
+
+	/* a new stream is opened and there are already all streams in use */
+	if( (monitoring == 0) && (pipe->references >= stream_count) ) {
+		return NULL;
+	}
+
+	/* pipe is not yet defined */
+	if( pipe->status == PIPE_UNDEFINED ) {
+		int err, i;
+		mixart_streaming_group_t streaming_group_resp;
+		mixart_streaming_group_req_t streaming_group_req;
+
+		snd_printdd("add_ref_pipe audio chip(%d) pcm(%d)\n", chip->chip_idx, pcm_number);
+
+		request.uid = (mixart_uid_t){0,0};      /* should be StreamManagerUID, but zero is OK if there is only one ! */
+		request.data = &streaming_group_req;
+		request.size = sizeof(streaming_group_req);
+
+		memset(&streaming_group_req, 0, sizeof(streaming_group_req));
+
+		streaming_group_req.stream_count = stream_count;
+		streaming_group_req.channel_count = 2;
+		streaming_group_req.latency = 256;
+		streaming_group_req.connector = pipe->uid_left_connector;  /* the left connector */
+
+		for (i=0; i<stream_count; i++) {
+			int j;
+			struct mixart_flowinfo *flowinfo;
+			struct mixart_bufferinfo *bufferinfo;
+			
+			/* we don't yet know the format, so config 16 bit pcm audio for instance */
+			streaming_group_req.stream_info[i].size_max_byte_frame = 1024;
+			streaming_group_req.stream_info[i].size_max_sample_frame = 256;
+			streaming_group_req.stream_info[i].nb_bytes_max_per_sample = MIXART_FLOAT_P__4_0_TO_HEX; /* is 4.0f */
+
+			/* find the right bufferinfo_array */
+			j = (chip->chip_idx * MIXART_MAX_STREAM_PER_CARD) + (pcm_number * (MIXART_PLAYBACK_STREAMS + MIXART_CAPTURE_STREAMS)) + i;
+			if(capture) j += MIXART_PLAYBACK_STREAMS; /* in the array capture is behind playback */
+
+			streaming_group_req.flow_entry[i] = j;
+
+			flowinfo = (struct mixart_flowinfo *)chip->mgr->flowinfo.area;
+			flowinfo[j].bufferinfo_array_phy_address = (u32)chip->mgr->bufferinfo.addr + (j * sizeof(mixart_bufferinfo_t));
+			flowinfo[j].bufferinfo_count = 1;               /* 1 will set the miXart to ring-buffer mode ! */
+
+			bufferinfo = (struct mixart_bufferinfo *)chip->mgr->bufferinfo.area;
+			bufferinfo[j].buffer_address = 0;               /* buffer is not yet allocated */
+			bufferinfo[j].available_length = 0;             /* buffer is not yet allocated */
+
+			/* construct the identifier of the stream buffer received in the interrupts ! */
+			bufferinfo[j].buffer_id = (chip->chip_idx << MIXART_NOTIFY_CARD_OFFSET) + (pcm_number << MIXART_NOTIFY_PCM_OFFSET ) + i;
+			if(capture) {
+				bufferinfo[j].buffer_id |= MIXART_NOTIFY_CAPT_MASK;
+			}
+		}
+
+		err = snd_mixart_send_msg(chip->mgr, &request, sizeof(streaming_group_resp), &streaming_group_resp);
+		if((err < 0) || (streaming_group_resp.status != 0)) {
+			snd_printk(KERN_ERR "error MSG_STREAM_ADD_**PUT_GROUP err=%x stat=%x !\n", err, streaming_group_resp.status);
+			return NULL;
+		}
+
+		pipe->group_uid = streaming_group_resp.group;     /* id of the pipe, as returned by embedded */
+		pipe->stream_count = streaming_group_resp.stream_count;
+		/* pipe->stream_uid[i] = streaming_group_resp.stream[i].stream_uid; */
+
+		pipe->status = PIPE_STOPPED;
+	}
+
+	if(monitoring)	pipe->monitoring = 1;
+	else		pipe->references++;
+
+	return pipe;
+}
+
+
+int snd_mixart_kill_ref_pipe( mixart_mgr_t *mgr, mixart_pipe_t *pipe, int monitoring)
+{
+	int err = 0;
+
+	if(pipe->status == PIPE_UNDEFINED)
+		return 0;
+
+	if(monitoring)
+		pipe->monitoring = 0;
+	else
+		pipe->references--;
+
+	if((pipe->references <= 0) && (pipe->monitoring == 0)) {
+
+		mixart_msg_t request;
+		mixart_delete_group_resp_t delete_resp;
+
+		/* release the clock */
+		err = mixart_set_clock( mgr, pipe, 0);
+		if( err < 0 ) {
+			snd_printk(KERN_ERR "mixart_set_clock(0) return error!\n");
+		}
+
+		/* stop the pipe */
+		err = mixart_set_pipe_state(mgr, pipe, 0);
+		if( err < 0 ) {
+			snd_printk(KERN_ERR "error stopping pipe!\n");
+		}
+
+		request.message_id = MSG_STREAM_DELETE_GROUP;
+		request.uid = (mixart_uid_t){0,0};
+		request.data = &pipe->group_uid;            /* the streaming group ! */
+		request.size = sizeof(pipe->group_uid);
+
+		/* delete the pipe */
+		err = snd_mixart_send_msg(mgr, &request, sizeof(delete_resp), &delete_resp);
+		if ((err < 0) || (delete_resp.status != 0)) {
+			snd_printk(KERN_ERR "error MSG_STREAM_DELETE_GROUP err(%x), status(%x)\n", err, delete_resp.status);
+		}
+
+		pipe->group_uid = (mixart_uid_t){0,0};
+		pipe->stream_count = 0;
+		pipe->status = PIPE_UNDEFINED;
+	}
+
+	return err;
+}
+
+static int mixart_set_stream_state(mixart_stream_t *stream, int start)
+{
+	mixart_t *chip;
+	mixart_stream_state_req_t stream_state_req;
+	mixart_msg_t request;
+
+	if(!stream->substream)
+		return -EINVAL;
+
+	memset(&stream_state_req, 0, sizeof(stream_state_req));
+	stream_state_req.stream_count = 1;
+	stream_state_req.stream_info.stream_desc.uid_pipe = stream->pipe->group_uid;
+	stream_state_req.stream_info.stream_desc.stream_idx = stream->substream->number;
+
+	if (stream->substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		request.message_id = start ? MSG_STREAM_START_INPUT_STAGE_PACKET : MSG_STREAM_STOP_INPUT_STAGE_PACKET;
+	else
+		request.message_id = start ? MSG_STREAM_START_OUTPUT_STAGE_PACKET : MSG_STREAM_STOP_OUTPUT_STAGE_PACKET;
+
+	request.uid = (mixart_uid_t){0,0};
+	request.data = &stream_state_req;
+	request.size = sizeof(stream_state_req);
+
+	stream->abs_period_elapsed = 0;            /* reset stream pos      */
+	stream->buf_periods = 0;
+	stream->buf_period_frag = 0;
+
+	chip = snd_pcm_substream_chip(stream->substream);
+
+	return snd_mixart_send_msg_nonblock(chip->mgr, &request);
+}
+
+/*
+ *  Trigger callback
+ */
+
+static int snd_mixart_trigger(snd_pcm_substream_t *subs, int cmd)
+{
+	mixart_stream_t *stream = (mixart_stream_t*)subs->runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+
+		snd_printdd("SNDRV_PCM_TRIGGER_START\n");
+
+		/* START_STREAM */
+		if( mixart_set_stream_state(stream, 1) )
+			return -EINVAL;
+
+		stream->status = MIXART_STREAM_STATUS_RUNNING;
+
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+
+		/* STOP_STREAM */
+		if( mixart_set_stream_state(stream, 0) )
+			return -EINVAL;
+
+		stream->status = MIXART_STREAM_STATUS_OPEN;
+
+		snd_printdd("SNDRV_PCM_TRIGGER_STOP\n");
+
+		break;
+
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		/* TODO */
+		stream->status = MIXART_STREAM_STATUS_PAUSE;
+		snd_printdd("SNDRV_PCM_PAUSE_PUSH\n");
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		/* TODO */
+		stream->status = MIXART_STREAM_STATUS_RUNNING;
+		snd_printdd("SNDRV_PCM_PAUSE_RELEASE\n");
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int mixart_sync_nonblock_events(mixart_mgr_t *mgr)
+{
+	int timeout = HZ;
+	while (atomic_read(&mgr->msg_processed) > 0) {
+		if (! timeout--) {
+			snd_printk(KERN_ERR "mixart: cannot process nonblock events!\n");
+			return -EBUSY;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+	return 0;
+}
+
+/*
+ *  prepare callback for all pcms
+ *
+ *  NOTE: this callback is non-atomic (pcm->info_flags |= SNDRV_PCM_INFO_NONATOMIC_OPS)
+ */
+static int snd_mixart_prepare(snd_pcm_substream_t *subs)
+{
+	mixart_t *chip = snd_pcm_substream_chip(subs);
+	mixart_stream_t *stream = (mixart_stream_t*)subs->runtime->private_data;
+
+	/* TODO de façon non bloquante, réappliquer les hw_params (rate, bits, codec) */
+
+	snd_printdd("snd_mixart_prepare\n");
+
+	mixart_sync_nonblock_events(chip->mgr);
+
+	/* only the first stream can choose the sample rate */
+	/* the further opened streams will be limited to its frequency (see open) */
+	if(chip->mgr->ref_count_rate == 1)
+		chip->mgr->sample_rate = subs->runtime->rate;
+
+	/* set the clock only once (first stream) on the same pipe */
+	if(stream->pipe->references == 1) {
+		if( mixart_set_clock(chip->mgr, stream->pipe, subs->runtime->rate) )
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+static int mixart_set_format(mixart_stream_t *stream, snd_pcm_format_t format)
+{
+	int err;
+	mixart_t *chip;
+	mixart_msg_t request;
+	mixart_stream_param_desc_t stream_param;
+	mixart_return_uid_t resp;
+
+	chip = snd_pcm_substream_chip(stream->substream);
+
+	memset(&stream_param, 0, sizeof(stream_param));
+
+	stream_param.coding_type = CT_LINEAR;
+	stream_param.number_of_channel = stream->channels;
+
+	stream_param.sampling_freq = chip->mgr->sample_rate;
+	if(stream_param.sampling_freq == 0)
+		stream_param.sampling_freq = 44100; /* if frequency not yet defined, use some default */
+
+	switch(format){
+	case SNDRV_PCM_FORMAT_U8:
+		stream_param.sample_type = ST_INTEGER_8;
+		stream_param.sample_size = 8;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		stream_param.sample_type = ST_INTEGER_16LE;
+		stream_param.sample_size = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S16_BE:
+		stream_param.sample_type = ST_INTEGER_16BE;
+		stream_param.sample_size = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_3LE:
+		stream_param.sample_type = ST_INTEGER_24LE;
+		stream_param.sample_size = 24;
+		break;
+	case SNDRV_PCM_FORMAT_S24_3BE:
+		stream_param.sample_type = ST_INTEGER_24BE;
+		stream_param.sample_size = 24;
+		break;
+	case SNDRV_PCM_FMTBIT_FLOAT_LE:
+		stream_param.sample_type = ST_FLOATING_POINT_32LE;
+		stream_param.sample_size = 32;
+		break;
+	case  SNDRV_PCM_FMTBIT_FLOAT_BE:
+		stream_param.sample_type = ST_FLOATING_POINT_32BE;
+		stream_param.sample_size = 32;
+		break;
+	default:
+		snd_printk(KERN_ERR "error mixart_set_format() : unknown format\n");
+		return -EINVAL;
+	}
+
+	snd_printdd("set SNDRV_PCM_FORMAT sample_type(%d) sample_size(%d) freq(%d) channels(%d)\n",
+		   stream_param.sample_type, stream_param.sample_size, stream_param.sampling_freq, stream->channels);
+
+	/* TODO: what else to configure ? */
+	/* stream_param.samples_per_frame = 2; */
+	/* stream_param.bytes_per_frame = 4; */
+	/* stream_param.bytes_per_sample = 2; */
+
+	stream_param.pipe_count = 1;      /* set to 1 */
+	stream_param.stream_count = 1;    /* set to 1 */
+	stream_param.stream_desc[0].uid_pipe = stream->pipe->group_uid;
+	stream_param.stream_desc[0].stream_idx = stream->substream->number;
+
+	request.message_id = MSG_STREAM_SET_INPUT_STAGE_PARAM;
+	request.uid = (mixart_uid_t){0,0};
+	request.data = &stream_param;
+	request.size = sizeof(stream_param);
+
+	err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp);
+	if((err < 0) || resp.error_code) {
+		snd_printk(KERN_ERR "MSG_STREAM_SET_INPUT_STAGE_PARAM err=%x; resp=%x\n", err, resp.error_code);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+/*
+ *  HW_PARAMS callback for all pcms
+ */
+static int snd_mixart_hw_params(snd_pcm_substream_t *subs,
+                                snd_pcm_hw_params_t *hw)
+{
+	mixart_t *chip = snd_pcm_substream_chip(subs);
+	mixart_mgr_t *mgr = chip->mgr;
+	mixart_stream_t *stream = (mixart_stream_t*)subs->runtime->private_data;
+	snd_pcm_format_t format;
+	int err;
+	int channels;
+
+	/* set up channels */
+	channels = params_channels(hw);
+
+	/*  set up format for the stream */
+	format = params_format(hw);
+
+	down(&mgr->setup_mutex);
+
+	/* update the stream levels */
+	if( stream->pcm_number <= MIXART_PCM_DIGITAL ) {
+		int is_aes = stream->pcm_number > MIXART_PCM_ANALOG;
+		if( subs->stream == SNDRV_PCM_STREAM_PLAYBACK )
+			mixart_update_playback_stream_level(chip, is_aes, subs->number);
+		else
+			mixart_update_capture_stream_level( chip, is_aes);
+	}
+
+	stream->channels = channels;
+
+	/* set the format to the board */
+	err = mixart_set_format(stream, format);
+	if(err < 0) {
+		return err;
+	}
+
+	/* allocate buffer */
+	err = snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw));
+
+	if (err > 0) {
+		struct mixart_bufferinfo *bufferinfo;
+		int i = (chip->chip_idx * MIXART_MAX_STREAM_PER_CARD) + (stream->pcm_number * (MIXART_PLAYBACK_STREAMS+MIXART_CAPTURE_STREAMS)) + subs->number;
+		if( subs->stream == SNDRV_PCM_STREAM_CAPTURE ) {
+			i += MIXART_PLAYBACK_STREAMS; /* in array capture is behind playback */
+		}
+		
+		bufferinfo = (struct mixart_bufferinfo *)chip->mgr->bufferinfo.area;
+		bufferinfo[i].buffer_address = subs->runtime->dma_addr;
+		bufferinfo[i].available_length = subs->runtime->dma_bytes;
+		/* bufferinfo[i].buffer_id  is already defined */
+
+		snd_printdd("snd_mixart_hw_params(pcm %d) : dma_addr(%x) dma_bytes(%x) subs-number(%d)\n", i, subs->runtime->dma_addr, subs->runtime->dma_bytes, subs->number);
+	}
+	up(&mgr->setup_mutex);
+
+	return err;
+}
+
+static int snd_mixart_hw_free(snd_pcm_substream_t *subs)
+{
+	mixart_t *chip = snd_pcm_substream_chip(subs);
+	snd_pcm_lib_free_pages(subs);
+	mixart_sync_nonblock_events(chip->mgr);
+	return 0;
+}
+
+
+
+/*
+ *  TODO CONFIGURATION SPACE for all pcms, mono pcm must update channels_max
+ */
+static snd_pcm_hardware_t snd_mixart_analog_caps =
+{
+	.info             = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+			      SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
+			      SNDRV_PCM_INFO_PAUSE),
+	.formats	  = ( SNDRV_PCM_FMTBIT_U8 |
+			      SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
+			      SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
+			      SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE ),
+	.rates            = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
+	.rate_min         = 8000,
+	.rate_max         = 48000,
+	.channels_min     = 1,
+	.channels_max     = 2,
+	.buffer_bytes_max = (32*1024),
+	.period_bytes_min = 256,                  /* 256 frames U8 mono*/
+	.period_bytes_max = (16*1024),
+	.periods_min      = 2,
+	.periods_max      = (32*1024/256),
+};
+
+static snd_pcm_hardware_t snd_mixart_digital_caps =
+{
+	.info             = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+			      SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
+			      SNDRV_PCM_INFO_PAUSE),
+	.formats	  = ( SNDRV_PCM_FMTBIT_U8 |
+			      SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
+			      SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
+			      SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE ),
+	.rates            = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+	.rate_min         = 32000,
+	.rate_max         = 48000,
+	.channels_min     = 1,
+	.channels_max     = 2,
+	.buffer_bytes_max = (32*1024),
+	.period_bytes_min = 256,                  /* 256 frames U8 mono*/
+	.period_bytes_max = (16*1024),
+	.periods_min      = 2,
+	.periods_max      = (32*1024/256),
+};
+
+
+static int snd_mixart_playback_open(snd_pcm_substream_t *subs)
+{
+	mixart_t            *chip = snd_pcm_substream_chip(subs);
+	mixart_mgr_t        *mgr = chip->mgr;
+	snd_pcm_runtime_t   *runtime = subs->runtime;
+	snd_pcm_t           *pcm = subs->pcm;
+	mixart_stream_t     *stream;
+	mixart_pipe_t       *pipe;
+	int err = 0;
+	int pcm_number;
+
+	down(&mgr->setup_mutex);
+
+	if ( pcm == chip->pcm ) {
+		pcm_number = MIXART_PCM_ANALOG;
+		runtime->hw = snd_mixart_analog_caps;
+	} else {
+		snd_assert ( pcm == chip->pcm_dig ); 
+		pcm_number = MIXART_PCM_DIGITAL;
+		runtime->hw = snd_mixart_digital_caps;
+	}
+	snd_printdd("snd_mixart_playback_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number);
+
+	/* get stream info */
+	stream = &(chip->playback_stream[pcm_number][subs->number]);
+
+	if (stream->status != MIXART_STREAM_STATUS_FREE){
+		/* streams in use */
+		snd_printk(KERN_ERR "snd_mixart_playback_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number);
+		err = -EBUSY;
+		goto _exit_open;
+	}
+
+	/* get pipe pointer (out pipe) */
+	pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 0, 0);
+
+	if (pipe == NULL) {
+		err = -EINVAL;
+		goto _exit_open;
+	}
+
+	/* start the pipe if necessary */
+	err = mixart_set_pipe_state(chip->mgr, pipe, 1);
+	if( err < 0 ) {
+		snd_printk(KERN_ERR "error starting pipe!\n");
+		snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0);
+		err = -EINVAL;
+		goto _exit_open;
+	}
+
+	stream->pipe        = pipe;
+	stream->pcm_number  = pcm_number;
+	stream->status      = MIXART_STREAM_STATUS_OPEN;
+	stream->substream   = subs;
+	stream->channels    = 0; /* not configured yet */
+
+	runtime->private_data = stream;
+
+	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
+	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 64);
+
+	/* if a sample rate is already used, another stream cannot change */
+	if(mgr->ref_count_rate++) {
+		if(mgr->sample_rate) {
+			runtime->hw.rate_min = runtime->hw.rate_max = mgr->sample_rate;
+		}
+	}
+
+ _exit_open:
+	up(&mgr->setup_mutex);
+
+	return err;
+}
+
+
+static int snd_mixart_capture_open(snd_pcm_substream_t *subs)
+{
+	mixart_t            *chip = snd_pcm_substream_chip(subs);
+	mixart_mgr_t        *mgr = chip->mgr;
+	snd_pcm_runtime_t   *runtime = subs->runtime;
+	snd_pcm_t           *pcm = subs->pcm;
+	mixart_stream_t     *stream;
+	mixart_pipe_t       *pipe;
+	int err = 0;
+	int pcm_number;
+
+	down(&mgr->setup_mutex);
+
+	if ( pcm == chip->pcm ) {
+		pcm_number = MIXART_PCM_ANALOG;
+		runtime->hw = snd_mixart_analog_caps;
+	} else {
+		snd_assert ( pcm == chip->pcm_dig ); 
+		pcm_number = MIXART_PCM_DIGITAL;
+		runtime->hw = snd_mixart_digital_caps;
+	}
+
+	runtime->hw.channels_min = 2; /* for instance, no mono */
+
+	snd_printdd("snd_mixart_capture_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number);
+
+	/* get stream info */
+	stream = &(chip->capture_stream[pcm_number]);
+
+	if (stream->status != MIXART_STREAM_STATUS_FREE){
+		/* streams in use */
+		snd_printk(KERN_ERR "snd_mixart_capture_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number);
+		err = -EBUSY;
+		goto _exit_open;
+	}
+
+	/* get pipe pointer (in pipe) */
+	pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 1, 0);
+
+	if (pipe == NULL) {
+		err = -EINVAL;
+		goto _exit_open;
+	}
+
+	/* start the pipe if necessary */
+	err = mixart_set_pipe_state(chip->mgr, pipe, 1);
+	if( err < 0 ) {
+		snd_printk(KERN_ERR "error starting pipe!\n");
+		snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0);
+		err = -EINVAL;
+		goto _exit_open;
+	}
+
+	stream->pipe        = pipe;
+	stream->pcm_number  = pcm_number;
+	stream->status      = MIXART_STREAM_STATUS_OPEN;
+	stream->substream   = subs;
+	stream->channels    = 0; /* not configured yet */
+
+	runtime->private_data = stream;
+
+	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
+	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 64);
+
+	/* if a sample rate is already used, another stream cannot change */
+	if(mgr->ref_count_rate++) {
+		if(mgr->sample_rate) {
+			runtime->hw.rate_min = runtime->hw.rate_max = mgr->sample_rate;
+		}
+	}
+
+ _exit_open:
+	up(&mgr->setup_mutex);
+
+	return err;
+}
+
+
+
+static int snd_mixart_close(snd_pcm_substream_t *subs)
+{
+	mixart_t *chip = snd_pcm_substream_chip(subs);
+	mixart_mgr_t *mgr = chip->mgr;
+	mixart_stream_t *stream = (mixart_stream_t*)subs->runtime->private_data;
+
+	down(&mgr->setup_mutex);
+
+	snd_printdd("snd_mixart_close C%d/P%d/Sub%d\n", chip->chip_idx, stream->pcm_number, subs->number);
+
+	/* sample rate released */
+	if(--mgr->ref_count_rate == 0) {
+		mgr->sample_rate = 0;
+	}
+
+	/* delete pipe */
+	if (snd_mixart_kill_ref_pipe(mgr, stream->pipe, 0 ) < 0) {
+
+		snd_printk(KERN_ERR "error snd_mixart_kill_ref_pipe C%dP%d\n", chip->chip_idx, stream->pcm_number);
+	}
+
+	stream->pipe      = NULL;
+	stream->status    = MIXART_STREAM_STATUS_FREE;
+	stream->substream = NULL;
+
+	up(&mgr->setup_mutex);
+	return 0;
+}
+
+
+static snd_pcm_uframes_t snd_mixart_stream_pointer(snd_pcm_substream_t * subs)
+{
+	snd_pcm_runtime_t *runtime = subs->runtime;
+	mixart_stream_t   *stream  = (mixart_stream_t*)runtime->private_data;
+
+	return (snd_pcm_uframes_t)((stream->buf_periods * runtime->period_size) + stream->buf_period_frag);
+}
+
+
+
+static snd_pcm_ops_t snd_mixart_playback_ops = {
+	.open      = snd_mixart_playback_open,
+	.close     = snd_mixart_close,
+	.ioctl     = snd_pcm_lib_ioctl,
+	.prepare   = snd_mixart_prepare,
+	.hw_params = snd_mixart_hw_params,
+	.hw_free   = snd_mixart_hw_free,
+	.trigger   = snd_mixart_trigger,
+	.pointer   = snd_mixart_stream_pointer,
+};
+
+static snd_pcm_ops_t snd_mixart_capture_ops = {
+	.open      = snd_mixart_capture_open,
+	.close     = snd_mixart_close,
+	.ioctl     = snd_pcm_lib_ioctl,
+	.prepare   = snd_mixart_prepare,
+	.hw_params = snd_mixart_hw_params,
+	.hw_free   = snd_mixart_hw_free,
+	.trigger   = snd_mixart_trigger,
+	.pointer   = snd_mixart_stream_pointer,
+};
+
+static void preallocate_buffers(mixart_t *chip, snd_pcm_t *pcm)
+{
+	snd_pcm_substream_t *subs;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		int idx = 0;
+		for (subs = pcm->streams[stream].substream; subs; subs = subs->next, idx++)
+			/* set up the unique device id with the chip index */
+			subs->dma_device.id = subs->pcm->device << 16 |
+				subs->stream << 8 | (subs->number + 1) |
+				(chip->chip_idx + 1) << 24;
+	}
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(chip->mgr->pci), 32*1024, 32*1024);
+}
+
+/*
+ */
+static int snd_mixart_pcm_analog(mixart_t *chip)
+{
+	int err;
+	snd_pcm_t *pcm;
+	char name[32];
+
+	sprintf(name, "miXart analog %d", chip->chip_idx);
+	if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_ANALOG,
+			       MIXART_PLAYBACK_STREAMS,
+			       MIXART_CAPTURE_STREAMS, &pcm)) < 0) {
+		snd_printk(KERN_ERR "cannot create the analog pcm %d\n", chip->chip_idx);
+		return err;
+	}
+
+	pcm->private_data = chip;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_mixart_playback_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops);
+
+	pcm->info_flags = SNDRV_PCM_INFO_NONATOMIC_OPS;
+	strcpy(pcm->name, name);
+
+	preallocate_buffers(chip, pcm);
+
+	chip->pcm = pcm;
+	return 0;
+}
+
+
+/*
+ */
+static int snd_mixart_pcm_digital(mixart_t *chip)
+{
+	int err;
+	snd_pcm_t *pcm;
+	char name[32];
+
+	sprintf(name, "miXart AES/EBU %d", chip->chip_idx);
+	if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_DIGITAL,
+			       MIXART_PLAYBACK_STREAMS,
+			       MIXART_CAPTURE_STREAMS, &pcm)) < 0) {
+		snd_printk(KERN_ERR "cannot create the digital pcm %d\n", chip->chip_idx);
+		return err;
+	}
+
+	pcm->private_data = chip;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_mixart_playback_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops);
+
+	pcm->info_flags = SNDRV_PCM_INFO_NONATOMIC_OPS;
+	strcpy(pcm->name, name);
+
+	preallocate_buffers(chip, pcm);
+
+	chip->pcm_dig = pcm;
+	return 0;
+}
+
+static int snd_mixart_chip_free(mixart_t *chip)
+{
+	snd_magic_kfree(chip);
+	return 0;
+}
+
+static int snd_mixart_chip_dev_free(snd_device_t *device)
+{
+	mixart_t *chip = snd_magic_cast(mixart_t, device->device_data, return -ENXIO);
+	return snd_mixart_chip_free(chip);
+}
+
+
+/*
+ */
+static int __devinit snd_mixart_create(mixart_mgr_t *mgr, snd_card_t *card, int idx)
+{
+	int err;
+	mixart_t *chip;
+	static snd_device_ops_t ops = {
+		.dev_free = snd_mixart_chip_dev_free,
+	};
+
+	mgr->chip[idx] = chip = snd_magic_kcalloc(mixart_t, 0, GFP_KERNEL);
+	if (! chip) {
+		snd_printk(KERN_ERR "cannot allocate chip\n");
+		return -ENOMEM;
+	}
+
+	chip->card = card;
+	chip->chip_idx = idx;
+	chip->mgr = mgr;
+
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
+		snd_mixart_chip_free(chip);
+		return err;
+	}
+
+	if (idx == 0) {
+		/* create a DSP loader only on first cardX*/
+		err = snd_mixart_hwdep_new(mgr);
+		if (err < 0)
+			return err;
+	}
+
+	snd_card_set_dev(card, &mgr->pci->dev);
+
+	return 0;
+}
+
+int snd_mixart_create_pcm(mixart_t* chip)
+{
+	int err;
+
+	err = snd_mixart_pcm_analog(chip);
+	if (err < 0)
+		return err;
+
+	if(chip->mgr->board_type == MIXART_DAUGHTER_TYPE_AES) {
+
+		err = snd_mixart_pcm_digital(chip);
+		if (err < 0)
+			return err;
+	}
+	return err;
+}
+
+
+/*
+ * release all the cards assigned to a manager instance
+ */
+static int snd_mixart_free(mixart_mgr_t *mgr)
+{
+	unsigned int i;
+
+	for (i = 0; i < mgr->num_cards; i++) {
+		if (mgr->chip[i])
+			snd_card_free(mgr->chip[i]->card);
+	}
+
+	/* stop mailbox */
+	snd_mixart_exit_mailbox(mgr);
+
+	/* release irq  */
+	if (mgr->irq >= 0)
+		free_irq(mgr->irq, (void *)mgr);
+
+	/* reset board if some firmware was loaded */
+	if(mgr->hwdep->dsp_loaded) {
+		snd_mixart_reset_board(mgr);
+		snd_printdd("reset miXart !\n");
+	}
+
+	/* release the i/o ports */
+	for (i = 0; i < 2; i++) {
+		if (mgr->mem[i].virt)
+			iounmap((void *)mgr->mem[i].virt);
+		if (mgr->mem[i].res) {
+			release_resource(mgr->mem[i].res);
+			kfree_nocheck(mgr->mem[i].res);
+		}
+	}
+
+	/* free flowarray */
+	if(mgr->flowinfo.area) {
+		snd_dma_free_pages(&mgr->dma_dev, &mgr->flowinfo);
+		mgr->flowinfo.area = NULL;
+	}
+	/* free bufferarray */
+	if(mgr->bufferinfo.area) {
+		snd_dma_free_pages(&mgr->dma_dev, &mgr->bufferinfo);
+		mgr->bufferinfo.area = NULL;
+	}
+
+	snd_magic_kfree(mgr);
+	return 0;
+}
+
+/*
+ * proc interface
+ */
+static long long snd_mixart_BA0_llseek(snd_info_entry_t *entry,
+				       void *private_file_data,
+				       struct file *file,
+				       long long offset,
+				       int orig)
+{
+	offset = offset & ~3; /* 4 bytes aligned */
+
+	switch(orig) {
+	case 0:  /* SEEK_SET */
+		file->f_pos = offset;
+		break;
+	case 1:  /* SEEK_CUR */
+		file->f_pos += offset;
+		break;
+	case 2:  /* SEEK_END, offset is negative */
+		file->f_pos = MIXART_BA0_SIZE + offset;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if(file->f_pos > MIXART_BA0_SIZE)
+		file->f_pos = MIXART_BA0_SIZE;
+	return file->f_pos;
+}
+
+static long long snd_mixart_BA1_llseek(snd_info_entry_t *entry,
+				       void *private_file_data,
+				       struct file *file,
+				       long long offset,
+				       int orig)
+{
+	offset = offset & ~3; /* 4 bytes aligned */
+
+	switch(orig) {
+	case 0:  /* SEEK_SET */
+		file->f_pos = offset;
+		break;
+	case 1:  /* SEEK_CUR */
+		file->f_pos += offset;
+		break;
+	case 2: /* SEEK_END, offset is negative */
+		file->f_pos = MIXART_BA1_SIZE + offset;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if(file->f_pos > MIXART_BA1_SIZE)
+		file->f_pos = MIXART_BA1_SIZE;
+	return file->f_pos;
+}
+
+/*
+  mixart_BA0 proc interface for BAR 0 - read callback
+ */
+static long snd_mixart_BA0_read(snd_info_entry_t *entry, void *file_private_data,
+				struct file *file, char *buf, long count)
+{
+	mixart_mgr_t *mgr = snd_magic_cast(mixart_mgr_t, entry->private_data, return -ENXIO);
+
+	count = count & ~3; /* make sure the read size is a multiple of 4 bytes */
+	if(count <= 0)
+		return 0;
+	if(file->f_pos + count > MIXART_BA0_SIZE)
+		count = (long)(MIXART_BA0_SIZE - file->f_pos);
+	if(copy_to_user_fromio(buf, MIXART_MEM( mgr, file->f_pos ), count))
+		return -EFAULT;
+	file->f_pos += count;
+	return count;
+}
+
+/*
+  mixart_BA1 proc interface for BAR 1 - read callback
+ */
+static long snd_mixart_BA1_read(snd_info_entry_t *entry, void *file_private_data,
+				struct file *file, char *buf, long count)
+{
+	mixart_mgr_t *mgr = snd_magic_cast(mixart_mgr_t, entry->private_data, return -ENXIO);
+
+	count = count & ~3; /* make sure the read size is a multiple of 4 bytes */
+	if(count <= 0)
+		return 0;
+	if(file->f_pos + count > MIXART_BA1_SIZE)
+		count = (long)(MIXART_BA1_SIZE - file->f_pos);
+	if(copy_to_user_fromio(buf, MIXART_REG( mgr, file->f_pos ), count))
+		return -EFAULT;
+	file->f_pos += count;
+	return count;
+}
+
+static struct snd_info_entry_ops snd_mixart_proc_ops_BA0 = {
+	.read   = snd_mixart_BA0_read,
+	.llseek = snd_mixart_BA0_llseek
+};
+
+static struct snd_info_entry_ops snd_mixart_proc_ops_BA1 = {
+	.read   = snd_mixart_BA1_read,
+	.llseek = snd_mixart_BA1_llseek
+};
+
+
+static void snd_mixart_proc_read(snd_info_entry_t *entry, 
+                                 snd_info_buffer_t * buffer)
+{
+	mixart_t *chip = snd_magic_cast(mixart_t, entry->private_data, return);        
+	u32 ref; 
+
+	snd_iprintf(buffer, "Digigram miXart (alsa card %d)\n\n", chip->chip_idx);
+
+	/* stats available when embedded OS is running */
+	if (chip->mgr->hwdep->dsp_loaded & ( 1 << MIXART_MOTHERBOARD_ELF_INDEX)) {
+		snd_iprintf(buffer, "- hardware -\n");
+		switch (chip->mgr->board_type ) {
+		case MIXART_DAUGHTER_TYPE_NONE     : snd_iprintf(buffer, "\tmiXart8 (no daughter board)\n\n"); break;
+		case MIXART_DAUGHTER_TYPE_AES      : snd_iprintf(buffer, "\tmiXart8 AES/EBU\n\n"); break;
+		case MIXART_DAUGHTER_TYPE_COBRANET : snd_iprintf(buffer, "\tmiXart8 Cobranet\n\n"); break;
+		default:                             snd_iprintf(buffer, "\tUNKNOWN!\n\n"); break;
+		}
+
+		snd_iprintf(buffer, "- system load -\n");	 
+
+		/* get perf reference */
+
+		ref = readl_be( MIXART_MEM( chip->mgr, MIXART_PSEUDOREG_PERF_SYSTEM_LOAD_OFFSET));
+
+		if (ref) {
+			u32 mailbox   = 100 * readl_be( MIXART_MEM( chip->mgr, MIXART_PSEUDOREG_PERF_MAILBX_LOAD_OFFSET)) / ref;
+			u32 streaming = 100 * readl_be( MIXART_MEM( chip->mgr, MIXART_PSEUDOREG_PERF_STREAM_LOAD_OFFSET)) / ref;
+			u32 interr    = 100 * readl_be( MIXART_MEM( chip->mgr, MIXART_PSEUDOREG_PERF_INTERR_LOAD_OFFSET)) / ref;
+
+			snd_iprintf(buffer, "\tstreaming          : %d\n", streaming);
+			snd_iprintf(buffer, "\tmailbox            : %d\n", mailbox);
+			snd_iprintf(buffer, "\tinterrups handling : %d\n\n", interr);
+		}
+	} /* endif elf loaded */
+}
+
+static void __devinit snd_mixart_proc_init(mixart_t *chip)
+{
+	snd_info_entry_t *entry;
+
+	/* text interface to read perf and temp meters */
+	if (! snd_card_proc_new(chip->card, "board_info", &entry)) {
+		entry->private_data = chip;
+		entry->c.text.read_size = 1024;
+		entry->c.text.read = snd_mixart_proc_read;
+	}
+
+	if (! snd_card_proc_new(chip->card, "mixart_BA0", &entry)) {
+		entry->content = SNDRV_INFO_CONTENT_DATA;
+		entry->private_data = chip->mgr;	
+		entry->c.ops = &snd_mixart_proc_ops_BA0;
+		entry->size = MIXART_BA0_SIZE;
+	}
+	if (! snd_card_proc_new(chip->card, "mixart_BA1", &entry)) {
+		entry->content = SNDRV_INFO_CONTENT_DATA;
+		entry->private_data = chip->mgr;
+		entry->c.ops = &snd_mixart_proc_ops_BA1;
+		entry->size = MIXART_BA1_SIZE;
+	}
+}
+/* end of proc interface */
+
+
+/*
+ *    probe function - creates the card manager
+ */
+static int __devinit snd_mixart_probe(struct pci_dev *pci,
+				      const struct pci_device_id *pci_id)
+{
+	static int dev;
+	mixart_mgr_t *mgr;
+	unsigned int i;
+	int err;
+	size_t size;
+
+	/*
+	 */
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (! enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	/* enable PCI device */
+	if ((err = pci_enable_device(pci)) < 0)
+		return err;
+	pci_set_master(pci);
+
+	/* check if we can restrict PCI DMA transfers to 32 bits */
+	if (!pci_dma_supported(pci, 0xffffffff)) {
+		snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n");
+		return -ENXIO;
+	}
+	pci_set_dma_mask(pci, 0xffffffff);
+
+	/*
+	 */
+	mgr = snd_magic_kcalloc(mixart_mgr_t, 0, GFP_KERNEL);
+	if (! mgr)
+		return -ENOMEM;
+
+	mgr->pci = pci;
+	mgr->irq = -1;
+
+	/* resource assignment */
+	for (i = 0; i < 2; i++) {
+		static int memory_sizes[2] = {
+			MIXART_BA0_SIZE, /* 16M */	  
+			MIXART_BA1_SIZE  /* 4 k */
+		};
+		mgr->mem[i].phys = pci_resource_start(pci, i);
+		mgr->mem[i].res = request_mem_region(mgr->mem[i].phys, memory_sizes[i], CARD_NAME);
+		if (! mgr->mem[i].res) {
+			snd_printk(KERN_ERR "unable to grab memory 0x%lx\n", mgr->mem[i].phys);
+			snd_mixart_free(mgr);
+			return -EBUSY;
+		}
+		mgr->mem[i].virt = (unsigned long)ioremap_nocache(mgr->mem[i].phys, memory_sizes[i]);
+	}
+
+	if (request_irq(pci->irq, snd_mixart_interrupt, SA_INTERRUPT|SA_SHIRQ, CARD_NAME, (void *)mgr)) {
+		snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+		snd_mixart_free(mgr);
+		return -EBUSY;
+	}
+	mgr->irq = pci->irq;
+
+	sprintf(mgr->shortname, "Digigram miXart");
+	sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, irq %i", mgr->shortname, mgr->mem[0].phys, mgr->mem[1].phys, mgr->irq);
+
+	/* ISR spinlock  */
+	mgr->lock = SPIN_LOCK_UNLOCKED;
+
+	/* init mailbox  */
+	mgr->msg_fifo_readptr = 0;
+	mgr->msg_fifo_writeptr = 0;
+
+	mgr->msg_lock = SPIN_LOCK_UNLOCKED;
+	init_MUTEX(&mgr->msg_mutex);
+	init_waitqueue_head(&mgr->msg_sleep);
+	atomic_set(&mgr->msg_processed, 0);
+
+	/* init setup mutex*/
+	init_MUTEX(&mgr->setup_mutex);
+
+	/* init message taslket */
+	tasklet_init( &mgr->msg_taskq, snd_mixart_msg_tasklet, (unsigned long) mgr);
+
+	/* card assignment */
+	mgr->num_cards = MIXART_MAX_CARDS; /* 4  FIXME: configurable? */
+	for (i = 0; i < mgr->num_cards; i++) {
+		snd_card_t *card;
+		char tmpid[16];
+		int idx;
+
+		if (index[dev] < 0)
+			idx = index[dev];
+		else
+			idx = index[dev] + i;
+		snprintf(tmpid, sizeof(tmpid), "%s-%d", id[dev], i);
+		card = snd_card_new(idx, tmpid, THIS_MODULE, 0);
+
+		if (! card) {
+			snd_printk(KERN_ERR "cannot allocate the card %d\n", i);
+			snd_mixart_free(mgr);
+			return -ENOMEM;
+		}
+
+		strcpy(card->driver, CARD_NAME);
+		sprintf(card->shortname, "%s [PCM #%d]", mgr->shortname, i);
+		sprintf(card->longname, "%s [PCM #%d]", mgr->longname, i);
+
+		if ((err = snd_mixart_create(mgr, card, i)) < 0) {
+			snd_mixart_free(mgr);
+			return err;
+		}
+
+		if(i==0) {
+			/* init proc interface only for chip0 */
+			snd_mixart_proc_init(mgr->chip[i]);
+		}
+
+		if ((err = snd_card_register(card)) < 0) {
+			snd_mixart_free(mgr);
+			return err;
+		}
+	}
+
+	/* init firmware status (mgr->hwdep->dsp_loaded reset in hwdep_new) */
+	mgr->board_type = MIXART_DAUGHTER_TYPE_NONE;
+
+	memset(&mgr->dma_dev, 0, sizeof(mgr->dma_dev));
+	mgr->dma_dev.type = SNDRV_DMA_TYPE_DEV;
+	mgr->dma_dev.dev = snd_dma_pci_data(mgr->pci);
+
+	/* create array of streaminfo */
+	size = PAGE_ALIGN( (MIXART_MAX_STREAM_PER_CARD * MIXART_MAX_CARDS * sizeof(mixart_flowinfo_t)) );
+	if (snd_dma_alloc_pages(&mgr->dma_dev, size, &mgr->flowinfo) < 0) {
+		snd_mixart_free(mgr);
+		return -ENOMEM;
+	}
+	/* init streaminfo_array */
+	memset(mgr->flowinfo.area, 0, size);
+
+	/* create array of bufferinfo */
+	size = PAGE_ALIGN( (MIXART_MAX_STREAM_PER_CARD * MIXART_MAX_CARDS * sizeof(mixart_bufferinfo_t)) );
+	if (snd_dma_alloc_pages(&mgr->dma_dev, size, &mgr->bufferinfo) < 0) {
+		snd_mixart_free(mgr);
+		return -ENOMEM;
+	}
+	/* init bufferinfo_array */
+	memset(mgr->bufferinfo.area, 0, size);
+
+	pci_set_drvdata(pci, mgr);
+	dev++;
+	return 0;
+}
+
+static void __devexit snd_mixart_remove(struct pci_dev *pci)
+{
+	snd_mixart_free(pci_get_drvdata(pci));
+	pci_set_drvdata(pci, NULL);
+}
+
+static struct pci_driver driver = {
+	.name = "Digigram miXart",
+	.id_table = snd_mixart_ids,
+	.probe = snd_mixart_probe,
+	.remove = __devexit_p(snd_mixart_remove),
+};
+
+static int __init alsa_card_mixart_init(void)
+{
+	int err;
+
+	if ((err = pci_module_init(&driver)) < 0) {
+#ifdef MODULE
+		snd_printk(KERN_ERR "Digigram miXart soundcard not found or device busy\n");
+#endif
+		return err;
+	}
+	return 0;
+}
+
+static void __exit alsa_card_mixart_exit(void)
+{
+	pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_mixart_init)
+module_exit(alsa_card_mixart_exit)
+
+#ifndef MODULE
+
+/* format is: snd-mixart=enable,index,id */
+
+static int __init alsa_card_mixart_setup(char *str)
+{
+	static unsigned __initdata nr_dev = 0;
+
+	if (nr_dev >= SNDRV_CARDS)
+		return 0;
+	(void)(get_option(&str,&enable[nr_dev]) == 2 &&
+	       get_option(&str,&index[nr_dev]) == 2 &&
+	       get_id(&str,&id[nr_dev]) == 2);
+	nr_dev++;
+	return 1;
+}
+
+__setup("snd-mixart=", alsa_card_mixart_setup);
+
+#endif /* ifndef MODULE */
--- diff/sound/pci/mixart/mixart.h	1970-01-01 01:00:00.000000000 +0100
+++ source/sound/pci/mixart/mixart.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,243 @@
+/*
+ * Driver for Digigram miXart soundcards
+ *
+ * main header file
+ *
+ * Copyright (c) 2003 by Digigram <alsa@digigram.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef __SOUND_MIXART_H
+#define __SOUND_MIXART_H
+
+#include <linux/interrupt.h>
+#include <sound/pcm.h>
+
+#define MIXART_DRIVER_VERSION	0x000100	/* 0.1.0 */
+
+
+/*
+ */
+
+#define mixart_t_magic		0xa17a3e01
+#define mixart_mgr_t_magic	0xa17a3e02
+
+typedef struct snd_mixart mixart_t;
+typedef struct snd_mixart_mgr mixart_mgr_t;
+
+typedef struct snd_mixart_stream mixart_stream_t;
+typedef struct snd_mixart_pipe mixart_pipe_t;
+
+typedef struct mixart_bufferinfo mixart_bufferinfo_t;
+typedef struct mixart_flowinfo mixart_flowinfo_t;
+typedef struct mixart_uid mixart_uid_t;
+
+struct mixart_uid
+{
+	u32 object_id;
+	u32 desc;
+};
+
+struct mem_area {
+	unsigned long phys;
+	unsigned long virt;
+	struct resource *res;
+};
+
+
+typedef struct mixart_route mixart_route_t;
+struct mixart_route {
+	unsigned char connected;
+	unsigned char phase_inv;
+	int volume;
+};
+
+
+/* firmware status codes  */
+#define MIXART_MOTHERBOARD_XLX_INDEX  0
+#define MIXART_MOTHERBOARD_ELF_INDEX  1
+#define MIXART_AESEBUBOARD_XLX_INDEX  2
+#define MIXART_HARDW_FILES_MAX_INDEX  3  /* xilinx, elf, AESEBU xilinx */
+
+#define MIXART_MAX_CARDS	4
+#define MSG_FIFO_SIZE           16
+
+#define MIXART_MAX_PHYS_CONNECTORS  (MIXART_MAX_CARDS * 2 * 2) /* 4 * stereo * (analog+digital) */
+
+struct snd_mixart_mgr {
+	unsigned int num_cards;
+	mixart_t *chip[MIXART_MAX_CARDS];
+
+	struct pci_dev *pci;
+
+	int irq;
+
+	/* memory-maps */
+	struct mem_area mem[2];
+
+	/* share the name */
+	char shortname[32];         /* short name of this soundcard */
+	char longname[80];          /* name of this soundcard */
+
+	/* message tasklet */
+	struct tasklet_struct msg_taskq;
+
+	/* one and only blocking message or notification may be pending  */
+	u32 pending_event;
+	wait_queue_head_t msg_sleep;
+
+	/* messages stored for tasklet */
+	u32 msg_fifo[MSG_FIFO_SIZE];
+	int msg_fifo_readptr;
+	int msg_fifo_writeptr;
+	atomic_t msg_processed;       /* number of messages to be processed in takslet */
+
+	spinlock_t lock;              /* interrupt spinlock */
+	spinlock_t msg_lock;          /* mailbox spinlock */
+	struct semaphore msg_mutex;   /* mutex for blocking_requests */
+
+	struct semaphore setup_mutex; /* mutex used in hw_params, open and close */
+
+	/* hardware interface */
+	snd_hwdep_t *hwdep;
+	unsigned int board_type;      /* read from embedded once elf file is loaded, 250 = miXart8, 251 = with AES, 252 = with Cobranet */
+
+	struct snd_dma_device dma_dev;
+	struct snd_dma_buffer flowinfo;
+	struct snd_dma_buffer bufferinfo;
+
+	mixart_uid_t         uid_console_manager;
+	int sample_rate;
+	int ref_count_rate;
+
+	struct semaphore mixer_mutex; /* mutex for mixer */
+
+};
+
+
+#define MIXART_STREAM_STATUS_FREE	0
+#define MIXART_STREAM_STATUS_OPEN	1
+#define MIXART_STREAM_STATUS_RUNNING	2
+#define MIXART_STREAM_STATUS_DRAINING	3
+#define MIXART_STREAM_STATUS_PAUSE	4
+
+#define MIXART_PLAYBACK_STREAMS		4
+#define MIXART_CAPTURE_STREAMS		1
+
+#define MIXART_PCM_ANALOG		0
+#define MIXART_PCM_DIGITAL		1
+#define MIXART_PCM_TOTAL		2
+
+#define MIXART_MAX_STREAM_PER_CARD  (MIXART_PCM_TOTAL * (MIXART_PLAYBACK_STREAMS + MIXART_CAPTURE_STREAMS) )
+
+
+#define MIXART_NOTIFY_CARD_MASK		0xF000
+#define MIXART_NOTIFY_CARD_OFFSET	12
+#define MIXART_NOTIFY_PCM_MASK		0x0F00
+#define MIXART_NOTIFY_PCM_OFFSET	8
+#define MIXART_NOTIFY_CAPT_MASK		0x0080
+#define MIXART_NOTIFY_SUBS_MASK		0x007F
+
+
+struct snd_mixart_stream {
+	snd_pcm_substream_t *substream;
+	mixart_pipe_t *pipe;
+	int pcm_number;
+
+	int status;      /* nothing, running, draining */
+
+	u64  abs_period_elapsed;  /* last absolute stream position where period_elapsed was called (multiple of runtime->period_size) */
+	u32  buf_periods;         /* periods counter in the buffer (< runtime->periods) */
+	u32  buf_period_frag;     /* defines with buf_period_pos the exact position in the buffer (< runtime->period_size) */
+
+	int channels;
+};
+
+
+enum mixart_pipe_status {
+	PIPE_UNDEFINED,
+	PIPE_STOPPED,
+	PIPE_RUNNING,
+	PIPE_CLOCK_SET
+};
+
+struct snd_mixart_pipe {
+	mixart_uid_t group_uid;			/* id of the pipe, as returned by embedded */
+	int          stream_count;
+	mixart_uid_t uid_left_connector;	/* UID's for the audio connectors */
+	mixart_uid_t uid_right_connector;
+	enum mixart_pipe_status status;
+	int references;             /* number of subs openned */
+	int monitoring;             /* pipe used for monitoring issue */
+};
+
+
+struct snd_mixart {
+	snd_card_t *card;
+	mixart_mgr_t *mgr;
+	int chip_idx;               /* zero based */
+	snd_hwdep_t *hwdep;	    /* DSP loader, only for the first card */
+
+	snd_pcm_t *pcm;             /* PCM analog i/o */
+	snd_pcm_t *pcm_dig;         /* PCM digital i/o */
+
+	/* allocate stereo pipe for instance */
+	mixart_pipe_t pipe_in_ana;
+	mixart_pipe_t pipe_out_ana;
+
+	/* if AES/EBU daughter board is available, additional pipes possible on pcm_dig */
+	mixart_pipe_t pipe_in_dig;
+	mixart_pipe_t pipe_out_dig;
+
+	mixart_stream_t playback_stream[MIXART_PCM_TOTAL][MIXART_PLAYBACK_STREAMS]; /* 0 = pcm, 1 = pcm_dig */
+	mixart_stream_t capture_stream[MIXART_PCM_TOTAL];                           /* 0 = pcm, 1 = pcm_dig */
+
+	/* UID's for the physical io's */
+	mixart_uid_t uid_out_analog_physio;
+	mixart_uid_t uid_in_analog_physio;
+
+	int analog_playback_active[2];		/* Mixer : Master Playback active (!mute) */
+	int analog_playback_volume[2];		/* Mixer : Master Playback Volume */
+	int analog_capture_volume[2];		/* Mixer : Master Capture Volume */
+	int digital_playback_active[2*MIXART_PLAYBACK_STREAMS][2];	/* Mixer : Digital Playback Active [(analog+AES output)*streams][stereo]*/
+	int digital_playback_volume[2*MIXART_PLAYBACK_STREAMS][2];	/* Mixer : Digital Playback Volume [(analog+AES output)*streams][stereo]*/
+	int digital_capture_volume[2][2];	/* Mixer : Digital Capture Volume [analog+AES output][stereo] */
+	int monitoring_active[2];		/* Mixer : Monitoring Active */
+	int monitoring_volume[2];		/* Mixer : Monitoring Volume */
+};
+
+struct mixart_bufferinfo
+{
+	u32 buffer_address;
+	u32 reserved[5];
+	u32 available_length;
+	u32 buffer_id;
+};
+
+struct mixart_flowinfo
+{
+	u32 bufferinfo_array_phy_address;
+	u32 reserved[11];
+	u32 bufferinfo_count;
+	u32 capture;
+};
+
+/* exported */
+int snd_mixart_create_pcm(mixart_t* chip);
+mixart_pipe_t* snd_mixart_add_ref_pipe( mixart_t *chip, int pcm_number, int capture, int monitoring);
+int snd_mixart_kill_ref_pipe( mixart_mgr_t *mgr, mixart_pipe_t *pipe, int monitoring);
+
+#endif /* __SOUND_MIXART_H */
--- diff/sound/pci/mixart/mixart_core.c	1970-01-01 01:00:00.000000000 +0100
+++ source/sound/pci/mixart/mixart_core.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,585 @@
+/*
+ * Driver for Digigram miXart soundcards
+ *
+ * low level interface with interrupt handling and mail box implementation
+ *
+ * Copyright (c) 2003 by Digigram <alsa@digigram.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <sound/driver.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <sound/core.h>
+#include "mixart.h"
+#include "mixart_hwdep.h"
+#include "mixart_core.h"
+
+
+#define MSG_TIMEOUT_JIFFIES         (400 * HZ) / 1000 /* 400 ms */
+
+#define MSG_DESCRIPTOR_SIZE         0x24
+#define MSG_HEADER_SIZE             (MSG_DESCRIPTOR_SIZE + 4)
+
+#define MSG_DEFAULT_SIZE            512
+
+#define MSG_TYPE_MASK               0x00000003    /* mask for following types */
+#define MSG_TYPE_NOTIFY             0             /* embedded -> driver (only notification, do not get_msg() !) */
+#define MSG_TYPE_COMMAND            1             /* driver <-> embedded (a command has no answer) */
+#define MSG_TYPE_REQUEST            2             /* driver -> embedded (request will get an answer back) */
+#define MSG_TYPE_ANSWER             3             /* embedded -> driver */
+#define MSG_CANCEL_NOTIFY_MASK      0x80000000    /* this bit is set for a notification that has been canceled */
+
+
+static int retrieve_msg_frame(mixart_mgr_t *mgr, u32 *msg_frame)
+{
+	/* read the message frame fifo */
+	u32 headptr, tailptr;
+
+	tailptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_POST_TAIL));
+	headptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_POST_HEAD));
+
+	if (tailptr == headptr)
+		return 0; /* no message posted */
+
+	snd_assert( tailptr >= MSG_OUTBOUND_POST_STACK, return 0); /* error */
+	snd_assert( tailptr < (MSG_OUTBOUND_POST_STACK+MSG_BOUND_STACK_SIZE), return 0); /* error */
+
+	*msg_frame = readl_be(MIXART_MEM(mgr, tailptr));
+
+	/* increment the tail index */
+	tailptr += 4;
+	if( tailptr >= (MSG_OUTBOUND_POST_STACK+MSG_BOUND_STACK_SIZE) )
+		tailptr = MSG_OUTBOUND_POST_STACK;
+	writel_be(tailptr, MIXART_MEM(mgr, MSG_OUTBOUND_POST_TAIL));
+
+	return 1;
+}
+
+static int get_msg(mixart_mgr_t *mgr, mixart_msg_t *resp, u32 msg_frame_address )
+{
+	unsigned long flags;
+	u32  headptr, i;
+	u32  size;
+	int  err;
+
+	spin_lock_irqsave(&mgr->msg_lock, flags);
+	err = 0;
+
+	/* copy message descriptor from miXart to driver */
+	size                =  readl_be(MIXART_MEM(mgr, msg_frame_address));       /* size of descriptor + response */
+	resp->message_id    =  readl_be(MIXART_MEM(mgr, msg_frame_address + 4));   /* dwMessageID */
+	resp->uid.object_id =  readl_be(MIXART_MEM(mgr, msg_frame_address + 8));   /* uidDest */
+	resp->uid.desc      =  readl_be(MIXART_MEM(mgr, msg_frame_address + 12));  /* */
+
+	if( (size < MSG_DESCRIPTOR_SIZE) || (resp->size < (size - MSG_DESCRIPTOR_SIZE))) {
+		err = -EINVAL;
+		snd_printk(KERN_ERR "problem with response size = %d\n", size);
+		goto _clean_exit;
+	}
+	size -= MSG_DESCRIPTOR_SIZE;
+
+	memcpy_fromio(resp->data, MIXART_MEM(mgr, msg_frame_address + MSG_HEADER_SIZE ), size);
+	resp->size = size;
+
+	/* swap if necessary */
+#ifndef __BIG_ENDIAN
+	size /= 4; /* u32 size */
+	for(i=0; i < size; i++) {
+		((u32*)resp->data)[i] = be32_to_cpu(((u32*)resp->data)[i]);
+	}
+#endif
+
+	/*
+	 * free message frame address
+	 */
+	headptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD));
+
+	if( (headptr < MSG_OUTBOUND_FREE_STACK) || ( headptr >= (MSG_OUTBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE))) {
+		err = -EINVAL;
+		goto _clean_exit;
+	}
+
+	/* give address back to outbound fifo */
+	writel_be(msg_frame_address, MIXART_MEM(mgr, headptr));
+
+	/* increment the outbound free head */
+	headptr += 4;
+	if( headptr >= (MSG_OUTBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE) )
+		headptr = MSG_OUTBOUND_FREE_STACK;
+
+	writel_be(headptr, MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD));
+
+ _clean_exit:
+	spin_unlock_irqrestore(&mgr->msg_lock, flags);
+
+	return err;
+}
+
+
+/*
+ * send a message to miXart. return: the msg_frame used for this message
+ */
+/* call with mgr->msg_lock held! */
+static int send_msg( mixart_mgr_t *mgr,
+		     mixart_msg_t *msg,
+		     int max_answersize,
+		     int mark_pending,
+		     u32 *msg_event)
+{
+	u32 headptr, tailptr;
+	u32 msg_frame_address;
+	int err, i;
+
+	snd_assert(msg->size % 4 == 0, return -EINVAL);
+
+	err = 0;
+
+	/* get message frame address */
+	tailptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_TAIL));
+	headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_HEAD));
+
+	if (tailptr == headptr) {
+		snd_printk(KERN_ERR "error: no message frame available\n");
+		return -EBUSY;
+	}
+
+	if( (tailptr < MSG_INBOUND_FREE_STACK) || (tailptr >= (MSG_INBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE))) {
+		return -EINVAL;
+	}
+
+	msg_frame_address = readl_be(MIXART_MEM(mgr, tailptr));
+	writel(0, MIXART_MEM(mgr, tailptr)); /* set address to zero on this fifo position */
+
+	/* increment the inbound free tail */
+	tailptr += 4;
+	if( tailptr >= (MSG_INBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE) )
+		tailptr = MSG_INBOUND_FREE_STACK;
+
+	writel_be(tailptr, MIXART_MEM(mgr, MSG_INBOUND_FREE_TAIL));
+
+	/* TODO : use memcpy_toio() with intermediate buffer to copy the message */
+
+	/* copy message descriptor to card memory */
+	writel_be( msg->size + MSG_DESCRIPTOR_SIZE,      MIXART_MEM(mgr, msg_frame_address) );      /* size of descriptor + request */
+	writel_be( msg->message_id ,                     MIXART_MEM(mgr, msg_frame_address + 4) );  /* dwMessageID */
+	writel_be( msg->uid.object_id,                   MIXART_MEM(mgr, msg_frame_address + 8) );  /* uidDest */
+	writel_be( msg->uid.desc,                        MIXART_MEM(mgr, msg_frame_address + 12) ); /* */
+	writel_be( MSG_DESCRIPTOR_SIZE,                  MIXART_MEM(mgr, msg_frame_address + 16) ); /* SizeHeader */
+	writel_be( MSG_DESCRIPTOR_SIZE,                  MIXART_MEM(mgr, msg_frame_address + 20) ); /* OffsetDLL_T16 */
+	writel_be( msg->size,                            MIXART_MEM(mgr, msg_frame_address + 24) ); /* SizeDLL_T16 */
+	writel_be( MSG_DESCRIPTOR_SIZE,                  MIXART_MEM(mgr, msg_frame_address + 28) ); /* OffsetDLL_DRV */
+	writel_be( 0,                                    MIXART_MEM(mgr, msg_frame_address + 32) ); /* SizeDLL_DRV */
+	writel_be( MSG_DESCRIPTOR_SIZE + max_answersize, MIXART_MEM(mgr, msg_frame_address + 36) ); /* dwExpectedAnswerSize */
+
+	/* copy message data to card memory */
+	for( i=0; i < msg->size; i+=4 ) {
+		writel_be( *(u32*)(msg->data + i), MIXART_MEM(mgr, MSG_HEADER_SIZE + msg_frame_address + i)  );
+	}
+
+	if( mark_pending ) {
+		if( *msg_event ) {
+			/* the pending event is the notification we wait for ! */
+			mgr->pending_event = *msg_event;
+		}
+		else {
+			/* the pending event is the answer we wait for (same address than the request)! */
+			mgr->pending_event = msg_frame_address;
+
+			/* copy address back to caller */
+			*msg_event = msg_frame_address;
+		}
+	}
+
+	/* mark the frame as a request (will have an answer) */
+	msg_frame_address |= MSG_TYPE_REQUEST;
+
+	/* post the frame */
+	headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_POST_HEAD));
+
+	if( (headptr < MSG_INBOUND_POST_STACK) || (headptr >= (MSG_INBOUND_POST_STACK+MSG_BOUND_STACK_SIZE))) {
+		return -EINVAL;
+	}
+
+	writel_be(msg_frame_address, MIXART_MEM(mgr, headptr));
+
+	/* increment the inbound post head */
+	headptr += 4;
+	if( headptr >= (MSG_INBOUND_POST_STACK+MSG_BOUND_STACK_SIZE) )
+		headptr = MSG_INBOUND_POST_STACK;
+
+	writel_be(headptr, MIXART_MEM(mgr, MSG_INBOUND_POST_HEAD));
+
+	return 0;
+}
+
+
+int snd_mixart_send_msg(mixart_mgr_t *mgr, mixart_msg_t *request, int max_resp_size, void *resp_data)
+{
+	mixart_msg_t resp;
+	u32 msg_frame = 0; /* set to 0, so it's no notification to wait for, but the answer */
+	int err;
+	wait_queue_t wait;
+	long timeout;
+
+	down(&mgr->msg_mutex);
+
+	init_waitqueue_entry(&wait, current);
+
+	spin_lock_irq(&mgr->msg_lock);
+	/* send the message */
+	err = send_msg(mgr, request, max_resp_size, 1, &msg_frame);  /* send and mark the answer pending */
+	if (err) {
+		spin_unlock_irq(&mgr->msg_lock);
+		up(&mgr->msg_mutex);
+		return err;
+	}
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	add_wait_queue(&mgr->msg_sleep, &wait);
+	spin_unlock_irq(&mgr->msg_lock);
+	timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES);
+	remove_wait_queue(&mgr->msg_sleep, &wait);
+
+	if (! timeout) {
+		/* error - no ack */
+		up(&mgr->msg_mutex);
+		snd_printk(KERN_ERR "error: no reponse on msg %x\n", msg_frame);
+		return -EIO;
+	}
+
+	/* retrieve the answer into the same mixart_msg_t */
+	resp.message_id = 0;
+	resp.uid = (mixart_uid_t){0,0};
+	resp.data = resp_data;
+	resp.size = max_resp_size;
+
+	err = get_msg(mgr, &resp, msg_frame);
+
+	if( request->message_id != resp.message_id )
+		snd_printk(KERN_ERR "REPONSE ERROR!\n");
+
+	up(&mgr->msg_mutex);
+	return err;
+}
+
+
+int snd_mixart_send_msg_wait_notif(mixart_mgr_t *mgr, mixart_msg_t *request, u32 notif_event)
+{
+	int err;
+	wait_queue_t wait;
+	long timeout;
+
+	snd_assert(notif_event != 0, return -EINVAL);
+	snd_assert((notif_event & MSG_TYPE_MASK) == MSG_TYPE_NOTIFY, return -EINVAL);
+	snd_assert((notif_event & MSG_CANCEL_NOTIFY_MASK) == 0, return -EINVAL);
+
+	down(&mgr->msg_mutex);
+
+	init_waitqueue_entry(&wait, current);
+
+	spin_lock_irq(&mgr->msg_lock);
+	/* send the message */
+	err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, &notif_event);  /* send and mark the notification event pending */
+	if(err) {
+		spin_unlock_irq(&mgr->msg_lock);
+		up(&mgr->msg_mutex);
+		return err;
+	}
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	add_wait_queue(&mgr->msg_sleep, &wait);
+	spin_unlock_irq(&mgr->msg_lock);
+	timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES);
+	remove_wait_queue(&mgr->msg_sleep, &wait);
+
+	if (! timeout) {
+		/* error - no ack */
+		up(&mgr->msg_mutex);
+		snd_printk(KERN_ERR "error: notification %x not received\n", notif_event);
+		return -EIO;
+	}
+
+	up(&mgr->msg_mutex);
+	return 0;
+}
+
+
+int snd_mixart_send_msg_nonblock(mixart_mgr_t *mgr, mixart_msg_t *request)
+{
+	u32 message_frame;
+	unsigned long flags;
+	int err;
+
+	/* just send the message (do not mark it as a pending one) */
+	spin_lock_irqsave(&mgr->msg_lock, flags);
+	err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 0, &message_frame);
+	spin_unlock_irqrestore(&mgr->msg_lock, flags);
+
+	/* the answer will be handled by snd_mixart_msg_tasklet()  */
+	atomic_inc(&mgr->msg_processed);
+
+	return err;
+}
+
+
+/* common buffer of tasklet and interrupt to send/receive messages */
+static u32 mixart_msg_data[MSG_DEFAULT_SIZE / 4];
+
+
+void snd_mixart_msg_tasklet( unsigned long arg)
+{
+	mixart_mgr_t *mgr = ( mixart_mgr_t*)(arg);
+	mixart_msg_t resp;
+	u32 msg, addr, type;
+	int err;
+
+	spin_lock(&mgr->lock);
+
+	while (mgr->msg_fifo_readptr != mgr->msg_fifo_writeptr) {
+		msg = mgr->msg_fifo[mgr->msg_fifo_readptr];
+		mgr->msg_fifo_readptr++;
+		mgr->msg_fifo_readptr %= MSG_FIFO_SIZE;
+
+		/* process the message ... */
+		addr = msg & ~MSG_TYPE_MASK;
+		type = msg & MSG_TYPE_MASK;
+
+		switch (type) {
+		case MSG_TYPE_ANSWER:
+			/* answer to a message on that we did not wait for (send_msg_nonblock) */
+			resp.message_id = 0;
+			resp.data = mixart_msg_data;
+			resp.size = sizeof(mixart_msg_data);
+			err = get_msg(mgr, &resp, addr);
+			if( err < 0 ) {
+				snd_printk(KERN_ERR "tasklet: error(%d) reading mf %x\n", err, msg);
+				break;
+			}
+
+			switch(resp.message_id) {
+			case MSG_STREAM_START_INPUT_STAGE_PACKET:
+			case MSG_STREAM_START_OUTPUT_STAGE_PACKET:
+			case MSG_STREAM_STOP_INPUT_STAGE_PACKET:
+			case MSG_STREAM_STOP_OUTPUT_STAGE_PACKET:
+				if(mixart_msg_data[0])
+					snd_printk(KERN_ERR "tasklet : error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n", mixart_msg_data[0]);
+				break;
+			default:
+				snd_printdd("tasklet received mf(%x) : msg_id(%x) uid(%x, %x) size(%d)\n",
+					   msg, resp.message_id, resp.uid.object_id, resp.uid.desc, resp.size);
+				break;
+			}
+			break;
+ 		case MSG_TYPE_NOTIFY:
+			/* msg contains no address ! do not get_msg() ! */
+		case MSG_TYPE_COMMAND:
+			/* get_msg() necessary */
+		default:
+			snd_printk(KERN_ERR "tasklet doesn't know what to do with message %x\n", msg);
+		} /* switch type */
+
+		/* decrement counter */
+		atomic_dec(&mgr->msg_processed);
+
+	} /* while there is a msg in fifo */
+
+	spin_unlock(&mgr->lock);
+}
+
+
+irqreturn_t snd_mixart_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	mixart_mgr_t *mgr = snd_magic_cast(mixart_mgr_t, dev_id, return IRQ_NONE);
+	int err;
+	mixart_msg_t resp;
+
+	u32 msg;
+	u32 it_reg;
+
+	spin_lock(&mgr->lock);
+
+	it_reg = readl_le(MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET));
+	if( !(it_reg & MIXART_OIDI) ) {
+		/* this device did not cause the interrupt */
+		spin_unlock(&mgr->lock);
+		return IRQ_NONE;
+	}
+
+	/* mask all interrupts */
+	writel_le(MIXART_HOST_ALL_INTERRUPT_MASKED, MIXART_REG(mgr, MIXART_PCI_OMIMR_OFFSET));
+
+	/* outdoorbell register clear */
+	it_reg = readl(MIXART_REG(mgr, MIXART_PCI_ODBR_OFFSET));
+	writel(it_reg, MIXART_REG(mgr, MIXART_PCI_ODBR_OFFSET));
+
+	/* clear interrupt */
+	writel_le( MIXART_OIDI, MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET) );
+
+	/* process interrupt */
+	while (retrieve_msg_frame(mgr, &msg)) {
+
+		switch (msg & MSG_TYPE_MASK) {
+		case MSG_TYPE_COMMAND:
+			resp.message_id = 0;
+			resp.data = mixart_msg_data;
+			resp.size = sizeof(mixart_msg_data);
+			err = get_msg(mgr, &resp, msg & ~MSG_TYPE_MASK);
+			if( err < 0 ) {
+				snd_printk(KERN_ERR "interrupt: error(%d) reading mf %x\n", err, msg);
+				break;
+			}
+
+			if(resp.message_id == MSG_SERVICES_TIMER_NOTIFY) {
+				int i;
+				mixart_timer_notify_t *notify = (mixart_timer_notify_t*)mixart_msg_data;
+
+				for(i=0; i<notify->stream_count; i++) {
+
+					u32 buffer_id = notify->streams[i].buffer_id;
+					unsigned int chip_number =  (buffer_id & MIXART_NOTIFY_CARD_MASK) >> MIXART_NOTIFY_CARD_OFFSET; /* card0 to 3 */
+					unsigned int pcm_number  =  (buffer_id & MIXART_NOTIFY_PCM_MASK ) >> MIXART_NOTIFY_PCM_OFFSET;  /* pcm0 to 3  */
+					unsigned int sub_number  =   buffer_id & MIXART_NOTIFY_SUBS_MASK;             /* 0 to MIXART_PLAYBACK_STREAMS */
+					unsigned int is_capture  = ((buffer_id & MIXART_NOTIFY_CAPT_MASK) != 0);      /* playback == 0 / capture == 1 */
+
+					mixart_t *chip  = mgr->chip[chip_number];
+					mixart_stream_t *stream;
+
+					if ((chip_number >= mgr->num_cards) || (pcm_number >= MIXART_PCM_TOTAL) || (sub_number >= MIXART_PLAYBACK_STREAMS)) {
+						snd_printk(KERN_ERR "error MSG_SERVICES_TIMER_NOTIFY buffer_id (%x) pos(%d)\n",
+							   buffer_id, notify->streams[i].sample_pos_low_part);
+						break;
+					}
+
+					if (is_capture)
+						stream = &chip->capture_stream[pcm_number];
+					else
+						stream = &chip->playback_stream[pcm_number][sub_number];
+
+					if (stream->substream && (stream->status == MIXART_STREAM_STATUS_RUNNING)) {
+						snd_pcm_runtime_t *runtime = stream->substream->runtime;
+						int elapsed = 0;
+						u64 sample_count = ((u64)notify->streams[i].sample_pos_high_part) << 32;
+						sample_count |= notify->streams[i].sample_pos_low_part;
+
+						while (1) {
+							u64 new_elapse_pos = stream->abs_period_elapsed +  runtime->period_size;
+
+							if (new_elapse_pos > sample_count) {
+								break; /* while */
+							}
+							else {
+								elapsed = 1;
+								stream->buf_periods++;
+								if (stream->buf_periods >= runtime->periods)
+									stream->buf_periods = 0;
+
+								stream->abs_period_elapsed = new_elapse_pos;
+							}
+						}
+						stream->buf_period_frag = (u32)( sample_count - stream->abs_period_elapsed );
+
+						if(elapsed) {
+							spin_unlock(&mgr->lock);
+							snd_pcm_period_elapsed(stream->substream);
+							spin_lock(&mgr->lock);
+						}
+					}
+				}
+				break;
+			}
+			if(resp.message_id == MSG_SERVICES_REPORT_TRACES) {
+				if(resp.size > 1) {
+#ifndef __BIG_ENDIAN
+					/* Traces are text: the swapped msg_data has to be swapped back ! */
+					int i;
+					for(i=0; i<(resp.size/4); i++) {
+						(mixart_msg_data)[i] = cpu_to_be32((mixart_msg_data)[i]);
+					}
+#endif
+					((char*)mixart_msg_data)[resp.size - 1] = 0;
+					snd_printdd("MIXART TRACE : %s\n", (char*)mixart_msg_data);
+				}
+				break;
+			}
+
+			snd_printdd("command %x not handled\n", resp.message_id);
+			break;
+
+		case MSG_TYPE_NOTIFY:
+			if(msg & MSG_CANCEL_NOTIFY_MASK) {
+				msg &= ~MSG_CANCEL_NOTIFY_MASK;
+				snd_printk(KERN_ERR "canceled notification %x !\n", msg);
+			}
+			/* no break, continue ! */
+		case MSG_TYPE_ANSWER:
+			/* answer or notification to a message we are waiting for*/
+			spin_lock(&mgr->msg_lock);
+			if( (msg & ~MSG_TYPE_MASK) == mgr->pending_event ) {
+				wake_up(&mgr->msg_sleep);
+				mgr->pending_event = 0;
+			}
+			/* answer to a message we did't want to wait for */
+			else {
+				mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg;
+				mgr->msg_fifo_writeptr++;
+				mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE;
+				tasklet_hi_schedule(&mgr->msg_taskq);
+			}
+			spin_unlock(&mgr->msg_lock);
+			break;
+		case MSG_TYPE_REQUEST:
+		default:
+			snd_printdd("interrupt received request %x\n", msg);
+			/* TODO : are there things to do here ? */
+			break;
+		} /* switch on msg type */
+	} /* while there are msgs */
+
+	/* allow interrupt again */
+	writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET));
+
+	spin_unlock(&mgr->lock);
+
+	return IRQ_HANDLED;
+}
+
+
+void snd_mixart_init_mailbox(mixart_mgr_t *mgr)
+{
+	writel( 0, MIXART_MEM( mgr, MSG_HOST_RSC_PROTECTION ) );
+	writel( 0, MIXART_MEM( mgr, MSG_AGENT_RSC_PROTECTION ) );
+
+	/* allow outbound messagebox to generate interrupts */
+	if(mgr->irq >= 0) {
+		writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET));
+	}
+	return;
+}
+
+void snd_mixart_exit_mailbox(mixart_mgr_t *mgr)
+{
+	/* no more interrupts on outbound messagebox */
+	writel_le( MIXART_HOST_ALL_INTERRUPT_MASKED, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET));
+	return;
+}
+
+void snd_mixart_reset_board(mixart_mgr_t *mgr)
+{
+	/* reset miXart */
+	writel_be( 1, MIXART_REG(mgr, MIXART_BA1_BRUTAL_RESET_OFFSET) );
+	return;
+}
--- diff/sound/pci/mixart/mixart_core.h	1970-01-01 01:00:00.000000000 +0100
+++ source/sound/pci/mixart/mixart_core.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,607 @@
+/*
+ * Driver for Digigram miXart soundcards
+ *
+ * low level interface with interrupt handling and mail box implementation
+ *
+ * Copyright (c) 2003 by Digigram <alsa@digigram.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef __SOUND_MIXART_CORE_H
+#define __SOUND_MIXART_CORE_H
+
+
+enum mixart_message_id {
+	MSG_CONNECTOR_GET_AUDIO_INFO         = 0x050008,
+	MSG_CONNECTOR_GET_OUT_AUDIO_LEVEL    = 0x050009,
+	MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL    = 0x05000A,
+
+	MSG_CONSOLE_MANAGER                  = 0x070000,
+	MSG_CONSOLE_GET_CLOCK_UID            = 0x070003,
+
+	MSG_PHYSICALIO_SET_LEVEL             = 0x0F0008,
+
+	MSG_STREAM_ADD_INPUT_GROUP           = 0x130000,
+	MSG_STREAM_ADD_OUTPUT_GROUP          = 0x130001,
+	MSG_STREAM_DELETE_GROUP              = 0x130004,
+	MSG_STREAM_START_STREAM_GRP_PACKET   = 0x130006,
+	MSG_STREAM_START_INPUT_STAGE_PACKET  = 0x130007,
+	MSG_STREAM_START_OUTPUT_STAGE_PACKET = 0x130008,
+	MSG_STREAM_STOP_STREAM_GRP_PACKET    = 0x130009,
+	MSG_STREAM_STOP_INPUT_STAGE_PACKET   = 0x13000A,
+	MSG_STREAM_STOP_OUTPUT_STAGE_PACKET  = 0x13000B,
+	MSG_STREAM_SET_INPUT_STAGE_PARAM     = 0x13000F,
+	MSG_STREAM_SET_OUTPUT_STAGE_PARAM    = 0x130010,
+	MSG_STREAM_SET_IN_AUDIO_LEVEL        = 0x130015,
+	MSG_STREAM_SET_OUT_STREAM_LEVEL      = 0x130017,
+
+	MSG_SYSTEM_FIRST_ID                  = 0x160000,
+	MSG_SYSTEM_ENUM_PHYSICAL_IO          = 0x16000E,
+	MSG_SYSTEM_ENUM_PLAY_CONNECTOR       = 0x160017,
+	MSG_SYSTEM_ENUM_RECORD_CONNECTOR     = 0x160018,
+	MSG_SYSTEM_WAIT_SYNCHRO_CMD          = 0x16002C,
+	MSG_SYSTEM_SEND_SYNCHRO_CMD          = 0x16002D,
+
+	MSG_SERVICES_TIMER_NOTIFY            = 0x1D0404,
+	MSG_SERVICES_REPORT_TRACES           = 0x1D0700,
+
+	MSG_CLOCK_CHECK_PROPERTIES           = 0x200001,
+	MSG_CLOCK_SET_PROPERTIES             = 0x200002,
+};
+
+
+typedef struct mixart_msg mixart_msg_t;
+struct mixart_msg
+{
+	u32          message_id;
+	mixart_uid_t uid;
+	void*        data;
+	size_t       size;
+};
+
+/* structs used to communicate with miXart */
+
+typedef struct mixart_enum_connector_resp mixart_enum_connector_resp_t;
+struct mixart_enum_connector_resp
+{
+	u32  error_code;
+	u32  first_uid_offset;
+	u32  uid_count;
+	u32  current_uid_index;
+	mixart_uid_t uid[MIXART_MAX_PHYS_CONNECTORS];
+} __attribute__((packed));
+
+
+/* used for following struct */
+#define MIXART_FLOAT_P_22_0_TO_HEX      0x41b00000  /* 22.0f */
+#define MIXART_FLOAT_M_20_0_TO_HEX      0xc1a00000  /* -20.0f */
+#define MIXART_FLOAT____0_0_TO_HEX      0x00000000  /* 0.0f */
+
+typedef struct mixart_audio_info_req mixart_audio_info_req_t;
+struct mixart_audio_info_req
+{
+	u32 line_max_level;    /* float */
+	u32 micro_max_level;   /* float */
+	u32 cd_max_level;      /* float */
+} __attribute__((packed));
+
+typedef struct mixart_analog_hw_info mixart_analog_hw_info_t;
+struct mixart_analog_hw_info
+{
+	u32 is_present;
+	u32 hw_connection_type;
+	u32 max_level;         /* float */
+	u32 min_var_level;     /* float */
+	u32 max_var_level;     /* float */
+	u32 step_var_level;    /* float */
+	u32 fix_gain;          /* float */
+	u32 zero_var;          /* float */
+} __attribute__((packed));
+
+typedef struct mixart_digital_hw_info mixart_digital_hw_info_t;
+struct mixart_digital_hw_info
+{
+	u32   hw_connection_type;
+	u32   presence;
+	u32   clock;
+	u32   reserved;
+} __attribute__((packed));
+
+typedef struct mixart_analog_info mixart_analog_info_t;
+struct mixart_analog_info
+{
+	u32                     type_mask;
+	mixart_analog_hw_info_t micro_info;
+	mixart_analog_hw_info_t line_info;
+	mixart_analog_hw_info_t cd_info;
+	u32                     analog_level_present;
+} __attribute__((packed));
+
+typedef struct mixart_digital_info mixart_digital_info_t;
+struct mixart_digital_info
+{
+	u32 type_mask;
+	mixart_digital_hw_info_t aes_info;
+	mixart_digital_hw_info_t adat_info;
+} __attribute__((packed));
+
+typedef struct mixart_audio_info mixart_audio_info_t;
+struct mixart_audio_info
+{
+	u32                   clock_type_mask;
+	mixart_analog_info_t  analog_info;
+	mixart_digital_info_t digital_info;
+} __attribute__((packed));
+
+typedef struct mixart_audio_info_resp mixart_audio_info_resp_t;
+struct mixart_audio_info_resp
+{
+	u32                 txx_status;
+	mixart_audio_info_t info;
+} __attribute__((packed));
+
+
+/* used for nb_bytes_max_per_sample */
+#define MIXART_FLOAT_P__4_0_TO_HEX      0x40800000  /* +4.0f */
+#define MIXART_FLOAT_P__8_0_TO_HEX      0x41000000  /* +8.0f */
+
+typedef struct mixart_stream_info mixart_stream_info_t;
+struct mixart_stream_info
+{
+	u32 size_max_byte_frame;
+	u32 size_max_sample_frame;
+	u32 nb_bytes_max_per_sample;  /* float */
+} __attribute__((packed));
+
+/*  MSG_STREAM_ADD_INPUT_GROUP */
+/*  MSG_STREAM_ADD_OUTPUT_GROUP */
+
+typedef struct mixart_streaming_group_req mixart_streaming_group_req_t;
+struct mixart_streaming_group_req
+{
+	u32 stream_count;
+	u32 channel_count;
+	u32 user_grp_number;
+	u32 first_phys_audio;
+	u32 latency;
+	mixart_stream_info_t stream_info[32];
+	mixart_uid_t connector;
+	u32 flow_entry[32];
+} __attribute__((packed));
+
+typedef struct mixart_stream_desc mixart_stream_desc_t;
+struct mixart_stream_desc
+{
+	mixart_uid_t stream_uid;
+	u32          stream_desc;
+} __attribute__((packed));
+
+typedef struct mixart_streaming_group mixart_streaming_group_t;
+struct mixart_streaming_group
+{
+	u32                  status;
+	mixart_uid_t         group;
+	u32                  pipe_desc;
+	u32                  stream_count;
+	mixart_stream_desc_t stream[32];
+} __attribute__((packed));
+
+/* MSG_STREAM_DELETE_GROUP */
+
+/* request : mixart_uid_t group */
+
+typedef struct mixart_delete_group_resp mixart_delete_group_resp_t;
+struct mixart_delete_group_resp
+{
+	u32  status;
+	u32  unused[2];
+} __attribute__((packed));
+
+
+/* 	MSG_STREAM_START_INPUT_STAGE_PACKET  = 0x130000 + 7,
+	MSG_STREAM_START_OUTPUT_STAGE_PACKET = 0x130000 + 8,
+	MSG_STREAM_STOP_INPUT_STAGE_PACKET   = 0x130000 + 10,
+	MSG_STREAM_STOP_OUTPUT_STAGE_PACKET  = 0x130000 + 11,
+ */
+
+typedef struct mixart_fx_couple_uid mixart_fx_couple_uid_t;
+struct mixart_fx_couple_uid
+{
+	mixart_uid_t uid_fx_code;
+	mixart_uid_t uid_fx_data;
+} __attribute__((packed));
+
+typedef struct mixart_txx_stream_desc mixart_txx_stream_desc_t;
+struct mixart_txx_stream_desc
+{
+	mixart_uid_t            uid_pipe;
+	u32                     stream_idx;
+	u32                     fx_number;
+	mixart_fx_couple_uid_t  uid_fx[4];
+} __attribute__((packed));
+
+typedef struct mixart_flow_info mixart_flow_info_t;
+struct mixart_flow_info
+{
+	mixart_txx_stream_desc_t  stream_desc;
+	u32                       flow_entry;
+	u32                       flow_phy_addr;
+} __attribute__((packed));
+
+typedef struct mixart_stream_state_req mixart_stream_state_req_t;
+struct mixart_stream_state_req
+{
+	u32                 delayed;
+	u64                 scheduler;
+	u32                 reserved4np[3];
+	u32                 stream_count;  /* set to 1 for instance */
+	mixart_flow_info_t  stream_info;   /* could be an array[stream_count] */
+} __attribute__((packed));
+
+/* 	MSG_STREAM_START_STREAM_GRP_PACKET   = 0x130000 + 6
+	MSG_STREAM_STOP_STREAM_GRP_PACKET    = 0x130000 + 9
+ */
+
+typedef struct mixart_group_state_req mixart_group_state_req_t;
+struct mixart_group_state_req
+{
+	u32           delayed;
+	u64           scheduler;
+	u32           reserved4np[2];
+	u32           pipe_count;    /* set to 1 for instance */
+	mixart_uid_t  pipe_uid[1];   /* could be an array[pipe_count] */
+} __attribute__((packed));
+
+typedef struct mixart_group_state_resp mixart_group_state_resp_t;
+struct mixart_group_state_resp
+{
+	u32           txx_status;
+	u64           scheduler;
+} __attribute__((packed));
+
+
+
+/* Structures used by the MSG_SERVICES_TIMER_NOTIFY command */
+
+typedef struct mixart_sample_pos mixart_sample_pos_t;
+struct mixart_sample_pos
+{
+	u32   buffer_id;
+	u32   validity;
+	u32   sample_pos_high_part;
+	u32   sample_pos_low_part;
+} __attribute__((packed));
+
+typedef struct mixart_timer_notify mixart_timer_notify_t;
+struct mixart_timer_notify
+{
+	u32                  stream_count;
+	mixart_sample_pos_t  streams[MIXART_MAX_STREAM_PER_CARD * MIXART_MAX_CARDS];
+} __attribute__((packed));
+
+
+/*	MSG_CONSOLE_GET_CLOCK_UID            = 0x070003,
+ */
+
+/* request is a uid with desc = MSG_CONSOLE_MANAGER | cardindex */
+
+typedef struct mixart_return_uid mixart_return_uid_t;
+struct mixart_return_uid
+{
+	u32 error_code;
+	mixart_uid_t uid;
+} __attribute__((packed));
+
+/*	MSG_CLOCK_CHECK_PROPERTIES           = 0x200001,
+	MSG_CLOCK_SET_PROPERTIES             = 0x200002,
+*/
+
+enum mixart_clock_generic_type {
+	CGT_NO_CLOCK,
+	CGT_INTERNAL_CLOCK,
+	CGT_PROGRAMMABLE_CLOCK,
+	CGT_INTERNAL_ENSLAVED_CLOCK,
+	CGT_EXTERNAL_CLOCK,
+	CGT_CURRENT_CLOCK
+};
+
+enum mixart_clock_mode {
+	CM_UNDEFINED,
+	CM_MASTER,
+	CM_SLAVE,
+	CM_STANDALONE,
+	CM_NOT_CONCERNED
+};
+
+
+typedef struct mixart_clock_properties mixart_clock_properties_t;
+struct mixart_clock_properties
+{
+	u32 error_code;
+	u32 validation_mask;
+	u32 frequency;
+	u32 reference_frequency;
+	u32 clock_generic_type;
+	u32 clock_mode;
+	mixart_uid_t uid_clock_source;
+	mixart_uid_t uid_event_source;
+	u32 event_mode;
+	u32 synchro_signal_presence;
+	u32 format;
+	u32 board_mask;
+	u32 nb_callers; /* set to 1 (see below) */
+	mixart_uid_t uid_caller[1];
+} __attribute__((packed));
+
+typedef struct mixart_clock_properties_resp mixart_clock_properties_resp_t;
+struct mixart_clock_properties_resp
+{
+	u32 status;
+	u32 clock_mode;
+} __attribute__((packed));
+
+
+/*	MSG_STREAM_SET_INPUT_STAGE_PARAM     = 0x13000F */
+/*	MSG_STREAM_SET_OUTPUT_STAGE_PARAM    = 0x130010 */
+
+enum mixart_coding_type {
+	CT_NOT_DEFINED,
+	CT_LINEAR,
+	CT_MPEG_L1,
+	CT_MPEG_L2,
+	CT_MPEG_L3,
+	CT_MPEG_L3_LSF,
+	CT_GSM
+};
+enum mixart_sample_type {
+	ST_NOT_DEFINED,
+	ST_FLOATING_POINT_32BE,
+	ST_FLOATING_POINT_32LE,
+	ST_FLOATING_POINT_64BE,
+	ST_FLOATING_POINT_64LE,
+	ST_FIXED_POINT_8,
+	ST_FIXED_POINT_16BE,
+	ST_FIXED_POINT_16LE,
+	ST_FIXED_POINT_24BE,
+	ST_FIXED_POINT_24LE,
+	ST_FIXED_POINT_32BE,
+	ST_FIXED_POINT_32LE,
+	ST_INTEGER_8,
+	ST_INTEGER_16BE,
+	ST_INTEGER_16LE,
+	ST_INTEGER_24BE,
+	ST_INTEGER_24LE,
+	ST_INTEGER_32BE,
+	ST_INTEGER_32LE
+};
+
+typedef struct mixart_stream_param_desc mixart_stream_param_desc_t;
+struct mixart_stream_param_desc
+{
+	u32 coding_type;  /* use enum mixart_coding_type */
+	u32 sample_type;  /* use enum mixart_sample_type */
+
+	union {
+		struct {
+			u32 linear_endian_ness;
+			u32 linear_bits;
+			u32 is_signed;
+			u32 is_float;
+		} linear_format_info;
+
+		struct {
+			u32 mpeg_layer;
+			u32 mpeg_mode;
+			u32 mpeg_mode_extension;
+			u32 mpeg_pre_emphasis;
+			u32 mpeg_has_padding_bit;
+			u32 mpeg_has_crc;
+			u32 mpeg_has_extension;
+			u32 mpeg_is_original;
+			u32 mpeg_has_copyright;
+		} mpeg_format_info;
+	} format_info;
+
+	u32 delayed;
+	u64 scheduler;
+	u32 sample_size;
+	u32 has_header;
+	u32 has_suffix;
+	u32 has_bitrate;
+	u32 samples_per_frame;
+	u32 bytes_per_frame;
+	u32 bytes_per_sample;
+	u32 sampling_freq;
+	u32 number_of_channel;
+	u32 stream_number;
+	u32 buffer_size;
+	u32 differed_time;
+	u32 reserved4np[3];
+	u32 pipe_count;                           /* set to 1 (array size !) */
+	u32 stream_count;                         /* set to 1 (array size !) */
+	mixart_txx_stream_desc_t stream_desc[1];  /* only one stream per command, but this could be an array */
+
+} __attribute__((packed));
+
+
+/*	MSG_CONNECTOR_GET_OUT_AUDIO_LEVEL    = 0x050009,
+ */
+
+
+typedef struct mixart_get_out_audio_level mixart_get_out_audio_level_t;
+struct mixart_get_out_audio_level
+{
+	u32 txx_status;
+	u32 digital_level;   /* float */
+	u32 analog_level;    /* float */
+	u32 monitor_level;   /* float */
+	u32 mute;
+	u32 monitor_mute1;
+	u32 monitor_mute2;
+} __attribute__((packed));
+
+
+/*	MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL    = 0x05000A,
+ */
+
+/* used for valid_mask below */
+#define MIXART_AUDIO_LEVEL_ANALOG_MASK	0x01
+#define MIXART_AUDIO_LEVEL_DIGITAL_MASK	0x02
+#define MIXART_AUDIO_LEVEL_MONITOR_MASK	0x04
+#define MIXART_AUDIO_LEVEL_MUTE_MASK	0x08
+#define MIXART_AUDIO_LEVEL_MUTE_M1_MASK	0x10
+#define MIXART_AUDIO_LEVEL_MUTE_M2_MASK	0x20
+
+typedef struct mixart_set_out_audio_level mixart_set_out_audio_level_t;
+struct mixart_set_out_audio_level
+{
+	u32 delayed;
+	u64 scheduler;
+	u32 valid_mask1;
+	u32 valid_mask2;
+	u32 digital_level;   /* float */
+	u32 analog_level;    /* float */
+	u32 monitor_level;   /* float */
+	u32 mute;
+	u32 monitor_mute1;
+	u32 monitor_mute2;
+	u32 reserved4np;
+} __attribute__((packed));
+
+
+/*	MSG_SYSTEM_ENUM_PHYSICAL_IO          = 0x16000E,
+ */
+
+#define MIXART_MAX_PHYS_IO  (MIXART_MAX_CARDS * 2 * 2) /* 4 * (analog+digital) * (playback+capture) */
+
+typedef struct mixart_uid_enumeration mixart_uid_enumeration_t;
+struct mixart_uid_enumeration
+{
+	u32 error_code;
+	u32 first_uid_offset;
+	u32 nb_uid;
+	u32 current_uid_index;
+	mixart_uid_t uid[MIXART_MAX_PHYS_IO];
+} __attribute__((packed));
+
+
+/*	MSG_PHYSICALIO_SET_LEVEL             = 0x0F0008,
+	MSG_PHYSICALIO_GET_LEVEL             = 0x0F000C,
+*/
+
+typedef struct mixart_io_channel_level mixart_io_channel_level_t;
+struct mixart_io_channel_level
+{
+	u32 analog_level;   /* float */
+	u32 unused[2];
+} __attribute__((packed));
+
+typedef struct mixart_io_level mixart_io_level_t;
+struct mixart_io_level
+{
+	s32 channel; /* 0=left, 1=right, -1=both, -2=both same */
+	mixart_io_channel_level_t level[2];
+} __attribute__((packed));
+
+
+/*	MSG_STREAM_SET_IN_AUDIO_LEVEL        = 0x130015,
+ */
+
+typedef struct mixart_in_audio_level_info mixart_in_audio_level_info_t;
+struct mixart_in_audio_level_info
+{
+	mixart_uid_t connector;
+	u32 valid_mask1;
+	u32 valid_mask2;
+	u32 digital_level;
+	u32 analog_level;
+} __attribute__((packed));
+
+typedef struct mixart_set_in_audio_level_req mixart_set_in_audio_level_req_t;
+struct mixart_set_in_audio_level_req
+{
+	u32 delayed;
+	u64 scheduler;
+	u32 audio_count;  /* set to <= 2 */
+	u32 reserved4np;
+	mixart_in_audio_level_info_t level[2];
+} __attribute__((packed));
+
+/* response is a 32 bit status */
+
+
+/*	MSG_STREAM_SET_OUT_STREAM_LEVEL      = 0x130017,
+ */
+
+/* defines used for valid_mask1 */
+#define MIXART_OUT_STREAM_SET_LEVEL_LEFT_AUDIO1		0x01
+#define MIXART_OUT_STREAM_SET_LEVEL_LEFT_AUDIO2		0x02
+#define MIXART_OUT_STREAM_SET_LEVEL_RIGHT_AUDIO1	0x04
+#define MIXART_OUT_STREAM_SET_LEVEL_RIGHT_AUDIO2	0x08
+#define MIXART_OUT_STREAM_SET_LEVEL_STREAM_1		0x10
+#define MIXART_OUT_STREAM_SET_LEVEL_STREAM_2		0x20
+#define MIXART_OUT_STREAM_SET_LEVEL_MUTE_1		0x40
+#define MIXART_OUT_STREAM_SET_LEVEL_MUTE_2		0x80
+
+typedef struct mixart_out_stream_level_info mixart_out_stream_level_info_t;
+struct mixart_out_stream_level_info
+{
+	u32 valid_mask1;
+	u32 valid_mask2;
+	u32 left_to_out1_level;
+	u32 left_to_out2_level;
+	u32 right_to_out1_level;
+	u32 right_to_out2_level;
+	u32 digital_level1;
+	u32 digital_level2;
+	u32 mute1;
+	u32 mute2;
+} __attribute__((packed));
+
+typedef struct mixart_set_out_stream_level mixart_set_out_stream_level_t;
+struct mixart_set_out_stream_level
+{
+	mixart_txx_stream_desc_t desc;
+	mixart_out_stream_level_info_t out_level;
+} __attribute__((packed));
+
+typedef struct mixart_set_out_stream_level_req mixart_set_out_stream_level_req_t;
+struct mixart_set_out_stream_level_req
+{
+	u32 delayed;
+	u64 scheduler;
+	u32 reserved4np[2];
+	u32 nb_of_stream;  /* set to 1 */
+	mixart_set_out_stream_level_t stream_level; /* could be an array */
+} __attribute__((packed));
+
+/* response to this request is a u32 status value */
+
+
+/* exported */
+void snd_mixart_init_mailbox(mixart_mgr_t *mgr);
+void snd_mixart_exit_mailbox(mixart_mgr_t *mgr);
+
+int  snd_mixart_send_msg(mixart_mgr_t *mgr, mixart_msg_t *request, int max_resp_size, void *resp_data);
+int  snd_mixart_send_msg_wait_notif(mixart_mgr_t *mgr, mixart_msg_t *request, u32 notif_event);
+int  snd_mixart_send_msg_nonblock(mixart_mgr_t *mgr, mixart_msg_t *request);
+
+irqreturn_t snd_mixart_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+void snd_mixart_msg_tasklet( unsigned long arg);
+
+void snd_mixart_reset_board(mixart_mgr_t *mgr);
+
+#endif /* __SOUND_MIXART_CORE_H */
--- diff/sound/pci/mixart/mixart_hwdep.c	1970-01-01 01:00:00.000000000 +0100
+++ source/sound/pci/mixart/mixart_hwdep.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,572 @@
+/*
+ * Driver for Digigram miXart soundcards
+ *
+ * hwdep device manager
+ *
+ * Copyright (c) 2003 by Digigram <alsa@digigram.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <sound/driver.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <sound/core.h>
+#include "mixart.h"
+#include "mixart_mixer.h"
+#include "mixart_core.h"
+#include "mixart_hwdep.h"
+
+
+/* miXart hwdep interface id string */
+#define SND_MIXART_HWDEP_ID       "miXart Loader"
+
+static int mixart_hwdep_open(snd_hwdep_t *hw, struct file *file)
+{
+	return 0;
+}
+
+static int mixart_hwdep_release(snd_hwdep_t *hw, struct file *file)
+{
+	return 0;
+}
+
+/**
+ * wait for a value on a peudo register, exit with a timeout
+ *
+ * @param mgr pointer to miXart manager structure
+ * @param offset unsigned pseudo_register base + offset of value
+ * @param value value
+ * @param timeout timeout in centisenconds
+ */
+static int mixart_wait_nice_for_register_value(mixart_mgr_t *mgr, u32 offset, int is_egal, u32 value, unsigned long timeout)
+{
+	unsigned long end_time = jiffies + (timeout * HZ / 100);
+	u32 read;
+
+	do {	/* we may take too long time in this loop.
+		 * so give controls back to kernel if needed.
+		 */
+		cond_resched();
+
+		read = readl_be( MIXART_MEM( mgr, offset ));
+		if(is_egal) {
+			if(read == value) return 0;
+		}
+		else { /* wait for different value */
+			if(read != value) return 0;
+		}
+	} while ( time_after_eq(end_time, jiffies) );
+
+	return -EBUSY;
+}
+
+
+/*
+  structures needed to upload elf code packets 
+ */
+typedef struct snd_mixart_elf32_ehdr snd_mixart_elf32_ehdr_t;
+
+struct snd_mixart_elf32_ehdr {
+	u8      e_ident[16];
+	u16     e_type;
+	u16     e_machine;
+	u32     e_version;
+	u32     e_entry;
+	u32     e_phoff;
+	u32     e_shoff;
+	u32     e_flags;
+	u16     e_ehsize;
+	u16     e_phentsize;
+	u16     e_phnum;
+	u16     e_shentsize;
+	u16     e_shnum;
+	u16     e_shstrndx;
+};
+
+typedef struct snd_mixart_elf32_phdr snd_mixart_elf32_phdr_t;
+
+struct snd_mixart_elf32_phdr {
+	u32     p_type;
+	u32     p_offset;
+	u32     p_vaddr;
+	u32     p_paddr;
+	u32     p_filesz;
+	u32     p_memsz;
+	u32     p_flags;
+	u32     p_align;
+};
+
+static int mixart_load_elf(mixart_mgr_t *mgr, snd_hwdep_dsp_image_t *dsp )
+{
+	char                    elf32_magic_number[4] = {0x7f,'E','L','F'};
+	snd_mixart_elf32_ehdr_t elf_header;
+	int                     i;
+
+	if ( copy_from_user(&elf_header, dsp->image , sizeof(snd_mixart_elf32_ehdr_t)) )
+		return -EFAULT;
+
+	for( i=0; i<4; i++ )
+		if ( elf32_magic_number[i] != elf_header.e_ident[i] )
+			return -EINVAL;
+
+	if( elf_header.e_phoff != 0 ) {
+		snd_mixart_elf32_phdr_t     elf_programheader;
+
+		for( i=0; i < be16_to_cpu(elf_header.e_phnum); i++ ) {
+			u32 pos = be32_to_cpu(elf_header.e_phoff) + (u32)(i * be16_to_cpu(elf_header.e_phentsize));
+
+			if( copy_from_user( &elf_programheader, dsp->image + pos, sizeof(elf_programheader) ) )
+				return -EFAULT;
+
+			if(elf_programheader.p_type != 0) {
+				if( elf_programheader.p_filesz != 0 ) {
+					if(copy_from_user_toio( MIXART_MEM( mgr, be32_to_cpu(elf_programheader.p_vaddr)),
+								dsp->image + be32_to_cpu( elf_programheader.p_offset ),
+								be32_to_cpu( elf_programheader.p_filesz )))
+						return -EFAULT;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+static int mixart_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t *info)
+{
+	mixart_mgr_t *mgr = snd_magic_cast(mixart_mgr_t, hw->private_data, return -ENXIO);
+
+	strcpy(info->id, "miXart");
+        info->num_dsps = MIXART_HARDW_FILES_MAX_INDEX;
+
+	if (mgr->hwdep->dsp_loaded & (1 <<  MIXART_MOTHERBOARD_ELF_INDEX))
+		info->chip_ready = 1;
+
+	info->version = MIXART_DRIVER_VERSION;
+	return 0;
+}
+
+/*
+ * get basic information and init miXart
+ */
+
+/* audio IDs for request to the board */
+#define MIXART_FIRST_ANA_AUDIO_ID       0
+#define MIXART_FIRST_DIG_AUDIO_ID       8
+
+static int mixart_enum_connectors(mixart_mgr_t *mgr)
+{
+	u32 k;
+	int err;
+	mixart_msg_t request;
+	mixart_enum_connector_resp_t connector;
+	mixart_audio_info_req_t  audio_info_req;
+	mixart_audio_info_resp_t audio_info;
+
+	audio_info_req.line_max_level = MIXART_FLOAT_P_22_0_TO_HEX;
+	audio_info_req.micro_max_level = MIXART_FLOAT_M_20_0_TO_HEX;
+	audio_info_req.cd_max_level = MIXART_FLOAT____0_0_TO_HEX;
+
+	request.message_id = MSG_SYSTEM_ENUM_PLAY_CONNECTOR;
+	request.uid = (mixart_uid_t){0,0};  /* board num = 0 */
+	request.data = NULL;
+	request.size = 0;
+
+	err = snd_mixart_send_msg(mgr, &request, sizeof(connector), &connector);
+	if((err < 0) || (connector.error_code) || (connector.uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
+		snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PLAY_CONNECTOR\n");
+		return -EINVAL;
+	}
+
+	for(k=0; k < connector.uid_count; k++) {
+		mixart_pipe_t* pipe;
+
+		if(k < MIXART_FIRST_DIG_AUDIO_ID) {
+			pipe = &mgr->chip[k/2]->pipe_out_ana;
+		} else {
+			pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_out_dig;
+		}
+		if(k & 1) {
+			pipe->uid_right_connector = connector.uid[k];   /* odd */
+		} else {
+			pipe->uid_left_connector = connector.uid[k];    /* even */
+		}
+
+		/* snd_printk(KERN_DEBUG "playback connector[%d].object_id = %x\n", k, connector.uid[k].object_id); */
+
+		/* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
+		request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
+		request.uid = connector.uid[k];
+		request.data = &audio_info_req;
+		request.size = sizeof(audio_info_req);
+
+		err = snd_mixart_send_msg(mgr, &request, sizeof(audio_info), &audio_info);
+		if( err < 0 ) {
+			snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
+			return err;
+		}
+		/*snd_printk(KERN_DEBUG "play  analog_info.analog_level_present = %x\n", audio_info.info.analog_info.analog_level_present);*/
+	}
+
+	request.message_id = MSG_SYSTEM_ENUM_RECORD_CONNECTOR;
+	request.uid = (mixart_uid_t){0,0};  /* board num = 0 */
+	request.data = NULL;
+	request.size = 0;
+
+	err = snd_mixart_send_msg(mgr, &request, sizeof(connector), &connector);
+	if((err < 0) || (connector.error_code) || (connector.uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
+		snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_RECORD_CONNECTOR\n");
+		return -EINVAL;
+	}
+
+	for(k=0; k < connector.uid_count; k++) {
+		mixart_pipe_t* pipe;
+
+		if(k < MIXART_FIRST_DIG_AUDIO_ID) {
+			pipe = &mgr->chip[k/2]->pipe_in_ana;
+		} else {
+			pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_in_dig;
+		}
+		if(k & 1) {
+			pipe->uid_right_connector = connector.uid[k];   /* odd */
+		} else {
+			pipe->uid_left_connector = connector.uid[k];    /* even */
+		}
+
+		/* snd_printk(KERN_DEBUG "capture connector[%d].object_id = %x\n", k, connector.uid[k].object_id); */
+
+		/* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
+		request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
+		request.uid = connector.uid[k];
+		request.data = &audio_info_req;
+		request.size = sizeof(audio_info_req);
+
+		err = snd_mixart_send_msg(mgr, &request, sizeof(audio_info), &audio_info);
+		if( err < 0 ) {
+			snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
+			return err;
+		}
+		/*snd_printk(KERN_DEBUG "rec  analog_info.analog_level_present = %x\n", audio_info.info.analog_info.analog_level_present);*/
+	}
+
+	return 0;
+}
+
+static int mixart_enum_physio(mixart_mgr_t *mgr)
+{
+	u32 k;
+	int err;
+	mixart_msg_t request;
+	mixart_uid_t get_console_mgr;
+	mixart_return_uid_t console_mgr;
+	mixart_uid_enumeration_t phys_io;
+
+	/* get the uid for the console manager */
+	get_console_mgr.object_id = 0;
+	get_console_mgr.desc = MSG_CONSOLE_MANAGER | 0; /* cardindex = 0 */
+
+	request.message_id = MSG_CONSOLE_GET_CLOCK_UID;
+	request.uid = get_console_mgr;
+	request.data = &get_console_mgr;
+	request.size = sizeof(get_console_mgr);
+
+	err = snd_mixart_send_msg(mgr, &request, sizeof(console_mgr), &console_mgr);
+
+	if( (err < 0) || (console_mgr.error_code != 0) ) {
+		snd_printk(KERN_DEBUG "error MSG_CONSOLE_GET_CLOCK_UID : err=%x\n", console_mgr.error_code);
+		return -EINVAL;
+	}
+
+	/* used later for clock issues ! */
+	mgr->uid_console_manager = console_mgr.uid;
+
+	request.message_id = MSG_SYSTEM_ENUM_PHYSICAL_IO;
+	request.uid = (mixart_uid_t){0,0};
+	request.data = &console_mgr.uid;
+	request.size = sizeof(console_mgr.uid);
+
+	err = snd_mixart_send_msg(mgr, &request, sizeof(phys_io), &phys_io);
+	if( (err < 0) || ( phys_io.error_code != 0 ) ) {
+		snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PHYSICAL_IO err(%x) error_code(%x)\n", err, phys_io.error_code );
+		return -EINVAL;
+	}
+
+	snd_assert(phys_io.nb_uid >= (MIXART_MAX_CARDS * 2),  return -EINVAL); /* min 2 phys io per card (analog in + analog out) */
+
+	for(k=0; k<mgr->num_cards; k++) {
+		mgr->chip[k]->uid_in_analog_physio = phys_io.uid[k];
+		mgr->chip[k]->uid_out_analog_physio = phys_io.uid[phys_io.nb_uid/2 + k]; 
+	}
+
+	return 0;
+}
+
+
+static int mixart_first_init(mixart_mgr_t *mgr)
+{
+	u32 k;
+	int err;
+	mixart_msg_t request;
+
+	if((err = mixart_enum_connectors(mgr)) < 0) return err;
+
+	if((err = mixart_enum_physio(mgr)) < 0) return err;
+
+	/* send a synchro command to card (necessary to do this before first MSG_STREAM_START_STREAM_GRP_PACKET) */
+	/* though why not here */
+	request.message_id = MSG_SYSTEM_SEND_SYNCHRO_CMD;
+	request.uid = (mixart_uid_t){0,0};
+	request.data = NULL;
+	request.size = 0;
+	/* this command has no data. response is a 32 bit status */
+	err = snd_mixart_send_msg(mgr, &request, sizeof(k), &k);
+	if( (err < 0) || (k != 0) ) {
+		snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD\n");
+		return err == 0 ? -EINVAL : err;
+	}
+
+	return 0;
+}
+
+
+/* firmware base addresses (when hard coded) */
+#define MIXART_MOTHERBOARD_XLX_BASE_ADDRESS   0x00600000
+
+static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp)
+{
+	mixart_mgr_t* mgr = snd_magic_cast(mixart_mgr_t, hw->private_data, return -ENXIO);
+	int           err, card_index;
+	u32           status_xilinx, status_elf, status_daught;
+	u32           val;
+
+	/* read motherboard xilinx status */
+	status_xilinx = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
+	/* read elf status */
+	status_elf = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
+	/* read daughterboard xilinx status */
+	status_daught = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
+
+	/* motherboard xilinx status 5 will say that the board is performing a reset */
+	if( status_xilinx == 5 ) {
+		snd_printk( KERN_ERR "miXart is resetting !\n");
+		return -EAGAIN; /* try again later */
+	}
+
+	switch (dsp->index)   {
+	case MIXART_MOTHERBOARD_XLX_INDEX:
+
+		/* xilinx already loaded ? */ 
+		if( status_xilinx == 4 ) {
+			snd_printk( KERN_DEBUG "xilinx is already loaded !\n");
+			return 0;
+		}
+		/* the status should be 0 == "idle" */
+		if( status_xilinx != 0 ) {
+			snd_printk( KERN_ERR "xilinx load error ! status = %d\n", status_xilinx);
+			return -EIO; /* modprob -r may help ? */
+		}
+
+		/* check xilinx validity */
+		snd_assert(((u32*)(dsp->image))[0]==0xFFFFFFFF, return -EINVAL);
+		snd_assert(dsp->length % 4 == 0, return -EINVAL);
+
+		/* set xilinx status to copying */
+		writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
+
+		/* setup xilinx base address */
+		writel_be( MIXART_MOTHERBOARD_XLX_BASE_ADDRESS, MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_BASE_ADDR_OFFSET ));
+		/* setup code size for xilinx file */
+		writel_be( dsp->length, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_SIZE_OFFSET ));
+
+		/* copy xilinx code */
+		if (copy_from_user_toio(  MIXART_MEM( mgr, MIXART_MOTHERBOARD_XLX_BASE_ADDRESS),  dsp->image,  dsp->length))
+			return -EFAULT;
+    
+		/* set xilinx status to copy finished */
+		writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
+
+		/* return, because no further processing needed */
+		return 0;
+
+	case MIXART_MOTHERBOARD_ELF_INDEX:
+
+		if( status_elf == 4 ) {
+			snd_printk( KERN_DEBUG "elf file already loaded !\n");
+			return 0;
+		}
+
+		/* the status should be 0 == "idle" */
+		if( status_elf != 0 ) {
+			snd_printk( KERN_ERR "elf load error ! status = %d\n", status_elf);
+			return -EIO; /* modprob -r may help ? */
+		}
+
+		/* wait for xilinx status == 4 */
+		err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET, 1, 4, 500); /* 5sec */
+		if (err < 0) {
+			snd_printk( KERN_ERR "xilinx was not loaded or could not be started\n");
+			return err;
+		}
+
+		/* init some data on the card */
+		writel_be( 0, MIXART_MEM( mgr, MIXART_PSEUDOREG_BOARDNUMBER ) ); /* set miXart boardnumber to 0 */
+		writel_be( 0, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) );         /* reset pointer to flow table on miXart */
+
+		/* set elf status to copying */
+		writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
+
+		/* process the copying of the elf packets */
+		err = mixart_load_elf( mgr, dsp);
+		if (err < 0) return err;
+
+		/* set elf status to copy finished */
+		writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
+
+		/* wait for elf status == 4 */
+		err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET, 1, 4, 300); /* 3sec */
+		if (err < 0) {
+			snd_printk( KERN_ERR "elf could not be started\n");
+			return err;
+		}
+
+		/* miXart waits at this point on the pointer to the flow table */
+		writel_be( (u32)mgr->flowinfo.addr, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) ); /* give pointer of flow table to miXart */
+
+		return 0;  /* return, another xilinx file has to be loaded before */
+
+	case MIXART_AESEBUBOARD_XLX_INDEX:
+	default:
+
+		/* elf and xilinx should be loaded */
+		if( (status_elf != 4) || (status_xilinx != 4) ) {
+			printk( KERN_ERR "xilinx or elf not successfully loaded\n");
+			return -EIO; /* modprob -r may help ? */
+		}
+
+		/* wait for daughter detection != 0 */
+		err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET, 0, 0, 30); /* 300msec */
+		if (err < 0) {
+			snd_printk( KERN_ERR "error starting elf file\n");
+			return err;
+		}
+
+		/* the board type can now be retrieved */
+		mgr->board_type = (DAUGHTER_TYPE_MASK & readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DBRD_TYPE_OFFSET)));
+
+		if (mgr->board_type == MIXART_DAUGHTER_TYPE_NONE)
+			break;  /* no daughter board; the file does not have to be loaded, continue after the switch */
+
+		/* only if aesebu daughter board presence (elf code must run)  */ 
+		if (mgr->board_type != MIXART_DAUGHTER_TYPE_AES )
+			return -EINVAL;
+
+		/* daughter should be idle */
+		if( status_daught != 0 ) {
+			printk( KERN_ERR "daughter load error ! status = %d\n", status_daught);
+			return -EIO; /* modprob -r may help ? */
+		}
+ 
+		/* check daughterboard xilinx validity */
+		snd_assert(((u32*)(dsp->image))[0]==0xFFFFFFFF, return -EINVAL);
+		snd_assert(dsp->length % 4 == 0, return -EINVAL);
+
+		/* inform mixart about the size of the file */
+		writel_be( dsp->length, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_SIZE_OFFSET ));
+
+		/* set daughterboard status to 1 */
+		writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
+
+		/* wait for status == 2 */
+		err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 2, 30); /* 300msec */
+		if (err < 0) {
+			snd_printk( KERN_ERR "daughter board load error\n");
+			return err;
+		}
+
+		/* get the address where to write the file */
+		val = readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_BASE_ADDR_OFFSET ));
+		snd_assert(val != 0, return -EINVAL);
+
+		/* copy daughterboard xilinx code */
+		if (copy_from_user_toio(  MIXART_MEM( mgr, val),  dsp->image,  dsp->length))
+			return -EFAULT;
+
+		/* set daughterboard status to 4 */
+		writel_be( 4, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
+
+		/* continue with init */
+		break;
+	} /* end of switch file index*/
+
+        /* wait for daughter status == 3 */
+        err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 3, 300); /* 3sec */
+        if (err < 0) {
+		snd_printk( KERN_ERR "daughter board could not be initialised\n");
+		return err;
+	}
+
+	/* init mailbox (communication with embedded) */
+	snd_mixart_init_mailbox(mgr);
+
+	/* first communication with embedded */
+	err = mixart_first_init(mgr);
+        if (err < 0) {
+		snd_printk( KERN_ERR "miXart could not be set up\n");
+		return err;
+	}
+
+       	/* create devices and mixer in accordance with HW options*/
+        for (card_index = 0; card_index < mgr->num_cards; card_index++) {
+		mixart_t *chip = mgr->chip[card_index];
+
+		if ((err = snd_mixart_create_pcm(chip)) < 0)
+			return err;
+
+		if (card_index == 0) {
+			if ((err = snd_mixart_create_mixer(chip->mgr)) < 0)
+	        		return err;
+		}
+
+		if ((err = snd_card_register(chip->card)) < 0)
+			return err;
+	};
+
+	snd_printdd("miXart firmware downloaded and successfully set up\n");
+
+	return 0;
+}
+
+
+int snd_mixart_hwdep_new(mixart_mgr_t *mgr)
+{
+	int err;
+	snd_hwdep_t *hw;
+
+	/* only create hwdep interface for first cardX (see "index" module parameter)*/
+	if ((err = snd_hwdep_new(mgr->chip[0]->card, SND_MIXART_HWDEP_ID, 0, &hw)) < 0)
+		return err;
+
+	hw->iface = SNDRV_HWDEP_IFACE_MIXART;
+	hw->private_data = mgr;
+	hw->ops.open = mixart_hwdep_open;
+	hw->ops.release = mixart_hwdep_release;
+	hw->ops.dsp_status = mixart_hwdep_dsp_status;
+	hw->ops.dsp_load = mixart_hwdep_dsp_load;
+	hw->exclusive = 1;
+	sprintf(hw->name,  SND_MIXART_HWDEP_ID);
+	mgr->hwdep = hw;
+	mgr->hwdep->dsp_loaded = 0;
+	return 0;
+}
--- diff/sound/pci/mixart/mixart_hwdep.h	1970-01-01 01:00:00.000000000 +0100
+++ source/sound/pci/mixart/mixart_hwdep.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,146 @@
+/*
+ * Driver for Digigram miXart soundcards
+ *
+ * definitions and makros for basic card access
+ *
+ * Copyright (c) 2003 by Digigram <alsa@digigram.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef __SOUND_MIXART_HWDEP_H
+#define __SOUND_MIXART_HWDEP_H
+
+#include <sound/hwdep.h>
+
+#define readl_be(x) be32_to_cpu(__raw_readl(x))
+#define writel_be(data,addr) __raw_writel(cpu_to_be32(data),addr)
+
+#define readl_le(x) le32_to_cpu(__raw_readl(x))
+#define writel_le(data,addr) __raw_writel(cpu_to_le32(data),addr)
+
+#define MIXART_MEM(mgr,x)	((mgr)->mem[0].virt + (x))
+#define MIXART_REG(mgr,x)	((mgr)->mem[1].virt + (x))
+
+
+/* Daughter board Type */
+#define DAUGHTER_TYPE_MASK     0x0F 
+#define DAUGHTER_VER_MASK      0xF0 
+#define DAUGHTER_TYPEVER_MASK  (DAUGHTER_TYPE_MASK|DAUGHTER_VER_MASK)
+ 
+#define MIXART_DAUGHTER_TYPE_NONE     0x00 
+#define MIXART_DAUGHTER_TYPE_COBRANET 0x08 
+#define MIXART_DAUGHTER_TYPE_AES      0x0E
+
+
+
+#define MIXART_BA0_SIZE 	(16 * 1024 * 1024) /* 16M */
+#define MIXART_BA1_SIZE 	(4  * 1024)        /* 4k */
+
+/*
+ * -----------BAR 0 --------------------------------------------------------------------------------------------------------
+ */
+#define  MIXART_PSEUDOREG                          0x2000                    /* base address for pseudoregister */
+
+#define  MIXART_PSEUDOREG_BOARDNUMBER              MIXART_PSEUDOREG+0        /* board number */
+
+/* perfmeter (available when elf loaded)*/
+#define  MIXART_PSEUDOREG_PERF_STREAM_LOAD_OFFSET  MIXART_PSEUDOREG+0x70     /* streaming load */
+#define  MIXART_PSEUDOREG_PERF_SYSTEM_LOAD_OFFSET  MIXART_PSEUDOREG+0x78     /* system load (reference)*/
+#define  MIXART_PSEUDOREG_PERF_MAILBX_LOAD_OFFSET  MIXART_PSEUDOREG+0x7C     /* mailbox load */
+#define  MIXART_PSEUDOREG_PERF_INTERR_LOAD_OFFSET  MIXART_PSEUDOREG+0x74     /* interrupt handling  load */
+
+/* motherboard xilinx loader info */
+#define  MIXART_PSEUDOREG_MXLX_BASE_ADDR_OFFSET    MIXART_PSEUDOREG+0x9C     /* 0x00600000 */ 
+#define  MIXART_PSEUDOREG_MXLX_SIZE_OFFSET         MIXART_PSEUDOREG+0xA0     /* xilinx size in bytes */ 
+#define  MIXART_PSEUDOREG_MXLX_STATUS_OFFSET       MIXART_PSEUDOREG+0xA4     /* status = EMBEBBED_STAT_XXX */ 
+
+/* elf loader info */
+#define  MIXART_PSEUDOREG_ELF_STATUS_OFFSET        MIXART_PSEUDOREG+0xB0     /* status = EMBEBBED_STAT_XXX */ 
+
+/* 
+*  after the elf code is loaded, and the flowtable info was passed to it,
+*  the driver polls on this address, until it shows 1 (presence) or 2 (absence)
+*  once it is non-zero, the daughter board type may be read
+*/
+#define  MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET     MIXART_PSEUDOREG+0x990   
+
+/* Global info structure */
+#define  MIXART_PSEUDOREG_DBRD_TYPE_OFFSET         MIXART_PSEUDOREG+0x994    /* Type and version of daughterboard  */
+
+
+/* daughterboard xilinx loader info */
+#define  MIXART_PSEUDOREG_DXLX_BASE_ADDR_OFFSET    MIXART_PSEUDOREG+0x998    /* get the address here where to write the file */ 
+#define  MIXART_PSEUDOREG_DXLX_SIZE_OFFSET         MIXART_PSEUDOREG+0x99C    /* xilinx size in bytes */ 
+#define  MIXART_PSEUDOREG_DXLX_STATUS_OFFSET       MIXART_PSEUDOREG+0x9A0    /* status = EMBEBBED_STAT_XXX */ 
+
+/*  */
+#define  MIXART_FLOWTABLE_PTR                      0x3000                    /* pointer to flow table */
+
+/* mailbox addresses  */
+
+/* message DRV -> EMB */
+#define MSG_INBOUND_POST_HEAD       0x010008	/* DRV posts MF + increment4 */
+#define	MSG_INBOUND_POST_TAIL       0x01000C	/* EMB gets MF + increment4 */
+/* message EMB -> DRV */
+#define	MSG_OUTBOUND_POST_TAIL      0x01001C	/* DRV gets MF + increment4 */
+#define	MSG_OUTBOUND_POST_HEAD      0x010018	/* EMB posts MF + increment4 */
+/* Get Free Frames */
+#define MSG_INBOUND_FREE_TAIL       0x010004	/* DRV gets MFA + increment4 */
+#define MSG_OUTBOUND_FREE_TAIL      0x010014	/* EMB gets MFA + increment4 */
+/* Put Free Frames */
+#define MSG_OUTBOUND_FREE_HEAD      0x010010	/* DRV puts MFA + increment4 */
+#define MSG_INBOUND_FREE_HEAD       0x010000    /* EMB puts MFA + increment4 */
+
+/* firmware addresses of the message fifos */
+#define MSG_BOUND_STACK_SIZE        0x004000    /* size of each following stack */
+/* posted messages */
+#define MSG_OUTBOUND_POST_STACK     0x108000    /* stack of messages to the DRV */
+#define MSG_INBOUND_POST_STACK      0x104000    /* stack of messages to the EMB */
+/* available empty messages */
+#define MSG_OUTBOUND_FREE_STACK     0x10C000    /* stack of free enveloped for EMB */
+#define MSG_INBOUND_FREE_STACK      0x100000    /* stack of free enveloped for DRV */
+
+
+/* defines for mailbox message frames */
+#define MSG_FRAME_OFFSET            0x64
+#define MSG_FRAME_SIZE              0x6400
+#define MSG_FRAME_NUMBER            32
+#define MSG_FROM_AGENT_ITMF_OFFSET  (MSG_FRAME_OFFSET + (MSG_FRAME_SIZE * MSG_FRAME_NUMBER))
+#define MSG_TO_AGENT_ITMF_OFFSET    (MSG_FROM_AGENT_ITMF_OFFSET + MSG_FRAME_SIZE)
+#define MSG_HOST_RSC_PROTECTION     (MSG_TO_AGENT_ITMF_OFFSET + MSG_FRAME_SIZE)
+#define MSG_AGENT_RSC_PROTECTION    (MSG_HOST_RSC_PROTECTION + 4)
+
+
+/*
+ * -----------BAR 1 --------------------------------------------------------------------------------------------------------
+ */
+
+/* interrupt addresses and constants */
+#define MIXART_PCI_OMIMR_OFFSET                 0x34    /* outbound message interrupt mask register */
+#define MIXART_PCI_OMISR_OFFSET                 0x30    /* outbound message interrupt status register */
+#define MIXART_PCI_ODBR_OFFSET                  0x60    /* outbound doorbell register */
+
+#define MIXART_BA1_BRUTAL_RESET_OFFSET          0x68    /* write 1 in LSBit to reset board */
+
+#define MIXART_HOST_ALL_INTERRUPT_MASKED        0x02B   /* 0000 0010 1011 */
+#define MIXART_ALLOW_OUTBOUND_DOORBELL          0x023   /* 0000 0010 0011 */
+#define MIXART_OIDI                             0x008   /* 0000 0000 1000 */
+
+
+/* exported */
+int snd_mixart_hwdep_new(mixart_mgr_t *mgr);
+
+#endif /* __SOUND_MIXART_HWDEP_H */
--- diff/sound/pci/mixart/mixart_mixer.c	1970-01-01 01:00:00.000000000 +0100
+++ source/sound/pci/mixart/mixart_mixer.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,1138 @@
+/*
+ * Driver for Digigram miXart soundcards
+ *
+ * mixer callbacks
+ *
+ * Copyright (c) 2003 by Digigram <alsa@digigram.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <sound/driver.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <sound/core.h>
+#include "mixart.h"
+#include "mixart_core.h"
+#include "mixart_hwdep.h"
+#include <sound/control.h>
+#include "mixart_mixer.h"
+
+#define chip_t mixart_t
+
+static u32 mixart_analog_level[256] = {
+	0xc2c00000,		/* [000] -96.0 dB */
+	0xc2bf0000,		/* [001] -95.5 dB */
+	0xc2be0000,		/* [002] -95.0 dB */
+	0xc2bd0000,		/* [003] -94.5 dB */
+	0xc2bc0000,		/* [004] -94.0 dB */
+	0xc2bb0000,		/* [005] -93.5 dB */
+	0xc2ba0000,		/* [006] -93.0 dB */
+	0xc2b90000,		/* [007] -92.5 dB */
+	0xc2b80000,		/* [008] -92.0 dB */
+	0xc2b70000,		/* [009] -91.5 dB */
+	0xc2b60000,		/* [010] -91.0 dB */
+	0xc2b50000,		/* [011] -90.5 dB */
+	0xc2b40000,		/* [012] -90.0 dB */
+	0xc2b30000,		/* [013] -89.5 dB */
+	0xc2b20000,		/* [014] -89.0 dB */
+	0xc2b10000,		/* [015] -88.5 dB */
+	0xc2b00000,		/* [016] -88.0 dB */
+	0xc2af0000,		/* [017] -87.5 dB */
+	0xc2ae0000,		/* [018] -87.0 dB */
+	0xc2ad0000,		/* [019] -86.5 dB */
+	0xc2ac0000,		/* [020] -86.0 dB */
+	0xc2ab0000,		/* [021] -85.5 dB */
+	0xc2aa0000,		/* [022] -85.0 dB */
+	0xc2a90000,		/* [023] -84.5 dB */
+	0xc2a80000,		/* [024] -84.0 dB */
+	0xc2a70000,		/* [025] -83.5 dB */
+	0xc2a60000,		/* [026] -83.0 dB */
+	0xc2a50000,		/* [027] -82.5 dB */
+	0xc2a40000,		/* [028] -82.0 dB */
+	0xc2a30000,		/* [029] -81.5 dB */
+	0xc2a20000,		/* [030] -81.0 dB */
+	0xc2a10000,		/* [031] -80.5 dB */
+	0xc2a00000,		/* [032] -80.0 dB */
+	0xc29f0000,		/* [033] -79.5 dB */
+	0xc29e0000,		/* [034] -79.0 dB */
+	0xc29d0000,		/* [035] -78.5 dB */
+	0xc29c0000,		/* [036] -78.0 dB */
+	0xc29b0000,		/* [037] -77.5 dB */
+	0xc29a0000,		/* [038] -77.0 dB */
+	0xc2990000,		/* [039] -76.5 dB */
+	0xc2980000,		/* [040] -76.0 dB */
+	0xc2970000,		/* [041] -75.5 dB */
+	0xc2960000,		/* [042] -75.0 dB */
+	0xc2950000,		/* [043] -74.5 dB */
+	0xc2940000,		/* [044] -74.0 dB */
+	0xc2930000,		/* [045] -73.5 dB */
+	0xc2920000,		/* [046] -73.0 dB */
+	0xc2910000,		/* [047] -72.5 dB */
+	0xc2900000,		/* [048] -72.0 dB */
+	0xc28f0000,		/* [049] -71.5 dB */
+	0xc28e0000,		/* [050] -71.0 dB */
+	0xc28d0000,		/* [051] -70.5 dB */
+	0xc28c0000,		/* [052] -70.0 dB */
+	0xc28b0000,		/* [053] -69.5 dB */
+	0xc28a0000,		/* [054] -69.0 dB */
+	0xc2890000,		/* [055] -68.5 dB */
+	0xc2880000,		/* [056] -68.0 dB */
+	0xc2870000,		/* [057] -67.5 dB */
+	0xc2860000,		/* [058] -67.0 dB */
+	0xc2850000,		/* [059] -66.5 dB */
+	0xc2840000,		/* [060] -66.0 dB */
+	0xc2830000,		/* [061] -65.5 dB */
+	0xc2820000,		/* [062] -65.0 dB */
+	0xc2810000,		/* [063] -64.5 dB */
+	0xc2800000,		/* [064] -64.0 dB */
+	0xc27e0000,		/* [065] -63.5 dB */
+	0xc27c0000,		/* [066] -63.0 dB */
+	0xc27a0000,		/* [067] -62.5 dB */
+	0xc2780000,		/* [068] -62.0 dB */
+	0xc2760000,		/* [069] -61.5 dB */
+	0xc2740000,		/* [070] -61.0 dB */
+	0xc2720000,		/* [071] -60.5 dB */
+	0xc2700000,		/* [072] -60.0 dB */
+	0xc26e0000,		/* [073] -59.5 dB */
+	0xc26c0000,		/* [074] -59.0 dB */
+	0xc26a0000,		/* [075] -58.5 dB */
+	0xc2680000,		/* [076] -58.0 dB */
+	0xc2660000,		/* [077] -57.5 dB */
+	0xc2640000,		/* [078] -57.0 dB */
+	0xc2620000,		/* [079] -56.5 dB */
+	0xc2600000,		/* [080] -56.0 dB */
+	0xc25e0000,		/* [081] -55.5 dB */
+	0xc25c0000,		/* [082] -55.0 dB */
+	0xc25a0000,		/* [083] -54.5 dB */
+	0xc2580000,		/* [084] -54.0 dB */
+	0xc2560000,		/* [085] -53.5 dB */
+	0xc2540000,		/* [086] -53.0 dB */
+	0xc2520000,		/* [087] -52.5 dB */
+	0xc2500000,		/* [088] -52.0 dB */
+	0xc24e0000,		/* [089] -51.5 dB */
+	0xc24c0000,		/* [090] -51.0 dB */
+	0xc24a0000,		/* [091] -50.5 dB */
+	0xc2480000,		/* [092] -50.0 dB */
+	0xc2460000,		/* [093] -49.5 dB */
+	0xc2440000,		/* [094] -49.0 dB */
+	0xc2420000,		/* [095] -48.5 dB */
+	0xc2400000,		/* [096] -48.0 dB */
+	0xc23e0000,		/* [097] -47.5 dB */
+	0xc23c0000,		/* [098] -47.0 dB */
+	0xc23a0000,		/* [099] -46.5 dB */
+	0xc2380000,		/* [100] -46.0 dB */
+	0xc2360000,		/* [101] -45.5 dB */
+	0xc2340000,		/* [102] -45.0 dB */
+	0xc2320000,		/* [103] -44.5 dB */
+	0xc2300000,		/* [104] -44.0 dB */
+	0xc22e0000,		/* [105] -43.5 dB */
+	0xc22c0000,		/* [106] -43.0 dB */
+	0xc22a0000,		/* [107] -42.5 dB */
+	0xc2280000,		/* [108] -42.0 dB */
+	0xc2260000,		/* [109] -41.5 dB */
+	0xc2240000,		/* [110] -41.0 dB */
+	0xc2220000,		/* [111] -40.5 dB */
+	0xc2200000,		/* [112] -40.0 dB */
+	0xc21e0000,		/* [113] -39.5 dB */
+	0xc21c0000,		/* [114] -39.0 dB */
+	0xc21a0000,		/* [115] -38.5 dB */
+	0xc2180000,		/* [116] -38.0 dB */
+	0xc2160000,		/* [117] -37.5 dB */
+	0xc2140000,		/* [118] -37.0 dB */
+	0xc2120000,		/* [119] -36.5 dB */
+	0xc2100000,		/* [120] -36.0 dB */
+	0xc20e0000,		/* [121] -35.5 dB */
+	0xc20c0000,		/* [122] -35.0 dB */
+	0xc20a0000,		/* [123] -34.5 dB */
+	0xc2080000,		/* [124] -34.0 dB */
+	0xc2060000,		/* [125] -33.5 dB */
+	0xc2040000,		/* [126] -33.0 dB */
+	0xc2020000,		/* [127] -32.5 dB */
+	0xc2000000,		/* [128] -32.0 dB */
+	0xc1fc0000,		/* [129] -31.5 dB */
+	0xc1f80000,		/* [130] -31.0 dB */
+	0xc1f40000,		/* [131] -30.5 dB */
+	0xc1f00000,		/* [132] -30.0 dB */
+	0xc1ec0000,		/* [133] -29.5 dB */
+	0xc1e80000,		/* [134] -29.0 dB */
+	0xc1e40000,		/* [135] -28.5 dB */
+	0xc1e00000,		/* [136] -28.0 dB */
+	0xc1dc0000,		/* [137] -27.5 dB */
+	0xc1d80000,		/* [138] -27.0 dB */
+	0xc1d40000,		/* [139] -26.5 dB */
+	0xc1d00000,		/* [140] -26.0 dB */
+	0xc1cc0000,		/* [141] -25.5 dB */
+	0xc1c80000,		/* [142] -25.0 dB */
+	0xc1c40000,		/* [143] -24.5 dB */
+	0xc1c00000,		/* [144] -24.0 dB */
+	0xc1bc0000,		/* [145] -23.5 dB */
+	0xc1b80000,		/* [146] -23.0 dB */
+	0xc1b40000,		/* [147] -22.5 dB */
+	0xc1b00000,		/* [148] -22.0 dB */
+	0xc1ac0000,		/* [149] -21.5 dB */
+	0xc1a80000,		/* [150] -21.0 dB */
+	0xc1a40000,		/* [151] -20.5 dB */
+	0xc1a00000,		/* [152] -20.0 dB */
+	0xc19c0000,		/* [153] -19.5 dB */
+	0xc1980000,		/* [154] -19.0 dB */
+	0xc1940000,		/* [155] -18.5 dB */
+	0xc1900000,		/* [156] -18.0 dB */
+	0xc18c0000,		/* [157] -17.5 dB */
+	0xc1880000,		/* [158] -17.0 dB */
+	0xc1840000,		/* [159] -16.5 dB */
+	0xc1800000,		/* [160] -16.0 dB */
+	0xc1780000,		/* [161] -15.5 dB */
+	0xc1700000,		/* [162] -15.0 dB */
+	0xc1680000,		/* [163] -14.5 dB */
+	0xc1600000,		/* [164] -14.0 dB */
+	0xc1580000,		/* [165] -13.5 dB */
+	0xc1500000,		/* [166] -13.0 dB */
+	0xc1480000,		/* [167] -12.5 dB */
+	0xc1400000,		/* [168] -12.0 dB */
+	0xc1380000,		/* [169] -11.5 dB */
+	0xc1300000,		/* [170] -11.0 dB */
+	0xc1280000,		/* [171] -10.5 dB */
+	0xc1200000,		/* [172] -10.0 dB */
+	0xc1180000,		/* [173] -9.5 dB */
+	0xc1100000,		/* [174] -9.0 dB */
+	0xc1080000,		/* [175] -8.5 dB */
+	0xc1000000,		/* [176] -8.0 dB */
+	0xc0f00000,		/* [177] -7.5 dB */
+	0xc0e00000,		/* [178] -7.0 dB */
+	0xc0d00000,		/* [179] -6.5 dB */
+	0xc0c00000,		/* [180] -6.0 dB */
+	0xc0b00000,		/* [181] -5.5 dB */
+	0xc0a00000,		/* [182] -5.0 dB */
+	0xc0900000,		/* [183] -4.5 dB */
+	0xc0800000,		/* [184] -4.0 dB */
+	0xc0600000,		/* [185] -3.5 dB */
+	0xc0400000,		/* [186] -3.0 dB */
+	0xc0200000,		/* [187] -2.5 dB */
+	0xc0000000,		/* [188] -2.0 dB */
+	0xbfc00000,		/* [189] -1.5 dB */
+	0xbf800000,		/* [190] -1.0 dB */
+	0xbf000000,		/* [191] -0.5 dB */
+	0x00000000,		/* [192] 0.0 dB */
+	0x3f000000,		/* [193] 0.5 dB */
+	0x3f800000,		/* [194] 1.0 dB */
+	0x3fc00000,		/* [195] 1.5 dB */
+	0x40000000,		/* [196] 2.0 dB */
+	0x40200000,		/* [197] 2.5 dB */
+	0x40400000,		/* [198] 3.0 dB */
+	0x40600000,		/* [199] 3.5 dB */
+	0x40800000,		/* [200] 4.0 dB */
+	0x40900000,		/* [201] 4.5 dB */
+	0x40a00000,		/* [202] 5.0 dB */
+	0x40b00000,		/* [203] 5.5 dB */
+	0x40c00000,		/* [204] 6.0 dB */
+	0x40d00000,		/* [205] 6.5 dB */
+	0x40e00000,		/* [206] 7.0 dB */
+	0x40f00000,		/* [207] 7.5 dB */
+	0x41000000,		/* [208] 8.0 dB */
+	0x41080000,		/* [209] 8.5 dB */
+	0x41100000,		/* [210] 9.0 dB */
+	0x41180000,		/* [211] 9.5 dB */
+	0x41200000,		/* [212] 10.0 dB */
+	0x41280000,		/* [213] 10.5 dB */
+	0x41300000,		/* [214] 11.0 dB */
+	0x41380000,		/* [215] 11.5 dB */
+	0x41400000,		/* [216] 12.0 dB */
+	0x41480000,		/* [217] 12.5 dB */
+	0x41500000,		/* [218] 13.0 dB */
+	0x41580000,		/* [219] 13.5 dB */
+	0x41600000,		/* [220] 14.0 dB */
+	0x41680000,		/* [221] 14.5 dB */
+	0x41700000,		/* [222] 15.0 dB */
+	0x41780000,		/* [223] 15.5 dB */
+	0x41800000,		/* [224] 16.0 dB */
+	0x41840000,		/* [225] 16.5 dB */
+	0x41880000,		/* [226] 17.0 dB */
+	0x418c0000,		/* [227] 17.5 dB */
+	0x41900000,		/* [228] 18.0 dB */
+	0x41940000,		/* [229] 18.5 dB */
+	0x41980000,		/* [230] 19.0 dB */
+	0x419c0000,		/* [231] 19.5 dB */
+	0x41a00000,		/* [232] 20.0 dB */
+	0x41a40000,		/* [233] 20.5 dB */
+	0x41a80000,		/* [234] 21.0 dB */
+	0x41ac0000,		/* [235] 21.5 dB */
+	0x41b00000,		/* [236] 22.0 dB */
+	0x41b40000,		/* [237] 22.5 dB */
+	0x41b80000,		/* [238] 23.0 dB */
+	0x41bc0000,		/* [239] 23.5 dB */
+	0x41c00000,		/* [240] 24.0 dB */
+	0x41c40000,		/* [241] 24.5 dB */
+	0x41c80000,		/* [242] 25.0 dB */
+	0x41cc0000,		/* [243] 25.5 dB */
+	0x41d00000,		/* [244] 26.0 dB */
+	0x41d40000,		/* [245] 26.5 dB */
+	0x41d80000,		/* [246] 27.0 dB */
+	0x41dc0000,		/* [247] 27.5 dB */
+	0x41e00000,		/* [248] 28.0 dB */
+	0x41e40000,		/* [249] 28.5 dB */
+	0x41e80000,		/* [250] 29.0 dB */
+	0x41ec0000,		/* [251] 29.5 dB */
+	0x41f00000,		/* [252] 30.0 dB */
+	0x41f40000,		/* [253] 30.5 dB */
+	0x41f80000,		/* [254] 31.0 dB */
+	0x41fc0000,		/* [255] 31.5 dB */
+};
+
+#define MIXART_ANALOG_CAPTURE_LEVEL_MIN   0      /* -96.0 dB + 8.0 dB = -88.0 dB */
+#define MIXART_ANALOG_CAPTURE_LEVEL_MAX   255    /*  31.5 dB + 8.0 dB =  39.5 dB */
+#define MIXART_ANALOG_CAPTURE_ZERO_LEVEL  176    /*  -8.0 dB + 8.0 dB =  0.0 dB */
+
+#define MIXART_ANALOG_PLAYBACK_LEVEL_MIN  0      /* -96.0 dB + 1.5 dB = -94.5 dB (possible is down to (-114.0+1.5)dB) */
+#define MIXART_ANALOG_PLAYBACK_LEVEL_MAX  192    /*   0.0 dB + 1.5 dB =  1.5 dB */
+#define MIXART_ANALOG_PLAYBACK_ZERO_LEVEL 189    /*  -1.5 dB + 1.5 dB =  0.0 dB */
+
+static int mixart_update_analog_audio_level(mixart_t* chip, int is_capture)
+{
+	int i, err;
+	mixart_msg_t request;
+	mixart_io_level_t io_level;
+	mixart_return_uid_t resp;
+
+	memset(&io_level, 0, sizeof(io_level));
+	io_level.channel = -1; /* left and right */
+
+	for(i=0; i<2; i++) {
+		if(is_capture) {
+			io_level.level[i].analog_level = mixart_analog_level[chip->analog_capture_volume[i]];
+		} else {
+			if(chip->analog_playback_active[i])
+				io_level.level[i].analog_level = mixart_analog_level[chip->analog_playback_volume[i]];
+			else
+				io_level.level[i].analog_level = mixart_analog_level[MIXART_ANALOG_PLAYBACK_LEVEL_MIN];
+		}
+	}
+
+	if(is_capture)	request.uid = chip->uid_in_analog_physio;
+	else		request.uid = chip->uid_out_analog_physio;
+	request.message_id = MSG_PHYSICALIO_SET_LEVEL;
+	request.data = &io_level;
+	request.size = sizeof(io_level);
+
+	err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp);
+	if((err<0) || (resp.error_code)) {
+		snd_printk(KERN_DEBUG "error MSG_PHYSICALIO_SET_LEVEL card(%d) is_capture(%d) error_code(%x)\n", chip->chip_idx, is_capture, resp.error_code);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * analog level control
+ */
+static int mixart_analog_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	if(kcontrol->private_value == 0) {	/* playback */
+		uinfo->value.integer.min = MIXART_ANALOG_PLAYBACK_LEVEL_MIN;  /* -96 dB */
+		uinfo->value.integer.max = MIXART_ANALOG_PLAYBACK_LEVEL_MAX;  /* 0 dB */
+	} else {				/* capture */
+		uinfo->value.integer.min = MIXART_ANALOG_CAPTURE_LEVEL_MIN;   /* -96 dB */
+		uinfo->value.integer.max = MIXART_ANALOG_CAPTURE_LEVEL_MAX;   /* 31.5 dB */
+	}
+	return 0;
+}
+
+static int mixart_analog_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	down(&chip->mgr->mixer_mutex);
+	if(kcontrol->private_value == 0) {	/* playback */
+		ucontrol->value.integer.value[0] = chip->analog_playback_volume[0];
+		ucontrol->value.integer.value[1] = chip->analog_playback_volume[1];
+	} else {				/* capture */
+		ucontrol->value.integer.value[0] = chip->analog_capture_volume[0];
+		ucontrol->value.integer.value[1] = chip->analog_capture_volume[1];
+	}
+	up(&chip->mgr->mixer_mutex);
+	return 0;
+}
+
+static int mixart_analog_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	int changed = 0;
+	int is_capture, i;
+
+	down(&chip->mgr->mixer_mutex);
+	is_capture = (kcontrol->private_value != 0);
+	for(i=0; i<2; i++) {
+		int  new_volume = ucontrol->value.integer.value[i];
+		int* stored_volume = is_capture ? &chip->analog_capture_volume[i] : &chip->analog_playback_volume[i];
+		if(*stored_volume != new_volume) {
+			*stored_volume = new_volume;
+			changed = 1;
+		}
+	}
+	if(changed)	mixart_update_analog_audio_level(chip, is_capture);
+	up(&chip->mgr->mixer_mutex);
+	return changed;
+}
+
+static snd_kcontrol_new_t mixart_control_analog_level = {
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	/* name will be filled later */
+	.info =		mixart_analog_vol_info,
+	.get =		mixart_analog_vol_get,
+	.put =		mixart_analog_vol_put,
+};
+
+/* shared */
+static int mixart_sw_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int mixart_audio_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+
+	down(&chip->mgr->mixer_mutex);
+	ucontrol->value.integer.value[0] = chip->analog_playback_active[0];
+	ucontrol->value.integer.value[1] = chip->analog_playback_active[1];
+	up(&chip->mgr->mixer_mutex);
+	return 0;
+}
+
+static int mixart_audio_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	int i, changed = 0;
+	down(&chip->mgr->mixer_mutex);
+	for(i=0; i<2; i++) {
+		if(chip->analog_playback_active[i] != ucontrol->value.integer.value[i]) {
+			chip->analog_playback_active[i] = ucontrol->value.integer.value[i];
+			changed = 1;
+		}
+	}
+	if(changed)	mixart_update_analog_audio_level(chip, 0); /* update playback levels */
+	up(&chip->mgr->mixer_mutex);
+	return changed;
+}
+
+static snd_kcontrol_new_t mixart_control_output_switch = {
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name =         "Master Playback Switch",
+	.info =         mixart_sw_info,		/* shared */
+	.get =          mixart_audio_sw_get,
+	.put =          mixart_audio_sw_put
+};
+
+static u32 mixart_digital_level[256] = {
+	0x00000000,		/* [000] = 0.00e+000 = mute if <= -109.5dB */
+	0x366e1c7a,		/* [001] = 3.55e-006 = pow(10.0, 0.05 * -109.0dB) */
+	0x367c3860,		/* [002] = 3.76e-006 = pow(10.0, 0.05 * -108.5dB) */
+	0x36859525,		/* [003] = 3.98e-006 = pow(10.0, 0.05 * -108.0dB) */
+	0x368d7f74,		/* [004] = 4.22e-006 = pow(10.0, 0.05 * -107.5dB) */
+	0x3695e1d4,		/* [005] = 4.47e-006 = pow(10.0, 0.05 * -107.0dB) */
+	0x369ec362,		/* [006] = 4.73e-006 = pow(10.0, 0.05 * -106.5dB) */
+	0x36a82ba8,		/* [007] = 5.01e-006 = pow(10.0, 0.05 * -106.0dB) */
+	0x36b222a0,		/* [008] = 5.31e-006 = pow(10.0, 0.05 * -105.5dB) */
+	0x36bcb0c1,		/* [009] = 5.62e-006 = pow(10.0, 0.05 * -105.0dB) */
+	0x36c7defd,		/* [010] = 5.96e-006 = pow(10.0, 0.05 * -104.5dB) */
+	0x36d3b6d3,		/* [011] = 6.31e-006 = pow(10.0, 0.05 * -104.0dB) */
+	0x36e0424e,		/* [012] = 6.68e-006 = pow(10.0, 0.05 * -103.5dB) */
+	0x36ed8c14,		/* [013] = 7.08e-006 = pow(10.0, 0.05 * -103.0dB) */
+	0x36fb9f6c,		/* [014] = 7.50e-006 = pow(10.0, 0.05 * -102.5dB) */
+	0x37054423,		/* [015] = 7.94e-006 = pow(10.0, 0.05 * -102.0dB) */
+	0x370d29a5,		/* [016] = 8.41e-006 = pow(10.0, 0.05 * -101.5dB) */
+	0x371586f0,		/* [017] = 8.91e-006 = pow(10.0, 0.05 * -101.0dB) */
+	0x371e631b,		/* [018] = 9.44e-006 = pow(10.0, 0.05 * -100.5dB) */
+	0x3727c5ac,		/* [019] = 1.00e-005 = pow(10.0, 0.05 * -100.0dB) */
+	0x3731b69a,		/* [020] = 1.06e-005 = pow(10.0, 0.05 * -99.5dB) */
+	0x373c3e53,		/* [021] = 1.12e-005 = pow(10.0, 0.05 * -99.0dB) */
+	0x374765c8,		/* [022] = 1.19e-005 = pow(10.0, 0.05 * -98.5dB) */
+	0x3753366f,		/* [023] = 1.26e-005 = pow(10.0, 0.05 * -98.0dB) */
+	0x375fba4f,		/* [024] = 1.33e-005 = pow(10.0, 0.05 * -97.5dB) */
+	0x376cfc07,		/* [025] = 1.41e-005 = pow(10.0, 0.05 * -97.0dB) */
+	0x377b06d5,		/* [026] = 1.50e-005 = pow(10.0, 0.05 * -96.5dB) */
+	0x3784f352,		/* [027] = 1.58e-005 = pow(10.0, 0.05 * -96.0dB) */
+	0x378cd40b,		/* [028] = 1.68e-005 = pow(10.0, 0.05 * -95.5dB) */
+	0x37952c42,		/* [029] = 1.78e-005 = pow(10.0, 0.05 * -95.0dB) */
+	0x379e030e,		/* [030] = 1.88e-005 = pow(10.0, 0.05 * -94.5dB) */
+	0x37a75fef,		/* [031] = 2.00e-005 = pow(10.0, 0.05 * -94.0dB) */
+	0x37b14ad5,		/* [032] = 2.11e-005 = pow(10.0, 0.05 * -93.5dB) */
+	0x37bbcc2c,		/* [033] = 2.24e-005 = pow(10.0, 0.05 * -93.0dB) */
+	0x37c6ecdd,		/* [034] = 2.37e-005 = pow(10.0, 0.05 * -92.5dB) */
+	0x37d2b65a,		/* [035] = 2.51e-005 = pow(10.0, 0.05 * -92.0dB) */
+	0x37df32a3,		/* [036] = 2.66e-005 = pow(10.0, 0.05 * -91.5dB) */
+	0x37ec6c50,		/* [037] = 2.82e-005 = pow(10.0, 0.05 * -91.0dB) */
+	0x37fa6e9b,		/* [038] = 2.99e-005 = pow(10.0, 0.05 * -90.5dB) */
+	0x3804a2b3,		/* [039] = 3.16e-005 = pow(10.0, 0.05 * -90.0dB) */
+	0x380c7ea4,		/* [040] = 3.35e-005 = pow(10.0, 0.05 * -89.5dB) */
+	0x3814d1cc,		/* [041] = 3.55e-005 = pow(10.0, 0.05 * -89.0dB) */
+	0x381da33c,		/* [042] = 3.76e-005 = pow(10.0, 0.05 * -88.5dB) */
+	0x3826fa6f,		/* [043] = 3.98e-005 = pow(10.0, 0.05 * -88.0dB) */
+	0x3830df51,		/* [044] = 4.22e-005 = pow(10.0, 0.05 * -87.5dB) */
+	0x383b5a49,		/* [045] = 4.47e-005 = pow(10.0, 0.05 * -87.0dB) */
+	0x3846743b,		/* [046] = 4.73e-005 = pow(10.0, 0.05 * -86.5dB) */
+	0x38523692,		/* [047] = 5.01e-005 = pow(10.0, 0.05 * -86.0dB) */
+	0x385eab48,		/* [048] = 5.31e-005 = pow(10.0, 0.05 * -85.5dB) */
+	0x386bdcf1,		/* [049] = 5.62e-005 = pow(10.0, 0.05 * -85.0dB) */
+	0x3879d6bc,		/* [050] = 5.96e-005 = pow(10.0, 0.05 * -84.5dB) */
+	0x38845244,		/* [051] = 6.31e-005 = pow(10.0, 0.05 * -84.0dB) */
+	0x388c2971,		/* [052] = 6.68e-005 = pow(10.0, 0.05 * -83.5dB) */
+	0x3894778d,		/* [053] = 7.08e-005 = pow(10.0, 0.05 * -83.0dB) */
+	0x389d43a4,		/* [054] = 7.50e-005 = pow(10.0, 0.05 * -82.5dB) */
+	0x38a6952c,		/* [055] = 7.94e-005 = pow(10.0, 0.05 * -82.0dB) */
+	0x38b0740f,		/* [056] = 8.41e-005 = pow(10.0, 0.05 * -81.5dB) */
+	0x38bae8ac,		/* [057] = 8.91e-005 = pow(10.0, 0.05 * -81.0dB) */
+	0x38c5fbe2,		/* [058] = 9.44e-005 = pow(10.0, 0.05 * -80.5dB) */
+	0x38d1b717,		/* [059] = 1.00e-004 = pow(10.0, 0.05 * -80.0dB) */
+	0x38de2440,		/* [060] = 1.06e-004 = pow(10.0, 0.05 * -79.5dB) */
+	0x38eb4de8,		/* [061] = 1.12e-004 = pow(10.0, 0.05 * -79.0dB) */
+	0x38f93f3a,		/* [062] = 1.19e-004 = pow(10.0, 0.05 * -78.5dB) */
+	0x39040206,		/* [063] = 1.26e-004 = pow(10.0, 0.05 * -78.0dB) */
+	0x390bd472,		/* [064] = 1.33e-004 = pow(10.0, 0.05 * -77.5dB) */
+	0x39141d84,		/* [065] = 1.41e-004 = pow(10.0, 0.05 * -77.0dB) */
+	0x391ce445,		/* [066] = 1.50e-004 = pow(10.0, 0.05 * -76.5dB) */
+	0x39263027,		/* [067] = 1.58e-004 = pow(10.0, 0.05 * -76.0dB) */
+	0x3930090d,		/* [068] = 1.68e-004 = pow(10.0, 0.05 * -75.5dB) */
+	0x393a7753,		/* [069] = 1.78e-004 = pow(10.0, 0.05 * -75.0dB) */
+	0x394583d2,		/* [070] = 1.88e-004 = pow(10.0, 0.05 * -74.5dB) */
+	0x395137ea,		/* [071] = 2.00e-004 = pow(10.0, 0.05 * -74.0dB) */
+	0x395d9d8a,		/* [072] = 2.11e-004 = pow(10.0, 0.05 * -73.5dB) */
+	0x396abf37,		/* [073] = 2.24e-004 = pow(10.0, 0.05 * -73.0dB) */
+	0x3978a814,		/* [074] = 2.37e-004 = pow(10.0, 0.05 * -72.5dB) */
+	0x3983b1f8,		/* [075] = 2.51e-004 = pow(10.0, 0.05 * -72.0dB) */
+	0x398b7fa6,		/* [076] = 2.66e-004 = pow(10.0, 0.05 * -71.5dB) */
+	0x3993c3b2,		/* [077] = 2.82e-004 = pow(10.0, 0.05 * -71.0dB) */
+	0x399c8521,		/* [078] = 2.99e-004 = pow(10.0, 0.05 * -70.5dB) */
+	0x39a5cb5f,		/* [079] = 3.16e-004 = pow(10.0, 0.05 * -70.0dB) */
+	0x39af9e4d,		/* [080] = 3.35e-004 = pow(10.0, 0.05 * -69.5dB) */
+	0x39ba063f,		/* [081] = 3.55e-004 = pow(10.0, 0.05 * -69.0dB) */
+	0x39c50c0b,		/* [082] = 3.76e-004 = pow(10.0, 0.05 * -68.5dB) */
+	0x39d0b90a,		/* [083] = 3.98e-004 = pow(10.0, 0.05 * -68.0dB) */
+	0x39dd1726,		/* [084] = 4.22e-004 = pow(10.0, 0.05 * -67.5dB) */
+	0x39ea30db,		/* [085] = 4.47e-004 = pow(10.0, 0.05 * -67.0dB) */
+	0x39f81149,		/* [086] = 4.73e-004 = pow(10.0, 0.05 * -66.5dB) */
+	0x3a03621b,		/* [087] = 5.01e-004 = pow(10.0, 0.05 * -66.0dB) */
+	0x3a0b2b0d,		/* [088] = 5.31e-004 = pow(10.0, 0.05 * -65.5dB) */
+	0x3a136a16,		/* [089] = 5.62e-004 = pow(10.0, 0.05 * -65.0dB) */
+	0x3a1c2636,		/* [090] = 5.96e-004 = pow(10.0, 0.05 * -64.5dB) */
+	0x3a2566d5,		/* [091] = 6.31e-004 = pow(10.0, 0.05 * -64.0dB) */
+	0x3a2f33cd,		/* [092] = 6.68e-004 = pow(10.0, 0.05 * -63.5dB) */
+	0x3a399570,		/* [093] = 7.08e-004 = pow(10.0, 0.05 * -63.0dB) */
+	0x3a44948c,		/* [094] = 7.50e-004 = pow(10.0, 0.05 * -62.5dB) */
+	0x3a503a77,		/* [095] = 7.94e-004 = pow(10.0, 0.05 * -62.0dB) */
+	0x3a5c9112,		/* [096] = 8.41e-004 = pow(10.0, 0.05 * -61.5dB) */
+	0x3a69a2d7,		/* [097] = 8.91e-004 = pow(10.0, 0.05 * -61.0dB) */
+	0x3a777ada,		/* [098] = 9.44e-004 = pow(10.0, 0.05 * -60.5dB) */
+	0x3a83126f,		/* [099] = 1.00e-003 = pow(10.0, 0.05 * -60.0dB) */
+	0x3a8ad6a8,		/* [100] = 1.06e-003 = pow(10.0, 0.05 * -59.5dB) */
+	0x3a9310b1,		/* [101] = 1.12e-003 = pow(10.0, 0.05 * -59.0dB) */
+	0x3a9bc784,		/* [102] = 1.19e-003 = pow(10.0, 0.05 * -58.5dB) */
+	0x3aa50287,		/* [103] = 1.26e-003 = pow(10.0, 0.05 * -58.0dB) */
+	0x3aaec98e,		/* [104] = 1.33e-003 = pow(10.0, 0.05 * -57.5dB) */
+	0x3ab924e5,		/* [105] = 1.41e-003 = pow(10.0, 0.05 * -57.0dB) */
+	0x3ac41d56,		/* [106] = 1.50e-003 = pow(10.0, 0.05 * -56.5dB) */
+	0x3acfbc31,		/* [107] = 1.58e-003 = pow(10.0, 0.05 * -56.0dB) */
+	0x3adc0b51,		/* [108] = 1.68e-003 = pow(10.0, 0.05 * -55.5dB) */
+	0x3ae91528,		/* [109] = 1.78e-003 = pow(10.0, 0.05 * -55.0dB) */
+	0x3af6e4c6,		/* [110] = 1.88e-003 = pow(10.0, 0.05 * -54.5dB) */
+	0x3b02c2f2,		/* [111] = 2.00e-003 = pow(10.0, 0.05 * -54.0dB) */
+	0x3b0a8276,		/* [112] = 2.11e-003 = pow(10.0, 0.05 * -53.5dB) */
+	0x3b12b782,		/* [113] = 2.24e-003 = pow(10.0, 0.05 * -53.0dB) */
+	0x3b1b690d,		/* [114] = 2.37e-003 = pow(10.0, 0.05 * -52.5dB) */
+	0x3b249e76,		/* [115] = 2.51e-003 = pow(10.0, 0.05 * -52.0dB) */
+	0x3b2e5f8f,		/* [116] = 2.66e-003 = pow(10.0, 0.05 * -51.5dB) */
+	0x3b38b49f,		/* [117] = 2.82e-003 = pow(10.0, 0.05 * -51.0dB) */
+	0x3b43a669,		/* [118] = 2.99e-003 = pow(10.0, 0.05 * -50.5dB) */
+	0x3b4f3e37,		/* [119] = 3.16e-003 = pow(10.0, 0.05 * -50.0dB) */
+	0x3b5b85e0,		/* [120] = 3.35e-003 = pow(10.0, 0.05 * -49.5dB) */
+	0x3b6887cf,		/* [121] = 3.55e-003 = pow(10.0, 0.05 * -49.0dB) */
+	0x3b764f0e,		/* [122] = 3.76e-003 = pow(10.0, 0.05 * -48.5dB) */
+	0x3b8273a6,		/* [123] = 3.98e-003 = pow(10.0, 0.05 * -48.0dB) */
+	0x3b8a2e77,		/* [124] = 4.22e-003 = pow(10.0, 0.05 * -47.5dB) */
+	0x3b925e89,		/* [125] = 4.47e-003 = pow(10.0, 0.05 * -47.0dB) */
+	0x3b9b0ace,		/* [126] = 4.73e-003 = pow(10.0, 0.05 * -46.5dB) */
+	0x3ba43aa2,		/* [127] = 5.01e-003 = pow(10.0, 0.05 * -46.0dB) */
+	0x3badf5d1,		/* [128] = 5.31e-003 = pow(10.0, 0.05 * -45.5dB) */
+	0x3bb8449c,		/* [129] = 5.62e-003 = pow(10.0, 0.05 * -45.0dB) */
+	0x3bc32fc3,		/* [130] = 5.96e-003 = pow(10.0, 0.05 * -44.5dB) */
+	0x3bcec08a,		/* [131] = 6.31e-003 = pow(10.0, 0.05 * -44.0dB) */
+	0x3bdb00c0,		/* [132] = 6.68e-003 = pow(10.0, 0.05 * -43.5dB) */
+	0x3be7facc,		/* [133] = 7.08e-003 = pow(10.0, 0.05 * -43.0dB) */
+	0x3bf5b9b0,		/* [134] = 7.50e-003 = pow(10.0, 0.05 * -42.5dB) */
+	0x3c02248a,		/* [135] = 7.94e-003 = pow(10.0, 0.05 * -42.0dB) */
+	0x3c09daac,		/* [136] = 8.41e-003 = pow(10.0, 0.05 * -41.5dB) */
+	0x3c1205c6,		/* [137] = 8.91e-003 = pow(10.0, 0.05 * -41.0dB) */
+	0x3c1aacc8,		/* [138] = 9.44e-003 = pow(10.0, 0.05 * -40.5dB) */
+	0x3c23d70a,		/* [139] = 1.00e-002 = pow(10.0, 0.05 * -40.0dB) */
+	0x3c2d8c52,		/* [140] = 1.06e-002 = pow(10.0, 0.05 * -39.5dB) */
+	0x3c37d4dd,		/* [141] = 1.12e-002 = pow(10.0, 0.05 * -39.0dB) */
+	0x3c42b965,		/* [142] = 1.19e-002 = pow(10.0, 0.05 * -38.5dB) */
+	0x3c4e4329,		/* [143] = 1.26e-002 = pow(10.0, 0.05 * -38.0dB) */
+	0x3c5a7bf1,		/* [144] = 1.33e-002 = pow(10.0, 0.05 * -37.5dB) */
+	0x3c676e1e,		/* [145] = 1.41e-002 = pow(10.0, 0.05 * -37.0dB) */
+	0x3c7524ac,		/* [146] = 1.50e-002 = pow(10.0, 0.05 * -36.5dB) */
+	0x3c81d59f,		/* [147] = 1.58e-002 = pow(10.0, 0.05 * -36.0dB) */
+	0x3c898712,		/* [148] = 1.68e-002 = pow(10.0, 0.05 * -35.5dB) */
+	0x3c91ad39,		/* [149] = 1.78e-002 = pow(10.0, 0.05 * -35.0dB) */
+	0x3c9a4efc,		/* [150] = 1.88e-002 = pow(10.0, 0.05 * -34.5dB) */
+	0x3ca373af,		/* [151] = 2.00e-002 = pow(10.0, 0.05 * -34.0dB) */
+	0x3cad2314,		/* [152] = 2.11e-002 = pow(10.0, 0.05 * -33.5dB) */
+	0x3cb76563,		/* [153] = 2.24e-002 = pow(10.0, 0.05 * -33.0dB) */
+	0x3cc24350,		/* [154] = 2.37e-002 = pow(10.0, 0.05 * -32.5dB) */
+	0x3ccdc614,		/* [155] = 2.51e-002 = pow(10.0, 0.05 * -32.0dB) */
+	0x3cd9f773,		/* [156] = 2.66e-002 = pow(10.0, 0.05 * -31.5dB) */
+	0x3ce6e1c6,		/* [157] = 2.82e-002 = pow(10.0, 0.05 * -31.0dB) */
+	0x3cf49003,		/* [158] = 2.99e-002 = pow(10.0, 0.05 * -30.5dB) */
+	0x3d0186e2,		/* [159] = 3.16e-002 = pow(10.0, 0.05 * -30.0dB) */
+	0x3d0933ac,		/* [160] = 3.35e-002 = pow(10.0, 0.05 * -29.5dB) */
+	0x3d1154e1,		/* [161] = 3.55e-002 = pow(10.0, 0.05 * -29.0dB) */
+	0x3d19f169,		/* [162] = 3.76e-002 = pow(10.0, 0.05 * -28.5dB) */
+	0x3d231090,		/* [163] = 3.98e-002 = pow(10.0, 0.05 * -28.0dB) */
+	0x3d2cba15,		/* [164] = 4.22e-002 = pow(10.0, 0.05 * -27.5dB) */
+	0x3d36f62b,		/* [165] = 4.47e-002 = pow(10.0, 0.05 * -27.0dB) */
+	0x3d41cd81,		/* [166] = 4.73e-002 = pow(10.0, 0.05 * -26.5dB) */
+	0x3d4d494a,		/* [167] = 5.01e-002 = pow(10.0, 0.05 * -26.0dB) */
+	0x3d597345,		/* [168] = 5.31e-002 = pow(10.0, 0.05 * -25.5dB) */
+	0x3d6655c3,		/* [169] = 5.62e-002 = pow(10.0, 0.05 * -25.0dB) */
+	0x3d73fbb4,		/* [170] = 5.96e-002 = pow(10.0, 0.05 * -24.5dB) */
+	0x3d813856,		/* [171] = 6.31e-002 = pow(10.0, 0.05 * -24.0dB) */
+	0x3d88e078,		/* [172] = 6.68e-002 = pow(10.0, 0.05 * -23.5dB) */
+	0x3d90fcbf,		/* [173] = 7.08e-002 = pow(10.0, 0.05 * -23.0dB) */
+	0x3d99940e,		/* [174] = 7.50e-002 = pow(10.0, 0.05 * -22.5dB) */
+	0x3da2adad,		/* [175] = 7.94e-002 = pow(10.0, 0.05 * -22.0dB) */
+	0x3dac5156,		/* [176] = 8.41e-002 = pow(10.0, 0.05 * -21.5dB) */
+	0x3db68738,		/* [177] = 8.91e-002 = pow(10.0, 0.05 * -21.0dB) */
+	0x3dc157fb,		/* [178] = 9.44e-002 = pow(10.0, 0.05 * -20.5dB) */
+	0x3dcccccd,		/* [179] = 1.00e-001 = pow(10.0, 0.05 * -20.0dB) */
+	0x3dd8ef67,		/* [180] = 1.06e-001 = pow(10.0, 0.05 * -19.5dB) */
+	0x3de5ca15,		/* [181] = 1.12e-001 = pow(10.0, 0.05 * -19.0dB) */
+	0x3df367bf,		/* [182] = 1.19e-001 = pow(10.0, 0.05 * -18.5dB) */
+	0x3e00e9f9,		/* [183] = 1.26e-001 = pow(10.0, 0.05 * -18.0dB) */
+	0x3e088d77,		/* [184] = 1.33e-001 = pow(10.0, 0.05 * -17.5dB) */
+	0x3e10a4d3,		/* [185] = 1.41e-001 = pow(10.0, 0.05 * -17.0dB) */
+	0x3e1936ec,		/* [186] = 1.50e-001 = pow(10.0, 0.05 * -16.5dB) */
+	0x3e224b06,		/* [187] = 1.58e-001 = pow(10.0, 0.05 * -16.0dB) */
+	0x3e2be8d7,		/* [188] = 1.68e-001 = pow(10.0, 0.05 * -15.5dB) */
+	0x3e361887,		/* [189] = 1.78e-001 = pow(10.0, 0.05 * -15.0dB) */
+	0x3e40e2bb,		/* [190] = 1.88e-001 = pow(10.0, 0.05 * -14.5dB) */
+	0x3e4c509b,		/* [191] = 2.00e-001 = pow(10.0, 0.05 * -14.0dB) */
+	0x3e586bd9,		/* [192] = 2.11e-001 = pow(10.0, 0.05 * -13.5dB) */
+	0x3e653ebb,		/* [193] = 2.24e-001 = pow(10.0, 0.05 * -13.0dB) */
+	0x3e72d424,		/* [194] = 2.37e-001 = pow(10.0, 0.05 * -12.5dB) */
+	0x3e809bcc,		/* [195] = 2.51e-001 = pow(10.0, 0.05 * -12.0dB) */
+	0x3e883aa8,		/* [196] = 2.66e-001 = pow(10.0, 0.05 * -11.5dB) */
+	0x3e904d1c,		/* [197] = 2.82e-001 = pow(10.0, 0.05 * -11.0dB) */
+	0x3e98da02,		/* [198] = 2.99e-001 = pow(10.0, 0.05 * -10.5dB) */
+	0x3ea1e89b,		/* [199] = 3.16e-001 = pow(10.0, 0.05 * -10.0dB) */
+	0x3eab8097,		/* [200] = 3.35e-001 = pow(10.0, 0.05 * -9.5dB) */
+	0x3eb5aa1a,		/* [201] = 3.55e-001 = pow(10.0, 0.05 * -9.0dB) */
+	0x3ec06dc3,		/* [202] = 3.76e-001 = pow(10.0, 0.05 * -8.5dB) */
+	0x3ecbd4b4,		/* [203] = 3.98e-001 = pow(10.0, 0.05 * -8.0dB) */
+	0x3ed7e89b,		/* [204] = 4.22e-001 = pow(10.0, 0.05 * -7.5dB) */
+	0x3ee4b3b6,		/* [205] = 4.47e-001 = pow(10.0, 0.05 * -7.0dB) */
+	0x3ef240e2,		/* [206] = 4.73e-001 = pow(10.0, 0.05 * -6.5dB) */
+	0x3f004dce,		/* [207] = 5.01e-001 = pow(10.0, 0.05 * -6.0dB) */
+	0x3f07e80b,		/* [208] = 5.31e-001 = pow(10.0, 0.05 * -5.5dB) */
+	0x3f0ff59a,		/* [209] = 5.62e-001 = pow(10.0, 0.05 * -5.0dB) */
+	0x3f187d50,		/* [210] = 5.96e-001 = pow(10.0, 0.05 * -4.5dB) */
+	0x3f21866c,		/* [211] = 6.31e-001 = pow(10.0, 0.05 * -4.0dB) */
+	0x3f2b1896,		/* [212] = 6.68e-001 = pow(10.0, 0.05 * -3.5dB) */
+	0x3f353bef,		/* [213] = 7.08e-001 = pow(10.0, 0.05 * -3.0dB) */
+	0x3f3ff911,		/* [214] = 7.50e-001 = pow(10.0, 0.05 * -2.5dB) */
+	0x3f4b5918,		/* [215] = 7.94e-001 = pow(10.0, 0.05 * -2.0dB) */
+	0x3f5765ac,		/* [216] = 8.41e-001 = pow(10.0, 0.05 * -1.5dB) */
+	0x3f642905,		/* [217] = 8.91e-001 = pow(10.0, 0.05 * -1.0dB) */
+	0x3f71adf9,		/* [218] = 9.44e-001 = pow(10.0, 0.05 * -0.5dB) */
+	0x3f800000,		/* [219] = 1.00e+000 = pow(10.0, 0.05 * 0.0dB) */
+	0x3f8795a0,		/* [220] = 1.06e+000 = pow(10.0, 0.05 * 0.5dB) */
+	0x3f8f9e4d,		/* [221] = 1.12e+000 = pow(10.0, 0.05 * 1.0dB) */
+	0x3f9820d7,		/* [222] = 1.19e+000 = pow(10.0, 0.05 * 1.5dB) */
+	0x3fa12478,		/* [223] = 1.26e+000 = pow(10.0, 0.05 * 2.0dB) */
+	0x3faab0d5,		/* [224] = 1.33e+000 = pow(10.0, 0.05 * 2.5dB) */
+	0x3fb4ce08,		/* [225] = 1.41e+000 = pow(10.0, 0.05 * 3.0dB) */
+	0x3fbf84a6,		/* [226] = 1.50e+000 = pow(10.0, 0.05 * 3.5dB) */
+	0x3fcaddc8,		/* [227] = 1.58e+000 = pow(10.0, 0.05 * 4.0dB) */
+	0x3fd6e30d,		/* [228] = 1.68e+000 = pow(10.0, 0.05 * 4.5dB) */
+	0x3fe39ea9,		/* [229] = 1.78e+000 = pow(10.0, 0.05 * 5.0dB) */
+	0x3ff11b6a,		/* [230] = 1.88e+000 = pow(10.0, 0.05 * 5.5dB) */
+	0x3fff64c1,		/* [231] = 2.00e+000 = pow(10.0, 0.05 * 6.0dB) */
+	0x40074368,		/* [232] = 2.11e+000 = pow(10.0, 0.05 * 6.5dB) */
+	0x400f4735,		/* [233] = 2.24e+000 = pow(10.0, 0.05 * 7.0dB) */
+	0x4017c496,		/* [234] = 2.37e+000 = pow(10.0, 0.05 * 7.5dB) */
+	0x4020c2bf,		/* [235] = 2.51e+000 = pow(10.0, 0.05 * 8.0dB) */
+	0x402a4952,		/* [236] = 2.66e+000 = pow(10.0, 0.05 * 8.5dB) */
+	0x40346063,		/* [237] = 2.82e+000 = pow(10.0, 0.05 * 9.0dB) */
+	0x403f1082,		/* [238] = 2.99e+000 = pow(10.0, 0.05 * 9.5dB) */
+	0x404a62c2,		/* [239] = 3.16e+000 = pow(10.0, 0.05 * 10.0dB) */
+	0x405660bd,		/* [240] = 3.35e+000 = pow(10.0, 0.05 * 10.5dB) */
+	0x406314a0,		/* [241] = 3.55e+000 = pow(10.0, 0.05 * 11.0dB) */
+	0x40708933,		/* [242] = 3.76e+000 = pow(10.0, 0.05 * 11.5dB) */
+	0x407ec9e1,		/* [243] = 3.98e+000 = pow(10.0, 0.05 * 12.0dB) */
+	0x4086f161,		/* [244] = 4.22e+000 = pow(10.0, 0.05 * 12.5dB) */
+	0x408ef052,		/* [245] = 4.47e+000 = pow(10.0, 0.05 * 13.0dB) */
+	0x4097688d,		/* [246] = 4.73e+000 = pow(10.0, 0.05 * 13.5dB) */
+	0x40a06142,		/* [247] = 5.01e+000 = pow(10.0, 0.05 * 14.0dB) */
+	0x40a9e20e,		/* [248] = 5.31e+000 = pow(10.0, 0.05 * 14.5dB) */
+	0x40b3f300,		/* [249] = 5.62e+000 = pow(10.0, 0.05 * 15.0dB) */
+	0x40be9ca5,		/* [250] = 5.96e+000 = pow(10.0, 0.05 * 15.5dB) */
+	0x40c9e807,		/* [251] = 6.31e+000 = pow(10.0, 0.05 * 16.0dB) */
+	0x40d5debc,		/* [252] = 6.68e+000 = pow(10.0, 0.05 * 16.5dB) */
+	0x40e28aeb,		/* [253] = 7.08e+000 = pow(10.0, 0.05 * 17.0dB) */
+	0x40eff755,		/* [254] = 7.50e+000 = pow(10.0, 0.05 * 17.5dB) */
+	0x40fe2f5e,		/* [255] = 7.94e+000 = pow(10.0, 0.05 * 18.0dB) */
+};
+
+#define MIXART_DIGITAL_LEVEL_MIN   0      /* -109.5 dB */
+#define MIXART_DIGITAL_LEVEL_MAX   255    /*  18.0 dB */
+#define MIXART_DIGITAL_ZERO_LEVEL  219    /*  0.0 dB */
+
+
+int mixart_update_playback_stream_level(mixart_t* chip, int is_aes, int idx)
+{
+	int err, i;
+	int volume[2];
+	mixart_msg_t request;
+	mixart_set_out_stream_level_req_t set_level;
+	u32 status;
+	mixart_pipe_t *pipe;
+
+	memset(&set_level, 0, sizeof(set_level));
+	set_level.nb_of_stream = 1;
+	set_level.stream_level.desc.stream_idx = idx;
+
+	if(is_aes) {
+		pipe = &chip->pipe_out_dig;	/* AES playback */
+		idx += MIXART_PLAYBACK_STREAMS;
+	} else {
+		pipe = &chip->pipe_out_ana;	/* analog playback */
+	}
+
+	/* only when pipe exists ! */
+	if(pipe->status == PIPE_UNDEFINED)
+		return 0;
+
+	set_level.stream_level.desc.uid_pipe = pipe->group_uid;
+
+	for(i=0; i<2; i++) {
+		if(chip->digital_playback_active[idx][i])
+			volume[i] = chip->digital_playback_volume[idx][i];
+		else
+			volume[i] = MIXART_DIGITAL_LEVEL_MIN;
+	}
+
+	set_level.stream_level.out_level.valid_mask1 = MIXART_OUT_STREAM_SET_LEVEL_LEFT_AUDIO1 | MIXART_OUT_STREAM_SET_LEVEL_RIGHT_AUDIO2;
+	set_level.stream_level.out_level.left_to_out1_level = mixart_digital_level[volume[0]];
+	set_level.stream_level.out_level.right_to_out2_level = mixart_digital_level[volume[1]];
+
+	request.message_id = MSG_STREAM_SET_OUT_STREAM_LEVEL;
+	request.uid = (mixart_uid_t){0,0};
+	request.data = &set_level;
+	request.size = sizeof(set_level);
+
+	err = snd_mixart_send_msg(chip->mgr, &request, sizeof(status), &status);
+	if((err<0) || status) {
+		snd_printk(KERN_DEBUG "error MSG_STREAM_SET_OUT_STREAM_LEVEL card(%d) status(%x)\n", chip->chip_idx, status);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int mixart_update_capture_stream_level(mixart_t* chip, int is_aes)
+{
+	int err, i, idx;
+	mixart_pipe_t* pipe;
+	mixart_msg_t request;
+	mixart_set_in_audio_level_req_t set_level;
+	u32 status;
+
+	if(is_aes) {
+		idx = 1;
+		pipe = &chip->pipe_in_dig;
+	} else {
+		idx = 0;
+		pipe = &chip->pipe_in_ana;
+	}
+
+	/* only when pipe exists ! */
+	if(pipe->status == PIPE_UNDEFINED)
+		return 0;
+
+	memset(&set_level, 0, sizeof(set_level));
+	set_level.audio_count = 2;
+	set_level.level[0].connector = pipe->uid_left_connector;
+	set_level.level[1].connector = pipe->uid_right_connector;
+
+	for(i=0; i<2; i++) {
+		set_level.level[i].valid_mask1 = MIXART_AUDIO_LEVEL_DIGITAL_MASK;
+		set_level.level[i].digital_level = mixart_digital_level[chip->digital_capture_volume[idx][i]];
+	}
+
+	request.message_id = MSG_STREAM_SET_IN_AUDIO_LEVEL;
+	request.uid = (mixart_uid_t){0,0};
+	request.data = &set_level;
+	request.size = sizeof(set_level);
+
+	err = snd_mixart_send_msg(chip->mgr, &request, sizeof(status), &status);
+	if((err<0) || status) {
+		snd_printk(KERN_DEBUG "error MSG_STREAM_SET_IN_AUDIO_LEVEL card(%d) status(%x)\n", chip->chip_idx, status);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+/* shared */
+static int mixart_digital_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = MIXART_DIGITAL_LEVEL_MIN;   /* -109.5 dB */
+	uinfo->value.integer.max = MIXART_DIGITAL_LEVEL_MAX;   /*   18.0 dB */
+	return 0;
+}
+
+#define MIXART_VOL_REC_MASK	1
+#define MIXART_VOL_AES_MASK	2
+
+static int mixart_pcm_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
+	int *stored_volume;
+	int is_capture = kcontrol->private_value & MIXART_VOL_REC_MASK;
+	int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK;
+	down(&chip->mgr->mixer_mutex);
+	if(is_capture) {
+		if(is_aes)	stored_volume = chip->digital_capture_volume[1];	/* AES capture */
+		else		stored_volume = chip->digital_capture_volume[0];	/* analog capture */
+	} else {
+		snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
+		if(is_aes)	stored_volume = chip->digital_playback_volume[MIXART_PLAYBACK_STREAMS + idx]; /* AES playback */
+		else		stored_volume = chip->digital_playback_volume[idx];	/* analog playback */
+	}
+	ucontrol->value.integer.value[0] = stored_volume[0];
+	ucontrol->value.integer.value[1] = stored_volume[1];
+	up(&chip->mgr->mixer_mutex);
+	return 0;
+}
+
+static int mixart_pcm_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
+	int changed = 0;
+	int is_capture = kcontrol->private_value & MIXART_VOL_REC_MASK;
+	int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK;
+	int* stored_volume;
+	int i;
+	down(&chip->mgr->mixer_mutex);
+	if(is_capture) {
+		if(is_aes)	stored_volume = chip->digital_capture_volume[1];	/* AES capture */
+		else		stored_volume = chip->digital_capture_volume[0];	/* analog capture */
+	} else {
+		snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
+		if(is_aes)	stored_volume = chip->digital_playback_volume[MIXART_PLAYBACK_STREAMS + idx]; /* AES playback */
+		else		stored_volume = chip->digital_playback_volume[idx];	/* analog playback */
+	}
+	for(i=0; i<2; i++) {
+		if(stored_volume[i] != ucontrol->value.integer.value[i]) {
+			stored_volume[i] = ucontrol->value.integer.value[i];
+			changed = 1;
+		}
+	}
+	if(changed) {
+		if(is_capture)	mixart_update_capture_stream_level(chip, is_aes);
+		else		mixart_update_playback_stream_level(chip, is_aes, idx);
+	}
+	up(&chip->mgr->mixer_mutex);
+	return changed;
+}
+
+static snd_kcontrol_new_t snd_mixart_pcm_vol =
+{
+	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+	/* name will be filled later */
+	/* count will be filled later */
+	.info =         mixart_digital_vol_info,		/* shared */
+	.get =          mixart_pcm_vol_get,
+	.put =          mixart_pcm_vol_put,
+};
+
+
+static int mixart_pcm_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
+	snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
+	down(&chip->mgr->mixer_mutex);
+	if(kcontrol->private_value & MIXART_VOL_AES_MASK)	/* AES playback */
+		idx += MIXART_PLAYBACK_STREAMS;
+	ucontrol->value.integer.value[0] = chip->digital_playback_active[idx][0];
+	ucontrol->value.integer.value[1] = chip->digital_playback_active[idx][1];
+	up(&chip->mgr->mixer_mutex);
+	return 0;
+}
+
+static int mixart_pcm_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	int changed = 0;
+	int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK;
+	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
+	int i, j;
+	snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
+	down(&chip->mgr->mixer_mutex);
+	j = idx;
+	if(is_aes)	j += MIXART_PLAYBACK_STREAMS;
+	for(i=0; i<2; i++) {
+		if(chip->digital_playback_active[j][i] != ucontrol->value.integer.value[i]) {
+			chip->digital_playback_active[j][i] = ucontrol->value.integer.value[i];
+			changed = 1;
+		}
+	}
+	if(changed)	mixart_update_playback_stream_level(chip, is_aes, idx);
+	up(&chip->mgr->mixer_mutex);
+	return changed;
+}
+
+static snd_kcontrol_new_t mixart_control_pcm_switch = {
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	/* name will be filled later */
+	.count =        MIXART_PLAYBACK_STREAMS,
+	.info =         mixart_sw_info,		/* shared */
+	.get =          mixart_pcm_sw_get,
+	.put =          mixart_pcm_sw_put
+};
+
+static int mixart_update_monitoring(mixart_t* chip, int channel)
+{
+	int err;
+	mixart_msg_t request;
+	mixart_set_out_audio_level_t audio_level;
+	u32 resp;
+
+	if(chip->pipe_out_ana.status == PIPE_UNDEFINED)
+		return -EINVAL; /* no pipe defined */
+
+	if(!channel)	request.uid = chip->pipe_out_ana.uid_left_connector;
+	else		request.uid = chip->pipe_out_ana.uid_right_connector;
+	request.message_id = MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL;
+	request.data = &audio_level;
+	request.size = sizeof(audio_level);
+
+	memset(&audio_level, 0, sizeof(audio_level));
+	audio_level.valid_mask1 = MIXART_AUDIO_LEVEL_MONITOR_MASK | MIXART_AUDIO_LEVEL_MUTE_M1_MASK;
+	audio_level.monitor_level = mixart_digital_level[chip->monitoring_volume[channel!=0]];
+	audio_level.monitor_mute1 = !chip->monitoring_active[channel!=0];
+
+	err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp);
+	if((err<0) || resp) {
+		snd_printk(KERN_DEBUG "error MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL card(%d) resp(%x)\n", chip->chip_idx, resp);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * monitoring level control
+ */
+
+static int mixart_monitor_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	down(&chip->mgr->mixer_mutex);
+	ucontrol->value.integer.value[0] = chip->monitoring_volume[0];
+	ucontrol->value.integer.value[1] = chip->monitoring_volume[1];
+	up(&chip->mgr->mixer_mutex);
+	return 0;
+}
+
+static int mixart_monitor_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	int changed = 0;
+	int i;
+	down(&chip->mgr->mixer_mutex);
+	for(i=0; i<2; i++) {
+		if(chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) {
+			chip->monitoring_volume[i] = ucontrol->value.integer.value[i];
+			mixart_update_monitoring(chip, i);
+			changed = 1;
+		}
+	}
+	up(&chip->mgr->mixer_mutex);
+	return changed;
+}
+
+static snd_kcontrol_new_t mixart_control_monitor_vol = {
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name =         "Monitoring Volume",
+	.info =		mixart_digital_vol_info,		/* shared */
+	.get =		mixart_monitor_vol_get,
+	.put =		mixart_monitor_vol_put,
+};
+
+/*
+ * monitoring switch control
+ */
+
+static int mixart_monitor_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	down(&chip->mgr->mixer_mutex);
+	ucontrol->value.integer.value[0] = chip->monitoring_active[0];
+	ucontrol->value.integer.value[1] = chip->monitoring_active[1];
+	up(&chip->mgr->mixer_mutex);
+	return 0;
+}
+
+static int mixart_monitor_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	int changed = 0;
+	int i;
+	down(&chip->mgr->mixer_mutex);
+	for(i=0; i<2; i++) {
+		if(chip->monitoring_active[i] != ucontrol->value.integer.value[i]) {
+			chip->monitoring_active[i] = ucontrol->value.integer.value[i];
+			changed |= (1<<i); /* mask 0x01 ans 0x02 */
+		}
+	}
+	if(changed) {
+		/* allocate or release resources for monitoring */
+		int allocate = chip->monitoring_active[0] || chip->monitoring_active[1];
+		if(allocate) {
+			snd_mixart_add_ref_pipe( chip, MIXART_PCM_ANALOG, 0, 1);	/* allocate the playback pipe for monitoring */
+			snd_mixart_add_ref_pipe( chip, MIXART_PCM_ANALOG, 1, 1);	/* allocate the capture pipe for monitoring */
+		}
+		if(changed & 0x01)	mixart_update_monitoring(chip, 0);
+		if(changed & 0x02)	mixart_update_monitoring(chip, 1);
+		if(!allocate) {
+			snd_mixart_kill_ref_pipe( chip->mgr, &chip->pipe_in_ana, 1);	/* release the capture pipe for monitoring */
+			snd_mixart_kill_ref_pipe( chip->mgr, &chip->pipe_out_ana, 1);	/* release the playback pipe for monitoring */
+		}
+	}
+
+	up(&chip->mgr->mixer_mutex);
+	return (changed != 0);
+}
+
+static snd_kcontrol_new_t mixart_control_monitor_sw = {
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name =         "Monitoring Switch",
+	.info =         mixart_sw_info,		/* shared */
+	.get =          mixart_monitor_sw_get,
+	.put =          mixart_monitor_sw_put
+};
+
+
+static void mixart_reset_audio_levels(mixart_t *chip)
+{
+	/* analog volumes can be set even if there is no pipe */
+	mixart_update_analog_audio_level(chip, 0);
+	/* analog levels for capture only on the first two chips */
+	if(chip->chip_idx < 2) {
+		mixart_update_analog_audio_level(chip, 1);
+	}
+	return;
+}
+
+
+int snd_mixart_create_mixer(mixart_mgr_t *mgr)
+{
+	mixart_t *chip;
+	int err, i;
+
+	init_MUTEX(&mgr->mixer_mutex); /* can be in another place */
+
+	for(i=0; i<mgr->num_cards; i++) {
+		snd_kcontrol_new_t temp;
+		chip = mgr->chip[i];
+
+		/* analog output level control */
+		temp = mixart_control_analog_level;
+		temp.name = "Master Playback Volume";
+		temp.private_value = 0; /* playback */
+		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+			return err;
+		/* output mute controls */
+		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&mixart_control_output_switch, chip))) < 0)
+			return err;
+
+		/* analog input level control only on first two chips !*/
+		if(i<2) {
+			temp = mixart_control_analog_level;
+			temp.name = "Master Capture Volume";
+			temp.private_value = 1; /* capture */
+			if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+				return err;
+		}
+
+		temp = snd_mixart_pcm_vol;
+		temp.name = "PCM Playback Volume";
+		temp.count = MIXART_PLAYBACK_STREAMS;
+		temp.private_value = 0; /* playback analog */
+		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+			return err;
+
+		temp.name = "PCM Capture Volume";
+		temp.count = 1;
+		temp.private_value = MIXART_VOL_REC_MASK; /* capture analog */
+		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+			return err;
+
+		if(mgr->board_type == MIXART_DAUGHTER_TYPE_AES) {
+			temp.name = "AES Playback Volume";
+			temp.count = MIXART_PLAYBACK_STREAMS;
+			temp.private_value = MIXART_VOL_AES_MASK; /* playback AES/EBU */
+			if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+				return err;
+
+			temp.name = "AES Capture Volume";
+			temp.count = 0;
+			temp.private_value = MIXART_VOL_REC_MASK | MIXART_VOL_AES_MASK; /* capture AES/EBU */
+			if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+				return err;
+		}
+		temp = mixart_control_pcm_switch;
+		temp.name = "PCM Playback Switch";
+		temp.private_value = 0; /* playback analog */
+		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+			return err;
+
+		if(mgr->board_type == MIXART_DAUGHTER_TYPE_AES) {
+			temp.name = "AES Playback Switch";
+			temp.private_value = MIXART_VOL_AES_MASK; /* playback AES/EBU */
+			if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+				return err;
+		}
+
+		/* monitoring */
+		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&mixart_control_monitor_vol, chip))) < 0)
+			return err;
+		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&mixart_control_monitor_sw, chip))) < 0)
+			return err;
+
+		/* init all mixer data and program the master volumes/switches */
+		mixart_reset_audio_levels(chip);
+	}
+	return 0;
+}
--- diff/sound/pci/mixart/mixart_mixer.h	1970-01-01 01:00:00.000000000 +0100
+++ source/sound/pci/mixart/mixart_mixer.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,31 @@
+/*
+ * Driver for Digigram miXart soundcards
+ *
+ * include file for mixer
+ *
+ * Copyright (c) 2003 by Digigram <alsa@digigram.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef __SOUND_MIXART_MIXER_H
+#define __SOUND_MIXART_MIXER_H
+
+/* exported */
+int mixart_update_playback_stream_level(mixart_t* chip, int is_aes, int idx);
+int mixart_update_capture_stream_level(mixart_t* chip, int is_aes);
+int snd_mixart_create_mixer(mixart_mgr_t* mgr);
+
+#endif /* __SOUND_MIXART_MIXER_H */
--- diff/sound/pcmcia/pdaudiocf/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ source/sound/pcmcia/pdaudiocf/Makefile	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,8 @@
+#
+# Makefile for ALSA
+# Copyright (c) 2004 by Jaroslav Kysela <perex@suse.cz>
+#
+
+snd-pdaudiocf-objs := pdaudiocf.o pdaudiocf_core.o pdaudiocf_irq.o pdaudiocf_pcm.o
+
+obj-$(CONFIG_SND_PDAUDIOCF) += snd-pdaudiocf.o
--- diff/sound/pcmcia/pdaudiocf/pdaudiocf.c	1970-01-01 01:00:00.000000000 +0100
+++ source/sound/pcmcia/pdaudiocf/pdaudiocf.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,426 @@
+/*
+ * Driver for Sound Core PDAudioCF soundcard
+ *
+ * Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <linux/slab.h>
+#include <pcmcia/version.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/cisreg.h>
+#include "pdaudiocf.h"
+#define SNDRV_GET_ID
+#include <sound/initval.h>
+
+/*
+ */
+
+#define CARD_NAME	"PDAudio-CF"
+
+MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_DESCRIPTION("Sound Core " CARD_NAME);
+MODULE_LICENSE("GPL");
+MODULE_CLASSES("{sound}");
+MODULE_DEVICES("{{Sound Core," CARD_NAME "}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable switches */
+static unsigned int irq_mask = 0xffff;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
+MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
+MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
+MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
+MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
+MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM_DESC(irq_mask, "IRQ bitmask for " CARD_NAME " soundcard.");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM_DESC(irq_list, "List of Available interrupts for " CARD_NAME " soundcard.");
+ 
+
+/*
+ */
+
+static dev_info_t dev_info = "snd-pdaudiocf";
+static snd_card_t *card_list[SNDRV_CARDS];
+static dev_link_t *dev_list;
+
+/*
+ * prototypes
+ */
+static void pdacf_config(dev_link_t *link);
+static int pdacf_event(event_t event, int priority, event_callback_args_t *args);
+static void snd_pdacf_detach(dev_link_t *link);
+
+static void pdacf_release(dev_link_t *link)
+{
+	if (link->state & DEV_CONFIG) {
+		/* release cs resources */
+		pcmcia_release_configuration(link->handle);
+		pcmcia_release_io(link->handle, &link->io);
+		pcmcia_release_irq(link->handle, &link->irq);
+		link->state &= ~DEV_CONFIG;
+	}
+}
+
+/*
+ * destructor
+ */
+static int snd_pdacf_free(pdacf_t *pdacf)
+{
+	dev_link_t *link = &pdacf->link;
+
+	pdacf_release(link);
+
+	/* Break the link with Card Services */
+	if (link->handle)
+		pcmcia_deregister_client(link->handle);
+
+	card_list[pdacf->index] = NULL;
+	pdacf->card = NULL;
+
+	snd_magic_kfree(pdacf);
+	return 0;
+}
+
+static int snd_pdacf_dev_free(snd_device_t *device)
+{
+	pdacf_t *chip = snd_magic_cast(pdacf_t, device->device_data, return -ENXIO);
+	return snd_pdacf_free(chip);
+}
+
+/*
+ * snd_pdacf_attach - attach callback for cs
+ */
+static dev_link_t *snd_pdacf_attach(void)
+{
+	client_reg_t client_reg;	/* Register with cardmgr */
+	dev_link_t *link;		/* Info for cardmgr */
+	int i, ret;
+	pdacf_t *pdacf;
+	snd_card_t *card;
+	static snd_device_ops_t ops = {
+		.dev_free =	snd_pdacf_dev_free,
+	};
+
+	snd_printdd(KERN_DEBUG "pdacf_attach called\n");
+	/* find an empty slot from the card list */
+	for (i = 0; i < SNDRV_CARDS; i++) {
+		if (! card_list[i])
+			break;
+	}
+	if (i >= SNDRV_CARDS) {
+		snd_printk(KERN_ERR "pdacf: too many cards found\n");
+		return NULL;
+	}
+	if (! enable[i])
+		return NULL; /* disabled explicitly */
+
+	/* ok, create a card instance */
+	card = snd_card_new(index[i], id[i], THIS_MODULE, 0);
+	if (card == NULL) {
+		snd_printk(KERN_ERR "pdacf: cannot create a card instance\n");
+		return NULL;
+	}
+
+	pdacf = snd_pdacf_create(card);
+	if (! pdacf)
+		return NULL;
+
+	if (snd_device_new(card, SNDRV_DEV_LOWLEVEL, pdacf, &ops) < 0) {
+		snd_magic_kfree(pdacf);
+		snd_card_free(card);
+		return NULL;
+	}
+
+	pdacf->index = i;
+	card_list[i] = card;
+
+	link = &pdacf->link;
+	link->priv = pdacf;
+
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+	link->io.NumPorts1 = 16;
+
+	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT | IRQ_FORCED_PULSE;
+	// link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+
+	link->irq.IRQInfo1 = IRQ_INFO2_VALID /* | IRQ_LEVEL_ID */;
+	if (irq_list[0] == -1)
+		link->irq.IRQInfo2 = irq_mask;
+	else
+		for (i = 0; i < 4; i++)
+			link->irq.IRQInfo2 |= 1 << irq_list[i];
+	link->irq.Handler = pdacf_interrupt;
+	link->irq.Instance = pdacf;
+	link->conf.Attributes = CONF_ENABLE_IRQ;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+	link->conf.ConfigIndex = 1;
+	link->conf.Present = PRESENT_OPTION;
+
+	/* Chain drivers */
+	link->next = dev_list;
+	dev_list = link;
+
+	/* Register with Card Services */
+	client_reg.dev_info = &dev_info;
+	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+	client_reg.EventMask = 
+		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL
+#ifdef CONFIG_PM
+		| CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET
+		| CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME
+#endif
+		;
+	client_reg.event_handler = &pdacf_event;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+
+	ret = pcmcia_register_client(&link->handle, &client_reg);
+	if (ret != CS_SUCCESS) {
+		cs_error(link->handle, RegisterClient, ret);
+		snd_pdacf_detach(link);
+		return NULL;
+	}
+
+	return link;
+}
+
+
+/**
+ * snd_pdacf_assign_resources - initialize the hardware and card instance.
+ * @port: i/o port for the card
+ * @irq: irq number for the card
+ *
+ * this function assigns the specified port and irq, boot the card,
+ * create pcm and control instances, and initialize the rest hardware.
+ *
+ * returns 0 if successful, or a negative error code.
+ */
+static int snd_pdacf_assign_resources(pdacf_t *pdacf, int port, int irq)
+{
+	int err;
+	snd_card_t *card = pdacf->card;
+
+	snd_printdd(KERN_DEBUG "pdacf assign resources: port = 0x%x, irq = %d\n", port, irq);
+	pdacf->port = port;
+	pdacf->irq = irq;
+	pdacf->chip_status |= PDAUDIOCF_STAT_IS_CONFIGURED;
+
+	err = snd_pdacf_ak4117_create(pdacf);
+	if (err < 0)
+		return err;	
+
+	strcpy(card->driver, "PDAudio-CF");
+	sprintf(card->shortname, "Core Sound %s", card->driver);
+	sprintf(card->longname, "%s at 0x%x, irq %i",
+		card->shortname, port, irq);
+
+	err = snd_pdacf_pcm_new(pdacf);
+	if (err < 0)
+		return err;
+
+#ifdef CONFIG_PM
+	card->power_state_private_data = pdacf;
+	card->set_power_state = snd_pdacf_set_power_state;
+#endif
+
+	if ((err = snd_card_register(card)) < 0)
+		return err;
+
+	return 0;
+}
+
+
+/*
+ * snd_pdacf_detach - detach callback for cs
+ */
+static void snd_pdacf_detach(dev_link_t *link)
+{
+	pdacf_t *chip = snd_magic_cast(pdacf_t, link->priv, return);
+
+	snd_printdd(KERN_DEBUG "pdacf_detach called\n");
+	/* Remove the interface data from the linked list */
+	{
+		dev_link_t **linkp;
+		/* Locate device structure */
+		for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+			if (*linkp == link)
+				break;
+		if (*linkp)
+			*linkp = link->next;
+	}
+	if (chip->chip_status & PDAUDIOCF_STAT_IS_CONFIGURED)
+		snd_pdacf_powerdown(chip);
+	chip->chip_status |= PDAUDIOCF_STAT_IS_STALE; /* to be sure */
+	snd_card_disconnect(chip->card);
+	snd_card_free_in_thread(chip->card);
+}
+
+/*
+ * snd_pdacf_detach_all - detach all instances linked to the hw
+ */
+static void snd_pdacf_detach_all(void)
+{
+	while (dev_list != NULL)
+		snd_pdacf_detach(dev_list);
+}
+
+/*
+ * configuration callback
+ */
+
+#define CS_CHECK(fn, ret) \
+do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+
+static void pdacf_config(dev_link_t *link)
+{
+	client_handle_t handle = link->handle;
+	pdacf_t *pdacf = snd_magic_cast(pdacf_t, link->priv, return);
+	tuple_t tuple;
+	cisparse_t parse;
+	config_info_t conf;
+	u_short buf[32];
+	int last_fn, last_ret;
+
+	snd_printdd(KERN_DEBUG "pdacf_config called\n");
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	tuple.Attributes = 0;
+	tuple.TupleData = (cisdata_t *)buf;
+	tuple.TupleDataMax = sizeof(buf);
+	tuple.TupleOffset = 0;
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+	link->conf.ConfigBase = parse.config.base;
+	link->conf.ConfigIndex = 0x5;
+
+	CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
+	link->conf.Vcc = conf.Vcc;
+
+	/* Configure card */
+	link->state |= DEV_CONFIG;
+
+	CS_CHECK(RequestIO, pcmcia_request_io(handle, &link->io));
+	CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
+	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
+
+	if (snd_pdacf_assign_resources(pdacf, link->io.BasePort1, link->irq.AssignedIRQ) < 0)
+		goto failed;
+
+	link->dev = &pdacf->node;
+	link->state &= ~DEV_CONFIG_PENDING;
+	return;
+
+cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+failed:
+	pcmcia_release_configuration(link->handle);
+	pcmcia_release_io(link->handle, &link->io);
+	pcmcia_release_irq(link->handle, &link->irq);
+}
+
+/*
+ * event callback
+ */
+static int pdacf_event(event_t event, int priority, event_callback_args_t *args)
+{
+	dev_link_t *link = args->client_data;
+	pdacf_t *chip = link->priv;
+
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		snd_printdd(KERN_DEBUG "CARD_REMOVAL..\n");
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG) {
+			chip->chip_status |= PDAUDIOCF_STAT_IS_STALE;
+		}
+		break;
+	case CS_EVENT_CARD_INSERTION:
+		snd_printdd(KERN_DEBUG "CARD_INSERTION..\n");
+		link->state |= DEV_PRESENT;
+		pdacf_config(link);
+		break;
+#ifdef CONFIG_PM
+	case CS_EVENT_PM_SUSPEND:
+		snd_printdd(KERN_DEBUG "SUSPEND\n");
+		link->state |= DEV_SUSPEND;
+		if (chip) {
+			snd_printdd(KERN_DEBUG "snd_pdacf_suspend calling\n");
+			snd_pdacf_suspend(chip);
+		}
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		snd_printdd(KERN_DEBUG "RESET_PHYSICAL\n");
+		if (link->state & DEV_CONFIG)
+			pcmcia_release_configuration(link->handle);
+		break;
+	case CS_EVENT_PM_RESUME:
+		snd_printdd(KERN_DEBUG "RESUME\n");
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		snd_printdd(KERN_DEBUG "CARD_RESET\n");
+		if (DEV_OK(link)) {
+			snd_printdd(KERN_DEBUG "requestconfig...\n");
+			pcmcia_request_configuration(link->handle, &link->conf);
+			if (chip) {
+				snd_printdd(KERN_DEBUG "calling snd_pdacf_resume\n");
+				snd_pdacf_resume(chip);
+			}
+		}
+		snd_printdd(KERN_DEBUG "resume done!\n");
+		break;
+#endif
+	}
+	return 0;
+}
+
+/*
+ * Module entry points
+ */
+static struct pcmcia_driver pdacf_cs_driver = {
+	.owner          = THIS_MODULE,
+	.drv            = {
+		.name   = "snd-pdaudiocf",
+	},
+	.attach         = snd_pdacf_attach,
+	.detach         = snd_pdacf_detach
+};
+
+static int __init init_pdacf(void)
+{
+	return pcmcia_register_driver(&pdacf_cs_driver);
+}
+
+static void __exit exit_pdacf(void)
+{
+	pcmcia_unregister_driver(&pdacf_cs_driver);
+	snd_pdacf_detach_all();
+}
+
+module_init(init_pdacf);
+module_exit(exit_pdacf);
--- diff/sound/pcmcia/pdaudiocf/pdaudiocf.h	1970-01-01 01:00:00.000000000 +0100
+++ source/sound/pcmcia/pdaudiocf/pdaudiocf.h	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,148 @@
+/*
+ * Driver for Sound Cors PDAudioCF soundcard
+ *
+ * Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef __PDAUDIOCF_H
+#define __PDAUDIOCF_H
+
+#include <sound/pcm.h>
+#include <asm/io.h>
+#include <linux/interrupt.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#include <sound/ak4117.h>
+
+/* PDAUDIOCF registers */
+#define PDAUDIOCF_REG_MD	0x00	/* music data, R/O */
+#define PDAUDIOCF_REG_WDP	0x02	/* write data pointer / 2, R/O */
+#define PDAUDIOCF_REG_RDP	0x04	/* read data pointer / 2, R/O */
+#define PDAUDIOCF_REG_TCR	0x06	/* test control register W/O */
+#define PDAUDIOCF_REG_SCR	0x08	/* status and control, R/W (see bit description) */
+#define PDAUDIOCF_REG_ISR	0x0a	/* interrupt status, R/O */
+#define PDAUDIOCF_REG_IER	0x0c	/* interrupt enable, R/W */
+#define PDAUDIOCF_REG_AK_IFR	0x0e	/* AK interface register, R/W */
+
+/* PDAUDIOCF_REG_TCR */
+#define PDAUDIOCF_ELIMAKMBIT	(1<<0)	/* simulate AKM music data */
+#define PDAUDIOCF_TESTDATASEL	(1<<1)	/* test data selection, 0 = 0x55, 1 = pseudo-random */
+
+/* PDAUDIOCF_REG_SCR */
+#define PDAUDIOCF_AK_SBP	(1<<0)	/* serial port busy flag */
+#define PDAUDIOCF_RST		(1<<2)	/* FPGA, AKM + SRAM buffer reset */
+#define PDAUDIOCF_PDN		(1<<3)	/* power down bit */
+#define PDAUDIOCF_CLKDIV0	(1<<4)	/* choose 24.576Mhz clock divided by 1,2,3 or 4 */
+#define PDAUDIOCF_CLKDIV1	(1<<5)
+#define PDAUDIOCF_RECORD	(1<<6)	/* start capturing to SRAM */
+#define PDAUDIOCF_AK_SDD	(1<<7)	/* music data detected */
+#define PDAUDIOCF_RED_LED_OFF	(1<<8)	/* red LED off override */
+#define PDAUDIOCF_BLUE_LED_OFF	(1<<9)	/* blue LED off override */
+#define PDAUDIOCF_DATAFMT0	(1<<10)	/* data format bits: 00 = 16-bit, 01 = 18-bit */
+#define PDAUDIOCF_DATAFMT1	(1<<11)	/* 10 = 20-bit, 11 = 24-bit, all right justified */
+#define PDAUDIOCF_FPGAREV(x)	((x>>12)&0x0f) /* FPGA revision */
+
+/* PDAUDIOCF_REG_ISR */
+#define PDAUDIOCF_IRQLVL	(1<<0)	/* Buffer level IRQ */
+#define PDAUDIOCF_IRQOVR	(1<<1)	/* Overrun IRQ */
+#define PDAUDIOCF_IRQAKM	(1<<2)	/* AKM IRQ */
+
+/* PDAUDIOCF_REG_IER */
+#define PDAUDIOCF_IRQLVLEN0	(1<<0)	/* fill threshold levels; 00 = none, 01 = 1/8th of buffer */
+#define PDAUDIOCF_IRQLVLEN1	(1<<1)	/* 10 = 1/4th of buffer, 11 = 1/2th of buffer */
+#define PDAUDIOCF_IRQOVREN	(1<<2)	/* enable overrun IRQ */
+#define PDAUDIOCF_IRQAKMEN	(1<<3)	/* enable AKM IRQ */
+#define PDAUDIOCF_BLUEDUTY0	(1<<8)	/* blue LED duty cycle; 00 = 100%, 01 = 50% */
+#define PDAUDIOCF_BLUEDUTY1	(1<<9)	/* 02 = 25%, 11 = 12% */
+#define PDAUDIOCF_REDDUTY0	(1<<10)	/* red LED duty cycle; 00 = 100%, 01 = 50% */
+#define PDAUDIOCF_REDDUTY1	(1<<11)	/* 02 = 25%, 11 = 12% */
+#define PDAUDIOCF_BLUESDD	(1<<12)	/* blue LED against SDD bit */
+#define PDAUDIOCF_BLUEMODULATE	(1<<13)	/* save power when 100% duty cycle selected */
+#define PDAUDIOCF_REDMODULATE	(1<<14)	/* save power when 100% duty cycle selected */
+#define PDAUDIOCF_HALFRATE	(1<<15)	/* slow both LED blinks by half (also spdif detect rate) */
+
+/* chip status */
+#define PDAUDIOCF_STAT_IS_STALE	(1<<0)
+#define PDAUDIOCF_STAT_IS_CONFIGURED (1<<1)
+#define PDAUDIOCF_STAT_IS_SUSPENDED (1<<2)
+
+typedef struct {
+	snd_card_t *card;
+	int index;
+
+	unsigned long port;
+	int irq;
+
+	spinlock_t reg_lock;
+	unsigned short regmap[8];
+	unsigned short suspend_reg_scr;
+	struct tasklet_struct tq;
+
+	spinlock_t ak4117_lock;
+	ak4117_t *ak4117;
+
+	unsigned int chip_status;
+
+	snd_pcm_t *pcm;
+	snd_pcm_substream_t *pcm_substream;
+	unsigned int pcm_running: 1;
+	unsigned int pcm_channels;
+	unsigned int pcm_swab;
+	unsigned int pcm_little;
+	unsigned int pcm_frame;
+	unsigned int pcm_sample;
+	unsigned int pcm_xor;
+	unsigned int pcm_size;
+	unsigned int pcm_period;
+	unsigned int pcm_tdone;
+	unsigned int pcm_hwptr;
+	void *pcm_area;
+	
+	/* pcmcia stuff */
+	dev_link_t link;
+	dev_node_t node;
+} pdacf_t;
+
+static inline void pdacf_reg_write(pdacf_t *chip, unsigned char reg, unsigned short val)
+{
+	outw(chip->regmap[reg>>1] = val, chip->port + reg);
+}
+
+static inline unsigned short pdacf_reg_read(pdacf_t *chip, unsigned char reg)
+{
+	return inw(chip->port + reg);
+}
+
+unsigned char pdacf_ak4117_read(void *private_data, unsigned char reg);
+void pdacf_ak4117_write(void *private_data, unsigned char reg, unsigned char val);
+pdacf_t *snd_pdacf_create(snd_card_t *card);
+int snd_pdacf_ak4117_create(pdacf_t *pdacf);
+void snd_pdacf_powerdown(pdacf_t *chip);
+#ifdef CONFIG_PM
+void snd_pdacf_suspend(pdacf_t *chip);
+void snd_pdacf_resume(pdacf_t *chip);
+int snd_pdacf_set_power_state(snd_card_t *card, unsigned int power_state);
+#endif
+int snd_pdacf_pcm_new(pdacf_t *chip);
+void pdacf_interrupt(int irq, void *dev, struct pt_regs *regs);
+void pdacf_tasklet(unsigned long private_data);
+void pdacf_reinit(pdacf_t *chip, int resume);
+
+#endif /* __PDAUDIOCF_H */
--- diff/sound/pcmcia/pdaudiocf/pdaudiocf_core.c	1970-01-01 01:00:00.000000000 +0100
+++ source/sound/pcmcia/pdaudiocf/pdaudiocf_core.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,317 @@
+/*
+ * Driver for Sound Core PDAudioCF soundcard
+ *
+ * Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include "pdaudiocf.h"
+#define SNDRV_GET_ID
+#include <sound/initval.h>
+
+/*
+ *
+ */
+unsigned char pdacf_ak4117_read(void *private_data, unsigned char reg)
+{
+	pdacf_t *chip = snd_magic_cast(pdacf_t, private_data, return 0);
+	unsigned long timeout;
+	unsigned long flags;
+	unsigned char res;
+
+	spin_lock_irqsave(&chip->ak4117_lock, flags);
+	timeout = 1000;
+	while (pdacf_reg_read(chip, PDAUDIOCF_REG_SCR) & PDAUDIOCF_AK_SBP) {
+		udelay(5);
+		if (--timeout == 0) {
+			spin_unlock_irqrestore(&chip->ak4117_lock, flags);
+			snd_printk(KERN_ERR "AK4117 ready timeout (read)\n");
+			return 0;
+		}
+	}
+	pdacf_reg_write(chip, PDAUDIOCF_REG_AK_IFR, (u16)reg << 8);
+	timeout = 1000;
+	while (pdacf_reg_read(chip, PDAUDIOCF_REG_SCR) & PDAUDIOCF_AK_SBP) {
+		udelay(5);
+		if (--timeout == 0) {
+			spin_unlock_irqrestore(&chip->ak4117_lock, flags);
+			snd_printk(KERN_ERR "AK4117 read timeout (read2)\n");
+			return 0;
+		}
+	}
+	res = (unsigned char)pdacf_reg_read(chip, PDAUDIOCF_REG_AK_IFR);
+	spin_unlock_irqrestore(&chip->ak4117_lock, flags);
+	return res;
+}
+
+void pdacf_ak4117_write(void *private_data, unsigned char reg, unsigned char val)
+{
+	pdacf_t *chip = snd_magic_cast(pdacf_t, private_data, return);
+	unsigned long timeout;
+	unsigned long flags;
+
+	spin_lock_irqsave(&chip->ak4117_lock, flags);
+	timeout = 1000;
+	while (inw(chip->port + PDAUDIOCF_REG_SCR) & PDAUDIOCF_AK_SBP) {
+		udelay(5);
+		if (--timeout == 0) {
+			spin_unlock_irqrestore(&chip->ak4117_lock, flags);
+			snd_printk(KERN_ERR "AK4117 ready timeout (write)\n");
+			return;
+		}
+	}
+	outw((u16)reg << 8 | val | (1<<13), chip->port + PDAUDIOCF_REG_AK_IFR);
+	spin_unlock_irqrestore(&chip->ak4117_lock, flags);
+}
+
+#if 0
+void pdacf_dump(pdacf_t *chip)
+{
+	printk("PDAUDIOCF DUMP (0x%lx):\n", chip->port);
+	printk("WPD         : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_WDP));
+	printk("RDP         : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_RDP));
+	printk("TCR         : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_TCR));
+	printk("SCR         : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_SCR));
+	printk("ISR         : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_ISR));
+	printk("IER         : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_IER));
+	printk("AK_IFR      : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_AK_IFR));
+}
+#endif
+
+static int pdacf_reset(pdacf_t *chip, int powerdown)
+{
+	u16 val;
+	
+	val = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
+	val |= PDAUDIOCF_PDN;
+	val &= ~PDAUDIOCF_RECORD;		/* for sure */
+	pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val);
+	udelay(5);
+	val |= PDAUDIOCF_RST;
+	pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val);
+	udelay(200);
+	val &= ~PDAUDIOCF_RST;
+	pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val);
+	udelay(5);
+	if (!powerdown) {
+		val &= ~PDAUDIOCF_PDN;
+		pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val);
+		udelay(200);
+	}
+	return 0;
+}
+
+void pdacf_reinit(pdacf_t *chip, int resume)
+{
+	pdacf_reset(chip, 0);
+	if (resume)
+		pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, chip->suspend_reg_scr);
+	snd_ak4117_reinit(chip->ak4117);
+	pdacf_reg_write(chip, PDAUDIOCF_REG_TCR, chip->regmap[PDAUDIOCF_REG_TCR>>1]);
+	pdacf_reg_write(chip, PDAUDIOCF_REG_IER, chip->regmap[PDAUDIOCF_REG_IER>>1]);
+}
+
+static void pdacf_proc_read(snd_info_entry_t * entry,
+                            snd_info_buffer_t * buffer)
+{
+	pdacf_t *chip = snd_magic_cast(pdacf_t, entry->private_data, return);
+	u16 tmp;
+
+	snd_iprintf(buffer, "PDAudioCF\n\n");
+	tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
+	snd_iprintf(buffer, "FPGA revision      : 0x%x\n", PDAUDIOCF_FPGAREV(tmp));
+	                                   
+}
+
+static void pdacf_proc_init(pdacf_t *chip)
+{
+	snd_info_entry_t *entry;
+
+	if (! snd_card_proc_new(chip->card, "pdaudiocf", &entry))
+		snd_info_set_text_ops(entry, chip, 1024, pdacf_proc_read);
+}
+
+pdacf_t *snd_pdacf_create(snd_card_t *card)
+{
+	pdacf_t *chip;
+
+	chip = snd_magic_kcalloc(pdacf_t, 0, GFP_KERNEL);
+	if (chip == NULL)
+		return NULL;
+	chip->card = card;
+	spin_lock_init(&chip->reg_lock);
+	spin_lock_init(&chip->ak4117_lock);
+	tasklet_init(&chip->tq, pdacf_tasklet, (unsigned long)chip);
+	card->private_data = chip;
+
+	pdacf_proc_init(chip);
+	return chip;
+}
+
+static void snd_pdacf_ak4117_change(ak4117_t *ak4117, unsigned char c0, unsigned char c1)
+{
+	pdacf_t *chip = ak4117->change_callback_private;
+	unsigned long flags;
+	u16 val;
+
+	if (!(c0 & AK4117_UNLCK))
+		return;
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	val = chip->regmap[PDAUDIOCF_REG_SCR>>1];
+	if (ak4117->rcs0 & AK4117_UNLCK)
+		val |= PDAUDIOCF_BLUE_LED_OFF;
+	else
+		val &= ~PDAUDIOCF_BLUE_LED_OFF;
+	pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val);
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+}
+
+int snd_pdacf_ak4117_create(pdacf_t *chip)
+{
+	int err;
+	u16 val;
+	/* design note: if we unmask PLL unlock, parity, valid, audio or auto bit interrupts */
+	/* from AK4117 then INT1 pin from AK4117 will be high all time, because PCMCIA interrupts are */
+	/* egde based and FPGA does logical OR for all interrupt sources, we cannot use these */
+	/* high-rate sources */
+	static unsigned char pgm[5] = {
+		AK4117_XTL_24_576M | AK4117_EXCT,				/* AK4117_REG_PWRDN */
+		AK4117_CM_PLL_XTAL | AK4117_PKCS_128fs | AK4117_XCKS_128fs,	/* AK4117_REQ_CLOCK */
+		AK4117_EFH_1024LRCLK | AK4117_DIF_24R | AK4117_IPS,		/* AK4117_REG_IO */
+		0xff,								/* AK4117_REG_INT0_MASK */
+		AK4117_MAUTO | AK4117_MAUD | AK4117_MULK | AK4117_MPAR | AK4117_MV, /* AK4117_REG_INT1_MASK */
+	};
+
+	err = pdacf_reset(chip, 0);
+	if (err < 0)
+		return err;
+	err = snd_ak4117_create(chip->card, pdacf_ak4117_read, pdacf_ak4117_write, pgm, chip, &chip->ak4117);
+	if (err < 0)
+		return err;
+
+	val = pdacf_reg_read(chip, PDAUDIOCF_REG_TCR);
+#if 1 /* normal operation */
+	val &= ~(PDAUDIOCF_ELIMAKMBIT|PDAUDIOCF_TESTDATASEL);
+#else /* debug */
+	val |= PDAUDIOCF_ELIMAKMBIT;
+	val &= ~PDAUDIOCF_TESTDATASEL;
+#endif
+	pdacf_reg_write(chip, PDAUDIOCF_REG_TCR, val);
+	
+	/* setup the FPGA to match AK4117 setup */
+	val = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
+	val &= ~(PDAUDIOCF_CLKDIV0 | PDAUDIOCF_CLKDIV1);		/* use 24.576Mhz clock */
+	val &= ~(PDAUDIOCF_RED_LED_OFF|PDAUDIOCF_BLUE_LED_OFF);
+	val |= PDAUDIOCF_DATAFMT0 | PDAUDIOCF_DATAFMT1;			/* 24-bit data */
+	pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val);
+
+	/* setup LEDs and IRQ */
+	val = pdacf_reg_read(chip, PDAUDIOCF_REG_IER);
+	val &= ~(PDAUDIOCF_IRQLVLEN0 | PDAUDIOCF_IRQLVLEN1);
+	val &= ~(PDAUDIOCF_BLUEDUTY0 | PDAUDIOCF_REDDUTY0 | PDAUDIOCF_REDDUTY1);
+	val |= PDAUDIOCF_BLUEDUTY1 | PDAUDIOCF_HALFRATE;
+	val |= PDAUDIOCF_IRQOVREN | PDAUDIOCF_IRQAKMEN;
+	pdacf_reg_write(chip, PDAUDIOCF_REG_IER, val);
+
+	chip->ak4117->change_callback_private = chip;
+	chip->ak4117->change_callback = snd_pdacf_ak4117_change;
+
+	/* update LED status */
+	snd_pdacf_ak4117_change(chip->ak4117, AK4117_UNLCK, 0);
+
+	return 0;
+}
+
+void snd_pdacf_powerdown(pdacf_t *chip)
+{
+	u16 val;
+
+	val = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
+	chip->suspend_reg_scr = val;
+	val |= PDAUDIOCF_RED_LED_OFF | PDAUDIOCF_BLUE_LED_OFF;
+	pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val);
+	/* disable interrupts, but use direct write to preserve old register value in chip->regmap */
+	val = inw(chip->port + PDAUDIOCF_REG_IER);
+	val &= ~(PDAUDIOCF_IRQOVREN|PDAUDIOCF_IRQAKMEN|PDAUDIOCF_IRQLVLEN0|PDAUDIOCF_IRQLVLEN1);
+	outw(val, chip->port + PDAUDIOCF_REG_IER);
+	pdacf_reset(chip, 1);
+}
+
+#ifdef CONFIG_PM
+
+void snd_pdacf_suspend(pdacf_t *chip)
+{
+	snd_card_t *card = chip->card;
+	u16 val;
+	
+	if (card->power_state == SNDRV_CTL_POWER_D3hot)
+		return;
+	snd_pcm_suspend_all(chip->pcm);
+	/* disable interrupts, but use direct write to preserve old register value in chip->regmap */
+	val = inw(chip->port + PDAUDIOCF_REG_IER);
+	val &= ~(PDAUDIOCF_IRQOVREN|PDAUDIOCF_IRQAKMEN|PDAUDIOCF_IRQLVLEN0|PDAUDIOCF_IRQLVLEN1);
+	outw(val, chip->port + PDAUDIOCF_REG_IER);
+	chip->chip_status |= PDAUDIOCF_STAT_IS_SUSPENDED;	/* ignore interrupts from now */
+	snd_pdacf_powerdown(chip);
+	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+}
+
+static inline int check_signal(pdacf_t *chip)
+{
+	return (chip->ak4117->rcs0 & AK4117_UNLCK) == 0;
+}
+
+void snd_pdacf_resume(pdacf_t *chip)
+{
+	snd_card_t *card = chip->card;
+	int timeout = 40;
+
+	if (card->power_state == SNDRV_CTL_POWER_D0)
+		return;
+	pdacf_reinit(chip, 1);
+	/* wait for AK4117's PLL */
+	while (timeout-- > 0 &&
+	       (snd_ak4117_external_rate(chip->ak4117) <= 0 || !check_signal(chip)))
+		mdelay(1);
+	chip->chip_status &= ~PDAUDIOCF_STAT_IS_SUSPENDED;
+	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+}
+
+int snd_pdacf_set_power_state(snd_card_t *card, unsigned int power_state)
+{
+	pdacf_t *chip = snd_magic_cast(pdacf_t, card->power_state_private_data, return -ENXIO);
+
+	switch (power_state) {
+	case SNDRV_CTL_POWER_D0:
+	case SNDRV_CTL_POWER_D1:
+	case SNDRV_CTL_POWER_D2:
+		snd_pdacf_resume(chip);
+		break;
+	case SNDRV_CTL_POWER_D3hot:
+	case SNDRV_CTL_POWER_D3cold:
+		snd_pdacf_suspend(chip);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+#endif
--- diff/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c	1970-01-01 01:00:00.000000000 +0100
+++ source/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,325 @@
+/*
+ * Driver for Sound Core PDAudioCF soundcard
+ *
+ * Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include "pdaudiocf.h"
+#define SNDRV_GET_ID
+#include <sound/initval.h>
+
+/*
+ *
+ */
+void pdacf_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+	pdacf_t *chip = snd_magic_cast(pdacf_t, dev, return);
+	unsigned short stat;
+
+	if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|
+				  PDAUDIOCF_STAT_IS_CONFIGURED|
+				  PDAUDIOCF_STAT_IS_SUSPENDED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
+		return;
+
+	stat = inw(chip->port + PDAUDIOCF_REG_ISR);
+	if (stat & (PDAUDIOCF_IRQLVL|PDAUDIOCF_IRQOVR)) {
+		if (stat & PDAUDIOCF_IRQOVR)	/* should never happen */
+			snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n");
+		if (chip->pcm_substream)
+			tasklet_hi_schedule(&chip->tq);
+		if (!(stat & PDAUDIOCF_IRQAKM))
+			stat |= PDAUDIOCF_IRQAKM;	/* check rate */
+	}
+	if (regs != NULL)
+		snd_ak4117_check_rate_and_errors(chip->ak4117, 0);
+}
+
+static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
+{
+	while (size-- > 0) {
+		*dst++ = inw(rdp_port) ^ xor;
+		inw(rdp_port);
+	}
+}
+
+static inline void pdacf_transfer_mono32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
+{
+	register u16 val1, val2;
+
+	while (size-- > 0) {
+		val1 = inw(rdp_port);
+		val2 = inw(rdp_port);
+		inw(rdp_port);
+		*dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
+	}
+}
+
+static inline void pdacf_transfer_stereo16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
+{
+	while (size-- > 0) {
+		*dst++ = inw(rdp_port) ^ xor;
+		*dst++ = inw(rdp_port) ^ xor;
+	}
+}
+
+static inline void pdacf_transfer_stereo32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
+{
+	register u16 val1, val2, val3;
+
+	while (size-- > 0) {
+		val1 = inw(rdp_port);
+		val2 = inw(rdp_port);
+		val3 = inw(rdp_port);
+		*dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
+		*dst++ = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
+	}
+}
+
+static inline void pdacf_transfer_mono16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
+{
+	while (size-- > 0) {
+		*dst++ = swab16(inw(rdp_port) ^ xor);
+		inw(rdp_port);
+	}
+}
+
+static inline void pdacf_transfer_mono32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
+{
+	register u16 val1, val2;
+
+	while (size-- > 0) {
+		val1 = inw(rdp_port);
+		val2 = inw(rdp_port);
+		inw(rdp_port);
+		*dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
+	}
+}
+
+static inline void pdacf_transfer_stereo16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
+{
+	while (size-- > 0) {
+		*dst++ = swab16(inw(rdp_port) ^ xor);
+		*dst++ = swab16(inw(rdp_port) ^ xor);
+	}
+}
+
+static inline void pdacf_transfer_stereo32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
+{
+	register u16 val1, val2, val3;
+
+	while (size-- > 0) {
+		val1 = inw(rdp_port);
+		val2 = inw(rdp_port);
+		val3 = inw(rdp_port);
+		*dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
+		*dst++ = swab32((((u32)val3 << 16) | (val2 & 0xff00)) ^ xor);
+	}
+}
+
+static inline void pdacf_transfer_mono24le(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
+{
+	register u16 val1, val2;
+	register u32 xval1;
+
+	while (size-- > 0) {
+		val1 = inw(rdp_port);
+		val2 = inw(rdp_port);
+		inw(rdp_port);
+		xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
+		*dst++ = (u8)(xval1 >> 8);
+		*dst++ = (u8)(xval1 >> 16);
+		*dst++ = (u8)(xval1 >> 24);
+	}
+}
+
+static inline void pdacf_transfer_mono24be(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
+{
+	register u16 val1, val2;
+	register u32 xval1;
+
+	while (size-- > 0) {
+		val1 = inw(rdp_port);
+		val2 = inw(rdp_port);
+		inw(rdp_port);
+		xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
+		*dst++ = (u8)(xval1 >> 24);
+		*dst++ = (u8)(xval1 >> 16);
+		*dst++ = (u8)(xval1 >> 8);
+	}
+}
+
+static inline void pdacf_transfer_stereo24le(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
+{
+	register u16 val1, val2, val3;
+	register u32 xval1, xval2;
+
+	while (size-- > 0) {
+		val1 = inw(rdp_port);
+		val2 = inw(rdp_port);
+		val3 = inw(rdp_port);
+		xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
+		xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
+		*dst++ = (u8)(xval1 >> 8);
+		*dst++ = (u8)(xval1 >> 16);
+		*dst++ = (u8)(xval1 >> 24);
+		*dst++ = (u8)(xval2 >> 8);
+		*dst++ = (u8)(xval2 >> 16);
+		*dst++ = (u8)(xval2 >> 24);
+	}
+}
+
+static inline void pdacf_transfer_stereo24be(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
+{
+	register u16 val1, val2, val3;
+	register u32 xval1, xval2;
+
+	while (size-- > 0) {
+		val1 = inw(rdp_port);
+		val2 = inw(rdp_port);
+		val3 = inw(rdp_port);
+		xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
+		xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
+		*dst++ = (u8)(xval1 >> 24);
+		*dst++ = (u8)(xval1 >> 16);
+		*dst++ = (u8)(xval1 >> 8);
+		*dst++ = (u8)(xval2 >> 24);
+		*dst++ = (u8)(xval2 >> 16);
+		*dst++ = (u8)(xval2 >> 8);
+	}
+}
+
+static void pdacf_transfer(pdacf_t *chip, unsigned int size, unsigned int off)
+{
+	unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
+	unsigned int xor = chip->pcm_xor;
+
+	if (chip->pcm_sample == 3) {
+		if (chip->pcm_little) {
+			if (chip->pcm_channels == 1) {
+				pdacf_transfer_mono24le((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
+			} else {
+				pdacf_transfer_stereo24le((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
+			}
+		} else {
+			if (chip->pcm_channels == 1) {
+				pdacf_transfer_mono24be((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
+			} else {
+				pdacf_transfer_stereo24be((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
+			}			
+		}
+		return;
+	}
+	if (chip->pcm_swab == 0) {
+		if (chip->pcm_channels == 1) {
+			if (chip->pcm_frame == 2) {
+				pdacf_transfer_mono16((u16 *)chip->pcm_area + off, xor, size, rdp_port);
+			} else {
+				pdacf_transfer_mono32((u32 *)chip->pcm_area + off, xor, size, rdp_port);
+			}
+		} else {
+			if (chip->pcm_frame == 2) {
+				pdacf_transfer_stereo16((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
+			} else {
+				pdacf_transfer_stereo32((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
+			}
+		}
+	} else {
+		if (chip->pcm_channels == 1) {
+			if (chip->pcm_frame == 2) {
+				pdacf_transfer_mono16sw((u16 *)chip->pcm_area + off, xor, size, rdp_port);
+			} else {
+				pdacf_transfer_mono32sw((u32 *)chip->pcm_area + off, xor, size, rdp_port);
+			}
+		} else {
+			if (chip->pcm_frame == 2) {
+				pdacf_transfer_stereo16sw((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
+			} else {
+				pdacf_transfer_stereo32sw((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
+			}
+		}
+	}
+}
+
+void pdacf_tasklet(unsigned long private_data)
+{
+	pdacf_t *chip = snd_magic_cast(pdacf_t, (void *)private_data, return);
+	int size, off, cont, rdp, wdp;
+
+	if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
+		return;
+	
+	if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream))
+		return;
+
+	rdp = inw(chip->port + PDAUDIOCF_REG_RDP);
+	wdp = inw(chip->port + PDAUDIOCF_REG_WDP);
+	// printk("TASKLET: rdp = %x, wdp = %x\n", rdp, wdp);
+	size = wdp - rdp;
+	if (size < 0)
+		size += 0x10000;
+	if (size == 0)
+		size = 0x10000;
+	size /= chip->pcm_frame;
+	if (size > 64)
+		size -= 32;
+
+#if 0
+	chip->pcm_hwptr += size;
+	chip->pcm_hwptr %= chip->pcm_size;
+	chip->pcm_tdone += size;
+	if (chip->pcm_frame == 2) {
+		unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
+		while (size-- > 0) {
+			inw(rdp_port);
+			inw(rdp_port);
+		}
+	} else {
+		unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
+		while (size-- > 0) {
+			inw(rdp_port);
+			inw(rdp_port);
+			inw(rdp_port);
+		}
+	}
+#else
+	off = chip->pcm_hwptr + chip->pcm_tdone;
+	off %= chip->pcm_size;
+	chip->pcm_tdone += size;
+	while (size > 0) {
+		cont = chip->pcm_size - off;
+		if (cont > size)
+			cont = size;
+		pdacf_transfer(chip, cont, off);
+		off += cont;
+		off %= chip->pcm_size;
+		size -= cont;
+	}
+#endif
+	spin_lock(&chip->reg_lock);
+	while (chip->pcm_tdone >= chip->pcm_period) {
+		chip->pcm_hwptr += chip->pcm_period;
+		chip->pcm_hwptr %= chip->pcm_size;
+		chip->pcm_tdone -= chip->pcm_period;
+		spin_unlock(&chip->reg_lock);
+		snd_pcm_period_elapsed(chip->pcm_substream);
+		spin_lock(&chip->reg_lock);
+	}
+	spin_unlock(&chip->reg_lock);
+	// printk("TASKLET: end\n");
+}
--- diff/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c	1970-01-01 01:00:00.000000000 +0100
+++ source/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c	2004-03-09 11:51:52.000000000 +0000
@@ -0,0 +1,363 @@
+/*
+ * Driver for Sound Core PDAudioCF soundcards
+ *
+ * PCM part
+ *
+ * Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <sound/driver.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/asoundef.h>
+#include "pdaudiocf.h"
+
+#define chip_t	pdacf_t
+
+
+/*
+ * we use a vmalloc'ed (sg-)buffer
+ */
+
+/* get the physical page pointer on the given offset */
+static struct page *snd_pcm_get_vmalloc_page(snd_pcm_substream_t *subs, unsigned long offset)
+{
+	void *pageptr = subs->runtime->dma_area + offset;
+	return vmalloc_to_page(pageptr);
+}
+
+/*
+ * hw_params callback
+ * NOTE: this may be called not only once per pcm open!
+ */
+static int snd_pcm_alloc_vmalloc_buffer(snd_pcm_substream_t *subs, size_t size)
+{
+	snd_pcm_runtime_t *runtime = subs->runtime;
+	if (runtime->dma_area) {
+		if (runtime->dma_bytes >= size)
+			return 0; /* already enough large */
+		vfree_nocheck(runtime->dma_area);
+	}
+	runtime->dma_area = vmalloc_nocheck(size);
+	if (! runtime->dma_area)
+		return -ENOMEM;
+	runtime->dma_bytes = size;
+	return 0;
+}
+
+/*
+ * hw_free callback
+ * NOTE: this may be called not only once per pcm open!
+ */
+static int snd_pcm_free_vmalloc_buffer(snd_pcm_substream_t *subs)
+{
+	snd_pcm_runtime_t *runtime = subs->runtime;
+	if (runtime->dma_area) {
+		vfree_nocheck(runtime->dma_area);
+		runtime->dma_area = NULL;
+	}
+	return 0;
+}
+
+/*
+ * clear the SRAM contents
+ */
+static int pdacf_pcm_clear_sram(pdacf_t *chip)
+{
+	int max_loop = 64 * 1024;
+
+	while (inw(chip->port + PDAUDIOCF_REG_RDP) != inw(chip->port + PDAUDIOCF_REG_WDP)) {
+		if (max_loop-- < 0)
+			return -EIO;
+		inw(chip->port + PDAUDIOCF_REG_MD);
+	}
+	return 0;
+}
+
+/*
+ * pdacf_pcm_trigger - trigger callback for capture
+ */
+static int pdacf_pcm_trigger(snd_pcm_substream_t *subs, int cmd)
+{
+	pdacf_t *chip = snd_pcm_substream_chip(subs);
+	snd_pcm_runtime_t *runtime = subs->runtime;
+	int inc, ret = 0, rate;
+	unsigned short mask, val, tmp;
+
+	if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
+		return -EBUSY;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		chip->pcm_hwptr = 0;
+		chip->pcm_tdone = 0;
+		/* fall thru */
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		mask = 0;
+		val = PDAUDIOCF_RECORD;
+		inc = 1;
+		rate = snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_STAT|AK4117_CHECK_NO_RATE);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		mask = PDAUDIOCF_RECORD;
+		val = 0;
+		inc = -1;
+		rate = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+	spin_lock(&chip->reg_lock);
+	chip->pcm_running += inc;
+	tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
+	if (chip->pcm_running) {
+		if ((chip->ak4117->rcs0 & AK4117_UNLCK) || runtime->rate != rate) {
+			chip->pcm_running -= inc;
+			ret = -EIO;
+			goto __end;
+		}
+	}
+	tmp &= ~mask;
+	tmp |= val;
+	pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp);
+      __end:
+	spin_unlock(&chip->reg_lock);
+	snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE);
+	return ret;
+}
+
+/*
+ * pdacf_pcm_hw_params - hw_params callback for playback and capture
+ */
+static int pdacf_pcm_hw_params(snd_pcm_substream_t *subs,
+				     snd_pcm_hw_params_t *hw_params)
+{
+	return snd_pcm_alloc_vmalloc_buffer(subs, params_buffer_bytes(hw_params));
+}
+
+/*
+ * pdacf_pcm_hw_free - hw_free callback for playback and capture
+ */
+static int pdacf_pcm_hw_free(snd_pcm_substream_t *subs)
+{
+	return snd_pcm_free_vmalloc_buffer(subs);
+}
+
+/*
+ * pdacf_pcm_prepare - prepare callback for playback and capture
+ */
+static int pdacf_pcm_prepare(snd_pcm_substream_t *subs)
+{
+	pdacf_t *chip = snd_pcm_substream_chip(subs);
+	snd_pcm_runtime_t *runtime = subs->runtime;
+	u16 val, nval, aval;
+
+	if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
+		return -EBUSY;
+
+	chip->pcm_channels = runtime->channels;
+
+	chip->pcm_little = snd_pcm_format_little_endian(runtime->format) > 0;
+#ifdef SNDRV_LITTLE_ENDIAN
+	chip->pcm_swab = snd_pcm_format_big_endian(runtime->format) > 0;
+#else
+	chip->pcm_swab = chip->pcm_little;
+#endif
+
+	if (snd_pcm_format_unsigned(runtime->format))
+		chip->pcm_xor = 0x80008000;
+
+	if (pdacf_pcm_clear_sram(chip) < 0)
+		return -EIO;
+	
+	val = nval = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
+	nval &= ~(PDAUDIOCF_DATAFMT0|PDAUDIOCF_DATAFMT1);
+	switch (runtime->format) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+	case SNDRV_PCM_FORMAT_S16_BE:
+		break;
+	default: /* 24-bit */
+		nval |= PDAUDIOCF_DATAFMT0 | PDAUDIOCF_DATAFMT1;
+		break;
+	}
+	aval = 0;
+	chip->pcm_sample = 4;
+	switch (runtime->format) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+	case SNDRV_PCM_FORMAT_S16_BE:
+		aval = AK4117_DIF_16R;
+		chip->pcm_frame = 2;
+		chip->pcm_sample = 2;
+		break;
+	case SNDRV_PCM_FORMAT_S24_3LE:
+	case SNDRV_PCM_FORMAT_S24_3BE:
+		chip->pcm_sample = 3;
+		/* fall trough */
+	default: /* 24-bit */
+		aval = AK4117_DIF_24R;
+		chip->pcm_frame = 3;
+		chip->pcm_xor &= 0xffff0000;
+		break;
+	}
+
+	if (val != nval) {
+		snd_ak4117_reg_write(chip->ak4117, AK4117_REG_IO, AK4117_DIF2|AK4117_DIF1|AK4117_DIF0, aval);
+		pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, nval);
+	}
+
+	val = pdacf_reg_read(chip,  PDAUDIOCF_REG_IER);
+	val &= ~(PDAUDIOCF_IRQLVLEN1);
+	val |= PDAUDIOCF_IRQLVLEN0;
+	pdacf_reg_write(chip, PDAUDIOCF_REG_IER, val);
+
+	chip->pcm_size = runtime->buffer_size;
+	chip->pcm_period = runtime->period_size;
+	chip->pcm_area = runtime->dma_area;
+
+	return 0;
+}
+
+
+/*
+ * capture hw information
+ */
+
+static snd_pcm_hardware_t pdacf_pcm_capture_hw = {
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
+				 SNDRV_PCM_INFO_MMAP_VALID),
+	.formats =		SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
+				SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
+				SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE,
+	.rates =		SNDRV_PCM_RATE_32000 |
+				SNDRV_PCM_RATE_44100 |
+				SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_88200 |
+				SNDRV_PCM_RATE_96000 |
+				SNDRV_PCM_RATE_176400 |
+				SNDRV_PCM_RATE_192000,
+	.rate_min =		32000,
+	.rate_max =		192000,
+	.channels_min =		1,
+	.channels_max =		2,
+	.buffer_bytes_max =	(512*1024),
+	.period_bytes_min =	8*1024,
+	.period_bytes_max =	(64*1024),
+	.periods_min =		2,
+	.periods_max =		128,
+	.fifo_size =		0,
+};
+
+
+/*
+ * pdacf_pcm_capture_open - open callback for capture
+ */
+static int pdacf_pcm_capture_open(snd_pcm_substream_t *subs)
+{
+	snd_pcm_runtime_t *runtime = subs->runtime;
+	pdacf_t *chip = snd_pcm_substream_chip(subs);
+
+	if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
+		return -EBUSY;
+
+	runtime->hw = pdacf_pcm_capture_hw;
+	runtime->private_data = chip;
+	chip->pcm_substream = subs;
+
+	return 0;
+}
+
+/*
+ * pdacf_pcm_capture_close - close callback for capture
+ */
+static int pdacf_pcm_capture_close(snd_pcm_substream_t *subs)
+{
+	pdacf_t *chip = snd_pcm_substream_chip(subs);
+
+	if (!chip)
+		return -EINVAL;
+	pdacf_reinit(chip, 0);
+	chip->pcm_substream = NULL;
+	return 0;
+}
+
+
+/*
+ * pdacf_pcm_capture_pointer - pointer callback for capture
+ */
+static snd_pcm_uframes_t pdacf_pcm_capture_pointer(snd_pcm_substream_t *subs)
+{
+	pdacf_t *chip = snd_pcm_substream_chip(subs);
+	return chip->pcm_hwptr;
+}
+
+/*
+ * operators for PCM capture
+ */
+static snd_pcm_ops_t pdacf_pcm_capture_ops = {
+	.open =		pdacf_pcm_capture_open,
+	.close =	pdacf_pcm_capture_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	pdacf_pcm_hw_params,
+	.hw_free =	pdacf_pcm_hw_free,
+	.prepare =	pdacf_pcm_prepare,
+	.trigger =	pdacf_pcm_trigger,
+	.pointer =	pdacf_pcm_capture_pointer,
+	.page =		snd_pcm_get_vmalloc_page,
+};
+
+
+/*
+ * free callback for pcm
+ */
+static void snd_pdacf_pcm_free(snd_pcm_t *pcm)
+{
+	pdacf_t *chip = snd_magic_cast(pdacf_t, pcm->private_data, return);
+	chip->pcm = NULL;
+}
+
+/*
+ * snd_pdacf_pcm_new - create and initialize a pcm
+ */
+int snd_pdacf_pcm_new(pdacf_t *chip)
+{
+	snd_pcm_t *pcm;
+	int err;
+
+	err = snd_pcm_new(chip->card, "PDAudioCF", 0, 0, 1, &pcm);
+	if (err < 0)
+		return err;
+		
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pdacf_pcm_capture_ops);
+
+	pcm->private_data = chip;
+	pcm->private_free = snd_pdacf_pcm_free;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, chip->card->shortname);
+	chip->pcm = pcm;
+	
+	err = snd_ak4117_build(chip->ak4117, pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
--- diff/Documentation/usb/scanner.txt	2004-03-04 11:41:42.000000000 +0000
+++ source/Documentation/usb/scanner.txt	1970-01-01 01:00:00.000000000 +0100
@@ -1,336 +0,0 @@
-Copyright (C) 1999, 2000 David E. Nelson <dnelson@jump.net>
-Updated 2003 by Henning Meier-Geinitz <henning@meier-geinitz.de>
-
-
-OVERVIEW
-
-This README addresses issues regarding how to configure the kernel to access a
-USB scanner.  Although the driver was originally conceived for USB HP
-scanners, it's general enough so that it can be used with most other USB
-scanners.  Also, one can pass the USB Vendor and Product IDs using module
-parameters for unknown scanners.
-
-There are two drivers for SCSI-over-USB scanners: 
-* The "hpusbscsi" module for Hewlett-Packard 53xx series, Hewlett-Packard 7400,
-  Minolta Scan Dual II, Minolta Elite II
-* The "microtek" module for the Microtek Scanmaker X6
-
-In addition to the kernel driver, user-space tools like SANE are necessary to
-actually use the scanner.  SANE ("Scanner Access Now Easy") provides drivers
-for a variety of USB scanners.  See the appropriate SANE man page for details,
-e.g. man sane-usb and man sane-hp (for HP scanners).
-
-NOTE: Just because a product is detected by this driver does not mean that
-applications exist that support the product.  It's in the hopes that this will
-allow developers a means to produce applications that will support the listed
-USB products.
-
-
-ADDITIONAL INFORMATION
-
-http://www.linux-usb.org/           (General information, mailing lists, links)
-http://www.mostang.com/sane/        (SANE user-space tools)
-http://www.meier-geinitz.de/kernel/ (USB scanner driver information and patches)
-
-
-REQUIREMENTS
-
-A host with a USB port.  Ideally, either a UHCI (Intel), OHCI (Compaq and
-others) or EHCI hardware should work.  
-
-Using "make menuconfig" or your preferred method for configuring the kernel,
-select "Support for USB", "OHCI HCD/UHCI HCD/EHCI HCD" depending on your
-hardware, "USB Scanner support", and "USB device filesystem".  Compile and
-install the modules (you may need to execute "depmod -a" to update the module
-dependencies).  If any of the USB sections were compiled into the kernel, a
-reboot is necessary.  NOTE: Updating the boot disk with "lilo" may also be
-required.  Testing was performed only as modules, YMMV.
-
-Up to 16 scanners can be connected/used simultaneously.  If devfs support is
-enabled, see next section.  Otherwise, the device files must be created
-manually if they don't exist yet, either by MAKEDEV or mknod.
-
-MAKEDEV method:
-  cd /dev
-  MAKEDEV usb
-  Check that the device files "/dev/usb/scanner0" - "/dev/usb/scanner15" have
-  been created.
-
-mknod method:
-  mknod /dev/usb/scanner0 c 180 48
-  mknod /dev/usb/scanner1 c 180 49
-                  . 
-                  .
-  mknod /dev/usb/scanner15 c 180 63
-
-Set appropriate permissions for /dev/usb/scanner[0-15] (don't forget
-about group and world permissions).  Both read and write permissions
-are required for proper operation.  For example:
-  chmod 666 /dev/usb/scanner0
-
-Load the appropriate modules (if compiled as modules):
-
-  modprobe ohci-hcd (or uhci-hcd, ehci-hcd)
-  modprobe scanner
-
-
-DEVFS
-
-The later versions of the Linux kernel (2.4.8'ish) included a dynamic
-device filesystem call "devfs".  With devfs, there is no need to
-create the device files as explained above; instead, they are
-dynamically created for you.  For USB Scanner, the device is created
-in /dev/usb/scannerX where X can range from 0 to 15 depending on the
-number of scanners connected to the system.
-
-To see if you have devfs, issue the command "cat /proc/filesytems".
-If devfs is listed you should be ready to go.  You should also have a
-process running called "devfsd".  In order to make sure, issue the
-command "ps aux | grep '[d]evfsd'".
-
-
-CONCLUSION
-
-That's it.  SANE should now be able to access the device.  To make sure the
-device was detected, use "cat /proc/bus/usb/devices".  Your scanner should be
-listed and the line starting with "I:" should look similar to this example:
-
-  I:  If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=usbscanner
-
-The important part is "Driver=usbscanner".  If it reads "Driver=(none)", the
-USB scanner driver didn't recognize the scanner.  Have a look at the MODULE
-PARAMETERS section for what to do in this case.
-
-For more details on the format of "/proc/bus/usb/devices" see
-Documentation/usb/proc_usb_info.txt.
-
-
-MESSAGES
-
-usb_control/bulk_msg: timeout -- On occasions this message will appear
-in "/var/adm/messages", on the console, or both depending on how
-your system is configured.  This is a side effect that scanners are
-sometimes very slow at warming up and/or initializing.  In most cases,
-however, only several of these messages should appear and is generally
-considered to be normal.  
-
-excessive NAK's received -- This message should be considered abnormal
-and generally indicates that the USB system is unable to communicate
-with the scanner for some particular reason.
-
-probe_scanner: Undetected endpoint -- The USB Scanner driver is fairly
-general when it comes to communicating to scanners.  Unfortunately,
-some vendors have designed their scanners in one way or another that
-this driver doesn't account for.
-
-probe_scanner: Endpoint determination failed -- This means that the
-driver is unable to detect a supported configuration for means to
-communicate with the scanner.  See also "probe_scanner: Undetected
-endpoint".
-
-funky result -- Most of the time the data flow between the computer
-and the scanner goes smoothly.  However, due to whatever reason,
-whether it be solar flares or stray neutrons, sometimes the
-communications don't work as expected.  The driver tries to handle
-most types of errors but not all.  When this message is seen,
-something weird happened.  Please contact the mailing list (see
-CONTACT section for details).
-
-
-MODULE PARAMETERS
-
-If you have a device that you wish to experiment with or try using
-this driver with, but the Vendor and Product IDs are not coded in,
-don't despair.  If the driver was compiled as a module, you can pass
-options to the driver.  Simply add 
-
-  options scanner vendor=0x#### product=0x****
-
-to the /etc/modprobe.conf file replacing the #'s and the *'s with the
-correct IDs.  The IDs can be retrieved from the messages file or
-using "cat /proc/bus/usb/devices".
-
-If the default timeout is too low, i.e. there are frequent "timeout" messages,
-you may want to increase the timeout manually by using the parameter
-"read_timeout".  The time is given in seconds.  This is an example for
-modprobe.conf with a timeout of 60 seconds:
-
-  options scanner read_timeout=60
- 
-If the "scanner" module is already loaded into memory, it must be reloaded for
-the module parameters to take effect.  In essence, "rmmod scanner; modprobe
-scanner" must be performed.
-
-
-BUGS
-
-Just look at the list of fixes in the source files. 
-
-
-CONTACT
-
-For asking about problems and fixes, use the linux-usb-users mailing list. For
-patches, linux-usb-devel should be used. Information on both lists can be
-found on http://www.linux-usb.org/.
-
-
-CHANGES
-
-- Amended for linux-2.5.54
-- Added information about read_timeout
-- Added more details about /proc/bus/usb/devices
-- Added/updated links
-- Added pointers two "special" scanner drivers
-- Reordering, spell-checking, formatting
-- Used /dev/usb/scanner[0-15] instead of /dev/usbscanner[0-15]
-- Removed some basic USB configuration stuff
-- Added EHCI
-- Removed some more references to HP
-- Amended for linux-2.4.12
-- Updated devfs support
-- Amended for linux-2.3.99-pre6-3
-- Appended hp_scan.c to end of this README
-- Removed most references to HP
-- Updated uhci/ohci host controller info
-- Updated support for multiple scanner support
-- Updated supported scanners list
-- Updated usbdevfs info
-- Spellcheck
-
-
-HP TEST PROGRAM
-
-There is a small test program (hp_scan.c -- appended below) that can
-be used to test the scanner device if it's an HP scanner that supports
-SCL (Scanner Control Language).  Known HP scanner that support SCL are
-the 4100, 5200, 6200, the 6300 -- note that the 4200 is *not*
-supported since it does not understand SCL; it's also strongly
-suspected that the 3300 and the PhotoSmart S20 are not SCL compliant.
-Hp_scan.c's purpose is to test the driver without having to
-retrieve/configure SANE.  Hp_scan.c will scan the entire bed and put
-the output into a file called "out.dat" in the current directory.  The
-data in the file is raw data so it's not very useful for imaging.
-
---------------- snip -- hp_scan.c -- snip ---------------
-/*
-
-This is a really crude attempt at writing a short test program.  It's
-mostly only to be used to test connectivity with USB HP scanners that
-understand SCL.  Currently, the supported models are 4100C, 5200C,
-6200C, and the 6300C.  Note that the 4200C is *NOT* acceptable.
-
-Copyright (C) David E. Nelson <dnelson@jump.net>, 1999
-
-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 <stdio.h>
-#include <stdlib.h>
-#include <error.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-/*
-   Gray Output produces about a 8945400 byte file.
-   Color Output produces a 26836200 byte file. 
-   
-   To compile: gcc -o hp_scan hp_scan.c
-*/
-
-// #define COLOR /* Undef to scan GrayScale */
-
-int send_cmd(int, const char *, int);
-int read_cmd(int, char *, int);
-
-int
-main(void) {
-
-	ssize_t cnt = 0, total_cnt = 0;
-
-	FILE *fpout;
-
-	int fp;
-	int data_size = 32768;
-
-	char *data;
-
-	static char reset_cmd[] = {'\x1b','E'};
-
-#ifdef COLOR
-	static char data_type_cmd[] = {'\x1b','*','a','5','T'}; /* Color */
-	static char data_width_cmd[] = {'\x1b','*','a','2','4','G'}; /* 24 Bit Color */
-#else
-	static char data_type_cmd[] = {'\x1b','*','a','4','T'}; /* Gray */
-	static char data_width_cmd[] = {'\x1b','*','a','8','G'}; /* 8 Bit Gray */
-#endif
-
-	static char query_cmd[] = {'\x1b', '*', 's', '2', '5', '7', 'E'};
-	static char start_scan_cmd[] = {'\x1b','*','f','0','S'};
-	
-	if(!(data=malloc(data_size))) {
-		perror("malloc failed");
-		exit (1);
-	}
-	
-	if((fp=open("/dev/usb/scanner0", O_RDWR)) < 0) {
-		perror("Unable to open scanner device");
-		exit (1);
-	}
-
-	if((fpout=fopen("out.dat", "w+")) == NULL) {
-		perror("Unable to open output file");
-		exit(1);
-	}
-
-	send_cmd(fp, reset_cmd, sizeof(reset_cmd));
-	send_cmd(fp, data_type_cmd, sizeof(data_type_cmd));
-	send_cmd(fp, data_width_cmd, sizeof(data_width_cmd));
-	send_cmd(fp, start_scan_cmd, sizeof(start_scan_cmd));
-
-	while ((cnt = read(fp, data, data_size)) > 0) {
-		printf("Read: %u\n", cnt); 
-		if(fwrite(data, sizeof(char), cnt, fpout) < 0) {
-			perror("Write to output file failed");
-			exit (1);
-		}
-		total_cnt += cnt;
-	}
-	if (cnt < 0) {
-		perror("Read from scanner failed");
-		exit (1);
-	}
-
-	printf("\nRead %lu bytes.\n", total_cnt);
-
-	send_cmd(fp, reset_cmd, sizeof(reset_cmd));
-
-	close(fp);
-	fclose(fpout);
-	return (0);
-}
-
-int
-send_cmd(int fp, const char * cmd, int length) {
-
-	int result;
-	int x;
-
-	if((result = write(fp, cmd, length)) != length) {
-		printf ("Write warning: %d bytes requested, %d written\n");
-	} else if (result < 0) {
-		perror ("send_cmd failure");
-		exit (1);
-	}
-	return (result);
-}
-	
-int
-read_cmd(int fp, char * response, int length) {
-
-	return read(fp, response, length);
-
-}
--- diff/arch/i386/lib/iodebug.c	2002-10-16 04:29:02.000000000 +0100
+++ source/arch/i386/lib/iodebug.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,11 +0,0 @@
-#include <asm/io.h>
-
-void * __io_virt_debug(unsigned long x, const char *file, int line)
-{
-	if (x < PAGE_OFFSET) {
-		printk("io mapaddr 0x%05lx not valid at %s:%d!\n", x, file, line);
-		return __va(x);
-	}
-	return (void *)x;
-}
-
--- diff/arch/x86_64/lib/iodebug.c	2002-10-16 04:28:24.000000000 +0100
+++ source/arch/x86_64/lib/iodebug.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,11 +0,0 @@
-#include <asm/io.h>
-
-void * __io_virt_debug(unsigned long x, const char *file, int line)
-{
-	if (x < PAGE_OFFSET) {
-		printk("io mapaddr 0x%05lx not valid at %s:%d!\n", x, file, line);
-		return __va(x);
-	}
-	return (void *)x;
-}
-
--- diff/drivers/char/ipmi/ipmi_kcs_intf.c	2004-03-04 11:41:46.000000000 +0000
+++ source/drivers/char/ipmi/ipmi_kcs_intf.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,1305 +0,0 @@
-/*
- * ipmi_kcs_intf.c
- *
- * The interface to the IPMI driver for the KCS.
- *
- * Author: MontaVista Software, Inc.
- *         Corey Minyard <minyard@mvista.com>
- *         source@mvista.com
- *
- * Copyright 2002 MontaVista Software Inc.
- *
- *  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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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 holds the "policy" for the interface to the KCS state
- * machine.  It does the configuration, handles timers and interrupts,
- * and drives the real KCS state machine.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <asm/system.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/list.h>
-#include <linux/ioport.h>
-#ifdef CONFIG_HIGH_RES_TIMERS
-#include <linux/hrtime.h>
-#endif
-#include <linux/interrupt.h>
-#include <linux/rcupdate.h>
-#include <linux/ipmi_smi.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include "ipmi_kcs_sm.h"
-#include <linux/init.h>
-
-/* Measure times between events in the driver. */
-#undef DEBUG_TIMING
-
-/* Timing parameters.  Call every 10 ms when not doing anything,
-   otherwise call every KCS_SHORT_TIMEOUT_USEC microseconds. */
-#define KCS_TIMEOUT_TIME_USEC	10000
-#define KCS_USEC_PER_JIFFY	(1000000/HZ)
-#define KCS_TIMEOUT_JIFFIES	(KCS_TIMEOUT_TIME_USEC/KCS_USEC_PER_JIFFY)
-#define KCS_SHORT_TIMEOUT_USEC  250 /* .25ms when the SM request a
-                                       short timeout */
-
-#ifdef CONFIG_IPMI_KCS
-/* This forces a dependency to the config file for this option. */
-#endif
-
-enum kcs_intf_state {
-	KCS_NORMAL,
-	KCS_GETTING_FLAGS,
-	KCS_GETTING_EVENTS,
-	KCS_CLEARING_FLAGS,
-	KCS_CLEARING_FLAGS_THEN_SET_IRQ,
-	KCS_GETTING_MESSAGES,
-	KCS_ENABLE_INTERRUPTS1,
-	KCS_ENABLE_INTERRUPTS2
-	/* FIXME - add watchdog stuff. */
-};
-
-struct kcs_info
-{
-	ipmi_smi_t          intf;
-	struct kcs_data     *kcs_sm;
-	spinlock_t          kcs_lock;
-	spinlock_t          msg_lock;
-	struct list_head    xmit_msgs;
-	struct list_head    hp_xmit_msgs;
-	struct ipmi_smi_msg *curr_msg;
-	enum kcs_intf_state kcs_state;
-
-	/* Flags from the last GET_MSG_FLAGS command, used when an ATTN
-	   is set to hold the flags until we are done handling everything
-	   from the flags. */
-#define RECEIVE_MSG_AVAIL	0x01
-#define EVENT_MSG_BUFFER_FULL	0x02
-#define WDT_PRE_TIMEOUT_INT	0x08
-	unsigned char       msg_flags;
-
-	/* If set to true, this will request events the next time the
-	   state machine is idle. */
-	atomic_t            req_events;
-
-	/* If true, run the state machine to completion on every send
-	   call.  Generally used after a panic to make sure stuff goes
-	   out. */
-	int                 run_to_completion;
-
-	/* The I/O port of a KCS interface. */
-	int                 port;
-
-	/* zero if no irq; */
-	int                 irq;
-
-	/* The physical and remapped memory addresses of a KCS interface. */
-	unsigned long	    physaddr;
-	unsigned char	    *addr;
-
-	/* The timer for this kcs. */
-	struct timer_list   kcs_timer;
-
-	/* The time (in jiffies) the last timeout occurred at. */
-	unsigned long       last_timeout_jiffies;
-
-	/* Used to gracefully stop the timer without race conditions. */
-	volatile int        stop_operation;
-	volatile int        timer_stopped;
-
-	/* The driver will disable interrupts when it gets into a
-	   situation where it cannot handle messages due to lack of
-	   memory.  Once that situation clears up, it will re-enable
-	   interrupts. */
-	int                 interrupt_disabled;
-};
-
-static void kcs_restart_short_timer(struct kcs_info *kcs_info);
-
-static void deliver_recv_msg(struct kcs_info *kcs_info, struct ipmi_smi_msg *msg)
-{
-	/* Deliver the message to the upper layer with the lock
-           released. */
-	spin_unlock(&(kcs_info->kcs_lock));
-	ipmi_smi_msg_received(kcs_info->intf, msg);
-	spin_lock(&(kcs_info->kcs_lock));
-}
-
-static void return_hosed_msg(struct kcs_info *kcs_info)
-{
-	struct ipmi_smi_msg *msg = kcs_info->curr_msg;
-
-	/* Make it a reponse */
-	msg->rsp[0] = msg->data[0] | 4;
-	msg->rsp[1] = msg->data[1];
-	msg->rsp[2] = 0xFF; /* Unknown error. */
-	msg->rsp_size = 3;
-			
-	kcs_info->curr_msg = NULL;
-	deliver_recv_msg(kcs_info, msg);
-}
-
-static enum kcs_result start_next_msg(struct kcs_info *kcs_info)
-{
-	int              rv;
-	struct list_head *entry = NULL;
-#ifdef DEBUG_TIMING
-	struct timeval t;
-#endif
-
-	/* No need to save flags, we aleady have interrupts off and we
-	   already hold the KCS lock. */
-	spin_lock(&(kcs_info->msg_lock));
-	
-	/* Pick the high priority queue first. */
-	if (! list_empty(&(kcs_info->hp_xmit_msgs))) {
-		entry = kcs_info->hp_xmit_msgs.next;
-	} else if (! list_empty(&(kcs_info->xmit_msgs))) {
-		entry = kcs_info->xmit_msgs.next;
-	}
-
-	if (!entry) {
-		kcs_info->curr_msg = NULL;
-		rv = KCS_SM_IDLE;
-	} else {
-		int err;
-
-		list_del(entry);
-		kcs_info->curr_msg = list_entry(entry,
-						struct ipmi_smi_msg,
-						link);
-#ifdef DEBUG_TIMING
-		do_gettimeofday(&t);
-		printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec);
-#endif
-		err = start_kcs_transaction(kcs_info->kcs_sm,
-					   kcs_info->curr_msg->data,
-					   kcs_info->curr_msg->data_size);
-		if (err) {
-			return_hosed_msg(kcs_info);
-		}
-
-		rv = KCS_CALL_WITHOUT_DELAY;
-	}
-	spin_unlock(&(kcs_info->msg_lock));
-
-	return rv;
-}
-
-static void start_enable_irq(struct kcs_info *kcs_info)
-{
-	unsigned char msg[2];
-
-	/* If we are enabling interrupts, we have to tell the
-	   BMC to use them. */
-	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
-	msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
-
-	start_kcs_transaction(kcs_info->kcs_sm, msg, 2);
-	kcs_info->kcs_state = KCS_ENABLE_INTERRUPTS1;
-}
-
-static void start_clear_flags(struct kcs_info *kcs_info)
-{
-	unsigned char msg[3];
-
-	/* Make sure the watchdog pre-timeout flag is not set at startup. */
-	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
-	msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
-	msg[2] = WDT_PRE_TIMEOUT_INT;
-
-	start_kcs_transaction(kcs_info->kcs_sm, msg, 3);
-	kcs_info->kcs_state = KCS_CLEARING_FLAGS;
-}
-
-/* When we have a situtaion where we run out of memory and cannot
-   allocate messages, we just leave them in the BMC and run the system
-   polled until we can allocate some memory.  Once we have some
-   memory, we will re-enable the interrupt. */
-static inline void disable_kcs_irq(struct kcs_info *kcs_info)
-{
-	if ((kcs_info->irq) && (!kcs_info->interrupt_disabled)) {
-		disable_irq_nosync(kcs_info->irq);
-		kcs_info->interrupt_disabled = 1;
-	}
-}
-
-static inline void enable_kcs_irq(struct kcs_info *kcs_info)
-{
-	if ((kcs_info->irq) && (kcs_info->interrupt_disabled)) {
-		enable_irq(kcs_info->irq);
-		kcs_info->interrupt_disabled = 0;
-	}
-}
-
-static void handle_flags(struct kcs_info *kcs_info)
-{
-	if (kcs_info->msg_flags & WDT_PRE_TIMEOUT_INT) {
-		/* Watchdog pre-timeout */
-		start_clear_flags(kcs_info);
-		kcs_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
-		spin_unlock(&(kcs_info->kcs_lock));
-		ipmi_smi_watchdog_pretimeout(kcs_info->intf);
-		spin_lock(&(kcs_info->kcs_lock));
-	} else if (kcs_info->msg_flags & RECEIVE_MSG_AVAIL) {
-		/* Messages available. */
-		kcs_info->curr_msg = ipmi_alloc_smi_msg();
-		if (!kcs_info->curr_msg) {
-			disable_kcs_irq(kcs_info);
-			kcs_info->kcs_state = KCS_NORMAL;
-			return;
-		}
-		enable_kcs_irq(kcs_info);
-
-		kcs_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
-		kcs_info->curr_msg->data[1] = IPMI_GET_MSG_CMD;
-		kcs_info->curr_msg->data_size = 2;
-
-		start_kcs_transaction(kcs_info->kcs_sm,
-				      kcs_info->curr_msg->data,
-				      kcs_info->curr_msg->data_size);
-		kcs_info->kcs_state = KCS_GETTING_MESSAGES;
-	} else if (kcs_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
-		/* Events available. */
-		kcs_info->curr_msg = ipmi_alloc_smi_msg();
-		if (!kcs_info->curr_msg) {
-			disable_kcs_irq(kcs_info);
-			kcs_info->kcs_state = KCS_NORMAL;
-			return;
-		}
-		enable_kcs_irq(kcs_info);
-
-		kcs_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
-		kcs_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
-		kcs_info->curr_msg->data_size = 2;
-
-		start_kcs_transaction(kcs_info->kcs_sm,
-				      kcs_info->curr_msg->data,
-				      kcs_info->curr_msg->data_size);
-		kcs_info->kcs_state = KCS_GETTING_EVENTS;
-	} else {
-		kcs_info->kcs_state = KCS_NORMAL;
-	}
-}
-
-static void handle_transaction_done(struct kcs_info *kcs_info)
-{
-	struct ipmi_smi_msg *msg;
-#ifdef DEBUG_TIMING
-	struct timeval t;
-
-	do_gettimeofday(&t);
-	printk("**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec);
-#endif
-	switch (kcs_info->kcs_state) {
-	case KCS_NORMAL:
-		if (!kcs_info->curr_msg)
-			break;
-			
-		kcs_info->curr_msg->rsp_size
-			= kcs_get_result(kcs_info->kcs_sm,
-					 kcs_info->curr_msg->rsp,
-					 IPMI_MAX_MSG_LENGTH);
-		
-		/* Do this here becase deliver_recv_msg() releases the
-		   lock, and a new message can be put in during the
-		   time the lock is released. */
-		msg = kcs_info->curr_msg;
-		kcs_info->curr_msg = NULL;
-		deliver_recv_msg(kcs_info, msg);
-		break;
-		
-	case KCS_GETTING_FLAGS:
-	{
-		unsigned char msg[4];
-		unsigned int  len;
-
-		/* We got the flags from the KCS, now handle them. */
-		len = kcs_get_result(kcs_info->kcs_sm, msg, 4);
-		if (msg[2] != 0) {
-			/* Error fetching flags, just give up for
-			   now. */
-			kcs_info->kcs_state = KCS_NORMAL;
-		} else if (len < 3) {
-			/* Hmm, no flags.  That's technically illegal, but
-			   don't use uninitialized data. */
-			kcs_info->kcs_state = KCS_NORMAL;
-		} else {
-			kcs_info->msg_flags = msg[3];
-			handle_flags(kcs_info);
-		}
-		break;
-	}
-
-	case KCS_CLEARING_FLAGS:
-	case KCS_CLEARING_FLAGS_THEN_SET_IRQ:
-	{
-		unsigned char msg[3];
-
-		/* We cleared the flags. */
-		kcs_get_result(kcs_info->kcs_sm, msg, 3);
-		if (msg[2] != 0) {
-			/* Error clearing flags */
-			printk(KERN_WARNING
-			       "ipmi_kcs: Error clearing flags: %2.2x\n",
-			       msg[2]);
-		}
-		if (kcs_info->kcs_state == KCS_CLEARING_FLAGS_THEN_SET_IRQ)
-			start_enable_irq(kcs_info);
-		else
-			kcs_info->kcs_state = KCS_NORMAL;
-		break;
-	}
-
-	case KCS_GETTING_EVENTS:
-	{
-		kcs_info->curr_msg->rsp_size
-			= kcs_get_result(kcs_info->kcs_sm,
-					 kcs_info->curr_msg->rsp,
-					 IPMI_MAX_MSG_LENGTH);
-
-		/* Do this here becase deliver_recv_msg() releases the
-		   lock, and a new message can be put in during the
-		   time the lock is released. */
-		msg = kcs_info->curr_msg;
-		kcs_info->curr_msg = NULL;
-		if (msg->rsp[2] != 0) {
-			/* Error getting event, probably done. */
-			msg->done(msg);
-
-			/* Take off the event flag. */
-			kcs_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
-		} else {
-			deliver_recv_msg(kcs_info, msg);
-		}
-		handle_flags(kcs_info);
-		break;
-	}
-
-	case KCS_GETTING_MESSAGES:
-	{
-		kcs_info->curr_msg->rsp_size
-			= kcs_get_result(kcs_info->kcs_sm,
-					 kcs_info->curr_msg->rsp,
-					 IPMI_MAX_MSG_LENGTH);
-
-		/* Do this here becase deliver_recv_msg() releases the
-		   lock, and a new message can be put in during the
-		   time the lock is released. */
-		msg = kcs_info->curr_msg;
-		kcs_info->curr_msg = NULL;
-		if (msg->rsp[2] != 0) {
-			/* Error getting event, probably done. */
-			msg->done(msg);
-
-			/* Take off the msg flag. */
-			kcs_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
-		} else {
-			deliver_recv_msg(kcs_info, msg);
-		}
-		handle_flags(kcs_info);
-		break;
-	}
-
-	case KCS_ENABLE_INTERRUPTS1:
-	{
-		unsigned char msg[4];
-
-		/* We got the flags from the KCS, now handle them. */
-		kcs_get_result(kcs_info->kcs_sm, msg, 4);
-		if (msg[2] != 0) {
-			printk(KERN_WARNING
-			       "ipmi_kcs: Could not enable interrupts"
-			       ", failed get, using polled mode.\n");
-			kcs_info->kcs_state = KCS_NORMAL;
-		} else {
-			msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
-			msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
-			msg[2] = msg[3] | 1; /* enable msg queue int */
-			start_kcs_transaction(kcs_info->kcs_sm, msg,3);
-			kcs_info->kcs_state = KCS_ENABLE_INTERRUPTS2;
-		}
-		break;
-	}
-
-	case KCS_ENABLE_INTERRUPTS2:
-	{
-		unsigned char msg[4];
-
-		/* We got the flags from the KCS, now handle them. */
-		kcs_get_result(kcs_info->kcs_sm, msg, 4);
-		if (msg[2] != 0) {
-			printk(KERN_WARNING
-			       "ipmi_kcs: Could not enable interrupts"
-			       ", failed set, using polled mode.\n");
-		}
-		kcs_info->kcs_state = KCS_NORMAL;
-		break;
-	}
-	}
-}
-
-/* Called on timeouts and events.  Timeouts should pass the elapsed
-   time, interrupts should pass in zero. */
-static enum kcs_result kcs_event_handler(struct kcs_info *kcs_info, int time)
-{
-	enum kcs_result kcs_result;
-
- restart:
-	/* There used to be a loop here that waited a little while
-	   (around 25us) before giving up.  That turned out to be
-	   pointless, the minimum delays I was seeing were in the 300us
-	   range, which is far too long to wait in an interrupt.  So
-	   we just run until the state machine tells us something
-	   happened or it needs a delay. */
-	kcs_result = kcs_event(kcs_info->kcs_sm, time);
-	time = 0;
-	while (kcs_result == KCS_CALL_WITHOUT_DELAY)
-	{
-		kcs_result = kcs_event(kcs_info->kcs_sm, 0);
-	}
-
-	if (kcs_result == KCS_TRANSACTION_COMPLETE)
-	{
-		handle_transaction_done(kcs_info);
-		kcs_result = kcs_event(kcs_info->kcs_sm, 0);
-	}
-	else if (kcs_result == KCS_SM_HOSED)
-	{
-		if (kcs_info->curr_msg != NULL) {
-			/* If we were handling a user message, format
-                           a response to send to the upper layer to
-                           tell it about the error. */
-			return_hosed_msg(kcs_info);
-		}
-		kcs_result = kcs_event(kcs_info->kcs_sm, 0);
-		kcs_info->kcs_state = KCS_NORMAL;
-	}
-
-	/* We prefer handling attn over new messages. */
-	if (kcs_result == KCS_ATTN)
-	{
-		unsigned char msg[2];
-
-		/* Got a attn, send down a get message flags to see
-                   what's causing it.  It would be better to handle
-                   this in the upper layer, but due to the way
-                   interrupts work with the KCS, that's not really
-                   possible. */
-		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
-		msg[1] = IPMI_GET_MSG_FLAGS_CMD;
-
-		start_kcs_transaction(kcs_info->kcs_sm, msg, 2);
-		kcs_info->kcs_state = KCS_GETTING_FLAGS;
-		goto restart;
-	}
-
-	/* If we are currently idle, try to start the next message. */
-	if (kcs_result == KCS_SM_IDLE) {
-		kcs_result = start_next_msg(kcs_info);
-		if (kcs_result != KCS_SM_IDLE)
-			goto restart;
-        }
-
-	if ((kcs_result == KCS_SM_IDLE)
-	    && (atomic_read(&kcs_info->req_events)))
-	{
-		/* We are idle and the upper layer requested that I fetch
-		   events, so do so. */
-		unsigned char msg[2];
-
-		atomic_set(&kcs_info->req_events, 0);
-		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
-		msg[1] = IPMI_GET_MSG_FLAGS_CMD;
-
-		start_kcs_transaction(kcs_info->kcs_sm, msg, 2);
-		kcs_info->kcs_state = KCS_GETTING_FLAGS;
-		goto restart;
-	}
-
-	return kcs_result;
-}
-
-static void sender(void                *send_info,
-		   struct ipmi_smi_msg *msg,
-		   int                 priority)
-{
-	struct kcs_info *kcs_info = (struct kcs_info *) send_info;
-	enum kcs_result result;
-	unsigned long   flags;
-#ifdef DEBUG_TIMING
-	struct timeval t;
-#endif
-
-	spin_lock_irqsave(&(kcs_info->msg_lock), flags);
-#ifdef DEBUG_TIMING
-	do_gettimeofday(&t);
-	printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
-#endif
-
-	if (kcs_info->run_to_completion) {
-		/* If we are running to completion, then throw it in
-		   the list and run transactions until everything is
-		   clear.  Priority doesn't matter here. */
-		list_add_tail(&(msg->link), &(kcs_info->xmit_msgs));
-
-		/* We have to release the msg lock and claim the kcs
-		   lock in this case, because of race conditions. */
-		spin_unlock_irqrestore(&(kcs_info->msg_lock), flags);
-
-		spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
-		result = kcs_event_handler(kcs_info, 0);
-		while (result != KCS_SM_IDLE) {
-			udelay(KCS_SHORT_TIMEOUT_USEC);
-			result = kcs_event_handler(kcs_info,
-						   KCS_SHORT_TIMEOUT_USEC);
-		}
-		spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
-		return;
-	} else {
-		if (priority > 0) {
-			list_add_tail(&(msg->link), &(kcs_info->hp_xmit_msgs));
-		} else {
-			list_add_tail(&(msg->link), &(kcs_info->xmit_msgs));
-		}
-	}
-	spin_unlock_irqrestore(&(kcs_info->msg_lock), flags);
-
-	spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
-	if ((kcs_info->kcs_state == KCS_NORMAL)
-	    && (kcs_info->curr_msg == NULL))
-	{
-		start_next_msg(kcs_info);
-		kcs_restart_short_timer(kcs_info);
-	}
-	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
-}
-
-static void set_run_to_completion(void *send_info, int i_run_to_completion)
-{
-	struct kcs_info *kcs_info = (struct kcs_info *) send_info;
-	enum kcs_result result;
-	unsigned long   flags;
-
-	spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
-
-	kcs_info->run_to_completion = i_run_to_completion;
-	if (i_run_to_completion) {
-		result = kcs_event_handler(kcs_info, 0);
-		while (result != KCS_SM_IDLE) {
-			udelay(KCS_SHORT_TIMEOUT_USEC);
-			result = kcs_event_handler(kcs_info,
-						   KCS_SHORT_TIMEOUT_USEC);
-		}
-	}
-
-	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
-}
-
-static void request_events(void *send_info)
-{
-	struct kcs_info *kcs_info = (struct kcs_info *) send_info;
-
-	atomic_set(&kcs_info->req_events, 1);
-}
-
-static int initialized = 0;
-
-/* Must be called with interrupts off and with the kcs_lock held. */
-static void kcs_restart_short_timer(struct kcs_info *kcs_info)
-{
-	if (del_timer(&(kcs_info->kcs_timer))) {
-#ifdef CONFIG_HIGH_RES_TIMERS
-		unsigned long jiffies_now;
-
-		/* If we don't delete the timer, then it will go off
-		   immediately, anyway.  So we only process if we
-		   actually delete the timer. */
-
-		/* We already have irqsave on, so no need for it
-                   here. */
-		read_lock(&xtime_lock);
-		jiffies_now = jiffies;
-		kcs_info->kcs_timer.expires = jiffies_now;
-
-		kcs_info->kcs_timer.sub_expires
-			= quick_update_jiffies_sub(jiffies_now);
-		read_unlock(&xtime_lock);
-
-		kcs_info->kcs_timer.sub_expires
-			+= usec_to_arch_cycles(KCS_SHORT_TIMEOUT_USEC);
-		while (kcs_info->kcs_timer.sub_expires >= cycles_per_jiffies) {
-			kcs_info->kcs_timer.expires++;
-			kcs_info->kcs_timer.sub_expires -= cycles_per_jiffies;
-		}
-#else
-		kcs_info->kcs_timer.expires = jiffies + 1;
-#endif
-		add_timer(&(kcs_info->kcs_timer));
-	}
-}
-
-static void kcs_timeout(unsigned long data)
-{
-	struct kcs_info *kcs_info = (struct kcs_info *) data;
-	enum kcs_result kcs_result;
-	unsigned long   flags;
-	unsigned long   jiffies_now;
-	unsigned long   time_diff;
-#ifdef DEBUG_TIMING
-	struct timeval t;
-#endif
-
-	if (kcs_info->stop_operation) {
-		kcs_info->timer_stopped = 1;
-		return;
-	}
-
-	spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
-#ifdef DEBUG_TIMING
-	do_gettimeofday(&t);
-	printk("**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec);
-#endif
-	jiffies_now = jiffies;
-
-	time_diff = ((jiffies_now - kcs_info->last_timeout_jiffies)
-		     * KCS_USEC_PER_JIFFY);
-	kcs_result = kcs_event_handler(kcs_info, time_diff);
-
-	kcs_info->last_timeout_jiffies = jiffies_now;
-
-	if ((kcs_info->irq) && (! kcs_info->interrupt_disabled)) {
-		/* Running with interrupts, only do long timeouts. */
-		kcs_info->kcs_timer.expires = jiffies + KCS_TIMEOUT_JIFFIES;
-		goto do_add_timer;
-	}
-
-	/* If the state machine asks for a short delay, then shorten
-           the timer timeout. */
-#ifdef CONFIG_HIGH_RES_TIMERS
-	if (kcs_result == KCS_CALL_WITH_DELAY) {
-		kcs_info->kcs_timer.sub_expires
-			+= usec_to_arch_cycles(KCS_SHORT_TIMEOUT_USEC);
-		while (kcs_info->kcs_timer.sub_expires >= cycles_per_jiffies) {
-			kcs_info->kcs_timer.expires++;
-			kcs_info->kcs_timer.sub_expires -= cycles_per_jiffies;
-		}
-	} else {
-		kcs_info->kcs_timer.expires = jiffies + KCS_TIMEOUT_JIFFIES;
-		kcs_info->kcs_timer.sub_expires = 0;
-	}
-#else
-	/* If requested, take the shortest delay possible */
-	if (kcs_result == KCS_CALL_WITH_DELAY) {
-		kcs_info->kcs_timer.expires = jiffies + 1;
-	} else {
-		kcs_info->kcs_timer.expires = jiffies + KCS_TIMEOUT_JIFFIES;
-	}
-#endif
-
- do_add_timer:
-	add_timer(&(kcs_info->kcs_timer));
-	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
-}
-
-static irqreturn_t kcs_irq_handler(int irq, void *data, struct pt_regs *regs)
-{
-	struct kcs_info *kcs_info = (struct kcs_info *) data;
-	unsigned long   flags;
-#ifdef DEBUG_TIMING
-	struct timeval t;
-#endif
-
-	spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
-	if (kcs_info->stop_operation)
-		goto out;
-
-#ifdef DEBUG_TIMING
-	do_gettimeofday(&t);
-	printk("**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec);
-#endif
-	kcs_event_handler(kcs_info, 0);
- out:
-	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
-	return IRQ_HANDLED;
-}
-
-static struct ipmi_smi_handlers handlers =
-{
-	.owner			= THIS_MODULE,
-	.sender			= sender,
-	.request_events		= request_events,
-	.set_run_to_completion	= set_run_to_completion,
-};
-
-static unsigned char ipmi_kcs_dev_rev;
-static unsigned char ipmi_kcs_fw_rev_major;
-static unsigned char ipmi_kcs_fw_rev_minor;
-static unsigned char ipmi_version_major;
-static unsigned char ipmi_version_minor;
-
-extern int kcs_dbg;
-static int ipmi_kcs_detect_hardware(unsigned int port,
-				    unsigned char *addr,
-				    struct kcs_data *data)
-{
-	unsigned char   msg[2];
-	unsigned char   resp[IPMI_MAX_MSG_LENGTH];
-	unsigned long   resp_len;
-	enum kcs_result kcs_result;
-
-	/* It's impossible for the KCS status register to be all 1's,
-	   (assuming a properly functioning, self-initialized BMC)
-	   but that's what you get from reading a bogus address, so we
-	   test that first. */
-
-	if (port) {
-		if (inb(port+1) == 0xff) return -ENODEV; 
-	} else { 
-		if (readb(addr+1) == 0xff) return -ENODEV; 
-	}
-
-	/* Do a Get Device ID command, since it comes back with some
-	   useful info. */
-	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
-	msg[1] = IPMI_GET_DEVICE_ID_CMD;
-	start_kcs_transaction(data, msg, 2);
-	
-	kcs_result = kcs_event(data, 0);
-	for (;;)
-	{
-		if (kcs_result == KCS_CALL_WITH_DELAY) {
-			udelay(100);
-			kcs_result = kcs_event(data, 100);
-		}
-		else if (kcs_result == KCS_CALL_WITHOUT_DELAY)
-		{
-			kcs_result = kcs_event(data, 0);
-		}
-		else
-			break;
-	}
-	if (kcs_result == KCS_SM_HOSED) {
-		/* We couldn't get the state machine to run, so whatever's at
-		   the port is probably not an IPMI KCS interface. */
-		return -ENODEV;
-	}
-	/* Otherwise, we got some data. */
-	resp_len = kcs_get_result(data, resp, IPMI_MAX_MSG_LENGTH);
-	if (resp_len < 6)
-		/* That's odd, it should be longer. */
-		return -EINVAL;
-	
-	if ((resp[1] != IPMI_GET_DEVICE_ID_CMD) || (resp[2] != 0))
-		/* That's odd, it shouldn't be able to fail. */
-		return -EINVAL;
-	
-	ipmi_kcs_dev_rev = resp[4] & 0xf;
-	ipmi_kcs_fw_rev_major = resp[5] & 0x7f;
-	ipmi_kcs_fw_rev_minor = resp[6];
-	ipmi_version_major = resp[7] & 0xf;
-	ipmi_version_minor = resp[7] >> 4;
-
-	return 0;
-}
-
-/* There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
-   a default IO port, and 1 ACPI/SPMI address.  That sets KCS_MAX_DRIVERS */
-
-#define KCS_MAX_PARMS 4
-#define KCS_MAX_DRIVERS ((KCS_MAX_PARMS * 2) + 2)
-static struct kcs_info *kcs_infos[KCS_MAX_DRIVERS] =
-{ NULL, NULL, NULL, NULL };
-
-#define DEVICE_NAME "ipmi_kcs"
-
-#define DEFAULT_IO_PORT 0xca2
-
-static int kcs_trydefaults = 1;
-static unsigned long kcs_addrs[KCS_MAX_PARMS] = { 0, 0, 0, 0 };
-static int kcs_ports[KCS_MAX_PARMS] = { 0, 0, 0, 0 };
-static int kcs_irqs[KCS_MAX_PARMS] = { 0, 0, 0, 0 };
-
-MODULE_PARM(kcs_trydefaults, "i");
-MODULE_PARM(kcs_addrs, "1-4l");
-MODULE_PARM(kcs_irqs, "1-4i");
-MODULE_PARM(kcs_ports, "1-4i");
-
-/* Returns 0 if initialized, or negative on an error. */
-static int init_one_kcs(int kcs_port, 
-			int irq, 
-			unsigned long kcs_physaddr,
-			struct kcs_info **kcs)
-{
-	int		rv;
-	struct kcs_info *new_kcs;
-
-	/* Did anything get passed in at all?  Both == zero disables the
-	   driver. */
-
-	if (!(kcs_port || kcs_physaddr)) 
-		return -ENODEV;
-	
-	/* Only initialize a port OR a physical address on this call.
-	   Also, IRQs can go with either ports or addresses. */
-
-	if (kcs_port && kcs_physaddr)
-		return -EINVAL;
-
-	new_kcs = kmalloc(sizeof(*new_kcs), GFP_KERNEL);
-	if (!new_kcs) {
-		printk(KERN_ERR "ipmi_kcs: out of memory\n");
-		return -ENOMEM;
-	}
-
-	/* So we know not to free it unless we have allocated one. */
-	new_kcs->kcs_sm = NULL;
-
-	new_kcs->addr = NULL;
-	new_kcs->physaddr = kcs_physaddr;
-	new_kcs->port = kcs_port;
-
-	if (kcs_port) {
-		if (request_region(kcs_port, 2, DEVICE_NAME) == NULL) {
-			kfree(new_kcs);
-			printk(KERN_ERR 
-			       "ipmi_kcs: can't reserve port @ 0x%4.4x\n",
-		       	       kcs_port);
-			return -EIO;
-		}
-	} else {
-		if (request_mem_region(kcs_physaddr, 2, DEVICE_NAME) == NULL) {
-			kfree(new_kcs);
-			printk(KERN_ERR 
-			       "ipmi_kcs: can't reserve memory @ 0x%lx\n",
-		       	       kcs_physaddr);
-			return -EIO;
-		}
-		if ((new_kcs->addr = ioremap(kcs_physaddr, 2)) == NULL) {
-			kfree(new_kcs);
-			printk(KERN_ERR 
-			       "ipmi_kcs: can't remap memory at 0x%lx\n",
-		       	       kcs_physaddr);
-			return -EIO;
-		}
-	}
-
-	new_kcs->kcs_sm = kmalloc(kcs_size(), GFP_KERNEL);
-	if (!new_kcs->kcs_sm) {
-		printk(KERN_ERR "ipmi_kcs: out of memory\n");
-		rv = -ENOMEM;
-		goto out_err;
-	}
-	init_kcs_data(new_kcs->kcs_sm, kcs_port, new_kcs->addr);
-	spin_lock_init(&(new_kcs->kcs_lock));
-	spin_lock_init(&(new_kcs->msg_lock));
-
-	rv = ipmi_kcs_detect_hardware(kcs_port, new_kcs->addr, new_kcs->kcs_sm);
-	if (rv) {
-		if (kcs_port) 
-			printk(KERN_ERR 
-			       "ipmi_kcs: No KCS @ port 0x%4.4x\n", 
-			       kcs_port);
-		else
-			printk(KERN_ERR 
-			       "ipmi_kcs: No KCS @ addr 0x%lx\n", 
-			       kcs_physaddr);
-		goto out_err;
-	}
-
-	if (irq != 0) {
-		rv = request_irq(irq,
-				 kcs_irq_handler,
-				 SA_INTERRUPT,
-				 DEVICE_NAME,
-				 new_kcs);
-		if (rv) {
-			printk(KERN_WARNING
-			       "ipmi_kcs: %s unable to claim interrupt %d,"
-			       " running polled\n",
-			       DEVICE_NAME, irq);
-			irq = 0;
-		}
-	}
-	new_kcs->irq = irq;
-
-	INIT_LIST_HEAD(&(new_kcs->xmit_msgs));
-	INIT_LIST_HEAD(&(new_kcs->hp_xmit_msgs));
-	new_kcs->curr_msg = NULL;
-	atomic_set(&new_kcs->req_events, 0);
-	new_kcs->run_to_completion = 0;
-
-	start_clear_flags(new_kcs);
-
-	if (irq) {
-		new_kcs->kcs_state = KCS_CLEARING_FLAGS_THEN_SET_IRQ;
-
-		printk(KERN_INFO 
-		       "ipmi_kcs: Acquiring BMC @ port=0x%x irq=%d\n",
-		       kcs_port, irq);
-
-	} else {
-		if (kcs_port)
-			printk(KERN_INFO 
-			       "ipmi_kcs: Acquiring BMC @ port=0x%x\n",
-		       	       kcs_port);
-		else
-			printk(KERN_INFO 
-			       "ipmi_kcs: Acquiring BMC @ addr=0x%lx\n",
-		       	       kcs_physaddr);
-	}
-
-	rv = ipmi_register_smi(&handlers,
-			       new_kcs,
-			       ipmi_version_major,
-			       ipmi_version_minor,
-			       &(new_kcs->intf));
-	if (rv) {
-		free_irq(irq, new_kcs);
-		printk(KERN_ERR 
-		       "ipmi_kcs: Unable to register device: error %d\n",
-		       rv);
-		goto out_err;
-	}
-
-	new_kcs->interrupt_disabled = 0;
-	new_kcs->timer_stopped = 0;
-	new_kcs->stop_operation = 0;
-
-	init_timer(&(new_kcs->kcs_timer));
-	new_kcs->kcs_timer.data = (long) new_kcs;
-	new_kcs->kcs_timer.function = kcs_timeout;
-	new_kcs->last_timeout_jiffies = jiffies;
-	new_kcs->kcs_timer.expires = jiffies + KCS_TIMEOUT_JIFFIES;
-	add_timer(&(new_kcs->kcs_timer));
-
-	*kcs = new_kcs;
-
-	return 0;
-
- out_err:
-	if (kcs_port) 
-		release_region (kcs_port, 2);
-	if (new_kcs->addr) 
-		iounmap(new_kcs->addr);
-	if (kcs_physaddr) 
-		release_mem_region(kcs_physaddr, 2);
-	if (new_kcs->kcs_sm)
-		kfree(new_kcs->kcs_sm);
-	kfree(new_kcs);
-	return rv;
-}
-
-#ifdef CONFIG_ACPI_INTERPRETER
-
-#include <linux/acpi.h>
-
-struct SPMITable {
-	s8      Signature[4];
-	u32     Length;
-	u8      Revision;
-	u8      Checksum;
-	s8      OEMID[6];
-	s8      OEMTableID[8];
-	s8      OEMRevision[4];
-	s8      CreatorID[4];
-	s8      CreatorRevision[4];
-	u8      InterfaceType[2];
-	s16     SpecificationRevision;
-
-	/*
-	 * Bit 0 - SCI interrupt supported
-	 * Bit 1 - I/O APIC/SAPIC
-	 */
-	u8      InterruptType;
-
-	/* If bit 0 of InterruptType is set, then this is the SCI
-	   interrupt in the GPEx_STS register. */
-	u8      GPE;
-
-	s16     Reserved;
-
-	/* If bit 1 of InterruptType is set, then this is the I/O
-	   APIC/SAPIC interrupt. */
-	u32     GlobalSystemInterrupt;
-
-	/* The actual register address. */
-	struct acpi_generic_address addr;
-
-	u8      UID[4];
-
-	s8      spmi_id[1]; /* A '\0' terminated array starts here. */
-};
-
-static int acpi_find_bmc(unsigned long *physaddr, int *port)
-{
-	acpi_status          status;
-	struct SPMITable     *spmi;
-	
-	status = acpi_get_firmware_table("SPMI", 1,
-					 ACPI_LOGICAL_ADDRESSING,
-					 (struct acpi_table_header **) &spmi);
-	if (status != AE_OK)
-		goto not_found;
-
-	if (spmi->InterfaceType[0] != 1)
-		/* Not IPMI. */
-		goto not_found;
-
-	if (spmi->InterfaceType[1] != 1)
-		/* Not KCS. */
-		goto not_found;
-
-	if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
-		*physaddr = spmi->addr.address;
-		printk("ipmi_kcs_intf: Found ACPI-specified state machine"
-		       " at memory address 0x%lx\n",
-		       (unsigned long) spmi->addr.address);
-	} else if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
-		*port = spmi->addr.address;
-		printk("ipmi_kcs_intf: Found ACPI-specified state machine"
-		       " at I/O address 0x%lx\n",
-		       (unsigned long) spmi->addr.address);
-	} else
-		goto not_found; /* Not an address type we recognise. */
-
-	return 0;
-
- not_found:
-	return -ENODEV;
-}
-#endif
-
-static __init int init_ipmi_kcs(void)
-{
-	int		rv = 0;
-	int		pos = 0;
-	int		i = 0;
-#ifdef CONFIG_ACPI_INTERPRETER
-	unsigned long	physaddr = 0;
-	int             port = 0;
-#endif
-
-	if (initialized)
-		return 0;
-	initialized = 1;
-
-	/* First do the "command-line" parameters */
-
-	for (i=0; i < KCS_MAX_PARMS; i++) {
-		rv = init_one_kcs(kcs_ports[i], 
-				  kcs_irqs[i], 
-				  0, 
-				  &(kcs_infos[pos]));
-		if (rv == 0)
-			pos++;
-
-		rv = init_one_kcs(0, 
-				  kcs_irqs[i], 
-				  kcs_addrs[i], 
-				  &(kcs_infos[pos]));
-		if (rv == 0)
-			pos++;
-	}
-
-	/* Only try the defaults if enabled and resources are available
-	   (because they weren't already specified above). */
-
-	if (kcs_trydefaults && (pos == 0)) {
-		rv = -EINVAL;
-#ifdef CONFIG_ACPI_INTERPRETER
-		if (rv && (physaddr = acpi_find_bmc(&physaddr, &port) == 0)) {
-			rv = init_one_kcs(port, 
-					  0, 
-					  physaddr, 
-					  &(kcs_infos[pos]));
-			if (rv == 0)
-				pos++;
-		}
-#endif
-		if (rv) {
-			rv = init_one_kcs(DEFAULT_IO_PORT, 
-					  0, 
-					  0, 
-					  &(kcs_infos[pos]));
-			if (rv == 0)
-				pos++;
-		}
-	}
-
-	if (kcs_infos[0] == NULL) {
-		printk("ipmi_kcs: Unable to find any KCS interfaces\n");
-		return -ENODEV;
-	} 
-
-	return 0;
-}
-module_init(init_ipmi_kcs);
-
-#ifdef MODULE
-void __exit cleanup_one_kcs(struct kcs_info *to_clean)
-{
-	int           rv;
-	unsigned long flags;
-
-	if (! to_clean)
-		return;
-
-	/* Tell the timer and interrupt handlers that we are shutting
-	   down. */
-	spin_lock_irqsave(&(to_clean->kcs_lock), flags);
-	spin_lock(&(to_clean->msg_lock));
-
-	to_clean->stop_operation = 1;
-
-	if (to_clean->irq != 0)
-		free_irq(to_clean->irq, to_clean);
-	if (to_clean->port) {
-		printk(KERN_INFO 
-		       "ipmi_kcs: Releasing BMC @ port=0x%x\n",
-		       to_clean->port);
-		release_region (to_clean->port, 2);
-	}
-	if (to_clean->addr) {
-		printk(KERN_INFO 
-		       "ipmi_kcs: Releasing BMC @ addr=0x%lx\n",
-		       to_clean->physaddr);
-		iounmap(to_clean->addr);
-		release_mem_region(to_clean->physaddr, 2);
-	}
-
-	spin_unlock(&(to_clean->msg_lock));
-	spin_unlock_irqrestore(&(to_clean->kcs_lock), flags);
-
-	/* Wait until we know that we are out of any interrupt
-	   handlers might have been running before we freed the
-	   interrupt. */
-	synchronize_kernel();
-
-	/* Wait for the timer to stop.  This avoids problems with race
-	   conditions removing the timer here. */
-	while (!to_clean->timer_stopped) {
-		schedule_timeout(1);
-	}
-
-	rv = ipmi_unregister_smi(to_clean->intf);
-	if (rv) {
-		printk(KERN_ERR 
-		       "ipmi_kcs: Unable to unregister device: errno=%d\n",
-		       rv);
-	}
-
-	initialized = 0;
-
-	kfree(to_clean->kcs_sm);
-	kfree(to_clean);
-}
-
-static __exit void cleanup_ipmi_kcs(void)
-{
-	int i;
-
-	if (!initialized)
-		return;
-
-	for (i=0; i<KCS_MAX_DRIVERS; i++) {
-		cleanup_one_kcs(kcs_infos[i]);
-	}
-}
-module_exit(cleanup_ipmi_kcs);
-#else
-
-/* Unfortunately, cmdline::get_options() only returns integers, not
-   longs.  Since we need ulongs (64-bit physical addresses) parse the 
-   comma-separated list manually.  Arguments can be one of these forms:
-   m0xaabbccddeeff	A physical memory address without an IRQ
-   m0xaabbccddeeff:cc	A physical memory address with an IRQ
-   p0xaabb		An IO port without an IRQ
-   p0xaabb:cc		An IO port with an IRQ
-   nodefaults		Suppress trying the default IO port or ACPI address 
-
-   For example, to pass one IO port with an IRQ, one address, and 
-   suppress the use of the default IO port and ACPI address,
-   use this option string: ipmi_kcs=p0xCA2:5,m0xFF5B0022,nodefaults
-
-   Remember, ipmi_kcs_setup() is passed the string after the equal sign. */
-
-static int __init ipmi_kcs_setup(char *str)
-{
-	unsigned long val;
-	char *cur, *colon;
-	int pos;
-
-	pos = 0;
-	
-	cur = strsep(&str, ",");
-	while ((cur) && (*cur) && (pos < KCS_MAX_PARMS)) {
-		switch (*cur) {
-		case 'n':
-			if (strcmp(cur, "nodefaults") == 0)
-				kcs_trydefaults = 0;
-			else
-				printk(KERN_INFO 
-				       "ipmi_kcs: bad parameter value %s\n",
-				       cur);
-			break;
-		
-		case 'm':
-		case 'p':
-			val = simple_strtoul(cur + 1,
-					     &colon,
-					     0);
-			if (*cur == 'p')
-				kcs_ports[pos] = val;
-			else
-				kcs_addrs[pos] = val;
-			if (*colon == ':') {
-				val = simple_strtoul(colon + 1,
-						     &colon,
-						     0);
-				kcs_irqs[pos] = val;
-			}
-			pos++;
-			break;
-
-		default:
-			printk(KERN_INFO 
-			       "ipmi_kcs: bad parameter value %s\n",
-			       cur);
-		}
-		cur = strsep(&str, ",");
-	}
-
-	return 1;
-}
-__setup("ipmi_kcs=", ipmi_kcs_setup);
-#endif
-
-MODULE_LICENSE("GPL");
--- diff/drivers/char/ipmi/ipmi_kcs_sm.h	2003-01-16 11:30:40.000000000 +0000
+++ source/drivers/char/ipmi/ipmi_kcs_sm.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,70 +0,0 @@
-/*
- * ipmi_kcs_sm.h
- *
- * State machine for handling IPMI KCS interfaces.
- *
- * Author: MontaVista Software, Inc.
- *         Corey Minyard <minyard@mvista.com>
- *         source@mvista.com
- *
- * Copyright 2002 MontaVista Software Inc.
- *
- *  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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.
- */
-
-struct kcs_data;
-
-void init_kcs_data(struct kcs_data *kcs,
-		   unsigned int    port,
-		   unsigned char   *addr);
-
-/* Start a new transaction in the state machine.  This will return -2
-   if the state machine is not idle, -1 if the size is invalid (to
-   large or too small), or 0 if the transaction is successfully
-   completed. */
-int start_kcs_transaction(struct kcs_data *kcs, char *data, unsigned int size);
-
-/* Return the results after the transaction.  This will return -1 if
-   the buffer is too small, zero if no transaction is present, or the
-   actual length of the result data. */
-int kcs_get_result(struct kcs_data *kcs, unsigned char *data, int length);
-
-enum kcs_result
-{
-	KCS_CALL_WITHOUT_DELAY, /* Call the driver again immediately */
-	KCS_CALL_WITH_DELAY,	/* Delay some before calling again. */
-	KCS_TRANSACTION_COMPLETE, /* A transaction is finished. */
-	KCS_SM_IDLE,		/* The SM is in idle state. */
-	KCS_SM_HOSED,		/* The hardware violated the state machine. */
-	KCS_ATTN		/* The hardware is asserting attn and the
-				   state machine is idle. */
-};
-
-/* Call this periodically (for a polled interface) or upon receiving
-   an interrupt (for a interrupt-driven interface).  If interrupt
-   driven, you should probably poll this periodically when not in idle
-   state.  This should be called with the time that passed since the
-   last call, if it is significant.  Time is in microseconds. */
-enum kcs_result kcs_event(struct kcs_data *kcs, long time);
-
-/* Return the size of the KCS structure in bytes. */
-int kcs_size(void);
--- diff/drivers/input/misc/gsc_ps2.c	2003-07-22 18:54:27.000000000 +0100
+++ source/drivers/input/misc/gsc_ps2.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,712 +0,0 @@
-/*
- * drivers/input/misc/gsc_ps2.c
- *
- * Copyright (c) 2002 Laurent Canet <canetl@esiee.fr>
- * Copyright (c) 2002 Thibaut Varene <varenet@esiee.fr>
- *
- * Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c
- * 	Copyright (c) 1999 Alex deVries <adevries@thepuffingroup.com>
- *	Copyright (c) 1999-2000 Philipp Rumpf <prumpf@tux.org>
- *	Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr>
- *	Copyright (c) 2000-2001 Thomas Marteau <marteaut@esiee.fr>
- *
- * HP PS/2 Keyboard, found in PA/RISC Workstations
- * very similar to AT keyboards, but without i8042
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * 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.
- * 
- * STATUS:
- * 11/09: lc: Only basic keyboard is supported, mouse still needs to be done.
- * 11/12: tv: switching iomapping; cleaning code; improving module stuff.
- * 11/13: lc & tv: leds aren't working. auto_repeat/meta are. Generaly good behavior.
- * 11/15: tv: 2AM: leds ARE working !
- * 11/16: tv: 3AM: escaped keycodes emulation *handled*, some keycodes are
- *	  still deliberately ignored (18), what are they used for ?
- * 11/21: lc: mouse is now working
- * 11/29: tv: first try for error handling in init sequence
- *
- * TODO:
- * Error handling in init sequence
- * SysRq handling
- * Pause key handling
- * Intellimouse & other rodents handling (at least send an error when
- * such a mouse is plugged : it will totally fault)
- * Mouse: set scaling / Dino testing
- * Bug chasing...
- *
- */
-
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ptrace.h>       /* interrupt.h wants struct pt_regs defined */
-#include <linux/interrupt.h>
-#include <linux/sched.h>        /* for request_irq/free_irq */        
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/kd.h>
-#include <linux/pci_ids.h>
-
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/parisc-device.h>
-
-/* Debugging stuff */
-#undef KBD_DEBUG
-#ifdef KBD_DEBUG
-	#define DPRINTK(fmt,args...) printk(KERN_DEBUG __FILE__ ":" fmt, ##args)
-#else 
-	#define DPRINTK(x,...)
-#endif
-
-
-/* 
- * Driver constants
- */
-
-/* PS/2 keyboard and mouse constants */
-#define AUX_RECONNECT		0xAA	/* PS/2 Mouse end of test successful */
-#define AUX_REPLY_ACK		0xFA
-#define AUX_ENABLE_DEV		0xF4	/* Enables aux device */
-
-/* Order of the mouse bytes coming to the host */
-#define PACKET_X		1
-#define PACKET_Y		2
-#define PACKET_CTRL		0
-
-#define GSC_MOUSE_OFFSET	0x0100	/* offset from keyboard to mouse port */
-#define GSC_DINO_OFFSET		0x800	/* offset for DINO controller versus LASI one */
-
-#define GSC_ID			0x00	/* ID and reset port offsets */
-#define GSC_RESET		0x00
-#define GSC_RCVDATA		0x04	/* receive and transmit port offsets */
-#define GSC_XMTDATA		0x04
-#define GSC_CONTROL		0x08	/* see: control register bits */
-#define GSC_STATUS		0x0C	/* see: status register bits */
-
-/* Control register bits */
-#define GSC_CTRL_ENBL		0x01	/* enable interface */
-#define GSC_CTRL_LPBXR		0x02	/* loopback operation */
-#define GSC_CTRL_DIAG		0x20	/* directly control clock/data line */
-#define GSC_CTRL_DATDIR		0x40	/* data line direct control */
-#define GSC_CTRL_CLKDIR		0x80	/* clock line direct control */
-
-/* Status register bits */
-#define GSC_STAT_RBNE		0x01	/* Receive Buffer Not Empty */
-#define GSC_STAT_TBNE		0x02	/* Transmit Buffer Not Empty */
-#define GSC_STAT_TERR		0x04	/* Timeout Error */
-#define GSC_STAT_PERR		0x08	/* Parity Error */
-#define GSC_STAT_CMPINTR	0x10	/* Composite Interrupt */
-#define GSC_STAT_DATSHD		0x40	/* Data Line Shadow */
-#define GSC_STAT_CLKSHD		0x80	/* Clock Line Shadow */
-
-/* Keycode map */
-#define KBD_ESCAPE0		0xe0
-#define KBD_ESCAPE1		0xe1
-#define KBD_RELEASE		0xf0
-#define KBD_ACK			0xfa
-#define KBD_RESEND		0xfe
-#define KBD_UNKNOWN		0
-
-#define KBD_TBLSIZE		512
-
-/* Mouse */
-#define MOUSE_LEFTBTN		0x1
-#define MOUSE_MIDBTN		0x4
-#define MOUSE_RIGHTBTN		0x2
-#define MOUSE_ALWAYS1		0x8
-#define MOUSE_XSIGN		0x10
-#define MOUSE_YSIGN		0x20
-#define MOUSE_XOVFLOW		0x40
-#define MOUSE_YOVFLOW		0x80
-
-/* Remnant of pc_keyb.h */
-#define KBD_CMD_SET_LEDS	0xED	/* Sets keyboard leds */
-#define KBD_CMD_SET_RATE	0xF3	/* Sets typematic rate */
-#define KBD_CMD_ENABLE		0xF4	/* Enables scanning */
-#define KBD_CMD_DISABLE		0xF5
-#define KBD_CMD_RESET		0xFF
-
-static unsigned char hpkeyb_keycode[KBD_TBLSIZE] =
-{
-	/* 00 */  KBD_UNKNOWN,  KEY_F9,        KBD_UNKNOWN,   KEY_F5,        KEY_F3,        KEY_F1,       KEY_F2,        KEY_F12,
-	/* 08 */  KBD_UNKNOWN,  KEY_F10,       KEY_F8,        KEY_F6,        KEY_F4,        KEY_TAB,      KEY_GRAVE,     KBD_UNKNOWN,
-	/* 10 */  KBD_UNKNOWN,  KEY_LEFTALT,   KEY_LEFTSHIFT, KBD_UNKNOWN,   KEY_LEFTCTRL,  KEY_Q,        KEY_1,         KBD_UNKNOWN,
-	/* 18 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_Z,         KEY_S,         KEY_A,         KEY_W,        KEY_2,         KBD_UNKNOWN,
-	/* 20 */  KBD_UNKNOWN,  KEY_C,         KEY_X,         KEY_D,         KEY_E,         KEY_4,        KEY_3,         KBD_UNKNOWN,
-	/* 28 */  KBD_UNKNOWN,  KEY_SPACE,     KEY_V,         KEY_F,         KEY_T,         KEY_R,        KEY_5,         KBD_UNKNOWN,
-	/* 30 */  KBD_UNKNOWN,  KEY_N,         KEY_B,         KEY_H,         KEY_G,         KEY_Y,        KEY_6,         KBD_UNKNOWN,
-	/* 38 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_M,         KEY_J,         KEY_U,         KEY_7,        KEY_8,         KBD_UNKNOWN,
-	/* 40 */  KBD_UNKNOWN,  KEY_COMMA,     KEY_K,         KEY_I,         KEY_O,         KEY_0,        KEY_9,         KBD_UNKNOWN,
-	/* 48 */  KBD_UNKNOWN,  KEY_DOT,       KEY_SLASH,     KEY_L,         KEY_SEMICOLON, KEY_P,        KEY_MINUS,     KBD_UNKNOWN,
-	/* 50 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_APOSTROPHE,KBD_UNKNOWN,   KEY_LEFTBRACE, KEY_EQUAL,    KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 58 */  KEY_CAPSLOCK, KEY_RIGHTSHIFT,KEY_ENTER,     KEY_RIGHTBRACE,KBD_UNKNOWN,   KEY_BACKSLASH,KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 60 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KEY_BACKSPACE, KBD_UNKNOWN,
-	/* 68 */  KBD_UNKNOWN,  KEY_KP1,       KBD_UNKNOWN,   KEY_KP4,       KEY_KP7,       KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 70 */  KEY_KP0,      KEY_KPDOT,     KEY_KP2,       KEY_KP5,       KEY_KP6,       KEY_KP8,      KEY_ESC,       KEY_NUMLOCK,
-	/* 78 */  KEY_F11,      KEY_KPPLUS,    KEY_KP3,       KEY_KPMINUS,   KEY_KPASTERISK,KEY_KP9,      KEY_SCROLLLOCK,KEY_103RD,
-	/* 80 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KEY_F7,        KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 88 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 90 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 98 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* a0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* a8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* b0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* b8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* c0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* c8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* d0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* d8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* e0 */  KBD_ESCAPE0,  KBD_ESCAPE1,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* e8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* f0 */  KBD_RELEASE,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* f8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_ACK,       KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_RESEND,    KBD_UNKNOWN,
-/* These are offset for escaped keycodes */
-	/* 00 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 08 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 10 */  KBD_UNKNOWN,  KEY_RIGHTALT,  KBD_UNKNOWN,   KBD_UNKNOWN,   KEY_RIGHTCTRL, KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 18 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 20 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 28 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 30 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 38 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 40 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 48 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_KPSLASH,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 50 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 58 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_KPENTER,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 60 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 68 */  KBD_UNKNOWN,  KEY_END,       KBD_UNKNOWN,   KEY_LEFT,      KEY_HOME,      KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 70 */  KEY_INSERT,   KEY_DELETE,    KEY_DOWN,      KBD_UNKNOWN,   KEY_RIGHT,     KEY_UP,       KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 78 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_PAGEDOWN,  KBD_UNKNOWN,   KEY_SYSRQ,     KEY_PAGEUP,   KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 80 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 88 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 90 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 98 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* a0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* a8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* b0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* b8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* c0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* c8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* d0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* d8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* e0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* e8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* f0 */  KBD_RELEASE,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* f8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN
-};
-
-
-/* Keyboard struct */
-static struct {
-	struct input_dev dev;
-	char * addr;
-	unsigned int irq;
-	unsigned int scancode;
-	unsigned int escaped;
-	unsigned int released;
-	unsigned int initialized;
-}
-hpkeyb = {
-	.escaped = 0,
-	.released = 0,
-	.initialized = 0
-};
-
-/* Mouse struct */
-static struct {
-   	struct input_dev dev;
-	char * addr;
-	unsigned long irq;
-	unsigned long initialized;
-	int nbread;
-	unsigned char bytes[3];
-	unsigned long last;
-}
-hpmouse = {
-	.initialized = 0,
-	.nbread = 0
-};
-
-static spinlock_t gscps2_lock = SPIN_LOCK_UNLOCKED;
-
-
-/*
- * Various HW level routines
- */
-
-#define gscps2_readb_input(x)		readb(x+GSC_RCVDATA)
-#define gscps2_readb_control(x)		readb(x+GSC_CONTROL)
-#define gscps2_readb_status(x)		readb(x+GSC_STATUS)
-#define gscps2_writeb_control(x, y)	writeb(x, y+GSC_CONTROL)
-
-static inline void gscps2_writeb_output(u8 val, char * addr)
-{
-	int wait = 250;			/* Keyboard is expected to react within 250ms */
-
-	while (gscps2_readb_status(addr) & GSC_STAT_TBNE) {
-		if (!--wait)
-			return;		/* This should not happen */
-		mdelay(1);
-	}
-	writeb(val, addr+GSC_XMTDATA);
-}
-
-static inline unsigned char gscps2_wait_input(char * addr)
-{
-	int wait = 250;			/* Keyboard is expected to react within 250ms */
-
-	while (!(gscps2_readb_status(addr) & GSC_STAT_RBNE)) {
-		if (!--wait)
-			return 0;	/* This should not happen */
-		mdelay(1);
-	}
-	return gscps2_readb_input(addr);
-}
-
-static int gscps2_writeb_safe_output(u8 val)
-{
-	/* This function waits for keyboard's ACK */
-	u8 scanread = KBD_UNKNOWN;
-	int loop = 5;
-	
-	while (hpkeyb_keycode[scanread]!=KBD_ACK && --loop > 0) {	
-		gscps2_writeb_output(val, hpkeyb.addr);
-		mdelay(5);
-		scanread = gscps2_wait_input(hpkeyb.addr);
-	}
-	
-	if (loop <= 0)
-		return -1;
-	
-	return 0;
-}
-
-/* Reset the PS2 port */
-static void __init gscps2_reset(char * addr)
-{
-	/* reset the interface */
-	writeb(0xff, addr+GSC_RESET);
-	writeb(0x0 , addr+GSC_RESET);
-
-	/* enable it */
-	gscps2_writeb_control(gscps2_readb_control(addr) | GSC_CTRL_ENBL, addr);
-}
-
-
-/**
- * gscps2_kbd_docode() - PS2 Keyboard basic handler
- *
- * Receives a keyboard scancode, analyses it and sends it to the input layer.
- */
-
-static void gscps2_kbd_docode(struct pt_regs *regs)
-{
-	int scancode = gscps2_readb_input(hpkeyb.addr);
-	DPRINTK("rel=%d scancode=%d, esc=%d ", hpkeyb.released, scancode, hpkeyb.escaped);
-
-	/* Handle previously escaped scancodes */
-	if (hpkeyb.escaped == KBD_ESCAPE0)
-		scancode |= 0x100;	/* jump to the next 256 chars of the table */
-		
-	switch (hpkeyb_keycode[scancode]) {
-		case KBD_RELEASE:
-			DPRINTK("release\n");
-			hpkeyb.released = 1;
-			break;
-		case KBD_RESEND:
-			DPRINTK("resend request\n");
-			break;
-		case KBD_ACK:
-			DPRINTK("ACK\n");
-			break;
-		case KBD_ESCAPE0:
-		case KBD_ESCAPE1:
-			DPRINTK("escape code %d\n", hpkeyb_keycode[scancode]);
-			hpkeyb.escaped = hpkeyb_keycode[scancode];
-			break;
-		case KBD_UNKNOWN:
-			DPRINTK("received unknown scancode %d, escape %d.\n",
-				scancode, hpkeyb.escaped);	/* This is a DPRINTK atm since we do not handle escaped scancodes cleanly */
-			if (hpkeyb.escaped)
-			hpkeyb.escaped = 0;
-			if (hpkeyb.released)
-				hpkeyb.released = 0;
-			return;
-		default:
-			hpkeyb.scancode = scancode;
-			DPRINTK("sent=%d, rel=%d\n",hpkeyb.scancode, hpkeyb.released);
-			/*input_regs(regs);*/
-			input_report_key(&hpkeyb.dev, hpkeyb_keycode[hpkeyb.scancode], !hpkeyb.released);
-			input_sync(&hpkeyb.dev);
-			if (hpkeyb.escaped)
-				hpkeyb.escaped = 0;
-			if (hpkeyb.released) 
-				hpkeyb.released = 0;
-			break;	
-	}
-}
-
-
-/**
- * gscps2_mouse_docode() - PS2 Mouse basic handler
- *
- * Receives mouse codes, processes them by packets of three, and sends
- * correct events to the input layer.
- */
-
-static void gscps2_mouse_docode(struct pt_regs *regs)
-{
-	int xrel, yrel;
-
-	/* process BAT (end of basic tests) command */
-	if ((hpmouse.nbread == 1) && (hpmouse.bytes[0] == AUX_RECONNECT))
-		hpmouse.nbread--;
-
-	/* stolen from psmouse.c */
-	if (hpmouse.nbread && time_after(jiffies, hpmouse.last + HZ/2)) {
-		printk(KERN_DEBUG "%s:%d : Lost mouse synchronization, throwing %d bytes away.\n", __FILE__, __LINE__,
-				hpmouse.nbread);
-		hpmouse.nbread = 0;
-	}
-
-	hpmouse.last = jiffies;
-	hpmouse.bytes[hpmouse.nbread++] = gscps2_readb_input(hpmouse.addr);
-	
-	/* process packet */
-	if (hpmouse.nbread == 3) {
-		
-		if (!(hpmouse.bytes[PACKET_CTRL] & MOUSE_ALWAYS1))
-			DPRINTK("Mouse: error on packet always1 bit checking\n");
-			/* XXX should exit now, bad data on the line! */
-		
-		if ((hpmouse.bytes[PACKET_CTRL] & (MOUSE_XOVFLOW | MOUSE_YOVFLOW)))
-			DPRINTK("Mouse: position overflow\n");
-		
-		/*input_regs(regs);*/
-
-		input_report_key(&hpmouse.dev, BTN_LEFT, hpmouse.bytes[PACKET_CTRL] & MOUSE_LEFTBTN);
-		input_report_key(&hpmouse.dev, BTN_MIDDLE, hpmouse.bytes[PACKET_CTRL] & MOUSE_MIDBTN);
-		input_report_key(&hpmouse.dev, BTN_RIGHT, hpmouse.bytes[PACKET_CTRL] & MOUSE_RIGHTBTN);
-		
-		xrel = hpmouse.bytes[PACKET_X];
-		yrel = hpmouse.bytes[PACKET_Y];
-		
-		/* Data sent by mouse are 9-bit signed, the sign bit is in the control packet */
-		if (xrel && (hpmouse.bytes[PACKET_CTRL] & MOUSE_XSIGN))
-			xrel = xrel - 0x100;
-		if (yrel && (hpmouse.bytes[PACKET_CTRL] & MOUSE_YSIGN))
-			yrel = yrel - 0x100;
-		
-		input_report_rel(&hpmouse.dev, REL_X, xrel);
-		input_report_rel(&hpmouse.dev, REL_Y, -yrel);	/* Y axis is received upside-down */
-		
-		input_sync(&hpmouse.dev);
-		
-		hpmouse.nbread = 0;
-	}
-}
-
-
-/**
- * gscps2_interrupt() - Interruption service routine
- *
- * This processes the list of scancodes queued and sends appropriate
- * key value to the system.
- */
-
-static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *reg)
-{
-	/* process mouse actions */
-	while (gscps2_readb_status(hpmouse.addr) & GSC_STAT_RBNE)
-		gscps2_mouse_docode(reg);
-	
-	/* process keyboard scancode */
-	while (gscps2_readb_status(hpkeyb.addr) & GSC_STAT_RBNE)
-		gscps2_kbd_docode(reg);
-
-	return IRQ_HANDLED;
-}
-
-
-/**
- * gscps2_hpkeyb_event() - Event handler
- * @return: success/error report
- *
- * Currently only updates leds on keyboard
- */
-
-int gscps2_hpkeyb_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-{
-	DPRINTK("Calling %s, type=%d, code=%d, value=%d\n",
-			__FUNCTION__, type, code, value);
-
-	if (!hpkeyb.initialized)
-		return -1;
-
-	if (type == EV_LED) {
-		u8 leds[2];
-
-		if (gscps2_writeb_safe_output(KBD_CMD_SET_LEDS)) {
-			printk(KERN_ERR "gsckbd_leds: timeout\n");
-			return -1;
-		}
-		DPRINTK("KBD_CMD_SET_LEDS\n");
-
-		*leds = (test_bit(LED_SCROLLL, dev->led) ? LED_SCR : 0)
-			| (test_bit(LED_NUML,    dev->led) ? LED_NUM : 0)
-			| (test_bit(LED_CAPSL,   dev->led) ? LED_CAP : 0);
-		DPRINTK("Sending leds=%x\n", *leds);
-		
-		if (gscps2_writeb_safe_output(*leds)) {
-			printk(KERN_ERR "gsckbd_leds: timeout\n");
-			return -1;
-		}
-		DPRINTK("leds sent\n");
-		
-		if (gscps2_writeb_safe_output(KBD_CMD_ENABLE)) {
-			printk(KERN_ERR "gsckbd_leds: timeout\n");
-			return -1;
-		}
-		DPRINTK("End\n");
-
-		return 0;
-
-	}
-	return -1;
-}
-
-
-/**
- * gscps2_kbd_probe() - Probes keyboard device and init input_dev structure
- * @return: number of device initialized (1, 0 on error)
- */
-
-static int __init gscps2_kbd_probe(void)
-{
-	int i, res = 0;
-	unsigned long flags;
-
-	if (hpkeyb.initialized) {
-		printk(KERN_ERR "GSC PS/2 keyboard driver already registered\n");
-		return 0;
-	}
-	
-	spin_lock_irqsave(&gscps2_lock, flags);
- 
-	if (!gscps2_writeb_safe_output(KBD_CMD_SET_LEDS)	&&
-	    !gscps2_writeb_safe_output(0)			&&
-	    !gscps2_writeb_safe_output(KBD_CMD_ENABLE))
-		res = 1;
- 
-	spin_unlock_irqrestore(&gscps2_lock, flags);
-
-	if (!res)
-		printk(KERN_ERR "Keyboard initialization sequence failled\n");
-	
-	init_input_dev(&hpkeyb.dev);
-	
-	for (i = 0; i < KBD_TBLSIZE; i++)
-		if (hpkeyb_keycode[i] != KBD_UNKNOWN)
-			set_bit(hpkeyb_keycode[i], hpkeyb.dev.keybit);
-		
-	hpkeyb.dev.evbit[0]	= BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
-	hpkeyb.dev.ledbit[0]	= BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
-	hpkeyb.dev.keycode	= hpkeyb_keycode;
-	hpkeyb.dev.keycodesize	= sizeof(unsigned char);
-	hpkeyb.dev.keycodemax	= KBD_TBLSIZE;
-	hpkeyb.dev.name		= "GSC Keyboard";
-	hpkeyb.dev.phys		= "hpkbd/input0";
-
-	hpkeyb.dev.event	= gscps2_hpkeyb_event;
-	
-	/* TODO These need some adjustement, are they really useful ? */
-	hpkeyb.dev.id.bustype	= BUS_GSC;
-	hpkeyb.dev.id.vendor	= PCI_VENDOR_ID_HP;
-	hpkeyb.dev.id.product	= 0x0001;
-	hpkeyb.dev.id.version	= 0x0010;
-	hpkeyb.initialized	= 1;
-
-	return 1;
-}
-
-
-/**
- * gscps2_mouse_probe() - Probes mouse device and init input_dev structure
- * @return: number of device initialized (1, 0 on error)
- *
- * Currently no check on initialization is performed
- */
-
-static int __init gscps2_mouse_probe(void)
-{
-	if (hpmouse.initialized) {
-		printk(KERN_ERR "GSC PS/2 Mouse driver already registered\n");
-		return 0;
-	}
-	
-	init_input_dev(&hpmouse.dev);
-	
-	hpmouse.dev.name	= "GSC Mouse";
-	hpmouse.dev.phys	= "hpmouse/input0";
-   	hpmouse.dev.evbit[0] 	= BIT(EV_KEY) | BIT(EV_REL);
-	hpmouse.dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
-	hpmouse.dev.relbit[0] 	= BIT(REL_X) | BIT(REL_Y);
-	hpmouse.last 		= 0;
-
-	gscps2_writeb_output(AUX_ENABLE_DEV, hpmouse.addr);
-	/* Try it a second time, this will give status if the device is available */
-	gscps2_writeb_output(AUX_ENABLE_DEV, hpmouse.addr);
-	
-	/* TODO These need some adjustement, are they really useful ? */
-	hpmouse.dev.id.bustype	= BUS_GSC;
-	hpmouse.dev.id.vendor	= 0x0001;
-	hpmouse.dev.id.product	= 0x0001;
-	hpmouse.dev.id.version	= 0x0010;
-	hpmouse.initialized = 1;
-	return 1;	/* XXX: we don't check if initialization failed */
-}
-
-
-/**
- * gscps2_probe() - Probes PS2 devices
- * @return: success/error report
- */
-
-static int __init gscps2_probe(struct parisc_device *dev)
-{
-	u8 id;
-	char *addr, *name;
-	int ret = 0, device_found = 0;
-	unsigned long hpa = dev->hpa;
-
-	if (!dev->irq)
-		goto fail_pitifully;
-	
-	/* Offset for DINO PS/2. Works with LASI even */
-	if (dev->id.sversion == 0x96)
-		hpa += GSC_DINO_OFFSET;
-
-	addr = ioremap(hpa, 256);
-	
-	if (!hpmouse.initialized || !hpkeyb.initialized)
-		gscps2_reset(addr);
-
-	ret = -EINVAL;
-	id = readb(addr+GSC_ID) & 0x0f;
-	switch (id) {
-		case 0:				/* keyboard */
-			hpkeyb.addr = addr;
-			name = "keyboard";
-			device_found = gscps2_kbd_probe();
-			break;
-		case 1:				/* mouse */
-			hpmouse.addr = addr;
-			name = "mouse";
-			device_found = gscps2_mouse_probe();
-			break;
-		default:
-			printk(KERN_WARNING "%s: Unsupported PS/2 port (id=%d) ignored\n",
-		    		__FUNCTION__, id);
-			goto fail_miserably;
-	}
-
-	/* No valid device found */
-	ret = -ENODEV;
-	if (!device_found)
-		goto fail_miserably;
-
-	/* Here we claim only if we have a device attached */
-	/* Allocate the irq and memory region for that device */
-	ret = -EBUSY;
-	if (request_irq(dev->irq, gscps2_interrupt, 0, name, NULL))
-		goto fail_miserably;
-
-	if (!request_mem_region(hpa, GSC_STATUS + 4, name))
-		goto fail_request_mem;
-	
-	/* Finalize input struct and register it */
-	switch (id) {
-		case 0:				/* keyboard */
-			hpkeyb.irq = dev->irq;
-			input_register_device(&hpkeyb.dev);	
-			break;
-		case 1:				/* mouse */
-			hpmouse.irq = dev->irq;
-			input_register_device(&hpmouse.dev);
-			break;
-		default:
-			break;
-	}
-
-	printk(KERN_INFO "input: PS/2 %s port at 0x%08lx (irq %d) found and attached\n",
-			name, hpa, dev->irq);
-
-	return 0;
-	
-fail_request_mem: free_irq(dev->irq, NULL);
-fail_miserably: iounmap(addr);
-fail_pitifully:	return ret;
-}
-
-
-
-static struct parisc_device_id gscps2_device_tbl[] = {
-	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00084 }, /* LASI PS/2 */
-/*	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00096 },  DINO PS/2 (XXX Not yet tested) */
-	{ 0, }	/* 0 terminated list */
-};
-
-static struct parisc_driver gscps2_driver = {
-	.name		= "GSC PS2",
-	.id_table	= gscps2_device_tbl,
-	.probe		= gscps2_probe,
-};
-
-static int __init gscps2_init(void)
-{
-	if (register_parisc_driver(&gscps2_driver))
-		return -EBUSY;
-	return 0;
-}
-
-static void __exit gscps2_exit(void)
-{
-	/* TODO this is probably not very good and needs to be checked */
-	if (hpkeyb.initialized) {
-		free_irq(hpkeyb.irq, gscps2_interrupt);
-		iounmap(hpkeyb.addr);
-		hpkeyb.initialized = 0;
-		input_unregister_device(&hpkeyb.dev);
-	}
-	if (hpmouse.initialized) {
-		free_irq(hpmouse.irq, gscps2_interrupt);
-		iounmap(hpmouse.addr);
-		hpmouse.initialized = 0;
-		input_unregister_device(&hpmouse.dev);
-	}
-	unregister_parisc_driver(&gscps2_driver);
-}
-
-
-MODULE_AUTHOR("Laurent Canet <canetl@esiee.fr>, Thibaut Varene <varenet@esiee.fr>");
-MODULE_DESCRIPTION("GSC PS/2 keyboard/mouse driver");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl);
-
-
-module_init(gscps2_init);
-module_exit(gscps2_exit);
--- diff/drivers/md/dm-ioctl-v1.c	2004-01-19 10:22:56.000000000 +0000
+++ source/drivers/md/dm-ioctl-v1.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,1159 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
- *
- * This file is released under the GPL.
- */
-
-#include "dm.h"
-
-#include <linux/module.h>
-#include <linux/vmalloc.h>
-#include <linux/miscdevice.h>
-#include <linux/dm-ioctl.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/slab.h>
-#include <linux/devfs_fs_kernel.h>
-
-#include <asm/uaccess.h>
-
-#define DM_DRIVER_EMAIL "dm@uk.sistina.com"
-
-/*-----------------------------------------------------------------
- * The ioctl interface needs to be able to look up devices by
- * name or uuid.
- *---------------------------------------------------------------*/
-struct hash_cell {
-	struct list_head name_list;
-	struct list_head uuid_list;
-
-	char *name;
-	char *uuid;
-	struct mapped_device *md;
-};
-
-#define NUM_BUCKETS 64
-#define MASK_BUCKETS (NUM_BUCKETS - 1)
-static struct list_head _name_buckets[NUM_BUCKETS];
-static struct list_head _uuid_buckets[NUM_BUCKETS];
-
-void dm_hash_remove_all(void);
-
-/*
- * Guards access to all three tables.
- */
-static DECLARE_RWSEM(_hash_lock);
-
-static void init_buckets(struct list_head *buckets)
-{
-	unsigned int i;
-
-	for (i = 0; i < NUM_BUCKETS; i++)
-		INIT_LIST_HEAD(buckets + i);
-}
-
-int dm_hash_init(void)
-{
-	init_buckets(_name_buckets);
-	init_buckets(_uuid_buckets);
-	devfs_mk_dir(DM_DIR);
-	return 0;
-}
-
-void dm_hash_exit(void)
-{
-	dm_hash_remove_all();
-	devfs_remove(DM_DIR);
-}
-
-/*-----------------------------------------------------------------
- * Hash function:
- * We're not really concerned with the str hash function being
- * fast since it's only used by the ioctl interface.
- *---------------------------------------------------------------*/
-static unsigned int hash_str(const char *str)
-{
-	const unsigned int hash_mult = 2654435387U;
-	unsigned int h = 0;
-
-	while (*str)
-		h = (h + (unsigned int) *str++) * hash_mult;
-
-	return h & MASK_BUCKETS;
-}
-
-/*-----------------------------------------------------------------
- * Code for looking up a device by name
- *---------------------------------------------------------------*/
-static struct hash_cell *__get_name_cell(const char *str)
-{
-	struct list_head *tmp;
-	struct hash_cell *hc;
-	unsigned int h = hash_str(str);
-
-	list_for_each (tmp, _name_buckets + h) {
-		hc = list_entry(tmp, struct hash_cell, name_list);
-		if (!strcmp(hc->name, str))
-			return hc;
-	}
-
-	return NULL;
-}
-
-static struct hash_cell *__get_uuid_cell(const char *str)
-{
-	struct list_head *tmp;
-	struct hash_cell *hc;
-	unsigned int h = hash_str(str);
-
-	list_for_each (tmp, _uuid_buckets + h) {
-		hc = list_entry(tmp, struct hash_cell, uuid_list);
-		if (!strcmp(hc->uuid, str))
-			return hc;
-	}
-
-	return NULL;
-}
-
-/*-----------------------------------------------------------------
- * Inserting, removing and renaming a device.
- *---------------------------------------------------------------*/
-static inline char *kstrdup(const char *str)
-{
-	char *r = kmalloc(strlen(str) + 1, GFP_KERNEL);
-	if (r)
-		strcpy(r, str);
-	return r;
-}
-
-static struct hash_cell *alloc_cell(const char *name, const char *uuid,
-				    struct mapped_device *md)
-{
-	struct hash_cell *hc;
-
-	hc = kmalloc(sizeof(*hc), GFP_KERNEL);
-	if (!hc)
-		return NULL;
-
-	hc->name = kstrdup(name);
-	if (!hc->name) {
-		kfree(hc);
-		return NULL;
-	}
-
-	if (!uuid)
-		hc->uuid = NULL;
-
-	else {
-		hc->uuid = kstrdup(uuid);
-		if (!hc->uuid) {
-			kfree(hc->name);
-			kfree(hc);
-			return NULL;
-		}
-	}
-
-	INIT_LIST_HEAD(&hc->name_list);
-	INIT_LIST_HEAD(&hc->uuid_list);
-	hc->md = md;
-	return hc;
-}
-
-static void free_cell(struct hash_cell *hc)
-{
-	if (hc) {
-		kfree(hc->name);
-		kfree(hc->uuid);
-		kfree(hc);
-	}
-}
-
-/*
- * devfs stuff.
- */
-static int register_with_devfs(struct hash_cell *hc)
-{
-	struct gendisk *disk = dm_disk(hc->md);
-
-	devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
-		       S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
-		       DM_DIR "/%s", hc->name);
-	return 0;
-}
-
-static int unregister_with_devfs(struct hash_cell *hc)
-{
-	devfs_remove(DM_DIR"/%s", hc->name);
-	return 0;
-}
-
-/*
- * The kdev_t and uuid of a device can never change once it is
- * initially inserted.
- */
-int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md)
-{
-	struct hash_cell *cell;
-
-	/*
-	 * Allocate the new cells.
-	 */
-	cell = alloc_cell(name, uuid, md);
-	if (!cell)
-		return -ENOMEM;
-
-	/*
-	 * Insert the cell into all three hash tables.
-	 */
-	down_write(&_hash_lock);
-	if (__get_name_cell(name))
-		goto bad;
-
-	list_add(&cell->name_list, _name_buckets + hash_str(name));
-
-	if (uuid) {
-		if (__get_uuid_cell(uuid)) {
-			list_del(&cell->name_list);
-			goto bad;
-		}
-		list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid));
-	}
-	register_with_devfs(cell);
-	dm_get(md);
-	up_write(&_hash_lock);
-
-	return 0;
-
- bad:
-	up_write(&_hash_lock);
-	free_cell(cell);
-	return -EBUSY;
-}
-
-void __hash_remove(struct hash_cell *hc)
-{
-	/* remove from the dev hash */
-	list_del(&hc->uuid_list);
-	list_del(&hc->name_list);
-	unregister_with_devfs(hc);
-	dm_put(hc->md);
-	free_cell(hc);
-}
-
-void dm_hash_remove_all(void)
-{
-	int i;
-	struct hash_cell *hc;
-	struct list_head *tmp, *n;
-
-	down_write(&_hash_lock);
-	for (i = 0; i < NUM_BUCKETS; i++) {
-		list_for_each_safe (tmp, n, _name_buckets + i) {
-			hc = list_entry(tmp, struct hash_cell, name_list);
-			__hash_remove(hc);
-		}
-	}
-	up_write(&_hash_lock);
-}
-
-int dm_hash_rename(const char *old, const char *new)
-{
-	char *new_name, *old_name;
-	struct hash_cell *hc;
-
-	/*
-	 * duplicate new.
-	 */
-	new_name = kstrdup(new);
-	if (!new_name)
-		return -ENOMEM;
-
-	down_write(&_hash_lock);
-
-	/*
-	 * Is new free ?
-	 */
-	hc = __get_name_cell(new);
-	if (hc) {
-		DMWARN("asked to rename to an already existing name %s -> %s",
-		       old, new);
-		up_write(&_hash_lock);
-		kfree(new_name);
-		return -EBUSY;
-	}
-
-	/*
-	 * Is there such a device as 'old' ?
-	 */
-	hc = __get_name_cell(old);
-	if (!hc) {
-		DMWARN("asked to rename a non existent device %s -> %s",
-		       old, new);
-		up_write(&_hash_lock);
-		kfree(new_name);
-		return -ENXIO;
-	}
-
-	/*
-	 * rename and move the name cell.
-	 */
-	unregister_with_devfs(hc);
-
-	list_del(&hc->name_list);
-	old_name = hc->name;
-	hc->name = new_name;
-	list_add(&hc->name_list, _name_buckets + hash_str(new_name));
-
-	/* rename the device node in devfs */
-	register_with_devfs(hc);
-
-	up_write(&_hash_lock);
-	kfree(old_name);
-	return 0;
-}
-
-
-/*-----------------------------------------------------------------
- * Implementation of the ioctl commands
- *---------------------------------------------------------------*/
-
-/*
- * All the ioctl commands get dispatched to functions with this
- * prototype.
- */
-typedef int (*ioctl_fn)(struct dm_ioctl *param, struct dm_ioctl *user);
-
-/*
- * Check a string doesn't overrun the chunk of
- * memory we copied from userland.
- */
-static int valid_str(char *str, void *begin, void *end)
-{
-	while (((void *) str >= begin) && ((void *) str < end))
-		if (!*str++)
-			return 0;
-
-	return -EINVAL;
-}
-
-static int next_target(struct dm_target_spec *last, uint32_t next,
-		       void *begin, void *end,
-		       struct dm_target_spec **spec, char **params)
-{
-	*spec = (struct dm_target_spec *)
-	    ((unsigned char *) last + next);
-	*params = (char *) (*spec + 1);
-
-	if (*spec < (last + 1) || ((void *) *spec > end))
-		return -EINVAL;
-
-	return valid_str(*params, begin, end);
-}
-
-static int populate_table(struct dm_table *table, struct dm_ioctl *args)
-{
-	int r, first = 1;
-	unsigned int i = 0;
-	struct dm_target_spec *spec;
-	char *params;
-	void *begin, *end;
-
-	if (!args->target_count) {
-		DMWARN("populate_table: no targets specified");
-		return -EINVAL;
-	}
-
-	begin = (void *) args;
-	end = begin + args->data_size;
-
-	for (i = 0; i < args->target_count; i++) {
-
-		if (first)
-			r = next_target((struct dm_target_spec *) args,
-					args->data_start,
-					begin, end, &spec, &params);
-		else
-			r = next_target(spec, spec->next, begin, end,
-					&spec, &params);
-
-		if (r) {
-			DMWARN("unable to find target");
-			return -EINVAL;
-		}
-
-		r = dm_table_add_target(table, spec->target_type,
-					(sector_t) spec->sector_start,
-					(sector_t) spec->length,
-					params);
-		if (r) {
-			DMWARN("internal error adding target to table");
-			return -EINVAL;
-		}
-
-		first = 0;
-	}
-
-	return dm_table_complete(table);
-}
-
-/*
- * Round up the ptr to the next 'align' boundary.  Obviously
- * 'align' must be a power of 2.
- */
-static inline void *align_ptr(void *ptr, unsigned int align)
-{
-	align--;
-	return (void *) (((unsigned long) (ptr + align)) & ~align);
-}
-
-/*
- * Copies a dm_ioctl and an optional additional payload to
- * userland.
- */
-static int results_to_user(struct dm_ioctl *user, struct dm_ioctl *param,
-			   void *data, uint32_t len)
-{
-	int r;
-	void *ptr = NULL;
-
-	if (data) {
-		ptr = align_ptr(user + 1, sizeof(unsigned long));
-		param->data_start = ptr - (void *) user;
-	}
-
-	/*
-	 * The version number has already been filled in, so we
-	 * just copy later fields.
-	 */
-	r = copy_to_user(&user->data_size, &param->data_size,
-			 sizeof(*param) - sizeof(param->version));
-	if (r)
-		return -EFAULT;
-
-	if (data) {
-		if (param->data_start + len > param->data_size)
-			return -ENOSPC;
-
-		if (copy_to_user(ptr, data, len))
-			r = -EFAULT;
-	}
-
-	return r;
-}
-
-/*
- * Fills in a dm_ioctl structure, ready for sending back to
- * userland.
- */
-static int __info(struct mapped_device *md, struct dm_ioctl *param)
-{
-	struct dm_table *table;
-	struct block_device *bdev;
-	struct gendisk *disk = dm_disk(md);
-
-	param->flags = DM_EXISTS_FLAG;
-	if (dm_suspended(md))
-		param->flags |= DM_SUSPEND_FLAG;
-
-	bdev = bdget_disk(disk, 0);
-	if (!bdev)
-		return -ENXIO;
-
-	param->dev = old_encode_dev(bdev->bd_dev);
-	param->open_count = bdev->bd_openers;
-	bdput(bdev);
-
-	if (disk->policy)
-		param->flags |= DM_READONLY_FLAG;
-
-	table = dm_get_table(md);
-	param->target_count = dm_table_get_num_targets(table);
-	dm_table_put(table);
-
-	return 0;
-}
-
-/*
- * Always use UUID for lookups if it's present, otherwise use name.
- */
-static inline struct mapped_device *find_device(struct dm_ioctl *param)
-{
-	struct hash_cell *hc;
-	struct mapped_device *md = NULL;
-
-	down_read(&_hash_lock);
-	hc = *param->uuid ? __get_uuid_cell(param->uuid) :
-		__get_name_cell(param->name);
-	if (hc) {
-		md = hc->md;
-
-		/*
-		 * Sneakily write in both the name and the uuid
-		 * while we have the cell.
-		 */
-		strlcpy(param->name, hc->name, sizeof(param->name));
-		if (hc->uuid)
-			strlcpy(param->uuid, hc->uuid, sizeof(param->uuid));
-		else
-			param->uuid[0] = '\0';
-
-		dm_get(md);
-	}
-	up_read(&_hash_lock);
-
-	return md;
-}
-
-#define ALIGNMENT sizeof(int)
-static void *_align(void *ptr, unsigned int a)
-{
-	register unsigned long align = --a;
-
-	return (void *) (((unsigned long) ptr + align) & ~align);
-}
-
-/*
- * Copies device info back to user space, used by
- * the create and info ioctls.
- */
-static int info(struct dm_ioctl *param, struct dm_ioctl *user)
-{
-	struct mapped_device *md;
-
-	param->flags = 0;
-
-	md = find_device(param);
-	if (!md)
-		/*
-		 * Device not found - returns cleared exists flag.
-		 */
-		goto out;
-
-	__info(md, param);
-	dm_put(md);
-
-      out:
-	return results_to_user(user, param, NULL, 0);
-}
-
-static inline int get_mode(struct dm_ioctl *param)
-{
-	int mode = FMODE_READ | FMODE_WRITE;
-
-	if (param->flags & DM_READONLY_FLAG)
-		mode = FMODE_READ;
-
-	return mode;
-}
-
-static int check_name(const char *name)
-{
-	if (name[0] == '/') {
-		DMWARN("invalid device name");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int create(struct dm_ioctl *param, struct dm_ioctl *user)
-{
-	int r;
-	struct dm_table *t;
-	struct mapped_device *md;
-
-	r = check_name(param->name);
-	if (r)
-		return r;
-
-	r = dm_table_create(&t, get_mode(param), param->target_count);
-	if (r)
-		return r;
-
-	r = populate_table(t, param);
-	if (r) {
-		dm_table_put(t);
-		return r;
-	}
-
-	if (param->flags & DM_PERSISTENT_DEV_FLAG)
-		r = dm_create_with_minor(MINOR(old_decode_dev(param->dev)), &md);
-	else
-		r = dm_create(&md);
-
-	if (r) {
-		dm_table_put(t);
-		return r;
-	}
-
-	/* suspend the device */
-	r = dm_suspend(md);
-	if (r) {
-		DMWARN("suspend failed");
-		dm_table_put(t);
-		dm_put(md);
-		return r;
-	}
-	/* swap in the table */
-	r = dm_swap_table(md, t);
-	if (r) {
-		DMWARN("table swap failed");
-		dm_table_put(t);
-		dm_put(md);
-		return r;
-	}
-
-	/* resume the device */
-	r = dm_resume(md);
-	if (r) {
-		DMWARN("resume failed");
-		dm_table_put(t);
-		dm_put(md);
-		return r;
-	}
-
-	dm_table_put(t);	/* md will have grabbed its own reference */
-
-	set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0);
-	r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md);
-	dm_put(md);
-
-	return r ? r : info(param, user);
-}
-
-/*
- * Build up the status struct for each target
- */
-static int __status(struct mapped_device *md, struct dm_ioctl *param,
-		    char *outbuf, size_t *len)
-{
-	unsigned int i, num_targets;
-	struct dm_target_spec *spec;
-	char *outptr;
-	status_type_t type;
-	struct dm_table *table = dm_get_table(md);
-
-	if (param->flags & DM_STATUS_TABLE_FLAG)
-		type = STATUSTYPE_TABLE;
-	else
-		type = STATUSTYPE_INFO;
-
-	outptr = outbuf;
-
-	/* Get all the target info */
-	num_targets = dm_table_get_num_targets(table);
-	for (i = 0; i < num_targets; i++) {
-		struct dm_target *ti = dm_table_get_target(table, i);
-
-		if (outptr - outbuf +
-		    sizeof(struct dm_target_spec) > param->data_size) {
-			dm_table_put(table);
-			return -ENOMEM;
-		}
-
-		spec = (struct dm_target_spec *) outptr;
-
-		spec->status = 0;
-		spec->sector_start = ti->begin;
-		spec->length = ti->len;
-		strlcpy(spec->target_type, ti->type->name,
-			sizeof(spec->target_type));
-
-		outptr += sizeof(struct dm_target_spec);
-
-		/* Get the status/table string from the target driver */
-		if (ti->type->status)
-			ti->type->status(ti, type, outptr,
-					 outbuf + param->data_size - outptr);
-		else
-			outptr[0] = '\0';
-
-		outptr += strlen(outptr) + 1;
-		_align(outptr, ALIGNMENT);
-		spec->next = outptr - outbuf;
-	}
-
-	param->target_count = num_targets;
-	*len = outptr - outbuf;
-	dm_table_put(table);
-
-	return 0;
-}
-
-/*
- * Return the status of a device as a text string for each
- * target.
- */
-static int get_status(struct dm_ioctl *param, struct dm_ioctl *user)
-{
-	struct mapped_device *md;
-	size_t len = 0;
-	int ret;
-	char *outbuf = NULL;
-
-	md = find_device(param);
-	if (!md)
-		/*
-		 * Device not found - returns cleared exists flag.
-		 */
-		goto out;
-
-	/* We haven't a clue how long the resultant data will be so
-	   just allocate as much as userland has allowed us and make sure
-	   we don't overun it */
-	outbuf = kmalloc(param->data_size, GFP_KERNEL);
-	if (!outbuf)
-		goto out;
-	/*
-	 * Get the status of all targets
-	 */
-	__status(md, param, outbuf, &len);
-
-	/*
-	 * Setup the basic dm_ioctl structure.
-	 */
-	__info(md, param);
-
-      out:
-	if (md)
-		dm_put(md);
-
-	ret = results_to_user(user, param, outbuf, len);
-
-	if (outbuf)
-		kfree(outbuf);
-
-	return ret;
-}
-
-/*
- * Wait for a device to report an event
- */
-static int wait_device_event(struct dm_ioctl *param, struct dm_ioctl *user)
-{
-	struct mapped_device *md;
-	DECLARE_WAITQUEUE(wq, current);
-
-	md = find_device(param);
-	if (!md)
-		/*
-		 * Device not found - returns cleared exists flag.
-		 */
-		goto out;
-
-	/*
-	 * Setup the basic dm_ioctl structure.
-	 */
-	__info(md, param);
-
-	/*
-	 * Wait for a notification event
-	 */
-	set_current_state(TASK_INTERRUPTIBLE);
- 	if (!dm_add_wait_queue(md, &wq, dm_get_event_nr(md))) {
- 		schedule();
- 		dm_remove_wait_queue(md, &wq);
- 	}
-  	set_current_state(TASK_RUNNING);
- 	dm_put(md);
-
-      out:
-	return results_to_user(user, param, NULL, 0);
-}
-
-/*
- * Retrieves a list of devices used by a particular dm device.
- */
-static int dep(struct dm_ioctl *param, struct dm_ioctl *user)
-{
-	int r;
-	unsigned int count;
-	struct mapped_device *md;
-	struct list_head *tmp;
-	size_t len = 0;
-	struct dm_target_deps *deps = NULL;
-	struct dm_table *table;
-
-	md = find_device(param);
-	if (!md)
-		goto out;
-	table = dm_get_table(md);
-
-	/*
-	 * Setup the basic dm_ioctl structure.
-	 */
-	__info(md, param);
-
-	/*
-	 * Count the devices.
-	 */
-	count = 0;
-	list_for_each(tmp, dm_table_get_devices(table))
-	    count++;
-
-	/*
-	 * Allocate a kernel space version of the dm_target_status
-	 * struct.
-	 */
-	if (array_too_big(sizeof(*deps), sizeof(*deps->dev), count)) {
-		dm_table_put(table);
-		dm_put(md);
-		return -ENOMEM;
-	}
-
-	len = sizeof(*deps) + (sizeof(*deps->dev) * count);
-	deps = kmalloc(len, GFP_KERNEL);
-	if (!deps) {
-		dm_table_put(table);
-		dm_put(md);
-		return -ENOMEM;
-	}
-
-	/*
-	 * Fill in the devices.
-	 */
-	deps->count = count;
-	count = 0;
-	list_for_each(tmp, dm_table_get_devices(table)) {
-		struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
-		deps->dev[count++] = old_encode_dev(dd->bdev->bd_dev);
-	}
-	dm_table_put(table);
-	dm_put(md);
-
-      out:
-	r = results_to_user(user, param, deps, len);
-
-	kfree(deps);
-	return r;
-}
-
-static int remove(struct dm_ioctl *param, struct dm_ioctl *user)
-{
-	struct hash_cell *hc;
-
-	down_write(&_hash_lock);
-	hc = *param->uuid ? __get_uuid_cell(param->uuid) :
-		__get_name_cell(param->name);
-	if (!hc) {
-		DMWARN("device doesn't appear to be in the dev hash table.");
-		up_write(&_hash_lock);
-		return -EINVAL;
-	}
-
-	/*
-	 * You may ask the interface to drop its reference to an
-	 * in use device.  This is no different to unlinking a
-	 * file that someone still has open.  The device will not
-	 * actually be destroyed until the last opener closes it.
-	 * The name and uuid of the device (both are interface
-	 * properties) will be available for reuse immediately.
-	 *
-	 * You don't want to drop a _suspended_ device from the
-	 * interface, since that will leave you with no way of
-	 * resuming it.
-	 */
-	if (dm_suspended(hc->md)) {
-		DMWARN("refusing to remove a suspended device.");
-		up_write(&_hash_lock);
-		return -EPERM;
-	}
-
-	__hash_remove(hc);
-	up_write(&_hash_lock);
-	return 0;
-}
-
-static int remove_all(struct dm_ioctl *param, struct dm_ioctl *user)
-{
-	dm_hash_remove_all();
-	return 0;
-}
-
-static int suspend(struct dm_ioctl *param, struct dm_ioctl *user)
-{
-	int r;
-	struct mapped_device *md;
-
-	md = find_device(param);
-	if (!md)
-		return -ENXIO;
-
-	if (param->flags & DM_SUSPEND_FLAG)
-		r = dm_suspend(md);
-	else
-		r = dm_resume(md);
-
-	dm_put(md);
-	return r;
-}
-
-static int reload(struct dm_ioctl *param, struct dm_ioctl *user)
-{
-	int r;
-	struct mapped_device *md;
-	struct dm_table *t;
-
-	r = dm_table_create(&t, get_mode(param), param->target_count);
-	if (r)
-		return r;
-
-	r = populate_table(t, param);
-	if (r) {
-		dm_table_put(t);
-		return r;
-	}
-
-	md = find_device(param);
-	if (!md) {
-		dm_table_put(t);
-		return -ENXIO;
-	}
-
-	r = dm_swap_table(md, t);
-	if (r) {
-		dm_put(md);
-		dm_table_put(t);
-		return r;
-	}
-	dm_table_put(t);	/* md will have taken its own reference */
-
-	set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0);
-	dm_put(md);
-
-	r = info(param, user);
-	return r;
-}
-
-static int rename(struct dm_ioctl *param, struct dm_ioctl *user)
-{
-	int r;
-	char *new_name = (char *) param + param->data_start;
-
-	if (valid_str(new_name, (void *) param,
-		      (void *) param + param->data_size)) {
-		DMWARN("Invalid new logical volume name supplied.");
-		return -EINVAL;
-	}
-
-	r = check_name(new_name);
-	if (r)
-		return r;
-
-	return dm_hash_rename(param->name, new_name);
-}
-
-
-/*-----------------------------------------------------------------
- * Implementation of open/close/ioctl on the special char
- * device.
- *---------------------------------------------------------------*/
-static ioctl_fn lookup_ioctl(unsigned int cmd)
-{
-	static struct {
-		int cmd;
-		ioctl_fn fn;
-	} _ioctls[] = {
-		{DM_VERSION_CMD, NULL},	/* version is dealt with elsewhere */
-		{DM_REMOVE_ALL_CMD, remove_all},
-		{DM_DEV_CREATE_CMD, create},
-		{DM_DEV_REMOVE_CMD, remove},
-		{DM_DEV_RELOAD_CMD, reload},
-		{DM_DEV_RENAME_CMD, rename},
-		{DM_DEV_SUSPEND_CMD, suspend},
-		{DM_DEV_DEPS_CMD, dep},
-		{DM_DEV_STATUS_CMD, info},
-		{DM_TARGET_STATUS_CMD, get_status},
-		{DM_TARGET_WAIT_CMD, wait_device_event},
-	};
-
-	return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn;
-}
-
-/*
- * As well as checking the version compatibility this always
- * copies the kernel interface version out.
- */
-static int check_version(unsigned int cmd, struct dm_ioctl *user)
-{
-	uint32_t version[3];
-	int r = 0;
-
-	if (copy_from_user(version, user->version, sizeof(version)))
-		return -EFAULT;
-
-	if ((DM_VERSION_MAJOR != version[0]) ||
-	    (DM_VERSION_MINOR < version[1])) {
-		DMWARN("ioctl interface mismatch: "
-		       "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)",
-		       DM_VERSION_MAJOR, DM_VERSION_MINOR,
-		       DM_VERSION_PATCHLEVEL,
-		       version[0], version[1], version[2], cmd);
-		r = -EINVAL;
-	}
-
-	/*
-	 * Fill in the kernel version.
-	 */
-	version[0] = DM_VERSION_MAJOR;
-	version[1] = DM_VERSION_MINOR;
-	version[2] = DM_VERSION_PATCHLEVEL;
-	if (copy_to_user(user->version, version, sizeof(version)))
-		return -EFAULT;
-
-	return r;
-}
-
-static void free_params(struct dm_ioctl *param)
-{
-	vfree(param);
-}
-
-static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param)
-{
-	struct dm_ioctl tmp, *dmi;
-
-	if (copy_from_user(&tmp, user, sizeof(tmp)))
-		return -EFAULT;
-
-	if (tmp.data_size < sizeof(tmp))
-		return -EINVAL;
-
-	dmi = (struct dm_ioctl *) vmalloc(tmp.data_size);
-	if (!dmi)
-		return -ENOMEM;
-
-	if (copy_from_user(dmi, user, tmp.data_size)) {
-		vfree(dmi);
-		return -EFAULT;
-	}
-
-	*param = dmi;
-	return 0;
-}
-
-static int validate_params(uint cmd, struct dm_ioctl *param)
-{
-	/* Ignores parameters */
-	if (cmd == DM_REMOVE_ALL_CMD)
-		return 0;
-
-	/* Unless creating, either name of uuid but not both */
-	if (cmd != DM_DEV_CREATE_CMD) {
-		if ((!*param->uuid && !*param->name) ||
-		    (*param->uuid && *param->name)) {
-			DMWARN("one of name or uuid must be supplied");
-			return -EINVAL;
-		}
-	}
-
-	/* Ensure strings are terminated */
-	param->name[DM_NAME_LEN - 1] = '\0';
-	param->uuid[DM_UUID_LEN - 1] = '\0';
-
-	return 0;
-}
-
-static int ctl_ioctl(struct inode *inode, struct file *file,
-		     uint command, ulong u)
-{
-	int r = 0;
-	unsigned int cmd;
-	struct dm_ioctl *param;
-	struct dm_ioctl *user = (struct dm_ioctl *) u;
-	ioctl_fn fn = NULL;
-
-	/* only root can play with this */
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-
-	if (_IOC_TYPE(command) != DM_IOCTL)
-		return -ENOTTY;
-
-	cmd = _IOC_NR(command);
-
-	/*
-	 * Check the interface version passed in.  This also
-	 * writes out the kernels interface version.
-	 */
-	r = check_version(cmd, user);
-	if (r)
-		return r;
-
-	/*
-	 * Nothing more to do for the version command.
-	 */
-	if (cmd == DM_VERSION_CMD)
-		return 0;
-
-	fn = lookup_ioctl(cmd);
-	if (!fn) {
-		DMWARN("dm_ctl_ioctl: unknown command 0x%x", command);
-		return -ENOTTY;
-	}
-
-	/*
-	 * Copy the parameters into kernel space.
-	 */
-	r = copy_params(user, &param);
-	if (r)
-		return r;
-
-	r = validate_params(cmd, param);
-	if (r) {
-		free_params(param);
-		return r;
-	}
-
-	r = fn(param, user);
-	free_params(param);
-	return r;
-}
-
-static struct file_operations _ctl_fops = {
-	.ioctl	 = ctl_ioctl,
-	.owner	 = THIS_MODULE,
-};
-
-static struct miscdevice _dm_misc = {
-	.minor		= MISC_DYNAMIC_MINOR,
-	.name		= DM_NAME,
-	.devfs_name	= "mapper/control",
-	.fops		= &_ctl_fops
-};
-
-/*
- * Create misc character device and link to DM_DIR/control.
- */
-int __init dm_interface_init(void)
-{
-	int r;
-
-	r = dm_hash_init();
-	if (r)
-		return r;
-
-	r = misc_register(&_dm_misc);
-	if (r) {
-		DMERR("misc_register failed for control device");
-		dm_hash_exit();
-		return r;
-	}
-
-	DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR,
-	       DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA,
-	       DM_DRIVER_EMAIL);
-	return 0;
-
-	if (misc_deregister(&_dm_misc) < 0)
-		DMERR("misc_deregister failed for control device");
-	dm_hash_exit();
-	return r;
-}
-
-void dm_interface_exit(void)
-{
-	if (misc_deregister(&_dm_misc) < 0)
-		DMERR("misc_deregister failed for control device");
-	dm_hash_exit();
-}
--- diff/drivers/md/dm-ioctl-v4.c	2004-01-19 10:22:56.000000000 +0000
+++ source/drivers/md/dm-ioctl-v4.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,1264 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
- *
- * This file is released under the GPL.
- */
-
-#include "dm.h"
-
-#include <linux/module.h>
-#include <linux/vmalloc.h>
-#include <linux/miscdevice.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/slab.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/dm-ioctl.h>
-
-#include <asm/uaccess.h>
-
-#define DM_DRIVER_EMAIL "dm@uk.sistina.com"
-
-/*-----------------------------------------------------------------
- * The ioctl interface needs to be able to look up devices by
- * name or uuid.
- *---------------------------------------------------------------*/
-struct hash_cell {
-	struct list_head name_list;
-	struct list_head uuid_list;
-
-	char *name;
-	char *uuid;
-	struct mapped_device *md;
-	struct dm_table *new_map;
-};
-
-#define NUM_BUCKETS 64
-#define MASK_BUCKETS (NUM_BUCKETS - 1)
-static struct list_head _name_buckets[NUM_BUCKETS];
-static struct list_head _uuid_buckets[NUM_BUCKETS];
-
-void dm_hash_remove_all(void);
-
-/*
- * Guards access to both hash tables.
- */
-static DECLARE_RWSEM(_hash_lock);
-
-static void init_buckets(struct list_head *buckets)
-{
-	unsigned int i;
-
-	for (i = 0; i < NUM_BUCKETS; i++)
-		INIT_LIST_HEAD(buckets + i);
-}
-
-int dm_hash_init(void)
-{
-	init_buckets(_name_buckets);
-	init_buckets(_uuid_buckets);
-	devfs_mk_dir(DM_DIR);
-	return 0;
-}
-
-void dm_hash_exit(void)
-{
-	dm_hash_remove_all();
-	devfs_remove(DM_DIR);
-}
-
-/*-----------------------------------------------------------------
- * Hash function:
- * We're not really concerned with the str hash function being
- * fast since it's only used by the ioctl interface.
- *---------------------------------------------------------------*/
-static unsigned int hash_str(const char *str)
-{
-	const unsigned int hash_mult = 2654435387U;
-	unsigned int h = 0;
-
-	while (*str)
-		h = (h + (unsigned int) *str++) * hash_mult;
-
-	return h & MASK_BUCKETS;
-}
-
-/*-----------------------------------------------------------------
- * Code for looking up a device by name
- *---------------------------------------------------------------*/
-static struct hash_cell *__get_name_cell(const char *str)
-{
-	struct list_head *tmp;
-	struct hash_cell *hc;
-	unsigned int h = hash_str(str);
-
-	list_for_each (tmp, _name_buckets + h) {
-		hc = list_entry(tmp, struct hash_cell, name_list);
-		if (!strcmp(hc->name, str))
-			return hc;
-	}
-
-	return NULL;
-}
-
-static struct hash_cell *__get_uuid_cell(const char *str)
-{
-	struct list_head *tmp;
-	struct hash_cell *hc;
-	unsigned int h = hash_str(str);
-
-	list_for_each (tmp, _uuid_buckets + h) {
-		hc = list_entry(tmp, struct hash_cell, uuid_list);
-		if (!strcmp(hc->uuid, str))
-			return hc;
-	}
-
-	return NULL;
-}
-
-/*-----------------------------------------------------------------
- * Inserting, removing and renaming a device.
- *---------------------------------------------------------------*/
-static inline char *kstrdup(const char *str)
-{
-	char *r = kmalloc(strlen(str) + 1, GFP_KERNEL);
-	if (r)
-		strcpy(r, str);
-	return r;
-}
-
-static struct hash_cell *alloc_cell(const char *name, const char *uuid,
-				    struct mapped_device *md)
-{
-	struct hash_cell *hc;
-
-	hc = kmalloc(sizeof(*hc), GFP_KERNEL);
-	if (!hc)
-		return NULL;
-
-	hc->name = kstrdup(name);
-	if (!hc->name) {
-		kfree(hc);
-		return NULL;
-	}
-
-	if (!uuid)
-		hc->uuid = NULL;
-
-	else {
-		hc->uuid = kstrdup(uuid);
-		if (!hc->uuid) {
-			kfree(hc->name);
-			kfree(hc);
-			return NULL;
-		}
-	}
-
-	INIT_LIST_HEAD(&hc->name_list);
-	INIT_LIST_HEAD(&hc->uuid_list);
-	hc->md = md;
-	hc->new_map = NULL;
-	return hc;
-}
-
-static void free_cell(struct hash_cell *hc)
-{
-	if (hc) {
-		kfree(hc->name);
-		kfree(hc->uuid);
-		kfree(hc);
-	}
-}
-
-/*
- * devfs stuff.
- */
-static int register_with_devfs(struct hash_cell *hc)
-{
-	struct gendisk *disk = dm_disk(hc->md);
-
-	devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
-		      S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
-		      DM_DIR "/%s", hc->name);
-	return 0;
-}
-
-static int unregister_with_devfs(struct hash_cell *hc)
-{
-	devfs_remove(DM_DIR"/%s", hc->name);
-	return 0;
-}
-
-/*
- * The kdev_t and uuid of a device can never change once it is
- * initially inserted.
- */
-int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md)
-{
-	struct hash_cell *cell;
-
-	/*
-	 * Allocate the new cells.
-	 */
-	cell = alloc_cell(name, uuid, md);
-	if (!cell)
-		return -ENOMEM;
-
-	/*
-	 * Insert the cell into both hash tables.
-	 */
-	down_write(&_hash_lock);
-	if (__get_name_cell(name))
-		goto bad;
-
-	list_add(&cell->name_list, _name_buckets + hash_str(name));
-
-	if (uuid) {
-		if (__get_uuid_cell(uuid)) {
-			list_del(&cell->name_list);
-			goto bad;
-		}
-		list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid));
-	}
-	register_with_devfs(cell);
-	dm_get(md);
-	up_write(&_hash_lock);
-
-	return 0;
-
- bad:
-	up_write(&_hash_lock);
-	free_cell(cell);
-	return -EBUSY;
-}
-
-void __hash_remove(struct hash_cell *hc)
-{
-	/* remove from the dev hash */
-	list_del(&hc->uuid_list);
-	list_del(&hc->name_list);
-	unregister_with_devfs(hc);
-	dm_put(hc->md);
-	if (hc->new_map)
-		dm_table_put(hc->new_map);
-	free_cell(hc);
-}
-
-void dm_hash_remove_all(void)
-{
-	int i;
-	struct hash_cell *hc;
-	struct list_head *tmp, *n;
-
-	down_write(&_hash_lock);
-	for (i = 0; i < NUM_BUCKETS; i++) {
-		list_for_each_safe (tmp, n, _name_buckets + i) {
-			hc = list_entry(tmp, struct hash_cell, name_list);
-			__hash_remove(hc);
-		}
-	}
-	up_write(&_hash_lock);
-}
-
-int dm_hash_rename(const char *old, const char *new)
-{
-	char *new_name, *old_name;
-	struct hash_cell *hc;
-
-	/*
-	 * duplicate new.
-	 */
-	new_name = kstrdup(new);
-	if (!new_name)
-		return -ENOMEM;
-
-	down_write(&_hash_lock);
-
-	/*
-	 * Is new free ?
-	 */
-	hc = __get_name_cell(new);
-	if (hc) {
-		DMWARN("asked to rename to an already existing name %s -> %s",
-		       old, new);
-		up_write(&_hash_lock);
-		kfree(new_name);
-		return -EBUSY;
-	}
-
-	/*
-	 * Is there such a device as 'old' ?
-	 */
-	hc = __get_name_cell(old);
-	if (!hc) {
-		DMWARN("asked to rename a non existent device %s -> %s",
-		       old, new);
-		up_write(&_hash_lock);
-		kfree(new_name);
-		return -ENXIO;
-	}
-
-	/*
-	 * rename and move the name cell.
-	 */
-	unregister_with_devfs(hc);
-
-	list_del(&hc->name_list);
-	old_name = hc->name;
-	hc->name = new_name;
-	list_add(&hc->name_list, _name_buckets + hash_str(new_name));
-
-	/* rename the device node in devfs */
-	register_with_devfs(hc);
-
-	up_write(&_hash_lock);
-	kfree(old_name);
-	return 0;
-}
-
-/*-----------------------------------------------------------------
- * Implementation of the ioctl commands
- *---------------------------------------------------------------*/
-/*
- * All the ioctl commands get dispatched to functions with this
- * prototype.
- */
-typedef int (*ioctl_fn)(struct dm_ioctl *param, size_t param_size);
-
-static int remove_all(struct dm_ioctl *param, size_t param_size)
-{
-	dm_hash_remove_all();
-	param->data_size = 0;
-	return 0;
-}
-
-/*
- * Round up the ptr to an 8-byte boundary.
- */
-#define ALIGN_MASK 7
-static inline void *align_ptr(void *ptr)
-{
-	return (void *) (((size_t) (ptr + ALIGN_MASK)) & ~ALIGN_MASK);
-}
-
-/*
- * Retrieves the data payload buffer from an already allocated
- * struct dm_ioctl.
- */
-static void *get_result_buffer(struct dm_ioctl *param, size_t param_size,
-			       size_t *len)
-{
-	param->data_start = align_ptr(param + 1) - (void *) param;
-
-	if (param->data_start < param_size)
-		*len = param_size - param->data_start;
-	else
-		*len = 0;
-
-	return ((void *) param) + param->data_start;
-}
-
-static int list_devices(struct dm_ioctl *param, size_t param_size)
-{
-	unsigned int i;
-	struct hash_cell *hc;
-	size_t len, needed = 0;
-	struct gendisk *disk;
-	struct dm_name_list *nl, *old_nl = NULL;
-
-	down_write(&_hash_lock);
-
-	/*
-	 * Loop through all the devices working out how much
-	 * space we need.
-	 */
-	for (i = 0; i < NUM_BUCKETS; i++) {
-		list_for_each_entry (hc, _name_buckets + i, name_list) {
-			needed += sizeof(struct dm_name_list);
-			needed += strlen(hc->name);
-			needed += ALIGN_MASK;
-		}
-	}
-
-	/*
-	 * Grab our output buffer.
-	 */
-	nl = get_result_buffer(param, param_size, &len);
-	if (len < needed) {
-		param->flags |= DM_BUFFER_FULL_FLAG;
-		goto out;
-	}
-	param->data_size = param->data_start + needed;
-
-	nl->dev = 0;	/* Flags no data */
-
-	/*
-	 * Now loop through filling out the names.
-	 */
-	for (i = 0; i < NUM_BUCKETS; i++) {
-		list_for_each_entry (hc, _name_buckets + i, name_list) {
-			if (old_nl)
-				old_nl->next = (uint32_t) ((void *) nl -
-							   (void *) old_nl);
-			disk = dm_disk(hc->md);
-			nl->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor));
-			nl->next = 0;
-			strcpy(nl->name, hc->name);
-
-			old_nl = nl;
-			nl = align_ptr(((void *) ++nl) + strlen(hc->name) + 1);
-		}
-	}
-
- out:
-	up_write(&_hash_lock);
-	return 0;
-}
-
-static int check_name(const char *name)
-{
-	if (strchr(name, '/')) {
-		DMWARN("invalid device name");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-/*
- * Fills in a dm_ioctl structure, ready for sending back to
- * userland.
- */
-static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
-{
-	struct gendisk *disk = dm_disk(md);
-	struct dm_table *table;
-	struct block_device *bdev;
-
-	param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG |
-			  DM_ACTIVE_PRESENT_FLAG);
-
-	if (dm_suspended(md))
-		param->flags |= DM_SUSPEND_FLAG;
-
-	bdev = bdget_disk(disk, 0);
-	if (!bdev)
-		return -ENXIO;
-
-	param->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor));
-
-	/*
-	 * Yes, this will be out of date by the time it gets back
-	 * to userland, but it is still very useful ofr
-	 * debugging.
-	 */
-	param->open_count = bdev->bd_openers;
-	bdput(bdev);
-
-	if (disk->policy)
-		param->flags |= DM_READONLY_FLAG;
-
-	param->event_nr = dm_get_event_nr(md);
-
-	table = dm_get_table(md);
-	if (table) {
-		param->flags |= DM_ACTIVE_PRESENT_FLAG;
-		param->target_count = dm_table_get_num_targets(table);
-		dm_table_put(table);
-	} else
-		param->target_count = 0;
-
-	return 0;
-}
-
-static int dev_create(struct dm_ioctl *param, size_t param_size)
-{
-	int r;
-	struct mapped_device *md;
-
-	r = check_name(param->name);
-	if (r)
-		return r;
-
-	if (param->flags & DM_PERSISTENT_DEV_FLAG)
-		r = dm_create_with_minor(MINOR(huge_decode_dev(param->dev)), &md);
-	else
-		r = dm_create(&md);
-
-	if (r)
-		return r;
-
-	r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md);
-	if (r) {
-		dm_put(md);
-		return r;
-	}
-
-	param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
-
-	r = __dev_status(md, param);
-	dm_put(md);
-
-	return r;
-}
-
-/*
- * Always use UUID for lookups if it's present, otherwise use name.
- */
-static inline struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param)
-{
-	return *param->uuid ?
-	    __get_uuid_cell(param->uuid) : __get_name_cell(param->name);
-}
-
-static inline struct mapped_device *find_device(struct dm_ioctl *param)
-{
-	struct hash_cell *hc;
-	struct mapped_device *md = NULL;
-
-	down_read(&_hash_lock);
-	hc = __find_device_hash_cell(param);
-	if (hc) {
-		md = hc->md;
-
-		/*
-		 * Sneakily write in both the name and the uuid
-		 * while we have the cell.
-		 */
-		strncpy(param->name, hc->name, sizeof(param->name));
-		if (hc->uuid)
-			strncpy(param->uuid, hc->uuid, sizeof(param->uuid)-1);
-		else
-			param->uuid[0] = '\0';
-
-		if (hc->new_map)
-			param->flags |= DM_INACTIVE_PRESENT_FLAG;
-		else
-			param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
-
-		dm_get(md);
-	}
-	up_read(&_hash_lock);
-
-	return md;
-}
-
-static int dev_remove(struct dm_ioctl *param, size_t param_size)
-{
-	struct hash_cell *hc;
-
-	down_write(&_hash_lock);
-	hc = __find_device_hash_cell(param);
-
-	if (!hc) {
-		DMWARN("device doesn't appear to be in the dev hash table.");
-		up_write(&_hash_lock);
-		return -ENXIO;
-	}
-
-	__hash_remove(hc);
-	up_write(&_hash_lock);
-	param->data_size = 0;
-	return 0;
-}
-
-/*
- * Check a string doesn't overrun the chunk of
- * memory we copied from userland.
- */
-static int invalid_str(char *str, void *end)
-{
-	while ((void *) str < end)
-		if (!*str++)
-			return 0;
-
-	return -EINVAL;
-}
-
-static int dev_rename(struct dm_ioctl *param, size_t param_size)
-{
-	int r;
-	char *new_name = (char *) param + param->data_start;
-
-	if (new_name < (char *) (param + 1) ||
-	    invalid_str(new_name, (void *) param + param_size)) {
-		DMWARN("Invalid new logical volume name supplied.");
-		return -EINVAL;
-	}
-
-	r = check_name(new_name);
-	if (r)
-		return r;
-
-	param->data_size = 0;
-	return dm_hash_rename(param->name, new_name);
-}
-
-static int do_suspend(struct dm_ioctl *param)
-{
-	int r = 0;
-	struct mapped_device *md;
-
-	md = find_device(param);
-	if (!md)
-		return -ENXIO;
-
-	if (!dm_suspended(md))
-		r = dm_suspend(md);
-
-	if (!r)
-		r = __dev_status(md, param);
-
-	dm_put(md);
-	return r;
-}
-
-static int do_resume(struct dm_ioctl *param)
-{
-	int r = 0;
-	struct hash_cell *hc;
-	struct mapped_device *md;
-	struct dm_table *new_map;
-
-	down_write(&_hash_lock);
-
-	hc = __find_device_hash_cell(param);
-	if (!hc) {
-		DMWARN("device doesn't appear to be in the dev hash table.");
-		up_write(&_hash_lock);
-		return -ENXIO;
-	}
-
-	md = hc->md;
-	dm_get(md);
-
-	new_map = hc->new_map;
-	hc->new_map = NULL;
-	param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
-
-	up_write(&_hash_lock);
-
-	/* Do we need to load a new map ? */
-	if (new_map) {
-		/* Suspend if it isn't already suspended */
-		if (!dm_suspended(md))
-			dm_suspend(md);
-
-		r = dm_swap_table(md, new_map);
-		if (r) {
-			dm_put(md);
-			dm_table_put(new_map);
-			return r;
-		}
-
-		if (dm_table_get_mode(new_map) & FMODE_WRITE)
-			set_disk_ro(dm_disk(md), 0);
-		else
-			set_disk_ro(dm_disk(md), 1);
-
-		dm_table_put(new_map);
-	}
-
-	if (dm_suspended(md))
-		r = dm_resume(md);
-
-	if (!r)
-		r = __dev_status(md, param);
-
-	dm_put(md);
-	return r;
-}
-
-/*
- * Set or unset the suspension state of a device.
- * If the device already is in the requested state we just return its status.
- */
-static int dev_suspend(struct dm_ioctl *param, size_t param_size)
-{
-	if (param->flags & DM_SUSPEND_FLAG)
-		return do_suspend(param);
-
-	return do_resume(param);
-}
-
-/*
- * Copies device info back to user space, used by
- * the create and info ioctls.
- */
-static int dev_status(struct dm_ioctl *param, size_t param_size)
-{
-	int r;
-	struct mapped_device *md;
-
-	md = find_device(param);
-	if (!md)
-		return -ENXIO;
-
-	r = __dev_status(md, param);
-	dm_put(md);
-	return r;
-}
-
-/*
- * Build up the status struct for each target
- */
-static void retrieve_status(struct dm_table *table,
-			    struct dm_ioctl *param, size_t param_size)
-{
-	unsigned int i, num_targets;
-	struct dm_target_spec *spec;
-	char *outbuf, *outptr;
-	status_type_t type;
-	size_t remaining, len, used = 0;
-
-	outptr = outbuf = get_result_buffer(param, param_size, &len);
-
-	if (param->flags & DM_STATUS_TABLE_FLAG)
-		type = STATUSTYPE_TABLE;
-	else
-		type = STATUSTYPE_INFO;
-
-	/* Get all the target info */
-	num_targets = dm_table_get_num_targets(table);
-	for (i = 0; i < num_targets; i++) {
-		struct dm_target *ti = dm_table_get_target(table, i);
-
-		remaining = len - (outptr - outbuf);
-		if (remaining < sizeof(struct dm_target_spec)) {
-			param->flags |= DM_BUFFER_FULL_FLAG;
-			break;
-		}
-
-		spec = (struct dm_target_spec *) outptr;
-
-		spec->status = 0;
-		spec->sector_start = ti->begin;
-		spec->length = ti->len;
-		strncpy(spec->target_type, ti->type->name,
-			sizeof(spec->target_type));
-
-		outptr += sizeof(struct dm_target_spec);
-		remaining = len - (outptr - outbuf);
-
-		/* Get the status/table string from the target driver */
-		if (ti->type->status) {
-			if (ti->type->status(ti, type, outptr, remaining)) {
-				param->flags |= DM_BUFFER_FULL_FLAG;
-				break;
-			}
-		} else
-			outptr[0] = '\0';
-
-		outptr += strlen(outptr) + 1;
-		used = param->data_start + (outptr - outbuf);
-
-		align_ptr(outptr);
-		spec->next = outptr - outbuf;
-	}
-
-	if (used)
-		param->data_size = used;
-
-	param->target_count = num_targets;
-}
-
-/*
- * Wait for a device to report an event
- */
-static int dev_wait(struct dm_ioctl *param, size_t param_size)
-{
-	int r;
-	struct mapped_device *md;
-	struct dm_table *table;
-	DECLARE_WAITQUEUE(wq, current);
-
-	md = find_device(param);
-	if (!md)
-		return -ENXIO;
-
-	/*
-	 * Wait for a notification event
-	 */
-	set_current_state(TASK_INTERRUPTIBLE);
-	if (!dm_add_wait_queue(md, &wq, param->event_nr)) {
-		schedule();
-		dm_remove_wait_queue(md, &wq);
-	}
- 	set_current_state(TASK_RUNNING);
-
-	/*
-	 * The userland program is going to want to know what
-	 * changed to trigger the event, so we may as well tell
-	 * him and save an ioctl.
-	 */
-	r = __dev_status(md, param);
-	if (r)
-		goto out;
-
-	table = dm_get_table(md);
-	if (table) {
-		retrieve_status(table, param, param_size);
-		dm_table_put(table);
-	}
-
- out:
-	dm_put(md);
-	return r;
-}
-
-static inline int get_mode(struct dm_ioctl *param)
-{
-	int mode = FMODE_READ | FMODE_WRITE;
-
-	if (param->flags & DM_READONLY_FLAG)
-		mode = FMODE_READ;
-
-	return mode;
-}
-
-static int next_target(struct dm_target_spec *last, uint32_t next, void *end,
-		       struct dm_target_spec **spec, char **target_params)
-{
-	*spec = (struct dm_target_spec *) ((unsigned char *) last + next);
-	*target_params = (char *) (*spec + 1);
-
-	if (*spec < (last + 1))
-		return -EINVAL;
-
-	return invalid_str(*target_params, end);
-}
-
-static int populate_table(struct dm_table *table,
-			  struct dm_ioctl *param, size_t param_size)
-{
-	int r;
-	unsigned int i = 0;
-	struct dm_target_spec *spec = (struct dm_target_spec *) param;
-	uint32_t next = param->data_start;
-	void *end = (void *) param + param_size;
-	char *target_params;
-
-	if (!param->target_count) {
-		DMWARN("populate_table: no targets specified");
-		return -EINVAL;
-	}
-
-	for (i = 0; i < param->target_count; i++) {
-
-		r = next_target(spec, next, end, &spec, &target_params);
-		if (r) {
-			DMWARN("unable to find target");
-			return r;
-		}
-
-		r = dm_table_add_target(table, spec->target_type,
-					(sector_t) spec->sector_start,
-					(sector_t) spec->length,
-					target_params);
-		if (r) {
-			DMWARN("error adding target to table");
-			return r;
-		}
-
-		next = spec->next;
-	}
-
-	return dm_table_complete(table);
-}
-
-static int table_load(struct dm_ioctl *param, size_t param_size)
-{
-	int r;
-	struct hash_cell *hc;
-	struct dm_table *t;
-
-	r = dm_table_create(&t, get_mode(param), param->target_count);
-	if (r)
-		return r;
-
-	r = populate_table(t, param, param_size);
-	if (r) {
-		dm_table_put(t);
-		return r;
-	}
-
-	down_write(&_hash_lock);
-	hc = __find_device_hash_cell(param);
-	if (!hc) {
-		DMWARN("device doesn't appear to be in the dev hash table.");
-		up_write(&_hash_lock);
-		return -ENXIO;
-	}
-
-	if (hc->new_map)
-		dm_table_put(hc->new_map);
-	hc->new_map = t;
-	param->flags |= DM_INACTIVE_PRESENT_FLAG;
-
-	r = __dev_status(hc->md, param);
-	up_write(&_hash_lock);
-	return r;
-}
-
-static int table_clear(struct dm_ioctl *param, size_t param_size)
-{
-	int r;
-	struct hash_cell *hc;
-
-	down_write(&_hash_lock);
-
-	hc = __find_device_hash_cell(param);
-	if (!hc) {
-		DMWARN("device doesn't appear to be in the dev hash table.");
-		up_write(&_hash_lock);
-		return -ENXIO;
-	}
-
-	if (hc->new_map) {
-		dm_table_put(hc->new_map);
-		hc->new_map = NULL;
-	}
-
-	param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
-
-	r = __dev_status(hc->md, param);
-	up_write(&_hash_lock);
-	return r;
-}
-
-/*
- * Retrieves a list of devices used by a particular dm device.
- */
-static void retrieve_deps(struct dm_table *table,
-			  struct dm_ioctl *param, size_t param_size)
-{
-	unsigned int count = 0;
-	struct list_head *tmp;
-	size_t len, needed;
-	struct dm_target_deps *deps;
-
-	deps = get_result_buffer(param, param_size, &len);
-
-	/*
-	 * Count the devices.
-	 */
-	list_for_each(tmp, dm_table_get_devices(table))
-		count++;
-
-	/*
-	 * Check we have enough space.
-	 */
-	needed = sizeof(*deps) + (sizeof(*deps->dev) * count);
-	if (len < needed) {
-		param->flags |= DM_BUFFER_FULL_FLAG;
-		return;
-	}
-
-	/*
-	 * Fill in the devices.
-	 */
-	deps->count = count;
-	count = 0;
-	list_for_each(tmp, dm_table_get_devices(table)) {
-		struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
-		deps->dev[count++] = huge_encode_dev(dd->bdev->bd_dev);
-	}
-
-	param->data_size = param->data_start + needed;
-}
-
-static int table_deps(struct dm_ioctl *param, size_t param_size)
-{
-	int r = 0;
-	struct mapped_device *md;
-	struct dm_table *table;
-
-	md = find_device(param);
-	if (!md)
-		return -ENXIO;
-
-	r = __dev_status(md, param);
-	if (r)
-		goto out;
-
-	table = dm_get_table(md);
-	if (table) {
-		retrieve_deps(table, param, param_size);
-		dm_table_put(table);
-	}
-
- out:
-	dm_put(md);
-	return r;
-}
-
-/*
- * Return the status of a device as a text string for each
- * target.
- */
-static int table_status(struct dm_ioctl *param, size_t param_size)
-{
-	int r;
-	struct mapped_device *md;
-	struct dm_table *table;
-
-	md = find_device(param);
-	if (!md)
-		return -ENXIO;
-
-	r = __dev_status(md, param);
-	if (r)
-		goto out;
-
-	table = dm_get_table(md);
-	if (table) {
-		retrieve_status(table, param, param_size);
-		dm_table_put(table);
-	}
-
- out:
-	dm_put(md);
-	return r;
-}
-
-/*-----------------------------------------------------------------
- * Implementation of open/close/ioctl on the special char
- * device.
- *---------------------------------------------------------------*/
-static ioctl_fn lookup_ioctl(unsigned int cmd)
-{
-	static struct {
-		int cmd;
-		ioctl_fn fn;
-	} _ioctls[] = {
-		{DM_VERSION_CMD, NULL},	/* version is dealt with elsewhere */
-		{DM_REMOVE_ALL_CMD, remove_all},
-		{DM_LIST_DEVICES_CMD, list_devices},
-
-		{DM_DEV_CREATE_CMD, dev_create},
-		{DM_DEV_REMOVE_CMD, dev_remove},
-		{DM_DEV_RENAME_CMD, dev_rename},
-		{DM_DEV_SUSPEND_CMD, dev_suspend},
-		{DM_DEV_STATUS_CMD, dev_status},
-		{DM_DEV_WAIT_CMD, dev_wait},
-
-		{DM_TABLE_LOAD_CMD, table_load},
-		{DM_TABLE_CLEAR_CMD, table_clear},
-		{DM_TABLE_DEPS_CMD, table_deps},
-		{DM_TABLE_STATUS_CMD, table_status}
-	};
-
-	return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn;
-}
-
-/*
- * As well as checking the version compatibility this always
- * copies the kernel interface version out.
- */
-static int check_version(unsigned int cmd, struct dm_ioctl *user)
-{
-	uint32_t version[3];
-	int r = 0;
-
-	if (copy_from_user(version, user->version, sizeof(version)))
-		return -EFAULT;
-
-	if ((DM_VERSION_MAJOR != version[0]) ||
-	    (DM_VERSION_MINOR < version[1])) {
-		DMWARN("ioctl interface mismatch: "
-		       "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)",
-		       DM_VERSION_MAJOR, DM_VERSION_MINOR,
-		       DM_VERSION_PATCHLEVEL,
-		       version[0], version[1], version[2], cmd);
-		r = -EINVAL;
-	}
-
-	/*
-	 * Fill in the kernel version.
-	 */
-	version[0] = DM_VERSION_MAJOR;
-	version[1] = DM_VERSION_MINOR;
-	version[2] = DM_VERSION_PATCHLEVEL;
-	if (copy_to_user(user->version, version, sizeof(version)))
-		return -EFAULT;
-
-	return r;
-}
-
-static void free_params(struct dm_ioctl *param)
-{
-	vfree(param);
-}
-
-static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param)
-{
-	struct dm_ioctl tmp, *dmi;
-
-	if (copy_from_user(&tmp, user, sizeof(tmp)))
-		return -EFAULT;
-
-	if (tmp.data_size < sizeof(tmp))
-		return -EINVAL;
-
-	dmi = (struct dm_ioctl *) vmalloc(tmp.data_size);
-	if (!dmi)
-		return -ENOMEM;
-
-	if (copy_from_user(dmi, user, tmp.data_size)) {
-		vfree(dmi);
-		return -EFAULT;
-	}
-
-	*param = dmi;
-	return 0;
-}
-
-static int validate_params(uint cmd, struct dm_ioctl *param)
-{
-	/* Always clear this flag */
-	param->flags &= ~DM_BUFFER_FULL_FLAG;
-
-	/* Ignores parameters */
-	if (cmd == DM_REMOVE_ALL_CMD || cmd == DM_LIST_DEVICES_CMD)
-		return 0;
-
-	/* Unless creating, either name or uuid but not both */
-	if (cmd != DM_DEV_CREATE_CMD) {
-		if ((!*param->uuid && !*param->name) ||
-		    (*param->uuid && *param->name)) {
-			DMWARN("one of name or uuid must be supplied, cmd(%u)",
-			       cmd);
-			return -EINVAL;
-		}
-	}
-
-	/* Ensure strings are terminated */
-	param->name[DM_NAME_LEN - 1] = '\0';
-	param->uuid[DM_UUID_LEN - 1] = '\0';
-
-	return 0;
-}
-
-static int ctl_ioctl(struct inode *inode, struct file *file,
-		     uint command, ulong u)
-{
-	int r = 0;
-	unsigned int cmd;
-	struct dm_ioctl *param;
-	struct dm_ioctl *user = (struct dm_ioctl *) u;
-	ioctl_fn fn = NULL;
-	size_t param_size;
-
-	/* only root can play with this */
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-
-	if (_IOC_TYPE(command) != DM_IOCTL)
-		return -ENOTTY;
-
-	cmd = _IOC_NR(command);
-
-	/*
-	 * Check the interface version passed in.  This also
-	 * writes out the kernel's interface version.
-	 */
-	r = check_version(cmd, user);
-	if (r)
-		return r;
-
-	/*
-	 * Nothing more to do for the version command.
-	 */
-	if (cmd == DM_VERSION_CMD)
-		return 0;
-
-	fn = lookup_ioctl(cmd);
-	if (!fn) {
-		DMWARN("dm_ctl_ioctl: unknown command 0x%x", command);
-		return -ENOTTY;
-	}
-
-	/*
-	 * Trying to avoid low memory issues when a device is
-	 * suspended.
-	 */
-	current->flags |= PF_MEMALLOC;
-
-	/*
-	 * Copy the parameters into kernel space.
-	 */
-	r = copy_params(user, &param);
-	if (r) {
-		current->flags &= ~PF_MEMALLOC;
-		return r;
-	}
-
-	/*
-	 * FIXME: eventually we will remove the PF_MEMALLOC flag
-	 * here.  However the tools still do nasty things like
-	 * 'load' while a device is suspended.
-	 */
-
-	r = validate_params(cmd, param);
-	if (r)
-		goto out;
-
-	param_size = param->data_size;
-	param->data_size = sizeof(*param);
-	r = fn(param, param_size);
-
-	/*
-	 * Copy the results back to userland.
-	 */
-	if (!r && copy_to_user(user, param, param->data_size))
-		r = -EFAULT;
-
- out:
-	free_params(param);
-	current->flags &= ~PF_MEMALLOC;
-	return r;
-}
-
-static struct file_operations _ctl_fops = {
-	.ioctl	 = ctl_ioctl,
-	.owner	 = THIS_MODULE,
-};
-
-static struct miscdevice _dm_misc = {
-	.minor 		= MISC_DYNAMIC_MINOR,
-	.name  		= DM_NAME,
-	.devfs_name 	= "mapper/control",
-	.fops  		= &_ctl_fops
-};
-
-/*
- * Create misc character device and link to DM_DIR/control.
- */
-int __init dm_interface_init(void)
-{
-	int r;
-
-	r = dm_hash_init();
-	if (r)
-		return r;
-
-	r = misc_register(&_dm_misc);
-	if (r) {
-		DMERR("misc_register failed for control device");
-		dm_hash_exit();
-		return r;
-	}
-
-	DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR,
-	       DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA,
-	       DM_DRIVER_EMAIL);
-	return 0;
-}
-
-void dm_interface_exit(void)
-{
-	if (misc_deregister(&_dm_misc) < 0)
-		DMERR("misc_deregister failed for control device");
-
-	dm_hash_exit();
-}
--- diff/drivers/net/wan/lmc/lmc_ver.h	2003-09-30 15:46:16.000000000 +0100
+++ source/drivers/net/wan/lmc/lmc_ver.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,123 +0,0 @@
-#include <linux/version.h>
-
-#ifndef _IF_LMC_LINUXVER_
-#define _IF_LMC_LINUXVER_
-
- /*
-  * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
-  * All rights reserved.  www.lanmedia.com
-  *
-  * This code is written by:
-  * Andrew Stanley-Jones (asj@cban.com)
-  * Rob Braun (bbraun@vix.com),
-  * Michael Graff (explorer@vix.com) and
-  * Matt Thomas (matt@3am-software.com).
-  *
-  * This software may be used and distributed according to the terms
-  * of the GNU General Public License version 2, incorporated herein by reference.
-  */
-
- /*
-  * This file defines and controls all linux version
-  * differences.
-  *
-  * This is being done to keep 1 central location where all linux
-  * version differences can be kept and maintained.  as this code was
-  * found version issues where pepered throughout the source code and
-  * made the souce code not only hard to read but version problems hard
-  * to track down.  If I'm overiding a function/etc with something in
-  * this file it will be prefixed by "LMC_" which will mean look
-  * here for the version dependent change that's been done.
-  *
-  */
-
-#if LINUX_VERSION_CODE < 0x20363
-#define net_device device
-#endif
-
-#if LINUX_VERSION_CODE < 0x20363
-#define LMC_XMITTER_BUSY(x) (x)->tbusy = 1
-#define LMC_XMITTER_FREE(x) (x)->tbusy = 0
-#define LMC_XMITTER_INIT(x) (x)->tbusy = 0
-#else
-#define LMC_XMITTER_BUSY(x) netif_stop_queue(x)
-#define LMC_XMITTER_FREE(x) netif_wake_queue(x)
-#define LMC_XMITTER_INIT(x) netif_start_queue(x)
-
-#endif
-
-
-#if LINUX_VERSION_CODE < 0x20100
-//typedef unsigned int u_int32_t;
-
-#define  LMC_SETUP_20_DEV {\
-                             int indx; \
-                             for (indx = 0; indx < DEV_NUMBUFFS; indx++) \
-                                skb_queue_head_init (&dev->buffs[indx]); \
-                          } \
-                          dev->family = AF_INET; \
-                          dev->pa_addr = 0; \
-                          dev->pa_brdaddr = 0; \
-                          dev->pa_mask = 0xFCFFFFFF; \
-                          dev->pa_alen = 4;		/* IP addr.  sizeof(u32) */
-
-#else
-
-#define LMC_SETUP_20_DEV
-
-#endif
-
-
-#if LINUX_VERSION_CODE < 0x20155 /* basically 2.2 plus */
-
-#define LMC_DEV_KFREE_SKB(skb) dev_kfree_skb((skb), FREE_WRITE)
-
-#else /* Mostly 2.0 kernels */
-
-#define LMC_DEV_KFREE_SKB(skb) dev_kfree_skb(skb)
-
-#endif
-
-#if LINUX_VERSION_CODE < 0x20200
-#else
-
-#endif
-
-#if LINUX_VERSION_CODE < 0x20100
-#define LMC_SKB_FREE(skb, val) (skb->free = val)
-#else
-#define LMC_SKB_FREE(skb, val)
-#endif
-
-
-#if (LINUX_VERSION_CODE >= 0x20200)
-
-#define LMC_SPIN_FLAGS                unsigned long flags;
-#define LMC_SPIN_LOCK_INIT(x)         spin_lock_init(&(x)->lmc_lock);
-#define LMC_SPIN_UNLOCK(x)            ((x)->lmc_lock = SPIN_LOCK_UNLOCKED)
-#define LMC_SPIN_LOCK_IRQSAVE(x)      spin_lock_irqsave (&(x)->lmc_lock, flags);
-#define LMC_SPIN_UNLOCK_IRQRESTORE(x) spin_unlock_irqrestore (&(x)->lmc_lock, flags);
-#else
-#define LMC_SPIN_FLAGS
-#define LMC_SPIN_LOCK_INIT(x)
-#define LMC_SPIN_UNLOCK(x)
-#define LMC_SPIN_LOCK_IRQSAVE(x)
-#define LMC_SPIN_UNLOCK_IRQRESTORE(x)
-#endif
-
-
-#if LINUX_VERSION_CODE >= 0x20100
-#define LMC_COPY_FROM_USER(x, y, z) if(copy_from_user ((x), (y), (z))) return -EFAULT
-#define LMC_COPY_TO_USER(x, y, z) if(copy_to_user ((x), (y), (z))) return -EFAULT
-#else
-#define LMC_COPY_FROM_USER(x, y, z) if(verify_area(VERIFY_READ, (y), (z))) \
-			               return -EFAULT; \
-                                    memcpy_fromfs ((x), (y), (z))
-
-#define LMC_COPY_TO_USER(x, y, z)   if(verify_area(VERIFY_WRITE, (x), (z))) \
-	                               return -EFAULT; \
-                                    memcpy_tofs ((x), (y), (z))
-#endif
-
-
-#endif
--- diff/include/linux/dm-ioctl-v1.h	2003-09-30 15:46:20.000000000 +0100
+++ source/include/linux/dm-ioctl-v1.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2001 Sistina Software (UK) Limited.
- *
- * This file is released under the LGPL.
- */
-
-#ifndef _LINUX_DM_IOCTL_V1_H
-#define _LINUX_DM_IOCTL_V1_H
-
-#include <linux/types.h>
-
-#define DM_DIR "mapper"	/* Slashes not supported */
-#define DM_MAX_TYPE_NAME 16
-#define DM_NAME_LEN 128
-#define DM_UUID_LEN 129
-
-/*
- * Implements a traditional ioctl interface to the device mapper.
- */
-
-/*
- * All ioctl arguments consist of a single chunk of memory, with
- * this structure at the start.  If a uuid is specified any
- * lookup (eg. for a DM_INFO) will be done on that, *not* the
- * name.
- */
-struct dm_ioctl {
-	/*
-	 * The version number is made up of three parts:
-	 * major - no backward or forward compatibility,
-	 * minor - only backwards compatible,
-	 * patch - both backwards and forwards compatible.
-	 *
-	 * All clients of the ioctl interface should fill in the
-	 * version number of the interface that they were
-	 * compiled with.
-	 *
-	 * All recognised ioctl commands (ie. those that don't
-	 * return -ENOTTY) fill out this field, even if the
-	 * command failed.
-	 */
-	uint32_t version[3];	/* in/out */
-	uint32_t data_size;	/* total size of data passed in
-				 * including this struct */
-
-	uint32_t data_start;	/* offset to start of data
-				 * relative to start of this struct */
-
-	uint32_t target_count;	/* in/out */
-	uint32_t open_count;	/* out */
-	uint32_t flags;		/* in/out */
-
-	__kernel_old_dev_t dev;	/* in/out */
-
-	char name[DM_NAME_LEN];	/* device name */
-	char uuid[DM_UUID_LEN];	/* unique identifier for
-				 * the block device */
-};
-
-/*
- * Used to specify tables.  These structures appear after the
- * dm_ioctl.
- */
-struct dm_target_spec {
-	int32_t status;		/* used when reading from kernel only */
-	uint64_t sector_start;
-	uint32_t length;
-
-	/*
-	 * Offset in bytes (from the start of this struct) to
-	 * next target_spec.
-	 */
-	uint32_t next;
-
-	char target_type[DM_MAX_TYPE_NAME];
-
-	/*
-	 * Parameter string starts immediately after this object.
-	 * Be careful to add padding after string to ensure correct
-	 * alignment of subsequent dm_target_spec.
-	 */
-};
-
-/*
- * Used to retrieve the target dependencies.
- */
-struct dm_target_deps {
-	uint32_t count;
-
-	__kernel_old_dev_t dev[0];	/* out */
-};
-
-/*
- * If you change this make sure you make the corresponding change
- * to dm-ioctl.c:lookup_ioctl()
- */
-enum {
-	/* Top level cmds */
-	DM_VERSION_CMD = 0,
-	DM_REMOVE_ALL_CMD,
-
-	/* device level cmds */
-	DM_DEV_CREATE_CMD,
-	DM_DEV_REMOVE_CMD,
-	DM_DEV_RELOAD_CMD,
-	DM_DEV_RENAME_CMD,
-	DM_DEV_SUSPEND_CMD,
-	DM_DEV_DEPS_CMD,
-	DM_DEV_STATUS_CMD,
-
-	/* target level cmds */
-	DM_TARGET_STATUS_CMD,
-	DM_TARGET_WAIT_CMD
-};
-
-#define DM_IOCTL 0xfd
-
-#define DM_VERSION       _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl)
-#define DM_REMOVE_ALL    _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl)
-
-#define DM_DEV_CREATE    _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl)
-#define DM_DEV_REMOVE    _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl)
-#define DM_DEV_RELOAD    _IOWR(DM_IOCTL, DM_DEV_RELOAD_CMD, struct dm_ioctl)
-#define DM_DEV_SUSPEND   _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl)
-#define DM_DEV_RENAME    _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl)
-#define DM_DEV_DEPS      _IOWR(DM_IOCTL, DM_DEV_DEPS_CMD, struct dm_ioctl)
-#define DM_DEV_STATUS    _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl)
-
-#define DM_TARGET_STATUS _IOWR(DM_IOCTL, DM_TARGET_STATUS_CMD, struct dm_ioctl)
-#define DM_TARGET_WAIT   _IOWR(DM_IOCTL, DM_TARGET_WAIT_CMD, struct dm_ioctl)
-
-#define DM_VERSION_MAJOR	1
-#define DM_VERSION_MINOR	0
-#define DM_VERSION_PATCHLEVEL	6
-#define DM_VERSION_EXTRA	"-ioctl (2002-10-15)"
-
-/* Status bits */
-#define DM_READONLY_FLAG	0x00000001
-#define DM_SUSPEND_FLAG		0x00000002
-#define DM_EXISTS_FLAG		0x00000004
-#define DM_PERSISTENT_DEV_FLAG	0x00000008
-
-/*
- * Flag passed into ioctl STATUS command to get table information
- * rather than current status.
- */
-#define DM_STATUS_TABLE_FLAG	0x00000010
-
-#endif				/* _LINUX_DM_IOCTL_H */
--- diff/include/linux/dm-ioctl-v4.h	2003-08-20 14:16:15.000000000 +0100
+++ source/include/linux/dm-ioctl-v4.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2001 - 2003 Sistina Software (UK) Limited.
- *
- * This file is released under the LGPL.
- */
-
-#ifndef _LINUX_DM_IOCTL_V4_H
-#define _LINUX_DM_IOCTL_V4_H
-
-#include <linux/types.h>
-
-#define DM_DIR "mapper"		/* Slashes not supported */
-#define DM_MAX_TYPE_NAME 16
-#define DM_NAME_LEN 128
-#define DM_UUID_LEN 129
-
-/*
- * A traditional ioctl interface for the device mapper.
- *
- * Each device can have two tables associated with it, an
- * 'active' table which is the one currently used by io passing
- * through the device, and an 'inactive' one which is a table
- * that is being prepared as a replacement for the 'active' one.
- *
- * DM_VERSION:
- * Just get the version information for the ioctl interface.
- *
- * DM_REMOVE_ALL:
- * Remove all dm devices, destroy all tables.  Only really used
- * for debug.
- *
- * DM_LIST_DEVICES:
- * Get a list of all the dm device names.
- *
- * DM_DEV_CREATE:
- * Create a new device, neither the 'active' or 'inactive' table
- * slots will be filled.  The device will be in suspended state
- * after creation, however any io to the device will get errored
- * since it will be out-of-bounds.
- *
- * DM_DEV_REMOVE:
- * Remove a device, destroy any tables.
- *
- * DM_DEV_RENAME:
- * Rename a device.
- *
- * DM_SUSPEND:
- * This performs both suspend and resume, depending which flag is
- * passed in.
- * Suspend: This command will not return until all pending io to
- * the device has completed.  Further io will be deferred until
- * the device is resumed.
- * Resume: It is no longer an error to issue this command on an
- * unsuspended device.  If a table is present in the 'inactive'
- * slot, it will be moved to the active slot, then the old table
- * from the active slot will be _destroyed_.  Finally the device
- * is resumed.
- *
- * DM_DEV_STATUS:
- * Retrieves the status for the table in the 'active' slot.
- *
- * DM_DEV_WAIT:
- * Wait for a significant event to occur to the device.  This
- * could either be caused by an event triggered by one of the
- * targets of the table in the 'active' slot, or a table change.
- *
- * DM_TABLE_LOAD:
- * Load a table into the 'inactive' slot for the device.  The
- * device does _not_ need to be suspended prior to this command.
- *
- * DM_TABLE_CLEAR:
- * Destroy any table in the 'inactive' slot (ie. abort).
- *
- * DM_TABLE_DEPS:
- * Return a set of device dependencies for the 'active' table.
- *
- * DM_TABLE_STATUS:
- * Return the targets status for the 'active' table.
- */
-
-/*
- * All ioctl arguments consist of a single chunk of memory, with
- * this structure at the start.  If a uuid is specified any
- * lookup (eg. for a DM_INFO) will be done on that, *not* the
- * name.
- */
-struct dm_ioctl {
-	/*
-	 * The version number is made up of three parts:
-	 * major - no backward or forward compatibility,
-	 * minor - only backwards compatible,
-	 * patch - both backwards and forwards compatible.
-	 *
-	 * All clients of the ioctl interface should fill in the
-	 * version number of the interface that they were
-	 * compiled with.
-	 *
-	 * All recognised ioctl commands (ie. those that don't
-	 * return -ENOTTY) fill out this field, even if the
-	 * command failed.
-	 */
-	uint32_t version[3];	/* in/out */
-	uint32_t data_size;	/* total size of data passed in
-				 * including this struct */
-
-	uint32_t data_start;	/* offset to start of data
-				 * relative to start of this struct */
-
-	uint32_t target_count;	/* in/out */
-	int32_t open_count;	/* out */
-	uint32_t flags;		/* in/out */
-	uint32_t event_nr;      	/* in/out */
-	uint32_t padding;
-
-	uint64_t dev;		/* in/out */
-
-	char name[DM_NAME_LEN];	/* device name */
-	char uuid[DM_UUID_LEN];	/* unique identifier for
-				 * the block device */
-};
-
-/*
- * Used to specify tables.  These structures appear after the
- * dm_ioctl.
- */
-struct dm_target_spec {
-	uint64_t sector_start;
-	uint64_t length;
-	int32_t status;		/* used when reading from kernel only */
-
-	/*
-	 * Offset in bytes (from the start of this struct) to
-	 * next target_spec.
-	 */
-	uint32_t next;
-
-	char target_type[DM_MAX_TYPE_NAME];
-
-	/*
-	 * Parameter string starts immediately after this object.
-	 * Be careful to add padding after string to ensure correct
-	 * alignment of subsequent dm_target_spec.
-	 */
-};
-
-/*
- * Used to retrieve the target dependencies.
- */
-struct dm_target_deps {
-	uint32_t count;	/* Array size */
-	uint32_t padding;	/* unused */
-	uint64_t dev[0];	/* out */
-};
-
-/*
- * Used to get a list of all dm devices.
- */
-struct dm_name_list {
-	uint64_t dev;
-	uint32_t next;		/* offset to the next record from
-				   the _start_ of this */
-	char name[0];
-};
-
-/*
- * If you change this make sure you make the corresponding change
- * to dm-ioctl.c:lookup_ioctl()
- */
-enum {
-	/* Top level cmds */
-	DM_VERSION_CMD = 0,
-	DM_REMOVE_ALL_CMD,
-	DM_LIST_DEVICES_CMD,
-
-	/* device level cmds */
-	DM_DEV_CREATE_CMD,
-	DM_DEV_REMOVE_CMD,
-	DM_DEV_RENAME_CMD,
-	DM_DEV_SUSPEND_CMD,
-	DM_DEV_STATUS_CMD,
-	DM_DEV_WAIT_CMD,
-
-	/* Table level cmds */
-	DM_TABLE_LOAD_CMD,
-	DM_TABLE_CLEAR_CMD,
-	DM_TABLE_DEPS_CMD,
-	DM_TABLE_STATUS_CMD,
-};
-
-#define DM_IOCTL 0xfd
-
-#define DM_VERSION       _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl)
-#define DM_REMOVE_ALL    _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl)
-#define DM_LIST_DEVICES  _IOWR(DM_IOCTL, DM_LIST_DEVICES_CMD, struct dm_ioctl)
-
-#define DM_DEV_CREATE    _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl)
-#define DM_DEV_REMOVE    _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl)
-#define DM_DEV_RENAME    _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl)
-#define DM_DEV_SUSPEND   _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl)
-#define DM_DEV_STATUS    _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl)
-#define DM_DEV_WAIT      _IOWR(DM_IOCTL, DM_DEV_WAIT_CMD, struct dm_ioctl)
-
-#define DM_TABLE_LOAD    _IOWR(DM_IOCTL, DM_TABLE_LOAD_CMD, struct dm_ioctl)
-#define DM_TABLE_CLEAR   _IOWR(DM_IOCTL, DM_TABLE_CLEAR_CMD, struct dm_ioctl)
-#define DM_TABLE_DEPS    _IOWR(DM_IOCTL, DM_TABLE_DEPS_CMD, struct dm_ioctl)
-#define DM_TABLE_STATUS  _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, struct dm_ioctl)
-
-#define DM_VERSION_MAJOR	4
-#define DM_VERSION_MINOR	0
-#define DM_VERSION_PATCHLEVEL	0
-#define DM_VERSION_EXTRA	"-ioctl (2003-06-04)"
-
-/* Status bits */
-#define DM_READONLY_FLAG	(1 << 0) /* In/Out */
-#define DM_SUSPEND_FLAG		(1 << 1) /* In/Out */
-#define DM_PERSISTENT_DEV_FLAG	(1 << 3) /* In */
-
-/*
- * Flag passed into ioctl STATUS command to get table information
- * rather than current status.
- */
-#define DM_STATUS_TABLE_FLAG	(1 << 4) /* In */
-
-/*
- * Flags that indicate whether a table is present in either of
- * the two table slots that a device has.
- */
-#define DM_ACTIVE_PRESENT_FLAG   (1 << 5) /* Out */
-#define DM_INACTIVE_PRESENT_FLAG (1 << 6) /* Out */
-
-/*
- * Indicates that the buffer passed in wasn't big enough for the
- * results.
- */
-#define DM_BUFFER_FULL_FLAG	(1 << 8) /* Out */
-
-#endif				/* _LINUX_DM_IOCTL_H */
