-mm2
--- diff/CREDITS	2004-02-18 08:54:06.000000000 +0000
+++ source/CREDITS	2004-03-16 09:37:55.272137528 +0000
@@ -82,13 +82,13 @@ S: Howell, NJ 07731
 S: USA
 
 N: Erik Andersen
-E: andersee@debian.org
-W: http://www.xmission.com/~andersen
-P: 1024/FC4CFFED 78 3C 6A 19 FA 5D 92 5A  FB AC 7B A5 A5 E1 FF 8E
+E: andersen@codepoet.org
+W: http://www.codepoet.org/
+P: 1024D/30D39057 1BC4 2742 E885 E4DE 9301  0C82 5F9B 643E 30D3 9057
 D: Maintainer of ide-cd and Uniform CD-ROM driver, 
 D: ATAPI CD-Changer support, Major 2.1.x CD-ROM update.
-S: 4538 South Carnegie Tech Street
-S: Salt Lake City, Utah 84120
+S: 352 North 525 East
+S: Springville, Utah 84663
 S: USA
 
 N: Michael Ang
@@ -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/
@@ -673,11 +682,6 @@ S: Northampton
 S: NN1 3QT
 S: United Kingdom
 
-N: Stephane Dalton
-E: sdalton@videotron.ca
-D: Tieman Voyager USB Braille display driver.
-S: Québec, Canada
-
 N: Uwe Dannowski
 E: Uwe.Dannowski@ira.uka.de
 W: http://i30www.ira.uka.de/~dannowsk/
@@ -797,11 +801,6 @@ E: cort@fsmlabs.com
 W: http://www.fsmlabs.com/linuxppcbk.html
 D: PowerPC
 
-N: Stéphane Doyon
-E: s.doyon@videotron.ca
-D: Tieman Voyager USB Braille display driver.
-S: Québec, Canada
-
 N: Oleg Drokin
 E: green@ccssu.crimea.ua
 W: http://www.ccssu.crimea.ua/~green
@@ -975,8 +974,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 +3487,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 09:00:51.000000000 +0000
+++ source/Documentation/DMA-mapping.txt	2004-03-16 09:37:55.274137224 +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/Makefile	2003-10-27 09:20:43.000000000 +0000
+++ source/Documentation/DocBook/Makefile	2004-03-16 09:37:55.274137224 +0000
@@ -149,12 +149,18 @@ quiet_cmd_fig2eps = FIG2EPS $@
       cmd_fig2eps = fig2dev -Leps $< $@
 
 %.eps: %.fig
+	@(which fig2dev > /dev/null 2>&1) || \
+	 (echo "*** You need to install transfig ***"; \
+	  exit 1)
 	$(call cmd,fig2eps)
 
 quiet_cmd_fig2png = FIG2PNG $@
       cmd_fig2png = fig2dev -Lpng $< $@
 
 %.png: %.fig
+	@(which fig2dev > /dev/null 2>&1) || \
+	 (echo "*** You need to install transfig ***"; \
+	  exit 1)
 	$(call cmd,fig2png)
 
 ###
--- diff/Documentation/DocBook/gadget.tmpl	2003-09-30 14:46:10.000000000 +0000
+++ source/Documentation/DocBook/gadget.tmpl	2004-03-16 09:37:55.275137072 +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/DocBook/parportbook.tmpl	2003-05-21 10:49:45.000000000 +0000
+++ source/Documentation/DocBook/parportbook.tmpl	2004-03-16 09:37:55.277136768 +0000
@@ -2730,7 +2730,7 @@ to permit their use in free software.
 
 </book>
 <!-- Additional function to be documented:
-!Ddrivers/parport/init.c
+--! Ddrivers/parport/init.c (this file doesn't exist any more)
 -->
 <!-- Local Variables: -->
 <!-- sgml-indent-step: 1 -->
--- diff/Documentation/IPMI.txt	2003-05-21 10:49:59.000000000 +0000
+++ source/Documentation/IPMI.txt	2004-03-16 09:37:55.278136616 +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 08:47:33.000000000 +0000
+++ source/Documentation/binfmt_misc.txt	2004-03-16 09:37:55.279136464 +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/devices.txt	2004-02-09 10:36:07.000000000 +0000
+++ source/Documentation/devices.txt	2004-03-16 09:37:55.281136160 +0000
@@ -2046,6 +2046,21 @@ Your cooperation is appreciated.
 		  1 = /dev/gpib1	Second GPIB bus
 		    ...
 
+160 block       Carmel 8-port SATA Disks on First Controller
+		  0 = /dev/carmel/0     SATA disk 0 whole disk
+		  1 = /dev/carmel/0p1   SATA disk 0 partition 1
+		    ...
+		 31 = /dev/carmel/0p31  SATA disk 0 partition 31
+
+		 32 = /dev/carmel/1     SATA disk 1 whole disk
+		 64 = /dev/carmel/2     SATA disk 2 whole disk
+		    ...
+		224 = /dev/carmel/7     SATA disk 7 whole disk
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 31.
+
 161 char	IrCOMM devices (IrDA serial/parallel emulation)
 		  0 = /dev/ircomm0	First IrCOMM device
 		  1 = /dev/ircomm1	Second IrCOMM device
@@ -2054,6 +2069,21 @@ Your cooperation is appreciated.
 		 17 = /dev/irlpt1	Second IrLPT device
 		    ...
 
+161 block       Carmel 8-port SATA Disks on Second Controller
+		  0 = /dev/carmel/8     SATA disk 8 whole disk
+		  1 = /dev/carmel/8p1   SATA disk 8 partition 1
+		    ...
+		 31 = /dev/carmel/8p31  SATA disk 8 partition 31
+
+		 32 = /dev/carmel/9     SATA disk 9 whole disk
+		 64 = /dev/carmel/10    SATA disk 10 whole disk
+		    ...
+		224 = /dev/carmel/15    SATA disk 15 whole disk
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 31. 
+
 162 char	Raw block device interface
 		  0 = /dev/rawctl	Raw I/O control device
 		  1 = /dev/raw/raw1	First raw I/O device
--- diff/Documentation/early-userspace/README	2003-08-26 09:00:51.000000000 +0000
+++ source/Documentation/early-userspace/README	2004-03-16 09:37:55.282136008 +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-11 10:20:19.000000000 +0000
+++ source/Documentation/filesystems/proc.txt	2004-03-16 09:37:55.284135704 +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 03:28:34.000000000 +0000
+++ source/Documentation/filesystems/udf.txt	2004-03-16 09:37:55.285135552 +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 03:28:31.000000000 +0000
+++ source/Documentation/filesystems/ufs.txt	2004-03-16 09:37:55.285135552 +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/i2c/sysfs-interface	2004-01-19 10:22:54.000000000 +0000
+++ source/Documentation/i2c/sysfs-interface	2004-03-16 09:37:55.287135248 +0000
@@ -3,22 +3,44 @@ Naming and data format standards for sys
 
 The libsensors library offers an interface to the raw sensors data
 through the sysfs interface. See libsensors documentation and source for
-more further information.
+more further information. As of writing this document, libsensors
+(from lm_sensors 2.8.3) is heavily chip-dependant. Adding or updating
+support for any given chip requires modifying the library's code.
+This is because libsensors was written for the procfs interface
+older kernel modules were using, which wasn't standardized enough.
+Recent versions of libsensors (from lm_sensors 2.8.2 and later) have
+support for the sysfs interface, though.
+
+The new sysfs interface was designed to be as chip-independant as
+possible.
+
+Note that motherboards vary widely in the connections to sensor chips.
+There is no standard that ensures, for example, that the second
+temperature sensor is connected to the CPU, or that the second fan is on
+the CPU. Also, some values reported by the chips need some computation
+before they make full sense. For example, most chips can only measure
+voltages between 0 and +4V. Other voltages are scaled back into that
+range using external resistors. Since the values of these resistors
+can change from motherboard to motherboard, the conversions cannot be
+hard coded into the driver and have to be done in user space.
+
+For this reason, even if we aim at a chip-independant libsensors, it will
+still require a configuration file (e.g. /etc/sensors.conf) for proper
+values conversion, labeling of inputs and hiding of unused inputs.
 
 An alternative method that some programs use is to access the sysfs
 files directly. This document briefly describes the standards that the
 drivers follow, so that an application program can scan for entries and
-access this data in a simple and consistent way.
+access this data in a simple and consistent way. That said, such programs
+will have to implement conversion, labeling and hiding of inputs. For
+this reason, it is still not recommended to bypass the library.
 
 If you are developing a userspace application please send us feedback on
 this standard.
 
-Note that motherboards vary widely in the connections to sensor chips.
-There is no standard that ensures, for example, that the second
-temperature sensor is connected to the CPU, or that the second fan is on
-the CPU. Therefore, programs must provide a facility for the user to
-label or bind /proc entries for display.  Sensor chips often have unused
-inputs that should be ignored by user programs.
+Note that this standard isn't completely established yet, so it is subject
+to changes, even important ones. One more reason to use the library instead
+of accessing sysfs files directly.
 
 Each chip gets its own directory in the sysfs /sys/devices tree.  To
 find all sensor chips, it is easier to follow the symlinks from
@@ -28,6 +50,15 @@ All sysfs values are fixed point numbers
 of the values, you should divide by the specified value.
 
 There is only one value per file, unlike the older /proc specification.
+The common scheme for files naming is: <type><number>_<item>. Usual
+types for sensor chips are "in" (voltage), "temp" (temperature) and
+"fan" (fan). Usual items are "input" (measured value), "max" (high
+threshold, "min" (low threshold). Numbering usually starts from 1,
+except for voltages which start from 0 (because most data sheets use
+this). A number is always used for elements that can be present more
+than once, even if there is a single element of the given type on the
+specific chip. Other files do not refer to a specific element, so
+they have a simple name, and no number.
 
 Alarms are direct indications read from the chips. The drivers do NOT
 make comparisons of readings to thresholds. This allows violations
@@ -38,71 +69,21 @@ to cause an alarm) is chip-dependent.
 
 -------------------------------------------------------------------------
 
-sysfs entries are as follows:
-
-
-Entry		Function
------		--------
-alarms		Alarm bitmask.
-		Read only.
-		Integer representation of one to four bytes.
-		A '1' bit means an alarm.
-		Chips should be programmed for 'comparator' mode so that
-		the alarm will 'come back' after you read the register
-		if it is still valid.
-		Generally a direct representation of a chip's internal
-		alarm registers; there is no standard for the position
-		of individual bits.
-		Bits are defined in kernel/include/sensors.h.
-
-beep_enable	Beep/interrupt enable
-		0 to disable.
-		1 to enable.
-		Read/Write
-
-beep_mask	Bitmask for beep.
-		Same format as 'alarms' with the same bit locations.
-		Read only.
-
-curr_max[1-n]	Current max value
-		Fixed point XXXXX, divide by 1000 to get Amps.
-		Read/Write.
-
-curr_min[1-n]	Current min value.
-		Fixed point XXXXX, divide by 1000 to get Amps.
-		Read/Write.
-
-curr_input[1-n]	Current input value
-		Fixed point XXXXX, divide by 1000 to get Amps.
-		Read only.
+************
+* Voltages *
+************
 
-eeprom		Raw EEPROM data in binary form.
-		Read only.
-
-fan_min[1-3]	Fan minimum value
-		Integer value indicating RPM
-		Read/Write.
-
-fan_input[1-3]	Fan input value.
-		Integer value indicating RPM
-		Read only.
-
-fan_div[1-3]	Fan divisor.
-		Integers in powers of two (1,2,4,8,16,32,64,128).
-		Some chips only support values 1,2,4,8.
-		See doc/fan-divisors for details.
-
-in_min[0-8]	Voltage min value.
+in[0-8]_min	Voltage min value.
 		Fixed point value in form XXXX.  Divide by 1000 to get
 		Volts.
 		Read/Write
 		
-in_max[0-8]	Voltage max value.
+in[0-8]_max	Voltage max value.
 		Fixed point value in form XXXX.  Divide by 1000 to get
 		Volts.
 		Read/Write
 		
-in_input[0-8]	Voltage input value.
+in[0-8]_input	Voltage input value.
 		Fixed point value in form XXXX.  Divide by 1000 to get
 		Volts.
 		Read only
@@ -116,76 +97,156 @@ in_input[0-8]	Voltage input value.
 		These drivers will output the actual voltage.
 		First two values are read/write and third is read only.
 		Typical usage:
-			in_*0	CPU #1 voltage (not scaled)
-			in_*1	CPU #1 voltage (not scaled)
-			in_*2	3.3V nominal (not scaled)
-			in_*3	5.0V nominal (scaled)
-			in_*4	12.0V nominal (scaled)
-			in_*5	-12.0V nominal (scaled)
-			in_*6	-5.0V nominal (scaled)
-			in_*7	varies
-			in_*8	varies
+			in0_*	CPU #1 voltage (not scaled)
+			in1_*	CPU #1 voltage (not scaled)
+			in2_*	3.3V nominal (not scaled)
+			in3_*	5.0V nominal (scaled)
+			in4_*	12.0V nominal (scaled)
+			in5_*	-12.0V nominal (scaled)
+			in6_*	-5.0V nominal (scaled)
+			in7_*	varies
+			in8_*	varies
+
+in0_ref		CPU core reference voltage.
+		Read only.
+		Fixed point value in form XXXX corresponding to CPU core
+		voltage as told to the sensor chip.  Divide by 1000 to
+		get Volts.  Not always correct.
+
+vrm		Voltage Regulator Module version number. 
+		Read only.
+		Two digit number (XX), first is major version, second is
+		minor version.
+		Affects the way the driver calculates the core voltage from
+		the vid pins. See doc/vid for details.
+
+
+********
+* Fans *
+********
+
+fan[1-3]_min	Fan minimum value
+		Integer value indicating RPM
+		Read/Write.
+
+fan[1-3]_input	Fan input value.
+		Integer value indicating RPM
+		Read only.
+
+fan[1-3]_div	Fan divisor.
+		Integers in powers of two (1,2,4,8,16,32,64,128).
+		Some chips only support values 1,2,4,8.
+		See doc/fan-divisors for details.
 
-pwm[1-3]	Pulse width modulation fan control.
+fan[1-3]_pwm	Pulse width modulation fan control.
 		Integer 0 - 255
 		Read/Write
 		255 is max or 100%.
 		Corresponds to the fans 1-3.
 
-pwm_enable[1-3] pwm enable
-		not always present even if pwm* is.
+fan[1-3]_pwm_enable
+		Switch PWM on and off.
+		Not always present even if fan*_pwm is.
 		0 to turn off
 		1 to turn on
 		Read/Write
 
-sensor[1-3]	Sensor type selection.
+
+****************
+* Temperatures *
+****************
+
+temp[1-3]_type	Sensor type selection.
 		Integers 1,2,3, or thermistor Beta value (3435)
 		Read/Write.
 
-temp_max[1-4]	Temperature max value.
+temp[1-4]_max	Temperature max value.
 		Fixed point value in form XXXXX and should be divided by
 		1000 to get degrees Celsius.
 		Read/Write value.
 
-temp_min[1-3]	Temperature min value.
+temp[1-3]_min	Temperature min value.
 		Fixed point value in form XXXXX and should be divided by
 		1000 to get degrees Celsius.
 		Read/Write value.
 
-temp_hyst[1-3]	Temperature hysteresis value.
+temp[1-3]_max_hyst
+		Temperature hysteresis value for max limit.
 		Fixed point value in form XXXXX and should be divided by
 		1000 to get degrees Celsius.  Must be reported as an
 		absolute temperature, NOT a delta from the max value.
 		Read/Write value.
 
-temp_input[1-4] Temperature input value.
+temp[1-4]_input Temperature input value.
 		Fixed point value in form XXXXX and should be divided by
 		1000 to get degrees Celsius.
 		Read only value.
 
-temp_crit	Temperature critical value, typically greater than all
-		temp_max values.
+temp[1-4]_crit	Temperature critical value, typically greater than
+		corresponding temp_max values.
 		Fixed point value in form XXXXX and should be divided by
 		1000 to get degrees Celsius.
-		Common to all temperature channels.
 		Read/Write value.
 
-		If there are multiple temperature sensors, temp_*1 is
+temp[1-2]_crit_hyst
+		Temperature hysteresis value for critical limit.
+		Fixed point value in form XXXXX and should be divided by
+		1000 to get degrees Celsius.  Must be reported as an
+		absolute temperature, NOT a delta from the critical value.
+		Read/Write value.
+
+		If there are multiple temperature sensors, temp1_* is
 		generally the sensor inside the chip itself, generally
-		reported as "motherboard temperature".  temp_*2 to
-		temp_*4 are generally sensors external to the chip
+		reported as "motherboard temperature".  temp2_* to
+		temp4_* are generally sensors external to the chip
 		itself, for example the thermal diode inside the CPU or
 		a thermistor nearby.
 
-vid		CPU core voltage.
+
+************
+* Currents *
+************
+
+Note that no known chip provides current measurements as of writing,
+so this part is theoretical, so to say.
+
+curr[1-n]_max	Current max value
+		Fixed point XXXXX, divide by 1000 to get Amps.
+		Read/Write.
+
+curr[1-n]_min	Current min value.
+		Fixed point XXXXX, divide by 1000 to get Amps.
+		Read/Write.
+
+curr[1-n]_input	Current input value
+		Fixed point XXXXX, divide by 1000 to get Amps.
 		Read only.
-		Fixed point value in form XXXX corresponding to CPU core
-		voltage as told to the sensor chip.  Divide by 1000 to
-		get Volts.  Not always correct.
 
-vrm		Voltage Regulator Module version number. 
+
+*********
+* Other *
+*********
+
+alarms		Alarm bitmask.
+		Read only.
+		Integer representation of one to four bytes.
+		A '1' bit means an alarm.
+		Chips should be programmed for 'comparator' mode so that
+		the alarm will 'come back' after you read the register
+		if it is still valid.
+		Generally a direct representation of a chip's internal
+		alarm registers; there is no standard for the position
+		of individual bits.
+		Bits are defined in kernel/include/sensors.h.
+
+beep_enable	Beep/interrupt enable
+		0 to disable.
+		1 to enable.
+		Read/Write
+
+beep_mask	Bitmask for beep.
+		Same format as 'alarms' with the same bit locations.
+		Read only.
+
+eeprom		Raw EEPROM data in binary form.
 		Read only.
-		Two digit number (XX), first is major version, second is
-		minor version.
-		Affects the way the driver calculates the core voltage from
-		the vid pins. See doc/vid for details.
--- diff/Documentation/i386/zero-page.txt	2004-02-18 08:54:06.000000000 +0000
+++ source/Documentation/i386/zero-page.txt	2004-03-16 09:37:55.287135248 +0000
@@ -75,7 +75,7 @@ Offset	Type		Description
 0x2cc	4 bytes		DISK80_SIG_BUFFER (setup.S)
 0x2d0 - 0x600		E820MAP
 0x600 - 0x7ff		EDDBUF (setup.S) for disk signature read sector
-0x600 - 0x7d3		EDDBUF (setup.S) for edd data
+0x600 - 0x7eb		EDDBUF (setup.S) for edd data
 
 0x800	string, 2K max	COMMAND_LINE, the kernel commandline as
 			copied using CL_OFFSET.
--- diff/Documentation/input/joystick-parport.txt	2002-10-16 03:29:06.000000000 +0000
+++ source/Documentation/input/joystick-parport.txt	2004-03-16 09:37:55.288135096 +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 03:29:05.000000000 +0000
+++ source/Documentation/input/joystick.txt	2004-03-16 09:37:55.289134944 +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-11 10:20:19.000000000 +0000
+++ source/Documentation/kernel-parameters.txt	2004-03-16 09:37:55.290134792 +0000
@@ -98,6 +98,10 @@ running once the system is up.
 				strictly ACPI specification compliant.
 
 			See also Documentation/pm.txt.
+
+	acpi_sleep=	[HW,ACPI] Sleep options
+			Format: { s3_bios, s3_mode }
+			See Documentation/power/video.txt
  
 	acpi_pic_sci=	[HW,ACPI] ACPI System Control Interrupt trigger mode
 			Format: { level | edge }
@@ -116,6 +120,10 @@ running once the system is up.
 	acpi_irq_isa=	[HW,ACPI] If irq_balance, Mark listed IRQs used by ISA
 			Format: <irq>,<irq>...
 
+	acpi_osi=	[HW,ACPI] empty param disables _OSI
+
+	acpi_serialize	[HW,ACPI] force serialization of AML methods
+
 	ad1816=		[HW,OSS]
 			Format: <io>,<irq>,<dma>,<dma2>
 			See also Documentation/sound/oss/AD1816.
@@ -154,7 +162,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
@@ -177,11 +193,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]
 
@@ -283,10 +306,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]
@@ -380,12 +404,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.
 
@@ -612,9 +638,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]
@@ -1159,10 +1185,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
@@ -1185,8 +1207,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-11 10:20:19.000000000 +0000
+++ source/Documentation/scsi/st.txt	2004-03-16 09:37:55.291134640 +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/scsi/sym53c8xx_2.txt	2003-05-21 10:49:49.000000000 +0000
+++ source/Documentation/scsi/sym53c8xx_2.txt	2004-03-16 09:37:55.292134488 +0000
@@ -567,7 +567,7 @@ characters and digits are allowed.
         nvram:n     do not look for serial NVRAM
         nvram:y     test controllers for onboard serial NVRAM
         (alternate binary form)
-        mvram=<bits options>
+        nvram=<bits options>
         0x01   look for NVRAM  (equivalent to nvram=y)
         0x02   ignore NVRAM "Synchronous negotiation" parameters for all devices
         0x04   ignore NVRAM "Wide negotiation"  parameter for all devices
@@ -661,7 +661,7 @@ optimized parameters value.
 The 'nvram' boot option can be entered in hexadecimal form in order 
 to ignore some options configured in the NVRAM, as follow:
 
-mvram=<bits options>
+nvram=<bits options>
       0x01   look for NVRAM  (equivalent to nvram=y)
       0x02   ignore NVRAM "Synchronous negotiation" parameters for all devices
       0x04   ignore NVRAM "Wide negotiation"  parameter for all devices
--- diff/Documentation/sound/alsa/ALSA-Configuration.txt	2004-02-18 08:54:06.000000000 +0000
+++ source/Documentation/sound/alsa/ALSA-Configuration.txt	2004-03-16 09:37:55.293134336 +0000
@@ -112,7 +112,8 @@ Module parameters
 		- value is used for /proc/asound filesystem
 		- this value can be used by applications for identification
 		  of card if user does not want identify card with index number
-    enable  	- enable card (only first card is enabled by default)
+    enable  	- enable card.  (all cards enabled for PCI and ISA PnP cards
+		  as default.)
 
   Module snd-ad1816a
   ------------------
@@ -178,6 +179,42 @@ Module parameters
     
     Module supports up to 8 cards, autoprobe and PnP.
 
+  Module snd-atiixp
+  -----------------
+
+    Module for ATI IXP 150/200/250 AC97 controllers.
+
+    ac97_clock		- AC'97 clock (defalut = 48000)
+    spdif_aclink	- S/PDIF transfer over AC-link (default = 1)
+
+    This module supports up to 8 cards and autoprobe.
+
+  Module snd-au8810, snd-au8820, snd-au8830
+  -----------------------------------------
+
+    Module for Aureal Vortex, Vortex2 and Advantage device.
+
+    pcifix	- Control PCI workarounds
+		  0 = Disable all workarounds
+		  1 = Force the PCI latency of the Aureal card to 0xff
+		  2 = Force the Extend PCI#2 Internal Master for Efficient
+		      Handling of Dummy Requests on the VIA KT133 AGP Bridge
+		  3 = Force both settings
+		  255 = Autodetect what is required (default)
+
+    This module supports all ADB PCM channels, ac97 mixer, SPDIF, hardware
+    EQ, mpu401, gameport. A3D and wavetable support are still in development.
+    Development and reverse engineering work is being coordinated at
+    http://savannah.nongnu.org/projects/openvortex/
+    SPDIF output has a copy of the AC97 codec output, unless you use the
+    "spdif" pcm device, which allows raw data passthru.
+    The hardware EQ hardware and SPDIF is only present in the Vortex2 and 
+    Advantage.
+
+    Note: Some ALSA mixer applicactions don't handle the SPDIF samplerate 
+           control correctly. If you have problems regarding this, try
+           another ALSA compliant mixer (alsamixer works).
+
   Module snd-azt2320
   ------------------
 
@@ -608,6 +645,7 @@ Module parameters
                      1 = use headphone control as master
                      2 = swap headphone and master controls
                      3 = for AD1985, turn on OMS bit and use headphone
+                     4 = for ALC65x, turn on the jack sense mode
 
     Module supports autoprobe and multiple bus-master chips (max 8).
 
@@ -627,6 +665,15 @@ Module parameters
 
     The power-management is supported.
     
+  Module snd-intel8x0m
+  --------------------
+
+    Module for Intel ICH (i8x0) chipset MC97 modems.
+
+    ac97_clock	  - AC'97 codec clock base (0 = auto-detect)
+
+    This module supports up to 8 cards and autoprobe.
+
   Module snd-interwave
   --------------------
 
@@ -692,6 +739,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 +1226,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/alsa-driver-api.tmpl	2003-05-21 10:49:54.000000000 +0000
+++ source/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl	2004-03-16 09:37:55.293134336 +0000
@@ -49,7 +49,6 @@
 !Esound/core/memory.c
 !Iinclude/sound/sndmagic.h
 !Esound/core/memalloc.c
-!Esound/core/sgbuf.c
      </sect1>
   </chapter>
   <chapter><title>PCM API</title>
@@ -71,6 +70,7 @@
      </sect1>
      <sect1><title>AC97 Codec API</title>
 !Esound/pci/ac97/ac97_codec.c
+!Esound/pci/ac97/ac97_pcm.c
      </sect1>
   </chapter>
   <chapter><title>MIDI API</title>
--- 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-16 09:37:55.298133576 +0000
@@ -18,8 +18,8 @@
       </affiliation>
      </author>
 
-     <date>Mar. 26, 2003</date>
-     <edition>0.3</edition>
+     <date>Mar. 6, 2004</date>
+     <edition>0.3.1</edition>
 
     <abstract>
       <para>
@@ -30,7 +30,7 @@
 
     <legalnotice>
     <para>
-    Copyright (c) 2002, 2003  Takashi Iwai <email>tiwai@suse.de</email>
+    Copyright (c) 2002-2004  Takashi Iwai <email>tiwai@suse.de</email>
     </para>
 
     <para>
@@ -111,18 +111,18 @@
 
       <para>
         One is the the trees provided as a tarball or via cvs from the
-      ALSA's ftp site, and another is the 2.5 (or later) Linux kernel
+      ALSA's ftp site, and another is the 2.6 (or later) Linux kernel
       tree. To synchronize both, the ALSA driver tree is split to
       two different trees: alsa-kernel and alsa-driver. The former
-      contains purely the source codes for the Linux 2.5 (or later)
-      tree. This tree is designed only for compilation on 2.5 or
+      contains purely the source codes for the Linux 2.6 (or later)
+      tree. This tree is designed only for compilation on 2.6 or
       later environment. The latter, alsa-driver, contains many subtle
       files for compiling the ALSA driver on the outside of Linux
       kernel like configure script, the wrapper functions for older,
       2.2 and 2.4 kernels, to adapt the latest kernel API,
       and additional drivers which are still in development or in
       tests.  The drivers in alsa-driver tree will be moved to
-      alsa-kernel (eventually 2.5 kernel tree) once when they are
+      alsa-kernel (eventually 2.6 kernel tree) once when they are
       finished and confirmed to work fine.
       </para>
 
@@ -346,7 +346,7 @@
     <section id="file-tree-oss-directory">
       <title>oss directory</title>
       <para>
-        The OSS/Lite source files are stored here on Linux 2.5 (or
+        The OSS/Lite source files are stored here on Linux 2.6 (or
       later) tree. (In the ALSA driver tarball, it's empty, of course :) 
       </para>
     </section>
@@ -1815,7 +1815,7 @@
 
       <para>
         Oh, one thing was forgotten. If you have no exported symbols,
-        you need to declare it on 2.2 or 2.4 kernels (on 2.5 kernels
+        you need to declare it on 2.2 or 2.4 kernels (on 2.6 kernels
         it's not necessary, though).
 
         <informalexample>
@@ -2075,8 +2075,9 @@
           snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
                           &snd_mychip_capture_ops);
           /* pre-allocation of buffers */
-          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;
   }
 ]]>
@@ -2202,8 +2203,9 @@
         <informalexample>
           <programlisting>
 <![CDATA[
-  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);
 ]]>
           </programlisting>
         </informalexample>
@@ -3769,14 +3771,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>
@@ -4718,7 +4726,8 @@ struct _snd_pcm_runtime {
         <informalexample>
           <programlisting>
 <![CDATA[
-  snd_pcm_lib_preallocate_pci_pages_for_all(pci, pcm, size, max);
+  snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+                                        snd_dma_pci_data(pci), size, max);
 ]]>
           </programlisting>
         </informalexample>
@@ -4728,8 +4737,25 @@ struct _snd_pcm_runtime {
       size to be changed via <filename>prealloc</filename> proc file.
       The allocator will try to get as the large area as possible
       within the given size. 
-      There are different versions of pre-allocator for different
-      buses.
+      </para>
+
+      <para>
+      The second argument (type) and the third argument (device pointer)
+      are dependent on the bus.
+      In the case of ISA bus, pass <function>snd_dma_isa_data()</function>
+      as the third argument with <constant>SNDRV_DMA_TYPE_DEV</constant> type.
+      For the continuous buffer unrelated to the bus can be pre-allocated
+      with <constant>SNDRV_DMA_TYPE_CONTINUOUS</constant> type and the
+      <function>snd_dma_continuous_data(GFP_KERNEL)</function> device pointer,
+      whereh <constant>GFP_KERNEL</constant> is the kernel allocation flag to
+      use.  For the SBUS, <constant>SNDRV_DMA_TYPE_SBUS</constant> and
+      <function>snd_dma_sbus_data(sbus_dev)</function> are used instead.
+      For the PCI scatter-gather buffers, use
+      <constant>SNDRV_DMA_TYPE_DEV_SG</constant> with
+      <function>snd_dma_pci_data(pci)</function>
+      (see the section
+          <link linkend="buffer-and-memory-non-contiguous"><citetitle>Non-Contiguous Buffers
+          </citetitle></link>).
       </para>
 
       <para>
@@ -4936,11 +4962,13 @@ struct _snd_pcm_runtime {
 
       <para>
         For creating the SG-buffer handler, call
-        <function>snd_pcm_lib_preallocate_sg_pages()</function> or
-        <function>snd_pcm_lib_preallocate_sg_pages_for_all()</function>
+        <function>snd_pcm_lib_preallocate_pages()</function> or
+        <function>snd_pcm_lib_preallocate_pages_for_all()</function>
+        with <constant>SNDRV_DMA_TYPE_DEV_SG</constant>
 	in the PCM constructor like other PCI pre-allocator.
-        You need to pass the
-        <structname>pci_dev</structname> struct pointer of the chip.
+        You need to pass the <function>snd_dma_pci_data(pci)</function>,
+        where pci is the struct <structname>pci_dev</structname> pointer
+        of the chip as well.
         The <type>snd_sg_buf_t</type> instance is created as
         substream-&gt;dma_private. You can cast
         the pointer like: 
@@ -5274,7 +5302,7 @@ struct _snd_pcm_runtime {
     </para>
 
     <para>
-      For keeping the readability of 2.5 source code, it's recommended to
+      For keeping the readability of 2.6 source code, it's recommended to
       separate the above ifdef condition as the patch file in alsa-driver
       directory.
       See <filename>alsa-driver/pci/ali5451.c</filename> for example.
@@ -5606,7 +5634,7 @@ struct _snd_pcm_runtime {
 	tree.  Then the driver is evaluated, audited and tested
 	by developers and users.  After a certain time, the driver
 	will go to alsa-kernel tree and eventually integrated into
-	Linux 2.5 tree.
+	Linux 2.6 tree.
 	</para>
 
 	<para>
@@ -5642,61 +5670,44 @@ struct _snd_pcm_runtime {
 
 	<listitem>
 	<para>
-	Modify alsa-driver/acore/Makefile
+	Create the Kconfig entry
 	</para>
 
 	<para>
-	Here define the dependent modules.
+	Add the new entry of Kconfig for your xyz driver.
       <informalexample>
         <programlisting>
 <![CDATA[
-  obj-$(CONFIG_SND_XYZ) += snd.o ...
+  config SND_BT87X
+          tristate "Foobar XYX"
+          depends on SND
+          select SND_PCM
+          help
+            Say 'Y' or 'M' to include support for Foobar XYZ soundcard.
 ]]>
         </programlisting>
       </informalexample>
 
-	If the driver supports PCM, snd-pcm.o,
-	snd-timer.o and snd-page-alloc.o
-	will be needed.
-	</para>
-	<para>
-	For rawmidi, snd-rawmidi.o is needed in addition.
-	The MIDI stuff is also related to the sequencer.
-	You'll need to modify alsa-driver/acore/seq/Makefile.
+	the line, select SND_PCM, specifies that the driver xyz supports
+	PCM.  In addition to SND_PCM, the following components are
+	supported for select command:
+	SND_RAWMIDI, SND_TIMER, SND_HWDEP, SND_MPU401_UART,
+	SND_OPL3_LIB, SND_OPL4_LIB, SND_VX_LIB, SND_AC97_CODEC.
+	Add the select command for each supported component.
 	</para>
 
 	<para>
-	For OPL3, snd-hwdep.o is needed, too.
-	It's involved with the sequencer, and as well as rawmidi,
-	you'll need to modify alsa-driver/acore/seq/Makefile
-	and acore/seq/instr/Makefile in addition.
-	Also, a new entry is necessary in
-	alsa-driver/drivers/opl3/Makefile.
+	Note that some selections imply the lowlevel selections.
+	For example, PCM includes TIMER, MPU401_UART includes RAWMIDI,
+	AC97_CODEC includes PCM, and OPL3_LIB includes HWDEP.
+	You don't need to give the lowlevel selections again.
 	</para>
 
-	</listitem>
-
-	<listitem>
 	<para>
-	Modify alsa-driver/utils/Modules.dep
+	For the details of Kconfig script, refer to the kbuild
+	documentation.
 	</para>
 
-	<para>
-	Add the module definition for configure, here.
-	The beginning of the line must be a vertical bar, following
-	the card module name (snd-xyz) and the list of its all 
-	dependent modules.
-
-      <informalexample>
-        <programlisting>
-<![CDATA[
-  %dir linux/sound/pci
-  |snd-azt3328 snd-pcm snd-mpu401-uart snd-opl3-lib snd-opl3-synth
-  |snd-xyz snd-pcm ...
-]]>
-        </programlisting>
-      </informalexample>
-	</para>
 	</listitem>
 
 	<listitem>
@@ -5724,7 +5735,7 @@ struct _snd_pcm_runtime {
       <informalexample>
         <programlisting>
 <![CDATA[
-  extra-subdir-y := pdplus vx222 xyz
+  obj-$(CONFIG_SND) += xyz/
 ]]>
         </programlisting>
       </informalexample>
@@ -5739,13 +5750,13 @@ struct _snd_pcm_runtime {
 	<title>Sample Makefile for a driver xyz</title>
         <programlisting>
 <![CDATA[
-  TOPDIR = ../..
+  ifndef SND_TOPDIR
+  SND_TOPDIR=../..
+  endif
 
   include $(TOPDIR)/toplevel.config
   include $(TOPDIR)/Makefile.conf
 
-  TOPDIR = $(MAINSRCDIR)
-
   snd-xyz-objs := xyz.o abc.o def.o
 
   obj-$(CONFIG_SND_XYZ) += snd-xyz.o
@@ -5759,7 +5770,7 @@ struct _snd_pcm_runtime {
 
 	<listitem>
 	<para>
-	Modify alsa-driver/acore/Makefile
+	Create the Kconfig entry
 	</para>
 
 	<para>
@@ -5769,23 +5780,6 @@ struct _snd_pcm_runtime {
 
 	<listitem>
 	<para>
-	Modify alsa-driver/utils/Modules.dep
-	</para>
-
-	<para>
-      <informalexample>
-        <programlisting>
-<![CDATA[
-	%dir linux/sound/pci/xyz
-	|snd-xyz snd-pcm ...
-]]>
-        </programlisting>
-      </informalexample>
-	</para>
-	</listitem>
-
-	<listitem>
-	<para>
 	Run cvscompile script to re-generate the configure script and
 	build the whole stuff again.
 	</para>
--- diff/Documentation/sound/alsa/Joystick.txt	2004-02-18 08:54:06.000000000 +0000
+++ source/Documentation/sound/alsa/Joystick.txt	2004-03-16 09:37:55.298133576 +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 03:27:22.000000000 +0000
+++ source/Documentation/usb/acm.txt	2004-03-16 09:37:55.299133424 +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 03:27:08.000000000 +0000
+++ source/Documentation/usb/error-codes.txt	2004-03-16 09:37:55.299133424 +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-11 10:20:19.000000000 +0000
+++ source/MAINTAINERS	2004-03-16 09:37:55.301133120 +0000
@@ -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
@@ -1966,13 +1972,6 @@ P:     Romain Lievin
 M:     roms@lpg.ticalc.org
 S:     Maintained
 
-TIEMAN VOYAGER USB BRAILLE DISPLAY DRIVER
-P:	Stephane Dalton
-M:	sdalton@videotron.ca
-P:	Stéphane Doyon
-M:	s.doyon@videotron.ca
-S:	Maintained
-
 TLAN NETWORK DRIVER
 P:	Samuel Chessman
 M:	chessman@tux.org
@@ -2037,8 +2036,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
@@ -2154,14 +2151,6 @@ L:	linux-usb-devel@lists.sourceforge.net
 W:	http://pegasus2.sourceforge.net/
 S:	Maintained
 
-USB SCANNER DRIVER
-P:	Henning Meier-Geinitz
-M:	henning@meier-geinitz.de
-L:	linux-usb-users@lists.sourceforge.net
-L:	linux-usb-devel@lists.sourceforge.net
-W:	http://www.meier-geinitz.de/kernel/
-S:	Maintained
-
 USB SE401 DRIVER
 P:	Jeroen Vreeken
 M:	pe1rxq@amsat.org
--- diff/Makefile	2004-03-11 10:20:19.000000000 +0000
+++ source/Makefile	2004-03-16 09:37:55.302132968 +0000
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 4
-EXTRAVERSION =
+EXTRAVERSION = -mm2
 NAME=Feisty Dunnart
 
 # *DOCUMENTATION*
@@ -304,17 +304,10 @@ RCS_TAR_IGNORE := --exclude SCCS --exclu
 # ===========================================================================
 # Rules shared between *config targets and build targets
 
-# Helpers built in scripts/
-
-scripts/docproc scripts/split-include : scripts ;
-
-.PHONY: scripts scripts/fixdep
-scripts:
-	$(Q)$(MAKE) $(build)=scripts
-
-scripts/fixdep:
-	$(Q)$(MAKE) $(build)=scripts $@
-
+# Basic helpers built in scripts/
+.PHONY: scripts_basic
+scripts_basic:
+	$(Q)$(MAKE) $(build)=scripts/basic
 
 # To make sure we do not include .config for any of the *config targets
 # catch them early, and hand them over to scripts/kconfig/Makefile
@@ -358,9 +351,9 @@ ifeq ($(config-targets),1)
 # *config targets only - make sure prerequisites are updated, and descend
 # in scripts/kconfig to make the *config target
 
-%config: scripts/fixdep FORCE
+config: scripts_basic FORCE
 	$(Q)$(MAKE) $(build)=scripts/kconfig $@
-config : scripts/fixdep FORCE
+%config: scripts_basic FORCE
 	$(Q)$(MAKE) $(build)=scripts/kconfig $@
 
 else
@@ -368,6 +361,16 @@ else
 # Build targets only - this includes vmlinux, arch specific targets, clean
 # targets and others. In general all targets except *config targets.
 
+# Additional helpers built in scripts/
+# Carefully list dependencies so we do not try to build scripts twice
+# in parrallel
+.PHONY: scripts
+scripts: scripts_basic include/config/MARKER
+	$(Q)$(MAKE) $(build)=$(@)
+
+scripts_basic: include/linux/autoconf.h
+
+
 # That's our default target when none is given on the command line
 # Note that 'modules' will be added as a prerequisite as well, 
 # in the CONFIG_MODULES part below
@@ -400,7 +403,9 @@ include .config
 # with it and forgot to run make oldconfig
 include/linux/autoconf.h: .config
 	$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
-
+else
+# Dummy target needed, because used as prerequisite
+include/linux/autoconf.h: ;
 endif
 
 include $(srctree)/arch/$(ARCH)/Makefile
@@ -444,6 +449,7 @@ endif
 
 ifdef CONFIG_DEBUG_INFO
 CFLAGS		+= -g
+AFLAGS		+= -g
 endif
 
 # warn about C99 declaration after statement
@@ -633,9 +639,9 @@ include/asm:
 
 # 	Split autoconf.h into include/linux/config/*
 
-include/config/MARKER: scripts/split-include include/linux/autoconf.h
+include/config/MARKER: include/linux/autoconf.h
 	@echo '  SPLIT   include/linux/autoconf.h -> include/config/*'
-	@scripts/split-include include/linux/autoconf.h include/config
+	@scripts/basic/split-include include/linux/autoconf.h include/config
 	@touch $@
 
 # Generate some files
@@ -757,26 +763,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 +780,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
 # ---------------------------------------------------------------------------
@@ -932,7 +935,7 @@ help:
 
 # Documentation targets
 # ---------------------------------------------------------------------------
-%docs: scripts/docproc FORCE
+%docs: scripts FORCE
 	$(Q)$(MAKE) $(build)=Documentation/DocBook $@
 
 # Scripts to check various things for consistency
--- diff/arch/alpha/kernel/alpha_ksyms.c	2004-03-11 10:20:19.000000000 +0000
+++ source/arch/alpha/kernel/alpha_ksyms.c	2004-03-16 09:37:55.303132816 +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/smp.c	2003-10-09 08:47:33.000000000 +0000
+++ source/arch/alpha/kernel/smp.c	2004-03-16 09:37:55.304132664 +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/common/sa1111-pcibuf.c	2004-03-11 10:20:19.000000000 +0000
+++ source/arch/arm/common/sa1111-pcibuf.c	2004-03-16 09:37:55.304132664 +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/arm26/Kconfig	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/arm26/Kconfig	2004-03-16 09:37:55.305132512 +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 08:47:33.000000000 +0000
+++ source/arch/cris/kernel/process.c	2004-03-16 09:37:55.305132512 +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-11 10:20:20.000000000 +0000
+++ source/arch/h8300/kernel/sys_h8300.c	2004-03-16 09:37:55.306132360 +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 09:00:51.000000000 +0000
+++ source/arch/h8300/kernel/syscalls.S	2004-03-16 09:37:55.306132360 +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-11 10:20:20.000000000 +0000
+++ source/arch/i386/Kconfig	2004-03-16 09:37:55.308132056 +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
@@ -1058,9 +1113,6 @@ choice
 	prompt "PCI access mode"
 	depends on PCI && !X86_VISWS
 	default PCI_GOANY
-
-config PCI_GOBIOS
-	bool "BIOS"
 	---help---
 	  On PCI systems, the BIOS can be used to detect the PCI devices and
 	  determine their configuration. However, some old PCI motherboards
@@ -1076,6 +1128,9 @@ config PCI_GOBIOS
 	  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_GOBIOS
+	bool "BIOS"
+
 config PCI_GOMMCONFIG
 	bool "MMConfig"
 
@@ -1241,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
@@ -1283,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
@@ -1299,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
@@ -1348,7 +1598,7 @@ config X86_BIOS_REBOOT
 
 config X86_TRAMPOLINE
 	bool
-	depends on SMP || X86_VISWS
+	depends on X86_SMP || (X86_VOYAGER && SMP)
 	default y
 
 config PC
--- diff/arch/i386/Makefile	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/i386/Makefile	2004-03-16 09:37:55.309131904 +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-11 10:20:20.000000000 +0000
+++ source/arch/i386/boot/setup.S	2004-03-16 09:37:55.310131752 +0000
@@ -51,6 +51,8 @@
  *   projects 1572D, 1484D, 1386D, 1226DT
  * disk signature read by Matt Domsch <Matt_Domsch@dell.com>
  *	and Andrew Wilks <Andrew_Wilks@dell.com> September 2003
+ * legacy CHS retreival by Patrick J. LoPresti <patl@users.sourceforge.net>
+ *      March 2004
  */
 
 #include <linux/config.h>
@@ -164,7 +166,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
 
@@ -592,7 +594,11 @@ done_apm_bios:
 	pushw	%ds
 	popw	%es
 	movw	$EDDBUF, %bx
-	int	$0x13
+	pushw   %dx             # work around buggy BIOSes
+	stc                     # work around buggy BIOSes
+	int     $0x13
+	sti                     # work around buggy BIOSes
+	popw    %dx
 	jc	disk_sig_done
 	movl	(EDDBUF+MBR_SIG_OFFSET), %eax
 	movl	%eax, (DISK80_SIG_BUFFER)	# store success
@@ -603,32 +609,34 @@ disk_sig_done:
 # This consists of two calls:
 #    int 13h ah=41h "Check Extensions Present"
 #    int 13h ah=48h "Get Device Parameters"
+#    int 13h ah=08h "Legacy Get Device Parameters"
 #
 # A buffer of size EDDMAXNR*(EDDEXTSIZE+EDDPARMSIZE) is reserved for our use
 # in the empty_zero_page at EDDBUF.  The first four bytes of which are
 # used to store the device number, interface support map and version
-# results from fn41.  The following 74 bytes are used to store
-# the results from fn48.  Starting from device 80h, fn41, then fn48
+# results from fn41.  The next four bytes are used to store the legacy
+# cylinders, heads, and sectors from fn08. The following 74 bytes are used to
+# store the results from fn48.  Starting from device 80h, fn41, then fn48
 # are called and their results stored in EDDBUF+n*(EDDEXTSIZE+EDDPARMIZE).
 # Then the pointer is incremented to store the data for the next call.
 # This repeats until either a device doesn't exist, or until EDDMAXNR
 # devices have been stored.
-# The one tricky part is that ds:si always points four bytes into
-# the structure, and the fn41 results are stored at offsets
+# The one tricky part is that ds:si always points EDDEXTSIZE bytes into
+# the structure, and the fn41 and fn08 results are stored at offsets
 # from there.  This removes the need to increment the pointer for
 # every store, and leaves it ready for the fn48 call.
 # A second one-byte buffer, EDDNR, in the empty_zero_page stores
 # the number of BIOS devices which exist, up to EDDMAXNR.
 # In setup.c, copy_edd() stores both empty_zero_page buffers away
-# for later use, as they would get overwritten otherwise. 
+# for later use, as they would get overwritten otherwise.
 # This code is sensitive to the size of the structs in edd.h
-edd_start:  
+edd_start:
 						# %ds points to the bootsector
        						# result buffer for fn48
-    	movw	$EDDBUF+EDDEXTSIZE, %si		# in ds:si, fn41 results
-						# kept just before that    
+	movw	$EDDBUF+EDDEXTSIZE, %si		# in ds:si, fn41 results
+						# kept just before that
 	movb	$0, (EDDNR)			# zero value at EDDNR
-    	movb	$0x80, %dl			# BIOS device 0x80
+	movb	$0x80, %dl			# BIOS device 0x80
 
 edd_check_ext:
 	movb	$CHECKEXTENSIONSPRESENT, %ah    # Function 41
@@ -636,30 +644,56 @@ edd_check_ext:
 	int	$0x13				# make the call
 	jc	edd_done			# no more BIOS devices
 
-    	cmpw	$EDDMAGIC2, %bx			# is magic right?
+	cmpw	$EDDMAGIC2, %bx			# is magic right?
 	jne	edd_next			# nope, next...
 
-    	movb	%dl, %ds:-4(%si)		# store device number
-    	movb	%ah, %ds:-3(%si)		# store version
-	movw	%cx, %ds:-2(%si)		# store extensions
+	movb	%dl, %ds:-8(%si)		# store device number
+	movb	%ah, %ds:-7(%si)		# store version
+	movw	%cx, %ds:-6(%si)		# store extensions
 	incb	(EDDNR)				# note that we stored something
-        
-edd_get_device_params:  
+
+edd_get_device_params:
 	movw	$EDDPARMSIZE, %ds:(%si)		# put size
-    	movb	$GETDEVICEPARAMETERS, %ah	# Function 48
+	movw	$0x0, %ds:2(%si)		# work around buggy BIOSes
+	movb	$GETDEVICEPARAMETERS, %ah	# Function 48
 	int	$0x13				# make the call
 						# Don't check for fail return
 						# it doesn't matter.
+edd_get_legacy_chs:
+	xorw    %ax, %ax
+	movw    %ax, %ds:-4(%si)
+	movw    %ax, %ds:-2(%si)
+        # Ralf Brown's Interrupt List says to set ES:DI to
+	# 0000h:0000h "to guard against BIOS bugs"
+	pushw   %es
+	movw    %ax, %es
+	movw    %ax, %di
+	pushw   %dx                             # legacy call clobbers %dl
+	movb    $LEGACYGETDEVICEPARAMETERS, %ah # Function 08
+	int     $0x13                           # make the call
+	jc      edd_legacy_done                 # failed
+	movb    %cl, %al                        # Low 6 bits are max
+	andb    $0x3F, %al                      #   sector number
+	movb	%al, %ds:-1(%si)                # Record max sect
+	movb    %dh, %ds:-2(%si)                # Record max head number
+	movb    %ch, %al                        # Low 8 bits of max cyl
+	shr     $6, %cl
+	movb    %cl, %ah                        # High 2 bits of max cyl
+	movw    %ax, %ds:-4(%si)
+
+edd_legacy_done:
+	popw    %dx
+	popw    %es
 	movw	%si, %ax			# increment si
 	addw	$EDDPARMSIZE+EDDEXTSIZE, %ax
 	movw	%ax, %si
 
 edd_next:
-        incb	%dl				# increment to next device
-       	cmpb	$EDDMAXNR, (EDDNR) 		# Out of space?
+	incb	%dl				# increment to next device
+	cmpb	$EDDMAXNR, (EDDNR) 		# Out of space?
 	jb	edd_check_ext			# keep looping
-    
-edd_done:   
+
+edd_done:
 #endif
 
 # Now we want to move to protected mode ...
--- diff/arch/i386/boot/tools/build.c	2003-05-21 10:49:49.000000000 +0000
+++ source/arch/i386/boot/tools/build.c	2004-03-16 09:37:55.311131600 +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/kernel/Makefile	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/Makefile	2004-03-16 09:37:55.311131600 +0000
@@ -7,13 +7,14 @@ 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
--- diff/arch/i386/kernel/acpi/boot.c	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/acpi/boot.c	2004-03-16 09:37:55.312131448 +0000
@@ -128,7 +128,9 @@ static int __init acpi_parse_mcfg(unsign
 
 	return 0;
 }
-#endif /* CONFIG_PCI_MMCONFIG */
+#else
+#define	acpi_parse_mcfg NULL
+#endif /* !CONFIG_PCI_MMCONFIG */
 
 #ifdef CONFIG_X86_LOCAL_APIC
 static int __init
@@ -370,7 +372,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);
 	}
@@ -424,6 +426,8 @@ static int __init acpi_parse_hpet(unsign
 	       hpet_address);
 	return 0;
 }
+#else
+#define	acpi_parse_hpet	NULL
 #endif
 
 /* detect the location of the ACPI PM Timer */
@@ -454,6 +458,8 @@ static int __init acpi_parse_fadt(unsign
 		printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n", pmtmr_ioport);
 	return 0;
 }
+#else
+#define	acpi_parse_fadt	NULL
 #endif
 
 
@@ -666,7 +672,7 @@ acpi_boot_init (void)
 		return error;
 	}
 
-	(void) acpi_table_parse(ACPI_BOOT, acpi_parse_sbf);
+	acpi_table_parse(ACPI_BOOT, acpi_parse_sbf);
 
 	/*
 	 * blacklist may disable ACPI entirely
@@ -683,19 +689,9 @@ acpi_boot_init (void)
 	 */
 	acpi_process_madt();
 
-#ifdef CONFIG_X86_PM_TIMER
 	acpi_table_parse(ACPI_FADT, acpi_parse_fadt);
-#endif
-
-#ifdef CONFIG_HPET_TIMER
-	(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
+	acpi_table_parse(ACPI_HPET, acpi_parse_hpet);
+	acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
 
 	return 0;
 }
--- diff/arch/i386/kernel/acpi/sleep.c	2003-08-20 13:16:24.000000000 +0000
+++ source/arch/i386/kernel/acpi/sleep.c	2004-03-16 09:37:55.313131296 +0000
@@ -19,13 +19,29 @@ extern void zap_low_mappings(void);
 
 extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long));
 
-static void init_low_mapping(pgd_t *pgd, int pgd_limit)
+static void map_low(pgd_t *pgd_base, unsigned long start, unsigned long end)
 {
-	int pgd_ofs = 0;
-
-	while ((pgd_ofs < pgd_limit) && (pgd_ofs + USER_PTRS_PER_PGD < PTRS_PER_PGD)) {
-		set_pgd(pgd, *(pgd+USER_PTRS_PER_PGD));
-		pgd_ofs++, pgd++;
+	unsigned long vaddr;
+	pmd_t *pmd;
+	pgd_t *pgd;
+	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;
+			set_pmd(pmd, __pmd(_KERNPG_TABLE + _PAGE_PSE +
+								vaddr - start));
+		}
 	}
 }
 
@@ -39,7 +55,9 @@ int acpi_save_state_mem (void)
 {
 	if (!acpi_wakeup_address)
 		return 1;
-	init_low_mapping(swapper_pg_dir, USER_PTRS_PER_PGD);
+	if (!cpu_has_pse)
+		return 1;
+	map_low(swapper_pg_dir, 0, LOW_MAPPINGS_SIZE);
 	memcpy((void *) acpi_wakeup_address, &wakeup_start, &wakeup_end - &wakeup_start);
 	acpi_copy_wakeup_routine(acpi_wakeup_address);
 
--- diff/arch/i386/kernel/apic.c	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/apic.c	2004-03-16 09:37:55.314131144 +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 08:47:16.000000000 +0000
+++ source/arch/i386/kernel/asm-offsets.c	2004-03-16 09:37:55.315130992 +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	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/bootflag.c	2004-03-16 09:37:55.315130992 +0000
@@ -48,7 +48,7 @@ static void __init sbf_write(u8 v)
 		if(!parity(v))
 			v|=SBF_PARITY;
 
-		printk(KERN_INFO "Simple Boot Flag 0x%x\n", v);
+		printk(KERN_INFO "Simple Boot Flag at 0x%x set to 0x%x\n", sbf_port, v);
 
 		spin_lock_irqsave(&rtc_lock, flags);
 		CMOS_WRITE(v, sbf_port);
--- diff/arch/i386/kernel/cpu/common.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/i386/kernel/cpu/common.c	2004-03-16 09:37:55.316130840 +0000
@@ -196,7 +196,6 @@ int __init have_cpuid_p(void)
 void __init generic_identify(struct cpuinfo_x86 * c)
 {
 	u32 tfms, xlvl;
-	int junk;
 
 	if (have_cpuid_p()) {
 		/* Get vendor name */
@@ -211,8 +210,8 @@ void __init generic_identify(struct cpui
 	
 		/* Intel-defined flags: level 0x00000001 */
 		if ( c->cpuid_level >= 0x00000001 ) {
-			u32 capability, excap;
-			cpuid(0x00000001, &tfms, &junk, &excap, &capability);
+			u32 capability, excap, misc;
+			cpuid(0x00000001, &tfms, &misc, &excap, &capability);
 			c->x86_capability[0] = capability;
 			c->x86_capability[4] = excap;
 			c->x86 = (tfms >> 8) & 15;
@@ -222,6 +221,9 @@ void __init generic_identify(struct cpui
 				c->x86_model += ((tfms >> 16) & 0xF) << 4;
 			} 
 			c->x86_mask = tfms & 15;
+
+			if (c->x86_capability[0] & (1<<19))
+				c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
 		} else {
 			/* Have CPUID level 0 only - unheard of */
 			c->x86 = 4;
@@ -232,7 +234,7 @@ void __init generic_identify(struct cpui
 		if ( (xlvl & 0xffff0000) == 0x80000000 ) {
 			if ( xlvl >= 0x80000001 )
 				c->x86_capability[1] = cpuid_edx(0x80000001);
-			if ( xlvl >= 0x80000004 )
+			if ( xlvl >= 0x80000004)
 				get_model_name(c); /* Default name */
 		}
 	}
@@ -261,15 +263,8 @@ static int __init x86_serial_nr_setup(ch
 }
 __setup("serialnumber", x86_serial_nr_setup);
 
-
-
-/*
- * This does the hard work of actually picking apart the CPU stuff...
- */
-void __init identify_cpu(struct cpuinfo_x86 *c)
+void __init early_identify_cpu(struct cpuinfo_x86 *c)
 {
-	int i;
-
 	c->loops_per_jiffy = loops_per_jiffy;
 	c->x86_cache_size = -1;
 	c->x86_vendor = X86_VENDOR_UNKNOWN;
@@ -277,6 +272,7 @@ void __init identify_cpu(struct cpuinfo_
 	c->x86_model = c->x86_mask = 0;	/* So far unknown... */
 	c->x86_vendor_id[0] = '\0'; /* Unset */
 	c->x86_model_id[0] = '\0';  /* Unset */
+	c->x86_clflush_size = 32;
 	memset(&c->x86_capability, 0, sizeof c->x86_capability);
 
 	if (!have_cpuid_p()) {
@@ -289,6 +285,16 @@ void __init identify_cpu(struct cpuinfo_
 	}
 
 	generic_identify(c);
+}
+
+/*
+ * This does the hard work of actually picking apart the CPU stuff...
+ */
+void __init identify_cpu(struct cpuinfo_x86 *c)
+{
+	int i;
+
+	early_identify_cpu(c);
 
 	printk(KERN_DEBUG "CPU:     After generic identify, caps: %08lx %08lx %08lx %08lx\n",
 		c->x86_capability[0],
@@ -514,12 +520,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-16 09:37:55.317130688 +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-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/cpu/intel.c	2004-03-16 09:37:55.317130688 +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-16 09:37:55.318130536 +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/dmi_scan.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/i386/kernel/dmi_scan.c	2004-03-16 09:37:55.319130384 +0000
@@ -525,7 +525,7 @@ static __init int print_if_true(struct d
 #ifdef	CONFIG_ACPI_BOOT
 extern int acpi_disabled, acpi_force;
 
-static __init __attribute__((unused)) int acpi_disable(struct dmi_blacklist *d) 
+static __init __attribute__((unused)) int disable_acpi(struct dmi_blacklist *d)
 { 
 	if (!acpi_force) { 
 		printk(KERN_NOTICE "%s detected: acpi off\n",d->ident); 
@@ -933,7 +933,7 @@ static __initdata struct dmi_blacklist d
 	 *	Boxes that need ACPI disabled
 	 */
 
-	{ acpi_disable, "IBM Thinkpad", {
+	{ disable_acpi, "IBM Thinkpad", {
 			MATCH(DMI_BOARD_VENDOR, "IBM"),
 			MATCH(DMI_BOARD_NAME, "2629H1G"),
 			NO_MATCH, NO_MATCH }},
--- diff/arch/i386/kernel/doublefault.c	2003-10-09 08:47:16.000000000 +0000
+++ source/arch/i386/kernel/doublefault.c	2004-03-16 09:37:55.319130384 +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/edd.c	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/edd.c	2004-03-16 09:37:55.320130232 +0000
@@ -1,8 +1,9 @@
 /*
  * linux/arch/i386/kernel/edd.c
- *  Copyright (C) 2002, 2003 Dell Inc.
+ *  Copyright (C) 2002, 2003, 2004 Dell Inc.
  *  by Matt Domsch <Matt_Domsch@dell.com>
  *  disk80 signature by Matt Domsch, Andrew Wilks, and Sandeep K. Shandilya
+ *  legacy CHS by Patrick J. LoPresti <patl@users.sourceforge.net>
  *
  * BIOS Enhanced Disk Drive Services (EDD)
  * conformant to T13 Committee www.t13.org
@@ -60,7 +61,7 @@ MODULE_AUTHOR("Matt Domsch <Matt_Domsch@
 MODULE_DESCRIPTION("sysfs interface to BIOS EDD information");
 MODULE_LICENSE("GPL");
 
-#define EDD_VERSION "0.12 2004-Jan-26"
+#define EDD_VERSION "0.13 2004-Mar-09"
 #define EDD_DEVICE_NAME_SIZE 16
 #define REPORT_URL "http://linux.dell.com/edd/results.html"
 
@@ -231,7 +232,7 @@ static ssize_t
 edd_show_raw_data(struct edd_device *edev, char *buf)
 {
 	struct edd_info *info = edd_dev_get_info(edev);
-	ssize_t len = sizeof (*info) - 4;
+	ssize_t len = sizeof (info->params);
 	if (!edev || !info || !buf) {
 		return -EINVAL;
 	}
@@ -240,10 +241,10 @@ edd_show_raw_data(struct edd_device *ede
 		len = info->params.length;
 
 	/* In case of buggy BIOSs */
-	if (len > (sizeof(*info) - 4))
-		len = sizeof(*info) - 4;
+	if (len > (sizeof(info->params)))
+		len = sizeof(info->params);
 
-	memcpy(buf, ((char *)info) + 4, len);
+	memcpy(buf, &info->params, len);
 	return len;
 }
 
@@ -321,6 +322,45 @@ edd_show_info_flags(struct edd_device *e
 }
 
 static ssize_t
+edd_show_legacy_cylinders(struct edd_device *edev, char *buf)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	char *p = buf;
+	if (!edev || !info || !buf) {
+		return -EINVAL;
+	}
+
+	p += snprintf(p, left, "0x%x\n", info->legacy_cylinders);
+	return (p - buf);
+}
+
+static ssize_t
+edd_show_legacy_heads(struct edd_device *edev, char *buf)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	char *p = buf;
+	if (!edev || !info || !buf) {
+		return -EINVAL;
+	}
+
+	p += snprintf(p, left, "0x%x\n", info->legacy_heads);
+	return (p - buf);
+}
+
+static ssize_t
+edd_show_legacy_sectors(struct edd_device *edev, char *buf)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	char *p = buf;
+	if (!edev || !info || !buf) {
+		return -EINVAL;
+	}
+
+	p += snprintf(p, left, "0x%x\n", info->legacy_sectors);
+	return (p - buf);
+}
+
+static ssize_t
 edd_show_default_cylinders(struct edd_device *edev, char *buf)
 {
 	struct edd_info *info = edd_dev_get_info(edev);
@@ -384,6 +424,33 @@ edd_show_sectors(struct edd_device *edev
  */
 
 static int
+edd_has_legacy_cylinders(struct edd_device *edev)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	if (!edev || !info)
+		return -EINVAL;
+	return info->legacy_cylinders > 0;
+}
+
+static int
+edd_has_legacy_heads(struct edd_device *edev)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	if (!edev || !info)
+		return -EINVAL;
+	return info->legacy_heads > 0;
+}
+
+static int
+edd_has_legacy_sectors(struct edd_device *edev)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	if (!edev || !info)
+		return -EINVAL;
+	return info->legacy_sectors > 0;
+}
+
+static int
 edd_has_default_cylinders(struct edd_device *edev)
 {
 	struct edd_info *info = edd_dev_get_info(edev);
@@ -452,6 +519,12 @@ static EDD_DEVICE_ATTR(version, 0444, ed
 static EDD_DEVICE_ATTR(extensions, 0444, edd_show_extensions, NULL);
 static EDD_DEVICE_ATTR(info_flags, 0444, edd_show_info_flags, NULL);
 static EDD_DEVICE_ATTR(sectors, 0444, edd_show_sectors, NULL);
+static EDD_DEVICE_ATTR(legacy_cylinders, 0444, edd_show_legacy_cylinders,
+		       edd_has_legacy_cylinders);
+static EDD_DEVICE_ATTR(legacy_heads, 0444, edd_show_legacy_heads,
+		       edd_has_legacy_heads);
+static EDD_DEVICE_ATTR(legacy_sectors, 0444, edd_show_legacy_sectors,
+		       edd_has_legacy_sectors);
 static EDD_DEVICE_ATTR(default_cylinders, 0444, edd_show_default_cylinders,
 		       edd_has_default_cylinders);
 static EDD_DEVICE_ATTR(default_heads, 0444, edd_show_default_heads,
@@ -478,6 +551,9 @@ static struct attribute * def_attrs[] = 
 
 /* These attributes are conditional and only added for some devices. */
 static struct edd_attribute * edd_attrs[] = {
+	&edd_attr_legacy_cylinders,
+	&edd_attr_legacy_heads,
+	&edd_attr_legacy_sectors,
 	&edd_attr_default_cylinders,
 	&edd_attr_default_heads,
 	&edd_attr_default_sectors_per_track,
--- diff/arch/i386/kernel/entry.S	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/entry.S	2004-03-16 09:37:55.322129928 +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 $(THREAD_SIZE - 512),%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,38 +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|_TIF_SYSCALL_AUDIT),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
 ENTRY(system_call)
@@ -287,7 +416,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|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
 	jnz syscall_trace_entry
 syscall_call:
 	call *sys_call_table(,%eax,4)
@@ -296,10 +425,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 +454,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 +469,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
@@ -354,7 +512,7 @@ syscall_trace_entry:
 	# perform syscall exit tracing
 	ALIGN
 syscall_exit_work:
-	testb $_TIF_SYSCALL_TRACE, %cl
+	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT), %cl
 	jz work_pending
 	sti				# could let do_syscall_trace() call
 					# schedule() instead
@@ -382,7 +540,7 @@ syscall_badsys:
  */
 .data
 ENTRY(interrupt)
-.text
+.previous
 
 vector=0
 ENTRY(irq_entries_start)
@@ -392,7 +550,7 @@ ENTRY(irq_entries_start)
 	jmp common_interrupt
 .data
 	.long 1b
-.text
+.previous
 vector=vector+1
 .endr
 
@@ -433,12 +591,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 +692,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 +769,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 +1030,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 +1047,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-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/head.S	2004-03-16 09:37:55.323129776 +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-16 09:37:55.324129624 +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-16 09:37:55.325129472 +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-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/i8259.c	2004-03-16 09:37:55.325129472 +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 08:47:33.000000000 +0000
+++ source/arch/i386/kernel/init_task.c	2004-03-16 09:37:55.325129472 +0000
@@ -20,13 +20,13 @@ EXPORT_SYMBOL(init_mm);
 /*
  * Initial thread structure.
  *
- * We need to make sure that this is 8192-byte aligned due to the
+ * We need to make sure that this is THREAD_SIZE aligned due to the
  * way process stacks are handled. This is done by having a special
  * "init_task" linker map entry..
  */
 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-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/io_apic.c	2004-03-16 09:37:55.327129168 +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-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/irq.c	2004-03-16 09:37:55.328129016 +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 08:47:16.000000000 +0000
+++ source/arch/i386/kernel/ldt.c	2004-03-16 09:37:55.329128864 +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-03-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/mpparse.c	2004-03-16 09:37:55.330128712 +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");
--- diff/arch/i386/kernel/nmi.c	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/nmi.c	2004-03-16 09:37:55.331128560 +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-16 09:37:55.332128408 +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-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/process.c	2004-03-16 09:37:55.333128256 +0000
@@ -28,6 +28,7 @@
 #include <linux/a.out.h>
 #include <linux/interrupt.h>
 #include <linux/config.h>
+#include <linux/version.h>
 #include <linux/delay.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
@@ -45,6 +46,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
@@ -222,7 +224,7 @@ void show_regs(struct pt_regs * regs)
 
 	if (regs->xcs & 3)
 		printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp);
-	printk(" EFLAGS: %08lx    %s\n",regs->eflags, print_tainted());
+	printk(" EFLAGS: %08lx    %s  (%s)\n",regs->eflags, print_tainted(),UTS_RELEASE);
 	printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
 		regs->eax,regs->ebx,regs->ecx,regs->edx);
 	printk("ESI: %08lx EDI: %08lx EBP: %08lx",
@@ -302,6 +304,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 +320,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 +356,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);
@@ -504,10 +518,41 @@ struct task_struct fastcall * __switch_t
 
 	__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/ptrace.c	2003-06-09 13:18:17.000000000 +0000
+++ source/arch/i386/kernel/ptrace.c	2004-03-16 09:37:55.333128256 +0000
@@ -14,6 +14,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/security.h>
+#include <linux/audit.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -524,6 +525,14 @@ out:
 __attribute__((regparm(3)))
 void do_syscall_trace(struct pt_regs *regs, int entryexit)
 {
+	if (unlikely(current->audit_context)) {
+		if (!entryexit)
+			audit_syscall_entry(current, regs->orig_eax,
+					    regs->ebx);
+		else
+			audit_syscall_exit(current);
+	}
+
 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
 		return;
 	if (!(current->ptrace & PT_PTRACED))
--- diff/arch/i386/kernel/reboot.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/i386/kernel/reboot.c	2004-03-16 09:37:55.334128104 +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, LOW_MAPPINGS_SIZE);
 
 	/*
 	 * Use `swapper_pg_dir' as our page directory.
--- diff/arch/i386/kernel/setup.c	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/setup.c	2004-03-16 09:37:55.335127952 +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;
 
@@ -790,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();
 
@@ -828,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
@@ -1102,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;
@@ -1138,6 +1149,8 @@ void __init setup_arch(char **cmdline_p)
 
 	dmi_scan_machine();
 
+	early_identify_cpu(&boot_cpu_data);
+
 #ifdef CONFIG_X86_GENERICARCH
 	generic_apic_probe(*cmdline_p);
 #endif	
--- diff/arch/i386/kernel/signal.c	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/signal.c	2004-03-16 09:37:55.336127800 +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);
--- diff/arch/i386/kernel/smp.c	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/smp.c	2004-03-16 09:37:55.337127648 +0000
@@ -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-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/smpboot.c	2004-03-16 09:37:55.338127496 +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 08:47:16.000000000 +0000
+++ source/arch/i386/kernel/sysenter.c	2004-03-16 09:37:55.339127344 +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 13:18:17.000000000 +0000
+++ source/arch/i386/kernel/trampoline.S	2004-03-16 09:37:55.339127344 +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-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/traps.c	2004-03-16 09:37:55.341127040 +0000
@@ -25,6 +25,7 @@
 #include <linux/highmem.h>
 #include <linux/kallsyms.h>
 #include <linux/ptrace.h>
+#include <linux/version.h>
 
 #ifdef CONFIG_EISA
 #include <linux/ioport.h>
@@ -54,12 +55,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 +88,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 +136,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,9 +215,10 @@ 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"
+			"   (%s) \n",
+		smp_processor_id(), 0xffff & regs->xcs, regs->eip,
+		print_tainted(), regs->eflags, UTS_RELEASE);
 	print_symbol("EIP is at %s\n", regs->eip);
 	printk("eax: %08lx   ebx: %08lx   ecx: %08lx   edx: %08lx\n",
 		regs->eax, regs->ebx, regs->ecx, regs->edx);
@@ -192,23 +233,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 +272,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 +319,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 +397,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 +415,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 +464,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 +606,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 +637,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 +660,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 +685,7 @@ clear_dr7:
 	__asm__("movl %0,%%db7"
 		: /* no output */
 		: "r" (0));
+	CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,)
 	return;
 
 debug_vm86:
@@ -794,19 +881,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 +954,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 +992,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-03-11 10:20:20.000000000 +0000
+++ source/arch/i386/kernel/vm86.c	2004-03-16 09:37:55.342126888 +0000
@@ -125,7 +125,7 @@ struct pt_regs * fastcall save_v86_state
 	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 08:47:16.000000000 +0000
+++ source/arch/i386/kernel/vmlinux.lds.S	2004-03-16 09:37:55.343126736 +0000
@@ -3,14 +3,19 @@
  */
 
 #include <asm-generic/vmlinux.lds.h>
-	
+#include <asm/thread_info.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)
 ENTRY(startup_32)
 jiffies = jiffies_64;
 SECTIONS
 {
-  . = 0xC0000000 + 0x100000;
+  . = __PAGE_OFFSET + 0x100000;
   /* read-only */
   _text = .;			/* Text and read-only data */
   .text : {
@@ -19,6 +24,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,25 +52,22 @@ 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) }
 
   _edata = .;			/* End of data section */
 
-  . = ALIGN(8192);		/* init_task */
+  . = ALIGN(THREAD_SIZE);	/* init_task */
   .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 +106,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 +114,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 +154,6 @@ SECTIONS
   .stab.index 0 : { *(.stab.index) }
   .stab.indexstr 0 : { *(.stab.indexstr) }
   .comment 0 : { *(.comment) }
+
+
 }
--- diff/arch/i386/kernel/vsyscall-int80.S	2003-05-21 10:50:14.000000000 +0000
+++ source/arch/i386/kernel/vsyscall-int80.S	2004-03-16 09:37:55.344126584 +0000
@@ -1,5 +1,10 @@
 /*
  * Code for the vsyscall page.  This version uses the old int $0x80 method.
+ *
+ * NOTE:
+ * 1) __kernel_vsyscall _must_ be first in this page.
+ * 2) there are alignment constraints on this stub, see vsyscall-sigreturn.S
+ *    for details.
  */
 
 	.text
--- diff/arch/i386/kernel/vsyscall-sigreturn.S	2003-05-21 10:50:14.000000000 +0000
+++ source/arch/i386/kernel/vsyscall-sigreturn.S	2004-03-16 09:37:55.344126584 +0000
@@ -2,8 +2,8 @@
  * Common code for the sigreturn entry points on the vsyscall page.
  * So far this code is the same for both int80 and sysenter versions.
  * This file is #include'd by vsyscall-*.S to define them after the
- * vsyscall entry point.  The addresses we get for these entry points
- * by doing ".balign 32" must match in both versions of the page.
+ * vsyscall entry point.  The kernel assumes that the addresses of these
+ * routines are constant for all vsyscall implementations.
  */
 
 #include <asm/unistd.h>
@@ -15,7 +15,7 @@
 */
 
 	.text
-	.balign 32
+	.org	__kernel_vsyscall+32
 	.globl __kernel_sigreturn
 	.type __kernel_sigreturn,@function
 __kernel_sigreturn:
--- diff/arch/i386/kernel/vsyscall-sysenter.S	2003-10-09 08:47:16.000000000 +0000
+++ source/arch/i386/kernel/vsyscall-sysenter.S	2004-03-16 09:37:55.345126432 +0000
@@ -1,5 +1,10 @@
 /*
  * Code for the vsyscall page.  This version uses the sysenter instruction.
+ *
+ * NOTE:
+ * 1) __kernel_vsyscall _must_ be first in this page.
+ * 2) there are alignment constraints on this stub, see vsyscall-sigreturn.S
+ *    for details.
  */
 
 	.text
@@ -7,6 +12,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 08:47:16.000000000 +0000
+++ source/arch/i386/kernel/vsyscall.lds	2004-03-16 09:37:55.345126432 +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 08:47:16.000000000 +0000
+++ source/arch/i386/lib/Makefile	2004-03-16 09:37:55.345126432 +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 08:47:16.000000000 +0000
+++ source/arch/i386/lib/checksum.S	2004-03-16 09:37:55.346126280 +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 08:47:16.000000000 +0000
+++ source/arch/i386/lib/dec_and_lock.c	2004-03-16 09:37:55.346126280 +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 08:47:16.000000000 +0000
+++ source/arch/i386/lib/getuser.S	2004-03-16 09:37:55.347126128 +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-16 09:37:55.348125976 +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-16 09:37:55.348125976 +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 09:07:28.000000000 +0000
+++ source/arch/i386/mach-es7000/Makefile	2004-03-16 09:37:55.348125976 +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 10:49:54.000000000 +0000
+++ source/arch/i386/mach-pc9800/Makefile	2004-03-16 09:37:55.349125824 +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-16 09:37:55.349125824 +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/mach-voyager/voyager_smp.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/i386/mach-voyager/voyager_smp.c	2004-03-16 09:37:55.350125672 +0000
@@ -623,7 +623,9 @@ do_boot_cpu(__u8 cpu)
 		((virt_to_phys(page_table_copies)) & PAGE_MASK)
 		| _PAGE_RW | _PAGE_USER | _PAGE_PRESENT;
 #else
-	((unsigned long *)swapper_pg_dir)[0] = 0x102007;
+	((unsigned long *)swapper_pg_dir)[0] = 
+		(virt_to_phys(pg0) & PAGE_MASK)
+		| _PAGE_RW | _PAGE_USER | _PAGE_PRESENT;
 #endif
 
 	if(quad_boot) {
--- diff/arch/i386/math-emu/fpu_system.h	2003-10-09 08:47:16.000000000 +0000
+++ source/arch/i386/math-emu/fpu_system.h	2004-03-16 09:37:55.351125520 +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 14:46:11.000000000 +0000
+++ source/arch/i386/mm/discontig.c	2004-03-16 09:37:55.351125520 +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/fault.c	2003-12-19 09:51:11.000000000 +0000
+++ source/arch/i386/mm/fault.c	2004-03-16 09:37:55.352125368 +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-16 09:37:55.353125216 +0000
@@ -29,7 +29,7 @@ static spinlock_t htlbpage_lock = SPIN_L
 
 static void enqueue_huge_page(struct page *page)
 {
-	list_add(&page->list,
+	list_add(&page->lru,
 		&hugepage_freelists[page_zone(page)->zone_pgdat->node_id]);
 }
 
@@ -44,8 +44,8 @@ static struct page *dequeue_huge_page(vo
 				break;
 	}
 	if (nid >= 0 && nid < MAX_NUMNODES && !list_empty(&hugepage_freelists[nid])) {
-		page = list_entry(hugepage_freelists[nid].next, struct page, list);
-		list_del(&page->list);
+		page = list_entry(hugepage_freelists[nid].next, struct page, lru);
+		list_del(&page->lru);
 	}
 	return page;
 }
@@ -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;
@@ -278,9 +299,8 @@ follow_huge_pmd(struct mm_struct *mm, un
 static void free_huge_page(struct page *page)
 {
 	BUG_ON(page_count(page));
-	BUG_ON(page->mapping);
 
-	INIT_LIST_HEAD(&page->list);
+	INIT_LIST_HEAD(&page->lru);
 
 	spin_lock(&htlbpage_lock);
 	enqueue_huge_page(page);
@@ -314,8 +334,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);
 }
 
@@ -409,19 +429,19 @@ static int try_to_free_low(int count)
 	/* all lowmem is on node 0 */
 	list_for_each(p, &hugepage_freelists[0]) {
 		if (map) {
-			list_del(&map->list);
+			list_del(&map->lru);
 			update_and_free_page(map);
 			htlbpagemem--;
 			map = NULL;
 			if (++count == 0)
 				break;
 		}
-		page = list_entry(p, struct page, list);
+		page = list_entry(p, struct page, lru);
 		if (!PageHighMem(page))
 			map = page;
 	}
 	if (map) {
-		list_del(&map->list);
+		list_del(&map->lru);
 		update_and_free_page(map);
 		htlbpagemem--;
 		count++;
--- diff/arch/i386/mm/init.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/i386/mm/init.c	2004-03-16 09:37:55.354125064 +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;
+
+	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_base = swapper_pg_dir;
+	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,38 +506,43 @@ 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)
 {
 	if (PTRS_PER_PMD > 1) {
 		pmd_cache = kmem_cache_create("pmd",
-					PTRS_PER_PMD*sizeof(pmd_t),
-					0,
-					SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN,
-					pmd_ctor,
-					NULL);
+				PTRS_PER_PMD*sizeof(pmd_t),
+				PTRS_PER_PMD*sizeof(pmd_t),
+				0,
+				pmd_ctor,
+				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),
+				PTRS_PER_PMD*sizeof(pmd_t),
+				0,
+				kpmd_ctor,
+				NULL);
+			if (!kpmd_cache)
+				panic("pgtable_cache_init(): "
+						"cannot create kpmd cache");
+		}
 	}
+
 	pgd_cache = kmem_cache_create("pgd",
 				PTRS_PER_PGD*sizeof(pgd_t),
+				PTRS_PER_PGD*sizeof(pgd_t),
 				0,
-				SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN,
-				pgd_ctor,
-				PTRS_PER_PMD == 1 ? pgd_dtor : NULL);
+				NULL, NULL);
 	if (!pgd_cache)
 		panic("pgtable_cache_init(): Cannot create pgd cache");
 }
--- diff/arch/i386/mm/pageattr.c	2003-08-20 13:16:24.000000000 +0000
+++ source/arch/i386/mm/pageattr.c	2004-03-16 09:37:55.355124912 +0000
@@ -67,22 +67,19 @@ static void flush_kernel_map(void *dummy
 
 static void set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte) 
 { 
-	struct page *page;
-	unsigned long flags;
-
 	set_pte_atomic(kpte, pte); 	/* change init_mm */
-	if (PTRS_PER_PMD > 1)
-		return;
-
-	spin_lock_irqsave(&pgd_lock, flags);
-	list_for_each_entry(page, &pgd_list, lru) {
-		pgd_t *pgd;
-		pmd_t *pmd;
-		pgd = (pgd_t *)page_address(page) + pgd_index(address);
-		pmd = pmd_offset(pgd, address);
-		set_pte_atomic((pte_t *)pmd, pte);
+#ifndef CONFIG_X86_PAE
+	{
+		struct list_head *l;
+		spin_lock(&mmlist_lock);
+		list_for_each(l, &init_mm.mmlist) {
+			struct mm_struct *mm = list_entry(l, struct mm_struct, mmlist);
+			pmd_t *pmd = pmd_offset(pgd_offset(mm, address), address);
+			set_pte_atomic((pte_t *)pmd, pte);
+		}
+		spin_unlock(&mmlist_lock);
 	}
-	spin_unlock_irqrestore(&pgd_lock, flags);
+#endif
 }
 
 /* 
@@ -135,7 +132,7 @@ __change_page_attr(struct page *page, pg
 	}
 
 	if (cpu_has_pse && (atomic_read(&kpte_page->count) == 1)) { 
-		list_add(&kpte_page->list, &df_list);
+		list_add(&kpte_page->lru, &df_list);
 		revert_page(kpte_page, address);
 	} 
 	return 0;
@@ -188,7 +185,7 @@ void global_flush_tlb(void)
 	flush_map();
 	n = l.next;
 	while (n != &l) {
-		struct page *pg = list_entry(n, struct page, list);
+		struct page *pg = list_entry(n, struct page, lru);
 		n = n->next;
 		__free_page(pg);
 	}
--- diff/arch/i386/mm/pgtable.c	2003-10-09 08:47:16.000000000 +0000
+++ source/arch/i386/mm/pgtable.c	2004-03-16 09:37:55.355124912 +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,50 +158,50 @@ 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
- * 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.
- * If the locking proves to be non-performant, a ticketing scheme with
- * checks at dup_mmap(), exec(), and other mmlist addition points
- * could be used. The locking scheme was chosen on the basis of
- * manfred's recommendations and having no core impact whatsoever.
+ * 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 4:4.
+ * (d) TASK_SIZE <= PAGE_OFFSET means non-4:4.
+ *
+ * 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
  */
-spinlock_t pgd_lock = SPIN_LOCK_UNLOCKED;
-LIST_HEAD(pgd_list);
-
-void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused)
+void pgd_ctor(void *__pgd, kmem_cache_t *cache, unsigned long unused)
 {
-	unsigned long flags;
+	pgd_t *pgd = (pgd_t *)__pgd;
 
-	if (PTRS_PER_PMD == 1)
-		spin_lock_irqsave(&pgd_lock, flags);
+	if ((PTRS_PER_PMD == 1) && (TASK_SIZE > PAGE_OFFSET))
+		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,
+	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));
-}
-
-/* never called when PTRS_PER_PMD > 1 */
-void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused)
-{
-	unsigned long flags; /* can be called from interrupt context */
-
-	spin_lock_irqsave(&pgd_lock, flags);
-	list_del(&virt_to_page(pgd)->lru);
-	spin_unlock_irqrestore(&pgd_lock, flags);
+	if (TASK_SIZE > PAGE_OFFSET)
+		memset(pgd, 0, (PTRS_PER_PGD - NR_SHARED_PMDS)*sizeof(pgd_t));
+	else
+		memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
 }
 
 pgd_t *pgd_alloc(struct mm_struct *mm)
@@ -208,18 +209,39 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
 	int i;
 	pgd_t *pgd = kmem_cache_alloc(pgd_cache, GFP_KERNEL);
 
+	if (pgd)
+		pgd_ctor(pgd, NULL, 0);
+
 	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 +252,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 09:00:51.000000000 +0000
+++ source/arch/i386/oprofile/op_model_p4.c	2004-03-16 09:37:55.356124760 +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/ia64/Kconfig	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/ia64/Kconfig	2004-03-16 09:37:55.357124608 +0000
@@ -416,93 +416,14 @@ source "drivers/pci/hotplug/Kconfig"
 
 source "drivers/pcmcia/Kconfig"
 
-source "drivers/parport/Kconfig"
-
 endif
 
 endmenu
 
-source "drivers/base/Kconfig"
-
-if !IA64_HP_SIM
-
-source "drivers/mtd/Kconfig"
-
-source "drivers/pnp/Kconfig"
-
-source "drivers/block/Kconfig"
-
-source "drivers/ide/Kconfig"
-
-source "drivers/ieee1394/Kconfig"
-
-source "drivers/message/i2o/Kconfig"
-
-source "drivers/md/Kconfig"
-
-source "drivers/message/fusion/Kconfig"
-
-endif
-
-
-source "drivers/scsi/Kconfig"
-
-source "net/Kconfig"
-
-
-if !IA64_HP_SIM
-
-source "drivers/isdn/Kconfig"
-
-source "drivers/cdrom/Kconfig"
-
-#
-# input before char - char/joystick depends on it. As does USB.
-#
-source "drivers/input/Kconfig"
-
-source "drivers/char/Kconfig"
-
-source "drivers/i2c/Kconfig"
-
-#source drivers/misc/Config.in
-source "drivers/media/Kconfig"
-
-endif
-
-
-menu "Block devices"
-	depends on IA64_HP_SIM
-
-config BLK_DEV_LOOP
-	tristate "Loopback device support"
-
-config BLK_DEV_NBD
-	tristate "Network block device support"
-	depends on NET
-
-config BLK_DEV_RAM
-	tristate "RAM disk support"
-
-config BLK_DEV_RAM_SIZE
-	int "Default RAM disk size"
-	depends on BLK_DEV_RAM
-	default "4096"
-
-endmenu
+source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
-if !IA64_HP_SIM
-
-source "drivers/video/Kconfig"
-
-source "sound/Kconfig"
-
-source "drivers/usb/Kconfig"
-
-endif
-
 source "lib/Kconfig"
 
 source "arch/ia64/hp/sim/Kconfig"
@@ -616,7 +537,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/hp/common/sba_iommu.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ia64/hp/common/sba_iommu.c	2004-03-16 09:37:55.358124456 +0000
@@ -1479,7 +1479,6 @@ ioc_iova_init(struct ioc *ioc)
 #ifdef FULL_VALID_PDIR
 	unsigned long index;
 #endif
-	unsigned int i;
 
 	/*
 	** Firmware programs the base and size of a "safe IOVA space"
@@ -1574,18 +1573,6 @@ ioc_iova_init(struct ioc *ioc)
 	/* Enable IOVA translation */
 	WRITE_REG(ioc->ibase | 1, ioc->ioc_hpa + IOC_IBASE);
 	READ_REG(ioc->ioc_hpa + IOC_IBASE);
-
-	/* Clear ROPE(N)_CONFIG AO bit.
-	** Disables "NT Ordering" (~= !"Relaxed Ordering")
-	** Overrides bit 1 in DMA Hint Sets.
-	** Improves netperf UDP_STREAM by ~10% for tg3 on bcm5701.
-	*/
-	for (i=0; i<(8*8); i+=8) {
-		unsigned long rope_config;
-		rope_config = READ_REG(ioc->ioc_hpa + IOC_ROPE0_CFG + i);
-		rope_config &= ~IOC_ROPE_AO;
-		WRITE_REG(rope_config, ioc->ioc_hpa + IOC_ROPE0_CFG + i);
-	}
 }
 
 static void __init
@@ -1659,26 +1646,25 @@ ioc_sac_init(struct ioc *ioc)
 static void __init
 ioc_zx1_init(struct ioc *ioc)
 {
+	unsigned long rope_config;
+	unsigned int i;
+
 	if (ioc->rev < 0x20)
 		panic(PFX "IOC 2.0 or later required for IOMMU support\n");
 
-	ioc->dma_mask = 0xFFFFFFFFFFUL;
+	/* 38 bit memory controller + extra bit for range displaced by MMIO */
+	ioc->dma_mask = (0x1UL << 39) - 1;
 
-	if (!iovp_shift) {
-		/* 64k is max iommu page size */
-		iovp_shift = min(PAGE_SHIFT, 16);
-		iovp_size = (1 << iovp_shift);
-		iovp_mask = ~(iovp_size - 1);
-	}
-}
-
-static void __init
-ioc_sx1000_init(struct ioc *ioc)
-{
-	if (!iovp_shift) {
-		iovp_shift = 12;	/* 4K for now */
-		iovp_size = (1 << iovp_shift);
-		iovp_mask = ~(iovp_size - 1);
+	/*
+	** Clear ROPE(N)_CONFIG AO bit.
+	** Disables "NT Ordering" (~= !"Relaxed Ordering")
+	** Overrides bit 1 in DMA Hint Sets.
+	** Improves netperf UDP_STREAM by ~10% for tg3 on bcm5701.
+	*/
+	for (i=0; i<(8*8); i+=8) {
+		rope_config = READ_REG(ioc->ioc_hpa + IOC_ROPE0_CFG + i);
+		rope_config &= ~IOC_ROPE_AO;
+		WRITE_REG(rope_config, ioc->ioc_hpa + IOC_ROPE0_CFG + i);
 	}
 }
 
@@ -1692,8 +1678,6 @@ struct ioc_iommu {
 
 static struct ioc_iommu ioc_iommu_info[] __initdata = {
 	{ ZX1_IOC_ID, "zx1", ioc_zx1_init },
-	{ REO_IOC_ID, "REO", ioc_sx1000_init },
-	{ SX1000_IOC_ID, "sx1000", ioc_sx1000_init },
 };
 
 static struct ioc * __init
@@ -1718,11 +1702,6 @@ ioc_init(u64 hpa, void *handle)
 	ioc->rev = READ_REG(ioc->ioc_hpa + IOC_FCLASS) & 0xFFUL;
 	ioc->dma_mask = 0xFFFFFFFFFFFFFFFFUL;	/* conservative */
 
-	if (iovp_shift) {
-		iovp_size = (1 << iovp_shift);
-		iovp_mask = ~(iovp_size - 1);
-	}
-
 	for (info = ioc_iommu_info; info < ioc_iommu_info + ARRAY_SIZE(ioc_iommu_info); info++) {
 		if (ioc->func_id == info->func_id) {
 			ioc->name = info->name;
@@ -1730,6 +1709,10 @@ ioc_init(u64 hpa, void *handle)
 				(info->init)(ioc);
 		}
 	}
+
+	iovp_size = (1 << iovp_shift);
+	iovp_mask = ~(iovp_size - 1);
+
 	DBG_INIT("%s: PAGE_SIZE %ldK, iovp_size %ldK\n", __FUNCTION__,
 		PAGE_SIZE >> 10, iovp_size >> 10);
 
@@ -1929,10 +1912,21 @@ acpi_sba_ioc_add(struct acpi_device *dev
 	 * For HWP0001, only SBA appears in ACPI namespace.  It encloses the PCI
 	 * root bridges, and its CSR space includes the IOC function.
 	 */
-	if (strncmp("HWP0001", dev_info->hardware_id.value, 7) == 0)
+	if (strncmp("HWP0001", dev_info->hardware_id.value, 7) == 0) {
 		hpa += ZX1_IOC_OFFSET;
+		/* zx1 based systems default to kernel page size iommu pages */
+		if (!iovp_shift)
+			iovp_shift = min(PAGE_SHIFT, 16);
+	}
 	ACPI_MEM_FREE(dev_info);
 
+	/*
+	 * default anything not caught above or specified on cmdline to 4k
+	 * iommu page size
+	 */
+	if (!iovp_shift)
+		iovp_shift = 12;
+
 	ioc = ioc_init(hpa, device->handle);
 	if (!ioc)
 		return 1;
--- diff/arch/ia64/hp/sim/simserial.c	2003-06-30 09:07:32.000000000 +0000
+++ source/arch/ia64/hp/sim/simserial.c	2004-03-16 09:37:55.359124304 +0000
@@ -636,7 +636,6 @@ static void rs_close(struct tty_struct *
 #ifdef SIMSERIAL_DEBUG
 		printk("rs_close: hung_up\n");
 #endif
-		MOD_DEC_USE_COUNT;
 		local_irq_restore(flags);
 		return;
 	}
@@ -661,7 +660,6 @@ static void rs_close(struct tty_struct *
 		state->count = 0;
 	}
 	if (state->count) {
-		MOD_DEC_USE_COUNT;
 		local_irq_restore(flags);
 		return;
 	}
@@ -686,7 +684,6 @@ static void rs_close(struct tty_struct *
 	}
 	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
-	MOD_DEC_USE_COUNT;
 }
 
 /*
@@ -874,17 +871,12 @@ static int rs_open(struct tty_struct *tt
 	int			retval, line;
 	unsigned long		page;
 
-	MOD_INC_USE_COUNT;
 	line = tty->index;
-	if ((line < 0) || (line >= NR_PORTS)) {
-		MOD_DEC_USE_COUNT;
+	if ((line < 0) || (line >= NR_PORTS))
 		return -ENODEV;
-	}
 	retval = get_async_struct(line, &info);
-	if (retval) {
-		MOD_DEC_USE_COUNT;
+	if (retval)
 		return retval;
-	}
 	tty->driver_data = info;
 	info->tty = tty;
 
@@ -895,10 +887,8 @@ static int rs_open(struct tty_struct *tt
 
 	if (!tmp_buf) {
 		page = get_zeroed_page(GFP_KERNEL);
-		if (!page) {
-			/* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
+		if (!page)
 			return -ENOMEM;
-		}
 		if (tmp_buf)
 			free_page(page);
 		else
@@ -912,7 +902,6 @@ static int rs_open(struct tty_struct *tt
 	    (info->flags & ASYNC_CLOSING)) {
 		if (info->flags & ASYNC_CLOSING)
 			interruptible_sleep_on(&info->close_wait);
-		/* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
 #ifdef SERIAL_DO_RESTART
 		return ((info->flags & ASYNC_HUP_NOTIFY) ?
 			-EAGAIN : -ERESTARTSYS);
@@ -926,7 +915,6 @@ static int rs_open(struct tty_struct *tt
 	 */
 	retval = startup(info);
 	if (retval) {
-		/* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
 		return retval;
 	}
 
@@ -1042,6 +1030,7 @@ simrs_init (void)
 
 	/* Initialize the tty_driver structure */
 
+	hp_simserial_driver->owner = THIS_MODULE;
 	hp_simserial_driver->driver_name = "simserial";
 	hp_simserial_driver->name = "ttyS";
 	hp_simserial_driver->major = TTY_MAJOR;
--- diff/arch/ia64/ia32/ia32_entry.S	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/ia64/ia32/ia32_entry.S	2004-03-16 09:37:55.360124152 +0000
@@ -465,7 +465,7 @@ ia32_syscall_table:
 	data8 sys_epoll_create
 	data8 sys32_epoll_ctl	/* 255 */
 	data8 sys32_epoll_wait
-	data8 sys_remap_file_pages
+	data8 old_remap_file_pages
 	data8 sys_set_tid_address
  	data8 sys32_timer_create
  	data8 compat_timer_settime	/* 260 */
@@ -484,5 +484,12 @@ ia32_syscall_table:
  	data8 sys_ni_syscall
   	data8 sys_ni_syscall
 
+  	data8 sys_ni_syscall		/* 275 */
+  	data8 sys_ni_syscall
+  	data8 sys_ni_syscall
+  	data8 sys_ni_syscall
+  	data8 sys_ni_syscall
+  	data8 sys_remap_file_pages	/* 280 */
+
 	// guard against failures to increase IA32_NR_syscalls
 	.org ia32_syscall_table + 8*IA32_NR_syscalls
--- diff/arch/ia64/ia32/ia32_support.c	2003-10-27 09:20:43.000000000 +0000
+++ source/arch/ia64/ia32/ia32_support.c	2004-03-16 09:37:55.360124152 +0000
@@ -134,8 +134,6 @@ ia32_load_state (struct task_struct *t)
 	regs->r17 = (_TSS << 48) | (_LDT << 32) | (__u32) regs->r17;
 	regs->r30 = load_desc(_LDT);				/* LDTD */
 	load_TLS(&t->thread, smp_processor_id());
-
-	put_cpu();
 }
 
 /*
--- diff/arch/ia64/ia32/sys_ia32.c	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/ia64/ia32/sys_ia32.c	2004-03-16 09:37:55.366123240 +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/kernel/entry.S	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/ia64/kernel/entry.S	2004-03-16 09:37:55.368122936 +0000
@@ -1367,7 +1367,7 @@ sys_call_table:
 	data8 sys_ni_syscall					/* was: ia64_oldfstat */
 	data8 sys_vhangup
 	data8 sys_lchown
-	data8 sys_remap_file_pages		// 1125
+	data8 old_remap_file_pages		// 1125
 	data8 sys_wait4
 	data8 sys_sysinfo
 	data8 sys_clone
@@ -1501,7 +1501,7 @@ sys_call_table:
 	data8 sys_clock_nanosleep
 	data8 sys_fstatfs64
 	data8 sys_statfs64
-	data8 sys_ni_syscall
+	data8 sys_remap_file_pages
 	data8 sys_ni_syscall			// 1260
 	data8 sys_ni_syscall
 	data8 sys_ni_syscall
--- diff/arch/ia64/kernel/head.S	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/ia64/kernel/head.S	2004-03-16 09:37:55.369122784 +0000
@@ -816,7 +816,7 @@ GLOBAL_ENTRY(ia64_delay_loop)
 	br.ret.sptk.many rp
 END(ia64_delay_loop)
 
-GLOBAL_ENTRY(ia64_invoke_kernel_thread_helper)
+GLOBAL_ENTRY(start_kernel_thread)
 	.prologue
 	.save rp, r0				// this is the end of the call-chain
 	.body
@@ -827,7 +827,7 @@ GLOBAL_ENTRY(ia64_invoke_kernel_thread_h
 	mov out0 = r8
 	br.call.sptk.many rp = sys_exit;;
 1:	br.sptk.few 1b				// not reached
-END(ia64_invoke_kernel_thread_helper)
+END(start_kernel_thread)
 
 #ifdef CONFIG_IA64_BRL_EMU
 
--- diff/arch/ia64/kernel/iosapic.c	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/ia64/kernel/iosapic.c	2004-03-16 09:37:55.376121720 +0000
@@ -170,7 +170,7 @@ gsi_to_irq (unsigned int gsi)
 }
 
 static void
-set_rte (unsigned int vector, unsigned int dest)
+set_rte (unsigned int vector, unsigned int dest, int mask)
 {
 	unsigned long pol, trigger, dmode;
 	u32 low32, high32;
@@ -205,6 +205,7 @@ set_rte (unsigned int vector, unsigned i
 	low32 = ((pol << IOSAPIC_POLARITY_SHIFT) |
 		 (trigger << IOSAPIC_TRIGGER_SHIFT) |
 		 (dmode << IOSAPIC_DELIVERY_SHIFT) |
+		 ((mask ? 1 : 0) << IOSAPIC_MASK_SHIFT) |
 		 vector);
 
 	/* dest contains both id and eid */
@@ -509,7 +510,7 @@ iosapic_register_intr (unsigned int gsi,
 	       (trigger == IOSAPIC_EDGE ? "edge" : "level"), dest, vector);
 
 	/* program the IOSAPIC routing table */
-	set_rte(vector, dest);
+	set_rte(vector, dest, 0);
 	return vector;
 }
 
@@ -557,7 +558,7 @@ iosapic_register_platform_intr (u32 int_
 	       (trigger == IOSAPIC_EDGE ? "edge" : "level"), dest, vector);
 
 	/* program the IOSAPIC routing table */
-	set_rte(vector, dest);
+	set_rte(vector, dest, 0);
 	return vector;
 }
 
@@ -583,7 +584,7 @@ iosapic_override_isa_irq (unsigned int i
 	    trigger == IOSAPIC_EDGE ? "edge" : "level", dest, vector);
 
 	/* program the IOSAPIC routing table */
-	set_rte(vector, dest);
+	set_rte(vector, dest, 0);
 }
 
 void __init
@@ -669,7 +670,7 @@ iosapic_enable_intr (unsigned int vector
 	/* direct the interrupt vector to the running cpu id */
 	dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
 #endif
-	set_rte(vector, dest);
+	set_rte(vector, dest, 1);
 
 	printk(KERN_INFO "IOSAPIC: vector %d -> CPU 0x%04x, enabled\n",
 	       vector, dest);
--- diff/arch/ia64/kernel/irq_ia64.c	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/ia64/kernel/irq_ia64.c	2004-03-16 09:37:55.376121720 +0000
@@ -57,6 +57,21 @@ __u8 isa_irq_to_vector_map[16] = {
 };
 EXPORT_SYMBOL(isa_irq_to_vector_map);
 
+static inline void
+irq_enter (void)
+{
+	preempt_count() += HARDIRQ_OFFSET;
+}
+
+static inline void
+irq_exit (void)
+{
+	preempt_count() -= IRQ_EXIT_OFFSET;
+	if (!in_interrupt() && local_softirq_pending())
+		do_softirq();
+	preempt_enable_no_resched();
+}
+
 int
 ia64_alloc_vector (void)
 {
--- diff/arch/ia64/kernel/mca.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ia64/kernel/mca.c	2004-03-16 09:37:55.377121568 +0000
@@ -103,8 +103,6 @@ extern void			ia64_slave_init_handler (v
 
 static ia64_mc_info_t		ia64_mc_info;
 
-extern struct hw_interrupt_type	irq_type_iosapic_level;
-
 struct ia64_mca_tlb_info ia64_mca_tlb_list[NR_CPUS];
 
 #define MAX_CPE_POLL_INTERVAL (15*60*HZ) /* 15 minutes */
@@ -1253,7 +1251,6 @@ ia64_mca_init(void)
 				if (irq_to_vector(irq) == cpev) {
 					desc = irq_descp(irq);
 					desc->status |= IRQ_PER_CPU;
-					desc->handler = &irq_type_iosapic_level;
 					setup_irq(irq, &mca_cpe_irqaction);
 				}
 			ia64_mca_register_cpev(cpev);
--- diff/arch/ia64/kernel/process.c	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/ia64/kernel/process.c	2004-03-16 09:37:55.378121416 +0000
@@ -574,8 +574,8 @@ ia64_set_personality (struct elf64_hdr *
 pid_t
 kernel_thread (int (*fn)(void *), void *arg, unsigned long flags)
 {
-	extern void ia64_invoke_kernel_thread_helper (void);
-	unsigned long *helper_fptr = (unsigned long *) &ia64_invoke_kernel_thread_helper;
+	extern void start_kernel_thread (void);
+	unsigned long *helper_fptr = (unsigned long *) &start_kernel_thread;
 	struct {
 		struct switch_stack sw;
 		struct pt_regs pt;
--- diff/arch/ia64/kernel/sal.c	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/ia64/kernel/sal.c	2004-03-16 09:37:55.379121264 +0000
@@ -10,7 +10,6 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/smp.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
 
@@ -21,6 +20,12 @@
 spinlock_t sal_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED;
 unsigned long sal_platform_features;
 
+unsigned short sal_revision;
+unsigned short sal_version;
+
+#define SAL_MAJOR(x) ((x) >> 8)
+#define SAL_MINOR(x) ((x) & 0xff)
+
 static struct {
 	void *addr;	/* function entry point */
 	void *gpval;	/* gp value to use */
@@ -86,13 +91,98 @@ ia64_sal_handler_init (void *entry_point
 	ia64_sal = (ia64_sal_handler) &pdesc;
 }
 
+static void __init
+check_versions (struct ia64_sal_systab *systab)
+{
+	sal_revision = (systab->sal_rev_major << 8) | systab->sal_rev_minor;
+	sal_version = (systab->sal_b_rev_major << 8) | systab->sal_b_rev_minor;
+
+	/* Check for broken firmware */
+	if ((sal_revision == SAL_VERSION_CODE(49, 29))
+	    && (sal_version == SAL_VERSION_CODE(49, 29)))
+	{
+		/*
+		 * Old firmware for zx2000 prototypes have this weird version number,
+		 * reset it to something sane.
+		 */
+		sal_revision = SAL_VERSION_CODE(2, 8);
+		sal_version = SAL_VERSION_CODE(0, 0);
+	}
+}
+
+static void __init
+sal_desc_entry_point (void *p)
+{
+	struct ia64_sal_desc_entry_point *ep = p;
+	ia64_pal_handler_init(__va(ep->pal_proc));
+	ia64_sal_handler_init(__va(ep->sal_proc), __va(ep->gp));
+}
+
+#ifdef CONFIG_SMP
+static void __init
+set_smp_redirect (int flag)
+{
+	if (no_int_routing)
+		smp_int_redirect &= ~flag;
+	else
+		smp_int_redirect |= flag;
+}
+#else
+#define set_smp_redirect(flag)	do { } while (0)
+#endif
+
+static void __init
+sal_desc_platform_feature (void *p)
+{
+	struct ia64_sal_desc_platform_feature *pf = p;
+	sal_platform_features = pf->feature_mask;
+
+	printk(KERN_INFO "SAL Platform features:");
+	if (!sal_platform_features) {
+		printk(" None\n");
+		return;
+	}
+
+	if (sal_platform_features & IA64_SAL_PLATFORM_FEATURE_BUS_LOCK)
+		printk(" BusLock");
+	if (sal_platform_features & IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT) {
+		printk(" IRQ_Redirection");
+		set_smp_redirect(SMP_IRQ_REDIRECTION);
+	}
+	if (sal_platform_features & IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT) {
+		printk(" IPI_Redirection");
+		set_smp_redirect(SMP_IPI_REDIRECTION);
+	}
+	if (sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)
+		printk(" ITC_Drift");
+	printk("\n");
+}
+
+#ifdef CONFIG_SMP
+static void __init
+sal_desc_ap_wakeup (void *p)
+{
+	struct ia64_sal_desc_ap_wakeup *ap = p;
+
+	switch (ap->mechanism) {
+	case IA64_SAL_AP_EXTERNAL_INT:
+		ap_wakeup_vector = ap->vector;
+		printk(KERN_INFO "SAL: AP wakeup using external interrupt "
+				"vector 0x%lx\n", ap_wakeup_vector);
+		break;
+	default:
+		printk(KERN_ERR "SAL: AP wakeup mechanism unsupported!\n");
+		break;
+	}
+}
+#else
+static void __init sal_desc_ap_wakeup(void *p) { }
+#endif
 
 void __init
 ia64_sal_init (struct ia64_sal_systab *systab)
 {
-	unsigned long min, max;
 	char *p;
-	struct ia64_sal_desc_entry_point *ep;
 	int i;
 
 	if (!systab) {
@@ -103,85 +193,34 @@ ia64_sal_init (struct ia64_sal_systab *s
 	if (strncmp(systab->signature, "SST_", 4) != 0)
 		printk(KERN_ERR "bad signature in system table!");
 
-	/*
-	 * revisions are coded in BCD, so %x does the job for us
-	 */
-	printk(KERN_INFO "SAL v%x.%x: oem=%.32s, product=%.32s\n",
-	       systab->sal_rev_major, systab->sal_rev_minor,
-	       systab->oem_id, systab->product_id);
+	check_versions(systab);
 
-	min = ~0UL;
-	max = 0;
+	/* revisions are coded in BCD, so %x does the job for us */
+	printk(KERN_INFO "SAL %x.%x: %.32s %.32s%sversion %x.%x\n",
+			SAL_MAJOR(sal_revision), SAL_MINOR(sal_revision),
+			systab->oem_id, systab->product_id,
+			systab->product_id[0] ? " " : "",
+			SAL_MAJOR(sal_version), SAL_MINOR(sal_version));
 
 	p = (char *) (systab + 1);
 	for (i = 0; i < systab->entry_count; i++) {
 		/*
-		 * The first byte of each entry type contains the type descriptor.
+		 * The first byte of each entry type contains the type
+		 * descriptor.
 		 */
 		switch (*p) {
-		      case SAL_DESC_ENTRY_POINT:
-			ep = (struct ia64_sal_desc_entry_point *) p;
-			printk(KERN_INFO "SAL: entry: pal_proc=0x%lx, sal_proc=0x%lx\n",
-			       ep->pal_proc, ep->sal_proc);
-			ia64_pal_handler_init(__va(ep->pal_proc));
-			ia64_sal_handler_init(__va(ep->sal_proc), __va(ep->gp));
+		case SAL_DESC_ENTRY_POINT:
+			sal_desc_entry_point(p);
 			break;
-
-		      case SAL_DESC_PTC:
+		case SAL_DESC_PLATFORM_FEATURE:
+			sal_desc_platform_feature(p);
+			break;
+		case SAL_DESC_PTC:
 			ia64_ptc_domain_info = (ia64_sal_desc_ptc_t *)p;
 			break;
-
-		      case SAL_DESC_AP_WAKEUP:
-#ifdef CONFIG_SMP
-		      {
-			      struct ia64_sal_desc_ap_wakeup *ap = (void *) p;
-
-			      switch (ap->mechanism) {
-				    case IA64_SAL_AP_EXTERNAL_INT:
-				      ap_wakeup_vector = ap->vector;
-				      printk(KERN_INFO "SAL: AP wakeup using external interrupt "
-					     "vector 0x%lx\n", ap_wakeup_vector);
-				      break;
-
-				    default:
-				      printk(KERN_ERR "SAL: AP wakeup mechanism unsupported!\n");
-				      break;
-			      }
-			      break;
-		      }
-#endif
-		      case SAL_DESC_PLATFORM_FEATURE:
-		      {
-			      struct ia64_sal_desc_platform_feature *pf = (void *) p;
-			      sal_platform_features = pf->feature_mask;
-			      printk(KERN_INFO "SAL: Platform features ");
-
-			      if (pf->feature_mask & IA64_SAL_PLATFORM_FEATURE_BUS_LOCK)
-				      printk("BusLock ");
-			      if (pf->feature_mask & IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT) {
-				      printk("IRQ_Redirection ");
-#ifdef CONFIG_SMP
-				      if (no_int_routing)
-					      smp_int_redirect &= ~SMP_IRQ_REDIRECTION;
-				      else
-					      smp_int_redirect |= SMP_IRQ_REDIRECTION;
-#endif
-			      }
-			      if (pf->feature_mask & IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT) {
-				      printk("IPI_Redirection ");
-#ifdef CONFIG_SMP
-				      if (no_int_routing)
-					      smp_int_redirect &= ~SMP_IPI_REDIRECTION;
-				      else
-					      smp_int_redirect |= SMP_IPI_REDIRECTION;
-#endif
-			      }
-			      if (pf->feature_mask & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)
-				      printk("ITC_Drift ");
-			      printk("\n");
-			      break;
- 		      }
-
+		case SAL_DESC_AP_WAKEUP:
+			sal_desc_ap_wakeup(p);
+			break;
 		}
 		p += SAL_DESC_SIZE(*p);
 	}
--- diff/arch/ia64/kernel/unaligned.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ia64/kernel/unaligned.c	2004-03-16 09:37:55.380121112 +0000
@@ -1337,7 +1337,7 @@ ia64_handle_unaligned (unsigned long ifa
 			 * be holding locks...
 			 */
 			if (user_mode(regs))
-				tty_write_message(current->tty, buf);
+				tty_write_message(current->signal->tty, buf);
 			buf[len-1] = '\0';	/* drop '\r' */
 			printk(KERN_WARNING "%s", buf);	/* watch for command names containing %s */
 		}
--- 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-16 09:37:55.380121112 +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 13:18:17.000000000 +0000
+++ source/arch/ia64/lib/swiotlb.c	2004-03-16 09:37:55.381120960 +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/mm/hugetlbpage.c	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/ia64/mm/hugetlbpage.c	2004-03-16 09:37:55.382120808 +0000
@@ -32,7 +32,7 @@ static spinlock_t htlbpage_lock = SPIN_L
 
 static void enqueue_huge_page(struct page *page)
 {
-	list_add(&page->list,
+	list_add(&page->lru,
 		&hugepage_freelists[page_zone(page)->zone_pgdat->node_id]);
 }
 
@@ -48,8 +48,8 @@ static struct page *dequeue_huge_page(vo
 	}
 	if (nid >= 0 && nid < MAX_NUMNODES &&
 	    !list_empty(&hugepage_freelists[nid])) {
-		page = list_entry(hugepage_freelists[nid].next, struct page, list);
-		list_del(&page->list);
+		page = list_entry(hugepage_freelists[nid].next, struct page, lru);
+		list_del(&page->lru);
 	}
 	return page;
 }
@@ -246,9 +246,8 @@ follow_huge_pmd(struct mm_struct *mm, un
 void free_huge_page(struct page *page)
 {
 	BUG_ON(page_count(page));
-	BUG_ON(page->mapping);
 
-	INIT_LIST_HEAD(&page->list);
+	INIT_LIST_HEAD(&page->lru);
 
 	spin_lock(&htlbpage_lock);
 	enqueue_huge_page(page);
@@ -449,19 +448,19 @@ int try_to_free_low(int count)
 	spin_lock(&htlbpage_lock);
 	list_for_each(p, &hugepage_freelists[0]) {
 		if (map) {
-			list_del(&map->list);
+			list_del(&map->lru);
 			update_and_free_page(map);
 			htlbpagemem--;
 			map = NULL;
 			if (++count == 0)
 				break;
 		}
-		page = list_entry(p, struct page, list);
+		page = list_entry(p, struct page, lru);
 		if (!PageHighMem(page))
 			map = page;
 	}
 	if (map) {
-		list_del(&map->list);
+		list_del(&map->lru);
 		update_and_free_page(map);
 		htlbpagemem--;
 		count++;
--- diff/arch/ia64/pci/pci.c	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/ia64/pci/pci.c	2004-03-16 09:37:55.382120808 +0000
@@ -57,17 +57,16 @@ struct pci_fixup pcibios_fixups[1];
 	((u64)(seg << 24) | (u64)(bus << 16) | \
 	 (u64)(devfn << 8) | (u64)(reg))
 
-
 static int
 pci_sal_read (int seg, int bus, int devfn, int reg, int len, u32 *value)
 {
 	int result = 0;
 	u64 data = 0;
 
-	if (!value || (seg > 255) || (bus > 255) || (devfn > 255) || (reg > 255))
+	if ((seg > 255) || (bus > 255) || (devfn > 255) || (reg > 255))
 		return -EINVAL;
 
-	result = ia64_sal_pci_config_read(PCI_SAL_ADDRESS(seg, bus, devfn, reg), len, &data);
+	result = ia64_sal_pci_config_read(PCI_SAL_ADDRESS(seg, bus, devfn, reg), 0, len, &data);
 
 	*value = (u32) data;
 
@@ -80,15 +79,62 @@ pci_sal_write (int seg, int bus, int dev
 	if ((seg > 255) || (bus > 255) || (devfn > 255) || (reg > 255))
 		return -EINVAL;
 
-	return ia64_sal_pci_config_write(PCI_SAL_ADDRESS(seg, bus, devfn, reg), len, value);
+	return ia64_sal_pci_config_write(PCI_SAL_ADDRESS(seg, bus, devfn, reg), 0, len, value);
 }
 
-struct pci_raw_ops pci_sal_ops = {
+static struct pci_raw_ops pci_sal_ops = {
 	.read = 	pci_sal_read,
 	.write =	pci_sal_write
 };
 
-struct pci_raw_ops *raw_pci_ops = &pci_sal_ops;	/* default to SAL */
+/* SAL 3.2 adds support for extended config space. */
+
+#define PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg) \
+	((u64)(seg << 28) | (u64)(bus << 20) | \
+	 (u64)(devfn << 12) | (u64)(reg))
+
+static int
+pci_sal_ext_read (int seg, int bus, int devfn, int reg, int len, u32 *value)
+{
+	int result = 0;
+	u64 data = 0;
+
+	if ((seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095))
+		return -EINVAL;
+
+	result = ia64_sal_pci_config_read(PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg), 1, len, &data);
+
+	*value = (u32) data;
+
+	return result;
+}
+
+static int
+pci_sal_ext_write (int seg, int bus, int devfn, int reg, int len, u32 value)
+{
+	if ((seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095))
+		return -EINVAL;
+
+	return ia64_sal_pci_config_write(PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg), 1, len, value);
+}
+
+static struct pci_raw_ops pci_sal_ext_ops = {
+	.read = 	pci_sal_ext_read,
+	.write =	pci_sal_ext_write
+};
+
+struct pci_raw_ops *raw_pci_ops = &pci_sal_ops;	/* default to SAL < 3.2 */
+
+static int __init
+pci_set_sal_ops (void)
+{
+	if (sal_version >= SAL_VERSION_CODE(3, 2)) {
+		raw_pci_ops = &pci_sal_ext_ops;
+	}
+	return 0;
+}
+
+arch_initcall(pci_set_sal_ops);
 
 
 static int
@@ -139,7 +185,8 @@ alloc_pci_controller (int seg)
 }
 
 static int __devinit
-alloc_resource (char *name, struct resource *root, unsigned long start, unsigned long end, unsigned long flags)
+alloc_resource (char *name, struct resource *root, unsigned long start, unsigned long end,
+		unsigned long flags)
 {
 	struct resource *res;
 
--- diff/arch/ia64/sn/io/hwgfs/ramfs.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/ia64/sn/io/hwgfs/ramfs.c	2004-03-16 09:37:55.383120656 +0000
@@ -84,7 +84,7 @@ static int hwgfs_mkdir(struct inode * di
 	return hwgfs_mknod(dir, dentry, mode | S_IFDIR, 0);
 }
 
-static int hwgfs_create(struct inode *dir, struct dentry *dentry, int mode)
+static int hwgfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *unused)
 {
 	return hwgfs_mknod(dir, dentry, mode | S_IFREG, 0);
 }
--- diff/arch/ia64/sn/io/machvec/pci_dma.c	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/ia64/sn/io/machvec/pci_dma.c	2004-03-16 09:37:55.384120504 +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/ia64/sn/io/sn2/pcibr/pcibr_dvr.c	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c	2004-03-16 09:37:55.385120352 +0000
@@ -2501,7 +2501,7 @@ pcibr_pcix_rbars_calc(pcibr_soft_t pcibr
     if (pcibr_soft->bs_pcix_num_funcs) {
 	if (pcibr_soft->bs_pcix_num_funcs > NUM_RBAR) {
 	    printk(KERN_WARNING
-		"%lx: Must oversubscribe Read Buffer Attribute Registers"
+		"%s: Must oversubscribe Read Buffer Attribute Registers"
 		"(RBAR).  Bus has %d RBARs but %d funcs need them.\n",
 		pcibr_soft->bs_name, NUM_RBAR, pcibr_soft->bs_pcix_num_funcs);
 	    percent_allowed = 0;
@@ -2603,7 +2603,7 @@ pcibr_debug(uint32_t type, vertex_hdl_t 
 		memset(buffer, 0, 1024);
 		vsnprintf(buffer, 1024, format, ap);
 		va_end(ap);
-		printk("", "%s", buffer);
+		printk("%s", buffer);
 		kfree(buffer);
 	    }
         }
--- diff/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c	2004-03-16 09:37:55.386120200 +0000
@@ -101,7 +101,7 @@ sn_dma_flush(unsigned long addr)
 {
 	nasid_t nasid;
 	int wid_num;
-	volatile struct sn_flush_device_list *p;
+	struct sn_flush_device_list *p;
 	int i,j;
 	int bwin;
 	unsigned long flags;
--- diff/arch/ia64/sn/io/sn2/pciio.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ia64/sn/io/sn2/pciio.c	2004-03-16 09:37:55.387120048 +0000
@@ -822,7 +822,7 @@ pciio_device_info_unregister(vertex_hdl_
 			     pciio_info_t pciio_info)
 {
     char		name[32];
-    vertex_hdl_t	pconn;
+    vertex_hdl_t	pconn = NULL;
 
     if (!pciio_info)
 	return;
@@ -835,7 +835,6 @@ pciio_device_info_unregister(vertex_hdl_
 
     hwgraph_vertex_unref(pconn);
     hwgraph_vertex_destroy(pconn);
-    
 }
 
 /*ARGSUSED */
--- diff/arch/ia64/sn/io/sn2/shub_intr.c	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/ia64/sn/io/sn2/shub_intr.c	2004-03-16 09:37:55.387120048 +0000
@@ -200,7 +200,6 @@ sn_shub_redirect_intr(pcibr_intr_t intr,
 	int cpuphys, slice;
 	nasid_t nasid;
 	unsigned long xtalk_addr;
-	void		*bridge = intr->bi_soft->bs_base;
 	int		irq;
 	int		i;
 	int		old_cpu;
@@ -237,13 +236,13 @@ sn_shub_redirect_intr(pcibr_intr_t intr,
 	for (bit = 0; bit < 8; bit++) {
 		if (intr->bi_ibits & (1 << bit) ) {
 			/* Disable interrupts. */
-			pcireg_intr_enable_bit_clr(bridge, bit);
+			pcireg_intr_enable_bit_clr(intr->bi_soft, bit);
 			/* Reset Host address (Interrupt destination) */
-			pcireg_intr_addr_addr_set(bridge, bit, xtalk_addr);
+			pcireg_intr_addr_addr_set(intr->bi_soft, bit, xtalk_addr);
 			/* Enable interrupt */
-			pcireg_intr_enable_bit_set(bridge, bit);
+			pcireg_intr_enable_bit_set(intr->bi_soft, bit);
 			/* Force an interrupt, just in case. */
-			pcireg_force_intr_set(bridge, bit);
+			pcireg_force_intr_set(intr->bi_soft, bit);
 		}
 	}
 	irq = intr->bi_irq;
--- diff/arch/ia64/sn/kernel/irq.c	2004-03-11 10:20:20.000000000 +0000
+++ source/arch/ia64/sn/kernel/irq.c	2004-03-16 09:37:55.388119896 +0000
@@ -15,6 +15,7 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/bootmem.h>
+#include <linux/cpumask.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/sn/sgi.h>
@@ -118,10 +119,11 @@ sn_end_irq(unsigned int irq)
 }
 
 static void
-sn_set_affinity_irq(unsigned int irq, unsigned long cpu)
+sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
 {
 #ifdef CONFIG_SMP
 	int redir = 0;
+	int cpu;
 	struct sn_intr_list_t *p = sn_intr_list[irq];
 	pcibr_intr_t intr;
 	extern void sn_shub_redirect_intr(pcibr_intr_t intr, unsigned long cpu);
@@ -135,7 +137,9 @@ sn_set_affinity_irq(unsigned int irq, un
 	if (intr == NULL)
 		return; 
 
+	cpu = first_cpu(mask);
 	sn_shub_redirect_intr(intr, cpu);
+	irq = irq & 0xff;  /* strip off redirect bit, if someone stuck it on. */
 	(void) set_irq_affinity_info(irq, cpu_physical_id(intr->bi_cpu), redir);
 #endif /* CONFIG_SMP */
 }
--- diff/arch/m68k/amiga/amiints.c	2003-06-09 13:18:17.000000000 +0000
+++ source/arch/m68k/amiga/amiints.c	2004-03-16 09:37:55.388119896 +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 13:18:17.000000000 +0000
+++ source/arch/m68k/bvme6000/bvmeints.c	2004-03-16 09:37:55.389119744 +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 13:18:17.000000000 +0000
+++ source/arch/m68k/hp300/time.c	2004-03-16 09:37:55.389119744 +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-11 10:20:20.000000000 +0000
+++ source/arch/m68k/kernel/entry.S	2004-03-16 09:37:55.390119592 +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-16 09:37:55.390119592 +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-11 10:20:20.000000000 +0000
+++ source/arch/m68k/kernel/sys_m68k.c	2004-03-16 09:37:55.391119440 +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-11 10:20:20.000000000 +0000
+++ source/arch/m68k/mac/iop.c	2004-03-16 09:37:55.392119288 +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-11 10:20:20.000000000 +0000
+++ source/arch/m68k/mac/macints.c	2004-03-16 09:37:55.393119136 +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 13:18:17.000000000 +0000
+++ source/arch/m68k/mac/oss.c	2004-03-16 09:37:55.393119136 +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 13:18:17.000000000 +0000
+++ source/arch/m68k/mac/psc.c	2004-03-16 09:37:55.394118984 +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-11 10:20:20.000000000 +0000
+++ source/arch/m68k/mac/via.c	2004-03-16 09:37:55.401117920 +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 13:18:17.000000000 +0000
+++ source/arch/m68k/q40/config.c	2004-03-16 09:37:55.402117768 +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-16 09:37:55.403117616 +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 13:18:17.000000000 +0000
+++ source/arch/m68k/sun3/sun3ints.c	2004-03-16 09:37:55.403117616 +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-11 10:20:20.000000000 +0000
+++ source/arch/m68knommu/kernel/sys_m68k.c	2004-03-16 09:37:55.404117464 +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 10:49:45.000000000 +0000
+++ source/arch/m68knommu/kernel/syscalltable.S	2004-03-16 09:37:55.404117464 +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/mm/dma-coherent.c	2004-03-11 10:20:21.000000000 +0000
+++ source/arch/mips/mm/dma-coherent.c	2004-03-16 09:37:55.404117464 +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-11 10:20:21.000000000 +0000
+++ source/arch/mips/mm/dma-ip27.c	2004-03-16 09:37:55.405117312 +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-11 10:20:21.000000000 +0000
+++ source/arch/mips/mm/dma-noncoherent.c	2004-03-16 09:37:55.406117160 +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/configs/712_defconfig	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/parisc/configs/712_defconfig	2004-03-16 09:37:55.407117008 +0000
@@ -22,6 +22,7 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 CONFIG_LOG_BUF_SHIFT=15
+# CONFIG_HOTPLUG is not set
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
@@ -30,6 +31,7 @@ CONFIG_EPOLL=y
 CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 
 #
 # Loadable module support
@@ -64,7 +66,6 @@ CONFIG_GSC_WAX=y
 # CONFIG_PCI is not set
 # CONFIG_CHASSIS_LCD_LED is not set
 # CONFIG_PDC_CHASSIS is not set
-# CONFIG_HOTPLUG is not set
 
 #
 # Executable file formats
@@ -79,6 +80,7 @@ CONFIG_BINFMT_ELF=y
 #
 # Generic Driver Options
 #
+CONFIG_DEBUG_DRIVER=y
 
 #
 # Memory Technology Devices (MTD)
@@ -99,7 +101,6 @@ CONFIG_PARPORT_GSC=y
 #
 # Plug and Play support
 #
-# CONFIG_PNP is not set
 
 #
 # Block devices
@@ -110,7 +111,6 @@ CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -144,7 +144,6 @@ CONFIG_CHR_DEV_SG=y
 #
 # SCSI low-level drivers
 #
-# CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_EATA_PIO is not set
 # CONFIG_SCSI_PPA is not set
@@ -170,13 +169,21 @@ CONFIG_MD_RAID5=y
 #
 # Fusion MPT device support
 #
-# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
 
 #
 # I2O device support
 #
 
 #
+# Macintosh device drivers
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -287,7 +294,7 @@ CONFIG_NET_RADIO=y
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_ISDN is not set
 
 #
 # Telephony Support
@@ -318,8 +325,8 @@ CONFIG_INPUT_EVDEV=y
 CONFIG_SOUND_GAMEPORT=y
 CONFIG_SERIO=y
 # CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
 # CONFIG_SERIO_PARKBD is not set
+CONFIG_SERIO_GSCPS2=y
 # CONFIG_HP_SDC is not set
 
 #
@@ -331,15 +338,17 @@ CONFIG_INPUT_KEYBOARD=y
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 # CONFIG_KEYBOARD_HIL_OLD is not set
+# CONFIG_KEYBOARD_HIL is not set
 CONFIG_INPUT_MOUSE=y
 # CONFIG_MOUSE_PS2 is not set
 # CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_HIL is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 CONFIG_INPUT_MISC=y
 # CONFIG_INPUT_PCSPKR is not set
 # CONFIG_INPUT_UINPUT is not set
-CONFIG_INPUT_GSC=y
+# CONFIG_HP_SDC_RTC is not set
 
 #
 # Character devices
@@ -370,31 +379,14 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 CONFIG_PRINTER=y
 # CONFIG_LP_CONSOLE is not set
 # CONFIG_PPDEV is not set
 # CONFIG_TIPAR is not set
 
 #
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Algorithms
-#
-
-#
-# I2C Hardware Bus support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
 # Mice
 #
 # CONFIG_BUSMOUSE is not set
@@ -425,6 +417,15 @@ CONFIG_GEN_RTC=y
 # CONFIG_RAW_DRIVER is not set
 
 #
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -444,7 +445,6 @@ CONFIG_FB_STI=y
 #
 # Console display driver support
 #
-# CONFIG_VGA_CONSOLE is not set
 # CONFIG_MDA_CONSOLE is not set
 CONFIG_STI_CONSOLE=y
 CONFIG_DUMMY_CONSOLE_COLUMNS=160
@@ -475,6 +475,11 @@ CONFIG_LOGO_PARISC_CLUT224=y
 #
 
 #
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -511,7 +516,6 @@ CONFIG_JOLIET=y
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
-CONFIG_DEVPTS_FS=y
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
@@ -520,6 +524,7 @@ CONFIG_RAMFS=y
 #
 # Miscellaneous filesystems
 #
+# CONFIG_HFSPLUS_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -549,11 +554,11 @@ CONFIG_SUNRPC=y
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-CONFIG_NLS=y
 
 #
 # Native Language Support
 #
+CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_CODEPAGE_437 is not set
 # CONFIG_NLS_CODEPAGE_737 is not set
@@ -628,6 +633,7 @@ CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_AES is not set
 # CONFIG_CRYPTO_CAST5 is not set
 # CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_ARC4 is not set
 # CONFIG_CRYPTO_DEFLATE is not set
 # CONFIG_CRYPTO_TEST is not set
 
--- diff/arch/parisc/configs/a500_defconfig	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/parisc/configs/a500_defconfig	2004-03-16 09:37:55.408116856 +0000
@@ -23,6 +23,7 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 CONFIG_LOG_BUF_SHIFT=16
+CONFIG_HOTPLUG=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_EMBEDDED=y
@@ -72,7 +73,6 @@ CONFIG_IOMMU_SBA=y
 # CONFIG_SUPERIO is not set
 CONFIG_CHASSIS_LCD_LED=y
 # CONFIG_PDC_CHASSIS is not set
-CONFIG_HOTPLUG=y
 
 #
 # PCMCIA/CardBus support
@@ -102,6 +102,7 @@ CONFIG_BINFMT_ELF=y
 # Generic Driver Options
 #
 # CONFIG_FW_LOADER is not set
+CONFIG_DEBUG_DRIVER=y
 
 #
 # Memory Technology Devices (MTD)
@@ -116,7 +117,6 @@ CONFIG_BINFMT_ELF=y
 #
 # Plug and Play support
 #
-# CONFIG_PNP is not set
 
 #
 # Block devices
@@ -195,9 +195,15 @@ CONFIG_SCSI_SYM53C8XX_IOMAPPED=y
 CONFIG_SCSI_QLOGIC_FC=m
 # CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
 CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+CONFIG_SCSI_QLA2300=m
+CONFIG_SCSI_QLA2322=m
+CONFIG_SCSI_QLA6312=m
+CONFIG_SCSI_QLA6322=m
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_NSP32 is not set
 CONFIG_SCSI_DEBUG=m
 
 #
@@ -215,6 +221,7 @@ CONFIG_MD_LINEAR=y
 CONFIG_MD_RAID0=y
 CONFIG_MD_RAID1=y
 # CONFIG_MD_RAID5 is not set
+# CONFIG_MD_RAID6 is not set
 # CONFIG_MD_MULTIPATH is not set
 # CONFIG_BLK_DEV_DM is not set
 
@@ -227,14 +234,17 @@ CONFIG_FUSION_ISENSE=m
 CONFIG_FUSION_CTL=m
 
 #
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+# IEEE 1394 (FireWire) support
 #
 # CONFIG_IEEE1394 is not set
 
 #
 # I2O device support
 #
-# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
 
 #
 # Networking support
@@ -362,7 +372,7 @@ CONFIG_LLC2=m
 #
 # Network testing
 #
-# CONFIG_NET_PKTGEN is not set
+CONFIG_NET_PKTGEN=m
 CONFIG_NETDEVICES=y
 
 #
@@ -391,9 +401,10 @@ CONFIG_TYPHOON=m
 #
 CONFIG_NET_TULIP=y
 CONFIG_DE2104X=m
-CONFIG_TULIP=y
+CONFIG_TULIP=m
 # CONFIG_TULIP_MWI is not set
 CONFIG_TULIP_MMIO=y
+# CONFIG_TULIP_NAPI is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_WINBOND_840 is not set
 # CONFIG_DM9102 is not set
@@ -405,10 +416,12 @@ CONFIG_PCNET32=m
 # CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
 # CONFIG_DGRS is not set
 CONFIG_EEPRO100=m
 # CONFIG_EEPRO100_PIO is not set
 CONFIG_E100=m
+CONFIG_E100_NAPI=y
 # CONFIG_FEALNX is not set
 CONFIG_NATSEMI=m
 # CONFIG_NE2K_PCI is not set
@@ -418,6 +431,7 @@ CONFIG_8139TOO=m
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
 # CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_8139_RXBUF_IDX=1
 # CONFIG_SIS900 is not set
 CONFIG_EPIC100=m
 # CONFIG_SUNDANCE is not set
@@ -482,13 +496,13 @@ CONFIG_HERMES=m
 CONFIG_PLX_HERMES=m
 CONFIG_TMD_HERMES=m
 CONFIG_PCI_HERMES=m
+# CONFIG_ATMEL is not set
 
 #
 # Wireless 802.11b Pcmcia/Cardbus cards support
 #
 CONFIG_PCMCIA_HERMES=m
 CONFIG_AIRO_CS=m
-# CONFIG_PCMCIA_ATMEL is not set
 # CONFIG_PCMCIA_WL3501 is not set
 CONFIG_NET_WIRELESS=y
 
@@ -535,7 +549,7 @@ CONFIG_PCMCIA_XIRC2PS=m
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_ISDN is not set
 
 #
 # Telephony Support
@@ -602,25 +616,7 @@ CONFIG_PDC_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Algorithms
-#
-
-#
-# I2C Hardware Bus support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
+# CONFIG_LEGACY_PTYS is not set
 
 #
 # Mice
@@ -659,6 +655,15 @@ CONFIG_RAW_DRIVER=y
 CONFIG_MAX_RAW_DEVS=256
 
 #
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -676,7 +681,6 @@ CONFIG_MAX_RAW_DEVS=256
 #
 # Console display driver support
 #
-# CONFIG_VGA_CONSOLE is not set
 # CONFIG_MDA_CONSOLE is not set
 # CONFIG_STI_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE_COLUMNS=160
@@ -692,6 +696,10 @@ CONFIG_DUMMY_CONSOLE=y
 # USB support
 #
 # CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
 # CONFIG_USB_GADGET is not set
 
 #
@@ -711,6 +719,7 @@ CONFIG_JFS_FS=m
 CONFIG_XFS_FS=m
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -740,7 +749,6 @@ CONFIG_VFAT_FS=m
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 # CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
 # CONFIG_DEVPTS_FS_XATTR is not set
 # CONFIG_TMPFS is not set
 # CONFIG_HUGETLBFS is not set
@@ -753,6 +761,7 @@ CONFIG_RAMFS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
@@ -876,6 +885,7 @@ CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_AES=m
 CONFIG_CRYPTO_CAST5=m
 CONFIG_CRYPTO_CAST6=m
+# CONFIG_CRYPTO_ARC4 is not set
 CONFIG_CRYPTO_DEFLATE=m
 CONFIG_CRYPTO_TEST=m
 
--- diff/arch/parisc/configs/c3000_defconfig	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/parisc/configs/c3000_defconfig	2004-03-16 09:37:55.409116704 +0000
@@ -23,6 +23,7 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 CONFIG_LOG_BUF_SHIFT=16
+CONFIG_HOTPLUG=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_EMBEDDED=y
@@ -71,7 +72,6 @@ CONFIG_IOMMU_SBA=y
 CONFIG_SUPERIO=y
 # CONFIG_CHASSIS_LCD_LED is not set
 # CONFIG_PDC_CHASSIS is not set
-CONFIG_HOTPLUG=y
 
 #
 # PCMCIA/CardBus support
@@ -101,6 +101,7 @@ CONFIG_BINFMT_ELF=y
 # Generic Driver Options
 #
 CONFIG_FW_LOADER=y
+CONFIG_DEBUG_DRIVER=y
 
 #
 # Memory Technology Devices (MTD)
@@ -128,7 +129,6 @@ CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -153,6 +153,7 @@ CONFIG_BLK_DEV_IDESCSI=y
 #
 # IDE chipset support/bugfixes
 #
+CONFIG_IDE_GENERIC=y
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -161,7 +162,6 @@ CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 # CONFIG_IDEDMA_PCI_AUTO is not set
-# CONFIG_IDEDMA_PCI_WIP is not set
 CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -252,11 +252,13 @@ CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
 CONFIG_SCSI_QLOGIC_FC=m
 # CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
 CONFIG_SCSI_QLOGIC_1280=m
-CONFIG_SCSI_QLA2XXX_CONFIG=y
-CONFIG_SCSI_QLA2XXX=m
+CONFIG_SCSI_QLA2XXX=y
 # CONFIG_SCSI_QLA21XX is not set
 # CONFIG_SCSI_QLA22XX is not set
-CONFIG_SCSI_QLA23XX=m
+CONFIG_SCSI_QLA2300=m
+CONFIG_SCSI_QLA2322=m
+CONFIG_SCSI_QLA6312=m
+CONFIG_SCSI_QLA6322=m
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_NSP32 is not set
@@ -280,8 +282,9 @@ CONFIG_MD_RAID0=y
 CONFIG_MD_RAID1=y
 # CONFIG_MD_RAID5 is not set
 # CONFIG_MD_RAID6 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_DM is not set
+CONFIG_MD_MULTIPATH=y
+CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_CRYPT is not set
 
 #
 # Fusion MPT device support
@@ -292,7 +295,7 @@ CONFIG_FUSION_ISENSE=m
 CONFIG_FUSION_CTL=m
 
 #
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+# IEEE 1394 (FireWire) support
 #
 # CONFIG_IEEE1394 is not set
 
@@ -302,6 +305,10 @@ CONFIG_FUSION_CTL=m
 # CONFIG_I2O is not set
 
 #
+# Macintosh device drivers
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -457,6 +464,7 @@ CONFIG_DE2104X=m
 CONFIG_TULIP=y
 # CONFIG_TULIP_MWI is not set
 # CONFIG_TULIP_MMIO is not set
+# CONFIG_TULIP_NAPI is not set
 CONFIG_DE4X5=m
 CONFIG_WINBOND_840=m
 # CONFIG_DM9102 is not set
@@ -474,6 +482,7 @@ CONFIG_B44=m
 CONFIG_EEPRO100=m
 # CONFIG_EEPRO100_PIO is not set
 CONFIG_E100=m
+# CONFIG_E100_NAPI is not set
 # CONFIG_FEALNX is not set
 CONFIG_NATSEMI=m
 # CONFIG_NE2K_PCI is not set
@@ -483,6 +492,7 @@ CONFIG_8139TOO=m
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
 # CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_8139_RXBUF_IDX=1
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
@@ -571,7 +581,7 @@ CONFIG_PCMCIA_AXNET=m
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_ISDN is not set
 
 #
 # Telephony Support
@@ -652,7 +662,8 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 
 #
 # Mice
@@ -696,6 +707,10 @@ CONFIG_MAX_RAW_DEVS=256
 # CONFIG_I2C is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -716,6 +731,7 @@ CONFIG_FB=y
 CONFIG_FB_STI=y
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON_OLD is not set
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_ATY is not set
@@ -731,7 +747,6 @@ CONFIG_FB_STI=y
 #
 # Console display driver support
 #
-# CONFIG_VGA_CONSOLE is not set
 # CONFIG_MDA_CONSOLE is not set
 CONFIG_STI_CONSOLE=y
 CONFIG_DUMMY_CONSOLE_COLUMNS=160
@@ -823,7 +838,6 @@ CONFIG_USB_KBTAB=m
 # USB Imaging devices
 #
 CONFIG_USB_MDC800=m
-CONFIG_USB_SCANNER=m
 CONFIG_USB_MICROTEK=m
 CONFIG_USB_HPUSBSCSI=m
 
@@ -867,6 +881,10 @@ CONFIG_USB_LEGOTOWER=m
 # CONFIG_USB_LCD is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_TEST is not set
+
+#
+# USB Gadget Support
+#
 # CONFIG_USB_GADGET is not set
 
 #
@@ -883,6 +901,7 @@ CONFIG_JBD=y
 CONFIG_XFS_FS=m
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -912,7 +931,6 @@ CONFIG_VFAT_FS=m
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 # CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
 # CONFIG_HUGETLBFS is not set
@@ -925,6 +943,7 @@ CONFIG_RAMFS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
@@ -1046,6 +1065,7 @@ CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_AES=m
 CONFIG_CRYPTO_CAST5=m
 CONFIG_CRYPTO_CAST6=m
+# CONFIG_CRYPTO_ARC4 is not set
 CONFIG_CRYPTO_DEFLATE=m
 CONFIG_CRYPTO_TEST=m
 
--- diff/arch/parisc/defconfig	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/parisc/defconfig	2004-03-16 09:37:55.410116552 +0000
@@ -22,6 +22,7 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 CONFIG_LOG_BUF_SHIFT=15
+# CONFIG_HOTPLUG is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 # CONFIG_EMBEDDED is not set
@@ -31,6 +32,7 @@ CONFIG_EPOLL=y
 CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 
 #
 # Loadable module support
@@ -71,7 +73,6 @@ CONFIG_IOMMU_SBA=y
 CONFIG_SUPERIO=y
 CONFIG_CHASSIS_LCD_LED=y
 CONFIG_PDC_CHASSIS=y
-# CONFIG_HOTPLUG is not set
 
 #
 # Executable file formats
@@ -86,6 +87,7 @@ CONFIG_BINFMT_ELF=y
 #
 # Generic Driver Options
 #
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -108,7 +110,6 @@ CONFIG_PARPORT_GSC=y
 #
 # Plug and Play support
 #
-# CONFIG_PNP is not set
 
 #
 # Block devices
@@ -195,8 +196,16 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20
 # CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_QLA6322 is not set
 # CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
@@ -209,6 +218,7 @@ CONFIG_MD_LINEAR=y
 CONFIG_MD_RAID0=y
 CONFIG_MD_RAID1=y
 CONFIG_MD_RAID5=y
+# CONFIG_MD_RAID6 is not set
 # CONFIG_MD_MULTIPATH is not set
 # CONFIG_BLK_DEV_DM is not set
 
@@ -218,7 +228,7 @@ CONFIG_MD_RAID5=y
 # CONFIG_FUSION is not set
 
 #
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+# IEEE 1394 (FireWire) support
 #
 # CONFIG_IEEE1394 is not set
 
@@ -228,6 +238,10 @@ CONFIG_MD_RAID5=y
 # CONFIG_I2O is not set
 
 #
+# Macintosh device drivers
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -319,6 +333,7 @@ CONFIG_NET_TULIP=y
 CONFIG_TULIP=y
 # CONFIG_TULIP_MWI is not set
 # CONFIG_TULIP_MMIO is not set
+# CONFIG_TULIP_NAPI is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_WINBOND_840 is not set
 # CONFIG_DM9102 is not set
@@ -330,6 +345,7 @@ CONFIG_NET_PCI=y
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_AC3200 is not set
 # CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 # CONFIG_E100 is not set
@@ -386,6 +402,7 @@ CONFIG_NET_RADIO=y
 #
 CONFIG_AIRO=y
 # CONFIG_HERMES is not set
+# CONFIG_ATMEL is not set
 CONFIG_NET_WIRELESS=y
 
 #
@@ -419,7 +436,7 @@ CONFIG_NET_WIRELESS=y
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_ISDN is not set
 
 #
 # Telephony Support
@@ -450,10 +467,10 @@ CONFIG_INPUT_EVDEV=y
 CONFIG_SOUND_GAMEPORT=y
 CONFIG_SERIO=y
 # CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
 # CONFIG_SERIO_PARKBD is not set
+CONFIG_SERIO_GSCPS2=y
 CONFIG_HP_SDC=y
-# CONFIG_HIL_MLC is not set
+CONFIG_HIL_MLC=y
 # CONFIG_SERIO_PCIPS2 is not set
 
 #
@@ -464,10 +481,11 @@ CONFIG_INPUT_KEYBOARD=y
 # CONFIG_KEYBOARD_SUNKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
-# CONFIG_KEYBOARD_HIL_OLD is not set
+CONFIG_KEYBOARD_HIL=y
 CONFIG_INPUT_MOUSE=y
 # CONFIG_MOUSE_PS2 is not set
 # CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_HIL is not set
 CONFIG_INPUT_JOYSTICK=y
 # CONFIG_JOYSTICK_IFORCE is not set
 # CONFIG_JOYSTICK_WARRIOR is not set
@@ -485,7 +503,6 @@ CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_INPUT_MISC=y
 # CONFIG_INPUT_PCSPKR is not set
 # CONFIG_INPUT_UINPUT is not set
-CONFIG_INPUT_GSC=y
 CONFIG_HP_SDC_RTC=y
 
 #
@@ -517,31 +534,14 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 CONFIG_PRINTER=y
 # CONFIG_LP_CONSOLE is not set
 # CONFIG_PPDEV is not set
 # CONFIG_TIPAR is not set
 
 #
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Algorithms
-#
-
-#
-# I2C Hardware Bus support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
 # Mice
 #
 # CONFIG_BUSMOUSE is not set
@@ -572,6 +572,15 @@ CONFIG_GEN_RTC=y
 # CONFIG_RAW_DRIVER is not set
 
 #
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -585,16 +594,19 @@ CONFIG_GEN_RTC=y
 # 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_STI=y
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON_OLD is not set
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_ATY is not set
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
@@ -603,7 +615,6 @@ CONFIG_FB_STI=y
 #
 # Console display driver support
 #
-# CONFIG_VGA_CONSOLE is not set
 # CONFIG_MDA_CONSOLE is not set
 CONFIG_STI_CONSOLE=y
 CONFIG_DUMMY_CONSOLE_COLUMNS=160
@@ -686,7 +697,6 @@ CONFIG_USB_OHCI_HCD=y
 # USB Imaging devices
 #
 # CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
 # CONFIG_USB_MICROTEK is not set
 # CONFIG_USB_HPUSBSCSI is not set
 
@@ -721,11 +731,19 @@ CONFIG_USB_OHCI_HCD=y
 #
 # USB Miscellaneous drivers
 #
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
 # CONFIG_USB_TIGL is not set
 # CONFIG_USB_AUERSWALD is not set
 # CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_BRLVGER is not set
 # CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+
+#
+# USB Gadget Support
+#
 # CONFIG_USB_GADGET is not set
 
 #
@@ -766,7 +784,6 @@ CONFIG_JOLIET=y
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 # CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
@@ -778,6 +795,7 @@ CONFIG_RAMFS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
@@ -809,7 +827,6 @@ CONFIG_SUNRPC=y
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
@@ -817,11 +834,11 @@ CONFIG_SUNRPC=y
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-CONFIG_NLS=y
 
 #
 # Native Language Support
 #
+CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_CODEPAGE_437 is not set
 # CONFIG_NLS_CODEPAGE_737 is not set
@@ -899,6 +916,7 @@ CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_AES is not set
 # CONFIG_CRYPTO_CAST5 is not set
 # CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_ARC4 is not set
 # CONFIG_CRYPTO_DEFLATE is not set
 # CONFIG_CRYPTO_TEST is not set
 
--- diff/arch/parisc/hpux/entry_hpux.S	2002-11-11 11:09:42.000000000 +0000
+++ source/arch/parisc/hpux/entry_hpux.S	2004-03-16 09:37:55.411116400 +0000
@@ -1,11 +1,23 @@
-/*
+/*    syscall table for HPUX specific syscalls
  *
- * Linux/PARISC Project (http://www.parisc-linux.org/)
+ *    Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *    Copyright (C) 1999 Matthew Wilcox <willy at debian . org>
  *
- * modified by Matthew Wilcox <willy@bofh.ai> 1999-07-26
+ *    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/sys.h>
 #include <linux/linkage.h>
 #include <asm/unistd.h>
--- diff/arch/parisc/kernel/drivers.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/parisc/kernel/drivers.c	2004-03-16 09:37:55.412116248 +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/entry.S	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/parisc/kernel/entry.S	2004-03-16 09:37:55.413116096 +0000
@@ -533,7 +533,7 @@ __kernel_thread:
 	ldil	L%CLONE_UNTRACED, %r26
 	ldo	CLONE_VM(%r26), %r26   /* Force CLONE_VM since only init_mm */
 	or	%r26, %r24, %r26      /* will have kernel mappings.	 */
-	copy	%r0, %r25		/* stack_start */
+	ldi	1, %r25			/* stack_start, signals kernel thread */
 	stw	%r0, -52(%r30)	     	/* user_tid */
 #ifdef __LP64__
 	ldo	-16(%r30),%r29		/* Reference param save area */
--- diff/arch/parisc/kernel/hardware.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/parisc/kernel/hardware.c	2004-03-16 09:37:55.415115792 +0000
@@ -333,8 +333,9 @@ static struct hp_hardware hp_hardware_li
 	{HPHW_A_DMA, 0x01F, 0x00089, 0x80, "SkyHawk 100/120 FW-SCSI"}, 
 	{HPHW_A_DMA, 0x027, 0x00089, 0x80, "Piranha 100 FW-SCSI"}, 
 	{HPHW_A_DMA, 0x032, 0x00089, 0x80, "Raven T' Core FW-SCSI"}, 
-	{HPHW_A_DMA, 0x03b, 0x00089, 0x80, "Raven U/L2 Core FW-SCSI"}, 
-	{HPHW_A_DMA, 0x03d, 0x00089, 0x80, "Merlin 160 Core FW-SCSI"},
+	{HPHW_A_DMA, 0x03B, 0x00089, 0x80, "Raven U/L2 Core FW-SCSI"}, 
+	{HPHW_A_DMA, 0x03C, 0x00089, 0x80, "Merlin 132 Core FW-SCSI"},
+	{HPHW_A_DMA, 0x03D, 0x00089, 0x80, "Merlin 160 Core FW-SCSI"},
 	{HPHW_A_DMA, 0x044, 0x00089, 0x80, "Mohawk Core FW-SCSI"}, 
 	{HPHW_A_DMA, 0x051, 0x00089, 0x80, "Firehawk FW-SCSI"}, 
 	{HPHW_A_DMA, 0x058, 0x00089, 0x80, "FireHawk 200 FW-SCSI"}, 
--- diff/arch/parisc/kernel/head64.S	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/parisc/kernel/head64.S	2004-03-16 09:37:55.415115792 +0000
@@ -165,9 +165,9 @@ common_stext:
 #endif /* CONFIG_SMP */
 
 	/* Save the rfi target address */
-	ldo		-THREAD_SZ_ALGN(%sp), %r1
-	ldd		TI_TASK(%r1), %r1
-	std		%r11,  TASK_PT_GR11(%r1)
+	ldd		TI_TASK-THREAD_SZ_ALGN(%sp), %r10
+	tophys_r1	%r10
+	std		%r11,  TASK_PT_GR11(%r10)
 
 #ifndef CONFIG_PDC_NARROW
 	/* Switch to wide mode; Superdome doesn't support narrow PDC
@@ -197,9 +197,9 @@ common_stext:
 
 stext_pdc_ret:
 	/* restore rfi target address*/
-	ldo		-THREAD_SZ_ALGN(%sp), %r1
-	ldd		TI_TASK(%r1), %r1
-	ldd		TASK_PT_GR11(%r1), %r11
+	ldd		TI_TASK-THREAD_SZ_ALGN(%sp), %r10
+	tophys_r1	%r10
+	ldd		TASK_PT_GR11(%r10), %r11
 
 	/* PARANOID: clear user scratch/user space SR's */
 	mtsp	%r0,%sr0
@@ -302,6 +302,7 @@ smp_slave_stext:
 	/*  Initialize the SP - monarch sets up smp_init_current_idle_task */
 	load32		PA(smp_init_current_idle_task),%sp
 	ldd		0(%sp),%sp	/* load task address */
+	ldd		TASK_THREAD_INFO(%sp), %sp
 	mtctl           %sp,%cr30       /* store in cr30 */
 	ldo             THREAD_SZ_ALGN(%sp),%sp
 	tophys_r1       %sp
--- diff/arch/parisc/kernel/module.c	2003-10-09 08:47:33.000000000 +0000
+++ source/arch/parisc/kernel/module.c	2004-03-16 09:37:55.416115640 +0000
@@ -1,25 +1,28 @@
-/*  Kernel module help for parisc.
+/*    Kernel dynamically loadable module help for PARISC.
+ *
+ *    The best reference for this stuff is probably the Processor-
+ *    Specific ELF Supplement for PA-RISC:
+ *        http://ftp.parisc-linux.org/docs/elf-pa-hp.pdf
+ *
+ *    Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *    Copyright (C) 2003 Randolph Chung <tausq at debian . org>
+ *
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    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 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
-
-    (c) 2003 Randolph Chung <tausq@debian.org>
-
-    The best reference for this stuff is probably the Processor-
-    Specific ELF Supplement for PA-RISC:
-	http://ftp.parisc-linux.org/docs/elf-pa-hp.pdf
-*/
 #include <linux/moduleloader.h>
 #include <linux/elf.h>
 #include <linux/vmalloc.h>
--- diff/arch/parisc/kernel/pacache.S	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/parisc/kernel/pacache.S	2004-03-16 09:37:55.417115488 +0000
@@ -221,6 +221,7 @@ flush_instruction_cache_local:
 	LDREG           ICACHE_STRIDE(%r1),%arg1
 	LDREG           ICACHE_COUNT(%r1),%arg2
 	LDREG           ICACHE_LOOP(%r1),%arg3
+	rsm             PSW_SM_I,%r22		/* No mmgt ops during loop*/
 	ADDIB=          -1,%arg3,fioneloop      /* Preadjust and test */
 	movb,<,n        %arg3,%r31,fisync       /* If loop < 0, do sync */
 
@@ -237,6 +238,7 @@ fioneloop:                              
 
 fisync:
 	sync
+	mtsm	%r22
 	bv      %r0(%r2)
 	nop
 	.exit
--- diff/arch/parisc/kernel/parisc_ksyms.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/parisc/kernel/parisc_ksyms.c	2004-03-16 09:37:55.417115488 +0000
@@ -67,8 +67,10 @@ EXPORT_SYMBOL(__cmpxchg_u64);
 #include <asm/uaccess.h>
 EXPORT_SYMBOL(lcopy_to_user);
 EXPORT_SYMBOL(lcopy_from_user);
-EXPORT_SYMBOL(lstrnlen_user);
+EXPORT_SYMBOL(lcopy_in_user);
+EXPORT_SYMBOL(lstrncpy_from_user);
 EXPORT_SYMBOL(lclear_user);
+EXPORT_SYMBOL(lstrnlen_user);
 
 #ifndef __LP64__
 /* Needed so insmod can set dp value */
--- diff/arch/parisc/kernel/pci-dma.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/parisc/kernel/pci-dma.c	2004-03-16 09:37:55.418115336 +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/pci.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/parisc/kernel/pci.c	2004-03-16 09:37:55.419115184 +0000
@@ -21,6 +21,7 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/cache.h>		/* for L1_CACHE_BYTES */
+#include <asm/superio.h>
 
 #define DEBUG_RESOURCES 0
 #define DEBUG_CONFIG 0
@@ -145,9 +146,13 @@ char *pcibios_setup(char *str)
 	return str;
 }
 
-
 /* Used in drivers/pci/quirks.c */
-struct pci_fixup pcibios_fixups[] = { {0} };
+struct pci_fixup pcibios_fixups[] = { 
+#ifdef CONFIG_SUPERIO
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_NS,	PCI_DEVICE_ID_NS_87415,	superio_fixup_pci },
+#endif
+	{ 0 }
+};
 
 
 /*
--- diff/arch/parisc/kernel/process.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/parisc/kernel/process.c	2004-03-16 09:37:55.420115032 +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>
@@ -251,6 +250,16 @@ sys_clone(unsigned long clone_flags, uns
 	  struct pt_regs *regs)
 {
 	int *user_tid = (int *)regs->gr[26];
+
+	/* usp must be word aligned.  This also prevents users from
+	 * passing in the value 1 (which is the signal for a special
+	 * return for a kernel thread) */
+	usp = ALIGN(usp, 4);
+
+	/* A zero value for usp means use the current stack */
+	if(usp == 0)
+		usp = regs->gr[30];
+
 	return do_fork(clone_flags & ~CLONE_IDLETASK, usp, regs, 0, user_tid, NULL);
 }
 
@@ -291,7 +300,7 @@ copy_thread(int nr, unsigned long clone_
 	 * We rely on the fact that kernel_thread passes
 	 * in zero for usp.
 	 */
-	if (usp == 0) {
+	if (usp == 1) {
 		/* kernel thread */
 		cregs->ksp = (((unsigned long)(ti)) + THREAD_SZ_ALGN);
 		/* Must exit via ret_from_kernel_thread in order
@@ -316,7 +325,7 @@ copy_thread(int nr, unsigned long clone_
 
 		/* Use same stack depth as parent */
 		cregs->ksp = ((unsigned long)(ti))
-			+ (pregs->gr[21] & (INIT_THREAD_SIZE - 1));
+			+ (pregs->gr[21] & (THREAD_SIZE - 1));
 		cregs->gr[30] = usp;
 		if (p->personality == PER_HPUX) {
 #ifdef CONFIG_HPUX
--- diff/arch/parisc/kernel/smp.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/parisc/kernel/smp.c	2004-03-16 09:37:55.427113968 +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-11 10:20:22.000000000 +0000
+++ source/arch/parisc/kernel/sys_parisc.c	2004-03-16 09:37:55.428113816 +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/parisc/kernel/vmlinux.lds.S	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/parisc/kernel/vmlinux.lds.S	2004-03-16 09:37:55.428113816 +0000
@@ -61,6 +61,9 @@ SECTIONS
   RODATA
 
   /* writeable */
+  . = ALIGN(4096);		/* Make sure this is paged aligned so
+  				   that we can properly leave these
+				   as writable */
   data_start = .;
 
   . = ALIGN(16);		/* Exception table */
--- diff/arch/ppc/boot/common/misc-common.c	2003-09-30 14:46:11.000000000 +0000
+++ source/arch/ppc/boot/common/misc-common.c	2004-03-16 09:37:55.429113664 +0000
@@ -67,6 +67,17 @@ extern unsigned char serial_getc(unsigne
 extern void serial_putc(unsigned long com_port, unsigned char c);
 #endif
 
+int
+printf(char const *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	_vprintk(putc, fmt, ap);
+	va_end(ap);
+	return 0;
+}
+
 void pause(void)
 {
 	puts("pause\n");
--- diff/arch/ppc/boot/ld.script	2003-10-09 08:47:16.000000000 +0000
+++ source/arch/ppc/boot/ld.script	2004-03-16 09:37:55.429113664 +0000
@@ -82,6 +82,7 @@ SECTIONS
     *(__ksymtab)
     *(__ksymtab_strings)
     *(__bug_table)
+    *(__kcrctab)
   }
 
 }
--- diff/arch/ppc/boot/lib/zlib.c	2003-09-30 14:46:12.000000000 +0000
+++ source/arch/ppc/boot/lib/zlib.c	2004-03-16 09:37:55.432113208 +0000
@@ -1,3 +1,7 @@
+#if 0
+#define DEBUG_ZLIB 1
+#define verbose 1
+#endif
 /*
  * This file is derived from various .h and .c files from the zlib-0.95
  * distribution by Jean-loup Gailly and Mark Adler, with some additions
@@ -85,16 +89,16 @@ extern char *z_errmsg[]; /* indexed by 1
 
 /* Diagnostic functions */
 #ifdef DEBUG_ZLIB
-#  include <stdio.h>
+#  include <nonstdio.h>
 #  ifndef verbose
 #    define verbose 0
 #  endif
-#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
-#  define Trace(x) fprintf x
-#  define Tracev(x) {if (verbose) fprintf x ;}
-#  define Tracevv(x) {if (verbose>1) fprintf x ;}
-#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
-#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#  define Assert(cond,msg) {if(!(cond)) printf(msg);}
+#  define Trace(x) printf x
+#  define Tracev(x) {if (verbose) printf x ;}
+#  define Tracevv(x) {if (verbose>1) printf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) printf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) printf x ;}
 #else
 #  define Assert(cond,msg)
 #  define Trace(x)
@@ -311,7 +315,7 @@ int inflateReset(
   z->msg = Z_NULL;
   z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
   inflate_blocks_reset(z->state->blocks, z, &c);
-  Trace((stderr, "inflate: reset\n"));
+  Trace(("inflate: reset\n"));
   return Z_OK;
 }
 
@@ -328,7 +332,7 @@ int inflateEnd(
     inflate_blocks_free(z->state->blocks, z, &c);
   ZFREE(z, z->state, sizeof(struct internal_state));
   z->state = Z_NULL;
-  Trace((stderr, "inflate: end\n"));
+  Trace(("inflate: end\n"));
   return Z_OK;
 }
 
@@ -372,7 +376,7 @@ int inflateInit2(
     inflateEnd(z);
     return Z_MEM_ERROR;
   }
-  Trace((stderr, "inflate: allocated\n"));
+  Trace(("inflate: allocated\n"));
 
   /* reset state */
   inflateReset(z);
@@ -437,7 +441,7 @@ int inflate(
         z->state->sub.marker = 5;       /* can't try inflateSync */
         break;
       }
-      Trace((stderr, "inflate: zlib header ok\n"));
+      Trace(("inflate: zlib header ok\n"));
       z->state->mode = BLOCKS;
     case BLOCKS:
       r = inflate_blocks(z->state->blocks, z, r);
@@ -482,7 +486,7 @@ int inflate(
         z->state->sub.marker = 5;       /* can't try inflateSync */
         break;
       }
-      Trace((stderr, "inflate: zlib check ok\n"));
+      Trace(("inflate: zlib check ok\n"));
       z->state->mode = DONE;
     case DONE:
       return Z_STREAM_END;
@@ -766,7 +770,7 @@ local void inflate_blocks_reset(
   s->read = s->write = s->window;
   if (s->checkfn != Z_NULL)
     s->check = (*s->checkfn)(0L, Z_NULL, 0);
-  Trace((stderr, "inflate:   blocks reset\n"));
+  Trace(("inflate:   blocks reset\n"));
 }
 
 
@@ -789,7 +793,7 @@ local inflate_blocks_statef *inflate_blo
   s->end = s->window + w;
   s->checkfn = c;
   s->mode = TYPE;
-  Trace((stderr, "inflate:   blocks allocated\n"));
+  Trace(("inflate:   blocks allocated\n"));
   inflate_blocks_reset(s, z, &s->check);
   return s;
 }
@@ -822,7 +826,7 @@ local int inflate_blocks(
       switch (t >> 1)
       {
         case 0:                         /* stored */
-          Trace((stderr, "inflate:     stored block%s\n",
+          Trace(("inflate:     stored block%s\n",
                  s->last ? " (last)" : ""));
           DUMPBITS(3)
           t = k & 7;                    /* go to byte boundary */
@@ -830,7 +834,7 @@ local int inflate_blocks(
           s->mode = LENS;               /* get length of stored block */
           break;
         case 1:                         /* fixed */
-          Trace((stderr, "inflate:     fixed codes block%s\n",
+          Trace(("inflate:     fixed codes block%s\n",
                  s->last ? " (last)" : ""));
           {
             uInt bl, bd;
@@ -850,7 +854,7 @@ local int inflate_blocks(
           s->mode = CODES;
           break;
         case 2:                         /* dynamic */
-          Trace((stderr, "inflate:     dynamic codes block%s\n",
+          Trace(("inflate:     dynamic codes block%s\n",
                  s->last ? " (last)" : ""));
           DUMPBITS(3)
           s->mode = TABLE;
@@ -874,7 +878,7 @@ local int inflate_blocks(
       }
       s->sub.left = (uInt)b & 0xffff;
       b = k = 0;                      /* dump bits */
-      Tracev((stderr, "inflate:       stored length %u\n", s->sub.left));
+      Tracev(("inflate:       stored length %u\n", s->sub.left));
       s->mode = s->sub.left ? STORED : TYPE;
       break;
     case STORED:
@@ -889,7 +893,7 @@ local int inflate_blocks(
       q += t;  m -= t;
       if ((s->sub.left -= t) != 0)
         break;
-      Tracev((stderr, "inflate:       stored end, %lu total out\n",
+      Tracev(("inflate:       stored end, %lu total out\n",
               z->total_out + (q >= s->read ? q - s->read :
               (s->end - s->read) + (q - s->window))));
       s->mode = s->last ? DRY : TYPE;
@@ -917,7 +921,7 @@ local int inflate_blocks(
       s->sub.trees.nblens = t;
       DUMPBITS(14)
       s->sub.trees.index = 0;
-      Tracev((stderr, "inflate:       table sizes ok\n"));
+      Tracev(("inflate:       table sizes ok\n"));
       s->mode = BTREE;
     case BTREE:
       while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
@@ -939,7 +943,7 @@ local int inflate_blocks(
         LEAVE
       }
       s->sub.trees.index = 0;
-      Tracev((stderr, "inflate:       bits tree ok\n"));
+      Tracev(("inflate:       bits tree ok\n"));
       s->mode = DTREE;
     case DTREE:
       while (t = s->sub.trees.table,
@@ -1002,7 +1006,7 @@ local int inflate_blocks(
           r = t;
           LEAVE
         }
-        Tracev((stderr, "inflate:       trees ok\n"));
+        Tracev(("inflate:       trees ok\n"));
         if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
         {
           inflate_trees_free(td, z);
@@ -1025,7 +1029,7 @@ local int inflate_blocks(
       inflate_trees_free(s->sub.decode.td, z);
       inflate_trees_free(s->sub.decode.tl, z);
       LOAD
-      Tracev((stderr, "inflate:       codes end, %lu total out\n",
+      Tracev(("inflate:       codes end, %lu total out\n",
               z->total_out + (q >= s->read ? q - s->read :
               (s->end - s->read) + (q - s->window))));
       if (!s->last)
@@ -1068,7 +1072,7 @@ local int inflate_blocks_free(
   inflate_blocks_reset(s, z, c);
   ZFREE(z, s->window, s->end - s->window);
   ZFREE(z, s, sizeof(struct inflate_blocks_state));
-  Trace((stderr, "inflate:   blocks freed\n"));
+  Trace(("inflate:   blocks freed\n"));
   return Z_OK;
 }
 
@@ -1230,7 +1234,7 @@ local uInt cpdext[] = { /* Extra bits fo
 #define N_MAX 288       /* maximum number of codes in any set */
 
 #ifdef DEBUG_ZLIB
-  uInt inflate_hufts;
+  local uInt inflate_hufts;
 #endif
 
 local int huft_build(
@@ -1687,7 +1691,7 @@ local inflate_codes_statef *inflate_code
     c->dbits = (Byte)bd;
     c->ltree = tl;
     c->dtree = td;
-    Tracev((stderr, "inflate:       codes new\n"));
+    Tracev(("inflate:       codes new\n"));
   }
   return c;
 }
@@ -1743,7 +1747,7 @@ local int inflate_codes(
       if (e == 0)               /* literal */
       {
         c->sub.lit = t->base;
-        Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+        Tracevv((t->base >= 0x20 && t->base < 0x7f ?
                  "inflate:         literal '%c'\n" :
                  "inflate:         literal 0x%02x\n", t->base));
         c->mode = LIT;
@@ -1764,7 +1768,7 @@ local int inflate_codes(
       }
       if (e & 32)               /* end of block */
       {
-        Tracevv((stderr, "inflate:         end of block\n"));
+        Tracevv(("inflate:         end of block\n"));
         c->mode = WASH;
         break;
       }
@@ -1779,7 +1783,7 @@ local int inflate_codes(
       DUMPBITS(j)
       c->sub.code.need = c->dbits;
       c->sub.code.tree = c->dtree;
-      Tracevv((stderr, "inflate:         length %u\n", c->len));
+      Tracevv(("inflate:         length %u\n", c->len));
       c->mode = DIST;
     case DIST:          /* i: get distance next */
       j = c->sub.code.need;
@@ -1809,7 +1813,7 @@ local int inflate_codes(
       NEEDBITS(j)
       c->sub.copy.dist += (uInt)b & inflate_mask[j];
       DUMPBITS(j)
-      Tracevv((stderr, "inflate:         distance %u\n", c->sub.copy.dist));
+      Tracevv(("inflate:         distance %u\n", c->sub.copy.dist));
       c->mode = COPY;
     case COPY:          /* o: copying bytes in window, waiting for space */
 #ifndef __TURBOC__ /* Turbo C bug for following expression */
@@ -1860,7 +1864,7 @@ local void inflate_codes_free(
 )
 {
   ZFREE(z, c, sizeof(struct inflate_codes_state));
-  Tracev((stderr, "inflate:       codes free\n"));
+  Tracev(("inflate:       codes free\n"));
 }
 
 /*+++++*/
@@ -1995,7 +1999,7 @@ local int inflate_fast(
     if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
     {
       DUMPBITS(t->bits)
-      Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+      Tracevv((t->base >= 0x20 && t->base < 0x7f ?
                 "inflate:         * literal '%c'\n" :
                 "inflate:         * literal 0x%02x\n", t->base));
       *q++ = (Byte)t->base;
@@ -2010,7 +2014,7 @@ local int inflate_fast(
         e &= 15;
         c = t->base + ((uInt)b & inflate_mask[e]);
         DUMPBITS(e)
-        Tracevv((stderr, "inflate:         * length %u\n", c));
+        Tracevv(("inflate:         * length %u\n", c));
 
         /* decode distance base of block to copy */
         GRABBITS(15);           /* max bits for distance code */
@@ -2024,7 +2028,7 @@ local int inflate_fast(
             GRABBITS(e)         /* get extra bits (up to 13) */
             d = t->base + ((uInt)b & inflate_mask[e]);
             DUMPBITS(e)
-            Tracevv((stderr, "inflate:         * distance %u\n", d));
+            Tracevv(("inflate:         * distance %u\n", d));
 
             /* do the copy */
             m -= c;
@@ -2069,7 +2073,7 @@ local int inflate_fast(
         if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0)
         {
           DUMPBITS(t->bits)
-          Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+          Tracevv((t->base >= 0x20 && t->base < 0x7f ?
                     "inflate:         * literal '%c'\n" :
                     "inflate:         * literal 0x%02x\n", t->base));
           *q++ = (Byte)t->base;
@@ -2079,7 +2083,7 @@ local int inflate_fast(
       }
       else if (e & 32)
       {
-        Tracevv((stderr, "inflate:         * end of block\n"));
+        Tracevv(("inflate:         * end of block\n"));
         UNGRAB
         UPDATE
         return Z_STREAM_END;
--- diff/arch/ppc/boot/openfirmware/Makefile	2003-09-17 11:28:02.000000000 +0000
+++ source/arch/ppc/boot/openfirmware/Makefile	2004-03-16 09:37:55.432113208 +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/misc.S	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ppc/kernel/misc.S	2004-03-16 09:37:55.433113056 +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-16 09:37:55.434112904 +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-11 10:20:22.000000000 +0000
+++ source/arch/ppc/kernel/smp.c	2004-03-16 09:37:55.434112904 +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 10:49:59.000000000 +0000
+++ source/arch/ppc/platforms/chrp_smp.c	2004-03-16 09:37:55.434112904 +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_feature.c	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/ppc/platforms/pmac_feature.c	2004-03-16 09:37:55.436112600 +0000
@@ -1360,7 +1360,7 @@ g5_fw_enable(struct device_node* node, l
 		mb();
 		k2_skiplist[1] = NULL;
 	} else {
-		k2_skiplist[0] = pdev;
+		k2_skiplist[1] = pdev;
 		mb();
 		MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);
 	}
--- diff/arch/ppc/platforms/pmac_smp.c	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/ppc/platforms/pmac_smp.c	2004-03-16 09:37:55.437112448 +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/ppc/platforms/proc_rtas.c	2003-09-30 14:46:12.000000000 +0000
+++ source/arch/ppc/platforms/proc_rtas.c	2004-03-16 09:37:55.438112296 +0000
@@ -20,6 +20,7 @@
 #include <linux/ctype.h>
 #include <linux/time.h>
 #include <linux/string.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
@@ -194,18 +195,18 @@ int check_location (char *c, int idx, ch
 /* ****************************************************************** */
 /* MAIN                                                               */
 /* ****************************************************************** */
-void proc_rtas_init(void)
+static int __init proc_rtas_init(void)
 {
 	struct proc_dir_entry *entry;
 
 	rtas = find_devices("rtas");
 	if ((rtas == 0) || (_machine != _MACH_chrp)) {
-		return;
+		return 1;
 	}
 
 	proc_rtas = proc_mkdir("rtas", 0);
 	if (proc_rtas == 0)
-		return;
+		return 1;
 
 	/* /proc/rtas entries */
 
@@ -226,7 +227,10 @@ void proc_rtas_init(void)
 
 	entry = create_proc_entry("volume", S_IWUSR|S_IRUGO, proc_rtas);
 	if (entry) entry->proc_fops = &ppc_rtas_tone_volume_operations;
+
+	return 0;
 }
+__initcall(proc_rtas_init);
 
 /* ****************************************************************** */
 /* POWER-ON-TIME                                                      */
--- diff/arch/ppc64/Kconfig	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/Kconfig	2004-03-16 09:37:55.438112296 +0000
@@ -173,6 +173,16 @@ config NUMA
 	bool "NUMA support"
 	depends on DISCONTIGMEM
 
+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
 	help
--- diff/arch/ppc64/Makefile	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/Makefile	2004-03-16 09:37:55.438112296 +0000
@@ -53,7 +53,7 @@ $(boottarget-y): vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
 
 bootimage-$(CONFIG_PPC_PSERIES) := zImage
-bootimage-$(CONFIG_PPC_ISERIES) := vmlinux.sm
+bootimage-$(CONFIG_PPC_ISERIES) := vmlinux
 BOOTIMAGE := $(bootimage-y)
 install: vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) $@
--- diff/arch/ppc64/configs/iSeries_defconfig	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/configs/iSeries_defconfig	2004-03-16 09:37:55.440111992 +0000
@@ -47,6 +47,7 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_KMOD is not set
+CONFIG_STOP_MACHINE=y
 
 #
 # Platform support
@@ -56,6 +57,7 @@ CONFIG_PPC_ISERIES=y
 CONFIG_PPC=y
 CONFIG_PPC64=y
 # CONFIG_POWER4_ONLY is not set
+# CONFIG_IOMMU_VMERGE is not set
 CONFIG_SMP=y
 CONFIG_NR_CPUS=32
 CONFIG_MSCHUNKS=y
@@ -89,6 +91,7 @@ CONFIG_PCI_NAMES=y
 # Generic Driver Options
 #
 CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -115,10 +118,10 @@ CONFIG_FW_LOADER=m
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_CARMEL is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_DCSSBLK is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -150,6 +153,12 @@ CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
 
 #
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=y
+CONFIG_SCSI_FC_ATTRS=y
+
+#
 # SCSI low-level drivers
 #
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
@@ -197,7 +206,6 @@ CONFIG_MD_RAID5=y
 CONFIG_MD_RAID6=y
 # CONFIG_MD_MULTIPATH is not set
 CONFIG_BLK_DEV_DM=y
-CONFIG_DM_IOCTL_V4=y
 CONFIG_DM_CRYPT=m
 
 #
@@ -437,6 +445,7 @@ CONFIG_IBMOL=y
 # CONFIG_TMS380TR is not set
 # CONFIG_NET_FC is not set
 # CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=y
 
 #
 # Wan interfaces
@@ -457,6 +466,10 @@ CONFIG_IBMOL=y
 # Bluetooth support
 #
 # CONFIG_BT is not set
+CONFIG_NETPOLL=y
+CONFIG_NETPOLL_RX=y
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
 
 #
 # ISDN subsystem
@@ -535,7 +548,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
@@ -556,6 +568,10 @@ CONFIG_MAX_RAW_DEVS=256
 # CONFIG_I2C is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -742,7 +758,6 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_VIOCONS=y
 CONFIG_VIODASD=y
 CONFIG_VIOCD=y
-# CONFIG_VIOCD_AZTECH is not set
 # CONFIG_VIOTAPE is not set
 CONFIG_VIOPATH=y
 
@@ -787,6 +802,7 @@ CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_AES=m
 CONFIG_CRYPTO_CAST5=m
 CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_DEFLATE=m
 CONFIG_CRYPTO_TEST=m
 
--- diff/arch/ppc64/configs/pSeries_defconfig	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/configs/pSeries_defconfig	2004-03-16 09:37:55.441111840 +0000
@@ -47,6 +47,7 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_KMOD is not set
+CONFIG_STOP_MACHINE=y
 
 #
 # Platform support
@@ -60,6 +61,7 @@ CONFIG_ALTIVEC=y
 # CONFIG_PPC_PMAC is not set
 # CONFIG_BOOTX_TEXT is not set
 # CONFIG_POWER4_ONLY is not set
+# CONFIG_IOMMU_VMERGE is not set
 CONFIG_SMP=y
 CONFIG_IRQ_ALL_CPUS=y
 CONFIG_NR_CPUS=32
@@ -106,6 +108,7 @@ CONFIG_PROC_DEVICETREE=y
 # Generic Driver Options
 #
 CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -132,10 +135,10 @@ CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_CARMEL is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_DCSSBLK is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -173,7 +176,7 @@ CONFIG_IDEDMA_PCI_AUTO=y
 CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
+CONFIG_BLK_DEV_AMD74XX=y
 # CONFIG_BLK_DEV_CMD64X is not set
 # CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
@@ -222,6 +225,12 @@ CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
 
 #
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=y
+CONFIG_SCSI_FC_ATTRS=y
+
+#
 # SCSI low-level drivers
 #
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
@@ -273,7 +282,6 @@ CONFIG_MD_RAID5=y
 CONFIG_MD_RAID6=y
 # CONFIG_MD_MULTIPATH is not set
 CONFIG_BLK_DEV_DM=y
-CONFIG_DM_IOCTL_V4=y
 CONFIG_DM_CRYPT=m
 
 #
@@ -515,6 +523,7 @@ CONFIG_IBMOL=y
 # CONFIG_TMS380TR is not set
 # CONFIG_NET_FC is not set
 # CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=y
 
 #
 # Wan interfaces
@@ -535,6 +544,10 @@ CONFIG_IBMOL=y
 # Bluetooth support
 #
 # CONFIG_BT is not set
+CONFIG_NETPOLL=y
+CONFIG_NETPOLL_RX=y
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
 
 #
 # ISDN subsystem
@@ -633,7 +646,6 @@ CONFIG_HVC_CONSOLE=y
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
@@ -707,6 +719,10 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -720,6 +736,7 @@ CONFIG_I2C_ALGOBIT=y
 # Graphics support
 #
 CONFIG_FB=y
+# CONFIG_FB_PM2 is not set
 # CONFIG_FB_CYBER2000 is not set
 CONFIG_FB_OF=y
 # CONFIG_FB_CT65550 is not set
@@ -776,7 +793,7 @@ CONFIG_LOGO_LINUX_CLUT224=y
 #
 # USB support
 #
-CONFIG_USB=m
+CONFIG_USB=y
 # CONFIG_USB_DEBUG is not set
 
 #
@@ -789,8 +806,8 @@ CONFIG_USB_DEVICEFS=y
 #
 # USB Host Controller Drivers
 #
-CONFIG_USB_EHCI_HCD=m
-CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_UHCI_HCD is not set
 
 #
@@ -799,7 +816,7 @@ CONFIG_USB_OHCI_HCD=m
 # CONFIG_USB_BLUETOOTH_TTY is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
-CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
@@ -813,16 +830,10 @@ CONFIG_USB_STORAGE=m
 #
 # USB Human Interface Devices (HID)
 #
-CONFIG_USB_HID=m
+CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
 # CONFIG_HID_FF is not set
 CONFIG_USB_HIDDEV=y
-
-#
-# USB HID Boot Protocol drivers
-#
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
 # CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
 # CONFIG_USB_KBTAB is not set
@@ -1076,6 +1087,7 @@ CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_AES=m
 CONFIG_CRYPTO_CAST5=m
 CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_DEFLATE=m
 CONFIG_CRYPTO_TEST=m
 
--- diff/arch/ppc64/defconfig	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/defconfig	2004-03-16 09:37:55.442111688 +0000
@@ -47,6 +47,7 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_KMOD is not set
+CONFIG_STOP_MACHINE=y
 
 #
 # Platform support
@@ -60,6 +61,7 @@ CONFIG_ALTIVEC=y
 # CONFIG_PPC_PMAC is not set
 # CONFIG_BOOTX_TEXT is not set
 # CONFIG_POWER4_ONLY is not set
+# CONFIG_IOMMU_VMERGE is not set
 CONFIG_SMP=y
 CONFIG_IRQ_ALL_CPUS=y
 CONFIG_NR_CPUS=32
@@ -106,6 +108,7 @@ CONFIG_PROC_DEVICETREE=y
 # Generic Driver Options
 #
 CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -132,10 +135,10 @@ CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_CARMEL is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_DCSSBLK is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -173,7 +176,7 @@ CONFIG_IDEDMA_PCI_AUTO=y
 CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
+CONFIG_BLK_DEV_AMD74XX=y
 # CONFIG_BLK_DEV_CMD64X is not set
 # CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
@@ -222,6 +225,12 @@ CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
 
 #
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=y
+CONFIG_SCSI_FC_ATTRS=y
+
+#
 # SCSI low-level drivers
 #
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
@@ -273,7 +282,6 @@ CONFIG_MD_RAID5=y
 CONFIG_MD_RAID6=y
 # CONFIG_MD_MULTIPATH is not set
 CONFIG_BLK_DEV_DM=y
-CONFIG_DM_IOCTL_V4=y
 CONFIG_DM_CRYPT=m
 
 #
@@ -515,6 +523,7 @@ CONFIG_IBMOL=y
 # CONFIG_TMS380TR is not set
 # CONFIG_NET_FC is not set
 # CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=y
 
 #
 # Wan interfaces
@@ -535,6 +544,10 @@ CONFIG_IBMOL=y
 # Bluetooth support
 #
 # CONFIG_BT is not set
+CONFIG_NETPOLL=y
+CONFIG_NETPOLL_RX=y
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
 
 #
 # ISDN subsystem
@@ -633,7 +646,6 @@ CONFIG_HVC_CONSOLE=y
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
@@ -707,6 +719,10 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -720,6 +736,7 @@ CONFIG_I2C_ALGOBIT=y
 # Graphics support
 #
 CONFIG_FB=y
+# CONFIG_FB_PM2 is not set
 # CONFIG_FB_CYBER2000 is not set
 CONFIG_FB_OF=y
 # CONFIG_FB_CT65550 is not set
@@ -776,7 +793,7 @@ CONFIG_LOGO_LINUX_CLUT224=y
 #
 # USB support
 #
-CONFIG_USB=m
+CONFIG_USB=y
 # CONFIG_USB_DEBUG is not set
 
 #
@@ -789,8 +806,8 @@ CONFIG_USB_DEVICEFS=y
 #
 # USB Host Controller Drivers
 #
-CONFIG_USB_EHCI_HCD=m
-CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_UHCI_HCD is not set
 
 #
@@ -799,7 +816,7 @@ CONFIG_USB_OHCI_HCD=m
 # CONFIG_USB_BLUETOOTH_TTY is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
-CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
@@ -813,16 +830,10 @@ CONFIG_USB_STORAGE=m
 #
 # USB Human Interface Devices (HID)
 #
-CONFIG_USB_HID=m
+CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
 # CONFIG_HID_FF is not set
 CONFIG_USB_HIDDEV=y
-
-#
-# USB HID Boot Protocol drivers
-#
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
 # CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
 # CONFIG_USB_KBTAB is not set
@@ -1076,6 +1087,7 @@ CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_AES=m
 CONFIG_CRYPTO_CAST5=m
 CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_DEFLATE=m
 CONFIG_CRYPTO_TEST=m
 
--- diff/arch/ppc64/kernel/HvLpConfig.c	2002-10-16 03:27:53.000000000 +0000
+++ source/arch/ppc64/kernel/HvLpConfig.c	2004-03-16 09:37:55.442111688 +0000
@@ -17,12 +17,11 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#ifndef _HVLPCONFIG_H
+#include <linux/module.h>
 #include <asm/iSeries/HvLpConfig.h>
-#endif
 
 HvLpIndex HvLpConfig_getLpIndex_outline(void)
 {
 	return HvLpConfig_getLpIndex();
 }
-
+EXPORT_SYMBOL(HvLpConfig_getLpIndex_outline);
--- diff/arch/ppc64/kernel/Makefile	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/Makefile	2004-03-16 09:37:55.443111536 +0000
@@ -5,11 +5,11 @@
 EXTRA_CFLAGS	+= -mno-minimal-toc
 extra-y		:= head.o vmlinux.lds.s
 
-obj-y               :=	setup.o entry.o traps.o irq.o idle.o \
+obj-y               :=	setup.o entry.o traps.o irq.o idle.o dma.o \
 			time.o process.o signal.o syscalls.o misc.o ptrace.o \
 			align.o semaphore.o bitops.o stab.o pacaData.o \
 			udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \
-			ptrace32.o signal32.o pmc.o rtc.o init_task.o \
+			ptrace32.o signal32.o rtc.o init_task.o \
 			lmb.o cputable.o cpu_setup_power4.o idle_power4.o \
 			iommu.o
 
@@ -29,7 +29,7 @@ obj-$(CONFIG_PPC_ISERIES) += iSeries_irq
 			     HvCall.o HvLpConfig.o LparData.o mf_proc.o \
 			     iSeries_setup.o ItLpQueue.o hvCall.o \
 			     mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \
-			     proc_pmc.o iSeries_iommu.o
+			     iSeries_iommu.o
 
 obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \
 			     eeh.o nvram.o pSeries_nvram.o rtasd.o ras.o \
--- diff/arch/ppc64/kernel/bitops.c	2002-10-16 03:28:27.000000000 +0000
+++ source/arch/ppc64/kernel/bitops.c	2004-03-16 09:37:55.444111384 +0000
@@ -3,6 +3,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <asm/bitops.h>
 #include <asm/byteorder.h>
 
@@ -44,8 +45,10 @@ found_first:
 found_middle:
 	return result + ffz(tmp);
 }
+EXPORT_SYMBOL(find_next_zero_bit);
 
-unsigned long find_next_bit(unsigned long *addr, unsigned long size, unsigned long offset)
+unsigned long find_next_bit(unsigned long *addr, unsigned long size,
+			    unsigned long offset)
 {
 	unsigned long *p = addr + (offset >> 6);
 	unsigned long result = offset & ~63UL;
@@ -82,8 +85,9 @@ found_first:
 found_middle:
 	return result + __ffs(tmp);
 }
+EXPORT_SYMBOL(find_next_bit);
 
-static __inline__ unsigned int ext2_ilog2(unsigned int x) 
+static inline unsigned int ext2_ilog2(unsigned int x)
 {
 	int lz;
 
@@ -91,16 +95,17 @@ static __inline__ unsigned int ext2_ilog
 	return 31 - lz;
 }
 
-static __inline__ unsigned int ext2_ffz(unsigned int x)
+static inline unsigned int ext2_ffz(unsigned int x)
 {
-	u32  tempRC;
+	u32 rc;
 	if ((x = ~x) == 0)
 		return 32;
-	tempRC = ext2_ilog2(x & -x);
-	return tempRC;
+	rc = ext2_ilog2(x & -x);
+	return rc;
 }
 
-unsigned long find_next_zero_le_bit(unsigned long *addr, unsigned long size, unsigned long offset)
+unsigned long find_next_zero_le_bit(unsigned long *addr, unsigned long size,
+				    unsigned long offset)
 {
         unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
         unsigned int result = offset & ~31;
@@ -136,3 +141,4 @@ found_first:
 found_middle:
         return result + ext2_ffz(tmp);
 }
+EXPORT_SYMBOL(find_next_zero_le_bit);
--- diff/arch/ppc64/kernel/eeh.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/eeh.c	2004-03-16 09:37:55.447110928 +0000
@@ -17,63 +17,348 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-/* Change Activity:
- * 2001/10/27 : engebret : Created.
- * End Change Activity 
- */
-
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/bootmem.h>
 #include <linux/mm.h>
+#include <linux/rbtree.h>
+#include <linux/spinlock.h>
+#include <linux/seq_file.h>
 #include <asm/paca.h>
 #include <asm/processor.h>
 #include <asm/naca.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
+#include <asm/pgtable.h>
 #include "pci.h"
 
+#undef DEBUG
+
 #define BUID_HI(buid) ((buid) >> 32)
 #define BUID_LO(buid) ((buid) & 0xffffffff)
-#define CONFIG_ADDR(busno, devfn) (((((busno) & 0xff) << 8) | ((devfn) & 0xf8)) << 8)
+#define CONFIG_ADDR(busno, devfn) \
+		(((((busno) & 0xff) << 8) | ((devfn) & 0xf8)) << 8)
 
-unsigned long eeh_total_mmio_ffs;
-unsigned long eeh_false_positives;
 /* RTAS tokens */
 static int ibm_set_eeh_option;
 static int ibm_set_slot_reset;
 static int ibm_read_slot_reset_state;
 
-static int eeh_implemented;
+static int eeh_subsystem_enabled;
 #define EEH_MAX_OPTS 4096
 static char *eeh_opts;
 static int eeh_opts_last;
 
-unsigned char	slot_err_buf[RTAS_ERROR_LOG_MAX];
+/* System monitoring statistics */
+static DEFINE_PER_CPU(unsigned long, total_mmio_ffs);
+static DEFINE_PER_CPU(unsigned long, false_positives);
+static DEFINE_PER_CPU(unsigned long, ignored_failures);
 
-pte_t *find_linux_pte(pgd_t *pgdir, unsigned long va);	/* from htab.c */
-static int eeh_check_opts_config(struct device_node *dn,
-				 int class_code, int vendor_id, int device_id,
+static int eeh_check_opts_config(struct device_node *dn, int class_code,
+				 int vendor_id, int device_id,
 				 int default_state);
 
-unsigned long eeh_token_to_phys(unsigned long token)
+/**
+ * The pci address cache subsystem.  This subsystem places
+ * PCI device address resources into a red-black tree, sorted
+ * according to the address range, so that given only an i/o
+ * address, the corresponding PCI device can be **quickly**
+ * found.
+ *
+ * Currently, the only customer of this code is the EEH subsystem;
+ * thus, this code has been somewhat tailored to suit EEH better.
+ * In particular, the cache does *not* hold the addresses of devices
+ * for which EEH is not enabled.
+ *
+ * (Implementation Note: The RB tree seems to be better/faster
+ * than any hash algo I could think of for this problem, even
+ * with the penalty of slow pointer chases for d-cache misses).
+ */
+struct pci_io_addr_range
+{
+	struct rb_node rb_node;
+	unsigned long addr_lo;
+	unsigned long addr_hi;
+	struct pci_dev *pcidev;
+	unsigned int flags;
+};
+
+static struct pci_io_addr_cache
+{
+	struct rb_root rb_root;
+	spinlock_t piar_lock;
+} pci_io_addr_cache_root;
+
+static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr)
+{
+	struct rb_node *n = pci_io_addr_cache_root.rb_root.rb_node;
+
+	while (n) {
+		struct pci_io_addr_range *piar;
+		piar = rb_entry(n, struct pci_io_addr_range, rb_node);
+
+		if (addr < piar->addr_lo) {
+			n = n->rb_left;
+		} else {
+			if (addr > piar->addr_hi) {
+				n = n->rb_right;
+			} else {
+				pci_dev_get(piar->pcidev);
+				return piar->pcidev;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * pci_get_device_by_addr - Get device, given only address
+ * @addr: mmio (PIO) phys address or i/o port number
+ *
+ * Given an mmio phys address, or a port number, find a pci device
+ * that implements this address.  Be sure to pci_dev_put the device
+ * when finished.  I/O port numbers are assumed to be offset
+ * from zero (that is, they do *not* have pci_io_addr added in).
+ * It is safe to call this function within an interrupt.
+ */
+static struct pci_dev *pci_get_device_by_addr(unsigned long addr)
+{
+	struct pci_dev *dev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags);
+	dev = __pci_get_device_by_addr(addr);
+	spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags);
+	return dev;
+}
+
+#ifdef DEBUG
+/*
+ * Handy-dandy debug print routine, does nothing more
+ * than print out the contents of our addr cache.
+ */
+static void pci_addr_cache_print(struct pci_io_addr_cache *cache)
+{
+	struct rb_node *n;
+	int cnt = 0;
+
+	n = rb_first(&cache->rb_root);
+	while (n) {
+		struct pci_io_addr_range *piar;
+		piar = rb_entry(n, struct pci_io_addr_range, rb_node);
+		printk(KERN_DEBUG "PCI: %s addr range %d [%lx-%lx]: %s %s\n",
+		       (piar->flags & IORESOURCE_IO) ? "i/o" : "mem", cnt,
+		       piar->addr_lo, piar->addr_hi, pci_name(piar->pcidev),
+		       pci_pretty_name(piar->pcidev));
+		cnt++;
+		n = rb_next(n);
+	}
+}
+#endif
+
+/* Insert address range into the rb tree. */
+static struct pci_io_addr_range *
+pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo,
+		      unsigned long ahi, unsigned int flags)
+{
+	struct rb_node **p = &pci_io_addr_cache_root.rb_root.rb_node;
+	struct rb_node *parent = NULL;
+	struct pci_io_addr_range *piar;
+
+	/* Walk tree, find a place to insert into tree */
+	while (*p) {
+		parent = *p;
+		piar = rb_entry(parent, struct pci_io_addr_range, rb_node);
+		if (alo < piar->addr_lo) {
+			p = &parent->rb_left;
+		} else if (ahi > piar->addr_hi) {
+			p = &parent->rb_right;
+		} else {
+			if (dev != piar->pcidev ||
+			    alo != piar->addr_lo || ahi != piar->addr_hi) {
+				printk(KERN_WARNING "PIAR: overlapping address range\n");
+			}
+			return piar;
+		}
+	}
+	piar = (struct pci_io_addr_range *)kmalloc(sizeof(struct pci_io_addr_range), GFP_ATOMIC);
+	if (!piar)
+		return NULL;
+
+	piar->addr_lo = alo;
+	piar->addr_hi = ahi;
+	piar->pcidev = dev;
+	piar->flags = flags;
+
+	rb_link_node(&piar->rb_node, parent, p);
+	rb_insert_color(&piar->rb_node, &pci_io_addr_cache_root.rb_root);
+
+	return piar;
+}
+
+static void __pci_addr_cache_insert_device(struct pci_dev *dev)
+{
+	struct device_node *dn;
+	int i;
+
+	dn = pci_device_to_OF_node(dev);
+	if (!dn) {
+		printk(KERN_WARNING "PCI: no pci dn found for dev=%s %s\n",
+			pci_name(dev), pci_pretty_name(dev));
+		pci_dev_put(dev);
+		return;
+	}
+
+	/* Skip any devices for which EEH is not enabled. */
+	if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) ||
+	    dn->eeh_mode & EEH_MODE_NOCHECK) {
+#ifdef DEBUG
+		printk(KERN_INFO "PCI: skip building address cache for=%s %s\n",
+		       pci_name(dev), pci_pretty_name(dev));
+#endif
+		pci_dev_put(dev);
+		return;
+	}
+
+	/* Walk resources on this device, poke them into the tree */
+	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+		unsigned long start = pci_resource_start(dev,i);
+		unsigned long end = pci_resource_end(dev,i);
+		unsigned int flags = pci_resource_flags(dev,i);
+
+		/* We are interested only bus addresses, not dma or other stuff */
+		if (0 == (flags & (IORESOURCE_IO | IORESOURCE_MEM)))
+			continue;
+		if (start == 0 || ~start == 0 || end == 0 || ~end == 0)
+			 continue;
+		pci_addr_cache_insert(dev, start, end, flags);
+	}
+}
+
+/**
+ * pci_addr_cache_insert_device - Add a device to the address cache
+ * @dev: PCI device whose I/O addresses we are interested in.
+ *
+ * In order to support the fast lookup of devices based on addresses,
+ * we maintain a cache of devices that can be quickly searched.
+ * This routine adds a device to that cache.
+ */
+void pci_addr_cache_insert_device(struct pci_dev *dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags);
+	__pci_addr_cache_insert_device(dev);
+	spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags);
+}
+
+static inline void __pci_addr_cache_remove_device(struct pci_dev *dev)
+{
+	struct rb_node *n;
+
+restart:
+	n = rb_first(&pci_io_addr_cache_root.rb_root);
+	while (n) {
+		struct pci_io_addr_range *piar;
+		piar = rb_entry(n, struct pci_io_addr_range, rb_node);
+
+		if (piar->pcidev == dev) {
+			rb_erase(n, &pci_io_addr_cache_root.rb_root);
+			kfree(piar);
+			goto restart;
+		}
+		n = rb_next(n);
+	}
+	pci_dev_put(dev);
+}
+
+/**
+ * pci_addr_cache_remove_device - remove pci device from addr cache
+ * @dev: device to remove
+ *
+ * Remove a device from the addr-cache tree.
+ * This is potentially expensive, since it will walk
+ * the tree multiple times (once per resource).
+ * But so what; device removal doesn't need to be that fast.
+ */
+void pci_addr_cache_remove_device(struct pci_dev *dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags);
+	__pci_addr_cache_remove_device(dev);
+	spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags);
+}
+
+/**
+ * pci_addr_cache_build - Build a cache of I/O addresses
+ *
+ * Build a cache of pci i/o addresses.  This cache will be used to
+ * find the pci device that corresponds to a given address.
+ * This routine scans all pci busses to build the cache.
+ * Must be run late in boot process, after the pci controllers
+ * have been scaned for devices (after all device resources are known).
+ */
+void __init pci_addr_cache_build(void)
+{
+	struct pci_dev *dev = NULL;
+
+	spin_lock_init(&pci_io_addr_cache_root.piar_lock);
+
+	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+		/* Ignore PCI bridges ( XXX why ??) */
+		if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) {
+			pci_dev_put(dev);
+			continue;
+		}
+		pci_addr_cache_insert_device(dev);
+	}
+
+#ifdef DEBUG
+	/* Verify tree built up above, echo back the list of addrs. */
+	pci_addr_cache_print(&pci_io_addr_cache_root);
+#endif
+}
+
+/**
+ * eeh_token_to_phys - convert EEH address token to phys address
+ * @token i/o token, should be address in the form 0xA....
+ *
+ * Converts EEH address tokens into physical addresses.  Note that
+ * ths routine does *not* convert I/O BAR addresses (which start
+ * with 0xE...) to phys addresses!
+ */
+static unsigned long eeh_token_to_phys(unsigned long token)
 {
-	if (REGION_ID(token) == EEH_REGION_ID) {
-		unsigned long vaddr = IO_TOKEN_TO_ADDR(token);
-		pte_t *ptep = find_linux_pte(ioremap_mm.pgd, vaddr);
-		unsigned long pa = pte_pfn(*ptep) << PAGE_SHIFT;
-		return pa | (vaddr & (PAGE_SIZE-1));
-	} else
+	pte_t *ptep;
+	unsigned long pa, vaddr;
+
+	if (REGION_ID(token) == EEH_REGION_ID)
+		vaddr = IO_TOKEN_TO_ADDR(token);
+	else
 		return token;
+
+	ptep = find_linux_pte(ioremap_mm.pgd, vaddr);
+	pa = pte_pfn(*ptep) << PAGE_SHIFT;
+
+	return pa | (vaddr & (PAGE_SIZE-1));
 }
 
-/* Check for an eeh failure at the given token address.
+/**
+ * eeh_check_failure - check if all 1's data is due to EEH slot freeze
+ * @token i/o token, should be address in the form 0xA....
+ * @val value, should be all 1's (XXX why do we need this arg??)
+ *
+ * Check for an eeh failure at the given token address.
  * The given value has been read and it should be 1's (0xff, 0xffff or
  * 0xffffffff).
  *
  * Probe to determine if an error actually occurred.  If not return val.
  * Otherwise panic.
+ *
+ * Note this routine might be called in an interrupt context ...
  */
 unsigned long eeh_check_failure(void *token, unsigned long val)
 {
@@ -81,81 +366,97 @@ unsigned long eeh_check_failure(void *to
 	struct pci_dev *dev;
 	struct device_node *dn;
 	unsigned long ret, rets[2];
+	static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+	/* dont want this on the stack */
+	static unsigned char slot_err_buf[RTAS_ERROR_LOG_MAX];
+	unsigned long flags;
 
-	/* IO BAR access could get us here...or if we manually force EEH
-	 * operation on even if the hardware won't support it.
-	 */
-	if (!eeh_implemented || ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE)
+	__get_cpu_var(total_mmio_ffs)++;
+
+	if (!eeh_subsystem_enabled)
 		return val;
 
-	/* Finding the phys addr + pci device is quite expensive.
-	 * However, the RTAS call is MUCH slower.... :(
-	 */
+	/* Finding the phys addr + pci device; this is pretty quick. */
 	addr = eeh_token_to_phys((unsigned long)token);
-	dev = pci_find_dev_by_addr(addr);
-	if (!dev) {
-		printk("EEH: no pci dev found for addr=0x%lx\n", addr);
+	dev = pci_get_device_by_addr(addr);
+	if (!dev)
 		return val;
-	}
+
 	dn = pci_device_to_OF_node(dev);
 	if (!dn) {
-		printk("EEH: no pci dn found for addr=0x%lx\n", addr);
+		pci_dev_put(dev);
 		return val;
 	}
 
 	/* Access to IO BARs might get this far and still not want checking. */
-	if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) || dn->eeh_mode & EEH_MODE_NOCHECK)
+	if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) ||
+	    dn->eeh_mode & EEH_MODE_NOCHECK) {
+		pci_dev_put(dev);
 		return val;
+	}
 
+	if (!dn->eeh_config_addr) {
+		pci_dev_put(dev);
+		return val;
+	}
 
-	/* Now test for an EEH failure.  This is VERY expensive.
+	/*
+	 * Now test for an EEH failure.  This is VERY expensive.
 	 * Note that the eeh_config_addr may be a parent device
 	 * in the case of a device behind a bridge, or it may be
 	 * function zero of a multi-function device.
 	 * In any case they must share a common PHB.
 	 */
-	if (dn->eeh_config_addr) {
-		ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
-				dn->eeh_config_addr, BUID_HI(dn->phb->buid),
-				BUID_LO(dn->phb->buid));
-		if (ret == 0 && rets[1] == 1 && rets[0] >= 2) {
-			unsigned long	slot_err_ret;
-
-			memset(slot_err_buf, 0, RTAS_ERROR_LOG_MAX);
-			slot_err_ret = rtas_call(rtas_token("ibm,slot-error-detail"),
-						 8, 1, NULL, dn->eeh_config_addr,
-						 BUID_HI(dn->phb->buid),
-						 BUID_LO(dn->phb->buid), NULL, 0,
-						 __pa(slot_err_buf), RTAS_ERROR_LOG_MAX,
-						 2 /* Permanent Error */);
-
-			if (slot_err_ret == 0)
-				log_error(slot_err_buf, ERR_TYPE_RTAS_LOG, 1 /* Fatal */);
-
-			/*
-			 * XXX We should create a separate sysctl for this.
-			 *
-			 * Since the panic_on_oops sysctl is used to halt
-			 * the system in light of potential corruption, we
-			 * can use it here.
-			 */
-			if (panic_on_oops)
-				panic("EEH: MMIO failure (%ld) on device:\n%s\n",
-				      rets[0], pci_name(dev));
-			else
-				printk("EEH: MMIO failure (%ld) on device:\n%s\n",
-				       rets[0], pci_name(dev));
+	ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
+			dn->eeh_config_addr, BUID_HI(dn->phb->buid),
+			BUID_LO(dn->phb->buid));
+
+	if (ret == 0 && rets[1] == 1 && rets[0] >= 2) {
+		unsigned long slot_err_ret;
+
+		spin_lock_irqsave(&lock, flags);
+		memset(slot_err_buf, 0, RTAS_ERROR_LOG_MAX);
+		slot_err_ret = rtas_call(rtas_token("ibm,slot-error-detail"),
+					 8, 1, NULL, dn->eeh_config_addr,
+					 BUID_HI(dn->phb->buid),
+					 BUID_LO(dn->phb->buid), NULL, 0,
+					 __pa(slot_err_buf),
+					 RTAS_ERROR_LOG_MAX,
+					 2 /* Permanent Error */);
+
+		if (slot_err_ret == 0)
+			log_error(slot_err_buf, ERR_TYPE_RTAS_LOG,
+				  1 /* Fatal */);
+
+		spin_unlock_irqrestore(&lock, flags);
+
+		/*
+		 * XXX We should create a separate sysctl for this.
+		 *
+		 * Since the panic_on_oops sysctl is used to halt
+		 * the system in light of potential corruption, we
+		 * can use it here.
+		 */
+		if (panic_on_oops) {
+			panic("EEH: MMIO failure (%ld) on device:%s %s\n",
+			      rets[0], pci_name(dev), pci_pretty_name(dev));
+		} else {
+			__get_cpu_var(ignored_failures)++;
+			printk(KERN_INFO "EEH: MMIO failure (%ld) on device:%s %s\n",
+			       rets[0], pci_name(dev), pci_pretty_name(dev));
 		}
+	} else {
+		__get_cpu_var(false_positives)++;
 	}
-	eeh_false_positives++;
-	return val;	/* good case */
 
+	pci_dev_put(dev);
+	return val;
 }
+EXPORT_SYMBOL(eeh_check_failure);
 
 struct eeh_early_enable_info {
 	unsigned int buid_hi;
 	unsigned int buid_lo;
-	int adapters_enabled;
 };
 
 /* Enable eeh for the given device node. */
@@ -165,7 +466,7 @@ static void *early_enable_eeh(struct dev
 	long ret;
 	char *status = get_property(dn, "status", 0);
 	u32 *class_code = (u32 *)get_property(dn, "class-code", 0);
-	u32 *vendor_id =(u32 *) get_property(dn, "vendor-id", 0);
+	u32 *vendor_id = (u32 *)get_property(dn, "vendor-id", 0);
 	u32 *device_id = (u32 *)get_property(dn, "device-id", 0);
 	u32 *regs;
 	int enable;
@@ -183,7 +484,8 @@ static void *early_enable_eeh(struct dev
 	     *device_id == 0x0188 || *device_id == 0x0302))
 		return NULL;
 
-	/* Now decide if we are going to "Disable" EEH checking
+	/*
+	 * Now decide if we are going to "Disable" EEH checking
 	 * for this device.  We still run with the EEH hardware active,
 	 * but we won't be checking for ff's.  This means a driver
 	 * could return bad data (very bad!), an interrupt handler could
@@ -194,15 +496,19 @@ static void *early_enable_eeh(struct dev
 	if ((*class_code >> 16) == PCI_BASE_CLASS_DISPLAY)
 		enable = 0;
 
-	if (!eeh_check_opts_config(dn, *class_code, *vendor_id, *device_id, enable)) {
+	if (!eeh_check_opts_config(dn, *class_code, *vendor_id, *device_id,
+				   enable)) {
 		if (enable) {
-			printk(KERN_INFO "EEH: %s user requested to run without EEH.\n", dn->full_name);
+			printk(KERN_WARNING "EEH: %s user requested to run "
+			       "without EEH.\n", dn->full_name);
 			enable = 0;
 		}
 	}
 
-	if (!enable)
+	if (!enable) {
 		dn->eeh_mode = EEH_MODE_NOCHECK;
+		return NULL;
+	}
 
 	/* This device may already have an EEH parent. */
 	if (dn->parent && (dn->parent->eeh_mode & EEH_MODE_SUPPORTED)) {
@@ -212,7 +518,7 @@ static void *early_enable_eeh(struct dev
 		return NULL;
 	}
 
-	/* Ok..see if this device supports EEH. */
+	/* Ok... see if this device supports EEH. */
 	regs = (u32 *)get_property(dn, "reg", 0);
 	if (regs) {
 		/* First register entry is addr (00BBSS00)  */
@@ -221,16 +527,27 @@ static void *early_enable_eeh(struct dev
 				regs[0], info->buid_hi, info->buid_lo,
 				EEH_ENABLE);
 		if (ret == 0) {
-			info->adapters_enabled++;
+			eeh_subsystem_enabled = 1;
 			dn->eeh_mode |= EEH_MODE_SUPPORTED;
 			dn->eeh_config_addr = regs[0];
+#ifdef DEBUG
+			printk(KERN_DEBUG "EEH: %s: eeh enabled\n",
+			       dn->full_name);
+#endif
+		} else {
+			printk(KERN_WARNING "EEH: %s: rtas_call failed.\n",
+			       dn->full_name);
 		}
+	} else {
+		printk(KERN_WARNING "EEH: %s: unable to get reg property.\n",
+		       dn->full_name);
 	}
+
 	return NULL; 
 }
 
 /*
- * Initialize eeh by trying to enable it for all of the adapters in the system.
+ * Initialize EEH by trying to enable it for all of the adapters in the system.
  * As a side effect we can determine here if eeh is supported at all.
  * Note that we leave EEH on so failed config cycles won't cause a machine
  * check.  If a user turns off EEH for a particular adapter they are really
@@ -240,43 +557,35 @@ static void *early_enable_eeh(struct dev
  * but for now disabling EEH for adapters is mostly to work around drivers that
  * directly access mmio space (without using the macros).
  *
- * The eeh-force-off/on option does literally what it says, so if Linux must
+ * The eeh-force-off option does literally what it says, so if Linux must
  * avoid enabling EEH this must be done.
  */
-void eeh_init(void)
+void __init eeh_init(void)
 {
 	struct device_node *phb;
 	struct eeh_early_enable_info info;
 	char *eeh_force_off = strstr(saved_command_line, "eeh-force-off");
-	char *eeh_force_on = strstr(saved_command_line, "eeh-force-on");
 
 	ibm_set_eeh_option = rtas_token("ibm,set-eeh-option");
 	ibm_set_slot_reset = rtas_token("ibm,set-slot-reset");
 	ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state");
 
-	/* Allow user to force eeh mode on or off -- even if the hardware
-	 * doesn't exist.  This allows driver writers to at least test use
-	 * of I/O macros even if we can't actually test for EEH failure.
-	 */
-	if (eeh_force_on > eeh_force_off)
-		eeh_implemented = 1;
-	else if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE)
+	if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE)
 		return;
 
-	if (eeh_force_off > eeh_force_on) {
-		/* User is forcing EEH off.  Be noisy if it is implemented. */
-		if (eeh_implemented)
-			printk(KERN_WARNING "EEH: WARNING: PCI Enhanced I/O Error Handling is user disabled\n");
-		eeh_implemented = 0;
+	if (eeh_force_off) {
+		printk(KERN_WARNING "EEH: WARNING: PCI Enhanced I/O Error "
+		       "Handling is user disabled\n");
 		return;
 	}
 
-
 	/* Enable EEH for all adapters.  Note that eeh requires buid's */
-	info.adapters_enabled = 0;
-	for (phb = of_find_node_by_name(NULL, "pci"); phb; phb = of_find_node_by_name(phb, "pci")) {
+	for (phb = of_find_node_by_name(NULL, "pci"); phb;
+	     phb = of_find_node_by_name(phb, "pci")) {
 		int len;
-		int *buid_vals = (int *) get_property(phb, "ibm,fw-phb-id", &len);
+		int *buid_vals;
+
+		buid_vals = (int *)get_property(phb, "ibm,fw-phb-id", &len);
 		if (!buid_vals)
 			continue;
 		if (len == sizeof(int)) {
@@ -286,35 +595,82 @@ void eeh_init(void)
 			info.buid_hi = buid_vals[0];
 			info.buid_lo = buid_vals[1];
 		} else {
-			printk("EEH: odd ibm,fw-phb-id len returned: %d\n", len);
+			printk(KERN_INFO "EEH: odd ibm,fw-phb-id len returned: %d\n", len);
 			continue;
 		}
 		traverse_pci_devices(phb, early_enable_eeh, NULL, &info);
 	}
-	if (info.adapters_enabled) {
+
+	if (eeh_subsystem_enabled)
 		printk(KERN_INFO "EEH: PCI Enhanced I/O Error Handling Enabled\n");
-		eeh_implemented = 1;
-	}
 }
 
-
-int eeh_set_option(struct pci_dev *dev, int option)
+/**
+ * eeh_add_device - perform EEH initialization for the indicated pci device
+ * @dev: pci device for which to set up EEH
+ *
+ * This routine can be used to perform EEH initialization for PCI
+ * devices that were added after system boot (e.g. hotplug, dlpar).
+ * Whether this actually enables EEH or not for this device depends
+ * on the type of the device, on earlier boot command-line
+ * arguments & etc.
+ */
+void eeh_add_device(struct pci_dev *dev)
 {
-	struct device_node *dn = pci_device_to_OF_node(dev);
-	struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
+	struct device_node *dn;
+	struct pci_controller *phb;
+	struct eeh_early_enable_info info;
 
-	if (dn == NULL || phb == NULL || phb->buid == 0 || !eeh_implemented)
-		return -2;
+	if (!dev || !eeh_subsystem_enabled)
+		return;
 
-	return rtas_call(ibm_set_eeh_option, 4, 1, NULL,
-			 CONFIG_ADDR(dn->busno, dn->devfn),
-			 BUID_HI(phb->buid), BUID_LO(phb->buid), option);
+#ifdef DEBUG
+	printk(KERN_DEBUG "EEH: adding device %s %s\n", pci_name(dev),
+	       pci_pretty_name(dev));
+#endif
+	dn = pci_device_to_OF_node(dev);
+	if (NULL == dn)
+		return;
+
+	phb = PCI_GET_PHB_PTR(dev);
+	if (NULL == phb || 0 == phb->buid) {
+		printk(KERN_WARNING "EEH: Expected buid but found none\n");
+		return;
+	}
+
+	info.buid_hi = BUID_HI(phb->buid);
+	info.buid_lo = BUID_LO(phb->buid);
+
+	early_enable_eeh(dn, &info);
+	pci_addr_cache_insert_device (dev);
 }
+EXPORT_SYMBOL(eeh_add_device);
+
+/**
+ * eeh_remove_device - undo EEH setup for the indicated pci device
+ * @dev: pci device to be removed
+ *
+ * This routine should be when a device is removed from a running
+ * system (e.g. by hotplug or dlpar).
+ */
+void eeh_remove_device(struct pci_dev *dev)
+{
+	if (!dev || !eeh_subsystem_enabled)
+		return;
 
+	/* Unregister the device with the EEH/PCI address search system */
+#ifdef DEBUG
+	printk(KERN_DEBUG "EEH: remove device %s %s\n", pci_name(dev),
+	       pci_pretty_name(dev));
+#endif
+	pci_addr_cache_remove_device(dev);
+}
+EXPORT_SYMBOL(eeh_remove_device);
 
-/* If EEH is implemented, find the PCI device using given phys addr
+/*
+ * If EEH is implemented, find the PCI device using given phys addr
  * and check to see if eeh failure checking is disabled.
- * Remap the addr (trivially) to the EEH region if not.
+ * Remap the addr (trivially) to the EEH region if EEH checking enabled.
  * For addresses not known to PCI the vaddr is simply returned unchanged.
  */
 void *eeh_ioremap(unsigned long addr, void *vaddr)
@@ -322,43 +678,78 @@ void *eeh_ioremap(unsigned long addr, vo
 	struct pci_dev *dev;
 	struct device_node *dn;
 
-	if (!eeh_implemented)
+	if (!eeh_subsystem_enabled)
 		return vaddr;
-	dev = pci_find_dev_by_addr(addr);
+
+	dev = pci_get_device_by_addr(addr);
 	if (!dev)
 		return vaddr;
+
 	dn = pci_device_to_OF_node(dev);
-	if (!dn)
+	if (!dn) {
+		pci_dev_put(dev);
 		return vaddr;
-	if (dn->eeh_mode & EEH_MODE_NOCHECK)
+	}
+
+	if (dn->eeh_mode & EEH_MODE_NOCHECK) {
+		pci_dev_put(dev);
 		return vaddr;
+	}
 
+	pci_dev_put(dev);
 	return (void *)IO_ADDR_TO_TOKEN(vaddr);
 }
 
-static int eeh_proc_falsepositive_read(char *page, char **start, off_t off,
-			 int count, int *eof, void *data)
+static int proc_eeh_show(struct seq_file *m, void *v)
 {
-	int len;
-	len = sprintf(page, "eeh_false_positives=%ld\n"
-		      "eeh_total_mmio_ffs=%ld\n",
-		      eeh_false_positives, eeh_total_mmio_ffs);
-	return len;
+	unsigned int cpu;
+	unsigned long ffs = 0, positives = 0, failures = 0;
+
+	for_each_cpu(cpu) {
+		ffs += per_cpu(total_mmio_ffs, cpu);
+		positives += per_cpu(false_positives, cpu);
+		failures += per_cpu(ignored_failures, cpu);
+	}
+
+	if (0 == eeh_subsystem_enabled) {
+		seq_printf(m, "EEH Subsystem is globally disabled\n");
+		seq_printf(m, "eeh_total_mmio_ffs=%ld\n", ffs);
+	} else {
+		seq_printf(m, "EEH Subsystem is enabled\n");
+		seq_printf(m, "eeh_total_mmio_ffs=%ld\n"
+			   "eeh_false_positives=%ld\n"
+			   "eeh_ignored_failures=%ld\n",
+			   ffs, positives, failures);
+	}
+
+	return 0;
 }
 
-/* Implementation of /proc/ppc64/eeh
- * For now it is one file showing false positives.
- */
+static int proc_eeh_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, proc_eeh_show, NULL);
+}
+
+static struct file_operations proc_eeh_operations = {
+	.open		= proc_eeh_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
 static int __init eeh_init_proc(void)
 {
-	struct proc_dir_entry *ent = create_proc_entry("ppc64/eeh", S_IRUGO, 0);
-	if (ent) {
-		ent->nlink = 1;
-		ent->data = NULL;
-		ent->read_proc = (void *)eeh_proc_falsepositive_read;
+	struct proc_dir_entry *e;
+
+	if (systemcfg->platform & PLATFORM_PSERIES) {
+		e = create_proc_entry("ppc64/eeh", 0, NULL);
+		if (e)
+			e->proc_fops = &proc_eeh_operations;
 	}
-	return 0;
+
+        return 0;
 }
+__initcall(eeh_init_proc);
 
 /*
  * Test if "dev" should be configured on or off.
@@ -386,10 +777,12 @@ static int eeh_check_opts_config(struct 
 	strs[nstrs++] = classname;
 	strs[nstrs++] = "";	/* yes, this matches the empty string */
 
-	/* Now see if any string matches the eeh_opts list.
+	/*
+	 * Now see if any string matches the eeh_opts list.
 	 * The eeh_opts list entries start with + or -.
 	 */
-	for (s = eeh_opts; s && (s < (eeh_opts + eeh_opts_last)); s += strlen(s)+1) {
+	for (s = eeh_opts; s && (s < (eeh_opts + eeh_opts_last));
+	     s += strlen(s)+1) {
 		for (i = 0; i < nstrs; i++) {
 			if (strcasecmp(strs[i], s+1) == 0) {
 				ret = (strs[i][0] == '+') ? 1 : 0;
@@ -399,7 +792,8 @@ static int eeh_check_opts_config(struct 
 	return ret;
 }
 
-/* Handle kernel eeh-on & eeh-off cmd line options for eeh.
+/*
+ * Handle kernel eeh-on & eeh-off cmd line options for eeh.
  *
  * We support:
  *	eeh-off=loc1,loc2,loc3...
@@ -420,7 +814,8 @@ static int eeh_check_opts_config(struct 
  * so eeh-off means eeh by default is off.
  */
 
-/* This is implemented as a null separated list of strings.
+/*
+ * This is implemented as a null separated list of strings.
  * Each string looks like this:  "+X" or "-X"
  * where X is a loc code, vendor:device, class (as shown above)
  * or empty which is used to indicate all.
@@ -428,10 +823,10 @@ static int eeh_check_opts_config(struct 
  * We interpret this option string list so that it will literally
  * behave left-to-right even if some combinations don't make sense.
  */
-
 static int __init eeh_parm(char *str, int state)
 {
 	char *s, *cur, *curend;
+
 	if (!eeh_opts) {
 		eeh_opts = alloc_bootmem(EEH_MAX_OPTS);
 		eeh_opts[eeh_opts_last++] = '+'; /* default */
@@ -446,15 +841,17 @@ static int __init eeh_parm(char *str, in
 		str++;
 	for (s = str; s && *s != '\0'; s = curend) {
 		cur = s;
+		/* ignore empties.  Don't treat as "all-on" or "all-off" */
 		while (*cur == ',')
-			cur++;	/* ignore empties.  Don't treat as "all-on" or "all-off" */
+			cur++;
 		curend = strchr(cur, ',');
 		if (!curend)
 			curend = cur + strlen(cur);
 		if (*cur) {
 			int curlen = curend-cur;
 			if (eeh_opts_last + curlen > EEH_MAX_OPTS-2) {
-				printk(KERN_INFO "EEH: sorry...too many eeh cmd line options\n");
+				printk(KERN_WARNING "EEH: sorry...too many "
+				       "eeh cmd line options\n");
 				return 1;
 			}
 			eeh_opts[eeh_opts_last++] = state ? '+' : '-';
@@ -463,6 +860,7 @@ static int __init eeh_parm(char *str, in
 			eeh_opts[eeh_opts_last++] = '\0';
 		}
 	}
+
 	return 1;
 }
 
@@ -476,6 +874,5 @@ static int __init eehon_parm(char *str)
 	return eeh_parm(str, 1);
 }
 
-__initcall(eeh_init_proc);
 __setup("eeh-off", eehoff_parm);
 __setup("eeh-on", eehon_parm);
--- diff/arch/ppc64/kernel/entry.S	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/entry.S	2004-03-16 09:37:55.455109712 +0000
@@ -95,7 +95,7 @@ _GLOBAL(DoSyscall)
 #endif /* SHOW_SYSCALLS */
 	clrrdi	r10,r1,THREAD_SHIFT
 	ld	r10,TI_FLAGS(r10)
-	andi.	r11,r10,_TIF_SYSCALL_TRACE
+	andi.	r11,r10,_TIF_SYSCALL_T_OR_A
 	bne-	50f
 	cmpli	0,r0,NR_syscalls
 	bge-	66f
@@ -151,7 +151,8 @@ _GLOBAL(ret_from_syscall_1)
 	b	22b
         
 /* Traced system call support */
-50:	bl	.do_syscall_trace
+50:	addi	r3,r1,STACK_FRAME_OVERHEAD
+	bl	.do_syscall_trace_enter
 	ld	r0,GPR0(r1)	/* Restore original registers */
 	ld	r3,GPR3(r1)
 	ld	r4,GPR4(r1)
@@ -201,7 +202,7 @@ _GLOBAL(ret_from_syscall_2)
 	oris	r10,r10,0x1000
 	std	r10,_CCR(r1)
 60:	std	r3,GPR3(r1)	/* Update return value */
-	bl	.do_syscall_trace
+	bl	.do_syscall_trace_leave
 	b	.ret_from_except
 66:	li	r3,ENOSYS
 	b	57b
@@ -234,14 +235,14 @@ _GLOBAL(ppc64_rt_sigreturn)
 
 80:	clrrdi	r4,r1,THREAD_SHIFT
 	ld	r4,TI_FLAGS(r4)
-	andi.	r4,r4,_TIF_SYSCALL_TRACE
+	andi.	r4,r4,_TIF_SYSCALL_T_OR_A
 	bne-	81f
 	cmpi	0,r3,0
 	bge	.ret_from_except
 	b	.ret_from_syscall_1
 81:	cmpi	0,r3,0
 	blt	.ret_from_syscall_2
-	bl	.do_syscall_trace
+	bl	.do_syscall_trace_leave
 	b	.ret_from_except
 
 /*
@@ -327,9 +328,9 @@ _GLOBAL(ret_from_fork)
 	bl	.schedule_tail
 	clrrdi	r4,r1,THREAD_SHIFT
 	ld	r4,TI_FLAGS(r4)
-	andi.	r4,r4,_TIF_SYSCALL_TRACE
+	andi.	r4,r4,_TIF_SYSCALL_T_OR_A
 	beq+	.ret_from_except
-	bl	.do_syscall_trace
+	bl	.do_syscall_trace_leave
 	b	.ret_from_except
 
 _GLOBAL(ret_from_except)
--- diff/arch/ppc64/kernel/iSeries_VpdInfo.c	2004-02-09 10:36:08.000000000 +0000
+++ source/arch/ppc64/kernel/iSeries_VpdInfo.c	2004-03-16 09:37:55.456109560 +0000
@@ -27,6 +27,7 @@
 /************************************************************************/
 #include <linux/config.h>
 #include <linux/init.h>
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <asm/types.h>
 #include <asm/resource.h>
@@ -105,6 +106,7 @@ LocationData* iSeries_GetLocationData(st
 	strcpy(&LocationPtr->CardLocation[0], &DevNode->CardLocation[0]);
 	return LocationPtr;
 }
+EXPORT_SYMBOL(iSeries_GetLocationData);
 
 /*
  * Formats the device information.
--- diff/arch/ppc64/kernel/iSeries_pci.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/iSeries_pci.c	2004-03-16 09:37:55.457109408 +0000
@@ -26,6 +26,7 @@
 #include <linux/list.h> 
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/module.h>
 #include <linux/ide.h>
 #include <linux/pci.h>
 
@@ -472,6 +473,7 @@ void *iSeries_memset_io(void *dest, char
 	}
 	return dest;
 }
+EXPORT_SYMBOL(iSeries_memset_io);
 
 void *iSeries_memcpy_toio(void *dest, void *source, size_t count)
 {
@@ -485,6 +487,7 @@ void *iSeries_memcpy_toio(void *dest, vo
 	}
 	return dest;
 }
+EXPORT_SYMBOL(iSeries_memcpy_toio);
 
 void *iSeries_memcpy_fromio(void *dest, void *source, size_t count)
 {
@@ -498,6 +501,7 @@ void *iSeries_memcpy_fromio(void *dest, 
 	}
 	return dest;
 }
+EXPORT_SYMBOL(iSeries_memcpy_fromio);
 
 /*
  * Look down the chain to find the matching Device Device
@@ -708,6 +712,7 @@ u8 iSeries_Read_Byte(void *IoAddress)
 
 	return (u8)ret.value;
 }
+EXPORT_SYMBOL(iSeries_Read_Byte);
 
 u16 iSeries_Read_Word(void *IoAddress)
 {
@@ -737,6 +742,7 @@ u16 iSeries_Read_Word(void *IoAddress)
 
 	return swab16((u16)ret.value);
 }
+EXPORT_SYMBOL(iSeries_Read_Word);
 
 u32 iSeries_Read_Long(void *IoAddress)
 {
@@ -766,6 +772,7 @@ u32 iSeries_Read_Long(void *IoAddress)
 
 	return swab32((u32)ret.value);
 }
+EXPORT_SYMBOL(iSeries_Read_Long);
 
 /*
  * Write MM I/O Instructions for the iSeries
@@ -799,6 +806,7 @@ void iSeries_Write_Byte(u8 data, void *I
 		rc = HvCall4(HvCallPciBarStore8, dsa, BarOffset, data, 0);
 	} while (CheckReturnCode("WWB", DevNode, rc) != 0);
 }
+EXPORT_SYMBOL(iSeries_Write_Byte);
 
 void iSeries_Write_Word(u16 data, void *IoAddress)
 {
@@ -825,6 +833,7 @@ void iSeries_Write_Word(u16 data, void *
 		rc = HvCall4(HvCallPciBarStore16, dsa, BarOffset, swab16(data), 0);
 	} while (CheckReturnCode("WWW", DevNode, rc) != 0);
 }
+EXPORT_SYMBOL(iSeries_Write_Word);
 
 void iSeries_Write_Long(u32 data, void *IoAddress)
 {
@@ -851,6 +860,7 @@ void iSeries_Write_Long(u32 data, void *
 		rc = HvCall4(HvCallPciBarStore32, dsa, BarOffset, swab32(data), 0);
 	} while (CheckReturnCode("WWL", DevNode, rc) != 0);
 }
+EXPORT_SYMBOL(iSeries_Write_Long);
 
 void pcibios_name_device(struct pci_dev *dev)
 {
--- diff/arch/ppc64/kernel/iSeries_pci_reset.c	2004-02-09 10:36:08.000000000 +0000
+++ source/arch/ppc64/kernel/iSeries_pci_reset.c	2004-03-16 09:37:55.457109408 +0000
@@ -29,6 +29,7 @@
 /************************************************************************/
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/irq.h>
 
@@ -100,3 +101,4 @@ int iSeries_Device_ToggleReset(struct pc
 	}
 	return DeviceNode->ReturnCode;
 }
+EXPORT_SYMBOL(iSeries_Device_ToggleReset);
--- diff/arch/ppc64/kernel/iSeries_proc.c	2004-02-09 10:36:08.000000000 +0000
+++ source/arch/ppc64/kernel/iSeries_proc.c	2004-03-16 09:37:55.458109256 +0000
@@ -1,131 +1,162 @@
 /*
-  * iSeries_proc.c
-  * Copyright (C) 2001  Kyle A. Lucke 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) 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/proc_fs.h>
-#include <linux/spinlock.h>
+ * iSeries_proc.c
+ * Copyright (C) 2001  Kyle A. Lucke IBM Corporation
+ * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen 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) 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/init.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <asm/paca.h>
+#include <asm/processor.h>
+#include <asm/time.h>
+#include <asm/naca.h>
+#include <asm/iSeries/ItLpPaca.h>
+#include <asm/iSeries/ItLpQueue.h>
+#include <asm/iSeries/HvCallXm.h>
+#include <asm/iSeries/IoHriMainStore.h>
+#include <asm/iSeries/LparData.h>
 #include <asm/iSeries/iSeries_proc.h>
 
-static struct proc_dir_entry *iSeries_proc_root;
-static int iSeries_proc_initializationDone;
-static spinlock_t iSeries_proc_lock;
-
-struct iSeries_proc_registration {
-	struct iSeries_proc_registration *next;
-	iSeriesProcFunction functionMember;
+static int __init iseries_proc_create(void)
+{
+	struct proc_dir_entry *e = proc_mkdir("iSeries", 0);
+	if (!e)
+		return 1;
+
+	return 0;
+}
+core_initcall(iseries_proc_create);
+
+static char *event_types[9] = {
+	"Hypervisor\t\t",
+	"Machine Facilities\t",
+	"Session Manager\t",
+	"SPD I/O\t\t",
+	"Virtual Bus\t\t",
+	"PCI I/O\t\t",
+	"RIO I/O\t\t",
+	"Virtual Lan\t\t",
+	"Virtual I/O\t\t"
 };
 
-struct iSeries_proc_registration preallocated[16];
+static int proc_lpevents_show(struct seq_file *m, void *v)
+{
+	unsigned int i;
+
+	seq_printf(m, "LpEventQueue 0\n");
+	seq_printf(m, "  events processed:\t%lu\n",
+		   (unsigned long)xItLpQueue.xLpIntCount);
 
-#define MYQUEUETYPE(T) struct MYQueue##T
-#define MYQUEUE(T) \
-MYQUEUETYPE(T) \
-{ \
-	struct T *head; \
-	struct T *tail; \
-}
-#define MYQUEUECTOR(q) do { (q)->head = NULL; (q)->tail = NULL; } while(0)
-#define MYQUEUEENQ(q, p) \
-do { \
-	(p)->next = NULL; \
-	if ((q)->head != NULL) { \
-		(q)->head->next = (p); \
-		(q)->head = (p); \
-	} else { \
-		(q)->tail = (q)->head = (p); \
-	} \
-} while(0)
-
-#define MYQUEUEDEQ(q,p) \
-do { \
-	(p) = (q)->tail; \
-	if ((p) != NULL) { \
-		(q)->tail = (p)->next; \
-		(p)->next = NULL; \
-	} \
-	if ((q)->tail == NULL) \
-		(q)->head = NULL; \
-} while(0)
-
-MYQUEUE(iSeries_proc_registration);
-typedef MYQUEUETYPE(iSeries_proc_registration) aQueue;
-
-static aQueue iSeries_free;
-static aQueue iSeries_queued;
-
-void iSeries_proc_early_init(void)
-{
-	int i = 0;
-	unsigned long flags;
-
-	iSeries_proc_initializationDone = 0;
-	spin_lock_init(&iSeries_proc_lock);
-	MYQUEUECTOR(&iSeries_free);
-	MYQUEUECTOR(&iSeries_queued);
-
-	spin_lock_irqsave(&iSeries_proc_lock, flags);
-	for (i = 0; i < 16; ++i)
-		MYQUEUEENQ(&iSeries_free, preallocated + i);
-	spin_unlock_irqrestore(&iSeries_proc_lock, flags);
-}
-
-static int iSeries_proc_create(void)
-{
-	unsigned long flags;
-	struct iSeries_proc_registration *reg;
-
-	printk("iSeries_proc: Creating /proc/iSeries\n");
-
-	spin_lock_irqsave(&iSeries_proc_lock, flags);
-	iSeries_proc_root = proc_mkdir("iSeries", 0);
-	if (!iSeries_proc_root)
-		goto out;
-
-	MYQUEUEDEQ(&iSeries_queued, reg);
-	while (reg != NULL) {
-		(*(reg->functionMember))(iSeries_proc_root);
-		MYQUEUEDEQ(&iSeries_queued, reg);
-	}
+	for (i = 0; i < 9; ++i)
+		seq_printf(m, "    %s %10lu\n", event_types[i],
+			   (unsigned long)xItLpQueue.xLpIntCountByType[i]);
+
+	seq_printf(m, "\n  events processed by processor:\n");
+
+	for_each_online_cpu(i)
+		seq_printf(m, "    CPU%02d  %10u\n", i, paca[i].lpEvent_count);
 
-	iSeries_proc_initializationDone = 1;
-out:
-	spin_unlock_irqrestore(&iSeries_proc_lock, flags);
 	return 0;
 }
 
-arch_initcall(iSeries_proc_create);
+static int proc_lpevents_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, proc_lpevents_show, NULL);
+}
+
+static struct file_operations proc_lpevents_operations = {
+	.open		= proc_lpevents_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
 
-void iSeries_proc_callback(iSeriesProcFunction initFunction)
+static unsigned long startTitan = 0;
+static unsigned long startTb = 0;
+
+static int proc_titantod_show(struct seq_file *m, void *v)
 {
-	unsigned long flags;
+	unsigned long tb0, titan_tod;
+
+	tb0 = get_tb();
+	titan_tod = HvCallXm_loadTod();
 
-	spin_lock_irqsave(&iSeries_proc_lock, flags);
-	if (iSeries_proc_initializationDone)
-		(*initFunction)(iSeries_proc_root);
-	else {
-		struct iSeries_proc_registration *reg = NULL;
-
-		MYQUEUEDEQ(&iSeries_free, reg);
-		if (reg != NULL) {
-			reg->functionMember = initFunction;
-			MYQUEUEENQ(&iSeries_queued, reg);
-		} else
-			printk("Couldn't get a queue entry\n");
+	seq_printf(m, "Titan\n" );
+	seq_printf(m, "  time base =          %016lx\n", tb0);
+	seq_printf(m, "  titan tod =          %016lx\n", titan_tod);
+	seq_printf(m, "  xProcFreq =          %016x\n",
+		   xIoHriProcessorVpd[0].xProcFreq);
+	seq_printf(m, "  xTimeBaseFreq =      %016x\n",
+		   xIoHriProcessorVpd[0].xTimeBaseFreq);
+	seq_printf(m, "  tb_ticks_per_jiffy = %lu\n", tb_ticks_per_jiffy);
+	seq_printf(m, "  tb_ticks_per_usec  = %lu\n", tb_ticks_per_usec);
+
+	if (!startTitan) {
+		startTitan = titan_tod;
+		startTb = tb0;
+	} else {
+		unsigned long titan_usec = (titan_tod - startTitan) >> 12;
+		unsigned long tb_ticks = (tb0 - startTb);
+		unsigned long titan_jiffies = titan_usec / (1000000/HZ);
+		unsigned long titan_jiff_usec = titan_jiffies * (1000000/HZ);
+		unsigned long titan_jiff_rem_usec = titan_usec - titan_jiff_usec;
+		unsigned long tb_jiffies = tb_ticks / tb_ticks_per_jiffy;
+		unsigned long tb_jiff_ticks = tb_jiffies * tb_ticks_per_jiffy;
+		unsigned long tb_jiff_rem_ticks = tb_ticks - tb_jiff_ticks;
+		unsigned long tb_jiff_rem_usec = tb_jiff_rem_ticks / tb_ticks_per_usec;
+		unsigned long new_tb_ticks_per_jiffy = (tb_ticks * (1000000/HZ))/titan_usec;
+
+		seq_printf(m, "  titan elapsed = %lu uSec\n", titan_usec);
+		seq_printf(m, "  tb elapsed    = %lu ticks\n", tb_ticks);
+		seq_printf(m, "  titan jiffies = %lu.%04lu \n", titan_jiffies,
+			   titan_jiff_rem_usec);
+		seq_printf(m, "  tb jiffies    = %lu.%04lu\n", tb_jiffies,
+			   tb_jiff_rem_usec);
+		seq_printf(m, "  new tb_ticks_per_jiffy = %lu\n",
+			   new_tb_ticks_per_jiffy);
 	}
-	spin_unlock_irqrestore(&iSeries_proc_lock, flags);
+
+	return 0;
+}
+
+static int proc_titantod_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, proc_titantod_show, NULL);
+}
+
+static struct file_operations proc_titantod_operations = {
+	.open		= proc_titantod_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int __init iseries_proc_init(void)
+{
+	struct proc_dir_entry *e;
+
+	e = create_proc_entry("iSeries/lpevents", S_IFREG|S_IRUGO, NULL);
+	if (e)
+		e->proc_fops = &proc_lpevents_operations;
+
+	e = create_proc_entry("iSeries/titanTod", S_IFREG|S_IRUGO, NULL);
+	if (e)
+		e->proc_fops = &proc_titantod_operations;
+
+	return 0;
 }
+__initcall(iseries_proc_init);
--- diff/arch/ppc64/kernel/iSeries_setup.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/iSeries_setup.c	2004-03-16 09:37:55.459109104 +0000
@@ -51,7 +51,6 @@
 #include <asm/iSeries/ItLpQueue.h>
 #include <asm/iSeries/IoHriMainStore.h>
 #include <asm/iSeries/iSeries_proc.h>
-#include <asm/proc_pmc.h>
 #include <asm/iSeries/mf.h>
 
 /* Function Prototypes */
@@ -393,12 +392,9 @@ void __init iSeries_init(unsigned long r
 
 	iSeries_setup_dprofile();
 
-	iSeries_proc_early_init();
 	mf_init();
 	mf_initialized = 1;
 	mb();
-
-	iSeries_proc_callback(&pmc_proc_init);
 }
 
 /*
--- diff/arch/ppc64/kernel/irq.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/irq.c	2004-03-16 09:37:55.460108952 +0000
@@ -66,7 +66,7 @@ irq_desc_t irq_desc[NR_IRQS] __cacheline
 		.lock = SPIN_LOCK_UNLOCKED
 	}
 };
-	
+
 int ppc_spurious_interrupts = 0;
 unsigned long lpEvent_count = 0;
 
@@ -183,6 +183,7 @@ do_free_irq(int irq, void* dev_id)
 	return -ENOENT;
 }
 
+
 int request_irq(unsigned int irq,
 	irqreturn_t (*handler)(int, void *, struct pt_regs *),
 	unsigned long irqflags, const char * devname, void *dev_id)
@@ -195,25 +196,25 @@ int request_irq(unsigned int irq,
 	if (!handler)
 		/* We could implement really free_irq() instead of that... */
 		return do_free_irq(irq, dev_id);
-	
+
 	action = (struct irqaction *)
 		kmalloc(sizeof(struct irqaction), GFP_KERNEL);
 	if (!action) {
 		printk(KERN_ERR "kmalloc() failed for irq %d !\n", irq);
 		return -ENOMEM;
 	}
-	
+
 	action->handler = handler;
-	action->flags = irqflags;					
+	action->flags = irqflags;
 	action->mask = 0;
 	action->name = devname;
 	action->dev_id = dev_id;
 	action->next = NULL;
-	
+
 	retval = setup_irq(irq, action);
 	if (retval)
 		kfree(action);
-		
+
 	return 0;
 }
 
@@ -342,13 +343,13 @@ int show_interrupts(struct seq_file *p, 
 		action = irq_desc[i].action;
 		if (!action || !action->handler)
 			goto skip;
-		seq_printf(p, "%3d: ", i);		
+		seq_printf(p, "%3d: ", i);
 #ifdef CONFIG_SMP
 		for (j = 0; j < NR_CPUS; j++) {
 			if (cpu_online(j))
 				seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 		}
-#else		
+#else
 		seq_printf(p, "%10u ", kstat_irqs(i));
 #endif /* CONFIG_SMP */
 		if (irq_desc[i].handler)		
@@ -373,8 +374,10 @@ static inline int handle_irq_event(int i
 	int status = 0;
 	int retval = 0;
 
+#ifndef CONFIG_PPC_ISERIES
 	if (!(action->flags & SA_INTERRUPT))
 		local_irq_enable();
+#endif
 
 	do {
 		status |= action->flags;
@@ -383,7 +386,9 @@ static inline int handle_irq_event(int i
 	} while (action);
 	if (status & SA_SAMPLE_RANDOM)
 		add_interrupt_randomness(irq);
+#ifndef CONFIG_PPC_ISERIES
 	local_irq_disable();
+#endif
 	return retval;
 }
 
@@ -577,13 +582,13 @@ int do_IRQ(struct pt_regs *regs)
 	irq_enter();
 
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
-	/* Debugging check for stack overflow: is there less than 8KB free? */
+	/* Debugging check for stack overflow: is there less than 4KB free? */
 	{
 		long sp;
 
 		sp = __get_SP() & (THREAD_SIZE-1);
 
-		if (unlikely(sp < (sizeof(struct thread_info) + 8192))) {
+		if (unlikely(sp < (sizeof(struct thread_info) + 4096))) {
 			printk("do_IRQ: stack overflow: %ld\n",
 				sp - sizeof(struct thread_info));
 			dump_stack();
@@ -670,7 +675,7 @@ void __init init_IRQ(void)
 		return;
 
 	once++;
-	
+
 	ppc_md.init_IRQ();
 }
 
@@ -699,6 +704,7 @@ static int irq_affinity_write_proc (stru
 {
 	int irq = (long)data, full_count = count, err;
 	cpumask_t new_value, tmp;
+	cpumask_t allcpus = CPU_MASK_ALL;
 
 	if (!irq_desc[irq].handler->set_affinity)
 		return -EIO;
@@ -708,6 +714,14 @@ static int irq_affinity_write_proc (stru
 		return err;
 
 	/*
+	 * We check for CPU_MASK_ALL in xics to send irqs to all cpus.
+	 * In some cases CPU_MASK_ALL is smaller than the cpumask (eg
+	 * NR_CPUS == 32 and cpumask is a long), so we mask it here to
+	 * be consistent.
+	 */
+	cpus_and(new_value, new_value, allcpus);
+
+	/*
 	 * Do not allow disabling IRQs completely - it's a too easy
 	 * way to make the system unusable accidentally :-) At least
 	 * one online CPU still has to be targeted.
@@ -900,4 +914,37 @@ int virt_irq_create_mapping(unsigned int
 	return NO_IRQ;
 }
 
+/*
+ * In most cases will get a hit on the very first slot checked in the
+ * virt_irq_to_real_map.  Only when there are a large number of
+ * IRQs will this be expensive.
+ */
+unsigned int real_irq_to_virt_slowpath(unsigned int real_irq)
+{
+	unsigned int virq;
+	unsigned int first_virq;
+
+	virq = real_irq;
+
+	if (virq > MAX_VIRT_IRQ)
+		virq = (virq % NR_VIRT_IRQS) + MIN_VIRT_IRQ;
+
+	first_virq = virq;
+
+	do {
+		if (virt_irq_to_real_map[virq] == real_irq)
+			return virq;
+
+		virq++;
+
+		if (virq >= MAX_VIRT_IRQ)
+			virq = 0;
+
+	} while (first_virq != virq);
+
+	return NO_IRQ;
+
+}
+
+
 #endif
--- diff/arch/ppc64/kernel/mf.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/mf.c	2004-03-16 09:37:55.461108800 +0000
@@ -30,13 +30,13 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/mm.h>
+#include <linux/module.h>
 #include <asm/iSeries/HvLpConfig.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <asm/nvram.h>
 #include <asm/time.h>
 #include <asm/iSeries/ItSpCommArea.h>
-#include <asm/iSeries/iSeries_proc.h>
 #include <asm/uaccess.h>
 #include <linux/dma-mapping.h>
 #include <linux/bcd.h>
@@ -560,6 +560,7 @@ void mf_allocateLpEvents(HvLpIndex targe
 	if ((rc != 0) && (hdlr != NULL))
 		(*hdlr)(userToken, rc);
 }
+EXPORT_SYMBOL(mf_allocateLpEvents);
 
 /*
  * Global kernel interface to unseed and deallocate events already in
@@ -590,6 +591,7 @@ void mf_deallocateLpEvents(HvLpIndex tar
 	if ((rc != 0) && (hdlr != NULL))
 		(*hdlr)(userToken, rc);
 }
+EXPORT_SYMBOL(mf_deallocateLpEvents);
 
 /*
  * Global kernel interface to tell the VSP object in the primary
@@ -680,8 +682,6 @@ void mf_init(void)
 
 	/* initialization complete */
 	printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities initialized\n");
-
-	iSeries_proc_callback(&mf_proc_init);
 }
 
 void mf_setSide(char side)
--- diff/arch/ppc64/kernel/mf_proc.c	2004-02-09 10:36:08.000000000 +0000
+++ source/arch/ppc64/kernel/mf_proc.c	2004-03-16 09:37:55.461108800 +0000
@@ -16,11 +16,10 @@
  * 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/init.h>
 #include <asm/uaccess.h>
 #include <asm/iSeries/mf.h>
 
-static struct proc_dir_entry *mf_proc_root = NULL;
-
 static int proc_mf_dump_cmdline(char *page, char **start, off_t off,
 		int count, int *eof, void *data)
 {
@@ -187,27 +186,28 @@ static int proc_mf_change_vmlinux(struct
 	return count;			
 }
 
-void mf_proc_init(struct proc_dir_entry *iSeries_proc)
+static int __init mf_proc_init(void)
 {
+	struct proc_dir_entry *mf_proc_root;
 	struct proc_dir_entry *ent;
 	struct proc_dir_entry *mf;
 	char name[2];
 	int i;
 
-	mf_proc_root = proc_mkdir("mf", iSeries_proc);
+	mf_proc_root = proc_mkdir("iSeries/mf", NULL);
 	if (!mf_proc_root)
-		return;
+		return 1;
 
 	name[1] = '\0';
 	for (i = 0; i < 4; i++) {
 		name[0] = 'A' + i;
 		mf = proc_mkdir(name, mf_proc_root);
 		if (!mf)
-			return;
+			return 1;
 
 		ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf);
 		if (!ent)
-			return;
+			return 1;
 		ent->nlink = 1;
 		ent->data = (void *)(long)i;
 		ent->read_proc = proc_mf_dump_cmdline;
@@ -218,7 +218,7 @@ void mf_proc_init(struct proc_dir_entry 
 
 		ent = create_proc_entry("vmlinux", S_IFREG|S_IWUSR, mf);
 		if (!ent)
-			return;
+			return 1;
 		ent->nlink = 1;
 		ent->data = (void *)(long)i;
 #if 0
@@ -239,7 +239,7 @@ void mf_proc_init(struct proc_dir_entry 
 
 	ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root);
 	if (!ent)
-		return;
+		return 1;
 	ent->nlink = 1;
 	ent->data = (void *)0;
 	ent->read_proc = proc_mf_dump_side;
@@ -247,9 +247,13 @@ void mf_proc_init(struct proc_dir_entry 
 
 	ent = create_proc_entry("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root);
 	if (!ent)
-		return;
+		return 1;
 	ent->nlink = 1;
 	ent->data = (void *)0;
 	ent->read_proc = proc_mf_dump_src;
 	ent->write_proc = proc_mf_change_src;
+
+	return 0;
 }
+
+__initcall(mf_proc_init);
--- diff/arch/ppc64/kernel/misc.S	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/misc.S	2004-03-16 09:37:55.462108648 +0000
@@ -565,35 +565,6 @@ _GLOBAL(kernel_thread)
 	ld	r30,-16(r1)
 	blr
 
-	.section	".toc","aw"
-.SYSCALL_ERRNO:
-	.tc errno[TC],errno
-
-	.section	".text"
-	.align 3
-	
-#define SYSCALL(name) \
-_GLOBAL(name) \
-	li	r0,__NR_##name; \
-	sc; \
-	bnslr; \
-	ld	r4,.SYSCALL_ERRNO@toc(2); \
-	std	r3,0(r4); \
-	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
 #endif
@@ -653,7 +624,7 @@ _GLOBAL(sys_call_table32)
 	.llong .sys_geteuid
 	.llong .sys_getegid		/* 50 */
 	.llong .sys_acct
-	.llong .sys32_umount
+	.llong .sys_umount
 	.llong .sys_ni_syscall		/* old lock syscall */
 	.llong .compat_sys_ioctl
 	.llong .compat_sys_fcntl		/* 55 */
--- diff/arch/ppc64/kernel/pSeries_lpar.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/pSeries_lpar.c	2004-03-16 09:37:55.462108648 +0000
@@ -37,6 +37,12 @@
 #include <asm/hvcall.h>
 #include <asm/prom.h>
 
+/* in pSeries_hvCall.S */
+EXPORT_SYMBOL(plpar_hcall);
+EXPORT_SYMBOL(plpar_hcall_4out);
+EXPORT_SYMBOL(plpar_hcall_norets);
+EXPORT_SYMBOL(plpar_hcall_8arg_2ret);
+
 long poll_pending(void)
 {
 	unsigned long dummy;
--- diff/arch/ppc64/kernel/pci.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/pci.c	2004-03-16 09:37:55.463108496 +0000
@@ -119,43 +119,6 @@ static void fixup_windbond_82c105(struct
 	}
 }
 
-/* Given an mmio phys address, find a pci device that implements
- * this address.  This is of course expensive, but only used
- * for device initialization or error paths.
- * For io BARs it is assumed the pci_io_base has already been added
- * into addr.
- *
- * Bridges are ignored although they could be used to optimize the search.
- */
-struct pci_dev *pci_find_dev_by_addr(unsigned long addr)
-{
-	struct pci_dev *dev = NULL;
-	int i;
-	unsigned long ioaddr;
-
-	ioaddr = (addr > isa_io_base) ? addr - isa_io_base : 0;
-
-	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-		if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE)
-			continue;
-		for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
-			unsigned long start = pci_resource_start(dev,i);
-			unsigned long end = pci_resource_end(dev,i);
-			unsigned int flags = pci_resource_flags(dev,i);
-			if (start == 0 || ~start == 0 ||
-			    end == 0 || ~end == 0)
-				continue;
-			if ((flags & IORESOURCE_IO) &&
-			    (ioaddr >= start && ioaddr <= end))
-				return dev;
-			else if ((flags & IORESOURCE_MEM) &&
-				 (addr >= start && addr <= end))
-				return dev;
-		}
-	}
-	return NULL;
-}
-
 void 
 pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
 			struct resource *res)
@@ -359,6 +322,10 @@ static int __init pcibios_init(void)
 	printk("PCI: Probing PCI hardware done\n");
 	//ppc64_boot_msg(0x41, "PCI Done");
 
+#ifdef CONFIG_PPC_PSERIES
+	pci_addr_cache_build();
+#endif
+
 	return 0;
 }
 
--- diff/arch/ppc64/kernel/pci.h	2003-07-08 08:55:18.000000000 +0000
+++ source/arch/ppc64/kernel/pci.h	2004-03-16 09:37:55.463108496 +0000
@@ -37,11 +37,14 @@ typedef void *(*traverse_func)(struct de
 void *traverse_pci_devices(struct device_node *start, traverse_func pre, traverse_func post, void *data);
 void *traverse_all_pci_devices(traverse_func pre);
 
-struct pci_dev *pci_find_dev_by_addr(unsigned long addr);
 void pci_devs_phb_init(void);
 void pci_fix_bus_sysdata(void);
 struct device_node *fetch_dev_dn(struct pci_dev *dev);
 
 #define PCI_GET_PHB_PTR(dev)    (((struct device_node *)(dev)->sysdata)->phb)
 
+/* PCI address cache management routines */
+void pci_addr_cache_insert_device(struct pci_dev *dev);
+void pci_addr_cache_remove_device(struct pci_dev *dev);
+
 #endif /* __PPC_KERNEL_PCI_H__ */
--- diff/arch/ppc64/kernel/pmac_smp.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/pmac_smp.c	2004-03-16 09:37:55.464108344 +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/pmc.c	2002-10-16 03:28:29.000000000 +0000
+++ source/arch/ppc64/kernel/pmc.c	2004-03-16 09:37:55.464108344 +0000
@@ -1,167 +0,0 @@
-/*
- * pmc.c
- * Copyright (C) 2001 Dave Engebretsen & Mike Corrigan 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) 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
- */
-
-/* Change Activity:
- * 2001/06/05 : engebret : Created.
- * End Change Activity 
- */
-
-#include <asm/proc_fs.h>
-#include <asm/paca.h>
-#include <asm/iSeries/ItLpPaca.h>
-#include <asm/iSeries/ItLpQueue.h>
-#include <asm/processor.h>
-
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <asm/pmc.h>
-#include <asm/uaccess.h>
-#include <asm/naca.h>
-
-struct _pmc_sw pmc_sw_system = {
-	0  
-};
-
-struct _pmc_sw pmc_sw_cpu[NR_CPUS] = {
-	{0 }, 
-};
-
-/*
- * Provide enough storage for either system level counters or
- * one cpu's counters.
- */
-struct _pmc_sw_text pmc_sw_text;
-struct _pmc_hw_text pmc_hw_text;
-
-char *
-ppc64_pmc_stab(int file)
-{
-	int  n;
-	unsigned long stab_faults, stab_capacity_castouts, stab_invalidations; 
-	unsigned long i;
-
-	stab_faults = stab_capacity_castouts = stab_invalidations = n = 0;
-
-	if (file == -1) {
-		for (i = 0;  i < NR_CPUS; i++) {
-			if (!cpu_online(i))
-				continue;
-			stab_faults += pmc_sw_cpu[i].stab_faults;
-			stab_capacity_castouts += pmc_sw_cpu[i].stab_capacity_castouts;
-			stab_invalidations += pmc_sw_cpu[i].stab_invalidations;
-		}
-		n += sprintf(pmc_sw_text.buffer + n,    
-			     "Faults         0x%lx\n", stab_faults); 
-		n += sprintf(pmc_sw_text.buffer + n, 
-			     "Castouts       0x%lx\n", stab_capacity_castouts); 
-		n += sprintf(pmc_sw_text.buffer + n, 
-			     "Invalidations  0x%lx\n", stab_invalidations); 
-	} else {
-		n += sprintf(pmc_sw_text.buffer + n,
-			     "Faults         0x%lx\n", 
-			     pmc_sw_cpu[file].stab_faults);
-		
-		n += sprintf(pmc_sw_text.buffer + n,   
-			     "Castouts       0x%lx\n", 
-			     pmc_sw_cpu[file].stab_capacity_castouts);
-		
-		n += sprintf(pmc_sw_text.buffer + n,   
-			     "Invalidations  0x%lx\n", 
-			     pmc_sw_cpu[file].stab_invalidations);
-
-		for (i = 0; i < STAB_ENTRY_MAX; i++) {
-			if (pmc_sw_cpu[file].stab_entry_use[i]) {
-				n += sprintf(pmc_sw_text.buffer + n,   
-					     "Entry %02ld       0x%lx\n", i, 
-					     pmc_sw_cpu[file].stab_entry_use[i]);
-			}
-		}
-
-	}
-
-	return(pmc_sw_text.buffer); 
-}
-
-char *
-ppc64_pmc_htab(int file)
-{
-	int  n;
-	unsigned long htab_primary_overflows, htab_capacity_castouts;
-	unsigned long htab_read_to_write_faults; 
-
-	htab_primary_overflows = htab_capacity_castouts = 0;
-	htab_read_to_write_faults = n = 0;
-
-	if (file == -1) {
-		n += sprintf(pmc_sw_text.buffer + n,    
-			     "Primary Overflows  0x%lx\n", 
-			     pmc_sw_system.htab_primary_overflows); 
-		n += sprintf(pmc_sw_text.buffer + n, 
-			     "Castouts           0x%lx\n", 
-			     pmc_sw_system.htab_capacity_castouts); 
-	} else {
-		n += sprintf(pmc_sw_text.buffer + n,
-			     "Primary Overflows  N/A\n");
-
-		n += sprintf(pmc_sw_text.buffer + n,   
-			     "Castouts           N/A\n\n");
-
-	}
-	
-	return(pmc_sw_text.buffer); 
-}
-
-char *
-ppc64_pmc_hw(int file)
-{
-	int  n;
-
-	n = 0;
-	if (file == -1) {
-		n += sprintf(pmc_hw_text.buffer + n, "Not Implemented\n");
-	} else {
-		n += sprintf(pmc_hw_text.buffer + n,    
-			     "MMCR0  0x%lx\n", mfspr(MMCR0)); 
-		n += sprintf(pmc_hw_text.buffer + n, 
-			     "MMCR1  0x%lx\n", mfspr(MMCR1)); 
-#if 0
-		n += sprintf(pmc_hw_text.buffer + n,    
-			     "MMCRA  0x%lx\n", mfspr(MMCRA)); 
-#endif
-
-		n += sprintf(pmc_hw_text.buffer + n,    
-			     "PMC1   0x%lx\n", mfspr(PMC1)); 
-		n += sprintf(pmc_hw_text.buffer + n,    
-			     "PMC2   0x%lx\n", mfspr(PMC2)); 
-		n += sprintf(pmc_hw_text.buffer + n,    
-			     "PMC3   0x%lx\n", mfspr(PMC3)); 
-		n += sprintf(pmc_hw_text.buffer + n,    
-			     "PMC4   0x%lx\n", mfspr(PMC4)); 
-		n += sprintf(pmc_hw_text.buffer + n,    
-			     "PMC5   0x%lx\n", mfspr(PMC5)); 
-		n += sprintf(pmc_hw_text.buffer + n,    
-			     "PMC6   0x%lx\n", mfspr(PMC6)); 
-		n += sprintf(pmc_hw_text.buffer + n,    
-			     "PMC7   0x%lx\n", mfspr(PMC7)); 
-		n += sprintf(pmc_hw_text.buffer + n,    
-			     "PMC8   0x%lx\n", mfspr(PMC8)); 
-	}
-
-	return(pmc_hw_text.buffer); 
-}
--- diff/arch/ppc64/kernel/ppc_ksyms.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/ppc_ksyms.c	2004-03-16 09:37:55.465108192 +0000
@@ -40,13 +40,8 @@
 #include <asm/hw_irq.h>
 #include <asm/abs_addr.h>
 #include <asm/cacheflush.h>
-#include <asm/proc_fs.h>
 #ifdef CONFIG_PPC_ISERIES
-#include <asm/iSeries/iSeries_pci.h>
-#include <asm/iSeries/iSeries_proc.h>
-#include <asm/iSeries/mf.h>
-#include <asm/iSeries/HvLpEvent.h>
-#include <asm/iSeries/HvLpConfig.h>
+#include <asm/iSeries/HvCallSc.h>
 #endif
 
 extern int do_signal(sigset_t *, struct pt_regs *);
@@ -59,9 +54,6 @@ EXPORT_SYMBOL(sys_ioctl);
 EXPORT_SYMBOL(isa_io_base);
 EXPORT_SYMBOL(pci_io_base);
 
-EXPORT_SYMBOL(find_next_zero_bit);
-EXPORT_SYMBOL(find_next_zero_le_bit);
-
 EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strncpy);
 EXPORT_SYMBOL(strcat);
@@ -98,7 +90,6 @@ EXPORT_SYMBOL(msChunks);
 EXPORT_SYMBOL(reloc_offset);
 
 #ifdef CONFIG_PPC_ISERIES
-EXPORT_SYMBOL(iSeries_proc_callback);
 EXPORT_SYMBOL(HvCall0);
 EXPORT_SYMBOL(HvCall1);
 EXPORT_SYMBOL(HvCall2);
@@ -107,11 +98,6 @@ EXPORT_SYMBOL(HvCall4);
 EXPORT_SYMBOL(HvCall5);
 EXPORT_SYMBOL(HvCall6);
 EXPORT_SYMBOL(HvCall7);
-EXPORT_SYMBOL(HvLpEvent_unregisterHandler);
-EXPORT_SYMBOL(HvLpEvent_registerHandler);
-EXPORT_SYMBOL(mf_allocateLpEvents);
-EXPORT_SYMBOL(mf_deallocateLpEvents);
-EXPORT_SYMBOL(HvLpConfig_getLpIndex_outline);
 #endif
 
 EXPORT_SYMBOL(_insb);
@@ -128,32 +114,6 @@ EXPORT_SYMBOL(ioremap);
 EXPORT_SYMBOL(__ioremap);
 EXPORT_SYMBOL(iounmap);
 
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL(pci_alloc_consistent);
-EXPORT_SYMBOL(pci_free_consistent);
-EXPORT_SYMBOL(pci_map_single);
-EXPORT_SYMBOL(pci_unmap_single);
-EXPORT_SYMBOL(pci_map_sg);
-EXPORT_SYMBOL(pci_unmap_sg);
-#ifdef CONFIG_PPC_ISERIES
-EXPORT_SYMBOL(iSeries_GetLocationData);
-EXPORT_SYMBOL(iSeries_Device_ToggleReset);
-EXPORT_SYMBOL(iSeries_memset_io);
-EXPORT_SYMBOL(iSeries_memcpy_toio);
-EXPORT_SYMBOL(iSeries_memcpy_fromio);
-EXPORT_SYMBOL(iSeries_Read_Byte);
-EXPORT_SYMBOL(iSeries_Read_Word);
-EXPORT_SYMBOL(iSeries_Read_Long);
-EXPORT_SYMBOL(iSeries_Write_Byte);
-EXPORT_SYMBOL(iSeries_Write_Word);
-EXPORT_SYMBOL(iSeries_Write_Long);
-#endif /* CONFIG_PPC_ISERIES */
-#ifndef CONFIG_PPC_ISERIES
-EXPORT_SYMBOL(eeh_check_failure);
-EXPORT_SYMBOL(eeh_total_mmio_ffs);
-#endif /* CONFIG_PPC_ISERIES */
-#endif /* CONFIG_PCI */
-
 EXPORT_SYMBOL(start_thread);
 EXPORT_SYMBOL(kernel_thread);
 
@@ -203,4 +163,5 @@ EXPORT_SYMBOL(console_drivers);
 
 EXPORT_SYMBOL(tb_ticks_per_usec);
 EXPORT_SYMBOL(paca);
-EXPORT_SYMBOL(proc_ppc64);
+EXPORT_SYMBOL(cur_cpu_spec);
+EXPORT_SYMBOL(systemcfg);
--- diff/arch/ppc64/kernel/proc_pmc.c	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/ppc64/kernel/proc_pmc.c	2004-03-16 09:37:55.467107888 +0000
@@ -1,810 +0,0 @@
-/*
- * proc_pmc.c
- * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen 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) 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
- */
-
-
-/* Change Activity:
- * 2001       : mikec    : Created
- * 2001/06/05 : engebret : Software event count support.
- * End Change Activity 
- */
-
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-
-#include <asm/proc_fs.h>
-#include <asm/paca.h>
-#include <asm/iSeries/ItLpPaca.h>
-#include <asm/iSeries/ItLpQueue.h>
-#include <asm/iSeries/HvCallXm.h>
-#include <asm/iSeries/IoHriMainStore.h>
-#include <asm/processor.h>
-#include <asm/time.h>
-#include <asm/iSeries/LparData.h>
-#include <asm/pmc.h>
-#include <asm/uaccess.h>
-#include <asm/naca.h>
-#include <asm/rtas.h>
-
-
-static int proc_pmc_control_mode = 0;
-
-static struct proc_dir_entry *proc_ppc64_pmc_system_root = NULL;
-static struct proc_dir_entry *proc_ppc64_pmc_cpu_root[NR_CPUS] = {NULL, };
-
-static spinlock_t proc_ppc64_lock;
-int proc_ppc64_pmc_find_file(void *data);
-int proc_ppc64_pmc_read(char *page, char **start, off_t off,
-			int count, int *eof, char *buffer);
-int proc_ppc64_pmc_stab_read(char *page, char **start, off_t off,
-			     int count, int *eof, void *data);
-int proc_ppc64_pmc_htab_read(char *page, char **start, off_t off,
-			     int count, int *eof, void *data);
-int proc_ppc64_pmc_hw_read(char *page, char **start, off_t off, 
-			   int count, int *eof, void *data);
-
-static struct proc_dir_entry *pmc_proc_root = NULL;
-
-int proc_get_lpevents( char *page, char **start, off_t off, int count, int *eof, void *data);
-int proc_reset_lpevents( struct file *file, const char *buffer, unsigned long count, void *data);
-
-int proc_get_titanTod( char *page, char **start, off_t off, int count, int *eof, void *data);
-
-int proc_pmc_get_control( char *page, char **start, off_t off, int count, int *eof, void *data);
-
-int proc_pmc_set_control( struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_mmcr0( struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_mmcr1( struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_mmcra( struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_pmc1(  struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_pmc2(  struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_pmc3(  struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_pmc4(  struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_pmc5(  struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_pmc6(  struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_pmc7(  struct file *file, const char *buffer, unsigned long count, void *data);
-int proc_pmc_set_pmc8(  struct file *file, const char *buffer, unsigned long count, void *data);
-
-#if 0
-int proc_ppc64_init(void)
-{
-	unsigned long i;
-	struct proc_dir_entry *ent = NULL;
-	char buf[256];
-
-	printk("proc_ppc64: Creating /proc/ppc64/pmc\n");
-
-	/*
-	 * Create the root, system, and cpu directories as follows:
-	 *   /proc/ppc64/pmc/system 
-	 *   /proc/ppc64/pmc/cpu0 
-	 */
-	spin_lock(&proc_ppc64_lock);
-	if (proc_ppc64.root == NULL) {
-		proc_ppc64_init();
-		if (!proc_ppc64.root) {
-			spin_unlock(&proc_ppc64_lock);
-			return;
-		}
-	}
-	spin_unlock(&proc_ppc64_lock);
-
-	/* Placeholder for rtas interfaces. */
-	if (proc_ppc64.rtas == NULL) {
-		return;
-	}
-
-	proc_ppc64_pmc_root = proc_mkdir("pmc", proc_ppc64.root);
-
-	proc_ppc64_pmc_system_root = proc_mkdir("system", proc_ppc64_pmc_root);
-	for (i = 0; i < NR_CPUS; i++) {
-		if (cpu_online(i)) {
-			sprintf(buf, "cpu%ld", i); 
-			proc_ppc64_pmc_cpu_root[i] =
-				proc_mkdir(buf, proc_ppc64_pmc_root);
-		}
-	}
-
-	/* Create directories for the software counters. */
-	for (i = 0; i < NR_CPUS; i++) {
-		if (!cpu_online(i))
-			continue;
-		ent = create_proc_entry("stab", S_IRUGO | S_IWUSR, 
-					proc_ppc64_pmc_cpu_root[i]);
-		if (ent) {
-			ent->nlink = 1;
-			ent->data = (void *)proc_ppc64_pmc_cpu_root[i];
-			ent->read_proc = (void *)proc_ppc64_pmc_stab_read;
-			ent->write_proc = NULL;
-		}
-
-		ent = create_proc_entry("htab", S_IRUGO | S_IWUSR, 
-					proc_ppc64_pmc_cpu_root[i]);
-		if (ent) {
-			ent->nlink = 1;
-			ent->data = (void *)proc_ppc64_pmc_cpu_root[i];
-			ent->read_proc = (void *)proc_ppc64_pmc_htab_read;
-			ent->write_proc = NULL;
-		}
-	}
-
-	ent = create_proc_entry("stab", S_IRUGO | S_IWUSR, 
-				proc_ppc64_pmc_system_root);
-	if (ent) {
-		ent->nlink = 1;
-		ent->data = (void *)proc_ppc64_pmc_system_root;
-		ent->read_proc = (void *)proc_ppc64_pmc_stab_read;
-		ent->write_proc = NULL;
-	}
-
-	ent = create_proc_entry("htab", S_IRUGO | S_IWUSR, 
-				proc_ppc64_pmc_system_root);
-	if (ent) {
-		ent->nlink = 1;
-		ent->data = (void *)proc_ppc64_pmc_system_root;
-		ent->read_proc = (void *)proc_ppc64_pmc_htab_read;
-		ent->write_proc = NULL;
-	}
-
-	/* Create directories for the hardware counters. */
-	for (i = 0; i < NR_CPUS; i++) {
-		if (!cpu_online(i))
-			continue;
-		ent = create_proc_entry("hardware", S_IRUGO | S_IWUSR, 
-					proc_ppc64_pmc_cpu_root[i]);
-		if (ent) {
-			ent->nlink = 1;
-			ent->data = (void *)proc_ppc64_pmc_cpu_root[i];
-			ent->read_proc = (void *)proc_ppc64_pmc_hw_read;
-			ent->write_proc = NULL;
-		}
-	}
-
-	ent = create_proc_entry("hardware", S_IRUGO | S_IWUSR, 
-				proc_ppc64_pmc_system_root);
-	if (ent) {
-		ent->nlink = 1;
-		ent->data = (void *)proc_ppc64_pmc_system_root;
-		ent->read_proc = (void *)proc_ppc64_pmc_hw_read;
-		ent->write_proc = NULL;
-	}
-}
-#endif
-
-/*
- * Find the requested 'file' given a proc token.
- *
- * Inputs: void * data: proc token
- * Output: int        : (0, ..., +N) = CPU number.
- *                      -1           = System.
- */
-int proc_ppc64_pmc_find_file(void *data)
-{
-	int i;
-
-	if ((unsigned long)data == 
-	   (unsigned long) proc_ppc64_pmc_system_root) {
-		return(-1); 
-	} else {
-		for (i = 0; i < NR_CPUS; i++) {
-			if (!cpu_online(i))
-				continue;
-			if ((unsigned long)data ==
-			   (unsigned long)proc_ppc64_pmc_cpu_root[i]) {
-				return(i); 
-			}
-		}
-	}
-
-	/* On error, just default to a type of system. */
-	printk("proc_ppc64_pmc_find_file: failed to find file token.\n"); 
-	return(-1); 
-}
-
-int 
-proc_ppc64_pmc_read(char *page, char **start, off_t off, 
-		    int count, int *eof, char *buffer)
-{
-	int buffer_size, n;
-
-	if (count < 0) return 0;
-
-	if (buffer == NULL) {
-		*eof = 1;
-		return 0;
-	}
-
-	/* Check for read beyond EOF */
-	buffer_size = n = strlen(buffer);
-	if (off >= buffer_size) {
-		*eof = 1;
-		return 0;
-	}
-	if (n > (buffer_size - off)) n = buffer_size - off;
-
-	/* Never return more than was requested */
-	if (n > count) {
-		n = count;
-	} else {
-		*eof = 1;
-	}
-
-	memcpy(page, buffer + off, n);
-
-	*start = page;
-
-	return n;
-}
-
-int 
-proc_ppc64_pmc_stab_read(char *page, char **start, off_t off, 
-			 int count, int *eof, void *data)
-{
-	int n, file;
-	char *buffer = NULL;
-
-	if (count < 0) return 0;
-	spin_lock(&proc_ppc64_lock);
-
-	/* Figure out which file is being request. */
-	file = proc_ppc64_pmc_find_file(data);
-
-	/* Update the counters and the text buffer representation. */
-	buffer = ppc64_pmc_stab(file);
-
-	/* Put the data into the requestor's buffer. */
-	n = proc_ppc64_pmc_read(page, start, off, count, eof, buffer); 
-
-	spin_unlock(&proc_ppc64_lock);
-	return n;
-}
-
-int 
-proc_ppc64_pmc_htab_read(char *page, char **start, off_t off, 
-			 int count, int *eof, void *data)
-{
-	int n, file;
-	char *buffer = NULL;
-
-	if (count < 0) return 0;
-	spin_lock(&proc_ppc64_lock);
-
-	/* Figure out which file is being request. */
-	file = proc_ppc64_pmc_find_file(data);
-
-	/* Update the counters and the text buffer representation. */
-	buffer = ppc64_pmc_htab(file);
-
-	/* Put the data into the requestor's buffer. */
-	n = proc_ppc64_pmc_read(page, start, off, count, eof, buffer);
-
-	spin_unlock(&proc_ppc64_lock);
-	return n;
-}
-
-int 
-proc_ppc64_pmc_hw_read(char *page, char **start, off_t off, 
-			     int count, int *eof, void *data)
-{
-	int n, file;
-	char *buffer = NULL;
-
-	if (count < 0) return 0;
-	spin_lock(&proc_ppc64_lock);
-
-	/* Figure out which file is being request. */
-	file = proc_ppc64_pmc_find_file(data);
-
-	/* Update the counters and the text buffer representation. */
-	buffer = ppc64_pmc_hw(file);
-
-	/* Put the data into the requestor's buffer. */
-	n = proc_ppc64_pmc_read(page, start, off, count, eof, buffer);
-
-	spin_unlock(&proc_ppc64_lock);
-	return n;
-}
-
-/* 
- * DRENG the remainder of these functions still need work ...
- */
-void pmc_proc_init(struct proc_dir_entry *iSeries_proc)
-{
-    struct proc_dir_entry *ent = NULL;
-
-    ent = create_proc_entry("lpevents", S_IFREG|S_IRUGO, iSeries_proc);
-    if (!ent) return;
-    ent->nlink = 1;
-    ent->data = (void *)0;
-    ent->read_proc = proc_get_lpevents;
-    ent->write_proc = proc_reset_lpevents;
-
-    ent = create_proc_entry("titanTod", S_IFREG|S_IRUGO, iSeries_proc);
-    if (!ent) return;
-    ent->nlink = 1;
-    ent->data = (void *)0;
-    ent->size = 0;
-    ent->read_proc = proc_get_titanTod;
-    ent->write_proc = NULL;
-
-    pmc_proc_root = proc_mkdir("pmc", iSeries_proc);
-    if (!pmc_proc_root) return;
-
-    ent = create_proc_entry("control", S_IFREG|S_IRUSR|S_IWUSR, pmc_proc_root);
-    if (!ent) return;
-    ent->nlink = 1;
-    ent->data = (void *)0;
-    ent->read_proc = proc_pmc_get_control;
-    ent->write_proc = proc_pmc_set_control;
-
-}
-
-static int pmc_calc_metrics( char *page, char **start, off_t off, int count, int *eof, int len)
-{
-	if ( len <= off+count)
-		*eof = 1;
-	*start = page+off;
-	len -= off;
-	if ( len > count )
-		len = count;
-	if ( len < 0 )
-		len = 0;
-	return len;
-}
-
-static char * lpEventTypes[9] = {
-	"Hypervisor\t\t",
-	"Machine Facilities\t",
-	"Session Manager\t",
-	"SPD I/O\t\t",
-	"Virtual Bus\t\t",
-	"PCI I/O\t\t",
-	"RIO I/O\t\t",
-	"Virtual Lan\t\t",
-	"Virtual I/O\t\t"
-	};
-	
-
-int proc_get_lpevents
-(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	unsigned i;
-	int len = 0;
-
-	len += sprintf( page+len, "LpEventQueue 0\n" );
-	len += sprintf( page+len, "  events processed:\t%lu\n",
-			(unsigned long)xItLpQueue.xLpIntCount );
-	for (i=0; i<9; ++i) {
-		len += sprintf( page+len, "    %s %10lu\n",
-			lpEventTypes[i],
-			(unsigned long)xItLpQueue.xLpIntCountByType[i] );
-	}
-	len += sprintf( page+len, "\n  events processed by processor:\n" );
-	for (i = 0; i < NR_CPUS; ++i) {
-		if (cpu_online(i))
-			len += sprintf( page+len, "    CPU%02d  %10u\n",
-				i, paca[i].lpEvent_count );
-	}
-
-	return pmc_calc_metrics( page, start, off, count, eof, len );
-
-}
-
-int proc_reset_lpevents( struct file *file, const char *buffer, unsigned long count, void *data )
-{
-	return count;
-}
-
-static unsigned long startTitan = 0;
-static unsigned long startTb = 0;
-
-
-int proc_get_titanTod
-(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	int len = 0;
-	unsigned long tb0, titan_tod;
-
-	tb0 = get_tb();
-	titan_tod = HvCallXm_loadTod();
-
-	len += sprintf( page+len, "Titan\n" );
-	len += sprintf( page+len, "  time base =          %016lx\n", tb0 );
-	len += sprintf( page+len, "  titan tod =          %016lx\n", titan_tod );
-	len += sprintf( page+len, "  xProcFreq =          %016x\n", xIoHriProcessorVpd[0].xProcFreq );
-	len += sprintf( page+len, "  xTimeBaseFreq =      %016x\n", xIoHriProcessorVpd[0].xTimeBaseFreq );
-	len += sprintf( page+len, "  tb_ticks_per_jiffy = %lu\n", tb_ticks_per_jiffy );
-	len += sprintf( page+len, "  tb_ticks_per_usec  = %lu\n", tb_ticks_per_usec );
-
-	if ( !startTitan ) {
-		startTitan = titan_tod;
-		startTb = tb0;
-	}
-	else {
-		unsigned long titan_usec = (titan_tod - startTitan) >> 12;
-		unsigned long tb_ticks = (tb0 - startTb);
-		unsigned long titan_jiffies = titan_usec / (1000000/HZ);
-		unsigned long titan_jiff_usec = titan_jiffies * (1000000/HZ);
-		unsigned long titan_jiff_rem_usec = titan_usec - titan_jiff_usec;
-		unsigned long tb_jiffies = tb_ticks / tb_ticks_per_jiffy;
-		unsigned long tb_jiff_ticks = tb_jiffies * tb_ticks_per_jiffy;
-		unsigned long tb_jiff_rem_ticks = tb_ticks - tb_jiff_ticks;
-		unsigned long tb_jiff_rem_usec = tb_jiff_rem_ticks / tb_ticks_per_usec;
-		unsigned long new_tb_ticks_per_jiffy = (tb_ticks * (1000000/HZ))/titan_usec;
-		
-		len += sprintf( page+len, "  titan elapsed = %lu uSec\n", titan_usec);
-		len += sprintf( page+len, "  tb elapsed    = %lu ticks\n", tb_ticks);
-		len += sprintf( page+len, "  titan jiffies = %lu.%04lu \n", titan_jiffies, titan_jiff_rem_usec );				
-		len += sprintf( page+len, "  tb jiffies    = %lu.%04lu\n", tb_jiffies, tb_jiff_rem_usec );
-		len += sprintf( page+len, "  new tb_ticks_per_jiffy = %lu\n", new_tb_ticks_per_jiffy );	
-
-	}
-	
-	return pmc_calc_metrics( page, start, off, count, eof, len );
-}
-	
-int proc_pmc_get_control
-(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	int len = 0;
-
-	if ( proc_pmc_control_mode == PMC_CONTROL_CPI ) {
-		unsigned long mach_cycles   = mfspr( PMC5 );
-		unsigned long inst_complete = mfspr( PMC4 );
-		unsigned long inst_dispatch = mfspr( PMC3 );
-		unsigned long thread_active_run = mfspr( PMC1 );
-		unsigned long thread_active  = mfspr( PMC2 );
-		unsigned long cpi = 0;
-		unsigned long cpithou = 0;
-		unsigned long remain;
-	
-		if ( inst_complete ) {
-			cpi = thread_active_run / inst_complete;
-			remain = thread_active_run % inst_complete;
-			if ( inst_complete > 1000000 ) 
-				cpithou = remain / ( inst_complete / 1000 );
-			else 
-				cpithou = ( remain * 1000 ) / inst_complete;
-		}
-		len += sprintf( page+len, "PMC CPI Mode\nRaw Counts\n" );
-		len += sprintf( page+len, "machine cycles           : %12lu\n", mach_cycles );
-		len += sprintf( page+len, "thread active cycles     : %12lu\n\n", thread_active );
-
-		len += sprintf( page+len, "instructions completed   : %12lu\n", inst_complete );
-		len += sprintf( page+len, "instructions dispatched  : %12lu\n", inst_dispatch );
-		len += sprintf( page+len, "thread active run cycles : %12lu\n", thread_active_run );
-
-		len += sprintf( page+len, "thread active run cycles/instructions completed\n" );
-		len += sprintf( page+len, "CPI = %lu.%03lu\n", cpi, cpithou );
-		
-	}
-	else if ( proc_pmc_control_mode == PMC_CONTROL_TLB ) {
-		len += sprintf( page+len, "PMC TLB Mode\n" );
-		len += sprintf( page+len, "I-miss count             : %12lu\n", mfspr( PMC1 ) );
-		len += sprintf( page+len, "I-miss latency           : %12lu\n", mfspr( PMC2 ) );
-		len += sprintf( page+len, "D-miss count             : %12lu\n", mfspr( PMC3 ) );
-		len += sprintf( page+len, "D-miss latency           : %12lu\n", mfspr( PMC4 ) );
-		len += sprintf( page+len, "IERAT miss count         : %12lu\n", mfspr( PMC5 ) );
-		len += sprintf( page+len, "D-reference count        : %12lu\n", mfspr( PMC6 ) );
-		len += sprintf( page+len, "miss PTEs searched       : %12lu\n", mfspr( PMC7 ) );
-		len += sprintf( page+len, "miss >8 PTEs searched    : %12lu\n", mfspr( PMC8 ) );
-	}
-	/* IMPLEMENT ME */
-	return pmc_calc_metrics( page, start, off, count, eof, len );
-}
-
-unsigned long proc_pmc_conv_int( const char *buf, unsigned count )
-{
-	const char * p;
-	char b0, b1;
-	unsigned v, multiplier, mult, i;
-	unsigned long val;
-	multiplier = 10;
-	p = buf;
-	if ( count >= 3 ) {
-		b0 = buf[0];
-		b1 = buf[1];
-		if ( ( b0 == '0' ) &&
-		     ( ( b1 == 'x' ) || ( b1 == 'X' ) ) ) {
-			p = buf + 2;
-			count -= 2;
-			multiplier = 16;
-		}
-			
-	}
-	val = 0;
-	for ( i=0; i<count; ++i ) {
-		b0 = *p++;
-		v = 0;
-		mult = multiplier;
-		if ( ( b0 >= '0' ) && ( b0 <= '9' ) ) 
-			v = b0 - '0';
-		else if ( multiplier == 16 ) {
-			if ( ( b0 >= 'a' ) && ( b0 <= 'f' ) )
-				v = b0 - 'a' + 10;
-			else if ( ( b0 >= 'A' ) && ( b0 <= 'F' ) )
-				v = b0 - 'A' + 10;
-			else 
-				mult = 1;
-		}
-		else
-			mult = 1;
-		val *= mult;
-		val += v;
-	}
-
-	return val;
-
-}
-
-static inline void proc_pmc_stop(void)
-{
-	/* Freeze all counters, leave everything else alone */
-	mtspr( MMCR0, mfspr( MMCR0 ) | 0x80000000 );
-}
-
-static inline void proc_pmc_start(void)
-{
-	/* Unfreeze all counters, leave everything else alone */
-	mtspr( MMCR0, mfspr( MMCR0 ) & ~0x80000000 );
-
-}
-
-static inline void proc_pmc_reset(void)
-{
-	/* Clear all the PMCs to zeros 
-	 * Assume a "stop" has already frozen the counters
-	 * Clear all the PMCs
-	 */
-	mtspr( PMC1, 0 );
-	mtspr( PMC2, 0 );
-	mtspr( PMC3, 0 );
-	mtspr( PMC4, 0 );
-	mtspr( PMC5, 0 );
-	mtspr( PMC6, 0 );
-	mtspr( PMC7, 0 );
-	mtspr( PMC8, 0 );
-
-}
-
-static inline void proc_pmc_cpi(void)
-{
-	/* Configure the PMC registers to count cycles and instructions */
-	/* so we can compute cpi */
-	/*
-	 * MMCRA[30]    = 1     Don't count in wait state (CTRL[31]=0)
-	 * MMCR0[6]     = 1     Freeze counters when any overflow
-	 * MMCR0[19:25] = 0x01  PMC1 counts Thread Active Run Cycles
-	 * MMCR0[26:31] = 0x05	PMC2 counts Thread Active Cycles
-	 * MMCR1[0:4]   = 0x07	PMC3 counts Instructions Dispatched
-	 * MMCR1[5:9]   = 0x03	PMC4 counts Instructions Completed
-	 * MMCR1[10:14] = 0x06	PMC5 counts Machine Cycles
-	 *
-	 */
-
-	proc_pmc_control_mode = PMC_CONTROL_CPI;
-	
-	/* Indicate to hypervisor that we are using the PMCs */
-	get_paca()->xLpPacaPtr->xPMCRegsInUse = 1;
-
-	/* Freeze all counters */
-	mtspr( MMCR0, 0x80000000 );
-	mtspr( MMCR1, 0x00000000 );
-	
-	/* Clear all the PMCs */
-	mtspr( PMC1, 0 );
-	mtspr( PMC2, 0 );
-	mtspr( PMC3, 0 );
-	mtspr( PMC4, 0 );
-	mtspr( PMC5, 0 );
-	mtspr( PMC6, 0 );
-	mtspr( PMC7, 0 );
-	mtspr( PMC8, 0 );
-
-	/* Freeze counters in Wait State (CTRL[31]=0) */
-	mtspr( MMCRA, 0x00000002 );
-
-	/* PMC3<-0x07, PMC4<-0x03, PMC5<-0x06 */
-	mtspr( MMCR1, 0x38cc0000 );
-
-	mb();
-	
-	/* PMC1<-0x01, PMC2<-0x05
-	 * Start all counters
-	 */
-	mtspr( MMCR0, 0x02000045 );
-	
-}
-
-static inline void proc_pmc_tlb(void)
-{
-	/* Configure the PMC registers to count tlb misses  */
-	/*
-	 * MMCR0[6]     = 1     Freeze counters when any overflow
-	 * MMCR0[19:25] = 0x55  Group count
-	 *   PMC1 counts  I misses
-	 *   PMC2 counts  I miss duration (latency)
-	 *   PMC3 counts  D misses
-	 *   PMC4 counts  D miss duration (latency)
-	 *   PMC5 counts  IERAT misses
-	 *   PMC6 counts  D references (including PMC7)
-	 *   PMC7 counts  miss PTEs searched
-	 *   PMC8 counts  miss >8 PTEs searched
-	 *   
-	 */
-
-	proc_pmc_control_mode = PMC_CONTROL_TLB;
-	
-	/* Indicate to hypervisor that we are using the PMCs */
-	get_paca()->xLpPacaPtr->xPMCRegsInUse = 1;
-
-	/* Freeze all counters */
-	mtspr( MMCR0, 0x80000000 );
-	mtspr( MMCR1, 0x00000000 );
-	
-	/* Clear all the PMCs */
-	mtspr( PMC1, 0 );
-	mtspr( PMC2, 0 );
-	mtspr( PMC3, 0 );
-	mtspr( PMC4, 0 );
-	mtspr( PMC5, 0 );
-	mtspr( PMC6, 0 );
-	mtspr( PMC7, 0 );
-	mtspr( PMC8, 0 );
-
-	mtspr( MMCRA, 0x00000000 );
-
-	mb();
-	
-	/* PMC1<-0x55
-	 * Start all counters
-	 */
-	mtspr( MMCR0, 0x02001540 );
-	
-}
-
-int proc_pmc_set_control( struct file *file, const char *buffer, unsigned long count, void *data )
-{
-	char stkbuf[10];
-	if (count > 9) count = 9;
-	if (copy_from_user (stkbuf, buffer, count)) {
-		return -EFAULT;
-	}
-	stkbuf[count] = 0;
-
-	if      ( ! strncmp( stkbuf, "stop", 4 ) )
-		proc_pmc_stop();
-	else if ( ! strncmp( stkbuf, "start", 5 ) )
-		proc_pmc_start();
-	else if ( ! strncmp( stkbuf, "reset", 5 ) )
-		proc_pmc_reset();
-	else if ( ! strncmp( stkbuf, "cpi", 3 ) )
-		proc_pmc_cpi();
-	else if ( ! strncmp( stkbuf, "tlb", 3 ) )
-		proc_pmc_tlb();
-	
-	/* IMPLEMENT ME */
-	return count;
-}
-
-int proc_pmc_set_mmcr0( struct file *file, const char *buffer, unsigned long count, void *data )
-{
-	unsigned long v;
-	v = proc_pmc_conv_int( buffer, count );
-	v = v & ~0x04000000;	/* Don't allow interrupts for now */
-	if ( v & ~0x80000000 ) 	/* Inform hypervisor we are using PMCs */
-		get_paca()->xLpPacaPtr->xPMCRegsInUse = 1;
-	else
-		get_paca()->xLpPacaPtr->xPMCRegsInUse = 0;
-	mtspr( MMCR0, v );
-	
-	return count;	
-}
-
-int proc_pmc_set_mmcr1( struct file *file, const char *buffer, unsigned long count, void *data )
-{
-	unsigned long v;
-	v = proc_pmc_conv_int( buffer, count );
-	mtspr( MMCR1, v );
-
-	return count;
-}
-
-int proc_pmc_set_mmcra( struct file *file, const char *buffer, unsigned long count, void *data )
-{
-	unsigned long v;
-	v = proc_pmc_conv_int( buffer, count );
-	v = v & ~0x00008000;	/* Don't allow interrupts for now */
-	mtspr( MMCRA, v );
-
-	return count;
-}
-
-
-int proc_pmc_set_pmc1( struct file *file, const char *buffer, unsigned long count, void *data )
-{
-	unsigned long v;
-	v = proc_pmc_conv_int( buffer, count );
-	mtspr( PMC1, v );
-
-	return count;
-}
-
-int proc_pmc_set_pmc2( struct file *file, const char *buffer, unsigned long count, void *data )
-{
-	unsigned long v;
-	v = proc_pmc_conv_int( buffer, count );
-	mtspr( PMC2, v );
-
-	return count;
-}
-
-int proc_pmc_set_pmc3( struct file *file, const char *buffer, unsigned long count, void *data )
-{
-	unsigned long v;
-	v = proc_pmc_conv_int( buffer, count );
-	mtspr( PMC3, v );
-
-	return count;
-}
-
-int proc_pmc_set_pmc4( struct file *file, const char *buffer, unsigned long count, void *data )
-{
-	unsigned long v;
-	v = proc_pmc_conv_int( buffer, count );
-	mtspr( PMC4, v );
-
-	return count;
-}
-
-int proc_pmc_set_pmc5( struct file *file, const char *buffer, unsigned long count, void *data )
-{
-	unsigned long v;
-	v = proc_pmc_conv_int( buffer, count );
-	mtspr( PMC5, v );
-
-	return count;
-}
-
-int proc_pmc_set_pmc6( struct file *file, const char *buffer, unsigned long count, void *data )
-{
-	unsigned long v;
-	v = proc_pmc_conv_int( buffer, count );
-	mtspr( PMC6, v );
-
-	return count;
-}
-
-int proc_pmc_set_pmc7( struct file *file, const char *buffer, unsigned long count, void *data )
-{
-	unsigned long v;
-	v = proc_pmc_conv_int( buffer, count );
-	mtspr( PMC7, v );
-
-	return count;
-}
-
-int proc_pmc_set_pmc8( struct file *file, const char *buffer, unsigned long count, void *data )
-{
-	unsigned long v;
-	v = proc_pmc_conv_int( buffer, count );
-	mtspr( PMC8, v );
-
-	return count;
-}
-
--- diff/arch/ppc64/kernel/proc_ppc64.c	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/ppc64/kernel/proc_ppc64.c	2004-03-16 09:37:55.468107736 +0000
@@ -18,15 +18,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-
-/*
- * Change Activity:
- * 2001       : mikec    : Created
- * 2001/06/05 : engebret : Software event count support.
- * 2003/02/13 : bergner  : Move PMC code to pmc.c
- * End Change Activity 
- */
-
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/mm.h>
@@ -34,7 +25,6 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 
-#include <asm/proc_fs.h>
 #include <asm/naca.h>
 #include <asm/paca.h>
 #include <asm/systemcfg.h>
@@ -42,10 +32,6 @@
 #include <asm/uaccess.h>
 #include <asm/prom.h>
 
-struct proc_ppc64_t proc_ppc64;
-
-void proc_ppc64_create_paca(int num);
-
 static loff_t  page_map_seek( struct file *file, loff_t off, int whence);
 static ssize_t page_map_read( struct file *file, char *buf, size_t nbytes, loff_t *ppos);
 static int     page_map_mmap( struct file *file, struct vm_area_struct *vma );
@@ -59,7 +45,7 @@ static struct file_operations page_map_f
 #ifdef CONFIG_PPC_PSERIES
 /* routines for /proc/ppc64/ofdt */
 static ssize_t ofdt_write(struct file *, const char __user *, size_t, loff_t *);
-static void proc_ppc64_create_ofdt(struct proc_dir_entry *);
+static void proc_ppc64_create_ofdt(void);
 static int do_remove_node(char *);
 static int do_add_node(char *, size_t);
 static void release_prop_list(const struct property *);
@@ -70,77 +56,19 @@ static struct file_operations ofdt_fops 
 };
 #endif
 
-int __init proc_ppc64_init(void)
-{
-
-
-	if (proc_ppc64.root == NULL) {
-		printk(KERN_INFO "proc_ppc64: Creating /proc/ppc64/\n");
-		proc_ppc64.root = proc_mkdir("ppc64", 0);
-		if (!proc_ppc64.root)
-			return 0;
-	} else {
-		return 0;
-	}
-
-	proc_ppc64.naca = create_proc_entry("naca", S_IRUSR, proc_ppc64.root);
-	if ( proc_ppc64.naca ) {
-		proc_ppc64.naca->nlink = 1;
-		proc_ppc64.naca->data = naca;
-		proc_ppc64.naca->size = 4096;
-		proc_ppc64.naca->proc_fops = &page_map_fops;
-	}
-	
-	proc_ppc64.systemcfg = create_proc_entry("systemcfg", S_IFREG|S_IRUGO, proc_ppc64.root);
-	if ( proc_ppc64.systemcfg ) {
-		proc_ppc64.systemcfg->nlink = 1;
-		proc_ppc64.systemcfg->data = systemcfg;
-		proc_ppc64.systemcfg->size = 4096;
-		proc_ppc64.systemcfg->proc_fops = &page_map_fops;
-	}
-
-	/* /proc/ppc64/paca/XX -- raw paca contents.  Only readable to root */
-	proc_ppc64.paca = proc_mkdir("paca", proc_ppc64.root);
-	if (proc_ppc64.paca) {
-		unsigned long i;
-
-		for (i = 0; i < NR_CPUS; i++) {
-			if (!cpu_online(i))
-				continue;
-			proc_ppc64_create_paca(i);
-		}
-	}
-
-#ifdef CONFIG_PPC_PSERIES
-	/* Placeholder for rtas interfaces. */
-	if (proc_ppc64.rtas == NULL)
-		proc_ppc64.rtas = proc_mkdir("rtas", proc_ppc64.root);
-
-	if (proc_ppc64.rtas)
-		proc_symlink("rtas", 0, "ppc64/rtas");
-
-	proc_ppc64_create_ofdt(proc_ppc64.root);
-#endif
-
-	return 0;
-}
-
-
 /*
- * NOTE: since paca data is always in flux the values will never be a consistant set.
- * In theory it could be made consistent if we made the corresponding cpu
- * copy the page for us (via an IPI).  Probably not worth it.
- *
+ * NOTE: since paca data is always in flux the values will never be a
+ * consistant set.
  */
-void proc_ppc64_create_paca(int num)
+static void __init proc_create_paca(struct proc_dir_entry *dir, int num)
 {
 	struct proc_dir_entry *ent;
 	struct paca_struct *lpaca = paca + num;
 	char buf[16];
 
 	sprintf(buf, "%02x", num);
-	ent = create_proc_entry(buf, S_IRUSR, proc_ppc64.paca);
-	if ( ent ) {
+	ent = create_proc_entry(buf, S_IRUSR, dir);
+	if (ent) {
 		ent->nlink = 1;
 		ent->data = lpaca;
 		ent->size = 4096;
@@ -148,6 +76,67 @@ void proc_ppc64_create_paca(int num)
 	}
 }
 
+/*
+ * Create the ppc64 and ppc64/rtas directories early. This allows us to
+ * assume that they have been previously created in drivers.
+ */
+static int __init proc_ppc64_create(void)
+{
+	struct proc_dir_entry *root;
+
+	root = proc_mkdir("ppc64", 0);
+	if (!root)
+		return 1;
+
+	if (!(systemcfg->platform & PLATFORM_PSERIES))
+		return 0;
+
+	if (!proc_mkdir("rtas", root))
+		return 1;
+
+	if (!proc_symlink("rtas", 0, "ppc64/rtas"))
+		return 1;
+
+	return 0;
+}
+core_initcall(proc_ppc64_create);
+
+static int __init proc_ppc64_init(void)
+{
+	unsigned long i;
+	struct proc_dir_entry *pde;
+
+	pde = create_proc_entry("ppc64/naca", S_IRUSR, NULL);
+	if (!pde)
+		return 1;
+	pde->nlink = 1;
+	pde->data = naca;
+	pde->size = 4096;
+	pde->proc_fops = &page_map_fops;
+
+	pde = create_proc_entry("ppc64/systemcfg", S_IFREG|S_IRUGO, NULL);
+	if (!pde)
+		return 1;
+	pde->nlink = 1;
+	pde->data = systemcfg;
+	pde->size = 4096;
+	pde->proc_fops = &page_map_fops;
+
+	/* /proc/ppc64/paca/XX -- raw paca contents.  Only readable to root */
+	pde = proc_mkdir("ppc64/paca", NULL);
+	if (!pde)
+		return 1;
+	for_each_cpu(i)
+		proc_create_paca(pde, i);
+
+#ifdef CONFIG_PPC_PSERIES
+	if ((systemcfg->platform & PLATFORM_PSERIES))
+		proc_ppc64_create_ofdt();
+#endif
+
+	return 0;
+}
+__initcall(proc_ppc64_init);
 
 static loff_t page_map_seek( struct file *file, loff_t off, int whence)
 {
@@ -204,11 +193,11 @@ static int page_map_mmap( struct file *f
 
 #ifdef CONFIG_PPC_PSERIES
 /* create /proc/ppc64/ofdt write-only by root */
-static void proc_ppc64_create_ofdt(struct proc_dir_entry *parent)
+static void proc_ppc64_create_ofdt(void)
 {
 	struct proc_dir_entry *ent;
 
-	ent = create_proc_entry("ofdt", S_IWUSR, parent);
+	ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL);
 	if (ent) {
 		ent->nlink = 1;
 		ent->data = NULL;
@@ -423,5 +412,3 @@ static void release_prop_list(const stru
 
 }
 #endif	/* defined(CONFIG_PPC_PSERIES) */
-
-fs_initcall(proc_ppc64_init);
--- diff/arch/ppc64/kernel/process.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/process.c	2004-03-16 09:37:55.468107736 +0000
@@ -34,6 +34,7 @@
 #include <linux/prctl.h>
 #include <linux/ptrace.h>
 #include <linux/kallsyms.h>
+#include <linux/version.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -193,8 +194,8 @@ void show_regs(struct pt_regs * regs)
 
 	printk("NIP: %016lX XER: %016lX LR: %016lX\n",
 	       regs->nip, regs->xer, regs->link);
-	printk("REGS: %p TRAP: %04lx    %s\n",
-	       regs, regs->trap, print_tainted());
+	printk("REGS: %p TRAP: %04lx   %s  (%s)\n",
+	       regs, regs->trap, print_tainted(), UTS_RELEASE);
 	printk("MSR: %016lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
 	       regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
 	       regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
--- diff/arch/ppc64/kernel/prom.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/prom.c	2004-03-16 09:37:55.475106672 +0000
@@ -2853,40 +2853,12 @@ int of_remove_node(struct device_node *n
 	struct device_node *parent, *child;
 
 	parent = of_get_parent(np);
-
 	if (!parent)
 		return -EINVAL;
 
-	/* Make sure we are not recursively removing
-	 * more than one level of nodes.  We need to
-	 * allow this so we can remove a slot containing
-	 * an IOA.
-	 */
-	for (child = of_get_next_child(np, NULL);
-	     child != NULL;
-	     child = of_get_next_child(np, child)) {
-		struct device_node *grandchild;
-
-		if ((grandchild = of_get_next_child(child, NULL))) {
-			/* Too deep */
-			of_node_put(grandchild);
-			of_node_put(child);
-			return -EBUSY;
-		}
-	}
-
-	/* Now that we're reasonably sure that we won't
-	 * overflow our stack, remove any children of np.
-	 */
-	for (child = of_get_next_child(np, NULL);
-	     child != NULL;
-	     child = of_get_next_child(np, child)) {
-		int rc;
-
-		if ((rc = of_remove_node(child))) {
-			of_node_put(child);
-			return rc;
-		}
+	if ((child = of_get_next_child(np, NULL))) {
+		of_node_put(child);
+		return -EBUSY;
 	}
 
 	write_lock(&devtree_lock);
@@ -2964,6 +2936,53 @@ static void remove_node_proc_entries(str
 #endif /* CONFIG_PROC_DEVICETREE */
 
 /*
+ * Fix up n_intrs and intrs fields in a new device node
+ *
+ */
+static int of_finish_dynamic_node_interrupts(struct device_node *node)
+{
+	int intrcells, intlen, i;
+	unsigned *irq, *ints, virq;
+	struct device_node *ic;
+
+	ints = (unsigned int *)get_property(node, "interrupts", &intlen);
+	intrcells = prom_n_intr_cells(node);
+	intlen /= intrcells * sizeof(unsigned int);
+	node->n_intrs = intlen;
+	node->intrs = kmalloc(sizeof(struct interrupt_info) * intlen,
+			      GFP_KERNEL);
+	if (!node->intrs)
+		return -ENOMEM;
+
+	for (i = 0; i < intlen; ++i) {
+		int n, j;
+		node->intrs[i].line = 0;
+		node->intrs[i].sense = 1;
+		n = map_interrupt(&irq, &ic, node, ints, intrcells);
+		if (n <= 0)
+			continue;
+		virq = virt_irq_create_mapping(irq[0]);
+		if (virq == NO_IRQ) {
+			printk(KERN_CRIT "Could not allocate interrupt "
+			       "number for %s\n", node->full_name);
+			return -ENOMEM;
+		}
+		node->intrs[i].line = openpic_to_irq(virq);
+		if (n > 1)
+			node->intrs[i].sense = irq[1];
+		if (n > 2) {
+			printk(KERN_DEBUG "hmmm, got %d intr cells for %s:", n,
+			       node->full_name);
+			for (j = 0; j < n; ++j)
+				printk(" %d", irq[j]);
+			printk("\n");
+		}
+		ints += intrcells;
+	}
+	return 0;
+}
+
+/*
  * Fix up the uninitialized fields in a new device node:
  * name, type, n_addrs, addrs, n_intrs, intrs, and pci-specific fields
  *
@@ -2978,11 +2997,8 @@ static int of_finish_dynamic_node(struct
 {
 	struct device_node *parent = of_get_parent(node);
 	u32 *regs;
-	unsigned int *ints;
-	int intlen, intrcells;
-	int i, j, n, err = 0;
-	unsigned int *irq, virq;
-	struct device_node *ic;
+	int err = 0;
+	phandle *ibm_phandle;
  
 	node->name = get_property(node, "name", 0);
 	node->type = get_property(node, "device_type", 0);
@@ -2998,6 +3014,10 @@ static int of_finish_dynamic_node(struct
 	if (systemcfg->platform == PLATFORM_POWERMAC)
 		return -ENODEV;
 
+	/* fix up new node's linux_phandle field */
+	if ((ibm_phandle = (unsigned int *)get_property(node, "ibm,phandle", NULL)))
+		node->linux_phandle = *ibm_phandle;
+
 	/* do the work of interpret_pci_props */
 	if (parent->type && !strcmp(parent->type, "pci")) {
 		struct address_range *adr;
@@ -3027,45 +3047,9 @@ static int of_finish_dynamic_node(struct
 	}
 
 	/* now do the work of finish_node_interrupts */
-
-	ints = (unsigned int *) get_property(node, "interrupts", &intlen);
-	if (!ints) {
-		err = -ENODEV;
-		goto out;
-	}
-
-	intrcells = prom_n_intr_cells(node);
-	intlen /= intrcells * sizeof(unsigned int);
-	node->n_intrs = intlen;
-	node->intrs = kmalloc(sizeof(struct interrupt_info) * intlen,
-			      GFP_KERNEL);
-	if (!node->intrs) {
-		err = -ENOMEM;
-		goto out;
-	}
-
-	for (i = 0; i < intlen; ++i) {
-		node->intrs[i].line = 0;
-		node->intrs[i].sense = 1;
-		n = map_interrupt(&irq, &ic, node, ints, intrcells);
-		if (n <= 0)
-			continue;
-		virq = virt_irq_create_mapping(irq[0]);
-		if (virq == NO_IRQ) {
-			printk(KERN_CRIT "Could not allocate interrupt "
-			       "number for %s\n", node->full_name);
-		} else
-			node->intrs[i].line = openpic_to_irq(virq);
-		if (n > 1)
-			node->intrs[i].sense = irq[1];
-		if (n > 2) {
-			printk(KERN_DEBUG "hmmm, got %d intr cells for %s:", n,
-			       node->full_name);
-			for (j = 0; j < n; ++j)
-				printk(" %d", irq[j]);
-			printk("\n");
-		}
-		ints += intrcells;
+	if (get_property(node, "interrupts", 0)) {
+		err = of_finish_dynamic_node_interrupts(node);
+		if (err) goto out;
 	}
 
        /* now do the rough equivalent of update_dn_pci_info, this
--- diff/arch/ppc64/kernel/ptrace.c	2003-02-26 16:01:01.000000000 +0000
+++ source/arch/ppc64/kernel/ptrace.c	2004-03-16 09:37:55.476106520 +0000
@@ -26,6 +26,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/security.h>
+#include <linux/audit.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -286,12 +287,8 @@ out:
 	return ret;
 }
 
-void do_syscall_trace(void)
+static void do_syscall_trace(void)
 {
-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
-		return;
-	if (!(current->ptrace & PT_PTRACED))
-		return;
 	/* the 0x80 provides a way for the tracing parent to distinguish
 	   between a syscall stop and SIGTRAP delivery */
 	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
@@ -307,3 +304,23 @@ void do_syscall_trace(void)
 		current->exit_code = 0;
 	}
 }
+
+void do_syscall_trace_enter(struct pt_regs *regs)
+{
+	if (unlikely(current->audit_context))
+		audit_syscall_entry(current, regs->gpr[0], regs->gpr[3]);
+
+	if (test_thread_flag(TIF_SYSCALL_TRACE)
+	    && (current->ptrace & PT_PTRACED))
+		do_syscall_trace();
+}
+
+void do_syscall_trace_leave(void)
+{
+	if (unlikely(current->audit_context))
+		audit_syscall_exit(current);
+
+	if (test_thread_flag(TIF_SYSCALL_TRACE)
+	    && (current->ptrace & PT_PTRACED))
+		do_syscall_trace();
+}
--- diff/arch/ppc64/kernel/ras.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/ras.c	2004-03-16 09:37:55.476106520 +0000
@@ -36,7 +36,6 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/irq.h>
-#include <linux/proc_fs.h>
 #include <linux/random.h>
 #include <linux/sysrq.h>
 
--- diff/arch/ppc64/kernel/rtas-proc.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/rtas-proc.c	2004-03-16 09:37:55.477106368 +0000
@@ -28,7 +28,6 @@
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/rtas.h>
-#include <asm/proc_fs.h>
 #include <asm/machdep.h> /* for ppc_md */
 #include <asm/time.h>
 
@@ -117,8 +116,6 @@
 
 
 /* Globals */
-extern struct proc_dir_entry *proc_rtas;
-
 static struct rtas_sensors sensors;
 static struct device_node *rtas_node = NULL;
 static unsigned long power_on_time = 0; /* Save the time the user set */
@@ -201,51 +198,50 @@ int get_location_code(struct individual_
 int check_location_string (char *c, char * buf);
 int check_location (char *c, int idx, char * buf);
 
-/* ****************************************************************** */
-/* MAIN                                                               */
-/* ****************************************************************** */
-void proc_rtas_init(void)
+static int __init proc_rtas_init(void)
 {
 	struct proc_dir_entry *entry;
 
-	rtas_node = of_find_node_by_name(NULL, "rtas");
-	if ((rtas_node == NULL) || (systemcfg->platform == PLATFORM_ISERIES_LPAR)) {
-		return;
-	}
-	
-	if (proc_ppc64.rtas == NULL) {
-		proc_ppc64_init();
-	}
-
-	if (proc_ppc64.rtas == NULL) {
-		printk(KERN_ERR "Failed to create /proc/rtas in proc_rtas_init\n");
-		return;
-	}
-
-	/* /proc/rtas entries */
-
-	entry = create_proc_entry("progress", S_IRUGO|S_IWUSR, proc_ppc64.rtas);
-	if (entry) entry->proc_fops = &ppc_rtas_progress_operations;
-
-	entry = create_proc_entry("clock", S_IRUGO|S_IWUSR, proc_ppc64.rtas); 
-	if (entry) entry->proc_fops = &ppc_rtas_clock_operations;
-
-	entry = create_proc_entry("poweron", S_IWUSR|S_IRUGO, proc_ppc64.rtas); 
-	if (entry) entry->proc_fops = &ppc_rtas_poweron_operations;
+	if (!(systemcfg->platform & PLATFORM_PSERIES))
+		return 1;
 
-	create_proc_read_entry("sensors", S_IRUGO, proc_ppc64.rtas, 
-			ppc_rtas_sensor_read, NULL);
-	
-	entry = create_proc_entry("frequency", S_IWUSR|S_IRUGO, proc_ppc64.rtas); 
-	if (entry) entry->proc_fops = &ppc_rtas_tone_freq_operations;
+	rtas_node = of_find_node_by_name(NULL, "rtas");
+	if (rtas_node == NULL)
+		return 1;
 
-	entry = create_proc_entry("volume", S_IWUSR|S_IRUGO, proc_ppc64.rtas); 
-	if (entry) entry->proc_fops = &ppc_rtas_tone_volume_operations;
+	entry = create_proc_entry("ppc64/rtas/progress", S_IRUGO|S_IWUSR, NULL);
+	if (entry)
+		entry->proc_fops = &ppc_rtas_progress_operations;
+
+	entry = create_proc_entry("ppc64/rtas/clock", S_IRUGO|S_IWUSR, NULL);
+	if (entry)
+		entry->proc_fops = &ppc_rtas_clock_operations;
+
+	entry = create_proc_entry("ppc64/rtas/poweron", S_IWUSR|S_IRUGO, NULL);
+	if (entry)
+		entry->proc_fops = &ppc_rtas_poweron_operations;
+
+	create_proc_read_entry("ppc64/rtas/sensors", S_IRUGO, NULL,
+			       ppc_rtas_sensor_read, NULL);
+
+	entry = create_proc_entry("ppc64/rtas/frequency", S_IWUSR|S_IRUGO,
+				  NULL);
+	if (entry)
+		entry->proc_fops = &ppc_rtas_tone_freq_operations;
+
+	entry = create_proc_entry("ppc64/rtas/volume", S_IWUSR|S_IRUGO, NULL);
+	if (entry)
+		entry->proc_fops = &ppc_rtas_tone_volume_operations;
+
+	entry = create_proc_entry("ppc64/rtas/rmo_buffer", S_IRUSR, NULL);
+	if (entry)
+		entry->proc_fops = &ppc_rtas_rmo_buf_ops;
 
-	entry = create_proc_entry("rmo_buffer", S_IRUSR, proc_ppc64.rtas);
-	if (entry) entry->proc_fops = &ppc_rtas_rmo_buf_ops;
+	return 0;
 }
 
+__initcall(proc_rtas_init);
+
 /* ****************************************************************** */
 /* POWER-ON-TIME                                                      */
 /* ****************************************************************** */
--- diff/arch/ppc64/kernel/rtas.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/rtas.c	2004-03-16 09:37:55.478106216 +0000
@@ -19,7 +19,6 @@
 #include <linux/init.h>
 
 #include <asm/prom.h>
-#include <asm/proc_fs.h>
 #include <asm/rtas.h>
 #include <asm/semaphore.h>
 #include <asm/machdep.h>
@@ -259,6 +258,33 @@ rtas_get_power_level(int powerdomain, in
 }
 
 int
+rtas_set_power_level(int powerdomain, int level, int *setlevel)
+{
+	int token = rtas_token("set-power-level");
+	unsigned int wait_time;
+	long returned_level;
+	int rc;
+
+	if (token == RTAS_UNKNOWN_SERVICE)
+		return RTAS_UNKNOWN_OP;
+
+	while (1) {
+		rc = (int) rtas_call(token, 2, 2, &returned_level, powerdomain,
+					level);
+		if (rc == RTAS_BUSY)
+			udelay(1);
+		else if (rtas_is_extended_busy(rc)) {
+			wait_time = rtas_extended_busy_delay_time(rc);
+			udelay(wait_time * 1000);
+		}
+		else
+			break;
+	}
+	*setlevel = (int) returned_level;
+	return rc;
+}
+
+int
 rtas_get_sensor(int sensor, int index, int *state)
 {
 	int token = rtas_token("get-sensor-state");
@@ -426,6 +452,7 @@ asmlinkage int ppc_rtas(struct rtas_args
 {
 	struct rtas_args args;
 	unsigned long flags;
+	int nargs;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
@@ -433,14 +460,15 @@ asmlinkage int ppc_rtas(struct rtas_args
 	if (copy_from_user(&args, uargs, 3 * sizeof(u32)) != 0)
 		return -EFAULT;
 
-	if (args.nargs > ARRAY_SIZE(args.args)
+	nargs = args.nargs;
+	if (nargs > ARRAY_SIZE(args.args)
 	    || args.nret > ARRAY_SIZE(args.args)
-	    || args.nargs + args.nret > ARRAY_SIZE(args.args))
+	    || nargs + args.nret > ARRAY_SIZE(args.args))
 		return -EINVAL;
 
 	/* Copy in args. */
 	if (copy_from_user(args.args, uargs->args,
-			   args.nargs * sizeof(rtas_arg_t)) != 0)
+			   nargs * sizeof(rtas_arg_t)) != 0)
 		return -EFAULT;
 
 	spin_lock_irqsave(&rtas.lock, flags);
@@ -449,14 +477,15 @@ asmlinkage int ppc_rtas(struct rtas_args
 	enter_rtas((void *)__pa((unsigned long)&get_paca()->xRtas));
 	args = get_paca()->xRtas;
 
+	args.rets  = (rtas_arg_t *)&(args.args[nargs]);
 	if (args.rets[0] == -1)
 		log_rtas_error(&args);
 
 	spin_unlock_irqrestore(&rtas.lock, flags);
 
 	/* Copy out args. */
-	if (copy_to_user(uargs->args + args.nargs,
-			 args.args + args.nargs,
+	if (copy_to_user(uargs->args + nargs,
+			 args.args + nargs,
 			 args.nret * sizeof(rtas_arg_t)) != 0)
 		return -EFAULT;
 
@@ -472,4 +501,5 @@ EXPORT_SYMBOL(rtas_data_buf_lock);
 EXPORT_SYMBOL(rtas_extended_busy_delay_time);
 EXPORT_SYMBOL(rtas_get_sensor);
 EXPORT_SYMBOL(rtas_get_power_level);
+EXPORT_SYMBOL(rtas_set_power_level);
 EXPORT_SYMBOL(rtas_set_indicator);
--- diff/arch/ppc64/kernel/rtas_flash.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/rtas_flash.c	2004-03-16 09:37:55.479106064 +0000
@@ -15,7 +15,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
-#include <asm/proc_fs.h>
+#include <linux/proc_fs.h>
 #include <asm/delay.h>
 #include <asm/uaccess.h>
 #include <asm/rtas.h>
@@ -106,10 +106,10 @@ struct rtas_validate_flash_t
 };
 
 static spinlock_t flash_file_open_lock = SPIN_LOCK_UNLOCKED;
-static struct proc_dir_entry *firmware_flash_pde = NULL;
-static struct proc_dir_entry *firmware_update_pde = NULL;
-static struct proc_dir_entry *validate_pde = NULL;
-static struct proc_dir_entry *manage_pde = NULL;
+static struct proc_dir_entry *firmware_flash_pde;
+static struct proc_dir_entry *firmware_update_pde;
+static struct proc_dir_entry *validate_pde;
+static struct proc_dir_entry *manage_pde;
 
 /* Do simple sanity checks on the flash image. */
 static int flash_list_valid(struct flash_block_list *flist)
@@ -501,7 +501,7 @@ static ssize_t validate_flash_read(struc
 }
 
 static ssize_t validate_flash_write(struct file *file, const char *buf,
-				size_t count, loff_t *off)
+				    size_t count, loff_t *off)
 {
 	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
 	struct rtas_validate_flash_t *args_buf;
@@ -567,18 +567,18 @@ static int validate_flash_release(struct
 	return 0;
 }
 
-static inline void remove_flash_pde(struct proc_dir_entry *dp)
+static void remove_flash_pde(struct proc_dir_entry *dp)
 {
 	if (dp) {
 		if (dp->data != NULL)
 			kfree(dp->data);
-		remove_proc_entry(dp->name, proc_ppc64.rtas);
+		remove_proc_entry(dp->name, NULL);
 	}
 }
 
-static inline int initialize_flash_pde_data(const char *rtas_call_name, 
-		                            size_t buf_size,
-					    struct proc_dir_entry *dp)
+static int initialize_flash_pde_data(const char *rtas_call_name,
+				     size_t buf_size,
+				     struct proc_dir_entry *dp)
 {
 	int *status;
 	int token;
@@ -591,7 +591,8 @@ static inline int initialize_flash_pde_d
 
 	memset(dp->data, 0, buf_size);
 
-	/* This code assumes that the status int is the first member of the
+	/*
+	 * This code assumes that the status int is the first member of the
 	 * struct 
 	 */
 	status = (int *) dp->data;
@@ -604,12 +605,12 @@ static inline int initialize_flash_pde_d
 	return 0;
 }
 
-static inline struct proc_dir_entry * create_flash_pde(const char *filename, 
-					struct file_operations *fops)
+static struct proc_dir_entry *create_flash_pde(const char *filename,
+					       struct file_operations *fops)
 {
 	struct proc_dir_entry *ent = NULL;
 
-	ent = create_proc_entry(filename, S_IRUSR | S_IWUSR, proc_ppc64.rtas);
+	ent = create_proc_entry(filename, S_IRUSR | S_IWUSR, NULL);
 	if (ent != NULL) {
 		ent->nlink = 1;
 		ent->proc_fops = fops;
@@ -644,50 +645,79 @@ int __init rtas_flash_init(void)
 {
 	int rc;
 
-	if (!proc_ppc64.rtas) {
-		printk(KERN_WARNING "rtas proc dir does not already exist");
-		return -ENOENT;
+	if (rtas_token("ibm,update-flash-64-and-reboot") ==
+		       RTAS_UNKNOWN_SERVICE) {
+		printk(KERN_ERR "rtas_flash: no firmware flash support\n");
+		return 1;
 	}
 
-	firmware_flash_pde = create_flash_pde(FIRMWARE_FLASH_NAME, 
+	firmware_flash_pde = create_flash_pde("ppc64/rtas/"
+					      FIRMWARE_FLASH_NAME,
 					      &rtas_flash_operations);
+	if (firmware_flash_pde == NULL) {
+		rc = -ENOMEM;
+		goto cleanup;
+	}
+
 	rc = initialize_flash_pde_data("ibm,update-flash-64-and-reboot",
 			 	       sizeof(struct rtas_update_flash_t), 
 				       firmware_flash_pde);
 	if (rc != 0)
-		return rc;
-	
-	firmware_update_pde = create_flash_pde(FIRMWARE_UPDATE_NAME, 
+		goto cleanup;
+
+	firmware_update_pde = create_flash_pde("ppc64/rtas/"
+					       FIRMWARE_UPDATE_NAME,
 					       &rtas_flash_operations);
+	if (firmware_update_pde == NULL) {
+		rc = -ENOMEM;
+		goto cleanup;
+	}
+
 	rc = initialize_flash_pde_data("ibm,update-flash-64-and-reboot",
 			 	       sizeof(struct rtas_update_flash_t), 
 				       firmware_update_pde);
 	if (rc != 0)
-		return rc;
-	
-	validate_pde = create_flash_pde(VALIDATE_FLASH_NAME, 
+		goto cleanup;
+
+	validate_pde = create_flash_pde("ppc64/rtas/" VALIDATE_FLASH_NAME,
 			      		&validate_flash_operations);
+	if (validate_pde == NULL) {
+		rc = -ENOMEM;
+		goto cleanup;
+	}
+
 	rc = initialize_flash_pde_data("ibm,validate-flash-image",
 		                       sizeof(struct rtas_validate_flash_t), 
 				       validate_pde);
 	if (rc != 0)
-		return rc;
-	
-	manage_pde = create_flash_pde(MANAGE_FLASH_NAME, 
+		goto cleanup;
+
+	manage_pde = create_flash_pde("ppc64/rtas" MANAGE_FLASH_NAME,
 				      &manage_flash_operations);
+	if (manage_pde == NULL) {
+		rc = -ENOMEM;
+		goto cleanup;
+	}
+
 	rc = initialize_flash_pde_data("ibm,manage-flash-image",
 			               sizeof(struct rtas_manage_flash_t),
 				       manage_pde);
 	if (rc != 0)
-		return rc;
-	
+		goto cleanup;
+
 	return 0;
+
+cleanup:
+	remove_flash_pde(firmware_flash_pde);
+	remove_flash_pde(firmware_update_pde);
+	remove_flash_pde(validate_pde);
+	remove_flash_pde(manage_pde);
+
+	return rc;
 }
 
 void __exit rtas_flash_cleanup(void)
 {
-	if (!proc_ppc64.rtas)
-		return;
 	remove_flash_pde(firmware_flash_pde);
 	remove_flash_pde(firmware_update_pde);
 	remove_flash_pde(validate_pde);
--- diff/arch/ppc64/kernel/rtasd.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/rtasd.c	2004-03-16 09:37:55.480105912 +0000
@@ -26,7 +26,6 @@
 #include <asm/prom.h>
 #include <asm/nvram.h>
 #include <asm/atomic.h>
-#include <asm/proc_fs.h>
 
 #if 0
 #define DEBUG(A...)	printk(KERN_ERR A)
@@ -47,7 +46,6 @@ static unsigned int rtas_event_scan_rate
 static unsigned int rtas_error_log_max;
 static unsigned int rtas_error_log_buffer_max;
 
-extern spinlock_t proc_ppc64_lock;
 extern volatile int no_more_logging;
 
 volatile int error_log_cnt = 0;
@@ -445,20 +443,18 @@ static int __init rtas_init(void)
 {
 	struct proc_dir_entry *entry;
 
-	if (proc_ppc64.rtas == NULL) {
-		proc_ppc64_init();
+	/* No RTAS, only warn if we are on a pSeries box  */
+	if (rtas_token("event-scan") == RTAS_UNKNOWN_SERVICE) {
+		if (systemcfg->platform & PLATFORM_PSERIES);
+			printk(KERN_ERR "rtasd: no RTAS on system\n");
+		return 1;
 	}
 
-	if (proc_ppc64.rtas == NULL) {
-		printk(KERN_ERR "rtas_init: /proc/ppc64/rtas does not exist.");
-		return -EIO;
-	}
-
-	entry = create_proc_entry("error_log", S_IRUSR, proc_ppc64.rtas);
+	entry = create_proc_entry("ppc64/error_log", S_IRUSR, NULL);
 	if (entry)
 		entry->proc_fops = &proc_rtas_log_operations;
 	else
-		printk(KERN_ERR "Failed to create rtas/error_log proc entry\n");
+		printk(KERN_ERR "Failed to create error_log proc entry\n");
 
 	if (kernel_thread(rtasd, 0, CLONE_FS) < 0)
 		printk(KERN_ERR "Failed to start RTAS daemon\n");
--- diff/arch/ppc64/kernel/scanlog.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/scanlog.c	2004-03-16 09:37:55.480105912 +0000
@@ -28,7 +28,6 @@
 #include <asm/uaccess.h>
 #include <asm/rtas.h>
 #include <asm/prom.h>
-#include <asm/proc_fs.h>
 
 #define MODULE_VERS "1.0"
 #define MODULE_NAME "scanlog"
@@ -212,16 +211,7 @@ int __init scanlog_init(void)
 		return -EIO;
 	}
 
-	if (proc_ppc64.rtas == NULL) {
-		proc_ppc64_init();
-	}
-
-	if (proc_ppc64.rtas == NULL) {
-		printk(KERN_ERR "Failed to create /proc/rtas in scanlog_init\n");
-		return -EIO;
-	}
-
-        ent = create_proc_entry("scan-log-dump",  S_IRUSR, proc_ppc64.rtas);
+        ent = create_proc_entry("ppc64/rtas/scan-log-dump",  S_IRUSR, NULL);
 	if (ent) {
 		ent->proc_fops = &scanlog_fops;
 		/* Ideally we could allocate a buffer < 4G */
--- diff/arch/ppc64/kernel/smp.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/smp.c	2004-03-16 09:37:55.481105760 +0000
@@ -796,3 +796,225 @@ static int __init topology_init(void)
 	return 0;
 }
 __initcall(topology_init);
+
+#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);
+		cpumask_t tmp1 = cpumask_of_cpu(i ^ 0x1);
+		cpumask_t tmp2 = cpumask_of_cpu(i);
+
+		*cpu_domain = SD_SIBLING_INIT;
+		cpus_or(cpu_domain->span, tmp1, tmp2);
+
+		*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];
+
+			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;
+	}
+
+	for (i = 0; i < MAX_NUMNODES; i++) {
+		int j;
+		cpumask_t nodemask;
+		struct sched_group *node = &sched_group_nodes[i];
+		cpumask_t node_cpumask = node_to_cpumask(i);
+		cpus_and(nodemask, node_cpumask, cpu_online_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;
+		cpumask_t node_cpumask = node_to_cpumask(i);
+		cpus_and(nodemask, node_cpumask, 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 */
--- diff/arch/ppc64/kernel/sys_ppc32.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/sys_ppc32.c	2004-03-16 09:37:55.483105456 +0000
@@ -2577,17 +2577,6 @@ asmlinkage long sys32_umask(u32 mask)
 	return sys_umask((int)mask);
 }
 
-
-/* Note: it is necessary to treat flags as an unsigned int,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long sys32_umount(char * name, u32 flags)
-{
-	return sys_umount(name, (int)flags);
-}
-
 struct __sysctl_args32 {
 	u32 name;
 	int nlen;
--- diff/arch/ppc64/kernel/vio.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/vio.c	2004-03-16 09:37:55.483105456 +0000
@@ -580,5 +580,4 @@ struct bus_type vio_bus_type = {
 	.match = vio_bus_match,
 };
 
-EXPORT_SYMBOL(plpar_hcall_norets);
-EXPORT_SYMBOL(plpar_hcall_8arg_2ret);
+EXPORT_SYMBOL(vio_bus_type);
--- diff/arch/ppc64/kernel/viopath.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/viopath.c	2004-03-16 09:37:55.485105152 +0000
@@ -28,7 +28,6 @@
  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  */
-#include <asm/uaccess.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -37,9 +36,10 @@
 #include <linux/proc_fs.h>
 #include <linux/dma-mapping.h>
 #include <linux/wait.h>
+#include <linux/seq_file.h>
 
-#include <asm/hardirq.h>	/* for is_atomic */
-
+#include <asm/hardirq.h>
+#include <asm/uaccess.h>
 #include <asm/iSeries/LparData.h>
 #include <asm/iSeries/HvLpEvent.h>
 #include <asm/iSeries/HvLpConfig.h>
@@ -184,21 +184,21 @@ static unsigned char e2a(unsigned char x
 	return ' ';
 }
 
-/* Handle reads from the proc file system
- */
-static int proc_read(char *buf, char **start, off_t offset,
-		     int blen, int *eof, void *data)
+static int proc_viopath_show(struct seq_file *m, void *v)
 {
+	char *buf;
+	dma_addr_t handle;
 	HvLpEvent_Rc hvrc;
 	DECLARE_MUTEX_LOCKED(Semaphore);
-	dma_addr_t dmaa =
-	    dma_map_single(iSeries_vio_dev, buf, PAGE_SIZE, DMA_FROM_DEVICE);
-	int len = PAGE_SIZE;
 
-	if (len > blen)
-		len = blen;
+	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!buf)
+		return 0;
+	memset(buf, 0, PAGE_SIZE);
+
+	handle = dma_map_single(iSeries_vio_dev, buf, PAGE_SIZE,
+				DMA_FROM_DEVICE);
 
-	memset(buf, 0x00, len);
 	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
 			HvLpEvent_Type_VirtualIo,
 			viomajorsubtype_config | vioconfigget,
@@ -206,50 +206,54 @@ static int proc_read(char *buf, char **s
 			viopath_sourceinst(viopath_hostLp),
 			viopath_targetinst(viopath_hostLp),
 			(u64)(unsigned long)&Semaphore, VIOVERSION << 16,
-			((u64)dmaa) << 32, len, 0, 0);
+			((u64)handle) << 32, PAGE_SIZE, 0, 0);
+
 	if (hvrc != HvLpEvent_Rc_Good)
-		printk("viopath hv error on op %d\n", (int) hvrc);
+		printk("viopath hv error on op %d\n", (int)hvrc);
 
 	down(&Semaphore);
 
-	dma_unmap_single(iSeries_vio_dev, dmaa, PAGE_SIZE, DMA_FROM_DEVICE);
+	dma_unmap_single(iSeries_vio_dev, handle, PAGE_SIZE, DMA_FROM_DEVICE);
+	kfree(buf);
+
+	buf[PAGE_SIZE] = '\0';
+	seq_printf(m, "%s", buf);
+
+	seq_printf(m, "SRLNBR=%c%c%c%c%c%c%c\n",
+		   e2a(xItExtVpdPanel.mfgID[2]),
+		   e2a(xItExtVpdPanel.mfgID[3]),
+		   e2a(xItExtVpdPanel.systemSerial[1]),
+		   e2a(xItExtVpdPanel.systemSerial[2]),
+		   e2a(xItExtVpdPanel.systemSerial[3]),
+		   e2a(xItExtVpdPanel.systemSerial[4]),
+		   e2a(xItExtVpdPanel.systemSerial[5]));
 
-	sprintf(buf + strlen(buf), "SRLNBR=");
-	buf[strlen(buf)] = e2a(xItExtVpdPanel.mfgID[2]);
-	buf[strlen(buf)] = e2a(xItExtVpdPanel.mfgID[3]);
-	buf[strlen(buf)] = e2a(xItExtVpdPanel.systemSerial[1]);
-	buf[strlen(buf)] = e2a(xItExtVpdPanel.systemSerial[2]);
-	buf[strlen(buf)] = e2a(xItExtVpdPanel.systemSerial[3]);
-	buf[strlen(buf)] = e2a(xItExtVpdPanel.systemSerial[4]);
-	buf[strlen(buf)] = e2a(xItExtVpdPanel.systemSerial[5]);
-	buf[strlen(buf)] = '\n';
-	*eof = 1;
-	return strlen(buf);
+	return 0;
 }
 
-/* Handle writes to our proc file system
- */
-static int proc_write(struct file *file, const char *buffer,
-		      unsigned long count, void *data)
+static int proc_viopath_open(struct inode *inode, struct file *file)
 {
-	/* Doesn't do anything today!!!
-	 */
-	return count;
+	return single_open(file, proc_viopath_show, NULL);
 }
 
-/* setup our proc file system entries
- */
-static void vio_proc_init(struct proc_dir_entry *iSeries_proc)
+static struct file_operations proc_viopath_operations = {
+	.open		= proc_viopath_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int __init vio_proc_init(void)
 {
-	struct proc_dir_entry *ent;
-	ent = create_proc_entry("config", S_IFREG | S_IRUSR, iSeries_proc);
-	if (!ent)
-		return;
-	ent->nlink = 1;
-	ent->data = NULL;
-	ent->read_proc = proc_read;
-	ent->write_proc = proc_write;
+	struct proc_dir_entry *e;
+
+	e = create_proc_entry("iSeries/config", 0, NULL);
+	if (e)
+		e->proc_fops = &proc_viopath_operations;
+
+        return 0;
 }
+__initcall(vio_proc_init);
 
 /* See if a given LP is active.  Allow for invalid lps to be passed in
  * and just return invalid
@@ -433,13 +437,8 @@ void vio_set_hostlp(void)
 	viopath_ourLp = HvLpConfig_getLpIndex();
 	viopath_hostLp = HvCallCfg_getHostingLpIndex(viopath_ourLp);
 
-	/* If we have a valid hosting LP, create a proc file system entry
-	 * for config information
-	 */
-	if (viopath_hostLp != HvLpIndexInvalid) {
-		iSeries_proc_callback(&vio_proc_init);
+	if (viopath_hostLp != HvLpIndexInvalid)
 		vio_setHandler(viomajorsubtype_config, handleConfig);
-	}
 }
 EXPORT_SYMBOL(vio_set_hostlp);
 
--- diff/arch/ppc64/kernel/xics.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/kernel/xics.c	2004-03-16 09:37:55.485105152 +0000
@@ -327,6 +327,8 @@ static void xics_mask_and_ack_irq(unsign
 	}
 }
 
+extern unsigned int real_irq_to_virt_slowpath(unsigned int real_irq);
+
 int xics_get_irq(struct pt_regs *regs)
 {
 	unsigned int cpu = smp_processor_id();
@@ -349,6 +351,8 @@ int xics_get_irq(struct pt_regs *regs)
 		irq = -1;
 	} else {
 		irq = real_irq_to_virt(vec);
+		if (irq == NO_IRQ)
+			irq = real_irq_to_virt_slowpath(vec);
 		if (irq == NO_IRQ) {
 			printk(KERN_ERR "Interrupt 0x%x (real) is invalid,"
 			       " disabling it.\n", vec);
--- diff/arch/ppc64/mm/hash_utils.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/mm/hash_utils.c	2004-03-16 09:37:55.486105000 +0000
@@ -39,7 +39,6 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/naca.h>
-#include <asm/pmc.h>
 #include <asm/machdep.h>
 #include <asm/lmb.h>
 #include <asm/abs_addr.h>
--- diff/arch/ppc64/mm/hugetlbpage.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/mm/hugetlbpage.c	2004-03-16 09:37:55.487104848 +0000
@@ -40,7 +40,7 @@ static struct list_head hugepage_freelis
 
 static void enqueue_huge_page(struct page *page)
 {
-	list_add(&page->list,
+	list_add(&page->lru,
 		&hugepage_freelists[page_zone(page)->zone_pgdat->node_id]);
 }
 
@@ -63,8 +63,8 @@ static struct page *dequeue_huge_page(vo
 	}
 
 	if (!list_empty(&hugepage_freelists[nid])) {
-		page = list_entry(hugepage_freelists[nid].next, struct page, list);
-		list_del(&page->list);
+		page = list_entry(hugepage_freelists[nid].next, struct page, lru);
+		list_del(&page->lru);
 	}
 
 	if (largepage_roundrobin)
@@ -407,9 +407,8 @@ follow_huge_pmd(struct mm_struct *mm, un
 static void free_huge_page(struct page *page)
 {
 	BUG_ON(page_count(page));
-	BUG_ON(page->mapping);
 
-	INIT_LIST_HEAD(&page->list);
+	INIT_LIST_HEAD(&page->lru);
 
 	spin_lock(&htlbpage_lock);
 	enqueue_huge_page(page);
--- diff/arch/ppc64/mm/init.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/mm/init.c	2004-03-16 09:37:55.488104696 +0000
@@ -36,7 +36,6 @@
 #include <linux/delay.h>
 #include <linux/bootmem.h>
 #include <linux/highmem.h>
-#include <linux/proc_fs.h>
 
 #include <asm/pgalloc.h>
 #include <asm/page.h>
@@ -76,8 +75,6 @@ pgd_t * ioremap_pgd = (pgd_t *)&ioremap_
 
 unsigned long klimit = (unsigned long)_end;
 
-HPTE *Hash=0;
-unsigned long Hash_size=0;
 unsigned long _SDR1=0;
 unsigned long _ASR=0;
 
--- diff/arch/ppc64/mm/numa.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/mm/numa.c	2004-03-16 09:37:55.488104696 +0000
@@ -22,9 +22,17 @@
 #define dbg(args...)
 #endif
 
-int numa_cpu_lookup_table[NR_CPUS] = { [ 0 ... (NR_CPUS - 1)] = -1};
+#ifdef DEBUG_NUMA
+#define ARRAY_INITIALISER -1
+#else
+#define ARRAY_INITIALISER 0
+#endif
+
+int numa_cpu_lookup_table[NR_CPUS] = { [ 0 ... (NR_CPUS - 1)] =
+	ARRAY_INITIALISER};
 int numa_memory_lookup_table[MAX_MEMORY >> MEMORY_INCREMENT_SHIFT] =
-	{ [ 0 ... ((MAX_MEMORY >> MEMORY_INCREMENT_SHIFT) - 1)] = -1};
+	{ [ 0 ... ((MAX_MEMORY >> MEMORY_INCREMENT_SHIFT) - 1)] =
+	ARRAY_INITIALISER};
 cpumask_t numa_cpumask_lookup_table[MAX_NUMNODES];
 int nr_cpus_in_node[MAX_NUMNODES] = { [0 ... (MAX_NUMNODES -1)] = 0};
 
--- diff/arch/ppc64/xmon/xmon.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/ppc64/xmon/xmon.c	2004-03-16 09:37:55.491104240 +0000
@@ -56,9 +56,6 @@ static u_int bus_error_jmp[100];
 #define setjmp xmon_setjmp
 #define longjmp xmon_longjmp
 
-/* Max number of stack frames we are willing to produce on a backtrace. */
-#define MAXFRAMECOUNT 50
-
 /* Breakpoint stuff */
 struct bpt {
 	unsigned long address;
@@ -85,7 +82,6 @@ static void dump(void);
 static void prdump(unsigned long, long);
 static int ppc_inst_dump(unsigned long, long);
 void print_address(unsigned long);
-static int getsp(void);
 static void backtrace(struct pt_regs *);
 static void excprint(struct pt_regs *);
 static void prregs(struct pt_regs *);
@@ -897,93 +893,75 @@ const char *getvecname(unsigned long vec
 	return ret;
 }
 
-static void
-backtrace(struct pt_regs *excp)
+/*
+ * Most of our exceptions are in the form:
+ *    bl handler
+ *    b .ret_from_exception
+ * and this currently fails to catch them.
+ */
+static inline int exception_frame(unsigned long ip)
 {
-	unsigned long sp;
-	unsigned long lr;
-	unsigned long stack[3];
+	extern void *ret_from_syscall_1, *ret_from_syscall_2, *ret_from_except;
+
+	if ((ip == (unsigned long)ret_from_syscall_1) ||
+	    (ip == (unsigned long)ret_from_syscall_2) ||
+	    (ip == (unsigned long)ret_from_except))
+		return 1;
+
+	return 0;
+}
+
+static int xmon_depth_to_print = 64;
+
+static void xmon_show_stack(unsigned long sp)
+{
+	unsigned long ip;
+	unsigned long newsp;
+	int count = 0;
 	struct pt_regs regs;
-	int framecount;
-	char *funcname;
-	/* declare these as raw ptrs so we don't get func descriptors */
-	extern void *ret_from_except, *ret_from_syscall_1;
 
-	if (excp != NULL) {
-	        lr = excp->link;
-		sp = excp->gpr[1];
-	} else {
-	        /* Use care not to call any function before this point
-		 so the saved lr has a chance of being good. */
-	        asm volatile ("mflr %0" : "=r" (lr) :);
-		sp = getsp();
-	}
-	scanhex(&sp);
-	scannl();
-	for (framecount = 0;
-	     sp != 0 && framecount < MAXFRAMECOUNT;
-	     sp = stack[0], framecount++) {
-		if (mread(sp, stack, sizeof(stack)) != sizeof(stack))
-			break;
-#if 0
-		if (lr != 0) {
-		    stack[2] = lr;	/* fake out the first saved lr.  It may not be saved yet. */
-		    lr = 0;
+	do {
+		if (sp < PAGE_OFFSET) {
+			printf("SP in userspace\n");
+			break;
 		}
-#endif
-		printf("%.16lx  %.16lx", sp, stack[2]);
-		/* TAI -- for now only the ones cast to unsigned long will match.
-		 * Need to test the rest...
-		 */
-		if ((stack[2] == (unsigned long)ret_from_except &&
-		            (funcname = "ret_from_except"))
-		    || (stack[2] == (unsigned long)ret_from_syscall_1 &&
-		            (funcname = "ret_from_syscall_1"))
-#if 0
-		    || stack[2] == (unsigned) &ret_from_syscall_2
-		    || stack[2] == (unsigned) &do_signal_ret
-#endif
-		    ) {
-			printf("  %s\n", funcname);
+
+		if (!mread((sp + 16), &ip, sizeof(unsigned long)))
+			break;
+
+		printf("[%016lx] [%016lx] ", sp, ip);
+		xmon_print_symbol("%s\n", ip);
+
+		if (exception_frame(ip)) {
 			if (mread(sp+112, &regs, sizeof(regs)) != sizeof(regs))
 				break;
-			printf("exception: %lx %s regs %lx\n", regs.trap, getvecname(regs.trap), sp+112);
-			printf("                  %.16lx", regs.nip);
-			if (regs.nip & 0xffffffff00000000UL)
-				xmon_print_symbol("  %s", regs.nip);
-			printf("\n");
-                        if (regs.gpr[1] < sp) {
-                            printf("<Stack drops into userspace %.16lx>\n", regs.gpr[1]);
-                            break;
-			}
 
-			sp = regs.gpr[1];
-			if (mread(sp, stack, sizeof(stack)) != sizeof(stack))
-				break;
-		} else {
-			if (stack[2])
-				xmon_print_symbol("  %s", stack[2]);
-			printf("\n");
-		}
-		if (stack[0] && stack[0] <= sp) {
-			if ((stack[0] & 0xffffffff00000000UL) == 0)
-				printf("<Stack drops into 32-bit userspace %.16lx>\n", stack[0]);
-			else
-				printf("<Corrupt stack.  Next backchain is %.16lx>\n", stack[0]);
-			break;
+                        printf("  exception: %lx %s regs %lx\n", regs.trap,
+			       getvecname(regs.trap), sp+112);
 		}
-	}
-	if (framecount >= MAXFRAMECOUNT)
-		printf("<Punt. Too many stack frames>\n");
+
+		if (!mread(sp, &newsp, sizeof(unsigned long)))
+			break;
+		if (newsp < sp)
+			break;
+
+		sp = newsp;
+	} while (count++ < xmon_depth_to_print);
 }
 
-int
-getsp()
+static void backtrace(struct pt_regs *excp)
 {
-	int x;
+	unsigned long sp;
+
+	if (excp == NULL)
+		sp = __get_SP();
+	else
+		sp = excp->gpr[1];
+
+	scanhex(&sp);
+	scannl();
 
-	asm("mr %0,1" : "=r" (x) :);
-	return x;
+	xmon_show_stack(sp);
 }
 
 spinlock_t exception_print_lock = SPIN_LOCK_UNLOCKED;
--- diff/arch/s390/Kconfig	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/s390/Kconfig	2004-03-16 09:37:55.492104088 +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/appldata/appldata_mem.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/s390/appldata/appldata_mem.c	2004-03-16 09:37:55.492104088 +0000
@@ -54,7 +54,9 @@ struct appldata_mem_data {
 	u64 freeswap;		/* free swap space */
 
 // New in 2.6 -->
-	u64 pgalloc;		/* page allocations */
+	u64 pgalloc_high;	/* page allocations */
+	u64 pgalloc_normal;
+	u64 pgalloc_dma;
 	u64 pgfault;		/* page faults (major+minor) */
 	u64 pgmajfault;		/* page faults (major only) */
 // <-- New in 2.6
@@ -69,7 +71,9 @@ static inline void appldata_debug_print(
 	P_DEBUG("pgpgout    = %8lu KB\n", mem_data->pgpgout);
 	P_DEBUG("pswpin     = %8lu Pages\n", mem_data->pswpin);
 	P_DEBUG("pswpout    = %8lu Pages\n", mem_data->pswpout);
-	P_DEBUG("pgalloc    = %8lu \n", mem_data->pgalloc);
+	P_DEBUG("pgalloc_high   = %8lu \n", mem_data->pgalloc_high);
+	P_DEBUG("pgalloc_normal = %8lu \n", mem_data->pgalloc_normal);
+	P_DEBUG("pgalloc_dma    = %8lu \n", mem_data->pgalloc_dma);
 	P_DEBUG("pgfault    = %8lu \n", mem_data->pgfault);
 	P_DEBUG("pgmajfault = %8lu \n", mem_data->pgmajfault);
 	P_DEBUG("sharedram  = %8lu KB\n", mem_data->sharedram);
@@ -105,11 +109,14 @@ static void appldata_get_mem_data(void *
 	mem_data->pgpgout    = ps.pgpgout >> 1;
 	mem_data->pswpin     = ps.pswpin;
 	mem_data->pswpout    = ps.pswpout;
-	mem_data->pgalloc    = ps.pgalloc;
+	mem_data->pgalloc_high   = ps.pgalloc_high;
+	mem_data->pgalloc_normal = ps.pgalloc_normal;
+	mem_data->pgalloc_dma    = ps.pgalloc_dma;
 	mem_data->pgfault    = ps.pgfault;
 	mem_data->pgmajfault = ps.pgmajfault;
 
-P_DEBUG("pgalloc = %lu, pgfree = %lu\n", ps.pgalloc, ps.pgfree);
+P_DEBUG("pgalloc_high = %lu, pgalloc_normal = %lu, pgalloc_dma = %lu, pgfree = %lu\n",
+	ps.pgalloc_high, ps.pgalloc_normal, ps.pgalloc_dma, ps.pgfree);
 
 	si_meminfo(&val);
 	mem_data->sharedram = val.sharedram;
--- diff/arch/s390/kernel/compat_linux.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/s390/kernel/compat_linux.c	2004-03-16 09:37:55.495103632 +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/compat_wrapper.S	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/s390/kernel/compat_wrapper.S	2004-03-16 09:37:55.496103480 +0000
@@ -1338,3 +1338,13 @@ sys32_io_cancel_wrapper:
 	llgtr	%r3,%r3			# struct iocb *
 	llgtr	%r4,%r4			# struct io_event *
 	jg	sys_io_cancel
+
+	.globl  sys32_remap_file_pages_wrapper
+sys32_remap_file_pages_wrapper:
+	llgfr	%r2,%r2			# unsigned long
+	llgfr	%r3,%r3			# unsigned long
+	llgfr	%r4,%r4			# unsigned long
+	llgfr	%r5,%r5			# unsigned long
+	llgfr	%r6,%r6			# unsigned long
+	jg	sys_remap_file_pages
+
--- diff/arch/s390/kernel/sys_s390.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/s390/kernel/sys_s390.c	2004-03-16 09:37:55.497103328 +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-16 09:37:55.497103328 +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)
@@ -273,3 +273,4 @@ SYSCALL(sys_clock_getres,sys_clock_getre
 SYSCALL(sys_clock_nanosleep,sys_clock_nanosleep,sys32_clock_nanosleep_wrapper)
 NI_SYSCALL							/* reserved for vserver */
 SYSCALL(s390_fadvise64_64,sys_ni_syscall,sys32_fadvise64_64_wrapper)
+SYSCALL(sys_remap_file_pages,sys_remap_file_pages,sys32_remap_file_pages_wrapper)
--- diff/arch/s390/mm/fault.c	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/s390/mm/fault.c	2004-03-16 09:37:55.498103176 +0000
@@ -256,6 +256,8 @@ survive:
 		goto do_sigbus;
 	case VM_FAULT_OOM:
 		goto out_of_memory;
+	case VM_FAULT_SIGSEGV:
+		goto bad_area;
 	default:
 		BUG();
 	}
--- diff/arch/sparc/kernel/ioport.c	2003-09-17 11:28:03.000000000 +0000
+++ source/arch/sparc/kernel/ioport.c	2004-03-16 09:37:55.499103024 +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-11 10:20:22.000000000 +0000
+++ source/arch/sparc/kernel/process.c	2004-03-16 09:37:55.499103024 +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-11 10:20:22.000000000 +0000
+++ source/arch/sparc/kernel/setup.c	2004-03-16 09:37:55.500102872 +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-11 10:20:22.000000000 +0000
+++ source/arch/sparc/kernel/smp.c	2004-03-16 09:37:55.500102872 +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-11 10:20:22.000000000 +0000
+++ source/arch/sparc/kernel/sparc_ksyms.c	2004-03-16 09:37:55.501102720 +0000
@@ -205,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
@@ -218,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 14:46:12.000000000 +0000
+++ source/arch/sparc/kernel/sun4d_smp.c	2004-03-16 09:37:55.501102720 +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 10:50:00.000000000 +0000
+++ source/arch/sparc/kernel/sun4m_smp.c	2004-03-16 09:37:55.502102568 +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/sparc64/Kconfig	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/sparc64/Kconfig	2004-03-16 09:37:55.502102568 +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/kernel/init_task.c	2003-10-09 08:47:33.000000000 +0000
+++ source/arch/sparc64/kernel/init_task.c	2004-03-16 09:37:55.503102416 +0000
@@ -24,14 +24,6 @@ __asm__ (".text");
 union thread_union init_thread_union = { INIT_THREAD_INFO(init_task) };
 
 /*
- * This is to make the init_thread+stack be the right size for >8k pagesize.
- * The definition of thread_union in sched.h makes it 16k wide.
- */
-#if PAGE_SHIFT != 13
-char init_task_stack[THREAD_SIZE - INIT_THREAD_SIZE] = { 0 };
-#endif
-
-/*
  * Initial task structure.
  *
  * All other task structs will be allocated on slabs in fork.c
--- diff/arch/sparc64/kernel/pci_iommu.c	2003-08-20 13:16:26.000000000 +0000
+++ source/arch/sparc64/kernel/pci_iommu.c	2004-03-16 09:37:55.503102416 +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 08:47:33.000000000 +0000
+++ source/arch/sparc64/kernel/process.c	2004-03-16 09:37:55.505102112 +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>
@@ -43,6 +41,7 @@
 #include <asm/fpumacro.h>
 #include <asm/head.h>
 #include <asm/cpudata.h>
+#include <asm/unistd.h>
 
 /* #define VERBOSE_SHOWREGS */
 
--- diff/arch/sparc64/kernel/sbus.c	2003-05-21 10:50:14.000000000 +0000
+++ source/arch/sparc64/kernel/sbus.c	2004-03-16 09:37:55.506101960 +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-11 10:20:22.000000000 +0000
+++ source/arch/sparc64/kernel/setup.c	2004-03-16 09:37:55.507101808 +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-03-11 10:20:22.000000000 +0000
+++ source/arch/sparc64/kernel/smp.c	2004-03-16 09:37:55.508101656 +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);
 
--- diff/arch/sparc64/kernel/sparc64_ksyms.c	2004-03-11 10:20:22.000000000 +0000
+++ source/arch/sparc64/kernel/sparc64_ksyms.c	2004-03-16 09:37:55.509101504 +0000
@@ -213,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);
@@ -232,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-11 10:20:22.000000000 +0000
+++ source/arch/sparc64/kernel/sys_sparc32.c	2004-03-16 09:37:55.511101200 +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-16 09:37:55.511101200 +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/sparc64/mm/hugetlbpage.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/sparc64/mm/hugetlbpage.c	2004-03-16 09:37:55.512101048 +0000
@@ -29,7 +29,7 @@ static spinlock_t htlbpage_lock = SPIN_L
 
 static void enqueue_huge_page(struct page *page)
 {
-	list_add(&page->list,
+	list_add(&page->lru,
 		 &hugepage_freelists[page_zone(page)->zone_pgdat->node_id]);
 }
 
@@ -46,8 +46,8 @@ static struct page *dequeue_huge_page(vo
 	if (nid >= 0 && nid < MAX_NUMNODES &&
 	    !list_empty(&hugepage_freelists[nid])) {
 		page = list_entry(hugepage_freelists[nid].next,
-				  struct page, list);
-		list_del(&page->list);
+				  struct page, lru);
+		list_del(&page->lru);
 	}
 	return page;
 }
@@ -248,9 +248,8 @@ struct page *follow_huge_pmd(struct mm_s
 static void free_huge_page(struct page *page)
 {
 	BUG_ON(page_count(page));
-	BUG_ON(page->mapping);
 
-	INIT_LIST_HEAD(&page->list);
+	INIT_LIST_HEAD(&page->lru);
 
 	spin_lock(&htlbpage_lock);
 	enqueue_huge_page(page);
@@ -384,19 +383,19 @@ static int try_to_free_low(int count)
 	/* all lowmem is on node 0 */
 	list_for_each(p, &hugepage_freelists[0]) {
 		if (map) {
-			list_del(&map->list);
+			list_del(&map->lru);
 			update_and_free_page(map);
 			htlbpagemem--;
 			map = NULL;
 			if (++count == 0)
 				break;
 		}
-		page = list_entry(p, struct page, list);
+		page = list_entry(p, struct page, lru);
 		if (!PageHighMem(page))
 			map = page;
 	}
 	if (map) {
-		list_del(&map->list);
+		list_del(&map->lru);
 		update_and_free_page(map);
 		htlbpagemem--;
 		count++;
--- diff/arch/v850/kernel/rte_mb_a_pci.c	2003-08-20 13:16:26.000000000 +0000
+++ source/arch/v850/kernel/rte_mb_a_pci.c	2004-03-16 09:37:55.513100896 +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-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/Kconfig	2004-03-16 09:37:55.514100744 +0000
@@ -160,9 +160,10 @@ config X86_CPUID
 	  with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to
 	  /dev/cpu/31/cpuid.
 
+# disable it for opteron optimized builds because it pulls in ACPI_BOOT
 config X86_HT
 	bool
-	depends on SMP
+	depends on SMP && !MK8
 	default y
        
 config MATH_EMULATION
@@ -330,6 +331,11 @@ config PCI_DIRECT
 	depends on PCI
 	default y
 
+config PCI_MMCONFIG 
+	bool "Support mmconfig PCI config space access" 
+	depends on PCI
+	select ACPI_BOOT
+
 # the drivers/pci/msi.c code needs to be fixed first before enabling
 config PCI_USE_VECTOR
 	bool "Vector-based interrupt indexing"
@@ -381,6 +387,10 @@ config COMPAT
 	depends on IA32_EMULATION
 	default y
 
+config SYSVIPC_COMPAT
+	bool
+	depends on COMPAT && SYSVIPC
+	default y
 
 config UID16
 	bool
@@ -452,6 +462,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 +494,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/Makefile	2004-03-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/Makefile	2004-03-16 09:37:55.514100744 +0000
@@ -63,7 +63,7 @@ head-y := arch/x86_64/kernel/head.o arch
 libs-y 					+= arch/x86_64/lib/
 core-y					+= arch/x86_64/kernel/ arch/x86_64/mm/
 core-$(CONFIG_IA32_EMULATION)		+= arch/x86_64/ia32/
-drivers-$(CONFIG_PCI)			+= arch/i386/pci/
+drivers-$(CONFIG_PCI)			+= arch/x86_64/pci/
 drivers-$(CONFIG_OPROFILE)		+= arch/x86_64/oprofile/
 
 boot := arch/x86_64/boot
--- diff/arch/x86_64/defconfig	2004-03-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/defconfig	2004-03-16 09:37:55.517100288 +0000
@@ -26,7 +26,7 @@ CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=18
+CONFIG_LOG_BUF_SHIFT=17
 # CONFIG_HOTPLUG is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
@@ -47,7 +47,8 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
-# CONFIG_KMOD is not set
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
 
 #
 # Processor type and features
@@ -93,20 +94,19 @@ CONFIG_ACPI_INTERPRETER=y
 CONFIG_ACPI_SLEEP=y
 CONFIG_ACPI_SLEEP_PROC_FS=y
 CONFIG_ACPI_AC=y
-CONFIG_ACPI_BATTERY=y
+# CONFIG_ACPI_BATTERY is not set
 CONFIG_ACPI_BUTTON=y
 CONFIG_ACPI_FAN=y
 CONFIG_ACPI_PROCESSOR=y
 CONFIG_ACPI_THERMAL=y
 # CONFIG_ACPI_ASUS is not set
-CONFIG_ACPI_TOSHIBA=y
-CONFIG_ACPI_DEBUG=y
+# CONFIG_ACPI_TOSHIBA is not set
+# CONFIG_ACPI_DEBUG is not set
 CONFIG_ACPI_BUS=y
 CONFIG_ACPI_EC=y
 CONFIG_ACPI_POWER=y
 CONFIG_ACPI_PCI=y
 CONFIG_ACPI_SYSTEM=y
-# CONFIG_ACPI_RELAXED_AML is not set
 # CONFIG_X86_PM_TIMER is not set
 
 #
@@ -119,16 +119,17 @@ CONFIG_ACPI_SYSTEM=y
 #
 CONFIG_PCI=y
 CONFIG_PCI_DIRECT=y
-# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_PCI_MMCONFIG=y
+CONFIG_PCI_LEGACY_PROC=y
 # CONFIG_PCI_NAMES is not set
 
 #
 # Executable file formats / Emulations
 #
 CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_MISC=y
 CONFIG_IA32_EMULATION=y
-# CONFIG_IA32_AOUT is not set
+CONFIG_IA32_AOUT=y
 CONFIG_COMPAT=y
 CONFIG_UID16=y
 
@@ -139,6 +140,7 @@ CONFIG_UID16=y
 #
 # Generic Driver Options
 #
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -148,7 +150,14 @@ CONFIG_UID16=y
 #
 # Parallel port support
 #
-# CONFIG_PARPORT is not set
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=y
+CONFIG_PARPORT_PC_CML1=y
+# CONFIG_PARPORT_SERIAL is not set
+# CONFIG_PARPORT_PC_FIFO is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
+# CONFIG_PARPORT_OTHER is not set
+CONFIG_PARPORT_1284=y
 
 #
 # Plug and Play support
@@ -158,6 +167,7 @@ CONFIG_UID16=y
 # Block devices
 #
 CONFIG_BLK_DEV_FD=y
+# CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -165,11 +175,8 @@ CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_LBD=y
-# CONFIG_DCSSBLK is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_LBD is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -187,7 +194,7 @@ CONFIG_IDEDISK_MULTI_MODE=y
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
+CONFIG_BLK_DEV_IDESCSI=m
 # CONFIG_IDE_TASK_IOCTL is not set
 # CONFIG_IDE_TASKFILE_IO is not set
 
@@ -195,11 +202,12 @@ CONFIG_BLK_DEV_IDECD=y
 # IDE chipset support/bugfixes
 #
 CONFIG_IDE_GENERIC=y
-# CONFIG_BLK_DEV_CMD640 is not set
+CONFIG_BLK_DEV_CMD640=y
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
+CONFIG_IDEPCI_SHARE_IRQ=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_BLK_DEV_GENERIC is not set
+CONFIG_BLK_DEV_GENERIC=y
 # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
@@ -218,16 +226,16 @@ CONFIG_BLK_DEV_AMD74XX=y
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_BLK_DEV_HPT366 is not set
 # CONFIG_BLK_DEV_SC1200 is not set
-CONFIG_BLK_DEV_PIIX=y
+# CONFIG_BLK_DEV_PIIX is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_BLK_DEV_PDC202XX_NEW is not set
 # CONFIG_BLK_DEV_SVWKS is not set
 # CONFIG_BLK_DEV_SIIMAGE is not set
-# CONFIG_BLK_DEV_SIS5513 is not set
+CONFIG_BLK_DEV_SIS5513=y
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
@@ -246,8 +254,9 @@ CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 # CONFIG_CHR_DEV_ST is not set
 # CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -260,7 +269,7 @@ CONFIG_BLK_DEV_SD=y
 #
 # SCSI low-level drivers
 #
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+CONFIG_BLK_DEV_3W_XXXX_RAID=y
 # CONFIG_SCSI_ACARD is not set
 # CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
@@ -268,7 +277,11 @@ CONFIG_BLK_DEV_SD=y
 # CONFIG_SCSI_AIC79XX is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_SATA is not set
+CONFIG_SCSI_SATA=y
+# CONFIG_SCSI_SATA_SVW is not set
+CONFIG_SCSI_ATA_PIIX=y
+# CONFIG_SCSI_SATA_PROMISE is not set
+CONFIG_SCSI_SATA_VIA=y
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_CPQFCTS is not set
 # CONFIG_SCSI_DMX3191D is not set
@@ -278,6 +291,8 @@ CONFIG_BLK_DEV_SD=y
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
@@ -330,37 +345,111 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
+CONFIG_NETLINK_DEV=y
 CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
+CONFIG_NET_KEY=m
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
 # CONFIG_IP_PNP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
+CONFIG_IP_MROUTE=y
+# CONFIG_IP_PIMSM_V1 is not set
+# CONFIG_IP_PIMSM_V2 is not set
 # CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
 CONFIG_IPV6=y
-# CONFIG_IPV6_PRIVACY is not set
+CONFIG_IPV6_PRIVACY=y
 # CONFIG_INET6_AH is not set
-# CONFIG_INET6_ESP is not set
-# CONFIG_INET6_IPCOMP is not set
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
 # CONFIG_IPV6_TUNNEL is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
-# CONFIG_NETFILTER is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_TFTP is not set
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+# CONFIG_IP_NF_MATCH_LIMIT is not set
+# CONFIG_IP_NF_MATCH_IPRANGE is not set
+# CONFIG_IP_NF_MATCH_MAC is not set
+# CONFIG_IP_NF_MATCH_PKTTYPE is not set
+# CONFIG_IP_NF_MATCH_MARK is not set
+# CONFIG_IP_NF_MATCH_MULTIPORT is not set
+# CONFIG_IP_NF_MATCH_TOS is not set
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+# CONFIG_IP_NF_MATCH_AH_ESP is not set
+# CONFIG_IP_NF_MATCH_LENGTH is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_MATCH_TCPMSS is not set
+# CONFIG_IP_NF_MATCH_HELPER is not set
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+# CONFIG_IP_NF_MATCH_OWNER is not set
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+# CONFIG_IP_NF_TARGET_REDIRECT is not set
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_SAME is not set
+# CONFIG_IP_NF_NAT_LOCAL is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_MANGLE=m
+# CONFIG_IP_NF_TARGET_TOS is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_DSCP is not set
+CONFIG_IP_NF_TARGET_MARK=m
+# CONFIG_IP_NF_TARGET_CLASSIFY is not set
+CONFIG_IP_NF_TARGET_LOG=m
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_IP_NF_TARGET_TCPMSS=m
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+
+#
+# IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
 
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
 CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+CONFIG_SCTP_HMAC_NONE=y
+# CONFIG_SCTP_HMAC_SHA1 is not set
+# CONFIG_SCTP_HMAC_MD5 is not set
 # CONFIG_ATM is not set
 # CONFIG_VLAN_8021Q is not set
 # CONFIG_LLC2 is not set
@@ -389,10 +478,11 @@ CONFIG_NETDEVICES=y
 # ARCnet devices
 #
 # CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
+CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
+CONFIG_TUN=m
+CONFIG_ETHERTAP=m
 
 #
 # Ethernet (10 or 100Mbit)
@@ -401,7 +491,9 @@ CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_VORTEX=m
+# CONFIG_TYPHOON is not set
 
 #
 # Tulip family network device support
@@ -409,25 +501,25 @@ CONFIG_MII=y
 # CONFIG_NET_TULIP is not set
 # CONFIG_HP100 is not set
 CONFIG_NET_PCI=y
-# CONFIG_PCNET32 is not set
-CONFIG_AMD8111_ETH=y
+CONFIG_PCNET32=y
+CONFIG_AMD8111_ETH=m
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_B44 is not set
-CONFIG_FORCEDETH=y
+# CONFIG_FORCEDETH is not set
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 # CONFIG_E100 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
-CONFIG_8139CP=m
-CONFIG_8139TOO=m
+# CONFIG_8139CP is not set
+CONFIG_8139TOO=y
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
 # CONFIG_8139_OLD_RX_RESET is not set
 CONFIG_8139_RXBUF_IDX=2
-# CONFIG_SIS900 is not set
+CONFIG_SIS900=m
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
 # CONFIG_VIA_RHINE is not set
@@ -437,7 +529,7 @@ CONFIG_8139_RXBUF_IDX=2
 #
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
-CONFIG_E1000=y
+CONFIG_E1000=m
 # CONFIG_E1000_NAPI is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
@@ -453,7 +545,15 @@ CONFIG_TIGON3=y
 # CONFIG_IXGB is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+CONFIG_PPPOE=m
 # CONFIG_SLIP is not set
 
 #
@@ -512,7 +612,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
 # CONFIG_INPUT_TSDEV is not set
-CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
 
 #
@@ -524,6 +624,7 @@ CONFIG_SERIO=y
 CONFIG_SERIO_I8042=y
 # CONFIG_SERIO_SERPORT is not set
 # CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PARKBD is not set
 # CONFIG_SERIO_PCIPS2 is not set
 
 #
@@ -547,7 +648,12 @@ CONFIG_MOUSE_PS2=y
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
-# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_ROCKETPORT=m
+# CONFIG_SYNCLINK is not set
+# CONFIG_SYNCLINKMP is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_STALDRV is not set
 
 #
 # Serial drivers
@@ -564,13 +670,16 @@ CONFIG_SERIAL_8250_NR_UARTS=4
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_PRINTER=y
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
 
 #
 # Mice
 #
-# CONFIG_BUSMOUSE is not set
+CONFIG_BUSMOUSE=y
 # CONFIG_QIC02_TAPE is not set
 
 #
@@ -594,12 +703,17 @@ CONFIG_RTC=y
 #
 CONFIG_AGP=y
 CONFIG_AGP_AMD64=y
-CONFIG_AGP_INTEL=y
-# CONFIG_DRM is not set
+# CONFIG_AGP_INTEL is not set
+CONFIG_DRM=y
+# CONFIG_DRM_TDFX is not set
+# CONFIG_DRM_GAMMA is not set
+# CONFIG_DRM_R128 is not set
+CONFIG_DRM_RADEON=m
+# CONFIG_DRM_SIS is not set
 # CONFIG_MWAVE is not set
-CONFIG_RAW_DRIVER=y
+CONFIG_RAW_DRIVER=m
 CONFIG_MAX_RAW_DEVS=256
-CONFIG_HANGCHECK_TIMER=y
+# CONFIG_HANGCHECK_TIMER is not set
 
 #
 # I2C support
@@ -607,6 +721,11 @@ CONFIG_HANGCHECK_TIMER=y
 # CONFIG_I2C is not set
 
 #
+# Misc devices
+#
+# CONFIG_IBM_ASM is not set
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -642,10 +761,11 @@ CONFIG_SOUND=y
 #
 # Open Sound System
 #
-CONFIG_SOUND_PRIME=y
+CONFIG_SOUND_PRIME=m
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
-# CONFIG_SOUND_EMU10K1 is not set
+CONFIG_SOUND_EMU10K1=m
+# CONFIG_MIDI_EMU10K1 is not set
 # CONFIG_SOUND_FUSION is not set
 # CONFIG_SOUND_CS4281 is not set
 # CONFIG_SOUND_ES1370 is not set
@@ -653,12 +773,13 @@ CONFIG_SOUND_PRIME=y
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
-CONFIG_SOUND_ICH=y
+CONFIG_SOUND_ICH=m
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_TRIDENT is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_VIA82CXXX is not set
+CONFIG_SOUND_VIA82CXXX=m
+# CONFIG_MIDI_VIA82CXXX is not set
 # CONFIG_SOUND_OSS is not set
 # CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_FORTE is not set
@@ -668,7 +789,151 @@ CONFIG_SOUND_ICH=y
 #
 # USB support
 #
-# CONFIG_USB is not set
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_BANDWIDTH=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_UHCI_HCD=m
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_MIDI is not set
+# CONFIG_USB_ACM is not set
+CONFIG_USB_PRINTER=m
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_XPAD is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=m
+
+#
+# USB Host-to-Host Cables
+#
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_GENESYS=y
+CONFIG_USB_NET1080=y
+CONFIG_USB_PL2301=y
+
+#
+# Intelligent USB Devices/Gadgets
+#
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+# CONFIG_USB_ZAURUS is not set
+# CONFIG_USB_CDCETHER is not set
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_AX8817X=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_BELKIN=m
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_TEST is not set
 
 #
 # USB Gadget Support
@@ -680,20 +945,17 @@ CONFIG_SOUND_ICH=y
 #
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
 # CONFIG_EXT2_FS_SECURITY is not set
 CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-CONFIG_EXT3_FS_POSIX_ACL=y
-# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT3_FS_XATTR is not set
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 CONFIG_FS_MBCACHE=y
 CONFIG_REISERFS_FS=y
 # CONFIG_REISERFS_CHECK is not set
-# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_PROC_INFO=y
 # CONFIG_JFS_FS is not set
-CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -705,14 +967,16 @@ CONFIG_AUTOFS_FS=y
 # CD-ROM/DVD Filesystems
 #
 CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
+CONFIG_JOLIET=y
 # CONFIG_ZISOFS is not set
-# CONFIG_UDF_FS is not set
+CONFIG_UDF_FS=m
 
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=m
 # CONFIG_NTFS_FS is not set
 
 #
@@ -723,8 +987,8 @@ CONFIG_PROC_KCORE=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
-CONFIG_HUGETLBFS=y
-CONFIG_HUGETLB_PAGE=y
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
 #
@@ -750,7 +1014,7 @@ CONFIG_RAMFS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFS_DIRECTIO=y
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
 # CONFIG_NFSD_V4 is not set
@@ -775,7 +1039,45 @@ CONFIG_MSDOS_PARTITION=y
 #
 # Native Language Support
 #
-# CONFIG_NLS is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
 
 #
 # Profiling support
@@ -803,9 +1105,28 @@ CONFIG_MAGIC_SYSRQ=y
 #
 # Cryptographic options
 #
-# CONFIG_CRYPTO is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_ARC4 is not set
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_TEST is not set
 
 #
 # Library routines
 #
 CONFIG_CRC32=y
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
--- diff/arch/x86_64/ia32/Makefile	2004-03-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/ia32/Makefile	2004-03-16 09:37:55.517100288 +0000
@@ -11,18 +11,22 @@ obj-$(CONFIG_IA32_EMULATION) += $(sysv-y
 
 obj-$(CONFIG_IA32_AOUT) += ia32_aout.o
 
-$(obj)/syscall32.o: $(src)/syscall32.c $(obj)/vsyscall.so
+$(obj)/syscall32.o: $(src)/syscall32.c \
+	$(foreach F,sysenter syscall,$(obj)/vsyscall-$F.so)
 
 # Teach kbuild about targets
-targets := vsyscall.o vsyscall.so
+targets := $(foreach F,sysenter syscall,vsyscall-$F.o vsyscall-$F.so)
 
 # The DSO images are built using a special linker script
-quiet_cmd_vsyscall = SYSCALL $@
-      cmd_vsyscall = $(CC) -m32 -nostdlib -shared -s \
+quiet_cmd_syscall = SYSCALL $@
+      cmd_syscall = $(CC) -m32 -nostdlib -shared -s \
 			   -Wl,-soname=linux-gate.so.1 -o $@ \
 			   -Wl,-T,$(filter-out FORCE,$^)
-$(obj)/vsyscall.so: $(src)/vsyscall.lds $(obj)/vsyscall.o FORCE
-	$(call if_changed,vsyscall)
 
-AFLAGS_vsyscall.o = -m32
+$(obj)/vsyscall-sysenter.so $(obj)/vsyscall-syscall.so: \
+$(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE
+	$(call if_changed,syscall)
+
+AFLAGS_vsyscall-sysenter.o = -m32
+AFLAGS_vsyscall-syscall.o = -m32
 CFLAGS_ia32_ioctl.o += -Ifs/
--- diff/arch/x86_64/ia32/ia32_binfmt.c	2004-03-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/ia32/ia32_binfmt.c	2004-03-16 09:37:55.518100136 +0000
@@ -32,7 +32,7 @@
 #define AT_SYSINFO 32
 #define AT_SYSINFO_EHDR		33
 
-int sysctl_vsyscall32;
+int sysctl_vsyscall32 = 1;
 
 #define ARCH_DLINFO do {  \
 	if (sysctl_vsyscall32) { \
@@ -46,7 +46,7 @@ struct elf_phdr; 
 
 #define IA32_EMULATOR 1
 
-#define ELF_ET_DYN_BASE		(IA32_PAGE_OFFSET/3 + 0x1000000)
+#define ELF_ET_DYN_BASE		(TASK_UNMAPPED_32 + 0x1000000)
 
 #undef ELF_ARCH
 #define ELF_ARCH EM_386
@@ -261,7 +261,6 @@ do {							\
 		set_thread_flag(TIF_ABI_PENDING);		\
 	else							\
 		clear_thread_flag(TIF_ABI_PENDING);		\
-	set_personality((ibcs2)?PER_SVR4:current->personality);	\
 } while (0)
 
 /* Override some function names */
--- diff/arch/x86_64/ia32/ia32_signal.c	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/x86_64/ia32/ia32_signal.c	2004-03-16 09:37:55.518100136 +0000
@@ -273,8 +273,6 @@ asmlinkage long sys32_sigreturn(struct p
 	sigset_t set;
 	unsigned int eax;
 
-	set_thread_flag(TIF_IRET);
-	
 	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__get_user(set.sig[0], &frame->sc.oldmask)
@@ -305,8 +303,6 @@ asmlinkage long sys32_rt_sigreturn(struc
 	stack_t st;
 	unsigned int eax;
 
-	set_thread_flag(TIF_IRET);
-
 	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
--- diff/arch/x86_64/ia32/ia32entry.S	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/x86_64/ia32/ia32entry.S	2004-03-16 09:37:55.519099984 +0000
@@ -12,6 +12,7 @@
 #include <asm/ia32_unistd.h>	
 #include <asm/thread_info.h>	
 #include <asm/segment.h>
+#include <asm/vsyscall32.h>
 #include <linux/linkage.h>
 
 	.macro IA32_ARG_FIXUP noebp=0
@@ -25,6 +26,99 @@
 	movl	%edx,%edx	/* zero extension */
 	.endm 
 
+	/* clobbers %eax */	
+	.macro  CLEAR_RREGS
+	xorl 	%eax,%eax
+	movq	%rax,R11(%rsp)
+	movq	%rax,R10(%rsp)
+	movq	%rax,R9(%rsp)
+	movq	%rax,R8(%rsp)
+	.endm
+
+/*
+ * 32bit SYSENTER instruction entry.
+ *
+ * Arguments:
+ * %eax	System call number.
+ * %ebx Arg1
+ * %ecx Arg2
+ * %edx Arg3
+ * %esi Arg4
+ * %edi Arg5
+ * %ebp user stack
+ * 0(%ebp) Arg6	
+ * 	
+ * Interrupts off.
+ *	
+ * This is purely a fast path. For anything complicated we use the int 0x80
+ * path below.	Set up a complete hardware stack frame to share code
+ * with the int 0x80 path.
+ */ 	
+ENTRY(ia32_sysenter_target)
+	CFI_STARTPROC
+	swapgs
+	movq	%gs:pda_kernelstack, %rsp
+	addq	$(PDA_STACKOFFSET),%rsp	
+	sti	
+ 	movl	%ebp,%ebp		/* zero extension */
+	pushq	$__USER32_DS
+	pushq	%rbp
+	pushfq
+	movl	$VSYSCALL32_SYSEXIT, %r10d
+	pushq	$__USER32_CS
+	movl	%eax, %eax
+	pushq	%r10
+	pushq	%rax
+	cld
+	SAVE_ARGS 0,0,1
+ 	/* no need to do an access_ok check here because rbp has been
+ 	   32bit zero extended */ 
+1:	movl	(%rbp),%r9d
+ 	.section __ex_table,"a"
+ 	.quad 1b,ia32_badarg
+ 	.previous	
+	GET_THREAD_INFO(%r10)
+	testl  $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%r10)
+	jnz  sysenter_tracesys
+sysenter_do_call:	
+	cmpl	$(IA32_NR_syscalls),%eax
+	jae	ia32_badsys
+	IA32_ARG_FIXUP 1
+	call	*ia32_sys_call_table(,%rax,8)
+	movq	%rax,RAX-ARGOFFSET(%rsp)
+	GET_THREAD_INFO(%r10)
+	cli
+	testl	$_TIF_ALLWORK_MASK,threadinfo_flags(%r10)
+	jnz	int_ret_from_sys_call
+	/* clear IF, that popfq doesn't enable interrupts early */
+	andl  $~0x200,EFLAGS-R11(%rsp) 
+	RESTORE_ARGS 1,24,1,1,1,1
+	popfq
+	popq	%rcx				/* User %esp */
+	movl	$VSYSCALL32_SYSEXIT,%edx	/* User %eip */
+	swapgs
+	sti		/* sti only takes effect after the next instruction */
+	/* sysexit */
+	.byte	0xf, 0x35
+
+sysenter_tracesys:
+	SAVE_REST
+	CLEAR_RREGS
+	movq	$-ENOSYS,RAX(%rsp)	/* really needed? */
+	movq	%rsp,%rdi        /* &pt_regs -> arg1 */
+	call	syscall_trace_enter
+	LOAD_ARGS ARGOFFSET  /* reload args from stack in case ptrace changed it */
+	RESTORE_REST
+	movl	%ebp, %ebp
+	/* no need to do an access_ok check here because rbp has been
+	   32bit zero extended */ 
+1:	movl	(%rbp),%r9d
+	.section __ex_table,"a"
+	.quad 1b,ia32_badarg
+	.previous
+	jmp	sysenter_do_call
+	CFI_ENDPROC
+
 /*
  * 32bit SYSCALL instruction entry.
  *
@@ -51,7 +145,7 @@ ENTRY(ia32_cstar_target)
 	movl	%esp,%r8d
 	movq	%gs:pda_kernelstack,%rsp
 	sti
-	SAVE_ARGS 8,1
+	SAVE_ARGS 8,1,1
 	movl 	%eax,%eax	/* zero extension */
 	movq	%rax,ORIG_RAX-ARGOFFSET(%rsp)
 	movq	%rcx,RIP-ARGOFFSET(%rsp)
@@ -66,47 +160,48 @@ ENTRY(ia32_cstar_target)
 	/* hardware stack frame is complete now */	
 1:	movl	(%r8),%r9d
 	.section __ex_table,"a"
-	.quad 1b,cstar_badarg
+	.quad 1b,ia32_badarg
 	.previous	
 	GET_THREAD_INFO(%r10)
-	bt  $TIF_SYSCALL_TRACE,threadinfo_flags(%r10)
-	jc  ia32_tracesys
+	testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%r10)
+	jnz   cstar_tracesys
 cstar_do_call:	
 	cmpl $IA32_NR_syscalls,%eax
 	jae  ia32_badsys
 	IA32_ARG_FIXUP 1
 	call *ia32_sys_call_table(,%rax,8)
-	.globl cstar_sysret
-	/* label must directly follow call */
-cstar_sysret:	
 	movq %rax,RAX-ARGOFFSET(%rsp)
 	GET_THREAD_INFO(%r10)
 	cli
 	testl $_TIF_ALLWORK_MASK,threadinfo_flags(%r10)
-	jnz 1f
-	RESTORE_ARGS 1,-ARG_SKIP,1,1
+	jnz  int_ret_from_sys_call
+	RESTORE_ARGS 1,-ARG_SKIP,1,1,1
 	movl RIP-ARGOFFSET(%rsp),%ecx
 	movl EFLAGS-ARGOFFSET(%rsp),%r11d	
 	movl RSP-ARGOFFSET(%rsp),%esp
 	swapgs
 	sysretl
 	
-1:
-	btc   $TIF_IRET,threadinfo_flags(%r10) 
-	jmp   int_ret_from_sys_call
-	
 cstar_tracesys:	
 	SAVE_REST
+	CLEAR_RREGS
 	movq $-ENOSYS,RAX(%rsp)	/* really needed? */
 	movq %rsp,%rdi        /* &pt_regs -> arg1 */
-	call syscall_trace
+	call syscall_trace_enter
 	LOAD_ARGS ARGOFFSET  /* reload args from stack in case ptrace changed it */
 	RESTORE_REST
+	movl RSP-ARGOFFSET(%rsp), %r8d
+	/* no need to do an access_ok check here because r8 has been
+	   32bit zero extended */ 
+1:	movl	(%r8),%r9d
+	.section __ex_table,"a"
+	.quad 1b,ia32_badarg
+	.previous
 	jmp cstar_do_call
 				
-cstar_badarg:
+ia32_badarg:
 	movq $-EFAULT,%rax
-	jmp cstar_sysret
+	jmp ia32_sysret
 	CFI_ENDPROC
 
 /* 
@@ -139,15 +234,16 @@ ENTRY(ia32_syscall)
 	cld
 	/* note the registers are not zero extended to the sf.
 	   this could be a problem. */
-	SAVE_ARGS
+	SAVE_ARGS 0,0,1
 	GET_THREAD_INFO(%r10)
-	bt $TIF_SYSCALL_TRACE,threadinfo_flags(%r10)
-	jc ia32_tracesys
+	testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%r10)
+	jnz ia32_tracesys
 ia32_do_syscall:	
 	cmpl $(IA32_NR_syscalls),%eax
 	jae  ia32_badsys
 	IA32_ARG_FIXUP
 	call *ia32_sys_call_table(,%rax,8) # xxx: rip relative
+ia32_sysret:
 	movq %rax,RAX-ARGOFFSET(%rsp)
 	jmp int_ret_from_sys_call 
 
@@ -155,7 +251,7 @@ ia32_tracesys:			 
 	SAVE_REST
 	movq $-ENOSYS,RAX(%rsp)	/* really needed? */
 	movq %rsp,%rdi        /* &pt_regs -> arg1 */
-	call syscall_trace
+	call syscall_trace_enter
 	LOAD_ARGS ARGOFFSET  /* reload args from stack in case ptrace changed it */
 	RESTORE_REST
 	jmp ia32_do_syscall
@@ -200,8 +296,7 @@ ENTRY(ia32_ptregs_common)
 	call *%rax
 	movq %r15, %r11
 	RESTORE_REST
-	cmpq $cstar_sysret,%r11
-	je   int_ret_from_sys_call /* misbalances the call/ret stack. sorry */
+	leaq ia32_sysret(%rip),%r11
 	pushq %r11
 	ret
 	CFI_ENDPROC
@@ -467,7 +562,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-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/ia32/ipc32.c	2004-03-16 09:37:55.521099680 +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/ia32/sys_ia32.c	2004-03-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/ia32/sys_ia32.c	2004-03-16 09:37:55.523099376 +0000
@@ -1876,18 +1876,9 @@ long sys32_quotactl(void)
 
 cond_syscall(sys32_ipc)
 
-struct exec_domain ia32_exec_domain = { 
-	.name = "linux/x86",
-	.pers_low = PER_LINUX32,
-	.pers_high = PER_LINUX32,
-};      
-
 static int __init ia32_init (void)
 {
 	printk("IA32 emulation $Id: sys_ia32.c,v 1.32 2002/03/24 13:02:28 ak Exp $\n");  
-	ia32_exec_domain.signal_map = default_exec_domain.signal_map;
-	ia32_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
-	register_exec_domain(&ia32_exec_domain);
 	return 0;
 }
 
--- diff/arch/x86_64/ia32/syscall32.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/x86_64/ia32/syscall32.c	2004-03-16 09:37:55.523099376 +0000
@@ -13,16 +13,22 @@
 #include <asm/tlbflush.h>
 #include <asm/ia32_unistd.h>
 
-/* 32bit VDSO mapped into user space. */ 
+/* 32bit VDSOs mapped into user space. */ 
 asm(".section \".init.data\",\"aw\"\n"
-    "syscall32:\n"
-    ".incbin \"arch/x86_64/ia32/vsyscall.so\"\n"
-    "syscall32_end:\n"
+    "syscall32_syscall:\n"
+    ".incbin \"arch/x86_64/ia32/vsyscall-syscall.so\"\n"
+    "syscall32_syscall_end:\n"
+    "syscall32_sysenter:\n"
+    ".incbin \"arch/x86_64/ia32/vsyscall-sysenter.so\"\n"
+    "syscall32_sysenter_end:\n"
     ".previous");
 
-extern unsigned char syscall32[], syscall32_end[];
+extern unsigned char syscall32_syscall[], syscall32_syscall_end[];
+extern unsigned char syscall32_sysenter[], syscall32_sysenter_end[];
+extern int sysctl_vsyscall32;
 
 char *syscall32_page; 
+static int use_sysenter __initdata = -1;
 
 /* RED-PEN: This knows too much about high level VM */ 
 /* Alternative would be to generate a vma with appropriate backing options
@@ -58,8 +64,28 @@ static int __init init_syscall32(void)
 	if (!syscall32_page) 
 		panic("Cannot allocate syscall32 page"); 
 	SetPageReserved(virt_to_page(syscall32_page));
-	memcpy(syscall32_page, syscall32, syscall32_end - syscall32);
+ 	if (use_sysenter > 0) {
+ 		memcpy(syscall32_page, syscall32_sysenter,
+ 		       syscall32_sysenter_end - syscall32_sysenter);
+ 	} else {
+  		memcpy(syscall32_page, syscall32_syscall,
+  		       syscall32_syscall_end - syscall32_syscall);
+  	}	
 	return 0;
 } 
 	
 __initcall(init_syscall32); 
+
+void __init syscall32_cpu_init(void)
+{
+	if (use_sysenter < 0)
+ 		use_sysenter = (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL);
+
+	/* Load these always in case some future AMD CPU supports
+	   SYSENTER from compat mode too. */
+	wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
+	wrmsr(MSR_IA32_SYSENTER_ESP, 0, 0);
+	wrmsrl(MSR_IA32_SYSENTER_EIP, ia32_sysenter_target);
+
+	wrmsrl(MSR_CSTAR, ia32_cstar_target);
+}
--- diff/arch/x86_64/kernel/Makefile	2004-03-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/kernel/Makefile	2004-03-16 09:37:55.524099224 +0000
@@ -8,10 +8,9 @@ obj-y	:= process.o semaphore.o signal.o 
 		ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_x86_64.o \
 		x8664_ksyms.o i387.o syscall.o vsyscall.o \
 		setup64.o bootflag.o e820.o reboot.o warmreboot.o
-obj-y += mce.o
+obj-y += mce.o acpi/
 
 obj-$(CONFIG_MTRR)		+= ../../i386/kernel/cpu/mtrr/
-obj-$(CONFIG_ACPI)		+= acpi/
 obj-$(CONFIG_X86_MSR)		+= msr.o
 obj-$(CONFIG_MICROCODE)		+= microcode.o
 obj-$(CONFIG_X86_CPUID)		+= cpuid.o
@@ -27,6 +26,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-03-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/kernel/acpi/boot.c	2004-03-16 09:37:55.525099072 +0000
@@ -78,6 +78,31 @@ __acpi_map_table (
 	return NULL; 
 } 	      
 
+#ifdef CONFIG_PCI_MMCONFIG
+static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
+{
+	struct acpi_table_mcfg *mcfg;
+
+	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 u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
@@ -234,6 +259,24 @@ acpi_parse_nmi_src (
 
 #endif /*CONFIG_X86_IO_APIC*/
 
+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
 static int __init
 acpi_parse_hpet (
@@ -404,6 +447,8 @@ acpi_boot_init (void)
 		return result;
 	}
 
+	(void) acpi_table_parse(ACPI_BOOT, acpi_parse_sbf);
+
 	result = acpi_blacklisted();
 	if (result) {
 		printk(KERN_WARNING PREFIX "BIOS listed in blacklist, disabling ACPI support\n");
@@ -550,6 +595,12 @@ acpi_boot_init (void)
 		printk("ACPI: no HPET table found (%d).\n", result); 
 #endif
 
+#ifdef CONFIG_PCI_MMCONFIG
+	result = acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+	if (result)
+		printk(KERN_ERR PREFIX "Error %d parsing MCFG\n", result);
+#endif
+
 	return 0;
 }
 
--- diff/arch/x86_64/kernel/entry.S	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/x86_64/kernel/entry.S	2004-03-16 09:37:55.527098768 +0000
@@ -131,8 +131,8 @@ ENTRY(ret_from_fork)
 	CFI_DEFAULT_STACK
 	call schedule_tail
 	GET_THREAD_INFO(%rcx)
-	bt $TIF_SYSCALL_TRACE,threadinfo_flags(%rcx)
-	jc rff_trace
+	testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx)
+	jnz rff_trace
 rff_action:	
 	RESTORE_REST
 	testl $3,CS-ARGOFFSET(%rsp)	# from kernel_thread?
@@ -143,7 +143,7 @@ rff_action:	
 	jmp ret_from_sys_call
 rff_trace:
 	movq %rsp,%rdi
-	call syscall_trace
+	call syscall_trace_leave
 	GET_THREAD_INFO(%rcx)	
 	jmp rff_action
 	CFI_ENDPROC
@@ -185,8 +185,8 @@ ENTRY(system_call)
 	movq  %rax,ORIG_RAX-ARGOFFSET(%rsp) 
 	movq  %rcx,RIP-ARGOFFSET(%rsp)  
 	GET_THREAD_INFO(%rcx)
-	bt    $TIF_SYSCALL_TRACE,threadinfo_flags(%rcx) 
-	jc    tracesys
+	testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx)
+	jnz tracesys
 	cmpq $__NR_syscall_max,%rax
 	ja badsys
 	movq %r10,%rcx
@@ -226,7 +226,7 @@ sysret_careful:
 	/* Handle a signal */ 
 sysret_signal:
 	sti
-	testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME),%edx
+	testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
 	jz    1f
 
 	/* Really a signal */
@@ -244,7 +244,7 @@ tracesys:			 
 	movq $-ENOSYS,RAX(%rsp)
 	FIXUP_TOP_OF_STACK %rdi
 	movq %rsp,%rdi
-	call syscall_trace
+	call syscall_trace_enter
 	LOAD_ARGS ARGOFFSET  /* reload args from stack in case ptrace changed it */
 	RESTORE_REST
 	cmpq $__NR_syscall_max,%rax
@@ -254,7 +254,7 @@ tracesys:			 
 	movq %rax,RAX-ARGOFFSET(%rsp)
 1:	SAVE_REST
 	movq %rsp,%rdi
-	call syscall_trace
+	call syscall_trace_leave
 	RESTORE_TOP_OF_STACK %rbx
 	RESTORE_REST
 	jmp ret_from_sys_call
@@ -297,17 +297,18 @@ int_very_careful:
 	sti
 	SAVE_REST
 	/* Check for syscall exit trace */	
-	bt $TIF_SYSCALL_TRACE,%edx
-	jnc int_signal
+	testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),%edx
+	jz int_signal
 	pushq %rdi
 	leaq 8(%rsp),%rdi	# &ptregs -> arg1	
-	call syscall_trace
+	call syscall_trace_leave
 	popq %rdi
 	btr  $TIF_SYSCALL_TRACE,%edi
+	btr  $TIF_SYSCALL_AUDIT,%edi
 	jmp int_restore_rest
 	
 int_signal:
-	testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING),%edx
+	testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_SINGLESTEP),%edx
 	jz 1f
 	movq %rsp,%rdi		# &ptregs -> arg1
 	xorl %esi,%esi		# oldset -> arg2
@@ -489,7 +490,7 @@ retint_careful:
 	jmp retint_check
 	
 retint_signal:
-	testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME),%edx
+	testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
 	jz    retint_swapgs
 	sti
 	SAVE_REST
@@ -572,6 +573,24 @@ ENTRY(spurious_interrupt)
 	jmp error_entry
 	.endm
 
+	/* error code is on the stack already */
+	/* handle NMI like exceptions that can happen everywhere */
+	.macro paranoidentry sym
+	SAVE_ALL
+	cld
+	movl $1,%ebx
+	movl  $MSR_GS_BASE,%ecx
+	rdmsr
+	testl %edx,%edx
+	js    1f
+	swapgs
+	xorl  %ebx,%ebx
+1:	movq %rsp,%rdi
+	movq ORIG_RAX(%rsp),%rsi
+	movq $-1,ORIG_RAX(%rsp)
+	call \sym
+	.endm
+	
 /*
  * Exception entry point. This expects an error code/orig_rax on the stack
  * and the exception handler in %rax.	
@@ -625,6 +644,7 @@ error_sti:	
 	movq ORIG_RAX(%rsp),%rsi	/* get error code */ 
 	movq $-1,ORIG_RAX(%rsp)
 	call *%rax
+	/* ebx:	no swapgs flag (1: don't need swapgs, 0: need it) */	 
 error_exit:		
 	movl %ebx,%eax		
 	RESTORE_REST
@@ -776,48 +796,59 @@ ENTRY(simd_coprocessor_error)
 	zeroentry do_simd_coprocessor_error	
 
 ENTRY(device_not_available)
-	CFI_STARTPROC
-	pushq $-1	#error code
-	SAVE_ALL
-	movl  $1,%ebx
-	testl $3,CS(%rsp)
-	je 1f
-	xorl %ebx,%ebx
-	swapgs
-1:	movq  %cr0,%rax
-	leaq  math_state_restore(%rip),%rcx
-	leaq  math_emulate(%rip),%rdx
-	testl $0x4,%eax
-	cmoveq %rcx,%rdx
-	call  *%rdx
-	jmp  error_exit
-	CFI_ENDPROC
+	zeroentry math_state_restore
 
+	/* runs on exception stack */
 ENTRY(debug)
-	zeroentry do_debug
+	CFI_STARTPROC
+	pushq $0
+	CFI_ADJUST_CFA_OFFSET 8		
+	paranoidentry do_debug
+paranoid_stack_switch:	
+	testq %rax,%rax
+	jz paranoid_exit
+	/* switch back to process stack to restore the state ptrace touched */
+	movq %rax,%rsp	
+	jmp paranoid_exit
+	CFI_ENDPROC
 
+	/* runs on exception stack */	
 ENTRY(nmi)
 	CFI_STARTPROC
 	pushq $-1
-	SAVE_ALL
-        /* NMI could happen inside the critical section of a swapgs,
-           so it is needed to use this expensive way to check. */
-        movl  $MSR_GS_BASE,%ecx
-        rdmsr
-        xorl  %ebx,%ebx
-        testl %edx,%edx
-        js    1f
-	swapgs
-	movl $1,%ebx
-1:	movq %rsp,%rdi # regs -> arg1
-	call do_nmi
-	/* XXX: should do preemption checks here */
+	CFI_ADJUST_CFA_OFFSET 8		
+	paranoidentry do_nmi
+	/* ebx:	no swapgs flag */
+paranoid_exit:
+	testl $3,CS(%rsp)
+	jnz   paranoid_userspace	
+	testl %ebx,%ebx				/* swapgs needed? */
+	jnz paranoid_restore
+paranoid_swapgs:	
 	cli
-	testl %ebx,%ebx
-	jz 2f
 	swapgs
-2:	RESTORE_ALL 8
+paranoid_restore:	
+	RESTORE_ALL 8
 	iretq
+paranoid_userspace:	
+	cli
+	GET_THREAD_INFO(%rcx)
+	movl threadinfo_flags(%rcx),%edx
+	testl $_TIF_NEED_RESCHED,%edx
+	jnz paranoid_resched
+	testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
+	jnz paranoid_signal
+	jmp paranoid_swapgs
+paranoid_resched:		
+	sti
+	call schedule
+	jmp paranoid_exit
+paranoid_signal:		
+	sti
+	xorl %esi,%esi /* oldset */
+	movq %rsp,%rdi /* &pt_regs */
+	call do_notify_resume
+	jmp paranoid_exit
 	CFI_ENDPROC
 	
 ENTRY(int3)
@@ -838,8 +869,10 @@ ENTRY(coprocessor_segment_overrun)
 ENTRY(reserved)
 	zeroentry do_reserved
 
+	/* runs on exception stack */
 ENTRY(double_fault)
-	errorentry do_double_fault	
+	paranoidentry do_double_fault
+	jmp paranoid_stack_switch
 
 ENTRY(invalid_TSS)
 	errorentry do_invalid_TSS
@@ -847,8 +880,10 @@ ENTRY(invalid_TSS)
 ENTRY(segment_not_present)
 	errorentry do_segment_not_present
 
+	/* runs on exception stack */
 ENTRY(stack_segment)
-	errorentry do_stack_segment
+	paranoidentry do_stack_segment
+	jmp paranoid_stack_switch
 
 ENTRY(general_protection)
 	errorentry do_general_protection
@@ -862,8 +897,14 @@ ENTRY(divide_error)
 ENTRY(spurious_interrupt_bug)
 	zeroentry do_spurious_interrupt_bug
 
+	/* runs on exception stack */
 ENTRY(machine_check)
-       zeroentry do_machine_check      
+	CFI_STARTPROC
+	pushq $0
+	CFI_ADJUST_CFA_OFFSET 8	
+	paranoidentry do_machine_check
+	jmp paranoid_exit
+	CFI_ENDPROC
 
 ENTRY(call_debug)
        zeroentry do_call_debug
--- diff/arch/x86_64/kernel/ioport.c	2003-09-30 14:46:12.000000000 +0000
+++ source/arch/x86_64/kernel/ioport.c	2004-03-16 09:37:55.527098768 +0000
@@ -95,7 +95,5 @@ asmlinkage long sys_iopl(unsigned int le
 			return -EPERM;
 	}
 	regs.eflags = (regs.eflags &~ 0x3000UL) | (level << 12);
-	/* Make sure we return the long way (not sysenter) */
-	set_thread_flag(TIF_IRET);
 	return 0;
 }
--- diff/arch/x86_64/kernel/irq.c	2004-03-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/kernel/irq.c	2004-03-16 09:37:55.528098616 +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-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/kernel/mpparse.c	2004-03-16 09:37:55.529098464 +0000
@@ -880,6 +880,7 @@ extern FADT_DESCRIPTOR acpi_fadt;
 
 void __init mp_config_ioapic_for_sci(int irq)
 {
+#ifdef CONFIG_ACPI_INTERPRETER
 	int ioapic;
 	int ioapic_pin;
 	struct acpi_table_madt *madt;
@@ -939,6 +940,7 @@ found:
 	 */
 	io_apic_set_pci_routing(ioapic, ioapic_pin, irq, 
 		(flags.trigger == 1 ? 0 : 1), (flags.polarity == 1 ? 0 : 1));
+#endif
 }
 
 #ifdef CONFIG_ACPI_PCI
--- diff/arch/x86_64/kernel/pci-gart.c	2004-03-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/kernel/pci-gart.c	2004-03-16 09:37:55.530098312 +0000
@@ -50,6 +50,12 @@ int force_iommu = 0;
 #endif
 int iommu_merge = 0; 
 int iommu_sac_force = 0; 
+
+/* If this is disabled the IOMMU will use an optimized flushing strategy
+   of only flushing when an mapping is reused. With it true the GART is flushed 
+   for every mapping. Problem is that doing the lazy flush seems to trigger
+   bugs with some popular PCI cards, in particular 3ware (but has been also
+   also seen with Qlogic at least). */
 int iommu_fullflush = 1;
 
 #define MAX_NB 8
@@ -177,7 +183,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-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/kernel/process.c	2004-03-16 09:37:55.530098312 +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>
@@ -53,7 +51,7 @@ asmlinkage extern void ret_from_fork(voi
 
 unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED;
 
-int hlt_counter;
+atomic_t hlt_counter = ATOMIC_INIT(0);
 
 /*
  * Powermanagement idle function, if any..
@@ -62,14 +60,14 @@ void (*pm_idle)(void);
 
 void disable_hlt(void)
 {
-	hlt_counter++;
+	atomic_inc(&hlt_counter);
 }
 
 EXPORT_SYMBOL(disable_hlt);
 
 void enable_hlt(void)
 {
-	hlt_counter--;
+	atomic_dec(&hlt_counter);
 }
 
 EXPORT_SYMBOL(enable_hlt);
@@ -80,7 +78,7 @@ EXPORT_SYMBOL(enable_hlt);
  */
 void default_idle(void)
 {
-	if (!hlt_counter) {
+	if (!atomic_read(&hlt_counter)) {
 		local_irq_disable();
 		if (!need_resched())
 			safe_halt();
--- diff/arch/x86_64/kernel/ptrace.c	2003-06-09 13:18:18.000000000 +0000
+++ source/arch/x86_64/kernel/ptrace.c	2004-03-16 09:37:55.531098160 +0000
@@ -16,6 +16,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/security.h>
+#include <linux/audit.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -486,7 +487,7 @@ out:
 	return ret;
 }
 
-asmlinkage void syscall_trace(struct pt_regs *regs)
+static void syscall_trace(struct pt_regs *regs)
 {
 
 #if 0
@@ -513,3 +514,23 @@ asmlinkage void syscall_trace(struct pt_
 		current->exit_code = 0;
 	}
 }
+
+asmlinkage void syscall_trace_enter(struct pt_regs *regs)
+{
+	if (unlikely(current->audit_context))
+		audit_syscall_entry(current, regs->orig_rax, regs->rdi);
+
+	if (test_thread_flag(TIF_SYSCALL_TRACE)
+	    && (current->ptrace & PT_PTRACED))
+		syscall_trace(regs);
+}
+
+asmlinkage void syscall_trace_leave(struct pt_regs *regs)
+{
+	if (unlikely(current->audit_context))
+		audit_syscall_exit(current);
+
+	if (test_thread_flag(TIF_SYSCALL_TRACE)
+	    && (current->ptrace & PT_PTRACED))
+		syscall_trace(regs);
+}
--- diff/arch/x86_64/kernel/setup.c	2004-03-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/kernel/setup.c	2004-03-16 09:37:55.532098008 +0000
@@ -218,6 +218,11 @@ static __init void parse_cmdline_early (
 		if (!memcmp(from, "acpi=ht", 7)) { 
 			acpi_ht = 1; 
 		}
+
+		/* acpi=strict disables out-of-spec workarounds */
+		else if (!memcmp(from, "acpi=strict", 11)) {
+			acpi_strict = 1;
+		}
 #endif
 
 		if (!memcmp(from, "nolapic", 7) ||
@@ -793,13 +798,12 @@ struct cpu_model_info {
 	char *model_names[16];
 };
 
-/*
- * This does the hard work of actually picking apart the CPU stuff...
- */
-void __init identify_cpu(struct cpuinfo_x86 *c)
+/* Do some early cpuid on the boot CPU to get some parameter that are
+   needed before check_bugs. Everything advanced is in identify_cpu
+   below. */
+void __init early_identify_cpu(struct cpuinfo_x86 *c)
 {
-	int i;
-	u32 xlvl, tfms;
+	u32 tfms;
 
 	c->loops_per_jiffy = loops_per_jiffy;
 	c->x86_cache_size = -1;
@@ -807,6 +811,7 @@ void __init identify_cpu(struct cpuinfo_
 	c->x86_model = c->x86_mask = 0;	/* So far unknown... */
 	c->x86_vendor_id[0] = '\0'; /* Unset */
 	c->x86_model_id[0] = '\0';  /* Unset */
+	c->x86_clflush_size = 64;
 	memset(&c->x86_capability, 0, sizeof c->x86_capability);
 
 	/* Get vendor name */
@@ -816,6 +821,7 @@ void __init identify_cpu(struct cpuinfo_
 	      (int *)&c->x86_vendor_id[4]);
 		
 	get_cpu_vendor(c);
+
 	/* Initialize the standard set of capabilities */
 	/* Note that the vendor-specific code below might override */
 
@@ -837,6 +843,17 @@ void __init identify_cpu(struct cpuinfo_
 		/* Have CPUID level 0 only - unheard of */
 		c->x86 = 4;
 	}
+}
+
+/*
+ * This does the hard work of actually picking apart the CPU stuff...
+ */
+void __init identify_cpu(struct cpuinfo_x86 *c)
+{
+	int i;
+	u32 xlvl;
+
+	early_identify_cpu(c);
 
 	/* AMD-defined flags: level 0x80000001 */
 	xlvl = cpuid_eax(0x80000000);
@@ -854,7 +871,6 @@ void __init identify_cpu(struct cpuinfo_
 			c->x86_capability[2] = cpuid_edx(0x80860001);
 	}
 
-
 	/*
 	 * Vendor-specific initialization.  In this section we
 	 * canonicalize the feature flags, meaning if there are
--- diff/arch/x86_64/kernel/setup64.c	2004-03-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/kernel/setup64.c	2004-03-16 09:37:55.533097856 +0000
@@ -202,7 +202,7 @@ void __init syscall_init(void)
 	wrmsrl(MSR_LSTAR, system_call); 
 
 #ifdef CONFIG_IA32_EMULATION   		
-	wrmsrl(MSR_CSTAR, ia32_cstar_target); 
+	syscall32_cpu_init ();
 #endif
 
 	/* Flags to clear on syscall */
@@ -274,6 +274,9 @@ void __init cpu_init (void)
 
 	asm volatile("pushfq ; popq %%rax ; btr $14,%%rax ; pushq %%rax ; popfq" ::: "eax");
 
+	if (cpu == 0) 
+		early_identify_cpu(&boot_cpu_data);
+
 	syscall_init();
 
 	wrmsrl(MSR_FS_BASE, 0);
@@ -287,7 +290,8 @@ void __init cpu_init (void)
 	 */
 	for (v = 0; v < N_EXCEPTION_STACKS; v++) {
 		if (cpu) {
-			estacks = (char *)__get_free_pages(GFP_ATOMIC, 0);
+			estacks = (char *)__get_free_pages(GFP_ATOMIC, 
+						   EXCEPTION_STACK_ORDER);
 			if (!estacks)
 				panic("Cannot allocate exception stack %ld %d\n",
 				      v, cpu); 
--- diff/arch/x86_64/kernel/smp.c	2003-11-25 15:24:57.000000000 +0000
+++ source/arch/x86_64/kernel/smp.c	2004-03-16 09:37:55.533097856 +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/smpboot.c	2004-03-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/kernel/smpboot.c	2004-03-16 09:37:55.534097704 +0000
@@ -55,11 +55,16 @@
 
 /* Number of siblings per CPU package */
 int smp_num_siblings = 1;
-int phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */
+char phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */
 
 /* Bitmask of currently online CPUs */
 cpumask_t cpu_online_map;
 
+/* which CPU (physical APIC ID) maps to which logical CPU number */
+volatile char x86_apicid_to_cpu[NR_CPUS];
+/* which logical CPU number maps to which CPU (physical APIC ID) */
+volatile char x86_cpu_to_apicid[NR_CPUS];
+
 static cpumask_t cpu_callin_map;
 cpumask_t cpu_callout_map;
 static cpumask_t smp_commenced_mask;
@@ -70,7 +75,7 @@ struct cpuinfo_x86 cpu_data[NR_CPUS] __c
 /* Set when the idlers are all forked */
 int smp_threads_ready;
 
-int cpu_sibling_map[NR_CPUS] __cacheline_aligned;
+char cpu_sibling_map[NR_CPUS] __cacheline_aligned;
 
 /*
  * Trampoline 80x86 program as an array.
@@ -574,6 +579,9 @@ static void __init do_boot_cpu (int apic
 	if (IS_ERR(idle))
 		panic("failed fork for CPU %d", cpu);
 	wake_up_forked_process(idle);	
+	x86_cpu_to_apicid[cpu] = apicid;
+	x86_apicid_to_cpu[apicid] = cpu;
+
 
 	/*
 	 * We remove it from the pidhash and the runqueue
@@ -885,7 +893,7 @@ static void __init smp_boot_cpus(unsigne
 					break;
 				}
 			}
-			if (cpu_sibling_map[cpu] == NO_PROC_ID) {
+			if (cpu_sibling_map[cpu] == (char)NO_PROC_ID) {
 				smp_num_siblings = 1;
 				printk(KERN_WARNING "WARNING: No sibling found for CPU %d.\n", cpu);
 			}
--- diff/arch/x86_64/kernel/traps.c	2004-03-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/kernel/traps.c	2004-03-16 09:37:55.535097552 +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]; 
 
@@ -351,24 +354,19 @@ void oops_end(void)
 
 void __die(const char * str, struct pt_regs * regs, long err)
 {
-	int nl = 0;
 	static int die_counter;
-	printk(KERN_EMERG "%s: %04lx [%u]\n", str, err & 0xffff,++die_counter);
-	notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
+	printk(KERN_EMERG "%s: %04lx [%u] ", str, err & 0xffff,++die_counter);
 #ifdef CONFIG_PREEMPT
 	printk("PREEMPT ");
-	nl = 1;
 #endif
 #ifdef CONFIG_SMP
 	printk("SMP ");
-	nl = 1;
 #endif
 #ifdef CONFIG_DEBUG_PAGEALLOC
 	printk("DEBUG_PAGEALLOC");
-	nl = 1;
 #endif
-	if (nl)
 		printk("\n");
+	notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
 	show_registers(regs);
 	/* Executive summary in case the oops scrolled away */
 	printk("RIP "); 
@@ -475,14 +473,27 @@ DO_ERROR( 4, SIGSEGV, "overflow", overfl
 DO_ERROR( 5, SIGSEGV, "bounds", bounds)
 DO_ERROR_INFO( 6, SIGILL,  "invalid operand", invalid_op, ILL_ILLOPN, regs->rip)
 DO_ERROR( 7, SIGSEGV, "device not available", device_not_available)
-DO_ERROR( 8, SIGSEGV, "double fault", double_fault)
 DO_ERROR( 9, SIGFPE,  "coprocessor segment overrun", coprocessor_segment_overrun)
 DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
 DO_ERROR(11, SIGBUS,  "segment not present", segment_not_present)
-DO_ERROR(12, SIGBUS,  "stack segment", stack_segment)
 DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2())
 DO_ERROR(18, SIGSEGV, "reserved", reserved)
 
+#define DO_ERROR_STACK(trapnr, signr, str, name) \
+asmlinkage unsigned long do_##name(struct pt_regs * regs, long error_code) \
+{ \
+	struct pt_regs *pr = ((struct pt_regs *)(current->thread.rsp0))-1; \
+	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \
+		return 0; \
+	if (regs->cs & 3) \
+		memcpy(pr, regs, sizeof(struct pt_regs)); \
+	do_trap(trapnr, signr, str, regs, error_code, NULL); \
+	return (regs->cs & 3) ? (unsigned long)pr : 0;		\
+}
+
+DO_ERROR_STACK(12, SIGBUS,  "stack segment", stack_segment)
+DO_ERROR_STACK( 8, SIGSEGV, "double fault", double_fault)
+
 asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
 {
 	conditional_sti(regs);
@@ -596,12 +607,18 @@ asmlinkage void default_do_nmi(struct pt
 	inb(0x71);		/* dummy */
 }
 
-asmlinkage void do_debug(struct pt_regs * regs, long error_code)
+/* runs on IST stack. */
+asmlinkage unsigned long do_debug(struct pt_regs * regs, unsigned long error_code)
 {
+	struct pt_regs *processregs;
 	unsigned long condition;
 	struct task_struct *tsk = current;
 	siginfo_t info;
 
+	processregs = (struct pt_regs *)(current->thread.rsp0)-1;
+	if (regs->cs & 3)
+		memcpy(processregs, regs, sizeof(struct pt_regs));
+
 #ifdef CONFIG_CHECKING
        { 
 	       /* RED-PEN interaction with debugger - could destroy gs */
@@ -658,17 +675,21 @@ asmlinkage void do_debug(struct pt_regs 
 	force_sig_info(SIGTRAP, &info, tsk);	
 clear_dr7:
 	asm volatile("movq %0,%%db7"::"r"(0UL));
-	notify_die(DIE_DEBUG, "debug", regs, error_code, 1, SIGTRAP);
-	return;
+	notify_die(DIE_DEBUG, "debug", regs, condition, 1, SIGTRAP);
+out:
+	return (regs->cs & 3) ? (unsigned long)processregs : 0;
 
 clear_TF_reenable:
+	printk("clear_tf_reenable\n");
 	set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
 
 clear_TF:
 	/* RED-PEN could cause spurious errors */
-	if (notify_die(DIE_DEBUG, "debug2", regs, error_code, 1, SIGTRAP) != NOTIFY_BAD)
+	if (notify_die(DIE_DEBUG, "debug2", regs, condition, 1, SIGTRAP) 
+	    != NOTIFY_BAD)
 	regs->eflags &= ~TF_MASK;
-	return;
+	
+	goto out;
 }
 
 /*
@@ -730,7 +751,7 @@ void math_error(void *rip)
 	force_sig_info(SIGFPE, &info, task);
 }
 
-asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
+asmlinkage void do_coprocessor_error(struct pt_regs * regs)
 {
 	conditional_sti(regs);
 	math_error((void *)regs->rip);
@@ -789,8 +810,7 @@ static inline void simd_math_error(void 
 	force_sig_info(SIGFPE, &info, task);
 }
 
-asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs,
-					  long error_code)
+asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs)
 {
 	conditional_sti(regs);
 		simd_math_error((void *)regs->rip);
@@ -818,11 +838,6 @@ asmlinkage void math_state_restore(void)
 	me->thread_info->status |= TS_USEDFPU;
 }
 
-asmlinkage void math_emulate(void)
-{
-	BUG();
-}
-
 void do_call_debug(struct pt_regs *regs) 
 { 
 	notify_die(DIE_CALL, "debug call", regs, 0, 255, SIGINT); 
@@ -831,7 +846,7 @@ void do_call_debug(struct pt_regs *regs)
 void __init trap_init(void)
 {
 	set_intr_gate(0,&divide_error);
-	set_intr_gate(1,&debug);
+	set_intr_gate_ist(1,&debug,DEBUG_STACK);
 	set_intr_gate_ist(2,&nmi,NMI_STACK);
 	set_system_gate(3,&int3);	/* int3-5 can be called from all */
 	set_system_gate(4,&overflow);
@@ -848,7 +863,7 @@ void __init trap_init(void)
 	set_intr_gate(15,&spurious_interrupt_bug);
 	set_intr_gate(16,&coprocessor_error);
 	set_intr_gate(17,&alignment_check);
-	set_intr_gate(18,&machine_check); 
+	set_intr_gate_ist(18,&machine_check, MCE_STACK); 
 	set_intr_gate(19,&simd_coprocessor_error);
 
 #ifdef CONFIG_IA32_EMULATION
--- diff/arch/x86_64/kernel/vsyscall.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/x86_64/kernel/vsyscall.c	2004-03-16 09:37:55.535097552 +0000
@@ -31,9 +31,6 @@
  *    broken programs will segfault and there's no security risk until we choose to
  *    fix it.
  *
- * Add HPET support (port from 2.4). Still needed?
- * Nop out vsyscall syscall to avoid anchor for buffer overflows when sysctl off.
- * 
  * These are not urgent things that we need to address only before shipping the first
  * production binary kernels.
  */
@@ -89,7 +86,7 @@ static force_inline void do_vgettimeofda
 			if (t < __vxtime.last_tsc) t = __vxtime.last_tsc;
 			usec += ((t - __vxtime.last_tsc) *
 				 __vxtime.tsc_quot) >> 32;
-			/* See comment in x86_64 do_gettimeopfday. */ 
+			/* See comment in x86_64 do_gettimeofday. */ 
 		} else {
 			usec += ((readl(fix_to_virt(VSYSCALL_HPET) + 0xf0) -
 				  __vxtime.last) * __vxtime.quot) >> 32;
@@ -106,6 +103,7 @@ static force_inline void do_get_tz(struc
 		*tz = __sys_tz;
 }
 
+
 static force_inline int gettimeofday(struct timeval *tv, struct timezone *tz)
 {
 	int ret;
@@ -115,6 +113,15 @@ static force_inline int gettimeofday(str
 	return ret;
 }
 
+static force_inline long time_syscall(long *t)
+{
+	long secs;
+	asm volatile("syscall" 
+		: "=a" (secs)
+		: "0" (__NR_time),"D" (t) : __syscall_clobber);
+	return secs;
+}
+
 static int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
 {
 	if (unlikely(!__sysctl_vsyscall))
@@ -126,16 +133,15 @@ static int __vsyscall(0) vgettimeofday(s
 	return 0;
 }
 
-static time_t __vsyscall(1) vtime(time_t * t)
+/* This will break when the xtime seconds get inaccurate, but that is
+ * unlikely */
+static time_t __vsyscall(1) vtime(time_t *t)
 {
-	struct timeval tv; 
 	if (unlikely(!__sysctl_vsyscall))
-		gettimeofday(&tv, NULL);
-	else
-		do_vgettimeofday(&tv);
-	if (t)
-		*t = tv.tv_sec; 
-	return tv.tv_sec;
+		return time_syscall(t);
+	else if (t)
+		*t = __xtime.tv_sec;		
+	return __xtime.tv_sec;
 }
 
 static long __vsyscall(2) venosys_0(void)
--- diff/arch/x86_64/kernel/x8664_ksyms.c	2004-03-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/kernel/x8664_ksyms.c	2004-03-16 09:37:55.536097400 +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);
@@ -225,3 +221,6 @@ EXPORT_SYMBOL_GPL(flush_tlb_all);
 #endif
 
 EXPORT_SYMBOL(sys_ioctl);
+
+EXPORT_SYMBOL(memcpy_toio);
+EXPORT_SYMBOL(memcpy_fromio);
--- diff/arch/x86_64/lib/Makefile	2003-06-30 09:07:20.000000000 +0000
+++ source/arch/x86_64/lib/Makefile	2004-03-16 09:37:55.536097400 +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/csum-copy.S	2004-03-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/lib/csum-copy.S	2004-03-16 09:37:55.536097400 +0000
@@ -220,10 +220,14 @@ csum_partial_copy_generic:
 	/* Exception handlers. Very simple, zeroing is done in the wrappers */
 .Lbad_source:
 	movq (%rsp),%rax
+	testq %rax,%rax
+	jz   .Lende
 	movl $-EFAULT,(%rax)
 	jmp  .Lende
 	
 .Lbad_dest:
 	movq 8(%rsp),%rax
+	testq %rax,%rax
+	jz   .Lende	
 	movl $-EFAULT,(%rax)
 	jmp .Lende
--- diff/arch/x86_64/lib/io.c	2002-12-30 10:17:12.000000000 +0000
+++ source/arch/x86_64/lib/io.c	2004-03-16 09:37:55.537097248 +0000
@@ -4,14 +4,10 @@
 
 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);
-EXPORT_SYMBOL(memcpy_fromio);
-
--- diff/arch/x86_64/mm/fault.c	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/x86_64/mm/fault.c	2004-03-16 09:37:55.538097096 +0000
@@ -280,15 +280,6 @@ asmlinkage void do_page_fault(struct pt_
 	if (unlikely(in_atomic() || !mm))
 		goto bad_area_nosemaphore;
 
-	/* Work around K8 erratum #100
-	   K8 in compat mode occasionally jumps to illegal addresses >4GB.
-	   We catch this here in the page fault handler because these
-	   addresses are not reachable. Just detect this case and return.
-	   Any code segment in LDT is compatibility mode. */
-	if ((regs->cs == __USER32_CS || (regs->cs & (1<<2))) &&
-		(address >> 32))
-		return;
-
  again:
 	down_read(&mm->mmap_sem);
 
@@ -373,6 +364,16 @@ bad_area_nosemaphore:
 		if (is_prefetch(regs, address))
 			return;
 
+		/* Work around K8 erratum #100 K8 in compat mode
+		   occasionally jumps to illegal addresses >4GB.  We
+		   catch this here in the page fault handler because
+		   these addresses are not reachable. Just detect this
+		   case and return.  Any code segment in LDT is
+		   compatibility mode. */
+		if ((regs->cs == __USER32_CS || (regs->cs & (1<<2))) &&
+		    (address >> 32))
+			return;
+
 		if (exception_trace && !unhandled_signal(tsk, SIGSEGV)) { 
 		printk(KERN_INFO 
 		       "%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %lx\n",
--- diff/arch/x86_64/mm/init.c	2004-03-11 10:20:23.000000000 +0000
+++ source/arch/x86_64/mm/init.c	2004-03-16 09:37:55.538097096 +0000
@@ -37,7 +37,9 @@
 #include <asm/proto.h>
 #include <asm/smp.h>
 
+#ifndef Dprintk
 #define Dprintk(x...)
+#endif
 
 extern char _stext[];
 
@@ -577,3 +579,32 @@ static __init int x8664_sysctl_init(void
 }
 __initcall(x8664_sysctl_init);
 #endif
+
+/* Pseudo VMAs to allow ptrace access for the vsyscall pages.  x86-64 has two
+   different ones: one for 32bit and one for 64bit. Use the appropiate
+   for the target task. */
+
+static struct vm_area_struct gate_vma = {
+	.vm_start = VSYSCALL_START,
+	.vm_end = VSYSCALL_END,
+	.vm_page_prot = PAGE_READONLY
+};
+
+static struct vm_area_struct gate32_vma = {
+	.vm_start = VSYSCALL32_BASE,
+	.vm_end = VSYSCALL32_END,
+	.vm_page_prot = PAGE_READONLY
+};
+
+struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
+{
+	return test_tsk_thread_flag(tsk, TIF_IA32) ? &gate32_vma : &gate_vma;
+}
+
+int in_gate_area(struct task_struct *task, unsigned long addr)
+{
+	struct vm_area_struct *vma = &gate_vma;
+	if (test_tsk_thread_flag(task, TIF_IA32))
+		vma = &gate32_vma;
+	return (addr >= vma->vm_start) && (addr < vma->vm_end);
+}
--- diff/arch/x86_64/mm/numa.c	2003-11-25 15:24:57.000000000 +0000
+++ source/arch/x86_64/mm/numa.c	2004-03-16 09:37:55.539096944 +0000
@@ -14,7 +14,9 @@
 #include <asm/dma.h>
 #include <asm/numa.h>
 
+#ifndef Dprintk
 #define Dprintk(x...)
+#endif
 
 struct pglist_data *node_data[MAXNODE];
 bootmem_data_t plat_node_bdata[MAX_NUMNODES];
--- diff/arch/x86_64/pci/Makefile	2003-06-30 09:07:29.000000000 +0000
+++ source/arch/x86_64/pci/Makefile	2004-03-16 09:37:55.539096944 +0000
@@ -1,29 +1,22 @@
 #
 # Makefile for X86_64 specific PCI routines
 #
-# Reuse the i386 PCI subsystem using symlinks
+# Reuse the i386 PCI subsystem
 #
+CFLAGS += -I arch/i386/pci
+
 obj-y		:= i386.o
 obj-$(CONFIG_PCI_DIRECT)+= direct.o
 obj-y		+= fixup.o
 obj-$(CONFIG_ACPI_PCI)	+= acpi.o
 obj-y			+= legacy.o irq.o common.o
+# mmconfig has a 64bit special
+obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o
 
-$(obj)/direct.c: $(obj)/pci.h
-	@ln -sf ../../i386/pci/direct.c $(obj)/direct.c
-$(obj)/legacy.c: $(obj)/pci.h
-	@ln -sf ../../i386/pci/legacy.c $(obj)/legacy.c
-$(obj)/common.c: $(obj)/pci.h
-	@ln -sf ../../i386/pci/common.c $(obj)/common.c
-$(obj)/acpi.c: $(obj)/pci.h
-	@ln -sf ../../i386/pci/acpi.c $(obj)/acpi.c
-$(obj)/pci.h:
-	@ln -sf ../../i386/pci/pci.h $(obj)/pci.h
-$(obj)/irq.c: $(obj)/pci.h
-	@ln -sf ../../i386/pci/irq.c $(obj)/irq.c
-$(obj)/fixup.c: $(obj)/pci.h
-	@ln -sf ../../i386/pci/fixup.c $(obj)/fixup.c
-$(obj)/i386.c: $(obj)/pci.h
-	@ln -sf ../../i386/pci/i386.c $(obj)/i386.c
-
-clean-files += i386.c legacy.c fixup.c acpi.c irq.c pci.h common.c direct.c
+direct-y += ../../i386/pci/direct.o
+acpi-y   += ../../i386/pci/acpi.o
+legacy-y += ../../i386/pci/legacy.o
+irq-y    += ../../i386/pci/irq.o
+common-y += ../../i386/pci/common.o
+fixup-y  += ../../i386/pci/fixup.o
+i386-y  += ../../i386/pci/i386.o
--- diff/drivers/acpi/dispatcher/dsmethod.c	2004-02-09 10:36:09.000000000 +0000
+++ source/drivers/acpi/dispatcher/dsmethod.c	2004-03-16 09:37:55.540096792 +0000
@@ -106,7 +106,7 @@ acpi_ds_parse_method (
 
 	/* Create a mutex for the method if there is a concurrency limit */
 
-	if ((obj_desc->method.concurrency != INFINITE_CONCURRENCY) &&
+	if ((obj_desc->method.concurrency != ACPI_INFINITE_CONCURRENCY) &&
 		(!obj_desc->method.semaphore)) {
 		status = acpi_os_create_semaphore (obj_desc->method.concurrency,
 				   obj_desc->method.concurrency,
@@ -300,34 +300,37 @@ acpi_ds_call_control_method (
 		return_ACPI_STATUS (status);
 	}
 
-	/* 1) Parse: Create a new walk state for the preempting walk */
+	if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) {
+		/* 1) Parse: Create a new walk state for the preempting walk */
 
-	next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id,
-			  op, obj_desc, NULL);
-	if (!next_walk_state) {
-		return_ACPI_STATUS (AE_NO_MEMORY);
-	}
+		next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id,
+				  op, obj_desc, NULL);
+		if (!next_walk_state) {
+			return_ACPI_STATUS (AE_NO_MEMORY);
+		}
 
-	/* Create and init a Root Node */
 
-	op = acpi_ps_create_scope_op ();
-	if (!op) {
-		status = AE_NO_MEMORY;
-		goto cleanup;
-	}
+		/* Create and init a Root Node */
 
-	status = acpi_ds_init_aml_walk (next_walk_state, op, method_node,
-			  obj_desc->method.aml_start, obj_desc->method.aml_length,
-			  NULL, NULL, 1);
-	if (ACPI_FAILURE (status)) {
-		acpi_ds_delete_walk_state (next_walk_state);
-		goto cleanup;
-	}
+		op = acpi_ps_create_scope_op ();
+		if (!op) {
+			status = AE_NO_MEMORY;
+			goto cleanup;
+		}
+
+		status = acpi_ds_init_aml_walk (next_walk_state, op, method_node,
+				  obj_desc->method.aml_start, obj_desc->method.aml_length,
+				  NULL, NULL, 1);
+		if (ACPI_FAILURE (status)) {
+			acpi_ds_delete_walk_state (next_walk_state);
+			goto cleanup;
+		}
 
-	/* Begin AML parse */
+		/* Begin AML parse */
 
-	status = acpi_ps_parse_aml (next_walk_state);
-	acpi_ps_delete_parse_tree (op);
+		status = acpi_ps_parse_aml (next_walk_state);
+		acpi_ps_delete_parse_tree (op);
+	}
 
 	/* 2) Execute: Create a new state for the preempting walk */
 
@@ -337,7 +340,6 @@ acpi_ds_call_control_method (
 		status = AE_NO_MEMORY;
 		goto cleanup;
 	}
-
 	/*
 	 * The resolved arguments were put on the previous walk state's operand
 	 * stack.  Operands on the previous walk state stack always
@@ -369,16 +371,25 @@ acpi_ds_call_control_method (
 	ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
 		"Starting nested execution, newstate=%p\n", next_walk_state));
 
+	if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
+		status = obj_desc->method.implementation (next_walk_state);
+		return_ACPI_STATUS (status);
+	}
+
 	return_ACPI_STATUS (AE_OK);
 
 
 	/* On error, we must delete the new walk state */
 
 cleanup:
+	if (next_walk_state->method_desc) {
+		/* Decrement the thread count on the method parse tree */
+
+	   next_walk_state->method_desc->method.thread_count--;
+	}
 	(void) acpi_ds_terminate_control_method (next_walk_state);
 	acpi_ds_delete_walk_state (next_walk_state);
 	return_ACPI_STATUS (status);
-
 }
 
 
@@ -500,11 +511,31 @@ acpi_ds_terminate_control_method (
 		}
 	}
 
-	/* Decrement the thread count on the method parse tree */
+	if (walk_state->method_desc->method.thread_count) {
+		ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+			"*** Not deleting method namespace, there are still %d threads\n",
+			walk_state->method_desc->method.thread_count));
+	}
 
-	walk_state->method_desc->method.thread_count--;
 	if (!walk_state->method_desc->method.thread_count) {
 		/*
+		 * Support to dynamically change a method from not_serialized to
+		 * Serialized if it appears that the method is written foolishly and
+		 * does not support multiple thread execution.  The best example of this
+		 * is if such a method creates namespace objects and blocks.  A second
+		 * thread will fail with an AE_ALREADY_EXISTS exception
+		 *
+		 * This code is here because we must wait until the last thread exits
+		 * before creating the synchronization semaphore.
+		 */
+		if ((walk_state->method_desc->method.concurrency == 1) &&
+			(!walk_state->method_desc->method.semaphore)) {
+			status = acpi_os_create_semaphore (1,
+					 1,
+					 &walk_state->method_desc->method.semaphore);
+		}
+
+		/*
 		 * There are no more threads executing this method.  Perform
 		 * additional cleanup.
 		 *
--- diff/drivers/acpi/events/evgpe.c	2004-02-09 10:36:09.000000000 +0000
+++ source/drivers/acpi/events/evgpe.c	2004-03-16 09:37:55.541096640 +0000
@@ -149,6 +149,11 @@ acpi_ev_gpe_detect (
 
 	ACPI_FUNCTION_NAME ("ev_gpe_detect");
 
+	/* Check for the case where there are no GPEs */
+
+	if (!gpe_xrupt_list) {
+		return (int_status);
+	}
 
 	/* Examine all GPE blocks attached to this interrupt level */
 
--- diff/drivers/acpi/executer/excreate.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/executer/excreate.c	2004-03-16 09:37:55.541096640 +0000
@@ -587,27 +587,33 @@ acpi_ex_create_method (
 	obj_desc->method.aml_start = aml_start;
 	obj_desc->method.aml_length = aml_length;
 
-	/* disassemble the method flags */
-
+	/*
+	 * Disassemble the method flags.  Split off the Arg Count
+	 * for efficiency
+	 */
 	method_flags = (u8) operand[1]->integer.value;
 
-	obj_desc->method.method_flags = method_flags;
-	obj_desc->method.param_count = (u8) (method_flags & METHOD_FLAGS_ARG_COUNT);
+	obj_desc->method.method_flags = (u8) (method_flags & ~AML_METHOD_ARG_COUNT);
+	obj_desc->method.param_count = (u8) (method_flags & AML_METHOD_ARG_COUNT);
 
 	/*
 	 * Get the concurrency count.  If required, a semaphore will be
 	 * created for this method when it is parsed.
 	 */
-	if (method_flags & METHOD_FLAGS_SERIALIZED) {
+	if (acpi_gbl_all_methods_serialized) {
+		obj_desc->method.concurrency = 1;
+		obj_desc->method.method_flags |= AML_METHOD_SERIALIZED;
+	}
+	else if (method_flags & AML_METHOD_SERIALIZED) {
 		/*
 		 * ACPI 1.0: Concurrency = 1
 		 * ACPI 2.0: Concurrency = (sync_level (in method declaration) + 1)
 		 */
 		obj_desc->method.concurrency = (u8)
-				  (((method_flags & METHOD_FLAGS_SYNCH_LEVEL) >> 4) + 1);
+				  (((method_flags & AML_METHOD_SYNCH_LEVEL) >> 4) + 1);
 	}
 	else {
-		obj_desc->method.concurrency = INFINITE_CONCURRENCY;
+		obj_desc->method.concurrency = ACPI_INFINITE_CONCURRENCY;
 	}
 
 	/* Attach the new object to the method Node */
--- diff/drivers/acpi/executer/exmutex.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/executer/exmutex.c	2004-03-16 09:37:55.542096488 +0000
@@ -176,15 +176,18 @@ acpi_ex_acquire_mutex (
 	/*
 	 * Support for multiple acquires by the owning thread
 	 */
+	if (obj_desc->mutex.owner_thread) {
+		/* Special case for Global Lock, allow all threads */
 
-	if ((obj_desc->mutex.owner_thread) &&
-		(obj_desc->mutex.owner_thread->thread_id == walk_state->thread->thread_id)) {
-		/*
-		 * The mutex is already owned by this thread,
-		 * just increment the acquisition depth
-		 */
-		obj_desc->mutex.acquisition_depth++;
-		return_ACPI_STATUS (AE_OK);
+		if ((obj_desc->mutex.owner_thread->thread_id == walk_state->thread->thread_id) ||
+			(obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore)) {
+			/*
+			 * The mutex is already owned by this thread,
+			 * just increment the acquisition depth
+			 */
+			obj_desc->mutex.acquisition_depth++;
+			return_ACPI_STATUS (AE_OK);
+		}
 	}
 
 	/* Acquire the mutex, wait if necessary */
@@ -254,9 +257,12 @@ acpi_ex_release_mutex (
 		return_ACPI_STATUS (AE_AML_INTERNAL);
 	}
 
-	/* The Mutex is owned, but this thread must be the owner */
-
-	if (obj_desc->mutex.owner_thread->thread_id != walk_state->thread->thread_id) {
+	/*
+	 * The Mutex is owned, but this thread must be the owner.
+	 * Special case for Global Lock, any thread can release
+	 */
+	if ((obj_desc->mutex.owner_thread->thread_id != walk_state->thread->thread_id) &&
+		(obj_desc->mutex.semaphore != acpi_gbl_global_lock_semaphore)) {
 		ACPI_REPORT_ERROR ((
 			"Thread %X cannot release Mutex [%4.4s] acquired by thread %X\n",
 			walk_state->thread->thread_id,
--- diff/drivers/acpi/hardware/hwsleep.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/acpi/hardware/hwsleep.c	2004-03-16 09:37:55.542096488 +0000
@@ -394,7 +394,7 @@ acpi_enter_sleep_state (
  *
  ******************************************************************************/
 
-acpi_status
+acpi_status asmlinkage
 acpi_enter_sleep_state_s4bios (
 	void)
 {
--- diff/drivers/acpi/namespace/nsaccess.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/acpi/namespace/nsaccess.c	2004-03-16 09:37:55.544096184 +0000
@@ -105,8 +105,15 @@ acpi_ns_root_initialize (void)
 		"Entering predefined entries into namespace\n"));
 
 	for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) {
+		/* _OSI is optional for now, will be permanent later */
+
+		if (!ACPI_STRCMP (init_val->name, "_OSI") && !acpi_gbl_create_osi_method) {
+			continue;
+		}
+
 		status = acpi_ns_lookup (NULL, init_val->name, init_val->type,
-				  ACPI_IMODE_LOAD_PASS2, ACPI_NS_NO_UPSEARCH, NULL, &new_node);
+				  ACPI_IMODE_LOAD_PASS2, ACPI_NS_NO_UPSEARCH,
+				  NULL, &new_node);
 
 		if (ACPI_FAILURE (status) || (!new_node)) /* Must be on same line for code converter */ {
 			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
@@ -122,7 +129,8 @@ acpi_ns_root_initialize (void)
 		if (init_val->val) {
 			status = acpi_os_predefined_override (init_val, &val);
 			if (ACPI_FAILURE (status)) {
-				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not override predefined %s\n",
+				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+					"Could not override predefined %s\n",
 					init_val->name));
 			}
 
@@ -147,15 +155,20 @@ acpi_ns_root_initialize (void)
 			 */
 			switch (init_val->type) {
 			case ACPI_TYPE_METHOD:
-				obj_desc->method.param_count =
-						(u8) ACPI_STRTOUL (val, NULL, 10);
+				obj_desc->method.param_count = (u8) ACPI_STRTOUL
+						  (val, NULL, 10);
 				obj_desc->common.flags |= AOPOBJ_DATA_VALID;
 
-#if defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)
+#if defined (_ACPI_ASL_COMPILER) || defined (_ACPI_DUMP_App)
 
-				/* Compiler cheats by putting parameter count in the owner_iD */
+				/* i_aSL Compiler cheats by putting parameter count in the owner_iD */
 
 				new_node->owner_id = obj_desc->method.param_count;
+#else
+				/* Mark this as a very SPECIAL method */
+
+				obj_desc->method.method_flags = AML_METHOD_INTERNAL_ONLY;
+				obj_desc->method.implementation = acpi_ut_osi_implementation;
 #endif
 				break;
 
@@ -180,8 +193,8 @@ acpi_ns_root_initialize (void)
 			case ACPI_TYPE_MUTEX:
 
 				obj_desc->mutex.node = new_node;
-				obj_desc->mutex.sync_level =
-						 (u16) ACPI_STRTOUL (val, NULL, 10);
+				obj_desc->mutex.sync_level = (u16) ACPI_STRTOUL
+						  (val, NULL, 10);
 
 				if (ACPI_STRCMP (init_val->name, "_GL_") == 0) {
 					/*
@@ -213,6 +226,7 @@ acpi_ns_root_initialize (void)
 
 
 			default:
+
 				ACPI_REPORT_ERROR (("Unsupported initial type value %X\n",
 					init_val->type));
 				acpi_ut_remove_reference (obj_desc);
--- diff/drivers/acpi/namespace/nsalloc.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/namespace/nsalloc.c	2004-03-16 09:37:55.544096184 +0000
@@ -334,10 +334,11 @@ acpi_ns_install_node (
 	node->owner_id = owner_id;
 	node->type = (u8) type;
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%4.4s (%s) added to %4.4s (%s) %p at %p\n",
-		acpi_ut_get_node_name (node), acpi_ut_get_type_name (node->type),
+	ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+		"%4.4s (%s) [Node %p Owner %X] added to %4.4s (%s) [Node %p]\n",
+		acpi_ut_get_node_name (node), acpi_ut_get_type_name (node->type), node, owner_id,
 		acpi_ut_get_node_name (parent_node), acpi_ut_get_type_name (parent_node->type),
-		parent_node, node));
+		parent_node));
 
 	/*
 	 * Increment the reference count(s) of all parents up to
--- diff/drivers/acpi/namespace/nseval.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/acpi/namespace/nseval.c	2004-03-16 09:37:55.545096032 +0000
@@ -82,11 +82,11 @@ acpi_ns_evaluate_relative (
 	union acpi_operand_object       **params,
 	union acpi_operand_object       **return_object)
 {
-	struct acpi_namespace_node      *prefix_node;
 	acpi_status                     status;
+	struct acpi_namespace_node      *prefix_node;
 	struct acpi_namespace_node      *node = NULL;
+	union acpi_generic_state        *scope_info;
 	char                            *internal_path = NULL;
-	union acpi_generic_state        scope_info;
 
 
 	ACPI_FUNCTION_TRACE ("ns_evaluate_relative");
@@ -106,6 +106,11 @@ acpi_ns_evaluate_relative (
 		return_ACPI_STATUS (status);
 	}
 
+	scope_info = acpi_ut_create_generic_state ();
+	if (!scope_info) {
+		goto cleanup1;
+	}
+
 	/* Get the prefix handle and Node */
 
 	status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
@@ -122,8 +127,8 @@ acpi_ns_evaluate_relative (
 
 	/* Lookup the name in the namespace */
 
-	scope_info.scope.node = prefix_node;
-	status = acpi_ns_lookup (&scope_info, internal_path, ACPI_TYPE_ANY,
+	scope_info->scope.node = prefix_node;
+	status = acpi_ns_lookup (scope_info, internal_path, ACPI_TYPE_ANY,
 			 ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL,
 			 &node);
 
@@ -148,7 +153,9 @@ acpi_ns_evaluate_relative (
 		pathname));
 
 cleanup:
+	acpi_ut_delete_generic_state (scope_info);
 
+cleanup1:
 	ACPI_MEM_FREE (internal_path);
 	return_ACPI_STATUS (status);
 }
--- diff/drivers/acpi/osl.c	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/acpi/osl.c	2004-03-16 09:37:55.546095880 +0000
@@ -1012,3 +1012,39 @@ acpi_os_name_setup(char *str)
 }
 
 __setup("acpi_os_name=", acpi_os_name_setup);
+
+/*
+ * _OSI control
+ * empty string disables _OSI
+ * TBD additional string adds to _OSI
+ */
+int __init
+acpi_osi_setup(char *str)
+{
+	if (str == NULL || *str == '\0') {
+		printk(KERN_INFO PREFIX "_OSI method disabled\n");
+		acpi_gbl_create_osi_method = FALSE;
+	} else
+	{
+		/* TBD */
+		printk(KERN_ERR PREFIX "_OSI additional string ignored -- %s\n", str);
+	}
+
+	return 1;
+}
+
+__setup("acpi_osi=", acpi_osi_setup);
+
+/* enable serialization to combat AE_ALREADY_EXISTS errors */
+int __init
+acpi_serialize_setup(char *str)
+{
+	printk(KERN_INFO PREFIX "serialize enabled\n");
+
+	acpi_gbl_all_methods_serialized = TRUE;
+
+	return 1;
+}
+
+__setup("acpi_serialize", acpi_serialize_setup);
+
--- diff/drivers/acpi/parser/psparse.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/parser/psparse.c	2004-03-16 09:37:55.547095728 +0000
@@ -426,7 +426,7 @@ acpi_ps_parse_loop (
 	acpi_status                     status = AE_OK;
 	union acpi_parse_object         *op = NULL;     /* current op */
 	union acpi_parse_object         *arg = NULL;
-	union acpi_parse_object         pre_op;
+	union acpi_parse_object         *pre_op = NULL;
 	struct acpi_parse_state         *parser_state;
 	u8                              *aml_op_start = NULL;
 
@@ -547,8 +547,17 @@ acpi_ps_parse_loop (
 			/* Create Op structure and append to parent's argument list */
 
 			if (walk_state->op_info->flags & AML_NAMED) {
-				pre_op.common.value.arg = NULL;
-				pre_op.common.aml_opcode = walk_state->opcode;
+				/* Allocate a new pre_op if necessary */
+
+				if (!pre_op) {
+					pre_op = acpi_ps_alloc_op (walk_state->opcode);
+					if (!pre_op) {
+						return_ACPI_STATUS (AE_NO_MEMORY);
+					}
+				}
+
+				pre_op->common.value.arg = NULL;
+				pre_op->common.aml_opcode = walk_state->opcode;
 
 				/*
 				 * Get and append arguments until we find the node that contains
@@ -562,7 +571,7 @@ acpi_ps_parse_loop (
 						goto close_this_op;
 					}
 
-					acpi_ps_append_arg (&pre_op, arg);
+					acpi_ps_append_arg (pre_op, arg);
 					INCREMENT_ARG_LIST (walk_state->arg_types);
 				}
 
@@ -603,7 +612,7 @@ acpi_ps_parse_loop (
 					goto close_this_op;
 				}
 
-				acpi_ps_append_arg (op, pre_op.common.value.arg);
+				acpi_ps_append_arg (op, pre_op->common.value.arg);
 				acpi_gbl_depth++;
 
 				if (op->common.aml_opcode == AML_REGION_OP) {
@@ -854,6 +863,10 @@ close_this_op:
 
 		acpi_ps_complete_this_op (walk_state, op);
 		op = NULL;
+		if (pre_op) {
+			acpi_ps_free_op (pre_op);
+			pre_op = NULL;
+		}
 
 		switch (status) {
 		case AE_OK:
@@ -1118,6 +1131,27 @@ acpi_ps_parse_aml (
 		else if (status != AE_OK) {
 			ACPI_REPORT_METHOD_ERROR ("Method execution failed",
 				walk_state->method_node, NULL, status);
+
+			/* Check for possible multi-thread reentrancy problem */
+
+			if ((status == AE_ALREADY_EXISTS) &&
+				(!walk_state->method_desc->method.semaphore)) {
+				/*
+				 * This method is marked not_serialized, but it tried to create a named
+				 * object, causing the second thread entrance to fail.  We will workaround
+				 * this by marking the method permanently as Serialized.
+				 */
+				walk_state->method_desc->method.method_flags |= AML_METHOD_SERIALIZED;
+				walk_state->method_desc->method.concurrency = 1;
+			}
+		}
+
+		if (walk_state->method_desc) {
+			/* Decrement the thread count on the method parse tree */
+
+			if (walk_state->method_desc->method.thread_count) {
+				walk_state->method_desc->method.thread_count--;
+			}
 		}
 
 		/* We are done with this walk, move on to the parent if any */
--- diff/drivers/acpi/parser/psscope.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/parser/psscope.c	2004-03-16 09:37:55.548095576 +0000
@@ -167,7 +167,6 @@ acpi_ps_push_scope (
 		return_ACPI_STATUS (AE_NO_MEMORY);
 	}
 
-
 	scope->common.data_type        = ACPI_DESC_TYPE_STATE_PSCOPE;
 	scope->parse_scope.op          = op;
 	scope->parse_scope.arg_list    = remaining_args;
@@ -178,13 +177,11 @@ acpi_ps_push_scope (
 
 	acpi_ut_push_generic_state (&parser_state->scope, scope);
 
-
 	if (arg_count == ACPI_VAR_ARGS) {
 		/* multiple arguments */
 
 		scope->parse_scope.arg_end = parser_state->pkg_end;
 	}
-
 	else {
 		/* single argument */
 
@@ -241,7 +238,6 @@ acpi_ps_pop_scope (
 
 		acpi_ut_delete_generic_state (scope);
 	}
-
 	else {
 		/* empty parse stack, prepare to fetch next opcode */
 
@@ -250,7 +246,6 @@ acpi_ps_pop_scope (
 		*arg_count              = 0;
 	}
 
-
 	ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped Op %p Args %X\n", *op, *arg_count));
 	return_VOID;
 }
@@ -275,14 +270,14 @@ acpi_ps_cleanup_scope (
 {
 	union acpi_generic_state        *scope;
 
+
 	ACPI_FUNCTION_TRACE_PTR ("ps_cleanup_scope", parser_state);
 
 
 	if (!parser_state) {
-		return;
+		return_VOID;
 	}
 
-
 	/* Delete anything on the scope stack */
 
 	while (parser_state->scope) {
--- diff/drivers/acpi/power.c	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/acpi/power.c	2004-03-16 09:37:55.548095576 +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/sleep/poweroff.c	2003-02-26 16:00:53.000000000 +0000
+++ source/drivers/acpi/sleep/poweroff.c	2004-03-16 09:37:55.548095576 +0000
@@ -8,11 +8,14 @@
 #include <linux/pm.h>
 #include <linux/init.h>
 #include <acpi/acpi_bus.h>
+#include <linux/sched.h>
 
 static void
 acpi_power_off (void)
 {
 	printk("%s called\n",__FUNCTION__);
+	/* Some SMP machines only can poweroff in boot CPU */
+	set_cpus_allowed(current, cpumask_of_cpu(0));
 	acpi_enter_sleep_state_prep(ACPI_STATE_S5);
 	ACPI_DISABLE_IRQS();
 	acpi_enter_sleep_state(ACPI_STATE_S5);
--- diff/drivers/acpi/tables.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/acpi/tables.c	2004-03-16 09:37:55.549095424 +0000
@@ -386,8 +386,13 @@ acpi_table_parse (
 	for (i = 0; i < sdt_count; i++) {
 		if (sdt_entry[i].id != id)
 			continue;
-		handler(sdt_entry[i].pa, sdt_entry[i].size);
 		count++;
+		if (count == 1)
+			handler(sdt_entry[i].pa, sdt_entry[i].size);
+
+		else
+			printk(KERN_WARNING PREFIX "%d duplicate %s table ignored.\n",
+				count, acpi_table_signatures[id]);
 	}
 
 	return count;
--- diff/drivers/acpi/utilities/uteval.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/acpi/utilities/uteval.c	2004-03-16 09:37:55.550095272 +0000
@@ -53,6 +53,62 @@
 
 /*******************************************************************************
  *
+ * FUNCTION:    acpi_ut_osi_implementation
+ *
+ * PARAMETERS:  walk_state          - Current walk state
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Implementation of _OSI predefined control method
+ *              Supported = _OSI (String)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_osi_implementation (
+	struct acpi_walk_state          *walk_state)
+{
+	union acpi_operand_object       *string_desc;
+	union acpi_operand_object       *return_desc;
+	acpi_native_uint                i;
+
+
+	ACPI_FUNCTION_TRACE ("ut_osi_implementation");
+
+
+	/* Validate the string input argument */
+
+	string_desc = walk_state->arguments[0].object;
+	if (!string_desc || (string_desc->common.type != ACPI_TYPE_STRING)) {
+		return_ACPI_STATUS (AE_TYPE);
+	}
+
+	/* Create a return object (Default value = 0) */
+
+	return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+	if (!return_desc) {
+		return_ACPI_STATUS (AE_NO_MEMORY);
+	}
+
+	/* Compare input string to table of supported strings */
+
+	for (i = 0; i < ACPI_NUM_OSI_STRINGS; i++) {
+		if (!ACPI_STRCMP (string_desc->string.pointer,
+				   (char *) acpi_gbl_valid_osi_strings[i])) {
+			/* This string is supported */
+
+			return_desc->integer.value = 0xFFFFFFFF;
+			break;
+		}
+	}
+
+	walk_state->return_desc = return_desc;
+	return_ACPI_STATUS (AE_CTRL_TERMINATE);
+}
+
+
+/*******************************************************************************
+ *
  * FUNCTION:    acpi_ut_evaluate_object
  *
  * PARAMETERS:  prefix_node         - Starting node
--- diff/drivers/acpi/utilities/utglobal.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/acpi/utilities/utglobal.c	2004-03-16 09:37:55.551095120 +0000
@@ -185,6 +185,15 @@ const char                          *acp
 					   "_S3D",
 					   "_S4D"};
 
+/* Strings supported by the _OSI predefined (internal) method */
+
+const char                          *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS] = {
+							 "Linux",
+							 "Windows 2000",
+							 "Windows 2001",
+							 "Windows 2001.1"};
+
+
 /******************************************************************************
  *
  * Namespace globals
@@ -195,14 +204,10 @@ const char                          *acp
 /*
  * Predefined ACPI Names (Built-in to the Interpreter)
  *
- * Initial values are currently supported only for types String and Number.
- * Both are specified as strings in this table.
- *
  * NOTES:
- * 1) _SB_ is defined to be a device to allow _SB_/_INI to be run
+ * 1) _SB_ is defined to be a device to allow \_SB_._INI to be run
  *    during the initialization sequence.
  */
-
 const struct acpi_predefined_names      acpi_gbl_pre_defined_names[] =
 { {"_GPE",    ACPI_TYPE_LOCAL_SCOPE,      NULL},
 	{"_PR_",    ACPI_TYPE_LOCAL_SCOPE,      NULL},
@@ -213,7 +218,7 @@ const struct acpi_predefined_names      
 	{"_OS_",    ACPI_TYPE_STRING,           ACPI_OS_NAME},
 	{"_GL_",    ACPI_TYPE_MUTEX,            "0"},
 
-#if defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)
+#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)
 	{"_OSI",    ACPI_TYPE_METHOD,           "1"},
 #endif
 	{NULL,      ACPI_TYPE_ANY,              NULL}              /* Table terminator */
@@ -224,7 +229,6 @@ const struct acpi_predefined_names      
  * Properties of the ACPI Object Types, both internal and external.
  * The table is indexed by values of acpi_object_type
  */
-
 const u8                                acpi_gbl_ns_properties[] =
 {
 	ACPI_NS_NORMAL,                     /* 00 Any              */
@@ -303,10 +307,8 @@ acpi_ut_hex_to_ascii_char (
  *
  ******************************************************************************/
 
-
 struct acpi_table_list              acpi_gbl_table_lists[NUM_ACPI_TABLE_TYPES];
 
-
 struct acpi_table_support           acpi_gbl_table_data[NUM_ACPI_TABLE_TYPES] =
 {
 	/***********    Name,   Signature, Global typed pointer     Signature size,      Type                  How many allowed?,    Contains valid AML? */
@@ -470,9 +472,8 @@ acpi_ut_get_event_name (
  *
  * The type ACPI_TYPE_ANY (Untyped) is used as a "don't care" when searching; when
  * stored in a table it really means that we have thus far seen no evidence to
- * indicatewhat type is actually going to be stored for this entry.
+ * indicate what type is actually going to be stored for this entry.
  */
-
 static const char                   acpi_gbl_bad_type[] = "UNDEFINED";
 #define TYPE_NAME_LENGTH    12                           /* Maximum length of each string */
 
@@ -777,6 +778,11 @@ acpi_ut_init_globals (
 
 	ACPI_FUNCTION_TRACE ("ut_init_globals");
 
+	/* Runtime configuration */
+
+	acpi_gbl_create_osi_method = TRUE;
+	acpi_gbl_all_methods_serialized = FALSE;
+
 	/* Memory allocation and cache lists */
 
 	ACPI_MEMSET (acpi_gbl_memory_lists, 0, sizeof (struct acpi_memory_list) * ACPI_NUM_MEM_LISTS);
--- diff/drivers/atm/fore200e.c	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/atm/fore200e.c	2004-03-16 09:37:55.553094816 +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 03:28:23.000000000 +0000
+++ source/drivers/atm/fore200e.h	2004-03-16 09:37:55.554094664 +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-16 09:37:55.557094208 +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/Makefile	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/base/Makefile	2004-03-16 09:37:55.598087976 +0000
@@ -6,3 +6,8 @@ obj-y			:= core.o sys.o interface.o bus.
 obj-y			+= power/
 obj-$(CONFIG_FW_LOADER)	+= firmware_class.o
 obj-$(CONFIG_NUMA)	+= node.o
+
+ifeq ($(CONFIG_DEBUG_DRIVER),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
--- diff/drivers/base/bus.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/base/bus.c	2004-03-16 09:37:55.599087824 +0000
@@ -9,10 +9,6 @@
  */
 
 #include <linux/config.h>
-#ifdef CONFIG_DEBUG_DRIVER
-#define DEBUG	1
-#endif
-
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/errno.h>
--- diff/drivers/base/class.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/base/class.c	2004-03-16 09:37:55.600087672 +0000
@@ -11,10 +11,6 @@
  */
 
 #include <linux/config.h>
-#ifdef CONFIG_DEBUG_DRIVER
-#define DEBUG	1
-#endif
-
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -106,13 +102,21 @@ void class_put(struct class * cls)
 
 int class_register(struct class * cls)
 {
+	int error;
+
 	pr_debug("device class '%s': registering\n",cls->name);
 
 	INIT_LIST_HEAD(&cls->children);
 	INIT_LIST_HEAD(&cls->interfaces);
-	kobject_set_name(&cls->subsys.kset.kobj,cls->name);
+	error = kobject_set_name(&cls->subsys.kset.kobj,cls->name);
+	if (error)
+		return error;
+
 	subsys_set_kset(cls,class_subsys);
-	subsystem_register(&cls->subsys);
+
+	error = subsystem_register(&cls->subsys);
+	if (error)
+		return error;
 
 	return 0;
 }
--- diff/drivers/base/class_simple.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/base/class_simple.c	2004-03-16 09:37:55.600087672 +0000
@@ -9,10 +9,6 @@
  */
 
 #include <linux/config.h>
-#ifdef CONFIG_DEBUG_DRIVER
-#define DEBUG	1
-#endif
-
 #include <linux/device.h>
 #include <linux/kdev_t.h>
 #include <linux/err.h>
--- diff/drivers/base/core.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/base/core.c	2004-03-16 09:37:55.600087672 +0000
@@ -9,10 +9,6 @@
  */
 
 #include <linux/config.h>
-#ifdef CONFIG_DEBUG_DRIVER
-#define DEBUG	1
-#endif
-
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/init.h>
--- diff/drivers/base/driver.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/base/driver.c	2004-03-16 09:37:55.601087520 +0000
@@ -9,10 +9,6 @@
  */
 
 #include <linux/config.h>
-#ifdef CONFIG_DEBUG_DRIVER
-#define DEBUG	1
-#endif
-
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/errno.h>
--- diff/drivers/base/map.c	2003-09-17 11:28:03.000000000 +0000
+++ source/drivers/base/map.c	2004-03-16 09:37:55.601087520 +0000
@@ -96,7 +96,7 @@ struct kobject *kobj_lookup(struct kobj_
 {
 	struct kobject *kobj;
 	struct probe *p;
-	unsigned best = ~0U;
+	unsigned long best = ~0UL;
 
 retry:
 	down_read(domain->sem);
--- diff/drivers/base/power/Makefile	2003-08-26 09:00:52.000000000 +0000
+++ source/drivers/base/power/Makefile	2004-03-16 09:37:55.602087368 +0000
@@ -1,2 +1,6 @@
 obj-y			:= shutdown.o
 obj-$(CONFIG_PM)	+= main.o suspend.o resume.o runtime.o sysfs.o
+
+ifeq ($(CONFIG_DEBUG_DRIVER),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
--- diff/drivers/base/power/main.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/base/power/main.c	2004-03-16 09:37:55.602087368 +0000
@@ -20,10 +20,6 @@
  */
 
 #include <linux/config.h>
-#ifdef CONFIG_DEBUG_DRIVER
-#define DEBUG	1
-#endif
-
 #include <linux/device.h>
 #include "power.h"
 
--- diff/drivers/base/power/shutdown.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/base/power/shutdown.c	2004-03-16 09:37:55.602087368 +0000
@@ -9,10 +9,6 @@
  */
 
 #include <linux/config.h>
-#ifdef CONFIG_DEBUG_DRIVER
-#define DEBUG	1
-#endif
-
 #include <linux/device.h>
 #include <asm/semaphore.h>
 
--- diff/drivers/base/sys.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/base/sys.c	2004-03-16 09:37:55.603087216 +0000
@@ -13,10 +13,6 @@
  */
 
 #include <linux/config.h>
-#ifdef CONFIG_DEBUG_DRIVER
-#define DEBUG	1
-#endif
-
 #include <linux/sysdev.h>
 #include <linux/err.h>
 #include <linux/module.h>
--- diff/drivers/block/Kconfig	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/block/Kconfig	2004-03-16 09:37:55.603087216 +0000
@@ -292,6 +292,15 @@ config BLK_DEV_NBD
 
 	  If unsure, say N.
 
+config BLK_DEV_CARMEL
+	tristate "Promise SATA SX8 (carmel) support"
+	depends on PCI
+	---help---
+	  Saying Y or M here will enable support for the 
+	  Promise SATA SX8 ("carmel") controllers.
+
+	  Use devices /dev/carmel/$N and /dev/carmel/$Np$M.
+
 config BLK_DEV_RAM
 	tristate "RAM disk support"
 	---help---
--- diff/drivers/block/Kconfig.iosched	2003-10-09 08:47:16.000000000 +0000
+++ source/drivers/block/Kconfig.iosched	2004-03-16 09:37:55.603087216 +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-11 10:20:23.000000000 +0000
+++ source/drivers/block/Makefile	2004-03-16 09:37:55.604087064 +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
@@ -40,3 +41,5 @@ obj-$(CONFIG_BLK_DEV_NBD)	+= nbd.o
 obj-$(CONFIG_BLK_DEV_CRYPTOLOOP) += cryptoloop.o
 
 obj-$(CONFIG_VIODASD)		+= viodasd.o
+obj-$(CONFIG_BLK_DEV_CARMEL)	+= carmel.o
+
--- diff/drivers/block/cciss_scsi.c	2003-08-26 09:00:52.000000000 +0000
+++ source/drivers/block/cciss_scsi.c	2004-03-16 09:37:55.605086912 +0000
@@ -693,7 +693,7 @@ complete_scsi_command( CommandList_struc
 	scsi_cmd_free(ctlr, cp);
 }
 
-static int __init 
+static int
 cciss_scsi_detect(int ctlr)
 {
 	struct Scsi_Host *sh;
--- diff/drivers/block/genhd.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/block/genhd.c	2004-03-16 09:37:55.605086912 +0000
@@ -184,7 +184,7 @@ static int exact_lock(dev_t dev, void *d
 }
 
 /**
- * add_gendisk - add partitioning information to kernel list
+ * add_disk - add partitioning information to kernel list
  * @disk: per-device partitioning information
  *
  * This function registers the partitioning information in @disk
--- diff/drivers/block/ll_rw_blk.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/block/ll_rw_blk.c	2004-03-16 09:37:55.609086304 +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);
@@ -36,12 +42,6 @@ static void blk_unplug_timeout(unsigned 
  */
 static kmem_cache_t *request_cachep;
 
-/*
- * plug management
- */
-static LIST_HEAD(blk_plug_list);
-static spinlock_t blk_plug_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
-
 static wait_queue_head_t congestion_wqh[2];
 
 /*
@@ -104,6 +104,7 @@ static void clear_queue_congested(reques
 
 	bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested;
 	clear_bit(bit, &q->backing_dev_info.state);
+	smp_mb__after_clear_bit();
 	if (waitqueue_active(wqh))
 		wake_up(wqh);
 }
@@ -227,9 +228,13 @@ void blk_queue_make_request(request_queu
 	blk_queue_dma_alignment(q, 511);
 
 	q->unplug_thresh = 4;		/* hmm */
+#if 0
 	q->unplug_delay = (3 * HZ) / 1000;	/* 3 milliseconds */
 	if (q->unplug_delay == 0)
 		q->unplug_delay = 1;
+#else
+	q->unplug_delay = HZ;
+#endif
 
 	INIT_WORK(&q->unplug_work, blk_unplug_work, q);
 
@@ -241,8 +246,6 @@ void blk_queue_make_request(request_queu
 	 */
 	blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
 
-	INIT_LIST_HEAD(&q->plug_list);
-
 	blk_queue_activity_fn(q, NULL, NULL);
 }
 
@@ -521,10 +524,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);
@@ -1094,13 +1097,11 @@ void blk_plug_device(request_queue_t *q)
 	 * don't plug a stopped queue, it must be paired with blk_start_queue()
 	 * which will restart the queueing
 	 */
-	if (!blk_queue_plugged(q)
-	    && !test_bit(QUEUE_FLAG_STOPPED, &q->queue_flags)) {
-		spin_lock(&blk_plug_lock);
-		list_add_tail(&q->plug_list, &blk_plug_list);
+	if (test_bit(QUEUE_FLAG_STOPPED, &q->queue_flags))
+		return;
+
+	if (!test_and_set_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags))
 		mod_timer(&q->unplug_timer, jiffies + q->unplug_delay);
-		spin_unlock(&blk_plug_lock);
-	}
 }
 
 EXPORT_SYMBOL(blk_plug_device);
@@ -1112,15 +1113,12 @@ EXPORT_SYMBOL(blk_plug_device);
 int blk_remove_plug(request_queue_t *q)
 {
 	WARN_ON(!irqs_disabled());
-	if (blk_queue_plugged(q)) {
-		spin_lock(&blk_plug_lock);
-		list_del_init(&q->plug_list);
-		del_timer(&q->unplug_timer);
-		spin_unlock(&blk_plug_lock);
-		return 1;
-	}
 
-	return 0;
+	if (!test_and_clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags))
+		return 0;
+
+	del_timer(&q->unplug_timer);
+	return 1;
 }
 
 EXPORT_SYMBOL(blk_remove_plug);
@@ -1136,8 +1134,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
 	 */
@@ -1153,14 +1149,11 @@ static inline void __generic_unplug_devi
  *   Linux uses plugging to build bigger requests queues before letting
  *   the device have at them. If a queue is plugged, the I/O scheduler
  *   is still adding and merging requests on the queue. Once the queue
- *   gets unplugged (either by manually calling this function, or by
- *   calling blk_run_queues()), the request_fn defined for the
- *   queue is invoked and transfers started.
+ *   gets unplugged, the request_fn defined for the queue is invoked and
+ *   transfers started.
  **/
-void generic_unplug_device(void *data)
+void generic_unplug_device(request_queue_t *q)
 {
-	request_queue_t *q = data;
-
 	spin_lock_irq(q->queue_lock);
 	__generic_unplug_device(q);
 	spin_unlock_irq(q->queue_lock);
@@ -1168,9 +1161,23 @@ void generic_unplug_device(void *data)
 
 EXPORT_SYMBOL(generic_unplug_device);
 
+static inline void blk_backing_dev_unplug(struct backing_dev_info *bdi)
+{
+	request_queue_t *q = bdi->unplug_io_data;
+
+	/*
+	 * devices don't necessarily have an ->unplug_fn defined
+	 */
+	if (q->unplug_fn)
+		q->unplug_fn(q);
+}
+
+EXPORT_SYMBOL(blk_backing_dev_unplug);
+
 static void blk_unplug_work(void *data)
 {
 	request_queue_t *q = data;
+
 	q->unplug_fn(q);
 }
 
@@ -1248,42 +1255,6 @@ void blk_run_queue(struct request_queue 
 EXPORT_SYMBOL(blk_run_queue);
 
 /**
- * blk_run_queues - fire all plugged queues
- *
- * Description:
- *   Start I/O on all plugged queues known to the block layer. Queues that
- *   are currently stopped are ignored. This is equivalent to the older
- *   tq_disk task queue run.
- **/
-#define blk_plug_entry(entry) list_entry((entry), request_queue_t, plug_list)
-void blk_run_queues(void)
-{
-	LIST_HEAD(local_plug_list);
-
-	spin_lock_irq(&blk_plug_lock);
-
-	/*
-	 * this will happen fairly often
-	 */
-	if (list_empty(&blk_plug_list))
-		goto out;
-
-	list_splice_init(&blk_plug_list, &local_plug_list);
-	
-	while (!list_empty(&local_plug_list)) {
-		request_queue_t *q = blk_plug_entry(local_plug_list.next);
-
-		spin_unlock_irq(&blk_plug_lock);
-		q->unplug_fn(q);
-		spin_lock_irq(&blk_plug_lock);
-	}
-out:
-	spin_unlock_irq(&blk_plug_lock);
-}
-
-EXPORT_SYMBOL(blk_run_queues);
-
-/**
  * blk_cleanup_queue: - release a &request_queue_t when it is no longer needed
  * @q:    the request queue to be released
  *
@@ -1344,6 +1315,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
@@ -1362,6 +1335,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;
@@ -1382,6 +1359,10 @@ request_queue_t *blk_alloc_queue(int gfp
 	memset(q, 0, sizeof(*q));
 	init_timer(&q->unplug_timer);
 	atomic_set(&q->refcnt, 1);
+
+	q->backing_dev_info.unplug_io_fn = blk_backing_dev_unplug;
+	q->backing_dev_info.unplug_io_data = q;
+
 	return q;
 }
 
@@ -1543,7 +1524,6 @@ static void freed_request(request_queue_
 	if (rl->count[rw] < queue_congestion_off_threshold(q))
 		clear_queue_congested(q, rw);
 	if (rl->count[rw]+1 <= q->nr_requests) {
-		smp_mb();
 		if (waitqueue_active(&rl->wait[rw]))
 			wake_up(&rl->wait[rw]);
 		if (!waitqueue_active(&rl->wait[rw]))
@@ -1625,6 +1605,7 @@ static struct request *get_request(reque
 	rq->rl = rl;
 	rq->waiting = NULL;
 	rq->special = NULL;
+	rq->data_len = 0;
 	rq->data = NULL;
 	rq->sense = NULL;
 
@@ -1770,6 +1751,144 @@ 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;
+	int ret;
+
+	rq = blk_get_request(q, rw, __GFP_WAIT);
+	if (!rq)
+		return ERR_PTR(-ENOMEM);
+
+	bio = bio_map_user(q, NULL, (unsigned long) ubuf, len, rw == READ);
+	if (!bio) {
+		int bytes = (len + 511) & ~511;
+
+		buf = kmalloc(bytes, q->bounce_gfp | GFP_USER);
+		if (!buf) {
+			ret = -ENOMEM;
+			goto fault;
+		}
+
+		if (rw == WRITE) {
+			if (copy_from_user(buf, ubuf, len)) {
+				ret = -EFAULT;
+				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 ERR_PTR(ret);
+}
+
+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
+ *
+ * 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)
+{
+	const int read = rq_data_dir(rq) == READ;
+	int ret = 0;
+
+	if (rq->biotail)
+		bio_unmap_user(rq->biotail, read);
+	if (rq->buffer) {
+		if (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);
@@ -1898,15 +2017,16 @@ EXPORT_SYMBOL(blk_put_request);
  * If no queues are congested then just wait for the next request to be
  * returned.
  */
-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);
@@ -2158,7 +2278,7 @@ out:
 	if (blk_queue_plugged(q)) {
 		int nr_queued = q->rq.count[READ] + q->rq.count[WRITE];
 
-		if (nr_queued == q->unplug_thresh)
+		if (nr_queued == q->unplug_thresh || bio_sync(bio))
 			__generic_unplug_device(q);
 	}
 	spin_unlock_irq(q->queue_lock);
@@ -2315,6 +2435,16 @@ 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;
 }
@@ -2602,10 +2732,24 @@ 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-11 10:20:23.000000000 +0000
+++ source/drivers/block/loop.c	2004-03-16 09:37:55.611086000 +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,35 @@ inactive:
 	goto out;
 }
 
+/*
+ * kick off io on the underlying address space
+ */
+static void loop_unplug(request_queue_t *q)
+{
+	struct loop_device *lo = q->queuedata;
+
+	clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags);
+	blk_run_address_space(lo->lo_backing_file->f_mapping);
+}
+
+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,16 +523,113 @@ 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)
 {
 	struct file	*file;
 	struct inode	*inode;
-	struct block_device *lo_device = NULL;
 	struct address_space *mapping;
 	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,22 +668,26 @@ 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;
 
 	set_device_ro(bdev, (lo_flags & LO_FLAGS_READ_ONLY) != 0);
 
 	lo->lo_blocksize = lo_blocksize;
-	lo->lo_device = lo_device;
+	lo->lo_device = bdev;
 	lo->lo_flags = lo_flags;
 	lo->lo_backing_file = file;
 	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));
 
@@ -570,6 +699,9 @@ static int loop_set_fd(struct loop_devic
 	 */
 	blk_queue_make_request(lo->lo_queue, loop_make_request);
 	lo->lo_queue->queuedata = lo;
+	lo->lo_queue->unplug_fn = loop_unplug;
+
+	set_capacity(disks[lo->lo_number], size);
 
 	set_blocksize(bdev, lo_blocksize);
 
@@ -660,6 +792,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 +1014,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-11 10:20:23.000000000 +0000
+++ source/drivers/block/rd.c	2004-03-16 09:37:55.611086000 +0000
@@ -271,6 +271,7 @@ static int rd_ioctl(struct inode *inode,
 static struct backing_dev_info rd_backing_dev_info = {
 	.ra_pages	= 0,	/* No readahead */
 	.memory_backed	= 1,	/* Does not contribute to dirty memory */
+	.unplug_io_fn = default_unplug_io_fn,
 };
 
 static int rd_open(struct inode *inode, struct file *filp)
--- diff/drivers/block/scsi_ioctl.c	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/block/scsi_ioctl.c	2004-03-16 09:37:55.613085696 +0000
@@ -24,13 +24,12 @@
 #include <linux/completion.h>
 #include <linux/cdrom.h>
 #include <linux/slab.h>
-#include <linux/bio.h>
 #include <linux/times.h>
 #include <asm/uaccess.h>
 
 #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] =
@@ -39,45 +38,9 @@ const unsigned char scsi_command_size[8]
 	16, 12, 10, 10
 };
 
-#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;
+EXPORT_SYMBOL(scsi_command_size);
 
-	return err;
-}
+#define BLK_DEFAULT_TIMEOUT	(60 * HZ)
 
 #include <scsi/sg.h>
 
@@ -148,9 +111,7 @@ static int sg_io(request_queue_t *q, str
 	unsigned long start_time;
 	int reading, writing;
 	struct request *rq;
-	struct bio *bio;
 	char sense[SCSI_SENSE_BUFFERSIZE];
-	void *buffer;
 
 	if (hdr->interface_id != 'S')
 		return -EINVAL;
@@ -167,11 +128,7 @@ static int sg_io(request_queue_t *q, str
 		return -EIO;
 
 	reading = writing = 0;
-	buffer = NULL;
-	bio = NULL;
 	if (hdr->dxfer_len) {
-		unsigned int bytes = (hdr->dxfer_len + 511) & ~511;
-
 		switch (hdr->dxfer_direction) {
 		default:
 			return -EINVAL;
@@ -186,31 +143,13 @@ static int sg_io(request_queue_t *q, str
 			break;
 		}
 
-		/*
-		 * first try to map it into a bio. reading from device will
-		 * be a write to vm.
-		 */
-		bio = bio_map_user(q, NULL, (unsigned long) hdr->dxferp,
-				   hdr->dxfer_len, reading);
-
-		/*
-		 * if bio setup failed, fall back to slow approach
-		 */
-		if (!bio) {
-			buffer = kmalloc(bytes, q->bounce_gfp | GFP_USER);
-			if (!buffer)
-				return -ENOMEM;
-
-			if (writing) {
-				if (copy_from_user(buffer, hdr->dxferp,
-						   hdr->dxfer_len))
-					goto out_buffer;
-			} else
-				memset(buffer, 0, hdr->dxfer_len);
-		}
-	}
+		rq = blk_rq_map_user(q, writing ? WRITE : READ, hdr->dxferp,
+				     hdr->dxfer_len);
 
-	rq = blk_get_request(q, writing ? WRITE : READ, __GFP_WAIT);
+		if (IS_ERR(rq))
+			return PTR_ERR(rq);
+	} else
+		rq = blk_get_request(q, READ, __GFP_WAIT);
 
 	/*
 	 * fill in request structure
@@ -226,14 +165,6 @@ static int sg_io(request_queue_t *q, str
 
 	rq->flags |= REQ_BLOCK_PC;
 
-	rq->bio = rq->biotail = NULL;
-
-	if (bio)
-		blk_rq_bio_prep(q, rq, bio);
-
-	rq->data = buffer;
-	rq->data_len = hdr->dxfer_len;
-
 	rq->timeout = (hdr->timeout * HZ) / 1000;
 	if (!rq->timeout)
 		rq->timeout = q->sg_timeout;
@@ -246,10 +177,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);
-
-	if (bio)
-		bio_unmap_user(bio, reading);
+	blk_execute_rq(q, bd_disk, rq);
 
 	/* write to all output members */
 	hdr->status = rq->errors;	
@@ -271,22 +199,12 @@ static int sg_io(request_queue_t *q, str
 			hdr->sb_len_wr = len;
 	}
 
-	blk_put_request(rq);
-
-	if (buffer) {
-		if (reading)
-			if (copy_to_user(hdr->dxferp, buffer, hdr->dxfer_len))
-				goto out_buffer;
-
-		kfree(buffer);
-	}
+	if (blk_rq_unmap_user(rq, hdr->dxferp, hdr->dxfer_len))
+		return -EFAULT;
 
 	/* may not have succeeded, but output values written to control
 	 * structure (struct sg_io_hdr).  */
 	return 0;
-out_buffer:
-	kfree(buffer);
-	return -EFAULT;
 }
 
 #define FORMAT_UNIT_TIMEOUT		(2 * 60 * 60 * HZ)
@@ -312,7 +230,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 +287,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) {
@@ -447,6 +365,8 @@ int scsi_cmd_ioctl(struct gendisk *bd_di
 			old_cdb = hdr.cmdp;
 			hdr.cmdp = cdb;
 			err = sg_io(q, bd_disk, &hdr);
+			if (err == -EFAULT)
+				break;
 
 			hdr.cmdp = old_cdb;
 			if (copy_to_user((struct sg_io_hdr *) arg, &hdr, sizeof(hdr)))
@@ -457,10 +377,9 @@ int scsi_cmd_ioctl(struct gendisk *bd_di
 			struct cdrom_generic_command cgc;
 			struct sg_io_hdr hdr;
 
-			if (copy_from_user(&cgc, (struct cdrom_generic_command *) arg, sizeof(cgc))) {
-				err = -EFAULT;
+			err = -EFAULT;
+			if (copy_from_user(&cgc, (struct cdrom_generic_command *) arg, sizeof(cgc)))
 				break;
-			}
 			cgc.timeout = clock_t_to_jiffies(cgc.timeout);
 			memset(&hdr, 0, sizeof(hdr));
 			hdr.interface_id = 'S';
@@ -493,7 +412,10 @@ int scsi_cmd_ioctl(struct gendisk *bd_di
 			hdr.timeout = cgc.timeout;
 			hdr.cmdp = cgc.cmd;
 			hdr.cmd_len = sizeof(cgc.cmd);
+
 			err = sg_io(q, bd_disk, &hdr);
+			if (err == -EFAULT)
+				break;
 
 			if (hdr.status)
 				err = -EIO;
@@ -529,7 +451,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:
@@ -541,4 +463,3 @@ int scsi_cmd_ioctl(struct gendisk *bd_di
 }
 
 EXPORT_SYMBOL(scsi_cmd_ioctl);
-EXPORT_SYMBOL(scsi_command_size);
--- diff/drivers/block/umem.c	2003-09-30 14:46:12.000000000 +0000
+++ source/drivers/block/umem.c	2004-03-16 09:37:55.614085544 +0000
@@ -368,9 +368,8 @@ static inline void reset_page(struct mm_
 	page->biotail = & page->bio;
 }
 
-static void mm_unplug_device(void *data)
+static void mm_unplug_device(request_queue_t *q)
 {
-	request_queue_t *q = data;
 	struct cardinfo *card = q->queuedata;
 	unsigned long flags;
 
--- diff/drivers/cdrom/cdrom.c	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/cdrom/cdrom.c	2004-03-16 09:37:55.616085240 +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,149 @@ 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 (IS_ERR(rq))
+			return PTR_ERR(rq);
+
+		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;
+			cdi->last_sense = s->sense_key;
+		}
+
+		if (blk_rq_unmap_user(rq, ubuf, len))
+			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);
+
+retry:
+	/*
+	 * for anything else than success and io error, we need to retry
+	 */
+	ret = cdrom_read_cdda_bpc(cdi, ubuf, lba, nframes);
+	if (!ret || ret != -EIO)
+		return ret;
+
+	/*
+	 * 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;
+		goto retry;
+	}
+
+	/*
+	 * so we have an io error of some sort with multi frame dma. if the
+	 * condition wasn't a hardware error
+	 * problems, not for any error
+	 */
+	if (cdi->last_sense != 0x04 && cdi->last_sense != 0x0b)
+		return ret;
+
+	printk("cdrom: dropping to old style cdda (sense=%x)\n", cdi->last_sense);
+	cdi->cdda_method = CDDA_OLD;
+	return cdrom_read_cdda_old(cdi, ubuf, lba, nframes);	
+}
+
 /* 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 +2428,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 +2445,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/cdrom/cdu31a.c	2003-09-17 11:28:04.000000000 +0000
+++ source/drivers/cdrom/cdu31a.c	2004-03-16 09:37:55.619084784 +0000
@@ -3203,13 +3203,16 @@ static struct gendisk *scd_gendisk;
 static char *load_mech[] __initdata =
     { "caddy", "tray", "pop-up", "unknown" };
 
-static void __init
+static int __init
 get_drive_configuration(unsigned short base_io,
 			unsigned char res_reg[], unsigned int *res_size)
 {
 	unsigned long retry_count;
 
 
+	if (!request_region(base_io, 4, "cdu31a"))
+		return 0;
+
 	/* Set the base address */
 	cdu31a_port = base_io;
 
@@ -3244,7 +3247,7 @@ get_drive_configuration(unsigned short b
 		/* If attention is never seen probably not a CDU31a present */
 		if (!is_attention()) {
 			res_reg[0] = 0x20;
-			return;
+			goto out_err;
 		}
 #endif
 
@@ -3254,11 +3257,17 @@ get_drive_configuration(unsigned short b
 		do_sony_cd_cmd(SONY_REQ_DRIVE_CONFIG_CMD,
 			       NULL,
 			       0, (unsigned char *) res_reg, res_size);
-		return;
+		if (*res_size <= 2 || (res_reg[0] & 0xf0) != 0)
+			goto out_err;
+		return 1;
 	}
 
 	/* Return an error */
 	res_reg[0] = 0x20;
+out_err:
+	release_region(cdu31a_port, 4);
+	cdu31a_port = 0;
+	return 0;
 }
 
 #ifndef MODULE
@@ -3307,9 +3316,6 @@ int __init cdu31a_init(void)
 	char msg[255];
 	char buf[40];
 	int i;
-	int drive_found;
-	int tmp_irq;
-
 
 	/*
 	 * According to Alex Freed (freed@europa.orion.adobe.com), this is
@@ -3323,52 +3329,33 @@ int __init cdu31a_init(void)
 		outb(0xe2, 0x9a01);
 	}
 
-	drive_found = 0;
-
 	/* Setting the base I/O address to 0xffff will disable it. */
-	if (cdu31a_port == 0xffff) {
-	} else if (cdu31a_port != 0) {
-		tmp_irq = cdu31a_irq;	/* Need IRQ 0 because we can't sleep here. */
-		cdu31a_irq = 0;
-
-		get_drive_configuration(cdu31a_port,
-					drive_config.exec_status,
-					&res_size);
-		if ((res_size > 2)
-		    && ((drive_config.exec_status[0] & 0xf0) == 0x00)) {
-			drive_found = 1;
-		}
+	if (cdu31a_port == 0xffff)
+		goto errout3;
 
+	if (cdu31a_port != 0) {
+		/* Need IRQ 0 because we can't sleep here. */
+		int tmp_irq = cdu31a_irq;
+		cdu31a_irq = 0;
+		if (!get_drive_configuration(cdu31a_port,
+					    drive_config.exec_status,
+					    &res_size))
+			goto errout3;
 		cdu31a_irq = tmp_irq;
 	} else {
 		cdu31a_irq = 0;
-		i = 0;
-		while ((cdu31a_addresses[i].base != 0)
-		       && (!drive_found)) {
-			if (check_region(cdu31a_addresses[i].base, 4)) {
-				i++;
-				continue;
-			}
-			get_drive_configuration(cdu31a_addresses[i].base,
-						drive_config.exec_status,
-						&res_size);
-			if ((res_size > 2)
-			    && ((drive_config.exec_status[0] & 0xf0) ==
-				0x00)) {
-				drive_found = 1;
+		for (i = 0; cdu31a_addresses[i].base; i++) {
+			if (get_drive_configuration(cdu31a_addresses[i].base,
+						     drive_config.exec_status,
+						     &res_size)) {
 				cdu31a_irq = cdu31a_addresses[i].int_num;
-			} else {
-				i++;
+				break;
 			}
 		}
+		if (!cdu31a_port)
+			goto errout3;
 	}
 
-	if (!drive_found)
-		goto errout3;
-
-	if (!request_region(cdu31a_port, 4, "cdu31a"))
-		goto errout3;
-
 	if (register_blkdev(MAJOR_NR, "cdu31a"))
 		goto errout2;
 
--- diff/drivers/cdrom/cm206.c	2003-09-17 11:28:04.000000000 +0000
+++ source/drivers/cdrom/cm206.c	2004-03-16 09:37:55.620084632 +0000
@@ -1389,7 +1389,7 @@ static struct gendisk *cm206_gendisk;
 
    Linus says it is too dangerous to use writes for probing, so we
    stick with pure reads for a while. Hope that 8 possible ranges,
-   check_region, 15 bits of one port and 6 of another make things
+   request_region, 15 bits of one port and 6 of another make things
    likely enough to accept the region on the first hit...
  */
 int __init probe_base_port(int base)
@@ -1400,13 +1400,15 @@ int __init probe_base_port(int base)
 	if (base)
 		b = e = base;
 	for (base = b; base <= e; base += 0x10) {
-		if (check_region(base, 0x10))
+		if (!request_region(base, 0x10,"cm206"))
 			continue;
 		for (i = 0; i < 3; i++)
 			fool = inw(base + 2);	/* empty possibly uart_receive_buffer */
 		if ((inw(base + 6) & 0xffef) != 0x0001 ||	/* line_status */
-		    (inw(base) & 0xad00) != 0)	/* data status */
+		    (inw(base) & 0xad00) != 0)	{ /* data status */
+		    	release_region(base,0x10);
 			continue;
+		}
 		return (base);
 	}
 	return 0;
@@ -1444,7 +1446,6 @@ int __init cm206_init(void)
 		return -EIO;
 	}
 	printk(" adapter at 0x%x", cm206_base);
-	request_region(cm206_base, 16, "cm206");
 	cd = (struct cm206_struct *) kmalloc(size, GFP_KERNEL);
 	if (!cd)
                goto out_base;
--- diff/drivers/cdrom/sjcd.c	2003-10-27 09:20:37.000000000 +0000
+++ source/drivers/cdrom/sjcd.c	2004-03-16 09:37:55.621084480 +0000
@@ -1700,7 +1700,7 @@ static int __init sjcd_init(void)
 	sprintf(sjcd_disk->disk_name, "sjcd");
 	sprintf(sjcd_disk->devfs_name, "sjcd");
 
-	if (check_region(sjcd_base, 4)) {
+	if (!request_region(sjcd_base, 4,"sjcd")) {
 		printk
 		    ("SJCD: Init failed, I/O port (%X) is already in use\n",
 		     sjcd_base);
--- diff/drivers/char/Kconfig	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/Kconfig	2004-03-16 09:37:55.622084328 +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
@@ -740,6 +716,7 @@ config HW_RANDOM
 
 config NVRAM
 	tristate "/dev/nvram support"
+	depends on ATARI || X86 || X86_64 || ARM || GENERIC_NVRAM
 	---help---
 	  If you say Y here and create a character special file /dev/nvram
 	  with major number 10 and minor number 144 using mknod ("man mknod"),
--- diff/drivers/char/Makefile	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/Makefile	2004-03-16 09:37:55.622084328 +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/applicom.c	2003-10-27 09:20:37.000000000 +0000
+++ source/drivers/char/applicom.c	2004-03-16 09:37:55.623084176 +0000
@@ -29,6 +29,7 @@
 #include <linux/pci.h>
 #include <linux/wait.h>
 #include <linux/init.h>
+#include <linux/fs.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
--- diff/drivers/char/drm/Kconfig	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/char/drm/Kconfig	2004-03-16 09:37:55.623084176 +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 17:54:27.000000000 +0000
+++ source/drivers/char/drm/drm.h	2004-03-16 09:37:55.624084024 +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-16 09:37:55.625083872 +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 17:54:27.000000000 +0000
+++ source/drivers/char/drm/drm_bufs.h	2004-03-16 09:37:55.626083720 +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 17:54:27.000000000 +0000
+++ source/drivers/char/drm/drm_dma.h	2004-03-16 09:37:55.627083568 +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-16 09:37:55.629083264 +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 08:47:16.000000000 +0000
+++ source/drivers/char/drm/drm_fops.h	2004-03-16 09:37:55.629083264 +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 17:54:27.000000000 +0000
+++ source/drivers/char/drm/drm_ioctl.h	2004-03-16 09:37:55.630083112 +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 14:46:12.000000000 +0000
+++ source/drivers/char/drm/drm_os_linux.h	2004-03-16 09:37:55.631082960 +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/drm_stub.h	2003-09-17 11:28:04.000000000 +0000
+++ source/drivers/char/drm/drm_stub.h	2004-03-16 09:37:55.632082808 +0000
@@ -35,6 +35,8 @@
 
 #define DRM_STUB_MAXCARDS 16	/* Enough for one machine */
 
+static struct class_simple *drm_class;
+
 /** Stub list. One for each minor. */
 static struct drm_stub_list {
 	const char             *name;
@@ -117,6 +119,7 @@ static int DRM(stub_getminor)(const char
 			DRM(stub_root) = DRM(proc_init)(dev, i, DRM(stub_root),
 							&DRM(stub_list)[i]
 							.dev_root);
+			class_simple_device_add(drm_class, MKDEV(DRM_MAJOR, i), NULL, name);
 			return i;
 		}
 	}
@@ -141,6 +144,7 @@ static int DRM(stub_putminor)(int minor)
 	DRM(proc_cleanup)(minor, DRM(stub_root),
 			  DRM(stub_list)[minor].dev_root);
 	if (minor) {
+		class_simple_device_remove(MKDEV(DRM_MAJOR, minor));
 		inter_module_put("drm");
 	} else {
 		inter_module_unregister("drm");
@@ -148,6 +152,8 @@ static int DRM(stub_putminor)(int minor)
 			  sizeof(*DRM(stub_list)) * DRM_STUB_MAXCARDS,
 			  DRM_MEM_STUB);
 		unregister_chrdev(DRM_MAJOR, "drm");
+		class_simple_device_remove(MKDEV(DRM_MAJOR, minor));
+		class_simple_destroy(drm_class);
 	}
 	return 0;
 }
@@ -170,10 +176,23 @@ int DRM(stub_register)(const char *name,
 		       drm_device_t *dev)
 {
 	struct drm_stub_info *i = NULL;
+	int ret1;
+	int ret2;
 
 	DRM_DEBUG("\n");
-	if (register_chrdev(DRM_MAJOR, "drm", &DRM(stub_fops)))
+	ret1 = register_chrdev(DRM_MAJOR, "drm", &DRM(stub_fops));
+	if (!ret1) {
+		drm_class = class_simple_create(THIS_MODULE, "drm");
+		if (IS_ERR(drm_class)) {
+			printk (KERN_ERR "Error creating drm class.\n");
+			unregister_chrdev(DRM_MAJOR, "drm");
+			return PTR_ERR(drm_class);
+		}
+	}
+	else if (ret1 == -EBUSY)
 		i = (struct drm_stub_info *)inter_module_get("drm");
+	else
+		return -1;
 
 	if (i) {
 				/* Already registered */
@@ -186,8 +205,18 @@ int DRM(stub_register)(const char *name,
 		DRM_DEBUG("calling inter_module_register\n");
 		inter_module_register("drm", THIS_MODULE, &DRM(stub_info));
 	}
-	if (DRM(stub_info).info_register)
-		return DRM(stub_info).info_register(name, fops, dev);
+	if (DRM(stub_info).info_register) {
+		ret2 = DRM(stub_info).info_register(name, fops, dev);
+		if (ret2) {
+			if (!ret1) {
+			unregister_chrdev(DRM_MAJOR, "drm");
+			class_simple_destroy(drm_class);
+			}
+			if (!i)
+				inter_module_unregister("drm");
+		}
+		return ret2;
+	}
 	return -1;
 }
 
--- diff/drivers/char/drm/gamma.h	2003-05-21 10:50:14.000000000 +0000
+++ source/drivers/char/drm/gamma.h	2004-03-16 09:37:55.632082808 +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 14:46:12.000000000 +0000
+++ source/drivers/char/drm/gamma_dma.c	2004-03-16 09:37:55.633082656 +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 10:50:14.000000000 +0000
+++ source/drivers/char/drm/gamma_drv.c	2004-03-16 09:37:55.634082504 +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 09:00:52.000000000 +0000
+++ source/drivers/char/drm/i810.h	2004-03-16 09:37:55.634082504 +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 14:46:12.000000000 +0000
+++ source/drivers/char/drm/i810_dma.c	2004-03-16 09:37:55.638081896 +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 10:50:14.000000000 +0000
+++ source/drivers/char/drm/i830.h	2004-03-16 09:37:55.638081896 +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 13:18:18.000000000 +0000
+++ source/drivers/char/drm/i830_dma.c	2004-03-16 09:37:55.640081592 +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 10:50:14.000000000 +0000
+++ source/drivers/char/drm/i830_drv.c	2004-03-16 09:37:55.640081592 +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 14:46:12.000000000 +0000
+++ source/drivers/char/drm/i830_irq.c	2004-03-16 09:37:55.640081592 +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 10:50:14.000000000 +0000
+++ source/drivers/char/drm/mga.h	2004-03-16 09:37:55.641081440 +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 13:18:18.000000000 +0000
+++ source/drivers/char/drm/mga_dma.c	2004-03-16 09:37:55.641081440 +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 03:27:56.000000000 +0000
+++ source/drivers/char/drm/mga_drv.c	2004-03-16 09:37:55.642081288 +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 13:18:18.000000000 +0000
+++ source/drivers/char/drm/mga_drv.h	2004-03-16 09:37:55.642081288 +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 10:50:14.000000000 +0000
+++ source/drivers/char/drm/mga_irq.c	2004-03-16 09:37:55.643081136 +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 09:00:52.000000000 +0000
+++ source/drivers/char/drm/r128.h	2004-03-16 09:37:55.643081136 +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 14:46:12.000000000 +0000
+++ source/drivers/char/drm/r128_cce.c	2004-03-16 09:37:55.644080984 +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 03:27:48.000000000 +0000
+++ source/drivers/char/drm/r128_drv.c	2004-03-16 09:37:55.645080832 +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 13:16:27.000000000 +0000
+++ source/drivers/char/drm/r128_drv.h	2004-03-16 09:37:55.646080680 +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 10:50:14.000000000 +0000
+++ source/drivers/char/drm/r128_irq.c	2004-03-16 09:37:55.646080680 +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	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/drm/r128_state.c	2004-03-16 09:37:55.647080528 +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 ) );
@@ -1280,6 +1280,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.
 	 */
@@ -1315,8 +1316,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;
@@ -1341,6 +1344,7 @@ int r128_cce_flip( DRM_IOCTL_ARGS )
 
 	r128_cce_dispatch_flip( dev );
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1362,6 +1366,7 @@ int r128_cce_swap( DRM_IOCTL_ARGS )
 	dev_priv->sarea_priv->dirty |= (R128_UPLOAD_CONTEXT |
 					R128_UPLOAD_MASKS);
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1421,6 +1426,7 @@ int r128_cce_vertex( DRM_IOCTL_ARGS )
 
 	r128_cce_dispatch_vertex( dev, buf );
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1492,6 +1498,7 @@ int r128_cce_indices( DRM_IOCTL_ARGS )
 
 	r128_cce_dispatch_indices( dev, buf, elts.start, elts.end, count );
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1501,6 +1508,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 );
 
@@ -1518,7 +1526,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 )
@@ -1526,6 +1537,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 );
 
@@ -1534,18 +1546,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 )
@@ -1568,6 +1582,7 @@ int r128_cce_stipple( DRM_IOCTL_ARGS )
 
 	r128_cce_dispatch_stipple( dev, mask );
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1643,6 +1658,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 14:46:12.000000000 +0000
+++ source/drivers/char/drm/radeon.h	2004-03-16 09:37:55.648080376 +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 14:46:12.000000000 +0000
+++ source/drivers/char/drm/radeon_cp.c	2004-03-16 09:37:55.649080224 +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 14:46:12.000000000 +0000
+++ source/drivers/char/drm/radeon_drm.h	2004-03-16 09:37:55.650080072 +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 17:54:27.000000000 +0000
+++ source/drivers/char/drm/radeon_drv.c	2004-03-16 09:37:55.651079920 +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 14:46:12.000000000 +0000
+++ source/drivers/char/drm/radeon_drv.h	2004-03-16 09:37:55.652079768 +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 10:50:14.000000000 +0000
+++ source/drivers/char/drm/radeon_irq.c	2004-03-16 09:37:55.652079768 +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-16 09:37:55.656079160 +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 14:46:12.000000000 +0000
+++ source/drivers/char/drm/sis.h	2004-03-16 09:37:55.656079160 +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 14:46:12.000000000 +0000
+++ source/drivers/char/drm/sis_mm.c	2004-03-16 09:37:55.659078704 +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 03:28:22.000000000 +0000
+++ source/drivers/char/drm/tdfx.h	2004-03-16 09:37:55.659078704 +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 03:28:22.000000000 +0000
+++ source/drivers/char/drm/tdfx_drv.c	2004-03-16 09:37:55.660078552 +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-11 10:20:23.000000000 +0000
+++ source/drivers/char/genrtc.c	2004-03-16 09:37:55.661078400 +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/hvc_console.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/hvc_console.c	2004-03-16 09:37:55.661078400 +0000
@@ -131,31 +131,65 @@ static int hvc_write(struct tty_struct *
 		     const unsigned char *buf, int count)
 {
 	struct hvc_struct *hp = tty->driver_data;
-	char *p;
-	int todo, written = 0;
+	char *tbuf, *p;
+	int tbsize, rsize, written = 0;
 	unsigned long flags;
 
-	spin_lock_irqsave(&hp->lock, flags);
-	while (count > 0 && (todo = N_OUTBUF - hp->n_outbuf) > 0) {
-		if (todo > count)
-			todo = count;
-		p = hp->outbuf + hp->n_outbuf;
-		if (from_user) {
-			todo -= copy_from_user(p, buf, todo);
-			if (todo == 0) {
+	if (from_user) {
+		tbsize = min(count, (int)PAGE_SIZE);
+		if (!(tbuf = kmalloc(tbsize, GFP_KERNEL)))
+			return -ENOMEM;
+
+		while ((rsize = count - written) > 0) {
+			int wsize;
+			if (rsize > tbsize)
+				rsize = tbsize;
+
+			p = tbuf;
+			rsize -= copy_from_user(p, buf, rsize);
+			if (!rsize) {
 				if (written == 0)
 					written = -EFAULT;
 				break;
 			}
-		} else
-			memcpy(p, buf, todo);
-		count -= todo;
-		buf += todo;
-		hp->n_outbuf += todo;
-		written += todo;
-		hvc_push(hp);
+			buf += rsize;
+			written += rsize;
+
+			spin_lock_irqsave(&hp->lock, flags);
+			for (wsize = N_OUTBUF - hp->n_outbuf; rsize && wsize;
+					wsize = N_OUTBUF - hp->n_outbuf) {
+				if (wsize > rsize)
+					wsize = rsize;
+				memcpy(hp->outbuf + hp->n_outbuf, p, wsize);
+				hp->n_outbuf += wsize;
+				hvc_push(hp);
+				rsize -= wsize;
+				p += wsize;
+			}
+			spin_unlock_irqrestore(&hp->lock, flags);
+
+			if (rsize)
+				break;
+
+			if (count < tbsize)
+				tbsize = count;
+		}
+
+		kfree(tbuf);
+	} else {
+		spin_lock_irqsave(&hp->lock, flags);
+		while (count > 0 && (rsize = N_OUTBUF - hp->n_outbuf) > 0) {
+			if (rsize > count)
+				rsize = count;
+			memcpy(hp->outbuf + hp->n_outbuf, buf, rsize);
+			count -= rsize;
+			buf += rsize;
+			hp->n_outbuf += rsize;
+			written += rsize;
+			hvc_push(hp);
+		}
+		spin_unlock_irqrestore(&hp->lock, flags);
 	}
-	spin_unlock_irqrestore(&hp->lock, flags);
 
 	return written;
 }
--- diff/drivers/char/ipmi/Kconfig	2003-10-27 09:20:37.000000000 +0000
+++ source/drivers/char/ipmi/Kconfig	2004-03-16 09:37:55.662078248 +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-16 09:37:55.662078248 +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 11:28:05.000000000 +0000
+++ source/drivers/char/ipmi/ipmi_devintf.c	2004-03-16 09:37:55.663078096 +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-11 10:20:23.000000000 +0000
+++ source/drivers/char/ipmi/ipmi_kcs_sm.c	2004-03-16 09:37:55.665077792 +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-16 09:37:55.671076880 +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 11:28:05.000000000 +0000
+++ source/drivers/char/ipmi/ipmi_watchdog.c	2004-03-16 09:37:55.672076728 +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-16 09:37:55.673076576 +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/lp.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/lp.c	2004-03-16 09:37:55.674076424 +0000
@@ -869,7 +869,7 @@ static struct parport_driver lp_driver =
 
 int __init lp_init (void)
 {
-	int i;
+	int i, err = 0;
 
 	if (parport_nr[0] == LP_PARPORT_OFF)
 		return 0;
@@ -900,10 +900,15 @@ int __init lp_init (void)
 
 	devfs_mk_dir("printers");
 	lp_class = class_simple_create(THIS_MODULE, "printer");
+	if (IS_ERR(lp_class)) {
+		err = PTR_ERR(lp_class);
+		goto out_devfs;
+	}
 
 	if (parport_register_driver (&lp_driver)) {
 		printk (KERN_ERR "lp: unable to register with parport\n");
-		return -EIO;
+		err = -EIO;
+		goto out_class;
 	}
 
 	if (!lp_count) {
@@ -915,6 +920,13 @@ int __init lp_init (void)
 	}
 
 	return 0;
+
+out_class:
+	class_simple_destroy(lp_class);
+out_devfs:
+	devfs_remove("printers");
+	unregister_chrdev(LP_MAJOR, "lp");
+	return err;
 }
 
 static int __init lp_init_module (void)
--- diff/drivers/char/mem.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/mem.c	2004-03-16 09:37:55.675076272 +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)
@@ -102,10 +105,11 @@ static inline int valid_phys_addr_range(
 }
 #endif
 
-static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
+static ssize_t do_write_mem(void *p, unsigned long realp,
 			    const char * buf, size_t count, loff_t *ppos)
 {
 	ssize_t written;
+	unsigned long copied;
 
 	written = 0;
 #if defined(__sparc__) || (defined(__mc68000__) && defined(CONFIG_MMU))
@@ -120,8 +124,14 @@ static ssize_t do_write_mem(struct file 
 		written+=sz;
 	}
 #endif
-	if (copy_from_user(p, buf, count))
+	copied = copy_from_user(p, buf, count);
+	if (copied) {
+		ssize_t ret = written + (count - copied);
+
+		if (ret)
+			return ret;
 		return -EFAULT;
+	}
 	written += count;
 	*ppos += written;
 	return written;
@@ -171,31 +181,27 @@ static ssize_t write_mem(struct file * f
 
 	if (!valid_phys_addr_range(p, &count))
 		return -EFAULT;
-	return do_write_mem(file, __va(p), p, buf, count, ppos);
+	return do_write_mem(__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;
 }
@@ -275,15 +281,19 @@ static ssize_t write_kmem(struct file * 
 	unsigned long p = *ppos;
 	ssize_t wrote = 0;
 	ssize_t virtr = 0;
+	ssize_t written;
 	char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */
 
 	if (p < (unsigned long) high_memory) {
+
 		wrote = count;
 		if (count > (unsigned long) high_memory - p)
 			wrote = (unsigned long) high_memory - p;
 
-		wrote = do_write_mem(file, (void*)p, p, buf, wrote, ppos);
-
+		written = do_write_mem((void*)p, p, buf, wrote, ppos);
+		if (written != wrote)
+			return written;
+		wrote = written;
 		p += wrote;
 		buf += wrote;
 		count -= wrote;
@@ -292,15 +302,21 @@ static ssize_t write_kmem(struct file * 
 	if (count > 0) {
 		kbuf = (char *)__get_free_page(GFP_KERNEL);
 		if (!kbuf)
-			return -ENOMEM;
+			return wrote ? wrote : -ENOMEM;
 		while (count > 0) {
 			int len = count;
 
 			if (len > PAGE_SIZE)
 				len = PAGE_SIZE;
-			if (len && copy_from_user(kbuf, buf, len)) {
-				free_page((unsigned long)kbuf);
-				return -EFAULT;
+			if (len) {
+				written = copy_from_user(kbuf, buf, len);
+				if (written != len) {
+					ssize_t ret;
+
+					free_page((unsigned long)kbuf);
+					ret = wrote + virtr + (len - written);
+					return ret ? ret : -EFAULT;
+				}
 			}
 			len = vwrite(kbuf, (char *)p, len);
 			count -= len;
--- diff/drivers/char/misc.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/misc.c	2004-03-16 09:37:55.676076120 +0000
@@ -342,6 +342,7 @@ static int __init misc_init(void)
 	if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
 		printk("unable to get major %d for misc devices\n",
 		       MISC_MAJOR);
+		class_simple_destroy(misc_class);
 		return -EIO;
 	}
 	return 0;
--- diff/drivers/char/n_tty.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/n_tty.c	2004-03-16 09:37:55.677075968 +0000
@@ -999,7 +999,8 @@ do_it_again:
 	/* NOTE: not yet done after every sleep pending a thorough
 	   check of the logic of this change. -- jlc */
 	/* don't stop on /dev/console */
-	if (file->f_op->write != redirected_tty_write && current->tty == tty) {
+	if (file->f_op->write != redirected_tty_write &&
+	    current->signal->tty == tty) {
 		if (tty->pgrp <= 0)
 			printk("read_chan: tty->pgrp <= 0!\n");
 		else if (process_group(current) != tty->pgrp) {
--- diff/drivers/char/pcmcia/synclink_cs.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/pcmcia/synclink_cs.c	2004-03-16 09:37:55.680075512 +0000
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/char/pcmcia/synclink_cs.c
  *
- * $Id: synclink_cs.c,v 4.15 2003/09/05 15:26:02 paulkf Exp $
+ * $Id: synclink_cs.c,v 4.21 2004/03/08 15:29:23 paulkf Exp $
  *
  * Device driver for Microgate SyncLink PC Card
  * multiprotocol serial adapter.
@@ -489,7 +489,7 @@ MODULE_PARM(dosyncppp,"1-" __MODULE_STRI
 MODULE_LICENSE("GPL");
 
 static char *driver_name = "SyncLink PC Card driver";
-static char *driver_version = "$Revision: 4.15 $";
+static char *driver_version = "$Revision: 4.21 $";
 
 static struct tty_driver *serial_driver;
 
@@ -4233,12 +4233,13 @@ void mgslpc_sppp_init(MGSLPC_INFO *info)
 	info->if_ptr = &info->pppdev;
 	info->netdev = info->pppdev.dev = d;
 
-	sppp_attach(&info->pppdev);
-
 	d->base_addr = info->io_base;
 	d->irq = info->irq_level;
 	d->priv = info;
 
+	sppp_attach(&info->pppdev);
+	mgslpc_setup(d);
+
 	if (register_netdev(d)) {
 		printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
 		sppp_detach(info->netdev);
@@ -4413,7 +4414,7 @@ struct net_device_stats *mgslpc_net_stat
 
 int mgslpc_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	MGSLPC_INFO *info = (MGSLPC_INFO *)dev->priv;
+	MGSLPC_INFO *info = dev->priv;
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__,__LINE__,
 			info->netname, cmd );
--- diff/drivers/char/rocket.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/rocket.c	2004-03-16 09:37:55.682075208 +0000
@@ -953,7 +953,7 @@ static int rp_open(struct tty_struct *tt
 	/*
 	 * Info->count is now 1; so it's safe to sleep now.
 	 */
-	info->session = current->session;
+	info->session = current->signal->session;
 	info->pgrp = process_group(current);
 
 	if ((info->flags & ROCKET_INITIALIZED) == 0) {
--- diff/drivers/char/sn_serial.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/sn_serial.c	2004-03-16 09:37:55.683075056 +0000
@@ -82,7 +82,6 @@ static DECLARE_TASKLET(sn_sal_tasklet, s
 static unsigned long sn_interrupt_timeout;
 
 extern u64 master_node_bedrock_address;
-
 static int sn_debug_printf(const char *fmt, ...);
 
 #undef DEBUG
@@ -105,7 +104,6 @@ struct sn_sal_ops {
 static struct sn_sal_ops *sn_func;
 
 /* Prototypes */
-static void __init sn_sal_serial_console_init(void);
 static int snt_hw_puts(const char *, int);
 static int snt_poll_getc(void);
 static int snt_poll_input_pending(void);
@@ -921,9 +919,6 @@ sn_sal_module_init(void)
 		printk(KERN_ERR "sn_serial: Unable to register tty driver\n");
 		return retval;
 	}
-#ifdef CONFIG_SGI_L1_SERIAL_CONSOLE
-	sn_sal_serial_console_init();
-#endif	/* CONFIG_SGI_L1_SERIAL_CONSOLE */
 	return 0;
 }
 
@@ -952,6 +947,7 @@ static void
 sn_sal_console_write(struct console *co, const char *s, unsigned count)
 {
 	unsigned long flags;
+	const char *s1;
 
 	BUG_ON(!sn_sal_is_asynch);
 
@@ -959,15 +955,36 @@ sn_sal_console_write(struct console *co,
 	 * oops, kdb, panic, etc.  make sure they get it. */
 	if (spin_is_locked(&sn_sal_lock)) {
 		synch_flush_xmit();
+		/* Output '\r' before each '\n' */
+		while ((s1 = memchr(s, '\n', count)) != NULL) {
+			sn_func->sal_puts(s, s1 - s);
+			sn_func->sal_puts("\r\n", 2);
+			count -= s1 + 1 - s;
+			s = s1 + 1;
+		}
 		sn_func->sal_puts(s, count);
 	}
 	else if (in_interrupt()) {
 		spin_lock_irqsave(&sn_sal_lock, flags);
 		synch_flush_xmit();
 		spin_unlock_irqrestore(&sn_sal_lock, flags);
+		/* Output '\r' before each '\n' */
+		while ((s1 = memchr(s, '\n', count)) != NULL) {
+			sn_func->sal_puts(s, s1 - s);
+			sn_func->sal_puts("\r\n", 2);
+			count -= s1 + 1 - s;
+			s = s1 + 1;
+		}
 		sn_func->sal_puts(s, count);
 	}
 	else
+		/* Output '\r' before each '\n' */
+		while ((s1 = memchr(s, '\n', count)) != NULL) {
+			sn_sal_write(NULL, 0, s, s1 - s);
+			sn_sal_write(NULL, 0, "\r\n", 2);
+			count -= s1 + 1 - s;
+			s = s1 + 1;
+		}
 		sn_sal_write(NULL, 0, s, count);
 }
 
@@ -993,7 +1010,7 @@ static struct console sal_console = {
 	.index = -1
 };
 
-static void __init
+static int __init
 sn_sal_serial_console_init(void)
 {
 	if (ia64_platform_is("sn2")) {
@@ -1001,6 +1018,8 @@ sn_sal_serial_console_init(void)
 		sn_debug_printf("sn_sal_serial_console_init : register console\n");
 		register_console(&sal_console);
 	}
+	return 0;
 }
+console_initcall(sn_sal_serial_console_init);
 
 #endif /* CONFIG_SGI_L1_SERIAL_CONSOLE */
--- diff/drivers/char/sx.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/sx.c	2004-03-16 09:37:55.685074752 +0000
@@ -1420,7 +1420,7 @@ static int sx_open  (struct tty_struct *
 
 	line = tty->index;
 	sx_dprintk (SX_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p, np=%d)\n", 
-	            current->pid, line, tty, current->tty, sx_nports);
+	            current->pid, line, tty, current->signal->tty, sx_nports);
 
 	if ((line < 0) || (line >= SX_NPORTS) || (line >= sx_nports))
 		return -ENODEV;
--- diff/drivers/char/synclink.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/synclink.c	2004-03-16 09:37:55.690073992 +0000
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/char/synclink.c
  *
- * $Id: synclink.c,v 4.16 2003/09/05 15:26:02 paulkf Exp $
+ * $Id: synclink.c,v 4.21 2004/03/08 15:29:22 paulkf Exp $
  *
  * Device driver for Microgate SyncLink ISA and PCI
  * high speed multiprotocol serial adapters.
@@ -909,7 +909,7 @@ MODULE_PARM(txdmabufs,"1-" __MODULE_STRI
 MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
 
 static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "$Revision: 4.16 $";
+static char *driver_version = "$Revision: 4.21 $";
 
 static int synclink_init_one (struct pci_dev *dev,
 				     const struct pci_device_id *ent);
@@ -7846,13 +7846,14 @@ static void mgsl_sppp_init(struct mgsl_s
 	info->if_ptr = &info->pppdev;
 	info->netdev = info->pppdev.dev = d;
 
-	sppp_attach(&info->pppdev);
-
 	d->base_addr = info->io_base;
 	d->irq = info->irq_level;
 	d->dma = info->dma_level;
 	d->priv = info;
 
+	sppp_attach(&info->pppdev);
+	mgsl_setup(d);
+
 	if (register_netdev(d)) {
 		printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
 		sppp_detach(info->netdev);
@@ -8022,7 +8023,7 @@ struct net_device_stats *mgsl_net_stats(
 
 int mgsl_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	struct mgsl_struct *info = (struct mgsl_struct *)dev->priv;
+	struct mgsl_struct *info = dev->priv;
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):mgsl_ioctl %s cmd=%08X\n", __FILE__,__LINE__,
 			info->netname, cmd );
--- diff/drivers/char/synclinkmp.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/synclinkmp.c	2004-03-16 09:37:55.695073232 +0000
@@ -1,5 +1,5 @@
 /*
- * $Id: synclinkmp.c,v 4.14 2003/09/05 15:26:03 paulkf Exp $
+ * $Id: synclinkmp.c,v 4.19 2004/03/08 15:29:23 paulkf Exp $
  *
  * Device driver for Microgate SyncLink Multiport
  * high speed multiprotocol serial adapter.
@@ -494,7 +494,7 @@ MODULE_PARM(maxframe,"1-" __MODULE_STRIN
 MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICES) "i");
 
 static char *driver_name = "SyncLink MultiPort driver";
-static char *driver_version = "$Revision: 4.14 $";
+static char *driver_version = "$Revision: 4.19 $";
 
 static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent);
 static void synclinkmp_remove_one(struct pci_dev *dev);
@@ -1653,11 +1653,12 @@ static void sppp_init(SLMP_INFO *info)
 	info->if_ptr = &info->pppdev;
 	info->netdev = info->pppdev.dev = d;
 
-	sppp_attach(&info->pppdev);
-
 	d->irq = info->irq_level;
 	d->priv = info;
 
+	sppp_attach(&info->pppdev);
+	cb_setup(d);
+
 	if (register_netdev(d)) {
 		printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
 		sppp_detach(info->netdev);
@@ -1828,7 +1829,7 @@ static struct net_device_stats *sppp_cb_
 
 static int sppp_cb_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	SLMP_INFO *info = (SLMP_INFO *)dev->priv;
+	SLMP_INFO *info = dev->priv;
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):ioctl %s cmd=%08X\n", __FILE__,__LINE__,
 			info->netname, cmd );
@@ -2604,7 +2605,7 @@ static void shutdown(SLMP_INFO * info)
 	del_timer(&info->status_timer);
 
 	if (info->tx_buf) {
-		free_page((unsigned long) info->tx_buf);
+		kfree(info->tx_buf);
 		info->tx_buf = 0;
 	}
 
--- diff/drivers/char/sysrq.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/char/sysrq.c	2004-03-16 09:37:55.695073232 +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/tty_io.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/tty_io.c	2004-03-16 09:37:55.699072624 +0000
@@ -316,7 +316,7 @@ struct tty_driver *get_tty_driver(dev_t 
  */
 int tty_check_change(struct tty_struct * tty)
 {
-	if (current->tty != tty)
+	if (current->signal->tty != tty)
 		return 0;
 	if (tty->pgrp <= 0) {
 		printk(KERN_WARNING "tty_check_change: tty->pgrp <= 0!\n");
@@ -481,17 +481,14 @@ void do_tty_hangup(void *data)
 	if (tty->session > 0) {
 		struct list_head *l;
 		for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid) {
-			task_t *task = p;
-			do {
-				if (task->tty == tty)
-					task->tty = NULL;
-				if (task->leader) {
-					send_group_sig_info(SIGHUP, SEND_SIG_PRIV, task);
-					send_group_sig_info(SIGCONT, SEND_SIG_PRIV, task);
-				}
-			} while_each_thread(p, task);
+			if (p->signal->tty == tty)
+				p->signal->tty = NULL;
+			if (!p->signal->leader)
+				continue;
+			send_group_sig_info(SIGHUP, SEND_SIG_PRIV, p);
+			send_group_sig_info(SIGCONT, SEND_SIG_PRIV, p);
 			if (tty->pgrp > 0)
-				p->tty_old_pgrp = tty->pgrp;
+				p->signal->tty_old_pgrp = tty->pgrp;
 		}
 	}
 	read_unlock(&tasklist_lock);
@@ -570,15 +567,15 @@ void disassociate_ctty(int on_exit)
 
 	lock_kernel();
 
-	tty = current->tty;
+	tty = current->signal->tty;
 	if (tty) {
 		tty_pgrp = tty->pgrp;
 		if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
 			tty_vhangup(tty);
 	} else {
-		if (current->tty_old_pgrp) {
-			kill_pg(current->tty_old_pgrp, SIGHUP, on_exit);
-			kill_pg(current->tty_old_pgrp, SIGCONT, on_exit);
+		if (current->signal->tty_old_pgrp) {
+			kill_pg(current->signal->tty_old_pgrp, SIGHUP, on_exit);
+			kill_pg(current->signal->tty_old_pgrp, SIGCONT, on_exit);
 		}
 		unlock_kernel();	
 		return;
@@ -589,17 +586,13 @@ void disassociate_ctty(int on_exit)
 			kill_pg(tty_pgrp, SIGCONT, on_exit);
 	}
 
-	current->tty_old_pgrp = 0;
+	current->signal->tty_old_pgrp = 0;
 	tty->session = 0;
 	tty->pgrp = -1;
 
 	read_lock(&tasklist_lock);
-	for_each_task_pid(current->session, PIDTYPE_SID, p, l, pid) {
-		task_t *task = p;
-		do {
-			task->tty = NULL;
-		} while_each_thread(p, task);
-	}
+	for_each_task_pid(current->signal->session, PIDTYPE_SID, p, l, pid)
+		p->signal->tty = NULL;
 	read_unlock(&tasklist_lock);
 	unlock_kernel();
 }
@@ -1267,20 +1260,11 @@ static void release_dev(struct file * fi
 		struct pid *pid;
 
 		read_lock(&tasklist_lock);
-		for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid) {
-			task_t *task = p;
-			do {
-				task->tty = NULL;
-			} while_each_thread(p, task);
-		}
-		if (o_tty) {
-			for_each_task_pid(o_tty->session, PIDTYPE_SID, p,l, pid) {
-				task_t *task = p;
-				do {
-					task->tty = NULL;
-				} while_each_thread(p, task);
-			}
-		}
+		for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid)
+			p->signal->tty = NULL;
+		if (o_tty)
+			for_each_task_pid(o_tty->session, PIDTYPE_SID, p,l, pid)
+				p->signal->tty = NULL;
 		read_unlock(&tasklist_lock);
 	}
 
@@ -1351,10 +1335,10 @@ static int tty_open(struct inode * inode
 retry_open:
 	noctty = filp->f_flags & O_NOCTTY;
 	if (device == MKDEV(TTYAUX_MAJOR,0)) {
-		if (!current->tty)
+		if (!current->signal->tty)
 			return -ENXIO;
-		driver = current->tty->driver;
-		index = current->tty->index;
+		driver = current->signal->tty->driver;
+		index = current->signal->tty->index;
 		filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
 		/* noctty = 1; */
 		goto got_driver;
@@ -1455,14 +1439,14 @@ got_driver:
 		goto retry_open;
 	}
 	if (!noctty &&
-	    current->leader &&
-	    !current->tty &&
+	    current->signal->leader &&
+	    !current->signal->tty &&
 	    tty->session == 0) {
 	    	task_lock(current);
-		current->tty = tty;
+		current->signal->tty = tty;
 		task_unlock(current);
-		current->tty_old_pgrp = 0;
-		tty->session = current->session;
+		current->signal->tty_old_pgrp = 0;
+		tty->session = current->signal->session;
 		tty->pgrp = process_group(current);
 	}
 	return 0;
@@ -1520,7 +1504,7 @@ static int tiocsti(struct tty_struct *tt
 {
 	char ch, mbz = 0;
 
-	if ((current->tty != tty) && !capable(CAP_SYS_ADMIN))
+	if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 	if (get_user(ch, arg))
 		return -EFAULT;
@@ -1611,14 +1595,14 @@ static int tiocsctty(struct tty_struct *
 	struct pid *pid;
 	task_t *p;
 
-	if (current->leader &&
-	    (current->session == tty->session))
+	if (current->signal->leader &&
+	    (current->signal->session == tty->session))
 		return 0;
 	/*
 	 * The process must be a session leader and
 	 * not have a controlling tty already.
 	 */
-	if (!current->leader || current->tty)
+	if (!current->signal->leader || current->signal->tty)
 		return -EPERM;
 	if (tty->session > 0) {
 		/*
@@ -1631,21 +1615,17 @@ static int tiocsctty(struct tty_struct *
 			 */
 
 			read_lock(&tasklist_lock);
-			for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid) {
-				task_t *task = p;
-				do {
-					task->tty = NULL;
-				} while_each_thread(p, task);
-			}
+			for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid)
+				p->signal->tty = NULL;
 			read_unlock(&tasklist_lock);
 		} else
 			return -EPERM;
 	}
 	task_lock(current);
-	current->tty = tty;
+	current->signal->tty = tty;
 	task_unlock(current);
-	current->tty_old_pgrp = 0;
-	tty->session = current->session;
+	current->signal->tty_old_pgrp = 0;
+	tty->session = current->signal->session;
 	tty->pgrp = process_group(current);
 	return 0;
 }
@@ -1656,7 +1636,7 @@ static int tiocgpgrp(struct tty_struct *
 	 * (tty == real_tty) is a cheap way of
 	 * testing if the tty is NOT a master pty.
 	 */
-	if (tty == real_tty && current->tty != real_tty)
+	if (tty == real_tty && current->signal->tty != real_tty)
 		return -ENOTTY;
 	return put_user(real_tty->pgrp, arg);
 }
@@ -1670,15 +1650,15 @@ static int tiocspgrp(struct tty_struct *
 		return -ENOTTY;
 	if (retval)
 		return retval;
-	if (!current->tty ||
-	    (current->tty != real_tty) ||
-	    (real_tty->session != current->session))
+	if (!current->signal->tty ||
+	    (current->signal->tty != real_tty) ||
+	    (real_tty->session != current->signal->session))
 		return -ENOTTY;
 	if (get_user(pgrp, (pid_t *) arg))
 		return -EFAULT;
 	if (pgrp < 0)
 		return -EINVAL;
-	if (session_of_pgrp(pgrp) != current->session)
+	if (session_of_pgrp(pgrp) != current->signal->session)
 		return -EPERM;
 	real_tty->pgrp = pgrp;
 	return 0;
@@ -1690,7 +1670,7 @@ static int tiocgsid(struct tty_struct *t
 	 * (tty == real_tty) is a cheap way of
 	 * testing if the tty is NOT a master pty.
 	*/
-	if (tty == real_tty && current->tty != real_tty)
+	if (tty == real_tty && current->signal->tty != real_tty)
 		return -ENOTTY;
 	if (real_tty->session <= 0)
 		return -ENOTTY;
@@ -1848,12 +1828,12 @@ int tty_ioctl(struct inode * inode, stru
 			clear_bit(TTY_EXCLUSIVE, &tty->flags);
 			return 0;
 		case TIOCNOTTY:
-			if (current->tty != tty)
+			if (current->signal->tty != tty)
 				return -ENOTTY;
-			if (current->leader)
+			if (current->signal->leader)
 				disassociate_ctty(0);
 			task_lock(current);
-			current->tty = NULL;
+			current->signal->tty = NULL;
 			task_unlock(current);
 			return 0;
 		case TIOCSCTTY:
@@ -1957,9 +1937,9 @@ static void __do_SAK(void *arg)
 		tty->driver->flush_buffer(tty);
 	read_lock(&tasklist_lock);
 	for_each_task_pid(session, PIDTYPE_SID, p, l, pid) {
-		if (p->tty == tty || session > 0) {
+		if (p->signal->tty == tty || session > 0) {
 			printk(KERN_NOTICE "SAK: killed process %d"
-			    " (%s): p->session==tty->session\n",
+			    " (%s): p->signal->session==tty->session\n",
 			    p->pid, p->comm);
 			send_sig(SIGKILL, p, 1);
 			continue;
@@ -2195,8 +2175,6 @@ void tty_unregister_device(struct tty_dr
 EXPORT_SYMBOL(tty_register_device);
 EXPORT_SYMBOL(tty_unregister_device);
 
-static struct kobject tty_kobj = {.name = "tty"};
-
 struct tty_driver *alloc_tty_driver(int lines)
 {
 	struct tty_driver *driver;
@@ -2256,7 +2234,6 @@ int tty_register_driver(struct tty_drive
 	int error;
         int i;
 	dev_t dev;
-	char *s;
 	void **p = NULL;
 
 	if (driver->flags & TTY_DRIVER_INSTALLED)
@@ -2296,15 +2273,11 @@ int tty_register_driver(struct tty_drive
 		driver->termios_locked = NULL;
 	}
 
-	driver->cdev.kobj.parent = &tty_kobj;
-	strcpy(driver->cdev.kobj.name, driver->name);
-	for (s = strchr(driver->cdev.kobj.name, '/'); s; s = strchr(s, '/'))
-		*s = '!';
 	cdev_init(&driver->cdev, &tty_fops);
 	driver->cdev.owner = driver->owner;
 	error = cdev_add(&driver->cdev, dev, driver->num);
 	if (error) {
-		kobject_del(&driver->cdev.kobj);
+		cdev_del(&driver->cdev);
 		unregister_chrdev_region(dev, driver->num);
 		driver->ttys = NULL;
 		driver->termios = driver->termios_locked = NULL;
@@ -2420,7 +2393,9 @@ static int __init tty_class_init(void)
 }
 
 postcore_initcall(tty_class_init);
- 
+
+/* 3/2004 jmc: why do these devices exist? */
+
 static struct cdev tty_cdev, console_cdev;
 #ifdef CONFIG_UNIX98_PTYS
 static struct cdev ptmx_cdev;
@@ -2435,7 +2410,6 @@ static struct cdev vc0_cdev;
  */
 static int __init tty_init(void)
 {
-	strcpy(tty_cdev.kobj.name, "dev.tty");
 	cdev_init(&tty_cdev, &tty_fops);
 	if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
 	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
@@ -2443,7 +2417,6 @@ static int __init tty_init(void)
 	devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty");
 	class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty");
 
-	strcpy(console_cdev.kobj.name, "dev.console");
 	cdev_init(&console_cdev, &console_fops);
 	if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
 	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
@@ -2451,11 +2424,7 @@ static int __init tty_init(void)
 	devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console");
 	class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 1), NULL, "console");
 
-	tty_kobj.kset = tty_cdev.kobj.kset;
-	kobject_register(&tty_kobj);
-
 #ifdef CONFIG_UNIX98_PTYS
-	strcpy(ptmx_cdev.kobj.name, "dev.ptmx");
 	cdev_init(&ptmx_cdev, &tty_fops);
 	if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
 	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
@@ -2465,7 +2434,6 @@ static int __init tty_init(void)
 #endif
 
 #ifdef CONFIG_VT
-	strcpy(vc0_cdev.kobj.name, "dev.vc0");
 	cdev_init(&vc0_cdev, &console_fops);
 	if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
 	    register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
--- diff/drivers/char/viocons.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/viocons.c	2004-03-16 09:37:55.700072472 +0000
@@ -1365,6 +1365,7 @@ static int __init viocons_init2(void)
 	viotty_driver->driver_name = "vioconsole";
 	viotty_driver->devfs_name = "vcs/";
 	viotty_driver->name = "tty";
+	viotty_driver->name_base = 1;
 	viotty_driver->major = TTY_MAJOR;
 	viotty_driver->minor_start = 1;
 	viotty_driver->type = TTY_DRIVER_TYPE_CONSOLE;
--- diff/drivers/char/vt.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/vt.c	2004-03-16 09:37:55.702072168 +0000
@@ -2277,7 +2277,7 @@ int tioclinux(struct tty_struct *tty, un
 
 	if (tty->driver->type != TTY_DRIVER_TYPE_CONSOLE)
 		return -EINVAL;
-	if (current->tty != tty && !capable(CAP_SYS_ADMIN))
+	if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 	if (get_user(type, (char *)arg))
 		return -EFAULT;
--- diff/drivers/char/vt_ioctl.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/vt_ioctl.c	2004-03-16 09:37:55.702072168 +0000
@@ -382,7 +382,7 @@ int vt_ioctl(struct tty_struct *tty, str
 	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
 	 */
 	perm = 0;
-	if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG))
+	if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
 		perm = 1;
  
 	kbd = kbd_table + console;
@@ -1221,4 +1221,3 @@ void change_console(unsigned int new_con
 
 	complete_change_console(new_console);
 }
-
--- diff/drivers/char/watchdog/advantechwdt.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/watchdog/advantechwdt.c	2004-03-16 09:37:55.703072016 +0000
@@ -256,8 +256,6 @@ static struct miscdevice advwdt_miscdev 
 
 static struct notifier_block advwdt_notifier = {
 	.notifier_call = advwdt_notify_sys,
-	.next = NULL,
-	.priority = 0,
 };
 
 static int __init
--- diff/drivers/char/watchdog/alim1535_wdt.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/watchdog/alim1535_wdt.c	2004-03-16 09:37:55.703072016 +0000
@@ -385,8 +385,6 @@ static struct miscdevice ali_miscdev = {
 
 static struct notifier_block ali_notifier = {
 	.notifier_call =	ali_notify_sys,
-	.next =			NULL,
-	.priority =		0,
 };
 
 /*
--- diff/drivers/char/watchdog/alim7101_wdt.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/watchdog/alim7101_wdt.c	2004-03-16 09:37:55.704071864 +0000
@@ -303,8 +303,6 @@ static int wdt_notify_sys(struct notifie
 static struct notifier_block wdt_notifier=
 {
 	.notifier_call = wdt_notify_sys,
-	.next = 0,
-	.priority = 0,
 };
 
 static void __exit alim7101_wdt_unload(void)
--- diff/drivers/char/watchdog/amd7xx_tco.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/watchdog/amd7xx_tco.c	2004-03-16 09:37:55.704071864 +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-11 10:20:23.000000000 +0000
+++ source/drivers/char/watchdog/cpu5wdt.c	2004-03-16 09:37:55.705071712 +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-11 10:20:23.000000000 +0000
+++ source/drivers/char/watchdog/eurotechwdt.c	2004-03-16 09:37:55.705071712 +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/ib700wdt.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/watchdog/ib700wdt.c	2004-03-16 09:37:55.706071560 +0000
@@ -284,8 +284,6 @@ static struct miscdevice ibwdt_miscdev =
 
 static struct notifier_block ibwdt_notifier = {
 	.notifier_call = ibwdt_notify_sys,
-	.next = NULL,
-	.priority = 0,
 };
 
 static int __init ibwdt_init(void)
--- diff/drivers/char/watchdog/machzwd.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/watchdog/machzwd.c	2004-03-16 09:37:55.706071560 +0000
@@ -447,8 +447,6 @@ static struct miscdevice zf_miscdev = {
  */
 static struct notifier_block zf_notifier = {
 	.notifier_call = zf_notify_sys,
-	.next = NULL,
-	.priority = 0,
 };
 
 static void __init zf_show_action(int act)
--- diff/drivers/char/watchdog/pcwd_pci.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/watchdog/pcwd_pci.c	2004-03-16 09:37:55.707071408 +0000
@@ -49,7 +49,7 @@
 
 /* Module and version information */
 #define WATCHDOG_VERSION "1.00"
-#define WATCHDOG_DATE "09/02/2004"
+#define WATCHDOG_DATE "13/03/2004"
 #define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"
 #define WATCHDOG_NAME "pcwd_pci"
 #define PFX WATCHDOG_NAME ": "
@@ -82,6 +82,9 @@
 #define CMD_READ_WATCHDOG_TIMEOUT	0x18
 #define CMD_WRITE_WATCHDOG_TIMEOUT	0x19
 
+/* We can only use 1 card due to the /dev/watchdog restriction */
+static int cards_found;
+
 /* internal variables */
 static int temp_panic;
 static unsigned long is_active;
@@ -505,7 +508,6 @@ static inline void check_temperature_sup
 static int __devinit pcipcwd_card_init(struct pci_dev *pdev,
 		const struct pci_device_id *ent)
 {
-	static int cards_found;
 	int ret = -EIO;
 	int got_fw_rev, fw_rev_major, fw_rev_minor;
 	char fw_ver_str[20];
@@ -527,7 +529,8 @@ static int __devinit pcipcwd_card_init(s
 
 	if (pci_resource_start(pdev, 0) == 0x0000) {
 		printk(KERN_ERR PFX "No I/O-Address for card detected\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto err_out_disable_device;
 	}
 
 	pcipcwd_private.pdev = pdev;
@@ -643,6 +646,7 @@ static void __devexit pcipcwd_card_exit(
 	unregister_reboot_notifier(&pcipcwd_notifier);
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
+	cards_found--;
 }
 
 static struct pci_device_id pcipcwd_pci_tbl[] = {
--- diff/drivers/char/watchdog/pcwd_usb.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/watchdog/pcwd_usb.c	2004-03-16 09:37:55.708071256 +0000
@@ -589,7 +589,7 @@ static int usb_pcwd_probe(struct usb_int
 	}
 
 	/* get the active interface descriptor */
-	iface_desc = &interface->altsetting[interface->act_altsetting];
+	iface_desc = interface->cur_altsetting;
 
 	/* check out that we have a HID device */
 	if (!(iface_desc->desc.bInterfaceClass == USB_CLASS_HID)) {
--- diff/drivers/char/watchdog/sbc60xxwdt.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/watchdog/sbc60xxwdt.c	2004-03-16 09:37:55.708071256 +0000
@@ -322,8 +322,6 @@ static int wdt_notify_sys(struct notifie
 static struct notifier_block wdt_notifier=
 {
 	.notifier_call = wdt_notify_sys,
-	.next = NULL,
-	.priority = 0,
 };
 
 static void __exit sbc60xxwdt_unload(void)
--- diff/drivers/char/watchdog/sc1200wdt.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/watchdog/sc1200wdt.c	2004-03-16 09:37:55.709071104 +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/sc520_wdt.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/watchdog/sc520_wdt.c	2004-03-16 09:37:55.709071104 +0000
@@ -354,8 +354,6 @@ static int wdt_notify_sys(struct notifie
 static struct notifier_block wdt_notifier=
 {
 	.notifier_call = wdt_notify_sys,
-	.next = NULL,
-	.priority = 0,
 };
 
 static void __exit sc520_wdt_unload(void)
--- diff/drivers/char/watchdog/w83627hf_wdt.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/watchdog/w83627hf_wdt.c	2004-03-16 09:37:55.709071104 +0000
@@ -257,8 +257,6 @@ static struct miscdevice wdt_miscdev = {
 
 static struct notifier_block wdt_notifier = {
 	.notifier_call = wdt_notify_sys,
-	.next = NULL,
-	.priority = 0,
 };
 
 static int __init
--- diff/drivers/char/watchdog/w83877f_wdt.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/watchdog/w83877f_wdt.c	2004-03-16 09:37:55.710070952 +0000
@@ -341,8 +341,6 @@ static int wdt_notify_sys(struct notifie
 static struct notifier_block wdt_notifier=
 {
 	.notifier_call = wdt_notify_sys,
-	.next = NULL,
-	.priority = 0,
 };
 
 static void __exit w83877f_wdt_unload(void)
--- diff/drivers/char/watchdog/wafer5823wdt.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/watchdog/wafer5823wdt.c	2004-03-16 09:37:55.711070800 +0000
@@ -252,8 +252,6 @@ static struct miscdevice wafwdt_miscdev 
 
 static struct notifier_block wafwdt_notifier = {
 	.notifier_call = wafwdt_notify_sys,
-	.next = NULL,
-	.priority = 0,
 };
 
 static int __init wafwdt_init(void)
--- diff/drivers/char/watchdog/wdt.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/char/watchdog/wdt.c	2004-03-16 09:37:55.711070800 +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)");
 
 /*
@@ -489,8 +459,6 @@ static struct miscdevice temp_miscdev=
 static struct notifier_block wdt_notifier=
 {
 	.notifier_call = wdt_notify_sys,
-	.next = NULL,
-	.priority = 0,
 };
 
 /**
--- diff/drivers/char/watchdog/wdt977.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/char/watchdog/wdt977.c	2004-03-16 09:37:55.713070496 +0000
@@ -1,5 +1,5 @@
 /*
- *	Wdt977	0.02:	A Watchdog Device for Netwinder W83977AF chip
+ *	Wdt977	0.03:	A Watchdog Device for Netwinder W83977AF chip
  *
  *	(c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>)
  *
@@ -29,24 +29,27 @@
 #include <linux/miscdevice.h>
 #include <linux/init.h>
 #include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/mach-types.h>
 #include <asm/uaccess.h>
 
+#define PFX "Wdt977: "
 #define WATCHDOG_MINOR	130
 
-#define	DEFAULT_TIMEOUT	1	/* default timeout = 1 minute */
+#define	DEFAULT_TIMEOUT	60			/* default timeout in seconds */
 
-static	int timeout = DEFAULT_TIMEOUT*60;	/* TO in seconds from user */
-static	int timeoutM = DEFAULT_TIMEOUT;		/* timeout in minutes */
+static	int timeout = DEFAULT_TIMEOUT;
+static	int timeoutM;				/* timeout in minutes */
 static	unsigned long timer_alive;
 static	int testmode;
 static	char expect_close;
 
 module_param(timeout, int, 0);
-MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=60");
+MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")");
 module_param(testmode, int, 0);
 MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0");
 
@@ -59,21 +62,102 @@ static int nowayout = 0;
 module_param(nowayout, int, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
+/*
+ * Start the watchdog
+ */
 
-/* This is kicking the watchdog by simply re-writing the timeout to reg. 0xF2 */
-static int kick_wdog(void)
+static int wdt977_start(void)
 {
-	/*
-	 *	Refresh the timer.
+	/* unlock the SuperIO chip */
+	outb(0x87,0x370);
+	outb(0x87,0x370);
+
+	/* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4
+	 * F2 has the timeout in minutes
+	 * F3 could be set to the POWER LED blink (with GP17 set to PowerLed)
+	 *   at timeout, and to reset timer on kbd/mouse activity (not impl.)
+	 * F4 is used to just clear the TIMEOUT'ed state (bit 0)
 	 */
+	outb(0x07,0x370);
+	outb(0x08,0x371);
+	outb(0xF2,0x370);
+	outb(timeoutM,0x371);
+	outb(0xF3,0x370);
+	outb(0x00,0x371);	/* another setting is 0E for kbd/mouse/LED */
+	outb(0xF4,0x370);
+	outb(0x00,0x371);
+
+	/* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
+	/* in test mode watch the bit 1 on F4 to indicate "triggered" */
+	if (!testmode)
+	{
+		outb(0x07,0x370);
+		outb(0x07,0x371);
+		outb(0xE6,0x370);
+		outb(0x08,0x371);
+	}
 
+	/* lock the SuperIO chip */
+	outb(0xAA,0x370);
+
+	printk(KERN_INFO PFX "activated.\n");
+
+	return 0;
+}
+
+/*
+ * Stop the watchdog
+ */
+
+static int wdt977_stop(void)
+{
+	/* unlock the SuperIO chip */
+	outb(0x87,0x370);
+	outb(0x87,0x370);
+
+	/* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4
+	* F3 is reset to its default state
+	* F4 can clear the TIMEOUT'ed state (bit 0) - back to default
+	* We can not use GP17 as a PowerLed, as we use its usage as a RedLed
+	*/
+	outb(0x07,0x370);
+	outb(0x08,0x371);
+	outb(0xF2,0x370);
+	outb(0xFF,0x371);
+	outb(0xF3,0x370);
+	outb(0x00,0x371);
+	outb(0xF4,0x370);
+	outb(0x00,0x371);
+	outb(0xF2,0x370);
+	outb(0x00,0x371);
+
+	/* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
+	outb(0x07,0x370);
+	outb(0x07,0x371);
+	outb(0xE6,0x370);
+	outb(0x08,0x371);
+
+	/* lock the SuperIO chip */
+	outb(0xAA,0x370);
+
+	printk(KERN_INFO PFX "shutdown.\n");
+
+	return 0;
+}
+
+/*
+ * Send a keepalive ping to the watchdog
+ * This is done by simply re-writing the timeout to reg. 0xF2
+ */
+
+static int wdt977_keepalive(void)
+{
 	/* unlock the SuperIO chip */
 	outb(0x87,0x370);
 	outb(0x87,0x370);
 
 	/* select device Aux2 (device=8) and kicks watchdog reg F2 */
 	/* F2 has the timeout in minutes */
-
 	outb(0x07,0x370);
 	outb(0x08,0x371);
 	outb(0xF2,0x370);
@@ -85,77 +169,77 @@ static int kick_wdog(void)
 	return 0;
 }
 
-
 /*
- *	Allow only one person to hold it open
+ * Set the watchdog timeout value
  */
 
-static int wdt977_open(struct inode *inode, struct file *file)
+static int wdt977_set_timeout(int t)
 {
-
-	if( test_and_set_bit(0,&timer_alive) )
-		return -EBUSY;
+	int tmrval;
 
 	/* convert seconds to minutes, rounding up */
-	timeoutM = timeout + 59;
-	timeoutM /= 60;
-
-	if (nowayout)
-	{
-		__module_get(THIS_MODULE);
+	tmrval = (t + 59) / 60;
 
-		/* do not permit disabling the watchdog by writing 0 to reg. 0xF2 */
-		if (!timeoutM) timeoutM = DEFAULT_TIMEOUT;
-	}
-
-	if (machine_is_netwinder())
-	{
+	if (machine_is_netwinder()) {
 		/* we have a hw bug somewhere, so each 977 minute is actually only 30sec
 		 *  this limits the max timeout to half of device max of 255 minutes...
 		 */
-		timeoutM += timeoutM;
+		tmrval += tmrval;
 	}
 
-	/* max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. */
-	if (timeoutM > 255) timeoutM = 255;
+	if ((tmrval < 1) || (tmrval > 255))
+		return -EINVAL;
 
-	/* convert seconds to minutes */
-	printk(KERN_INFO "Wdt977 Watchdog activated: timeout = %d sec, nowayout = %i, testmode = %i.\n",
-		machine_is_netwinder() ? (timeoutM>>1)*60 : timeoutM*60,
-		nowayout, testmode);
+	/* timeout is the timeout in seconds, timeoutM is the timeout in minutes) */
+	timeout = t;
+	timeoutM = tmrval;
+	return 0;
+}
+
+/*
+ * Get the watchdog status
+ */
+
+static int wdt977_get_status(int *status)
+{
+	int new_status;
+
+	*status=0;
 
 	/* unlock the SuperIO chip */
 	outb(0x87,0x370);
 	outb(0x87,0x370);
 
-	/* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4
-	 * F2 has the timeout in minutes
-	 * F3 could be set to the POWER LED blink (with GP17 set to PowerLed)
-	 *   at timeout, and to reset timer on kbd/mouse activity (not impl.)
-	 * F4 is used to just clear the TIMEOUT'ed state (bit 0)
-	 */
+	/* select device Aux2 (device=8) and read watchdog reg F4 */
 	outb(0x07,0x370);
 	outb(0x08,0x371);
-	outb(0xF2,0x370);
-	outb(timeoutM,0x371);
-	outb(0xF3,0x370);
-	outb(0x00,0x371);	/* another setting is 0E for kbd/mouse/LED */
 	outb(0xF4,0x370);
-	outb(0x00,0x371);
-
-	/* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
-	/* in test mode watch the bit 1 on F4 to indicate "triggered" */
-	if (!testmode)
-	{
-		outb(0x07,0x370);
-		outb(0x07,0x371);
-		outb(0xE6,0x370);
-		outb(0x08,0x371);
-	}
+	new_status = inb(0x371);
 
 	/* lock the SuperIO chip */
 	outb(0xAA,0x370);
 
+	if (new_status & 1)
+		*status |= WDIOF_CARDRESET;
+
+	return 0;
+}
+
+
+/*
+ *	/dev/watchdog handling
+ */
+
+static int wdt977_open(struct inode *inode, struct file *file)
+{
+	/* If the watchdog is alive we don't need to start it again */
+	if( test_and_set_bit(0,&timer_alive) )
+		return -EBUSY;
+
+	if (nowayout)
+		__module_get(THIS_MODULE);
+
+	wdt977_start();
 	return 0;
 }
 
@@ -167,40 +251,11 @@ static int wdt977_release(struct inode *
 	 */
 	if (expect_close == 42)
 	{
-		/* unlock the SuperIO chip */
-		outb(0x87,0x370);
-		outb(0x87,0x370);
-
-		/* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4
-		* F3 is reset to its default state
-		* F4 can clear the TIMEOUT'ed state (bit 0) - back to default
-		* We can not use GP17 as a PowerLed, as we use its usage as a RedLed
-		*/
-		outb(0x07,0x370);
-		outb(0x08,0x371);
-		outb(0xF2,0x370);
-		outb(0xFF,0x371);
-		outb(0xF3,0x370);
-		outb(0x00,0x371);
-		outb(0xF4,0x370);
-		outb(0x00,0x371);
-		outb(0xF2,0x370);
-		outb(0x00,0x371);
-
-		/* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
-		outb(0x07,0x370);
-		outb(0x07,0x371);
-		outb(0xE6,0x370);
-		outb(0x08,0x371);
-
-		/* lock the SuperIO chip */
-		outb(0xAA,0x370);
-
+		wdt977_stop();
 		clear_bit(0,&timer_alive);
-
-		printk(KERN_INFO "Wdt977 Watchdog: shutdown\n");
 	} else {
-		printk(KERN_CRIT "WDT device closed unexpectedly.  WDT will not stop!\n");
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		wdt977_keepalive();
 	}
 	expect_close = 0;
 	return 0;
@@ -240,7 +295,7 @@ static ssize_t wdt977_write(struct file 
 			}
 		}
 
-		kick_wdog();
+		wdt977_keepalive();
 	}
 	return count;
 }
@@ -257,14 +312,19 @@ static ssize_t wdt977_write(struct file 
  */
 
 static struct watchdog_info ident = {
-	.options	= WDIOF_SETTIMEOUT,
-	.identity	= "Winbond 83977",
+	.options =		WDIOF_SETTIMEOUT |
+				WDIOF_MAGICCLOSE |
+				WDIOF_KEEPALIVEPING,
+	.firmware_version =	1,
+	.identity =		"Winbond 83977",
 };
 
 static int wdt977_ioctl(struct inode *inode, struct file *file,
 	unsigned int cmd, unsigned long arg)
 {
-	int temp;
+	int status;
+	int new_options, retval = -EINVAL;
+	int new_timeout;
 
 	switch(cmd)
 	{
@@ -272,62 +332,59 @@ static int wdt977_ioctl(struct inode *in
 		return -ENOIOCTLCMD;
 
 	case WDIOC_GETSUPPORT:
-	    return copy_to_user((struct watchdog_info *)arg, &ident,
+		return copy_to_user((struct watchdog_info *)arg, &ident,
 			sizeof(ident)) ? -EFAULT : 0;
 
+	case WDIOC_GETSTATUS:
+		wdt977_get_status(&status);
+		return put_user(status, (int *) arg);
+
 	case WDIOC_GETBOOTSTATUS:
 		return put_user(0, (int *) arg);
 
-	case WDIOC_GETSTATUS:
-		/* unlock the SuperIO chip */
-		outb(0x87,0x370);
-		outb(0x87,0x370);
+	case WDIOC_KEEPALIVE:
+		wdt977_keepalive();
+		return 0;
 
-		/* select device Aux2 (device=8) and read watchdog reg F4 */
-		outb(0x07,0x370);
-		outb(0x08,0x371);
-		outb(0xF4,0x370);
-		temp = inb(0x371);
+	case WDIOC_SETOPTIONS:
+		if (get_user (new_options, (int *) arg))
+			return -EFAULT;
 
-		/* lock the SuperIO chip */
-		outb(0xAA,0x370);
+		if (new_options & WDIOS_DISABLECARD) {
+			wdt977_stop();
+			retval = 0;
+		}
 
-		/* return info if "expired" in test mode */
-		return put_user(temp & 1, (int *) arg);
+		if (new_options & WDIOS_ENABLECARD) {
+			wdt977_start();
+			retval = 0;
+		}
 
-	case WDIOC_KEEPALIVE:
-		kick_wdog();
-		return 0;
+		return retval;
 
 	case WDIOC_SETTIMEOUT:
-		if (copy_from_user(&temp, (int *) arg, sizeof(int)))
+		if (get_user(new_timeout, (int *) arg))
 			return -EFAULT;
 
-		/* convert seconds to minutes, rounding up */
-		temp += 59;
-		temp /= 60;
-
-		/* we have a hw bug somewhere, so each 977 minute is actually only 30sec
-		*  this limits the max timeout to half of device max of 255 minutes...
-		*/
-		if (machine_is_netwinder())
-		{
-		    temp += temp;
-		}
+		if (wdt977_set_timeout(new_timeout))
+		    return -EINVAL;
 
-		/* Sanity check */
-		if (temp < 0 || temp > 255)
-			return -EINVAL;
+		wdt977_keepalive();
+		/* Fall */
 
-		if (!temp && nowayout)
-			return -EINVAL;
+	case WDIOC_GETTIMEOUT:
+		return put_user(timeout, (int *)arg);
 
-		timeoutM = temp;
-		kick_wdog();
-		return 0;
 	}
 }
 
+static int wdt977_notify_sys(struct notifier_block *this, unsigned long code,
+	void *unused)
+{
+	if(code==SYS_DOWN || code==SYS_HALT)
+		wdt977_stop();
+	return NOTIFY_DONE;
+}
 
 static struct file_operations wdt977_fops=
 {
@@ -345,21 +402,48 @@ static struct miscdevice wdt977_miscdev=
 	.fops		= &wdt977_fops,
 };
 
+static struct notifier_block wdt977_notifier = {
+	.notifier_call = wdt977_notify_sys,
+};
+
 static int __init nwwatchdog_init(void)
 {
 	int retval;
 	if (!machine_is_netwinder())
 		return -ENODEV;
 
+	/* Check that the timeout value is within it's range ; if not reset to the default */
+	if (wdt977_set_timeout(timeout)) {
+		wdt977_set_timeout(DEFAULT_TIMEOUT);
+		printk(KERN_INFO PFX "timeout value must be 60<timeout<15300, using %d\n",
+			DEFAULT_TIMEOUT);
+	}
+
+	retval = register_reboot_notifier(&wdt977_notifier);
+	if (retval) {
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			retval);
+		return retval;
+	}
+
 	retval = misc_register(&wdt977_miscdev);
-	if (!retval)
-		printk(KERN_INFO "Wdt977 Watchdog sleeping.\n");
-	return retval;
+	if (retval) {
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, retval);
+		unregister_reboot_notifier(&wdt977_notifier);
+		return retval;
+	}
+
+	printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode = %i)\n",
+		timeout, nowayout, testmode);
+
+	return 0;
 }
 
 static void __exit nwwatchdog_exit(void)
 {
 	misc_deregister(&wdt977_miscdev);
+	unregister_reboot_notifier(&wdt977_notifier);
 }
 
 module_init(nwwatchdog_init);
--- diff/drivers/eisa/eisa-bus.c	2003-10-09 08:47:34.000000000 +0000
+++ source/drivers/eisa/eisa-bus.c	2004-03-16 09:37:55.713070496 +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/Kconfig	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/i2c/Kconfig	2004-03-16 09:37:55.714070344 +0000
@@ -15,9 +15,6 @@ config I2C
 
 	  Both I2C and SMBus are supported here. You will need this for
 	  hardware sensors support, and also for Video For Linux support.
-	  Specifically, if you want to use a BT848 based frame grabber/overlay
-	  boards under Linux, say Y here and also to "I2C bit-banging
-	  interfaces", below.
 
 	  If you want I2C support, you should say Y here and also to the
 	  specific driver for your bus adapter(s) below.
--- diff/drivers/i2c/busses/Kconfig	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/i2c/busses/Kconfig	2004-03-16 09:37:55.733067456 +0000
@@ -144,6 +144,17 @@ config I2C_ITE
 	  This support is also available as a module.  If so, the module 
 	  will be called i2c-ite.
 
+config I2C_IXP42X
+	tristate "IXP42x GPIO-Based I2C Interface"
+	depends on I2C && ARCH_IXP425
+	select I2C_ALGOBIT
+	help
+	  Say Y here if you have an Intel IXP42x(420,421,422,425) based 
+	  system and are using GPIO lines for an I2C bus.
+
+	  This support is also available as a module. If so, the module
+	  will be called i2c-ixp42x.
+
 config I2C_KEYWEST
 	tristate "Powermac Keywest I2C interface"
 	depends on I2C && PPC_PMAC
--- diff/drivers/i2c/busses/Makefile	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/i2c/busses/Makefile	2004-03-16 09:37:55.733067456 +0000
@@ -15,6 +15,7 @@ obj-$(CONFIG_I2C_IBM_IIC)	+= i2c-ibm_iic
 obj-$(CONFIG_I2C_IOP3XX)	+= i2c-iop3xx.o
 obj-$(CONFIG_I2C_ISA)		+= i2c-isa.o
 obj-$(CONFIG_I2C_ITE)		+= i2c-ite.o
+obj-$(CONFIG_I2C_IXP42X)	+= i2c-ixp42x.o
 obj-$(CONFIG_I2C_KEYWEST)	+= i2c-keywest.o
 obj-$(CONFIG_I2C_NFORCE2)	+= i2c-nforce2.o
 obj-$(CONFIG_I2C_PHILIPSPAR)	+= i2c-philips-par.o
--- diff/drivers/i2c/busses/i2c-ali1535.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/i2c/busses/i2c-ali1535.c	2004-03-16 09:37:55.735067152 +0000
@@ -484,6 +484,7 @@ static struct i2c_algorithm smbus_algori
 
 static struct i2c_adapter ali1535_adapter = {
 	.owner		= THIS_MODULE,
+	.class          = I2C_ADAP_CLASS_SMBUS,
 	.algo		= &smbus_algorithm,
 	.name		= "unset",
 };
@@ -517,6 +518,7 @@ static int __devinit ali1535_probe(struc
 static void __devexit ali1535_remove(struct pci_dev *dev)
 {
 	i2c_del_adapter(&ali1535_adapter);
+	release_region(ali1535_smba, ALI1535_SMB_IOSIZE);
 }
 
 static struct pci_driver ali1535_driver = {
@@ -534,7 +536,6 @@ static int __init i2c_ali1535_init(void)
 static void __exit i2c_ali1535_exit(void)
 {
 	pci_unregister_driver(&ali1535_driver);
-	release_region(ali1535_smba, ALI1535_SMB_IOSIZE);
 }
 
 MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
--- diff/drivers/i2c/busses/i2c-elv.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/i2c/busses/i2c-elv.c	2004-03-16 09:37:55.743065936 +0000
@@ -18,7 +18,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     */
 /* ------------------------------------------------------------------------- */
 
-/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
+/* With some changes from KyÃ¶sti MÃ¤lkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
 #include <linux/config.h>
--- diff/drivers/i2c/busses/i2c-i801.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/i2c/busses/i2c-i801.c	2004-03-16 09:37:55.748065176 +0000
@@ -608,6 +608,7 @@ static int __devinit i801_probe(struct p
 static void __devexit i801_remove(struct pci_dev *dev)
 {
 	i2c_del_adapter(&i801_adapter);
+	release_region(i801_smba, (isich4 ? 16 : 8));
 }
 
 static struct pci_driver i801_driver = {
@@ -625,7 +626,6 @@ static int __init i2c_i801_init(void)
 static void __exit i2c_i801_exit(void)
 {
 	pci_unregister_driver(&i801_driver);
-	release_region(i801_smba, (isich4 ? 16 : 8));
 }
 
 MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
--- diff/drivers/i2c/busses/i2c-iop3xx.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/i2c/busses/i2c-iop3xx.c	2004-03-16 09:37:55.749065024 +0000
@@ -129,7 +129,7 @@ static void iop3xx_adap_final_cleanup(st
  * NB: the handler has to clear the source of the interrupt! 
  * Then it passes the SR flags of interest to BH via adap data
  */
-static void iop3xx_i2c_handler(int this_irq, 
+static irqreturn_t iop3xx_i2c_handler(int this_irq, 
 				void *dev_id, 
 				struct pt_regs *regs) 
 {
@@ -142,6 +142,7 @@ static void iop3xx_i2c_handler(int this_
 		iop3xx_adap->biu->SR_received |= sr;
 		wake_up_interruptible(&iop3xx_adap->waitq);
 	}
+	return IRQ_HANDLED;
 }
 
 /* check all error conditions, clear them , report most important */
@@ -185,7 +186,7 @@ static int iop3xx_adap_wait_event(struct
 	unsigned sr = 0;
 	int interrupted;
 	int done;
-	int rc;
+	int rc = 0;
 
 	do {
 		interrupted = wait_event_interruptible_timeout (
@@ -198,13 +199,13 @@ static int iop3xx_adap_wait_event(struct
 			return rc;
 		}else if (!interrupted) {
 			*status = sr;
-			return rc = -ETIMEDOUT;
+			return -ETIMEDOUT;
 		}
 	} while(!done);
 
 	*status = sr;
 
-	return rc = 0;
+	return 0;
 }
 
 /*
@@ -284,7 +285,7 @@ static int iop3xx_adap_write_byte(struct
 {
 	unsigned cr = *iop3xx_adap->biu->CR;
 	int status;
-	int rc;
+	int rc = 0;
 
 	*iop3xx_adap->biu->DBR = byte;
 	cr &= ~IOP321_ICR_MSTART;
@@ -304,7 +305,7 @@ static int iop3xx_adap_read_byte(struct 
 {
 	unsigned cr = *iop3xx_adap->biu->CR;
 	int status;
-	int rc;
+	int rc = 0;
 
 	cr &= ~IOP321_ICR_MSTART;
 
@@ -386,13 +387,16 @@ static int iop3xx_master_xfer(struct i2c
 	iop3xx_adap_reset(iop3xx_adap);
 	iop3xx_adap_enable(iop3xx_adap);
 
-	for (im = 0; ret == 0 && im != num; ++im) {
+	for (im = 0; ret == 0 && im != num; im++) {
 		ret = iop3xx_handle_msg(i2c_adap, &msgs[im]);
 	}
 
 	iop3xx_adap_transaction_cleanup(iop3xx_adap);
+	
+	if(ret)
+		return ret;
 
-	return ret;   
+	return im;   
 }
 
 static int algo_control(struct i2c_adapter *adapter, unsigned int cmd,
--- diff/drivers/i2c/busses/i2c-prosavage.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/i2c/busses/i2c-prosavage.c	2004-03-16 09:37:55.750064872 +0000
@@ -216,7 +216,7 @@ static int i2c_register_bus(struct pci_d
 /*
  * Cleanup stuff
  */
-static void __devexit prosavage_remove(struct pci_dev *dev)
+static void prosavage_remove(struct pci_dev *dev)
 {
 	struct s_i2c_chip *chip;
 	int i, ret;
@@ -321,7 +321,7 @@ static struct pci_driver prosavage_drive
 	.name		=	"prosavage-smbus",
 	.id_table	=	prosavage_pci_tbl,
 	.probe		=	prosavage_probe,
-	.remove		=	__devexit_p(prosavage_remove),
+	.remove		=	prosavage_remove,
 };
 
 static int __init i2c_prosavage_init(void)
--- diff/drivers/i2c/busses/i2c-sis5595.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/i2c/busses/i2c-sis5595.c	2004-03-16 09:37:55.751064720 +0000
@@ -364,6 +364,7 @@ static struct i2c_algorithm smbus_algori
 
 static struct i2c_adapter sis5595_adapter = {
 	.owner		= THIS_MODULE,
+	.class          = I2C_ADAP_CLASS_SMBUS,
 	.name		= "unset",
 	.algo		= &smbus_algorithm,
 };
@@ -391,6 +392,7 @@ static int __devinit sis5595_probe(struc
 static void __devexit sis5595_remove(struct pci_dev *dev)
 {
 	i2c_del_adapter(&sis5595_adapter);
+	release_region(sis5595_base + SMB_INDEX, 2);
 }
 
 static struct pci_driver sis5595_driver = {
@@ -408,7 +410,6 @@ static int __init i2c_sis5595_init(void)
 static void __exit i2c_sis5595_exit(void)
 {
 	pci_unregister_driver(&sis5595_driver);
-	release_region(sis5595_base + SMB_INDEX, 2);
 }
 
 MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
--- diff/drivers/i2c/busses/i2c-via.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/i2c/busses/i2c-via.c	2004-03-16 09:37:55.751064720 +0000
@@ -92,6 +92,7 @@ static struct i2c_algo_bit_data bit_data
 
 static struct i2c_adapter vt586b_adapter = {
 	.owner		= THIS_MODULE,
+	.class          = I2C_ADAP_CLASS_SMBUS,
 	.name		= "VIA i2c",
 	.algo_data	= &bit_data,
 };
--- diff/drivers/i2c/busses/i2c-voodoo3.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/i2c/busses/i2c-voodoo3.c	2004-03-16 09:37:55.762063048 +0000
@@ -171,6 +171,7 @@ static struct i2c_algo_bit_data voo_i2c_
 
 static struct i2c_adapter voodoo3_i2c_adapter = {
 	.owner		= THIS_MODULE,
+	.class		= I2C_ADAP_CLASS_TV_ANALOG, 
 	.name		= "I2C Voodoo3/Banshee adapter",
 	.algo_data	= &voo_i2c_bit_data,
 };
@@ -187,6 +188,7 @@ static struct i2c_algo_bit_data voo_ddc_
 
 static struct i2c_adapter voodoo3_ddc_adapter = {
 	.owner		= THIS_MODULE,
+	.class		= I2C_ADAP_CLASS_DDC, 
 	.name		= "DDC Voodoo3/Banshee adapter",
 	.algo_data	= &voo_ddc_bit_data,
 };
--- diff/drivers/i2c/chips/Kconfig	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/i2c/chips/Kconfig	2004-03-16 09:37:55.763062896 +0000
@@ -2,7 +2,7 @@
 # I2C Sensor device configuration
 #
 
-menu "I2C Hardware Sensors Chip support"
+menu "Hardware Sensors Chip support"
 	depends on I2C
 
 config I2C_SENSOR
@@ -33,18 +33,6 @@ config SENSORS_ASB100
 	  This driver can also be built as a module.  If so, the module
 	  will be called asb100.
 
-config SENSORS_EEPROM
-	tristate "EEPROM (DIMM) reader"
-	depends on I2C && EXPERIMENTAL
-	select I2C_SENSOR
-	help
-	  If you say yes here you get read-only access to the EEPROM data
-	  available on modern memory DIMMs, and which could theoretically
-	  also be available on other devices.
-
-	  This driver can also be built as a module.  If so, the module
-	  will be called eeprom.
-
 config SENSORS_FSCHER
 	tristate "FSC Hermes"
 	depends on I2C && EXPERIMENTAL
@@ -102,6 +90,17 @@ config SENSORS_LM78
 	  This driver can also be built as a module.  If so, the module
 	  will be called lm78.
 
+config SENSORS_LM80
+	tristate "National Semiconductor LM80"
+	depends on I2C && EXPERIMENTAL
+	select I2C_SENSOR
+	help
+	  If you say yes here you get support for National Semiconductor
+	  LM80 sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm80.
+
 config SENSORS_LM83
 	tristate "National Semiconductor LM83"
 	depends on I2C && EXPERIMENTAL
@@ -171,4 +170,32 @@ config SENSORS_W83L785TS
 	  This driver can also be built as a module.  If so, the module
 	  will be called w83l785ts.
 
+config SENSORS_W83627HF
+	tristate "Winbond W83627HF, W83627THF, W83637HF, W83697HF"
+	depends on I2C && EXPERIMENTAL
+	select I2C_SENSOR
+	help
+	  If you say yes here you get support for the Winbond W836X7 series
+	  of sensor chips: the W83627HF, W83627THF, W83637HF, and the W83697HF
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called w83627hf.
+
+endmenu
+
+menu "Other I2C Chip support"
+	depends on I2C
+
+config SENSORS_EEPROM
+	tristate "EEPROM reader"
+	depends on I2C && EXPERIMENTAL
+	select I2C_SENSOR
+	help
+	  If you say yes here you get read-only access to the EEPROM data
+	  available on modern memory DIMMs and Sony Vaio laptops.  Such
+	  EEPROMs could theoretically be available on other devices as well.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called eeprom.
+
 endmenu
--- diff/drivers/i2c/chips/Makefile	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/i2c/chips/Makefile	2004-03-16 09:37:55.763062896 +0000
@@ -4,6 +4,7 @@
 
 # asb100, then w83781d go first, as they can override other drivers' addresses.
 obj-$(CONFIG_SENSORS_ASB100)	+= asb100.o
+obj-$(CONFIG_SENSORS_W83627HF)	+= w83627hf.o
 obj-$(CONFIG_SENSORS_W83781D)	+= w83781d.o
 
 obj-$(CONFIG_SENSORS_ADM1021)	+= adm1021.o
@@ -13,6 +14,7 @@ obj-$(CONFIG_SENSORS_GL518SM)	+= gl518sm
 obj-$(CONFIG_SENSORS_IT87)	+= it87.o
 obj-$(CONFIG_SENSORS_LM75)	+= lm75.o
 obj-$(CONFIG_SENSORS_LM78)	+= lm78.o
+obj-$(CONFIG_SENSORS_LM80)	+= lm80.o
 obj-$(CONFIG_SENSORS_LM83)	+= lm83.o
 obj-$(CONFIG_SENSORS_LM85)	+= lm85.o
 obj-$(CONFIG_SENSORS_LM90)	+= lm90.o
--- diff/drivers/i2c/chips/adm1021.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/i2c/chips/adm1021.c	2004-03-16 09:37:55.765062592 +0000
@@ -139,7 +139,7 @@ static int adm1021_detach_client(struct 
 static int adm1021_read_value(struct i2c_client *client, u8 reg);
 static int adm1021_write_value(struct i2c_client *client, u8 reg,
 			       u16 value);
-static void adm1021_update_client(struct i2c_client *client);
+static struct adm1021_data *adm1021_update_device(struct device *dev);
 
 /* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */
 static int read_only = 0;
@@ -148,7 +148,7 @@ static int read_only = 0;
 /* This is the driver that will be inserted */
 static struct i2c_driver adm1021_driver = {
 	.owner		= THIS_MODULE,
-	.name		= "ADM1021-MAX1617",
+	.name		= "adm1021",
 	.id		= I2C_DRIVERID_ADM1021,
 	.flags		= I2C_DF_NOTIFY,
 	.attach_adapter	= adm1021_attach_adapter,
@@ -161,15 +161,10 @@ static struct i2c_driver adm1021_driver 
 static int adm1021_id = 0;
 
 #define show(value)	\
-static ssize_t show_##value(struct device *dev, char *buf)	\
-{								\
-	struct i2c_client *client = to_i2c_client(dev);		\
-	struct adm1021_data *data = i2c_get_clientdata(client);	\
-	int temp;						\
-								\
-	adm1021_update_client(client);				\
-	temp = TEMP_FROM_REG(data->value);			\
-	return sprintf(buf, "%d\n", temp);			\
+static ssize_t show_##value(struct device *dev, char *buf)		\
+{									\
+	struct adm1021_data *data = adm1021_update_device(dev);		\
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value));	\
 }
 show(temp_max);
 show(temp_hyst);
@@ -179,13 +174,10 @@ show(remote_temp_hyst);
 show(remote_temp_input);
 
 #define show2(value)	\
-static ssize_t show_##value(struct device *dev, char *buf)	\
-{								\
-	struct i2c_client *client = to_i2c_client(dev);		\
-	struct adm1021_data *data = i2c_get_clientdata(client);	\
-								\
-	adm1021_update_client(client);				\
-	return sprintf(buf, "%d\n", data->value);		\
+static ssize_t show_##value(struct device *dev, char *buf)		\
+{									\
+	struct adm1021_data *data = adm1021_update_device(dev);		\
+	return sprintf(buf, "%d\n", data->value);			\
 }
 show2(alarms);
 show2(die_code);
@@ -206,12 +198,12 @@ set(temp_hyst, ADM1021_REG_THYST_W);
 set(remote_temp_max, ADM1021_REG_REMOTE_TOS_W);
 set(remote_temp_hyst, ADM1021_REG_REMOTE_THYST_W);
 
-static DEVICE_ATTR(temp_max1, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
-static DEVICE_ATTR(temp_min1, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst);
-static DEVICE_ATTR(temp_input1, S_IRUGO, show_temp_input, NULL);
-static DEVICE_ATTR(temp_max2, S_IWUSR | S_IRUGO, show_remote_temp_max, set_remote_temp_max);
-static DEVICE_ATTR(temp_min2, S_IWUSR | S_IRUGO, show_remote_temp_hyst, set_remote_temp_hyst);
-static DEVICE_ATTR(temp_input2, S_IRUGO, show_remote_temp_input, NULL);
+static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
+static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst);
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL);
+static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_remote_temp_max, set_remote_temp_max);
+static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_remote_temp_hyst, set_remote_temp_hyst);
+static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote_temp_input, NULL);
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 static DEVICE_ATTR(die_code, S_IRUGO, show_die_code, NULL);
 
@@ -331,12 +323,12 @@ static int adm1021_detect(struct i2c_ada
 	adm1021_init_client(new_client);
 
 	/* Register sysfs hooks */
-	device_create_file(&new_client->dev, &dev_attr_temp_max1);
-	device_create_file(&new_client->dev, &dev_attr_temp_min1);
-	device_create_file(&new_client->dev, &dev_attr_temp_input1);
-	device_create_file(&new_client->dev, &dev_attr_temp_max2);
-	device_create_file(&new_client->dev, &dev_attr_temp_min2);
-	device_create_file(&new_client->dev, &dev_attr_temp_input2);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max);
+	device_create_file(&new_client->dev, &dev_attr_temp1_min);
+	device_create_file(&new_client->dev, &dev_attr_temp1_input);
+	device_create_file(&new_client->dev, &dev_attr_temp2_max);
+	device_create_file(&new_client->dev, &dev_attr_temp2_min);
+	device_create_file(&new_client->dev, &dev_attr_temp2_input);
 	device_create_file(&new_client->dev, &dev_attr_alarms);
 	if (data->type == adm1021)
 		device_create_file(&new_client->dev, &dev_attr_die_code);
@@ -393,8 +385,9 @@ static int adm1021_write_value(struct i2
 	return 0;
 }
 
-static void adm1021_update_client(struct i2c_client *client)
+static struct adm1021_data *adm1021_update_device(struct device *dev)
 {
+	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1021_data *data = i2c_get_clientdata(client);
 
 	down(&data->update_lock);
@@ -424,6 +417,8 @@ static void adm1021_update_client(struct
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 static int __init sensors_adm1021_init(void)
--- diff/drivers/i2c/chips/asb100.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/i2c/chips/asb100.c	2004-03-16 09:37:55.767062288 +0000
@@ -274,7 +274,7 @@ static ssize_t \
 { \
 	return show_in(dev, buf, 0x##offset); \
 } \
-static DEVICE_ATTR(in_input##offset, S_IRUGO, \
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, \
 		show_in##offset, NULL) \
 static ssize_t \
 	show_in##offset##_min (struct device *dev, char *buf) \
@@ -296,9 +296,9 @@ static ssize_t set_in##offset##_max (str
 { \
 	return set_in_max(dev, buf, count, 0x##offset); \
 } \
-static DEVICE_ATTR(in_min##offset, S_IRUGO | S_IWUSR, \
+static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
 		show_in##offset##_min, set_in##offset##_min) \
-static DEVICE_ATTR(in_max##offset, S_IRUGO | S_IWUSR, \
+static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
 		show_in##offset##_max, set_in##offset##_max)
 
 sysfs_in(0)
@@ -310,9 +310,9 @@ sysfs_in(5)
 sysfs_in(6)
 
 #define device_create_file_in(client, offset) do { \
-	device_create_file(&client->dev, &dev_attr_in_input##offset); \
-	device_create_file(&client->dev, &dev_attr_in_min##offset); \
-	device_create_file(&client->dev, &dev_attr_in_max##offset); \
+	device_create_file(&client->dev, &dev_attr_in##offset##_input); \
+	device_create_file(&client->dev, &dev_attr_in##offset##_min); \
+	device_create_file(&client->dev, &dev_attr_in##offset##_max); \
 } while (0)
 
 /* 3 Fans */
@@ -412,11 +412,11 @@ static ssize_t set_fan##offset##_div(str
 { \
 	return set_fan_div(dev, buf, count, offset - 1); \
 } \
-static DEVICE_ATTR(fan_input##offset, S_IRUGO, \
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
 		show_fan##offset, NULL) \
-static DEVICE_ATTR(fan_min##offset, S_IRUGO | S_IWUSR, \
+static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
 		show_fan##offset##_min, set_fan##offset##_min) \
-static DEVICE_ATTR(fan_div##offset, S_IRUGO | S_IWUSR, \
+static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
 		show_fan##offset##_div, set_fan##offset##_div)
 
 sysfs_fan(1)
@@ -424,9 +424,9 @@ sysfs_fan(2)
 sysfs_fan(3)
 
 #define device_create_file_fan(client, offset) do { \
-	device_create_file(&client->dev, &dev_attr_fan_input##offset); \
-	device_create_file(&client->dev, &dev_attr_fan_min##offset); \
-	device_create_file(&client->dev, &dev_attr_fan_div##offset); \
+	device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
+	device_create_file(&client->dev, &dev_attr_fan##offset##_min); \
+	device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
 } while (0)
 
 /* 4 Temp. Sensors */
@@ -484,7 +484,7 @@ static ssize_t show_temp##num(struct dev
 { \
 	return show_temp(dev, buf, num-1); \
 } \
-static DEVICE_ATTR(temp_input##num, S_IRUGO, show_temp##num, NULL) \
+static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL) \
 static ssize_t show_temp_max##num(struct device *dev, char *buf) \
 { \
 	return show_temp_max(dev, buf, num-1); \
@@ -494,7 +494,7 @@ static ssize_t set_temp_max##num(struct 
 { \
 	return set_temp_max(dev, buf, count, num-1); \
 } \
-static DEVICE_ATTR(temp_max##num, S_IRUGO | S_IWUSR, \
+static DEVICE_ATTR(temp##num##_max, S_IRUGO | S_IWUSR, \
 		show_temp_max##num, set_temp_max##num) \
 static ssize_t show_temp_hyst##num(struct device *dev, char *buf) \
 { \
@@ -505,7 +505,7 @@ static ssize_t set_temp_hyst##num(struct
 { \
 	return set_temp_hyst(dev, buf, count, num-1); \
 } \
-static DEVICE_ATTR(temp_hyst##num, S_IRUGO | S_IWUSR, \
+static DEVICE_ATTR(temp##num##_max_hyst, S_IRUGO | S_IWUSR, \
 		show_temp_hyst##num, set_temp_hyst##num)
 
 sysfs_temp(1)
@@ -515,9 +515,9 @@ sysfs_temp(4)
 
 /* VID */
 #define device_create_file_temp(client, num) do { \
-	device_create_file(&client->dev, &dev_attr_temp_input##num); \
-	device_create_file(&client->dev, &dev_attr_temp_max##num); \
-	device_create_file(&client->dev, &dev_attr_temp_hyst##num); \
+	device_create_file(&client->dev, &dev_attr_temp##num##_input); \
+	device_create_file(&client->dev, &dev_attr_temp##num##_max); \
+	device_create_file(&client->dev, &dev_attr_temp##num##_max_hyst); \
 } while (0)
 
 static ssize_t show_vid(struct device *dev, char *buf)
@@ -526,9 +526,9 @@ static ssize_t show_vid(struct device *d
 	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
 }
 
-static DEVICE_ATTR(vid, S_IRUGO, show_vid, NULL)
+static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid, NULL)
 #define device_create_file_vid(client) \
-device_create_file(&client->dev, &dev_attr_vid)
+device_create_file(&client->dev, &dev_attr_in0_ref)
 
 /* VRM */
 static ssize_t show_vrm(struct device *dev, char *buf)
@@ -597,12 +597,12 @@ static ssize_t set_pwm_enable1(struct de
 	return count;
 }
 
-static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1)
-static DEVICE_ATTR(pwm_enable1, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR(fan1_pwm, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1)
+static DEVICE_ATTR(fan1_pwm_enable, S_IRUGO | S_IWUSR,
 		show_pwm_enable1, set_pwm_enable1)
 #define device_create_file_pwm1(client) do { \
-	device_create_file(&new_client->dev, &dev_attr_pwm1); \
-	device_create_file(&new_client->dev, &dev_attr_pwm_enable1); \
+	device_create_file(&new_client->dev, &dev_attr_fan1_pwm); \
+	device_create_file(&new_client->dev, &dev_attr_fan1_pwm_enable); \
 } while (0)
 
 /* This function is called when:
--- diff/drivers/i2c/chips/fscher.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/i2c/chips/fscher.c	2004-03-16 09:37:55.768062136 +0000
@@ -26,6 +26,11 @@
  *  and Philip Edelbrock <phil@netroedge.com>
  */
 
+#include <linux/config.h>
+#ifdef CONFIG_I2C_DEBUG_CHIP
+#define DEBUG	1
+#endif
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -108,7 +113,7 @@ SENSORS_INSMOD_1(fscher);
 static int fscher_attach_adapter(struct i2c_adapter *adapter);
 static int fscher_detect(struct i2c_adapter *adapter, int address, int kind);
 static int fscher_detach_client(struct i2c_client *client);
-static void fscher_update_client(struct i2c_client *client);
+static struct fscher_data *fscher_update_device(struct device *dev);
 static void fscher_init_client(struct i2c_client *client);
 
 static int fscher_read_value(struct i2c_client *client, u8 reg);
@@ -160,71 +165,69 @@ static int fscher_id = 0;
  * Sysfs stuff
  */
 
-#define sysfs_r(kind, offset, reg) \
-static ssize_t show_##kind (struct fscher_data *, char *, int); \
-static ssize_t show_##kind##offset (struct device *, char *); \
-static ssize_t show_##kind##offset (struct device *dev, char *buf) \
+#define sysfs_r(kind, sub, offset, reg) \
+static ssize_t show_##kind##sub (struct fscher_data *, char *, int); \
+static ssize_t show_##kind##offset##sub (struct device *, char *); \
+static ssize_t show_##kind##offset##sub (struct device *dev, char *buf) \
 { \
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct fscher_data *data = i2c_get_clientdata(client); \
-	fscher_update_client(client); \
-	return show_##kind(data, buf, (offset)); \
+	struct fscher_data *data = fscher_update_device(dev); \
+	return show_##kind##sub(data, buf, (offset)); \
 }
 
-#define sysfs_w(kind, offset, reg) \
-static ssize_t set_##kind (struct i2c_client *, struct fscher_data *, const char *, size_t, int, int); \
-static ssize_t set_##kind##offset (struct device *, const char *, size_t); \
-static ssize_t set_##kind##offset (struct device *dev, const char *buf, size_t count) \
+#define sysfs_w(kind, sub, offset, reg) \
+static ssize_t set_##kind##sub (struct i2c_client *, struct fscher_data *, const char *, size_t, int, int); \
+static ssize_t set_##kind##offset##sub (struct device *, const char *, size_t); \
+static ssize_t set_##kind##offset##sub (struct device *dev, const char *buf, size_t count) \
 { \
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct fscher_data *data = i2c_get_clientdata(client); \
-	return set_##kind(client, data, buf, count, (offset), reg); \
+	return set_##kind##sub(client, data, buf, count, (offset), reg); \
 }
 
-#define sysfs_rw_n(kind, offset, reg) \
-sysfs_r(kind, offset, reg) \
-sysfs_w(kind, offset, reg) \
-static DEVICE_ATTR(kind##offset, S_IRUGO | S_IWUSR, show_##kind##offset, set_##kind##offset);
-
-#define sysfs_rw(kind, reg) \
-sysfs_r(kind, 0, reg) \
-sysfs_w(kind, 0, reg) \
-static DEVICE_ATTR(kind, S_IRUGO | S_IWUSR, show_##kind##0, set_##kind##0);
-
-#define sysfs_ro_n(kind, offset, reg) \
-sysfs_r(kind, offset, reg) \
-static DEVICE_ATTR(kind##offset, S_IRUGO, show_##kind##offset, NULL);
-
-#define sysfs_ro(kind, reg) \
-sysfs_r(kind, 0, reg) \
-static DEVICE_ATTR(kind, S_IRUGO, show_##kind##0, NULL);
+#define sysfs_rw_n(kind, sub, offset, reg) \
+sysfs_r(kind, sub, offset, reg) \
+sysfs_w(kind, sub, offset, reg) \
+static DEVICE_ATTR(kind##offset##sub, S_IRUGO | S_IWUSR, show_##kind##offset##sub, set_##kind##offset##sub);
+
+#define sysfs_rw(kind, sub, reg) \
+sysfs_r(kind, sub, 0, reg) \
+sysfs_w(kind, sub, 0, reg) \
+static DEVICE_ATTR(kind##sub, S_IRUGO | S_IWUSR, show_##kind##0##sub, set_##kind##0##sub);
+
+#define sysfs_ro_n(kind, sub, offset, reg) \
+sysfs_r(kind, sub, offset, reg) \
+static DEVICE_ATTR(kind##offset##sub, S_IRUGO, show_##kind##offset##sub, NULL);
+
+#define sysfs_ro(kind, sub, reg) \
+sysfs_r(kind, sub, 0, reg) \
+static DEVICE_ATTR(kind, S_IRUGO, show_##kind##0##sub, NULL);
 
 #define sysfs_fan(offset, reg_status, reg_min, reg_ripple, reg_act) \
-sysfs_rw_n(pwm       , offset, reg_min) \
-sysfs_rw_n(fan_status, offset, reg_status) \
-sysfs_rw_n(fan_div   , offset, reg_ripple) \
-sysfs_ro_n(fan_input , offset, reg_act)
+sysfs_rw_n(fan, _pwm   , offset, reg_min) \
+sysfs_rw_n(fan, _status, offset, reg_status) \
+sysfs_rw_n(fan, _div   , offset, reg_ripple) \
+sysfs_ro_n(fan, _input , offset, reg_act)
 
 #define sysfs_temp(offset, reg_status, reg_act) \
-sysfs_rw_n(temp_status, offset, reg_status) \
-sysfs_ro_n(temp_input , offset, reg_act)
+sysfs_rw_n(temp, _status, offset, reg_status) \
+sysfs_ro_n(temp, _input , offset, reg_act)
     
 #define sysfs_in(offset, reg_act) \
-sysfs_ro_n(in_input, offset, reg_act)
+sysfs_ro_n(in, _input, offset, reg_act)
 
 #define sysfs_revision(reg_revision) \
-sysfs_ro(revision, reg_revision)
+sysfs_ro(revision, , reg_revision)
 
 #define sysfs_alarms(reg_events) \
-sysfs_ro(alarms, reg_events)
+sysfs_ro(alarms, , reg_events)
 
 #define sysfs_control(reg_control) \
-sysfs_rw(control, reg_control)
+sysfs_rw(control, , reg_control)
 
 #define sysfs_watchdog(reg_control, reg_status, reg_preset) \
-sysfs_rw(watchdog_control, reg_control) \
-sysfs_rw(watchdog_status , reg_status) \
-sysfs_rw(watchdog_preset , reg_preset)
+sysfs_rw(watchdog, _control, reg_control) \
+sysfs_rw(watchdog, _status , reg_status) \
+sysfs_rw(watchdog, _preset , reg_preset)
 
 sysfs_fan(1, FSCHER_REG_FAN0_STATE, FSCHER_REG_FAN0_MIN,
 	     FSCHER_REG_FAN0_RIPPLE, FSCHER_REG_FAN0_ACT)
@@ -248,21 +251,21 @@ sysfs_watchdog(FSCHER_REG_WDOG_CONTROL, 
   
 #define device_create_file_fan(client, offset) \
 do { \
-	device_create_file(&client->dev, &dev_attr_fan_status##offset); \
-	device_create_file(&client->dev, &dev_attr_pwm##offset); \
-	device_create_file(&client->dev, &dev_attr_fan_div##offset); \
-	device_create_file(&client->dev, &dev_attr_fan_input##offset); \
+	device_create_file(&client->dev, &dev_attr_fan##offset##_status); \
+	device_create_file(&client->dev, &dev_attr_fan##offset##_pwm); \
+	device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
+	device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
 } while (0)
 
 #define device_create_file_temp(client, offset) \
 do { \
-	device_create_file(&client->dev, &dev_attr_temp_status##offset); \
-	device_create_file(&client->dev, &dev_attr_temp_input##offset); \
+	device_create_file(&client->dev, &dev_attr_temp##offset##_status); \
+	device_create_file(&client->dev, &dev_attr_temp##offset##_input); \
 } while (0)
 
 #define device_create_file_in(client, offset) \
 do { \
-	device_create_file(&client->dev, &dev_attr_in_input##offset); \
+	device_create_file(&client->dev, &dev_attr_in##offset##_input); \
 } while (0)
 
 #define device_create_file_revision(client) \
@@ -415,8 +418,9 @@ static void fscher_init_client(struct i2
 	data->revision =  fscher_read_value(client, FSCHER_REG_REVISION);
 }
 
-static void fscher_update_client(struct i2c_client *client)
+static struct fscher_data *fscher_update_device(struct device *dev)
 {
+	struct i2c_client *client = to_i2c_client(dev);
 	struct fscher_data *data = i2c_get_clientdata(client);
 
 	down(&data->update_lock);
@@ -461,6 +465,8 @@ static void fscher_update_client(struct 
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 
@@ -484,7 +490,7 @@ static ssize_t show_fan_status(struct fs
 	return sprintf(buf, "%u\n", data->fan_status[FAN_INDEX_FROM_NUM(nr)] & 0x04);
 }
 
-static ssize_t set_pwm(struct i2c_client *client, struct fscher_data *data,
+static ssize_t set_fan_pwm(struct i2c_client *client, struct fscher_data *data,
 		       const char *buf, size_t count, int nr, int reg)
 {
 	data->fan_min[FAN_INDEX_FROM_NUM(nr)] = simple_strtoul(buf, NULL, 10) & 0xff;
@@ -493,7 +499,7 @@ static ssize_t set_pwm(struct i2c_client
 	return count;
 }
 
-static ssize_t show_pwm (struct fscher_data *data, char *buf, int nr)
+static ssize_t show_fan_pwm (struct fscher_data *data, char *buf, int nr)
 {
 	return sprintf(buf, "%u\n", data->fan_min[FAN_INDEX_FROM_NUM(nr)]);
 }
--- diff/drivers/i2c/chips/gl518sm.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/i2c/chips/gl518sm.c	2004-03-16 09:37:55.770061832 +0000
@@ -151,7 +151,7 @@ static void gl518_init_client(struct i2c
 static int gl518_detach_client(struct i2c_client *client);
 static int gl518_read_value(struct i2c_client *client, u8 reg);
 static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value);
-static void gl518_update_client(struct i2c_client *client);
+static struct gl518_data *gl518_update_device(struct device *dev);
 
 /* This is the driver that will be inserted */
 static struct i2c_driver gl518_driver = {
@@ -176,18 +176,14 @@ static int gl518_id = 0;
 #define show(type, suffix, value)					\
 static ssize_t show_##suffix(struct device *dev, char *buf)		\
 {									\
-	struct i2c_client *client = to_i2c_client(dev);			\
-	struct gl518_data *data = i2c_get_clientdata(client);		\
-	gl518_update_client(client);					\
+	struct gl518_data *data = gl518_update_device(dev);		\
 	return sprintf(buf, "%d\n", type##_FROM_REG(data->value));	\
 }
 
 #define show_fan(suffix, value, index)					\
 static ssize_t show_##suffix(struct device *dev, char *buf)		\
 {									\
-	struct i2c_client *client = to_i2c_client(dev);			\
-	struct gl518_data *data = i2c_get_clientdata(client);		\
-	gl518_update_client(client);					\
+	struct gl518_data *data = gl518_update_device(dev);		\
 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->value[index],	\
 		DIV_FROM_REG(data->fan_div[index])));			\
 }
@@ -307,29 +303,29 @@ static ssize_t set_fan_min2(struct devic
 	return count;
 }
 
-static DEVICE_ATTR(temp_input1, S_IRUGO, show_temp_input1, NULL);
-static DEVICE_ATTR(temp_max1, S_IWUSR|S_IRUGO, show_temp_max1, set_temp_max1);
-static DEVICE_ATTR(temp_hyst1, S_IWUSR|S_IRUGO,
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL);
+static DEVICE_ATTR(temp1_max, S_IWUSR|S_IRUGO, show_temp_max1, set_temp_max1);
+static DEVICE_ATTR(temp1_max_hyst, S_IWUSR|S_IRUGO,
 	show_temp_hyst1, set_temp_hyst1);
-static DEVICE_ATTR(fan_auto1, S_IWUSR|S_IRUGO, show_fan_auto1, set_fan_auto1);
-static DEVICE_ATTR(fan_input1, S_IRUGO, show_fan_input1, NULL);
-static DEVICE_ATTR(fan_input2, S_IRUGO, show_fan_input2, NULL);
-static DEVICE_ATTR(fan_min1, S_IWUSR|S_IRUGO, show_fan_min1, set_fan_min1);
-static DEVICE_ATTR(fan_min2, S_IWUSR|S_IRUGO, show_fan_min2, set_fan_min2);
-static DEVICE_ATTR(fan_div1, S_IWUSR|S_IRUGO, show_fan_div1, set_fan_div1);
-static DEVICE_ATTR(fan_div2, S_IWUSR|S_IRUGO, show_fan_div2, set_fan_div2);
-static DEVICE_ATTR(in_input0, S_IRUGO, show_in_input0, NULL);
-static DEVICE_ATTR(in_input1, S_IRUGO, show_in_input1, NULL);
-static DEVICE_ATTR(in_input2, S_IRUGO, show_in_input2, NULL);
-static DEVICE_ATTR(in_input3, S_IRUGO, show_in_input3, NULL);
-static DEVICE_ATTR(in_min0, S_IWUSR|S_IRUGO, show_in_min0, set_in_min0);
-static DEVICE_ATTR(in_min1, S_IWUSR|S_IRUGO, show_in_min1, set_in_min1);
-static DEVICE_ATTR(in_min2, S_IWUSR|S_IRUGO, show_in_min2, set_in_min2);
-static DEVICE_ATTR(in_min3, S_IWUSR|S_IRUGO, show_in_min3, set_in_min3);
-static DEVICE_ATTR(in_max0, S_IWUSR|S_IRUGO, show_in_max0, set_in_max0);
-static DEVICE_ATTR(in_max1, S_IWUSR|S_IRUGO, show_in_max1, set_in_max1);
-static DEVICE_ATTR(in_max2, S_IWUSR|S_IRUGO, show_in_max2, set_in_max2);
-static DEVICE_ATTR(in_max3, S_IWUSR|S_IRUGO, show_in_max3, set_in_max3);
+static DEVICE_ATTR(fan1_auto, S_IWUSR|S_IRUGO, show_fan_auto1, set_fan_auto1);
+static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input1, NULL);
+static DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input2, NULL);
+static DEVICE_ATTR(fan1_min, S_IWUSR|S_IRUGO, show_fan_min1, set_fan_min1);
+static DEVICE_ATTR(fan2_min, S_IWUSR|S_IRUGO, show_fan_min2, set_fan_min2);
+static DEVICE_ATTR(fan1_div, S_IWUSR|S_IRUGO, show_fan_div1, set_fan_div1);
+static DEVICE_ATTR(fan2_div, S_IWUSR|S_IRUGO, show_fan_div2, set_fan_div2);
+static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input0, NULL);
+static DEVICE_ATTR(in1_input, S_IRUGO, show_in_input1, NULL);
+static DEVICE_ATTR(in2_input, S_IRUGO, show_in_input2, NULL);
+static DEVICE_ATTR(in3_input, S_IRUGO, show_in_input3, NULL);
+static DEVICE_ATTR(in0_min, S_IWUSR|S_IRUGO, show_in_min0, set_in_min0);
+static DEVICE_ATTR(in1_min, S_IWUSR|S_IRUGO, show_in_min1, set_in_min1);
+static DEVICE_ATTR(in2_min, S_IWUSR|S_IRUGO, show_in_min2, set_in_min2);
+static DEVICE_ATTR(in3_min, S_IWUSR|S_IRUGO, show_in_min3, set_in_min3);
+static DEVICE_ATTR(in0_max, S_IWUSR|S_IRUGO, show_in_max0, set_in_max0);
+static DEVICE_ATTR(in1_max, S_IWUSR|S_IRUGO, show_in_max1, set_in_max1);
+static DEVICE_ATTR(in2_max, S_IWUSR|S_IRUGO, show_in_max2, set_in_max2);
+static DEVICE_ATTR(in3_max, S_IWUSR|S_IRUGO, show_in_max3, set_in_max3);
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 static DEVICE_ATTR(beep_enable, S_IWUSR|S_IRUGO,
 	show_beep_enable, set_beep_enable);
@@ -424,28 +420,28 @@ static int gl518_detect(struct i2c_adapt
 	gl518_init_client((struct i2c_client *) new_client);
 
 	/* Register sysfs hooks */
-	device_create_file(&new_client->dev, &dev_attr_in_input0);
-	device_create_file(&new_client->dev, &dev_attr_in_input1);
-	device_create_file(&new_client->dev, &dev_attr_in_input2);
-	device_create_file(&new_client->dev, &dev_attr_in_input3);
-	device_create_file(&new_client->dev, &dev_attr_in_min0);
-	device_create_file(&new_client->dev, &dev_attr_in_min1);
-	device_create_file(&new_client->dev, &dev_attr_in_min2);
-	device_create_file(&new_client->dev, &dev_attr_in_min3);
-	device_create_file(&new_client->dev, &dev_attr_in_max0);
-	device_create_file(&new_client->dev, &dev_attr_in_max1);
-	device_create_file(&new_client->dev, &dev_attr_in_max2);
-	device_create_file(&new_client->dev, &dev_attr_in_max3);
-	device_create_file(&new_client->dev, &dev_attr_fan_auto1);
-	device_create_file(&new_client->dev, &dev_attr_fan_input1);
-	device_create_file(&new_client->dev, &dev_attr_fan_input2);
-	device_create_file(&new_client->dev, &dev_attr_fan_min1);
-	device_create_file(&new_client->dev, &dev_attr_fan_min2);
-	device_create_file(&new_client->dev, &dev_attr_fan_div1);
-	device_create_file(&new_client->dev, &dev_attr_fan_div2);
-	device_create_file(&new_client->dev, &dev_attr_temp_input1);
-	device_create_file(&new_client->dev, &dev_attr_temp_max1);
-	device_create_file(&new_client->dev, &dev_attr_temp_hyst1);
+	device_create_file(&new_client->dev, &dev_attr_in0_input);
+	device_create_file(&new_client->dev, &dev_attr_in1_input);
+	device_create_file(&new_client->dev, &dev_attr_in2_input);
+	device_create_file(&new_client->dev, &dev_attr_in3_input);
+	device_create_file(&new_client->dev, &dev_attr_in0_min);
+	device_create_file(&new_client->dev, &dev_attr_in1_min);
+	device_create_file(&new_client->dev, &dev_attr_in2_min);
+	device_create_file(&new_client->dev, &dev_attr_in3_min);
+	device_create_file(&new_client->dev, &dev_attr_in0_max);
+	device_create_file(&new_client->dev, &dev_attr_in1_max);
+	device_create_file(&new_client->dev, &dev_attr_in2_max);
+	device_create_file(&new_client->dev, &dev_attr_in3_max);
+	device_create_file(&new_client->dev, &dev_attr_fan1_auto);
+	device_create_file(&new_client->dev, &dev_attr_fan1_input);
+	device_create_file(&new_client->dev, &dev_attr_fan2_input);
+	device_create_file(&new_client->dev, &dev_attr_fan1_min);
+	device_create_file(&new_client->dev, &dev_attr_fan2_min);
+	device_create_file(&new_client->dev, &dev_attr_fan1_div);
+	device_create_file(&new_client->dev, &dev_attr_fan2_div);
+	device_create_file(&new_client->dev, &dev_attr_temp1_input);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
 	device_create_file(&new_client->dev, &dev_attr_alarms);
 	device_create_file(&new_client->dev, &dev_attr_beep_enable);
 	device_create_file(&new_client->dev, &dev_attr_beep_mask);
@@ -523,8 +519,9 @@ static int gl518_write_value(struct i2c_
 		return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static void gl518_update_client(struct i2c_client *client)
+static struct gl518_data *gl518_update_device(struct device *dev)
 {
+	struct i2c_client *client = to_i2c_client(dev);
 	struct gl518_data *data = i2c_get_clientdata(client);
 	int val;
 
@@ -590,6 +587,8 @@ static void gl518_update_client(struct i
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 static int __init sensors_gl518sm_init(void)
--- diff/drivers/i2c/chips/it87.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/i2c/chips/it87.c	2004-03-16 09:37:55.773061376 +0000
@@ -6,7 +6,7 @@
               IT8712F  Super I/O chip w/LPC interface & SMbus
               Sis950   A clone of the IT8705F
 
-    Copyright (c) 2001 Chris Gauthron <chrisg@0-in.com> 
+    Copyright (C) 2001 Chris Gauthron <chrisg@0-in.com> 
     Largely inspired by lm78.c of the same package
 
     This program is free software; you can redistribute it and/or modify
@@ -55,13 +55,10 @@ SENSORS_INSMOD_4(it87, it8705, it8712, s
 
 
 /* Update battery voltage after every reading if true */
-static int update_vbat = 0;
+static int update_vbat;
 
-
-/* Enable Temp1 as thermal resistor */
-/* Enable Temp2 as thermal diode */
-/* Enable Temp3 as thermal resistor */
-static int temp_type = 0x2a;
+/* Reset the registers on init if true */
+static int reset;
 
 /* Many IT87 constants specified below */
 
@@ -135,61 +132,6 @@ static int DIV_TO_REG(int val)
 }
 #define DIV_FROM_REG(val) (1 << (val))
 
-/* Initial limits. Use the config file to set better limits. */
-#define IT87_INIT_IN_0 170
-#define IT87_INIT_IN_1 250
-#define IT87_INIT_IN_2 (330 / 2)
-#define IT87_INIT_IN_3 (((500)   * 100)/168)
-#define IT87_INIT_IN_4 (((1200)  * 10)/38)
-#define IT87_INIT_IN_5 (((1200)  * 10)/72)
-#define IT87_INIT_IN_6 (((500)   * 10)/56)
-#define IT87_INIT_IN_7 (((500)   * 100)/168)
-
-#define IT87_INIT_IN_PERCENTAGE 10
-
-#define IT87_INIT_IN_MIN_0 \
-	(IT87_INIT_IN_0 - IT87_INIT_IN_0 * IT87_INIT_IN_PERCENTAGE / 100)
-#define IT87_INIT_IN_MAX_0 \
-	(IT87_INIT_IN_0 + IT87_INIT_IN_0 * IT87_INIT_IN_PERCENTAGE / 100)
-#define IT87_INIT_IN_MIN_1 \
-	(IT87_INIT_IN_1 - IT87_INIT_IN_1 * IT87_INIT_IN_PERCENTAGE / 100)
-#define IT87_INIT_IN_MAX_1 \
-	(IT87_INIT_IN_1 + IT87_INIT_IN_1 * IT87_INIT_IN_PERCENTAGE / 100)
-#define IT87_INIT_IN_MIN_2 \
-	(IT87_INIT_IN_2 - IT87_INIT_IN_2 * IT87_INIT_IN_PERCENTAGE / 100)
-#define IT87_INIT_IN_MAX_2 \
-	(IT87_INIT_IN_2 + IT87_INIT_IN_2 * IT87_INIT_IN_PERCENTAGE / 100)
-#define IT87_INIT_IN_MIN_3 \
-	(IT87_INIT_IN_3 - IT87_INIT_IN_3 * IT87_INIT_IN_PERCENTAGE / 100)
-#define IT87_INIT_IN_MAX_3 \
-	(IT87_INIT_IN_3 + IT87_INIT_IN_3 * IT87_INIT_IN_PERCENTAGE / 100)
-#define IT87_INIT_IN_MIN_4 \
-	(IT87_INIT_IN_4 - IT87_INIT_IN_4 * IT87_INIT_IN_PERCENTAGE / 100)
-#define IT87_INIT_IN_MAX_4 \
-	(IT87_INIT_IN_4 + IT87_INIT_IN_4 * IT87_INIT_IN_PERCENTAGE / 100)
-#define IT87_INIT_IN_MIN_5 \
-	(IT87_INIT_IN_5 - IT87_INIT_IN_5 * IT87_INIT_IN_PERCENTAGE / 100)
-#define IT87_INIT_IN_MAX_5 \
-	(IT87_INIT_IN_5 + IT87_INIT_IN_5 * IT87_INIT_IN_PERCENTAGE / 100)
-#define IT87_INIT_IN_MIN_6 \
-	(IT87_INIT_IN_6 - IT87_INIT_IN_6 * IT87_INIT_IN_PERCENTAGE / 100)
-#define IT87_INIT_IN_MAX_6 \
-	(IT87_INIT_IN_6 + IT87_INIT_IN_6 * IT87_INIT_IN_PERCENTAGE / 100)
-#define IT87_INIT_IN_MIN_7 \
-	(IT87_INIT_IN_7 - IT87_INIT_IN_7 * IT87_INIT_IN_PERCENTAGE / 100)
-#define IT87_INIT_IN_MAX_7 \
-	(IT87_INIT_IN_7 + IT87_INIT_IN_7 * IT87_INIT_IN_PERCENTAGE / 100)
-
-#define IT87_INIT_FAN_MIN_1 3000
-#define IT87_INIT_FAN_MIN_2 3000
-#define IT87_INIT_FAN_MIN_3 3000
-
-#define IT87_INIT_TEMP_HIGH_1 600
-#define IT87_INIT_TEMP_LOW_1  200
-#define IT87_INIT_TEMP_HIGH_2 600
-#define IT87_INIT_TEMP_LOW_2  200
-#define IT87_INIT_TEMP_HIGH_3 600 
-#define IT87_INIT_TEMP_LOW_3  200
 
 /* For each registered IT87, we need to keep some data in memory. That
    data is pointed to by it87_list[NR]->data. The structure itself is
@@ -225,13 +167,13 @@ static int it87_detach_client(struct i2c
 static int it87_read_value(struct i2c_client *client, u8 register);
 static int it87_write_value(struct i2c_client *client, u8 register,
 			u8 value);
-static void it87_update_client(struct i2c_client *client);
+static struct it87_data *it87_update_device(struct device *dev);
 static void it87_init_client(struct i2c_client *client, struct it87_data *data);
 
 
 static struct i2c_driver it87_driver = {
 	.owner		= THIS_MODULE,
-	.name		= "IT87xx",
+	.name		= "it87",
 	.id		= I2C_DRIVERID_IT87,
 	.flags		= I2C_DF_NOTIFY,
 	.attach_adapter	= it87_attach_adapter,
@@ -242,25 +184,19 @@ static int it87_id = 0;
 
 static ssize_t show_in(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
-	it87_update_client(client);
+	struct it87_data *data = it87_update_device(dev);
 	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])*10 );
 }
 
 static ssize_t show_in_min(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
-	it87_update_client(client);
+	struct it87_data *data = it87_update_device(dev);
 	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])*10 );
 }
 
 static ssize_t show_in_max(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
-	it87_update_client(client);
+	struct it87_data *data = it87_update_device(dev);
 	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])*10 );
 }
 
@@ -293,7 +229,7 @@ static ssize_t							\
 {								\
 	return show_in(dev, buf, 0x##offset);			\
 }								\
-static DEVICE_ATTR(in_input##offset, S_IRUGO, show_in##offset, NULL)
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL)
 
 #define limit_in_offset(offset)					\
 static ssize_t							\
@@ -316,9 +252,9 @@ static ssize_t set_in##offset##_max (str
 {								\
 	return set_in_max(dev, buf, count, 0x##offset);		\
 }								\
-static DEVICE_ATTR(in_min##offset, S_IRUGO | S_IWUSR, 		\
+static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, 	\
 		show_in##offset##_min, set_in##offset##_min)	\
-static DEVICE_ATTR(in_max##offset, S_IRUGO | S_IWUSR, 		\
+static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, 	\
 		show_in##offset##_max, set_in##offset##_max)
 
 show_in_offset(0);
@@ -342,23 +278,17 @@ show_in_offset(8);
 /* 3 temperatures */
 static ssize_t show_temp(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
-	it87_update_client(client);
+	struct it87_data *data = it87_update_device(dev);
 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])*100 );
 }
 static ssize_t show_temp_max(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
-	it87_update_client(client);
+	struct it87_data *data = it87_update_device(dev);
 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])*100);
 }
 static ssize_t show_temp_min(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
-	it87_update_client(client);
+	struct it87_data *data = it87_update_device(dev);
 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])*100);
 }
 static ssize_t set_temp_max(struct device *dev, const char *buf, 
@@ -406,10 +336,10 @@ static ssize_t set_temp_##offset##_min (
 {									\
 	return set_temp_min(dev, buf, count, 0x##offset - 1);		\
 }									\
-static DEVICE_ATTR(temp_input##offset, S_IRUGO, show_temp_##offset, NULL) \
-static DEVICE_ATTR(temp_max##offset, S_IRUGO | S_IWUSR, 		\
+static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL) \
+static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, 		\
 		show_temp_##offset##_max, set_temp_##offset##_max) 	\
-static DEVICE_ATTR(temp_min##offset, S_IRUGO | S_IWUSR, 		\
+static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, 		\
 		show_temp_##offset##_min, set_temp_##offset##_min)	
 
 show_temp_offset(1);
@@ -418,14 +348,12 @@ show_temp_offset(3);
 
 static ssize_t show_sensor(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
-	it87_update_client(client);
+	struct it87_data *data = it87_update_device(dev);
 	if (data->sensor & (1 << nr))
-	    return sprintf(buf, "1\n");
+		return sprintf(buf, "3\n");  /* thermal diode */
 	if (data->sensor & (8 << nr))
-	    return sprintf(buf, "2\n");
-	return sprintf(buf, "0\n");
+		return sprintf(buf, "2\n");  /* thermistor */
+	return sprintf(buf, "0\n");      /* disabled */
 }
 static ssize_t set_sensor(struct device *dev, const char *buf, 
 		size_t count, int nr)
@@ -436,10 +364,13 @@ static ssize_t set_sensor(struct device 
 
 	data->sensor &= ~(1 << nr);
 	data->sensor &= ~(8 << nr);
-	if (val == 1)
+	/* 3 = thermal diode; 2 = thermistor; 0 = disabled */
+	if (val == 3)
 	    data->sensor |= 1 << nr;
 	else if (val == 2)
 	    data->sensor |= 8 << nr;
+	else if (val != 0)
+		return -1;
 	it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor);
 	return count;
 }
@@ -453,7 +384,7 @@ static ssize_t set_sensor_##offset (stru
 {									\
 	return set_sensor(dev, buf, count, 0x##offset - 1);		\
 }									\
-static DEVICE_ATTR(sensor##offset, S_IRUGO | S_IWUSR,	 		\
+static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR,	 		\
 		show_sensor_##offset, set_sensor_##offset)
 
 show_sensor_offset(1);
@@ -463,25 +394,19 @@ show_sensor_offset(3);
 /* 3 Fans */
 static ssize_t show_fan(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
-	it87_update_client(client);
+	struct it87_data *data = it87_update_device(dev);
 	return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], 
 				DIV_FROM_REG(data->fan_div[nr])) );
 }
 static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
-	it87_update_client(client);
+	struct it87_data *data = it87_update_device(dev);
 	return sprintf(buf,"%d\n",
 		FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) );
 }
 static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
-	it87_update_client(client);
+	struct it87_data *data = it87_update_device(dev);
 	return sprintf(buf,"%d\n", DIV_FROM_REG(data->fan_div[nr]) );
 }
 static ssize_t set_fan_min(struct device *dev, const char *buf, 
@@ -554,10 +479,10 @@ static ssize_t set_fan_##offset##_div (s
 {									\
 	return set_fan_div(dev, buf, count, 0x##offset - 1);		\
 }									\
-static DEVICE_ATTR(fan_input##offset, S_IRUGO, show_fan_##offset, NULL) \
-static DEVICE_ATTR(fan_min##offset, S_IRUGO | S_IWUSR, 			\
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL) \
+static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, 		\
 		show_fan_##offset##_min, set_fan_##offset##_min) 	\
-static DEVICE_ATTR(fan_div##offset, S_IRUGO | S_IWUSR, 			\
+static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, 		\
 		show_fan_##offset##_div, set_fan_##offset##_div)
 
 show_fan_offset(1);
@@ -567,9 +492,7 @@ show_fan_offset(3);
 /* Alarms */
 static ssize_t show_alarms(struct device *dev, char *buf)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
-	it87_update_client(client);
+	struct it87_data *data = it87_update_device(dev);
 	return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms));
 }
 static DEVICE_ATTR(alarms, S_IRUGO | S_IWUSR, show_alarms, NULL);
@@ -706,52 +629,52 @@ int it87_detect(struct i2c_adapter *adap
 	it87_init_client(new_client, data);
 
 	/* Register sysfs hooks */
-	device_create_file(&new_client->dev, &dev_attr_in_input0);
-	device_create_file(&new_client->dev, &dev_attr_in_input1);
-	device_create_file(&new_client->dev, &dev_attr_in_input2);
-	device_create_file(&new_client->dev, &dev_attr_in_input3);
-	device_create_file(&new_client->dev, &dev_attr_in_input4);
-	device_create_file(&new_client->dev, &dev_attr_in_input5);
-	device_create_file(&new_client->dev, &dev_attr_in_input6);
-	device_create_file(&new_client->dev, &dev_attr_in_input7);
-	device_create_file(&new_client->dev, &dev_attr_in_input8);
-	device_create_file(&new_client->dev, &dev_attr_in_min0);
-	device_create_file(&new_client->dev, &dev_attr_in_min1);
-	device_create_file(&new_client->dev, &dev_attr_in_min2);
-	device_create_file(&new_client->dev, &dev_attr_in_min3);
-	device_create_file(&new_client->dev, &dev_attr_in_min4);
-	device_create_file(&new_client->dev, &dev_attr_in_min5);
-	device_create_file(&new_client->dev, &dev_attr_in_min6);
-	device_create_file(&new_client->dev, &dev_attr_in_min7);
-	device_create_file(&new_client->dev, &dev_attr_in_max0);
-	device_create_file(&new_client->dev, &dev_attr_in_max1);
-	device_create_file(&new_client->dev, &dev_attr_in_max2);
-	device_create_file(&new_client->dev, &dev_attr_in_max3);
-	device_create_file(&new_client->dev, &dev_attr_in_max4);
-	device_create_file(&new_client->dev, &dev_attr_in_max5);
-	device_create_file(&new_client->dev, &dev_attr_in_max6);
-	device_create_file(&new_client->dev, &dev_attr_in_max7);
-	device_create_file(&new_client->dev, &dev_attr_temp_input1);
-	device_create_file(&new_client->dev, &dev_attr_temp_input2);
-	device_create_file(&new_client->dev, &dev_attr_temp_input3);
-	device_create_file(&new_client->dev, &dev_attr_temp_max1);
-	device_create_file(&new_client->dev, &dev_attr_temp_max2);
-	device_create_file(&new_client->dev, &dev_attr_temp_max3);
-	device_create_file(&new_client->dev, &dev_attr_temp_min1);
-	device_create_file(&new_client->dev, &dev_attr_temp_min2);
-	device_create_file(&new_client->dev, &dev_attr_temp_min3);
-	device_create_file(&new_client->dev, &dev_attr_sensor1);
-	device_create_file(&new_client->dev, &dev_attr_sensor2);
-	device_create_file(&new_client->dev, &dev_attr_sensor3);
-	device_create_file(&new_client->dev, &dev_attr_fan_input1);
-	device_create_file(&new_client->dev, &dev_attr_fan_input2);
-	device_create_file(&new_client->dev, &dev_attr_fan_input3);
-	device_create_file(&new_client->dev, &dev_attr_fan_min1);
-	device_create_file(&new_client->dev, &dev_attr_fan_min2);
-	device_create_file(&new_client->dev, &dev_attr_fan_min3);
-	device_create_file(&new_client->dev, &dev_attr_fan_div1);
-	device_create_file(&new_client->dev, &dev_attr_fan_div2);
-	device_create_file(&new_client->dev, &dev_attr_fan_div3);
+	device_create_file(&new_client->dev, &dev_attr_in0_input);
+	device_create_file(&new_client->dev, &dev_attr_in1_input);
+	device_create_file(&new_client->dev, &dev_attr_in2_input);
+	device_create_file(&new_client->dev, &dev_attr_in3_input);
+	device_create_file(&new_client->dev, &dev_attr_in4_input);
+	device_create_file(&new_client->dev, &dev_attr_in5_input);
+	device_create_file(&new_client->dev, &dev_attr_in6_input);
+	device_create_file(&new_client->dev, &dev_attr_in7_input);
+	device_create_file(&new_client->dev, &dev_attr_in8_input);
+	device_create_file(&new_client->dev, &dev_attr_in0_min);
+	device_create_file(&new_client->dev, &dev_attr_in1_min);
+	device_create_file(&new_client->dev, &dev_attr_in2_min);
+	device_create_file(&new_client->dev, &dev_attr_in3_min);
+	device_create_file(&new_client->dev, &dev_attr_in4_min);
+	device_create_file(&new_client->dev, &dev_attr_in5_min);
+	device_create_file(&new_client->dev, &dev_attr_in6_min);
+	device_create_file(&new_client->dev, &dev_attr_in7_min);
+	device_create_file(&new_client->dev, &dev_attr_in0_max);
+	device_create_file(&new_client->dev, &dev_attr_in1_max);
+	device_create_file(&new_client->dev, &dev_attr_in2_max);
+	device_create_file(&new_client->dev, &dev_attr_in3_max);
+	device_create_file(&new_client->dev, &dev_attr_in4_max);
+	device_create_file(&new_client->dev, &dev_attr_in5_max);
+	device_create_file(&new_client->dev, &dev_attr_in6_max);
+	device_create_file(&new_client->dev, &dev_attr_in7_max);
+	device_create_file(&new_client->dev, &dev_attr_temp1_input);
+	device_create_file(&new_client->dev, &dev_attr_temp2_input);
+	device_create_file(&new_client->dev, &dev_attr_temp3_input);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max);
+	device_create_file(&new_client->dev, &dev_attr_temp2_max);
+	device_create_file(&new_client->dev, &dev_attr_temp3_max);
+	device_create_file(&new_client->dev, &dev_attr_temp1_min);
+	device_create_file(&new_client->dev, &dev_attr_temp2_min);
+	device_create_file(&new_client->dev, &dev_attr_temp3_min);
+	device_create_file(&new_client->dev, &dev_attr_temp1_type);
+	device_create_file(&new_client->dev, &dev_attr_temp2_type);
+	device_create_file(&new_client->dev, &dev_attr_temp3_type);
+	device_create_file(&new_client->dev, &dev_attr_fan1_input);
+	device_create_file(&new_client->dev, &dev_attr_fan2_input);
+	device_create_file(&new_client->dev, &dev_attr_fan3_input);
+	device_create_file(&new_client->dev, &dev_attr_fan1_min);
+	device_create_file(&new_client->dev, &dev_attr_fan2_min);
+	device_create_file(&new_client->dev, &dev_attr_fan3_min);
+	device_create_file(&new_client->dev, &dev_attr_fan1_div);
+	device_create_file(&new_client->dev, &dev_attr_fan2_div);
+	device_create_file(&new_client->dev, &dev_attr_fan3_div);
 	device_create_file(&new_client->dev, &dev_attr_alarms);
 
 	return 0;
@@ -825,85 +748,50 @@ static int it87_write_value(struct i2c_c
 		return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-/* Called when we have found a new IT87. It should set limits, etc. */
+/* Called when we have found a new IT87. */
 static void it87_init_client(struct i2c_client *client, struct it87_data *data)
 {
-	/* Reset all except Watchdog values and last conversion values
-	   This sets fan-divs to 2, among others */
-	it87_write_value(client, IT87_REG_CONFIG, 0x80);
-	it87_write_value(client, IT87_REG_VIN_MIN(0),
-			 IN_TO_REG(IT87_INIT_IN_MIN_0));
-	it87_write_value(client, IT87_REG_VIN_MAX(0),
-			 IN_TO_REG(IT87_INIT_IN_MAX_0));
-	it87_write_value(client, IT87_REG_VIN_MIN(1),
-			 IN_TO_REG(IT87_INIT_IN_MIN_1));
-	it87_write_value(client, IT87_REG_VIN_MAX(1),
-			 IN_TO_REG(IT87_INIT_IN_MAX_1));
-	it87_write_value(client, IT87_REG_VIN_MIN(2),
-			 IN_TO_REG(IT87_INIT_IN_MIN_2));
-	it87_write_value(client, IT87_REG_VIN_MAX(2),
-			 IN_TO_REG(IT87_INIT_IN_MAX_2));
-	it87_write_value(client, IT87_REG_VIN_MIN(3),
-			 IN_TO_REG(IT87_INIT_IN_MIN_3));
-	it87_write_value(client, IT87_REG_VIN_MAX(3),
-			 IN_TO_REG(IT87_INIT_IN_MAX_3));
-	it87_write_value(client, IT87_REG_VIN_MIN(4),
-			 IN_TO_REG(IT87_INIT_IN_MIN_4));
-	it87_write_value(client, IT87_REG_VIN_MAX(4),
-			 IN_TO_REG(IT87_INIT_IN_MAX_4));
-	it87_write_value(client, IT87_REG_VIN_MIN(5),
-			 IN_TO_REG(IT87_INIT_IN_MIN_5));
-	it87_write_value(client, IT87_REG_VIN_MAX(5),
-			 IN_TO_REG(IT87_INIT_IN_MAX_5));
-	it87_write_value(client, IT87_REG_VIN_MIN(6),
-			 IN_TO_REG(IT87_INIT_IN_MIN_6));
-	it87_write_value(client, IT87_REG_VIN_MAX(6),
-			 IN_TO_REG(IT87_INIT_IN_MAX_6));
-	it87_write_value(client, IT87_REG_VIN_MIN(7),
-			 IN_TO_REG(IT87_INIT_IN_MIN_7));
-	it87_write_value(client, IT87_REG_VIN_MAX(7),
-			 IN_TO_REG(IT87_INIT_IN_MAX_7));
-	/* Note: Battery voltage does not have limit registers */
-	it87_write_value(client, IT87_REG_FAN_MIN(0),
-			 FAN_TO_REG(IT87_INIT_FAN_MIN_1, 2));
-	it87_write_value(client, IT87_REG_FAN_MIN(1),
-			 FAN_TO_REG(IT87_INIT_FAN_MIN_2, 2));
-	it87_write_value(client, IT87_REG_FAN_MIN(2),
-			 FAN_TO_REG(IT87_INIT_FAN_MIN_3, 2));
-	it87_write_value(client, IT87_REG_TEMP_HIGH(0),
-			 TEMP_TO_REG(IT87_INIT_TEMP_HIGH_1));
-	it87_write_value(client, IT87_REG_TEMP_LOW(0),
-			 TEMP_TO_REG(IT87_INIT_TEMP_LOW_1));
-	it87_write_value(client, IT87_REG_TEMP_HIGH(1),
-			 TEMP_TO_REG(IT87_INIT_TEMP_HIGH_2));
-	it87_write_value(client, IT87_REG_TEMP_LOW(1),
-			 TEMP_TO_REG(IT87_INIT_TEMP_LOW_2));
-	it87_write_value(client, IT87_REG_TEMP_HIGH(2),
-			 TEMP_TO_REG(IT87_INIT_TEMP_HIGH_3));
-	it87_write_value(client, IT87_REG_TEMP_LOW(2),
-			 TEMP_TO_REG(IT87_INIT_TEMP_LOW_3));
-
-	/* Enable voltage monitors */
-	it87_write_value(client, IT87_REG_VIN_ENABLE, 0xff);
-
-	/* Enable Temp1-Temp3 */
-	data->sensor = (it87_read_value(client, IT87_REG_TEMP_ENABLE) & 0xc0);
-	data->sensor |= temp_type & 0x3f;
-	it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor);
+	int tmp;
 
-	/* Enable fans */
-	it87_write_value(client, IT87_REG_FAN_CTRL,
-			(it87_read_value(client, IT87_REG_FAN_CTRL) & 0x8f)
-			| 0x70);
+	if (reset) {
+		/* Reset all except Watchdog values and last conversion values
+		   This sets fan-divs to 2, among others */
+		it87_write_value(client, IT87_REG_CONFIG, 0x80);
+	}
+
+	/* Check if temperature channnels are reset manually or by some reason */
+	tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE);
+	if ((tmp & 0x3f) == 0) {
+		/* Temp1,Temp3=thermistor; Temp2=thermal diode */
+		tmp = (tmp & 0xc0) | 0x2a;
+		it87_write_value(client, IT87_REG_TEMP_ENABLE, tmp);
+	}
+	data->sensor = tmp;
+
+	/* Check if voltage monitors are reset manually or by some reason */
+	tmp = it87_read_value(client, IT87_REG_VIN_ENABLE);
+	if ((tmp & 0xff) == 0) {
+		/* Enable all voltage monitors */
+		it87_write_value(client, IT87_REG_VIN_ENABLE, 0xff);
+	}
+
+	/* Check if tachometers are reset manually or by some reason */
+	tmp = it87_read_value(client, IT87_REG_FAN_CTRL);
+	if ((tmp & 0x70) == 0) {
+		/* Enable all fan tachometers */
+		tmp = (tmp & 0x8f) | 0x70;
+		it87_write_value(client, IT87_REG_FAN_CTRL, tmp);
+	}
 
 	/* Start monitoring */
 	it87_write_value(client, IT87_REG_CONFIG,
-			 (it87_read_value(client, IT87_REG_CONFIG) & 0xb7)
+			 (it87_read_value(client, IT87_REG_CONFIG) & 0x36)
 			 | (update_vbat ? 0x41 : 0x01));
 }
 
-static void it87_update_client(struct i2c_client *client)
+static struct it87_data *it87_update_device(struct device *dev)
 {
+	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
 	int i;
 
@@ -967,11 +855,15 @@ static void it87_update_client(struct i2
 			(it87_read_value(client, IT87_REG_ALARM2) << 8) |
 			(it87_read_value(client, IT87_REG_ALARM3) << 16);
 
+		data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE);
+
 		data->last_updated = jiffies;
 		data->valid = 1;
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 static int __init sm_it87_init(void)
@@ -989,8 +881,8 @@ MODULE_AUTHOR("Chris Gauthron <chrisg@0-
 MODULE_DESCRIPTION("IT8705F, IT8712F, Sis950 driver");
 MODULE_PARM(update_vbat, "i");
 MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
-MODULE_PARM(temp_type, "i");
-MODULE_PARM_DESC(temp_type, "Temperature sensor type, normally leave unset");
+MODULE_PARM(reset, "i");
+MODULE_PARM_DESC(reset, "Reset the chip's registers, default no");
 MODULE_LICENSE("GPL");
 
 module_init(sm_it87_init);
--- diff/drivers/i2c/chips/lm75.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/i2c/chips/lm75.c	2004-03-16 09:37:55.801057120 +0000
@@ -64,7 +64,7 @@ static void lm75_init_client(struct i2c_
 static int lm75_detach_client(struct i2c_client *client);
 static int lm75_read_value(struct i2c_client *client, u8 reg);
 static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value);
-static void lm75_update_client(struct i2c_client *client);
+static struct lm75_data *lm75_update_device(struct device *dev);
 
 
 /* This is the driver that will be inserted */
@@ -82,9 +82,7 @@ static int lm75_id = 0;
 #define show(value)	\
 static ssize_t show_##value(struct device *dev, char *buf)		\
 {									\
-	struct i2c_client *client = to_i2c_client(dev);			\
-	struct lm75_data *data = i2c_get_clientdata(client);		\
-	lm75_update_client(client);					\
+	struct lm75_data *data = lm75_update_device(dev);		\
 	return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value));	\
 }
 show(temp_max);
@@ -104,9 +102,9 @@ static ssize_t set_##value(struct device
 set(temp_max, LM75_REG_TEMP_OS);
 set(temp_hyst, LM75_REG_TEMP_HYST);
 
-static DEVICE_ATTR(temp_max1, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
-static DEVICE_ATTR(temp_hyst1, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst);
-static DEVICE_ATTR(temp_input1, S_IRUGO, show_temp_input, NULL);
+static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
+static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst);
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL);
 
 static int lm75_attach_adapter(struct i2c_adapter *adapter)
 {
@@ -197,9 +195,9 @@ static int lm75_detect(struct i2c_adapte
 	lm75_init_client(new_client);
 	
 	/* Register sysfs hooks */
-	device_create_file(&new_client->dev, &dev_attr_temp_max1);
-	device_create_file(&new_client->dev, &dev_attr_temp_hyst1);
-	device_create_file(&new_client->dev, &dev_attr_temp_input1);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
+	device_create_file(&new_client->dev, &dev_attr_temp1_input);
 
 	return 0;
 
@@ -250,8 +248,9 @@ static void lm75_init_client(struct i2c_
 	lm75_write_value(client, LM75_REG_CONF, 0);
 }
 
-static void lm75_update_client(struct i2c_client *client)
+static struct lm75_data *lm75_update_device(struct device *dev)
 {
+	struct i2c_client *client = to_i2c_client(dev);
 	struct lm75_data *data = i2c_get_clientdata(client);
 
 	down(&data->update_lock);
@@ -268,6 +267,8 @@ static void lm75_update_client(struct i2
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 static int __init sensors_lm75_init(void)
--- diff/drivers/i2c/chips/lm78.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/i2c/chips/lm78.c	2004-03-16 09:37:55.804056664 +0000
@@ -223,7 +223,7 @@ static int lm78_detach_client(struct i2c
 
 static int lm78_read_value(struct i2c_client *client, u8 register);
 static int lm78_write_value(struct i2c_client *client, u8 register, u8 value);
-static void lm78_update_client(struct i2c_client *client);
+static struct lm78_data *lm78_update_device(struct device *dev);
 static void lm78_init_client(struct i2c_client *client);
 
 
@@ -239,25 +239,19 @@ static struct i2c_driver lm78_driver = {
 /* 7 Voltages */
 static ssize_t show_in(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm78_data *data = i2c_get_clientdata(client);
-	lm78_update_client(client);
+	struct lm78_data *data = lm78_update_device(dev);
 	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
 }
 
 static ssize_t show_in_min(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm78_data *data = i2c_get_clientdata(client);
-	lm78_update_client(client);
+	struct lm78_data *data = lm78_update_device(dev);
 	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
 }
 
 static ssize_t show_in_max(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm78_data *data = i2c_get_clientdata(client);
-	lm78_update_client(client);
+	struct lm78_data *data = lm78_update_device(dev);
 	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
 }
 
@@ -289,7 +283,7 @@ static ssize_t							\
 {								\
 	return show_in(dev, buf, 0x##offset);			\
 }								\
-static DEVICE_ATTR(in_input##offset, S_IRUGO, 			\
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, 		\
 		show_in##offset, NULL)				\
 static ssize_t							\
 	show_in##offset##_min (struct device *dev, char *buf)   \
@@ -311,9 +305,9 @@ static ssize_t set_in##offset##_max (str
 {								\
 	return set_in_max(dev, buf, count, 0x##offset);		\
 }								\
-static DEVICE_ATTR(in_min##offset, S_IRUGO | S_IWUSR,		\
+static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,		\
 		show_in##offset##_min, set_in##offset##_min)    \
-static DEVICE_ATTR(in_max##offset, S_IRUGO | S_IWUSR,		\
+static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,		\
 		show_in##offset##_max, set_in##offset##_max)
 
 show_in_offset(0);
@@ -327,17 +321,13 @@ show_in_offset(6);
 /* Temperature */
 static ssize_t show_temp(struct device *dev, char *buf)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm78_data *data = i2c_get_clientdata(client);
-	lm78_update_client(client);
+	struct lm78_data *data = lm78_update_device(dev);
 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp));
 }
 
 static ssize_t show_temp_over(struct device *dev, char *buf)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm78_data *data = i2c_get_clientdata(client);
-	lm78_update_client(client);
+	struct lm78_data *data = lm78_update_device(dev);
 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over));
 }
 
@@ -353,9 +343,7 @@ static ssize_t set_temp_over(struct devi
 
 static ssize_t show_temp_hyst(struct device *dev, char *buf)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm78_data *data = i2c_get_clientdata(client);
-	lm78_update_client(client);
+	struct lm78_data *data = lm78_update_device(dev);
 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst));
 }
 
@@ -369,27 +357,23 @@ static ssize_t set_temp_hyst(struct devi
 	return count;
 }
 
-static DEVICE_ATTR(temp_input1, S_IRUGO, show_temp, NULL)
-static DEVICE_ATTR(temp_max1, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL)
+static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
 		show_temp_over, set_temp_over)
-static DEVICE_ATTR(temp_hyst1, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
 		show_temp_hyst, set_temp_hyst)
 
 /* 3 Fans */
 static ssize_t show_fan(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm78_data *data = i2c_get_clientdata(client);
-	lm78_update_client(client);
+	struct lm78_data *data = lm78_update_device(dev);
 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
 		DIV_FROM_REG(data->fan_div[nr])) );
 }
 
 static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm78_data *data = i2c_get_clientdata(client);
-	lm78_update_client(client);
+	struct lm78_data *data = lm78_update_device(dev);
 	return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr],
 		DIV_FROM_REG(data->fan_div[nr])) );
 }
@@ -407,9 +391,7 @@ static ssize_t set_fan_min(struct device
 
 static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm78_data *data = i2c_get_clientdata(client);
-	lm78_update_client(client);
+	struct lm78_data *data = lm78_update_device(dev);
 	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
 }
 
@@ -460,8 +442,8 @@ static ssize_t set_fan_##offset##_min (s
 {									\
 	return set_fan_min(dev, buf, count, 0x##offset - 1);		\
 }									\
-static DEVICE_ATTR(fan_input##offset, S_IRUGO, show_fan_##offset, NULL) \
-static DEVICE_ATTR(fan_min##offset, S_IRUGO | S_IWUSR,			\
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL) \
+static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
 		show_fan_##offset##_min, set_fan_##offset##_min)
 
 static ssize_t set_fan_1_div(struct device *dev, const char *buf,
@@ -481,28 +463,24 @@ show_fan_offset(2);
 show_fan_offset(3);
 
 /* Fan 3 divisor is locked in H/W */
-static DEVICE_ATTR(fan_div1, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
 		show_fan_1_div, set_fan_1_div)
-static DEVICE_ATTR(fan_div2, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
 		show_fan_2_div, set_fan_2_div)
-static DEVICE_ATTR(fan_div3, S_IRUGO, show_fan_3_div, NULL)
+static DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_3_div, NULL)
 
 /* VID */
 static ssize_t show_vid(struct device *dev, char *buf)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm78_data *data = i2c_get_clientdata(client);
-	lm78_update_client(client);
+	struct lm78_data *data = lm78_update_device(dev);
 	return sprintf(buf, "%d\n", VID_FROM_REG(data->vid));
 }
-static DEVICE_ATTR(vid, S_IRUGO, show_vid, NULL);
+static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid, NULL);
 
 /* Alarms */
 static ssize_t show_alarms(struct device *dev, char *buf)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm78_data *data = i2c_get_clientdata(client);
-	lm78_update_client(client);
+	struct lm78_data *data = lm78_update_device(dev);
 	return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms));
 }
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
@@ -657,41 +635,41 @@ int lm78_detect(struct i2c_adapter *adap
 	lm78_init_client(new_client);
 
 	/* Register sysfs hooks */
-	device_create_file(&new_client->dev, &dev_attr_in_input0);
-	device_create_file(&new_client->dev, &dev_attr_in_min0);
-	device_create_file(&new_client->dev, &dev_attr_in_max0);
-	device_create_file(&new_client->dev, &dev_attr_in_input1);
-	device_create_file(&new_client->dev, &dev_attr_in_min1);
-	device_create_file(&new_client->dev, &dev_attr_in_max1);
-	device_create_file(&new_client->dev, &dev_attr_in_input2);
-	device_create_file(&new_client->dev, &dev_attr_in_min2);
-	device_create_file(&new_client->dev, &dev_attr_in_max2);
-	device_create_file(&new_client->dev, &dev_attr_in_input3);
-	device_create_file(&new_client->dev, &dev_attr_in_min3);
-	device_create_file(&new_client->dev, &dev_attr_in_max3);
-	device_create_file(&new_client->dev, &dev_attr_in_input4);
-	device_create_file(&new_client->dev, &dev_attr_in_min4);
-	device_create_file(&new_client->dev, &dev_attr_in_max4);
-	device_create_file(&new_client->dev, &dev_attr_in_input5);
-	device_create_file(&new_client->dev, &dev_attr_in_min5);
-	device_create_file(&new_client->dev, &dev_attr_in_max5);
-	device_create_file(&new_client->dev, &dev_attr_in_input6);
-	device_create_file(&new_client->dev, &dev_attr_in_min6);
-	device_create_file(&new_client->dev, &dev_attr_in_max6);
-	device_create_file(&new_client->dev, &dev_attr_temp_input1);
-	device_create_file(&new_client->dev, &dev_attr_temp_max1);
-	device_create_file(&new_client->dev, &dev_attr_temp_hyst1);
-	device_create_file(&new_client->dev, &dev_attr_fan_input1);
-	device_create_file(&new_client->dev, &dev_attr_fan_min1);
-	device_create_file(&new_client->dev, &dev_attr_fan_div1);
-	device_create_file(&new_client->dev, &dev_attr_fan_input2);
-	device_create_file(&new_client->dev, &dev_attr_fan_min2);
-	device_create_file(&new_client->dev, &dev_attr_fan_div2);
-	device_create_file(&new_client->dev, &dev_attr_fan_input3);
-	device_create_file(&new_client->dev, &dev_attr_fan_min3);
-	device_create_file(&new_client->dev, &dev_attr_fan_div3);
+	device_create_file(&new_client->dev, &dev_attr_in0_input);
+	device_create_file(&new_client->dev, &dev_attr_in0_min);
+	device_create_file(&new_client->dev, &dev_attr_in0_max);
+	device_create_file(&new_client->dev, &dev_attr_in1_input);
+	device_create_file(&new_client->dev, &dev_attr_in1_min);
+	device_create_file(&new_client->dev, &dev_attr_in1_max);
+	device_create_file(&new_client->dev, &dev_attr_in2_input);
+	device_create_file(&new_client->dev, &dev_attr_in2_min);
+	device_create_file(&new_client->dev, &dev_attr_in2_max);
+	device_create_file(&new_client->dev, &dev_attr_in3_input);
+	device_create_file(&new_client->dev, &dev_attr_in3_min);
+	device_create_file(&new_client->dev, &dev_attr_in3_max);
+	device_create_file(&new_client->dev, &dev_attr_in4_input);
+	device_create_file(&new_client->dev, &dev_attr_in4_min);
+	device_create_file(&new_client->dev, &dev_attr_in4_max);
+	device_create_file(&new_client->dev, &dev_attr_in5_input);
+	device_create_file(&new_client->dev, &dev_attr_in5_min);
+	device_create_file(&new_client->dev, &dev_attr_in5_max);
+	device_create_file(&new_client->dev, &dev_attr_in6_input);
+	device_create_file(&new_client->dev, &dev_attr_in6_min);
+	device_create_file(&new_client->dev, &dev_attr_in6_max);
+	device_create_file(&new_client->dev, &dev_attr_temp1_input);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
+	device_create_file(&new_client->dev, &dev_attr_fan1_input);
+	device_create_file(&new_client->dev, &dev_attr_fan1_min);
+	device_create_file(&new_client->dev, &dev_attr_fan1_div);
+	device_create_file(&new_client->dev, &dev_attr_fan2_input);
+	device_create_file(&new_client->dev, &dev_attr_fan2_min);
+	device_create_file(&new_client->dev, &dev_attr_fan2_div);
+	device_create_file(&new_client->dev, &dev_attr_fan3_input);
+	device_create_file(&new_client->dev, &dev_attr_fan3_min);
+	device_create_file(&new_client->dev, &dev_attr_fan3_div);
 	device_create_file(&new_client->dev, &dev_attr_alarms);
-	device_create_file(&new_client->dev, &dev_attr_vid);
+	device_create_file(&new_client->dev, &dev_attr_in0_ref);
 
 	return 0;
 
@@ -829,8 +807,9 @@ static void lm78_init_client(struct i2c_
 
 }
 
-static void lm78_update_client(struct i2c_client *client)
+static struct lm78_data *lm78_update_device(struct device *dev)
 {
+	struct i2c_client *client = to_i2c_client(dev);
 	struct lm78_data *data = i2c_get_clientdata(client);
 	int i;
 
@@ -879,6 +858,8 @@ static void lm78_update_client(struct i2
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 static int __init sm_lm78_init(void)
--- diff/drivers/i2c/chips/lm83.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/i2c/chips/lm83.c	2004-03-16 09:37:55.805056512 +0000
@@ -118,7 +118,7 @@ static const u8 LM83_REG_W_HIGH[] = {
 static int lm83_attach_adapter(struct i2c_adapter *adapter);
 static int lm83_detect(struct i2c_adapter *adapter, int address, int kind);
 static int lm83_detach_client(struct i2c_client *client);
-static void lm83_update_client(struct i2c_client *client);
+static struct lm83_data *lm83_update_device(struct device *dev);
 
 /*
  * Driver data (common to all clients)
@@ -162,9 +162,7 @@ static int lm83_id = 0;
 #define show_temp(suffix, value) \
 static ssize_t show_temp_##suffix(struct device *dev, char *buf) \
 { \
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct lm83_data *data = i2c_get_clientdata(client); \
-	lm83_update_client(client); \
+	struct lm83_data *data = lm83_update_device(dev); \
 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \
 }
 show_temp(input1, temp_input[0]);
@@ -195,23 +193,21 @@ set_temp(crit, temp_crit, LM83_REG_W_TCR
 
 static ssize_t show_alarms(struct device *dev, char *buf)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm83_data *data = i2c_get_clientdata(client);
-	lm83_update_client(client);
+	struct lm83_data *data = lm83_update_device(dev);
 	return sprintf(buf, "%d\n", data->alarms);
 }
 
-static DEVICE_ATTR(temp_input1, S_IRUGO, show_temp_input1, NULL);
-static DEVICE_ATTR(temp_input2, S_IRUGO, show_temp_input2, NULL);
-static DEVICE_ATTR(temp_input3, S_IRUGO, show_temp_input3, NULL);
-static DEVICE_ATTR(temp_input4, S_IRUGO, show_temp_input4, NULL);
-static DEVICE_ATTR(temp_max1, S_IWUSR | S_IRUGO, show_temp_high1,
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL);
+static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL);
+static DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_input3, NULL);
+static DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_input4, NULL);
+static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_high1,
     set_temp_high1);
-static DEVICE_ATTR(temp_max2, S_IWUSR | S_IRUGO, show_temp_high2,
+static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2,
     set_temp_high2);
-static DEVICE_ATTR(temp_max3, S_IWUSR | S_IRUGO, show_temp_high3,
+static DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp_high3,
     set_temp_high3);
-static DEVICE_ATTR(temp_max4, S_IWUSR | S_IRUGO, show_temp_high4,
+static DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp_high4,
     set_temp_high4);
 static DEVICE_ATTR(temp_crit, S_IWUSR | S_IRUGO, show_temp_crit,
     set_temp_crit);
@@ -320,14 +316,14 @@ static int lm83_detect(struct i2c_adapte
 	 */
 
 	/* Register sysfs hooks */
-	device_create_file(&new_client->dev, &dev_attr_temp_input1);
-	device_create_file(&new_client->dev, &dev_attr_temp_input2);
-	device_create_file(&new_client->dev, &dev_attr_temp_input3);
-	device_create_file(&new_client->dev, &dev_attr_temp_input4);
-	device_create_file(&new_client->dev, &dev_attr_temp_max1);
-	device_create_file(&new_client->dev, &dev_attr_temp_max2);
-	device_create_file(&new_client->dev, &dev_attr_temp_max3);
-	device_create_file(&new_client->dev, &dev_attr_temp_max4);
+	device_create_file(&new_client->dev, &dev_attr_temp1_input);
+	device_create_file(&new_client->dev, &dev_attr_temp2_input);
+	device_create_file(&new_client->dev, &dev_attr_temp3_input);
+	device_create_file(&new_client->dev, &dev_attr_temp4_input);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max);
+	device_create_file(&new_client->dev, &dev_attr_temp2_max);
+	device_create_file(&new_client->dev, &dev_attr_temp3_max);
+	device_create_file(&new_client->dev, &dev_attr_temp4_max);
 	device_create_file(&new_client->dev, &dev_attr_temp_crit);
 	device_create_file(&new_client->dev, &dev_attr_alarms);
 
@@ -353,8 +349,9 @@ static int lm83_detach_client(struct i2c
 	return 0;
 }
 
-static void lm83_update_client(struct i2c_client *client)
+static struct lm83_data *lm83_update_device(struct device *dev)
 {
+	struct i2c_client *client = to_i2c_client(dev);
 	struct lm83_data *data = i2c_get_clientdata(client);
 
 	down(&data->update_lock);
@@ -385,6 +382,8 @@ static void lm83_update_client(struct i2
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 static int __init sensors_lm83_init(void)
--- diff/drivers/i2c/chips/lm85.c	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/i2c/chips/lm85.c	2004-03-16 09:37:55.829052864 +0000
@@ -397,7 +397,7 @@ static int lm85_detach_client(struct i2c
 
 static int lm85_read_value(struct i2c_client *client, u8 register);
 static int lm85_write_value(struct i2c_client *client, u8 register, int value);
-static void lm85_update_client(struct i2c_client *client);
+static struct lm85_data *lm85_update_device(struct device *dev);
 static void lm85_init_client(struct i2c_client *client);
 
 
@@ -417,18 +417,12 @@ static int lm85_id = 0;
 /* 4 Fans */
 static ssize_t show_fan(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm85_data *data = i2c_get_clientdata(client);
-
-	lm85_update_client(client);
+	struct lm85_data *data = lm85_update_device(dev);
 	return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr]) );
 }
 static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm85_data *data = i2c_get_clientdata(client);
-
-	lm85_update_client(client);
+	struct lm85_data *data = lm85_update_device(dev);
 	return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr]) );
 }
 static ssize_t set_fan_min(struct device *dev, const char *buf, 
@@ -460,8 +454,8 @@ static ssize_t set_fan_##offset##_min (s
 {									\
 	return set_fan_min(dev, buf, count, 0x##offset - 1);		\
 }									\
-static DEVICE_ATTR(fan_input##offset, S_IRUGO, show_fan_##offset, NULL) \
-static DEVICE_ATTR(fan_min##offset, S_IRUGO | S_IWUSR, 			\
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL) \
+static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, 		\
 		show_fan_##offset##_min, set_fan_##offset##_min)
 
 show_fan_offset(1);
@@ -473,21 +467,15 @@ show_fan_offset(4);
 
 static ssize_t show_vid_reg(struct device *dev, char *buf)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm85_data *data = i2c_get_clientdata(client);
-
-	lm85_update_client(client);
+	struct lm85_data *data = lm85_update_device(dev);
 	return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
 }
 
-static DEVICE_ATTR(vid, S_IRUGO, show_vid_reg, NULL)
+static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL)
 
 static ssize_t show_vrm_reg(struct device *dev, char *buf)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm85_data *data = i2c_get_clientdata(client);
-
-	lm85_update_client(client);
+	struct lm85_data *data = lm85_update_device(dev);
 	return sprintf(buf, "%ld\n", (long) data->vrm);
 }
 
@@ -506,10 +494,7 @@ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUS
 
 static ssize_t show_alarms_reg(struct device *dev, char *buf)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm85_data *data = i2c_get_clientdata(client);
-
-	lm85_update_client(client);
+	struct lm85_data *data = lm85_update_device(dev);
 	return sprintf(buf, "%ld\n", (long) ALARMS_FROM_REG(data->alarms));
 }
 
@@ -519,10 +504,7 @@ static DEVICE_ATTR(alarms, S_IRUGO, show
 
 static ssize_t show_pwm(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm85_data *data = i2c_get_clientdata(client);
-
-	lm85_update_client(client);
+	struct lm85_data *data = lm85_update_device(dev);
 	return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm[nr]) );
 }
 static ssize_t set_pwm(struct device *dev, const char *buf, 
@@ -541,11 +523,9 @@ static ssize_t set_pwm(struct device *de
 }
 static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm85_data *data = i2c_get_clientdata(client);
+	struct lm85_data *data = lm85_update_device(dev);
 	int	pwm_zone;
 
-	lm85_update_client(client);
 	pwm_zone = ZONE_FROM_REG(data->autofan[nr].config);
 	return sprintf(buf,"%d\n", (pwm_zone != 0 && pwm_zone != -1) );
 }
@@ -564,9 +544,9 @@ static ssize_t show_pwm_enable##offset (
 {									\
 	return show_pwm_enable(dev, buf, 0x##offset - 1);			\
 }									\
-static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, 			\
+static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, 			\
 		show_pwm_##offset, set_pwm_##offset)			\
-static DEVICE_ATTR(pwm_enable##offset, S_IRUGO, show_pwm_enable##offset, NULL)
+static DEVICE_ATTR(fan##offset##_pwm_enable, S_IRUGO, show_pwm_enable##offset, NULL)
 
 show_pwm_reg(1);
 show_pwm_reg(2);
@@ -576,18 +556,12 @@ show_pwm_reg(3);
 
 static ssize_t show_in(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm85_data *data = i2c_get_clientdata(client);
-
-	lm85_update_client(client);
+	struct lm85_data *data = lm85_update_device(dev);
 	return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in[nr]) );
 }
 static ssize_t show_in_min(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm85_data *data = i2c_get_clientdata(client);
-
-	lm85_update_client(client);
+	struct lm85_data *data = lm85_update_device(dev);
 	return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr]) );
 }
 static ssize_t set_in_min(struct device *dev, const char *buf, 
@@ -606,10 +580,7 @@ static ssize_t set_in_min(struct device 
 }
 static ssize_t show_in_max(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm85_data *data = i2c_get_clientdata(client);
-
-	lm85_update_client(client);
+	struct lm85_data *data = lm85_update_device(dev);
 	return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr]) );
 }
 static ssize_t set_in_max(struct device *dev, const char *buf, 
@@ -649,10 +620,10 @@ static ssize_t set_in_##offset##_max (st
 {									\
 	return set_in_max(dev, buf, count, 0x##offset);			\
 }									\
-static DEVICE_ATTR(in_input##offset, S_IRUGO, show_in_##offset, NULL)	\
-static DEVICE_ATTR(in_min##offset, S_IRUGO | S_IWUSR, 			\
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in_##offset, NULL)	\
+static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, 		\
 		show_in_##offset##_min, set_in_##offset##_min)		\
-static DEVICE_ATTR(in_max##offset, S_IRUGO | S_IWUSR, 			\
+static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, 		\
 		show_in_##offset##_max, set_in_##offset##_max)
 
 show_in_reg(0);
@@ -665,18 +636,12 @@ show_in_reg(4);
 
 static ssize_t show_temp(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm85_data *data = i2c_get_clientdata(client);
-
-	lm85_update_client(client);
+	struct lm85_data *data = lm85_update_device(dev);
 	return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp[nr]) );
 }
 static ssize_t show_temp_min(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm85_data *data = i2c_get_clientdata(client);
-
-	lm85_update_client(client);
+	struct lm85_data *data = lm85_update_device(dev);
 	return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr]) );
 }
 static ssize_t set_temp_min(struct device *dev, const char *buf, 
@@ -695,10 +660,7 @@ static ssize_t set_temp_min(struct devic
 }
 static ssize_t show_temp_max(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm85_data *data = i2c_get_clientdata(client);
-
-	lm85_update_client(client);
+	struct lm85_data *data = lm85_update_device(dev);
 	return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr]) );
 }
 static ssize_t set_temp_max(struct device *dev, const char *buf, 
@@ -738,10 +700,10 @@ static ssize_t set_temp_##offset##_max (
 {									\
 	return set_temp_max(dev, buf, count, 0x##offset - 1);		\
 }									\
-static DEVICE_ATTR(temp_input##offset, S_IRUGO, show_temp_##offset, NULL)	\
-static DEVICE_ATTR(temp_min##offset, S_IRUGO | S_IWUSR, 		\
+static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL)	\
+static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, 		\
 		show_temp_##offset##_min, set_temp_##offset##_min)	\
-static DEVICE_ATTR(temp_max##offset, S_IRUGO | S_IWUSR, 		\
+static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, 		\
 		show_temp_##offset##_max, set_temp_##offset##_max)
 
 show_temp_reg(1);
@@ -886,46 +848,46 @@ int lm85_detect(struct i2c_adapter *adap
 	lm85_init_client(new_client);
 
 	/* Register sysfs hooks */
-	device_create_file(&new_client->dev, &dev_attr_fan_input1);
-	device_create_file(&new_client->dev, &dev_attr_fan_input2);
-	device_create_file(&new_client->dev, &dev_attr_fan_input3);
-	device_create_file(&new_client->dev, &dev_attr_fan_input4);
-	device_create_file(&new_client->dev, &dev_attr_fan_min1);
-	device_create_file(&new_client->dev, &dev_attr_fan_min2);
-	device_create_file(&new_client->dev, &dev_attr_fan_min3);
-	device_create_file(&new_client->dev, &dev_attr_fan_min4);
-	device_create_file(&new_client->dev, &dev_attr_pwm1);
-	device_create_file(&new_client->dev, &dev_attr_pwm2);
-	device_create_file(&new_client->dev, &dev_attr_pwm3);
-	device_create_file(&new_client->dev, &dev_attr_pwm_enable1);
-	device_create_file(&new_client->dev, &dev_attr_pwm_enable2);
-	device_create_file(&new_client->dev, &dev_attr_pwm_enable3);
-	device_create_file(&new_client->dev, &dev_attr_in_input0);
-	device_create_file(&new_client->dev, &dev_attr_in_input1);
-	device_create_file(&new_client->dev, &dev_attr_in_input2);
-	device_create_file(&new_client->dev, &dev_attr_in_input3);
-	device_create_file(&new_client->dev, &dev_attr_in_input4);
-	device_create_file(&new_client->dev, &dev_attr_in_min0);
-	device_create_file(&new_client->dev, &dev_attr_in_min1);
-	device_create_file(&new_client->dev, &dev_attr_in_min2);
-	device_create_file(&new_client->dev, &dev_attr_in_min3);
-	device_create_file(&new_client->dev, &dev_attr_in_min4);
-	device_create_file(&new_client->dev, &dev_attr_in_max0);
-	device_create_file(&new_client->dev, &dev_attr_in_max1);
-	device_create_file(&new_client->dev, &dev_attr_in_max2);
-	device_create_file(&new_client->dev, &dev_attr_in_max3);
-	device_create_file(&new_client->dev, &dev_attr_in_max4);
-	device_create_file(&new_client->dev, &dev_attr_temp_input1);
-	device_create_file(&new_client->dev, &dev_attr_temp_input2);
-	device_create_file(&new_client->dev, &dev_attr_temp_input3);
-	device_create_file(&new_client->dev, &dev_attr_temp_min1);
-	device_create_file(&new_client->dev, &dev_attr_temp_min2);
-	device_create_file(&new_client->dev, &dev_attr_temp_min3);
-	device_create_file(&new_client->dev, &dev_attr_temp_max1);
-	device_create_file(&new_client->dev, &dev_attr_temp_max2);
-	device_create_file(&new_client->dev, &dev_attr_temp_max3);
+	device_create_file(&new_client->dev, &dev_attr_fan1_input);
+	device_create_file(&new_client->dev, &dev_attr_fan2_input);
+	device_create_file(&new_client->dev, &dev_attr_fan3_input);
+	device_create_file(&new_client->dev, &dev_attr_fan4_input);
+	device_create_file(&new_client->dev, &dev_attr_fan1_min);
+	device_create_file(&new_client->dev, &dev_attr_fan2_min);
+	device_create_file(&new_client->dev, &dev_attr_fan3_min);
+	device_create_file(&new_client->dev, &dev_attr_fan4_min);
+	device_create_file(&new_client->dev, &dev_attr_fan1_pwm);
+	device_create_file(&new_client->dev, &dev_attr_fan2_pwm);
+	device_create_file(&new_client->dev, &dev_attr_fan3_pwm);
+	device_create_file(&new_client->dev, &dev_attr_fan1_pwm_enable);
+	device_create_file(&new_client->dev, &dev_attr_fan2_pwm_enable);
+	device_create_file(&new_client->dev, &dev_attr_fan3_pwm_enable);
+	device_create_file(&new_client->dev, &dev_attr_in0_input);
+	device_create_file(&new_client->dev, &dev_attr_in1_input);
+	device_create_file(&new_client->dev, &dev_attr_in2_input);
+	device_create_file(&new_client->dev, &dev_attr_in3_input);
+	device_create_file(&new_client->dev, &dev_attr_in4_input);
+	device_create_file(&new_client->dev, &dev_attr_in0_min);
+	device_create_file(&new_client->dev, &dev_attr_in1_min);
+	device_create_file(&new_client->dev, &dev_attr_in2_min);
+	device_create_file(&new_client->dev, &dev_attr_in3_min);
+	device_create_file(&new_client->dev, &dev_attr_in4_min);
+	device_create_file(&new_client->dev, &dev_attr_in0_max);
+	device_create_file(&new_client->dev, &dev_attr_in1_max);
+	device_create_file(&new_client->dev, &dev_attr_in2_max);
+	device_create_file(&new_client->dev, &dev_attr_in3_max);
+	device_create_file(&new_client->dev, &dev_attr_in4_max);
+	device_create_file(&new_client->dev, &dev_attr_temp1_input);
+	device_create_file(&new_client->dev, &dev_attr_temp2_input);
+	device_create_file(&new_client->dev, &dev_attr_temp3_input);
+	device_create_file(&new_client->dev, &dev_attr_temp1_min);
+	device_create_file(&new_client->dev, &dev_attr_temp2_min);
+	device_create_file(&new_client->dev, &dev_attr_temp3_min);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max);
+	device_create_file(&new_client->dev, &dev_attr_temp2_max);
+	device_create_file(&new_client->dev, &dev_attr_temp3_max);
 	device_create_file(&new_client->dev, &dev_attr_vrm);
-	device_create_file(&new_client->dev, &dev_attr_vid);
+	device_create_file(&new_client->dev, &dev_attr_in0_ref);
 	device_create_file(&new_client->dev, &dev_attr_alarms);
 
 	return 0;
@@ -1047,8 +1009,9 @@ void lm85_init_client(struct i2c_client 
 	lm85_write_value(client, LM85_REG_CONFIG, value);
 }
 
-void lm85_update_client(struct i2c_client *client)
+static struct lm85_data *lm85_update_device(struct device *dev)
 {
+	struct i2c_client *client = to_i2c_client(dev);
 	struct lm85_data *data = i2c_get_clientdata(client);
 	int i;
 
@@ -1189,6 +1152,8 @@ void lm85_update_client(struct i2c_clien
 	data->valid = 1;
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 
--- diff/drivers/i2c/chips/lm90.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/i2c/chips/lm90.c	2004-03-16 09:37:55.838051496 +0000
@@ -126,7 +126,7 @@ static int lm90_detect(struct i2c_adapte
 	int kind);
 static void lm90_init_client(struct i2c_client *client);
 static int lm90_detach_client(struct i2c_client *client);
-static void lm90_update_client(struct i2c_client *client);
+static struct lm90_data *lm90_update_device(struct device *dev);
 
 /*
  * Driver data (common to all clients)
@@ -171,9 +171,7 @@ static int lm90_id = 0;
 #define show_temp(value, converter) \
 static ssize_t show_##value(struct device *dev, char *buf) \
 { \
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct lm90_data *data = i2c_get_clientdata(client); \
-	lm90_update_client(client); \
+	struct lm90_data *data = lm90_update_device(dev); \
 	return sprintf(buf, "%d\n", converter(data->value)); \
 }
 show_temp(temp_input1, TEMP1_FROM_REG);
@@ -216,9 +214,7 @@ set_temp1(temp_crit2, LM90_REG_W_REMOTE_
 #define show_temp_hyst(value, basereg) \
 static ssize_t show_##value(struct device *dev, char *buf) \
 { \
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct lm90_data *data = i2c_get_clientdata(client); \
-	lm90_update_client(client); \
+	struct lm90_data *data = lm90_update_device(dev); \
 	return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->basereg) \
 		       - HYST_FROM_REG(data->temp_hyst)); \
 }
@@ -239,29 +235,27 @@ static ssize_t set_temp_hyst1(struct dev
 
 static ssize_t show_alarms(struct device *dev, char *buf)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm90_data *data = i2c_get_clientdata(client);
-	lm90_update_client(client);
+	struct lm90_data *data = lm90_update_device(dev);
 	return sprintf(buf, "%d\n", data->alarms);
 }
 
-static DEVICE_ATTR(temp_input1, S_IRUGO, show_temp_input1, NULL);
-static DEVICE_ATTR(temp_input2, S_IRUGO, show_temp_input2, NULL);
-static DEVICE_ATTR(temp_min1, S_IWUSR | S_IRUGO, show_temp_low1,
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL);
+static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL);
+static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_low1,
 	set_temp_low1);
-static DEVICE_ATTR(temp_min2, S_IWUSR | S_IRUGO, show_temp_low2,
+static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_low2,
 	set_temp_low2);
-static DEVICE_ATTR(temp_max1, S_IWUSR | S_IRUGO, show_temp_high1,
+static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_high1,
 	set_temp_high1);
-static DEVICE_ATTR(temp_max2, S_IWUSR | S_IRUGO, show_temp_high2,
+static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2,
 	set_temp_high2);
-static DEVICE_ATTR(temp_crit1, S_IWUSR | S_IRUGO, show_temp_crit1,
+static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_crit1,
 	set_temp_crit1);
-static DEVICE_ATTR(temp_crit2, S_IWUSR | S_IRUGO, show_temp_crit2,
+static DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit2,
 	set_temp_crit2);
-static DEVICE_ATTR(temp_hyst1, S_IWUSR | S_IRUGO, show_temp_hyst1,
+static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst1,
 	set_temp_hyst1);
-static DEVICE_ATTR(temp_hyst2, S_IRUGO, show_temp_hyst2, NULL);
+static DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_hyst2, NULL);
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 
 /*
@@ -381,16 +375,16 @@ static int lm90_detect(struct i2c_adapte
 	lm90_init_client(new_client);
 
 	/* Register sysfs hooks */
-	device_create_file(&new_client->dev, &dev_attr_temp_input1);
-	device_create_file(&new_client->dev, &dev_attr_temp_input2);
-	device_create_file(&new_client->dev, &dev_attr_temp_min1);
-	device_create_file(&new_client->dev, &dev_attr_temp_min2);
-	device_create_file(&new_client->dev, &dev_attr_temp_max1);
-	device_create_file(&new_client->dev, &dev_attr_temp_max2);
-	device_create_file(&new_client->dev, &dev_attr_temp_crit1);
-	device_create_file(&new_client->dev, &dev_attr_temp_crit2);
-	device_create_file(&new_client->dev, &dev_attr_temp_hyst1);
-	device_create_file(&new_client->dev, &dev_attr_temp_hyst2);
+	device_create_file(&new_client->dev, &dev_attr_temp1_input);
+	device_create_file(&new_client->dev, &dev_attr_temp2_input);
+	device_create_file(&new_client->dev, &dev_attr_temp1_min);
+	device_create_file(&new_client->dev, &dev_attr_temp2_min);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max);
+	device_create_file(&new_client->dev, &dev_attr_temp2_max);
+	device_create_file(&new_client->dev, &dev_attr_temp1_crit);
+	device_create_file(&new_client->dev, &dev_attr_temp2_crit);
+	device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
+	device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst);
 	device_create_file(&new_client->dev, &dev_attr_alarms);
 
 	return 0;
@@ -430,8 +424,9 @@ static int lm90_detach_client(struct i2c
 	return 0;
 }
 
-static void lm90_update_client(struct i2c_client *client)
+static struct lm90_data *lm90_update_device(struct device *dev)
 {
+	struct i2c_client *client = to_i2c_client(dev);
 	struct lm90_data *data = i2c_get_clientdata(client);
 
 	down(&data->update_lock);
@@ -505,6 +500,8 @@ static void lm90_update_client(struct i2
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 static int __init sensors_lm90_init(void)
--- diff/drivers/i2c/chips/via686a.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/i2c/chips/via686a.c	2004-03-16 09:37:55.841051040 +0000
@@ -409,30 +409,24 @@ static inline void via686a_write_value(s
 	outb_p(value, client->addr + reg);
 }
 
-static void via686a_update_client(struct i2c_client *client);
+static struct via686a_data *via686a_update_device(struct device *dev);
 static void via686a_init_client(struct i2c_client *client);
 
 /* following are the sysfs callback functions */
 
 /* 7 voltage sensors */
 static ssize_t show_in(struct device *dev, char *buf, int nr) {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct via686a_data *data = i2c_get_clientdata(client);
-	via686a_update_client(client);
+	struct via686a_data *data = via686a_update_device(dev);
 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr)*10 );
 }
 
 static ssize_t show_in_min(struct device *dev, char *buf, int nr) {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct via686a_data *data = i2c_get_clientdata(client);
-	via686a_update_client(client);
+	struct via686a_data *data = via686a_update_device(dev);
 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr)*10 );
 }
 
 static ssize_t show_in_max(struct device *dev, char *buf, int nr) {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct via686a_data *data = i2c_get_clientdata(client);
-	via686a_update_client(client);
+	struct via686a_data *data = via686a_update_device(dev);
 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr)*10 );
 }
 
@@ -482,10 +476,10 @@ static ssize_t set_in##offset##_max (str
 {								\
 	return set_in_max(dev, buf, count, 0x##offset);		\
 }								\
-static DEVICE_ATTR(in_input##offset, S_IRUGO, show_in##offset, NULL) 	\
-static DEVICE_ATTR(in_min##offset, S_IRUGO | S_IWUSR, 		\
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL) 	\
+static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, 	\
 		show_in##offset##_min, set_in##offset##_min)	\
-static DEVICE_ATTR(in_max##offset, S_IRUGO | S_IWUSR, 		\
+static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, 	\
 		show_in##offset##_max, set_in##offset##_max)
 
 show_in_offset(0);
@@ -496,21 +490,15 @@ show_in_offset(4);
 
 /* 3 temperatures */
 static ssize_t show_temp(struct device *dev, char *buf, int nr) {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct via686a_data *data = i2c_get_clientdata(client);
-	via686a_update_client(client);
+	struct via686a_data *data = via686a_update_device(dev);
 	return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr])*100 );
 }
 static ssize_t show_temp_over(struct device *dev, char *buf, int nr) {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct via686a_data *data = i2c_get_clientdata(client);
-	via686a_update_client(client);
+	struct via686a_data *data = via686a_update_device(dev);
 	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr])*100);
 }
 static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct via686a_data *data = i2c_get_clientdata(client);
-	via686a_update_client(client);
+	struct via686a_data *data = via686a_update_device(dev);
 	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr])*100);
 }
 static ssize_t set_temp_over(struct device *dev, const char *buf, 
@@ -556,10 +544,10 @@ static ssize_t set_temp_##offset##_hyst 
 {									\
 	return set_temp_hyst(dev, buf, count, 0x##offset - 1);		\
 }									\
-static DEVICE_ATTR(temp_input##offset, S_IRUGO, show_temp_##offset, NULL) \
-static DEVICE_ATTR(temp_max##offset, S_IRUGO | S_IWUSR, 		\
+static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL) \
+static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, 		\
 		show_temp_##offset##_over, set_temp_##offset##_over) 	\
-static DEVICE_ATTR(temp_hyst##offset, S_IRUGO | S_IWUSR, 		\
+static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, 		\
 		show_temp_##offset##_hyst, set_temp_##offset##_hyst)	
 
 show_temp_offset(1);
@@ -568,23 +556,17 @@ show_temp_offset(3);
 
 /* 2 Fans */
 static ssize_t show_fan(struct device *dev, char *buf, int nr) {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct via686a_data *data = i2c_get_clientdata(client);
-	via686a_update_client(client);
+	struct via686a_data *data = via686a_update_device(dev);
 	return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], 
 				DIV_FROM_REG(data->fan_div[nr])) );
 }
 static ssize_t show_fan_min(struct device *dev, char *buf, int nr) {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct via686a_data *data = i2c_get_clientdata(client);
-	via686a_update_client(client);
+	struct via686a_data *data = via686a_update_device(dev);
 	return sprintf(buf,"%d\n",
 		FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) );
 }
 static ssize_t show_fan_div(struct device *dev, char *buf, int nr) {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct via686a_data *data = i2c_get_clientdata(client);
-	via686a_update_client(client);
+	struct via686a_data *data = via686a_update_device(dev);
 	return sprintf(buf,"%d\n", DIV_FROM_REG(data->fan_div[nr]) );
 }
 static ssize_t set_fan_min(struct device *dev, const char *buf, 
@@ -631,10 +613,10 @@ static ssize_t set_fan_##offset##_div (s
 {									\
 	return set_fan_div(dev, buf, count, 0x##offset - 1);		\
 }									\
-static DEVICE_ATTR(fan_input##offset, S_IRUGO, show_fan_##offset, NULL) \
-static DEVICE_ATTR(fan_min##offset, S_IRUGO | S_IWUSR, 			\
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL) \
+static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, 		\
 		show_fan_##offset##_min, set_fan_##offset##_min) 	\
-static DEVICE_ATTR(fan_div##offset, S_IRUGO | S_IWUSR, 			\
+static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, 		\
 		show_fan_##offset##_div, set_fan_##offset##_div)
 
 show_fan_offset(1);
@@ -642,9 +624,7 @@ show_fan_offset(2);
 
 /* Alarms */
 static ssize_t show_alarms(struct device *dev, char *buf) {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct via686a_data *data = i2c_get_clientdata(client);
-	via686a_update_client(client);
+	struct via686a_data *data = via686a_update_device(dev);
 	return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms));
 }
 static DEVICE_ATTR(alarms, S_IRUGO | S_IWUSR, show_alarms, NULL);
@@ -653,7 +633,7 @@ static DEVICE_ATTR(alarms, S_IRUGO | S_I
    smbus_driver and isa_driver, and clients could be of either kind */
 static struct i2c_driver via686a_driver = {
 	.owner		= THIS_MODULE,
-	.name		= "VIA686A",
+	.name		= "via686a",
 	.id		= I2C_DRIVERID_VIA686A,
 	.flags		= I2C_DF_NOTIFY,
 	.attach_adapter	= via686a_attach_adapter,
@@ -742,36 +722,36 @@ static int via686a_detect(struct i2c_ada
 	via686a_init_client(new_client);
 
 	/* Register sysfs hooks */
-	device_create_file(&new_client->dev, &dev_attr_in_input0);
-	device_create_file(&new_client->dev, &dev_attr_in_input1);
-	device_create_file(&new_client->dev, &dev_attr_in_input2);
-	device_create_file(&new_client->dev, &dev_attr_in_input3);
-	device_create_file(&new_client->dev, &dev_attr_in_input4);
-	device_create_file(&new_client->dev, &dev_attr_in_min0);
-	device_create_file(&new_client->dev, &dev_attr_in_min1);
-	device_create_file(&new_client->dev, &dev_attr_in_min2);
-	device_create_file(&new_client->dev, &dev_attr_in_min3);
-	device_create_file(&new_client->dev, &dev_attr_in_min4);
-	device_create_file(&new_client->dev, &dev_attr_in_max0);
-	device_create_file(&new_client->dev, &dev_attr_in_max1);
-	device_create_file(&new_client->dev, &dev_attr_in_max2);
-	device_create_file(&new_client->dev, &dev_attr_in_max3);
-	device_create_file(&new_client->dev, &dev_attr_in_max4);
-	device_create_file(&new_client->dev, &dev_attr_temp_input1);
-	device_create_file(&new_client->dev, &dev_attr_temp_input2);
-	device_create_file(&new_client->dev, &dev_attr_temp_input3);
-	device_create_file(&new_client->dev, &dev_attr_temp_max1);
-	device_create_file(&new_client->dev, &dev_attr_temp_max2);
-	device_create_file(&new_client->dev, &dev_attr_temp_max3);
-	device_create_file(&new_client->dev, &dev_attr_temp_hyst1);
-	device_create_file(&new_client->dev, &dev_attr_temp_hyst2);
-	device_create_file(&new_client->dev, &dev_attr_temp_hyst3);
-	device_create_file(&new_client->dev, &dev_attr_fan_input1);
-	device_create_file(&new_client->dev, &dev_attr_fan_input2);
-	device_create_file(&new_client->dev, &dev_attr_fan_min1);
-	device_create_file(&new_client->dev, &dev_attr_fan_min2);
-	device_create_file(&new_client->dev, &dev_attr_fan_div1);
-	device_create_file(&new_client->dev, &dev_attr_fan_div2);
+	device_create_file(&new_client->dev, &dev_attr_in0_input);
+	device_create_file(&new_client->dev, &dev_attr_in1_input);
+	device_create_file(&new_client->dev, &dev_attr_in2_input);
+	device_create_file(&new_client->dev, &dev_attr_in3_input);
+	device_create_file(&new_client->dev, &dev_attr_in4_input);
+	device_create_file(&new_client->dev, &dev_attr_in0_min);
+	device_create_file(&new_client->dev, &dev_attr_in1_min);
+	device_create_file(&new_client->dev, &dev_attr_in2_min);
+	device_create_file(&new_client->dev, &dev_attr_in3_min);
+	device_create_file(&new_client->dev, &dev_attr_in4_min);
+	device_create_file(&new_client->dev, &dev_attr_in0_max);
+	device_create_file(&new_client->dev, &dev_attr_in1_max);
+	device_create_file(&new_client->dev, &dev_attr_in2_max);
+	device_create_file(&new_client->dev, &dev_attr_in3_max);
+	device_create_file(&new_client->dev, &dev_attr_in4_max);
+	device_create_file(&new_client->dev, &dev_attr_temp1_input);
+	device_create_file(&new_client->dev, &dev_attr_temp2_input);
+	device_create_file(&new_client->dev, &dev_attr_temp3_input);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max);
+	device_create_file(&new_client->dev, &dev_attr_temp2_max);
+	device_create_file(&new_client->dev, &dev_attr_temp3_max);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
+	device_create_file(&new_client->dev, &dev_attr_temp2_max_hyst);
+	device_create_file(&new_client->dev, &dev_attr_temp3_max_hyst);
+	device_create_file(&new_client->dev, &dev_attr_fan1_input);
+	device_create_file(&new_client->dev, &dev_attr_fan2_input);
+	device_create_file(&new_client->dev, &dev_attr_fan1_min);
+	device_create_file(&new_client->dev, &dev_attr_fan2_min);
+	device_create_file(&new_client->dev, &dev_attr_fan1_div);
+	device_create_file(&new_client->dev, &dev_attr_fan2_div);
 	device_create_file(&new_client->dev, &dev_attr_alarms);
 
 	return 0;
@@ -854,8 +834,9 @@ static void via686a_init_client(struct i
 			    !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS));
 }
 
-static void via686a_update_client(struct i2c_client *client)
+static struct via686a_data *via686a_update_device(struct device *dev)
 {
+	struct i2c_client *client = to_i2c_client(dev);
 	struct via686a_data *data = i2c_get_clientdata(client);
 	int i;
 
@@ -916,6 +897,8 @@ static void via686a_update_client(struct
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 static struct pci_device_id via686a_pci_ids[] = {
--- diff/drivers/i2c/chips/w83781d.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/i2c/chips/w83781d.c	2004-03-16 09:37:55.845050432 +0000
@@ -25,8 +25,7 @@
 
     Chip	#vin	#fanin	#pwm	#temp	wchipid	vendid	i2c	ISA
     as99127f	7	3	1?	3	0x31	0x12c3	yes	no
-    as99127f rev.2 (type_name = 1299127f)	0x31	0x5ca3	yes	no
-    asb100 "bach" (type_name = as99127f)	0x31	0x0694	yes	no
+    as99127f rev.2 (type_name = as99127f)	0x31	0x5ca3	yes	no
     w83781d	7	3	0	3	0x10-1	0x5ca3	yes	yes
     w83627hf	9	3	2	3	0x21	0x5ca3	yes	yes(LPC)
     w83627thf	9	3	2	3	0x90	0x5ca3	no	yes(LPC)
@@ -248,10 +247,10 @@ struct w83781d_data {
 	u8 fan_min[3];		/* Register value */
 	u8 temp;
 	u8 temp_max;		/* Register value */
-	u8 temp_hyst;		/* Register value */
+	u8 temp_max_hyst;	/* Register value */
 	u16 temp_add[2];	/* Register value */
 	u16 temp_max_add[2];	/* Register value */
-	u16 temp_hyst_add[2];	/* Register value */
+	u16 temp_max_hyst_add[2];	/* Register value */
 	u8 fan_div[3];		/* Register encoding, shifted right */
 	u8 vid;			/* Register encoding, combined */
 	u32 alarms;		/* Register encoding, combined */
@@ -277,7 +276,7 @@ static int w83781d_detach_client(struct 
 static int w83781d_read_value(struct i2c_client *client, u16 register);
 static int w83781d_write_value(struct i2c_client *client, u16 register,
 			       u16 value);
-static void w83781d_update_client(struct i2c_client *client);
+static struct w83781d_data *w83781d_update_device(struct device *dev);
 static void w83781d_init_client(struct i2c_client *client);
 
 static inline u16 swap_bytes(u16 val)
@@ -298,11 +297,7 @@ static struct i2c_driver w83781d_driver 
 #define show_in_reg(reg) \
 static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
 { \
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct w83781d_data *data = i2c_get_clientdata(client); \
-	 \
-	w83781d_update_client(client); \
-	 \
+	struct w83781d_data *data = w83781d_update_device(dev); \
 	return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr] * 10)); \
 }
 show_in_reg(in);
@@ -331,7 +326,7 @@ show_regs_in_##offset (struct device *de
 { \
         return show_in(dev, buf, 0x##offset); \
 } \
-static DEVICE_ATTR(in_input##offset, S_IRUGO, show_regs_in_##offset, NULL)
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL)
 
 #define sysfs_in_reg_offset(reg, offset) \
 static ssize_t show_regs_in_##reg##offset (struct device *dev, char *buf) \
@@ -342,7 +337,7 @@ static ssize_t store_regs_in_##reg##offs
 { \
 	return store_in_##reg (dev, buf, count, 0x##offset); \
 } \
-static DEVICE_ATTR(in_##reg##offset, S_IRUGO| S_IWUSR, show_regs_in_##reg##offset, store_regs_in_##reg##offset)
+static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_in_##reg##offset, store_regs_in_##reg##offset)
 
 #define sysfs_in_offsets(offset) \
 sysfs_in_offset(offset); \
@@ -361,19 +356,15 @@ sysfs_in_offsets(8);
 
 #define device_create_file_in(client, offset) \
 do { \
-device_create_file(&client->dev, &dev_attr_in_input##offset); \
-device_create_file(&client->dev, &dev_attr_in_min##offset); \
-device_create_file(&client->dev, &dev_attr_in_max##offset); \
+device_create_file(&client->dev, &dev_attr_in##offset##_input); \
+device_create_file(&client->dev, &dev_attr_in##offset##_min); \
+device_create_file(&client->dev, &dev_attr_in##offset##_max); \
 } while (0)
 
 #define show_fan_reg(reg) \
 static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
 { \
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct w83781d_data *data = i2c_get_clientdata(client); \
-	 \
-	w83781d_update_client(client); \
-	 \
+	struct w83781d_data *data = w83781d_update_device(dev); \
 	return sprintf(buf,"%ld\n", \
 		FAN_FROM_REG(data->reg[nr-1], (long)DIV_FROM_REG(data->fan_div[nr-1]))); \
 }
@@ -401,7 +392,7 @@ static ssize_t show_regs_fan_##offset (s
 { \
 	return show_fan(dev, buf, 0x##offset); \
 } \
-static DEVICE_ATTR(fan_input##offset, S_IRUGO, show_regs_fan_##offset, NULL)
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL)
 
 #define sysfs_fan_min_offset(offset) \
 static ssize_t show_regs_fan_min##offset (struct device *dev, char *buf) \
@@ -412,7 +403,7 @@ static ssize_t store_regs_fan_min##offse
 { \
 	return store_fan_min(dev, buf, count, 0x##offset); \
 } \
-static DEVICE_ATTR(fan_min##offset, S_IRUGO | S_IWUSR, show_regs_fan_min##offset, store_regs_fan_min##offset)
+static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, show_regs_fan_min##offset, store_regs_fan_min##offset)
 
 sysfs_fan_offset(1);
 sysfs_fan_min_offset(1);
@@ -423,18 +414,14 @@ sysfs_fan_min_offset(3);
 
 #define device_create_file_fan(client, offset) \
 do { \
-device_create_file(&client->dev, &dev_attr_fan_input##offset); \
-device_create_file(&client->dev, &dev_attr_fan_min##offset); \
+device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
+device_create_file(&client->dev, &dev_attr_fan##offset##_min); \
 } while (0)
 
 #define show_temp_reg(reg) \
 static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
 { \
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct w83781d_data *data = i2c_get_clientdata(client); \
-	 \
-	w83781d_update_client(client); \
-	 \
+	struct w83781d_data *data = w83781d_update_device(dev); \
 	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
 		if (data->type == as99127f) { \
 			return sprintf(buf,"%ld\n", \
@@ -449,7 +436,7 @@ static ssize_t show_##reg (struct device
 }
 show_temp_reg(temp);
 show_temp_reg(temp_max);
-show_temp_reg(temp_hyst);
+show_temp_reg(temp_max_hyst);
 
 #define store_temp_reg(REG, reg) \
 static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \
@@ -477,7 +464,7 @@ static ssize_t store_temp_##reg (struct 
 	return count; \
 }
 store_temp_reg(OVER, max);
-store_temp_reg(HYST, hyst);
+store_temp_reg(HYST, max_hyst);
 
 #define sysfs_temp_offset(offset) \
 static ssize_t \
@@ -485,7 +472,7 @@ show_regs_temp_##offset (struct device *
 { \
 	return show_temp(dev, buf, 0x##offset); \
 } \
-static DEVICE_ATTR(temp_input##offset, S_IRUGO, show_regs_temp_##offset, NULL)
+static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL)
 
 #define sysfs_temp_reg_offset(reg, offset) \
 static ssize_t show_regs_temp_##reg##offset (struct device *dev, char *buf) \
@@ -496,12 +483,12 @@ static ssize_t store_regs_temp_##reg##of
 { \
 	return store_temp_##reg (dev, buf, count, 0x##offset); \
 } \
-static DEVICE_ATTR(temp_##reg##offset, S_IRUGO| S_IWUSR, show_regs_temp_##reg##offset, store_regs_temp_##reg##offset)
+static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_temp_##reg##offset, store_regs_temp_##reg##offset)
 
 #define sysfs_temp_offsets(offset) \
 sysfs_temp_offset(offset); \
 sysfs_temp_reg_offset(max, offset); \
-sysfs_temp_reg_offset(hyst, offset);
+sysfs_temp_reg_offset(max_hyst, offset);
 
 sysfs_temp_offsets(1);
 sysfs_temp_offsets(2);
@@ -509,34 +496,26 @@ sysfs_temp_offsets(3);
 
 #define device_create_file_temp(client, offset) \
 do { \
-device_create_file(&client->dev, &dev_attr_temp_input##offset); \
-device_create_file(&client->dev, &dev_attr_temp_max##offset); \
-device_create_file(&client->dev, &dev_attr_temp_hyst##offset); \
+device_create_file(&client->dev, &dev_attr_temp##offset##_input); \
+device_create_file(&client->dev, &dev_attr_temp##offset##_max); \
+device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \
 } while (0)
 
 static ssize_t
 show_vid_reg(struct device *dev, char *buf)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83781d_data *data = i2c_get_clientdata(client);
-
-	w83781d_update_client(client);
-
+	struct w83781d_data *data = w83781d_update_device(dev);
 	return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
 }
 
 static
-DEVICE_ATTR(vid, S_IRUGO, show_vid_reg, NULL)
+DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL)
 #define device_create_file_vid(client) \
-device_create_file(&client->dev, &dev_attr_vid);
+device_create_file(&client->dev, &dev_attr_in0_ref);
 static ssize_t
 show_vrm_reg(struct device *dev, char *buf)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83781d_data *data = i2c_get_clientdata(client);
-
-	w83781d_update_client(client);
-
+	struct w83781d_data *data = w83781d_update_device(dev);
 	return sprintf(buf, "%ld\n", (long) data->vrm);
 }
 
@@ -560,11 +539,7 @@ device_create_file(&client->dev, &dev_at
 static ssize_t
 show_alarms_reg(struct device *dev, char *buf)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83781d_data *data = i2c_get_clientdata(client);
-
-	w83781d_update_client(client);
-
+	struct w83781d_data *data = w83781d_update_device(dev);
 	return sprintf(buf, "%ld\n", (long) ALARMS_FROM_REG(data->alarms));
 }
 
@@ -575,11 +550,7 @@ device_create_file(&client->dev, &dev_at
 #define show_beep_reg(REG, reg) \
 static ssize_t show_beep_##reg (struct device *dev, char *buf) \
 { \
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct w83781d_data *data = i2c_get_clientdata(client); \
-	 \
-	w83781d_update_client(client); \
-	 \
+	struct w83781d_data *data = w83781d_update_device(dev); \
 	return sprintf(buf,"%ld\n", (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \
 }
 show_beep_reg(ENABLE, enable);
@@ -640,60 +611,81 @@ device_create_file(&client->dev, &dev_at
 device_create_file(&client->dev, &dev_attr_beep_mask); \
 } while (0)
 
-/* w83697hf only has two fans */
 static ssize_t
 show_fan_div_reg(struct device *dev, char *buf, int nr)
 {
+	struct w83781d_data *data = w83781d_update_device(dev);
+	return sprintf(buf, "%ld\n",
+		       (long) DIV_FROM_REG(data->fan_div[nr - 1]));
+}
+
+static ssize_t
+store_regs_fan_div_1(struct device *dev, const char *buf, size_t count)
+{
 	struct i2c_client *client = to_i2c_client(dev);
 	struct w83781d_data *data = i2c_get_clientdata(client);
+	u32 reg;
 
-	w83781d_update_client(client);
+	data->fan_div[0] = DIV_TO_REG(simple_strtoul(buf, NULL, 10),
+				      data->type);
 
-	return sprintf(buf, "%ld\n",
-		       (long) DIV_FROM_REG(data->fan_div[nr - 1]));
+	reg = w83781d_read_value(client, W83781D_REG_VID_FANDIV) & 0xcf;
+	reg |= (data->fan_div[0] & 0x03) << 4;
+	w83781d_write_value(client, W83781D_REG_VID_FANDIV, reg);
+
+	/* w83781d and as99127f don't have extended divisor bits */
+	if (data->type != w83781d && data->type != as99127f) {
+		reg = w83781d_read_value(client, W83781D_REG_VBAT) & 0xdf;
+		reg |= (data->fan_div[0] & 0x04) << 3;
+		w83781d_write_value(client, W83781D_REG_VBAT, reg);
+	}
+
+	return count;
 }
 
-/* w83697hf only has two fans */
 static ssize_t
-store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_regs_fan_div_2(struct device *dev, const char *buf, size_t count)
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct w83781d_data *data = i2c_get_clientdata(client);
-	u32 val, old, old2, old3 = 0;
+	u32 reg;
 
-	val = simple_strtoul(buf, NULL, 10);
-	old = w83781d_read_value(client, W83781D_REG_VID_FANDIV);
+	data->fan_div[1] = DIV_TO_REG(simple_strtoul(buf, NULL, 10),
+				      data->type);
 
-	data->fan_div[nr - 1] = DIV_TO_REG(val, data->type);
+	reg = w83781d_read_value(client, W83781D_REG_VID_FANDIV) & 0x3f;
+	reg |= (data->fan_div[1] & 0x03) << 6;
+	w83781d_write_value(client, W83781D_REG_VID_FANDIV, reg);
 
 	/* w83781d and as99127f don't have extended divisor bits */
-	if ((data->type != w83781d) && data->type != as99127f) {
-		old3 = w83781d_read_value(client, W83781D_REG_VBAT);
+	if (data->type != w83781d && data->type != as99127f) {
+		reg = w83781d_read_value(client, W83781D_REG_VBAT) & 0xbf;
+		reg |= (data->fan_div[1] & 0x04) << 4;
+		w83781d_write_value(client, W83781D_REG_VBAT, reg);
 	}
-	if (nr >= 3 && data->type != w83697hf) {
-		old2 = w83781d_read_value(client, W83781D_REG_PIN);
-		old2 = (old2 & 0x3f) | ((data->fan_div[2] & 0x03) << 6);
-		w83781d_write_value(client, W83781D_REG_PIN, old2);
 
-		if ((data->type != w83781d) && (data->type != as99127f)) {
-			old3 = (old3 & 0x7f) | ((data->fan_div[2] & 0x04) << 5);
-		}
-	}
-	if (nr >= 2) {
-		old = (old & 0x3f) | ((data->fan_div[1] & 0x03) << 6);
+	return count;
+}
 
-		if ((data->type != w83781d) && (data->type != as99127f)) {
-			old3 = (old3 & 0xbf) | ((data->fan_div[1] & 0x04) << 4);
-		}
-	}
-	if (nr >= 1) {
-		old = (old & 0xcf) | ((data->fan_div[0] & 0x03) << 4);
-		w83781d_write_value(client, W83781D_REG_VID_FANDIV, old);
+static ssize_t
+store_regs_fan_div_3(struct device *dev, const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83781d_data *data = i2c_get_clientdata(client);
+	u32 reg;
 
-		if ((data->type != w83781d) && (data->type != as99127f)) {
-			old3 = (old3 & 0xdf) | ((data->fan_div[0] & 0x04) << 3);
-			w83781d_write_value(client, W83781D_REG_VBAT, old3);
-		}
+	data->fan_div[2] = DIV_TO_REG(simple_strtoul(buf, NULL, 10),
+				      data->type);
+
+	reg = w83781d_read_value(client, W83781D_REG_PIN) & 0x3f;
+	reg |= (data->fan_div[2] & 0x03) << 6;
+	w83781d_write_value(client, W83781D_REG_PIN, reg);
+
+	/* w83781d and as99127f don't have extended divisor bits */
+	if (data->type != w83781d && data->type != as99127f) {
+		reg = w83781d_read_value(client, W83781D_REG_VBAT) & 0x7f;
+		reg |= (data->fan_div[2] & 0x04) << 5;
+		w83781d_write_value(client, W83781D_REG_VBAT, reg);
 	}
 
 	return count;
@@ -704,11 +696,7 @@ static ssize_t show_regs_fan_div_##offse
 { \
 	return show_fan_div_reg(dev, buf, offset); \
 } \
-static ssize_t store_regs_fan_div_##offset (struct device *dev, const char *buf, size_t count) \
-{ \
-	return store_fan_div_reg(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(fan_div##offset, S_IRUGO | S_IWUSR, show_regs_fan_div_##offset, store_regs_fan_div_##offset)
+static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, show_regs_fan_div_##offset, store_regs_fan_div_##offset)
 
 sysfs_fan_div(1);
 sysfs_fan_div(2);
@@ -716,18 +704,14 @@ sysfs_fan_div(3);
 
 #define device_create_file_fan_div(client, offset) \
 do { \
-device_create_file(&client->dev, &dev_attr_fan_div##offset); \
+device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
 } while (0)
 
 /* w83697hf only has two fans */
 static ssize_t
 show_pwm_reg(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83781d_data *data = i2c_get_clientdata(client);
-
-	w83781d_update_client(client);
-
+	struct w83781d_data *data = w83781d_update_device(dev);
 	return sprintf(buf, "%ld\n", (long) PWM_FROM_REG(data->pwm[nr - 1]));
 }
 
@@ -735,11 +719,7 @@ show_pwm_reg(struct device *dev, char *b
 static ssize_t
 show_pwmenable_reg(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83781d_data *data = i2c_get_clientdata(client);
-
-	w83781d_update_client(client);
-
+	struct w83781d_data *data = w83781d_update_device(dev);
 	return sprintf(buf, "%ld\n", (long) data->pwmenable[nr - 1]);
 }
 
@@ -809,7 +789,7 @@ static ssize_t store_regs_pwm_##offset (
 { \
 	return store_pwm_reg(dev, buf, count, offset); \
 } \
-static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, show_regs_pwm_##offset, store_regs_pwm_##offset)
+static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, show_regs_pwm_##offset, store_regs_pwm_##offset)
 
 #define sysfs_pwmenable(offset) \
 static ssize_t show_regs_pwmenable_##offset (struct device *dev, char *buf) \
@@ -820,7 +800,7 @@ static ssize_t store_regs_pwmenable_##of
 { \
 	return store_pwmenable_reg(dev, buf, count, offset); \
 } \
-static DEVICE_ATTR(pwm_enable##offset, S_IRUGO | S_IWUSR, show_regs_pwmenable_##offset, store_regs_pwmenable_##offset)
+static DEVICE_ATTR(fan##offset##_pwm_enable, S_IRUGO | S_IWUSR, show_regs_pwmenable_##offset, store_regs_pwmenable_##offset)
 
 sysfs_pwm(1);
 sysfs_pwm(2);
@@ -830,22 +810,18 @@ sysfs_pwm(4);
 
 #define device_create_file_pwm(client, offset) \
 do { \
-device_create_file(&client->dev, &dev_attr_pwm##offset); \
+device_create_file(&client->dev, &dev_attr_fan##offset##_pwm); \
 } while (0)
 
 #define device_create_file_pwmenable(client, offset) \
 do { \
-device_create_file(&client->dev, &dev_attr_pwm_enable##offset); \
+device_create_file(&client->dev, &dev_attr_fan##offset##_pwm_enable); \
 } while (0)
 
 static ssize_t
 show_sensor_reg(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83781d_data *data = i2c_get_clientdata(client);
-
-	w83781d_update_client(client);
-
+	struct w83781d_data *data = w83781d_update_device(dev);
 	return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]);
 }
 
@@ -902,7 +878,7 @@ static ssize_t store_regs_sensor_##offse
 { \
     return store_sensor_reg(dev, buf, count, offset); \
 } \
-static DEVICE_ATTR(sensor##offset, S_IRUGO | S_IWUSR, show_regs_sensor_##offset, store_regs_sensor_##offset)
+static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, show_regs_sensor_##offset, store_regs_sensor_##offset)
 
 sysfs_sensor(1);
 sysfs_sensor(2);
@@ -910,19 +886,16 @@ sysfs_sensor(3);
 
 #define device_create_file_sensor(client, offset) \
 do { \
-device_create_file(&client->dev, &dev_attr_sensor##offset); \
+device_create_file(&client->dev, &dev_attr_temp##offset##_type); \
 } while (0)
 
 #ifdef W83781D_RT
 static ssize_t
 show_rt_reg(struct device *dev, char *buf, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83781d_data *data = i2c_get_clientdata(client);
+	struct w83781d_data *data = w83781d_update_device(dev);
 	int i, j = 0;
 
-	w83781d_update_client(client);
-
 	for (i = 0; i < 32; i++) {
 		if (i > 0)
 			j += sprintf(buf, " %ld", (long) data->rt[nr - 1][i]);
@@ -1194,10 +1167,8 @@ w83781d_detect(struct i2c_adapter *adapt
 		val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN);
 		/* Check for Winbond or Asus ID if in bank 0 */
 		if ((!(val1 & 0x07)) &&
-		    (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3)
-		      && (val2 != 0x94))
-		     || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)
-			 && (val2 != 0x06)))) {
+		    (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3))
+		     || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) {
 			err = -ENODEV;
 			goto ERROR2;
 		}
@@ -1226,7 +1197,7 @@ w83781d_detect(struct i2c_adapter *adapt
 		val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN);
 		if (val2 == 0x5c)
 			vendid = winbond;
-		else if ((val2 == 0x12) || (val2 == 0x06))
+		else if (val2 == 0x12)
 			vendid = asus;
 		else {
 			err = -ENODEV;
@@ -1632,7 +1603,11 @@ w83781d_init_client(struct i2c_client *c
 		if (type != w83781d) {
 			/* enable comparator mode for temp2 and temp3 so
 			   alarm indication will work correctly */
-			w83781d_write_value(client, W83781D_REG_IRQ, 0x41);
+			i = w83781d_read_value(client, W83781D_REG_IRQ);
+			if (!(i & 0x40))
+				w83781d_write_value(client, W83781D_REG_IRQ,
+						    i | 0x40);
+
 			for (i = 0; i < 3; i++)
 				data->pwmenable[i] = 1;
 		}
@@ -1645,9 +1620,9 @@ w83781d_init_client(struct i2c_client *c
 			    | 0x01);
 }
 
-static void
-w83781d_update_client(struct i2c_client *client)
+static struct w83781d_data *w83781d_update_device(struct device *dev)
 {
+	struct i2c_client *client = to_i2c_client(dev);
 	struct w83781d_data *data = i2c_get_clientdata(client);
 	int i;
 
@@ -1697,13 +1672,13 @@ w83781d_update_client(struct i2c_client 
 		data->temp = w83781d_read_value(client, W83781D_REG_TEMP(1));
 		data->temp_max =
 		    w83781d_read_value(client, W83781D_REG_TEMP_OVER(1));
-		data->temp_hyst =
+		data->temp_max_hyst =
 		    w83781d_read_value(client, W83781D_REG_TEMP_HYST(1));
 		data->temp_add[0] =
 		    w83781d_read_value(client, W83781D_REG_TEMP(2));
 		data->temp_max_add[0] =
 		    w83781d_read_value(client, W83781D_REG_TEMP_OVER(2));
-		data->temp_hyst_add[0] =
+		data->temp_max_hyst_add[0] =
 		    w83781d_read_value(client, W83781D_REG_TEMP_HYST(2));
 		if (data->type != w83783s && data->type != w83697hf) {
 			data->temp_add[1] =
@@ -1711,7 +1686,7 @@ w83781d_update_client(struct i2c_client 
 			data->temp_max_add[1] =
 			    w83781d_read_value(client,
 					       W83781D_REG_TEMP_OVER(3));
-			data->temp_hyst_add[1] =
+			data->temp_max_hyst_add[1] =
 			    w83781d_read_value(client,
 					       W83781D_REG_TEMP_HYST(3));
 		}
@@ -1760,6 +1735,8 @@ w83781d_update_client(struct i2c_client 
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 static int __init
--- diff/drivers/i2c/chips/w83l785ts.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/i2c/chips/w83l785ts.c	2004-03-16 09:37:55.851049520 +0000
@@ -12,6 +12,9 @@
  * Ported to Linux 2.6 by Wolfgang Ziegler <nuppla@gmx.at> and Jean Delvare
  * <khali@linux-fr.org>.
  *
+ * Thanks to James Bolt <james@evilpenguin.com> for benchmarking the read
+ * error handling mechanism.
+ *
  * 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
@@ -86,7 +89,7 @@ static int w83l785ts_detect(struct i2c_a
 	int kind);
 static int w83l785ts_detach_client(struct i2c_client *client);
 static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval);
-static void w83l785ts_update_client(struct i2c_client *client);
+static struct w83l785ts_data *w83l785ts_update_device(struct device *dev);
 
 /*
  * Driver data (common to all clients)
@@ -127,22 +130,18 @@ static int w83l785ts_id = 0;
 
 static ssize_t show_temp(struct device *dev, char *buf)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83l785ts_data *data = i2c_get_clientdata(client);
-	w83l785ts_update_client(client);
+	struct w83l785ts_data *data = w83l785ts_update_device(dev);
 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp));
 }
 
 static ssize_t show_temp_over(struct device *dev, char *buf)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83l785ts_data *data = i2c_get_clientdata(client);
-	w83l785ts_update_client(client);
+	struct w83l785ts_data *data = w83l785ts_update_device(dev);
 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over));
 }
 
-static DEVICE_ATTR(temp_input1, S_IRUGO, show_temp, NULL)
-static DEVICE_ATTR(temp_max1, S_IRUGO, show_temp_over, NULL)
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL)
+static DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_over, NULL)
 
 /*
  * Real code
@@ -256,8 +255,8 @@ static int w83l785ts_detect(struct i2c_a
 	 */
 
 	/* Register sysfs hooks */
-	device_create_file(&new_client->dev, &dev_attr_temp_input1);
-	device_create_file(&new_client->dev, &dev_attr_temp_max1);
+	device_create_file(&new_client->dev, &dev_attr_temp1_input);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max);
 
 	return 0;
 
@@ -301,8 +300,9 @@ static u8 w83l785ts_read_value(struct i2
 	return defval;
 }
 
-static void w83l785ts_update_client(struct i2c_client *client)
+static struct w83l785ts_data *w83l785ts_update_device(struct device *dev)
 {
+	struct i2c_client *client = to_i2c_client(dev);
 	struct w83l785ts_data *data = i2c_get_clientdata(client);
 
 	down(&data->update_lock);
@@ -321,6 +321,8 @@ static void w83l785ts_update_client(stru
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 static int __init sensors_w83l785ts_init(void)
--- diff/drivers/i2c/i2c-core.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/i2c/i2c-core.c	2004-03-16 09:37:55.868046936 +0000
@@ -175,7 +175,7 @@ int i2c_del_adapter(struct i2c_adapter *
 		driver = list_entry(item, struct i2c_driver, list);
 		if (driver->detach_adapter)
 			if ((res = driver->detach_adapter(adap))) {
-				dev_warn(&adap->dev, "can't detach adapter"
+				dev_warn(&adap->dev, "can't detach adapter "
 					 "while detaching driver %s: driver not "
 					 "detached!", driver->name);
 				goto out_unlock;
@@ -437,8 +437,11 @@ static void i2c_dec_use_client(struct i2
 
 int i2c_use_client(struct i2c_client *client)
 {
-	if (!i2c_inc_use_client(client))
-		return -ENODEV;
+	int ret;
+
+	ret = i2c_inc_use_client(client);
+	if (ret)
+		return ret;
 
 	if (client->flags & I2C_CLIENT_ALLOW_USE) {
 		if (client->flags & I2C_CLIENT_ALLOW_MULTIPLE_USE)
@@ -618,7 +621,7 @@ int i2c_control(struct i2c_client *clien
 	int ret = 0;
 	struct i2c_adapter *adap = client->adapter;
 
-	dev_dbg(&client->dev, "i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg);
+	dev_dbg(&client->adapter->dev, "i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg);
 	switch (cmd) {
 		case I2C_RETRIES:
 			adap->retries = arg;
--- diff/drivers/i2c/i2c-dev.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/i2c/i2c-dev.c	2004-03-16 09:37:55.876045720 +0000
@@ -72,24 +72,18 @@ struct i2c_dev *i2c_dev_get_by_minor(uns
 struct i2c_dev *i2c_dev_get_by_adapter(struct i2c_adapter *adap)
 {
 	struct i2c_dev *i2c_dev = NULL;
-	int i;
 
 	spin_lock(&i2c_dev_array_lock);
-	for (i = 0; i < I2C_MINORS; ++i) {
-		if ((i2c_dev_array[i]) &&
-		    (i2c_dev_array[i]->adap == adap)) {
-			i2c_dev = i2c_dev_array[i];
-			break;
-		}
-	}
+	if ((i2c_dev_array[adap->nr]) &&
+	    (i2c_dev_array[adap->nr]->adap == adap))
+		i2c_dev = i2c_dev_array[adap->nr];
 	spin_unlock(&i2c_dev_array_lock);
 	return i2c_dev;
 }
 
-static struct i2c_dev *get_free_i2c_dev(void)
+static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap)
 {
 	struct i2c_dev *i2c_dev;
-	unsigned int i;
 
 	i2c_dev = kmalloc(sizeof(*i2c_dev), GFP_KERNEL);
 	if (!i2c_dev)
@@ -97,15 +91,16 @@ static struct i2c_dev *get_free_i2c_dev(
 	memset(i2c_dev, 0x00, sizeof(*i2c_dev));
 
 	spin_lock(&i2c_dev_array_lock);
-	for (i = 0; i < I2C_MINORS; ++i) {
-		if (i2c_dev_array[i])
-			continue;
-		i2c_dev->minor = i;
-		i2c_dev_array[i] = i2c_dev;
+	if (i2c_dev_array[adap->nr]) {
 		spin_unlock(&i2c_dev_array_lock);
-		return i2c_dev;
+		dev_err(&adap->dev, "i2c-dev already has a device assigned to this adapter\n");
+		goto error;
 	}
+	i2c_dev->minor = adap->nr;
+	i2c_dev_array[adap->nr] = i2c_dev;
 	spin_unlock(&i2c_dev_array_lock);
+	return i2c_dev;
+error:
 	kfree(i2c_dev);
 	return ERR_PTR(-ENODEV);
 }
@@ -124,6 +119,13 @@ static ssize_t show_dev(struct class_dev
 }
 static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
 
+static ssize_t show_adapter_name(struct class_device *class_dev, char *buf)
+{
+	struct i2c_dev *i2c_dev = to_i2c_dev(class_dev);
+	return sprintf(buf, "%s\n", i2c_dev->adap->name);
+}
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
+
 static ssize_t i2cdev_read (struct file *file, char __user *buf, size_t count,
                             loff_t *offset)
 {
@@ -187,7 +189,7 @@ int i2cdev_ioctl (struct inode *inode, s
 	int i,datasize,res;
 	unsigned long funcs;
 
-	dev_dbg(&client->dev, "i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n",
+	dev_dbg(&client->adapter->dev, "i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n",
 		iminor(inode),cmd, arg);
 
 	switch ( cmd ) {
@@ -308,7 +310,7 @@ int i2cdev_ioctl (struct inode *inode, s
 		    (data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
 		    (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) &&
 		    (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) {
-			dev_dbg(&client->dev,
+			dev_dbg(&client->adapter->dev,
 				"size out of range (%x) in ioctl I2C_SMBUS.\n",
 				data_arg.size);
 			return -EINVAL;
@@ -317,7 +319,7 @@ int i2cdev_ioctl (struct inode *inode, s
 		   so the check is valid if size==I2C_SMBUS_QUICK too. */
 		if ((data_arg.read_write != I2C_SMBUS_READ) && 
 		    (data_arg.read_write != I2C_SMBUS_WRITE)) {
-			dev_dbg(&client->dev, 
+			dev_dbg(&client->adapter->dev, 
 				"read_write out of range (%x) in ioctl I2C_SMBUS.\n",
 				data_arg.read_write);
 			return -EINVAL;
@@ -336,7 +338,7 @@ int i2cdev_ioctl (struct inode *inode, s
 					      data_arg.size, NULL);
 
 		if (data_arg.data == NULL) {
-			dev_dbg(&client->dev,
+			dev_dbg(&client->adapter->dev,
 				"data is NULL pointer in ioctl I2C_SMBUS.\n");
 			return -EINVAL;
 		}
@@ -439,7 +441,7 @@ static int i2cdev_attach_adapter(struct 
 	struct i2c_dev *i2c_dev;
 	int retval;
 
-	i2c_dev = get_free_i2c_dev();
+	i2c_dev = get_free_i2c_dev(adap);
 	if (IS_ERR(i2c_dev))
 		return PTR_ERR(i2c_dev);
 
@@ -459,6 +461,7 @@ static int i2cdev_attach_adapter(struct 
 	if (retval)
 		goto error;
 	class_device_create_file(&i2c_dev->class_dev, &class_device_attr_dev);
+	class_device_create_file(&i2c_dev->class_dev, &class_device_attr_name);
 	return 0;
 error:
 	return_i2c_dev(i2c_dev);
--- diff/drivers/ide/Kconfig	2004-03-11 10:20:23.000000000 +0000
+++ source/drivers/ide/Kconfig	2004-03-16 09:37:55.877045568 +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-11 10:20:24.000000000 +0000
+++ source/drivers/ide/ide-cd.c	2004-03-16 09:37:55.880045112 +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-11 10:20:24.000000000 +0000
+++ source/drivers/ide/ide-disk.c	2004-03-16 09:37:55.883044656 +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-11 10:20:24.000000000 +0000
+++ source/drivers/ide/ide-io.c	2004-03-16 09:37:55.890043592 +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 11:28:05.000000000 +0000
+++ source/drivers/ide/ide-lib.c	2004-03-16 09:37:55.891043440 +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-11 10:20:24.000000000 +0000
+++ source/drivers/ide/ide-probe.c	2004-03-16 09:37:55.892043288 +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-11 10:20:24.000000000 +0000
+++ source/drivers/ide/ide-taskfile.c	2004-03-16 09:37:55.894042984 +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-16 09:37:55.895042832 +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/macide.c	2003-09-17 11:28:05.000000000 +0000
+++ source/drivers/ide/legacy/macide.c	2004-03-16 09:37:55.896042680 +0000
@@ -94,6 +94,7 @@ static void macide_mediabay_interrupt(in
 void macide_init(void)
 {
 	hw_regs_t hw;
+	ide_hwif_t *hwif;
 	int index = -1;
 
 	switch (macintosh_config->ide_type) {
@@ -102,21 +103,21 @@ void macide_init(void)
 				0, 0, macide_ack_intr,
 //				quadra_ide_iops,
 				IRQ_NUBUS_F);
-		index = ide_register_hw(&hw, NULL);
+		index = ide_register_hw(&hw, &hwif);
 		break;
 	case MAC_IDE_PB:
 		ide_setup_ports(&hw, IDE_BASE, macide_offsets,
 				0, 0, macide_ack_intr,
 //				macide_pb_iops,
 				IRQ_NUBUS_C);
-		index = ide_register_hw(&hw, NULL);
+		index = ide_register_hw(&hw, &hwif);
 		break;
 	case MAC_IDE_BABOON:
 		ide_setup_ports(&hw, BABOON_BASE, macide_offsets,
 				0, 0, NULL,
 //				macide_baboon_iops,
 				IRQ_BABOON_1);
-		index = ide_register_hw(&hw, NULL);
+		index = ide_register_hw(&hw, &hwif);
 		if (index == -1) break;
 		if (macintosh_config->ident == MAC_MODEL_PB190) {
 
@@ -141,6 +142,7 @@ void macide_init(void)
 	}
 
         if (index != -1) {
+		hwif->mmio = 2;
 		if (macintosh_config->ide_type == MAC_IDE_QUADRA)
 			printk(KERN_INFO "ide%d: Macintosh Quadra IDE interface\n", index);
 		else if (macintosh_config->ide_type == MAC_IDE_PB)
--- diff/drivers/ide/legacy/pdc4030.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/ide/legacy/pdc4030.c	2004-03-16 09:37:55.896042680 +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-11 10:20:24.000000000 +0000
+++ source/drivers/ide/pci/Makefile	2004-03-16 09:37:55.897042528 +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-11 10:20:24.000000000 +0000
+++ source/drivers/ide/pci/pdc202xx_new.c	2004-03-16 09:37:55.898042376 +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-11 10:20:24.000000000 +0000
+++ source/drivers/ide/pci/pdc202xx_new.h	2004-03-16 09:37:55.899042224 +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-11 10:20:24.000000000 +0000
+++ source/drivers/ide/pci/piix.c	2004-03-16 09:37:55.900042072 +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-11 10:20:24.000000000 +0000
+++ source/drivers/ide/pci/siimage.c	2004-03-16 09:37:55.901041920 +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/amdtp.c	2004-03-11 10:20:24.000000000 +0000
+++ source/drivers/ieee1394/amdtp.c	2004-03-16 09:37:55.902041768 +0000
@@ -1266,7 +1266,6 @@ static int __init amdtp_init_module (voi
 {
 	cdev_init(&amdtp_cdev, &amdtp_fops);
 	amdtp_cdev.owner = THIS_MODULE;
-	kobject_set_name(&amdtp_cdev.kobj, "amdtp");
 	if (cdev_add(&amdtp_cdev, IEEE1394_AMDTP_DEV, 16)) {
 		HPSB_ERR("amdtp: unable to add char device");
  		return -EIO;
--- diff/drivers/ieee1394/dma.c	2004-03-11 10:20:24.000000000 +0000
+++ source/drivers/ieee1394/dma.c	2004-03-16 09:37:55.902041768 +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-11 10:20:24.000000000 +0000
+++ source/drivers/ieee1394/dma.h	2004-03-16 09:37:55.902041768 +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-11 10:20:24.000000000 +0000
+++ source/drivers/ieee1394/dv1394.c	2004-03-16 09:37:55.905041312 +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);
@@ -2616,7 +2616,6 @@ static int __init dv1394_init_module(voi
 
 	cdev_init(&dv1394_cdev, &dv1394_fops);
 	dv1394_cdev.owner = THIS_MODULE;
-	kobject_set_name(&dv1394_cdev.kobj, "dv1394");
 	ret = cdev_add(&dv1394_cdev, IEEE1394_DV1394_DEV, 16);
 	if (ret) {
 		printk(KERN_ERR "dv1394: unable to register character device\n");
--- diff/drivers/ieee1394/ieee1394_core.c	2004-03-11 10:20:24.000000000 +0000
+++ source/drivers/ieee1394/ieee1394_core.c	2004-03-16 09:37:55.906041160 +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-11 10:20:24.000000000 +0000
+++ source/drivers/ieee1394/ohci1394.c	2004-03-16 09:37:55.909040704 +0000
@@ -620,6 +620,39 @@ static void ohci_initialize(struct ti_oh
 		if (status & 0x20)
 			set_phy_reg(ohci, 8, status & ~1);
 	}
+
+        /* Serial EEPROM Sanity check. */
+        if ((ohci->max_packet_size < 512) ||
+	    (ohci->max_packet_size > 4096)) {
+		/* Serial EEPROM contents are suspect, set a sane max packet
+		 * size and print the raw contents for bug reports if verbose
+		 * debug is enabled. */
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+		int i;
+#endif
+
+		PRINT(KERN_DEBUG, "Serial EEPROM has suspicious values, "
+                      "attempting to setting max_packet_size to 512 bytes");
+		reg_write(ohci, OHCI1394_BusOptions,
+			  (reg_read(ohci, OHCI1394_BusOptions) & 0xf007) | 0x8002);
+		ohci->max_packet_size = 512;
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+		PRINT(KERN_DEBUG, "    EEPROM Present: %d",
+		      (reg_read(ohci, OHCI1394_Version) >> 24) & 0x1);
+		reg_write(ohci, OHCI1394_GUID_ROM, 0x80000000);
+
+		for (i = 0; 
+		     ((i < 1000) &&
+		      (reg_read(ohci, OHCI1394_GUID_ROM) & 0x80000000)); i++)
+			udelay(10);
+
+		for (i = 0; i < 0x20; i++) {
+			reg_write(ohci, OHCI1394_GUID_ROM, 0x02000000);
+			PRINT(KERN_DEBUG, "    EEPROM %02x: %02x", i,
+			      (reg_read(ohci, OHCI1394_GUID_ROM) >> 16) & 0xff);
+		}
+#endif
+	}
 }
 
 /* 
@@ -1732,7 +1765,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 +1822,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 +2049,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/pcilynx.c	2004-03-11 10:20:24.000000000 +0000
+++ source/drivers/ieee1394/pcilynx.c	2004-03-16 09:37:55.910040552 +0000
@@ -1460,7 +1460,7 @@ static void remove_card(struct pci_dev *
                 reg_write(lynx, PCI_INT_ENABLE, 0);
                 free_irq(lynx->dev->irq, lynx);
 
-		/* Disable IRM Contender */
+		/* Disable IRM Contender and LCtrl */
 		if (lynx->phyic.reg_1394a)
 			set_phy_reg(lynx, 4, ~0xc0 & get_phy_reg(lynx, 4));
 
@@ -1788,12 +1788,12 @@ static int __devinit add_card(struct pci
                 reg_set_bits(lynx, GPIO_CTRL_A, 0x1);
                 reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1); 
         } else {
-                /* set the contender bit in the extended PHY register
+                /* set the contender and LCtrl bit in the extended PHY register
                  * set. (Should check that bis 0,1,2 (=0xE0) is set
                  * in register 2?)
                  */
                 i = get_phy_reg(lynx, 4);
-                if (i != -1) set_phy_reg(lynx, 4, i | 0x40);
+                if (i != -1) set_phy_reg(lynx, 4, i | 0xc0);
         }
 
 
--- diff/drivers/ieee1394/raw1394.c	2004-03-11 10:20:24.000000000 +0000
+++ source/drivers/ieee1394/raw1394.c	2004-03-16 09:37:55.912040248 +0000
@@ -2746,9 +2746,9 @@ static int __init init_raw1394(void)
 
 	cdev_init(&raw1394_cdev, &raw1394_fops);
 	raw1394_cdev.owner = THIS_MODULE;
-	kobject_set_name(&raw1394_cdev.kobj, RAW1394_DEVICE_NAME);
 	ret = cdev_add(&raw1394_cdev, IEEE1394_RAW1394_DEV, 1);
 	if (ret) {
+		/* jmc: leaves reference to (static) raw1394_cdev */
                 HPSB_ERR("raw1394 failed to register minor device block");
                 devfs_remove(RAW1394_DEVICE_NAME);
                 hpsb_unregister_highlevel(&raw1394_highlevel);
--- diff/drivers/ieee1394/sbp2.c	2004-03-11 10:20:24.000000000 +0000
+++ source/drivers/ieee1394/sbp2.c	2004-03-16 09:37:55.914039944 +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/ieee1394/video1394.c	2004-03-11 10:20:24.000000000 +0000
+++ source/drivers/ieee1394/video1394.c	2004-03-16 09:37:55.916039640 +0000
@@ -1457,7 +1457,6 @@ static int __init video1394_init_module 
 
 	cdev_init(&video1394_cdev, &video1394_fops);
 	video1394_cdev.owner = THIS_MODULE;
-	kobject_set_name(&video1394_cdev.kobj, VIDEO1394_DRIVER_NAME);
 	ret = cdev_add(&video1394_cdev, IEEE1394_VIDEO1394_DEV, 16);
 	if (ret) {
 		PRINT_G(KERN_ERR, "video1394: unable to get minor device block");
--- diff/drivers/input/evdev.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/input/evdev.c	2004-03-16 09:37:55.916039640 +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 09:00:52.000000000 +0000
+++ source/drivers/input/gameport/ns558.c	2004-03-16 09:37:55.917039488 +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
@@ -276,6 +289,7 @@ void __exit ns558_exit(void)
 #endif
 			case NS558_ISA:
 				release_region(port->gameport.io & ~(port->size - 1), port->size);
+				kfree(port);
 				break;
 		
 			default:
--- diff/drivers/input/input.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/input/input.c	2004-03-16 09:37:55.918039336 +0000
@@ -727,6 +727,8 @@ static int __init input_init(void)
 	int retval = -ENOMEM;
 
 	input_class = class_simple_create(THIS_MODULE, "input");
+	if (IS_ERR(input_class))
+		return PTR_ERR(input_class);
 	input_proc_init();
 	retval = register_chrdev(INPUT_MAJOR, "input", &input_fops);
 	if (retval) {
@@ -734,6 +736,7 @@ static int __init input_init(void)
 		remove_proc_entry("devices", proc_bus_input_dir);
 		remove_proc_entry("handlers", proc_bus_input_dir);
 		remove_proc_entry("input", proc_bus);
+		class_simple_destroy(input_class);
 		return retval;
 	}
 
@@ -743,6 +746,7 @@ static int __init input_init(void)
 		remove_proc_entry("handlers", proc_bus_input_dir);
 		remove_proc_entry("input", proc_bus);
 		unregister_chrdev(INPUT_MAJOR, "input");
+		class_simple_destroy(input_class);
 	}
 	return retval;
 }
--- diff/drivers/input/joystick/amijoy.c	2003-06-09 13:18:18.000000000 +0000
+++ source/drivers/input/joystick/amijoy.c	2004-03-16 09:37:55.918039336 +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 08:47:34.000000000 +0000
+++ source/drivers/input/joystick/analog.c	2004-03-16 09:37:55.919039184 +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-16 09:37:55.921038880 +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-16 09:37:55.922038728 +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 14:46:14.000000000 +0000
+++ source/drivers/input/joystick/iforce/iforce-usb.c	2004-03-16 09:37:55.923038576 +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-16 09:37:55.923038576 +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 08:47:34.000000000 +0000
+++ source/drivers/input/keyboard/Kconfig	2004-03-16 09:37:55.924038424 +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 10:49:55.000000000 +0000
+++ source/drivers/input/keyboard/Makefile	2004-03-16 09:37:55.924038424 +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-16 09:37:55.926038120 +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,20 +577,21 @@ 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))
@@ -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,29 @@ static int atkbd_reconnect(struct serio 
 {
 	struct atkbd *atkbd = serio->private;
 	struct serio_dev *dev = serio->dev;
-	int i;
+	unsigned char param[1];
 
-        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) {
+		param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0)
+		         | (test_bit(LED_NUML,    atkbd->dev.led) ? 2 : 0)
+ 		         | (test_bit(LED_CAPSL,   atkbd->dev.led) ? 4 : 0);
+		
 		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));
+		if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
+			return -1;
 	}
 
-	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-16 09:37:55.927037968 +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 13:16:09.000000000 +0000
+++ source/drivers/input/keyboard/sunkbd.c	2004-03-16 09:37:55.928037816 +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 14:46:14.000000000 +0000
+++ source/drivers/input/misc/Kconfig	2004-03-16 09:37:55.928037816 +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-16 09:37:55.929037664 +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-16 09:37:55.929037664 +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-16 09:37:55.930037512 +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 09:07:33.000000000 +0000
+++ source/drivers/input/mouse/Makefile	2004-03-16 09:37:55.930037512 +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-16 09:37:55.930037512 +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-16 09:37:55.931037360 +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-16 09:37:55.931037360 +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);
@@ -637,13 +643,15 @@ static int psmouse_reconnect(struct seri
 {
 	struct psmouse *psmouse = serio->private;
 	struct serio_dev *dev = serio->dev;
-	int old_type = psmouse->type;
+	int old_type;
 
-	if (!dev) {
+	if (!dev || !psmouse) {
 		printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n");
 		return -1;
 	}
 
+	old_type = psmouse->type;
+
 	psmouse->state = PSMOUSE_NEW_DEVICE;
 	psmouse->type = psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = 0;
 	if (psmouse->reconnect) {
--- diff/drivers/input/mouse/synaptics.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/input/mouse/synaptics.c	2004-03-16 09:37:55.932037208 +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-16 09:37:55.933037056 +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 14:46:14.000000000 +0000
+++ source/drivers/input/serio/Kconfig	2004-03-16 09:37:55.933037056 +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 09:07:29.000000000 +0000
+++ source/drivers/input/serio/Makefile	2004-03-16 09:37:55.933037056 +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-io.h	2003-06-30 09:07:29.000000000 +0000
+++ source/drivers/input/serio/i8042-io.h	2004-03-16 09:37:55.934036904 +0000
@@ -25,6 +25,9 @@
 #elif defined(__ia64__)
 # define I8042_KBD_IRQ isa_irq_to_vector(1)
 # define I8042_AUX_IRQ isa_irq_to_vector(12)
+#elif defined(__arm__)
+/* defined in include/asm-arm/arch-xxx/irqs.h */
+#include <asm/irq.h>
 #else
 # define I8042_KBD_IRQ	1
 # define I8042_AUX_IRQ	12
--- diff/drivers/input/serio/i8042.c	2004-03-11 10:20:24.000000000 +0000
+++ source/drivers/input/serio/i8042.c	2004-03-16 09:37:55.935036752 +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-16 09:37:55.935036752 +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/isdn/hisax/hfc_usb.c	2004-03-11 10:20:24.000000000 +0000
+++ source/drivers/isdn/hisax/hfc_usb.c	2004-03-16 09:37:55.936036600 +0000
@@ -1349,9 +1349,11 @@ static int __devinit hfc_usb_probe(struc
 {
 	struct usb_device *dev= interface_to_usbdev(intf);
 	hfcusb_data *context;
-	struct usb_host_interface *iface = intf->altsetting + intf->act_altsetting;
+	struct usb_host_interface *iface = intf->cur_altsetting;
+	struct usb_host_interface *iface_used = NULL;
 	struct usb_host_endpoint *ep;
-	int i, idx, probe_alt_setting,vend_idx, cfg_used, *vcf, attr, cfg_found, cidx, ep_addr;
+	int ifnum = iface->desc.bInterfaceNumber;
+	int i, idx, alt_idx, probe_alt_setting, vend_idx, cfg_used, *vcf, attr, cfg_found, cidx, ep_addr;
 	int cmptbl[16],small_match,iso_packet_size,packet_size,alt_used=0;
 
 //        usb_show_device(dev);
@@ -1366,7 +1368,7 @@ static int __devinit hfc_usb_probe(struc
 
 #ifdef VERBOSE_USB_DEBUG	
 	printk(KERN_INFO "HFC-USB: probing interface(%d) actalt(%d) minor(%d)\n",
-		intf->altsetting->desc.bInterfaceNumber, intf->act_altsetting, intf->minor);
+		ifnum, iface->desc.bAlternateSetting, intf->minor);
 #endif
 
 	if (vend_idx != 0xffff) {
@@ -1374,14 +1376,15 @@ static int __devinit hfc_usb_probe(struc
 		printk(KERN_INFO "HFC-USB: found vendor idx:%d  name:%s\n",vend_idx,vdata[vend_idx].vend_name);
 #endif
 		/* if vendor and product ID is OK, start probing a matching alternate setting ... */
-		probe_alt_setting = 0;
+		alt_idx = 0;
 		small_match=0xffff;
 		// default settings
 		iso_packet_size=16;
 		packet_size=64;
 
-		while(probe_alt_setting < intf->num_altsetting) {
-			iface = intf->altsetting + probe_alt_setting;
+		while (alt_idx < intf->num_altsetting) {
+			iface = intf->altsetting + alt_idx;
+			probe_alt_setting = iface->desc.bAlternateSetting;
 			cfg_used=0;
 
 #ifdef VERBOSE_USB_DEBUG
@@ -1395,7 +1398,7 @@ static int __devinit hfc_usb_probe(struc
 
 #ifdef VERBOSE_USB_DEBUG
 				printk(KERN_INFO "HFC-USB: (if=%d alt=%d cfg_used=%d)\n",
-					probe_alt_setting, intf->act_altsetting,cfg_used);
+					ifnum, probe_alt_setting, cfg_used);
 #endif
 				// copy table
 				memcpy(cmptbl,vcf,16*sizeof(int));
@@ -1448,6 +1451,7 @@ static int __devinit hfc_usb_probe(struc
 					if (cfg_used < small_match) {
 						small_match = cfg_used;
 						alt_used = probe_alt_setting;
+						iface_used = iface;
 					}
 #ifdef VERBOSE_USB_DEBUG
 					printk(KERN_INFO "HFC-USB: small_match=%x %x\n", small_match, alt_used);
@@ -1457,15 +1461,14 @@ static int __devinit hfc_usb_probe(struc
 				cfg_used++;
 			}
 
-			probe_alt_setting++;
-		}		/* (probe_alt_setting < intf->num_altsetting) */
+			alt_idx++;
+		}		/* (alt_idx < intf->num_altsetting) */
 #ifdef VERBOSE_USB_DEBUG
 		printk(KERN_INFO "HFC-USB: final small_match=%x alt_used=%x\n",small_match, alt_used);
 #endif
 		// yiipiee, we found a valid config
 		if (small_match != 0xffff) {
-			intf->act_altsetting = alt_used;
-			iface = intf->altsetting + intf->act_altsetting;
+			iface = iface_used;
 
 			if (!(context = kmalloc(sizeof(hfcusb_data), GFP_KERNEL)))
 				return(-ENOMEM);  /* got no mem */
@@ -1542,8 +1545,8 @@ static int __devinit hfc_usb_probe(struc
 
 			// now share our luck
 			context->dev = dev;						/* save device */
-			context->if_used = intf->altsetting->desc.bInterfaceNumber;	/* save used interface */
-			context->alt_used = intf->act_altsetting;			/* and alternate config */
+			context->if_used = ifnum;					/* save used interface */
+			context->alt_used = alt_used;					/* and alternate config */
 			context->ctrl_paksize = dev->descriptor.bMaxPacketSize0;	/* control size */
 			context->cfg_used=vcf[16];					// store used config
 			context->vend_idx=vend_idx;					// store found vendor
--- diff/drivers/macintosh/Kconfig	2004-03-11 10:20:24.000000000 +0000
+++ source/drivers/macintosh/Kconfig	2004-03-16 09:37:55.937036448 +0000
@@ -1,5 +1,6 @@
 
 menu "Macintosh device drivers"
+	depends on PPC || MAC
 
 config ADB
 	bool "Apple Desktop Bus (ADB) support"
--- diff/drivers/macintosh/mediabay.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/macintosh/mediabay.c	2004-03-16 09:37:55.938036296 +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/macintosh/therm_pm72.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/macintosh/therm_pm72.c	2004-03-16 09:37:55.939036144 +0000
@@ -2,7 +2,7 @@
  * Device driver for the thermostats & fan controller of  the
  * Apple G5 "PowerMac7,2" desktop machines.
  *
- * (c) Copyright IBM Corp. 2003
+ * (c) Copyright IBM Corp. 2003-2004
  *
  * Maintained by: Benjamin Herrenschmidt
  *                <benh@kernel.crashing.org>
@@ -45,7 +45,7 @@
  *        - Add things like /sbin/overtemp for non-critical
  *          overtemp conditions so userland can take some policy
  *          decisions, like slewing down CPUs
- *	  - Deal with fan failures
+ *	  - Deal with fan and i2c failures in a better way
  *
  * History:
  *
@@ -63,9 +63,16 @@
  *	- Move back statics definitions to .c file
  *	- Avoid calling schedule_timeout with a negative number
  *
- *  Dev. 18, 2003 : 0.8
+ *  Dec. 18, 2003 : 0.8
  *	- Fix typo when reading back fan speed on 2 CPU machines
  *
+ *  Mar. 11, 2004 : 0.9
+ *	- Rework code accessing the ADC chips, make it more robust and
+ *	  closer to the chip spec. Also make sure it is configured properly,
+ *        I've seen yet unexplained cases where on startup, I would have stale
+ *        values in the configuration register
+ *	- Switch back to use of target fan speed for PID, thus lowering
+ *        pressure on i2c
  */
 
 #include <linux/config.h>
@@ -94,14 +101,14 @@
 
 #include "therm_pm72.h"
 
-#define VERSION "0.8"
+#define VERSION "0.9"
 
 #undef DEBUG
 
 #ifdef DEBUG
 #define DBG(args...)	printk(args)
 #else
-#define DBG(args...)
+#define DBG(args...)	do { } while(0)
 #endif
 
 
@@ -194,14 +201,76 @@ static void detach_i2c_chip(struct i2c_c
 /*
  * Here are the i2c chip access wrappers
  */
-static int read_smon_adc(struct i2c_client *chip, int chan)
+
+static void initialize_adc(struct cpu_pid_state *state)
 {
-	int ctrl;
+	int rc;
+	u8 buf[2];
+
+	/* Read ADC the configuration register and cache it. We
+	 * also make sure Config2 contains proper values, I've seen
+	 * cases where we got stale grabage in there, thus preventing
+	 * proper reading of conv. values
+	 */
 
-	ctrl = i2c_smbus_read_byte_data(chip, 1);
-	i2c_smbus_write_byte_data(chip, 1, (ctrl & 0x1f) | (chan << 5));
-	wait_ms(1);
-	return le16_to_cpu(i2c_smbus_read_word_data(chip, 4)) >> 6;
+	/* Clear Config2 */
+	buf[0] = 5;
+	buf[1] = 0;
+	i2c_master_send(state->monitor, buf, 2);
+
+	/* Read & cache Config1 */
+	buf[0] = 1;
+	rc = i2c_master_send(state->monitor, buf, 1);
+	if (rc > 0) {
+		rc = i2c_master_recv(state->monitor, buf, 1);
+		if (rc > 0) {
+			state->adc_config = buf[0];
+			DBG("ADC config reg: %02x\n", state->adc_config);
+			/* Disable shutdown mode */
+		       	state->adc_config &= 0xfe;
+			buf[0] = 1;
+			buf[1] = state->adc_config;
+			rc = i2c_master_send(state->monitor, buf, 2);
+		}
+	}
+	if (rc <= 0)
+		printk(KERN_ERR "therm_pm72: Error reading ADC config"
+		       " register !\n");
+}
+
+static int read_smon_adc(struct cpu_pid_state *state, int chan)
+{
+	int rc, data, tries = 0;
+	u8 buf[2];
+
+	for (;;) {
+		/* Set channel */
+		buf[0] = 1;
+		buf[1] = (state->adc_config & 0x1f) | (chan << 5);
+		rc = i2c_master_send(state->monitor, buf, 2);
+		if (rc <= 0)
+			goto error;
+		/* Wait for convertion */
+		wait_ms(1);
+		/* Switch to data register */
+		buf[0] = 4;
+		rc = i2c_master_send(state->monitor, buf, 1);
+		if (rc <= 0)
+			goto error;
+		/* Read result */
+		rc = i2c_master_recv(state->monitor, buf, 2);
+		if (rc < 0)
+			goto error;
+		data = ((u16)buf[0]) << 8 | (u16)buf[1];
+		return data >> 6;
+	error:
+		DBG("Error reading ADC, retrying...\n");
+		if (++tries > 10) {
+			printk(KERN_ERR "therm_pm72: Error reading ADC !\n");
+			return -1;
+		}
+		wait_ms(10);
+	}
 }
 
 static int fan_read_reg(int reg, unsigned char *buf, int nb)
@@ -460,9 +529,13 @@ static void do_monitor_cpu(struct cpu_pi
 	DBG("  current rpm: %d\n", state->rpm);
 
 	/* Get some sensor readings and scale it */
-	temp = read_smon_adc(state->monitor, 1);
-	voltage = read_smon_adc(state->monitor, 3);
-	current_a = read_smon_adc(state->monitor, 4);
+	temp = read_smon_adc(state, 1);
+	if (temp == -1) {
+		state->overtemp++;
+		return;
+	}
+	voltage = read_smon_adc(state, 3);
+	current_a = read_smon_adc(state, 4);
 
 	/* Fixup temperature according to diode calibration
 	 */
@@ -476,7 +549,8 @@ static void do_monitor_cpu(struct cpu_pi
 	 * full blown immediately and try to trigger a shutdown
 	 */
 	if (temp >= ((state->mpu.tmax + 8) << 16)) {
-		printk(KERN_WARNING "Warning ! CPU %d temperature way above maximum (%d) !\n",
+		printk(KERN_WARNING "Warning ! CPU %d temperature way above maximum"
+		       " (%d) !\n",
 		       state->index, temp >> 16);
 		state->overtemp = CPU_MAX_OVERTEMP;
 	} else if (temp > (state->mpu.tmax << 16))
@@ -613,6 +687,7 @@ static int init_cpu_state(struct cpu_pid
 	state->first = 1;
 	state->rpm = 1000;
 	state->overtemp = 0;
+	state->adc_config = 0x00;
 
 	if (index == 0)
 		state->monitor = attach_i2c_chip(SUPPLY_MONITOR_ID, "CPU0_monitor");
@@ -941,9 +1016,18 @@ static int main_control_loop(void *x)
 
 	DBG("main_control_loop started\n");
 
+	down(&driver_lock);
+
 	/* Set the PCI fan once for now */
 	set_pwm_fan(SLOTS_FAN_PWM_ID, SLOTS_FAN_DEFAULT_PWM);
 
+	/* Initialize ADCs */
+	initialize_adc(&cpu_state[0]);
+	if (cpu_state[1].monitor != NULL)
+		initialize_adc(&cpu_state[1]);
+
+	up(&driver_lock);
+
 	while (state == state_attached) {
 		unsigned long elapsed, start;
 
--- diff/drivers/macintosh/therm_pm72.h	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/macintosh/therm_pm72.h	2004-03-16 09:37:55.940035992 +0000
@@ -85,7 +85,7 @@ static char * critical_overtemp_path = "
  * I'm not sure which of these Apple's algorithm is supposed
  * to use
  */
-#define RPM_PID_USE_ACTUAL_SPEED		1
+#define RPM_PID_USE_ACTUAL_SPEED		0
 
 /*
  * i2c IDs. Currently, we hard code those and assume that
@@ -220,6 +220,7 @@ struct cpu_pid_state
 	s32			current_a;
 	s32			last_temp;
 	int			first;
+	u8			adc_config;
 };
 
 /*
--- diff/drivers/mca/mca-bus.c	2003-08-26 09:00:52.000000000 +0000
+++ source/drivers/mca/mca-bus.c	2004-03-16 09:37:55.940035992 +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/dm-crypt.c	2004-03-11 10:20:24.000000000 +0000
+++ source/drivers/md/dm-crypt.c	2004-03-16 09:37:55.941035840 +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);
@@ -667,7 +668,7 @@ static int crypt_map(struct dm_target *t
 
 		/* out of memory -> run queues */
 		if (remaining)
-			blk_run_queues();
+			blk_congestion_wait(bio_data_dir(clone), HZ/100);
 	}
 
 	/* drop reference, clones could have returned before we reach this */
@@ -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	2004-03-11 10:20:24.000000000 +0000
+++ source/drivers/md/dm-ioctl.c	2004-03-16 09:37:55.943035536 +0000
@@ -33,6 +33,14 @@ struct hash_cell {
 	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];
@@ -88,30 +96,24 @@ static unsigned int hash_str(const char 
  *---------------------------------------------------------------*/
 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);
+	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 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);
+	list_for_each_entry (hc, _uuid_buckets + h, uuid_list)
 		if (!strcmp(hc->uuid, str))
 			return hc;
-	}
 
 	return NULL;
 }
@@ -415,6 +417,80 @@ static int list_devices(struct dm_ioctl 
 	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, '/')) {
@@ -935,6 +1011,7 @@ static void retrieve_deps(struct dm_tabl
 	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);
@@ -942,7 +1019,7 @@ static void retrieve_deps(struct dm_tabl
 	/*
 	 * Count the devices.
 	 */
-	list_for_each(tmp, dm_table_get_devices(table))
+	list_for_each (tmp, dm_table_get_devices(table))
 		count++;
 
 	/*
@@ -959,10 +1036,8 @@ static void retrieve_deps(struct dm_tabl
 	 */
 	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);
+	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;
 }
@@ -1045,7 +1120,9 @@ static ioctl_fn lookup_ioctl(unsigned in
 		{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_TABLE_STATUS_CMD, table_status},
+
+		{DM_LIST_VERSIONS_CMD, list_versions}
 	};
 
 	return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn;
@@ -1119,7 +1196,9 @@ static int validate_params(uint cmd, str
 	param->flags &= ~DM_BUFFER_FULL_FLAG;
 
 	/* Ignores parameters */
-	if (cmd == DM_REMOVE_ALL_CMD || cmd == DM_LIST_DEVICES_CMD)
+	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 */
--- diff/drivers/md/dm-linear.c	2003-09-30 14:46:14.000000000 +0000
+++ source/drivers/md/dm-linear.c	2004-03-16 09:37:55.943035536 +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-11 10:20:24.000000000 +0000
+++ source/drivers/md/dm-stripe.c	2004-03-16 09:37:55.944035384 +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-11 10:20:24.000000000 +0000
+++ source/drivers/md/dm-table.c	2004-03-16 09:37:55.944035384 +0000
@@ -279,6 +279,9 @@ void dm_table_get(struct dm_table *t)
 
 void dm_table_put(struct dm_table *t)
 {
+	if (!t)
+		return;
+
 	if (atomic_dec_and_test(&t->holders))
 		table_destroy(t);
 }
@@ -329,13 +332,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 +632,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 +660,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 +744,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,9 +870,41 @@ 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;
+}
+
+void dm_table_unplug_all(struct dm_table *t)
+{
+	struct list_head *d, *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);
+
+		if (q->unplug_fn) {
+			set_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags);
+			q->unplug_fn(q);
+		}
+	}
+}
 
 EXPORT_SYMBOL(dm_vcalloc);
 EXPORT_SYMBOL(dm_get_device);
 EXPORT_SYMBOL(dm_put_device);
 EXPORT_SYMBOL(dm_table_event);
 EXPORT_SYMBOL(dm_table_get_mode);
+EXPORT_SYMBOL(dm_table_put);
+EXPORT_SYMBOL(dm_table_get);
+EXPORT_SYMBOL(dm_table_unplug_all);
--- diff/drivers/md/dm-target.c	2003-06-30 09:07:21.000000000 +0000
+++ source/drivers/md/dm-target.c	2004-03-16 09:37:55.945035232 +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-11 10:20:24.000000000 +0000
+++ source/drivers/md/dm.c	2004-03-16 09:37:55.947034928 +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 map_lock;
 	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.
  */
@@ -202,6 +238,24 @@ static int queue_io(struct mapped_device
 	return 0;		/* deferred successfully */
 }
 
+/*
+ * Everyone (including functions in this file), should use this
+ * function to access the md->map field, and make sure they call
+ * dm_table_put() when finished.
+ */
+struct dm_table *dm_get_table(struct mapped_device *md)
+{
+	struct dm_table *t;
+
+	read_lock(&md->map_lock);
+	t = md->map;
+	if (t)
+		dm_table_get(t);
+	read_unlock(&md->map_lock);
+
+	return t;
+}
+
 /*-----------------------------------------------------------------
  * CRUD START:
  *   A more elegant soln is in the works that uses the queue
@@ -232,17 +286,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 +330,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,26 +341,30 @@ 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 {
 	struct mapped_device *md;
+	struct dm_table *map;
 	struct bio *bio;
 	struct dm_io *io;
 	sector_t sector;
@@ -346,8 +418,17 @@ static struct bio *clone_bio(struct bio 
 static void __clone_and_map(struct clone_info *ci)
 {
 	struct bio *clone, *bio = ci->bio;
-	struct dm_target *ti = dm_table_find_target(ci->md->map, ci->sector);
+	struct dm_target *ti = dm_table_find_target(ci->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 +437,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 +460,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,16 +475,20 @@ 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;
-		ti = dm_table_find_target(ci->md->map, ci->sector);
+		ti = dm_table_find_target(ci->map, ci->sector);
 
 		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;
@@ -418,6 +503,12 @@ static void __split_bio(struct mapped_de
 {
 	struct clone_info ci;
 
+	ci.map = dm_get_table(md);
+	if (!ci.map) {
+		bio_io_error(bio, bio->bi_size);
+		return;
+	}
+
 	ci.md = md;
 	ci.bio = bio;
 	ci.io = alloc_io(md);
@@ -435,12 +526,12 @@ static void __split_bio(struct mapped_de
 
 	/* drop the extra reference count */
 	dec_pending(ci.io, 0);
+	dm_table_put(ci.map);
 }
 /*-----------------------------------------------------------------
  * CRUD END
  *---------------------------------------------------------------*/
 
-
 /*
  * The request function that just remaps the bio built up by
  * dm_merge_bvec.
@@ -479,16 +570,38 @@ 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);
 	up_read(&md->lock);
 	return 0;
 }
 
+static void dm_unplug_all(request_queue_t *q)
+{
+	struct mapped_device *md = q->queuedata;
+	struct dm_table *map = dm_get_table(md);
+
+	clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags);
+	if (map) {
+		dm_table_unplug_all(map);
+		dm_table_put(map);
+	}
+}
+
+static int dm_any_congested(void *congested_data, int bdi_bits)
+{
+	int r;
+	struct mapped_device *md = (struct mapped_device *) congested_data;
+	struct dm_table *map = dm_get_table(md);
+
+	if (!map || test_bit(DMF_BLOCK_IO, &md->flags))
+		r = bdi_bits;
+	else
+		r = dm_table_any_congested(map, bdi_bits);
+
+	dm_table_put(map);
+	return r;
+}
+
 /*-----------------------------------------------------------------
  * A bitset is used to keep track of allocated minor numbers.
  *---------------------------------------------------------------*/
@@ -560,6 +673,7 @@ static struct mapped_device *alloc_dev(u
 
 	memset(md, 0, sizeof(*md));
 	init_rwsem(&md->lock);
+	rwlock_init(&md->map_lock);
 	atomic_set(&md->holders, 1);
 
 	md->queue = blk_alloc_queue(GFP_KERNEL);
@@ -567,16 +681,24 @@ 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->queue->unplug_fn = dm_unplug_all;
 
 	md->io_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
 				     mempool_free_slab, _io_cache);
  	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 +714,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 +729,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,28 +768,34 @@ 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;
 
-	dm_table_event_callback(md->map, event_callback, md);
+	write_lock(&md->map_lock);
+	md->map = t;
+	write_unlock(&md->map_lock);
 
 	dm_table_get(t);
+	dm_table_event_callback(md->map, event_callback, md);
 	dm_table_set_restrictions(t, q);
 	return 0;
 }
 
 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->map_lock);
 	md->map = NULL;
+	write_unlock(&md->map_lock);
+	dm_table_put(map);
 }
 
 /*
@@ -701,25 +831,29 @@ void dm_get(struct mapped_device *md)
 
 void dm_put(struct mapped_device *md)
 {
+	struct dm_table *map = dm_get_table(md);
+
 	if (atomic_dec_and_test(&md->holders)) {
-		if (!test_bit(DMF_SUSPENDED, &md->flags) && md->map)
-			dm_table_suspend_targets(md->map);
+		if (!test_bit(DMF_SUSPENDED, &md->flags) && map)
+			dm_table_suspend_targets(map);
 		__unbind(md);
 		free_dev(md);
 	}
+
+	dm_table_put(map);
 }
 
 /*
- * 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);
+		__split_bio(md, c);
 		c = n;
 	}
 }
@@ -757,6 +891,7 @@ int dm_swap_table(struct mapped_device *
  */
 int dm_suspend(struct mapped_device *md)
 {
+	struct dm_table *map;
 	DECLARE_WAITQUEUE(wait, current);
 
 	down_write(&md->lock);
@@ -774,11 +909,17 @@ int dm_suspend(struct mapped_device *md)
 	add_wait_queue(&md->wait, &wait);
 	up_write(&md->lock);
 
+	/* unplug */
+	map = dm_get_table(md);
+	if (map) {
+		dm_table_unplug_all(map);
+		dm_table_put(map);
+	}
+
 	/*
 	 * Then we wait for the already mapped ios to
 	 * complete.
 	 */
-	blk_run_queues();
 	while (1) {
 		set_current_state(TASK_INTERRUPTIBLE);
 
@@ -792,8 +933,11 @@ int dm_suspend(struct mapped_device *md)
 	down_write(&md->lock);
 	remove_wait_queue(&md->wait, &wait);
 	set_bit(DMF_SUSPENDED, &md->flags);
-	if (md->map)
-		dm_table_suspend_targets(md->map);
+
+	map = dm_get_table(md);
+	if (map)
+		dm_table_suspend_targets(map);
+	dm_table_put(map);
 	up_write(&md->lock);
 
 	return 0;
@@ -802,23 +946,26 @@ int dm_suspend(struct mapped_device *md)
 int dm_resume(struct mapped_device *md)
 {
 	struct bio *def;
+	struct dm_table *map = dm_get_table(md);
 
 	down_write(&md->lock);
-	if (!md->map ||
+	if (!map ||
 	    !test_bit(DMF_SUSPENDED, &md->flags) ||
-	    !dm_table_get_size(md->map)) {
+	    !dm_table_get_size(map)) {
 		up_write(&md->lock);
+		dm_table_put(map);
 		return -EINVAL;
 	}
 
-	dm_table_resume_targets(md->map);
+	dm_table_resume_targets(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();
+	dm_table_unplug_all(md->map);
+	dm_table_put(map);
 
 	return 0;
 }
@@ -868,19 +1015,6 @@ struct gendisk *dm_disk(struct mapped_de
 	return md->disk;
 }
 
-struct dm_table *dm_get_table(struct mapped_device *md)
-{
-	struct dm_table *t;
-
-	down_read(&md->lock);
-	t = md->map;
-	if (t)
-		dm_table_get(t);
-	up_read(&md->lock);
-
-	return t;
-}
-
 int dm_suspended(struct mapped_device *md)
 {
 	return test_bit(DMF_SUSPENDED, &md->flags);
--- diff/drivers/md/dm.h	2004-03-11 10:20:24.000000000 +0000
+++ source/drivers/md/dm.h	2004-03-16 09:37:55.948034776 +0000
@@ -115,6 +115,8 @@ 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);
+void dm_table_unplug_all(struct dm_table *t);
 
 /*-----------------------------------------------------------------
  * A registry of target types.
@@ -123,6 +125,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-11 10:20:24.000000000 +0000
+++ source/drivers/md/md.c	2004-03-16 09:37:55.950034472 +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];
@@ -160,6 +160,28 @@ static int md_fail_request (request_queu
 	return 0;
 }
 
+static void md_unplug_all(request_queue_t *q)
+{
+	mddev_t *mddev = q->queuedata;
+	struct list_head *tmp;
+	mdk_rdev_t *rdev;
+
+	clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags);
+
+	/*
+	 * this list iteration is done without any locking in md?!
+	 */
+	ITERATE_RDEV(mddev, rdev, tmp) {
+		request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
+
+		if (r_queue->unplug_fn) {
+			set_bit(QUEUE_FLAG_PLUGGED, &r_queue->queue_flags);
+			r_queue->unplug_fn(r_queue);
+		}
+	}
+
+}
+
 static inline mddev_t *mddev_get(mddev_t *mddev)
 {
 	atomic_inc(&mddev->active);
@@ -335,6 +357,8 @@ static int sync_page_io(struct block_dev
 	struct bio_vec vec;
 	struct completion event;
 
+	rw |= (1 << BIO_RW_SYNC);
+
 	bio_init(&bio);
 	bio.bi_io_vec = &vec;
 	vec.bv_page = page;
@@ -349,7 +373,6 @@ static int sync_page_io(struct block_dev
 	bio.bi_private = &event;
 	bio.bi_end_io = bi_complete;
 	submit_bio(rw, &bio);
-	blk_run_queues();
 	wait_for_completion(&event);
 
 	return test_bit(BIO_UPTODATE, &bio.bi_flags);
@@ -1447,7 +1470,7 @@ abort:
 	return 1;
 }
 
-static int mdp_major = 0;
+int mdp_major = 0;
 
 static struct kobject *md_probe(dev_t dev, int *part, void *data)
 {
@@ -1644,6 +1667,7 @@ static int do_md_run(mddev_t * mddev)
 	 */
 	mddev->queue->queuedata = mddev;
 	mddev->queue->make_request_fn = mddev->pers->make_request;
+	mddev->queue->unplug_fn = md_unplug_all;
 
 	mddev->changed = 1;
 	return 0;
@@ -1792,7 +1816,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 +1849,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 +1951,7 @@ static int autostart_array(dev_t startde
 	/*
 	 * possibly return codes
 	 */
-	autorun_devices();
+	autorun_devices(0);
 	return 0;
 
 }
@@ -2407,7 +2436,7 @@ static int md_ioctl(struct inode *inode,
 #ifndef MODULE
 		case RAID_AUTORUN:
 			err = 0;
-			autostart_arrays();
+			autostart_arrays(arg);
 			goto done;
 #endif
 		default:;
@@ -2713,7 +2742,7 @@ int md_thread(void * arg)
 		run = thread->run;
 		if (run) {
 			run(thread->mddev);
-			blk_run_queues();
+			blk_run_queue(thread->mddev->queue);
 		}
 		if (signal_pending(current))
 			flush_signals(current);
@@ -3281,7 +3310,7 @@ static void md_do_sync(mddev_t *mddev)
 		    test_bit(MD_RECOVERY_ERR, &mddev->recovery))
 			break;
 
-		blk_run_queues();
+		blk_run_queue(mddev->queue);
 
 	repeat:
 		if (jiffies >= mark[last_mark] + SYNC_MARK_STEP ) {
@@ -3577,7 +3606,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 +3631,7 @@ static void autostart_arrays(void)
 	}
 	dev_cnt = 0;
 
-	autorun_devices();
+	autorun_devices(part);
 }
 
 #endif
--- diff/drivers/md/raid0.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/md/raid0.c	2004-03-16 09:37:55.951034320 +0000
@@ -313,8 +313,8 @@ static int raid0_run (mddev_t *mddev)
 
 	/* calculate the max read-ahead size.
 	 * For read-ahead of large files to be effective, we need to
-	 * readahead at least a whole stripe. i.e. number of devices
-	 * multiplied by chunk size.
+	 * readahead at least twice a whole stripe. i.e. number of devices
+	 * multiplied by chunk size times 2.
 	 * If an individual device has an ra_pages greater than the
 	 * chunk size, then we will not drive that device as hard as it
 	 * wants.  We consider this a configuration error: a larger
@@ -322,8 +322,8 @@ static int raid0_run (mddev_t *mddev)
 	 */
 	{
 		int stripe = mddev->raid_disks * mddev->chunk_size / PAGE_CACHE_SIZE;
-		if (mddev->queue->backing_dev_info.ra_pages < stripe)
-			mddev->queue->backing_dev_info.ra_pages = stripe;
+		if (mddev->queue->backing_dev_info.ra_pages < 2* stripe)
+			mddev->queue->backing_dev_info.ra_pages = 2* stripe;
 	}
 
 
--- diff/drivers/md/raid1.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/md/raid1.c	2004-03-16 09:37:55.952034168 +0000
@@ -451,6 +451,7 @@ rb_out:
 
 static void device_barrier(conf_t *conf, sector_t sect)
 {
+	blk_run_queue(conf->mddev->queue);
 	spin_lock_irq(&conf->resync_lock);
 	wait_event_lock_irq(conf->wait_idle, !waitqueue_active(&conf->wait_resume), conf->resync_lock);
 	
@@ -478,6 +479,7 @@ static int make_request(request_queue_t 
 	 * thread has put up a bar for new requests.
 	 * Continue immediately if no resync is active currently.
 	 */
+	blk_run_queue(conf->mddev->queue);
 	spin_lock_irq(&conf->resync_lock);
 	wait_event_lock_irq(conf->wait_resume, !conf->barrier, conf->resync_lock);
 	conf->nr_pending++;
@@ -644,6 +646,7 @@ static void print_conf(conf_t *conf)
 
 static void close_sync(conf_t *conf)
 {
+	blk_run_queue(conf->mddev->queue);
 	spin_lock_irq(&conf->resync_lock);
 	wait_event_lock_irq(conf->wait_resume, !conf->barrier, conf->resync_lock);
 	spin_unlock_irq(&conf->resync_lock);
--- diff/drivers/md/raid5.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/md/raid5.c	2004-03-16 09:37:55.954033864 +0000
@@ -249,6 +249,7 @@ static struct stripe_head *get_active_st
 				break;
 			if (!sh) {
 				conf->inactive_blocked = 1;
+				blk_run_queue(conf->mddev->queue);
 				wait_event_lock_irq(conf->wait_for_stripe,
 						    !list_empty(&conf->inactive_list) &&
 						    (atomic_read(&conf->active_stripes) < (NR_STRIPES *3/4)
@@ -1292,9 +1293,8 @@ static inline void raid5_activate_delaye
 		}
 	}
 }
-static void raid5_unplug_device(void *data)
+static void raid5_unplug_device(request_queue_t *q)
 {
-	request_queue_t *q = data;
 	mddev_t *mddev = q->queuedata;
 	raid5_conf_t *conf = mddev_to_conf(mddev);
 	unsigned long flags;
@@ -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(1);
 	}
 	spin_lock(&sh->lock);	
 	set_bit(STRIPE_SYNCING, &sh->state);
@@ -1602,14 +1603,14 @@ memory = conf->max_nr_stripes * (sizeof(
 
 	print_raid5_conf(conf);
 
-	/* read-ahead size must cover a whole stripe, which is
-	 * (n-1) * chunksize where 'n' is the number of raid devices
+	/* read-ahead size must cover two whole stripes, which is
+	 * 2 * (n-1) * chunksize where 'n' is the number of raid devices
 	 */
 	{
 		int stripe = (mddev->raid_disks-1) * mddev->chunk_size
 			/ PAGE_CACHE_SIZE;
-		if (mddev->queue->backing_dev_info.ra_pages < stripe)
-			mddev->queue->backing_dev_info.ra_pages = stripe;
+		if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
+			mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
 	}
 
 	/* Ok, everything is just fine now */
--- diff/drivers/md/raid6main.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/md/raid6main.c	2004-03-16 09:37:55.956033560 +0000
@@ -1454,9 +1454,8 @@ static inline void raid6_activate_delaye
 		}
 	}
 }
-static void raid6_unplug_device(void *data)
+static void raid6_unplug_device(request_queue_t *q)
 {
-	request_queue_t *q = data;
 	mddev_t *mddev = q->queuedata;
 	raid6_conf_t *conf = mddev_to_conf(mddev);
 	unsigned long flags;
@@ -1571,7 +1570,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(1);
 	}
 	spin_lock(&sh->lock);
 	set_bit(STRIPE_SYNCING, &sh->state);
@@ -1771,14 +1771,14 @@ static int run (mddev_t *mddev)
 
 	print_raid6_conf(conf);
 
-	/* read-ahead size must cover a whole stripe, which is
-	 * (n-2) * chunksize where 'n' is the number of raid devices
+	/* read-ahead size must cover two whole stripes, which is
+	 * 2 * (n-2) * chunksize where 'n' is the number of raid devices
 	 */
 	{
 		int stripe = (mddev->raid_disks-2) * mddev->chunk_size
 			/ PAGE_CACHE_SIZE;
-		if (mddev->queue->backing_dev_info.ra_pages < stripe)
-			mddev->queue->backing_dev_info.ra_pages = stripe;
+		if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
+			mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
 	}
 
 	/* Ok, everything is just fine now */
--- diff/drivers/media/dvb/frontends/alps_tdlb7.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/media/dvb/frontends/alps_tdlb7.c	2004-03-16 09:37:55.958033256 +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-11 10:20:25.000000000 +0000
+++ source/drivers/media/dvb/frontends/sp887x.c	2004-03-16 09:37:55.959033104 +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-11 10:20:25.000000000 +0000
+++ source/drivers/media/dvb/frontends/tda1004x.c	2004-03-16 09:37:55.960032952 +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/video-buf.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/media/video/video-buf.c	2004-03-16 09:37:55.961032800 +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-11 10:20:25.000000000 +0000
+++ source/drivers/message/fusion/Kconfig	2004-03-16 09:37:55.961032800 +0000
@@ -3,7 +3,7 @@ menu "Fusion MPT device support"
 
 config FUSION
 	tristate "Fusion MPT (base + ScsiHost) drivers"
-	depends on BLK_DEV_SD && PCI
+	depends on PCI
 	---help---
 	  LSI Logic Fusion(TM) Message Passing Technology (MPT) device support
 	  provides high performance SCSI host initiator, and LAN [1] interface
@@ -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/Makefile	2003-02-13 11:46:52.000000000 +0000
+++ source/drivers/message/fusion/Makefile	2004-03-16 09:37:55.962032648 +0000
@@ -17,10 +17,16 @@ EXTRA_CFLAGS += ${MPT_CFLAGS}
 
 # Fusion MPT drivers; recognized debug defines...
 #  MPT general:
-#EXTRA_CFLAGS += -DDEBUG
+#EXTRA_CFLAGS += -DMPT_DEBUG_SCSI
 #EXTRA_CFLAGS += -DMPT_DEBUG
 #EXTRA_CFLAGS += -DMPT_DEBUG_MSG_FRAME
 #EXTRA_CFLAGS += -DMPT_DEBUG_SG
+
+# This is a temporary fix for the reply/request fifo
+# for some 64bit archs. Uncommenting this line
+# will place the fifo's in 32bit space
+#EXTRA_CFLAGS += -DMPTBASE_MEM_ALLOC_FIFO_FIX
+
 #
 # driver/module specifics...
 #
--- diff/drivers/message/fusion/isense.c	2004-01-19 10:22:57.000000000 +0000
+++ source/drivers/message/fusion/isense.c	2004-03-16 09:37:55.962032648 +0000
@@ -5,7 +5,7 @@
  *      Error Report logging output.  This module implements SCSI-3
  *      Opcode lookup and a sorted table of SCSI-3 ASC/ASCQ strings.
  *
- *  Copyright (c) 1991-2003 Steven J. Ralston
+ *  Copyright (c) 1991-2004 Steven J. Ralston
  *  Written By: Steven J. Ralston
  *  (yes I wrote some of the orig. code back in 1991!)
  *  (mailto:sjralston1@netscape.net)
@@ -66,7 +66,7 @@
 #endif
 
 #define MODULEAUTHOR "Steven J. Ralston"
-#define COPYRIGHT "Copyright (c) 2001-2003 " MODULEAUTHOR
+#define COPYRIGHT "Copyright (c) 2001-2004 " MODULEAUTHOR
 #include "mptbase.h"
 
 #include "isense.h"
--- diff/drivers/message/fusion/linux_compat.h	2003-09-17 11:28:07.000000000 +0000
+++ source/drivers/message/fusion/linux_compat.h	2004-03-16 09:37:55.963032496 +0000
@@ -15,25 +15,7 @@
 #define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 #endif
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-#define SET_NICE(current,x)	do {(current)->nice = (x);} while (0)
-#else
-#define SET_NICE(current,x)
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
-#define pci_enable_device(pdev)	(0)
-#define SCSI_DATA_UNKNOWN	0
-#define SCSI_DATA_WRITE		1
-#define SCSI_DATA_READ		2
-#define SCSI_DATA_NONE		3
-#endif
-
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-#define pci_set_dma_mask(pdev, mask)	(0)
-#define scsi_set_pci_device(sh, pdev)	(0)
-#endif
+#define SET_NICE(current,x) do {(current)->nice = (x);} while (0)
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
 #	if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
@@ -147,31 +129,9 @@ typedef void (*__cleanup_module_func_t)(
 
 
 /* PCI/driver subsystem { */
-#if 0	/* FIXME Don't know what to use to check for the proper kernel version */
-#define DEVICE_COUNT_RESOURCE           6
-#define PCI_BASEADDR_FLAGS(idx)         base_address[idx]
-#define PCI_BASEADDR_START(idx)         base_address[idx] & ~0xFUL
-/*
- * We have to keep track of the original value using
- * a temporary, and not by just sticking pdev->base_address[x]
- * back.  pdev->base_address[x] is an opaque cookie that can
- * be used by the PCI implementation on a given Linux port
- * for any purpose. -DaveM
- */
-#define PCI_BASEADDR_SIZE(__pdev, __idx) \
-({	unsigned int size, tmp; \
-	pci_read_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), &tmp); \
-	pci_write_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), 0xffffffff); \
-	pci_read_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), &size); \
-	pci_write_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), tmp); \
-	(4 - size); \
-})
-#else
 #define PCI_BASEADDR_FLAGS(idx)         resource[idx].flags
 #define PCI_BASEADDR_START(idx)         resource[idx].start
 #define PCI_BASEADDR_SIZE(dev,idx)      (dev)->resource[idx].end - (dev)->resource[idx].start + 1
-#endif		/* } ifndef 0 */
-
 
 /* Compatability for the 2.3.x PCI DMA API. */
 #ifndef PCI_DMA_BIDIRECTIONAL
@@ -227,54 +187,10 @@ static __inline__ int __get_order(unsign
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif /* PCI_DMA_BIDIRECTIONAL */
 
-/*
- *  With the new command queuing code in the SCSI mid-layer we no longer have
- *  to hold the io_request_lock spin lock when calling the scsi_done routine.
- *  For now we only do this with the 2.5.1 kernel or newer.
- */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1)
-        #define MPT_HOST_LOCK(flags)
-        #define MPT_HOST_UNLOCK(flags)
-#else
-        #define MPT_HOST_LOCK(flags) \
-                spin_lock_irqsave(&io_request_lock, flags)
-        #define MPT_HOST_UNLOCK(flags) \
-                spin_unlock_irqrestore(&io_request_lock, flags)
-#endif
-
-/*
- *  We use our new error handling code if the kernel version is 2.4.18 or newer.
- */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,18)
-        #define MPT_SCSI_USE_NEW_EH
-#endif
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
 #define mpt_work_struct work_struct
 #define MPT_INIT_WORK(_task, _func, _data) INIT_WORK(_task, _func, _data)
-#else
-#define mpt_work_struct tq_struct
-#define MPT_INIT_WORK(_task, _func, _data) \
-({	(_task)->sync = 0; \
-	(_task)->routine = (_func); \
-	(_task)->data = (void *) (_data); \
-})
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
-#define mptscsih_sync_irq(_irq) synchronize_irq(_irq)
-#else
-#define mptscsih_sync_irq(_irq) synchronize_irq()
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,58)
-#define mpt_inc_use_count()
-#define mpt_dec_use_count()
-#else
-#define mpt_inc_use_count() MOD_INC_USE_COUNT
-#define mpt_dec_use_count() MOD_DEC_USE_COUNT
-#endif
-
+#define mpt_sync_irq(_irq) synchronize_irq(_irq)
 
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif /* _LINUX_COMPAT_H */
--- diff/drivers/message/fusion/lsi/mpi.h	2002-10-16 03:27:17.000000000 +0000
+++ source/drivers/message/fusion/lsi/mpi.h	2004-03-16 09:37:55.964032344 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *  Copyright (c) 2000-2003 LSI Logic Corporation.
  *
  *
- *           Name:  MPI.H
+ *           Name:  mpi.h
  *          Title:  MPI Message independent structures and definitions
  *  Creation Date:  July 27, 2000
  *
- *    MPI.H Version:  01.02.07
+ *    mpi.h Version:  01.05.xx
  *
  *  Version History
  *  ---------------
@@ -48,6 +48,10 @@
  *  05-31-02  01.02.05  Bumped MPI_HEADER_VERSION_UNIT.
  *  07-12-02  01.02.06  Added define for MPI_FUNCTION_MAILBOX.
  *  09-16-02  01.02.07  Bumped value for MPI_HEADER_VERSION_UNIT.
+ *  11-15-02  01.02.08  Added define MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX and
+ *                      obsoleted define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX.
+ *  04-01-03  01.02.09  New IOCStatus code: MPI_IOCSTATUS_FC_EXCHANGE_CANCELED
+ *  06-26-03  01.02.10  Bumped MPI_HEADER_VERSION_UNIT value.
  *  --------------------------------------------------------------------------
  */
 
@@ -62,7 +66,7 @@
 *****************************************************************************/
 
 #define MPI_VERSION_MAJOR                   (0x01)
-#define MPI_VERSION_MINOR                   (0x02)
+#define MPI_VERSION_MINOR                   (0x05)
 #define MPI_VERSION_MAJOR_MASK              (0xFF00)
 #define MPI_VERSION_MAJOR_SHIFT             (8)
 #define MPI_VERSION_MINOR_MASK              (0x00FF)
@@ -73,10 +77,12 @@
 #define MPI_VERSION_01_00                   (0x0100)
 #define MPI_VERSION_01_01                   (0x0101)
 #define MPI_VERSION_01_02                   (0x0102)
+#define MPI_VERSION_01_03                   (0x0103)
+#define MPI_VERSION_01_05                   (0x0105)
 /* Note: The major versions of 0xe0 through 0xff are reserved */
 
 /* versioning for this MPI header set */
-#define MPI_HEADER_VERSION_UNIT             (0x09)
+#define MPI_HEADER_VERSION_UNIT             (0x00)
 #define MPI_HEADER_VERSION_DEV              (0x00)
 #define MPI_HEADER_VERSION_UNIT_MASK        (0xFF00)
 #define MPI_HEADER_VERSION_UNIT_SHIFT       (8)
@@ -171,6 +177,8 @@
 #define MPI_REPLY_POST_FIFO_OFFSET          (0x00000044)
 #define MPI_REPLY_FREE_FIFO_OFFSET          (0x00000044)
 
+#define MPI_HI_PRI_REQUEST_QUEUE_OFFSET     (0x00000048)
+
 
 
 /*****************************************************************************
@@ -230,10 +238,6 @@
 #define MPI_FUNCTION_TARGET_ASSIST                  (0x0B)
 #define MPI_FUNCTION_TARGET_STATUS_SEND             (0x0C)
 #define MPI_FUNCTION_TARGET_MODE_ABORT              (0x0D)
-#define MPI_FUNCTION_TARGET_FC_BUF_POST_LINK_SRVC   (0x0E) /* obsolete name */
-#define MPI_FUNCTION_TARGET_FC_RSP_LINK_SRVC        (0x0F) /* obsolete name */
-#define MPI_FUNCTION_TARGET_FC_EX_SEND_LINK_SRVC    (0x10) /* obsolete name */
-#define MPI_FUNCTION_TARGET_FC_ABORT                (0x11) /* obsolete name */
 #define MPI_FUNCTION_FC_LINK_SRVC_BUF_POST          (0x0E)
 #define MPI_FUNCTION_FC_LINK_SRVC_RSP               (0x0F)
 #define MPI_FUNCTION_FC_EX_LINK_SRVC_SEND           (0x10)
@@ -251,16 +255,46 @@
 
 #define MPI_FUNCTION_MAILBOX                        (0x19)
 
+#define MPI_FUNCTION_SMP_PASSTHROUGH                (0x1A)
+#define MPI_FUNCTION_SAS_IO_UNIT_CONTROL            (0x1B)
+
+#define MPI_DIAG_BUFFER_POST                        (0x1D)
+#define MPI_DIAG_RELEASE                            (0x1E)
+
+#define MPI_FUNCTION_SCSI_IO_32                     (0x1F)
+
 #define MPI_FUNCTION_LAN_SEND                       (0x20)
 #define MPI_FUNCTION_LAN_RECEIVE                    (0x21)
 #define MPI_FUNCTION_LAN_RESET                      (0x22)
 
+#define MPI_FUNCTION_INBAND_BUFFER_POST             (0x28)
+#define MPI_FUNCTION_INBAND_SEND                    (0x29)
+#define MPI_FUNCTION_INBAND_RSP                     (0x2A)
+#define MPI_FUNCTION_INBAND_ABORT                   (0x2B)
+
 #define MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET         (0x40)
 #define MPI_FUNCTION_IO_UNIT_RESET                  (0x41)
 #define MPI_FUNCTION_HANDSHAKE                      (0x42)
 #define MPI_FUNCTION_REPLY_FRAME_REMOVAL            (0x43)
 
 
+/* standard version format */
+typedef struct _MPI_VERSION_STRUCT
+{
+    U8                      Dev;                        /* 00h */
+    U8                      Unit;                       /* 01h */
+    U8                      Minor;                      /* 02h */
+    U8                      Major;                      /* 03h */
+} MPI_VERSION_STRUCT, MPI_POINTER PTR_MPI_VERSION_STRUCT,
+  MpiVersionStruct_t, MPI_POINTER pMpiVersionStruct;
+
+typedef union _MPI_VERSION_FORMAT
+{
+    MPI_VERSION_STRUCT      Struct;
+    U32                     Word;
+} MPI_VERSION_FORMAT, MPI_POINTER PTR_MPI_VERSION_FORMAT,
+  MpiVersionFormat_t, MPI_POINTER pMpiVersionFormat_t;
+
 
 /*****************************************************************************
 *
@@ -573,44 +607,54 @@ typedef struct _MSG_DEFAULT_REPLY
 /*  Common IOCStatus values for all replies                                 */
 /****************************************************************************/
 
-#define MPI_IOCSTATUS_SUCCESS                  (0x0000)
-#define MPI_IOCSTATUS_INVALID_FUNCTION         (0x0001)
-#define MPI_IOCSTATUS_BUSY                     (0x0002)
-#define MPI_IOCSTATUS_INVALID_SGL              (0x0003)
-#define MPI_IOCSTATUS_INTERNAL_ERROR           (0x0004)
-#define MPI_IOCSTATUS_RESERVED                 (0x0005)
-#define MPI_IOCSTATUS_INSUFFICIENT_RESOURCES   (0x0006)
-#define MPI_IOCSTATUS_INVALID_FIELD            (0x0007)
-#define MPI_IOCSTATUS_INVALID_STATE            (0x0008)
+#define MPI_IOCSTATUS_SUCCESS                   (0x0000)
+#define MPI_IOCSTATUS_INVALID_FUNCTION          (0x0001)
+#define MPI_IOCSTATUS_BUSY                      (0x0002)
+#define MPI_IOCSTATUS_INVALID_SGL               (0x0003)
+#define MPI_IOCSTATUS_INTERNAL_ERROR            (0x0004)
+#define MPI_IOCSTATUS_RESERVED                  (0x0005)
+#define MPI_IOCSTATUS_INSUFFICIENT_RESOURCES    (0x0006)
+#define MPI_IOCSTATUS_INVALID_FIELD             (0x0007)
+#define MPI_IOCSTATUS_INVALID_STATE             (0x0008)
+#define MPI_IOCSTATUS_OP_STATE_NOT_SUPPORTED    (0x0009)
 
 /****************************************************************************/
 /*  Config IOCStatus values                                                 */
 /****************************************************************************/
 
-#define MPI_IOCSTATUS_CONFIG_INVALID_ACTION    (0x0020)
-#define MPI_IOCSTATUS_CONFIG_INVALID_TYPE      (0x0021)
-#define MPI_IOCSTATUS_CONFIG_INVALID_PAGE      (0x0022)
-#define MPI_IOCSTATUS_CONFIG_INVALID_DATA      (0x0023)
-#define MPI_IOCSTATUS_CONFIG_NO_DEFAULTS       (0x0024)
-#define MPI_IOCSTATUS_CONFIG_CANT_COMMIT       (0x0025)
+#define MPI_IOCSTATUS_CONFIG_INVALID_ACTION     (0x0020)
+#define MPI_IOCSTATUS_CONFIG_INVALID_TYPE       (0x0021)
+#define MPI_IOCSTATUS_CONFIG_INVALID_PAGE       (0x0022)
+#define MPI_IOCSTATUS_CONFIG_INVALID_DATA       (0x0023)
+#define MPI_IOCSTATUS_CONFIG_NO_DEFAULTS        (0x0024)
+#define MPI_IOCSTATUS_CONFIG_CANT_COMMIT        (0x0025)
 
 /****************************************************************************/
 /*  SCSIIO Reply (SPI & FCP) initiator values                               */
 /****************************************************************************/
 
-#define MPI_IOCSTATUS_SCSI_RECOVERED_ERROR     (0x0040)
-#define MPI_IOCSTATUS_SCSI_INVALID_BUS         (0x0041)
-#define MPI_IOCSTATUS_SCSI_INVALID_TARGETID    (0x0042)
-#define MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE    (0x0043)
-#define MPI_IOCSTATUS_SCSI_DATA_OVERRUN        (0x0044)
-#define MPI_IOCSTATUS_SCSI_DATA_UNDERRUN       (0x0045)
-#define MPI_IOCSTATUS_SCSI_IO_DATA_ERROR       (0x0046)
-#define MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR      (0x0047)
-#define MPI_IOCSTATUS_SCSI_TASK_TERMINATED     (0x0048)
-#define MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH   (0x0049)
-#define MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED    (0x004A)
-#define MPI_IOCSTATUS_SCSI_IOC_TERMINATED      (0x004B)
-#define MPI_IOCSTATUS_SCSI_EXT_TERMINATED      (0x004C)
+#define MPI_IOCSTATUS_SCSI_RECOVERED_ERROR      (0x0040)
+#define MPI_IOCSTATUS_SCSI_INVALID_BUS          (0x0041)
+#define MPI_IOCSTATUS_SCSI_INVALID_TARGETID     (0x0042)
+#define MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE     (0x0043)
+#define MPI_IOCSTATUS_SCSI_DATA_OVERRUN         (0x0044)
+#define MPI_IOCSTATUS_SCSI_DATA_UNDERRUN        (0x0045)
+#define MPI_IOCSTATUS_SCSI_IO_DATA_ERROR        (0x0046)
+#define MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR       (0x0047)
+#define MPI_IOCSTATUS_SCSI_TASK_TERMINATED      (0x0048)
+#define MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH    (0x0049)
+#define MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED     (0x004A)
+#define MPI_IOCSTATUS_SCSI_IOC_TERMINATED       (0x004B)
+#define MPI_IOCSTATUS_SCSI_EXT_TERMINATED       (0x004C)
+
+/****************************************************************************/
+/*  For use by SCSI Initiator and SCSI Target end-to-end data protection    */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_EEDP_CRC_ERROR            (0x004D)
+#define MPI_IOCSTATUS_EEDP_LBA_TAG_ERROR        (0x004E)
+#define MPI_IOCSTATUS_EEDP_APP_TAG_ERROR        (0x004F)
+
 
 /****************************************************************************/
 /*  SCSI (SPI & FCP) target values                                          */
@@ -618,7 +662,8 @@ typedef struct _MSG_DEFAULT_REPLY
 
 #define MPI_IOCSTATUS_TARGET_PRIORITY_IO         (0x0060)
 #define MPI_IOCSTATUS_TARGET_INVALID_PORT        (0x0061)
-#define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX    (0x0062)
+#define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX    (0x0062)   /* obsolete */
+#define MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX    (0x0062)
 #define MPI_IOCSTATUS_TARGET_ABORTED             (0x0063)
 #define MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE   (0x0064)
 #define MPI_IOCSTATUS_TARGET_NO_CONNECTION       (0x0065)
@@ -626,7 +671,7 @@ typedef struct _MSG_DEFAULT_REPLY
 #define MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT   (0x006B)
 
 /****************************************************************************/
-/*  Additional FCP target values                                            */
+/*  Additional FCP target values (obsolete)                                 */
 /****************************************************************************/
 
 #define MPI_IOCSTATUS_TARGET_FC_ABORTED         (0x0066)    /* obsolete */
@@ -642,6 +687,7 @@ typedef struct _MSG_DEFAULT_REPLY
 #define MPI_IOCSTATUS_FC_RX_ID_INVALID          (0x0067)
 #define MPI_IOCSTATUS_FC_DID_INVALID            (0x0068)
 #define MPI_IOCSTATUS_FC_NODE_LOGGED_OUT        (0x0069)
+#define MPI_IOCSTATUS_FC_EXCHANGE_CANCELED      (0x006C)
 
 /****************************************************************************/
 /*  LAN values                                                              */
@@ -656,6 +702,25 @@ typedef struct _MSG_DEFAULT_REPLY
 #define MPI_IOCSTATUS_LAN_PARTIAL_PACKET        (0x0086)
 #define MPI_IOCSTATUS_LAN_CANCELED              (0x0087)
 
+/****************************************************************************/
+/*  Serial Attached SCSI values                                                              */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED    (0x0090)
+
+/****************************************************************************/
+/*  Inband values                                                           */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_INBAND_ABORTED            (0x0098)
+#define MPI_IOCSTATUS_INBAND_NO_CONNECTION      (0x0099)
+
+/****************************************************************************/
+/*  Diagnostic Tools values                                                 */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_DIAGNOSTIC_RELEASED       (0x00A0)
+
 
 /****************************************************************************/
 /*  IOCStatus flag to indicate that log info is available                   */
@@ -669,9 +734,12 @@ typedef struct _MSG_DEFAULT_REPLY
 /****************************************************************************/
 
 #define MPI_IOCLOGINFO_TYPE_MASK                (0xF0000000)
+#define MPI_IOCLOGINFO_TYPE_SHIFT               (28)
 #define MPI_IOCLOGINFO_TYPE_NONE                (0x0)
 #define MPI_IOCLOGINFO_TYPE_SCSI                (0x1)
 #define MPI_IOCLOGINFO_TYPE_FC                  (0x2)
+#define MPI_IOCLOGINFO_TYPE_SAS                 (0x3)
+#define MPI_IOCLOGINFO_TYPE_ISCSI               (0x4)
 #define MPI_IOCLOGINFO_LOG_DATA_MASK            (0x0FFFFFFF)
 
 
--- diff/drivers/message/fusion/lsi/mpi_cnfg.h	2002-10-16 03:28:23.000000000 +0000
+++ source/drivers/message/fusion/lsi/mpi_cnfg.h	2004-03-16 09:37:55.969031584 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *  Copyright (c) 2000-2003 LSI Logic Corporation.
  *
  *
- *           Name:  MPI_CNFG.H
+ *           Name:  mpi_cnfg.h
  *          Title:  MPI Config message, structures, and Pages
  *  Creation Date:  July 27, 2000
  *
- *    MPI_CNFG.H Version:  01.02.09
+ *    mpi_cnfg.h Version:  01.05.xx
  *
  *  Version History
  *  ---------------
@@ -127,7 +127,24 @@
  *                      MPI_SCSIDEVPAGE1_CONF_EXTENDED_PARAMS_ENABLE.
  *                      Added new config page: CONFIG_PAGE_SCSI_DEVICE_3.
  *                      Modified MPI_FCPORTPAGE5_FLAGS_ defines.
- *  09-16-02 01.02.09   Added more MPI_SCSIDEVPAGE1_CONF_FORCE_PPR_MSG define.
+ *  09-16-02 01.02.09   Added MPI_SCSIDEVPAGE1_CONF_FORCE_PPR_MSG define.
+ *  11-15-02 01.02.10   Added ConnectedID defines for CONFIG_PAGE_SCSI_PORT_0.
+ *                      Added more Flags defines for CONFIG_PAGE_FC_PORT_1.
+ *                      Added more Flags defines for CONFIG_PAGE_FC_DEVICE_0.
+ *  04-01-03 01.02.11   Added RR_TOV field and additional Flags defines for
+ *                      CONFIG_PAGE_FC_PORT_1.
+ *                      Added define MPI_FCPORTPAGE5_FLAGS_DISABLE to disable
+ *                      an alias.
+ *                      Added more device id defines.
+ *  06-26-03 01.02.12   Added MPI_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID define.
+ *                      Added TargetConfig and IDConfig fields to
+ *                      CONFIG_PAGE_SCSI_PORT_1.
+ *                      Added more PortFlags defines for CONFIG_PAGE_SCSI_PORT_2
+ *                      to control DV.
+ *                      Added more Flags defines for CONFIG_PAGE_FC_PORT_1.
+ *                      In CONFIG_PAGE_FC_DEVICE_0, replaced Reserved1 field
+ *                      with ADISCHardALPA.
+ *                      Added MPI_FC_DEVICE_PAGE0_PROT_FCP_RETRY define.
  *  --------------------------------------------------------------------------
  */
 
@@ -159,6 +176,19 @@ typedef union _CONFIG_PAGE_HEADER_UNION
 } ConfigPageHeaderUnion, MPI_POINTER pConfigPageHeaderUnion,
   fCONFIG_PAGE_HEADER_UNION, MPI_POINTER PTR_CONFIG_PAGE_HEADER_UNION;
 
+typedef struct _CONFIG_EXTENDED_PAGE_HEADER
+{
+    U8                  PageVersion;                /* 00h */
+    U8                  Reserved1;                  /* 01h */
+    U8                  PageNumber;                 /* 02h */
+    U8                  PageType;                   /* 03h */
+    U16                 ExtPageLength;              /* 04h */
+    U8                  ExtPageType;                /* 06h */
+    U8                  Reserved2;                  /* 07h */
+} fCONFIG_EXTENDED_PAGE_HEADER, MPI_POINTER PTR_CONFIG_EXTENDED_PAGE_HEADER,
+  ConfigExtendedPageHeader_t, MPI_POINTER pConfigExtendedPageHeader_t;
+
+
 
 /****************************************************************************
 *   PageType field values
@@ -180,12 +210,23 @@ typedef union _CONFIG_PAGE_HEADER_UNION
 #define MPI_CONFIG_PAGETYPE_RAID_VOLUME             (0x08)
 #define MPI_CONFIG_PAGETYPE_MANUFACTURING           (0x09)
 #define MPI_CONFIG_PAGETYPE_RAID_PHYSDISK           (0x0A)
+#define MPI_CONFIG_PAGETYPE_INBAND                  (0x0B)
+#define MPI_CONFIG_PAGETYPE_EXTENDED                (0x0F)
 #define MPI_CONFIG_PAGETYPE_MASK                    (0x0F)
 
 #define MPI_CONFIG_TYPENUM_MASK                     (0x0FFF)
 
 
 /****************************************************************************
+*   ExtPageType field values
+****************************************************************************/
+#define MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT          (0x10)
+#define MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER         (0x11)
+#define MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE           (0x12)
+#define MPI_CONFIG_EXTPAGETYPE_SAS_PHY              (0x13)
+
+
+/****************************************************************************
 *   PageAddress field values
 ****************************************************************************/
 #define MPI_SCSI_PORT_PGAD_PORT_MASK                (0x000000FF)
@@ -219,6 +260,24 @@ typedef union _CONFIG_PAGE_HEADER_UNION
 #define MPI_PHYSDISK_PGAD_PHYSDISKNUM_MASK          (0x000000FF)
 #define MPI_PHYSDISK_PGAD_PHYSDISKNUM_SHIFT         (0)
 
+#define MPI_SAS_DEVICE_PGAD_FORM_MASK               (0xF0000000)
+#define MPI_SAS_DEVICE_PGAD_FORM_SHIFT              (28)
+#define MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE    (0x00000000)
+#define MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID      (0x00000001)
+#define MPI_SAS_DEVICE_PGAD_FORM_HANDLE             (0x00000002)
+#define MPI_SAS_DEVICE_PGAD_GNH_HANDLE_MASK         (0x0000FFFF)
+#define MPI_SAS_DEVICE_PGAD_GNH_HANDLE_SHIFT        (0)
+#define MPI_SAS_DEVICE_PGAD_BT_BUS_MASK             (0x0000FF00)
+#define MPI_SAS_DEVICE_PGAD_BT_BUS_SHIFT            (8)
+#define MPI_SAS_DEVICE_PGAD_BT_TID_MASK             (0x000000FF)
+#define MPI_SAS_DEVICE_PGAD_BT_TID_SHIFT            (0)
+#define MPI_SAS_DEVICE_PGAD_H_HANDLE_MASK           (0x0000FFFF)
+#define MPI_SAS_DEVICE_PGAD_H_HANDLE_SHIFT          (0)
+
+#define MPI_SAS_PHY_PGAD_PHY_NUMBER_MASK            (0x00FF0000)
+#define MPI_SAS_PHY_PGAD_PHY_NUMBER_SHIFT           (16)
+#define MPI_SAS_PHY_PGAD_DEVHANDLE_MASK             (0x0000FFFF)
+#define MPI_SAS_PHY_PGAD_DEVHANDLE_SHIFT            (0)
 
 
 /****************************************************************************
@@ -230,7 +289,8 @@ typedef struct _MSG_CONFIG
     U8                      Reserved;                   /* 01h */
     U8                      ChainOffset;                /* 02h */
     U8                      Function;                   /* 03h */
-    U8                      Reserved1[3];               /* 04h */
+    U16                     ExtPageLength;              /* 04h */
+    U8                      ExtPageType;                /* 06h */
     U8                      MsgFlags;                   /* 07h */
     U32                     MsgContext;                 /* 08h */
     U8                      Reserved2[8];               /* 0Ch */
@@ -260,7 +320,8 @@ typedef struct _MSG_CONFIG_REPLY
     U8                      Reserved;                   /* 01h */
     U8                      MsgLength;                  /* 02h */
     U8                      Function;                   /* 03h */
-    U8                      Reserved1[3];               /* 04h */
+    U16                     ExtPageLength;              /* 04h */
+    U8                      ExtPageType;                /* 06h */
     U8                      MsgFlags;                   /* 07h */
     U32                     MsgContext;                 /* 08h */
     U8                      Reserved2[2];               /* 0Ch */
@@ -281,23 +342,22 @@ typedef struct _MSG_CONFIG_REPLY
 /****************************************************************************
 *   Manufacturing Config pages
 ****************************************************************************/
+#define MPI_MANUFACTPAGE_VENDORID_LSILOGIC          (0x1000)
+/* Fibre Channel */
 #define MPI_MANUFACTPAGE_DEVICEID_FC909             (0x0621)
 #define MPI_MANUFACTPAGE_DEVICEID_FC919             (0x0624)
 #define MPI_MANUFACTPAGE_DEVICEID_FC929             (0x0622)
 #define MPI_MANUFACTPAGE_DEVICEID_FC919X            (0x0628)
 #define MPI_MANUFACTPAGE_DEVICEID_FC929X            (0x0626)
-
+/* SCSI */
 #define MPI_MANUFACTPAGE_DEVID_53C1030              (0x0030)
 #define MPI_MANUFACTPAGE_DEVID_53C1030ZC            (0x0031)
 #define MPI_MANUFACTPAGE_DEVID_1030_53C1035         (0x0032)
 #define MPI_MANUFACTPAGE_DEVID_1030ZC_53C1035       (0x0033)
 #define MPI_MANUFACTPAGE_DEVID_53C1035              (0x0040)
 #define MPI_MANUFACTPAGE_DEVID_53C1035ZC            (0x0041)
-
-#define MPI_MANUFACTPAGE_DEVID_SA2010               (0x0804)
-#define MPI_MANUFACTPAGE_DEVID_SA2010ZC             (0x0805)
-#define MPI_MANUFACTPAGE_DEVID_SA2020               (0x0806)
-#define MPI_MANUFACTPAGE_DEVID_SA2020ZC             (0x0807)
+/* SAS */
+#define MPI_MANUFACTPAGE_DEVID_SAS1064              (0x0050)
 
 
 typedef struct _CONFIG_PAGE_MANUFACTURING_0
@@ -381,8 +441,8 @@ typedef struct _CONFIG_PAGE_MANUFACTURIN
     U8                              InfoOffset1;        /* 0Ah */
     U8                              InfoSize1;          /* 0Bh */
     U8                              InquirySize;        /* 0Ch */
-    U8                              Reserved2;          /* 0Dh */
-    U16                             Reserved3;          /* 0Eh */
+    U8                              Flags;              /* 0Dh */
+    U16                             Reserved2;          /* 0Eh */
     U8                              InquiryData[56];    /* 10h */
     U32                             ISVolumeSettings;   /* 48h */
     U32                             IMEVolumeSettings;  /* 4Ch */
@@ -390,7 +450,30 @@ typedef struct _CONFIG_PAGE_MANUFACTURIN
 } fCONFIG_PAGE_MANUFACTURING_4, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_4,
   ManufacturingPage4_t, MPI_POINTER pManufacturingPage4_t;
 
-#define MPI_MANUFACTURING4_PAGEVERSION                  (0x00)
+#define MPI_MANUFACTURING4_PAGEVERSION                  (0x01)
+
+/* defines for the Flags field */
+#define MPI_MANPAGE4_IR_NO_MIX_SAS_SATA                 (0x01)
+
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_5
+{
+    fCONFIG_PAGE_HEADER              Header;             /* 00h */
+    U64                             BaseWWID;           /* 04h */
+} fCONFIG_PAGE_MANUFACTURING_5, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_5,
+  ManufacturingPage5_t, MPI_POINTER pManufacturingPage5_t;
+
+#define MPI_MANUFACTURING5_PAGEVERSION                  (0x00)
+
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_6
+{
+    fCONFIG_PAGE_HEADER              Header;             /* 00h */
+    U32                             ProductSpecificInfo;/* 04h */
+} fCONFIG_PAGE_MANUFACTURING_6, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_6,
+  ManufacturingPage6_t, MPI_POINTER pManufacturingPage6_t;
+
+#define MPI_MANUFACTURING6_PAGEVERSION                  (0x00)
 
 
 /****************************************************************************
@@ -414,16 +497,18 @@ typedef struct _CONFIG_PAGE_IO_UNIT_1
 } fCONFIG_PAGE_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_1,
   IOUnitPage1_t, MPI_POINTER pIOUnitPage1_t;
 
-#define MPI_IOUNITPAGE1_PAGEVERSION                     (0x00)
+#define MPI_IOUNITPAGE1_PAGEVERSION                     (0x01)
 
 /* IO Unit Page 1 Flags defines */
-
 #define MPI_IOUNITPAGE1_MULTI_FUNCTION                  (0x00000000)
 #define MPI_IOUNITPAGE1_SINGLE_FUNCTION                 (0x00000001)
 #define MPI_IOUNITPAGE1_MULTI_PATHING                   (0x00000002)
 #define MPI_IOUNITPAGE1_SINGLE_PATHING                  (0x00000000)
+#define MPI_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID         (0x00000004)
+#define MPI_IOUNITPAGE1_DISABLE_QUEUE_FULL_HANDLING     (0x00000020)
 #define MPI_IOUNITPAGE1_DISABLE_IR                      (0x00000040)
 #define MPI_IOUNITPAGE1_FORCE_32                        (0x00000080)
+#define MPI_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE        (0x00000100)
 
 
 typedef struct _MPI_ADAPTER_INFO
@@ -453,6 +538,11 @@ typedef struct _CONFIG_PAGE_IO_UNIT_2
 #define MPI_IOUNITPAGE2_FLAGS_COLOR_VIDEO_DISABLE       (0x00000008)
 #define MPI_IOUNITPAGE2_FLAGS_DONT_HOOK_INT_40          (0x00000010)
 
+#define MPI_IOUNITPAGE2_FLAGS_DEV_LIST_DISPLAY_MASK     (0x000000E0)
+#define MPI_IOUNITPAGE2_FLAGS_INSTALLED_DEV_DISPLAY     (0x00000000)
+#define MPI_IOUNITPAGE2_FLAGS_ADAPTER_DISPLAY           (0x00000020)
+#define MPI_IOUNITPAGE2_FLAGS_ADAPTER_DEV_DISPLAY       (0x00000040)
+
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
@@ -515,6 +605,12 @@ typedef struct _CONFIG_PAGE_IOC_1
 
 #define MPI_IOCPAGE1_PAGEVERSION                        (0x01)
 
+/* defines for the Flags field */
+#define MPI_IOCPAGE1_EEDP_HOST_SUPPORTS_DIF             (0x08000000)
+#define MPI_IOCPAGE1_EEDP_MODE_MASK                     (0x07000000)
+#define MPI_IOCPAGE1_EEDP_MODE_OFF                      (0x00000000)
+#define MPI_IOCPAGE1_EEDP_MODE_T10                      (0x01000000)
+#define MPI_IOCPAGE1_EEDP_MODE_LSI_1                    (0x02000000)
 #define MPI_IOCPAGE1_REPLY_COALESCING                   (0x00000001)
 
 #define MPI_IOCPAGE1_PCISLOTNUM_UNKNOWN                 (0xFF)
@@ -655,7 +751,7 @@ typedef struct _IOC_5_HOT_SPARE
 
 typedef struct _CONFIG_PAGE_IOC_5
 {
-    fCONFIG_PAGE_HEADER         Header;                         /* 00h */
+    fCONFIG_PAGE_HEADER          Header;                         /* 00h */
     U32                         Reserved1;                      /* 04h */
     U8                          NumHotSpares;                   /* 08h */
     U8                          Reserved2;                      /* 09h */
@@ -667,6 +763,57 @@ typedef struct _CONFIG_PAGE_IOC_5
 #define MPI_IOCPAGE5_PAGEVERSION                        (0x00)
 
 
+/****************************************************************************
+*   BIOS Port Config Pages
+****************************************************************************/
+
+typedef struct _CONFIG_PAGE_BIOS_1
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U32                     BiosOptions;                /* 04h */
+    U32                     IOCSettings;                /* 08h */
+    U32                     Reserved1;                  /* 0Ch */
+    U32                     DeviceSettings;             /* 10h */
+    U16                     NumberOfDevices;            /* 14h */
+    U16                     Reserved2;                  /* 16h */
+    U16                     IOTimeoutBlockDevicesNonRM; /* 18h */
+    U16                     IOTimeoutSequential;        /* 1Ah */
+    U16                     IOTimeoutOther;             /* 1Ch */
+    U16                     IOTimeoutBlockDevicesRM;    /* 1Eh */
+} fCONFIG_PAGE_BIOS_1, MPI_POINTER PTR_CONFIG_PAGE_BIOS_1,
+  BIOSPage1_t, MPI_POINTER pBIOSPage1_t;
+
+#define MPI_BIOSPAGE1_PAGEVERSION                       (0x00)
+
+/* values for the BiosOptions field */
+#define MPI_BIOSPAGE1_OPTIONS_SPI_ENABLE                (0x00000400)
+#define MPI_BIOSPAGE1_OPTIONS_FC_ENABLE                 (0x00000200)
+#define MPI_BIOSPAGE1_OPTIONS_SAS_ENABLE                (0x00000100)
+#define MPI_BIOSPAGE1_OPTIONS_DISABLE_BIOS              (0x00000001)
+
+/* values for the IOCSettings field */
+#define MPI_BIOSPAGE1_IOCSET_MASK_SPINUP_DELAY          (0x00000F00)
+#define MPI_BIOSPAGE1_IOCSET_SHIFT_SPINUP_DELAY         (8)
+
+#define MPI_BIOSPAGE1_IOCSET_MASK_RM_SETTING            (0x000000C0)
+#define MPI_BIOSPAGE1_IOCSET_NONE_RM_SETTING            (0x00000000)
+#define MPI_BIOSPAGE1_IOCSET_BOOT_RM_SETTING            (0x00000040)
+#define MPI_BIOSPAGE1_IOCSET_MEDIA_RM_SETTING           (0x00000080)
+
+#define MPI_BIOSPAGE1_IOCSET_MASK_ADAPTER_SUPPORT       (0x00000030)
+#define MPI_BIOSPAGE1_IOCSET_NO_SUPPORT                 (0x00000000)
+#define MPI_BIOSPAGE1_IOCSET_BIOS_SUPPORT               (0x00000010)
+#define MPI_BIOSPAGE1_IOCSET_OS_SUPPORT                 (0x00000020)
+#define MPI_BIOSPAGE1_IOCSET_ALL_SUPPORT                (0x00000030)
+
+#define MPI_BIOSPAGE1_IOCSET_ALTERNATE_CHS              (0x00000008)
+
+/* values for the DeviceSettings field */
+#define MPI_BIOSPAGE1_DEVSET_DISABLE_SEQ_LUN            (0x00000008)
+#define MPI_BIOSPAGE1_DEVSET_DISABLE_RM_LUN             (0x00000004)
+#define MPI_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN         (0x00000002)
+#define MPI_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN          (0x00000001)
+
 
 /****************************************************************************
 *   SCSI Port Config Pages
@@ -686,7 +833,27 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_0
 #define MPI_SCSIPORTPAGE0_CAP_DT                        (0x00000002)
 #define MPI_SCSIPORTPAGE0_CAP_QAS                       (0x00000004)
 #define MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK      (0x0000FF00)
+#define MPI_SCSIPORTPAGE0_SYNC_ASYNC                    (0x00)
+#define MPI_SCSIPORTPAGE0_SYNC_5                        (0x32)
+#define MPI_SCSIPORTPAGE0_SYNC_10                       (0x19)
+#define MPI_SCSIPORTPAGE0_SYNC_20                       (0x0C)
+#define MPI_SCSIPORTPAGE0_SYNC_33_33                    (0x0B)
+#define MPI_SCSIPORTPAGE0_SYNC_40                       (0x0A)
+#define MPI_SCSIPORTPAGE0_SYNC_80                       (0x09)
+#define MPI_SCSIPORTPAGE0_SYNC_160                      (0x08)
+#define MPI_SCSIPORTPAGE0_SYNC_UNKNOWN                  (0xFF)
+
+#define MPI_SCSIPORTPAGE0_CAP_SHIFT_MIN_SYNC_PERIOD     (8)
+#define MPI_SCSIPORTPAGE0_CAP_GET_MIN_SYNC_PERIOD(Cap)      \
+    (  ((Cap) & MPI_SCSIPORTPAGE0_CAP_MASK_MIN_SYNC_PERIOD) \
+    >> MPI_SCSIPORTPAGE0_CAP_SHIFT_MIN_SYNC_PERIOD          \
+    )
 #define MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK      (0x00FF0000)
+#define MPI_SCSIPORTPAGE0_CAP_SHIFT_MAX_SYNC_OFFSET     (16)
+#define MPI_SCSIPORTPAGE0_CAP_GET_MAX_SYNC_OFFSET(Cap)      \
+    (  ((Cap) & MPI_SCSIPORTPAGE0_CAP_MASK_MAX_SYNC_OFFSET) \
+    >> MPI_SCSIPORTPAGE0_CAP_SHIFT_MAX_SYNC_OFFSET          \
+    )
 #define MPI_SCSIPORTPAGE0_CAP_WIDE                      (0x20000000)
 #define MPI_SCSIPORTPAGE0_CAP_AIP                       (0x80000000)
 
@@ -694,6 +861,10 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_0
 #define MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD                (0x01)
 #define MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE                 (0x02)
 #define MPI_SCSIPORTPAGE0_PHY_SIGNAL_LVD                (0x03)
+#define MPI_SCSIPORTPAGE0_PHY_MASK_CONNECTED_ID         (0xFF000000)
+#define MPI_SCSIPORTPAGE0_PHY_SHIFT_CONNECTED_ID        (24)
+#define MPI_SCSIPORTPAGE0_PHY_BUS_FREE_CONNECTED_ID     (0xFE)
+#define MPI_SCSIPORTPAGE0_PHY_UNKNOWN_CONNECTED_ID      (0xFF)
 
 
 typedef struct _CONFIG_PAGE_SCSI_PORT_1
@@ -701,13 +872,22 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_1
     fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Configuration;              /* 04h */
     U32                     OnBusTimerValue;            /* 08h */
+    U8                      TargetConfig;               /* 0Ch */
+    U8                      Reserved1;                  /* 0Dh */
+    U16                     IDConfig;                   /* 0Eh */
 } fCONFIG_PAGE_SCSI_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_1,
   SCSIPortPage1_t, MPI_POINTER pSCSIPortPage1_t;
 
-#define MPI_SCSIPORTPAGE1_PAGEVERSION                   (0x02)
+#define MPI_SCSIPORTPAGE1_PAGEVERSION                   (0x03)
 
+/* Configuration values */
 #define MPI_SCSIPORTPAGE1_CFG_PORT_SCSI_ID_MASK         (0x000000FF)
 #define MPI_SCSIPORTPAGE1_CFG_PORT_RESPONSE_ID_MASK     (0xFFFF0000)
+#define MPI_SCSIPORTPAGE1_CFG_SHIFT_PORT_RESPONSE_ID    (16)
+
+/* TargetConfig values */
+#define MPI_SCSIPORTPAGE1_TARGCONFIG_TARG_ONLY        (0x01)
+#define MPI_SCSIPORTPAGE1_TARGCONFIG_INIT_TARG        (0x02)
 
 
 typedef struct _MPI_DEVICE_INFO
@@ -727,13 +907,21 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_2
 } fCONFIG_PAGE_SCSI_PORT_2, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_2,
   SCSIPortPage2_t, MPI_POINTER pSCSIPortPage2_t;
 
-#define MPI_SCSIPORTPAGE2_PAGEVERSION                       (0x01)
+#define MPI_SCSIPORTPAGE2_PAGEVERSION                       (0x02)
 
+/* PortFlags values */
 #define MPI_SCSIPORTPAGE2_PORT_FLAGS_SCAN_HIGH_TO_LOW       (0x00000001)
 #define MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET       (0x00000004)
 #define MPI_SCSIPORTPAGE2_PORT_FLAGS_ALTERNATE_CHS          (0x00000008)
 #define MPI_SCSIPORTPAGE2_PORT_FLAGS_TERMINATION_DISABLE    (0x00000010)
 
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK                (0x00000060)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_FULL_DV                (0x00000000)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY          (0x00000020)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV                 (0x00000060)
+
+
+/* PortSettings values */
 #define MPI_SCSIPORTPAGE2_PORT_HOST_ID_MASK                 (0x0000000F)
 #define MPI_SCSIPORTPAGE2_PORT_MASK_INIT_HBA                (0x00000030)
 #define MPI_SCSIPORTPAGE2_PORT_DISABLE_INIT_HBA             (0x00000000)
@@ -741,7 +929,11 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_2
 #define MPI_SCSIPORTPAGE2_PORT_OS_INIT_HBA                  (0x00000020)
 #define MPI_SCSIPORTPAGE2_PORT_BIOS_OS_INIT_HBA             (0x00000030)
 #define MPI_SCSIPORTPAGE2_PORT_REMOVABLE_MEDIA              (0x000000C0)
+#define MPI_SCSIPORTPAGE2_PORT_RM_NONE                      (0x00000000)
+#define MPI_SCSIPORTPAGE2_PORT_RM_BOOT_ONLY                 (0x00000040)
+#define MPI_SCSIPORTPAGE2_PORT_RM_WITH_MEDIA                (0x00000080)
 #define MPI_SCSIPORTPAGE2_PORT_SPINUP_DELAY_MASK            (0x00000F00)
+#define MPI_SCSIPORTPAGE2_PORT_SHIFT_SPINUP_DELAY           (8)
 #define MPI_SCSIPORTPAGE2_PORT_MASK_NEGO_MASTER_SETTINGS    (0x00003000)
 #define MPI_SCSIPORTPAGE2_PORT_NEGO_MASTER_SETTINGS         (0x00000000)
 #define MPI_SCSIPORTPAGE2_PORT_NONE_MASTER_SETTINGS         (0x00001000)
@@ -778,7 +970,9 @@ typedef struct _CONFIG_PAGE_SCSI_DEVICE_
 #define MPI_SCSIDEVPAGE0_NP_RTI                         (0x00000040)
 #define MPI_SCSIDEVPAGE0_NP_PCOMP_EN                    (0x00000080)
 #define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK        (0x0000FF00)
+#define MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_PERIOD           (8)
 #define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK        (0x00FF0000)
+#define MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_OFFSET           (16)
 #define MPI_SCSIDEVPAGE0_NP_WIDE                        (0x20000000)
 #define MPI_SCSIDEVPAGE0_NP_AIP                         (0x80000000)
 
@@ -808,7 +1002,9 @@ typedef struct _CONFIG_PAGE_SCSI_DEVICE_
 #define MPI_SCSIDEVPAGE1_RP_RTI                         (0x00000040)
 #define MPI_SCSIDEVPAGE1_RP_PCOMP_EN                    (0x00000080)
 #define MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK        (0x0000FF00)
+#define MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD       (8)
 #define MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK        (0x00FF0000)
+#define MPI_SCSIDEVPAGE1_RP_SHIFT_MAX_SYNC_OFFSET       (16)
 #define MPI_SCSIDEVPAGE1_RP_WIDE                        (0x20000000)
 #define MPI_SCSIDEVPAGE1_RP_AIP                         (0x80000000)
 
@@ -915,7 +1111,7 @@ typedef struct _CONFIG_PAGE_FC_PORT_0
 
 #define MPI_FCPORTPAGE0_FLAGS_ALIAS_ALPA_SUPPORTED      (0x00000010)
 #define MPI_FCPORTPAGE0_FLAGS_ALIAS_WWN_SUPPORTED       (0x00000020)
-#define MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID          (0x00000030)
+#define MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID          (0x00000040)
 
 #define MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK          (0x00000F00)
 #define MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT            (0x00000000)
@@ -954,13 +1150,19 @@ typedef struct _CONFIG_PAGE_FC_PORT_0
 #define MPI_FCPORTPAGE0_SUPPORT_CLASS_2                 (0x00000002)
 #define MPI_FCPORTPAGE0_SUPPORT_CLASS_3                 (0x00000004)
 
-#define MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED             (0x00000001) /* (SNIA)HBA_PORTSPEED_1GBIT 1  1 GBit/sec  */
-#define MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED             (0x00000002) /* (SNIA)HBA_PORTSPEED_2GBIT 2  2 GBit/sec  */
-#define MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED            (0x00000004) /* (SNIA)HBA_PORTSPEED_10GBIT 4 10 GBit/sec */
+#define MPI_FCPORTPAGE0_SUPPORT_SPEED_UKNOWN            (0x00000000) /* (SNIA)HBA_PORTSPEED_UNKNOWN 0   Unknown - transceiver incapable of reporting */
+#define MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED             (0x00000001) /* (SNIA)HBA_PORTSPEED_1GBIT   1   1 GBit/sec */
+#define MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED             (0x00000002) /* (SNIA)HBA_PORTSPEED_2GBIT   2   2 GBit/sec */
+#define MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED            (0x00000004) /* (SNIA)HBA_PORTSPEED_10GBIT  4  10 GBit/sec */
+#define MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED             (0x00000008) /* (SNIA)HBA_PORTSPEED_4GBIT   8   4 GBit/sec */
 
+#define MPI_FCPORTPAGE0_CURRENT_SPEED_UKNOWN            MPI_FCPORTPAGE0_SUPPORT_SPEED_UKNOWN
 #define MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT             MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED
 #define MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT             MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED
 #define MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT            MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED
+#define MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT             MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED
+#define MPI_FCPORTPAGE0_CURRENT_SPEED_NOT_NEGOTIATED    (0x00008000)        /* (SNIA)HBA_PORTSPEED_NOT_NEGOTIATED (1<<15) Speed not established */
+
 
 
 typedef struct _CONFIG_PAGE_FC_PORT_1
@@ -974,15 +1176,25 @@ typedef struct _CONFIG_PAGE_FC_PORT_1
     U8                      TopologyConfig;             /* 1Ah */
     U8                      AltConnector;               /* 1Bh */
     U8                      NumRequestedAliases;        /* 1Ch */
-    U8                      Reserved1;                  /* 1Dh */
-    U16                     Reserved2;                  /* 1Eh */
+    U8                      RR_TOV;                     /* 1Dh */
+    U8                      InitiatorDeviceTimeout;     /* 1Eh */
+    U8                      InitiatorIoPendTimeout;     /* 1Fh */
 } fCONFIG_PAGE_FC_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_1,
   FCPortPage1_t, MPI_POINTER pFCPortPage1_t;
 
-#define MPI_FCPORTPAGE1_PAGEVERSION                     (0x04)
+#define MPI_FCPORTPAGE1_PAGEVERSION                     (0x06)
 
 #define MPI_FCPORTPAGE1_FLAGS_EXT_FCP_STATUS_EN         (0x08000000)
 #define MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY     (0x04000000)
+#define MPI_FCPORTPAGE1_FLAGS_FORCE_USE_NOSEEPROM_WWNS  (0x02000000)
+#define MPI_FCPORTPAGE1_FLAGS_VERBOSE_RESCAN_EVENTS     (0x01000000)
+#define MPI_FCPORTPAGE1_FLAGS_TARGET_MODE_OXID          (0x00800000)
+#define MPI_FCPORTPAGE1_FLAGS_PORT_OFFLINE              (0x00400000)
+#define MPI_FCPORTPAGE1_FLAGS_SOFT_ALPA_FALLBACK        (0x00200000)
+#define MPI_FCPORTPAGE1_FLAGS_MASK_RR_TOV_UNITS         (0x00000070)
+#define MPI_FCPORTPAGE1_FLAGS_SUPPRESS_PROT_REG         (0x00000008)
+#define MPI_FCPORTPAGE1_FLAGS_PLOGI_ON_LOGO             (0x00000004)
+#define MPI_FCPORTPAGE1_FLAGS_MAINTAIN_LOGINS           (0x00000002)
 #define MPI_FCPORTPAGE1_FLAGS_SORT_BY_DID               (0x00000001)
 #define MPI_FCPORTPAGE1_FLAGS_SORT_BY_WWN               (0x00000000)
 
@@ -993,6 +1205,11 @@ typedef struct _CONFIG_PAGE_FC_PORT_1
 #define MPI_FCPORTPAGE1_FLAGS_PROT_LAN                  ((U32)MPI_PORTFACTS_PROTOCOL_LAN << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
 #define MPI_FCPORTPAGE1_FLAGS_PROT_LOGBUSADDR           ((U32)MPI_PORTFACTS_PROTOCOL_LOGBUSADDR << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
 
+#define MPI_FCPORTPAGE1_FLAGS_NONE_RR_TOV_UNITS         (0x00000000)
+#define MPI_FCPORTPAGE1_FLAGS_THOUSANDTH_RR_TOV_UNITS   (0x00000010)
+#define MPI_FCPORTPAGE1_FLAGS_TENTH_RR_TOV_UNITS        (0x00000030)
+#define MPI_FCPORTPAGE1_FLAGS_TEN_RR_TOV_UNITS          (0x00000050)
+
 #define MPI_FCPORTPAGE1_HARD_ALPA_NOT_USED              (0xFF)
 
 #define MPI_FCPORTPAGE1_LCONFIG_SPEED_MASK              (0x0F)
@@ -1009,6 +1226,8 @@ typedef struct _CONFIG_PAGE_FC_PORT_1
 
 #define MPI_FCPORTPAGE1_ALT_CONN_UNKNOWN                (0x00)
 
+#define MPI_FCPORTPAGE1_INITIATOR_DEV_TIMEOUT_MASK      (0x7F)
+
 
 typedef struct _CONFIG_PAGE_FC_PORT_2
 {
@@ -1108,12 +1327,13 @@ typedef struct _CONFIG_PAGE_FC_PORT_5
 } fCONFIG_PAGE_FC_PORT_5, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5,
   FCPortPage5_t, MPI_POINTER pFCPortPage5_t;
 
-#define MPI_FCPORTPAGE5_PAGEVERSION                     (0x01)
+#define MPI_FCPORTPAGE5_PAGEVERSION                     (0x02)
 
 #define MPI_FCPORTPAGE5_FLAGS_ALPA_ACQUIRED             (0x01)
 #define MPI_FCPORTPAGE5_FLAGS_HARD_ALPA                 (0x02)
 #define MPI_FCPORTPAGE5_FLAGS_HARD_WWNN                 (0x04)
 #define MPI_FCPORTPAGE5_FLAGS_HARD_WWPN                 (0x08)
+#define MPI_FCPORTPAGE5_FLAGS_DISABLE                   (0x10)
 
 typedef struct _CONFIG_PAGE_FC_PORT_6
 {
@@ -1322,7 +1542,7 @@ typedef struct _CONFIG_PAGE_FC_DEVICE_0
     U8                      Flags;                      /* 19h */
     U16                     BBCredit;                   /* 1Ah */
     U16                     MaxRxFrameSize;             /* 1Ch */
-    U8                      Reserved1;                  /* 1Eh */
+    U8                      ADISCHardALPA;              /* 1Eh */
     U8                      PortNumber;                 /* 1Fh */
     U8                      FcPhLowestVersion;          /* 20h */
     U8                      FcPhHighestVersion;         /* 21h */
@@ -1331,13 +1551,16 @@ typedef struct _CONFIG_PAGE_FC_DEVICE_0
 } fCONFIG_PAGE_FC_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_FC_DEVICE_0,
   FCDevicePage0_t, MPI_POINTER pFCDevicePage0_t;
 
-#define MPI_FC_DEVICE_PAGE0_PAGEVERSION                 (0x02)
+#define MPI_FC_DEVICE_PAGE0_PAGEVERSION                 (0x03)
 
 #define MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID    (0x01)
+#define MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID         (0x02)
+#define MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID          (0x04)
 
 #define MPI_FC_DEVICE_PAGE0_PROT_IP                     (0x01)
 #define MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET             (0x02)
 #define MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR          (0x04)
+#define MPI_FC_DEVICE_PAGE0_PROT_FCP_RETRY              (0x08)
 
 #define MPI_FC_DEVICE_PAGE0_PGAD_PORT_MASK      (MPI_FC_DEVICE_PGAD_PORT_MASK)
 #define MPI_FC_DEVICE_PAGE0_PGAD_FORM_MASK      (MPI_FC_DEVICE_PGAD_FORM_MASK)
@@ -1348,6 +1571,7 @@ typedef struct _CONFIG_PAGE_FC_DEVICE_0
 #define MPI_FC_DEVICE_PAGE0_PGAD_BUS_SHIFT      (MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT)
 #define MPI_FC_DEVICE_PAGE0_PGAD_TID_MASK       (MPI_FC_DEVICE_PGAD_BT_TID_MASK)
 
+#define MPI_FC_DEVICE_PAGE0_HARD_ALPA_UNKNOWN   (0xFF)
 
 /****************************************************************************
 *   RAID Volume Config Pages
@@ -1565,5 +1789,317 @@ typedef struct _CONFIG_PAGE_LAN_1
 #define MPI_LAN_PAGE1_DEV_STATE_RESET                   (0x00)
 #define MPI_LAN_PAGE1_DEV_STATE_OPERATIONAL             (0x01)
 
+
+/****************************************************************************
+*   Inband Config Pages
+****************************************************************************/
+
+typedef struct _CONFIG_PAGE_INBAND_0
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    MPI_VERSION_FORMAT      InbandVersion;              /* 04h */
+    U16                     MaximumBuffers;             /* 08h */
+    U16                     Reserved1;                  /* 0Ah */
+} fCONFIG_PAGE_INBAND_0, MPI_POINTER PTR_CONFIG_PAGE_INBAND_0,
+  InbandPage0_t, MPI_POINTER pInbandPage0_t;
+
+#define MPI_INBAND_PAGEVERSION          (0x00)
+
+
+
+/****************************************************************************
+*   SAS IO Unit Config Pages
+****************************************************************************/
+
+typedef struct _MPI_SAS_IO_UNIT0_PHY_DATA
+{
+    U8          Port;                   /* 00h */
+    U8          PortFlags;              /* 01h */
+    U8          PhyFlags;               /* 02h */
+    U8          NegotiatedLinkRate;     /* 03h */
+    U32         ControllerPhyDeviceInfo;/* 04h */
+    U16         AttachedDeviceHandle;   /* 08h */
+    U16         ControllerDevHandle;    /* 0Ah */
+    U32         Reserved2;              /* 0Ch */
+} MPI_SAS_IO_UNIT0_PHY_DATA, MPI_POINTER PTR_MPI_SAS_IO_UNIT0_PHY_DATA,
+  SasIOUnit0PhyData, MPI_POINTER pSasIOUnit0PhyData;
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_SAS_IOUNIT0_PHY_MAX
+#define MPI_SAS_IOUNIT0_PHY_MAX         (1)
+#endif
+
+typedef struct _CONFIG_PAGE_SAS_IO_UNIT_0
+{
+    fCONFIG_EXTENDED_PAGE_HEADER     Header;                             /* 00h */
+    U32                             Reserved1;                          /* 08h */
+    U8                              NumPhys;                            /* 0Ch */
+    U8                              Reserved2;                          /* 0Dh */
+    U16                             Reserved3;                          /* 0Eh */
+    MPI_SAS_IO_UNIT0_PHY_DATA       PhyData[MPI_SAS_IOUNIT0_PHY_MAX];   /* 10h */
+} fCONFIG_PAGE_SAS_IO_UNIT_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_0,
+  SasIOUnitPage0_t, MPI_POINTER pSasIOUnitPage0_t;
+
+#define MPI_SASIOUNITPAGE0_PAGEVERSION      (0x00)
+
+/* values for SAS IO Unit Page 0 PortFlags */
+#define MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS    (0x08)
+#define MPI_SAS_IOUNIT0_PORT_FLAGS_0_TARGET_IOC_NUM         (0x00)
+#define MPI_SAS_IOUNIT0_PORT_FLAGS_1_TARGET_IOC_NUM         (0x04)
+#define MPI_SAS_IOUNIT0_PORT_FLAGS_WAIT_FOR_PORTENABLE      (0x02)
+#define MPI_SAS_IOUNIT0_PORT_FLAGS_AUTO_PORT_CONFIG         (0x01)
+
+/* values for SAS IO Unit Page 0 PhyFlags */
+#define MPI_SAS_IOUNIT0_PHY_FLAGS_PHY_DISABLED              (0x04)
+#define MPI_SAS_IOUNIT0_PHY_FLAGS_TX_INVERT                 (0x02)
+#define MPI_SAS_IOUNIT0_PHY_FLAGS_RX_INVERT                 (0x01)
+
+/* values for SAS IO Unit Page 0 NegotiatedLinkRate */
+#define MPI_SAS_IOUNIT0_RATE_UNKNOWN                        (0x00)
+#define MPI_SAS_IOUNIT0_RATE_PHY_DISABLED                   (0x01)
+#define MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION       (0x02)
+#define MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE              (0x03)
+#define MPI_SAS_IOUNIT0_RATE_1_5                            (0x08)
+#define MPI_SAS_IOUNIT0_RATE_3_0                            (0x09)
+
+/* see mpi_sas.h for values for SAS IO Unit Page 0 ControllerPhyDeviceInfo values */
+
+
+typedef struct _MPI_SAS_IO_UNIT1_PHY_DATA
+{
+    U8          Port;                   /* 00h */
+    U8          PortFlags;              /* 01h */
+    U8          PhyFlags;               /* 02h */
+    U8          MaxMinLinkRate;         /* 03h */
+    U32         ControllerPhyDeviceInfo;/* 04h */
+    U32         Reserved1;              /* 08h */
+} MPI_SAS_IO_UNIT1_PHY_DATA, MPI_POINTER PTR_MPI_SAS_IO_UNIT1_PHY_DATA,
+  SasIOUnit1PhyData, MPI_POINTER pSasIOUnit1PhyData;
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_SAS_IOUNIT1_PHY_MAX
+#define MPI_SAS_IOUNIT1_PHY_MAX         (1)
+#endif
+
+typedef struct _CONFIG_PAGE_SAS_IO_UNIT_1
+{
+    fCONFIG_EXTENDED_PAGE_HEADER Header;                             /* 00h */
+    U32                         Reserved1;                          /* 08h */
+    U8                          NumPhys;                            /* 0Ch */
+    U8                          Reserved2;                          /* 0Dh */
+    U16                         Reserved3;                          /* 0Eh */
+    MPI_SAS_IO_UNIT1_PHY_DATA   PhyData[MPI_SAS_IOUNIT1_PHY_MAX];   /* 10h */
+} fCONFIG_PAGE_SAS_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_1,
+  SasIOUnitPage1_t, MPI_POINTER pSasIOUnitPage1_t;
+
+#define MPI_SASIOUNITPAGE1_PAGEVERSION      (0x00)
+
+/* values for SAS IO Unit Page 0 PortFlags */
+#define MPI_SAS_IOUNIT1_PORT_FLAGS_0_TARGET_IOC_NUM         (0x00)
+#define MPI_SAS_IOUNIT1_PORT_FLAGS_1_TARGET_IOC_NUM         (0x04)
+#define MPI_SAS_IOUNIT1_PORT_FLAGS_WAIT_FOR_PORTENABLE      (0x02)
+#define MPI_SAS_IOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG         (0x01)
+
+/* values for SAS IO Unit Page 0 PhyFlags */
+#define MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE               (0x04)
+#define MPI_SAS_IOUNIT1_PHY_FLAGS_TX_INVERT                 (0x02)
+#define MPI_SAS_IOUNIT1_PHY_FLAGS_RX_INVERT                 (0x01)
+
+/* values for SAS IO Unit Page 0 MaxMinLinkRate */
+#define MPI_SAS_IOUNIT1_MAX_RATE_MASK                       (0xF0)
+#define MPI_SAS_IOUNIT1_MAX_RATE_1_5                        (0x80)
+#define MPI_SAS_IOUNIT1_MAX_RATE_3_0                        (0x90)
+#define MPI_SAS_IOUNIT1_MIN_RATE_MASK                       (0x0F)
+#define MPI_SAS_IOUNIT1_MIN_RATE_1_5                        (0x08)
+#define MPI_SAS_IOUNIT1_MIN_RATE_3_0                        (0x09)
+
+/* see mpi_sas.h for values for SAS IO Unit Page 1 ControllerPhyDeviceInfo values */
+
+
+typedef struct _CONFIG_PAGE_SAS_IO_UNIT_2
+{
+    fCONFIG_EXTENDED_PAGE_HEADER         Header;                 /* 00h */
+    U32                                 Reserved1;              /* 08h */
+    U16                                 MaxPersistentIDs;       /* 0Ch */
+    U16                                 NumPersistentIDsUsed;   /* 0Eh */
+    U8                                  Status;                 /* 10h */
+    U8                                  Flags;                  /* 11h */
+    U16                                 Reserved2;              /* 12h */
+} fCONFIG_PAGE_SAS_IO_UNIT_2, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_2,
+  SasIOUnitPage2_t, MPI_POINTER pSasIOUnitPage2_t;
+
+#define MPI_SASIOUNITPAGE2_PAGEVERSION      (0x00)
+
+/* values for SAS IO Unit Page 2 Status field */
+#define MPI_SAS_IOUNIT2_STATUS_DISABLED_PERSISTENT_MAPPINGS (0x02)
+#define MPI_SAS_IOUNIT2_STATUS_FULL_PERSISTENT_MAPPINGS     (0x01)
+
+/* values for SAS IO Unit Page 2 Flags field */
+#define MPI_SAS_IOUNIT2_FLAGS_DISABLE_PERSISTENT_MAPPINGS   (0x01)
+
+
+typedef struct _CONFIG_PAGE_SAS_IO_UNIT_3
+{
+    fCONFIG_EXTENDED_PAGE_HEADER Header;                         /* 00h */
+    U32                         Reserved1;                      /* 08h */
+    U32                         MaxInvalidDwordCount;           /* 0Ch */
+    U32                         InvalidDwordCountTime;          /* 10h */
+    U32                         MaxRunningDisparityErrorCount;  /* 14h */
+    U32                         RunningDisparityErrorTime;      /* 18h */
+    U32                         MaxLossDwordSynchCount;         /* 1Ch */
+    U32                         LossDwordSynchCountTime;        /* 20h */
+    U32                         MaxPhyResetProblemCount;        /* 24h */
+    U32                         PhyResetProblemTime;            /* 28h */
+} fCONFIG_PAGE_SAS_IO_UNIT_3, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_3,
+  SasIOUnitPage3_t, MPI_POINTER pSasIOUnitPage3_t;
+
+#define MPI_SASIOUNITPAGE3_PAGEVERSION      (0x00)
+
+
+typedef struct _CONFIG_PAGE_SAS_EXPANDER_0
+{
+    fCONFIG_EXTENDED_PAGE_HEADER         Header;                 /* 00h */
+    U32                                 Reserved1;              /* 08h */
+    U64                                 SASAddress;             /* 0Ch */
+    U32                                 Reserved2;              /* 14h */
+    U16                                 DevHandle;              /* 18h */
+    U16                                 ParentDevHandle;        /* 1Ah */
+    U16                                 ExpanderChangeCount;    /* 1Ch */
+    U16                                 ExpanderRouteIndexes;   /* 1Eh */
+    U8                                  NumPhys;                /* 20h */
+    U8                                  SASLevel;               /* 21h */
+    U8                                  Flags;                  /* 22h */
+    U8                                  Reserved3;              /* 23h */
+} fCONFIG_PAGE_SAS_EXPANDER_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_EXPANDER_0,
+  SasExpanderPage0_t, MPI_POINTER pSasExpanderPage0_t;
+
+#define MPI_SASEXPANDER0_PAGEVERSION        (0x00)
+
+/* values for SAS Expander Page 0 Flags field */
+#define MPI_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG      (0x02)
+#define MPI_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS      (0x01)
+
+
+typedef struct _CONFIG_PAGE_SAS_DEVICE_0
+{
+    fCONFIG_EXTENDED_PAGE_HEADER         Header;                 /* 00h */
+    U32                                 Reserved1;              /* 08h */
+    U64                                 SASAddress;             /* 0Ch */
+    U32                                 Reserved2;              /* 14h */
+    U16                                 DevHandle;              /* 18h */
+    U8                                  TargetID;               /* 1Ah */
+    U8                                  Bus;                    /* 1Bh */
+    U32                                 DeviceInfo;             /* 1Ch */
+    U16                                 Flags;                  /* 20h */
+    U8                                  PhysicalPort;           /* 22h */
+    U8                                  Reserved3;              /* 23h */
+} fCONFIG_PAGE_SAS_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_DEVICE_0,
+  SasDevicePage0_t, MPI_POINTER pSasDevicePage0_t;
+
+#define MPI_SASDEVICE0_PAGEVERSION          (0x00)
+
+/* values for SAS Device Page 0 Flags field */
+#define MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT    (0x04)
+#define MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED         (0x02)
+#define MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT        (0x01)
+
+/* see mpi_sas.h for values for SAS Device Page 0 DeviceInfo values */
+
+
+typedef struct _CONFIG_PAGE_SAS_DEVICE_1
+{
+    fCONFIG_EXTENDED_PAGE_HEADER         Header;                 /* 00h */
+    U32                                 Reserved1;              /* 08h */
+    U64                                 SASAddress;             /* 0Ch */
+    U32                                 Reserved2;              /* 14h */
+    U16                                 DevHandle;              /* 18h */
+    U8                                  TargetID;               /* 1Ah */
+    U8                                  Bus;                    /* 1Bh */
+    U8                                  InitialRegDeviceFIS[20];/* 1Ch */
+} fCONFIG_PAGE_SAS_DEVICE_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_DEVICE_1,
+  SasDevicePage1_t, MPI_POINTER pSasDevicePage1_t;
+
+#define MPI_SASDEVICE1_PAGEVERSION          (0x00)
+
+
+typedef struct _CONFIG_PAGE_SAS_PHY_0
+{
+    fCONFIG_EXTENDED_PAGE_HEADER         Header;                 /* 00h */
+    U32                                 Reserved1;              /* 08h */
+    U64                                 SASAddress;             /* 0Ch */
+    U16                                 AttachedDevHandle;      /* 14h */
+    U8                                  AttachedPhyIdentifier;  /* 16h */
+    U8                                  Reserved2;              /* 17h */
+    U32                                 AttachedDeviceInfo;     /* 18h */
+    U8                                  ProgrammedLinkRate;     /* 20h */
+    U8                                  HwLinkRate;             /* 21h */
+    U8                                  ChangeCount;            /* 22h */
+    U8                                  Reserved3;              /* 23h */
+    U32                                 PhyInfo;                /* 24h */
+} fCONFIG_PAGE_SAS_PHY_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_PHY_0,
+  SasPhyPage0_t, MPI_POINTER pSasPhyPage0_t;
+
+#define MPI_SASPHY0_PAGEVERSION             (0x00)
+
+/* values for SAS PHY Page 0 ProgrammedLinkRate field */
+#define MPI_SAS_PHY0_PRATE_MAX_RATE_MASK                        (0xF0)
+#define MPI_SAS_PHY0_PRATE_MAX_RATE_NOT_PROGRAMMABLE            (0x00)
+#define MPI_SAS_PHY0_PRATE_MAX_RATE_1_5                         (0x80)
+#define MPI_SAS_PHY0_PRATE_MAX_RATE_3_0                         (0x90)
+#define MPI_SAS_PHY0_PRATE_MIN_RATE_MASK                        (0x0F)
+#define MPI_SAS_PHY0_PRATE_MIN_RATE_NOT_PROGRAMMABLE            (0x00)
+#define MPI_SAS_PHY0_PRATE_MIN_RATE_1_5                         (0x08)
+#define MPI_SAS_PHY0_PRATE_MIN_RATE_3_0                         (0x09)
+
+/* values for SAS PHY Page 0 HwLinkRate field */
+#define MPI_SAS_PHY0_HWRATE_MAX_RATE_MASK                       (0xF0)
+#define MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5                        (0x80)
+#define MPI_SAS_PHY0_HWRATE_MAX_RATE_3_0                        (0x90)
+#define MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK                       (0x0F)
+#define MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5                        (0x08)
+#define MPI_SAS_PHY0_HWRATE_MIN_RATE_3_0                        (0x09)
+
+/* values for SAS PHY Page 0 PhyInfo field */
+#define MPI_SAS_PHY0_PHYINFO_SATA_PORT_ACTIVE                   (0x00004000)
+#define MPI_SAS_PHY0_PHYINFO_SATA_PORT_SELECTOR                 (0x00002000)
+#define MPI_SAS_PHY0_PHYINFO_VIRTUAL_PHY                        (0x00001000)
+
+#define MPI_SAS_PHY0_PHYINFO_MASK_PARTIAL_PATHWAY_TIME          (0x00000F00)
+#define MPI_SAS_PHY0_PHYINFO_SHIFT_PARTIAL_PATHWAY_TIME         (8)
+
+#define MPI_SAS_PHY0_PHYINFO_MASK_ROUTING_ATTRIBUTE             (0x000000F0)
+#define MPI_SAS_PHY0_PHYINFO_DIRECT_ROUTING                     (0x00000000)
+#define MPI_SAS_PHY0_PHYINFO_SUBTRACTIVE_ROUTING                (0x00000010)
+#define MPI_SAS_PHY0_PHYINFO_TABLE_ROUTING                      (0x00000020)
+
+#define MPI_SAS_PHY0_PHYINFO_MASK_LINK_RATE                     (0x0000000F)
+#define MPI_SAS_PHY0_PHYINFO_UNKNOWN_LINK_RATE                  (0x00000000)
+#define MPI_SAS_PHY0_PHYINFO_PHY_DISABLED                       (0x00000001)
+#define MPI_SAS_PHY0_PHYINFO_NEGOTIATION_FAILED                 (0x00000002)
+#define MPI_SAS_PHY0_PHYINFO_SATA_OOB_COMPLETE                  (0x00000003)
+#define MPI_SAS_PHY0_PHYINFO_RATE_1_5                           (0x00000008)
+#define MPI_SAS_PHY0_PHYINFO_RATE_3_0                           (0x00000009)
+
+
+typedef struct _CONFIG_PAGE_SAS_PHY_1
+{
+    fCONFIG_EXTENDED_PAGE_HEADER Header;                     /* 00h */
+    U32                         Reserved1;                  /* 08h */
+    U32                         InvalidDwordCount;          /* 0Ch */
+    U32                         RunningDisparityErrorCount; /* 10h */
+    U32                         LossDwordSynchCount;        /* 14h */
+    U32                         PhyResetProblemCount;       /* 18h */
+} fCONFIG_PAGE_SAS_PHY_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_PHY_1,
+  SasPhyPage1_t, MPI_POINTER pSasPhyPage1_t;
+
+#define MPI_SASPHY1_PAGEVERSION             (0x00)
+
+
 #endif
 
--- diff/drivers/message/fusion/lsi/mpi_fc.h	2002-10-16 03:27:18.000000000 +0000
+++ source/drivers/message/fusion/lsi/mpi_fc.h	2004-03-16 09:37:55.969031584 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *  Copyright (c) 2000-2003 LSI Logic Corporation.
  *
  *
- *           Name:  MPI_FC.H
+ *           Name:  mpi_fc.h
  *          Title:  MPI Fibre Channel messages and structures
  *  Creation Date:  June 12, 2000
  *
- *    MPI_FC.H Version:  01.02.03
+ *    mpi_fc.h Version:  01.05.xx
  *
  *  Version History
  *  ---------------
@@ -45,7 +45,7 @@
 
 /*****************************************************************************
 *
-*        F C    T a r g e t    M o d e    M e s s a g e s
+*        F C    D i r e c t    A c c e s s     M e s s a g e s
 *
 *****************************************************************************/
 
@@ -334,6 +334,7 @@ typedef struct _MSG_FC_PRIMITIVE_SEND_RE
   FcPrimitiveSendRequest_t, MPI_POINTER pFcPrimitiveSendRequest_t;
 
 #define MPI_FC_PRIM_SEND_FLAGS_PORT_MASK       (0x01)
+#define MPI_FC_PRIM_SEND_FLAGS_ML_RESET_LINK   (0x02)
 #define MPI_FC_PRIM_SEND_FLAGS_RESET_LINK      (0x04)
 #define MPI_FC_PRIM_SEND_FLAGS_STOP_SEND       (0x08)
 #define MPI_FC_PRIM_SEND_FLAGS_SEND_ONCE       (0x10)
--- diff/drivers/message/fusion/lsi/mpi_init.h	2002-10-16 03:27:12.000000000 +0000
+++ source/drivers/message/fusion/lsi/mpi_init.h	2004-03-16 09:37:55.970031432 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *  Copyright (c) 2000-2003 LSI Logic Corporation.
  *
  *
- *           Name:  MPI_INIT.H
+ *           Name:  mpi_init.h
  *          Title:  MPI initiator mode messages and structures
  *  Creation Date:  June 8, 2000
  *
- *    MPI_INIT.H Version:  01.02.05
+ *    mpi_init.h Version:  01.05.xx
  *
  *  Version History
  *  ---------------
@@ -31,6 +31,8 @@
  *  10-04-01  01.02.04  Added defines for SEP request Action field.
  *  05-31-02  01.02.05  Added MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR define
  *                      for SCSI IO requests.
+ *  11-15-02  01.02.06  Added special extended SCSI Status defines for FCP.
+ *  06-26-03  01.02.07  Added MPI_SCSI_STATUS_FCPEXT_UNASSIGNED define.
  *  --------------------------------------------------------------------------
  */
 
@@ -45,7 +47,7 @@
 *****************************************************************************/
 
 /****************************************************************************/
-/*  SCSI IO messages and assocaited structures                              */
+/*  SCSI IO messages and associated structures                              */
 /****************************************************************************/
 
 typedef struct _MSG_SCSI_IO_REQUEST
@@ -78,6 +80,16 @@ typedef struct _MSG_SCSI_IO_REQUEST
 #define MPI_SCSIIO_MSGFLGS_SENSE_LOC_HOST           (0x00)
 #define MPI_SCSIIO_MSGFLGS_SENSE_LOC_IOC            (0x02)
 #define MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR  (0x04)
+#define MPI_SCSIIO_MSGFLGS_EEDP_TYPE_MASK           (0xE0)
+#define MPI_SCSIIO_MSGFLGS_EEDP_NONE                (0x00)
+#define MPI_SCSIIO_MSGFLGS_EEDP_RDPROTECT_T10       (0x20)
+#define MPI_SCSIIO_MSGFLGS_EEDP_VRPROTECT_T10       (0x40)
+#define MPI_SCSIIO_MSGFLGS_EEDP_WRPROTECT_T10       (0x60)
+#define MPI_SCSIIO_MSGFLGS_EEDP_520_READ_MODE1      (0x20)
+#define MPI_SCSIIO_MSGFLGS_EEDP_520_WRITE_MODE1     (0x40)
+#define MPI_SCSIIO_MSGFLGS_EEDP_8_9_READ_MODE1      (0x60)
+#define MPI_SCSIIO_MSGFLGS_EEDP_8_9_WRITE_MODE1     (0x80)
+
 
 /* SCSI IO LUN fields */
 
@@ -153,6 +165,10 @@ typedef struct _MSG_SCSI_IO_REPLY
 #define MPI_SCSI_STATUS_TASK_SET_FULL           (0x28)
 #define MPI_SCSI_STATUS_ACA_ACTIVE              (0x30)
 
+#define MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT    (0x80)
+#define MPI_SCSI_STATUS_FCPEXT_NO_LINK              (0x81)
+#define MPI_SCSI_STATUS_FCPEXT_UNASSIGNED           (0x82)
+
 
 /* SCSI IO Reply SCSIState values */
 
@@ -176,6 +192,33 @@ typedef struct _MSG_SCSI_IO_REPLY
 
 
 /****************************************************************************/
+/*  SCSI IO 32 Request message structure                                    */
+/****************************************************************************/
+
+typedef struct _MSG_SCSI_IO32_REQUEST
+{
+    U8                      TargetID;           /* 00h */
+    U8                      Bus;                /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      CDBLength;          /* 04h */
+    U8                      SenseBufferLength;  /* 05h */
+    U8                      Reserved;           /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U8                      LUN[8];             /* 0Ch */
+    U32                     Control;            /* 14h */
+    U8                      CDB[32];            /* 18h */
+    U32                     DataLength;         /* 38h */
+    U32                     SenseBufferLowAddr; /* 3Ch */
+    SGE_IO_UNION            SGL;                /* 40h */
+} MSG_SCSI_IO32_REQUEST, MPI_POINTER PTR_MSG_SCSI_IO32_REQUEST,
+  SCSIIO32Request_t, MPI_POINTER pSCSIIO32Request_t;
+
+/* SCSI IO 32 uses the same defines as above for SCSI IO */
+
+
+/****************************************************************************/
 /*  SCSI Task Management messages                                           */
 /****************************************************************************/
 
@@ -203,6 +246,7 @@ typedef struct _MSG_SCSI_TASK_MGMT
 #define MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET          (0x03)
 #define MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS             (0x04)
 #define MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET    (0x05)
+#define MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET        (0x06)
 
 /* MsgFlags bits */
 #define MPI_SCSITASKMGMT_MSGFLAGS_TARGET_RESET_OPTION   (0x00)
--- diff/drivers/message/fusion/lsi/mpi_ioc.h	2002-10-16 03:27:49.000000000 +0000
+++ source/drivers/message/fusion/lsi/mpi_ioc.h	2004-03-16 09:37:55.972031128 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *  Copyright (c) 2000-2003 LSI Logic Corporation.
  *
  *
- *           Name:  MPI_IOC.H
+ *           Name:  mpi_ioc.h
  *          Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages
  *  Creation Date:  August 11, 2000
  *
- *    MPI_IOC.H Version:  01.02.06
+ *    mpi_ioc.h Version:  01.05.xx
  *
  *  Version History
  *  ---------------
@@ -55,6 +55,8 @@
  *  05-31-02  01.02.06  Added define for
  *                      MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID.
  *                      Added AliasIndex to EVENT_DATA_LOGOUT structure.
+ *  04-01-03  01.02.07  Added defines for MPI_FW_HEADER_SIGNATURE_.
+ *  06-26-03  01.02.08  Added new values to the product family defines.
  *  --------------------------------------------------------------------------
  */
 
@@ -87,19 +89,21 @@ typedef struct _MSG_IOC_INIT
     U8                      Reserved1[2];               /* 0Eh */
     U32                     HostMfaHighAddr;            /* 10h */
     U32                     SenseBufferHighAddr;        /* 14h */
+    U32                     ReplyFifoHostSignalingAddr; /* 18h */
 } MSG_IOC_INIT, MPI_POINTER PTR_MSG_IOC_INIT,
   IOCInit_t, MPI_POINTER pIOCInit_t;
 
 /* WhoInit values */
-#define MPI_WHOINIT_NO_ONE                      (0x00)
-#define MPI_WHOINIT_SYSTEM_BIOS                 (0x01)
-#define MPI_WHOINIT_ROM_BIOS                    (0x02)
-#define MPI_WHOINIT_PCI_PEER                    (0x03)
-#define MPI_WHOINIT_HOST_DRIVER                 (0x04)
-#define MPI_WHOINIT_MANUFACTURER                (0x05)
+#define MPI_WHOINIT_NO_ONE                          (0x00)
+#define MPI_WHOINIT_SYSTEM_BIOS                     (0x01)
+#define MPI_WHOINIT_ROM_BIOS                        (0x02)
+#define MPI_WHOINIT_PCI_PEER                        (0x03)
+#define MPI_WHOINIT_HOST_DRIVER                     (0x04)
+#define MPI_WHOINIT_MANUFACTURER                    (0x05)
 
 /* Flags values */
-#define MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE      (0x01)
+#define MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE          (0x01)
+#define MPI_IOCINIT_FLAGS_REPLY_FIFO_HOST_SIGNAL    (0x02)
 
 typedef struct _MSG_IOC_INIT_REPLY
 {
@@ -179,8 +183,10 @@ typedef struct _MSG_IOC_FACTS_REPLY
     U8                      MaxDevices;                 /* 2Eh */
     U8                      MaxBuses;                   /* 2Fh */
     U32                     FWImageSize;                /* 30h */
-    U32                     Reserved4;                  /* 34h */
+    U32                     IOCCapabilities;            /* 34h */
     MPI_FW_VERSION          FWVersion;                  /* 38h */
+    U16                     HighPriorityQueueDepth;     /* 3Ch */
+    U16                     Reserved2;                  /* 3Eh */
 } MSG_IOC_FACTS_REPLY, MPI_POINTER PTR_MSG_IOC_FACTS_REPLY,
   IOCFactsReply_t, MPI_POINTER pIOCFactsReply_t;
 
@@ -192,12 +198,22 @@ typedef struct _MSG_IOC_FACTS_REPLY
 
 #define MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL    (0x0001)
 #define MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID     (0x0002)
+#define MPI_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL        (0x0004)
+#define MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL   (0x0008)
 
 #define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT         (0x01)
 
 #define MPI_IOCFACTS_EVENTSTATE_DISABLED            (0x00)
 #define MPI_IOCFACTS_EVENTSTATE_ENABLED             (0x01)
 
+#define MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q          (0x00000001)
+#define MPI_IOCFACTS_CAPABILITY_REPLY_HOST_SIGNAL   (0x00000002)
+#define MPI_IOCFACTS_CAPABILITY_QUEUE_FULL_HANDLING (0x00000004)
+#define MPI_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER   (0x00000008)
+#define MPI_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER     (0x00000010)
+#define MPI_IOCFACTS_CAPABILITY_EXTENDED_BUFFER     (0x00000020)
+#define MPI_IOCFACTS_CAPABILITY_EEDP                (0x00000040)
+
 
 
 /*****************************************************************************
@@ -253,6 +269,8 @@ typedef struct _MSG_PORT_FACTS_REPLY
 #define MPI_PORTFACTS_PORTTYPE_INACTIVE         (0x00)
 #define MPI_PORTFACTS_PORTTYPE_SCSI             (0x01)
 #define MPI_PORTFACTS_PORTTYPE_FC               (0x10)
+#define MPI_PORTFACTS_PORTTYPE_ISCSI            (0x20)
+#define MPI_PORTFACTS_PORTTYPE_SAS              (0x30)
 
 /* ProtocolFlags values */
 
@@ -386,6 +404,10 @@ typedef struct _MSG_EVENT_ACK_REPLY
 #define MPI_EVENT_INTEGRATED_RAID           (0x0000000B)
 #define MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE (0x0000000C)
 #define MPI_EVENT_ON_BUS_TIMER_EXPIRED      (0x0000000D)
+#define MPI_EVENT_QUEUE_FULL                (0x0000000E)
+#define MPI_EVENT_SAS_DEVICE_STATUS_CHANGE  (0x0000000F)
+#define MPI_EVENT_SAS_SES                   (0x00000010)
+#define MPI_EVENT_PERSISTENT_TABLE_FULL     (0x00000011)
 
 /* AckRequired field values */
 
@@ -433,6 +455,39 @@ typedef struct _EVENT_DATA_SCSI_DEVICE_S
 #define MPI_EVENT_SCSI_DEV_STAT_RC_NOT_RESPONDING       (0x04)
 #define MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA           (0x05)
 
+/* SAS Device Status Change Event data */
+
+typedef struct _EVENT_DATA_SAS_DEVICE_STATUS_CHANGE
+{
+    U8                      TargetID;                   /* 00h */
+    U8                      Bus;                        /* 01h */
+    U8                      ReasonCode;                 /* 02h */
+    U8                      Reserved;                   /* 03h */
+    U8                      ASC;                        /* 04h */
+    U8                      ASCQ;                       /* 05h */
+    U16                     DevHandle;                  /* 06h */
+    U32                     DeviceInfo;                 /* 08h */
+} EVENT_DATA_SAS_DEVICE_STATUS_CHANGE,
+  MPI_POINTER PTR_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE,
+  MpiEventDataSasDeviceStatusChange_t,
+  MPI_POINTER pMpiEventDataSasDeviceStatusChange_t;
+
+/* MPI SAS Device Status Change Event data ReasonCode values */
+#define MPI_EVENT_SAS_DEV_STAT_RC_ADDED                 (0x03)
+#define MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING        (0x04)
+#define MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA            (0x05)
+#define MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED      (0x06)
+
+/* SCSI Event data for Queue Full event */
+
+typedef struct _EVENT_DATA_QUEUE_FULL
+{
+    U8                      TargetID;                   /* 00h */
+    U8                      Bus;                        /* 01h */
+    U16                     CurrentDepth;               /* 02h */
+} EVENT_DATA_QUEUE_FULL, MPI_POINTER PTR_EVENT_DATA_QUEUE_FULL,
+  EventDataQueueFull_t, MPI_POINTER pEventDataQueueFull_t;
+
 /* MPI Link Status Change Event data */
 
 typedef struct _EVENT_DATA_LINK_STATUS
@@ -538,6 +593,7 @@ typedef struct _MSG_FW_DOWNLOAD
 #define MPI_FW_DOWNLOAD_ITYPE_FW            (0x01)
 #define MPI_FW_DOWNLOAD_ITYPE_BIOS          (0x02)
 #define MPI_FW_DOWNLOAD_ITYPE_NVDATA        (0x03)
+#define MPI_FW_DOWNLOAD_ITYPE_BOOTLOADER    (0x04)
 
 
 typedef struct _FWDownloadTCSGE
@@ -590,6 +646,7 @@ typedef struct _MSG_FW_UPLOAD
 #define MPI_FW_UPLOAD_ITYPE_FW_FLASH        (0x01)
 #define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH      (0x02)
 #define MPI_FW_UPLOAD_ITYPE_NVDATA          (0x03)
+#define MPI_FW_UPLOAD_ITYPE_BOOTLOADER      (0x04)
 
 typedef struct _FWUploadTCSGE
 {
@@ -653,6 +710,11 @@ typedef struct _MPI_FW_HEADER
 #define MPI_FW_HEADER_PID_TYPE_MASK             (0xF000)
 #define MPI_FW_HEADER_PID_TYPE_SCSI             (0x0000)
 #define MPI_FW_HEADER_PID_TYPE_FC               (0x1000)
+#define MPI_FW_HEADER_PID_TYPE_SAS              (0x2000)
+
+#define MPI_FW_HEADER_SIGNATURE_0               (0x5AEAA55A)
+#define MPI_FW_HEADER_SIGNATURE_1               (0xA55AEAA5)
+#define MPI_FW_HEADER_SIGNATURE_2               (0x5AA55AEA)
 
 #define MPI_FW_HEADER_PID_PROD_MASK                     (0x0F00)
 #define MPI_FW_HEADER_PID_PROD_INITIATOR_SCSI           (0x0100)
@@ -663,6 +725,7 @@ typedef struct _MPI_FW_HEADER
 #define MPI_FW_HEADER_PID_PROD_CTX_SCSI                 (0x0600)
 
 #define MPI_FW_HEADER_PID_FAMILY_MASK           (0x00FF)
+/* SCSI */
 #define MPI_FW_HEADER_PID_FAMILY_1030A0_SCSI    (0x0001)
 #define MPI_FW_HEADER_PID_FAMILY_1030B0_SCSI    (0x0002)
 #define MPI_FW_HEADER_PID_FAMILY_1030B1_SCSI    (0x0003)
@@ -673,9 +736,17 @@ typedef struct _MPI_FW_HEADER
 #define MPI_FW_HEADER_PID_FAMILY_1020C0_SCSI    (0x0008)
 #define MPI_FW_HEADER_PID_FAMILY_1035A0_SCSI    (0x0009)
 #define MPI_FW_HEADER_PID_FAMILY_1035B0_SCSI    (0x000A)
+#define MPI_FW_HEADER_PID_FAMILY_1030TA0_SCSI   (0x000B)
+#define MPI_FW_HEADER_PID_FAMILY_1020TA0_SCSI   (0x000C)
+/* Fibre Channel */
 #define MPI_FW_HEADER_PID_FAMILY_909_FC         (0x0000)
 #define MPI_FW_HEADER_PID_FAMILY_919_FC         (0x0001)
 #define MPI_FW_HEADER_PID_FAMILY_919X_FC        (0x0002)
+#define MPI_FW_HEADER_PID_FAMILY_919XL_FC       (0x0003)
+#define MPI_FW_HEADER_PID_FAMILY_949_FC         (0x0004)
+#define MPI_FW_HEADER_PID_FAMILY_959_FC         (0x0005)
+/* SAS */
+#define MPI_FW_HEADER_PID_FAMILY_1064_SAS       (0x0001)
 
 typedef struct _MPI_EXT_IMAGE_HEADER
 {
@@ -694,5 +765,6 @@ typedef struct _MPI_EXT_IMAGE_HEADER
 #define MPI_EXT_IMAGE_TYPE_UNSPECIFIED          (0x00)
 #define MPI_EXT_IMAGE_TYPE_FW                   (0x01)
 #define MPI_EXT_IMAGE_TYPE_NVDATA               (0x03)
+#define MPI_EXT_IMAGE_TYPE_BOOTLOADER           (0x04)
 
 #endif
--- diff/drivers/message/fusion/lsi/mpi_lan.h	2002-10-16 03:28:22.000000000 +0000
+++ source/drivers/message/fusion/lsi/mpi_lan.h	2004-03-16 09:37:55.973030976 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *  Copyright (c) 2000-2003 LSI Logic Corporation.
  *
  *
- *           Name:  MPI_LAN.H
+ *           Name:  mpi_lan.h
  *          Title:  MPI LAN messages and structures
  *  Creation Date:  June 30, 2000
  *
- *    MPI_LAN.H Version:  01.02.01
+ *    mpi_lan.h Version:  01.05.xx
  *
  *  Version History
  *  ---------------
--- diff/drivers/message/fusion/lsi/mpi_raid.h	2003-05-21 10:49:50.000000000 +0000
+++ source/drivers/message/fusion/lsi/mpi_raid.h	2004-03-16 09:37:55.974030824 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2001-2002 LSI Logic Corporation.
+ *  Copyright (c) 2001-2003 LSI Logic Corporation.
  *
  *
- *           Name:  MPI_RAID.H
+ *           Name:  mpi_raid.h
  *          Title:  MPI RAID message and structures
  *  Creation Date:  February 27, 2001
  *
- *    MPI_RAID.H Version:  01.02.07
+ *    mpi_raid.h Version:  01.05.xx
  *
  *  Version History
  *  ---------------
@@ -25,6 +25,9 @@
  *                      MPI_RAID_ACTION_INACTIVATE_VOLUME, and
  *                      MPI_RAID_ACTION_ADATA_INACTIVATE_ALL.
  *  07-12-02  01.02.07  Added structures for Mailbox request and reply.
+ *  11-15-02  01.02.08  Added missing MsgContext field to MSG_MAILBOX_REQUEST.
+ *  04-01-03  01.02.09  New action data option flag for
+ *                      MPI_RAID_ACTION_DELETE_VOLUME.
  *  --------------------------------------------------------------------------
  */
 
@@ -40,7 +43,7 @@
 
 
 /****************************************************************************/
-/* RAID Volume Request                                                      */
+/* RAID Action Request                                                      */
 /****************************************************************************/
 
 typedef struct _MSG_RAID_ACTION
@@ -90,6 +93,9 @@ typedef struct _MSG_RAID_ACTION
 #define MPI_RAID_ACTION_ADATA_KEEP_PHYS_DISKS       (0x00000000)
 #define MPI_RAID_ACTION_ADATA_DEL_PHYS_DISKS        (0x00000001)
 
+#define MPI_RAID_ACTION_ADATA_KEEP_LBA0             (0x00000000)
+#define MPI_RAID_ACTION_ADATA_ZERO_LBA0             (0x00000002)
+
 /* ActionDataWord defines for use with MPI_RAID_ACTION_ACTIVATE_VOLUME action */
 #define MPI_RAID_ACTION_ADATA_INACTIVATE_ALL        (0x00000001)
 
@@ -184,7 +190,7 @@ typedef struct _MSG_SCSI_IO_RAID_PT_REPL
 
 
 /****************************************************************************/
-/* Mailbox request structure */
+/* Mailbox reqeust structure */
 /****************************************************************************/
 
 typedef struct _MSG_MAILBOX_REQUEST
@@ -195,6 +201,7 @@ typedef struct _MSG_MAILBOX_REQUEST
     U16                     Reserved2;
     U8                      Reserved3;
     U8                      MsgFlags;
+    U32                     MsgContext;
     U8                      Command[10];
     U16                     Reserved4;
     SGE_IO_UNION            SGL;
--- diff/drivers/message/fusion/lsi/mpi_targ.h	2002-10-16 03:27:18.000000000 +0000
+++ source/drivers/message/fusion/lsi/mpi_targ.h	2004-03-16 09:37:55.975030672 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *  Copyright (c) 2000-2003 LSI Logic Corporation.
  *
  *
- *           Name:  MPI_TARG.H
+ *           Name:  mpi_targ.h
  *          Title:  MPI Target mode messages and structures
  *  Creation Date:  June 22, 2000
  *
- *    MPI_TARG.H Version:  01.02.07
+ *    mpi_targ.h Version:  01.05.xx
  *
  *  Version History
  *  ---------------
@@ -41,6 +41,8 @@
  *                      Added AliasIndex field to MPI_TARGET_FCP_CMD_BUFFER.
  *  09-16-02  01.02.07  Added flags for confirmed completion.
  *                      Added PRIORITY_REASON_TARGET_BUSY.
+ *  11-15-02  01.02.08  Added AliasID field to MPI_TARGET_SCSI_SPI_CMD_BUFFER.
+ *  04-01-03  01.02.09  Added OptionalOxid field to MPI_TARGET_FCP_CMD_BUFFER.
  *  --------------------------------------------------------------------------
  */
 
@@ -171,7 +173,7 @@ typedef struct _MPI_TARGET_FCP_CMD_BUFFE
     U32     FcpDl;                                      /* 1Ch */
     U8      AliasIndex;                                 /* 20h */
     U8      Reserved1;                                  /* 21h */
-    U16     Reserved2;                                  /* 22h */
+    U16     OptionalOxid;                               /* 22h */
 } MPI_TARGET_FCP_CMD_BUFFER, MPI_POINTER PTR_MPI_TARGET_FCP_CMD_BUFFER,
   MpiTargetFcpCmdBuffer, MPI_POINTER pMpiTargetFcpCmdBuffer;
 
@@ -190,6 +192,10 @@ typedef struct _MPI_TARGET_SCSI_SPI_CMD_
     U8      TaskManagementFlags;                        /* 12h */
     U8      AdditionalCDBLength;                        /* 13h */
     U8      CDB[16];                                    /* 14h */
+    /* Alias ID */
+    U8      AliasID;                                    /* 24h */
+    U8      Reserved1;                                  /* 25h */
+    U16     Reserved2;                                  /* 26h */
 } MPI_TARGET_SCSI_SPI_CMD_BUFFER,
   MPI_POINTER PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER,
   MpiTargetScsiSpiCmdBuffer, MPI_POINTER pMpiTargetScsiSpiCmdBuffer;
--- diff/drivers/message/fusion/lsi/mpi_type.h	2002-10-16 03:28:25.000000000 +0000
+++ source/drivers/message/fusion/lsi/mpi_type.h	2004-03-16 09:37:55.975030672 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *  Copyright (c) 2000-2003 LSI Logic Corporation.
  *
  *
- *           Name:  MPI_TYPE.H
+ *           Name:  mpi_type.h
  *          Title:  MPI Basic type definitions
  *  Creation Date:  June 6, 2000
  *
- *    MPI Version:  01.02.01
+ *    mpi_type.h Version:  01.05.xx
  *
  *  Version History
  *  ---------------
--- diff/drivers/message/fusion/mptbase.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/message/fusion/mptbase.c	2004-03-16 09:37:55.989028544 +0000
@@ -44,7 +44,7 @@
  *      for gobs of hard work fixing and optimizing LAN code.
  *      THANK YOU!
  *
- *  Copyright (c) 1999-2003 LSI Logic Corporation
+ *  Copyright (c) 1999-2004 LSI Logic Corporation
  *  Originally By: Steven J. Ralston
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:mpt_linux_developer@lsil.com)
@@ -209,8 +209,8 @@ static int	GetFcPortPage0(MPT_ADAPTER *i
 static int	GetIoUnitPage2(MPT_ADAPTER *ioc);
 static int	mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
 static int	mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
-static int	mpt_findImVolumes(MPT_ADAPTER *ioc);
 static void 	mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
+static void 	mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
 static void	mpt_timer_expired(unsigned long data);
 static int	SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
 static int	SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
@@ -347,14 +347,14 @@ mpt_interrupt(int irq, void *bus_id, str
 	MPT_FRAME_HDR	*mf;
 	MPT_FRAME_HDR	*mr;
 	u32		 pa;
-	int		 req_idx = -1;
+	int		 req_idx;
 	int		 cb_idx;
 	int		 type;
 	int		 freeme;
-	int		 count = 0;
 
 	ioc = bus_id;
 
+#ifdef MPT_DEBUG_IRQ
 	/*
 	 * Verify ioc pointer is ok
 	 */
@@ -369,6 +369,7 @@ mpt_interrupt(int irq, void *bus_id, str
 			return IRQ_NONE;
 		}
 	}
+#endif
 
 	/*
 	 *  Drain the reply FIFO!
@@ -521,17 +522,7 @@ mpt_interrupt(int irq, void *bus_id, str
 			spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 		}
 
-		count++;
-		dirqprintk((MYIOC_s_INFO_FMT "ISR processed frame #%d\n", ioc->name, count));
 		mb();
-
-		if (count >= MPT_MAX_REPLIES_PER_ISR) {
-			dirqprintk((MYIOC_s_INFO_FMT "ISR processed %d replies.",
-					ioc->name, count));
-			dirqprintk((" Giving this ISR a break!\n"));
-			return IRQ_HANDLED;
-		}
-
 	}	/* drain reply FIFO */
 
 	return IRQ_HANDLED;
@@ -605,7 +596,8 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRA
 	} else if (func == MPI_FUNCTION_EVENT_ACK) {
 		dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
 				ioc->name));
-	} else if (func == MPI_FUNCTION_CONFIG) {
+	} else if (func == MPI_FUNCTION_CONFIG ||
+		   func == MPI_FUNCTION_TOOLBOX) {
 		CONFIGPARMS *pCfg;
 		unsigned long flags;
 
@@ -714,11 +706,7 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DR
 			MptCallbacks[i] = cbfunc;
 			MptDriverClass[i] = dclass;
 			MptEvHandlers[i] = NULL;
-			MptDeviceDriverHandlers[i] = NULL;
 			last_drv_idx = i;
-			if (cbfunc != mpt_base_reply) {
-				mpt_inc_use_count();
-			}
 			break;
 		}
 	}
@@ -745,10 +733,6 @@ mpt_deregister(int cb_idx)
 		last_drv_idx++;
 		if (isense_idx != -1 && isense_idx <= cb_idx)
 			isense_idx++;
-
-		if (cb_idx != mpt_base_index) {
-			mpt_dec_use_count();
-		}
 	}
 }
 
@@ -890,7 +874,7 @@ mpt_device_driver_deregister(int cb_idx)
 MPT_FRAME_HDR*
 mpt_get_msg_frame(int handle, int iocid)
 {
-	MPT_FRAME_HDR *mf = NULL;
+	MPT_FRAME_HDR *mf;
 	MPT_ADAPTER *iocp;
 	unsigned long flags;
 
@@ -922,6 +906,8 @@ mpt_get_msg_frame(int handle, int iocid)
 		iocp->mfcnt++;
 #endif
 	}
+	else
+		mf = NULL;
 	spin_unlock_irqrestore(&iocp->FreeQlock, flags);
 
 #ifdef MFCNT
@@ -986,7 +972,11 @@ mpt_put_msg_frame(int handle, int iocid,
 
 		mf_dma_addr = iocp->req_frames_low_dma + req_offset;
 		CHIPREG_WRITE32(&iocp->chip->RequestFifo, mf_dma_addr);
+	} else {
+		printk (KERN_ERR
+		    "mpt_put_msg_frame: Invalid iocid=%d\n", iocid);
 	}
+
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1135,7 +1125,7 @@ mpt_send_handshake_request(int handle, i
 				 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
 
 		/* Wait for IOC doorbell int */
-		if ((ii = WaitForDoorbellInt(iocp, 2, sleepFlag)) < 0) {
+		if ((ii = WaitForDoorbellInt(iocp, 5, sleepFlag)) < 0) {
 			return ii;
 		}
 
@@ -1148,7 +1138,7 @@ mpt_send_handshake_request(int handle, i
 
 		CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
 
-		if ((r = WaitForDoorbellAck(iocp, 1, sleepFlag)) < 0) {
+		if ((r = WaitForDoorbellAck(iocp, 5, sleepFlag)) < 0) {
 			return -2;
 		}
 
@@ -1162,7 +1152,7 @@ mpt_send_handshake_request(int handle, i
 				(req_as_bytes[(ii*4) + 2] << 16) |
 				(req_as_bytes[(ii*4) + 3] << 24));
 			CHIPREG_WRITE32(&iocp->chip->Doorbell, word);
-			if ((r = WaitForDoorbellAck(iocp, 1, sleepFlag)) < 0) {
+			if ((r = WaitForDoorbellAck(iocp, 5, sleepFlag)) < 0) {
 				r = -3;
 				break;
 			}
@@ -1190,10 +1180,12 @@ mpt_send_handshake_request(int handle, i
 MPT_ADAPTER *
 mpt_adapter_find_first(void)
 {
-	MPT_ADAPTER *this = NULL;
+	MPT_ADAPTER *this;
 
 	if (! Q_IS_EMPTY(&MptAdapters))
 		this = MptAdapters.head;
+	else
+		this = NULL;
 
 	return this;
 }
@@ -1208,10 +1200,12 @@ mpt_adapter_find_first(void)
 MPT_ADAPTER *
 mpt_adapter_find_next(MPT_ADAPTER *prev)
 {
-	MPT_ADAPTER *next = NULL;
+	MPT_ADAPTER *next;
 
 	if (prev && (prev->forw != (MPT_ADAPTER*)&MptAdapters.head))
 		next = prev->forw;
+	else
+		next = NULL;
 
 	return next;
 }
@@ -1272,10 +1266,12 @@ mptbase_probe(struct pci_dev *pdev, cons
 	int		 ii;
 	int		 r = -ENODEV;
 	u64		 mask = 0xffffffffffffffffULL;
+	u8		 revision;
+	u8		 pcixcmd;
 
 	if (pci_enable_device(pdev))
 		return r;
-
+	
 	if (!pci_set_dma_mask(pdev, mask)) {
 		dprintk((KERN_INFO MYNAM
 			": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
@@ -1296,12 +1292,30 @@ mptbase_probe(struct pci_dev *pdev, cons
 		printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
 		return -ENOMEM;
 	}
-	memset(ioc, 0, sizeof(*ioc));
+	memset(ioc, 0, sizeof(MPT_ADAPTER));
 	ioc->alloc_total = sizeof(MPT_ADAPTER);
 	ioc->req_sz = MPT_DEFAULT_FRAME_SIZE;		/* avoid div by zero! */
-	ioc->reply_sz = ioc->req_sz;
+	ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
 
 	ioc->pcidev = pdev;
+
+#if defined(MPTBASE_MEM_ALLOC_FIFO_FIX)
+	memcpy(&ioc->pcidev32,ioc->pcidev,sizeof(struct pci_dev));
+	if (pci_set_dma_mask(&ioc->pcidev32, 0xFFFFFFFF)) {
+		dprintk((KERN_INFO MYNAM
+			": error setting 32bit mask\n"));
+		kfree(ioc);
+		return -ENODEV;
+	}
+
+	if (pci_set_consistent_dma_mask(&ioc->pcidev32, 0xFFFFFFFF)) {
+		dprintk((KERN_INFO MYNAM
+			": error setting 32bit mask\n"));
+		kfree(ioc);
+		return -ENODEV;
+	}
+#endif
+
 	ioc->diagPending = 0;
 	spin_lock_init(&ioc->diagLock);
 
@@ -1412,48 +1426,45 @@ mptbase_probe(struct pci_dev *pdev, cons
 	}
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
 		ioc->chip_type = FC929X;
-		ioc->prod_name = "LSIFC929X";
-		{
+		pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+		if (revision < XL_929) {
+			ioc->prod_name = "LSIFC929X";
 			/* 929X Chip Fix. Set Split transactions level
-			 * for PCIX. Set bits 5 - 6 to zero, turn on bit 4.
-			 */
-			u16 pcixcmd = 0;
-			pci_read_config_word(pdev, 0x6a, &pcixcmd);
-			pcixcmd &= 0xFF9F;
-			pcixcmd |= 0x0010;
-			pci_write_config_word(pdev, 0x6a, pcixcmd);
+		 	* for PCIX. Set MOST bits to zero.
+		 	*/
+			pci_read_config_byte(pdev, 0x6a, &pcixcmd);
+			pcixcmd &= 0x8F;
+			pci_write_config_byte(pdev, 0x6a, pcixcmd);
+		} else {
+			ioc->prod_name = "LSIFC929XL";
+			/* 929XL Chip Fix. Set MMRBC to 0x08.
+		 	*/
+			pci_read_config_byte(pdev, 0x6a, &pcixcmd);
+			pcixcmd |= 0x08;
+			pci_write_config_byte(pdev, 0x6a, pcixcmd);
 		}
 	}
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
 		ioc->chip_type = FC919X;
 		ioc->prod_name = "LSIFC919X";
-		{
-			/* 919X Chip Fix. Set Split transactions level
-			 * for PCIX. Set bits 5 - 6 to zero, turn on bit 4.
-			 */
-			u16 pcixcmd = 0;
-			pci_read_config_word(pdev, 0x6a, &pcixcmd);
-			pcixcmd &= 0xFF9F;
-			pcixcmd |= 0x0010;
-			pci_write_config_word(pdev, 0x6a, pcixcmd);
-		}
+		/* 919X Chip Fix. Set Split transactions level
+		 * for PCIX. Set MOST bits to zero.
+		 */
+		pci_read_config_byte(pdev, 0x6a, &pcixcmd);
+		pcixcmd &= 0x8F;
+		pci_write_config_byte(pdev, 0x6a, pcixcmd);
 	}
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
 		ioc->chip_type = C1030;
 		ioc->prod_name = "LSI53C1030";
-		{
-			u8 revision;
-
-			/* 1030 Chip Fix. Disable Split transactions
-			 * for PCIX. Set bits 4 - 6 to zero if Rev < C0( = 8)
-			 */
-			pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
-			if (revision < 0x08) {
-				u16 pcixcmd = 0;
-				pci_read_config_word(pdev, 0x6a, &pcixcmd);
-				pcixcmd &= 0xFF8F;
-				pci_write_config_word(pdev, 0x6a, pcixcmd);
-			}
+		/* 1030 Chip Fix. Disable Split transactions
+		 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
+		 */
+		pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+		if (revision < C0_1030) {
+			pci_read_config_byte(pdev, 0x6a, &pcixcmd);
+			pcixcmd &= 0x8F;
+			pci_write_config_byte(pdev, 0x6a, pcixcmd);
 		}
 	}
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
@@ -1515,17 +1526,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;
 	}
 
@@ -1565,6 +1577,7 @@ mptbase_remove(struct pci_dev *pdev)
 	CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
 
 	ioc->active = 0;
+	mpt_sync_irq(pdev->irq);
 
 	/* Clear any lingering interrupt */
 	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
@@ -1574,7 +1587,6 @@ mptbase_remove(struct pci_dev *pdev)
 	Q_DEL_ITEM(ioc);
 	mpt_adapter_dispose(ioc);
 
-	mptscsih_sync_irq(pdev->irq);
 	pci_set_drvdata(pdev, NULL);
 }
 
@@ -1755,20 +1767,23 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
 	int	 r;
 	int	 ii;
 	int	 handlers;
+	int	 ret = 0;
+	int	 reset_alt_ioc_active = 0;
 
 	printk(KERN_INFO MYNAM ": Initiating %s %s\n",
 			ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
 
-	/* Disable reply interrupts */
+	/* Disable reply interrupts (also blocks FreeQ) */
 	CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
 	ioc->active = 0;
-	/* NOTE: Access to IOC's request FreeQ is now blocked! */
 
 	if (ioc->alt_ioc) {
-		/* Disable alt-IOC's reply interrupts for a bit ... */
+		if (ioc->alt_ioc->active)
+			reset_alt_ioc_active = 1;
+
+		/* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
 		CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
 		ioc->alt_ioc->active = 0;
-		/* NOTE: Access to alt-IOC's request FreeQ is now blocked! */
 	}
 
 	hard = 1;
@@ -1776,15 +1791,29 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
 		hard = 0;
 
 	if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
-		printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
-				ioc->name);
+		if (hard_reset_done == -4) {
+			printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
+					ioc->name);
+
+			if (reset_alt_ioc_active && ioc->alt_ioc) {
+				/* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
+				dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
+						ioc->alt_ioc->name));
+				CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM));
+				ioc->alt_ioc->active = 1;
+			}
+
+		} else {
+			printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
+					ioc->name);
+		}
 		return -1;
 	}
 
 	/* hard_reset_done = 0 if a soft reset was performed
 	 * and 1 if a hard reset was performed.
 	 */
-	if (hard_reset_done && ioc->alt_ioc) {
+	if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
 		if ((r = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
 			alt_ioc_ready = 1;
 		else
@@ -1793,42 +1822,55 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
 					ioc->alt_ioc->name, r);
 	}
 
-	/* Get IOC facts! */
+	/* Get IOC facts! Allow 1 retry */
 	if ((r = GetIocFacts(ioc, sleepFlag, reason)) != 0)
-		return -2;
-	if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+		r = GetIocFacts(ioc, sleepFlag, reason);
+
+	if (r) {
+		ret = -2;
+	} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
 		MptDisplayIocCapabilities(ioc);
 	}
 
 	if (alt_ioc_ready) {
-		if ((r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0)
-			return -2;
-		if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+		if ((r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
+			/* Retry - alt IOC was initialized once
+			 */
+			r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
+		}
+		if (r) {
+			alt_ioc_ready = 0;
+			reset_alt_ioc_active = 0;
+		} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
 			MptDisplayIocCapabilities(ioc->alt_ioc);
 		}
 	}
 
-	/*
-	 * Prime reply & request queues!
+	/* Prime reply & request queues!
 	 * (mucho alloc's) Must be done prior to
 	 * init as upper addresses are needed for init.
+	 * If fails, continue with alt-ioc processing
 	 */
-	if ((r = PrimeIocFifos(ioc)) != 0)
-		return -3;
+	if ((ret == 0) && ((r = PrimeIocFifos(ioc)) != 0))
+		ret = -3;
 
-	// May need to check/upload firmware & data here!
-	if ((r = SendIocInit(ioc, sleepFlag)) != 0)
-		return -4;
+	/* May need to check/upload firmware & data here!
+	 * If fails, continue with alt-ioc processing
+	 */
+	if ((ret == 0) && ((r = SendIocInit(ioc, sleepFlag)) != 0))
+		ret = -4;
 // NEW!
 	if (alt_ioc_ready && ((r = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
 		printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
 				ioc->alt_ioc->name, r);
 		alt_ioc_ready = 0;
+		reset_alt_ioc_active = 0;
 	}
 
 	if (alt_ioc_ready) {
 		if ((r = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
 			alt_ioc_ready = 0;
+			reset_alt_ioc_active = 0;
 			printk(KERN_WARNING MYNAM
 				": alt-%s: (%d) init failure WARNING!\n",
 					ioc->alt_ioc->name, r);
@@ -1840,9 +1882,14 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
 			ddlprintk((MYIOC_s_INFO_FMT
 				"firmware upload required!\n", ioc->name));
 
-			r = mpt_do_upload(ioc, sleepFlag);
-			if (r != 0)
-				printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
+			/* Controller is not operational, cannot do upload
+			 */
+			if (ret == 0) {
+				r = mpt_do_upload(ioc, sleepFlag);
+				if (r != 0)
+					printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
+			}
+
 			/* Handle the alt IOC too */
 			if ((alt_ioc_ready) && (ioc->alt_ioc->upload_fw)){
 				ddlprintk((MYIOC_s_INFO_FMT
@@ -1855,12 +1902,13 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
 		}
 	}
 
+	if (ret == 0) {
+		/* Enable! (reply interrupt) */
+		CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
+		ioc->active = 1;
+	}
 
-	/* Enable! (reply interrupt) */
-	CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
-	ioc->active = 1;
-
-	if (ioc->alt_ioc) {
+	if (reset_alt_ioc_active && ioc->alt_ioc) {
 		/* (re)Enable alt-IOC! (reply interrupt) */
 		dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
 				ioc->alt_ioc->name));
@@ -1872,7 +1920,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
 	 *  Enable MPT base driver management of EventNotification
 	 *  and EventAck handling.
 	 */
-	if (!ioc->facts.EventState)
+	if ((ret == 0) && (!ioc->facts.EventState))
 		(void) SendEventNotification(ioc, 1);	/* 1=Enable EventNotification */
 
 	if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
@@ -1886,7 +1934,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
 	 *	routine calls HardResetHandler, which calls into here again,
 	 *	and we try GetLanConfigPages again...
 	 */
-	if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+	if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
 		if ((int)ioc->chip_type <= (int)FC929) {
 			/*
 			 *  Pre-fetch FC port WWN and stuff...
@@ -1928,6 +1976,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
 			/* Check, and possibly reset, the coalescing value
 			 */
 			mpt_read_ioc_pg_1(ioc);
+
+			mpt_read_ioc_pg_4(ioc);
 		}
 
 		GetIoUnitPage2(ioc);
@@ -1942,24 +1992,24 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
 	if (hard_reset_done) {
 		r = handlers = 0;
 		for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
-			if (MptResetHandlers[ii]) {
+			if ((ret == 0) && MptResetHandlers[ii]) {
 				dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
 						ioc->name, ii));
 				r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET);
 				handlers++;
+			}
 
-				if (alt_ioc_ready) {
-					dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
-							ioc->name, ioc->alt_ioc->name, ii));
-					r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
-					handlers++;
-				}
+			if (alt_ioc_ready && MptResetHandlers[ii]) {
+				dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
+						ioc->name, ioc->alt_ioc->name, ii));
+				r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
+				handlers++;
 			}
 		}
 		/* FIXME?  Examine results here? */
 	}
 
-	return 0;
+	return ret;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2114,6 +2164,15 @@ mpt_adapter_disable(MPT_ADAPTER *this, i
 			kfree(this->spi_data.pIocPg3);
 			this->spi_data.pIocPg3 = NULL;
 		}
+
+		if (freeup && this->spi_data.pIocPg4 != NULL) {
+			sz = this->spi_data.IocPg4Sz;
+			pci_free_consistent(this->pcidev, sz,
+				this->spi_data.pIocPg4,
+				this->spi_data.IocPg4_dma);
+			this->spi_data.pIocPg4 = NULL;
+			this->alloc_total -= sz;
+		}
 	}
 }
 
@@ -2429,7 +2488,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF
 	 * 1 byte in size, so we can just fire it off as is.
 	 */
 	r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
-			reply_sz, (u16*)facts, 3 /*seconds*/, sleepFlag);
+			reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
 	if (r != 0)
 		return r;
 
@@ -2510,7 +2569,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF
 			 */
 			ioc->req_sz = MIN(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
 			ioc->req_depth = MIN(MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
-			ioc->reply_sz = ioc->req_sz;
+			ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
 			ioc->reply_depth = MIN(MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
 
 			dprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
@@ -2578,7 +2637,7 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn
 	 * 1 byte in size, so we can just fire it off as is.
 	 */
 	ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
-				reply_sz, (u16*)pfacts, 3 /*seconds*/, sleepFlag);
+				reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
 	if (ii != 0)
 		return ii;
 
@@ -2651,6 +2710,8 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF
 /*	ioc_init.MsgFlags = 0;				*/
 /*	ioc_init.MsgContext = cpu_to_le32(0x00000000);	*/
 	ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz);	/* in BYTES */
+		
+	ioc->facts.RequestFrameSize = ioc_init.ReplyFrameSize;
 
 	if (sizeof(dma_addr_t) == sizeof(u64)) {
 		/* Save the upper 32-bits of the request
@@ -2663,6 +2724,9 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF
 		ioc_init.HostMfaHighAddr = cpu_to_le32(0);
 		ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
 	}
+		
+	ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
+	ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
 
 	dprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
 			ioc->name, &ioc_init));
@@ -2773,8 +2837,8 @@ SendPortEnable(MPT_ADAPTER *ioc, int por
 void *
 mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz)
 {
-	fw_image_t	**cached_fw = NULL;
-	u8		*mem = NULL;
+	fw_image_t	**cached_fw;
+	u8		*mem;
 	dma_addr_t	fw_dma;
 	int		alloc_total = 0;
 	int		bytes_left, bytes, num_frags;
@@ -2922,7 +2986,7 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee
 	u8			 reply[sizeof(FWUploadReply_t)];
 	FWUpload_t		*prequest;
 	FWUploadReply_t		*preply;
-	FWUploadTCSGE_t		*ptcsge = NULL;
+	FWUploadTCSGE_t		*ptcsge;
 	int			 sgeoffset;
 	int			 ii, sz, reply_sz;
 	int			 cmdStatus, freeMem = 0;
@@ -3054,16 +3118,16 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee
 static int
 mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag)
 {
-	MpiFwHeader_t		*FwHdr = NULL;
+	MpiFwHeader_t		*FwHdr;
 	MpiExtImageHeader_t 	*ExtHdr;
-	fw_image_t		**pCached = NULL;
+	fw_image_t		**pCached=NULL;
 	int			 fw_sz;
 	u32			 diag0val;
 #ifdef MPT_DEBUG
 	u32			 diag1val = 0;
 #endif
 	int			 count = 0;
-	u32			*ptru32 = NULL;
+	u32			*ptru32;
 	u32			 diagRwData;
 	u32			 nextImage;
 	u32			 ext_offset;
@@ -3097,11 +3161,11 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int s
 		pCached = (fw_image_t **)ioc->cached_fw;
 	else if (ioc->alt_ioc && (ioc->alt_ioc->cached_fw != NULL))
 		pCached = (fw_image_t **)ioc->alt_ioc->cached_fw;
+	else
+		return -2;
 
 	ddlprintk((MYIOC_s_INFO_FMT "DbGb2: FW Image @ %p\n",
 			ioc->name, pCached));
-	if (!pCached)
-		return -2;
 
 	/* Write magic sequence to WriteSequence register
 	 * until enter diagnostic mode
@@ -3351,6 +3415,7 @@ KickStart(MPT_ADAPTER *ioc, int force, i
 		SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
 
 		if (sleepFlag == CAN_SLEEP) {
+			set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout(HZ);
 		} else {
 			mdelay (1000);
@@ -3551,11 +3616,11 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign
 		} else {
 			/* Wait for FW to reload and for board
 			 * to go to the READY state.
-			 * Maximum wait is 30 seconds.
+			 * Maximum wait is 60 seconds.
 			 * If fail, no error will check again
 			 * with calling program.
 			 */
-			for (count = 0; count < 30; count ++) {
+			for (count = 0; count < 60; count ++) {
 				doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
 				doorbell &= MPI_IOC_STATE_MASK;
 
@@ -3673,7 +3738,7 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_
 	dprintk((KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
 			ioc->name, reset_type));
 	CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
-	if ((r = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0)
+	if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
 		return r;
 
 	/* FW ACK'd request, wait for READY state
@@ -3736,7 +3801,11 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
 
 	if (ioc->reply_frames == NULL) {
 		sz = (ioc->reply_sz * ioc->reply_depth) + 128;
+#if defined(MPTBASE_MEM_ALLOC_FIFO_FIX)
+		mem = pci_alloc_consistent(&ioc->pcidev32, sz, &ioc->reply_alloc_dma);
+#else		
 		mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->reply_alloc_dma);
+#endif		
 		if (mem == NULL)
 			goto out_fail;
 
@@ -3778,7 +3847,11 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
 		 */
 		sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
 
+#if defined(MPTBASE_MEM_ALLOC_FIFO_FIX)
+		mem = pci_alloc_consistent(&ioc->pcidev32, sz, &ioc->req_alloc_dma);
+#else
 		mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->req_alloc_dma);
+#endif		
 		if (mem == NULL)
 			goto out_fail;
 
@@ -3894,8 +3967,8 @@ out_fail:
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *	mpt_handshake_req_reply_wait - Send MPT request to and receive reply from
- *	IOC via doorbell handshake method.
+ *	mpt_handshake_req_reply_wait - Send MPT request to and receive reply
+ *	from IOC via doorbell handshake method.
  *	@ioc: Pointer to MPT_ADAPTER structure
  *	@reqBytes: Size of the request in bytes
  *	@req: Pointer to MPT request frame
@@ -3955,7 +4028,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER
 	 * our handshake request.
 	 */
 	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
-	if (!failcnt && (t = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0)
+	if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
 		failcnt++;
 
 	if (!failcnt) {
@@ -3973,7 +4046,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER
 				    (req_as_bytes[(ii*4) + 3] << 24));
 
 			CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
-			if ((t = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0)
+			if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
 				failcnt++;
 		}
 
@@ -4137,7 +4210,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, i
 	} else {
 		hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
 		CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
-		if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0)
+		if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
 			failcnt++;
 		else {
 			hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
@@ -4154,7 +4227,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, i
 	 * reply 16 bits at a time.
 	 */
 	for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
-		if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0)
+		if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
 			failcnt++;
 		hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
 		/* don't overflow our IOC hs_reply[] buffer! */
@@ -4163,7 +4236,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, i
 		CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
 	}
 
-	if (!failcnt && (t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0)
+	if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
 		failcnt++;
 	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
 
@@ -4466,7 +4539,7 @@ GetIoUnitPage2(MPT_ADAPTER *ioc)
 static int
 mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
 {
-	u8			*pbuf = NULL;
+	u8			*pbuf;
 	dma_addr_t		 buf_dma;
 	CONFIGPARMS		 cfg;
 	ConfigPageHeader_t	 header;
@@ -4528,6 +4601,9 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc
 				pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
 				pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
 
+				if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 )
+					ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
+
 				ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
 				data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
 				if (data) {
@@ -4552,7 +4628,6 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc
 			}
 			if (pbuf) {
 				pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
-				pbuf = NULL;
 			}
 		}
 	}
@@ -4589,6 +4664,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc
 				/* Save the Port Page 2 data
 				 * (reformat into a 32bit quantity)
 				 */
+				data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
+				ioc->spi_data.PortFlags = data;
 				for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
 					pdevice = &pPP2->DeviceSettings[ii];
 					data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
@@ -4598,7 +4675,6 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc
 			}
 
 			pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
-			pbuf = NULL;
 		}
 	}
 
@@ -4671,11 +4747,12 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTE
  *	-EFAULT if read of config page header fails or data pointer not NULL
  *	-ENOMEM if pci_alloc failed
  */
-static int
+int
 mpt_findImVolumes(MPT_ADAPTER *ioc)
 {
-	IOCPage2_t		*pIoc2 = NULL;
-	ConfigPageIoc2RaidVol_t	*pIocRv = NULL;
+	IOCPage2_t		*pIoc2;
+	u8			*mem;
+	ConfigPageIoc2RaidVol_t	*pIocRv;
 	dma_addr_t		 ioc2_dma;
 	CONFIGPARMS		 cfg;
 	ConfigPageHeader_t	 header;
@@ -4685,9 +4762,6 @@ mpt_findImVolumes(MPT_ADAPTER *ioc)
 	u8			 nVols, nPhys;
 	u8			 vid, vbus, vioc;
 
-	if (ioc->spi_data.pIocPg3)
-		return -EFAULT;	
-
 	/* Read IOCP2 header then the page.
 	 */
 	header.PageVersion = 0;
@@ -4716,11 +4790,22 @@ mpt_findImVolumes(MPT_ADAPTER *ioc)
 	if (mpt_config(ioc, &cfg) != 0)
 		goto done_and_free;
 
+	if ( (mem = (u8 *)ioc->spi_data.pIocPg2) == NULL ) {
+		mem = kmalloc(iocpage2sz, GFP_ATOMIC);
+		if (mem) {
+			ioc->spi_data.pIocPg2 = (IOCPage2_t *) mem;
+		} else {
+			goto done_and_free;
+		}
+	}
+	memcpy(mem, (u8 *)pIoc2, iocpage2sz);
+
 	/* Identify RAID Volume Id's */
 	nVols = pIoc2->NumActiveVolumes;
 	if ( nVols == 0) {
-		/* No RAID Volumes.  Done.
+		/* No RAID Volume.
 		 */
+		goto done_and_free;
 	} else {
 		/* At least 1 RAID Volume
 		 */
@@ -4745,17 +4830,14 @@ mpt_findImVolumes(MPT_ADAPTER *ioc)
 	/* Identify Hidden Physical Disk Id's */
 	nPhys = pIoc2->NumActivePhysDisks;
 	if (nPhys == 0) {
-		/* No physical disks. Done.
+		/* No physical disks.
 		 */
 	} else {
 		mpt_read_ioc_pg_3(ioc);
 	}
 
 done_and_free:
-	if (pIoc2) {
-		pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
-		pIoc2 = NULL;
-	}
+	pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
 
 	return rc;
 }
@@ -4763,7 +4845,7 @@ done_and_free:
 int
 mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
 {
-	IOCPage3_t		*pIoc3 = NULL;
+	IOCPage3_t		*pIoc3;
 	u8			*mem;
 	CONFIGPARMS		 cfg;
 	ConfigPageHeader_t	 header;
@@ -4816,18 +4898,66 @@ mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
 		}
 	}
 
-	if (pIoc3) {
-		pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
-		pIoc3 = NULL;
-	}
+	pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
 
 	return 0;
 }
 
 static void
+mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
+{
+	IOCPage4_t		*pIoc4;
+	CONFIGPARMS		 cfg;
+	ConfigPageHeader_t	 header;
+	dma_addr_t		 ioc4_dma;
+	int			 iocpage4sz;
+
+	/* Read and save IOC Page 4
+	 */
+	header.PageVersion = 0;
+	header.PageLength = 0;
+	header.PageNumber = 4;
+	header.PageType = MPI_CONFIG_PAGETYPE_IOC;
+	cfg.hdr = &header;
+	cfg.physAddr = -1;
+	cfg.pageAddr = 0;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.dir = 0;
+	cfg.timeout = 0;
+	if (mpt_config(ioc, &cfg) != 0)
+		return;
+
+	if (header.PageLength == 0)
+		return;
+
+	if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
+		iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
+		pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
+		if (!pIoc4)
+			return;
+	} else {
+		ioc4_dma = ioc->spi_data.IocPg4_dma;
+		iocpage4sz = ioc->spi_data.IocPg4Sz;
+	}
+
+	/* Read the Page into dma memory.
+	 */
+	cfg.physAddr = ioc4_dma;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+	if (mpt_config(ioc, &cfg) == 0) {
+		ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
+		ioc->spi_data.IocPg4_dma = ioc4_dma;
+		ioc->spi_data.IocPg4Sz = iocpage4sz;
+	} else {
+		pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
+		ioc->spi_data.pIocPg4 = NULL;
+	}
+}
+
+static void
 mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
 {
-	IOCPage1_t		*pIoc1 = NULL;
+	IOCPage1_t		*pIoc1;
 	CONFIGPARMS		 cfg;
 	ConfigPageHeader_t	 header;
 	dma_addr_t		 ioc1_dma;
@@ -4903,10 +5033,7 @@ mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
 		}
 	}
 
-	if (pIoc1) {
-		pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
-		pIoc1 = NULL;
-	}
+	pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
 
 	return;
 }
@@ -5022,9 +5149,8 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS
 	pReq->Reserved = 0;
 	pReq->ChainOffset = 0;
 	pReq->Function = MPI_FUNCTION_CONFIG;
-	pReq->Reserved1[0] = 0;
-	pReq->Reserved1[1] = 0;
-	pReq->Reserved1[2] = 0;
+	pReq->ExtPageLength = 0;
+	pReq->ExtPageType = 0;
 	pReq->MsgFlags = 0;
 	for (ii=0; ii < 8; ii++)
 		pReq->Reserved2[ii] = 0;
@@ -5083,6 +5209,112 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_toolbox - Generic function to issue toolbox message
+ *	@ioc - Pointer to an adapter structure
+ *	@cfg - Pointer to a toolbox structure. Struct contains
+ *		action, page address, direction, physical address
+ *		and pointer to a configuration page header
+ *		Page header is updated.
+ *
+ *	Returns 0 for success
+ *	-EPERM if not allowed due to ISR context
+ *	-EAGAIN if no msg frames currently available
+ *	-EFAULT for non-successful reply or no reply (timeout)
+ */
+int
+mpt_toolbox(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
+{
+	ToolboxIstwiReadWriteRequest_t	*pReq;
+	MPT_FRAME_HDR	*mf;
+	unsigned long	 flags;
+	int		 rc;
+	int		 flagsLength;
+	int		 in_isr;
+
+	/* (Bugzilla:fibrebugs, #513)
+	 * Bug fix (part 1)!  20010905 -sralston
+	 *	Prevent calling wait_event() (below), if caller happens
+	 *	to be in ISR context, because that is fatal!
+	 */
+	in_isr = in_interrupt();
+	if (in_isr) {
+		dcprintk((MYIOC_s_WARN_FMT "toobox request not allowed in ISR context!\n",
+				ioc->name));
+		return -EPERM;
+	}
+
+	/* Get and Populate a free Frame
+	 */
+	if ((mf = mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) {
+		dcprintk((MYIOC_s_WARN_FMT "mpt_toolbox: no msg frames!\n",
+				ioc->name));
+		return -EAGAIN;
+	}
+	pReq = (ToolboxIstwiReadWriteRequest_t	*)mf;
+	pReq->Tool = pCfg->action;
+	pReq->Reserved = 0;
+	pReq->ChainOffset = 0;
+	pReq->Function = MPI_FUNCTION_TOOLBOX;
+	pReq->Reserved1 = 0;
+	pReq->Reserved2 = 0;
+	pReq->MsgFlags = 0;
+	pReq->Flags = pCfg->dir;
+	pReq->BusNum = 0;
+	pReq->Reserved3 = 0;
+	pReq->NumAddressBytes = 0x01;
+	pReq->Reserved4 = 0;
+	pReq->DataLength = 0x04;
+	pReq->DeviceAddr = 0xB0;
+	pReq->Addr1 = 0;
+	pReq->Addr2 = 0;
+	pReq->Addr3 = 0;
+	pReq->Reserved5 = 0;
+
+	/* Add a SGE to the config request.
+	 */
+
+	flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | 4;
+
+	mpt_add_sge((char *)&pReq->SGL, flagsLength, pCfg->physAddr);
+
+	dcprintk((MYIOC_s_INFO_FMT "Sending Toolbox request, Tool=%x\n",
+		ioc->name, pReq->Tool));
+
+	/* Append pCfg pointer to end of mf
+	 */
+	*((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) =  (void *) pCfg;
+
+	/* Initalize the timer
+	 */
+	init_timer(&pCfg->timer);
+	pCfg->timer.data = (unsigned long) ioc;
+	pCfg->timer.function = mpt_timer_expired;
+	pCfg->wait_done = 0;
+
+	/* Set the timer; ensure 10 second minimum */
+	if (pCfg->timeout < 10)
+		pCfg->timer.expires = jiffies + HZ*10;
+	else
+		pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
+
+	/* Add to end of Q, set timer and then issue this command */
+	spin_lock_irqsave(&ioc->FreeQlock, flags);
+	Q_ADD_TAIL(&ioc->configQ.head, &pCfg->linkage, Q_ITEM);
+	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+	add_timer(&pCfg->timer);
+	mpt_put_msg_frame(mpt_base_index, ioc->id, mf);
+	wait_event(mpt_waitq, pCfg->wait_done);
+
+	/* mf has been freed - do not access */
+
+	rc = pCfg->status;
+
+	return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *	mpt_timer_expired - Call back for timer process.
  *	Used only internal config functionality.
@@ -5124,9 +5356,12 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int rese
 
 	dprintk((KERN_WARNING MYNAM
 			": IOC %s_reset routed to MPT base driver!\n",
-			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
+			reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
 
-	if (reset_phase == MPT_IOC_PRE_RESET) {
+	if (reset_phase == MPT_IOC_SETUP_RESET) {
+		;
+	} else if (reset_phase == MPT_IOC_PRE_RESET) {
 		/* If the internal config Q is not empty -
 		 * delete timer. MF resources will be freed when
 		 * the FIFO's are primed.
@@ -5590,7 +5825,7 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, i
 	int		 rc;
 	unsigned long	 flags;
 
-	dprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
+	dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
 #ifdef MFCNT
 	printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
 	printk("MF count 0x%x !\n", ioc->mfcnt);
@@ -5611,6 +5846,29 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, i
 	/* FIXME: If do_ioc_recovery fails, repeat....
 	 */
 
+	/* The SCSI driver needs to adjust timeouts on all current
+	 * commands prior to the diagnostic reset being issued.
+	 * Prevents timeouts occuring during a diagnostic reset...very bad.
+	 * For all other protocol drivers, this is a no-op.
+	 */
+	{
+		int	 ii;
+		int	 r = 0;
+
+		for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+			if (MptResetHandlers[ii]) {
+				dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
+						ioc->name, ii));
+				r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_SETUP_RESET);
+				if (ioc->alt_ioc) {
+					dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
+							ioc->name, ioc->alt_ioc->name, ii));
+					r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_SETUP_RESET);
+				}
+			}
+		}
+	}
+
 	if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
 		printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
 			rc, ioc->name);
@@ -5625,7 +5883,7 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, i
 		ioc->alt_ioc->diagPending = 0;
 	spin_unlock_irqrestore(&ioc->diagLock, flags);
 
-	dprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
+	dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
 
 	return rc;
 }
@@ -5634,7 +5892,7 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, i
 static char *
 EventDescriptionStr(u8 event, u32 evData0)
 {
-	char *ds = NULL;
+	char *ds;
 
 	switch(event) {
 	case MPI_EVENT_NONE:
@@ -5839,109 +6097,11 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 lo
 		"FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
 		"FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
 	};
-	char *desc = "unknown";
 	u8 subcl = (log_info >> 24) & 0x7;
-	u32 SubCl = log_info & 0x27000000;
-
-	switch(log_info) {
-/* FCP Initiator */
-	case MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME:
-		desc = "Received an out of order frame - unsupported";
-		break;
-	case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME:
-		desc = "Bad start of frame primative";
-		break;
-	case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME:
-		desc = "Bad end of frame primative";
-		break;
-	case MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN:
-		desc = "Receiver hardware detected overrun";
-		break;
-	case MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER:
-		desc = "Other errors caught by IOC which require retries";
-		break;
-	case MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD:
-		desc = "Main processor could not initialize sub-processor";
-		break;
-/* FC Target */
-	case MPI_IOCLOGINFO_FC_TARGET_NO_PDISC:
-		desc = "Not sent because we are waiting for a PDISC from the initiator";
-		break;
-	case MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN:
-		desc = "Not sent because we are not logged in to the remote node";
-		break;
-	case MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP:
-		desc = "Data Out, Auto Response, not sent due to a LIP";
-		break;
-	case MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP:
-		desc = "Data In, Auto Response, not sent due to a LIP";
-		break;
-	case MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA:
-		desc = "Data In, Auto Response, missing data frames";
-		break;
-	case MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP:
-		desc = "Data Out, No Response, not sent due to a LIP";
-		break;
-	case MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP:
-		desc = "Auto-response after a write not sent due to a LIP";
-		break;
-	case MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP:
-		desc = "Data In, No Response, not completed due to a LIP";
-		break;
-	case MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA:
-		desc = "Data In, No Response, missing data frames";
-		break;
-	case MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP:
-		desc = "Manual Response not sent due to a LIP";
-		break;
-	case MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3:
-		desc = "Not sent because remote node does not support Class 3";
-		break;
-	case MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID:
-		desc = "Not sent because login to remote node not validated";
-		break;
-	case MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND:
-		desc = "Cleared from the outbound queue after a logout";
-		break;
-	case MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN:
-		desc = "Cleared waiting for data after a logout";
-		break;
-/* LAN */
-	case MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING:
-		desc = "Transaction Context Sgl Missing";
-		break;
-	case MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE:
-		desc = "Transaction Context found before an EOB";
-		break;
-	case MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET:
-		desc = "Transaction Context value has reserved bits set";
-		break;
-	case MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG:
-		desc = "Invalid SGL Flags";
-		break;
-/* FC Link */
-	case MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT:
-		desc = "Loop initialization timed out";
-		break;
-	case MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED:
-		desc = "Another system controller already initialized the loop";
-		break;
-	case MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED:
-		desc = "Not synchronized to signal or still negotiating (possible cable problem)";
-		break;
-	case MPI_IOCLOGINFO_FC_LINK_CRC_ERROR:
-		desc = "CRC check detected error on received frame";
-		break;
-	}
+//	u32 SubCl = log_info & 0x27000000;
 
 	printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}",
 			ioc->name, log_info, subcl_str[subcl]);
-	if (SubCl == MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET)
-		printk(", byte_offset=%d\n", log_info & MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET);
-	else if (SubCl == MPI_IOCLOGINFO_FC_STATE_CHANGE)
-		printk("\n");		/* StateChg in LogInfo & 0x00FFFFFF, above */
-	else
-		printk("\n" KERN_INFO " %s\n", desc);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -6021,7 +6181,6 @@ mpt_register_ascqops_strings(void *ascqT
 		isense_idx = last_drv_idx;
 		r = 1;
 	}
-	mpt_inc_use_count();
 	return r;
 }
 
@@ -6040,7 +6199,6 @@ mpt_deregister_ascqops_strings(void)
 	mpt_ScsiOpcodesPtr = NULL;
 	printk(KERN_INFO MYNAM ": English readable SCSI-3 strings disabled)-:\n");
 	isense_idx = -1;
-	mpt_dec_use_count();
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -6072,6 +6230,8 @@ EXPORT_SYMBOL(mpt_lan_index);
 EXPORT_SYMBOL(mpt_stm_index);
 EXPORT_SYMBOL(mpt_HardResetHandler);
 EXPORT_SYMBOL(mpt_config);
+EXPORT_SYMBOL(mpt_toolbox);
+EXPORT_SYMBOL(mpt_findImVolumes);
 EXPORT_SYMBOL(mpt_read_ioc_pg_3);
 EXPORT_SYMBOL(mpt_alloc_fw_memory);
 EXPORT_SYMBOL(mpt_free_fw_memory);
--- diff/drivers/message/fusion/mptbase.h	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/message/fusion/mptbase.h	2004-03-16 09:37:55.991028240 +0000
@@ -8,7 +8,7 @@
  *  Credits:
  *     (see mptbase.c)
  *
- *  Copyright (c) 1999-2003 LSI Logic Corporation
+ *  Copyright (c) 1999-2004 LSI Logic Corporation
  *  Originally By: Steven J. Ralston
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:mpt_linux_developer@lsil.com)
@@ -68,6 +68,7 @@
 
 #include "lsi/mpi_fc.h"		/* Fibre Channel (lowlevel) support */
 #include "lsi/mpi_targ.h"	/* SCSI/FCP Target protcol support */
+#include "lsi/mpi_tool.h"	/* Tools support */
 #include "lsi/fc_log.h"
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -77,11 +78,11 @@
 #endif
 
 #ifndef COPYRIGHT
-#define COPYRIGHT	"Copyright (c) 1999-2003 " MODULEAUTHOR
+#define COPYRIGHT	"Copyright (c) 1999-2004 " 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.01.01"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.01.01"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -93,10 +94,10 @@
  */
 #define MPT_MAX_ADAPTERS		18
 #define MPT_MAX_PROTOCOL_DRIVERS	16
-#define MPT_MAX_BUS			1
+#define MPT_MAX_BUS			1	/* Do not change */
 #define MPT_MAX_FC_DEVICES		255
 #define MPT_MAX_SCSI_DEVICES		16
-#define MPT_LAST_LUN			31
+#define MPT_LAST_LUN			255
 #define MPT_SENSE_BUFFER_ALLOC		64
 	/* allow for 256 max sense alloc, but only 255 max request */
 #if MPT_SENSE_BUFFER_ALLOC >= 256
@@ -127,6 +128,8 @@
 #define  MPT_MAX_FRAME_SIZE		128
 #define  MPT_DEFAULT_FRAME_SIZE		128
 
+#define  MPT_REPLY_FRAME_SIZE		0x40  /* Must be a multiple of 8 */
+
 #define  MPT_SG_REQ_128_SCALE		1
 #define  MPT_SG_REQ_96_SCALE		2
 #define  MPT_SG_REQ_64_SCALE		4
@@ -150,6 +153,9 @@
 #define MPT_NARROW			0
 #define MPT_WIDE			1
 
+#define C0_1030				0x08
+#define XL_929				0x01
+
 #ifdef __KERNEL__	/* { */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
@@ -185,8 +191,8 @@ struct mpt_pci_driver{
 	void (*remove) (struct pci_dev *dev);
 	void (*shutdown) (struct device * dev);
 #ifdef CONFIG_PM
-	int  (*suspend) (struct pci_dev *dev, u32 state);
 	int  (*resume) (struct pci_dev *dev);
+	int  (*suspend) (struct pci_dev *dev, u32 state);
 #endif
 };
 
@@ -201,9 +207,6 @@ typedef union _MPT_FRAME_TRACKER {
 		u32			 arg1;
 		u32			 pad;
 		void			*argp1;
-#ifndef MPT_SCSI_USE_NEW_EH
-		void			*argp2;
-#endif
 	} linkage;
 	/*
 	 * NOTE: When request frames are free, on the linkage structure
@@ -255,6 +258,7 @@ typedef struct _MPT_FRAME_HDR {
 		MPIHeader_t		hdr;
 		SCSIIORequest_t		scsireq;
 		SCSIIOReply_t		sreply;
+		ConfigReply_t		configreply;
 		MPIDefaultReply_t	reply;
 		MPT_FRAME_TRACKER	frame;
 	} u;
@@ -408,12 +412,9 @@ typedef struct _VirtDevice {
 	ScsiCmndTracker		 SentQ;
 	ScsiCmndTracker		 DoneQ;
 	u32			 num_luns;
-//--- LUN split here?
-	u32			 luns;		/* Max LUNs is 32 */
-	u8			 inq_data[SCSI_STD_INQUIRY_BYTES];	/* 36 */
-	u8			 pad0[4];
-	u8			 inq00_data[20];
-	u8			 pad1[4];
+	u32			 luns[8];		/* Max LUNs is 256 */
+	u8			 pad[4];
+	u8			 inq_data[8];
 		/* IEEE Registered Extended Identifier
 		   obtained via INQUIRY VPD page 0x83 */
 		/* NOTE: Do not separate uniq_prepad and uniq_data
@@ -421,26 +422,17 @@ typedef struct _VirtDevice {
 	u8			 uniq_prepad[8];
 	u8			 uniq_data[20];
 	u8			 pad2[4];
-	u8			 inqC3_data[12];
-	u8			 pad3[4];
-	u8			 inqC9_data[12];
-	u8			 pad4[4];
-	u8			 dev_vol_name[64];
 } VirtDevice;
 
 /*
  *  Fibre Channel (SCSI) target device and associated defines...
  */
-#define MPT_TARGET_DEFAULT_DV_STATUS	0
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,55)
-#define MPT_TARGET_FLAGS_CONFIGURED	0x02
-#define MPT_TARGET_FLAGS_Q_YES		0x08
-#else
+#define MPT_TARGET_DEFAULT_DV_STATUS	0x00
 #define MPT_TARGET_FLAGS_VALID_NEGO	0x01
 #define MPT_TARGET_FLAGS_VALID_INQUIRY	0x02
 #define MPT_TARGET_FLAGS_Q_YES		0x08
 #define MPT_TARGET_FLAGS_VALID_56	0x10
-#endif
+#define MPT_TARGET_FLAGS_SAF_TE_ISSUED	0x20
 
 #define MPT_TARGET_NO_NEGO_WIDE		0x01
 #define MPT_TARGET_NO_NEGO_SYNC		0x02
@@ -539,8 +531,13 @@ typedef struct _mpt_ioctl_events {
 /* #define MPT_SCSICFG_BLK_NEGO		0x10	   WriteSDP1 with WDTR and SDTR disabled */
 
 typedef	struct _ScsiCfgData {
+	u32		 PortFlags;
 	int		*nvram;			/* table of device NVRAM values */
+	IOCPage2_t	*pIocPg2;		/* table of Raid Volumes */
 	IOCPage3_t	*pIocPg3;		/* table of physical disks */
+	IOCPage4_t	*pIocPg4;		/* SEP devices addressing */
+	dma_addr_t	 IocPg4_dma;		/* Phys Addr of IOCPage4 data */
+	int		 IocPg4Sz;		/* IOCPage4 size */
 	u8		 dvStatus[MPT_MAX_SCSI_DEVICES];
 	int		 isRaid;		/* bit field, 1 if RAID */
 	u8		 minSyncFactor;		/* 0xFF if async */
@@ -554,7 +551,8 @@ typedef	struct _ScsiCfgData {
 	u8		 dvScheduled;		/* 1 if scheduled */
 	u8		 forceDv;		/* 1 to force DV scheduling */
 	u8		 noQas;			/* Disable QAS for this adapter */
-	u8		 rsvd[2];
+	u8		 Saf_Te;		/* 1 to force all Processors as SAF-TE if Inquiry data length is too short to check for SAF-TE */
+	u8		 rsvd[1];
 } ScsiCfgData;
 
 typedef struct _fw_image {
@@ -610,6 +608,9 @@ typedef struct _MPT_ADAPTER
 	u32			 sense_buf_low_dma;
 	int			 mtrr_reg;
 	struct pci_dev		*pcidev;	/* struct pci_dev pointer */
+#if defined(MPTBASE_MEM_ALLOC_FIFO_FIX)
+	struct pci_dev		pcidev32;	/* struct pci_dev pointer */
+#endif	
 	u8			*memmap;	/* mmap address */
 	struct Scsi_Host	*sh;		/* Scsi Host pointer */
 	ScsiCfgData		spi_data;	/* Scsi config. data */
@@ -622,6 +623,12 @@ typedef struct _MPT_ADAPTER
 	int			 eventTypes;	/* Event logging parameters */
 	int			 eventContext;	/* Next event context */
 	int			 eventLogSize;	/* Max number of cached events */
+#ifdef MPTSCSIH_DBG_TIMEOUT
+	int			timeout_hard;
+	int			timeout_delta;
+	int			timeout_cnt;
+	int			timeout_maxcnt;
+#endif
 	struct _mpt_ioctl_events *events;	/* pointer to event log */
 	fw_image_t		**cached_fw;	/* Pointer to FW SG List */
 	Q_TRACKER		 configQ;	/* linked list of config. requests */
@@ -665,6 +672,7 @@ typedef int (*MPT_RESETHANDLER)(MPT_ADAP
 /* reset_phase defs */
 #define MPT_IOC_PRE_RESET		0
 #define MPT_IOC_POST_RESET		1
+#define MPT_IOC_SETUP_RESET		2
 
 /*
  * Invent MPT host event (super-set of MPI Events)
@@ -880,14 +888,12 @@ typedef struct _MPT_LOCAL_REPLY {
 #define MPT_NVRAM_WIDE_DISABLE		(0x00100000)
 #define MPT_NVRAM_BOOT_CHOICE		(0x00200000)
 
-#ifdef MPT_SCSI_USE_NEW_EH
 /* The TM_STATE variable is used to provide strict single threading of TM
  * requests as well as communicate TM error conditions.
  */
 #define TM_STATE_NONE          (0)
 #define	TM_STATE_IN_PROGRESS   (1)
 #define	TM_STATE_ERROR	       (2)
-#endif
 
 typedef struct _MPT_SCSI_HOST {
 	MPT_ADAPTER		 *ioc;
@@ -928,12 +934,8 @@ typedef struct _MPT_SCSI_HOST {
 	u8			  is_spi;		/* Parallel SCSI i/f */
 	u8			  negoNvram;		/* DV disabled, nego NVRAM */
 	u8			  is_multipath;		/* Multi-path compatible */
-#ifdef MPT_SCSI_USE_NEW_EH
 	u8                        tmState;
 	u8			  rsvd[1];
-#else
-	u8			  rsvd[2];
-#endif
 	MPT_FRAME_HDR		 *tmPtr;		/* Ptr to TM request*/
 	MPT_FRAME_HDR		 *cmdPtr;		/* Ptr to nonOS request */
 	struct scsi_cmnd	 *abortSCpnt;
@@ -1033,8 +1035,10 @@ extern u32	 mpt_GetIocState(MPT_ADAPTER 
 extern void	 mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan);
 extern int	 mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
 extern int	 mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg);
+extern int	 mpt_toolbox(MPT_ADAPTER *ioc, CONFIGPARMS *cfg);
 extern void	*mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz);
 extern void	 mpt_free_fw_memory(MPT_ADAPTER *ioc, fw_image_t **alt_img);
+extern int	 mpt_findImVolumes(MPT_ADAPTER *ioc);
 extern int	 mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
 
 /*
--- diff/drivers/message/fusion/mptctl.c	2004-01-19 10:22:57.000000000 +0000
+++ source/drivers/message/fusion/mptctl.c	2004-03-16 09:37:55.994027784 +0000
@@ -29,7 +29,7 @@
  *
  *      (see also mptbase.c)
  *
- *  Copyright (c) 1999-2003 LSI Logic Corporation
+ *  Copyright (c) 1999-2004 LSI Logic Corporation
  *  Originally By: Steven J. Ralston, Noah Romer
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:mpt_linux_developer@lsil.com)
@@ -82,6 +82,7 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/miscdevice.h>
+#include <linux/smp_lock.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -91,7 +92,7 @@
 #include "../../scsi/scsi.h"
 #include "../../scsi/hosts.h"
 
-#define COPYRIGHT	"Copyright (c) 1999-2003 LSI Logic Corporation"
+#define COPYRIGHT	"Copyright (c) 1999-2004 LSI Logic Corporation"
 #define MODULEAUTHOR	"Steven J. Ralston, Noah Romer, Pamela Delaney"
 #include "mptbase.h"
 #include "mptctl.h"
@@ -260,6 +261,7 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME
 			iocStatus = reply->u.reply.IOCStatus & MPI_IOCSTATUS_MASK;
 			if (iocStatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED) {
 				if (ioc->ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE) {
+					ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
 					del_timer (&ioc->ioctl->timer);
 					ioc->ioctl->timer.expires = jiffies + HZ;
 					add_timer(&ioc->ioctl->timer);
@@ -456,7 +458,7 @@ mptctl_set_tm_flags(MPT_SCSI_HOST *hd) {
 	unsigned long flags;
 
 	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
-#ifdef MPT_SCSI_USE_NEW_EH
+
 	if (hd->tmState == TM_STATE_NONE) {
 		hd->tmState = TM_STATE_IN_PROGRESS;
 		hd->tmPending = 1;
@@ -465,15 +467,7 @@ mptctl_set_tm_flags(MPT_SCSI_HOST *hd) {
 		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 		return -EBUSY;
 	}
-#else
-	if (hd->tmPending) {
-		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-		return -EBUSY;
-	} else {
-		hd->tmPending = 1;
-		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-	}
-#endif
+
 	return 0;
 }
 
@@ -488,14 +482,10 @@ mptctl_free_tm_flags(MPT_ADAPTER *ioc)
 		return;
 
 	spin_lock_irqsave(&ioc->FreeQlock, flags);
-#ifdef MPT_SCSI_USE_NEW_EH
+
 	hd->tmState = TM_STATE_ERROR;
 	hd->tmPending = 0;
 	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-#else
-	hd->tmPending = 0;
-	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-#endif
 
 	return;
 }
@@ -513,9 +503,12 @@ mptctl_ioc_reset(MPT_ADAPTER *ioc, int r
 {
 	MPT_IOCTL *ioctl = ioc->ioctl;
 	dctlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to IOCTL driver!\n",
-			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
+			reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
 
-	if (reset_phase == MPT_IOC_PRE_RESET){
+	if (reset_phase == MPT_IOC_SETUP_RESET){
+		;
+	} else if (reset_phase == MPT_IOC_PRE_RESET){
 
 		/* Someone has called the reset handler to
 		 * do a hard reset. No more replies from the FW.
@@ -532,13 +525,15 @@ mptctl_ioc_reset(MPT_ADAPTER *ioc, int r
 		}
 
 	} else {
+		ioctl->tmPtr = NULL;
+
 		/* Set the status and continue IOCTL
 		 * processing. All memory will be free'd
 		 * by originating thread after wake_up is
 		 * called.
 		 */
 		if (ioctl && (ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE)){
-			ioctl->status = MPT_IOCTL_STATUS_DID_IOCRESET;
+			ioctl->status |= MPT_IOCTL_STATUS_DID_IOCRESET;
 
 			/* Wake up the calling process
 			 */
@@ -620,7 +615,11 @@ mptctl_ioctl(struct inode *inode, struct
 		return -ENODEV;
 	}
 
-
+	if (!iocp->active) {
+		printk(KERN_ERR "%s::mptctl_ioctl() @%d - Controller disabled.\n",
+				__FILE__, __LINE__);
+		return -EFAULT;
+	}
 
 	/* Handle those commands that are just returning
 	 * information stored in the driver.
@@ -691,7 +690,7 @@ static int mptctl_do_reset(unsigned long
 		return -ENODEV; /* (-6) No such device or address */
 	}
 
-	if (mpt_HardResetHandler(iocp, NO_SLEEP) != 0) {
+	if (mpt_HardResetHandler(iocp, CAN_SLEEP) != 0) {
 		printk (KERN_ERR "%s@%d::mptctl_do_reset - reset failed.\n",
 			__FILE__, __LINE__);
 		return -1;
@@ -1254,10 +1253,10 @@ mptctl_getiocinfo (unsigned long arg, un
 	/* Fill in the data and return the structure to the calling
 	 * program
 	 */
-	if (ioc->chip_type == C1030)
-		karg.adapterType = MPT_IOCTL_INTERFACE_SCSI;
-	else
+	if ((int)ioc->chip_type <= (int) FC929)
 		karg.adapterType = MPT_IOCTL_INTERFACE_FC;
+	else
+		karg.adapterType = MPT_IOCTL_INTERFACE_SCSI;
 
 	port = karg.hdr.port;
 
@@ -1307,7 +1306,8 @@ mptctl_getiocinfo (unsigned long arg, un
 
 	/* Set the Version Strings.
 	 */
-	strlcpy (karg.driverVersion, MPT_LINUX_PACKAGE_NAME, MPT_IOCTL_VERSION_LENGTH);
+	strncpy (karg.driverVersion, MPT_LINUX_PACKAGE_NAME, MPT_IOCTL_VERSION_LENGTH);
+	karg.driverVersion[MPT_IOCTL_VERSION_LENGTH-1]='\0';
 
 	karg.busChangeEvent = 0;
 	karg.hostId = ioc->pfacts[port].PortSCSIID;
@@ -1343,15 +1343,18 @@ mptctl_gettargetinfo (unsigned long arg)
 	MPT_ADAPTER		*ioc;
 	struct Scsi_Host	*sh;
 	MPT_SCSI_HOST		*hd;
+	VirtDevice		*vdev;
 	char			*pmem;
 	int			*pdata;
+	IOCPage2_t		*pIoc2;
 	int			iocnum;
 	int			numDevices = 0;
 	unsigned int		max_id;
-	int			ii, jj, lun;
+	int			id, jj, indexed_lun, lun_index;
+	u32			lun;
 	int			maxWordsLeft;
 	int			numBytes;
-	u8			port;
+	u8			port, devType, bus_id;
 
 	dctlprintk(("mptctl_gettargetinfo called.\n"));
 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) {
@@ -1418,27 +1421,59 @@ mptctl_gettargetinfo (unsigned long arg)
 		 * sh->max_id = maximum target ID + 1
 		 */
 		if (hd && hd->Targets) {
-			ii = 0;
-			while (ii <= max_id) {
-				if (hd->Targets[ii]) {
-					for (jj = 0; jj <= MPT_LAST_LUN; jj++) {
-						lun = (1 << jj);
-						if (hd->Targets[ii]->luns & lun) {
-							numDevices++;
-							*pdata = (jj << 16) | ii;
-							--maxWordsLeft;
-
-							pdata++;
-
-							if (maxWordsLeft <= 0)
-								break;
+			mpt_findImVolumes(ioc);
+			pIoc2 = ioc->spi_data.pIocPg2;
+			for ( id = 0; id <= max_id; id++ ) {
+				if ( pIoc2 && pIoc2->NumActiveVolumes &&
+					( id == pIoc2->RaidVolume[0].VolumeID ) ) {
+					if (maxWordsLeft <= 0) {
+						printk(KERN_ERR "mptctl_gettargetinfo - "
+			"buffer is full but volume is available on ioc %d\n, numDevices=%d", iocnum, numDevices);
+						goto data_space_full;
+					}
+                    			if ( ( pIoc2->RaidVolume[0].Flags & MPI_IOCPAGE2_FLAG_VOLUME_INACTIVE ) == 0 )
+                        			devType = 0x80;
+                    			else
+                        			devType = 0xC0;
+					bus_id = pIoc2->RaidVolume[0].VolumeBus;
+	            			numDevices++;
+                    			*pdata = ( (devType << 24) | (bus_id << 8) | id );
+					dctlprintk((KERN_ERR "mptctl_gettargetinfo - "
+		"volume ioc=%d target=%x numDevices=%d pdata=%p\n", iocnum, *pdata, numDevices, pdata));
+                    			pdata++;
+					--maxWordsLeft;
+            			} else {
+					vdev = hd->Targets[id];
+					if (vdev) {
+						for (jj = 0; jj <= MPT_LAST_LUN; jj++) {
+							lun_index = (jj >> 5);
+							indexed_lun = (jj % 32);
+							lun = (1 << indexed_lun);
+							if (vdev->luns[lun_index] & lun) {
+								if (maxWordsLeft <= 0) {
+									printk(KERN_ERR
+									"mptctl_gettargetinfo - "
+									"buffer is full but more targets are available on ioc %d numDevices=%d\n",
+									iocnum, numDevices);
+									goto data_space_full;
+								}
+								bus_id = vdev->bus_id;
+								numDevices++;
+                            					*pdata = ( (jj << 16) | (bus_id << 8) | id );
+								dctlprintk((KERN_ERR
+								 "mptctl_gettargetinfo - "
+								 "target ioc=%d target=%x numDevices=%d pdata=%p\n",
+								 iocnum, *pdata, numDevices, pdata));
+								pdata++;
+								--maxWordsLeft;
+							}
 						}
 					}
 				}
-				ii++;
 			}
 		}
 	}
+data_space_full:
 	karg.numDevices = numDevices;
 
 	/* Copy part of the data from kernel memory to user memory
@@ -1507,8 +1542,10 @@ mptctl_readtest (unsigned long arg)
 #else
 	karg.chip_type = ioc->chip_type;
 #endif
-	strlcpy (karg.name, ioc->name, MPT_MAX_NAME);
-	strlcpy (karg.product, ioc->prod_name, MPT_PRODUCT_LENGTH);
+	strncpy (karg.name, ioc->name, MPT_MAX_NAME);
+	karg.name[MPT_MAX_NAME-1]='\0';
+	strncpy (karg.product, ioc->prod_name, MPT_PRODUCT_LENGTH);
+	karg.product[MPT_PRODUCT_LENGTH-1]='\0';
 
 	/* Copy the data from kernel memory to user memory
 	 */
@@ -1806,22 +1843,20 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 	MPT_FRAME_HDR	*mf = NULL;
 	MPIHeader_t	*hdr;
 	char		*psge;
-	MptSge_t	*this_sge = NULL;
-	MptSge_t	*sglbuf = NULL;
 	struct buflist	bufIn;	/* data In buffer */
 	struct buflist	bufOut; /* data Out buffer */
-	dma_addr_t	sglbuf_dma;
-	dma_addr_t	dma_addr;
+	dma_addr_t	dma_addr_in;
+	dma_addr_t	dma_addr_out;
 	int		dir;	/* PCI data direction */
 	int		sgSize = 0;	/* Num SG elements */
-	int		this_alloc;
-	int		 iocnum, flagsLength;
-	int		 sz, rc = 0;
-	int		 msgContext;
+	int		iocnum, flagsLength;
+	int		sz, rc = 0;
+	int		msgContext;
 	int		tm_flags_set = 0;
 	u16		req_idx;
 
 	dctlprintk(("mptctl_do_mpt_command called.\n"));
+	bufIn.kptr = bufOut.kptr = NULL;
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
@@ -1848,7 +1883,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 	if (karg.dataOutSize > 0)
 		sz += sizeof(dma_addr_t) + sizeof(u32);
 
-	if ( sz > ioc->req_sz) {
+	if (sz > ioc->req_sz) {
 		printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
 			"Request frame too large (%d) maximum (%d)\n",
 				__FILE__, __LINE__, sz, ioc->req_sz);
@@ -1891,6 +1926,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 	switch (hdr->Function) {
 	case MPI_FUNCTION_IOC_FACTS:
 	case MPI_FUNCTION_PORT_FACTS:
+		karg.dataOutSize  = karg.dataInSize = 0;
+		break;
+
 	case MPI_FUNCTION_CONFIG:
 	case MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND:
 	case MPI_FUNCTION_FC_EX_LINK_SRVC_SEND:
@@ -1928,12 +1966,14 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 			 */
 			if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE)
 				pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+			else
+				pScsiReq->SenseBufferLength = karg.maxSenseBytes;
 
 			pScsiReq->SenseBufferLowAddr =
 				cpu_to_le32(ioc->sense_buf_low_dma
 				   + (req_idx * MPT_SENSE_BUFFER_ALLOC));
 
-			if ( (hd = (MPT_SCSI_HOST *) ioc->sh->hostdata)) {
+			if ((hd = (MPT_SCSI_HOST *) ioc->sh->hostdata)) {
 				if (hd->Targets)
 					pTarget = hd->Targets[target];
 			}
@@ -1944,11 +1984,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 			/* Have the IOCTL driver set the direction based
 			 * on the dataOutSize (ordering issue with Sparc).
 			 */
-			if (karg.dataOutSize > 0 ) {
+			if (karg.dataOutSize > 0) {
 				scsidir = MPI_SCSIIO_CONTROL_WRITE;
 				dataSize = karg.dataOutSize;
-			}
-			else {
+			} else {
 				scsidir = MPI_SCSIIO_CONTROL_READ;
 				dataSize = karg.dataInSize;
 			}
@@ -1990,6 +2029,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 			 */
 			if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE)
 				pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+			else
+				pScsiReq->SenseBufferLength = karg.maxSenseBytes;
 
 			pScsiReq->SenseBufferLowAddr =
 				cpu_to_le32(ioc->sense_buf_low_dma
@@ -2001,11 +2042,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 			/* Have the IOCTL driver set the direction based
 			 * on the dataOutSize (ordering issue with Sparc).
 			 */
-			if (karg.dataOutSize > 0 ) {
+			if (karg.dataOutSize > 0) {
 				scsidir = MPI_SCSIIO_CONTROL_WRITE;
 				dataSize = karg.dataOutSize;
-			}
-			else {
+			} else {
 				scsidir = MPI_SCSIIO_CONTROL_READ;
 				dataSize = karg.dataInSize;
 			}
@@ -2033,7 +2073,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 					__FILE__, __LINE__);
 				rc = -EFAULT;
 				goto done_free_mem;
-			}  else if (mptctl_set_tm_flags(hd) != 0) {
+			} else if (mptctl_set_tm_flags(hd) != 0) {
 				rc = -EPERM;
 				goto done_free_mem;
 			}
@@ -2107,7 +2147,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 	 * preceede the data in (read) SGE. psgList is used to free the
 	 * allocated memory.
 	 */
-	psge = (char *) ( ((int *) mf) + karg.dataSgeOffset);
+	psge = (char *) (((int *) mf) + karg.dataSgeOffset);
 	flagsLength = 0;
 
 	/* bufIn and bufOut are used for user to kernel space transfers
@@ -2115,30 +2155,18 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 	bufIn.kptr = bufOut.kptr = NULL;
 	bufIn.len = bufOut.len = 0;
 
-	if (karg.dataOutSize > 0 )
+	if (karg.dataOutSize > 0)
 		sgSize ++;
 
-	if (karg.dataInSize > 0 )
+	if (karg.dataInSize > 0)
 		sgSize ++;
 
 	if (sgSize > 0) {
 
-		/* Allocate memory for the SGL.
-		 * Used to free kernel memory once
-		 * the MF is freed.
-		 */
-		sglbuf = pci_alloc_consistent (ioc->pcidev,
-			sgSize*sizeof(MptSge_t), &sglbuf_dma);
-		if (sglbuf == NULL) {
-			rc = -ENOMEM;
-			goto done_free_mem;
-		}
-		this_sge = sglbuf;
-
 		/* Set up the dataOut memory allocation */
 		if (karg.dataOutSize > 0) {
 			dir = PCI_DMA_TODEVICE;
-			if (karg.dataInSize > 0 ) {
+			if (karg.dataInSize > 0) {
 				flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
 						MPI_SGE_FLAGS_DIRECTION |
 						mpt_addr_size() )
@@ -2147,22 +2175,25 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 				flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
 			}
 			flagsLength |= karg.dataOutSize;
-
-			this_alloc = karg.dataOutSize;
-			bufOut.len = this_alloc;
+			bufOut.len = karg.dataOutSize;
 			bufOut.kptr = pci_alloc_consistent(
-					ioc->pcidev, this_alloc, &dma_addr);
+					ioc->pcidev, bufOut.len, &dma_addr_out);
 
 			if (bufOut.kptr == NULL) {
 				rc = -ENOMEM;
 				goto done_free_mem;
 			} else {
+				/* Set up this SGE.
+				 * Copy to MF and to sglbuf
+				 */
+				mpt_add_sge(psge, flagsLength, dma_addr_out);
+				psge += (sizeof(u32) + sizeof(dma_addr_t));
+
 				/* Copy user data to kernel space.
 				 */
 				if (copy_from_user(bufOut.kptr,
 						karg.dataOutBufPtr,
 						bufOut.len)) {
-
 					printk(KERN_ERR
 						"%s@%d::mptctl_do_mpt_command - Unable "
 						"to read user data "
@@ -2171,16 +2202,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 					rc =  -EFAULT;
 					goto done_free_mem;
 				}
-
-				/* Set up this SGE.
-				 * Copy to MF and to sglbuf
-				 */
-				mpt_add_sge(psge, flagsLength, dma_addr);
-				psge += (sizeof(u32) + sizeof(dma_addr_t));
-
-				this_sge->FlagsLength = flagsLength;
-				this_sge->Address = dma_addr;
-				this_sge++;
 			}
 		}
 
@@ -2189,10 +2210,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 			flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
 			flagsLength |= karg.dataInSize;
 
-			this_alloc = karg.dataInSize;
-			bufIn.len = this_alloc;
+			bufIn.len = karg.dataInSize;
 			bufIn.kptr = pci_alloc_consistent(ioc->pcidev,
-							this_alloc, &dma_addr);
+					bufIn.len, &dma_addr_in);
+
 			if (bufIn.kptr == NULL) {
 				rc = -ENOMEM;
 				goto done_free_mem;
@@ -2200,11 +2221,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 				/* Set up this SGE
 				 * Copy to MF and to sglbuf
 				 */
-				mpt_add_sge(psge, flagsLength, dma_addr);
-
-				this_sge->FlagsLength = flagsLength;
-				this_sge->Address = dma_addr;
-				this_sge++;
+				mpt_add_sge(psge, flagsLength, dma_addr_in);
 			}
 		}
 	} else  {
@@ -2228,7 +2245,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 
 	if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
 		rc = mpt_send_handshake_request(mptctl_id, ioc->id,
-				sizeof(SCSITaskMgmt_t), (u32*)mf, NO_SLEEP);
+				sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP);
 		if (rc == 0) {
 			wait_event(mptctl_wait, ioc->ioctl->wait_done);
 		} else {
@@ -2236,45 +2253,41 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 			tm_flags_set= 0;
 			del_timer(&ioc->ioctl->timer);
 			ioc->ioctl->status &= ~MPT_IOCTL_STATUS_TIMER_ACTIVE;
-			ioc->ioctl->status = MPT_IOCTL_STATUS_TM_FAILED;
+			ioc->ioctl->status |= MPT_IOCTL_STATUS_TM_FAILED;
+			mpt_free_msg_frame(mptctl_id, ioc->id, mf);
 		}
 	} else {
 		mpt_put_msg_frame(mptctl_id, ioc->id, mf);
 		wait_event(mptctl_wait, ioc->ioctl->wait_done);
 	}
 
-	/* The command is complete.  * Return data to the user.
+	mf = NULL;
+
+	/* MF Cleanup:
+	 * If command failed and failure triggered a diagnostic reset
+	 * OR a diagnostic reset happens during command processing,
+	 * no data, messaging queues are reset (mf cannot be accessed),
+	 * and status is DID_IOCRESET
 	 *
-	 * If command completed,  mf has been freed so cannot
-	 * use this memory.
+	 * If a user-requested bus reset fails to be handshaked, then
+	 * mf is returned to free queue and status is TM_FAILED.
 	 *
-	 * If timeout, a recovery  mechanism has been called.
-	 * Need to free the mf.
+	 * Otherise, the command completed and the mf was freed
+	 # by ISR (mf cannot be touched).
 	 */
 	if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) {
-
-		/* A timeout - there is no data to return to the
-		 * the user other than an error.
-		 * The timer callback deleted the
+		/* The timer callback deleted the
 		 * timer and reset the adapter queues.
 		 */
 		printk(KERN_WARNING "%s@%d::mptctl_do_mpt_command - "
 			"Timeout Occurred on IOCTL! Reset IOC.\n", __FILE__, __LINE__);
 		tm_flags_set= 0;
 		rc = -ETIME;
-
-		/* Free memory and return to the calling function
-		 */
-		goto done_free_mem;
 	} else if (ioc->ioctl->status & MPT_IOCTL_STATUS_TM_FAILED) {
-		/* User TM request failed!
+		/* User TM request failed! mf has not been freed.
 		 */
 		rc = -ENODATA;
 	} else {
-		/* Callback freed request frame.
-		 */
-		mf = NULL;
-
 		/* If a valid reply frame, copy to the user.
 		 * Offset 2: reply length in U32's
 		 */
@@ -2332,42 +2345,31 @@ mptctl_do_mpt_command (struct mpt_ioctl_
 	}
 
 done_free_mem:
-	/* Clear status bits.
-	 */
-	ioc->ioctl->status = 0;
+	/* Clear all status bits except TMTIMER_ACTIVE, this bit is cleared
+	 * upon completion of the TM command.
+	 * ioc->ioctl->status = 0;
+	 */
+	ioc->ioctl->status &= ~(MPT_IOCTL_STATUS_TIMER_ACTIVE | MPT_IOCTL_STATUS_TM_FAILED |
+			MPT_IOCTL_STATUS_COMMAND_GOOD | MPT_IOCTL_STATUS_SENSE_VALID |
+			MPT_IOCTL_STATUS_RF_VALID | MPT_IOCTL_STATUS_DID_IOCRESET);
 
 	if (tm_flags_set)
 		mptctl_free_tm_flags(ioc);
 
-	if (sglbuf) {
-		this_sge = sglbuf;
-
-		/* Free the allocated memory.
-		 */
-		 if (bufOut.kptr != NULL ) {
-			dma_addr = this_sge->Address;
-			this_sge++;	/* go to next structure */
-			this_alloc = bufOut.len;
-			pci_free_consistent(ioc->pcidev,
-				this_alloc, (void *) bufOut.kptr, dma_addr);
-		}
-
-		if (bufIn.kptr != NULL ) {
-			dma_addr = this_sge->Address;
-			this_alloc = bufIn.len;
-
-			pci_free_consistent(ioc->pcidev,
-					this_alloc, (void *) bufIn.kptr, dma_addr);
-		}
-
-		this_alloc = sgSize * sizeof(MptSge_t);
+	/* Free the allocated memory.
+	 */
+	 if (bufOut.kptr != NULL) {
 		pci_free_consistent(ioc->pcidev,
-				this_alloc, (void *) sglbuf, sglbuf_dma);
+			bufOut.len, (void *) bufOut.kptr, dma_addr_out);
+	}
 
+	if (bufIn.kptr != NULL) {
+		pci_free_consistent(ioc->pcidev,
+			bufIn.len, (void *) bufIn.kptr, dma_addr_in);
 	}
 
-	/* mf will be null if allocation failed OR
-	 * if command completed OK (callback freed)
+	/* mf is null if command issued successfully
+	 * otherwise, failure occured after mf acquired.
 	 */
 	if (mf)
 		mpt_free_msg_frame(mptctl_id, ioc->id, mf);
@@ -2405,7 +2407,7 @@ mptctl_hp_hostinfo(unsigned long arg, un
 	 */
 	if (data_size == sizeof(hp_host_info_t))
 		cim_rev = 1;
-	else if (data_size == (sizeof(hp_host_info_t) + 12))
+	else if (data_size == sizeof(hp_host_info_rev0_t))
 		cim_rev = 0;	/* obsolete */
 	else
 		return -EFAULT;
@@ -2478,7 +2480,7 @@ mptctl_hp_hostinfo(unsigned long arg, un
 	cfg.dir = 0;	/* read */
 	cfg.timeout = 10;
 
-	strlcpy(karg.serial_number, " ", sizeof(karg.serial_number));
+	strncpy(karg.serial_number, " ", 24);
 	if (mpt_config(ioc, &cfg) == 0) {
 		if (cfg.hdr->PageLength > 0) {
 			/* Issue the second config page request */
@@ -2489,9 +2491,10 @@ mptctl_hp_hostinfo(unsigned long arg, un
 				cfg.physAddr = buf_dma;
 				if (mpt_config(ioc, &cfg) == 0) {
 					ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf;
-					if (strlen(pdata->BoardTracerNumber) > 1)
-						strlcpy(karg.serial_number, pdata->BoardTracerNumber,
-							sizeof(karg.serial_number));
+					if (strlen(pdata->BoardTracerNumber) > 1) {
+						strncpy(karg.serial_number, 									    pdata->BoardTracerNumber, 24);
+						karg.serial_number[24-1]='\0';
+					}
 				}
 				pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
 				pbuf = NULL;
@@ -2535,6 +2538,20 @@ mptctl_hp_hostinfo(unsigned long arg, un
 		}
 	}
 
+	cfg.pageAddr = 0;
+	cfg.action = MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL;
+	cfg.dir = MPI_TB_ISTWI_FLAGS_READ;
+	cfg.timeout = 10;
+	pbuf = pci_alloc_consistent(ioc->pcidev, 4, &buf_dma);
+	if (pbuf) {
+		cfg.physAddr = buf_dma;
+		if ((mpt_toolbox(ioc, &cfg)) == 0) {
+			karg.rsvd = *(u32 *)pbuf;
+		}
+		pci_free_consistent(ioc->pcidev, 4, pbuf, buf_dma);
+		pbuf = NULL;
+	}
+
 	/* Copy the data from kernel memory to user memory
 	 */
 	if (copy_to_user((char *)arg, &karg,
@@ -2736,6 +2753,19 @@ static struct miscdevice mptctl_miscdev 
  * to ensure the structure contents is properly processed by mptctl.
  */
 static int
+compat_mptctl_ioctl(unsigned int fd, unsigned int cmd,
+			unsigned long arg, struct file *filp)
+{
+	int ret;
+
+	lock_kernel();
+	dctlprintk((KERN_INFO MYNAM "::compat_mptctl_ioctl() called\n"));
+	ret = mptctl_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+	unlock_kernel();
+	return ret;
+}
+ 
+static int
 compat_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd,
 			unsigned long arg, struct file *filp)
 {
@@ -2875,30 +2905,30 @@ int __init mptctl_init(void)
 	}
 
 #ifdef CONFIG_COMPAT
-	err = register_ioctl32_conversion(MPTIOCINFO, NULL);
+	err = register_ioctl32_conversion(MPTIOCINFO, compat_mptctl_ioctl);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTIOCINFO1, NULL);
+	err = register_ioctl32_conversion(MPTIOCINFO1, compat_mptctl_ioctl);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTTARGETINFO, NULL);
+	err = register_ioctl32_conversion(MPTTARGETINFO, compat_mptctl_ioctl);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTTEST, NULL);
+	err = register_ioctl32_conversion(MPTTEST, compat_mptctl_ioctl);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTEVENTQUERY, NULL);
+	err = register_ioctl32_conversion(MPTEVENTQUERY, compat_mptctl_ioctl);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTEVENTENABLE, NULL);
+	err = register_ioctl32_conversion(MPTEVENTENABLE, compat_mptctl_ioctl);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTEVENTREPORT, NULL);
+	err = register_ioctl32_conversion(MPTEVENTREPORT, compat_mptctl_ioctl);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTHARDRESET, NULL);
+	err = register_ioctl32_conversion(MPTHARDRESET, compat_mptctl_ioctl);
 	if (++where && err) goto out_fail;
 	err = register_ioctl32_conversion(MPTCOMMAND32, compat_mpt_command);
 	if (++where && err) goto out_fail;
 	err = register_ioctl32_conversion(MPTFWDOWNLOAD32,
 					  compat_mptfwxfer_ioctl);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(HP_GETHOSTINFO, NULL);
+	err = register_ioctl32_conversion(HP_GETHOSTINFO, compat_mptctl_ioctl);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(HP_GETTARGETINFO, NULL);
+	err = register_ioctl32_conversion(HP_GETTARGETINFO, compat_mptctl_ioctl);
 	if (++where && err) goto out_fail;
 #endif
 
--- diff/drivers/message/fusion/mptctl.h	2004-01-19 10:22:57.000000000 +0000
+++ source/drivers/message/fusion/mptctl.h	2004-03-16 09:37:55.995027632 +0000
@@ -15,7 +15,7 @@
  *
  *      (see also mptbase.c)
  *
- *  Copyright (c) 1999-2003 LSI Logic Corporation
+ *  Copyright (c) 1999-2004 LSI Logic Corporation
  *  Originally By: Steven J. Ralston
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:mpt_linux_developer@lsil.com)
@@ -342,6 +342,7 @@ struct mpt_ioctl_command32 {
 #define CPQFCTS_IOC_MAGIC 'Z'
 #define HP_IOC_MAGIC 'Z'
 #define HP_GETHOSTINFO		_IOR(HP_IOC_MAGIC, 20, hp_host_info_t)
+#define HP_GETHOSTINFO1		_IOR(HP_IOC_MAGIC, 20, hp_host_info_rev0_t)
 #define HP_GETTARGETINFO	_IOR(HP_IOC_MAGIC, 21, hp_target_info_t)
 
 /* All HP IOCTLs must include this header
@@ -357,7 +358,7 @@ typedef struct _hp_header {
 /*
  *  Header:
  *  iocnum 	required (input)
- *  host 	ignored	
+ *  host 	ignored
  *  channe	ignored
  *  id		ignored
  *  lun		ignored
@@ -371,9 +372,9 @@ typedef struct _hp_host_info {
 	u8		 devfn;
 	u8		 bus;
 	ushort		 host_no;		/* SCSI Host number, if scsi driver not loaded*/
-	u8		 fw_version[16];	/* string */	
+	u8		 fw_version[16];	/* string */
 	u8		 serial_number[24];	/* string */
-	u32		 ioc_status;	
+	u32		 ioc_status;
 	u32		 bus_phys_width;
 	u32		 base_io_addr;
 	u32		 rsvd;
@@ -382,10 +383,33 @@ typedef struct _hp_host_info {
 	unsigned int	 timeouts;		/* num timeouts */
 } hp_host_info_t;
 
+/* replace ulongs with uints, need to preserve backwards
+ * compatibility.
+ */
+typedef struct _hp_host_info_rev0 {
+	hp_header_t	 hdr;
+	u16		 vendor;
+	u16		 device;
+	u16		 subsystem_vendor;
+	u16		 subsystem_id;
+	u8		 devfn;
+	u8		 bus;
+	ushort		 host_no;		/* SCSI Host number, if scsi driver not loaded*/
+	u8		 fw_version[16];	/* string */
+	u8		 serial_number[24];	/* string */
+	u32		 ioc_status;
+	u32		 bus_phys_width;
+	u32		 base_io_addr;
+	u32		 rsvd;
+	unsigned long	 hard_resets;		/* driver initiated resets */
+	unsigned long	 soft_resets;		/* ioc, external resets */
+	unsigned long	 timeouts;		/* num timeouts */
+} hp_host_info_rev0_t;
+
 /*
  *  Header:
  *  iocnum 	required (input)
- *  host 	required	
+ *  host 	required
  *  channel	required	(bus number)
  *  id		required
  *  lun		ignored
--- diff/drivers/message/fusion/mptlan.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/message/fusion/mptlan.c	2004-03-16 09:37:55.997027328 +0000
@@ -23,7 +23,7 @@
  *
  *      (see also mptbase.c)
  *
- *  Copyright (c) 2000-2003 LSI Logic Corporation
+ *  Copyright (c) 2000-2004 LSI Logic Corporation
  *  Originally By: Noah Romer
  *  (mailto:mpt_linux_developer@lsil.com)
  *
@@ -337,15 +337,18 @@ static int
 mpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
 	struct net_device *dev = mpt_landev[ioc->id];
-	struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+	struct mpt_lan_priv *priv = netdev_priv(dev);
 
 	dlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to LAN driver!\n",
-			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
+			reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
 
 	if (priv->mpt_rxfidx == NULL)
 		return (1);
 
-	if (reset_phase == MPT_IOC_PRE_RESET) {
+	if (reset_phase == MPT_IOC_SETUP_RESET) {
+		;
+	} else if (reset_phase == MPT_IOC_PRE_RESET) {
 		int i;
 		unsigned long flags;
 
@@ -406,7 +409,7 @@ mpt_lan_event_process(MPT_ADAPTER *ioc, 
 static int
 mpt_lan_open(struct net_device *dev)
 {
-	struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+	struct mpt_lan_priv *priv = netdev_priv(dev);
 	int i;
 
 	if (mpt_lan_reset(dev) != 0) {
@@ -497,7 +500,7 @@ mpt_lan_reset(struct net_device *dev)
 {
 	MPT_FRAME_HDR *mf;
 	LANResetRequest_t *pResetReq;
-	struct mpt_lan_priv *priv = (struct mpt_lan_priv *)dev->priv;
+	struct mpt_lan_priv *priv = netdev_priv(dev);
 
 	mf = mpt_get_msg_frame(LanCtx, priv->mpt_dev->id);
 
@@ -526,7 +529,7 @@ mpt_lan_reset(struct net_device *dev)
 static int
 mpt_lan_close(struct net_device *dev)
 {
-	struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+	struct mpt_lan_priv *priv = netdev_priv(dev);
 	MPT_ADAPTER *mpt_dev = priv->mpt_dev;
 	unsigned int timeout;
 	int i;
@@ -587,7 +590,7 @@ mpt_lan_close(struct net_device *dev)
 static struct net_device_stats *
 mpt_lan_get_stats(struct net_device *dev)
 {
-	struct mpt_lan_priv *priv = (struct mpt_lan_priv *)dev->priv;
+	struct mpt_lan_priv *priv = netdev_priv(dev);
 
 	return (struct net_device_stats *) &priv->stats;
 }
@@ -607,7 +610,7 @@ mpt_lan_change_mtu(struct net_device *de
 static void
 mpt_lan_tx_timeout(struct net_device *dev)
 {
-	struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+	struct mpt_lan_priv *priv = netdev_priv(dev);
 	MPT_ADAPTER *mpt_dev = priv->mpt_dev;
 
 	if (mpt_dev->active) {
@@ -621,7 +624,7 @@ mpt_lan_tx_timeout(struct net_device *de
 static int
 mpt_lan_send_turbo(struct net_device *dev, u32 tmsg)
 {
-	struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+	struct mpt_lan_priv *priv = netdev_priv(dev);
 	MPT_ADAPTER *mpt_dev = priv->mpt_dev;
 	struct sk_buff *sent;
 	unsigned long flags;
@@ -654,7 +657,7 @@ mpt_lan_send_turbo(struct net_device *de
 static int
 mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep)
 {
-	struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+	struct mpt_lan_priv *priv = netdev_priv(dev);
 	MPT_ADAPTER *mpt_dev = priv->mpt_dev;
 	struct sk_buff *sent;
 	unsigned long flags;
@@ -727,7 +730,7 @@ out:
 static int
 mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
 {
-	struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+	struct mpt_lan_priv *priv = netdev_priv(dev);
 	MPT_ADAPTER *mpt_dev = priv->mpt_dev;
 	MPT_FRAME_HDR *mf;
 	LANSendRequest_t *pSendReq;
@@ -955,11 +958,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 +1118,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 +1146,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);
@@ -1369,7 +1386,7 @@ mpt_register_lan_device (MPT_ADAPTER *mp
 
 	dev->mtu = MPT_LAN_MTU;
 
-	priv = (struct mpt_lan_priv *) dev->priv;
+	priv = netdev_priv(dev);
 
 	priv->mpt_dev = mpt_dev;
 	priv->pnum = pnum;
--- diff/drivers/message/fusion/mptscsih.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/message/fusion/mptscsih.c	2004-03-16 09:37:56.016024440 +0000
@@ -21,7 +21,7 @@
  *
  *      (see mptbase.c)
  *
- *  Copyright (c) 1999-2003 LSI Logic Corporation
+ *  Copyright (c) 1999-2004 LSI Logic Corporation
  *  Original author: Steven J. Ralston
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:mpt_linux_developer@lsil.com)
@@ -165,17 +165,19 @@ static u32	SCPNT_TO_LOOKUP_IDX(Scsi_Cmnd
 static MPT_FRAME_HDR *mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx);
 static void	post_pendingQ_commands(MPT_SCSI_HOST *hd);
 
-static int	mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag);
-static int	mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag);
+static int	mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag);
+static int	mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag);
 
 static int	mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
 static int	mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
 
-static void	mptscsih_target_settings(MPT_SCSI_HOST *hd, VirtDevice *target, Scsi_Device *sdev);
+static void	mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen);
+void		mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56);
 static void	mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
 static void	mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags);
 static void	mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id);
 static int	mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target, int flags);
+static int	mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus);
 static int	mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
 static void	mptscsih_timer_expired(unsigned long data);
 static void	mptscsih_taskmgmt_timeout(unsigned long data);
@@ -190,7 +192,7 @@ static int	mptscsih_do_raid(MPT_SCSI_HOS
 static void	mptscsih_domainValidation(void *hd);
 static int	mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id);
 static void	mptscsih_qas_check(MPT_SCSI_HOST *hd, int id);
-static int	mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int target);
+static int	mptscsih_doDv(MPT_SCSI_HOST *hd, int channel, int target);
 static void	mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage);
 static void	mptscsih_fillbuf(char *buffer, int size, int index, int width);
 #endif
@@ -200,8 +202,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);
@@ -214,7 +216,6 @@ static int mptscsih_resume(struct pci_de
  */
 
 static int	mpt_scsi_hosts = 0;
-static atomic_t	queue_depth;
 
 static int	ScsiDoneCtx = -1;
 static int	ScsiTaskCtx = -1;
@@ -243,6 +244,10 @@ static int scandv_wait_done = 1;
 static struct mptscsih_driver_setup
 	driver_setup = MPTSCSIH_DRIVER_SETUP;
 
+#ifdef MPTSCSIH_DBG_TIMEOUT
+static Scsi_Cmnd *foo_to[8];
+#endif
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 /* see mptscsih.h */
@@ -438,10 +443,10 @@ mptscsih_add_chain(char *pAddr, u8 next,
 static inline int
 mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex)
 {
-	MPT_FRAME_HDR *chainBuf = NULL;
+	MPT_FRAME_HDR *chainBuf;
 	unsigned long flags;
-	int rc = FAILED;
-	int chain_idx = MPT_HOST_NO_CHAIN;
+	int rc;
+	int chain_idx;
 
 	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
 	if (!Q_IS_EMPTY(&hd->FreeChainQ)) {
@@ -454,6 +459,10 @@ mptscsih_getFreeChainBuffer(MPT_SCSI_HOS
 		chain_idx = offset / hd->ioc->req_sz;
 		rc = SUCCESS;
 	}
+	else {
+		rc = FAILED;
+		chain_idx = MPT_HOST_NO_CHAIN;
+	}
 	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 
 
@@ -506,13 +515,12 @@ mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_
 	/* Map the data portion, if any.
 	 * sges_left  = 0 if no data transfer.
 	 */
-	sges_left = SCpnt->use_sg;
-	if (SCpnt->use_sg) {
+	if ( (sges_left = SCpnt->use_sg) ) {
 		sges_left = pci_map_sg(hd->ioc->pcidev,
 			       (struct scatterlist *) SCpnt->request_buffer,
 			       SCpnt->use_sg,
 			       scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
-		if (sges_left == 0) 
+		if (sges_left == 0)
 			return FAILED;
 	} else if (SCpnt->request_bufflen) {
 		dma_addr_t	 buf_dma_addr;
@@ -729,50 +737,67 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
 
 	hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
 
-	if ((mf == NULL) ||
-	    (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
-		printk(MYIOC_s_ERR_FMT "%s req frame ptr! (=%p)!\n",
-				ioc->name, mf?"BAD":"NULL", (void *) mf);
-		return 0;
-	}
-
 	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
 	sc = hd->ScsiLookup[req_idx];
 	if (sc == NULL) {
+		MPIHeader_t *hdr = (MPIHeader_t *)mf;
+
 		/* Remark: writeSDP1 will use the ScsiDoneCtx
 		 * If a SCSI I/O cmd, device disabled by OS and
 		 * completion done. Cannot touch sc struct. Just free mem.
 		 */
-		atomic_dec(&queue_depth);
+		if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
+			printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
+			ioc->name);
 
 		mptscsih_freeChainBuffers(hd, req_idx);
 		return 1;
 	}
 
-	dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
-			ioc->name, mf, mr, sc, req_idx));
-
-	atomic_dec(&queue_depth);
+	dmfprintk((MYIOC_s_INFO_FMT
+		"ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
+		ioc->name, mf, mr, sc, req_idx));
 
 	sc->result = DID_OK << 16;		/* Set default reply as OK */
 	pScsiReq = (SCSIIORequest_t *) mf;
 	pScsiReply = (SCSIIOReply_t *) mr;
 
+#ifdef MPTSCSIH_DBG_TIMEOUT
+	if (ioc->timeout_cnt > 0) {
+		int ii, left = 0;
+
+		for (ii=0; ii < 8; ii++) {
+			if (sc == foo_to[ii]) {
+				printk(MYIOC_s_INFO_FMT "complete (%p, %ld)\n",
+					ioc->name, sc, jiffies);
+				foo_to[ii] = NULL;
+			}
+			if (foo_to[ii] != NULL)
+				left++;
+		}
+
+		if (left == 0) {
+			ioc->timeout_maxcnt = 0;
+			ioc->timeout_cnt = 0;
+		}
+	}
+#endif
+
 	if (pScsiReply == NULL) {
 		/* special context reply handling */
 		;
 	} else {
 		u32	 xfer_cnt;
 		u16	 status;
-		u8	 scsi_state;
+		u8	 scsi_state, scsi_status;
 
 		status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
 		scsi_state = pScsiReply->SCSIState;
 
-		dsprintk((KERN_NOTICE "  Uh-Oh! (%d:%d:%d) mf=%p, mr=%p, sc=%p\n",
+		dprintk((KERN_NOTICE "  Uh-Oh! (%d:%d:%d) mf=%p, mr=%p, sc=%p\n",
 				ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1],
 				mf, mr, sc));
-		dsprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh"
+		dprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh"
 				", SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
 				status, scsi_state, pScsiReply->SCSIStatus,
 				le32_to_cpu(pScsiReply->IOCLogInfo)));
@@ -780,14 +805,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
 		if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
 			copy_sense_data(sc, hd, mf, pScsiReply);
 
-		/*
-		 *  Look for + dump FCP ResponseInfo[]!
-		 */
-		if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID) {
-			dprintk((KERN_NOTICE "  FCP_ResponseInfo=%08xh\n",
-					     le32_to_cpu(pScsiReply->ResponseInfo)));
-		}
-
 		switch(status) {
 		case MPI_IOCSTATUS_BUSY:			/* 0x0002 */
 			/* CHECKME!
@@ -827,52 +844,45 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
 		case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:	/* 0x0049 */
 		case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */
 			/*
-			 *  YIKES!  I just discovered that SCSI IO which
-			 *  returns check condition, SenseKey=05 (ILLEGAL REQUEST)
-			 *  and ASC/ASCQ=94/01 (LSI Logic RAID vendor specific),
-			 *  comes down this path!
 			 *  Do upfront check for valid SenseData and give it
 			 *  precedence!
 			 */
-			sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
-			if (scsi_state == 0) {
-				;
-			} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+			scsi_status = pScsiReply->SCSIStatus;
+			sc->result = (DID_OK << 16) | scsi_status;
+			xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
+			if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
 				/* Have already saved the status and sense data
 				 */
 				;
-			} else if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
-				/* What to do?
-				 */
-				sc->result = DID_SOFT_ERROR << 16;
-			}
-			else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
-				/*  Not real sure here either...  */
-				sc->result = DID_RESET << 16;
+			} else {
+				if ( (xfer_cnt == 0) || (sc->underflow > xfer_cnt)) {
+					sc->result = DID_SOFT_ERROR << 16;
+				}
+				if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
+					/* What to do?
+				 	*/
+					sc->result = DID_SOFT_ERROR << 16;
+				}
+				else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
+					/*  Not real sure here either...  */
+					sc->result = DID_RESET << 16;
+				}
 			}
 
 			/* Give report and update residual count.
 			 */
-			xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
 			dprintk((KERN_NOTICE "  sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
 					sc->underflow));
 			dprintk((KERN_NOTICE "  ActBytesXferd=%02xh\n", xfer_cnt));
 
 			sc->resid = sc->request_bufflen - xfer_cnt;
 			dprintk((KERN_NOTICE "  SET sc->resid=%02xh\n", sc->resid));
-
-			if(sc->underflow > xfer_cnt) {
-				printk(MYIOC_s_INFO_FMT
-				"SCSI data underrun: underflow=%02x, xfercnt=%02x\n",
-				ioc->name, sc->underflow, xfer_cnt);
-				sc->result = DID_SOFT_ERROR << 16;
-			}
-
+			
 			/* Report Queue Full
 			 */
-			if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
+			if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
 				mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
-
+			
 			break;
 
 		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
@@ -965,9 +975,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
 
 	hd->ScsiLookup[req_idx] = NULL;
 
-	MPT_HOST_LOCK(flags);
 	sc->scsi_done(sc);		/* Issue the command callback */
-	MPT_HOST_UNLOCK(flags);
 
 	/* Free Chain buffers */
 	mptscsih_freeChainBuffers(hd, req_idx);
@@ -988,7 +996,7 @@ flush_doneQ(MPT_SCSI_HOST *hd)
 
 	/* Flush the doneQ.
 	 */
-	dprintk((KERN_INFO MYNAM ": flush_doneQ called\n"));
+	dtmprintk((KERN_INFO MYNAM ": flush_doneQ called\n"));
 	while (1) {
 		spin_lock_irqsave(&hd->freedoneQlock, flags);
 		if (Q_IS_EMPTY(&hd->doneQ)) {
@@ -1013,9 +1021,7 @@ flush_doneQ(MPT_SCSI_HOST *hd)
 
 		/* Do the OS callback.
 		 */
-                MPT_HOST_LOCK(flags);
 		SCpnt->scsi_done(SCpnt);
-                MPT_HOST_UNLOCK(flags);
 	}
 
 	return;
@@ -1055,6 +1061,26 @@ search_doneQ_for_cmd(MPT_SCSI_HOST *hd, 
 	return;
 }
 
+static void
+mptscsih_reset_timeouts (MPT_SCSI_HOST *hd)
+{
+	Scsi_Cmnd	*SCpnt;
+	int		 ii;
+	int		 max = hd->ioc->req_depth;
+		
+
+	for (ii= 0; ii < max; ii++) {
+		if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
+	/* calling mod_timer() panics in 2.6 kernel...
+	 * need to investigate
+	 */
+//			mod_timer(&SCpnt->eh_timeout, jiffies + (HZ * 60));
+			dtmprintk((MYIOC_s_WARN_FMT "resetting SCpnt=%p timeout + 60HZ",
+				(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
+		}
+	}
+}
+
 /*
  *	mptscsih_flush_running_cmds - For each command found, search
  *		Scsi_Host instance taskQ and reply to OS.
@@ -1068,23 +1094,24 @@ search_doneQ_for_cmd(MPT_SCSI_HOST *hd, 
 static void
 mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
 {
-	Scsi_Cmnd	*SCpnt = NULL;
-	MPT_FRAME_HDR	*mf = NULL;
+	Scsi_Cmnd	*SCpnt;
+	MPT_FRAME_HDR	*mf;
+	MPT_DONE_Q	*buffer;
 	int		 ii;
 	int		 max = hd->ioc->req_depth;
+	unsigned long	 flags;
 
 	dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
 	for (ii= 0; ii < max; ii++) {
 		if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
 
 			/* Command found.
-			 *
-			 * Search pendingQ, if found,
-			 * delete from Q. If found, do not decrement
-			 * queue_depth, command never posted.
 			 */
-			if (mptscsih_search_pendingQ(hd, ii) == NULL)
-				atomic_dec(&queue_depth);
+
+			/* Search pendingQ, if found,
+			 * delete from Q.
+			 */
+			mptscsih_search_pendingQ(hd, ii);
 
 			/* Null ScsiLookup index
 			 */
@@ -1111,15 +1138,39 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOS
 			}
 			SCpnt->result = DID_RESET << 16;
 			SCpnt->host_scribble = NULL;
-                        MPT_HOST_LOCK(flags);
-			SCpnt->scsi_done(SCpnt);	/* Issue the command callback */
-                        MPT_HOST_UNLOCK(flags);
 
 			/* Free Chain buffers */
 			mptscsih_freeChainBuffers(hd, ii);
 
 			/* Free Message frames */
 			mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
+
+#if 1
+			/* Post to doneQ, do not reply until POST phase
+			 * of reset handler....prevents new commands from
+			 * being queued.
+			 */
+			spin_lock_irqsave(&hd->freedoneQlock, flags);
+			if (!Q_IS_EMPTY(&hd->freeQ)) {
+				buffer = hd->freeQ.head;
+				Q_DEL_ITEM(buffer);
+
+				/* Set the Scsi_Cmnd pointer
+				 */
+				buffer->argp = (void *)SCpnt;
+
+				/* Add to the doneQ
+				 */
+				Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q);
+				spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+			} else {
+				spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+				SCpnt->scsi_done(SCpnt);
+			}
+#else
+			SCpnt->scsi_done(SCpnt);	/* Issue the command callback */
+#endif
+
 		}
 	}
 
@@ -1147,8 +1198,8 @@ mptscsih_search_running_cmds(MPT_SCSI_HO
 	int		 ii;
 	int		 max = hd->ioc->req_depth;
 
-	dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d numIos %d\n",
-			target, lun, max, atomic_read(&queue_depth)));
+	dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n",
+			target, lun, max));
 
 	for (ii=0; ii < max; ii++) {
 		if (hd->ScsiLookup[ii] != NULL) {
@@ -1161,11 +1212,6 @@ mptscsih_search_running_cmds(MPT_SCSI_HO
 			if ((mf->TargetID != ((u8)target)) || (mf->LUN[1] != ((u8) lun)))
 				continue;
 
-			/* If cmd pended, do not decrement queue_depth, command never posted.
-			 */
-			if (mptscsih_search_pendingQ(hd, ii) == NULL)
-				atomic_dec(&queue_depth);
-
 			/* Cleanup
 			 */
 			hd->ScsiLookup[ii] = NULL;
@@ -1177,73 +1223,6 @@ mptscsih_search_running_cmds(MPT_SCSI_HO
 	return;
 }
 
-#ifdef DROP_TEST
-/* 	mptscsih_flush_drop_test - Free resources and do callback if
- *		DROP_TEST enabled.
- *
- *	@hd: Pointer to a SCSI HOST structure
- *
- *	Returns: None.
- *
- *	Must be called while new I/Os are being queued.
- */
-static void
-mptscsih_flush_drop_test (MPT_SCSI_HOST *hd)
-{
-	Scsi_Cmnd	*sc;
-	unsigned long	 flags;
-	u16		 req_idx;
-
-	/* Free resources for the drop test MF
-	 * and chain buffers.
-	 */
-	if (dropMfPtr) {
-		req_idx = le16_to_cpu(dropMfPtr->u.frame.hwhdr.msgctxu.fld.req_idx);
-		sc = hd->ScsiLookup[req_idx];
-		if (sc == NULL) {
-			printk(MYIOC_s_ERR_FMT "Drop Test: NULL ScsiCmd ptr!\n",
-					ioc->name);
-		} else {
-			/* unmap OS resources, set status, do callback
-			 * free driver resources
-			 */
-			if (sc->use_sg) {
-				pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
-					    sc->use_sg, scsi_to_pci_dma_dir(sc->sc_data_direction));
-			} else if (sc->request_bufflen) {
-				scPrivate	*my_priv;
-
-				my_priv = (scPrivate *) &sc->SCp;
-				pci_unmap_single(ioc->pcidev, (dma_addr_t)(ulong)my_priv->p1,
-					   sc->request_bufflen,
-					   scsi_to_pci_dma_dir(sc->sc_data_direction));
-			}
-
-			sc->host_scribble = NULL;
-			sc->result = DID_RESET << 16;
-			hd->ScsiLookup[req_idx] = NULL;
-			atomic_dec(&queue_depth);
-			MPT_HOST_LOCK(flags);
-			sc->scsi_done(sc);	/* Issue callback */
-			MPT_HOST_UNLOCK(flags);
-		}
-
-		mptscsih_freeChainBuffers(hd, req_idx);
-		mpt_free_msg_frame(ScsiDoneCtx, ioc->id, dropMfPtr);
-		printk(MYIOC_s_INFO_FMT "Free'd Dropped cmd (%p)\n",
-					hd->ioc->name, sc);
-		printk(MYIOC_s_INFO_FMT "mf (%p) reqidx (%4x)\n",
-					hd->ioc->name, dropMfPtr, req_idx);
-		printk(MYIOC_s_INFO_FMT "Num Tot (%d) Good (%d) Bad (%d) \n",
-				hd->ioc->name, dropTestNum,
-				dropTestOK, dropTestBad);
-	}
-	dropMfPtr = NULL;
-
-	return;
-}
-#endif
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *	mptscsih_initChainBuffers - Allocate memory for and initialize
@@ -1263,18 +1242,15 @@ mptscsih_initChainBuffers (MPT_SCSI_HOST
 	/* ReqToChain size must equal the req_depth
 	 * index = req_idx
 	 */
-	sz = hd->ioc->req_depth * sizeof(int);
 	if (hd->ReqToChain == NULL) {
+		sz = hd->ioc->req_depth * sizeof(int);
 		mem = kmalloc(sz, GFP_ATOMIC);
 		if (mem == NULL)
 			return -1;
 
 		hd->ReqToChain = (int *) mem;
-	} else {
-		mem = (u8 *) hd->ReqToChain;
 	}
-/*	memset(mem, 0xFF, sz); */
-	for(ii=0;ii<hd->ioc->req_depth;ii++)
+	for (ii = 0; ii < hd->ioc->req_depth; ii++)
 		hd->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
 
 	/* ChainToChain size must equal the total number
@@ -1322,7 +1298,11 @@ mptscsih_initChainBuffers (MPT_SCSI_HOST
 	if (hd->ChainBuffer == NULL) {
 		/* Allocate free chain buffer pool
 		 */
+#if defined(MPTBASE_MEM_ALLOC_FIFO_FIX)
+		mem = pci_alloc_consistent(&hd->ioc->pcidev32, sz, &hd->ChainBufferDMA);
+#else		
 		mem = pci_alloc_consistent(hd->ioc->pcidev, sz, &hd->ChainBufferDMA);
+#endif		
 		if (mem == NULL)
 			return -1;
 
@@ -1405,310 +1385,333 @@ 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;
-	MPT_SCSI_HOST		*hd = NULL;
+	struct Scsi_Host	*sh;
+	MPT_SCSI_HOST		*hd;
 	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);
-	int			portnum;
 	MPT_DONE_Q		*freedoneQ;
 	unsigned long		 flags;
 	int			 sz, ii;
 	int			 numSGE = 0;
 	int			 scale;
+	int			 ioc_cap;
 	u8			*mem;
 	int			error=0;
 
-	for (portnum=0; portnum < ioc->facts.NumberOfPorts; portnum++) {
-
-		/* 20010215 -sralston
-		 *  Added sanity check on SCSI Initiator-mode enabled
-		 *  for this MPT adapter.
-		 */
-		if (!(ioc->pfacts[portnum].ProtocolFlags &
-		  MPI_PORTFACTS_PROTOCOL_INITIATOR)) {
-			printk(MYIOC_s_WARN_FMT
-			  "Skipping because SCSI Initiator mode is NOT enabled!\n",
-			  ioc->name);
-			continue;
-		}
-
-		/* 20010202 -sralston
-		 *  Added sanity check on readiness of the MPT adapter.
-		 */
-		if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
-			printk(MYIOC_s_WARN_FMT
-			  "Skipping because it's not operational!\n",
-			  ioc->name);
-			continue;
-		}
-
-		sh = scsi_host_alloc(&driver_template, sizeof(MPT_SCSI_HOST));
-		if (sh != NULL) {
-			spin_lock_irqsave(&ioc->FreeQlock, flags);
-
-			/* Attach the SCSI Host to the IOC structure
-			 */
-			ioc->sh = sh;
-
-			sh->io_port = 0;
-			sh->n_io_port = 0;
-			sh->irq = 0;
-
-			/* set 16 byte cdb's */
-			sh->max_cmd_len = 16;
-
-			/* Yikes!  This is important!
-			 * Otherwise, by default, linux
-			 * only scans target IDs 0-7!
-			 * pfactsN->MaxDevices unreliable
-			 * (not supported in early
-			 *	versions of the FW).
-			 * max_id = 1 + actual max id,
-			 * max_lun = 1 + actual last lun,
-			 *	see hosts.h :o(
-			 */
-			if ((int)ioc->chip_type > (int)FC929) {
-				sh->max_id = MPT_MAX_SCSI_DEVICES;
-			} else {
-			/* For FC, increase the queue depth
-			 * from MPT_SCSI_CAN_QUEUE (31)
-			 * to MPT_FC_CAN_QUEUE (63).
-			 */
-				sh->can_queue = MPT_FC_CAN_QUEUE;
-				sh->max_id =
-				  MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
-			}
-
-			sh->max_lun = MPT_LAST_LUN + 1;
-			sh->max_sectors = MPT_SCSI_MAX_SECTORS;
-			sh->this_id = ioc->pfacts[portnum].PortSCSIID;
-
-			/* Required entry.
-			 */
-			sh->unique_id = ioc->id;
-
-			/* Verify that we won't exceed the maximum
-			 * number of chain buffers
-			 * We can optimize:  ZZ = req_sz/sizeof(SGE)
-			 * For 32bit SGE's:
-			 *  numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
-			 *               + (req_sz - 64)/sizeof(SGE)
-			 * A slightly different algorithm is required for
-			 * 64bit SGEs.
-			 */
-			scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
-			if (sizeof(dma_addr_t) == sizeof(u64)) {
-				numSGE = (scale - 1) *
-				  (ioc->facts.MaxChainDepth-1) + scale +
-				  (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
-				  sizeof(u32));
-			} else {
-				numSGE = 1 + (scale - 1) *
-				  (ioc->facts.MaxChainDepth-1) + scale +
-				  (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
-				  sizeof(u32));
-			}
 
-			if (numSGE < sh->sg_tablesize) {
-				/* Reset this value */
-				dprintk((MYIOC_s_INFO_FMT
-				  "Resetting sg_tablesize to %d from %d\n",
-				  ioc->name, numSGE, sh->sg_tablesize));
-				sh->sg_tablesize = numSGE;
-			}
-
-			/* Set the pci device pointer in Scsi_Host structure.
-			 */
-			scsi_set_device(sh, &ioc->pcidev->dev);
-
-			spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
-			hd = (MPT_SCSI_HOST *) sh->hostdata;
-			hd->ioc = ioc;
-			hd->max_sge = sh->sg_tablesize;
-
-			if ((int)ioc->chip_type > (int)FC929)
-			hd->is_spi = 1;
+	/* 20010202 -sralston
+	 *  Added sanity check on readiness of the MPT adapter.
+	 */
+	if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
+		printk(MYIOC_s_WARN_FMT
+		  "Skipping because it's not operational!\n",
+		  ioc->name);
+		return -ENODEV;
+	}
 
-			if (DmpService && (ioc->chip_type == FC919 ||
-			  ioc->chip_type == FC929)) {
-				hd->is_multipath = 1;
-			}
-			hd->port = 0; /* FIXME! */
+	if (!ioc->active) {
+		printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
+		  ioc->name);
+		return -ENODEV;
+	}
 
-			/* SCSI needs Scsi_Cmnd lookup table!
-			 * (with size equal to req_depth*PtrSz!)
-			 */
-			sz = hd->ioc->req_depth * sizeof(void *);
-			mem = kmalloc(sz, GFP_ATOMIC);
-			if (mem == NULL) {
-				error = -ENOMEM;
-				goto mptscsih_probe_failed;
-			}
+	/*  Sanity check - ensure at least 1 port is INITIATOR capable
+	 */
+	ioc_cap = 0;
+	for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+		if (ioc->pfacts[ii].ProtocolFlags &
+		    MPI_PORTFACTS_PROTOCOL_INITIATOR)
+			ioc_cap ++;
+	}
 
-			memset(mem, 0, sz);
-			hd->ScsiLookup = (struct scsi_cmnd **) mem;
+	if (!ioc_cap) {
+		printk(MYIOC_s_WARN_FMT
+			"Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
+			ioc->name, ioc);
+		return -ENODEV;
+	}
 
-			dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
-				 ioc->name, hd->ScsiLookup, sz));
+	sh = scsi_host_alloc(&driver_template, sizeof(MPT_SCSI_HOST));
+        
+	if (!sh) {
+		printk(MYIOC_s_WARN_FMT
+			"Unable to register controller with SCSI subsystem\n",
+			ioc->name);
+                return -1;
+        }
+	
+	spin_lock_irqsave(&ioc->FreeQlock, flags);
 
-			if (mptscsih_initChainBuffers(hd, 1) < 0) {
-				error = -EINVAL;
-				goto mptscsih_probe_failed;
-			}
+	/* Attach the SCSI Host to the IOC structure
+	 */
+	ioc->sh = sh;
 
-			/* Allocate memory for free and doneQ's
-			 */
-			sz = sh->can_queue * sizeof(MPT_DONE_Q);
-			mem = kmalloc(sz, GFP_ATOMIC);
-			if (mem == NULL) {
-				error = -ENOMEM;
-				goto mptscsih_probe_failed;
-			}
+	sh->io_port = 0;
+	sh->n_io_port = 0;
+	sh->irq = 0;
+
+	/* set 16 byte cdb's */
+	sh->max_cmd_len = 16;
+
+	/* Yikes!  This is important!
+	 * Otherwise, by default, linux
+	 * only scans target IDs 0-7!
+	 * pfactsN->MaxDevices unreliable
+	 * (not supported in early
+	 *	versions of the FW).
+	 * max_id = 1 + actual max id,
+	 * max_lun = 1 + actual last lun,
+	 *	see hosts.h :o(
+	 */
+	if ((int)ioc->chip_type > (int)FC929) {
+		sh->max_id = MPT_MAX_SCSI_DEVICES;
+	} else {
+	/* For FC, increase the queue depth
+	 * from MPT_SCSI_CAN_QUEUE (31)
+	 * to MPT_FC_CAN_QUEUE (63).
+	 */
+		sh->can_queue = MPT_FC_CAN_QUEUE;
+		sh->max_id =
+		  MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
+	}
+		
+	sh->max_lun = MPT_LAST_LUN + 1;
+	sh->max_sectors = MPT_SCSI_MAX_SECTORS;
+	sh->max_channel = 0;
+	sh->this_id = ioc->pfacts[0].PortSCSIID;
+		
+	/* Required entry.
+	 */
+	sh->unique_id = ioc->id;
+
+	/* Verify that we won't exceed the maximum
+	 * number of chain buffers
+	 * We can optimize:  ZZ = req_sz/sizeof(SGE)
+	 * For 32bit SGE's:
+	 *  numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
+	 *               + (req_sz - 64)/sizeof(SGE)
+	 * A slightly different algorithm is required for
+	 * 64bit SGEs.
+	 */
+	scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
+	if (sizeof(dma_addr_t) == sizeof(u64)) {
+		numSGE = (scale - 1) *
+		  (ioc->facts.MaxChainDepth-1) + scale +
+		  (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
+		  sizeof(u32));
+	} else {
+		numSGE = 1 + (scale - 1) *
+		  (ioc->facts.MaxChainDepth-1) + scale +
+		  (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
+		  sizeof(u32));
+	}
+		
+	if (numSGE < sh->sg_tablesize) {
+		/* Reset this value */
+		dprintk((MYIOC_s_INFO_FMT
+		  "Resetting sg_tablesize to %d from %d\n",
+		  ioc->name, numSGE, sh->sg_tablesize));
+		sh->sg_tablesize = numSGE;
+	}
 
-			memset(mem, 0xFF, sz);
-			hd->memQ = mem;
+	/* Set the pci device pointer in Scsi_Host structure.
+	 */
+	scsi_set_device(sh, &ioc->pcidev->dev);
 
-			/* Initialize the free, done and pending Qs.
-			 */
-			Q_INIT(&hd->freeQ, MPT_DONE_Q);
-			Q_INIT(&hd->doneQ, MPT_DONE_Q);
-			Q_INIT(&hd->pendingQ, MPT_DONE_Q);
-			spin_lock_init(&hd->freedoneQlock);
-
-			mem = hd->memQ;
-			for (ii=0; ii < sh->can_queue; ii++) {
-				freedoneQ = (MPT_DONE_Q *) mem;
-				Q_ADD_TAIL(&hd->freeQ.head, freedoneQ, MPT_DONE_Q);
-				mem += sizeof(MPT_DONE_Q);
-			}
+	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 
-			/* Initialize this Scsi_Host
-			 * internal task Q.
-			 */
-			Q_INIT(&hd->taskQ, MPT_FRAME_HDR);
-			hd->taskQcnt = 0;
+	hd = (MPT_SCSI_HOST *) sh->hostdata;
+	hd->ioc = ioc;
+	hd->max_sge = sh->sg_tablesize;
+
+	if ((int)ioc->chip_type > (int)FC929)
+	hd->is_spi = 1;
+
+	if (DmpService && (ioc->chip_type == FC919 ||
+	  ioc->chip_type == FC929)) {
+		hd->is_multipath = 1;
+	}
+
+	/* SCSI needs Scsi_Cmnd lookup table!
+	 * (with size equal to req_depth*PtrSz!)
+	 */
+	sz = hd->ioc->req_depth * sizeof(void *);
+	mem = kmalloc(sz, GFP_ATOMIC);
+	if (mem == NULL) {
+		error = -ENOMEM;
+		goto mptscsih_probe_failed;
+	}
 
-			/* Allocate memory for the device structures.
-			 * A non-Null pointer at an offset
-			 * indicates a device exists.
-			 * max_id = 1 + maximum id (hosts.h)
-			 */
-			sz = sh->max_id * sizeof(void *);
-			mem = kmalloc(sz, GFP_ATOMIC);
-			if (mem == NULL) {
-				error = -ENOMEM;
-				goto mptscsih_probe_failed;
-			}
+	memset(mem, 0, sz);
+	hd->ScsiLookup = (struct scsi_cmnd **) mem;
 
-			memset(mem, 0, sz);
-			hd->Targets = (VirtDevice **) mem;
+	dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
+		 ioc->name, hd->ScsiLookup, sz));
+		
+	if (mptscsih_initChainBuffers(hd, 1) < 0) {
+		error = -EINVAL;
+		goto mptscsih_probe_failed;
+	}
+
+	/* Allocate memory for free and doneQ's
+	 */
+	sz = sh->can_queue * sizeof(MPT_DONE_Q);
+	mem = kmalloc(sz, GFP_ATOMIC);
+	if (mem == NULL) {
+		error = -ENOMEM;
+		goto mptscsih_probe_failed;
+	}
 
-			dprintk((KERN_INFO
-			  "  Targets @ %p, sz=%d\n", hd->Targets, sz));
+	memset(mem, 0xFF, sz);
+	hd->memQ = mem;
 
+	/* Initialize the free, done and pending Qs.
+	 */
+	Q_INIT(&hd->freeQ, MPT_DONE_Q);
+	Q_INIT(&hd->doneQ, MPT_DONE_Q);
+	Q_INIT(&hd->pendingQ, MPT_DONE_Q);
+	spin_lock_init(&hd->freedoneQlock);
+
+	mem = hd->memQ;
+	for (ii=0; ii < sh->can_queue; ii++) {
+		freedoneQ = (MPT_DONE_Q *) mem;
+		Q_ADD_TAIL(&hd->freeQ.head, freedoneQ, MPT_DONE_Q);
+		mem += sizeof(MPT_DONE_Q);
+	}
+
+	/* Initialize this Scsi_Host
+	 * internal task Q.
+	 */
+	Q_INIT(&hd->taskQ, MPT_FRAME_HDR);
+	hd->taskQcnt = 0;
+		
+	/* Allocate memory for the device structures.
+	 * A non-Null pointer at an offset
+	 * indicates a device exists.
+	 * max_id = 1 + maximum id (hosts.h)
+	 */
+	sz = sh->max_id * sizeof(void *);
+	mem = kmalloc(sz, GFP_ATOMIC);
+	if (mem == NULL) {
+		error = -ENOMEM;
+		goto mptscsih_probe_failed;
+	}
 
-			/* Clear the TM flags
-			 */
-			hd->tmPending = 0;
-			hd->tmState = TM_STATE_NONE;
-			hd->resetPending = 0;
-			hd->abortSCpnt = NULL;
-			hd->tmPtr = NULL;
-			hd->numTMrequests = 0;
+	memset(mem, 0, sz);
+	hd->Targets = (VirtDevice **) mem;
 
-			/* Clear the pointer used to store
-			 * single-threaded commands, i.e., those
-			 * issued during a bus scan, dv and
-			 * configuration pages.
-			 */
-			hd->cmdPtr = NULL;
+	dprintk((KERN_INFO
+	  "  Targets @ %p, sz=%d\n", hd->Targets, sz));
 
-			/* Initialize this SCSI Hosts' timers
-			 * To use, set the timer expires field
-			 * and add_timer
-			 */
-			init_timer(&hd->timer);
-			hd->timer.data = (unsigned long) hd;
-			hd->timer.function = mptscsih_timer_expired;
-
-			init_timer(&hd->TMtimer);
-			hd->TMtimer.data = (unsigned long) hd;
-			hd->TMtimer.function = mptscsih_taskmgmt_timeout;
-			hd->qtag_tick = jiffies;
+	/* Clear the TM flags
+	 */
+	hd->tmPending = 0;
+	hd->tmState = TM_STATE_NONE;
+	hd->resetPending = 0;
+	hd->abortSCpnt = NULL;
+	hd->tmPtr = NULL;
+	hd->numTMrequests = 0;
+		
+	/* Clear the pointer used to store
+	 * single-threaded commands, i.e., those
+	 * issued during a bus scan, dv and
+	 * configuration pages.
+	 */
+	hd->cmdPtr = NULL;
 
-			/* Moved Earlier Pam D */
-			/* ioc->sh = sh;	*/
+	/* Initialize this SCSI Hosts' timers
+	 * To use, set the timer expires field
+	 * and add_timer
+	 */
+	init_timer(&hd->timer);
+	hd->timer.data = (unsigned long) hd;
+	hd->timer.function = mptscsih_timer_expired;
+
+	init_timer(&hd->TMtimer);
+	hd->TMtimer.data = (unsigned long) hd;
+	hd->TMtimer.function = mptscsih_taskmgmt_timeout;
+	hd->qtag_tick = jiffies;
+
+	/* Moved Earlier Pam D */
+	/* ioc->sh = sh;	*/
+
+#ifdef MPTSCSIH_DBG_TIMEOUT
+	hd->ioc->timeout_hard = 0;
+	hd->ioc->timeout_delta = 30 * HZ;
+	hd->ioc->timeout_maxcnt = 0;
+	hd->ioc->timeout_cnt = 0;
+	for (ii=0; ii < 8; ii++)
+		foo_to[ii] = NULL;
+#endif
+	if (hd->is_spi) {
+		/* Update with the driver setup
+		 * values.
+		 */
+		if (hd->ioc->spi_data.maxBusWidth >
+		  driver_setup.max_width) {
+			hd->ioc->spi_data.maxBusWidth =
+			  driver_setup.max_width;
+		}
 
-			if (hd->is_spi) {
-				/* Update with the driver setup
-				 * values.
-				 */
-				if (hd->ioc->spi_data.maxBusWidth >
-				  driver_setup.max_width) {
-					hd->ioc->spi_data.maxBusWidth =
-					  driver_setup.max_width;
-				}
+		if (hd->ioc->spi_data.minSyncFactor <
+		  driver_setup.min_sync_fac) {
+			hd->ioc->spi_data.minSyncFactor =
+			  driver_setup.min_sync_fac;
+		}
 
-				if (hd->ioc->spi_data.minSyncFactor <
-				  driver_setup.min_sync_fac) {
-					hd->ioc->spi_data.minSyncFactor =
-					  driver_setup.min_sync_fac;
-				}
+		if (hd->ioc->spi_data.minSyncFactor == MPT_ASYNC) {
+			hd->ioc->spi_data.maxSyncOffset = 0;
+		}
 
-				if (hd->ioc->spi_data.minSyncFactor == MPT_ASYNC) {
-					hd->ioc->spi_data.maxSyncOffset = 0;
-				}
+		hd->ioc->spi_data.Saf_Te = driver_setup.saf_te;
 
-				hd->negoNvram = 0;
+		hd->negoNvram = 0;
 #ifndef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
-				hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
+		hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
 #endif
-				if (driver_setup.dv == 0) {
-					hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
-				}
-
-				hd->ioc->spi_data.forceDv = 0;
-				for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
-					hd->ioc->spi_data.dvStatus[ii] =
-					  MPT_SCSICFG_NEGOTIATE;
-				}
-
-				if (hd->negoNvram == 0) {
-					for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)
-						hd->ioc->spi_data.dvStatus[ii] |=
-						  MPT_SCSICFG_DV_NOT_DONE;
-				}
+		if (driver_setup.dv == 0) {
+			hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
+		}
 
-				ddvprintk((MYIOC_s_INFO_FMT
-					"dv %x width %x factor %x \n",
-					hd->ioc->name, driver_setup.dv,
-					driver_setup.max_width,
-					driver_setup.min_sync_fac));
+		hd->ioc->spi_data.forceDv = 0;
+		for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+			hd->ioc->spi_data.dvStatus[ii] =
+			  MPT_SCSICFG_NEGOTIATE;
+		}
 
-			}
+		if (hd->negoNvram == 0) {
+			for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)
+				hd->ioc->spi_data.dvStatus[ii] |=
+				  MPT_SCSICFG_DV_NOT_DONE;
+		}
 
-			mpt_scsi_hosts++;
+		ddvprintk((MYIOC_s_INFO_FMT
+			"dv %x width %x factor %x saf_te %x\n",
+			hd->ioc->name, driver_setup.dv,
+			driver_setup.max_width,
+			driver_setup.min_sync_fac,
+			driver_setup.saf_te));
+	}
 
-			error = scsi_add_host (sh, &ioc->pcidev->dev);
-			if(error) {
-				dprintk((KERN_ERR MYNAM,
-				  "scsi_add_host failed\n"));
-				goto mptscsih_probe_failed;
-			}
+	mpt_scsi_hosts++;
 
-			scsi_scan_host(sh);
-			return 0;
-		} /* scsi_host_alloc */
+	error = scsi_add_host (sh, &ioc->pcidev->dev);
+	if(error) {
+		dprintk((KERN_ERR MYNAM
+		  "scsi_add_host failed\n"));
+		goto mptscsih_probe_failed;
+	}
 
-	} /* for each adapter port */
+	scsi_scan_host(sh);
+	return 0;
 
 mptscsih_probe_failed:
 
 	mptscsih_remove(pdev);
 	return error;
+
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1718,7 +1721,7 @@ mptscsih_probe_failed:
  *
  *
  */
-static void __devexit
+static void
 mptscsih_remove(struct pci_dev *pdev)
 {
 	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);
@@ -1920,7 +1923,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,
@@ -2023,7 +2026,7 @@ mptscsih_exit(void)
 const char *
 mptscsih_info(struct Scsi_Host *SChost)
 {
-	MPT_SCSI_HOST *h = NULL;
+	MPT_SCSI_HOST *h;
 	int size = 0;
 
 	if (info_kbuf == NULL)
@@ -2099,101 +2102,20 @@ static int mptscsih_host_info(MPT_ADAPTE
 	return ((info.pos > info.offset) ? info.pos - info.offset : 0);
 }
 
-struct mptscsih_usrcmd {
-	ulong target;
-	ulong lun;
-	ulong data;
-	ulong cmd;
-};
-
-#define UC_GET_SPEED	0x10
-
-static void mptscsih_exec_user_cmd(MPT_ADAPTER *ioc, struct mptscsih_usrcmd *uc)
+#ifndef MPTSCSIH_DBG_TIMEOUT
+static int mptscsih_user_command(MPT_ADAPTER *ioc, char *pbuf, int len)
 {
-	CONFIGPARMS		 cfg;
-	dma_addr_t		 cfg_dma_addr = -1;
-	ConfigPageHeader_t	 header;
-
-	dprintk(("exec_user_command: ioc %p cmd %ld target=%ld\n",
-			ioc, uc->cmd, uc->target));
-
-	switch (uc->cmd) {
-	case UC_GET_SPEED:
-		{
-			SCSIDevicePage0_t	*pData = NULL;
-
-			if (ioc->spi_data.sdp0length == 0)
-				return;
-
-			pData = (SCSIDevicePage0_t *)pci_alloc_consistent(ioc->pcidev,
-				 ioc->spi_data.sdp0length * 4, &cfg_dma_addr);
-
-			if (pData == NULL)
-				return;
-
-			header.PageVersion = ioc->spi_data.sdp0version;
-			header.PageLength = ioc->spi_data.sdp0length;
-			header.PageNumber = 0;
-			header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
-
-			cfg.hdr = &header;
-			cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
-			cfg.dir = 0;
-			cfg.pageAddr = (u32) uc->target; /* bus << 8 | target */
-			cfg.physAddr = cfg_dma_addr;
-
-			if (mpt_config(ioc, &cfg) == 0) {
-				u32 np = le32_to_cpu(pData->NegotiatedParameters);
-				u32 tmp = np & MPI_SCSIDEVPAGE0_NP_WIDE;
-
-				printk("Target %d: %s;",
-						(u32) uc->target,
-						tmp ? "Wide" : "Narrow");
-
-				tmp = np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK;
-				if (tmp) {
-					u32 speed = 0;
-					printk(" Synchronous");
-					tmp = (tmp >> 16);
-					printk(" (Offset=0x%x", tmp);
-					tmp = np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK;
-					tmp = (tmp >> 8);
-					printk(" Factor=0x%x)", tmp);
-					if (tmp <= MPT_ULTRA320)
-						speed=160;
-					else if (tmp <= MPT_ULTRA160)
-						speed=80;
-					else if (tmp <= MPT_ULTRA2)
-						speed=40;
-					else if (tmp <= MPT_ULTRA)
-						speed=20;
-					else if (tmp <= MPT_FAST)
-						speed=10;
-					else if (tmp <= MPT_SCSI)
-						speed=5;
-
-					if (np & MPI_SCSIDEVPAGE0_NP_WIDE)
-						speed*=2;
-
-					printk(" %dMB/sec\n", speed);
-
-				} else
-					printk(" Asynchronous.\n");
-			} else {
-				printk("failed\n" );
-			}
-
-			pci_free_consistent(ioc->pcidev, ioc->spi_data.sdp0length * 4,
-					    pData, cfg_dma_addr);
-		}
-		break;
-	}
+	/* Not yet implemented */
+	return len;
 }
-
+#else
 #define is_digit(c)	((c) >= '0' && (c) <= '9')
 #define digit_to_bin(c)	((c) - '0')
 #define is_space(c)	((c) == ' ' || (c) == '\t')
 
+#define UC_DBG_TIMEOUT		0x01
+#define UC_DBG_HARDRESET	0x02
+
 static int skip_spaces(char *ptr, int len)
 {
 	int cnt, c;
@@ -2242,50 +2164,66 @@ static int is_keyword(char *ptr, int len
 
 static int mptscsih_user_command(MPT_ADAPTER *ioc, char *buffer, int length)
 {
-	char *ptr	= buffer;
-	struct mptscsih_usrcmd cmd, *uc = &cmd;
-	ulong		target;
-	int		arg_len;
-	int len		= length;
+	char *ptr = buffer;
+	char btmp[24];	/* REMOVE */
+	int arg_len;
+	int len	= length;
+	int cmd;
+	ulong number = 1;
+	ulong delta = 10;
 
-	uc->target = uc->cmd = uc->lun = uc->data = 0;
-	
 	if ((len > 0) && (ptr[len -1] == '\n'))
 		--len;
 
-	if ((arg_len = is_keyword(ptr, len, "getspeed")) != 0)
-		uc->cmd = UC_GET_SPEED;
-	else
-		arg_len = 0;
-
-	dprintk(("user_command:  arg_len=%d, cmd=%ld\n", arg_len, uc->cmd));
+	if (len < 22) {
+		strncpy(btmp, buffer, len);
+		btmp[len+1]='\0';
+	} else {
+		strncpy(btmp, buffer, 22);
+		btmp[23]='\0';
+	}
+	printk("user_command:  ioc %d, buffer %s, length %d\n",
+			ioc->id, btmp, length);
 
-	if (!arg_len)
+	if ((arg_len = is_keyword(ptr, len, "timeout")) != 0)
+		cmd = UC_DBG_TIMEOUT;
+	else if ((arg_len = is_keyword(ptr, len, "hardreset")) != 0)
+		cmd = UC_DBG_HARDRESET;
+	else
 		return -EINVAL;
 
 	ptr += arg_len;
 	len -= arg_len;
 
-	switch(uc->cmd) {
-		case UC_GET_SPEED:
+	switch(cmd) {
+		case UC_DBG_TIMEOUT:
 			SKIP_SPACES(1);
-			GET_INT_ARG(target);
-			uc->target = target;
+			GET_INT_ARG(number);
+			SKIP_SPACES(1);
+			GET_INT_ARG(delta);
 			break;
 	}
 
-	dprintk(("user_command: target=%ld len=%d\n", uc->target, len));
+	printk("user_command: cnt=%ld delta=%ld\n", number, delta);
 
 	if (len)
 		return -EINVAL;
 	else {
-		/* process this command ...
-		 */
-		mptscsih_exec_user_cmd(ioc, uc);
+		if (cmd == UC_DBG_HARDRESET) {
+			ioc->timeout_hard = 1;
+		} else if (cmd == UC_DBG_TIMEOUT) {
+			/* process this command ...
+			 */
+			ioc->timeout_maxcnt = 0;
+			ioc->timeout_delta = delta < 2 ? 2 : delta;
+			ioc->timeout_cnt = 0;
+			ioc->timeout_maxcnt = number < 8 ? number: 8;
+		}
 	}
 	/* Not yet implemented */
 	return length;
 }
+#endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
@@ -2303,7 +2241,7 @@ static int mptscsih_user_command(MPT_ADA
 int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
 			int length, int func)
 {
-	MPT_ADAPTER	*ioc = NULL;
+	MPT_ADAPTER	*ioc;
 	MPT_SCSI_HOST	*hd = NULL;
 	int size = 0;
 
@@ -2334,49 +2272,8 @@ int mptscsih_proc_info(struct Scsi_Host 
 
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-	static int max_qd = 1;
 #define ADD_INDEX_LOG(req_ent)	do { } while(0)
 
-#ifdef	DROP_TEST
-#define DROP_IOC	1	/* IOC to force failures */
-#define DROP_TARGET	3	/* Target ID to force failures */
-#define	DROP_THIS_CMD	10000	/* iteration to drop command */
-static int dropCounter = 0;
-static int dropTestOK = 0;	/* num did good */
-static int dropTestBad = 0;	/* num did bad */
-static int dropTestNum = 0;	/* total = good + bad + incomplete */
-static int numTotCmds = 0;
-static MPT_FRAME_HDR *dropMfPtr = NULL;
-static int numTMrequested = 0;
-#endif
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *	mptscsih_put_msgframe - Wrapper routine to post message frame to F/W.
- *	@context: Call back context (ScsiDoneCtx, ScsiScanDvCtx)
- *	@id: IOC id number
- *	@mf: Pointer to message frame
- *
- *	Handles the call to mptbase for posting request and queue depth
- *	tracking.
- *
- *	Returns none.
- */
-static inline void
-mptscsih_put_msgframe(int context, int id, MPT_FRAME_HDR *mf)
-{
-	/* Main banana... */
-	atomic_inc(&queue_depth);
-	if (atomic_read(&queue_depth) > max_qd) {
-		max_qd = atomic_read(&queue_depth);
-		dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd));
-	}
-
-	mpt_put_msg_frame(context, id, mf);
-
-	return;
-}
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *	mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
@@ -2396,7 +2293,7 @@ mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*d
 	MPT_FRAME_HDR		*mf;
 	SCSIIORequest_t		*pScsiReq;
 	VirtDevice		*pTarget;
-	MPT_DONE_Q		*buffer = NULL;
+	MPT_DONE_Q		*buffer;
 	unsigned long		 flags;
 	int	 target;
 	int	 lun;
@@ -2424,9 +2321,14 @@ mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*d
 
 	if (hd->resetPending) {
 		/* Prevent new commands from being issued
-		 * while reloading the FW.
+		 * while reloading the FW. Reset timer to 60 seconds,
+		 * as the FW can take some time to come ready.
+		 * For New EH, cmds on doneQ posted to FW.
 		 */
 		did_errcode = 1;
+		mod_timer(&SCpnt->eh_timeout, jiffies + (HZ * 60));
+		dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
+			(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
 		goto did_error;
 	}
 
@@ -2481,8 +2383,8 @@ mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*d
 
 	/* Use the above information to set up the message frame
 	 */
-	pScsiReq->TargetID = target;
-	pScsiReq->Bus = hd->port;
+	pScsiReq->TargetID = (u8) target;
+	pScsiReq->Bus = (u8) SCpnt->device->channel;
 	pScsiReq->ChainOffset = 0;
 	pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
 	pScsiReq->CDBLength = SCpnt->cmd_len;
@@ -2501,12 +2403,14 @@ mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*d
 
 	/*
 	 *  Write SCSI CDB into the message
-	 *  Should write from cmd_len up to 16, but skip for performance reasons.
 	 */
 	cmd_len = SCpnt->cmd_len;
 	for (ii=0; ii < cmd_len; ii++)
 		pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
 
+	for (ii=cmd_len; ii < 16; ii++)
+		pScsiReq->CDB[ii] = 0;
+
 	/* DataLength */
 	pScsiReq->DataLength = cpu_to_le32(datalen);
 
@@ -2532,39 +2436,6 @@ mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*d
 		hd->ScsiLookup[my_idx] = SCpnt;
 		SCpnt->host_scribble = NULL;
 
-#ifdef	DROP_TEST
-		numTotCmds++;
-		/* If the IOC number and target match, increment
-		 * counter. If counter matches DROP_THIS, do not
-		 * issue command to FW to force a reset.
-		 * Save the MF pointer so we can free resources
-		 * when task mgmt completes.
-		 */
-		if ((hd->ioc->id == DROP_IOC) && (target == DROP_TARGET)) {
-			dropCounter++;
-
-			if (dropCounter == DROP_THIS_CMD) {
-				dropCounter = 0;
-
-				/* If global is set, then we are already
-				 * doing something - so keep issuing commands.
-				 */
-				if (dropMfPtr == NULL) {
-					dropTestNum++;
-					dropMfPtr = mf;
-					atomic_inc(&queue_depth);
-					printk(MYIOC_s_INFO_FMT
-						"Dropped SCSI cmd (%p)\n",
-						hd->ioc->name, SCpnt);
-					printk("mf (%p) req (%4x) tot cmds (%d)\n",
-						mf, my_idx, numTotCmds);
-
-					return 0;
-				}
-			}
-		}
-#endif
-
 		/* SCSI specific processing */
 		issueCmd = 1;
 		if (hd->is_spi) {
@@ -2617,8 +2488,20 @@ mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*d
 			}
 		}
 
+#ifdef MPTSCSIH_DBG_TIMEOUT
+		if (hd->ioc->timeout_cnt < hd->ioc->timeout_maxcnt) {
+			foo_to[hd->ioc->timeout_cnt] = SCpnt;
+			hd->ioc->timeout_cnt++;
+			//mod_timer(&SCpnt->eh_timeout, jiffies + hd->ioc->timeout_delta);
+			issueCmd = 0;
+			printk(MYIOC_s_WARN_FMT
+				"to pendingQ: (sc=%p, mf=%p, time=%ld)\n",
+				hd->ioc->name, SCpnt, mf, jiffies);
+		}
+#endif
+
 		if (issueCmd) {
-			mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+			mpt_put_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
 			dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
 					hd->ioc->name, SCpnt, mf, my_idx));
 		} else {
@@ -2660,6 +2543,8 @@ did_error:
 	SCpnt->result = (DID_BUS_BUSY << 16);
 	spin_lock_irqsave(&hd->freedoneQlock, flags);
 	if (!Q_IS_EMPTY(&hd->freeQ)) {
+		dtmprintk((MYIOC_s_WARN_FMT "SCpnt=%p to doneQ\n",
+			(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
 		buffer = hd->freeQ.head;
 		Q_DEL_ITEM(buffer);
 
@@ -2692,7 +2577,7 @@ did_error:
 static void
 mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx)
 {
-	MPT_FRAME_HDR *chain = NULL;
+	MPT_FRAME_HDR *chain;
 	unsigned long flags;
 	int chain_idx;
 	int next;
@@ -2755,9 +2640,9 @@ mptscsih_freeChainBuffers(MPT_SCSI_HOST 
  *	Returns 0 for SUCCESS or -1 if FAILED.
  */
 static int
-mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag)
+mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag)
 {
-	MPT_ADAPTER	*ioc = NULL;
+	MPT_ADAPTER	*ioc;
 	int		 rc = -1;
 	int		 doTask = 1;
 	u32		 ioc_raw_state;
@@ -2770,19 +2655,18 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8
 		return 0;
 
 	ioc = hd->ioc;
-	dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
-
 	if (ioc == NULL) {
 		printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
-		return 0;
+		return FAILED;
 	}
+	dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
 
 	// SJR - CHECKME - Can we avoid this here?
 	// (mpt_HardResetHandler has this check...)
 	spin_lock_irqsave(&ioc->diagLock, flags);
 	if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
 		spin_unlock_irqrestore(&ioc->diagLock, flags);
-		return 0;
+		return FAILED;
 	}
 	spin_unlock_irqrestore(&ioc->diagLock, flags);
 
@@ -2792,6 +2676,37 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8
 	if (hd->numTMrequests > MPT_HOST_TOO_MANY_TM)
 		doTask = 0;
 
+	/*  Wait a fixed amount of time for the TM pending flag to be cleared.
+	 *  If we time out and not bus reset, then we return a FAILED status to the caller.
+	 *  The call to mptscsih_tm_pending_wait() will set the pending flag if we are
+	 *  successful. Otherwise, reload the FW.
+	 */
+	if (mptscsih_tm_pending_wait(hd) == FAILED) {
+		if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
+			dtmprintk((KERN_WARNING MYNAM ": %s: TMHandler abort: "
+			   "Timed out waiting for last TM (%d) to complete! \n",
+			   hd->ioc->name, hd->tmPending));
+			return FAILED;
+		} else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
+			dtmprintk((KERN_WARNING MYNAM ": %s: TMHandler target reset: "
+			   "Timed out waiting for last TM (%d) to complete! \n",
+			   hd->ioc->name, hd->tmPending));
+			return FAILED;
+		} else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
+			dtmprintk((KERN_WARNING MYNAM ": %s: TMHandler bus reset: "
+			   "Timed out waiting for last TM (%d) to complete! \n",
+			   hd->ioc->name, hd->tmPending));
+			if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
+				return FAILED;
+
+			doTask = 0;
+		}
+	} else {
+		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+		hd->tmPending |=  (1 << type);
+		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+	}
+
 	/* Is operational?
 	 */
 	ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
@@ -2799,7 +2714,7 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8
 #ifdef MPT_DEBUG_RESET
 	if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
 		printk(MYIOC_s_WARN_FMT
-			"TM Handler: IOC Not operational! state 0x%x Calling HardResetHandler\n",
+			"TM Handler: IOC Not operational(0x%x)!\n",
 			hd->ioc->name, ioc_raw_state);
 	}
 #endif
@@ -2811,23 +2726,24 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8
 		 */
 		if (hd->hard_resets < -1)
 			hd->hard_resets++;
-		rc = mptscsih_IssueTaskMgmt(hd, type, target, lun, ctx2abort, timeout, sleepFlag);
+		rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout, sleepFlag);
 		if (rc) {
 			printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
 		} else {
 			dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
 		}
 	}
-#ifdef DROP_TEST
-	numTMrequested++;
-	if (numTMrequested > 5) {
-		rc = 0;		/* set to 1 to force a hard reset */
-		numTMrequested = 0;
-	}
+
+#ifdef MPTSCSIH_DBG_TIMEOUT
+	if (hd->ioc->timeout_hard)
+		rc = 1;
 #endif
 
-	if (rc || ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw)) {
-		dtmprintk((MYIOC_s_INFO_FMT "Falling through to HardReset! \n",
+	/* Only fall through to the HRH if this is a bus reset
+	 */
+	if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
+		ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
+		dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
 			 hd->ioc->name));
 		rc = mpt_HardResetHandler(hd->ioc, sleepFlag);
 	}
@@ -2857,7 +2773,7 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8
  *	else other non-zero value returned.
  */
 static int
-mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag)
+mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag)
 {
 	MPT_FRAME_HDR	*mf;
 	SCSITaskMgmt_t	*pScsiTm;
@@ -2879,7 +2795,7 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd
 	 */
 	pScsiTm = (SCSITaskMgmt_t *) mf;
 	pScsiTm->TargetID = target;
-	pScsiTm->Bus = hd->port;
+	pScsiTm->Bus = channel;
 	pScsiTm->ChainOffset = 0;
 	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
 
@@ -2953,8 +2869,11 @@ mptscsih_abort(Scsi_Cmnd * SCpnt)
 		return FAILED;
 	}
 
-	printk(KERN_WARNING MYNAM ": %s: >> Attempting task abort! (sc=%p, numIOs=%d)\n",
-	       hd->ioc->name, SCpnt, atomic_read(&queue_depth));
+	if (hd->resetPending)
+		return FAILED;
+
+	printk(KERN_WARNING MYNAM ": %s: >> Attempting task abort! (sc=%p)\n",
+	       hd->ioc->name, SCpnt);
 
 	if (hd->timeouts < -1)
 		hd->timeouts++;
@@ -2968,38 +2887,21 @@ mptscsih_abort(Scsi_Cmnd * SCpnt)
 		search_doneQ_for_cmd(hd, SCpnt);
 
 		SCpnt->result = DID_RESET << 16;
-		SCpnt->scsi_done(SCpnt);
 		dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
 			   "Command not in the active list! (sc=%p)\n",
 			   hd->ioc->name, SCpnt));
 		return SUCCESS;
 	}
 
-	/*  Wait a fixed amount of time for the TM pending flag to be cleared.
-	 *  If we time out, then we return a FAILED status to the caller.  This
-	 *  call to mptscsih_tm_pending_wait() will set the pending flag if we are
-	 *  successful.
-	 */
-	spin_unlock_irq(host_lock);
-	if (mptscsih_tm_pending_wait(hd) == FAILED){
-		dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
-			   "Timed out waiting for previous TM to complete! "
-			   "(sc = %p)\n",
-			   hd->ioc->name, SCpnt));
-		spin_lock_irq(host_lock);
-		return FAILED;
-	}
-	spin_lock_irq(host_lock);
-
 	/* If this command is pended, then timeout/hang occurred
 	 * during DV. Post command and flush pending Q
 	 * and then following up with the reset request.
 	 */
 	if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
-		mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+		mpt_put_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
 		post_pendingQ_commands(hd);
 		dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
-			   "Found command in pending queue! (sc=%p)\n",
+			   "Posting pended cmd! (sc=%p)\n",
 			   hd->ioc->name, SCpnt));
 	}
 
@@ -3017,7 +2919,7 @@ mptscsih_abort(Scsi_Cmnd * SCpnt)
 
 	spin_unlock_irq(host_lock);
 	if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
-		SCpnt->device->id, SCpnt->device->lun,
+		SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun,
 		ctx2abort, (HZ*2) /* 2 second timeout */,CAN_SLEEP)
 		< 0) {
 
@@ -3064,31 +2966,21 @@ mptscsih_dev_reset(Scsi_Cmnd * SCpnt)
 		return FAILED;
 	}
 
-	printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p, numIOs=%d)\n",
-	       hd->ioc->name, SCpnt, atomic_read(&queue_depth));
+	if (hd->resetPending)
+		return FAILED;
+
+	printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p)\n",
+	       hd->ioc->name, SCpnt);
 
-	/* Unsupported for SCSI. Suppored for FCP
+	/* Unsupported for SCSI. Supported for FCP
 	 */
 	if (hd->is_spi)
 		return FAILED;
 
-	/*  Wait a fixed amount of time for the TM pending flag to be cleared.
-	 *  If we time out, then we return a FAILED status to the caller.  This
-	 *  call to mptscsih_tm_pending_wait() will set the pending flag if we are
-	 *  successful.
-	 */
 	spin_unlock_irq(host_lock);
-	if (mptscsih_tm_pending_wait(hd) == FAILED) {
-		dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_dev_reset: "
-			   "Timed out waiting for previous TM to complete! "
-			   "(sc = %p)\n",
-			   hd->ioc->name, SCpnt));
-		spin_lock_irq(host_lock);
-		return FAILED;
-	}
-
 	if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
-		SCpnt->device->id, 0, 0, (HZ*5) /* 5 second timeout */, CAN_SLEEP)
+		SCpnt->device->channel, SCpnt->device->id,
+		0, 0, (HZ*5) /* 5 second timeout */, CAN_SLEEP)
 		< 0){
 		/* The TM request failed and the subsequent FW-reload failed!
 		 * Fatal error case.
@@ -3129,30 +3021,19 @@ mptscsih_bus_reset(Scsi_Cmnd * SCpnt)
 		return FAILED;
 	}
 
-	printk(KERN_WARNING MYNAM ": %s: >> Attempting bus reset! (sc=%p, numIOs=%d)\n",
-	       hd->ioc->name, SCpnt, atomic_read(&queue_depth));
+	printk(KERN_WARNING MYNAM ": %s: >> Attempting bus reset! (sc=%p)\n",
+	       hd->ioc->name, SCpnt);
 
 	if (hd->timeouts < -1)
 		hd->timeouts++;
 
-	/*  Wait a fixed amount of time for the TM pending flag to be cleared.
-	 *  If we time out, then we return a FAILED status to the caller.  This
-	 *  call to mptscsih_tm_pending_wait() will set the pending flag if we are
-	 *  successful.
-	 */
-	spin_unlock_irq(host_lock);
-	if (mptscsih_tm_pending_wait(hd) == FAILED) {
-		dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_bus_reset: "
-			   "Timed out waiting for previous TM to complete! "
-			   "(sc = %p)\n",
-			   hd->ioc->name, SCpnt));
-		spin_lock_irq(host_lock);
-		return FAILED;
-	}
-
 	/* We are now ready to execute the task management request. */
+	spin_unlock_irq(host_lock);
+//	printk("testing start : mptscsih_schedule_reset\n");
+//	mptscsih_schedule_reset(hd);
+//	printk("testing end: mptscsih_schedule_reset\n");
 	if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
-		0, 0, 0, (HZ*5) /* 5 second timeout */, CAN_SLEEP)
+		SCpnt->device->channel, 0, 0, 0, (HZ*5) /* 5 second timeout */, CAN_SLEEP)
 	    < 0){
 
 		/* The TM request failed and the subsequent FW-reload failed!
@@ -3197,8 +3078,6 @@ mptscsih_host_reset(Scsi_Cmnd *SCpnt)
 
 	printk(KERN_WARNING MYNAM ": %s: >> Attempting host reset! (sc=%p)\n",
 	       hd->ioc->name, SCpnt);
-	printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n",
-	       hd->ioc->name, atomic_read(&queue_depth));
 
 	/*  If our attempts to reset the host failed, then return a failed
 	 *  status.  The host will be taken off line by the SCSI mid-layer.
@@ -3274,7 +3153,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *
 {
 	SCSITaskMgmtReply_t	*pScsiTmReply;
 	SCSITaskMgmt_t		*pScsiTmReq;
-	MPT_SCSI_HOST		*hd = NULL;
+	MPT_SCSI_HOST		*hd;
 	unsigned long		 flags;
 	u8			 tmType = 0;
 
@@ -3325,10 +3204,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *
 			 */
 			if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
 				hd->abortSCpnt = NULL;
-#ifdef	DROP_TEST
-			if (dropMfPtr)
-				dropTestBad++;
-#endif
+
 			/* If an internal command is present
 			 * or the TM failed - reload the FW.
 			 * FC FW may respond FAILED to an ABORT
@@ -3349,17 +3225,9 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *
 			hd->abortSCpnt = NULL;
 			flush_doneQ(hd);
 
-#ifdef	DROP_TEST
-			if (dropMfPtr)
-				dropTestOK++;
-#endif
 		}
 	}
 
-#ifdef	DROP_TEST
-	mptscsih_flush_drop_test(hd);
-#endif
-
 	hd->tmPtr = NULL;
 	spin_lock_irqsave(&ioc->FreeQlock, flags);
 	hd->tmPending = 0;
@@ -3438,15 +3306,14 @@ mptscsih_slave_alloc(Scsi_Device *device
 
 	hd = (MPT_SCSI_HOST *)host->hostdata;
 
-
 	if (hd == NULL)
-		return ENODEV;
+		return -ENODEV;
 
 	if ((vdev = hd->Targets[device->id]) == NULL) {
 		if ((vdev = kmalloc(sizeof(VirtDevice), GFP_ATOMIC)) == NULL) {
 			printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%d) FAILED!\n",
-					hd->ioc->name, (int)sizeof(VirtDevice));
-			return ENOMEM;
+			hd->ioc->name, (int)sizeof(VirtDevice));
+			return -ENOMEM;
 		} else {
 			memset(vdev, 0, sizeof(VirtDevice));
 			rwlock_init(&vdev->VdevLock);
@@ -3476,9 +3343,10 @@ mptscsih_slave_destroy(Scsi_Device *devi
 	struct Scsi_Host	*host = device->host;
 	MPT_SCSI_HOST		*hd;
 	VirtDevice		*vdev;
+	int 			raid_volume=0;
 
 	hd = (MPT_SCSI_HOST *)host->hostdata;
-	
+
 	if (hd == NULL)
 		return;
 
@@ -3489,8 +3357,8 @@ mptscsih_slave_destroy(Scsi_Device *devi
 	if ((vdev = hd->Targets[device->id]) != NULL) {
 		vdev->num_luns--;
 
-		if (vdev->luns & (1 << device->lun))
-			vdev->luns &= ~(1 << device->lun);
+		if (vdev->luns[0] & (1 << device->lun))
+			vdev->luns[0] &= ~(1 << device->lun);
 
 		/* Free device structure only if number of luns is 0.
 		 */
@@ -3498,232 +3366,115 @@ mptscsih_slave_destroy(Scsi_Device *devi
 			kfree(hd->Targets[device->id]);
 			hd->Targets[device->id] = NULL;
 
-			if (hd->is_spi) {
-				hd->ioc->spi_data.dvStatus[device->id] = MPT_SCSICFG_NEGOTIATE;
-
-				if (hd->negoNvram == 0)
-					hd->ioc->spi_data.dvStatus[device->id] |= MPT_SCSICFG_DV_NOT_DONE;
-
-				/* Don't alter isRaid, not allowed to move
-				 * volumes on a running system.
-				 */
-				if (hd->ioc->spi_data.isRaid & (1 << (device->id)))
-					hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3;
-			}
-		}
-	}
-
-	return;
-}
-
-/*
- *	OS entry point to adjust the queue_depths on a per-device basis.
- *	Called once per device the bus scan. Use it to force the queue_depth
- *	member to 1 if a device does not support Q tags.
- *	Return non-zero if fails.
- */
-int
-mptscsih_slave_configure(Scsi_Device *device)
-{
-	struct Scsi_Host	*host = device->host;
-	VirtDevice		*vdev;
-	MPT_SCSI_HOST		*hd;
-
-	hd = (MPT_SCSI_HOST *)host->hostdata;
-
-	dsprintk((KERN_INFO "slave_configure: device @ %p, id=%d, LUN=%d, channel=%d\n",
-		device, device->id, device->lun, device->channel));
-	dsprintk((KERN_INFO "sdtr %d wdtr %d ppr %d inq length=%d\n",
-		device->sdtr, device->wdtr, device->ppr, device->inquiry_len));
-	dsprintk(("tagged %d simple %d ordered %d\n",
-		device->tagged_supported, device->simple_tags, device->ordered_tags));
-
-	/*	set target parameters, queue depths, set dv flags ?  */
-	if (hd && (hd->Targets != NULL)) {
-		vdev = hd->Targets[device->id];
+			if (!hd->is_spi) 
+				return;
 
-		if (vdev && !(vdev->tflags & MPT_TARGET_FLAGS_CONFIGURED)) {
-			/* Configure only the first discovered LUN
-			 */
-			vdev->raidVolume = 0;
-			if (hd->is_spi && (hd->ioc->spi_data.isRaid & (1 << (device->id)))) {
-				vdev->raidVolume = 1;
-				ddvtprintk((KERN_INFO "RAID Volume @ id %d\n", device->id));
+			if((hd->ioc->spi_data.isRaid) && (hd->ioc->spi_data.pIocPg3)) {
+			int i;
+				for(i=0;i<hd->ioc->spi_data.pIocPg3->NumPhysDisks &&
+					raid_volume==0;i++)
+						
+					if(device->id == 
+					  hd->ioc->spi_data.pIocPg3->PhysDisk[i].PhysDiskNum) {
+						raid_volume=1;
+						hd->ioc->spi_data.forceDv |=
+						  MPT_SCSICFG_RELOAD_IOC_PG3;
+					}
 			}
 
-			mptscsih_target_settings(hd, vdev, device);
-
-			vdev->tflags |= MPT_TARGET_FLAGS_CONFIGURED;
-		}
+			if(!raid_volume){
+				hd->ioc->spi_data.dvStatus[device->id] =
+				MPT_SCSICFG_NEGOTIATE;
 
-		if (vdev) {
-			/* set the queue depth for all devices
-			 */
-			if (!device->tagged_supported ||
-			    !(vdev->tflags & MPT_TARGET_FLAGS_Q_YES)) {
-				scsi_adjust_queue_depth(device, 0, 1);
-			} else if (vdev->type == 0x00
-				   && (vdev->minSyncFactor <= MPT_ULTRA160 || !hd->is_spi)) {
-				scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
-							MPT_SCSI_CMD_PER_DEV_HIGH);
-			} else {
-				scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
-							MPT_SCSI_CMD_PER_DEV_LOW);
+				if (hd->negoNvram == 0)
+					hd->ioc->spi_data.dvStatus[device->id]
+					|= MPT_SCSICFG_DV_NOT_DONE;
 			}
-
-			vdev->luns |= (1 << device->lun);
-			vdev->tflags |= MPT_TARGET_FLAGS_CONFIGURED;
 		}
 	}
-	return 0;
-}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *  Update the target negotiation parameters based on the
- *  the Inquiry data, adapter capabilities, and NVRAM settings.
- *
- */
-static void
-mptscsih_target_settings(MPT_SCSI_HOST *hd, VirtDevice *target, Scsi_Device *sdev)
-{
-	ScsiCfgData *pspi_data = &hd->ioc->spi_data;
-	int  id = (int) target->target_id;
-	int  nvram;
-	u8 width = MPT_NARROW;
-	u8 factor = MPT_ASYNC;
-	u8 offset = 0;
-	u8 nfactor;
-	u8 noQas = 1;
-
-	ddvtprintk((KERN_INFO "set Target: (id %d) \n", id));
-
-	if (!hd->is_spi) {
-		/* FC - only care about QTag support
-	 	 */
-		if (sdev->tagged_supported)
-			target->tflags |= MPT_TARGET_FLAGS_Q_YES;
-		return;
-	}
-
-	/* SCSI - Set flags based on Inquiry data
-	 */
-	if (sdev->scsi_level < 2) {
-		width = 0;
-		factor = MPT_ULTRA2;
-		offset = pspi_data->maxSyncOffset;
-	} else {
-		width = sdev->wdtr;
-		if (sdev->sdtr) {
-			if (sdev->ppr) {
-				/* U320 requires IU capability */
-				if ((sdev->inquiry_len > 56) && (sdev->inquiry[56] & 0x01))
-					factor = MPT_ULTRA320;
-				else
-					factor = MPT_ULTRA160;
-			} else
-				factor = MPT_ULTRA2;
-
-			/* If RAID, never disable QAS
-			 * else if non RAID, do not disable
-			 *   QAS if bit 1 is set
-			 * bit 1 QAS support, non-raid only
-			 * bit 0 IU support
-			 */
-			if ((target->raidVolume == 1) ||
-			    ((sdev->inquiry_len > 56) && (sdev->inquiry[56] & 0x02)))
-				noQas = 0;
-
-			offset = pspi_data->maxSyncOffset;
-
-		} else {
-			factor = MPT_ASYNC;
-			offset = 0;
-		}
-	}
-
-	/* Update tflags based on NVRAM settings. (SCSI only)
-	 */
-	if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
-		nvram = pspi_data->nvram[id];
-		nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
-
-		if (width)
-			width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
-
-		if (offset > 0) {
-			/* Ensure factor is set to the
-			 * maximum of: adapter, nvram, inquiry
-			 */
-			if (nfactor) {
-				if (nfactor < pspi_data->minSyncFactor )
-					nfactor = pspi_data->minSyncFactor;
-
-				factor = MAX (factor, nfactor);
-				if (factor == MPT_ASYNC)
-					offset = 0;
-			} else {
-				offset = 0;
-				factor = MPT_ASYNC;
-			}
-		} else
-			factor = MPT_ASYNC;
-	}
-
-	/* Make sure data is consistent
-	 */
-	if ((!width) && (factor < MPT_ULTRA2))
-		factor = MPT_ULTRA2;
-
-	/* Save the data to the target structure.
-	 */
-	target->minSyncFactor = factor;
-	target->maxOffset = offset;
-	target->maxWidth = width;
-	if (sdev->tagged_supported)
-		target->tflags |= MPT_TARGET_FLAGS_Q_YES;
-
-	/* Disable unused features.
-	 */
-	target->negoFlags = pspi_data->noQas;
-	if (!width)
-		target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
-
-	if (!offset)
-		target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
+	
+	return;
+}
 
-	if (noQas)
-		target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+/*
+ *	OS entry point to adjust the queue_depths on a per-device basis.
+ *	Called once per device the bus scan. Use it to force the queue_depth
+ *	member to 1 if a device does not support Q tags.
+ *	Return non-zero if fails.
+ */
+int
+mptscsih_slave_configure(Scsi_Device *device)
+{
+	struct Scsi_Host	*sh = device->host;
+	VirtDevice		*pTarget;
+	MPT_SCSI_HOST		*hd = (MPT_SCSI_HOST *)sh->hostdata;
 
-	/* GEM, processor WORKAROUND
-	 */
-	target->type = sdev->inquiry[0] & 0x1F;
-	if ((target->type == 0x03) || (target->type > 0x08)){
-		target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
-		pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO;
+	if ((hd == NULL) || (hd->Targets == NULL)) {
+		return 0;
 	}
 
-	/* Disable QAS if mixed configuration case
-	 */
-	if ((noQas) && (!pspi_data->noQas) && (target->type == 0x00)){
-		VirtDevice	*vdev;
-		int ii;
-
-		ddvtprintk((KERN_INFO "Disabling QAS!\n"));
-		pspi_data->noQas = MPT_TARGET_NO_NEGO_QAS;
-		for (ii = 0; ii < id; ii++) {
-			vdev = hd->Targets[id];
-			if (vdev != NULL)
-				vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+	dsprintk((MYIOC_s_INFO_FMT
+		"device @ %p, id=%d, LUN=%d, channel=%d\n",
+		hd->ioc->name, device, device->id, device->lun, device->channel));
+	dsprintk((MYIOC_s_INFO_FMT
+		"sdtr %d wdtr %d ppr %d inq length=%d\n",
+		hd->ioc->name, device->sdtr, device->wdtr,
+		device->ppr, device->inquiry_len));
+
+	if (device->id > sh->max_id) {
+		/* error case, should never happen */
+		scsi_adjust_queue_depth(device, 0, 1);
+		goto slave_configure_exit;
+	}
+
+	pTarget = hd->Targets[device->id];
+
+	if (pTarget == NULL) {
+		/* error case - don't know about this device */
+		scsi_adjust_queue_depth(device, 0, 1);
+		goto slave_configure_exit;
+	}
+
+	mptscsih_initTarget(hd, device->channel, device->id, device->lun,
+		device->inquiry, device->inquiry_len );
+	scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
+		MPT_SCSI_CMD_PER_DEV_HIGH);
+	if ( hd->is_spi ) {
+		if (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
+			if (!(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
+				scsi_adjust_queue_depth(device, 0, 1);
+			else if (((pTarget->inq_data[0] & 0x1f) == 0x00)
+			  && (pTarget->minSyncFactor <= MPT_ULTRA160 ))
+				scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
+					MPT_SCSI_CMD_PER_DEV_HIGH);
+			else
+				scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
+					MPT_SCSI_CMD_PER_DEV_LOW);
+		} else {
+			/* error case - No Inq. Data */
+			scsi_adjust_queue_depth(device, 0, 1);
 		}
 	}
 
-	ddvtprintk((KERN_INFO "Final settings id %d: dvstatus 0x%x\n", sdev->id, pspi_data->dvStatus[id]));
-	ddvtprintk(("wide %d, factor 0x%x offset 0x%x neg flags 0x%x flags 0x%x\n",
-			width, factor, offset, target->negoFlags, target->tflags));
+	dsprintk((MYIOC_s_INFO_FMT
+		"Queue depth=%d, tflags=%x\n",
+		hd->ioc->name, device->queue_depth, pTarget->tflags));
 
-	return;
+	dsprintk((MYIOC_s_INFO_FMT
+		"negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
+		hd->ioc->name, pTarget->negoFlags, pTarget->maxOffset, pTarget->minSyncFactor));
+
+slave_configure_exit:
+
+	dsprintk((MYIOC_s_INFO_FMT
+		"tagged %d, simple %d, ordered %d\n",
+		hd->ioc->name,device->tagged_supported, device->simple_tags,
+		device->ordered_tags));
+
+	return 0;
 }
 
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  Private routines...
@@ -3789,11 +3540,10 @@ copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_
 		thisIo.SCSIStatus = pScsiReply->SCSIStatus;
 		thisIo.DoDisplay = 1;
 		if (hd->is_multipath)
-			sprintf(devFoo, "%d:%d:%d \"%s\"",
+			sprintf(devFoo, "%d:%d:%d",
 					hd->ioc->id,
 					pReq->TargetID,
-					pReq->LUN[1],
-					target->dev_vol_name);
+					pReq->LUN[1]);
 		else
 			sprintf(devFoo, "%d:%d:%d", hd->ioc->id, sc->device->id, sc->device->lun);
 		thisIo.DevIDStr = devFoo;
@@ -3842,7 +3592,7 @@ mptscsih_search_pendingQ(MPT_SCSI_HOST *
 	unsigned long	 flags;
 	MPT_DONE_Q	*buffer;
 	MPT_FRAME_HDR	*mf = NULL;
-	MPT_FRAME_HDR	*cmdMfPtr = NULL;
+	MPT_FRAME_HDR	*cmdMfPtr;
 
 	ddvtprintk((MYIOC_s_INFO_FMT ": search_pendingQ ...", hd->ioc->name));
 	cmdMfPtr = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
@@ -3911,7 +3661,7 @@ post_pendingQ_commands(MPT_SCSI_HOST *hd
 			continue;
 		}
 
-		mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+		mpt_put_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
 
 #if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
 		{
@@ -3930,12 +3680,13 @@ post_pendingQ_commands(MPT_SCSI_HOST *hd
 static int
 mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
-	MPT_SCSI_HOST	*hd = NULL;
+	MPT_SCSI_HOST	*hd;
 	unsigned long	 flags;
 
 	dtmprintk((KERN_WARNING MYNAM
 			": IOC %s_reset routed to SCSI host driver!\n",
-			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
+			reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
 
 	/* If a FW reload request arrives after base installed but
 	 * before all scsi hosts have been attached, then an alt_ioc
@@ -3946,9 +3697,8 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int
 	else
 		hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
 
-	if (reset_phase == MPT_IOC_PRE_RESET) {
-		dtmprintk((MYIOC_s_WARN_FMT "Do Pre-Diag Reset handling\n",
-			ioc->name));
+	if (reset_phase == MPT_IOC_SETUP_RESET) {
+		dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
 
 		/* Clean Up:
 		 * 1. Set Hard Reset Pending Flag
@@ -3956,6 +3706,11 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int
 		 */
 		hd->resetPending = 1;
 
+		mptscsih_reset_timeouts (hd);
+	
+	} else if (reset_phase == MPT_IOC_PRE_RESET) {
+		dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
+
 		/* 2. Flush running commands
 		 *	Clean drop test code - if compiled
 		 *	Clean ScsiLookup (and associated memory)
@@ -3964,9 +3719,6 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int
 
 		/* 2a. Drop Test Command.
 		 */
-#ifdef	DROP_TEST
-		mptscsih_flush_drop_test(hd);
-#endif
 
 		/* 2b. Reply to OS all known outstanding I/O commands.
 		 */
@@ -3979,7 +3731,6 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int
 		if (hd->cmdPtr) {
 			del_timer(&hd->timer);
 			mpt_free_msg_frame(ScsiScanDvCtx, ioc->id, hd->cmdPtr);
-			atomic_dec(&queue_depth);
 		}
 
 		/* 2d. If a task management has not completed,
@@ -3990,12 +3741,14 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int
 			mpt_free_msg_frame(ScsiTaskCtx, ioc->id, hd->tmPtr);
 		}
 
-		dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset handling complete.\n",
-			ioc->name));
+#ifdef MPTSCSIH_DBG_TIMEOUT
+		ioc->timeout_hard = 0;
+#endif
+
+		dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
 
 	} else {
-		dtmprintk((MYIOC_s_WARN_FMT "Do Post-Diag Reset handling\n",
-			ioc->name));
+		dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
 
 		/* Once a FW reload begins, all new OS commands are
 		 * redirected to the doneQ w/ a reset status.
@@ -4052,10 +3805,6 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int
 		 */
 		flush_doneQ(hd);
 
-		dtmprintk((MYIOC_s_WARN_FMT "Post-Reset handling complete.\n",
-			ioc->name));
-
-
 		/* 8. Set flag to force DV and re-read IOC Page 3
 		 */
 		if (hd->is_spi) {
@@ -4063,6 +3812,8 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int
 			ddvtprintk(("Set reload IOC Pg3 Flag\n"));
 		}
 
+		dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
+
 	}
 
 	return 1;		/* currently means nothing really */
@@ -4571,6 +4322,268 @@ int mpt_ScsiHost_ErrorReport(IO_Info_t *
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mptscsih_initTarget - Target, LUN alloc/free functionality.
+ *	@hd: Pointer to MPT_SCSI_HOST structure
+ *	@bus_id: Bus number (?)
+ *	@target_id: SCSI target id
+ *	@lun: SCSI LUN id
+ *	@data: Pointer to data
+ *	@dlen: Number of INQUIRY bytes
+ *
+ *	NOTE: It's only SAFE to call this routine if data points to
+ *	sane & valid STANDARD INQUIRY data!
+ *
+ *	Allocate and initialize memory for this target.
+ *	Save inquiry data.
+ *
+ */
+static void
+mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen)
+{
+	int		indexed_lun, lun_index;
+	VirtDevice	*vdev;
+	char		data_56;
+
+	dprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
+			hd->ioc->name, bus_id, target_id, lun, hd));
+
+	/* Is LUN supported? If so, upper 3 bits will be 0
+	* in first byte of inquiry data.
+	*/
+	if (data[0] & 0xe0)
+		return;
+
+	vdev = hd->Targets[target_id];
+
+	lun_index = (lun >> 5);  /* 32 luns per lun_index */
+	indexed_lun = (lun % 32);
+	vdev->luns[lun_index] |= (1 << indexed_lun);
+
+	vdev->raidVolume = 0;
+	if (hd->is_spi) {
+		if (hd->ioc->spi_data.isRaid & (1 << target_id)) {
+			vdev->raidVolume = 1;
+			ddvtprintk((KERN_INFO "RAID Volume @ id %d\n", target_id));
+		}
+	}
+
+	if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
+		if ( dlen > 8 ) {
+			memcpy (vdev->inq_data, data, 8);
+		} else {
+			memcpy (vdev->inq_data, data, dlen);
+		}
+		vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
+
+		/* If LUN 0, tape and have not done DV, set the DV flag.
+		 */
+		if (hd->is_spi && (lun == 0) && (data[0] == SCSI_TYPE_TAPE)) {
+			ScsiCfgData *pSpi = &hd->ioc->spi_data;
+			if (pSpi->dvStatus[target_id] & MPT_SCSICFG_DV_NOT_DONE)
+				pSpi->dvStatus[target_id] |= MPT_SCSICFG_NEED_DV;
+		}
+
+		if ( (data[0] == SCSI_TYPE_PROC) &&
+			!(vdev->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
+			if ( dlen > 49 ) {
+				vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
+				if ( data[44] == 'S' &&
+				     data[45] == 'A' &&
+				     data[46] == 'F' &&
+				     data[47] == '-' &&
+				     data[48] == 'T' &&
+				     data[49] == 'E' ) {
+					vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
+					mptscsih_writeIOCPage4(hd, target_id, bus_id);
+				}
+			} else {
+				/* Treat all Processors as SAF-TE if
+				 * command line option is set */
+				if ( hd->ioc->spi_data.Saf_Te ) {
+					vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
+					mptscsih_writeIOCPage4(hd, target_id, bus_id);
+				}
+			}
+		}
+
+		data_56 = 0;
+		if (dlen > 56) {
+			if ( (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) {
+			/* Update the target capabilities
+			 */
+				data_56 = data[56];
+				vdev->tflags |= MPT_TARGET_FLAGS_VALID_56;
+			}
+		}
+		mptscsih_setTargetNegoParms(hd, vdev, data_56);
+	}
+
+	dprintk((KERN_INFO "  target = %p\n", vdev));
+	return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Update the target negotiation parameters based on the
+ *  the Inquiry data, adapter capabilities, and NVRAM settings.
+ *
+ */
+void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56)
+{
+	ScsiCfgData *pspi_data = &hd->ioc->spi_data;
+	int  id = (int) target->target_id;
+	int  nvram;
+	char canQ = 0;
+	VirtDevice	*vdev;
+	int ii;
+	u8 width = MPT_NARROW;
+	u8 factor = MPT_ASYNC;
+	u8 offset = 0;
+	u8 version, nfactor;
+	u8 noQas = 1;
+
+	if (!hd->is_spi) {
+		if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
+			if (target->inq_data[7] & 0x02)
+				target->tflags |= MPT_TARGET_FLAGS_Q_YES;
+		}
+		return;
+	}
+
+	target->negoFlags = pspi_data->noQas;
+
+	/* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine
+	 * support. If available, default QAS to off and allow enabling.
+	 * If not available, default QAS to on, turn off for non-disks.
+	 */
+
+	/* Set flags based on Inquiry data
+	 */
+	if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
+		version = target->inq_data[2] & 0x07;
+		if (version < 2) {
+			width = 0;
+			factor = MPT_ULTRA2;
+			offset = pspi_data->maxSyncOffset;
+		} else {
+			if (target->inq_data[7] & 0x20) {
+				width = 1;
+			}
+
+			if (target->inq_data[7] & 0x10) {
+				/* bits 2 & 3 show DT support
+				 */
+				if ((byte56 & 0x04) == 0)
+					factor = MPT_ULTRA2;
+				else if ((byte56 & 0x03) == 0)
+					factor = MPT_ULTRA160;
+				else
+					factor = MPT_ULTRA320;
+				offset = pspi_data->maxSyncOffset;
+
+				/* If RAID, never disable QAS
+				 * else if non RAID, do not disable
+				 *   QAS if bit 1 is set
+				 * bit 1 QAS support, non-raid only
+				 * bit 0 IU support
+				 */
+				if ((target->raidVolume == 1) || ((byte56 & 0x02) != 0))
+					noQas = 0;
+			} else {
+				factor = MPT_ASYNC;
+				offset = 0;
+			}
+		}
+
+		if (target->inq_data[7] & 0x02) {
+			canQ = 1;
+		}
+
+		/* Update tflags based on NVRAM settings. (SCSI only)
+		 */
+		if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+			nvram = pspi_data->nvram[id];
+			nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
+
+			if (width)
+				width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
+
+			if (offset > 0) {
+				/* Ensure factor is set to the
+				 * maximum of: adapter, nvram, inquiry
+				 */
+				if (nfactor) {
+					if (nfactor < pspi_data->minSyncFactor )
+						nfactor = pspi_data->minSyncFactor;
+
+					factor = MAX (factor, nfactor);
+					if (factor == MPT_ASYNC)
+						offset = 0;
+				} else {
+					offset = 0;
+					factor = MPT_ASYNC;
+				}
+			} else {
+				factor = MPT_ASYNC;
+			}
+		}
+
+		/* Make sure data is consistent
+		 */
+		if ((!width) && (factor < MPT_ULTRA2)) {
+			factor = MPT_ULTRA2;
+		}
+
+		/* Save the data to the target structure.
+		 */
+		target->minSyncFactor = factor;
+		target->maxOffset = offset;
+		target->maxWidth = width;
+		if (canQ) {
+			target->tflags |= MPT_TARGET_FLAGS_Q_YES;
+		}
+
+		target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
+
+		/* Disable unused features.
+		 */
+		if (!width)
+			target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
+
+		if (!offset)
+			target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
+
+		/* GEM, processor WORKAROUND
+		 */
+		if (((target->inq_data[0] & 0x1F) == 0x03)
+			|| ((target->inq_data[0] & 0x1F) > 0x08)) {
+			target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
+			pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO;
+		} else {
+			if (noQas && (pspi_data->noQas == 0)) {
+				pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
+				target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+
+				/* Disable QAS in a mixed configuration case
+		 		*/
+
+//				ddvtprintk((KERN_INFO "Disabling QAS!\n"));
+				for (ii = 0; ii < id; ii++) {
+					if ( (vdev = hd->Targets[ii]) ) {
+						vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+					}
+				}
+			}
+		}
+	}
+
+	return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
  * Else set the NEED_DV flag after Read Capacity Issued (disks)
  * or Mode Sense (cdroms).
@@ -4581,7 +4594,7 @@ int mpt_ScsiHost_ErrorReport(IO_Info_t *
 static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq)
 {
 	u8 cmd;
-	
+
 	if ((pReq->LUN[1] != 0) || (hd->negoNvram != 0))
 		return;
 
@@ -4609,16 +4622,14 @@ static void mptscsih_set_dvflags(MPT_SCS
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- * If no Target (old) or Target unconfigured (new) and bus reset on 1st I/O,
- * set the flag to prevent any future negotiations to this device.
+ * If no Target, bus reset on 1st I/O. Set the flag to
+ * prevent any future negotiations to this device.
  */
 static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id)
 {
-	if (hd->Targets) {
-		VirtDevice *vdev = hd->Targets[target_id];
-		if ((vdev == NULL) || !(vdev->tflags & MPT_TARGET_FLAGS_CONFIGURED))
-			hd->ioc->spi_data.dvStatus[target_id] |= MPT_SCSICFG_BLK_NEGO;
-	}
+
+	if ((hd->Targets) && (hd->Targets[target_id] == NULL))
+		hd->ioc->spi_data.dvStatus[target_id] |= MPT_SCSICFG_BLK_NEGO;
 
 	return;
 }
@@ -4691,9 +4702,9 @@ static int
 mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
 {
 	MPT_ADAPTER		*ioc = hd->ioc;
-	Config_t		*pReq = NULL;
-	SCSIDevicePage1_t	*pData = NULL;
-	VirtDevice		*pTarget = NULL;
+	Config_t		*pReq;
+	SCSIDevicePage1_t	*pData;
+	VirtDevice		*pTarget;
 	MPT_FRAME_HDR		*mf;
 	dma_addr_t		 dataDma;
 	u16			 req_idx;
@@ -4784,13 +4795,11 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, in
 		/* If id is not a raid volume, get the updated
 		 * transmission settings from the target structure.
 		 */
-		if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume
-				&& (pTarget->tflags & MPT_TARGET_FLAGS_CONFIGURED)) {
+		if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) {
 			width = pTarget->maxWidth;
 			factor = pTarget->minSyncFactor;
 			offset = pTarget->maxOffset;
 			negoFlags = pTarget->negoFlags;
-			pTarget = NULL;
 		}
 
 		if (flags & MPT_SCSICFG_BLK_NEGO)
@@ -4832,9 +4841,8 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, in
 		pReq->Reserved = 0;
 		pReq->ChainOffset = 0;
 		pReq->Function = MPI_FUNCTION_CONFIG;
-		pReq->Reserved1[0] = 0;
-		pReq->Reserved1[1] = 0;
-		pReq->Reserved1[2] = 0;
+		pReq->ExtPageLength = 0;
+		pReq->ExtPageType = 0;
 		pReq->MsgFlags = 0;
 		for (ii=0; ii < 8; ii++) {
 			pReq->Reserved2[ii] = 0;
@@ -4861,14 +4869,93 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, in
 		pData->Reserved = 0;
 		pData->Configuration = cpu_to_le32(configuration);
 
-		dsprintk((MYIOC_s_INFO_FMT
+		dprintk((MYIOC_s_INFO_FMT
 			"write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n",
 				ioc->name, id, (id | (bus<<8)),
 				requested, configuration));
 
-		mptscsih_put_msgframe(ScsiDoneCtx, ioc->id, mf);
+		mpt_put_msg_frame(ScsiDoneCtx, ioc->id, mf);
+	}
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*	mptscsih_writeIOCPage4  - write IOC Page 4
+ *	@hd: Pointer to a SCSI Host Structure
+ *	@target_id: write IOC Page4 for this ID & Bus
+ *
+ *	Return: -EAGAIN if unable to obtain a Message Frame
+ *		or 0 if success.
+ *
+ *	Remark: We do not wait for a return, write pages sequentially.
+ */
+static int
+mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
+{
+	MPT_ADAPTER		*ioc = hd->ioc;
+	Config_t		*pReq;
+	IOCPage4_t		*IOCPage4Ptr;
+	MPT_FRAME_HDR		*mf;
+	dma_addr_t		 dataDma;
+	u16			 req_idx;
+	u32			 frameOffset;
+	u32			 flagsLength;
+	int			 ii;
+
+	/* Get a MF for this command.
+	 */
+	if ((mf = mpt_get_msg_frame(ScsiDoneCtx, ioc->id)) == NULL) {
+		dprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
+					ioc->name));
+		return -EAGAIN;
+	}
+
+	ddvprintk((MYIOC_s_INFO_FMT "writeIOCPage4 (mf=%p, id=%d)\n",
+		ioc->name, mf, target_id));
+
+	/* Set the request and the data pointers.
+	 * Place data at end of MF.
+	 */
+	pReq = (Config_t *)mf;
+
+	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+	frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
+
+	/* Complete the request frame (same for all requests).
+	 */
+	pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+	pReq->Reserved = 0;
+	pReq->ChainOffset = 0;
+	pReq->Function = MPI_FUNCTION_CONFIG;
+	pReq->ExtPageLength = 0;
+	pReq->ExtPageType = 0;
+	pReq->MsgFlags = 0;
+	for (ii=0; ii < 8; ii++) {
+		pReq->Reserved2[ii] = 0;
 	}
 
+       	IOCPage4Ptr = ioc->spi_data.pIocPg4;
+       	dataDma = ioc->spi_data.IocPg4_dma;
+       	ii = IOCPage4Ptr->ActiveSEP++;
+       	IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
+       	IOCPage4Ptr->SEP[ii].SEPBus = bus;
+       	pReq->Header = IOCPage4Ptr->Header;
+	pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
+
+	/* Add a SGE to the config request.
+	 */
+	flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
+		(IOCPage4Ptr->Header.PageLength + ii) * 4;
+
+	mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
+
+	dsprintk((MYIOC_s_INFO_FMT
+		"writeIOCPage4: pgaddr 0x%x\n",
+			ioc->name, (target_id | (bus<<8))));
+
+	mpt_put_msg_frame(ScsiDoneCtx, ioc->id, mf);
+
 	return 0;
 }
 
@@ -4982,8 +5069,6 @@ mptscsih_scandv_complete(MPT_ADAPTER *io
 	ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
 			hd->ioc->name, mf, mr, req_idx));
 
-	atomic_dec(&queue_depth);
-
 	hd->pLocal = &hd->localReply;
 	hd->pLocal->scsiStatus = 0;
 
@@ -5042,7 +5127,7 @@ mptscsih_scandv_complete(MPT_ADAPTER *io
 				u8		*sense_data;
 				int		 sz;
 
-				/* save sense data in global & target structure
+				/* save sense data in global structure
 				 */
 				completionCode = MPT_SCANDV_SENSE;
 				hd->pLocal->scsiStatus = pReply->SCSIStatus;
@@ -5215,7 +5300,7 @@ mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 a
 	hd->cmdPtr = mf;
 
 	add_timer(&hd->timer);
-	mptscsih_put_msgframe(ScsiScanDvCtx, hd->ioc->id, mf);
+	mpt_put_msg_frame(ScsiScanDvCtx, hd->ioc->id, mf);
 	wait_event(scandv_waitq, scandv_wait_done);
 
 	if ((hd->pLocal == NULL) || (hd->pLocal->completion != MPT_SCANDV_GOOD))
@@ -5452,7 +5537,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER
 	hd->cmdPtr = mf;
 
 	add_timer(&hd->timer);
-	mptscsih_put_msgframe(ScsiScanDvCtx, hd->ioc->id, mf);
+	mpt_put_msg_frame(ScsiScanDvCtx, hd->ioc->id, mf);
 	wait_event(scandv_waitq, scandv_wait_done);
 
 	if (hd->pLocal) {
@@ -5490,7 +5575,7 @@ static int
 mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum)
 {
 	MPT_ADAPTER		*ioc= hd->ioc;
-	VirtDevice		*pTarget = NULL;
+	VirtDevice		*pTarget;
 	SCSIDevicePage1_t	*pcfg1Data = NULL;
 	INTERNAL_CMD		 iocmd;
 	CONFIGPARMS		 cfg;
@@ -5498,7 +5583,8 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST
 	ConfigPageHeader_t	 header1;
 	int			 bus = 0;
 	int			 id = 0;
-	int			 lun = 0;
+	int			 lun;
+	int			 indexed_lun, lun_index;
 	int			 hostId = ioc->pfacts[portnum].PortSCSIID;
 	int			 max_id;
 	int			 requested, configuration, data;
@@ -5593,7 +5679,9 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST
 			for (lun=0; lun <= MPT_LAST_LUN; lun++) {
 				/* If LUN present, issue the command
 				 */
-				if (pTarget->luns & (1<<lun)) {
+				lun_index = (lun >> 5);  /* 32 luns per lun_index */
+				indexed_lun = (lun % 32);
+				if (pTarget->luns[lun_index] & (1<<indexed_lun)) {
 					iocmd.lun = lun;
 					(void) mptscsih_do_cmd(hd, &iocmd);
 				}
@@ -5634,8 +5722,8 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST
 static void
 mptscsih_domainValidation(void *arg)
 {
-	MPT_SCSI_HOST		*hd = NULL;
-	MPT_ADAPTER		*ioc = NULL;
+	MPT_SCSI_HOST		*hd;
+	MPT_ADAPTER		*ioc;
 	unsigned long		 flags;
 	int 			 id, maxid, dvStatus, did;
 	int			 ii, isPhysDisk;
@@ -5792,7 +5880,7 @@ static int mptscsih_is_phys_disk(MPT_ADA
  */
 static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id)
 {
-	VirtDevice *pTarget = NULL;
+	VirtDevice *pTarget;
 	int ii;
 
 	if (hd->Targets == NULL)
@@ -5843,15 +5931,15 @@ static void mptscsih_qas_check(MPT_SCSI_
  *	Return: None.
  */
 static int
-mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
+mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
 {
 	MPT_ADAPTER		*ioc = hd->ioc;
-	VirtDevice		*pTarget = NULL;
-	SCSIDevicePage1_t	*pcfg1Data = NULL;
-	SCSIDevicePage0_t	*pcfg0Data = NULL;
-	u8			*pbuf1 = NULL;
-	u8			*pbuf2 = NULL;
-	u8			*pDvBuf = NULL;
+	VirtDevice		*pTarget;
+	SCSIDevicePage1_t	*pcfg1Data;
+	SCSIDevicePage0_t	*pcfg0Data;
+	u8			*pbuf1;
+	u8			*pbuf2;
+	u8			*pDvBuf;
 	dma_addr_t		 dvbuf_dma = -1;
 	dma_addr_t		 buf1_dma = -1;
 	dma_addr_t		 buf2_dma = -1;
@@ -5871,6 +5959,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int por
 	int			 patt;
 	int			 repeat;
 	int			 retcode = 0;
+	int			 nfactor =  MPT_ULTRA320;
 	char			 firstPass = 1;
 	char			 doFallback = 0;
 	char			 readPage0;
@@ -5883,14 +5972,17 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int por
 	if (ioc->spi_data.sdp0length == 0)
 		return 0;
 
-	if (id == ioc->pfacts[portnum].PortSCSIID)
+	/* If multiple buses are used, require that the initiator
+	 * id be the same on all buses.
+	 */
+	if (id == ioc->pfacts[0].PortSCSIID)
 		return 0;
 
 	lun = 0;
-	bus = 0;
+	bus = (u8) bus_number;
 	ddvtprintk((MYIOC_s_NOTE_FMT
-			"DV started: numIOs %d bus=%d, id %d dv @ %p\n",
-			ioc->name, atomic_read(&queue_depth), bus, id, &dv));
+			"DV started: bus=%d, id %d dv @ %p\n",
+			ioc->name, bus, id, &dv));
 
 	/* Prep DV structure
 	 */
@@ -5916,11 +6008,11 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int por
 	iocmd.rsvd = iocmd.rsvd2 = 0;
 
 	pTarget = hd->Targets[id];
-	if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_CONFIGURED)) {
+	if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
 		/* Another GEM workaround. Check peripheral device type,
 		 * if PROCESSOR, quit DV.
 		 */
-		if ((pTarget->type == 0x03) || (pTarget->type > 0x08)) {
+		if (((pTarget->inq_data[0] & 0x1F) == 0x03) || ((pTarget->inq_data[0] & 0x1F) > 0x08)) {
 			pTarget->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
 			return 0;
 		}
@@ -5992,24 +6084,34 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int por
 
 	/* Skip this ID? Set cfg.hdr to force config page write
 	 */
-	if ((ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID) &&
-			(!(ioc->spi_data.nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE))) {
+	{
+		ScsiCfgData *pspi_data = &hd->ioc->spi_data;
+		if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+			/* Set the factor from nvram */
+			nfactor = (pspi_data->nvram[id] & MPT_NVRAM_SYNC_MASK) >> 8;
+			if (nfactor < pspi_data->minSyncFactor )
+				nfactor = pspi_data->minSyncFactor;
 
-		ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
-			ioc->name, bus, id, lun));
+			if (!(pspi_data->nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE) ||
+				(pspi_data->PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV) ) {
 
-		dv.cmd = MPT_SET_MAX;
-		mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
-		cfg.hdr = &header1;
-		/* Double writes to SDP1 can cause problems,
-		 * skip save of the final negotiated settings to
-		 * SCSI device page 1.
-		 */
-		cfg.physAddr = cfg1_dma_addr;
-		cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
-		cfg.dir = 1;
-		mpt_config(hd->ioc, &cfg);
-		goto target_done;
+				ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
+					ioc->name, bus, id, lun));
+
+				dv.cmd = MPT_SET_MAX;
+				mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+				cfg.hdr = &header1;
+
+				/* Save the final negotiated settings to
+				 * SCSI device page 1.
+				 */
+				cfg.physAddr = cfg1_dma_addr;
+				cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+				cfg.dir = 1;
+				mpt_config(hd->ioc, &cfg);
+				goto target_done;
+			}
+		}
 	}
 
 	/* Finish iocmd inititialization - hidden or visible disk? */
@@ -6059,7 +6161,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int por
 	sz = SCSI_STD_INQUIRY_BYTES;
 	rc = MPT_SCANDV_GOOD;
 	while (1) {
-		ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test.\n", ioc->name));
+		ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test on id=%d\n", ioc->name, id));
 		retcode = 0;
 		dv.cmd = MPT_SET_MIN;
 		mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
@@ -6131,6 +6233,14 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int por
 			}
 		}
 
+		/* Reset the size for disks
+		 */
+		inq0 = (*pbuf1) & 0x1F;
+		if ((inq0 == 0) && pTarget && !pTarget->raidVolume) {
+			sz = 0x40;
+			iocmd.size = sz;
+		}
+
 		/* Another GEM workaround. Check peripheral device type,
 		 * if PROCESSOR, quit DV.
 		 */
@@ -6140,6 +6250,28 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int por
 		if (mptscsih_do_cmd(hd, &iocmd) < 0)
 			goto target_done;
 
+		if (sz == 0x40) {
+			if ((pTarget->maxWidth == 1) && (pTarget->maxOffset) && (nfactor < 0x0A)
+				&& (pTarget->minSyncFactor > 0x09)) {
+				if ((pbuf1[56] & 0x04) == 0)
+					;
+				else if ((pbuf1[56] & 0x01) == 1) {
+					pTarget->minSyncFactor =
+					    nfactor > MPT_ULTRA320 ? nfactor : MPT_ULTRA320;
+				} else {
+					pTarget->minSyncFactor =
+					    nfactor > MPT_ULTRA160 ? nfactor : MPT_ULTRA160;
+				}
+
+				dv.max.factor = pTarget->minSyncFactor;
+
+				if ((pbuf1[56] & 0x02) == 0) {
+					pTarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+					hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
+				}
+			}
+		}
+
 		if (doFallback)
 			dv.cmd = MPT_FALLBACK;
 		else
@@ -6223,7 +6355,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int por
 			firstPass = 0;
 		}
 	}
-	ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test completed OK.\n", ioc->name));
+	ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test on id=%d completed OK.\n", ioc->name, id));
 	inq0 = (*pbuf1) & 0x1F;
 
 	/* Continue only for disks
@@ -6231,6 +6363,9 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int por
 	if (inq0 != 0)
 		goto target_done;
 
+	if ( ioc->spi_data.PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY )
+		goto target_done;
+
 	/* Start the Enhanced Test.
 	 * 0) issue TUR to clear out check conditions
 	 * 1) read capacity of echo (regular) buffer
@@ -6671,8 +6806,8 @@ target_done:
 	if (pDvBuf)
 		pci_free_consistent(ioc->pcidev, dv_alloc, pDvBuf, dvbuf_dma);
 
-	ddvtprintk((MYIOC_s_INFO_FMT "DV Done. IOs outstanding = %d\n",
-			ioc->name, atomic_read(&queue_depth)));
+	ddvtprintk((MYIOC_s_INFO_FMT "DV Done.\n",
+			ioc->name));
 
 	return retcode;
 }
@@ -6687,9 +6822,9 @@ target_done:
 static void
 mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
 {
-	VirtDevice		*pTarget = NULL;
-	SCSIDevicePage0_t	*pPage0 = NULL;
-	SCSIDevicePage1_t	*pPage1 = NULL;
+	VirtDevice		*pTarget;
+	SCSIDevicePage0_t	*pPage0;
+	SCSIDevicePage1_t	*pPage1;
 	int			val = 0, data, configuration;
 	u8			width = 0;
 	u8			offset = 0;
@@ -6841,7 +6976,6 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVP
 				factor = MPT_ULTRA;
 				width = MPT_WIDE;
 			} else if ((factor == MPT_ULTRA) && width) {
-				factor = MPT_ULTRA;
 				width = MPT_NARROW;
 			} else if (factor < MPT_FAST) {
 				factor = MPT_FAST;
@@ -7072,9 +7206,9 @@ mptscsih_fillbuf(char *buffer, int size,
 /* Commandline Parsing routines and defines.
  *
  * insmod format:
- *	insmod mptscsih mptscsih="width:1 dv:n factor:0x09"
+ *	insmod mptscsih mptscsih="width:1 dv:n factor:0x09 saf-te:1"
  *  boot format:
- *	mptscsih=width:1,dv:n,factor:0x8
+ *	mptscsih=width:1,dv:n,factor:0x8,saf-te:1
  *
  */
 #ifdef MODULE
@@ -7087,11 +7221,13 @@ static char setup_token[] __initdata =
 	"dv:"
 	"width:"
 	"factor:"
-       ;	/* DONNOT REMOVE THIS ';' */
+	"saf-te:"
+       ;	/* DO NOT REMOVE THIS ';' */
 
 #define OPT_DV			1
 #define OPT_MAX_WIDTH		2
 #define OPT_MIN_SYNC_FACTOR	3
+#define OPT_SAF_TE		4
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static int
@@ -7148,6 +7284,10 @@ mptscsih_setup(char *str)
 			driver_setup.min_sync_fac = val;
 			break;
 
+		case OPT_SAF_TE:
+			driver_setup.saf_te = val;
+			break;
+
 		default:
 			printk("mptscsih_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
 			break;
--- diff/drivers/message/fusion/mptscsih.h	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/message/fusion/mptscsih.h	2004-03-16 09:37:56.017024288 +0000
@@ -15,7 +15,7 @@
  *
  *      (see also mptbase.c)
  *
- *  Copyright (c) 1999-2003 LSI Logic Corporation
+ *  Copyright (c) 1999-2004 LSI Logic Corporation
  *  Originally By: Steven J. Ralston
  *  (mailto:netscape.net)
  *  (mailto:mpt_linux_developer@lsil.com)
@@ -70,11 +70,7 @@
  *	Try to keep these at 2^N-1
  */
 #define MPT_FC_CAN_QUEUE	127
-#if defined MPT_SCSI_USE_NEW_EH
-	#define MPT_SCSI_CAN_QUEUE	127
-#else
-	#define MPT_SCSI_CAN_QUEUE	63
-#endif
+#define MPT_SCSI_CAN_QUEUE	127
 
 #define MPT_SCSI_CMD_PER_DEV_HIGH	31
 #define MPT_SCSI_CMD_PER_DEV_LOW	7
@@ -98,7 +94,7 @@
 #define MPT_SCSI_SG_DEPTH	40
 #endif
 
-/* To disable domain validation, comment the
+/* To disable domain validation, uncomment the
  * following line. No effect for FC devices.
  * For SCSI devices, driver will negotiate to
  * NVRAM settings (if available) or to maximum adapter
@@ -114,12 +110,14 @@
 #define MPTSCSIH_DOMAIN_VALIDATION      1
 #define MPTSCSIH_MAX_WIDTH              1
 #define MPTSCSIH_MIN_SYNC               0x08
+#define MPTSCSIH_SAF_TE                 0
 
 struct mptscsih_driver_setup
 {
         u8      dv;
         u8      max_width;
         u8      min_sync_fac;
+        u8      saf_te;
 };
 
 
@@ -128,6 +126,7 @@ struct mptscsih_driver_setup
         MPTSCSIH_DOMAIN_VALIDATION,             \
         MPTSCSIH_MAX_WIDTH,                     \
         MPTSCSIH_MIN_SYNC,                      \
+        MPTSCSIH_SAF_TE,                        \
 }
 
 
--- diff/drivers/message/fusion/scsi3.h	2004-01-19 10:22:57.000000000 +0000
+++ source/drivers/message/fusion/scsi3.h	2004-03-16 09:37:56.018024136 +0000
@@ -4,7 +4,7 @@
  *      (Ultimately) SCSI-3 definitions; for now, inheriting
  *      SCSI-2 definitions.
  *
- *  Copyright (c) 1996-2003 Steven J. Ralston
+ *  Copyright (c) 1996-2004 Steven J. Ralston
  *  Written By: Steven J. Ralston (19960517)
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:mpt_linux_developer@lsil.com)
--- diff/drivers/message/i2o/i2o_core.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/message/i2o/i2o_core.c	2004-03-16 09:37:56.020023832 +0000
@@ -1179,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
--- diff/drivers/mtd/devices/blkmtd.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/mtd/devices/blkmtd.c	2004-03-16 09:37:56.047019728 +0000
@@ -147,8 +147,7 @@ static int blkmtd_readpage(struct blkmtd
 		bio->bi_private = &event;
 		bio->bi_end_io = bi_read_complete;
 		if(bio_add_page(bio, page, PAGE_SIZE, 0) == PAGE_SIZE) {
-			submit_bio(READ, bio);
-			blk_run_queues();
+			submit_bio(READ_SYNC, bio);
 			wait_for_completion(&event);
 			err = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : -EIO;
 			bio_put(bio);
@@ -179,8 +178,7 @@ static int blkmtd_write_out(struct bio *
 	init_completion(&event);
 	bio->bi_private = &event;
 	bio->bi_end_io = bi_write_complete;
-	submit_bio(WRITE, bio);
-	blk_run_queues();
+	submit_bio(WRITE_SYNC, bio);
 	wait_for_completion(&event);
 	DEBUG(3, "submit_bio completed, bi_vcnt = %d\n", bio->bi_vcnt);
 	err = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : -EIO;
@@ -664,12 +662,12 @@ static struct blkmtd_dev *add_device(cha
 	}
 
 	memset(dev, 0, sizeof(struct blkmtd_dev));
+	dev->blkdev = bdev;
 	atomic_set(&(dev->blkdev->bd_inode->i_mapping->truncate_count), 0);
 	if(!readonly) {
 		init_MUTEX(&dev->wrbuf_mutex);
 	}
 
-	dev->blkdev = bdev;
 	dev->mtd_info.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
 
 	/* Setup the MTD structure */
--- diff/drivers/net/3c501.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/3c501.c	2004-03-16 09:37:56.048019576 +0000
@@ -306,7 +306,7 @@ static int __init el1_probe1(struct net_
 		printk(KERN_DEBUG "%s", version);
 
 	memset(dev->priv, 0, sizeof(struct net_local));
-	lp=dev->priv;
+	lp = netdev_priv(dev);
 	spin_lock_init(&lp->lock);
 	
 	/*
@@ -341,7 +341,7 @@ static int el_open(struct net_device *de
 {
 	int retval;
 	int ioaddr = dev->base_addr;
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned long flags;
 
 	if (el_debug > 2)
@@ -371,7 +371,7 @@ static int el_open(struct net_device *de
  
 static void el_timeout(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
  
 	if (el_debug)
@@ -411,7 +411,7 @@ static void el_timeout(struct net_device
 
 static int el_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	unsigned long flags;
 
@@ -524,7 +524,7 @@ static irqreturn_t el_interrupt(int irq,
 	int axsr;			/* Aux. status reg. */
 
 	ioaddr = dev->base_addr;
-	lp = (struct net_local *)dev->priv;
+	lp = netdev_priv(dev);
 
 	spin_lock(&lp->lock);
 	
@@ -698,7 +698,7 @@ out:
 
 static void el_receive(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	int pkt_len;
 	struct sk_buff *skb;
@@ -764,7 +764,7 @@ static void el_receive(struct net_device
 
 static void  el_reset(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	if (el_debug> 2)
@@ -828,7 +828,7 @@ static int el1_close(struct net_device *
  
 static struct net_device_stats *el1_get_stats(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	return &lp->stats;
 }
 
--- diff/drivers/net/3c503.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/3c503.c	2004-03-16 09:37:56.049019424 +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/3c507.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/3c507.c	2004-03-16 09:37:56.050019272 +0000
@@ -441,7 +441,7 @@ static int __init el16_probe1(struct net
 	if (net_debug)
 		printk(version);
 
-	lp = dev->priv;
+	lp = netdev_priv(dev);
  	memset(lp, 0, sizeof(*lp));
 	spin_lock_init(&lp->lock);
 
@@ -471,7 +471,7 @@ static int el16_open(struct net_device *
 
 static void el16_tx_timeout (struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *) dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	unsigned long shmem = dev->mem_start;
 
@@ -501,7 +501,7 @@ static void el16_tx_timeout (struct net_
 
 static int el16_send_packet (struct sk_buff *skb, struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *) dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	unsigned long flags;
 	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
@@ -546,7 +546,7 @@ static irqreturn_t el16_interrupt(int ir
 	}
 
 	ioaddr = dev->base_addr;
-	lp = (struct net_local *)dev->priv;
+	lp = netdev_priv(dev);
 	shmem = dev->mem_start;
 
 	spin_lock(&lp->lock);
@@ -660,7 +660,7 @@ static int el16_close(struct net_device 
    closed. */
 static struct net_device_stats *el16_get_stats(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	/* ToDo: decide if there are any useful statistics from the SCB. */
 
@@ -670,7 +670,7 @@ static struct net_device_stats *el16_get
 /* Initialize the Rx-block list. */
 static void init_rx_bufs(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned long write_ptr;
 	unsigned short SCB_base = SCB_BASE;
 
@@ -713,7 +713,7 @@ static void init_rx_bufs(struct net_devi
 
 static void init_82586_mem(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	short ioaddr = dev->base_addr;
 	unsigned long shmem = dev->mem_start;
 
@@ -771,7 +771,7 @@ static void init_82586_mem(struct net_de
 
 static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	short ioaddr = dev->base_addr;
 	ushort tx_block = lp->tx_head;
 	unsigned long write_ptr = dev->mem_start + tx_block;
@@ -820,7 +820,7 @@ static void hardware_send_packet(struct 
 
 static void el16_rx(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned long shmem = dev->mem_start;
 	ushort rx_head = lp->rx_head;
 	ushort rx_tail = lp->rx_tail;
--- diff/drivers/net/3c509.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/net/3c509.c	2004-03-16 09:37:56.052018968 +0000
@@ -304,7 +304,7 @@ static int nopnp;
 
 static int __init el3_common_init(struct net_device *dev)
 {
-	struct el3_private *lp = dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	short i;
 	int err;
 
@@ -355,7 +355,7 @@ static int __init el3_common_init(struct
 
 static void el3_common_remove (struct net_device *dev)
 {
-		struct el3_private *lp = dev->priv;
+		struct el3_private *lp = netdev_priv(dev);
 
 		(void) lp;				/* Keep gcc quiet... */
 #ifdef CONFIG_PM
@@ -575,7 +575,7 @@ no_pnp:
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 	dev->if_port = if_port;
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 #if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
 	lp->dev = &idev->dev;
 #endif
@@ -671,7 +671,7 @@ static int __init el3_mca_probe(struct d
 		dev->base_addr = ioaddr;
 		dev->irq = irq;
 		dev->if_port = if_port;
-		lp = dev->priv;
+		lp = netdev_priv(dev);
 		lp->dev = device;
 		lp->type = EL3_MCA;
 		device->driver_data = dev;
@@ -732,7 +732,7 @@ static int __init el3_eisa_probe (struct
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 	dev->if_port = if_port;
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 	lp->dev = device;
 	lp->type = EL3_EISA;
 	eisa_set_drvdata (edev, dev);
@@ -829,7 +829,7 @@ el3_open(struct net_device *dev)
 static void
 el3_tx_timeout (struct net_device *dev)
 {
-	struct el3_private *lp = (struct el3_private *)dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	/* Transmitter timeout, serious problems. */
@@ -849,7 +849,7 @@ el3_tx_timeout (struct net_device *dev)
 static int
 el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct el3_private *lp = (struct el3_private *)dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	unsigned long flags;
 
@@ -943,7 +943,7 @@ el3_interrupt(int irq, void *dev_id, str
 		return IRQ_NONE;
 	}
 
-	lp = (struct el3_private *)dev->priv;
+	lp = netdev_priv(dev);
 	spin_lock(&lp->lock);
 
 	ioaddr = dev->base_addr;
@@ -975,7 +975,7 @@ el3_interrupt(int irq, void *dev_id, str
 				outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
 			}
 			if (status & TxComplete) {			/* Really Tx error. */
-				struct el3_private *lp = (struct el3_private *)dev->priv;
+				struct el3_private *lp = netdev_priv(dev);
 				short tx_status;
 				int i = 4;
 
@@ -1022,7 +1022,7 @@ el3_interrupt(int irq, void *dev_id, str
 static struct net_device_stats *
 el3_get_stats(struct net_device *dev)
 {
-	struct el3_private *lp = (struct el3_private *)dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	unsigned long flags;
 
 	/*
@@ -1043,7 +1043,7 @@ el3_get_stats(struct net_device *dev)
 	*/
 static void update_stats(struct net_device *dev)
 {
-	struct el3_private *lp = (struct el3_private *)dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	if (el3_debug > 5)
@@ -1073,7 +1073,7 @@ static void update_stats(struct net_devi
 static int
 el3_rx(struct net_device *dev)
 {
-	struct el3_private *lp = (struct el3_private *)dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	short rx_status;
 
@@ -1145,7 +1145,7 @@ static void
 set_multicast_list(struct net_device *dev)
 {
 	unsigned long flags;
-	struct el3_private *lp = (struct el3_private *)dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	if (el3_debug > 1) {
@@ -1172,7 +1172,7 @@ static int
 el3_close(struct net_device *dev)
 {
 	int ioaddr = dev->base_addr;
-	struct el3_private *lp = (struct el3_private *)dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	
 	if (el3_debug > 2)
 		printk("%s: Shutting down ethercard.\n", dev->name);
@@ -1317,7 +1317,7 @@ static int
 netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
 {
 	u32 ethcmd;
-	struct el3_private *lp = dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 
 	/* dev_ioctl() in ../../net/core/dev.c has already checked
 	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
@@ -1558,7 +1558,7 @@ el3_suspend(struct pm_dev *pdev)
 		return -EINVAL;
 
 	dev = (struct net_device *)pdev->data;
-	lp = (struct el3_private *)dev->priv;
+	lp = netdev_priv(dev);
 	ioaddr = dev->base_addr;
 
 	spin_lock_irqsave(&lp->lock, flags);
@@ -1585,7 +1585,7 @@ el3_resume(struct pm_dev *pdev)
 		return -EINVAL;
 
 	dev = (struct net_device *)pdev->data;
-	lp = (struct el3_private *)dev->priv;
+	lp = netdev_priv(dev);
 	ioaddr = dev->base_addr;
 
 	spin_lock_irqsave(&lp->lock, flags);
--- diff/drivers/net/3c527.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/3c527.c	2004-03-16 09:37:56.054018664 +0000
@@ -226,7 +226,7 @@ static struct ethtool_ops netdev_ethtool
 
 static void cleanup_card(struct net_device *dev)
 {
-	struct mc32_local *lp=dev->priv;
+	struct mc32_local *lp = netdev_priv(dev);
 	unsigned slot = lp->slot;
 	mca_mark_as_unused(slot);
 	mca_set_adapter_name(slot, NULL);
@@ -307,7 +307,7 @@ static int __init mc32_probe1(struct net
 	int i, err;
 	u8 POS;
 	u32 base;
-	struct mc32_local *lp = dev->priv;
+	struct mc32_local *lp = netdev_priv(dev);
 	static u16 mca_io_bases[]={
 		0x7280,0x7290,
 		0x7680,0x7690,
@@ -573,7 +573,7 @@ static inline void mc32_ready_poll(struc
 
 static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int len)
 {
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	struct mc32_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	int ret = -1;
 
@@ -619,7 +619,7 @@ static int mc32_command_nowait(struct ne
   
 static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len)
 {
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	struct mc32_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	int ret = 0;
 	
@@ -671,7 +671,7 @@ static int mc32_command(struct net_devic
 
 static void mc32_start_transceiver(struct net_device *dev) {
 
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	struct mc32_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	/* Ignore RX overflow on device closure */ 
@@ -706,7 +706,7 @@ static void mc32_start_transceiver(struc
 
 static void mc32_halt_transceiver(struct net_device *dev) 
 {
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	struct mc32_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	mc32_ready_poll(dev);	
@@ -743,7 +743,7 @@ static void mc32_halt_transceiver(struct
 	 
 static int mc32_load_rx_ring(struct net_device *dev)
 {
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	struct mc32_local *lp = netdev_priv(dev);
 	int i;
 	u16 rx_base;
 	volatile struct skb_header *p;
@@ -792,7 +792,7 @@ static int mc32_load_rx_ring(struct net_
 
 static void mc32_flush_rx_ring(struct net_device *dev)
 {
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	struct mc32_local *lp = netdev_priv(dev);
 	int i; 
 
 	for(i=0; i < RX_RING_LEN; i++) 
@@ -824,7 +824,7 @@ static void mc32_flush_rx_ring(struct ne
 
 static void mc32_load_tx_ring(struct net_device *dev)
 { 
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	struct mc32_local *lp = netdev_priv(dev);
 	volatile struct skb_header *p;
 	int i; 
 	u16 tx_base;
@@ -861,7 +861,7 @@ static void mc32_load_tx_ring(struct net
 
 static void mc32_flush_tx_ring(struct net_device *dev)
 {
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	struct mc32_local *lp = netdev_priv(dev);
 	int i;
 
 	for (i=0; i < TX_RING_LEN; i++)
@@ -899,7 +899,7 @@ static void mc32_flush_tx_ring(struct ne
 static int mc32_open(struct net_device *dev)
 {
 	int ioaddr = dev->base_addr;
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	struct mc32_local *lp = netdev_priv(dev);
 	u8 one=1;
 	u8 regs;
 	u16 descnumbuffs[2] = {TX_RING_LEN, RX_RING_LEN};
@@ -1022,7 +1022,7 @@ static void mc32_timeout(struct net_devi
 
 static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	struct mc32_local *lp = netdev_priv(dev);
 	u32 head = atomic_read(&lp->tx_ring_head);
 	
 	volatile struct skb_header *p, *np;
@@ -1092,7 +1092,7 @@ static int mc32_send_packet(struct sk_bu
 
 static void mc32_update_stats(struct net_device *dev)
 {
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	struct mc32_local *lp = netdev_priv(dev);
 	volatile struct mc32_stats *st = lp->stats; 
 
 	u32 rx_errors=0; 
@@ -1143,7 +1143,7 @@ static void mc32_update_stats(struct net
 
 static void mc32_rx_ring(struct net_device *dev)
 {
-	struct mc32_local *lp=dev->priv;		
+	struct mc32_local *lp = netdev_priv(dev);
 	volatile struct skb_header *p;
 	u16 rx_ring_tail;
 	u16 rx_old_tail;
@@ -1236,7 +1236,7 @@ static void mc32_rx_ring(struct net_devi
 
 static void mc32_tx_ring(struct net_device *dev) 
 {
-	struct mc32_local *lp=(struct mc32_local *)dev->priv;
+	struct mc32_local *lp = netdev_priv(dev);
 	volatile struct skb_header *np;
 
 	/*
@@ -1333,7 +1333,7 @@ static irqreturn_t mc32_interrupt(int ir
 	}
  
 	ioaddr = dev->base_addr;
-	lp = (struct mc32_local *)dev->priv;
+	lp = netdev_priv(dev);
 
 	/* See whats cooking */
 
@@ -1450,7 +1450,7 @@ static irqreturn_t mc32_interrupt(int ir
 
 static int mc32_close(struct net_device *dev)
 {
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	struct mc32_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	u8 regs;
@@ -1499,7 +1499,7 @@ static int mc32_close(struct net_device 
 
 static struct net_device_stats *mc32_get_stats(struct net_device *dev)
 {
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	struct mc32_local *lp = netdev_priv(dev);
 	
 	mc32_update_stats(dev); 
 	return &lp->net_stats;
@@ -1531,7 +1531,7 @@ static struct net_device_stats *mc32_get
 
 static void do_mc32_set_multicast_list(struct net_device *dev, int retry)
 {
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	struct mc32_local *lp = netdev_priv(dev);
 	u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */ 
 
 	if (dev->flags&IFF_PROMISC)
--- diff/drivers/net/3c59x.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/net/3c59x.c	2004-03-16 09:37:56.064017144 +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)
@@ -1013,7 +1025,7 @@ static int vortex_eisa_remove (struct de
 		BUG();
 	}
 
-	vp = dev->priv;
+	vp = netdev_priv(dev);
 	ioaddr = dev->base_addr;
 	
 	unregister_netdev (dev);
@@ -1115,7 +1127,7 @@ static int __devinit vortex_probe1(struc
 	}
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, gendev);
-	vp = dev->priv;
+	vp = netdev_priv(dev);
 
 	option = global_options;
 
@@ -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);
@@ -1516,7 +1531,7 @@ static void
 vortex_up(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 	unsigned int config;
 	int i;
 
@@ -1714,7 +1729,7 @@ vortex_up(struct net_device *dev)
 static int
 vortex_open(struct net_device *dev)
 {
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 	int i;
 	int retval;
 
@@ -1772,7 +1787,7 @@ static void
 vortex_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int next_tick = 60*HZ;
 	int ok = 0;
@@ -1898,7 +1913,7 @@ leave_media_alone:
 
 static void vortex_tx_timeout(struct net_device *dev)
 {
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
@@ -1968,7 +1983,7 @@ static void vortex_tx_timeout(struct net
 static void
 vortex_error(struct net_device *dev, int status)
 {
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int do_tx_reset = 0, reset_mask = 0;
 	unsigned char tx_status = 0;
@@ -2070,7 +2085,7 @@ vortex_error(struct net_device *dev, int
 static int
 vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	/* Put out the doubleword header... */
@@ -2125,7 +2140,7 @@ vortex_start_xmit(struct sk_buff *skb, s
 static int
 boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	/* Calculate the next Tx descriptor entry. */
 	int entry = vp->cur_tx % TX_RING_SIZE;
@@ -2225,7 +2240,7 @@ static irqreturn_t
 vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_id;
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 	long ioaddr;
 	int status;
 	int work_done = max_interrupt_work;
@@ -2330,7 +2345,7 @@ static irqreturn_t
 boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_id;
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 	long ioaddr;
 	int status;
 	int work_done = max_interrupt_work;
@@ -2455,7 +2470,7 @@ handler_exit:
 
 static int vortex_rx(struct net_device *dev)
 {
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int i;
 	short rx_status;
@@ -2525,7 +2540,7 @@ static int vortex_rx(struct net_device *
 static int
 boomerang_rx(struct net_device *dev)
 {
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 	int entry = vp->cur_rx % RX_RING_SIZE;
 	long ioaddr = dev->base_addr;
 	int rx_status;
@@ -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. */
@@ -2627,7 +2643,7 @@ static void
 rx_oom_timer(unsigned long arg)
 {
 	struct net_device *dev = (struct net_device *)arg;
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 
 	spin_lock_irq(&vp->lock);
 	if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE)	/* This test is redundant, but makes me feel good */
@@ -2642,7 +2658,7 @@ rx_oom_timer(unsigned long arg)
 static void
 vortex_down(struct net_device *dev)
 {
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	netif_stop_queue (dev);
@@ -2678,7 +2694,7 @@ vortex_down(struct net_device *dev)
 static int
 vortex_close(struct net_device *dev)
 {
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int i;
 
@@ -2740,7 +2756,7 @@ static void
 dump_tx_ring(struct net_device *dev)
 {
 	if (vortex_debug > 0) {
-		struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 		long ioaddr = dev->base_addr;
 		
 		if (vp->full_bus_master_tx) {
@@ -2773,7 +2789,7 @@ dump_tx_ring(struct net_device *dev)
 
 static struct net_device_stats *vortex_get_stats(struct net_device *dev)
 {
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 	unsigned long flags;
 
 	if (netif_device_present(dev)) {	/* AKPM: Used to be netif_running */
@@ -2793,7 +2809,7 @@ static struct net_device_stats *vortex_g
 	*/
 static void update_stats(long ioaddr, struct net_device *dev)
 {
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 	int old_window = inw(ioaddr + EL3_CMD);
 
 	if (old_window == 0xffff)	/* Chip suspended or ejected. */
@@ -2834,7 +2850,7 @@ static void update_stats(long ioaddr, st
 static void vortex_get_drvinfo(struct net_device *dev,
 					struct ethtool_drvinfo *info)
 {
-	struct vortex_private *vp = dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 
 	strcpy(info->driver, DRV_NAME);
 	strcpy(info->version, DRV_VERSION);
@@ -2855,7 +2871,7 @@ static struct ethtool_ops vortex_ethtool
 
 static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
 	int phy = vp->phys[0] & 0x1f;
@@ -2942,7 +2958,7 @@ static void mdio_sync(long ioaddr, int b
 
 static int mdio_read(struct net_device *dev, int phy_id, int location)
 {
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 	int i;
 	long ioaddr = dev->base_addr;
 	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
@@ -2976,7 +2992,7 @@ static int mdio_read(struct net_device *
 
 static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
 {
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
 	long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
@@ -3010,7 +3026,7 @@ static void mdio_write(struct net_device
 /* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */
 static void acpi_set_WOL(struct net_device *dev)
 {
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	struct vortex_private *vp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	/* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
@@ -3036,7 +3052,7 @@ static void __devexit vortex_remove_one 
 		BUG();
 	}
 
-	vp = dev->priv;
+	vp = netdev_priv(dev);
 
 	/* AKPM: FIXME: we should have
 	 *	if (vp->cb_fn_base) iounmap(vp->cb_fn_base);
--- diff/drivers/net/7990.c	2003-05-21 10:50:15.000000000 +0000
+++ source/drivers/net/7990.c	2004-03-16 09:37:56.065016992 +0000
@@ -99,7 +99,7 @@ static void load_csrs (struct lance_priv
 /* Set up the Lance Rx and Tx rings and the init block */
 static void lance_init_ring (struct net_device *dev)
 {
-        struct lance_private *lp = (struct lance_private *) dev->priv;
+        struct lance_private *lp = netdev_priv(dev);
         volatile struct lance_init_block *ib = lp->init_block;
         volatile struct lance_init_block *aib; /* for LANCE_ADDR computations */
         int leptr;
@@ -216,7 +216,7 @@ static int init_restart_lance (struct la
 
 static int lance_reset (struct net_device *dev)
 {
-        struct lance_private *lp = (struct lance_private *)dev->priv;
+        struct lance_private *lp = netdev_priv(dev);
         int status;
         DECLARE_LL;
     
@@ -236,7 +236,7 @@ static int lance_reset (struct net_devic
 
 static int lance_rx (struct net_device *dev)
 {
-        struct lance_private *lp = (struct lance_private *) dev->priv;
+        struct lance_private *lp = netdev_priv(dev);
         volatile struct lance_init_block *ib = lp->init_block;
         volatile struct lance_rx_desc *rd;
         unsigned char bits;
@@ -316,7 +316,7 @@ static int lance_rx (struct net_device *
 
 static int lance_tx (struct net_device *dev)
 {
-        struct lance_private *lp = (struct lance_private *) dev->priv;
+        struct lance_private *lp = netdev_priv(dev);
         volatile struct lance_init_block *ib = lp->init_block;
         volatile struct lance_tx_desc *td;
         int i, j;
@@ -401,7 +401,7 @@ static irqreturn_t
 lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
 {
         struct net_device *dev = (struct net_device *)dev_id;
-        struct lance_private *lp = (struct lance_private *)dev->priv;
+        struct lance_private *lp = netdev_priv(dev);
         int csr0;
         DECLARE_LL;
 
@@ -457,7 +457,7 @@ lance_interrupt (int irq, void *dev_id, 
 
 int lance_open (struct net_device *dev)
 {
-        struct lance_private *lp = (struct lance_private *)dev->priv;
+        struct lance_private *lp = netdev_priv(dev);
 	int res;
         DECLARE_LL;
         
@@ -474,7 +474,7 @@ int lance_open (struct net_device *dev)
 
 int lance_close (struct net_device *dev)
 {
-        struct lance_private *lp = (struct lance_private *) dev->priv;
+        struct lance_private *lp = netdev_priv(dev);
         DECLARE_LL;
         
 	netif_stop_queue (dev);
@@ -499,7 +499,7 @@ void lance_tx_timeout(struct net_device 
 
 int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
 {
-        struct lance_private *lp = (struct lance_private *)dev->priv;
+        struct lance_private *lp = netdev_priv(dev);
         volatile struct lance_init_block *ib = lp->init_block;
         int entry, skblen, len;
         static int outs;
@@ -556,7 +556,7 @@ int lance_start_xmit (struct sk_buff *sk
 
 struct net_device_stats *lance_get_stats (struct net_device *dev)
 {
-        struct lance_private *lp = (struct lance_private *) dev->priv;
+        struct lance_private *lp = netdev_priv(dev);
 
         return &lp->stats;
 }
@@ -564,7 +564,7 @@ struct net_device_stats *lance_get_stats
 /* taken from the depca driver via a2065.c */
 static void lance_load_multicast (struct net_device *dev)
 {
-        struct lance_private *lp = (struct lance_private *) dev->priv;
+        struct lance_private *lp = netdev_priv(dev);
         volatile struct lance_init_block *ib = lp->init_block;
         volatile u16 *mcast_table = (u16 *)&ib->filter;
         struct dev_mc_list *dmi=dev->mc_list;
@@ -601,7 +601,7 @@ static void lance_load_multicast (struct
 
 void lance_set_multicast (struct net_device *dev)
 {
-        struct lance_private *lp = (struct lance_private *) dev->priv;
+        struct lance_private *lp = netdev_priv(dev);
         volatile struct lance_init_block *ib = lp->init_block;
 	int stopped;
         DECLARE_LL;
--- diff/drivers/net/8139too.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/8139too.c	2004-03-16 09:37:56.067016688 +0000
@@ -968,12 +968,11 @@ static int __devinit rtl8139_init_one (s
 	if (i < 0)
 		return i;
 
+	assert (dev != NULL);
 	tp = dev->priv;
+	assert (tp != NULL);
 	ioaddr = tp->mmio_addr;
-
 	assert (ioaddr != NULL);
-	assert (dev != NULL);
-	assert (tp != NULL);
 
 	addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6;
 	for (i = 0; i < 3; i++)
--- diff/drivers/net/82596.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/82596.c	2004-03-16 09:37:56.068016536 +0000
@@ -458,7 +458,7 @@ static inline int wait_cfg(struct net_de
  
 static void i596_display_data(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	struct i596_cmd *cmd;
 	struct i596_rfd *rfd;
 	struct i596_rbd *rbd;
@@ -528,7 +528,7 @@ static irqreturn_t i596_error(int irq, v
 
 static inline void init_rx_bufs(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *)dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	int i;
 	struct i596_rfd *rfd;
 	struct i596_rbd *rbd;
@@ -579,7 +579,7 @@ static inline void init_rx_bufs(struct n
 
 static inline void remove_rx_bufs(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *)dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	struct i596_rbd *rbd;
 	int i;
 
@@ -593,7 +593,7 @@ static inline void remove_rx_bufs(struct
 
 static void rebuild_rx_bufs(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	int i;
 
 	/* Ensure rx frame/buffer descriptors are tidy */
@@ -612,7 +612,7 @@ static void rebuild_rx_bufs(struct net_d
 
 static int init_i596_mem(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 #if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET)
 	short ioaddr = dev->base_addr;
 #endif
@@ -765,7 +765,7 @@ failed:
 
 static inline int i596_rx(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *)dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	struct i596_rfd *rfd;
 	struct i596_rbd *rbd;
 	int frames = 0;
@@ -960,7 +960,7 @@ static inline void i596_reset(struct net
 
 static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	unsigned long flags;
 
@@ -1030,7 +1030,7 @@ static int i596_open(struct net_device *
 
 static void i596_tx_timeout (struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	/* Transmitter timeout, serious problems. */
@@ -1059,7 +1059,7 @@ static void i596_tx_timeout (struct net_
 
 static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	struct tx_cmd *tx_cmd;
 	struct i596_tbd *tbd;
 	short length = skb->len;
@@ -1245,7 +1245,7 @@ struct net_device * __init i82596_probe(
 
 	dev->priv = (void *)(dev->mem_start);
 
-	lp = (struct i596_private *) dev->priv;
+	lp = netdev_priv(dev);
 	DEB(DEB_INIT,printk(KERN_DEBUG "%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n",
 			dev->name, (unsigned long)lp,
 			sizeof(struct i596_private), (unsigned long)&lp->scb));
@@ -1305,7 +1305,7 @@ static irqreturn_t i596_interrupt(int ir
 	}
 
 	ioaddr = dev->base_addr;
-	lp = (struct i596_private *) dev->priv;
+	lp = netdev_priv(dev);
 
 	spin_lock (&lp->lock);
 
@@ -1448,7 +1448,7 @@ static irqreturn_t i596_interrupt(int ir
 
 static int i596_close(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	unsigned long flags;
 
 	netif_stop_queue(dev);
@@ -1495,7 +1495,7 @@ static int i596_close(struct net_device 
 static struct net_device_stats *
  i596_get_stats(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 
 	return &lp->stats;
 }
@@ -1506,7 +1506,7 @@ static struct net_device_stats *
 
 static void set_multicast_list(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	int config = 0, cnt;
 
 	DEB(DEB_MULTI,printk(KERN_DEBUG "%s: set multicast list, %d entries, promisc %s, allmulti %s\n",
--- diff/drivers/net/8390.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/net/8390.c	2004-03-16 09:37:56.069016384 +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-16 09:37:56.070016232 +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-11 10:20:25.000000000 +0000
+++ source/drivers/net/Kconfig	2004-03-16 09:37:56.071016080 +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-11 10:20:25.000000000 +0000
+++ source/drivers/net/Makefile	2004-03-16 09:37:56.072015928 +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/a2065.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/net/a2065.c	2004-03-16 09:37:56.073015776 +0000
@@ -164,7 +164,7 @@ static void load_csrs (struct lance_priv
 /* Setup the Lance Rx and Tx rings */
 static void lance_init_ring (struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_init_block *ib = lp->init_block;
 	volatile struct lance_init_block *aib; /* for LANCE_ADDR computations */
 	int leptr;
@@ -265,7 +265,7 @@ static int init_restart_lance (struct la
 
 static int lance_rx (struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_init_block *ib = lp->init_block;
 	volatile struct lance_regs *ll = lp->ll;
 	volatile struct lance_rx_desc *rd;
@@ -342,7 +342,7 @@ static int lance_rx (struct net_device *
 
 static int lance_tx (struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_init_block *ib = lp->init_block;
 	volatile struct lance_regs *ll = lp->ll;
 	volatile struct lance_tx_desc *td;
@@ -433,7 +433,7 @@ lance_interrupt (int irq, void *dev_id, 
 
 	dev = (struct net_device *) dev_id;
 
-	lp = (struct lance_private *) dev->priv;
+	lp = netdev_priv(dev);
 	ll = lp->ll;
 
 	ll->rap = LE_CSR0;		/* LANCE Controller Status */
@@ -481,7 +481,7 @@ struct net_device *last_dev = 0;
 
 static int lance_open (struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_regs *ll = lp->ll;
 	int ret;
 
@@ -506,7 +506,7 @@ static int lance_open (struct net_device
 
 static int lance_close (struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_regs *ll = lp->ll;
 
 	netif_stop_queue(dev);
@@ -522,7 +522,7 @@ static int lance_close (struct net_devic
 
 static inline int lance_reset (struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_regs *ll = lp->ll;
 	int status;
     
@@ -545,7 +545,7 @@ static inline int lance_reset (struct ne
 
 static void lance_tx_timeout(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_regs *ll = lp->ll;
 
 	printk(KERN_ERR "%s: transmit timed out, status %04x, reset\n",
@@ -556,7 +556,7 @@ static void lance_tx_timeout(struct net_
 
 static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_regs *ll = lp->ll;
 	volatile struct lance_init_block *ib = lp->init_block;
 	int entry, skblen, len;
@@ -624,7 +624,7 @@ static int lance_start_xmit (struct sk_b
 
 static struct net_device_stats *lance_get_stats (struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 
 	return &lp->stats;
 }
@@ -632,7 +632,7 @@ static struct net_device_stats *lance_ge
 /* taken from the depca driver */
 static void lance_load_multicast (struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_init_block *ib = lp->init_block;
 	volatile u16 *mcast_table = (u16 *)&ib->filter;
 	struct dev_mc_list *dmi=dev->mc_list;
@@ -668,7 +668,7 @@ static void lance_load_multicast (struct
 
 static void lance_set_multicast (struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_init_block *ib = lp->init_block;
 	volatile struct lance_regs *ll = lp->ll;
 
@@ -748,7 +748,7 @@ static int __devinit a2065_init_one(stru
 	}
 
 	SET_MODULE_OWNER(dev);
-	priv = dev->priv;
+	priv = netdev_priv(dev);
 
 	r1->name = dev->name;
 	r2->name = dev->name;
--- diff/drivers/net/ac3200.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/ac3200.c	2004-03-16 09:37:56.073015776 +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-11 10:20:25.000000000 +0000
+++ source/drivers/net/acenic.c	2004-03-16 09:37:56.077015168 +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-11 10:20:25.000000000 +0000
+++ source/drivers/net/amd8111e.c	2004-03-16 09:37:56.079014864 +0000
@@ -174,7 +174,7 @@ This is the mii register read function p
 */ 
 static int amd8111e_mdio_read(struct net_device * dev, int phy_id, int reg_num)
 {
-	struct amd8111e_priv* lp = dev->priv;
+	struct amd8111e_priv* lp = netdev_priv(dev);
 	unsigned int reg_val;
 
 	amd8111e_read_phy(lp,phy_id,reg_num,&reg_val);
@@ -187,7 +187,7 @@ This is the mii register write function 
 */ 
 static void amd8111e_mdio_write(struct net_device * dev, int phy_id, int reg_num, int val)
 {
-	struct amd8111e_priv* lp = dev->priv;
+	struct amd8111e_priv* lp = netdev_priv(dev);
 
 	amd8111e_write_phy(lp, phy_id, reg_num, val);
 }
@@ -197,7 +197,7 @@ This function will set PHY speed. During
 */
 static void amd8111e_set_ext_phy(struct net_device *dev)
 {
-	struct amd8111e_priv *lp = (struct amd8111e_priv *)dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	u32 bmcr,advert,tmp;
 	
 	/* Determine mii register values to set the speed */
@@ -239,7 +239,7 @@ all transmit and receive skbuffs.
 */
 static int amd8111e_free_skbs(struct net_device *dev)
 {
-	struct amd8111e_priv *lp = (struct amd8111e_priv *)dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	struct sk_buff* rx_skbuff;
 	int i;
 
@@ -272,7 +272,7 @@ This will set the receive buffer length 
 */
 static inline void amd8111e_set_rx_buff_len(struct net_device* dev)
 {
-	struct amd8111e_priv* lp = dev->priv;
+	struct amd8111e_priv* lp = netdev_priv(dev);
 	unsigned int mtu = dev->mtu;
 	
 	if (mtu > ETH_DATA_LEN){
@@ -290,7 +290,7 @@ This function will free all the previous
  */
 static int amd8111e_init_ring(struct net_device *dev)
 {
-	struct amd8111e_priv *lp = (struct amd8111e_priv *)dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	int i;
 
 	lp->rx_idx = lp->tx_idx = 0;
@@ -371,7 +371,7 @@ static int amd8111e_set_coalesce(struct 
 	unsigned int timeout;
 	unsigned int event_count;
 
-	struct amd8111e_priv *lp = dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	void* mmio = lp->mmio;
 	struct amd8111e_coalesce_conf * coal_conf = &lp->coal_conf;
 
@@ -429,7 +429,7 @@ This function initializes the device reg
 */
 static int amd8111e_restart(struct net_device *dev)
 {
-	struct amd8111e_priv *lp = (struct amd8111e_priv* )dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	void * mmio = lp->mmio;
 	int i,reg_val;
 
@@ -663,7 +663,7 @@ This function will free all the transmit
 */
 static int amd8111e_tx(struct net_device *dev)
 {
-	struct amd8111e_priv* lp = dev->priv;
+	struct amd8111e_priv* lp = netdev_priv(dev);
 	int tx_index = lp->tx_complete_idx & TX_RING_DR_MOD_MASK;
 	int status;
 	/* Complete all the transmit packet */
@@ -705,7 +705,7 @@ This function will check the ownership o
 */
 static int amd8111e_rx(struct net_device *dev)
 {
-	struct amd8111e_priv *lp = dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	struct sk_buff *skb,*new_skb;
 	int rx_index = lp->rx_idx & RX_RING_DR_MOD_MASK;
 	int min_pkt_len, status;
@@ -809,7 +809,7 @@ This function will indicate the link sta
 */
 static int amd8111e_link_change(struct net_device* dev)
 {	
-	struct amd8111e_priv *lp = dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	int status0,speed;
 
 	/* read the link change */
@@ -871,7 +871,7 @@ This function reads the mib registers an
 */ 
 static struct net_device_stats *amd8111e_get_stats(struct net_device * dev)
 {
-	struct amd8111e_priv *lp = dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	void * mmio = lp->mmio;
 	unsigned long flags;
 	/* struct net_device_stats *prev_stats = &lp->prev_stats; */
@@ -966,7 +966,7 @@ according to the datarate and the packet
 */
 static int amd8111e_calc_coalesce(struct net_device *dev)
 {
-	struct amd8111e_priv *lp = dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	struct amd8111e_coalesce_conf * coal_conf = &lp->coal_conf;
 	int tx_pkt_rate;
 	int rx_pkt_rate;
@@ -1102,7 +1102,7 @@ static irqreturn_t amd8111e_interrupt(in
 {
 
 	struct net_device * dev = (struct net_device *) dev_id;
-	struct amd8111e_priv *lp = dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	void * mmio = lp->mmio;
 	unsigned int intr0;
 	unsigned int handled = 1;
@@ -1153,12 +1153,23 @@ 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.
 */
 static int amd8111e_close(struct net_device * dev)
 {
-	struct amd8111e_priv *lp = dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	netif_stop_queue(dev);
 	
 	spin_lock_irq(&lp->lock);
@@ -1185,7 +1196,7 @@ static int amd8111e_close(struct net_dev
 */
 static int amd8111e_open(struct net_device * dev )
 {
-	struct amd8111e_priv *lp = (struct amd8111e_priv *)dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 
 	if(dev->irq ==0 || request_irq(dev->irq, amd8111e_interrupt, SA_SHIRQ,
 					 dev->name, dev)) 
@@ -1231,7 +1242,7 @@ This function will queue the transmit pa
 
 static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev)
 {
-	struct amd8111e_priv *lp = dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	int tx_index;
 	unsigned long flags;
 
@@ -1338,7 +1349,7 @@ list to the device.
 static void amd8111e_set_multicast_list(struct net_device *dev)
 {
 	struct dev_mc_list* mc_ptr;
-	struct amd8111e_priv *lp = dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	u32 mc_filter[2] ;
 	int i,bit_num;
 	if(dev->flags & IFF_PROMISC){
@@ -1388,7 +1399,7 @@ This function handles all the  ethtool i
 	
 static int amd8111e_ethtool_ioctl(struct net_device* dev, void* useraddr)
 {
-	struct amd8111e_priv *lp = dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	struct pci_dev *pci_dev = lp->pci_dev;
 	u32 ethcmd;
 	
@@ -1510,7 +1521,7 @@ static int amd8111e_ethtool_ioctl(struct
 static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd)
 {
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
-	struct amd8111e_priv *lp = dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	int err;
 	u32 mii_regval;
 
@@ -1554,7 +1565,7 @@ This function changes the mtu of the dev
 */  
 int amd8111e_change_mtu(struct net_device *dev, int new_mtu)
 {
-	struct amd8111e_priv *lp = dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	int err;
 
 	if ((new_mtu < AMD8111E_MIN_MTU) || (new_mtu > AMD8111E_MAX_MTU))
@@ -1584,7 +1595,7 @@ int amd8111e_change_mtu(struct net_devic
 #if AMD8111E_VLAN_TAG_USED
 static void amd8111e_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
 {
-	struct  amd8111e_priv *lp = dev->priv;
+	struct  amd8111e_priv *lp = netdev_priv(dev);
 	spin_lock_irq(&lp->lock);
 	lp->vlgrp = grp;
 	spin_unlock_irq(&lp->lock);
@@ -1592,7 +1603,7 @@ static void amd8111e_vlan_rx_register(st
 	
 static void amd8111e_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
 {
-	struct amd8111e_priv *lp = dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	spin_lock_irq(&lp->lock);
 	if (lp->vlgrp)
 		lp->vlgrp->vlan_devices[vid] = NULL;
@@ -1623,7 +1634,7 @@ static int amd8111e_enable_link_change(s
 
 static void amd8111e_tx_timeout(struct net_device *dev)
 {
-	struct amd8111e_priv* lp = dev->priv;
+	struct amd8111e_priv* lp = netdev_priv(dev);
 	int err;
 
 	printk(KERN_ERR "%s: transmit timed out, resetting\n",
@@ -1637,7 +1648,7 @@ static void amd8111e_tx_timeout(struct n
 static int amd8111e_suspend(struct pci_dev *pci_dev, u32 state)
 {	
 	struct net_device *dev = pci_get_drvdata(pci_dev);
-	struct amd8111e_priv *lp = dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	
 	if (!netif_running(dev))
 		return 0;
@@ -1680,7 +1691,7 @@ static int amd8111e_suspend(struct pci_d
 static int amd8111e_resume(struct pci_dev *pci_dev)
 {
 	struct net_device *dev = pci_get_drvdata(pci_dev);
-	struct amd8111e_priv *lp = dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	
 	if (!netif_running(dev))
 		return 0;
@@ -1719,7 +1730,7 @@ static void __devexit amd8111e_remove_on
 }
 static void amd8111e_config_ipg(struct net_device* dev)
 {
-	struct amd8111e_priv *lp = dev->priv;
+	struct amd8111e_priv *lp = netdev_priv(dev);
 	struct ipg_info* ipg_data = &lp->ipg_data;
 	void * mmio = lp->mmio;
 	unsigned int prev_col_cnt = ipg_data->col_cnt;
@@ -1841,7 +1852,7 @@ static int __devinit amd8111e_probe_one(
 	dev->vlan_rx_kill_vid = amd8111e_vlan_rx_kill_vid;
 #endif	
 	
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 	lp->pci_dev = pdev;
 	lp->amd8111e_net_dev = dev;
 	lp->pm_cap = pm_cap;
@@ -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-11 10:20:25.000000000 +0000
+++ source/drivers/net/apne.c	2004-03-16 09:37:56.080014712 +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/appletalk/cops.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/net/appletalk/cops.c	2004-03-16 09:37:56.082014408 +0000
@@ -333,7 +333,7 @@ static int __init cops_probe1(struct net
 
 	dev->base_addr = ioaddr;
 
-        lp = (struct cops_local *)dev->priv;
+        lp = netdev_priv(dev);
         memset(lp, 0, sizeof(struct cops_local));
         spin_lock_init(&lp->lock);
 
@@ -422,7 +422,7 @@ static int __init cops_irq (int ioaddr, 
  */
 static int cops_open(struct net_device *dev)
 {
-    struct cops_local *lp = (struct cops_local *)dev->priv;
+    struct cops_local *lp = netdev_priv(dev);
 
 	if(dev->irq==0)
 	{
@@ -456,7 +456,7 @@ static int cops_open(struct net_device *
  */
 static int cops_jumpstart(struct net_device *dev)
 {
-	struct cops_local *lp = (struct cops_local *)dev->priv;
+	struct cops_local *lp = netdev_priv(dev);
 
 	/*
          *      Once the card has the firmware loaded and has acquired
@@ -490,7 +490,7 @@ static void tangent_wait_reset(int ioadd
  */
 static void cops_reset(struct net_device *dev, int sleep)
 {
-        struct cops_local *lp = (struct cops_local *)dev->priv;
+        struct cops_local *lp = netdev_priv(dev);
         int ioaddr=dev->base_addr;
 
         if(lp->board==TANGENT)
@@ -525,7 +525,7 @@ static void cops_load (struct net_device
 {
         struct ifreq ifr;
         struct ltfirmware *ltf= (struct ltfirmware *)&ifr.ifr_data;
-        struct cops_local *lp=(struct cops_local *)dev->priv;
+        struct cops_local *lp = netdev_priv(dev);
         int ioaddr=dev->base_addr;
 	int length, i = 0;
 
@@ -618,7 +618,7 @@ static void cops_load (struct net_device
  */
 static int cops_nodeid (struct net_device *dev, int nodeid)
 {
-	struct cops_local *lp = (struct cops_local *) dev->priv;
+	struct cops_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	if(lp->board == DAYNA)
@@ -730,7 +730,7 @@ static irqreturn_t cops_interrupt(int ir
         int boguscount = 0;
 
         ioaddr = dev->base_addr;
-        lp = (struct cops_local *)dev->priv;
+        lp = netdev_priv(dev);
 
 	if(lp->board==DAYNA)
 	{
@@ -765,7 +765,7 @@ static void cops_rx(struct net_device *d
         int pkt_len = 0;
         int rsp_type = 0;
         struct sk_buff *skb = NULL;
-        struct cops_local *lp = dev->priv;
+        struct cops_local *lp = netdev_priv(dev);
         int ioaddr = dev->base_addr;
         int boguscount = 0;
         unsigned long flags;
@@ -869,7 +869,7 @@ static void cops_rx(struct net_device *d
 
 static void cops_timeout(struct net_device *dev)
 {
-        struct cops_local *lp = (struct cops_local *)dev->priv;
+        struct cops_local *lp = netdev_priv(dev);
         int ioaddr = dev->base_addr;
 
 	lp->stats.tx_errors++;
@@ -891,7 +891,7 @@ static void cops_timeout(struct net_devi
 
 static int cops_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-        struct cops_local *lp = (struct cops_local *)dev->priv;
+        struct cops_local *lp = netdev_priv(dev);
         int ioaddr = dev->base_addr;
         unsigned long flags;
 
@@ -966,7 +966,7 @@ static int cops_hard_header(struct sk_bu
  
 static int cops_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-        struct cops_local *lp = (struct cops_local *)dev->priv;
+        struct cops_local *lp = netdev_priv(dev);
         struct sockaddr_at *sa = (struct sockaddr_at *)&ifr->ifr_addr;
         struct atalk_addr *aa = (struct atalk_addr *)&lp->node_addr;
 
@@ -1002,7 +1002,7 @@ static int cops_ioctl(struct net_device 
  
 static int cops_close(struct net_device *dev)
 {
-	struct cops_local *lp = (struct cops_local *)dev->priv;
+	struct cops_local *lp = netdev_priv(dev);
 
 	/* If we were running polled, yank the timer.
 	 */
@@ -1019,7 +1019,7 @@ static int cops_close(struct net_device 
  */
 static struct net_device_stats *cops_get_stats(struct net_device *dev)
 {
-        struct cops_local *lp = (struct cops_local *)dev->priv;
+        struct cops_local *lp = netdev_priv(dev);
         return &lp->stats;
 }
 
--- diff/drivers/net/ariadne.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/net/ariadne.c	2004-03-16 09:37:56.089013344 +0000
@@ -184,7 +184,7 @@ static int __devinit ariadne_init_one(st
     }
 
     SET_MODULE_OWNER(dev);
-    priv = dev->priv;
+    priv = netdev_priv(dev);
 
     r1->name = dev->name;
     r2->name = dev->name;
@@ -333,7 +333,7 @@ static int ariadne_open(struct net_devic
 
 static void ariadne_init_ring(struct net_device *dev)
 {
-    struct ariadne_private *priv = (struct ariadne_private *)dev->priv;
+    struct ariadne_private *priv = netdev_priv(dev);
     volatile struct lancedata *lancedata = (struct lancedata *)dev->mem_start;
     int i;
 
@@ -379,7 +379,7 @@ static void ariadne_init_ring(struct net
 
 static int ariadne_close(struct net_device *dev)
 {
-    struct ariadne_private *priv = (struct ariadne_private *)dev->priv;
+    struct ariadne_private *priv = netdev_priv(dev);
     volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr;
 
     netif_stop_queue(dev);
@@ -434,7 +434,7 @@ static irqreturn_t ariadne_interrupt(int
     if (!(lance->RDP & INTR))		/* Check if any interrupt has been */
 	return IRQ_NONE;		/* generated by the board. */
 
-    priv = (struct ariadne_private *)dev->priv;
+    priv = netdev_priv(dev);
 
     boguscnt = 10;
     while ((csr0 = lance->RDP) & (ERR|RINT|TINT) && --boguscnt >= 0) {
@@ -589,7 +589,7 @@ static void ariadne_tx_timeout(struct ne
 
 static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-    struct ariadne_private *priv = (struct ariadne_private *)dev->priv;
+    struct ariadne_private *priv = netdev_priv(dev);
     volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr;
     int entry;
     unsigned long flags;
@@ -697,7 +697,7 @@ static int ariadne_start_xmit(struct sk_
 
 static int ariadne_rx(struct net_device *dev)
 {
-    struct ariadne_private *priv = (struct ariadne_private *)dev->priv;
+    struct ariadne_private *priv = netdev_priv(dev);
     int entry = priv->cur_rx % RX_RING_SIZE;
     int i;
 
@@ -787,7 +787,7 @@ static int ariadne_rx(struct net_device 
 
 static struct net_device_stats *ariadne_get_stats(struct net_device *dev)
 {
-    struct ariadne_private *priv = (struct ariadne_private *)dev->priv;
+    struct ariadne_private *priv = netdev_priv(dev);
     volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr;
     short saved_addr;
     unsigned long flags;
--- diff/drivers/net/arm/am79c961a.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/net/arm/am79c961a.c	2004-03-16 09:37:56.090013192 +0000
@@ -196,7 +196,7 @@ am79c961_ramtest(struct net_device *dev,
 static void
 am79c961_init_for_open(struct net_device *dev)
 {
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	struct dev_priv *priv = netdev_priv(dev);
 	unsigned long flags;
 	unsigned char *p;
 	u_int hdr_addr, first_free_addr;
@@ -271,7 +271,7 @@ am79c961_init_for_open(struct net_device
 static void am79c961_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	struct dev_priv *priv = netdev_priv(dev);
 	unsigned int lnkstat, carrier;
 
 	lnkstat = read_ireg(dev->base_addr, ISALED0) & ISALED0_LNKST;
@@ -291,7 +291,7 @@ static void am79c961_timer(unsigned long
 static int
 am79c961_open(struct net_device *dev)
 {
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	struct dev_priv *priv = netdev_priv(dev);
 	int ret;
 
 	memset (&priv->stats, 0, sizeof (priv->stats));
@@ -318,7 +318,7 @@ am79c961_open(struct net_device *dev)
 static int
 am79c961_close(struct net_device *dev)
 {
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	struct dev_priv *priv = netdev_priv(dev);
 	unsigned long flags;
 
 	del_timer_sync(&priv->timer);
@@ -341,7 +341,7 @@ am79c961_close(struct net_device *dev)
  */
 static struct net_device_stats *am79c961_getstats (struct net_device *dev)
 {
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	struct dev_priv *priv = netdev_priv(dev);
 	return &priv->stats;
 }
 
@@ -365,7 +365,7 @@ static void am79c961_mc_hash(struct dev_
  */
 static void am79c961_setmulticastlist (struct net_device *dev)
 {
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	struct dev_priv *priv = netdev_priv(dev);
 	unsigned long flags;
 	unsigned short multi_hash[4], mode;
 	int i, stopped;
@@ -444,7 +444,7 @@ static void am79c961_timeout(struct net_
 static int
 am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
 {
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	struct dev_priv *priv = netdev_priv(dev);
 	unsigned int hdraddr, bufaddr;
 	unsigned int head;
 	unsigned long flags;
@@ -593,7 +593,7 @@ static irqreturn_t
 am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *)dev_id;
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	struct dev_priv *priv = netdev_priv(dev);
 	u_int status, n = 100;
 	int handled = 0;
 
@@ -630,7 +630,7 @@ am79c961_interrupt(int irq, void *dev_id
 static int
 am79c961_hw_init(struct net_device *dev)
 {
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	struct dev_priv *priv = netdev_priv(dev);
 
 	spin_lock_irq(&priv->chip_lock);
 	write_rreg (dev->base_addr, CSR0, CSR0_STOP);
@@ -662,7 +662,7 @@ static int __init am79c961_init(void)
 	if (!dev)
 		goto out;
 
-	priv = dev->priv;
+	priv = netdev_priv(dev);
 
 	/*
 	 * Fixed address and IRQ lines here.
--- diff/drivers/net/arm/ether1.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/arm/ether1.c	2004-03-16 09:37:56.091013040 +0000
@@ -447,7 +447,7 @@ static rbd_t  init_rbd	= {
 static int
 ether1_init_for_open (struct net_device *dev)
 {
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	struct ether1_priv *priv = netdev_priv(dev);
 	int i, status, addr, next, next2;
 	int failures = 0;
 	unsigned long timeout;
@@ -616,7 +616,7 @@ ether1_init_for_open (struct net_device 
 static int
 ether1_txalloc (struct net_device *dev, int size)
 {
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	struct ether1_priv *priv = netdev_priv(dev);
 	int start, tail;
 
 	size = (size + 1) & ~1;
@@ -642,7 +642,7 @@ ether1_txalloc (struct net_device *dev, 
 static int
 ether1_open (struct net_device *dev)
 {
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	struct ether1_priv *priv = netdev_priv(dev);
 
 	if (!is_valid_ether_addr(dev->dev_addr)) {
 		printk(KERN_WARNING "%s: invalid ethernet MAC address\n",
@@ -668,7 +668,7 @@ ether1_open (struct net_device *dev)
 static void
 ether1_timeout(struct net_device *dev)
 {
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	struct ether1_priv *priv = netdev_priv(dev);
 
 	printk(KERN_WARNING "%s: transmit timeout, network cable problem?\n",
 		dev->name);
@@ -686,7 +686,7 @@ ether1_timeout(struct net_device *dev)
 static int
 ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
 {
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	struct ether1_priv *priv = netdev_priv(dev);
 	int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr;
 	unsigned long flags;
 	tx_t tx;
@@ -762,7 +762,7 @@ ether1_sendpacket (struct sk_buff *skb, 
 static void
 ether1_xmit_done (struct net_device *dev)
 {
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	struct ether1_priv *priv = netdev_priv(dev);
 	nop_t nop;
 	int caddr, tst;
 
@@ -863,7 +863,7 @@ again:
 static void
 ether1_recv_done (struct net_device *dev)
 {
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	struct ether1_priv *priv = netdev_priv(dev);
 	int status;
 	int nexttail, rbdaddr;
 	rbd_t rbd;
@@ -919,7 +919,7 @@ static irqreturn_t
 ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *)dev_id;
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	struct ether1_priv *priv = netdev_priv(dev);
 	int status;
 
 	status = ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS);
@@ -978,7 +978,7 @@ ether1_close (struct net_device *dev)
 static struct net_device_stats *
 ether1_getstats (struct net_device *dev)
 {
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	struct ether1_priv *priv = netdev_priv(dev);
 	return &priv->stats;
 }
 
@@ -1030,7 +1030,7 @@ ether1_probe(struct expansion_card *ec, 
 	request_region(dev->base_addr, 16, dev->name);
 	request_region(dev->base_addr + 0x800, 4096, dev->name);
 
-	priv = (struct ether1_priv *)dev->priv;
+	priv = netdev_priv(dev);
 	if ((priv->bus_type = ether1_reset(dev)) == 0) {
 		ret = -ENODEV;
 		goto release;
--- diff/drivers/net/arm/ether3.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/arm/ether3.c	2004-03-16 09:37:56.092012888 +0000
@@ -121,7 +121,7 @@ static inline void ether3_outw(int v, co
 static int
 ether3_setbuffer(struct net_device *dev, buffer_rw_t read, int start)
 {
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	struct dev_priv *priv = netdev_priv(dev);
 	int timeout = 1000;
 
 	ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
@@ -180,7 +180,7 @@ static void
 ether3_ledoff(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	struct dev_priv *priv = netdev_priv(dev);
 	ether3_outw(priv->regs.config2 |= CFG2_CTRLO, REG_CONFIG2);
 }
 
@@ -280,7 +280,7 @@ ether3_ramtest(struct net_device *dev, u
 static int __init
 ether3_init_2(struct net_device *dev)
 {
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	struct dev_priv *priv = netdev_priv(dev);
 	int i;
 
 	priv->regs.config1 = CFG1_RECVCOMPSTAT0|CFG1_DMABURST8;
@@ -330,7 +330,7 @@ ether3_init_2(struct net_device *dev)
 static void
 ether3_init_for_open(struct net_device *dev)
 {
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	struct dev_priv *priv = netdev_priv(dev);
 	int i;
 
 	memset(&priv->stats, 0, sizeof(struct net_device_stats));
@@ -434,7 +434,7 @@ ether3_open(struct net_device *dev)
 static int
 ether3_close(struct net_device *dev)
 {
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	struct dev_priv *priv = netdev_priv(dev);
 
 	netif_stop_queue(dev);
 
@@ -457,7 +457,7 @@ ether3_close(struct net_device *dev)
  */
 static struct net_device_stats *ether3_getstats(struct net_device *dev)
 {
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	struct dev_priv *priv = netdev_priv(dev);
 	return &priv->stats;
 }
 
@@ -469,7 +469,7 @@ static struct net_device_stats *ether3_g
  */
 static void ether3_setmulticastlist(struct net_device *dev)
 {
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	struct dev_priv *priv = netdev_priv(dev);
 
 	priv->regs.config1 &= ~CFG1_RECVPROMISC;
 
@@ -487,7 +487,7 @@ static void ether3_setmulticastlist(stru
 static void
 ether3_timeout(struct net_device *dev)
 {
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	struct dev_priv *priv = netdev_priv(dev);
 	unsigned long flags;
 
 	del_timer(&priv->timer);
@@ -518,7 +518,7 @@ ether3_timeout(struct net_device *dev)
 static int
 ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
 {
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	struct dev_priv *priv = netdev_priv(dev);
 	unsigned long flags;
 	unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 	unsigned int ptr, next_ptr;
@@ -594,7 +594,7 @@ ether3_interrupt(int irq, void *dev_id, 
 		printk("eth3irq: %d ", irq);
 #endif
 
-	priv = (struct dev_priv *)dev->priv;
+	priv = netdev_priv(dev);
 
 	status = ether3_inw(REG_STATUS);
 
@@ -844,7 +844,7 @@ ether3_probe(struct expansion_card *ec, 
 		goto free;
 	}
 
-	priv = (struct dev_priv *) dev->priv;
+	priv = netdev_priv(dev);
 	init_timer(&priv->timer);
 
 	/* Reset card...
--- diff/drivers/net/arm/etherh.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/arm/etherh.c	2004-03-16 09:37:56.093012736 +0000
@@ -144,7 +144,7 @@ static expansioncard_ops_t etherh_ops = 
 static void
 etherh_setif(struct net_device *dev)
 {
-	struct etherh_priv *eh = (struct etherh_priv *)dev->priv;
+	struct etherh_priv *eh = netdev_priv(dev);
 	struct ei_device *ei_local = &eh->eidev;
 	unsigned long addr, flags;
 
@@ -188,7 +188,7 @@ etherh_setif(struct net_device *dev)
 static int
 etherh_getifstat(struct net_device *dev)
 {
-	struct etherh_priv *eh = (struct etherh_priv *)dev->priv;
+	struct etherh_priv *eh = netdev_priv(dev);
 	struct ei_device *ei_local = &eh->eidev;
 	int stat = 0;
 
@@ -256,7 +256,7 @@ static int etherh_set_config(struct net_
 static void
 etherh_reset(struct net_device *dev)
 {
-	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+	struct ei_device *ei_local = netdev_priv(dev);
 
 	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, dev->base_addr);
 
@@ -283,7 +283,7 @@ etherh_reset(struct net_device *dev)
 static void
 etherh_block_output (struct net_device *dev, int count, const unsigned char *buf, int start_page)
 {
-	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+	struct ei_device *ei_local = netdev_priv(dev);
 	unsigned int addr, dma_addr;
 	unsigned long dma_start;
 
@@ -349,7 +349,7 @@ etherh_block_output (struct net_device *
 static void
 etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
 {
-	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+	struct ei_device *ei_local = netdev_priv(dev);
 	unsigned int addr, dma_addr;
 	unsigned char *buf;
 
@@ -390,7 +390,7 @@ etherh_block_input (struct net_device *d
 static void
 etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
 {
-	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+	struct ei_device *ei_local = netdev_priv(dev);
 	unsigned int addr, dma_addr;
 
 	if (ei_local->dmaing) {
@@ -432,7 +432,7 @@ etherh_get_header (struct net_device *de
 static int
 etherh_open(struct net_device *dev)
 {
-	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+	struct ei_device *ei_local = netdev_priv(dev);
 
 	if (!is_valid_ether_addr(dev->dev_addr)) {
 		printk(KERN_WARNING "%s: invalid ethernet MAC address\n",
@@ -557,7 +557,7 @@ etherh_probe(struct expansion_card *ec, 
 		goto out;
 	}
 
-	eh = dev->priv;
+	eh = netdev_priv(dev);
 
 	spin_lock_init(&eh->eidev.page_lock);
 
@@ -653,7 +653,7 @@ etherh_probe(struct expansion_card *ec, 
 		break;
 	}
 
-	ei_local = (struct ei_device *) dev->priv;
+	ei_local = netdev_priv(dev);
 	if (ec->cid.product == PROD_ANT_ETHERM) {
 		ei_local->tx_start_page = ETHERM_TX_START_PAGE;
 		ei_local->stop_page     = ETHERM_STOP_PAGE;
--- diff/drivers/net/at1700.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/at1700.c	2004-03-16 09:37:56.094012584 +0000
@@ -241,7 +241,7 @@ static int irq;
 static void cleanup_card(struct net_device *dev)
 {
 #ifdef CONFIG_MCA	
-	struct net_local *lp = dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	if (lp->mca_slot)
 		mca_mark_as_unused(lp->mca_slot);
 #endif	
@@ -319,8 +319,8 @@ static int __init at1700_probe1(struct n
 	char at1700_irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15};
 	unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0;
 	int slot, ret = -ENODEV;
-	struct net_local *lp = dev->priv;
-	
+	struct net_local *lp = netdev_priv(dev);
+
 #ifndef CONFIG_X86_PC9800
 	if (!request_region(ioaddr, AT1700_IO_EXTENT, dev->name))
 		return -EBUSY;
@@ -618,7 +618,7 @@ static int __init read_eeprom(long ioadd
 
 static int net_open(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	/* Set the configuration register 0 to 32K 100ns. byte-wide memory, 16 bit
@@ -649,7 +649,7 @@ static int net_open(struct net_device *d
 
 static void net_tx_timeout (struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	printk ("%s: transmit timed out with status %04x, %s?\n", dev->name,
@@ -683,7 +683,7 @@ static void net_tx_timeout (struct net_d
 
 static int net_send_packet (struct sk_buff *skb, struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *) dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 	short len = skb->len;
@@ -748,7 +748,7 @@ net_interrupt(int irq, void *dev_id, str
 	}
 
 	ioaddr = dev->base_addr;
-	lp = (struct net_local *)dev->priv;
+	lp = netdev_priv(dev);
 	
 	spin_lock (&lp->lock);
 	
@@ -808,7 +808,7 @@ net_interrupt(int irq, void *dev_id, str
 static void
 net_rx(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	int boguscount = 5;
 
@@ -891,7 +891,7 @@ net_rx(struct net_device *dev)
 /* The inverse routine to net_open(). */
 static int net_close(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	netif_stop_queue(dev);
@@ -919,7 +919,7 @@ static int net_close(struct net_device *
 static struct net_device_stats *
 net_get_stats(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	return &lp->stats;
 }
 
@@ -931,7 +931,7 @@ static void
 set_rx_mode(struct net_device *dev)
 {
 	int ioaddr = dev->base_addr;
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned char mc_filter[8];		 /* Multicast hash filter */
 	unsigned long flags;
 	int i;
--- diff/drivers/net/atari_bionet.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/atari_bionet.c	2004-03-16 09:37:56.095012432 +0000
@@ -408,7 +408,7 @@ struct net_device * __init bionet_probe(
  */
 static int
 bionet_open(struct net_device *dev) {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	if (bionet_debug > 0)
 		printk("bionet_open\n");
@@ -433,7 +433,7 @@ bionet_open(struct net_device *dev) {
 
 static int
 bionet_send_packet(struct sk_buff *skb, struct net_device *dev) {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned long flags;
 
 	/* Block a timer-based transmit from overlapping.  This could better be
@@ -499,7 +499,7 @@ bionet_send_packet(struct sk_buff *skb, 
  */
 static void
 bionet_poll_rx(struct net_device *dev) {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int boguscount = 10;
 	int pkt_len, status;
 	unsigned long flags;
@@ -601,7 +601,7 @@ bionet_poll_rx(struct net_device *dev) {
 static void
 bionet_tick(unsigned long data) {
 	struct net_device	 *dev = (struct net_device *)data;
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	if( bionet_debug > 0 && (lp->open_time++ & 7) == 8 )
 		printk("bionet_tick: %ld\n", lp->open_time);
@@ -616,7 +616,7 @@ bionet_tick(unsigned long data) {
  */
 static int
 bionet_close(struct net_device *dev) {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	if (bionet_debug > 0)
 		printk("bionet_close, open_time=%ld\n", lp->open_time);
@@ -638,7 +638,7 @@ bionet_close(struct net_device *dev) {
  */
 static struct net_device_stats *net_get_stats(struct net_device *dev) 
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	return &lp->stats;
 }
 
--- diff/drivers/net/atari_pamsnet.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/net/atari_pamsnet.c	2004-03-16 09:37:56.096012280 +0000
@@ -667,7 +667,7 @@ struct net_device * __init pamsnet_probe
  */
 static int
 pamsnet_open(struct net_device *dev) {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	if (pamsnet_debug > 0)
 		printk("pamsnet_open\n");
@@ -696,7 +696,7 @@ pamsnet_open(struct net_device *dev) {
 
 static int
 pamsnet_send_packet(struct sk_buff *skb, struct net_device *dev) {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned long flags;
 
 	/* Block a timer-based transmit from overlapping.  This could better be
@@ -742,7 +742,7 @@ pamsnet_send_packet(struct sk_buff *skb,
  */
 static void
 pamsnet_poll_rx(struct net_device *dev) {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int boguscount;
 	int pkt_len;
 	struct sk_buff *skb;
@@ -817,7 +817,7 @@ pamsnet_poll_rx(struct net_device *dev) 
 static void
 pamsnet_tick(unsigned long data) {
 	struct net_device	 *dev = (struct net_device *)data;
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	if( pamsnet_debug > 0 && (lp->open_time++ & 7) == 8 )
 		printk("pamsnet_tick: %ld\n", lp->open_time);
@@ -832,7 +832,7 @@ pamsnet_tick(unsigned long data) {
  */
 static int
 pamsnet_close(struct net_device *dev) {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	if (pamsnet_debug > 0)
 		printk("pamsnet_close, open_time=%ld\n", lp->open_time);
@@ -859,7 +859,7 @@ pamsnet_close(struct net_device *dev) {
  */
 static struct net_device_stats *net_get_stats(struct net_device *dev) 
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	return &lp->stats;
 }
 
--- diff/drivers/net/atp.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/atp.c	2004-03-16 09:37:56.097012128 +0000
@@ -335,7 +335,7 @@ static int __init atp_probe1(long ioaddr
 	/* Reset the ethernet hardware and activate the printer pass-through. */
 	write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX);
 
-	lp = (struct net_local *)dev->priv;
+	lp = netdev_priv(dev);
 	lp->chip_type = RTL8002;
 	lp->addr_mode = CMR2h_Normal;
 	spin_lock_init(&lp->lock);
@@ -432,7 +432,7 @@ static unsigned short __init eeprom_op(l
    */
 static int net_open(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int ret;
 
 	/* The interrupt line is turned off (tri-stated) when the device isn't in
@@ -458,7 +458,7 @@ static int net_open(struct net_device *d
    the hardware may have been temporarily detached. */
 static void hardware_init(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
     int i;
 
@@ -541,7 +541,7 @@ static void write_packet(long ioaddr, in
 
 static void tx_timeout(struct net_device *dev)
 {
-	struct net_local *np = (struct net_local *)dev->priv;
+	struct net_local *np = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	printk(KERN_WARNING "%s: Transmit timed out, %s?\n", dev->name,
@@ -557,7 +557,7 @@ static void tx_timeout(struct net_device
 
 static int atp_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int length;
 	unsigned long flags;
@@ -611,7 +611,7 @@ atp_interrupt(int irq, void *dev_instanc
 		return IRQ_NONE;
 	}
 	ioaddr = dev->base_addr;
-	lp = (struct net_local *)dev->priv;
+	lp = netdev_priv(dev);
 
 	spin_lock(&lp->lock);
 
@@ -726,7 +726,7 @@ static void atp_timed_checker(unsigned l
 {
 	struct net_device *dev = (struct net_device *)data;
 	long ioaddr = dev->base_addr;
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int tickssofar = jiffies - lp->last_rx_time;
 	int i;
 
@@ -740,7 +740,7 @@ static void atp_timed_checker(unsigned l
 		for (i = 0; i < 6; i++)
 			if (read_cmd_byte(ioaddr, PAR0 + i) != atp_timed_dev->dev_addr[i])
 				{
-			struct net_local *lp = (struct net_local *)atp_timed_dev->priv;
+			struct net_local *lp = netdev_priv(atp_timed_dev);
 			write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]);
 			if (i == 2)
 			  lp->stats.tx_errors++;
@@ -762,7 +762,7 @@ static void atp_timed_checker(unsigned l
 /* We have a good packet(s), get it/them out of the buffers. */
 static void net_rx(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	struct rx_header rx_head;
 
@@ -838,7 +838,7 @@ static void read_block(long ioaddr, int 
 static int
 net_close(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	netif_stop_queue(dev);
@@ -863,7 +863,7 @@ net_close(struct net_device *dev)
 static struct net_device_stats *
 net_get_stats(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	return &lp->stats;
 }
 
@@ -873,7 +873,7 @@ net_get_stats(struct net_device *dev)
 
 static void set_rx_mode_8002(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	if ( dev->mc_count > 0 || (dev->flags & (IFF_ALLMULTI|IFF_PROMISC))) {
@@ -890,7 +890,7 @@ static void set_rx_mode_8002(struct net_
 
 static void set_rx_mode_8012(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	unsigned char new_mode, mc_filter[8]; /* Multicast hash filter */
 	int i;
--- diff/drivers/net/b44.c	2003-11-25 15:24:58.000000000 +0000
+++ source/drivers/net/b44.c	2004-03-16 09:37:56.098011976 +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/bagetlance.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/bagetlance.c	2004-03-16 09:37:56.101011520 +0000
@@ -594,7 +594,7 @@ static int __init lance_probe1( struct n
 	return( 0 );
 
   probe_ok:
-	lp = (struct lance_private *)dev->priv;
+	lp = netdev_priv(dev);
 	MEM = (struct lance_memory *)memaddr;
 	IO = lp->iobase = (struct lance_ioreg *)ioaddr;
 	dev->base_addr = (unsigned long)ioaddr; /* informational only */
@@ -736,7 +736,7 @@ static int __init lance_probe1( struct n
 
 static int lance_open( struct net_device *dev )
 
-{	struct lance_private *lp = (struct lance_private *)dev->priv;
+{	struct lance_private *lp = netdev_priv(dev);
 	struct lance_ioreg	 *IO = lp->iobase;
 	int i;
 
@@ -778,7 +778,7 @@ static int lance_open( struct net_device
 
 static void lance_init_ring( struct net_device *dev )
 
-{	struct lance_private *lp = (struct lance_private *)dev->priv;
+{	struct lance_private *lp = netdev_priv(dev);
 	int i;
 	unsigned offset;
 
@@ -834,7 +834,7 @@ static void lance_init_ring( struct net_
 
 static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
 
-{	struct lance_private *lp = (struct lance_private *)dev->priv;
+{	struct lance_private *lp = netdev_priv(dev);
 	struct lance_ioreg	 *IO = lp->iobase;
 	int entry, len;
 	struct lance_tx_head *head;
@@ -988,7 +988,7 @@ static irqreturn_t lance_interrupt( int 
 		return IRQ_NONE;
 	}
 
-	lp = (struct lance_private *)dev->priv;
+	lp = netdev_priv(dev);
 	IO = lp->iobase;
 	AREG = CSR0;
 
@@ -1101,7 +1101,7 @@ static irqreturn_t lance_interrupt( int 
 
 static int lance_rx( struct net_device *dev )
 
-{	struct lance_private *lp = (struct lance_private *)dev->priv;
+{	struct lance_private *lp = netdev_priv(dev);
 	int entry = lp->cur_rx & RX_RING_MOD_MASK;
 	int i;
 
@@ -1225,7 +1225,7 @@ static int lance_rx( struct net_device *
 
 static int lance_close( struct net_device *dev )
 
-{	struct lance_private *lp = (struct lance_private *)dev->priv;
+{	struct lance_private *lp = netdev_priv(dev);
 	struct lance_ioreg	 *IO = lp->iobase;
 
 	dev->start = 0;
@@ -1247,7 +1247,7 @@ static int lance_close( struct net_devic
 static struct net_device_stats *lance_get_stats( struct net_device *dev )
 
 {	
-	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	return &lp->stats;
 }
 
@@ -1261,7 +1261,7 @@ static struct net_device_stats *lance_ge
 
 static void set_multicast_list( struct net_device *dev )
 
-{	struct lance_private *lp = (struct lance_private *)dev->priv;
+{	struct lance_private *lp = netdev_priv(dev);
 	struct lance_ioreg	 *IO = lp->iobase;
 
 	if (!dev->start)
@@ -1303,7 +1303,7 @@ static void set_multicast_list( struct n
 
 static int lance_set_mac_address( struct net_device *dev, void *addr )
 
-{	struct lance_private *lp = (struct lance_private *)dev->priv;
+{	struct lance_private *lp = netdev_priv(dev);
 	struct sockaddr *saddr = addr;
 	int i;
 
--- diff/drivers/net/bmac.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/bmac.c	2004-03-16 09:37:56.102011368 +0000
@@ -226,7 +226,7 @@ volatile unsigned short bmread(struct ne
 static void
 bmac_enable_and_reset_chip(struct net_device *dev)
 {
-	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	struct bmac_data *bp = netdev_priv(dev);
 	volatile struct dbdma_regs *rd = bp->rx_dma;
 	volatile struct dbdma_regs *td = bp->tx_dma;
 
@@ -310,7 +310,7 @@ bmac_mif_write(struct net_device *dev, u
 static void
 bmac_init_registers(struct net_device *dev)
 {
-	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	struct bmac_data *bp = netdev_priv(dev);
 	volatile unsigned short regValue;
 	unsigned short *pWord16;
 	int i;
@@ -405,7 +405,7 @@ bmac_enable_interrupts(struct net_device
 static void
 bmac_start_chip(struct net_device *dev)
 {
-	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	struct bmac_data *bp = netdev_priv(dev);
 	volatile struct dbdma_regs *rd = bp->rx_dma;
 	unsigned short	oldConfig;
 
@@ -425,7 +425,7 @@ static void
 bmac_init_phy(struct net_device *dev)
 {
 	unsigned int addr;
-	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	struct bmac_data *bp = netdev_priv(dev);
 
 	printk(KERN_DEBUG "phy registers:");
 	for (addr = 0; addr < 32; ++addr) {
@@ -458,7 +458,7 @@ static void bmac_init_chip(struct net_de
 static int bmac_suspend(struct macio_dev *mdev, u32 state)
 {
 	struct net_device* dev = macio_get_drvdata(mdev);	
-	struct bmac_data *bp = dev->priv;	
+	struct bmac_data *bp = netdev_priv(dev);
 	unsigned long flags;
 	unsigned short config;
 	int i;
@@ -508,7 +508,7 @@ static int bmac_suspend(struct macio_dev
 static int bmac_resume(struct macio_dev *mdev)
 {
 	struct net_device* dev = macio_get_drvdata(mdev);	
-	struct bmac_data *bp = dev->priv;	
+	struct bmac_data *bp = netdev_priv(dev);
 
 	/* see if this is enough */
 	if (bp->opened)
@@ -525,7 +525,7 @@ static int bmac_resume(struct macio_dev 
 
 static int bmac_set_address(struct net_device *dev, void *addr)
 {
-	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	struct bmac_data *bp = netdev_priv(dev);
 	unsigned char *p = addr;
 	unsigned short *pWord16;
 	unsigned long flags;
@@ -550,7 +550,7 @@ static int bmac_set_address(struct net_d
 
 static inline void bmac_set_timeout(struct net_device *dev)
 {
-	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	struct bmac_data *bp = netdev_priv(dev);
 	unsigned long flags;
 
 	spin_lock_irqsave(&bp->lock, flags);
@@ -656,7 +656,7 @@ bmac_init_rx_ring(struct bmac_data *bp)
 
 static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	struct bmac_data *bp = netdev_priv(dev);
 	volatile struct dbdma_regs *td = bp->tx_dma;
 	int i;
 
@@ -692,7 +692,7 @@ static int rxintcount;
 static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
-	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	struct bmac_data *bp = netdev_priv(dev);
 	volatile struct dbdma_regs *rd = bp->rx_dma;
 	volatile struct dbdma_cmd *cp;
 	int i, nb, stat;
@@ -769,7 +769,7 @@ static int txintcount;
 static irqreturn_t bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
-	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	struct bmac_data *bp = netdev_priv(dev);
 	volatile struct dbdma_cmd *cp;
 	int stat;
 	unsigned long flags;
@@ -822,7 +822,7 @@ static irqreturn_t bmac_txdma_intr(int i
 
 static struct net_device_stats *bmac_stats(struct net_device *dev)
 {
-	struct bmac_data *p = (struct bmac_data *) dev->priv;
+	struct bmac_data *p = netdev_priv(dev);
 
 	return &p->stats;
 }
@@ -995,7 +995,7 @@ bmac_remove_multi(struct net_device *dev
 static void bmac_set_multicast(struct net_device *dev)
 {
 	struct dev_mc_list *dmi;
-	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	struct bmac_data *bp = netdev_priv(dev);
 	int num_addrs = dev->mc_count;
 	unsigned short rx_cfg;
 	int i;
@@ -1086,7 +1086,7 @@ static int miscintcount;
 static irqreturn_t bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
-	struct bmac_data *bp = (struct bmac_data *)dev->priv;
+	struct bmac_data *bp = netdev_priv(dev);
 	unsigned int status = bmread(dev, STATUS);
 	if (miscintcount++ < 10) {
 		XXDEBUG(("bmac_misc_intr\n"));
@@ -1232,7 +1232,7 @@ bmac_get_station_address(struct net_devi
 
 static void bmac_reset_and_enable(struct net_device *dev)
 {
-	struct bmac_data *bp = dev->priv;
+	struct bmac_data *bp = netdev_priv(dev);
 	unsigned long flags;
 	struct sk_buff *skb;
 	unsigned char *data;
@@ -1288,7 +1288,7 @@ static int __devinit bmac_probe(struct m
 		return -ENOMEM;
 	}
 		
-	bp = (struct bmac_data *) dev->priv;
+	bp = netdev_priv(dev);
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
 	macio_set_drvdata(mdev, dev);
@@ -1408,7 +1408,7 @@ out_free:
 
 static int bmac_open(struct net_device *dev)
 {
-	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	struct bmac_data *bp = netdev_priv(dev);
 	/* XXDEBUG(("bmac: enter open\n")); */
 	/* reset the chip */
 	bp->opened = 1;
@@ -1420,7 +1420,7 @@ static int bmac_open(struct net_device *
 
 static int bmac_close(struct net_device *dev)
 {
-	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	struct bmac_data *bp = netdev_priv(dev);
 	volatile struct dbdma_regs *rd = bp->rx_dma;
 	volatile struct dbdma_regs *td = bp->tx_dma;
 	unsigned short config;
@@ -1469,7 +1469,7 @@ static int bmac_close(struct net_device 
 static void
 bmac_start(struct net_device *dev)
 {
-	struct bmac_data *bp = dev->priv;
+	struct bmac_data *bp = netdev_priv(dev);
 	int i;
 	struct sk_buff *skb;
 	unsigned long flags;
@@ -1495,7 +1495,7 @@ bmac_start(struct net_device *dev)
 static int
 bmac_output(struct sk_buff *skb, struct net_device *dev)
 {
-	struct bmac_data *bp = dev->priv;
+	struct bmac_data *bp = netdev_priv(dev);
 	skb_queue_tail(bp->queue, skb);
 	bmac_start(dev);
 	return 0;
@@ -1504,7 +1504,7 @@ bmac_output(struct sk_buff *skb, struct 
 static void bmac_tx_timeout(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *) data;
-	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	struct bmac_data *bp = netdev_priv(dev);
 	volatile struct dbdma_regs *td = bp->tx_dma;
 	volatile struct dbdma_regs *rd = bp->rx_dma;
 	volatile struct dbdma_cmd *cp;
@@ -1630,7 +1630,7 @@ bmac_proc_info(char *buffer, char **star
 static int __devexit bmac_remove(struct macio_dev *mdev)
 {
 	struct net_device *dev = macio_get_drvdata(mdev);
-	struct bmac_data *bp = dev->priv;
+	struct bmac_data *bp = netdev_priv(dev);
 
 	unregister_netdev(dev);
 
--- diff/drivers/net/cs89x0.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/cs89x0.c	2004-03-16 09:37:56.105010912 +0000
@@ -399,7 +399,7 @@ get_eeprom_cksum(int off, int len, int *
 static int __init
 cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	static unsigned version_printed;
 	int i;
 	unsigned rev_type = 0;
@@ -735,7 +735,7 @@ out1:
 static void
 get_dma_channel(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	if (lp->dma) {
 		dev->dma = lp->dma;
@@ -757,7 +757,7 @@ get_dma_channel(struct net_device *dev)
 static void
 write_dma(struct net_device *dev, int chip_type, int dma)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	if ((lp->isa_config & ANY_ISA_DMA) == 0)
 		return;
 	if (chip_type == CS8900) {
@@ -770,7 +770,7 @@ write_dma(struct net_device *dev, int ch
 static void
 set_dma_cfg(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	if (lp->use_dma) {
 		if ((lp->isa_config & ANY_ISA_DMA) == 0) {
@@ -793,7 +793,7 @@ set_dma_cfg(struct net_device *dev)
 static int
 dma_bufcfg(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	if (lp->use_dma)
 		return (lp->isa_config & ANY_ISA_DMA)? RX_DMA_ENBL : 0;
 	else
@@ -804,7 +804,7 @@ static int
 dma_busctl(struct net_device *dev)
 {
 	int retval = 0;
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	if (lp->use_dma) {
 		if (lp->isa_config & ANY_ISA_DMA)
 			retval |= RESET_RX_DMA; /* Reset the DMA pointer */
@@ -820,7 +820,7 @@ dma_busctl(struct net_device *dev)
 static void
 dma_rx(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	struct sk_buff *skb;
 	int status, length;
 	unsigned char *bp = lp->rx_dma_ptr;
@@ -882,7 +882,7 @@ skip_this_frame:
 
 void  __init reset_chip(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	int reset_start_time;
 
@@ -912,7 +912,7 @@ void  __init reset_chip(struct net_devic
 static void
 control_dc_dc(struct net_device *dev, int on_not_off)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned int selfcontrol;
 	int timenow = jiffies;
 	/* control the DC to DC convertor in the SelfControl register.  
@@ -940,7 +940,7 @@ control_dc_dc(struct net_device *dev, in
 static int
 detect_tp(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int timenow = jiffies;
 	int fdx;
 
@@ -1055,7 +1055,7 @@ send_test_pkt(struct net_device *dev)
 static int
 detect_aui(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	if (net_debug > 1) printk("%s: Attempting AUI\n", dev->name);
 	control_dc_dc(dev, 0);
@@ -1071,7 +1071,7 @@ detect_aui(struct net_device *dev)
 static int
 detect_bnc(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	if (net_debug > 1) printk("%s: Attempting BNC\n", dev->name);
 	control_dc_dc(dev, 1);
@@ -1117,7 +1117,7 @@ write_irq(struct net_device *dev, int ch
 static int
 net_open(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int result = 0;
 	int i;
 	int ret;
@@ -1358,7 +1358,7 @@ static void net_timeout(struct net_devic
 
 static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	if (net_debug > 3) {
 		printk("%s: sent %d byte packet of type %x\n",
@@ -1419,7 +1419,7 @@ static irqreturn_t net_interrupt(int irq
  	int handled = 0;
 
 	ioaddr = dev->base_addr;
-	lp = (struct net_local *)dev->priv;
+	lp = netdev_priv(dev);
 
 	/* we MUST read all the events out of the ISQ, otherwise we'll never
            get interrupted again.  As a consequence, we can't have any limit
@@ -1517,7 +1517,7 @@ count_rx_errors(int status, struct net_l
 static void
 net_rx(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	struct sk_buff *skb;
 	int status, length;
 
@@ -1573,7 +1573,7 @@ static void release_dma_buff(struct net_
 static int
 net_close(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	netif_stop_queue(dev);
 	
@@ -1600,7 +1600,7 @@ net_close(struct net_device *dev)
 static struct net_device_stats *
 net_get_stats(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned long flags;
 
 	spin_lock_irqsave(&lp->lock, flags);
@@ -1614,7 +1614,7 @@ net_get_stats(struct net_device *dev)
 
 static void set_multicast_list(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned long flags;
 
 	spin_lock_irqsave(&lp->lock, flags);
@@ -1758,7 +1758,7 @@ init_module(void)
 
 	dev->irq = irq;
 	dev->base_addr = io;
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 
 #if ALLOW_DMA
 	if (use_dma) {
--- diff/drivers/net/declance.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/declance.c	2004-03-16 09:37:56.106010760 +0000
@@ -433,7 +433,7 @@ void cp_from_buf(const int type, void *t
 /* Setup the Lance Rx and Tx rings */
 static void lance_init_ring(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_init_block *ib;
 	int leptr;
 	int i;
@@ -530,7 +530,7 @@ static int init_restart_lance(struct lan
 
 static int lance_rx(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_init_block *ib;
 	volatile struct lance_rx_desc *rd = 0;
 	unsigned char bits;
@@ -617,7 +617,7 @@ static int lance_rx(struct net_device *d
 
 static void lance_tx(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_init_block *ib;
 	volatile struct lance_regs *ll = lp->ll;
 	volatile struct lance_tx_desc *td;
@@ -709,7 +709,7 @@ static irqreturn_t
 lance_interrupt(const int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_regs *ll = lp->ll;
 	int csr0;
 
@@ -757,7 +757,7 @@ struct net_device *last_dev = 0;
 static int lance_open(struct net_device *dev)
 {
 	volatile struct lance_init_block *ib = (struct lance_init_block *) (dev->mem_start);
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_regs *ll = lp->ll;
 	int status = 0;
 
@@ -822,7 +822,7 @@ static int lance_open(struct net_device 
 
 static int lance_close(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_regs *ll = lp->ll;
 
 	netif_stop_queue(dev);
@@ -856,7 +856,7 @@ static int lance_close(struct net_device
 
 static inline int lance_reset(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_regs *ll = lp->ll;
 	int status;
 
@@ -873,7 +873,7 @@ static inline int lance_reset(struct net
 
 static void lance_tx_timeout(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_regs *ll = lp->ll;
 
 	printk(KERN_ERR "%s: transmit timed out, status %04x, reset\n",
@@ -884,7 +884,7 @@ static void lance_tx_timeout(struct net_
 
 static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_regs *ll = lp->ll;
 	volatile struct lance_init_block *ib = (struct lance_init_block *) (dev->mem_start);
 	int entry, skblen, len;
@@ -936,7 +936,7 @@ static int lance_start_xmit(struct sk_bu
 
 static struct net_device_stats *lance_get_stats(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 
 	return &lp->stats;
 }
@@ -982,7 +982,7 @@ static void lance_load_multicast(struct 
 
 static void lance_set_multicast(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_init_block *ib;
 	volatile struct lance_regs *ll = lp->ll;
 
@@ -1048,7 +1048,7 @@ static int __init dec_lance_init(const i
 	 * alloc_etherdev ensures the data structures used by the LANCE
 	 * are aligned.
 	 */
-	lp = (struct lance_private *) dev->priv;
+	lp = netdev_priv(dev);
 	spin_lock_init(&lp->lock);
 
 	lp->type = type;
@@ -1287,7 +1287,7 @@ static void __exit dec_lance_cleanup(voi
 {
 	while (root_lance_dev) {
 		struct net_device *dev = root_lance_dev;
-		struct lance_private *lp = (struct lance_private *)dev->priv;
+		struct lance_private *lp = netdev_priv(dev);
 		unregister_netdev(dev);
 #ifdef CONFIG_TC
 		if (lp->slot >= 0)
--- diff/drivers/net/dl2k.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/dl2k.c	2004-03-16 09:37:56.114009544 +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-11 10:20:25.000000000 +0000
+++ source/drivers/net/e100.c	2004-03-16 09:37:56.116009240 +0000
@@ -158,7 +158,7 @@
 
 
 #define DRV_NAME		"e100"
-#define DRV_VERSION		"3.0.16"
+#define DRV_VERSION		"3.0.17"
 #define DRV_DESCRIPTION		"Intel(R) PRO/100 Network Driver"
 #define DRV_COPYRIGHT		"Copyright(c) 1999-2004 Intel Corporation"
 #define PFX			DRV_NAME ": "
@@ -1285,6 +1285,7 @@ static inline int e100_tx_clean(struct n
 				le16_to_cpu(cb->u.tcb.tbd.size),
 				PCI_DMA_TODEVICE);
 			dev_kfree_skb_any(cb->skb);
+			cb->skb = NULL;
 			tx_cleaned = 1;
 		}
 		cb->status = 0;
@@ -1347,6 +1348,7 @@ static int e100_alloc_cbs(struct nic *ni
 		cb->dma_addr = nic->cbs_dma_addr + i * sizeof(struct cb);
 		cb->link = cpu_to_le32(nic->cbs_dma_addr +
 			((i+1) % count) * sizeof(struct cb));
+		cb->skb = NULL;
 	}
 
 	nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = nic->cbs;
@@ -1387,8 +1389,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;
@@ -1405,8 +1407,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);
@@ -1421,11 +1423,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-16 09:37:56.117009088 +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-16 09:37:56.118008936 +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/eepro.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/eepro.c	2004-03-16 09:37:56.120008632 +0000
@@ -662,7 +662,7 @@ static void eepro_recalc (struct net_dev
 {
 	struct eepro_local *	lp;
 
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 	lp->xmt_ram = RAM_SIZE - lp->rcv_ram;
 
 	if (lp->eepro == LAN595FX_10ISA) {
@@ -680,9 +680,9 @@ static void eepro_recalc (struct net_dev
 }
 
 /* prints boot-time info */
-static void eepro_print_info (struct net_device *dev)
+static void __init eepro_print_info (struct net_device *dev)
 {
-	struct eepro_local *	lp = dev->priv;
+	struct eepro_local *	lp = netdev_priv(dev);
 	int			i;
 	const char *		ifmap[] = {"AUI", "10Base2", "10BaseT"};
 
@@ -769,7 +769,7 @@ static int __init eepro_probe1(struct ne
 	if ((inb(ioaddr + ID_REG) & R_ROBIN_BITS) != (counter + 0x40))
 		goto exit;
 
-	lp = (struct eepro_local *)dev->priv;
+	lp = netdev_priv(dev);
 	memset(lp, 0, sizeof(struct eepro_local));
 	lp->xmt_bar = XMT_BAR_PRO;
 	lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO;
@@ -932,7 +932,7 @@ static int eepro_open(struct net_device 
 	unsigned short temp_reg, old8, old9;
 	int irqMask;
 	int i, ioaddr = dev->base_addr;
-	struct eepro_local *lp = (struct eepro_local *)dev->priv;
+	struct eepro_local *lp = netdev_priv(dev);
 
 	if (net_debug > 3)
 		printk(KERN_DEBUG "%s: entering eepro_open routine.\n", dev->name);
@@ -1106,7 +1106,7 @@ static int eepro_open(struct net_device 
 
 static void eepro_tx_timeout (struct net_device *dev)
 {
-	struct eepro_local *lp = (struct eepro_local *) dev->priv;
+	struct eepro_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	/* if (net_debug > 1) */
@@ -1122,7 +1122,7 @@ static void eepro_tx_timeout (struct net
 
 static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct eepro_local *lp = (struct eepro_local *)dev->priv;
+	struct eepro_local *lp = netdev_priv(dev);
 	unsigned long flags;
 	int ioaddr = dev->base_addr;
 	short length = skb->len;
@@ -1187,7 +1187,7 @@ eepro_interrupt(int irq, void *dev_id, s
                 return IRQ_NONE;
         }
 
-	lp = (struct eepro_local *)dev->priv;
+	lp = netdev_priv(dev);
 
         spin_lock(&lp->lock);
 
@@ -1235,7 +1235,7 @@ eepro_interrupt(int irq, void *dev_id, s
 
 static int eepro_close(struct net_device *dev)
 {
-	struct eepro_local *lp = (struct eepro_local *)dev->priv;
+	struct eepro_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	short temp_reg;
 
@@ -1280,7 +1280,7 @@ static int eepro_close(struct net_device
 static struct net_device_stats *
 eepro_get_stats(struct net_device *dev)
 {
-	struct eepro_local *lp = (struct eepro_local *)dev->priv;
+	struct eepro_local *lp = netdev_priv(dev);
 
 	return &lp->stats;
 }
@@ -1290,7 +1290,7 @@ eepro_get_stats(struct net_device *dev)
 static void
 set_multicast_list(struct net_device *dev)
 {
-	struct eepro_local *lp = (struct eepro_local *)dev->priv;
+	struct eepro_local *lp = netdev_priv(dev);
 	short ioaddr = dev->base_addr;
 	unsigned short mode;
 	struct dev_mc_list *dmi=dev->mc_list;
@@ -1424,7 +1424,7 @@ read_eeprom(int ioaddr, int location, st
 {
 	int i;
 	unsigned short retval = 0;
-	struct eepro_local *lp = dev->priv;
+	struct eepro_local *lp = netdev_priv(dev);
 	short ee_addr = ioaddr + lp->eeprom_reg;
 	int read_cmd = location | EE_READ_CMD;
 	short ctrl_val = EECS ;
@@ -1468,7 +1468,7 @@ read_eeprom(int ioaddr, int location, st
 static int
 hardware_send_packet(struct net_device *dev, void *buf, short length)
 {
-	struct eepro_local *lp = (struct eepro_local *)dev->priv;
+	struct eepro_local *lp = netdev_priv(dev);
 	short ioaddr = dev->base_addr;
 	unsigned status, tx_available, last, end;
 
@@ -1553,7 +1553,7 @@ hardware_send_packet(struct net_device *
 static void
 eepro_rx(struct net_device *dev)
 {
-	struct eepro_local *lp = (struct eepro_local *)dev->priv;
+	struct eepro_local *lp = netdev_priv(dev);
 	short ioaddr = dev->base_addr;
 	short boguscount = 20;
 	short rcv_car = lp->rx_start;
@@ -1651,7 +1651,7 @@ eepro_rx(struct net_device *dev)
 static void
 eepro_transmit_interrupt(struct net_device *dev)
 {
-	struct eepro_local *lp = (struct eepro_local *)dev->priv;
+	struct eepro_local *lp = netdev_priv(dev);
 	short ioaddr = dev->base_addr;
 	short boguscount = 25; 
 	short xmt_status;
--- diff/drivers/net/eepro100.c	2003-10-09 08:47:16.000000000 +0000
+++ source/drivers/net/eepro100.c	2004-03-16 09:37:56.122008328 +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)
 {
@@ -839,7 +856,7 @@ static int __devinit speedo_found1(struc
 
 	dev->irq = pdev->irq;
 
-	sp = dev->priv;
+	sp = netdev_priv(dev);
 	sp->pdev = pdev;
 	sp->msg_enable = DEBUG;
 	sp->acpi_pwr = 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;
@@ -995,7 +1015,7 @@ static void mdio_write(struct net_device
 static int
 speedo_open(struct net_device *dev)
 {
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int retval;
 
@@ -1082,7 +1102,7 @@ speedo_open(struct net_device *dev)
 /* Start the chip hardware after a full reset. */
 static void speedo_resume(struct net_device *dev)
 {
-	struct speedo_private *sp = dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	/* Start with a Tx threshold of 256 (0x..20.... 8 byte units). */
@@ -1162,7 +1182,7 @@ static void speedo_resume(struct net_dev
 static void
 speedo_rx_soft_reset(struct net_device *dev)
 {
-	struct speedo_private *sp = dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	struct RxFD *rfd;
 	long ioaddr;
 
@@ -1194,7 +1214,7 @@ speedo_rx_soft_reset(struct net_device *
 static void speedo_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int phy_num = sp->phy[0] & 0x1f;
 
@@ -1239,7 +1259,7 @@ static void speedo_timer(unsigned long d
 
 static void speedo_show_state(struct net_device *dev)
 {
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	int i;
 
 	if (netif_msg_pktdata(sp)) {
@@ -1282,7 +1302,7 @@ static void speedo_show_state(struct net
 static void
 speedo_init_rx_ring(struct net_device *dev)
 {
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	struct RxFD *rxf, *last_rxf = NULL;
 	dma_addr_t last_rxf_dma = 0 /* to shut up the compiler */;
 	int i;
@@ -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,21 +1336,21 @@ 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;
 }
 
 static void speedo_purge_tx(struct net_device *dev)
 {
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	int entry;
 
 	while ((int)(sp->cur_tx - sp->dirty_tx) > 0) {
@@ -1362,7 +1382,7 @@ static void speedo_purge_tx(struct net_d
 
 static void reset_mii(struct net_device *dev)
 {
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 
 	/* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */
 	if ((sp->phy[0] & 0x8000) == 0) {
@@ -1385,7 +1405,7 @@ static void reset_mii(struct net_device 
 
 static void speedo_tx_timeout(struct net_device *dev)
 {
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int status = inw(ioaddr + SCBStatus);
 	unsigned long flags;
@@ -1447,7 +1467,7 @@ static void speedo_tx_timeout(struct net
 static int
 speedo_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int entry;
 
@@ -1518,7 +1538,7 @@ speedo_start_xmit(struct sk_buff *skb, s
 static void speedo_tx_buffer_gc(struct net_device *dev)
 {
 	unsigned int dirty_tx;
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 
 	dirty_tx = sp->dirty_tx;
 	while ((int)(sp->cur_tx - dirty_tx) > 0) {
@@ -1585,7 +1605,7 @@ static irqreturn_t speedo_interrupt(int 
 	unsigned int handled = 0;
 
 	ioaddr = dev->base_addr;
-	sp = (struct speedo_private *)dev->priv;
+	sp = netdev_priv(dev);
 
 #ifndef final_version
 	/* A lock to prevent simultaneous entry on SMP machines. */
@@ -1677,7 +1697,7 @@ static irqreturn_t speedo_interrupt(int 
 
 static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry)
 {
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	struct RxFD *rxf;
 	struct sk_buff *skb;
 	/* Get a fresh skbuff to replace the consumed one. */
@@ -1696,29 +1716,29 @@ 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;
 }
 
 static inline void speedo_rx_link(struct net_device *dev, int entry,
 								  struct RxFD *rxf, dma_addr_t rxf_dma)
 {
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	rxf->status = cpu_to_le32(0xC0000001); 	/* '1' for driver use only. */
 	rxf->link = 0;			/* None yet. */
 	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;
 }
 
 static int speedo_refill_rx_buf(struct net_device *dev, int force)
 {
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	int entry;
 	struct RxFD *rxf;
 
@@ -1760,7 +1780,7 @@ static int speedo_refill_rx_buf(struct n
 
 static void speedo_refill_rx_buffers(struct net_device *dev, int force)
 {
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 
 	/* Refill the RX ring. */
 	while ((int)(sp->cur_rx - sp->dirty_rx) > 0 &&
@@ -1770,7 +1790,7 @@ static void speedo_refill_rx_buffers(str
 static int
 speedo_rx(struct net_device *dev)
 {
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	int entry = sp->cur_rx % RX_RING_SIZE;
 	int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx;
 	int alloc_ok = 1;
@@ -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);
@@ -1884,7 +1909,7 @@ static int
 speedo_close(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	int i;
 
 	netdevice_stop(dev);
@@ -1962,7 +1987,7 @@ speedo_close(struct net_device *dev)
 static struct net_device_stats *
 speedo_get_stats(struct net_device *dev)
 {
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	/* Update only if the previous dump finished. */
@@ -1995,7 +2020,7 @@ speedo_get_stats(struct net_device *dev)
 static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
 {
 	u32 ethcmd;
-	struct speedo_private *sp = dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 		
 	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
 		return -EFAULT;
@@ -2070,7 +2095,7 @@ static int netdev_ethtool_ioctl(struct n
 
 static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
 	int phy = sp->phy[0] & 0x1f;
 	int saved_acpi;
@@ -2121,7 +2146,7 @@ static int speedo_ioctl(struct net_devic
 */
 static void set_rx_mode(struct net_device *dev)
 {
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	struct descriptor *last_cmd;
 	char new_rx_mode;
@@ -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);
@@ -2313,7 +2338,7 @@ static void set_rx_mode(struct net_devic
 static int eepro100_suspend(struct pci_dev *pdev, u32 state)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	pci_save_state(pdev, sp->pm_state);
@@ -2333,7 +2358,7 @@ static int eepro100_suspend(struct pci_d
 static int eepro100_resume(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	pci_restore_state(pdev, sp->pm_state);
@@ -2363,7 +2388,7 @@ static int eepro100_resume(struct pci_de
 static void __devexit eepro100_remove_one (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = netdev_priv(dev);
 	
 	unregister_netdev(dev);
 
--- diff/drivers/net/eexpress.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/eexpress.c	2004-03-16 09:37:56.124008024 +0000
@@ -452,7 +452,7 @@ static int eexp_open(struct net_device *
 {
 	int ret;
 	unsigned short ioaddr = dev->base_addr;
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 #if NET_DEBUG > 6
 	printk(KERN_DEBUG "%s: eexp_open()\n", dev->name);
@@ -515,7 +515,7 @@ static int eexp_open(struct net_device *
 static int eexp_close(struct net_device *dev)
 {
 	unsigned short ioaddr = dev->base_addr;
-	struct net_local *lp = dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	int irq = dev->irq;
 
@@ -541,7 +541,7 @@ static int eexp_close(struct net_device 
 
 static struct net_device_stats *eexp_stats(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	return &lp->stats;
 }
@@ -553,7 +553,7 @@ static struct net_device_stats *eexp_sta
 
 static void unstick_cu(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned short ioaddr = dev->base_addr;
 
 	if (lp->started)
@@ -627,7 +627,7 @@ static void unstick_cu(struct net_device
 
 static void eexp_timeout(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 #ifdef CONFIG_SMP
 	unsigned long flags;
 #endif
@@ -667,7 +667,7 @@ static void eexp_timeout(struct net_devi
  */
 static int eexp_xmit(struct sk_buff *buf, struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	short length = buf->len;
 #ifdef CONFIG_SMP
 	unsigned long flags;
@@ -728,7 +728,7 @@ static unsigned short eexp_start_irq(str
 				     unsigned short status)
 {
 	unsigned short ack_cmd = SCB_ack(status);
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned short ioaddr = dev->base_addr;
 	if ((dev->flags & IFF_UP) && !(lp->started & STARTED_CU)) {
 		short diag_status, tdr_status;
@@ -806,7 +806,7 @@ static irqreturn_t eexp_irq(int irq, voi
 		return IRQ_NONE;
 	}
 
-	lp = (struct net_local *)dev->priv;
+	lp = netdev_priv(dev);
 	ioaddr = dev->base_addr;
 
 	spin_lock(&lp->lock);
@@ -925,7 +925,7 @@ static void eexp_hw_set_interface(struct
 
 static void eexp_hw_rx_pio(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned short rx_block = lp->rx_ptr;
 	unsigned short boguscount = lp->num_rx_bufs;
 	unsigned short ioaddr = dev->base_addr;
@@ -1022,7 +1022,7 @@ static void eexp_hw_rx_pio(struct net_de
 static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
 		       unsigned short len)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned short ioaddr = dev->base_addr;
 
 	if (LOCKUP16 || lp->width) {
@@ -1090,7 +1090,7 @@ static int __init eexp_hw_probe(struct n
 	unsigned int memory_size;
 	int i;
 	unsigned short xsum = 0;
-	struct net_local *lp = dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	printk("%s: EtherExpress 16 at %#x ",dev->name,ioaddr);
 
@@ -1262,7 +1262,7 @@ static unsigned short __init eexp_hw_rea
 
 static unsigned short eexp_hw_lasttxstat(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned short tx_block = lp->tx_reap;
 	unsigned short status;
 
@@ -1332,7 +1332,7 @@ static unsigned short eexp_hw_lasttxstat
 
 static void eexp_hw_txrestart(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned short ioaddr = dev->base_addr;
 
 	lp->last_tx_restart = lp->tx_link;
@@ -1377,7 +1377,7 @@ static void eexp_hw_txrestart(struct net
 
 static void eexp_hw_txinit(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned short tx_block = TX_BUF_START;
 	unsigned short curtbuf;
 	unsigned short ioaddr = dev->base_addr;
@@ -1419,7 +1419,7 @@ static void eexp_hw_txinit(struct net_de
 
 static void eexp_hw_rxinit(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned short rx_block = lp->rx_buf_start;
 	unsigned short ioaddr = dev->base_addr;
 
@@ -1478,7 +1478,7 @@ static void eexp_hw_rxinit(struct net_de
 
 static void eexp_hw_init586(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned short ioaddr = dev->base_addr;
 	int i;
 
@@ -1639,7 +1639,7 @@ static void
 eexp_set_multicast(struct net_device *dev)
 {
         unsigned short ioaddr = dev->base_addr;
-        struct net_local *lp = (struct net_local *)dev->priv;
+        struct net_local *lp = netdev_priv(dev);
         int kick = 0, i;
         if ((dev->flags & IFF_PROMISC) != lp->was_promisc) {
                 outw(CONF_PROMISC & ~31, ioaddr+SM_PTR);
--- diff/drivers/net/epic100.c	2003-09-17 11:28:07.000000000 +0000
+++ source/drivers/net/epic100.c	2004-03-16 09:37:56.125007872 +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-16 09:37:56.126007720 +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/eth16i.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/eth16i.c	2004-03-16 09:37:56.127007568 +0000
@@ -486,7 +486,7 @@ out:
 
 static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
 {
-	struct eth16i_local *lp = dev->priv;
+	struct eth16i_local *lp = netdev_priv(dev);
 	static unsigned version_printed;
 	int retval;
 
@@ -950,7 +950,7 @@ static void eth16i_eeprom_cmd(int ioaddr
 
 static int eth16i_open(struct net_device *dev)
 {
-	struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+	struct eth16i_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	
 	/* Powerup the chip */
@@ -986,7 +986,7 @@ static int eth16i_open(struct net_device
 
 static int eth16i_close(struct net_device *dev)
 {
-	struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+	struct eth16i_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	eth16i_reset(dev);
@@ -1012,7 +1012,7 @@ static int eth16i_close(struct net_devic
 
 static void eth16i_timeout(struct net_device *dev)
 {
-	struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+	struct eth16i_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	/* 
 	   If we get here, some higher level has decided that 
@@ -1053,7 +1053,7 @@ static void eth16i_timeout(struct net_de
 
 static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+	struct eth16i_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	int status = 0;
 	ushort length = skb->len;
@@ -1130,7 +1130,7 @@ static int eth16i_tx(struct sk_buff *skb
 
 static void eth16i_rx(struct net_device *dev)
 {
-	struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+	struct eth16i_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	int boguscount = MAX_RX_LOOP;
 
@@ -1232,7 +1232,7 @@ static irqreturn_t eth16i_interrupt(int 
 	int handled = 0;
 
 	ioaddr = dev->base_addr;
-	lp = (struct eth16i_local *)dev->priv;
+	lp = netdev_priv(dev);
 
 	/* Turn off all interrupts from adapter */
 	outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
@@ -1340,7 +1340,7 @@ static void eth16i_skip_packet(struct ne
 
 static void eth16i_reset(struct net_device *dev)
 {
-	struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+	struct eth16i_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	if(eth16i_debug > 1) 
@@ -1372,7 +1372,7 @@ static void eth16i_multicast(struct net_
 
 static struct net_device_stats *eth16i_get_stats(struct net_device *dev)
 {
-	struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+	struct eth16i_local *lp = netdev_priv(dev);
 	return &lp->stats;
 }
 
--- diff/drivers/net/ethertap.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/ethertap.c	2004-03-16 09:37:56.128007416 +0000
@@ -121,7 +121,7 @@ out:
 
 static int ethertap_open(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local*)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	if (ethertap_debug > 2)
 		printk(KERN_DEBUG "%s: Doing ethertap_open()...", dev->name);
@@ -150,7 +150,7 @@ static unsigned ethertap_mc_hash(__u8 *d
 static void set_multicast_list(struct net_device *dev)
 {
 	unsigned groups = ~0;
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	if (!(dev->flags&(IFF_NOARP|IFF_PROMISC|IFF_ALLMULTI))) {
 		struct dev_mc_list *dmi;
@@ -176,7 +176,7 @@ static void set_multicast_list(struct ne
  
 static int ethertap_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 #ifdef CONFIG_ETHERTAP_MC
 	struct ethhdr *eth = (struct ethhdr*)skb->data;
 #endif
@@ -234,7 +234,7 @@ static int ethertap_start_xmit(struct sk
 
 static __inline__ int ethertap_rx_skb(struct sk_buff *skb, struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 #ifdef CONFIG_ETHERTAP_MC
 	struct ethhdr *eth = (struct ethhdr*)(skb->data + 2);
 #endif
@@ -320,7 +320,7 @@ static void ethertap_rx(struct sock *sk,
 
 static int ethertap_close(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	struct sock *sk = lp->nl;
 
 	if (ethertap_debug > 2)
@@ -338,7 +338,7 @@ static int ethertap_close(struct net_dev
 
 static struct net_device_stats *ethertap_get_stats(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	return &lp->stats;
 }
 
--- diff/drivers/net/fc/iph5526.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/net/fc/iph5526.c	2004-03-16 09:37:56.132006808 +0000
@@ -238,7 +238,7 @@ int __init iph5526_probe(struct net_devi
 
 static int __init iph5526_probe_pci(struct net_device *dev)
 {
-	struct fc_info *fi = (struct fc_info *)dev->priv;
+	struct fc_info *fi = netdev_priv(dev);
 	fi->dev = dev;
 	dev->base_addr = fi->base_addr;
 	dev->irq = fi->irq;
@@ -2908,7 +2908,7 @@ static int iph5526_close(struct net_devi
 
 static void iph5526_timeout(struct net_device *dev)
 {
-	struct fc_info *fi = (struct fc_info*)dev->priv;
+	struct fc_info *fi = netdev_priv(dev);
 	printk(KERN_WARNING "%s: timed out on send.\n", dev->name);
 	fi->fc_stats.rx_dropped++;
 	dev->trans_start = jiffies;
@@ -2917,7 +2917,7 @@ static void iph5526_timeout(struct net_d
 
 static int iph5526_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct fc_info *fi = (struct fc_info*)dev->priv;
+	struct fc_info *fi = netdev_priv(dev);
 	int status = 0;
 	short type = 0;
 	u_long flags;
@@ -3688,7 +3688,7 @@ int count = 0, j;
 
 static struct net_device_stats * iph5526_get_stats(struct net_device *dev)
 {	
-struct fc_info *fi = (struct fc_info*)dev->priv; 
+struct fc_info *fi = netdev_priv(dev);
 	return (struct net_device_stats *) &fi->fc_stats;
 }
 
--- diff/drivers/net/fealnx.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/fealnx.c	2004-03-16 09:37:56.133006656 +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/fec.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/net/fec.c	2004-03-16 09:37:56.135006352 +0000
@@ -269,7 +269,7 @@ fec_enet_start_xmit(struct sk_buff *skb,
 	volatile fec_t	*fecp;
 	volatile cbd_t	*bdp;
 
-	fep = dev->priv;
+	fep = netdev_priv(dev);
 	fecp = (volatile fec_t*)dev->base_addr;
 
 	if (!fep->link) {
@@ -349,7 +349,7 @@ fec_enet_start_xmit(struct sk_buff *skb,
 static void
 fec_timeout(struct net_device *dev)
 {
-	struct fec_enet_private *fep = dev->priv;
+	struct fec_enet_private *fep = netdev_priv(dev);
 
 	printk("%s: transmit timed out.\n", dev->name);
 	fep->stats.tx_errors++;
@@ -445,7 +445,7 @@ fec_enet_tx(struct net_device *dev)
 	volatile cbd_t	*bdp;
 	struct	sk_buff	*skb;
 
-	fep = dev->priv;
+	fep = netdev_priv(dev);
 	spin_lock(&fep->lock);
 	bdp = fep->dirty_tx;
 
@@ -524,7 +524,7 @@ fec_enet_rx(struct net_device *dev)
 	ushort	pkt_len;
 	__u8 *data;
 
-	fep = dev->priv;
+	fep = netdev_priv(dev);
 	fecp = (volatile fec_t*)dev->base_addr;
 
 	/* First, grab all of the stats for the incoming packet.
@@ -645,7 +645,7 @@ fec_enet_mii(struct net_device *dev)
 	mii_list_t	*mip;
 	uint		mii_reg;
 
-	fep = (struct fec_enet_private *)dev->priv;
+	fep = netdev_priv(dev);
 	ep = fec_hwp;
 	mii_reg = ep->fec_mii_data;
 	
@@ -675,7 +675,7 @@ mii_queue(struct net_device *dev, int re
 
 	/* Add PHY address to register command.
 	*/
-	fep = dev->priv;
+	fep = netdev_priv(dev);
 	regval |= fep->phy_addr << 23;
 
 	retval = 0;
@@ -720,7 +720,7 @@ static void mii_do_cmd(struct net_device
 
 static void mii_parse_sr(uint mii_reg, struct net_device *dev)
 {
-	struct fec_enet_private *fep = dev->priv;
+	struct fec_enet_private *fep = netdev_priv(dev);
 	volatile uint *s = &(fep->phy_status);
 
 	*s &= ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC);
@@ -735,7 +735,7 @@ static void mii_parse_sr(uint mii_reg, s
 
 static void mii_parse_cr(uint mii_reg, struct net_device *dev)
 {
-	struct fec_enet_private *fep = dev->priv;
+	struct fec_enet_private *fep = netdev_priv(dev);
 	volatile uint *s = &(fep->phy_status);
 
 	*s &= ~(PHY_CONF_ANE | PHY_CONF_LOOP);
@@ -748,7 +748,7 @@ static void mii_parse_cr(uint mii_reg, s
 
 static void mii_parse_anar(uint mii_reg, struct net_device *dev)
 {
-	struct fec_enet_private *fep = dev->priv;
+	struct fec_enet_private *fep = netdev_priv(dev);
 	volatile uint *s = &(fep->phy_status);
 
 	*s &= ~(PHY_CONF_SPMASK);
@@ -774,7 +774,7 @@ static void mii_parse_anar(uint mii_reg,
 
 static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev)
 {
-	struct fec_enet_private *fep = dev->priv;
+	struct fec_enet_private *fep = netdev_priv(dev);
 	volatile uint *s = &(fep->phy_status);
 
 	*s &= ~(PHY_STAT_SPMASK);
@@ -841,7 +841,7 @@ static phy_info_t phy_info_lxt970 = {
 
 static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev)
 {
-	struct fec_enet_private *fep = dev->priv;
+	struct fec_enet_private *fep = netdev_priv(dev);
 	volatile uint *s = &(fep->phy_status);
 
 	*s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC);
@@ -919,7 +919,7 @@ static phy_info_t phy_info_lxt971 = {
 
 static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev)
 {
-	struct fec_enet_private *fep = dev->priv;
+	struct fec_enet_private *fep = netdev_priv(dev);
 	volatile uint *s = &(fep->phy_status);
 
 	*s &= ~(PHY_STAT_SPMASK);
@@ -983,7 +983,7 @@ static phy_info_t phy_info_qs6612 = {
 
 static void mii_parse_am79c874_dr(uint mii_reg, struct net_device *dev)
 {
-	struct fec_enet_private *fep = dev->priv;
+	struct fec_enet_private *fep = netdev_priv(dev);
 	volatile uint *s = &(fep->phy_status);
 
 	*s &= ~(PHY_STAT_SPMASK | PHY_STAT_ANC);
@@ -1280,7 +1280,7 @@ static void __inline__ fec_uncache(unsig
 
 static void mii_display_status(struct net_device *dev)
 {
-	struct fec_enet_private *fep = dev->priv;
+	struct fec_enet_private *fep = netdev_priv(dev);
 	volatile uint *s = &(fep->phy_status);
 
 	if (!fep->link && !fep->old_link) {
@@ -1316,7 +1316,7 @@ static void mii_display_status(struct ne
 
 static void mii_display_config(struct net_device *dev)
 {
-	struct fec_enet_private *fep = dev->priv;
+	struct fec_enet_private *fep = netdev_priv(dev);
 	volatile uint *s = &(fep->phy_status);
 
 	printk("%s: config: auto-negotiation ", dev->name);
@@ -1347,7 +1347,7 @@ static void mii_display_config(struct ne
 
 static void mii_relink(struct net_device *dev)
 {
-	struct fec_enet_private *fep = dev->priv;
+	struct fec_enet_private *fep = netdev_priv(dev);
 	int duplex;
 
 	fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0;
@@ -1372,7 +1372,7 @@ static void mii_relink(struct net_device
 
 static void mii_queue_relink(uint mii_reg, struct net_device *dev)
 {
-	struct fec_enet_private *fep = dev->priv;
+	struct fec_enet_private *fep = netdev_priv(dev);
 
 	INIT_WORK(&fep->phy_task, (void*)mii_relink, dev);
 	schedule_work(&fep->phy_task);
@@ -1380,7 +1380,7 @@ static void mii_queue_relink(uint mii_re
 
 static void mii_queue_config(uint mii_reg, struct net_device *dev)
 {
-	struct fec_enet_private *fep = dev->priv;
+	struct fec_enet_private *fep = netdev_priv(dev);
 
 	INIT_WORK(&fep->phy_task, (void*)mii_display_config, dev);
 	schedule_work(&fep->phy_task);
@@ -1403,7 +1403,7 @@ mii_discover_phy3(uint mii_reg, struct n
 	struct fec_enet_private *fep;
 	int	i;
 
-	fep = dev->priv;
+	fep = netdev_priv(dev);
 	fep->phy_id |= (mii_reg & 0xffff);
 	printk("fec: PHY @ 0x%x, ID 0x%08x", fep->phy_addr, fep->phy_id);
 
@@ -1431,7 +1431,7 @@ mii_discover_phy(uint mii_reg, struct ne
 	volatile fec_t *fecp;
 	uint phytype;
 
-	fep = dev->priv;
+	fep = netdev_priv(dev);
 	fecp = fec_hwp;
 
 	if (fep->phy_addr < 32) {
@@ -1466,7 +1466,7 @@ mii_link_interrupt(int irq, void * dev_i
 #endif
 {
 	struct	net_device *dev = dev_id;
-	struct fec_enet_private *fep = dev->priv;
+	struct fec_enet_private *fep = netdev_priv(dev);
 
 	fec_phy_ack_intr();
 
@@ -1482,7 +1482,7 @@ mii_link_interrupt(int irq, void * dev_i
 static int
 fec_enet_open(struct net_device *dev)
 {
-	struct fec_enet_private *fep = dev->priv;
+	struct fec_enet_private *fep = netdev_priv(dev);
 
 	/* I should reset the ring buffers here, but I don't yet know
 	 * a simple way to do that.
@@ -1531,7 +1531,7 @@ fec_enet_close(struct net_device *dev)
 
 static struct net_device_stats *fec_enet_get_stats(struct net_device *dev)
 {
-	struct fec_enet_private *fep = (struct fec_enet_private *)dev->priv;
+	struct fec_enet_private *fep = netdev_priv(dev);
 
 	return &fep->stats;
 }
@@ -1557,7 +1557,7 @@ static void set_multicast_list(struct ne
 	unsigned int i, j, bit, data, crc;
 	unsigned char hash;
 
-	fep = (struct fec_enet_private *)dev->priv;
+	fep = netdev_priv(dev);
 	ep = fec_hwp;
 
 	if (dev->flags&IFF_PROMISC) {
@@ -1643,7 +1643,7 @@ fec_set_mac_address(struct net_device *d
   */
 int __init fec_enet_init(struct net_device *dev)
 {
-	struct fec_enet_private *fep = dev->priv;
+	struct fec_enet_private *fep = netdev_priv(dev);
 	unsigned long	mem_addr;
 	volatile cbd_t	*bdp;
 	cbd_t		*cbd_base;
@@ -1807,7 +1807,7 @@ fec_restart(struct net_device *dev, int 
 
 	fecp = fec_hwp;
 
-	fep = dev->priv;
+	fep = netdev_priv(dev);
 
 	/* Whack a reset.  We should wait for this.
 	*/
@@ -1924,7 +1924,7 @@ fec_stop(struct net_device *dev)
 	struct fec_enet_private *fep;
 
 	fecp = fec_hwp;
-	fep = dev->priv;
+	fep = netdev_priv(dev);
 
 	fecp->fec_x_cntrl = 0x01;	/* Graceful transmit stop */
 
--- diff/drivers/net/forcedeth.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/forcedeth.c	2004-03-16 09:37:56.138005896 +0000
@@ -11,6 +11,7 @@
  * countries.
  *
  * Copyright (C) 2003 Manfred Spraul
+ * Copyright (C) 2004 Andrew de Quincey (wol support)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -28,7 +29,7 @@
  *
  * Changelog:
  * 	0.01: 05 Oct 2003: First release that compiles without warnings.
- * 	0.02: 05 Oct 2003: Fix bug for drain_tx: do not try to free NULL skbs.
+ * 	0.02: 05 Oct 2003: Fix bug for nv_drain_tx: do not try to free NULL skbs.
  * 			   Check all PCI BARs for the register window.
  * 			   udelay added to mii_rw.
  * 	0.03: 06 Oct 2003: Initialize dev->irq.
@@ -37,7 +38,7 @@
  * 	0.06: 10 Oct 2003: MAC Address read updated, pff flag generation updated,
  * 			   irq mask updated
  * 	0.07: 14 Oct 2003: Further irq mask updates.
- * 	0.08: 20 Oct 2003: rx_desc.Length initialization added, alloc_rx refill
+ * 	0.08: 20 Oct 2003: rx_desc.Length initialization added, nv_alloc_rx refill
  * 			   added into irq handler, NULL check for drain_ring.
  * 	0.09: 20 Oct 2003: Basic link speed irq implementation. Only handle the
  * 			   requested interrupt sources.
@@ -47,7 +48,7 @@
  * 	0.12: 23 Oct 2003: Cleanups for release.
  * 	0.13: 25 Oct 2003: Limit for concurrent tx packets increased to 10.
  * 			   Set link speed correctly. start rx before starting
- * 			   tx (start_rx sets the link speed).
+ * 			   tx (nv_start_rx sets the link speed).
  * 	0.14: 25 Oct 2003: Nic dependant irq mask.
  * 	0.15: 08 Nov 2003: fix smp deadlock with set_multicast_list during
  * 			   open.
@@ -58,7 +59,7 @@
  * 	0.18: 17 Nov 2003: fix oops due to late initialization of dev_stats
  * 	0.19: 29 Nov 2003: Handle RxNoBuf, detect & handle invalid mac
  * 			   addresses, really stop rx if already running
- * 			   in start_rx, clean up a bit.
+ * 			   in nv_start_rx, clean up a bit.
  * 				(C) Carl-Daniel Hailfinger
  * 	0.20: 07 Dec 2003: alloc fixes
  * 	0.21: 12 Jan 2004: additional alloc fix, nic polling fix.
@@ -66,6 +67,8 @@
  * 			   on close.
  * 				(C) Carl-Daniel Hailfinger, Manfred Spraul
  *	0.23: 26 Jan 2004: various small cleanups
+ *	0.24: 27 Feb 2004: make driver even less anonymous in backtraces
+ *	0.25: 09 Mar 2004: wol support
  *
  * Known bugs:
  * We suspect that on some hardware no TX done interrupts are generated.
@@ -77,7 +80,7 @@
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * superfluous timer interrupts from the nic.
  */
-#define FORCEDETH_VERSION		"0.23"
+#define FORCEDETH_VERSION		"0.25"
 
 #include <linux/module.h>
 #include <linux/types.h>
@@ -232,6 +235,7 @@ enum {
 #define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT		0x01
 #define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT	0x02
 #define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE	0x04
+#define NVREG_WAKEUPFLAGS_ENABLE	0x1111
 
 	NvRegPatternCRC = 0x204,
 	NvRegPatternMask = 0x208,
@@ -340,6 +344,7 @@ struct fe_priv {
 	u32 linkspeed;
 	int duplex;
 	int phyaddr;
+	int wolenabled;
 
 	/* General data: RO fields */
 	dma_addr_t ring_addr;
@@ -468,12 +473,12 @@ static int mii_rw(struct net_device *dev
 	return retval;
 }
 
-static void start_rx(struct net_device *dev)
+static void nv_start_rx(struct net_device *dev)
 {
 	struct fe_priv *np = get_nvpriv(dev);
 	u8 *base = get_hwbase(dev);
 
-	dprintk(KERN_DEBUG "%s: start_rx\n", dev->name);
+	dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name);
 	/* Already running? Stop it. */
 	if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) {
 		writel(0, base + NvRegReceiverControl);
@@ -485,48 +490,48 @@ static void start_rx(struct net_device *
 	pci_push(base);
 }
 
-static void stop_rx(struct net_device *dev)
+static void nv_stop_rx(struct net_device *dev)
 {
 	u8 *base = get_hwbase(dev);
 
-	dprintk(KERN_DEBUG "%s: stop_rx\n", dev->name);
+	dprintk(KERN_DEBUG "%s: nv_stop_rx\n", dev->name);
 	writel(0, base + NvRegReceiverControl);
 	reg_delay(dev, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0,
 		       NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX,
-		       KERN_INFO "stop_rx: ReceiverStatus remained busy");
+		       KERN_INFO "nv_stop_rx: ReceiverStatus remained busy");
 
 	udelay(NV_RXSTOP_DELAY2);
 	writel(0, base + NvRegLinkSpeed);
 }
 
-static void start_tx(struct net_device *dev)
+static void nv_start_tx(struct net_device *dev)
 {
 	u8 *base = get_hwbase(dev);
 
-	dprintk(KERN_DEBUG "%s: start_tx\n", dev->name);
+	dprintk(KERN_DEBUG "%s: nv_start_tx\n", dev->name);
 	writel(NVREG_XMITCTL_START, base + NvRegTransmitterControl);
 	pci_push(base);
 }
 
-static void stop_tx(struct net_device *dev)
+static void nv_stop_tx(struct net_device *dev)
 {
 	u8 *base = get_hwbase(dev);
 
-	dprintk(KERN_DEBUG "%s: stop_tx\n", dev->name);
+	dprintk(KERN_DEBUG "%s: nv_stop_tx\n", dev->name);
 	writel(0, base + NvRegTransmitterControl);
 	reg_delay(dev, NvRegTransmitterStatus, NVREG_XMITSTAT_BUSY, 0,
 		       NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX,
-		       KERN_INFO "stop_tx: TransmitterStatus remained busy");
+		       KERN_INFO "nv_stop_tx: TransmitterStatus remained busy");
 
 	udelay(NV_TXSTOP_DELAY2);
 	writel(0, base + NvRegUnknownTransmitterReg);
 }
 
-static void txrx_reset(struct net_device *dev)
+static void nv_txrx_reset(struct net_device *dev)
 {
 	u8 *base = get_hwbase(dev);
 
-	dprintk(KERN_DEBUG "%s: txrx_reset\n", dev->name);
+	dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name);
 	writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET, base + NvRegTxRxControl);
 	pci_push(base);
 	udelay(NV_TXRX_RESET_DELAY);
@@ -551,9 +556,10 @@ static struct net_device_stats *nv_get_s
 	return &np->stats;
 }
 
-static int nv_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static int nv_ethtool_ioctl(struct net_device *dev, void *useraddr)
 {
 	struct fe_priv *np = get_nvpriv(dev);
+	u8 *base = get_hwbase(dev);
 	u32 ethcmd;
 
 	if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
@@ -580,6 +586,39 @@ static int nv_ethtool_ioctl (struct net_
 			return -EFAULT;
 		return 0;
 	}
+	case ETHTOOL_GWOL:
+	{
+		struct ethtool_wolinfo wolinfo;
+		memset(&wolinfo, 0, sizeof(wolinfo));
+		wolinfo.supported = WAKE_MAGIC;
+
+		spin_lock_irq(&np->lock);
+		if (np->wolenabled)
+			wolinfo.wolopts = WAKE_MAGIC;
+		spin_unlock_irq(&np->lock);
+
+		if (copy_to_user(useraddr, &wolinfo, sizeof(wolinfo)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SWOL:
+	{
+		struct ethtool_wolinfo wolinfo;
+		if (copy_from_user(&wolinfo, useraddr, sizeof(wolinfo)))
+			return -EFAULT;
+
+		spin_lock_irq(&np->lock);
+		if (wolinfo.wolopts == 0) {
+			writel(0, base + NvRegWakeUpFlags);
+			np->wolenabled = 0;
+		}
+		if (wolinfo.wolopts & WAKE_MAGIC) {
+			writel(NVREG_WAKEUPFLAGS_ENABLE, base + NvRegWakeUpFlags);
+			np->wolenabled = 1;
+		}
+		spin_unlock_irq(&np->lock);
+		return 0;
+	}
 
 	default:
 		break;
@@ -603,11 +642,11 @@ static int nv_ioctl(struct net_device *d
 }
 
 /*
- * alloc_rx: fill rx ring entries.
+ * nv_alloc_rx: fill rx ring entries.
  * Return 1 if the allocations for the skbs failed and the
  * rx engine is without Available descriptors
  */
-static int alloc_rx(struct net_device *dev)
+static int nv_alloc_rx(struct net_device *dev)
 {
 	struct fe_priv *np = get_nvpriv(dev);
 	unsigned int refill_rx = np->refill_rx;
@@ -633,7 +672,7 @@ static int alloc_rx(struct net_device *d
 		np->rx_ring[nr].Length = cpu_to_le16(RX_NIC_BUFSIZE);
 		wmb();
 		np->rx_ring[nr].Flags = cpu_to_le16(NV_RX_AVAIL);
-		dprintk(KERN_DEBUG "%s: alloc_rx: Packet  %d marked as Available\n",
+		dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet  %d marked as Available\n",
 					dev->name, refill_rx);
 		refill_rx++;
 	}
@@ -643,13 +682,13 @@ static int alloc_rx(struct net_device *d
 	return 0;
 }
 
-static void do_rx_refill(unsigned long data)
+static void nv_do_rx_refill(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *) data;
 	struct fe_priv *np = get_nvpriv(dev);
 
 	disable_irq(dev->irq);
-	if (alloc_rx(dev)) {
+	if (nv_alloc_rx(dev)) {
 		spin_lock(&np->lock);
 		if (!np->in_shutdown)
 			mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
@@ -658,7 +697,7 @@ static void do_rx_refill(unsigned long d
 	enable_irq(dev->irq);
 }
 
-static int init_ring(struct net_device *dev)
+static int nv_init_ring(struct net_device *dev)
 {
 	struct fe_priv *np = get_nvpriv(dev);
 	int i;
@@ -673,10 +712,10 @@ static int init_ring(struct net_device *
 	for (i = 0; i < RX_RING; i++) {
 		np->rx_ring[i].Flags = 0;
 	}
-	return alloc_rx(dev);
+	return nv_alloc_rx(dev);
 }
 
-static void drain_tx(struct net_device *dev)
+static void nv_drain_tx(struct net_device *dev)
 {
 	struct fe_priv *np = get_nvpriv(dev);
 	int i;
@@ -693,7 +732,7 @@ static void drain_tx(struct net_device *
 	}
 }
 
-static void drain_rx(struct net_device *dev)
+static void nv_drain_rx(struct net_device *dev)
 {
 	struct fe_priv *np = get_nvpriv(dev);
 	int i;
@@ -712,8 +751,8 @@ static void drain_rx(struct net_device *
 
 static void drain_ring(struct net_device *dev)
 {
-	drain_tx(dev);
-	drain_rx(dev);
+	nv_drain_tx(dev);
+	nv_drain_rx(dev);
 }
 
 /*
@@ -759,11 +798,11 @@ static int nv_start_xmit(struct sk_buff 
 }
 
 /*
- * tx_done: check for completed packets, release the skbs.
+ * nv_tx_done: check for completed packets, release the skbs.
  *
  * Caller must own np->lock.
  */
-static void tx_done(struct net_device *dev)
+static void nv_tx_done(struct net_device *dev)
 {
 	struct fe_priv *np = get_nvpriv(dev);
 
@@ -773,7 +812,7 @@ static void tx_done(struct net_device *d
 
 		prd = &np->tx_ring[i];
 
-		dprintk(KERN_DEBUG "%s: tx_done: looking at packet %d, Flags 0x%x.\n",
+		dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n",
 					dev->name, np->nic_tx, prd->Flags);
 		if (prd->Flags & cpu_to_le16(NV_TX_VALID))
 			break;
@@ -814,26 +853,26 @@ static void nv_tx_timeout(struct net_dev
 	spin_lock_irq(&np->lock);
 
 	/* 1) stop tx engine */
-	stop_tx(dev);
+	nv_stop_tx(dev);
 
 	/* 2) check that the packets were not sent already: */
-	tx_done(dev);
+	nv_tx_done(dev);
 
 	/* 3) if there are dead entries: clear everything */
 	if (np->next_tx != np->nic_tx) {
 		printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name);
-		drain_tx(dev);
+		nv_drain_tx(dev);
 		np->next_tx = np->nic_tx = 0;
 		writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
 		netif_wake_queue(dev);
 	}
 
 	/* 4) restart tx engine */
-	start_tx(dev);
+	nv_start_tx(dev);
 	spin_unlock_irq(&np->lock);
 }
 
-static void rx_process(struct net_device *dev)
+static void nv_rx_process(struct net_device *dev)
 {
 	struct fe_priv *np = get_nvpriv(dev);
 
@@ -847,7 +886,7 @@ static void rx_process(struct net_device
 
 		i = np->cur_rx % RX_RING;
 		prd = &np->rx_ring[i];
-		dprintk(KERN_DEBUG "%s: rx_process: looking at packet %d, Flags 0x%x.\n",
+		dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n",
 					dev->name, np->cur_rx, prd->Flags);
 
 		if (prd->Flags & cpu_to_le16(NV_RX_AVAIL))
@@ -915,7 +954,7 @@ static void rx_process(struct net_device
 
 		skb_put(skb, len);
 		skb->protocol = eth_type_trans(skb, dev);
-		dprintk(KERN_DEBUG "%s: rx_process: packet %d with %d bytes, proto %d accepted.\n",
+		dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n",
 					dev->name, np->cur_rx, len, skb->protocol);
 		netif_rx(skb);
 		dev->last_rx = jiffies;
@@ -990,24 +1029,24 @@ static void nv_set_multicast(struct net_
 	addr[0] |= NVREG_MCASTADDRA_FORCE;
 	pff |= NVREG_PFF_ALWAYS;
 	spin_lock_irq(&np->lock);
-	stop_rx(dev);
+	nv_stop_rx(dev);
 	writel(addr[0], base + NvRegMulticastAddrA);
 	writel(addr[1], base + NvRegMulticastAddrB);
 	writel(mask[0], base + NvRegMulticastMaskA);
 	writel(mask[1], base + NvRegMulticastMaskB);
 	writel(pff, base + NvRegPacketFilterFlags);
-	start_rx(dev);
+	nv_start_rx(dev);
 	spin_unlock_irq(&np->lock);
 }
 
-static int update_linkspeed(struct net_device *dev)
+static int nv_update_linkspeed(struct net_device *dev)
 {
 	struct fe_priv *np = get_nvpriv(dev);
 	int adv, lpa, newls, newdup;
 
 	adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
 	lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ);
-	dprintk(KERN_DEBUG "%s: update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n",
+	dprintk(KERN_DEBUG "%s: nv_update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n",
 				dev->name, adv, lpa);
 
 	/* FIXME: handle parallel detection properly, handle gigabit ethernet */
@@ -1037,7 +1076,7 @@ static int update_linkspeed(struct net_d
 	return 0;
 }
 
-static void link_irq(struct net_device *dev)
+static void nv_link_irq(struct net_device *dev)
 {
 	struct fe_priv *np = get_nvpriv(dev);
 	u8 *base = get_hwbase(dev);
@@ -1050,29 +1089,29 @@ static void link_irq(struct net_device *
 
 	miival = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ);
 	if (miival & BMSR_ANEGCOMPLETE) {
-		update_linkspeed(dev);
+		nv_update_linkspeed(dev);
 
 		if (netif_carrier_ok(dev)) {
-			stop_rx(dev);
+			nv_stop_rx(dev);
 		} else {
 			netif_carrier_on(dev);
 			printk(KERN_INFO "%s: link up.\n", dev->name);
 		}
 		writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD),
 					base + NvRegMisc1);
-		start_rx(dev);
+		nv_start_rx(dev);
 	} else {
 		if (netif_carrier_ok(dev)) {
 			netif_carrier_off(dev);
 			printk(KERN_INFO "%s: link down.\n", dev->name);
-			stop_rx(dev);
+			nv_stop_rx(dev);
 		}
 		writel(np->linkspeed, base + NvRegLinkSpeed);
 		pci_push(base);
 	}
 }
 
-static irqreturn_t nic_irq(int foo, void *data, struct pt_regs *regs)
+static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) data;
 	struct fe_priv *np = get_nvpriv(dev);
@@ -1080,7 +1119,7 @@ static irqreturn_t nic_irq(int foo, void
 	u32 events;
 	int i;
 
-	dprintk(KERN_DEBUG "%s: nic_irq\n", dev->name);
+	dprintk(KERN_DEBUG "%s: nv_nic_irq\n", dev->name);
 
 	for (i=0; ; i++) {
 		events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;
@@ -1092,13 +1131,13 @@ static irqreturn_t nic_irq(int foo, void
 
 		if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) {
 			spin_lock(&np->lock);
-			tx_done(dev);
+			nv_tx_done(dev);
 			spin_unlock(&np->lock);
 		}
 
 		if (events & (NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) {
-			rx_process(dev);
-			if (alloc_rx(dev)) {
+			nv_rx_process(dev);
+			if (nv_alloc_rx(dev)) {
 				spin_lock(&np->lock);
 				if (!np->in_shutdown)
 					mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
@@ -1108,7 +1147,7 @@ static irqreturn_t nic_irq(int foo, void
 
 		if (events & NVREG_IRQ_LINK) {
 			spin_lock(&np->lock);
-			link_irq(dev);
+			nv_link_irq(dev);
 			spin_unlock(&np->lock);
 		}
 		if (events & (NVREG_IRQ_TX_ERR)) {
@@ -1127,31 +1166,32 @@ static irqreturn_t nic_irq(int foo, void
 
 			if (!np->in_shutdown)
 				mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
-			printk(KERN_DEBUG "%s: too many iterations (%d) in nic_irq.\n", dev->name, i);
+			printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
 			spin_unlock(&np->lock);
 			break;
 		}
 
 	}
-	dprintk(KERN_DEBUG "%s: nic_irq completed\n", dev->name);
+	dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name);
 
 	return IRQ_RETVAL(i);
 }
 
-static void do_nic_poll(unsigned long data)
+static void nv_do_nic_poll(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *) data;
 	struct fe_priv *np = get_nvpriv(dev);
 	u8 *base = get_hwbase(dev);
 
 	disable_irq(dev->irq);
+	/* FIXME: Do we need synchronize_irq(dev->irq) here? */
 	/*
 	 * reenable interrupts on the nic, we have to do this before calling
-	 * nic_irq because that may decide to do otherwise
+	 * nv_nic_irq because that may decide to do otherwise
 	 */
 	writel(np->irqmask, base + NvRegIrqMask);
 	pci_push(base);
-	nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL);
+	nv_nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL);
 	enable_irq(dev->irq);
 }
 
@@ -1173,12 +1213,12 @@ static int nv_open(struct net_device *de
 	writel(0, base + NvRegAdapterControl);
 	writel(0, base + NvRegLinkSpeed);
 	writel(0, base + NvRegUnknownTransmitterReg);
-	txrx_reset(dev);
+	nv_txrx_reset(dev);
 	writel(0, base + NvRegUnknownSetupReg6);
 
 	/* 2) initialize descriptor rings */
 	np->in_shutdown = 0;
-	oom = init_ring(dev);
+	oom = nv_init_ring(dev);
 
 	/* 3) set mac address */
 	{
@@ -1224,7 +1264,7 @@ static int nv_open(struct net_device *de
 		np->phyaddr = i;
 
 		spin_lock_irq(&np->lock);
-		update_linkspeed(dev);
+		nv_update_linkspeed(dev);
 		spin_unlock_irq(&np->lock);
 
 		break;
@@ -1279,7 +1319,7 @@ static int nv_open(struct net_device *de
 	writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
 	pci_push(base);
 
-	ret = request_irq(dev->irq, &nic_irq, SA_SHIRQ, dev->name, dev);
+	ret = request_irq(dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev);
 	if (ret)
 		goto out_drain;
 
@@ -1291,8 +1331,8 @@ static int nv_open(struct net_device *de
 	writel(0, base + NvRegMulticastMaskA);
 	writel(0, base + NvRegMulticastMaskB);
 	writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags);
-	start_rx(dev);
-	start_tx(dev);
+	nv_start_rx(dev);
+	nv_start_tx(dev);
 	netif_start_queue(dev);
 	if (oom)
 		mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
@@ -1326,8 +1366,8 @@ static int nv_close(struct net_device *d
 
 	netif_stop_queue(dev);
 	spin_lock_irq(&np->lock);
-	stop_tx(dev);
-	stop_rx(dev);
+	nv_stop_tx(dev);
+	nv_stop_rx(dev);
 	base = get_hwbase(dev);
 
 	/* disable interrupts on the nic or we will lock up */
@@ -1341,6 +1381,9 @@ static int nv_close(struct net_device *d
 
 	drain_ring(dev);
 
+	if (np->wolenabled)
+		nv_start_rx(dev);
+
 	/* FIXME: power down nic */
 
 	return 0;
@@ -1367,10 +1410,10 @@ static int __devinit nv_probe(struct pci
 
 	init_timer(&np->oom_kick);
 	np->oom_kick.data = (unsigned long) dev;
-	np->oom_kick.function = &do_rx_refill;	/* timer handler */
+	np->oom_kick.function = &nv_do_rx_refill;	/* timer handler */
 	init_timer(&np->nic_poll);
 	np->nic_poll.data = (unsigned long) dev;
-	np->nic_poll.function = &do_nic_poll;	/* timer handler */
+	np->nic_poll.function = &nv_do_nic_poll;	/* timer handler */
 
 	err = pci_enable_device(pci_dev);
 	if (err) {
@@ -1459,6 +1502,10 @@ static int __devinit nv_probe(struct pci
 			dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
 			dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
 
+	/* disable WOL */
+	writel(0, base + NvRegWakeUpFlags);
+	np->wolenabled = 0;
+
 	np->tx_flags = cpu_to_le16(NV_TX_LASTPACKET|NV_TX_LASTPACKET1|NV_TX_VALID);
 	if (id->driver_data & DEV_NEED_LASTPACKET1)
 		np->tx_flags |= cpu_to_le16(NV_TX_LASTPACKET1);
--- diff/drivers/net/gt96100eth.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/net/gt96100eth.c	2004-03-16 09:37:56.140005592 +0000
@@ -277,7 +277,7 @@ read_MII(int phy_addr, u32 reg)
 static void
 dump_tx_desc(int dbg_lvl, struct net_device *dev, int i)
 {
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
 	gt96100_td_t *td = &gp->tx_ring[i];
 
 	dbg(dbg_lvl, "Tx descriptor at 0x%08lx:\n", virt_to_phys(td));
@@ -292,7 +292,7 @@ dump_tx_desc(int dbg_lvl, struct net_dev
 static void
 dump_rx_desc(int dbg_lvl, struct net_device *dev, int i)
 {
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
 	gt96100_rd_t *rd = &gp->rx_ring[i];
 
 	dbg(dbg_lvl, "Rx descriptor at 0x%08lx:\n", virt_to_phys(rd));
@@ -332,7 +332,7 @@ write_MII(int phy_addr, u32 reg, u16 dat
 static void
 dump_tx_ring(struct net_device *dev)
 {
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
 	int i;
 
 	dbg(0, "%s: txno/txni/cnt=%d/%d/%d\n", __FUNCTION__,
@@ -345,7 +345,7 @@ dump_tx_ring(struct net_device *dev)
 static void
 dump_rx_ring(struct net_device *dev)
 {
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
 	int i;
 
 	dbg(0, "%s: rxno=%d\n", __FUNCTION__, gp->rx_next_out);
@@ -359,7 +359,7 @@ static void
 dump_MII(int dbg_lvl, struct net_device *dev)
 {
 	int i, val;
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
     
 	if (dbg_lvl <= GT96100_DEBUG) {
 		for (i=0; i<7; i++) {
@@ -419,7 +419,7 @@ dump_skb(int dbg_lvl, struct net_device 
 static int
 gt96100_add_hash_entry(struct net_device *dev, unsigned char* addr)
 {
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
 	//u16 hashResult, stmp;
 	//unsigned char ctmp, hash_ea[6];
 	u32 tblEntry1, tblEntry0, *tblEntryAddr;
@@ -544,7 +544,7 @@ update_stats(struct gt96100_private *gp)
 static void
 abort(struct net_device *dev, u32 abort_bits)
 {
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
 	int timedout = 100; // wait up to 100 msec for hard stop to complete
 
 	dbg(3, "%s\n", __FUNCTION__);
@@ -582,7 +582,7 @@ abort(struct net_device *dev, u32 abort_
 static void
 hard_stop(struct net_device *dev)
 {
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
 
 	dbg(3, "%s\n", __FUNCTION__);
 
@@ -598,7 +598,7 @@ hard_stop(struct net_device *dev)
 static void
 enable_ether_irq(struct net_device *dev)
 {
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
 	u32 intMask;
 	/*
 	 * route ethernet interrupt to GT_SERINT0 for port 0,
@@ -631,7 +631,7 @@ enable_ether_irq(struct net_device *dev)
 static void
 disable_ether_irq(struct net_device *dev)
 {
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
 	u32 intMask;
 	int intr_mask_reg = (gp->port_num == 0) ?
 		GT96100_SERINT0_MASK : GT96100_INT0_HIGH_MASK;
@@ -745,7 +745,7 @@ gt96100_probe1(int port_num)
 		goto out1;
 	}
 
-	gp = dev->priv;
+	gp = netdev_priv(dev);
 
 	memset(gp, 0, sizeof(*gp)); // clear it
 
@@ -839,7 +839,7 @@ out:
 static void
 reset_tx(struct net_device *dev)
 {
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
 	int i;
 
 	abort(dev, sdcmrAT);
@@ -877,7 +877,7 @@ reset_tx(struct net_device *dev)
 static void
 reset_rx(struct net_device *dev)
 {
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
 	int i;
 
 	abort(dev, sdcmrAR);
@@ -934,7 +934,7 @@ gt96100_check_tx_consistent(struct gt961
 static int
 gt96100_init(struct net_device *dev)
 {
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
 	u32 tmp;
 	u16 mii_reg;
     
@@ -1115,7 +1115,7 @@ gt96100_close(struct net_device *dev)
 static int
 gt96100_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
 	unsigned long flags;
 	int nextIn;
 
@@ -1187,7 +1187,7 @@ gt96100_tx(struct sk_buff *skb, struct n
 static int
 gt96100_rx(struct net_device *dev, u32 status)
 {
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
 	struct sk_buff *skb;
 	int pkt_len, nextOut, cdp;
 	gt96100_rd_t *rd;
@@ -1296,7 +1296,7 @@ gt96100_rx(struct net_device *dev, u32 s
 static void
 gt96100_tx_complete(struct net_device *dev, u32 status)
 {
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
 	int nextOut, cdp;
 	gt96100_td_t *td;
 	u32 cmdstat;
@@ -1385,7 +1385,7 @@ static irqreturn_t
 gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *)dev_id;
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
 	u32 status;
     	int handled = 0;
 
@@ -1486,7 +1486,7 @@ gt96100_interrupt(int irq, void *dev_id,
 static void
 gt96100_tx_timeout(struct net_device *dev)
 {
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
 	unsigned long flags;
     
 	spin_lock_irqsave(&gp->lock, flags);
@@ -1511,7 +1511,7 @@ gt96100_tx_timeout(struct net_device *de
 static void
 gt96100_set_rx_mode(struct net_device *dev)
 {
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
 	unsigned long flags;
 	//struct dev_mc_list *mcptr;
     
@@ -1555,7 +1555,7 @@ gt96100_set_rx_mode(struct net_device *d
 static struct net_device_stats *
 gt96100_get_stats(struct net_device *dev)
 {
-	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+	struct gt96100_private *gp = netdev_priv(dev);
 	unsigned long flags;
 
 	dbg(3, "%s: dev=%p\n", __FUNCTION__, dev);
--- diff/drivers/net/hamachi.c	2003-09-30 14:46:15.000000000 +0000
+++ source/drivers/net/hamachi.c	2004-03-16 09:37:56.142005288 +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/hamradio/baycom_epp.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/net/hamradio/baycom_epp.c	2004-03-16 09:37:56.144004984 +0000
@@ -646,7 +646,7 @@ static int transmit(struct baycom_state 
 
 static void do_rxpacket(struct net_device *dev)
 {
-	struct baycom_state *bc = (struct baycom_state *)dev->priv;
+	struct baycom_state *bc = netdev_priv(dev);
 	struct sk_buff *skb;
 	unsigned char *cp;
 	unsigned pktlen;
@@ -705,7 +705,7 @@ static void do_rxpacket(struct net_devic
         
 static int receive(struct net_device *dev, int cnt)
 {
-	struct baycom_state *bc = (struct baycom_state *)dev->priv;
+	struct baycom_state *bc = netdev_priv(dev);
 	struct parport *pp = bc->pdev->port;
         unsigned int bitbuf, notbitstream, bitstream, numbits, state;
 	unsigned char tmp[128];
@@ -790,7 +790,7 @@ static void epp_bh(struct net_device *de
 	int cnt, cnt2;
 	
 	baycom_paranoia_check_void(dev, "epp_bh");
-	bc = (struct baycom_state *)dev->priv;
+	bc = netdev_priv(dev);
 	if (!bc->work_running)
 		return;
 	baycom_int_freq(bc);
@@ -908,7 +908,7 @@ static int baycom_send_packet(struct sk_
 	struct baycom_state *bc;
 
 	baycom_paranoia_check(dev, "baycom_send_packet", 0);
-	bc = (struct baycom_state *)dev->priv;
+	bc = netdev_priv(dev);
 	if (skb->data[0] != 0) {
 		do_kiss_params(bc, skb->data, skb->len);
 		dev_kfree_skb(skb);
@@ -944,7 +944,7 @@ static struct net_device_stats *baycom_g
 	struct baycom_state *bc;
 
 	baycom_paranoia_check(dev, "baycom_get_stats", NULL);
-	bc = (struct baycom_state *)dev->priv;
+	bc = netdev_priv(dev);
 	/* 
 	 * Get the current statistics.  This may be called with the
 	 * card open or closed. 
@@ -960,7 +960,7 @@ static void epp_wakeup(void *handle)
         struct baycom_state *bc;
 
 	baycom_paranoia_check_void(dev, "epp_wakeup");
-        bc = (struct baycom_state *)dev->priv;
+        bc = netdev_priv(dev);
         printk(KERN_DEBUG "baycom_epp: %s: why am I being woken up?\n", dev->name);
         if (!parport_claim(bc->pdev))
                 printk(KERN_DEBUG "baycom_epp: %s: I'm broken.\n", dev->name);
@@ -987,7 +987,7 @@ static int epp_open(struct net_device *d
 	unsigned long tstart;
 	
 	baycom_paranoia_check(dev, "epp_open", -ENXIO);
-	bc = (struct baycom_state *)dev->priv;
+	bc = netdev_priv(dev);
         pp = parport_find_base(dev->base_addr);
         if (!pp) {
                 printk(KERN_ERR "%s: parport at 0x%lx unknown\n", bc_drvname, dev->base_addr);
@@ -1102,7 +1102,7 @@ static int epp_close(struct net_device *
 	unsigned char tmp[1];
 
 	baycom_paranoia_check(dev, "epp_close", -EINVAL);
-	bc = (struct baycom_state *)dev->priv;
+	bc = netdev_priv(dev);
 	pp = bc->pdev->port;
 	bc->work_running = 0;
 	flush_scheduled_work();
@@ -1163,7 +1163,7 @@ static int baycom_ioctl(struct net_devic
 	struct hdlcdrv_ioctl hi;
 
 	baycom_paranoia_check(dev, "baycom_ioctl", -EINVAL);
-	bc = (struct baycom_state *)dev->priv;
+	bc = netdev_priv(dev);
 	if (cmd != SIOCDEVPRIVATE)
 		return -ENOIOCTLCMD;
 	if (get_user(cmd, (int *)ifr->ifr_data))
@@ -1290,7 +1290,7 @@ static void baycom_probe(struct net_devi
 	/*
 	 * not a real probe! only initialize data structures
 	 */
-	bc = (struct baycom_state *)dev->priv;
+	bc = netdev_priv(dev);
 	/*
 	 * initialize the baycom_state struct
 	 */
@@ -1351,7 +1351,7 @@ MODULE_LICENSE("GPL");
 
 static void __init baycom_epp_dev_setup(struct net_device *dev)
 {
-	struct baycom_state *bc = dev->priv;
+	struct baycom_state *bc = netdev_priv(dev);
 
 	/*
 	 * initialize part of the baycom_state struct
@@ -1415,7 +1415,7 @@ static void __exit cleanup_baycomepp(voi
 		struct net_device *dev = baycom_device[i];
 
 		if (dev) {
-			struct baycom_state *bc = dev->priv;
+			struct baycom_state *bc = netdev_priv(dev);
 			if (bc->magic == BAYCOM_MAGIC) {
 				unregister_netdev(dev);
 				free_netdev(dev);
--- diff/drivers/net/hamradio/baycom_par.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/hamradio/baycom_par.c	2004-03-16 09:37:56.145004832 +0000
@@ -272,7 +272,7 @@ static __inline__ void par96_rx(struct n
 static void par96_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *)dev_id;
-	struct baycom_state *bc = (struct baycom_state *)dev->priv;
+	struct baycom_state *bc = netdev_priv(dev);
 
 	if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC)
 		return;
@@ -302,7 +302,7 @@ static void par96_interrupt(int irq, voi
 static void par96_wakeup(void *handle)
 {
         struct net_device *dev = (struct net_device *)handle;
-	struct baycom_state *bc = (struct baycom_state *)dev->priv;
+	struct baycom_state *bc = netdev_priv(dev);
 
 	printk(KERN_DEBUG "baycom_par: %s: why am I being woken up?\n", dev->name);
 	if (!parport_claim(bc->pdev))
@@ -313,7 +313,7 @@ static void par96_wakeup(void *handle)
 
 static int par96_open(struct net_device *dev)
 {
-	struct baycom_state *bc = (struct baycom_state *)dev->priv;
+	struct baycom_state *bc = netdev_priv(dev);
 	struct parport *pp;
 
 	if (!dev || !bc)
@@ -362,7 +362,7 @@ static int par96_open(struct net_device 
 
 static int par96_close(struct net_device *dev)
 {
-	struct baycom_state *bc = (struct baycom_state *)dev->priv;
+	struct baycom_state *bc = netdev_priv(dev);
 	struct parport *pp;
 
 	if (!dev || !bc)
@@ -424,7 +424,7 @@ static int baycom_ioctl(struct net_devic
 		printk(KERN_ERR "bc_ioctl: invalid device struct\n");
 		return -EINVAL;
 	}
-	bc = (struct baycom_state *)dev->priv;
+	bc = netdev_priv(dev);
 
 	if (cmd != SIOCDEVPRIVATE)
 		return -ENOIOCTLCMD;
@@ -524,7 +524,7 @@ static int __init init_baycompar(void)
 		if (IS_ERR(dev)) 
 			break;
 
-		bc = (struct baycom_state *)dev->priv;
+		bc = netdev_priv(dev);
 		if (set_hw && baycom_setmode(bc, mode[i]))
 			set_hw = 0;
 		found++;
--- diff/drivers/net/hamradio/baycom_ser_fdx.c	2003-09-30 14:46:15.000000000 +0000
+++ source/drivers/net/hamradio/baycom_ser_fdx.c	2004-03-16 09:37:56.146004680 +0000
@@ -281,7 +281,7 @@ static __inline__ void ser12_rx(struct n
 static irqreturn_t ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *)dev_id;
-	struct baycom_state *bc = (struct baycom_state *)dev->priv;
+	struct baycom_state *bc = netdev_priv(dev);
 	struct timeval tv;
 	unsigned char iir, msr;
 	unsigned int txcount = 0;
@@ -407,7 +407,7 @@ static enum uart ser12_check_uart(unsign
 
 static int ser12_open(struct net_device *dev)
 {
-	struct baycom_state *bc = (struct baycom_state *)dev->priv;
+	struct baycom_state *bc = netdev_priv(dev);
 	enum uart u;
 
 	if (!dev || !bc)
@@ -466,7 +466,7 @@ static int ser12_open(struct net_device 
 
 static int ser12_close(struct net_device *dev)
 {
-	struct baycom_state *bc = (struct baycom_state *)dev->priv;
+	struct baycom_state *bc = netdev_priv(dev);
 
 	if (!dev || !bc)
 		return -EINVAL;
@@ -536,7 +536,7 @@ static int baycom_ioctl(struct net_devic
 		printk(KERN_ERR "bc_ioctl: invalid device struct\n");
 		return -EINVAL;
 	}
-	bc = (struct baycom_state *)dev->priv;
+	bc = netdev_priv(dev);
 
 	if (cmd != SIOCDEVPRIVATE)
 		return -ENOIOCTLCMD;
@@ -644,7 +644,7 @@ static int __init init_baycomserfdx(void
 		if (IS_ERR(dev)) 
 			break;
 
-		bc = (struct baycom_state *)dev->priv;
+		bc = netdev_priv(dev);
 		if (set_hw && baycom_setmode(bc, mode[i]))
 			set_hw = 0;
 		bc->baud = baud[i];
--- diff/drivers/net/hamradio/baycom_ser_hdx.c	2003-09-30 14:46:15.000000000 +0000
+++ source/drivers/net/hamradio/baycom_ser_hdx.c	2004-03-16 09:37:56.147004528 +0000
@@ -375,7 +375,7 @@ static inline void ser12_rx(struct net_d
 static irqreturn_t ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *)dev_id;
-	struct baycom_state *bc = (struct baycom_state *)dev->priv;
+	struct baycom_state *bc = netdev_priv(dev);
 	unsigned char iir;
 
 	if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC)
@@ -468,7 +468,7 @@ static enum uart ser12_check_uart(unsign
 
 static int ser12_open(struct net_device *dev)
 {
-	struct baycom_state *bc = (struct baycom_state *)dev->priv;
+	struct baycom_state *bc = netdev_priv(dev);
 	enum uart u;
 
 	if (!dev || !bc)
@@ -511,7 +511,7 @@ static int ser12_open(struct net_device 
 
 static int ser12_close(struct net_device *dev)
 {
-	struct baycom_state *bc = (struct baycom_state *)dev->priv;
+	struct baycom_state *bc = netdev_priv(dev);
 
 	if (!dev || !bc)
 		return -EINVAL;
@@ -576,7 +576,7 @@ static int baycom_ioctl(struct net_devic
 		printk(KERN_ERR "bc_ioctl: invalid device struct\n");
 		return -EINVAL;
 	}
-	bc = (struct baycom_state *)dev->priv;
+	bc = netdev_priv(dev);
 
 	if (cmd != SIOCDEVPRIVATE)
 		return -ENOIOCTLCMD;
@@ -681,7 +681,7 @@ static int __init init_baycomserhdx(void
 		if (IS_ERR(dev)) 
 			break;
 
-		bc = (struct baycom_state *)dev->priv;
+		bc = netdev_priv(dev);
 		if (set_hw && baycom_setmode(bc, mode[i]))
 			set_hw = 0;
 		found++;
--- diff/drivers/net/hp-plus.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/hp-plus.c	2004-03-16 09:37:56.147004528 +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-16 09:37:56.148004376 +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/hplance.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/hplance.c	2004-03-16 09:37:56.148004376 +0000
@@ -63,7 +63,7 @@ static struct hplance_private *root_hpla
 
 static void cleanup_card(struct net_device *dev)
 {
-        struct hplance_private *lp = dev->priv;
+        struct hplance_private *lp = netdev_priv(dev);
 	dio_unconfig_board(lp->scode);
 }
 
@@ -97,7 +97,7 @@ struct net_device * __init hplance_probe
 		dio_config_board(scode);
                 hplance_init(dev, scode);
 		if (!register_netdev(dev)) {
-			struct hplance_private *lp = dev->priv;
+			struct hplance_private *lp = netdev_priv(dev);
 			lp->next_module = root_hplance_dev;
 			root_hplance_dev = lp;
 			return dev;
@@ -141,7 +141,7 @@ static void __init hplance_init(struct n
                 printk("%c%2.2x", i == 0 ? ' ' : ':', dev->dev_addr[i]);
         }
         
-        lp = (struct hplance_private *)dev->priv;
+        lp = netdev_priv(dev);
         lp->lance.name = (char*)name;                   /* discards const, shut up gcc */
         lp->lance.ll = (struct lance_regs *)(va + HPLANCE_REGOFF);
         lp->lance.init_block = (struct lance_init_block *)(va + HPLANCE_MEMOFF); /* CPU addr */
@@ -195,7 +195,7 @@ static unsigned short hplance_readrdp(vo
 static int hplance_open(struct net_device *dev)
 {
         int status;
-        struct hplance_private *lp = (struct hplance_private *)dev->priv;
+        struct hplance_private *lp = netdev_priv(dev);
         struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
         
         status = lance_open(dev);                 /* call generic lance open code */
@@ -209,7 +209,7 @@ static int hplance_open(struct net_devic
 
 static int hplance_close(struct net_device *dev)
 {
-        struct hplance_private *lp = (struct hplance_private *)dev->priv;
+        struct hplance_private *lp = netdev_priv(dev);
         struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
         out_8(&(hpregs->status), 8);              /* disable interrupts at boardlevel */
         lance_close(dev);
--- diff/drivers/net/hydra.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/net/hydra.c	2004-03-16 09:37:56.149004224 +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/ibmveth.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/net/ibmveth.c	2004-03-16 09:37:56.150004072 +0000
@@ -527,7 +527,10 @@ static int ibmveth_open(struct net_devic
 	ibmveth_debug_printk("registering irq 0x%x\n", netdev->irq);
 	if((rc = request_irq(netdev->irq, &ibmveth_interrupt, 0, netdev->name, netdev)) != 0) {
 		ibmveth_error_printk("unable to request irq 0x%x, rc %d\n", netdev->irq, rc);
-		h_free_logical_lan(adapter->vdev->unit_address);
+		do {
+			rc = h_free_logical_lan(adapter->vdev->unit_address);
+		} while H_isLongBusy(rc);
+
 		ibmveth_cleanup(adapter);
 		return rc;
 	}
@@ -556,7 +559,9 @@ static int ibmveth_close(struct net_devi
 	cancel_delayed_work(&adapter->replenish_task);
 	flush_scheduled_work();
 
-	lpar_rc = h_free_logical_lan(adapter->vdev->unit_address);
+	do {
+		lpar_rc = h_free_logical_lan(adapter->vdev->unit_address);
+	} while H_isLongBusy(lpar_rc);
 
 	if(lpar_rc != H_Success)
 	{
@@ -617,6 +622,8 @@ static int ibmveth_start_xmit(struct sk_
 	union ibmveth_buf_desc desc[IbmVethMaxSendFrags];
 	unsigned long lpar_rc;
 	int nfrags = 0, curfrag;
+	unsigned long correlator;
+	unsigned int retry_count;
 
 	if ((skb_shinfo(skb)->nr_frags + 1) > IbmVethMaxSendFrags) {
 		adapter->stats.tx_dropped++;
@@ -674,8 +681,8 @@ static int ibmveth_start_xmit(struct sk_
 	}
 
 	/* send the frame. Arbitrarily set retrycount to 1024 */
-	unsigned long correlator = 0;
-	unsigned int retry_count = 1024;
+	correlator = 0;
+	retry_count = 1024;
 	do {
 		lpar_rc = h_send_logical_lan(adapter->vdev->unit_address,
 					     desc[0].desc,
--- diff/drivers/net/irda/vlsi_ir.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/net/irda/vlsi_ir.c	2004-03-16 09:37:56.152003768 +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/isa-skeleton.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/net/isa-skeleton.c	2004-03-16 09:37:56.153003616 +0000
@@ -303,7 +303,7 @@ static int __init netcard_probe1(struct 
 	}
 #endif	/* jumpered DMA */
 
-	np = (struct net_local *)dev->priv;
+	np = netdev_priv(dev);
 	spin_lock_init(&np->lock);
 
 	dev->open		= net_open;
@@ -326,7 +326,7 @@ out:
 
 static void net_tx_timeout(struct net_device *dev)
 {
-	struct net_local *np = (struct net_local *)dev->priv;
+	struct net_local *np = netdev_priv(dev);
 
 	printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
 	       tx_done(dev) ? "IRQ conflict" : "network cable problem");
@@ -361,7 +361,7 @@ static void net_tx_timeout(struct net_de
 static int
 net_open(struct net_device *dev)
 {
-	struct net_local *np = (struct net_local *)dev->priv;
+	struct net_local *np = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	/*
 	 * This is used if the interrupt line can turned off (shared).
@@ -399,7 +399,7 @@ net_open(struct net_device *dev)
  */
 static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct net_local *np = (struct net_local *)dev->priv;
+	struct net_local *np = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 	unsigned char *buf = skb->data;
@@ -465,7 +465,7 @@ static int net_send_packet(struct sk_buf
  */
 void net_tx(struct net_device *dev)
 {
-	struct net_local *np = (struct net_local *)dev->priv;
+	struct net_local *np = netdev_priv(dev);
 	int entry;
 
 	/* This protects us from concurrent execution of
@@ -508,7 +508,7 @@ static irqreturn_t net_interrupt(int irq
 
 	ioaddr = dev->base_addr;
 
-	np = (struct net_local *)dev->priv;
+	np = netdev_priv(dev);
 	status = inw(ioaddr + 0);
 
 	if (status == 0)
@@ -539,7 +539,7 @@ out:
 static void
 net_rx(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	int boguscount = 10;
 
@@ -591,7 +591,7 @@ net_rx(struct net_device *dev)
 static int
 net_close(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	lp->open_time = 0;
@@ -620,7 +620,7 @@ net_close(struct net_device *dev)
  */
 static struct net_device_stats *net_get_stats(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	short ioaddr = dev->base_addr;
 
 	/* Update the statistics from the device registers. */
--- diff/drivers/net/lasi_82596.c	2004-03-11 10:20:25.000000000 +0000
+++ source/drivers/net/lasi_82596.c	2004-03-16 09:37:56.154003464 +0000
@@ -426,7 +426,7 @@ static inline void CA(struct net_device 
 
 static inline void MPU_PORT(struct net_device *dev, int c, dma_addr_t x)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 
 	u32 v = (u32) (c) | (u32) (x);
 	u16 a, b;
@@ -481,7 +481,7 @@ static inline int wait_cmd(struct net_de
 
 static void i596_display_data(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	struct i596_cmd *cmd;
 	struct i596_rfd *rfd;
 	struct i596_rbd *rbd;
@@ -541,7 +541,7 @@ static void i596_error(int irq, void *de
 
 static inline void init_rx_bufs(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *)dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	int i;
 	struct i596_rfd *rfd;
 	struct i596_rbd *rbd;
@@ -595,7 +595,7 @@ static inline void init_rx_bufs(struct n
 
 static inline void remove_rx_bufs(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *)dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	struct i596_rbd *rbd;
 	int i;
 
@@ -612,7 +612,7 @@ static inline void remove_rx_bufs(struct
 
 static void rebuild_rx_bufs(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	int i;
 
 	/* Ensure rx frame/buffer descriptors are tidy */
@@ -633,7 +633,7 @@ static void rebuild_rx_bufs(struct net_d
 
 static int init_i596_mem(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	unsigned long flags;
 
 	disable_irq(dev->irq);	/* disable IRQs from LAN */
@@ -727,7 +727,7 @@ failed:
 
 static inline int i596_rx(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *)dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	struct i596_rfd *rfd;
 	struct i596_rbd *rbd;
 	int frames = 0;
@@ -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);
@@ -939,7 +940,7 @@ static inline void i596_reset(struct net
 
 static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	unsigned long flags;
 
 	DEB(DEB_ADDCMD,printk("i596_add_cmd cmd_head %p\n", lp->cmd_head));
@@ -987,7 +988,7 @@ static void i596_add_cmd(struct net_devi
    device list */
 static int i596_test(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	volatile int *tint;
 	u32 data;
 
@@ -1041,7 +1042,7 @@ out:
 
 static void i596_tx_timeout (struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 
 	/* Transmitter timeout, serious problems. */
 	DEB(DEB_ERRORS,printk("%s: transmit timed out, status resetting.\n",
@@ -1070,7 +1071,7 @@ static void i596_tx_timeout (struct net_
 
 static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	struct tx_cmd *tx_cmd;
 	struct i596_tbd *tbd;
 	short length = skb->len;
@@ -1219,7 +1220,7 @@ static int __devinit i82596_probe(struct
 
 	dev->priv = (void *)(dev->mem_start);
 
-	lp = (struct i596_private *) dev->priv;
+	lp = netdev_priv(dev);
 	DEB(DEB_INIT,printk ("%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n",
 		dev->name, (unsigned long)lp,
 		sizeof(struct i596_private), (unsigned long)&lp->scb));
@@ -1249,7 +1250,7 @@ static irqreturn_t i596_interrupt(int ir
 		return IRQ_NONE;
 	}
 
-	lp = (struct i596_private *) dev->priv;
+	lp = netdev_priv(dev);
 
 	spin_lock (&lp->lock);
 
@@ -1395,7 +1396,7 @@ static irqreturn_t i596_interrupt(int ir
 
 static int i596_close(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	unsigned long flags;
 
 	netif_stop_queue(dev);
@@ -1429,7 +1430,7 @@ static int i596_close(struct net_device 
 static struct net_device_stats *
  i596_get_stats(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 
 	return &lp->stats;
 }
@@ -1440,7 +1441,7 @@ static struct net_device_stats *
 
 static void set_multicast_list(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	int config = 0, cnt;
 
 	DEB(DEB_MULTI,printk("%s: set multicast list, %d entries, promisc %s, allmulti %s\n", dev->name, dev->mc_count, dev->flags & IFF_PROMISC ? "ON" : "OFF", dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));
@@ -1540,7 +1541,7 @@ lan_init_chip(struct parisc_device *dev)
 
 	retval = register_netdev(netdevice);
 	if (retval) {
-		struct i596_private *lp = netdevice->priv;
+		struct i596_private *lp = netdev_priv(netdevice);
 		printk(KERN_WARNING __FILE__ ": register_netdevice ret'd %d\n", retval);
 		dma_free_noncoherent(lp->dev, sizeof(struct i596_private), 
 				    (void *)netdevice->mem_start, lp->dma_addr);
@@ -1594,7 +1595,7 @@ static void __exit lasi_82596_exit(void)
 		
 		unregister_netdev(netdevice);
 
-		lp = (struct i596_private *) netdevice->priv;
+		lp = netdev_priv(netdevice);
 		dma_free_noncoherent(lp->dev, sizeof(struct i596_private), 
 				       (void *)netdevice->mem_start, lp->dma_addr);
 		free_netdev(netdevice);
--- diff/drivers/net/lne390.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/lne390.c	2004-03-16 09:37:56.155003312 +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/loopback.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/loopback.c	2004-03-16 09:37:56.155003312 +0000
@@ -123,7 +123,7 @@ static void emulate_large_send_offload(s
  */
 static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
+	struct net_device_stats *stats = netdev_priv(dev);
 
 	skb_orphan(skb);
 
--- diff/drivers/net/mac8390.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/mac8390.c	2004-03-16 09:37:56.156003160 +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/mac89x0.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/mac89x0.c	2004-03-16 09:37:56.157003008 +0000
@@ -225,7 +225,7 @@ struct net_device * __init mac89x0_probe
 		goto out;
 
 	/* Initialize the net_device structure. */
-	lp = (struct net_local *)dev->priv;
+	lp = netdev_priv(dev);
 
 	/* Fill in the 'dev' fields. */
 	dev->base_addr = ioaddr;
@@ -328,7 +328,7 @@ void __init reset_chip(struct net_device
 static int
 net_open(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int i;
 
 	/* Disable the interrupt for now */
@@ -392,7 +392,7 @@ net_send_packet(struct sk_buff *skb, str
 	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
 		printk("%s: Transmitter access conflict.\n", dev->name);
 	else {
-		struct net_local *lp = (struct net_local *)dev->priv;
+		struct net_local *lp = netdev_priv(dev);
 		unsigned long flags;
 
 		if (net_debug > 3)
@@ -446,7 +446,7 @@ static irqreturn_t net_interrupt(int irq
 	dev->interrupt = 1;
 
 	ioaddr = dev->base_addr;
-	lp = (struct net_local *)dev->priv;
+	lp = netdev_priv(dev);
 
 	/* we MUST read all the events out of the ISQ, otherwise we'll never
            get interrupted again.  As a consequence, we can't have any limit
@@ -505,7 +505,7 @@ static irqreturn_t net_interrupt(int irq
 static void
 net_rx(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	struct sk_buff *skb;
 	int status, length;
 
@@ -571,7 +571,7 @@ net_close(struct net_device *dev)
 static struct net_device_stats *
 net_get_stats(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned long flags;
 
 	local_irq_save(flags);
@@ -585,7 +585,7 @@ net_get_stats(struct net_device *dev)
 
 static void set_multicast_list(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	if(dev->flags&IFF_PROMISC)
 	{
--- diff/drivers/net/myri_sbus.c	2003-10-27 09:20:38.000000000 +0000
+++ source/drivers/net/myri_sbus.c	2004-03-16 09:37:56.157003008 +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-16 09:37:56.159002704 +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-11 10:20:26.000000000 +0000
+++ source/drivers/net/ne.c	2004-03-16 09:37:56.160002552 +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-16 09:37:56.161002400 +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-16 09:37:56.162002248 +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-16 09:37:56.163002096 +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-16 09:37:56.164001944 +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/ni5010.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/ni5010.c	2004-03-16 09:37:56.165001792 +0000
@@ -309,7 +309,7 @@ static int __init ni5010_probe1(struct n
 	PRINTK2((KERN_DEBUG "%s: I/O #9 passed!\n", dev->name));
 
 	/* DMA is not supported (yet?), so no use detecting it */
-	lp = (struct ni5010_local*)dev->priv;
+	lp = netdev_priv(dev);
 
 	spin_lock_init(&lp->lock);
 
@@ -484,7 +484,7 @@ static irqreturn_t ni5010_interrupt(int 
 	PRINTK2((KERN_DEBUG "%s: entering ni5010_interrupt\n", dev->name));
 
 	ioaddr = dev->base_addr;
-	lp = (struct ni5010_local *)dev->priv;
+	lp = netdev_priv(dev);
 	
 	spin_lock(&lp->lock);
 	status = inb(IE_ISTAT); 
@@ -527,7 +527,7 @@ static void dump_packet(void *buf, int l
 /* We have a good packet, get it out of the buffer. */
 static void ni5010_rx(struct net_device *dev)
 {
-	struct ni5010_local *lp = (struct ni5010_local *)dev->priv;
+	struct ni5010_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	unsigned char rcv_stat;
 	struct sk_buff *skb;
@@ -592,7 +592,7 @@ static void ni5010_rx(struct net_device 
 
 static int process_xmt_interrupt(struct net_device *dev)
 {
-	struct ni5010_local *lp = (struct ni5010_local *)dev->priv;
+	struct ni5010_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	int xmit_stat;
 
@@ -651,7 +651,7 @@ static int ni5010_close(struct net_devic
    closed. */
 static struct net_device_stats *ni5010_get_stats(struct net_device *dev)
 {
-	struct ni5010_local *lp = (struct ni5010_local *)dev->priv;
+	struct ni5010_local *lp = netdev_priv(dev);
 
 	PRINTK2((KERN_DEBUG "%s: entering ni5010_get_stats\n", dev->name));
 	
@@ -693,7 +693,7 @@ static void ni5010_set_multicast_list(st
 
 static void hardware_send_packet(struct net_device *dev, char *buf, int length, int pad)
 {
-	struct ni5010_local *lp = (struct ni5010_local *)dev->priv;
+	struct ni5010_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	unsigned long flags;
 	unsigned int buf_offs;
--- diff/drivers/net/oaknet.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/oaknet.c	2004-03-16 09:37:56.165001792 +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-16 09:37:56.167001488 +0000
@@ -283,7 +283,7 @@ static dev_link_t *tc574_attach(void)
 	dev = alloc_etherdev(sizeof(struct el3_private));
 	if (!dev)
 		return NULL;
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 	link = &lp->link;
 	link->priv = dev;
 
@@ -384,11 +384,13 @@ 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;
 	struct net_device *dev = link->priv;
-	struct el3_private *lp = dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	tuple_t tuple;
 	cisparse_t parse;
 	unsigned short buf[32];
@@ -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:
@@ -733,7 +737,7 @@ static void mdio_write(ioaddr_t ioaddr, 
 /* Reset and restore all of the 3c574 registers. */
 static void tc574_reset(struct net_device *dev)
 {
-	struct el3_private *lp = (struct el3_private *)dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	int i, ioaddr = dev->base_addr;
 	unsigned long flags;
 
@@ -814,7 +818,7 @@ static void tc574_reset(struct net_devic
 
 static int el3_open(struct net_device *dev)
 {
-	struct el3_private *lp = (struct el3_private *)dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	dev_link_t *link = &lp->link;
 
 	if (!DEV_OK(link))
@@ -837,7 +841,7 @@ static int el3_open(struct net_device *d
 
 static void el3_tx_timeout(struct net_device *dev)
 {
-	struct el3_private *lp = (struct el3_private *)dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	ioaddr_t ioaddr = dev->base_addr;
 	
 	printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name);
@@ -852,7 +856,7 @@ static void el3_tx_timeout(struct net_de
 
 static void pop_tx_status(struct net_device *dev)
 {
-	struct el3_private *lp = (struct el3_private *)dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	ioaddr_t ioaddr = dev->base_addr;
 	int i;
     
@@ -877,7 +881,7 @@ static void pop_tx_status(struct net_dev
 static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	ioaddr_t ioaddr = dev->base_addr;
-	struct el3_private *lp = (struct el3_private *)dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	unsigned long flags;
 
 	DEBUG(3, "%s: el3_start_xmit(length = %ld) called, "
@@ -909,7 +913,7 @@ static int el3_start_xmit(struct sk_buff
 static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
-	struct el3_private *lp = dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	ioaddr_t ioaddr, status;
 	int work_budget = max_interrupt_work;
 	int handled = 0;
@@ -1002,7 +1006,7 @@ static irqreturn_t el3_interrupt(int irq
 static void media_check(unsigned long arg)
 {
 	struct net_device *dev = (struct net_device *) arg;
-	struct el3_private *lp = dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	ioaddr_t ioaddr = dev->base_addr;
 	unsigned long flags;
 	unsigned short /* cable, */ media, partner;
@@ -1074,7 +1078,7 @@ reschedule:
 
 static struct net_device_stats *el3_get_stats(struct net_device *dev)
 {
-	struct el3_private *lp = (struct el3_private *)dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 
 	if (netif_device_present(dev)) {
 		unsigned long flags;
@@ -1091,7 +1095,7 @@ static struct net_device_stats *el3_get_
  */
 static void update_stats(struct net_device *dev)
 {
-	struct el3_private *lp = (struct el3_private *)dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	ioaddr_t ioaddr = dev->base_addr;
 	u8 rx, tx, up;
 
@@ -1128,7 +1132,7 @@ static void update_stats(struct net_devi
 
 static int el3_rx(struct net_device *dev, int worklimit)
 {
-	struct el3_private *lp = (struct el3_private *)dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	ioaddr_t ioaddr = dev->base_addr;
 	short rx_status;
 	
@@ -1190,7 +1194,7 @@ static struct ethtool_ops netdev_ethtool
 /* Provide ioctl() calls to examine the MII xcvr state. */
 static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct el3_private *lp = (struct el3_private *)dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	ioaddr_t ioaddr = dev->base_addr;
 	u16 *data = (u16 *)&rq->ifr_data;
 	int phy = lp->phys & 0x1f;
@@ -1259,7 +1263,7 @@ static void set_rx_mode(struct net_devic
 static int el3_close(struct net_device *dev)
 {
 	ioaddr_t ioaddr = dev->base_addr;
-	struct el3_private *lp = dev->priv;
+	struct el3_private *lp = netdev_priv(dev);
 	dev_link_t *link = &lp->link;
 
 	DEBUG(2, "%s: shutting down ethercard.\n", dev->name);
--- diff/drivers/net/pcmcia/3c589_cs.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/pcmcia/3c589_cs.c	2004-03-16 09:37:56.170001032 +0000
@@ -196,7 +196,7 @@ static dev_link_t *tc589_attach(void)
     dev = alloc_etherdev(sizeof(struct el3_private));
     if (!dev)
 	 return NULL;
-    lp = dev->priv;
+    lp = netdev_priv(dev);
     link = &lp->link;
     link->priv = dev;
 
@@ -304,11 +304,11 @@ static void tc589_config(dev_link_t *lin
 {
     client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
-    struct el3_private *lp = dev->priv;
+    struct el3_private *lp = netdev_priv(dev);
     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;
 
@@ -526,7 +528,7 @@ static u16 read_eeprom(ioaddr_t ioaddr, 
 */
 static void tc589_set_xcvr(struct net_device *dev, int if_port)
 {
-    struct el3_private *lp = (struct el3_private *)dev->priv;
+    struct el3_private *lp = netdev_priv(dev);
     ioaddr_t ioaddr = dev->base_addr;
     
     EL3WINDOW(0);
@@ -648,7 +650,7 @@ static int el3_config(struct net_device 
 
 static int el3_open(struct net_device *dev)
 {
-    struct el3_private *lp = (struct el3_private *)dev->priv;
+    struct el3_private *lp = netdev_priv(dev);
     dev_link_t *link = &lp->link;
     
     if (!DEV_OK(link))
@@ -672,7 +674,7 @@ static int el3_open(struct net_device *d
 
 static void el3_tx_timeout(struct net_device *dev)
 {
-    struct el3_private *lp = (struct el3_private *)dev->priv;
+    struct el3_private *lp = netdev_priv(dev);
     ioaddr_t ioaddr = dev->base_addr;
     
     printk(KERN_WARNING "%s: Transmit timed out!\n", dev->name);
@@ -687,7 +689,7 @@ static void el3_tx_timeout(struct net_de
 
 static void pop_tx_status(struct net_device *dev)
 {
-    struct el3_private *lp = (struct el3_private *)dev->priv;
+    struct el3_private *lp = netdev_priv(dev);
     ioaddr_t ioaddr = dev->base_addr;
     int i;
     
@@ -741,7 +743,7 @@ static int el3_start_xmit(struct sk_buff
 static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
     struct net_device *dev = (struct net_device *) dev_id;
-    struct el3_private *lp = dev->priv;
+    struct el3_private *lp = netdev_priv(dev);
     ioaddr_t ioaddr, status;
     int i = 0, handled = 1;
     
@@ -826,7 +828,7 @@ static irqreturn_t el3_interrupt(int irq
 static void media_check(unsigned long arg)
 {
     struct net_device *dev = (struct net_device *)(arg);
-    struct el3_private *lp = dev->priv;
+    struct el3_private *lp = netdev_priv(dev);
     ioaddr_t ioaddr = dev->base_addr;
     u16 media, errs;
     unsigned long flags;
@@ -906,7 +908,7 @@ reschedule:
 
 static struct net_device_stats *el3_get_stats(struct net_device *dev)
 {
-    struct el3_private *lp = (struct el3_private *)dev->priv;
+    struct el3_private *lp = netdev_priv(dev);
     unsigned long flags;
     dev_link_t *link = &lp->link;
 
@@ -928,7 +930,7 @@ static struct net_device_stats *el3_get_
 */
 static void update_stats(struct net_device *dev)
 {
-    struct el3_private *lp = (struct el3_private *)dev->priv;
+    struct el3_private *lp = netdev_priv(dev);
     ioaddr_t ioaddr = dev->base_addr;
 
     DEBUG(2, "%s: updating the statistics.\n", dev->name);
@@ -955,7 +957,7 @@ static void update_stats(struct net_devi
 
 static int el3_rx(struct net_device *dev)
 {
-    struct el3_private *lp = (struct el3_private *)dev->priv;
+    struct el3_private *lp = netdev_priv(dev);
     ioaddr_t ioaddr = dev->base_addr;
     int worklimit = 32;
     short rx_status;
@@ -1009,7 +1011,7 @@ static int el3_rx(struct net_device *dev
 
 static void set_multicast_list(struct net_device *dev)
 {
-    struct el3_private *lp = dev->priv;
+    struct el3_private *lp = netdev_priv(dev);
     dev_link_t *link = &lp->link;
     ioaddr_t ioaddr = dev->base_addr;
     u16 opts = SetRxFilter | RxStation | RxBroadcast;
@@ -1024,7 +1026,7 @@ static void set_multicast_list(struct ne
 
 static int el3_close(struct net_device *dev)
 {
-    struct el3_private *lp = dev->priv;
+    struct el3_private *lp = netdev_priv(dev);
     dev_link_t *link = &lp->link;
     ioaddr_t ioaddr = dev->base_addr;
     
--- diff/drivers/net/pcmcia/axnet_cs.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/pcmcia/axnet_cs.c	2004-03-16 09:37:56.172000728 +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-16 09:37:56.173000576 +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;
 
@@ -179,7 +178,7 @@ static dev_link_t *com20020_attach(void)
 
     memset(info, 0, sizeof(struct com20020_dev_t));
     memset(link, 0, sizeof(struct dev_link_t));
-    lp = dev->priv;
+    lp = netdev_priv(dev);
     lp->timeout = timeout;
     lp->backplane = backplane;
     lp->clockp = clockp;
@@ -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);
 	    
 		/*
@@ -394,21 +390,22 @@ static void com20020_config(dev_link_t *
 	goto failed;
     }
     
-    lp = dev->priv;
+    lp = netdev_priv(dev);
     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);
@@ -492,7 +489,7 @@ static int com20020_event(event_t event,
             pcmcia_request_configuration(link->handle, &link->conf);
             if (link->open) {
 		int ioaddr = dev->base_addr;
-		struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+		struct arcnet_local *lp = netdev_priv(dev);
 		ARCRESET;
             }
         }
--- diff/drivers/net/pcmcia/fmvj18x_cs.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/pcmcia/fmvj18x_cs.c	2004-03-16 09:37:56.175000272 +0000
@@ -256,7 +256,7 @@ static dev_link_t *fmvj18x_attach(void)
     dev = alloc_etherdev(sizeof(local_info_t));
     if (!dev)
 	return NULL;
-    lp = dev->priv;
+    lp = netdev_priv(dev);
     link = &lp->link;
     link->priv = dev;
 
@@ -394,7 +394,7 @@ static void fmvj18x_config(dev_link_t *l
 {
     client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
-    local_info_t *lp = dev->priv;
+    local_info_t *lp = netdev_priv(dev);
     tuple_t tuple;
     cisparse_t parse;
     u_short buf[32];
@@ -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:
@@ -803,7 +805,7 @@ module_exit(exit_fmvj18x_cs);
 static irqreturn_t fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
     struct net_device *dev = dev_id;
-    local_info_t *lp = dev->priv;
+    local_info_t *lp = netdev_priv(dev);
     ioaddr_t ioaddr;
     unsigned short tx_stat, rx_stat;
 
@@ -862,7 +864,7 @@ static irqreturn_t fjn_interrupt(int irq
 
 static void fjn_tx_timeout(struct net_device *dev)
 {
-    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    struct local_info_t *lp = netdev_priv(dev);
     ioaddr_t ioaddr = dev->base_addr;
 
     printk(KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n",
@@ -892,7 +894,7 @@ static void fjn_tx_timeout(struct net_de
 
 static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    struct local_info_t *lp = netdev_priv(dev);
     ioaddr_t ioaddr = dev->base_addr;
     short length = skb->len;
     
@@ -966,7 +968,7 @@ static int fjn_start_xmit(struct sk_buff
 
 static void fjn_reset(struct net_device *dev)
 {
-    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    struct local_info_t *lp = netdev_priv(dev);
     ioaddr_t ioaddr = dev->base_addr;
     int i;
 
@@ -1052,7 +1054,7 @@ static void fjn_reset(struct net_device 
 
 static void fjn_rx(struct net_device *dev)
 {
-    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    struct local_info_t *lp = netdev_priv(dev);
     ioaddr_t ioaddr = dev->base_addr;
     int boguscount = 10;	/* 5 -> 10: by agy 19940922 */
 
@@ -1181,7 +1183,7 @@ static int fjn_config(struct net_device 
 
 static int fjn_open(struct net_device *dev)
 {
-    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    struct local_info_t *lp = netdev_priv(dev);
     dev_link_t *link = &lp->link;
 
     DEBUG(4, "fjn_open('%s').\n", dev->name);
@@ -1206,7 +1208,7 @@ static int fjn_open(struct net_device *d
 
 static int fjn_close(struct net_device *dev)
 {
-    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    struct local_info_t *lp = netdev_priv(dev);
     dev_link_t *link = &lp->link;
     ioaddr_t ioaddr = dev->base_addr;
 
@@ -1239,7 +1241,7 @@ static int fjn_close(struct net_device *
 
 static struct net_device_stats *fjn_get_stats(struct net_device *dev)
 {
-    local_info_t *lp = (local_info_t *)dev->priv;
+    local_info_t *lp = netdev_priv(dev);
     return &lp->stats;
 } /* fjn_get_stats */
 
@@ -1252,7 +1254,7 @@ static struct net_device_stats *fjn_get_
 static void set_rx_mode(struct net_device *dev)
 {
     ioaddr_t ioaddr = dev->base_addr;
-    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    struct local_info_t *lp = netdev_priv(dev);
     u_char mc_filter[8];		 /* Multicast hash filter */
     u_long flags;
     int i;
--- diff/drivers/net/pcmcia/ibmtr_cs.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/pcmcia/ibmtr_cs.c	2004-03-16 09:37:56.176000120 +0000
@@ -178,7 +178,7 @@ static dev_link_t *ibmtr_attach(void)
 
     link = &info->link;
     link->priv = info;
-    info->ti = dev->priv; 
+    info->ti = netdev_priv(dev);
 
     link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
     link->io.NumPorts1 = 4;
@@ -256,7 +256,7 @@ static void ibmtr_detach(dev_link_t *lin
 	unregister_netdev(dev);
 
     {
-	struct tok_info *ti = (struct tok_info *)dev->priv;
+	struct tok_info *ti = netdev_priv(dev);
 	del_timer_sync(&(ti->tr_timer));
     }
     if (link->state & DEV_CONFIG)
@@ -287,7 +287,7 @@ static void ibmtr_config(dev_link_t *lin
     client_handle_t handle = link->handle;
     ibmtr_dev_t *info = link->priv;
     struct net_device *dev = info->dev;
-    struct tok_info *ti = dev->priv;
+    struct tok_info *ti = netdev_priv(dev);
     tuple_t tuple;
     cisparse_t parse;
     win_req_t req;
@@ -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);
@@ -412,7 +411,7 @@ static void ibmtr_release(dev_link_t *li
     pcmcia_release_io(link->handle, &link->io);
     pcmcia_release_irq(link->handle, &link->irq);
     if (link->win) {
-	struct tok_info *ti = dev->priv;
+	struct tok_info *ti = netdev_priv(dev);
 	iounmap((void *)ti->mmio);
 	pcmcia_release_window(link->win);
 	pcmcia_release_window(info->sram_win_handle);
--- diff/drivers/net/pcmcia/nmclan_cs.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/pcmcia/nmclan_cs.c	2004-03-16 09:37:56.177999816 +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-16 09:37:56.179999512 +0000
@@ -327,7 +327,7 @@ static dev_link_t *smc91c92_attach(void)
     dev = alloc_etherdev(sizeof(struct smc_private));
     if (!dev)
 	return NULL;
-    smc = dev->priv;
+    smc = netdev_priv(dev);
     link = &smc->link;
     link->priv = dev;
 
@@ -483,7 +483,7 @@ static int next_tuple(client_handle_t ha
 static int mhz_3288_power(dev_link_t *link)
 {
     struct net_device *dev = link->priv;
-    struct smc_private *smc = dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     u_char tmp;
 
     /* Read the ISR twice... */
@@ -505,7 +505,7 @@ static int mhz_3288_power(dev_link_t *li
 static int mhz_mfc_config(dev_link_t *link)
 {
     struct net_device *dev = link->priv;
-    struct smc_private *smc = dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     tuple_t tuple;
     cisparse_t parse;
     u_char buf[255];
@@ -618,7 +618,7 @@ static int mhz_setup(dev_link_t *link)
 static void mot_config(dev_link_t *link)
 {
     struct net_device *dev = link->priv;
-    struct smc_private *smc = dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     ioaddr_t ioaddr = dev->base_addr;
     ioaddr_t iouart = link->io.BasePort2;
 
@@ -894,13 +894,14 @@ static void smc91c92_config(dev_link_t *
 {
     client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
-    struct smc_private *smc = dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     tuple_t tuple;
     cisparse_t parse;
     u_short buf[32];
     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:
@@ -1069,7 +1082,7 @@ static void smc91c92_release(dev_link_t 
     pcmcia_release_irq(link->handle, &link->irq);
     if (link->win) {
 	struct net_device *dev = link->priv;
-	struct smc_private *smc = dev->priv;
+	struct smc_private *smc = netdev_priv(dev);
 	iounmap(smc->base);
 	pcmcia_release_window(link->win);
     }
@@ -1091,7 +1104,7 @@ static int smc91c92_event(event_t event,
 {
     dev_link_t *link = args->client_data;
     struct net_device *dev = link->priv;
-    struct smc_private *smc = dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     int i;
 
     DEBUG(1, "smc91c92_event(0x%06x)\n", event);
@@ -1240,7 +1253,7 @@ static void smc_dump(struct net_device *
 
 static int smc_open(struct net_device *dev)
 {
-    struct smc_private *smc = dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     dev_link_t *link = &smc->link;
 
 #ifdef PCMCIA_DEBUG
@@ -1277,7 +1290,7 @@ static int smc_open(struct net_device *d
 
 static int smc_close(struct net_device *dev)
 {
-    struct smc_private *smc = dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     dev_link_t *link = &smc->link;
     ioaddr_t ioaddr = dev->base_addr;
 
@@ -1314,7 +1327,7 @@ static int smc_close(struct net_device *
 
 static void smc_hardware_send_packet(struct net_device * dev)
 {
-    struct smc_private *smc = dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     struct sk_buff *skb = smc->saved_skb;
     ioaddr_t ioaddr = dev->base_addr;
     u_char packet_no;
@@ -1379,7 +1392,7 @@ static void smc_hardware_send_packet(str
 
 static void smc_tx_timeout(struct net_device *dev)
 {
-    struct smc_private *smc = dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     ioaddr_t ioaddr = dev->base_addr;
 
     printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, "
@@ -1394,7 +1407,7 @@ static void smc_tx_timeout(struct net_de
 
 static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-    struct smc_private *smc = dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     ioaddr_t ioaddr = dev->base_addr;
     u_short num_pages;
     short time_out, ir;
@@ -1460,7 +1473,7 @@ static int smc_start_xmit(struct sk_buff
 
 static void smc_tx_err(struct net_device * dev)
 {
-    struct smc_private *smc = (struct smc_private *)dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     ioaddr_t ioaddr = dev->base_addr;
     int saved_packet = inw(ioaddr + PNR_ARR) & 0xff;
     int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f;
@@ -1504,7 +1517,7 @@ static void smc_tx_err(struct net_device
 
 static void smc_eph_irq(struct net_device *dev)
 {
-    struct smc_private *smc = dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     ioaddr_t ioaddr = dev->base_addr;
     u_short card_stats, ephs;
 
@@ -1539,7 +1552,7 @@ static void smc_eph_irq(struct net_devic
 static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
     struct net_device *dev = dev_id;
-    struct smc_private *smc = dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     ioaddr_t ioaddr;
     u_short saved_bank, saved_pointer, mask, status;
     unsigned int handled = 1;
@@ -1657,7 +1670,7 @@ irq_done:
 
 static void smc_rx(struct net_device *dev)
 {
-    struct smc_private *smc = (struct smc_private *)dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     ioaddr_t ioaddr = dev->base_addr;
     int rx_status;
     int packet_length;	/* Caution: not frame length, rather words
@@ -1725,7 +1738,7 @@ static void smc_rx(struct net_device *de
 
 static struct net_device_stats *smc_get_stats(struct net_device *dev)
 {
-    struct smc_private *smc = (struct smc_private *)dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     /* Nothing to update - the 91c92 is a pretty primative chip. */
     return &smc->stats;
 }
@@ -1765,7 +1778,7 @@ static void fill_multicast_tbl(int count
 static void set_rx_mode(struct net_device *dev)
 {
     ioaddr_t ioaddr = dev->base_addr;
-    struct smc_private *smc = dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     u_int multicast_table[ 2 ] = { 0, };
     unsigned long flags;
     u_short rx_cfg_setting;
@@ -1804,7 +1817,7 @@ static void set_rx_mode(struct net_devic
 
 static int s9k_config(struct net_device *dev, struct ifmap *map)
 {
-    struct smc_private *smc = dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
 	if (smc->cfg & CFG_MII_SELECT)
 	    return -EOPNOTSUPP;
@@ -1830,7 +1843,7 @@ static int s9k_config(struct net_device 
 */
 static void smc_set_xcvr(struct net_device *dev, int if_port)
 {
-    struct smc_private *smc = (struct smc_private *)dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     ioaddr_t ioaddr = dev->base_addr;
     u_short saved_bank;
 
@@ -1855,7 +1868,7 @@ static void smc_set_xcvr(struct net_devi
 static void smc_reset(struct net_device *dev)
 {
     ioaddr_t ioaddr = dev->base_addr;
-    struct smc_private *smc = dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     int i;
 
     DEBUG(0, "%s: smc91c92 reset called.\n", dev->name);
@@ -1930,7 +1943,7 @@ static void smc_reset(struct net_device 
 static void media_check(u_long arg)
 {
     struct net_device *dev = (struct net_device *) arg;
-    struct smc_private *smc = dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     ioaddr_t ioaddr = dev->base_addr;
     u_short i, media, saved_bank;
     u_short link;
@@ -2044,7 +2057,7 @@ reschedule:
 static int smc_link_ok(struct net_device *dev)
 {
     ioaddr_t ioaddr = dev->base_addr;
-    struct smc_private *smc = dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
 
     if (smc->cfg & CFG_MII_SELECT) {
 	return mii_link_ok(&smc->mii_if);
@@ -2109,7 +2122,7 @@ static int smc_netdev_set_ecmd(struct ne
 static int smc_ethtool_ioctl (struct net_device *dev, void *useraddr)
 {
     u32 ethcmd;
-    struct smc_private *smc = dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
 
     if (get_user(ethcmd, (u32 *)useraddr))
 	return -EFAULT;
@@ -2202,7 +2215,7 @@ static int smc_ethtool_ioctl (struct net
 
 static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
-    struct smc_private *smc = dev->priv;
+    struct smc_private *smc = netdev_priv(dev);
     struct mii_ioctl_data *mii;
     int rc = 0;
     u_short saved_bank;
--- diff/drivers/net/pcmcia/xirc2ps_cs.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/pcmcia/xirc2ps_cs.c	2004-03-16 09:37:56.181999208 +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",
@@ -1666,6 +1669,7 @@ static void netdev_get_drvinfo(struct ne
 			       struct ethtool_drvinfo *info)
 {
 	strcpy(info->driver, "xirc2ps_cs");
+	sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
 }
 
 static struct ethtool_ops netdev_ethtool_ops = {
--- diff/drivers/net/pcnet32.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/pcnet32.c	2004-03-16 09:37:56.182999056 +0000
@@ -225,10 +225,12 @@ static int full_duplex[MAX_UNITS];
  * v1.27b  Sep 30 2002 Kent Yoder <yoder1@us.ibm.com>
  * 	   Added timer for cable connection state changes.
  * v1.28   20 Feb 2004 Don Fry <brazilnut@us.ibm.com>
- *	   Jon Lewis <jonmason@us.ibm.com>, Chinmay Albal <albal@in.ibm.com>
+ *	   Jon Mason <jonmason@us.ibm.com>, Chinmay Albal <albal@in.ibm.com>
  *	   Now uses ethtool_ops, netif_msg_* and generic_mii_ioctl.
  *	   Fixes bogus 'Bus master arbitration failure', pci_[un]map_single
  *	   length errors, and transmit hangs.  Cleans up after errors in open.
+ *	   Jim Lewis <jklewis@us.ibm.com> added ethernet loopback test.
+ *	   Thomas Munck Steenholdt <tmus@tmus.dk> non-mii ioctl corrections.
  */
 
 
@@ -479,6 +481,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 +1116,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;
@@ -1733,13 +1747,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/plip.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/plip.c	2004-03-16 09:37:56.184998752 +0000
@@ -280,7 +280,7 @@ inline static unsigned char read_status 
 static void
 plip_init_netdev(struct net_device *dev)
 {
-	struct net_local *nl = dev->priv;
+	struct net_local *nl = netdev_priv(dev);
 
 	/* Then, override parts of it */
 	dev->hard_start_xmit	 = plip_tx_packet;
@@ -323,7 +323,7 @@ plip_init_netdev(struct net_device *dev)
 static void
 plip_kick_bh(struct net_device *dev)
 {
-	struct net_local *nl = (struct net_local *)dev->priv;
+	struct net_local *nl = netdev_priv(dev);
 
 	if (nl->is_deferred)
 		schedule_work(&nl->immediate);
@@ -366,7 +366,7 @@ static plip_func connection_state_table[
 static void
 plip_bh(struct net_device *dev)
 {
-	struct net_local *nl = (struct net_local *)dev->priv;
+	struct net_local *nl = netdev_priv(dev);
 	struct plip_local *snd = &nl->snd_data;
 	struct plip_local *rcv = &nl->rcv_data;
 	plip_func f;
@@ -384,7 +384,7 @@ plip_bh(struct net_device *dev)
 static void
 plip_timer_bh(struct net_device *dev)
 {
-	struct net_local *nl = (struct net_local *)dev->priv;
+	struct net_local *nl = netdev_priv(dev);
 	
 	if (!(atomic_read (&nl->kill_timer))) {
 		plip_interrupt (-1, dev, NULL);
@@ -917,7 +917,7 @@ plip_interrupt(int irq, void *dev_id, st
 		return;
 	}
 
-	nl = (struct net_local *)dev->priv;
+	nl = netdev_priv(dev);
 	rcv = &nl->rcv_data;
 
 	spin_lock_irq (&nl->lock);
@@ -961,7 +961,7 @@ plip_interrupt(int irq, void *dev_id, st
 static int
 plip_tx_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct net_local *nl = (struct net_local *)dev->priv;
+	struct net_local *nl = netdev_priv(dev);
 	struct plip_local *snd = &nl->snd_data;
 
 	if (netif_queue_stopped(dev))
@@ -1021,7 +1021,7 @@ plip_hard_header(struct sk_buff *skb, st
                  unsigned short type, void *daddr,
 	         void *saddr, unsigned len)
 {
-	struct net_local *nl = (struct net_local *)dev->priv;
+	struct net_local *nl = netdev_priv(dev);
 	int ret;
 
 	if ((ret = nl->orig_hard_header(skb, dev, type, daddr, saddr, len)) >= 0)
@@ -1033,7 +1033,7 @@ plip_hard_header(struct sk_buff *skb, st
 int plip_hard_header_cache(struct neighbour *neigh,
                            struct hh_cache *hh)
 {
-	struct net_local *nl = (struct net_local *)neigh->dev->priv;
+	struct net_local *nl = neigh->dev->priv;
 	int ret;
 	
 	if ((ret = nl->orig_hard_header_cache(neigh, hh)) == 0)
@@ -1057,7 +1057,7 @@ int plip_hard_header_cache(struct neighb
 static int
 plip_open(struct net_device *dev)
 {
-	struct net_local *nl = (struct net_local *)dev->priv;
+	struct net_local *nl = netdev_priv(dev);
 	struct in_device *in_dev;
 
 	/* Grab the port */
@@ -1116,7 +1116,7 @@ plip_open(struct net_device *dev)
 static int
 plip_close(struct net_device *dev)
 {
-	struct net_local *nl = (struct net_local *)dev->priv;
+	struct net_local *nl = netdev_priv(dev);
 	struct plip_local *snd = &nl->snd_data;
 	struct plip_local *rcv = &nl->rcv_data;
 
@@ -1163,7 +1163,7 @@ static int
 plip_preempt(void *handle)
 {
 	struct net_device *dev = (struct net_device *)handle;
-	struct net_local *nl = (struct net_local *)dev->priv;
+	struct net_local *nl = netdev_priv(dev);
 
 	/* Stand our ground if a datagram is on the wire */
 	if (nl->connection != PLIP_CN_NONE) {
@@ -1179,7 +1179,7 @@ static void
 plip_wakeup(void *handle)
 {
 	struct net_device *dev = (struct net_device *)handle;
-	struct net_local *nl = (struct net_local *)dev->priv;
+	struct net_local *nl = netdev_priv(dev);
 
 	if (nl->port_owner) {
 		/* Why are we being woken up? */
@@ -1207,7 +1207,7 @@ plip_wakeup(void *handle)
 static struct net_device_stats *
 plip_get_stats(struct net_device *dev)
 {
-	struct net_local *nl = (struct net_local *)dev->priv;
+	struct net_local *nl = netdev_priv(dev);
 	struct net_device_stats *r = &nl->enet_stats;
 
 	return r;
@@ -1216,7 +1216,7 @@ plip_get_stats(struct net_device *dev)
 static int
 plip_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct net_local *nl = (struct net_local *) dev->priv;
+	struct net_local *nl = netdev_priv(dev);
 	struct plipconf *pc = (struct plipconf *) &rq->ifr_data;
 
 	switch(pc->pcmd) {
@@ -1288,7 +1288,7 @@ static void plip_attach (struct parport 
 		                 "which is fairly inefficient!\n", port->name);
 		}
 
-		nl = dev->priv;
+		nl = netdev_priv(dev);
 		nl->pardev = parport_register_device(port, name, plip_preempt,
 						 plip_wakeup, plip_interrupt, 
 						 0, dev);
@@ -1348,7 +1348,7 @@ static void __exit plip_cleanup_module (
 
 	for (i=0; i < PLIP_MAX; i++) {
 		if ((dev = dev_plip[i])) {
-			struct net_local *nl = dev->priv;
+			struct net_local *nl = netdev_priv(dev);
 			unregister_netdev(dev);
 			if (nl->port_owner)
 				parport_release(nl->pardev);
--- diff/drivers/net/ppp_generic.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/ppp_generic.c	2004-03-16 09:37:56.185998600 +0000
@@ -45,6 +45,7 @@
 #include <linux/smp_lock.h>
 #include <linux/rwsem.h>
 #include <linux/stddef.h>
+#include <linux/device.h>
 #include <net/slhc_vj.h>
 #include <asm/atomic.h>
 
@@ -271,6 +272,8 @@ static int ppp_connect_channel(struct ch
 static int ppp_disconnect_channel(struct channel *pch);
 static void ppp_destroy_channel(struct channel *pch);
 
+static struct class_simple *ppp_class;
+
 /* Translates a PPP protocol number to a NP index (NP == network protocol) */
 static inline int proto_to_npindex(int proto)
 {
@@ -804,15 +807,29 @@ static int __init ppp_init(void)
 	printk(KERN_INFO "PPP generic driver version " PPP_VERSION "\n");
 	err = register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops);
 	if (!err) {
+		ppp_class = class_simple_create(THIS_MODULE, "ppp");
+		if (IS_ERR(ppp_class)) {
+			err = PTR_ERR(ppp_class);
+			goto out_chrdev;
+		}
+		class_simple_device_add(ppp_class, MKDEV(PPP_MAJOR, 0), NULL, "ppp");
 		err = devfs_mk_cdev(MKDEV(PPP_MAJOR, 0),
 				S_IFCHR|S_IRUSR|S_IWUSR, "ppp");
 		if (err)
-			unregister_chrdev(PPP_MAJOR, "ppp");
+			goto out_class;
 	}
 
+out:
 	if (err)
 		printk(KERN_ERR "failed to register PPP device (%d)\n", err);
 	return err;
+
+out_class:
+	class_simple_device_remove(MKDEV(PPP_MAJOR,0));
+	class_simple_destroy(ppp_class);
+out_chrdev:
+	unregister_chrdev(PPP_MAJOR, "ppp");
+	goto out;
 }
 
 /*
@@ -2545,6 +2562,8 @@ static void __exit ppp_cleanup(void)
 	if (unregister_chrdev(PPP_MAJOR, "ppp") != 0)
 		printk(KERN_ERR "PPP: failed to unregister PPP device\n");
 	devfs_remove("ppp");
+	class_simple_device_remove(MKDEV(PPP_MAJOR, 0));
+	class_simple_destroy(ppp_class);
 }
 
 /*
--- diff/drivers/net/r8169.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/r8169.c	2004-03-16 09:37:56.189997992 +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 14:46:15.000000000 +0000
+++ source/drivers/net/rrunner.c	2004-03-16 09:37:56.191997688 +0000
@@ -108,7 +108,7 @@ static int __devinit rr_init_one(struct 
 		goto out2;
 	}
 
-	rrpriv = (struct rr_private *)dev->priv;
+	rrpriv = netdev_priv(dev);
 
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
@@ -236,7 +236,7 @@ static void __devexit rr_remove_one (str
 	struct net_device *dev = pci_get_drvdata(pdev);
 
 	if (dev) {
-		struct rr_private *rr = dev->priv;
+		struct rr_private *rr = netdev_priv(dev);
 
 		if (!(readl(&rr->regs->HostCtrl) & NIC_HALTED)){
 			printk(KERN_ERR "%s: trying to unload running NIC\n",
@@ -308,7 +308,7 @@ static int rr_reset(struct net_device *d
 	u32 start_pc;
 	int i;
 
-	rrpriv = (struct rr_private *)dev->priv;
+	rrpriv = netdev_priv(dev);
 	regs = rrpriv->regs;
 
 	rr_load_firmware(dev);
@@ -524,7 +524,7 @@ static int __init rr_init(struct net_dev
 	u32 sram_size, rev;
 	int i;
 
-	rrpriv = (struct rr_private *)dev->priv;
+	rrpriv = netdev_priv(dev);
 	regs = rrpriv->regs;
 
 	rev = readl(&regs->FwRev);
@@ -595,7 +595,7 @@ static int rr_init1(struct net_device *d
 	int ecode = 0;
 	short i;
 
-	rrpriv = (struct rr_private *)dev->priv;
+	rrpriv = netdev_priv(dev);
 	regs = rrpriv->regs;
 
 	spin_lock_irqsave(&rrpriv->lock, flags);
@@ -761,7 +761,7 @@ static u32 rr_handle_event(struct net_de
 	struct rr_regs *regs;
 	u32 tmp;
 
-	rrpriv = (struct rr_private *)dev->priv;
+	rrpriv = netdev_priv(dev);
 	regs = rrpriv->regs;
 
 	while (prodidx != eidx){
@@ -960,7 +960,7 @@ static u32 rr_handle_event(struct net_de
 
 static void rx_int(struct net_device *dev, u32 rxlimit, u32 index)
 {
-	struct rr_private *rrpriv = (struct rr_private *)dev->priv;
+	struct rr_private *rrpriv = netdev_priv(dev);
 	struct rr_regs *regs = rrpriv->regs;
 
 	do {
@@ -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;
 
@@ -1052,7 +1060,7 @@ static irqreturn_t rr_interrupt(int irq,
 	struct net_device *dev = (struct net_device *)dev_id;
 	u32 prodidx, rxindex, eidx, txcsmr, rxlimit, txcon;
 
-	rrpriv = (struct rr_private *)dev->priv;
+	rrpriv = netdev_priv(dev);
 	regs = rrpriv->regs;
 
 	if (!(readl(&regs->HostCtrl) & RR_INT))
@@ -1133,7 +1141,7 @@ static irqreturn_t rr_interrupt(int irq,
 static void rr_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct rr_private *rrpriv = (struct rr_private *)dev->priv;
+	struct rr_private *rrpriv = netdev_priv(dev);
 	struct rr_regs *regs = rrpriv->regs;
 	unsigned long flags;
 
@@ -1160,7 +1168,7 @@ static void rr_timer(unsigned long data)
 
 static int rr_open(struct net_device *dev)
 {
-	struct rr_private *rrpriv = (struct rr_private *)dev->priv;
+	struct rr_private *rrpriv = netdev_priv(dev);
 	struct pci_dev *pdev = rrpriv->pci_dev;
 	struct rr_regs *regs;
 	int ecode = 0;
@@ -1296,7 +1304,7 @@ static void rr_dump(struct net_device *d
 	short i;
 	int len;
 
-	rrpriv = (struct rr_private *)dev->priv;
+	rrpriv = netdev_priv(dev);
 	regs = rrpriv->regs;
 
 	printk("%s: dumping NIC TX rings\n", dev->name);
@@ -1361,7 +1369,7 @@ static int rr_close(struct net_device *d
 
 	netif_stop_queue(dev);
 
-	rrpriv = (struct rr_private *)dev->priv;
+	rrpriv = netdev_priv(dev);
 	regs = rrpriv->regs;
 
 	/*
@@ -1418,7 +1426,7 @@ static int rr_close(struct net_device *d
 
 static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct rr_private *rrpriv = (struct rr_private *)dev->priv;
+	struct rr_private *rrpriv = netdev_priv(dev);
 	struct rr_regs *regs = rrpriv->regs;
 	struct ring_ctrl *txctrl;
 	unsigned long flags;
@@ -1488,7 +1496,7 @@ static struct net_device_stats *rr_get_s
 {
 	struct rr_private *rrpriv;
 
-	rrpriv = (struct rr_private *)dev->priv;
+	rrpriv = netdev_priv(dev);
 
 	return(&rrpriv->stats);
 }
@@ -1511,7 +1519,7 @@ static int rr_load_firmware(struct net_d
 	u32 p2len, p2size, nr_seg, revision, io, sram_size;
 	struct eeprom *hw = NULL;
 
-	rrpriv = (struct rr_private *)dev->priv;
+	rrpriv = netdev_priv(dev);
 	regs = rrpriv->regs;
 
 	if (dev->flags & IFF_UP)
@@ -1614,7 +1622,7 @@ static int rr_ioctl(struct net_device *d
 	unsigned int i;
 	int error = -EOPNOTSUPP;
 
-	rrpriv = dev->priv;
+	rrpriv = netdev_priv(dev);
 
 	switch(cmd){
 	case SIOCRRGFW:
--- diff/drivers/net/sb1000.c	2003-09-30 14:46:15.000000000 +0000
+++ source/drivers/net/sb1000.c	2004-03-16 09:37:56.192997536 +0000
@@ -746,7 +746,7 @@ sb1000_rx(struct net_device *dev)
 	int ioaddr, ns;
 	unsigned int skbsize;
 	struct sk_buff *skb;
-	struct sb1000_private *lp = (struct sb1000_private *)dev->priv;
+	struct sb1000_private *lp = netdev_priv(dev);
 	struct net_device_stats *stats = &lp->stats;
 
 	/* SB1000 frame constants */
@@ -905,7 +905,7 @@ sb1000_error_dpc(struct net_device *dev)
 	char *name;
 	unsigned char st[5];
 	int ioaddr[2];
-	struct sb1000_private *lp = (struct sb1000_private *)dev->priv;
+	struct sb1000_private *lp = netdev_priv(dev);
 	const unsigned char Command0[6] = {0x80, 0x26, 0x00, 0x00, 0x00, 0x00};
 	const int ErrorDpcCounterInitialize = 200;
 
@@ -932,7 +932,7 @@ sb1000_open(struct net_device *dev)
 {
 	char *name;
 	int ioaddr[2], status;
-	struct sb1000_private *lp = (struct sb1000_private *)dev->priv;
+	struct sb1000_private *lp = netdev_priv(dev);
 	const unsigned short FirmwareVersion[] = {0x01, 0x01};
 
 	ioaddr[0] = dev->base_addr;
@@ -998,7 +998,7 @@ static int sb1000_dev_ioctl(struct net_d
 	short PID[4];
 	int ioaddr[2], status, frequency;
 	unsigned int stats[5];
-	struct sb1000_private *lp = (struct sb1000_private *)dev->priv;
+	struct sb1000_private *lp = netdev_priv(dev);
 
 	if (!(dev && dev->flags & IFF_UP))
 		return -ENODEV;
@@ -1092,7 +1092,7 @@ static irqreturn_t sb1000_interrupt(int 
 	unsigned char st;
 	int ioaddr[2];
 	struct net_device *dev = (struct net_device *) dev_id;
-	struct sb1000_private *lp = (struct sb1000_private *)dev->priv;
+	struct sb1000_private *lp = netdev_priv(dev);
 
 	const unsigned char Command0[6] = {0x80, 0x2c, 0x00, 0x00, 0x00, 0x00};
 	const unsigned char Command1[6] = {0x80, 0x2e, 0x00, 0x00, 0x00, 0x00};
@@ -1148,7 +1148,7 @@ static irqreturn_t sb1000_interrupt(int 
 
 static struct net_device_stats *sb1000_stats(struct net_device *dev)
 {
-	struct sb1000_private *lp = (struct sb1000_private *)dev->priv;
+	struct sb1000_private *lp = netdev_priv(dev);
 	return &lp->stats;
 }
 
@@ -1156,7 +1156,7 @@ static int sb1000_close(struct net_devic
 {
 	int i;
 	int ioaddr[2];
-	struct sb1000_private *lp = (struct sb1000_private *)dev->priv;
+	struct sb1000_private *lp = netdev_priv(dev);
 
 	if (sb1000_debug > 2)
 		printk(KERN_DEBUG "%s: Shutting down sb1000.\n", dev->name);
--- diff/drivers/net/sb1250-mac.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/sb1250-mac.c	2004-03-16 09:37:56.201996168 +0000
@@ -2080,7 +2080,7 @@ static int sbmac_set_duplex(struct sbmac
 static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs)
 {
 	struct net_device *dev = (struct net_device *) dev_instance;
-	struct sbmac_softc *sc = (struct sbmac_softc *) (dev->priv);
+	struct sbmac_softc *sc = netdev_priv(dev);
 	uint64_t isr;
 	int handled = 0;
 
@@ -2150,7 +2150,7 @@ static irqreturn_t sbmac_intr(int irq,vo
  ********************************************************************* */
 static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+	struct sbmac_softc *sc = netdev_priv(dev);
 	
 	/* lock eth irq */
 	spin_lock_irq (&sc->sbm_lock);
@@ -2374,7 +2374,7 @@ static int sbmac_init(struct net_device 
 	int i;
 	int err;
 	
-	sc = (struct sbmac_softc *)dev->priv;
+	sc = netdev_priv(dev);
 	
 	/* Determine controller base address */
 	
@@ -2454,7 +2454,7 @@ static int sbmac_init(struct net_device 
 
 static int sbmac_open(struct net_device *dev)
 {
-	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+	struct sbmac_softc *sc = netdev_priv(dev);
 	
 	if (debug > 1) {
 		printk(KERN_DEBUG "%s: sbmac_open() irq %d.\n", dev->name, dev->irq);
@@ -2609,7 +2609,7 @@ static int sbmac_mii_poll(struct sbmac_s
 static void sbmac_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+	struct sbmac_softc *sc = netdev_priv(dev);
 	int next_tick = HZ;
 	int mii_status;
 
@@ -2655,7 +2655,7 @@ static void sbmac_timer(unsigned long da
 
 static void sbmac_tx_timeout (struct net_device *dev)
 {
-	struct sbmac_softc *sc = (struct sbmac_softc *) dev->priv;
+	struct sbmac_softc *sc = netdev_priv(dev);
 	
 	spin_lock_irq (&sc->sbm_lock);
 	
@@ -2673,7 +2673,7 @@ static void sbmac_tx_timeout (struct net
 
 static struct net_device_stats *sbmac_get_stats(struct net_device *dev)
 {
-	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+	struct sbmac_softc *sc = netdev_priv(dev);
 	unsigned long flags;
 	
 	spin_lock_irqsave(&sc->sbm_lock, flags);
@@ -2691,7 +2691,7 @@ static void sbmac_set_rx_mode(struct net
 {
 	unsigned long flags;
 	int msg_flag = 0;
-	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+	struct sbmac_softc *sc = netdev_priv(dev);
 
 	spin_lock_irqsave(&sc->sbm_lock, flags);
 	if ((dev->flags ^ sc->sbm_devflags) & IFF_PROMISC) {
@@ -2726,7 +2726,7 @@ static void sbmac_set_rx_mode(struct net
 
 static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+	struct sbmac_softc *sc = netdev_priv(dev);
 	u16 *data = (u16 *)&rq->ifr_data;
 	unsigned long flags;
 	int retval;
@@ -2762,7 +2762,7 @@ static int sbmac_mii_ioctl(struct net_de
 
 static int sbmac_close(struct net_device *dev)
 {
-	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+	struct sbmac_softc *sc = netdev_priv(dev);
 	unsigned long flags;
 	int irq;
 
@@ -2911,7 +2911,7 @@ sbmac_cleanup_module(void)
 	for (idx = 0; idx < MAX_UNITS; idx++) {
 		dev = dev_sbmac[idx];
 		if (!dev) {
-			struct sbmac_softc *sc = dev->priv;
+			struct sbmac_softc *sc = netdev_priv(dev);
 			unregister_netdev(dev);
 			sbmac_uninitctx(sc);
 			free_netdev(dev);
--- diff/drivers/net/seeq8005.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/seeq8005.c	2004-03-16 09:37:56.203995864 +0000
@@ -357,7 +357,7 @@ out:
    */
 static int seeq8005_open(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	{
 		 int irqval = request_irq(dev->irq, &seeq8005_interrupt, 0, "seeq8005", dev);
@@ -390,7 +390,7 @@ static void seeq8005_timeout(struct net_
 
 static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	short length = skb->len;
 	unsigned char *buf;
 
@@ -424,7 +424,7 @@ static irqreturn_t seeq8005_interrupt(in
 	int handled = 0;
 
 	ioaddr = dev->base_addr;
-	lp = (struct net_local *)dev->priv;
+	lp = netdev_priv(dev);
 
 	status = inw(SEEQ_STATUS);
 	do {
@@ -462,7 +462,7 @@ static irqreturn_t seeq8005_interrupt(in
 /* We have a good packet(s), get it/them out of the buffers. */
 static void seeq8005_rx(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int boguscount = 10;
 	int pkt_hdr;
 	int ioaddr = dev->base_addr;
@@ -561,7 +561,7 @@ static void seeq8005_rx(struct net_devic
 /* The inverse routine to net_open(). */
 static int seeq8005_close(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	lp->open_time = 0;
@@ -583,7 +583,7 @@ static int seeq8005_close(struct net_dev
    closed. */
 static struct net_device_stats *seeq8005_get_stats(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 
 	return &lp->stats;
 }
@@ -618,7 +618,7 @@ static void set_multicast_list(struct ne
 
 void seeq8005_init(struct net_device *dev, int startp)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	int i;
 	
--- diff/drivers/net/sgiseeq.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/sgiseeq.c	2004-03-16 09:37:56.204995712 +0000
@@ -151,7 +151,7 @@ static inline void seeq_load_eaddr(struc
 
 static int seeq_init_ring(struct net_device *dev)
 {
-	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
+	struct sgiseeq_private *sp = netdev_priv(dev);
 	volatile struct sgiseeq_init_block *ib = &sp->srings;
 	int i;
 
@@ -423,7 +423,7 @@ static inline void sgiseeq_tx(struct net
 static irqreturn_t sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
-	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
+	struct sgiseeq_private *sp = netdev_priv(dev);
 	struct hpc3_ethregs *hregs = sp->hregs;
 	struct sgiseeq_regs *sregs = sp->sregs;
 
@@ -445,7 +445,7 @@ static irqreturn_t sgiseeq_interrupt(int
 
 static int sgiseeq_open(struct net_device *dev)
 {
-	struct sgiseeq_private *sp = (struct sgiseeq_private *)dev->priv;
+	struct sgiseeq_private *sp = netdev_priv(dev);
 	struct sgiseeq_regs *sregs = sp->sregs;
 
 	int err = init_seeq(dev, sp, sregs);
@@ -459,7 +459,7 @@ static int sgiseeq_open(struct net_devic
 
 static int sgiseeq_close(struct net_device *dev)
 {
-	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
+	struct sgiseeq_private *sp = netdev_priv(dev);
 	struct sgiseeq_regs *sregs = sp->sregs;
 
 	netif_stop_queue(dev);
@@ -472,7 +472,7 @@ static int sgiseeq_close(struct net_devi
 
 static inline int sgiseeq_reset(struct net_device *dev)
 {
-	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
+	struct sgiseeq_private *sp = netdev_priv(dev);
 	struct sgiseeq_regs *sregs = sp->sregs;
 	int err;
 
@@ -494,7 +494,7 @@ void sgiseeq_my_reset(void)
 
 static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
+	struct sgiseeq_private *sp = netdev_priv(dev);
 	struct hpc3_ethregs *hregs = sp->hregs;
 	unsigned long flags;
 	struct sgiseeq_tx_desc *td;
@@ -560,7 +560,7 @@ static void timeout(struct net_device *d
 
 static struct net_device_stats *sgiseeq_get_stats(struct net_device *dev)
 {
-	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
+	struct sgiseeq_private *sp = netdev_priv(dev);
 
 	return &sp->stats;
 }
@@ -710,7 +710,7 @@ static void __exit sgiseeq_exit(void)
 	struct net_device *next, *dev = root_sgiseeq_dev;
 
 	while (dev) {
-		sp = (struct sgiseeq_private *) dev->priv;
+		sp = netdev_priv(dev);
 		next = sp->next_module;
 		unregister_netdev(dev);
 		free_irq(dev->irq, dev);
--- diff/drivers/net/sis190.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/sis190.c	2004-03-16 09:37:56.205995560 +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-11 10:20:26.000000000 +0000
+++ source/drivers/net/sis900.c	2004-03-16 09:37:56.206995408 +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-11 10:20:26.000000000 +0000
+++ source/drivers/net/sk98lin/skge.c	2004-03-16 09:37:56.210994800 +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/sk_g16.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/sk_g16.c	2004-03-16 09:37:56.211994648 +0000
@@ -650,7 +650,7 @@ int __init SK_probe(struct net_device *d
     int sk_addr_flag = 0;   /* SK ADDR correct? 1 - no, 0 - yes */
     unsigned int rom_addr;  /* used to store RAM address used for POS_ADDR */
 
-    struct priv *p = dev->priv;         /* SK_G16 private structure */
+    struct priv *p = netdev_priv(dev);	/* SK_G16 private structure */
 
     if (inb(SK_POS0) != SK_IDLOW || inb(SK_POS1) != SK_IDHIGH)
 	return -ENODEV;
@@ -869,7 +869,7 @@ static int SK_open(struct net_device *de
 
     int irqtab[] = SK_IRQS; 
 
-    struct priv *p = (struct priv *)dev->priv;
+    struct priv *p = netdev_priv(dev);
 
     PRINTK(("## %s: At beginning of SK_open(). CSR0: %#06x\n", 
            SK_NAME, SK_read_reg(CSR0)));
@@ -1023,7 +1023,7 @@ static int SK_lance_init(struct net_devi
 {
     int i;
     unsigned long flags;
-    struct priv *p = (struct priv *) dev->priv; 
+    struct priv *p = netdev_priv(dev);
     struct tmd  *tmdp;
     struct rmd  *rmdp;
 
@@ -1196,7 +1196,7 @@ static void SK_timeout(struct net_device
 
 static int SK_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-    struct priv *p = (struct priv *) dev->priv;
+    struct priv *p = netdev_priv(dev);
     struct tmd *tmdp;
     static char pad[64];
 
@@ -1285,7 +1285,7 @@ static irqreturn_t SK_interrupt(int irq,
 {
     int csr0;
     struct net_device *dev = dev_id;
-    struct priv *p = (struct priv *) dev->priv;
+    struct priv *p = netdev_priv(dev);
 
 
     PRINTK2(("## %s: SK_interrupt(). status: %#06x\n", 
@@ -1355,7 +1355,7 @@ static void SK_txintr(struct net_device 
 {
     int tmdstat;
     struct tmd *tmdp;
-    struct priv *p = (struct priv *) dev->priv;
+    struct priv *p = netdev_priv(dev);
 
 
     PRINTK2(("## %s: SK_txintr() status: %#06x\n", 
@@ -1469,7 +1469,7 @@ static void SK_rxintr(struct net_device 
 
     struct rmd *rmdp;
     int rmdstat;
-    struct priv *p = (struct priv *) dev->priv;
+    struct priv *p = netdev_priv(dev);
 
     PRINTK2(("## %s: SK_rxintr(). CSR0: %#06x\n", 
             SK_NAME, SK_read_reg(CSR0)));
@@ -1653,7 +1653,7 @@ static int SK_close(struct net_device *d
 static struct net_device_stats *SK_get_stats(struct net_device *dev)
 {
 
-    struct priv *p = (struct priv *) dev->priv;
+    struct priv *p = netdev_priv(dev);
 
     PRINTK(("## %s: SK_get_stats(). CSR0: %#06x\n", 
            SK_NAME, SK_read_reg(CSR0)));
@@ -2030,7 +2030,7 @@ void __init SK_print_ram(struct net_devi
 {
 
     int i;    
-    struct priv *p = (struct priv *) dev->priv;
+    struct priv *p = netdev_priv(dev);
 
     printk("## %s: RAM Details.\n"
            "##   RAM at %#08x tmdhead: %#08x rmdhead: %#08x initblock: %#08x\n",
--- diff/drivers/net/slip.c	2003-10-27 09:20:38.000000000 +0000
+++ source/drivers/net/slip.c	2004-03-16 09:37:56.212994496 +0000
@@ -1307,7 +1307,7 @@ static int sl_ioctl(struct net_device *d
 		/* Resolve race condition, when ioctl'ing hanged up 
 		   and opened by another process device.
 		 */
-		if (sl->tty != current->tty && sl->pid != current->pid) {
+		if (sl->tty != current->signal->tty && sl->pid != current->pid) {
 			spin_unlock_bh(&sl->lock);
 			return -EPERM;
 		}
--- diff/drivers/net/smc-mca.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/smc-mca.c	2004-03-16 09:37:56.213994344 +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-16 09:37:56.214994192 +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-16 09:37:56.214994192 +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/smc9194.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/smc9194.c	2004-03-16 09:37:56.215994040 +0000
@@ -465,7 +465,7 @@ static void smc_setmulticast( int ioaddr
 */
 static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * dev )
 {
-	struct smc_local *lp 	= (struct smc_local *)dev->priv;
+	struct smc_local *lp = netdev_priv(dev);
 	unsigned short ioaddr 	= dev->base_addr;
 	word 			length;
 	unsigned short 		numPages;
@@ -576,7 +576,7 @@ static int smc_wait_to_send_packet( stru
 */
 static void smc_hardware_send_packet( struct net_device * dev )
 {
-	struct smc_local *lp = (struct smc_local *)dev->priv;
+	struct smc_local *lp = netdev_priv(dev);
 	byte	 		packet_no;
 	struct sk_buff * 	skb = lp->saved_skb;
 	word			length;
@@ -1150,7 +1150,7 @@ static irqreturn_t smc_interrupt(int irq
 {
 	struct net_device *dev 	= dev_id;
 	int ioaddr 		= dev->base_addr;
-	struct smc_local *lp 	= (struct smc_local *)dev->priv;
+	struct smc_local *lp = netdev_priv(dev);
 
 	byte	status;
 	word	card_stats;
@@ -1274,7 +1274,7 @@ static irqreturn_t smc_interrupt(int irq
 */
 static void smc_rcv(struct net_device *dev)
 {
-	struct smc_local *lp = (struct smc_local *)dev->priv;
+	struct smc_local *lp = netdev_priv(dev);
 	int 	ioaddr = dev->base_addr;
 	int 	packet_number;
 	word	status;
@@ -1401,7 +1401,7 @@ done:
 static void smc_tx( struct net_device * dev )
 {
 	int	ioaddr = dev->base_addr;
-	struct smc_local *lp = (struct smc_local *)dev->priv;
+	struct smc_local *lp = netdev_priv(dev);
 	byte saved_packet;
 	byte packet_no;
 	word tx_status;
@@ -1474,7 +1474,7 @@ static int smc_close(struct net_device *
  . This may be called with the card open or closed.
  .-------------------------------------------------------------*/
 static struct net_device_stats* smc_query_statistics(struct net_device *dev) {
-	struct smc_local *lp = (struct smc_local *)dev->priv;
+	struct smc_local *lp = netdev_priv(dev);
 
 	return &lp->stats;
 }
--- diff/drivers/net/starfire.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/net/starfire.c	2004-03-16 09:37:56.217993736 +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-16 09:37:56.218993584 +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/sun3lance.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/sun3lance.c	2004-03-16 09:37:56.219993432 +0000
@@ -332,7 +332,7 @@ static int __init lance_probe( struct ne
 		return 0;
 	}
 
-	lp = (struct lance_private *)dev->priv;
+	lp = netdev_priv(dev);
 
 	/* XXX - leak? */
 	MEM = dvma_malloc_align(sizeof(struct lance_memory), 0x10000);
@@ -402,7 +402,7 @@ static int __init lance_probe( struct ne
 
 static int lance_open( struct net_device *dev )
 {
-	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	int i;
 
 	DPRINTK( 2, ( "%s: lance_open()\n", dev->name ));
@@ -439,7 +439,7 @@ static int lance_open( struct net_device
 
 static void lance_init_ring( struct net_device *dev )
 {
-	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	int i;
 
 	lp->lock = 0;
@@ -499,7 +499,7 @@ static void lance_init_ring( struct net_
 
 static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
 {
-	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	int entry, len;
 	struct lance_tx_head *head;
 	unsigned long flags;
@@ -646,7 +646,7 @@ static int lance_start_xmit( struct sk_b
 static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp)
 {
 	struct net_device *dev = dev_id;
-	struct lance_private *lp = dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	int csr0;
 	static int in_interrupt;
 
@@ -772,7 +772,7 @@ static irqreturn_t lance_interrupt( int 
 /* get packet, toss into skbuff */
 static int lance_rx( struct net_device *dev )
 {
-	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	int entry = lp->new_rx;
 
 	/* If we own the next entry, it's a new packet. Send it up. */
@@ -870,7 +870,7 @@ static int lance_rx( struct net_device *
 
 static int lance_close( struct net_device *dev )
 {
-	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 
 	netif_stop_queue(dev);
 
@@ -888,7 +888,7 @@ static int lance_close( struct net_devic
 
 static struct net_device_stats *lance_get_stats( struct net_device *dev )
 {
-	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 
 	return &lp->stats;
 }
@@ -904,7 +904,7 @@ static struct net_device_stats *lance_ge
 /* completely untested on a sun3 */
 static void set_multicast_list( struct net_device *dev )
 {
-	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 
 	if(netif_queue_stopped(dev))
 		/* Only possible if board is already started */
--- diff/drivers/net/sunbmac.c	2003-10-27 09:20:38.000000000 +0000
+++ source/drivers/net/sunbmac.c	2004-03-16 09:37:56.220993280 +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-11 10:20:26.000000000 +0000
+++ source/drivers/net/sundance.c	2004-03-16 09:37:56.222992976 +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-11 10:20:26.000000000 +0000
+++ source/drivers/net/sungem.c	2004-03-16 09:37:56.230991760 +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-16 09:37:56.233991304 +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 10:49:45.000000000 +0000
+++ source/drivers/net/sunhme.h	2004-03-16 09:37:56.233991304 +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/sunlance.c	2003-10-27 09:20:38.000000000 +0000
+++ source/drivers/net/sunlance.c	2004-03-16 09:37:56.235991000 +0000
@@ -313,7 +313,7 @@ static void load_csrs(struct lance_priva
 /* Setup the Lance Rx and Tx rings */
 static void lance_init_ring_dvma(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_init_block *ib = lp->init_block;
 	dma_addr_t aib = lp->init_block_dvma;
 	__u32 leptr;
@@ -370,7 +370,7 @@ static void lance_init_ring_dvma(struct 
 
 static void lance_init_ring_pio(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_init_block *ib = lp->init_block;
 	u32 leptr;
 	int i;
@@ -500,7 +500,7 @@ static int init_restart_lance(struct lan
 
 static void lance_rx_dvma(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_init_block *ib = lp->init_block;
 	volatile struct lance_rx_desc *rd;
 	u8 bits;
@@ -563,7 +563,7 @@ static void lance_rx_dvma(struct net_dev
 
 static void lance_tx_dvma(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_init_block *ib = lp->init_block;
 	int i, j;
 
@@ -673,7 +673,7 @@ static void lance_piocopy_to_skb(struct 
 
 static void lance_rx_pio(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_init_block *ib = lp->init_block;
 	volatile struct lance_rx_desc *rd;
 	unsigned char bits;
@@ -735,7 +735,7 @@ static void lance_rx_pio(struct net_devi
 
 static void lance_tx_pio(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_init_block *ib = lp->init_block;
 	int i, j;
 
@@ -816,7 +816,7 @@ out:
 static irqreturn_t lance_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *)dev_id;
-	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	int csr0;
     
 	sbus_writew(LE_CSR0, lp->lregs + RAP);
@@ -915,7 +915,7 @@ struct net_device *last_dev = 0;
 
 static int lance_open(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_init_block *ib = lp->init_block;
 	int status = 0;
 
@@ -968,7 +968,7 @@ static int lance_open(struct net_device 
 
 static int lance_close(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 
 	netif_stop_queue(dev);
 	del_timer_sync(&lp->multicast_timer);
@@ -981,7 +981,7 @@ static int lance_close(struct net_device
 
 static int lance_reset(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	int status;
     
 	STOP_LANCE(lp);
@@ -1102,7 +1102,7 @@ static void lance_piozero(volatile void 
 
 static void lance_tx_timeout(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 
 	printk(KERN_ERR "%s: transmit timed out, status %04x, reset\n",
 	       dev->name, sbus_readw(lp->lregs + RDP));
@@ -1112,7 +1112,7 @@ static void lance_tx_timeout(struct net_
 
 static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_init_block *ib = lp->init_block;
 	int entry, skblen, len;
 
@@ -1165,7 +1165,7 @@ static int lance_start_xmit(struct sk_bu
 
 static struct net_device_stats *lance_get_stats(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 
 	return &lp->stats;
 }
@@ -1173,7 +1173,7 @@ static struct net_device_stats *lance_ge
 /* taken from the depca driver */
 static void lance_load_multicast(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_init_block *ib = lp->init_block;
 	volatile u16 *mcast_table = (u16 *) &ib->filter;
 	struct dev_mc_list *dmi = dev->mc_list;
@@ -1223,7 +1223,7 @@ static void lance_load_multicast(struct 
 
 static void lance_set_multicast(struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	volatile struct lance_init_block *ib = lp->init_block;
 	u16 mode;
 
@@ -1291,7 +1291,7 @@ static void lance_free_hwresources(struc
 /* Ethtool support... */
 static void sparc_lance_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct lance_private *lp = dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 
 	strcpy(info->driver, "sunlance");
 	strcpy(info->version, "2.02");
@@ -1325,7 +1325,7 @@ static int __init sparc_lance_init(struc
 	if (!dev)
 		return -ENOMEM;
 
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 
 	if (sparc_lance_debug && version_printed++ == 0)
 		printk (KERN_INFO "%s", version);
--- diff/drivers/net/tg3.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/tg3.c	2004-03-16 09:37:56.240990240 +0000
@@ -2280,8 +2280,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;
@@ -2466,6 +2467,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;
@@ -7614,6 +7622,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-16 09:37:56.243989784 +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-11 10:20:26.000000000 +0000
+++ source/drivers/net/tokenring/3c359.c	2004-03-16 09:37:56.244989632 +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/abyss.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/tokenring/abyss.c	2004-03-16 09:37:56.245989480 +0000
@@ -154,7 +154,7 @@ static int __devinit abyss_attach(struct
 		printk(":%2.2x", dev->dev_addr[i]);
 	printk("\n");
 
-	tp = dev->priv;
+	tp = netdev_priv(dev);
 	tp->setnselout = abyss_setnselout_pins;
 	tp->sifreadb = abyss_sifreadb;
 	tp->sifreadw = abyss_sifreadw;
@@ -188,7 +188,7 @@ err_out_trdev:
 static unsigned short abyss_setnselout_pins(struct net_device *dev)
 {
 	unsigned short val = 0;
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	
 	if(tp->DataRate == SPEED_4)
 		val |= 0x01;  /* Set 4Mbps */
@@ -398,7 +398,7 @@ static void abyss_read_eeprom(struct net
 	unsigned short val;
 	int i;
 	
-	tp = (struct net_local *)dev->priv;
+	tp = netdev_priv(dev);
 	ioaddr = dev->base_addr;
 	
 	/* Must enable glue chip first */
--- diff/drivers/net/tokenring/madgemc.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/tokenring/madgemc.c	2004-03-16 09:37:56.246989328 +0000
@@ -365,7 +365,7 @@ static int __init madgemc_probe(void)
 				return 0;
 			return -1;
 		}
-		tp = (struct net_local *)dev->priv;
+		tp = netdev_priv(dev);
 
 		/* 
 		 * The MC16 is physically a 32bit card.  However, Madge
@@ -504,7 +504,7 @@ static irqreturn_t madgemc_interrupt(int
 unsigned short madgemc_setnselout_pins(struct net_device *dev)
 {
 	unsigned char reg1;
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	
 	reg1 = inb(dev->base_addr + MC_CONTROL_REG1);
 
@@ -731,7 +731,7 @@ static int madgemc_mcaproc(char *buf, in
 	}
 	len += sprintf(buf+len, "-------\n");
 	if (curcard) {
-		struct net_local *tp = (struct net_local *)dev->priv;
+		struct net_local *tp = netdev_priv(dev);
 		int i;
 		
 		len += sprintf(buf+len, "Card Revision: %d\n", curcard->cardrev);
--- diff/drivers/net/tokenring/olympic.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/tokenring/olympic.c	2004-03-16 09:37:56.248989024 +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/tokenring/proteon.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/tokenring/proteon.c	2004-03-16 09:37:56.248989024 +0000
@@ -158,7 +158,7 @@ static int __init setup_card(struct net_
 		printk(":%2.2x", dev->dev_addr[j]);
 	printk("\n");
 		
-	tp = (struct net_local *)dev->priv;
+	tp = netdev_priv(dev);
 	tp->setnselout = proteon_setnselout_pins;
 		
 	tp->sifreadb = proteon_sifreadb;
@@ -316,7 +316,7 @@ unsigned short proteon_setnselout_pins(s
 
 static int proteon_open(struct net_device *dev)
 {  
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	unsigned short val = 0;
 	int i;
 
--- diff/drivers/net/tokenring/skisa.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/tokenring/skisa.c	2004-03-16 09:37:56.256987808 +0000
@@ -175,7 +175,7 @@ static int __init setup_card(struct net_
 		printk(":%2.2x", dev->dev_addr[j]);
 	printk("\n");
 		
-	tp = (struct net_local *)dev->priv;
+	tp = netdev_priv(dev);
 	tp->setnselout = sk_isa_setnselout_pins;
 		
 	tp->sifreadb = sk_isa_sifreadb;
@@ -332,7 +332,7 @@ unsigned short sk_isa_setnselout_pins(st
 
 static int sk_isa_open(struct net_device *dev)
 {  
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	unsigned short val = 0;
 	unsigned short oldval;
 	int i;
--- diff/drivers/net/tokenring/smctr.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/tokenring/smctr.c	2004-03-16 09:37:56.262986896 +0000
@@ -327,7 +327,7 @@ static int smctr_wait_while_cbusy(struct
  */
 static int smctr_alloc_shared_memory(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         if(smctr_debug > 10)
                 printk(KERN_DEBUG "%s: smctr_alloc_shared_memory\n", dev->name);
@@ -454,7 +454,7 @@ static int smctr_bypass_state(struct net
 
 static int smctr_checksum_firmware(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         __u16 i, checksum = 0;
 
         if(smctr_debug > 10)
@@ -477,10 +477,10 @@ static int smctr_checksum_firmware(struc
         return (0);
 }
 
-static int smctr_chk_mca(struct net_device *dev)
+static int __init smctr_chk_mca(struct net_device *dev)
 {
 #ifdef CONFIG_MCA
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	int current_slot;
 	__u8 r1, r2, r3, r4, r5;
 
@@ -631,7 +631,7 @@ static int smctr_chk_mca(struct net_devi
 
 static int smctr_chg_rx_mask(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int err = 0;
 
         if(smctr_debug > 10)
@@ -694,7 +694,7 @@ static int smctr_chg_rx_mask(struct net_
 
 static int smctr_clear_int(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         outb((tp->trc_mask | CSR_CLRTINT), dev->base_addr + CSR);
 
@@ -716,7 +716,7 @@ static int smctr_clear_trc_reset(int ioa
  */
 static int smctr_close(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         struct sk_buff *skb;
         int err;
 
@@ -752,7 +752,7 @@ static int smctr_close(struct net_device
 
 static int smctr_decode_firmware(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         short bit = 0x80, shift = 12;
         DECODE_TREE_NODE *tree;
         short branch, tsize;
@@ -823,7 +823,7 @@ static int smctr_disable_16bit(struct ne
  */
 static int smctr_disable_adapter_ctrl_store(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int ioaddr = dev->base_addr;
 
         if(smctr_debug > 10)
@@ -837,7 +837,7 @@ static int smctr_disable_adapter_ctrl_st
 
 static int smctr_disable_bic_int(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int ioaddr = dev->base_addr;
 
         tp->trc_mask = CSR_MSK_ALL | CSR_MSKCBUSY
@@ -849,7 +849,7 @@ static int smctr_disable_bic_int(struct 
 
 static int smctr_enable_16bit(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         __u8    r;
 
         if(tp->adapter_bus == BUS_ISA16_TYPE)
@@ -869,7 +869,7 @@ static int smctr_enable_16bit(struct net
  */
 static int smctr_enable_adapter_ctrl_store(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int ioaddr = dev->base_addr;
 
         if(smctr_debug > 10)
@@ -900,7 +900,7 @@ static int smctr_enable_adapter_ram(stru
 
 static int smctr_enable_bic_int(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int ioaddr = dev->base_addr;
         __u8 r;
 
@@ -926,7 +926,7 @@ static int smctr_enable_bic_int(struct n
 
 static int __init smctr_chk_isa(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int ioaddr = dev->base_addr;
         __u8 r1, r2, b, chksum = 0;
         __u16 r;
@@ -1155,7 +1155,7 @@ out:
 
 static int __init smctr_get_boardid(struct net_device *dev, int mca)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int ioaddr = dev->base_addr;
         __u8 r, r1, IdByte;
         __u16 BoardIdMask;
@@ -1273,7 +1273,7 @@ static int smctr_get_functional_address(
  */
 static unsigned int smctr_get_num_rx_bdbs(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         unsigned int mem_used = 0;
 
         /* Allocate System Control Blocks. */
@@ -1358,7 +1358,7 @@ static int smctr_get_physical_drop_numbe
 
 static __u8 * smctr_get_rx_pointer(struct net_device *dev, short queue)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         BDBlock *bdb;
 
         bdb = (BDBlock *)((__u32)tp->ram_access
@@ -1382,7 +1382,7 @@ static int smctr_get_station_id(struct n
  */
 static struct net_device_stats *smctr_get_stats(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         return ((struct net_device_stats *)&tp->MacStat);
 }
@@ -1390,7 +1390,7 @@ static struct net_device_stats *smctr_ge
 static FCBlock *smctr_get_tx_fcb(struct net_device *dev, __u16 queue,
         __u16 bytes_count)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         FCBlock *pFCB;
         BDBlock *pbdb;
         unsigned short alloc_size;
@@ -1513,7 +1513,7 @@ static int smctr_hardware_send_packet(st
 
 static int smctr_init_acbs(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         unsigned int i;
         ACBlock *acb;
 
@@ -1557,7 +1557,7 @@ static int smctr_init_acbs(struct net_de
 
 static int smctr_init_adapter(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int err;
 
         if(smctr_debug > 10)
@@ -1640,7 +1640,7 @@ static int smctr_init_adapter(struct net
 
 static int smctr_init_card_real(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int err = 0;
 
         if(smctr_debug > 10)
@@ -1716,7 +1716,7 @@ static int smctr_init_card_real(struct n
 
 static int smctr_init_rx_bdbs(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         unsigned int i, j;
         BDBlock *bdb;
         __u16 *buf;
@@ -1768,7 +1768,7 @@ static int smctr_init_rx_bdbs(struct net
 
 static int smctr_init_rx_fcbs(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         unsigned int i, j;
         FCBlock *fcb;
 
@@ -1818,7 +1818,7 @@ static int smctr_init_rx_fcbs(struct net
 
 static int smctr_init_shared_memory(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         unsigned int i;
         __u32 *iscpb;
 
@@ -1876,7 +1876,7 @@ static int smctr_init_shared_memory(stru
 
 static int smctr_init_tx_bdbs(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         unsigned int i, j;
         BDBlock *bdb;
 
@@ -1906,7 +1906,7 @@ static int smctr_init_tx_bdbs(struct net
 
 static int smctr_init_tx_fcbs(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         unsigned int i, j;
         FCBlock *fcb;
 
@@ -1945,7 +1945,7 @@ static int smctr_init_tx_fcbs(struct net
 
 static int smctr_internal_self_test(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int err;
 
         if((err = smctr_issue_test_internal_rom_cmd(dev)))
@@ -1998,7 +1998,7 @@ static irqreturn_t smctr_interrupt(int i
         }
 
         ioaddr = dev->base_addr;
-        tp = (struct net_local *)dev->priv;
+        tp = netdev_priv(dev);
         
 
         if(tp->status == NOT_INITIALIZED)
@@ -2471,7 +2471,7 @@ static irqreturn_t smctr_interrupt(int i
 static int smctr_issue_enable_int_cmd(struct net_device *dev,
         __u16 interrupt_enable_mask)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int err;
 
         if((err = smctr_wait_while_cbusy(dev)))
@@ -2487,7 +2487,7 @@ static int smctr_issue_enable_int_cmd(st
 
 static int smctr_issue_int_ack(struct net_device *dev, __u16 iack_code, __u16 ibits)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         if(smctr_wait_while_cbusy(dev))
                 return (-1);
@@ -2503,7 +2503,7 @@ static int smctr_issue_int_ack(struct ne
 
 static int smctr_issue_init_timers_cmd(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         unsigned int i;
         int err;
         __u16 *pTimer_Struc = (__u16 *)tp->misc_command_data;
@@ -2660,7 +2660,7 @@ static int smctr_issue_init_timers_cmd(s
 
 static int smctr_issue_init_txrx_cmd(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         unsigned int i;
         int err;
         void **txrx_ptrs = (void *)tp->misc_command_data;
@@ -2748,7 +2748,7 @@ static int smctr_issue_read_word_cmd(str
 
 static int smctr_issue_remove_cmd(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int err;
 
         if((err = smctr_wait_while_cbusy(dev)))
@@ -2764,7 +2764,7 @@ static int smctr_issue_remove_cmd(struct
 
 static int smctr_issue_resume_acb_cmd(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int err;
 
         if((err = smctr_wait_while_cbusy(dev)))
@@ -2782,7 +2782,7 @@ static int smctr_issue_resume_acb_cmd(st
 
 static int smctr_issue_resume_rx_bdb_cmd(struct net_device *dev, __u16 queue)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int err;
 
         if((err = smctr_wait_while_cbusy(dev)))
@@ -2802,7 +2802,7 @@ static int smctr_issue_resume_rx_bdb_cmd
 
 static int smctr_issue_resume_rx_fcb_cmd(struct net_device *dev, __u16 queue)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         if(smctr_debug > 10)
                 printk(KERN_DEBUG "%s: smctr_issue_resume_rx_fcb_cmd\n", dev->name);
@@ -2824,7 +2824,7 @@ static int smctr_issue_resume_rx_fcb_cmd
 
 static int smctr_issue_resume_tx_fcb_cmd(struct net_device *dev, __u16 queue)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         if(smctr_debug > 10)
                 printk(KERN_DEBUG "%s: smctr_issue_resume_tx_fcb_cmd\n", dev->name);
@@ -2893,7 +2893,7 @@ static int smctr_issue_tri_loopback_cmd(
 static int smctr_issue_write_byte_cmd(struct net_device *dev,
         short aword_cnt, void *byte)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
         unsigned int iword, ibyte;
 	int err;
 
@@ -2917,7 +2917,7 @@ static int smctr_issue_write_byte_cmd(st
 static int smctr_issue_write_word_cmd(struct net_device *dev,
         short aword_cnt, void *word)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         unsigned int i, err;
 
         if((err = smctr_wait_while_cbusy(dev)))
@@ -2947,7 +2947,7 @@ static int smctr_join_complete_state(str
 
 static int smctr_link_tx_fcbs_to_bdbs(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         unsigned int i, j;
         FCBlock *fcb;
         BDBlock *bdb;
@@ -2971,7 +2971,7 @@ static int smctr_link_tx_fcbs_to_bdbs(st
 
 static int smctr_load_firmware(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         __u16 i, checksum = 0;
         int err = 0;
 
@@ -3071,7 +3071,7 @@ static int smctr_load_node_addr(struct n
  */
 static int smctr_lobe_media_test(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         unsigned int i, perror = 0;
         unsigned short saved_rcv_mask;
 
@@ -3146,7 +3146,7 @@ static int smctr_lobe_media_test(struct 
 
 static int smctr_lobe_media_test_cmd(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int err;
 
         if(smctr_debug > 10)
@@ -3230,7 +3230,7 @@ static int smctr_make_8025_hdr(struct ne
 
 static int smctr_make_access_pri(struct net_device *dev, MAC_SUB_VECTOR *tsv)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         tsv->svi = AUTHORIZED_ACCESS_PRIORITY;
         tsv->svl = S_AUTHORIZED_ACCESS_PRIORITY;
@@ -3255,7 +3255,7 @@ static int smctr_make_addr_mod(struct ne
 static int smctr_make_auth_funct_class(struct net_device *dev,
         MAC_SUB_VECTOR *tsv)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         tsv->svi = AUTHORIZED_FUNCTION_CLASS;
         tsv->svl = S_AUTHORIZED_FUNCTION_CLASS;
@@ -3280,7 +3280,7 @@ static int smctr_make_corr(struct net_de
 
 static int smctr_make_funct_addr(struct net_device *dev, MAC_SUB_VECTOR *tsv)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         smctr_get_functional_address(dev);
 
@@ -3298,7 +3298,7 @@ static int smctr_make_funct_addr(struct 
 
 static int smctr_make_group_addr(struct net_device *dev, MAC_SUB_VECTOR *tsv)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         smctr_get_group_address(dev);
 
@@ -3324,7 +3324,7 @@ static int smctr_make_group_addr(struct 
 static int smctr_make_phy_drop_num(struct net_device *dev,
         MAC_SUB_VECTOR *tsv)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         smctr_get_physical_drop_number(dev);
 
@@ -3355,7 +3355,7 @@ static int smctr_make_product_id(struct 
 
 static int smctr_make_station_id(struct net_device *dev, MAC_SUB_VECTOR *tsv)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         smctr_get_station_id(dev);
 
@@ -3393,7 +3393,7 @@ static int smctr_make_ring_station_statu
 static int smctr_make_ring_station_version(struct net_device *dev,
         MAC_SUB_VECTOR *tsv)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         tsv->svi = RING_STATION_VERSION_NUMBER;
         tsv->svl = S_RING_STATION_VERSION_NUMBER;
@@ -3433,7 +3433,7 @@ static int smctr_make_tx_status_code(str
 static int smctr_make_upstream_neighbor_addr(struct net_device *dev,
         MAC_SUB_VECTOR *tsv)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         smctr_get_upstream_neighbor_addr(dev);
 
@@ -3485,7 +3485,7 @@ static int smctr_open(struct net_device 
 /* Interrupt driven open of Token card. */
 static int smctr_open_tr(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         unsigned long flags;
         int err;
 
@@ -3618,7 +3618,7 @@ struct net_device __init *smctr_probe(in
 	return dev;
 out1:
 #ifdef CONFIG_MCA
-	{ struct net_local *tp = (struct net_local *)dev->priv;
+	{ struct net_local *tp = netdev_priv(dev);
 	  if (tp->slot_num)
 		mca_mark_as_unused(tp->slot_num);
 	}
@@ -3634,7 +3634,7 @@ out:
 static int __init smctr_probe1(struct net_device *dev, int ioaddr)
 {
         static unsigned version_printed;
-        struct net_local *tp = dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int err;
         __u32 *ram;
 
@@ -3654,7 +3654,7 @@ static int __init smctr_probe1(struct ne
 		}
         }
 
-        tp = (struct net_local *)dev->priv;
+        tp = netdev_priv(dev);
         dev->mem_start = tp->ram_base;
         dev->mem_end = dev->mem_start + 0x10000;
         ram = (__u32 *)phys_to_virt(dev->mem_start);
@@ -3696,7 +3696,7 @@ out:
 static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size,
         struct net_device *dev, __u16 rx_status)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         struct sk_buff *skb;
         __u16 rcode, correlator;
         int err = 0;
@@ -3917,7 +3917,7 @@ static int smctr_process_rx_packet(MAC_H
 /* Adapter RAM test. Incremental word ODD boundary data test. */
 static int smctr_ram_memory_test(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         __u16 page, pages_of_ram, start_pattern = 0, word_pattern = 0,
                 word_read = 0, err_word = 0, err_pattern = 0;
         unsigned int err_offset;
@@ -4310,7 +4310,7 @@ static int smctr_rcv_unknown(struct net_
  */
 static int smctr_reset_adapter(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int ioaddr = dev->base_addr;
 
         /* Reseting the NIC will put it in a halted and un-initialized state. */        smctr_set_trc_reset(ioaddr);
@@ -4329,7 +4329,7 @@ static int smctr_reset_adapter(struct ne
 
 static int smctr_restart_tx_chain(struct net_device *dev, short queue)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int err = 0;
 
         if(smctr_debug > 10)
@@ -4347,7 +4347,7 @@ static int smctr_restart_tx_chain(struct
 
 static int smctr_ring_status_chg(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         if(smctr_debug > 10)
                 printk(KERN_DEBUG "%s: smctr_ring_status_chg\n", dev->name);
@@ -4449,7 +4449,7 @@ static int smctr_ring_status_chg(struct 
 
 static int smctr_rx_frame(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         __u16 queue, status, rx_size, err = 0;
         __u8 *pbuff;
 
@@ -4516,7 +4516,7 @@ static int smctr_rx_frame(struct net_dev
 
 static int smctr_send_dat(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         unsigned int i, err;
         MAC_HEADER *tmf;
         FCBlock *fcb;
@@ -4596,7 +4596,7 @@ static void smctr_timeout(struct net_dev
  */
 static int smctr_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         if(smctr_debug > 10)
                 printk(KERN_DEBUG "%s: smctr_send_packet\n", dev->name);
@@ -4621,7 +4621,7 @@ static int smctr_send_packet(struct sk_b
 
 static int smctr_send_lobe_media_test(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 	MAC_SUB_VECTOR *tsv;
 	MAC_HEADER *tmf;
         FCBlock *fcb;
@@ -4917,7 +4917,7 @@ static int smctr_send_rsp(struct net_dev
 
 static int smctr_send_rq_init(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         MAC_HEADER *tmf;
         MAC_SUB_VECTOR *tsv;
         FCBlock *fcb;
@@ -5001,7 +5001,7 @@ static int smctr_send_rq_init(struct net
 static int smctr_send_tx_forward(struct net_device *dev, MAC_HEADER *rmf,
         __u16 *tx_fstatus)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         FCBlock *fcb;
         unsigned int i;
 	int err;
@@ -5065,7 +5065,7 @@ static int smctr_send_tx_forward(struct 
 static int smctr_set_auth_access_pri(struct net_device *dev,
         MAC_SUB_VECTOR *rsv)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         if(rsv->svl != S_AUTHORIZED_ACCESS_PRIORITY)
                 return (E_SUB_VECTOR_LENGTH_ERROR);
@@ -5078,7 +5078,7 @@ static int smctr_set_auth_access_pri(str
 static int smctr_set_auth_funct_class(struct net_device *dev,
         MAC_SUB_VECTOR *rsv)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         if(rsv->svl != S_AUTHORIZED_FUNCTION_CLASS)
                 return (E_SUB_VECTOR_LENGTH_ERROR);
@@ -5139,7 +5139,7 @@ static int smctr_set_frame_forward(struc
 static int smctr_set_local_ring_num(struct net_device *dev,
         MAC_SUB_VECTOR *rsv)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         if(rsv->svl != S_LOCAL_RING_NUMBER)
                 return (E_SUB_VECTOR_LENGTH_ERROR);
@@ -5153,7 +5153,7 @@ static int smctr_set_local_ring_num(stru
 
 static unsigned short smctr_set_ctrl_attention(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int ioaddr = dev->base_addr;
 
         if(tp->bic_type == BIC_585_CHIP)
@@ -5177,7 +5177,7 @@ static void smctr_set_multicast_list(str
 
 static int smctr_set_page(struct net_device *dev, __u8 *buf)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         __u8 amask;
         __u32 tptr;
 
@@ -5207,7 +5207,7 @@ static int smctr_set_phy_drop(struct net
  */
 static int smctr_set_ring_speed(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 	int err;
 
         if(tp->media_type == MEDIA_UTP_16)
@@ -5235,7 +5235,7 @@ static int smctr_set_ring_speed(struct n
 
 static int smctr_set_rx_look_ahead(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         __u16 sword, rword;
 
         if(smctr_debug > 10)
@@ -5278,7 +5278,7 @@ static int smctr_set_trc_reset(int ioadd
 static int smctr_setup_single_cmd(struct net_device *dev,
         __u16 command, __u16 subcommand)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         unsigned int err;
 
         if(smctr_debug > 10)
@@ -5305,7 +5305,7 @@ static int smctr_setup_single_cmd(struct
 static int smctr_setup_single_cmd_w_data(struct net_device *dev,
         __u16 command, __u16 subcommand)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         tp->acb_head->cmd_done_status   = ACB_COMMAND_NOT_DONE;
         tp->acb_head->cmd               = command;
@@ -5318,7 +5318,7 @@ static int smctr_setup_single_cmd_w_data
 
 static char *smctr_malloc(struct net_device *dev, __u16 size)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         char *m;
 
         m = (char *)(tp->ram_access + tp->sh_mem_used);
@@ -5329,7 +5329,7 @@ static char *smctr_malloc(struct net_dev
 
 static int smctr_status_chg(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         if(smctr_debug > 10)
                 printk(KERN_DEBUG "%s: smctr_status_chg\n", dev->name);
@@ -5365,7 +5365,7 @@ static int smctr_status_chg(struct net_d
 static int smctr_trc_send_packet(struct net_device *dev, FCBlock *fcb,
         __u16 queue)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         int err = 0;
 
         if(smctr_debug > 10)
@@ -5386,7 +5386,7 @@ static int smctr_trc_send_packet(struct 
 
 static __u16 smctr_tx_complete(struct net_device *dev, __u16 queue)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         __u16 status, err = 0;
         int cstatus;
 
@@ -5441,7 +5441,7 @@ static __u16 smctr_tx_complete(struct ne
 static unsigned short smctr_tx_move_frame(struct net_device *dev,
         struct sk_buff *skb, __u8 *pbuff, unsigned int bytes)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         unsigned int ram_usable;
         __u32 flen, len, offset = 0;
         __u8 *frag, *page;
@@ -5482,7 +5482,7 @@ static unsigned short smctr_tx_move_fram
 /* Update the error statistic counters for this adapter. */
 static int smctr_update_err_stats(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         struct tr_statistics *tstat = &tp->MacStat;
 
         if(tstat->internal_errors)
@@ -5524,7 +5524,7 @@ static int smctr_update_err_stats(struct
 
 static int smctr_update_rx_chain(struct net_device *dev, __u16 queue)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         FCBlock *fcb;
         BDBlock *bdb;
         __u16 size, len;
@@ -5562,7 +5562,7 @@ static int smctr_update_rx_chain(struct 
 static int smctr_update_tx_chain(struct net_device *dev, FCBlock *fcb,
         __u16 queue)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
 
         if(smctr_debug > 20)
                 printk(KERN_DEBUG "smctr_update_tx_chain\n");
@@ -5598,7 +5598,7 @@ static int smctr_update_tx_chain(struct 
 
 static int smctr_wait_cmd(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         unsigned int loop_count = 0x20000;
 
         if(smctr_debug > 10)
@@ -5623,7 +5623,7 @@ static int smctr_wait_cmd(struct net_dev
 
 static int smctr_wait_while_cbusy(struct net_device *dev)
 {
-        struct net_local *tp = (struct net_local *)dev->priv;
+        struct net_local *tp = netdev_priv(dev);
         unsigned int timeout = 0x20000;
         int ioaddr = dev->base_addr;
         __u8 r;
@@ -5686,7 +5686,7 @@ static struct net_device *setup_card(int
 	return dev;
  out1:
 #ifdef CONFIG_MCA
-	{ struct net_local *tp = (struct net_local *)dev->priv;
+	{ struct net_local *tp = netdev_priv(dev);
 	  if (tp->slot_num)
 		mca_mark_as_unused(tp->slot_num);
 	}
@@ -5726,7 +5726,7 @@ void cleanup_module(void)
 
 			unregister_netdev(dev);
 #ifdef CONFIG_MCA
-			{ struct net_local *tp = dev->priv;
+			{ struct net_local *tp = netdev_priv(dev);
 			if (tp->slot_num)
 				mca_mark_as_unused(tp->slot_num);
 			}
--- diff/drivers/net/tokenring/tms380tr.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/tokenring/tms380tr.c	2004-03-16 09:37:56.265986440 +0000
@@ -243,7 +243,7 @@ static int madgemc_sifprobe(struct net_d
  */
 int tms380tr_open(struct net_device *dev)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	int err;
 	
 	/* init the spinlock */
@@ -313,7 +313,7 @@ int tms380tr_open(struct net_device *dev
 static void tms380tr_timer_end_wait(unsigned long data)
 {
 	struct net_device *dev = (struct net_device*)data;
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 
 	if(tp->Sleeping)
 	{
@@ -329,7 +329,7 @@ static void tms380tr_timer_end_wait(unsi
  */
 static int tms380tr_chipset_init(struct net_device *dev)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	int err;
 
 	tms380tr_init_ipb(tp);
@@ -364,7 +364,7 @@ static int tms380tr_chipset_init(struct 
  */
 static void tms380tr_init_net_local(struct net_device *dev)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	int i;
 	dma_addr_t dmabuf;
 
@@ -492,7 +492,7 @@ static void tms380tr_init_opb(struct net
 	unsigned short BufferSize = BUFFER_SIZE;
 	int i;
 
-	tp = (struct net_local *)dev->priv;
+	tp = netdev_priv(dev);
 
 	tp->ocpl.OPENOptions 	 = 0;
 	tp->ocpl.OPENOptions 	|= ENABLE_FULL_DUPLEX_SELECTION;
@@ -531,7 +531,7 @@ static void tms380tr_init_opb(struct net
  */
 static void tms380tr_open_adapter(struct net_device *dev)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 
 	if(tp->OpenCommandIssued)
 		return;
@@ -569,7 +569,7 @@ static void tms380tr_enable_interrupts(s
  */
 static void tms380tr_exec_cmd(struct net_device *dev, unsigned short Command)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 
 	tp->CMDqueue |= Command;
 	tms380tr_chk_outstanding_cmds(dev);
@@ -596,7 +596,7 @@ static void tms380tr_timeout(struct net_
  */
 static int tms380tr_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	int err;
 
 	err = tms380tr_hardware_send_packet(skb, dev);
@@ -616,7 +616,7 @@ static int tms380tr_hardware_send_packet
 	unsigned long flags;
 	int i;
 	dma_addr_t dmabuf, newbuf;
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
    
 	/* Try to get a free TPL from the chain.
 	 *
@@ -715,7 +715,7 @@ static void tms380tr_chk_src_addr(unsign
 static void tms380tr_timer_chk(unsigned long data)
 {
 	struct net_device *dev = (struct net_device*)data;
-	struct net_local *tp = (struct net_local*)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 
 	if(tp->HaltInProgress)
 		return;
@@ -755,7 +755,7 @@ irqreturn_t tms380tr_interrupt(int irq, 
 		return IRQ_NONE;
 	}
 
-	tp = (struct net_local *)dev->priv;
+	tp = netdev_priv(dev);
 
 	irq_type = SIFREADW(SIFSTS);
 
@@ -843,7 +843,7 @@ irqreturn_t tms380tr_interrupt(int irq, 
  */
 static void tms380tr_reset_interrupt(struct net_device *dev)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	SSB *ssb = &tp->ssb;
 
 	/*
@@ -929,7 +929,7 @@ static unsigned char tms380tr_chk_ssb(st
  */
 static void tms380tr_cmd_status_irq(struct net_device *dev)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	unsigned short ssb_cmd, ssb_parm_0;
 	unsigned short ssb_parm_1;
 	char *open_err = "Open error -";
@@ -1126,7 +1126,7 @@ static void tms380tr_cmd_status_irq(stru
  */
 int tms380tr_close(struct net_device *dev)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	netif_stop_queue(dev);
 	
 	del_timer(&tp->timer);
@@ -1172,7 +1172,7 @@ int tms380tr_close(struct net_device *de
  */
 static struct net_device_stats *tms380tr_get_stats(struct net_device *dev)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 
 	return ((struct net_device_stats *)&tp->MacStat);
 }
@@ -1182,7 +1182,7 @@ static struct net_device_stats *tms380tr
  */
 static void tms380tr_set_multicast_list(struct net_device *dev)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	unsigned int OpenOptions;
 	
 	OpenOptions = tp->ocpl.OPENOptions &
@@ -1275,7 +1275,7 @@ static void tms380tr_exec_sifcmd(struct 
  */
 static int tms380tr_reset_adapter(struct net_device *dev)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	unsigned short *fw_ptr;
 	unsigned short count, c, count2;
 	const struct firmware *fw_entry = NULL;
@@ -1428,7 +1428,7 @@ static int tms380tr_bringup_diags(struct
  */
 static int tms380tr_init_adapter(struct net_device *dev)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 
 	const unsigned char SCB_Test[6] = {0x00, 0x00, 0xC1, 0xE2, 0xD4, 0x8B};
 	const unsigned char SSB_Test[8] = {0xFF, 0xFF, 0xD1, 0xD7,
@@ -1541,7 +1541,7 @@ static int tms380tr_init_adapter(struct 
  */
 static void tms380tr_chk_outstanding_cmds(struct net_device *dev)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	unsigned long Addr = 0;
 
 	if(tp->CMDqueue == 0)
@@ -1713,7 +1713,7 @@ static void tms380tr_chk_outstanding_cmd
  */
 static void tms380tr_ring_status_irq(struct net_device *dev)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 
 	tp->CurrentRingStatus = be16_to_cpu((unsigned short)tp->ssb.Parm[0]);
 
@@ -1785,7 +1785,7 @@ static void tms380tr_chk_irq(struct net_
 {
 	int i;
 	unsigned short AdapterCheckBlock[4];
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 
 	tp->AdapterOpenFlag = 0;	/* Adapter closed now */
 
@@ -1941,7 +1941,7 @@ static void tms380tr_chk_irq(struct net_
  */
 static int tms380tr_read_ptr(struct net_device *dev)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	unsigned short adapterram;
 
 	tms380tr_read_ram(dev, (unsigned char *)&tp->intptrs.BurnedInAddrPtr,
@@ -2031,7 +2031,7 @@ static void tms380tr_cancel_tx_queue(str
  */
 static void tms380tr_tx_status_irq(struct net_device *dev)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	unsigned char HighByte, HighAc, LowAc;
 	TPL *tpl;
 
@@ -2102,7 +2102,7 @@ static void tms380tr_tx_status_irq(struc
  */
 static void tms380tr_rcv_status_irq(struct net_device *dev)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	unsigned char *ReceiveDataPtr;
 	struct sk_buff *skb;
 	unsigned int Length, Length2;
@@ -2293,7 +2293,7 @@ static void tms380tr_update_rcv_stats(st
 
 static int tms380tr_set_mac_address(struct net_device *dev, void *addr)
 {
-	struct net_local *tp = (struct net_local *)dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	struct sockaddr *saddr = addr;
 	
 	if (tp->AdapterOpenFlag || tp->AdapterVirtOpenFlag) {
@@ -2327,7 +2327,7 @@ void tmsdev_term(struct net_device *dev)
 {
 	struct net_local *tp;
 
-	tp = (struct net_local *) dev->priv;
+	tp = netdev_priv(dev);
 	pci_unmap_single(tp->pdev, tp->dmabuffer, sizeof(struct net_local),
 		PCI_DMA_BIDIRECTIONAL);
 }
@@ -2338,7 +2338,7 @@ int tmsdev_init(struct net_device *dev, 
 	struct net_local *tms_local;
 
 	memset(dev->priv, 0, sizeof(struct net_local));
-	tms_local = (struct net_local *)dev->priv;
+	tms_local = netdev_priv(dev);
 	init_waitqueue_head(&tms_local->wait_for_tok_int);
 	tms_local->dmalimit = dmalimit;
 	tms_local->pdev = pdev;
--- diff/drivers/net/tulip/21142.c	2002-11-11 11:09:37.000000000 +0000
+++ source/drivers/net/tulip/21142.c	2004-03-16 09:37:56.265986440 +0000
@@ -29,7 +29,7 @@ static u16 t21142_csr15[] = { 0x0008, 0x
 void t21142_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int csr12 = inl(ioaddr + CSR12);
 	int next_tick = 60*HZ;
@@ -103,7 +103,7 @@ void t21142_timer(unsigned long data)
 
 void t21142_start_nway(struct net_device *dev)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int csr14 = ((tp->sym_advertise & 0x0780) << 9)  |
 		((tp->sym_advertise & 0x0020) << 1) | 0xffbf;
@@ -131,7 +131,7 @@ void t21142_start_nway(struct net_device
 
 void t21142_lnk_change(struct net_device *dev, int csr5)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int csr12 = inl(ioaddr + CSR12);
 
--- diff/drivers/net/tulip/de2104x.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/tulip/de2104x.c	2004-03-16 09:37:56.267986136 +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/de4x5.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/tulip/de4x5.c	2004-03-16 09:37:56.273985224 +0000
@@ -1086,7 +1086,7 @@ static int __devinit 
 de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
 {
     char name[DE4X5_NAME_LENGTH + 1];
-    struct de4x5_private *lp = dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     struct pci_dev *pdev = NULL;
     int i, status=0;
 
@@ -1294,7 +1294,7 @@ de4x5_hw_init(struct net_device *dev, u_
 static int
 de4x5_open(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     int i, status = 0;
     s32 omr;
@@ -1384,7 +1384,7 @@ de4x5_init(struct net_device *dev)
 static int
 de4x5_sw_reset(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     int i, j, status = 0;
     s32 bmr, omr;
@@ -1462,7 +1462,7 @@ de4x5_sw_reset(struct net_device *dev)
 static int
 de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     int status = 0;
     u_long flags = 0;
@@ -1551,7 +1551,7 @@ de4x5_interrupt(int irq, void *dev_id, s
 	printk ("de4x5_interrupt(): irq %d for unknown device.\n", irq);
 	return IRQ_NONE;
     }
-    lp = (struct de4x5_private *)dev->priv;
+    lp = netdev_priv(dev);
     spin_lock(&lp->lock);
     iobase = dev->base_addr;
 	
@@ -1610,7 +1610,7 @@ de4x5_interrupt(int irq, void *dev_id, s
 static int
 de4x5_rx(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     int entry;
     s32 status;
@@ -1701,7 +1701,7 @@ de4x5_free_tx_buff(struct de4x5_private 
 static int
 de4x5_tx(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     int entry;
     s32 status;
@@ -1753,7 +1753,7 @@ de4x5_tx(struct net_device *dev)
 static int
 de4x5_ast(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     int next_tick = DE4X5_AUTOSENSE_MS;
     
     disable_ast(dev);
@@ -1776,7 +1776,7 @@ de4x5_ast(struct net_device *dev)
 static int
 de4x5_txur(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     int omr;
 
@@ -1799,7 +1799,7 @@ de4x5_txur(struct net_device *dev)
 static int 
 de4x5_rx_ovfc(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     int omr;
 
@@ -1820,7 +1820,7 @@ de4x5_rx_ovfc(struct net_device *dev)
 static int
 de4x5_close(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     s32 imr, omr;
     
@@ -1856,7 +1856,7 @@ de4x5_close(struct net_device *dev)
 static struct net_device_stats *
 de4x5_get_stats(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     
     lp->stats.rx_missed_errors = (int)(inl(DE4X5_MFC) & (MFC_OVFL | MFC_CNTR));
@@ -1867,7 +1867,7 @@ de4x5_get_stats(struct net_device *dev)
 static void
 de4x5_local_stats(struct net_device *dev, char *buf, int pkt_len)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     int i;
 
     for (i=1; i<DE4X5_PKT_STAT_SZ-1; i++) {
@@ -1906,7 +1906,7 @@ de4x5_local_stats(struct net_device *dev
 static void
 load_packet(struct net_device *dev, char *buf, u32 flags, struct sk_buff *skb)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     int entry = (lp->tx_new ? lp->tx_new-1 : lp->txRingSize-1);
     dma_addr_t buf_dma = dma_map_single(lp->gendev, buf, flags & TD_TBS1, DMA_TO_DEVICE);
 
@@ -1927,7 +1927,7 @@ load_packet(struct net_device *dev, char
 static void
 set_multicast_list(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
 
     /* First, double check that the adapter is open */
@@ -1957,7 +1957,7 @@ set_multicast_list(struct net_device *de
 static void
 SetMulticastFilter(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     struct dev_mc_list *dmi=dev->mc_list;
     u_long iobase = dev->base_addr;
     int i, j, bit, byte;
@@ -2036,7 +2036,7 @@ static int __init de4x5_eisa_probe (stru
 		status = -ENOMEM;
 		goto release_reg_2;
 	}
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 	
 	cfid = (u32) inl(PCI_CFID);
 	lp->cfrv = (u_short) inl(PCI_CFRV);
@@ -2142,7 +2142,7 @@ srom_search(struct net_device *dev, stru
     u_int irq = 0, device;
     u_long iobase = 0;                     /* Clear upper 32 bits in Alphas */
     int i, j, cfrv;
-    struct de4x5_private *lp = dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     struct list_head *walk = &pdev->bus_list;
 
     for (walk = walk->next; walk != &pdev->bus_list; walk = walk->next) {
@@ -2245,7 +2245,7 @@ static int __devinit de4x5_pci_probe (st
 	if (!(dev = alloc_etherdev (sizeof (struct de4x5_private))))
 		return -ENOMEM;
 
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 	lp->bus = PCI;
 	lp->bus_num = 0;
 	
@@ -2374,7 +2374,7 @@ static struct pci_driver de4x5_pci_drive
 static int
 autoconf_media(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     int next_tick = DE4X5_AUTOSENSE_MS;
 
@@ -2415,7 +2415,7 @@ autoconf_media(struct net_device *dev)
 static int
 dc21040_autoconf(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     int next_tick = DE4X5_AUTOSENSE_MS;
     s32 imr;
@@ -2488,7 +2488,7 @@ dc21040_state(struct net_device *dev, in
 	      int next_state, int suspect_state, 
 	      int (*fn)(struct net_device *, int))
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     int next_tick = DE4X5_AUTOSENSE_MS;
     int linkBad;
 
@@ -2527,7 +2527,7 @@ de4x5_suspect_state(struct net_device *d
 		      int (*fn)(struct net_device *, int),
 		      int (*asfn)(struct net_device *))
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     int next_tick = DE4X5_AUTOSENSE_MS;
     int linkBad;
 
@@ -2569,7 +2569,7 @@ de4x5_suspect_state(struct net_device *d
 static int
 dc21041_autoconf(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     s32 sts, irqs, irq_mask, imr, omr;
     int next_tick = DE4X5_AUTOSENSE_MS;
@@ -2771,7 +2771,7 @@ dc21041_autoconf(struct net_device *dev)
 static int
 dc21140m_autoconf(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     int ana, anlpa, cap, cr, slnk, sr;
     int next_tick = DE4X5_AUTOSENSE_MS;
     u_long imr, omr, iobase = dev->base_addr;
@@ -2955,7 +2955,7 @@ dc21140m_autoconf(struct net_device *dev
 static int
 dc2114x_autoconf(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     s32 cr, anlpa, ana, cap, irqs, irq_mask, imr, omr, slnk, sr, sts;
     int next_tick = DE4X5_AUTOSENSE_MS;
@@ -3206,7 +3206,7 @@ printk("Huh?: media:%02x\n", lp->media);
 static int
 srom_autoconf(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
 
     return lp->infoleaf_fn(dev);
 }
@@ -3219,7 +3219,7 @@ srom_autoconf(struct net_device *dev)
 static int
 srom_map_media(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
 
     lp->fdx = 0;
     if (lp->infoblock_media == lp->media) 
@@ -3284,7 +3284,7 @@ srom_map_media(struct net_device *dev)
 static void
 de4x5_init_connection(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     u_long flags = 0;
 
@@ -3313,7 +3313,7 @@ de4x5_init_connection(struct net_device 
 static int
 de4x5_reset_phy(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     int next_tick = 0;
 
@@ -3347,7 +3347,7 @@ de4x5_reset_phy(struct net_device *dev)
 static int
 test_media(struct net_device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     s32 sts, csr12;
     
@@ -3385,7 +3385,7 @@ test_media(struct net_device *dev, s32 i
 static int
 test_tp(struct net_device *dev, s32 msec)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     int sisr;
     
@@ -3414,7 +3414,7 @@ test_tp(struct net_device *dev, s32 msec
 static int
 test_for_100Mb(struct net_device *dev, int msec)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     int gep = 0, ret = ((lp->chipset & ~0x00ff)==DC2114x? -1 :GEP_SLNK);
 
     if (lp->timeout < 0) {
@@ -3445,7 +3445,7 @@ test_for_100Mb(struct net_device *dev, i
 static int
 wait_for_link(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
 
     if (lp->timeout < 0) {
 	lp->timeout = 1;
@@ -3467,7 +3467,7 @@ wait_for_link(struct net_device *dev)
 static int
 test_mii_reg(struct net_device *dev, int reg, int mask, int pol, long msec)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     int test;
     u_long iobase = dev->base_addr;
     
@@ -3491,7 +3491,7 @@ test_mii_reg(struct net_device *dev, int
 static int
 is_spd_100(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     int spd;
     
@@ -3515,7 +3515,7 @@ is_spd_100(struct net_device *dev)
 static int
 is_100_up(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     
     if (lp->useMII) {
@@ -3536,7 +3536,7 @@ is_100_up(struct net_device *dev)
 static int
 is_10_up(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     
     if (lp->useMII) {
@@ -3559,7 +3559,7 @@ is_10_up(struct net_device *dev)
 static int
 is_anc_capable(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     
     if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
@@ -3578,7 +3578,7 @@ is_anc_capable(struct net_device *dev)
 static int
 ping_media(struct net_device *dev, int msec)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     int sisr;
     
@@ -3619,7 +3619,7 @@ ping_media(struct net_device *dev, int m
 static struct sk_buff *
 de4x5_alloc_rx_buff(struct net_device *dev, int index, int len)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     struct sk_buff *p;
 
 #if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY)
@@ -3667,7 +3667,7 @@ de4x5_alloc_rx_buff(struct net_device *d
 static void
 de4x5_free_rx_buffs(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     int i;
 
     for (i=0; i<lp->rxRingSize; i++) {
@@ -3684,7 +3684,7 @@ de4x5_free_rx_buffs(struct net_device *d
 static void
 de4x5_free_tx_buffs(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     int i;
 
     for (i=0; i<lp->txRingSize; i++) {
@@ -3711,7 +3711,7 @@ de4x5_free_tx_buffs(struct net_device *d
 static void
 de4x5_save_skbs(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     s32 omr;
 
@@ -3732,7 +3732,7 @@ de4x5_save_skbs(struct net_device *dev)
 static void
 de4x5_rst_desc_ring(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     int i;
     s32 omr;
@@ -3765,7 +3765,7 @@ de4x5_rst_desc_ring(struct net_device *d
 static void
 de4x5_cache_state(struct net_device *dev, int flag)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
 
     switch(flag) {
@@ -3795,7 +3795,7 @@ de4x5_cache_state(struct net_device *dev
 static void
 de4x5_put_cache(struct net_device *dev, struct sk_buff *skb)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     struct sk_buff *p;
 
     if (lp->cache.skb) {
@@ -3812,7 +3812,7 @@ de4x5_put_cache(struct net_device *dev, 
 static void
 de4x5_putb_cache(struct net_device *dev, struct sk_buff *skb)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     struct sk_buff *p = lp->cache.skb;
 
     lp->cache.skb = skb;
@@ -3824,7 +3824,7 @@ de4x5_putb_cache(struct net_device *dev,
 static struct sk_buff *
 de4x5_get_cache(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     struct sk_buff *p = lp->cache.skb;
 
     if (p) {
@@ -3842,7 +3842,7 @@ de4x5_get_cache(struct net_device *dev)
 static int
 test_ans(struct net_device *dev, s32 irqs, s32 irq_mask, s32 msec)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     s32 sts, ans;
     
@@ -3870,7 +3870,7 @@ test_ans(struct net_device *dev, s32 irq
 static void
 de4x5_setup_intr(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     s32 imr, sts;
     
@@ -3891,7 +3891,7 @@ de4x5_setup_intr(struct net_device *dev)
 static void
 reset_init_sia(struct net_device *dev, s32 csr13, s32 csr14, s32 csr15)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
 
     RESET_SIA;
@@ -4014,7 +4014,7 @@ static void
 DevicePresent(struct net_device *dev, u_long aprom_addr)
 {
     int i, j=0;
-    struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     
     if (lp->chipset == DC21040) {
 	if (lp->bus == EISA) {
@@ -4095,7 +4095,7 @@ get_hw_addr(struct net_device *dev)
     u_long iobase = dev->base_addr;
     int broken, i, k, tmp, status = 0;
     u_short j,chksum;
-    struct de4x5_private *lp = dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
 
     broken = de4x5_bad_srom(lp);
 
@@ -4210,7 +4210,7 @@ de4x5_strncmp(char *a, char *b, int n)
 static void
 srom_repair(struct net_device *dev, int card)
 {
-    struct de4x5_private *lp = dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
 
     switch(card) {
       case SMC:
@@ -4231,7 +4231,7 @@ srom_repair(struct net_device *dev, int 
 static int
 test_bad_enet(struct net_device *dev, int status)
 {
-    struct de4x5_private *lp = dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     int i, tmp;
 
     for (tmp=0,i=0; i<ETH_ALEN; i++) tmp += (u_char)dev->dev_addr[i];
@@ -4384,7 +4384,7 @@ getfrom_srom(u_long addr)
 static int
 srom_infoleaf_info(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     int i, count;
     u_char *p;
 
@@ -4432,7 +4432,7 @@ srom_infoleaf_info(struct net_device *de
 static void
 srom_init(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
     u_char count;
 
@@ -4477,7 +4477,7 @@ srom_init(struct net_device *dev)
 static void
 srom_exec(struct net_device *dev, u_char *p)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     u_char count = (p ? *p++ : 0);
     u_short *w = (u_short *)p;
@@ -4514,7 +4514,7 @@ dc21041_infoleaf(struct net_device *dev)
 static int 
 dc21140_infoleaf(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_char count = 0;
     u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
     int next_tick = DE4X5_AUTOSENSE_MS;
@@ -4552,7 +4552,7 @@ dc21140_infoleaf(struct net_device *dev)
 static int 
 dc21142_infoleaf(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_char count = 0;
     u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
     int next_tick = DE4X5_AUTOSENSE_MS;
@@ -4587,7 +4587,7 @@ dc21142_infoleaf(struct net_device *dev)
 static int 
 dc21143_infoleaf(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_char count = 0;
     u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
     int next_tick = DE4X5_AUTOSENSE_MS;
@@ -4625,7 +4625,7 @@ dc21143_infoleaf(struct net_device *dev)
 static int 
 compact_infoblock(struct net_device *dev, u_char count, u_char *p)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_char flags, csr6;
 
     /* Recursively figure out the info blocks */
@@ -4665,7 +4665,7 @@ compact_infoblock(struct net_device *dev
 static int 
 type0_infoblock(struct net_device *dev, u_char count, u_char *p)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_char flags, csr6, len = (*p & BLOCK_LEN)+1;
 
     /* Recursively figure out the info blocks */
@@ -4705,7 +4705,7 @@ type0_infoblock(struct net_device *dev, 
 static int 
 type1_infoblock(struct net_device *dev, u_char count, u_char *p)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_char len = (*p & BLOCK_LEN)+1;
 
     /* Recursively figure out the info blocks */
@@ -4744,7 +4744,7 @@ type1_infoblock(struct net_device *dev, 
 static int 
 type2_infoblock(struct net_device *dev, u_char count, u_char *p)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_char len = (*p & BLOCK_LEN)+1;
 
     /* Recursively figure out the info blocks */
@@ -4785,7 +4785,7 @@ type2_infoblock(struct net_device *dev, 
 static int 
 type3_infoblock(struct net_device *dev, u_char count, u_char *p)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_char len = (*p & BLOCK_LEN)+1;
 
     /* Recursively figure out the info blocks */
@@ -4827,7 +4827,7 @@ type3_infoblock(struct net_device *dev, 
 static int 
 type4_infoblock(struct net_device *dev, u_char count, u_char *p)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_char flags, csr6, len = (*p & BLOCK_LEN)+1;
 
     /* Recursively figure out the info blocks */
@@ -4872,7 +4872,7 @@ type4_infoblock(struct net_device *dev, 
 static int 
 type5_infoblock(struct net_device *dev, u_char count, u_char *p)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_char len = (*p & BLOCK_LEN)+1;
 
     /* Recursively figure out the info blocks */
@@ -5072,7 +5072,7 @@ mii_get_oui(u_char phyaddr, u_long ioadd
 static int
 mii_get_phy(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     int i, j, k, n, limit=sizeof(phy_info)/sizeof(struct phy_table);
     int id;
@@ -5136,7 +5136,7 @@ mii_get_phy(struct net_device *dev)
 static char *
 build_setup_frame(struct net_device *dev, int mode)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     int i;
     char *pa = lp->setup_frame;
     
@@ -5176,7 +5176,7 @@ enable_ast(struct net_device *dev, u32 t
 static void
 disable_ast(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     
     del_timer(&lp->timer);
     
@@ -5186,7 +5186,7 @@ disable_ast(struct net_device *dev)
 static long
 de4x5_switch_mac_port(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     s32 omr;
 
@@ -5222,7 +5222,7 @@ de4x5_switch_mac_port(struct net_device 
 static void
 gep_wr(s32 data, struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
 
     if (lp->chipset == DC21140) {
@@ -5237,7 +5237,7 @@ gep_wr(s32 data, struct net_device *dev)
 static int
 gep_rd(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
 
     if (lp->chipset == DC21140) {
@@ -5252,7 +5252,7 @@ gep_rd(struct net_device *dev)
 static void
 timeout(struct net_device *dev, void (*fn)(u_long data), u_long data, u_long msec)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     int dt;
     
     /* First, cancel any pending timer events */
@@ -5275,7 +5275,7 @@ timeout(struct net_device *dev, void (*f
 static void
 yawn(struct net_device *dev, int state)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
 
     if ((lp->chipset == DC21040) || (lp->chipset == DC21140)) return;
@@ -5321,7 +5321,7 @@ yawn(struct net_device *dev, int state)
 static void
 de4x5_parse_params(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     char *p, *q, t;
 
     lp->params.fdx = 0;
@@ -5364,7 +5364,7 @@ de4x5_parse_params(struct net_device *de
 static void
 de4x5_dbg_open(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     int i;
     
     if (de4x5_debug & DEBUG_OPEN) {
@@ -5415,7 +5415,7 @@ de4x5_dbg_open(struct net_device *dev)
 static void
 de4x5_dbg_mii(struct net_device *dev, int k)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
     
     if (de4x5_debug & DEBUG_MII) {
@@ -5443,7 +5443,7 @@ de4x5_dbg_mii(struct net_device *dev, in
 static void
 de4x5_dbg_media(struct net_device *dev)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     
     if (lp->media != lp->c_media) {
 	if (de4x5_debug & DEBUG_MEDIA) {
@@ -5534,7 +5534,7 @@ de4x5_dbg_rx(struct sk_buff *skb, int le
 static int
 de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_private *lp = netdev_priv(dev);
     struct de4x5_ioctl *ioc = (struct de4x5_ioctl *) &rq->ifr_data;
     u_long iobase = dev->base_addr;
     int i, j, status = 0;
--- diff/drivers/net/tulip/dmfe.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/tulip/dmfe.c	2004-03-16 09:37:56.275984920 +0000
@@ -392,7 +392,7 @@ static int __devinit dmfe_init_one (stru
 	}
 
 	/* Init system & device */
-	db = dev->priv;
+	db = netdev_priv(dev);
 
 	/* Allocate Tx/Rx descriptor memory */
 	db->desc_pool_ptr = pci_alloc_consistent(pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, &db->desc_pool_dma_ptr);
@@ -466,7 +466,7 @@ err_out_free:
 static void __devexit dmfe_remove_one (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct dmfe_board_info *db = dev->priv;
+	struct dmfe_board_info *db = netdev_priv(dev);
 
 	DMFE_DBUG(0, "dmfe_remove_one()", 0);
 
@@ -494,7 +494,7 @@ static void __devexit dmfe_remove_one (s
 static int dmfe_open(struct DEVICE *dev)
 {
 	int ret;
-	struct dmfe_board_info *db = dev->priv;
+	struct dmfe_board_info *db = netdev_priv(dev);
 
 	DMFE_DBUG(0, "dmfe_open", 0);
 
@@ -552,7 +552,7 @@ static int dmfe_open(struct DEVICE *dev)
 
 static void dmfe_init_dm910x(struct DEVICE *dev)
 {
-	struct dmfe_board_info *db = dev->priv;
+	struct dmfe_board_info *db = netdev_priv(dev);
 	unsigned long ioaddr = db->ioaddr;
 
 	DMFE_DBUG(0, "dmfe_init_dm910x()", 0);
@@ -618,7 +618,7 @@ static void dmfe_init_dm910x(struct DEVI
 
 static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev)
 {
-	struct dmfe_board_info *db = dev->priv;
+	struct dmfe_board_info *db = netdev_priv(dev);
 	struct tx_desc *txptr;
 	unsigned long flags;
 
@@ -687,7 +687,7 @@ static int dmfe_start_xmit(struct sk_buf
 
 static int dmfe_stop(struct DEVICE *dev)
 {
-	struct dmfe_board_info *db = dev->priv;
+	struct dmfe_board_info *db = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 
 	DMFE_DBUG(0, "dmfe_stop", 0);
@@ -730,7 +730,7 @@ static int dmfe_stop(struct DEVICE *dev)
 static irqreturn_t dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct DEVICE *dev = dev_id;
-	struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv;
+	struct dmfe_board_info *db = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 	unsigned long flags;
 
@@ -957,7 +957,7 @@ static void dmfe_rx_packet(struct DEVICE
 
 static struct net_device_stats * dmfe_get_stats(struct DEVICE *dev)
 {
-	struct dmfe_board_info *db = (struct dmfe_board_info *)dev->priv;
+	struct dmfe_board_info *db = netdev_priv(dev);
 
 	DMFE_DBUG(0, "dmfe_get_stats", 0);
 	return &db->stats;
@@ -970,7 +970,7 @@ static struct net_device_stats * dmfe_ge
 
 static void dmfe_set_filter_mode(struct DEVICE * dev)
 {
-	struct dmfe_board_info *db = dev->priv;
+	struct dmfe_board_info *db = netdev_priv(dev);
 	unsigned long flags;
 
 	DMFE_DBUG(0, "dmfe_set_filter_mode()", 0);
@@ -1003,7 +1003,7 @@ static void dmfe_set_filter_mode(struct 
 static void netdev_get_drvinfo(struct net_device *dev,
 			       struct ethtool_drvinfo *info)
 {
-	struct dmfe_board_info *np = dev->priv;
+	struct dmfe_board_info *np = netdev_priv(dev);
 
 	strcpy(info->driver, DRV_NAME);
 	strcpy(info->version, DRV_VERSION);
@@ -1028,7 +1028,7 @@ static void dmfe_timer(unsigned long dat
 	u32 tmp_cr8;
 	unsigned char tmp_cr12;
 	struct DEVICE *dev = (struct DEVICE *) data;
-	struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv;
+	struct dmfe_board_info *db = netdev_priv(dev);
  	unsigned long flags;
 
 	DMFE_DBUG(0, "dmfe_timer()", 0);
@@ -1160,7 +1160,7 @@ static void dmfe_timer(unsigned long dat
 
 static void dmfe_dynamic_reset(struct DEVICE *dev)
 {
-	struct dmfe_board_info *db = dev->priv;
+	struct dmfe_board_info *db = netdev_priv(dev);
 
 	DMFE_DBUG(0, "dmfe_dynamic_reset()", 0);
 
@@ -1358,7 +1358,7 @@ static void dm9132_id_table(struct DEVIC
 
 static void send_filter_frame(struct DEVICE *dev, int mc_cnt)
 {
-	struct dmfe_board_info *db = dev->priv;
+	struct dmfe_board_info *db = netdev_priv(dev);
 	struct dev_mc_list *mcptr;
 	struct tx_desc *txptr;
 	u16 * addrptr;
--- diff/drivers/net/tulip/eeprom.c	2002-11-11 11:09:37.000000000 +0000
+++ source/drivers/net/tulip/eeprom.c	2004-03-16 09:37:56.276984768 +0000
@@ -136,7 +136,7 @@ void __devinit tulip_parse_eeprom(struct
 	static struct mediatable *last_mediatable;
 	static unsigned char *last_ee_data;
 	static int controller_index;
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	unsigned char *ee_data = tp->eeprom;
 	int i;
 
--- diff/drivers/net/tulip/interrupt.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/tulip/interrupt.c	2004-03-16 09:37:56.277984616 +0000
@@ -63,7 +63,7 @@ unsigned int mit_table[MIT_SIZE+1] =
 
 int tulip_refill_rx(struct net_device *dev)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	int entry;
 	int refilled = 0;
 
@@ -109,7 +109,7 @@ void oom_timer(unsigned long data)
 
 int tulip_poll(struct net_device *dev, int *budget)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	int entry = tp->cur_rx % RX_RING_SIZE;
 	int rx_work_limit = *budget;
 	int received = 0;
@@ -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);
@@ -354,7 +357,7 @@ done:
 
 static int tulip_rx(struct net_device *dev)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	int entry = tp->cur_rx % RX_RING_SIZE;
 	int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
 	int received = 0;
@@ -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);
@@ -465,7 +471,7 @@ static inline unsigned int phy_interrupt
 {
 #ifdef __hppa__
 	int csr12 = inl(dev->base_addr + CSR12) & 0xff;
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 
 	if (csr12 != tp->csr12_shadow) {
 		/* ack interrupt */
@@ -490,7 +496,7 @@ static inline unsigned int phy_interrupt
 irqreturn_t tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *)dev_instance;
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int csr5;
 	int missed;
--- diff/drivers/net/tulip/media.c	2002-12-11 11:50:25.000000000 +0000
+++ source/drivers/net/tulip/media.c	2004-03-16 09:37:56.277984616 +0000
@@ -48,7 +48,7 @@ static const unsigned char comet_miireg2
 
 int tulip_mdio_read(struct net_device *dev, int phy_id, int location)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	int i;
 	int read_cmd = (0xf6 << 10) | ((phy_id & 0x1f) << 5) | location;
 	int retval = 0;
@@ -111,7 +111,7 @@ int tulip_mdio_read(struct net_device *d
 
 void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int val)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	int i;
 	int cmd = (0x5002 << 16) | ((phy_id & 0x1f) << 23) | (location<<18) | (val & 0xffff);
 	long ioaddr = dev->base_addr;
@@ -171,7 +171,7 @@ void tulip_mdio_write(struct net_device 
 void tulip_select_media(struct net_device *dev, int startup)
 {
 	long ioaddr = dev->base_addr;
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	struct mediatable *mtable = tp->mtable;
 	u32 new_csr6;
 	int i;
@@ -374,7 +374,7 @@ void tulip_select_media(struct net_devic
   */
 int tulip_check_duplex(struct net_device *dev)
 {
-	struct tulip_private *tp = dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	unsigned int bmsr, lpa, negotiated, new_csr6;
 
 	bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR);
@@ -420,7 +420,7 @@ int tulip_check_duplex(struct net_device
 
 void __devinit tulip_find_mii (struct net_device *dev, int board_idx)
 {
-	struct tulip_private *tp = dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	int phyn, phy_idx = 0;
 	int mii_reg0;
 	int mii_advert;
--- diff/drivers/net/tulip/pnic.c	2002-11-11 11:09:37.000000000 +0000
+++ source/drivers/net/tulip/pnic.c	2004-03-16 09:37:56.278984464 +0000
@@ -20,7 +20,7 @@
 
 void pnic_do_nway(struct net_device *dev)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	u32 phy_reg = inl(ioaddr + 0xB8);
 	u32 new_csr6 = tp->csr6 & ~0x40C40200;
@@ -53,7 +53,7 @@ void pnic_do_nway(struct net_device *dev
 
 void pnic_lnk_change(struct net_device *dev, int csr5)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int phy_reg = inl(ioaddr + 0xB8);
 
@@ -89,7 +89,7 @@ void pnic_lnk_change(struct net_device *
 void pnic_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int next_tick = 60*HZ;
 
--- diff/drivers/net/tulip/pnic2.c	2002-11-11 11:09:37.000000000 +0000
+++ source/drivers/net/tulip/pnic2.c	2004-03-16 09:37:56.278984464 +0000
@@ -84,7 +84,7 @@
 void pnic2_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int next_tick = 60*HZ;
 
@@ -100,7 +100,7 @@ void pnic2_timer(unsigned long data)
 
 void pnic2_start_nway(struct net_device *dev)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
         int csr14;
         int csr12;
@@ -175,7 +175,7 @@ void pnic2_start_nway(struct net_device 
 
 void pnic2_lnk_change(struct net_device *dev, int csr5)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
         int csr14;
 
--- diff/drivers/net/tulip/timer.c	2002-11-11 11:09:37.000000000 +0000
+++ source/drivers/net/tulip/timer.c	2004-03-16 09:37:56.279984312 +0000
@@ -20,7 +20,7 @@
 void tulip_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	u32 csr12 = inl(ioaddr + CSR12);
 	int next_tick = 2*HZ;
@@ -135,7 +135,7 @@ void tulip_timer(unsigned long data)
 void mxic_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int next_tick = 60*HZ;
 
@@ -152,7 +152,7 @@ void mxic_timer(unsigned long data)
 void comet_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int next_tick = 60*HZ;
 
--- diff/drivers/net/tulip/tulip_core.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/tulip/tulip_core.c	2004-03-16 09:37:56.281984008 +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,
@@ -276,7 +276,7 @@ static void tulip_set_power_state (struc
 
 static void tulip_up(struct net_device *dev)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int next_tick = 3*HZ;
 	int i;
@@ -499,7 +499,7 @@ tulip_open(struct net_device *dev)
 
 static void tulip_tx_timeout(struct net_device *dev)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	unsigned long flags;
 
@@ -587,7 +587,7 @@ static void tulip_tx_timeout(struct net_
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
 static void tulip_init_ring(struct net_device *dev)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	int i;
 
 	tp->susp_rx = 0;
@@ -638,7 +638,7 @@ static void tulip_init_ring(struct net_d
 static int
 tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	int entry;
 	u32 flag;
 	dma_addr_t mapping;
@@ -724,7 +724,7 @@ static void tulip_clean_tx_ring(struct t
 static void tulip_down (struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct tulip_private *tp = (struct tulip_private *) dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	unsigned long flags;
 
 	del_timer_sync (&tp->timer);
@@ -764,7 +764,7 @@ static void tulip_down (struct net_devic
 static int tulip_close (struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct tulip_private *tp = (struct tulip_private *) dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	int i;
 
 	netif_stop_queue (dev);
@@ -811,7 +811,7 @@ static int tulip_close (struct net_devic
 
 static struct net_device_stats *tulip_get_stats(struct net_device *dev)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	if (netif_running(dev)) {
@@ -830,7 +830,7 @@ static struct net_device_stats *tulip_ge
 
 static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
 {
-	struct tulip_private *np = dev->priv;
+	struct tulip_private *np = netdev_priv(dev);
 	u32 ethcmd;
 
 	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
@@ -855,7 +855,7 @@ static int netdev_ethtool_ioctl(struct n
 /* Provide ioctl() calls to examine the MII xcvr state. */
 static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct tulip_private *tp = dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
 	const unsigned int phy_idx = 0;
@@ -964,7 +964,7 @@ static int private_ioctl (struct net_dev
 
 static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	u16 hash_table[32];
 	struct dev_mc_list *mclist;
 	int i;
@@ -995,7 +995,7 @@ static void build_setup_frame_hash(u16 *
 
 static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	struct dev_mc_list *mclist;
 	int i;
 	u16 *eaddrs;
@@ -1023,7 +1023,7 @@ static void build_setup_frame_perfect(u1
 
 static void set_rx_mode(struct net_device *dev)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int csr6;
 
@@ -1150,7 +1150,7 @@ static void set_rx_mode(struct net_devic
 static void __devinit tulip_mwi_config (struct pci_dev *pdev,
 					struct net_device *dev)
 {
-	struct tulip_private *tp = dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	u8 cache;
 	u16 pci_command;
 	u32 csr0;
@@ -1373,7 +1373,7 @@ static int __devinit tulip_init_one (str
 	 * initialize private data structure 'tp'
 	 * it is zeroed and aligned in alloc_etherdev
 	 */
-	tp = dev->priv;
+	tp = netdev_priv(dev);
 
 	tp->rx_ring = pci_alloc_consistent(pdev,
 					   sizeof(struct tulip_rx_desc) * RX_RING_SIZE +
@@ -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;
@@ -1756,7 +1759,7 @@ static void __devexit tulip_remove_one (
 	if (!dev)
 		return;
 
-	tp = dev->priv;
+	tp = netdev_priv(dev);
 	pci_free_consistent (pdev,
 			     sizeof (struct tulip_rx_desc) * RX_RING_SIZE +
 			     sizeof (struct tulip_tx_desc) * TX_RING_SIZE,
@@ -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-16 09:37:56.282983856 +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/tulip/xircom_cb.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/net/tulip/xircom_cb.c	2004-03-16 09:37:56.284983552 +0000
@@ -178,7 +178,7 @@ static void print_binary(unsigned int nu
 static void netdev_get_drvinfo(struct net_device *dev,
 			       struct ethtool_drvinfo *info)
 {
-	struct xircom_private *private = dev->priv;
+	struct xircom_private *private = netdev_priv(dev);
 
 	strcpy(info->driver, "xircom_cb");
 	strcpy(info->bus_info, pci_name(private->pdev));
@@ -235,7 +235,7 @@ static int __devinit xircom_probe(struct
 		printk(KERN_ERR "xircom_probe: failed to allocate etherdev\n");
 		goto device_fail;
 	}
-	private = dev->priv;
+	private = netdev_priv(dev);
 	
 	/* Allocate the send/receive buffers */
 	private->rx_buffer = pci_alloc_consistent(pdev,8192,&private->rx_dma_handle);
@@ -312,7 +312,7 @@ device_fail:
 static void __devexit xircom_remove(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct xircom_private *card = dev->priv;
+	struct xircom_private *card = netdev_priv(dev);
 
 	enter("xircom_remove");
 	pci_free_consistent(pdev,8192,card->rx_buffer,card->rx_dma_handle);
@@ -328,7 +328,7 @@ static void __devexit xircom_remove(stru
 static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_instance;
-	struct xircom_private *card = (struct xircom_private *) dev->priv;
+	struct xircom_private *card = netdev_priv(dev);
 	unsigned int status;
 	int i;
 
@@ -385,7 +385,7 @@ static int xircom_start_xmit(struct sk_b
 	int desc;
 	enter("xircom_start_xmit");
 	
-	card = (struct xircom_private*)dev->priv;
+	card = netdev_priv(dev);
 	spin_lock_irqsave(&card->lock,flags);
 	
 	/* First see if we can free some descriptors */
@@ -444,7 +444,7 @@ static int xircom_start_xmit(struct sk_b
 
 static int xircom_open(struct net_device *dev)
 {
-	struct xircom_private *xp = (struct xircom_private *) dev->priv;
+	struct xircom_private *xp = netdev_priv(dev);
 	int retval;
 	enter("xircom_open");
 	printk(KERN_INFO "xircom cardbus adaptor found, registering as %s, using irq %i \n",dev->name,dev->irq);
@@ -466,7 +466,7 @@ static int xircom_close(struct net_devic
 	unsigned long flags;
 	
 	enter("xircom_close");
-	card = dev->priv;
+	card = netdev_priv(dev);
 	netif_stop_queue(dev); /* we don't want new packets */
 
 	
@@ -495,7 +495,7 @@ static int xircom_close(struct net_devic
 
 static struct net_device_stats *xircom_get_stats(struct net_device *dev)
 {
-        struct xircom_private *card = (struct xircom_private *)dev->priv;
+        struct xircom_private *card = netdev_priv(dev);
         return &card->stats;
 } 
                                                  
--- diff/drivers/net/tun.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/tun.c	2004-03-16 09:37:56.285983400 +0000
@@ -70,7 +70,7 @@ static int tun_net_close(struct net_devi
 /* Net device start xmit */
 static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct tun_struct *tun = (struct tun_struct *)dev->priv;
+	struct tun_struct *tun = netdev_priv(dev);
 
 	DBG(KERN_INFO "%s: tun_net_xmit %d\n", tun->dev->name, skb->len);
 
@@ -113,14 +113,14 @@ static void tun_net_mclist(struct net_de
 
 static struct net_device_stats *tun_net_stats(struct net_device *dev)
 {
-	struct tun_struct *tun = (struct tun_struct *)dev->priv;
+	struct tun_struct *tun = netdev_priv(dev);
 	return &tun->stats;
 }
 
 /* Initialize net device. */
 static void tun_net_init(struct net_device *dev)
 {
-	struct tun_struct *tun = (struct tun_struct *)dev->priv;
+	struct tun_struct *tun = netdev_priv(dev);
    
 	switch (tun->flags & TUN_TYPE_MASK) {
 	case TUN_TUN_DEV:
@@ -153,7 +153,7 @@ static void tun_net_init(struct net_devi
 /* Poll */
 static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
 {  
-	struct tun_struct *tun = (struct tun_struct *)file->private_data;
+	struct tun_struct *tun = file->private_data;
 	unsigned int mask = POLLOUT | POLLWRNORM;
 
 	if (!tun)
@@ -217,7 +217,7 @@ static __inline__ ssize_t tun_get_user(s
 static ssize_t tun_chr_writev(struct file * file, const struct iovec *iv, 
 			      unsigned long count, loff_t *pos)
 {
-	struct tun_struct *tun = (struct tun_struct *)file->private_data;
+	struct tun_struct *tun = file->private_data;
 	unsigned long i;
 	size_t len;
 
@@ -279,7 +279,7 @@ static __inline__ ssize_t tun_put_user(s
 static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv,
 			    unsigned long count, loff_t *pos)
 {
-	struct tun_struct *tun = (struct tun_struct *)file->private_data;
+	struct tun_struct *tun = file->private_data;
 	DECLARE_WAITQUEUE(wait, current);
 	struct sk_buff *skb;
 	ssize_t len, ret = 0;
@@ -341,7 +341,7 @@ static ssize_t tun_chr_read(struct file 
 
 static void tun_setup(struct net_device *dev)
 {
-	struct tun_struct *tun = dev->priv;
+	struct tun_struct *tun = netdev_priv(dev);
 
 	skb_queue_head_init(&tun->readq);
 	init_waitqueue_head(&tun->read_wait);
@@ -413,7 +413,7 @@ static int tun_set_iff(struct file *file
 		if (!dev)
 			return -ENOMEM;
 
-		tun = dev->priv;
+		tun = netdev_priv(dev);
 		tun->dev = dev;
 		tun->flags = flags;
 
@@ -455,7 +455,7 @@ static int tun_set_iff(struct file *file
 static int tun_chr_ioctl(struct inode *inode, struct file *file, 
 			 unsigned int cmd, unsigned long arg)
 {
-	struct tun_struct *tun = (struct tun_struct *)file->private_data;
+	struct tun_struct *tun = file->private_data;
 
 	if (cmd == TUNSETIFF && !tun) {
 		struct ifreq ifr;
@@ -527,7 +527,7 @@ static int tun_chr_ioctl(struct inode *i
 
 static int tun_chr_fasync(int fd, struct file *file, int on)
 {
-	struct tun_struct *tun = (struct tun_struct *)file->private_data;
+	struct tun_struct *tun = file->private_data;
 	int ret;
 
 	if (!tun)
@@ -558,7 +558,7 @@ static int tun_chr_open(struct inode *in
 
 static int tun_chr_close(struct inode *inode, struct file *file)
 {
-	struct tun_struct *tun = (struct tun_struct *)file->private_data;
+	struct tun_struct *tun = file->private_data;
 
 	if (!tun)
 		return 0;
--- diff/drivers/net/typhoon.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/typhoon.c	2004-03-16 09:37:56.287983096 +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 11:28:08.000000000 +0000
+++ source/drivers/net/via-rhine.c	2004-03-16 09:37:56.289982792 +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/comx-hw-locomx.c	2003-09-30 14:46:16.000000000 +0000
+++ source/drivers/net/wan/comx-hw-locomx.c	2004-03-16 09:37:56.290982640 +0000
@@ -77,7 +77,7 @@ struct locomx_data {
 
 static int LOCOMX_txe(struct net_device *dev)
 {
-	struct comx_channel *ch = dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 	struct locomx_data *hw = ch->HW_privdata;
 
 	return (!hw->board.chanA.tx_next_skb);
@@ -86,8 +86,8 @@ static int LOCOMX_txe(struct net_device 
 
 static void locomx_rx(struct z8530_channel *c, struct sk_buff *skb)
 {
-	struct net_device *dev=c->netdevice;
-	struct comx_channel *ch=dev->priv;
+	struct net_device *dev = c->netdevice;
+	struct comx_channel *ch = netdev_priv(dev);
 	
 	if (ch->debug_flags & DEBUG_HW_RX) {
 		comx_debug_skb(dev, skb, "locomx_rx receiving");
@@ -97,7 +97,7 @@ static void locomx_rx(struct z8530_chann
 
 static int LOCOMX_send_packet(struct net_device *dev, struct sk_buff *skb) 
 {
-	struct comx_channel *ch = (struct comx_channel *)dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 	struct locomx_data *hw = ch->HW_privdata;
 
 	if (ch->debug_flags & DEBUG_HW_TX) {
@@ -126,9 +126,9 @@ static int LOCOMX_send_packet(struct net
 
 static void locomx_status_timerfun(unsigned long d)
 {
-	struct net_device *dev=(struct net_device *)d;
-	struct comx_channel *ch=dev->priv;
-	struct locomx_data *hw=ch->HW_privdata;
+	struct net_device *dev = (struct net_device *)d;
+	struct comx_channel *ch = netdev_priv(dev);
+	struct locomx_data *hw = ch->HW_privdata;
 
 	if(!(ch->line_status & LINE_UP) &&
 	    (hw->board.chanA.status & CTS)) {
@@ -144,7 +144,7 @@ static void locomx_status_timerfun(unsig
 
 static int LOCOMX_open(struct net_device *dev)
 {
-	struct comx_channel *ch = dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 	struct locomx_data *hw = ch->HW_privdata;
 	struct proc_dir_entry *procfile = ch->procdir->subdir;
 	unsigned long flags;
@@ -256,7 +256,7 @@ irq_fail:
 
 static int LOCOMX_close(struct net_device *dev)
 {
-	struct comx_channel *ch = dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 	struct locomx_data *hw = ch->HW_privdata;
 	struct proc_dir_entry *procfile = ch->procdir->subdir;
 
@@ -376,7 +376,7 @@ static int locomx_write_proc(struct file
 
 static int LOCOMX_init(struct net_device *dev) 
 {
-	struct comx_channel *ch = (struct comx_channel *)dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 	struct locomx_data *hw;
 	struct proc_dir_entry *new_file;
 
@@ -449,7 +449,7 @@ cleanup_HW_privdata:
 
 static int LOCOMX_exit(struct net_device *dev)
 {
-	struct comx_channel *ch = (struct comx_channel *)dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 
 	ch->HW_access_board = NULL;
 	ch->HW_release_board = NULL;
--- diff/drivers/net/wan/comx-hw-munich.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/wan/comx-hw-munich.c	2004-03-16 09:37:56.292982336 +0000
@@ -373,7 +373,7 @@ static munich_board_t pcicom_boards[MAX_
 
 void rework_idle_channels(struct net_device *dev)
 {
-    struct comx_channel *ch = dev->priv;
+    struct comx_channel *ch = netdev_priv(dev);
     struct slicecom_privdata *hw = ch->HW_privdata;
     munich_board_t *board = slicecom_boards + hw->boardnum;
     munich_ccb_t *ccb = board->ccb;
@@ -731,7 +731,7 @@ static void pcicom_modemline(unsigned lo
 {
     munich_board_t *board = (munich_board_t *) b;
     struct net_device *dev = board->twins[0];
-    struct comx_channel *ch = dev->priv;
+    struct comx_channel *ch = netdev_priv(dev);
     unsigned long regs;
 
     regs = readl((void *)(&board->bar1[GPDATA]));
@@ -765,7 +765,7 @@ static void pcicom_modemline(unsigned lo
 
 static int MUNICH_txe(struct net_device *dev)
 {
-    struct comx_channel *ch = dev->priv;
+    struct comx_channel *ch = netdev_priv(dev);
     struct slicecom_privdata *hw = ch->HW_privdata;
 
     return (hw->busy < TX_DESC_MAX - 1);
@@ -905,7 +905,7 @@ static int munich_probe(void)
 #if 0
 static int slicecom_reset(struct net_device *dev)
 {
-    struct comx_channel *ch = dev->priv;
+    struct comx_channel *ch = netdev_priv(dev);
 
     printk("slicecom_reset: resetting the hardware\n");
 
@@ -933,7 +933,7 @@ static int slicecom_reset(struct net_dev
 
 static int MUNICH_send_packet(struct net_device *dev, struct sk_buff *skb)
 {
-    struct comx_channel *ch = (struct comx_channel *)dev->priv;
+    struct comx_channel *ch = netdev_priv(dev);
     struct slicecom_privdata *hw = ch->HW_privdata;
 
     /* Send it to the debug facility too if needed: */
@@ -1085,7 +1085,7 @@ static irqreturn_t MUNICH_interrupt(int 
 		goto go_for_next_interrupt;
 	    }
 
-	    ch = (struct comx_channel *)dev->priv;
+	    ch = netdev_priv(dev);
 	    hw = (struct slicecom_privdata *)ch->HW_privdata;
 
 	    //      printk("Rx STAT=0x%08x int_info=0x%08x rx_desc_ptr=%d rx_desc.status=0x%01x\n",
@@ -1125,7 +1125,7 @@ static irqreturn_t MUNICH_interrupt(int 
 
 	    if (dev != NULL)
 	    {
-		ch = (struct comx_channel *)dev->priv;
+		ch = netdev_priv(dev);
 		hw = (struct slicecom_privdata *)ch->HW_privdata;
 
 		rx_status = hw->rx_desc[hw->rx_desc_ptr].status;
@@ -1261,7 +1261,7 @@ static irqreturn_t MUNICH_interrupt(int 
 		goto go_for_next_tx_interrupt;
 	    }
 
-	    ch = (struct comx_channel *)dev->priv;
+	    ch = netdev_priv(dev);
 	    hw = (struct slicecom_privdata *)ch->HW_privdata;
 
 	    //      printk("Tx STAT=0x%08x int_info=0x%08x tiq_ptr=%d\n", stat, int_info.all, board->tiq_ptr );
@@ -1295,7 +1295,7 @@ static irqreturn_t MUNICH_interrupt(int 
 	    {
 		int newbusy;
 
-		ch = (struct comx_channel *)dev->priv;
+		ch = netdev_priv(dev);
 		hw = (struct slicecom_privdata *)ch->HW_privdata;
 
 		/* We don't trust the "Tx available" info from the TIQ, but check        */
@@ -1398,7 +1398,7 @@ static irqreturn_t MUNICH_interrupt(int 
 
 static int MUNICH_open(struct net_device *dev)
 {
-    struct comx_channel *ch = dev->priv;
+    struct comx_channel *ch = netdev_priv(dev);
     struct slicecom_privdata *hw = ch->HW_privdata;
     struct proc_dir_entry *procfile = ch->procdir->subdir;
     munich_board_t *board;
@@ -1891,7 +1891,7 @@ static int MUNICH_open(struct net_device
 
 static int MUNICH_close(struct net_device *dev)
 {
-    struct comx_channel *ch = dev->priv;
+    struct comx_channel *ch = netdev_priv(dev);
     struct slicecom_privdata *hw = ch->HW_privdata;
     struct proc_dir_entry *procfile = ch->procdir->subdir;
     munich_board_t *board;
@@ -2028,7 +2028,7 @@ static int MUNICH_close(struct net_devic
 
 static int MUNICH_minden(struct net_device *dev, char *page)
 {
-    struct comx_channel *ch = dev->priv;
+    struct comx_channel *ch = netdev_priv(dev);
     struct slicecom_privdata *hw = ch->HW_privdata;
     munich_board_t *board;
     struct net_device *devp;
@@ -2290,7 +2290,7 @@ static int munich_read_proc(char *page, 
 {
     struct proc_dir_entry *file = (struct proc_dir_entry *)data;
     struct net_device *dev = file->parent->data;
-    struct comx_channel *ch = dev->priv;
+    struct comx_channel *ch = netdev_priv(dev);
     struct slicecom_privdata *hw = ch->HW_privdata;
     munich_board_t *board;
 
@@ -2388,7 +2388,7 @@ static int munich_write_proc(struct file
 {
     struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
     struct net_device *dev = (struct net_device *)entry->parent->data;
-    struct comx_channel *ch = dev->priv;
+    struct comx_channel *ch = netdev_priv(dev);
     struct slicecom_privdata *hw = ch->HW_privdata;
     munich_board_t *board;
 
@@ -2656,7 +2656,7 @@ static int init_escape(struct comx_chann
 
 static int BOARD_init(struct net_device *dev)
 {
-    struct comx_channel *ch = (struct comx_channel *)dev->priv;
+    struct comx_channel *ch = netdev_priv(dev);
     struct slicecom_privdata *hw;
     struct proc_dir_entry *new_file;
 
@@ -2772,7 +2772,7 @@ static int BOARD_init(struct net_device 
  */
 static int BOARD_exit(struct net_device *dev)
 {
-    struct comx_channel *ch = (struct comx_channel *)dev->priv;
+    struct comx_channel *ch = netdev_priv(dev);
 
     /* Free private data area */
 //    board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards);
--- diff/drivers/net/wan/comx.c	2003-09-30 14:46:16.000000000 +0000
+++ source/drivers/net/wan/comx.c	2004-03-16 09:37:56.294982032 +0000
@@ -119,7 +119,7 @@ struct comx_debugflags_struct	comx_debug
 
 int comx_debug(struct net_device *dev, char *fmt, ...)
 {
-	struct comx_channel *ch = dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 	char *page,*str;
 	va_list args;
 	int len;
@@ -162,7 +162,7 @@ int comx_debug(struct net_device *dev, c
 
 int comx_debug_skb(struct net_device *dev, struct sk_buff *skb, char *msg)
 {
-	struct comx_channel *ch = dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 
 	if (!ch->debug_area) return 0;
 	if (!skb) comx_debug(dev, "%s: %s NULL skb\n\n", dev->name, msg);
@@ -175,7 +175,7 @@ int comx_debug_bytes(struct net_device *
 		char *msg)
 {
 	int pos = 0;
-	struct comx_channel *ch = dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 
 	if (!ch->debug_area) return 0;
 
@@ -207,7 +207,7 @@ int comx_debug_bytes(struct net_device *
 static void comx_loadavg_timerfun(unsigned long d)
 {
 	struct net_device *dev = (struct net_device *)d;
-	struct comx_channel *ch = dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 
 	ch->avg_bytes[ch->loadavg_counter] = ch->current_stats->rx_bytes;
 	ch->avg_bytes[ch->loadavg_counter + ch->loadavg_size] = 
@@ -222,7 +222,7 @@ static void comx_loadavg_timerfun(unsign
 static void comx_reset_timerfun(unsigned long d)
 { 
 	struct net_device *dev = (struct net_device *)d;
-	struct comx_channel *ch = dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 
 	if(!(ch->line_status & (PROTO_LOOP | PROTO_UP))) {
 		if(test_and_set_bit(0,&ch->reset_pending) && ch->HW_reset) {
@@ -236,7 +236,7 @@ static void comx_reset_timerfun(unsigned
 
 static int comx_open(struct net_device *dev)
 {
-	struct comx_channel *ch = dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 	struct proc_dir_entry *comxdir = ch->procdir->subdir;
 	int ret=0;
 
@@ -268,7 +268,7 @@ static int comx_open(struct net_device *
 
 static int comx_close(struct net_device *dev)
 {
-	struct comx_channel *ch = dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 	struct proc_dir_entry *comxdir = ch->procdir->subdir;
 	int ret = -ENODEV;
 
@@ -303,7 +303,7 @@ static int comx_close(struct net_device 
 
 void comx_status(struct net_device *dev, int status)
 {
-	struct comx_channel *ch = dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 
 #if 0
 	if(status & (PROTO_UP | PROTO_LOOP)) {
@@ -321,7 +321,7 @@ void comx_status(struct net_device *dev,
 
 static int comx_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct comx_channel *ch = dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 	int rc;
 
 	if (skb->len > dev->mtu + dev->hard_header_len) {
@@ -342,7 +342,7 @@ static int comx_xmit(struct sk_buff *skb
 static int comx_header(struct sk_buff *skb, struct net_device *dev, 
 	unsigned short type, void *daddr, void *saddr, unsigned len) 
 {
-	struct comx_channel *ch = dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 
 	if (ch->LINE_header) {
 		return (ch->LINE_header(skb, dev, type, daddr, saddr, len));
@@ -354,7 +354,7 @@ static int comx_header(struct sk_buff *s
 static int comx_rebuild_header(struct sk_buff *skb) 
 {
 	struct net_device *dev = skb->dev;
-	struct comx_channel *ch = dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 
 	if (ch->LINE_rebuild_header) {
 		return(ch->LINE_rebuild_header(skb));
@@ -365,7 +365,7 @@ static int comx_rebuild_header(struct sk
 
 int comx_rx(struct net_device *dev, struct sk_buff *skb)
 {
-	struct comx_channel *ch = dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 
 	if (ch->debug_flags & DEBUG_COMX_RX) {
 		comx_debug_skb(dev, skb, "comx_rx skb");
@@ -379,7 +379,7 @@ int comx_rx(struct net_device *dev, stru
 
 static struct net_device_stats *comx_stats(struct net_device *dev)
 {
-	struct comx_channel *ch = (struct comx_channel *)dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 
 	return ch->current_stats;
 }
@@ -387,7 +387,7 @@ static struct net_device_stats *comx_sta
 void comx_lineup_func(unsigned long d)
 {
 	struct net_device *dev = (struct net_device *)d;
-	struct comx_channel *ch = dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 
 	del_timer(&ch->lineup_timer);
 	clear_bit(0, &ch->lineup_pending);
@@ -405,7 +405,7 @@ void comx_lineup_func(unsigned long d)
 
 static int comx_statistics(struct net_device *dev, char *page)
 {
-	struct comx_channel *ch = dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 	int len = 0;
 	int tmp;
 	int i = 0;
@@ -472,7 +472,7 @@ static int comx_statistics(struct net_de
 
 static int comx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	struct comx_channel *ch = dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 
 	if (ch->LINE_ioctl) {
 		return(ch->LINE_ioctl(dev, ifr, cmd));
@@ -535,7 +535,7 @@ static int comx_read_proc(char *page, ch
 {
 	struct proc_dir_entry *file = (struct proc_dir_entry *)data;
 	struct net_device *dev = file->parent->data;
-	struct comx_channel *ch=(struct comx_channel *)dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 	int len = 0;
 
 	if (strcmp(file->name, FILENAME_STATUS) == 0) {
@@ -599,7 +599,7 @@ static int comx_write_proc(struct file *
 {
 	struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
 	struct net_device *dev = (struct net_device *)entry->parent->data;
-	struct comx_channel *ch=(struct comx_channel *)dev->priv;
+	struct comx_channel *ch = netdev_priv(dev);
 	char *page;
 	struct comx_hardware *hw = comx_channels;
 	struct comx_protocol *line = comx_lines;
@@ -821,7 +821,7 @@ static int comx_mkdir(struct inode *dir,
 	if (register_netdevice(dev)) {
 		goto cleanup_filename_debug;
 	}
-	ch=dev->priv;
+	ch = netdev_priv(dev);
 	if((ch->if_ptr = (void *)kmalloc(sizeof(struct ppp_device), 
 				 GFP_KERNEL)) == NULL) {
 		goto cleanup_register;
@@ -874,7 +874,7 @@ static int comx_rmdir(struct inode *dir,
 
 	lock_kernel();
 	dev = entry->data;
-	ch = dev->priv;
+	ch = netdev_priv(dev);
 	if (dev->flags & IFF_UP) {
 		printk(KERN_ERR "%s: down interface before removing it\n", dev->name);
 		unlock_kernel();
--- diff/drivers/net/wan/cosa.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/wan/cosa.c	2004-03-16 09:37:56.295981880 +0000
@@ -639,7 +639,7 @@ static void sppp_channel_delete(struct c
 
 static int cosa_sppp_open(struct net_device *d)
 {
-	struct channel_data *chan = d->priv;
+	struct channel_data *chan = netdev_priv(d);
 	int err;
 	unsigned long flags;
 
@@ -679,7 +679,7 @@ static int cosa_sppp_open(struct net_dev
 
 static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	struct channel_data *chan = dev->priv;
+	struct channel_data *chan = netdev_priv(dev);
 
 	netif_stop_queue(dev);
 
@@ -690,7 +690,7 @@ static int cosa_sppp_tx(struct sk_buff *
 
 static void cosa_sppp_timeout(struct net_device *dev)
 {
-	struct channel_data *chan = dev->priv;
+	struct channel_data *chan = netdev_priv(dev);
 
 	if (test_bit(RXBIT, &chan->cosa->rxtx)) {
 		chan->stats.rx_errors++;
@@ -709,7 +709,7 @@ static void cosa_sppp_timeout(struct net
 
 static int cosa_sppp_close(struct net_device *d)
 {
-	struct channel_data *chan = d->priv;
+	struct channel_data *chan = netdev_priv(d);
 	unsigned long flags;
 
 	netif_stop_queue(d);
@@ -789,7 +789,7 @@ static int sppp_tx_done(struct channel_d
 
 static struct net_device_stats *cosa_net_stats(struct net_device *dev)
 {
-	struct channel_data *chan = dev->priv;
+	struct channel_data *chan = netdev_priv(dev);
 	return &chan->stats;
 }
 
@@ -807,7 +807,7 @@ static ssize_t cosa_read(struct file *fi
 {
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
-	struct channel_data *chan = (struct channel_data *)file->private_data;
+	struct channel_data *chan = file->private_data;
 	struct cosa_data *cosa = chan->cosa;
 	char *kbuf;
 
@@ -881,7 +881,7 @@ static ssize_t cosa_write(struct file *f
 	const char *buf, size_t count, loff_t *ppos)
 {
 	DECLARE_WAITQUEUE(wait, current);
-	struct channel_data *chan = (struct channel_data *)file->private_data;
+	struct channel_data *chan = file->private_data;
 	struct cosa_data *cosa = chan->cosa;
 	unsigned long flags;
 	char *kbuf;
@@ -990,7 +990,7 @@ static int cosa_open(struct inode *inode
 
 static int cosa_release(struct inode *inode, struct file *file)
 {
-	struct channel_data *channel = (struct channel_data *)file->private_data;
+	struct channel_data *channel = file->private_data;
 	struct cosa_data *cosa;
 	unsigned long flags;
 
@@ -1205,7 +1205,7 @@ static int cosa_sppp_ioctl(struct net_de
 	int cmd)
 {
 	int rv;
-	struct channel_data *chan = (struct channel_data *)dev->priv;
+	struct channel_data *chan = netdev_priv(dev);
 	rv = cosa_ioctl_common(chan->cosa, chan, cmd, (unsigned long)ifr->ifr_data);
 	if (rv == -ENOIOCTLCMD) {
 		return sppp_do_ioctl(dev, ifr, cmd);
@@ -1216,7 +1216,7 @@ static int cosa_sppp_ioctl(struct net_de
 static int cosa_chardev_ioctl(struct inode *inode, struct file *file,
 	unsigned int cmd, unsigned long arg)
 {
-	struct channel_data *channel = (struct channel_data *)file->private_data;
+	struct channel_data *channel = file->private_data;
 	struct cosa_data *cosa = channel->cosa;
 	return cosa_ioctl_common(cosa, channel, cmd, arg);
 }
--- diff/drivers/net/wan/dscc4.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/wan/dscc4.c	2004-03-16 09:37:56.296981728 +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/lapbether.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/wan/lapbether.c	2004-03-16 09:37:56.297981576 +0000
@@ -198,7 +198,7 @@ drop:
 
 static void lapbeth_data_transmit(struct net_device *ndev, struct sk_buff *skb)
 {
-	struct lapbethdev *lapbeth = ndev->priv;
+	struct lapbethdev *lapbeth = netdev_priv(ndev);
 	unsigned char *ptr;
 	struct net_device *dev;
 	int size = skb->len;
@@ -269,7 +269,7 @@ static void lapbeth_disconnected(struct 
  */
 static struct net_device_stats *lapbeth_get_stats(struct net_device *dev)
 {
-	struct lapbethdev *lapbeth = (struct lapbethdev *)dev->priv;
+	struct lapbethdev *lapbeth = netdev_priv(dev);
 	return &lapbeth->stats;
 }
 
@@ -278,7 +278,7 @@ static struct net_device_stats *lapbeth_
  */
 static int lapbeth_set_mac_address(struct net_device *dev, void *addr)
 {
-	struct sockaddr *sa = (struct sockaddr *)addr;
+	struct sockaddr *sa = addr;
 	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
 	return 0;
 }
@@ -355,7 +355,7 @@ static int lapbeth_new_device(struct net
 	if (!ndev)
 		goto out;
 
-	lapbeth = ndev->priv;
+	lapbeth = netdev_priv(ndev);
 	lapbeth->axdev = ndev;
 
 	dev_hold(dev);
@@ -397,7 +397,7 @@ static int lapbeth_device_event(struct n
 				unsigned long event, void *ptr)
 {
 	struct lapbethdev *lapbeth;
-	struct net_device *dev = (struct net_device *)ptr;
+	struct net_device *dev = ptr;
 
 	if (!dev_is_ethdev(dev))
 		return NOTIFY_DONE;
--- diff/drivers/net/wd.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/wd.c	2004-03-16 09:37:56.298981424 +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/wireless/Kconfig	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/wireless/Kconfig	2004-03-16 09:37:56.298981424 +0000
@@ -307,6 +307,53 @@ config PCMCIA_WL3501
 	 It has basic support for Linux wireless extensions and initial
 	 micro support for ethtool.
 
+comment "Prism GT/Duette 802.11(a/b/g) PCI/PCMCIA support"
+	depends on NET_RADIO && PCI
+config PRISM54
+	tristate 'Intersil Prism GT/Duette/Indigo PCI/PCMCIA' 
+	depends on PCI && NET_RADIO && EXPERIMENTAL && HOTPLUG
+	select FW_LOADER
+	---help---
+	  Enable PCI and Cardbus support for the following chipset based cards:
+
+	  ISL3880 - Prism GT		802.11 b/g
+	  ISL3877 - Prism Indigo	802.11 a
+	  ISL3890 - Prism Duette	802.11 a/b/g
+	  
+	  For a complete list of supported cards visit <http://prism54.org>.
+	  Here is the latest confirmed list of supported cards:
+
+	  3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72
+	  Allnet ALL0271 PCI Card
+	  Compex WL54G Cardbus Card
+	  Corega CG-WLCB54GT Cardbus Card
+	  D-Link Air Plus Xtreme G A1 Cardbus Card aka DWL-g650
+	  I-O Data WN-G54/CB Cardbus Card
+	  Kobishi XG-300 aka Z-Com Cardbus Card
+	  Netgear WG511 Cardbus Card
+	  Ovislink WL-5400PCI PCI Card
+	  Peabird WLG-PCI PCI Card
+	  Sitecom WL-100i Cardbus Card
+	  Sitecom WL-110i PCI Card
+	  SMC2802W - EZ Connect g 2.4GHz 54 Mbps Wireless PCI Card
+	  SMC2835W - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card
+	  Z-Com XG-900 PCI Card
+	  Zyxel G-100 Cardbus Card
+
+	  If you enable this you will need a firmware file as well.
+	  You will need to copy this to /usr/lib/hotplug/firmware/isl3890.
+	  You can get this non-GPL'd firmware file from the Prism54 project page:
+	  <http://prism54.org>
+	  You will also need the /etc/hotplug/firmware.agent script from
+	  a current hotplug package.
+
+	  Note: You need a motherboard with DMA support to use any of these cards 
+	  
+	  If you want to compile the driver as a module ( = code which can be
+	  inserted in and removed from the running kernel whenever you want),
+	  say M here and read <file:Documentation/modules.txt>.  The module
+	  will be called prism54.ko.
+
 # yes, this works even when no drivers are selected
 config NET_WIRELESS
 	bool
--- diff/drivers/net/wireless/Makefile	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/wireless/Makefile	2004-03-16 09:37:56.299981272 +0000
@@ -26,6 +26,8 @@ obj-$(CONFIG_ATMEL)             += atmel
 obj-$(CONFIG_PCI_ATMEL)         += atmel_pci.o 
 obj-$(CONFIG_PCMCIA_ATMEL)      += atmel_cs.o
 
+obj-$(CONFIG_PRISM54)		+= prism54/
+
 # 16-bit wireless PCMCIA client drivers
 obj-$(CONFIG_PCMCIA_RAYCS)	+= ray_cs.o
 obj-$(CONFIG_PCMCIA_WL3501)	+= wl3501_cs.o
--- diff/drivers/net/wireless/airo.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/wireless/airo.c	2004-03-16 09:37:56.303980664 +0000
@@ -1505,7 +1505,7 @@ static int RxSeqValid (struct airo_info 
 	seq = micSeq - (context->window - 33);
 
 	//Too old of a SEQ number to check.
-	if ((u32)seq < 0)
+	if ((s32)seq < 0)
 		return ERROR;
     
 	if ( seq > 64 ) {
--- diff/drivers/net/wireless/atmel.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/wireless/atmel.c	2004-03-16 09:37:56.307980056 +0000
@@ -796,7 +796,7 @@ static void tx_update_descriptor(struct 
 
 static int start_tx (struct sk_buff *skb, struct net_device *dev)
 {
-	struct atmel_private *priv = (struct atmel_private *)dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	struct ieee802_11_hdr header;
 	unsigned long flags;
 	u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
@@ -1167,7 +1167,7 @@ static void reset_irq_status(struct atme
 static irqreturn_t service_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
-	struct atmel_private *priv = (struct atmel_private *) dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	u8 isr;
 	
 	if (priv->card && priv->present_callback && 
@@ -1234,13 +1234,13 @@ static irqreturn_t service_interrupt(int
 
 static struct net_device_stats *atmel_get_stats (struct net_device *dev)
 {
-	struct atmel_private *priv = (struct atmel_private *)dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	return &priv->stats;
 }
 
 static struct iw_statistics *atmel_get_wireless_stats (struct net_device *dev)
 {
-	struct atmel_private *priv = (struct atmel_private *)dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 
 	/* update the link quality here in case we are seeing no beacons 
 	   at all to drive the process */
@@ -1287,7 +1287,7 @@ static int atmel_set_mac_address(struct 
 
 static int atmel_open (struct net_device *dev)
 {
-	struct atmel_private *priv = (struct atmel_private *) dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	priv->station_state = STATION_STATE_INITIALIZING;
 	if (!reset_atmel_card(dev)) {
 		priv->station_state = STATION_STATE_DOWN;
@@ -1298,7 +1298,7 @@ static int atmel_open (struct net_device
 
 static int atmel_close (struct net_device *dev)
 {
-	struct atmel_private *priv = (struct atmel_private *) dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 		
 	netif_carrier_off(dev);	
 	if (netif_running(dev))
@@ -1378,7 +1378,7 @@ static int atmel_proc_output (char *buf,
 static int atmel_read_proc(char *page, char **start, off_t off,
 			   int count, int *eof, void *data)
 {
-        struct atmel_private *priv = (struct atmel_private *)data;
+        struct atmel_private *priv = data;
 	int len = atmel_proc_output (page, priv);
         if (len <= off+count) *eof = 1;
         *start = page + off;
@@ -1406,7 +1406,7 @@ struct net_device *init_atmel_card( unsi
 		goto err_out_free;
 	}
 
-	priv = dev->priv;
+	priv = netdev_priv(dev);
 	priv->dev = dev;
 	priv->sys_dev = sys_dev;
 	priv->present_callback = card_present;
@@ -1525,7 +1525,7 @@ EXPORT_SYMBOL(init_atmel_card);
 
 void stop_atmel_card(struct net_device *dev, int freeres)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 		
 	/* put a brick on it... */
 	if (priv->bus_type == BUS_TYPE_PCCARD) 
@@ -1582,7 +1582,7 @@ static int atmel_set_essid(struct net_de
 			   struct iw_point *dwrq,
 			   char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 
 	/* Check if we asked for `any' */
 	if(dwrq->flags == 0) {
@@ -1610,7 +1610,7 @@ static int atmel_get_essid(struct net_de
 			   struct iw_point *dwrq,
 			   char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 
 	/* Get the current SSID */
 	if (priv->SSID_size == 0) {
@@ -1633,7 +1633,7 @@ static int atmel_get_wap(struct net_devi
 			 struct sockaddr *awrq,
 			 char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	memcpy(awrq->sa_data, priv->CurrentBSSID, 6);
 	awrq->sa_family = ARPHRD_ETHER;
 
@@ -1645,7 +1645,7 @@ static int atmel_set_encode(struct net_d
 			    struct iw_point *dwrq,
 			    char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 
 	/* Basic checking: do we have a key to set ?
 	 * Note : with the new API, it's impossible to get a NULL pointer.
@@ -1736,7 +1736,7 @@ static int atmel_get_encode(struct net_d
 			    struct iw_point *dwrq,
 			    char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
 	
 	if (!priv->wep_is_on)
@@ -1776,7 +1776,7 @@ static int atmel_set_rate(struct net_dev
 			  struct iw_param *vwrq,
 			  char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	
 	if (vwrq->fixed == 0) {
 		priv->tx_rate = 3;
@@ -1808,7 +1808,7 @@ static int atmel_set_mode(struct net_dev
 			  __u32 *uwrq,
 			  char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 
 	if (*uwrq != IW_MODE_ADHOC && *uwrq != IW_MODE_INFRA)
 		return -EINVAL;
@@ -1822,7 +1822,7 @@ static int atmel_get_mode(struct net_dev
 			  __u32 *uwrq,
 			  char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	
 	*uwrq = priv->operating_mode;
 	return 0;
@@ -1833,7 +1833,7 @@ static int atmel_get_rate(struct net_dev
 			 struct iw_param *vwrq,
 			 char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 
 	if (priv->auto_tx_rate) {
 		vwrq->fixed = 0;
@@ -1855,7 +1855,7 @@ static int atmel_set_power(struct net_de
 			   struct iw_param *vwrq,
 			   char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	priv->power_mode = vwrq->disabled ? 0 : 1;
 	return -EINPROGRESS;
 }
@@ -1865,7 +1865,7 @@ static int atmel_get_power(struct net_de
 			   struct iw_param *vwrq,
 			   char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	vwrq->disabled = priv->power_mode ? 0 : 1;
 	vwrq->flags = IW_POWER_ON;
 	return 0;
@@ -1876,7 +1876,7 @@ static int atmel_set_retry(struct net_de
 			   struct iw_param *vwrq,
 			   char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	
 	if(!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) {
 		if(vwrq->flags & IW_RETRY_MAX)
@@ -1899,7 +1899,7 @@ static int atmel_get_retry(struct net_de
 			   struct iw_param *vwrq,
 			   char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 
 	vwrq->disabled = 0;      /* Can't be disabled */
 
@@ -1922,7 +1922,7 @@ static int atmel_set_rts(struct net_devi
 			 struct iw_param *vwrq,
 			 char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	int rthr = vwrq->value;
 
 	if(vwrq->disabled)
@@ -1940,7 +1940,7 @@ static int atmel_get_rts(struct net_devi
 			 struct iw_param *vwrq,
 			 char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	
 	vwrq->value = priv->rts_threshold;
 	vwrq->disabled = (vwrq->value >= 2347);
@@ -1954,7 +1954,7 @@ static int atmel_set_frag(struct net_dev
 			  struct iw_param *vwrq,
 			  char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	int fthr = vwrq->value;
 
 	if(vwrq->disabled)
@@ -1973,7 +1973,7 @@ static int atmel_get_frag(struct net_dev
 			  struct iw_param *vwrq,
 			  char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 
 	vwrq->value = priv->frag_threshold;
 	vwrq->disabled = (vwrq->value >= 2346);
@@ -1990,7 +1990,7 @@ static int atmel_set_freq(struct net_dev
 			  struct iw_freq *fwrq,
 			  char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	int rc = -EINPROGRESS;		/* Call commit handler */
 	
 	/* If setting by frequency, convert to a channel */
@@ -2024,7 +2024,7 @@ static int atmel_get_freq(struct net_dev
 			  struct iw_freq *fwrq,
 			  char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 
 	fwrq->m = priv->channel;
 	fwrq->e = 0;
@@ -2036,7 +2036,7 @@ static int atmel_set_scan(struct net_dev
 			  struct iw_param *vwrq,
 			  char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 
 	/* Note : you may have realised that, as this is a SET operation,
 	 * this is privileged and therefore a normal user can't
@@ -2074,7 +2074,7 @@ static int atmel_get_scan(struct net_dev
 			  struct iw_point *dwrq,
 			  char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	int i;
 	char *current_ev = extra;
 	struct iw_event	iwe;
@@ -2126,7 +2126,7 @@ static int atmel_get_range(struct net_de
 			   struct iw_point *dwrq,
 			   char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	struct iw_range *range = (struct iw_range *) extra;
 	int k,i,j;
 
@@ -2193,7 +2193,7 @@ static int atmel_set_wap(struct net_devi
 			 struct sockaddr *awrq,
 			 char *extra)
 {
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	int i;
 	static const u8 bcast[] = { 255, 255, 255, 255, 255, 255 };
 	
@@ -2318,7 +2318,7 @@ static const struct iw_handler_def	atmel
 static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	int rc = 0;
-	struct atmel_private *priv = (struct atmel_private *) dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	atmel_priv_ioctl com;
 	struct iwreq *wrq = (struct iwreq *) rq;
 	unsigned char *new_firmware;
@@ -3053,7 +3053,7 @@ static void atmel_management_frame(struc
 static void atmel_management_timer(u_long a)
 {
   struct net_device *dev = (struct net_device *) a;
-  struct atmel_private *priv = (struct atmel_private *)dev->priv;
+  struct atmel_private *priv = netdev_priv(dev);
   unsigned long flags;
   
   /* Check if the card has been yanked. */
@@ -3297,7 +3297,7 @@ static int atmel_wakeup_firmware(struct 
 static int probe_atmel_card(struct net_device *dev)
 {
 	int rc = 0;
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	 
 	/* reset pccard */
 	if (priv->bus_type == BUS_TYPE_PCCARD) 
@@ -3486,7 +3486,7 @@ int reset_atmel_card(struct net_device *
 	   which is the route into the rest of the firmare datastructures. */
 
 	int channel;
-	struct atmel_private *priv = dev->priv;
+	struct atmel_private *priv = netdev_priv(dev);
 	u8 configuration;
 	
 	/* data to add to the firmware names, in priority order
--- diff/drivers/net/wireless/orinoco.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/net/wireless/orinoco.c	2004-03-16 09:37:56.312979296 +0000
@@ -599,7 +599,7 @@ static int orinoco_debug_dump_recs(struc
 
 int __orinoco_up(struct net_device *dev)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	struct hermes *hw = &priv->hw;
 	int err;
 
@@ -626,7 +626,7 @@ int __orinoco_up(struct net_device *dev)
 
 int __orinoco_down(struct net_device *dev)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	struct hermes *hw = &priv->hw;
 	int err;
 
@@ -657,7 +657,7 @@ int __orinoco_down(struct net_device *de
 
 int orinoco_reinit_firmware(struct net_device *dev)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	struct hermes *hw = &priv->hw;
 	int err;
 
@@ -685,7 +685,7 @@ int orinoco_reinit_firmware(struct net_d
 
 static int orinoco_open(struct net_device *dev)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	unsigned long flags;
 	int err;
 
@@ -705,7 +705,7 @@ static int orinoco_open(struct net_devic
 
 int orinoco_stop(struct net_device *dev)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	int err = 0;
 
 	/* We mustn't use orinoco_lock() here, because we need to be
@@ -724,7 +724,7 @@ int orinoco_stop(struct net_device *dev)
 
 static int __orinoco_program_rids(struct net_device *dev)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
 	int err;
 	struct hermes_idstring idbuf;
@@ -912,7 +912,7 @@ ESSID in IBSS-Ad-Hoc mode.\n", dev->name
 /* xyzzy */
 static int orinoco_reconfigure(struct net_device *dev)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	struct hermes *hw = &priv->hw;
 	unsigned long flags;
 	int err = 0;
@@ -965,7 +965,7 @@ static int orinoco_reconfigure(struct ne
  * schedule_work() */
 static void orinoco_reset(struct net_device *dev)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	struct hermes *hw = &priv->hw;
 	int err;
 	unsigned long flags;
@@ -1070,7 +1070,7 @@ is_ethersnap(struct header_struct *hdr)
 static void
 orinoco_set_multicast_list(struct net_device *dev)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	unsigned long flags;
 
 	if (orinoco_lock(priv, &flags) != 0) {
@@ -1433,7 +1433,7 @@ static void show_rx_frame(struct orinoco
 irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *)dev_id;
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
 	int count = MAX_IRQLOOPS_PER_IRQ;
 	u16 evstat, events;
@@ -1561,7 +1561,7 @@ static void print_linkstatus(struct net_
 
 static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	u16 infofid;
 	struct {
 		u16 len;
@@ -1662,7 +1662,7 @@ static void __orinoco_ev_info(struct net
 
 static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	struct net_device_stats *stats = &priv->stats;
 	struct iw_statistics *wstats = &priv->wstats;
 	struct sk_buff *skb = NULL;
@@ -1814,7 +1814,7 @@ static void __orinoco_ev_rx(struct net_d
 
 static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	struct net_device_stats *stats = &priv->stats;
 	u16 fid = hermes_read_regn(hw, TXCOMPLFID);
 	struct hermes_tx_descriptor desc;
@@ -1840,7 +1840,7 @@ static void __orinoco_ev_txexc(struct ne
 
 static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	struct net_device_stats *stats = &priv->stats;
 
 	stats->tx_packets++;
@@ -1850,7 +1850,7 @@ static void __orinoco_ev_tx(struct net_d
 
 static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 
 	u16 fid = hermes_read_regn(hw, ALLOCFID);
 
@@ -1886,7 +1886,7 @@ static int determine_firmware_type(struc
 
 static void determine_firmware(struct net_device *dev)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
 	int err;
 	struct sta_id sta_id;
@@ -2024,7 +2024,7 @@ static void determine_firmware(struct ne
 static int
 orinoco_init(struct net_device *dev)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
 	int err = 0;
 	struct hermes_idstring nickbuf;
@@ -2204,7 +2204,7 @@ orinoco_init(struct net_device *dev)
 struct net_device_stats *
 orinoco_get_stats(struct net_device *dev)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	
 	return &priv->stats;
 }
@@ -2212,7 +2212,7 @@ orinoco_get_stats(struct net_device *dev
 struct iw_statistics *
 orinoco_get_wireless_stats(struct net_device *dev)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
 	struct iw_statistics *wstats = &priv->wstats;
 	int err = 0;
@@ -2271,7 +2271,7 @@ orinoco_get_wireless_stats(struct net_de
 static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac,
 				    int level, int noise)
 {
-	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	int i;
 
 	/* Gather wireless spy statistics: for each packet, compare the
@@ -2290,7 +2290,7 @@ orinoco_stat_gather(struct net_device *d
 		    struct sk_buff *skb,
 		    struct hermes_rx_descriptor *desc)
 {
-	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 
 	/* Using spy support with lots of Rx packets, like in an
 	 * infrastructure (AP), will really slow down everything, because
@@ -2311,7 +2311,7 @@ orinoco_stat_gather(struct net_device *d
 static int
 orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	struct net_device_stats *stats = &priv->stats;
 	hermes_t *hw = &priv->hw;
 	int err = 0;
@@ -2449,7 +2449,7 @@ orinoco_xmit(struct sk_buff *skb, struct
 static void
 orinoco_tx_timeout(struct net_device *dev)
 {
-	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	struct net_device_stats *stats = &priv->stats;
 	struct hermes *hw = &priv->hw;
 
@@ -2466,7 +2466,7 @@ orinoco_tx_timeout(struct net_device *de
 static int
 orinoco_change_mtu(struct net_device *dev, int new_mtu)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 
 	if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) )
 		return -EINVAL;
@@ -2484,7 +2484,7 @@ orinoco_change_mtu(struct net_device *de
 static void
 __orinoco_set_multicast_list(struct net_device *dev)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
 	int err = 0;
 	int promisc, mc_count;
@@ -2554,7 +2554,7 @@ __orinoco_set_multicast_list(struct net_
 
 static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	int err = 0;
 	int mode;
 	struct iw_range range;
@@ -2699,7 +2699,7 @@ static int orinoco_ioctl_getiwrange(stru
 
 static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
 	int setindex = priv->tx_key;
 	int enable = priv->wep_on;
@@ -2794,7 +2794,7 @@ static int orinoco_ioctl_setiwencode(str
 
 static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
 	u16 xlen = 0;
 	char keybuf[ORINOCO_MAX_KEY_SIZE];
@@ -2841,7 +2841,7 @@ static int orinoco_ioctl_getiwencode(str
 
 static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	char essidbuf[IW_ESSID_MAX_SIZE+1];
 	int err;
 	unsigned long flags;
@@ -2874,7 +2874,7 @@ static int orinoco_ioctl_setessid(struct
 
 static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	char essidbuf[IW_ESSID_MAX_SIZE+1];
 	int active;
 	int err = 0;
@@ -2907,7 +2907,7 @@ static int orinoco_ioctl_getessid(struct
 
 static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	char nickbuf[IW_ESSID_MAX_SIZE+1];
 	int err;
 	unsigned long flags;
@@ -2935,7 +2935,7 @@ static int orinoco_ioctl_setnick(struct 
 
 static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	char nickbuf[IW_ESSID_MAX_SIZE+1];
 	int err;
 	unsigned long flags;
@@ -2957,7 +2957,7 @@ static int orinoco_ioctl_getnick(struct 
 
 static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	int chan = -1;
 	int err;
 	unsigned long flags;
@@ -2999,7 +2999,7 @@ static int orinoco_ioctl_setfreq(struct 
 
 static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
 	u16 val;
 	int err;
@@ -3025,7 +3025,7 @@ static int orinoco_ioctl_getsens(struct 
 
 static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	int val = srq->value;
 	int err;
 	unsigned long flags;
@@ -3047,7 +3047,7 @@ static int orinoco_ioctl_setsens(struct 
 
 static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	int val = rrq->value;
 	int err;
 	unsigned long flags;
@@ -3070,7 +3070,7 @@ static int orinoco_ioctl_setrts(struct n
 
 static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	int err = 0;
 	unsigned long flags;
 
@@ -3105,7 +3105,7 @@ supported on this firmware. Using MWO ro
 
 static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
 	int err = 0;
 	u16 val;
@@ -3143,7 +3143,7 @@ static int orinoco_ioctl_getfrag(struct 
 
 static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	int err = 0;
 	int ratemode = -1;
 	int bitrate; /* 100s of kilobits */
@@ -3186,7 +3186,7 @@ static int orinoco_ioctl_setrate(struct 
 
 static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
 	int err = 0;
 	int ratemode;
@@ -3253,7 +3253,7 @@ static int orinoco_ioctl_getrate(struct 
 
 static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	int err = 0;
 	unsigned long flags;
 
@@ -3306,7 +3306,7 @@ static int orinoco_ioctl_setpower(struct
 
 static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
 	int err = 0;
 	u16 enable, period, timeout, mcast;
@@ -3356,7 +3356,7 @@ static int orinoco_ioctl_getpower(struct
 #if WIRELESS_EXT > 10
 static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
 	int err = 0;
 	u16 short_limit, long_limit, lifetime;
@@ -3409,7 +3409,7 @@ static int orinoco_ioctl_getretry(struct
 
 static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	int val = *( (int *) wrq->u.name );
 	int err;
 	unsigned long flags;
@@ -3429,7 +3429,7 @@ static int orinoco_ioctl_setibssport(str
 
 static int orinoco_ioctl_getibssport(struct net_device *dev, struct iwreq *wrq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	int *val = (int *)wrq->u.name;
 	int err;
 	unsigned long flags;
@@ -3446,7 +3446,7 @@ static int orinoco_ioctl_getibssport(str
 
 static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	int val = *( (int *) wrq->u.name );
 	int err = 0;
 	unsigned long flags;
@@ -3488,7 +3488,7 @@ static int orinoco_ioctl_setport3(struct
 
 static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	int *val = (int *)wrq->u.name;
 	int err;
 	unsigned long flags;
@@ -3507,7 +3507,7 @@ static int orinoco_ioctl_getport3(struct
  * Jean II */
 static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	struct sockaddr address[IW_MAX_SPY];
 	int number = srq->length;
 	int i;
@@ -3554,7 +3554,7 @@ static int orinoco_ioctl_setspy(struct n
 
 static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	struct sockaddr address[IW_MAX_SPY];
 	struct iw_quality spy_stat[IW_MAX_SPY];
 	int number;
@@ -3601,7 +3601,7 @@ static int orinoco_ioctl_getspy(struct n
 static int
 orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	struct iwreq *wrq = (struct iwreq *)rq;
 	int err = 0;
 	int tmp;
@@ -4057,7 +4057,7 @@ struct {
 
 static int orinoco_debug_dump_recs(struct net_device *dev)
 {
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
 	u8 *val8;
 	u16 *val16;
@@ -4131,7 +4131,7 @@ struct net_device *alloc_orinocodev(int 
 	dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card);
 	if (!dev)
 		return NULL;
-	priv = (struct orinoco_private *)dev->priv;
+	priv = netdev_priv(dev);
 	priv->ndev = dev;
 	if (sizeof_card)
 		priv->card = (void *)((unsigned long)dev->priv + sizeof(struct orinoco_private));
--- diff/drivers/net/yellowfin.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/yellowfin.c	2004-03-16 09:37:56.313979144 +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-11 10:20:26.000000000 +0000
+++ source/drivers/net/zorro8390.c	2004-03-16 09:37:56.313979144 +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-16 09:37:56.317978536 +0000
@@ -38,9 +38,8 @@
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/string.h>
-#define PCI_DEBUG
 #include <linux/pci.h>
-#undef PCI_DEBUG
+#include <linux/reboot.h>
 
 #include <asm/byteorder.h>
 #include <asm/cache.h>		/* for L1_CACHE_BYTES */
@@ -63,6 +62,18 @@
 #undef DEBUG_CCIO_INIT
 #undef DEBUG_CCIO_RUN_SG
 
+#ifdef CONFIG_PROC_FS
+/*
+ * CCIO_SEARCH_TIME can help measure how fast the bitmap search is.
+ * impacts performance though - ditch it if you don't use it.
+ */
+#define CCIO_SEARCH_TIME
+#undef CCIO_MAP_STATS
+#else
+#undef CCIO_SEARCH_TIME
+#undef CCIO_MAP_STATS
+#endif
+
 #include <linux/proc_fs.h>
 #include <asm/runway.h>		/* for proc_runway_root */
 
@@ -219,15 +230,18 @@ struct ioc {
 	struct ioa_registers *ioc_hpa;  /* I/O MMU base address */
 	u8  *res_map;	                /* resource map, bit == pdir entry */
 	u64 *pdir_base;	                /* physical base address */
+	u32 pdir_size; 			/* bytes, function of IOV Space size */
 	u32 res_hint;	                /* next available IOVP - 
 					   circular search */
 	u32 res_size;		    	/* size of resource map in bytes */
 	spinlock_t res_lock;
 
-#ifdef CONFIG_PROC_FS
+#ifdef CCIO_SEARCH_TIME
 #define CCIO_SEARCH_SAMPLE 0x100
 	unsigned long avg_search[CCIO_SEARCH_SAMPLE];
 	unsigned long avg_idx;		  /* current index into avg_search */
+#endif
+#ifdef CCIO_MAP_STATS
 	unsigned long used_pages;
 	unsigned long msingle_calls;
 	unsigned long msingle_pages;
@@ -237,12 +251,10 @@ struct ioc {
 	unsigned long usingle_pages;
 	unsigned long usg_calls;
 	unsigned long usg_pages;
-
-	unsigned short cujo20_bug;
 #endif
+	unsigned short cujo20_bug;
 
 	/* STUFF We don't need in performance path */
-	u32 pdir_size; 			/* in bytes, determined by IOV Space size */
 	u32 chainid_shift; 		/* specify bit location of chain_id */
 	struct ioc *next;		/* Linked list of discovered iocs */
 	const char *name;		/* device name from firmware */
@@ -289,11 +301,11 @@ static int ioc_count;
 ** If the search wraps around, and passes the res_hint, it will
 ** cause the kernel to panic anyhow.
 */
-#define CCIO_SEARCH_LOOP(ioc, res_idx, mask_ptr, size)  \
+#define CCIO_SEARCH_LOOP(ioc, res_idx, mask, size)  \
        for(; res_ptr < res_end; ++res_ptr) { \
-               if(0 == (*res_ptr & *mask_ptr)) { \
-                       *res_ptr |= *mask_ptr; \
-                       res_idx = (int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \
+               if(0 == (*res_ptr & mask)) { \
+                       *res_ptr |= mask; \
+                       res_idx = (unsigned int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \
                        ioc->res_hint = res_idx + (size >> 3); \
                        goto resource_found; \
                } \
@@ -302,10 +314,9 @@ static int ioc_count;
 #define CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, size) \
        u##size *res_ptr = (u##size *)&((ioc)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \
        u##size *res_end = (u##size *)&(ioc)->res_map[ioa->res_size]; \
-       u##size *mask_ptr = (u##size *)&mask; \
-       CCIO_SEARCH_LOOP(ioc, res_idx, mask_ptr, size); \
+       CCIO_SEARCH_LOOP(ioc, res_idx, mask, size); \
        res_ptr = (u##size *)&(ioc)->res_map[0]; \
-       CCIO_SEARCH_LOOP(ioa, res_idx, mask_ptr, size);
+       CCIO_SEARCH_LOOP(ioa, res_idx, mask, size);
 
 /*
 ** Find available bit in this ioa's resource map.
@@ -331,40 +342,51 @@ static int ioc_count;
  * of available pages for the requested size.
  */
 static int
-ccio_alloc_range(struct ioc *ioc, unsigned long pages_needed)
+ccio_alloc_range(struct ioc *ioc, size_t size)
 {
-	int res_idx;
-	unsigned long mask;
-#ifdef CONFIG_PROC_FS
+	unsigned int pages_needed = size >> IOVP_SHIFT;
+	unsigned int res_idx;
+#ifdef CCIO_SEARCH_TIME
 	unsigned long cr_start = mfctl(16);
 #endif
 	
-	ASSERT(pages_needed);
-	ASSERT((pages_needed * IOVP_SIZE) <= DMA_CHUNK_SIZE);
-	ASSERT(pages_needed <= BITS_PER_LONG);
-
-	mask = ~(~0UL >> pages_needed);
+	BUG_ON(pages_needed == 0);
+	BUG_ON((pages_needed * IOVP_SIZE) > DMA_CHUNK_SIZE);
      
-	DBG_RES("%s() size: %d pages_needed %d mask 0x%08lx\n", 
-		__FUNCTION__, size, pages_needed, mask);
+	DBG_RES("%s() size: %d pages_needed %d\n", 
+		__FUNCTION__, size, pages_needed);
 
 	/*
 	** "seek and ye shall find"...praying never hurts either...
 	** ggg sacrifices another 710 to the computer gods.
 	*/
 
-	if(pages_needed <= 8) {
+	if (pages_needed <= 8) {
+		/*
+		 * LAN traffic will not thrash the TLB IFF the same NIC
+		 * uses 8 adjacent pages to map seperate payload data.
+		 * ie the same byte in the resource bit map.
+		 */
+#if 0
+		/* FIXME: bit search should shift it's way through
+		 * an unsigned long - not byte at a time. As it is now,
+		 * we effectively allocate this byte to this mapping.
+		 */
+		unsigned long mask = ~(~0UL >> pages_needed);
 		CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 8);
-	} else if(pages_needed <= 16) {
-		CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 16);
-	} else if(pages_needed <= 32) {
-		CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 32);
+#else
+		CCIO_FIND_FREE_MAPPING(ioc, res_idx, 0xff, 8);
+#endif
+	} else if (pages_needed <= 16) {
+		CCIO_FIND_FREE_MAPPING(ioc, res_idx, 0xffff, 16);
+	} else if (pages_needed <= 32) {
+		CCIO_FIND_FREE_MAPPING(ioc, res_idx, ~(unsigned int)0, 32);
 #ifdef __LP64__
-	} else if(pages_needed <= 64) {
-		CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 64);
+	} else if (pages_needed <= 64) {
+		CCIO_FIND_FREE_MAPPING(ioc, res_idx, ~0UL, 64);
 #endif
 	} else {
-		panic("%s: %s() Too many pages to map. pages_needed: %ld\n",
+		panic("%s: %s() Too many pages to map. pages_needed: %u\n",
 		       __FILE__,  __FUNCTION__, pages_needed);
 	}
 
@@ -373,10 +395,10 @@ ccio_alloc_range(struct ioc *ioc, unsign
 	
 resource_found:
 	
-	DBG_RES("%s() res_idx %d mask 0x%08lx res_hint: %d\n",
-		__FUNCTION__, res_idx, mask, ioc->res_hint);
+	DBG_RES("%s() res_idx %d res_hint: %d\n",
+		__FUNCTION__, res_idx, ioc->res_hint);
 
-#ifdef CONFIG_PROC_FS
+#ifdef CCIO_SEARCH_TIME
 	{
 		unsigned long cr_end = mfctl(16);
 		unsigned long tmp = cr_end - cr_start;
@@ -385,10 +407,10 @@ resource_found:
 	}
 	ioc->avg_search[ioc->avg_idx++] = cr_start;
 	ioc->avg_idx &= CCIO_SEARCH_SAMPLE - 1;
-
+#endif
+#ifdef CCIO_MAP_STATS
 	ioc->used_pages += pages_needed;
 #endif
-
 	/* 
 	** return the bit address.
 	*/
@@ -397,9 +419,8 @@ resource_found:
 
 #define CCIO_FREE_MAPPINGS(ioc, res_idx, mask, size) \
         u##size *res_ptr = (u##size *)&((ioc)->res_map[res_idx]); \
-	u##size *mask_ptr = (u##size *)&mask; \
-        ASSERT((*res_ptr & *mask_ptr) == *mask_ptr); \
-        *res_ptr &= ~(*mask_ptr);
+        BUG_ON((*res_ptr & mask) != mask); \
+        *res_ptr &= ~(mask);
 
 /**
  * ccio_free_range - Free pages from the ioc's resource map.
@@ -413,32 +434,35 @@ resource_found:
 static void
 ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped)
 {
-	unsigned long mask;
 	unsigned long iovp = CCIO_IOVP(iova);
 	unsigned int res_idx = PDIR_INDEX(iovp) >> 3;
 
-	ASSERT(pages_mapped);
-	ASSERT((pages_mapped * IOVP_SIZE) <= DMA_CHUNK_SIZE);
-	ASSERT(pages_mapped <= BITS_PER_LONG);
+	BUG_ON(pages_mapped == 0);
+	BUG_ON((pages_mapped * IOVP_SIZE) > DMA_CHUNK_SIZE);
+	BUG_ON(pages_mapped > BITS_PER_LONG);
 
-	mask = ~(~0UL >> pages_mapped);
+	DBG_RES("%s():  res_idx: %d pages_mapped %d\n", 
+		__FUNCTION__, res_idx, pages_mapped);
 
-	DBG_RES("%s():  res_idx: %d pages_mapped %d mask 0x%08lx\n", 
-		__FUNCTION__, res_idx, pages_mapped, mask);
-
-#ifdef CONFIG_PROC_FS
+#ifdef CCIO_MAP_STATS
 	ioc->used_pages -= pages_mapped;
 #endif
 
 	if(pages_mapped <= 8) {
+#if 0
+		/* see matching comments in alloc_range */
+		unsigned long mask = ~(~0UL >> pages_mapped);
 		CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 8);
+#else
+		CCIO_FREE_MAPPINGS(ioc, res_idx, 0xff, 8);
+#endif
 	} else if(pages_mapped <= 16) {
-		CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 16);
+		CCIO_FREE_MAPPINGS(ioc, res_idx, 0xffff, 16);
 	} else if(pages_mapped <= 32) {
-		CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 32);
+		CCIO_FREE_MAPPINGS(ioc, res_idx, ~(unsigned int)0, 32);
 #ifdef __LP64__
 	} else if(pages_mapped <= 64) {
-		CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 64);
+		CCIO_FREE_MAPPINGS(ioc, res_idx, ~0UL, 64);
 #endif
 	} else {
 		panic("%s:%s() Too many pages to unmap.\n", __FILE__,
@@ -533,13 +557,14 @@ static u32 hint_lookup[] = {
  * index are bits 12:19 of the value returned by LCI.
  */ 
 void CCIO_INLINE
-ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, void * vba, unsigned long hints)
+ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
+		   unsigned long hints)
 {
 	register unsigned long pa = (volatile unsigned long) vba;
 	register unsigned long ci; /* coherent index */
 
 	/* We currently only support kernel addresses */
-	ASSERT(sid == KERNEL_SPACE);
+	BUG_ON(sid != KERNEL_SPACE);
 
 	mtsp(sid,1);
 
@@ -652,7 +677,7 @@ ccio_mark_invalid(struct ioc *ioc, dma_a
 		unsigned int idx = PDIR_INDEX(iovp);
 		char *pdir_ptr = (char *) &(ioc->pdir_base[idx]);
 
-		ASSERT(idx < (ioc->pdir_size / sizeof(u64)));
+		BUG_ON(idx >= (ioc->pdir_size / sizeof(u64)));
 		pdir_ptr[7] = 0;	/* clear only VALID bit */ 
 		/*
 		** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360)
@@ -722,7 +747,7 @@ ccio_map_single(struct device *dev, void
 	BUG_ON(!dev);
 	ioc = GET_IOC(dev);
 
-	ASSERT(size > 0);
+	BUG_ON(size <= 0);
 
 	/* save offset bits */
 	offset = ((unsigned long) addr) & ~IOVP_MASK;
@@ -731,12 +756,12 @@ ccio_map_single(struct device *dev, void
 	size = ROUNDUP(size + offset, IOVP_SIZE);
 	spin_lock_irqsave(&ioc->res_lock, flags);
 
-#ifdef CONFIG_PROC_FS
+#ifdef CCIO_MAP_STATS
 	ioc->msingle_calls++;
 	ioc->msingle_pages += size >> IOVP_SHIFT;
 #endif
 
-	idx = ccio_alloc_range(ioc, (size >> IOVP_SHIFT));
+	idx = ccio_alloc_range(ioc, size);
 	iovp = (dma_addr_t)MKIOVP(idx);
 
 	pdir_start = &(ioc->pdir_base[idx]);
@@ -749,7 +774,7 @@ ccio_map_single(struct device *dev, void
 		hint |= HINT_SAFE_DMA;
 
 	while(size > 0) {
-		ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, addr, hint);
+		ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long)addr, hint);
 
 		DBG_RUN(" pdir %p %08x%08x\n",
 			pdir_start,
@@ -795,7 +820,7 @@ ccio_unmap_single(struct device *dev, dm
 
 	spin_lock_irqsave(&ioc->res_lock, flags);
 
-#ifdef CONFIG_PROC_FS
+#ifdef CCIO_MAP_STATS
 	ioc->usingle_calls++;
 	ioc->usingle_pages += size >> IOVP_SHIFT;
 #endif
@@ -861,180 +886,10 @@ ccio_free_consistent(struct device *dev,
 */
 #define PIDE_FLAG 0x80000000UL
 
-/**
- * ccio_fill_pdir - Insert coalesced scatter/gather chunks into the I/O Pdir.
- * @ioc: The I/O Controller.
- * @startsg: The scatter/gather list of coalesced chunks.
- * @nents: The number of entries in the scatter/gather list.
- * @hint: The DMA Hint.
- *
- * This function inserts the coalesced scatter/gather list chunks into the
- * I/O Controller's I/O Pdir.
- */ 
-static CCIO_INLINE int
-ccio_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents, 
-	       unsigned long hint)
-{
-	struct scatterlist *dma_sg = startsg;	/* pointer to current DMA */
-	int n_mappings = 0;
-	u64 *pdirp = 0;
-	unsigned long dma_offset = 0;
-
-	dma_sg--;
-	while (nents-- > 0) {
-		int cnt = sg_dma_len(startsg);
-		sg_dma_len(startsg) = 0;
-
-		DBG_RUN_SG(" %d : %08lx/%05x %08lx/%05x\n", nents,
-			   (unsigned long)sg_dma_address(startsg), cnt,
-			   sg_virt_addr(startsg), startsg->length
-		);
-
-		/*
-		** Look for the start of a new DMA stream
-		*/
-		if(sg_dma_address(startsg) & PIDE_FLAG) {
-			u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG;
-			dma_offset = (unsigned long) pide & ~IOVP_MASK;
-			sg_dma_address(startsg) = 0;
-			dma_sg++;
-			sg_dma_address(dma_sg) = pide;
-			pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]);
-			n_mappings++;
-		}
-
-		/*
-		** Look for a VCONTIG chunk
-		*/
-		if (cnt) {
-			unsigned long vaddr = sg_virt_addr(startsg);
-			ASSERT(pdirp);
-
-			/* Since multiple Vcontig blocks could make up
-			** one DMA stream, *add* cnt to dma_len.
-			*/
-			sg_dma_len(dma_sg) += cnt;
-			cnt += dma_offset;
-			dma_offset=0;	/* only want offset on first chunk */
-			cnt = ROUNDUP(cnt, IOVP_SIZE);
-#ifdef CONFIG_PROC_FS
-			ioc->msg_pages += cnt >> IOVP_SHIFT;
+#ifdef CCIO_MAP_STATS
+#define IOMMU_MAP_STATS
 #endif
-			do {
-				ccio_io_pdir_entry(pdirp, KERNEL_SPACE, 
-						   (void *)vaddr, hint);
-				vaddr += IOVP_SIZE;
-				cnt -= IOVP_SIZE;
-				pdirp++;
-			} while (cnt > 0);
-		}
-		startsg++;
-	}
-	return(n_mappings);
-}
-
-/*
-** First pass is to walk the SG list and determine where the breaks are
-** in the DMA stream. Allocates PDIR entries but does not fill them.
-** Returns the number of DMA chunks.
-**
-** Doing the fill separate from the coalescing/allocation keeps the
-** code simpler. Future enhancement could make one pass through
-** the sglist do both.
-*/
-
-static CCIO_INLINE int
-ccio_coalesce_chunks(struct ioc *ioc, struct scatterlist *startsg, int nents)
-{
-	struct scatterlist *vcontig_sg;    /* VCONTIG chunk head */
-	unsigned long vcontig_len;         /* len of VCONTIG chunk */
-	unsigned long vcontig_end;
-	struct scatterlist *dma_sg;        /* next DMA stream head */
-	unsigned long dma_offset, dma_len; /* start/len of DMA stream */
-	int n_mappings = 0;
-
-	while (nents > 0) {
-
-		/*
-		** Prepare for first/next DMA stream
-		*/
-		dma_sg = vcontig_sg = startsg;
-		dma_len = vcontig_len = vcontig_end = startsg->length;
-		vcontig_end += sg_virt_addr(startsg);
-		dma_offset = sg_virt_addr(startsg) & ~IOVP_MASK;
-
-		/* PARANOID: clear entries */
-		sg_dma_address(startsg) = 0;
-		sg_dma_len(startsg) = 0;
-
-		/*
-		** This loop terminates one iteration "early" since
-		** it's always looking one "ahead".
-		*/
-		while(--nents > 0) {
-			unsigned long startsg_end;
-
-			startsg++;
-			startsg_end = sg_virt_addr(startsg) + 
-				startsg->length;
-
-			/* PARANOID: clear entries */
-			sg_dma_address(startsg) = 0;
-			sg_dma_len(startsg) = 0;
-
-			/*
-			** First make sure current dma stream won't
-			** exceed DMA_CHUNK_SIZE if we coalesce the
-			** next entry.
-			*/   
-			if(ROUNDUP(dma_len + dma_offset + startsg->length,
-				   IOVP_SIZE) > DMA_CHUNK_SIZE)
-				break;
-
-			/*
-			** Append the next transaction?
-			*/
-			if (vcontig_end == sg_virt_addr(startsg)) {
-				vcontig_len += startsg->length;
-				vcontig_end += startsg->length;
-				dma_len     += startsg->length;
-				continue;
-			}
-
-			/*
-			** Not virtually contigous.
-			** Terminate prev chunk.
-			** Start a new chunk.
-			**
-			** Once we start a new VCONTIG chunk, dma_offset
-			** can't change. And we need the offset from the first
-			** chunk - not the last one. Ergo Successive chunks
-			** must start on page boundaries and dove tail
-			** with its predecessor.
-			*/
-			sg_dma_len(vcontig_sg) = vcontig_len;
-
-			vcontig_sg = startsg;
-			vcontig_len = startsg->length;
-			break;
-		}
-
-		/*
-		** End of DMA Stream
-		** Terminate last VCONTIG block.
-		** Allocate space for DMA stream.
-		*/
-		sg_dma_len(vcontig_sg) = vcontig_len;
-		dma_len = ROUNDUP(dma_len + dma_offset, IOVP_SIZE);
-		sg_dma_address(dma_sg) =
-			PIDE_FLAG 
-			| (ccio_alloc_range(ioc, (dma_len >> IOVP_SHIFT)) << IOVP_SHIFT)
-			| dma_offset;
-		n_mappings++;
-	}
-
-	return n_mappings;
-}
+#include "iommu-helpers.h"
 
 /**
  * ccio_map_sg - Map the scatter/gather list into the IOMMU.
@@ -1053,6 +908,8 @@ ccio_map_sg(struct device *dev, struct s
 	int coalesced, filled = 0;
 	unsigned long flags;
 	unsigned long hint = hint_lookup[(int)direction];
+	unsigned long prev_len = 0, current_len = 0;
+	int i;
 	
 	BUG_ON(!dev);
 	ioc = GET_IOC(dev);
@@ -1067,10 +924,13 @@ ccio_map_sg(struct device *dev, struct s
 		sg_dma_len(sglist) = sglist->length;
 		return 1;
 	}
+
+	for(i = 0; i < nents; i++)
+		prev_len += sglist[i].length;
 	
 	spin_lock_irqsave(&ioc->res_lock, flags);
 
-#ifdef CONFIG_PROC_FS
+#ifdef CCIO_MAP_STATS
 	ioc->msg_calls++;
 #endif
 
@@ -1082,7 +942,7 @@ ccio_map_sg(struct device *dev, struct s
 	** w/o this association, we wouldn't have coherent DMA!
 	** Access to the virtual address is what forces a two pass algorithm.
 	*/
-	coalesced = ccio_coalesce_chunks(ioc, sglist, nents);
+	coalesced = iommu_coalesce_chunks(ioc, sglist, nents, ccio_alloc_range);
 
 	/*
 	** Program the I/O Pdir
@@ -1092,13 +952,19 @@ ccio_map_sg(struct device *dev, struct s
 	** o dma_len will contain the number of bytes to map 
 	** o page/offset contain the virtual address.
 	*/
-	filled = ccio_fill_pdir(ioc, sglist, nents, hint);
+	filled = iommu_fill_pdir(ioc, sglist, nents, hint, ccio_io_pdir_entry);
 
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
 
-	ASSERT(coalesced == filled);
+	BUG_ON(coalesced != filled);
+
 	DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled);
 
+	for (i = 0; i < filled; i++)
+		current_len += sg_dma_len(sglist + i);
+
+	BUG_ON(current_len != prev_len);
+
 	return filled;
 }
 
@@ -1123,13 +989,13 @@ ccio_unmap_sg(struct device *dev, struct
 	DBG_RUN_SG("%s() START %d entries,  %08lx,%x\n",
 		__FUNCTION__, nents, sg_virt_addr(sglist), sglist->length);
 
-#ifdef CONFIG_PROC_FS
+#ifdef CCIO_MAP_STATS
 	ioc->usg_calls++;
 #endif
 
 	while(sg_dma_len(sglist) && nents--) {
 
-#ifdef CONFIG_PROC_FS
+#ifdef CCIO_MAP_STATS
 		ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT;
 #endif
 		ccio_unmap_single(dev, sg_dma_address(sglist),
@@ -1149,8 +1015,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
@@ -1199,18 +1067,18 @@ static int ccio_proc_info(char *buf, cha
 			      total_pages * 8, total_pages);
 		if (proc_append(tmp, len, &buf, &offset, &count))
 			break;
-		
+#ifdef CCIO_MAP_STATS
 		len = sprintf(tmp, "IO PDIR entries : %ld free  %ld used (%d%%)\n",
 			      total_pages - ioc->used_pages, ioc->used_pages,
 			      (int)(ioc->used_pages * 100 / total_pages));
 		if (proc_append(tmp, len, &buf, &offset, &count))
 			break;
-		
+#endif
 		len = sprintf(tmp, "Resource bitmap : %d bytes (%d pages)\n", 
 			ioc->res_size, total_pages);
 		if (proc_append(tmp, len, &buf, &offset, &count))
 			break;
-		
+#ifdef CCIO_SEARCH_TIME
 		min = max = ioc->avg_search[0];
 		for(j = 0; j < CCIO_SEARCH_SAMPLE; ++j) {
 			avg += ioc->avg_search[j];
@@ -1224,7 +1092,8 @@ static int ccio_proc_info(char *buf, cha
 			      min, avg, max);
 		if (proc_append(tmp, len, &buf, &offset, &count))
 			break;
-
+#endif
+#ifdef CCIO_MAP_STATS
 		len = sprintf(tmp, "pci_map_single(): %8ld calls  %8ld pages (avg %d/1000)\n",
 			      ioc->msingle_calls, ioc->msingle_pages,
 			      (int)((ioc->msingle_pages * 1000)/ioc->msingle_calls));
@@ -1250,7 +1119,7 @@ static int ccio_proc_info(char *buf, cha
 			      (int)((ioc->usg_pages * 1000)/ioc->usg_calls));
 		if (proc_append(tmp, len, &buf, &offset, &count))
 			break;
-
+#endif	/* CCIO_MAP_STATS */
 		ioc = ioc->next;
 	}
 
@@ -1336,9 +1205,7 @@ void ccio_cujo20_fixup(struct parisc_dev
 	struct ioc *ioc = ccio_get_iommu(dev);
 	u8 *res_ptr;
 
-#ifdef CONFIG_PROC_FS
 	ioc->cujo20_bug = 1;
-#endif
 	res_ptr = ioc->res_map;
 	idx = PDIR_INDEX(iovp) >> 3;
 
@@ -1429,16 +1296,16 @@ ccio_ioc_init(struct ioc *ioc)
 	*/
 
 	iov_order = get_order(iova_space_size) >> (IOVP_SHIFT - PAGE_SHIFT);
-	ASSERT(iov_order <= (30 - IOVP_SHIFT));   /* iova_space_size <= 1GB */
-	ASSERT(iov_order >= (20 - IOVP_SHIFT));   /* iova_space_size >= 1MB */
+	BUG_ON(iov_order > (30 - IOVP_SHIFT));   /* iova_space_size <= 1GB */
+	BUG_ON(iov_order < (20 - IOVP_SHIFT));   /* iova_space_size >= 1MB */
 	iova_space_size = 1 << (iov_order + IOVP_SHIFT);
 
 	ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64);
 
-	ASSERT(ioc->pdir_size < 4 * 1024 * 1024);   /* max pdir size < 4MB */
+	BUG_ON(ioc->pdir_size >= 4 * 1024 * 1024);   /* max pdir size < 4MB */
 
 	/* Verify it's a power of two */
-	ASSERT((1 << get_order(ioc->pdir_size)) == (ioc->pdir_size >> PAGE_SHIFT));
+	BUG_ON((1 << get_order(ioc->pdir_size)) != (ioc->pdir_size >> PAGE_SHIFT));
 
 	DBG_INIT("%s() hpa 0x%p mem %luMB IOV %dMB (%d bits) PDIR size 0x%0x",
 		__FUNCTION__, ioc->ioc_hpa, physmem>>20, iova_space_size>>20,
@@ -1452,7 +1319,7 @@ ccio_ioc_init(struct ioc *ioc)
 	}
 	memset(ioc->pdir_base, 0, ioc->pdir_size);
 
-	ASSERT((((unsigned long)ioc->pdir_base) & PAGE_MASK) == (unsigned long)ioc->pdir_base);
+	BUG_ON((((unsigned long)ioc->pdir_base) & PAGE_MASK) != (unsigned long)ioc->pdir_base);
 	DBG_INIT(" base %p", ioc->pdir_base);
 
 	/* resource map size dictated by pdir_size */
@@ -1684,13 +1551,14 @@ static int ccio_probe(struct parisc_devi
 	
 
 	if (ioc_count == 0) {
-		/* XXX: Create separate entries for each ioc */
+		/* FIXME: Create separate entries for each ioc */
 		create_proc_read_entry(MODULE_NAME, S_IRWXU, proc_runway_root,
 				       ccio_proc_info, NULL);
 		create_proc_read_entry(MODULE_NAME"-bitmap", S_IRWXU,
 				       proc_runway_root, ccio_resource_map, NULL);
 	}
-
+	parisc_vmerge_boundary = IOVP_SIZE;
+	parisc_vmerge_max_size = BITS_PER_LONG * IOVP_SIZE;
 	ioc_count++;
 	return 0;
 }
--- diff/drivers/parisc/ccio-rm-dma.c	2003-02-13 11:46:53.000000000 +0000
+++ source/drivers/parisc/ccio-rm-dma.c	2004-03-16 09:37:56.318978384 +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/eisa.c	2003-09-30 14:46:16.000000000 +0000
+++ source/drivers/parisc/eisa.c	2004-03-16 09:37:56.318978384 +0000
@@ -116,6 +116,16 @@ void eisa_out32(unsigned int data, unsig
 		gsc_writel(cpu_to_le32(data), eisa_permute(port));
 }
 
+#ifndef CONFIG_PCI
+/* We call these directly without PCI.  See asm/io.h. */
+EXPORT_SYMBOL(eisa_in8);
+EXPORT_SYMBOL(eisa_in16);
+EXPORT_SYMBOL(eisa_in32);
+EXPORT_SYMBOL(eisa_out8);
+EXPORT_SYMBOL(eisa_out16);
+EXPORT_SYMBOL(eisa_out32);
+#endif
+
 /* Interrupt handling */
 
 /* cached interrupt mask registers */
--- diff/drivers/parisc/gsc.c	2003-06-30 09:07:29.000000000 +0000
+++ source/drivers/parisc/gsc.c	2004-03-16 09:37:56.319978232 +0000
@@ -29,6 +29,11 @@
 
 #include "gsc.h"
 
+/* This sets the vmerge boundary and size, it's here because it has to
+ * be available on all platforms (zero means no-virtual merging) */
+unsigned long parisc_vmerge_boundary = 0;
+unsigned long parisc_vmerge_max_size = 0;
+
 #undef DEBUG
 
 #ifdef DEBUG
--- diff/drivers/parisc/lba_pci.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/parisc/lba_pci.c	2004-03-16 09:37:56.320978080 +0000
@@ -533,10 +533,10 @@ static int lba_cfg_read(struct pci_bus *
 	*/
 	LBA_CFG_TR4_ADDR_SETUP(d, tok | pos);
 	switch(size) {
-	case 1: *(u8 *)  data = READ_REG8(d->hba.base_addr + LBA_PCI_CFG_DATA);
-	   break;
-	case 2: *(u16 *) data = READ_REG16(d->hba.base_addr + LBA_PCI_CFG_DATA);
-	   break;
+	case 1: *(u8 *)  data = READ_REG8(d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & 3));
+		break;
+	case 2: *(u16 *) data = READ_REG16(d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & 2));
+		break;
 	case 4: *(u32 *) data = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_DATA);
 	   break;
 	}
@@ -613,13 +613,14 @@ static int lba_cfg_write(struct pci_bus 
 	/* Basic Algorithm */
 	LBA_CFG_TR4_ADDR_SETUP(d, tok | pos);
 	switch(size) {
-	case 1: WRITE_REG8 (data, d->hba.base_addr + LBA_PCI_CFG_DATA);
+	case 1: WRITE_REG8 (data, d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & 3));
 		   break;
-	case 2: WRITE_REG16(data, d->hba.base_addr + LBA_PCI_CFG_DATA);
+	case 2: WRITE_REG16(data, d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & 2));
 		   break;
 	case 4: WRITE_REG32(data, d->hba.base_addr + LBA_PCI_CFG_DATA);
 		   break;
 	}
+	/* flush posted write */
 	lba_t32 = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_ADDR);
 	return 0;
 }
--- diff/drivers/parisc/sba_iommu.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/parisc/sba_iommu.c	2004-03-16 09:37:56.323977624 +0000
@@ -700,7 +700,8 @@ typedef unsigned long space_t;
 
 
 void SBA_INLINE
-sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba)
+sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
+		  unsigned long hint)
 {
 	u64 pa; /* physical address */
 	register unsigned ci; /* coherent index */
@@ -874,7 +875,7 @@ sba_map_single(struct device *dev, void 
 
 	while (size > 0) {
 		ASSERT(((u8 *)pdir_start)[7] == 0); /* verify availability */
-		sba_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long) addr);
+		sba_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long) addr, 0);
 
 		DBG_RUN(" pdir 0x%p %02x%02x%02x%02x%02x%02x%02x%02x\n",
 			pdir_start,
@@ -1027,243 +1028,15 @@ sba_free_consistent(struct device *hwdev
 */
 #define PIDE_FLAG 0x80000000UL
 
-#ifdef DEBUG_LARGE_SG_ENTRIES
-int dump_run_sg = 0;
-#endif
-
-
-/**
- * sba_fill_pdir - write allocated SG entries into IO PDIR
- * @ioc: IO MMU structure which owns the pdir we are interested in.
- * @startsg:  list of IOVA/size pairs
- * @nents: number of entries in startsg list
- *
- * Take preprocessed SG list and write corresponding entries
- * in the IO PDIR.
- */
-
-static SBA_INLINE int
-sba_fill_pdir(
-	struct ioc *ioc,
-	struct scatterlist *startsg,
-	int nents)
-{
-	struct scatterlist *dma_sg = startsg;	/* pointer to current DMA */
-	int n_mappings = 0;
-	u64 *pdirp = 0;
-	unsigned long dma_offset = 0;
-
-	dma_sg--;
-	while (nents-- > 0) {
-		int     cnt = sg_dma_len(startsg);
-		sg_dma_len(startsg) = 0;
-
-#ifdef DEBUG_LARGE_SG_ENTRIES
-		if (dump_run_sg)
-			printk(KERN_DEBUG " %2d : %08lx/%05x %p/%05x\n",
-				nents,
-				(unsigned long) sg_dma_address(startsg), cnt,
-				sg_virt_addr(startsg), startsg->length
-		);
-#else
-		DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n",
-				nents,
-				(unsigned long) sg_dma_address(startsg), cnt,
-				sg_virt_addr(startsg), startsg->length
-		);
-#endif
-		/*
-		** Look for the start of a new DMA stream
-		*/
-		if (sg_dma_address(startsg) & PIDE_FLAG) {
-			u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG;
-			dma_offset = (unsigned long) pide & ~IOVP_MASK;
-			sg_dma_address(startsg) = 0;
-			dma_sg++;
-			sg_dma_address(dma_sg) = pide;
-			pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]);
-			n_mappings++;
-		}
-
-		/*
-		** Look for a VCONTIG chunk
-		*/
-		if (cnt) {
-			unsigned long vaddr = (unsigned long) sg_virt_addr(startsg);
-			ASSERT(pdirp);
-
-			/* Since multiple Vcontig blocks could make up
-			** one DMA stream, *add* cnt to dma_len.
-			*/
-			sg_dma_len(dma_sg) += cnt;
-			cnt += dma_offset;
-			dma_offset=0;	/* only want offset on first chunk */
-			cnt = ROUNDUP(cnt, IOVP_SIZE);
 #ifdef SBA_COLLECT_STATS
-			ioc->msg_pages += cnt >> IOVP_SHIFT;
-#endif
-			do {
-				sba_io_pdir_entry(pdirp, KERNEL_SPACE, vaddr);
-				vaddr += IOVP_SIZE;
-				cnt -= IOVP_SIZE;
-				pdirp++;
-			} while (cnt > 0);
-		}
-		startsg++;
-	}
-#ifdef DEBUG_LARGE_SG_ENTRIES
-	dump_run_sg = 0;
+#define IOMMU_MAP_STATS
 #endif
-	return(n_mappings);
-}
-
-
-/*
-** Two address ranges are DMA contiguous *iff* "end of prev" and
-** "start of next" are both on a page boundary.
-**
-** (shift left is a quick trick to mask off upper bits)
-*/
-#define DMA_CONTIG(__X, __Y) \
-	(((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL)
-
-
-/**
- * sba_coalesce_chunks - preprocess the SG list
- * @ioc: IO MMU structure which owns the pdir we are interested in.
- * @startsg:  list of IOVA/size pairs
- * @nents: number of entries in startsg list
- *
- * First pass is to walk the SG list and determine where the breaks are
- * in the DMA stream. Allocates PDIR entries but does not fill them.
- * Returns the number of DMA chunks.
- *
- * Doing the fill separate from the coalescing/allocation keeps the
- * code simpler. Future enhancement could make one pass through
- * the sglist do both.
- */
-static SBA_INLINE int
-sba_coalesce_chunks( struct ioc *ioc,
-	struct scatterlist *startsg,
-	int nents)
-{
-	struct scatterlist *vcontig_sg;    /* VCONTIG chunk head */
-	unsigned long vcontig_len;         /* len of VCONTIG chunk */
-	unsigned long vcontig_end;
-	struct scatterlist *dma_sg;        /* next DMA stream head */
-	unsigned long dma_offset, dma_len; /* start/len of DMA stream */
-	int n_mappings = 0;
-
-	while (nents > 0) {
-		unsigned long vaddr = (unsigned long) sg_virt_addr(startsg); 
-
-		/*
-		** Prepare for first/next DMA stream
-		*/
-		dma_sg = vcontig_sg = startsg;
-		dma_len = vcontig_len = vcontig_end = startsg->length;
-		vcontig_end +=  vaddr;
-		dma_offset = vaddr & ~IOVP_MASK;
-
-		/* PARANOID: clear entries */
-		sg_dma_address(startsg) = 0;
-		sg_dma_len(startsg) = 0;
-
-		/*
-		** This loop terminates one iteration "early" since
-		** it's always looking one "ahead".
-		*/
-		while (--nents > 0) {
-			unsigned long vaddr;	/* tmp */
-
-			startsg++;
-
-			/* PARANOID: clear entries */
-			sg_dma_address(startsg) = 0;
-			sg_dma_len(startsg) = 0;
-
-			/* catch brokenness in SCSI layer */
-			ASSERT(startsg->length <= DMA_CHUNK_SIZE);
-
-			/*
-			** First make sure current dma stream won't
-			** exceed DMA_CHUNK_SIZE if we coalesce the
-			** next entry.
-			*/
-			if (((dma_len + dma_offset + startsg->length + ~IOVP_MASK) & IOVP_MASK) > DMA_CHUNK_SIZE)
-				break;
-
-			/*
-			** Then look for virtually contiguous blocks.
-			** PARISC needs to associate a virtual address
-			** with each IO address mapped. The CPU cache is
-			** virtually tagged and the IOMMU uses part
-			** of the virtual address to participate in
-			** CPU cache coherency.
-			**
-			** append the next transaction?
-			*/
-			vaddr = (unsigned long) sg_virt_addr(startsg);
-			if  (vcontig_end == vaddr)
-			{
-				vcontig_len += startsg->length;
-				vcontig_end += startsg->length;
-				dma_len     += startsg->length;
-				continue;
-			}
+#include "iommu-helpers.h"
 
 #ifdef DEBUG_LARGE_SG_ENTRIES
-			dump_run_sg = (vcontig_len > IOVP_SIZE);
+int dump_run_sg = 0;
 #endif
 
-			/*
-			** Not virtually contigous.
-			** Terminate prev chunk.
-			** Start a new chunk.
-			**
-			** Once we start a new VCONTIG chunk, dma_offset
-			** can't change. And we need the offset from the first
-			** chunk - not the last one. Ergo Successive chunks
-			** must start on page boundaries and dove tail
-			** with its predecessor.
-			*/
-			sg_dma_len(vcontig_sg) = vcontig_len;
-
-			vcontig_sg = startsg;
-			vcontig_len = startsg->length;
-
-			/*
-			** 3) do the entries end/start on page boundaries?
-			**    Don't update vcontig_end until we've checked.
-			*/
-			if (DMA_CONTIG(vcontig_end, vaddr))
-			{
-				vcontig_end = vcontig_len + vaddr;
-				dma_len += vcontig_len;
-				continue;
-			} else {
-				break;
-			}
-		}
-
-		/*
-		** End of DMA Stream
-		** Terminate last VCONTIG block.
-		** Allocate space for DMA stream.
-		*/
-		sg_dma_len(vcontig_sg) = vcontig_len;
-		dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK;
-		ASSERT(dma_len <= DMA_CHUNK_SIZE);
-		sg_dma_address(dma_sg) =
-			PIDE_FLAG 
-			| (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT)
-			| dma_offset;
-		n_mappings++;
-	}
-
-	return n_mappings;
-}
-
 
 /**
  * sba_map_sg - map Scatter/Gather list
@@ -1318,7 +1091,7 @@ sba_map_sg(struct device *dev, struct sc
 	** w/o this association, we wouldn't have coherent DMA!
 	** Access to the virtual address is what forces a two pass algorithm.
 	*/
-	coalesced = sba_coalesce_chunks(ioc, sglist, nents);
+	coalesced = iommu_coalesce_chunks(ioc, sglist, nents, sba_alloc_range);
 
 	/*
 	** Program the I/O Pdir
@@ -1328,7 +1101,7 @@ sba_map_sg(struct device *dev, struct sc
 	** o dma_len will contain the number of bytes to map 
 	** o address contains the virtual address.
 	*/
-	filled = sba_fill_pdir(ioc, sglist, nents);
+	filled = iommu_fill_pdir(ioc, sglist, nents, 0, sba_io_pdir_entry);
 
 #ifdef ASSERT_PDIR_SANITY
 	if (sba_check_pdir(ioc,"Check after sba_map_sg()"))
@@ -1410,8 +1183,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,
 };
 
 
@@ -2045,6 +1820,9 @@ sba_driver_callback(struct parisc_device
 	create_proc_info_entry("bitmap", 0, proc_runway_root, sba_resource_map);
 #endif
 #endif
+	parisc_vmerge_boundary = IOVP_SIZE;
+	parisc_vmerge_max_size = IOVP_SIZE * BITS_PER_LONG;
+
 	return 0;
 }
 
--- diff/drivers/parisc/superio.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/parisc/superio.c	2004-03-16 09:37:56.323977624 +0000
@@ -69,11 +69,15 @@
 #include <linux/termios.h>
 #include <linux/tty.h>
 #include <linux/serial_core.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
 #include <asm/io.h>
 #include <asm/hardware.h>
 #include <asm/irq.h>
 #include <asm/superio.h>
 
+#define SUPERIO_IDE_MAX_RETRIES 25
+
 static struct superio_device sio_dev;
 
 
@@ -161,7 +165,6 @@ superio_init(struct superio_device *sio)
 	printk (KERN_INFO "SuperIO: Found NS87560 Legacy I/O device at %s (IRQ %i) \n",
 		pci_name(pdev),pdev->irq);
 
-	/* Find our I/O devices */
 	pci_read_config_dword (pdev, SIO_SP1BAR, &sio->sp1_base);
 	sio->sp1_base &= ~1;
 	printk (KERN_INFO "SuperIO: Serial port 1 at 0x%x\n", sio->sp1_base);
@@ -462,16 +465,72 @@ superio_parport_init(void)
 }
 
 
-int
-superio_get_ide_irq(void)
+static u8 superio_ide_inb (unsigned long port);
+static unsigned long superio_ide_status[2];
+static unsigned long superio_ide_select[2];
+static unsigned long superio_ide_dma_status[2];
+
+void superio_fixup_pci(struct pci_dev *pdev)
 {
-	if (sio_dev.irq_region)
-		return sio_dev.irq_region->data.irqbase + IDE_IRQ;
-	else
-		return 0;
+	u8 prog;
+
+	pdev->class |= 0x5;
+	pci_write_config_byte(pdev, PCI_CLASS_PROG, pdev->class);
+
+	pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
+	printk("PCI: Enabled native mode for NS87415 (pif=0x%x)\n", prog);
+}
+
+/* Because of a defect in Super I/O, all reads of the PCI DMA status 
+ * registers, IDE status register and the IDE select register need to be 
+ * retried
+ */
+static u8 superio_ide_inb (unsigned long port)
+{
+	if (port == superio_ide_status[0] ||
+	    port == superio_ide_status[1] ||
+	    port == superio_ide_select[0] ||
+	    port == superio_ide_select[1] ||
+	    port == superio_ide_dma_status[0] ||
+	    port == superio_ide_dma_status[1]) {
+		u8 tmp;
+		int retries = SUPERIO_IDE_MAX_RETRIES;
+
+		/* printk(" [ reading port 0x%x with retry ] ", port); */
+
+		do {
+			tmp = inb(port);
+			if (tmp == 0)
+				udelay(50);
+		} while (tmp == 0 && retries-- > 0);
+
+		return tmp;
+	}
+
+	return inb(port);
 }
 
-EXPORT_SYMBOL(superio_get_ide_irq);
+void __init superio_ide_init_iops (struct hwif_s *hwif)
+{
+	u32 base, dmabase;
+	u8 tmp;
+	struct pci_dev *pdev = hwif->pci_dev;
+	u8 port = hwif->channel;
+
+	base = pci_resource_start(pdev, port * 2) & ~3;
+	dmabase = pci_resource_start(pdev, 4) & ~3;
+
+	superio_ide_status[port] = base + IDE_STATUS_OFFSET;
+	superio_ide_select[port] = base + IDE_SELECT_OFFSET;
+	superio_ide_dma_status[port] = dmabase + (!port ? 2 : 0xa);
+	
+	/* Clear error/interrupt, enable dma */
+	tmp = superio_ide_inb(superio_ide_dma_status[port]);
+	outb(tmp | 0x66, superio_ide_dma_status[port]);
+
+	/* We need to override inb to workaround a SuperIO errata */
+	hwif->INB = superio_ide_inb;
+}
 
 static int __devinit superio_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
--- diff/drivers/parport/parport_gsc.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/parport/parport_gsc.c	2004-03-16 09:37:56.393966984 +0000
@@ -476,7 +476,7 @@ static int __devinit parport_init_chip(s
 	return 0;
 }
 
-static void __devexit parport_remove_chip(struct parisc_device *dev)
+static int __devexit parport_remove_chip(struct parisc_device *dev)
 {
 	struct parport *p = dev->dev.driver_data;
 	if (p) {
@@ -495,6 +495,7 @@ static void __devexit parport_remove_chi
 		parport_put_port(p);
 		kfree (ops); /* hope no-one cached it */
 	}
+	return 0;
 }
 
 static struct parisc_device_id parport_tbl[] = {
@@ -508,7 +509,7 @@ static struct parisc_driver parport_driv
 	.name		= "Parallel",
 	.id_table	= parport_tbl,
 	.probe		= parport_init_chip,
-	.remove		= parport_remove_chip,
+	.remove		= __devexit_p(parport_remove_chip),
 };
 
 int __devinit parport_gsc_init(void)
--- diff/drivers/pci/hotplug/Makefile	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/pci/hotplug/Makefile	2004-03-16 09:37:56.394966832 +0000
@@ -40,7 +40,9 @@ acpiphp-objs		:=	acpiphp_core.o	\
 				acpiphp_res.o
 
 rpaphp-objs		:=	rpaphp_core.o	\
-				rpaphp_pci.o	
+				rpaphp_pci.o	\
+				rpaphp_slot.o	\
+				rpaphp_vio.o
 
 rpadlpar_io-objs	:=	rpadlpar_core.o \
 				rpadlpar_sysfs.o
--- diff/drivers/pci/hotplug/acpiphp.h	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/pci/hotplug/acpiphp.h	2004-03-16 09:37:56.395966680 +0000
@@ -235,7 +235,7 @@ extern u32 acpiphp_get_address (struct a
 extern struct pci_dev *acpiphp_allocate_pcidev (struct pci_bus *pbus, int dev, int fn);
 extern int acpiphp_configure_slot (struct acpiphp_slot *slot);
 extern int acpiphp_configure_function (struct acpiphp_func *func);
-extern int acpiphp_unconfigure_function (struct acpiphp_func *func);
+extern void acpiphp_unconfigure_function (struct acpiphp_func *func);
 extern int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge);
 extern int acpiphp_init_func_resource (struct acpiphp_func *func);
 
--- diff/drivers/pci/hotplug/acpiphp_glue.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/pci/hotplug/acpiphp_glue.c	2004-03-16 09:37:56.396966528 +0000
@@ -694,14 +694,14 @@ static int power_on_slot(struct acpiphp_
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		if (func->flags & FUNC_HAS_PS0) {
-			dbg("%s: executing _PS0 on %s\n", __FUNCTION__,
-			    pci_name(func->pci_dev));
+			dbg("%s: executing _PS0\n", __FUNCTION__);
 			status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);
 			if (ACPI_FAILURE(status)) {
 				warn("%s: _PS0 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
-			}
+			} else
+				break;
 		}
 	}
 
@@ -737,7 +737,8 @@ static int power_off_slot(struct acpiphp
 				warn("%s: _PS3 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
-			}
+			} else
+				break;
 		}
 	}
 
@@ -757,7 +758,8 @@ static int power_off_slot(struct acpiphp
 				warn("%s: _EJ0 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
-			}
+			} else
+				break;
 		}
 	}
 
@@ -865,15 +867,8 @@ static int disable_device(struct acpiphp
 	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
-		if (func->pci_dev) {
-			if (acpiphp_unconfigure_function(func) == 0) {
-				func->pci_dev = NULL;
-			} else {
-				err("failed to unconfigure device\n");
-				retval = -1;
-				goto err_exit;
-			}
-		}
+		if (func->pci_dev)
+			acpiphp_unconfigure_function(func);
 	}
 
 	slot->flags &= (~SLOT_ENABLED);
@@ -1269,7 +1264,7 @@ int acpiphp_check_bridge(struct acpiphp_
 					up(&slot->crit_sect);
 					goto err_exit;
 				}
-				enabled++;
+				disabled++;
 			}
 		} else {
 			/* if disabled but present, enable */
@@ -1280,7 +1275,7 @@ int acpiphp_check_bridge(struct acpiphp_
 					up(&slot->crit_sect);
 					goto err_exit;
 				}
-				disabled++;
+				enabled++;
 			}
 		}
 	}
--- diff/drivers/pci/hotplug/acpiphp_pci.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/pci/hotplug/acpiphp_pci.c	2004-03-16 09:37:56.397966376 +0000
@@ -83,8 +83,8 @@ static int init_config_space (struct acp
 		if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
 			/* This is IO */
 
-			len = bar & 0xFFFFFFFC;
-			len = ~len + 1;
+			len = bar & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
+			len = len & ~(len - 1);
 
 			dbg("len in IO %x, BAR %d\n", len, count);
 
@@ -226,8 +226,8 @@ static int detect_used_resource (struct 
 		if (len & PCI_BASE_ADDRESS_SPACE_IO) {
 			/* This is IO */
 			base = bar & 0xFFFFFFFC;
-			len &= 0xFFFFFFFC;
-			len = ~len + 1;
+			len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
+			len = len & ~(len - 1);
 
 			dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
 
@@ -351,8 +351,8 @@ int acpiphp_init_func_resource (struct a
 		if (len & PCI_BASE_ADDRESS_SPACE_IO) {
 			/* This is IO */
 			base = bar & 0xFFFFFFFC;
-			len &= 0xFFFFFFFC;
-			len = ~len + 1;
+			len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
+			len = len & ~(len - 1);
 
 			dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
 
@@ -485,14 +485,13 @@ int acpiphp_configure_function (struct a
  * @func: function to be unconfigured
  *
  */
-int acpiphp_unconfigure_function (struct acpiphp_func *func)
+void acpiphp_unconfigure_function (struct acpiphp_func *func)
 {
 	struct acpiphp_bridge *bridge;
-	int retval = 0;
 
 	/* if pci_dev is NULL, ignore it */
 	if (!func->pci_dev)
-		goto err_exit;
+		return;
 
 	pci_remove_bus_device(func->pci_dev);
 
@@ -505,7 +504,4 @@ int acpiphp_unconfigure_function (struct
 	acpiphp_move_resource(&func->p_mem_head, &bridge->p_mem_head);
 	acpiphp_move_resource(&func->bus_head, &bridge->bus_head);
 	spin_unlock(&bridge->res_lock);
-
- err_exit:
-	return retval;
 }
--- diff/drivers/pci/hotplug/acpiphp_res.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/pci/hotplug/acpiphp_res.c	2004-03-16 09:37:56.398966224 +0000
@@ -224,7 +224,7 @@ struct pci_resource *acpiphp_get_io_reso
 		}  /* End of too big on top end */
 
 		/* For IO make sure it's not in the ISA aliasing space */
-		if (node->base & 0x300L)
+		if ((node->base & 0x300L) && !(node->base & 0xfffff000))
 			continue;
 
 		/* If we got here, then it is the right size
--- diff/drivers/pci/hotplug/pci_hotplug_core.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/pci/hotplug/pci_hotplug_core.c	2004-03-16 09:37:56.399966072 +0000
@@ -104,19 +104,7 @@ static struct kobj_type hotplug_slot_kty
 	.release = &hotplug_slot_release,
 };
 
-/* 
- * We create a struct subsystem on our own and not use decl_subsys so
- * we can have a sane name "slots" in sysfs, yet still keep a good
- * global variable name "pci_hotplug_slots_subsys.
- * If the decl_subsys() #define ever changes, this declaration will
- * need to be update to make sure everything is initialized properly.
- */
-struct subsystem pci_hotplug_slots_subsys = {
-	.kset = {
-		.kobj = { .name = "slots" },
-		.ktype = &hotplug_slot_ktype,
-	}
-};
+decl_subsys_name(pci_hotplug_slots, slots, &hotplug_slot_ktype, NULL);
 
 /* these strings match up with the values in pci_bus_speed */
 static char *pci_bus_speed_strings[] = {
--- diff/drivers/pci/hotplug/pciehp_pci.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/pci/hotplug/pciehp_pci.c	2004-03-16 09:37:56.400965920 +0000
@@ -103,7 +103,7 @@ int pciehp_unconfigure_device(struct pci
  */
 int pciehp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
 {
-#if !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64)
+#if defined(CONFIG_X86) && !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64)
 	int rc;
 	u16 temp_word;
 	struct pci_dev fakedev;
--- diff/drivers/pci/hotplug/pciehprm_acpi.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/pci/hotplug/pciehprm_acpi.c	2004-03-16 09:37:56.401965768 +0000
@@ -1268,7 +1268,8 @@ static int print_acpi_resources (struct 
 int pciehprm_print_pirt(void)
 {
 	dbg("PCIEHPRM ACPI Slots\n");
-	print_acpi_resources (acpi_bridges_head);
+	if (acpi_bridges_head)
+		print_acpi_resources (acpi_bridges_head);
 
 	return 0;
 }
--- diff/drivers/pci/hotplug/rpadlpar_core.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/pci/hotplug/rpadlpar_core.c	2004-03-16 09:37:56.402965616 +0000
@@ -43,7 +43,28 @@ static char *get_node_drc_name(struct de
 	return ptr;
 }
 
-static struct device_node *find_php_slot_node(char *drc_name)
+static struct device_node *find_php_slot_vio_node(char *drc_name)
+{
+	struct device_node *child;
+	struct device_node *parent = of_find_node_by_name(NULL, "vdevice");
+
+	if (!parent)
+		return NULL;
+
+	for (child = of_get_next_child(parent, NULL);	
+	     child; child = of_get_next_child(parent, child)) {
+	
+		char *loc_code;
+	
+		loc_code = get_property(child, "ibm,loc-code", NULL);
+		if (loc_code && !strcmp(loc_code, drc_name))
+			return child;
+	}
+
+	return NULL;
+}
+
+static struct device_node *find_php_slot_pci_node(char *drc_name)
 {
 	struct device_node *np = NULL;
 	char *name;
@@ -72,7 +93,7 @@ static inline struct hotplug_slot *find_
 static struct slot *find_slot(char *drc_name)
 {
 	struct hotplug_slot *php_slot = find_php_slot(drc_name);
-	
+
 	if (!php_slot)
 		return NULL;
 
@@ -127,14 +148,14 @@ static int pci_add_secondary_bus(struct 
 	rpadlpar_claim_one_bus(bridge_dev->bus);
 
 	if (hose->last_busno < child->number)
-	    	hose->last_busno = child->number;
+		hose->last_busno = child->number;
 
 	dn->bussubno = child->number;
 
 	/* ioremap() for child bus */
 	if (remap_bus_range(child)) {
 		printk(KERN_ERR "%s: could not ioremap() child bus\n",
-				__FUNCTION__);
+			__FUNCTION__);
 		return 1;
 	}
 
@@ -162,9 +183,9 @@ static struct pci_dev *dlpar_pci_add_bus
 		return NULL;
 	}
 
-	if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE)  {
+	if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
 		printk(KERN_ERR "%s: unexpected header type %d\n",
-				__FUNCTION__, dev->hdr_type);
+			__FUNCTION__, dev->hdr_type);
 		return NULL;
 	}
 
@@ -180,7 +201,7 @@ static int dlpar_pci_remove_bus(struct p
 
 	if (!bridge_dev) {
 		printk(KERN_ERR "%s: unexpected null device\n",
-				__FUNCTION__);
+			__FUNCTION__);
 		return 1;
 	}
 
@@ -188,11 +209,25 @@ static int dlpar_pci_remove_bus(struct p
 
 	if (unmap_bus_range(secondary_bus)) {
 		printk(KERN_ERR "%s: failed to unmap bus range\n",
-				__FUNCTION__);
+			__FUNCTION__);
 		return 1;
 	}
 
 	pci_remove_bus_device(bridge_dev);
+	return 0;
+}
+
+static inline int dlpar_add_pci_slot(char *drc_name, struct device_node *dn)
+{
+	struct pci_dev *dev;
+
+	/* Add pci bus */
+	dev = dlpar_pci_add_bus(dn);
+	if (!dev) {
+		printk(KERN_ERR "%s: unable to add bus %s\n", __FUNCTION__,
+			drc_name);
+		return -EIO;
+	}
 
 	return 0;
 }
@@ -212,37 +247,33 @@ static int dlpar_pci_remove_bus(struct p
  */
 int dlpar_add_slot(char *drc_name)
 {
-	struct device_node *dn = find_php_slot_node(drc_name);
-	struct pci_dev *dev;
+	struct device_node *dn;
 	int rc = 0;
 
 	if (down_interruptible(&rpadlpar_sem))
 		return -ERESTARTSYS;
 
-	if (!dn) {
-		rc = -ENODEV;
-		goto exit;
-	}
-
 	/* Check for existing hotplug slot */
 	if (find_slot(drc_name)) {
 		rc = -EINVAL;
 		goto exit;
 	}
 
-	/* Add pci bus */
-	dev = dlpar_pci_add_bus(dn);
-	if (!dev) {
-		printk(KERN_ERR "%s: unable to add bus %s\n", __FUNCTION__,
-				drc_name);
-		rc = -EIO;
-		goto exit;
+	dn = find_php_slot_vio_node(drc_name);
+	if (!dn) {
+		dn = find_php_slot_pci_node(drc_name);
+		if (dn)
+			rc = dlpar_add_pci_slot(drc_name, dn);
+		else {
+			rc = -ENODEV;
+			goto exit;
+		}
 	}
 
-	/* Add hotplug slot for new bus */
-	if (rpaphp_add_slot(drc_name)) {
+	/* Add hotplug slot for new VIOA or PCI */
+	if (!rc && rpaphp_add_slot(dn)) {
 		printk(KERN_ERR "%s: unable to add hotplug slot %s\n",
-				__FUNCTION__, drc_name);
+			__FUNCTION__, drc_name);
 		rc = -EIO;
 	}
 exit:
@@ -251,60 +282,107 @@ exit:
 }
 
 /**
- * dlpar_remove_slot - DLPAR remove an I/O Slot
+ * dlpar_remove_vio_slot - DLPAR remove a virtual I/O Slot
  * @drc_name: drc-name of newly added slot
  *
  * Remove the kernel and hotplug representations
  * of an I/O Slot.
  * Return Codes:
  * 0			Success
+ * -EIO			Internal  Error
+ */
+int dlpar_remove_vio_slot(struct slot *slot, char *drc_name)
+{
+	/* Remove hotplug slot */
+
+	if (rpaphp_remove_slot(slot)) {
+		printk(KERN_ERR "%s: unable to remove hotplug slot %s\n",
+			__FUNCTION__, drc_name);
+		return -EIO;
+	}
+	return 0;
+}
+
+/**
+ * dlpar_remove_slot - DLPAR remove a PCI I/O Slot
+ * @drc_name: drc-name of newly added slot
+ *
+ * Remove the kernel and hotplug representations
+ * of a PCI I/O Slot.
+ * Return Codes:
+ * 0			Success
  * -ENODEV		Not a valid drc_name
- * -EINVAL		Slot already removed
- * -ERESTARTSYS		Signalled before obtaining lock
  * -EIO			Internal PCI Error
  */
-int dlpar_remove_slot(char *drc_name)
+int dlpar_remove_pci_slot(struct slot *slot, char *drc_name)
 {
-	struct device_node *dn = find_php_slot_node(drc_name);
-	struct slot *slot;
+	struct device_node *dn = find_php_slot_pci_node(drc_name);
 	struct pci_dev *bridge_dev;
-	int rc = 0;
-
-	if (down_interruptible(&rpadlpar_sem))
-		return -ERESTARTSYS;
 
-	if (!dn) {
-		rc = -ENODEV;
-		goto exit;
-	}
-
-	slot = find_slot(drc_name);
-	if (!slot) {
-		rc = -EINVAL;
-		goto exit;
-	}
+	if (!dn)
+		return -ENODEV;
 
 	bridge_dev = slot->bridge;
 	if (!bridge_dev) {
 		printk(KERN_ERR "%s: unexpected null bridge device\n",
-				__FUNCTION__);
-		rc = -EIO;
-		goto exit;
+			__FUNCTION__);
+		return -EIO;
 	}
 
 	/* Remove hotplug slot */
 	if (rpaphp_remove_slot(slot)) {
 		printk(KERN_ERR "%s: unable to remove hotplug slot %s\n",
-				__FUNCTION__, drc_name);
-		rc = -EIO;
-		goto exit;
+			__FUNCTION__, drc_name);
+		return -EIO;
 	}
 
 	/* Remove pci bus */
 	if (dlpar_pci_remove_bus(bridge_dev)) {
 		printk(KERN_ERR "%s: unable to remove pci bus %s\n",
-				__FUNCTION__, drc_name);
-		rc = -EIO;
+			__FUNCTION__, drc_name);
+		return -EIO;
+	}
+	return 0;
+}
+
+/**
+ * dlpar_remove_slot - DLPAR remove an I/O Slot
+ * @drc_name: drc-name of newly added slot
+ *
+ * Remove the kernel and hotplug representations
+ * of an I/O Slot.
+ * Return Codes:
+ * 0			Success
+ * -ENODEV		Not a valid drc_name
+ * -EINVAL		Slot already removed
+ * -ERESTARTSYS		Signalled before obtaining lock
+ * -EIO			Internal Error
+ */
+int dlpar_remove_slot(char *drc_name)
+{
+	struct slot *slot;
+	int rc = 0;
+
+	if (down_interruptible(&rpadlpar_sem))
+		return -ERESTARTSYS;
+	
+	slot = find_slot(drc_name);
+	if (!slot) {
+		rc = -EINVAL;
+		goto exit;
+	}
+	
+	switch (slot->dev_type) {
+		case PCI_DEV:
+			rc = dlpar_remove_pci_slot(slot, drc_name);
+			break;
+
+		case VIO_DEV:
+			rc = dlpar_remove_vio_slot(slot, drc_name);
+			break;
+
+		default:
+			rc = -EIO;
 	}
 exit:
 	up(&rpadlpar_sem);
@@ -324,7 +402,7 @@ int __init rpadlpar_io_init(void)
 
 	if (!is_dlpar_capable()) {
 		printk(KERN_WARNING "%s: partition not DLPAR capable\n",
-				__FUNCTION__);
+			__FUNCTION__);
 		return -EPERM;
 	}
 
--- diff/drivers/pci/hotplug/rpaphp.h	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/pci/hotplug/rpaphp.h	2004-03-16 09:37:56.402965616 +0000
@@ -26,6 +26,8 @@
 
 #ifndef _PPC64PHP_H
 #define _PPC64PHP_H
+
+#include <linux/pci.h>
 #include "pci_hotplug.h"
 
 #define DR_INDICATOR 9002
@@ -34,24 +36,22 @@
 #define POWER_ON	100
 #define POWER_OFF	0
 
-#define LED_OFF		0 
-#define LED_ON		1	/* continuous on */ 
+#define LED_OFF		0
+#define LED_ON		1	/* continuous on */
 #define LED_ID		2	/* slow blinking */
 #define LED_ACTION	3	/* fast blinking */
 
-#define SLOT_NAME_SIZE 12
-
 /* Error status from rtas_get-sensor */
-#define NEED_POWER    -9000     /* slot must be power up and unisolated to get state */
-#define PWR_ONLY      -9001     /* slot must be powerd up to get state, leave isolated */
-#define ERR_SENSE_USE -9002     /* No DR operation will succeed, slot is unusable  */
+#define NEED_POWER    -9000	/* slot must be power up and unisolated to get state */
+#define PWR_ONLY      -9001	/* slot must be powerd up to get state, leave isolated */
+#define ERR_SENSE_USE -9002	/* No DR operation will succeed, slot is unusable  */
 
 /* Sensor values from rtas_get-sensor */
-#define EMPTY	0       /* No card in slot */
-#define PRESENT	1       /* Card in slot */
+#define EMPTY           0	/* No card in slot */
+#define PRESENT         1	/* Card in slot */
 
 #define MY_NAME "rpaphp"
-
+extern int debug;
 #define dbg(format, arg...)					\
 	do {							\
 		if (debug)					\
@@ -64,6 +64,10 @@
 
 #define SLOT_MAGIC	0x67267322
 
+/* slot types */
+#define VIO_DEV	1
+#define PCI_DEV	2
+
 /* slot states */
 
 #define	NOT_VALID	3
@@ -75,27 +79,55 @@
  * struct slot - slot information for each *physical* slot
  */
 struct slot {
-	u32	magic;
-	int     state;
-	u32     index;
-	u32     type;
-	u32     power_domain;
-	char    *name;
-	struct	device_node *dn;/* slot's device_node in OFDT		*/
-				/* dn has phb info			*/
-	struct	pci_dev	*bridge;/* slot's pci_dev in pci_devices	*/
-
-	struct	pci_dev	*dev;	/* pci_dev of device in this slot 	*/
-				/* it will be used for unconfig		*/ 
-				/* NULL if slot is empty		*/
-
-	struct  hotplug_slot    *hotplug_slot;
-	struct list_head	rpaphp_slot_list;
+	u32 magic;
+	int state;
+	u32 index;
+	u32 type;
+	u32 power_domain;
+	char *name;
+	struct device_node *dn;	/* slot's device_node in OFDT */
+	/* dn has phb info */
+	struct pci_dev *bridge;	/* slot's pci_dev in pci_devices */
+	union {
+		struct pci_dev *pci_dev;	/* pci_dev of device in this slot */
+		/* it will be used for unconfig */
+		/* NULL if slot is empty */
+		struct vio_dev *vio_dev;	/* vio_dev of the device in this slot */
+	} dev;
+	u8 dev_type;		/* VIO or PCI */
+	struct hotplug_slot *hotplug_slot;
+	struct list_head rpaphp_slot_list;
 };
 
+extern struct hotplug_slot_ops rpaphp_hotplug_slot_ops;
+extern struct list_head rpaphp_slot_head;
+extern int num_slots;
+
+/* function prototypes */
+
+/* rpaphp_pci.c */
 extern struct pci_dev *rpaphp_find_pci_dev(struct device_node *dn);
-extern int rpaphp_add_slot(char *slot_name);
-extern int rpaphp_remove_slot(struct slot *slot);
 extern int rpaphp_claim_resource(struct pci_dev *dev, int resource);
+extern int rpaphp_enable_pci_slot(struct slot *slot);
+extern int register_pci_slot(struct slot *slot);
+extern int rpaphp_unconfig_pci_adapter(struct slot *slot);
+extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value);
+
+/* rpaphp_core.c */
+extern int rpaphp_add_slot(struct device_node *dn);
+extern int rpaphp_remove_slot(struct slot *slot);
 
-#endif /* _PPC64PHP_H */
+/* rpaphp_vio.c */
+extern int rpaphp_get_vio_adapter_status(struct slot *slot, int is_init, u8 * value);
+extern int rpaphp_unconfig_vio_adapter(struct slot *slot);
+extern int register_vio_slot(struct device_node *dn);
+extern int rpaphp_enable_vio_slot(struct slot *slot);
+
+/* rpaphp_slot.c */
+extern void dealloc_slot_struct(struct slot *slot);
+extern struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, int power_domain);
+extern int register_slot(struct slot *slot);
+extern int rpaphp_get_power_status(struct slot *slot, u8 * value);
+extern int rpaphp_set_attention_status(struct slot *slot, u8 status);
+	
+#endif				/* _PPC64PHP_H */
--- diff/drivers/pci/hotplug/rpaphp_core.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/pci/hotplug/rpaphp_core.c	2004-03-16 09:37:56.405965160 +0000
@@ -31,18 +31,18 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
+#include <asm/eeh.h>       /* for eeh_add_device() */
 #include <asm/rtas.h>		/* rtas_call */
 #include <asm/pci-bridge.h>	/* for pci_controller */
-#include "../pci.h"		/* for pci_add_new_bus*/
-				/* and pci_do_scan_bus*/
+#include "../pci.h"		/* for pci_add_new_bus */
+				/* and pci_do_scan_bus */
 #include "rpaphp.h"
 #include "pci_hotplug.h"
 
-
-static int debug;
+int debug;
 static struct semaphore rpaphp_sem;
-static LIST_HEAD (rpaphp_slot_head);
-static int num_slots;
+LIST_HEAD(rpaphp_slot_head);
+int num_slots;
 
 #define DRIVER_VERSION	"0.1"
 #define DRIVER_AUTHOR	"Linda Xie <lxie@us.ibm.com>"
@@ -59,109 +59,35 @@ module_param(debug, int, 0644);
 static int enable_slot(struct hotplug_slot *slot);
 static int disable_slot(struct hotplug_slot *slot);
 static int set_attention_status(struct hotplug_slot *slot, u8 value);
-static int get_power_status(struct hotplug_slot *slot, u8 *value);
-static int get_attention_status(struct hotplug_slot *slot, u8 *value);
-static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
+static int get_power_status(struct hotplug_slot *slot, u8 * value);
+static int get_attention_status(struct hotplug_slot *slot, u8 * value);
+static int get_adapter_status(struct hotplug_slot *slot, u8 * value);
 static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
 static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
 
-static struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
-	.owner			= THIS_MODULE,
-	.enable_slot		= enable_slot,
-	.disable_slot		= disable_slot,
-	.set_attention_status	= set_attention_status,
-	.get_power_status	= get_power_status,
-	.get_attention_status	= get_attention_status,
-	.get_adapter_status	= get_adapter_status,
-	.get_max_bus_speed	= get_max_bus_speed,
-	.get_cur_bus_speed	= get_cur_bus_speed,
+struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
+	.owner = THIS_MODULE,
+	.enable_slot = enable_slot,
+	.disable_slot = disable_slot,
+	.set_attention_status = set_attention_status,
+	.get_power_status = get_power_status,
+	.get_attention_status = get_attention_status,
+	.get_adapter_status = get_adapter_status,
+	.get_max_bus_speed = get_max_bus_speed,
+	.get_cur_bus_speed = get_cur_bus_speed,
 };
 
-static int rpaphp_get_sensor_state(int index, int *state)
-{
-	int rc;
-
-	rc = rtas_get_sensor(DR_ENTITY_SENSE, index, state);
-
-	if (rc) {
-		if (rc ==  NEED_POWER || rc == PWR_ONLY) {
-			dbg("%s: slot must be power up to get sensor-state\n",
-				__FUNCTION__);
-		} else if (rc == ERR_SENSE_USE)
-			info("%s: slot is unusable\n", __FUNCTION__);
-		   else err("%s failed to get sensor state\n", __FUNCTION__);
-	}
-	return rc;
-}
-
-static struct pci_dev *rpaphp_find_bridge_pdev(struct slot *slot)
-{
-	return rpaphp_find_pci_dev(slot->dn);
-}
-
-static struct pci_dev *rpaphp_find_adapter_pdev(struct slot *slot)
-{
-	return rpaphp_find_pci_dev(slot->dn->child);
-}
-
-/* Inline functions to check the sanity of a pointer that is passed to us */
-static inline int slot_paranoia_check(struct slot *slot, const char *function)
+static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
 {
-	if (!slot) {
-		dbg("%s - slot == NULL\n", function);
-		return -1;
-	}
-
-	if (!slot->hotplug_slot) {
-		dbg("%s - slot->hotplug_slot == NULL!\n", function);
-		return -1;
-	}
-	return 0;
-}
-
-static inline struct slot *get_slot(struct hotplug_slot *hotplug_slot, const char *function)
-{
-	struct slot *slot;
-
 	if (!hotplug_slot) {
 		dbg("%s - hotplug_slot == NULL\n", function);
 		return NULL;
 	}
-
-	slot = (struct slot *)hotplug_slot->private;
-	if (slot_paranoia_check(slot, function))
-		return NULL;
-	return slot;
-}
-
-static inline int rpaphp_set_attention_status(struct slot *slot, u8 status)
-{
-	int	rc;
-
-	/* status: LED_OFF or LED_ON */
-	rc = rtas_set_indicator(DR_INDICATOR, slot->index, status);
-	if (rc)
-		err("slot(%s) set attention-status(%d) failed! rc=0x%x\n",
-			slot->name, status, rc);
-	
-	return rc;
-}
-
-static int rpaphp_get_power_status(struct slot *slot, u8 *value)
-{
-	int	rc;
-
-	rc = rtas_get_power_level(slot->power_domain, (int *)value);
-	if (rc)
-		err("failed to get power-level for slot(%s), rc=0x%x\n",
-			slot->name, rc);
-
-	return rc;
+	return (struct slot *)hotplug_slot->private;
 }
 
 static int rpaphp_get_attention_status(struct slot *slot)
 {
-
 	return slot->hotplug_slot->info->attention_status;
 }
 
@@ -172,7 +98,7 @@ static int rpaphp_get_attention_status(s
  * echo 2 > attention -- set LED ID(identify, light is blinking)
  *
  */
-static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 value)
+static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value)
 {
 	int retval = 0;
 	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
@@ -182,25 +108,21 @@ static int set_attention_status (struct 
 
 	down(&rpaphp_sem);
 	switch (value) {
-		case 0:
-			retval = rpaphp_set_attention_status(slot, LED_OFF);
-			hotplug_slot->info->attention_status = 0;
-			break;
-
-		case 1:
-		default:
-			retval = rpaphp_set_attention_status(slot, LED_ON);
-			hotplug_slot->info->attention_status = 1;
-			break;
-
-		case 2:
-			retval = rpaphp_set_attention_status(slot, LED_ID);
-			hotplug_slot->info->attention_status = 2;
-			break;
-
+	case 0:
+		retval = rpaphp_set_attention_status(slot, LED_OFF);
+		hotplug_slot->info->attention_status = 0;
+		break;
+	case 1:
+	default:
+		retval = rpaphp_set_attention_status(slot, LED_ON);
+		hotplug_slot->info->attention_status = 1;
+		break;
+	case 2:
+		retval = rpaphp_set_attention_status(slot, LED_ID);
+		hotplug_slot->info->attention_status = 2;
+		break;
 	}
 	up(&rpaphp_sem);
-	
 	return retval;
 }
 
@@ -211,7 +133,7 @@ static int set_attention_status (struct 
  *
  *
  */
-static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
+static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value)
 {
 	int retval;
 	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
@@ -222,7 +144,6 @@ static int get_power_status (struct hotp
 	down(&rpaphp_sem);
 	retval = rpaphp_get_power_status(slot, value);
 	up(&rpaphp_sem);
-
 	return retval;
 }
 
@@ -231,7 +152,7 @@ static int get_power_status (struct hotp
  *
  *
  */
-static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
+static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value)
 {
 	int retval = 0;
 	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
@@ -239,81 +160,36 @@ static int get_attention_status (struct 
 	if (slot == NULL)
 		return -ENODEV;
 
-
 	down(&rpaphp_sem);
 	*value = rpaphp_get_attention_status(slot);
 	up(&rpaphp_sem);
-
 	return retval;
 }
 
-/*
- * get_adapter_status - get  the status of a slot
- *
- * 0-- slot is empty
- * 1-- adapter is configured
- * 2-- adapter is not configured
- * 3-- not valid
- */
-static int rpaphp_get_adapter_status(struct slot *slot, int is_init, u8 *value)
-{
-	int	state, rc;
-
-	*value 		  = NOT_VALID;
-
-	rc = rpaphp_get_sensor_state(slot->index, &state);
-
-	if (rc)
-		return rc;
-
-	if (state == PRESENT) {
-		dbg("slot is occupied\n");
-
-		if (!is_init) /* at run-time slot->state can be changed by */
-			  /* config/unconfig adapter	 		   */
-			*value = slot->state;
-		else {
-		if (!slot->dn->child)
-			dbg("%s: %s is not valid OFDT node\n",
-				__FUNCTION__, slot->dn->full_name);
-		else
-			if (rpaphp_find_pci_dev(slot->dn->child))
-				*value = CONFIGURED;
-			else {
-				dbg("%s: can't find pdev of adapter in slot[%s]\n",
-					__FUNCTION__, slot->name);
-				*value = NOT_CONFIGURED;
-				}
-		}
-	} else
-		if (state == EMPTY) {
-		dbg("slot is empty\n");
-			*value = state;
-		}
-	
-	return 0;
-}
-
-static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
+static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value)
 {
 	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval = 0;
 
 	if (slot == NULL)
 		return -ENODEV;
-
 	down(&rpaphp_sem);
-
 	/*  have to go through this */
-	retval = rpaphp_get_adapter_status(slot, 0, value);
-
+	switch (slot->dev_type) {
+	case PCI_DEV:
+		retval = rpaphp_get_pci_adapter_status(slot, 0, value);
+		break;
+	case VIO_DEV:
+		retval = rpaphp_get_vio_adapter_status(slot, 0, value);
+		break;
+	default:
+		retval = -EINVAL;
+	}
 	up(&rpaphp_sem);
-
 	return retval;
 }
 
-
-static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
 {
 	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 
@@ -321,46 +197,42 @@ static int get_max_bus_speed (struct hot
 		return -ENODEV;
 
 	down(&rpaphp_sem);
-
 	switch (slot->type) {
-		case 1:
-		case 2:
-		case 3:
-		case 4:
-		case 5:
-		case 6:
-			*value = PCI_SPEED_33MHz;	/* speed for case 1-6 */
-			break;
-		case 7:
-		case 8:
-			*value = PCI_SPEED_66MHz;
-			break;
-		case 11:
-		case 14:
-			*value = PCI_SPEED_66MHz_PCIX;
-			break;
-		case 12:
-		case 15:
-			*value = PCI_SPEED_100MHz_PCIX;
-			break;
-		case 13:
-		case 16:
-			*value = PCI_SPEED_133MHz_PCIX;
-			break;
-		default:
-			*value = PCI_SPEED_UNKNOWN;
-			break;
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+		*value = PCI_SPEED_33MHz;	/* speed for case 1-6 */
+		break;
+	case 7:
+	case 8:
+		*value = PCI_SPEED_66MHz;
+		break;
+	case 11:
+	case 14:
+		*value = PCI_SPEED_66MHz_PCIX;
+		break;
+	case 12:
+	case 15:
+		*value = PCI_SPEED_100MHz_PCIX;
+		break;
+	case 13:
+	case 16:
+		*value = PCI_SPEED_133MHz_PCIX;
+		break;
+	default:
+		*value = PCI_SPEED_UNKNOWN;
+		break;
 
 	}
-
 	up(&rpaphp_sem);
-
 	return 0;
 }
 
-
 /* return dummy value because not sure if PRA provides any method... */
-static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
 {
 	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 
@@ -368,416 +240,106 @@ static int get_cur_bus_speed (struct hot
 		return -ENODEV;
 
 	*value = PCI_SPEED_UNKNOWN;
-
 	return 0;
 }
 
-/*
- * rpaphp_validate_slot - make sure the name of the slot matches
- * 				the location code , if the slots is not
- *				empty.
- */
-static int rpaphp_validate_slot(const char *slot_name, const int slot_index)
-{
-	struct device_node	*dn;
-
-	for(dn = find_all_nodes(); dn; dn = dn->next) {
-
-		int 		*index;
-		unsigned char	*loc_code;
-
-		index  = (int *)get_property(dn, "ibm,my-drc-index", NULL);
-
-		if (index && *index == slot_index) {
-			char *slash, *tmp_str;
-
-			loc_code = get_property(dn, "ibm,loc-code", NULL);
-			if (!loc_code) { 
-				return -1;
-			}
-
-			tmp_str = kmalloc(MAX_LOC_CODE, GFP_KERNEL); 
-			if (!tmp_str) {
-				err("%s: out of memory\n", __FUNCTION__);
-				return -1;
-			}
-				
-			strcpy(tmp_str, loc_code);
-			slash = strrchr(tmp_str, '/');
-			if (slash) 
-				*slash = '\0';
-			
-			if (strcmp(slot_name, tmp_str)) {
-				kfree(tmp_str);
-				return -1;
-			}
-
-			kfree(tmp_str);
-			break;
-		}
-	}
-	
-	return 0;
-}
-
-/* Must be called before pci_bus_add_devices */
-static void rpaphp_fixup_new_devices(struct pci_bus *bus)
-{
-	struct pci_dev *dev;
-
-	list_for_each_entry(dev, &bus->devices, bus_list) {
-	/*
-	 * Skip already-present devices (which are on the
-	 * global device list.)
-	 */
-		if (list_empty(&dev->global_list)) {
-			int i;
-			pcibios_fixup_device_resources(dev, bus);
-			pci_read_irq_line(dev);
-			for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-				struct resource *r = &dev->resource[i];
-				if (r->parent || !r->start || !r->flags)
-					continue;
-				rpaphp_claim_resource(dev, i);
-			}
-		}
-	}
-}
-
-static struct pci_dev *rpaphp_config_adapter(struct slot *slot)
-{
-	struct pci_bus 		*pci_bus;
-	struct device_node	*dn;
-	int 			num;
-	struct pci_dev		*dev = NULL;
-
-	if (slot->bridge) {
-
-		pci_bus = slot->bridge->subordinate;
-
-		if (!pci_bus) {
-			err("%s: can't find bus structure\n", __FUNCTION__);
-			goto exit;
-		}
-
-		for (dn = slot->dn->child; dn; dn = dn->sibling) {
-			dbg("child dn's devfn=[%x]\n", dn->devfn);
-				num = pci_scan_slot(pci_bus,
-				PCI_DEVFN(PCI_SLOT(dn->devfn),  0));
-
-				dbg("pci_scan_slot return num=%d\n", num);
-
-			if (num) {
-				rpaphp_fixup_new_devices(pci_bus);
-				pci_bus_add_devices(pci_bus);
-			}
-		}
-
-		dev = rpaphp_find_pci_dev(slot->dn->child);
-	} else {
-		/* slot is not enabled */
-		err("slot doesn't have pci_dev structure\n");
-		dev = NULL;
-		goto exit;
-	}
-
-exit:
-	dbg("Exit %s: pci_dev %s\n", __FUNCTION__, dev? "found":"not found");
-
-	return dev;
-}
-
-static int rpaphp_unconfig_adapter(struct slot *slot)
-{
-	if (!slot->dev) {
-		info("%s: no card in slot[%s]\n",
-			__FUNCTION__, slot->name);
-
-		return -EINVAL;
-	}
-
-	/* remove the device from the pci core */
-	pci_remove_bus_device(slot->dev);
-
-	pci_dev_put(slot->dev);
-	slot->state = NOT_CONFIGURED;
-
-	dbg("%s: adapter in slot[%s] unconfigured.\n", __FUNCTION__, slot->name);
-
-	return 0;
-}
-
-/* free up the memory user be a slot */
-
-static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot)
-{
-	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
-
-	if (slot == NULL)
-		return;
-
-	kfree(slot->hotplug_slot->info);
-	kfree(slot->hotplug_slot->name);
-	kfree(slot->hotplug_slot);
-	pci_dev_put(slot->bridge);
-	pci_dev_put(slot->dev);
-	kfree(slot);
-}
-
 int rpaphp_remove_slot(struct slot *slot)
 {
 	int retval = 0;
+	char *rm_link;
 
-  	sysfs_remove_link(slot->hotplug_slot->kobj.parent,
-			slot->bridge->slot_name);
+	dbg("%s - Entry: slot[%s]\n", __FUNCTION__, slot->name);
+	if (slot->dev_type == PCI_DEV)
+		rm_link = pci_name(slot->bridge);
+	else
+		rm_link = strstr(slot->dn->full_name, "@");
 
+	sysfs_remove_link(slot->hotplug_slot->kobj.parent, rm_link);
 	list_del(&slot->rpaphp_slot_list);
 	retval = pci_hp_deregister(slot->hotplug_slot);
 	if (retval)
 		err("Problem unregistering a slot %s\n", slot->name);
+
 	num_slots--;
 
+	dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
 	return retval;
 }
 
-static int is_php_dn(struct device_node *dn, int **indexes,  int **names, int **types, int **power_domains)
+static int is_php_dn(struct device_node *dn, int **indexes, int **names, int **types,
+	  int **power_domains)
 {
-	*indexes = (int *)get_property(dn, "ibm,drc-indexes", NULL);
+	*indexes = (int *) get_property(dn, "ibm,drc-indexes", NULL);
 	if (!*indexes)
-		return(0);
-
+		return (0);
 	/* &names[1] contains NULL terminated slot names */
-	*names = (int *)get_property(dn, "ibm,drc-names", NULL);
+	*names = (int *) get_property(dn, "ibm,drc-names", NULL);
 	if (!*names)
-		return(0);
-
+		return (0);
 	/* &types[1] contains NULL terminated slot types */
-	*types = (int *)get_property(dn, "ibm,drc-types", NULL);
+	*types = (int *) get_property(dn, "ibm,drc-types", NULL);
 	if (!*types)
-		return(0);
-
+		return (0);
 	/* power_domains[1...n] are the slot power domains */
-	*power_domains = (int *)get_property(dn,
-		"ibm,drc-power-domains", NULL);
+	*power_domains = (int *) get_property(dn,
+					      "ibm,drc-power-domains", NULL);
 	if (!*power_domains)
-		return(0);
-
-	if (!get_property(dn, "ibm,fw-pci-hot-plug-ctrl", NULL))
-		return(0);
-
-	return(1);
-}
-
-static struct slot *alloc_slot_struct(void)
-{
-	struct slot *slot;
-
-	slot = kmalloc(sizeof(struct slot), GFP_KERNEL);
-	if (!slot)
-		return (NULL);
-	memset(slot, 0, sizeof(struct slot));
-	slot->hotplug_slot = kmalloc(sizeof(struct hotplug_slot),
-		GFP_KERNEL);
-	if (!slot->hotplug_slot) {
-		kfree(slot);
-		return (NULL);
-	}
-	memset(slot->hotplug_slot, 0, sizeof(struct hotplug_slot));
-	slot->hotplug_slot->info = kmalloc(sizeof(struct hotplug_slot_info),
-		GFP_KERNEL);
-	if (!slot->hotplug_slot->info) {
-		kfree(slot->hotplug_slot);
-		kfree(slot);
-		return (NULL);
-	}
-	memset(slot->hotplug_slot->info, 0, sizeof(struct hotplug_slot_info));
-	slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
-	if (!slot->hotplug_slot->name) {
-		kfree(slot->hotplug_slot->info);
-		kfree(slot->hotplug_slot);
-		kfree(slot);
-		return (NULL);
-	}
-	return (slot);
+		return (0);
+	if (strcmp(dn->name, "pci") == 0 &&
+	    !get_property(dn, "ibm,fw-pci-hot-plug-ctrl", NULL))
+		return (0);
+	return (1);
 }
 
-static int setup_hotplug_slot_info(struct slot *slot)
+static inline int is_vdevice_root(struct device_node *dn)
 {
-	rpaphp_get_power_status(slot,
-		&slot->hotplug_slot->info->power_status);
-
-	rpaphp_get_adapter_status(slot, 1,
-		&slot->hotplug_slot->info->adapter_status);
-
-	if (slot->hotplug_slot->info->adapter_status == NOT_VALID) {
-		dbg("%s: NOT_VALID: skip dn->full_name=%s\n",
-			__FUNCTION__, slot->dn->full_name);
-		    kfree(slot->hotplug_slot->info);
-		    kfree(slot->hotplug_slot->name);
-		    kfree(slot->hotplug_slot);
-		    kfree(slot);
-		return (-1);
-	}
-	return (0);
-}
-
-static int register_slot(struct slot *slot)
-{
-	int retval;
-
-	retval = pci_hp_register(slot->hotplug_slot);
-	if (retval) {
-		err("pci_hp_register failed with error %d\n", retval);
-		rpaphp_release_slot(slot->hotplug_slot);
-		return (retval);
-	}
-	/* create symlink between slot->name and it's bus_id */
-	dbg("%s: sysfs_create_link: %s --> %s\n", __FUNCTION__,
-		slot->bridge->slot_name, slot->name);
-	retval = sysfs_create_link(slot->hotplug_slot->kobj.parent,
-			&slot->hotplug_slot->kobj,
-			slot->bridge->slot_name);
-	if (retval) {
-		err("sysfs_create_link failed with error %d\n", retval);
-		rpaphp_release_slot(slot->hotplug_slot);
-		return (retval);
-	}
-	/* add slot to our internal list */
-	dbg("%s adding slot[%s] to rpaphp_slot_list\n",
-		__FUNCTION__, slot->name);
-
-	list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
-
-	info("Slot [%s] (bus_id=%s) registered\n",
-		slot->name, slot->bridge->slot_name);
-	return (0);
+	return !strcmp(dn->name, "vdevice");
 }
 
 /*************************************
  * Add  Hot Plug slot(s) to sysfs
  *
  ************************************/
-int rpaphp_add_slot(char *slot_name)
+int rpaphp_add_slot(struct device_node *dn)
 {
-	struct slot		*slot;
-	int 			retval = 0;
-	int 			i;
-	struct device_node 	*dn;
-	int 			*indexes, *names, *types, *power_domains;
-	char 			*name, *type;
-
-	for (dn = find_all_nodes(); dn; dn = dn->next) {
-
-		if (dn->name != 0 && strcmp(dn->name, "pci") == 0)	{
-			if (!is_php_dn(dn, &indexes, &names, &types, &power_domains))
-				continue;
-
-			dbg("%s : found device_node in OFDT full_name=%s, name=%s\n",
-				__FUNCTION__, dn->full_name, dn->name);
-
-			name = (char *)&names[1];
-			type = (char *)&types[1];
-
-			for (i = 0; i < indexes[0];
-				i++,
-				name += (strlen(name) + 1),
-				type += (strlen(type) + 1)) {
-
-				dbg("%s: name[%s] index[%x]\n",
-					__FUNCTION__, name, indexes[i+1]);
-
-				if (slot_name && strcmp(slot_name, name))
-					continue;
-
-				if (rpaphp_validate_slot(name, indexes[i + 1])) {
-					dbg("%s: slot(%s, 0x%x) is invalid.\n",
-						__FUNCTION__, name, indexes[i+ 1]);
-					continue;
-				}
-
-				slot = alloc_slot_struct();
-				if (!slot) {
-					retval = -ENOMEM;
-					goto exit;
-				}
-
-				slot->name = slot->hotplug_slot->name;
-				slot->index = indexes[i + 1];
-				strcpy(slot->name, name);
-				slot->type = simple_strtoul(type, NULL, 10);
-				if (slot->type < 1  || slot->type > 16)
-					slot->type = 0;
-
-				slot->power_domain = power_domains[i + 1];
-				slot->magic = SLOT_MAGIC;
-				slot->hotplug_slot->private = slot;
-				slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops;
-				slot->hotplug_slot->release = &rpaphp_release_slot;
-				slot->dn = dn;
-
-				/*
-			 	* Initilize the slot info structure with some known
-			 	* good values.
-			 	*/
-				if (setup_hotplug_slot_info(slot))
-					continue;
-
-				slot->bridge = rpaphp_find_bridge_pdev(slot);
-				if (!slot->bridge && slot_name) { /* slot being added doesn't have pci_dev yet*/
-					dbg("%s: no pci_dev for bridge dn %s\n",
-							__FUNCTION__, slot_name);
-					kfree(slot->hotplug_slot->info);
-					kfree(slot->hotplug_slot->name);
-					kfree(slot->hotplug_slot);
-					kfree(slot);
-					continue;
-				}
-
-				/* find slot's pci_dev if it's not empty*/
-				if (slot->hotplug_slot->info->adapter_status == EMPTY) {
-					slot->state = EMPTY;  /* slot is empty */
-					slot->dev = NULL;
-				} else {  /* slot is occupied */
-					if(!(slot->dn->child)) { /* non-empty slot has to have child */
-						err("%s: slot[%s]'s device_node doesn't have child for adapter\n",
-						__FUNCTION__, slot->name);
-						kfree(slot->hotplug_slot->info);
-						kfree(slot->hotplug_slot->name);
-						kfree(slot->hotplug_slot);
-						kfree(slot);
-						continue;
-
-					}
-
-					slot->dev = rpaphp_find_adapter_pdev(slot);
-					if(slot->dev) {
-						slot->state = CONFIGURED;
-						pci_dev_get(slot->dev);
-					} else {
-						/* DLPAR add as opposed to
-						 * boot time */
-						slot->state = NOT_CONFIGURED;
-						}
-				}
-				dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n",
-					__FUNCTION__, dn->full_name, slot->index, slot->name,
-					slot->power_domain, slot->type);
-
-				retval = register_slot(slot);
-				if (retval)
-					goto exit;
-
-				num_slots++;
-
-				if (slot_name)
-					goto exit;
-
-			}/* for indexes */
-		}/* "pci" */
-	}/* find_all_nodes */
-exit:
+	struct slot *slot;
+	int retval = 0;
+	int i;
+	int *indexes, *names, *types, *power_domains;
+	char *name, *type;
+
+	dbg("Entry %s: dn->full_name=%s\n", __FUNCTION__, dn->full_name);
+
+	if (dn->parent && is_vdevice_root(dn->parent)) {
+		/* register a VIO device */
+		retval = register_vio_slot(dn);
+		goto exit;
+	}
+
+	/* register PCI devices */
+	if (dn->name != 0 && strcmp(dn->name, "pci") == 0 &&
+	    is_php_dn(dn, &indexes, &names, &types, &power_domains)) {
+
+		name = (char *) &names[1];
+		type = (char *) &types[1];
+		for (i = 0; i < indexes[0];
+		     i++,
+		     name += (strlen(name) + 1), type += (strlen(type) + 1)) {
+			if (!(slot = alloc_slot_struct(dn, indexes[i + 1], name,
+						       power_domains[i + 1]))) {
+				retval = -ENOMEM;
+				goto exit;
+			}
+			slot->type = simple_strtoul(type, NULL, 10);
+			if (slot->type < 1 || slot->type > 16)
+				slot->type = 0;
+			retval = register_pci_slot(slot);
+
+		}		/* for indexes */
+	}			/* end of PCI device_node */
+      exit:
 	dbg("%s - Exit: num_slots=%d rc[%d]\n",
-		__FUNCTION__, num_slots, retval);
+	    __FUNCTION__, num_slots, retval);
 	return retval;
 }
 
@@ -785,31 +347,28 @@ exit:
  * init_slots - initialize 'struct slot' structures for each slot
  *
  */
-static int init_slots (void)
+static void init_slots(void)
 {
-	int 			retval = 0;
+	struct device_node *dn;
 
-	retval = rpaphp_add_slot(NULL);
-
-	return retval;
+	for (dn = find_all_nodes(); dn; dn = dn->next)
+		rpaphp_add_slot(dn);
 }
 
-
-static int init_rpa (void)
+static int init_rpa(void)
 {
-	int 			retval = 0;
 
 	init_MUTEX(&rpaphp_sem);
 
 	/* initialize internal data structure etc. */
-	retval = init_slots();
+	init_slots();
 	if (!num_slots)
-		retval = -ENODEV;
+		return -ENODEV;
 
-	return retval;
+	return 0;
 }
 
-static void cleanup_slots (void)
+static void cleanup_slots(void)
 {
 	struct list_head *tmp, *n;
 	struct slot *slot;
@@ -817,125 +376,100 @@ static void cleanup_slots (void)
 	/*
 	 * Unregister all of our slots with the pci_hotplug subsystem,
 	 * and free up all memory that we had allocated.
-	 * memory will be freed in release_slot callback.
+	 * memory will be freed in release_slot callback. 
 	 */
 
-	list_for_each_safe (tmp, n, &rpaphp_slot_head) {
+	list_for_each_safe(tmp, n, &rpaphp_slot_head) {
+		char *rm_link;
+
 		slot = list_entry(tmp, struct slot, rpaphp_slot_list);
-		sysfs_remove_link(slot->hotplug_slot->kobj.parent,
-			slot->bridge->slot_name);
+		if (slot->dev_type == PCI_DEV)
+			rm_link = pci_name(slot->bridge);
+		else
+			rm_link = strstr(slot->dn->full_name, "@");
+		sysfs_remove_link(slot->hotplug_slot->kobj.parent, rm_link);
 		list_del(&slot->rpaphp_slot_list);
 		pci_hp_deregister(slot->hotplug_slot);
 	}
-
 	return;
 }
 
-
 static int __init rpaphp_init(void)
 {
-	int retval = 0;
-
 	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
 
 	/* read all the PRA info from the system */
-	retval = init_rpa();
-
-	return retval;
+	return init_rpa();
 }
 
-
 static void __exit rpaphp_exit(void)
 {
 	cleanup_slots();
 }
 
-
 static int enable_slot(struct hotplug_slot *hotplug_slot)
 {
-	int retval = 0, state;
-
+	int retval = 0;
 	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 
 	if (slot == NULL)
 		return -ENODEV;
 
 	if (slot->state == CONFIGURED) {
-		dbg("%s: %s is already enabled\n",
-			__FUNCTION__, slot->name);
+		dbg("%s: %s is already enabled\n", __FUNCTION__, slot->name);
 		goto exit;
 	}
 
 	dbg("ENABLING SLOT %s\n", slot->name);
-
 	down(&rpaphp_sem);
-
-	retval = rpaphp_get_sensor_state(slot->index, &state);
-
-	if (retval)
-		goto exit;
-
-	dbg("%s: sensor state[%d]\n", __FUNCTION__, state);
-
-	/* if slot is not empty, enable the adapter */
-	if (state == PRESENT) {
-		dbg("%s : slot[%s] is occupid.\n", __FUNCTION__, slot->name);
-
-		
-		slot->dev = rpaphp_config_adapter(slot);
-		if (slot->dev != NULL) {
-			slot->state = CONFIGURED;
-
-			dbg("%s: adapter %s in slot[%s] has been configured\n",
-				__FUNCTION__, slot->dev->slot_name,
-				slot->name);
-		} else {
-			slot->state = NOT_CONFIGURED;
-
-			dbg("%s: no pci_dev struct for adapter in slot[%s]\n",
-				__FUNCTION__, slot->name);
-		}
-
-	} else if (state == EMPTY) {
-		dbg("%s : slot[%s] is empty\n", __FUNCTION__, slot->name);
-		slot->state = EMPTY;
-	} else {
-		err("%s: slot[%s] is in invalid state\n", __FUNCTION__, slot->name);
-		slot->state = NOT_VALID;
+	switch (slot->dev_type) {
+	case PCI_DEV:
+		retval = rpaphp_enable_pci_slot(slot);
+		break;
+	case VIO_DEV:
+		retval = rpaphp_enable_vio_slot(slot);
+		break;
+	default:
 		retval = -EINVAL;
 	}
-
-exit:
-	if (slot->state != NOT_VALID)
-		rpaphp_set_attention_status(slot, LED_ON);
-	else
-		rpaphp_set_attention_status(slot, LED_ID);
-
 	up(&rpaphp_sem);
-
+      exit:
+	dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
 	return retval;
 }
 
 static int disable_slot(struct hotplug_slot *hotplug_slot)
 {
-	int	retval;
+	int retval;
 	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 
 	if (slot == NULL)
 		return -ENODEV;
 
-	dbg("DISABLING SLOT %s\n", slot->name);
-
-	down(&rpaphp_sem);
-
-	rpaphp_set_attention_status(slot, LED_ID);
+	dbg("%s - Entry: slot[%s]\n", __FUNCTION__, slot->name);
 
-	retval = rpaphp_unconfig_adapter(slot);
-
-	rpaphp_set_attention_status(slot, LED_OFF);
+	if (slot->state == NOT_CONFIGURED) {
+		dbg("%s: %s is already disabled\n", __FUNCTION__, slot->name);
+		goto exit;
+	}
 
+	dbg("DISABLING SLOT %s\n", slot->name);
+	down(&rpaphp_sem);
+	switch (slot->dev_type) {
+	case PCI_DEV:
+		rpaphp_set_attention_status(slot, LED_ID);
+		retval = rpaphp_unconfig_pci_adapter(slot);
+		rpaphp_set_attention_status(slot, LED_OFF);
+		break;
+	case VIO_DEV:
+		retval = rpaphp_unconfig_vio_adapter(slot);
+		break;
+	default:
+		retval = -ENODEV;
+	}
 	up(&rpaphp_sem);
-
+      exit:
+	dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
 	return retval;
 }
 
--- diff/drivers/pci/hotplug/rpaphp_pci.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/pci/hotplug/rpaphp_pci.c	2004-03-16 09:37:56.406965008 +0000
@@ -23,32 +23,35 @@
  *
  */
 #include <linux/pci.h>
-#include <asm/pci-bridge.h>	/* for pci_controller */
-#include "rpaphp.h"
+#include <asm/pci-bridge.h>
+#include "../pci.h"		/* for pci_add_new_bus */
 
+#include "rpaphp.h"
 
 struct pci_dev *rpaphp_find_pci_dev(struct device_node *dn)
 {
-	struct pci_dev		*retval_dev = NULL, *dev = NULL;
-
-	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-		if(!dev->bus)
-			continue;
+	struct pci_dev *retval_dev = NULL, *dev = NULL;
+	char bus_id[BUS_ID_SIZE];
 
-		if (dev->devfn != dn->devfn)
-			continue;
+	sprintf(bus_id, "%04x:%02x:%02x.%d",dn->phb->global_number,
+		dn->busno, PCI_SLOT(dn->devfn), PCI_FUNC(dn->devfn));
 
-		if (dn->phb->global_number == pci_domain_nr(dev->bus) &&
-		    dn->busno == dev->bus->number) {
+	dbg("Enter rpaphp_find_pci_dev() full_name=%s bus_id=%s\n", 
+		dn->full_name, bus_id);
+	
+	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+               if (!strcmp(pci_name(dev), bus_id)) {
 			retval_dev = dev;
+			dbg("rpaphp_find_pci_dev(): found dev=%p\n\n", dev);
 			break;
 		}
 	}
-
 	return retval_dev;
 
 }
 
+EXPORT_SYMBOL_GPL(rpaphp_find_pci_dev);
+
 int rpaphp_claim_resource(struct pci_dev *dev, int resource)
 {
 	struct resource *res = &dev->resource[resource];
@@ -63,13 +66,333 @@ int rpaphp_claim_resource(struct pci_dev
 
 	if (err) {
 		err("PCI: %s region %d of %s %s [%lx:%lx]\n",
-			root ? "Address space collision on" :
-			"No parent found for",
-			resource, dtype, pci_name(dev), res->start, res->end);
+		    root ? "Address space collision on" :
+		    "No parent found for",
+		    resource, dtype, pci_name(dev), res->start, res->end);
 	}
-
 	return err;
 }
 
-EXPORT_SYMBOL_GPL(rpaphp_find_pci_dev);
 EXPORT_SYMBOL_GPL(rpaphp_claim_resource);
+
+static struct pci_dev *rpaphp_find_bridge_pdev(struct slot *slot)
+{
+	return rpaphp_find_pci_dev(slot->dn);
+}
+
+static struct pci_dev *rpaphp_find_adapter_pdev(struct slot *slot)
+{
+	return rpaphp_find_pci_dev(slot->dn->child);
+}
+
+static int rpaphp_get_sensor_state(struct slot *slot, int *state)
+{
+	int rc;
+	int setlevel;
+
+	rc = rtas_get_sensor(DR_ENTITY_SENSE, slot->index, state);
+
+	if (rc) {
+		if (rc == NEED_POWER || rc == PWR_ONLY) {
+			dbg("%s: slot must be power up to get sensor-state\n",
+			    __FUNCTION__);
+
+			/* some slots have to be powered up 
+			 * before get-sensor will succeed.
+			 */
+			rc = rtas_set_power_level(slot->power_domain, POWER_ON,
+						  &setlevel);
+			if (rc) {
+				dbg("%s: power on slot[%s] failed rc=%d.\n",
+				    __FUNCTION__, slot->name, rc);
+			} else {
+				rc = rtas_get_sensor(DR_ENTITY_SENSE,
+						     slot->index, state);
+			}
+		} else if (rc == ERR_SENSE_USE)
+			info("%s: slot is unusable\n", __FUNCTION__);
+		else
+			err("%s failed to get sensor state\n", __FUNCTION__);
+	}
+	return rc;
+}
+
+/*
+ * get_pci_adapter_status - get  the status of a slot
+ * 
+ * 0-- slot is empty
+ * 1-- adapter is configured
+ * 2-- adapter is not configured
+ * 3-- not valid
+ */
+int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value)
+{
+	int state, rc;
+	*value = NOT_VALID;
+
+	rc = rpaphp_get_sensor_state(slot, &state);
+	if (rc)
+		goto exit;
+	if (state == PRESENT) {
+		if (!is_init)
+			/* at run-time slot->state can be changed by */
+			/* config/unconfig adapter                        */
+			*value = slot->state;
+		else {
+			if (!slot->dn->child)
+				dbg("%s: %s is not valid OFDT node\n",
+				    __FUNCTION__, slot->dn->full_name);
+			else if (rpaphp_find_pci_dev(slot->dn->child))
+				*value = CONFIGURED;
+			else {
+				dbg("%s: can't find pdev of adapter in slot[%s]\n", __FUNCTION__, slot->name);
+				*value = NOT_CONFIGURED;
+			}
+		}
+	} else if (state == EMPTY) {
+		dbg("slot is empty\n");
+		*value = state;
+	}
+
+      exit:
+	return rc;
+}
+
+/* Must be called before pci_bus_add_devices */
+static void rpaphp_fixup_new_pci_devices(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		/*
+		 * Skip already-present devices (which are on the
+		 * global device list.)
+		 */
+		if (list_empty(&dev->global_list)) {
+			int i;
+
+			pcibios_fixup_device_resources(dev, bus);
+			pci_read_irq_line(dev);
+			for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+				struct resource *r = &dev->resource[i];
+				if (r->parent || !r->start || !r->flags)
+					continue;
+				rpaphp_claim_resource(dev, i);
+			}
+		}
+	}
+}
+
+static void rpaphp_pci_config_device(struct pci_bus *pci_bus, struct device_node *dn)
+{
+	int num;
+
+	num = pci_scan_slot(pci_bus, PCI_DEVFN(PCI_SLOT(dn->devfn), 0));
+	if (num) {
+		rpaphp_fixup_new_pci_devices(pci_bus);
+		pci_bus_add_devices(pci_bus);
+	}
+	return;
+}
+
+static int rpaphp_pci_config_bridge(struct pci_dev *dev, struct device_node *dn);
+
+/*****************************************************************************
+ rpaphp_pci_config_dn() will recursively configure all devices under the 
+ given slot->dn and return the dn's pci_dev.
+ *****************************************************************************/
+static struct pci_dev *rpaphp_pci_config_dn(struct device_node *dn, struct pci_bus *bus)
+{
+	struct device_node *local;
+	struct pci_dev *dev;
+
+	for (local = dn->child; local; local = local->sibling) {
+		rpaphp_pci_config_device(bus, local);
+		dev = rpaphp_find_pci_dev(local);
+		if (!rpaphp_pci_config_bridge(dev, local))
+			return NULL;
+	}
+
+	return dev;
+}
+
+static int rpaphp_pci_config_bridge(struct pci_dev *dev, struct device_node *dn)
+{
+	if (dev && dn->child) {	/* dn is a PCI bridge node */
+		struct pci_bus *child;
+		u8 sec_busno;
+
+		/* get busno of downstream bus */
+		pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno);
+
+		/* add to children of PCI bridge dev->bus */
+		child = pci_add_new_bus(dev->bus, dev, sec_busno);
+		if (!child) {
+			err("%s: could not add second bus\n", __FUNCTION__);
+			return 0;
+		}
+		sprintf(child->name, "PCI Bus #%02x", child->number);
+		/* Fixup subordinate bridge bases and resureces */
+		pcibios_fixup_bus(child);
+
+		/* may need do more stuff here */
+		rpaphp_pci_config_dn(dn, dev->subordinate);
+	}
+	return 1;
+}
+
+static struct pci_dev *rpaphp_config_pci_adapter(struct slot *slot)
+{
+	struct pci_bus *pci_bus;
+	struct pci_dev *dev = NULL;
+
+	dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name);
+
+	if (slot->bridge) {
+
+		pci_bus = slot->bridge->subordinate;
+		if (!pci_bus) {
+			err("%s: can't find bus structure\n", __FUNCTION__);
+			goto exit;
+		}
+
+		dev = rpaphp_pci_config_dn(slot->dn, pci_bus);
+	} else {
+		/* slot is not enabled */
+		err("slot doesn't have pci_dev structure\n");
+		dev = NULL;
+		goto exit;
+	}
+
+      exit:
+	dbg("Exit %s: pci_dev %s\n", __FUNCTION__, dev ? "found" : "not found");
+	return dev;
+}
+
+int rpaphp_unconfig_pci_adapter(struct slot *slot)
+{
+	int retval = 0;
+
+	dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name);
+	if (!slot->dev.pci_dev) {
+		info("%s: no card in slot[%s]\n", __FUNCTION__, slot->name);
+
+		retval = -EINVAL;
+		goto exit;
+	}
+	/* remove the device from the pci core */
+	pci_remove_bus_device(slot->dev.pci_dev);
+
+	slot->state = NOT_CONFIGURED;
+	info("%s: adapter in slot[%s] unconfigured.\n", __FUNCTION__,
+	     slot->name);
+exit:
+	dbg("Exit %s, rc=0x%x\n", __FUNCTION__, retval);
+	return retval;
+}
+
+static int setup_pci_hotplug_slot_info(struct slot *slot)
+{
+	dbg("%s Initilize the PCI slot's hotplug->info structure ...\n",
+	    __FUNCTION__);
+	rpaphp_get_power_status(slot, &slot->hotplug_slot->info->power_status);
+	rpaphp_get_pci_adapter_status(slot, 1,
+				      &slot->hotplug_slot->info->
+				      adapter_status);
+	if (slot->hotplug_slot->info->adapter_status == NOT_VALID) {
+		dbg("%s: NOT_VALID: skip dn->full_name=%s\n",
+		    __FUNCTION__, slot->dn->full_name);
+		dealloc_slot_struct(slot);
+		return (-1);
+	}
+	return (0);
+}
+
+static int setup_pci_slot(struct slot *slot)
+{
+	slot->bridge = rpaphp_find_bridge_pdev(slot);
+	if (!slot->bridge) {	/* slot being added doesn't have pci_dev yet */
+		dbg("%s: no pci_dev for bridge dn %s\n", __FUNCTION__, slot->name);
+		dealloc_slot_struct(slot);
+		return 1;
+	}
+
+	/* find slot's pci_dev if it's not empty */
+	if (slot->hotplug_slot->info->adapter_status == EMPTY) {
+		slot->state = EMPTY;	/* slot is empty */
+		slot->dev.pci_dev = NULL;
+	} else {
+		/* slot is occupied */
+		if (!(slot->dn->child)) {
+			/* non-empty slot has to have child */
+			err("%s: slot[%s]'s device_node doesn't have child for adapter\n", __FUNCTION__, slot->name);
+			dealloc_slot_struct(slot);
+			return 1;
+		}
+		slot->dev.pci_dev = rpaphp_find_adapter_pdev(slot);
+		if (slot->dev.pci_dev) {
+			slot->state = CONFIGURED;
+		
+		} else {
+			/* DLPAR add as opposed to 
+			 * boot time */
+			slot->state = NOT_CONFIGURED;
+		}
+	}
+	return 0;
+}
+
+int register_pci_slot(struct slot *slot)
+{
+	int rc = 1;
+
+	slot->dev_type = PCI_DEV;
+	if (setup_pci_hotplug_slot_info(slot))
+		goto exit_rc;
+	if (setup_pci_slot(slot))
+		goto exit_rc;
+	rc = register_slot(slot);
+      exit_rc:
+	if (rc)
+		dealloc_slot_struct(slot);
+	return rc;
+}
+
+int rpaphp_enable_pci_slot(struct slot *slot)
+{
+	int retval = 0, state;
+
+	retval = rpaphp_get_sensor_state(slot, &state);
+	if (retval)
+		goto exit;
+	dbg("%s: sensor state[%d]\n", __FUNCTION__, state);
+	/* if slot is not empty, enable the adapter */
+	if (state == PRESENT) {
+		dbg("%s : slot[%s] is occupid.\n", __FUNCTION__, slot->name);
+		if ((slot->dev.pci_dev =
+		     rpaphp_config_pci_adapter(slot)) != NULL) {
+			slot->state = CONFIGURED;
+			dbg("%s: PCI adapter %s in slot[%s] has been configured\n", 
+				__FUNCTION__, pci_name(slot->dev.pci_dev), slot->name);
+		} else {
+			slot->state = NOT_CONFIGURED;
+			dbg("%s: no pci_dev struct for adapter in slot[%s]\n",
+			    __FUNCTION__, slot->name);
+		}
+	} else if (state == EMPTY) {
+		dbg("%s : slot[%s] is empty\n", __FUNCTION__, slot->name);
+		slot->state = EMPTY;
+	} else {
+		err("%s: slot[%s] is in invalid state\n", __FUNCTION__,
+		    slot->name);
+		slot->state = NOT_VALID;
+		retval = -EINVAL;
+	}
+      exit:
+	if (slot->state != NOT_VALID)
+		rpaphp_set_attention_status(slot, LED_ON);
+	else
+		rpaphp_set_attention_status(slot, LED_ID);
+	dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
+	return retval;
+}
--- diff/drivers/pci/hotplug/shpchp_pci.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/pci/hotplug/shpchp_pci.c	2004-03-16 09:37:56.406965008 +0000
@@ -101,7 +101,7 @@ int shpchp_unconfigure_device(struct pci
  */
 int shpchp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
 {
-#if !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64)
+#if defined(CONFIG_X86) && !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64)
 	int rc;
 	u16 temp_word;
 	struct pci_dev fakedev;
--- diff/drivers/pci/pci.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/pci/pci.c	2004-03-16 09:37:56.407964856 +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/probe.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/pci/probe.c	2004-03-16 09:37:56.408964704 +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/pci/quirks.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/pci/quirks.c	2004-03-16 09:37:56.409964552 +0000
@@ -760,7 +760,7 @@ static int __devinitdata sis_96x_compati
 
 #define SIS_DETECT_REGISTER 0x40
 
-static void __init quirk_sis_503_smbus(struct pci_dev *dev)
+static void __init quirk_sis_503(struct pci_dev *dev)
 {
 	u8 reg;
 	u16 devid;
@@ -768,7 +768,7 @@ static void __init quirk_sis_503_smbus(s
 	pci_read_config_byte(dev, SIS_DETECT_REGISTER, &reg);
 	pci_write_config_byte(dev, SIS_DETECT_REGISTER, reg | (1 << 6));
 	pci_read_config_word(dev, PCI_DEVICE_ID, &devid);
-	if ((devid & 0xfff0) != 0x0960) {
+	if (((devid & 0xfff0) != 0x0960) && (devid != 0x0018)) {
 		pci_write_config_byte(dev, SIS_DETECT_REGISTER, reg);
 		return;
 	}
@@ -905,12 +905,14 @@ static struct pci_fixup pci_fixups[] __d
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443BX_2, 	quirk_natoma },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		quirk_nopcipci },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_496,		quirk_nopcipci },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_503,		quirk_sis_503_smbus },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_503,		quirk_sis_503 },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_LPC,		quirk_sis_96x_smbus },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_645,		quirk_sis_96x_compatible },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_646,		quirk_sis_96x_compatible },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_648,		quirk_sis_96x_compatible },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_650,		quirk_sis_96x_compatible },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_651,		quirk_sis_96x_compatible },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_735,		quirk_sis_96x_compatible },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_961,		quirk_sis_96x_smbus },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_962,		quirk_sis_96x_smbus },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_963,		quirk_sis_96x_smbus },
--- diff/drivers/pcmcia/Kconfig	2003-09-30 14:46:16.000000000 +0000
+++ source/drivers/pcmcia/Kconfig	2004-03-16 09:37:56.409964552 +0000
@@ -26,6 +26,25 @@ config PCMCIA
 	  To compile this driver as modules, choose M here: the
 	  modules will be called pcmcia_core and ds.
 
+config PCMCIA_DEBUG
+	bool "Enable PCMCIA debugging"
+	depends on PCMCIA != n
+	help
+	  Say Y here to enable PCMCIA subsystem debugging.  You
+	  will need to choose the debugging level either via the
+	  kernel command line, or module options depending whether
+	  you build the PCMCIA as modules.
+
+	  The kernel command line options are:
+	    pcmcia_core.pc_debug=N
+	    ds.pc_debug=N
+	    sa11xx_core.pc_debug=N
+
+	  The module option is called pc_debug=N
+
+	  In all the above examples, N is the debugging verbosity
+	  level.
+
 config YENTA
 	tristate "CardBus yenta-compatible bridge support"
 	depends on PCMCIA && PCI
--- diff/drivers/pcmcia/Makefile	2003-06-30 09:07:33.000000000 +0000
+++ source/drivers/pcmcia/Makefile	2004-03-16 09:37:56.409964552 +0000
@@ -2,6 +2,10 @@
 # Makefile for the kernel pcmcia subsystem (c/o David Hinds)
 #
 
+ifeq ($(CONFIG_PCMCIA_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
 obj-$(CONFIG_PCMCIA)				+= pcmcia_core.o ds.o
 obj-$(CONFIG_YENTA) 				+= yenta_socket.o
 
--- diff/drivers/pcmcia/au1000_generic.c	2003-10-09 08:47:34.000000000 +0000
+++ source/drivers/pcmcia/au1000_generic.c	2004-03-16 09:37:56.411964248 +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 08:47:34.000000000 +0000
+++ source/drivers/pcmcia/au1000_pb1x00.c	2004-03-16 09:37:56.412964096 +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-16 09:37:56.413963944 +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 14:46:16.000000000 +0000
+++ source/drivers/pcmcia/cardbus.c	2004-03-16 09:37:56.414963792 +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-16 09:37:56.415963640 +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-16 09:37:56.419963032 +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 = {
@@ -127,103 +133,6 @@ socket_state_t dead_socket = {
 LIST_HEAD(pcmcia_socket_list);
 DECLARE_RWSEM(pcmcia_socket_list_rwsem);
 
-/*====================================================================*/
-
-/* String tables for error messages */
-
-typedef struct lookup_t {
-    int key;
-    char *msg;
-} lookup_t;
-
-static const lookup_t error_table[] = {
-    { CS_SUCCESS,		"Operation succeeded" },
-    { CS_BAD_ADAPTER,		"Bad adapter" },
-    { CS_BAD_ATTRIBUTE, 	"Bad attribute", },
-    { CS_BAD_BASE,		"Bad base address" },
-    { CS_BAD_EDC,		"Bad EDC" },
-    { CS_BAD_IRQ,		"Bad IRQ" },
-    { CS_BAD_OFFSET,		"Bad offset" },
-    { CS_BAD_PAGE,		"Bad page number" },
-    { CS_READ_FAILURE,		"Read failure" },
-    { CS_BAD_SIZE,		"Bad size" },
-    { CS_BAD_SOCKET,		"Bad socket" },
-    { CS_BAD_TYPE,		"Bad type" },
-    { CS_BAD_VCC,		"Bad Vcc" },
-    { CS_BAD_VPP,		"Bad Vpp" },
-    { CS_BAD_WINDOW,		"Bad window" },
-    { CS_WRITE_FAILURE,		"Write failure" },
-    { CS_NO_CARD,		"No card present" },
-    { CS_UNSUPPORTED_FUNCTION,	"Usupported function" },
-    { CS_UNSUPPORTED_MODE,	"Unsupported mode" },
-    { CS_BAD_SPEED,		"Bad speed" },
-    { CS_BUSY,			"Resource busy" },
-    { CS_GENERAL_FAILURE,	"General failure" },
-    { CS_WRITE_PROTECTED,	"Write protected" },
-    { CS_BAD_ARG_LENGTH,	"Bad argument length" },
-    { CS_BAD_ARGS,		"Bad arguments" },
-    { CS_CONFIGURATION_LOCKED,	"Configuration locked" },
-    { CS_IN_USE,		"Resource in use" },
-    { CS_NO_MORE_ITEMS,		"No more items" },
-    { CS_OUT_OF_RESOURCE,	"Out of resource" },
-    { CS_BAD_HANDLE,		"Bad handle" },
-    { CS_BAD_TUPLE,		"Bad CIS tuple" }
-};
-#define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t))
-
-static const lookup_t service_table[] = {
-    { AccessConfigurationRegister,	"AccessConfigurationRegister" },
-    { AddSocketServices,		"AddSocketServices" },
-    { AdjustResourceInfo,		"AdjustResourceInfo" },
-    { CheckEraseQueue,			"CheckEraseQueue" },
-    { CloseMemory,			"CloseMemory" },
-    { DeregisterClient,			"DeregisterClient" },
-    { DeregisterEraseQueue,		"DeregisterEraseQueue" },
-    { GetCardServicesInfo,		"GetCardServicesInfo" },
-    { GetClientInfo,			"GetClientInfo" },
-    { GetConfigurationInfo,		"GetConfigurationInfo" },
-    { GetEventMask,			"GetEventMask" },
-    { GetFirstClient,			"GetFirstClient" },
-    { GetFirstRegion,			"GetFirstRegion" },
-    { GetFirstTuple,			"GetFirstTuple" },
-    { GetNextClient,			"GetNextClient" },
-    { GetNextRegion,			"GetNextRegion" },
-    { GetNextTuple,			"GetNextTuple" },
-    { GetStatus,			"GetStatus" },
-    { GetTupleData,			"GetTupleData" },
-    { MapMemPage,			"MapMemPage" },
-    { ModifyConfiguration,		"ModifyConfiguration" },
-    { ModifyWindow,			"ModifyWindow" },
-    { OpenMemory,			"OpenMemory" },
-    { ParseTuple,			"ParseTuple" },
-    { ReadMemory,			"ReadMemory" },
-    { RegisterClient,			"RegisterClient" },
-    { RegisterEraseQueue,		"RegisterEraseQueue" },
-    { RegisterMTD,			"RegisterMTD" },
-    { ReleaseConfiguration,		"ReleaseConfiguration" },
-    { ReleaseIO,			"ReleaseIO" },
-    { ReleaseIRQ,			"ReleaseIRQ" },
-    { ReleaseWindow,			"ReleaseWindow" },
-    { RequestConfiguration,		"RequestConfiguration" },
-    { RequestIO,			"RequestIO" },
-    { RequestIRQ,			"RequestIRQ" },
-    { RequestSocketMask,		"RequestSocketMask" },
-    { RequestWindow,			"RequestWindow" },
-    { ResetCard,			"ResetCard" },
-    { SetEventMask,			"SetEventMask" },
-    { ValidateCIS,			"ValidateCIS" },
-    { WriteMemory,			"WriteMemory" },
-    { BindDevice,			"BindDevice" },
-    { BindMTD,				"BindMTD" },
-    { ReportError,			"ReportError" },
-    { SuspendCard,			"SuspendCard" },
-    { ResumeCard,			"ResumeCard" },
-    { EjectCard,			"EjectCard" },
-    { InsertCard,			"InsertCard" },
-    { ReplaceCIS,			"ReplaceCIS" }
-};
-#define SERVICE_COUNT (sizeof(service_table)/sizeof(lookup_t))
-
 
 /*====================================================================
 
@@ -306,7 +215,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 +286,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,10 +352,9 @@ 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;
     s->socket = dead_socket;
     s->ops->init(s);
     s->ops->set_socket(s, &s->socket);
@@ -499,8 +407,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 +424,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,10 +441,13 @@ static void socket_remove_drivers(struct
 
 static void socket_shutdown(struct pcmcia_socket *skt)
 {
+	cs_dbg(skt, 4, "shutdown\n");
+
 	socket_remove_drivers(skt);
+	skt->state &= SOCKET_INUSE|SOCKET_PRESENT;
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(cs_to_timeout(shutdown_delay));
-	skt->state &= ~SOCKET_PRESENT;
+	skt->state &= SOCKET_INUSE;
 	shutdown_socket(skt);
 }
 
@@ -556,6 +455,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 +479,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 +487,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 +509,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 +529,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 +543,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 +558,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 +572,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 +739,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 +765,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) {
@@ -979,77 +887,6 @@ int pcmcia_access_configuration_register
     return CS_SUCCESS;
 } /* access_configuration_register */
 
-/*======================================================================
-
-    Bind_device() associates a device driver with a particular socket.
-    It is normally called by Driver Services after it has identified
-    a newly inserted card.  An instance of that driver will then be
-    eligible to register as a client of this socket.
-    
-======================================================================*/
-
-int pcmcia_bind_device(bind_req_t *req)
-{
-    client_t *client;
-    struct pcmcia_socket *s;
-
-    s = req->Socket;
-    if (!s)
-	    return CS_BAD_SOCKET;
-
-    client = (client_t *)kmalloc(sizeof(client_t), GFP_KERNEL);
-    if (!client) return CS_OUT_OF_RESOURCE;
-    memset(client, '\0', sizeof(client_t));
-    client->client_magic = CLIENT_MAGIC;
-    strlcpy(client->dev_info, (char *)req->dev_info, DEV_NAME_LEN);
-    client->Socket = s;
-    client->Function = req->Function;
-    client->state = CLIENT_UNBOUND;
-    client->erase_busy.next = &client->erase_busy;
-    client->erase_busy.prev = &client->erase_busy;
-    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);
-    return CS_SUCCESS;
-} /* bind_device */
-
-/*======================================================================
-
-    Bind_mtd() associates a device driver with a particular memory
-    region.  It is normally called by Driver Services after it has
-    identified a memory device type.  An instance of the corresponding
-    driver will then be able to register to control this region.
-    
-======================================================================*/
-
-int pcmcia_bind_mtd(mtd_bind_t *req)
-{
-    struct pcmcia_socket *s;
-    memory_handle_t region;
-    
-    s = req->Socket;
-    if (!s)
-	    return CS_BAD_SOCKET;
-    
-    if (req->Attributes & REGION_TYPE_AM)
-	region = s->a_region;
-    else
-	region = s->c_region;
-    
-    while (region) {
-	if (region->info.CardOffset == req->CardOffset) break;
-	region = region->info.next;
-    }
-    if (!region || (region->mtd != NULL))
-	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);
-    return CS_SUCCESS;
-} /* bind_mtd */
 
 /*====================================================================*/
 
@@ -1061,9 +898,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 +912,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 +1382,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 +1916,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 {
@@ -2119,15 +1958,11 @@ int pcmcia_reset_card(client_handle_t ha
     
 ======================================================================*/
 
-int pcmcia_suspend_card(client_handle_t handle, client_req_t *req)
+int pcmcia_suspend_card(struct pcmcia_socket *skt)
 {
-	struct pcmcia_socket *skt;
 	int ret;
     
-	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 {
@@ -2146,15 +1981,11 @@ int pcmcia_suspend_card(client_handle_t 
 	return ret;
 } /* suspend_card */
 
-int pcmcia_resume_card(client_handle_t handle, client_req_t *req)
+int pcmcia_resume_card(struct pcmcia_socket *skt)
 {
-	struct pcmcia_socket *skt;
 	int ret;
     
-	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 {
@@ -2179,15 +2010,11 @@ int pcmcia_resume_card(client_handle_t h
     
 ======================================================================*/
 
-int pcmcia_eject_card(client_handle_t handle, client_req_t *req)
+int pcmcia_eject_card(struct pcmcia_socket *skt)
 {
-	struct pcmcia_socket *skt;
 	int ret;
     
-	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 {
@@ -2208,15 +2035,11 @@ int pcmcia_eject_card(client_handle_t ha
 	return ret;
 } /* eject_card */
 
-int pcmcia_insert_card(client_handle_t handle, client_req_t *req)
+int pcmcia_insert_card(struct pcmcia_socket *skt)
 {
-	struct pcmcia_socket *skt;
 	int ret;
 
-	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 {
@@ -2260,35 +2083,6 @@ int pcmcia_set_event_mask(client_handle_
     return CS_SUCCESS;
 } /* set_event_mask */
 
-/*====================================================================*/
-
-int pcmcia_report_error(client_handle_t handle, error_info_t *err)
-{
-    int i;
-    char *serv;
-
-    if (CHECK_HANDLE(handle))
-	printk(KERN_NOTICE);
-    else
-	printk(KERN_NOTICE "%s: ", handle->dev_info);
-    
-    for (i = 0; i < SERVICE_COUNT; i++)
-	if (service_table[i].key == err->func) break;
-    if (i < SERVICE_COUNT)
-	serv = service_table[i].msg;
-    else
-	serv = "Unknown service number";
-
-    for (i = 0; i < ERROR_COUNT; i++)
-	if (error_table[i].key == err->retcode) break;
-    if (i < ERROR_COUNT)
-	printk("%s: %s\n", serv, error_table[i].msg);
-    else
-	printk("%s: Unknown error code %#x\n", serv, err->retcode);
-
-    return CS_SUCCESS;
-} /* report_error */
-
 /*======================================================================
 
     OS-specific module glue goes here
@@ -2297,8 +2091,6 @@ int pcmcia_report_error(client_handle_t 
 /* in alpha order */
 EXPORT_SYMBOL(pcmcia_access_configuration_register);
 EXPORT_SYMBOL(pcmcia_adjust_resource_info);
-EXPORT_SYMBOL(pcmcia_bind_device);
-EXPORT_SYMBOL(pcmcia_bind_mtd);
 EXPORT_SYMBOL(pcmcia_check_erase_queue);
 EXPORT_SYMBOL(pcmcia_close_memory);
 EXPORT_SYMBOL(pcmcia_copy_memory);
@@ -2333,7 +2125,6 @@ EXPORT_SYMBOL(pcmcia_release_io);
 EXPORT_SYMBOL(pcmcia_release_irq);
 EXPORT_SYMBOL(pcmcia_release_window);
 EXPORT_SYMBOL(pcmcia_replace_cis);
-EXPORT_SYMBOL(pcmcia_report_error);
 EXPORT_SYMBOL(pcmcia_request_configuration);
 EXPORT_SYMBOL(pcmcia_request_io);
 EXPORT_SYMBOL(pcmcia_request_irq);
@@ -2360,7 +2151,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 14:46:16.000000000 +0000
+++ source/drivers/pcmcia/cs_internal.h	2004-03-16 09:37:56.420962880 +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);
@@ -194,11 +193,22 @@ void release_resource_db(void);
 extern struct rw_semaphore pcmcia_socket_list_rwsem;
 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)
+#define cs_socket_name(skt)	((skt)->dev.class_id)
+
+#ifdef DEBUG
+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, 	\
+		       cs_socket_name(skt) , ## 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-16 09:37:56.428961664 +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>
@@ -53,6 +54,7 @@
 
 #include <asm/atomic.h>
 
+#define IN_CARD_SERVICES
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
@@ -61,6 +63,8 @@
 #include <pcmcia/ds.h>
 #include <pcmcia/ss.h>
 
+#include "cs_internal.h"
+
 /*====================================================================*/
 
 /* Module parameters */
@@ -69,13 +73,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;
+
+module_param(pc_debug, int, 0644);
 
-#ifdef PCMCIA_DEBUG
-INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+#define ds_dbg(lvl, fmt, arg...) do {				\
+	if (pc_debug > (lvl))					\
+		printk(KERN_DEBUG "ds: " fmt , ## arg);		\
+} while (0)
 #else
-#define DEBUG(n, args...)
+#define ds_dbg(lvl, fmt, arg...) do { } while (0)
 #endif
 
 /*====================================================================*/
@@ -113,10 +121,10 @@ struct pcmcia_bus_socket {
 	struct pcmcia_socket	*parent;
 };
 
-#define SOCKET_PRESENT		0x01
-#define SOCKET_BUSY		0x02
-#define SOCKET_REMOVAL_PENDING	0x10
-#define SOCKET_DEAD		0x80
+#define DS_SOCKET_PRESENT		0x01
+#define DS_SOCKET_BUSY			0x02
+#define DS_SOCKET_REMOVAL_PENDING	0x10
+#define DS_SOCKET_DEAD			0x80
 
 /*====================================================================*/
 
@@ -129,6 +137,214 @@ extern struct proc_dir_entry *proc_pccar
 
 /*====================================================================*/
 
+/* code which was in cs.c before */
+
+/*======================================================================
+
+    Bind_device() associates a device driver with a particular socket.
+    It is normally called by Driver Services after it has identified
+    a newly inserted card.  An instance of that driver will then be
+    eligible to register as a client of this socket.
+    
+======================================================================*/
+
+static int pcmcia_bind_device(bind_req_t *req)
+{
+	client_t *client;
+	struct pcmcia_socket *s;
+
+	s = req->Socket;
+	if (!s)
+		return CS_BAD_SOCKET;
+
+	client = (client_t *) kmalloc(sizeof(client_t), GFP_KERNEL);
+	if (!client) 
+		return CS_OUT_OF_RESOURCE;
+	memset(client, '\0', sizeof(client_t));
+	client->client_magic = CLIENT_MAGIC;
+	strlcpy(client->dev_info, (char *)req->dev_info, DEV_NAME_LEN);
+	client->Socket = s;
+	client->Function = req->Function;
+	client->state = CLIENT_UNBOUND;
+	client->erase_busy.next = &client->erase_busy;
+	client->erase_busy.prev = &client->erase_busy;
+	init_waitqueue_head(&client->mtd_req);
+	client->next = s->clients;
+	s->clients = client;
+	ds_dbg(1, "%s: bind_device(): client 0x%p, dev %s\n",
+		cs_socket_name(client->Socket), client, client->dev_info);
+	return CS_SUCCESS;
+} /* bind_device */
+
+
+/*======================================================================
+
+    Bind_mtd() associates a device driver with a particular memory
+    region.  It is normally called by Driver Services after it has
+    identified a memory device type.  An instance of the corresponding
+    driver will then be able to register to control this region.
+    
+======================================================================*/
+
+static int pcmcia_bind_mtd(mtd_bind_t *req)
+{
+	struct pcmcia_socket *s;
+	memory_handle_t region;
+
+	s = req->Socket;
+	if (!s)
+		return CS_BAD_SOCKET;
+    
+	if (req->Attributes & REGION_TYPE_AM)
+		region = s->a_region;
+	else
+		region = s->c_region;
+
+	while (region) {
+		if (region->info.CardOffset == req->CardOffset) 
+			break;
+		region = region->info.next;
+	}
+	if (!region || (region->mtd != NULL))
+		return CS_BAD_OFFSET;
+	strlcpy(region->dev_info, (char *)req->dev_info, DEV_NAME_LEN);
+
+	ds_dbg(1, "%s: bind_mtd: attr 0x%x, offset 0x%x, dev %s\n",
+	      cs_socket_name(s), req->Attributes, req->CardOffset,
+	      (char *)req->dev_info);
+	return CS_SUCCESS;
+} /* bind_mtd */
+
+
+/* String tables for error messages */
+
+typedef struct lookup_t {
+    int key;
+    char *msg;
+} lookup_t;
+
+static const lookup_t error_table[] = {
+    { CS_SUCCESS,		"Operation succeeded" },
+    { CS_BAD_ADAPTER,		"Bad adapter" },
+    { CS_BAD_ATTRIBUTE, 	"Bad attribute", },
+    { CS_BAD_BASE,		"Bad base address" },
+    { CS_BAD_EDC,		"Bad EDC" },
+    { CS_BAD_IRQ,		"Bad IRQ" },
+    { CS_BAD_OFFSET,		"Bad offset" },
+    { CS_BAD_PAGE,		"Bad page number" },
+    { CS_READ_FAILURE,		"Read failure" },
+    { CS_BAD_SIZE,		"Bad size" },
+    { CS_BAD_SOCKET,		"Bad socket" },
+    { CS_BAD_TYPE,		"Bad type" },
+    { CS_BAD_VCC,		"Bad Vcc" },
+    { CS_BAD_VPP,		"Bad Vpp" },
+    { CS_BAD_WINDOW,		"Bad window" },
+    { CS_WRITE_FAILURE,		"Write failure" },
+    { CS_NO_CARD,		"No card present" },
+    { CS_UNSUPPORTED_FUNCTION,	"Usupported function" },
+    { CS_UNSUPPORTED_MODE,	"Unsupported mode" },
+    { CS_BAD_SPEED,		"Bad speed" },
+    { CS_BUSY,			"Resource busy" },
+    { CS_GENERAL_FAILURE,	"General failure" },
+    { CS_WRITE_PROTECTED,	"Write protected" },
+    { CS_BAD_ARG_LENGTH,	"Bad argument length" },
+    { CS_BAD_ARGS,		"Bad arguments" },
+    { CS_CONFIGURATION_LOCKED,	"Configuration locked" },
+    { CS_IN_USE,		"Resource in use" },
+    { CS_NO_MORE_ITEMS,		"No more items" },
+    { CS_OUT_OF_RESOURCE,	"Out of resource" },
+    { CS_BAD_HANDLE,		"Bad handle" },
+    { CS_BAD_TUPLE,		"Bad CIS tuple" }
+};
+
+
+static const lookup_t service_table[] = {
+    { AccessConfigurationRegister,	"AccessConfigurationRegister" },
+    { AddSocketServices,		"AddSocketServices" },
+    { AdjustResourceInfo,		"AdjustResourceInfo" },
+    { CheckEraseQueue,			"CheckEraseQueue" },
+    { CloseMemory,			"CloseMemory" },
+    { DeregisterClient,			"DeregisterClient" },
+    { DeregisterEraseQueue,		"DeregisterEraseQueue" },
+    { GetCardServicesInfo,		"GetCardServicesInfo" },
+    { GetClientInfo,			"GetClientInfo" },
+    { GetConfigurationInfo,		"GetConfigurationInfo" },
+    { GetEventMask,			"GetEventMask" },
+    { GetFirstClient,			"GetFirstClient" },
+    { GetFirstRegion,			"GetFirstRegion" },
+    { GetFirstTuple,			"GetFirstTuple" },
+    { GetNextClient,			"GetNextClient" },
+    { GetNextRegion,			"GetNextRegion" },
+    { GetNextTuple,			"GetNextTuple" },
+    { GetStatus,			"GetStatus" },
+    { GetTupleData,			"GetTupleData" },
+    { MapMemPage,			"MapMemPage" },
+    { ModifyConfiguration,		"ModifyConfiguration" },
+    { ModifyWindow,			"ModifyWindow" },
+    { OpenMemory,			"OpenMemory" },
+    { ParseTuple,			"ParseTuple" },
+    { ReadMemory,			"ReadMemory" },
+    { RegisterClient,			"RegisterClient" },
+    { RegisterEraseQueue,		"RegisterEraseQueue" },
+    { RegisterMTD,			"RegisterMTD" },
+    { ReleaseConfiguration,		"ReleaseConfiguration" },
+    { ReleaseIO,			"ReleaseIO" },
+    { ReleaseIRQ,			"ReleaseIRQ" },
+    { ReleaseWindow,			"ReleaseWindow" },
+    { RequestConfiguration,		"RequestConfiguration" },
+    { RequestIO,			"RequestIO" },
+    { RequestIRQ,			"RequestIRQ" },
+    { RequestSocketMask,		"RequestSocketMask" },
+    { RequestWindow,			"RequestWindow" },
+    { ResetCard,			"ResetCard" },
+    { SetEventMask,			"SetEventMask" },
+    { ValidateCIS,			"ValidateCIS" },
+    { WriteMemory,			"WriteMemory" },
+    { BindDevice,			"BindDevice" },
+    { BindMTD,				"BindMTD" },
+    { ReportError,			"ReportError" },
+    { SuspendCard,			"SuspendCard" },
+    { ResumeCard,			"ResumeCard" },
+    { EjectCard,			"EjectCard" },
+    { InsertCard,			"InsertCard" },
+    { ReplaceCIS,			"ReplaceCIS" }
+};
+
+
+int pcmcia_report_error(client_handle_t handle, error_info_t *err)
+{
+	int i;
+	char *serv;
+
+	if (CHECK_HANDLE(handle))
+		printk(KERN_NOTICE);
+	else
+		printk(KERN_NOTICE "%s: ", handle->dev_info);
+
+	for (i = 0; i < ARRAY_SIZE(service_table); i++)
+		if (service_table[i].key == err->func)
+			break;
+	if (i < ARRAY_SIZE(service_table))
+		serv = service_table[i].msg;
+	else
+		serv = "Unknown service number";
+
+	for (i = 0; i < ARRAY_SIZE(error_table); i++)
+		if (error_table[i].key == err->retcode)
+			break;
+	if (i < ARRAY_SIZE(error_table))
+		printk("%s: %s\n", serv, error_table[i].msg);
+	else
+		printk("%s: Unknown error code %#x\n", serv, err->retcode);
+
+	return CS_SUCCESS;
+} /* report_error */
+EXPORT_SYMBOL(pcmcia_report_error);
+
+/* end of code which was in cs.c before */
+
+/*======================================================================*/
+
 void cs_error(client_handle_t handle, int func, int ret)
 {
 	error_info_t err = { func, ret };
@@ -249,12 +465,12 @@ static int handle_request(struct pcmcia_
 {
     if (s->req_pending != 0)
 	return CS_IN_USE;
-    if (s->state & SOCKET_BUSY)
+    if (s->state & DS_SOCKET_BUSY)
 	s->req_pending = 1;
     handle_event(s, event);
     if (wait_event_interruptible(s->request, s->req_pending <= 0))
         return CS_IN_USE;
-    if (s->state & SOCKET_BUSY)
+    if (s->state & DS_SOCKET_BUSY)
         return s->req_result;
     return CS_SUCCESS;
 }
@@ -263,7 +479,7 @@ static void handle_removal(void *data)
 {
     struct pcmcia_bus_socket *s = data;
     handle_event(s, CS_EVENT_CARD_REMOVAL);
-    s->state &= ~SOCKET_REMOVAL_PENDING;
+    s->state &= ~DS_SOCKET_REMOVAL_PENDING;
 }
 
 /*======================================================================
@@ -277,22 +493,22 @@ 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",
+    ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n",
 	  event, priority, args->client_handle);
     s = args->client_data;
     
     switch (event) {
 	
     case CS_EVENT_CARD_REMOVAL:
-	s->state &= ~SOCKET_PRESENT;
-	if (!(s->state & SOCKET_REMOVAL_PENDING)) {
-		s->state |= SOCKET_REMOVAL_PENDING;
+	s->state &= ~DS_SOCKET_PRESENT;
+	if (!(s->state & DS_SOCKET_REMOVAL_PENDING)) {
+		s->state |= DS_SOCKET_REMOVAL_PENDING;
 		schedule_delayed_work(&s->removal,  HZ/10);
 	}
 	break;
 	
     case CS_EVENT_CARD_INSERTION:
-	s->state |= SOCKET_PRESENT;
+	s->state |= DS_SOCKET_PRESENT;
 	handle_event(s, event);
 	break;
 
@@ -353,7 +569,7 @@ static int bind_request(struct pcmcia_bu
     if (!s)
 	    return -EINVAL;
 
-    DEBUG(2, "bind_request(%d, '%s')\n", s->parent->sock,
+    ds_dbg(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 +700,7 @@ static int unbind_request(struct pcmcia_
 {
     socket_bind_t **b, *c;
 
-    DEBUG(2, "unbind_request(%d, '%s')\n", s->parent->sock,
+    ds_dbg(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,17 +734,17 @@ static int ds_open(struct inode *inode, 
     struct pcmcia_bus_socket *s;
     user_info_t *user;
 
-    DEBUG(0, "ds_open(socket %d)\n", i);
+    ds_dbg(0, "ds_open(socket %d)\n", i);
 
     s = pcmcia_get_bus_socket(i);
     if (!s)
 	    return -ENODEV;
 
     if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
-	if (s->state & SOCKET_BUSY)
+	if (s->state & DS_SOCKET_BUSY)
 	    return -EBUSY;
 	else
-	    s->state |= SOCKET_BUSY;
+	    s->state |= DS_SOCKET_BUSY;
     }
     
     user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
@@ -540,7 +756,7 @@ static int ds_open(struct inode *inode, 
     s->user = user;
     file->private_data = user;
     
-    if (s->state & SOCKET_PRESENT)
+    if (s->state & DS_SOCKET_PRESENT)
 	queue_event(user, CS_EVENT_CARD_INSERTION);
     return 0;
 } /* ds_open */
@@ -552,7 +768,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));
+    ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
 
     user = file->private_data;
     if (CHECK_USER(user))
@@ -562,7 +778,7 @@ static int ds_release(struct inode *inod
 
     /* Unlink user data structure */
     if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
-	s->state &= ~SOCKET_BUSY;
+	s->state &= ~DS_SOCKET_BUSY;
 	s->req_pending = 0;
 	wake_up_interruptible(&s->request);
     }
@@ -588,7 +804,7 @@ static ssize_t ds_read(struct file *file
     user_info_t *user;
     int ret;
 
-    DEBUG(2, "ds_read(socket %d)\n", iminor(inode));
+    ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode));
     
     if (count < 4)
 	return -EINVAL;
@@ -598,7 +814,7 @@ static ssize_t ds_read(struct file *file
 	return -EIO;
     
     s = user->socket;
-    if (s->state & SOCKET_DEAD)
+    if (s->state & DS_SOCKET_DEAD)
         return -EIO;
 
     ret = wait_event_interruptible(s->queue, !queue_empty(user));
@@ -616,7 +832,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));
+    ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
     
     if (count != 4)
 	return -EINVAL;
@@ -628,7 +844,7 @@ static ssize_t ds_write(struct file *fil
 	return -EIO;
 
     s = user->socket;
-    if (s->state & SOCKET_DEAD)
+    if (s->state & DS_SOCKET_DEAD)
         return -EIO;
 
     if (s->req_pending) {
@@ -650,7 +866,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));
+    ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode));
     
     user = file->private_data;
     if (CHECK_USER(user))
@@ -677,14 +893,14 @@ 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);
+    ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
     
     user = file->private_data;
     if (CHECK_USER(user))
 	return -EIO;
 
     s = user->socket;
-    if (s->state & SOCKET_DEAD)
+    if (s->state & DS_SOCKET_DEAD)
         return -EIO;
     
     size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
@@ -697,14 +913,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);
+	    ds_dbg(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);
+	    ds_dbg(3, "ds_ioctl(): verify_write = %d\n", err);
 	    return err;
 	}
     }
@@ -748,16 +964,16 @@ static int ds_ioctl(struct inode * inode
 	ret = pcmcia_validate_cis(s->handle, &buf.cisinfo);
 	break;
     case DS_SUSPEND_CARD:
-	ret = pcmcia_suspend_card(s->handle, NULL);
+	ret = pcmcia_suspend_card(s->parent);
 	break;
     case DS_RESUME_CARD:
-	ret = pcmcia_resume_card(s->handle, NULL);
+	ret = pcmcia_resume_card(s->parent);
 	break;
     case DS_EJECT_CARD:
-	ret = pcmcia_eject_card(s->handle, NULL);
+	ret = pcmcia_eject_card(s->parent);
 	break;
     case DS_INSERT_CARD:
-	ret = pcmcia_insert_card(s->handle, NULL);
+	ret = pcmcia_insert_card(s->parent);
 	break;
     case DS_ACCESS_CONFIGURATION_REGISTER:
 	if ((buf.conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN))
@@ -806,7 +1022,7 @@ static int ds_ioctl(struct inode * inode
     }
     
     if ((err == 0) && (ret != CS_SUCCESS)) {
-	DEBUG(2, "ds_ioctl: ret = %d\n", ret);
+	ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
 	switch (ret) {
 	case CS_BAD_SOCKET: case CS_NO_CARD:
 	    err = -ENODEV; break;
@@ -916,7 +1132,7 @@ static void pcmcia_bus_remove_socket(str
 
 	pcmcia_deregister_client(socket->pcmcia->handle);
 
-	socket->pcmcia->state |= SOCKET_DEAD;
+	socket->pcmcia->state |= DS_SOCKET_DEAD;
 	pcmcia_put_bus_socket(socket->pcmcia);
 	socket->pcmcia = NULL;
 
--- diff/drivers/pcmcia/i82365.c	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/pcmcia/i82365.c	2004-03-16 09:37:56.429961512 +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-11 10:20:26.000000000 +0000
+++ source/drivers/pcmcia/sa11xx_core.c	2004-03-16 09:37:56.431961208 +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, 2, "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-16 09:37:56.432961056 +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-16 09:37:56.433960904 +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, __func__ , ##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/s390/char/keyboard.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/s390/char/keyboard.c	2004-03-16 09:37:56.434960752 +0000
@@ -471,7 +471,7 @@ kbd_ioctl(struct kbd_data *kbd, struct f
 	 * To have permissions to do most of the vt ioctls, we either have
 	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
 	 */
-	perm = current->tty == kbd->tty || capable(CAP_SYS_TTY_CONFIG);
+	perm = current->signal->tty == kbd->tty || capable(CAP_SYS_TTY_CONFIG);
 	switch (cmd) {
 	case KDGKBTYPE:
 		return put_user(KB_101, (char*) arg);
--- diff/drivers/s390/char/tape_class.c	2004-03-11 10:20:26.000000000 +0000
+++ source/drivers/s390/char/tape_class.c	2004-03-16 09:37:56.434960752 +0000
@@ -46,13 +46,10 @@ struct cdev *register_tape_dev(
 	cdev->owner = fops->owner;
 	cdev->ops   = fops;
 	cdev->dev   = dev;
-	strcpy(cdev->kobj.name, devname);
-	for (s = strchr(cdev->kobj.name, '/'); s; s = strchr(s, '/'))
-		*s = '!';
 
 	rc = cdev_add(cdev, cdev->dev, 1);
 	if (rc) {
-		kobject_put(&cdev->kobj);
+		cdev_del(cdev);
 		return ERR_PTR(rc);
 	}
 	class_simple_device_add(tape_class, cdev->dev, device, "%s", devname);
--- diff/drivers/scsi/3w-xxxx.c	2003-09-30 14:46:16.000000000 +0000
+++ source/drivers/scsi/3w-xxxx.c	2004-03-16 09:37:56.505949960 +0000
@@ -6,7 +6,7 @@
    		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                      Brad Strand <linux@3ware.com>
 
-   Copyright (C) 1999-2003 3ware Inc.
+   Copyright (C) 1999-2004 3ware Inc.
 
    Kernel compatiblity By: 	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -179,6 +179,8 @@
    1.02.00.036 - Increase character ioctl timeout to 60 seconds.
    1.02.00.037 - Fix tw_ioctl() to handle all non-data ATA passthru cmds
                  for 'smartmontools' support.
+   1.26.00.038 - Roll driver minor version to 26 to denote kernel 2.6.
+                 Add support for cmds_per_lun module parameter.
 */
 
 #include <linux/module.h>
@@ -205,6 +207,7 @@ MODULE_LICENSE("GPL");
 #include <linux/reboot.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
+#include <linux/moduleparam.h>
 
 #include <asm/errno.h>
 #include <asm/io.h>
@@ -242,10 +245,15 @@ static struct file_operations tw_fops = 
 };
 
 /* Globals */
-char *tw_driver_version="1.02.00.037";
+char *tw_driver_version="1.26.00.038";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
 static int twe_major = -1;
+static int cmds_per_lun;
+
+/* Module parameters */
+module_param(cmds_per_lun, int, 0);
+MODULE_PARM_DESC(cmds_per_lun, "Maximum commands per LUN");
 
 /* Functions */
 
@@ -1141,14 +1149,6 @@ int tw_findcards(Scsi_Host_Template *tw_
 			/* Set card status as online */
 			tw_dev->online = 1;
 
-#ifdef CONFIG_3W_XXXX_CMD_PER_LUN
-			tw_host->cmd_per_lun = CONFIG_3W_XXXX_CMD_PER_LUN;
-			if (tw_host->cmd_per_lun > TW_MAX_CMDS_PER_LUN)
-				tw_host->cmd_per_lun = TW_MAX_CMDS_PER_LUN;
-#else
-			/* Use SHT cmd_per_lun here */
-			tw_host->cmd_per_lun = TW_MAX_CMDS_PER_LUN;
-#endif
 			tw_dev->free_head = TW_Q_START;
 			tw_dev->free_tail = TW_Q_START;
 			tw_dev->free_wrap = TW_Q_LENGTH - 1;
@@ -3386,13 +3386,13 @@ int tw_slave_configure(Scsi_Device *SDpt
 
 	dprintk(KERN_WARNING "3w-xxxx: tw_slave_configure()\n");
 
-#ifdef CONFIG_3W_XXXX_CMD_PER_LUN
-	max_cmds = CONFIG_3W_XXXX_CMD_PER_LUN;
-	if (max_cmds > TW_MAX_CMDS_PER_LUN)
+	if (cmds_per_lun) {
+		max_cmds = cmds_per_lun;
+		if (max_cmds > TW_MAX_CMDS_PER_LUN)
+			max_cmds = TW_MAX_CMDS_PER_LUN;
+	} else {
 		max_cmds = TW_MAX_CMDS_PER_LUN;
-#else
-	max_cmds = TW_MAX_CMDS_PER_LUN;
-#endif
+	}
 	scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, max_cmds);
 
 	return 0;
@@ -3488,6 +3488,7 @@ static Scsi_Host_Template driver_templat
 	.eh_abort_handler	= tw_scsi_eh_abort,
 	.eh_host_reset_handler	= tw_scsi_eh_reset,
 	.bios_param		= tw_scsi_biosparam,
+	.slave_configure	= tw_slave_configure,
 	.can_queue		= TW_Q_LENGTH-2,
 	.this_id		= -1,
 	.sg_tablesize		= TW_MAX_SGL_LENGTH,
--- diff/drivers/scsi/3w-xxxx.h	2003-09-30 14:46:16.000000000 +0000
+++ source/drivers/scsi/3w-xxxx.h	2004-03-16 09:37:56.513948744 +0000
@@ -6,7 +6,7 @@
    		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                      Brad Strand <linux@3ware.com>
 
-   Copyright (C) 1999-2003 3ware Inc.
+   Copyright (C) 1999-2004 3ware Inc.
 
    Kernel compatiblity By:	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
--- diff/drivers/scsi/53c700.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/53c700.c	2004-03-16 09:37:56.521947528 +0000
@@ -137,6 +137,9 @@
 #include "scsi.h"
 #include "hosts.h"
 
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
+
 #include "53c700.h"
 
 /* NOTE: For 64 bit drivers there are points in the code where we use
@@ -173,6 +176,8 @@ STATIC void NCR_700_slave_destroy(Scsi_D
 
 STATIC struct device_attribute *NCR_700_dev_attrs[];
 
+STATIC struct scsi_transport_template *NCR_700_transport_template = NULL;
+
 static char *NCR_700_phase[] = {
 	"",
 	"after selection",
@@ -236,6 +241,53 @@ static __u8 NCR_700_SDTR_msg[] = {
 	NCR_700_MAX_OFFSET
 };
 
+/* This translates the SDTR message offset and period to a value
+ * which can be loaded into the SXFER_REG.
+ *
+ * NOTE: According to SCSI-2, the true transfer period (in ns) is
+ *       actually four times this period value */
+static inline __u8
+NCR_700_offset_period_to_sxfer(struct NCR_700_Host_Parameters *hostdata,
+			       __u8 offset, __u8 period)
+{
+	int XFERP;
+
+	__u8 min_xferp = (hostdata->chip710
+			  ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP);
+	__u8 max_offset = (hostdata->chip710
+			   ? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET);
+
+	if(offset == 0)
+		return 0;
+
+	if(period < hostdata->min_period) {
+		printk(KERN_WARNING "53c700: Period %dns is less than this chip's minimum, setting to %d\n", period*4, NCR_700_SDTR_msg[3]*4);
+		period = hostdata->min_period;
+	}
+	XFERP = (period*4 * hostdata->sync_clock)/1000 - 4;
+	if(offset > max_offset) {
+		printk(KERN_WARNING "53c700: Offset %d exceeds chip maximum, setting to %d\n",
+		       offset, max_offset);
+		offset = max_offset;
+	}
+	if(XFERP < min_xferp) {
+		printk(KERN_WARNING "53c700: XFERP %d is less than minium, setting to %d\n",
+		       XFERP,  min_xferp);
+		XFERP =  min_xferp;
+	}
+	return (offset & 0x0f) | (XFERP & 0x07)<<4;
+}
+
+static inline __u8
+NCR_700_get_SXFER(Scsi_Device *SDp)
+{
+	struct NCR_700_Host_Parameters *hostdata = 
+		(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
+
+	return NCR_700_offset_period_to_sxfer(hostdata, spi_offset(SDp),
+					      spi_period(SDp));
+}
+
 struct Scsi_Host *
 NCR_700_detect(Scsi_Host_Template *tpnt,
 	       struct NCR_700_Host_Parameters *hostdata)
@@ -321,11 +373,13 @@ 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;
 	host->max_lun = NCR_700_MAX_LUNS;
+	BUG_ON(NCR_700_transport_template == NULL);
+	host->transportt = NCR_700_transport_template;
 	host->unique_id = hostdata->base;
 	host->base = hostdata->base;
 	hostdata->eh_complete = NULL;
@@ -520,40 +574,6 @@ save_for_reselection(struct NCR_700_Host
 	hostdata->cmd = NULL;
 }
 
-/* This translates the SDTR message offset and period to a value
- * which can be loaded into the SXFER_REG.
- *
- * NOTE: According to SCSI-2, the true transfer period (in ns) is
- *       actually four times this period value */
-STATIC inline __u8
-NCR_700_offset_period_to_sxfer(struct NCR_700_Host_Parameters *hostdata,
-			       __u8 offset, __u8 period)
-{
-	int XFERP;
-	__u8 min_xferp = (hostdata->chip710
-			  ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP);
-	__u8 max_offset = (hostdata->chip710
-			   ? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET);
-	/* NOTE: NCR_700_SDTR_msg[3] contains our offer of the minimum
-	 * period.  It is set in NCR_700_chip_setup() */
-	if(period < NCR_700_SDTR_msg[3]) {
-		printk(KERN_WARNING "53c700: Period %dns is less than this chip's minimum, setting to %d\n", period*4, NCR_700_SDTR_msg[3]*4);
-		period = NCR_700_SDTR_msg[3];
-	}
-	XFERP = (period*4 * hostdata->sync_clock)/1000 - 4;
-	if(offset > max_offset) {
-		printk(KERN_WARNING "53c700: Offset %d exceeds chip maximum, setting to %d\n",
-		       offset, max_offset);
-		offset = max_offset;
-	}
-	if(XFERP < min_xferp) {
-		printk(KERN_WARNING "53c700: XFERP %d is less than minium, setting to %d\n",
-		       XFERP,  min_xferp);
-		XFERP =  min_xferp;
-	}
-	return (offset & 0x0f) | (XFERP & 0x07)<<4;
-}
-
 STATIC inline void
 NCR_700_unmap(struct NCR_700_Host_Parameters *hostdata, Scsi_Cmnd *SCp,
 	      struct NCR_700_command_slot *slot)
@@ -724,11 +744,9 @@ NCR_700_chip_setup(struct Scsi_Host *hos
 	 * exact details of this calculation which is based on a
 	 * setting of the SXFER register */
 	min_period = 1000*(4+min_xferp)/(4*hostdata->sync_clock);
-	if(min_period > NCR_700_MIN_PERIOD) {
-		NCR_700_SDTR_msg[3] = min_period;
-	}
-	if(hostdata->chip710)
-		NCR_700_SDTR_msg[4] = NCR_710_MAX_OFFSET;
+	hostdata->min_period = NCR_700_MIN_PERIOD;
+	if(min_period > NCR_700_MIN_PERIOD)
+		hostdata->min_period = min_period;
 }
 
 STATIC void
@@ -777,20 +795,25 @@ process_extended_message(struct Scsi_Hos
 		if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) {
 			__u8 period = hostdata->msgin[3];
 			__u8 offset = hostdata->msgin[4];
-			__u8 sxfer;
 
-			if(offset != 0 && period != 0)
-				sxfer = NCR_700_offset_period_to_sxfer(hostdata, offset, period);
-			else 
-				sxfer = 0;
+			if(offset == 0 || period == 0) {
+				offset = 0;
+				period = 0;
+			}
 			
-			if(sxfer != NCR_700_get_SXFER(SCp->device)) {
-				printk(KERN_INFO "scsi%d: (%d:%d) Synchronous at offset %d, period %dns\n",
-				       host->host_no, pun, lun,
-				       offset, period*4);
-				
-				NCR_700_set_SXFER(SCp->device, sxfer);
+			if(NCR_700_is_flag_set(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION)) {
+				if(spi_offset(SCp->device) != 0)
+					printk(KERN_INFO "scsi%d: (%d:%d) Synchronous at offset %d, period %dns\n",
+					       host->host_no, pun, lun,
+					       offset, period*4);
+				else
+					printk(KERN_INFO "scsi%d: (%d:%d) Asynchronous\n",
+					       host->host_no, pun, lun);
+				NCR_700_clear_flag(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION);
 			}
+				
+			spi_offset(SCp->device) = offset;
+			spi_period(SCp->device) = period;
 			
 
 			NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
@@ -870,7 +893,7 @@ process_message(struct Scsi_Host *host,	
 	case A_REJECT_MSG:
 		if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) {
 			/* Rejected our sync negotiation attempt */
-			NCR_700_set_SXFER(SCp->device, 0);
+			spi_period(SCp->device) = spi_offset(SCp->device) = 0;
 			NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
 			NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
 		} else if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING)) {
@@ -982,8 +1005,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 +1030,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);
@@ -1396,6 +1419,8 @@ NCR_700_start_command(Scsi_Cmnd *SCp)
 	   NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC)) {
 		memcpy(&hostdata->msgout[count], NCR_700_SDTR_msg,
 		       sizeof(NCR_700_SDTR_msg));
+		hostdata->msgout[count+3] = spi_period(SCp->device);
+		hostdata->msgout[count+4] = spi_offset(SCp->device);
 		count += sizeof(NCR_700_SDTR_msg);
 		NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
 	}
@@ -1497,6 +1522,8 @@ NCR_700_intr(int irq, void *dev_id, stru
 			printk(KERN_ERR "scsi%d: Bus Reset detected, executing command %p, slot %p, dsp %08x[%04x]\n",
 			       host->host_no, SCp, SCp == NULL ? NULL : SCp->host_scribble, dsp, dsp - hostdata->pScript);
 
+			scsi_report_bus_reset(host, 0);
+
 			/* clear all the negotiated parameters */
 			__shost_for_each_device(SDp, host)
 				SDp->hostdata = 0;
@@ -1942,6 +1969,9 @@ NCR_700_bus_reset(Scsi_Cmnd * SCp)
 	wait_for_completion(&complete);
 	spin_lock_irq(SCp->device->host->host_lock);
 	hostdata->eh_complete = NULL;
+	/* Revalidate the transport parameters of the failing device */
+	if(hostdata->fast)
+		spi_schedule_dv_device(SCp->device);
 	return SUCCESS;
 }
 
@@ -1967,9 +1997,57 @@ NCR_700_host_reset(Scsi_Cmnd * SCp)
 	return SUCCESS;
 }
 
+STATIC void
+NCR_700_set_period(struct scsi_device *SDp, int period)
+{
+	struct NCR_700_Host_Parameters *hostdata = 
+		(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
+	
+	if(!hostdata->fast)
+		return;
+
+	if(period < hostdata->min_period)
+		period = hostdata->min_period;
+
+	spi_period(SDp) = period;
+	NCR_700_clear_flag(SDp, NCR_700_DEV_NEGOTIATED_SYNC);
+	NCR_700_clear_flag(SDp, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
+	NCR_700_set_flag(SDp, NCR_700_DEV_PRINT_SYNC_NEGOTIATION);
+}
+
+STATIC void
+NCR_700_set_offset(struct scsi_device *SDp, int offset)
+{
+	struct NCR_700_Host_Parameters *hostdata = 
+		(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
+	int max_offset = hostdata->chip710
+		? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET;
+	
+	if(!hostdata->fast)
+		return;
+
+	if(offset > max_offset)
+		offset = max_offset;
+
+	/* if we're currently async, make sure the period is reasonable */
+	if(spi_offset(SDp) == 0 && (spi_period(SDp) < hostdata->min_period ||
+				    spi_period(SDp) > 0xff))
+		spi_period(SDp) = hostdata->min_period;
+
+	spi_offset(SDp) = offset;
+	NCR_700_clear_flag(SDp, NCR_700_DEV_NEGOTIATED_SYNC);
+	NCR_700_clear_flag(SDp, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
+	NCR_700_set_flag(SDp, NCR_700_DEV_PRINT_SYNC_NEGOTIATION);
+}
+
+
+
 STATIC int
 NCR_700_slave_configure(Scsi_Device *SDp)
 {
+	struct NCR_700_Host_Parameters *hostdata = 
+		(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
+
 	/* to do here: allocate memory; build a queue_full list */
 	if(SDp->tagged_supported) {
 		/* do TCQ stuff here */
@@ -1977,6 +2055,13 @@ NCR_700_slave_configure(Scsi_Device *SDp
 		/* initialise to default depth */
 		scsi_adjust_queue_depth(SDp, 0, SDp->host->cmd_per_lun);
 	}
+	if(hostdata->fast) {
+		/* Find the correct offset and period via domain validation */
+		spi_dv_device(SDp);
+	} else {
+		spi_offset(SDp) = 0;
+		spi_period(SDp) = 0;
+	}
 	return 0;
 }
 
@@ -2033,3 +2118,27 @@ STATIC struct device_attribute *NCR_700_
 EXPORT_SYMBOL(NCR_700_detect);
 EXPORT_SYMBOL(NCR_700_release);
 EXPORT_SYMBOL(NCR_700_intr);
+
+static struct spi_function_template NCR_700_transport_functions =  {
+	.set_period	= NCR_700_set_period,
+	.show_period	= 1,
+	.set_offset	= NCR_700_set_offset,
+	.show_offset	= 1,
+};
+
+static int __init NCR_700_init(void)
+{
+	NCR_700_transport_template = spi_attach_transport(&NCR_700_transport_functions);
+	if(!NCR_700_transport_template)
+		return -ENODEV;
+	return 0;
+}
+
+static void __exit NCR_700_exit(void)
+{
+	spi_release_transport(NCR_700_transport_template);
+}
+
+module_init(NCR_700_init);
+module_exit(NCR_700_exit);
+
--- diff/drivers/scsi/53c700.h	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/53c700.h	2004-03-16 09:37:56.523947224 +0000
@@ -99,19 +99,9 @@ struct NCR_700_SG_List {
 #define NCR_700_DEV_NEGOTIATED_SYNC	(1<<16)
 #define NCR_700_DEV_BEGIN_SYNC_NEGOTIATION	(1<<17)
 #define NCR_700_DEV_BEGIN_TAG_QUEUEING	(1<<18)
-#define NCR_700_DEV_TAG_STARVATION_WARNED (1<<19)
+#define NCR_700_DEV_PRINT_SYNC_NEGOTIATION (1<<19)
 
 static inline void
-NCR_700_set_SXFER(Scsi_Device *SDp, __u8 sxfer)
-{
-	SDp->hostdata = (void *)(((long)SDp->hostdata & 0xffffff00) |
-				(sxfer & 0xff));
-}
-static inline __u8 NCR_700_get_SXFER(Scsi_Device *SDp)
-{
-	return (((unsigned long)SDp->hostdata) & 0xff);
-}
-static inline void
 NCR_700_set_depth(Scsi_Device *SDp, __u8 depth)
 {
 	long l = (long)SDp->hostdata;
@@ -215,6 +205,7 @@ struct NCR_700_Host_Parameters {
 	__u8	tag_negotiated;
 	__u8	rev;
 	__u8	reselection_id;
+	__u8	min_period;
 
 	/* Free list, singly linked by ITL_forw elements */
 	struct NCR_700_command_slot *free_list;
@@ -439,6 +430,7 @@ struct NCR_700_Host_Parameters {
 	} \
 }
 
+
 static inline __u8
 NCR_700_mem_readb(struct Scsi_Host *host, __u32 reg)
 {
--- diff/drivers/scsi/BusLogic.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/BusLogic.c	2004-03-16 09:37:56.535945400 +0000
@@ -140,7 +140,7 @@ static char *BusLogic_CommandFailureReas
   Name, Copyright Notice, and Electronic Mail Address.
 */
 
-static void __init BusLogic_AnnounceDriver(struct BusLogic_HostAdapter *HostAdapter)
+static void BusLogic_AnnounceDriver(struct BusLogic_HostAdapter *HostAdapter)
 {
   BusLogic_Announce("***** BusLogic SCSI Driver Version "
 		    BusLogic_DriverVersion " of "
--- diff/drivers/scsi/Kconfig	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/Kconfig	2004-03-16 09:37:56.542944336 +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
@@ -438,6 +457,14 @@ config SCSI_SATA_VIA
 
 	  If unsure, say N.
 
+config SCSI_SATA_VITESSE
+	tristate "VITESSE VSC-7174 SATA support"
+	depends on SCSI_SATA && PCI && EXPERIMENTAL
+	help
+	  This option enables support for Vitesse VSC7174 Serial ATA.
+
+	  If unsure, say N.
+
 config SCSI_BUSLOGIC
 	tristate "BusLogic SCSI support"
 	depends on (PCI || ISA || MCA) && SCSI
@@ -845,6 +872,7 @@ config SCSI_NCR53C406A
 config SCSI_NCR_D700
 	tristate "NCR Dual 700 MCA SCSI support"
 	depends on MCA && SCSI
+	select SCSI_SPI_ATTRS
 	help
 	  This is a driver for the MicroChannel Dual 700 card produced by
 	  NCR and commonly used in 345x/35xx/4100 class machines.  It always
@@ -861,6 +889,7 @@ config 53C700_IO_MAPPED
 config SCSI_LASI700
 	tristate "HP Lasi SCSI support for 53c700/710"
 	depends on GSC && SCSI
+	select SCSI_SPI_ATTRS
 	help
 	  This is a driver for the SCSI controller in the Lasi chip found in
 	  many PA-RISC workstations & servers.  If you do not know whether you
@@ -1212,6 +1241,7 @@ config SCSI_SEAGATE
 config SCSI_SIM710
 	tristate "Simple 53c710 SCSI support (Compaq, NCR machines)"
 	depends on (EISA || MCA) && SCSI
+	select SCSI_SPI_ATTRS
 	---help---
 	  This driver for NCR53c710 based SCSI host adapters.
 
--- diff/drivers/scsi/Makefile	2004-02-18 08:54:11.000000000 +0000
+++ source/drivers/scsi/Makefile	2004-03-16 09:37:56.542944336 +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
@@ -41,7 +49,7 @@ obj-$(CONFIG_SCSI_MAC_ESP)	+= mac_esp.o	
 obj-$(CONFIG_SUN3_SCSI)		+= sun3_scsi.o  sun3_scsi_vme.o
 obj-$(CONFIG_MVME16x_SCSI)	+= mvme16x.o	53c7xx.o
 obj-$(CONFIG_BVME6000_SCSI)	+= bvme6000.o	53c7xx.o
-obj-$(CONFIG_SCSI_SIM710)	+= sim710.o	53c700.o
+obj-$(CONFIG_SCSI_SIM710)	+= 53c700.o	sim710.o
 obj-$(CONFIG_SCSI_ADVANSYS)	+= advansys.o
 obj-$(CONFIG_SCSI_PCI2000)	+= pci2000.o
 obj-$(CONFIG_SCSI_PCI2220I)	+= pci2220i.o
@@ -64,7 +72,7 @@ obj-$(CONFIG_SCSI_IN2000)	+= in2000.o
 obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o
 obj-$(CONFIG_SCSI_GENERIC_NCR5380_MMIO) += g_NCR5380_mmio.o
 obj-$(CONFIG_SCSI_NCR53C406A)	+= NCR53c406a.o
-obj-$(CONFIG_SCSI_NCR_D700)	+= NCR_D700.o 53c700.o
+obj-$(CONFIG_SCSI_NCR_D700)	+= 53c700.o NCR_D700.o
 obj-$(CONFIG_SCSI_NCR_Q720)	+= NCR_Q720_mod.o
 obj-$(CONFIG_SCSI_SYM53C416)	+= sym53c416.o
 obj-$(CONFIG_SCSI_QLOGIC_FAS)	+= qlogicfas.o
@@ -107,13 +115,14 @@ obj-$(CONFIG_SUN3X_ESP)		+= NCR53C9x.o	s
 obj-$(CONFIG_SCSI_DEBUG)	+= scsi_debug.o
 obj-$(CONFIG_SCSI_FCAL)		+= fcal.o
 obj-$(CONFIG_SCSI_CPQFCTS)	+= cpqfc.o
-obj-$(CONFIG_SCSI_LASI700)	+= lasi700.o 53c700.o
+obj-$(CONFIG_SCSI_LASI700)	+= 53c700.o lasi700.o
 obj-$(CONFIG_SCSI_NSP32)	+= nsp32.o
 obj-$(CONFIG_SCSI_SATA_SVW)	+= libata.o sata_svw.o
 obj-$(CONFIG_SCSI_ATA_PIIX)	+= libata.o ata_piix.o
 obj-$(CONFIG_SCSI_SATA_PROMISE)	+= libata.o sata_promise.o
 obj-$(CONFIG_SCSI_SATA_SIL)	+= libata.o sata_sil.o
 obj-$(CONFIG_SCSI_SATA_VIA)	+= libata.o sata_via.o
+obj-$(CONFIG_SCSI_SATA_VITESSE)	+= libata.o sata_vsc.o
 
 obj-$(CONFIG_ARM)		+= arm/
 
@@ -130,7 +139,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/aacraid/linit.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/aacraid/linit.c	2004-03-16 09:37:56.543944184 +0000
@@ -99,8 +99,8 @@ static struct pci_device_id aac_pci_tbl[
 
 	{ 0x9005, 0x0285, 0x9005, 0x0288, 0, 0, 16 }, /* Adaptec 3230S (Harrier)*/
 	{ 0x9005, 0x0285, 0x9005, 0x0289, 0, 0, 17 }, /* Adaptec 3240S (Tornado)*/
-	{ 0x9005, 0x0285, 0x9005, 0x028a, 0, 0, 18 }, /* ASR-2020S PCI-X ZCR (Skyhawk)*/
-	{ 0x9005, 0x0285, 0x9005, 0x028b, 0, 0, 19 }, /* ASR-2020S SO-DIMM PCI-X ZCR(Terminator)*/
+	{ 0x9005, 0x0285, 0x9005, 0x028a, 0, 0, 18 }, /* ASR-2020 ZCR PCI-X U320 */
+	{ 0x9005, 0x0285, 0x9005, 0x028b, 0, 0, 19 }, /* ASR-2025 ZCR DIMM U320 */
 	{ 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 20 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II)*/
 
 	{ 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 21 }, /* Perc 320/DC*/
@@ -116,6 +116,8 @@ static struct pci_device_id aac_pci_tbl[
 	{ 0x9005, 0x0285, 0x0E11, 0x0295, 0, 0, 30 }, /* SATA 6Ch (Bearcat) */
 
 	{ 0x9005, 0x0286, 0x9005, 0x028c, 0, 0, 31 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */
+	{ 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 32 }, /* ASR-2020SA      (ZCR PCI-X SATA) */
+	{ 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 33 }, /* ASR-2025SA      (ZCR DIMM SATA) */
 	{ 0,}
 };
 MODULE_DEVICE_TABLE(pci, aac_pci_tbl);
@@ -145,8 +147,8 @@ static struct aac_driver_ident aac_drive
 
 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 3230S   ", 2 }, /* Adaptec 3230S (Harrier)*/
 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 3240S   ", 2 }, /* Adaptec 3240S (Tornado)*/
-	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2020S PCI-X ", 2 }, /* ASR-2020S PCI-X ZCR (Skyhawk)*/
-	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2020S PCI-X ", 2 }, /* ASR-2020S SO-DIMM PCI-X ZCR(Terminator)*/
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2020ZCR     ", 2 }, /* ASR-2020 ZCR PCI-X U320 */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2025ZCR     ", 2 }, /* ASR-2025 ZCR DIMM U320 */
 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2410SA SATA ", 2 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II)*/
 
 	{ aac_rx_init, "percraid", "DELL    ", "PERC 320/DC     ", 2, AAC_QUIRK_31BIT }, /* Perc 320/DC*/
@@ -162,6 +164,8 @@ static struct aac_driver_ident aac_drive
 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "SATA 6Channel   ", 1 }, /* SATA 6Ch (Bearcat) */
 
 	{ aac_rkt_init,"aacraid",  "ADAPTEC ", "ASR-2230S PCI-X ", 2 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2020SA      ", 1 }, /* ASR-2020SA      (ZCR PCI-X SATA) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2025SA      ", 1 }, /* ASR-2025SA      (ZCR DIMM SATA) */
 };
 
 /**
--- diff/drivers/scsi/aacraid/rkt.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/aacraid/rkt.c	2004-03-16 09:37:56.544944032 +0000
@@ -427,6 +427,7 @@ int aac_rkt_init(struct aac_dev *dev, un
 	dev->a_ops.adapter_disable_int = aac_rkt_disable_interrupt;
 	dev->a_ops.adapter_notify = aac_rkt_notify_adapter;
 	dev->a_ops.adapter_sync_cmd = rkt_sync_cmd;
+	dev->a_ops.adapter_check_health = aac_rkt_check_health;
 
 	if (aac_init_adapter(dev) == NULL)
 		return -1;
--- diff/drivers/scsi/aacraid/rx.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/aacraid/rx.c	2004-03-16 09:37:56.544944032 +0000
@@ -427,6 +427,7 @@ int aac_rx_init(struct aac_dev *dev, uns
 	dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt;
 	dev->a_ops.adapter_notify = aac_rx_notify_adapter;
 	dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
+	dev->a_ops.adapter_check_health = aac_rx_check_health;
 
 	if (aac_init_adapter(dev) == NULL)
 		return -1;
--- diff/drivers/scsi/aacraid/sa.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/aacraid/sa.c	2004-03-16 09:37:56.545943880 +0000
@@ -407,6 +407,7 @@ int aac_sa_init(struct aac_dev *dev, uns
 	dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt;
 	dev->a_ops.adapter_notify = aac_sa_notify_adapter;
 	dev->a_ops.adapter_sync_cmd = sa_sync_cmd;
+	dev->a_ops.adapter_check_health = aac_sa_check_health;
 
 	dprintk(("FUNCDONE\n"));
 
--- diff/drivers/scsi/aic7xxx/Kconfig.aic79xx	2003-05-21 10:50:09.000000000 +0000
+++ source/drivers/scsi/aic7xxx/Kconfig.aic79xx	2004-03-16 09:37:56.545943880 +0000
@@ -4,7 +4,7 @@
 #
 config SCSI_AIC79XX
 	tristate "Adaptec AIC79xx U320 support"
-	depends on PCI
+	depends on PCI && SCSI
 	help
 	This driver supports all of Adaptec's Ultra 320 PCI-X
 	based SCSI controllers.
--- diff/drivers/scsi/aic7xxx/Kconfig.aic7xxx	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/scsi/aic7xxx/Kconfig.aic7xxx	2004-03-16 09:37:56.546943728 +0000
@@ -4,7 +4,7 @@
 #
 config SCSI_AIC7XXX
 	tristate "Adaptec AIC7xxx Fast -> U160 support (New Driver)"
-	depends on PCI || EISA
+	depends on (PCI || EISA) && SCSI
 	---help---
 	This driver supports all of Adaptec's Fast through Ultra 160 PCI
 	based SCSI controllers as well as the aic7770 based EISA and VLB
--- diff/drivers/scsi/aic7xxx/aic7xxx_osm.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/aic7xxx/aic7xxx_osm.c	2004-03-16 09:37:56.549943272 +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/constants.c	2003-11-25 15:24:58.000000000 +0000
+++ source/drivers/scsi/constants.c	2004-03-16 09:37:56.557942056 +0000
@@ -1135,7 +1135,7 @@ void print_Scsi_Cmnd(struct scsi_cmnd *c
 static const char * hostbyte_table[]={
 "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", 
 "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",
-"DID_PASSTHROUGH", "DID_SOFT_ERROR", NULL};
+"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", NULL};
 
 void print_hostbyte(int scsiresult)
 {   static int maxcode=0;
--- diff/drivers/scsi/cpqfcTSinit.c	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/scsi/cpqfcTSinit.c	2004-03-16 09:37:56.558941904 +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 11:28:09.000000000 +0000
+++ source/drivers/scsi/dc395x.c	2004-03-16 09:37:56.575939320 +0000
@@ -62,6 +62,10 @@
 #include <linux/pci.h>
 #include <linux/list.h>
 
+#define DC395X_NAME	"dc395x"
+#define DC395X_BANNER	"Tekram DC395(U/UW/F), DC315(U) - ASIC TRM-S1040"
+#define DC395X_VERSION	"v2.05, 2004/03/08"
+
 /*---------------------------------------------------------------------------
                                   Features
  ---------------------------------------------------------------------------*/
@@ -82,22 +86,16 @@
 #define DBG_KG		0x0001
 #define DBG_0		0x0002
 #define DBG_1		0x0004
-#define DBG_DCB		0x0008
-#define DBG_PARSE	0x0010		/* debug command line parsing */
-#define DBG_SGPARANOIA	0x0020
+#define DBG_SG		0x0020
 #define DBG_FIFO	0x0040
 #define DBG_PIO		0x0080
-#define DBG_RECURSION	0x0100		/* check for excessive recursion */
-#define DBG_MALLOC	0x0200		/* report on memory allocations */
-#define DBG_TRACE	0x0400
-#define DBG_TRACEALL	0x0800
 
 
 /*
  * Set set of things to output debugging for.
  * Undefine to remove all debugging
  */
-/*#define DEBUG_MASK (DBG_0|DBG_1|DBG_DCB|DBG_PARSE|DBG_SGPARANOIA|DBG_FIFO|DBG_PIO|DBG_TRACE|DBG_TRACEALL)*/
+/*#define DEBUG_MASK (DBG_0|DBG_1|DBG_SG|DBG_FIFO|DBG_PIO)*/
 /*#define  DEBUG_MASK	DBG_0*/
 
 
@@ -138,72 +136,6 @@
 #endif
 
 
-/*
- * The recursion debugging just counts entries into the driver and
- * prints out a messge if it exceeds a certain limit. This variable
- * hold the count.
- */
-#if debug_enabled(DBG_RECURSION)
-static int dbg_in_driver = 0;
-#endif
-
-
-/*
- * Memory allocation debugging
- * Just reports when memory is allocated and/or released.
- */
-#if debug_enabled(DBG_MALLOC)
-inline void *dc395x_kmalloc(size_t sz, int fl)
-{
-	void *ptr = kmalloc(sz, fl);
-	dprintkl(KERN_DEBUG, "Alloc %i bytes @ %p w/ fl %08x\n", sz, ptr, fl);
-	return ptr;
-}
-inline void dc395x_kfree(const void *adr)
-{
-	dprintkl(KERN_DEBUG, "Free mem @ %p\n", adr);
-	kfree(adr);
-}
-#else
-#define dc395x_kmalloc(sz, fl)	kmalloc(sz, fl)
-#define dc395x_kfree(adr) kfree(adr)
-#endif
-
-
-/*
- * Debug/trace stuff
- */
-#if debug_enabled(DBG_TRACEALL)
-# define TRACEOUTALL(x...) printk ( x)
-#else
-# define TRACEOUTALL(x...) do {} while (0)
-#endif
-
-#if debug_enabled(DBG_TRACE|DBG_TRACEALL)
-# define DEBUGTRACEBUFSZ 512
-static char tracebuf[64];
-static char traceoverflow[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-# define TRACEPRINTF(x...) \
-	do { \
-		int ln = sprintf(tracebuf, x); \
-		if (srb->debugpos + ln >= DEBUGTRACEBUFSZ) { \
-			srb->debugtrace[srb->debugpos] = 0; \
-			srb->debugpos = DEBUGTRACEBUFSZ/5; \
-			srb->debugtrace[srb->debugpos++] = '>'; \
-		} \
-		sprintf(srb->debugtrace + srb->debugpos, "%s", tracebuf); \
-		srb->debugpos += ln - 1; \
-	} while (0)
-# define TRACEOUT(x...) printk (x)
-#else
-# define TRACEPRINTF(x...) do {} while (0)
-# define TRACEOUT(x...) do {} while (0)
-#endif
-
-
-/*---------------------------------------------------------------------------
- ---------------------------------------------------------------------------*/
-
 #ifndef PCI_VENDOR_ID_TEKRAM
 #define PCI_VENDOR_ID_TEKRAM                    0x1DE1	/* Vendor ID    */
 #endif
@@ -212,32 +144,16 @@ static char traceoverflow[8] = { 0, 0, 0
 #endif
 
 
-
 #define DC395x_LOCK_IO(dev,flags)		spin_lock_irqsave(((struct Scsi_Host *)dev)->host_lock, flags)
 #define DC395x_UNLOCK_IO(dev,flags)		spin_unlock_irqrestore(((struct Scsi_Host *)dev)->host_lock, flags)
 
-#define DC395x_ACB_INITLOCK(acb)		spin_lock_init(&acb->smp_lock)
-#define DC395x_ACB_LOCK(acb,acb_flags)		if (!acb->lock_level_count[cpuid]) { spin_lock_irqsave(&acb->smp_lock,acb_flags); acb->lock_level_count[cpuid]++; } else { acb->lock_level_count[cpuid]++; }
-#define DC395x_ACB_UNLOCK(acb,acb_flags)	if (--acb->lock_level_count[cpuid] == 0) { spin_unlock_irqrestore(&acb->smp_lock,acb_flags); }
-
-#define DC395x_SMP_IO_LOCK(dev,irq_flags)	spin_lock_irqsave(((struct Scsi_Host*)dev)->host_lock,irq_flags)
-#define DC395x_SMP_IO_UNLOCK(dev,irq_flags)	spin_unlock_irqrestore(((struct Scsi_Host*)dev)->host_lock,irq_flags)
-
-
 #define DC395x_read8(acb,address)		(u8)(inb(acb->io_port_base + (address)))
-#define DC395x_read8_(address, base)		(u8)(inb((USHORT)(base) + (address)))
 #define DC395x_read16(acb,address)		(u16)(inw(acb->io_port_base + (address)))
 #define DC395x_read32(acb,address)		(u32)(inl(acb->io_port_base + (address)))
 #define DC395x_write8(acb,address,value)	outb((value), acb->io_port_base + (address))
-#define DC395x_write8_(address,value,base)	outb((value), (USHORT)(base) + (address))
 #define DC395x_write16(acb,address,value)	outw((value), acb->io_port_base + (address))
 #define DC395x_write32(acb,address,value)	outl((value), acb->io_port_base + (address))
 
-
-#define BUS_ADDR(sg)		sg_dma_address(&(sg))
-#define CPU_ADDR(sg)		(page_address((sg).page)+(sg).offset)
-#define PAGE_ADDRESS(sg)	page_address((sg)->page)
-
 /* cmd->result */
 #define RES_TARGET		0x000000FF	/* Target State */
 #define RES_TARGET_LNX  STATUS_MASK	/* Only official ... */
@@ -254,20 +170,22 @@ static char traceoverflow[8] = { 0, 0, 0
 #define SET_RES_DID(who,did) { who &= ~RES_DID; who |= (int)(did) << 16; }
 #define SET_RES_DRV(who,drv) { who &= ~RES_DRV; who |= (int)(drv) << 24; }
 
-/*
-**************************************************************************
-*/
 #define TAG_NONE 255
 
+/*
+ * srb->segement_x is the hw sg list. It is always allocated as a
+ * DC395x_MAX_SG_LISTENTRY entries in a linear block which does not
+ * cross a page boundy.
+ */
+#define SEGMENTX_LEN	(sizeof(struct SGentry)*DC395x_MAX_SG_LISTENTRY)
+
+
 struct SGentry {
 	u32 address;		/* bus! address */
 	u32 length;
 };
 
-
-/*
- * The SEEPROM structure for TRM_S1040 
- */
+/* The SEEPROM structure for TRM_S1040 */
 struct NVRamTarget {
 	u8 cfg0;		/* Target configuration byte 0  */
 	u8 period;		/* Target period                */
@@ -275,7 +193,6 @@ struct NVRamTarget {
 	u8 cfg3;		/* Target configuration byte 3  */
 };
 
-
 struct NvRamType {
 	u8 sub_vendor_id[2];	/* 0,1  Sub Vendor ID   */
 	u8 sub_sys_id[2];	/* 2,3  Sub System ID   */
@@ -302,28 +219,31 @@ struct NvRamType {
 	u16 cksum;		/* 126,127 */
 };
 
-
-/*-----------------------------------------------------------------------
-  SCSI Request Block
-  -----------------------------------------------------------------------*/
 struct ScsiReqBlk {
 	struct list_head list;		/* next/prev ptrs for srb lists */
 	struct DeviceCtlBlk *dcb;
-
-	/* HW scatter list (up to 64 entries) */
-	struct SGentry *segment_x;
 	Scsi_Cmnd *cmd;
 
-	unsigned char *virt_addr;	/* set by update_sg_list */
+	struct SGentry *segment_x;	/* Linear array of hw sg entries (up to 64 entries) */
+	u32 sg_bus_addr;	        /* Bus address of sg list (ie, of segment_x) */
 
-	u32 total_xfer_length;
-	u32 xferred;		/* Backup for the already xferred len */
+	u8 sg_count;			/* No of HW sg entries for this request */
+	u8 sg_index;			/* Index of HW sg entry for this request */
+	u32 total_xfer_length;		/* Total number of bytes remaining to be transfered */
+	unsigned char *virt_addr;	/* Virtual address of current transfer position */
 
-	u32 sg_bus_addr;	/* bus address of DC395x scatterlist */
+	/*
+	 * The sense buffer handling function, request_sense, uses
+	 * the first hw sg entry (segment_x[0]) and the transfer
+	 * length (total_xfer_length). While doing this it stores the
+	 * original values into the last sg hw list
+	 * (srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1] and the
+	 * total_xfer_length in xferred. These values are restored in
+	 * pci_unmap_srb_sense. This is the only place xferred is used.
+	 */
+	u32 xferred;		        /* Saved copy of total_xfer_length */
 
 	u16 state;
-	u8 sg_count;
-	u8 sg_index;
 
 	u8 msgin_buf[6];
 	u8 msgout_buf[6];
@@ -339,17 +259,8 @@ struct ScsiReqBlk {
 	u8 flag;
 
 	u8 scsi_phase;
-
-#if debug_enabled(DBG_TRACE|DBG_TRACEALL)
-	u16 debugpos;
-	char *debugtrace;
-#endif
 };
 
-
-/*-----------------------------------------------------------------------
-  Device Control Block
-  -----------------------------------------------------------------------*/
 struct DeviceCtlBlk {
 	struct list_head list;		/* next/prev ptrs for the dcb list */
 	struct AdapterCtlBlk *acb;
@@ -377,9 +288,6 @@ struct DeviceCtlBlk {
 	u8 init_tcq_flag;
 };
 
-/*-----------------------------------------------------------------------
-  Adapter Control Block
-  -----------------------------------------------------------------------*/
 struct AdapterCtlBlk {
 	struct Scsi_Host *scsi_host;
 
@@ -423,80 +331,63 @@ struct AdapterCtlBlk {
 };
 
 
-
-
 /*---------------------------------------------------------------------------
                             Forward declarations
  ---------------------------------------------------------------------------*/
-static void data_out_phase0(struct AdapterCtlBlk *acb,
-			    struct ScsiReqBlk *srb,
-			    u16 * pscsi_status);
-static void data_in_phase0(struct AdapterCtlBlk *acb,
-			   struct ScsiReqBlk *srb,
-			   u16 * pscsi_status);
-static void command_phase0(struct AdapterCtlBlk *acb,
-			   struct ScsiReqBlk *srb,
-			   u16 * pscsi_status);
-static void status_phase0(struct AdapterCtlBlk *acb,
-			  struct ScsiReqBlk *srb,
-			  u16 * pscsi_status);
-static void msgout_phase0(struct AdapterCtlBlk *acb,
-			  struct ScsiReqBlk *srb,
-			  u16 * pscsi_status);
-static void msgin_phase0(struct AdapterCtlBlk *acb,
-			 struct ScsiReqBlk *srb,
-			 u16 * pscsi_status);
-static void data_out_phase1(struct AdapterCtlBlk *acb,
-			    struct ScsiReqBlk *srb,
-			    u16 * pscsi_status);
-static void data_in_phase1(struct AdapterCtlBlk *acb,
-			   struct ScsiReqBlk *srb,
-			   u16 * pscsi_status);
-static void command_phase1(struct AdapterCtlBlk *acb,
-			   struct ScsiReqBlk *srb,
-			   u16 * pscsi_status);
-static void status_phase1(struct AdapterCtlBlk *acb,
-			  struct ScsiReqBlk *srb,
-			  u16 * pscsi_status);
-static void msgout_phase1(struct AdapterCtlBlk *acb,
-			  struct ScsiReqBlk *srb,
-			  u16 * pscsi_status);
-static void msgin_phase1(struct AdapterCtlBlk *acb,
-			 struct ScsiReqBlk *srb,
-			 u16 * pscsi_status);
+static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
 static void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
-		 u16 * pscsi_status);
-static void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
-		 u16 * pscsi_status);
+		u16 *pscsi_status);
+static void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 
+		u16 *pscsi_status);
 static void set_basic_config(struct AdapterCtlBlk *acb);
 static void cleanup_after_transfer(struct AdapterCtlBlk *acb,
-				   struct ScsiReqBlk *srb);
+		struct ScsiReqBlk *srb);
 static void reset_scsi_bus(struct AdapterCtlBlk *acb);
 static void data_io_transfer(struct AdapterCtlBlk *acb,
-			     struct ScsiReqBlk *srb, u16 io_dir);
+		struct ScsiReqBlk *srb, u16 io_dir);
 static void disconnect(struct AdapterCtlBlk *acb);
 static void reselect(struct AdapterCtlBlk *acb);
 static u8 start_scsi(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
-		     struct ScsiReqBlk *srb);
-static void build_srb(Scsi_Cmnd * cmd, struct DeviceCtlBlk *dcb,
-		      struct ScsiReqBlk *srb);
+		struct ScsiReqBlk *srb);
+static void build_srb(Scsi_Cmnd *cmd, struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb);
 static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_code,
-			   Scsi_Cmnd * cmd, u8 force);
+		Scsi_Cmnd *cmd, u8 force);
 static void scsi_reset_detect(struct AdapterCtlBlk *acb);
-static void pci_unmap_srb(struct AdapterCtlBlk *acb,
-			  struct ScsiReqBlk *srb);
+static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb);
 static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb,
-				struct ScsiReqBlk *srb);
+		struct ScsiReqBlk *srb);
 static inline void enable_msgout_abort(struct AdapterCtlBlk *acb,
-				       struct ScsiReqBlk *srb);
-static void srb_done(struct AdapterCtlBlk *acb,
-		     struct DeviceCtlBlk *dcb,
-		     struct ScsiReqBlk *srb);
-static void request_sense(struct AdapterCtlBlk *acb,
-			  struct DeviceCtlBlk *dcb,
-			  struct ScsiReqBlk *srb);
+		struct ScsiReqBlk *srb);
+static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb);
+static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb);
 static inline void set_xfer_rate(struct AdapterCtlBlk *acb,
-				 struct DeviceCtlBlk *dcb);
+		struct DeviceCtlBlk *dcb);
 static void waiting_timeout(unsigned long ptr);
 
 
@@ -504,11 +395,7 @@ static void waiting_timeout(unsigned lon
                                  Static Data
  ---------------------------------------------------------------------------*/
 static u16 current_sync_offset = 0;
-static char monitor_next_irq = 0;
 
-/* 
- * dc395x_statev = (void *)dc395x_scsi_phase0[phase]
- */
 static void *dc395x_scsi_phase0[] = {
 	data_out_phase0,/* phase:0 */
 	data_in_phase0,	/* phase:1 */
@@ -520,9 +407,6 @@ static void *dc395x_scsi_phase0[] = {
 	msgin_phase0,	/* phase:7 */
 };
 
-/*
- * dc395x_statev = (void *)dc395x_scsi_phase1[phase]
- */
 static void *dc395x_scsi_phase1[] = {
 	data_out_phase1,/* phase:0 */
 	data_in_phase1,	/* phase:1 */
@@ -558,8 +442,6 @@ static void *dc395x_scsi_phase1[] = {
 /* real period:48ns,76ns,100ns,124ns,148ns,176ns,200ns,248ns */
 static u8 clock_period[] = { 12, 18, 25, 31, 37, 43, 50, 62 };
 static u16 clock_speed[] = { 200, 133, 100, 80, 67, 58, 50, 40 };
-/* real period:48ns,72ns,100ns,124ns,148ns,172ns,200ns,248ns */
-
 
 
 /*---------------------------------------------------------------------------
@@ -655,8 +537,9 @@ static struct ParameterData __initdata c
 
 
 /*
- * Safe settings. If set to zero the the BIOS/default values with command line
- * overrides will be used. If set to 1 then safe and slow settings will be used.
+ * Safe settings. If set to zero the the BIOS/default values with
+ * command line overrides will be used. If set to 1 then safe and
+ * slow settings will be used.
  */
 static int use_safe_settings = 0;
 module_param_named(safe, use_safe_settings, bool, 0);
@@ -686,8 +569,7 @@ MODULE_PARM_DESC(reset_delay, "Reset del
  * set_safe_settings - if the use_safe_settings option is set then
  * set all values to the safe and slow values.
  **/
-static
-void __init set_safe_settings(void)
+static void __init set_safe_settings(void)
 {
 	if (use_safe_settings)
 	{
@@ -706,25 +588,24 @@ void __init set_safe_settings(void)
  * fix_settings - reset any boot parameters which are out of range
  * back to the default values.
  **/
-static
-void __init fix_settings(void)
+static void __init fix_settings(void)
 {
 	int i;
 
-	dprintkdbg(DBG_PARSE, "setup %08x %08x %08x %08x %08x %08x\n",
-		    cfg_data[CFG_ADAPTER_ID].value,
-		    cfg_data[CFG_MAX_SPEED].value,
-		    cfg_data[CFG_DEV_MODE].value,
-		    cfg_data[CFG_ADAPTER_MODE].value,
-		    cfg_data[CFG_TAGS].value,
-		    cfg_data[CFG_RESET_DELAY].value);
+	dprintkdbg(DBG_1,
+		"setup: AdapterId=%08x MaxSpeed=%08x DevMode=%08x "
+		"AdapterMode=%08x Tags=%08x ResetDelay=%08x\n",
+		cfg_data[CFG_ADAPTER_ID].value,
+		cfg_data[CFG_MAX_SPEED].value,
+		cfg_data[CFG_DEV_MODE].value,
+		cfg_data[CFG_ADAPTER_MODE].value,
+		cfg_data[CFG_TAGS].value,
+		cfg_data[CFG_RESET_DELAY].value);
 	for (i = 0; i < CFG_NUM; i++)
 	{
-		if (cfg_data[i].value < cfg_data[i].min ||
-			cfg_data[i].value > cfg_data[i].max)
-		{
+		if (cfg_data[i].value < cfg_data[i].min
+		    || cfg_data[i].value > cfg_data[i].max)
 			cfg_data[i].value = cfg_data[i].def;
-		}
 	}
 }
 
@@ -734,8 +615,8 @@ void __init fix_settings(void)
  * Mapping from the eeprom delay index value (index into this array)
  * to the the number of actual seconds that the delay should be for.
  */
-static
-char __initdata eeprom_index_to_delay_map[] = { 1, 3, 5, 10, 16, 30, 60, 120 };
+static char __initdata eeprom_index_to_delay_map[] = 
+	{ 1, 3, 5, 10, 16, 30, 60, 120 };
 
 
 /**
@@ -744,25 +625,24 @@ char __initdata eeprom_index_to_delay_ma
  *
  * @eeprom: The eeprom structure in which we find the delay index to map.
  **/
-static
-void __init eeprom_index_to_delay(struct NvRamType *eeprom)
+static void __init eeprom_index_to_delay(struct NvRamType *eeprom)
 {
 	eeprom->delay_time = eeprom_index_to_delay_map[eeprom->delay_time];
 }
 
 
 /**
- * delay_to_eeprom_index - Take a delay in seconds and return the closest
- * eeprom index which will delay for at least that amount of seconds.
+ * delay_to_eeprom_index - Take a delay in seconds and return the
+ * closest eeprom index which will delay for at least that amount of
+ * seconds.
  *
  * @delay: The delay, in seconds, to find the eeprom index for.
  **/
 static int __init delay_to_eeprom_index(int delay)
 {
 	u8 idx = 0;
-	while (idx < 7 && eeprom_index_to_delay_map[idx] < delay) {
+	while (idx < 7 && eeprom_index_to_delay_map[idx] < delay)
 		idx++;
-	}
 	return idx;
 }
 
@@ -774,38 +654,34 @@ static int __init delay_to_eeprom_index(
  *
  * @eeprom: The eeprom data to override with command line options.
  **/
-static
-void __init eeprom_override(struct NvRamType *eeprom)
+static void __init eeprom_override(struct NvRamType *eeprom)
 {
 	u8 id;
 
 	/* Adapter Settings */
-	if (cfg_data[CFG_ADAPTER_ID].value != CFG_PARAM_UNSET) {
-		eeprom->scsi_id =
-		    (u8)cfg_data[CFG_ADAPTER_ID].value;
-	}
-	if (cfg_data[CFG_ADAPTER_MODE].value != CFG_PARAM_UNSET) {
-		eeprom->channel_cfg =
-		    (u8)cfg_data[CFG_ADAPTER_MODE].value;
-	}
-	if (cfg_data[CFG_RESET_DELAY].value != CFG_PARAM_UNSET) {
-		eeprom->delay_time =
-		    delay_to_eeprom_index(cfg_data[CFG_RESET_DELAY].value);
-	}
-	if (cfg_data[CFG_TAGS].value != CFG_PARAM_UNSET) {
+	if (cfg_data[CFG_ADAPTER_ID].value != CFG_PARAM_UNSET)
+		eeprom->scsi_id = (u8)cfg_data[CFG_ADAPTER_ID].value;
+
+	if (cfg_data[CFG_ADAPTER_MODE].value != CFG_PARAM_UNSET)
+		eeprom->channel_cfg = (u8)cfg_data[CFG_ADAPTER_MODE].value;
+
+	if (cfg_data[CFG_RESET_DELAY].value != CFG_PARAM_UNSET)
+		eeprom->delay_time = delay_to_eeprom_index(
+					cfg_data[CFG_RESET_DELAY].value);
+
+	if (cfg_data[CFG_TAGS].value != CFG_PARAM_UNSET)
 		eeprom->max_tag = (u8)cfg_data[CFG_TAGS].value;
-	}
 
 	/* Device Settings */
 	for (id = 0; id < DC395x_MAX_SCSI_ID; id++) {
-		if (cfg_data[CFG_DEV_MODE].value != CFG_PARAM_UNSET) {
+		if (cfg_data[CFG_DEV_MODE].value != CFG_PARAM_UNSET)
 			eeprom->target[id].cfg0 =
-			    (u8)cfg_data[CFG_DEV_MODE].value;
-		}
-		if (cfg_data[CFG_MAX_SPEED].value != CFG_PARAM_UNSET) {
+				(u8)cfg_data[CFG_DEV_MODE].value;
+
+		if (cfg_data[CFG_MAX_SPEED].value != CFG_PARAM_UNSET)
 			eeprom->target[id].period =
-			    (u8)cfg_data[CFG_MAX_SPEED].value;
-		}
+				(u8)cfg_data[CFG_MAX_SPEED].value;
+
 	}
 }
 
@@ -813,39 +689,21 @@ void __init eeprom_override(struct NvRam
 /*---------------------------------------------------------------------------
  ---------------------------------------------------------------------------*/
 
-/**
- * list_size - Returns the size (in number of entries) of the
- * supplied list.
- *
- * @head: The pointer to the head of the list to count the items in.
- **/
-static
-unsigned int list_size(struct list_head *head)
+static unsigned int list_size(struct list_head *head)
 {
 	unsigned int count = 0;
 	struct list_head *pos;
 	list_for_each(pos, head)
 		count++;
 	return count;
-}                                                                                        
+}
 
 
-/**
- * dcb_get_next - Given a dcb return the next dcb in the list of
- * dcb's, wrapping back to the start of the dcb list if required.
- * Returns the supplied dcb if there is only one dcb in the list.
- *
- * @head: The pointer to the head of the list to count the items in.
- * @pos: The pointer the dcb for which we are searching for the
- *       following dcb.
- **/
-static
-struct DeviceCtlBlk *dcb_get_next(
-		struct list_head *head,
+static struct DeviceCtlBlk *dcb_get_next(struct list_head *head,
 		struct DeviceCtlBlk *pos)
 {
 	int use_next = 0;
-	struct DeviceCtlBlk* next = NULL;	
+	struct DeviceCtlBlk* next = NULL;
 	struct DeviceCtlBlk* i;
 
 	if (list_empty(head))
@@ -870,22 +728,7 @@ struct DeviceCtlBlk *dcb_get_next(
 }
 
 
-/*
- * Queueing philosphy:
- * There are a couple of lists:
- * - Waiting: Contains a list of SRBs not yet sent (per DCB)
- * - Free: List of free SRB slots
- * 
- * If there are no waiting commands for the DCB, the new one is sent to the bus
- * otherwise the oldest one is taken from the Waiting list and the new one is 
- * queued to the Waiting List
- * 
- * Lists are managed using two pointers and eventually a counter
- */
-
-/* Nomen est omen ... */
-static inline
-void free_tag(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
+static void free_tag(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
 {
 	if (srb->tag_number < 255) {
 		dcb->tag_mask &= ~(1 << srb->tag_number);	/* free tag mask */
@@ -895,9 +738,8 @@ void free_tag(struct DeviceCtlBlk *dcb, 
 
 
 /* Find cmd in SRB list */
-inline static
-struct ScsiReqBlk *find_cmd(Scsi_Cmnd *cmd,
-			    struct list_head *head)
+inline static struct ScsiReqBlk *find_cmd(Scsi_Cmnd *cmd, 
+		struct list_head *head)
 {
 	struct ScsiReqBlk *i;
 	list_for_each_entry(i, head, list)
@@ -907,88 +749,59 @@ struct ScsiReqBlk *find_cmd(Scsi_Cmnd *c
 }
 
 
-/*
- * srb_get_free - Return a free srb from the list of free SRBs that
- * is stored with the acb.
- */
-static
-struct ScsiReqBlk *srb_get_free(struct AdapterCtlBlk *acb)
+static struct ScsiReqBlk *srb_get_free(struct AdapterCtlBlk *acb)
 {
 	struct list_head *head = &acb->srb_free_list;
-	struct ScsiReqBlk *srb;
+	struct ScsiReqBlk *srb = NULL;
 
 	if (!list_empty(head)) {
 		srb = list_entry(head->next, struct ScsiReqBlk, list);
 		list_del(head->next);
-		dprintkdbg(DBG_0, "srb_get_free: got srb %p\n", srb);
-	} else {
-		srb = NULL;
-		dprintkl(KERN_ERR, "Out of Free SRBs :-(\n");
+		dprintkdbg(DBG_0, "srb_get_free: srb=%p\n", srb);
 	}
 	return srb;
 }
 
 
-/*
- * srb_free_insert - Insert an srb to the head of the free list
- * stored in the acb.
- */
-static
-void srb_free_insert(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
+static void srb_free_insert(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
 {
-	dprintkdbg(DBG_0, "srb_free_insert: put srb %p\n", srb);
-        list_add_tail(&srb->list, &acb->srb_free_list);
+	dprintkdbg(DBG_0, "srb_free_insert: srb=%p\n", srb);
+	list_add_tail(&srb->list, &acb->srb_free_list);
 }
 
 
-/*
- * srb_waiting_insert - Insert an srb to the head of the wiating list
- * stored in the dcb.
- */
-static
-void srb_waiting_insert(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
+static void srb_waiting_insert(struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb)
 {
-	dprintkdbg(DBG_0, "srb_waiting_insert: srb %p cmd %li\n", srb, srb->cmd->pid);
-        list_add(&srb->list, &dcb->srb_waiting_list);
+	dprintkdbg(DBG_0, "srb_waiting_insert: (pid#%li) <%02i-%i> srb=%p\n",
+		srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+	list_add(&srb->list, &dcb->srb_waiting_list);
 }
 
 
-/*
- * srb_waiting_append - Append an srb to the tail of the waiting list
- * stored in the dcb.
- */
-static inline
-void srb_waiting_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
+static void srb_waiting_append(struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb)
 {
-	dprintkdbg(DBG_0, "srb_waiting_append: srb %p cmd %li\n", srb, srb->cmd->pid);
-        list_add_tail(&srb->list, &dcb->srb_waiting_list);
+	dprintkdbg(DBG_0, "srb_waiting_append: (pid#%li) <%02i-%i> srb=%p\n",
+		 srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+	list_add_tail(&srb->list, &dcb->srb_waiting_list);
 }
 
 
-/*
- * srb_going_append - Append an srb to the tail of the going list
- * stored in the dcb.
- */
-static inline
-void srb_going_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
+static void srb_going_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
 {
-	dprintkdbg(DBG_0, "srb_going_append: srb %p\n", srb);
-        list_add_tail(&srb->list, &dcb->srb_going_list);
+	dprintkdbg(DBG_0, "srb_going_append: (pid#%li) <%02i-%i> srb=%p\n",
+		srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+	list_add_tail(&srb->list, &dcb->srb_going_list);
 }
 
 
-
-/*
- * srb_going_remove - Remove an srb from the going list stored in the
- * dcb.
- */
-static
-void srb_going_remove(struct DeviceCtlBlk *dcb,
-		      struct ScsiReqBlk *srb)
+static void srb_going_remove(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
 {
 	struct ScsiReqBlk *i;
 	struct ScsiReqBlk *tmp;
-	dprintkdbg(DBG_0, "srb_going_remove: srb %p\n", srb);
+	dprintkdbg(DBG_0, "srb_going_remove: (pid#%li) <%02i-%i> srb=%p\n",
+		srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
 
 	list_for_each_entry_safe(i, tmp, &dcb->srb_going_list, list)
 		if (i == srb) {
@@ -998,17 +811,13 @@ void srb_going_remove(struct DeviceCtlBl
 }
 
 
-/*
- * srb_waiting_remove - Remove an srb from the waiting list stored in the
- * dcb.
- */
-static
-void srb_waiting_remove(struct DeviceCtlBlk *dcb,
-			struct ScsiReqBlk *srb)
+static void srb_waiting_remove(struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb)
 {
 	struct ScsiReqBlk *i;
 	struct ScsiReqBlk *tmp;
-	dprintkdbg(DBG_0, "srb_waiting_remove: srb %p\n", srb);
+	dprintkdbg(DBG_0, "srb_waiting_remove: (pid#%li) <%02i-%i> srb=%p\n",
+		srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
 
 	list_for_each_entry_safe(i, tmp, &dcb->srb_waiting_list, list)
 		if (i == srb) {
@@ -1018,37 +827,28 @@ void srb_waiting_remove(struct DeviceCtl
 }
 
 
-/*
- * srb_going_to_waiting_move - Remove an srb from the going list in
- * the dcb and insert it at the head of the waiting list in the dcb.
- */
-static
-void srb_going_to_waiting_move(struct DeviceCtlBlk *dcb,
-			       struct ScsiReqBlk *srb)
+static void srb_going_to_waiting_move(struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb)
 {
-	dprintkdbg(DBG_0, "srb_going_waiting_move: srb %p, pid = %li\n", srb, srb->cmd->pid);
+	dprintkdbg(DBG_0,
+		"srb_going_to_waiting_move: (pid#%li) <%02i-%i> srb=%p\n",
+		srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
 	list_move(&srb->list, &dcb->srb_waiting_list);
 }
 
 
-/*
- * srb_waiting_to_going_move - Remove an srb from the waiting list in
- * the dcb and insert it at the head of the going list in the dcb.
- */
-static
-void srb_waiting_to_going_move(struct DeviceCtlBlk *dcb,
-			       struct ScsiReqBlk *srb)
-{
-	/* Remove from waiting list */
-	dprintkdbg(DBG_0, "srb_waiting_to_going: srb %p\n", srb);
-	TRACEPRINTF("WtG *");
+static void srb_waiting_to_going_move(struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb)
+{
+	dprintkdbg(DBG_0,
+		"srb_waiting_to_going_move: (pid#%li) <%02i-%i> srb=%p\n",
+		srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
 	list_move(&srb->list, &dcb->srb_going_list);
 }
 
 
 /* Sets the timer to wake us up */
-static
-void waiting_set_timer(struct AdapterCtlBlk *acb, unsigned long to)
+static void waiting_set_timer(struct AdapterCtlBlk *acb, unsigned long to)
 {
 	if (timer_pending(&acb->waiting_timer))
 		return;
@@ -1065,8 +865,7 @@ void waiting_set_timer(struct AdapterCtl
 
 
 /* Send the next command from the waiting list to the bus */
-static
-void waiting_process_next(struct AdapterCtlBlk *acb)
+static void waiting_process_next(struct AdapterCtlBlk *acb)
 {
 	struct DeviceCtlBlk *start = NULL;
 	struct DeviceCtlBlk *pos;
@@ -1074,7 +873,7 @@ void waiting_process_next(struct Adapter
 	struct ScsiReqBlk *srb;
 	struct list_head *dcb_list_head = &acb->dcb_list;
 
-	if ((acb->active_dcb)
+	if (acb->active_dcb
 	    || (acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV)))
 		return;
 
@@ -1135,8 +934,9 @@ void waiting_process_next(struct Adapter
 static void waiting_timeout(unsigned long ptr)
 {
 	unsigned long flags;
-	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *) ptr;
-	dprintkdbg(DBG_KG, "Debug: Waiting queue woken up by timer.\n");
+	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)ptr;
+	dprintkdbg(DBG_1,
+		"waiting_timeout: Queue woken up by timer. acb=%p\n", acb);
 	DC395x_LOCK_IO(acb->scsi_host, flags);
 	waiting_process_next(acb);
 	DC395x_UNLOCK_IO(acb->scsi_host, flags);
@@ -1144,28 +944,17 @@ static void waiting_timeout(unsigned lon
 
 
 /* Get the DCB for a given ID/LUN combination */
-static inline
-struct DeviceCtlBlk *find_dcb(struct AdapterCtlBlk *acb, u8 id, u8 lun)
+static struct DeviceCtlBlk *find_dcb(struct AdapterCtlBlk *acb, u8 id, u8 lun)
 {
 	return acb->children[id][lun];
 }
 
 
-/***********************************************************************
- * Function: static void send_srb (struct AdapterCtlBlk* acb, struct ScsiReqBlk* srb)
- *
- * Purpose: Send SCSI Request Block (srb) to adapter (acb)
- *
- *            dc395x_queue_command
- *            waiting_process_next
- *
- ***********************************************************************/
-static
-void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
+/* Send SCSI Request Block (srb) to adapter (acb) */
+static void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
 {
-	struct DeviceCtlBlk *dcb;
+	struct DeviceCtlBlk *dcb = srb->dcb;
 
-	dcb = srb->dcb;
 	if (dcb->max_command <= list_size(&dcb->srb_going_list) ||
 	    acb->active_dcb ||
 	    (acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV))) {
@@ -1174,130 +963,29 @@ void send_srb(struct AdapterCtlBlk *acb,
 		return;
 	}
 
-	if (!start_scsi(acb, dcb, srb)) {
+	if (!start_scsi(acb, dcb, srb))
 		srb_going_append(dcb, srb);
-	} else {
+	else {
 		srb_waiting_insert(dcb, srb);
 		waiting_set_timer(acb, HZ / 50);
 	}
 }
 
 
-/*
- *********************************************************************
- *
- * Function: static void build_srb (Scsi_Cmd *cmd, struct DeviceCtlBlk* dcb, struct ScsiReqBlk* srb)
- *
- *  Purpose: Prepare SRB for being sent to Device DCB w/ command *cmd
- *
- *********************************************************************
- */
-static
-void build_srb(Scsi_Cmnd * cmd, struct DeviceCtlBlk *dcb,
-	       struct ScsiReqBlk *srb)
-{
-	int i, max;
-	struct SGentry *sgp;
-	struct scatterlist *sl;
-	u32 request_size;
-	int dir;
+/* Prepare SRB for being sent to Device DCB w/ command *cmd */
+static void build_srb(Scsi_Cmnd *cmd, struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb)
+{
+	int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+	dprintkdbg(DBG_0, "build_srb: (pid#%li) <%02i-%i>\n",
+		cmd->pid, dcb->target_id, dcb->target_lun);
 
-	dprintkdbg(DBG_0, "build_srb..............\n");
-	/*memset (srb, 0, sizeof (struct ScsiReqBlk)); */
 	srb->dcb = dcb;
 	srb->cmd = cmd;
-	/* Find out about direction */
-	dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
-
-	if (cmd->use_sg && dir != PCI_DMA_NONE) {
-		unsigned int len = 0;
-		/* TODO: In case usg_sg and the no of segments differ, things
-		 * will probably go wrong. */
-		max = srb->sg_count =
-		    pci_map_sg(dcb->acb->dev,
-			       (struct scatterlist *) cmd->request_buffer,
-			       cmd->use_sg, dir);
-		sgp = srb->segment_x;
-		request_size = cmd->request_bufflen;
-		dprintkdbg(DBG_SGPARANOIA, 
-		       "BuildSRB: Bufflen = %d, buffer = %p, use_sg = %d\n",
-		       cmd->request_bufflen, cmd->request_buffer,
-		       cmd->use_sg);
-		dprintkdbg(DBG_SGPARANOIA, 
-		       "Mapped %i Segments to %i\n", cmd->use_sg,
-		       srb->sg_count);
-		sl = (struct scatterlist *) cmd->request_buffer;
-
-		srb->virt_addr = page_address(sl->page);
-		for (i = 0; i < max; i++) {
-			u32 busaddr = (u32) sg_dma_address(&sl[i]);
-			u32 seglen = (u32) sl[i].length;
-			sgp[i].address = busaddr;
-			sgp[i].length = seglen;
-			len += seglen;
-			dprintkdbg(DBG_SGPARANOIA,
-			       "Setting up sgp %d, address = 0x%08x, length = %d, tot len = %d\n",
-			       i, busaddr, seglen, len);
-		}
-		sgp += max - 1;
-		/* Fixup for last buffer too big as it is allocated on even page boundaries */
-		if (len > request_size) {
-#if debug_enabled(DBG_KG) || debug_enabled(DBG_SGPARANOIA)
-			dprintkdbg(DBG_KG|DBG_SGPARANOIA,
-			       "Fixup SG total length: %d->%d, last seg %d->%d\n",
-			       len, request_size, sgp->length,
-			       sgp->length - (len - request_size));
-#endif
-			sgp->length -= (len - request_size);
-			len = request_size;
-		}
-		/* WIDE padding */
-		if (dcb->sync_period & WIDE_SYNC && len % 2) {
-			len++;
-			sgp->length++;
-		}
-		srb->total_xfer_length = len;	/*? */
-		/* Hopefully this does not cross a page boundary ... */
-		srb->sg_bus_addr =
-		    pci_map_single(dcb->acb->dev, srb->segment_x,
-				   sizeof(struct SGentry) *
-				   DC395x_MAX_SG_LISTENTRY,
-				   PCI_DMA_TODEVICE);
-		dprintkdbg(DBG_SGPARANOIA,
-		       "Map SG descriptor list %p (%05x) to %08x\n",
-		       srb->segment_x,
-		       sizeof(struct SGentry) * DC395x_MAX_SG_LISTENTRY,
-		       srb->sg_bus_addr);
-	} else {
-		if (cmd->request_buffer && dir != PCI_DMA_NONE) {
-			u32 len = cmd->request_bufflen;	/* Actual request size */
-			srb->sg_count = 1;
-			srb->segment_x[0].address =
-			    pci_map_single(dcb->acb->dev,
-					   cmd->request_buffer, len, dir);
-			/* WIDE padding */
-			if (dcb->sync_period & WIDE_SYNC && len % 2)
-				len++;
-			srb->segment_x[0].length = len;
-			srb->total_xfer_length = len;
-			srb->virt_addr = cmd->request_buffer;
-			srb->sg_bus_addr = 0;
-			dprintkdbg(DBG_SGPARANOIA,
-			       "BuildSRB: len = %d, buffer = %p, use_sg = %d, map %08x\n",
-			       len, cmd->request_buffer, cmd->use_sg,
-			       srb->segment_x[0].address);
-		} else {
-			srb->sg_count = 0;
-			srb->total_xfer_length = 0;
-			srb->sg_bus_addr = 0;
-			srb->virt_addr = 0;
-			dprintkdbg(DBG_SGPARANOIA,
-			       "BuildSRB: buflen = %d, buffer = %p, use_sg = %d, NOMAP %08x\n",
-			       cmd->bufflen, cmd->request_buffer,
-			       cmd->use_sg, srb->segment_x[0].address);
-		}
-	}
-
+	srb->sg_count = 0;
+	srb->total_xfer_length = 0;
+	srb->sg_bus_addr = 0;
+	srb->virt_addr = 0;
 	srb->sg_index = 0;
 	srb->adapter_status = 0;
 	srb->target_status = 0;
@@ -1306,29 +994,80 @@ void build_srb(Scsi_Cmnd * cmd, struct D
 	srb->flag = 0;
 	srb->state = 0;
 	srb->retry_count = 0;
-
-#if debug_enabled(DBG_TRACE|DBG_TRACEALL) && debug_enabled(DBG_SGPARANOIA)
-	if ((unsigned long)srb->debugtrace & (DEBUGTRACEBUFSZ - 1)) {
-		dprintkdbg(DBG_SGPARANOIA,
-			"SRB %i (%p): debugtrace %p corrupt!\n",
-		       (srb - dcb->acb->srb_array) /
-		       sizeof(struct ScsiReqBlk), srb, srb->debugtrace);
-	}
-#endif
-#if debug_enabled(DBG_TRACE|DBG_TRACEALL)
-	srb->debugpos = 0;
-	srb->debugtrace = 0;
-#endif
-	TRACEPRINTF("pid %li(%li):%02x %02x..(%i-%i) *", cmd->pid,
-		    jiffies, cmd->cmnd[0], cmd->cmnd[1],
-		    cmd->device->id, cmd->device->lun);
 	srb->tag_number = TAG_NONE;
-
 	srb->scsi_phase = PH_BUS_FREE;	/* initial phase */
 	srb->end_message = 0;
-	return;
-}
 
+	if (dir == PCI_DMA_NONE || !cmd->request_buffer) {
+		dprintkdbg(DBG_0,
+			"build_srb: [0] len=%d buf=%p use_sg=%d !MAP=%08x\n",
+			cmd->bufflen, cmd->request_buffer,
+			cmd->use_sg, srb->segment_x[0].address);
+	} else if (cmd->use_sg) {
+		int i;
+		u32 reqlen = cmd->request_bufflen;
+		struct scatterlist *sl = (struct scatterlist *)
+					 cmd->request_buffer;
+		struct SGentry *sgp = srb->segment_x;
+		srb->sg_count = pci_map_sg(dcb->acb->dev, sl, cmd->use_sg,
+					   dir);
+		dprintkdbg(DBG_0,
+			"build_srb: [n] len=%d buf=%p use_sg=%d segs=%d\n",
+			reqlen, cmd->request_buffer, cmd->use_sg,
+			srb->sg_count);
+
+		srb->virt_addr = page_address(sl->page);
+		for (i = 0; i < srb->sg_count; i++) {
+			u32 busaddr = (u32)sg_dma_address(&sl[i]);
+			u32 seglen = (u32)sl[i].length;
+			sgp[i].address = busaddr;
+			sgp[i].length = seglen;
+			srb->total_xfer_length += seglen;
+		}
+		sgp += srb->sg_count - 1;
+
+		/*
+		 * adjust last page if too big as it is allocated
+		 * on even page boundaries
+		 */
+		if (srb->total_xfer_length > reqlen) {
+			sgp->length -= (srb->total_xfer_length - reqlen);
+			srb->total_xfer_length = reqlen;
+		}
+
+		/* Fixup for WIDE padding - make sure length is even */
+		if (dcb->sync_period & WIDE_SYNC &&
+		    srb->total_xfer_length % 2) {
+			srb->total_xfer_length++;
+			sgp->length++;
+		}
+
+		srb->sg_bus_addr = pci_map_single(dcb->acb->dev,
+						srb->segment_x,
+				            	SEGMENTX_LEN,
+				            	PCI_DMA_TODEVICE);
+
+		dprintkdbg(DBG_SG, "build_srb: [n] map sg %p->%08x(%05x)\n",
+			srb->segment_x, srb->sg_bus_addr, SEGMENTX_LEN);
+	} else {
+		srb->total_xfer_length = cmd->request_bufflen;
+		srb->sg_count = 1;
+		srb->segment_x[0].address =
+			pci_map_single(dcb->acb->dev, cmd->request_buffer,
+				       srb->total_xfer_length, dir);
+
+		/* Fixup for WIDE padding - make sure length is even */
+		if (dcb->sync_period & WIDE_SYNC && srb->total_xfer_length % 2)
+			srb->total_xfer_length++;
+
+		srb->segment_x[0].length = srb->total_xfer_length;
+		srb->virt_addr = cmd->request_buffer;
+		dprintkdbg(DBG_0,
+			"build_srb: [1] len=%d buf=%p use_sg=%d map=%08x\n",
+			srb->total_xfer_length, cmd->request_buffer,
+			cmd->use_sg, srb->segment_x[0].address);
+	}
+}
 
 
 /**
@@ -1350,27 +1089,14 @@ void build_srb(Scsi_Cmnd * cmd, struct D
  *        and is expected to be held on return.
  *
  **/
-static int
-dc395x_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+static int dc395x_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 {
 	struct DeviceCtlBlk *dcb;
 	struct ScsiReqBlk *srb;
 	struct AdapterCtlBlk *acb =
 	    (struct AdapterCtlBlk *)cmd->device->host->hostdata;
-
-	dprintkdbg(DBG_0, "Queue Cmd=%02x,Tgt=%d,LUN=%d (pid=%li)\n",
-		   cmd->cmnd[0],
-		   cmd->device->id,
-		   cmd->device->lun,
-		   cmd->pid);
-
-#if debug_enabled(DBG_RECURSION)
-	if (dbg_in_driver++ > NORM_REC_LVL) {
-		dprintkl(KERN_DEBUG,
-			"%i queue_command () recursion? (pid=%li)\n",
-			dbg_in_driver, cmd->pid);
-	}
-#endif
+	dprintkdbg(DBG_0, "queue_command: (pid#%li) <%02i-%i> cmnd=0x%02x\n",
+		cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
 
 	/* Assume BAD_TARGET; will be cleared later */
 	cmd->result = DID_BAD_TARGET << 16;
@@ -1384,8 +1110,8 @@ dc395x_queue_command(Scsi_Cmnd *cmd, voi
 
 	/* does the specified lun on the specified device exist */
 	if (!(acb->dcb_map[cmd->device->id] & (1 << cmd->device->lun))) {
-		dprintkl(KERN_INFO, "Ignore target %02x lun %02x\n", cmd->device->id,
-		       cmd->device->lun);
+		dprintkl(KERN_INFO, "queue_command: Ignore target <%02i-%i>\n",
+			cmd->device->id, cmd->device->lun);
 		goto complete;
 	}
 
@@ -1393,9 +1119,8 @@ dc395x_queue_command(Scsi_Cmnd *cmd, voi
 	dcb = find_dcb(acb, cmd->device->id, cmd->device->lun);
 	if (!dcb) {
 		/* should never happen */
-		dprintkl(KERN_ERR, "no DCB failed, target %02x lun %02x\n",
-				   cmd->device->id, cmd->device->lun);
-		dprintkl(KERN_ERR, "No DCB in queuecommand (2)!\n");
+		dprintkl(KERN_ERR, "queue_command: No such device <%02i-%i>",
+			cmd->device->id, cmd->device->lun);
 		goto complete;
 	}
 
@@ -1403,7 +1128,6 @@ dc395x_queue_command(Scsi_Cmnd *cmd, voi
 	cmd->scsi_done = done;
 	cmd->result = 0;
 
-	/* get a free SRB */
 	srb = srb_get_free(acb);
 	if (!srb)
 	{
@@ -1411,11 +1135,10 @@ dc395x_queue_command(Scsi_Cmnd *cmd, voi
 		 * Return 1 since we are unable to queue this command at this
 		 * point in time.
 		 */
-		dprintkdbg(DBG_0, "No free SRB's in queuecommand\n");
+		dprintkdbg(DBG_0, "queue_command: No free srb's\n");
 		return 1;
 	}
 
-	/* build srb for the command */
 	build_srb(cmd, dcb, srb);
 
 	if (!list_empty(&dcb->srb_waiting_list)) {
@@ -1426,11 +1149,7 @@ dc395x_queue_command(Scsi_Cmnd *cmd, voi
 		/* process immediately */
 		send_srb(acb, srb);
 	}
-	dprintkdbg(DBG_1, "... command (pid %li) queued successfully.\n", cmd->pid);
-
-#if debug_enabled(DBG_RECURSION)
-	dbg_in_driver--
-#endif
+	dprintkdbg(DBG_1, "queue_command: (pid#%li) done\n", cmd->pid);
 	return 0;
 
 complete:
@@ -1440,28 +1159,16 @@ complete:
 	 * done when the commad is for things like non existent
 	 * devices.
 	 */
-#if debug_enabled(DBG_RECURSION)
-		dbg_in_driver--
-#endif
 	done(cmd);
 	return 0;
 }
 
 
-
-
 /*
- *********************************************************************
- *
- * Function   : dc395x_bios_param
- * Description: Return the disk geometry for the given SCSI device.
- *********************************************************************
+ * Return the disk geometry for the given SCSI device.
  */
-static
-int dc395x_bios_param(struct scsi_device *sdev,
-		      struct block_device *bdev,
-		      sector_t capacity,
-		      int *info)
+static int dc395x_bios_param(struct scsi_device *sdev,
+		struct block_device *bdev, sector_t capacity, int *info)
 {
 #ifdef CONFIG_SCSI_DC395x_TRMS1040_TRADMAP
 	int heads, sectors, cylinders;
@@ -1469,7 +1176,7 @@ int dc395x_bios_param(struct scsi_device
 	int size = capacity;
 
 	dprintkdbg(DBG_0, "dc395x_bios_param..............\n");
-	acb = (struct AdapterCtlBlk *) sdev->host->hostdata;
+	acb = (struct AdapterCtlBlk *)sdev->host->hostdata;
 	heads = 64;
 	sectors = 32;
 	cylinders = size / (heads * sectors);
@@ -1489,12 +1196,8 @@ int dc395x_bios_param(struct scsi_device
 }
 
 
-/*
- * DC395x register dump
- */
-static
-void dump_register_info(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
-			struct ScsiReqBlk *srb)
+static void dump_register_info(struct AdapterCtlBlk *acb,
+		struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
 {
 	u16 pstat;
 	struct pci_dev *dev = acb->dev;
@@ -1504,64 +1207,58 @@ void dump_register_info(struct AdapterCt
 	if (!srb && dcb)
 		srb = dcb->active_srb;
 	if (srb) {
-		if (!(srb->cmd))
-			dprintkl(KERN_INFO, "dump: SRB %p: cmd %p OOOPS!\n", srb,
-			       srb->cmd);
+		if (!srb->cmd)
+			dprintkl(KERN_INFO, "dump: srb=%p cmd=%p OOOPS!\n",
+				srb, srb->cmd);
 		else
-			dprintkl(KERN_INFO, "dump: SRB %p: cmd %p pid %li: %02x (%02i-%i)\n",
-			       srb, srb->cmd, srb->cmd->pid,
-			       srb->cmd->cmnd[0], srb->cmd->device->id,
-			       srb->cmd->device->lun);
-		printk("              SGList %p Cnt %i Idx %i Len %i\n",
+			dprintkl(KERN_INFO, "dump: srb=%p cmd=%p (pid#%li) "
+				 "cmnd=0x%02x <%02i-%i>\n",
+			    	srb, srb->cmd, srb->cmd->pid,
+				srb->cmd->cmnd[0], srb->cmd->device->id,
+			       	srb->cmd->device->lun);
+		printk("  sglist=%p cnt=%i idx=%i len=%i\n",
 		       srb->segment_x, srb->sg_count, srb->sg_index,
 		       srb->total_xfer_length);
-		printk
-		    ("              State %04x Status %02x Phase %02x (%sconn.)\n",
-		     srb->state, srb->status, srb->scsi_phase,
-		     (acb->active_dcb) ? "" : "not");
-		TRACEOUT("        %s\n", srb->debugtrace);
-	}
-	dprintkl(KERN_INFO, "dump: SCSI block\n");
-	printk
-	    ("              Status %04x FIFOCnt %02x Signals %02x IRQStat %02x\n",
-	     DC395x_read16(acb, TRM_S1040_SCSI_STATUS),
-	     DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
-	     DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL),
-	     DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS));
-	printk
-	    ("              Sync %02x Target %02x RSelID %02x SCSICtr %08x\n",
-	     DC395x_read8(acb, TRM_S1040_SCSI_SYNC),
-	     DC395x_read8(acb, TRM_S1040_SCSI_TARGETID),
-	     DC395x_read8(acb, TRM_S1040_SCSI_IDMSG),
-	     DC395x_read32(acb, TRM_S1040_SCSI_COUNTER));
-	printk
-	    ("              IRQEn %02x Config %04x Cfg2 %02x Cmd %02x SelTO %02x\n",
-	     DC395x_read8(acb, TRM_S1040_SCSI_INTEN),
-	     DC395x_read16(acb, TRM_S1040_SCSI_CONFIG0),
-	     DC395x_read8(acb, TRM_S1040_SCSI_CONFIG2),
-	     DC395x_read8(acb, TRM_S1040_SCSI_COMMAND),
-	     DC395x_read8(acb, TRM_S1040_SCSI_TIMEOUT));
-	dprintkl(KERN_INFO, "dump: DMA block\n");
-	printk
-	    ("              Cmd %04x FIFOCnt %02x FStat %02x IRQStat %02x IRQEn %02x Cfg %04x\n",
-	     DC395x_read16(acb, TRM_S1040_DMA_COMMAND),
-	     DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
-	     DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
-	     DC395x_read8(acb, TRM_S1040_DMA_STATUS),
-	     DC395x_read8(acb, TRM_S1040_DMA_INTEN),
-	     DC395x_read16(acb, TRM_S1040_DMA_CONFIG));
-	printk("              TCtr %08x CTCtr %08x Addr %08x%08x\n",
-	       DC395x_read32(acb, TRM_S1040_DMA_XCNT),
-	       DC395x_read32(acb, TRM_S1040_DMA_CXCNT),
-	       DC395x_read32(acb, TRM_S1040_DMA_XHIGHADDR),
-	       DC395x_read32(acb, TRM_S1040_DMA_XLOWADDR));
-	dprintkl(KERN_INFO, "dump: Misc: GCtrl %02x GStat %02x GTmr %02x\n",
-	       DC395x_read8(acb, TRM_S1040_GEN_CONTROL),
-	       DC395x_read8(acb, TRM_S1040_GEN_STATUS),
-	       DC395x_read8(acb, TRM_S1040_GEN_TIMER));
-	dprintkl(KERN_INFO, "dump: PCI Status %04x\n", pstat);
-
-
+		printk("  state=0x%04x status=0x%02x phase=0x%02x (%sconn.)\n",
+		       srb->state, srb->status, srb->scsi_phase,
+		       (acb->active_dcb) ? "" : "not");
+	}
+	dprintkl(KERN_INFO, "dump: SCSI{status=0x%04x fifocnt=0x%02x "
+		"signals=0x%02x irqstat=0x%02x sync=0x%02x target=0x%02x "
+		"rselid=0x%02x ctr=0x%08x irqen=0x%02x config=0x%04x "
+		"config2=0x%02x cmd=0x%02x selto=0x%02x}\n",
+		DC395x_read16(acb, TRM_S1040_SCSI_STATUS),
+		DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
+		DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL),
+		DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS),
+		DC395x_read8(acb, TRM_S1040_SCSI_SYNC),
+		DC395x_read8(acb, TRM_S1040_SCSI_TARGETID),
+		DC395x_read8(acb, TRM_S1040_SCSI_IDMSG),
+		DC395x_read32(acb, TRM_S1040_SCSI_COUNTER),
+		DC395x_read8(acb, TRM_S1040_SCSI_INTEN),
+		DC395x_read16(acb, TRM_S1040_SCSI_CONFIG0),
+		DC395x_read8(acb, TRM_S1040_SCSI_CONFIG2),
+		DC395x_read8(acb, TRM_S1040_SCSI_COMMAND),
+		DC395x_read8(acb, TRM_S1040_SCSI_TIMEOUT));
+	dprintkl(KERN_INFO, "dump: DMA{cmd=0x%04x fifocnt=0x%02x fstat=0x%02x "
+		"irqstat=0x%02x irqen=0x%02x cfg=0x%04x tctr=0x%08x "
+		"ctctr=0x%08x addr=0x%08x:0x%08x}\n",
+		DC395x_read16(acb, TRM_S1040_DMA_COMMAND),
+		DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
+		DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
+		DC395x_read8(acb, TRM_S1040_DMA_STATUS),
+		DC395x_read8(acb, TRM_S1040_DMA_INTEN),
+		DC395x_read16(acb, TRM_S1040_DMA_CONFIG),
+		DC395x_read32(acb, TRM_S1040_DMA_XCNT),
+		DC395x_read32(acb, TRM_S1040_DMA_CXCNT),
+		DC395x_read32(acb, TRM_S1040_DMA_XHIGHADDR),
+		DC395x_read32(acb, TRM_S1040_DMA_XLOWADDR));
+	dprintkl(KERN_INFO, "dump: gen{gctrl=0x%02x gstat=0x%02x gtmr=0x%02x} "
+		"pci{status=0x%04x}\n",
+		DC395x_read8(acb, TRM_S1040_GEN_CONTROL),
+		DC395x_read8(acb, TRM_S1040_GEN_STATUS),
+		DC395x_read8(acb, TRM_S1040_GEN_TIMER),
+		pstat);
 }
 
 
@@ -1572,32 +1269,19 @@ static inline void clear_fifo(struct Ada
 	u8 fifocnt = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT);
 	if (!(fifocnt & 0x40))
 		dprintkdbg(DBG_FIFO,
-		       "Clr FIFO (%i bytes) on phase %02x in %s\n",
+			"clear_fifo: (%i bytes) on phase %02x in %s\n",
 			fifocnt & 0x3f, lines, txt);
 #endif
-#if debug_enabled(DBG_TRACE)   
-	if (acb->active_dcb && acb->active_dcb->active_srb) {
-		struct ScsiReqBlk *srb = acb->active_dcb->active_srb;
-		TRACEPRINTF("#*");
-	}
-#endif
 	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO);
 }
 
 
-/*
- ********************************************************************
- *
- *		DC395x_reset      scsi_reset_detect
- *
- ********************************************************************
- */
 static void reset_dev_param(struct AdapterCtlBlk *acb)
 {
 	struct DeviceCtlBlk *dcb;
 	struct NvRamType *eeprom = &acb->eeprom;
+	dprintkdbg(DBG_0, "reset_dev_param: acb=%p\n", acb);
 
-	dprintkdbg(DBG_0, "reset_dev_param..............\n");
 	list_for_each_entry(dcb, &acb->dcb_list, list) {
 		u8 period_index;
 
@@ -1616,22 +1300,17 @@ static void reset_dev_param(struct Adapt
 
 
 /*
- *********************************************************************
- * Function : int dc395x_eh_bus_reset(Scsi_Cmnd *cmd)
- * Purpose  : perform a hard reset on the SCSI bus
- * Inputs   : cmd - some command for this host (for fetching hooks)
- * Returns  : SUCCESS (0x2002) on success, else FAILED (0x2003).
- *********************************************************************
+ * perform a hard reset on the SCSI bus
+ * @cmd - some command for this host (for fetching hooks)
+ * Returns: SUCCESS (0x2002) on success, else FAILED (0x2003).
  */
-static int dc395x_eh_bus_reset(Scsi_Cmnd * cmd)
+static int dc395x_eh_bus_reset(Scsi_Cmnd *cmd)
 {
-	struct AdapterCtlBlk *acb;
-	/*u32         acb_flags=0; */
-
-	dprintkl(KERN_INFO, "reset requested!\n");
-	acb = (struct AdapterCtlBlk *) cmd->device->host->hostdata;
-	/* mid level guarantees no recursion */
-	/*DC395x_ACB_LOCK(acb,acb_flags); */
+	struct AdapterCtlBlk *acb =
+		(struct AdapterCtlBlk *)cmd->device->host->hostdata;
+	dprintkl(KERN_INFO,
+		"eh_bus_reset: (pid#%li) target=<%02i-%i> cmd=%p\n",
+		cmd->pid, cmd->device->id, cmd->device->lun, cmd);
 
 	if (timer_pending(&acb->waiting_timer))
 		del_timer(&acb->waiting_timer);
@@ -1657,52 +1336,42 @@ static int dc395x_eh_bus_reset(Scsi_Cmnd
 	 */
 	/* Clear SCSI FIFO          */
 	DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO);
-	clear_fifo(acb, "reset");
+	clear_fifo(acb, "eh_bus_reset");
 	/* Delete pending IRQ */
 	DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS);
 	set_basic_config(acb);
 
 	reset_dev_param(acb);
 	doing_srb_done(acb, DID_RESET, cmd, 0);
-
 	acb->active_dcb = NULL;
-
 	acb->acb_flag = 0;	/* RESET_DETECT, RESET_DONE ,RESET_DEV */
 	waiting_process_next(acb);
 
-	/*DC395x_ACB_LOCK(acb,acb_flags); */
 	return SUCCESS;
 }
 
 
 /*
- *********************************************************************
- * Function : int dc395x_eh_abort(Scsi_Cmnd *cmd)
- * Purpose  : abort an errant SCSI command
- * Inputs   : cmd - command to be aborted
- * Returns  : SUCCESS (0x2002) on success, else FAILED (0x2003).
- *********************************************************************
+ * abort an errant SCSI command
+ * @cmd - command to be aborted
+ * Returns: SUCCESS (0x2002) on success, else FAILED (0x2003).
  */
-static int dc395x_eh_abort(Scsi_Cmnd * cmd)
+static int dc395x_eh_abort(Scsi_Cmnd *cmd)
 {
 	/*
 	 * Look into our command queues: If it has not been sent already,
 	 * we remove it and return success. Otherwise fail.
 	 */
 	struct AdapterCtlBlk *acb =
-	    (struct AdapterCtlBlk *) cmd->device->host->hostdata;
+	    (struct AdapterCtlBlk *)cmd->device->host->hostdata;
 	struct DeviceCtlBlk *dcb;
 	struct ScsiReqBlk *srb;
-
-	dprintkl(KERN_INFO, "eh abort: cmd %p (pid %li, %02i-%i) ",
-			     cmd,
-			     cmd->pid,
-			     cmd->device->id,
-			     cmd->device->lun);
+	dprintkl(KERN_INFO, "eh_abort: (pid#%li) target=<%02i-%i> cmd=%p\n",
+		cmd->pid, cmd->device->id, cmd->device->lun, cmd);
 
 	dcb = find_dcb(acb, cmd->device->id, cmd->device->lun);
 	if (!dcb) {
-		dprintkl(KERN_DEBUG, "abort - no DCB found");
+		dprintkl(KERN_DEBUG, "eh_abort: No such device\n");
 		return FAILED;
 	}
 
@@ -1713,32 +1382,31 @@ static int dc395x_eh_abort(Scsi_Cmnd * c
 		pci_unmap_srb(acb, srb);
 		free_tag(dcb, srb);
 		srb_free_insert(acb, srb);
-		dprintkl(KERN_DEBUG, "abort - command found in waiting commands queue");
+		dprintkl(KERN_DEBUG, "eh_abort: Command was waiting\n");
 		cmd->result = DID_ABORT << 16;
 		return SUCCESS;
 	}
 	srb = find_cmd(cmd, &dcb->srb_going_list);
 	if (srb) {
-		dprintkl(KERN_DEBUG, "abort - command currently in progress");
+		dprintkl(KERN_DEBUG, "eh_abort: Command in progress");
 		/* XXX: Should abort the command here */
 	} else {
-		dprintkl(KERN_DEBUG, "abort - command not found");
+		dprintkl(KERN_DEBUG, "eh_abort: Command not found");
 	}
 	return FAILED;
 }
 
 
 /* SDTR */
-static
-void build_sdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
+static void build_sdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
 		struct ScsiReqBlk *srb)
 {
 	u8 *ptr = srb->msgout_buf + srb->msg_count;
 	if (srb->msg_count > 1) {
 		dprintkl(KERN_INFO,
-		       "Build_SDTR: msgout_buf BUSY (%i: %02x %02x)\n",
-		       srb->msg_count, srb->msgout_buf[0],
-		       srb->msgout_buf[1]);
+			"build_sdtr: msgout_buf BUSY (%i: %02x %02x)\n",
+			srb->msg_count, srb->msgout_buf[0],
+			srb->msgout_buf[1]);
 		return;
 	}
 	if (!(dcb->dev_mode & NTC_DO_SYNC_NEGO)) {
@@ -1754,25 +1422,21 @@ void build_sdtr(struct AdapterCtlBlk *ac
 	*ptr++ = dcb->sync_offset;	/* Transfer period (max. REQ/ACK dist) */
 	srb->msg_count += 5;
 	srb->state |= SRB_DO_SYNC_NEGO;
-	TRACEPRINTF("S *");
 }
 
 
-/* SDTR */
-static
-void build_wdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
+/* WDTR */
+static void build_wdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
 		struct ScsiReqBlk *srb)
 {
-	u8 wide =
-	    ((dcb->dev_mode & NTC_DO_WIDE_NEGO) & (acb->
-						   config & HCC_WIDE_CARD))
-	    ? 1 : 0;
+	u8 wide = ((dcb->dev_mode & NTC_DO_WIDE_NEGO) &
+		   (acb->config & HCC_WIDE_CARD)) ? 1 : 0;
 	u8 *ptr = srb->msgout_buf + srb->msg_count;
 	if (srb->msg_count > 1) {
 		dprintkl(KERN_INFO,
-		       "Build_WDTR: msgout_buf BUSY (%i: %02x %02x)\n",
-		       srb->msg_count, srb->msgout_buf[0],
-		       srb->msgout_buf[1]);
+			"build_wdtr: msgout_buf BUSY (%i: %02x %02x)\n",
+			srb->msg_count, srb->msgout_buf[0],
+			srb->msgout_buf[1]);
 		return;
 	}
 	*ptr++ = MSG_EXTENDED;	/* (01h) */
@@ -1781,7 +1445,6 @@ void build_wdtr(struct AdapterCtlBlk *ac
 	*ptr++ = wide;
 	srb->msg_count += 4;
 	srb->state |= SRB_DO_WIDE_NEGO;
-	TRACEPRINTF("W *");
 }
 
 
@@ -1809,7 +1472,7 @@ static void selto_timer(struct AdapterCt
 void selection_timeout_missed(unsigned long ptr)
 {
 	unsigned long flags;
-	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *) ptr;
+	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)ptr;
 	struct ScsiReqBlk *srb;
 	dprintkl(KERN_DEBUG, "Chip forgot to produce SelTO IRQ!\n");
 	if (!acb->active_dcb || !acb->active_dcb->active_srb) {
@@ -1818,39 +1481,30 @@ void selection_timeout_missed(unsigned l
 	}
 	DC395x_LOCK_IO(acb->scsi_host, flags);
 	srb = acb->active_dcb->active_srb;
-	TRACEPRINTF("N/TO *");
 	disconnect(acb);
 	DC395x_UNLOCK_IO(acb->scsi_host, flags);
 }
 #endif
 
 
-/*
- * scsiio
- *		DC395x_DoWaitingSRB    srb_done 
- *		send_srb         request_sense
- */
-static
-u8 start_scsi(struct AdapterCtlBlk * acb, struct DeviceCtlBlk * dcb,
-	      struct ScsiReqBlk * srb)
+static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
+		struct ScsiReqBlk* srb)
 {
 	u16 s_stat2, return_code;
 	u8 s_stat, scsicommand, i, identify_message;
 	u8 *ptr;
+	dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> srb=%p\n",
+		srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
 
-	dprintkdbg(DBG_0, "start_scsi..............\n");
 	srb->tag_number = TAG_NONE;	/* acb->tag_max_num: had error read in eeprom */
 
 	s_stat = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL);
 	s_stat2 = 0;
 	s_stat2 = DC395x_read16(acb, TRM_S1040_SCSI_STATUS);
-	TRACEPRINTF("Start %02x *", s_stat);
 #if 1
 	if (s_stat & 0x20 /* s_stat2 & 0x02000 */ ) {
-		dprintkdbg(DBG_KG,
-		       "StartSCSI: pid %li(%02i-%i): BUSY %02x %04x\n",
-		       srb->cmd->pid, dcb->target_id, dcb->target_lun,
-		       s_stat, s_stat2);
+		dprintkdbg(DBG_KG, "start_scsi: (pid#%li) BUSY %02x %04x\n",
+			srb->cmd->pid, s_stat, s_stat2);
 		/*
 		 * Try anyway?
 		 *
@@ -1861,41 +1515,32 @@ u8 start_scsi(struct AdapterCtlBlk * acb
 		 * Instead let this fail and have the timer make sure the command is 
 		 * tried again after a short time
 		 */
-		TRACEPRINTF("^*");
 		/*selto_timer (acb); */
-		/*monitor_next_irq = 1; */
 		return 1;
 	}
 #endif
 	if (acb->active_dcb) {
-		dprintkl(KERN_DEBUG, "We try to start a SCSI command (%li)!\n",
-		       srb->cmd->pid);
-		dprintkl(KERN_DEBUG, "While another one (%li) is active!!\n",
-		       (acb->active_dcb->active_srb ? acb->active_dcb->
-			active_srb->cmd->pid : 0));
-		TRACEOUT(" %s\n", srb->debugtrace);
-		if (acb->active_dcb->active_srb)
-			TRACEOUT(" %s\n",
-				 acb->active_dcb->active_srb->debugtrace);
+		dprintkl(KERN_DEBUG, "start_scsi: (pid#%li) Attempt to start a"
+			"command while another command (pid#%li) is active.",
+			srb->cmd->pid,
+			acb->active_dcb->active_srb ?
+			    acb->active_dcb->active_srb->cmd->pid : 0);
 		return 1;
 	}
 	if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) {
-		dprintkdbg(DBG_KG,
-		       "StartSCSI failed (busy) for pid %li(%02i-%i)\n",
-		       srb->cmd->pid, dcb->target_id, dcb->target_lun);
-		TRACEPRINTF("°*");
+		dprintkdbg(DBG_KG, "start_scsi: (pid#%li) Failed (busy)\n",
+			srb->cmd->pid);
 		return 1;
 	}
 	/* Allow starting of SCSI commands half a second before we allow the mid-level
 	 * to queue them again after a reset */
 	if (time_before(jiffies, acb->scsi_host->last_reset - HZ / 2)) {
-		dprintkdbg(DBG_KG, 
-		       "We were just reset and don't accept commands yet!\n");
+		dprintkdbg(DBG_KG, "start_scsi: Refuse cmds (reset wait)\n");
 		return 1;
 	}
 
 	/* Flush FIFO */
-	clear_fifo(acb, "Start");
+	clear_fifo(acb, "start_scsi");
 	DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id);
 	DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id);
 	DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period);
@@ -1939,9 +1584,7 @@ u8 start_scsi(struct AdapterCtlBlk * acb
 		}
 		srb->msg_count = 0;
 	}
-	/* 
-	 ** Send identify message   
-	 */
+	/* Send identify message */
 	DC395x_write8(acb, TRM_S1040_SCSI_FIFO, identify_message);
 
 	scsicommand = SCMD_SEL_ATN;
@@ -1958,37 +1601,29 @@ u8 start_scsi(struct AdapterCtlBlk * acb
 			tag_number++;
 		}
 		if (tag_number >= dcb->max_command) {
-			dprintkl(KERN_WARNING,
-			       "Start_SCSI: Out of tags for pid %li (%i-%i)\n",
-			       srb->cmd->pid, srb->cmd->device->id,
-			       srb->cmd->device->lun);
+			dprintkl(KERN_WARNING, "start_scsi: (pid#%li) "
+				"Out of tags target=<%02i-%i>)\n",
+				srb->cmd->pid, srb->cmd->device->id,
+				srb->cmd->device->lun);
 			srb->state = SRB_READY;
 			DC395x_write16(acb, TRM_S1040_SCSI_CONTROL,
 				       DO_HWRESELECT);
 			return 1;
 		}
-		/* 
-		 ** Send Tag id
-		 */
+		/* Send Tag id */
 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_SIMPLE_QTAG);
 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, tag_number);
 		dcb->tag_mask |= tag_mask;
 		srb->tag_number = tag_number;
-		TRACEPRINTF("Tag %i *", tag_number);
-
 		scsicommand = SCMD_SEL_ATN3;
 		srb->state = SRB_START_;
 	}
 #endif
 /*polling:*/
-	/*
-	 *          Send CDB ..command block .........                     
-	 */
-	dprintkdbg(DBG_KG, 
-	       "StartSCSI (pid %li) %02x (%i-%i): Tag %i\n",
-	       srb->cmd->pid, srb->cmd->cmnd[0],
-	       srb->cmd->device->id, srb->cmd->device->lun,
-	       srb->tag_number);
+	/* Send CDB ..command block ......... */
+	dprintkdbg(DBG_KG, "start_scsi: (pid#%li) <%02i-%i> cmnd=0x%02x tag=%i\n",
+		srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun,
+		srb->cmd->cmnd[0], srb->tag_number);
 	if (srb->flag & AUTO_REQSENSE) {
 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE);
 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5));
@@ -1998,7 +1633,7 @@ u8 start_scsi(struct AdapterCtlBlk * acb
 			      sizeof(srb->cmd->sense_buffer));
 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
 	} else {
-		ptr = (u8 *) srb->cmd->cmnd;
+		ptr = (u8 *)srb->cmd->cmnd;
 		for (i = 0; i < srb->cmd->cmd_len; i++)
 			DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr++);
 	}
@@ -2011,10 +1646,8 @@ u8 start_scsi(struct AdapterCtlBlk * acb
 		 * we caught an interrupt (must be reset or reselection ... )
 		 * : Let's process it first!
 		 */
-		dprintkdbg(DBG_0, "Debug: StartSCSI failed (busy) for pid %li(%02i-%i)!\n",
+		dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> Failed - busy\n",
 			srb->cmd->pid, dcb->target_id, dcb->target_lun);
-		/*clear_fifo (acb, "Start2"); */
-		/*DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH); */
 		srb->state = SRB_READY;
 		free_tag(dcb, srb);
 		srb->msg_count = 0;
@@ -2032,23 +1665,13 @@ u8 start_scsi(struct AdapterCtlBlk * acb
 		/* it's important for atn stop */
 		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL,
 			       DO_DATALATCH | DO_HWRESELECT);
-		/*
-		 ** SCSI command
-		 */
-		TRACEPRINTF("%02x *", scsicommand);
+		/* SCSI command */
 		DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, scsicommand);
 	}
 	return return_code;
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *		init_adapter
- ********************************************************************
- */
-
 /**
  * dc395x_handle_interrupt - Handle an interrupt that has been confirmed to
  *                           have been triggered for this card.
@@ -2056,37 +1679,29 @@ u8 start_scsi(struct AdapterCtlBlk * acb
  * @acb:	 a pointer to the adpter control block
  * @scsi_status: the status return when we checked the card
  **/
-static void dc395x_handle_interrupt(struct AdapterCtlBlk *acb, u16 scsi_status)
+static void dc395x_handle_interrupt(struct AdapterCtlBlk *acb,
+		u16 scsi_status)
 {
 	struct DeviceCtlBlk *dcb;
 	struct ScsiReqBlk *srb;
 	u16 phase;
 	u8 scsi_intstatus;
 	unsigned long flags;
-	void (*dc395x_statev) (struct AdapterCtlBlk *, struct ScsiReqBlk *,
-			       u16 *);
+	void (*dc395x_statev)(struct AdapterCtlBlk *, struct ScsiReqBlk *, 
+			      u16 *);
 
 	DC395x_LOCK_IO(acb->scsi_host, flags);
 
 	/* This acknowledges the IRQ */
 	scsi_intstatus = DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS);
 	if ((scsi_status & 0x2007) == 0x2002)
-		dprintkl(KERN_DEBUG, "COP after COP completed? %04x\n",
-		       scsi_status);
-#if 1				/*def DBG_0 */
-	if (monitor_next_irq) {
-		dprintkl(KERN_INFO,
-		       "status=%04x intstatus=%02x\n", scsi_status,
-		       scsi_intstatus);
-		monitor_next_irq--;
-	}
-#endif
-	/*DC395x_ACB_LOCK(acb,acb_flags); */
+		dprintkl(KERN_DEBUG,
+			"COP after COP completed? %04x\n", scsi_status);
 	if (debug_enabled(DBG_KG)) {
 		if (scsi_intstatus & INT_SELTIMEOUT)
-		dprintkdbg(DBG_KG, "Sel Timeout IRQ\n");
+			dprintkdbg(DBG_KG, "handle_interrupt: Selection timeout\n");
 	}
-	/*dprintkl(KERN_DEBUG, "DC395x_IRQ: intstatus = %02x ", scsi_intstatus); */
+	/*dprintkl(KERN_DEBUG, "handle_interrupt: intstatus = 0x%02x ", scsi_intstatus); */
 
 	if (timer_pending(&acb->selto_timer))
 		del_timer(&acb->selto_timer);
@@ -2111,8 +1726,8 @@ static void dc395x_handle_interrupt(stru
 		dcb = acb->active_dcb;
 		if (!dcb) {
 			dprintkl(KERN_DEBUG,
-			       "Oops: BusService (%04x %02x) w/o ActiveDCB!\n",
-			       scsi_status, scsi_intstatus);
+				"Oops: BusService (%04x %02x) w/o ActiveDCB!\n",
+				scsi_status, scsi_intstatus);
 			goto out_unlock;
 		}
 		srb = dcb->active_srb;
@@ -2120,12 +1735,10 @@ static void dc395x_handle_interrupt(stru
 			dprintkdbg(DBG_0, "MsgOut Abort Device.....\n");
 			enable_msgout_abort(acb, srb);
 		}
-		/*
-		 ************************************************************
-		 * software sequential machine
-		 ************************************************************
-		 */
-		phase = (u16) srb->scsi_phase;
+
+		/* software sequential machine */
+		phase = (u16)srb->scsi_phase;
+
 		/* 
 		 * 62037 or 62137
 		 * call  dc395x_scsi_phase0[]... "phase entry"
@@ -2139,22 +1752,20 @@ static void dc395x_handle_interrupt(stru
 		/* nop0,		phase:5 PH_BUS_FREE .. initial phase */
 		/* msgout_phase0,	phase:6 */
 		/* msgin_phase0,	phase:7 */
-		dc395x_statev = (void *) dc395x_scsi_phase0[phase];
+		dc395x_statev = dc395x_scsi_phase0[phase];
 		dc395x_statev(acb, srb, &scsi_status);
+
 		/* 
-		 *$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ 
-		 *
-		 *        if there were any exception occured
-		 *        scsi_status will be modify to bus free phase
-		 * new scsi_status transfer out from ... previous dc395x_statev
-		 *
-		 *$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ 
+		 * if there were any exception occured scsi_status
+		 * will be modify to bus free phase new scsi_status
+		 * transfer out from ... previous dc395x_statev
 		 */
 		srb->scsi_phase = scsi_status & PHASEMASK;
-		phase = (u16) scsi_status & PHASEMASK;
+		phase = (u16)scsi_status & PHASEMASK;
+
 		/* 
-		 * call  dc395x_scsi_phase1[]... "phase entry"
-		 * handle every phase do transfer
+		 * call  dc395x_scsi_phase1[]... "phase entry" handle
+		 * every phase to do transfer
 		 */
 		/* data_out_phase1,	phase:0 */
 		/* data_in_phase1,	phase:1 */
@@ -2164,30 +1775,22 @@ static void dc395x_handle_interrupt(stru
 		/* nop1,		phase:5 PH_BUS_FREE .. initial phase */
 		/* msgout_phase1,	phase:6 */
 		/* msgin_phase1,	phase:7 */
-		dc395x_statev = (void *) dc395x_scsi_phase1[phase];
+		dc395x_statev = dc395x_scsi_phase1[phase];
 		dc395x_statev(acb, srb, &scsi_status);
 	}
       out_unlock:
 	DC395x_UNLOCK_IO(acb->scsi_host, flags);
-	return;
 }
 
 
-static
-irqreturn_t dc395x_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dc395x_interrupt(int irq, void *dev_id,
+		struct pt_regs *regs)
 {
 	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)dev_id;
 	u16 scsi_status;
 	u8 dma_status;
 	irqreturn_t handled = IRQ_NONE;
 
-	dprintkdbg(DBG_0, "dc395x_interrupt..............\n");
-#if debug_enabled(DBG_RECURSION)
-        if (dbg_in_driver++ > NORM_REC_LVL) {
-		dprintkl(KERN_DEBUG, "%i interrupt recursion?\n", dbg_in_driver);
-	}
-#endif
-
 	/*
 	 * Check for pending interupt
 	 */
@@ -2200,7 +1803,7 @@ irqreturn_t dc395x_interrupt(int irq, vo
 	}
 	else if (dma_status & 0x20) {
 		/* Error from the DMA engine */
-		dprintkl(KERN_INFO, "Interrupt from DMA engine: %02x!\n", dma_status);
+		dprintkl(KERN_INFO, "Interrupt from DMA engine: 0x%02x!\n", dma_status);
 #if 0
 		dprintkl(KERN_INFO, "This means DMA error! Try to handle ...\n");
 		if (acb->active_dcb) {
@@ -2216,135 +1819,75 @@ irqreturn_t dc395x_interrupt(int irq, vo
 		handled = IRQ_HANDLED;
 	}
 
-#if debug_enabled(DBG_RECURSION)
-	dbg_in_driver--
-#endif
 	return handled;
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *	msgout_phase0: one of dc395x_scsi_phase0[] vectors
- *	 dc395x_statev = (void *)dc395x_scsi_phase0[phase]
- *			           if phase =6
- ********************************************************************
- */
-static
-void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
-		    u16 * pscsi_status)
+static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
 {
-	dprintkdbg(DBG_0, "msgout_phase0.....\n");
-	if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT)) {
+	dprintkdbg(DBG_0, "msgout_phase0: (pid#%li)\n", srb->cmd->pid);
+	if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT))
 		*pscsi_status = PH_BUS_FREE;	/*.. initial phase */
-	}
+
 	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
 	srb->state &= ~SRB_MSGOUT;
-	TRACEPRINTF("MOP0 *");
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *	msgout_phase1: one of dc395x_scsi_phase0[] vectors
- *	 dc395x_statev = (void *)dc395x_scsi_phase0[phase]
- *					if phase =6	    
- ********************************************************************
- */
-static
-void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
-		    u16 * pscsi_status)
+static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
 {
 	u16 i;
 	u8 *ptr;
-	struct DeviceCtlBlk *dcb;
+	dprintkdbg(DBG_0, "msgout_phase1: (pid#%li)\n", srb->cmd->pid);
 
-	dprintkdbg(DBG_0, "msgout_phase1..............\n");
-	TRACEPRINTF("MOP1*");
-	dcb = acb->active_dcb;
-	clear_fifo(acb, "MOP1");
+	clear_fifo(acb, "msgout_phase1");
 	if (!(srb->state & SRB_MSGOUT)) {
 		srb->state |= SRB_MSGOUT;
-		dprintkl(KERN_DEBUG, "Debug: pid %li: MsgOut Phase unexpected.\n", srb->cmd->pid);	/* So what ? */
+		dprintkl(KERN_DEBUG,
+			"msgout_phase1: (pid#%li) Phase unexpected\n",
+			srb->cmd->pid);	/* So what ? */
 	}
 	if (!srb->msg_count) {
-		dprintkdbg(DBG_0, "Debug: pid %li: NOP Msg (no output message there).\n",
+		dprintkdbg(DBG_0, "msgout_phase1: (pid#%li) NOP msg\n",
 			srb->cmd->pid);
 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_NOP);
 		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
 		DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
-		TRACEPRINTF("\\*");
-		TRACEOUT(" %s\n", srb->debugtrace);
 		return;
 	}
-	ptr = (u8 *) srb->msgout_buf;
-	TRACEPRINTF("(*");
-	/*dprintkl(KERN_DEBUG, "Send msg: "); print_msg (ptr, srb->msg_count); */
-	/*dprintkl(KERN_DEBUG, "MsgOut: "); */
-	for (i = 0; i < srb->msg_count; i++) {
-		TRACEPRINTF("%02x *", *ptr);
+	ptr = (u8 *)srb->msgout_buf;
+	for (i = 0; i < srb->msg_count; i++)
 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr++);
-	}
-	TRACEPRINTF(")*");
 	srb->msg_count = 0;
-	/*printk("\n"); */
-	if (/*(dcb->flag & ABORT_DEV_) && */
-	    (srb->msgout_buf[0] == MSG_ABORT))
+	if (srb->msgout_buf[0] == MSG_ABORT)
 		srb->state = SRB_ABORT_SENT;
 
-	/*1.25 */
-	/*DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH); *//* it's important for atn stop */
-	/*
-	 ** SCSI command 
-	 */
-	/*TRACEPRINTF (".*"); */
 	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *	command_phase0: one of dc395x_scsi_phase0[] vectors
- *	 dc395x_statev = (void *)dc395x_scsi_phase0[phase]
- *				if phase =2 
- ********************************************************************
- */
-static
-void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
-		    u16 * pscsi_status)
+static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
 {
-	TRACEPRINTF("COP0 *");
-	/*1.25 */
-	/*clear_fifo (acb, COP0); */
+	dprintkdbg(DBG_0, "command_phase0: (pid#%li)\n", srb->cmd->pid);
 	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *	command_phase1: one of dc395x_scsi_phase1[] vectors
- *	 dc395x_statev = (void *)dc395x_scsi_phase1[phase]
- *				if phase =2    	 
- ********************************************************************
- */
-static
-void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
-		    u16 * pscsi_status)
+static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
 {
 	struct DeviceCtlBlk *dcb;
 	u8 *ptr;
 	u16 i;
+	dprintkdbg(DBG_0, "command_phase1: (pid#%li)\n", srb->cmd->pid);
 
-	dprintkdbg(DBG_0, "command_phase1..............\n");
-	TRACEPRINTF("COP1*");
-	clear_fifo(acb, "COP1");
+	clear_fifo(acb, "command_phase1");
 	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRATN);
 	if (!(srb->flag & AUTO_REQSENSE)) {
-		ptr = (u8 *) srb->cmd->cmnd;
+		ptr = (u8 *)srb->cmd->cmnd;
 		for (i = 0; i < srb->cmd->cmd_len; i++) {
 			DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr);
 			ptr++;
@@ -2364,22 +1907,24 @@ void command_phase1(struct AdapterCtlBlk
 	/* it's important for atn stop */
 	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
 	/* SCSI command */
-	TRACEPRINTF(".*");
 	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
 }
 
 
-/* Do sanity checks for S/G list */
-static inline void check_sg_list(struct ScsiReqBlk *srb)
+/*
+ * Verify that the remaining space in the hw sg lists is the same as
+ * the count of remaining bytes in srb->total_xfer_length
+ */
+static void sg_verify_length(struct ScsiReqBlk *srb)
 {
-	if (debug_enabled(DBG_SGPARANOIA)) {
+	if (debug_enabled(DBG_SG)) {
 		unsigned len = 0;
 		unsigned idx = srb->sg_index;
 		struct SGentry *psge = srb->segment_x + idx;
 		for (; idx < srb->sg_count; psge++, idx++)
 			len += psge->length;
 		if (len != srb->total_xfer_length)
-			dprintkdbg(DBG_SGPARANOIA,
+			dprintkdbg(DBG_SG,
 			       "Inconsistent SRB S/G lengths (Tot=%i, Count=%i) !!\n",
 			       srb->total_xfer_length, len);
 	}			       
@@ -2390,75 +1935,90 @@ static inline void check_sg_list(struct 
  * Compute the next Scatter Gather list index and adjust its length
  * and address if necessary; also compute virt_addr
  */
-static void update_sg_list(struct ScsiReqBlk *srb, u32 left)
+static void sg_update_list(struct ScsiReqBlk *srb, u32 left)
 {
-	struct SGentry *psge;
-	u32 xferred = 0;
 	u8 idx;
-	Scsi_Cmnd *cmd = srb->cmd;
 	struct scatterlist *sg;
+	Scsi_Cmnd *cmd = srb->cmd;
 	int segment = cmd->use_sg;
+	u32 xferred = srb->total_xfer_length - left; /* bytes transfered */
+	struct SGentry *psge = srb->segment_x + srb->sg_index;
+
+	dprintkdbg(DBG_0,
+		"sg_update_list: Transfered %i of %i bytes, %i remain\n",
+		xferred, srb->total_xfer_length, left);
+	if (xferred == 0) {
+		/* nothing to update since we did not transfer any data */
+		return;
+	}
 
-	dprintkdbg(DBG_KG, "Update SG: Total %i, Left %i\n",
-	       srb->total_xfer_length, left);
-	check_sg_list(srb);
-	psge = srb->segment_x + srb->sg_index;
-	/* data that has already been transferred */
-	xferred = srb->total_xfer_length - left;
-	if (srb->total_xfer_length != left) {
-		/*check_sg_list_TX (srb, xferred); */
-		/* Remaining */
-		srb->total_xfer_length = left;
-		/* parsing from last time disconnect SGIndex */
-		for (idx = srb->sg_index; idx < srb->sg_count; idx++) {
+	sg_verify_length(srb);
+	srb->total_xfer_length = left;	/* update remaining count */
+	for (idx = srb->sg_index; idx < srb->sg_count; idx++) {
+		if (xferred >= psge->length) {
 			/* Complete SG entries done */
-			if (xferred >= psge->length)
-				xferred -= psge->length;
-			/* Partial SG entries done */
-			else {
-				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);
-				break;
-			}
-			psge++;
+			xferred -= psge->length;
+		} else {
+			/* Partial SG entry done */
+			psge->length -= xferred;
+			psge->address += xferred;
+			srb->sg_index = idx;
+			pci_dma_sync_single_for_device(srb->dcb->
+					    acb->dev,
+					    srb->sg_bus_addr,
+					    SEGMENTX_LEN,
+					    PCI_DMA_TODEVICE);
+			break;
 		}
-		check_sg_list(srb);
+		psge++;
 	}
-	/* We need the corresponding virtual address sg_to_virt */
-	/*dprintkl(KERN_DEBUG, "sg_to_virt: bus %08x -> virt ", psge->address); */
+	sg_verify_length(srb);
+
+	/* we need the corresponding virtual address */
 	if (!segment) {
 		srb->virt_addr += xferred;
-		/*printk("%p\n", srb->virt_addr); */
 		return;
 	}
+
 	/* We have to walk the scatterlist to find it */
-	sg = (struct scatterlist *) cmd->request_buffer;
+	sg = (struct scatterlist *)cmd->request_buffer;
 	while (segment--) {
-		/*printk("(%08x)%p ", BUS_ADDR(*sg), PAGE_ADDRESS(sg)); */
 		unsigned long mask =
-		    ~((unsigned long) sg->length - 1) & PAGE_MASK;
-		if ((BUS_ADDR(*sg) & mask) == (psge->address & mask)) {
-			srb->virt_addr = (PAGE_ADDRESS(sg)
+		    ~((unsigned long)sg->length - 1) & PAGE_MASK;
+		if ((sg_dma_address(sg) & mask) == (psge->address & mask)) {
+			srb->virt_addr = (page_address(sg->page)
 					   + psge->address -
 					   (psge->address & PAGE_MASK));
-			/*printk("%p\n", srb->virt_addr); */
 			return;
 		}
 		++sg;
 	}
-	dprintkl(KERN_ERR, "sg_to_virt failed!\n");
+
+	dprintkl(KERN_ERR, "sg_update_list: sg_to_virt failed\n");
 	srb->virt_addr = 0;
 }
 
 
+/*
+ * We have transfered a single byte (PIO mode?) and need to update
+ * the count of bytes remaining (total_xfer_length) and update the sg
+ * entry to either point to next byte in the current sg entry, or of
+ * already at the end to point to the start of the next sg entry
+ */
+static void sg_subtract_one(struct ScsiReqBlk *srb)
+{
+	srb->total_xfer_length--;
+	srb->segment_x[srb->sg_index].length--;
+	if (srb->total_xfer_length &&
+	    !srb->segment_x[srb->sg_index].length) {
+		if (debug_enabled(DBG_PIO))
+			printk(" (next segment)");
+		srb->sg_index++;
+		sg_update_list(srb, srb->total_xfer_length);
+	}
+}
+
+
 /* 
  * cleanup_after_transfer
  * 
@@ -2467,27 +2027,21 @@ static void update_sg_list(struct ScsiRe
  * Should probably also be called from other places
  * Best might be to call it in DataXXPhase0, if new phase will differ 
  */
-static
-void cleanup_after_transfer(struct AdapterCtlBlk *acb,
-			    struct ScsiReqBlk *srb)
+static void cleanup_after_transfer(struct AdapterCtlBlk *acb,
+		struct ScsiReqBlk *srb)
 {
-	TRACEPRINTF(" Cln*");
 	/*DC395x_write8 (TRM_S1040_DMA_STATUS, FORCEDMACOMP); */
 	if (DC395x_read16(acb, TRM_S1040_DMA_COMMAND) & 0x0001) {	/* read */
 		if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40))
-			clear_fifo(acb, "ClnIn");
-
+			clear_fifo(acb, "cleanup/in");
 		if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80))
 			DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO);
 	} else {		/* write */
 		if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80))
 			DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO);
-
 		if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40))
-			clear_fifo(acb, "ClnOut");
-
+			clear_fifo(acb, "cleanup/out");
 	}
-	/*1.25 */
 	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
 }
 
@@ -2497,26 +2051,16 @@ void cleanup_after_transfer(struct Adapt
  * Seems to be needed for unknown reasons; could be a hardware bug :-(
  */
 #define DC395x_LASTPIO 4
-/*
- ********************************************************************
- * scsiio
- *	data_out_phase0: one of dc395x_scsi_phase0[] vectors
- *	 dc395x_statev = (void *)dc395x_scsi_phase0[phase]
- *				if phase =0 
- ********************************************************************
- */
-static
-void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
-		     u16 * pscsi_status)
+
+
+static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
 {
-	u16 scsi_status;
-	u32 d_left_counter = 0;
 	struct DeviceCtlBlk *dcb = srb->dcb;
-
-	dprintkdbg(DBG_0, "data_out_phase0.....\n");
-	TRACEPRINTF("DOP0*");
-	dcb = srb->dcb;
-	scsi_status = *pscsi_status;
+	u16 scsi_status = *pscsi_status;
+	u32 d_left_counter = 0;
+	dprintkdbg(DBG_0, "data_out_phase0: (pid#%li) <%02i-%i>\n",
+		srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
 
 	/*
 	 * KG: We need to drain the buffers before we draw any conclusions!
@@ -2530,12 +2074,14 @@ void data_out_phase0(struct AdapterCtlBl
 	 * KG: Stop DMA engine pushing more data into the SCSI FIFO
 	 * If we need more data, the DMA SG list will be freshly set up, anyway
 	 */
-	dprintkdbg(DBG_PIO, "DOP0: DMA_FCNT: %02x, DMA_FSTAT: %02x, SCSI_FCNT: %02x, CTR %06x, stat %04x, Tot: %06x\n",
-	       DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
-	       DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
-	       DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
-	       DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), scsi_status,
-	       srb->total_xfer_length);
+	dprintkdbg(DBG_PIO, "data_out_phase0: "
+		"DMA{fifcnt=0x%02x fifostat=0x%02x} "
+		"SCSI{fifocnt=0x%02x cnt=0x%06x status=0x%04x} total=0x%06x\n",
+		DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
+		DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
+		DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
+		DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), scsi_status,
+		srb->total_xfer_length);
 	DC395x_write8(acb, TRM_S1040_DMA_CONTROL, STOPDMAXFER | CLRXFIFO);
 
 	if (!(srb->state & SRB_XFERPAD)) {
@@ -2554,31 +2100,21 @@ void data_out_phase0(struct AdapterCtlBl
 			 * if there was some data left in SCSI FIFO
 			 */
 			d_left_counter =
-			    (u32) (DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) &
-				   0x1F);
+			    (u32)(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) &
+				  0x1F);
 			if (dcb->sync_period & WIDE_SYNC)
 				d_left_counter <<= 1;
 
-			dprintkdbg(DBG_KG,
-			       "Debug: SCSI FIFO contains %i %s in DOP0\n",
-			       DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
-			       (dcb->
-				sync_period & WIDE_SYNC) ? "words" :
-			       "bytes");
-			dprintkdbg(DBG_KG,
-			       "SCSI FIFOCNT %02x, SCSI CTR %08x\n",
-			       DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
-			       DC395x_read32(acb, TRM_S1040_SCSI_COUNTER));
-			dprintkdbg(DBG_KG,
-			       "DMA FIFOCNT %04x, FIFOSTAT %02x, DMA CTR %08x\n",
-			       DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
-			       DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
-			       DC395x_read32(acb, TRM_S1040_DMA_CXCNT));
-
-			/*
-			 * if WIDE scsi SCSI FIFOCNT unit is word !!!
-			 * so need to *= 2
-			 */
+			dprintkdbg(DBG_KG, "data_out_phase0: FIFO contains %i %s\n"
+				"SCSI{fifocnt=0x%02x cnt=0x%08x} "
+				"DMA{fifocnt=0x%04x cnt=0x%02x ctr=0x%08x}\n",
+				DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
+				(dcb->sync_period & WIDE_SYNC) ? "words" : "bytes",
+				DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
+				DC395x_read32(acb, TRM_S1040_SCSI_COUNTER),
+				DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
+				DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
+				DC395x_read32(acb, TRM_S1040_DMA_CXCNT));
 		}
 		/*
 		 * calculate all the residue data that not yet tranfered
@@ -2592,16 +2128,16 @@ void data_out_phase0(struct AdapterCtlBl
 		if (srb->total_xfer_length > DC395x_LASTPIO)
 			d_left_counter +=
 			    DC395x_read32(acb, TRM_S1040_SCSI_COUNTER);
-		TRACEPRINTF("%06x *", d_left_counter);
 
 		/* Is this a good idea? */
-		/*clear_fifo (acb, "DOP1"); */
+		/*clear_fifo(acb, "DOP1"); */
 		/* KG: What is this supposed to be useful for? WIDE padding stuff? */
 		if (d_left_counter == 1 && dcb->sync_period & WIDE_SYNC
 		    && srb->cmd->request_bufflen % 2) {
 			d_left_counter = 0;
-			dprintkl(KERN_INFO, "DOP0: Discard 1 byte. (%02x)\n",
-			       scsi_status);
+			dprintkl(KERN_INFO,
+				"data_out_phase0: Discard 1 byte (0x%02x)\n",
+				scsi_status);
 		}
 		/*
 		 * KG: Oops again. Same thinko as above: The SCSI might have been
@@ -2613,19 +2149,9 @@ void data_out_phase0(struct AdapterCtlBl
 		 * KG: This is nonsense: We have been WRITING data to the bus
 		 * If the SCSI engine has no bytes left, how should the DMA engine?
 		 */
-		if ((d_left_counter ==
-		     0) /*|| (scsi_status & SCSIXFERCNT_2_ZERO) ) */ ) {
-			/*
-			 * int ctr = 6000000; u8 TempDMAstatus;
-			 * do
-			 * {
-			 *  TempDMAstatus = DC395x_read8(acb, TRM_S1040_DMA_STATUS);
-			 * } while( !(TempDMAstatus & DMAXFERCOMP) && --ctr);
-			 * if (ctr < 6000000-1) dprintkl(KERN_DEBUG, "DMA should be complete ... in DOP1\n");
-			 * if (!ctr) dprintkl(KERN_ERR, "Deadlock in DataOutPhase0 !!\n");
-			 */
+		if (d_left_counter == 0) {
 			srb->total_xfer_length = 0;
-		} else {	/* Update SG list         */
+		} else {
 			/*
 			 * if transfer not yet complete
 			 * there were some data residue in SCSI FIFO or
@@ -2635,18 +2161,18 @@ void data_out_phase0(struct AdapterCtlBl
 			    srb->total_xfer_length - d_left_counter;
 			const int diff =
 			    (dcb->sync_period & WIDE_SYNC) ? 2 : 1;
-			update_sg_list(srb, d_left_counter);
+			sg_update_list(srb, d_left_counter);
 			/* KG: Most ugly hack! Apparently, this works around a chip bug */
 			if ((srb->segment_x[srb->sg_index].length ==
 			     diff && srb->cmd->use_sg)
 			    || ((oldxferred & ~PAGE_MASK) ==
 				(PAGE_SIZE - diff))
 			    ) {
-				dprintkl(KERN_INFO,
-				       "Work around chip bug (%i)?\n", diff);
+				dprintkl(KERN_INFO, "data_out_phase0: "
+					"Work around chip bug (%i)?\n", diff);
 				d_left_counter =
 				    srb->total_xfer_length - diff;
-				update_sg_list(srb, d_left_counter);
+				sg_update_list(srb, d_left_counter);
 				/*srb->total_xfer_length -= diff; */
 				/*srb->virt_addr += diff; */
 				/*if (srb->cmd->use_sg) */
@@ -2654,71 +2180,30 @@ void data_out_phase0(struct AdapterCtlBl
 			}
 		}
 	}
-#if 0
-	if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40))
-		dprintkl(KERN_DEBUG,
-			"DOP0(%li): %i bytes in SCSI FIFO! (Clear!)\n",
-			srb->cmd->pid,
-			DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f);
-#endif
-	/*clear_fifo (acb, "DOP0"); */
-	/*DC395x_write8 (TRM_S1040_DMA_CONTROL, CLRXFIFO | ABORTXFER); */
-#if 1
 	if ((*pscsi_status & PHASEMASK) != PH_DATA_OUT) {
-		/*dprintkl(KERN_DEBUG, "Debug: Clean up after Data Out ...\n"); */
 		cleanup_after_transfer(acb, srb);
 	}
-#endif
-	TRACEPRINTF(".*");
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *	data_out_phase1: one of dc395x_scsi_phase0[] vectors
- *	 dc395x_statev = (void *)dc395x_scsi_phase0[phase]
- *				if phase =0    
- *		62037
- ********************************************************************
- */
-static
-void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
-		     u16 * pscsi_status)
+static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
 {
-
-	dprintkdbg(DBG_0, "data_out_phase1.....\n");
-	/*1.25 */
-	TRACEPRINTF("DOP1*");
-	clear_fifo(acb, "DOP1");
-	/*
-	 ** do prepare befor transfer when data out phase
-	 */
+	dprintkdbg(DBG_0, "data_out_phase1: (pid#%li) <%02i-%i>\n",
+		srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+	clear_fifo(acb, "data_out_phase1");
+	/* do prepare before transfer when data out phase */
 	data_io_transfer(acb, srb, XFERDATAOUT);
-	TRACEPRINTF(".*");
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *	data_in_phase0: one of dc395x_scsi_phase1[] vectors
- *	 dc395x_statev = (void *)dc395x_scsi_phase1[phase]
- *				if phase =1  
- ********************************************************************
- */
-static
-void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
-		    u16 * pscsi_status)
+static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
 {
-	u16 scsi_status;
+	u16 scsi_status = *pscsi_status;
 	u32 d_left_counter = 0;
-	/*struct DeviceCtlBlk*   dcb = srb->dcb; */
-	/*u8 bval; */
-
-	dprintkdbg(DBG_0, "data_in_phase0..............\n");
-	TRACEPRINTF("DIP0*");
-	scsi_status = *pscsi_status;
+	dprintkdbg(DBG_0, "data_in_phase0: (pid#%li) <%02i-%i>\n",
+		srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
 
 	/*
 	 * KG: DataIn is much more tricky than DataOut. When the device is finished
@@ -2735,10 +2220,8 @@ void data_in_phase0(struct AdapterCtlBlk
 	 */
 	if (!(srb->state & SRB_XFERPAD)) {
 		if (scsi_status & PARITYERROR) {
-			dprintkl(KERN_INFO,
-			       "Parity Error (pid %li, target %02i-%i)\n",
-			       srb->cmd->pid, srb->cmd->device->id,
-			       srb->cmd->device->lun);
+			dprintkl(KERN_INFO, "data_in_phase0: (pid#%li) "
+				"Parity Error\n", srb->cmd->pid);
 			srb->status |= PARITY_ERROR;
 		}
 		/*
@@ -2751,7 +2234,7 @@ void data_in_phase0(struct AdapterCtlBlk
 #if 0
 			int ctr = 6000000;
 			dprintkl(KERN_DEBUG,
-			       "DIP0: Wait for DMA FIFO to flush ...\n");
+				"DIP0: Wait for DMA FIFO to flush ...\n");
 			/*DC395x_write8  (TRM_S1040_DMA_CONTROL, STOPDMAXFER); */
 			/*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 7); */
 			/*DC395x_write8  (TRM_S1040_SCSI_COMMAND, SCMD_DMA_IN); */
@@ -2766,73 +2249,56 @@ void data_in_phase0(struct AdapterCtlBlk
 				       "Deadlock in DIP0 waiting for DMA FIFO empty!!\n");
 			/*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 0); */
 #endif
-			dprintkdbg(DBG_KG, "DIP0: DMA_FIFO: %02x %02x\n",
-			       DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
-			       DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT));
+			dprintkdbg(DBG_KG, "data_in_phase0: "
+				"DMA{fifocnt=0x%02x fifostat=0x%02x}\n",
+				DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
+				DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT));
 		}
 		/* Now: Check remainig data: The SCSI counters should tell us ... */
 		d_left_counter = DC395x_read32(acb, TRM_S1040_SCSI_COUNTER)
 		    + ((DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f)
 		       << ((srb->dcb->sync_period & WIDE_SYNC) ? 1 :
 			   0));
-
-		dprintkdbg(DBG_KG, "SCSI FIFO contains %i %s in DIP0\n",
-			  DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f,
-			  (srb->dcb->
-			  sync_period & WIDE_SYNC) ? "words" : "bytes");
-		dprintkdbg(DBG_KG, "SCSI FIFOCNT %02x, SCSI CTR %08x\n",
-			  DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
-			  DC395x_read32(acb, TRM_S1040_SCSI_COUNTER));
-		dprintkdbg(DBG_KG, "DMA FIFOCNT %02x,%02x DMA CTR %08x\n",
-			  DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
-			  DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
-			  DC395x_read32(acb, TRM_S1040_DMA_CXCNT));
-		dprintkdbg(DBG_KG, "Remaining: TotXfer: %i, SCSI FIFO+Ctr: %i\n",
-			  srb->total_xfer_length, d_left_counter);
+		dprintkdbg(DBG_KG, "data_in_phase0: "
+			"SCSI{fifocnt=0x%02x%s ctr=0x%08x} "
+			"DMA{fifocnt=0x%02x fifostat=0x%02x ctr=0x%08x} "
+			"Remain{totxfer=%i scsi_fifo+ctr=%i}\n",
+			DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
+			(srb->dcb->sync_period & WIDE_SYNC) ? "words" : "bytes",
+			DC395x_read32(acb, TRM_S1040_SCSI_COUNTER),
+			DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
+			DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
+			DC395x_read32(acb, TRM_S1040_DMA_CXCNT),
+			srb->total_xfer_length, d_left_counter);
 #if DC395x_LASTPIO
 		/* KG: Less than or equal to 4 bytes can not be transfered via DMA, it seems. */
 		if (d_left_counter
 		    && srb->total_xfer_length <= DC395x_LASTPIO) {
 			/*u32 addr = (srb->segment_x[srb->sg_index].address); */
-			/*update_sg_list (srb, d_left_counter); */
-			dprintkdbg(DBG_PIO, "DIP0: PIO (%i %s) to %p for remaining %i bytes:",
-				  DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) &
-				  0x1f,
-				  (srb->dcb->
-				   sync_period & WIDE_SYNC) ? "words" :
-				  "bytes", srb->virt_addr,
-				  srb->total_xfer_length);
-
+			/*sg_update_list (srb, d_left_counter); */
+			dprintkdbg(DBG_PIO, "data_in_phase0: PIO (%i %s) to "
+				"%p for remaining %i bytes:",
+				DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f,
+				(srb->dcb->sync_period & WIDE_SYNC) ?
+				    "words" : "bytes",
+				srb->virt_addr,
+				srb->total_xfer_length);
 			if (srb->dcb->sync_period & WIDE_SYNC)
 				DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
 					      CFG2_WIDEFIFO);
-
-			while (DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) !=
-			       0x40) {
-				u8 byte =
-				    DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
+			while (DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) != 0x40) {
+				u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
 				*(srb->virt_addr)++ = byte;
 				if (debug_enabled(DBG_PIO))
 					printk(" %02x", byte);
-				srb->total_xfer_length--;
 				d_left_counter--;
-				srb->segment_x[srb->sg_index].length--;
-				if (srb->total_xfer_length
-				    && !srb->segment_x[srb->sg_index].
-				    length) {
-				    	if (debug_enabled(DBG_PIO))
-						printk(" (next segment)");
-					srb->sg_index++;
-					update_sg_list(srb,
-							     d_left_counter);
-				}
+				sg_subtract_one(srb);
 			}
 			if (srb->dcb->sync_period & WIDE_SYNC) {
-#if 1				/* Read the last byte ... */
+#if 1
+                /* Read the last byte ... */
 				if (srb->total_xfer_length > 0) {
-					u8 byte =
-					    DC395x_read8
-					    (acb, TRM_S1040_SCSI_FIFO);
+					u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
 					*(srb->virt_addr)++ = byte;
 					srb->total_xfer_length--;
 					if (debug_enabled(DBG_PIO))
@@ -2859,8 +2325,8 @@ void data_in_phase0(struct AdapterCtlBlk
 			 * if there was some data left in SCSI FIFO
 			 */
 			d_left_counter =
-			    (u32) (DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) &
-				   0x1F);
+			    (u32)(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) &
+				  0x1F);
 			if (srb->dcb->sync_period & WIDE_SYNC)
 				d_left_counter <<= 1;
 			/*
@@ -2870,19 +2336,8 @@ void data_in_phase0(struct AdapterCtlBlk
 			 */
 		}
 #endif
-		/*d_left_counter += DC395x_read32(acb, TRM_S1040_SCSI_COUNTER); */
-#if 0
-		dprintkl(KERN_DEBUG,
-		       "DIP0: ctr=%08x, DMA_FIFO=%02x,%02x SCSI_FIFO=%02x\n",
-		       d_left_counter, DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
-		       DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
-		       DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT));
-		dprintkl(KERN_DEBUG, "DIP0: DMAStat %02x\n",
-		       DC395x_read8(acb, TRM_S1040_DMA_STATUS));
-#endif
-
 		/* KG: This should not be needed any more! */
-		if ((d_left_counter == 0)
+		if (d_left_counter == 0
 		    || (scsi_status & SCSIXFERCNT_2_ZERO)) {
 #if 0
 			int ctr = 6000000;
@@ -2896,12 +2351,6 @@ void data_in_phase0(struct AdapterCtlBlk
 				       "Deadlock in DataInPhase0 waiting for DMA!!\n");
 			srb->total_xfer_length = 0;
 #endif
-#if 0				/*def DBG_KG             */
-			dprintkl(KERN_DEBUG,
-			       "DIP0: DMA not yet ready: %02x: %i -> %i bytes\n",
-			       DC395x_read8(acb, TRM_S1040_DMA_STATUS),
-			       srb->total_xfer_length, d_left_counter);
-#endif
 			srb->total_xfer_length = d_left_counter;
 		} else {	/* phase changed */
 			/*
@@ -2912,333 +2361,209 @@ void data_in_phase0(struct AdapterCtlBlk
 			 * there were some data residue in SCSI FIFO or
 			 * SCSI transfer counter not empty
 			 */
-			update_sg_list(srb, d_left_counter);
+			sg_update_list(srb, d_left_counter);
 		}
 	}
 	/* KG: The target may decide to disconnect: Empty FIFO before! */
 	if ((*pscsi_status & PHASEMASK) != PH_DATA_IN) {
-		/*dprintkl(KERN_DEBUG, "Debug: Clean up after Data In  ...\n"); */
 		cleanup_after_transfer(acb, srb);
 	}
-#if 0
-	/* KG: Make sure, no previous transfers are pending! */
-	bval = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT);
-	if (!(bval & 0x40)) {
-		bval &= 0x1f;
-		dprintkl(KERN_DEBUG,
-		       "DIP0(%li): %i bytes in SCSI FIFO (stat %04x) (left %08x)!!\n",
-		       srb->cmd->pid, bval & 0x1f, scsi_status,
-		       d_left_counter);
-		if ((d_left_counter == 0)
-		    || (scsi_status & SCSIXFERCNT_2_ZERO)) {
-			dprintkl(KERN_DEBUG, "Clear FIFO!\n");
-			clear_fifo(acb, "DIP0");
+}
+
+
+static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
+{
+	dprintkdbg(DBG_0, "data_in_phase1: (pid#%li) <%02i-%i>\n",
+		srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+	data_io_transfer(acb, srb, XFERDATAIN);
+}
+
+
+static void data_io_transfer(struct AdapterCtlBlk *acb, 
+		struct ScsiReqBlk *srb, u16 io_dir)
+{
+	struct DeviceCtlBlk *dcb = srb->dcb;
+	u8 bval;
+	dprintkdbg(DBG_0,
+		"data_io_transfer: (pid#%li) <%02i-%i> %c len=%i, sg=(%i/%i)\n",
+		srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun,
+		((io_dir & DMACMD_DIR) ? 'r' : 'w'),
+		srb->total_xfer_length, srb->sg_index, srb->sg_count);
+	if (srb == acb->tmp_srb)
+		dprintkl(KERN_ERR, "data_io_transfer: Using tmp_srb!\n");
+	if (srb->sg_index >= srb->sg_count) {
+		/* can't happen? out of bounds error */
+		return;
+	}
+
+	if (srb->total_xfer_length > DC395x_LASTPIO) {
+		u8 dma_status = DC395x_read8(acb, TRM_S1040_DMA_STATUS);
+		/*
+		 * KG: What should we do: Use SCSI Cmd 0x90/0x92?
+		 * Maybe, even ABORTXFER would be appropriate
+		 */
+		if (dma_status & XFERPENDING) {
+			dprintkl(KERN_DEBUG, "data_io_transfer: Xfer pending! "
+				"Expect trouble!\n");
+			dump_register_info(acb, dcb, srb);
+			DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO);
+		}
+		/* clear_fifo(acb, "IO"); */
+		/* 
+		 * load what physical address of Scatter/Gather list table
+		 * want to be transfer
+		 */
+		srb->state |= SRB_DATA_XFER;
+		DC395x_write32(acb, TRM_S1040_DMA_XHIGHADDR, 0);
+		if (srb->cmd->use_sg) {	/* with S/G */
+			io_dir |= DMACMD_SG;
+			DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR,
+				       srb->sg_bus_addr +
+				       sizeof(struct SGentry) *
+				       srb->sg_index);
+			/* load how many bytes in the sg list table */
+			DC395x_write32(acb, TRM_S1040_DMA_XCNT,
+				       ((u32)(srb->sg_count -
+					      srb->sg_index) << 3));
+		} else {	/* without S/G */
+			io_dir &= ~DMACMD_SG;
+			DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR,
+				       srb->segment_x[0].address);
+			DC395x_write32(acb, TRM_S1040_DMA_XCNT,
+				       srb->segment_x[0].length);
+		}
+		/* load total transfer length (24bits) max value 16Mbyte */
+		DC395x_write32(acb, TRM_S1040_SCSI_COUNTER,
+			       srb->total_xfer_length);
+		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
+		if (io_dir & DMACMD_DIR) {	/* read */
+			DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
+				      SCMD_DMA_IN);
+			DC395x_write16(acb, TRM_S1040_DMA_COMMAND, io_dir);
+		} else {
+			DC395x_write16(acb, TRM_S1040_DMA_COMMAND, io_dir);
+			DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
+				      SCMD_DMA_OUT);
 		}
-	}
-#endif
-	/*DC395x_write8 (TRM_S1040_DMA_CONTROL, CLRXFIFO | ABORTXFER); */
-
-	/*clear_fifo (acb, "DIP0"); */
-	/*DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH); */
-	TRACEPRINTF(".*");
-}
-
 
-/*
- ********************************************************************
- * scsiio
- *	data_in_phase1: one of dc395x_scsi_phase0[] vectors
- *	 dc395x_statev = (void *)dc395x_scsi_phase0[phase]
- *				if phase =1 
- ********************************************************************
- */
-static
-void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
-		    u16 * pscsi_status)
-{
-	dprintkdbg(DBG_0, "data_in_phase1.....\n");
-	/* FIFO should be cleared, if previous phase was not DataPhase */
-	/*clear_fifo (acb, "DIP1"); */
-	/* Allow data in! */
-	/*DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH); */
-	TRACEPRINTF("DIP1:*");
-	/*
-	 ** do prepare before transfer when data in phase
-	 */
-	data_io_transfer(acb, srb, XFERDATAIN);
-	TRACEPRINTF(".*");
-}
+	}
+#if DC395x_LASTPIO
+	else if (srb->total_xfer_length > 0) {	/* The last four bytes: Do PIO */
+		/* 
+		 * load what physical address of Scatter/Gather list table
+		 * want to be transfer
+		 */
+		srb->state |= SRB_DATA_XFER;
+		/* load total transfer length (24bits) max value 16Mbyte */
+		DC395x_write32(acb, TRM_S1040_SCSI_COUNTER,
+			       srb->total_xfer_length);
+		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
+		if (io_dir & DMACMD_DIR) {	/* read */
+			DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
+				      SCMD_FIFO_IN);
+		} else {	/* write */
+			int ln = srb->total_xfer_length;
+			if (srb->dcb->sync_period & WIDE_SYNC)
+				DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
+				     CFG2_WIDEFIFO);
+			dprintkdbg(DBG_PIO,
+				"data_io_transfer: PIO %i bytes from %p:",
+				srb->total_xfer_length, srb->virt_addr);
 
+			while (srb->total_xfer_length) {
+				if (debug_enabled(DBG_PIO))
+					printk(" %02x", (unsigned char) *(srb->virt_addr));
 
-/*
- ********************************************************************
- * scsiio
- *		data_out_phase1
- *		data_in_phase1
- ********************************************************************
- */
-static
-void data_io_transfer(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
-		      u16 io_dir)
-{
-	u8 bval;
-	struct DeviceCtlBlk *dcb;
+				DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 
+				     *(srb->virt_addr)++);
 
-	dprintkdbg(DBG_0, "DataIO_transfer %c (pid %li): len = %i, SG: %i/%i\n",
-	       ((io_dir & DMACMD_DIR) ? 'r' : 'w'), srb->cmd->pid,
-	       srb->total_xfer_length, srb->sg_index,
-	       srb->sg_count);
-	TRACEPRINTF("%05x(%i/%i)*", srb->total_xfer_length,
-		    srb->sg_index, srb->sg_count);
-	dcb = srb->dcb;
-	if (srb == acb->tmp_srb) {
-		dprintkl(KERN_ERR, "Using tmp_srb in DataPhase!\n");
-	}
-	if (srb->sg_index < srb->sg_count) {
-		if (srb->total_xfer_length > DC395x_LASTPIO) {
-			u8 dma_status = DC395x_read8(acb, TRM_S1040_DMA_STATUS);
-			/*
-			 * KG: What should we do: Use SCSI Cmd 0x90/0x92?
-			 * Maybe, even ABORTXFER would be appropriate
-			 */
-			if (dma_status & XFERPENDING) {
-				dprintkl(KERN_DEBUG, "Xfer pending! Expect trouble!!\n");
-				dump_register_info(acb, dcb, srb);
-				DC395x_write8(acb, TRM_S1040_DMA_CONTROL,
-					      CLRXFIFO);
-			}
-			/*clear_fifo (acb, "IO"); */
-			/* 
-			 * load what physical address of Scatter/Gather list table want to be
-			 * transfer 
-			 */
-			srb->state |= SRB_DATA_XFER;
-			DC395x_write32(acb, TRM_S1040_DMA_XHIGHADDR, 0);
-			if (srb->cmd->use_sg) {	/* with S/G */
-				io_dir |= DMACMD_SG;
-				DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR,
-					       srb->sg_bus_addr +
-					       sizeof(struct SGentry) *
-					       srb->sg_index);
-				/* load how many bytes in the Scatter/Gather list table */
-				DC395x_write32(acb, TRM_S1040_DMA_XCNT,
-					       ((u32)
-						(srb->sg_count -
-						 srb->sg_index) << 3));
-			} else {	/* without S/G */
-				io_dir &= ~DMACMD_SG;
-				DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR,
-					       srb->segment_x[0].address);
-				DC395x_write32(acb, TRM_S1040_DMA_XCNT,
-					       srb->segment_x[0].length);
-			}
-			/* load total transfer length (24bits) max value 16Mbyte */
-			DC395x_write32(acb, TRM_S1040_SCSI_COUNTER,
-				       srb->total_xfer_length);
-			DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
-			if (io_dir & DMACMD_DIR) {	/* read */
-				DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
-					      SCMD_DMA_IN);
-				DC395x_write16(acb, TRM_S1040_DMA_COMMAND,
-					       io_dir);
-			} else {
-				DC395x_write16(acb, TRM_S1040_DMA_COMMAND,
-					       io_dir);
-				DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
-					      SCMD_DMA_OUT);
+				sg_subtract_one(srb);
 			}
-
-		}
-#if DC395x_LASTPIO
-		else if (srb->total_xfer_length > 0) {	/* The last four bytes: Do PIO */
-			/*clear_fifo (acb, "IO"); */
-			/* 
-			 * load what physical address of Scatter/Gather list table want to be
-			 * transfer 
-			 */
-			srb->state |= SRB_DATA_XFER;
-			/* load total transfer length (24bits) max value 16Mbyte */
-			DC395x_write32(acb, TRM_S1040_SCSI_COUNTER,
-				       srb->total_xfer_length);
-			DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
-			if (io_dir & DMACMD_DIR) {	/* read */
-				DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
-					      SCMD_FIFO_IN);
-			} else {	/* write */
-				int ln = srb->total_xfer_length;
-				if (srb->dcb->sync_period & WIDE_SYNC)
-					DC395x_write8
-					    (acb, TRM_S1040_SCSI_CONFIG2,
-					     CFG2_WIDEFIFO);
-				dprintkdbg(DBG_PIO, "DOP1: PIO %i bytes from %p:",
-					  srb->total_xfer_length,
-					  srb->virt_addr);
-				while (srb->total_xfer_length) {
+			if (srb->dcb->sync_period & WIDE_SYNC) {
+				if (ln % 2) {
+					DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
 					if (debug_enabled(DBG_PIO))
-						printk(" %02x", (unsigned char) *(srb->virt_addr));
-					DC395x_write8
-					    (acb, TRM_S1040_SCSI_FIFO,
-					     *(srb->virt_addr)++);
-					srb->total_xfer_length--;
-					srb->segment_x[srb->sg_index].
-					    length--;
-					if (srb->total_xfer_length
-					    && !srb->segment_x[srb->
-							       sg_index].
-					    length) {
-						if (debug_enabled(DBG_PIO))
-							printk(" (next segment)");
-						srb->sg_index++;
-						update_sg_list(srb,
-							       srb->total_xfer_length);
-					}
-				}
-				if (srb->dcb->sync_period & WIDE_SYNC) {
-					if (ln % 2) {
-						DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
-						if (debug_enabled(DBG_PIO))
-							printk(" |00");
-					}
-					DC395x_write8
-					    (acb, TRM_S1040_SCSI_CONFIG2, 0);
+						printk(" |00");
 				}
-				/*DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, ln); */
-				if (debug_enabled(DBG_PIO))
-					printk("\n");
-				DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
-						  SCMD_FIFO_OUT);
+				DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
 			}
+			/*DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, ln); */
+			if (debug_enabled(DBG_PIO))
+				printk("\n");
+			DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
+					  SCMD_FIFO_OUT);
 		}
+	}
 #endif				/* DC395x_LASTPIO */
-		else {		/* xfer pad */
-
-			u8 data = 0, data2 = 0;
-			if (srb->sg_count) {
-				srb->adapter_status = H_OVER_UNDER_RUN;
-				srb->status |= OVER_RUN;
-			}
-			/*
-			 * KG: despite the fact that we are using 16 bits I/O ops
-			 * the SCSI FIFO is only 8 bits according to the docs
-			 * (we can set bit 1 in 0x8f to serialize FIFO access ...)
-			 */
-			if (dcb->sync_period & WIDE_SYNC) {
-				DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 2);
-				DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
-					      CFG2_WIDEFIFO);
-				if (io_dir & DMACMD_DIR) {	/* read */
-					data =
-					    DC395x_read8
-					    (acb, TRM_S1040_SCSI_FIFO);
-					data2 =
-					    DC395x_read8
-					    (acb, TRM_S1040_SCSI_FIFO);
-					/*dprintkl(KERN_DEBUG, "DataIO: Xfer pad: %02x %02x\n", data, data2); */
-				} else {
-					/* Danger, Robinson: If you find KGs scattered over the wide
-					 * disk, the driver or chip is to blame :-( */
-					DC395x_write8(acb, TRM_S1040_SCSI_FIFO,
-						      'K');
-					DC395x_write8(acb, TRM_S1040_SCSI_FIFO,
-						      'G');
-				}
-				DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
+	else {		/* xfer pad */
+		u8 data = 0, data2 = 0;
+		if (srb->sg_count) {
+			srb->adapter_status = H_OVER_UNDER_RUN;
+			srb->status |= OVER_RUN;
+		}
+		/*
+		 * KG: despite the fact that we are using 16 bits I/O ops
+		 * the SCSI FIFO is only 8 bits according to the docs
+		 * (we can set bit 1 in 0x8f to serialize FIFO access ...)
+		 */
+		if (dcb->sync_period & WIDE_SYNC) {
+			DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 2);
+			DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
+				      CFG2_WIDEFIFO);
+			if (io_dir & DMACMD_DIR) {
+				data = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
+				data2 = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
 			} else {
-				DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1);
-				/* Danger, Robinson: If you find a collection of Ks on your disk
-				 * something broke :-( */
-				if (io_dir & DMACMD_DIR) {	/* read */
-					data =
-					    DC395x_read8
-					    (acb, TRM_S1040_SCSI_FIFO);
-					/*dprintkl(KERN_DEBUG, "DataIO: Xfer pad: %02x\n", data); */
-				} else {
-					DC395x_write8(acb, TRM_S1040_SCSI_FIFO,
-						      'K');
-				}
+				/* Danger, Robinson: If you find KGs
+				 * scattered over the wide disk, the driver
+				 * or chip is to blame :-( */
+				DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'K');
+				DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'G');
 			}
-			srb->state |= SRB_XFERPAD;
-			DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
-			/*
-			 * SCSI command 
-			 */
-			bval =
-			    (io_dir & DMACMD_DIR) ? SCMD_FIFO_IN :
-			    SCMD_FIFO_OUT;
-			DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, bval);
+			DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
+		} else {
+			DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1);
+			/* Danger, Robinson: If you find a collection of Ks on your disk
+			 * something broke :-( */
+			if (io_dir & DMACMD_DIR)
+				data = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
+			else
+				DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'K');
 		}
+		srb->state |= SRB_XFERPAD;
+		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
+		/* SCSI command */
+		bval = (io_dir & DMACMD_DIR) ? SCMD_FIFO_IN : SCMD_FIFO_OUT;
+		DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, bval);
 	}
-	/*monitor_next_irq = 2; */
-	/*printk(" done\n"); */
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *	status_phase0: one of dc395x_scsi_phase0[] vectors
- *	 dc395x_statev = (void *)dc395x_scsi_phase0[phase]
- *				if phase =3  
- ********************************************************************
- */
-static
-void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
-		   u16 * pscsi_status)
+static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
 {
-	dprintkdbg(DBG_0, "StatusPhase0 (pid %li)\n", srb->cmd->pid);
-	TRACEPRINTF("STP0 *");
+	dprintkdbg(DBG_0, "status_phase0: (pid#%li) <%02i-%i>\n",
+		srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
 	srb->target_status = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
 	srb->end_message = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);	/* get message */
 	srb->state = SRB_COMPLETED;
 	*pscsi_status = PH_BUS_FREE;	/*.. initial phase */
-	/*1.25 */
-	/*clear_fifo (acb, "STP0"); */
 	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
-	/*
-	 ** SCSI command 
-	 */
 	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *	status_phase1: one of dc395x_scsi_phase1[] vectors
- *	 dc395x_statev = (void *)dc395x_scsi_phase1[phase]
- *				if phase =3 
- ********************************************************************
- */
-static
-void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
-		   u16 * pscsi_status)
-{
-	dprintkdbg(DBG_0, "StatusPhase1 (pid=%li)\n", srb->cmd->pid);
-	TRACEPRINTF("STP1 *");
-	/* Cleanup is now done at the end of DataXXPhase0 */
-	/*cleanup_after_transfer (acb, srb); */
-
+static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
+{
+	dprintkdbg(DBG_0, "status_phase1: (pid#%li) <%02i-%i>\n",
+		srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
 	srb->state = SRB_STATUS;
 	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
-	/*
-	 * SCSI command 
-	 */
 	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_COMP);
 }
 
-/* Message handling */
-
-#if 0
-/* Print received message */
-static void print_msg(u8 * msg_buf, u32 len)
-{
-	int i;
-	printk(" %02x", msg_buf[0]);
-	for (i = 1; i < len; i++)
-		printk(" %02x", msg_buf[i]);
-	printk("\n");
-}
-#endif
 
 /* Check if the message is complete */
 static inline u8 msgin_completed(u8 * msgbuf, u32 len)
@@ -3260,53 +2585,44 @@ static inline u8 msgin_completed(u8 * ms
 
 
 /* reject_msg */
-static inline
-void msgin_reject(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
+static inline void msgin_reject(struct AdapterCtlBlk *acb,
+		struct ScsiReqBlk *srb)
 {
 	srb->msgout_buf[0] = MESSAGE_REJECT;
 	srb->msg_count = 1;
 	DC395x_ENABLE_MSGOUT;
 	srb->state &= ~SRB_MSGIN;
 	srb->state |= SRB_MSGOUT;
-	dprintkl(KERN_INFO,
-	       "Reject message %02x from %02i-%i\n", srb->msgin_buf[0],
-	       srb->dcb->target_id, srb->dcb->target_lun);
-	TRACEPRINTF("\\*");
+	dprintkl(KERN_INFO, "msgin_reject: 0x%02x <%02i-%i>\n",
+		srb->msgin_buf[0],
+		srb->dcb->target_id, srb->dcb->target_lun);
 }
 
 
 /* abort command */
-static inline
-void enable_msgout_abort(struct AdapterCtlBlk *acb,
-			 struct ScsiReqBlk *srb)
+static inline void enable_msgout_abort(struct AdapterCtlBlk *acb,
+		struct ScsiReqBlk *srb)
 {
 	srb->msgout_buf[0] = ABORT;
 	srb->msg_count = 1;
 	DC395x_ENABLE_MSGOUT;
 	srb->state &= ~SRB_MSGIN;
 	srb->state |= SRB_MSGOUT;
-	/*
-	   if (srb->dcb)
-	   srb->dcb->flag &= ~ABORT_DEV_;
-	 */
-	TRACEPRINTF("#*");
 }
 
 
-static
-struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb,
-			      struct DeviceCtlBlk *dcb,
-			      u8 tag)
+static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb,
+		struct DeviceCtlBlk *dcb, u8 tag)
 {
 	struct ScsiReqBlk *srb = NULL;
 	struct ScsiReqBlk *i;
-	        
+	dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) tag=%i srb=%p\n",
+		   srb->cmd->pid, tag, srb);
 
-	dprintkdbg(DBG_0, "QTag Msg (SRB %p): %i\n", srb, tag);
 	if (!(dcb->tag_mask & (1 << tag)))
 		dprintkl(KERN_DEBUG,
-		       "MsgIn_QTag: tag_mask (%08x) does not reserve tag %i!\n",
-		       dcb->tag_mask, tag);
+			"msgin_qtag: tag_mask=0x%08x does not reserve tag %i!\n",
+			dcb->tag_mask, tag);
 
 	if (list_empty(&dcb->srb_going_list))
 		goto mingx0;
@@ -3319,8 +2635,8 @@ struct ScsiReqBlk *msgin_qtag(struct Ada
 	if (!srb)
 		goto mingx0;
 
-	dprintkdbg(DBG_0, "pid %li (%i-%i)\n", srb->cmd->pid,
-	       srb->dcb->target_id, srb->dcb->target_lun);
+	dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) <%02i-%i>\n",
+		srb->cmd->pid, srb->dcb->target_id, srb->dcb->target_lun);
 	if (dcb->flag & ABORT_DEV_) {
 		/*srb->state = SRB_ABORT_SENT; */
 		enable_msgout_abort(acb, srb);
@@ -3329,20 +2645,6 @@ struct ScsiReqBlk *msgin_qtag(struct Ada
 	if (!(srb->state & SRB_DISCONNECT))
 		goto mingx0;
 
-	/* Tag found */
-	{
-		struct ScsiReqBlk *last_srb;
-		        
-		TRACEPRINTF("[%s]*", dcb->active_srb->debugtrace);
-		TRACEPRINTF("RTag*");
-		/* Just for debugging ... */
-		
-		last_srb = srb;
-		srb = dcb->active_srb;
-		TRACEPRINTF("Found.*");
-		srb = last_srb;
-	}
-
 	memcpy(srb->msgin_buf, dcb->active_srb->msgin_buf, acb->msg_len);
 	srb->state |= dcb->active_srb->state;
 	srb->state |= SRB_DATA_XFER;
@@ -3357,15 +2659,13 @@ struct ScsiReqBlk *msgin_qtag(struct Ada
 	srb->msgout_buf[0] = MSG_ABORT_TAG;
 	srb->msg_count = 1;
 	DC395x_ENABLE_MSGOUT;
-	TRACEPRINTF("?*");
-	dprintkl(KERN_DEBUG, "Unknown tag received: %i: abort !!\n", tag);
+	dprintkl(KERN_DEBUG, "msgin_qtag: Unknown tag %i - abort\n", tag);
 	return srb;
 }
 
 
-/* Reprogram registers */
-static inline void
-reprogram_regs(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb)
+static inline void reprogram_regs(struct AdapterCtlBlk *acb,
+		struct DeviceCtlBlk *dcb)
 {
 	DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id);
 	DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period);
@@ -3375,12 +2675,12 @@ reprogram_regs(struct AdapterCtlBlk *acb
 
 
 /* set async transfer mode */
-static
-void msgin_set_async(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
+static void msgin_set_async(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
 {
 	struct DeviceCtlBlk *dcb = srb->dcb;
-	dprintkl(KERN_DEBUG, "Target %02i: No sync transfers\n", dcb->target_id);
-	TRACEPRINTF("!S *");
+	dprintkl(KERN_DEBUG, "msgin_set_async: No sync transfers <%02i-%i>\n",
+		dcb->target_id, dcb->target_lun);
+
 	dcb->sync_mode &= ~(SYNC_NEGO_ENABLE);
 	dcb->sync_mode |= SYNC_NEGO_DONE;
 	/*dcb->sync_period &= 0; */
@@ -3392,26 +2692,23 @@ void msgin_set_async(struct AdapterCtlBl
 	    && !(dcb->sync_mode & WIDE_NEGO_DONE)) {
 		build_wdtr(acb, dcb, srb);
 		DC395x_ENABLE_MSGOUT;
-		dprintkdbg(DBG_0, "SDTR(rej): Try WDTR anyway ...\n");
+		dprintkdbg(DBG_0, "msgin_set_async(rej): Try WDTR anyway\n");
 	}
 }
 
 
 /* set sync transfer mode */
-static
-void msgin_set_sync(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
+static void msgin_set_sync(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
 {
+	struct DeviceCtlBlk *dcb = srb->dcb;
 	u8 bval;
 	int fact;
-	struct DeviceCtlBlk *dcb = srb->dcb;
-	/*u8 oldsyncperiod = dcb->sync_period; */
-	/*u8 oldsyncoffset = dcb->sync_offset; */
-
-	dprintkdbg(DBG_1, "Target %02i: Sync: %ins (%02i.%01i MHz) Offset %i\n",
-	       dcb->target_id, srb->msgin_buf[3] << 2,
-	       (250 / srb->msgin_buf[3]),
-	       ((250 % srb->msgin_buf[3]) * 10) / srb->msgin_buf[3],
-	       srb->msgin_buf[4]);
+	dprintkdbg(DBG_1, "msgin_set_sync: <%02i> Sync: %ins "
+		"(%02i.%01i MHz) Offset %i\n",
+		dcb->target_id, srb->msgin_buf[3] << 2,
+		(250 / srb->msgin_buf[3]),
+		((250 % srb->msgin_buf[3]) * 10) / srb->msgin_buf[3],
+		srb->msgin_buf[4]);
 
 	if (srb->msgin_buf[4] > 15)
 		srb->msgin_buf[4] = 15;
@@ -3430,8 +2727,8 @@ void msgin_set_sync(struct AdapterCtlBlk
 		bval++;
 	if (srb->msgin_buf[3] < clock_period[bval])
 		dprintkl(KERN_INFO,
-		       "Increase sync nego period to %ins\n",
-		       clock_period[bval] << 2);
+			"msgin_set_sync: Increase sync nego period to %ins\n",
+			clock_period[bval] << 2);
 	srb->msgin_buf[3] = clock_period[bval];
 	dcb->sync_period &= 0xf0;
 	dcb->sync_period |= ALT_SYNC | bval;
@@ -3443,18 +2740,17 @@ void msgin_set_sync(struct AdapterCtlBlk
 		fact = 250;
 
 	dprintkl(KERN_INFO,
-	       "Target %02i: %s Sync: %ins Offset %i (%02i.%01i MB/s)\n",
-	       dcb->target_id, (fact == 500) ? "Wide16" : "",
-	       dcb->min_nego_period << 2, dcb->sync_offset,
-	       (fact / dcb->min_nego_period),
-	       ((fact % dcb->min_nego_period) * 10 +
+		"Target %02i: %s Sync: %ins Offset %i (%02i.%01i MB/s)\n",
+		dcb->target_id, (fact == 500) ? "Wide16" : "",
+		dcb->min_nego_period << 2, dcb->sync_offset,
+		(fact / dcb->min_nego_period),
+		((fact % dcb->min_nego_period) * 10 +
 		dcb->min_nego_period / 2) / dcb->min_nego_period);
 
-	TRACEPRINTF("S%i *", dcb->min_nego_period << 2);
 	if (!(srb->state & SRB_DO_SYNC_NEGO)) {
 		/* Reply with corrected SDTR Message */
-		dprintkl(KERN_DEBUG, " .. answer w/  %ins %i\n",
-		       srb->msgin_buf[3] << 2, srb->msgin_buf[4]);
+		dprintkl(KERN_DEBUG, "msgin_set_sync: answer w/%ins %i\n",
+			srb->msgin_buf[3] << 2, srb->msgin_buf[4]);
 
 		memcpy(srb->msgout_buf, srb->msgin_buf, 5);
 		srb->msg_count = 5;
@@ -3465,7 +2761,7 @@ void msgin_set_sync(struct AdapterCtlBlk
 		    && !(dcb->sync_mode & WIDE_NEGO_DONE)) {
 			build_wdtr(acb, dcb, srb);
 			DC395x_ENABLE_MSGOUT;
-			dprintkdbg(DBG_0, "SDTR: Also try WDTR ...\n");
+			dprintkdbg(DBG_0, "msgin_set_sync: Also try WDTR\n");
 		}
 	}
 	srb->state &= ~SRB_DO_SYNC_NEGO;
@@ -3475,14 +2771,12 @@ void msgin_set_sync(struct AdapterCtlBlk
 }
 
 
-static inline
-void msgin_set_nowide(struct AdapterCtlBlk *acb,
-		      struct ScsiReqBlk *srb)
+static inline void msgin_set_nowide(struct AdapterCtlBlk *acb,
+		struct ScsiReqBlk *srb)
 {
 	struct DeviceCtlBlk *dcb = srb->dcb;
-	dprintkdbg(DBG_KG, "WDTR got rejected from target %02i\n",
-	       dcb->target_id);
-	TRACEPRINTF("!W *");
+	dprintkdbg(DBG_1, "msgin_set_nowide: <%02i>\n", dcb->target_id);
+
 	dcb->sync_period &= ~WIDE_SYNC;
 	dcb->sync_mode &= ~(WIDE_NEGO_ENABLE);
 	dcb->sync_mode |= WIDE_NEGO_DONE;
@@ -3492,23 +2786,24 @@ void msgin_set_nowide(struct AdapterCtlB
 	    && !(dcb->sync_mode & SYNC_NEGO_DONE)) {
 		build_sdtr(acb, dcb, srb);
 		DC395x_ENABLE_MSGOUT;
-		dprintkdbg(DBG_0, "WDTR(rej): Try SDTR anyway ...\n");
+		dprintkdbg(DBG_0, "msgin_set_nowide: Rejected. Try SDTR anyway\n");
 	}
 }
 
-static
-void msgin_set_wide(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
+static void msgin_set_wide(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
 {
 	struct DeviceCtlBlk *dcb = srb->dcb;
 	u8 wide = (dcb->dev_mode & NTC_DO_WIDE_NEGO
 		   && acb->config & HCC_WIDE_CARD) ? 1 : 0;
+	dprintkdbg(DBG_1, "msgin_set_wide: <%02i>\n", dcb->target_id);
+
 	if (srb->msgin_buf[3] > wide)
 		srb->msgin_buf[3] = wide;
 	/* Completed */
 	if (!(srb->state & SRB_DO_WIDE_NEGO)) {
 		dprintkl(KERN_DEBUG,
-		       "Target %02i initiates Wide Nego ...\n",
-		       dcb->target_id);
+			"msgin_set_wide: Wide nego initiated <%02i>\n",
+			dcb->target_id);
 		memcpy(srb->msgout_buf, srb->msgin_buf, 4);
 		srb->msg_count = 4;
 		srb->state |= SRB_DO_WIDE_NEGO;
@@ -3521,28 +2816,21 @@ void msgin_set_wide(struct AdapterCtlBlk
 	else
 		dcb->sync_period &= ~WIDE_SYNC;
 	srb->state &= ~SRB_DO_WIDE_NEGO;
-	TRACEPRINTF("W%i *", (dcb->sync_period & WIDE_SYNC ? 1 : 0));
 	/*dcb->sync_mode &= ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE); */
-	dprintkdbg(DBG_KG,
-	       "Wide transfers (%i bit) negotiated with target %02i\n",
-	       (8 << srb->msgin_buf[3]), dcb->target_id);
+	dprintkdbg(DBG_1,
+		"msgin_set_wide: Wide (%i bit) negotiated <%02i>\n",
+		(8 << srb->msgin_buf[3]), dcb->target_id);
 	reprogram_regs(acb, dcb);
 	if ((dcb->sync_mode & SYNC_NEGO_ENABLE)
 	    && !(dcb->sync_mode & SYNC_NEGO_DONE)) {
 		build_sdtr(acb, dcb, srb);
 		DC395x_ENABLE_MSGOUT;
-		dprintkdbg(DBG_0, "WDTR: Also try SDTR ...\n");
+		dprintkdbg(DBG_0, "msgin_set_wide: Also try SDTR.\n");
 	}
 }
 
 
 /*
- ********************************************************************
- * scsiio
- *	msgin_phase0: one of dc395x_scsi_phase0[] vectors
- *	 dc395x_statev = (void *)dc395x_scsi_phase0[phase]
- *				if phase =7   
- *
  * extended message codes:
  *
  *	code	description
@@ -3553,25 +2841,15 @@ void msgin_set_wide(struct AdapterCtlBlk
  *	03h	WIDE DATA TRANSFER REQUEST
  *   04h - 7Fh	Reserved
  *   80h - FFh	Vendor specific
- *  
- ********************************************************************
  */
-static
-void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
-		  u16 * pscsi_status)
+static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
 {
-	struct DeviceCtlBlk *dcb;
-
-	dprintkdbg(DBG_0, "msgin_phase0..............\n");
-	TRACEPRINTF("MIP0*");
-	dcb = acb->active_dcb;
+	struct DeviceCtlBlk *dcb = acb->active_dcb;
+	dprintkdbg(DBG_0, "msgin_phase0: (pid#%li)\n", srb->cmd->pid);
 
 	srb->msgin_buf[acb->msg_len++] = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
 	if (msgin_completed(srb->msgin_buf, acb->msg_len)) {
-		TRACEPRINTF("(%02x)*", srb->msgin_buf[0]);
-		/*dprintkl(KERN_INFO, "MsgIn:"); */
-		/*print_msg (srb->msgin_buf, acb->msg_len); */
-
 		/* Now eval the msg */
 		switch (srb->msgin_buf[0]) {
 		case DISCONNECT:
@@ -3581,7 +2859,6 @@ void msgin_phase0(struct AdapterCtlBlk *
 		case SIMPLE_QUEUE_TAG:
 		case HEAD_OF_QUEUE_TAG:
 		case ORDERED_QUEUE_TAG:
-			TRACEPRINTF("(%02x)*", srb->msgin_buf[1]);
 			srb =
 			    msgin_qtag(acb, dcb,
 					      srb->msgin_buf[1]);
@@ -3605,7 +2882,6 @@ void msgin_phase0(struct AdapterCtlBlk *
 			break;
 
 		case EXTENDED_MESSAGE:
-			TRACEPRINTF("(%02x)*", srb->msgin_buf[2]);
 			/* SDTR */
 			if (srb->msgin_buf[1] == 3
 			    && srb->msgin_buf[2] == EXTENDED_SDTR) {
@@ -3613,52 +2889,51 @@ void msgin_phase0(struct AdapterCtlBlk *
 				break;
 			}
 			/* WDTR */
-			if (srb->msgin_buf[1] == 2 && srb->msgin_buf[2] == EXTENDED_WDTR && srb->msgin_buf[3] <= 2) {	/* sanity check ... */
+			if (srb->msgin_buf[1] == 2
+			    && srb->msgin_buf[2] == EXTENDED_WDTR
+			    && srb->msgin_buf[3] <= 2) { /* sanity check ... */
 				msgin_set_wide(acb, srb);
 				break;
 			}
 			msgin_reject(acb, srb);
 			break;
 
-			/* Discard  wide residual */
 		case MSG_IGNOREWIDE:
-			dprintkdbg(DBG_0, "Ignore Wide Residual!\n");
-			/*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 1); */
-			/*DC395x_read8 (TRM_S1040_SCSI_FIFO); */
+			/* Discard  wide residual */
+			dprintkdbg(DBG_0, "msgin_phase0: Ignore Wide Residual!\n");
 			break;
 
-			/* nothing has to be done */
 		case COMMAND_COMPLETE:
+			/* nothing has to be done */
 			break;
 
+		case SAVE_POINTERS:
 			/*
-			 * SAVE POINTER may be ignored as we have the struct ScsiReqBlk* associated with the
-			 * scsi command. Thanks, Gérard, for pointing it out.
+			 * SAVE POINTER may be ignored as we have the struct
+			 * ScsiReqBlk* associated with the scsi command.
 			 */
-		case SAVE_POINTERS:
-			dprintkdbg(DBG_0, "SAVE POINTER message received (pid %li: rem.%i) ... ignore :-(\n",
-			       srb->cmd->pid, srb->total_xfer_length);
-			/*srb->Saved_Ptr = srb->TotalxferredLen; */
+			dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) "
+				"SAVE POINTER rem=%i Ignore\n",
+				srb->cmd->pid, srb->total_xfer_length);
 			break;
-			/* The device might want to restart transfer with a RESTORE */
+
 		case RESTORE_POINTERS:
-			dprintkl(KERN_DEBUG,
-			       "RESTORE POINTER message received ... ignore :-(\n");
-			/*dc395x_restore_ptr (acb, srb); */
+			dprintkdbg(DBG_0, "msgin_phase0: RESTORE POINTER. Ignore\n");
 			break;
+
 		case ABORT:
-			dprintkl(KERN_DEBUG,
-			       "ABORT msg received (pid %li %02i-%i)\n",
-			       srb->cmd->pid, dcb->target_id,
-			       dcb->target_lun);
+			dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) "
+				"<%02i-%i> ABORT msg\n",
+				srb->cmd->pid, dcb->target_id,
+				dcb->target_lun);
 			dcb->flag |= ABORT_DEV_;
 			enable_msgout_abort(acb, srb);
 			break;
-			/* reject unknown messages */
+
 		default:
+			/* reject unknown messages */
 			if (srb->msgin_buf[0] & IDENTIFY_BASE) {
-				dprintkl(KERN_DEBUG, "Identify Message received?\n");
-				/*TRACEOUT (" %s\n", srb->debugtrace); */
+				dprintkdbg(DBG_0, "msgin_phase0: Identify msg\n");
 				srb->msg_count = 1;
 				srb->msgout_buf[0] = dcb->identify_msg;
 				DC395x_ENABLE_MSGOUT;
@@ -3666,104 +2941,51 @@ void msgin_phase0(struct AdapterCtlBlk *
 				/*break; */
 			}
 			msgin_reject(acb, srb);
-			TRACEOUT(" %s\n", srb->debugtrace);
 		}
-		TRACEPRINTF(".*");
 
 		/* Clear counter and MsgIn state */
 		srb->state &= ~SRB_MSGIN;
 		acb->msg_len = 0;
 	}
-
-	/*1.25 */
-	if ((*pscsi_status & PHASEMASK) != PH_MSG_IN)
-#if 0
-		clear_fifo(acb, "MIP0_");
-#else
-		TRACEPRINTF("N/Cln *");
-#endif
 	*pscsi_status = PH_BUS_FREE;
 	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important ... you know! */
 	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *	msgin_phase1: one of dc395x_scsi_phase1[] vectors
- *	 dc395x_statev = (void *)dc395x_scsi_phase1[phase]
- *				if phase =7	   
- ********************************************************************
- */
-static
-void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
-		  u16 * pscsi_status)
-{
-	dprintkdbg(DBG_0, "msgin_phase1..............\n");
-	TRACEPRINTF("MIP1 *");
-	clear_fifo(acb, "MIP1");
+static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
+{
+	dprintkdbg(DBG_0, "msgin_phase1: (pid#%li)\n", srb->cmd->pid);
+	clear_fifo(acb, "msgin_phase1");
 	DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1);
 	if (!(srb->state & SRB_MSGIN)) {
 		srb->state &= ~SRB_DISCONNECT;
 		srb->state |= SRB_MSGIN;
 	}
 	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
-	/*
-	 * SCSI command 
-	 */
+	/* SCSI command */
 	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_IN);
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *	nop0: one of dc395x_scsi_phase1[] ,dc395x_scsi_phase0[] vectors
- *	 dc395x_statev = (void *)dc395x_scsi_phase0[phase]
- *	 dc395x_statev = (void *)dc395x_scsi_phase1[phase]
- *				if phase =4 ..PH_BUS_FREE
- ********************************************************************
- */
-static
-void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
-	  u16 * pscsi_status)
+static void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
 {
-	/*TRACEPRINTF("NOP0 *"); */
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *	nop1: one of dc395x_scsi_phase0[] ,dc395x_scsi_phase1[] vectors
- *	 dc395x_statev = (void *)dc395x_scsi_phase0[phase]
- *	 dc395x_statev = (void *)dc395x_scsi_phase1[phase]
- *				if phase =5
- ********************************************************************
- */
-static
-void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
-	  u16 * pscsi_status)
+static void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
 {
-	/*TRACEPRINTF("NOP1 *"); */
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *		msgin_phase0
- ********************************************************************
- */
-static
-void set_xfer_rate(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb)
+static void set_xfer_rate(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb)
 {
 	struct DeviceCtlBlk *i;
 
-	/*
-	 * set all lun device's  period , offset
-	 */
+	/* set all lun device's  period, offset */
 	if (dcb->identify_msg & 0x07)
 		return;
 
@@ -3782,47 +3004,39 @@ void set_xfer_rate(struct AdapterCtlBlk 
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *		dc395x_interrupt
- ********************************************************************
- */
 static void disconnect(struct AdapterCtlBlk *acb)
 {
-	struct DeviceCtlBlk *dcb;
+	struct DeviceCtlBlk *dcb = acb->active_dcb;
 	struct ScsiReqBlk *srb;
 
-	dprintkdbg(DBG_0, "Disconnect (pid=%li)\n", acb->active_dcb->active_srb->cmd->pid);
-	dcb = acb->active_dcb;
 	if (!dcb) {
-		dprintkl(KERN_ERR, "Disc: Exception Disconnect dcb=NULL !!\n ");
+		dprintkl(KERN_ERR, "disconnect: No such device\n");
 		udelay(500);
 		/* Suspend queue for a while */
 		acb->scsi_host->last_reset =
 		    jiffies + HZ / 2 +
 		    HZ * acb->eeprom.delay_time;
-		clear_fifo(acb, "DiscEx");
+		clear_fifo(acb, "disconnectEx");
 		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT);
 		return;
 	}
 	srb = dcb->active_srb;
 	acb->active_dcb = NULL;
-	TRACEPRINTF("DISC *");
+	dprintkdbg(DBG_0, "disconnect: (pid#%li)\n", srb->cmd->pid);
 
 	srb->scsi_phase = PH_BUS_FREE;	/* initial phase */
-	clear_fifo(acb, "Disc");
+	clear_fifo(acb, "disconnect");
 	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT);
 	if (srb->state & SRB_UNEXPECT_RESEL) {
-		dprintkl(KERN_ERR, "Disc: Unexpected Reselection (%i-%i)\n",
-		       dcb->target_id, dcb->target_lun);
+		dprintkl(KERN_ERR,
+			"disconnect: Unexpected reselection <%02i-%i>\n",
+			dcb->target_id, dcb->target_lun);
 		srb->state = 0;
 		waiting_process_next(acb);
 	} else if (srb->state & SRB_ABORT_SENT) {
-		/*Scsi_Cmnd* cmd = srb->cmd; */
 		dcb->flag &= ~ABORT_DEV_;
 		acb->scsi_host->last_reset = jiffies + HZ / 2 + 1;
-		dprintkl(KERN_ERR, "Disc: SRB_ABORT_SENT!\n");
+		dprintkl(KERN_ERR, "disconnect: SRB_ABORT_SENT\n");
 		doing_srb_done(acb, DID_ABORT, srb->cmd, 1);
 		waiting_process_next(acb);
 	} else {
@@ -3837,19 +3051,16 @@ static void disconnect(struct AdapterCtl
 			if (srb->state != SRB_START_
 			    && srb->state != SRB_MSGOUT) {
 				srb->state = SRB_READY;
-				dprintkl(KERN_DEBUG, "Unexpected Disconnection (pid %li)!\n",
-				       srb->cmd->pid);
+				dprintkl(KERN_DEBUG,
+					"disconnect: (pid#%li) Unexpected\n",
+					srb->cmd->pid);
 				srb->target_status = SCSI_STAT_SEL_TIMEOUT;
-				TRACEPRINTF("UnExpD *");
-				TRACEOUT("%s\n", srb->debugtrace);
 				goto disc1;
 			} else {
 				/* Normal selection timeout */
-				TRACEPRINTF("SlTO *");
-				dprintkdbg(DBG_KG,
-				       "Disc: SelTO (pid=%li) for dev %02i-%i\n",
-				       srb->cmd->pid, dcb->target_id,
-				       dcb->target_lun);
+				dprintkdbg(DBG_KG, "disconnect: (pid#%li) "
+					"<%02i-%i> SelTO\n", srb->cmd->pid,
+					dcb->target_id, dcb->target_lun);
 				if (srb->retry_count++ > DC395x_MAX_RETRIES
 				    || acb->scan_devices) {
 					srb->target_status =
@@ -3858,8 +3069,9 @@ static void disconnect(struct AdapterCtl
 				}
 				free_tag(dcb, srb);
 				srb_going_to_waiting_move(dcb, srb);
-				dprintkdbg(DBG_KG, "Retry pid %li ...\n",
-				       srb->cmd->pid);
+				dprintkdbg(DBG_KG,
+					"disconnect: (pid#%li) Retry\n",
+					srb->cmd->pid);
 				waiting_set_timer(acb, HZ / 20);
 			}
 		} else if (srb->state & SRB_DISCONNECT) {
@@ -3867,18 +3079,11 @@ static void disconnect(struct AdapterCtl
 			/*
 			 * SRB_DISCONNECT (This is what we expect!)
 			 */
-			/* dprintkl(KERN_DEBUG, "DoWaitingSRB (pid=%li)\n", srb->cmd->pid); */
-			TRACEPRINTF("+*");
 			if (bval & 0x40) {
-				dprintkdbg(DBG_0, "Debug: DISC: SCSI bus stat %02x: ACK set! Other controllers?\n",
+				dprintkdbg(DBG_0, "disconnect: SCSI bus stat "
+					" 0x%02x: ACK set! Other controllers?\n",
 					bval);
 				/* It could come from another initiator, therefore don't do much ! */
-				TRACEPRINTF("ACK(%02x) *", bval);
-				/*dump_register_info (acb, dcb, srb); */
-				/*TRACEOUT (" %s\n", srb->debugtrace); */
-				/*dcb->flag |= ABORT_DEV_; */
-				/*enable_msgout_abort (acb, srb); */
-				/*DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_CLRFIFO | DO_CLRATN | DO_HWRESELECT); */
 			} else
 				waiting_process_next(acb);
 		} else if (srb->state & SRB_COMPLETED) {
@@ -3889,51 +3094,40 @@ static void disconnect(struct AdapterCtl
 			free_tag(dcb, srb);
 			dcb->active_srb = NULL;
 			srb->state = SRB_FREE;
-			/*dprintkl(KERN_DEBUG, "done (pid=%li)\n", srb->cmd->pid); */
 			srb_done(acb, dcb, srb);
 		}
 	}
-	return;
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *		reselect
- ********************************************************************
- */
 static void reselect(struct AdapterCtlBlk *acb)
 {
-	struct DeviceCtlBlk *dcb;
+	struct DeviceCtlBlk *dcb = acb->active_dcb;
 	struct ScsiReqBlk *srb = NULL;
 	u16 rsel_tar_lun_id;
 	u8 id, lun;
 	u8 arblostflag = 0;
+	dprintkdbg(DBG_0, "reselect: acb=%p\n", acb);
 
-	dprintkdbg(DBG_0, "reselect..............\n");
-
-	clear_fifo(acb, "Resel");
+	clear_fifo(acb, "reselect");
 	/*DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH); */
 	/* Read Reselected Target ID and LUN */
 	rsel_tar_lun_id = DC395x_read16(acb, TRM_S1040_SCSI_TARGETID);
-	dcb = acb->active_dcb;
 	if (dcb) {		/* Arbitration lost but Reselection win */
 		srb = dcb->active_srb;
 		if (!srb) {
-			dprintkl(KERN_DEBUG, "Arb lost Resel won, but active_srb == NULL!\n");
+			dprintkl(KERN_DEBUG, "reselect: Arb lost Resel won, "
+				"but active_srb == NULL\n");
 			DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
 			return;
 		}
 		/* Why the if ? */
-		if (!(acb->scan_devices)) {
-			dprintkdbg(DBG_KG,
-			       "Arb lost but Resel win pid %li (%02i-%i) Rsel %04x Stat %04x\n",
-			       srb->cmd->pid, dcb->target_id,
-			       dcb->target_lun, rsel_tar_lun_id,
-			       DC395x_read16(acb, TRM_S1040_SCSI_STATUS));
-			TRACEPRINTF("ArbLResel!*");
-			/*TRACEOUT (" %s\n", srb->debugtrace); */
+		if (!acb->scan_devices) {
+			dprintkdbg(DBG_KG, "reselect: (pid#%li) <%02i-%i> "
+				"Arb lost but Resel win rsel=%i stat=0x%04x\n",
+				srb->cmd->pid, dcb->target_id,
+				dcb->target_lun, rsel_tar_lun_id,
+				DC395x_read16(acb, TRM_S1040_SCSI_STATUS));
 			arblostflag = 1;
 			/*srb->state |= SRB_DISCONNECT; */
 
@@ -3947,47 +3141,37 @@ static void reselect(struct AdapterCtlBl
 	}
 	/* Read Reselected Target Id and LUN */
 	if (!(rsel_tar_lun_id & (IDENTIFY_BASE << 8)))
-		dprintkl(KERN_DEBUG, "Resel expects identify msg! Got %04x!\n",
-		       rsel_tar_lun_id);
+		dprintkl(KERN_DEBUG, "reselect: Expects identify msg. "
+			"Got %i!\n", rsel_tar_lun_id);
 	id = rsel_tar_lun_id & 0xff;
 	lun = (rsel_tar_lun_id >> 8) & 7;
 	dcb = find_dcb(acb, id, lun);
 	if (!dcb) {
-		dprintkl(KERN_ERR, "Reselect from non existing device (%02i-%i)\n",
-		       id, lun);
+		dprintkl(KERN_ERR, "reselect: From non existent device "
+			"<%02i-%i>\n", id, lun);
 		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
 		return;
 	}
-
 	acb->active_dcb = dcb;
 
 	if (!(dcb->dev_mode & NTC_DO_DISCONNECT))
-		dprintkl(KERN_DEBUG, "Reselection in spite of forbidden disconnection? (%02i-%i)\n",
-		       dcb->target_id, dcb->target_lun);
+		dprintkl(KERN_DEBUG, "reselect: in spite of forbidden "
+			"disconnection? <%02i-%i>\n",
+			dcb->target_id, dcb->target_lun);
 
-	if ((dcb->sync_mode & EN_TAG_QUEUEING) /*&& !arblostflag */ ) {
-		struct ScsiReqBlk *oldSRB = srb;
+	if (dcb->sync_mode & EN_TAG_QUEUEING /*&& !arblostflag */) {
 		srb = acb->tmp_srb;
-#if debug_enabled(DBG_TRACE|DBG_TRACEALL)
-		srb->debugpos = 0;
-		srb->debugtrace[0] = 0;
-#endif
 		dcb->active_srb = srb;
-		if (oldSRB)
-			TRACEPRINTF("ArbLResel(%li):*", oldSRB->cmd->pid);
-		/*if (arblostflag) dprintkl(KERN_DEBUG, "Reselect: Wait for Tag ... \n"); */
 	} else {
 		/* There can be only one! */
 		srb = dcb->active_srb;
-		if (srb)
-			TRACEPRINTF("RSel *");
 		if (!srb || !(srb->state & SRB_DISCONNECT)) {
 			/*
 			 * abort command
 			 */
 			dprintkl(KERN_DEBUG,
-			       "Reselected w/o disconnected cmds from %02i-%i?\n",
-			       dcb->target_id, dcb->target_lun);
+				"reselect: w/o disconnected cmds <%02i-%i>\n",
+				dcb->target_id, dcb->target_lun);
 			srb = acb->tmp_srb;
 			srb->state = SRB_UNEXPECT_RESEL;
 			dcb->active_srb = srb;
@@ -4000,14 +3184,11 @@ static void reselect(struct AdapterCtlBl
 				srb->state = SRB_DATA_XFER;
 
 		}
-		/*if (arblostflag) TRACEOUT (" %s\n", srb->debugtrace); */
 	}
 	srb->scsi_phase = PH_BUS_FREE;	/* initial phase */
-	/* 
-	 ***********************************************
-	 ** Program HA ID, target ID, period and offset
-	 ***********************************************
-	 */
+
+	/* Program HA ID, target ID, period and offset */
+	dprintkdbg(DBG_0, "reselect: select <%i>\n", dcb->target_id);
 	DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id);	/* host   ID */
 	DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id);		/* target ID */
 	DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, dcb->sync_offset);		/* offset    */
@@ -4018,10 +3199,6 @@ static void reselect(struct AdapterCtlBl
 }
 
 
-
-
-
-
 static inline u8 tagq_blacklist(char *name)
 {
 #ifndef DC395x_NO_TAGQ
@@ -4038,8 +3215,7 @@ static inline u8 tagq_blacklist(char *na
 }
 
 
-static
-void disc_tagq_set(struct DeviceCtlBlk *dcb, struct ScsiInqData *ptr)
+static void disc_tagq_set(struct DeviceCtlBlk *dcb, struct ScsiInqData *ptr)
 {
 	/* Check for SCSI format (ANSI and Response data format) */
 	if ((ptr->Vers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2) {
@@ -4048,7 +3224,7 @@ void disc_tagq_set(struct DeviceCtlBlk *
 		    /*(dcb->dev_mode & NTC_DO_DISCONNECT) */
 		    /* ((dcb->dev_type == TYPE_DISK) 
 		       || (dcb->dev_type == TYPE_MOD)) && */
-		    !tagq_blacklist(((char *) ptr) + 8)) {
+		    !tagq_blacklist(((char *)ptr) + 8)) {
 			if (dcb->max_command == 1)
 				dcb->max_command =
 				    dcb->acb->tag_max_num;
@@ -4060,9 +3236,8 @@ void disc_tagq_set(struct DeviceCtlBlk *
 }
 
 
-static
-void add_dev(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
-	     struct ScsiInqData *ptr)
+static void add_dev(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
+		struct ScsiInqData *ptr)
 {
 	u8 bval1 = ptr->DevType & SCSI_DEVTYPE;
 	dcb->dev_type = bval1;
@@ -4071,59 +3246,45 @@ void add_dev(struct AdapterCtlBlk *acb, 
 }
 
 
-/* 
- ********************************************************************
- * unmap mapped pci regions from SRB
- ********************************************************************
- */
-static
-void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
+/* unmap mapped pci regions from SRB */
+static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
 {
-	int dir;
 	Scsi_Cmnd *cmd = srb->cmd;
-	dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+	int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
 	if (cmd->use_sg && dir != PCI_DMA_NONE) {
 		/* unmap DC395x SG list */
-		dprintkdbg(DBG_SGPARANOIA,
-		       "Unmap SG descriptor list %08x (%05x)\n",
-		       srb->sg_bus_addr,
-		       sizeof(struct SGentry) * DC395x_MAX_SG_LISTENTRY);
+		dprintkdbg(DBG_SG, "pci_unmap_srb: list=%08x(%05x)\n",
+			srb->sg_bus_addr, SEGMENTX_LEN);
 		pci_unmap_single(acb->dev, srb->sg_bus_addr,
-				 sizeof(struct SGentry) *
-				 DC395x_MAX_SG_LISTENTRY,
+				 SEGMENTX_LEN,
 				 PCI_DMA_TODEVICE);
-		dprintkdbg(DBG_SGPARANOIA, "Unmap %i SG segments from %p\n",
-		       cmd->use_sg, cmd->request_buffer);
+		dprintkdbg(DBG_SG, "pci_unmap_srb: segs=%i buffer=%p\n",
+			cmd->use_sg, cmd->request_buffer);
 		/* unmap the sg segments */
 		pci_unmap_sg(acb->dev,
-			     (struct scatterlist *) cmd->request_buffer,
+			     (struct scatterlist *)cmd->request_buffer,
 			     cmd->use_sg, dir);
 	} else if (cmd->request_buffer && dir != PCI_DMA_NONE) {
-		dprintkdbg(DBG_SGPARANOIA, "Unmap buffer at %08x (%05x)\n",
-		       srb->segment_x[0].address, cmd->request_bufflen);
+		dprintkdbg(DBG_SG, "pci_unmap_srb: buffer=%08x(%05x)\n",
+			srb->segment_x[0].address, cmd->request_bufflen);
 		pci_unmap_single(acb->dev, srb->segment_x[0].address,
 				 cmd->request_bufflen, dir);
 	}
 }
 
 
-/* 
- ********************************************************************
- * unmap mapped pci sense buffer from SRB
- ********************************************************************
- */
-static
-void pci_unmap_srb_sense(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
+/* unmap mapped pci sense buffer from SRB */
+static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb,
+		struct ScsiReqBlk *srb)
 {
 	if (!(srb->flag & AUTO_REQSENSE))
 		return;
 	/* Unmap sense buffer */
-	dprintkdbg(DBG_SGPARANOIA, "Unmap sense buffer from %08x\n",
+	dprintkdbg(DBG_SG, "pci_unmap_srb_sense: buffer=%08x\n",
 	       srb->segment_x[0].address);
 	pci_unmap_single(acb->dev, srb->segment_x[0].address,
 			 srb->segment_x[0].length, PCI_DMA_FROMDEVICE);
 	/* Restore SG stuff */
-	/*printk ("Auto_ReqSense finished: Restore Counters ...\n"); */
 	srb->total_xfer_length = srb->xferred;
 	srb->segment_x[0].address =
 	    srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address;
@@ -4133,42 +3294,33 @@ void pci_unmap_srb_sense(struct AdapterC
 
 
 /*
- ********************************************************************
- * scsiio
- *		disconnect
- *	Complete execution of a SCSI command
- *	Signal completion to the generic SCSI driver  
- ********************************************************************
+ * Complete execution of a SCSI command
+ * Signal completion to the generic SCSI driver  
  */
-static
-void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
-	      struct ScsiReqBlk *srb)
+static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb)
 {
 	u8 tempcnt, status;
-	Scsi_Cmnd *cmd;
+	Scsi_Cmnd *cmd = srb->cmd;
 	struct ScsiInqData *ptr;
-	/*u32              drv_flags=0; */
 	int dir;
 
-	cmd = srb->cmd;
-	TRACEPRINTF("DONE *");
-
 	dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
-	ptr = (struct ScsiInqData *) (cmd->request_buffer);
-	if (cmd->use_sg)
-		ptr =
-		    (struct ScsiInqData *) CPU_ADDR(*(struct scatterlist *)
-						    ptr);
-	dprintkdbg(DBG_SGPARANOIA, 
-	       "SRBdone SG=%i (%i/%i), req_buf = %p, adr = %p\n",
-	       cmd->use_sg, srb->sg_index, srb->sg_count,
-	       cmd->request_buffer, ptr);
-	dprintkdbg(DBG_KG,
-	       "SRBdone (pid %li, target %02i-%i): ", srb->cmd->pid,
-	       srb->cmd->device->id, srb->cmd->device->lun);
+	if (cmd->use_sg) {
+		struct scatterlist* sg = (struct scatterlist *)cmd->request_buffer;
+		ptr = (struct ScsiInqData *)(page_address(sg->page) + sg->offset);
+	} else {
+		ptr = (struct ScsiInqData *)(cmd->request_buffer);
+	}
+
+	dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->pid,
+		srb->cmd->device->id, srb->cmd->device->lun);
+	dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p addr=%p\n",
+		srb, cmd->use_sg, srb->sg_index, srb->sg_count,
+		cmd->request_buffer, ptr);
 	status = srb->target_status;
 	if (srb->flag & AUTO_REQSENSE) {
-		dprintkdbg(DBG_0, "AUTO_REQSENSE1..............\n");
+		dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE1\n");
 		pci_unmap_srb_sense(acb, srb);
 		/*
 		 ** target status..........................
@@ -4176,61 +3328,60 @@ void srb_done(struct AdapterCtlBlk *acb,
 		srb->flag &= ~AUTO_REQSENSE;
 		srb->adapter_status = 0;
 		srb->target_status = CHECK_CONDITION << 1;
-		if (debug_enabled(DBG_KG)) {
+		if (debug_enabled(DBG_1)) {
 			switch (cmd->sense_buffer[2] & 0x0f) {
 			case NOT_READY:
 				dprintkl(KERN_DEBUG,
-				     "ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ",
+				     "ReqSense: NOT_READY cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
 				     cmd->cmnd[0], dcb->target_id,
 				     dcb->target_lun, status, acb->scan_devices);
 				break;
 			case UNIT_ATTENTION:
 				dprintkl(KERN_DEBUG,
-				     "ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ",
+				     "ReqSense: UNIT_ATTENTION cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
 				     cmd->cmnd[0], dcb->target_id,
 				     dcb->target_lun, status, acb->scan_devices);
 				break;
 			case ILLEGAL_REQUEST:
 				dprintkl(KERN_DEBUG,
-				     "ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ",
+				     "ReqSense: ILLEGAL_REQUEST cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
 				     cmd->cmnd[0], dcb->target_id,
 				     dcb->target_lun, status, acb->scan_devices);
 				break;
 			case MEDIUM_ERROR:
 				dprintkl(KERN_DEBUG,
-				     "ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ",
+				     "ReqSense: MEDIUM_ERROR cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
 				     cmd->cmnd[0], dcb->target_id,
 				     dcb->target_lun, status, acb->scan_devices);
 				break;
 			case HARDWARE_ERROR:
 				dprintkl(KERN_DEBUG,
-				     "ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ",
+				     "ReqSense: HARDWARE_ERROR cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
 				     cmd->cmnd[0], dcb->target_id,
 				     dcb->target_lun, status, acb->scan_devices);
 				break;
 			}
 			if (cmd->sense_buffer[7] >= 6)
-				dprintkl(KERN_DEBUG, 
-				     "Sense=%02x, ASC=%02x, ASCQ=%02x (%08x %08x) ",
-				     cmd->sense_buffer[2], cmd->sense_buffer[12],
-				     cmd->sense_buffer[13],
-				     *((unsigned int *) (cmd->sense_buffer + 3)),
-				     *((unsigned int *) (cmd->sense_buffer + 8)));
+				printk("sense=0x%02x ASC=0x%02x ASCQ=0x%02x "
+					"(0x%08x 0x%08x)\n",
+					cmd->sense_buffer[2], cmd->sense_buffer[12],
+					cmd->sense_buffer[13],
+					*((unsigned int *)(cmd->sense_buffer + 3)),
+					*((unsigned int *)(cmd->sense_buffer + 8)));
 			else
-				dprintkl(KERN_DEBUG,
-				     "Sense=%02x, No ASC/ASCQ (%08x) ",
-				     cmd->sense_buffer[2],
-				     *((unsigned int *) (cmd->sense_buffer + 3)));
+				printk("sense=0x%02x No ASC/ASCQ (0x%08x)\n",
+					cmd->sense_buffer[2],
+					*((unsigned int *)(cmd->sense_buffer + 3)));
 		}
 
 		if (status == (CHECK_CONDITION << 1)) {
 			cmd->result = DID_BAD_TARGET << 16;
 			goto ckc_e;
 		}
-		dprintkdbg(DBG_0, "AUTO_REQSENSE2..............\n");
+		dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE2\n");
 
-		if ((srb->total_xfer_length)
-		    && (srb->total_xfer_length >= cmd->underflow))
+		if (srb->total_xfer_length
+		    && srb->total_xfer_length >= cmd->underflow)
 			cmd->result =
 			    MK_RES_LNX(DRIVER_SENSE, DID_OK,
 				       srb->end_message, CHECK_CONDITION);
@@ -4253,8 +3404,7 @@ void srb_done(struct AdapterCtlBlk *acb,
 			return;
 		} else if (status_byte(status) == QUEUE_FULL) {
 			tempcnt = (u8)list_size(&dcb->srb_going_list);
-			printk
-			    ("\nDC395x:  QUEUE_FULL for dev %02i-%i with %i cmnds\n",
+			dprintkl(KERN_INFO, "QUEUE_FULL for dev <%02i-%i> with %i cmnds\n",
 			     dcb->target_id, dcb->target_lun, tempcnt);
 			if (tempcnt > 1)
 				tempcnt--;
@@ -4298,11 +3448,11 @@ void srb_done(struct AdapterCtlBlk *acb,
 
 	if (dir != PCI_DMA_NONE) {
 		if (cmd->use_sg)
-			pci_dma_sync_sg(acb->dev,
-					(struct scatterlist *) cmd->
+			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);
 	}
@@ -4336,48 +3486,35 @@ void srb_done(struct AdapterCtlBlk *acb,
 	cmd->SCp.buffers_residual = 0;
 	if (debug_enabled(DBG_KG)) {
 		if (srb->total_xfer_length)
-			dprintkdbg(DBG_KG, "pid %li: %02x (%02i-%i): Missed %i bytes\n",
-			     cmd->pid, cmd->cmnd[0], cmd->device->id,
-			     cmd->device->lun, srb->total_xfer_length);
+			dprintkdbg(DBG_KG, "srb_done: (pid#%li) <%02i-%i> "
+				"cmnd=0x%02x Missed %i bytes\n",
+				cmd->pid, cmd->device->id, cmd->device->lun,
+				cmd->cmnd[0], srb->total_xfer_length);
 	}
 
 	srb_going_remove(dcb, srb);
 	/* Add to free list */
 	if (srb == acb->tmp_srb)
-		dprintkl(KERN_ERR, "ERROR! Completed Cmnd with tmp_srb!\n");
-	else
+		dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n");
+	else {
+		dprintkdbg(DBG_0, "srb_done: (pid#%li) done result=0x%08x\n",
+			cmd->pid, cmd->result);
 		srb_free_insert(acb, srb);
-
-	dprintkdbg(DBG_0, "SRBdone: done pid %li\n", cmd->pid);
-	if (debug_enabled(DBG_KG)) {
-		printk(" 0x%08x\n", cmd->result);
 	}
-	TRACEPRINTF("%08x(%li)*", cmd->result, jiffies);
 	pci_unmap_srb(acb, srb);
-	/*DC395x_UNLOCK_ACB_NI; */
-	cmd->scsi_done(cmd);
-	/*DC395x_LOCK_ACB_NI; */
-	TRACEOUTALL(KERN_INFO " %s\n", srb->debugtrace);
 
+	cmd->scsi_done(cmd);
 	waiting_process_next(acb);
-	return;
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *		DC395x_reset
- * abort all cmds in our queues
- ********************************************************************
- */
-static
-void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
-		    Scsi_Cmnd * cmd, u8 force)
+/* abort all cmds in our queues */
+static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
+		Scsi_Cmnd *cmd, u8 force)
 {
 	struct DeviceCtlBlk *dcb;
-
 	dprintkl(KERN_INFO, "doing_srb_done: pids ");
+
 	list_for_each_entry(dcb, &acb->dcb_list, list) {
 		struct ScsiReqBlk *srb;
 		struct ScsiReqBlk *tmp;
@@ -4390,16 +3527,8 @@ void doing_srb_done(struct AdapterCtlBlk
 			p = srb->cmd;
 			dir = scsi_to_pci_dma_dir(p->sc_data_direction);
 			result = MK_RES(0, did_flag, 0, 0);
-
-			/*result = MK_RES(0,DID_RESET,0,0); */
-			TRACEPRINTF("Reset(%li):%08x*", jiffies, result);
-			printk(" (G)");
-#if 1				/*ndef DC395x_DEBUGTRACE */
-			printk("%li(%02i-%i) ", p->pid,
+			printk("G:%li(%02i-%i) ", p->pid,
 			       p->device->id, p->device->lun);
-#endif
-			TRACEOUT("%s\n", srb->debugtrace);
-
 			srb_going_remove(dcb, srb);
 			free_tag(dcb, srb);
 			srb_free_insert(acb, srb);
@@ -4414,11 +3543,11 @@ void doing_srb_done(struct AdapterCtlBlk
 		}
 		if (!list_empty(&dcb->srb_going_list))
 			dprintkl(KERN_DEBUG, 
-			       "How could the ML send cmnds to the Going queue? (%02i-%i)!!\n",
+			       "How could the ML send cmnds to the Going queue? <%02i-%i>\n",
 			       dcb->target_id, dcb->target_lun);
 		if (dcb->tag_mask)
 			dprintkl(KERN_DEBUG,
-			       "tag_mask for %02i-%i should be empty, is %08x!\n",
+			       "tag_mask for <%02i-%i> should be empty, is %08x!\n",
 			       dcb->target_id, dcb->target_lun,
 			       dcb->tag_mask);
 
@@ -4428,16 +3557,10 @@ void doing_srb_done(struct AdapterCtlBlk
 			p = srb->cmd;
 
 			result = MK_RES(0, did_flag, 0, 0);
-			TRACEPRINTF("Reset(%li):%08x*", jiffies, result);
-			printk(" (W)");
-#if 1				/*ndef DC395x_DEBUGTRACE */
-			printk("%li(%i-%i)", p->pid, p->device->id,
+			printk("W:%li<%02i-%i>", p->pid, p->device->id,
 			       p->device->lun);
-#endif
-			TRACEOUT("%s\n", srb->debugtrace);
 			srb_waiting_remove(dcb, srb);
 			srb_free_insert(acb, srb);
-
 			p->result = result;
 			pci_unmap_srb_sense(acb, srb);
 			pci_unmap_srb(acb, srb);
@@ -4448,41 +3571,26 @@ void doing_srb_done(struct AdapterCtlBlk
 			}
 		}
 		if (!list_empty(&dcb->srb_waiting_list))
-			printk
-			    ("\nDC395x: Debug: ML queued %i cmnds again to %02i-%i\n",
+			dprintkl(KERN_DEBUG, "ML queued %i cmnds again to <%02i-%i>\n",
 			     list_size(&dcb->srb_waiting_list), dcb->target_id,
 			     dcb->target_lun);
-
 		dcb->flag &= ~ABORT_DEV_;
 	}
 	printk("\n");
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *		DC395x_shutdown   DC395x_reset
- ********************************************************************
- */
 static void reset_scsi_bus(struct AdapterCtlBlk *acb)
 {
-	/*u32  drv_flags=0; */
-
-	dprintkdbg(DBG_0, "reset_scsi_bus..............\n");
-
-	/*DC395x_DRV_LOCK(drv_flags); */
+	dprintkdbg(DBG_0, "reset_scsi_bus: acb=%p\n", acb);
 	acb->acb_flag |= RESET_DEV;	/* RESET_DETECT, RESET_DONE, RESET_DEV */
-
 	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_RSTSCSI);
-	while (!(DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET));
 
-	/*DC395x_DRV_UNLOCK(drv_flags); */
-	return;
+	while (!(DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET))
+		/* nothing */;
 }
 
 
-/* Set basic config */
 static void set_basic_config(struct AdapterCtlBlk *acb)
 {
 	u8 bval;
@@ -4508,7 +3616,6 @@ static void set_basic_config(struct Adap
 	wval = DC395x_read16(acb, TRM_S1040_DMA_CONFIG) & ~DMA_FIFO_CTRL;
 	wval |=
 	    DMA_FIFO_HALF_HALF | DMA_ENHANCE /*| DMA_MEM_MULTI_READ */ ;
-	/*dprintkl(KERN_INFO, "DMA_Config: %04x\n", wval); */
 	DC395x_write16(acb, TRM_S1040_DMA_CONFIG, wval);
 	/* Clear pending interrupt status */
 	DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS);
@@ -4520,15 +3627,9 @@ static void set_basic_config(struct Adap
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *		dc395x_interrupt
- ********************************************************************
- */
 static void scsi_reset_detect(struct AdapterCtlBlk *acb)
 {
-	dprintkl(KERN_INFO, "scsi_reset_detect\n");
+	dprintkl(KERN_INFO, "scsi_reset_detect: acb=%p\n", acb);
 	/* delay half a second */
 	if (timer_pending(&acb->waiting_timer))
 		del_timer(&acb->waiting_timer);
@@ -4542,7 +3643,7 @@ static void scsi_reset_detect(struct Ada
 	    jiffies + 5 * HZ / 2 +
 	    HZ * acb->eeprom.delay_time;
 
-	clear_fifo(acb, "RstDet");
+	clear_fifo(acb, "scsi_reset_detect");
 	set_basic_config(acb);
 	/*1.25 */
 	/*DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); */
@@ -4558,28 +3659,16 @@ static void scsi_reset_detect(struct Ada
 		acb->acb_flag = 0;
 		waiting_process_next(acb);
 	}
-
-	return;
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *		srb_done
- ********************************************************************
- */
-static
-void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
-		   struct ScsiReqBlk *srb)
+static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb)
 {
-	Scsi_Cmnd *cmd;
+	Scsi_Cmnd *cmd = srb->cmd;
+	dprintkdbg(DBG_1, "request_sense: (pid#%li) <%02i-%i>\n",
+		cmd->pid, cmd->device->id, cmd->device->lun);
 
-	cmd = srb->cmd;
-	dprintkdbg(DBG_KG,
-	       "request_sense for pid %li, target %02i-%i\n",
-	       cmd->pid, cmd->device->id, cmd->device->lun);
-	TRACEPRINTF("RqSn*");
 	srb->flag |= AUTO_REQSENSE;
 	srb->adapter_status = 0;
 	srb->target_status = 0;
@@ -4600,27 +3689,22 @@ void request_sense(struct AdapterCtlBlk 
 	srb->segment_x[0].address =
 	    pci_map_single(acb->dev, cmd->sense_buffer,
 			   sizeof(cmd->sense_buffer), PCI_DMA_FROMDEVICE);
-	dprintkdbg(DBG_SGPARANOIA, "Map sense buffer at %p (%05x) to %08x\n",
-	       cmd->sense_buffer, sizeof(cmd->sense_buffer),
-	       srb->segment_x[0].address);
+	dprintkdbg(DBG_SG, "request_sense: map buffer %p->%08x(%05x)\n",
+	       cmd->sense_buffer, srb->segment_x[0].address,
+	       sizeof(cmd->sense_buffer));
 	srb->sg_count = 1;
 	srb->sg_index = 0;
 
 	if (start_scsi(acb, dcb, srb)) {	/* Should only happen, if sb. else grabs the bus */
 		dprintkl(KERN_DEBUG,
-		       "Request Sense failed for pid %li (%02i-%i)!\n",
-		       srb->cmd->pid, dcb->target_id, dcb->target_lun);
-		TRACEPRINTF("?*");
+			"request_sense: (pid#%li) failed <%02i-%i>\n",
+			srb->cmd->pid, dcb->target_id, dcb->target_lun);
 		srb_going_to_waiting_move(dcb, srb);
 		waiting_set_timer(acb, HZ / 100);
 	}
-	TRACEPRINTF(".*");
 }
 
 
-
-
-
 /**
  * device_alloc - Allocate a new device instance. This create the
  * devices instance and sets up all the data items. The adapter
@@ -4634,18 +3718,17 @@ void request_sense(struct AdapterCtlBlk 
  *
  * Return the new device if succesfull or NULL on failure.
  **/
-static
-struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb, u8 target, u8 lun)
+static struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb,
+		u8 target, u8 lun)
 {
 	struct NvRamType *eeprom = &acb->eeprom;
 	u8 period_index = eeprom->target[target].period & 0x07;
 	struct DeviceCtlBlk *dcb;
 
-	dcb = dc395x_kmalloc(sizeof(struct DeviceCtlBlk), GFP_ATOMIC);
-	dprintkdbg(DBG_0, "device_alloc: device %p\n", dcb);
-	if (!dcb) {
+	dcb = kmalloc(sizeof(struct DeviceCtlBlk), GFP_ATOMIC);
+	dprintkdbg(DBG_0, "device_alloc: <%02i-%i>\n", target, lun);
+	if (!dcb)
 		return NULL;
-	}
 	dcb->acb = NULL;
 	INIT_LIST_HEAD(&dcb->srb_going_list);
 	INIT_LIST_HEAD(&dcb->srb_waiting_list);
@@ -4684,10 +3767,10 @@ struct DeviceCtlBlk *device_alloc(struct
 		list_for_each_entry(p, &acb->dcb_list, list)
 			if (p->target_id == dcb->target_id)
 				break;
-		dprintkdbg(DBG_KG, 
-		       "Copy settings from %02i-%02i to %02i-%02i\n",
-		       p->target_id, p->target_lun,
-		       dcb->target_id, dcb->target_lun);
+		dprintkdbg(DBG_1, 
+		       "device_alloc: <%02i-%i> copy from <%02i-%i>\n",
+		       dcb->target_id, dcb->target_lun,
+		       p->target_id, p->target_lun);
 		dcb->sync_mode = p->sync_mode;
 		dcb->sync_period = p->sync_period;
 		dcb->min_nego_period = p->min_nego_period;
@@ -4704,8 +3787,8 @@ struct DeviceCtlBlk *device_alloc(struct
  * @acb: The adapter device to be updated
  * @dcb: A newly created and intialised device instance to add.
  **/
-static
-void adapter_add_device(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb)
+static void adapter_add_device(struct AdapterCtlBlk *acb,
+		struct DeviceCtlBlk *dcb)
 {
 	/* backpointer to adapter */
 	dcb->acb = acb;
@@ -4732,13 +3815,13 @@ void adapter_add_device(struct AdapterCt
  * @acb: The adapter device to be updated
  * @dcb: A device that has previously been added to the adapter.
  **/
-static
-void adapter_remove_device(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb)
+static void adapter_remove_device(struct AdapterCtlBlk *acb,
+		struct DeviceCtlBlk *dcb)
 {
 	struct DeviceCtlBlk *i;
 	struct DeviceCtlBlk *tmp;
-	dprintkdbg(DBG_0, "adapter_remove_device: Remove device (ID %i, LUN %i): %p\n",
-		   dcb->target_id, dcb->target_lun, dcb);
+	dprintkdbg(DBG_0, "adapter_remove_device: <%02i-%i>\n",
+		dcb->target_id, dcb->target_lun);
 
 	/* fix up any pointers to this device that we have in the adapter */
 	if (acb->active_dcb == dcb)
@@ -4767,17 +3850,18 @@ void adapter_remove_device(struct Adapte
  * @acb: The adapter device to be updated
  * @dcb: A device that has previously been added to the adapter.
  */
-static
-void adapter_remove_and_free_device(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb)
+static void adapter_remove_and_free_device(struct AdapterCtlBlk *acb,
+		struct DeviceCtlBlk *dcb)
 {
 	if (list_size(&dcb->srb_going_list) > 1) {
-		dprintkdbg(DBG_DCB, "adapter_remove_and_free_device: "
-		           "Won't remove because of %i active requests\n",
+		dprintkdbg(DBG_1, "adapter_remove_and_free_device: <%02i-%i> "
+		           "Won't remove because of %i active requests.\n",
+			   dcb->target_id, dcb->target_lun,
 			   list_size(&dcb->srb_going_list));
 		return;
 	}
 	adapter_remove_device(acb, dcb);
-	dc395x_kfree(dcb);
+	kfree(dcb);
 }
 
 
@@ -4787,12 +3871,11 @@ void adapter_remove_and_free_device(stru
  *
  * @acb: The adapter from which all devices should be removed.
  **/
-static
-void adapter_remove_and_free_all_devices(struct AdapterCtlBlk* acb)
+static void adapter_remove_and_free_all_devices(struct AdapterCtlBlk* acb)
 {
 	struct DeviceCtlBlk *dcb;
 	struct DeviceCtlBlk *tmp;
-	dprintkdbg(DBG_DCB, "adapter_remove_and_free_all_devices: Free all devices (%i devices)\n",
+	dprintkdbg(DBG_1, "adapter_remove_and_free_all_devices: num=%i\n",
 		   list_size(&acb->dcb_list));
 
 	list_for_each_entry_safe(dcb, tmp, &acb->dcb_list, list)
@@ -4807,8 +3890,7 @@ void adapter_remove_and_free_all_devices
  *
  * @scsi_device: The new scsi device that we need to handle.
  **/
-static
-int dc395x_slave_alloc(struct scsi_device *scsi_device)
+static int dc395x_slave_alloc(struct scsi_device *scsi_device)
 {
 	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)scsi_device->host->hostdata;
 	struct DeviceCtlBlk *dcb;
@@ -4828,8 +3910,7 @@ int dc395x_slave_alloc(struct scsi_devic
  *
  * @scsi_device: The new scsi device that we need to handle.
  **/
-static
-void dc395x_slave_destroy(struct scsi_device *scsi_device)
+static void dc395x_slave_destroy(struct scsi_device *scsi_device)
 {
 	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)scsi_device->host->hostdata;
 	struct DeviceCtlBlk *dcb = find_dcb(acb, scsi_device->id, scsi_device->lun);
@@ -4847,14 +3928,12 @@ void dc395x_slave_destroy(struct scsi_de
  *
  * @io_port: base I/O address
  **/
-static
-void __init trms1040_wait_30us(u16 io_port)
+static void __init trms1040_wait_30us(u16 io_port)
 {
 	/* ScsiPortStallExecution(30); wait 30 us */
 	outb(5, io_port + TRM_S1040_GEN_TIMER);
 	while (!(inb(io_port + TRM_S1040_GEN_STATUS) & GTIMEOUT))
 		/* nothing */ ;
-	return;
 }
 
 
@@ -4866,8 +3945,7 @@ void __init trms1040_wait_30us(u16 io_po
  * @cmd:	SB + op code (command) to send
  * @addr:	address to send
  **/
-static
-void __init trms1040_write_cmd(u16 io_port, u8 cmd, u8 addr)
+static void __init trms1040_write_cmd(u16 io_port, u8 cmd, u8 addr)
 {
 	int i;
 	u8 send_data;
@@ -4912,8 +3990,7 @@ void __init trms1040_write_cmd(u16 io_po
  * @addr:	offset into EEPROM
  * @byte:	bytes to write
  **/
-static
-void __init trms1040_set_data(u16 io_port, u8 addr, u8 byte)
+static void __init trms1040_set_data(u16 io_port, u8 addr, u8 byte)
 {
 	int i;
 	u8 send_data;
@@ -4967,10 +4044,9 @@ void __init trms1040_set_data(u16 io_por
  * @eeprom:	the data to write
  * @io_port:	the base io port
  **/
-static
-void __init trms1040_write_all(struct NvRamType *eeprom, u16 io_port)
+static void __init trms1040_write_all(struct NvRamType *eeprom, u16 io_port)
 {
-	u8 *b_eeprom = (u8 *) eeprom;
+	u8 *b_eeprom = (u8 *)eeprom;
 	u8 addr;
 
 	/* Enable SEEPROM */
@@ -4983,9 +4059,8 @@ void __init trms1040_write_all(struct Nv
 	trms1040_wait_30us(io_port);
 
 	/* write */
-	for (addr = 0; addr < 128; addr++, b_eeprom++) {
+	for (addr = 0; addr < 128; addr++, b_eeprom++)
 		trms1040_set_data(io_port, addr, *b_eeprom);
-	}
 
 	/* write disable */
 	trms1040_write_cmd(io_port, 0x04, 0x00);
@@ -5009,8 +4084,7 @@ void __init trms1040_write_all(struct Nv
  *
  * Returns the the byte read.
  **/
-static
-u8 __init trms1040_get_data(u16 io_port, u8 addr)
+static u8 __init trms1040_get_data(u16 io_port, u8 addr)
 {
 	int i;
 	u8 read_byte;
@@ -5048,10 +4122,9 @@ u8 __init trms1040_get_data(u16 io_port,
  * @eeprom:	where to store the data
  * @io_port:	the base io port
  **/
-static
-void __init trms1040_read_all(struct NvRamType *eeprom, u16 io_port)
+static void __init trms1040_read_all(struct NvRamType *eeprom, u16 io_port)
 {
-	u8 *b_eeprom = (u8 *) eeprom;
+	u8 *b_eeprom = (u8 *)eeprom;
 	u8 addr;
 
 	/* Enable SEEPROM */
@@ -5059,9 +4132,8 @@ void __init trms1040_read_all(struct NvR
 	     io_port + TRM_S1040_GEN_CONTROL);
 
 	/* read details */
-	for (addr = 0; addr < 128; addr++, b_eeprom++) {
+	for (addr = 0; addr < 128; addr++, b_eeprom++)
 		*b_eeprom = trms1040_get_data(io_port, addr);
-	}
 
 	/* Disable SEEPROM */
 	outb((inb(io_port + TRM_S1040_GEN_CONTROL) & ~EN_EEPROM),
@@ -5080,10 +4152,9 @@ void __init trms1040_read_all(struct NvR
  * @eeprom:	caller allocated strcuture to read the eeprom data into
  * @io_port:	io port to read from
  **/
-static
-void __init check_eeprom(struct NvRamType *eeprom, u16 io_port)
+static void __init check_eeprom(struct NvRamType *eeprom, u16 io_port)
 {
-	u16 *w_eeprom = (u16 *) eeprom;
+	u16 *w_eeprom = (u16 *)eeprom;
 	u16 w_addr;
 	u16 cksum;
 	u32 d_addr;
@@ -5092,7 +4163,7 @@ void __init check_eeprom(struct NvRamTyp
 	trms1040_read_all(eeprom, io_port);	/* read eeprom */
 
 	cksum = 0;
-	for (w_addr = 0, w_eeprom = (u16 *) eeprom; w_addr < 64;
+	for (w_addr = 0, w_eeprom = (u16 *)eeprom; w_addr < 64;
 	     w_addr++, w_eeprom++)
 		cksum += *w_eeprom;
 	if (cksum != 0x1234) {
@@ -5101,21 +4172,21 @@ void __init check_eeprom(struct NvRamTyp
 		 * Load a set of defaults into the eeprom buffer
 		 */
 		dprintkl(KERN_WARNING,
-		       "EEProm checksum error: using default values and options.\n");
-		eeprom->sub_vendor_id[0] = (u8) PCI_VENDOR_ID_TEKRAM;
-		eeprom->sub_vendor_id[1] = (u8) (PCI_VENDOR_ID_TEKRAM >> 8);
-		eeprom->sub_sys_id[0] = (u8) PCI_DEVICE_ID_TEKRAM_TRMS1040;
+			"EEProm checksum error: using default values and options.\n");
+		eeprom->sub_vendor_id[0] = (u8)PCI_VENDOR_ID_TEKRAM;
+		eeprom->sub_vendor_id[1] = (u8)(PCI_VENDOR_ID_TEKRAM >> 8);
+		eeprom->sub_sys_id[0] = (u8)PCI_DEVICE_ID_TEKRAM_TRMS1040;
 		eeprom->sub_sys_id[1] =
-		    (u8) (PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8);
+		    (u8)(PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8);
 		eeprom->sub_class = 0x00;
-		eeprom->vendor_id[0] = (u8) PCI_VENDOR_ID_TEKRAM;
-		eeprom->vendor_id[1] = (u8) (PCI_VENDOR_ID_TEKRAM >> 8);
-		eeprom->device_id[0] = (u8) PCI_DEVICE_ID_TEKRAM_TRMS1040;
+		eeprom->vendor_id[0] = (u8)PCI_VENDOR_ID_TEKRAM;
+		eeprom->vendor_id[1] = (u8)(PCI_VENDOR_ID_TEKRAM >> 8);
+		eeprom->device_id[0] = (u8)PCI_DEVICE_ID_TEKRAM_TRMS1040;
 		eeprom->device_id[1] =
-		    (u8) (PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8);
+		    (u8)(PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8);
 		eeprom->reserved = 0x00;
 
-		for (d_addr = 0, d_eeprom = (u32 *) eeprom->target;
+		for (d_addr = 0, d_eeprom = (u32 *)eeprom->target;
 		     d_addr < 16; d_addr++, d_eeprom++)
 			*d_eeprom = 0x00000077;	/* cfg3,cfg2,period,cfg0 */
 
@@ -5130,7 +4201,7 @@ void __init check_eeprom(struct NvRamTyp
 		eeprom_override(eeprom);
 
 		eeprom->cksum = 0x00;
-		for (w_addr = 0, cksum = 0, w_eeprom = (u16 *) eeprom;
+		for (w_addr = 0, cksum = 0, w_eeprom = (u16 *)eeprom;
 		     w_addr < 63; w_addr++, w_eeprom++)
 			cksum += *w_eeprom;
 
@@ -5145,113 +4216,47 @@ void __init check_eeprom(struct NvRamTyp
 }
 
 
-
-
 /**
  * print_eeprom_settings - output the eeprom settings
  * to the kernel log so people can see what they were.
  *
  * @eeprom: The eeprom data strucutre to show details for.
  **/
-static
-void __init print_eeprom_settings(struct NvRamType *eeprom)
+static void __init print_eeprom_settings(struct NvRamType *eeprom)
 {
 	dprintkl(KERN_INFO, "Used settings: AdapterID=%02i, Speed=%i(%02i.%01iMHz), dev_mode=0x%02x\n",
-	       eeprom->scsi_id,
-	       eeprom->target[0].period,
-	       clock_speed[eeprom->target[0].period] / 10,
-	       clock_speed[eeprom->target[0].period] % 10,
-	       eeprom->target[0].cfg0);
+		eeprom->scsi_id,
+		eeprom->target[0].period,
+		clock_speed[eeprom->target[0].period] / 10,
+		clock_speed[eeprom->target[0].period] % 10,
+		eeprom->target[0].cfg0);
 	dprintkl(KERN_INFO, "               AdaptMode=0x%02x, Tags=%i(%02i), DelayReset=%is\n",
-	       eeprom->channel_cfg,
-	       eeprom->max_tag,
-	       1 << eeprom->max_tag,
-	       eeprom->delay_time);
-}
-
-
-
-#if debug_enabled(DBG_TRACE|DBG_TRACEALL)
-/*
- * Memory for trace buffers
- */
-static
-void free_tracebufs(struct AdapterCtlBlk *acb)
-{
-	int i;
-	const unsigned bufs_per_page = PAGE_SIZE / DEBUGTRACEBUFSZ;
-
-	for (i = 0; i < srb_idx; i += bufs_per_page)
-		if (acb->srb_array[i].debugtrace)
-			dc395x_kfree(acb->srb_array[i].debugtrace);
+		eeprom->channel_cfg, eeprom->max_tag,
+		1 << eeprom->max_tag, eeprom->delay_time);
 }
 
 
-static
-int alloc_tracebufs(struct AdapterCtlBlk *acb)
-{
-	const unsigned mem_needed =
-	    (DC395x_MAX_SRB_CNT + 1) * DEBUGTRACEBUFSZ;
-	int pages = (mem_needed + (PAGE_SIZE - 1)) / PAGE_SIZE;
-	const unsigned bufs_per_page = PAGE_SIZE / DEBUGTRACEBUFSZ;
-	int srb_idx = 0;
-	unsigned i = 0;
-	unsigned char *ptr;
-
-	for (i = 0; i < DC395x_MAX_SRB_CNT; i++)
-		acb->srb_array[i].debugtrace = NULL;
-
-	while (pages--) {
-		ptr = dc395x_kmalloc(PAGE_SIZE, GFP_KERNEL);
-		if (!ptr) {
-			free_tracebufs(acb);
-			return 1;
-		}
-		/*dprintkl(KERN_DEBUG, "Alloc %li bytes at %p for tracebuf %i\n", */
-		/*      PAGE_SIZE, ptr, srb_idx); */
-		i = 0;
-		while (i < bufs_per_page && srb_idx < DC395x_MAX_SRB_CNT)
-			acb->srb_array[srb_idx++].debugtrace =
-			    ptr + (i++ * DEBUGTRACEBUFSZ);
-	}
-	if (i < bufs_per_page) {
-		acb->srb.debugtrace = ptr + (i * DEBUGTRACEBUFSZ);
-		acb->srb.debugtrace[0] = 0;
-	} else
-		dprintkl(KERN_DEBUG, "No space for tmsrb tracebuf reserved?!\n");
-	return 0;
-}
-#else
-static void free_tracebufs(struct AdapterCtlBlk *acb) {}
-static int alloc_tracebufs(struct AdapterCtlBlk *acb) { return 0; }
-#endif
-
 /* Free SG tables */
-static
-void adapter_sg_tables_free(struct AdapterCtlBlk *acb)
+static void adapter_sg_tables_free(struct AdapterCtlBlk *acb)
 {
 	int i;
-	const unsigned srbs_per_page = PAGE_SIZE/(DC395x_MAX_SG_LISTENTRY
-						  *sizeof(struct SGentry));
+	const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN;
 
 	for (i = 0; i < DC395x_MAX_SRB_CNT; i += srbs_per_page)
 		if (acb->srb_array[i].segment_x)
-			dc395x_kfree(acb->srb_array[i].segment_x);
+			kfree(acb->srb_array[i].segment_x);
 }
 
 
 /*
  * Allocate SG tables; as we have to pci_map them, an SG list (struct SGentry*)
  * should never cross a page boundary */
-static
-int __init adapter_sg_tables_alloc(struct AdapterCtlBlk *acb)
+static int __init adapter_sg_tables_alloc(struct AdapterCtlBlk *acb)
 {
 	const unsigned mem_needed = (DC395x_MAX_SRB_CNT+1)
-	                            *DC395x_MAX_SG_LISTENTRY
-	                            *sizeof(struct SGentry);
+	                            *SEGMENTX_LEN;
 	int pages = (mem_needed+(PAGE_SIZE-1))/PAGE_SIZE;
-	const unsigned srbs_per_page = PAGE_SIZE/(DC395x_MAX_SG_LISTENTRY
-	                                          *sizeof(struct SGentry));
+	const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN;
 	int srb_idx = 0;
 	unsigned i = 0;
 	struct SGentry *ptr;
@@ -5261,13 +4266,13 @@ int __init adapter_sg_tables_alloc(struc
 
 	dprintkdbg(DBG_1, "Allocate %i pages for SG tables\n", pages);
 	while (pages--) {
-		ptr = (struct SGentry *)dc395x_kmalloc(PAGE_SIZE, GFP_KERNEL);
+		ptr = (struct SGentry *)kmalloc(PAGE_SIZE, GFP_KERNEL);
 		if (!ptr) {
 			adapter_sg_tables_free(acb);
 			return 1;
 		}
 		dprintkdbg(DBG_1, "Allocate %li bytes at %p for SG segments %i\n",
-				  PAGE_SIZE, ptr, srb_idx);
+			PAGE_SIZE, ptr, srb_idx);
 		i = 0;
 		while (i < srbs_per_page && srb_idx < DC395x_MAX_SRB_CNT)
 			acb->srb_array[srb_idx++].segment_x =
@@ -5292,14 +4297,13 @@ int __init adapter_sg_tables_alloc(struc
  *
  * @acb: The adapter to print the information for.
  **/
-static
-void __init adapter_print_config(struct AdapterCtlBlk *acb)
+static void __init adapter_print_config(struct AdapterCtlBlk *acb)
 {
 	u8 bval;
 
 	bval = DC395x_read8(acb, TRM_S1040_GEN_STATUS);
-	dprintkl(KERN_INFO, "%s Connectors: ",
-	       ((bval & WIDESCSI) ? "(Wide)" : ""));
+	dprintkl(KERN_INFO, "%sConnectors: ",
+		((bval & WIDESCSI) ? "(Wide) " : ""));
 	if (!(bval & CON5068))
 		printk("ext%s ", !(bval & EXT68HIGH) ? "68" : "50");
 	if (!(bval & CON68))
@@ -5337,8 +4341,7 @@ void __init adapter_print_config(struct 
  *
  * @acb: The adapter to initialize.
  **/
-static
-void __init adapter_init_params(struct AdapterCtlBlk *acb)
+static void __init adapter_init_params(struct AdapterCtlBlk *acb)
 {
 	struct NvRamType *eeprom = &acb->eeprom;
 	int i;
@@ -5400,8 +4403,7 @@ void __init adapter_init_params(struct A
  *
  * @host: The scsi host instance to fill in the values for.
  **/
-static
-void __init adapter_init_scsi_host(struct Scsi_Host *host)
+static void __init adapter_init_scsi_host(struct Scsi_Host *host)
 {
         struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata;
 	struct NvRamType *eeprom = &acb->eeprom;
@@ -5495,8 +4497,8 @@ void __init adapter_init_chip(struct Ada
  * Returns 0 if the initialization succeeds, any other value on
  * failure.
  **/
-static
-int __init adapter_init(struct AdapterCtlBlk *acb, u32 io_port, u32 io_port_len, u8 irq)
+static int __init adapter_init(struct AdapterCtlBlk *acb, u32 io_port,
+		u32 io_port_len, u8 irq)
 {
 	if (!request_region(io_port, io_port_len, DC395X_NAME)) {
 		dprintkl(KERN_ERR, "Failed to reserve IO region 0x%x\n", io_port);
@@ -5528,19 +4530,15 @@ int __init adapter_init(struct AdapterCt
 		dprintkl(KERN_DEBUG, "Memory allocation for SG tables failed\n");
 		goto failed;
 	}
-	if (alloc_tracebufs(acb)) {
-		dprintkl(KERN_DEBUG, "Memory allocation for trace buffers failed\n");
-		goto failed;
-	}
 	adapter_init_scsi_host(acb->scsi_host);
 	adapter_init_chip(acb);
 	set_basic_config(acb);
 
-	dprintkdbg(DBG_0, "adapter_init: acb=%p, pdcb_map=%p "
-	                  "psrb_array=%p ACB size=%04x, DCB size=%04x "
-	                  "SRB size=%04x\n",
-		   acb, acb->dcb_map, acb->srb_array, sizeof(struct AdapterCtlBlk),
-		   sizeof(struct DeviceCtlBlk), sizeof(struct ScsiReqBlk));
+	dprintkdbg(DBG_0,
+		"adapter_init: acb=%p, pdcb_map=%p psrb_array=%p "
+		"size{acb=0x%04x dcb=0x%04x srb=0x%04x}\n",
+		acb, acb->dcb_map, acb->srb_array, sizeof(struct AdapterCtlBlk),
+		sizeof(struct DeviceCtlBlk), sizeof(struct ScsiReqBlk));
 	return 0;
 
 failed:
@@ -5549,7 +4547,6 @@ failed:
 	if (acb->io_port_base)
 		release_region(acb->io_port_base, acb->io_port_len);
 	adapter_sg_tables_free(acb);
-	free_tracebufs(acb);
 
 	return 1;
 }
@@ -5562,8 +4559,7 @@ failed:
  *
  * @acb: The adapter which we are to shutdown.
  **/
-static
-void adapter_uninit_chip(struct AdapterCtlBlk *acb)
+static void adapter_uninit_chip(struct AdapterCtlBlk *acb)
 {
 	/* disable interrupts */
 	DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0);
@@ -5586,8 +4582,7 @@ void adapter_uninit_chip(struct AdapterC
  *
  * @acb: The adapter which we are to un-initialize.
  **/
-static
-void adapter_uninit(struct AdapterCtlBlk *acb)
+static void adapter_uninit(struct AdapterCtlBlk *acb)
 {
 	unsigned long flags;
 	DC395x_LOCK_IO(acb->scsi_host, flags);
@@ -5608,31 +4603,9 @@ void adapter_uninit(struct AdapterCtlBlk
 		release_region(acb->io_port_base, acb->io_port_len);
 
 	adapter_sg_tables_free(acb);
-	free_tracebufs(acb);
 }
 
 
-/*
- ******************************************************************
- * Function: dc395x_proc_info(char* buffer, char **start,
- *			 off_t offset, int length, int hostno, int inout)
- *  Purpose: return SCSI Adapter/Device Info
- *    Input:
- *          buffer: Pointer to a buffer where to write info
- *		 start :
- *		 offset:
- *		 hostno: Host adapter index
- *		 inout : Read (=0) or set(!=0) info
- *   Output:
- *          buffer: contains info length 
- *		         
- *    return value: length of info in buffer
- *
- ******************************************************************
- */
-
-/* KG: dc395x_proc_info taken from driver aha152x.c */
-
 #undef SPRINTF
 #define SPRINTF(args...) pos += sprintf(pos, args)
 
@@ -5641,9 +4614,8 @@ void adapter_uninit(struct AdapterCtlBlk
  if (YN) SPRINTF(" Yes ");\
  else SPRINTF(" No  ")
 
-static
-int dc395x_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length,
-		     int inout)
+static int dc395x_proc_info(struct Scsi_Host *host, char *buffer,
+		char **start, off_t offset, int length, int inout)
 {
 	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata;
 	int spd, spd1;
@@ -5741,16 +4713,12 @@ int dc395x_proc_info(struct Scsi_Host *h
 				dcb->target_id, dcb->target_lun,
 				list_size(&dcb->srb_going_list));
 		list_for_each_entry(srb, &dcb->srb_going_list, list)
-#if debug_enabled(DBG_TRACE|DBG_TRACEALL)
-			SPRINTF("\n  %s", srb->debugtrace);
-#else
 			SPRINTF(" %li", srb->cmd->pid);
-#endif
 		if (!list_empty(&dcb->srb_waiting_list) || !list_empty(&dcb->srb_going_list))
 			SPRINTF("\n");
 	}
 
-	if (debug_enabled(DBG_DCB)) {
+	if (debug_enabled(DBG_1)) {
 		SPRINTF("DCB list for ACB %p:\n", acb);
 		list_for_each_entry(dcb, &acb->dcb_list, list) {
 			SPRINTF("%p -> ", dcb);
@@ -5770,11 +4738,6 @@ int dc395x_proc_info(struct Scsi_Host *h
 }
 
 
-
-
-/*
- * SCSI host template
- */
 static Scsi_Host_Template dc395x_driver_template = {
 	.module                 = THIS_MODULE,
 	.proc_name              = DC395X_NAME,
@@ -5799,8 +4762,7 @@ static Scsi_Host_Template dc395x_driver_
  * banner_display - Display banner on first instance of driver
  * initialized.
  **/
-static
-void banner_display(void)
+static void banner_display(void)
 {
 	static int banner_done = 0;
 	if (!banner_done)
@@ -5824,9 +4786,8 @@ void banner_display(void)
  *
  * Returns 0 on success, or an error code (-ve) on failure.
  **/
-static
-int __devinit dc395x_init_one(struct pci_dev *dev,
-			      const struct pci_device_id *id)
+static int __devinit dc395x_init_one(struct pci_dev *dev,
+		const struct pci_device_id *id)
 {
 	struct Scsi_Host *scsi_host;
 	struct AdapterCtlBlk *acb;
@@ -5859,7 +4820,7 @@ int __devinit dc395x_init_one(struct pci
 
 	/* initialise the adapter and everything we need */
  	if (adapter_init(acb, io_port_base, io_port_len, irq)) {
-		dprintkl(KERN_INFO, "DC395x_initAdapter initial ERROR\n");
+		dprintkl(KERN_INFO, "adapter init failed\n");
 		scsi_host_put(scsi_host);
 		return -ENODEV;
 	}
@@ -5870,7 +4831,7 @@ int __devinit dc395x_init_one(struct pci
 	if (scsi_add_host(scsi_host, &dev->dev)) {
 		dprintkl(KERN_ERR, "scsi_add_host failed\n");
 		adapter_uninit(acb);
-                scsi_host_put(scsi_host);
+		scsi_host_put(scsi_host);
 		return -ENODEV;
 	}
 	pci_set_drvdata(dev, scsi_host);
@@ -5891,7 +4852,7 @@ static void __devexit dc395x_remove_one(
 	struct Scsi_Host *scsi_host = pci_get_drvdata(dev);
 	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)(scsi_host->hostdata);
 
-	dprintkdbg(DBG_0, "Removing instance\n");
+	dprintkdbg(DBG_0, "dc395x_remove_one: acb=%p\n", acb);
 
 	scsi_remove_host(scsi_host);
 	adapter_uninit(acb);
@@ -5900,10 +4861,6 @@ static void __devexit dc395x_remove_one(
 }
 
 
-/*
- * Table which identifies the PCI devices which
- * are handled by this device driver.
- */
 static struct pci_device_id dc395x_pci_table[] = {
 	{
 		.vendor		= PCI_VENDOR_ID_TEKRAM,
@@ -5916,10 +4873,6 @@ static struct pci_device_id dc395x_pci_t
 MODULE_DEVICE_TABLE(pci, dc395x_pci_table);
 
 
-/*
- * PCI driver operations.
- * Tells the PCI sub system what can be done with the card.
- */
 static struct pci_driver dc395x_driver = {
 	.name           = DC395X_NAME,
 	.id_table       = dc395x_pci_table,
@@ -5933,8 +4886,7 @@ static struct pci_driver dc395x_driver =
  *
  * Used by both module and built-in driver to initialise this driver.
  **/
-static
-int __init dc395x_module_init(void)
+static int __init dc395x_module_init(void)
 {
 	return pci_module_init(&dc395x_driver);
 }
@@ -5943,8 +4895,7 @@ int __init dc395x_module_init(void)
 /**
  * dc395x_module_exit - Module cleanup function.
  **/
-static
-void __exit dc395x_module_exit(void)
+static void __exit dc395x_module_exit(void)
 {
 	pci_unregister_driver(&dc395x_driver);
 }
--- diff/drivers/scsi/dc395x.h	2003-08-26 09:00:53.000000000 +0000
+++ source/drivers/scsi/dc395x.h	2004-03-16 09:37:56.649928072 +0000
@@ -7,21 +7,11 @@
 /*	(SCSI chip set used Tekram ASIC TRM-S1040)			*/
 /*									*/
 /************************************************************************/
-
 #ifndef DC395x_H
 #define DC395x_H
 
 /************************************************************************/
 /*									*/
-/*	Name, Banner and Version					*/
-/*									*/
-/************************************************************************/
-#define DC395X_NAME			"dc395x"
-#define DC395X_BANNER			"Tekram DC395(U/UW/F), DC315(U) - ASIC TRM-S1040"
-#define DC395X_VERSION			"v2.04, 2003/05/19"
-
-/************************************************************************/
-/*									*/
 /*	Initial values							*/
 /*									*/
 /************************************************************************/
--- diff/drivers/scsi/eata.c	2003-08-20 13:16:12.000000000 +0000
+++ source/drivers/scsi/eata.c	2004-03-16 09:37:56.650927920 +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-16 09:37:56.651927768 +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-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/ide-scsi.c	2004-03-16 09:37:57.132854656 +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-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/ini9100u.c	2004-03-16 09:37:57.282831856 +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/libata-core.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/libata-core.c	2004-03-16 09:37:57.293830184 +0000
@@ -141,7 +141,7 @@ void ata_tf_load_pio(struct ata_port *ap
 	}
 
 	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
-		outb(tf->hob_feature, ioaddr->error_addr);
+		outb(tf->hob_feature, ioaddr->feature_addr);
 		outb(tf->hob_nsect, ioaddr->nsect_addr);
 		outb(tf->hob_lbal, ioaddr->lbal_addr);
 		outb(tf->hob_lbam, ioaddr->lbam_addr);
@@ -155,7 +155,7 @@ void ata_tf_load_pio(struct ata_port *ap
 	}
 
 	if (is_addr) {
-		outb(tf->feature, ioaddr->error_addr);
+		outb(tf->feature, ioaddr->feature_addr);
 		outb(tf->nsect, ioaddr->nsect_addr);
 		outb(tf->lbal, ioaddr->lbal_addr);
 		outb(tf->lbam, ioaddr->lbam_addr);
@@ -199,7 +199,7 @@ void ata_tf_load_mmio(struct ata_port *a
 	}
 
 	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
-		writeb(tf->hob_feature, (void *) ioaddr->error_addr);
+		writeb(tf->hob_feature, (void *) ioaddr->feature_addr);
 		writeb(tf->hob_nsect, (void *) ioaddr->nsect_addr);
 		writeb(tf->hob_lbal, (void *) ioaddr->lbal_addr);
 		writeb(tf->hob_lbam, (void *) ioaddr->lbam_addr);
@@ -213,7 +213,7 @@ void ata_tf_load_mmio(struct ata_port *a
 	}
 
 	if (is_addr) {
-		writeb(tf->feature, (void *) ioaddr->error_addr);
+		writeb(tf->feature, (void *) ioaddr->feature_addr);
 		writeb(tf->nsect, (void *) ioaddr->nsect_addr);
 		writeb(tf->lbal, (void *) ioaddr->lbal_addr);
 		writeb(tf->lbam, (void *) ioaddr->lbam_addr);
@@ -250,7 +250,7 @@ void ata_exec_command_pio(struct ata_por
 {
 	DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
 
-       	outb(tf->command, ap->ioaddr.cmdstat_addr);
+       	outb(tf->command, ap->ioaddr.command_addr);
 	ata_pause(ap);
 }
 
@@ -271,7 +271,7 @@ void ata_exec_command_mmio(struct ata_po
 {
 	DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
 
-       	writeb(tf->command, (void *) ap->ioaddr.cmdstat_addr);
+       	writeb(tf->command, (void *) ap->ioaddr.command_addr);
 	ata_pause(ap);
 }
 
@@ -417,7 +417,7 @@ void ata_tf_read_mmio(struct ata_port *a
  */
 u8 ata_check_status_pio(struct ata_port *ap)
 {
-	return inb(ap->ioaddr.cmdstat_addr);
+	return inb(ap->ioaddr.status_addr);
 }
 
 /**
@@ -433,7 +433,7 @@ u8 ata_check_status_pio(struct ata_port 
  */
 u8 ata_check_status_mmio(struct ata_port *ap)
 {
-       	return readb((void *) ap->ioaddr.cmdstat_addr);
+       	return readb((void *) ap->ioaddr.status_addr);
 }
 
 static const char * udma_str[] = {
@@ -1346,12 +1346,6 @@ void ata_bus_reset(struct ata_port *ap)
 
 	DPRINTK("ENTER, host %u, port %u\n", ap->id, ap->port_no);
 
-	/* set up device control */
-	if (ap->flags & ATA_FLAG_MMIO)
-		writeb(ap->ctl, ioaddr->ctl_addr);
-	else
-		outb(ap->ctl, ioaddr->ctl_addr);
-
 	/* determine if device 0/1 are present */
 	if (ap->flags & ATA_FLAG_SATA_RESET)
 		dev0 = 1;
@@ -1372,8 +1366,14 @@ void ata_bus_reset(struct ata_port *ap)
 	/* issue bus reset */
 	if (ap->flags & ATA_FLAG_SRST)
 		rc = ata_bus_softreset(ap, devmask);
-	else if ((ap->flags & ATA_FLAG_SATA_RESET) == 0)
+	else if ((ap->flags & ATA_FLAG_SATA_RESET) == 0) {
+		/* set up device control */
+		if (ap->flags & ATA_FLAG_MMIO)
+			writeb(ap->ctl, ioaddr->ctl_addr);
+		else
+			outb(ap->ctl, ioaddr->ctl_addr);
 		rc = ata_bus_edd(ap);
+	}
 
 	if (rc)
 		goto err_out;
@@ -1399,6 +1399,14 @@ void ata_bus_reset(struct ata_port *ap)
 	    (ap->device[1].class == ATA_DEV_NONE))
 		goto err_out;
 
+	if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
+		/* set up device control for ATA_FLAG_SATA_RESET */
+		if (ap->flags & ATA_FLAG_MMIO)
+			writeb(ap->ctl, ioaddr->ctl_addr);
+		else
+			outb(ap->ctl, ioaddr->ctl_addr);
+	}
+
 	DPRINTK("EXIT\n");
 	return;
 
@@ -1445,7 +1453,8 @@ static void ata_host_set_pio(struct ata_
 		if (ata_dev_present(&ap->device[i])) {
 			ap->device[i].pio_mode = (pio == 3) ?
 				XFER_PIO_3 : XFER_PIO_4;
-			ap->ops->set_piomode(ap, &ap->device[i], pio);
+			if (ap->ops->set_piomode)
+				ap->ops->set_piomode(ap, &ap->device[i], pio);
 		}
 
 	return;
@@ -1509,7 +1518,9 @@ static void ata_host_set_udma(struct ata
 	for (i = 0; i < ATA_MAX_DEVICES; i++)
 		if (ata_dev_present(&ap->device[i])) {
 			ap->device[i].udma_mode = udma_mode;
-			ap->ops->set_udmamode(ap, &ap->device[i], udma_mode);
+			if (ap->ops->set_udmamode)
+				ap->ops->set_udmamode(ap, &ap->device[i],
+						      udma_mode);
 		}
 
 	return;
@@ -2369,8 +2380,8 @@ static void ata_dma_complete(struct ata_
  *	One if interrupt was handled, zero if not (shared irq).
  */
 
-static inline unsigned int ata_host_intr (struct ata_port *ap,
-					  struct ata_queued_cmd *qc)
+inline unsigned int ata_host_intr (struct ata_port *ap,
+				   struct ata_queued_cmd *qc)
 {
 	u8 status, host_stat;
 	unsigned int handled = 0;
@@ -2728,7 +2739,7 @@ int ata_port_start (struct ata_port *ap)
 	if (!ap->prd)
 		return -ENOMEM;
 	
-	DPRINTK("prd alloc, virt %p, dma %x\n", ap->prd, ap->prd_dma);
+	DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, (unsigned long long) ap->prd_dma);
 
 	return 0;
 }
@@ -3026,12 +3037,14 @@ void ata_std_ports(struct ata_ioports *i
 {
 	ioaddr->data_addr = ioaddr->cmd_addr + ATA_REG_DATA;
 	ioaddr->error_addr = ioaddr->cmd_addr + ATA_REG_ERR;
+	ioaddr->feature_addr = ioaddr->cmd_addr + ATA_REG_FEATURE;
 	ioaddr->nsect_addr = ioaddr->cmd_addr + ATA_REG_NSECT;
 	ioaddr->lbal_addr = ioaddr->cmd_addr + ATA_REG_LBAL;
 	ioaddr->lbam_addr = ioaddr->cmd_addr + ATA_REG_LBAM;
 	ioaddr->lbah_addr = ioaddr->cmd_addr + ATA_REG_LBAH;
 	ioaddr->device_addr = ioaddr->cmd_addr + ATA_REG_DEVICE;
-	ioaddr->cmdstat_addr = ioaddr->cmd_addr + ATA_REG_CMD;
+	ioaddr->status_addr = ioaddr->cmd_addr + ATA_REG_STATUS;
+	ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD;
 }
 
 /**
@@ -3153,12 +3166,14 @@ int ata_pci_init_one (struct pci_dev *pd
 
 	if (legacy_mode) {
 		probe_ent->port[0].cmd_addr = 0x1f0;
+		probe_ent->port[0].altstatus_addr =
 		probe_ent->port[0].ctl_addr = 0x3f6;
 		probe_ent->n_ports = 1;
 		probe_ent->irq = 14;
 		ata_std_ports(&probe_ent->port[0]);
 
 		probe_ent2->port[0].cmd_addr = 0x170;
+		probe_ent2->port[0].altstatus_addr =
 		probe_ent2->port[0].ctl_addr = 0x376;
 		probe_ent2->port[0].bmdma_addr = pci_resource_start(pdev, 4)+8;
 		probe_ent2->n_ports = 1;
@@ -3173,11 +3188,13 @@ int ata_pci_init_one (struct pci_dev *pd
 	} else {
 		probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0);
 		ata_std_ports(&probe_ent->port[0]);
+		probe_ent->port[0].altstatus_addr =
 		probe_ent->port[0].ctl_addr =
 			pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
 
 		probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2);
 		ata_std_ports(&probe_ent->port[1]);
+		probe_ent->port[1].altstatus_addr =
 		probe_ent->port[1].ctl_addr =
 			pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
 		probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8;
@@ -3367,4 +3384,4 @@ EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
 EXPORT_SYMBOL_GPL(ata_scsi_error);
 EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
 EXPORT_SYMBOL_GPL(ata_scsi_release);
-
+EXPORT_SYMBOL_GPL(ata_host_intr);
--- diff/drivers/scsi/megaraid.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/scsi/megaraid.c	2004-03-16 09:37:57.314826992 +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;
 }
@@ -5118,10 +5086,6 @@ static int __init megaraid_init(void)
 	if (max_mbox_busy_wait > MBOX_BUSY_WAIT)
 		max_mbox_busy_wait = MBOX_BUSY_WAIT;
 
-	error = pci_module_init(&megaraid_pci_driver);
-	if (error) 
-		return error;
-	
 #ifdef CONFIG_PROC_FS
 	mega_proc_dir_entry = proc_mkdir("megaraid", &proc_root);
 	if (!mega_proc_dir_entry) {
@@ -5129,6 +5093,13 @@ static int __init megaraid_init(void)
 				"megaraid: failed to create megaraid root\n");
 	}
 #endif
+	error = pci_module_init(&megaraid_pci_driver);
+	if (error) {
+#ifdef CONFIG_PROC_FS
+		remove_proc_entry("megaraid", &proc_root);
+#endif
+		return error;
+	}
 
 	/*
 	 * Register the driver as a character device, for applications
--- diff/drivers/scsi/ncr53c8xx.c	2003-10-09 08:47:34.000000000 +0000
+++ source/drivers/scsi/ncr53c8xx.c	2004-03-16 09:37:57.319826232 +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-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/oktagon_esp.c	2004-03-16 09:37:57.333824104 +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/pcmcia/qlogic_stub.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/scsi/pcmcia/qlogic_stub.c	2004-03-16 09:37:57.344822432 +0000
@@ -43,9 +43,11 @@
 #include <linux/major.h>
 #include <linux/blkdev.h>
 #include <scsi/scsi_ioctl.h>
+#include <linux/interrupt.h>
 
 #include "scsi.h"
 #include "hosts.h"
+#include "../qlogicfas.h"
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -57,8 +59,10 @@
 
 extern Scsi_Host_Template qlogicfas_driver_template;
 extern void qlogicfas_preset(int port, int irq);
-extern struct Scsi_Host *__qlogicfas_detect(Scsi_Host_Template *);
 extern int qlogicfas_bus_reset(Scsi_Cmnd *);
+extern irqreturn_t do_ql_ihandl(int irq, void *dev_id, struct pt_regs *regs);
+
+static char *qlogic_name = "qlogic_cs";
 
 #ifdef PCMCIA_DEBUG
 static int pc_debug = PCMCIA_DEBUG;
@@ -100,6 +104,71 @@ static dev_link_t *dev_list = NULL;
 
 static dev_info_t dev_info = "qlogic_cs";
 
+static struct Scsi_Host *qlogic_detect(Scsi_Host_Template *host,
+				dev_link_t *link, int qbase, int qlirq)
+{
+	int qltyp;		/* type of chip */
+	int qinitid;
+	struct Scsi_Host *shost;	/* registered host structure */
+	qlogicfas_priv_t priv;
+
+	qltyp = inb(qbase + 0xe) & 0xf8;
+	qinitid = host->this_id;
+	if (qinitid < 0)
+		qinitid = 7;	/* if no ID, use 7 */
+	outb(1, qbase + 8);	/* set for PIO pseudo DMA */
+	REG0;
+	outb(0x40 | qlcfg8 | qinitid, qbase + 8);	/* (ini) bus id, disable scsi rst */
+	outb(qlcfg5, qbase + 5);	/* select timer */
+	outb(qlcfg9, qbase + 9);	/* prescaler */
+
+#if QL_RESET_AT_START
+	outb(3, qbase + 3);
+	REG1;
+	/* FIXME: timeout */
+	while (inb(qbase + 0xf) & 4)
+		cpu_relax();
+	REG0;
+#endif
+
+	host->name = qlogic_name;
+	shost = scsi_host_alloc(host, sizeof(struct qlogicfas_priv));
+	if (!shost)
+		goto err;
+	shost->io_port = qbase;
+	shost->n_io_port = 16;
+	shost->dma_channel = -1;
+	if (qlirq != -1)
+		shost->irq = qlirq;
+
+	priv = (qlogicfas_priv_t)&(shost->hostdata[0]);
+	priv->qlirq = qlirq;
+	priv->qbase = qbase;
+	priv->qinitid = qinitid;
+
+	if (request_irq(qlirq, do_ql_ihandl, 0, qlogic_name, shost))
+		goto free_scsi_host;
+
+	sprintf(priv->qinfo,
+		"Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d",
+		qltyp, qbase, qlirq, QL_TURBO_PDMA);
+
+	if (scsi_add_host(shost, NULL))
+		goto free_interrupt;
+
+	scsi_scan_host(shost);
+
+	return shost;
+
+free_interrupt:
+	free_irq(qlirq, shost);
+
+free_scsi_host:
+	scsi_host_put(shost);
+	
+err:
+	return NULL;
+}
 static dev_link_t *qlogic_attach(void)
 {
 	scsi_info_t *info;
@@ -238,18 +307,19 @@ static void qlogic_config(dev_link_t * l
 		outb(0x04, link->io.BasePort1 + 0xd);
 	}
 
-	/* A bad hack... */
-	release_region(link->io.BasePort1, link->io.NumPorts1);
+	qlogicfas_driver_template.name = qlogic_name;
+	qlogicfas_driver_template.proc_name = qlogic_name;
 
 	/* The KXL-810AN has a bigger IO port window */
 	if (link->io.NumPorts1 == 32)
-		qlogicfas_preset(link->io.BasePort1 + 16, link->irq.AssignedIRQ);
+		host = qlogic_detect(&qlogicfas_driver_template, link,
+			link->io.BasePort1 + 16, link->irq.AssignedIRQ);
 	else
-		qlogicfas_preset(link->io.BasePort1, link->irq.AssignedIRQ);
-
-	host = __qlogicfas_detect(&qlogicfas_driver_template);
+		host = qlogic_detect(&qlogicfas_driver_template, link,
+			link->io.BasePort1, link->irq.AssignedIRQ);
+	
 	if (!host) {
-		printk(KERN_INFO "qlogic_cs: no SCSI devices found\n");
+		printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name);
 		goto out;
 	}
 
@@ -257,16 +327,17 @@ static void qlogic_config(dev_link_t * l
 	link->dev = &info->node;
 	info->host = host;
 
-	scsi_add_host(host, NULL); /* XXX handle failure */
-	scsi_scan_host(host);
-
 out:
 	link->state &= ~DEV_CONFIG_PENDING;
 	return;
 
 cs_failed:
 	cs_error(link->handle, last_fn, last_ret);
-	qlogic_release(link);
+	link->dev = NULL;
+	pcmcia_release_configuration(link->handle);
+	pcmcia_release_io(link->handle, &link->io);
+	pcmcia_release_irq(link->handle, &link->irq);
+	link->state &= ~DEV_CONFIG;
 	return;
 
 }				/* qlogic_config */
@@ -282,11 +353,13 @@ static void qlogic_release(dev_link_t *l
 	scsi_remove_host(info->host);
 	link->dev = NULL;
 
+	free_irq(link->irq.AssignedIRQ, info->host);
+
 	pcmcia_release_configuration(link->handle);
 	pcmcia_release_io(link->handle, &link->io);
 	pcmcia_release_irq(link->handle, &link->irq);
 
-	scsi_unregister(info->host);
+	scsi_host_put(info->host);
 
 	link->state &= ~DEV_CONFIG;
 }
@@ -340,7 +413,7 @@ static int qlogic_event(event_t event, i
 static struct pcmcia_driver qlogic_cs_driver = {
 	.owner		= THIS_MODULE,
 	.drv		= {
-		.name	= "qlogic_cs",
+	.name		= "qlogic_cs",
 	},
 	.attach		= qlogic_attach,
 	.detach		= qlogic_detach,
@@ -360,5 +433,8 @@ static void __exit exit_qlogic_cs(void)
 		qlogic_detach(dev_list);
 }
 
+MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
+MODULE_DESCRIPTION("Driver for the PCMCIA Qlogic FAS SCSI controllers");
+MODULE_LICENSE("GPL");
 module_init(init_qlogic_cs);
 module_exit(exit_qlogic_cs);
--- diff/drivers/scsi/qlogicfas.c	2003-08-20 13:16:13.000000000 +0000
+++ source/drivers/scsi/qlogicfas.c	2004-03-16 09:37:57.353821064 +0000
@@ -27,7 +27,6 @@
    SCSI driver cleanup and audit. This driver still needs work on the
    following
    	-	Non terminating hardware waits
-   	-	Support multiple cards at a time
    	-	Some layering violations with its pcmcia stub
 
    Redistributable under terms of the GNU General Public License
@@ -39,92 +38,6 @@
    are deemed to be part of the source code.
 
 */
-/*----------------------------------------------------------------*/
-/* Configuration */
-
-/* Set the following to 2 to use normal interrupt (active high/totempole-
-   tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
-   drain */
-
-#define QL_INT_ACTIVE_HIGH 2
-
-/* Set the following to 1 to enable the use of interrupts.  Note that 0 tends
-   to be more stable, but slower (or ties up the system more) */
-
-#define QL_USE_IRQ 1
-
-/* Set the following to max out the speed of the PIO PseudoDMA transfers,
-   again, 0 tends to be slower, but more stable.  */
-
-#define QL_TURBO_PDMA 1
-
-/* This should be 1 to enable parity detection */
-
-#define QL_ENABLE_PARITY 1
-
-/* This will reset all devices when the driver is initialized (during bootup).
-   The other linux drivers don't do this, but the DOS drivers do, and after
-   using DOS or some kind of crash or lockup this will bring things back
-   without requiring a cold boot.  It does take some time to recover from a
-   reset, so it is slower, and I have seen timeouts so that devices weren't
-   recognized when this was set. */
-
-#define QL_RESET_AT_START 0
-
-/* crystal frequency in megahertz (for offset 5 and 9)
-   Please set this for your card.  Most Qlogic cards are 40 Mhz.  The
-   Control Concepts ISA (not VLB) is 24 Mhz */
-
-#define XTALFREQ	40
-
-/**********/
-/* DANGER! modify these at your own risk */
-/* SLOWCABLE can usually be reset to zero if you have a clean setup and
-   proper termination.  The rest are for synchronous transfers and other
-   advanced features if your device can transfer faster than 5Mb/sec.
-   If you are really curious, email me for a quick howto until I have
-   something official */
-/**********/
-
-/*****/
-/* config register 1 (offset 8) options */
-/* This needs to be set to 1 if your cabling is long or noisy */
-#define SLOWCABLE 1
-
-/*****/
-/* offset 0xc */
-/* This will set fast (10Mhz) synchronous timing when set to 1
-   For this to have an effect, FASTCLK must also be 1 */
-#define FASTSCSI 0
-
-/* This when set to 1 will set a faster sync transfer rate */
-#define FASTCLK 0	/*(XTALFREQ>25?1:0)*/
-
-/*****/
-/* offset 6 */
-/* This is the sync transfer divisor, XTALFREQ/X will be the maximum
-   achievable data rate (assuming the rest of the system is capable
-   and set properly) */
-#define SYNCXFRPD 5	/*(XTALFREQ/5)*/
-
-/*****/
-/* offset 7 */
-/* This is the count of how many synchronous transfers can take place
-	i.e. how many reqs can occur before an ack is given.
-	The maximum value for this is 15, the upper bits can modify
-	REQ/ACK assertion and deassertion during synchronous transfers
-	If this is 0, the bus will only transfer asynchronously */
-#define SYNCOFFST 0
-/* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles
-	of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will
-	cause the deassertion to be early by 1/2 clock.  Bits 5&4 control
-	the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */
-
-/*----------------------------------------------------------------*/
-#ifdef PCMCIA
-#undef QL_INT_ACTIVE_HIGH
-#define QL_INT_ACTIVE_HIGH 0
-#endif
 
 #include <linux/module.h>
 #include <linux/blkdev.h>		/* to get disk capacity */
@@ -144,42 +57,21 @@
 
 #include "scsi.h"
 #include "hosts.h"
+#include "qlogicfas.h"
 
 /*----------------------------------------------------------------*/
-/* driver state info, local to driver */
-static int qbase;		/* Port */
-static int qinitid;		/* initiator ID */
-static int qabort;		/* Flag to cause an abort */
-static int qlirq = -1;		/* IRQ being used */
-static char qinfo[80];		/* description */
-static Scsi_Cmnd *qlcmd;	/* current command being processed */
-
-static int qlcfg5 = (XTALFREQ << 5);	/* 15625/512 */
-static int qlcfg6 = SYNCXFRPD;
-static int qlcfg7 = SYNCOFFST;
-static int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4);
-static int qlcfg9 = ((XTALFREQ + 4) / 5);
-static int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4);
-
-int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *));
+int qlcfg5 = (XTALFREQ << 5);	/* 15625/512 */
+int qlcfg6 = SYNCXFRPD;
+int qlcfg7 = SYNCOFFST;
+int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4);
+int qlcfg9 = ((XTALFREQ + 4) / 5);
+int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4);
 
-/*----------------------------------------------------------------*/
-/* The qlogic card uses two register maps - These macros select which one */
-#define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd ))
-#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd ))
+static char qlogicfas_name[] = "qlogicfas";
 
-/* following is watchdog timeout in microseconds */
-#define WATCHDOG 5000000
+int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *));
 
 /*----------------------------------------------------------------*/
-/* the following will set the monitor border color (useful to find
-   where something crashed or gets stuck at and as a simple profiler) */
-
-#if 0
-#define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);}
-#else
-#define rtrc(i) {}
-#endif
 
 /*----------------------------------------------------------------*/
 /* local functions */
@@ -187,9 +79,10 @@ int qlogicfas_queuecommand(Scsi_Cmnd * c
 
 /* error recovery - reset everything */
 
-static void ql_zap(void)
+static void ql_zap(qlogicfas_priv_t priv)
 {
 	int x;
+	int qbase = priv->qbase;
 
 	x = inb(qbase + 0xd);
 	REG0;
@@ -203,9 +96,10 @@ static void ql_zap(void)
  *	Do a pseudo-dma tranfer
  */
  
-static int ql_pdma(int phase, char *request, int reqlen)
+static int ql_pdma(qlogicfas_priv_t priv, int phase, char *request, int reqlen)
 {
 	int j;
+	int qbase = priv->qbase;
 	j = 0;
 	if (phase & 1) {	/* in */
 #if QL_TURBO_PDMA
@@ -287,23 +181,25 @@ static int ql_pdma(int phase, char *requ
  *	Wait for interrupt flag (polled - not real hardware interrupt) 
  */
 
-static int ql_wai(void)
+static int ql_wai(qlogicfas_priv_t priv)
 {
 	int k;
+	int qbase = priv->qbase;
 	unsigned long i;
 
 	k = 0;
 	i = jiffies + WATCHDOG;
-	while (time_before(jiffies, i) && !qabort && !((k = inb(qbase + 4)) & 0xe0)) {
+	while (time_before(jiffies, i) && !priv->qabort &&
+					!((k = inb(qbase + 4)) & 0xe0)) {
 		barrier();
 		cpu_relax();
 	}
 	if (time_after_eq(jiffies, i))
 		return (DID_TIME_OUT);
-	if (qabort)
-		return (qabort == 1 ? DID_ABORT : DID_RESET);
+	if (priv->qabort)
+		return (priv->qabort == 1 ? DID_ABORT : DID_RESET);
 	if (k & 0x60)
-		ql_zap();
+		ql_zap(priv);
 	if (k & 0x20)
 		return (DID_PARITY);
 	if (k & 0x40)
@@ -318,9 +214,11 @@ static int ql_wai(void)
 
 static void ql_icmd(Scsi_Cmnd * cmd)
 {
+	qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]);
+	int 	qbase = priv->qbase;
 	unsigned int i;
 
-	qabort = 0;
+	priv->qabort = 0;
 
 	REG0;
 	/* clearing of interrupts and the fifo is needed */
@@ -341,7 +239,7 @@ static void ql_icmd(Scsi_Cmnd * cmd)
 	/* configurables */
 	outb(qlcfgc, qbase + 0xc);
 	/* config: no reset interrupt, (initiator) bus id */
-	outb(0x40 | qlcfg8 | qinitid, qbase + 8);
+	outb(0x40 | qlcfg8 | priv->qinitid, qbase + 8);
 	outb(qlcfg7, qbase + 7);
 	outb(qlcfg6, qbase + 6);
 	 /**/ outb(qlcfg5, qbase + 5);	/* select timer */
@@ -352,7 +250,7 @@ static void ql_icmd(Scsi_Cmnd * cmd)
 	for (i = 0; i < cmd->cmd_len; i++)
 		outb(cmd->cmnd[i], qbase + 2);
 
-	qlcmd = cmd;
+	priv->qlcmd = cmd;
 	outb(0x41, qbase + 3);	/* select and send command */
 }
 
@@ -372,6 +270,8 @@ static unsigned int ql_pcmd(Scsi_Cmnd * 
 	struct scatterlist *sglist;	/* scatter-gather list pointer */
 	unsigned int sgcount;	/* sg counter */
 	char *buf;
+	qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]);
+	int qbase = priv->qbase;
 
 	rtrc(1)
 	j = inb(qbase + 6);
@@ -382,7 +282,7 @@ static unsigned int ql_pcmd(Scsi_Cmnd * 
 	i |= inb(qbase + 5);	/* the 0x10 bit can be set after the 0x08 */
 	if (i != 0x18) {
 		printk(KERN_ERR "Ql:Bad Interrupt status:%02x\n", i);
-		ql_zap();
+		ql_zap(priv);
 		return (DID_BAD_INTR << 16);
 	}
 	j &= 7;			/* j = inb( qbase + 7 ) >> 5; */
@@ -395,7 +295,7 @@ static unsigned int ql_pcmd(Scsi_Cmnd * 
 	if (j != 3 && j != 4) {
 		printk(KERN_ERR "Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n",
 		     j, i, inb(qbase + 7) & 0x1f);
-		ql_zap();
+		ql_zap(priv);
 		return (DID_ERROR << 16);
 	}
 	result = DID_OK;
@@ -413,18 +313,19 @@ static unsigned int ql_pcmd(Scsi_Cmnd * 
 		/* PIO pseudo DMA to buffer or sglist */
 		REG1;
 		if (!cmd->use_sg)
-			ql_pdma(phase, cmd->request_buffer,
+			ql_pdma(priv, phase, cmd->request_buffer,
 				cmd->request_bufflen);
 		else {
 			sgcount = cmd->use_sg;
 			sglist = cmd->request_buffer;
 			while (sgcount--) {
-				if (qabort) {
+				if (priv->qabort) {
 					REG0;
-					return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
+					return ((priv->qabort == 1 ?
+						DID_ABORT : DID_RESET) << 16);
 				}
 				buf = page_address(sglist->page) + sglist->offset;
-				if (ql_pdma(phase, buf, sglist->length))
+				if (ql_pdma(priv, phase, buf, sglist->length))
 					break;
 				sglist++;
 			}
@@ -435,7 +336,7 @@ static unsigned int ql_pcmd(Scsi_Cmnd * 
 		 *	Wait for irq (split into second state of irq handler
 		 *	if this can take time) 
 		 */
-		if ((k = ql_wai()))
+		if ((k = ql_wai(priv)))
 			return (k << 16);
 		k = inb(qbase + 5);	/* should be 0x10, bus service */
 	}
@@ -446,11 +347,12 @@ static unsigned int ql_pcmd(Scsi_Cmnd * 
 	 
 	k = jiffies + WATCHDOG;
 
-	while (time_before(jiffies, k) && !qabort && !(inb(qbase + 4) & 6))
+	while (time_before(jiffies, k) && !priv->qabort &&
+						!(inb(qbase + 4) & 6))
 		cpu_relax();	/* wait for status phase */
 
 	if (time_after_eq(jiffies, k)) {
-		ql_zap();
+		ql_zap(priv);
 		return (DID_TIME_OUT << 16);
 	}
 
@@ -458,11 +360,11 @@ static unsigned int ql_pcmd(Scsi_Cmnd * 
 	while (inb(qbase + 5))
 		cpu_relax();	/* clear pending ints */
 
-	if (qabort)
-		return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
+	if (priv->qabort)
+		return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16);
 
 	outb(0x11, qbase + 3);	/* get status and message */
-	if ((k = ql_wai()))
+	if ((k = ql_wai(priv)))
 		return (k << 16);
 	i = inb(qbase + 5);	/* get chip irq stat */
 	j = inb(qbase + 7) & 0x1f;	/* and bytes rec'd */
@@ -479,7 +381,7 @@ static unsigned int ql_pcmd(Scsi_Cmnd * 
 	}
 	outb(0x12, qbase + 3);	/* done, disconnect */
 	rtrc(1)
-	if ((k = ql_wai()))
+	if ((k = ql_wai(priv)))
 		return (k << 16);
 
 	/*
@@ -487,21 +389,19 @@ static unsigned int ql_pcmd(Scsi_Cmnd * 
 	 */
 	 
 	i = inb(qbase + 5);	/* should be bus service */
-	while (!qabort && ((i & 0x20) != 0x20)) {
+	while (!priv->qabort && ((i & 0x20) != 0x20)) {
 		barrier();
 		cpu_relax();
 		i |= inb(qbase + 5);
 	}
 	rtrc(0)
 
-	if (qabort)
-		return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
+	if (priv->qabort)
+		return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16);
 		
 	return (result << 16) | (message << 8) | (status & STATUS_MASK);
 }
 
-#if QL_USE_IRQ
-
 /*
  *	Interrupt handler 
  */
@@ -509,20 +409,23 @@ static unsigned int ql_pcmd(Scsi_Cmnd * 
 static void ql_ihandl(int irq, void *dev_id, struct pt_regs *regs)
 {
 	Scsi_Cmnd *icmd;
+	struct Scsi_Host *host = (struct Scsi_Host *)dev_id;
+	qlogicfas_priv_t priv = (qlogicfas_priv_t)&(host->hostdata[0]);
+	int qbase = priv->qbase;
 	REG0;
 
 	if (!(inb(qbase + 4) & 0x80))	/* false alarm? */
 		return;
 
-	if (qlcmd == NULL) {	/* no command to process? */
+	if (priv->qlcmd == NULL) {	/* no command to process? */
 		int i;
 		i = 16;
 		while (i-- && inb(qbase + 5));	/* maybe also ql_zap() */
 		return;
 	}
-	icmd = qlcmd;
+	icmd = priv->qlcmd;
 	icmd->result = ql_pcmd(icmd);
-	qlcmd = NULL;
+	priv->qlcmd = NULL;
 	/*
 	 *	If result is CHECK CONDITION done calls qcommand to request 
 	 *	sense 
@@ -530,7 +433,7 @@ static void ql_ihandl(int irq, void *dev
 	(icmd->scsi_done) (icmd);
 }
 
-static irqreturn_t do_ql_ihandl(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t do_ql_ihandl(int irq, void *dev_id, struct pt_regs *regs)
 {
 	unsigned long flags;
 	struct Scsi_Host *host = dev_id;
@@ -541,17 +444,14 @@ static irqreturn_t do_ql_ihandl(int irq,
 	return IRQ_HANDLED;
 }
 
-#endif
-
-#if QL_USE_IRQ
-
 /*
  *	Queued command
  */
 
 int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
 {
-	if (cmd->device->id == qinitid) {
+	qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]);
+	if (cmd->device->id == priv->qinitid) {
 		cmd->result = DID_BAD_TARGET << 16;
 		done(cmd);
 		return 0;
@@ -559,44 +459,27 @@ int qlogicfas_queuecommand(Scsi_Cmnd * c
 
 	cmd->scsi_done = done;
 	/* wait for the last command's interrupt to finish */
-	while (qlcmd != NULL) {
+	while (priv->qlcmd != NULL) {
 		barrier();
 		cpu_relax();
 	}
 	ql_icmd(cmd);
 	return 0;
 }
-#else
-int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
-{
-	return 1;
-}
-#endif
-
-#ifdef PCMCIA
-
-/*
- *	Allow PCMCIA code to preset the port
- *	port should be 0 and irq to -1 respectively for autoprobing 
- */
-
-void qlogicfas_preset(int port, int irq)
-{
-	qbase = port;
-	qlirq = irq;
-}
-
-#endif
 
+#ifndef PCMCIA
 /*
  *	Look for qlogic card and init if found 
  */
  
-struct Scsi_Host *__qlogicfas_detect(Scsi_Host_Template *host)
+struct Scsi_Host *__qlogicfas_detect(Scsi_Host_Template *host, int qbase,
+								int qlirq)
 {
 	int i, j;		/* these are only used by IRQ detect */
 	int qltyp;		/* type of chip */
+	int qinitid;
 	struct Scsi_Host *hreg;	/* registered host structure */
+	qlogicfas_priv_t priv;
 
 	/*	Qlogic Cards only exist at 0x230 or 0x330 (the chip itself
 	 *	decodes the address - I check 230 first since MIDI cards are
@@ -609,7 +492,7 @@ struct Scsi_Host *__qlogicfas_detect(Scs
 
 	if (!qbase) {
 		for (qbase = 0x230; qbase < 0x430; qbase += 0x100) {
-			if (!request_region(qbase, 0x10, "qlogicfas"))
+			if (!request_region(qbase, 0x10, qlogicfas_name))
 				continue;
 			REG1;
 			if (((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7)
@@ -641,7 +524,6 @@ struct Scsi_Host *__qlogicfas_detect(Scs
 	REG0;
 #endif
 
-#if QL_USE_IRQ
 	/*
 	 *	IRQ probe - toggle pin and check request pending 
 	 */
@@ -668,49 +550,98 @@ struct Scsi_Host *__qlogicfas_detect(Scs
 	} else
 		printk(KERN_INFO "Ql: Using preset IRQ %d\n", qlirq);
 
-	if (qlirq >= 0 && !request_irq(qlirq, do_ql_ihandl, 0, "qlogicfas", NULL))
-		host->can_queue = 1;
-#endif
-	hreg = scsi_register(host, 0);	/* no host data */
+	hreg = scsi_host_alloc(host, sizeof(struct qlogicfas_priv));
 	if (!hreg)
 		goto err_release_mem;
+	priv = (qlogicfas_priv_t)&(hreg->hostdata[0]);
 	hreg->io_port = qbase;
 	hreg->n_io_port = 16;
 	hreg->dma_channel = -1;
 	if (qlirq != -1)
 		hreg->irq = qlirq;
+	priv->qbase = qbase;
+	priv->qlirq = qlirq;
+	priv->qinitid = qinitid;
+	priv->shost = hreg;
 
-	sprintf(qinfo,
+	sprintf(priv->qinfo,
 		"Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d",
 		qltyp, qbase, qlirq, QL_TURBO_PDMA);
-	host->name = qinfo;
+	host->name = qlogicfas_name;
+
+	if (request_irq(qlirq, do_ql_ihandl, 0, qlogicfas_name, hreg))
+		goto free_scsi_host;
+
+	if (scsi_add_host(hreg, NULL))
+		goto free_interrupt;
+
+	scsi_scan_host(hreg);
 
 	return hreg;
 
+free_interrupt:
+	free_irq(qlirq, hreg);
+
+free_scsi_host:
+	scsi_host_put(hreg);
+
 err_release_mem:
 	release_region(qbase, 0x10);
-	if (host->can_queue)
-		free_irq(qlirq, do_ql_ihandl);
-	return NULL;;
-
+	return NULL;
 }
 
+#define MAX_QLOGICFAS	8
+static qlogicfas_priv_t cards;
+static int iobase[MAX_QLOGICFAS];
+static int irq[MAX_QLOGICFAS] = { [0 ... MAX_QLOGICFAS-1] = -1 };
+MODULE_PARM(iobase, "1-" __MODULE_STRING(MAX_QLOGICFAS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_QLOGICFAS) "i");
+MODULE_PARM_DESC(iobase, "I/O address");
+MODULE_PARM_DESC(irq, "IRQ");
+
 int __devinit qlogicfas_detect(Scsi_Host_Template *sht)
 {
-	return (__qlogicfas_detect(sht) != NULL);
+	struct Scsi_Host	*shost;
+	qlogicfas_priv_t	priv;
+	int	i,
+		num = 0;
+
+	for (i = 0; i < MAX_QLOGICFAS; i++) {
+		shost = __qlogicfas_detect(sht, iobase[num], irq[num]);
+		if (shost == NULL) {
+			/* no more devices */
+			break;
+		}
+		priv = (qlogicfas_priv_t)&(shost->hostdata[0]);
+		priv->next = cards;
+		cards = priv;
+		num++;
+	}
+
+	return num;
 }
 
 static int qlogicfas_release(struct Scsi_Host *shost)
 {
-	if (shost->irq)
-		free_irq(shost->irq, NULL);
+	qlogicfas_priv_t priv = (qlogicfas_priv_t)&(shost->hostdata[0]);
+	int qbase = priv->qbase;
+
+	if (shost->irq) {
+		REG1;
+		outb(0, qbase + 0xb);	/* disable ints */
+	
+		free_irq(shost->irq, shost);
+	}
 	if (shost->dma_channel != 0xff)
 		free_dma(shost->dma_channel);
 	if (shost->io_port && shost->n_io_port)
 		release_region(shost->io_port, shost->n_io_port);
-	scsi_unregister(shost);
+	scsi_remove_host(shost);
+	scsi_host_put(shost);
+
 	return 0;
 }
+#endif	/* ifndef PCMCIA */
 
 /* 
  *	Return bios parameters 
@@ -742,8 +673,9 @@ int qlogicfas_biosparam(struct scsi_devi
  
 static int qlogicfas_abort(Scsi_Cmnd * cmd)
 {
-	qabort = 1;
-	ql_zap();
+	qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]);
+	priv->qabort = 1;
+	ql_zap(priv);
 	return SUCCESS;
 }
 
@@ -755,8 +687,9 @@ static int qlogicfas_abort(Scsi_Cmnd * c
 
 int qlogicfas_bus_reset(Scsi_Cmnd * cmd)
 {
-	qabort = 2;
-	ql_zap();
+	qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]);
+	priv->qabort = 2;
+	ql_zap(priv);
 	return SUCCESS;
 }
 
@@ -784,22 +717,17 @@ static int qlogicfas_device_reset(Scsi_C
 
 static const char *qlogicfas_info(struct Scsi_Host *host)
 {
-	return qinfo;
+	qlogicfas_priv_t priv = (qlogicfas_priv_t)&(host->hostdata[0]);
+	return priv->qinfo;
 }
 
-MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
-MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers");
-MODULE_LICENSE("GPL");
-
 /*
  *	The driver template is also needed for PCMCIA
  */
 Scsi_Host_Template qlogicfas_driver_template = {
 	.module			= THIS_MODULE,
-	.name			= "qlogicfas",
-	.proc_name		= "qlogicfas",
-	.detect			= qlogicfas_detect,
-	.release		= qlogicfas_release,
+	.name			= qlogicfas_name,
+	.proc_name		= qlogicfas_name,
 	.info			= qlogicfas_info,
 	.queuecommand		= qlogicfas_queuecommand,
 	.eh_abort_handler	= qlogicfas_abort,
@@ -807,7 +735,7 @@ Scsi_Host_Template qlogicfas_driver_temp
 	.eh_device_reset_handler= qlogicfas_device_reset,
 	.eh_host_reset_handler	= qlogicfas_host_reset,
 	.bios_param		= qlogicfas_biosparam,
-	.can_queue		= 0,
+	.can_queue		= 1,
 	.this_id		= -1,
 	.sg_tablesize		= SG_ALL,
 	.cmd_per_lun		= 1,
@@ -815,6 +743,28 @@ Scsi_Host_Template qlogicfas_driver_temp
 };
 
 #ifndef PCMCIA
-#define driver_template qlogicfas_driver_template
-#include "scsi_module.c"
-#endif
+static __init int qlogicfas_init(void)
+{
+	if (!qlogicfas_detect(&qlogicfas_driver_template)) {
+		/* no cards found */
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static __exit void qlogicfas_exit(void)
+{
+	qlogicfas_priv_t	priv;
+
+	for (priv = cards; priv != NULL; priv = priv->next)
+		qlogicfas_release(priv->shost);
+}
+
+MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
+MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers");
+MODULE_LICENSE("GPL");
+module_init(qlogicfas_init);
+module_exit(qlogicfas_exit);
+#endif	/* ifndef PCMCIA */
+
--- diff/drivers/scsi/sata_promise.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/sata_promise.c	2004-03-16 09:37:57.372818176 +0000
@@ -146,10 +146,6 @@ struct pdc_host_priv {
 
 static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
-static void pdc_sata_set_piomode (struct ata_port *ap, struct ata_device *adev,
-			      unsigned int pio);
-static void pdc_sata_set_udmamode (struct ata_port *ap, struct ata_device *adev,
-			      unsigned int udma);
 static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static void pdc_dma_start(struct ata_queued_cmd *qc);
 static void pdc20621_dma_start(struct ata_queued_cmd *qc);
@@ -200,8 +196,6 @@ static Scsi_Host_Template pdc_sata_sht =
 
 static struct ata_port_operations pdc_sata_ops = {
 	.port_disable		= ata_port_disable,
-	.set_piomode		= pdc_sata_set_piomode,
-	.set_udmamode		= pdc_sata_set_udmamode,
 	.tf_load		= pdc_tf_load_mmio,
 	.tf_read		= ata_tf_read_mmio,
 	.check_status		= ata_check_status_mmio,
@@ -220,8 +214,6 @@ static struct ata_port_operations pdc_sa
 
 static struct ata_port_operations pdc_20621_ops = {
 	.port_disable		= ata_port_disable,
-	.set_piomode		= pdc_sata_set_piomode,
-	.set_udmamode		= pdc_sata_set_udmamode,
 	.tf_load		= pdc_tf_load_mmio,
 	.tf_read		= ata_tf_read_mmio,
 	.check_status		= ata_check_status_mmio,
@@ -378,19 +370,6 @@ static void pdc_sata_scr_write (struct a
 	writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
 }
 
-static void pdc_sata_set_piomode (struct ata_port *ap, struct ata_device *adev,
-			      unsigned int pio)
-{
-	/* dummy */
-}
-
-
-static void pdc_sata_set_udmamode (struct ata_port *ap, struct ata_device *adev,
-			      unsigned int udma)
-{
-	/* dummy */
-}
-
 enum pdc_packet_bits {
 	PDC_PKT_READ		= (1 << 2),
 	PDC_PKT_NODATA		= (1 << 3),
@@ -1172,13 +1151,16 @@ static void pdc_sata_setup_port(struct a
 {
 	port->cmd_addr		= base;
 	port->data_addr		= base;
+	port->feature_addr	=
 	port->error_addr	= base + 0x4;
 	port->nsect_addr	= base + 0x8;
 	port->lbal_addr		= base + 0xc;
 	port->lbam_addr		= base + 0x10;
 	port->lbah_addr		= base + 0x14;
 	port->device_addr	= base + 0x18;
-	port->cmdstat_addr	= base + 0x1c;
+	port->command_addr	=
+	port->status_addr	= base + 0x1c;
+	port->altstatus_addr	=
 	port->ctl_addr		= base + 0x38;
 }
 
--- diff/drivers/scsi/sata_sil.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/sata_sil.c	2004-03-16 09:37:57.373818024 +0000
@@ -75,10 +75,6 @@ enum {
 	SIL_QUIRK_UDMA5MAX	= (1 << 1),
 };
 
-static void sil_set_piomode (struct ata_port *ap, struct ata_device *adev,
-			      unsigned int pio);
-static void sil_set_udmamode (struct ata_port *ap, struct ata_device *adev,
-			      unsigned int udma);
 static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
 static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
@@ -141,8 +137,6 @@ static Scsi_Host_Template sil_sht = {
 static struct ata_port_operations sil_ops = {
 	.port_disable		= ata_port_disable,
 	.dev_config		= sil_dev_config,
-	.set_piomode		= sil_set_piomode,
-	.set_udmamode		= sil_set_udmamode,
 	.tf_load		= ata_tf_load_mmio,
 	.tf_read		= ata_tf_read_mmio,
 	.check_status		= ata_check_status_mmio,
@@ -287,22 +281,6 @@ static void sil_dev_config(struct ata_po
 	}
 }
 
-static void sil_set_piomode (struct ata_port *ap, struct ata_device *adev,
-			      unsigned int pio)
-{
-	/* We need empty implementation, the core doesn't test for NULL
-	 * function pointer
-	 */
-}
-
-static void sil_set_udmamode (struct ata_port *ap, struct ata_device *adev,
-			      unsigned int udma)
-{
-	/* We need empty implementation, the core doesn't test for NULL
-	 * function pointer
-	 */
-}
-
 static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	static int printed_version;
@@ -360,12 +338,14 @@ static int sil_init_one (struct pci_dev 
 
 	base = (unsigned long) mmio_base;
 	probe_ent->port[0].cmd_addr = base + SIL_IDE0_TF;
+	probe_ent->port[0].altstatus_addr =
 	probe_ent->port[0].ctl_addr = base + SIL_IDE0_CTL;
 	probe_ent->port[0].bmdma_addr = base + SIL_IDE0_BMDMA;
 	probe_ent->port[0].scr_addr = base + SIL_IDE0_SCR;
 	ata_std_ports(&probe_ent->port[0]);
 
 	probe_ent->port[1].cmd_addr = base + SIL_IDE1_TF;
+	probe_ent->port[1].altstatus_addr =
 	probe_ent->port[1].ctl_addr = base + SIL_IDE1_CTL;
 	probe_ent->port[1].bmdma_addr = base + SIL_IDE1_BMDMA;
 	probe_ent->port[1].scr_addr = base + SIL_IDE1_SCR;
@@ -373,12 +353,14 @@ static int sil_init_one (struct pci_dev 
 
 	if (ent->driver_data == sil_3114) {
 		probe_ent->port[2].cmd_addr = base + SIL_IDE2_TF;
+		probe_ent->port[2].altstatus_addr =
 		probe_ent->port[2].ctl_addr = base + SIL_IDE2_CTL;
 		probe_ent->port[2].bmdma_addr = base + SIL_IDE2_BMDMA;
 		probe_ent->port[2].scr_addr = base + SIL_IDE2_SCR;
 		ata_std_ports(&probe_ent->port[2]);
 
 		probe_ent->port[3].cmd_addr = base + SIL_IDE3_TF;
+		probe_ent->port[3].altstatus_addr =
 		probe_ent->port[3].ctl_addr = base + SIL_IDE3_CTL;
 		probe_ent->port[3].bmdma_addr = base + SIL_IDE3_BMDMA;
 		probe_ent->port[3].scr_addr = base + SIL_IDE3_SCR;
--- diff/drivers/scsi/sata_svw.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/sata_svw.c	2004-03-16 09:37:57.374817872 +0000
@@ -103,13 +103,13 @@ static void k2_sata_tf_load(struct ata_p
 		ata_wait_idle(ap);
 	}
 	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
-		writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->error_addr);
+		writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr);
 		writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr);
 		writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr);
 		writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr);
 		writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr);
 	} else if (is_addr) {
-		writew(tf->feature, ioaddr->error_addr);
+		writew(tf->feature, ioaddr->feature_addr);
 		writew(tf->nsect, ioaddr->nsect_addr);
 		writew(tf->lbal, ioaddr->lbal_addr);
 		writew(tf->lbam, ioaddr->lbam_addr);
@@ -146,27 +146,9 @@ static void k2_sata_tf_read(struct ata_p
 
 static u8 k2_stat_check_status(struct ata_port *ap)
 {
-       	return readl((void *) ap->ioaddr.cmdstat_addr);
+       	return readl((void *) ap->ioaddr.status_addr);
 }
 
-static void k2_sata_set_piomode (struct ata_port *ap, struct ata_device *adev,
-			      unsigned int pio)
-{
-	/* We need empty implementation, the core doesn't test for NULL
-	 * function pointer
-	 */
-}
-
-
-static void k2_sata_set_udmamode (struct ata_port *ap, struct ata_device *adev,
-			      unsigned int udma)
-{
-	/* We need empty implementation, the core doesn't test for NULL
-	 * function pointer
-	 */
-}
-
-
 #ifdef CONFIG_PPC_OF
 /*
  * k2_sata_proc_info
@@ -239,8 +221,6 @@ static Scsi_Host_Template k2_sata_sht = 
 
 static struct ata_port_operations k2_sata_ops = {
 	.port_disable		= ata_port_disable,
-	.set_piomode		= k2_sata_set_piomode,
-	.set_udmamode		= k2_sata_set_udmamode,
 	.tf_load		= k2_sata_tf_load,
 	.tf_read		= k2_sata_tf_read,
 	.check_status		= k2_stat_check_status,
@@ -261,13 +241,16 @@ static void k2_sata_setup_port(struct at
 {
 	port->cmd_addr		= base + K2_SATA_TF_CMD_OFFSET;
 	port->data_addr		= base + K2_SATA_TF_DATA_OFFSET;
+	port->feature_addr	=
 	port->error_addr	= base + K2_SATA_TF_ERROR_OFFSET;
 	port->nsect_addr	= base + K2_SATA_TF_NSECT_OFFSET;
 	port->lbal_addr		= base + K2_SATA_TF_LBAL_OFFSET;
 	port->lbam_addr		= base + K2_SATA_TF_LBAM_OFFSET;
 	port->lbah_addr		= base + K2_SATA_TF_LBAH_OFFSET;
 	port->device_addr	= base + K2_SATA_TF_DEVICE_OFFSET;
-	port->cmdstat_addr	= base + K2_SATA_TF_CMDSTAT_OFFSET;
+	port->command_addr	=
+	port->status_addr	= base + K2_SATA_TF_CMDSTAT_OFFSET;
+	port->altstatus_addr	=
 	port->ctl_addr		= base + K2_SATA_TF_CTL_OFFSET;
 	port->bmdma_addr	= base + K2_SATA_DMA_CMD_OFFSET;
 	port->scr_addr		= base + K2_SATA_SCR_STATUS_OFFSET;
--- diff/drivers/scsi/sata_via.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/sata_via.c	2004-03-16 09:37:57.375817720 +0000
@@ -43,10 +43,6 @@ enum {
 static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static void svia_sata_phy_reset(struct ata_port *ap);
 static void svia_port_disable(struct ata_port *ap);
-static void svia_set_piomode (struct ata_port *ap, struct ata_device *adev,
-			      unsigned int pio);
-static void svia_set_udmamode (struct ata_port *ap, struct ata_device *adev,
-			       unsigned int udma);
 
 static unsigned int in_module_init = 1;
 
@@ -83,8 +79,6 @@ static Scsi_Host_Template svia_sht = {
 
 static struct ata_port_operations svia_sata_ops = {
 	.port_disable		= svia_port_disable,
-	.set_piomode		= svia_set_piomode,
-	.set_udmamode		= svia_set_udmamode,
 
 	.tf_load		= ata_tf_load_pio,
 	.tf_read		= ata_tf_read_pio,
@@ -167,38 +161,6 @@ static void svia_port_disable(struct ata
 }
 
 /**
- *	svia_set_piomode -
- *	@ap:
- *	@adev:
- *	@pio:
- *
- *	LOCKING:
- *
- */
-
-static void svia_set_piomode (struct ata_port *ap, struct ata_device *adev,
-			      unsigned int pio)
-{
-	/* FIXME: needed? */
-}
-
-/**
- *	svia_set_udmamode -
- *	@ap:
- *	@adev:
- *	@udma:
- *
- *	LOCKING:
- *
- */
-
-static void svia_set_udmamode (struct ata_port *ap, struct ata_device *adev,
-			      unsigned int udma)
-{
-	/* FIXME: needed? */
-}
-
-/**
  *	svia_init_one -
  *	@pdev:
  *	@ent:
--- diff/drivers/scsi/scsi.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/scsi.c	2004-03-16 09:37:57.376817568 +0000
@@ -104,7 +104,7 @@ const char *const scsi_device_types[MAX_
 	"Communications   ",
 	"Unknown          ",
 	"Unknown          ",
-	"Unknown          ",
+	"RAID             ",
 	"Enclosure        ",
 };
 
@@ -1097,7 +1097,7 @@ int scsi_device_cancel(struct scsi_devic
 	struct list_head *lh, *lh_sf;
 	unsigned long flags;
 
-	sdev->sdev_state = SDEV_CANCEL;
+	scsi_device_set_state(sdev, SDEV_CANCEL);
 
 	spin_lock_irqsave(&sdev->list_lock, flags);
 	list_for_each_entry(scmd, &sdev->cmd_list, list) {
--- diff/drivers/scsi/scsi_devinfo.c	2003-10-27 09:20:43.000000000 +0000
+++ source/drivers/scsi/scsi_devinfo.c	2004-03-16 09:37:57.383816504 +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-16 09:37:57.395814680 +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 {
@@ -1181,6 +1293,8 @@ int scsi_decide_disposition(struct scsi_
 		 */
 	case DID_SOFT_ERROR:
 		goto maybe_retry;
+	case DID_IMM_RETRY:
+		return NEEDS_RETRY;
 
 	case DID_ERROR:
 		if (msg_byte(scmd->result) == COMMAND_COMPLETE &&
@@ -1401,10 +1515,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-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/scsi_lib.c	2004-03-16 09:37:57.396814528 +0000
@@ -24,7 +24,7 @@
 #include "scsi_logging.h"
 
 
-#define SG_MEMPOOL_NR		5
+#define SG_MEMPOOL_NR		(sizeof(scsi_sg_pools)/sizeof(struct scsi_host_sg_pool))
 #define SG_MEMPOOL_SIZE		32
 
 struct scsi_host_sg_pool {
@@ -34,9 +34,27 @@ struct scsi_host_sg_pool {
 	mempool_t	*pool;
 };
 
+#if (SCSI_MAX_PHYS_SEGMENTS < 32)
+#error SCSI_MAX_PHYS_SEGMENTS is too small
+#endif
+
 #define SP(x) { x, "sgpool-" #x } 
-struct scsi_host_sg_pool scsi_sg_pools[SG_MEMPOOL_NR] = { 
-	SP(8), SP(16), SP(32), SP(64), SP(MAX_PHYS_SEGMENTS)
+struct scsi_host_sg_pool scsi_sg_pools[] = { 
+	SP(8),
+	SP(16),
+	SP(32),
+#if (SCSI_MAX_PHYS_SEGMENTS > 32)
+	SP(64),
+#if (SCSI_MAX_PHYS_SEGMENTS > 64)
+	SP(128),
+#if (SCSI_MAX_PHYS_SEGMENTS > 128)
+	SP(256),
+#if (SCSI_MAX_PHYS_SEGMENTS > 256)
+#error SCSI_MAX_PHYS_SEGMENTS is too large
+#endif
+#endif
+#endif
+#endif
 }; 	
 #undef SP
 
@@ -172,6 +190,10 @@ int scsi_queue_insert(struct scsi_cmnd *
  *		like ioctls and character device requests - this is because
  *		we essentially just inject a request into the queue for the
  *		device.
+ *
+ *		In order to support the scsi_device_quiesce function, we
+ *		now inject requests on the *head* of the device queue
+ *		rather than the tail.
  */
 void scsi_do_req(struct scsi_request *sreq, const void *cmnd,
 		 void *buffer, unsigned bufflen,
@@ -202,11 +224,9 @@ void scsi_do_req(struct scsi_request *sr
 		sreq->sr_cmd_len = COMMAND_SIZE(sreq->sr_cmnd[0]);
 
 	/*
-	 * At this point, we merely set up the command, stick it in the normal
-	 * request queue, and return.  Eventually that request will come to the
-	 * top of the list, and will be dispatched.
+	 * head injection *required* here otherwise quiesce won't work
 	 */
-	scsi_insert_special_req(sreq, 0);
+	scsi_insert_special_req(sreq, 1);
 }
  
 static void scsi_wait_done(struct scsi_cmnd *cmd)
@@ -558,12 +578,21 @@ static struct scatterlist *scsi_alloc_sg
 	case 17 ... 32:
 		cmd->sglist_len = 2;
 		break;
+#if (SCSI_MAX_PHYS_SEGMENTS > 32)
 	case 33 ... 64:
 		cmd->sglist_len = 3;
 		break;
-	case 65 ... MAX_PHYS_SEGMENTS:
+#if (SCSI_MAX_PHYS_SEGMENTS > 64)
+	case 65 ... 128:
 		cmd->sglist_len = 4;
 		break;
+#if (SCSI_MAX_PHYS_SEGMENTS  > 128)
+	case 129 ... 256:
+		cmd->sglist_len = 5;
+		break;
+#endif
+#endif
+#endif
 	default:
 		return NULL;
 	}
@@ -917,6 +946,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;
 }
@@ -939,7 +969,7 @@ static int scsi_prep_fn(struct request_q
 		}
 		/* OK, we only allow special commands (i.e. not
 		 * user initiated ones */
-		specials_only = 1;
+		specials_only = sdev->sdev_state;
 	}
 
 	/*
@@ -965,6 +995,9 @@ static int scsi_prep_fn(struct request_q
 	} else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
 
 		if(unlikely(specials_only)) {
+			if(specials_only == SDEV_QUIESCE)
+				return BLKPREP_DEFER;
+			
 			printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to device being removed\n",
 			       sdev->host->host_no, sdev->id, sdev->lun);
 			return BLKPREP_KILL;
@@ -1285,7 +1318,7 @@ struct request_queue *scsi_alloc_queue(s
 	blk_queue_prep_rq(q, scsi_prep_fn);
 
 	blk_queue_max_hw_segments(q, shost->sg_tablesize);
-	blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
+	blk_queue_max_phys_segments(q, SCSI_MAX_PHYS_SEGMENTS);
 	blk_queue_max_sectors(q, shost->max_sectors);
 	blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost));
 	blk_queue_segment_boundary(q, shost->dma_boundary);
@@ -1508,3 +1541,95 @@ scsi_mode_sense(struct scsi_device *sdev
 
 	return ret;
 }
+
+/**
+ *	scsi_device_set_state - Take the given device through the device
+ *		state model.
+ *	@sdev:	scsi device to change the state of.
+ *	@state:	state to change to.
+ *
+ *	Returns zero if unsuccessful or an error if the requested 
+ *	transition is illegal.
+ **/
+int
+scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
+{
+	enum scsi_device_state oldstate = sdev->sdev_state;
+
+	/* FIXME: eventually we will enforce all the state model
+	 * transitions here */
+
+	if(oldstate == state)
+		return 0;
+
+	switch(state) {
+	case SDEV_RUNNING:
+		if(oldstate != SDEV_CREATED && oldstate != SDEV_QUIESCE)
+			return -EINVAL;
+		break;
+
+	case SDEV_QUIESCE:
+		if(oldstate != SDEV_RUNNING)
+			return -EINVAL;
+		break;
+
+	default:
+		break;
+	}
+	sdev->sdev_state = state;
+
+	return 0;
+}
+EXPORT_SYMBOL(scsi_device_set_state);
+
+/**
+ *	scsi_device_quiesce - Block user issued commands.
+ *	@sdev:	scsi device to quiesce.
+ *
+ *	This works by trying to transition to the SDEV_QUIESCE state
+ *	(which must be a legal transition).  When the device is in this
+ *	state, only special requests will be accepted, all others will
+ *	be deferred.  Since special requests may also be requeued requests,
+ *	a successful return doesn't guarantee the device will be 
+ *	totally quiescent.
+ *
+ *	Must be called with user context, may sleep.
+ *
+ *	Returns zero if unsuccessful or an error if not.
+ **/
+int
+scsi_device_quiesce(struct scsi_device *sdev)
+{
+	int err = scsi_device_set_state(sdev, SDEV_QUIESCE);
+	if(err)
+		return err;
+
+	scsi_run_queue(sdev->request_queue);
+	while(sdev->device_busy) {
+		schedule_timeout(HZ/5);
+		scsi_run_queue(sdev->request_queue);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(scsi_device_quiesce);
+
+/**
+ *	scsi_device_resume - Restart user issued commands to a quiesced device.
+ *	@sdev:	scsi device to resume.
+ *
+ *	Moves the device from quiesced back to running and restarts the
+ *	queues.
+ *
+ *	Must be called with user context, may sleep.
+ **/
+void
+scsi_device_resume(struct scsi_device *sdev)
+{
+	if(sdev->sdev_state != SDEV_QUIESCE)
+		return;
+
+	scsi_device_set_state(sdev, SDEV_RUNNING);
+	scsi_run_queue(sdev->request_queue);
+}
+EXPORT_SYMBOL(scsi_device_resume);
+
--- diff/drivers/scsi/scsi_priv.h	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/scsi_priv.h	2004-03-16 09:37:57.397814376 +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-16 09:37:57.399814072 +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);
@@ -627,6 +643,10 @@ static int scsi_add_lun(struct scsi_devi
 	if (*bflags & BLIST_USE_10_BYTE_MS)
 		sdev->use_10_for_ms = 1;
 
+	/* set the device running here so that slave configure
+	 * may do I/O */
+	scsi_device_set_state(sdev, SDEV_RUNNING);
+
 	if(sdev->host->hostt->slave_configure)
 		sdev->host->hostt->slave_configure(sdev);
 
@@ -744,6 +764,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 +1322,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-16 09:37:57.400813920 +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,13 +350,12 @@ static int attr_add(struct device *dev, 
  **/
 int scsi_sysfs_add_sdev(struct scsi_device *sdev)
 {
-	int error = -EINVAL, i;
+	struct class_device_attribute **attrs;
+	int error, i;
 
-	if (sdev->sdev_state != SDEV_CREATED)
+	if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0)
 		return error;
 
-	sdev->sdev_state = SDEV_RUNNING;
-
 	error = device_add(&sdev->sdev_gendev);
 	if (error) {
 		printk(KERN_INFO "error 1\n");
@@ -362,9 +367,20 @@ int scsi_sysfs_add_sdev(struct scsi_devi
 		printk(KERN_INFO "error 2\n");
 		goto clean_device;
 	}
-
+	/* take a reference for the sdev_classdev; this is
+	 * released by the sdev_class .release */
 	get_device(&sdev->sdev_gendev);
 
+	if (sdev->transport_classdev.class) {
+		error = class_device_add(&sdev->transport_classdev);
+		if (error)
+			goto clean_device2;
+		/* take a reference for the transport_classdev; this
+		 * is released by the transport_class .release */
+		get_device(&sdev->sdev_gendev);
+		
+	}
+
 	if (sdev->host->hostt->sdev_attrs) {
 		for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) {
 			error = attr_add(&sdev->sdev_gendev,
@@ -388,11 +404,25 @@ 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:
-	sdev->sdev_state = SDEV_CANCEL;
+ clean_device2:
+	class_device_del(&sdev->sdev_classdev);
+ clean_device:
+	scsi_device_set_state(sdev, SDEV_CANCEL);
 
 	device_del(&sdev->sdev_gendev);
 	put_device(&sdev->sdev_gendev);
@@ -407,11 +437,15 @@ clean_device:
 void scsi_remove_device(struct scsi_device *sdev)
 {
 	if (sdev->sdev_state == SDEV_RUNNING || sdev->sdev_state == SDEV_CANCEL) {
-		sdev->sdev_state = SDEV_DEL;
+		scsi_device_set_state(sdev, SDEV_DEL);
 		class_device_unregister(&sdev->sdev_classdev);
+		if(sdev->transport_classdev.class)
+			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 +532,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-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/sd.c	2004-03-16 09:37:57.417811336 +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/sg.c	2004-02-18 08:54:11.000000000 +0000
+++ source/drivers/scsi/sg.c	2004-03-16 09:37:57.420810880 +0000
@@ -1409,7 +1409,6 @@ find_empty_slot:
 	SCSI_LOG_TIMEOUT(3, printk("sg_add: dev=%d \n", k));
 	memset(sdp, 0, sizeof(*sdp));
 	sprintf(disk->disk_name, "sg%d", k);
-	strncpy(cdev->kobj.name, disk->disk_name, KOBJ_NAME_LEN);
 	cdev->owner = THIS_MODULE;
 	cdev->ops = &sg_fops;
 	disk->major = SCSI_GENERIC_MAJOR;
@@ -1439,7 +1438,7 @@ find_empty_slot:
 				MKDEV(SCSI_GENERIC_MAJOR, k), 
 				cl_dev->dev, "%s", 
 				disk->disk_name);
-		if (NULL == sg_class_member)
+		if (IS_ERR(sg_class_member))
 			printk(KERN_WARNING "sg_add: "
 				"class_simple_device_add failed\n");
 		class_set_devdata(sg_class_member, sdp);
@@ -1462,7 +1461,7 @@ find_empty_slot:
 out:
 	put_disk(disk);
 	if (cdev)
-		kobject_put(&cdev->kobj);
+		cdev_del(cdev);
 	return error;
 }
 
--- diff/drivers/scsi/sr.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/sr.c	2004-03-16 09:37:57.421810728 +0000
@@ -566,10 +566,13 @@ 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;
+
+	if (register_cdrom(&cd->cdi))
+		goto fail_put;
 
 	dev_set_drvdata(dev, cd);
 	add_disk(disk);
--- diff/drivers/scsi/st.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/scsi/st.c	2004-03-16 09:37:57.427809816 +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;
 
@@ -3944,7 +3959,7 @@ out_free_tape:
 		}
 	}
 	if (cdev)
-		kobject_put(&cdev->kobj);
+		cdev_del(cdev);
 	write_lock(&st_dev_arr_lock);
 	scsi_tapes[dev_num] = NULL;
 	st_nr_dev--;
@@ -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-16 09:37:57.427809816 +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/sym53c8xx.h	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/scsi/sym53c8xx_2/sym53c8xx.h	2004-03-16 09:37:57.428809664 +0000
@@ -70,13 +70,6 @@
 #define	SYM_CONF_DMA_ADDRESSING_MODE CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE
 
 /*
- *  NCR PQS/PDS special device support.
- */
-#if 1
-#define SYM_CONF_PQS_PDS_SUPPORT
-#endif
-
-/*
  *  NVRAM support.
  */
 #if 1
--- diff/drivers/scsi/sym53c8xx_2/sym_defs.h	2003-09-17 11:28:10.000000000 +0000
+++ source/drivers/scsi/sym53c8xx_2/sym_defs.h	2004-03-16 09:37:57.429809512 +0000
@@ -127,135 +127,6 @@ struct sym_pci_chip {
 };
 
 /*
- *	Symbios NVRAM data format
- */
-#define SYMBIOS_NVRAM_SIZE 368
-#define SYMBIOS_NVRAM_ADDRESS 0x100
-
-struct Symbios_nvram {
-/* Header 6 bytes */
-	u_short type;		/* 0x0000 */
-	u_short byte_count;	/* excluding header/trailer */
-	u_short checksum;
-
-/* Controller set up 20 bytes */
-	u_char	v_major;	/* 0x00 */
-	u_char	v_minor;	/* 0x30 */
-	u32	boot_crc;
-	u_short	flags;
-#define SYMBIOS_SCAM_ENABLE	(1)
-#define SYMBIOS_PARITY_ENABLE	(1<<1)
-#define SYMBIOS_VERBOSE_MSGS	(1<<2)
-#define SYMBIOS_CHS_MAPPING	(1<<3)
-#define SYMBIOS_NO_NVRAM	(1<<3)	/* ??? */
-	u_short	flags1;
-#define SYMBIOS_SCAN_HI_LO	(1)
-	u_short	term_state;
-#define SYMBIOS_TERM_CANT_PROGRAM	(0)
-#define SYMBIOS_TERM_ENABLED		(1)
-#define SYMBIOS_TERM_DISABLED		(2)
-	u_short	rmvbl_flags;
-#define SYMBIOS_RMVBL_NO_SUPPORT	(0)
-#define SYMBIOS_RMVBL_BOOT_DEVICE	(1)
-#define SYMBIOS_RMVBL_MEDIA_INSTALLED	(2)
-	u_char	host_id;
-	u_char	num_hba;	/* 0x04 */
-	u_char	num_devices;	/* 0x10 */
-	u_char	max_scam_devices;	/* 0x04 */
-	u_char	num_valid_scam_devices;	/* 0x00 */
-	u_char	flags2;
-#define SYMBIOS_AVOID_BUS_RESET		(1<<2)
-
-/* Boot order 14 bytes * 4 */
-	struct Symbios_host{
-		u_short	type;		/* 4:8xx / 0:nok */
-		u_short	device_id;	/* PCI device id */
-		u_short	vendor_id;	/* PCI vendor id */
-		u_char	bus_nr;		/* PCI bus number */
-		u_char	device_fn;	/* PCI device/function number << 3*/
-		u_short	word8;
-		u_short	flags;
-#define	SYMBIOS_INIT_SCAN_AT_BOOT	(1)
-		u_short	io_port;	/* PCI io_port address */
-	} host[4];
-
-/* Targets 8 bytes * 16 */
-	struct Symbios_target {
-		u_char	flags;
-#define SYMBIOS_DISCONNECT_ENABLE	(1)
-#define SYMBIOS_SCAN_AT_BOOT_TIME	(1<<1)
-#define SYMBIOS_SCAN_LUNS		(1<<2)
-#define SYMBIOS_QUEUE_TAGS_ENABLED	(1<<3)
-		u_char	rsvd;
-		u_char	bus_width;	/* 0x08/0x10 */
-		u_char	sync_offset;
-		u_short	sync_period;	/* 4*period factor */
-		u_short	timeout;
-	} target[16];
-/* Scam table 8 bytes * 4 */
-	struct Symbios_scam {
-		u_short	id;
-		u_short	method;
-#define SYMBIOS_SCAM_DEFAULT_METHOD	(0)
-#define SYMBIOS_SCAM_DONT_ASSIGN	(1)
-#define SYMBIOS_SCAM_SET_SPECIFIC_ID	(2)
-#define SYMBIOS_SCAM_USE_ORDER_GIVEN	(3)
-		u_short status;
-#define SYMBIOS_SCAM_UNKNOWN		(0)
-#define SYMBIOS_SCAM_DEVICE_NOT_FOUND	(1)
-#define SYMBIOS_SCAM_ID_NOT_SET		(2)
-#define SYMBIOS_SCAM_ID_VALID		(3)
-		u_char	target_id;
-		u_char	rsvd;
-	} scam[4];
-
-	u_char	spare_devices[15*8];
-	u_char	trailer[6];		/* 0xfe 0xfe 0x00 0x00 0x00 0x00 */
-};
-typedef struct Symbios_nvram	Symbios_nvram;
-typedef struct Symbios_host	Symbios_host;
-typedef struct Symbios_target	Symbios_target;
-typedef struct Symbios_scam	Symbios_scam;
-
-/*
- *	Tekram NvRAM data format.
- */
-#define TEKRAM_NVRAM_SIZE 64
-#define TEKRAM_93C46_NVRAM_ADDRESS 0
-#define TEKRAM_24C16_NVRAM_ADDRESS 0x40
-
-struct Tekram_nvram {
-	struct Tekram_target {
-		u_char	flags;
-#define	TEKRAM_PARITY_CHECK		(1)
-#define TEKRAM_SYNC_NEGO		(1<<1)
-#define TEKRAM_DISCONNECT_ENABLE	(1<<2)
-#define	TEKRAM_START_CMD		(1<<3)
-#define TEKRAM_TAGGED_COMMANDS		(1<<4)
-#define TEKRAM_WIDE_NEGO		(1<<5)
-		u_char	sync_index;
-		u_short	word2;
-	} target[16];
-	u_char	host_id;
-	u_char	flags;
-#define TEKRAM_MORE_THAN_2_DRIVES	(1)
-#define TEKRAM_DRIVES_SUP_1GB		(1<<1)
-#define	TEKRAM_RESET_ON_POWER_ON	(1<<2)
-#define TEKRAM_ACTIVE_NEGATION		(1<<3)
-#define TEKRAM_IMMEDIATE_SEEK		(1<<4)
-#define	TEKRAM_SCAN_LUNS		(1<<5)
-#define	TEKRAM_REMOVABLE_FLAGS		(3<<6)	/* 0: disable; */
-						/* 1: boot device; 2:all */
-	u_char	boot_delay_index;
-	u_char	max_tags_index;
-	u_short	flags1;
-#define TEKRAM_F2_F6_ENABLED		(1)
-	u_short	spare[29];
-};
-typedef struct Tekram_nvram	Tekram_nvram;
-typedef struct Tekram_target	Tekram_target;
-
-/*
  *	SYM53C8XX IO register data structure.
  */
 struct sym_reg {
--- diff/drivers/scsi/sym53c8xx_2/sym_fw.c	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/scsi/sym53c8xx_2/sym_fw.c	2004-03-16 09:37:57.430809360 +0000
@@ -135,7 +135,7 @@ static struct sym_fwz_ofs sym_fw2z_ofs =
  *  Patch routine for firmware #1.
  */
 static void
-sym_fw1_patch(hcb_p np)
+sym_fw1_patch(struct sym_hcb *np)
 {
 	struct sym_fw1a_scr *scripta0;
 	struct sym_fw1b_scr *scriptb0;
@@ -176,7 +176,7 @@ sym_fw1_patch(hcb_p np)
  *  Patch routine for firmware #2.
  */
 static void
-sym_fw2_patch(hcb_p np)
+sym_fw2_patch(struct sym_hcb *np)
 {
 	struct sym_fw2a_scr *scripta0;
 	struct sym_fw2b_scr *scriptb0;
@@ -282,7 +282,7 @@ sym_fw_fill_data (u32 *in, u32 *out)
  *  To be done for all firmwares.
  */
 static void 
-sym_fw_setup_bus_addresses(hcb_p np, struct sym_fw *fw)
+sym_fw_setup_bus_addresses(struct sym_hcb *np, struct sym_fw *fw)
 {
 	u32 *pa;
 	u_short *po;
@@ -319,7 +319,7 @@ sym_fw_setup_bus_addresses(hcb_p np, str
  *  Setup routine for firmware #1.
  */
 static void 
-sym_fw1_setup(hcb_p np, struct sym_fw *fw)
+sym_fw1_setup(struct sym_hcb *np, struct sym_fw *fw)
 {
 	struct sym_fw1a_scr *scripta0;
 	struct sym_fw1b_scr *scriptb0;
@@ -343,7 +343,7 @@ sym_fw1_setup(hcb_p np, struct sym_fw *f
  *  Setup routine for firmware #2.
  */
 static void 
-sym_fw2_setup(hcb_p np, struct sym_fw *fw)
+sym_fw2_setup(struct sym_hcb *np, struct sym_fw *fw)
 {
 	struct sym_fw2a_scr *scripta0;
 	struct sym_fw2b_scr *scriptb0;
@@ -389,7 +389,7 @@ sym_find_firmware(struct sym_pci_chip *c
 /*
  *  Bind a script to physical addresses.
  */
-void sym_fw_bind_script (hcb_p np, u32 *start, int len)
+void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len)
 {
 	u32 opcode, new, old, tmp1, tmp2;
 	u32 *end, *cur;
--- 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-16 09:37:57.432809056 +0000
@@ -57,7 +57,9 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <scsi/scsi.h>
+
 #include "sym_glue.h"
+#include "sym_nvram.h"
 
 #define NAME53C		"sym53c"
 #define NAME53C8XX	"sym53c8xx"
@@ -212,17 +214,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 +250,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 +413,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)
@@ -532,7 +552,7 @@ static int sym_queue_command(struct sym_
 /*
  *  Setup buffers and pointers that address the CDB.
  */
-static int __inline sym_setup_cdb(struct sym_hcb *np, struct scsi_cmnd *ccb, struct sym_ccb *cp)
+static inline int sym_setup_cdb(struct sym_hcb *np, struct scsi_cmnd *ccb, struct sym_ccb *cp)
 {
 	u32	cmd_ba;
 	int	cmd_len;
@@ -1281,7 +1301,7 @@ static int is_keyword(char *ptr, int len
 {
 	int verb_len = strlen(verb);
 
-	if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len))
+	if (len >= verb_len && !memcmp(verb, ptr, verb_len))
 		return verb_len;
 	else
 		return 0;
@@ -1938,7 +1958,7 @@ int __init sym53c8xx_setup(char *str)
 	char *cur = str;
 	char *pc, *pv;
 	unsigned long val;
-	int i,  c;
+	unsigned int i,  c;
 	int xi = 0;
 
 	while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
@@ -2171,6 +2191,55 @@ sym53c8xx_pci_init(struct pci_dev *pdev,
 	return 0;
 }
 
+/*
+ * The NCR PQS and PDS cards are constructed as a DEC bridge
+ * behind which sits a proprietary NCR memory controller and
+ * either four or two 53c875s as separate devices.  We can tell
+ * if an 875 is part of a PQS/PDS or not since if it is, it will
+ * be on the same bus as the memory controller.  In its usual
+ * mode of operation, the 875s are slaved to the memory
+ * controller for all transfers.  To operate with the Linux
+ * driver, the memory controller is disabled and the 875s
+ * freed to function independently.  The only wrinkle is that
+ * the preset SCSI ID (which may be zero) must be read in from
+ * a special configuration space register of the 875.
+ */
+void sym_config_pqs(struct pci_dev *pdev, struct sym_device *sym_dev)
+{
+	int slot;
+
+	for (slot = 0; slot < 256; slot++) {
+		u8 tmp;
+		struct pci_dev *memc = pci_get_slot(pdev->bus, slot);
+
+		if (!memc || memc->vendor != 0x101a || memc->device == 0x0009) {
+			pci_dev_put(memc);
+			continue;
+		}
+
+		/*
+		 * We set these bits in the memory controller once per 875.
+		 * This isn't a problem in practice.
+		 */
+
+		/* bit 1: allow individual 875 configuration */
+		pci_read_config_byte(memc, 0x44, &tmp);
+		tmp |= 0x2;
+		pci_write_config_byte(memc, 0x44, tmp);
+
+		/* bit 2: drive individual 875 interrupts to the bus */
+		pci_read_config_byte(memc, 0x45, &tmp);
+		tmp |= 0x4;
+		pci_write_config_byte(memc, 0x45, tmp);
+
+		pci_read_config_byte(pdev, 0x84, &tmp);
+		sym_dev->host_id = tmp;
+
+		pci_dev_put(memc);
+
+		break;
+	}
+}
 
 /*
  *  Called before unloading the module.
@@ -2221,79 +2290,6 @@ static struct scsi_host_template sym2_te
 #endif
 };
 
-#ifdef _SYM_CONF_PQS_PDS_SUPPORT
-#if 0
-/*
- *  Detect all NCR PQS/PDS boards and keep track of their bus nr.
- *
- *  The NCR PQS or PDS card is constructed as a DEC bridge
- *  behind which sit a proprietary NCR memory controller and
- *  four or two 53c875s as separate devices.  In its usual mode
- *  of operation, the 875s are slaved to the memory controller
- *  for all transfers.  We can tell if an 875 is part of a
- *  PQS/PDS or not since if it is, it will be on the same bus
- *  as the memory controller.  To operate with the Linux
- *  driver, the memory controller is disabled and the 875s
- *  freed to function independently.  The only wrinkle is that
- *  the preset SCSI ID (which may be zero) must be read in from
- *  a special configuration space register of the 875
- */
-#ifndef SYM_CONF_MAX_PQS_BUS
-#define SYM_CONF_MAX_PQS_BUS 16
-#endif
-static int pqs_bus[SYM_CONF_MAX_PQS_BUS] __initdata = { 0 };
-
-static void __init sym_detect_pqs_pds(void)
-{
-	short index;
-	struct pci_dev *dev = NULL;
-
-	for(index=0; index < SYM_CONF_MAX_PQS_BUS; index++) {
-		u_char tmp;
-
-		dev = pci_find_device(0x101a, 0x0009, dev);
-		if (dev == NULL) {
-			pqs_bus[index] = -1;
-			break;
-		}
-		printf_info(NAME53C8XX ": NCR PQS/PDS memory controller detected on bus %d\n", dev->bus->number);
-		pci_read_config_byte(dev, 0x44, &tmp);
-		/* bit 1: allow individual 875 configuration */
-		tmp |= 0x2;
-		pci_write_config_byte(dev, 0x44, tmp);
-		pci_read_config_byte(dev, 0x45, &tmp);
-		/* bit 2: drive individual 875 interrupts to the bus */
-		tmp |= 0x4;
-		pci_write_config_byte(dev, 0x45, tmp);
-
-		pqs_bus[index] = dev->bus->number;
-	}
-}
-#endif
-
-static int pqs_probe()
-{
-}
-
-static void pqs_remove()
-{
-}
-
-static struct pci_device_id pqs_id_table[] __devinitdata = {
-	{ 0x101a, 0x0009, },
-	{ 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, pqs_id_table);
-
-static struct pci_driver pqs_driver = {
-	.name		= NAME53C8XX " (PQS)",
-	.id_table	= pqs_id_table,
-	.probe		= pqs_probe,
-	.remove		= __devexit_p(pqs_remove),
-};
-#endif /* PQS */
-
 static int attach_count;
 
 static int __devinit sym2_probe(struct pci_dev *pdev,
@@ -2318,6 +2314,8 @@ static int __devinit sym2_probe(struct p
 	if (sym53c8xx_pci_init(pdev, &sym_dev))
 		goto free;
 
+	sym_config_pqs(pdev, &sym_dev);
+
 	sym_get_nvram(&sym_dev, &nvram);
 
 	instance = sym_attach(&sym2_template, attach_count, &sym_dev);
@@ -2406,9 +2404,6 @@ static struct pci_driver sym2_driver = {
 
 static int __init sym2_init(void)
 {
-#ifdef _SYM_CONF_PQS_PDS_SUPPORT
-	pci_register_driver(&pqs_driver);
-#endif
 	pci_register_driver(&sym2_driver);
 	return 0;
 }
@@ -2416,9 +2411,6 @@ static int __init sym2_init(void)
 static void __exit sym2_exit(void)
 {
 	pci_unregister_driver(&sym2_driver);
-#ifdef _SYM_CONF_PQS_PDS_SUPPORT
-	pci_unregister_driver(&pqs_driver);
-#endif
 }
 
 module_init(sym2_init);
--- diff/drivers/scsi/sym53c8xx_2/sym_glue.h	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/scsi/sym53c8xx_2/sym_glue.h	2004-03-16 09:37:57.433808904 +0000
@@ -77,9 +77,9 @@
 /*
  *  General driver includes.
  */
-#include "sym_misc.h"
 #include "sym_conf.h"
 #include "sym_defs.h"
+#include "sym_misc.h"
 
 /*
  * Configuration addendum for Linux.
@@ -113,6 +113,26 @@
 #define sym_mdelay(ms)	mdelay(ms)
 
 /*
+ *  A 'read barrier' flushes any data that have been prefetched 
+ *  by the processor due to out of order execution. Such a barrier 
+ *  must notably be inserted prior to looking at data that have 
+ *  been DMAed, assuming that program does memory READs in proper 
+ *  order and that the device ensured proper ordering of WRITEs.
+ *
+ *  A 'write barrier' prevents any previous WRITEs to pass further 
+ *  WRITEs. Such barriers must be inserted each time another agent 
+ *  relies on ordering of WRITEs.
+ *
+ *  Note that, due to posting of PCI memory writes, we also must 
+ *  insert dummy PCI read transactions when some ordering involving 
+ *  both directions over the PCI does matter. PCI transactions are 
+ *  fully ordered in each direction.
+ */
+
+#define MEMORY_READ_BARRIER()	rmb()
+#define MEMORY_WRITE_BARRIER()	wmb()
+
+/*
  *  Let the compiler know about driver data structure names.
  */
 typedef struct sym_tcb *tcb_p;
@@ -413,6 +433,8 @@ struct sym_slot {
 	char	inst_name[16];
 };
 
+struct sym_nvram;
+
 struct sym_device {
 	struct pci_dev *pdev;
 	struct sym_slot  s;
@@ -420,13 +442,8 @@ struct sym_device {
 	struct sym_nvram *nvram;
 	u_short device_id;
 	u_char host_id;
-#ifdef	SYM_CONF_PQS_PDS_SUPPORT
-	u_char pqs_pds;
-#endif
 };
 
-typedef struct sym_device *sdev_p;
-
 /*
  *  The driver definitions (sym_hipd.h) must know about a 
  *  couple of things related to the memory allocator.
--- diff/drivers/scsi/sym53c8xx_2/sym_hipd.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/scsi/sym53c8xx_2/sym_hipd.c	2004-03-16 09:37:57.443807384 +0000
@@ -50,13 +50,10 @@
  * SUCH DAMAGE.
  */
 
-#define SYM_DRIVER_NAME	"sym-2.1.18f"
+#define SYM_DRIVER_NAME	"sym-2.1.18i"
 
-#ifdef __FreeBSD__
-#include <dev/sym/sym_glue.h>
-#else
 #include "sym_glue.h"
-#endif
+#include "sym_nvram.h"
 
 #if 0
 #define SYM_DEBUG_GENERIC_SUPPORT
@@ -616,8 +613,7 @@ sym_getsync(hcb_p np, u_char dt, u_char 
 	if (dt) {
 		fak = (kpc - 1) / (div_10M[div] << 1) + 1 - 2;
 		/* ret = ((2+fak)*div_10M[div])/np->clock_khz; */
-	}
-	else {
+	} else {
 		fak = (kpc - 1) / div_10M[div] + 1 - 4;
 		/* ret = ((4+fak)*div_10M[div])/np->clock_khz; */
 	}
@@ -625,8 +621,10 @@ sym_getsync(hcb_p np, u_char dt, u_char 
 	/*
 	 *  Check against our hardware limits, or bugs :).
 	 */
-	if (fak < 0)	{fak = 0; ret = -1;}
-	if (fak > 2)	{fak = 2; ret = -1;}
+	if (fak > 2) {
+		fak = 2;
+		ret = -1;
+	}
 
 	/*
 	 *  Compute and return sync parameters.
@@ -1054,8 +1052,9 @@ static int sym_prepare_setting(hcb_p np,
 		sym_nvram_setup_target (np, i, nvram);
 
 		/*
-		 *  For now, guess PPR/DT support from the period 
-		 *  and BUS width.
+		 * Some single-ended devices may crash on receiving a
+		 * PPR negotiation attempt.  Only try PPR if we're in
+		 * LVD mode.
 		 */
 		if (np->features & FE_ULTRA3) {
 			tp->tinfo.user.options |= PPR_OPT_DT;
--- diff/drivers/scsi/sym53c8xx_2/sym_hipd.h	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/scsi/sym53c8xx_2/sym_hipd.h	2004-03-16 09:37:57.445807080 +0000
@@ -171,6 +171,15 @@
 #define	SYM_CONF_MIN_ASYNC (40)
 
 /*
+ *  Shortest memory chunk is (1<<SYM_MEM_SHIFT), currently 16.
+ *  Actual allocations happen as SYM_MEM_CLUSTER_SIZE sized.
+ *  (1 PAGE at a time is just fine).
+ */
+#define SYM_MEM_SHIFT	4
+#define SYM_MEM_CLUSTER_SIZE	(1UL << SYM_MEM_CLUSTER_SHIFT)
+#define SYM_MEM_CLUSTER_MASK	(SYM_MEM_CLUSTER_SIZE-1)
+
+/*
  *  Number of entries in the START and DONE queues.
  *
  *  We limit to 1 PAGE in order to succeed allocation of 
@@ -196,21 +205,6 @@
 #define MAX_QUEUE	SYM_CONF_MAX_QUEUE
 
 /*
- *  Union of supported NVRAM formats.
- */
-struct sym_nvram {
-	int type;
-#define	SYM_SYMBIOS_NVRAM	(1)
-#define	SYM_TEKRAM_NVRAM	(2)
-#if SYM_CONF_NVRAM_SUPPORT
-	union {
-		Symbios_nvram Symbios;
-		Tekram_nvram Tekram;
-	} data;
-#endif
-};
-
-/*
  *  Common definitions for both bus space based and legacy IO methods.
  */
 #define INB(r)		INB_OFF(offsetof(struct sym_reg,r))
@@ -1114,23 +1108,6 @@ struct sym_hcb {
 
 #define HCB_BA(np, lbl)	(np->hcb_ba + offsetof(struct sym_hcb, lbl))
 
-/*
- *  NVRAM reading (sym_nvram.c).
- */
-#if SYM_CONF_NVRAM_SUPPORT
-void sym_nvram_setup_host (hcb_p np, struct sym_nvram *nvram);
-void sym_nvram_setup_target (hcb_p np, int target, struct sym_nvram *nvp);
-int sym_read_nvram (sdev_p np, struct sym_nvram *nvp);
-#else
-static inline void sym_nvram_setup_host(hcb_p np, struct sym_nvram *nvram) { }
-static inline void sym_nvram_setup_target(hcb_p np, struct sym_nvram *nvram) { }
-static inline int sym_read_nvram(sdev_p np, struct sym_nvram *nvp)
-{
-	nvp->type = 0;
-	return 0;
-}
-#endif
-
 
 /*
  *  FIRMWARES (sym_fw.c)
@@ -1257,8 +1234,8 @@ bad:
  *  Set up data pointers used by SCRIPTS.
  *  Called from O/S specific code.
  */
-static void __inline 
-sym_setup_data_pointers(hcb_p np, ccb_p cp, int dir)
+static inline void sym_setup_data_pointers(struct sym_hcb *np,
+		struct sym_ccb *cp, int dir)
 {
 	u32 lastp, goalp;
 
@@ -1323,15 +1300,6 @@ sym_setup_data_pointers(hcb_p np, ccb_p 
  */
 
 /*
- *  Shortest memory chunk is (1<<SYM_MEM_SHIFT), currently 16.
- *  Actual allocations happen as SYM_MEM_CLUSTER_SIZE sized.
- *  (1 PAGE at a time is just fine).
- */
-#define SYM_MEM_SHIFT	4
-#define SYM_MEM_CLUSTER_SIZE	(1UL << SYM_MEM_CLUSTER_SHIFT)
-#define SYM_MEM_CLUSTER_MASK	(SYM_MEM_CLUSTER_SIZE-1)
-
-/*
  *  Link between free memory chunks of a given size.
  */
 typedef struct sym_m_link {
--- diff/drivers/scsi/sym53c8xx_2/sym_misc.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/scsi/sym53c8xx_2/sym_misc.c	2004-03-16 09:37:57.445807080 +0000
@@ -315,7 +315,7 @@ __sym_sniff_inquiry(hcb_p np, u_char tn,
 	 */
 	inq_byte56 = tp->inq_byte56;
 	if (inq_version >= 4 && inq_len > 56)
-		tp->inq_byte56 = inq_data[56];
+		inq_byte56 = inq_data[56];
 #if 0
 printf("XXXXXX [%d] inq_version=%x inq_byte7=%x inq_byte56=%x XXXXX\n",
 	inq_len, inq_version, inq_byte7, inq_byte56);
@@ -328,6 +328,7 @@ printf("XXXXXX [%d] inq_version=%x inq_b
 	    tp->inq_byte56  != inq_byte56) {
 		tp->inq_version = inq_version;
 		tp->inq_byte7   = inq_byte7;
+		tp->inq_byte56  = inq_byte56;
 		return 1;
 	}
 	return 0;
--- diff/drivers/scsi/sym53c8xx_2/sym_misc.h	2003-09-17 11:28:10.000000000 +0000
+++ source/drivers/scsi/sym53c8xx_2/sym_misc.h	2004-03-16 09:37:57.446806928 +0000
@@ -54,41 +54,6 @@
 #define SYM_MISC_H
 
 /*
- *  A 'read barrier' flushes any data that have been prefetched 
- *  by the processor due to out of order execution. Such a barrier 
- *  must notably be inserted prior to looking at data that have 
- *  been DMAed, assuming that program does memory READs in proper 
- *  order and that the device ensured proper ordering of WRITEs.
- *
- *  A 'write barrier' prevents any previous WRITEs to pass further 
- *  WRITEs. Such barriers must be inserted each time another agent 
- *  relies on ordering of WRITEs.
- *
- *  Note that, due to posting of PCI memory writes, we also must 
- *  insert dummy PCI read transactions when some ordering involving 
- *  both directions over the PCI does matter. PCI transactions are 
- *  fully ordered in each direction.
- *
- *  IA32 processors insert implicit barriers when the processor 
- *  accesses unchacheable either for reading or writing, and 
- *  donnot reorder WRITEs. As a result, some 'read barriers' can 
- *  be avoided (following access to uncacheable), and 'write 
- *  barriers' should be useless (preventing compiler optimizations 
- *  should be enough).
- */
-
-#define __READ_BARRIER()	rmb()
-#define __WRITE_BARRIER()	wmb()
-
-#ifndef MEMORY_READ_BARRIER
-#define MEMORY_READ_BARRIER()	__READ_BARRIER()
-#endif
-#ifndef MEMORY_WRITE_BARRIER
-#define MEMORY_WRITE_BARRIER()	__WRITE_BARRIER()
-#endif
-
-
-/*
  *  A la VMS/CAM-3 queue management.
  */
 typedef struct sym_quehead {
@@ -222,48 +187,11 @@ static __inline struct sym_quehead *sym_
 #define sym_is_bit(p, n)	(((u32 *)(p))[(n)>>5] &   (1<<((n)&0x1f)))
 
 /*
- *  Portable but silly implemented byte order primitives.
- */
-#if	BYTE_ORDER == BIG_ENDIAN
-
-#define __revb16(x) (	(((u16)(x) & (u16)0x00ffU) << 8) | \
-			(((u16)(x) & (u16)0xff00U) >> 8) 	)
-#define __revb32(x) (	(((u32)(x) & 0x000000ffU) << 24) | \
-			(((u32)(x) & 0x0000ff00U) <<  8) | \
-			(((u32)(x) & 0x00ff0000U) >>  8) | \
-			(((u32)(x) & 0xff000000U) >> 24)	)
-
-#define __htole16(v)	__revb16(v)
-#define __htole32(v)	__revb32(v)
-#define __le16toh(v)	__htole16(v)
-#define __le32toh(v)	__htole32(v)
-
-static __inline u16	_htole16(u16 v) { return __htole16(v); }
-static __inline u32	_htole32(u32 v) { return __htole32(v); }
-#define _le16toh	_htole16
-#define _le32toh	_htole32
-
-#else	/* LITTLE ENDIAN */
-
-#define __htole16(v)	(v)
-#define __htole32(v)	(v)
-#define __le16toh(v)	(v)
-#define __le32toh(v)	(v)
-
-#define _htole16(v)	(v)
-#define _htole32(v)	(v)
-#define _le16toh(v)	(v)
-#define _le32toh(v)	(v)
-
-#endif	/* BYTE_ORDER */
-
-/*
  * The below round up/down macros are to be used with a constant 
  * as argument (sizeof(...) for example), for the compiler to 
  * optimize the whole thing.
  */
 #define _U_(a,m)	(a)<=(1<<m)?m:
-#define _D_(a,m)	(a)<(1<<(m+1))?m:
 
 /*
  * Round up logarithm to base 2 of a 16 bit constant.
@@ -274,23 +202,4 @@ static __inline u32	_htole32(u32 v) { re
  _U_(a, 8)_U_(a, 9)_U_(a,10)_U_(a,11)_U_(a,12)_U_(a,13)_U_(a,14)_U_(a,15) \
  16)
 
-/*
- * Round down logarithm to base 2 of a 16 bit constant.
- */
-#define _LGRD16_(a) \
-( \
- _D_(a, 0)_D_(a, 1)_D_(a, 2)_D_(a, 3)_D_(a, 4)_D_(a, 5)_D_(a, 6)_D_(a, 7) \
- _D_(a, 8)_D_(a, 9)_D_(a,10)_D_(a,11)_D_(a,12)_D_(a,13)_D_(a,14)_D_(a,15) \
- 16)
-
-/*
- * Round up a 16 bit constant to the nearest power of 2.
- */
-#define _SZRU16_(a) ((a)==0?0:(1<<_LGRU16_(a)))
-
-/*
- * Round down a 16 bit constant to the nearest power of 2.
- */
-#define _SZRD16_(a) ((a)==0?0:(1<<_LGRD16_(a)))
-
 #endif /* SYM_MISC_H */
--- diff/drivers/scsi/sym53c8xx_2/sym_nvram.c	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/scsi/sym53c8xx_2/sym_nvram.c	2004-03-16 09:37:57.447806776 +0000
@@ -50,11 +50,8 @@
  * SUCH DAMAGE.
  */
 
-#ifdef __FreeBSD__
-#include <dev/sym/sym_glue.h>
-#else
 #include "sym_glue.h"
-#endif
+#include "sym_nvram.h"
 
 /*
  *  Some poor and bogus sync table that refers to Tekram NVRAM layout.
@@ -246,8 +243,8 @@ static void sym_display_Tekram_nvram(str
 	}
 }
 #else
-static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) { }
-static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) { }
+static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) { (void)np; (void)nvram; }
+static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) { (void)np; (void)nvram; }
 #endif	/* SYM_CONF_DEBUG_NVRAM */
 
 
@@ -383,6 +380,61 @@ static void S24C16_read_byte(struct sym_
 	S24C16_write_ack(np, ack_data, gpreg, gpcntl);
 }
 
+#if SYM_CONF_NVRAM_WRITE_SUPPORT
+/*
+ *  Write 'len' bytes starting at 'offset'.
+ */
+static int sym_write_S24C16_nvram(struct sym_device *np, int offset,
+		u_char *data, int len)
+{
+	u_char	gpcntl, gpreg;
+	u_char	old_gpcntl, old_gpreg;
+	u_char	ack_data;
+	int	x;
+
+	/* save current state of GPCNTL and GPREG */
+	old_gpreg	= INB (nc_gpreg);
+	old_gpcntl	= INB (nc_gpcntl);
+	gpcntl		= old_gpcntl & 0x1c;
+
+	/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
+	OUTB (nc_gpreg,  old_gpreg);
+	OUTB (nc_gpcntl, gpcntl);
+
+	/* this is to set NVRAM into a known state with GPIO0/1 both low */
+	gpreg = old_gpreg;
+	S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
+	S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
+		
+	/* now set NVRAM inactive with GPIO0/1 both high */
+	S24C16_stop(np, &gpreg);
+
+	/* NVRAM has to be written in segments of 16 bytes */
+	for (x = 0; x < len ; x += 16) {
+		do {
+			S24C16_start(np, &gpreg);
+			S24C16_write_byte(np, &ack_data,
+					  0xa0 | (((offset+x) >> 7) & 0x0e),
+					  &gpreg, &gpcntl);
+		} while (ack_data & 0x01);
+
+		S24C16_write_byte(np, &ack_data, (offset+x) & 0xff, 
+				  &gpreg, &gpcntl);
+
+		for (y = 0; y < 16; y++)
+			S24C16_write_byte(np, &ack_data, data[x+y], 
+					  &gpreg, &gpcntl);
+		S24C16_stop(np, &gpreg);
+	}
+
+	/* return GPIO0/1 to original states after having accessed NVRAM */
+	OUTB (nc_gpcntl, old_gpcntl);
+	OUTB (nc_gpreg,  old_gpreg);
+
+	return 0;
+}
+#endif /* SYM_CONF_NVRAM_WRITE_SUPPORT */
+
 /*
  *  Read 'len' bytes starting at 'offset'.
  */
--- diff/drivers/scsi/sym53c8xx_comm.h	2003-10-09 08:47:34.000000000 +0000
+++ source/drivers/scsi/sym53c8xx_comm.h	2004-03-16 09:37:57.448806624 +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 13:16:13.000000000 +0000
+++ source/drivers/scsi/u14-34f.c	2004-03-16 09:37:57.449806472 +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/21285.c	2003-09-30 14:46:17.000000000 +0000
+++ source/drivers/serial/21285.c	2004-03-16 09:37:57.450806320 +0000
@@ -15,6 +15,7 @@
 #include <linux/console.h>
 #include <linux/serial_core.h>
 #include <linux/serial.h>
+#include <linux/device.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -542,3 +543,4 @@ module_exit(serial21285_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver $Revision: 1.37 $");
+MODULE_ALIAS_CHARDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);
--- diff/drivers/serial/8250.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/serial/8250.c	2004-03-16 09:37:57.452806016 +0000
@@ -833,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;
@@ -1194,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) {
@@ -1865,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);
@@ -2144,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/amba.c	2003-06-09 13:18:19.000000000 +0000
+++ source/drivers/serial/amba.c	2004-03-16 09:37:57.452806016 +0000
@@ -39,6 +39,7 @@
 #include <linux/serial.h>
 #include <linux/console.h>
 #include <linux/sysrq.h>
+#include <linux/device.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -758,3 +759,4 @@ module_exit(ambauart_exit);
 MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
 MODULE_DESCRIPTION("ARM AMBA serial port driver $Revision: 1.41 $");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV(SERIAL_AMBA_MAJOR, SERIAL_AMBA_MINOR);
--- diff/drivers/serial/anakin.c	2003-05-21 10:50:16.000000000 +0000
+++ source/drivers/serial/anakin.c	2004-03-16 09:37:57.453805864 +0000
@@ -30,6 +30,7 @@
 #include <linux/serial.h>
 #include <linux/console.h>
 #include <linux/sysrq.h>
+#include <linux/device.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -541,3 +542,4 @@ MODULE_DESCRIPTION("Anakin serial driver
 MODULE_AUTHOR("Tak-Shing Chan <chan@aleph1.co.uk>");
 MODULE_SUPPORTED_DEVICE("ttyAN");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV(SERIAL_ANAKIN_MAJOR, SERIAL_ANAKIN_MINOR);
--- diff/drivers/serial/clps711x.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/serial/clps711x.c	2004-03-16 09:37:57.453805864 +0000
@@ -34,6 +34,7 @@
 #include <linux/console.h>
 #include <linux/sysrq.h>
 #include <linux/spinlock.h>
+#include <linux/device.h>
 
 #include <asm/hardware.h>
 #include <asm/io.h>
@@ -611,3 +612,4 @@ module_exit(clps711xuart_exit);
 MODULE_AUTHOR("Deep Blue Solutions Ltd");
 MODULE_DESCRIPTION("CLPS-711x generic serial driver $Revision: 1.42 $");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR);
--- diff/drivers/serial/mux.c	2004-02-18 08:54:11.000000000 +0000
+++ source/drivers/serial/mux.c	2004-03-16 09:37:57.454805712 +0000
@@ -25,6 +25,7 @@
 #include <linux/console.h>
 #include <linux/slab.h>
 #include <linux/delay.h> /* for udelay */
+#include <linux/device.h>
 #include <asm/io.h>
 #include <asm/parisc-device.h>
 
@@ -535,3 +536,4 @@ module_exit(mux_exit);
 MODULE_AUTHOR("Ryan Bradetich");
 MODULE_DESCRIPTION("Serial MUX driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(MUX_MAJOR);
--- diff/drivers/serial/sa1100.c	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/serial/sa1100.c	2004-03-16 09:37:57.455805560 +0000
@@ -953,3 +953,4 @@ module_exit(sa1100_serial_exit);
 MODULE_AUTHOR("Deep Blue Solutions Ltd");
 MODULE_DESCRIPTION("SA1100 generic serial port driver $Revision: 1.50 $");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_SA1100_MAJOR);
--- diff/drivers/serial/serial_core.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/serial/serial_core.c	2004-03-16 09:37:57.457805256 +0000
@@ -1985,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/Kconfig	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/Kconfig	2004-03-16 09:37:57.458805104 +0000
@@ -6,32 +6,36 @@ menu "USB support"
 
 # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
 config USB
-	tristate "Support for USB"
+	tristate "Support for Host-side USB"
 	depends on PCI || SA1111 || ARCH_OMAP1510 || ARCH_OMAP1610
 	---help---
 	  Universal Serial Bus (USB) is a specification for a serial bus
 	  subsystem which offers higher speeds and more features than the
 	  traditional PC serial port.  The bus supplies power to peripherals
 	  and allows for hot swapping.  Up to 127 USB peripherals can be
-	  connected to a single USB port in a tree structure.  The USB port is
-	  the root of the tree, the peripherals are the leaves and the inner
-	  nodes are special USB devices called hubs.  Many newer PC's have USB
-	  ports and newer peripherals such as scanners, keyboards, mice,
-	  modems, and printers support the USB protocol and can be connected
-	  to the PC via those ports.
-
-	  Say Y here if your computer has a USB port and you want to use USB
-	  devices.  You then need to say Y to at least one of "UHCI HCD support"
-	  or "OHCI HCD support" below (the type of interface that the USB hardware
-	  in your computer provides to the operating system) and then choose
-	  from amongst the drivers for USB peripherals.  You may want to check
-	  out the information provided in <file:Documentation/usb/> and
-	  especially the links given in <file:Documentation/usb/usb-help.txt>.
-
-	  If you have a new USB 2.0 High Speed system, you should also choose
-	  "EHCI HCD (USB 2.0) support" as well as at least one of UHCI or OHCI.
-
-	  It doesn't normally hurt to select them all if you are not certain.
+	  connected to a single USB host in a tree structure.
+	  
+	  The USB host is the root of the tree, the peripherals are the
+	  leaves and the inner nodes are special USB devices called hubs.
+	  Most PCs now have USB host ports, used to connect peripherals
+	  such as scanners, keyboards, mice, modems, cameras, disks,
+	  flash memory, network links, and printers to the PC.
+
+	  Say Y here if your computer has a host-side USB port and you want
+	  to use USB devices.  You then need to say Y to at least one of the
+	  Host Controller Driver (HCD) options below.  Choose a USB 1.1
+	  controller, such as "UHCI HCD support" or "OHCI HCD support",
+	  and "EHCI HCD (USB 2.0) support" except for older systems that
+	  do not have USB 2.0 support.  It doesn't normally hurt to select
+	  them all if you are not certain.
+
+	  If your system has a device-side USB port, used in the peripheral
+	  side of the USB protocol, see the "USB Gadget" framework instead.
+
+	  After choosing your HCD, then select drivers for the USB peripherals
+	  you'll be using.  You may want to check out the information provided
+	  in <file:Documentation/usb/> and especially the links given in
+	  <file:Documentation/usb/usb-help.txt>.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called usbcore.
--- diff/drivers/usb/Makefile	2004-02-18 08:54:11.000000000 +0000
+++ source/drivers/usb/Makefile	2004-03-16 09:37:57.459804952 +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/
@@ -50,7 +55,6 @@ obj-$(CONFIG_USB_MICROTEK)	+= image/
 obj-$(CONFIG_USB_SERIAL)	+= serial/
 
 obj-$(CONFIG_USB_AUERSWALD)	+= misc/
-obj-$(CONFIG_USB_BRLVGER)	+= misc/
 obj-$(CONFIG_USB_EMI26)		+= misc/
 obj-$(CONFIG_USB_LCD)		+= misc/
 obj-$(CONFIG_USB_LEGOTOWER)	+= misc/
--- diff/drivers/usb/class/audio.c	2004-02-18 08:54:11.000000000 +0000
+++ source/drivers/usb/class/audio.c	2004-03-16 09:37:57.469803432 +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,11 @@
  *              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
+ * 2004-03-07:	Alan Stern <stern@rowland.harvard.edu>
+ *		Add usb_ifnum_to_if() and usb_altnum_to_altsetting() support.
+ *		Use the in-memory descriptors instead of reading them from the device.
+ * 
  */
 
 /*
@@ -141,8 +146,8 @@
  *
  * How does the parsing work? First, all interfaces are searched
  * for an AudioControl class interface. If found, the config descriptor
- * that belongs to the current configuration is fetched from the device.
- * Then the HEADER descriptor is fetched. It contains a list of
+ * that belongs to the current configuration is searched and
+ * the HEADER descriptor is found. It contains a list of
  * all AudioStreaming and MIDIStreaming devices. This list is then walked,
  * and all AudioStreaming interfaces are classified into input and output
  * interfaces (according to the endpoint0 direction in altsetting1) (MIDIStreaming
@@ -1512,7 +1517,6 @@ static int find_format(struct audioforma
 static int set_format_in(struct usb_audiodev *as)
 {
 	struct usb_device *dev = as->state->usbdev;
-	struct usb_host_config *config = dev->actconfig;
 	struct usb_host_interface *alts;
 	struct usb_interface *iface;
 	struct usbin *u = &as->usbin;
@@ -1522,9 +1526,9 @@ static int set_format_in(struct usb_audi
 	unsigned char data[3];
 	int fmtnr, ret;
 
-	if (u->interface < 0 || u->interface >= config->desc.bNumInterfaces)
+	iface = usb_ifnum_to_if(dev, u->interface);
+	if (!iface)
 		return 0;
-	iface = config->interface[u->interface];
 
 	fmtnr = find_format(as->fmtin, as->numfmtin, d->format, d->srate);
 	if (fmtnr < 0) {
@@ -1533,7 +1537,7 @@ static int set_format_in(struct usb_audi
 	}
 
 	fmt = as->fmtin + fmtnr;
-	alts = &iface->altsetting[fmt->altsetting];
+	alts = usb_altnum_to_altsetting(iface, fmt->altsetting);
 	u->format = fmt->format;
 	u->datapipe = usb_rcvisocpipe(dev, alts->endpoint[0].desc.bEndpointAddress & 0xf);
 	u->syncpipe = u->syncinterval = 0;
@@ -1542,18 +1546,20 @@ 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;
 	if (d->srate > fmt->sratehi)
 		d->srate = fmt->sratehi;
-	dprintk((KERN_DEBUG "usbaudio: set_format_in: usb_set_interface %u %u\n", alts->desc.bInterfaceNumber, fmt->altsetting));
+	dprintk((KERN_DEBUG "usbaudio: set_format_in: usb_set_interface %u %u\n",
+			u->interface, fmt->altsetting));
 	if (usb_set_interface(dev, alts->desc.bInterfaceNumber, fmt->altsetting) < 0) {
 		printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
 		       dev->devnum, u->interface, fmt->altsetting);
@@ -1600,7 +1606,6 @@ static int set_format_in(struct usb_audi
 static int set_format_out(struct usb_audiodev *as)
 {
 	struct usb_device *dev = as->state->usbdev;
-	struct usb_host_config *config = dev->actconfig;
 	struct usb_host_interface *alts;
 	struct usb_interface *iface;	
 	struct usbout *u = &as->usbout;
@@ -1610,9 +1615,9 @@ static int set_format_out(struct usb_aud
 	unsigned char data[3];
 	int fmtnr, ret;
 
-	if (u->interface < 0 || u->interface >= config->desc.bNumInterfaces)
+	iface = usb_ifnum_to_if(dev, u->interface);
+	if (!iface)
 		return 0;
-	iface = config->interface[u->interface];
 
 	fmtnr = find_format(as->fmtout, as->numfmtout, d->format, d->srate);
 	if (fmtnr < 0) {
@@ -1622,7 +1627,7 @@ static int set_format_out(struct usb_aud
 
 	fmt = as->fmtout + fmtnr;
 	u->format = fmt->format;
-	alts = &iface->altsetting[fmt->altsetting];
+	alts = usb_altnum_to_altsetting(iface, fmt->altsetting);
 	u->datapipe = usb_sndisocpipe(dev, alts->endpoint[0].desc.bEndpointAddress & 0xf);
 	u->syncpipe = u->syncinterval = 0;
 	if ((alts->endpoint[0].desc.bmAttributes & 0x0c) == 0x04) {
@@ -1637,18 +1642,20 @@ 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;
 	if (d->srate > fmt->sratehi)
 		d->srate = fmt->sratehi;
-	dprintk((KERN_DEBUG "usbaudio: set_format_out: usb_set_interface %u %u\n", alts->desc.bInterfaceNumber, fmt->altsetting));
+	dprintk((KERN_DEBUG "usbaudio: set_format_out: usb_set_interface %u %u\n",
+			u->interface, fmt->altsetting));
 	if (usb_set_interface(dev, u->interface, fmt->altsetting) < 0) {
 		printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
 		       dev->devnum, u->interface, fmt->altsetting);
@@ -2697,7 +2704,6 @@ static int usb_audio_release(struct inod
 	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
 	struct usb_audio_state *s;
 	struct usb_device *dev;
-	struct usb_interface *iface;
 
 	lock_kernel();
 	s = as->state;
@@ -2707,19 +2713,15 @@ static int usb_audio_release(struct inod
 	down(&open_sem);
 	if (file->f_mode & FMODE_WRITE) {
 		usbout_stop(as);
-		if (dev && as->usbout.interface >= 0) {
-			iface = dev->actconfig->interface[as->usbout.interface];
-			usb_set_interface(dev, iface->altsetting->desc.bInterfaceNumber, 0);
-		}
+		if (dev && as->usbout.interface >= 0)
+			usb_set_interface(dev, as->usbout.interface, 0);
 		dmabuf_release(&as->usbout.dma);
 		usbout_release(as);
 	}
 	if (file->f_mode & FMODE_READ) {
 		usbin_stop(as);
-		if (dev && as->usbin.interface >= 0) {
-			iface = dev->actconfig->interface[as->usbin.interface];
-			usb_set_interface(dev, iface->altsetting->desc.bInterfaceNumber, 0);
-		}
+		if (dev && as->usbin.interface >= 0)
+			usb_set_interface(dev, as->usbin.interface, 0);
 		dmabuf_release(&as->usbin.dma);
 		usbin_release(as);
 	}
@@ -2824,12 +2826,11 @@ static void usb_audio_parsestreaming(str
 {
 	struct usb_device *dev = s->usbdev;
 	struct usb_audiodev *as;
-	struct usb_host_config *config = dev->actconfig;
 	struct usb_host_interface *alts;
 	struct usb_interface *iface;
 	struct audioformat *fp;
 	unsigned char *fmt, *csep;
-	unsigned int i, j, k, format;
+	unsigned int i, j, k, format, idx;
 
 	if (!(as = kmalloc(sizeof(struct usb_audiodev), GFP_KERNEL)))
 		return;
@@ -2870,9 +2871,10 @@ static void usb_audio_parsestreaming(str
 	/* search for input formats */
 	if (asifin >= 0) {
 		as->usbin.flags = FLG_CONNECTED;
-		iface = config->interface[asifin];
-		for (i = 0; i < iface->num_altsetting; i++) {
-			alts = &iface->altsetting[i];
+		iface = usb_ifnum_to_if(dev, asifin);
+		for (idx = 0; idx < iface->num_altsetting; idx++) {
+			alts = &iface->altsetting[idx];
+			i = alts->desc.bAlternateSetting;
 			if (alts->desc.bInterfaceClass != USB_CLASS_AUDIO || alts->desc.bInterfaceSubClass != 2)
 				continue;
 			if (alts->desc.bNumEndpoints < 1) {
@@ -2951,14 +2953,15 @@ static void usb_audio_parsestreaming(str
 	/* search for output formats */
 	if (asifout >= 0) {
 		as->usbout.flags = FLG_CONNECTED;
-		iface = config->interface[asifout];
-		for (i = 0; i < iface->num_altsetting; i++) {
-			alts = &iface->altsetting[i];
+		iface = usb_ifnum_to_if(dev, asifout);
+		for (idx = 0; idx < iface->num_altsetting; idx++) {
+			alts = &iface->altsetting[idx];
+			i = alts->desc.bAlternateSetting;
 			if (alts->desc.bInterfaceClass != USB_CLASS_AUDIO || alts->desc.bInterfaceSubClass != 2)
 				continue;
 			if (alts->desc.bNumEndpoints < 1) {
 				/* altsetting 0 should never have iso EPs */
-				if (alts->desc.bAlternateSetting != 0)
+				if (i != 0)
 				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u does not have an endpoint\n", 
 				       dev->devnum, asifout, i);
 				continue;
@@ -3655,8 +3658,8 @@ static void usb_audio_constructmixer(str
 static struct usb_audio_state *usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif)
 {
 	struct usb_audio_state *s;
-	struct usb_host_config *config = dev->actconfig;
 	struct usb_interface *iface;
+	struct usb_host_interface *alt;
 	unsigned char ifin[USB_MAXINTERFACES], ifout[USB_MAXINTERFACES];
 	unsigned char *p1;
 	unsigned int i, j, k, numifin = 0, numifout = 0;
@@ -3685,54 +3688,63 @@ static struct usb_audio_state *usb_audio
 		       dev->devnum, ctrlif);
 	for (i = 0; i < p1[7]; i++) {
 		j = p1[8+i];
-		if (j >= config->desc.bNumInterfaces) {
+		iface = usb_ifnum_to_if(dev, j);
+		if (!iface) {
 			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u does not exist\n",
 			       dev->devnum, ctrlif, j);
 			continue;
 		}
-		iface = config->interface[j];
-		if (iface->altsetting[0].desc.bInterfaceClass != USB_CLASS_AUDIO) {
-			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u is not an AudioClass interface\n",
-			       dev->devnum, ctrlif, j);
+		if (iface->num_altsetting == 1) {
+			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has only 1 altsetting.\n", dev->devnum, ctrlif);
 			continue;
 		}
-		if (iface->altsetting[0].desc.bInterfaceSubClass == 3) {
-			printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u interface %u MIDIStreaming not supported\n",
+		alt = usb_altnum_to_altsetting(iface, 0);
+		if (!alt) {
+			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no altsetting 0\n",
 			       dev->devnum, ctrlif, j);
 			continue;
 		}
-		if (iface->altsetting[0].desc.bInterfaceSubClass != 2) {
-			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u invalid AudioClass subtype\n",
+		if (alt->desc.bInterfaceClass != USB_CLASS_AUDIO) {
+			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u is not an AudioClass interface\n",
 			       dev->devnum, ctrlif, j);
 			continue;
 		}
-		if (iface->num_altsetting == 0) {
-			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has no working interface.\n", dev->devnum, ctrlif);
+		if (alt->desc.bInterfaceSubClass == 3) {
+			printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u interface %u MIDIStreaming not supported\n",
+			       dev->devnum, ctrlif, j);
 			continue;
 		}
-		if (iface->num_altsetting == 1) {
-			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has only 1 altsetting.\n", dev->devnum, ctrlif);
+		if (alt->desc.bInterfaceSubClass != 2) {
+			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u invalid AudioClass subtype\n",
+			       dev->devnum, ctrlif, j);
 			continue;
 		}
-		if (iface->altsetting[0].desc.bNumEndpoints > 0) {
+		if (alt->desc.bNumEndpoints > 0) {
 			/* Check all endpoints; should they all have a bandwidth of 0 ? */
-			for (k = 0; k < iface->altsetting[0].desc.bNumEndpoints; k++) {
-				if (iface->altsetting[0].endpoint[k].desc.wMaxPacketSize > 0) {
+			for (k = 0; k < alt->desc.bNumEndpoints; k++) {
+				if (alt->endpoint[k].desc.wMaxPacketSize > 0) {
 					printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u endpoint %d does not have 0 bandwidth at alt[0]\n", dev->devnum, ctrlif, k);
 					break;
 				}
 			}
-			if (k < iface->altsetting[0].desc.bNumEndpoints)
+			if (k < alt->desc.bNumEndpoints)
 				continue;
 		}
-		if (iface->altsetting[1].desc.bNumEndpoints < 1) {
+
+		alt = usb_altnum_to_altsetting(iface, 1);
+		if (!alt) {
+			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no altsetting 1\n",
+			       dev->devnum, ctrlif, j);
+			continue;
+		}
+		if (alt->desc.bNumEndpoints < 1) {
 			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no endpoint\n",
 			       dev->devnum, ctrlif, j);
 			continue;
 		}
 		/* note: this requires the data endpoint to be ep0 and the optional sync
 		   ep to be ep1, which seems to be the case */
-		if (iface->altsetting[1].endpoint[0].desc.bEndpointAddress & USB_DIR_IN) {
+		if (alt->endpoint[0].desc.bEndpointAddress & USB_DIR_IN) {
 			if (numifin < USB_MAXINTERFACES) {
 				ifin[numifin++] = j;
 				usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1);
@@ -3779,12 +3791,9 @@ static int usb_audio_probe(struct usb_in
 			   const struct usb_device_id *id)
 {
 	struct usb_device *dev = interface_to_usbdev (intf);
-	struct usb_host_config *config = dev->actconfig;	
 	struct usb_audio_state *s;
 	unsigned char *buffer;
-	unsigned char buf[8];
-	unsigned int i, buflen;
-	int ret;
+	unsigned int buflen;
 
 #if 0
 	printk(KERN_DEBUG "usbaudio: Probing if %i: IC %x, ISC %x\n", ifnum,
@@ -3796,26 +3805,8 @@ static int usb_audio_probe(struct usb_in
 	 * audiocontrol interface found
 	 * find which configuration number is active
 	 */
-	i = dev->actconfig - config;
-
-	ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buf, 8);
-	if (ret < 0) {
-		printk(KERN_ERR "usbaudio: cannot get first 8 bytes of config descriptor %d of device %d (error %d)\n", i, dev->devnum, ret);
-		return -EIO;
-	}
-	if (buf[1] != USB_DT_CONFIG || buf[0] < 9) {
-		printk(KERN_ERR "usbaudio: invalid config descriptor %d of device %d\n", i, dev->devnum);
-		return -EIO;
-	}
-	buflen = buf[2] | (buf[3] << 8);
-	if (!(buffer = kmalloc(buflen, GFP_KERNEL)))
-		return -ENOMEM;
-	ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buffer, buflen);
-	if (ret < 0) {
-		kfree(buffer);
-		printk(KERN_ERR "usbaudio: cannot get config descriptor %d of device %d (error %d)\n", i, dev->devnum, ret);
-		return -EIO;
-	}
+	buffer = dev->rawdescriptors[dev->actconfig - dev->config];
+	buflen = dev->actconfig->desc.wTotalLength;
 	s = usb_audio_parsecontrol(dev, buffer, buflen, intf->altsetting->desc.bInterfaceNumber);
 	if (s) {
 		usb_set_intfdata (intf, s);
--- diff/drivers/usb/class/bluetty.c	2003-09-17 11:28:10.000000000 +0000
+++ source/drivers/usb/class/bluetty.c	2004-03-16 09:37:57.470803280 +0000
@@ -1025,7 +1025,7 @@ static int usb_bluetooth_probe (struct u
 	int num_bulk_in = 0;
 	int num_bulk_out = 0;
 
-	interface = &intf->altsetting[0];
+	interface = intf->cur_altsetting;
 	control_out_endpoint = interface->desc.bInterfaceNumber;
 
 	/* find the endpoints that we need */
--- diff/drivers/usb/class/cdc-acm.c	2004-02-18 08:54:11.000000000 +0000
+++ source/drivers/usb/class/cdc-acm.c	2004-03-16 09:37:57.470803280 +0000
@@ -595,12 +595,12 @@ static int acm_probe (struct usb_interfa
 			 * is there it's not for call management ... so use
 			 * the cdc union descriptor whenever there is one.
 			 */
-			ifcom = intf->altsetting + 0;
+			ifcom = intf->cur_altsetting;
 			if (intf == cfacm->interface[j]) {
-				ifdata = cfacm->interface[j + 1]->altsetting + 0;
+				ifdata = cfacm->interface[j + 1]->cur_altsetting;
 				data = cfacm->interface[j + 1];
 			} else if (intf == cfacm->interface[j + 1]) {
-				ifdata = cfacm->interface[j]->altsetting + 0;
+				ifdata = cfacm->interface[j]->cur_altsetting;
 				data = cfacm->interface[j];
 			} else
 				continue;
--- diff/drivers/usb/class/usb-midi.c	2003-09-30 14:46:17.000000000 +0000
+++ source/drivers/usb/class/usb-midi.c	2004-03-16 09:37:57.472802976 +0000
@@ -39,9 +39,6 @@
 #include <linux/init.h>
 #include <asm/semaphore.h>
 
-/** This declaration is missing from linux/usb.h **/
-extern int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size);
-
 #include "usb-midi.h"
 
 /* ------------------------------------------------------------------------- */
@@ -1519,15 +1516,17 @@ static int on_bits( unsigned short v )
 static int get_alt_setting( struct usb_device *d, int ifnum )
 {
 	int alts, alt=0;
+	struct usb_interface *iface;
 	struct usb_host_interface *interface;
 	struct usb_endpoint_descriptor *ep;
 	int epin, epout;
 	int i;
 
-	alts = d->actconfig->interface[ifnum]->num_altsetting;
+	iface = usb_ifnum_to_if( d, ifnum );
+	alts = iface->num_altsetting;
 
 	for ( alt=0 ; alt<alts ; alt++ ) {
-		interface = &d->actconfig->interface[ifnum]->altsetting[alt];
+		interface = &iface->altsetting[alt];
 		epin = -1;
 		epout = -1;
 
@@ -1542,7 +1541,7 @@ static int get_alt_setting( struct usb_d
 				epout = i;
 			}
 			if ( epin >= 0 && epout >= 0 ) {
-				return alt;
+				return interface->desc.bAlternateSetting;
 			}
 		}
 	}
@@ -1780,12 +1779,13 @@ static int alloc_usb_midi_device( struct
  *  Called by usb_midi_probe();
  **/
 
-static int detect_yamaha_device( struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s)
+static int detect_yamaha_device( struct usb_device *d,
+		struct usb_interface *iface, unsigned int ifnum,
+		struct usb_midi_state *s)
 {
-	struct usb_host_config *c = d->actconfig;
 	struct usb_host_interface *interface;
 	struct usb_midi_device *u;
-	unsigned char buf[USB_DT_CONFIG_SIZE], *buffer;
+	unsigned char *buffer;
 	int bufSize;
 	int i;
 	int alts=-1;
@@ -1795,13 +1795,13 @@ static int detect_yamaha_device( struct 
 		return -EINVAL;
 	}
 
-	for ( i=0 ; i < c->interface[ifnum]->num_altsetting; i++ ) {
-		interface = c->interface[ifnum]->altsetting + i;
+	for ( i=0 ; i < iface->num_altsetting; i++ ) {
+		interface = iface->altsetting + i;
 
 		if ( interface->desc.bInterfaceClass != 255 ||
 		     interface->desc.bInterfaceSubClass != 0 )
 			continue;
-		alts = i;
+		alts = interface->desc.bAlternateSetting;
 	}
 	if ( alts == -1 ) {
 		return -EINVAL;
@@ -1810,30 +1810,11 @@ static int detect_yamaha_device( struct 
 	printk(KERN_INFO "usb-midi: Found YAMAHA USB-MIDI device on dev %04x:%04x, iface %d\n",
 	       d->descriptor.idVendor, d->descriptor.idProduct, ifnum);
 
-	ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buf, USB_DT_CONFIG_SIZE );
-	if ( ret < 0 ) {
-		printk(KERN_INFO "usb-midi: Could not get config (error=%d).\n", ret);
-		return -EINVAL;
-	}
-	if ( buf[1] != USB_DT_CONFIG || buf[0] < USB_DT_CONFIG_SIZE ) {
-		printk(KERN_INFO "usb-midi: config not as expected.\n");
-		return -EINVAL;
-	}
-	bufSize = buf[2] | buf[3]<<8;
-	buffer = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL);
-	if ( !buffer ) {
-		printk(KERN_INFO "usb-midi: Could not allocate memory.\n");
-		return -EINVAL;
-	}
-	ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buffer, bufSize );
-	if ( ret < 0 ) {
-		printk(KERN_INFO "usb-midi: Could not get full config (error=%d).\n", ret);
-		kfree(buffer);
-		return -EINVAL;
-	}
+	i = d->actconfig - d->config;
+	buffer = d->rawdescriptors[i];
+	bufSize = d->actconfig->desc.wTotalLength;
 
 	u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 1);
-	kfree(buffer);
 	if ( u == NULL ) {
 		return -EINVAL;
 	}
@@ -1878,24 +1859,25 @@ static int detect_vendor_specific_device
  *  Returns 0 on success, negative on failure.
  * Called by usb_midi_probe();
  **/
-static int detect_midi_subclass(struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s)
+static int detect_midi_subclass(struct usb_device *d,
+		struct usb_interface *iface, unsigned int ifnum,
+		struct usb_midi_state *s)
 {
-	struct usb_host_config *c = d->actconfig;
 	struct usb_host_interface *interface;
 	struct usb_midi_device *u;
-	unsigned char buf[USB_DT_CONFIG_SIZE], *buffer;
+	unsigned char *buffer;
 	int bufSize;
 	int i;
 	int alts=-1;
 	int ret;
 
-	for ( i=0 ; i < c->interface[ifnum]->num_altsetting; i++ ) {
-		interface = c->interface[ifnum]->altsetting + i;
+	for ( i=0 ; i < iface->num_altsetting; i++ ) {
+		interface = iface->altsetting + i;
 
 		if ( interface->desc.bInterfaceClass != USB_CLASS_AUDIO ||
 		     interface->desc.bInterfaceSubClass != USB_SUBCLASS_MIDISTREAMING )
 			continue;
-		alts = i;
+		alts = interface->desc.bAlternateSetting;
 	}
 	if ( alts == -1 ) {
 		return -EINVAL;
@@ -1915,30 +1897,11 @@ static int detect_midi_subclass(struct u
 	   descriptor they modify or extend.
 	*/
 
-	ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buf, USB_DT_CONFIG_SIZE );
-	if ( ret < 0 ) {
-		printk(KERN_INFO "usb-midi: Could not get config (error=%d).\n", ret);
-		return -EINVAL;
-	}
-	if ( buf[1] != USB_DT_CONFIG || buf[0] < USB_DT_CONFIG_SIZE ) {
-		printk(KERN_INFO "usb-midi: config not as expected.\n");
-		return -EINVAL;
-	}
-	bufSize = buf[2] | buf[3]<<8;
-	buffer = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL);
-	if ( !buffer ) {
-		printk(KERN_INFO "usb-midi: Could not allocate memory.\n");
-		return -EINVAL;
-	}
-	ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buffer, bufSize );
-	if ( ret < 0 ) {
-		printk(KERN_INFO "usb-midi: Could not get full config (error=%d).\n", ret);
-		kfree(buffer);
-		return -EINVAL;
-	}
+	i = d->actconfig - d->config;
+	buffer = d->rawdescriptors[i];
+	bufSize = d->actconfig->desc.wTotalLength;
 
 	u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 0);
-	kfree(buffer);
 	if ( u == NULL ) {
 		return -EINVAL;
 	}
@@ -2002,7 +1965,7 @@ static int usb_midi_probe(struct usb_int
 {
 	struct usb_midi_state *s;
 	struct usb_device *dev = interface_to_usbdev(intf);
-	int ifnum = intf->altsetting->desc.bInterfaceNumber;
+	int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
 
 	s = (struct usb_midi_state *)kmalloc(sizeof(struct usb_midi_state), GFP_KERNEL);
 	if ( !s )
@@ -2018,9 +1981,9 @@ static int usb_midi_probe(struct usb_int
 
 	if (
 		detect_by_hand( dev, ifnum, s ) &&
-		detect_midi_subclass( dev, ifnum, s ) &&
+		detect_midi_subclass( dev, intf, ifnum, s ) &&
 		detect_vendor_specific_device( dev, ifnum, s ) &&
-		detect_yamaha_device( dev, ifnum, s) ) {
+		detect_yamaha_device( dev, intf, ifnum, s) ) {
 		kfree(s);
 		return -EIO;
 	}
--- diff/drivers/usb/class/usblp.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/usb/class/usblp.c	2004-03-16 09:37:57.473802824 +0000
@@ -133,6 +133,7 @@ struct usblp {
 	wait_queue_head_t	wait;			/* Zzzzz ... */
 	int			readcount;		/* Counter for reads */
 	int			ifnum;			/* Interface number */
+	struct usb_interface	*intf;			/* The interface */
 	/* Alternate-setting numbers and endpoints for each protocol
 	 * (7/1/{index=1,2,3}) that the device supports: */
 	struct {
@@ -609,8 +610,10 @@ static ssize_t usblp_write(struct file *
 	while (writecount < count) {
 		if (!usblp->wcomplete) {
 			barrier();
-			if (file->f_flags & O_NONBLOCK)
+			if (file->f_flags & O_NONBLOCK) {
+				writecount += transfer_length;
 				return writecount ? writecount : -EAGAIN;
+			}
 
 			timeout = USBLP_WRITE_TIMEOUT;
 			add_wait_queue(&usblp->wait, &wait);
@@ -670,7 +673,8 @@ static ssize_t usblp_write(struct file *
 
 		usblp->writeurb->transfer_buffer_length = transfer_length;
 
-		if (copy_from_user(usblp->writeurb->transfer_buffer, buffer + writecount, transfer_length)) {
+		if (copy_from_user(usblp->writeurb->transfer_buffer, 
+				   buffer + writecount, transfer_length)) {
 			up(&usblp->sem);
 			return writecount ? writecount : -EFAULT;
 		}
@@ -837,7 +841,8 @@ static int usblp_probe(struct usb_interf
 	usblp->dev = dev;
 	init_MUTEX (&usblp->sem);
 	init_waitqueue_head(&usblp->wait);
-	usblp->ifnum = intf->altsetting->desc.bInterfaceNumber;
+	usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+	usblp->intf = intf;
 
 	usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!usblp->writeurb) {
@@ -973,7 +978,7 @@ static int usblp_select_alts(struct usbl
 	struct usb_endpoint_descriptor *epd, *epwrite, *epread;
 	int p, i, e;
 
-	if_alt = usblp->dev->actconfig->interface[usblp->ifnum];
+	if_alt = usblp->intf;
 
 	for (p = 0; p < USBLP_MAX_PROTOCOLS; p++)
 		usblp->protocol[p].alt_setting = -1;
@@ -1022,7 +1027,8 @@ static int usblp_select_alts(struct usbl
 			epread = NULL;
 		}
 
-		usblp->protocol[ifd->desc.bInterfaceProtocol].alt_setting = i;
+		usblp->protocol[ifd->desc.bInterfaceProtocol].alt_setting =
+				ifd->desc.bAlternateSetting;
 		usblp->protocol[ifd->desc.bInterfaceProtocol].epwrite = epwrite;
 		usblp->protocol[ifd->desc.bInterfaceProtocol].epread = epread;
 	}
--- diff/drivers/usb/core/buffer.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/usb/core/buffer.c	2004-03-16 09:37:57.474802672 +0000
@@ -51,8 +51,8 @@ static const size_t	pool_max [HCD_BUFFER
  * @hcd: the bus whose buffer pools are to be initialized
  * Context: !in_interrupt()
  *
- * Call this as part of initializing a host controller that uses the pci dma
- * memory allocators.  It initializes some pools of dma-consistent memory that
+ * Call this as part of initializing a host controller that uses the dma
+ * memory allocators.  It initializes some pools of dma-coherent memory that
  * will be shared by all drivers using that controller, or returns a negative
  * errno value on error.
  *
@@ -115,6 +115,12 @@ void *hcd_buffer_alloc (
 	struct usb_hcd		*hcd = bus->hcpriv;
 	int 			i;
 
+	/* some USB hosts just use PIO */
+	if (!bus->controller->dma_mask) {
+		*dma = ~(dma_addr_t) 0;
+		return kmalloc (size, mem_flags);
+	}
+
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
 		if (size <= pool_max [i])
 			return dma_pool_alloc (hcd->pool [i], mem_flags, dma);
@@ -134,6 +140,12 @@ void hcd_buffer_free (
 
 	if (!addr)
 		return;
+
+	if (!bus->controller->dma_mask) {
+		kfree (addr);
+		return;
+	}
+
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
 		if (size <= pool_max [i]) {
 			dma_pool_free (hcd->pool [i], addr, dma);
--- diff/drivers/usb/core/config.c	2003-09-30 14:46:17.000000000 +0000
+++ source/drivers/usb/core/config.c	2004-03-16 09:37:57.474802672 +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-16 09:37:57.475802520 +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-16 09:37:57.476802368 +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-11 10:20:27.000000000 +0000
+++ source/drivers/usb/core/hcd-pci.c	2004-03-16 09:37:57.476802368 +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/hcd.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/usb/core/hcd.c	2004-03-16 09:37:57.477802216 +0000
@@ -1213,7 +1213,7 @@ static int hcd_unlink_urb (struct urb *u
 			break;
 	}
 	if (tmp != &urb->urb_list) {
-		retval = -EINVAL;
+		retval = -EIDRM;
 		goto done;
 	}
 
@@ -1294,7 +1294,7 @@ done:
 	spin_unlock (&hcd_data_lock);
 	spin_unlock_irqrestore (&urb->lock, flags);
 bye:
-	if (retval && sys && sys->driver)
+	if (retval != -EIDRM && sys && sys->driver)
 		dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
 	return retval;
 }
--- diff/drivers/usb/core/hub.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/usb/core/hub.c	2004-03-16 09:37:57.478802064 +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-11 10:20:27.000000000 +0000
+++ source/drivers/usb/core/message.c	2004-03-16 09:37:57.480801760 +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/urb.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/core/urb.c	2004-03-16 09:37:57.481801608 +0000
@@ -116,7 +116,8 @@ struct urb * usb_get_urb(struct urb *urb
  * describing that request to the USB subsystem.  Request completion will
  * be indicated later, asynchronously, by calling the completion handler.
  * The three types of completion are success, error, and unlink
- * (also called "request cancellation").
+ * (a software-induced fault, also called "request cancelation").  
+ *
  * URBs may be submitted in interrupt context.
  *
  * The caller must have correctly initialized the URB before submitting
@@ -127,12 +128,23 @@ struct urb * usb_get_urb(struct urb *urb
  *
  * Successful submissions return 0; otherwise this routine returns a
  * negative error number.  If the submission is successful, the complete()
- * callback from the urb will be called exactly once, when the USB core and
- * host controller driver are finished with the urb.  When the completion
+ * callback from the URB will be called exactly once, when the USB core and
+ * Host Controller Driver (HCD) are finished with the URB.  When the completion
  * function is called, control of the URB is returned to the device
  * driver which issued the request.  The completion handler may then
  * immediately free or reuse that URB.
  *
+ * With few exceptions, USB device drivers should never access URB fields
+ * provided by usbcore or the HCD until its complete() is called.
+ * The exceptions relate to periodic transfer scheduling.  For both
+ * interrupt and isochronous urbs, as part of successful URB submission
+ * urb->interval is modified to reflect the actual transfer period used
+ * (normally some power of two units).  And for isochronous urbs,
+ * urb->start_frame is modified to reflect when the URB's transfers were
+ * scheduled to start.  Not all isochronous transfer scheduling policies
+ * will work, but most host controller drivers should easily handle ISO
+ * queues going from now until 10-200 msec into the future.
+ *
  * For control endpoints, the synchronous usb_control_msg() call is
  * often used (in non-interrupt context) instead of this call.
  * That is often used through convenience wrappers, for the requests
@@ -143,15 +155,17 @@ struct urb * usb_get_urb(struct urb *urb
  *
  * URBs may be submitted to endpoints before previous ones complete, to
  * minimize the impact of interrupt latencies and system overhead on data
- * throughput.  This is required for continuous isochronous data streams,
+ * throughput.  With that queuing policy, an endpoint's queue would never
+ * be empty.  This is required for continuous isochronous data streams,
  * and may also be required for some kinds of interrupt transfers. Such
- * queueing also maximizes bandwidth utilization by letting USB controllers
+ * queuing also maximizes bandwidth utilization by letting USB controllers
  * start work on later requests before driver software has finished the
- * completion processing for earlier requests.
+ * completion processing for earlier (successful) requests.
  *
- * Bulk and Isochronous URBs may always be queued.  At this writing, all
- * mainstream host controller drivers support queueing for control and
- * interrupt transfer requests.
+ * As of Linux 2.6, all USB endpoint transfer queues support depths greater
+ * than one.  This was previously a HCD-specific behavior, except for ISO
+ * transfers.  Non-isochronous endpoint queues are inactive during cleanup
+ * after faults (transfer errors or cancelation).
  *
  * Reserved Bandwidth Transfers:
  *
@@ -389,7 +403,7 @@ int usb_submit_urb(struct urb *urb, int 
  * When the URB_ASYNC_UNLINK transfer flag for the URB is clear, this
  * request is synchronous.  Success is indicated by returning zero,
  * at which time the urb will have been unlinked and its completion
- * handler will have been called with urb->status -ENOENT.  Failure is
+ * handler will have been called with urb->status == -ENOENT.  Failure is
  * indicated by any other return value.
  *
  * The synchronous cancelation mode may not be used
@@ -400,8 +414,37 @@ int usb_submit_urb(struct urb *urb, int 
  * When the URB_ASYNC_UNLINK transfer flag for the URB is set, this
  * request is asynchronous.  Success is indicated by returning -EINPROGRESS,
  * at which time the urb will normally not have been unlinked.
- * The completion function will see urb->status -ECONNRESET.  Failure
+ * The completion function will see urb->status == -ECONNRESET.  Failure
  * is indicated by any other return value.
+ *
+ * Unlinking and Endpoint Queues:
+ *
+ * Host Controller Driver (HCDs) place all the URBs for a particular
+ * endpoint in a queue.  Normally the queue advances as the controller
+ * hardware processes each request.  But when an URB terminates with any
+ * fault (such as an error, or being unlinked) its queue stops, at least
+ * until that URB's completion routine returns.  It is guaranteed that
+ * the queue will not restart until all its unlinked URBs have been fully
+ * retired, with their completion routines run, even if that's not until
+ * some time after the original completion handler returns.
+ *
+ * This means that USB device drivers can safely build deep queues for
+ * large or complex transfers, and clean them up reliably after any sort
+ * of aborted transfer by unlinking all pending URBs at the first fault.
+ *
+ * Note that an URB terminating early because a short packet was received
+ * will count as an error if and only if the URB_SHORT_NOT_OK flag is set.
+ * Also, that all unlinks performed in any URB completion handler must
+ * be asynchronous.
+ *
+ * Queues for isochronous endpoints are treated differently, because they
+ * advance at fixed rates.  Such queues do not stop when an URB is unlinked.
+ * An unlinked URB may leave a gap in the stream of packets.  It is undefined
+ * whether such gaps can be filled in.
+ *
+ * When control URBs terminates with an error, it is likely that the
+ * status stage of the transfer will not take place, even if it is merely
+ * a soft error resulting from a short-packet with URB_SHORT_NOT_OK set.
  */
 int usb_unlink_urb(struct urb *urb)
 {
--- diff/drivers/usb/core/usb.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/usb/core/usb.c	2004-03-16 09:37:57.482801456 +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/Kconfig	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/gadget/Kconfig	2004-03-16 09:37:57.484801152 +0000
@@ -3,6 +3,15 @@
 #    (a) a peripheral controller, and
 #    (b) the gadget driver using it.
 #
+# NOTE:  Gadget support ** DOES NOT ** depend on host-side CONFIG_USB !!
+#
+#  - Host systems (like PCs) need CONFIG_USB (with "A" jacks).
+#  - Peripherals (like PDAs) need CONFIG_USB_GADGET (with "B" jacks).
+#  - Some systems have both kinds of of controller.
+#
+# With help from a special transceiver and a "Mini-AB" jack, systems with
+# both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG).
+#
 menu "USB Gadget Support"
 
 config USB_GADGET
@@ -11,7 +20,7 @@ config USB_GADGET
 	   USB is a master/slave protocol, organized with one master
 	   host (such as a PC) controlling up to 127 peripheral devices.
 	   The USB hardware is asymmetric, which makes it easier to set up:
-	   you can't connect two "to-the-host" connectors to each other.
+	   you can't connect a "to-the-host" connector to a peripheral.
 
 	   Linux can run in the host, or in the peripheral.  In both cases
 	   you need a low level bus controller driver, and some software
@@ -43,6 +52,7 @@ choice
 config USB_GADGET_NET2280
 	boolean "NetChip 2280"
 	depends on PCI
+	select USB_GADGET_DUALSPEED
 	help
 	   NetChip 2280 is a PCI based USB peripheral controller which
 	   supports both full and high speed USB 2.0 data transfers.  
@@ -126,6 +136,13 @@ config USB_SA1100
 
 endchoice
 
+config USB_GADGET_DUALSPEED
+	bool
+	depends on USB_GADGET
+	default n
+	help
+	  Means that gadget drivers should include extra descriptors
+	  and code to handle dual-speed controllers.
 
 #
 # USB Gadget Drivers
--- diff/drivers/usb/gadget/Makefile	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/gadget/Makefile	2004-03-16 09:37:57.484801152 +0000
@@ -8,8 +8,8 @@ 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_zero-objs			:= zero.o usbstring.o config.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-16 09:37:57.486800848 +0000
@@ -124,7 +124,6 @@ struct eth_dev {
  * DRIVER_VERSION_NUM ... alerts the host side driver to differences
  * EP_*_NAME ... which endpoints do we use for which purpose?
  * EP_*_NUM ... numbers for them (often limited by hardware)
- * HIGHSPEED ... define if ep0 and descriptors need high speed support
  * WAKEUP ... if hardware supports remote wakeup AND we will issue the
  * 	usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP
  *
@@ -162,7 +161,6 @@ static const char EP_IN_NAME [] = "ep-b"
 #define EP_IN_NUM	2
 static const char EP_STATUS_NAME [] = "ep-f";
 #define EP_STATUS_NUM	3
-#define HIGHSPEED
 /* supports remote wakeup, but this driver doesn't */
 
 extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
@@ -311,7 +309,7 @@ static const char EP_IN_NAME[] = "ep2in-
 #define DEFAULT_QLEN	2	/* double buffering by default */
 #endif
 
-#ifdef HIGHSPEED
+#ifdef CONFIG_USB_GADGET_DUALSPEED
 
 static unsigned qmult = 5;
 module_param (qmult, uint, S_IRUGO|S_IWUSR);
@@ -324,7 +322,7 @@ module_param (qmult, uint, S_IRUGO|S_IWU
 /* also defer IRQs on highspeed TX */
 #define TX_DELAY	DEFAULT_QLEN
 
-#else	/* !HIGHSPEED ... full speed: */
+#else	/* full speed (low speed doesn't do bulk) */
 #define qlen(gadget) DEFAULT_QLEN
 #endif
 
@@ -607,7 +605,26 @@ fs_sink_desc = {
 	.wMaxPacketSize =	__constant_cpu_to_le16 (64),
 };
 
-#ifdef	HIGHSPEED
+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	CONFIG_USB_GADGET_DUALSPEED
 
 /*
  * usb 2.0 devices need to expose both high speed and full speed
@@ -660,6 +677,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))
@@ -669,7 +705,7 @@ dev_qualifier = {
 /* if there's no high speed support, maxpacket doesn't change. */
 #define ep_desc(g,hs,fs) fs
 
-#endif	/* !HIGHSPEED */
+#endif	/* !CONFIG_USB_GADGET_DUALSPEED */
 
 /*-------------------------------------------------------------------------*/
 
@@ -704,86 +740,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 CONFIG_USB_GADGET_DUALSPEED
+	int				hs = (speed == USB_SPEED_HIGH);
 
-#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;
-
-	/* 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;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -992,7 +967,7 @@ eth_set_config (struct eth_dev *dev, uns
 
 		switch (gadget->speed) {
 		case USB_SPEED_FULL:	speed = "full"; break;
-#ifdef HIGHSPEED
+#ifdef CONFIG_USB_GADGET_DUALSPEED
 		case USB_SPEED_HIGH:	speed = "high"; break;
 #endif
 		default: 		speed = "?"; break;
@@ -1163,15 +1138,19 @@ eth_setup (struct usb_gadget *gadget, co
 			value = min (ctrl->wLength, (u16) sizeof device_desc);
 			memcpy (req->buf, &device_desc, value);
 			break;
-#ifdef HIGHSPEED
+#ifdef CONFIG_USB_GADGET_DUALSPEED
 		case USB_DT_DEVICE_QUALIFIER:
+			if (!gadget->is_dualspeed)
+				break;
 			value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
 			memcpy (req->buf, &dev_qualifier, value);
 			break;
 
 		case USB_DT_OTHER_SPEED_CONFIG:
+			if (!gadget->is_dualspeed)
+				break;
 			// FALLTHROUGH
-#endif /* HIGHSPEED */
+#endif /* CONFIG_USB_GADGET_DUALSPEED */
 		case USB_DT_CONFIG:
 			value = config_buf (gadget->speed, req->buf,
 					ctrl->wValue >> 8,
@@ -1675,7 +1654,7 @@ static int eth_start_xmit (struct sk_buf
 #endif
 	req->length = length;
 
-#ifdef	HIGHSPEED
+#ifdef	CONFIG_USB_GADGET_DUALSPEED
 	/* throttle highspeed IRQ rate back slightly */
 	req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
 		? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0)
@@ -1798,7 +1777,7 @@ eth_bind (struct usb_gadget *gadget)
 #endif
 
 	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
-#ifdef	HIGHSPEED
+#ifdef	CONFIG_USB_GADGET_DUALSPEED
 	/* assumes ep0 uses the same value for both speeds ... */
 	dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
 #endif
@@ -1894,7 +1873,7 @@ fail:
 /*-------------------------------------------------------------------------*/
 
 static struct usb_gadget_driver eth_driver = {
-#ifdef HIGHSPEED
+#ifdef CONFIG_USB_GADGET_DUALSPEED
 	.speed		= USB_SPEED_HIGH,
 #else
 	.speed		= USB_SPEED_FULL,
--- diff/drivers/usb/gadget/net2280.c	2004-03-11 10:20:27.000000000 +0000
+++ source/drivers/usb/gadget/net2280.c	2004-03-16 09:37:57.488800544 +0000
@@ -2663,7 +2663,7 @@ static void gadget_release (struct devic
 
 /* tear down the binding between this driver and the pci device */
 
-static void __exit net2280_remove (struct pci_dev *pdev)
+static void net2280_remove (struct pci_dev *pdev)
 {
 	struct net2280		*dev = pci_get_drvdata (pdev);
 
@@ -2736,6 +2736,7 @@ static int net2280_probe (struct pci_dev
 	spin_lock_init (&dev->lock);
 	dev->pdev = pdev;
 	dev->gadget.ops = &net2280_ops;
+	dev->gadget.is_dualspeed = 1;
 
 	/* the "gadget" abstracts/virtualizes the controller */
 	strcpy (dev->gadget.dev.bus_id, "gadget");
@@ -2884,7 +2885,7 @@ static struct pci_driver net2280_pci_dri
 	.id_table =	pci_ids,
 
 	.probe =	net2280_probe,
-	.remove =	__exit_p(net2280_remove),
+	.remove =	net2280_remove,
 
 	/* FIXME add power management support */
 };
--- diff/drivers/usb/gadget/usbstring.c	2003-06-09 13:18:19.000000000 +0000
+++ source/drivers/usb/gadget/usbstring.c	2004-03-16 09:37:57.488800544 +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/gadget/zero.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/gadget/zero.c	2004-03-16 09:37:57.490800240 +0000
@@ -1,7 +1,7 @@
 /*
  * zero.c -- Gadget Zero, for USB development
  *
- * Copyright (C) 2003 David Brownell
+ * Copyright (C) 2003-2004 David Brownell
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -103,6 +103,11 @@ static const char loopback [] = "loop in
 /*-------------------------------------------------------------------------*/
 
 /*
+ * driver assumes self-powered hardware, and
+ * has no way for users to trigger remote wakeup.
+ */
+
+/*
  * hardware-specific configuration, controlled by which device
  * controller driver was configured.
  *
@@ -110,11 +115,6 @@ static const char loopback [] = "loop in
  * DRIVER_VERSION_NUM ... alerts the host side driver to differences
  * EP_*_NAME ... which endpoints do we use for which purpose?
  * EP_*_NUM ... numbers for them (often limited by hardware)
- * HIGHSPEED ... define if ep0 and descriptors need high speed support
- * MAX_USB_POWER ... define if we use other than 100 mA bus current
- * SELFPOWER ... if we can run on bus power, zero
- * WAKEUP ... if hardware supports remote wakeup AND we will issue the
- * 	usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP
  *
  * add other defines for other portability issues, like hardware that
  * for some reason doesn't handle full speed bulk maxpacket of 64.
@@ -138,9 +138,6 @@ static const char EP_OUT_NAME [] = "ep-a
 #define EP_OUT_NUM	2
 static const char EP_IN_NAME [] = "ep-b";
 #define EP_IN_NUM	2
-#define HIGHSPEED
-/* specific hardware configs could be bus-powered */
-/* supports remote wakeup, but this driver doesn't */
 #endif
 
 /*
@@ -161,8 +158,6 @@ static const char EP_OUT_NAME [] = "ep12
 #define EP_OUT_NUM	12
 static const char EP_IN_NAME [] = "ep11in-bulk";
 #define EP_IN_NUM	11
-/* doesn't support bus-powered operation */
-/* supports remote wakeup, but this driver doesn't */
 #endif
 
 /*
@@ -183,8 +178,6 @@ static const char EP_OUT_NAME [] = "ep1o
 #define EP_OUT_NUM	1
 static const char EP_IN_NAME [] = "ep2in-bulk";
 #define EP_IN_NUM	2
-/* doesn't support bus-powered operation */
-/* doesn't support remote wakeup? */
 #endif
 
 /*
@@ -199,7 +192,6 @@ static const char EP_OUT_NAME [] = "ep1-
 #define EP_OUT_NUM	1
 static const char EP_IN_NAME [] = "ep2-bulk";
 #define EP_IN_NUM	2
-/* doesn't support remote wakeup */
 #endif
 
 /*-------------------------------------------------------------------------*/
@@ -208,30 +200,6 @@ static const char EP_IN_NAME [] = "ep2-b
 #	error Configure some USB peripheral controller driver!
 #endif
 
-/* power usage is config specific.
- * hardware that supports remote wakeup defaults to disabling it.
- */
-
-#ifndef	SELFPOWER
-/* default: say we're self-powered */
-#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
-/* else:
- * - SELFPOWER value must be zero
- * - MAX_USB_POWER may be nonzero.
- */
-#endif
-
-#ifndef	MAX_USB_POWER
-/* any hub supports this steady state bus power consumption */
-#define MAX_USB_POWER	100	/* mA */
-#endif
-
-#ifndef	WAKEUP
-/* default: this driver won't do remote wakeup */
-#define WAKEUP		0
-/* else value must be USB_CONFIG_ATT_WAKEUP */
-#endif
-
 /*-------------------------------------------------------------------------*/
 
 /* big enough to hold our biggest descriptor */
@@ -290,8 +258,8 @@ module_param (pattern, uint, S_IRUGO|S_I
 /*
  * Normally the "loopback" configuration is second (index 1) so
  * it's not the default.  Here's where to change that order, to
- * work better with hosts (like Linux ... for now!) where config
- * changes are problematic.
+ * work better with hosts where config changes are problematic.
+ * Or controllers (like superh) that only support one config.
  */
 static int loopdefault = 0;
 
@@ -301,7 +269,7 @@ module_param (loopdefault, bool, S_IRUGO
 
 /* Thanks to NetChip Technologies for donating this product ID.
  *
- * DO NOT REUSE THESE IDs with any other driver!!  Ever!!
+ * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
  * Instead:  allocate your own, using normal USB-IF procedures.
  */
 #define DRIVER_VENDOR_NUM	0x0525		/* NetChip */
@@ -353,8 +321,8 @@ source_sink_config = {
 	.bNumInterfaces =	1,
 	.bConfigurationValue =	CONFIG_SOURCE_SINK,
 	.iConfiguration =	STRING_SOURCE_SINK,
-	.bmAttributes =		USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP,
-	.bMaxPower =		(MAX_USB_POWER + 1) / 2,
+	.bmAttributes =		USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+	.bMaxPower =		1,	/* self-powered */
 };
 
 static const struct usb_config_descriptor
@@ -366,8 +334,8 @@ loopback_config = {
 	.bNumInterfaces =	1,
 	.bConfigurationValue =	CONFIG_LOOPBACK,
 	.iConfiguration =	STRING_LOOPBACK,
-	.bmAttributes =		USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP,
-	.bMaxPower =		(MAX_USB_POWER + 1) / 2,
+	.bmAttributes =		USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+	.bMaxPower =		1,	/* self-powered */
 };
 
 /* one interface in each configuration */
@@ -414,7 +382,21 @@ fs_sink_desc = {
 	.wMaxPacketSize =	__constant_cpu_to_le16 (64),
 };
 
-#ifdef	HIGHSPEED
+static const struct usb_descriptor_header *fs_source_sink_function [] = {
+	(struct usb_descriptor_header *) &source_sink_intf,
+	(struct usb_descriptor_header *) &fs_sink_desc,
+	(struct usb_descriptor_header *) &fs_source_desc,
+	0,
+};
+
+static const struct usb_descriptor_header *fs_loopback_function [] = {
+	(struct usb_descriptor_header *) &loopback_intf,
+	(struct usb_descriptor_header *) &fs_sink_desc,
+	(struct usb_descriptor_header *) &fs_source_desc,
+	0,
+};
+
+#ifdef	CONFIG_USB_GADGET_DUALSPEED
 
 /*
  * usb 2.0 devices need to expose both high speed and full speed
@@ -425,22 +407,20 @@ fs_sink_desc = {
  * for the config descriptor.
  */
 
-static const struct usb_endpoint_descriptor
+static struct usb_endpoint_descriptor
 hs_source_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
-	.bEndpointAddress =	EP_IN_NUM | USB_DIR_IN,
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 	.wMaxPacketSize =	__constant_cpu_to_le16 (512),
 };
 
-static const struct usb_endpoint_descriptor
+static struct usb_endpoint_descriptor
 hs_sink_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
-	.bEndpointAddress =	EP_OUT_NUM,
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 	.wMaxPacketSize =	__constant_cpu_to_le16 (512),
 };
@@ -456,6 +436,20 @@ dev_qualifier = {
 	.bNumConfigurations =	2,
 };
 
+static const struct usb_descriptor_header *hs_source_sink_function [] = {
+	(struct usb_descriptor_header *) &source_sink_intf,
+	(struct usb_descriptor_header *) &hs_source_desc,
+	(struct usb_descriptor_header *) &hs_sink_desc,
+	0,
+};
+
+static const struct usb_descriptor_header *hs_loopback_function [] = {
+	(struct usb_descriptor_header *) &loopback_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))
 
@@ -464,13 +458,14 @@ dev_qualifier = {
 /* if there's no high speed support, maxpacket doesn't change. */
 #define ep_desc(g,hs,fs) fs
 
-#endif	/* !HIGHSPEED */
+#endif	/* !CONFIG_USB_GADGET_DUALSPEED */
 
+static char				manufacturer [40];
 static char				serial [40];
 
 /* static strings, in iso 8859/1 */
 static struct usb_string		strings [] = {
-	{ STRING_MANUFACTURER, UTS_SYSNAME " " UTS_RELEASE " with " CHIP, },
+	{ STRING_MANUFACTURER, manufacturer, },
 	{ STRING_PRODUCT, longname, },
 	{ STRING_SERIAL, serial, },
 	{ STRING_LOOPBACK, loopback, },
@@ -502,60 +497,42 @@ static struct usb_gadget_strings	stringt
  * device?)
  */
 static int
-config_buf (enum usb_device_speed speed,
+config_buf (struct usb_gadget *gadget,
 		u8 *buf, u8 type, unsigned index)
 {
-	int		is_source_sink;
-	const unsigned	config_len = USB_DT_CONFIG_SIZE
-				+ USB_DT_INTERFACE_SIZE
-				+ 2 * USB_DT_ENDPOINT_SIZE;
-#ifdef HIGHSPEED
-	int		hs;
+	int				is_source_sink;
+	int				len;
+	const struct usb_descriptor_header **function;
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+	int				hs = (gadget->speed == USB_SPEED_HIGH);
 #endif
+
 	/* two configurations will always be index 0 and index 1 */
 	if (index > 1)
 		return -EINVAL;
-	if (config_len > USB_BUFSIZ)
-		return -EDOM;
 	is_source_sink = loopdefault ? (index == 1) : (index == 0);
 
-	/* config (or other speed config) */
-	if (is_source_sink)
-		memcpy (buf, &source_sink_config, USB_DT_CONFIG_SIZE);
-	else
-		memcpy (buf, &loopback_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;
-
-	/* one interface */
-	if (is_source_sink)
-		memcpy (buf, &source_sink_intf, USB_DT_INTERFACE_SIZE);
-	else
-		memcpy (buf, &loopback_intf, USB_DT_INTERFACE_SIZE);
-	buf += USB_DT_INTERFACE_SIZE;
-
-	/* the endpoints in that interface (at that speed) */
-#ifdef HIGHSPEED
-	hs = (speed == USB_SPEED_HIGH);
+#ifdef CONFIG_USB_GADGET_DUALSPEED
 	if (type == USB_DT_OTHER_SPEED_CONFIG)
 		hs = !hs;
-	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
+	if (hs)
+		function = is_source_sink
+			? hs_source_sink_function
+			: hs_loopback_function;
+	else
 #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;
+		function = is_source_sink
+			? fs_source_sink_function
+			: fs_loopback_function;
+
+	len = usb_gadget_config_buf (is_source_sink
+					? &source_sink_config
+					: &loopback_config,
+			buf, USB_BUFSIZ, function);
+	if (len < 0)
+		return len;
+	((struct usb_config_descriptor *) buf)->bDescriptorType = type;
+	return len;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1019,17 +996,21 @@ zero_setup (struct usb_gadget *gadget, c
 			value = min (ctrl->wLength, (u16) sizeof device_desc);
 			memcpy (req->buf, &device_desc, value);
 			break;
-#ifdef HIGHSPEED
+#ifdef CONFIG_USB_GADGET_DUALSPEED
 		case USB_DT_DEVICE_QUALIFIER:
+			if (!gadget->is_dualspeed)
+				break;
 			value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
 			memcpy (req->buf, &dev_qualifier, value);
 			break;
 
 		case USB_DT_OTHER_SPEED_CONFIG:
+			if (!gadget->is_dualspeed)
+				break;
 			// FALLTHROUGH
-#endif /* HIGHSPEED */
+#endif /* CONFIG_USB_GADGET_DUALSPEED */
 		case USB_DT_CONFIG:
-			value = config_buf (gadget->speed, req->buf,
+			value = config_buf (gadget, req->buf,
 					ctrl->wValue >> 8,
 					ctrl->wValue & 0xff);
 			if (value >= 0)
@@ -1212,14 +1193,26 @@ zero_bind (struct usb_gadget *gadget)
 	dev->req->complete = zero_setup_complete;
 
 	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
-#ifdef HIGHSPEED
+
+#ifdef CONFIG_USB_GADGET_DUALSPEED
 	/* assume ep0 uses the same value for both speeds ... */
 	dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+
+	/* and that all endpoints are dual-speed */
+	hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
+	hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
 #endif
 
 	gadget->ep0->driver_data = dev;
 
 	INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
+	INFO (dev, "using %s, OUT %s IN %s\n", gadget->name,
+		EP_OUT_NAME, EP_IN_NAME);
+
+	snprintf (manufacturer, sizeof manufacturer,
+		UTS_SYSNAME " " UTS_RELEASE " with %s",
+		gadget->name);
+
 	return 0;
 
 enomem:
@@ -1230,7 +1223,7 @@ enomem:
 /*-------------------------------------------------------------------------*/
 
 static struct usb_gadget_driver zero_driver = {
-#ifdef HIGHSPEED
+#ifdef CONFIG_USB_GADGET_DUALSPEED
 	.speed		= USB_SPEED_HIGH,
 #else
 	.speed		= USB_SPEED_FULL,
--- diff/drivers/usb/host/Kconfig	2003-09-30 14:46:17.000000000 +0000
+++ source/drivers/usb/host/Kconfig	2004-03-16 09:37:57.491800088 +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-11 10:20:27.000000000 +0000
+++ source/drivers/usb/host/ehci-dbg.c	2004-03-16 09:37:57.492799936 +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-11 10:20:27.000000000 +0000
+++ source/drivers/usb/host/ehci-hcd.c	2004-03-16 09:37:57.493799784 +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-11 10:20:27.000000000 +0000
+++ source/drivers/usb/host/ehci-sched.c	2004-03-16 09:37:57.496799328 +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-11 10:20:27.000000000 +0000
+++ source/drivers/usb/host/ehci.h	2004-03-16 09:37:57.497799176 +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-11 10:20:27.000000000 +0000
+++ source/drivers/usb/host/uhci-hcd.c	2004-03-16 09:37:57.500798720 +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);
 }
 
@@ -2458,9 +2444,11 @@ static int uhci_suspend(struct usb_hcd *
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 
 	/* Don't try to suspend broken motherboards, reset instead */
-	if (suspend_allowed(uhci))
+	if (suspend_allowed(uhci)) {
 		suspend_hc(uhci);
-	else
+		uhci->saved_framenumber =
+				inw(uhci->io_addr + USBFRNUM) & 0x3ff;
+	} else
 		reset_hc(uhci);
 	return 0;
 }
@@ -2471,9 +2459,20 @@ 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 don't maintain the UHCI register values
+		 * during a PM suspend/resume cycle, so reinitialize
+		 * the Frame Number, the Framelist Base Address, and the
+		 * Interrupt Enable registers.
+		 */
+		outw(uhci->saved_framenumber, uhci->io_addr + USBFRNUM);
+		outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);
+		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-11 10:20:27.000000000 +0000
+++ source/drivers/usb/host/uhci-hcd.h	2004-03-16 09:37:57.500798720 +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 */
 
 /*
@@ -350,6 +350,7 @@ struct uhci_hcd {
 	enum uhci_state state;			/* FIXME: needs a spinlock */
 	unsigned long state_end;		/* Time of next transition */
 	int resume_detect;			/* Need a Global Resume */
+	unsigned int saved_framenumber;		/* Save during PM suspend */
 
 	/* Main list of URB's currently controlled by this HC */
 	spinlock_t urb_list_lock;
--- diff/drivers/usb/image/hpusbscsi.c	2003-08-20 13:16:13.000000000 +0000
+++ source/drivers/usb/image/hpusbscsi.c	2004-03-16 09:37:57.501798568 +0000
@@ -42,7 +42,7 @@ hpusbscsi_usb_probe(struct usb_interface
 		    const struct usb_device_id *id)
 {
 	struct usb_device *dev = interface_to_usbdev(intf);
-	struct usb_host_interface *altsetting =	intf->altsetting;
+	struct usb_host_interface *altsetting =	intf->cur_altsetting;
 	struct hpusbscsi *new;
 	int error = -ENOMEM;
 	int i;
--- diff/drivers/usb/image/mdc800.c	2003-09-17 11:28:10.000000000 +0000
+++ source/drivers/usb/image/mdc800.c	2004-03-16 09:37:57.502798416 +0000
@@ -431,7 +431,7 @@ static int mdc800_usb_probe (struct usb_
 		err ("probe fails -> wrong Number of Configuration");
 		return -ENODEV;
 	}
-	intf_desc = &intf->altsetting[0];
+	intf_desc = intf->cur_altsetting;
 
 	if (
 			( intf_desc->desc.bInterfaceClass != 0xff )
@@ -469,13 +469,6 @@ static int mdc800_usb_probe (struct usb_
 	}
 
 
-	usb_driver_claim_interface (&mdc800_usb_driver, intf, mdc800);
-	if (usb_set_interface (dev, intf_desc->desc.bInterfaceNumber, 0) < 0)
-	{
-		err ("MDC800 Configuration fails.");
-		return -ENODEV;
-	}
-
 	info ("Found Mustek MDC800 on USB.");
 
 	down (&mdc800->io_lock);
@@ -551,8 +544,6 @@ static void mdc800_usb_disconnect (struc
 		usb_unlink_urb (mdc800->write_urb);
 		usb_unlink_urb (mdc800->download_urb);
 
-		usb_driver_release_interface (&mdc800_usb_driver, intf);
-
 		mdc800->dev=0;
 		usb_set_intfdata(intf, NULL);
 	}
--- diff/drivers/usb/image/microtek.c	2003-08-20 13:16:13.000000000 +0000
+++ source/drivers/usb/image/microtek.c	2004-03-16 09:37:57.502798416 +0000
@@ -693,7 +693,6 @@ static int mts_usb_probe(struct usb_inte
 			 const struct usb_device_id *id)
 {
 	int i;
-	int result;
 	int ep_out = -1;
 	int ep_in_set[3]; /* this will break if we have more than three endpoints
 			   which is why we check */
@@ -703,7 +702,7 @@ static int mts_usb_probe(struct usb_inte
 	struct vendor_product const* p;
 	struct usb_device *dev = interface_to_usbdev (intf);
 
-	/* the altsettting 0 on the interface we're probing */
+	/* the current altsetting on the interface we're probing */
 	struct usb_host_interface *altsetting;
 
 	MTS_DEBUG_GOT_HERE();
@@ -724,8 +723,8 @@ static int mts_usb_probe(struct usb_inte
 		MTS_MESSAGE( "model %s is not known to be fully supported, reports welcome!\n",
 			     p->name );
 
-	/* the altsettting 0 on the interface we're probing */
-	altsetting = &(intf->altsetting[0]);
+	/* the current altsetting on the interface we're probing */
+	altsetting = intf->cur_altsetting;
 
 
 	/* Check if the config is sane */
@@ -766,20 +765,6 @@ static int mts_usb_probe(struct usb_inte
 		MTS_WARNING( "couldn't find an output bulk endpoint. Bailing out.\n" );
 		return -ENODEV;
 	}
-
-	result = usb_set_interface(dev, altsetting->desc.bInterfaceNumber, 0);
-
-	MTS_DEBUG("usb_set_interface returned %d.\n",result);
-	switch( result )
-	{
-	case 0: /* no error */
-		break;
-
-	default:
-		MTS_DEBUG( "unknown error %d from usb_set_interface\n",
-			(int)result );
- 		return -ENODEV;
-	}
 	
 	
 	new_desc = kmalloc(sizeof(struct mts_desc), GFP_KERNEL);
--- diff/drivers/usb/input/Kconfig	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/input/Kconfig	2004-03-16 09:37:57.503798264 +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 10:49:46.000000000 +0000
+++ source/drivers/usb/input/Makefile	2004-03-16 09:37:57.503798264 +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/aiptek.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/input/aiptek.c	2004-03-16 09:37:57.504798112 +0000
@@ -43,7 +43,8 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/usb.h>
-
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
 /*
  * Version Information
  */
@@ -160,9 +161,9 @@ aiptek_irq(struct urb *urb, struct pt_re
 	proximity = data[5] & 0x01;
 	input_report_key(dev, BTN_TOOL_PEN, proximity);
 
-	x = ((__u32) data[1]) | ((__u32) data[2] << 8);
-	y = ((__u32) data[3]) | ((__u32) data[4] << 8);
-	pressure = ((__u32) data[6]) | ((__u32) data[7] << 8);
+	x = le16_to_cpu(get_unaligned((u16 *) &data[1]));
+	y = le16_to_cpu(get_unaligned((u16 *) &data[3]));
+	pressure = le16_to_cpu(*(u16 *) &data[6]);
 	pressure -= aiptek->features->pressure_min;
 
 	if (pressure < 0) {
@@ -209,8 +210,10 @@ aiptek_open(struct input_dev *dev)
 		return 0;
 
 	aiptek->irq->dev = aiptek->usbdev;
-	if (usb_submit_urb(aiptek->irq, GFP_KERNEL))
+	if (usb_submit_urb(aiptek->irq, GFP_KERNEL)) {
+		aiptek->open--;
 		return -EIO;
+	}
 
 	return 0;
 }
@@ -234,19 +237,27 @@ usb_set_report(struct usb_device *dev, s
 		(type << 8) + id, inter->desc.bInterfaceNumber, buf, size, HZ);
 }
 
-static void
+static int
 aiptek_command(struct usb_device *dev, struct usb_host_interface *inter,
 	       unsigned char command, unsigned char data)
 {
-	__u8 buf[3];
+	u8 *buf;
+	int err;
+	
+	buf = kmalloc(3, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
 
 	buf[0] = 4;
 	buf[1] = command;
 	buf[2] = data;
 
-	if (usb_set_report(dev, inter, 3, 2, buf, 3) != 3) {
+	if ((err = usb_set_report(dev, inter, 3, 2, buf, 3)) != 3) {
 		dbg("aiptek_command: 0x%x 0x%x\n", command, data);
 	}
+	
+	kfree(buf);
+	return err < 0 ? err : 0;
 }
 
 static int 
@@ -257,30 +268,32 @@ aiptek_probe(struct usb_interface *intf,
 	struct usb_host_interface *interface = intf->altsetting + 0;
 	struct usb_endpoint_descriptor *endpoint;
 	struct aiptek *aiptek;
+	int err = -ENOMEM;
 
 	if (!(aiptek = kmalloc(sizeof (struct aiptek), GFP_KERNEL)))
-		return -ENOMEM;
+		goto error_out_noalloc;
 
 	memset(aiptek, 0, sizeof (struct aiptek));
 
-	aiptek->data = usb_buffer_alloc(dev, 10, SLAB_ATOMIC, &aiptek->data_dma);
+	aiptek->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &aiptek->data_dma);
 	if (!aiptek->data) {
-		kfree(aiptek);
-		return -ENOMEM;
+		goto error_out_nobuf;
 	}
 
 	aiptek->irq = usb_alloc_urb(0, GFP_KERNEL);
 	if (!aiptek->irq) {
-		usb_buffer_free(dev, 10, aiptek->data, aiptek->data_dma);
-		kfree(aiptek);
-		return -ENOMEM;
+		goto error_out_nourb;
 	}
 
 	/* Resolution500LPI */
-	aiptek_command(dev, interface, 0x18, 0x04);
+	err = aiptek_command(dev, interface, 0x18, 0x04);
+	if (err)
+		goto error_out;
 
 	/* SwitchToTablet */
-	aiptek_command(dev, interface, 0x10, 0x01);
+	err = aiptek_command(dev, interface, 0x10, 0x01);
+	if (err)
+		goto error_out;
 
 	aiptek->features = aiptek_features + id->driver_info;
 
@@ -340,6 +353,16 @@ aiptek_probe(struct usb_interface *intf,
 
 	usb_set_intfdata(intf, aiptek);
 	return 0;
+
+error_out:
+	usb_free_urb(aiptek->irq);
+error_out_nourb:
+	usb_buffer_free(dev, 10, aiptek->data, aiptek->data_dma);
+error_out_nobuf:
+	kfree(aiptek);
+error_out_noalloc:
+	return err;
+	
 }
 
 static void
--- diff/drivers/usb/input/hid-core.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/input/hid-core.c	2004-03-16 09:37:57.514796592 +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;
@@ -1069,24 +1076,41 @@ static int hid_submit_ctrl(struct hid_de
 {
 	struct hid_report *report;
 	unsigned char dir;
+	int len;
 
 	report = hid->ctrl[hid->ctrltail].report;
 	dir = hid->ctrl[hid->ctrltail].dir;
 
-	if (dir == USB_DIR_OUT)
+	len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
+	if (dir == USB_DIR_OUT) {
 		hid_output_report(report, hid->ctrlbuf);
-
-	hid->urbctrl->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
-	hid->urbctrl->pipe = (dir == USB_DIR_OUT) ?  usb_sndctrlpipe(hid->dev, 0) : usb_rcvctrlpipe(hid->dev, 0);
+		hid->urbctrl->pipe = usb_sndctrlpipe(hid->dev, 0);
+		hid->urbctrl->transfer_buffer_length = len;
+	} else {
+		int maxpacket, padlen;
+
+		hid->urbctrl->pipe = usb_rcvctrlpipe(hid->dev, 0);
+		maxpacket = usb_maxpacket(hid->dev, hid->urbctrl->pipe, 0);
+		if (maxpacket > 0) {
+			padlen = (len + maxpacket - 1) / maxpacket;
+			padlen *= maxpacket;
+			if (padlen > HID_BUFFER_SIZE)
+				padlen = HID_BUFFER_SIZE;
+		} else
+			padlen = 0;
+		hid->urbctrl->transfer_buffer_length = padlen;
+	}
 	hid->urbctrl->dev = hid->dev;
 
 	hid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir;
 	hid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT;
 	hid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id);
 	hid->cr->wIndex = cpu_to_le16(hid->ifnum);
-	hid->cr->wLength = cpu_to_le16(hid->urbctrl->transfer_buffer_length);
+	hid->cr->wLength = cpu_to_le16(len);
 
-	dbg("submitting ctrl urb");
+	dbg("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u",
+	    hid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report",
+	    hid->cr->wValue, hid->cr->wIndex, hid->cr->wLength);
 
 	if (usb_submit_urb(hid->urbctrl, GFP_ATOMIC)) {
 		err("usb_submit_urb(ctrl) failed");
@@ -1262,9 +1286,25 @@ void hid_init_reports(struct hid_device 
 	struct hid_report_enum *report_enum;
 	struct hid_report *report;
 	struct list_head *list;
-	int len;
 	int err, ret;
 
+	/*
+	 * The Set_Idle request is supposed to affect only the
+	 * "Interrupt In" pipe. Unfortunately, buggy devices such as
+	 * the BTC keyboard (ID 046e:5303) the request also affects
+	 * Get_Report requests on the control pipe.  In the worst
+	 * case, if the device was put on idle for an indefinite
+	 * amount of time (as we do below) and there are no input
+	 * events to report, the Get_Report requests will just hang
+	 * until we get a USB timeout.  To avoid this, we temporarily
+	 * establish a minimal idle time of 1ms.  This shouldn't hurt
+	 * bugfree devices and will cause a worst-case extra delay of
+	 * 1ms for buggy ones.
+	 */
+	usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0),
+			HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (1 << 8),
+			hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+
 	report_enum = hid->report_enum + HID_INPUT_REPORT;
 	list = report_enum->report_list.next;
 	while (list != &report_enum->report_list) {
@@ -1297,11 +1337,8 @@ void hid_init_reports(struct hid_device 
 	list = report_enum->report_list.next;
 	while (list != &report_enum->report_list) {
 		report = (struct hid_report *) list;
-		len = ((report->size - 1) >> 3) + 1 + report_enum->numbered;
-		if (len > hid->urbin->transfer_buffer_length)
-			hid->urbin->transfer_buffer_length = len < HID_BUFFER_SIZE ? len : HID_BUFFER_SIZE;
 		usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0),
-			0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE, report->id,
+			HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, report->id,
 			hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
 		list = list->next;
 	}
@@ -1313,11 +1350,12 @@ void hid_init_reports(struct hid_device 
 #define USB_DEVICE_ID_WACOM_INTUOS	0x0020
 #define USB_DEVICE_ID_WACOM_PL		0x0030
 #define USB_DEVICE_ID_WACOM_INTUOS2	0x0040
+#define USB_DEVICE_ID_WACOM_VOLITO      0x0060
+#define USB_DEVICE_ID_WACOM_PTU         0x0003
 
 #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,22 +1394,52 @@ 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
+
+#define USB_VENDOR_ID_CHIC		0x05fe
+#define USB_DEVICE_ID_CHIC_GAMEPAD	0x0014
+
 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 },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 2, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 3, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 4, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2, HID_QUIRK_IGNORE },
@@ -1383,37 +1451,34 @@ struct hid_blacklist {
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 3, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 4, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 5, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 1, HID_QUIRK_IGNORE },
 	{ 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_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 5, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 7, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PTU, 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_CHIC, USB_DEVICE_ID_CHIC_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 +1510,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;
@@ -1518,12 +1583,17 @@ static struct hid_device *usb_hid_config
 			continue;
 
 		if (endpoint->bEndpointAddress & USB_DIR_IN) {
+			int len;
+
 			if (hid->urbin)
 				continue;
 			if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL)))
 				goto fail;
 			pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
-			usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, 0,
+			len = usb_maxpacket(dev, pipe, 0);
+			if (len > HID_BUFFER_SIZE)
+				len = HID_BUFFER_SIZE;
+			usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, len,
 					 hid_irq_in, hid, endpoint->bInterval);
 			hid->urbin->transfer_dma = hid->inbuf_dma;
 			hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
--- diff/drivers/usb/input/hid-ff.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/input/hid-ff.c	2004-03-16 09:37:57.514796592 +0000
@@ -29,7 +29,7 @@
 
 #include <linux/input.h>
 
-#define DEBUG
+#undef DEBUG
 #include <linux/usb.h>
 
 #include "hid.h"
--- diff/drivers/usb/input/hid-input.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/input/hid-input.c	2004-03-16 09:37:57.515796440 +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);
@@ -567,8 +569,10 @@ int hidinput_connect(struct hid_device *
 		while (list != &report_enum->report_list) {
 			report = (struct hid_report *) list;
 
-			if (!report->maxfield)
+			if (!report->maxfield) {
+				list = list->next;
 				continue;
+			}
 
 			if (!hidinput) {
 				hidinput = kmalloc(sizeof(*hidinput), GFP_KERNEL);
--- diff/drivers/usb/input/hid.h	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/input/hid.h	2004-03-16 09:37:57.516796288 +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
@@ -309,7 +310,7 @@ struct hid_report_enum {
 
 #define HID_REPORT_TYPES 3
 
-#define HID_BUFFER_SIZE		32
+#define HID_BUFFER_SIZE		64		/* use 64 for compatibility with all possible packetlen */
 #define HID_CONTROL_FIFO_SIZE	256		/* to init devices with >100 reports */
 #define HID_OUTPUT_FIFO_SIZE	64
 
--- diff/drivers/usb/input/hiddev.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/input/hiddev.c	2004-03-16 09:37:57.524795072 +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-16 09:37:57.524795072 +0000
@@ -4,6 +4,8 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/usb.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
 
 /*
  * Version Information
@@ -65,8 +67,8 @@ static void kbtab_irq(struct urb *urb, s
 		goto exit;
 	}
 
-	kbtab->x = (data[2] << 8) + data[1];
-	kbtab->y = (data[4] << 8) + data[3];
+	kbtab->x = le16_to_cpu(get_unaligned((u16 *) &data[1]));
+	kbtab->y = le16_to_cpu(get_unaligned((u16 *) &data[3]));
 
 	kbtab->pressure = (data[5]);
 
@@ -74,12 +76,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);
 
@@ -105,8 +110,10 @@ static int kbtab_open(struct input_dev *
 		return 0;
 
 	kbtab->irq->dev = kbtab->usbdev;
-	if (usb_submit_urb(kbtab->irq, GFP_KERNEL))
+	if (usb_submit_urb(kbtab->irq, GFP_KERNEL)) {
+		kbtab->open--;
 		return -EIO;
+	}
 
 	return 0;
 }
@@ -130,7 +137,7 @@ static int kbtab_probe(struct usb_interf
 		return -ENOMEM;
 	memset(kbtab, 0, sizeof(struct kbtab));
 
-	kbtab->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &kbtab->data_dma);
+	kbtab->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &kbtab->data_dma);
 	if (!kbtab->data) {
 		kfree(kbtab);
 		return -ENOMEM;
--- diff/drivers/usb/input/pid.c	2003-06-30 09:07:23.000000000 +0000
+++ source/drivers/usb/input/pid.c	2004-03-16 09:37:57.525794920 +0000
@@ -200,6 +200,7 @@ static int hid_pid_upload_effect(struct 
 			    break;
 
 		if ( id == FF_EFFECTS_MAX) {
+			spin_unlock_irqrestore(&pid_private->lock,flags);
 // TEMP - We need to get ff_effects_max correctly first:  || id >= dev->ff_effects_max) {
 			dev_dbg(&pid_private->hid->dev->dev, "Not enough device memory\n");
 			return -ENOMEM;
--- diff/drivers/usb/input/usbkbd.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/input/usbkbd.c	2004-03-16 09:37:57.526794768 +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-16 09:37:57.527794616 +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-16 09:37:57.529794312 +0000
@@ -1,14 +1,15 @@
 /*
  *  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>
  *  Copyright (c) 2000 James E. Blair		<corvus@gnu.org>
  *  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>
+ *  Copyright (c) 2002-2004 Ping Cheng		<pingc@wacom.com>
  *
  *  ChangeLog:
  *      v0.1 (vp)  - Initial release
@@ -48,6 +49,8 @@
  *	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
+ *	v1.40 (pc) - Add support for several new devices, fix eraser reporting, ...
  */
 
 /*
@@ -63,6 +66,8 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/usb.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
 
 /*
  * Version Information
@@ -106,7 +111,7 @@ struct wacom {
 static int usb_set_report(struct usb_interface *intf, unsigned char type,
 				unsigned char id, void *buf, int size)
 {
-        return usb_control_msg(interface_to_usbdev(intf),
+	return usb_control_msg(interface_to_usbdev(intf),
 		usb_sndctrlpipe(interface_to_usbdev(intf), 0),
                 USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
                 (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
@@ -137,14 +142,12 @@ static void wacom_pl_irq(struct urb *urb
 	}
 
 	if (data[0] != 2)
-		dbg("received unknown report #%d", data[0]);
+		dbg("wacom_pl_irq: received unknown report #%d", data[0]);
 
 	prox = data[1] & 0x40;
 
 	input_regs(dev, regs);
 	
-	input_report_key(dev, BTN_TOOL_PEN, prox);
-	
 	if (prox) {
 
 		pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
@@ -152,15 +155,103 @@ static void wacom_pl_irq(struct urb *urb
 			pressure = (pressure << 1) | ((data[4] >> 6) & 1);
 		pressure += (wacom->features->pressure_max + 1) / 2;
 
+		/*
+		 * if going from out of proximity into proximity select between the eraser
+		 * and the pen based on the state of the stylus2 button, choose eraser if
+		 * pressed else choose pen. if not a proximity change from out to in, send
+		 * an out of proximity for previous tool then a in for new tool.
+		 */
+		if (!wacom->tool[0]) {
+			/* Going into proximity select tool */
+			wacom->tool[1] = (data[4] & 0x20)? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+		}
+		else {
+			/* was entered with stylus2 pressed */
+			if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20) ) {
+				/* report out proximity for previous tool */
+				input_report_key(dev, wacom->tool[1], 0);
+				input_sync(dev);
+				wacom->tool[1] = BTN_TOOL_PEN;
+				goto exit;
+			}
+		}
+		if (wacom->tool[1] != BTN_TOOL_RUBBER) {
+			/* Unknown tool selected default to pen tool */
+			wacom->tool[1] = BTN_TOOL_PEN;
+		}
+		input_report_key(dev, wacom->tool[1], prox); /* report in proximity for tool */
 		input_report_abs(dev, ABS_X, data[3] | ((__u32)data[2] << 7) | ((__u32)(data[1] & 0x03) << 14));
 		input_report_abs(dev, ABS_Y, data[6] | ((__u32)data[5] << 7) | ((__u32)(data[4] & 0x03) << 14));
 		input_report_abs(dev, ABS_PRESSURE, pressure);
 
 		input_report_key(dev, BTN_TOUCH, data[4] & 0x08);
 		input_report_key(dev, BTN_STYLUS, data[4] & 0x10);
-		input_report_key(dev, BTN_STYLUS2, data[4] & 0x20);
+		/* Only allow the stylus2 button to be reported for the pen tool. */
+		input_report_key(dev, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20));
 	}
-	
+	else {
+		/* report proximity-out of a (valid) tool */
+		if (wacom->tool[1] != BTN_TOOL_RUBBER) {
+			/* Unknown tool selected default to pen tool */
+			wacom->tool[1] = BTN_TOOL_PEN;
+		}
+		input_report_key(dev, wacom->tool[1], prox);
+	}
+
+	wacom->tool[0] = prox; /* Save proximity state */
+	input_sync(dev);
+
+exit:
+	retval = usb_submit_urb (urb, GFP_ATOMIC);
+	if (retval)
+		err ("%s - usb_submit_urb failed with result %d",
+		     __FUNCTION__, retval);
+}
+
+static void wacom_ptu_irq(struct urb *urb, struct pt_regs *regs)
+{
+	struct wacom *wacom = urb->context;
+	unsigned char *data = wacom->data;
+	struct input_dev *dev = &wacom->dev;
+	int retval;
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	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;
+	}
+
+	if (data[0] != 2)
+	{
+		printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
+	}
+
+	input_regs(dev, regs);
+	if (data[1] & 0x04)
+	{
+		input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x20);
+		input_report_key(dev, BTN_TOUCH, data[1] & 0x08);
+	}
+	else
+	{
+		input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x20);
+		input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
+	}
+	input_report_abs(dev, ABS_X, data[3] << 8 | data[2]);
+	input_report_abs(dev, ABS_Y, data[5] << 8 | data[4]);
+	input_report_abs(dev, ABS_PRESSURE, (data[6]|data[7] << 8));
+	input_report_key(dev, BTN_STYLUS, data[1] & 0x02);
+	input_report_key(dev, BTN_STYLUS2, data[1] & 0x10);
+
 	input_sync(dev);
 
 exit:
@@ -194,8 +285,8 @@ static void wacom_penpartner_irq(struct 
 
 	input_regs(dev, regs);
 	input_report_key(dev, BTN_TOOL_PEN, 1);
-	input_report_abs(dev, ABS_X, data[2] << 8 | data[1]);
-	input_report_abs(dev, ABS_Y, data[4] << 8 | data[3]);
+	input_report_abs(dev, ABS_X, le16_to_cpu(get_unaligned((u16 *) &data[1])));
+	input_report_abs(dev, ABS_Y, le16_to_cpu(get_unaligned((u16 *) &data[3])));
 	input_report_abs(dev, ABS_PRESSURE, (signed char)data[6] + 127);
 	input_report_key(dev, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20));
 	input_report_key(dev, BTN_STYLUS, (data[5] & 0x40));
@@ -231,11 +322,15 @@ static void wacom_graphire_irq(struct ur
 		goto exit;
 	}
 
+	/* check if we can handle the data */
+	if (data[0] == 99)
+		goto exit;
+
 	if (data[0] != 2)
-		dbg("received unknown report #%d", data[0]);
+		dbg("wacom_graphire_irq: received unknown report #%d", data[0]);
 
-	x = data[2] | ((__u32)data[3] << 8);
-	y = data[4] | ((__u32)data[5] << 8);
+	x = le16_to_cpu(*(u16 *) &data[2]);
+	y = le16_to_cpu(*(u16 *) &data[4]);
 
 	input_regs(dev, regs);
 
@@ -249,13 +344,16 @@ static void wacom_graphire_irq(struct ur
 			input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x80);
 			break;
 
-		case 2: /* Mouse */
+		case 2: /* Mouse with wheel */
+			input_report_key(dev, BTN_MIDDLE, data[1] & 0x04);
+			input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
+			/* fall through */
+
+                case 3: /* Mouse without wheel */
 			input_report_key(dev, BTN_TOOL_MOUSE, data[7] > 24);
 			input_report_key(dev, BTN_LEFT, data[1] & 0x01);
 			input_report_key(dev, BTN_RIGHT, data[1] & 0x02);
-			input_report_key(dev, BTN_MIDDLE, data[1] & 0x04);
 			input_report_abs(dev, ABS_DISTANCE, data[7]);
-			input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
 
 			input_report_abs(dev, ABS_X, x);
 			input_report_abs(dev, ABS_Y, y);
@@ -269,7 +367,7 @@ static void wacom_graphire_irq(struct ur
 		input_report_abs(dev, ABS_Y, y);
 	}
 
-	input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
+	input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(u16 *) &data[6]));
 	input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
 	input_report_key(dev, BTN_STYLUS, data[1] & 0x02);
 	input_report_key(dev, BTN_STYLUS2, data[1] & 0x04);
@@ -308,7 +406,7 @@ static void wacom_intuos_irq(struct urb 
 	}
 
 	if (data[0] != 2)
-		dbg("received unknown report #%d", data[0]);
+		dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
 
 	input_regs(dev, regs);
 
@@ -317,18 +415,18 @@ static void wacom_intuos_irq(struct urb 
 
 	if ((data[1] & 0xfc) == 0xc0) {						/* Enter report */
 
-		wacom->serial[idx] = ((__u32)(data[3] & 0x0f) << 4) +		/* serial number of the tool */
-			((__u32)data[4] << 16) + ((__u32)data[5] << 12) +
+		wacom->serial[idx] = ((__u32)(data[3] & 0x0f) << 28) +		/* serial number of the tool */
+			((__u32)data[4] << 20) + ((__u32)data[5] << 12) +
 			((__u32)data[6] << 4) + (data[7] >> 4);
 
 		switch (((__u32)data[2] << 4) | (data[3] >> 4)) {
-			case 0x832:
+			case 0x812:
 			case 0x012: wacom->tool[idx] = BTN_TOOL_PENCIL;		break;	/* Inking pen */
 			case 0x822:
 			case 0x842:
 			case 0x852:
 			case 0x022: wacom->tool[idx] = BTN_TOOL_PEN;		break;	/* Pen */
-			case 0x812:
+			case 0x832:
 			case 0x032: wacom->tool[idx] = BTN_TOOL_BRUSH;		break;	/* Stroke pen */
 			case 0x007:
 		        case 0x09c:
@@ -337,7 +435,10 @@ static void wacom_intuos_irq(struct urb 
 			case 0x82a:
 			case 0x85a:
 		        case 0x91a:
+			case 0xd1a:
 			case 0x0fa: wacom->tool[idx] = BTN_TOOL_RUBBER;		break;	/* Eraser */
+			case 0xd12:
+			case 0x912:
 			case 0x112: wacom->tool[idx] = BTN_TOOL_AIRBRUSH;	break;	/* Airbrush */
 			default:    wacom->tool[idx] = BTN_TOOL_PEN;		break;	/* Unknown tool */
 		}
@@ -350,13 +451,14 @@ static void wacom_intuos_irq(struct urb 
 
 	if ((data[1] & 0xfe) == 0x80) {						/* Exit report */
 		input_report_key(dev, wacom->tool[idx], 0);
+		input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
 		input_sync(dev);
 		goto exit;
 	}
 
-	input_report_abs(dev, ABS_X, ((__u32)data[2] << 8) | data[3]);
-	input_report_abs(dev, ABS_Y, ((__u32)data[4] << 8) | data[5]);
-	input_report_abs(dev, ABS_DISTANCE, data[9] >> 4);
+	input_report_abs(dev, ABS_X, be16_to_cpu(*(u16 *) &data[2]));
+	input_report_abs(dev, ABS_Y, be16_to_cpu(*(u16 *) &data[4]));
+	input_report_abs(dev, ABS_DISTANCE, data[9]);
 
 	if ((data[1] & 0xb8) == 0xa0) {						/* general pen packet */
 		input_report_abs(dev, ABS_PRESSURE, t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
@@ -378,8 +480,8 @@ static void wacom_intuos_irq(struct urb 
 		if (data[1] & 0x02) {						/* Rotation packet */
 
 			input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ?
-					 ((__u32)data[6] << 2) | ((data[7] >> 6) & 3):
-					 (-(((__u32)data[6] << 2) | ((data[7] >> 6) & 3))) - 1);
+					 ((__u32)data[6] << 3) | ((data[7] >> 5) & 7):
+					 (-(((__u32)data[6] << 3) | ((data[7] >> 5) & 7))) - 1);
 
 		} else {
 
@@ -391,17 +493,17 @@ static void wacom_intuos_irq(struct urb 
 
 				input_report_key(dev, BTN_SIDE,   data[8] & 0x20);
 				input_report_key(dev, BTN_EXTRA,  data[8] & 0x10);
-				input_report_abs(dev, ABS_THROTTLE,  (data[8] & 0x08) ?
+				input_report_abs(dev, ABS_THROTTLE,  -((data[8] & 0x08) ?
 						 ((__u32)data[6] << 2) | ((data[7] >> 6) & 3) :
-						 -((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
+						 -((__u32)data[6] << 2) | ((data[7] >> 6) & 3)));
 
 			} else {
 				if (wacom->tool[idx] == BTN_TOOL_MOUSE) {	/* 2D mouse packets */	
 					input_report_key(dev, BTN_LEFT,   data[8] & 0x04);
 					input_report_key(dev, BTN_MIDDLE, data[8] & 0x08);
 					input_report_key(dev, BTN_RIGHT,  data[8] & 0x10);
-					input_report_abs(dev, REL_WHEEL, 
-					    ((__u32)(data[8] & 0x01) - (__u32)((data[8] & 0x02) >> 1)));
+					input_report_rel(dev, REL_WHEEL, 
+					    (-(__u32)(data[8] & 0x01) + (__u32)((data[8] & 0x02) >> 1)));
 				}
 				else {     /* Lens cursor packets */
 					input_report_key(dev, BTN_LEFT,   data[8] & 0x01);
@@ -414,6 +516,8 @@ static void wacom_intuos_irq(struct urb 
 		}
 	}
 	
+	input_report_key(dev, wacom->tool[idx], 1);
+	input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
 	input_sync(dev);
 
 exit:
@@ -429,22 +533,26 @@ struct wacom_features wacom_features[] =
 	{ "Wacom Graphire2 4x5", 8,  10206,  7422,  511, 32, 1, wacom_graphire_irq },
  	{ "Wacom Graphire2 5x7", 8,  13918, 10206,  511, 32, 1, wacom_graphire_irq },
 	{ "Wacom Graphire3",     8,  10208,  7424,  511, 32, 1, wacom_graphire_irq },
-  	{ "Wacom Intuos 4x5",   10,  12700, 10360, 1023, 15, 2, wacom_intuos_irq },
- 	{ "Wacom Intuos 6x8",   10,  20600, 16450, 1023, 15, 2, wacom_intuos_irq },
- 	{ "Wacom Intuos 9x12",  10,  30670, 24130, 1023, 15, 2, wacom_intuos_irq },
- 	{ "Wacom Intuos 12x12", 10,  30670, 31040, 1023, 15, 2, wacom_intuos_irq },
- 	{ "Wacom Intuos 12x18", 10,  45860, 31040, 1023, 15, 2, wacom_intuos_irq },
+	{ "Wacom Graphire3 6x8", 8,  16704, 12064,  511, 32, 1, wacom_graphire_irq },
+  	{ "Wacom Intuos 4x5",   10,  12700, 10600, 1023, 15, 2, wacom_intuos_irq },
+ 	{ "Wacom Intuos 6x8",   10,  20320, 16240, 1023, 15, 2, wacom_intuos_irq },
+ 	{ "Wacom Intuos 9x12",  10,  30480, 24060, 1023, 15, 2, wacom_intuos_irq },
+ 	{ "Wacom Intuos 12x12", 10,  30480, 31680, 1023, 15, 2, wacom_intuos_irq },
+ 	{ "Wacom Intuos 12x18", 10,  45720, 31680, 1023, 15, 2, wacom_intuos_irq },
  	{ "Wacom PL400",         8,   5408,  4056,  255, 32, 3, wacom_pl_irq },
  	{ "Wacom PL500",         8,   6144,  4608,  255, 32, 3, wacom_pl_irq },
  	{ "Wacom PL600",         8,   6126,  4604,  255, 32, 3, wacom_pl_irq },
  	{ "Wacom PL600SX",       8,   6260,  5016,  255, 32, 3, wacom_pl_irq },
  	{ "Wacom PL550",         8,   6144,  4608,  511, 32, 3, wacom_pl_irq },
  	{ "Wacom PL800",         8,   7220,  5780,  511, 32, 3, wacom_pl_irq },
-	{ "Wacom Intuos2 4x5",   10, 12700, 10360, 1023, 15, 2, wacom_intuos_irq },
-	{ "Wacom Intuos2 6x8",   10, 20600, 16450, 1023, 15, 2, wacom_intuos_irq },
-	{ "Wacom Intuos2 9x12",  10, 30670, 24130, 1023, 15, 2, wacom_intuos_irq },
-	{ "Wacom Intuos2 12x12", 10, 30670, 31040, 1023, 15, 2, wacom_intuos_irq },
-	{ "Wacom Intuos2 12x18", 10, 45860, 31040, 1023, 15, 2, wacom_intuos_irq },
+	{ "Wacom Intuos2 4x5",   10, 12700, 10600, 1023, 15, 2, wacom_intuos_irq },
+	{ "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq },
+	{ "Wacom Intuos2 9x12",  10, 30480, 24060, 1023, 15, 2, wacom_intuos_irq },
+	{ "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, 2, wacom_intuos_irq },
+	{ "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, 2, wacom_intuos_irq },
+	{ "Wacom Volito",        8,   5104,  3712,  511, 32, 1, wacom_graphire_irq },
+	{ "Wacom Cintiq Partner",8,  20480, 15360,  511, 32, 3, wacom_ptu_irq },
+	{ "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq },
  	{ }
 };
 
@@ -454,6 +562,7 @@ struct usb_device_id wacom_ids[] = {
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x11) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x12) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x13) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x14) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) },
@@ -470,6 +579,9 @@ struct usb_device_id wacom_ids[] = {
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x43) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x44) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
 	{ }
 };
 
@@ -483,8 +595,10 @@ static int wacom_open(struct input_dev *
 		return 0;
 
 	wacom->irq->dev = wacom->usbdev;
-	if (usb_submit_urb(wacom->irq, GFP_KERNEL))
+	if (usb_submit_urb(wacom->irq, GFP_KERNEL)) {
+		wacom->open--;
 		return -EIO;
+	}
 
 	return 0;
 }
@@ -509,7 +623,7 @@ static int wacom_probe(struct usb_interf
 		return -ENOMEM;
 	memset(wacom, 0, sizeof(struct wacom));
 
-	wacom->data = usb_buffer_alloc(dev, 10, SLAB_ATOMIC, &wacom->data_dma);
+	wacom->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma);
 	if (!wacom->data) {
 		kfree(wacom);
 		return -ENOMEM;
@@ -538,8 +652,9 @@ static int wacom_probe(struct usb_interf
 			break;
 
 		case 2:
-			wacom->dev.evbit[0] |= BIT(EV_MSC);
+			wacom->dev.evbit[0] |= BIT(EV_MSC) | BIT(EV_REL);
 			wacom->dev.mscbit[0] |= BIT(MSC_SERIAL);
+			wacom->dev.relbit[0] |= BIT(REL_WHEEL);
 			wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
  			wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE)	| BIT(BTN_TOOL_BRUSH)
 							  | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2);
--- diff/drivers/usb/misc/Kconfig	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/misc/Kconfig	2004-03-16 09:37:57.529794312 +0000
@@ -86,17 +86,6 @@ config USB_LEGOTOWER
 	  a module, say M here and read
 	  <file:Documentation/kbuild/modules.txt>.
 
-config USB_BRLVGER
-	tristate "Tieman Voyager USB Braille display support (EXPERIMENTAL)"
-	depends on USB && EXPERIMENTAL
-	help
-	  Say Y here if you want to use the Voyager USB Braille display from
-	  Tieman. See <file:Documentation/usb/brlvger.txt> for more
-	  information.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called brlvger.
-
 config USB_LCD
 	tristate "USB LCD driver support"
 	depends on USB
--- diff/drivers/usb/misc/Makefile	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/misc/Makefile	2004-03-16 09:37:57.529794312 +0000
@@ -4,7 +4,6 @@
 #
 
 obj-$(CONFIG_USB_AUERSWALD)	+= auerswald.o
-obj-$(CONFIG_USB_BRLVGER)	+= brlvger.o
 obj-$(CONFIG_USB_EMI62)		+= emi62.o
 obj-$(CONFIG_USB_EMI26)		+= emi26.o
 obj-$(CONFIG_USB_LCD)		+= usblcd.o
--- diff/drivers/usb/misc/usbtest.c	2004-03-11 10:20:28.000000000 +0000
+++ source/drivers/usb/misc/usbtest.c	2004-03-16 09:37:57.531794008 +0000
@@ -149,8 +149,6 @@ get_endpoints (struct usbtest_dev *dev, 
 				if (!out)
 					out = e;
 			}
-			if (in && out)
-				goto found;
 			continue;
 try_iso:
 			if (e->desc.bEndpointAddress & USB_DIR_IN) {
@@ -160,9 +158,9 @@ try_iso:
 				if (!iso_out)
 					iso_out = e;
 			}
-			if (iso_in && iso_out)
-				goto found;
 		}
+		if ((in && out)  ||  (iso_in && iso_out))
+			goto found;
 	}
 	return -EINVAL;
 
@@ -181,7 +179,8 @@ found:
 			in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
 		dev->out_pipe = usb_sndbulkpipe (udev,
 			out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
-	} else if (iso_in) {
+	}
+	if (iso_in) {
 		dev->iso_in = &iso_in->desc;
 		dev->in_iso_pipe = usb_rcvisocpipe (udev,
 				iso_in->desc.bEndpointAddress
@@ -211,7 +210,7 @@ static void simple_callback (struct urb 
 static struct urb *simple_alloc_urb (
 	struct usb_device	*udev,
 	int			pipe,
-	long			bytes
+	unsigned long		bytes
 )
 {
 	struct urb		*urb;
@@ -490,7 +489,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 +555,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 +575,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;
 		}
 
@@ -916,7 +911,7 @@ test_ctrl_queue (struct usbtest_dev *dev
 			req.wValue = cpu_to_le16 (USB_DT_INTERFACE << 8);
 			// interface == 0
 			len = sizeof (struct usb_interface_descriptor);
-			expected = -EPIPE;
+			expected = EPIPE;
 			break;
 		// NOTE: two consecutive stalls in the queue here.
 		// that tests fault recovery a bit more aggressively.
@@ -945,7 +940,7 @@ test_ctrl_queue (struct usbtest_dev *dev
 			req.wValue = cpu_to_le16 (USB_DT_ENDPOINT << 8);
 			// endpoint == 0
 			len = sizeof (struct usb_interface_descriptor);
-			expected = -EPIPE;
+			expected = EPIPE;
 			break;
 		// NOTE: sometimes even a third fault in the queue!
 		case 12:	// get string 0 descriptor (MAY STALL)
@@ -1072,7 +1067,7 @@ static int unlink1 (struct usbtest_dev *
 	 * due to errors, or is just NAKing requests.
 	 */
 	if ((retval = usb_submit_urb (urb, SLAB_KERNEL)) != 0) {
-		dbg ("submit/unlink fail %d", retval);
+		dev_dbg (&dev->intf->dev, "submit fail %d\n", retval);
 		return retval;
 	}
 
@@ -1087,18 +1082,22 @@ retry:
 		 * "normal" drivers would prevent resubmission, but
 		 * since we're testing unlink paths, we can't.
 		 */
-		dbg ("unlink retry");
+		dev_dbg (&dev->intf->dev, "unlink retry\n");
 		goto retry;
 	}
 	if (!(retval == 0 || retval == -EINPROGRESS)) {
-		dbg ("submit/unlink fail %d", retval);
+		dev_dbg (&dev->intf->dev, "unlink fail %d\n", retval);
 		return retval;
 	}
 
 	wait_for_completion (&completion);
 	retval = urb->status;
 	simple_free_urb (urb);
-	return retval;
+
+	if (async)
+		return (retval != -ECONNRESET) ? -ECONNRESET : 0;
+	else
+		return (retval != -ENOENT) ? -ENOENT : 0;
 }
 
 static int unlink_simple (struct usbtest_dev *dev, int pipe, int len)
@@ -1723,7 +1722,8 @@ usbtest_ioctl (struct usb_interface *int
 			retval = unlink_simple (dev, dev->in_pipe,
 						param->length);
 		if (retval)
-			dbg ("unlink reads failed, iterations left %d", i);
+			dev_dbg (&intf->dev, "unlink reads failed %d, "
+				"iterations left %d\n", retval, i);
 		break;
 	case 12:
 		if (dev->out_pipe == 0 || !param->length)
@@ -1735,7 +1735,8 @@ usbtest_ioctl (struct usb_interface *int
 			retval = unlink_simple (dev, dev->out_pipe,
 						param->length);
 		if (retval)
-			dbg ("unlink writes failed, iterations left %d", i);
+			dev_dbg (&intf->dev, "unlink writes failed %d, "
+				"iterations left %d\n", retval, i);
 		break;
 
 	/* ep halt tests */
@@ -1965,7 +1966,10 @@ static struct usbtest_info fw_info = {
 	.name		= "usb test device",
 	.ep_in		= 2,
 	.ep_out		= 2,
-	.alt		= 0,
+	.alt		= 1,
+	.autoconf	= 1,		// iso and ctrl_out need autoconf
+	.ctrl_out	= 1,
+	.iso		= 1,		// iso_ep's are #8 in/out
 };
 
 /* peripheral running Linux and 'zero.c' test firmware, or
--- diff/drivers/usb/net/Kconfig	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/net/Kconfig	2004-03-16 09:37:57.532793856 +0000
@@ -131,6 +131,14 @@ config USB_USBNET
 comment "USB Host-to-Host Cables"
 	depends on USB_USBNET
 
+config USB_ALI_M5632
+	boolean "ALi M5632 based 'USB 2.0 Data Link' cables"
+	depends on USB_USBNET
+	default y
+	help
+	  Choose this option if you're using a host-to-host cable
+	  based on this design, which supports USB 2.0 high speed.
+
 config USB_AN2720
 	boolean "AnchorChips 2720 based cables (Xircom PGUNET, ...)"
 	depends on USB_USBNET
--- diff/drivers/usb/net/pegasus.h	2004-01-19 10:22:59.000000000 +0000
+++ source/drivers/usb/net/pegasus.h	2004-03-16 09:37:57.532793856 +0000
@@ -128,6 +128,7 @@ struct usb_eth_dev {
 #define	VENDOR_DLINK		0x2001
 #define	VENDOR_ELCON		0x0db7
 #define	VENDOR_ELSA		0x05cc
+#define	VENDOR_GIGABYTE		0x1044
 #define	VENDOR_HAWKING		0x0e66
 #define	VENDOR_HP		0x03f0
 #define	VENDOR_IODATA		0x04bb
@@ -178,6 +179,9 @@ PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus I
 PEGASUS_DEV( "ADMtek ADM8513 \"Pegasus II\" USB Ethernet",
 		VENDOR_ADMTEK, 0x8513,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "ADMtek ADM8515 \"Pegasus II\" USB-2.0 Ethernet",
+		VENDOR_ADMTEK, 0x8515,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (evaluation board)",
 		VENDOR_ADMTEK, 0x0986,
 		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
@@ -223,6 +227,8 @@ PEGASUS_DEV( "EasiDock Ethernet", VENDOR
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000,
 		DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "GIGABYTE GN-BR402W Wireless Router", VENDOR_GIGABYTE, 0x8002,
+		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "HP hn210c Ethernet USB", VENDOR_HP, 0x811c,
@@ -263,6 +269,8 @@ PEGASUS_DEV( "NETGEAR FA101", VENDOR_NET
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "OCT Inc.", VENDOR_OCT, 0x0109,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "OCT USB TO Ethernet", VENDOR_OCT, 0x0901,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
--- diff/drivers/usb/net/usbnet.c	2004-03-11 10:20:28.000000000 +0000
+++ source/drivers/usb/net/usbnet.c	2004-03-16 09:37:57.534793552 +0000
@@ -384,6 +384,23 @@ static void skb_return (struct usbnet *d
 }
 
 
+#ifdef	CONFIG_USB_ALI_M5632
+#define	HAVE_HARDWARE
+
+/*-------------------------------------------------------------------------
+ *
+ * ALi M5632 driver ... does high speed
+ *
+ *-------------------------------------------------------------------------*/
+
+static const struct driver_info	ali_m5632_info = {
+	.description =	"ALi M5632",
+};
+
+
+#endif
+
+
 #ifdef	CONFIG_USB_AN2720
 #define	HAVE_HARDWARE
 
@@ -3009,7 +3026,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);
 
@@ -3133,6 +3150,13 @@ out:
 
 static const struct usb_device_id	products [] = {
 
+#ifdef	CONFIG_USB_ALI_M5632
+{
+	USB_DEVICE (0x0402, 0x5632),	// ALi defaults
+	.driver_info =	(unsigned long) &ali_m5632_info,
+},
+#endif
+
 #ifdef	CONFIG_USB_AN2720
 {
 	USB_DEVICE (0x0547, 0x2720),	// AnchorChips defaults
@@ -3314,6 +3338,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-11 10:20:28.000000000 +0000
+++ source/drivers/usb/serial/ftdi_sio.c	2004-03-16 09:37:57.536793248 +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-11 10:20:28.000000000 +0000
+++ source/drivers/usb/serial/ftdi_sio.h	2004-03-16 09:37:57.536793248 +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 11:28:11.000000000 +0000
+++ source/drivers/usb/serial/kl5kusb105.c	2004-03-16 09:37:57.561789448 +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/pl2303.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/serial/pl2303.c	2004-03-16 09:37:57.562789296 +0000
@@ -403,7 +403,7 @@ static int pl2303_open (struct usb_seria
 {
 	struct termios tmp_termios;
 	struct usb_serial *serial = port->serial;
-	unsigned char buf[10];
+	unsigned char *buf;
 	int result;
 
 	if (port_paranoia_check (port, __FUNCTION__))
@@ -414,6 +414,10 @@ static int pl2303_open (struct usb_seria
 	usb_clear_halt(serial->dev, port->write_urb->pipe);
 	usb_clear_halt(serial->dev, port->read_urb->pipe);
 
+	buf = kmalloc(10, GFP_KERNEL);
+	if (buf==NULL)
+		return -ENOMEM;
+
 #define FISH(a,b,c,d)								\
 	result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0),	\
 			       b, a, c, d, buf, 1, 100);			\
@@ -433,6 +437,8 @@ static int pl2303_open (struct usb_seria
 	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
 	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
 
+	kfree(buf);
+
 	/* Setup termios */
 	if (port->tty) {
 		pl2303_set_termios (port, &tmp_termios);
--- diff/drivers/usb/serial/usb-serial.c	2003-12-19 09:51:11.000000000 +0000
+++ source/drivers/usb/serial/usb-serial.c	2004-03-16 09:37:57.563789144 +0000
@@ -1006,7 +1006,7 @@ int usb_serial_probe(struct usb_interfac
 
 	/* descriptor matches, let's find the endpoints needed */
 	/* check out the endpoints */
-	iface_desc = &interface->altsetting[0];
+	iface_desc = interface->cur_altsetting;
 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
 		endpoint = &iface_desc->endpoint[i].desc;
 		
--- diff/drivers/usb/serial/visor.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/serial/visor.c	2004-03-16 09:37:57.573787624 +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-16 09:37:57.575787320 +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/Kconfig	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/storage/Kconfig	2004-03-16 09:37:57.581786408 +0000
@@ -1,8 +1,6 @@
 #
 # USB Storage driver configuration
 #
-comment "SCSI support is needed for USB Storage"
-	depends on USB && SCSI=n
 
 config USB_STORAGE
 	tristate "USB Mass Storage support"
--- diff/drivers/usb/storage/scsiglue.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/storage/scsiglue.c	2004-03-16 09:37:57.582786256 +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-11 10:20:28.000000000 +0000
+++ source/drivers/usb/storage/transport.c	2004-03-16 09:37:57.583786104 +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-11 10:20:28.000000000 +0000
+++ source/drivers/usb/storage/unusual_devs.h	2004-03-16 09:37:57.584785952 +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
 
@@ -409,6 +417,13 @@ UNUSUAL_DEV(  0x05e3, 0x0702, 0x0000, 0x
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_INQUIRY ),
 
+/* Reported by Henning Schild <henning@wh9.tu-dresden.de> */
+UNUSUAL_DEV(  0x05e3, 0x0702, 0x0113, 0x0113,
+		"EagleTec",
+		"External Hard Disk",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+
 /* Reported by Hanno Boeck <hanno@gmx.de>
  * Taken from the Lycoris Kernel */
 UNUSUAL_DEV(  0x0636, 0x0003, 0x0000, 0x9999,
@@ -440,12 +455,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 +628,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 +661,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 +711,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-16 09:37:57.585785800 +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 11:28:11.000000000 +0000
+++ source/drivers/usb/storage/usb.h	2004-03-16 09:37:57.585785800 +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_monitor.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/video/aty/radeon_monitor.c	2004-03-16 09:37:57.586785648 +0000
@@ -757,7 +757,7 @@ void __devinit radeon_check_modes(struct
 	    && rinfo->mon1_EDID) {
 		struct fb_var_screeninfo var;
 		RTRACE("Parsing EDID data for panel info\n");
-		if (parse_edid(rinfo->mon1_EDID, &var) == 0) {
+		if (fb_parse_edid(rinfo->mon1_EDID, &var) == 0) {
 			if (var.xres >= rinfo->panel_info.xres &&
 			    var.yres >= rinfo->panel_info.yres)
 				radeon_var_to_panel_info(rinfo, &var);
--- diff/drivers/video/console/fbcon.c	2004-03-11 10:20:28.000000000 +0000
+++ source/drivers/video/console/fbcon.c	2004-03-16 09:37:57.589785192 +0000
@@ -309,94 +309,6 @@ int set_con2fb_map(int unit, int newidx)
 }
 
 /*
- * drawing helpers
- */
-static void putcs_unaligned(struct vc_data *vc, struct fb_info *info,
-			    struct fb_image *image, int count,
-			    const unsigned short *s)
-{
-	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
-	unsigned int width = (vc->vc_font.width + 7) >> 3;
-	unsigned int cellsize = vc->vc_font.height * width;
-	unsigned int maxcnt = info->pixmap.size/cellsize;
-	unsigned int shift_low = 0, mod = vc->vc_font.width % 8;
-	unsigned int shift_high = 8, size, pitch, cnt, k;
-	unsigned int buf_align = info->pixmap.buf_align - 1;
-	unsigned int scan_align = info->pixmap.scan_align - 1;
-	unsigned int idx = vc->vc_font.width >> 3;
-	u8 *src, *dst, *dst0;
-
-	while (count) {
-		if (count > maxcnt)
-			cnt = k = maxcnt;
-		else
-			cnt = k = count;
-
-		image->width = vc->vc_font.width * cnt;
-		pitch = ((image->width + 7) >> 3) + scan_align;
-		pitch &= ~scan_align;
-		size = pitch * vc->vc_font.height + buf_align;
-		size &= ~buf_align;
-		dst0 = fb_get_buffer_offset(info, &info->pixmap, size);
-		image->data = dst0;
-		while (k--) {
-			src = vc->vc_font.data + (scr_readw(s++) & charmask)*
-			cellsize;
-			dst = dst0;
-			fb_move_buf_unaligned(info, &info->pixmap, dst, pitch, src,
-						idx, image->height, shift_high,
-						shift_low, mod);
-			shift_low += mod;
-			dst0 += (shift_low >= 8) ? width : width - 1;
-			shift_low &= 7;
-			shift_high = 8 - shift_low;
-		}
-		info->fbops->fb_imageblit(info, image);
-		image->dx += cnt * vc->vc_font.width;
-		count -= cnt;
-	}
-}
-
-static void putcs_aligned(struct vc_data *vc, struct fb_info *info,
-			  struct fb_image *image, int count,
-			  const unsigned short *s)
-{
-	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
-	unsigned int width = vc->vc_font.width >> 3;
-	unsigned int cellsize = vc->vc_font.height * width;
-	unsigned int maxcnt = info->pixmap.size/cellsize;
-	unsigned int scan_align = info->pixmap.scan_align - 1;
-	unsigned int buf_align = info->pixmap.buf_align - 1;
-	unsigned int pitch, cnt, size, k;
-	u8 *src, *dst, *dst0;
-
-	while (count) {
-		if (count > maxcnt)
-			cnt = k = maxcnt;
-		else
-			cnt = k = count;
-		
-		pitch = width * cnt + scan_align;
-		pitch &= ~scan_align;
-		size = pitch * vc->vc_font.height + buf_align;
-		size &= ~buf_align;
-		image->width = vc->vc_font.width * cnt;
-		dst0 = fb_get_buffer_offset(info, &info->pixmap, size);
-		image->data = dst0;
-		while (k--) {
-			src = vc->vc_font.data + (scr_readw(s++)&charmask)*cellsize;
-			dst = dst0;
-			fb_move_buf_aligned(info, &info->pixmap, dst, pitch, src,
-						width, image->height);
-			dst0 += width;
-		}
-		info->fbops->fb_imageblit(info, image);
-		image->dx += cnt * vc->vc_font.width;
-		count -= cnt;
-	}
-}
-
-/*
  * Accelerated handlers.
  */
 void accel_bmove(struct vc_data *vc, struct fb_info *info, int sy, 
@@ -430,48 +342,23 @@ void accel_clear(struct vc_data *vc, str
 	info->fbops->fb_fillrect(info, &region);
 }	
 
-static void accel_putc(struct vc_data *vc, struct fb_info *info,
-                      int c, int ypos, int xpos)
+void accel_putcs(struct vc_data *vc, struct fb_info *info,
+			const unsigned short *s, int count, int yy, int xx)
 {
 	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
 	unsigned int width = (vc->vc_font.width + 7) >> 3;
+	unsigned int cellsize = vc->vc_font.height * width;
+	unsigned int maxcnt = info->pixmap.size/cellsize;
 	unsigned int scan_align = info->pixmap.scan_align - 1;
 	unsigned int buf_align = info->pixmap.buf_align - 1;
+	unsigned int shift_low = 0, mod = vc->vc_font.width % 8;
+	unsigned int shift_high = 8, pitch, cnt, size, k;
 	int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
 	int fgshift = (vc->vc_hi_font_mask) ? 9 : 8;
-	unsigned int size, pitch;
-	struct fb_image image;
-	u8 *src, *dst;
-
-	image.dx = xpos * vc->vc_font.width;
-	image.dy = ypos * vc->vc_font.height;
-	image.width = vc->vc_font.width;
-	image.height = vc->vc_font.height;
-	image.fg_color = attr_fgcol(fgshift, c);
-	image.bg_color = attr_bgcol(bgshift, c);
-	image.depth = 1;
-
-	pitch = width + scan_align;
-	pitch &= ~scan_align;
-	size = pitch * vc->vc_font.height;
-	size += buf_align;
-	size &= ~buf_align;
-	dst = fb_get_buffer_offset(info, &info->pixmap, size);
-	image.data = dst;
-	src = vc->vc_font.data + (c & charmask) * vc->vc_font.height * width;
-
-	fb_move_buf_aligned(info, &info->pixmap, dst, pitch, src, width, image.height);
-
-	info->fbops->fb_imageblit(info, &image);
-}
-
-void accel_putcs(struct vc_data *vc, struct fb_info *info,
-			const unsigned short *s, int count, int yy, int xx)
-{
-	int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
-	int fgshift = (vc->vc_hi_font_mask) ? 9 : 8;
+	unsigned int idx = vc->vc_font.width >> 3;
 	struct fb_image image;
 	u16 c = scr_readw(s);
+	u8 *src, *dst, *dst0;
 
 	image.fg_color = attr_fgcol(fgshift, c);
 	image.bg_color = attr_bgcol(bgshift, c);
@@ -480,10 +367,41 @@ void accel_putcs(struct vc_data *vc, str
 	image.height = vc->vc_font.height;
 	image.depth = 1;
 
-	if (!(vc->vc_font.width & 7))
-               putcs_aligned(vc, info, &image, count, s);
-        else
-               putcs_unaligned(vc, info, &image, count, s);
+	while (count) {
+		if (count > maxcnt)
+			cnt = k = maxcnt;
+		else
+			cnt = k = count;
+
+		image.width = vc->vc_font.width * cnt;
+		pitch = ((image.width + 7) >> 3) + scan_align;
+		pitch &= ~scan_align;
+		size = pitch * image.height + buf_align;
+		size &= ~buf_align;
+		dst0 = fb_get_buffer_offset(info, &info->pixmap, size);
+		image.data = dst0;
+		while (k--) {
+			src = vc->vc_font.data + (scr_readw(s++) & charmask)*cellsize;
+			dst = dst0;
+
+			if (mod) {
+				fb_move_buf_unaligned(info, &info->pixmap, dst, pitch,
+						   src, idx, image.height, shift_high,
+						   shift_low, mod);
+				shift_low += mod;
+				dst0 += (shift_low >= 8) ? width : width - 1;
+				shift_low &= 7;
+				shift_high = 8 - shift_low;
+			} else {
+				fb_move_buf_aligned(info, &info->pixmap, dst, pitch,
+						 src, idx, image.height);
+				dst0 += width;
+			}
+		}
+		info->fbops->fb_imageblit(info, &image);
+		image.dx += cnt * vc->vc_font.width;
+		count -= cnt;
+	}
 }
 
 void accel_clear_margins(struct vc_data *vc, struct fb_info *info,
@@ -724,15 +642,13 @@ static __inline__ void updatescrollmode(
 static void fbcon_set_display(struct vc_data *vc, int init, int logo)
 {
 	struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]];
+	int nr_rows, nr_cols, old_rows, old_cols, i, charcnt = 256;
 	struct display *p = &fb_display[vc->vc_num];
-	int nr_rows, nr_cols;
-	int old_rows, old_cols;
 	unsigned short *save = NULL, *r, *q;
-	int i, charcnt = 256;
 	struct font_desc *font;
 
 	if (vc->vc_num != fg_console || (info->flags & FBINFO_FLAG_MODULE) ||
-	    info->fix.type == FB_TYPE_TEXT)
+	    (info->fix.type == FB_TYPE_TEXT))
 		logo = 0;
 
 	info->var.xoffset = info->var.yoffset = p->yscroll = 0;	/* reset wrap/pan */
@@ -958,11 +874,19 @@ static void fbcon_clear(struct vc_data *
 		accel_clear(vc, info, real_y(p, sy), sx, height, width);
 }
 
-
 static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos)
 {
 	struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]];
+	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+	unsigned int scan_align = info->pixmap.scan_align - 1;
+	unsigned int buf_align = info->pixmap.buf_align - 1;
+	unsigned int width = (vc->vc_font.width + 7) >> 3;
+	int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+	int fgshift = (vc->vc_hi_font_mask) ? 9 : 8;
 	struct display *p = &fb_display[vc->vc_num];
+	unsigned int size, pitch;
+	struct fb_image image;
+	u8 *src, *dst;
 
 	if (!info->fbops->fb_blank && console_blanked)
 		return;
@@ -972,7 +896,28 @@ static void fbcon_putc(struct vc_data *v
 	if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT)
 		return;
 
-	accel_putc(vc, info, c, real_y(p, ypos), xpos);
+	image.dx = xpos * vc->vc_font.width;
+	image.dy = real_y(p, ypos) * vc->vc_font.height;
+	image.width = vc->vc_font.width;
+	image.height = vc->vc_font.height;
+	image.fg_color = attr_fgcol(fgshift, c);
+	image.bg_color = attr_bgcol(bgshift, c);
+	image.depth = 1;
+
+	src = vc->vc_font.data + (c & charmask) * vc->vc_font.height * width;
+
+	pitch = width + scan_align;
+	pitch &= ~scan_align;
+	size = pitch * vc->vc_font.height;
+	size += buf_align;
+	size &= ~buf_align;
+
+	dst = fb_get_buffer_offset(info, &info->pixmap, size);
+	image.data = dst;
+
+	fb_move_buf_aligned(info, &info->pixmap, dst, pitch, src, width, image.height);
+
+	info->fbops->fb_imageblit(info, &image);
 }
 
 static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
@@ -2345,6 +2290,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 +2298,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 +2317,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/dnfb.c	2003-05-21 10:50:16.000000000 +0000
+++ source/drivers/video/dnfb.c	2004-03-16 09:37:57.590785040 +0000
@@ -103,8 +103,6 @@
 
 #define SWAP(A) ((A>>8) | ((A&0xff) <<8))
 
-static struct fb_info fb_info;
-
 /* frame buffer operations */
 
 static int dnfb_blank(int blank, struct fb_info *info);
@@ -119,7 +117,7 @@ static struct fb_ops dn_fb_ops = {
 	.fb_cursor	= soft_cursor,
 };
 
-struct fb_var_screeninfo dnfb_var __initdata = {
+struct fb_var_screeninfo dnfb_var __devinitdata = {
 	.xres		1280,
 	.yres		1024,
 	.xres_virtual	2048,
@@ -130,7 +128,7 @@ struct fb_var_screeninfo dnfb_var __init
 	.vmode		FB_VMODE_NONINTERLACED,
 };
 
-static struct fb_fix_screeninfo dnfb_fix __initdata = {
+static struct fb_fix_screeninfo dnfb_fix __devinitdata = {
 	.id		"Apollo Mono",
 	.smem_start	(FRAME_BUFFER_START + IO_BASE),
 	.smem_len	FRAME_BUFFER_LEN,
@@ -148,7 +146,7 @@ static int dnfb_blank(int blank, struct 
 	return 0;
 }
 
-static 
+static
 void dnfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 {
 
@@ -224,21 +222,38 @@ void dnfb_copyarea(struct fb_info *info,
 	out_8(AP_CONTROL_0, NORMAL_MODE);
 }
 
+/*
+ * Initialization
+ */
 
-unsigned long __init dnfb_init(unsigned long mem_start)
+static int __devinit dnfb_probe(struct device *device)
 {
-	int err;
+	struct platform_device *dev = to_platform_device(device);
+	struct fb_info *info;
+	int err = 0;
+
+	info = framebuffer_alloc(0, &dev->dev);
+	if (!info)
+		return -ENOMEM;
+
+	info->fbops = &dn_fb_ops;
+	info->fix = dnfb_fix;
+	info->var = dnfb_var;
+	info->screen_base = (u_char *) info->fix.smem_start;
+
+	err = fb_alloc_cmap(&info->cmap, 2, 0);
+	if (err < 0) {
+		framebuffer_release(info);
+		return err;
+	}
 
-	fb_info.fbops = &dn_fb_ops;
-	fb_info.fix = dnfb_fix;
-	fb_info.var = dnfb_var;
-	fb_info.screen_base = (u_char *) fb_info.fix.smem_start;
-
-	fb_alloc_cmap(&fb_info.cmap, 2, 0);
-
-	err = register_framebuffer(&fb_info);
-	if (err < 0)
-		panic("unable to register apollo frame buffer\n");
+	err = register_framebuffer(info);
+	if (err < 0) {
+		fb_dealloc_cmap(&info->cmap);
+		framebuffer_release(info);
+		return err;
+	}
+	dev_set_drvdata(&dev->dev, info);
 
 	/* now we have registered we can safely setup the hardware */
 	out_8(AP_CONTROL_3A, RESET_CREG);
@@ -249,7 +264,31 @@ unsigned long __init dnfb_init(unsigned 
 	out_be16(AP_ROP_1, SWAP(0x3));
 
 	printk("apollo frame buffer alive and kicking !\n");
-	return mem_start;
+	return err;
+}
+
+static struct device_driver dnfb_driver = {
+	.name	= "dnfb",
+	.bus	= &platform_bus_type,
+	.probe	= dnfb_probe,
+};
+
+static struct platform_device dnfb_device = {
+	.name	= "dnfb",
+};
+
+int __init dnfb_init(void)
+{
+	int ret;
+
+	ret = driver_register(&dnfb_driver);
+
+	if (!ret) {
+		ret = platform_device_register(&dnfb_device);
+		if (ret)
+			driver_unregister(&dnfb_driver);
+	}
+	return ret;
 }
 
 MODULE_LICENSE("GPL");
--- diff/drivers/video/fbmon.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/video/fbmon.c	2004-03-16 09:37:57.592784736 +0000
@@ -41,6 +41,15 @@
  * EDID parser
  */
 
+#undef DEBUG  /* define this for verbose EDID parsing output */
+
+#ifdef DEBUG
+#define DPRINTK(fmt, args...) printk(fmt,## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+
 const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff,
 	0xff, 0xff, 0xff, 0x00
 };
@@ -84,203 +93,93 @@ static int edid_check_header(unsigned ch
 	return 1;
 }
 
-static void parse_vendor_block(unsigned char *block)
+static void parse_vendor_block(unsigned char *block, struct fb_monspecs *specs)
 {
-	unsigned char c[4];
-
-	c[0] = ((block[0] & 0x7c) >> 2) + '@';
-	c[1] = ((block[0] & 0x03) << 3) + ((block[1] & 0xe0) >> 5) + '@';
-	c[2] = (block[1] & 0x1f) + '@';
-	c[3] = 0;
-	printk("   Manufacturer: %s ", c);
-	printk("Model: %x ", block[2] + (block[3] << 8));
-	printk("Serial#: %u\n", block[4] + (block[5] << 8) + 
-	       (block[6] << 16) + (block[7] << 24));
-	printk("   Year: %u Week %u\n", block[9] + 1990, block[8]);
-}
-
-static void parse_dpms_capabilities(unsigned char flags)
-{
-	printk("      DPMS: Active %s, Suspend %s, Standby %s\n",
+	specs->manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';
+	specs->manufacturer[1] = ((block[0] & 0x03) << 3) +
+		((block[1] & 0xe0) >> 5) + '@';
+	specs->manufacturer[2] = (block[1] & 0x1f) + '@';
+	specs->manufacturer[3] = 0;
+	specs->model = block[2] + (block[3] << 8);
+	specs->serial = block[4] + (block[5] << 8) +
+	       (block[6] << 16) + (block[7] << 24);
+	specs->year = block[9] + 1990;
+	specs->week = block[8];
+	DPRINTK("   Manufacturer: %s\n", specs->manufacturer);
+	DPRINTK("   Model: %x\n", specs->model);
+	DPRINTK("   Serial#: %u\n", specs->serial);
+	DPRINTK("   Year: %u Week %u\n", specs->year, specs->week);
+}
+
+static void get_dpms_capabilities(unsigned char flags,
+				  struct fb_monspecs *specs)
+{
+	specs->dpms = 0;
+	if (flags & DPMS_ACTIVE_OFF)
+		specs->dpms |= FB_DPMS_ACTIVE_OFF;
+	if (flags & DPMS_SUSPEND)
+		specs->dpms |= FB_DPMS_SUSPEND;
+	if (flags & DPMS_STANDBY)
+		specs->dpms |= FB_DPMS_STANDBY;
+	DPRINTK("      DPMS: Active %s, Suspend %s, Standby %s\n",
 	       (flags & DPMS_ACTIVE_OFF) ? "yes" : "no",
 	       (flags & DPMS_SUSPEND)    ? "yes" : "no",
 	       (flags & DPMS_STANDBY)    ? "yes" : "no");
 }
 	
-static void print_chroma(unsigned char *block)
+static void get_chroma(unsigned char *block, struct fb_monspecs *specs)
 {
 	int tmp;
 
+	DPRINTK("      Chroma\n");
 	/* Chromaticity data */
-	printk("      Chromaticity: ");
 	tmp = ((block[5] & (3 << 6)) >> 6) | (block[0x7] << 2);
 	tmp *= 1000;
 	tmp += 512;
-	printk("RedX:   0.%03d ", tmp/1024);
+	specs->chroma.redx = tmp/1024;
+	DPRINTK("         RedX:     0.%03d ", specs->chroma.redx);
 
 	tmp = ((block[5] & (3 << 4)) >> 4) | (block[0x8] << 2);
 	tmp *= 1000;
 	tmp += 512;
-	printk("RedY:   0.%03d\n", tmp/1024);
+	specs->chroma.redy = tmp/1024;
+	DPRINTK("RedY:     0.%03d\n", specs->chroma.redy);
 
 	tmp = ((block[5] & (3 << 2)) >> 2) | (block[0x9] << 2);
 	tmp *= 1000;
 	tmp += 512;
-	printk("                    GreenX: 0.%03d ", tmp/1024);
+	specs->chroma.greenx = tmp/1024;
+	DPRINTK("         GreenX:   0.%03d ", specs->chroma.greenx);
 
 	tmp = (block[5] & 3) | (block[0xa] << 2);
 	tmp *= 1000;
 	tmp += 512;
-	printk("GreenY: 0.%03d\n", tmp/1024);
+	specs->chroma.greeny = tmp/1024;
+	DPRINTK("GreenY:   0.%03d\n", specs->chroma.greeny);
 
 	tmp = ((block[6] & (3 << 6)) >> 6) | (block[0xb] << 2);
 	tmp *= 1000;
 	tmp += 512;
-	printk("                    BlueX:  0.%03d ", tmp/1024);
+	specs->chroma.bluex = tmp/1024;
+	DPRINTK("         BlueX:    0.%03d ", specs->chroma.bluex);
 
 	tmp = ((block[6] & (3 << 4)) >> 4) | (block[0xc] << 2);
 	tmp *= 1000;
 	tmp += 512;
-	printk("BlueY:  0.%03d\n", tmp/1024);
+	specs->chroma.bluey = tmp/1024;
+	DPRINTK("BlueY:    0.%03d\n", specs->chroma.bluey);
 	
 	tmp = ((block[6] & (3 << 2)) >> 2) | (block[0xd] << 2);
 	tmp *= 1000;
 	tmp += 512;
-	printk("                    WhiteX: 0.%03d ", tmp/1024);
+	specs->chroma.whitex = tmp/1024;
+	DPRINTK("         WhiteX:   0.%03d ", specs->chroma.whitex);
 
 	tmp = (block[6] & 3) | (block[0xe] << 2);
 	tmp *= 1000;
 	tmp += 512;
-	printk("WhiteY: 0.%03d\n", tmp/1024);
-}
-
-static void parse_display_block(unsigned char *block)
-{
-	unsigned char c;
-
-	c = (block[0] & 0x80) >> 7;
-	if (c) 
-		printk("      Digital Display Input");
-	else {
-		printk("      Analog Display Input: Input Voltage - ");
-		switch ((block[0] & 0x60) >> 5) {
-		case 0:
-			printk("0.700V/0.300V");
-			break;
-		case 1:
-			printk("0.714V/0.286V");
-			break;
-		case 2:
-			printk("1.000V/0.400V");
-			break;
-		case 3:
-			printk("0.700V/0.000V");
-			break;
-		default:
-			printk("unknown");
-		}
-		printk("\n");
-	}
-	c = (block[0] & 0x10) >> 4;
-	if (c)
-		printk("      Configurable signal level\n");
-	printk("      Sync: ");
-	c = block[0] & 0x0f;
-	if (c & 0x10)
-		printk("Blank to Blank ");
-	if (c & 0x08)
-		printk("Separate ");
-	if (c & 0x04)
-		printk("Composite ");
-	if (c & 0x02)
-		printk("Sync on Green ");
-	if (c & 0x01)
-		printk("Serration on ");
-	printk("\n");
-
-	printk("      Max H-size in cm: ");
-	c = block[1];
-	if (c) 
-		printk("%d\n", c);
-	else
-		printk("variable\n");
-	
-	printk("      Max V-size in cm: ");
-	c = block[2];
-	if (c)
-		printk("%d\n", c);
-	else
-		printk("variable\n");
-
-	c = block[3];
-	printk("      Gamma: ");
-	printk("%d.%d\n", (c + 100)/100, (c+100) % 100);
-
-	parse_dpms_capabilities(block[4]);
-
-	switch ((block[4] & 0x18) >> 3) {
-	case 0:
-		printk("      Monochrome/Grayscale\n");
-		break;
-	case 1:
-		printk("      RGB Color Display\n");
-		break;
-	case 2:
-		printk("      Non-RGB Multicolor Display\n");
-		break;
-	default:
-		printk("      Unknown\n");
-		break;
-	}
-
-	print_chroma(block);
-	
-	c = block[4] & 0x7;
-	if (c & 0x04)
-		printk("      Default color format is primary\n");
-	if (c & 0x02)
-		printk("      First DETAILED Timing is preferred\n");
-	if (c & 0x01)
-		printk("      Display is GTF capable\n");
-}
-
-static void parse_std_md_block(unsigned char *block)
-{
-	unsigned char c;
-
-	c = block[0];
-	if (c&0x80) printk("      720x400@70Hz\n");
-	if (c&0x40) printk("      720x400@88Hz\n");
-	if (c&0x20) printk("      640x480@60Hz\n");
-	if (c&0x10) printk("      640x480@67Hz\n");
-	if (c&0x08) printk("      640x480@72Hz\n");
-	if (c&0x04) printk("      640x480@75Hz\n");
-	if (c&0x02) printk("      800x600@56Hz\n");
-	if (c&0x01) printk("      800x600@60Hz\n");
-
-	c = block[1];
-	if (c&0x80) printk("      800x600@72Hz\n");
-	if (c&0x40) printk("      800x600@75Hz\n");
-	if (c&0x20) printk("      832x624@75Hz\n");
-	if (c&0x10) printk("      1024x768@87Hz (interlaced)\n");
-	if (c&0x08) printk("      1024x768@60Hz\n");
-	if (c&0x04) printk("      1024x768@70Hz\n");
-	if (c&0x02) printk("      1024x768@75Hz\n");
-	if (c&0x01) printk("      1280x1024@75Hz\n");
-
-	c = block[2];
-	if (c&0x80) printk("      1152x870@75Hz\n");
-	printk("      Manufacturer's mask: %x\n",c&0x7F);
-}
-		
-		
-static int edid_is_timing_block(unsigned char *block)
-{
-	if ((block[0] != 0x00) || (block[1] != 0x00) || 
-	    (block[2] != 0x00) || (block[4] != 0x00)) 
-		return 1;
-	else
-		return 0;
+	specs->chroma.whitey = tmp/1024;
+	DPRINTK("WhiteY:   0.%03d\n", specs->chroma.whitey);
 }
 
 static int edid_is_serial_block(unsigned char *block)
@@ -323,154 +222,6 @@ static int edid_is_monitor_block(unsigne
 		return 0;
 }
 
-static int edid_is_color_block(unsigned char *block)
-{
-	if ((block[0] == 0x00) && (block[1] == 0x00) && 
-	    (block[2] == 0x00) && (block[3] == 0xfb) &&
-	    (block[4] == 0x00))
-		return 1;
-	else
-		return 0;
-}
-
-static int edid_is_std_timings_block(unsigned char *block)
-{
-	if ((block[0] == 0x00) && (block[1] == 0x00) && 
-	    (block[2] == 0x00) && (block[3] == 0xfa) &&
-	    (block[4] == 0x00))
-		return 1;
-	else
-		return 0;
-}
-
-static void parse_serial_block(unsigned char *block)
-{
-	unsigned char c[13];
-	
-	copy_string(block, c);
-	printk("      Serial No     : %s\n", c);
-}
-
-static void parse_ascii_block(unsigned char *block)
-{
-	unsigned char c[13];
-	
-	copy_string(block, c);
-	printk("      %s\n", c);
-}
-
-static void parse_limits_block(unsigned char *block)
-{
-	printk("      HorizSync     : %d-%d KHz\n", H_MIN_RATE, H_MAX_RATE);
-	printk("      VertRefresh   : %d-%d Hz\n", V_MIN_RATE, V_MAX_RATE);
-	if (MAX_PIXEL_CLOCK != 10*0xff)
-		printk("      Max Pixelclock: %d MHz\n", (int) MAX_PIXEL_CLOCK);
-}
-
-static void parse_monitor_block(unsigned char *block)
-{
-	unsigned char c[13];
-	
-	copy_string(block, c);
-	printk("      Monitor Name  : %s\n", c);
-}
-
-static void parse_color_block(unsigned char *block)
-{
-	printk("      Color Point    : unimplemented\n");
-}
-
-static void parse_std_timing_block(unsigned char *block)
-{
-	int xres, yres = 0, refresh, ratio, err = 1;
-	
-	xres = (block[0] + 31) * 8;
-	if (xres <= 256)
-		return;
-
-	ratio = (block[1] & 0xc0) >> 6;
-	switch (ratio) {
-	case 0:
-		yres = xres;
-		break;
-	case 1:
-		yres = (xres * 3)/4;
-		break;
-	case 2:
-		yres = (xres * 4)/5;
-		break;
-	case 3:
-		yres = (xres * 9)/16;
-		break;
-	}
-	refresh = (block[1] & 0x3f) + 60;
-	printk("      %dx%d@%dHz\n", xres, yres, refresh);
-	err = 0;
-}
-
-static void parse_dst_timing_block(unsigned char *block)
-{
-	int i;
-
-	block += 5;
-	for (i = 0; i < 5; i++, block += STD_TIMING_DESCRIPTION_SIZE)
-		parse_std_timing_block(block);
-}
-
-static void parse_detailed_timing_block(unsigned char *block)
-{
-	printk("      %d MHz ",  PIXEL_CLOCK/1000000);
-	printk("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET, 
-	       H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);
-	printk("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET, 
-	       V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);
-	printk("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-", 
-	       (VSYNC_POSITIVE) ? "+" : "-");
-}
-
-int parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
-{
-	int i;
-	unsigned char *block;
-
-	if (edid == NULL || var == NULL)
-		return 1;
-
-	if (!(edid_checksum(edid)))
-		return 1;
-
-	if (!(edid_check_header(edid)))
-		return 1;
-
-	block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
-
-	for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
-		if (edid_is_timing_block(block)) {
-			var->xres = var->xres_virtual = H_ACTIVE;
-			var->yres = var->yres_virtual = V_ACTIVE;
-			var->height = var->width = -1;
-			var->right_margin = H_SYNC_OFFSET;
-			var->left_margin = (H_ACTIVE + H_BLANKING) -
-				(H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
-			var->upper_margin = V_BLANKING - V_SYNC_OFFSET - 
-				V_SYNC_WIDTH;
-			var->lower_margin = V_SYNC_OFFSET;
-			var->hsync_len = H_SYNC_WIDTH;
-			var->vsync_len = V_SYNC_WIDTH;
-			var->pixclock = PIXEL_CLOCK;
-			var->pixclock /= 1000;
-			var->pixclock = KHZ2PICOS(var->pixclock);
-
-			if (HSYNC_POSITIVE)
-				var->sync |= FB_SYNC_HOR_HIGH_ACT;
-			if (VSYNC_POSITIVE)
-				var->sync |= FB_SYNC_VERT_HIGH_ACT;
-			return 0;
-		}
-	}
-	return 1;
-}
-
 static void calc_mode_timings(int xres, int yres, int refresh, struct fb_videomode *mode)
 {
 	struct fb_var_screeninfo var;
@@ -500,45 +251,82 @@ static int get_est_timing(unsigned char 
 	unsigned char c;
 
 	c = block[0];
-	if (c&0x80) 
-		calc_mode_timings(720, 400, 70, &mode[num++]);
-	if (c&0x40) 
-		calc_mode_timings(720, 400, 88, &mode[num++]);
-	if (c&0x20)
+	if (c&0x80) {
+		calc_mode_timings(720, 400, 70, &mode[num]);
+		mode[num++].flag = FB_MODE_IS_CALCULATED;
+		DPRINTK("      720x400@70Hz\n");
+	}
+	if (c&0x40) {
+		calc_mode_timings(720, 400, 88, &mode[num]);
+		mode[num++].flag = FB_MODE_IS_CALCULATED;
+		DPRINTK("      720x400@88Hz\n");
+	}
+	if (c&0x20) {
 		mode[num++] = vesa_modes[3];
-	if (c&0x10)
-		calc_mode_timings(640, 480, 67, &mode[num++]);
-	if (c&0x08)
+		DPRINTK("      640x480@60Hz\n");
+	}
+	if (c&0x10) {
+		calc_mode_timings(640, 480, 67, &mode[num]);
+		mode[num++].flag = FB_MODE_IS_CALCULATED;
+		DPRINTK("      640x480@67Hz\n");
+	}
+	if (c&0x08) {
 		mode[num++] = vesa_modes[4];
-	if (c&0x04)
+		DPRINTK("      640x480@72Hz\n");
+	}
+	if (c&0x04) {
 		mode[num++] = vesa_modes[5];
-	if (c&0x02)
+		DPRINTK("      640x480@75Hz\n");
+	}
+	if (c&0x02) {
 		mode[num++] = vesa_modes[7];
-	if (c&0x01)
+		DPRINTK("      800x600@56Hz\n");
+	}
+	if (c&0x01) {
 		mode[num++] = vesa_modes[8];
+		DPRINTK("      800x600@60Hz\n");
+	}
 
 	c = block[1];
-	if (c&0x80)
+	if (c&0x80) {
  		mode[num++] = vesa_modes[9];
-	if (c&0x40)
+		DPRINTK("      800x600@72Hz\n");
+	}
+	if (c&0x40) {
  		mode[num++] = vesa_modes[10];
-	if (c&0x20)
-		calc_mode_timings(832, 624, 75, &mode[num++]);
-	if (c&0x10)
+		DPRINTK("      800x600@75Hz\n");
+	}
+	if (c&0x20) {
+		calc_mode_timings(832, 624, 75, &mode[num]);
+		mode[num++].flag = FB_MODE_IS_CALCULATED;
+		DPRINTK("      832x624@75Hz\n");
+	}
+	if (c&0x10) {
 		mode[num++] = vesa_modes[12];
-	if (c&0x08)
+		DPRINTK("      1024x768@87Hz Interlaced\n");
+	}
+	if (c&0x08) {
 		mode[num++] = vesa_modes[13];
-	if (c&0x04)
+		DPRINTK("      1024x768@60Hz\n");
+	}
+	if (c&0x04) {
 		mode[num++] = vesa_modes[14];
-	if (c&0x02)
+		DPRINTK("      1024x768@70Hz\n");
+	}
+	if (c&0x02) {
 		mode[num++] = vesa_modes[15];
-	if (c&0x01)
+		DPRINTK("      1024x768@75Hz\n");
+	}
+	if (c&0x01) {
 		mode[num++] = vesa_modes[21];
-
+		DPRINTK("      1280x1024@75Hz\n");
+	}
 	c = block[2];
-	if (c&0x80)
+	if (c&0x80) {
 		mode[num++] = vesa_modes[17];
-
+		DPRINTK("      1152x870@75Hz\n");
+	}
+	DPRINTK("      Manufacturer's mask: %x\n",c&0x7F);
 	return num;
 }
 
@@ -567,17 +355,17 @@ static int get_std_timing(unsigned char 
 	}
 	refresh = (block[1] & 0x3f) + 60;
 
+	DPRINTK("      %dx%d@%dHz\n", xres, yres, refresh);
 	for (i = 0; i < VESA_MODEDB_SIZE; i++) {
 		if (vesa_modes[i].xres == xres && 
 		    vesa_modes[i].yres == yres &&
 		    vesa_modes[i].refresh == refresh) {
 			*mode = vesa_modes[i];
-			break;
-		} else {
-			calc_mode_timings(xres, yres, refresh, mode);
-			break;
+			mode->flag |= FB_MODE_IS_STANDARD;
+			return 1;
 		}
 	}
+	calc_mode_timings(xres, yres, refresh, mode);
 	return 1;
 }
 
@@ -615,6 +403,15 @@ static void get_detailed_timing(unsigned
 	mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *
 				     (V_ACTIVE + V_BLANKING));
 	mode->vmode = 0;
+	mode->flag = FB_MODE_IS_DETAILED;
+
+	DPRINTK("      %d MHz ",  PIXEL_CLOCK/1000000);
+	DPRINTK("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET,
+	       H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);
+	DPRINTK("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET,
+	       V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);
+	DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-",
+	       (VSYNC_POSITIVE) ? "+" : "-");
 }
 
 /**
@@ -647,21 +444,30 @@ struct fb_videomode *fb_create_modedb(un
 
 	*dbsize = 0;
 
+	DPRINTK("   Supported VESA Modes\n");
 	block = edid + ESTABLISHED_TIMING_1;
 	num += get_est_timing(block, &mode[num]);
 
+	DPRINTK("   Standard Timings\n");
 	block = edid + STD_TIMING_DESCRIPTIONS_START;
 	for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE) 
 		num += get_std_timing(block, &mode[num]);
 
+	DPRINTK("   Detailed Timings\n");
 	block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
 	for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
+	        int first = 1;
+
 		if (block[0] == 0x00 && block[1] == 0x00) {
 			if (block[3] == 0xfa) {
 				num += get_dst_timing(block + 5, &mode[num]);
 			}
 		} else  {
 			get_detailed_timing(block, &mode[num]);
+			if (first) {
+			        mode[num].flag |= FB_MODE_IS_FIRST;
+				first = 0;
+			}
 			num++;
 		}
 	}
@@ -694,45 +500,24 @@ void fb_destroy_modedb(struct fb_videomo
 		kfree(modedb);
 }
 
-/**
- * fb_get_monitor_limits - get monitor operating limits
- * @edid: EDID data
- * @specs: fb_monspecs structure pointer
- *
- * DESCRIPTION:
- * Gets monitor operating limits from EDID data and places them in 
- * @specs
- */
 int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
 {
 	int i, retval = 1;
 	unsigned char *block;
 
-	if (edid == NULL || specs == NULL)
-		return 1;
-
-	if (!(edid_checksum(edid)))
-		return 1;
-
-	if (!(edid_check_header(edid)))
-		return 1;
-
-	memset(specs, 0, sizeof(struct fb_monspecs));
 	block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
 
-	printk("Monitor Operating Limits: ");
+	DPRINTK("      Monitor Operating Limits: ");
 	for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
 		if (edid_is_limits_block(block)) {
 			specs->hfmin = H_MIN_RATE * 1000;
 			specs->hfmax = H_MAX_RATE * 1000;
 			specs->vfmin = V_MIN_RATE;
 			specs->vfmax = V_MAX_RATE;
-			specs->dclkmax = (MAX_PIXEL_CLOCK != 10*0xff) ?
-				MAX_PIXEL_CLOCK * 1000000 : 0;
+			specs->dclkmax = MAX_PIXEL_CLOCK * 1000000;
 			specs->gtf = (GTF_SUPPORT) ? 1 : 0;
-			specs->dpms = edid[DPMS_FLAGS];
 			retval = 0;
-			printk("From EDID\n");
+			DPRINTK("From EDID\n");
 			break;
 		}
 	}
@@ -744,7 +529,7 @@ int fb_get_monitor_limits(unsigned char 
 
 		modes = fb_create_modedb(edid, &num_modes);
 		if (!modes) {
-			printk("None Available\n");
+			DPRINTK("None Available\n");
 			return 1;
 		}
 
@@ -767,15 +552,189 @@ int fb_get_monitor_limits(unsigned char 
 			if (specs->vfmin == 0 || specs->vfmin > hz)
 				specs->vfmin = hz;
 		}
-		printk("Extrapolated\n");
+		DPRINTK("Extrapolated\n");
 		fb_destroy_modedb(modes);
 	}
-	printk("     H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n", specs->hfmin/1000, specs->hfmax/1000, 
-	       specs->vfmin, specs->vfmax, specs->dclkmax/1000000);
+	DPRINTK("           H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n",
+		specs->hfmin/1000, specs->hfmax/1000, specs->vfmin,
+		specs->vfmax, specs->dclkmax/1000000);
 	return retval;
 }
 
-void show_edid(unsigned char *edid)
+static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs)
+{
+	unsigned char c, *block;
+
+	block = edid + EDID_STRUCT_DISPLAY;
+
+	fb_get_monitor_limits(edid, specs);
+
+	c = (block[0] & 0x80) >> 7;
+	specs->input = 0;
+	if (c) {
+		specs->input |= FB_DISP_DDI;
+		DPRINTK("      Digital Display Input");
+	} else {
+		DPRINTK("      Analog Display Input: Input Voltage - ");
+		switch ((block[0] & 0x60) >> 5) {
+		case 0:
+			DPRINTK("0.700V/0.300V");
+			specs->input |= FB_DISP_ANA_700_300;
+			break;
+		case 1:
+			DPRINTK("0.714V/0.286V");
+			specs->input |= FB_DISP_ANA_714_286;
+			break;
+		case 2:
+			DPRINTK("1.000V/0.400V");
+			specs->input |= FB_DISP_ANA_1000_400;
+			break;
+		case 3:
+			DPRINTK("0.700V/0.000V");
+			specs->input |= FB_DISP_ANA_700_000;
+			break;
+		default:
+			DPRINTK("unknown");
+			specs->input |= FB_DISP_UNKNOWN;
+		}
+	}
+	DPRINTK("\n      Sync: ");
+	c = (block[0] & 0x10) >> 4;
+	if (c)
+		DPRINTK("      Configurable signal level\n");
+	c = block[0] & 0x0f;
+	specs->signal = 0;
+	if (c & 0x10) {
+		DPRINTK("Blank to Blank ");
+		specs->signal |= FB_SIGNAL_BLANK_BLANK;
+	}
+	if (c & 0x08) {
+		DPRINTK("Separate ");
+		specs->signal |= FB_SIGNAL_SEPARATE;
+	}
+	if (c & 0x04) {
+		DPRINTK("Composite ");
+		specs->signal |= FB_SIGNAL_COMPOSITE;
+	}
+	if (c & 0x02) {
+		DPRINTK("Sync on Green ");
+		specs->signal |= FB_SIGNAL_SYNC_ON_GREEN;
+	}
+	if (c & 0x01) {
+		DPRINTK("Serration on ");
+		specs->signal |= FB_SIGNAL_SERRATION_ON;
+	}
+	DPRINTK("\n");
+	specs->max_x = block[1];
+	specs->max_y = block[2];
+	DPRINTK("      Max H-size in cm: ");
+	if (specs->max_x)
+		DPRINTK("%d\n", specs->max_x);
+	else
+		DPRINTK("variable\n");
+	DPRINTK("      Max V-size in cm: ");
+	if (specs->max_y)
+		DPRINTK("%d\n", specs->max_y);
+	else
+		DPRINTK("variable\n");
+
+	c = block[3];
+	specs->gamma = c+100;
+	DPRINTK("      Gamma: ");
+	DPRINTK("%d.%d\n", specs->gamma/100, specs->gamma % 100);
+
+	get_dpms_capabilities(block[4], specs);
+
+	switch ((block[4] & 0x18) >> 3) {
+	case 0:
+		DPRINTK("      Monochrome/Grayscale\n");
+		specs->input |= FB_DISP_MONO;
+		break;
+	case 1:
+		DPRINTK("      RGB Color Display\n");
+		specs->input |= FB_DISP_RGB;
+		break;
+	case 2:
+		DPRINTK("      Non-RGB Multicolor Display\n");
+		specs->input |= FB_DISP_MULTI;
+		break;
+	default:
+		DPRINTK("      Unknown\n");
+		specs->input |= FB_DISP_UNKNOWN;
+		break;
+	}
+
+	get_chroma(block, specs);
+
+	specs->misc = 0;
+	c = block[4] & 0x7;
+	if (c & 0x04) {
+		DPRINTK("      Default color format is primary\n");
+		specs->misc |= FB_MISC_PRIM_COLOR;
+	}
+	if (c & 0x02) {
+		DPRINTK("      First DETAILED Timing is preferred\n");
+		specs->misc |= FB_MISC_1ST_DETAIL;
+	}
+	if (c & 0x01) {
+		printk("      Display is GTF capable\n");
+		specs->gtf = 1;
+	}
+}
+
+static int edid_is_timing_block(unsigned char *block)
+{
+	if ((block[0] != 0x00) || (block[1] != 0x00) ||
+	    (block[2] != 0x00) || (block[4] != 0x00))
+		return 1;
+	else
+		return 0;
+}
+
+int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
+{
+	int i;
+	unsigned char *block;
+
+	if (edid == NULL || var == NULL)
+		return 1;
+
+	if (!(edid_checksum(edid)))
+		return 1;
+
+	if (!(edid_check_header(edid)))
+		return 1;
+
+	block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+
+	for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
+		if (edid_is_timing_block(block)) {
+			var->xres = var->xres_virtual = H_ACTIVE;
+			var->yres = var->yres_virtual = V_ACTIVE;
+			var->height = var->width = -1;
+			var->right_margin = H_SYNC_OFFSET;
+			var->left_margin = (H_ACTIVE + H_BLANKING) -
+				(H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
+			var->upper_margin = V_BLANKING - V_SYNC_OFFSET -
+				V_SYNC_WIDTH;
+			var->lower_margin = V_SYNC_OFFSET;
+			var->hsync_len = H_SYNC_WIDTH;
+			var->vsync_len = V_SYNC_WIDTH;
+			var->pixclock = PIXEL_CLOCK;
+			var->pixclock /= 1000;
+			var->pixclock = KHZ2PICOS(var->pixclock);
+
+			if (HSYNC_POSITIVE)
+				var->sync |= FB_SYNC_HOR_HIGH_ACT;
+			if (VSYNC_POSITIVE)
+				var->sync |= FB_SYNC_VERT_HIGH_ACT;
+			return 0;
+		}
+	}
+	return 1;
+}
+
+void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
 {
 	unsigned char *block;
 	int i;
@@ -788,83 +747,52 @@ void show_edid(unsigned char *edid)
 
 	if (!(edid_check_header(edid)))
 		return;
-	printk("========================================\n");
-	printk("Display Information (EDID)\n");
-	printk("========================================\n");
-	printk("   EDID Version %d.%d\n", (int) edid[EDID_STRUCT_VERSION],
-	       (int) edid[EDID_STRUCT_REVISION]);
 
-	parse_vendor_block(edid + ID_MANUFACTURER_NAME);
+	memset(specs, 0, sizeof(struct fb_monspecs));
 
-	printk("   Display Characteristics:\n");
-	parse_display_block(edid + EDID_STRUCT_DISPLAY);
+	specs->version = edid[EDID_STRUCT_VERSION];
+	specs->revision = edid[EDID_STRUCT_REVISION];
 
-	printk("   Standard Timings\n");
-	block = edid + STD_TIMING_DESCRIPTIONS_START;
-	for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE) 
-		parse_std_timing_block(block);
+	DPRINTK("========================================\n");
+	DPRINTK("Display Information (EDID)\n");
+	DPRINTK("========================================\n");
+	DPRINTK("   EDID Version %d.%d\n", (int) specs->version,
+	       (int) specs->revision);
 
-	printk("   Supported VESA Modes\n");
-	parse_std_md_block(edid + ESTABLISHED_TIMING_1);
+	parse_vendor_block(edid + ID_MANUFACTURER_NAME, specs);
 
-	printk("   Detailed Monitor Information\n");
 	block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
 	for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
 		if (edid_is_serial_block(block)) {
-			parse_serial_block(block);
+			copy_string(block, specs->serial_no);
+			DPRINTK("   Serial Number: %s\n", specs->serial_no);
 		} else if (edid_is_ascii_block(block)) {
-			parse_ascii_block(block);
-		} else if (edid_is_limits_block(block)) {
-			parse_limits_block(block);
+			copy_string(block, specs->ascii);
+			DPRINTK("   ASCII Block: %s\n", specs->ascii);
 		} else if (edid_is_monitor_block(block)) {
-			parse_monitor_block(block);
-		} else if (edid_is_color_block(block)) {
-			parse_color_block(block);
-		} else if (edid_is_std_timings_block(block)) {
-			parse_dst_timing_block(block);
-		} else if (edid_is_timing_block(block)) {
-			parse_detailed_timing_block(block);
+			copy_string(block, specs->monitor);
+			DPRINTK("   Monitor Name: %s\n", specs->monitor);
 		}
 	}
-	printk("========================================\n");
-}
 
-#ifdef CONFIG_PPC_OF
-char *get_EDID_from_OF(struct pci_dev *pdev)
-{
-	static char *propnames[] =
-	    { "DFP,EDID", "LCD,EDID", "EDID", "EDID1", NULL };
-	unsigned char *pedid = NULL;
-	struct device_node *dp;
-	int i;
+	DPRINTK("   Display Characteristics:\n");
+	get_monspecs(edid, specs);
 
-	if (pdev == NULL)
-		return NULL;
-	dp = pci_device_to_OF_node(pdev);
-	while (dp != NULL) {
-		for (i = 0; propnames[i] != NULL; ++i) {
-			pedid = (unsigned char *) get_property(dp, propnames[i], NULL);
-			if (pedid != NULL)
-				return pedid;
-		}
-		dp = dp->child;
-	}
-	show_edid(pedid);
-	return pedid;
+	specs->modedb = fb_create_modedb(edid, &specs->modedb_len);
+	DPRINTK("========================================\n");
 }
-#endif
 
-#ifdef CONFIG_X86
-char *get_EDID_from_BIOS(void *dummy)
+char *get_EDID_from_firmware(struct device *dev)
 {
-	unsigned char *pedid = edid_info.dummy;
-	
+	unsigned char *pedid = NULL;
+
+#if defined(CONFIG_EDID_FIRMWARE) && defined(CONFIG_X86)
+	pedid = edid_info.dummy;
 	if (!pedid)
 		return NULL;
-	show_edid(pedid);
-	return pedid;				
-}
 #endif
+	return pedid;
+}
 
 /* 
  * VESA Generalized Timing Formula (GTF) 
@@ -1179,7 +1107,7 @@ int fb_get_mode(int flags, u32 val, stru
  * REQUIRES:
  * A valid info->monspecs.
  */
-int fb_validate_mode(struct fb_var_screeninfo *var, struct fb_info *info)
+int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info)
 {
 	u32 hfreq, vfreq, htotal, vtotal, pixclock;
 	u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax;
@@ -1228,16 +1156,12 @@ int fb_validate_mode(struct fb_var_scree
 		-EINVAL : 0;
 }
 
-EXPORT_SYMBOL(parse_edid);
-EXPORT_SYMBOL(show_edid);
-#ifdef CONFIG_X86
-EXPORT_SYMBOL(get_EDID_from_BIOS);
-#endif
-#ifdef CONFIG_PPC_OF
-EXPORT_SYMBOL(get_EDID_from_OF);
-#endif
-EXPORT_SYMBOL(fb_get_monitor_limits);
+EXPORT_SYMBOL(fb_parse_edid);
+EXPORT_SYMBOL(fb_edid_to_monspecs);
+EXPORT_SYMBOL(get_EDID_from_firmware);
+
 EXPORT_SYMBOL(fb_get_mode);
 EXPORT_SYMBOL(fb_validate_mode);
 EXPORT_SYMBOL(fb_create_modedb);
 EXPORT_SYMBOL(fb_destroy_modedb);
+EXPORT_SYMBOL(fb_get_monitor_limits);
--- diff/drivers/video/fm2fb.c	2003-05-21 10:50:16.000000000 +0000
+++ source/drivers/video/fm2fb.c	2004-03-16 09:37:57.593784584 +0000
@@ -49,7 +49,7 @@
  *	not assembled with memory for the alpha channel. In this
  *	case it could be possible to add the frame buffer into the
  *	normal memory pool.
- *	
+ *
  *	At relative address 0x1ffff8 of the frame buffers base address
  *	there exists a control register with the number of
  *	four control bits. They have the following meaning:
@@ -64,7 +64,7 @@
  *	is not very much information about the FrameMaster II in
  *	the world so I add these information for completeness.
  *
- *	JP1  interlace selection (1-2 non interlaced/2-3 interlaced) 
+ *	JP1  interlace selection (1-2 non interlaced/2-3 interlaced)
  *	JP2  wait state creation (leave as is!)
  *	JP3  wait state creation (leave as is!)
  *	JP4  modulate composite sync on green output (1-2 composite
@@ -127,12 +127,7 @@
 
 static volatile unsigned char *fm2fb_reg;
 
-#define arraysize(x)	(sizeof(x)/sizeof(*(x)))
-
-static struct fb_info fb_info;
-static u32 pseudo_palette[17];
-
-static struct fb_fix_screeninfo fb_fix __initdata = {
+static struct fb_fix_screeninfo fb_fix __devinitdata = {
 	.smem_len =	FRAMEMASTER_REG,
 	.type =		FB_TYPE_PACKED_PIXELS,
 	.visual =	FB_VISUAL_TRUECOLOR,
@@ -141,12 +136,12 @@ static struct fb_fix_screeninfo fb_fix _
 	.accel =	FB_ACCEL_NONE,
 };
 
-static int fm2fb_mode __initdata = -1;
+static int fm2fb_mode __devinitdata = -1;
 
 #define FM2FB_MODE_PAL	0
 #define FM2FB_MODE_NTSC	1
 
-static struct fb_var_screeninfo fb_var_modes[] __initdata = {
+static struct fb_var_screeninfo fb_var_modes[] __devinitdata = {
     {
 	/* 768 x 576, 32 bpp (PAL) */
 	768, 576, 768, 576, 0, 0, 32, 0,
@@ -161,11 +156,10 @@ static struct fb_var_screeninfo fb_var_m
 	33333, 10, 102, 10, 5, 80, 34, FB_SYNC_COMP_HIGH_ACT, 0
     }
 };
-    
+
     /*
      *  Interface used by the world
      */
-int fm2fb_init(void);
 
 static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
                            u_int transp, struct fb_info *info);
@@ -174,7 +168,7 @@ static int fm2fb_blank(int blank, struct
 static struct fb_ops fm2fb_ops = {
 	.owner		= THIS_MODULE,
 	.fb_setcolreg	= fm2fb_setcolreg,
-	.fb_blank	= fm2fb_blank,	
+	.fb_blank	= fm2fb_blank,
 	.fb_fillrect	= cfb_fillrect,
 	.fb_copyarea	= cfb_copyarea,
 	.fb_imageblit	= cfb_imageblit,
@@ -202,7 +196,7 @@ static int fm2fb_blank(int blank, struct
 static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
                          u_int transp, struct fb_info *info)
 {
-	if (regno > 15)
+	if (regno > info->cmap.len)
 		return 1;
 	red >>= 8;
 	green >>= 8;
@@ -216,66 +210,91 @@ static int fm2fb_setcolreg(u_int regno, 
      *  Initialisation
      */
 
-int __init fm2fb_init(void)
+static int __devinit fm2fb_probe(struct zorro_dev *z,
+				 const struct zorro_device_id *id);
+
+static struct zorro_device_id fm2fb_devices[] __devinitdata = {
+	{ ZORRO_PROD_BSC_FRAMEMASTER_II },
+	{ ZORRO_PROD_HELFRICH_RAINBOW_II },
+	{ 0 }
+};
+
+static struct zorro_driver fm2fb_driver = {
+	.name		= "fm2fb",
+	.id_table	= fm2fb_devices,
+	.probe		= fm2fb_probe,
+};
+
+static int __devinit fm2fb_probe(struct zorro_dev *z,
+				 const struct zorro_device_id *id)
 {
-	struct zorro_dev *z = NULL;
+	struct fb_info *info;
 	unsigned long *ptr;
 	int is_fm;
 	int x, y;
 
-	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
-		if (z->id == ZORRO_PROD_BSC_FRAMEMASTER_II)
-			is_fm = 1;
-		else if (z->id == ZORRO_PROD_HELFRICH_RAINBOW_II)
-			is_fm = 0;
-		else
-			continue;
-		
-		if (!request_mem_region(z->resource.start, FRAMEMASTER_SIZE, "fm2fb"))
-			continue;
-
-		/* assigning memory to kernel space */
-		fb_fix.smem_start = z->resource.start;
-		fb_info.screen_base = ioremap(fb_fix.smem_start, FRAMEMASTER_SIZE);
-		fb_fix.mmio_start = fb_fix.smem_start + FRAMEMASTER_REG;
-		fm2fb_reg  = (unsigned char *)(fb_info.screen_base+FRAMEMASTER_REG);
-	
-		strcpy(fb_fix.id, is_fm ? "FrameMaster II" : "Rainbow II");
-
-		/* make EBU color bars on display */
-		ptr = (unsigned long *)fb_fix.smem_start;
-		for (y = 0; y < 576; y++) {
-			for (x = 0; x < 96; x++) *ptr++ = 0xffffff;/* white */
-			for (x = 0; x < 96; x++) *ptr++ = 0xffff00;/* yellow */
-			for (x = 0; x < 96; x++) *ptr++ = 0x00ffff;/* cyan */
-			for (x = 0; x < 96; x++) *ptr++ = 0x00ff00;/* green */
-			for (x = 0; x < 96; x++) *ptr++ = 0xff00ff;/* magenta */
-			for (x = 0; x < 96; x++) *ptr++ = 0xff0000;/* red */
-			for (x = 0; x < 96; x++) *ptr++ = 0x0000ff;/* blue */
-			for (x = 0; x < 96; x++) *ptr++ = 0x000000;/* black */
-		}
-		fm2fb_blank(0, NULL);
+	is_fm = z->id == ZORRO_PROD_BSC_FRAMEMASTER_II;
 
-		if (fm2fb_mode == -1)
-			fm2fb_mode = FM2FB_MODE_PAL;
+	if (!zorro_request_device(z,"fm2fb"))
+		return -ENXIO;
 
-		fb_info.fbops = &fm2fb_ops;
-		fb_info.var = fb_var_modes[fm2fb_mode];
-		fb_info.screen_base = (char *)fb_fix.smem_start;
-		fb_info.pseudo_palette = pseudo_palette;
-		fb_info.fix = fb_fix;
-		fb_info.flags = FBINFO_FLAG_DEFAULT;
+	info = framebuffer_alloc(256 * sizeof(u32), &z->dev);
+	if (!info) {
+		zorro_release_device(z);
+		return -ENOMEM;
+	}
 
-		/* The below fields will go away !!!! */
-		fb_alloc_cmap(&fb_info.cmap, 16, 0);
+	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+		framebuffer_release(info);
+		zorro_release_device(z);
+		return -ENOMEM;
+	}
 
-		if (register_framebuffer(&fb_info) < 0)
-			return -EINVAL;
+	/* assigning memory to kernel space */
+	fb_fix.smem_start = zorro_resource_start(z);
+	info->screen_base = ioremap(fb_fix.smem_start, FRAMEMASTER_SIZE);
+	fb_fix.mmio_start = fb_fix.smem_start + FRAMEMASTER_REG;
+	fm2fb_reg  = (unsigned char *)(info->screen_base+FRAMEMASTER_REG);
+
+	strcpy(fb_fix.id, is_fm ? "FrameMaster II" : "Rainbow II");
+
+	/* make EBU color bars on display */
+	ptr = (unsigned long *)fb_fix.smem_start;
+	for (y = 0; y < 576; y++) {
+		for (x = 0; x < 96; x++) *ptr++ = 0xffffff;/* white */
+		for (x = 0; x < 96; x++) *ptr++ = 0xffff00;/* yellow */
+		for (x = 0; x < 96; x++) *ptr++ = 0x00ffff;/* cyan */
+		for (x = 0; x < 96; x++) *ptr++ = 0x00ff00;/* green */
+		for (x = 0; x < 96; x++) *ptr++ = 0xff00ff;/* magenta */
+		for (x = 0; x < 96; x++) *ptr++ = 0xff0000;/* red */
+		for (x = 0; x < 96; x++) *ptr++ = 0x0000ff;/* blue */
+		for (x = 0; x < 96; x++) *ptr++ = 0x000000;/* black */
+	}
+	fm2fb_blank(0, info);
 
-		printk("fb%d: %s frame buffer device\n", fb_info.node, fb_fix.id);
-		return 0;
+	if (fm2fb_mode == -1)
+		fm2fb_mode = FM2FB_MODE_PAL;
+
+	info->fbops = &fm2fb_ops;
+	info->var = fb_var_modes[fm2fb_mode];
+	info->pseudo_palette = info->par;
+	info->par = NULL;
+	info->fix = fb_fix;
+	info->flags = FBINFO_FLAG_DEFAULT;
+
+	if (register_framebuffer(info) < 0) {
+		fb_dealloc_cmap(&info->cmap);
+		framebuffer_release(info);
+		zorro_release_device(z);
+		return -EINVAL;
 	}
-	return -ENXIO;
+	printk("fb%d: %s frame buffer device\n", info->node, fb_fix.id);
+	return 0;
+}
+
+int __init fm2fb_init(void)
+{
+	return zorro_register_driver(&fm2fb_driver);
 }
 
 int __init fm2fb_setup(char *options)
@@ -285,7 +304,7 @@ int __init fm2fb_setup(char *options)
 	if (!options || !*options)
 		return 0;
 
-	while ((this_opt = strsep(&options, ",")) != NULL) {	
+	while ((this_opt = strsep(&options, ",")) != NULL) {
 		if (!strncmp(this_opt, "pal", 3))
 			fm2fb_mode = FM2FB_MODE_PAL;
 		else if (!strncmp(this_opt, "ntsc", 4))
--- diff/drivers/video/i810/i810_main.h	2003-09-30 14:46:18.000000000 +0000
+++ source/drivers/video/i810/i810_main.h	2004-03-16 09:37:57.593784584 +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/drivers/video/modedb.c	2003-05-21 10:50:10.000000000 +0000
+++ source/drivers/video/modedb.c	2004-03-16 09:37:57.595784280 +0000
@@ -39,7 +39,7 @@ const char *global_mode_option = NULL;
 
 #define DEFAULT_MODEDB_INDEX	0
 
-static const struct fb_videomode modedb[] __initdata = {
+static const struct fb_videomode modedb[] = {
     {
 	/* 640x400 @ 70 Hz, 31.5 kHz hsync */
 	NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2,
@@ -130,11 +130,11 @@ static const struct fb_videomode modedb[
 	0, FB_VMODE_NONINTERLACED   	
     }, {
 	/* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/
-	"LCD_XGA_75", 75, 1400, 1050, 9271, 120, 56, 13, 0, 112, 3,
+	NULL, 75, 1400, 1050, 9271, 120, 56, 13, 0, 112, 3,
 	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
     }, {
 	/* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/
-	"LCD_XGA_60", 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3,
+        NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3,
 	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
     }, {
 	/* 1024x768 @ 85 Hz, 70.24 kHz hsync */
@@ -254,109 +254,128 @@ static const struct fb_videomode modedb[
 const struct fb_videomode vesa_modes[] = {
 	/* 0 640x350-85 VESA */
 	{ NULL, 85, 640, 350, 31746,  96, 32, 60, 32, 64, 3,
-	  FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA},
 	/* 1 640x400-85 VESA */
 	{ NULL, 85, 640, 400, 31746,  96, 32, 41, 01, 64, 3,
-	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 2 720x400-85 VESA */
 	{ NULL, 85, 721, 400, 28169, 108, 36, 42, 01, 72, 3,
-	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 3 640x480-60 VESA */
 	{ NULL, 60, 640, 480, 39682,  48, 16, 33, 10, 96, 2, 
-	  0, FB_VMODE_NONINTERLACED },
+	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 4 640x480-72 VESA */
 	{ NULL, 72, 640, 480, 31746, 128, 24, 29, 9, 40, 2, 
-	  0, FB_VMODE_NONINTERLACED },
+	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 5 640x480-75 VESA */
 	{ NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3,
-	  0, FB_VMODE_NONINTERLACED },
+	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 6 640x480-85 VESA */
 	{ NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3,
-	  0, FB_VMODE_NONINTERLACED },
+	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 7 800x600-56 VESA */
 	{ NULL, 56, 800, 600, 27777, 128, 24, 22, 01, 72, 2,
-	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 8 800x600-60 VESA */
 	{ NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4,
-	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 9 800x600-72 VESA */
 	{ NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
-	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 10 800x600-75 VESA */
 	{ NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3,
-	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 11 800x600-85 VESA */
 	{ NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3,
-	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
         /* 12 1024x768i-43 VESA */
 	{ NULL, 53, 1024, 768, 22271, 56, 8, 41, 0, 176, 8,
-	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_INTERLACED, FB_MODE_IS_VESA },
 	/* 13 1024x768-60 VESA */
 	{ NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6,
-	  0, FB_VMODE_NONINTERLACED },
+	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 14 1024x768-70 VESA */
 	{ NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6,
-	  0, FB_VMODE_NONINTERLACED },
+	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 15 1024x768-75 VESA */
 	{ NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3,
-	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 16 1024x768-85 VESA */
 	{ NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3,
-	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 17 1152x864-75 VESA */
 	{ NULL, 75, 1153, 864, 9259, 256, 64, 32, 1, 128, 3,
-	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 18 1280x960-60 VESA */
 	{ NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3,
-	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 19 1280x960-85 VESA */
 	{ NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3,
-	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 20 1280x1024-60 VESA */
 	{ NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
-	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 21 1280x1024-75 VESA */
 	{ NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3,
-	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 22 1280x1024-85 VESA */
 	{ NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
-	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 23 1600x1200-60 VESA */
 	{ NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
-	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 24 1600x1200-65 VESA */
 	{ NULL, 65, 1600, 1200, 5698, 304,  64, 46, 1, 192, 3,
-	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 25 1600x1200-70 VESA */
 	{ NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3,
-	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 26 1600x1200-75 VESA */
 	{ NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, 
-	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 27 1600x1200-85 VESA */
 	{ NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3,
-	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 28 1792x1344-60 VESA */
 	{ NULL, 60, 1792, 1344, 4882, 328, 128, 46, 1, 200, 3,
-	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 29 1792x1344-75 VESA */
 	{ NULL, 75, 1792, 1344, 3831, 352, 96, 69, 1, 216, 3,
-	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 30 1856x1392-60 VESA */
 	{ NULL, 60, 1856, 1392, 4580, 352, 96, 43, 1, 224, 3,
-	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 31 1856x1392-75 VESA */
 	{ NULL, 75, 1856, 1392, 3472, 352, 128, 104, 1, 224, 3,
-	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 32 1920x1440-60 VESA */
 	{ NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 200, 3,
-	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 	/* 33 1920x1440-75 VESA */
 	{ NULL, 60, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
-	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
 };
 
-static int __init my_atoi(const char *name)
+static int my_atoi(const char *name)
 {
     int val = 0;
 
@@ -447,11 +466,11 @@ int __fb_try_mode(struct fb_var_screenin
  *
  */
 
-int __init fb_find_mode(struct fb_var_screeninfo *var,
-			struct fb_info *info, const char *mode_option,
-			const struct fb_videomode *db, unsigned int dbsize,
-			const struct fb_videomode *default_mode,
-			unsigned int default_bpp)
+int fb_find_mode(struct fb_var_screeninfo *var,
+		 struct fb_info *info, const char *mode_option,
+		 const struct fb_videomode *db, unsigned int dbsize,
+		 const struct fb_videomode *default_mode,
+		 unsigned int default_bpp)
 {
     int i, j;
 
@@ -535,5 +554,5 @@ done:
     return 0;
 }
 
-EXPORT_SYMBOL(__fb_try_mode);
 EXPORT_SYMBOL(vesa_modes);
+EXPORT_SYMBOL(fb_find_mode);
--- diff/fs/Kconfig	2004-03-11 10:20:28.000000000 +0000
+++ source/fs/Kconfig	2004-03-16 09:37:57.596784128 +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-11 10:20:28.000000000 +0000
+++ source/fs/Makefile	2004-03-16 09:37:57.597783976 +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	2004-03-11 10:20:28.000000000 +0000
+++ source/fs/adfs/super.c	2004-03-16 09:37:57.598783824 +0000
@@ -335,6 +335,8 @@ static int adfs_fill_super(struct super_
 	struct adfs_sb_info *asb;
 	struct inode *root;
 
+	sb->s_flags |= MS_NODIRATIME;
+
 	asb = kmalloc(sizeof(*asb), GFP_KERNEL);
 	if (!asb)
 		return -ENOMEM;
--- diff/fs/affs/super.c	2003-10-09 08:47:34.000000000 +0000
+++ source/fs/affs/super.c	2004-03-16 09:37:57.599783672 +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-11 10:20:28.000000000 +0000
+++ source/fs/afs/inode.c	2004-03-16 09:37:57.599783672 +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-03-11 10:20:28.000000000 +0000
+++ source/fs/afs/super.c	2004-03-16 09:37:57.600783520 +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 = {
--- diff/fs/bfs/dir.c	2003-10-09 08:47:17.000000000 +0000
+++ source/fs/bfs/dir.c	2004-03-16 09:37:57.600783520 +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 14:46:18.000000000 +0000
+++ source/fs/binfmt_aout.c	2004-03-16 09:37:57.601783368 +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-11 10:20:28.000000000 +0000
+++ source/fs/binfmt_elf.c	2004-03-16 09:37:57.602783216 +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);
 	}
@@ -1130,7 +1129,7 @@ static void fill_prstatus(struct elf_prs
 	prstatus->pr_pid = p->pid;
 	prstatus->pr_ppid = p->parent->pid;
 	prstatus->pr_pgrp = process_group(p);
-	prstatus->pr_sid = p->session;
+	prstatus->pr_sid = p->signal->session;
 	jiffies_to_timeval(p->utime, &prstatus->pr_utime);
 	jiffies_to_timeval(p->stime, &prstatus->pr_stime);
 	jiffies_to_timeval(p->cutime, &prstatus->pr_cutime);
@@ -1158,7 +1157,7 @@ static void fill_psinfo(struct elf_prpsi
 	psinfo->pr_pid = p->pid;
 	psinfo->pr_ppid = p->parent->pid;
 	psinfo->pr_pgrp = process_group(p);
-	psinfo->pr_sid = p->session;
+	psinfo->pr_sid = p->signal->session;
 
 	i = p->state ? ffz(~p->state) + 1 : 0;
 	psinfo->pr_state = i;
--- diff/fs/binfmt_flat.c	2004-03-11 10:20:28.000000000 +0000
+++ source/fs/binfmt_flat.c	2004-03-16 09:37:57.602783216 +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-11 10:20:28.000000000 +0000
+++ source/fs/binfmt_misc.c	2004-03-16 09:37:57.603783064 +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-16 09:37:57.604782912 +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-11 10:20:28.000000000 +0000
+++ source/fs/block_dev.c	2004-03-16 09:37:57.605782760 +0000
@@ -116,9 +116,18 @@ static int
 blkdev_get_block(struct inode *inode, sector_t iblock,
 		struct buffer_head *bh, int create)
 {
-	if (iblock >= max_block(I_BDEV(inode)))
-		return -EIO;
-
+	if (iblock >= max_block(I_BDEV(inode))) {
+		if (create)
+			return -EIO;
+
+		/*
+		 * for reads, we're just trying to fill a partial page.
+		 * return a hole, they will have to call get_block again
+		 * before they can fill it, and they will get -EIO at that
+		 * time
+		 */
+		return 0;
+	}
 	bh->b_bdev = I_BDEV(inode);
 	bh->b_blocknr = iblock;
 	set_buffer_mapped(bh);
@@ -146,8 +155,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 +531,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 +544,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 +796,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-11 10:20:28.000000000 +0000
+++ source/fs/buffer.c	2004-03-16 09:37:57.608782304 +0000
@@ -132,7 +132,7 @@ void __wait_on_buffer(struct buffer_head
 	do {
 		prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
 		if (buffer_locked(bh)) {
-			blk_run_queues();
+			blk_run_address_space(bh->b_bdev->bd_inode->i_mapping);
 			io_schedule();
 		}
 	} while (buffer_locked(bh));
@@ -396,7 +396,7 @@ out:
  * Hack idea: for the blockdev mapping, i_bufferlist_lock contention
  * may be quite high.  This code could TryLock the page, and if that
  * succeeds, there is no need to take private_lock. (But if
- * private_lock is contended then so is mapping->page_lock).
+ * private_lock is contended then so is mapping->tree_lock).
  */
 static struct buffer_head *
 __find_get_block_slow(struct block_device *bdev, sector_t block, int unused)
@@ -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);
@@ -490,7 +491,6 @@ static void free_more_memory(void)
 	pg_data_t *pgdat;
 
 	wakeup_bdflush(1024);
-	blk_run_queues();
 	yield();
 
 	for_each_pgdat(pgdat) {
@@ -825,12 +825,6 @@ EXPORT_SYMBOL(mark_buffer_dirty_inode);
  * bit, see a bunch of clean buffers and we'd end up with dirty buffers/clean
  * page on the dirty page list.
  *
- * There is also a small window where the page is dirty, and not on dirty_pages.
- * Also a possibility that by the time the page is added to dirty_pages, it has
- * been set clean.  The page lists are somewhat approximate in this regard.
- * It's better to have clean pages accidentally attached to dirty_pages than to
- * leave dirty pages attached to clean_pages.
- *
  * We use private_lock to lock against try_to_free_buffers while using the
  * page's buffer list.  Also use this to protect against clean buffers being
  * added to the page after it was set dirty.
@@ -857,24 +851,28 @@ 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);
 	}
 	spin_unlock(&mapping->private_lock);
 
 	if (!TestSetPageDirty(page)) {
-		spin_lock(&mapping->page_lock);
+		spin_lock_irq(&mapping->tree_lock);
 		if (page->mapping) {	/* Race with truncate? */
 			if (!mapping->backing_dev_info->memory_backed)
 				inc_page_state(nr_dirty);
-			list_del(&page->list);
-			list_add(&page->list, &mapping->dirty_pages);
+			radix_tree_tag_set(&mapping->page_tree, page->index,
+						PAGECACHE_TAG_DIRTY);
 		}
-		spin_unlock(&mapping->page_lock);
+		spin_unlock_irq(&mapping->tree_lock);
 		__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
 	}
 	
@@ -1226,7 +1224,7 @@ __getblk_slow(struct block_device *bdev,
  * The relationship between dirty buffers and dirty pages:
  *
  * Whenever a page has any dirty buffers, the page's dirty bit is set, and
- * the page appears on its address_space.dirty_pages list.
+ * the page is tagged dirty in its radix tree.
  *
  * At all times, the dirtiness of the buffers represents the dirtiness of
  * subsections of the page.  If the page has buffers, the page dirty bit is
@@ -1248,13 +1246,13 @@ __getblk_slow(struct block_device *bdev,
 /**
  * mark_buffer_dirty - mark a buffer_head as needing writeout
  *
- * mark_buffer_dirty() will set the dirty bit against the buffer,
- * then set its backing page dirty, then attach the page to its
- * address_space's dirty_pages list and then attach the address_space's
- * inode to its superblock's dirty inode list.
+ * mark_buffer_dirty() will set the dirty bit against the buffer, then set its
+ * backing page dirty, then tag the page as dirty in its address_space's radix
+ * tree and then attach the address_space's inode to its superblock's dirty
+ * inode list.
  *
  * mark_buffer_dirty() is atomic.  It takes bh->b_page->mapping->private_lock,
- * mapping->page_lock and the global inode_lock.
+ * mapping->tree_lock and the global inode_lock.
  */
 void fastcall mark_buffer_dirty(struct buffer_head *bh)
 {
@@ -1806,27 +1804,28 @@ 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)) {
+		if (!buffer_mapped(bh))
+			continue;
+		if (wbc->sync_mode != WB_SYNC_NONE) {
+			lock_buffer(bh);
+		} else {
+			if (test_set_buffer_locked(bh)) {
+				if (buffer_dirty(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);
+				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));
-	SetPageWriteback(page);		/* Keeps try_to_free_buffers() away */
+	set_page_writeback(page);	/* Keeps try_to_free_buffers() away */
 	unlock_page(page);
 
 	/*
@@ -1889,7 +1888,7 @@ recover:
 	} while ((bh = bh->b_this_page) != head);
 	SetPageError(page);
 	BUG_ON(PageWriteback(page));
-	SetPageWriteback(page);
+	set_page_writeback(page);
 	unlock_page(page);
 	do {
 		struct buffer_head *next = bh->b_this_page;
@@ -2924,7 +2923,10 @@ EXPORT_SYMBOL(try_to_free_buffers);
 
 int block_sync_page(struct page *page)
 {
-	blk_run_queues();
+	struct address_space *mapping;
+	smp_mb();
+	mapping = page->mapping;
+	blk_run_address_space(mapping);
 	return 0;
 }
 
--- diff/fs/char_dev.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/char_dev.c	2004-03-16 09:37:57.609782152 +0000
@@ -340,15 +340,9 @@ static int exact_lock(dev_t dev, void *d
 
 int cdev_add(struct cdev *p, dev_t dev, unsigned count)
 {
-	int err = kobject_add(&p->kobj);
-	if (err)
-		return err;
-	err = kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
-	if (err)
-		kobject_del(&p->kobj);
 	p->dev = dev;
 	p->count = count;
-	return err;
+	return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
 }
 
 static void cdev_unmap(dev_t dev, unsigned count)
@@ -359,7 +353,6 @@ static void cdev_unmap(dev_t dev, unsign
 void cdev_del(struct cdev *p)
 {
 	cdev_unmap(p->dev, p->count);
-	kobject_del(&p->kobj);
 	kobject_put(&p->kobj);
 }
 
@@ -407,18 +400,12 @@ static struct kobj_type ktype_cdev_dynam
 	.release	= cdev_dynamic_release,
 };
 
-static struct kset kset_dynamic = {
-	.subsys = &cdev_subsys,
-	.kobj = {.name = "major",},
-	.ktype = &ktype_cdev_dynamic,
-};
-
 struct cdev *cdev_alloc(void)
 {
 	struct cdev *p = kmalloc(sizeof(struct cdev), GFP_KERNEL);
 	if (p) {
 		memset(p, 0, sizeof(struct cdev));
-		p->kobj.kset = &kset_dynamic;
+		p->kobj.ktype = &ktype_cdev_dynamic;
 		INIT_LIST_HEAD(&p->list);
 		kobject_init(&p->kobj);
 	}
@@ -428,7 +415,6 @@ struct cdev *cdev_alloc(void)
 void cdev_init(struct cdev *cdev, struct file_operations *fops)
 {
 	INIT_LIST_HEAD(&cdev->list);
-	kobj_set_kset_s(cdev, cdev_subsys);
 	cdev->kobj.ktype = &ktype_cdev_default;
 	kobject_init(&cdev->kobj);
 	cdev->ops = fops;
@@ -444,8 +430,12 @@ static struct kobject *base_probe(dev_t 
 
 void __init chrdev_init(void)
 {
-	subsystem_register(&cdev_subsys);
-	kset_register(&kset_dynamic);
+/*
+ * Keep cdev_subsys around because (and only because) the kobj_map code
+ * depends on the rwsem it contains.  We don't make it public in sysfs,
+ * however.
+ */
+	subsystem_init(&cdev_subsys);
 	cdev_map = kobj_map_init(base_probe, &cdev_subsys);
 }
 
--- diff/fs/cifs/cifsfs.c	2003-10-27 09:20:44.000000000 +0000
+++ source/fs/cifs/cifsfs.c	2004-03-16 09:37:57.610782000 +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/cifs/file.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/cifs/file.c	2004-03-16 09:37:57.611781848 +0000
@@ -898,11 +898,9 @@ static void cifs_copy_cache_pages(struct
 		if(list_empty(pages))
 			break;
 
-		spin_lock(&mapping->page_lock);
-		page = list_entry(pages->prev, struct page, list);
+		page = list_entry(pages->prev, struct page, lru);
 
-		list_del(&page->list);
-		spin_unlock(&mapping->page_lock);
+		list_del(&page->lru);
 
 		if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) {
 			page_cache_release(page);
@@ -962,14 +960,10 @@ cifs_readpages(struct file *file, struct
 	pagevec_init(&lru_pvec, 0);
 
 	for(i = 0;i<num_pages;) {
-		spin_lock(&mapping->page_lock);
-		if(list_empty(page_list)) {
-			spin_unlock(&mapping->page_lock);
+		if(list_empty(page_list))
 			break;
-		}
-		page = list_entry(page_list->prev, struct page, list);
+		page = list_entry(page_list->prev, struct page, lru);
 		offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
-	        spin_unlock(&mapping->page_lock);
 
 		/* for reads over a certain size could initiate async read ahead */
 
@@ -989,12 +983,11 @@ cifs_readpages(struct file *file, struct
 			cFYI(1,("Read error in readpages: %d",rc));
 			/* clean up remaing pages off list */
             
-			spin_lock(&mapping->page_lock);
 			while (!list_empty(page_list) && (i < num_pages)) {
-				page = list_entry(page_list->prev, struct page, list);
-				list_del(&page->list);
+				page = list_entry(page_list->prev,
+						struct page, lru);
+				list_del(&page->lru);
 			}
-			spin_unlock(&mapping->page_lock);
 			break;
 		} else if (bytes_read > 0) {
 			pSMBr = (struct smb_com_read_rsp *)smb_read_data;
@@ -1010,8 +1003,9 @@ cifs_readpages(struct file *file, struct
 			cFYI(1,("No bytes read cleaning remaining pages off readahead list"));
 			/* BB turn off caching and do new lookup on file size at server? */
 			while (!list_empty(page_list) && (i < num_pages)) {
-				page = list_entry(page_list->prev, struct page, list);
-				list_del(&page->list);
+				page = list_entry(page_list->prev,
+						struct page, lru);
+				list_del(&page->lru);
 			}
 
 			break;
--- diff/fs/coda/dir.c	2003-09-30 14:46:18.000000000 +0000
+++ source/fs/coda/dir.c	2004-03-16 09:37:57.612781696 +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	2004-03-11 10:20:28.000000000 +0000
+++ source/fs/coda/inode.c	2004-03-16 09:37:57.613781544 +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;
@@ -308,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/compat_ioctl.c	2004-03-11 10:20:28.000000000 +0000
+++ source/fs/compat_ioctl.c	2004-03-16 09:37:57.615781240 +0000
@@ -1604,7 +1604,7 @@ static int vt_check(struct file *file)
 	 * To have permissions to do most of the vt ioctls, we either have
 	 * to be the owner of the tty, or super-user.
 	 */
-	if (current->tty == tty || capable(CAP_SYS_ADMIN))
+	if (current->signal->tty == tty || capable(CAP_SYS_ADMIN))
 		return 1;
 	return 0;                                                    
 }
--- diff/fs/cramfs/inode.c	2004-03-11 10:20:28.000000000 +0000
+++ source/fs/cramfs/inode.c	2004-03-16 09:37:57.615781240 +0000
@@ -201,6 +201,8 @@ static int cramfs_fill_super(struct supe
 	struct cramfs_sb_info *sbi;
 	struct inode *root;
 
+	sb->s_flags |= MS_RDONLY;
+
 	sbi = kmalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL);
 	if (!sbi)
 		return -ENOMEM;
--- diff/fs/direct-io.c	2004-01-19 10:22:59.000000000 +0000
+++ source/fs/direct-io.c	2004-03-16 09:37:57.617780936 +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);
-			blk_run_queues();
+			spin_unlock_irqrestore(&dio->bio_lock, flags);
+			blk_run_address_space(dio->inode->i_mapping);
 			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();
+		blk_run_address_space(inode->i_mapping);
+		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-16 09:37:57.621780328 +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);
+}
+EXPORT_SYMBOL(mark_info_dirty);
+
+/*
+ *	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)
@@ -674,12 +771,12 @@ static void print_warning(struct dquot *
 
 	if (!need_print_warning(dquot) || (flag && test_and_set_bit(flag, &dquot->dq_flags)))
 		return;
-	tty_write_message(current->tty, dquot->dq_sb->s_id);
+	tty_write_message(current->signal->tty, dquot->dq_sb->s_id);
 	if (warntype == ISOFTWARN || warntype == BSOFTWARN)
-		tty_write_message(current->tty, ": warning, ");
+		tty_write_message(current->signal->tty, ": warning, ");
 	else
-		tty_write_message(current->tty, ": write failed, ");
-	tty_write_message(current->tty, quotatypes[dquot->dq_type]);
+		tty_write_message(current->signal->tty, ": write failed, ");
+	tty_write_message(current->signal->tty, quotatypes[dquot->dq_type]);
 	switch (warntype) {
 		case IHARDWARN:
 			msg = " file limit reached.\n";
@@ -700,7 +797,7 @@ static void print_warning(struct dquot *
 			msg = " block quota exceeded.\n";
 			break;
 	}
-	tty_write_message(current->tty, msg);
+	tty_write_message(current->signal->tty, msg);
 }
 
 static inline void flush_warnings(struct dquot **dquots, char *warntype)
@@ -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/exec.c	2004-03-11 10:20:28.000000000 +0000
+++ source/fs/exec.c	2004-03-16 09:37:57.622780176 +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 */
@@ -601,6 +601,11 @@ static inline int de_thread(struct task_
 		newsig->group_stop_count = 0;
 		newsig->curr_target = NULL;
 		init_sigpending(&newsig->shared_pending);
+
+		newsig->pgrp = oldsig->pgrp;
+		newsig->session = oldsig->session;
+		newsig->leader = oldsig->leader;
+		newsig->tty_old_pgrp = oldsig->tty_old_pgrp;
 	}
 
 	if (thread_group_empty(current))
@@ -833,7 +838,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 +1112,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-11 10:20:28.000000000 +0000
+++ source/fs/ext2/acl.c	2004-03-16 09:37:57.622780176 +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 13:18:20.000000000 +0000
+++ source/fs/ext2/dir.c	2004-03-16 09:37:57.623780024 +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/ext3/acl.c	2004-03-11 10:20:28.000000000 +0000
+++ source/fs/ext3/acl.c	2004-03-16 09:37:57.624779872 +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 09:07:34.000000000 +0000
+++ source/fs/ext3/dir.c	2004-03-16 09:37:57.624779872 +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/inode.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/ext3/inode.c	2004-03-16 09:37:57.626779568 +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-16 09:37:57.628779264 +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-11 10:20:28.000000000 +0000
+++ source/fs/ext3/super.c	2004-03-16 09:37:57.631778808 +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 */
 }
 
@@ -1117,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;
@@ -1296,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;
@@ -1406,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:
@@ -1832,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)
@@ -1952,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 (*old_write_dquot)(struct dquot *dquot);
+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 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,
@@ -2015,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-16 09:37:57.632778656 +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/freevxfs/vxfs_super.c	2004-03-11 10:20:28.000000000 +0000
+++ source/fs/freevxfs/vxfs_super.c	2004-03-16 09:37:57.633778504 +0000
@@ -145,6 +145,8 @@ static int vxfs_fill_super(struct super_
 	u_long			bsize;
 	struct inode *root;
 
+	sbp->s_flags |= MS_RDONLY;
+
 	infp = kmalloc(sizeof(*infp), GFP_KERNEL);
 	if (!infp) {
 		printk(KERN_WARNING "vxfs: unable to allocate incore superblock\n");
--- diff/fs/fs-writeback.c	2004-03-11 10:20:28.000000000 +0000
+++ source/fs/fs-writeback.c	2004-03-16 09:37:57.633778504 +0000
@@ -123,12 +123,6 @@ static void write_inode(struct inode *in
  * starvation of particular inodes when others are being redirtied, prevent
  * livelocks, etc.
  *
- * So what we do is to move all pages which are to be written from dirty_pages
- * onto io_pages.  And keep on writing io_pages until it's empty.  Refusing to
- * move more pages onto io_pages until io_pages is empty.  Once that point has
- * been reached, we are ready to take another pass across the inode's dirty
- * pages.
- *
  * Called under inode_lock.
  */
 static void
@@ -152,10 +146,6 @@ __sync_single_inode(struct inode *inode,
 	 * read speculatively by this cpu before &= ~I_DIRTY  -- mikulas
 	 */
 
-	spin_lock(&mapping->page_lock);
-	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);
@@ -170,10 +160,7 @@ __sync_single_inode(struct inode *inode,
 	spin_lock(&inode_lock);
 	inode->i_state &= ~I_LOCK;
 	if (!(inode->i_state & I_FREEING)) {
-		if (!list_empty(&mapping->io_pages)) {
-		 	/* Needs more writeback */
-			inode->i_state |= I_DIRTY_PAGES;
-		} else if (!list_empty(&mapping->dirty_pages)) {
+		if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
 			/* Redirtied */
 			inode->i_state |= I_DIRTY_PAGES;
 			mapping->dirtied_when = jiffies;
--- diff/fs/hfs/super.c	2004-03-11 10:20:28.000000000 +0000
+++ source/fs/hfs/super.c	2004-03-16 09:37:57.634778352 +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);
--- diff/fs/hpfs/buffer.c	2004-03-11 10:20:28.000000000 +0000
+++ source/fs/hpfs/buffer.c	2004-03-16 09:37:57.634778352 +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 08:47:34.000000000 +0000
+++ source/fs/hpfs/hpfs_fn.h	2004-03-16 09:37:57.635778200 +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 08:47:17.000000000 +0000
+++ source/fs/hpfs/namei.c	2004-03-16 09:37:57.637777896 +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/hugetlbfs/inode.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/hugetlbfs/inode.c	2004-03-16 09:37:57.637777896 +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-11 10:20:28.000000000 +0000
+++ source/fs/inode.c	2004-03-16 09:37:57.639777592 +0000
@@ -176,15 +176,12 @@ void inode_init_once(struct inode *inode
 {
 	memset(inode, 0, sizeof(*inode));
 	INIT_HLIST_NODE(&inode->i_hash);
-	INIT_LIST_HEAD(&inode->i_data.clean_pages);
-	INIT_LIST_HEAD(&inode->i_data.dirty_pages);
-	INIT_LIST_HEAD(&inode->i_data.locked_pages);
-	INIT_LIST_HEAD(&inode->i_data.io_pages);
 	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);
+	spin_lock_init(&inode->i_data.tree_lock);
 	init_MUTEX(&inode->i_data.i_shared_sem);
 	atomic_set(&inode->i_data.truncate_count, 0);
 	INIT_LIST_HEAD(&inode->i_data.private_list);
@@ -285,7 +282,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 +295,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 +336,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 +436,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 +547,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 +596,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 +645,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 +981,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);
@@ -1031,6 +1029,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);
@@ -1178,6 +1177,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 +1215,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-11 10:20:28.000000000 +0000
+++ source/fs/jffs/inode-v23.c	2004-03-16 09:37:57.641777288 +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-16 09:37:57.641777288 +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/jfs/jfs_logmgr.c	2004-03-11 10:20:28.000000000 +0000
+++ source/fs/jfs/jfs_logmgr.c	2004-03-16 09:37:57.643776984 +0000
@@ -1972,8 +1972,7 @@ static int lbmRead(struct jfs_log * log,
 
 	bio->bi_end_io = lbmIODone;
 	bio->bi_private = bp;
-	submit_bio(READ, bio);
-	blk_run_queues();
+	submit_bio(READ_SYNC, bio);
 
 	wait_event(bp->l_ioevent, (bp->l_flag != lbmREAD));
 
@@ -2117,9 +2116,8 @@ static void lbmStartIO(struct lbuf * bp)
 
 	/* check if journaling to disk has been disabled */
 	if (!log->no_integrity) {
-		submit_bio(WRITE, bio);
+		submit_bio(WRITE_SYNC, bio);
 		INCREMENT(lmStat.submitted);
-		blk_run_queues();
 	}
 	else {
 		bio->bi_size = 0;
--- diff/fs/libfs.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/libfs.c	2004-03-16 09:37:57.644776832 +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	2004-03-11 10:20:28.000000000 +0000
+++ source/fs/lockd/clntproc.c	2004-03-16 09:37:57.645776680 +0000
@@ -443,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 13:18:20.000000000 +0000
+++ source/fs/lockd/host.c	2004-03-16 09:37:57.645776680 +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 13:18:20.000000000 +0000
+++ source/fs/lockd/mon.c	2004-03-16 09:37:57.646776528 +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 03:27:53.000000000 +0000
+++ source/fs/lockd/svc4proc.c	2004-03-16 09:37:57.646776528 +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 10:49:50.000000000 +0000
+++ source/fs/lockd/svclock.c	2004-03-16 09:37:57.647776376 +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 03:28:28.000000000 +0000
+++ source/fs/lockd/svcproc.c	2004-03-16 09:37:57.648776224 +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 13:18:20.000000000 +0000
+++ source/fs/minix/dir.c	2004-03-16 09:37:57.648776224 +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/mpage.c	2003-08-26 09:00:54.000000000 +0000
+++ source/fs/mpage.c	2004-03-16 09:37:57.650775920 +0000
@@ -329,10 +329,10 @@ mpage_readpages(struct address_space *ma
 
 	pagevec_init(&lru_pvec, 0);
 	for (page_idx = 0; page_idx < nr_pages; page_idx++) {
-		struct page *page = list_entry(pages->prev, struct page, list);
+		struct page *page = list_entry(pages->prev, struct page, lru);
 
 		prefetchw(&page->flags);
-		list_del(&page->list);
+		list_del(&page->lru);
 		if (!add_to_page_cache(page, mapping,
 					page->index, GFP_KERNEL)) {
 			bio = do_mpage_readpage(bio, page,
@@ -546,7 +546,7 @@ alloc_new:
 	}
 
 	BUG_ON(PageWriteback(page));
-	SetPageWriteback(page);
+	set_page_writeback(page);
 	unlock_page(page);
 	if (boundary || (first_unmapped != blocks_per_page)) {
 		bio = mpage_bio_submit(WRITE, bio);
@@ -589,31 +589,13 @@ out:
  * This is a library function, which implements the writepages()
  * address_space_operation.
  *
- * (The next two paragraphs refer to code which isn't here yet, but they
- *  explain the presence of address_space.io_pages)
- *
- * Pages can be moved from clean_pages or locked_pages onto dirty_pages
- * at any time - it's not possible to lock against that.  So pages which
- * have already been added to a BIO may magically reappear on the dirty_pages
- * list.  And mpage_writepages() will again try to lock those pages.
- * But I/O has not yet been started against the page.  Thus deadlock.
- *
- * To avoid this, mpage_writepages() will only write pages from io_pages. The
- * caller must place them there.  We walk io_pages, locking the pages and
- * submitting them for I/O, moving them to locked_pages.
- *
- * This has the added benefit of preventing a livelock which would otherwise
- * occur if pages are being dirtied faster than we can write them out.
- *
  * If a page is already under I/O, generic_writepages() skips it, even
  * if it's dirty.  This is desirable behaviour for memory-cleaning writeback,
  * but it is INCORRECT for data-integrity system calls such as fsync().  fsync()
  * and msync() need to guarantee that all the data which was dirty at the time
- * the call was made get new I/O started against them.  So if called_for_sync()
- * is true, we must wait for existing IO to complete.
- *
- * It's fairly rare for PageWriteback pages to be on ->dirty_pages.  It
- * means that someone redirtied the page while it was under I/O.
+ * the call was made get new I/O started against them.  If wbc->sync_mode is
+ * WB_SYNC_ALL then we were called for data integrity and we must wait for
+ * existing IO to complete.
  */
 int
 mpage_writepages(struct address_space *mapping,
@@ -625,6 +607,9 @@ mpage_writepages(struct address_space *m
 	int ret = 0;
 	int done = 0;
 	int (*writepage)(struct page *page, struct writeback_control *wbc);
+	struct pagevec pvec;
+	int nr_pages;
+	pgoff_t index;
 
 	if (wbc->nonblocking && bdi_write_congested(bdi)) {
 		wbc->encountered_congestion = 1;
@@ -635,72 +620,58 @@ mpage_writepages(struct address_space *m
 	if (get_block == NULL)
 		writepage = mapping->a_ops->writepage;
 
-	spin_lock(&mapping->page_lock);
-	while (!list_empty(&mapping->io_pages) && !done) {
-		struct page *page = list_entry(mapping->io_pages.prev,
-					struct page, list);
-		list_del(&page->list);
-		if (PageWriteback(page) && wbc->sync_mode == WB_SYNC_NONE) {
-			if (PageDirty(page)) {
-				list_add(&page->list, &mapping->dirty_pages);
-				continue;
-			}
-			list_add(&page->list, &mapping->locked_pages);
-			continue;
-		}
-		if (!PageDirty(page)) {
-			list_add(&page->list, &mapping->clean_pages);
-			continue;
-		}
-		list_add(&page->list, &mapping->locked_pages);
-
-		page_cache_get(page);
-		spin_unlock(&mapping->page_lock);
-
-		/*
-		 * At this point we hold neither mapping->page_lock nor
-		 * lock on the page itself: the page may be truncated or
-		 * invalidated (changing page->mapping to NULL), or even
-		 * swizzled back from swapper_space to tmpfs file mapping.
-		 */
-
-		lock_page(page);
-
-		if (wbc->sync_mode != WB_SYNC_NONE)
-			wait_on_page_writeback(page);
-
-		if (page->mapping == mapping && !PageWriteback(page) &&
-					test_clear_page_dirty(page)) {
-			if (writepage) {
-				ret = (*writepage)(page, wbc);
-				if (ret) {
-					if (ret == -ENOSPC)
-						set_bit(AS_ENOSPC,
-							&mapping->flags);
-					else
-						set_bit(AS_EIO,
-							&mapping->flags);
+	pagevec_init(&pvec, 0);
+	index = 0;
+	while (!done && (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
+					PAGECACHE_TAG_DIRTY, PAGEVEC_SIZE))) {
+		unsigned i;
+
+		for (i = 0; i < nr_pages; i++) {
+			struct page *page = pvec.pages[i];
+
+			/*
+			 * At this point we hold neither mapping->tree_lock nor
+			 * lock on the page itself: the page may be truncated or
+			 * invalidated (changing page->mapping to NULL), or even
+			 * swizzled back from swapper_space to tmpfs file
+			 * mapping
+			 */
+
+			lock_page(page);
+
+			if (wbc->sync_mode != WB_SYNC_NONE)
+				wait_on_page_writeback(page);
+
+			if (page->mapping == mapping && !PageWriteback(page) &&
+						test_clear_page_dirty(page)) {
+				if (writepage) {
+					ret = (*writepage)(page, wbc);
+					if (ret) {
+						if (ret == -ENOSPC)
+							set_bit(AS_ENOSPC,
+							  &mapping->flags);
+						else
+							set_bit(AS_EIO,
+							  &mapping->flags);
+					}
+				} else {
+					bio = mpage_writepage(bio, page,
+						get_block, &last_block_in_bio,
+						&ret, wbc);
+				}
+				if (ret || (--(wbc->nr_to_write) <= 0))
+					done = 1;
+				if (wbc->nonblocking &&
+						bdi_write_congested(bdi)) {
+					wbc->encountered_congestion = 1;
+					done = 1;
 				}
 			} else {
-				bio = mpage_writepage(bio, page, get_block,
-					&last_block_in_bio, &ret, wbc);
-			}
-			if (ret || (--(wbc->nr_to_write) <= 0))
-				done = 1;
-			if (wbc->nonblocking && bdi_write_congested(bdi)) {
-				wbc->encountered_congestion = 1;
-				done = 1;
+				unlock_page(page);
 			}
-		} else {
-			unlock_page(page);
 		}
-		page_cache_release(page);
-		spin_lock(&mapping->page_lock);
+		pagevec_release(&pvec);
 	}
-	/*
-	 * Leave any remaining dirty pages on ->io_pages
-	 */
-	spin_unlock(&mapping->page_lock);
 	if (bio)
 		mpage_bio_submit(WRITE, bio);
 	return ret;
--- diff/fs/namei.c	2004-03-11 10:20:28.000000000 +0000
+++ source/fs/namei.c	2004-03-16 09:37:57.651775768 +0000
@@ -26,6 +26,7 @@
 #include <linux/personality.h>
 #include <linux/security.h>
 #include <linux/mount.h>
+#include <linux/audit.h>
 #include <asm/namei.h>
 #include <asm/uaccess.h>
 
@@ -141,10 +142,12 @@ char * getname(const char __user * filen
 
 		result = tmp;
 		if (retval < 0) {
-			putname(tmp);
+			__putname(tmp);
 			result = ERR_PTR(retval);
 		}
 	}
+	if (unlikely(current->audit_context) && !IS_ERR(result) && result)
+		audit_getname(result);
 	return result;
 }
 
@@ -860,6 +863,8 @@ walk_init_root(const char *name, struct 
 
 int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata *nd)
 {
+	int retval;
+
 	nd->last_type = LAST_ROOT; /* if there are only slashes... */
 	nd->flags = flags;
 
@@ -882,7 +887,13 @@ int fastcall path_lookup(const char *nam
 	}
 	read_unlock(&current->fs->lock);
 	current->total_link_count = 0;
-	return link_path_walk(name, nd);
+	retval = link_path_walk(name, nd);
+	if (unlikely(current->audit_context
+		     && nd && nd->dentry && nd->dentry->d_inode))
+		audit_inode(name,
+			    nd->dentry->d_inode->i_ino,
+			    nd->dentry->d_inode->i_rdev);
+	return retval;
 }
 
 /*
--- diff/fs/namespace.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/namespace.c	2004-03-16 09:37:57.652775616 +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-16 09:37:57.653775464 +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-16 09:37:57.655775160 +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-16 09:37:57.656775008 +0000
@@ -128,6 +128,7 @@ nfs_direct_read_seg(struct inode *inode,
 		.inode		= inode,
 		.args		= {
 			.fh		= NFS_FH(inode),
+			.lockowner	= current->files,
 		},
 		.res		= {
 			.fattr		= &rdata.fattr,
@@ -258,6 +259,7 @@ nfs_direct_write_seg(struct inode *inode
 		.inode		= inode,
 		.args		= {
 			.fh		= NFS_FH(inode),
+			.lockowner	= current->files,
 		},
 		.res		= {
 			.fattr		= &wdata.fattr,
@@ -269,6 +271,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 +337,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-16 09:37:57.656775008 +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-16 09:37:57.660774400 +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;
-	}
-
-	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;
+	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 (!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,107 @@ __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);
+
+	/* 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;
+	nfsi->cache_change_attribute ++;
+	atomic_dec(&nfsi->data_updates);
+}
+
+/**
+ * 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;
+
+	/* Has the link count changed? */
+	if (inode->i_nlink != fattr->nlink)
+		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 +1108,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 +1175,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 +1190,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 +1206,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 +1224,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 +1368,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
@@ -1391,8 +1407,8 @@ static void nfs4_clear_inode(struct inod
 				inode->i_sb->s_id,
 				(long long)NFS_FILEID(inode),
 				state);
-		list_del(&state->inode_states);
-		nfs4_put_open_state(state);
+		BUG_ON(atomic_read(&state->count) != 1);
+		nfs4_close_state(state, state->state);
 	}
 	/* Now call standard NFS clear_inode() code */
 	nfs_clear_inode(inode);
@@ -1472,17 +1488,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 +1513,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 +1622,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 +1687,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 +1739,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-16 09:37:57.661774248 +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 14:46:18.000000000 +0000
+++ source/fs/nfs/nfs2xdr.c	2004-03-16 09:37:57.662774096 +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-16 09:37:57.663773944 +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;
 }
@@ -739,11 +729,10 @@ nfs3_read_done(struct rpc_task *task)
 }
 
 static void
-nfs3_proc_read_setup(struct nfs_read_data *data, unsigned int count)
+nfs3_proc_read_setup(struct nfs_read_data *data)
 {
 	struct rpc_task		*task = &data->task;
 	struct inode		*inode = data->inode;
-	struct nfs_page		*req;
 	int			flags;
 	struct rpc_message	msg = {
 		.rpc_proc	= &nfs3_procedures[NFS3PROC_READ],
@@ -751,47 +740,33 @@ nfs3_proc_read_setup(struct nfs_read_dat
 		.rpc_resp	= &data->res,
 		.rpc_cred	= data->cred,
 	};
-	
-	req = nfs_list_entry(data->pages.next);
-	data->args.fh     = NFS_FH(inode);
-	data->args.offset = req_offset(req);
-	data->args.pgbase = req->wb_pgbase;
-	data->args.pages  = data->pagevec;
-	data->args.count  = count;
-	data->res.fattr   = &data->fattr;
-	data->res.count   = count;
-	data->res.eof     = 0;
-	
+
 	/* N.B. Do we need to test? Never called for swapfile inode */
 	flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
 
 	/* Finalize the task. */
 	rpc_init_task(task, NFS_CLIENT(inode), nfs3_read_done, flags);
-	task->tk_calldata = data;
-	/* Release requests */
-	task->tk_release = nfs_readdata_release;
-
-	rpc_call_setup(&data->task, &msg, 0);
+	rpc_call_setup(task, &msg, 0);
 }
 
 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);
 }
 
 static void
-nfs3_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
+nfs3_proc_write_setup(struct nfs_write_data *data, int how)
 {
 	struct rpc_task		*task = &data->task;
 	struct inode		*inode = data->inode;
-	struct nfs_page		*req;
 	int			stable;
 	int			flags;
 	struct rpc_message	msg = {
@@ -808,44 +783,31 @@ nfs3_proc_write_setup(struct nfs_write_d
 			stable = NFS_DATA_SYNC;
 	} else
 		stable = NFS_UNSTABLE;
-	
-	req = nfs_list_entry(data->pages.next);
-	data->args.fh     = NFS_FH(inode);
-	data->args.offset = req_offset(req);
-	data->args.pgbase = req->wb_pgbase;
-	data->args.count  = count;
 	data->args.stable = stable;
-	data->args.pages  = data->pagevec;
-	data->res.fattr   = &data->fattr;
-	data->res.count   = count;
-	data->res.verf    = &data->verf;
 
 	/* Set the initial flags for the task.  */
 	flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
 
 	/* Finalize the task. */
 	rpc_init_task(task, NFS_CLIENT(inode), nfs3_write_done, flags);
-	task->tk_calldata = data;
-	/* Release requests */
-	task->tk_release = nfs_writedata_release;
-
-	rpc_call_setup(&data->task, &msg, 0);
+	rpc_call_setup(task, &msg, 0);
 }
 
 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);
 }
 
 static void
-nfs3_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how)
+nfs3_proc_commit_setup(struct nfs_write_data *data, int how)
 {
 	struct rpc_task		*task = &data->task;
 	struct inode		*inode = data->inode;
@@ -857,23 +819,12 @@ nfs3_proc_commit_setup(struct nfs_write_
 		.rpc_cred	= data->cred,
 	};
 
-	data->args.fh     = NFS_FH(data->inode);
-	data->args.offset = start;
-	data->args.count  = len;
-	data->res.count   = len;
-	data->res.fattr   = &data->fattr;
-	data->res.verf    = &data->verf;
-	
 	/* Set the initial flags for the task.  */
 	flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
 
 	/* Finalize the task. */
 	rpc_init_task(task, NFS_CLIENT(inode), nfs3_commit_done, flags);
-	task->tk_calldata = data;
-	/* Release requests */
-	task->tk_release = nfs_commit_release;
-	
-	rpc_call_setup(&data->task, &msg, 0);
+	rpc_call_setup(task, &msg, 0);
 }
 
 /*
--- diff/fs/nfs/nfs3xdr.c	2003-09-30 14:46:18.000000000 +0000
+++ source/fs/nfs/nfs3xdr.c	2004-03-16 09:37:57.664773792 +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-16 09:37:57.667773336 +0000
@@ -54,12 +54,24 @@
 #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[];
 
 extern nfs4_stateid zero_stateid;
 
+/* Prevent leaks of NFSv4 errors into userland */
+static inline int nfs4_map_errors(int err)
+{
+	if (err < -1000) {
+		printk(KERN_WARNING "%s could not handle NFSv4 error %d\n",
+				__FUNCTION__, -err);
+		return -EIO;
+	}
+	return err;
+}
+
 static void
 nfs4_setup_compound(struct nfs4_compound *cp, struct nfs4_op *ops,
 		    struct nfs_server *server, char *tag)
@@ -505,6 +517,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 +703,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 +836,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 +884,9 @@ nfs4_proc_get_root(struct nfs_server *se
 		break;
 	}
 out:
-	return status;
+	if (status)
+		return nfs4_map_errors(status);
+	return nfs4_proc_fsinfo(server, fhandle, info);
 }
 
 static int
@@ -883,7 +900,7 @@ nfs4_proc_getattr(struct inode *inode, s
 	nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "getattr");
 	nfs4_setup_putfh(&compound, NFS_FH(inode));
 	nfs4_setup_getattr(&compound, fattr);
-	return nfs4_call_compound(&compound, NULL, 0);
+	return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0));
 }
 
 /* 
@@ -969,7 +986,7 @@ nfs4_proc_lookup(struct inode *dir, stru
 
 	if (status >= 0)
 		status = nfs_refresh_inode(dir, &dir_attr);
-	return status;
+	return nfs4_map_errors(status);
 }
 
 static int
@@ -1016,7 +1033,7 @@ nfs4_proc_access(struct inode *inode, st
 		else if (req_access != resp_access)
 			status = -EACCES;
 	}
-	return status;
+	return nfs4_map_errors(status);
 }
 
 /*
@@ -1052,7 +1069,7 @@ nfs4_proc_readlink(struct inode *inode, 
 	nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "readlink");
 	nfs4_setup_putfh(&compound, NFS_FH(inode));
 	nfs4_setup_readlink(&compound, PAGE_CACHE_SIZE, &page);
-	return nfs4_call_compound(&compound, NULL, 0);
+	return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0));
 }
 
 static int
@@ -1079,23 +1096,19 @@ nfs4_proc_read(struct nfs_read_data *rda
 	if (filp) {
 		struct nfs4_state *state;
 		state = (struct nfs4_state *)filp->private_data;
-		nfs4_copy_stateid(&rdata->args.stateid, state, rdata->lockowner);
+		rdata->args.state = state;
 		msg.rpc_cred = state->owner->so_cred;
 	} else {
-		memcpy(&rdata->args.stateid, &zero_stateid, sizeof(rdata->args.stateid));
+		rdata->args.state = NULL;
 		msg.rpc_cred = NFS_I(inode)->mm_cred;
 	}
 
 	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;
+	return nfs4_map_errors(status);
 }
 
 static int
@@ -1121,18 +1134,17 @@ nfs4_proc_write(struct nfs_write_data *w
 	if (filp) {
 		struct nfs4_state *state;
 		state = (struct nfs4_state *)filp->private_data;
-		nfs4_copy_stateid(&wdata->args.stateid, state, wdata->lockowner);
+		wdata->args.state = state;
 		msg.rpc_cred = state->owner->so_cred;
 	} else {
-		memcpy(&wdata->args.stateid, &zero_stateid, sizeof(wdata->args.stateid));
+		wdata->args.state = NULL;
 		msg.rpc_cred = NFS_I(inode)->mm_cred;
 	}
 
 	fattr->valid = 0;
 	status = rpc_call_sync(server->client, &msg, rpcflags);
-	NFS_CACHEINV(inode);
 	dprintk("NFS reply write: %d\n", status);
-	return status;
+	return nfs4_map_errors(status);
 }
 
 static int
@@ -1154,20 +1166,15 @@ nfs4_proc_commit(struct nfs_write_data *
 	/*
 	 * Try first to use O_WRONLY, then O_RDWR stateid.
 	 */
-	if (filp) {
-		struct nfs4_state *state;
-		state = (struct nfs4_state *)filp->private_data;
-		nfs4_copy_stateid(&cdata->args.stateid, state, cdata->lockowner);
-		msg.rpc_cred = state->owner->so_cred;
-	} else {
-		memcpy(&cdata->args.stateid, &zero_stateid, sizeof(cdata->args.stateid));
+	if (filp)
+		msg.rpc_cred = ((struct nfs4_state *)filp->private_data)->owner->so_cred;
+	else
 		msg.rpc_cred = NFS_I(inode)->mm_cred;
-	}
 
 	fattr->valid = 0;
 	status = rpc_call_sync(server->client, &msg, 0);
 	dprintk("NFS reply commit: %d\n", status);
-	return status;
+	return nfs4_map_errors(status);
 }
 
 /*
@@ -1234,7 +1241,7 @@ nfs4_proc_remove(struct inode *dir, stru
 		process_cinfo(&dir_cinfo, &dir_attr);
 		nfs_refresh_inode(dir, &dir_attr);
 	}
-	return status;
+	return nfs4_map_errors(status);
 }
 
 struct unlink_desc {
@@ -1312,7 +1319,7 @@ nfs4_proc_rename(struct inode *old_dir, 
 		nfs_refresh_inode(old_dir, &old_dir_attr);
 		nfs_refresh_inode(new_dir, &new_dir_attr);
 	}
-	return status;
+	return nfs4_map_errors(status);
 }
 
 static int
@@ -1342,7 +1349,7 @@ nfs4_proc_link(struct inode *inode, stru
 		nfs_refresh_inode(dir, &dir_attr);
 		nfs_refresh_inode(inode, &fattr);
 	}
-	return status;
+	return nfs4_map_errors(status);
 }
 
 static int
@@ -1373,7 +1380,7 @@ nfs4_proc_symlink(struct inode *dir, str
 		process_cinfo(&dir_cinfo, &dir_attr);
 		nfs_refresh_inode(dir, &dir_attr);
 	}
-	return status;
+	return nfs4_map_errors(status);
 }
 
 static int
@@ -1403,7 +1410,7 @@ nfs4_proc_mkdir(struct inode *dir, struc
 		process_cinfo(&dir_cinfo, &dir_attr);
 		nfs_refresh_inode(dir, &dir_attr);
 	}
-	return status;
+	return nfs4_map_errors(status);
 }
 
 static int
@@ -1421,9 +1428,11 @@ 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;
+	return nfs4_map_errors(status);
 }
 
 static int
@@ -1453,7 +1462,7 @@ nfs4_proc_mknod(struct inode *dir, struc
 		process_cinfo(&dir_cinfo, &dir_attr);
 		nfs_refresh_inode(dir, &dir_attr);
 	}
-	return status;
+	return nfs4_map_errors(status);
 }
 
 static int
@@ -1463,11 +1472,10 @@ 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);
-	return nfs4_call_compound(&compound, NULL, 0);
+	return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0));
 }
 
 static int
@@ -1480,8 +1488,7 @@ nfs4_proc_fsinfo(struct nfs_server *serv
 		.rpc_resp = fsinfo,
 	};
 
-	memset(fsinfo, 0, sizeof(*fsinfo));
-	return rpc_call_sync(server->client, &msg, 0);
+	return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0));
 }
 
 static int
@@ -1491,25 +1498,10 @@ 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);
-	return nfs4_call_compound(&compound, NULL, 0);
-}
-
-static void
-nfs4_restart_read(struct rpc_task *task)
-{
-	struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata;
-	struct nfs_page *req;
-
-	rpc_restart_call(task);
-	req = nfs_list_entry(data->pages.next);
-	if (req->wb_state)
-		nfs4_copy_stateid(&data->args.stateid, req->wb_state, req->wb_lockowner);
-	else
-		memcpy(&data->args.stateid, &zero_stateid, sizeof(data->args.stateid));
+	return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0));
 }
 
 static void
@@ -1517,25 +1509,19 @@ 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;
+		rpc_restart_call(task);
 		return;
 	}
 	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);
 }
 
 static void
-nfs4_proc_read_setup(struct nfs_read_data *data, unsigned int count)
+nfs4_proc_read_setup(struct nfs_read_data *data)
 {
 	struct rpc_task	*task = &data->task;
 	struct rpc_message msg = {
@@ -1545,85 +1531,36 @@ nfs4_proc_read_setup(struct nfs_read_dat
 		.rpc_cred = data->cred,
 	};
 	struct inode *inode = data->inode;
-	struct nfs_page *req = nfs_list_entry(data->pages.next);
 	int flags;
 
-	data->args.fh     = NFS_FH(inode);
-	data->args.offset = req_offset(req);
-	data->args.pgbase = req->wb_pgbase;
-	data->args.pages  = data->pagevec;
-	data->args.count  = count;
-	data->res.fattr   = &data->fattr;
-	data->res.count   = count;
-	data->res.eof     = 0;
 	data->timestamp   = jiffies;
 
-	data->lockowner = req->wb_lockowner;
-	if (req->wb_state)
-		nfs4_copy_stateid(&data->args.stateid, req->wb_state, req->wb_lockowner);
-	else
-		memcpy(&data->args.stateid, &zero_stateid, sizeof(data->args.stateid));
-
 	/* N.B. Do we need to test? Never called for swapfile inode */
 	flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
 
 	/* Finalize the task. */
 	rpc_init_task(task, NFS_CLIENT(inode), nfs4_read_done, flags);
-	task->tk_calldata = data;
-	/* Release requests */
-	task->tk_release = nfs_readdata_release;
-
 	rpc_call_setup(task, &msg, 0);
 }
 
 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;
-	struct nfs_page *req;
-
-	rpc_restart_call(task);
-	req = nfs_list_entry(data->pages.next);
-	if (req->wb_state)
-		nfs4_copy_stateid(&data->args.stateid, req->wb_state, req->wb_lockowner);
-	else
-		memcpy(&data->args.stateid, &zero_stateid, sizeof(data->args.stateid));
-}
-
-static void
 nfs4_write_done(struct rpc_task *task)
 {
 	struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
 	struct inode *inode = data->inode;
 	
 	if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) {
-		task->tk_action = nfs4_restart_write;
+		rpc_restart_call(task);
 		return;
 	}
 	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);
 }
 
 static void
-nfs4_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
+nfs4_proc_write_setup(struct nfs_write_data *data, int how)
 {
 	struct rpc_task	*task = &data->task;
 	struct rpc_message msg = {
@@ -1633,7 +1570,6 @@ nfs4_proc_write_setup(struct nfs_write_d
 		.rpc_cred = data->cred,
 	};
 	struct inode *inode = data->inode;
-	struct nfs_page *req = nfs_list_entry(data->pages.next);
 	int stable;
 	int flags;
 	
@@ -1644,33 +1580,15 @@ nfs4_proc_write_setup(struct nfs_write_d
 			stable = NFS_DATA_SYNC;
 	} else
 		stable = NFS_UNSTABLE;
-
-	data->args.fh     = NFS_FH(inode);
-	data->args.offset = req_offset(req);
-	data->args.pgbase = req->wb_pgbase;
-	data->args.count  = count;
 	data->args.stable = stable;
-	data->args.pages  = data->pagevec;
-	data->res.fattr   = &data->fattr;
-	data->res.count   = count;
-	data->res.verf    = &data->verf;
-	data->timestamp   = jiffies;
 
-	data->lockowner = req->wb_lockowner;
-	if (req->wb_state)
-		nfs4_copy_stateid(&data->args.stateid, req->wb_state, req->wb_lockowner);
-	else
-		memcpy(&data->args.stateid, &zero_stateid, sizeof(data->args.stateid));
+	data->timestamp   = jiffies;
 
 	/* Set the initial flags for the task.  */
 	flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
 
 	/* Finalize the task. */
 	rpc_init_task(task, NFS_CLIENT(inode), nfs4_write_done, flags);
-	task->tk_calldata = data;
-	/* Release requests */
-	task->tk_release = nfs_writedata_release;
-
 	rpc_call_setup(task, &msg, 0);
 }
 
@@ -1681,16 +1599,15 @@ nfs4_commit_done(struct rpc_task *task)
 	struct inode *inode = data->inode;
 	
 	if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) {
-		task->tk_action = nfs4_restart_write;
+		rpc_restart_call(task);
 		return;
 	}
-	nfs4_write_refresh_inode(inode, data->res.fattr);
 	/* Call back common NFS writeback processing */
 	nfs_commit_done(task);
 }
 
 static void
-nfs4_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how)
+nfs4_proc_commit_setup(struct nfs_write_data *data, int how)
 {
 	struct rpc_task	*task = &data->task;
 	struct rpc_message msg = {
@@ -1702,22 +1619,11 @@ nfs4_proc_commit_setup(struct nfs_write_
 	struct inode *inode = data->inode;
 	int flags;
 	
-	data->args.fh     = NFS_FH(data->inode);
-	data->args.offset = start;
-	data->args.count  = len;
-	data->res.count   = len;
-	data->res.fattr   = &data->fattr;
-	data->res.verf    = &data->verf;
-	
 	/* Set the initial flags for the task.  */
 	flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
 
 	/* Finalize the task. */
 	rpc_init_task(task, NFS_CLIENT(inode), nfs4_commit_done, flags);
-	task->tk_calldata = data;
-	/* Release requests */
-	task->tk_release = nfs_commit_release;
-	
 	rpc_call_setup(task, &msg, 0);	
 }
 
@@ -1807,6 +1713,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 +1730,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;
 }
 
@@ -1850,7 +1762,7 @@ nfs4_async_handle_error(struct rpc_task 
 {
 	struct nfs4_client *clp = server->nfs4_state;
 
-	if (!clp)
+	if (!clp || task->tk_status >= 0)
 		return 0;
 	switch(task->tk_status) {
 		case -NFS4ERR_STALE_CLIENTID:
@@ -1869,6 +1781,7 @@ nfs4_async_handle_error(struct rpc_task 
 			task->tk_status = 0;
 			return -EAGAIN;
 	}
+	task->tk_status = nfs4_map_errors(task->tk_status);
 	return 0;
 }
 
@@ -1946,16 +1859,9 @@ nfs4_handle_error(struct nfs_server *ser
 			break;
 		case -NFS4ERR_OLD_STATEID:
 			ret = 0;
-			break;
-		default:
-			if (errorcode <= -1000) {
-				printk(KERN_WARNING "%s could not handle NFSv4 error %d\n",
-						__FUNCTION__, -errorcode);
-				ret = -EIO;
-			}
 	}
 	/* We failed to handle the error */
-	return ret;
+	return nfs4_map_errors(ret);
 }
 
 
@@ -2130,7 +2036,7 @@ nfs4_proc_getlk(struct nfs4_state *state
 	if (lsp)
 		nfs4_put_lock_state(lsp);
 	up(&state->lock_sema);
-	return status;
+	return nfs4_map_errors(status);
 }
 
 int
@@ -2175,7 +2081,7 @@ nfs4_proc_unlck(struct nfs4_state *state
 	nfs4_put_lock_state(lsp);
 out:
 	up(&state->lock_sema);
-	return status;
+	return nfs4_map_errors(status);
 }
 
 static int
@@ -2251,7 +2157,7 @@ nfs4_proc_setlk(struct nfs4_state *state
 	nfs4_put_lock_state(lsp);
 out:
 	up(&state->lock_sema);
-	return status;
+	return nfs4_map_errors(status);
 }
 
 static int
--- diff/fs/nfs/nfs4state.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/nfs/nfs4state.c	2004-03-16 09:37:57.668773184 +0000
@@ -105,7 +105,7 @@ nfs4_alloc_client(struct in_addr *addr)
 		INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp);
 		INIT_LIST_HEAD(&clp->cl_superblocks);
 		init_waitqueue_head(&clp->cl_waitq);
-		INIT_RPC_WAITQ(&clp->cl_rpcwaitq, "NFS4 client");
+		rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client");
 		clp->cl_state = 1 << NFS4CLNT_NEW;
 	}
 	return clp;
@@ -411,18 +411,20 @@ out:
 	return state;
 }
 
-void
-nfs4_put_open_state(struct nfs4_state *state)
+static void
+__nfs4_put_open_state(struct nfs4_state *state)
 {
 	struct inode *inode = state->inode;
 	struct nfs4_state_owner *owner = state->owner;
 	int status = 0;
 
-	if (!atomic_dec_and_lock(&state->count, &inode->i_lock))
+	if (!atomic_dec_and_lock(&state->count, &inode->i_lock)) {
+		up(&owner->so_sema);
 		return;
-	list_del(&state->inode_states);
+	}
+	if (!list_empty(&state->inode_states))
+		list_del(&state->inode_states);
 	spin_unlock(&inode->i_lock);
-	down(&owner->so_sema);
 	list_del(&state->open_states);
 	if (state->state != 0) {
 		do {
@@ -440,6 +442,13 @@ nfs4_put_open_state(struct nfs4_state *s
 }
 
 void
+nfs4_put_open_state(struct nfs4_state *state)
+{
+	down(&state->owner->so_sema);
+	__nfs4_put_open_state(state);
+}
+
+void
 nfs4_close_state(struct nfs4_state *state, mode_t mode)
 {
 	struct inode *inode = state->inode;
@@ -479,8 +488,7 @@ nfs4_close_state(struct nfs4_state *stat
 		status = nfs4_handle_error(NFS_SERVER(inode), status);
 		down(&owner->so_sema);
 	} while (!status);
-	up(&owner->so_sema);
-	nfs4_put_open_state(state);
+	__nfs4_put_open_state(state);
 }
 
 /*
@@ -790,7 +798,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-16 09:37:57.671772728 +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);
@@ -868,14 +868,32 @@ encode_putrootfh(struct xdr_stream *xdr)
         return 0;
 }
 
+static void
+encode_stateid(struct xdr_stream *xdr, struct nfs4_state *state, fl_owner_t lockowner)
+{
+	extern nfs4_stateid zero_stateid;
+	nfs4_stateid stateid;
+	uint32_t *p;
+
+	RESERVE_SPACE(16);
+	if (state != NULL) {
+		nfs4_copy_stateid(&stateid, state, lockowner);
+		WRITEMEM(stateid.data, sizeof(stateid.data));
+	} else
+		WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data));
+}
+
 static int
 encode_read(struct xdr_stream *xdr, struct nfs_readargs *args)
 {
 	uint32_t *p;
 
-	RESERVE_SPACE(32);
+	RESERVE_SPACE(4);
 	WRITE32(OP_READ);
-	WRITEMEM(args->stateid.data, sizeof(args->stateid.data));
+
+	encode_stateid(xdr, args->state, args->lockowner);
+
+	RESERVE_SPACE(12);
 	WRITE64(args->offset);
 	WRITE32(args->count);
 
@@ -1057,9 +1075,12 @@ encode_write(struct xdr_stream *xdr, str
 {
 	uint32_t *p;
 
-	RESERVE_SPACE(36);
+	RESERVE_SPACE(4);
 	WRITE32(OP_WRITE);
-	WRITEMEM(args->stateid.data, sizeof(args->stateid.data));
+
+	encode_stateid(xdr, args->state, args->lockowner);
+
+	RESERVE_SPACE(16);
 	WRITE64(args->offset);
 	WRITE32(args->stable);
 	WRITE32(args->count);
@@ -3165,6 +3186,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		}
 };
 
@@ -3180,6 +3205,10 @@ nfs_stat_to_errno(int stat)
 		if (nfs_errtbl[i].stat == stat)
 			return nfs_errtbl[i].errno;
 	}
+	if (stat < 0) {
+		/* The server is looney tunes. */
+		return ESERVERFAULT;
+	}
 	/* If we cannot translate the error, the recovery routines should
 	 * handle it.
 	 * Note: remaining NFSv4 error codes have values > 10000, so should
--- diff/fs/nfs/nfsroot.c	2003-08-26 09:00:54.000000000 +0000
+++ source/fs/nfs/nfsroot.c	2004-03-16 09:37:57.672772576 +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-16 09:37:57.673772424 +0000
@@ -32,7 +32,7 @@ static inline struct nfs_page *
 nfs_page_alloc(void)
 {
 	struct nfs_page	*p;
-	p = kmem_cache_alloc(nfs_page_cachep, SLAB_NOFS);
+	p = kmem_cache_alloc(nfs_page_cachep, SLAB_KERNEL);
 	if (p) {
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->wb_list);
@@ -88,6 +88,7 @@ nfs_create_request(struct file *file, st
 	 * long write-back delay. This will be adjusted in
 	 * update_nfs_request below if the region is not locked. */
 	req->wb_page    = page;
+	atomic_set(&req->wb_complete, 0);
 	req->wb_index	= page->index;
 	page_cache_get(page);
 	req->wb_offset  = offset;
@@ -246,7 +247,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 +258,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 +275,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-16 09:37:57.674772272 +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,17 +547,22 @@ 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);
 }
 
 static void
-nfs_proc_read_setup(struct nfs_read_data *data, unsigned int count)
+nfs_proc_read_setup(struct nfs_read_data *data)
 {
 	struct rpc_task		*task = &data->task;
 	struct inode		*inode = data->inode;
-	struct nfs_page		*req;
 	int			flags;
 	struct rpc_message	msg = {
 		.rpc_proc	= &nfs_procedures[NFSPROC_READ],
@@ -555,27 +570,13 @@ nfs_proc_read_setup(struct nfs_read_data
 		.rpc_resp	= &data->res,
 		.rpc_cred	= data->cred,
 	};
-	
-	req = nfs_list_entry(data->pages.next);
-	data->args.fh     = NFS_FH(inode);
-	data->args.offset = req_offset(req);
-	data->args.pgbase = req->wb_pgbase;
-	data->args.pages  = data->pagevec;
-	data->args.count  = count;
-	data->res.fattr   = &data->fattr;
-	data->res.count   = count;
-	data->res.eof     = 0;
-	
+
 	/* N.B. Do we need to test? Never called for swapfile inode */
 	flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
 
 	/* Finalize the task. */
 	rpc_init_task(task, NFS_CLIENT(inode), nfs_read_done, flags);
-	task->tk_calldata = data;
-	/* Release requests */
-	task->tk_release = nfs_readdata_release;
-
-	rpc_call_setup(&data->task, &msg, 0);
+	rpc_call_setup(task, &msg, 0);
 }
 
 static void
@@ -584,16 +585,15 @@ 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);
 }
 
 static void
-nfs_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
+nfs_proc_write_setup(struct nfs_write_data *data, int how)
 {
 	struct rpc_task		*task = &data->task;
 	struct inode		*inode = data->inode;
-	struct nfs_page		*req;
 	int			flags;
 	struct rpc_message	msg = {
 		.rpc_proc	= &nfs_procedures[NFSPROC_WRITE],
@@ -603,32 +603,18 @@ nfs_proc_write_setup(struct nfs_write_da
 	};
 
 	/* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */
-	
-	req = nfs_list_entry(data->pages.next);
-	data->args.fh     = NFS_FH(inode);
-	data->args.offset = req_offset(req);
-	data->args.pgbase = req->wb_pgbase;
-	data->args.count  = count;
 	data->args.stable = NFS_FILE_SYNC;
-	data->args.pages  = data->pagevec;
-	data->res.fattr   = &data->fattr;
-	data->res.count   = count;
-	data->res.verf    = &data->verf;
 
 	/* Set the initial flags for the task.  */
 	flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
 
 	/* Finalize the task. */
 	rpc_init_task(task, NFS_CLIENT(inode), nfs_write_done, flags);
-	task->tk_calldata = data;
-	/* Release requests */
-	task->tk_release = nfs_writedata_release;
-
-	rpc_call_setup(&data->task, &msg, 0);
+	rpc_call_setup(task, &msg, 0);
 }
 
 static void
-nfs_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how)
+nfs_proc_commit_setup(struct nfs_write_data *data, int how)
 {
 	BUG();
 }
--- diff/fs/nfs/read.c	2003-10-09 08:47:34.000000000 +0000
+++ source/fs/nfs/read.c	2004-03-16 09:37:57.676771968 +0000
@@ -35,6 +35,8 @@
 #define NFSDBG_FACILITY		NFSDBG_PAGECACHE
 
 static int nfs_pagein_one(struct list_head *, struct inode *);
+static void nfs_readpage_result_partial(struct nfs_read_data *, int);
+static void nfs_readpage_result_full(struct nfs_read_data *, int);
 
 static kmem_cache_t *nfs_rdata_cachep;
 static mempool_t *nfs_rdata_mempool;
@@ -57,12 +59,37 @@ static __inline__ void nfs_readdata_free
 	mempool_free(p, nfs_rdata_mempool);
 }
 
-void nfs_readdata_release(struct rpc_task *task)
+static void nfs_readdata_release(struct rpc_task *task)
 {
         struct nfs_read_data   *data = (struct nfs_read_data *)task->tk_calldata;
         nfs_readdata_free(data);
 }
 
+static
+unsigned int nfs_page_length(struct inode *inode, struct page *page)
+{
+	loff_t i_size = i_size_read(inode);
+	unsigned long idx;
+
+	if (i_size <= 0)
+		return 0;
+	idx = (i_size - 1) >> PAGE_CACHE_SHIFT;
+	if (page->index > idx)
+		return 0;
+	if (page->index != idx)
+		return PAGE_CACHE_SIZE;
+	return 1 + ((i_size - 1) & (PAGE_CACHE_SIZE - 1));
+}
+
+static
+int nfs_return_empty_page(struct page *page)
+{
+	memclear_highpage_flush(page, 0, PAGE_CACHE_SIZE);
+	SetPageUptodate(page);
+	unlock_page(page);
+	return 0;
+}
+
 /*
  * Read a page synchronously.
  */
@@ -78,6 +105,7 @@ nfs_readpage_sync(struct file *file, str
 		.inode		= inode,
 		.args		= {
 			.fh		= NFS_FH(inode),
+			.lockowner	= current->files,
 			.pages		= &page,
 			.pgbase		= 0UL,
 			.count		= rsize,
@@ -121,9 +149,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);
@@ -142,89 +174,209 @@ nfs_readpage_async(struct file *file, st
 {
 	LIST_HEAD(one_request);
 	struct nfs_page	*new;
+	unsigned int len;
 
-	new = nfs_create_request(file, inode, page, 0, PAGE_CACHE_SIZE);
+	len = nfs_page_length(inode, page);
+	if (len == 0)
+		return nfs_return_empty_page(page);
+	new = nfs_create_request(file, inode, page, 0, len);
 	if (IS_ERR(new)) {
 		unlock_page(page);
 		return PTR_ERR(new);
 	}
+	if (len < PAGE_CACHE_SIZE)
+		memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len);
+
 	nfs_lock_request(new);
 	nfs_list_add_request(new, &one_request);
 	nfs_pagein_one(&one_request, inode);
 	return 0;
 }
 
+static void nfs_readpage_release(struct nfs_page *req)
+{
+	unlock_page(req->wb_page);
+
+	nfs_clear_request(req);
+	nfs_release_request(req);
+	nfs_unlock_request(req);
+
+	dprintk("NFS: read done (%s/%Ld %d@%Ld)\n",
+			req->wb_inode->i_sb->s_id,
+			(long long)NFS_FILEID(req->wb_inode),
+			req->wb_bytes,
+			(long long)req_offset(req));
+}
+
 /*
  * Set up the NFS read request struct
  */
-static void
-nfs_read_rpcsetup(struct list_head *head, struct nfs_read_data *data)
+static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
+		unsigned int count, unsigned int offset)
 {
 	struct inode		*inode;
-	struct nfs_page		*req;
-	struct page		**pages;
-	unsigned int		count;
 
-	pages = data->pagevec;
-	count = 0;
-	while (!list_empty(head)) {
-		req = nfs_list_entry(head->next);
-		nfs_list_remove_request(req);
-		nfs_list_add_request(req, &data->pages);
-		*pages++ = req->wb_page;
-		count += req->wb_bytes;
-	}
-	req = nfs_list_entry(data->pages.next);
+	data->req	  = req;
 	data->inode	  = inode = req->wb_inode;
 	data->cred	  = req->wb_cred;
 
-	NFS_PROTO(inode)->read_setup(data, count);
+	data->args.fh     = NFS_FH(inode);
+	data->args.offset = req_offset(req) + offset;
+	data->args.pgbase = req->wb_pgbase + offset;
+	data->args.pages  = data->pagevec;
+	data->args.count  = count;
+	data->args.lockowner = req->wb_lockowner;
+	data->args.state  = req->wb_state;
+
+	data->res.fattr   = &data->fattr;
+	data->res.count   = count;
+	data->res.eof     = 0;
+
+	NFS_PROTO(inode)->read_setup(data);
+
+	data->task.tk_cookie = (unsigned long)inode;
+	data->task.tk_calldata = data;
+	/* Release requests */
+	data->task.tk_release = nfs_readdata_release;
 
-	dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu.\n",
+	dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n",
 			data->task.tk_pid,
 			inode->i_sb->s_id,
 			(long long)NFS_FILEID(inode),
 			count,
-			(unsigned long long)req_offset(req));
+			data->args.offset);
 }
 
 static void
 nfs_async_read_error(struct list_head *head)
 {
 	struct nfs_page	*req;
-	struct page	*page;
 
 	while (!list_empty(head)) {
 		req = nfs_list_entry(head->next);
-		page = req->wb_page;
 		nfs_list_remove_request(req);
-		SetPageError(page);
-		unlock_page(page);
-		nfs_clear_request(req);
-		nfs_release_request(req);
-		nfs_unlock_request(req);
+		SetPageError(req->wb_page);
+		nfs_readpage_release(req);
 	}
 }
 
-static int
-nfs_pagein_one(struct list_head *head, struct inode *inode)
+/*
+ * Start an async read operation
+ */
+static void nfs_execute_read(struct nfs_read_data *data)
+{
+	struct rpc_clnt *clnt = NFS_CLIENT(data->inode);
+	sigset_t oldset;
+
+	rpc_clnt_sigmask(clnt, &oldset);
+	lock_kernel();
+	rpc_execute(&data->task);
+	unlock_kernel();
+	rpc_clnt_sigunmask(clnt, &oldset);
+}
+
+/*
+ * Generate multiple requests to fill a single page.
+ *
+ * We optimize to reduce the number of read operations on the wire.  If we
+ * detect that we're reading a page, or an area of a page, that is past the
+ * end of file, we do not generate NFS read operations but just clear the
+ * parts of the page that would have come back zero from the server anyway.
+ *
+ * We rely on the cached value of i_size to make this determination; another
+ * client can fill pages on the server past our cached end-of-file, but we
+ * won't see the new data until our attribute cache is updated.  This is more
+ * or less conventional NFS client behavior.
+ */
+static int nfs_pagein_multi(struct list_head *head, struct inode *inode)
+{
+	struct nfs_page *req = nfs_list_entry(head->next);
+	struct page *page = req->wb_page;
+	struct nfs_read_data *data;
+	unsigned int rsize = NFS_SERVER(inode)->rsize;
+	unsigned int nbytes, offset;
+	int requests = 0;
+	LIST_HEAD(list);
+
+	nfs_list_remove_request(req);
+
+	nbytes = req->wb_bytes;
+	for(;;) {
+		data = nfs_readdata_alloc();
+		if (!data)
+			goto out_bad;
+		list_add(&data->pages, &list);
+		requests++;
+		if (nbytes <= rsize)
+			break;
+		nbytes -= rsize;
+	}
+	atomic_set(&req->wb_complete, requests);
+
+	ClearPageError(page);
+	offset = 0;
+	nbytes = req->wb_bytes;
+	do {
+		data = list_entry(list.next, struct nfs_read_data, pages);
+		list_del_init(&data->pages);
+
+		data->pagevec[0] = page;
+		data->complete = nfs_readpage_result_partial;
+
+		if (nbytes > rsize) {
+			nfs_read_rpcsetup(req, data, rsize, offset);
+			offset += rsize;
+			nbytes -= rsize;
+		} else {
+			nfs_read_rpcsetup(req, data, nbytes, offset);
+			nbytes = 0;
+		}
+		nfs_execute_read(data);
+	} while (nbytes != 0);
+
+	return 0;
+
+out_bad:
+	while (!list_empty(&list)) {
+		data = list_entry(list.next, struct nfs_read_data, pages);
+		list_del(&data->pages);
+		nfs_readdata_free(data);
+	}
+	SetPageError(page);
+	nfs_readpage_release(req);
+	return -ENOMEM;
+}
+
+static int nfs_pagein_one(struct list_head *head, struct inode *inode)
 {
-	struct rpc_clnt		*clnt = NFS_CLIENT(inode);
+	struct nfs_page		*req;
+	struct page		**pages;
 	struct nfs_read_data	*data;
-	sigset_t		oldset;
+	unsigned int		count;
+
+	if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE)
+		return nfs_pagein_multi(head, inode);
 
 	data = nfs_readdata_alloc();
 	if (!data)
 		goto out_bad;
 
-	nfs_read_rpcsetup(head, data);
+	pages = data->pagevec;
+	count = 0;
+	while (!list_empty(head)) {
+		req = nfs_list_entry(head->next);
+		nfs_list_remove_request(req);
+		nfs_list_add_request(req, &data->pages);
+		ClearPageError(req->wb_page);
+		*pages++ = req->wb_page;
+		count += req->wb_bytes;
+	}
+	req = nfs_list_entry(data->pages.next);
+
+	data->complete = nfs_readpage_result_full;
+	nfs_read_rpcsetup(req, data, count, 0);
 
-	/* Start the async call */
-	rpc_clnt_sigmask(clnt, &oldset);
-	lock_kernel();
-	rpc_execute(&data->task);
-	unlock_kernel();
-	rpc_clnt_sigunmask(clnt, &oldset);
+	nfs_execute_read(data);
 	return 0;
 out_bad:
 	nfs_async_read_error(head);
@@ -254,54 +406,95 @@ nfs_pagein_list(struct list_head *head, 
 }
 
 /*
+ * Handle a read reply that fills part of a page.
+ */
+static void nfs_readpage_result_partial(struct nfs_read_data *data, int status)
+{
+	struct nfs_page *req = data->req;
+	struct page *page = req->wb_page;
+
+	if (status >= 0) {
+		unsigned int request = data->args.count;
+		unsigned int result = data->res.count;
+
+		if (result < request) {
+			memclear_highpage_flush(page,
+						data->args.pgbase + result,
+						request - result);
+		}
+	} else
+		SetPageError(page);
+
+	if (atomic_dec_and_test(&req->wb_complete)) {
+		if (!PageError(page))
+			SetPageUptodate(page);
+		nfs_readpage_release(req);
+	}
+}
+
+/*
  * This is the callback from RPC telling us whether a reply was
  * received or some error occurred (timeout or socket shutdown).
  */
-void
-nfs_readpage_result(struct rpc_task *task)
+static void nfs_readpage_result_full(struct nfs_read_data *data, int status)
 {
-	struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata;
 	unsigned int count = data->res.count;
 
-	dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
-		task->tk_pid, task->tk_status);
-
 	while (!list_empty(&data->pages)) {
 		struct nfs_page *req = nfs_list_entry(data->pages.next);
 		struct page *page = req->wb_page;
 		nfs_list_remove_request(req);
 
-		if (task->tk_status >= 0) {
+		if (status >= 0) {
 			if (count < PAGE_CACHE_SIZE) {
-				memclear_highpage_flush(page,
+				if (count < req->wb_bytes)
+					memclear_highpage_flush(page,
 							req->wb_pgbase + count,
 							req->wb_bytes - count);
-
 				count = 0;
 			} else
 				count -= PAGE_CACHE_SIZE;
 			SetPageUptodate(page);
 		} else
 			SetPageError(page);
-		unlock_page(page);
+		nfs_readpage_release(req);
+	}
+}
 
-		dprintk("NFS: read (%s/%Ld %d@%Ld)\n",
-                        req->wb_inode->i_sb->s_id,
-                        (long long)NFS_FILEID(req->wb_inode),
-                        req->wb_bytes,
-                        (long long)req_offset(req));
-		nfs_clear_request(req);
-		nfs_release_request(req);
-		nfs_unlock_request(req);
+/*
+ * This is the callback from RPC telling us whether a reply was
+ * received or some error occurred (timeout or socket shutdown).
+ */
+void nfs_readpage_result(struct rpc_task *task)
+{
+	struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata;
+	struct nfs_readargs *argp = &data->args;
+	struct nfs_readres *resp = &data->res;
+	int status = task->tk_status;
+
+	dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
+		task->tk_pid, status);
+
+	/* Is this a short read? */
+	if (task->tk_status >= 0 && resp->count < argp->count && !resp->eof) {
+		/* Has the server at least made some progress? */
+		if (resp->count != 0) {
+			/* Yes, so retry the read at the end of the data */
+			argp->offset += resp->count;
+			argp->pgbase += resp->count;
+			argp->count -= resp->count;
+			rpc_restart_call(task);
+			return;
+		}
+		task->tk_status = -EIO;
 	}
+	NFS_FLAGS(data->inode) |= NFS_INO_INVALID_ATIME;
+	data->complete(data, status);
 }
 
 /*
  * Read a page over NFS.
- * We read the page synchronously in the following cases:
- *  -	The NFS rsize is smaller than PAGE_CACHE_SIZE. We could kludge our way
- *	around this by creating several consecutive read requests, but
- *	that's hardly worth it.
+ * We read the page synchronously in the following case:
  *  -	The error flag is set for this page. This happens only when a
  *	previous async read operation failed.
  */
@@ -324,7 +517,7 @@ nfs_readpage(struct file *file, struct p
 	if (error)
 		goto out_error;
 
-	if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) {
+	if (!IS_SYNC(inode)) {
 		error = nfs_readpage_async(file, inode, page);
 		goto out;
 	}
@@ -346,26 +539,25 @@ struct nfs_readdesc {
 };
 
 static int
-readpage_sync_filler(void *data, struct page *page)
-{
-	struct nfs_readdesc *desc = (struct nfs_readdesc *)data;
-	return nfs_readpage_sync(desc->filp, page->mapping->host, page);
-}
-
-static int
 readpage_async_filler(void *data, struct page *page)
 {
 	struct nfs_readdesc *desc = (struct nfs_readdesc *)data;
 	struct inode *inode = page->mapping->host;
 	struct nfs_page *new;
+	unsigned int len;
 
 	nfs_wb_page(inode, page);
-	new = nfs_create_request(desc->filp, inode, page, 0, PAGE_CACHE_SIZE);
+	len = nfs_page_length(inode, page);
+	if (len == 0)
+		return nfs_return_empty_page(page);
+	new = nfs_create_request(desc->filp, inode, page, 0, len);
 	if (IS_ERR(new)) {
 			SetPageError(page);
 			unlock_page(page);
 			return PTR_ERR(new);
 	}
+	if (len < PAGE_CACHE_SIZE)
+		memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len);
 	nfs_lock_request(new);
 	nfs_list_add_request(new, desc->head);
 	return 0;
@@ -380,14 +572,16 @@ nfs_readpages(struct file *filp, struct 
 		.filp		= filp,
 		.head		= &head,
 	};
-	struct nfs_server *server = NFS_SERVER(mapping->host);
-	int is_sync = server->rsize < PAGE_CACHE_SIZE;
+	struct inode *inode = mapping->host;
+	struct nfs_server *server = NFS_SERVER(inode);
 	int ret;
 
-	ret = read_cache_pages(mapping, pages,
-			       is_sync ? readpage_sync_filler :
-					 readpage_async_filler,
-			       &desc);
+	dprintk("NFS: nfs_readpages (%s/%Ld %d)\n",
+			inode->i_sb->s_id,
+			(long long)NFS_FILEID(inode),
+			nr_pages);
+
+	ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc);
 	if (!list_empty(&head)) {
 		int err = nfs_pagein_list(&head, server->rpages);
 		if (!ret)
--- diff/fs/nfs/unlink.c	2003-06-30 09:07:24.000000000 +0000
+++ source/fs/nfs/unlink.c	2004-03-16 09:37:57.676771968 +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-16 09:37:57.699768472 +0000
@@ -74,12 +74,17 @@
 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 void nfs_writeback_done_partial(struct nfs_write_data *, int);
+static void nfs_writeback_done_full(struct nfs_write_data *, int);
+static int nfs_wait_on_write_congestion(struct address_space *, int);
+static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int);
 
 static kmem_cache_t *nfs_wdata_cachep;
 static mempool_t *nfs_wdata_mempool;
 static mempool_t *nfs_commit_mempool;
 
+static DECLARE_WAIT_QUEUE_HEAD(nfs_write_congestion);
+
 static __inline__ struct nfs_write_data *nfs_writedata_alloc(void)
 {
 	struct nfs_write_data	*p;
@@ -96,7 +101,7 @@ static __inline__ void nfs_writedata_fre
 	mempool_free(p, nfs_wdata_mempool);
 }
 
-void nfs_writedata_release(struct rpc_task *task)
+static void nfs_writedata_release(struct rpc_task *task)
 {
 	struct nfs_write_data	*wdata = (struct nfs_write_data *)task->tk_calldata;
 	nfs_writedata_free(wdata);
@@ -118,29 +123,69 @@ static __inline__ void nfs_commit_free(s
 	mempool_free(p, nfs_commit_mempool);
 }
 
-void nfs_commit_release(struct rpc_task *task)
+/* 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 nfs_write_data	*wdata = (struct nfs_write_data *)task->tk_calldata;
-	nfs_commit_free(wdata);
+	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.
  */
-static int
-nfs_writepage_sync(struct file *file, struct inode *inode, struct page *page,
-		   unsigned int offset, unsigned int count)
+static int nfs_writepage_sync(struct file *file, struct inode *inode,
+		struct page *page, unsigned int offset, unsigned int count,
+		int how)
 {
 	unsigned int	wsize = NFS_SERVER(inode)->wsize;
 	int		result, written = 0;
-	int		swapfile = IS_SWAPFILE(inode);
 	struct nfs_write_data	wdata = {
-		.flags		= swapfile ? NFS_RPC_SWAPFLAGS : 0,
+		.flags		= how,
 		.cred		= NULL,
 		.inode		= inode,
 		.args		= {
 			.fh		= NFS_FH(inode),
+			.lockowner	= current->files,
 			.pages		= &page,
 			.stable		= NFS_FILE_SYNC,
 			.pgbase		= offset,
@@ -157,8 +202,9 @@ 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)
+		if (count < wsize)
 			wdata.args.count = count;
 		wdata.args.offset = page_offset(page) + wdata.args.pgbase;
 
@@ -177,58 +223,62 @@ 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);
 
 	if (PageError(page))
 		ClearPageError(page);
 
 io_error:
+	nfs_end_data_update(inode);
 	if (wdata.cred)
 		put_rpccred(wdata.cred);
 
 	return written ? written : result;
 }
 
-static int
-nfs_writepage_async(struct file *file, struct inode *inode, struct page *page,
-		    unsigned int offset, unsigned int count)
+static int nfs_writepage_async(struct file *file, struct inode *inode,
+		struct page *page, unsigned int offset, unsigned int count)
 {
 	struct nfs_page	*req;
-	loff_t		end;
 	int		status;
 
 	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);
-
  out:
 	return status;
 }
 
+static int wb_priority(struct writeback_control *wbc)
+{
+	if (wbc->for_reclaim)
+		return FLUSH_HIGHPRI;
+	if (wbc->for_kupdate)
+		return FLUSH_LOWPRI;
+	return 0;
+}
+
 /*
  * Write an mmapped page to the server.
  */
-int
-nfs_writepage(struct page *page, struct writeback_control *wbc)
+int nfs_writepage(struct page *page, struct writeback_control *wbc)
 {
 	struct inode *inode = page->mapping->host;
 	unsigned long end_index;
 	unsigned offset = PAGE_CACHE_SIZE;
 	loff_t i_size = i_size_read(inode);
 	int inode_referenced = 0;
+	int priority = wb_priority(wbc);
 	int err;
 
 	/*
@@ -244,7 +294,7 @@ nfs_writepage(struct page *page, struct 
 	end_index = i_size >> PAGE_CACHE_SHIFT;
 
 	/* Ensure we've flushed out any previous writes */
-	nfs_wb_page(inode,page);
+	nfs_wb_page_priority(inode, page, priority);
 
 	/* easy case */
 	if (page->index < end_index)
@@ -258,44 +308,60 @@ nfs_writepage(struct page *page, struct 
 		goto out;
 do_it:
 	lock_kernel();
-	if (NFS_SERVER(inode)->wsize >= PAGE_CACHE_SIZE && !IS_SYNC(inode) &&
-			inode_referenced) {
+	if (!IS_SYNC(inode) && inode_referenced) {
 		err = nfs_writepage_async(NULL, inode, page, 0, offset);
-		if (err >= 0)
+		if (err >= 0) {
 			err = 0;
+			if (wbc->for_reclaim)
+				err = WRITEPAGE_ACTIVATE;
+		}
 	} else {
-		err = nfs_writepage_sync(NULL, inode, page, 0, offset); 
+		err = nfs_writepage_sync(NULL, inode, page, 0, offset, priority);
 		if (err == offset)
 			err = 0;
 	}
 	unlock_kernel();
 out:
-	unlock_page(page);
+	if (err != WRITEPAGE_ACTIVATE)
+		unlock_page(page);
 	if (inode_referenced)
 		iput(inode);
 	return err; 
 }
 
-int
-nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
+/*
+ * Note: causes nfs_update_request() to block on the assumption
+ * 	 that the writeback is generated due to memory pressure.
+ */
+int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
 {
+	struct backing_dev_info *bdi = mapping->backing_dev_info;
 	struct inode *inode = mapping->host;
-	int is_sync = !wbc->nonblocking;
 	int err;
 
 	err = generic_writepages(mapping, wbc);
 	if (err)
-		goto out;
-	err = nfs_flush_file(inode, NULL, 0, 0, 0);
+		return err;
+	while (test_and_set_bit(BDI_write_congested, &bdi->state) != 0) {
+		if (wbc->nonblocking)
+			return 0;
+		nfs_wait_on_write_congestion(mapping, 0);
+	}
+	err = nfs_flush_inode(inode, 0, 0, wb_priority(wbc));
 	if (err < 0)
 		goto out;
-	if (wbc->sync_mode == WB_SYNC_HOLD)
-		goto out;
-	if (is_sync && wbc->sync_mode == WB_SYNC_ALL) {
-		err = nfs_wb_all(inode);
-	} else
-		nfs_commit_file(inode, NULL, 0, 0, 0);
+	wbc->nr_to_write -= err;
+	if (!wbc->nonblocking && wbc->sync_mode == WB_SYNC_ALL) {
+		err = nfs_wait_on_requests(inode, 0, 0);
+		if (err < 0)
+			goto out;
+	}
+	err = nfs_commit_inode(inode, 0, 0, wb_priority(wbc));
+	if (err > 0)
+		wbc->nr_to_write -= err;
 out:
+	clear_bit(BDI_write_congested, &bdi->state);
+	wake_up_all(&nfs_write_congestion);
 	return err;
 }
 
@@ -312,8 +378,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;
@@ -322,7 +390,7 @@ nfs_inode_add_request(struct inode *inod
 /*
  * Insert a write request into an inode
  */
-static inline void
+static void
 nfs_inode_remove_request(struct nfs_page *req)
 {
 	struct nfs_inode *nfsi;
@@ -336,6 +404,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);
@@ -372,7 +441,7 @@ nfs_find_request(struct inode *inode, un
 /*
  * Add a request to the inode's dirty list.
  */
-static inline void
+static void
 nfs_mark_request_dirty(struct nfs_page *req)
 {
 	struct inode *inode = req->wb_inode;
@@ -400,7 +469,7 @@ nfs_dirty_request(struct nfs_page *req)
 /*
  * Add a request to the inode's commit list.
  */
-static inline void
+static void
 nfs_mark_request_commit(struct nfs_page *req)
 {
 	struct inode *inode = req->wb_inode;
@@ -421,7 +490,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 +510,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 +520,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 +530,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 +537,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 +554,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 +561,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");
@@ -509,6 +573,38 @@ nfs_scan_commit(struct inode *inode, str
 }
 #endif
 
+static int nfs_wait_on_write_congestion(struct address_space *mapping, int intr)
+{
+	struct backing_dev_info *bdi = mapping->backing_dev_info;
+	DEFINE_WAIT(wait);
+	int ret = 0;
+
+	might_sleep();
+
+	if (!bdi_write_congested(bdi))
+		return 0;
+	if (intr) {
+		struct rpc_clnt *clnt = NFS_CLIENT(mapping->host);
+		sigset_t oldset;
+
+		rpc_clnt_sigmask(clnt, &oldset);
+		prepare_to_wait(&nfs_write_congestion, &wait, TASK_INTERRUPTIBLE);
+		if (bdi_write_congested(bdi)) {
+			if (signalled())
+				ret = -ERESTARTSYS;
+			else
+				schedule();
+		}
+		rpc_clnt_sigunmask(clnt, &oldset);
+	} else {
+		prepare_to_wait(&nfs_write_congestion, &wait, TASK_UNINTERRUPTIBLE);
+		if (bdi_write_congested(bdi))
+			schedule();
+	}
+	finish_wait(&nfs_write_congestion, &wait);
+	return ret;
+}
+
 
 /*
  * Try to update any existing write request, or create one if there is none.
@@ -521,11 +617,14 @@ static struct nfs_page *
 nfs_update_request(struct file* file, struct inode *inode, struct page *page,
 		   unsigned int offset, unsigned int bytes)
 {
+	struct nfs_server *server = NFS_SERVER(inode);
 	struct nfs_page		*req, *new = NULL;
 	unsigned long		rqend, end;
 
 	end = offset + bytes;
 
+	if (nfs_wait_on_write_congestion(page->mapping, server->flags & NFS_MOUNT_INTR))
+		return ERR_PTR(-ERESTARTSYS);
 	for (;;) {
 		/* Loop over all inode entries and see if we find
 		 * A request for the page we wish to update
@@ -600,46 +699,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)
 {
@@ -669,25 +728,20 @@ nfs_flush_incompatible(struct file *file
  * XXX: Keep an eye on generic_file_read to make sure it doesn't do bad
  * things with a page scheduled for an RPC call (e.g. invalidate it).
  */
-int
-nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsigned int count)
+int nfs_updatepage(struct file *file, struct page *page,
+		unsigned int offset, unsigned int count)
 {
 	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",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
 		count, (long long)(page_offset(page) +offset));
 
-	/*
-	 * If wsize is smaller than page size, update and write
-	 * page synchronously.
-	 */
-	if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE || IS_SYNC(inode)) {
-		status = nfs_writepage_sync(file, inode, page, offset, count);
+	if (IS_SYNC(inode)) {
+		status = nfs_writepage_sync(file, inode, page, offset, count, 0);
 		if (status > 0) {
 			if (offset == 0 && status == PAGE_CACHE_SIZE)
 				SetPageUptodate(page);
@@ -696,6 +750,27 @@ nfs_updatepage(struct file *file, struct
 		return status;
 	}
 
+	/* 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 (unlikely(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,20 +789,12 @@ 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:
         dprintk("NFS:      nfs_updatepage returns %d (isize %Ld)\n",
 			status, (long long)i_size_read(inode));
@@ -736,43 +803,159 @@ done:
 	return status;
 }
 
+static void nfs_writepage_release(struct nfs_page *req)
+{
+	end_page_writeback(req->wb_page);
+
+#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
+	if (!PageError(req->wb_page)) {
+		if (NFS_NEED_RESCHED(req)) {
+			nfs_mark_request_dirty(req);
+			goto out;
+		} else if (NFS_NEED_COMMIT(req)) {
+			nfs_mark_request_commit(req);
+			goto out;
+		}
+	}
+	nfs_inode_remove_request(req);
+
+out:
+	nfs_clear_commit(req);
+	nfs_clear_reschedule(req);
+#else
+	nfs_inode_remove_request(req);
+#endif
+	nfs_unlock_request(req);
+}
+
+static inline int flush_task_priority(int how)
+{
+	switch (how & (FLUSH_HIGHPRI|FLUSH_LOWPRI)) {
+		case FLUSH_HIGHPRI:
+			return RPC_PRIORITY_HIGH;
+		case FLUSH_LOWPRI:
+			return RPC_PRIORITY_LOW;
+	}
+	return RPC_PRIORITY_NORMAL;
+}
+
 /*
  * Set up the argument/result storage required for the RPC call.
  */
-static void
-nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how)
+static void nfs_write_rpcsetup(struct nfs_page *req,
+		struct nfs_write_data *data,
+		unsigned int count, unsigned int offset,
+		int how)
 {
 	struct rpc_task		*task = &data->task;
 	struct inode		*inode;
-	struct nfs_page		*req;
-	struct page		**pages;
-	unsigned int		count;
 
 	/* Set up the RPC argument and reply structs
 	 * NB: take care not to mess about with data->commit et al. */
 
-	pages = data->pagevec;
-	count = 0;
-	while (!list_empty(head)) {
-		req = nfs_list_entry(head->next);
-		nfs_list_remove_request(req);
-		nfs_list_add_request(req, &data->pages);
-		SetPageWriteback(req->wb_page);
-		*pages++ = req->wb_page;
-		count += req->wb_bytes;
-	}
-	req = nfs_list_entry(data->pages.next);
+	data->req = req;
 	data->inode = inode = req->wb_inode;
 	data->cred = req->wb_cred;
 
-	NFS_PROTO(inode)->write_setup(data, count, how);
+	data->args.fh     = NFS_FH(inode);
+	data->args.offset = req_offset(req) + offset;
+	data->args.pgbase = req->wb_pgbase + offset;
+	data->args.count  = count;
+	data->args.pages  = data->pagevec;
+	data->res.fattr   = &data->fattr;
+	data->res.count   = count;
+	data->res.verf    = &data->verf;
+
+	NFS_PROTO(inode)->write_setup(data, how);
+
+	data->task.tk_priority = flush_task_priority(how);
+	data->task.tk_cookie = (unsigned long)inode;
+	data->task.tk_calldata = data;
+	/* Release requests */
+	data->task.tk_release = nfs_writedata_release;
 
 	dprintk("NFS: %4d initiated write call (req %s/%Ld, %u bytes @ offset %Lu)\n",
 		task->tk_pid,
 		inode->i_sb->s_id,
 		(long long)NFS_FILEID(inode),
 		count,
-		(unsigned long long)req_offset(req));
+		data->args.offset);
+}
+
+static void nfs_execute_write(struct nfs_write_data *data)
+{
+	struct rpc_clnt *clnt = NFS_CLIENT(data->inode);
+	sigset_t oldset;
+
+	rpc_clnt_sigmask(clnt, &oldset);
+	lock_kernel();
+	rpc_execute(&data->task);
+	unlock_kernel();
+	rpc_clnt_sigunmask(clnt, &oldset);
+}
+
+/*
+ * Generate multiple small requests to write out a single
+ * contiguous dirty area on one page.
+ */
+static int nfs_flush_multi(struct list_head *head, struct inode *inode, int how)
+{
+	struct nfs_page *req = nfs_list_entry(head->next);
+	struct page *page = req->wb_page;
+	struct nfs_write_data *data;
+	unsigned int wsize = NFS_SERVER(inode)->wsize;
+	unsigned int nbytes, offset;
+	int requests = 0;
+	LIST_HEAD(list);
+
+	nfs_list_remove_request(req);
+
+	nbytes = req->wb_bytes;
+	for (;;) {
+		data = nfs_writedata_alloc();
+		if (!data)
+			goto out_bad;
+		list_add(&data->pages, &list);
+		requests++;
+		if (nbytes <= wsize)
+			break;
+		nbytes -= wsize;
+	}
+	atomic_set(&req->wb_complete, requests);
+
+	ClearPageError(page);
+	SetPageWriteback(page);
+	offset = 0;
+	nbytes = req->wb_bytes;
+	do {
+		data = list_entry(list.next, struct nfs_write_data, pages);
+		list_del_init(&data->pages);
+
+		data->pagevec[0] = page;
+		data->complete = nfs_writeback_done_partial;
+
+		if (nbytes > wsize) {
+			nfs_write_rpcsetup(req, data, wsize, offset, how);
+			offset += wsize;
+			nbytes -= wsize;
+		} else {
+			nfs_write_rpcsetup(req, data, nbytes, offset, how);
+			nbytes = 0;
+		}
+		nfs_execute_write(data);
+	} while (nbytes != 0);
+
+	return 0;
+
+out_bad:
+	while (!list_empty(&list)) {
+		data = list_entry(list.next, struct nfs_write_data, pages);
+		list_del(&data->pages);
+		nfs_writedata_free(data);
+	}
+	nfs_mark_request_dirty(req);
+	nfs_unlock_request(req);
+	return -ENOMEM;
 }
 
 /*
@@ -783,25 +966,38 @@ nfs_write_rpcsetup(struct list_head *hea
  * This is the case if nfs_updatepage detects a conflicting request
  * that has been written but not committed.
  */
-static int
-nfs_flush_one(struct list_head *head, struct inode *inode, int how)
+static int nfs_flush_one(struct list_head *head, struct inode *inode, int how)
 {
-	struct rpc_clnt 	*clnt = NFS_CLIENT(inode);
+	struct nfs_page		*req;
+	struct page		**pages;
 	struct nfs_write_data	*data;
-	sigset_t		oldset;
+	unsigned int		count;
+
+	if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE)
+		return nfs_flush_multi(head, inode, how);
 
 	data = nfs_writedata_alloc();
 	if (!data)
 		goto out_bad;
 
+	pages = data->pagevec;
+	count = 0;
+	while (!list_empty(head)) {
+		req = nfs_list_entry(head->next);
+		nfs_list_remove_request(req);
+		nfs_list_add_request(req, &data->pages);
+		ClearPageError(req->wb_page);
+		SetPageWriteback(req->wb_page);
+		*pages++ = req->wb_page;
+		count += req->wb_bytes;
+	}
+	req = nfs_list_entry(data->pages.next);
+
+	data->complete = nfs_writeback_done_full;
 	/* Set up the argument struct */
-	nfs_write_rpcsetup(head, data, how);
+	nfs_write_rpcsetup(req, data, count, 0, how);
 
-	rpc_clnt_sigmask(clnt, &oldset);
-	lock_kernel();
-	rpc_execute(&data->task);
-	unlock_kernel();
-	rpc_clnt_sigunmask(clnt, &oldset);
+	nfs_execute_write(data);
 	return 0;
  out_bad:
 	while (!list_empty(head)) {
@@ -840,62 +1036,59 @@ nfs_flush_list(struct list_head *head, i
 	return error;
 }
 
-
 /*
- * This function is called when the WRITE call is complete.
+ * Handle a write reply that flushed part of a page.
  */
-void
-nfs_writeback_done(struct rpc_task *task)
+static void nfs_writeback_done_partial(struct nfs_write_data *data, int status)
 {
-	struct nfs_write_data	*data = (struct nfs_write_data *) task->tk_calldata;
-	struct nfs_writeargs	*argp = &data->args;
-	struct nfs_writeres	*resp = &data->res;
-	struct nfs_page		*req;
-	struct page		*page;
+	struct nfs_page		*req = data->req;
+	struct page		*page = req->wb_page;
 
-	dprintk("NFS: %4d nfs_writeback_done (status %d)\n",
-		task->tk_pid, task->tk_status);
+	dprintk("NFS: write (%s/%Ld %d@%Ld)",
+		req->wb_inode->i_sb->s_id,
+		(long long)NFS_FILEID(req->wb_inode),
+		req->wb_bytes,
+		(long long)req_offset(req));
 
-	/* We can't handle that yet but we check for it nevertheless */
-	if (resp->count < argp->count && task->tk_status >= 0) {
-		static unsigned long    complain;
-		if (time_before(complain, jiffies)) {
-			printk(KERN_WARNING
-			       "NFS: Server wrote less than requested.\n");
-			complain = jiffies + 300 * HZ;
-		}
-		/* Can't do anything about it right now except throw
-		 * an error. */
-		task->tk_status = -EIO;
-	}
+	if (status < 0) {
+		ClearPageUptodate(page);
+		SetPageError(page);
+		if (req->wb_file)
+			req->wb_file->f_error = status;
+		dprintk(", error = %d\n", status);
+	} else {
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
-	if (data->verf.committed < argp->stable && task->tk_status >= 0) {
-		/* We tried a write call, but the server did not
-		 * commit data to stable storage even though we
-		 * requested it.
-		 * Note: There is a known bug in Tru64 < 5.0 in which
-		 *	 the server reports NFS_DATA_SYNC, but performs
-		 *	 NFS_FILE_SYNC. We therefore implement this checking
-		 *	 as a dprintk() in order to avoid filling syslog.
-		 */
-		static unsigned long    complain;
-
-		if (time_before(complain, jiffies)) {
-			dprintk("NFS: faulty NFS server %s:"
-				" (committed = %d) != (stable = %d)\n",
-				NFS_SERVER(data->inode)->hostname,
-				data->verf.committed, argp->stable);
-			complain = jiffies + 300 * HZ;
-		}
-	}
+		if (data->verf.committed < NFS_FILE_SYNC) {
+			if (!NFS_NEED_COMMIT(req)) {
+				nfs_defer_commit(req);
+				memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf));
+				dprintk(" defer commit\n");
+			} else if (memcmp(&req->wb_verf, &data->verf, sizeof(req->wb_verf))) {
+				nfs_defer_reschedule(req);
+				dprintk(" server reboot detected\n");
+			}
+		} else
 #endif
+			dprintk(" OK\n");
+	}
 
-	/*
-	 * 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.
-	 */
+	if (atomic_dec_and_test(&req->wb_complete))
+		nfs_writepage_release(req);
+}
+
+/*
+ * Handle a write reply that flushes a whole page.
+ *
+ * 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.
+ */
+static void nfs_writeback_done_full(struct nfs_write_data *data, int status)
+{
+	struct nfs_page		*req;
+	struct page		*page;
+
+	/* Update attributes as result of writeback. */
 	while (!list_empty(&data->pages)) {
 		req = nfs_list_entry(data->pages.next);
 		nfs_list_remove_request(req);
@@ -907,20 +1100,20 @@ nfs_writeback_done(struct rpc_task *task
 			req->wb_bytes,
 			(long long)req_offset(req));
 
-		if (task->tk_status < 0) {
+		if (status < 0) {
 			ClearPageUptodate(page);
 			SetPageError(page);
 			if (req->wb_file)
-				req->wb_file->f_error = task->tk_status;
+				req->wb_file->f_error = status;
 			end_page_writeback(page);
 			nfs_inode_remove_request(req);
-			dprintk(", error = %d\n", task->tk_status);
+			dprintk(", error = %d\n", status);
 			goto next;
 		}
 		end_page_writeback(page);
 
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
-		if (argp->stable != NFS_UNSTABLE || data->verf.committed == NFS_FILE_SYNC) {
+		if (data->args.stable != NFS_UNSTABLE || data->verf.committed == NFS_FILE_SYNC) {
 			nfs_inode_remove_request(req);
 			dprintk(" OK\n");
 			goto next;
@@ -936,13 +1129,88 @@ nfs_writeback_done(struct rpc_task *task
 	}
 }
 
+/*
+ * This function is called when the WRITE call is complete.
+ */
+void nfs_writeback_done(struct rpc_task *task)
+{
+	struct nfs_write_data	*data = (struct nfs_write_data *) task->tk_calldata;
+	struct nfs_writeargs	*argp = &data->args;
+	struct nfs_writeres	*resp = &data->res;
+
+	dprintk("NFS: %4d nfs_writeback_done (status %d)\n",
+		task->tk_pid, task->tk_status);
 
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
+	if (resp->verf->committed < argp->stable && task->tk_status >= 0) {
+		/* We tried a write call, but the server did not
+		 * commit data to stable storage even though we
+		 * requested it.
+		 * Note: There is a known bug in Tru64 < 5.0 in which
+		 *	 the server reports NFS_DATA_SYNC, but performs
+		 *	 NFS_FILE_SYNC. We therefore implement this checking
+		 *	 as a dprintk() in order to avoid filling syslog.
+		 */
+		static unsigned long    complain;
+
+		if (time_before(complain, jiffies)) {
+			dprintk("NFS: faulty NFS server %s:"
+				" (committed = %d) != (stable = %d)\n",
+				NFS_SERVER(data->inode)->hostname,
+				resp->verf->committed, argp->stable);
+			complain = jiffies + 300 * HZ;
+		}
+	}
+#endif
+	/* Is this a short write? */
+	if (task->tk_status >= 0 && resp->count < argp->count) {
+		static unsigned long    complain;
+
+		/* Has the server at least made some progress? */
+		if (resp->count != 0) {
+			/* Was this an NFSv2 write or an NFSv3 stable write? */
+			if (resp->verf->committed != NFS_UNSTABLE) {
+				/* Resend from where the server left off */
+				argp->offset += resp->count;
+				argp->pgbase += resp->count;
+				argp->count -= resp->count;
+			} else {
+				/* Resend as a stable write in order to avoid
+				 * headaches in the case of a server crash.
+				 */
+				argp->stable = NFS_FILE_SYNC;
+			}
+			rpc_restart_call(task);
+			return;
+		}
+		if (time_before(complain, jiffies)) {
+			printk(KERN_WARNING
+			       "NFS: Server wrote less than requested.\n");
+			complain = jiffies + 300 * HZ;
+		}
+		/* Can't do anything about it except throw an error. */
+		task->tk_status = -EIO;
+	}
+
+	/*
+	 * Process the nfs_page list
+	 */
+	data->complete(data, task->tk_status);
+}
+
+
+#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
+static void nfs_commit_release(struct rpc_task *task)
+{
+	struct nfs_write_data	*wdata = (struct nfs_write_data *)task->tk_calldata;
+	nfs_commit_free(wdata);
+}
+
 /*
  * Set up the argument/result storage required for the RPC call.
  */
-static void
-nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how)
+static void nfs_commit_rpcsetup(struct list_head *head,
+		struct nfs_write_data *data, int how)
 {
 	struct rpc_task		*task = &data->task;
 	struct nfs_page		*first, *last;
@@ -971,7 +1239,20 @@ nfs_commit_rpcsetup(struct list_head *he
 	data->inode	  = inode;
 	data->cred	  = first->wb_cred;
 
-	NFS_PROTO(inode)->commit_setup(data, start, len, how);
+	data->args.fh     = NFS_FH(data->inode);
+	data->args.offset = start;
+	data->args.count  = len;
+	data->res.count   = len;
+	data->res.fattr   = &data->fattr;
+	data->res.verf    = &data->verf;
+
+	NFS_PROTO(inode)->commit_setup(data, how);
+
+	data->task.tk_priority = flush_task_priority(how);
+	data->task.tk_cookie = (unsigned long)inode;
+	data->task.tk_calldata = data;
+	/* Release requests */
+	data->task.tk_release = nfs_commit_release;
 	
 	dprintk("NFS: %4d initiated commit call\n", task->tk_pid);
 }
@@ -982,10 +1263,8 @@ nfs_commit_rpcsetup(struct list_head *he
 int
 nfs_commit_list(struct list_head *head, int how)
 {
-	struct rpc_clnt		*clnt;
 	struct nfs_write_data	*data;
 	struct nfs_page         *req;
-	sigset_t		oldset;
 
 	data = nfs_commit_alloc();
 
@@ -994,13 +1273,8 @@ nfs_commit_list(struct list_head *head, 
 
 	/* Set up the argument struct */
 	nfs_commit_rpcsetup(head, data, how);
-	clnt = NFS_CLIENT(data->inode);
 
-	rpc_clnt_sigmask(clnt, &oldset);
-	lock_kernel();
-	rpc_execute(&data->task);
-	unlock_kernel();
-	rpc_clnt_sigunmask(clnt, &oldset);
+	nfs_execute_write(data);
 	return 0;
  out_bad:
 	while (!list_empty(head)) {
@@ -1061,7 +1335,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 +1343,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 +1353,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 +1361,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 +1374,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 +1383,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/ntfs/compress.c	2003-08-26 09:00:54.000000000 +0000
+++ source/fs/ntfs/compress.c	2004-03-16 09:37:57.700768320 +0000
@@ -23,6 +23,7 @@
 
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
+#include <linux/blkdev.h>
 
 #include "ntfs.h"
 
@@ -668,7 +669,7 @@ lock_retry_remap:
 					"uptodate! Unplugging the disk queue "
 					"and rescheduling.");
 			get_bh(tbh);
-			blk_run_queues();
+			blk_run_address_space(mapping);
 			schedule();
 			put_bh(tbh);
 			if (unlikely(!buffer_uptodate(tbh)))
--- diff/fs/open.c	2004-03-11 10:20:28.000000000 +0000
+++ source/fs/open.c	2004-03-16 09:37:57.703767864 +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;
 }
@@ -954,6 +956,7 @@ out_error:
 	fd = error;
 	goto out;
 }
+EXPORT_SYMBOL_GPL(sys_open);
 
 #ifndef __alpha__
 
@@ -1036,7 +1039,7 @@ EXPORT_SYMBOL(sys_close);
 asmlinkage long sys_vhangup(void)
 {
 	if (capable(CAP_SYS_TTY_CONFIG)) {
-		tty_vhangup(current->tty);
+		tty_vhangup(current->signal->tty);
 		return 0;
 	}
 	return -EPERM;
--- diff/fs/proc/array.c	2004-03-11 10:20:28.000000000 +0000
+++ source/fs/proc/array.c	2004-03-16 09:37:57.703767864 +0000
@@ -168,7 +168,7 @@ static inline char * task_state(struct t
 		p->pid && p->ptrace ? p->parent->pid : 0,
 		p->uid, p->euid, p->suid, p->fsuid,
 		p->gid, p->egid, p->sgid, p->fsgid);
-	read_unlock(&tasklist_lock);	
+	read_unlock(&tasklist_lock);
 	task_lock(p);
 	buffer += sprintf(buffer,
 		"FDSize:\t%d\n"
@@ -301,7 +301,7 @@ int proc_pid_stat(struct task_struct *ta
 	sigset_t sigign, sigcatch;
 	char state;
 	int res;
-	pid_t ppid;
+ 	pid_t ppid, pgid = -1, sid = -1;
 	int num_threads = 0;
 	struct mm_struct *mm;
 
@@ -311,10 +311,6 @@ int proc_pid_stat(struct task_struct *ta
 	mm = task->mm;
 	if(mm)
 		mm = mmgrab(mm);
-	if (task->tty) {
-		tty_pgrp = task->tty->pgrp;
-		tty_nr = new_encode_dev(tty_devnum(task->tty));
-	}
 	task_unlock(task);
 	if (mm) {
 		down_read(&mm->mmap_sem);
@@ -335,7 +331,15 @@ int proc_pid_stat(struct task_struct *ta
 		collect_sigign_sigcatch(task, &sigign, &sigcatch);
 		spin_unlock_irq(&task->sighand->siglock);
 	}
-	read_unlock(&tasklist_lock);		
+	if (task->signal) {
+		if (task->signal->tty) {
+			tty_pgrp = task->signal->tty->pgrp;
+			tty_nr = new_encode_dev(tty_devnum(task->signal->tty));
+		}
+		pgid = process_group(task);
+		sid = task->signal->session;
+	}
+	read_unlock(&tasklist_lock);
 
 	/* scale priority and nice values from timeslices to -20..20 */
 	/* to make it look like a "normal" Unix priority/nice value  */
@@ -352,8 +356,8 @@ int proc_pid_stat(struct task_struct *ta
 		task->comm,
 		state,
 		ppid,
-		process_group(task),
-		task->session,
+		pgid,
+		sid,
 		tty_nr,
 		tty_pgrp,
 		task->flags,
--- diff/fs/proc/generic.c	2004-01-19 10:22:59.000000000 +0000
+++ source/fs/proc/generic.c	2004-03-16 09:37:57.704767712 +0000
@@ -661,6 +661,7 @@ void remove_proc_entry(const char *name,
 			  proc_alloc_map);
 		proc_kill_inodes(de);
 		de->nlink = 0;
+		WARN_ON(de->subdir);
 		if (!atomic_read(&de->count))
 			free_proc_entry(de);
 		else {
--- diff/fs/proc/inode.c	2003-10-09 08:47:34.000000000 +0000
+++ source/fs/proc/inode.c	2004-03-16 09:37:57.704767712 +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 14:46:19.000000000 +0000
+++ source/fs/proc/kmsg.c	2004-03-16 09:37:57.704767712 +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-03-11 10:20:28.000000000 +0000
+++ source/fs/proc/proc_misc.c	2004-03-16 09:37:57.706767408 +0000
@@ -361,7 +361,8 @@ int show_stat(struct seq_file *p, void *
 	int i;
 	extern unsigned long total_forks;
 	unsigned long jif;
-	unsigned int sum = 0, user = 0, nice = 0, system = 0, idle = 0, iowait = 0, irq = 0, softirq = 0;
+	u64	sum = 0, user = 0, nice = 0, system = 0,
+		idle = 0, iowait = 0, irq = 0, softirq = 0;
 
 	jif = - wall_to_monotonic.tv_sec;
 	if (wall_to_monotonic.tv_nsec)
@@ -381,26 +382,35 @@ int show_stat(struct seq_file *p, void *
 			sum += kstat_cpu(i).irqs[j];
 	}
 
-	seq_printf(p, "cpu  %u %u %u %u %u %u %u\n",
-		jiffies_to_clock_t(user),
-		jiffies_to_clock_t(nice),
-		jiffies_to_clock_t(system),
-		jiffies_to_clock_t(idle),
-		jiffies_to_clock_t(iowait),
-		jiffies_to_clock_t(irq),
-		jiffies_to_clock_t(softirq));
+	seq_printf(p, "cpu  %llu %llu %llu %llu %llu %llu %llu\n",
+		(unsigned long long)jiffies_64_to_clock_t(user),
+		(unsigned long long)jiffies_64_to_clock_t(nice),
+		(unsigned long long)jiffies_64_to_clock_t(system),
+		(unsigned long long)jiffies_64_to_clock_t(idle),
+		(unsigned long long)jiffies_64_to_clock_t(iowait),
+		(unsigned long long)jiffies_64_to_clock_t(irq),
+		(unsigned long long)jiffies_64_to_clock_t(softirq));
 	for_each_cpu(i) {
-		seq_printf(p, "cpu%d %u %u %u %u %u %u %u\n",
+		/* two separate calls here to work around gcc-2.95.3 ICE */
+		seq_printf(p, "cpu%d %llu %llu %llu ",
 			i,
-			jiffies_to_clock_t(kstat_cpu(i).cpustat.user),
-			jiffies_to_clock_t(kstat_cpu(i).cpustat.nice),
-			jiffies_to_clock_t(kstat_cpu(i).cpustat.system),
-			jiffies_to_clock_t(kstat_cpu(i).cpustat.idle),
-			jiffies_to_clock_t(kstat_cpu(i).cpustat.iowait),
-			jiffies_to_clock_t(kstat_cpu(i).cpustat.irq),
-			jiffies_to_clock_t(kstat_cpu(i).cpustat.softirq));
+			(unsigned long long)
+			  jiffies_64_to_clock_t(kstat_cpu(i).cpustat.user),
+			(unsigned long long)
+			  jiffies_64_to_clock_t(kstat_cpu(i).cpustat.nice),
+			(unsigned long long)
+			  jiffies_64_to_clock_t(kstat_cpu(i).cpustat.system));
+		seq_printf(p, "%llu %llu %llu %llu\n",
+			(unsigned long long)
+			  jiffies_64_to_clock_t(kstat_cpu(i).cpustat.idle),
+			(unsigned long long)
+			  jiffies_64_to_clock_t(kstat_cpu(i).cpustat.iowait),
+			(unsigned long long)
+			  jiffies_64_to_clock_t(kstat_cpu(i).cpustat.irq),
+			(unsigned long long)
+			  jiffies_64_to_clock_t(kstat_cpu(i).cpustat.softirq));
 	}
-	seq_printf(p, "intr %u", sum);
+	seq_printf(p, "intr %llu", (unsigned long long)sum);
 
 #if !defined(CONFIG_PPC64) && !defined(CONFIG_ALPHA)
 	for (i = 0; i < NR_IRQS; i++)
@@ -408,7 +418,7 @@ int show_stat(struct seq_file *p, void *
 #endif
 
 	seq_printf(p,
-		"\nctxt %lu\n"
+		"\nctxt %llu\n"
 		"btime %lu\n"
 		"processes %lu\n"
 		"procs_running %lu\n"
@@ -641,6 +651,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 +748,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/root.c	2003-08-20 13:16:33.000000000 +0000
+++ source/fs/proc/root.c	2004-03-16 09:37:57.706767408 +0000
@@ -74,9 +74,6 @@ void __init proc_root_init(void)
 #ifdef CONFIG_PROC_DEVICETREE
 	proc_device_tree_init();
 #endif
-#ifdef CONFIG_PPC_RTAS
-	proc_rtas_init();
-#endif
 	proc_bus = proc_mkdir("bus", 0);
 }
 
--- diff/fs/proc/task_mmu.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/proc/task_mmu.c	2004-03-16 09:37:57.706767408 +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 13:18:20.000000000 +0000
+++ source/fs/qnx4/dir.c	2004-03-16 09:37:57.707767256 +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 08:47:34.000000000 +0000
+++ source/fs/quota_v1.c	2004-03-16 09:37:57.707767256 +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 10:50:00.000000000 +0000
+++ source/fs/quota_v2.c	2004-03-16 09:37:57.709766952 +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/read_write.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/read_write.c	2004-03-16 09:37:57.709766952 +0000
@@ -143,6 +143,7 @@ asmlinkage off_t sys_lseek(unsigned int 
 bad:
 	return retval;
 }
+EXPORT_SYMBOL_GPL(sys_lseek);
 
 #if !defined(__alpha__)
 asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
@@ -281,6 +282,7 @@ asmlinkage ssize_t sys_read(unsigned int
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(sys_read);
 
 asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count)
 {
--- diff/fs/readdir.c	2004-03-11 10:20:28.000000000 +0000
+++ source/fs/readdir.c	2004-03-16 09:37:57.710766800 +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 13:18:20.000000000 +0000
+++ source/fs/reiserfs/dir.c	2004-03-16 09:37:57.710766800 +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/reiserfs/file.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/reiserfs/file.c	2004-03-16 09:37:57.711766648 +0000
@@ -365,7 +365,7 @@ int reiserfs_allocate_blocks_for_region(
     // it means there are no existing in-tree representation for file area
     // we are going to overwrite, so there is nothing to scan through for holes.
     for ( curr_block = 0, itempos = path.pos_in_item ; curr_block < blocks_to_allocate && res == POSITION_FOUND ; ) {
-
+retry:
 	if ( itempos >= ih_item_len(ih)/UNFM_P_SIZE ) {
 	    /* We run out of data in this indirect item, let's look for another
 	       one. */
@@ -422,8 +422,8 @@ int reiserfs_allocate_blocks_for_region(
 		    bh=get_last_bh(&path);
 		    ih=get_ih(&path);
 		    item = get_item(&path);
-		    // Itempos is still the same
-		    continue;
+		    itempos = path.pos_in_item;
+		    goto retry;
 		}
 		modifying_this_item = 1;
 	    }
@@ -856,8 +856,12 @@ int reiserfs_prepare_file_region_for_wri
 			/* Try to find next item */
 			res = search_for_position_by_key(inode->i_sb, &key, &path);
 			/* Abort if no more items */
-			if ( res != POSITION_FOUND )
+			if ( res != POSITION_FOUND ) {
+			    /* make sure later loops don't use this item */
+			    itembuf = NULL;
+			    item = NULL;
 			    break;
+			}
 
 			/* Update information about current indirect item */
 			itembuf = get_last_bh( &path );
@@ -1191,6 +1195,14 @@ out:
     return res;
 }
 
+static ssize_t reiserfs_aio_write(struct kiocb *iocb, const char __user *buf,
+			       size_t count, loff_t pos)
+{
+    return generic_file_aio_write(iocb, buf, count, pos);
+}
+
+
+
 struct file_operations reiserfs_file_operations = {
     .read	= generic_file_read,
     .write	= reiserfs_file_write,
@@ -1199,6 +1211,8 @@ struct file_operations reiserfs_file_ope
     .release	= reiserfs_file_release,
     .fsync	= reiserfs_sync_file,
     .sendfile	= generic_file_sendfile,
+    .aio_read   = generic_file_aio_read,
+    .aio_write  = reiserfs_aio_write,
 };
 
 
--- diff/fs/reiserfs/inode.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/reiserfs/inode.c	2004-03-16 09:37:57.713766344 +0000
@@ -209,7 +209,7 @@ static int file_capable (struct inode * 
   pathrelse(path) ;
   reiserfs_update_sd(th, inode) ;
   journal_end(th, s, len) ;
-  journal_begin(th, s, len) ;
+  journal_begin(th, s, JOURNAL_PER_BALANCE_CNT * 6) ;
   reiserfs_update_inode_transaction(inode) ;
 }
 
@@ -444,7 +444,7 @@ static int reiserfs_get_blocks_direct_io
         /* make sure future calls to the direct io funcs for this offset
         ** in the file fail by unmapping the buffer
         */
-        reiserfs_unmap_buffer(bh_result);
+        clear_buffer_mapped(bh_result);
         ret = -EINVAL ;
     }
     /* Possible unpacked tail. Flush the data before pages have
--- diff/fs/reiserfs/stree.c	2003-08-20 13:16:33.000000000 +0000
+++ source/fs/reiserfs/stree.c	2004-03-16 09:37:57.716765888 +0000
@@ -652,8 +652,8 @@ int search_by_key (struct super_block * 
                                        stop at leaf level - set to
                                        DISK_LEAF_NODE_LEVEL */
     ) {
-    int  n_block_number = SB_ROOT_BLOCK (p_s_sb),
-      expected_level = SB_TREE_HEIGHT (p_s_sb);
+    int  n_block_number;
+    int  expected_level;
     struct buffer_head  *       p_s_bh;
     struct path_element *       p_s_last_element;
     int				n_node_level, n_retval;
@@ -677,6 +677,8 @@ int search_by_key (struct super_block * 
     /* With each iteration of this loop we search through the items in the
        current node, and calculate the next current node(next path element)
        for the next iteration of this loop.. */
+    n_block_number = SB_ROOT_BLOCK (p_s_sb);
+    expected_level = -1;
     while ( 1 ) {
 
 #ifdef CONFIG_REISERFS_CHECK
@@ -690,7 +692,6 @@ int search_by_key (struct super_block * 
 	/* prep path to have another element added to it. */
 	p_s_last_element = PATH_OFFSET_PELEMENT(p_s_search_path, ++p_s_search_path->path_length);
 	fs_gen = get_generation (p_s_sb);
-	expected_level --;
 
 #ifdef SEARCH_BY_KEY_READA
 	/* schedule read of right neighbor */
@@ -705,25 +706,26 @@ int search_by_key (struct super_block * 
 	    pathrelse(p_s_search_path);
 	    return IO_ERROR;
 	}
-
- 	if( fs_changed (fs_gen, p_s_sb) ) {
- 		PROC_INFO_INC( p_s_sb, search_by_key_fs_changed );
- 		PROC_INFO_INC( p_s_sb, sbk_fs_changed[ expected_level - 1 ] );
- 	}
+	if (expected_level == -1)
+		expected_level = SB_TREE_HEIGHT (p_s_sb);
+	expected_level --;
 
 	/* It is possible that schedule occurred. We must check whether the key
 	   to search is still in the tree rooted from the current buffer. If
 	   not then repeat search from the root. */
 	if ( fs_changed (fs_gen, p_s_sb) && 
-	     (!B_IS_IN_TREE (p_s_bh) || !key_in_buffer(p_s_search_path, p_s_key, p_s_sb)) ) {
- 	    PROC_INFO_INC( p_s_sb, search_by_key_restarted );
+	    (!B_IS_IN_TREE (p_s_bh) ||
+	     B_LEVEL(p_s_bh) != expected_level ||
+	     !key_in_buffer(p_s_search_path, p_s_key, p_s_sb))) {
+	    PROC_INFO_INC( p_s_sb, search_by_key_fs_changed );
+	    PROC_INFO_INC( p_s_sb, search_by_key_restarted );
 	    PROC_INFO_INC( p_s_sb, sbk_restarted[ expected_level - 1 ] );
 	    decrement_counters_in_path(p_s_search_path);
 	    
 	    /* Get the root block number so that we can repeat the search
-               starting from the root. */
+	       starting from the root. */
 	    n_block_number = SB_ROOT_BLOCK (p_s_sb);
-	    expected_level = SB_TREE_HEIGHT (p_s_sb);
+	    expected_level = -1;
 	    right_neighbor_of_leaf_node = 0;
 	    
 	    /* repeat search from the root */
@@ -1103,6 +1105,7 @@ static char  prepare_for_delete_or_cut(
 	    for (n_counter = *p_n_removed;
 		 n_counter < n_unfm_number; n_counter++, p_n_unfm_pointer-- ) {
 
+		cond_resched();
 		if (item_moved (&s_ih, p_s_path)) {
 		    need_research = 1 ;
 		    break;
@@ -1754,7 +1757,7 @@ void reiserfs_do_truncate (struct reiser
 	  reiserfs_update_sd(th, p_s_inode) ;
 
 	  journal_end(th, p_s_inode->i_sb, orig_len_alloc) ;
-	  journal_begin(th, p_s_inode->i_sb, orig_len_alloc) ;
+	  journal_begin(th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 6) ;
 	  reiserfs_update_inode_transaction(p_s_inode) ;
 	}
     } while ( n_file_size > ROUND_UP (n_new_file_size) &&
--- diff/fs/select.c	2003-10-09 08:47:34.000000000 +0000
+++ source/fs/select.c	2004-03-16 09:37:57.717765736 +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 08:47:34.000000000 +0000
+++ source/fs/smbfs/inode.c	2004-03-16 09:37:57.718765584 +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-03-11 10:20:28.000000000 +0000
+++ source/fs/stat.c	2004-03-16 09:37:57.718765584 +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-11 10:20:28.000000000 +0000
+++ source/fs/super.c	2004-03-16 09:37:57.719765432 +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-16 09:37:57.720765280 +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);
@@ -120,13 +133,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 +151,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 14:46:19.000000000 +0000
+++ source/fs/sysfs/group.c	2004-03-16 09:37:57.720765280 +0000
@@ -55,8 +55,8 @@ int sysfs_create_group(struct kobject * 
 	if ((error = create_files(dir,grp))) {
 		if (grp->name)
 			sysfs_remove_subdir(dir);
-		dput(dir);
 	}
+	dput(dir);
 	return error;
 }
 
@@ -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 13:18:20.000000000 +0000
+++ source/fs/sysv/dir.c	2004-03-16 09:37:57.721765128 +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 13:18:20.000000000 +0000
+++ source/fs/udf/dir.c	2004-03-16 09:37:57.721765128 +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 08:39:50.000000000 +0000
+++ source/fs/udf/file.c	2004-03-16 09:37:57.722764976 +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 08:47:34.000000000 +0000
+++ source/fs/udf/inode.c	2004-03-16 09:37:57.724764672 +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-16 09:37:57.725764520 +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 08:47:17.000000000 +0000
+++ source/fs/udf/namei.c	2004-03-16 09:37:57.726764368 +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-16 09:37:57.727764216 +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-16 09:37:57.729763912 +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
@@ -57,6 +57,7 @@
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/vfs.h>
+#include <linux/vmalloc.h>
 #include <asm/byteorder.h>
 
 #include <linux/udf_fs.h>
@@ -133,7 +134,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 +326,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 +1653,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 +1731,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 +1778,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-16 09:37:57.730763760 +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 03:27:48.000000000 +0000
+++ source/fs/udf/udf_sb.h	2004-03-16 09:37:57.731763608 +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 11:28:12.000000000 +0000
+++ source/fs/udf/udfdecl.h	2004-03-16 09:37:57.732763456 +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-16 09:37:57.733763304 +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 13:18:20.000000000 +0000
+++ source/fs/ufs/dir.c	2004-03-16 09:37:57.733763304 +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 11:28:12.000000000 +0000
+++ source/fs/ufs/inode.c	2004-03-16 09:37:57.735763000 +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 14:46:19.000000000 +0000
+++ source/fs/ufs/namei.c	2004-03-16 09:37:57.735763000 +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-16 09:37:57.737762696 +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/truncate.c	2003-02-26 16:00:55.000000000 +0000
+++ source/fs/ufs/truncate.c	2004-03-16 09:37:57.737762696 +0000
@@ -38,6 +38,7 @@
 #include <linux/string.h>
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
+#include <linux/blkdev.h>
 #include <linux/sched.h>
 
 #include "swab.h"
@@ -456,7 +457,7 @@ void ufs_truncate (struct inode * inode)
 			break;
 		if (IS_SYNC(inode) && (inode->i_state & I_DIRTY))
 			ufs_sync_inode (inode);
-		blk_run_queues();
+		blk_run_address_space(inode->i_mapping);
 		yield();
 	}
 	offset = inode->i_size & uspi->s_fshift;
--- diff/fs/ufs/util.c	2003-05-21 10:49:55.000000000 +0000
+++ source/fs/ufs/util.c	2004-03-16 09:37:57.738762544 +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 10:49:46.000000000 +0000
+++ source/fs/ufs/util.h	2004-03-16 09:37:57.738762544 +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-11 10:20:28.000000000 +0000
+++ source/fs/xfs/linux/xfs_aops.c	2004-03-16 09:37:57.739762392 +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_buf.c	2004-03-11 10:20:28.000000000 +0000
+++ source/fs/xfs/linux/xfs_buf.c	2004-03-16 09:37:57.740762240 +0000
@@ -1013,7 +1013,7 @@ pagebuf_lock(
 {
 	PB_TRACE(pb, "lock", 0);
 	if (atomic_read(&pb->pb_io_remaining))
-		blk_run_queues();
+		blk_run_address_space(pb->pb_target->pbr_mapping);
 	down(&pb->pb_sema);
 	PB_SET_OWNER(pb);
 	PB_TRACE(pb, "locked", 0);
@@ -1109,7 +1109,7 @@ _pagebuf_wait_unpin(
 		if (atomic_read(&pb->pb_pin_count) == 0)
 			break;
 		if (atomic_read(&pb->pb_io_remaining))
-			blk_run_queues();
+			blk_run_address_space(pb->pb_target->pbr_mapping);
 		schedule();
 	}
 	remove_wait_queue(&pb->pb_waiters, &wait);
@@ -1407,7 +1407,7 @@ submit_io:
 	if (pb->pb_flags & PBF_RUN_QUEUES) {
 		pb->pb_flags &= ~PBF_RUN_QUEUES;
 		if (atomic_read(&pb->pb_io_remaining) > 1)
-			blk_run_queues();
+			blk_run_address_space(pb->pb_target->pbr_mapping);
 	}
 }
 
@@ -1471,7 +1471,7 @@ pagebuf_iowait(
 {
 	PB_TRACE(pb, "iowait", 0);
 	if (atomic_read(&pb->pb_io_remaining))
-		blk_run_queues();
+		blk_run_address_space(pb->pb_target->pbr_mapping);
 	down(&pb->pb_iodonesema);
 	PB_TRACE(pb, "iowaited", (long)pb->pb_error);
 	return pb->pb_error;
@@ -1617,7 +1617,6 @@ STATIC int
 pagebuf_daemon(
 	void			*data)
 {
-	int			count;
 	page_buf_t		*pb;
 	struct list_head	*curr, *next, tmp;
 
@@ -1640,7 +1639,6 @@ pagebuf_daemon(
 
 		spin_lock(&pbd_delwrite_lock);
 
-		count = 0;
 		list_for_each_safe(curr, next, &pbd_delwrite_queue) {
 			pb = list_entry(curr, page_buf_t, pb_list);
 
@@ -1657,7 +1655,6 @@ pagebuf_daemon(
 				pb->pb_flags &= ~PBF_DELWRI;
 				pb->pb_flags |= PBF_WRITE;
 				list_move(&pb->pb_list, &tmp);
-				count++;
 			}
 		}
 
@@ -1667,12 +1664,11 @@ pagebuf_daemon(
 			list_del_init(&pb->pb_list);
 
 			pagebuf_iostrategy(pb);
+			blk_run_address_space(pb->pb_target->pbr_mapping);
 		}
 
 		if (as_list_len > 0)
 			purge_addresses();
-		if (count)
-			blk_run_queues();
 
 		force_flush = 0;
 	} while (pagebuf_daemon_active);
@@ -1689,7 +1685,6 @@ pagebuf_delwri_flush(
 	page_buf_t		*pb;
 	struct list_head	*curr, *next, tmp;
 	int			pincount = 0;
-	int			flush_cnt = 0;
 
 	pagebuf_runall_queues(pagebuf_dataio_workqueue);
 	pagebuf_runall_queues(pagebuf_logio_workqueue);
@@ -1733,14 +1728,8 @@ pagebuf_delwri_flush(
 
 		pagebuf_lock(pb);
 		pagebuf_iostrategy(pb);
-		if (++flush_cnt > 32) {
-			blk_run_queues();
-			flush_cnt = 0;
-		}
 	}
 
-	blk_run_queues();
-
 	while (!list_empty(&tmp)) {
 		pb = list_entry(tmp.next, page_buf_t, pb_list);
 
@@ -1751,6 +1740,9 @@ pagebuf_delwri_flush(
 		pagebuf_rele(pb);
 	}
 
+	if (flags & PBDF_WAIT)
+		blk_run_address_space(target->pbr_mapping);
+
 	if (pinptr)
 		*pinptr = pincount;
 }
--- diff/fs/xfs/linux/xfs_vnode.h	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/xfs/linux/xfs_vnode.h	2004-03-16 09:37:57.741762088 +0000
@@ -600,7 +600,8 @@ static __inline__ void vn_flagclr(struct
 	(!list_empty(&(LINVFS_GET_IP(vp)->i_mapping->i_mmap)) || \
 	(!list_empty(&(LINVFS_GET_IP(vp)->i_mapping->i_mmap_shared))))
 #define VN_CACHED(vp)	(LINVFS_GET_IP(vp)->i_mapping->nrpages)
-#define VN_DIRTY(vp)	(!list_empty(&(LINVFS_GET_IP(vp)->i_mapping->dirty_pages)))
+#define VN_DIRTY(vp)	mapping_tagged(LINVFS_GET_IP(vp)->i_mapping, \
+					PAGECACHE_TAG_DIRTY)
 #define VMODIFY(vp)	VN_FLAGSET(vp, VMODIFIED)
 #define VUNMODIFY(vp)	VN_FLAGCLR(vp, VMODIFIED)
 
--- diff/include/acpi/acconfig.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/acpi/acconfig.h	2004-03-16 09:37:57.742761936 +0000
@@ -64,7 +64,7 @@
 
 /* Version string */
 
-#define ACPI_CA_VERSION                 0x20040220
+#define ACPI_CA_VERSION                 0x20040311
 
 /* Maximum objects in the various object caches */
 
@@ -185,6 +185,10 @@
 
 #define ACPI_SMBUS_BUFFER_SIZE          34
 
+/* Number of strings associated with the _OSI reserved method */
+
+#define ACPI_NUM_OSI_STRINGS            4
+
 
 /******************************************************************************
  *
--- diff/include/acpi/acglobal.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/acpi/acglobal.h	2004-03-16 09:37:57.742761936 +0000
@@ -79,6 +79,14 @@ extern      u32                         
 
 extern      u32                                 acpi_gbl_nesting_level;
 
+/*****************************************************************************
+ *
+ * Runtime configuration
+ *
+ ****************************************************************************/
+
+ACPI_EXTERN u8                                  acpi_gbl_create_osi_method;
+ACPI_EXTERN u8                                  acpi_gbl_all_methods_serialized;
 
 /*****************************************************************************
  *
@@ -169,6 +177,7 @@ extern const char                       
 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];
+extern const char                              *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS];
 
 
 /*****************************************************************************
@@ -179,7 +188,7 @@ extern const char                       
 
 #define NUM_NS_TYPES                    ACPI_TYPE_INVALID+1
 
-#if defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)
+#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)
 #define NUM_PREDEFINED_NAMES            10
 #else
 #define NUM_PREDEFINED_NAMES            9
--- diff/include/acpi/acmacros.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/acpi/acmacros.h	2004-03-16 09:37:57.743761784 +0000
@@ -681,7 +681,4 @@
 
 #endif /* ACPI_DBG_TRACK_ALLOCATIONS */
 
-
-#define ACPI_GET_STACK_POINTER          _asm {mov eax, ebx}
-
 #endif /* ACMACROS_H */
--- diff/include/acpi/acobject.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/acpi/acobject.h	2004-03-16 09:37:57.743761784 +0000
@@ -180,7 +180,11 @@ struct acpi_object_event
 };
 
 
-#define INFINITE_CONCURRENCY        0xFF
+#define ACPI_INFINITE_CONCURRENCY   0xFF
+
+typedef
+acpi_status (*ACPI_INTERNAL_METHOD) (
+	struct acpi_walk_state          *walk_state);
 
 struct acpi_object_method
 {
@@ -190,6 +194,7 @@ struct acpi_object_method
 	u32                                     aml_length;
 	void                                    *semaphore;
 	u8                                      *aml_start;
+	ACPI_INTERNAL_METHOD            implementation;
 	u8                                      concurrency;
 	u8                                      thread_count;
 	acpi_owner_id                           owning_id;
--- diff/include/acpi/acpixf.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/acpi/acpixf.h	2004-03-16 09:37:57.744761632 +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-03-11 10:20:28.000000000 +0000
+++ source/include/acpi/actypes.h	2004-03-16 09:37:57.745761480 +0000
@@ -349,7 +349,6 @@ typedef u64                             
 /*
  * Power state values
  */
-
 #define ACPI_STATE_UNKNOWN              (u8) 0xFF
 
 #define ACPI_STATE_S0                   (u8) 0
@@ -393,7 +392,6 @@ typedef u64                             
 #define ACPI_NOTIFY_BUS_MODE_MISMATCH   (u8) 6
 #define ACPI_NOTIFY_POWER_FAULT         (u8) 7
 
-
 /*
  *  Table types.  These values are passed to the table related APIs
  */
@@ -409,7 +407,6 @@ typedef u32                             
 #define ACPI_TABLE_MAX                  6
 #define NUM_ACPI_TABLE_TYPES            (ACPI_TABLE_MAX+1)
 
-
 /*
  * Types associated with ACPI names and objects.  The first group of
  * values (up to ACPI_TYPE_EXTERNAL_MAX) correspond to the definition
@@ -794,7 +791,7 @@ acpi_status (*acpi_init_handler) (
 #define ACPI_INIT_DEVICE_INI        1
 
 
-/* Address Spaces (Operation Regions */
+/* Address Spaces (For Operation Regions) */
 
 typedef
 acpi_status (*acpi_adr_space_handler) (
--- diff/include/acpi/acutils.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/acpi/acutils.h	2004-03-16 09:37:57.745761480 +0000
@@ -52,7 +52,6 @@ acpi_status (*acpi_pkg_callback) (
 	union acpi_generic_state        *state,
 	void                            *context);
 
-
 acpi_status
 acpi_ut_walk_package_tree (
 	union acpi_operand_object       *source_object,
@@ -60,7 +59,6 @@ acpi_ut_walk_package_tree (
 	acpi_pkg_callback               walk_callback,
 	void                            *context);
 
-
 struct acpi_pkg_info
 {
 	u8                              *free_space;
@@ -476,6 +474,10 @@ acpi_ut_delete_internal_object_list (
 
 
 acpi_status
+acpi_ut_osi_implementation (
+	struct acpi_walk_state          *walk_state);
+
+acpi_status
 acpi_ut_evaluate_object (
 	struct acpi_namespace_node      *prefix_node,
 	char                            *path,
--- diff/include/acpi/amlcode.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/acpi/amlcode.h	2004-03-16 09:37:57.746761328 +0000
@@ -496,11 +496,17 @@ typedef enum
 } AML_ACCESS_ATTRIBUTE;
 
 
-/* bit fields in method_flags byte */
+/* Bit fields in method_flags byte */
 
-#define METHOD_FLAGS_ARG_COUNT      0x07
-#define METHOD_FLAGS_SERIALIZED     0x08
-#define METHOD_FLAGS_SYNCH_LEVEL    0xF0
+#define AML_METHOD_ARG_COUNT        0x07
+#define AML_METHOD_SERIALIZED       0x08
+#define AML_METHOD_SYNCH_LEVEL      0xF0
+
+/* METHOD_FLAGS_ARG_COUNT is not used internally, define additional flags */
+
+#define AML_METHOD_INTERNAL_ONLY    0x01
+#define AML_METHOD_RESERVED1        0x02
+#define AML_METHOD_RESERVED2        0x04
 
 
 #endif /* __AMLCODE_H__ */
--- diff/include/asm-alpha/irq.h	2003-08-20 13:16:33.000000000 +0000
+++ source/include/asm-alpha/irq.h	2004-03-16 09:37:57.747761176 +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-16 09:37:57.748761024 +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 08:47:17.000000000 +0000
+++ source/include/asm-alpha/spinlock.h	2004-03-16 09:37:57.748761024 +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/arch-ebsa285/irqs.h	2003-05-21 10:50:16.000000000 +0000
+++ source/include/asm-arm/arch-ebsa285/irqs.h	2004-03-16 09:37:57.749760872 +0000
@@ -91,8 +91,8 @@
 
 #undef RTC_IRQ
 #define RTC_IRQ		IRQ_ISA_RTC_ALARM
-#undef AUX_IRQ
-#define AUX_IRQ		(machine_is_netwinder() ? IRQ_NETWINDER_PS2MOUSE : IRQ_ISA_PS2MOUSE)
+#define I8042_KBD_IRQ	IRQ_ISA_KEYBOARD
+#define I8042_AUX_IRQ	(machine_is_netwinder() ? IRQ_NETWINDER_PS2MOUSE : IRQ_ISA_PS2MOUSE)
 #define IRQ_FLOPPYDISK	IRQ_ISA_FLOPPY
 
 #define irq_canonicalize(_i)	(((_i) == IRQ_ISA_CASCADE) ? IRQ_ISA_2 : _i)
--- diff/include/asm-arm/arch-shark/irqs.h	2002-11-28 11:30:39.000000000 +0000
+++ source/include/asm-arm/arch-shark/irqs.h	2004-03-16 09:37:57.749760872 +0000
@@ -8,5 +8,6 @@
 
 #define IRQ_ISA_KEYBOARD	 1
 #define RTC_IRQ			 8
-#define AUX_IRQ			12
+#define I8042_KBD_IRQ		 1
+#define I8042_AUX_IRQ		12
 #define IRQ_HARDDISK            14
--- diff/include/asm-arm/dma-mapping.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-arm/dma-mapping.h	2004-03-16 09:37:57.750760720 +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 10:50:16.000000000 +0000
+++ source/include/asm-arm/irq.h	2004-03-16 09:37:57.751760568 +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 09:07:24.000000000 +0000
+++ source/include/asm-arm26/irq.h	2004-03-16 09:37:57.751760568 +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-arm26/thread_info.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-arm26/thread_info.h	2004-03-16 09:37:57.752760416 +0000
@@ -81,8 +81,6 @@ static inline struct thread_info *curren
 
 /* FIXME - PAGE_SIZE < 32K */
 #define THREAD_SIZE		(8192)
-/*FIXME INIT_THREAD_SIZE - how big? */
-//#define INIT_THREAD_SIZE        (65536)
 #define __get_user_regs(x) (((struct pt_regs *)((unsigned long)(x) + THREAD_SIZE - 8)) - 1)
 
 extern struct thread_info *alloc_thread_info(struct task_struct *task);
--- diff/include/asm-cris/irq.h	2003-07-11 08:39:50.000000000 +0000
+++ source/include/asm-cris/irq.h	2004-03-16 09:37:57.752760416 +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-16 09:37:57.753760264 +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-16 09:37:57.753760264 +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 09:00:54.000000000 +0000
+++ source/include/asm-generic/siginfo.h	2004-03-16 09:37:57.753760264 +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-11 10:20:28.000000000 +0000
+++ source/include/asm-generic/tlb.h	2004-03-16 09:37:57.754760112 +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 11:28:12.000000000 +0000
+++ source/include/asm-h8300/irq.h	2004-03-16 09:37:57.754760112 +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-11 10:20:28.000000000 +0000
+++ source/include/asm-h8300/unistd.h	2004-03-16 09:37:57.755759960 +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-03-11 10:20:28.000000000 +0000
+++ source/include/asm-i386/acpi.h	2004-03-16 09:37:57.755759960 +0000
@@ -28,6 +28,8 @@
 
 #ifdef __KERNEL__
 
+#include <asm/system.h>		/* defines cmpxchg */
+
 #define COMPILER_DEPENDENT_INT64   long long
 #define COMPILER_DEPENDENT_UINT64  unsigned long long
 
@@ -61,33 +63,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
--- diff/include/asm-i386/bugs.h	2003-10-09 08:47:17.000000000 +0000
+++ source/include/asm-i386/bugs.h	2004-03-16 09:37:57.756759808 +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-16 09:37:57.756759808 +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/desc.h	2003-10-09 08:47:17.000000000 +0000
+++ source/include/asm-i386/desc.h	2004-03-16 09:37:57.756759808 +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-16 09:37:57.757759656 +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/edd.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-i386/edd.h	2004-03-16 09:37:57.758759504 +0000
@@ -34,10 +34,11 @@
 				   in empty_zero_block - treat this as 1 byte  */
 #define EDDBUF	0x600		/* addr of edd_info structs in empty_zero_block */
 #define EDDMAXNR 6		/* number of edd_info structs starting at EDDBUF  */
-#define EDDEXTSIZE 4		/* change these if you muck with the structures */
+#define EDDEXTSIZE 8		/* change these if you muck with the structures */
 #define EDDPARMSIZE 74
 #define CHECKEXTENSIONSPRESENT 0x41
 #define GETDEVICEPARAMETERS 0x48
+#define LEGACYGETDEVICEPARAMETERS 0x08
 #define EDDMAGIC1 0x55AA
 #define EDDMAGIC2 0xAA55
 
@@ -165,6 +166,9 @@ struct edd_info {
 	u8 device;
 	u8 version;
 	u16 interface_support;
+	u16 legacy_cylinders;
+	u8 legacy_heads;
+	u8 legacy_sectors;
 	struct edd_device_params params;
 } __attribute__ ((packed));
 
--- diff/include/asm-i386/fixmap.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-i386/fixmap.h	2004-03-16 09:37:57.759759352 +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,16 +64,21 @@ 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,
@@ -98,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 08:47:34.000000000 +0000
+++ source/include/asm-i386/highmem.h	2004-03-16 09:37:57.759759352 +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-16 09:37:57.760759200 +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-16 09:37:57.760759200 +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 08:47:17.000000000 +0000
+++ source/include/asm-i386/kmap_types.h	2004-03-16 09:37:57.761759048 +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/mman.h	2003-10-09 08:47:34.000000000 +0000
+++ source/include/asm-i386/mman.h	2004-03-16 09:37:57.761759048 +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 08:47:17.000000000 +0000
+++ source/include/asm-i386/mmu.h	2004-03-16 09:37:57.762758896 +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 08:47:17.000000000 +0000
+++ source/include/asm-i386/mmu_context.h	2004-03-16 09:37:57.762758896 +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-11 10:20:28.000000000 +0000
+++ source/include/asm-i386/module.h	2004-03-16 09:37:57.763758744 +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 08:47:17.000000000 +0000
+++ source/include/asm-i386/page.h	2004-03-16 09:37:57.764758592 +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-16 09:37:57.764758592 +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 10:49:56.000000000 +0000
+++ source/include/asm-i386/pgtable-2level.h	2004-03-16 09:37:57.765758440 +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 13:16:33.000000000 +0000
+++ source/include/asm-i386/pgtable-3level.h	2004-03-16 09:37:57.765758440 +0000
@@ -120,7 +120,18 @@ 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
 
+extern struct kmem_cache_s *pae_pgd_cachep;
+
 #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-16 09:37:57.766758288 +0000
@@ -32,16 +32,20 @@
 #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 spinlock_t pgd_lock;
-extern struct list_head pgd_list;
+extern kmem_cache_t *pgd_cache, *pmd_cache, *kpmd_cache;
 
 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);
+
+/*
+ * The size of the low 1:1 mappings that we use during bootup,
+ * SMP-boot and ACPI-sleep:
+ */
+#define LOW_MAPPINGS_SIZE (16*1024*1024)
 
 #endif /* !__ASSEMBLY__ */
 
@@ -51,6 +55,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 +72,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 +187,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 +247,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-11 10:20:28.000000000 +0000
+++ source/include/asm-i386/processor.h	2004-03-16 09:37:57.767758136 +0000
@@ -63,6 +63,7 @@ struct cpuinfo_x86 {
 	int	f00f_bug;
 	int	coma_bug;
 	unsigned long loops_per_jiffy;
+	int     x86_clflush_size;	/* cache line size of L2 */
 } __attribute__((__aligned__(SMP_CACHE_BYTES)));
 
 #define X86_VENDOR_INTEL 0
@@ -291,11 +292,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.
  */
@@ -403,9 +399,12 @@ struct tss_struct {
 	unsigned long stack[64];
 } __attribute__((packed));
 
+#define ARCH_MIN_TASKALIGN	16
+
 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 +448,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 +485,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 +663,12 @@ 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
+
+#define cache_line_size() (boot_cpu_data.x86_clflush_size)
+extern void early_identify_cpu(struct cpuinfo_x86 *c);
+
 #endif /* __ASM_I386_PROCESSOR_H */
--- diff/include/asm-i386/rwlock.h	2003-10-09 08:47:17.000000000 +0000
+++ source/include/asm-i386/rwlock.h	2004-03-16 09:37:57.768757984 +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-03-11 10:20:28.000000000 +0000
+++ source/include/asm-i386/smp.h	2004-03-16 09:37:57.768757984 +0000
@@ -34,7 +34,7 @@
 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);
--- diff/include/asm-i386/spinlock.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-i386/spinlock.h	2004-03-16 09:37:57.769757832 +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-16 09:37:57.769757832 +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-11 10:20:28.000000000 +0000
+++ source/include/asm-i386/thread_info.h	2004-03-16 09:37:57.770757680 +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,8 @@ 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_SYSCALL_AUDIT	7	/* syscall auditing active */
 #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
@@ -141,9 +151,13 @@ 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_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
+#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 */
+/* work to do on interrupt/exception return */
+#define _TIF_WORK_MASK \
+  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT))
 #define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
 
 /*
--- diff/include/asm-i386/tlbflush.h	2003-10-09 08:47:17.000000000 +0000
+++ source/include/asm-i386/tlbflush.h	2004-03-16 09:37:57.770757680 +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-16 09:37:57.771757528 +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 08:47:17.000000000 +0000
+++ source/include/asm-i386/uaccess.h	2004-03-16 09:37:57.772757376 +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-11 10:20:28.000000000 +0000
+++ source/include/asm-i386/unistd.h	2004-03-16 09:37:57.772757376 +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/compat.h	2003-08-20 13:16:33.000000000 +0000
+++ source/include/asm-ia64/compat.h	2004-03-16 09:37:57.773757224 +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 13:18:20.000000000 +0000
+++ source/include/asm-ia64/dma-mapping.h	2004-03-16 09:37:57.773757224 +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/hardirq.h	2003-08-20 13:16:33.000000000 +0000
+++ source/include/asm-ia64/hardirq.h	2004-03-16 09:37:57.774757072 +0000
@@ -2,7 +2,7 @@
 #define _ASM_IA64_HARDIRQ_H
 
 /*
- * Copyright (C) 1998-2002 Hewlett-Packard Co
+ * Modified 1998-2002, 2004 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
@@ -86,8 +86,6 @@
 #define hardirq_trylock()	(!in_interrupt())
 #define hardirq_endlock()	do { } while (0)
 
-#define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
-
 #ifdef CONFIG_PREEMPT
 # include <linux/smp_lock.h>
 # define in_atomic()		((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked())
@@ -97,14 +95,6 @@
 # define IRQ_EXIT_OFFSET HARDIRQ_OFFSET
 #endif
 
-#define irq_exit()						\
-do {								\
-		preempt_count() -= IRQ_EXIT_OFFSET;		\
-		if (!in_interrupt() && local_softirq_pending())	\
-			do_softirq();				\
-		preempt_enable_no_resched();			\
-} while (0)
-
 #ifdef CONFIG_SMP
   extern void synchronize_irq (unsigned int irq);
 #else
--- diff/include/asm-ia64/ia32.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/asm-ia64/ia32.h	2004-03-16 09:37:57.774757072 +0000
@@ -6,7 +6,7 @@
 #include <asm/ptrace.h>
 #include <asm/signal.h>
 
-#define IA32_NR_syscalls		275 /* length of syscall table */
+#define IA32_NR_syscalls		281 /* length of syscall table */
 
 #ifndef __ASSEMBLY__
 
--- diff/include/asm-ia64/irq.h	2003-05-21 10:50:16.000000000 +0000
+++ source/include/asm-ia64/irq.h	2004-03-16 09:37:57.774757072 +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-16 09:37:57.775756920 +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 13:18:20.000000000 +0000
+++ source/include/asm-ia64/machvec_hpzx1.h	2004-03-16 09:37:57.776756768 +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-16 09:37:57.776756768 +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/mman.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ia64/mman.h	2004-03-16 09:37:57.777756616 +0000
@@ -30,6 +30,7 @@
 #define MAP_NORESERVE	0x04000		/* don't check for reservations */
 #define MAP_POPULATE	0x08000		/* 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-ia64/pci.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-ia64/pci.h	2004-03-16 09:37:57.779756312 +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/pgtable.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ia64/pgtable.h	2004-03-16 09:37:57.780756160 +0000
@@ -433,7 +433,8 @@ extern void paging_init (void);
  * Format of file pte:
  *	bit   0   : present bit (must be zero)
  *	bit   1   : _PAGE_FILE (must be one)
- *	bits  2-62: file_offset/PAGE_SIZE
+ *	bit   2   : _PAGE_AR_RW
+ *	bits  3-62: file_offset/PAGE_SIZE
  *	bit  63   : _PAGE_PROTNONE bit
  */
 #define __swp_type(entry)		(((entry).val >> 2) & 0x7f)
@@ -442,9 +443,17 @@ extern void paging_init (void);
 #define __pte_to_swp_entry(pte)		((swp_entry_t) { pte_val(pte) })
 #define __swp_entry_to_pte(x)		((pte_t) { (x).val })
 
-#define PTE_FILE_MAX_BITS		61
-#define pte_to_pgoff(pte)		((pte_val(pte) << 1) >> 3)
-#define pgoff_to_pte(off)		((pte_t) { ((off) << 2) | _PAGE_FILE })
+#define PTE_FILE_MAX_BITS		59
+#define pte_to_pgoff(pte)		((pte_val(pte) << 1) >> 4)
+
+#define pte_to_pgprot(pte) \
+	__pgprot((pte_val(pte) & (_PAGE_AR_RW | _PAGE_PROTNONE)) \
+		| ((pte_val(pte) & _PAGE_PROTNONE) ? 0 : \
+			(__ACCESS_BITS | _PAGE_PL_3)))
+
+#define pgoff_prot_to_pte(off, prot) \
+       ((pte_t) { _PAGE_FILE + \
+               (pgprot_val(prot) & (_PAGE_AR_RW | _PAGE_PROTNONE)) + (off) })
 
 #define io_remap_page_range remap_page_range	/* XXX is this right? */
 
--- diff/include/asm-ia64/sal.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/asm-ia64/sal.h	2004-03-16 09:37:57.781756008 +0000
@@ -35,6 +35,7 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/bcd.h>
 #include <linux/spinlock.h>
 #include <linux/efi.h>
 
@@ -229,6 +230,10 @@ typedef struct ia64_sal_desc_ap_wakeup {
 extern ia64_sal_handler ia64_sal;
 extern struct ia64_sal_desc_ptc *ia64_ptc_domain_info;
 
+extern unsigned short sal_revision;	/* supported SAL spec revision */
+extern unsigned short sal_version;	/* SAL version; OEM dependent */
+#define SAL_VERSION_CODE(major, minor) ((BIN2BCD(major) << 8) | BIN2BCD(minor))
+
 extern const char *ia64_sal_strerror (long status);
 extern void ia64_sal_init (struct ia64_sal_systab *sal_systab);
 
@@ -741,10 +746,10 @@ ia64_sal_mc_set_params (u64 param_type, 
 
 /* Read from PCI configuration space */
 static inline s64
-ia64_sal_pci_config_read (u64 pci_config_addr, u64 size, u64 *value)
+ia64_sal_pci_config_read (u64 pci_config_addr, int type, u64 size, u64 *value)
 {
 	struct ia64_sal_retval isrv;
-	SAL_CALL(isrv, SAL_PCI_CONFIG_READ, pci_config_addr, size, 0, 0, 0, 0, 0);
+	SAL_CALL(isrv, SAL_PCI_CONFIG_READ, pci_config_addr, size, type, 0, 0, 0, 0);
 	if (value)
 		*value = isrv.v0;
 	return isrv.status;
@@ -752,11 +757,11 @@ ia64_sal_pci_config_read (u64 pci_config
 
 /* Write to PCI configuration space */
 static inline s64
-ia64_sal_pci_config_write (u64 pci_config_addr, u64 size, u64 value)
+ia64_sal_pci_config_write (u64 pci_config_addr, int type, u64 size, u64 value)
 {
 	struct ia64_sal_retval isrv;
 	SAL_CALL(isrv, SAL_PCI_CONFIG_WRITE, pci_config_addr, size, value,
-	         0, 0, 0, 0);
+	         type, 0, 0, 0);
 	return isrv.status;
 }
 
--- diff/include/asm-ia64/sn/router.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ia64/sn/router.h	2004-03-16 09:37:57.782755856 +0000
@@ -20,6 +20,7 @@
 #include <asm/sn/vector.h>
 #include <asm/sn/slotnum.h>
 #include <asm/sn/arch.h>
+#include <asm/sn/sgi.h>
 
 typedef uint64_t	router_reg_t;
 
--- diff/include/asm-ia64/spinlock.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/asm-ia64/spinlock.h	2004-03-16 09:37:57.788754944 +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-11 10:20:28.000000000 +0000
+++ source/include/asm-ia64/tlb.h	2004-03-16 09:37:57.789754792 +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-ia64/unistd.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-ia64/unistd.h	2004-03-16 09:37:57.789754792 +0000
@@ -248,6 +248,9 @@
 #define __NR_clock_nanosleep		1256
 #define __NR_fstatfs64			1257
 #define __NR_statfs64			1258
+#define __NR_reserved1			1259	/* reserved for NUMA interface */
+#define __NR_reserved2			1260	/* reserved for NUMA interface */
+#define __NR_reserved3			1261	/* reserved for NUMA interface */
 
 #ifdef __KERNEL__
 
--- diff/include/asm-m68k/bitops.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-m68k/bitops.h	2004-03-16 09:37:57.790754640 +0000
@@ -21,6 +21,8 @@
    __constant_test_and_set_bit(nr, vaddr) : \
    __generic_test_and_set_bit(nr, vaddr))
 
+#define __test_and_set_bit(nr,vaddr) test_and_set_bit(nr,vaddr)
+
 static inline int __constant_test_and_set_bit(int nr,
 					      volatile unsigned long *vaddr)
 {
--- diff/include/asm-m68k/irq.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-m68k/irq.h	2004-03-16 09:37:57.791754488 +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-11 10:20:28.000000000 +0000
+++ source/include/asm-m68k/unistd.h	2004-03-16 09:37:57.791754488 +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-11 10:20:28.000000000 +0000
+++ source/include/asm-m68knommu/irq.h	2004-03-16 09:37:57.792754336 +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-11 10:20:28.000000000 +0000
+++ source/include/asm-m68knommu/unistd.h	2004-03-16 09:37:57.792754336 +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-11 10:20:28.000000000 +0000
+++ source/include/asm-mips/dma-mapping.h	2004-03-16 09:37:57.793754184 +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-11 10:20:28.000000000 +0000
+++ source/include/asm-mips/irq.h	2004-03-16 09:37:57.793754184 +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-11 10:20:28.000000000 +0000
+++ source/include/asm-mips/pci.h	2004-03-16 09:37:57.793754184 +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-11 10:20:28.000000000 +0000
+++ source/include/asm-mips/spinlock.h	2004-03-16 09:37:57.794754032 +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-16 09:37:57.794754032 +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/floppy.h	2002-11-11 11:09:38.000000000 +0000
+++ source/include/asm-parisc/floppy.h	2004-03-16 09:37:57.795753880 +0000
@@ -1,11 +1,22 @@
-/*
- * Architecture specific parts of the Floppy driver
+/*    Architecture specific parts of the Floppy driver
+ *
+ *    Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *    Copyright (C) 2000 Matthew Wilcox (willy a debian . org)
+ *    Copyright (C) 2000 Dave Kennedy
+ *
+ *    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 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.
+ *    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) 1995
+ *    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 __ASM_PARISC_FLOPPY_H
 #define __ASM_PARISC_FLOPPY_H
--- diff/include/asm-parisc/grfioctl.h	2002-11-11 11:09:38.000000000 +0000
+++ source/include/asm-parisc/grfioctl.h	2004-03-16 09:37:57.795753880 +0000
@@ -1,7 +1,23 @@
-/*
- * Architecture specific parts of HP's STI (framebuffer) driver
- * structures are HP-UX compatible for XFree86 usage 
- */ 
+/*  Architecture specific parts of HP's STI (framebuffer) driver.
+ *  Structures are HP-UX compatible for XFree86 usage.
+ * 
+ *    Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *    Copyright (C) 2001 Helge Deller (deller a parisc-linux org)
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    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 __ASM_PARISC_GRFIOCTL_H
 #define __ASM_PARISC_GRFIOCTL_H
--- diff/include/asm-parisc/ide.h	2003-05-21 10:49:56.000000000 +0000
+++ source/include/asm-parisc/ide.h	2004-03-16 09:37:57.796753728 +0000
@@ -14,36 +14,13 @@
 #ifdef __KERNEL__
 
 #include <linux/config.h>
-#include <asm/superio.h>
 
 #ifndef MAX_HWIFS
 #define MAX_HWIFS	2
 #endif
 
-static __inline__ int ide_default_irq(ide_ioreg_t base)
-{
-	switch (base) {
-#ifdef CONFIG_SUPERIO
-		case 0x1f0: 
-		case 0x170:
-			return superio_get_ide_irq();
-#endif /* CONFIG_SUPERIO */
-		default:
-			return 0;
-	}
-}
-
-static __inline__ ide_ioreg_t ide_default_io_base(int index)
-{
-	switch (index) {
-#ifdef CONFIG_SUPERIO 
-		case 0:	return (superio_get_ide_irq() ? 0x1f0 : 0);
-		case 1:	return (superio_get_ide_irq() ? 0x170 : 0);
-#endif /* CONFIG_SUPERIO */
-		default:
-			return 0;
-	}
-}
+#define ide_default_irq(base) (0)
+#define ide_default_io_base(index) ((ide_ioreg_t)0)
 
 static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
@@ -93,7 +70,7 @@ static __inline__ void ide_init_default_
 static __inline__ void __ide_mm_insw(unsigned long port, void *addr, u32 count)
 {
 	while (count--) {
-		*(u16 *)addr = readw(port);
+		*(u16 *)addr = __raw_readw(port);
 		addr += 2;
 	}
 }
@@ -101,7 +78,7 @@ static __inline__ void __ide_mm_insw(uns
 static __inline__ void __ide_mm_insl(unsigned long port, void *addr, u32 count)
 {
 	while (count--) {
-		*(u32 *)addr = readl(port);
+		*(u32 *)addr = __raw_readl(port);
 		addr += 4;
 	}
 }
@@ -109,7 +86,7 @@ static __inline__ void __ide_mm_insl(uns
 static __inline__ void __ide_mm_outsw(unsigned long port, void *addr, u32 count)
 {
 	while (count--) {
-		writew(*(u16 *)addr, port);
+		__raw_writew(*(u16 *)addr, port);
 		addr += 2;
 	}
 }
@@ -117,7 +94,7 @@ static __inline__ void __ide_mm_outsw(un
 static __inline__ void __ide_mm_outsl(unsigned long port, void *addr, u32 count)
 {
 	while (count--) {
-		writel(*(u32 *)addr, port);
+		__raw_writel(*(u32 *)addr, port);
 		addr += 4;
 	}
 }
--- diff/include/asm-parisc/io.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-parisc/io.h	2004-03-16 09:37:57.796753728 +0000
@@ -13,6 +13,12 @@
 #include <linux/types.h>
 #include <asm/pgtable.h>
 
+extern unsigned long parisc_vmerge_boundary;
+extern unsigned long parisc_vmerge_max_size;
+
+#define BIO_VMERGE_BOUNDARY	parisc_vmerge_boundary
+#define BIO_VMERGE_MAX_SIZE	parisc_vmerge_max_size
+
 #define virt_to_phys(a) ((unsigned long)__pa(a))
 #define phys_to_virt(a) __va(a)
 #define virt_to_bus virt_to_phys
--- diff/include/asm-parisc/ioctl.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/asm-parisc/ioctl.h	2004-03-16 09:37:57.796753728 +0000
@@ -1,8 +1,24 @@
-/* $Id: ioctl.h,v 1.2 1999/12/29 22:18:15 willy Exp $
+/*
+ *    Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *    Copyright (C) 1999,2003 Matthew Wilcox < willy at debian . org >
+ *    portions from "linux/ioctl.h for Linux" by H.H. Bergman.
+ *
+ *    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.
  *
- * linux/ioctl.h for Linux by H.H. Bergman.
+ *    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 _ASM_PARISC_IOCTL_H
 #define _ASM_PARISC_IOCTL_H
 
--- diff/include/asm-parisc/irq.h	2003-10-09 08:47:34.000000000 +0000
+++ source/include/asm-parisc/irq.h	2004-03-16 09:37:57.797753576 +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/namei.h	2002-10-16 03:28:20.000000000 +0000
+++ source/include/asm-parisc/namei.h	2004-03-16 09:37:57.797753576 +0000
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.1.1.1 1999/03/15 19:41:02 pjlahaie Exp $
+/* $Id: namei.h,v 1.1 1996/12/13 14:48:21 jj Exp $
  * linux/include/asm-parisc/namei.h
  *
  * Included from linux/fs/namei.c
--- diff/include/asm-parisc/pci.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-parisc/pci.h	2004-03-16 09:37:57.798753424 +0000
@@ -43,7 +43,7 @@
 **
 ** This is the "common" or "base" data structure which HBA drivers
 ** (eg Dino or LBA) are required to place at the top of their own
-** dev->sysdata structure.  I've heard this called "C inheritance" too.
+** platform_data structure.  I've heard this called "C inheritance" too.
 **
 ** Data needed by pcibios layer belongs here.
 */
--- diff/include/asm-parisc/semaphore.h	2003-09-17 11:28:12.000000000 +0000
+++ source/include/asm-parisc/semaphore.h	2004-03-16 09:37:57.798753424 +0000
@@ -1,15 +1,29 @@
-#ifndef _ASM_PARISC_SEMAPHORE_H
-#define _ASM_PARISC_SEMAPHORE_H
-
-/*
- * SMP- and interrupt-safe semaphores.
+/*    SMP- and interrupt-safe semaphores.
+ *    PA-RISC version by Matthew Wilcox
  *
- * (C) Copyright 1996 Linus Torvalds
+ *    Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *    Copyright (C) 1996 Linus Torvalds
+ *    Copyright (C) 1999-2001 Matthew Wilcox < willy at debian d0T org >
+ *    Copyright (C) 2000 Grant Grundler < grundler a debian org >
  *
- * PA-RISC version by Matthew Wilcox
+ *    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 _ASM_PARISC_SEMAPHORE_H
+#define _ASM_PARISC_SEMAPHORE_H
+
 #include <linux/spinlock.h>
 #include <linux/wait.h>
 #include <linux/rwsem.h>
--- diff/include/asm-parisc/superio.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-parisc/superio.h	2004-03-16 09:37:57.798753424 +0000
@@ -81,9 +81,12 @@ struct superio_device {
 	|| ((x)->device == PCI_DEVICE_ID_NS_87560_LIO) \
 	|| ((x)->device == PCI_DEVICE_ID_NS_87560_USB) ) )
 
+struct hwif_s;
+
 extern void superio_inform_irq(int irq);
 extern void superio_serial_init(void);		/* called by rs_init() */
 extern int superio_fixup_irq(struct pci_dev *pcidev); /* called by iosapic */
-extern int superio_get_ide_irq(void);
+extern void superio_fixup_pci(struct pci_dev *pdev);
+extern void superio_ide_init_iops (struct hwif_s *hwif);
 
 #endif /* _PARISC_SUPERIO_H */
--- diff/include/asm-parisc/unistd.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-parisc/unistd.h	2004-03-16 09:37:57.799753272 +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 14:46:19.000000000 +0000
+++ source/include/asm-ppc/irq.h	2004-03-16 09:37:57.799753272 +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 14:46:19.000000000 +0000
+++ source/include/asm-ppc/mman.h	2004-03-16 09:37:57.800753120 +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-16 09:37:57.800753120 +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-16 09:37:57.801752968 +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-16 09:37:57.802752816 +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/dma-mapping.h	2002-12-30 10:17:13.000000000 +0000
+++ source/include/asm-ppc64/dma-mapping.h	2004-03-16 09:37:57.802752816 +0000
@@ -1 +1,75 @@
-#include <asm-generic/dma-mapping.h>
+/* Copyright (C) 2004 IBM
+ *
+ * Implements the generic device dma API for ppc64. Handles
+ * the pci and vio busses
+ */
+
+#ifndef _ASM_DMA_MAPPING_H
+#define _ASM_DMA_MAPPING_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/cache.h>
+/* need struct page definitions */
+#include <linux/mm.h>
+#include <asm/scatterlist.h>
+#include <asm/bug.h>
+
+extern int dma_supported(struct device *dev, u64 mask);
+extern int dma_set_mask(struct device *dev, u64 dma_mask);
+extern void *dma_alloc_coherent(struct device *dev, size_t size,
+		dma_addr_t *dma_handle, int flag);
+extern void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
+		dma_addr_t dma_handle);
+extern dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
+		size_t size, enum dma_data_direction direction);
+extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
+		size_t size, enum dma_data_direction direction);
+extern dma_addr_t dma_map_page(struct device *dev, struct page *page,
+		unsigned long offset, size_t size,
+		enum dma_data_direction direction);
+extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+		size_t size, enum dma_data_direction direction);
+extern int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+		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,
+		size_t size, enum dma_data_direction direction);
+extern void dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems,
+		enum dma_data_direction direction);
+
+/* Now for the API extensions over the pci_ one */
+
+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
+#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+#define dma_is_consistent(d)	(1)
+
+static inline int
+dma_get_cache_alignment(void)
+{
+	/* no easy way to get cache size on all processors, so return
+	 * the maximum possible, to be safe */
+	return (1 << L1_CACHE_SHIFT_MAX);
+}
+
+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)
+{
+	/* just sync everything, that's all the pci API can do */
+	dma_sync_single(dev, dma_handle, offset+size, direction);
+}
+
+static inline void
+dma_cache_sync(void *vaddr, size_t size,
+	       enum dma_data_direction direction)
+{
+	/* could define this in terms of the dma_cache ... operations,
+	 * but if you get this on a platform, you should convert the platform
+	 * to using the generic device DMA API */
+	BUG();
+}
+
+#endif	/* _ASM_DMA_MAPPING_H */
--- diff/include/asm-ppc64/eeh.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-ppc64/eeh.h	2004-03-16 09:37:57.805752360 +0000
@@ -17,15 +17,11 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-/* Start Change Log
- * 2001/10/27 : engebret : Created.
- * End Change Log 
- */
-
-#ifndef _EEH_H
-#define _EEH_H
+#ifndef _PPC64_EEH_H
+#define _PPC64_EEH_H
 
 #include <linux/string.h>
+#include <linux/init.h>
 
 struct pci_dev;
 
@@ -33,22 +29,43 @@ struct pci_dev;
  * a bad page fault if the address is used directly (i.e. these addresses are
  * never actually mapped.  Translation between IO <-> EEH region is 1 to 1.
  */
-#define IO_TOKEN_TO_ADDR(token) (((unsigned long)(token) & ~(0xfUL << REGION_SHIFT)) | \
-				(IO_REGION_ID << REGION_SHIFT))
-#define IO_ADDR_TO_TOKEN(addr) (((unsigned long)(addr) & ~(0xfUL << REGION_SHIFT)) | \
-				(EEH_REGION_ID << REGION_SHIFT))
+#define IO_TOKEN_TO_ADDR(token) \
+	(((unsigned long)(token) & ~(0xfUL << REGION_SHIFT)) | \
+	(IO_REGION_ID << REGION_SHIFT))
+
+#define IO_ADDR_TO_TOKEN(addr) \
+	(((unsigned long)(addr) & ~(0xfUL << REGION_SHIFT)) | \
+	(EEH_REGION_ID << REGION_SHIFT))
 
 /* Values for eeh_mode bits in device_node */
 #define EEH_MODE_SUPPORTED	(1<<0)
 #define EEH_MODE_NOCHECK	(1<<1)
 
-/* This is for profiling only */
-extern unsigned long eeh_total_mmio_ffs;
-
-void eeh_init(void);
-int eeh_get_state(unsigned long ea);
+extern void __init eeh_init(void);
 unsigned long eeh_check_failure(void *token, unsigned long val);
 void *eeh_ioremap(unsigned long addr, void *vaddr);
+void __init pci_addr_cache_build(void);
+
+/**
+ * eeh_add_device - perform EEH initialization for the indicated pci device
+ * @dev: pci device for which to set up EEH
+ *
+ * This routine can be used to perform EEH initialization for PCI
+ * devices that were added after system boot (e.g. hotplug, dlpar).
+ * Whether this actually enables EEH or not for this device depends
+ * on the type of the device, on earlier boot command-line
+ * arguments & etc.
+ */
+void eeh_add_device(struct pci_dev *);
+
+/**
+ * eeh_remove_device - undo EEH setup for the indicated pci device
+ * @dev: pci device to be removed
+ *
+ * This routine should be when a device is removed from a running
+ * system (e.g. by hotplug or dlpar).
+ */
+void eeh_remove_device(struct pci_dev *);
 
 #define EEH_DISABLE		0
 #define EEH_ENABLE		1
@@ -56,18 +73,8 @@ void *eeh_ioremap(unsigned long addr, vo
 #define EEH_RELEASE_DMA		3
 int eeh_set_option(struct pci_dev *dev, int options);
 
-/* Given a PCI device check if eeh should be configured or not.
- * This may look at firmware properties and/or kernel cmdline options.
- */
-int is_eeh_configured(struct pci_dev *dev);
-
-/* Translate a (possible) eeh token to a physical addr.
- * If "token" is not an eeh token it is simply returned under
- * the assumption that it is already a physical addr.
- */
-unsigned long eeh_token_to_phys(unsigned long token);
-
-/* EEH_POSSIBLE_ERROR() -- test for possible MMIO failure.
+/*
+ * EEH_POSSIBLE_ERROR() -- test for possible MMIO failure.
  *
  * Order this macro for performance.
  * If EEH is off for a device and it is a memory BAR, ioremap will
@@ -78,30 +85,22 @@ unsigned long eeh_token_to_phys(unsigned
  * If this macro yields TRUE, the caller relays to eeh_check_failure()
  * which does further tests out of line.
  */
-/* #define EEH_POSSIBLE_IO_ERROR(val) (~(val) == 0) */
-/* #define EEH_POSSIBLE_ERROR(addr, vaddr, val) ((vaddr) != (addr) && EEH_POSSIBLE_IO_ERROR(val) */
-/* This version is rearranged to collect some profiling data */
-#define EEH_POSSIBLE_IO_ERROR(val) (~(val) == 0 && ++eeh_total_mmio_ffs)
-#define EEH_POSSIBLE_ERROR(addr, vaddr, val) (EEH_POSSIBLE_IO_ERROR(val) && (vaddr) != (addr))
+#define EEH_POSSIBLE_IO_ERROR(val, type)	((val) == (type)~0)
+
+/* The vaddr will equal the addr if EEH checking is disabled for
+ * this device.  This is because eeh_ioremap() will not have
+ * remapped to 0xA0, and thus both vaddr and addr will be 0xE0...
+ */
+#define EEH_POSSIBLE_ERROR(addr, vaddr, val, type) \
+		((vaddr) != (addr) && EEH_POSSIBLE_IO_ERROR(val, type))
 
 /* 
  * MMIO read/write operations with EEH support.
- *
- * addr: 64b token of the form 0xA0PPBBDDyyyyyyyy
- *       0xA0     : Unmapped MMIO region
- *       PP       : PHB index (starting at zero)
- *	 BB	  : PCI Bus number under given PHB
- *	 DD	  : PCI devfn under given bus
- *       yyyyyyyy : Virtual address offset
- * 
- * An actual virtual address is produced from this token
- * by masking into the form:
- *   0xE0000000yyyyyyyy
  */
 static inline u8 eeh_readb(void *addr) {
 	volatile u8 *vaddr = (volatile u8 *)IO_TOKEN_TO_ADDR(addr);
 	u8 val = in_8(vaddr);
-	if (EEH_POSSIBLE_ERROR(addr, vaddr, val))
+	if (EEH_POSSIBLE_ERROR(addr, vaddr, val, u8))
 		return eeh_check_failure(addr, val);
 	return val;
 }
@@ -109,10 +108,11 @@ static inline void eeh_writeb(u8 val, vo
 	volatile u8 *vaddr = (volatile u8 *)IO_TOKEN_TO_ADDR(addr);
 	out_8(vaddr, val);
 }
+
 static inline u16 eeh_readw(void *addr) {
 	volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
 	u16 val = in_le16(vaddr);
-	if (EEH_POSSIBLE_ERROR(addr, vaddr, val))
+	if (EEH_POSSIBLE_ERROR(addr, vaddr, val, u16))
 		return eeh_check_failure(addr, val);
 	return val;
 }
@@ -120,10 +120,22 @@ static inline void eeh_writew(u16 val, v
 	volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
 	out_le16(vaddr, val);
 }
+static inline u16 eeh_raw_readw(void *addr) {
+	volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
+	u16 val = in_be16(vaddr);
+	if (EEH_POSSIBLE_ERROR(addr, vaddr, val, u16))
+		return eeh_check_failure(addr, val);
+	return val;
+}
+static inline void eeh_raw_writew(u16 val, void *addr) {
+	volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
+	out_be16(vaddr, val);
+}
+
 static inline u32 eeh_readl(void *addr) {
 	volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
 	u32 val = in_le32(vaddr);
-	if (EEH_POSSIBLE_ERROR(addr, vaddr, val))
+	if (EEH_POSSIBLE_ERROR(addr, vaddr, val, u32))
 		return eeh_check_failure(addr, val);
 	return val;
 }
@@ -131,10 +143,22 @@ static inline void eeh_writel(u32 val, v
 	volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
 	out_le32(vaddr, val);
 }
+static inline u32 eeh_raw_readl(void *addr) {
+	volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
+	u32 val = in_be32(vaddr);
+	if (EEH_POSSIBLE_ERROR(addr, vaddr, val, u32))
+		return eeh_check_failure(addr, val);
+	return val;
+}
+static inline void eeh_raw_writel(u32 val, void *addr) {
+	volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
+	out_be32(vaddr, val);
+}
+
 static inline u64 eeh_readq(void *addr) {
 	volatile u64 *vaddr = (volatile u64 *)IO_TOKEN_TO_ADDR(addr);
 	u64 val = in_le64(vaddr);
-	if (EEH_POSSIBLE_ERROR(addr, vaddr, val))
+	if (EEH_POSSIBLE_ERROR(addr, vaddr, val, u64))
 		return eeh_check_failure(addr, val);
 	return val;
 }
@@ -142,6 +166,17 @@ static inline void eeh_writeq(u64 val, v
 	volatile u64 *vaddr = (volatile u64 *)IO_TOKEN_TO_ADDR(addr);
 	out_le64(vaddr, val);
 }
+static inline u64 eeh_raw_readq(void *addr) {
+	volatile u64 *vaddr = (volatile u64 *)IO_TOKEN_TO_ADDR(addr);
+	u64 val = in_be64(vaddr);
+	if (EEH_POSSIBLE_ERROR(addr, vaddr, val, u64))
+		return eeh_check_failure(addr, val);
+	return val;
+}
+static inline void eeh_raw_writeq(u64 val, void *addr) {
+	volatile u64 *vaddr = (volatile u64 *)IO_TOKEN_TO_ADDR(addr);
+	out_be64(vaddr, val);
+}
 
 static inline void eeh_memset_io(void *addr, int c, unsigned long n) {
 	void *vaddr = (void *)IO_TOKEN_TO_ADDR(addr);
@@ -150,8 +185,15 @@ static inline void eeh_memset_io(void *a
 static inline void eeh_memcpy_fromio(void *dest, void *src, unsigned long n) {
 	void *vsrc = (void *)IO_TOKEN_TO_ADDR(src);
 	memcpy(dest, vsrc, n);
-	/* look for ffff's here at dest[n] */
+	/* Look for ffff's here at dest[n].  Assume that at least 4 bytes
+	 * were copied. Check all four bytes.
+	 */
+	if ((n >= 4) &&
+		(EEH_POSSIBLE_ERROR(src, vsrc, (*((u32 *) dest+n-4)), u32))) {
+		eeh_check_failure(src, (*((u32 *) dest+n-4)));
+	}
 }
+
 static inline void eeh_memcpy_toio(void *dest, void *src, unsigned long n) {
 	void *vdest = (void *)IO_TOKEN_TO_ADDR(dest);
 	memcpy(vdest, src, n);
@@ -169,8 +211,8 @@ static inline u8 eeh_inb(unsigned long p
 	if (_IO_IS_ISA(port) && !_IO_HAS_ISA_BUS)
 		return ~0;
 	val = in_8((u8 *)(port+pci_io_base));
-	if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val))
-		return eeh_check_failure((void*)(port+pci_io_base), val);
+	if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val, u8))
+		return eeh_check_failure((void*)(port), val);
 	return val;
 }
 
@@ -184,8 +226,8 @@ static inline u16 eeh_inw(unsigned long 
 	if (_IO_IS_ISA(port) && !_IO_HAS_ISA_BUS)
 		return ~0;
 	val = in_le16((u16 *)(port+pci_io_base));
-	if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val))
-		return eeh_check_failure((void*)(port+pci_io_base), val);
+	if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val, u16))
+		return eeh_check_failure((void*)(port), val);
 	return val;
 }
 
@@ -199,8 +241,8 @@ static inline u32 eeh_inl(unsigned long 
 	if (_IO_IS_ISA(port) && !_IO_HAS_ISA_BUS)
 		return ~0;
 	val = in_le32((u32 *)(port+pci_io_base));
-	if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val))
-		return eeh_check_failure((void*)(port+pci_io_base), val);
+	if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val, u32))
+		return eeh_check_failure((void*)(port), val);
 	return val;
 }
 
@@ -209,4 +251,23 @@ static inline void eeh_outl(u32 val, uns
 		return out_le32((u32 *)(port+pci_io_base), val);
 }
 
-#endif /* _EEH_H */
+/* in-string eeh macros */
+static inline void eeh_insb(unsigned long port, void * buf, int ns) {
+	_insb((u8 *)(port+pci_io_base), buf, ns);
+	if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR((*(((u8*)buf)+ns-1)), u8))
+		eeh_check_failure((void*)(port), *(u8*)buf);
+}
+
+static inline void eeh_insw_ns(unsigned long port, void * buf, int ns) {
+	_insw_ns((u16 *)(port+pci_io_base), buf, ns);
+	if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR((*(((u16*)buf)+ns-1)), u16))
+		eeh_check_failure((void*)(port), *(u16*)buf);
+}
+
+static inline void eeh_insl_ns(unsigned long port, void * buf, int nl) {
+	_insl_ns((u32 *)(port+pci_io_base), buf, nl);
+	if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR((*(((u32*)buf)+nl-1)), u32))
+		eeh_check_failure((void*)(port), *(u32*)buf);
+}
+
+#endif /* _PPC64_EEH_H */
--- diff/include/asm-ppc64/hvcall.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-ppc64/hvcall.h	2004-03-16 09:37:57.805752360 +0000
@@ -4,6 +4,14 @@
 #define H_Success	0
 #define H_Busy		1	/* Hardware busy -- retry later */
 #define H_Constrained	4	/* Resource request constrained to max allowed */
+#define H_LongBusyStartRange   9900  /* Start of long busy range */
+#define H_LongBusyOrder1msec   9900  /* Long busy, hint that 1msec is a good time to retry */
+#define H_LongBusyOrder10msec  9901  /* Long busy, hint that 10msec is a good time to retry */
+#define H_LongBusyOrder100msec 9902  /* Long busy, hint that 100msec is a good time to retry */
+#define H_LongBusyOrder1sec    9903  /* Long busy, hint that 1sec is a good time to retry */
+#define H_LongBusyOrder10sec   9904  /* Long busy, hint that 10sec is a good time to retry */
+#define H_LongBusyOrder100sec  9905  /* Long busy, hint that 100sec is a good time to retry */
+#define H_LongBusyEndRange     9905  /* End of long busy range */
 #define H_Hardware	-1	/* Hardware error */
 #define H_Function	-2	/* Function not supported */
 #define H_Privilege	-3	/* Caller not privileged */
@@ -21,6 +29,16 @@
 #define H_RemoteParm           -15
 #define H_Resource             -16
 
+/* Long Busy is a condition that can be returned by the firmware
+ * when a call cannot be completed now, but the identical call
+ * should be retried later.  This prevents calls blocking in the
+ * firmware for long periods of time. Annoyingly the firmware can return
+ * a range of return codes, hinting at how long we should wait before
+ * retrying.  If you don't care for the hint, the macro below is a good
+ * way to check for the long_busy return codes
+ */
+#define H_isLongBusy(x)  ((x >= H_LongBusyStartRange) && (x <= H_LongBusyEndRange))
+
 /* Flags */
 #define H_LARGE_PAGE		(1UL<<(63-16))
 #define H_EXACT		    (1UL<<(63-24))	/* Use exact PTE or return H_PTEG_FULL */
@@ -76,7 +94,7 @@
 #define H_PROD		        0xE8
 #define H_GET_PPP		0xEC
 #define H_SET_PPP		0xF0
-#define H_SET_PURR		0xF4
+#define H_PURR			0xF4
 #define H_PIC		        0xF8
 #define H_REG_CRQ		0xFC
 #define H_FREE_CRQ		0x100
@@ -84,6 +102,9 @@
 #define H_SEND_CRQ		0x108
 #define H_COPY_RDMA             0x110
 #define H_POLL_PENDING	        0x1D8
+#define H_VTERM_PARTNER_INFO	0x150
+#define H_REGISTER_VTERM		0x154
+#define H_FREE_VTERM			0x158
 
 /* plpar_hcall() -- Generic call interface using above opcodes
  *
--- diff/include/asm-ppc64/iSeries/iSeries_proc.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ppc64/iSeries/iSeries_proc.h	2004-03-16 09:37:57.806752208 +0000
@@ -19,12 +19,6 @@
 #ifndef _ISERIES_PROC_H
 #define _ISERIES_PROC_H
 
-#include <linux/proc_fs.h>
-
 extern void iSeries_proc_early_init(void);
 
-typedef void (*iSeriesProcFunction)(struct proc_dir_entry *iSeries_proc);
-
-extern void iSeries_proc_callback(iSeriesProcFunction initFunction);
-
 #endif /* _iSeries_PROC_H */
--- diff/include/asm-ppc64/iSeries/mf.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ppc64/iSeries/mf.h	2004-03-16 09:37:57.806752208 +0000
@@ -67,6 +67,4 @@ extern int mf_getRtcTime(unsigned long *
 extern int mf_getRtc( struct rtc_time * tm );
 extern int mf_setRtc( struct rtc_time * tm );
 
-extern void mf_proc_init(struct proc_dir_entry *iSeries_proc);
-
 #endif /* MF_H_INCLUDED */
--- diff/include/asm-ppc64/io.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-ppc64/io.h	2004-03-16 09:37:57.807752056 +0000
@@ -58,6 +58,13 @@ extern unsigned long pci_io_base;
 #define outb(data,addr)		writeb(data,((unsigned long)(addr)))  
 #define outw(data,addr)		writew(data,((unsigned long)(addr)))  
 #define outl(data,addr)		writel(data,((unsigned long)(addr)))
+/*
+ * The *_ns versions below don't do byte-swapping.
+ * Neither do the standard versions now, these are just here
+ * for older code.
+ */
+#define insw_ns(port, buf, ns)	_insw_ns((u16 *)((port)+pci_io_base), (buf), (ns))
+#define insl_ns(port, buf, nl)	_insl_ns((u32 *)((port)+pci_io_base), (buf), (nl))
 #else
 #define __raw_readb(addr)       (*(volatile unsigned char *)(addr))
 #define __raw_readw(addr)       (*(volatile unsigned short *)(addr))
@@ -90,12 +97,16 @@ extern unsigned long pci_io_base;
  * They are only used in practice for transferring buffers which
  * are arrays of bytes, and byte-swapping is not appropriate in
  * that case.  - paulus */
-#define insb(port, buf, ns)	_insb((u8 *)((port)+pci_io_base), (buf), (ns))
-#define outsb(port, buf, ns)	_outsb((u8 *)((port)+pci_io_base), (buf), (ns))
-#define insw(port, buf, ns)	_insw_ns((u16 *)((port)+pci_io_base), (buf), (ns))
-#define outsw(port, buf, ns)	_outsw_ns((u16 *)((port)+pci_io_base), (buf), (ns))
-#define insl(port, buf, nl)	_insl_ns((u32 *)((port)+pci_io_base), (buf), (nl))
-#define outsl(port, buf, nl)	_outsl_ns((u32 *)((port)+pci_io_base), (buf), (nl))
+#define insb(port, buf, ns)	eeh_insb((port), (buf), (ns))
+#define insw(port, buf, ns)	eeh_insw_ns((port), (buf), (ns))
+#define insl(port, buf, nl)	eeh_insl_ns((port), (buf), (nl))
+#define insw_ns(port, buf, ns)	eeh_insw_ns((port), (buf), (ns))
+#define insl_ns(port, buf, nl)	eeh_insl_ns((port), (buf), (nl))
+
+#define outsb(port, buf, ns)  _outsb((u8 *)((port)+pci_io_base), (buf), (ns))
+#define outsw(port, buf, ns)  _outsw_ns((u16 *)((port)+pci_io_base), (buf), (ns))
+#define outsl(port, buf, nl)  _outsl_ns((u32 *)((port)+pci_io_base), (buf), (nl))
+
 #endif
 
 #define readb_relaxed(addr) readb(addr)
@@ -130,9 +141,7 @@ extern void _outsl_ns(volatile u32 *port
  * Neither do the standard versions now, these are just here
  * for older code.
  */
-#define insw_ns(port, buf, ns)	_insw_ns((u16 *)((port)+pci_io_base), (buf), (ns))
 #define outsw_ns(port, buf, ns)	_outsw_ns((u16 *)((port)+pci_io_base), (buf), (ns))
-#define insl_ns(port, buf, nl)	_insl_ns((u32 *)((port)+pci_io_base), (buf), (nl))
 #define outsl_ns(port, buf, nl)	_outsl_ns((u32 *)((port)+pci_io_base), (buf), (nl))
 
 
@@ -204,6 +213,9 @@ static inline void iosync(void)
 
 /*
  * 8, 16 and 32 bit, big and little endian I/O operations, with barrier.
+ * These routines do not perform EEH-related I/O address translation,
+ * and should not be used directly by device drivers.  Use inb/readb
+ * instead.
  */
 static inline int in_8(volatile unsigned char *addr)
 {
--- diff/include/asm-ppc64/irq.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-ppc64/irq.h	2004-03-16 09:37:57.807752056 +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/mmzone.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-ppc64/mmzone.h	2004-03-16 09:37:57.808751904 +0000
@@ -28,7 +28,8 @@ extern int nr_cpus_in_node[];
 #define MEMORY_INCREMENT_SHIFT 28
 #define MEMORY_INCREMENT (1UL << MEMORY_INCREMENT_SHIFT)
 
-#define DEBUG_NUMA
+/* NUMA debugging, will not work on a DLPAR machine */
+#undef DEBUG_NUMA
 
 static inline int pa_to_nid(unsigned long pa)
 {
--- diff/include/asm-ppc64/pci.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-ppc64/pci.h	2004-03-16 09:37:57.808751904 +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/pmc.h	2002-10-16 03:28:24.000000000 +0000
+++ source/include/asm-ppc64/pmc.h	2004-03-16 09:37:57.809751752 +0000
@@ -1,113 +0,0 @@
-/* 
- * pmc.h
- * Copyright (C) 2001  Dave Engebretsen & Mike Corrigan IBM Corporation.
- *
- * The PPC64 PMC subsystem encompases both the hardware PMC registers and 
- * a set of software event counters.  An interface is provided via the
- * proc filesystem which can be used to access this subsystem.
- *
- * 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
- */
-
-/* Start Change Log
- * 2001/06/05 : engebret : Created.
- * End Change Log 
- */
-
-#ifndef _PPC64_TYPES_H
-#include        <asm/types.h>
-#endif
-
-#ifndef _PMC_H
-#define _PMC_H
-
-#define STAB_ENTRY_MAX 64
-
-struct _pmc_hw
-{
-	u64 mmcr0; 
-	u64 mmcr1; 
-	u64 mmcra; 
-
-	u64 pmc1; 
-	u64 pmc2; 
-	u64 pmc3; 
-	u64 pmc4; 
-	u64 pmc5; 
-	u64 pmc6; 
-	u64 pmc7; 
-	u64 pmc8; 
-};
-
-struct _pmc_sw
-{
-	u64 stab_faults;           /* Count of faults on the stab      */
-	u64 stab_capacity_castouts;/* Count of castouts from the stab  */
-	u64 stab_invalidations;	   /* Count of invalidations from the  */
-                                   /*   stab, not including castouts   */
-	u64 stab_entry_use[STAB_ENTRY_MAX]; 
-
-	u64 htab_primary_overflows;
-	u64 htab_capacity_castouts;
-	u64 htab_read_to_write_fault;
-};
-
-#define PMC_HW_TEXT_ENTRY_COUNT (sizeof(struct _pmc_hw) / sizeof(u64))
-#define PMC_SW_TEXT_ENTRY_COUNT (sizeof(struct _pmc_sw) / sizeof(u64))
-#define PMC_TEXT_ENTRY_SIZE  64
-
-struct _pmc_sw_text {
-	char buffer[PMC_SW_TEXT_ENTRY_COUNT * PMC_TEXT_ENTRY_SIZE];
-};
-
-struct _pmc_hw_text {
-	char buffer[PMC_HW_TEXT_ENTRY_COUNT * PMC_TEXT_ENTRY_SIZE];
-};
-
-extern struct _pmc_sw pmc_sw_system;
-extern struct _pmc_sw pmc_sw_cpu[];
-
-extern struct _pmc_sw_text pmc_sw_text;
-extern struct _pmc_hw_text pmc_hw_text;
-extern char *ppc64_pmc_stab(int file);
-extern char *ppc64_pmc_htab(int file);
-extern char *ppc64_pmc_hw(int file);
-
-#if 1
-#define PMC_SW_PROCESSOR(F)      pmc_sw_cpu[smp_processor_id()].F++
-#define PMC_SW_PROCESSOR_A(F, E) (pmc_sw_cpu[smp_processor_id()].F[(E)])++
-#define PMC_SW_SYSTEM(F)         pmc_sw_system.F++
-#else
-#define PMC_SW_PROCESSOR(F)   do {;} while (0)
-#define PMC_SW_PROCESSOR_A(F) do {;} while (0)
-#define PMC_SW_SYSTEM(F)      do {;} while (0)
-#endif
-
-#define MMCR0 795
-#define MMCR1 798
-#define MMCRA 786
-#define PMC1  787
-#define PMC2  788
-#define PMC3  789
-#define PMC4  790
-#define PMC5  791
-#define PMC6  792
-#define PMC7  793
-#define PMC8  794
-
-#define PMC_CONTROL_CPI 1
-#define PMC_CONTROL_TLB 2
-
-#endif /* _PMC_H */
--- diff/include/asm-ppc64/ppc32.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ppc64/ppc32.h	2004-03-16 09:37:57.809751752 +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-ppc64/proc_fs.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ppc64/proc_fs.h	2004-03-16 09:37:57.810751600 +0000
@@ -1,39 +0,0 @@
-#ifndef _PPC64_PROC_FS_H
-#define _PPC64_PROC_FS_H
-/*
- * proc_fs.h
- * Copyright (C) 2001  Mike Corrigan  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) 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
- */
-
-/* Change Activity: */
-/* tgall -- merge of iSeries/iSeries_proc.h and proc_pmc.h */
-/* End Change Activity */
-
-#include <linux/proc_fs.h>
-
-struct proc_ppc64_t {
-	struct proc_dir_entry *root;
-	struct proc_dir_entry *naca;
-	struct proc_dir_entry *paca;
-	struct proc_dir_entry *systemcfg;
-	struct proc_dir_entry *rtas;
-};
-
-extern struct proc_ppc64_t proc_ppc64;
-extern int proc_ppc64_init(void);
-
-#endif /* _PPC64_PROC_FS_H */
--- diff/include/asm-ppc64/proc_pmc.h	2002-10-16 03:28:30.000000000 +0000
+++ source/include/asm-ppc64/proc_pmc.h	2004-03-16 09:37:57.810751600 +0000
@@ -1,33 +0,0 @@
-/*
- * pmc_proc.h
- * Copyright (C) 2001  Mike Corrigan  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) 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
- */
-
-
-/* Change Activity: */
-/* End Change Activity */
-
-#ifndef _PMC_PROC_H
-#define _PMC_PROC_H
-
-#include <linux/proc_fs.h>
-
-void pmc_proc_init(struct proc_dir_entry *iSeries_proc);
-void proc_ppc64_init(void);
-
-#endif /* _PMC_PROC_H */
-
--- diff/include/asm-ppc64/processor.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-ppc64/processor.h	2004-03-16 09:37:57.811751448 +0000
@@ -618,6 +618,11 @@ static inline void prefetchw(const void 
 
 #define spin_lock_prefetch(x)	prefetchw(x)
 
+#ifdef CONFIG_SCHED_SMT
+#define ARCH_HAS_SCHED_DOMAIN
+#define ARCH_HAS_SCHED_WAKE_BALANCE
+#endif
+
 #endif /* ASSEMBLY */
 
 #endif /* __ASM_PPC64_PROCESSOR_H */
--- diff/include/asm-ppc64/rtas.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ppc64/rtas.h	2004-03-16 09:37:57.811751448 +0000
@@ -177,6 +177,7 @@ extern void rtas_power_off(void);
 extern void rtas_halt(void);
 extern int rtas_get_sensor(int sensor, int index, int *state);
 extern int rtas_get_power_level(int powerdomain, int *level);
+extern int rtas_set_power_level(int powerdomain, int level, int *setlevel);
 extern int rtas_set_indicator(int indicator, int index, int new_value);
 
 /* Given an RTAS status code of 9900..9905 compute the hinted delay */
--- diff/include/asm-ppc64/thread_info.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-ppc64/thread_info.h	2004-03-16 09:37:57.811751448 +0000
@@ -97,6 +97,7 @@ static inline struct thread_info *curren
 #define TIF_32BIT		5	/* 32 bit binary */
 #define TIF_RUN_LIGHT		6	/* iSeries run light */
 #define TIF_ABI_PENDING		7	/* 32/64 bit switch needed */
+#define TIF_SYSCALL_AUDIT	8	/* syscall auditing active */
 
 /* as above, but as bit values */
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
@@ -107,6 +108,8 @@ static inline struct thread_info *curren
 #define _TIF_32BIT		(1<<TIF_32BIT)
 #define _TIF_RUN_LIGHT		(1<<TIF_RUN_LIGHT)
 #define _TIF_ABI_PENDING	(1<<TIF_ABI_PENDING)
+#define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
+#define _TIF_SYSCALL_T_OR_A	(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
 
 #define _TIF_USER_WORK_MASK	(_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \
 				 _TIF_NEED_RESCHED)
--- diff/include/asm-ppc64/unistd.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-ppc64/unistd.h	2004-03-16 09:37:57.812751296 +0000
@@ -399,15 +399,19 @@ type name(type1 arg1, type2 arg2, type3 
 /*
  * System call prototypes.
  */
-extern pid_t setsid(void);
-extern int write(int fd, const char *buf, off_t count);
-extern int read(int fd, char *buf, off_t count);
-extern off_t lseek(int fd, off_t offset, int count);
-extern int dup(int fd);
-extern int execve(const char *file, char **argv, char **envp);
-extern int open(const char *file, int flag, int mode);
-extern int close(int fd);
-extern pid_t waitpid(pid_t pid, int *wait_stat, int options);
+static inline _syscall3(int, execve, __const__ char *, file, char **, argv,
+			char **,envp)
+static inline _syscall3(int, open, __const__ char *, file, int, flag, int, mode)
+static inline _syscall1(int, close, int, fd)
+static inline _syscall1(int, dup, int, fd)
+static inline _syscall3(int, read, int, fd, char *, buf , off_t, count)
+static inline _syscall3(int, write, int, fd, __const__ char *, buf, off_t,
+			count)
+static inline _syscall0(pid_t, setsid)
+static inline _syscall3(off_t, lseek, int, fd, off_t, offset, int, count)
+static inline _syscall3(pid_t, waitpid, pid_t, pid, int *, wait_stat, int,
+			options)
+
 #endif /* __KERNEL_SYSCALLS__ */
 
 asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
--- diff/include/asm-ppc64/vio.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-ppc64/vio.h	2004-03-16 09:37:57.812751296 +0000
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/device.h>
+#include <linux/pci.h>
 #include <asm/hvcall.h>
 #include <asm/prom.h>
 #include <asm/scatterlist.h>
@@ -44,8 +45,11 @@ int vio_register_driver(struct vio_drive
 void vio_unregister_driver(struct vio_driver *drv);
 const struct vio_device_id * vio_match_device(const struct vio_device_id *ids, 
 						const struct vio_dev *dev);
+
 struct vio_dev * __devinit vio_register_device(struct device_node *node_vdev);
 void __devinit vio_unregister_device(struct vio_dev *dev);
+struct vio_dev *vio_find_node(struct device_node *vnode);
+
 const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length);
 int vio_get_irq(struct vio_dev *dev);
 struct iommu_table * vio_build_iommu_table(struct vio_dev *dev);
@@ -65,6 +69,33 @@ void *vio_alloc_consistent(struct vio_de
 void vio_free_consistent(struct vio_dev *dev, size_t size, void *vaddr, 
 			 dma_addr_t dma_handle);
 
+static inline int vio_dma_supported(struct vio_dev *hwdev, u64 mask)
+{
+	return 1;
+}
+
+#define vio_map_page(dev, page, off, size, dir) \
+		vio_map_single(dev, (page_address(page) + (off)), size, dir)
+#define vio_unmap_page(dev,addr,sz,dir) vio_unmap_single(dev,addr,sz,dir)
+
+
+static inline void vio_dma_sync_single(struct vio_dev *hwdev,
+				       dma_addr_t dma_handle,
+				       size_t size, int direction)
+{
+	BUG_ON(direction == PCI_DMA_NONE);
+	/* nothing to do */
+}
+
+static inline void vio_dma_sync_sg(struct vio_dev *hwdev,
+				   struct scatterlist *sg,
+				   int nelems, int direction)
+{
+	BUG_ON(direction == PCI_DMA_NONE);
+	/* nothing to do */
+}
+static inline int vio_set_dma_mask(struct vio_dev *dev, u64 mask) { return -EIO; }
+
 extern struct bus_type vio_bus_type;
 
 struct vio_device_id {
--- diff/include/asm-s390/compat.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-s390/compat.h	2004-03-16 09:37:57.813751144 +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 13:16:14.000000000 +0000
+++ source/include/asm-s390/irq.h	2004-03-16 09:37:57.813751144 +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/mman.h	2003-09-30 14:46:20.000000000 +0000
+++ source/include/asm-s390/mman.h	2004-03-16 09:37:57.814750992 +0000
@@ -30,6 +30,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-s390/pgtable.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-s390/pgtable.h	2004-03-16 09:37:57.815750840 +0000
@@ -209,16 +209,41 @@ extern char empty_zero_page[PAGE_SIZE];
  * C  : changed bit
  */
 
-/* Hardware bits in the page table entry */
+/* Hardware bits in the page table entry. */
 #define _PAGE_RO        0x200          /* HW read-only                     */
 #define _PAGE_INVALID   0x400          /* HW invalid                       */
 
-/* Mask and four different kinds of invalid pages. */
-#define _PAGE_INVALID_MASK	0x601
+/* Software bits in the page table entry. */
+#define _PAGE_FILE	0x001
+#define _PAGE_PROTNONE	0x002
+
+/*
+ * We have 8 different page "types", two valid types and 6 invalid types
+ * (p = page address, o = swap offset, t = swap type, f = file offset):
+ *                     0 xxxxxxxxxxxxxxxxxxx 0IP0 yyyyyy NF
+ * valid rw:           0 <--------p--------> 0000 <--0-> 00
+ * valid ro:           0 <--------p--------> 0010 <--0-> 00
+ * invalid none:       0 <--------p--------> 0100 <--0-> 10
+ * invalid empty:      0 <--------0--------> 0100 <--0-> 00
+ * invalid swap:       0 <--------o--------> 0110 <--t-> 00
+ * invalid file rw:    0 <--------f--------> 0100 <--f-> 01
+ * invalid file ro:    0 <--------f--------> 0110 <--f-> 01
+ * invaild file none:  0 <--------f--------> 0100 <--f-> 11
+ *
+ * The format for 64 bit is almost identical, there isn't a leading zero
+ * and the number of bits in the page address part of the pte is 52 bits
+ * instead of 19.
+ */
+
 #define _PAGE_INVALID_EMPTY	0x400
-#define _PAGE_INVALID_NONE	0x401
 #define _PAGE_INVALID_SWAP	0x600
-#define _PAGE_INVALID_FILE	0x601
+#define _PAGE_INVALID_FILE	0x401
+
+#define _PTE_IS_VALID(__pte)	(!(pte_val(__pte) & _PAGE_INVALID))
+#define _PTE_IS_NONE(__pte)	((pte_val(__pte) & 0x603) == 0x402)
+#define _PTE_IS_EMPTY(__pte)	((pte_val(__pte) & 0x603) == 0x400)
+#define _PTE_IS_SWAP(__pte)	((pte_val(__pte) & 0x603) == 0x600)
+#define _PTE_IS_FILE(__pte)	((pte_val(__pte) & 0x401) == 0x401)
 
 #ifndef __s390x__
 
@@ -279,13 +304,11 @@ extern char empty_zero_page[PAGE_SIZE];
 /*
  * No mapping available
  */
-#define PAGE_NONE_SHARED  __pgprot(_PAGE_INVALID_NONE)
-#define PAGE_NONE_PRIVATE __pgprot(_PAGE_INVALID_NONE)
-#define PAGE_RO_SHARED	  __pgprot(_PAGE_RO)
-#define PAGE_RO_PRIVATE	  __pgprot(_PAGE_RO)
-#define PAGE_COPY	  __pgprot(_PAGE_RO)
-#define PAGE_SHARED	  __pgprot(0)
-#define PAGE_KERNEL	  __pgprot(0)
+#define PAGE_NONE	__pgprot(_PAGE_INVALID | _PAGE_PROTNONE)
+#define PAGE_READONLY	__pgprot(_PAGE_RO)
+#define PAGE_COPY	__pgprot(_PAGE_RO)
+#define PAGE_SHARED	__pgprot(0)
+#define PAGE_KERNEL	__pgprot(0)
 
 /*
  * The S390 can't do page protection for execute, and considers that the
@@ -293,21 +316,21 @@ extern char empty_zero_page[PAGE_SIZE];
  * the closest we can get..
  */
          /*xwr*/
-#define __P000  PAGE_NONE_PRIVATE
-#define __P001  PAGE_RO_PRIVATE
+#define __P000  PAGE_NONE
+#define __P001  PAGE_READONLY
 #define __P010  PAGE_COPY
 #define __P011  PAGE_COPY
-#define __P100  PAGE_RO_PRIVATE
-#define __P101  PAGE_RO_PRIVATE
+#define __P100  PAGE_READONLY
+#define __P101  PAGE_READONLY
 #define __P110  PAGE_COPY
 #define __P111  PAGE_COPY
 
-#define __S000  PAGE_NONE_SHARED
-#define __S001  PAGE_RO_SHARED
+#define __S000  PAGE_NONE
+#define __S001  PAGE_READONLY
 #define __S010  PAGE_SHARED
 #define __S011  PAGE_SHARED
-#define __S100  PAGE_RO_SHARED
-#define __S101  PAGE_RO_SHARED
+#define __S100  PAGE_READONLY
+#define __S101  PAGE_READONLY
 #define __S110  PAGE_SHARED
 #define __S111  PAGE_SHARED
 
@@ -373,18 +396,17 @@ extern inline int pmd_bad(pmd_t pmd)
 
 extern inline int pte_none(pte_t pte)
 {
-	return (pte_val(pte) & _PAGE_INVALID_MASK) == _PAGE_INVALID_EMPTY;
+	return _PTE_IS_EMPTY(pte);
 }
 
 extern inline int pte_present(pte_t pte)
 {
-	return !(pte_val(pte) & _PAGE_INVALID) ||
-		(pte_val(pte) & _PAGE_INVALID_MASK) == _PAGE_INVALID_NONE;
+	return _PTE_IS_VALID(pte) || _PTE_IS_NONE(pte);
 }
 
 extern inline int pte_file(pte_t pte)
 {
-	return (pte_val(pte) & _PAGE_INVALID_MASK) == _PAGE_INVALID_FILE;
+	return _PTE_IS_FILE(pte);
 }
 
 #define pte_same(a,b)	(pte_val(a) == pte_val(b))
@@ -465,8 +487,8 @@ extern inline pte_t pte_modify(pte_t pte
 
 extern inline pte_t pte_wrprotect(pte_t pte)
 {
-	/* Do not clobber _PAGE_INVALID_NONE pages!  */
-	if (!(pte_val(pte) & _PAGE_INVALID))
+	/* Do not clobber PROT_NONE pages!  */
+	if (!_PTE_IS_NONE(pte))
 		pte_val(pte) |= _PAGE_RO;
 	return pte;
 }
@@ -719,14 +741,14 @@ extern inline pmd_t * pmd_offset(pgd_t *
  * information in the lowcore.
  * Bit 21 and bit 22 are the page invalid bit and the page protection
  * bit. We set both to indicate a swapped page.
- * Bit 31 is used as the software page present bit. If a page is
- * swapped this obviously has to be zero.
- * This leaves the bits 1-19 and bits 24-30 to store type and offset.
- * We use the 7 bits from 24-30 for the type and the 19 bits from 1-19
+ * Bit 30 and 31 are used to distinguish the different page types. For
+ * a swapped page these bits need to be zero.
+ * This leaves the bits 1-19 and bits 24-29 to store type and offset.
+ * We use the 6 bits from 24-29 for the type and the 19 bits from 1-19
  * for the offset.
- * 0|     offset      |0110|type |0
- * 00000000001111111111222222222233
- * 01234567890123456789012345678901
+ * 0|     offset        |0110| type |00|
+ * 0 0000000001111111111 2222 222222 33
+ * 0 1234567890123456789 0123 456789 01
  *
  * 64 bit swap entry format:
  * A page-table entry has some bits we have to treat in a special way.
@@ -736,19 +758,19 @@ extern inline pmd_t * pmd_offset(pgd_t *
  * information in the lowcore.
  * Bit 53 and bit 54 are the page invalid bit and the page protection
  * bit. We set both to indicate a swapped page.
- * Bit 63 is used as the software page present bit. If a page is
- * swapped this obviously has to be zero.
- * This leaves the bits 0-51 and bits 56-62 to store type and offset.
- * We use the 7 bits from 56-62 for the type and the 52 bits from 0-51
+ * Bit 62 and 63 are used to distinguish the different page types. For
+ * a swapped page these bits need to be zero.
+ * This leaves the bits 0-51 and bits 56-61 to store type and offset.
+ * We use the 6 bits from 56-61 for the type and the 52 bits from 0-51
  * for the offset.
- * |                     offset                       |0110|type |0
- * 0000000000111111111122222222223333333333444444444455555555556666
- * 0123456789012345678901234567890123456789012345678901234567890123
+ * |                      offset                        |0110| type |00|
+ *  0000000000111111111122222222223333333333444444444455 5555 555566 66
+ *  0123456789012345678901234567890123456789012345678901 2345 678901 23
  */
 extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
 {
 	pte_t pte;
-	pte_val(pte) = (type << 1) | (offset << 12) | _PAGE_INVALID_SWAP;
+	pte_val(pte) = (type << 2) | (offset << 12) | _PAGE_INVALID_SWAP;
 #ifndef __s390x__
 	BUG_ON((pte_val(pte) & 0x80000901) != 0);
 #else /* __s390x__ */
@@ -757,7 +779,7 @@ extern inline pte_t mk_swap_pte(unsigned
 	return pte;
 }
 
-#define __swp_type(entry)	(((entry).val >> 1) & 0x3f)
+#define __swp_type(entry)	(((entry).val >> 2) & 0x3f)
 #define __swp_offset(entry)	((entry).val >> 12)
 #define __swp_entry(type,offset) ((swp_entry_t) { pte_val(mk_swap_pte((type),(offset))) })
 
@@ -767,17 +789,21 @@ extern inline pte_t mk_swap_pte(unsigned
 typedef pte_t *pte_addr_t;
 
 #ifndef __s390x__
-# define PTE_FILE_MAX_BITS	26
+# define PTE_FILE_MAX_BITS	25
 #else /* __s390x__ */
-# define PTE_FILE_MAX_BITS	59
+# define PTE_FILE_MAX_BITS	58
 #endif /* __s390x__ */
 
 #define pte_to_pgoff(__pte) \
-	((((__pte).pte >> 12) << 7) + (((__pte).pte >> 1) & 0x7f))
+	((((__pte).pte >> 12) << 6) + (((__pte).pte >> 2) & 0x3f))
+
+#define pte_to_pgprot(pte) \
+	__pgprot(pte_val(pte) & (_PAGE_RO | _PAGE_PROTNONE))
 
-#define pgoff_to_pte(__off) \
-	((pte_t) { ((((__off) & 0x7f) << 1) + (((__off) >> 7) << 12)) \
-		   | _PAGE_INVALID_FILE })
+#define pgoff_prot_to_pte(__off, __prot) \
+	((pte_t) { _PAGE_INVALID_FILE | \
+		((((__off) & 0x3f) << 2) + (((__off) >> 6) << 12)) | \
+		(pgprot_val(__prot) & (_PAGE_RO | _PAGE_PROTNONE)) })
 
 #endif /* !__ASSEMBLY__ */
 
--- diff/include/asm-s390/unistd.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-s390/unistd.h	2004-03-16 09:37:57.816750688 +0000
@@ -260,8 +260,9 @@
  * Number 263 is reserved for vserver
  */
 #define __NR_fadvise64_64	264
+#define __NR_remap_file_pages	265
 
-#define NR_syscalls 265
+#define NR_syscalls 266
 
 /* 
  * There are some system calls that are not present on 64 bit, some
@@ -553,7 +554,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-16 09:37:57.817750536 +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-16 09:37:57.818750384 +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-16 09:37:57.818750384 +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-16 09:37:57.819750232 +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 10:50:16.000000000 +0000
+++ source/include/asm-sparc/sbus.h	2004-03-16 09:37:57.819750232 +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/thread_info.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-sparc/thread_info.h	2004-03-16 09:37:57.820750080 +0000
@@ -100,9 +100,6 @@ BTFIXUPDEF_CALL(void, free_thread_info, 
  * Size of kernel stack for each process.
  * Observe the order of get_free_pages() in alloc_thread_info().
  * The sun4 has 8K stack too, because it's short on memory, and 16K is a waste.
- *
- * XXX Watch how INIT_THREAD_SIZE evolves in linux/sched.h and elsewhere.
- *     On 2.5.24 it happens to match 8192 magically.
  */
 #define THREAD_SIZE		8192
 
--- diff/include/asm-sparc64/compat.h	2003-07-08 08:55:19.000000000 +0000
+++ source/include/asm-sparc64/compat.h	2004-03-16 09:37:57.820750080 +0000
@@ -29,6 +29,7 @@ typedef s32		compat_int_t;
 typedef s32		compat_long_t;
 typedef u32		compat_uint_t;
 typedef u32		compat_ulong_t;
+typedef u32		compat_timer_t;
 
 struct compat_timespec {
 	compat_time_t	tv_sec;
--- diff/include/asm-sparc64/irq.h	2003-08-26 09:00:54.000000000 +0000
+++ source/include/asm-sparc64/irq.h	2004-03-16 09:37:57.821749928 +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-16 09:37:57.822749776 +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/pgtable.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/asm-sparc64/pgtable.h	2004-03-16 09:37:57.822749776 +0000
@@ -322,9 +322,16 @@ static inline pte_t mk_pte_io(unsigned l
 
 /* File offset in PTE support. */
 #define pte_file(pte)		(pte_val(pte) & _PAGE_FILE)
-#define pte_to_pgoff(pte)	(pte_val(pte) >> PAGE_SHIFT)
-#define pgoff_to_pte(off)	(__pte(((off) << PAGE_SHIFT) | _PAGE_FILE))
-#define PTE_FILE_MAX_BITS	(64UL - PAGE_SHIFT - 1UL)
+#define __pte_to_pgprot(pte) \
+		__pgprot(pte_val(pte) & (_PAGE_READ|_PAGE_WRITE))
+#define __file_pte_to_pgprot(pte) \
+		__pgprot(((pte_val(pte) >> PAGE_SHIFT) & 0x3UL) << 8)
+#define pte_to_pgprot(pte) \
+	(pte_file(pte) ? __file_pte_to_pgprot(pte) : __pte_to_pgprot(pte))
+#define pte_to_pgoff(pte)	(pte_val(pte) >> (PAGE_SHIFT+2))
+#define pgoff_prot_to_pte(off, prot) \
+	((__pte(((off) | ((pgprot_val(prot) >> 8) & 0x3UL)))) << (PAGE_SHIFT+2) | _PAGE_FILE)
+#define PTE_FILE_MAX_BITS	(64UL - PAGE_SHIFT - 3UL)
 
 extern unsigned long prom_virt_to_phys(unsigned long, int *);
 
--- diff/include/asm-sparc64/sbus.h	2002-10-16 03:27:19.000000000 +0000
+++ source/include/asm-sparc64/sbus.h	2004-03-16 09:37:57.823749624 +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/spinlock.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-sparc64/spinlock.h	2004-03-16 09:37:57.823749624 +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-11 10:20:28.000000000 +0000
+++ source/include/asm-sparc64/unistd.h	2004-03-16 09:37:57.824749472 +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 08:47:17.000000000 +0000
+++ source/include/asm-um/irq.h	2004-03-16 09:37:57.824749472 +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/processor-generic.h	2003-10-09 08:47:17.000000000 +0000
+++ source/include/asm-um/processor-generic.h	2004-03-16 09:37:57.824749472 +0000
@@ -94,8 +94,6 @@ struct thread_struct {
 	.request		= { 0 } \
 }
 
-#define INIT_THREAD_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE)
-
 typedef struct {
 	unsigned long seg;
 } mm_segment_t;
--- diff/include/asm-v850/irq.h	2003-05-21 10:50:16.000000000 +0000
+++ source/include/asm-v850/irq.h	2004-03-16 09:37:57.825749320 +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-16 09:37:57.825749320 +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-03-11 10:20:28.000000000 +0000
+++ source/include/asm-x86_64/acpi.h	2004-03-16 09:37:57.826749168 +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;
 }
--- diff/include/asm-x86_64/bitops.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/asm-x86_64/bitops.h	2004-03-16 09:37:57.826749168 +0000
@@ -503,6 +503,8 @@ static __inline__ int ffs(int x)
 /* find last set bit */
 #define fls(x) generic_fls(x)
 
+#define ARCH_HAS_ATOMIC_UNSIGNED 1
+
 #endif /* __KERNEL__ */
 
 #endif /* _X86_64_BITOPS_H */
--- diff/include/asm-x86_64/calling.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-x86_64/calling.h	2004-03-16 09:37:57.827749016 +0000
@@ -31,7 +31,7 @@
 #define ARGOFFSET R11
 #define SWFRAME ORIG_RAX
 
-	.macro SAVE_ARGS addskip=0,norcx=0 	
+	.macro SAVE_ARGS addskip=0,norcx=0,nor891011=0
 	subq  $9*8+\addskip,%rsp
 	CFI_ADJUST_CFA_OFFSET	9*8+\addskip
 	movq  %rdi,8*8(%rsp) 
@@ -47,6 +47,8 @@
 	.endif
 	movq  %rax,4*8(%rsp) 
 	CFI_OFFSET	rax,4*8-(9*8+\addskip)
+	.if \nor891011
+	.else
 	movq  %r8,3*8(%rsp) 
 	CFI_OFFSET	r8,3*8-(9*8+\addskip)
 	movq  %r9,2*8(%rsp) 
@@ -55,17 +57,21 @@
 	CFI_OFFSET	r10,1*8-(9*8+\addskip)
 	movq  %r11,(%rsp) 
 	CFI_OFFSET	r11,-(9*8+\addskip)
+	.endif
 	.endm
 
 #define ARG_SKIP 9*8
-	.macro RESTORE_ARGS skiprax=0,addskip=0,skiprcx=0,skipr11=0
+	.macro RESTORE_ARGS skiprax=0,addskip=0,skiprcx=0,skipr11=0,skipr8910=0,skiprdx=0
 	.if \skipr11
 	.else
 	movq (%rsp),%r11
 	.endif
+	.if \skipr8910
+	.else
 	movq 1*8(%rsp),%r10
 	movq 2*8(%rsp),%r9
 	movq 3*8(%rsp),%r8
+	.endif
 	.if \skiprax
 	.else
 	movq 4*8(%rsp),%rax
@@ -74,7 +80,10 @@
 	.else
 	movq 5*8(%rsp),%rcx
 	.endif
+	.if \skiprdx
+	.else
 	movq 6*8(%rsp),%rdx
+	.endif
 	movq 7*8(%rsp),%rsi
 	movq 8*8(%rsp),%rdi
 	.if ARG_SKIP+\addskip > 0
--- diff/include/asm-x86_64/compat.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-x86_64/compat.h	2004-03-16 09:37:57.827749016 +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 11:28:12.000000000 +0000
+++ source/include/asm-x86_64/ia32_unistd.h	2004-03-16 09:37:57.828748864 +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-16 09:37:57.828748864 +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-16 09:37:57.829748712 +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 14:46:20.000000000 +0000
+++ source/include/asm-x86_64/mman.h	2004-03-16 09:37:57.829748712 +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/msr.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-x86_64/msr.h	2004-03-16 09:37:57.829748712 +0000
@@ -156,6 +156,10 @@ extern inline unsigned int cpuid_edx(uns
 #define MSR_MTRRcap		0x0fe
 #define MSR_IA32_BBL_CR_CTL        0x119
 
+#define MSR_IA32_SYSENTER_CS	0x174
+#define MSR_IA32_SYSENTER_ESP	0x175
+#define MSR_IA32_SYSENTER_EIP	0x176
+
 #define MSR_IA32_MCG_CAP       0x179
 #define MSR_IA32_MCG_STATUS        0x17a
 #define MSR_IA32_MCG_CTL       0x17b
--- diff/include/asm-x86_64/page.h	2003-06-30 09:07:29.000000000 +0000
+++ source/include/asm-x86_64/page.h	2004-03-16 09:37:57.830748560 +0000
@@ -137,6 +137,13 @@ extern __inline__ int get_order(unsigned
 #define VM_STACK_DEFAULT_FLAGS \
 	(test_thread_flag(TIF_IA32) ? vm_stack_flags32 : vm_stack_flags) 
 	
+#define CONFIG_ARCH_GATE_AREA 1	
+
+#ifndef __ASSEMBLY__
+struct task_struct;
+struct vm_area_struct *get_gate_vma(struct task_struct *tsk);
+int in_gate_area(struct task_struct *task, unsigned long addr);
+#endif
 
 #endif /* __KERNEL__ */
 
--- diff/include/asm-x86_64/pci.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-x86_64/pci.h	2004-03-16 09:37:57.831748408 +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-11 10:20:28.000000000 +0000
+++ source/include/asm-x86_64/pgtable.h	2004-03-16 09:37:57.831748408 +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/processor.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-x86_64/processor.h	2004-03-16 09:37:57.832748256 +0000
@@ -173,7 +173,7 @@ static inline void clear_in_cr4 (unsigne
  * space during mmap's.
  */
 #define IA32_PAGE_OFFSET ((current->personality & ADDR_LIMIT_3GB) ? 0xc0000000 : 0xFFFFe000)
-#define TASK_UNMAPPED_32 (PAGE_ALIGN(0xc5000000))
+#define TASK_UNMAPPED_32 PAGE_ALIGN(IA32_PAGE_OFFSET/3)
 #define TASK_UNMAPPED_64 PAGE_ALIGN(TASK_SIZE/3) 
 #define TASK_UNMAPPED_BASE	\
 	(test_thread_flag(TIF_IA32) ? TASK_UNMAPPED_32 : TASK_UNMAPPED_64)  
@@ -262,7 +262,9 @@ struct thread_struct {
 #define STACKFAULT_STACK 1
 #define DOUBLEFAULT_STACK 2 
 #define NMI_STACK 3 
-#define N_EXCEPTION_STACKS 3  /* hw limit: 7 */
+#define DEBUG_STACK 4 
+#define MCE_STACK 5
+#define N_EXCEPTION_STACKS 5  /* hw limit: 7 */
 #define EXCEPTION_STKSZ (PAGE_SIZE << EXCEPTION_STACK_ORDER)
 #define EXCEPTION_STACK_ORDER 0 
 
@@ -451,4 +453,6 @@ static inline void __mwait(unsigned long
 	ti->task;					\
 })
 
+#define cache_line_size() (boot_cpu_data.x86_clflush_size)
+
 #endif /* __ASM_X86_64_PROCESSOR_H */
--- diff/include/asm-x86_64/proto.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-x86_64/proto.h	2004-03-16 09:37:57.832748256 +0000
@@ -21,6 +21,7 @@ extern void syscall_init(void);
 
 extern void ia32_syscall(void);
 extern void ia32_cstar_target(void); 
+extern void ia32_sysenter_target(void); 
 
 extern void calibrate_delay(void);
 extern void cpu_idle(void);
@@ -37,6 +38,8 @@ extern int numa_setup(char *opt);
 extern int setup_early_printk(char *); 
 extern void early_printk(const char *fmt, ...) __attribute__((format(printf,1,2)));
 
+extern void early_identify_cpu(struct cpuinfo_x86 *c);
+
 extern int k8_scan_nodes(unsigned long start, unsigned long end);
 
 extern int numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn);
@@ -68,6 +71,7 @@ extern void show_regs(struct pt_regs * r
 
 extern int map_syscall32(struct mm_struct *mm, unsigned long address);
 extern char *syscall32_page;
+extern void syscall32_cpu_init(void);
 
 extern void setup_node_bootmem(int nodeid, unsigned long start, unsigned long end);
 
--- diff/include/asm-x86_64/smp.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-x86_64/smp.h	2004-03-16 09:37:57.832748256 +0000
@@ -47,7 +47,7 @@ extern void smp_invalidate_rcv(void);		/
 extern void (*mtrr_hook) (void);
 extern void zap_low_mappings(void);
 void smp_stop_cpu(void);
-extern int cpu_sibling_map[];
+extern char cpu_sibling_map[];
 
 #define SMP_TRAMPOLINE_BASE 0x6000
 
@@ -74,7 +74,15 @@ extern __inline int hard_smp_processor_i
 	return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID));
 }
 
-#define safe_smp_processor_id() (disable_apic ? 0 : hard_smp_processor_id())
+/*
+ * Some lowlevel functions might want to know about
+ * the real APIC ID <-> CPU # mapping.
+ * AK: why is this volatile?
+ */
+extern volatile char x86_apicid_to_cpu[NR_CPUS];
+extern volatile char x86_cpu_to_apicid[NR_CPUS];
+
+#define safe_smp_processor_id() (disable_apic ? 0 : x86_apicid_to_cpu[hard_smp_processor_id()])
 
 #define cpu_online(cpu) cpu_isset(cpu, cpu_online_map)
 #endif /* !ASSEMBLY */
--- diff/include/asm-x86_64/system.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-x86_64/system.h	2004-03-16 09:37:57.833748104 +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/thread_info.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-x86_64/thread_info.h	2004-03-16 09:37:57.834747952 +0000
@@ -82,7 +82,6 @@ static inline struct thread_info *stack_
 #else /* !__ASSEMBLY__ */
 
 /* how to get the thread information struct from ASM */
-/* only works on the process stack. otherwise get it via the PDA. */
 #define GET_THREAD_INFO(reg) \
 	movq %gs:pda_kernelstack,reg ; \
 	subq $(THREAD_SIZE-PDA_STACKOFFSET),reg
@@ -102,6 +101,7 @@ static inline struct thread_info *stack_
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_SINGLESTEP		4	/* reenable singlestep on user return*/
 #define TIF_IRET		5	/* force IRET */
+#define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
 #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_IA32		17	/* 32bit process */ 
 #define TIF_FORK		18	/* ret_from_fork */
@@ -113,13 +113,17 @@ static inline struct thread_info *stack_
 #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_IRET		(1<<TIF_IRET)
+#define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 #define _TIF_IA32		(1<<TIF_IA32)
 #define _TIF_FORK		(1<<TIF_FORK)
 #define _TIF_ABI_PENDING	(1<<TIF_ABI_PENDING)
 
-#define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
-#define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
+/* work to do on interrupt/exception return */
+#define _TIF_WORK_MASK \
+  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP))
+/* work to do on any return to user space */
+#define _TIF_ALLWORK_MASK 0x0000FFFF	
 
 #define PREEMPT_ACTIVE     0x4000000
 
--- diff/include/asm-x86_64/unistd.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/asm-x86_64/unistd.h	2004-03-16 09:37:57.834747952 +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/asm-x86_64/vsyscall32.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-x86_64/vsyscall32.h	2004-03-16 09:37:57.835747800 +0000
@@ -3,11 +3,18 @@
 
 /* Values need to match arch/x86_64/ia32/vsyscall.lds */
 
+#ifdef __ASSEMBLY__
+#define VSYSCALL32_BASE 0xffffe000
+#define VSYSCALL32_SYSEXIT (VSYSCALL32_BASE + 0x410)
+#else
 #define VSYSCALL32_BASE 0xffffe000UL
+#define VSYSCALL32_END (VSYSCALL32_BASE + PAGE_SIZE)
 #define VSYSCALL32_EHDR ((const struct elf32_hdr *) VSYSCALL32_BASE)
 
 #define VSYSCALL32_VSYSCALL ((void *)VSYSCALL32_BASE + 0x400) 
+#define VSYSCALL32_SYSEXIT ((void *)VSYSCALL32_BASE + 0x410)
 #define VSYSCALL32_SIGRETURN ((void *)VSYSCALL32_BASE + 0x500) 
 #define VSYSCALL32_RTSIGRETURN ((void *)VSYSCALL32_BASE + 0x600) 
+#endif
 
 #endif
--- diff/include/linux/backing-dev.h	2003-05-21 10:49:56.000000000 +0000
+++ source/include/linux/backing-dev.h	2004-03-16 09:37:57.836747648 +0000
@@ -20,26 +20,46 @@ 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 */
+	void (*unplug_io_fn)(struct backing_dev_info *);
+	void *unplug_io_data;
 };
 
 extern struct backing_dev_info default_backing_dev_info;
+void default_unplug_io_fn(struct backing_dev_info *bdi);
 
 int writeback_acquire(struct backing_dev_info *bdi);
 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 13:16:34.000000000 +0000
+++ source/include/linux/binfmts.h	2004-03-16 09:37:57.836747648 +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/bio.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/bio.h	2004-03-16 09:37:57.836747648 +0000
@@ -124,6 +124,7 @@ struct bio {
 #define BIO_RW_AHEAD	1
 #define BIO_RW_BARRIER	2
 #define BIO_RW_FAILFAST	3
+#define BIO_RW_SYNC	4
 
 /*
  * various member access, note that bio_data should of course not be used
@@ -138,6 +139,7 @@ struct bio {
 #define bio_cur_sectors(bio)	(bio_iovec(bio)->bv_len >> 9)
 #define bio_data(bio)		(page_address(bio_page((bio))) + bio_offset((bio)))
 #define bio_barrier(bio)	((bio)->bi_rw & (1 << BIO_RW_BARRIER))
+#define bio_sync(bio)		((bio)->bi_rw & (1 << BIO_RW_SYNC))
 
 /*
  * will die
--- diff/include/linux/blkdev.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/linux/blkdev.h	2004-03-16 09:37:57.838747344 +0000
@@ -243,7 +243,7 @@ typedef int (merge_requests_fn) (request
 typedef void (request_fn_proc) (request_queue_t *q);
 typedef int (make_request_fn) (request_queue_t *q, struct bio *bio);
 typedef int (prep_rq_fn) (request_queue_t *, struct request *);
-typedef void (unplug_fn) (void *q);
+typedef void (unplug_fn) (request_queue_t *);
 
 struct bio_vec;
 typedef int (merge_bvec_fn) (request_queue_t *, struct bio *, struct bio_vec *);
@@ -315,8 +315,6 @@ struct request_queue
 	unsigned long		bounce_pfn;
 	int			bounce_gfp;
 
-	struct list_head	plug_list;
-
 	/*
 	 * various queue flags, see QUEUE_* below
 	 */
@@ -370,8 +368,9 @@ struct request_queue
 #define QUEUE_FLAG_WRITEFULL	4	/* read queue has been filled */
 #define QUEUE_FLAG_DEAD		5	/* queue being torn down */
 #define QUEUE_FLAG_REENTER	6	/* Re-entrancy avoidance */
+#define QUEUE_FLAG_PLUGGED	7	/* queue is plugged */
 
-#define blk_queue_plugged(q)	!list_empty(&(q)->plug_list)
+#define blk_queue_plugged(q)	test_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags)
 #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)
 
@@ -515,14 +514,29 @@ extern int scsi_cmd_ioctl(struct gendisk
 extern void blk_start_queue(request_queue_t *q);
 extern void blk_stop_queue(request_queue_t *q);
 extern void __blk_stop_queue(request_queue_t *q);
-extern void blk_run_queue(request_queue_t *q);
+extern void blk_run_queue(request_queue_t *);
 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);
+extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *);
 
 static inline request_queue_t *bdev_get_queue(struct block_device *bdev)
 {
 	return bdev->bd_disk->queue;
 }
 
+static inline void blk_run_backing_dev(struct backing_dev_info *bdi)
+{
+	if (bdi && bdi->unplug_io_fn)
+		bdi->unplug_io_fn(bdi);
+}
+
+static inline void blk_run_address_space(struct address_space *mapping)
+{
+	if (mapping)
+		blk_run_backing_dev(mapping->backing_dev_info);
+}
+
 /*
  * end_request() and friends. Must be called with the request queue spinlock
  * acquired. All functions called within end_request() _must_be_ atomic.
@@ -569,7 +583,7 @@ extern struct backing_dev_info *blk_get_
 
 extern int blk_rq_map_sg(request_queue_t *, struct request *, struct scatterlist *);
 extern void blk_dump_rq_flags(struct request *, char *);
-extern void generic_unplug_device(void *);
+extern void generic_unplug_device(request_queue_t *);
 extern long nr_blockdev_pages(void);
 
 int blk_get_queue(request_queue_t *);
@@ -589,7 +603,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-16 09:37:57.839747192 +0000
@@ -877,10 +877,18 @@ struct mode_page_header {
 #include <linux/fs.h>		/* not really needed, later.. */
 #include <linux/device.h>
 
+/*
+ * _OLD will use PIO transfer on atapi devices, _BPC_* will use DMA
+ */
+#define CDDA_OLD		0	/* old style */
+#define CDDA_BPC_SINGLE		1	/* single frame block pc */
+#define CDDA_BPC_FULL		2	/* multi frame 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 +902,8 @@ 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 */
+	__u8 last_sense;
 	int for_data;
 	int (*exit)(struct cdrom_device_info *);
 	int mrw_mode_page;
--- diff/include/linux/compat.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/linux/compat.h	2004-03-16 09:37:57.839747192 +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;
@@ -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-03-11 10:20:28.000000000 +0000
+++ source/include/linux/compat_ioctl.h	2004-03-16 09:37:57.840747040 +0000
@@ -134,6 +134,7 @@ COMPATIBLE_IOCTL(DM_TABLE_LOAD)
 COMPATIBLE_IOCTL(DM_TABLE_CLEAR)
 COMPATIBLE_IOCTL(DM_TABLE_DEPS)
 COMPATIBLE_IOCTL(DM_TABLE_STATUS)
+COMPATIBLE_IOCTL(DM_LIST_VERSIONS)
 /* Big K */
 COMPATIBLE_IOCTL(PIO_FONT)
 COMPATIBLE_IOCTL(GIO_FONT)
--- diff/include/linux/compiler-gcc.h	2003-10-09 08:47:17.000000000 +0000
+++ source/include/linux/compiler-gcc.h	2004-03-16 09:37:57.883740504 +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-11 10:20:28.000000000 +0000
+++ source/include/linux/compiler-gcc3.h	2004-03-16 09:37:57.884740352 +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-11 10:20:28.000000000 +0000
+++ source/include/linux/compiler.h	2004-03-16 09:37:57.884740352 +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 08:47:17.000000000 +0000
+++ source/include/linux/config.h	2004-03-16 09:37:57.885740200 +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/device-mapper.h	2003-06-30 09:07:24.000000000 +0000
+++ source/include/linux/device-mapper.h	2004-03-16 09:37:57.885740200 +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-16 09:37:57.886740048 +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	2004-03-11 10:20:28.000000000 +0000
+++ source/include/linux/dm-ioctl.h	2004-03-16 09:37:57.886740048 +0000
@@ -163,6 +163,16 @@ struct dm_name_list {
 };
 
 /*
+ * 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()
  */
@@ -185,6 +195,9 @@ enum {
 	DM_TABLE_CLEAR_CMD,
 	DM_TABLE_DEPS_CMD,
 	DM_TABLE_STATUS_CMD,
+
+	/* Added later */
+	DM_LIST_VERSIONS_CMD,
 };
 
 #define DM_IOCTL 0xfd
@@ -205,10 +218,12 @@ enum {
 #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	0
+#define DM_VERSION_MINOR	1
 #define DM_VERSION_PATCHLEVEL	0
-#define DM_VERSION_EXTRA	"-ioctl (2003-06-04)"
+#define DM_VERSION_EXTRA	"-ioctl (2003-12-10)"
 
 /* Status bits */
 #define DM_READONLY_FLAG	(1 << 0) /* In/Out */
--- diff/include/linux/dma-mapping.h	2002-12-30 10:17:13.000000000 +0000
+++ source/include/linux/dma-mapping.h	2004-03-16 09:37:57.886740048 +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-16 09:37:57.887739896 +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-16 09:37:57.893738984 +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-16 09:37:57.894738832 +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/fb.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/linux/fb.h	2004-03-16 09:37:57.896738528 +0000
@@ -236,15 +236,71 @@ struct fb_con2fbmap {
 #define VESA_HSYNC_SUSPEND      2
 #define VESA_POWERDOWN          3
 
+/* Definitions below are used in the parsed monitor specs */
+#define FB_DPMS_ACTIVE_OFF	1
+#define FB_DPMS_SUSPEND		2
+#define FB_DPMS_STANDBY		4
+
+#define FB_DISP_DDI		1
+#define FB_DISP_ANA_700_300	2
+#define FB_DISP_ANA_714_286	4
+#define FB_DISP_ANA_1000_400	8
+#define FB_DISP_ANA_700_000	16
+
+#define FB_DISP_MONO		32
+#define FB_DISP_RGB		64
+#define FB_DISP_MULTI		128
+#define FB_DISP_UNKNOWN		256
+
+#define FB_SIGNAL_NONE		0
+#define FB_SIGNAL_BLANK_BLANK	1
+#define FB_SIGNAL_SEPARATE	2
+#define FB_SIGNAL_COMPOSITE	4
+#define FB_SIGNAL_SYNC_ON_GREEN	8
+#define FB_SIGNAL_SERRATION_ON	16
+
+#define FB_MISC_PRIM_COLOR	1
+#define FB_MISC_1ST_DETAIL	2	/* First Detailed Timing is preferred */
+
+struct fb_chroma {
+	__u32 redx;	/* in fraction of 1024 */
+	__u32 greenx;
+	__u32 bluex;
+	__u32 whitex;
+	__u32 redy;
+	__u32 greeny;
+	__u32 bluey;
+	__u32 whitey;
+};
+
 struct fb_monspecs {
+	struct fb_chroma chroma;
+	struct fb_videomode *modedb;	/* mode database */
+	__u8  manufacturer[4];		/* Manufacturer */
+	__u8  monitor[14];		/* Monitor String */
+	__u8  serial_no[14];		/* Serial Number */
+	__u8  ascii[14];		/* ? */
+	__u32 modedb_len;		/* mode database length */
+	__u32 model;			/* Monitor Model */
+	__u32 serial;			/* Serial Number - Integer */
+	__u32 year;			/* Year manufactured */
+	__u32 week;			/* Week Manufactured */
 	__u32 hfmin;			/* hfreq lower limit (Hz) */
-	__u32 hfmax; 			/* hfreq upper limit (Hz) */
+	__u32 hfmax;			/* hfreq upper limit (Hz) */
+	__u32 dclkmin;			/* pixelclock lower limit (Hz) */
+	__u32 dclkmax;			/* pixelclock upper limit (Hz) */
+	__u16 input;			/* display type - see FB_DISP_* */
+	__u16 dpms;			/* DPMS support - see FB_DPMS_ */
+	__u16 signal;			/* Signal Type - see FB_SIGNAL_* */
 	__u16 vfmin;			/* vfreq lower limit (Hz) */
 	__u16 vfmax;			/* vfreq upper limit (Hz) */
-	__u32 dclkmin;                  /* pixelclock lower limit (Hz) */
-	__u32 dclkmax;                  /* pixelclock upper limit (Hz) */
-	unsigned gtf  : 1;              /* supports GTF */
-	unsigned dpms : 1;		/* supports DPMS */
+	__u16 gamma;			/* Gamma - in fractions of 100 */
+	__u16 gtf	: 1;		/* supports GTF */
+	__u16 misc;			/* Misc flags - see FB_MISC_* */
+	__u8  version;			/* EDID version... */
+	__u8  revision;			/* ...and revision */
+	__u8  max_x;			/* Maximum horizontal size (cm) */
+	__u8  max_y;			/* Maximum vertical size (cm) */
 };
 
 #define FB_VBLANK_VBLANKING	0x001	/* currently in a vertical blank */
@@ -379,14 +435,19 @@ struct fb_pixmap {
 	u32 scan_align;		/* alignment per scanline		*/
 	u32 access_align;	/* alignment per read/write		*/
 	u32 flags;		/* see FB_PIXMAP_*			*/
-				/* access methods			*/
+	/* access methods */
 	void (*outbuf)(struct fb_info *info, u8 *addr, u8 *src, unsigned int size);
 	u8   (*inbuf) (struct fb_info *info, u8 *addr);
 };
 
-    /*
-     *  Frame buffer operations
-     */
+
+/*
+ * Frame buffer operations
+ *
+ * LOCKING NOTE: those functions must _ALL_ be called with the console
+ * semaphore held, this is the only suitable locking mecanism we have
+ * in 2.6. Some may be called at interrupt time at this point though.
+ */
 
 struct fb_ops {
 	/* open/release and usage marking */
@@ -394,13 +455,16 @@ struct fb_ops {
 	int (*fb_open)(struct fb_info *info, int user);
 	int (*fb_release)(struct fb_info *info, int user);
 
-	/* For framebuffers with strange non linear layouts */
+	/* For framebuffers with strange non linear layouts or that do not
+	 * work with normal memory mapped access
+	 */
 	ssize_t (*fb_read)(struct file *file, char *buf, size_t count, loff_t *ppos);
 	ssize_t (*fb_write)(struct file *file, const char *buf, size_t count, loff_t *ppos);
 
 	/* checks var and eventually tweaks it to something supported,
 	 * DO NOT MODIFY PAR */
 	int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
+
 	/* set the video mode according to info->var */
 	int (*fb_set_par)(struct fb_info *info);
 
@@ -441,15 +505,14 @@ struct fb_ops {
 struct fb_info {
 	int node;
 	int flags;
-	int open;			/* Has this been open already ? */
 #define FBINFO_FLAG_MODULE	1	/* Low-level driver is a module */
 	struct fb_var_screeninfo var;	/* Current var */
 	struct fb_fix_screeninfo fix;	/* Current fix */
 	struct fb_monspecs monspecs;	/* Current Monitor specs */
 	struct fb_cursor cursor;	/* Current cursor */	
 	struct work_struct queue;	/* Framebuffer event queue */
-	struct fb_pixmap pixmap;	/* Image Hardware Mapper */
-	struct fb_pixmap sprite;	/* Cursor hardware Mapper */
+	struct fb_pixmap pixmap;	/* Image hardware mapper */
+	struct fb_pixmap sprite;	/* Cursor hardware mapper */
 	struct fb_cmap cmap;		/* Current cmap */
 	struct fb_ops *fbops;
 	char *screen_base;		/* Virtual address */
@@ -459,6 +522,7 @@ struct fb_info {
 #define FBINFO_STATE_RUNNING	0
 #define FBINFO_STATE_SUSPENDED	1
 	u32 state;			/* Hardware state i.e suspend */
+
 	/* From here on everything is device dependent */
 	void *par;	
 };
@@ -469,12 +533,14 @@ struct fb_info {
 #define FBINFO_FLAG_DEFAULT	0
 #endif
 
+// This will go away
 #if defined(__sparc__)
 
 /* We map all of our framebuffers such that big-endian accesses
  * are what we want, so the following is sufficient.
  */
 
+// This will go away
 #define fb_readb sbus_readb
 #define fb_readw sbus_readw
 #define fb_readl sbus_readl
@@ -485,7 +551,7 @@ struct fb_info {
 #define fb_writeq sbus_writeq
 #define fb_memset sbus_memset_io
 
-#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || defined(__sh__)
+#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || defined(__sh__) || defined(__powerpc__)
 
 #define fb_readb __raw_readb
 #define fb_readw __raw_readw
@@ -546,24 +612,32 @@ extern struct fb_info *framebuffer_alloc
 extern void framebuffer_release(struct fb_info *info);
 
 /* drivers/video/fbmon.c */
-#define FB_MAXTIMINGS       0
-#define FB_VSYNCTIMINGS     1
-#define FB_HSYNCTIMINGS     2
-#define FB_DCLKTIMINGS      3
-#define FB_IGNOREMON    0x100
+#define FB_MAXTIMINGS		0
+#define FB_VSYNCTIMINGS		1
+#define FB_HSYNCTIMINGS		2
+#define FB_DCLKTIMINGS		3
+#define FB_IGNOREMON		0x100
+
+#define FB_MODE_IS_UNKNOWN	0
+#define FB_MODE_IS_DETAILED	1
+#define FB_MODE_IS_STANDARD	2
+#define FB_MODE_IS_VESA		4
+#define FB_MODE_IS_CALCULATED	8
+#define FB_MODE_IS_FIRST	16
 
 extern int fbmon_valid_timings(u_int pixclock, u_int htotal, u_int vtotal,
 			       const struct fb_info *fb_info);
 extern int fbmon_dpms(const struct fb_info *fb_info);
 extern int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var,
 		       struct fb_info *info);
-extern int fb_validate_mode(struct fb_var_screeninfo *var,
+extern int fb_validate_mode(const struct fb_var_screeninfo *var,
 			    struct fb_info *info);
-extern int parse_edid(unsigned char *edid, struct fb_var_screeninfo *var);
+extern int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var);
+extern int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs);
+extern void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs);
 extern int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs);
 extern struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize);
 extern void fb_destroy_modedb(struct fb_videomode *modedb);
-extern void show_edid(unsigned char *edid);
 
 /* drivers/video/modedb.c */
 #define VESA_MODEDB_SIZE 34
@@ -578,58 +652,28 @@ extern struct fb_cmap *fb_default_cmap(i
 extern void fb_invert_cmaps(void);
 
 struct fb_videomode {
-    const char *name;	/* optional */
-    u32 refresh;	/* optional */
-    u32 xres;
-    u32 yres;
-    u32 pixclock;
-    u32 left_margin;
-    u32 right_margin;
-    u32 upper_margin;
-    u32 lower_margin;
-    u32 hsync_len;
-    u32 vsync_len;
-    u32 sync;
-    u32 vmode;
-};
-
-#ifdef MODULE
-static inline int fb_find_mode(struct fb_var_screeninfo *var,
-			       struct fb_info *info,
-			       const char *mode_option,
-			       const struct fb_videomode *db,
-			       unsigned int dbsize,
-			       const struct fb_videomode *default_mode,
-			       unsigned int default_bpp)
-{
-    extern int __fb_try_mode(struct fb_var_screeninfo *var,
-	    		     struct fb_info *info,
-			     const struct fb_videomode *mode,
-			     unsigned int bpp);
-    /*
-     *  FIXME: How to make the compiler optimize vga640x400 away if
-     *         default_mode is non-NULL?
-     */
-    static const struct fb_videomode vga640x400 = {
-	/* 640x400 @ 70 Hz, 31.5 kHz hsync */
-	NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2,
-	0, FB_VMODE_NONINTERLACED
-    };
-    if (!default_mode)
-	default_mode = &vga640x400;
-    if (!default_bpp)
-	default_bpp = 8;
-    return __fb_try_mode(var, info, default_mode, default_bpp);
-}
-#else
-extern int __init fb_find_mode(struct fb_var_screeninfo *var,
-			       struct fb_info *info,
-			       const char *mode_option,
-			       const struct fb_videomode *db,
-			       unsigned int dbsize,
-			       const struct fb_videomode *default_mode,
-			       unsigned int default_bpp);
-#endif
+	const char *name;	/* optional */
+	u32 refresh;		/* optional */
+	u32 xres;
+	u32 yres;
+	u32 pixclock;
+	u32 left_margin;
+	u32 right_margin;
+	u32 upper_margin;
+	u32 lower_margin;
+	u32 hsync_len;
+	u32 vsync_len;
+	u32 sync;
+	u32 vmode;
+	u32 flag;
+};
+
+extern int fb_find_mode(struct fb_var_screeninfo *var,
+			struct fb_info *info, const char *mode_option,
+			const struct fb_videomode *db,
+			unsigned int dbsize,
+			const struct fb_videomode *default_mode,
+			unsigned int default_bpp);
 
 #endif /* __KERNEL__ */
 
--- diff/include/linux/fs.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/linux/fs.h	2004-03-16 09:37:57.898738224 +0000
@@ -20,6 +20,7 @@
 #include <linux/radix-tree.h>
 #include <linux/kobject.h>
 #include <asm/atomic.h>
+#include <linux/audit.h>
 
 struct iovec;
 struct nameidata;
@@ -82,6 +83,8 @@ extern int leases_enable, dir_notify_ena
 #define WRITE 1
 #define READA 2		/* read-ahead  - don't block if no resources */
 #define SPECIAL 4	/* For non-blockdevice requests in request queue */
+#define READ_SYNC	(READ | BIO_RW_SYNC)
+#define WRITE_SYNC	(WRITE | BIO_RW_SYNC)
 
 #define SEL_IN		1
 #define SEL_OUT		2
@@ -89,6 +92,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 +141,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 +175,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. */
@@ -319,11 +325,7 @@ struct backing_dev_info;
 struct address_space {
 	struct inode		*host;		/* owner: inode, block_device */
 	struct radix_tree_root	page_tree;	/* radix tree of all pages */
-	spinlock_t		page_lock;	/* and spinlock protecting it */
-	struct list_head	clean_pages;	/* list of clean pages */
-	struct list_head	dirty_pages;	/* list of dirty pages */
-	struct list_head	locked_pages;	/* list of locked pages */
-	struct list_head	io_pages;	/* being prepared for I/O */
+	spinlock_t		tree_lock;	/* and spinlock protecting it */
 	unsigned long		nrpages;	/* number of total pages */
 	struct address_space_operations *a_ops;	/* methods */
 	struct list_head	i_mmap;		/* list of private mappings */
@@ -363,6 +365,15 @@ struct block_device {
 };
 
 /*
+ * Radix-tre tags, for tagging dirty and writeback pages within the pagecache
+ * radix trees
+ */
+#define PAGECACHE_TAG_DIRTY	0
+#define PAGECACHE_TAG_WRITEBACK	1
+
+int mapping_tagged(struct address_space *mapping, int tag);
+
+/*
  * Use sequence counter to get consistent i_size on 32-bit processors.
  */
 #if BITS_PER_LONG==32 && defined(CONFIG_SMP)
@@ -376,6 +387,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 +407,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 +520,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 +715,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 */
@@ -1128,11 +1144,23 @@ extern char * getname(const char __user 
 extern void vfs_caches_init(unsigned long);
 
 #define __getname()	kmem_cache_alloc(names_cachep, SLAB_KERNEL)
-#define putname(name)	kmem_cache_free(names_cachep, (void *)(name))
+#define __putname(name) kmem_cache_free(names_cachep, (void *)(name))
+#ifndef CONFIG_AUDITSYSCALL
+#define putname(name)   __putname(name)
+#else
+#define putname(name)							\
+	do {								\
+		if (unlikely(current->audit_context))			\
+			audit_putname(name);				\
+		else							\
+			__putname(name);				\
+	} while (0)
+#endif
 
 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 +1238,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 +1350,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 +1371,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 11:28:12.000000000 +0000
+++ source/include/linux/hiddev.h	2004-03-16 09:37:57.898738224 +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/ide.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/linux/ide.h	2004-03-16 09:37:57.900737920 +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/idr.h	2004-03-11 10:20:28.000000000 +0000
+++ source/include/linux/idr.h	2004-03-16 09:37:57.900737920 +0000
@@ -23,6 +23,7 @@
 # error "BITS_PER_LONG is not 32 or 64"
 #endif
 
+#define IDR_SIZE (1 << IDR_BITS)
 #define IDR_MASK ((1 << IDR_BITS)-1)
 
 /* Define the size of the id's */
@@ -53,6 +54,17 @@ struct idr {
 	spinlock_t	  lock;
 };
 
+#define IDR_INIT(name)	\
+{								\
+	.top		= NULL,					\
+	.id_free	= NULL,					\
+	.count		= 0,					\
+	.layers 	= 0,					\
+	.id_free_cnt	= 0,					\
+	.lock		= SPIN_LOCK_UNLOCKED,			\
+}
+#define DEFINE_IDR(name)	struct idr name = IDR_INIT(name)
+
 /*
  * This is what we export.
  */
--- diff/include/linux/init.h	2003-11-25 15:24:59.000000000 +0000
+++ source/include/linux/init.h	2004-03-16 09:37:57.901737768 +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/ipmi.h	2003-05-21 10:49:46.000000000 +0000
+++ source/include/linux/ipmi.h	2004-03-16 09:37:57.902737616 +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-16 09:37:57.903737464 +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-16 09:37:57.903737464 +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 09:00:54.000000000 +0000
+++ source/include/linux/irq.h	2004-03-16 09:37:57.903737464 +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/kernel_stat.h	2003-08-26 09:00:54.000000000 +0000
+++ source/include/linux/kernel_stat.h	2004-03-16 09:37:57.904737312 +0000
@@ -14,13 +14,13 @@
  */
 
 struct cpu_usage_stat {
-	unsigned int user;
-	unsigned int nice;
-	unsigned int system;
-	unsigned int softirq;
-	unsigned int irq;
-	unsigned int idle;
-	unsigned int iowait;
+	u64 user;
+	u64 nice;
+	u64 system;
+	u64 softirq;
+	u64 irq;
+	u64 idle;
+	u64 iowait;
 };
 
 struct kernel_stat {
@@ -34,7 +34,7 @@ DECLARE_PER_CPU(struct kernel_stat, ksta
 /* Must have preemption disabled for this to be meaningful. */
 #define kstat_this_cpu	__get_cpu_var(kstat)
 
-extern unsigned long nr_context_switches(void);
+extern unsigned long long nr_context_switches(void);
 
 /*
  * Number of interrupts per specific IRQ source, since bootup
--- diff/include/linux/kmalloc_sizes.h	2003-05-21 10:50:00.000000000 +0000
+++ source/include/linux/kmalloc_sizes.h	2004-03-16 09:37:57.904737312 +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/kobject.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/kobject.h	2004-03-16 09:37:57.904737312 +0000
@@ -151,6 +151,14 @@ struct subsystem _name##_subsys = { \
 		.hotplug_ops =_hotplug_ops, \
 	} \
 }
+#define decl_subsys_name(_varname,_name,_type,_hotplug_ops) \
+struct subsystem _varname##_subsys = { \
+	.kset = { \
+		.kobj = { .name = __stringify(_name) }, \
+		.ktype = _type, \
+		.hotplug_ops =_hotplug_ops, \
+	} \
+}
 
 
 /**
--- diff/include/linux/libata.h	2004-03-11 10:20:29.000000000 +0000
+++ source/include/linux/libata.h	2004-03-16 09:37:57.905737160 +0000
@@ -183,12 +183,15 @@ struct ata_ioports {
 	unsigned long		cmd_addr;
 	unsigned long		data_addr;
 	unsigned long		error_addr;
+	unsigned long		feature_addr;
 	unsigned long		nsect_addr;
 	unsigned long		lbal_addr;
 	unsigned long		lbam_addr;
 	unsigned long		lbah_addr;
 	unsigned long		device_addr;
-	unsigned long		cmdstat_addr;
+	unsigned long		status_addr;
+	unsigned long		command_addr;
+	unsigned long		altstatus_addr;
 	unsigned long		ctl_addr;
 	unsigned long		bmdma_addr;
 	unsigned long		scr_addr;
@@ -408,6 +411,7 @@ extern int ata_scsi_queuecmd(struct scsi
 extern int ata_scsi_error(struct Scsi_Host *host);
 extern int ata_scsi_release(struct Scsi_Host *host);
 extern int ata_scsi_slave_config(struct scsi_device *sdev);
+extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
 /*
  * Default driver ops implementations
  */
@@ -465,8 +469,8 @@ static inline u8 ata_chk_status(struct a
 static inline u8 ata_altstatus(struct ata_port *ap)
 {
 	if (ap->flags & ATA_FLAG_MMIO)
-		return readb(ap->ioaddr.ctl_addr);
-	return inb(ap->ioaddr.ctl_addr);
+		return readb(ap->ioaddr.altstatus_addr);
+	return inb(ap->ioaddr.altstatus_addr);
 }
 
 static inline void ata_pause(struct ata_port *ap)
@@ -494,7 +498,7 @@ static inline u8 ata_wait_idle(struct at
 	u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
 
 	if (status & (ATA_BUSY | ATA_DRQ)) {
-		unsigned long l = ap->ioaddr.cmdstat_addr;
+		unsigned long l = ap->ioaddr.status_addr;
 		printk(KERN_WARNING
 		       "ATA: abnormal status 0x%X on port 0x%lX\n",
 		       status, l);
--- diff/include/linux/list.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/list.h	2004-03-16 09:37:57.906737008 +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-16 09:37:57.906737008 +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 09:00:54.000000000 +0000
+++ source/include/linux/lockd/lockd.h	2004-03-16 09:37:57.906737008 +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-11 10:20:29.000000000 +0000
+++ source/include/linux/loop.h	2004-03-16 09:37:57.907736856 +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-16 09:37:57.907736856 +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-11 10:20:29.000000000 +0000
+++ source/include/linux/mm.h	2004-03-16 09:37:57.908736704 +0000
@@ -152,6 +152,12 @@ struct pte_chain;
 struct mmu_gather;
 struct inode;
 
+#ifdef ARCH_HAS_ATOMIC_UNSIGNED
+typedef unsigned page_flags_t;
+#else
+typedef unsigned long page_flags_t;
+#endif
+
 /*
  * Each physical page in the system has a struct page associated with
  * it to keep track of whatever it is we are using the page for at the
@@ -168,12 +174,11 @@ struct inode;
  * TODO: make this structure smaller, it could be as small as 32 bytes.
  */
 struct page {
-	unsigned long flags;		/* atomic flags, some possibly
+	page_flags_t flags;		/* atomic flags, some possibly
 					   updated asynchronously */
 	atomic_t count;			/* Usage count, see below. */
-	struct list_head list;		/* ->mapping has some page lists. */
 	struct address_space *mapping;	/* The inode (or ...) we belong to. */
-	unsigned long index;		/* Our offset within mapping. */
+	pgoff_t index;			/* Our offset within mapping. */
 	struct list_head lru;		/* Pageout list, eg. active_list;
 					   protected by zone->lru_lock !! */
 	union {
@@ -233,24 +238,24 @@ extern void FASTCALL(__page_cache_releas
 static inline int page_count(struct page *p)
 {
 	if (PageCompound(p))
-		p = (struct page *)p->lru.next;
+		p = (struct page *)p->private;
 	return atomic_read(&(p)->count);
 }
 
 static inline void get_page(struct page *page)
 {
 	if (PageCompound(page))
-		page = (struct page *)page->lru.next;
+		page = (struct page *)page->private;
 	atomic_inc(&page->count);
 }
 
 static inline void put_page(struct page *page)
 {
 	if (PageCompound(page)) {
-		page = (struct page *)page->lru.next;
+		page = (struct page *)page->private;
 		if (put_page_testzero(page)) {
-			if (page->lru.prev) {	/* destructor? */
-				(*(void (*)(struct page *))page->lru.prev)(page);
+			if (page[1].mapping) {	/* destructor? */
+				(*(void (*)(struct page *))page[1].mapping)(page);
 			} else {
 				__page_cache_release(page);
 			}
@@ -333,7 +338,7 @@ static inline void put_page(struct page 
  * We'll have up to (MAX_NUMNODES * MAX_NR_ZONES) zones total,
  * so we use (MAX_NODES_SHIFT + MAX_ZONES_SHIFT) here to get enough bits.
  */
-#define NODEZONE_SHIFT (BITS_PER_LONG - MAX_NODES_SHIFT - MAX_ZONES_SHIFT)
+#define NODEZONE_SHIFT (sizeof(page_flags_t)*8 - MAX_NODES_SHIFT - MAX_ZONES_SHIFT)
 #define NODEZONE(node, zone)	((node << ZONES_SHIFT) | zone)
 
 static inline unsigned long page_zonenum(struct page *page)
@@ -415,10 +420,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 +457,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);
@@ -634,6 +641,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-11 10:20:29.000000000 +0000
+++ source/include/linux/mmzone.h	2004-03-16 09:37:57.909736552 +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 */
@@ -288,6 +289,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;
@@ -310,7 +316,7 @@ extern struct pglist_data contig_page_da
 
 #include <asm/mmzone.h>
 
-#if BITS_PER_LONG == 32
+#if BITS_PER_LONG == 32 || defined(ARCH_HAS_ATOMIC_UNSIGNED)
 /*
  * with 32 bit page->flags field, we reserve 8 bits for node/zone info.
  * there are 3 zones (2 bits) and this leaves 8-2=6 bits for nodes.
--- diff/include/linux/module.h	2004-03-11 10:20:29.000000000 +0000
+++ source/include/linux/module.h	2004-03-16 09:37:57.909736552 +0000
@@ -64,11 +64,12 @@ void sort_main_extable(void);
 #define __MODULE_INFO(tag, name, info)					  \
 static const char __module_cat(name,__LINE__)[]				  \
   __attribute_used__							  \
-  __attribute__((section(".modinfo"),unused)) = __stringify(tag) "=" info
+  __attribute__((section(".modinfo"))) = __stringify(tag) "=" info
 
 #define MODULE_GENERIC_TABLE(gtype,name)			\
 extern const struct gtype##_id __mod_##gtype##_table		\
-  __attribute__ ((unused, alias(__stringify(name))))
+  __attribute_used__						\
+  __attribute__ ((alias(__stringify(name))))
 
 #define THIS_MODULE (&__this_module)
 
@@ -165,7 +166,7 @@ void *__symbol_get_gpl(const char *symbo
 	extern void *__crc_##sym __attribute__((weak));		\
 	static const unsigned long __kcrctab_##sym		\
 	__attribute_used__					\
-	__attribute__((section("__kcrctab" sec), unused))	\
+	__attribute__((section("__kcrctab" sec)))		\
 	= (unsigned long) &__crc_##sym;
 #else
 #define __CRC_SYMBOL(sym, sec)
@@ -179,7 +180,7 @@ void *__symbol_get_gpl(const char *symbo
 	= MODULE_SYMBOL_PREFIX #sym;                    	\
 	static const struct kernel_symbol __ksymtab_##sym	\
 	__attribute_used__					\
-	__attribute__((section("__ksymtab" sec), unused))	\
+	__attribute__((section("__ksymtab" sec)))		\
 	= { (unsigned long)&sym, __kstrtab_##sym }
 
 #define EXPORT_SYMBOL(sym)					\
--- diff/include/linux/moduleparam.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/moduleparam.h	2004-03-16 09:37:57.910736400 +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-11 10:20:29.000000000 +0000
+++ source/include/linux/msg.h	2004-03-16 09:37:57.910736400 +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-16 09:37:57.910736400 +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-11 10:20:29.000000000 +0000
+++ source/include/linux/netdevice.h	2004-03-16 09:37:57.912736096 +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);
 }
 
@@ -774,6 +791,17 @@ enum {
 #define netif_msg_hw(p)		((p)->msg_enable & NETIF_MSG_HW)
 #define netif_msg_wol(p)	((p)->msg_enable & NETIF_MSG_WOL)
 
+static inline u32 netif_msg_init(int debug_value, int default_msg_enable_bits)
+{
+	/* use default */
+	if (debug_value < 0 || debug_value >= (sizeof(u32) * 8))
+		return default_msg_enable_bits;
+	if (debug_value == 0)	/* no output */
+		return 0;
+	/* set low N bits */
+	return (1 << debug_value) - 1;
+}
+
 /* Schedule rx intr now? */
 
 static inline int netif_rx_schedule_prep(struct net_device *dev)
--- diff/include/linux/netlink.h	2004-03-11 10:20:29.000000000 +0000
+++ source/include/linux/netlink.h	2004-03-16 09:37:57.912736096 +0000
@@ -13,6 +13,7 @@
 #define NETLINK_XFRM		6	/* ipsec */
 #define NETLINK_SELINUX		7	/* SELinux event notifications */
 #define NETLINK_ARPD		8
+#define NETLINK_AUDIT		9	/* auditing */
 #define NETLINK_ROUTE6		11	/* af_inet6 route comm channel */
 #define NETLINK_IP6_FW		13
 #define NETLINK_DNRTMSG		14	/* DECnet routing messages */
--- diff/include/linux/nfs_fs.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/nfs_fs.h	2004-03-16 09:37:57.914735792 +0000
@@ -69,6 +69,8 @@
 #define FLUSH_SYNC		1	/* file being synced, or contention */
 #define FLUSH_WAIT		2	/* wait for completion */
 #define FLUSH_STABLE		4	/* commit to stable storage */
+#define FLUSH_LOWPRI		8	/* low priority background flush */
+#define FLUSH_HIGHPRI		16	/* high priority memory reclaim flush */
 
 #ifdef __KERNEL__
 
@@ -99,7 +101,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 +120,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 +175,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 +192,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 +205,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 +235,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 +273,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
@@ -298,10 +337,8 @@ extern int  nfs_writepages(struct addres
 extern int  nfs_flush_incompatible(struct file *file, struct page *page);
 extern int  nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int);
 extern void nfs_writeback_done(struct rpc_task *task);
-extern void nfs_writedata_release(struct rpc_task *task);
 
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
-extern void nfs_commit_release(struct rpc_task *task);
 extern void nfs_commit_done(struct rpc_task *);
 #endif
 
@@ -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,29 +369,23 @@ 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;
 }
 
 /*
  * Write back all requests on one page - we do this before reading it.
  */
-static inline int
-nfs_wb_page(struct inode *inode, struct page* page)
+static inline int nfs_wb_page_priority(struct inode *inode, struct page* page, int how)
 {
-	int error = nfs_sync_file(inode, 0, page->index, 1,
-						FLUSH_WAIT | FLUSH_STABLE);
+	int error = nfs_sync_inode(inode, page->index, 1,
+			how | 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)
+static inline int nfs_wb_page(struct inode *inode, struct page* page)
 {
-	int error = nfs_sync_file(inode, file, 0, 0, FLUSH_WAIT);
-	return (error < 0) ? error : 0;
+	return nfs_wb_page_priority(inode, page, 0);
 }
 
 /* Hack for future NFS swap support */
@@ -371,7 +401,6 @@ extern int  nfs_readpages(struct file *,
 		struct list_head *, unsigned);
 extern int  nfs_pagein_list(struct list_head *, int);
 extern void nfs_readpage_result(struct rpc_task *);
-extern void nfs_readdata_release(struct rpc_task *);
 
 /*
  * linux/fs/mount_clnt.c
@@ -383,20 +412,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 +697,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-16 09:37:57.915735640 +0000
@@ -17,10 +17,14 @@
 #include <linux/sunrpc/auth.h>
 #include <linux/nfs_xdr.h>
 
+#include <asm/atomic.h>
+
 /*
  * Valid flags for a dirty buffer
  */
 #define PG_BUSY			0
+#define PG_NEED_COMMIT		1
+#define PG_NEED_RESCHED		2
 
 struct nfs_page {
 	struct list_head	wb_list,	/* Defines state of page: */
@@ -31,6 +35,7 @@ struct nfs_page {
 	struct rpc_cred		*wb_cred;
 	struct nfs4_state	*wb_state;
 	struct page		*wb_page;	/* page to read in/write out */
+	atomic_t		wb_complete;	/* i/os we're waiting for */
 	wait_queue_head_t	wb_wait;	/* wait queue */
 	unsigned long		wb_index;	/* Offset >> PAGE_CACHE_SHIFT */
 	unsigned int		wb_offset,	/* Offset & ~PAGE_CACHE_MASK */
@@ -42,6 +47,8 @@ struct nfs_page {
 };
 
 #define NFS_WBACK_BUSY(req)	(test_bit(PG_BUSY,&(req)->wb_flags))
+#define NFS_NEED_COMMIT(req)	(test_bit(PG_NEED_COMMIT,&(req)->wb_flags))
+#define NFS_NEED_RESCHED(req)	(test_bit(PG_NEED_RESCHED,&(req)->wb_flags))
 
 extern	struct nfs_page *nfs_create_request(struct file *, struct inode *,
 					    struct page *,
@@ -53,7 +60,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 *);
@@ -93,8 +100,7 @@ nfs_unlock_request(struct nfs_page *req)
 	smp_mb__before_clear_bit();
 	clear_bit(PG_BUSY, &req->wb_flags);
 	smp_mb__after_clear_bit();
-	if (waitqueue_active(&req->wb_wait))
-		wake_up_all(&req->wb_wait);
+	wake_up_all(&req->wb_wait);
 	nfs_release_request(req);
 }
 
@@ -115,6 +121,38 @@ nfs_list_remove_request(struct nfs_page 
 	req->wb_list_head = NULL;
 }
 
+static inline int
+nfs_defer_commit(struct nfs_page *req)
+{
+	if (test_and_set_bit(PG_NEED_COMMIT, &req->wb_flags))
+		return 0;
+	return 1;
+}
+
+static inline void
+nfs_clear_commit(struct nfs_page *req)
+{
+	smp_mb__before_clear_bit();
+	clear_bit(PG_NEED_COMMIT, &req->wb_flags);
+	smp_mb__after_clear_bit();
+}
+
+static inline int
+nfs_defer_reschedule(struct nfs_page *req)
+{
+	if (test_and_set_bit(PG_NEED_RESCHED, &req->wb_flags))
+		return 0;
+	return 1;
+}
+
+static inline void
+nfs_clear_reschedule(struct nfs_page *req)
+{
+	smp_mb__before_clear_bit();
+	clear_bit(PG_NEED_RESCHED, &req->wb_flags);
+	smp_mb__after_clear_bit();
+}
+
 static inline struct nfs_page *
 nfs_list_entry(struct list_head *head)
 {
--- diff/include/linux/nfs_xdr.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/nfs_xdr.h	2004-03-16 09:37:57.916735488 +0000
@@ -229,7 +229,8 @@ struct nfs_lockres {
 
 struct nfs_readargs {
 	struct nfs_fh *		fh;
-	nfs4_stateid		stateid;
+	fl_owner_t		lockowner;
+	struct nfs4_state *	state;
 	__u64			offset;
 	__u32			count;
 	unsigned int		pgbase;
@@ -252,7 +253,8 @@ struct nfs_readres {
 
 struct nfs_writeargs {
 	struct nfs_fh *		fh;
-	nfs4_stateid		stateid;
+	fl_owner_t		lockowner;
+	struct nfs4_state *	state;
 	__u64			offset;
 	__u32			count;
 	enum nfs3_stable_how	stable;
@@ -656,20 +658,23 @@ struct nfs4_compound {
 
 #endif /* CONFIG_NFS_V4 */
 
+struct nfs_page;
+
 struct nfs_read_data {
 	int			flags;
 	struct rpc_task		task;
 	struct inode		*inode;
 	struct rpc_cred		*cred;
-	fl_owner_t		lockowner;
 	struct nfs_fattr	fattr;	/* fattr storage */
 	struct list_head	pages;	/* Coalesced read requests */
+	struct nfs_page		*req;	/* multi ops per nfs_page */
 	struct page		*pagevec[NFS_READ_MAXIOV];
 	struct nfs_readargs args;
 	struct nfs_readres  res;
 #ifdef CONFIG_NFS_V4
 	unsigned long		timestamp;	/* For lease renewal */
 #endif
+	void (*complete) (struct nfs_read_data *, int);
 };
 
 struct nfs_write_data {
@@ -677,20 +682,19 @@ struct nfs_write_data {
 	struct rpc_task		task;
 	struct inode		*inode;
 	struct rpc_cred		*cred;
-	fl_owner_t		lockowner;
 	struct nfs_fattr	fattr;
 	struct nfs_writeverf	verf;
 	struct list_head	pages;		/* Coalesced requests we wish to flush */
+	struct nfs_page		*req;		/* multi ops per nfs_page */
 	struct page		*pagevec[NFS_WRITE_MAXIOV];
 	struct nfs_writeargs	args;		/* argument struct */
 	struct nfs_writeres	res;		/* result struct */
 #ifdef CONFIG_NFS_V4
 	unsigned long		timestamp;	/* For lease renewal */
 #endif
+	void (*complete) (struct nfs_write_data *, int);
 };
 
-struct nfs_page;
-
 /*
  * RPC procedure vector for NFSv2/NFSv3 demuxing
  */
@@ -700,7 +704,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 *);
@@ -737,9 +741,9 @@ struct nfs_rpc_ops {
 	int	(*pathconf) (struct nfs_server *, struct nfs_fh *,
 			     struct nfs_pathconf *);
 	u32 *	(*decode_dirent)(u32 *, struct nfs_entry *, int plus);
-	void	(*read_setup)   (struct nfs_read_data *, unsigned int count);
-	void	(*write_setup)  (struct nfs_write_data *, unsigned int count, int how);
-	void	(*commit_setup) (struct nfs_write_data *, u64 start, u32 len, int how);
+	void	(*read_setup)   (struct nfs_read_data *);
+	void	(*write_setup)  (struct nfs_write_data *, int how);
+	void	(*commit_setup) (struct nfs_write_data *, int how);
 	int	(*file_open)   (struct inode *, struct file *);
 	int	(*file_release) (struct inode *, struct file *);
 	void	(*request_init)(struct nfs_page *, struct file *);
--- diff/include/linux/page-flags.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/linux/page-flags.h	2004-03-16 09:37:57.917735336 +0000
@@ -80,6 +80,9 @@
 /*
  * Global page accounting.  One instance per CPU.  Only unsigned longs are
  * allowed.
+ *
+ * NOTE: if this structure is changed then mm/page_alloc.c and
+ * arch/s390/appldata/appldata_mem.c must be updated accordingly
  */
 struct page_state {
 	unsigned long nr_dirty;		/* Dirty writeable pages */
@@ -98,23 +101,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 +149,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
@@ -284,10 +315,18 @@ extern struct address_space swapper_spac
 struct page;	/* forward declaration */
 
 int test_clear_page_dirty(struct page *page);
+int __clear_page_dirty(struct page *page);
+int test_clear_page_writeback(struct page *page);
+int test_set_page_writeback(struct page *page);
 
 static inline void clear_page_dirty(struct page *page)
 {
 	test_clear_page_dirty(page);
 }
 
+static inline void set_page_writeback(struct page *page)
+{
+	test_set_page_writeback(page);
+}
+
 #endif	/* PAGE_FLAGS_H */
--- diff/include/linux/pagemap.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/linux/pagemap.h	2004-03-16 09:37:57.917735336 +0000
@@ -69,9 +69,10 @@ extern struct page * find_trylock_page(s
 				unsigned long index);
 extern struct page * find_or_create_page(struct address_space *mapping,
 				unsigned long index, unsigned int gfp_mask);
-extern unsigned int find_get_pages(struct address_space *mapping,
-				pgoff_t start, unsigned int nr_pages,
-				struct page **pages);
+unsigned find_get_pages(struct address_space *mapping, pgoff_t start,
+			unsigned int nr_pages, struct page **pages);
+unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index,
+			int tag, unsigned int nr_pages, struct page **pages);
 
 /*
  * Returns locked page at given index in given cache, creating it if needed.
@@ -141,7 +142,6 @@ static inline unsigned long get_page_cac
 static inline void ___add_to_page_cache(struct page *page,
 		struct address_space *mapping, unsigned long index)
 {
-	list_add(&page->list, &mapping->clean_pages);
 	page->mapping = mapping;
 	page->index = index;
 
--- diff/include/linux/pagevec.h	2003-10-09 08:47:17.000000000 +0000
+++ source/include/linux/pagevec.h	2004-03-16 09:37:57.918735184 +0000
@@ -22,8 +22,11 @@ void __pagevec_free(struct pagevec *pvec
 void __pagevec_lru_add(struct pagevec *pvec);
 void __pagevec_lru_add_active(struct pagevec *pvec);
 void pagevec_strip(struct pagevec *pvec);
-unsigned int pagevec_lookup(struct pagevec *pvec, struct address_space *mapping,
-		pgoff_t start, unsigned int nr_pages);
+unsigned pagevec_lookup(struct pagevec *pvec, struct address_space *mapping,
+		pgoff_t start, unsigned nr_pages);
+unsigned pagevec_lookup_tag(struct pagevec *pvec,
+		struct address_space *mapping, pgoff_t *index, int tag,
+		unsigned nr_pages);
 
 static inline void pagevec_init(struct pagevec *pvec, int cold)
 {
--- diff/include/linux/pci.h	2004-03-11 10:20:29.000000000 +0000
+++ source/include/linux/pci.h	2004-03-16 09:37:57.919735032 +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-11 10:20:29.000000000 +0000
+++ source/include/linux/pci_ids.h	2004-03-16 09:37:57.920734880 +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
@@ -569,6 +571,7 @@
 #define PCI_DEVICE_ID_SI_6202		0x0002
 #define PCI_DEVICE_ID_SI_503		0x0008
 #define PCI_DEVICE_ID_SI_ACPI		0x0009
+#define PCI_DEVICE_ID_SI_LPC		0x0018
 #define PCI_DEVICE_ID_SI_5597_VGA	0x0200
 #define PCI_DEVICE_ID_SI_6205		0x0205
 #define PCI_DEVICE_ID_SI_501		0x0406
--- diff/include/linux/quota.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/linux/quota.h	2004-03-16 09:37:57.921734728 +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-16 09:37:57.922734576 +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/radix-tree.h	2003-05-21 10:50:10.000000000 +0000
+++ source/include/linux/radix-tree.h	2004-03-16 09:37:57.922734576 +0000
@@ -20,8 +20,7 @@
 #define _LINUX_RADIX_TREE_H
 
 #include <linux/preempt.h>
-
-struct radix_tree_node;
+#include <linux/types.h>
 
 struct radix_tree_root {
 	unsigned int		height;
@@ -29,25 +28,40 @@ struct radix_tree_root {
 	struct radix_tree_node	*rnode;
 };
 
-#define RADIX_TREE_INIT(mask)	{0, (mask), NULL}
+#define RADIX_TREE_INIT(mask)	{					\
+	.height = 0,							\
+	.gfp_mask = (mask),						\
+	.rnode = NULL,							\
+}
 
 #define RADIX_TREE(name, mask) \
 	struct radix_tree_root name = RADIX_TREE_INIT(mask)
 
-#define INIT_RADIX_TREE(root, mask)	\
-do {					\
-	(root)->height = 0;		\
-	(root)->gfp_mask = (mask);	\
-	(root)->rnode = NULL;		\
+#define INIT_RADIX_TREE(root, mask)					\
+do {									\
+	(root)->height = 0;						\
+	(root)->gfp_mask = (mask);					\
+	(root)->rnode = NULL;						\
 } while (0)
 
-extern int radix_tree_insert(struct radix_tree_root *, unsigned long, void *);
-extern void *radix_tree_lookup(struct radix_tree_root *, unsigned long);
-extern void *radix_tree_delete(struct radix_tree_root *, unsigned long);
-extern unsigned int
+int radix_tree_insert(struct radix_tree_root *, unsigned long, void *);
+void *radix_tree_lookup(struct radix_tree_root *, unsigned long);
+void *radix_tree_delete(struct radix_tree_root *, unsigned long);
+unsigned int
 radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
 			unsigned long first_index, unsigned int max_items);
 int radix_tree_preload(int gfp_mask);
+void radix_tree_init(void);
+void *radix_tree_tag_set(struct radix_tree_root *root,
+			unsigned long index, int tag);
+void *radix_tree_tag_clear(struct radix_tree_root *root,
+			unsigned long index, int tag);
+int radix_tree_tag_get(struct radix_tree_root *root,
+			unsigned long index, int tag);
+unsigned int
+radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,
+		unsigned long first_index, unsigned int max_items, int tag);
+int radix_tree_tagged(struct radix_tree_root *root, int tag);
 
 static inline void radix_tree_preload_end(void)
 {
--- diff/include/linux/raid/md_k.h	2004-03-11 10:20:29.000000000 +0000
+++ source/include/linux/raid/md_k.h	2004-03-16 09:37:57.923734424 +0000
@@ -326,7 +326,6 @@ do {									\
 		if (condition)						\
 			break;						\
 		spin_unlock_irq(&lock);					\
-		blk_run_queues();					\
 		schedule();						\
 		spin_lock_irq(&lock);					\
 	}								\
@@ -341,30 +340,5 @@ do {									\
 	__wait_event_lock_irq(wq, condition, lock);			\
 } while (0)
 
-
-#define __wait_disk_event(wq, condition) 				\
-do {									\
-	wait_queue_t __wait;						\
-	init_waitqueue_entry(&__wait, current);				\
-									\
-	add_wait_queue(&wq, &__wait);					\
-	for (;;) {							\
-		set_current_state(TASK_UNINTERRUPTIBLE);		\
-		if (condition)						\
-			break;						\
-		blk_run_queues();					\
-		schedule();						\
-	}								\
-	current->state = TASK_RUNNING;					\
-	remove_wait_queue(&wq, &__wait);				\
-} while (0)
-
-#define wait_disk_event(wq, condition) 					\
-do {									\
-	if (condition)	 						\
-		break;							\
-	__wait_disk_event(wq, condition);				\
-} while (0)
-
 #endif
 
--- diff/include/linux/reiserfs_fs.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/reiserfs_fs.h	2004-03-16 09:37:57.925734120 +0000
@@ -1335,7 +1335,8 @@ static inline loff_t max_reiserfs_offset
 #define fs_generation(s) (REISERFS_SB(s)->s_generation_counter)
 #define get_generation(s) atomic_read (&fs_generation(s))
 #define FILESYSTEM_CHANGED_TB(tb)  (get_generation((tb)->tb_sb) != (tb)->fs_gen)
-#define fs_changed(gen,s) (gen != get_generation (s))
+#define __fs_changed(gen,s) (gen != get_generation (s))
+#define fs_changed(gen,s) ({cond_resched(); __fs_changed(gen, s);})
 
 
 /***************************************************************************/
--- diff/include/linux/rmap-locking.h	2003-06-30 09:07:34.000000000 +0000
+++ source/include/linux/rmap-locking.h	2004-03-16 09:37:57.925734120 +0000
@@ -10,8 +10,8 @@
 struct pte_chain;
 extern kmem_cache_t *pte_chain_cache;
 
-#define pte_chain_lock(page)	bit_spin_lock(PG_chainlock, &page->flags)
-#define pte_chain_unlock(page)	bit_spin_unlock(PG_chainlock, &page->flags)
+#define pte_chain_lock(page)	bit_spin_lock(PG_chainlock, (unsigned long *)&page->flags)
+#define pte_chain_unlock(page)	bit_spin_unlock(PG_chainlock, (unsigned long *)&page->flags)
 
 struct pte_chain *pte_chain_alloc(int gfp_flags);
 void __pte_chain_free(struct pte_chain *pte_chain);
--- diff/include/linux/sched.h	2004-03-11 10:20:29.000000000 +0000
+++ source/include/linux/sched.h	2004-03-16 09:37:57.927733816 +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 */
@@ -265,6 +270,15 @@ struct signal_struct {
 
 	/* thread group stop support, overloads group_exit_code too */
 	int			group_stop_count;
+
+	/* job control IDs */
+	pid_t pgrp;
+	pid_t tty_old_pgrp;
+	pid_t session;
+	/* boolean value for session group leader */
+	int leader;
+
+	struct tty_struct *tty; /* NULL if no tty */
 };
 
 /*
@@ -358,6 +372,8 @@ int set_current_groups(struct group_info
     ((gi)->blocks[(i)/NGROUPS_PER_BLOCK][(i)%NGROUPS_PER_BLOCK])
 
 
+struct audit_context;		/* See audit.c */
+
 struct task_struct {
 	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
 	struct thread_info *thread_info;
@@ -394,12 +410,7 @@ struct task_struct {
 	unsigned long personality;
 	int did_exec:1;
 	pid_t pid;
-	pid_t __pgrp;		/* Accessed via process_group() */
-	pid_t tty_old_pgrp;
-	pid_t session;
 	pid_t tgid;
-	/* boolean value for session group leader */
-	int leader;
 	/* 
 	 * pointers to (original) parent process, youngest child, younger sibling,
 	 * older sibling, respectively.  (p->father can be replaced with 
@@ -442,7 +453,6 @@ struct task_struct {
 	char comm[16];
 /* file system info */
 	int link_count, total_link_count;
-	struct tty_struct *tty; /* NULL if no tty */
 /* ipc stuff */
 	struct sysv_sem sysvsem;
 /* CPU-specific state of this task */
@@ -467,6 +477,7 @@ struct task_struct {
 	sigset_t *notifier_mask;
 	
 	void *security;
+	struct audit_context *audit_context;
 
 /* Thread group tracking */
    	u32 parent_exec_id;
@@ -495,7 +506,7 @@ struct task_struct {
 
 static inline pid_t process_group(struct task_struct *tsk)
 {
-	return tsk->group_leader->__pgrp;
+	return tsk->signal->pgrp;
 }
 
 extern void __put_task_struct(struct task_struct *tsk);
@@ -527,8 +538,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,10 +655,8 @@ 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
 
 extern void set_user_nice(task_t *p, long nice);
@@ -560,13 +672,9 @@ void yield(void);
  */
 extern struct exec_domain	default_exec_domain;
 
-#ifndef INIT_THREAD_SIZE
-# define INIT_THREAD_SIZE	2048*sizeof(long)
-#endif
-
 union thread_union {
 	struct thread_info thread_info;
-	unsigned long stack[INIT_THREAD_SIZE/sizeof(long)];
+	unsigned long stack[THREAD_SIZE/sizeof(long)];
 };
 
 #ifndef __HAVE_ARCH_KSTACK_END
--- diff/include/linux/security.h	2004-03-11 10:20:29.000000000 +0000
+++ source/include/linux/security.h	2004-03-16 09:37:57.930733360 +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-11 10:20:29.000000000 +0000
+++ source/include/linux/sem.h	2004-03-16 09:37:57.930733360 +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-11 10:20:29.000000000 +0000
+++ source/include/linux/serial_core.h	2004-03-16 09:37:57.931733208 +0000
@@ -160,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-16 09:37:57.932733056 +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/socket.h	2004-03-11 10:20:29.000000000 +0000
+++ source/include/linux/socket.h	2004-03-16 09:37:57.933732904 +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 08:47:17.000000000 +0000
+++ source/include/linux/spinlock.h	2004-03-16 09:37:57.934732752 +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 08:55:19.000000000 +0000
+++ source/include/linux/sunrpc/debug.h	2004-03-16 09:37:57.935732600 +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/sched.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/sunrpc/sched.h	2004-03-16 09:37:57.935732600 +0000
@@ -49,6 +49,8 @@ struct rpc_task {
 				tk_cred_retry,
 				tk_suid_retry;
 
+	unsigned long		tk_cookie;	/* Cookie for batching tasks */
+
 	/*
 	 * timeout_fn   to be executed by timer bottom half
 	 * callback	to be executed after waking up
@@ -72,7 +74,9 @@ struct rpc_task {
 	unsigned long		tk_timeout;	/* timeout for rpc_sleep() */
 	unsigned short		tk_flags;	/* misc flags */
 	unsigned char		tk_active   : 1;/* Task has been activated */
+	unsigned char		tk_priority : 2;/* Task priority */
 	unsigned long		tk_runstate;	/* Task run status */
+	struct list_head	tk_links;	/* links to related tasks */
 #ifdef RPC_DEBUG
 	unsigned short		tk_pid;		/* debugging aid */
 #endif
@@ -138,28 +142,58 @@ typedef void			(*rpc_action)(struct rpc_
 	} while(0)
 
 /*
+ * Task priorities.
+ * Note: if you change these, you must also change
+ * the task initialization definitions below.
+ */
+#define RPC_PRIORITY_LOW	0
+#define RPC_PRIORITY_NORMAL	1
+#define RPC_PRIORITY_HIGH	2
+#define RPC_NR_PRIORITY		(RPC_PRIORITY_HIGH+1)
+
+/*
  * RPC synchronization objects
  */
 struct rpc_wait_queue {
-	struct list_head	tasks;
+	struct list_head	tasks[RPC_NR_PRIORITY];	/* task queue for each priority level */
+	unsigned long		cookie;			/* cookie of last task serviced */
+	unsigned char		maxpriority;		/* maximum priority (0 if queue is not a priority queue) */
+	unsigned char		priority;		/* current priority */
+	unsigned char		count;			/* # task groups remaining serviced so far */
+	unsigned char		nr;			/* # tasks remaining for cookie */
 #ifdef RPC_DEBUG
-	char *			name;
+	const char *		name;
 #endif
 };
 
+/*
+ * This is the # requests to send consecutively
+ * from a single cookie.  The aim is to improve
+ * performance of NFS operations such as read/write.
+ */
+#define RPC_BATCH_COUNT			16
+
 #ifndef RPC_DEBUG
-# define RPC_WAITQ_INIT(var,qname) ((struct rpc_wait_queue) {LIST_HEAD_INIT(var)})
-# define RPC_WAITQ(var,qname)      struct rpc_wait_queue var = RPC_WAITQ_INIT(var.tasks,qname)
-# define INIT_RPC_WAITQ(ptr,qname) do { \
-	INIT_LIST_HEAD(&(ptr)->tasks); \
-	} while(0)
+# define RPC_WAITQ_INIT(var,qname) { \
+		.tasks = { \
+			[0] = LIST_HEAD_INIT(var.tasks[0]), \
+			[1] = LIST_HEAD_INIT(var.tasks[1]), \
+			[2] = LIST_HEAD_INIT(var.tasks[2]), \
+		}, \
+	}
 #else
-# define RPC_WAITQ_INIT(var,qname) ((struct rpc_wait_queue) {LIST_HEAD_INIT(var.tasks), qname})
-# define RPC_WAITQ(var,qname)      struct rpc_wait_queue var = RPC_WAITQ_INIT(var,qname)
-# define INIT_RPC_WAITQ(ptr,qname) do { \
-	INIT_LIST_HEAD(&(ptr)->tasks); (ptr)->name = qname; \
-	} while(0)
+# define RPC_WAITQ_INIT(var,qname) { \
+		.tasks = { \
+			[0] = LIST_HEAD_INIT(var.tasks[0]), \
+			[1] = LIST_HEAD_INIT(var.tasks[1]), \
+			[2] = LIST_HEAD_INIT(var.tasks[2]), \
+		}, \
+		.name = qname, \
+	}
 #endif
+# define RPC_WAITQ(var,qname)      struct rpc_wait_queue var = RPC_WAITQ_INIT(var,qname)
+
+#define RPC_IS_PRIORITY(q)		((q)->maxpriority > 0)
 
 /*
  * Function prototypes
@@ -175,6 +209,8 @@ void		rpc_run_child(struct rpc_task *par
 					rpc_action action);
 int		rpc_add_wait_queue(struct rpc_wait_queue *, struct rpc_task *);
 void		rpc_remove_wait_queue(struct rpc_task *);
+void		rpc_init_priority_wait_queue(struct rpc_wait_queue *, const char *);
+void		rpc_init_wait_queue(struct rpc_wait_queue *, const char *);
 void		rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *,
 					rpc_action action, rpc_action timer);
 void		rpc_add_timer(struct rpc_task *, rpc_action);
@@ -194,16 +230,14 @@ void		rpc_show_tasks(void);
 int		rpc_init_mempool(void);
 void		rpc_destroy_mempool(void);
 
-static __inline__ void
-rpc_exit(struct rpc_task *task, int status)
+static inline void rpc_exit(struct rpc_task *task, int status)
 {
 	task->tk_status = status;
 	task->tk_action = NULL;
 }
 
 #ifdef RPC_DEBUG
-static __inline__ char *
-rpc_qname(struct rpc_wait_queue *q)
+static inline const char * rpc_qname(struct rpc_wait_queue *q)
 {
 	return ((q && q->name) ? q->name : "unknown");
 }
--- diff/include/linux/sunrpc/timer.h	2003-10-09 08:47:34.000000000 +0000
+++ source/include/linux/sunrpc/timer.h	2004-03-16 09:37:57.936732448 +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-16 09:37:57.936732448 +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-16 09:37:57.937732296 +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/swap.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/swap.h	2004-03-16 09:37:57.937732296 +0000
@@ -232,6 +232,8 @@ extern sector_t map_swap_page(struct swa
 extern struct swap_info_struct *get_swap_info_struct(unsigned);
 extern int can_share_swap_page(struct page *);
 extern int remove_exclusive_swap_page(struct page *);
+struct backing_dev_info;
+extern void swap_unplug_io_fn(struct backing_dev_info *);
 
 extern struct swap_list_t swap_list;
 extern spinlock_t swaplock;
--- diff/include/linux/syscalls.h	2004-03-11 10:20:29.000000000 +0000
+++ source/include/linux/syscalls.h	2004-03-16 09:37:57.938732144 +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);
@@ -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-11 10:20:29.000000000 +0000
+++ source/include/linux/sysctl.h	2004-03-16 09:37:57.939731992 +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 */
 };
 
 
--- diff/include/linux/sysfs.h	2003-08-26 09:00:54.000000000 +0000
+++ source/include/linux/sysfs.h	2004-03-16 09:37:57.939731992 +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 09:00:54.000000000 +0000
+++ source/include/linux/topology.h	2004-03-16 09:37:57.940731840 +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-16 09:37:57.940731840 +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 03:28:33.000000000 +0000
+++ source/include/linux/ufs_fs.h	2004-03-16 09:37:57.942731536 +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 03:27:08.000000000 +0000
+++ source/include/linux/ufs_fs_i.h	2004-03-16 09:37:57.942731536 +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-16 09:37:57.944731232 +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);
 
 
 /**
@@ -461,8 +495,8 @@ extern struct bus_type usb_bus_type;
  * @minor_base: the start of the minor range for this driver.
  *
  * This structure is used for the usb_register_dev() and
- * usb_unregister_dev() functions, to consolodate a number of the
- * paramaters used for them.
+ * usb_unregister_dev() functions, to consolidate a number of the
+ * parameters used for them.
  */
 struct usb_class_driver {
 	char *name;
@@ -520,7 +554,7 @@ typedef void (*usb_complete_t)(struct ur
  * @urb_list: For use by current owner of the URB.
  * @pipe: Holds endpoint number, direction, type, and more.
  *	Create these values with the eight macros available;
- *	usb_{snd,rcv}TYPEpipe(dev,endpoint), where the type is "ctrl"
+ *	usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is "ctrl"
  *	(control), "bulk", "int" (interrupt), or "iso" (isochronous).
  *	For example usb_sndbulkpipe() or usb_rcvintpipe().  Endpoint
  *	numbers range from zero to fifteen.  Note that "in" endpoint two
@@ -539,8 +573,8 @@ typedef void (*usb_complete_t)(struct ur
  * 	the I/O request will be performed (unless URB_NO_TRANSFER_DMA_MAP
  *	is set).  This buffer must be suitable for DMA; allocate it with
  *	kmalloc() or equivalent.  For transfers to "in" endpoints, contents
- *	of this buffer will be modified.  This buffer is used for data
- *	phases of control transfers.
+ *	of this buffer will be modified.  This buffer is used for the data
+ *	stage of control transfers.
  * @transfer_dma: When transfer_flags includes URB_NO_TRANSFER_DMA_MAP,
  *	the device driver is saying that it provided this DMA address,
  *	which the host controller driver should use in preference to the
@@ -563,8 +597,7 @@ typedef void (*usb_complete_t)(struct ur
  *	device driver has provided this DMA address for the setup packet.
  *	The host controller driver should use this in preference to
  *	setup_packet.
- * @start_frame: Returns the initial frame for interrupt or isochronous
- *	transfers.
+ * @start_frame: Returns the initial frame for isochronous transfers.
  * @number_of_packets: Lists the number of ISO transfer buffers.
  * @interval: Specifies the polling interval for interrupt or isochronous
  *	transfers.  The units are frames (milliseconds) for for full and low
@@ -632,13 +665,14 @@ typedef void (*usb_complete_t)(struct ur
  * Interrupt UBS must provide an interval, saying how often (in milliseconds
  * or, for highspeed devices, 125 microsecond units)
  * to poll for transfers.  After the URB has been submitted, the interval
- * and start_frame fields reflect how the transfer was actually scheduled.
+ * field reflects how the transfer was actually scheduled.
  * The polling interval may be more frequent than requested.
  * For example, some controllers have a maximum interval of 32 microseconds,
  * while others support intervals of up to 1024 microseconds.
  * Isochronous URBs also have transfer intervals.  (Note that for isochronous
  * endpoints, as well as high speed interrupt endpoints, the encoding of
- * the transfer interval in the endpoint descriptor is logarithmic.)
+ * the transfer interval in the endpoint descriptor is logarithmic.
+ * Device drivers must convert that value to linear units themselves.)
  *
  * Isochronous URBs normally use the URB_ISO_ASAP transfer flag, telling
  * the host controller to schedule the transfer as soon as bandwidth
@@ -671,8 +705,9 @@ typedef void (*usb_complete_t)(struct ur
  * The context field is normally used to link URBs back to the relevant
  * driver or request state.
  *
- * When completion callback is invoked for non-isochronous URBs, the
- * actual_length field tells how many bytes were transferred.
+ * When the completion callback is invoked for non-isochronous URBs, the
+ * actual_length field tells how many bytes were transferred.  This field
+ * is updated even when the URB terminated with an error or was unlinked.
  *
  * ISO transfer status is reported in the status and actual_length fields
  * of the iso_frame_desc array, and the number of errors is reported in
@@ -699,9 +734,9 @@ struct urb
 	int actual_length;		/* (return) actual transfer length */
 	unsigned char *setup_packet;	/* (in) setup packet (control only) */
 	dma_addr_t setup_dma;		/* (in) dma addr for setup_packet */
-	int start_frame;		/* (modify) start frame (INT/ISO) */
+	int start_frame;		/* (modify) start frame (ISO) */
 	int number_of_packets;		/* (in) number of ISO packets */
-	int interval;			/* (in) transfer interval (INT/ISO) */
+	int interval;			/* (modify) transfer interval (INT/ISO) */
 	int error_count;		/* (return) number of ISO errors */
 	int timeout;			/* (in) timeout, in jiffies */
 	void *context;			/* (in) context for completion */
@@ -830,14 +865,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-16 09:37:57.945731080 +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);
@@ -465,6 +465,8 @@ struct usb_gadget_ops {
  * 	driver setup() requests
  * @ep_list: List of other endpoints supported by the device.
  * @speed: Speed of current connection to USB host.
+ * @is_dualspeed: True if the controller supports both high and full speed
+ *	operation.  If it does, the gadget driver must also support both.
  * @name: Identifies the controller hardware type.  Used in diagnostics
  * 	and sometimes configuration.
  * @dev: Driver model state for this abstract device.
@@ -488,6 +490,7 @@ struct usb_gadget {
 	struct usb_ep			*ep0;
 	struct list_head		ep_list;	/* of usb_ep */
 	enum usb_device_speed		speed;
+	unsigned			is_dualspeed:1;
 	const char			*name;
 	struct device			dev;
 };
@@ -690,7 +693,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 +719,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-11 10:20:29.000000000 +0000
+++ source/include/linux/workqueue.h	2004-03-16 09:37:57.945731080 +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 08:47:17.000000000 +0000
+++ source/include/linux/writeback.h	2004-03-16 09:37:57.946730928 +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/irda/vlsi_ir.h	2003-09-17 11:28:12.000000000 +0000
+++ source/include/net/irda/vlsi_ir.h	2004-03-16 09:37:57.947730776 +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/pcmcia/cs.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/pcmcia/cs.h	2004-03-16 09:37:57.948730624 +0000
@@ -422,8 +422,6 @@ enum service {
 };
 
 int pcmcia_access_configuration_register(client_handle_t handle, conf_reg_t *reg);
-int pcmcia_bind_device(bind_req_t *req);
-int pcmcia_bind_mtd(mtd_bind_t *req);
 int pcmcia_deregister_client(client_handle_t handle);
 int pcmcia_get_configuration_info(client_handle_t handle, config_info_t *config);
 int pcmcia_get_card_services_info(servinfo_t *info);
@@ -447,10 +445,10 @@ int pcmcia_request_io(client_handle_t ha
 int pcmcia_request_irq(client_handle_t handle, irq_req_t *req);
 int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle_t *wh);
 int pcmcia_reset_card(client_handle_t handle, client_req_t *req);
-int pcmcia_suspend_card(client_handle_t handle, client_req_t *req);
-int pcmcia_resume_card(client_handle_t handle, client_req_t *req);
-int pcmcia_eject_card(client_handle_t handle, client_req_t *req);
-int pcmcia_insert_card(client_handle_t handle, client_req_t *req);
+int pcmcia_suspend_card(struct pcmcia_socket *skt);
+int pcmcia_resume_card(struct pcmcia_socket *skt);
+int pcmcia_eject_card(struct pcmcia_socket *skt);
+int pcmcia_insert_card(struct pcmcia_socket *skt);
 int pcmcia_set_event_mask(client_handle_t handle, eventmask_t *mask);
 int pcmcia_report_error(client_handle_t handle, error_info_t *err);
 struct pci_bus *pcmcia_lookup_bus(client_handle_t handle);
--- diff/include/scsi/scsi.h	2004-03-11 10:20:29.000000000 +0000
+++ source/include/scsi/scsi.h	2004-03-16 09:37:57.948730624 +0000
@@ -10,6 +10,12 @@
 
 #include <linux/types.h>
 
+/*
+ *	The maximum sg list length SCSI can cope with
+ *	(currently must be a power of 2 between 32 and 256)
+ */
+#define SCSI_MAX_PHYS_SEGMENTS	MAX_PHYS_SEGMENTS
+
 
 /*
  *	SCSI command lengths
@@ -200,6 +206,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
 
 /*
@@ -273,6 +280,7 @@ struct scsi_lun {
 #define DID_BAD_INTR    0x09	/* Got an interrupt we weren't expecting.  */
 #define DID_PASSTHROUGH 0x0a	/* Force command past mid-layer            */
 #define DID_SOFT_ERROR  0x0b	/* The low level driver just wish a retry  */
+#define DID_IMM_RETRY   0x0c	/* Retry without decrementing retry count  */
 #define DRIVER_OK       0x00	/* Driver status                           */
 
 /*
--- diff/include/scsi/scsi_device.h	2003-12-19 09:51:02.000000000 +0000
+++ source/include/scsi/scsi_device.h	2004-03-16 09:37:57.949730472 +0000
@@ -15,7 +15,7 @@ struct scsi_mode_data;
  * sdev state
  */
 enum scsi_device_state {
-	SDEV_CREATED,		/* device created but not added to sysfs
+	SDEV_CREATED = 1,	/* device created but not added to sysfs
 				 * Only internal commands allowed (for inq) */
 	SDEV_RUNNING,		/* device properly configured
 				 * All commands allowed */
@@ -23,6 +23,9 @@ enum scsi_device_state {
 				 * Only error handler commands allowed */
 	SDEV_DEL,		/* device deleted 
 				 * no commands allowed */
+	SDEV_QUIESCE,		/* Device quiescent.  No block commands
+				 * will be accepted, only specials (which
+				 * originate in the mid-layer) */
 };
 
 struct scsi_device {
@@ -94,6 +97,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 +107,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);
@@ -164,4 +173,8 @@ extern int scsi_set_medium_removal(struc
 extern int scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
 			   unsigned char *buffer, int len, int timeout,
 			   int retries, struct scsi_mode_data *data);
+extern int scsi_device_set_state(struct scsi_device *sdev,
+				 enum scsi_device_state state);
+extern int scsi_device_quiesce(struct scsi_device *sdev);
+extern void scsi_device_resume(struct scsi_device *sdev);
 #endif /* _SCSI_SCSI_DEVICE_H */
--- diff/include/scsi/scsi_host.h	2003-11-25 15:24:59.000000000 +0000
+++ source/include/scsi/scsi_host.h	2004-03-16 09:37:57.949730472 +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-16 09:37:57.950730320 +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-16 09:37:57.985725000 +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-16 09:37:57.986724848 +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-16 09:37:57.987724696 +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-16 09:37:57.988724544 +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-16 09:37:57.989724392 +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 10:50:10.000000000 +0000
+++ source/include/sound/memalloc.h	2004-03-16 09:37:57.990724240 +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-16 09:37:57.991724088 +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-16 09:37:57.991724088 +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-16 09:37:57.991724088 +0000
@@ -200,6 +200,9 @@ 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
+#define vortex_t_magic				0xa15a4601
+#define atiixp_t_magic				0xa15a4701
 
 #else
 
--- diff/include/sound/trident.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/sound/trident.h	2004-03-16 09:37:57.992723936 +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-16 09:37:57.992723936 +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-16 09:37:57.993723784 +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-11 10:20:29.000000000 +0000
+++ source/init/Kconfig	2004-03-16 09:37:57.994723632 +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
@@ -120,6 +138,26 @@ config SYSCTL
 	  building a kernel for install/rescue disks or your system is very
 	  limited in memory.
 
+config AUDIT
+	bool "Auditing support"
+	default y if SECURITY_SELINUX
+	default n
+	help
+	  Enable auditing infrastructure that can be used with another
+	  kernel subsystem, such as SELinux (which requires this for
+	  logging of avc messages output).  Does not do system-call
+	  auditing without CONFIG_AUDITSYSCALL.
+
+config AUDITSYSCALL
+	bool "Enable system-call auditing support"
+	depends on AUDIT && (X86 || PPC64)
+	default y if SECURITY_SELINUX
+	default n
+	help
+	  Enable low-overhead system-call auditing infrastructure that
+	  can be used independently or with another kernel subsystem,
+	  such as SELinux.
+
 config LOG_BUF_SHIFT
 	int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" if DEBUG_KERNEL
 	range 12 20
--- diff/init/do_mounts.c	2004-01-19 10:22:59.000000000 +0000
+++ source/init/do_mounts.c	2004-03-16 09:37:57.995723480 +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;
@@ -163,6 +165,9 @@ dev_t __init name_to_dev_t(char *name)
 	res = Root_NFS;
 	if (strcmp(name, "nfs") == 0)
 		goto done;
+	res = Root_RAM0;
+	if (strcmp(name, "ram") == 0)
+		goto done;
 
 	if (strlen(name) > 31)
 		goto fail;
@@ -285,7 +290,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 +329,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-11 10:20:29.000000000 +0000
+++ source/init/do_mounts.h	2004-03-16 09:37:57.995723480 +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-11 10:20:29.000000000 +0000
+++ source/init/do_mounts_devfs.c	2004-03-16 09:37:57.996723328 +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-16 09:37:57.996723328 +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 14:46:21.000000000 +0000
+++ source/init/do_mounts_md.c	2004-03-16 09:37:57.998723024 +0000
@@ -12,15 +12,19 @@
  * 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;
+
+extern int mdp_major;
 /*
  * Parse the command-line parameters given our kernel, but do not
  * actually try to invoke the MD device now; that is handled by
@@ -43,21 +47,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 +86,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,36 +103,45 @@ 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;
 }
 
+#define MdpMinorShift 6
+
 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);
-		create_dev(name, MKDEV(MD_MAJOR, minor), devfs_name);
+		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);
+		if (partitioned)
+			dev = MKDEV(mdp_major, minor << MdpMinorShift);
+		else
+			dev = MKDEV(MD_MAJOR, minor);
+		create_dev(name, dev, devfs_name);
 		for (i = 0; i < MD_SB_DISKS && devname != 0; i++) {
 			char *p;
 			char comp_name[64];
@@ -143,34 +164,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 +204,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 +232,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 +252,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 +270,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-16 09:37:57.998723024 +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-11 10:20:29.000000000 +0000
+++ source/init/initramfs.c	2004-03-16 09:37:57.999722872 +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-11 10:20:29.000000000 +0000
+++ source/init/main.c	2004-03-16 09:37:58.000722720 +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>
@@ -42,6 +41,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>
@@ -156,8 +156,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++;
@@ -418,12 +421,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();
@@ -568,7 +571,6 @@ static void do_pre_smp_initcalls(void)
 
 	migration_init();
 #endif
-	node_nr_running_init();
 	spawn_ksoftirqd();
 }
 
@@ -599,8 +601,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();
 
 	/*
@@ -612,11 +622,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-16 09:37:58.000722720 +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-16 09:37:58.001722568 +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-11 10:20:29.000000000 +0000
+++ source/ipc/sem.c	2004-03-16 09:37:58.002722416 +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/shm.c	2004-03-11 10:20:29.000000000 +0000
+++ source/ipc/shm.c	2004-03-16 09:37:58.021719528 +0000
@@ -380,9 +380,7 @@ static void shm_get_stat(unsigned long *
 
 		if (is_file_hugepages(shp->shm_file)) {
 			struct address_space *mapping = inode->i_mapping;
-			spin_lock(&mapping->page_lock);
 			*rss += (HPAGE_SIZE/PAGE_SIZE)*mapping->nrpages;
-			spin_unlock(&mapping->page_lock);
 		} else {
 			struct shmem_inode_info *info = SHMEM_I(inode);
 			spin_lock(&info->lock);
@@ -760,6 +758,21 @@ asmlinkage long sys_shmdt(char __user *s
 	down_write(&mm->mmap_sem);
 
 	/*
+	 * This function tries to be smart and unmap shm segments that
+	 * were modified by partial mlock or munmap calls:
+	 * - It first determines the size of the shm segment that should be
+	 *   unmapped: It searches for a vma that is backed by shm and that
+	 *   started at address shmaddr. It records it's size and then unmaps
+	 *   it.
+	 * - Then it unmaps all shm vmas that started at shmaddr and that
+	 *   are within the initially determined size.
+	 * Errors from do_munmap are ignored: the function only fails if
+	 * it's called with invalid parameters or if it's called to unmap
+	 * a part of a vma. Both calls in this function are for full vmas,
+	 * the parameters are directly copied from the vma itself and always
+	 * valid - therefore do_munmap cannot fail. (famous last words?)
+	 */
+	/*
 	 * If it had been mremap()'d, the starting address would not
 	 * match the usual checks anyway. So assume all vma's are
 	 * above the starting address given.
@@ -776,10 +789,12 @@ asmlinkage long sys_shmdt(char __user *s
 		 */
 		if ((vma->vm_ops == &shm_vm_ops || is_vm_hugetlb_page(vma)) &&
 			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
-
+			int ret;
 
 			size = vma->vm_file->f_dentry->d_inode->i_size;
-			do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
+			ret = do_munmap(mm, vma->vm_start,
+					vma->vm_end - vma->vm_start);
+			WARN_ON(ret);
 			/*
 			 * We discovered the size of the shm segment, so
 			 * break out of here and fall through to the next
@@ -803,9 +818,13 @@ asmlinkage long sys_shmdt(char __user *s
 
 		/* finding a matching vma now does not alter retval */
 		if ((vma->vm_ops == &shm_vm_ops || is_vm_hugetlb_page(vma)) &&
-			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff)
+			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
+			int ret;
 
-			do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
+			ret = do_munmap(mm, vma->vm_start,
+					vma->vm_end - vma->vm_start);
+			WARN_ON(ret);
+		}
 		vma = next;
 	}
 
--- diff/ipc/util.c	2004-03-11 10:20:29.000000000 +0000
+++ source/ipc/util.c	2004-03-16 09:37:58.021719528 +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-16 09:37:58.022719376 +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-11 10:20:29.000000000 +0000
+++ source/kernel/Makefile	2004-03-16 09:37:58.022719376 +0000
@@ -12,15 +12,18 @@ 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
+obj-$(CONFIG_AUDIT) += audit.o
+obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
 
 ifneq ($(CONFIG_IA64),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
--- diff/kernel/acct.c	2004-03-11 10:20:29.000000000 +0000
+++ source/kernel/acct.c	2004-03-16 09:37:58.023719224 +0000
@@ -346,7 +346,7 @@ static void do_acct_process(long exitcod
 	/* we really need to bite the bullet and change layout */
 	ac.ac_uid = current->uid;
 	ac.ac_gid = current->gid;
-	ac.ac_tty = current->tty ? old_encode_dev(tty_devnum(current->tty)) : 0;
+	ac.ac_tty = current->signal->tty ? old_encode_dev(tty_devnum(current->signal->tty)) : 0;
 
 	ac.ac_flag = 0;
 	if (current->flags & PF_FORKNOEXEC)
--- diff/kernel/exit.c	2004-03-11 10:20:29.000000000 +0000
+++ source/kernel/exit.c	2004-03-16 09:37:58.024719072 +0000
@@ -136,13 +136,13 @@ int session_of_pgrp(int pgrp)
 
 	read_lock(&tasklist_lock);
 	for_each_task_pid(pgrp, PIDTYPE_PGID, p, l, pid)
-		if (p->session > 0) {
-			sid = p->session;
+		if (p->signal->session > 0) {
+			sid = p->signal->session;
 			goto out;
 		}
 	p = find_task_by_pid(pgrp);
 	if (p)
-		sid = p->session;
+		sid = p->signal->session;
 out:
 	read_unlock(&tasklist_lock);
 	
@@ -170,7 +170,7 @@ static int will_become_orphaned_pgrp(int
 				|| p->real_parent->pid == 1)
 			continue;
 		if (process_group(p->real_parent) != pgrp
-			    && p->real_parent->session == p->session) {
+			    && p->real_parent->signal->session == p->signal->session) {
 			ret = 0;
 			break;
 		}
@@ -259,14 +259,14 @@ void __set_special_pids(pid_t session, p
 {
 	struct task_struct *curr = current;
 
-	if (curr->session != session) {
+	if (curr->signal->session != session) {
 		detach_pid(curr, PIDTYPE_SID);
-		curr->session = session;
+		curr->signal->session = session;
 		attach_pid(curr, PIDTYPE_SID, session);
 	}
 	if (process_group(curr) != pgrp) {
 		detach_pid(curr, PIDTYPE_PGID);
-		curr->group_leader->__pgrp = pgrp;
+		curr->signal->pgrp = pgrp;
 		attach_pid(curr, PIDTYPE_PGID, pgrp);
 	}
 }
@@ -341,7 +341,7 @@ void daemonize(const char *name, ...)
 	exit_mm(current);
 
 	set_special_pids(1, 1);
-	current->tty = NULL;
+	current->signal->tty = NULL;
 
 	/* Block and flush all signals */
 	sigfillset(&blocked);
@@ -564,7 +564,7 @@ static inline void reparent_thread(task_
 	 * outside, so the child pgrp is now orphaned.
 	 */
 	if ((process_group(p) != process_group(father)) &&
-	    (p->session == father->session)) {
+	    (p->signal->session == father->signal->session)) {
 		int pgrp = process_group(p);
 
 		if (will_become_orphaned_pgrp(pgrp, NULL) && has_stopped_jobs(pgrp)) {
@@ -675,7 +675,7 @@ static void exit_notify(struct task_stru
 	t = tsk->real_parent;
 	
 	if ((process_group(t) != process_group(tsk)) &&
-	    (t->session == tsk->session) &&
+	    (t->signal->session == tsk->signal->session) &&
 	    will_become_orphaned_pgrp(process_group(tsk), tsk) &&
 	    has_stopped_jobs(process_group(tsk))) {
 		__kill_pg_info(SIGHUP, (void *)1, process_group(tsk));
@@ -780,7 +780,7 @@ asmlinkage NORET_TYPE void do_exit(long 
 	exit_itimers(tsk);
 	exit_thread();
 
-	if (tsk->leader)
+	if (tsk->signal->leader)
 		disassociate_ctty(1);
 
 	module_put(tsk->thread_info->exec_domain->module);
--- diff/kernel/fork.c	2004-03-11 10:20:29.000000000 +0000
+++ source/kernel/fork.c	2004-03-16 09:37:58.032717856 +0000
@@ -21,6 +21,7 @@
 #include <linux/completion.h>
 #include <linux/namespace.h>
 #include <linux/personality.h>
+#include <linux/sem.h>
 #include <linux/file.h>
 #include <linux/binfmts.h>
 #include <linux/mman.h>
@@ -31,6 +32,7 @@
 #include <linux/futex.h>
 #include <linux/ptrace.h>
 #include <linux/mount.h>
+#include <linux/audit.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -39,9 +41,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)
  */
@@ -85,6 +84,8 @@ void __put_task_struct(struct task_struc
 	WARN_ON(atomic_read(&tsk->usage));
 	WARN_ON(tsk == current);
 
+	if (unlikely(tsk->audit_context))
+		audit_free(tsk);
 	security_task_free(tsk);
 	free_uid(tsk->user);
 	put_group_info(tsk->group_info);
@@ -209,11 +210,14 @@ EXPORT_SYMBOL(autoremove_wake_function);
 void __init fork_init(unsigned long mempages)
 {
 #ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR
+#ifndef ARCH_MIN_TASKALIGN
+#define ARCH_MIN_TASKALIGN	0
+#endif
 	/* create a slab on which task_structs can be allocated */
 	task_struct_cachep =
 		kmem_cache_create("task_struct",
-				  sizeof(struct task_struct),0,
-				  SLAB_MUST_HWCACHE_ALIGN, NULL, NULL);
+				  sizeof(struct task_struct),ARCH_MIN_TASKALIGN,
+				  0, NULL, NULL);
 	if (!task_struct_cachep)
 		panic("fork_init(): cannot create task_struct SLAB cache");
 #endif
@@ -276,7 +280,7 @@ 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;
@@ -813,6 +817,12 @@ static inline int copy_signal(unsigned l
 	sig->curr_target = NULL;
 	init_sigpending(&sig->shared_pending);
 
+	sig->tty = current->signal->tty;
+	sig->pgrp = process_group(current);
+	sig->session = current->signal->session;
+	sig->leader = 0;	/* session leadership doesn't inherit */
+	sig->tty_old_pgrp = 0;
+
 	return 0;
 }
 
@@ -937,21 +947,22 @@ struct task_struct *copy_process(unsigne
 	init_timer(&p->real_timer);
 	p->real_timer.data = (unsigned long) p;
 
-	p->leader = 0;		/* session leadership doesn't inherit */
-	p->tty_old_pgrp = 0;
 	p->utime = p->stime = 0;
 	p->cutime = p->cstime = 0;
 	p->lock_depth = -1;		/* -1 = no lock */
 	p->start_time = get_jiffies_64();
 	p->security = NULL;
 	p->io_context = NULL;
+	p->audit_context = NULL;
 
 	retval = -ENOMEM;
 	if ((retval = security_task_alloc(p)))
 		goto bad_fork_cleanup;
+	if ((retval = audit_alloc(p)))
+		goto bad_fork_cleanup_security;
 	/* copy all the process information */
 	if ((retval = copy_semundo(clone_flags, p)))
-		goto bad_fork_cleanup_security;
+		goto bad_fork_cleanup_audit;
 	if ((retval = copy_files(clone_flags, p)))
 		goto bad_fork_cleanup_semundo;
 	if ((retval = copy_fs(clone_flags, p)))
@@ -1057,7 +1068,7 @@ struct task_struct *copy_process(unsigne
 	if (thread_group_leader(p)) {
 		attach_pid(p, PIDTYPE_TGID, p->tgid);
 		attach_pid(p, PIDTYPE_PGID, process_group(p));
-		attach_pid(p, PIDTYPE_SID, p->session);
+		attach_pid(p, PIDTYPE_SID, p->signal->session);
 		if (p->pid)
 			__get_cpu_var(process_counts)++;
 	} else
@@ -1086,6 +1097,8 @@ bad_fork_cleanup_files:
 	exit_files(p); /* blocking */
 bad_fork_cleanup_semundo:
 	exit_sem(p);
+bad_fork_cleanup_audit:
+	audit_free(p);
 bad_fork_cleanup_security:
 	security_task_free(p);
 bad_fork_cleanup:
--- diff/kernel/futex.c	2004-02-18 08:54:13.000000000 +0000
+++ source/kernel/futex.c	2004-03-16 09:37:58.033717704 +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-11 10:20:29.000000000 +0000
+++ source/kernel/kthread.c	2004-03-16 09:37:58.033717704 +0000
@@ -10,6 +10,7 @@
 #include <linux/completion.h>
 #include <linux/err.h>
 #include <linux/unistd.h>
+#include <linux/file.h>
 #include <asm/semaphore.h>
 
 struct kthread_create_info
@@ -41,6 +42,21 @@ int kthread_should_stop(void)
 	return (kthread_stop_info.k == current);
 }
 
+
+static void kthread_exit_files(void)
+{
+	struct fs_struct *fs;
+	struct task_struct *tsk = current;
+
+	exit_fs(tsk);		/* current->fs->count--; */
+	fs = init_task.fs;
+	tsk->fs = fs;
+	atomic_inc(&fs->count);
+ 	exit_files(tsk);
+	current->files = init_task.files;
+	atomic_inc(&tsk->files->count);
+}
+
 static int kthread(void *_create)
 {
 	struct kthread_create_info *create = _create;
@@ -50,6 +66,8 @@ static int kthread(void *_create)
 	int ret = -EINTR;
 	cpumask_t mask = CPU_MASK_ALL;
 
+	kthread_exit_files();
+
 	/* Copy data: it's on keventd's stack */
 	threadfn = create->threadfn;
 	data = create->data;
@@ -91,7 +109,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 +148,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-11 10:20:29.000000000 +0000
+++ source/kernel/module.c	2004-03-16 09:37:58.035717400 +0000
@@ -596,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:
@@ -1241,7 +1243,15 @@ static void add_kallsyms(struct module *
 		mod->symtab[i].st_info
 			= elf_type(&mod->symtab[i], sechdrs, secstrings, mod);
 }
-#endif
+#else
+static inline void add_kallsyms(struct module *mod,
+				Elf_Shdr *sechdrs,
+				unsigned int symindex,
+				unsigned int strindex,
+				const char *secstrings)
+{
+}
+#endif /* CONFIG_KALLSYMS */
 
 /* Allocate and load the module: note that size of section 0 is always
    zero, and we rely on this for optional sections. */
@@ -1514,14 +1524,12 @@ static struct module *load_module(void _
 	percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr,
 		       sechdrs[pcpuindex].sh_size);
 
+	add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);
+
 	err = module_finalize(hdr, sechdrs, mod);
 	if (err < 0)
 		goto cleanup;
 
-#ifdef CONFIG_KALLSYMS
-	add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);
-#endif
-
 	mod->args = args;
 	if (obsparmindex) {
 		err = obsolete_params(mod->name, mod->args,
--- diff/kernel/pid.c	2004-03-11 10:20:29.000000000 +0000
+++ source/kernel/pid.c	2004-03-16 09:37:58.035717400 +0000
@@ -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)
@@ -253,14 +255,14 @@ void switch_exec_pids(task_t *leader, ta
 
 	attach_pid(thread, PIDTYPE_PID, thread->pid);
 	attach_pid(thread, PIDTYPE_TGID, thread->tgid);
-	attach_pid(thread, PIDTYPE_PGID, leader->__pgrp);
-	attach_pid(thread, PIDTYPE_SID, thread->session);
+	attach_pid(thread, PIDTYPE_PGID, thread->signal->pgrp);
+	attach_pid(thread, PIDTYPE_SID, thread->signal->session);
 	list_add_tail(&thread->tasks, &init_task.tasks);
 
 	attach_pid(leader, PIDTYPE_PID, leader->pid);
 	attach_pid(leader, PIDTYPE_TGID, leader->tgid);
-	attach_pid(leader, PIDTYPE_PGID, leader->__pgrp);
-	attach_pid(leader, PIDTYPE_SID, leader->session);
+	attach_pid(leader, PIDTYPE_PGID, leader->signal->pgrp);
+	attach_pid(leader, PIDTYPE_SID, leader->signal->session);
 }
 
 /*
@@ -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/power/disk.c	2004-03-11 10:20:29.000000000 +0000
+++ source/kernel/power/disk.c	2004-03-16 09:37:58.036717248 +0000
@@ -84,7 +84,6 @@ static void free_some_memory(void)
 	while (shrink_all_memory(10000))
 		printk(".");
 	printk("|\n");
-	blk_run_queues();
 }
 
 
--- diff/kernel/power/pmdisk.c	2004-03-11 10:20:29.000000000 +0000
+++ source/kernel/power/pmdisk.c	2004-03-16 09:37:58.037717096 +0000
@@ -859,7 +859,6 @@ static int end_io(struct bio * bio, unsi
 
 static void wait_io(void)
 {
-	blk_run_queues();
 	while(atomic_read(&io_done))
 		io_schedule();
 }
@@ -898,7 +897,7 @@ static int submit(int rw, pgoff_t page_o
 	if (rw == WRITE)
 		bio_set_pages_dirty(bio);
 	start_io();
-	submit_bio(rw,bio);
+	submit_bio(rw|BIO_RW_SYNC,bio);
 	wait_io();
  Done:
 	bio_put(bio);
--- diff/kernel/power/swsusp.c	2004-03-11 10:20:29.000000000 +0000
+++ source/kernel/power/swsusp.c	2004-03-16 09:37:58.037717096 +0000
@@ -707,11 +707,6 @@ int software_suspend(void)
 
 		free_some_memory();
 		
-		/* No need to invalidate any vfsmnt list -- 
-		 * they will be valid after resume, anyway.
-		 */
-		blk_run_queues();
-
 		/* Save state of all device drivers, and stop them. */		   
 		if ((res = device_suspend(4))==0)
 			/* If stopping device drivers worked, we proceed basically into
--- diff/kernel/sched.c	2004-03-11 10:20:29.000000000 +0000
+++ source/kernel/sched.c	2004-03-16 09:37:58.042716336 +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>
@@ -91,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
 
 /*
@@ -187,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,24 +201,39 @@ struct prio_array {
  */
 struct runqueue {
 	spinlock_t lock;
-	unsigned long nr_running, nr_switches, expired_timestamp,
-		      nr_uninterruptible, timestamp_last_tick;
+
+	/*
+	 * nr_running and cpu_load should be in the same cacheline because
+	 * remote CPUs use both these fields when doing load calculation.
+	 */
+	unsigned long nr_running;
+#ifdef CONFIG_SMP
+	unsigned long cpu_load;
+#endif
+	unsigned long long nr_switches;
+	unsigned long expired_timestamp, 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];
-#endif
+	int best_expired_prio;
+	atomic_t nr_iowait;
+
+	/* 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))
@@ -233,51 +248,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
@@ -545,37 +525,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;
 }
@@ -636,7 +609,63 @@ void kick_process(task_t *p)
 }
 
 EXPORT_SYMBOL_GPL(kick_process);
+/*
+ * Return a low guess at the load of cpu.
+ */
+static inline unsigned long get_low_cpu_load(int cpu)
+{
+	runqueue_t *rq = cpu_rq(cpu);
+	unsigned long load_now = rq->nr_running << SCHED_LOAD_SHIFT;
+
+	return min(rq->cpu_load, load_now);
+}
+
+static inline unsigned long get_high_cpu_load(int cpu)
+{
+	runqueue_t *rq = cpu_rq(cpu);
+	unsigned long load_now = rq->nr_running << SCHED_LOAD_SHIFT;
+
+	return max(rq->cpu_load, load_now);
+}
+
+#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
 
 /***
@@ -659,44 +688,113 @@ 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;
+#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)))
+		goto out_activate;
+
+	/* Passive load balancing */
+	load = get_low_cpu_load(cpu);
+	this_load = get_high_cpu_load(this_cpu) + 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;
+	}
+
+	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;
+	}
+	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);
+	}
+	goto out_activate;
+
+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;
@@ -755,8 +853,8 @@ void fastcall 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;
@@ -872,7 +970,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);
@@ -934,7 +1032,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;
@@ -950,9 +1048,9 @@ unsigned long nr_uninterruptible(void)
 	return sum;
 }
 
-unsigned long nr_context_switches(void)
+unsigned long long nr_context_switches(void)
 {
-	unsigned long i, sum = 0;
+	unsigned long long i, sum = 0;
 
 	for_each_cpu(i)
 		sum += cpu_rq(i)->nr_switches;
@@ -1004,6 +1102,14 @@ 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.
@@ -1016,28 +1122,26 @@ static void sched_migrate_task(task_t *p
 	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))
+	if (!cpu_isset(dest_cpu, p->cpus_allowed))
 		goto out;
 
 	/* force the process onto the specified CPU */
-	if (__set_cpus_allowed(p, new_mask, &req)) {
+	if (migrate_task(p, 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);
@@ -1047,215 +1151,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);
+		else
+			load = get_high_cpu_load(i) + 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)
+			sched_migrate_task(current, 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);
 	/*
@@ -1263,69 +1233,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: */
@@ -1338,9 +1310,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;
@@ -1350,104 +1323,468 @@ 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;
+	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;
+
+	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);
+			} else
+				load = get_low_cpu_load(i);
+
+			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;
+}
+
+/*
+ * 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);
+
+		if (load >= max_load) {
+			max_load = load;
+			busiest = cpu_rq(i);
+		}
+	}
+
+	return busiest;
 }
 
 /*
- * 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.
+ * 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);
-	}
+	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 old_load, this_load;
+	unsigned long j = jiffies + CPU_OFFSET(this_cpu);
+	struct sched_domain *domain = this_sched_domain();
+
+	/* Update our load */
+	old_load = this_rq->cpu_load;
+	this_load = this_rq->nr_running << SCHED_LOAD_SHIFT;
+	this_rq->cpu_load = (old_load + this_load) / 2;
+
+	/* 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);
@@ -1501,7 +1838,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)
@@ -1585,9 +1924,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(int cpu, runqueue_t *rq)
+{
+	int i;
+	struct sched_domain *sd = cpu_sched_domain(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(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(int cpu, runqueue_t *rq, task_t *p)
+{
+	int ret = 0, i;
+	struct sched_domain *sd = cpu_sched_domain(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(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(int cpu, runqueue_t *rq)
+{
+}
+
+static inline int dependent_sleeper(int cpu, runqueue_t *rq, task_t *p)
+{
+	return 0;
+}
+#endif
+
 void scheduling_functions_start_here(void) { }
 
 /*
@@ -1602,7 +2026,7 @@ asmlinkage void schedule(void)
 	struct list_head *queue;
 	unsigned long long now;
 	unsigned long run_time;
-	int idx;
+	int cpu, idx;
 
 	/*
 	 * Test if we are atomic.  Since do_exit() needs to call into
@@ -1652,13 +2076,15 @@ need_resched:
 			deactivate_task(prev, rq);
 	}
 
+	cpu = smp_processor_id();
 	if (unlikely(!rq->nr_running)) {
 #ifdef CONFIG_SMP
-		load_balance(rq, 1, cpu_to_node_mask(smp_processor_id()));
+		idle_balance(cpu, rq);
 #endif
 		if (!rq->nr_running) {
 			next = rq->idle;
 			rq->expired_timestamp = 0;
+			wake_sleeping_dependent(cpu, rq);
 			goto switch_tasks;
 		}
 	}
@@ -1679,6 +2105,11 @@ need_resched:
 	queue = array->queue + idx;
 	next = list_entry(queue->next, task_t, run_list);
 
+	if (dependent_sleeper(cpu, rq, next)) {
+		next = rq->idle;
+		goto switch_tasks;
+	}
+
 	if (next->activated > 0) {
 		unsigned long long delta = now - next->timestamp;
 
@@ -2015,6 +2446,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__
 
 /*
@@ -2713,7 +3151,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);
@@ -2727,8 +3170,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;
@@ -2737,14 +3188,18 @@ 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;
 
 	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;
@@ -2781,7 +3236,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);
@@ -2792,8 +3253,7 @@ 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;
@@ -2860,6 +3320,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;
@@ -2867,6 +3531,11 @@ 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->active = rq->arrays;
@@ -2876,7 +3545,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-11 10:20:29.000000000 +0000
+++ source/kernel/signal.c	2004-03-16 09:37:58.044716032 +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>
@@ -588,7 +589,8 @@ static int check_kill_permission(int sig
 	error = -EPERM;
 	if ((!info || ((unsigned long)info != 1 &&
 			(unsigned long)info != 2 && SI_FROMUSER(info)))
-	    && ((sig != SIGCONT) || (current->session != t->session))
+	    && ((sig != SIGCONT) ||
+		(current->signal->session != t->signal->session))
 	    && (current->euid ^ t->suid) && (current->euid ^ t->uid)
 	    && (current->uid ^ t->suid) && (current->uid ^ t->uid)
 	    && !capable(CAP_KILL))
@@ -1051,17 +1053,23 @@ int __kill_pg_info(int sig, struct sigin
 	struct task_struct *p;
 	struct list_head *l;
 	struct pid *pid;
-	int err, retval = -ESRCH;
+	int retval;
+	int found;
 
 	if (pgrp <= 0)
 		return -EINVAL;
 
+	found = 0;
+	retval = 0;
 	for_each_task_pid(pgrp, PIDTYPE_PGID, p, l, pid) {
+		int err;
+
+		found = 1;
 		err = group_send_sig_info(sig, info, p);
-		if (retval)
+		if (!retval)
 			retval = err;
 	}
-	return retval;
+	return found ? retval : -ESRCH;
 }
 
 int
@@ -1097,7 +1105,7 @@ kill_sl_info(int sig, struct siginfo *in
 	retval = -ESRCH;
 	read_lock(&tasklist_lock);
 	for_each_task_pid(sid, PIDTYPE_SID, p, l, pid) {
-		if (!p->leader)
+		if (!p->signal->leader)
 			continue;
 		err = group_send_sig_info(sig, info, p);
 		if (retval)
@@ -2003,6 +2011,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 +2055,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-11 10:20:29.000000000 +0000
+++ source/kernel/softirq.c	2004-03-16 09:37:58.045715880 +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);
--- diff/kernel/sys.c	2004-03-11 10:20:29.000000000 +0000
+++ source/kernel/sys.c	2004-03-16 09:37:58.046715728 +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)
@@ -979,7 +985,7 @@ asmlinkage long sys_setpgid(pid_t pid, p
 
 	if (p->parent == current || p->real_parent == current) {
 		err = -EPERM;
-		if (p->session != current->session)
+		if (p->signal->session != current->signal->session)
 			goto out;
 		err = -EACCES;
 		if (p->did_exec)
@@ -991,7 +997,7 @@ asmlinkage long sys_setpgid(pid_t pid, p
 	}
 
 	err = -EPERM;
-	if (p->leader)
+	if (p->signal->leader)
 		goto out;
 
 	if (pgid != pid) {
@@ -1000,7 +1006,7 @@ asmlinkage long sys_setpgid(pid_t pid, p
 		struct list_head *l;
 
 		for_each_task_pid(pgid, PIDTYPE_PGID, p, l, pid)
-			if (p->session == current->session)
+			if (p->signal->session == current->signal->session)
 				goto ok_pgid;
 		goto out;
 	}
@@ -1012,7 +1018,7 @@ ok_pgid:
 
 	if (process_group(p) != pgid) {
 		detach_pid(p, PIDTYPE_PGID);
-		p->group_leader->__pgrp = pgid;
+		p->signal->pgrp = pgid;
 		attach_pid(p, PIDTYPE_PGID, pgid);
 	}
 
@@ -1054,7 +1060,7 @@ asmlinkage long sys_getpgrp(void)
 asmlinkage long sys_getsid(pid_t pid)
 {
 	if (!pid) {
-		return current->session;
+		return current->signal->session;
 	} else {
 		int retval;
 		struct task_struct *p;
@@ -1066,7 +1072,7 @@ asmlinkage long sys_getsid(pid_t pid)
 		if(p) {
 			retval = security_task_getsid(p);
 			if (!retval)
-				retval = p->session;
+				retval = p->signal->session;
 		}
 		read_unlock(&tasklist_lock);
 		return retval;
@@ -1087,10 +1093,10 @@ asmlinkage long sys_setsid(void)
 	if (pid)
 		goto out;
 
-	current->leader = 1;
+	current->signal->leader = 1;
 	__set_special_pids(current->pid, current->pid);
-	current->tty = NULL;
-	current->tty_old_pgrp = 0;
+	current->signal->tty = NULL;
+	current->signal->tty_old_pgrp = 0;
 	err = process_group(current);
 out:
 	write_unlock_irq(&tasklist_lock);
--- diff/kernel/sysctl.c	2004-03-11 10:20:29.000000000 +0000
+++ source/kernel/sysctl.c	2004-03-16 09:37:58.047715576 +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-11 10:20:29.000000000 +0000
+++ source/kernel/timer.c	2004-03-16 09:37:58.049715272 +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
@@ -1037,7 +1043,10 @@ fastcall signed long schedule_timeout(si
 	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();
--- diff/kernel/workqueue.c	2004-03-11 10:20:29.000000000 +0000
+++ source/kernel/workqueue.c	2004-03-16 09:37:58.050715120 +0000
@@ -47,6 +47,7 @@ struct cpu_workqueue_struct {
 	struct workqueue_struct *wq;
 	task_t *thread;
 
+	int run_depth;		/* Detect run_workqueue() recursion depth */
 } ____cacheline_aligned;
 
 /*
@@ -78,18 +79,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 fastcall 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)
 {
@@ -129,6 +141,13 @@ static inline void run_workqueue(struct 
 	 * done.
 	 */
 	spin_lock_irqsave(&cwq->lock, flags);
+	cwq->run_depth++;
+	if (cwq->run_depth > 3) {
+		/* morton gets to eat his hat */
+		printk("%s: recursion depth exceeded: %d\n",
+			__FUNCTION__, cwq->run_depth);
+		dump_stack();
+	}
 	while (!list_empty(&cwq->worklist)) {
 		struct work_struct *work = list_entry(cwq->worklist.next,
 						struct work_struct, entry);
@@ -146,6 +165,7 @@ static inline void run_workqueue(struct 
 		cwq->remove_sequence++;
 		wake_up(&cwq->work_done);
 	}
+	cwq->run_depth--;
 	spin_unlock_irqrestore(&cwq->lock, flags);
 }
 
@@ -218,6 +238,14 @@ void fastcall flush_workqueue(struct wor
 			continue;
 		cwq = wq->cpu_wq + cpu;
 
+		if (cwq->thread == current) {
+			/*
+			 * Probably keventd trying to flush its own queue.
+			 * So simply run it by hand rather than deadlocking.
+			 */
+			run_workqueue(cwq);
+			continue;
+		}
 		spin_lock_irq(&cwq->lock);
 		sequence_needed = cwq->insert_sequence;
 
@@ -267,6 +295,7 @@ struct workqueue_struct *create_workqueu
 	wq = kmalloc(sizeof(*wq), GFP_KERNEL);
 	if (!wq)
 		return NULL;
+	memset(wq, 0, sizeof(*wq));
 
 	for (cpu = 0; cpu < NR_CPUS; cpu++) {
 		if (!cpu_online(cpu))
@@ -333,16 +362,17 @@ int keventd_up(void)
 int current_is_keventd(void)
 {
 	struct cpu_workqueue_struct *cwq;
-	int cpu;
+	int cpu = smp_processor_id();	/* preempt-safe: keventd is per-cpu */
+	int ret = 0;
 
 	BUG_ON(!keventd_wq);
 
-	for_each_cpu(cpu) {
-		cwq = keventd_wq->cpu_wq + cpu;
-		if (current == cwq->thread)
-			return 1;
-	}
-	return 0;
+	cwq = keventd_wq->cpu_wq + cpu;
+	if (current == cwq->thread)
+		ret = 1;
+
+	return ret;
+
 }
 
 void init_workqueues(void)
@@ -352,7 +382,6 @@ void init_workqueues(void)
 }
 
 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/idr.c	2004-03-11 10:20:29.000000000 +0000
+++ source/lib/idr.c	2004-03-16 09:37:58.051714968 +0000
@@ -109,7 +109,7 @@ static kmem_cache_t *idr_layer_cache;
 
 
 
-static inline struct idr_layer *alloc_layer(struct idr *idp)
+static struct idr_layer *alloc_layer(struct idr *idp)
 {
 	struct idr_layer *p;
 
@@ -123,7 +123,7 @@ static inline struct idr_layer *alloc_la
 	return(p);
 }
 
-static inline void free_layer(struct idr *idp, struct idr_layer *p)
+static void free_layer(struct idr *idp, struct idr_layer *p)
 {
 	/*
 	 * Depends on the return element being zeroed.
@@ -137,7 +137,7 @@ static inline void free_layer(struct idr
 
 int idr_pre_get(struct idr *idp, unsigned gfp_mask)
 {
-	while (idp->id_free_cnt < idp->layers + 1) {
+	while (idp->id_free_cnt < IDR_FREE_MAX) {
 		struct idr_layer *new;
 		new = kmem_cache_alloc(idr_layer_cache, gfp_mask);
 		if(new == NULL)
@@ -148,91 +148,125 @@ int idr_pre_get(struct idr *idp, unsigne
 }
 EXPORT_SYMBOL(idr_pre_get);
 
-static inline int sub_alloc(struct idr *idp, int shift, void *ptr)
+static int sub_alloc(struct idr *idp, void *ptr, int *starting_id)
 {
-	int n, v = 0;
-	struct idr_layer *p;
-	struct idr_layer **pa[MAX_LEVEL];
-	struct idr_layer ***paa = &pa[0];
-	
-	*paa = NULL;
-	*++paa = &idp->top;
+	int n, m, sh;
+	struct idr_layer *p, *new;
+	struct idr_layer *pa[MAX_LEVEL];
+	int l, id;
+	long bm;
 
-	/*
-	 * By keeping each pointer in an array we can do the 
-	 * "after" recursion processing.  In this case, that means
-	 * we can update the upper level bit map.
-	 */
-	
-	while (1){
-		p = **paa;
-		n = ffz(p->bitmap);
-		if (shift){
-			/*
-			 * We run around this while until we
-			 * reach the leaf node...
-			 */
-			if (!p->ary[n]){
-				/*
-				 * If no node, allocate one, AFTER
-				 * we insure that we will not
-				 * intrude on the reserved bit field.
-				 */
-				if ((n << shift) >= MAX_ID_BIT)
-					return -1;
-				p->ary[n] = alloc_layer(idp);
-				p->count++;
+	id = *starting_id;
+	p = idp->top;
+	l = idp->layers;
+	pa[l--] = NULL;
+	while (1) {
+		/*
+		 * We run around this while until we reach the leaf node...
+		 */
+		n = (id >> (IDR_BITS*l)) & IDR_MASK;
+		bm = ~p->bitmap;
+		m = find_next_bit(&bm, IDR_SIZE, n);
+		if (m == IDR_SIZE) {
+			/* no space available go back to previous layer. */
+			l++;
+			id = (id | ((1 << (IDR_BITS*l))-1)) + 1;
+			if (!(p = pa[l])) {
+				*starting_id = id;
+				return -2;
 			}
-			*++paa = &p->ary[n];
-			v += (n << shift);
-			shift -= IDR_BITS;
-		} else {
-			/*
-			 * We have reached the leaf node, plant the
-			 * users pointer and return the raw id.
-			 */
-			p->ary[n] = (struct idr_layer *)ptr;
-			__set_bit(n, &p->bitmap);
-			v += n;
+			continue;
+		}
+		if (m != n) {
+			sh = IDR_BITS*l;
+			id = ((id >> sh) ^ n ^ m) << sh;
+		}
+		if (id >= MAX_ID_BIT)
+			return -1;
+		if (l == 0)
+			break;
+		/*
+		 * Create the layer below if it is missing.
+		 */
+		if (!p->ary[m]) {
+			if (!(new = alloc_layer(idp)))
+				return -1;
+			p->ary[m] = new;
 			p->count++;
-			/*
-			 * This is the post recursion processing.  Once
-			 * we find a bitmap that is not full we are
-			 * done
-			 */
-			while (*(paa-1) && (**paa)->bitmap == IDR_FULL){
-				n = *paa - &(**(paa-1))->ary[0];
-				__set_bit(n, &(**--paa)->bitmap);
-			}
-			return(v);
 		}
+		pa[l--] = p;
+		p = p->ary[m];
+	}
+	/*
+	 * We have reached the leaf node, plant the
+	 * users pointer and return the raw id.
+	 */
+	p->ary[m] = (struct idr_layer *)ptr;
+	__set_bit(m, &p->bitmap);
+	p->count++;
+	/*
+	 * If this layer is full mark the bit in the layer above
+	 * to show that this part of the radix tree is full.
+	 * This may complete the layer above and require walking
+	 * up the radix tree.
+	 */
+	n = id;
+	while (p->bitmap == IDR_FULL) {
+		if (!(p = pa[++l]))
+			break;
+		n = n >> IDR_BITS;
+		__set_bit((n & IDR_MASK), &p->bitmap);
 	}
+	return(id);
 }
 
-int idr_get_new(struct idr *idp, void *ptr)
+int idr_get_new_above(struct idr *idp, void *ptr, int starting_id)
 {
-	int v;
+	struct idr_layer *p, *new;
+	int layers, v, id;
 	
-	if (idp->id_free_cnt < idp->layers + 1) 
-		return (-1);
+	id = starting_id;
+build_up:
+	p = idp->top;
+	layers = idp->layers;
+	if (unlikely(!p)) {
+		if (!(p = alloc_layer(idp)))
+			return -1;
+		layers = 1;
+	}
 	/*
-	 * Add a new layer if the array is full 
+	 * Add a new layer to the top of the tree if the requested
+	 * id is larger than the currently allocated space.
 	 */
-	if (unlikely(!idp->top || idp->top->bitmap == IDR_FULL)){
-		/*
-		 * This is a bit different than the lower layers because
-		 * we have one branch already allocated and full.
-		 */
-		struct idr_layer *new = alloc_layer(idp);
-		new->ary[0] = idp->top;
-		if ( idp->top)
-			++new->count;
-		idp->top = new;
-		if ( idp->layers++ )
+	while (id >= (1 << (layers*IDR_BITS))) {
+		layers++;
+		if (!p->count)
+			continue;
+		if (!(new = alloc_layer(idp))) {
+			/*
+			 * The allocation failed.  If we built part of
+			 * the structure tear it down.
+			 */
+			for (new = p; p && p != idp->top; new = p) {
+				p = p->ary[0];
+				new->ary[0] = 0;
+				new->bitmap = new->count = 0;
+				free_layer(idp, new);
+			}
+			return -1;
+		}
+		new->ary[0] = p;
+		new->count = 1;
+		if (p->bitmap == IDR_FULL)
 			__set_bit(0, &new->bitmap);
+		p = new;
 	}
-	v = sub_alloc(idp,  (idp->layers - 1) * IDR_BITS, ptr);
-	if ( likely(v >= 0 )){
+	idp->top = p;
+	idp->layers = layers;
+	v = sub_alloc(idp, ptr, &id);
+	if (v == -2)
+		goto build_up;
+	if ( likely(v >= 0 )) {
 		idp->count++;
 		v += (idp->count << MAX_ID_SHIFT);
 		if ( unlikely( v == -1 ))
@@ -240,10 +274,16 @@ int idr_get_new(struct idr *idp, void *p
 	}
 	return(v);
 }
+EXPORT_SYMBOL(idr_get_new_above);
+
+int idr_get_new(struct idr *idp, void *ptr)
+{
+	return idr_get_new_above(idp, ptr, 0);
+}
 EXPORT_SYMBOL(idr_get_new);
 
 
-static inline void sub_remove(struct idr *idp, int shift, int id)
+static void sub_remove(struct idr *idp, int shift, int id)
 {
 	struct idr_layer *p = idp->top;
 	struct idr_layer **pa[MAX_LEVEL];
--- diff/lib/radix-tree.c	2003-05-21 10:50:10.000000000 +0000
+++ source/lib/radix-tree.c	2004-03-16 09:37:58.053714664 +0000
@@ -6,12 +6,12 @@
  * 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.
@@ -26,21 +26,36 @@
 #include <linux/slab.h>
 #include <linux/gfp.h>
 #include <linux/string.h>
+#include <linux/bitops.h>
 
 /*
  * Radix tree node definition.
+ *
+ * RADIX_TREE_MAP_SHIFT must be >= log2(BITS_PER_LONG).  Otherwise the tags
+ * array will have zero size and the set_tag() arithmetic will go wrong.
  */
-#define RADIX_TREE_MAP_SHIFT  6
-#define RADIX_TREE_MAP_SIZE  (1UL << RADIX_TREE_MAP_SHIFT)
-#define RADIX_TREE_MAP_MASK  (RADIX_TREE_MAP_SIZE-1)
+#ifdef __KERNEL__
+#define RADIX_TREE_MAP_SHIFT	6
+#else
+#define RADIX_TREE_MAP_SHIFT	3	/* For more stressful testing */
+#endif
+#define RADIX_TREE_TAGS		2
+
+#define RADIX_TREE_MAP_SIZE	(1UL << RADIX_TREE_MAP_SHIFT)
+#define RADIX_TREE_MAP_MASK	(RADIX_TREE_MAP_SIZE-1)
+
+#define RADIX_TREE_TAG_LONGS	\
+	((RADIX_TREE_MAP_SIZE + BITS_PER_LONG - 1) / BITS_PER_LONG)
 
 struct radix_tree_node {
 	unsigned int	count;
 	void		*slots[RADIX_TREE_MAP_SIZE];
+	unsigned long	tags[RADIX_TREE_TAGS][RADIX_TREE_TAG_LONGS];
 };
 
 struct radix_tree_path {
 	struct radix_tree_node *node, **slot;
+	int offset;
 };
 
 #define RADIX_TREE_INDEX_BITS  (8 /* CHAR_BIT */ * sizeof(unsigned long))
@@ -122,6 +137,22 @@ out:
 	return ret;
 }
 
+static inline void tag_set(struct radix_tree_node *node, int tag, int offset)
+{
+	if (!test_bit(offset, &node->tags[tag][0]))
+		__set_bit(offset, &node->tags[tag][0]);
+}
+
+static inline void tag_clear(struct radix_tree_node *node, int tag, int offset)
+{
+	__clear_bit(offset, &node->tags[tag][0]);
+}
+
+static inline int tag_get(struct radix_tree_node *node, int tag, int offset)
+{
+	return test_bit(offset, &node->tags[tag][0]);
+}
+
 /*
  *	Return the maximum key which can be store into a
  *	radix tree with height HEIGHT.
@@ -138,26 +169,53 @@ static int radix_tree_extend(struct radi
 {
 	struct radix_tree_node *node;
 	unsigned int height;
+	char tags[RADIX_TREE_TAGS];
+	int tag;
 
 	/* Figure out what the height should be.  */
 	height = root->height + 1;
 	while (index > radix_tree_maxindex(height))
 		height++;
 
-	if (root->rnode) {
-		do {
-			if (!(node = radix_tree_node_alloc(root)))
-				return -ENOMEM;
-
-			/* Increase the height.  */
-			node->slots[0] = root->rnode;
-			node->count = 1;
-			root->rnode = node;
-			root->height++;
-		} while (height > root->height);
-	} else 
+	if (root->rnode == NULL) {
 		root->height = height;
+		goto out;
+	}
 
+	/*
+	 * Prepare the tag status of the top-level node for propagation
+	 * into the newly-pushed top-level node(s)
+	 */
+	for (tag = 0; tag < RADIX_TREE_TAGS; tag++) {
+		int idx;
+
+		tags[tag] = 0;
+		for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
+			if (root->rnode->tags[tag][idx]) {
+				tags[tag] = 1;
+				break;
+			}
+		}
+	}
+
+	do {
+		if (!(node = radix_tree_node_alloc(root)))
+			return -ENOMEM;
+
+		/* Increase the height.  */
+		node->slots[0] = root->rnode;
+
+		/* Propagate the aggregated tag info into the new root */
+		for (tag = 0; tag < RADIX_TREE_TAGS; tag++) {
+			if (tags[tag])
+				tag_set(node, tag, 0);
+		}
+
+		node->count = 1;
+		root->rnode = node;
+		root->height++;
+	} while (height > root->height);
+out:
 	return 0;
 }
 
@@ -169,23 +227,27 @@ static int radix_tree_extend(struct radi
  *
  *	Insert an item into the radix tree at position @index.
  */
-int radix_tree_insert(struct radix_tree_root *root, unsigned long index, void *item)
+int radix_tree_insert(struct radix_tree_root *root,
+			unsigned long index, void *item)
 {
 	struct radix_tree_node *node = NULL, *tmp, **slot;
 	unsigned int height, shift;
+	int offset;
 	int error;
 
 	/* Make sure the tree is high enough.  */
-	if (index > radix_tree_maxindex(root->height)) {
+	if ((!index && !root->rnode) ||
+			index > radix_tree_maxindex(root->height)) {
 		error = radix_tree_extend(root, index);
 		if (error)
 			return error;
 	}
-    
+
 	slot = &root->rnode;
 	height = root->height;
 	shift = (height-1) * RADIX_TREE_MAP_SHIFT;
 
+	offset = 0;			/* uninitialised var warning */
 	while (height > 0) {
 		if (*slot == NULL) {
 			/* Have to add a child node.  */
@@ -196,18 +258,21 @@ int radix_tree_insert(struct radix_tree_
 				node->count++;
 		}
 
-		/* Go a level down.  */
+		/* Go a level down */
+		offset = (index >> shift) & RADIX_TREE_MAP_MASK;
 		node = *slot;
-		slot = (struct radix_tree_node **)
-			(node->slots + ((index >> shift) & RADIX_TREE_MAP_MASK));
+		slot = (struct radix_tree_node **)(node->slots + offset);
 		shift -= RADIX_TREE_MAP_SHIFT;
 		height--;
 	}
 
 	if (*slot != NULL)
 		return -EEXIST;
-	if (node)
+	if (node) {
 		node->count++;
+		BUG_ON(tag_get(node, 0, offset));
+		BUG_ON(tag_get(node, 1, offset));
+	}
 
 	*slot = item;
 	return 0;
@@ -219,7 +284,7 @@ EXPORT_SYMBOL(radix_tree_insert);
  *	@root:		radix tree root
  *	@index:		index key
  *
- *	Lookup them item at the position @index in the radix tree @root.
+ *	Lookup the item at the position @index in the radix tree @root.
  */
 void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index)
 {
@@ -238,16 +303,174 @@ void *radix_tree_lookup(struct radix_tre
 			return NULL;
 
 		slot = (struct radix_tree_node **)
-			((*slot)->slots + ((index >> shift) & RADIX_TREE_MAP_MASK));
+			((*slot)->slots +
+				((index >> shift) & RADIX_TREE_MAP_MASK));
 		shift -= RADIX_TREE_MAP_SHIFT;
 		height--;
 	}
 
-	return (void *) *slot;
+	return *slot;
 }
 EXPORT_SYMBOL(radix_tree_lookup);
 
-static /* inline */ unsigned int
+/**
+ *	radix_tree_tag_set - set a tag on a radix tree node
+ *	@root:		radix tree root
+ *	@index:		index key
+ *	@tag: 		tag index
+ *
+ *	Set the search tag corresponging to @index in the radix tree.  From
+ *	the root all the way down to the leaf node.
+ *
+ *	Returns the address of the tagged item.   Setting a tag on a not-present
+ *	item is a bug.
+ */
+void *radix_tree_tag_set(struct radix_tree_root *root,
+			unsigned long index, int tag)
+{
+	unsigned int height, shift;
+	struct radix_tree_node **slot;
+
+	height = root->height;
+	if (index > radix_tree_maxindex(height))
+		return NULL;
+
+	shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
+	slot = &root->rnode;
+
+	while (height > 0) {
+		int offset;
+
+		offset = (index >> shift) & RADIX_TREE_MAP_MASK;
+		tag_set(*slot, tag, offset);
+		slot = (struct radix_tree_node **)((*slot)->slots + offset);
+		BUG_ON(*slot == NULL);
+		shift -= RADIX_TREE_MAP_SHIFT;
+		height--;
+	}
+
+	return *slot;
+}
+EXPORT_SYMBOL(radix_tree_tag_set);
+
+/**
+ *	radix_tree_tag_clear - clear a tag on a radix tree node
+ *	@root:		radix tree root
+ *	@index:		index key
+ *	@tag: 		tag index
+ *
+ *	Clear the search tag corresponging to @index in the radix tree.  If
+ *	this causes the leaf node to have no tags set then clear the tag in the
+ *	next-to-leaf node, etc.
+ *
+ *	Returns the address of the tagged item on success, else NULL.  ie:
+ *	has the same return value and semantics as radix_tree_lookup().
+ */
+void *radix_tree_tag_clear(struct radix_tree_root *root,
+			unsigned long index, int tag)
+{
+	struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
+	unsigned int height, shift;
+	void *ret = NULL;
+
+	height = root->height;
+	if (index > radix_tree_maxindex(height))
+		goto out;
+
+	shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
+	pathp->node = NULL;
+	pathp->slot = &root->rnode;
+
+	while (height > 0) {
+		int offset;
+
+		if (*pathp->slot == NULL)
+			goto out;
+
+		offset = (index >> shift) & RADIX_TREE_MAP_MASK;
+		pathp[1].offset = offset;
+		pathp[1].node = *pathp[0].slot;
+		pathp[1].slot = (struct radix_tree_node **)
+				(pathp[1].node->slots + offset);
+		pathp++;
+		shift -= RADIX_TREE_MAP_SHIFT;
+		height--;
+	}
+
+	ret = *pathp[0].slot;
+	if (ret == NULL)
+		goto out;
+
+	do {
+		int idx;
+
+		tag_clear(pathp[0].node, tag, pathp[0].offset);
+		for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
+			if (pathp[0].node->tags[tag][idx])
+				goto out;
+		}
+		pathp--;
+	} while (pathp[0].node);
+out:
+	return ret;
+}
+EXPORT_SYMBOL(radix_tree_tag_clear);
+
+#ifndef __KERNEL__	/* Only the test harness uses this at present */
+/**
+ *	radix_tree_tag_get - get a tag on a radix tree node
+ *	@root:		radix tree root
+ *	@index:		index key
+ *	@tag: 		tag index
+ *
+ *	Return the search tag corresponging to @index in the radix tree.
+ *
+ *	Returns zero if the tag is unset, or if there is no corresponding item
+ *	in the tree.
+ */
+int radix_tree_tag_get(struct radix_tree_root *root,
+			unsigned long index, int tag)
+{
+	unsigned int height, shift;
+	struct radix_tree_node **slot;
+	int saw_unset_tag = 0;
+
+	height = root->height;
+	if (index > radix_tree_maxindex(height))
+		return 0;
+
+	shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
+	slot = &root->rnode;
+
+	for ( ; ; ) {
+		int offset;
+
+		if (*slot == NULL)
+			return 0;
+
+		offset = (index >> shift) & RADIX_TREE_MAP_MASK;
+
+		/*
+		 * This is just a debug check.  Later, we can bale as soon as
+		 * we see an unset tag.
+		 */
+		if (!tag_get(*slot, tag, offset))
+			saw_unset_tag = 1;
+		if (height == 1) {
+			int ret = tag_get(*slot, tag, offset);
+
+			BUG_ON(ret && saw_unset_tag);
+			return ret;
+		}
+		slot = (struct radix_tree_node **)((*slot)->slots + offset);
+		shift -= RADIX_TREE_MAP_SHIFT;
+		height--;
+	}
+}
+EXPORT_SYMBOL(radix_tree_tag_get);
+#endif
+
+static unsigned int
 __lookup(struct radix_tree_root *root, void **results, unsigned long index,
 	unsigned int max_items, unsigned long *next_index)
 {
@@ -314,17 +537,6 @@ radix_tree_gang_lookup(struct radix_tree
 	unsigned long cur_index = first_index;
 	unsigned int ret = 0;
 
-	if (root->rnode == NULL)
-		goto out;
-	if (max_index == 0) {			/* Bah.  Special case */
-		if (first_index == 0) {
-			if (max_items > 0) {
-				*results = root->rnode;
-				ret = 1;
-			}
-		}
-		goto out;
-	}
 	while (ret < max_items) {
 		unsigned int nr_found;
 		unsigned long next_index;	/* Index of next search */
@@ -338,11 +550,101 @@ radix_tree_gang_lookup(struct radix_tree
 			break;
 		cur_index = next_index;
 	}
-out:
 	return ret;
 }
 EXPORT_SYMBOL(radix_tree_gang_lookup);
 
+/*
+ * FIXME: the two tag_get()s here should use find_next_bit() instead of
+ * open-coding the search.
+ */
+static unsigned int
+__lookup_tag(struct radix_tree_root *root, void **results, unsigned long index,
+	unsigned int max_items, unsigned long *next_index, int tag)
+{
+	unsigned int nr_found = 0;
+	unsigned int shift;
+	unsigned int height = root->height;
+	struct radix_tree_node *slot;
+
+	shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
+	slot = root->rnode;
+
+	while (height > 0) {
+		unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK;
+
+		for ( ; i < RADIX_TREE_MAP_SIZE; i++) {
+			if (tag_get(slot, tag, i)) {
+				BUG_ON(slot->slots[i] == NULL);
+				break;
+			}
+			index &= ~((1 << shift) - 1);
+			index += 1 << shift;
+			if (index == 0)
+				goto out;	/* 32-bit wraparound */
+		}
+		if (i == RADIX_TREE_MAP_SIZE)
+			goto out;
+		height--;
+		if (height == 0) {	/* Bottom level: grab some items */
+			unsigned long j = index & RADIX_TREE_MAP_MASK;
+
+			for ( ; j < RADIX_TREE_MAP_SIZE; j++) {
+				index++;
+				if (tag_get(slot, tag, j)) {
+					BUG_ON(slot->slots[j] == NULL);
+					results[nr_found++] = slot->slots[j];
+					if (nr_found == max_items)
+						goto out;
+				}
+			}
+		}
+		shift -= RADIX_TREE_MAP_SHIFT;
+		slot = slot->slots[i];
+	}
+out:
+	*next_index = index;
+	return nr_found;
+}
+
+/**
+ *	radix_tree_gang_lookup_tag - perform multiple lookup on a radix tree
+ *	                             based on a tag
+ *	@root:		radix tree root
+ *	@results:	where the results of the lookup are placed
+ *	@first_index:	start the lookup from this key
+ *	@max_items:	place up to this many items at *results
+ *	@tag:		the tag index
+ *
+ *	Performs an index-ascending scan of the tree for present items which
+ *	have the tag indexed by @tag set.  Places the items at *@results and
+ *	returns the number of items which were placed at *@results.
+ */
+unsigned int
+radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,
+		unsigned long first_index, unsigned int max_items, int tag)
+{
+	const unsigned long max_index = radix_tree_maxindex(root->height);
+	unsigned long cur_index = first_index;
+	unsigned int ret = 0;
+
+	while (ret < max_items) {
+		unsigned int nr_found;
+		unsigned long next_index;	/* Index of next search */
+
+		if (cur_index > max_index)
+			break;
+		nr_found = __lookup_tag(root, results + ret, cur_index,
+					max_items - ret, &next_index, tag);
+		ret += nr_found;
+		if (next_index == 0)
+			break;
+		cur_index = next_index;
+	}
+	return ret;
+}
+EXPORT_SYMBOL(radix_tree_gang_lookup_tag);
+
 /**
  *	radix_tree_delete    -    delete an item from a radix tree
  *	@root:		radix tree root
@@ -355,24 +657,31 @@ EXPORT_SYMBOL(radix_tree_gang_lookup);
 void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
 {
 	struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
+	struct radix_tree_path *orig_pathp;
 	unsigned int height, shift;
 	void *ret = NULL;
+	char tags[RADIX_TREE_TAGS];
+	int nr_cleared_tags;
 
 	height = root->height;
 	if (index > radix_tree_maxindex(height))
 		goto out;
 
-	shift = (height-1) * RADIX_TREE_MAP_SHIFT;
+	shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
 	pathp->node = NULL;
 	pathp->slot = &root->rnode;
 
 	while (height > 0) {
+		int offset;
+
 		if (*pathp->slot == NULL)
 			goto out;
 
+		offset = (index >> shift) & RADIX_TREE_MAP_MASK;
+		pathp[1].offset = offset;
 		pathp[1].node = *pathp[0].slot;
 		pathp[1].slot = (struct radix_tree_node **)
-		    (pathp[1].node->slots + ((index >> shift) & RADIX_TREE_MAP_MASK));
+				(pathp[1].node->slots + offset);
 		pathp++;
 		shift -= RADIX_TREE_MAP_SHIFT;
 		height--;
@@ -382,20 +691,67 @@ void *radix_tree_delete(struct radix_tre
 	if (ret == NULL)
 		goto out;
 
+	orig_pathp = pathp;
+
+	/*
+	 * Clear all tags associated with the just-deleted item
+	 */
+	memset(tags, 0, sizeof(tags));
+	do {
+		int tag;
+
+		nr_cleared_tags = RADIX_TREE_TAGS;
+		for (tag = 0; tag < RADIX_TREE_TAGS; tag++) {
+			int idx;
+
+			if (!tags[tag])
+				tag_clear(pathp[0].node, tag, pathp[0].offset);
+
+			for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
+				if (pathp[0].node->tags[tag][idx]) {
+					tags[tag] = 1;
+					nr_cleared_tags--;
+					break;
+				}
+			}
+		}
+		pathp--;
+	} while (pathp[0].node && nr_cleared_tags);
+
+	pathp = orig_pathp;
 	*pathp[0].slot = NULL;
 	while (pathp[0].node && --pathp[0].node->count == 0) {
 		pathp--;
+		BUG_ON(*pathp[0].slot == NULL);
 		*pathp[0].slot = NULL;
 		radix_tree_node_free(pathp[1].node);
 	}
-
 	if (root->rnode == NULL)
-		root->height = 0;  /* Empty tree, we can reset the height */
+		root->height = 0;
 out:
 	return ret;
 }
 EXPORT_SYMBOL(radix_tree_delete);
 
+/**
+ *	radix_tree_tagged - test whether any items in the tree are tagged
+ *	@root:		radix tree root
+ *	@tag:		tag to test
+ */
+int radix_tree_tagged(struct radix_tree_root *root, int tag)
+{
+	int idx;
+
+	if (!root->rnode)
+		return 0;
+	for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
+		if (root->rnode->tags[tag][idx])
+			return 1;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(radix_tree_tagged);
+
 static void
 radix_tree_node_ctor(void *node, kmem_cache_t *cachep, unsigned long flags)
 {
--- diff/mm/Makefile	2003-10-09 08:47:17.000000000 +0000
+++ source/mm/Makefile	2004-03-16 09:37:58.054714512 +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/fadvise.c	2004-02-18 08:54:13.000000000 +0000
+++ source/mm/fadvise.c	2004-03-16 09:37:58.054714512 +0000
@@ -65,9 +65,8 @@ asmlinkage long sys_fadvise64_64(int fd,
 	case POSIX_FADV_DONTNEED:
 		if (!bdi_write_congested(mapping->backing_dev_info))
 			filemap_flush(mapping);
-		start_index = offset >> PAGE_CACHE_SHIFT;
-		end_index = (offset + len + PAGE_CACHE_SIZE - 1) >>
-						PAGE_CACHE_SHIFT;
+		start_index = (offset + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT;
+		end_index = ((offset + len) >> PAGE_CACHE_SHIFT) - 1;
 		invalidate_mapping_pages(mapping, start_index, end_index);
 		break;
 	default:
--- diff/mm/filemap.c	2004-03-11 10:20:29.000000000 +0000
+++ source/mm/filemap.c	2004-03-16 09:37:58.057714056 +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,
@@ -59,7 +60,7 @@
  *    ->private_lock		(__free_pte->__set_page_dirty_buffers)
  *      ->swap_list_lock
  *        ->swap_device_lock	(exclusive_swap_page, others)
- *          ->mapping->page_lock
+ *          ->mapping->tree_lock
  *
  *  ->i_sem
  *    ->i_shared_sem		(truncate->invalidate_mmap_range)
@@ -73,14 +74,17 @@
  *  ->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)
+ *    ->mapping->tree_lock	(__sync_single_inode)
  *
  *  ->page_table_lock
  *    ->swap_device_lock	(try_to_unmap_one)
  *    ->private_lock		(try_to_unmap_one)
- *    ->page_lock		(try_to_unmap_one)
+ *    ->tree_lock		(try_to_unmap_one)
  *    ->zone.lru_lock		(follow_page->mark_page_accessed)
  *
  *  ->task->proc_lock
@@ -90,16 +94,14 @@
 /*
  * Remove a page from the page cache and free it. Caller has to make
  * sure the page is locked and that nobody else uses it - or that usage
- * is safe.  The caller must hold a write_lock on the mapping's page_lock.
+ * is safe.  The caller must hold a write_lock on the mapping's tree_lock.
  */
 void __remove_from_page_cache(struct page *page)
 {
 	struct address_space *mapping = page->mapping;
 
 	radix_tree_delete(&mapping->page_tree, page->index);
-	list_del(&page->list);
 	page->mapping = NULL;
-
 	mapping->nrpages--;
 	pagecache_acct(-1);
 }
@@ -111,15 +113,17 @@ void remove_from_page_cache(struct page 
 	if (unlikely(!PageLocked(page)))
 		PAGE_BUG(page);
 
-	spin_lock(&mapping->page_lock);
+	spin_lock_irq(&mapping->tree_lock);
 	__remove_from_page_cache(page);
-	spin_unlock(&mapping->page_lock);
+	spin_unlock_irq(&mapping->tree_lock);
 }
 
 static inline int sync_page(struct page *page)
 {
-	struct address_space *mapping = page->mapping;
+	struct address_space *mapping;
 
+	smp_mb();
+	mapping = page->mapping;
 	if (mapping && mapping->a_ops && mapping->a_ops->sync_page)
 		return mapping->a_ops->sync_page(page);
 	return 0;
@@ -145,9 +149,6 @@ static int __filemap_fdatawrite(struct a
 	if (mapping->backing_dev_info->memory_backed)
 		return 0;
 
-	spin_lock(&mapping->page_lock);
-	list_splice_init(&mapping->dirty_pages, &mapping->io_pages);
-	spin_unlock(&mapping->page_lock);
 	ret = do_writepages(mapping, &wbc);
 	return ret;
 }
@@ -156,7 +157,6 @@ int filemap_fdatawrite(struct address_sp
 {
 	return __filemap_fdatawrite(mapping, WB_SYNC_ALL);
 }
-
 EXPORT_SYMBOL(filemap_fdatawrite);
 
 /*
@@ -167,55 +167,40 @@ int filemap_flush(struct address_space *
 {
 	return __filemap_fdatawrite(mapping, WB_SYNC_NONE);
 }
-
 EXPORT_SYMBOL(filemap_flush);
 
-/**
- * filemap_fdatawait - walk the list of locked pages of the given address
- *                     space and wait for all of them.
- * @mapping: address space structure to wait for
+/*
+ * Wait for writeback to complete against pages indexed by start->end
+ * inclusive
  */
-int filemap_fdatawait(struct address_space * mapping)
+static int wait_on_page_writeback_range(struct address_space *mapping,
+				pgoff_t start, pgoff_t end)
 {
+	struct pagevec pvec;
+	int nr_pages;
 	int ret = 0;
-	int progress;
+	pgoff_t index;
 
-restart:
-	progress = 0;
-	spin_lock(&mapping->page_lock);
-        while (!list_empty(&mapping->locked_pages)) {
-		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
-			list_add(&page->list, &mapping->clean_pages);
+	if (end > start)
+		return 0;
 
-		if (!PageWriteback(page)) {
-			if (++progress > 32) {
-				if (need_resched()) {
-					spin_unlock(&mapping->page_lock);
-					__cond_resched();
-					goto restart;
-				}
-			}
-			continue;
+	pagevec_init(&pvec, 0);
+	index = start;
+	while ((nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
+				PAGECACHE_TAG_WRITEBACK,
+				min(end - index + 1, (pgoff_t)PAGEVEC_SIZE)))) {
+		unsigned i;
+
+		for (i = 0; i < nr_pages; i++) {
+			struct page *page = pvec.pages[i];
+
+			wait_on_page_writeback(page);
+			if (PageError(page))
+				ret = -EIO;
 		}
-
-		progress = 0;
-		page_cache_get(page);
-		spin_unlock(&mapping->page_lock);
-
-		wait_on_page_writeback(page);
-		if (PageError(page))
-			ret = -EIO;
-
-		page_cache_release(page);
-		spin_lock(&mapping->page_lock);
+		pagevec_release(&pvec);
+		cond_resched();
 	}
-	spin_unlock(&mapping->page_lock);
 
 	/* Check for outstanding write errors */
 	if (test_and_clear_bit(AS_ENOSPC, &mapping->flags))
@@ -226,8 +211,31 @@ restart:
 	return ret;
 }
 
+/**
+ * filemap_fdatawait - walk the list of under-writeback pages of the given
+ *     address space and wait for all of them.
+ *
+ * @mapping: address space structure to wait for
+ */
+int filemap_fdatawait(struct address_space *mapping)
+{
+	return wait_on_page_writeback_range(mapping, 0, -1);
+}
+
 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.
@@ -252,7 +260,7 @@ int add_to_page_cache(struct page *page,
 
 	if (error == 0) {
 		page_cache_get(page);
-		spin_lock(&mapping->page_lock);
+		spin_lock_irq(&mapping->tree_lock);
 		error = radix_tree_insert(&mapping->page_tree, offset, page);
 		if (!error) {
 			SetPageLocked(page);
@@ -260,7 +268,7 @@ int add_to_page_cache(struct page *page,
 		} else {
 			page_cache_release(page);
 		}
-		spin_unlock(&mapping->page_lock);
+		spin_unlock_irq(&mapping->tree_lock);
 		radix_tree_preload_end();
 	}
 	return error;
@@ -348,8 +356,7 @@ void end_page_writeback(struct page *pag
 	wait_queue_head_t *waitqueue = page_waitqueue(page);
 
 	if (!TestClearPageReclaim(page) || rotate_reclaimable_page(page)) {
-		smp_mb__before_clear_bit();
-		if (!TestClearPageWriteback(page))
+		if (!test_clear_page_writeback(page))
 			BUG();
 		smp_mb__after_clear_bit();
 	}
@@ -396,11 +403,11 @@ struct page * find_get_page(struct addre
 	 * We scan the hash list read-only. Addition to and removal from
 	 * the hash-list needs a held write-lock.
 	 */
-	spin_lock(&mapping->page_lock);
+	spin_lock_irq(&mapping->tree_lock);
 	page = radix_tree_lookup(&mapping->page_tree, offset);
 	if (page)
 		page_cache_get(page);
-	spin_unlock(&mapping->page_lock);
+	spin_unlock_irq(&mapping->tree_lock);
 	return page;
 }
 
@@ -413,11 +420,11 @@ struct page *find_trylock_page(struct ad
 {
 	struct page *page;
 
-	spin_lock(&mapping->page_lock);
+	spin_lock_irq(&mapping->tree_lock);
 	page = radix_tree_lookup(&mapping->page_tree, offset);
 	if (page && TestSetPageLocked(page))
 		page = NULL;
-	spin_unlock(&mapping->page_lock);
+	spin_unlock_irq(&mapping->tree_lock);
 	return page;
 }
 
@@ -439,15 +446,15 @@ struct page *find_lock_page(struct addre
 {
 	struct page *page;
 
-	spin_lock(&mapping->page_lock);
+	spin_lock_irq(&mapping->tree_lock);
 repeat:
 	page = radix_tree_lookup(&mapping->page_tree, offset);
 	if (page) {
 		page_cache_get(page);
 		if (TestSetPageLocked(page)) {
-			spin_unlock(&mapping->page_lock);
+			spin_unlock_irq(&mapping->tree_lock);
 			lock_page(page);
-			spin_lock(&mapping->page_lock);
+			spin_lock_irq(&mapping->tree_lock);
 
 			/* Has the page been truncated while we slept? */
 			if (page->mapping != mapping || page->index != offset) {
@@ -457,7 +464,7 @@ repeat:
 			}
 		}
 	}
-	spin_unlock(&mapping->page_lock);
+	spin_unlock_irq(&mapping->tree_lock);
 	return page;
 }
 
@@ -525,18 +532,39 @@ EXPORT_SYMBOL(find_or_create_page);
  *
  * find_get_pages() returns the number of pages which were found.
  */
-unsigned int find_get_pages(struct address_space *mapping, pgoff_t start,
+unsigned find_get_pages(struct address_space *mapping, pgoff_t start,
 			    unsigned int nr_pages, struct page **pages)
 {
 	unsigned int i;
 	unsigned int ret;
 
-	spin_lock(&mapping->page_lock);
+	spin_lock_irq(&mapping->tree_lock);
 	ret = radix_tree_gang_lookup(&mapping->page_tree,
 				(void **)pages, start, nr_pages);
 	for (i = 0; i < ret; i++)
 		page_cache_get(pages[i]);
-	spin_unlock(&mapping->page_lock);
+	spin_unlock_irq(&mapping->tree_lock);
+	return ret;
+}
+
+/*
+ * Like find_get_pages, except we only return pages which are tagged with
+ * `tag'.   We update *start to index the next page for the traversal.
+ */
+unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index,
+			int tag, unsigned int nr_pages, struct page **pages)
+{
+	unsigned int i;
+	unsigned int ret;
+
+	spin_lock_irq(&mapping->tree_lock);
+	ret = radix_tree_gang_lookup_tag(&mapping->page_tree,
+				(void **)pages, *index, nr_pages, tag);
+	for (i = 0; i < ret; i++)
+		page_cache_get(pages[i]);
+	if (ret)
+		*index = pages[ret - 1]->index + 1;
+	spin_unlock_irq(&mapping->tree_lock);
 	return ret;
 }
 
@@ -574,7 +602,7 @@ EXPORT_SYMBOL(grab_cache_page_nowait);
 
 /*
  * This is a generic file read routine, and uses the
- * inode->i_op->readpage() function for the actual low-level
+ * mapping->a_ops->readpage() function for the actual low-level
  * stuff.
  *
  * This is really ugly. But the goto's actually try to clarify some
@@ -1200,8 +1228,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:
 	/*
@@ -1294,12 +1327,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);
@@ -1319,19 +1362,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;
@@ -1715,6 +1748,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
@@ -1803,12 +1837,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;
@@ -1897,6 +1940,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:
@@ -1988,6 +2039,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)
@@ -1996,18 +2050,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-11 10:20:29.000000000 +0000
+++ source/mm/fremap.c	2004-03-16 09:37:58.057714056 +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/memory.c	2004-03-11 10:20:29.000000000 +0000
+++ source/mm/memory.c	2004-03-16 09:37:58.059713752 +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,11 +141,13 @@ 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);
 }
 
@@ -222,7 +228,7 @@ int copy_page_range(struct mm_struct *ds
 	if (is_vm_hugetlb_page(vma))
 		return copy_hugetlb_page_range(dst, src, vma);
 
-	pte_chain = pte_chain_alloc(GFP_ATOMIC);
+	pte_chain = pte_chain_alloc(GFP_ATOMIC | __GFP_NOWARN);
 	if (!pte_chain) {
 		spin_unlock(&dst->page_table_lock);
 		pte_chain = pte_chain_alloc(GFP_KERNEL);
@@ -328,14 +334,14 @@ 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,
 							pte_chain);
 				if (pte_chain)
 					goto cont_copy_pte_range_noset;
-				pte_chain = pte_chain_alloc(GFP_ATOMIC);
+				pte_chain = pte_chain_alloc(GFP_ATOMIC | __GFP_NOWARN);
 				if (pte_chain)
 					goto cont_copy_pte_range_noset;
 
@@ -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; 
@@ -693,6 +707,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 +751,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 +764,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 +812,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 +1093,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 +1327,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);
@@ -1336,7 +1361,7 @@ do_anonymous_page(struct mm_struct *mm, 
 	struct pte_chain *pte_chain;
 	int ret;
 
-	pte_chain = pte_chain_alloc(GFP_ATOMIC);
+	pte_chain = pte_chain_alloc(GFP_ATOMIC | __GFP_NOWARN);
 	if (!pte_chain) {
 		pte_unmap(page_table);
 		spin_unlock(&mm->page_table_lock);
@@ -1371,7 +1396,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 +1511,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 +1548,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 +1563,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 +1617,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);
--- diff/mm/mempool.c	2003-01-13 14:18:16.000000000 +0000
+++ source/mm/mempool.c	2004-03-16 09:37:58.060713600 +0000
@@ -209,6 +209,7 @@ repeat_alloc:
 	 * If the pool is less than 50% full and we can perform effective
 	 * page reclaim then try harder to allocate an element.
 	 */
+	mb();
 	if ((gfp_mask & __GFP_FS) && (gfp_mask != gfp_nowait) &&
 				(pool->curr_nr <= pool->min_nr/2)) {
 		element = pool->alloc(gfp_mask, pool->pool_data);
@@ -233,9 +234,8 @@ repeat_alloc:
 	if (!(gfp_mask & __GFP_WAIT))
 		return NULL;
 
-	blk_run_queues();
-
 	prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE);
+	mb();
 	if (!pool->curr_nr)
 		io_schedule();
 	finish_wait(&pool->wait, &wait);
@@ -256,6 +256,7 @@ void mempool_free(void *element, mempool
 {
 	unsigned long flags;
 
+	mb();
 	if (pool->curr_nr < pool->min_nr) {
 		spin_lock_irqsave(&pool->lock, flags);
 		if (pool->curr_nr < pool->min_nr) {
--- diff/mm/mmap.c	2004-03-11 10:20:29.000000000 +0000
+++ source/mm/mmap.c	2004-03-16 09:37:58.061713448 +0000
@@ -138,17 +138,34 @@ out:
 }
 
 #ifdef DEBUG_MM_RB
-static int browse_rb(struct rb_node * rb_node) {
-	int i = 0;
-	if (rb_node) {
+static int browse_rb(struct rb_root *root) {
+	int i, j;
+	struct rb_node *nd, *pn = NULL;
+	i = 0;
+	unsigned long prev = 0, pend = 0;
+
+	for (nd = rb_first(root); nd; nd = rb_next(nd)) {
+		struct vm_area_struct *vma;
+		vma = rb_entry(nd, struct vm_area_struct, vm_rb);
+		if (vma->vm_start < prev)
+			printk("vm_start %lx prev %lx\n", vma->vm_start, prev), i = -1;
+		if (vma->vm_start < pend)
+			printk("vm_start %lx pend %lx\n", vma->vm_start, pend);
+		if (vma->vm_start > vma->vm_end)
+			printk("vm_end %lx < vm_start %lx\n", vma->vm_end, vma->vm_start);
 		i++;
-		i += browse_rb(rb_node->rb_left);
-		i += browse_rb(rb_node->rb_right);
+		pn = nd;
+	}
+	j = 0;
+	for (nd = pn; nd; nd = rb_prev(nd)) {
+		j++;
 	}
+	if (i != j)
+		printk("backwards %d, forwards %d\n", j, i), i = 0;
 	return i;
 }
 
-static void validate_mm(struct mm_struct * mm) {
+void validate_mm(struct mm_struct * mm) {
 	int bug = 0;
 	int i = 0;
 	struct vm_area_struct * tmp = mm->mmap;
@@ -158,7 +175,7 @@ static void validate_mm(struct mm_struct
 	}
 	if (i != mm->map_count)
 		printk("map_count %d vm_next %d\n", mm->map_count, i), bug = 1;
-	i = browse_rb(mm->mm_rb.rb_node);
+	i = browse_rb(&mm->mm_rb);
 	if (i != mm->map_count)
 		printk("map_count %d rb %d\n", mm->map_count, i), bug = 1;
 	if (bug)
@@ -691,8 +708,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;
@@ -1430,7 +1451,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-16 09:37:58.062713296 +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,8 @@ 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 +301,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 +350,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,6 +370,11 @@ static void wb_kupdate(unsigned long arg
 		next_jif = jiffies + HZ;
 	if (dirty_writeback_centisecs)
 		mod_timer(&wb_timer, next_jif);
+
+	/*
+	 * The timer may have been set as a result of our writes.
+	 */
+	del_timer(&laptop_mode_wb_timer);
 }
 
 /*
@@ -364,13 +393,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 +477,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);
 }
@@ -470,12 +515,8 @@ int write_one_page(struct page *page, in
 	if (wait)
 		wait_on_page_writeback(page);
 
-	spin_lock(&mapping->page_lock);
-	list_del(&page->list);
 	if (test_clear_page_dirty(page)) {
-		list_add(&page->list, &mapping->locked_pages);
 		page_cache_get(page);
-		spin_unlock(&mapping->page_lock);
 		ret = mapping->a_ops->writepage(page, &wbc);
 		if (ret == 0 && wait) {
 			wait_on_page_writeback(page);
@@ -484,8 +525,6 @@ int write_one_page(struct page *page, in
 		}
 		page_cache_release(page);
 	} else {
-		list_add(&page->list, &mapping->clean_pages);
-		spin_unlock(&mapping->page_lock);
 		unlock_page(page);
 	}
 	return ret;
@@ -493,9 +532,8 @@ int write_one_page(struct page *page, in
 EXPORT_SYMBOL(write_one_page);
 
 /*
- * For address_spaces which do not use buffers.  Just set the page's dirty bit
- * and move it to the dirty_pages list.  Also perform space reservation if
- * required.
+ * For address_spaces which do not use buffers.  Just tag the page as dirty in
+ * its radix tree.
  *
  * __set_page_dirty_nobuffers() may return -ENOSPC.  But if it does, the page
  * is still safe, as long as it actually manages to find some blocks at
@@ -513,19 +551,22 @@ int __set_page_dirty_nobuffers(struct pa
 		struct address_space *mapping = page->mapping;
 
 		if (mapping) {
-			spin_lock(&mapping->page_lock);
+			spin_lock_irq(&mapping->tree_lock);
 			if (page->mapping) {	/* Race with truncate? */
 				BUG_ON(page->mapping != mapping);
 				if (!mapping->backing_dev_info->memory_backed)
 					inc_page_state(nr_dirty);
-				list_del(&page->list);
-				list_add(&page->list, &mapping->dirty_pages);
+				radix_tree_tag_set(&mapping->page_tree,
+					page->index, PAGECACHE_TAG_DIRTY);
 			}
-			spin_unlock(&mapping->page_lock);
+			spin_unlock_irq(&mapping->tree_lock);
 			if (!PageSwapCache(page))
 				__mark_inode_dirty(mapping->host,
 							I_DIRTY_PAGES);
 		}
+		if (unlikely(block_dump))
+			printk("%s(%d): dirtied page\n",
+					current->comm, current->pid);
 	}
 	return ret;
 }
@@ -558,13 +599,102 @@ EXPORT_SYMBOL(set_page_dirty_lock);
  */
 int test_clear_page_dirty(struct page *page)
 {
-	if (TestClearPageDirty(page)) {
-		struct address_space *mapping = page->mapping;
+	struct address_space *mapping = page->mapping;
+	unsigned long flags;
 
-		if (mapping && !mapping->backing_dev_info->memory_backed)
-			dec_page_state(nr_dirty);
-		return 1;
+	if (mapping) {
+		spin_lock_irqsave(&mapping->tree_lock, flags);
+		if (TestClearPageDirty(page)) {
+			radix_tree_tag_clear(&mapping->page_tree, page->index,
+						PAGECACHE_TAG_DIRTY);
+			spin_unlock_irqrestore(&mapping->tree_lock, flags);
+			if (!mapping->backing_dev_info->memory_backed)
+				dec_page_state(nr_dirty);
+			return 1;
+		}
+		spin_unlock_irqrestore(&mapping->tree_lock, flags);
+		return 0;
 	}
-	return 0;
+	return TestClearPageDirty(page);
 }
 EXPORT_SYMBOL(test_clear_page_dirty);
+
+/*
+ * Clear a page's dirty flag while ignoring dirty memory accounting
+ */
+int __clear_page_dirty(struct page *page)
+{
+	struct address_space *mapping = page->mapping;
+
+	if (mapping) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&mapping->tree_lock, flags);
+		if (TestClearPageDirty(page)) {
+			radix_tree_tag_clear(&mapping->page_tree, page->index,
+						PAGECACHE_TAG_DIRTY);
+			spin_unlock_irqrestore(&mapping->tree_lock, flags);
+			return 1;
+		}
+		spin_unlock_irqrestore(&mapping->tree_lock, flags);
+		return 0;
+	}
+	return TestClearPageDirty(page);
+}
+
+int test_clear_page_writeback(struct page *page)
+{
+	struct address_space *mapping = page->mapping;
+	int ret;
+
+	if (mapping) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&mapping->tree_lock, flags);
+		ret = TestClearPageWriteback(page);
+		if (ret)
+			radix_tree_tag_clear(&mapping->page_tree, page->index,
+						PAGECACHE_TAG_WRITEBACK);
+		spin_unlock_irqrestore(&mapping->tree_lock, flags);
+	} else {
+		ret = TestClearPageWriteback(page);
+	}
+	return ret;
+}
+
+int test_set_page_writeback(struct page *page)
+{
+	struct address_space *mapping = page->mapping;
+	int ret;
+
+	if (mapping) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&mapping->tree_lock, flags);
+		ret = TestSetPageWriteback(page);
+		if (ret)
+			radix_tree_tag_set(&mapping->page_tree, page->index,
+						PAGECACHE_TAG_WRITEBACK);
+		spin_unlock_irqrestore(&mapping->tree_lock, flags);
+	} else {
+		ret = TestSetPageWriteback(page);
+	}
+	return ret;
+
+}
+
+/*
+ * Return true if any of the pages in the mapping are marged with the
+ * passed tag.
+ */
+int mapping_tagged(struct address_space *mapping, int tag)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&mapping->tree_lock, flags);
+	ret = radix_tree_tagged(&mapping->page_tree, tag);
+	spin_unlock_irqrestore(&mapping->tree_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(mapping_tagged);
--- diff/mm/page_alloc.c	2004-03-11 10:20:29.000000000 +0000
+++ source/mm/page_alloc.c	2004-03-16 09:37:58.065712840 +0000
@@ -71,13 +71,14 @@ static int bad_range(struct zone *zone, 
 
 static void bad_page(const char *function, struct page *page)
 {
-	printk("Bad page state at %s (in process '%s', page %p)\n", function, current->comm, page);
-	printk("flags:0x%08lx mapping:%p mapped:%d count:%d\n",
+	printk(KERN_EMERG "Bad page state at %s (in process '%s', page %p)\n",
+		function, current->comm, page);
+	printk(KERN_EMERG "flags:0x%08lx mapping:%p mapped:%d count:%d\n",
 		page->flags, page->mapping,
 		page_mapped(page), page_count(page));
-	printk("Backtrace:\n");
+	printk(KERN_EMERG "Backtrace:\n");
 	dump_stack();
-	printk("Trying to fix it up, but a reboot is needed\n");
+	printk(KERN_EMERG "Trying to fix it up, but a reboot is needed\n");
 	page->flags &= ~(1 << PG_private	|
 			1 << PG_locked	|
 			1 << PG_lru	|
@@ -99,13 +100,13 @@ static void bad_page(const char *functio
  *
  * The remaining PAGE_SIZE pages are called "tail pages".
  *
- * All pages have PG_compound set.  All pages have their lru.next pointing at
+ * All pages have PG_compound set.  All pages have their ->private pointing at
  * the head page (even the head page has this).
  *
- * The head page's lru.prev, if non-zero, holds the address of the compound
- * page's put_page() function.
+ * The first tail page's ->mapping, if non-zero, holds the address of the
+ * compound page's put_page() function.
  *
- * The order of the allocation is stored in the first tail page's lru.prev.
+ * The order of the allocation is stored in the first tail page's ->index
  * This is only for debug at present.  This usage means that zero-order pages
  * may not be compound.
  */
@@ -114,13 +115,13 @@ static void prep_compound_page(struct pa
 	int i;
 	int nr_pages = 1 << order;
 
-	page->lru.prev = NULL;
-	page[1].lru.prev = (void *)order;
+	page[1].mapping = 0;
+	page[1].index = order;
 	for (i = 0; i < nr_pages; i++) {
 		struct page *p = page + i;
 
 		SetPageCompound(p);
-		p->lru.next = (void *)page;
+		p->private = (unsigned long)page;
 	}
 }
 
@@ -129,7 +130,7 @@ static void destroy_compound_page(struct
 	int i;
 	int nr_pages = 1 << order;
 
-	if (page[1].lru.prev != (void *)order)
+	if (page[1].index != order)
 		bad_page(__FUNCTION__, page);
 
 	for (i = 0; i < nr_pages; i++) {
@@ -137,7 +138,7 @@ static void destroy_compound_page(struct
 
 		if (!PageCompound(p))
 			bad_page(__FUNCTION__, page);
-		if (p->lru.next != (void *)page)
+		if (p->private != (unsigned long)page)
 			bad_page(__FUNCTION__, page);
 		ClearPageCompound(p);
 	}
@@ -199,13 +200,13 @@ static inline void __free_pages_bulk (st
 		buddy2 = base + page_idx;
 		BUG_ON(bad_range(zone, buddy1));
 		BUG_ON(bad_range(zone, buddy2));
-		list_del(&buddy1->list);
+		list_del(&buddy1->lru);
 		mask <<= 1;
 		area++;
 		index >>= 1;
 		page_idx &= mask;
 	}
-	list_add(&(base + page_idx)->list, &area->free_list);
+	list_add(&(base + page_idx)->lru, &area->free_list);
 }
 
 static inline void free_pages_check(const char *function, struct page *page)
@@ -253,9 +254,9 @@ free_pages_bulk(struct zone *zone, int c
 	zone->all_unreclaimable = 0;
 	zone->pages_scanned = 0;
 	while (!list_empty(list) && count--) {
-		page = list_entry(list->prev, struct page, list);
+		page = list_entry(list->prev, struct page, lru);
 		/* have to delete it as __free_pages_bulk list manipulates */
-		list_del(&page->list);
+		list_del(&page->lru);
 		__free_pages_bulk(page, base, zone, area, mask, order);
 		ret++;
 	}
@@ -271,7 +272,7 @@ void __free_pages_ok(struct page *page, 
 	mod_page_state(pgfree, 1 << order);
 	for (i = 0 ; i < (1 << order) ; ++i)
 		free_pages_check(__FUNCTION__, page + i);
-	list_add(&page->list, &list);
+	list_add(&page->lru, &list);
 	kernel_map_pages(page, 1<<order, 0);
 	free_pages_bulk(page_zone(page), 1, &list, order);
 }
@@ -290,7 +291,7 @@ expand(struct zone *zone, struct page *p
 		area--;
 		high--;
 		size >>= 1;
-		list_add(&page->list, &area->free_list);
+		list_add(&page->lru, &area->free_list);
 		MARK_USED(index, high, area);
 		index += size;
 		page += size;
@@ -353,8 +354,8 @@ static struct page *__rmqueue(struct zon
 		if (list_empty(&area->free_list))
 			continue;
 
-		page = list_entry(area->free_list.next, struct page, list);
-		list_del(&page->list);
+		page = list_entry(area->free_list.next, struct page, lru);
+		list_del(&page->lru);
 		index = page - zone->zone_mem_map;
 		if (current_order != MAX_ORDER-1)
 			MARK_USED(index, current_order, area);
@@ -384,7 +385,7 @@ static int rmqueue_bulk(struct zone *zon
 		if (page == NULL)
 			break;
 		allocated++;
-		list_add_tail(&page->list, list);
+		list_add_tail(&page->lru, list);
 	}
 	spin_unlock_irqrestore(&zone->lock, flags);
 	return allocated;
@@ -426,7 +427,7 @@ int is_head_of_free_region(struct page *
 	spin_lock_irqsave(&zone->lock, flags);
 	for (order = MAX_ORDER - 1; order >= 0; --order)
 		list_for_each(curr, &zone->free_area[order].free_list)
-			if (page == list_entry(curr, struct page, list)) {
+			if (page == list_entry(curr, struct page, lru)) {
 				spin_unlock_irqrestore(&zone->lock, flags);
 				return 1 << order;
 			}
@@ -464,7 +465,7 @@ static void fastcall free_hot_cold_page(
 	local_irq_save(flags);
 	if (pcp->count >= pcp->high)
 		pcp->count -= free_pages_bulk(zone, pcp->batch, &pcp->list, 0);
-	list_add(&page->list, &pcp->list);
+	list_add(&page->lru, &pcp->list);
 	pcp->count++;
 	local_irq_restore(flags);
 	put_cpu();
@@ -500,8 +501,8 @@ static struct page *buffered_rmqueue(str
 			pcp->count += rmqueue_bulk(zone, 0,
 						pcp->batch, &pcp->list);
 		if (pcp->count) {
-			page = list_entry(pcp->list.next, struct page, list);
-			list_del(&page->list);
+			page = list_entry(pcp->list.next, struct page, lru);
+			list_del(&page->lru);
 			pcp->count--;
 		}
 		local_irq_restore(flags);
@@ -512,14 +513,14 @@ static struct page *buffered_rmqueue(str
 		spin_lock_irqsave(&zone->lock, flags);
 		page = __rmqueue(zone, order);
 		spin_unlock_irqrestore(&zone->lock, flags);
-		if (order && page)
-			prep_compound_page(page, order);
 	}
 
 	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);
+		if (order)
+			prep_compound_page(page, order);
 	}
 	return page;
 }
@@ -690,6 +691,42 @@ 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.
  */
@@ -697,6 +734,10 @@ fastcall unsigned long __get_free_pages(
 {
 	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;
@@ -1021,6 +1062,7 @@ void show_free_areas(void)
 			" high:%lukB"
 			" active:%lukB"
 			" inactive:%lukB"
+			" present:%lukB"
 			"\n",
 			zone->name,
 			K(zone->free_pages),
@@ -1028,7 +1070,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)
 			);
 	}
 
@@ -1088,6 +1131,112 @@ 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++) {
+		cpumask_t tmp;
+
+		/* 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 */
+		tmp = node_to_cpumask(n);
+		if (!cpus_empty(tmp))
+			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;
@@ -1124,6 +1273,8 @@ static void __init build_zonelists(pg_da
 	} 
 }
 
+#endif	/* CONFIG_NUMA */
+
 void __init build_all_zonelists(void)
 {
 	int i;
@@ -1210,7 +1361,7 @@ void __init memmap_init_zone(struct page
 		set_page_zone(page, NODEZONE(nid, zone));
 		set_page_count(page, 0);
 		SetPageReserved(page);
-		INIT_LIST_HEAD(&page->list);
+		INIT_LIST_HEAD(&page->lru);
 #ifdef WANT_PAGE_VIRTUAL
 		/* The shift won't overflow because ZONE_NORMAL is below 4G. */
 		if (zone != ZONE_HIGHMEM)
@@ -1298,7 +1449,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)
@@ -1481,23 +1633,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",
 };
 
--- diff/mm/page_io.c	2002-12-16 09:26:07.000000000 +0000
+++ source/mm/page_io.c	2004-03-16 09:37:58.066712688 +0000
@@ -104,7 +104,7 @@ int swap_writepage(struct page *page, st
 		goto out;
 	}
 	inc_page_state(pswpout);
-	SetPageWriteback(page);
+	set_page_writeback(page);
 	unlock_page(page);
 	submit_bio(WRITE, bio);
 out:
--- diff/mm/pdflush.c	2004-03-11 10:20:29.000000000 +0000
+++ source/mm/pdflush.c	2004-03-16 09:37:58.066712688 +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-16 09:37:58.068712384 +0000
@@ -15,11 +15,16 @@
 #include <linux/backing-dev.h>
 #include <linux/pagevec.h>
 
+void default_unplug_io_fn(struct backing_dev_info *bdi)
+{
+}
+EXPORT_SYMBOL(default_unplug_io_fn);
+
 struct backing_dev_info default_backing_dev_info = {
 	.ra_pages	= (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE,
 	.state		= 0,
+	.unplug_io_fn	= default_unplug_io_fn,
 };
-
 EXPORT_SYMBOL_GPL(default_backing_dev_info);
 
 /*
@@ -30,8 +35,8 @@ 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);
 
 /*
@@ -47,7 +52,7 @@ static inline unsigned long get_min_read
 	return (VM_MIN_READAHEAD * 1024) / PAGE_CACHE_SIZE;
 }
 
-#define list_to_page(head) (list_entry((head)->prev, struct page, list))
+#define list_to_page(head) (list_entry((head)->prev, struct page, lru))
 
 /**
  * read_cache_pages - populate an address space with some pages, and
@@ -71,7 +76,7 @@ int read_cache_pages(struct address_spac
 
 	while (!list_empty(pages)) {
 		page = list_to_page(pages);
-		list_del(&page->list);
+		list_del(&page->lru);
 		if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) {
 			page_cache_release(page);
 			continue;
@@ -84,7 +89,7 @@ int read_cache_pages(struct address_spac
 				struct page *victim;
 
 				victim = list_to_page(pages);
-				list_del(&victim->list);
+				list_del(&victim->lru);
 				page_cache_release(victim);
 			}
 			break;
@@ -111,7 +116,7 @@ static int read_pages(struct address_spa
 	pagevec_init(&lru_pvec, 0);
 	for (page_idx = 0; page_idx < nr_pages; page_idx++) {
 		struct page *page = list_to_page(pages);
-		list_del(&page->list);
+		list_del(&page->lru);
 		if (!add_to_page_cache(page, mapping,
 					page->index, GFP_KERNEL)) {
 			mapping->a_ops->readpage(filp, page);
@@ -229,7 +234,7 @@ __do_page_cache_readahead(struct address
 	/*
 	 * Preallocate as many pages as we will need.
 	 */
-	spin_lock(&mapping->page_lock);
+	spin_lock_irq(&mapping->tree_lock);
 	for (page_idx = 0; page_idx < nr_to_read; page_idx++) {
 		unsigned long page_offset = offset + page_idx;
 		
@@ -240,16 +245,16 @@ __do_page_cache_readahead(struct address
 		if (page)
 			continue;
 
-		spin_unlock(&mapping->page_lock);
+		spin_unlock_irq(&mapping->tree_lock);
 		page = page_cache_alloc_cold(mapping);
-		spin_lock(&mapping->page_lock);
+		spin_lock_irq(&mapping->tree_lock);
 		if (!page)
 			break;
 		page->index = page_offset;
-		list_add(&page->list, &page_pool);
+		list_add(&page->lru, &page_pool);
 		ret++;
 	}
-	spin_unlock(&mapping->page_lock);
+	spin_unlock_irq(&mapping->tree_lock);
 
 	/*
 	 * Now start the IO.  We ignore I/O errors - if the page is not
@@ -380,9 +385,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 +463,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 +486,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-11 10:20:29.000000000 +0000
+++ source/mm/rmap.c	2004-03-16 09:37:58.069712232 +0000
@@ -118,7 +118,7 @@ int fastcall page_referenced(struct page
 	int referenced = 0;
 
 	if (page_test_and_clear_young(page))
-		mark_page_accessed(page);
+		referenced++;
 
 	if (TestClearPageReferenced(page))
 		referenced++;
@@ -343,6 +343,7 @@ static int fastcall try_to_unmap_one(str
 		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 fastcall try_to_unmap_one(str
 		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 fastcall try_to_unmap_one(str
 	if (pte_dirty(pte))
 		set_page_dirty(page);
 
-	mm->rss--;
+	dec_rss(mm, page);
 	page_cache_release(page);
 	ret = SWAP_SUCCESS;
 
@@ -522,8 +525,8 @@ void __init pte_chain_init(void)
 {
 	pte_chain_cache = kmem_cache_create(	"pte_chain",
 						sizeof(struct pte_chain),
+						sizeof(struct pte_chain),
 						0,
-						SLAB_MUST_HWCACHE_ALIGN,
 						pte_chain_ctor,
 						NULL);
 
--- diff/mm/shmem.c	2004-02-09 10:36:12.000000000 +0000
+++ source/mm/shmem.c	2004-03-16 09:37:58.070712080 +0000
@@ -133,6 +133,7 @@ static struct vm_operations_struct shmem
 static struct backing_dev_info shmem_backing_dev_info = {
 	.ra_pages	= 0,	/* No readahead */
 	.memory_backed	= 1,	/* Does not contribute to dirty memory */
+	.unplug_io_fn = default_unplug_io_fn,
 };
 
 LIST_HEAD(shmem_inodes);
@@ -1002,6 +1003,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 +1025,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-11 10:20:29.000000000 +0000
+++ source/mm/slab.c	2004-03-16 09:37:58.073711624 +0000
@@ -121,6 +121,14 @@
 /* Shouldn't this be in a header file somewhere? */
 #define	BYTES_PER_WORD		sizeof(void *)
 
+#ifndef cache_line_size
+#define cache_line_size()	L1_CACHE_BYTES
+#endif
+
+#ifndef ARCH_KMALLOC_MINALIGN
+#define ARCH_KMALLOC_MINALIGN 0
+#endif
+
 /* Legal flag mask for kmem_cache_create(). */
 #if DEBUG
 # define CREATE_MASK	(SLAB_DEBUG_INITIAL | SLAB_RED_ZONE | \
@@ -268,6 +276,7 @@ struct kmem_cache_s {
 	unsigned int		colour_off;	/* colour offset */
 	unsigned int		colour_next;	/* cache colouring */
 	kmem_cache_t		*slabp_cache;
+	unsigned int		slab_size;
 	unsigned int		dflags;		/* dynamic flags */
 
 	/* constructor func */
@@ -445,18 +454,18 @@ 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
  * global 'mem_map'. These are used to find the slab an obj belongs to.
  * With kfree(), these are used to find the cache which an obj belongs to.
  */
-#define	SET_PAGE_CACHE(pg,x)  ((pg)->list.next = (struct list_head *)(x))
-#define	GET_PAGE_CACHE(pg)    ((kmem_cache_t *)(pg)->list.next)
-#define	SET_PAGE_SLAB(pg,x)   ((pg)->list.prev = (struct list_head *)(x))
-#define	GET_PAGE_SLAB(pg)     ((struct slab *)(pg)->list.prev)
+#define	SET_PAGE_CACHE(pg,x)  ((pg)->lru.next = (struct list_head *)(x))
+#define	GET_PAGE_CACHE(pg)    ((kmem_cache_t *)(pg)->lru.next)
+#define	SET_PAGE_SLAB(pg,x)   ((pg)->lru.prev = (struct list_head *)(x))
+#define	GET_PAGE_SLAB(pg)     ((struct slab *)(pg)->lru.prev)
 
 /* These are the default caches for kmalloc. Custom caches can have other sizes. */
 struct cache_sizes malloc_sizes[] = {
@@ -490,8 +499,10 @@ static kmem_cache_t cache_cache = {
 	.objsize	= sizeof(kmem_cache_t),
 	.flags		= SLAB_NO_REAP,
 	.spinlock	= SPIN_LOCK_UNLOCKED,
-	.colour_off	= L1_CACHE_BYTES,
 	.name		= "kmem_cache",
+#if DEBUG
+	.reallen	= sizeof(kmem_cache_t),
+#endif
 };
 
 /* Guard access to the cache-chain. */
@@ -535,7 +546,7 @@ static inline struct array_cache *ac_dat
 }
 
 /* Cal the num objs, wastage, and bytes left over for a given slab size. */
-static void cache_estimate (unsigned long gfporder, size_t size,
+static void cache_estimate (unsigned long gfporder, size_t size, size_t align,
 		 int flags, size_t *left_over, unsigned int *num)
 {
 	int i;
@@ -548,7 +559,7 @@ static void cache_estimate (unsigned lon
 		extra = sizeof(kmem_bufctl_t);
 	}
 	i = 0;
-	while (i*size + L1_CACHE_ALIGN(base+i*extra) <= wastage)
+	while (i*size + ALIGN(base+i*extra, align) <= wastage)
 		i++;
 	if (i > 0)
 		i--;
@@ -558,7 +569,7 @@ static void cache_estimate (unsigned lon
 
 	*num = i;
 	wastage -= i*size;
-	wastage -= L1_CACHE_ALIGN(base+i*extra);
+	wastage -= ALIGN(base+i*extra, align);
 	*left_over = wastage;
 }
 
@@ -688,16 +699,20 @@ void __init kmem_cache_init(void)
 	init_MUTEX(&cache_chain_sem);
 	INIT_LIST_HEAD(&cache_chain);
 	list_add(&cache_cache.next, &cache_chain);
+	cache_cache.colour_off = cache_line_size();
 	cache_cache.array[smp_processor_id()] = &initarray_cache.cache;
 
-	cache_estimate(0, cache_cache.objsize, 0,
-			&left_over, &cache_cache.num);
+	cache_cache.objsize = ALIGN(cache_cache.objsize, cache_line_size());
+
+	cache_estimate(0, cache_cache.objsize, cache_line_size(), 0,
+				&left_over, &cache_cache.num);
 	if (!cache_cache.num)
 		BUG();
 
 	cache_cache.colour = left_over/cache_cache.colour_off;
 	cache_cache.colour_next = 0;
-
+	cache_cache.slab_size = ALIGN(cache_cache.num*sizeof(kmem_bufctl_t) +
+				sizeof(struct slab), cache_line_size());
 
 	/* 2+3) create the kmalloc caches */
 	sizes = malloc_sizes;
@@ -711,7 +726,7 @@ void __init kmem_cache_init(void)
 		 * allow tighter packing of the smaller caches. */
 		sizes->cs_cachep = kmem_cache_create(
 			names->name, sizes->cs_size,
-			0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+			ARCH_KMALLOC_MINALIGN, 0, NULL, NULL);
 		if (!sizes->cs_cachep)
 			BUG();
 
@@ -723,7 +738,7 @@ void __init kmem_cache_init(void)
 
 		sizes->cs_dmacachep = kmem_cache_create(
 			names->name_dma, sizes->cs_size,
-			0, SLAB_CACHE_DMA|SLAB_HWCACHE_ALIGN, NULL, NULL);
+			ARCH_KMALLOC_MINALIGN, SLAB_CACHE_DMA, NULL, NULL);
 		if (!sizes->cs_dmacachep)
 			BUG();
 
@@ -914,7 +929,7 @@ static void print_objinfo(kmem_cache_t *
 		printk("\n");
 	}
 	realobj = (char*)objp+obj_dbghead(cachep);
-	size = cachep->objsize;
+	size = obj_reallen(cachep);
 	for (i=0; i<size && lines;i+=16, lines--) {
 		int limit;
 		limit = 16;
@@ -1039,7 +1054,7 @@ static void slab_destroy (kmem_cache_t *
  * kmem_cache_create - Create a cache.
  * @name: A string which is used in /proc/slabinfo to identify this cache.
  * @size: The size of objects to be created in this cache.
- * @offset: The offset to use within the page.
+ * @align: The required alignment for the objects.
  * @flags: SLAB flags
  * @ctor: A constructor for the objects.
  * @dtor: A destructor for the objects.
@@ -1064,16 +1079,15 @@ static void slab_destroy (kmem_cache_t *
  * %SLAB_NO_REAP - Don't automatically reap this cache when we're under
  * memory pressure.
  *
- * %SLAB_HWCACHE_ALIGN - Align the objects in this cache to a hardware
- * cacheline.  This can be beneficial if you're counting cycles as closely
- * as davem.
+ * %SLAB_HWCACHE_ALIGN - This flag has no effect and will be removed soon.
+ *
  */
 kmem_cache_t *
-kmem_cache_create (const char *name, size_t size, size_t offset,
+kmem_cache_create (const char *name, size_t size, size_t align,
 	unsigned long flags, void (*ctor)(void*, kmem_cache_t *, unsigned long),
 	void (*dtor)(void*, kmem_cache_t *, unsigned long))
 {
-	size_t left_over, align, slab_size;
+	size_t left_over, slab_size;
 	kmem_cache_t *cachep = NULL;
 
 	/*
@@ -1084,7 +1098,7 @@ kmem_cache_create (const char *name, siz
 		(size < BYTES_PER_WORD) ||
 		(size > (1<<MAX_OBJ_ORDER)*PAGE_SIZE) ||
 		(dtor && !ctor) ||
-		(offset < 0 || offset > size)) {
+		(align < 0)) {
 			printk(KERN_ERR "%s: Early error in slab %s\n",
 					__FUNCTION__, name);
 			BUG();
@@ -1101,22 +1115,16 @@ kmem_cache_create (const char *name, siz
 
 #if FORCED_DEBUG
 	/*
-	 * Enable redzoning and last user accounting, except
-	 * - for caches with forced alignment: redzoning would violate the
-	 *   alignment
-	 * - for caches with large objects, if the increased size would
-	 *   increase the object size above the next power of two: caches
-	 *   with object sizes just above a power of two have a significant
-	 *   amount of internal fragmentation
+	 * Enable redzoning and last user accounting, except for caches with
+	 * large objects, if the increased size would increase the object size
+	 * above the next power of two: caches with object sizes just above a
+	 * power of two have a significant amount of internal fragmentation.
 	 */
-	if ((size < 4096 || fls(size-1) == fls(size-1+3*BYTES_PER_WORD))
-			&& !(flags & SLAB_MUST_HWCACHE_ALIGN)) {
+	if ((size < 4096 || fls(size-1) == fls(size-1+3*BYTES_PER_WORD)))
 		flags |= SLAB_RED_ZONE|SLAB_STORE_USER;
-	}
 	flags |= SLAB_POISON;
 #endif
 #endif
-
 	/*
 	 * Always checks flags, a caller might be expecting debug
 	 * support which isn't available.
@@ -1124,15 +1132,23 @@ kmem_cache_create (const char *name, siz
 	if (flags & ~CREATE_MASK)
 		BUG();
 
+	if (align) {
+		/* minimum supported alignment: */
+		if (align < BYTES_PER_WORD)
+			align = BYTES_PER_WORD;
+
+		/* combinations of forced alignment and advanced debugging is
+		 * not yet implemented.
+		 */
+		flags &= ~(SLAB_RED_ZONE|SLAB_STORE_USER);
+	}
+
 	/* Get cache's description obj. */
 	cachep = (kmem_cache_t *) kmem_cache_alloc(&cache_cache, SLAB_KERNEL);
 	if (!cachep)
 		goto opps;
 	memset(cachep, 0, sizeof(kmem_cache_t));
 
-#if DEBUG
-	cachep->reallen = size;
-#endif
 	/* Check that size is in terms of words.  This is needed to avoid
 	 * unaligned accesses for some archs when redzoning is used, and makes
 	 * sure any on-slab bufctl's are also correctly aligned.
@@ -1143,30 +1159,31 @@ kmem_cache_create (const char *name, siz
 	}
 	
 #if DEBUG
+	cachep->reallen = size;
+
 	if (flags & SLAB_RED_ZONE) {
-		/*
-		 * There is no point trying to honour cache alignment
-		 * when redzoning.
-		 */
-		flags &= ~SLAB_HWCACHE_ALIGN;
+		/* redzoning only works with word aligned caches */
+		align = BYTES_PER_WORD;
+
 		/* add space for red zone words */
 		cachep->dbghead += BYTES_PER_WORD;
 		size += 2*BYTES_PER_WORD;
 	}
 	if (flags & SLAB_STORE_USER) {
-		flags &= ~SLAB_HWCACHE_ALIGN;
-		size += BYTES_PER_WORD; /* add space */
+		/* user store requires word alignment and
+		 * one word storage behind the end of the real
+		 * object.
+		 */
+		align = BYTES_PER_WORD;
+		size += BYTES_PER_WORD;
 	}
 #if FORCED_DEBUG && defined(CONFIG_DEBUG_PAGEALLOC)
-	if (size > 128 && cachep->reallen > L1_CACHE_BYTES && size < PAGE_SIZE) {
+	if (size > 128 && cachep->reallen > cache_line_size() && size < PAGE_SIZE) {
 		cachep->dbghead += PAGE_SIZE - size;
 		size = PAGE_SIZE;
 	}
 #endif
 #endif
-	align = BYTES_PER_WORD;
-	if (flags & SLAB_HWCACHE_ALIGN)
-		align = L1_CACHE_BYTES;
 
 	/* Determine if the slab management is 'on' or 'off' slab. */
 	if (size >= (PAGE_SIZE>>3))
@@ -1176,13 +1193,16 @@ kmem_cache_create (const char *name, siz
 		 */
 		flags |= CFLGS_OFF_SLAB;
 
-	if (flags & SLAB_HWCACHE_ALIGN) {
-		/* Need to adjust size so that objs are cache aligned. */
-		/* Small obj size, can get at least two per cache line. */
+	if (!align) {
+		/* Default alignment: compile time specified l1 cache size.
+		 * Except if an object is really small, then squeeze multiple
+		 * into one cacheline.
+		 */
+		align = cache_line_size();
 		while (size <= align/2)
 			align /= 2;
-		size = (size+align-1)&(~(align-1));
 	}
+	size = ALIGN(size, align);
 
 	/* Cal size (in pages) of slabs, and the num of objs per slab.
 	 * This could be made much more intelligent.  For now, try to avoid
@@ -1192,7 +1212,7 @@ kmem_cache_create (const char *name, siz
 	do {
 		unsigned int break_flag = 0;
 cal_wastage:
-		cache_estimate(cachep->gfporder, size, flags,
+		cache_estimate(cachep->gfporder, size, align, flags,
 						&left_over, &cachep->num);
 		if (break_flag)
 			break;
@@ -1226,7 +1246,8 @@ next:
 		cachep = NULL;
 		goto opps;
 	}
-	slab_size = L1_CACHE_ALIGN(cachep->num*sizeof(kmem_bufctl_t)+sizeof(struct slab));
+	slab_size = ALIGN(cachep->num*sizeof(kmem_bufctl_t)
+				+ sizeof(struct slab), align);
 
 	/*
 	 * If the slab has been placed off-slab, and we have enough space then
@@ -1237,14 +1258,17 @@ next:
 		left_over -= slab_size;
 	}
 
-	/* Offset must be a multiple of the alignment. */
-	offset += (align-1);
-	offset &= ~(align-1);
-	if (!offset)
-		offset = L1_CACHE_BYTES;
-	cachep->colour_off = offset;
-	cachep->colour = left_over/offset;
+	if (flags & CFLGS_OFF_SLAB) {
+		/* really off slab. No need for manual alignment */
+		slab_size = cachep->num*sizeof(kmem_bufctl_t)+sizeof(struct slab);
+	}
 
+	cachep->colour_off = cache_line_size();
+	/* Offset must be a multiple of the alignment. */
+	if (cachep->colour_off < align)
+		cachep->colour_off = align;
+	cachep->colour = left_over/cachep->colour_off;
+	cachep->slab_size = slab_size;
 	cachep->flags = flags;
 	cachep->gfpflags = 0;
 	if (flags & SLAB_CACHE_DMA)
@@ -1270,10 +1294,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;
@@ -1287,7 +1314,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);
@@ -1300,16 +1327,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(); 
 			}	
@@ -1512,8 +1547,7 @@ static inline struct slab* alloc_slabmgm
 			return NULL;
 	} else {
 		slabp = objp+colour_off;
-		colour_off += L1_CACHE_ALIGN(cachep->num *
-				sizeof(kmem_bufctl_t) + sizeof(struct slab));
+		colour_off += cachep->slab_size;
 	}
 	slabp->inuse = 0;
 	slabp->colouroff = colour_off;
@@ -1934,6 +1968,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;
@@ -1995,12 +2038,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);
@@ -2781,6 +2826,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
@@ -2821,9 +2889,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-03-11 10:20:29.000000000 +0000
+++ source/mm/swap.c	2004-03-16 09:37:58.074711472 +0000
@@ -67,7 +67,7 @@ int rotate_reclaimable_page(struct page 
 		list_add_tail(&page->lru, &zone->inactive_list);
 		inc_page_state(pgrotated);
 	}
-	if (!TestClearPageWriteback(page))
+	if (!test_clear_page_writeback(page))
 		BUG();
 	spin_unlock_irqrestore(&zone->lru_lock, flags);
 	return 0;
@@ -350,13 +350,21 @@ void pagevec_strip(struct pagevec *pvec)
  *
  * pagevec_lookup() returns the number of pages which were found.
  */
-unsigned int pagevec_lookup(struct pagevec *pvec, struct address_space *mapping,
-		pgoff_t start, unsigned int nr_pages)
+unsigned pagevec_lookup(struct pagevec *pvec, struct address_space *mapping,
+		pgoff_t start, unsigned nr_pages)
 {
 	pvec->nr = find_get_pages(mapping, start, nr_pages, pvec->pages);
 	return pagevec_count(pvec);
 }
 
+unsigned pagevec_lookup_tag(struct pagevec *pvec, struct address_space *mapping,
+		pgoff_t *index, int tag, unsigned nr_pages)
+{
+	pvec->nr = find_get_pages_tag(mapping, index, tag,
+					nr_pages, pvec->pages);
+	return pagevec_count(pvec);
+}
+
 
 #ifdef CONFIG_SMP
 /*
--- diff/mm/swap_state.c	2003-08-20 13:16:34.000000000 +0000
+++ source/mm/swap_state.c	2004-03-16 09:37:58.074711472 +0000
@@ -19,17 +19,14 @@
 static struct backing_dev_info swap_backing_dev_info = {
 	.ra_pages	= 0,	/* No readahead */
 	.memory_backed	= 1,	/* Does not contribute to dirty memory */
+	.unplug_io_fn	= swap_unplug_io_fn,
 };
 
 extern struct address_space_operations swap_aops;
 
 struct address_space swapper_space = {
 	.page_tree	= RADIX_TREE_INIT(GFP_ATOMIC),
-	.page_lock	= SPIN_LOCK_UNLOCKED,
-	.clean_pages	= LIST_HEAD_INIT(swapper_space.clean_pages),
-	.dirty_pages	= LIST_HEAD_INIT(swapper_space.dirty_pages),
-	.io_pages	= LIST_HEAD_INIT(swapper_space.io_pages),
-	.locked_pages	= LIST_HEAD_INIT(swapper_space.locked_pages),
+	.tree_lock	= SPIN_LOCK_UNLOCKED,
 	.a_ops		= &swap_aops,
 	.backing_dev_info = &swap_backing_dev_info,
 	.i_mmap		= LIST_HEAD_INIT(swapper_space.i_mmap),
@@ -149,7 +146,7 @@ int add_to_swap(struct page * page)
 		switch (err) {
 		case 0:				/* Success */
 			SetPageUptodate(page);
-			ClearPageDirty(page);
+			__clear_page_dirty(page);
 			set_page_dirty(page);
 			INC_CACHE_INFO(add_total);
 			return 1;
@@ -182,9 +179,9 @@ void delete_from_swap_cache(struct page 
   
 	entry.val = page->index;
 
-	spin_lock(&swapper_space.page_lock);
+	spin_lock_irq(&swapper_space.tree_lock);
 	__delete_from_swap_cache(page);
-	spin_unlock(&swapper_space.page_lock);
+	spin_unlock_irq(&swapper_space.tree_lock);
 
 	swap_free(entry);
 	page_cache_release(page);
@@ -195,8 +192,8 @@ int move_to_swap_cache(struct page *page
 	struct address_space *mapping = page->mapping;
 	int err;
 
-	spin_lock(&swapper_space.page_lock);
-	spin_lock(&mapping->page_lock);
+	spin_lock_irq(&swapper_space.tree_lock);
+	spin_lock(&mapping->tree_lock);
 
 	err = radix_tree_insert(&swapper_space.page_tree, entry.val, page);
 	if (!err) {
@@ -204,13 +201,12 @@ int move_to_swap_cache(struct page *page
 		___add_to_page_cache(page, &swapper_space, entry.val);
 	}
 
-	spin_unlock(&mapping->page_lock);
-	spin_unlock(&swapper_space.page_lock);
+	spin_unlock(&mapping->tree_lock);
+	spin_unlock_irq(&swapper_space.tree_lock);
 
 	if (!err) {
 		if (!swap_duplicate(entry))
 			BUG();
-		/* shift page from clean_pages to dirty_pages list */
 		BUG_ON(PageDirty(page));
 		set_page_dirty(page);
 		INC_CACHE_INFO(add_total);
@@ -231,8 +227,8 @@ int move_from_swap_cache(struct page *pa
 
 	entry.val = page->index;
 
-	spin_lock(&swapper_space.page_lock);
-	spin_lock(&mapping->page_lock);
+	spin_lock_irq(&swapper_space.tree_lock);
+	spin_lock(&mapping->tree_lock);
 
 	err = radix_tree_insert(&mapping->page_tree, index, page);
 	if (!err) {
@@ -240,13 +236,12 @@ int move_from_swap_cache(struct page *pa
 		___add_to_page_cache(page, mapping, index);
 	}
 
-	spin_unlock(&mapping->page_lock);
-	spin_unlock(&swapper_space.page_lock);
+	spin_unlock(&mapping->tree_lock);
+	spin_unlock_irq(&swapper_space.tree_lock);
 
 	if (!err) {
 		swap_free(entry);
-		/* shift page from clean_pages to dirty_pages list */
-		ClearPageDirty(page);
+		__clear_page_dirty(page);
 		set_page_dirty(page);
 	}
 	return err;
--- diff/mm/swapfile.c	2004-02-18 08:54:13.000000000 +0000
+++ source/mm/swapfile.c	2004-03-16 09:37:58.076711168 +0000
@@ -23,6 +23,7 @@
 #include <linux/module.h>
 #include <linux/rmap-locking.h>
 #include <linux/security.h>
+#include <linux/backing-dev.h>
 
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
@@ -44,8 +45,64 @@ struct swap_list_t swap_list = {-1, -1};
 
 struct swap_info_struct swap_info[MAX_SWAPFILES];
 
+/*
+ * Array of backing blockdevs, for swap_unplug_fn.  We need this because the
+ * bdev->unplug_fn can sleep and we cannot hold swap_list_lock while calling
+ * the unplug_fn.  And swap_list_lock cannot be turned into a semaphore.
+ */
+static DECLARE_MUTEX(swap_bdevs_sem);
+static struct block_device *swap_bdevs[MAX_SWAPFILES];
+
 #define SWAPFILE_CLUSTER 256
 
+/*
+ * Caller holds swap_bdevs_sem
+ */
+static void install_swap_bdev(struct block_device *bdev)
+{
+	int i;
+
+	for (i = 0; i < MAX_SWAPFILES; i++) {
+		if (swap_bdevs[i] == NULL) {
+			swap_bdevs[i] = bdev;
+			return;
+		}
+	}
+	BUG();
+}
+
+static void remove_swap_bdev(struct block_device *bdev)
+{
+	int i;
+
+	for (i = 0; i < MAX_SWAPFILES; i++) {
+		if (swap_bdevs[i] == bdev) {
+			memcpy(&swap_bdevs[i], &swap_bdevs[i + 1],
+				(MAX_SWAPFILES - i - 1) * sizeof(*swap_bdevs));
+			swap_bdevs[MAX_SWAPFILES - 1] = NULL;
+			return;
+		}
+	}
+	BUG();
+}
+
+void swap_unplug_io_fn(struct backing_dev_info *unused_bdi)
+{
+	int i;
+
+	down(&swap_bdevs_sem);
+	for (i = 0; i < MAX_SWAPFILES; i++) {
+		struct block_device *bdev = swap_bdevs[i];
+		struct backing_dev_info *bdi;
+
+		if (bdev == NULL)
+			break;
+		bdi = bdev->bd_inode->i_mapping->backing_dev_info;
+		(*bdi->unplug_io_fn)(bdi);
+	}
+	up(&swap_bdevs_sem);
+}
+
 static inline int scan_swap_map(struct swap_info_struct *si)
 {
 	unsigned long offset;
@@ -253,10 +310,10 @@ static int exclusive_swap_page(struct pa
 		/* Is the only swap cache user the cache itself? */
 		if (p->swap_map[swp_offset(entry)] == 1) {
 			/* Recheck the page count with the pagecache lock held.. */
-			spin_lock(&swapper_space.page_lock);
+			spin_lock_irq(&swapper_space.tree_lock);
 			if (page_count(page) - !!PagePrivate(page) == 2)
 				retval = 1;
-			spin_unlock(&swapper_space.page_lock);
+			spin_unlock_irq(&swapper_space.tree_lock);
 		}
 		swap_info_put(p);
 	}
@@ -324,13 +381,13 @@ int remove_exclusive_swap_page(struct pa
 	retval = 0;
 	if (p->swap_map[swp_offset(entry)] == 1) {
 		/* Recheck the page count with the pagecache lock held.. */
-		spin_lock(&swapper_space.page_lock);
+		spin_lock_irq(&swapper_space.tree_lock);
 		if ((page_count(page) == 2) && !PageWriteback(page)) {
 			__delete_from_swap_cache(page);
 			SetPageDirty(page);
 			retval = 1;
 		}
-		spin_unlock(&swapper_space.page_lock);
+		spin_unlock_irq(&swapper_space.tree_lock);
 	}
 	swap_info_put(p);
 
@@ -387,7 +444,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);
@@ -1088,6 +1145,7 @@ asmlinkage long sys_swapoff(const char _
 		swap_list_unlock();
 		goto out_dput;
 	}
+	down(&swap_bdevs_sem);
 	swap_list_lock();
 	swap_device_lock(p);
 	swap_file = p->swap_file;
@@ -1099,6 +1157,8 @@ asmlinkage long sys_swapoff(const char _
 	destroy_swap_extents(p);
 	swap_device_unlock(p);
 	swap_list_unlock();
+	remove_swap_bdev(p->bdev);
+	up(&swap_bdevs_sem);
 	vfree(swap_map);
 	if (S_ISBLK(mapping->host->i_mode)) {
 		struct block_device *bdev = I_BDEV(mapping->host);
@@ -1412,6 +1472,7 @@ asmlinkage long sys_swapon(const char __
 	if (error)
 		goto bad_swap;
 
+	down(&swap_bdevs_sem);
 	swap_list_lock();
 	swap_device_lock(p);
 	p->flags = SWP_ACTIVE;
@@ -1437,6 +1498,8 @@ asmlinkage long sys_swapon(const char __
 	}
 	swap_device_unlock(p);
 	swap_list_unlock();
+	install_swap_bdev(p->bdev);
+	up(&swap_bdevs_sem);
 	error = 0;
 	goto out;
 bad_swap:
--- diff/mm/truncate.c	2003-10-09 08:47:34.000000000 +0000
+++ source/mm/truncate.c	2004-03-16 09:37:58.076711168 +0000
@@ -62,7 +62,7 @@ truncate_complete_page(struct address_sp
  * This is for invalidate_inode_pages().  That function can be called at
  * any time, and is not supposed to throw away dirty pages.  But pages can
  * be marked dirty at any time too.  So we re-check the dirtiness inside
- * ->page_lock.  That provides exclusion against the __set_page_dirty
+ * ->tree_lock.  That provides exclusion against the __set_page_dirty
  * functions.
  */
 static int
@@ -74,13 +74,13 @@ invalidate_complete_page(struct address_
 	if (PagePrivate(page) && !try_to_release_page(page, 0))
 		return 0;
 
-	spin_lock(&mapping->page_lock);
+	spin_lock_irq(&mapping->tree_lock);
 	if (PageDirty(page)) {
-		spin_unlock(&mapping->page_lock);
+		spin_unlock_irq(&mapping->tree_lock);
 		return 0;
 	}
 	__remove_from_page_cache(page);
-	spin_unlock(&mapping->page_lock);
+	spin_unlock_irq(&mapping->tree_lock);
 	ClearPageUptodate(page);
 	page_cache_release(page);	/* pagecache ref */
 	return 1;
@@ -174,6 +174,9 @@ void truncate_inode_pages(struct address
 		}
 		pagevec_release(&pvec);
 	}
+
+	if (lstart == 0)
+		WARN_ON(mapping->nrpages);
 }
 
 EXPORT_SYMBOL(truncate_inode_pages);
@@ -219,6 +222,8 @@ unsigned long invalidate_mapping_pages(s
 			ret += invalidate_complete_page(mapping, page);
 unlock:
 			unlock_page(page);
+			if (next > end)
+				break;
 		}
 		pagevec_release(&pvec);
 		cond_resched();
--- diff/mm/vmscan.c	2004-02-18 08:54:13.000000000 +0000
+++ source/mm/vmscan.c	2004-03-16 09:37:58.079710712 +0000
@@ -43,14 +43,15 @@
 int vm_swappiness = 60;
 static long total_memory;
 
+#define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru))
+
 #ifdef ARCH_HAS_PREFETCH
 #define prefetch_prev_lru_page(_page, _base, _field)			\
 	do {								\
 		if ((_page)->lru.prev != _base) {			\
 			struct page *prev;				\
 									\
-			prev = list_entry(_page->lru.prev,		\
-					struct page, lru);		\
+			prev = lru_to_page(&(_page->lru));		\
 			prefetch(&prev->_field);			\
 		}							\
 	} while (0)
@@ -64,8 +65,7 @@ static long total_memory;
 		if ((_page)->lru.prev != _base) {			\
 			struct page *prev;				\
 									\
-			prev = list_entry(_page->lru.prev,		\
-					struct page, lru);		\
+			prev = lru_to_page(&(_page->lru));			\
 			prefetchw(&prev->_field);			\
 		}							\
 	} while (0)
@@ -135,7 +135,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 +147,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 +155,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 +244,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);
@@ -260,7 +260,7 @@ shrink_list(struct list_head *page_list,
 		int may_enter_fs;
 		int referenced;
 
-		page = list_entry(page_list->prev, struct page, lru);
+		page = lru_to_page(page_list);
 		list_del(&page->lru);
 
 		if (TestSetPageLocked(page))
@@ -268,7 +268,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));
 
@@ -352,7 +352,6 @@ shrink_list(struct list_head *page_list,
 				goto keep_locked;
 			if (!may_write_to_queue(mapping->backing_dev_info))
 				goto keep_locked;
-			spin_lock(&mapping->page_lock);
 			if (test_clear_page_dirty(page)) {
 				int res;
 				struct writeback_control wbc = {
@@ -362,9 +361,6 @@ shrink_list(struct list_head *page_list,
 					.for_reclaim = 1,
 				};
 
-				list_move(&page->list, &mapping->locked_pages);
-				spin_unlock(&mapping->page_lock);
-
 				SetPageReclaim(page);
 				res = mapping->a_ops->writepage(page, &wbc);
 				if (res < 0)
@@ -379,7 +375,6 @@ shrink_list(struct list_head *page_list,
 				}
 				goto keep;
 			}
-			spin_unlock(&mapping->page_lock);
 		}
 
 		/*
@@ -413,7 +408,7 @@ shrink_list(struct list_head *page_list,
 		if (!mapping)
 			goto keep_locked;	/* truncate got there first */
 
-		spin_lock(&mapping->page_lock);
+		spin_lock_irq(&mapping->tree_lock);
 
 		/*
 		 * The non-racy check for busy page.  It is critical to check
@@ -421,7 +416,7 @@ shrink_list(struct list_head *page_list,
 		 * not in use by anybody. 	(pagecache + us == 2)
 		 */
 		if (page_count(page) != 2 || PageDirty(page)) {
-			spin_unlock(&mapping->page_lock);
+			spin_unlock_irq(&mapping->tree_lock);
 			goto keep_locked;
 		}
 
@@ -429,7 +424,7 @@ shrink_list(struct list_head *page_list,
 		if (PageSwapCache(page)) {
 			swp_entry_t swap = { .val = page->index };
 			__delete_from_swap_cache(page);
-			spin_unlock(&mapping->page_lock);
+			spin_unlock_irq(&mapping->tree_lock);
 			swap_free(swap);
 			__put_page(page);	/* The pagecache ref */
 			goto free_it;
@@ -437,7 +432,7 @@ shrink_list(struct list_head *page_list,
 #endif /* CONFIG_SWAP */
 
 		__remove_from_page_cache(page);
-		spin_unlock(&mapping->page_lock);
+		spin_unlock_irq(&mapping->tree_lock);
 		__put_page(page);
 
 free_it:
@@ -459,9 +454,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,42 +463,33 @@ 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);
+			page = lru_to_page(&zone->inactive_list);
 
 			prefetchw_prev_lru_page(page,
 						&zone->inactive_list, flags);
@@ -532,9 +515,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;
@@ -544,7 +534,7 @@ shrink_cache(const int nr_pages, struct 
 		 * Put back any unfreeable pages.
 		 */
 		while (!list_empty(&page_list)) {
-			page = list_entry(page_list.prev, struct page, lru);
+			page = lru_to_page(&page_list);
 			if (TestSetPageLRU(page))
 				BUG();
 			list_del(&page->lru);
@@ -584,7 +574,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;
@@ -603,7 +593,7 @@ refill_inactive_zone(struct zone *zone, 
 	pgmoved = 0;
 	spin_lock_irq(&zone->lru_lock);
 	while (nr_pages && !list_empty(&zone->active_list)) {
-		page = list_entry(zone->active_list.prev, struct page, lru);
+		page = lru_to_page(&zone->active_list);
 		prefetchw_prev_lru_page(page, &zone->active_list, flags);
 		if (!TestClearPageLRU(page))
 			BUG();
@@ -654,20 +644,20 @@ refill_inactive_zone(struct zone *zone, 
 		reclaim_mapped = 1;
 
 	while (!list_empty(&l_hold)) {
-		page = list_entry(l_hold.prev, struct page, lru);
+		page = lru_to_page(&l_hold);
 		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
@@ -685,7 +675,7 @@ refill_inactive_zone(struct zone *zone, 
 	pgmoved = 0;
 	spin_lock_irq(&zone->lru_lock);
 	while (!list_empty(&l_inactive)) {
-		page = list_entry(l_inactive.prev, struct page, lru);
+		page = lru_to_page(&l_inactive);
 		prefetchw_prev_lru_page(page, &l_inactive, flags);
 		if (TestSetPageLRU(page))
 			BUG();
@@ -714,7 +704,7 @@ refill_inactive_zone(struct zone *zone, 
 
 	pgmoved = 0;
 	while (!list_empty(&l_active)) {
-		page = list_entry(l_active.prev, struct page, lru);
+		page = lru_to_page(&l_active);
 		prefetchw_prev_lru_page(page, &l_active, flags);
 		if (TestSetPageLRU(page))
 			BUG();
@@ -733,20 +723,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 +748,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);
 	}
-	return shrink_cache(nr_pages, zone, gfp_mask,
-				max_scan, nr_mapped);
+
+	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 0;
 }
 
 /*
@@ -798,15 +785,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 +800,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 +828,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 +843,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 +863,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 +891,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 +916,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;
 
--- diff/net/Kconfig	2004-03-11 10:20:29.000000000 +0000
+++ source/net/Kconfig	2004-03-16 09:37:58.079710712 +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 08:47:34.000000000 +0000
+++ source/net/Makefile	2004-03-16 09:37:58.080710560 +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/core/Makefile	2003-09-17 11:28:12.000000000 +0000
+++ source/net/core/Makefile	2004-03-16 09:37:58.080710560 +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-11 10:20:29.000000000 +0000
+++ source/net/core/dev.c	2004-03-16 09:37:58.082710256 +0000
@@ -105,6 +105,7 @@
 #include <linux/kmod.h>
 #include <linux/module.h>
 #include <linux/kallsyms.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 +1514,6 @@ static void sample_queue(unsigned long d
 }
 #endif
 
-
 /**
  *	netif_rx	-	post buffer to the network code
  *	@skb: buffer to post
@@ -1538,6 +1538,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 +1700,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 +1833,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 +1859,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();
--- diff/net/ipv4/devinet.c	2004-03-11 10:20:29.000000000 +0000
+++ source/net/ipv4/devinet.c	2004-03-16 09:37:58.083710104 +0000
@@ -1210,11 +1210,11 @@ int ipv4_doint_and_flush_strategy(ctl_ta
 
 static struct devinet_sysctl_table {
 	struct ctl_table_header *sysctl_header;
-	ctl_table		devinet_vars[20];
-	ctl_table		devinet_dev[2];
-	ctl_table		devinet_conf_dir[2];
-	ctl_table		devinet_proto_dir[2];
-	ctl_table		devinet_root_dir[2];
+	ctl_table		devinet_vars[21];
+	ctl_table		devinet_dev[3];
+	ctl_table		devinet_conf_dir[3];
+	ctl_table		devinet_proto_dir[3];
+	ctl_table		devinet_root_dir[3];
 } devinet_sysctl = {
 	.devinet_vars = {
 		{
@@ -1372,6 +1372,7 @@ static struct devinet_sysctl_table {
 			.proc_handler	= &ipv4_doint_and_flush,
 			.strategy	= &ipv4_doint_and_flush_strategy,
 		},
+		{ .ctl_name = 0 }
 	},
 	.devinet_dev = {
 		{
@@ -1380,6 +1381,7 @@ static struct devinet_sysctl_table {
 			.mode		= 0555,
 			.child		= devinet_sysctl.devinet_vars,
 		},
+		{ .ctl_name = 0 }
 	},
 	.devinet_conf_dir = {
 	        {
@@ -1388,6 +1390,7 @@ static struct devinet_sysctl_table {
 			.mode		= 0555,
 			.child		= devinet_sysctl.devinet_dev,
 		},
+		{ .ctl_name = 0 }
 	},
 	.devinet_proto_dir = {
 		{
@@ -1396,6 +1399,7 @@ static struct devinet_sysctl_table {
 			.mode		= 0555,
 			.child 		= devinet_sysctl.devinet_conf_dir,
 		},
+		{ .ctl_name = 0 }
 	},
 	.devinet_root_dir = {
 		{
@@ -1404,6 +1408,7 @@ static struct devinet_sysctl_table {
 			.mode		= 0555,
 			.child		= devinet_sysctl.devinet_proto_dir,
 		},
+		{ .ctl_name = 0 }
 	},
 };
 
--- diff/net/ipv4/ipconfig.c	2004-03-11 10:20:29.000000000 +0000
+++ source/net/ipv4/ipconfig.c	2004-03-16 09:37:58.085709800 +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/netfilter/ipt_owner.c	2004-02-18 08:54:13.000000000 +0000
+++ source/net/ipv4/netfilter/ipt_owner.c	2004-03-16 09:37:58.085709800 +0000
@@ -95,7 +95,7 @@ match_sid(const struct sk_buff *skb, pid
 	read_lock(&tasklist_lock);
 	do_each_thread(g, p) {
 		struct files_struct *files;
-		if (p->session != sid)
+		if (p->signal->session != sid)
 			continue;
 
 		task_lock(p);
--- diff/net/ipv6/netfilter/ip6t_owner.c	2004-02-18 08:54:13.000000000 +0000
+++ source/net/ipv6/netfilter/ip6t_owner.c	2004-03-16 09:37:58.086709648 +0000
@@ -61,7 +61,7 @@ match_sid(const struct sk_buff *skb, pid
 	read_lock(&tasklist_lock);
 	do_each_thread(g, p) {
 		struct files_struct *files;
-		if (p->session != sid)
+		if (p->signal->session != sid)
 			continue;
 
 		task_lock(p);
--- diff/net/netlink/netlink_dev.c	2003-09-17 11:28:12.000000000 +0000
+++ source/net/netlink/netlink_dev.c	2004-03-16 09:37:58.086709648 +0000
@@ -27,6 +27,7 @@
 #include <linux/init.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/smp_lock.h>
+#include <linux/device.h>
 
 #include <asm/bitops.h>
 #include <asm/system.h>
@@ -34,6 +35,7 @@
 
 static long open_map;
 static struct socket *netlink_user[MAX_LINKS];
+static struct class_simple *netlink_class;
 
 /*
  *	Device operations
@@ -229,17 +231,26 @@ static int __init init_netlink(void)
 		return -EIO;
 	}
 
+	netlink_class = class_simple_create(THIS_MODULE, "netlink");
+	if (IS_ERR(netlink_class)) {
+		printk (KERN_ERR "Error creating netlink class.\n");
+		unregister_chrdev(NETLINK_MAJOR, "netlink");
+		return PTR_ERR(netlink_class);
+	}
+
 	devfs_mk_dir("netlink");
 
 	/*  Someone tell me the official names for the uppercase ones  */
 	for (i = 0; i < ARRAY_SIZE(entries); i++) {
 		devfs_mk_cdev(MKDEV(NETLINK_MAJOR, entries[i].minor),
 			S_IFCHR|S_IRUSR|S_IWUSR, "netlink/%s", entries[i].name);
+		class_simple_device_add(netlink_class, MKDEV(NETLINK_MAJOR, entries[i].minor), NULL, "%s", entries[i].name);
 	}
 
 	for (i = 0; i < 16; i++) {
 		devfs_mk_cdev(MKDEV(NETLINK_MAJOR, i + 16),
 			S_IFCHR|S_IRUSR|S_IWUSR, "netlink/tap%d", i);
+		class_simple_device_add(netlink_class, MKDEV(NETLINK_MAJOR, i + 16), NULL, "tap%d", i);
 	}
 
 	return 0;
@@ -249,11 +260,16 @@ static void __exit cleanup_netlink(void)
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(entries); i++)
+	for (i = 0; i < ARRAY_SIZE(entries); i++) {
 		devfs_remove("netlink/%s", entries[i].name);
-	for (i = 0; i < 16; i++)
+		class_simple_device_remove(MKDEV(NETLINK_MAJOR, entries[i].minor));
+	}
+	for (i = 0; i < 16; i++) {
 		devfs_remove("netlink/tap%d", i);
+		class_simple_device_remove(MKDEV(NETLINK_MAJOR, i + 16));
+	}
 	devfs_remove("netlink");
+	class_simple_destroy(netlink_class);
 	unregister_chrdev(NETLINK_MAJOR, "netlink");
 }
 
--- diff/net/sched/sch_htb.c	2004-03-11 10:20:29.000000000 +0000
+++ source/net/sched/sch_htb.c	2004-03-16 09:37:58.088709344 +0000
@@ -437,13 +437,13 @@ static void htb_add_to_wait_tree (struct
 		cl->pq_key++;
 
 	/* update the nearest event cache */
-	if (q->near_ev_cache[cl->level] - cl->pq_key < 0x80000000)
+	if (time_after(q->near_ev_cache[cl->level], cl->pq_key))
 		q->near_ev_cache[cl->level] = cl->pq_key;
 	
 	while (*p) {
 		struct htb_class *c; parent = *p;
 		c = rb_entry(parent, struct htb_class, pq_node);
-		if (cl->pq_key - c->pq_key < 0x80000000)
+		if (time_after_eq(cl->pq_key, c->pq_key))
 			p = &parent->rb_right;
 		else 
 			p = &parent->rb_left;
@@ -869,7 +869,7 @@ static long htb_do_events(struct htb_sch
 		while (p->rb_left) p = p->rb_left;
 
 		cl = rb_entry(p, struct htb_class, pq_node);
-		if (cl->pq_key - (q->jiffies+1) < 0x80000000) {
+		if (time_after(cl->pq_key, q->jiffies)) {
 			HTB_DBG(8,3,"htb_do_ev_ret delay=%ld\n",cl->pq_key - q->jiffies);
 			return cl->pq_key - q->jiffies;
 		}
@@ -1048,7 +1048,7 @@ static struct sk_buff *htb_dequeue(struc
 		/* common case optimization - skip event handler quickly */
 		int m;
 		long delay;
-		if (q->jiffies - q->near_ev_cache[level] < 0x80000000 || 0) {
+		if (time_after_eq(q->jiffies, q->near_ev_cache[level])) {
 			delay = htb_do_events(q,level);
 			q->near_ev_cache[level] = q->jiffies + (delay ? delay : HZ);
 #ifdef HTB_DEBUG
--- diff/net/sunrpc/auth_gss/auth_gss.c	2004-03-11 10:20:29.000000000 +0000
+++ source/net/sunrpc/auth_gss/auth_gss.c	2004-03-16 09:37:58.088709344 +0000
@@ -365,7 +365,7 @@ retry:
 	gss_msg = gss_new;
 	memset(gss_new, 0, sizeof(*gss_new));
 	INIT_LIST_HEAD(&gss_new->list);
-	INIT_RPC_WAITQ(&gss_new->waitq, "RPCSEC_GSS upcall waitq");
+	rpc_init_wait_queue(&gss_new->waitq, "RPCSEC_GSS upcall waitq");
 	atomic_set(&gss_new->count, 2);
 	msg = &gss_new->msg;
 	msg->data = &gss_new->uid;
--- diff/net/sunrpc/auth_gss/svcauth_gss.c	2004-03-11 10:20:29.000000000 +0000
+++ source/net/sunrpc/auth_gss/svcauth_gss.c	2004-03-16 09:37:58.089709192 +0000
@@ -687,7 +687,7 @@ svcauth_gss_accept(struct svc_rqst *rqst
 	u32		*reject_stat = resv->iov_base;
 	int		ret;
 
-	dprintk("RPC: svcauth_gss: argv->iov_len = %zd\n",argv->iov_len);
+	dprintk("RPC: svcauth_gss: argv->iov_len = %Zd\n",argv->iov_len);
 
 	*authp = rpc_autherr_badcred;
 	if (!svcdata)
--- diff/net/sunrpc/auth_unix.c	2004-03-11 10:20:29.000000000 +0000
+++ source/net/sunrpc/auth_unix.c	2004-03-16 09:37:58.090709040 +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-16 09:37:58.093708584 +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);
@@ -141,7 +144,7 @@ rpc_create_client(struct rpc_xprt *xprt,
 	clnt->cl_vers     = version->number;
 	clnt->cl_prot     = xprt->prot;
 	clnt->cl_stats    = program->stats;
-	INIT_RPC_WAITQ(&clnt->cl_pmap_default.pm_bindwait, "bindwait");
+	rpc_init_wait_queue(&clnt->cl_pmap_default.pm_bindwait, "bindwait");
 
 	if (!clnt->cl_port)
 		clnt->cl_autobind = 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-16 09:37:58.094708432 +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-11 10:20:29.000000000 +0000
+++ source/net/sunrpc/sched.c	2004-03-16 09:37:58.096708128 +0000
@@ -162,6 +162,26 @@ rpc_delete_timer(struct rpc_task *task)
 }
 
 /*
+ * Add new request to a priority queue.
+ */
+static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue, struct rpc_task *task)
+{
+	struct list_head *q;
+	struct rpc_task *t;
+
+	q = &queue->tasks[task->tk_priority];
+	if (unlikely(task->tk_priority > queue->maxpriority))
+		q = &queue->tasks[queue->maxpriority];
+	list_for_each_entry(t, q, tk_list) {
+		if (t->tk_cookie == task->tk_cookie) {
+			list_add_tail(&task->tk_list, &t->tk_links);
+			return;
+		}
+	}
+	list_add_tail(&task->tk_list, q);
+}
+
+/*
  * Add new request to wait queue.
  *
  * Swapper tasks always get inserted at the head of the queue.
@@ -169,8 +189,7 @@ rpc_delete_timer(struct rpc_task *task)
  * improve overall performance.
  * Everyone else gets appended to the queue to ensure proper FIFO behavior.
  */
-static inline int
-__rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task)
+static int __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task)
 {
 	if (task->tk_rpcwait == queue)
 		return 0;
@@ -179,10 +198,12 @@ __rpc_add_wait_queue(struct rpc_wait_que
 		printk(KERN_WARNING "RPC: doubly enqueued task!\n");
 		return -EWOULDBLOCK;
 	}
-	if (RPC_IS_SWAPPER(task))
-		list_add(&task->tk_list, &queue->tasks);
+	if (RPC_IS_PRIORITY(queue))
+		__rpc_add_wait_queue_priority(queue, task);
+	else if (RPC_IS_SWAPPER(task))
+		list_add(&task->tk_list, &queue->tasks[0]);
 	else
-		list_add_tail(&task->tk_list, &queue->tasks);
+		list_add_tail(&task->tk_list, &queue->tasks[0]);
 	task->tk_rpcwait = queue;
 
 	dprintk("RPC: %4d added to queue %p \"%s\"\n",
@@ -191,8 +212,7 @@ __rpc_add_wait_queue(struct rpc_wait_que
 	return 0;
 }
 
-int
-rpc_add_wait_queue(struct rpc_wait_queue *q, struct rpc_task *task)
+int rpc_add_wait_queue(struct rpc_wait_queue *q, struct rpc_task *task)
 {
 	int		result;
 
@@ -203,18 +223,35 @@ rpc_add_wait_queue(struct rpc_wait_queue
 }
 
 /*
+ * Remove request from a priority queue.
+ */
+static void __rpc_remove_wait_queue_priority(struct rpc_task *task)
+{
+	struct rpc_task *t;
+
+	if (!list_empty(&task->tk_links)) {
+		t = list_entry(task->tk_links.next, struct rpc_task, tk_list);
+		list_move(&t->tk_list, &task->tk_list);
+		list_splice_init(&task->tk_links, &t->tk_links);
+	}
+	list_del(&task->tk_list);
+}
+
+/*
  * Remove request from queue.
  * Note: must be called with spin lock held.
  */
-static inline void
-__rpc_remove_wait_queue(struct rpc_task *task)
+static void __rpc_remove_wait_queue(struct rpc_task *task)
 {
 	struct rpc_wait_queue *queue = task->tk_rpcwait;
 
 	if (!queue)
 		return;
 
-	list_del(&task->tk_list);
+	if (RPC_IS_PRIORITY(queue))
+		__rpc_remove_wait_queue_priority(task);
+	else
+		list_del(&task->tk_list);
 	task->tk_rpcwait = NULL;
 
 	dprintk("RPC: %4d removed from queue %p \"%s\"\n",
@@ -231,6 +268,48 @@ rpc_remove_wait_queue(struct rpc_task *t
 	spin_unlock_bh(&rpc_queue_lock);
 }
 
+static inline void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority)
+{
+	queue->priority = priority;
+	queue->count = 1 << (priority * 2);
+}
+
+static inline void rpc_set_waitqueue_cookie(struct rpc_wait_queue *queue, unsigned long cookie)
+{
+	queue->cookie = cookie;
+	queue->nr = RPC_BATCH_COUNT;
+}
+
+static inline void rpc_reset_waitqueue_priority(struct rpc_wait_queue *queue)
+{
+	rpc_set_waitqueue_priority(queue, queue->maxpriority);
+	rpc_set_waitqueue_cookie(queue, 0);
+}
+
+static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname, int maxprio)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(queue->tasks); i++)
+		INIT_LIST_HEAD(&queue->tasks[i]);
+	queue->maxpriority = maxprio;
+	rpc_reset_waitqueue_priority(queue);
+#ifdef RPC_DEBUG
+	queue->name = qname;
+#endif
+}
+
+void rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname)
+{
+	__rpc_init_priority_wait_queue(queue, qname, RPC_PRIORITY_HIGH);
+}
+
+void rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname)
+{
+	__rpc_init_priority_wait_queue(queue, qname, 0);
+}
+EXPORT_SYMBOL(rpc_init_wait_queue);
+
 /*
  * Make an RPC task runnable.
  *
@@ -255,13 +334,11 @@ rpc_make_runnable(struct rpc_task *task)
 				return;
 			}
 			rpc_clear_sleeping(task);
-			if (waitqueue_active(&rpciod_idle))
-				wake_up(&rpciod_idle);
+			wake_up(&rpciod_idle);
 		}
 	} else {
 		rpc_clear_sleeping(task);
-		if (waitqueue_active(&task->tk_wait))
-			wake_up(&task->tk_wait);
+		wake_up(&task->tk_wait);
 	}
 }
 
@@ -287,8 +364,7 @@ void rpciod_wake_up(void)
 {
 	if(rpciod_pid==0)
 		printk(KERN_ERR "rpciod: wot no daemon?\n");
-	if (waitqueue_active(&rpciod_idle))
-		wake_up(&rpciod_idle);
+	wake_up(&rpciod_idle);
 }
 
 /*
@@ -406,17 +482,72 @@ rpc_wake_up_task(struct rpc_task *task)
 }
 
 /*
+ * Wake up the next task on a priority queue.
+ */
+static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queue)
+{
+	struct list_head *q;
+	struct rpc_task *task;
+
+	/*
+	 * Service a batch of tasks from a single cookie.
+	 */
+	q = &queue->tasks[queue->priority];
+	if (!list_empty(q)) {
+		task = list_entry(q->next, struct rpc_task, tk_list);
+		if (queue->cookie == task->tk_cookie) {
+			if (--queue->nr)
+				goto out;
+			list_move_tail(&task->tk_list, q);
+		}
+		/*
+		 * Check if we need to switch queues.
+		 */
+		if (--queue->count)
+			goto new_cookie;
+	}
+
+	/*
+	 * Service the next queue.
+	 */
+	do {
+		if (q == &queue->tasks[0])
+			q = &queue->tasks[queue->maxpriority];
+		else
+			q = q - 1;
+		if (!list_empty(q)) {
+			task = list_entry(q->next, struct rpc_task, tk_list);
+			goto new_queue;
+		}
+	} while (q != &queue->tasks[queue->priority]);
+
+	rpc_reset_waitqueue_priority(queue);
+	return NULL;
+
+new_queue:
+	rpc_set_waitqueue_priority(queue, (unsigned int)(q - &queue->tasks[0]));
+new_cookie:
+	rpc_set_waitqueue_cookie(queue, task->tk_cookie);
+out:
+	__rpc_wake_up_task(task);
+	return task;
+}
+
+/*
  * Wake up the next task on the wait queue.
  */
-struct rpc_task *
-rpc_wake_up_next(struct rpc_wait_queue *queue)
+struct rpc_task * rpc_wake_up_next(struct rpc_wait_queue *queue)
 {
 	struct rpc_task	*task = NULL;
 
 	dprintk("RPC:      wake_up_next(%p \"%s\")\n", queue, rpc_qname(queue));
 	spin_lock_bh(&rpc_queue_lock);
-	task_for_first(task, &queue->tasks)
-		__rpc_wake_up_task(task);
+	if (RPC_IS_PRIORITY(queue))
+		task = __rpc_wake_up_next_priority(queue);
+	else {
+		task_for_first(task, &queue->tasks[0])
+			__rpc_wake_up_task(task);
+	}
 	spin_unlock_bh(&rpc_queue_lock);
 
 	return task;
@@ -428,15 +559,22 @@ rpc_wake_up_next(struct rpc_wait_queue *
  *
  * Grabs rpc_queue_lock
  */
-void
-rpc_wake_up(struct rpc_wait_queue *queue)
+void rpc_wake_up(struct rpc_wait_queue *queue)
 {
 	struct rpc_task *task;
 
+	struct list_head *head;
 	spin_lock_bh(&rpc_queue_lock);
-	while (!list_empty(&queue->tasks))
-		task_for_first(task, &queue->tasks)
+	head = &queue->tasks[queue->maxpriority];
+	for (;;) {
+		while (!list_empty(head)) {
+			task = list_entry(head->next, struct rpc_task, tk_list);
 			__rpc_wake_up_task(task);
+		}
+		if (head == &queue->tasks[0])
+			break;
+		head--;
+	}
 	spin_unlock_bh(&rpc_queue_lock);
 }
 
@@ -447,17 +585,22 @@ rpc_wake_up(struct rpc_wait_queue *queue
  *
  * Grabs rpc_queue_lock
  */
-void
-rpc_wake_up_status(struct rpc_wait_queue *queue, int status)
+void rpc_wake_up_status(struct rpc_wait_queue *queue, int status)
 {
+	struct list_head *head;
 	struct rpc_task *task;
 
 	spin_lock_bh(&rpc_queue_lock);
-	while (!list_empty(&queue->tasks)) {
-		task_for_first(task, &queue->tasks) {
+	head = &queue->tasks[queue->maxpriority];
+	for (;;) {
+		while (!list_empty(head)) {
+			task = list_entry(head->next, struct rpc_task, tk_list);
 			task->tk_status = status;
 			__rpc_wake_up_task(task);
 		}
+		if (head == &queue->tasks[0])
+			break;
+		head--;
 	}
 	spin_unlock_bh(&rpc_queue_lock);
 }
@@ -530,6 +673,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 +691,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) {
@@ -638,21 +786,22 @@ __rpc_schedule(void)
 
 	dprintk("RPC:      rpc_schedule enter\n");
 	while (1) {
-		spin_lock_bh(&rpc_queue_lock);
 
-		task_for_first(task, &schedq.tasks) {
+		task_for_first(task, &schedq.tasks[0]) {
 			__rpc_remove_wait_queue(task);
 			spin_unlock_bh(&rpc_queue_lock);
 
 			__rpc_execute(task);
+			spin_lock_bh(&rpc_queue_lock);
 		} else {
-			spin_unlock_bh(&rpc_queue_lock);
 			break;
 		}
 
 		if (++count >= 200 || need_resched()) {
 			count = 0;
+			spin_unlock_bh(&rpc_queue_lock);
 			schedule();
+			spin_lock_bh(&rpc_queue_lock);
 		}
 	}
 	dprintk("RPC:      rpc_schedule leave\n");
@@ -704,9 +853,7 @@ rpc_free(struct rpc_task *task)
 /*
  * Creation and deletion of RPC task structures
  */
-inline void
-rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt,
-				rpc_action callback, int flags)
+void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, rpc_action callback, int flags)
 {
 	memset(task, 0, sizeof(*task));
 	init_timer(&task->tk_timer);
@@ -724,6 +871,10 @@ rpc_init_task(struct rpc_task *task, str
 	task->tk_cred_retry = 2;
 	task->tk_suid_retry = 1;
 
+	task->tk_priority = RPC_PRIORITY_NORMAL;
+	task->tk_cookie = (unsigned long)current;
+	INIT_LIST_HEAD(&task->tk_links);
+
 	/* Add to global list of all tasks */
 	spin_lock(&rpc_sched_lock);
 	list_add(&task->tk_task, &all_tasks);
@@ -861,7 +1012,7 @@ rpc_find_parent(struct rpc_task *child)
 	struct list_head *le;
 
 	parent = (struct rpc_task *) child->tk_calldata;
-	task_for_each(task, le, &childq.tasks)
+	task_for_each(task, le, &childq.tasks[0])
 		if (task == parent)
 			return parent;
 
@@ -941,7 +1092,7 @@ static DECLARE_MUTEX_LOCKED(rpciod_runni
 static inline int
 rpciod_task_pending(void)
 {
-	return !list_empty(&schedq.tasks);
+	return !list_empty(&schedq.tasks[0]);
 }
 
 
@@ -964,27 +1115,41 @@ rpciod(void *ptr)
 	allow_signal(SIGKILL);
 
 	dprintk("RPC: rpciod starting (pid %d)\n", rpciod_pid);
+	spin_lock_bh(&rpc_queue_lock);
 	while (rpciod_users) {
+		DEFINE_WAIT(wait);
 		if (signalled()) {
+			spin_unlock_bh(&rpc_queue_lock);
 			rpciod_killall();
 			flush_signals(current);
+			spin_lock_bh(&rpc_queue_lock);
 		}
 		__rpc_schedule();
-		if (current->flags & PF_FREEZE)
+		if (current->flags & PF_FREEZE) {
+			spin_unlock_bh(&rpc_queue_lock);
 			refrigerator(PF_IOTHREAD);
+			spin_lock_bh(&rpc_queue_lock);
+		}
 
 		if (++rounds >= 64) {	/* safeguard */
+			spin_unlock_bh(&rpc_queue_lock);
 			schedule();
 			rounds = 0;
+			spin_lock_bh(&rpc_queue_lock);
 		}
 
-		if (!rpciod_task_pending()) {
-			dprintk("RPC: rpciod back to sleep\n");
-			wait_event_interruptible(rpciod_idle, rpciod_task_pending());
-			dprintk("RPC: switch to rpciod\n");
+		dprintk("RPC: rpciod back to sleep\n");
+		prepare_to_wait(&rpciod_idle, &wait, TASK_INTERRUPTIBLE);
+		if (!rpciod_task_pending() && !signalled()) {
+			spin_unlock_bh(&rpc_queue_lock);
+			schedule();
 			rounds = 0;
+			spin_lock_bh(&rpc_queue_lock);
 		}
+		finish_wait(&rpciod_idle, &wait);
+		dprintk("RPC: switch to rpciod\n");
 	}
+	spin_unlock_bh(&rpc_queue_lock);
 
 	dprintk("RPC: rpciod shutdown commences\n");
 	if (!list_empty(&all_tasks)) {
@@ -1008,7 +1173,9 @@ rpciod_killall(void)
 	while (!list_empty(&all_tasks)) {
 		clear_thread_flag(TIF_SIGPENDING);
 		rpc_killall_tasks(NULL);
+		spin_lock_bh(&rpc_queue_lock);
 		__rpc_schedule();
+		spin_unlock_bh(&rpc_queue_lock);
 		if (!list_empty(&all_tasks)) {
 			dprintk("rpciod_killall: waiting for tasks to exit\n");
 			yield();
--- diff/net/sunrpc/sunrpc_syms.c	2004-03-11 10:20:29.000000000 +0000
+++ source/net/sunrpc/sunrpc_syms.c	2004-03-16 09:37:58.097707976 +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-16 09:37:58.097707976 +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-16 09:37:58.098707824 +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-11 10:20:29.000000000 +0000
+++ source/net/sunrpc/xprt.c	2004-03-16 09:37:58.100707520 +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,17 +454,74 @@ 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.
  *
  */
-void
-xprt_connect(struct rpc_task *task)
+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 +542,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 +569,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;
@@ -791,8 +782,6 @@ udp_data_ready(struct sock *sk, int len)
  dropit:
 	skb_free_datagram(sk, skb);
  out:
-	if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-		wake_up_interruptible(sk->sk_sleep);
 	read_unlock(&sk->sk_callback_lock);
 }
 
@@ -1052,8 +1041,6 @@ tcp_state_change(struct sock *sk)
 		break;
 	}
  out:
-	if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-		wake_up_interruptible_all(sk->sk_sleep);
 	read_unlock(&sk->sk_callback_lock);
 }
 
@@ -1093,8 +1080,6 @@ xprt_write_space(struct sock *sk)
 	if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending)
 		rpc_wake_up_task(xprt->snd_task);
 	spin_unlock_bh(&xprt->sock_lock);
-	if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-		wake_up_interruptible(sk->sk_sleep);
 out:
 	read_unlock(&sk->sk_callback_lock);
 }
@@ -1313,10 +1298,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 +1314,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)
 {
-	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;
+	return xprt->xid++;
+}
+
+static inline void xprt_init_xid(struct rpc_xprt *xprt)
+{
+	get_random_bytes(&xprt->xid, sizeof(xprt->xid));
 }
 
 /*
@@ -1359,8 +1335,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 +1366,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 +1397,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;
+
 /*
  * Initialize an RPC client
  */
@@ -1431,21 +1407,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 +1441,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) {
@@ -1467,21 +1458,22 @@ xprt_setup(int proto, struct sockaddr_in
 	} else
 		xprt_default_timeout(&xprt->timeout, xprt->prot);
 
-	INIT_RPC_WAITQ(&xprt->pending, "xprt_pending");
-	INIT_RPC_WAITQ(&xprt->sending, "xprt_sending");
-	INIT_RPC_WAITQ(&xprt->resend, "xprt_resend");
-	INIT_RPC_WAITQ(&xprt->backlog, "xprt_backlog");
+	rpc_init_wait_queue(&xprt->pending, "xprt_pending");
+	rpc_init_wait_queue(&xprt->sending, "xprt_sending");
+	rpc_init_wait_queue(&xprt->resend, "xprt_resend");
+	rpc_init_priority_wait_queue(&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;
 }
@@ -1489,31 +1481,28 @@ xprt_setup(int proto, struct sockaddr_in
 /*
  * Bind to a reserved port
  */
-static inline int
-xprt_bindresvport(struct socket *sock)
+static inline int 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 +1552,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);
 	}
 }
@@ -1576,8 +1565,7 @@ xprt_sock_setbufsize(struct rpc_xprt *xp
  * Datastream sockets are created here, but xprt_connect will create
  * and connect stream sockets.
  */
-static struct socket *
-xprt_create_socket(int proto, struct rpc_timeout *to, int resvport)
+static struct socket * xprt_create_socket(struct rpc_xprt *xprt, int proto, int resvport)
 {
 	struct socket	*sock;
 	int		type, err;
@@ -1593,7 +1581,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 +1602,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;
 }
 
 /*
@@ -1637,8 +1620,7 @@ xprt_shutdown(struct rpc_xprt *xprt)
 	rpc_wake_up(&xprt->resend);
 	rpc_wake_up(&xprt->pending);
 	rpc_wake_up(&xprt->backlog);
-	if (waitqueue_active(&xprt->cong_wait))
-		wake_up(&xprt->cong_wait);
+	wake_up(&xprt->cong_wait);
 	del_timer_sync(&xprt->timer);
 }
 
@@ -1648,8 +1630,7 @@ xprt_shutdown(struct rpc_xprt *xprt)
 int
 xprt_clear_backlog(struct rpc_xprt *xprt) {
 	rpc_wake_up_next(&xprt->backlog);
-	if (waitqueue_active(&xprt->cong_wait))
-		wake_up(&xprt->cong_wait);
+	wake_up(&xprt->cong_wait);
 	return 1;
 }
 
@@ -1662,6 +1643,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/Makefile	2004-03-11 10:20:29.000000000 +0000
+++ source/scripts/Makefile	2004-03-16 09:37:58.101707368 +0000
@@ -2,14 +2,10 @@
 # scripts contains sources for various helper programs used throughout
 # the kernel for the build process.
 # ---------------------------------------------------------------------------
-# fix-dep: 	 Used to generate dependency information during build process
-# split-include: Divide all config symbols up in a number of files in
-#                include/config/...
 # docproc: 	 Preprocess .tmpl file in order to generate .sgml docs
 # conmakehash:	 Create arrays for initializing the kernel console tables
 
-host-progs	:= fixdep split-include conmakehash docproc kallsyms modpost \
-		   mk_elfconfig pnmtologo bin2c
+host-progs	:= conmakehash kallsyms modpost mk_elfconfig pnmtologo bin2c
 always		:= $(host-progs) empty.o
 
 modpost-objs	:= modpost.o file2alias.o sumversion.o
@@ -17,10 +13,7 @@ modpost-objs	:= modpost.o file2alias.o s
 subdir-$(CONFIG_MODVERSIONS)	+= genksyms
 
 # Let clean descend into subdirs
-subdir-	+= lxdialog kconfig
-
-# fixdep is needed to compile other host programs
-$(addprefix $(obj)/,$(filter-out fixdep,$(always)) $(subdir-y)): $(obj)/fixdep
+subdir-	+= basic lxdialog kconfig
 
 # dependencies on generated files need to be listed explicitly
 
--- diff/scripts/Makefile.build	2004-03-11 10:20:29.000000000 +0000
+++ source/scripts/Makefile.build	2004-03-16 09:37:58.101707368 +0000
@@ -162,7 +162,7 @@ define rule_cc_o_c
 	$(if $($(quiet)cmd_cc_o_c),echo '  $($(quiet)cmd_cc_o_c)';)	  \
 	$(cmd_cc_o_c);							  \
 	$(cmd_modversions)						  \
-	scripts/fixdep $(depfile) $@ '$(cmd_cc_o_c)' > $(@D)/.$(@F).tmp;  \
+	scripts/basic/fixdep $(depfile) $@ '$(cmd_cc_o_c)' > $(@D)/.$(@F).tmp;  \
 	rm -f $(depfile);						  \
 	mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd
 endef
--- diff/scripts/Makefile.lib	2004-02-18 08:54:13.000000000 +0000
+++ source/scripts/Makefile.lib	2004-03-16 09:37:58.102707216 +0000
@@ -249,7 +249,7 @@ if_changed_dep = $(if $(strip $? $(filte
 	@set -e; \
 	$(if $($(quiet)cmd_$(1)),echo '  $(subst ','\'',$($(quiet)cmd_$(1)))';) \
 	$(cmd_$(1)); \
-	scripts/fixdep $(depfile) $@ '$(subst $$,$$$$,$(subst ','\'',$(cmd_$(1))))' > $(@D)/.$(@F).tmp; \
+	scripts/basic/fixdep $(depfile) $@ '$(subst $$,$$$$,$(subst ','\'',$(cmd_$(1))))' > $(@D)/.$(@F).tmp; \
 	rm -f $(depfile); \
 	mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd)
 
--- diff/scripts/modpost.c	2004-03-11 10:20:29.000000000 +0000
+++ source/scripts/modpost.c	2004-03-16 09:37:58.102707216 +0000
@@ -11,6 +11,7 @@
  * Usage: modpost vmlinux module1.o module2.o ...
  */
 
+#include <ctype.h>
 #include "modpost.h"
 
 /* Are we using CONFIG_MODVERSIONS? */
@@ -44,8 +45,6 @@ warn(const char *fmt, ...)
 	va_end(arglist);
 }
 
-#define NOFAIL(ptr)	do_nofail((ptr), __FILE__, __LINE__, #ptr)
-
 void *do_nofail(void *ptr, const char *file, int line, const char *expr)
 {
 	if (!ptr) {
@@ -63,18 +62,19 @@ struct module *
 new_module(char *modname)
 {
 	struct module *mod;
-	char *p;
+	char *p, *s;
 	
 	mod = NOFAIL(malloc(sizeof(*mod)));
 	memset(mod, 0, sizeof(*mod));
-	mod->name = NOFAIL(strdup(modname));
+	p = NOFAIL(strdup(modname));
 
 	/* strip trailing .o */
-	p = strstr(mod->name, ".o");
-	if (p)
-		*p = 0;
+	if ((s = strrchr(p, '.')) != NULL)
+		if (strcmp(s, ".o") == 0)
+			*s = '\0';
 
 	/* add to list */
+	mod->name = p;
 	mod->next = modules;
 	modules = mod;
 
@@ -206,6 +206,42 @@ grab_file(const char *filename, unsigned
 	return map;
 }
 
+/*
+   Return a copy of the next line in a mmap'ed file.
+   spaces in the beginning of the line is trimmed away.
+   Return a pointer to a static buffer.
+*/
+char*
+get_next_line(unsigned long *pos, void *file, unsigned long size)
+{
+	static char line[4096];
+	int skip = 1;
+	size_t len = 0;
+	char *p = (char *)file + *pos;
+	char *s = line;
+
+	for (; *pos < size ; (*pos)++)
+	{
+		if (skip && isspace(*p)) {
+			p++;
+			continue;
+		}
+		skip = 0;
+		if (*p != '\n' && (*pos < size)) {
+			len++;
+			*s++ = *p++;
+			if (len > 4095)
+				break; /* Too long, stop */
+		} else {
+			/* End of string */
+			*s = '\0';
+			return line;
+		}
+	}
+	/* End of buffer */
+	return NULL;
+}
+
 void
 release_file(void *file, unsigned long size)
 {
--- diff/scripts/modpost.h	2004-03-11 10:20:29.000000000 +0000
+++ source/scripts/modpost.h	2004-03-16 09:37:58.103707064 +0000
@@ -53,6 +53,9 @@ static inline void __endian(const void *
 
 #endif
 
+#define NOFAIL(ptr)   do_nofail((ptr), __FILE__, __LINE__, #ptr)
+void *do_nofail(void *ptr, const char *file, int line, const char *expr);
+
 struct buffer {
 	char *p;
 	int pos;
@@ -95,4 +98,5 @@ void maybe_frob_version(const char *modf
 			unsigned long modinfo_offset);
 
 void *grab_file(const char *filename, unsigned long *size);
+char* get_next_line(unsigned long *pos, void *file, unsigned long size);
 void release_file(void *file, unsigned long size);
--- diff/scripts/sumversion.c	2004-03-11 10:20:29.000000000 +0000
+++ source/scripts/sumversion.c	2004-03-16 09:37:58.104706912 +0000
@@ -323,12 +323,12 @@ static int parse_file(const char *fname,
  * figure out source file. */
 static int parse_source_files(const char *objfile, struct md4_ctx *md)
 {
-	char *cmd, *file, *p, *end;
+	char *cmd, *file, *line, *dir;
 	const char *base;
-	unsigned long flen;
-	int dirlen, ret = 0;
+	unsigned long flen, pos = 0;
+	int dirlen, ret = 0, check_files = 0;
 
-	cmd = malloc(strlen(objfile) + sizeof("..cmd"));
+	cmd = NOFAIL(malloc(strlen(objfile) + sizeof("..cmd")));
 
 	base = strrchr(objfile, '/');
 	if (base) {
@@ -339,6 +339,9 @@ static int parse_source_files(const char
 		dirlen = 0;
 		sprintf(cmd, ".%s.cmd", objfile);
 	}
+	dir = NOFAIL(malloc(dirlen + 1));
+	strncpy(dir, objfile, dirlen);
+	dir[dirlen] = '\0';
 
 	file = grab_file(cmd, &flen);
 	if (!file) {
@@ -357,48 +360,38 @@ static int parse_source_files(const char
 
 	   Sum all files in the same dir or subdirs.
 	*/
-	/* Strictly illegal: file is not nul terminated. */
-	p = strstr(file, "\ndeps_");
-	if (!p) {
-		fprintf(stderr, "Warning: could not find deps_ line in %s\n",
-			cmd);
-		goto out_file;
-	}
-	p = strstr(p, ":=");
-	if (!p) {
-		fprintf(stderr, "Warning: could not find := line in %s\n",
-			cmd);
-		goto out_file;
-	}
-	p += strlen(":=");
-	p += strspn(p, " \\\n");
+	while ((line = get_next_line(&pos, file, flen)) != NULL) {
+		char* p = line;
+		if (strncmp(line, "deps_", sizeof("deps_")-1) == 0) {
+			check_files = 1;
+			continue;
+		}
+		if (!check_files)
+			continue;
 
-	end = strstr(p, "\n\n");
-	if (!end) {
-		fprintf(stderr, "Warning: could not find end line in %s\n",
-			cmd);
-		goto out_file;
-	}
-
-	while (p < end) {
-		unsigned int len;
-
-		len = strcspn(p, " \\\n");
-		if (memcmp(objfile, p, dirlen) == 0) {
-			char source[len + 1];
-
-			memcpy(source, p, len);
-			source[len] = '\0';
-			printf("parsing %s\n", source);
-			if (!parse_file(source, md)) {
+		/* Continue until line does not end with '\' */
+		if ( *(p + strlen(p)-1) != '\\')
+			break;
+		/* Terminate line at first space, to get rid of final ' \' */
+		while (*p) {
+			if isspace(*p) {
+				*p = '\0';
+				break;
+			}
+			p++;
+		}
+
+		/* Check if this file is in same dir as objfile */
+		if ((strstr(line, dir)+strlen(dir)-1) == strrchr(line, '/')) {
+			if (!parse_file(line, md)) {
 				fprintf(stderr,
 					"Warning: could not open %s: %s\n",
-					source, strerror(errno));
+					line, strerror(errno));
 				goto out_file;
 			}
+
 		}
-		p += len;
-		p += strspn(p, " \\\n");
+
 	}
 
 	/* Everyone parsed OK */
@@ -406,6 +399,7 @@ static int parse_source_files(const char
 out_file:
 	release_file(file, flen);
 out:
+	free(dir);
 	free(cmd);
 	return ret;
 }
--- diff/scripts/ver_linux	2003-10-09 08:47:34.000000000 +0000
+++ source/scripts/ver_linux	2004-03-16 09:37:58.104706912 +0000
@@ -21,8 +21,9 @@ gcc --version 2>&1| grep gcc | awk \
 make --version 2>&1 | awk -F, '{print $1}' | awk \
       '/GNU Make/{print "Gnu make              ",$NF}'
 
-ld -v 2>&1 | awk -F\) '{print $1}' | awk \
-      '/BFD/{print "binutils              ",$NF}'
+ld -v | awk -F\) '{print $1}' | awk \
+'/BFD/{print "binutils              ",$NF} \
+/^GNU/{print "binutils              ",$4}'
 
 fdformat --version | awk -F\- '{print "util-linux            ", $NF}'
 
--- diff/security/dummy.c	2004-03-11 10:20:29.000000000 +0000
+++ source/security/dummy.c	2004-03-16 09:37:58.105706760 +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/avc.c	2004-02-18 08:54:13.000000000 +0000
+++ source/security/selinux/avc.c	2004-03-16 09:37:58.106706608 +0000
@@ -22,6 +22,7 @@
 #include <linux/un.h>
 #include <net/af_unix.h>
 #include <linux/ip.h>
+#include <linux/audit.h>
 #include "avc.h"
 #include "avc_ss.h"
 #include "class_to_string.h"
@@ -66,14 +67,10 @@ struct avc_callback_node {
 };
 
 static spinlock_t avc_lock = SPIN_LOCK_UNLOCKED;
-static spinlock_t avc_log_lock = SPIN_LOCK_UNLOCKED;
 static struct avc_node *avc_node_freelist = NULL;
 static struct avc_cache avc_cache;
-static char *avc_audit_buffer = NULL;
 static unsigned avc_cache_stats[AVC_NSTATS];
 static struct avc_callback_node *avc_callbacks = NULL;
-static unsigned int avc_log_level = 4; /* default:  KERN_WARNING */
-static char avc_level_string[4] = "< >";
 
 static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
 {
@@ -85,14 +82,14 @@ static inline int avc_hash(u32 ssid, u32
  * @tclass: target security class
  * @av: access vector
  */
-void avc_dump_av(u16 tclass, u32 av)
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
 {
 	char **common_pts = 0;
 	u32 common_base = 0;
 	int i, i2, perm;
 
 	if (av == 0) {
-		printk(" null");
+		audit_log_format(ab, " null");
 		return;
 	}
 
@@ -104,12 +101,12 @@ void avc_dump_av(u16 tclass, u32 av)
 		}
 	}
 
-	printk(" {");
+	audit_log_format(ab, " {");
 	i = 0;
 	perm = 1;
 	while (perm < common_base) {
 		if (perm & av)
-			printk(" %s", common_pts[i]);
+			audit_log_format(ab, " %s", common_pts[i]);
 		i++;
 		perm <<= 1;
 	}
@@ -122,13 +119,14 @@ void avc_dump_av(u16 tclass, u32 av)
 					break;
 			}
 			if (i2 < ARRAY_SIZE(av_perm_to_string))
-				printk(" %s", av_perm_to_string[i2].name);
+				audit_log_format(ab, " %s",
+						 av_perm_to_string[i2].name);
 		}
 		i++;
 		perm <<= 1;
 	}
 
-	printk(" }");
+	audit_log_format(ab, " }");
 }
 
 /**
@@ -137,7 +135,7 @@ void avc_dump_av(u16 tclass, u32 av)
  * @tsid: target security identifier
  * @tclass: target security class
  */
-void avc_dump_query(u32 ssid, u32 tsid, u16 tclass)
+void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tclass)
 {
 	int rc;
 	char *scontext;
@@ -145,20 +143,20 @@ void avc_dump_query(u32 ssid, u32 tsid, 
 
  	rc = security_sid_to_context(ssid, &scontext, &scontext_len);
 	if (rc)
-		printk("ssid=%d", ssid);
+		audit_log_format(ab, "ssid=%d", ssid);
 	else {
-		printk("scontext=%s", scontext);
+		audit_log_format(ab, "scontext=%s", scontext);
 		kfree(scontext);
 	}
 
 	rc = security_sid_to_context(tsid, &scontext, &scontext_len);
 	if (rc)
-		printk(" tsid=%d", tsid);
+		audit_log_format(ab, " tsid=%d", tsid);
 	else {
-		printk(" tcontext=%s", scontext);
+		audit_log_format(ab, " tcontext=%s", scontext);
 		kfree(scontext);
 	}
-	printk(" tclass=%s", class_to_string[tclass]);
+	audit_log_format(ab, " tclass=%s", class_to_string[tclass]);
 }
 
 /**
@@ -192,11 +190,7 @@ void __init avc_init(void)
 		avc_node_freelist = new;
 	}
 
-	avc_audit_buffer = (char *)__get_free_page(GFP_ATOMIC);
-	if (!avc_audit_buffer)
-		panic("AVC:  unable to allocate audit buffer\n");
-
-	avc_level_string[1] = '0' + avc_log_level;
+	audit_log(current->audit_context, "AVC INITIALIZED\n");
 }
 
 #if 0
@@ -418,12 +412,13 @@ out:
 	return rc;
 }
 
-static inline void avc_print_ipv4_addr(u32 addr, u16 port, char *name1, char *name2)
+static inline void avc_print_ipv4_addr(struct audit_buffer *ab, u32 addr,
+				       u16 port, char *name1, char *name2)
 {
 	if (addr)
-		printk(" %s=%d.%d.%d.%d", name1, NIPQUAD(addr));
+		audit_log_format(ab, " %s=%d.%d.%d.%d", name1, NIPQUAD(addr));
 	if (port)
-		printk(" %s=%d", name2, ntohs(port));
+		audit_log_format(ab, " %s=%d", name2, ntohs(port));
 }
 
 /*
@@ -503,9 +498,8 @@ void avc_audit(u32 ssid, u32 tsid,
 {
 	struct task_struct *tsk = current;
 	struct inode *inode = NULL;
-	char *p;
 	u32 denied, audited;
-	unsigned long flags;
+	struct audit_buffer *ab;
 
 	denied = requested & ~avd->allowed;
 	if (denied) {
@@ -523,19 +517,18 @@ void avc_audit(u32 ssid, u32 tsid,
 	if (!check_avc_ratelimit())
 		return;
 
-	/* prevent overlapping printks */
-	spin_lock_irqsave(&avc_log_lock,flags);
-
-	printk("%s\n", avc_level_string);
-	printk("%savc:  %s ", avc_level_string, denied ? "denied" : "granted");
-	avc_dump_av(tclass,audited);
-	printk(" for ");
+	ab = audit_log_start(current->audit_context);
+	if (!ab)
+		return;		/* audit_panic has been called */
+	audit_log_format(ab, "avc:  %s ", denied ? "denied" : "granted");
+	avc_dump_av(ab, tclass,audited);
+	audit_log_format(ab, " for ");
 	if (a && a->tsk)
 		tsk = a->tsk;
 	if (tsk && tsk->pid) {
 		struct mm_struct *mm;
 		struct vm_area_struct *vma;
-		printk(" pid=%d", tsk->pid);
+		audit_log_format(ab, " pid=%d", tsk->pid);
 		if (tsk == current)
 			mm = current->mm;
 		else
@@ -546,11 +539,9 @@ void avc_audit(u32 ssid, u32 tsid,
 				while (vma) {
 					if ((vma->vm_flags & VM_EXECUTABLE) &&
 					    vma->vm_file) {
-						p = d_path(vma->vm_file->f_dentry,
-							   vma->vm_file->f_vfsmnt,
-							   avc_audit_buffer,
-							   PAGE_SIZE);
-						printk(" exe=%s", p);
+						audit_log_d_path(ab, "exe=",
+								 vma->vm_file->f_dentry,
+								 vma->vm_file->f_vfsmnt);
 						break;
 					}
 					vma = vma->vm_next;
@@ -560,29 +551,25 @@ void avc_audit(u32 ssid, u32 tsid,
 			if (tsk != current)
 				mmput(mm);
 		} else {
-			printk(" comm=%s", tsk->comm);
+			audit_log_format(ab, " comm=%s", tsk->comm);
 		}
 	}
 	if (a) {
 		switch (a->type) {
 		case AVC_AUDIT_DATA_IPC:
-			printk(" key=%d", a->u.ipc_id);
+			audit_log_format(ab, " key=%d", a->u.ipc_id);
 			break;
 		case AVC_AUDIT_DATA_CAP:
-			printk(" capability=%d", a->u.cap);
+			audit_log_format(ab, " capability=%d", a->u.cap);
 			break;
 		case AVC_AUDIT_DATA_FS:
 			if (a->u.fs.dentry) {
 				struct dentry *dentry = a->u.fs.dentry;
 				if (a->u.fs.mnt) {
-					p = d_path(dentry,
-						   a->u.fs.mnt,
-						   avc_audit_buffer,
-						   PAGE_SIZE);
-					if (p)
-						printk(" path=%s", p);
+					audit_log_d_path(ab, "path=", dentry, a->u.fs.mnt);
 				} else {
-					printk(" name=%s", dentry->d_name.name);
+					audit_log_format(ab, " name=%s",
+							 dentry->d_name.name);
 				}
 				inode = dentry->d_inode;
 			} else if (a->u.fs.inode) {
@@ -590,13 +577,15 @@ void avc_audit(u32 ssid, u32 tsid,
 				inode = a->u.fs.inode;
 				dentry = d_find_alias(inode);
 				if (dentry) {
-					printk(" name=%s", dentry->d_name.name);
+					audit_log_format(ab, " name=%s",
+							 dentry->d_name.name);
 					dput(dentry);
 				}
 			}
 			if (inode)
-				printk(" dev=%s ino=%ld",
-				       inode->i_sb->s_id, inode->i_ino);
+				audit_log_format(ab, " dev=%s ino=%ld",
+						 inode->i_sb->s_id,
+						 inode->i_ino);
 			break;
 		case AVC_AUDIT_DATA_NET:
 			if (a->u.net.sk) {
@@ -607,53 +596,45 @@ void avc_audit(u32 ssid, u32 tsid,
 				switch (sk->sk_family) {
 				case AF_INET:
 					inet = inet_sk(sk);
-					avc_print_ipv4_addr(inet->rcv_saddr,
-					                    inet->sport,
-					                    "laddr", "lport");
-					avc_print_ipv4_addr(inet->daddr,
-					                    inet->dport,
-					                    "faddr", "fport");
+					avc_print_ipv4_addr(ab, inet->rcv_saddr,
+							    inet->sport,
+							    "laddr", "lport");
+					avc_print_ipv4_addr(ab, inet->daddr,
+							    inet->dport,
+							    "faddr", "fport");
 					break;
 				case AF_UNIX:
 					u = unix_sk(sk);
 					if (u->dentry) {
-						p = d_path(u->dentry,
-							   u->mnt,
-							   avc_audit_buffer,
-							   PAGE_SIZE);
-						printk(" path=%s", p);
+						audit_log_d_path(ab, "path=",
+								 u->dentry, u->mnt);
 					} else if (u->addr) {
-						p = avc_audit_buffer;
-						memcpy(p,
-						       u->addr->name->sun_path,
-						       u->addr->len-sizeof(short));
-						if (*p == 0) {
-							*p = '@';
-							p += u->addr->len-sizeof(short);
-							*p = 0;
-						}
-						printk(" path=%s",
-						       avc_audit_buffer);
+						int len = u->addr->len-sizeof(short);
+						char *p = &u->addr->name->sun_path[0];
+						if (*p)
+							audit_log_format(ab, "path=%*.*s",
+									 len, len, p);
+						else
+							audit_log_format(ab, "path=@%*.*s",
+									 len-1, len-1, p+1);
 					}
 					break;
 				}
 			}
 			
-			avc_print_ipv4_addr(a->u.net.saddr, a->u.net.sport,
-			                    "saddr", "src");
-			avc_print_ipv4_addr(a->u.net.daddr, a->u.net.dport,
-			                    "daddr", "dest");
+			avc_print_ipv4_addr(ab, a->u.net.saddr, a->u.net.sport,
+					    "saddr", "src");
+			avc_print_ipv4_addr(ab, a->u.net.daddr, a->u.net.dport,
+					    "daddr", "dest");
 
 			if (a->u.net.netif)
-				printk(" netif=%s", a->u.net.netif);
+				audit_log_format(ab, " netif=%s", a->u.net.netif);
 			break;
 		}
 	}
-	printk(" ");
-	avc_dump_query(ssid, tsid, tclass);
-	printk("\n");
-
-	spin_unlock_irqrestore(&avc_log_lock,flags);
+	audit_log_format(ab, " ");
+	avc_dump_query(ab, ssid, tsid, tclass);
+	audit_log_end(ab);
 }
 
 /**
@@ -1083,13 +1064,4 @@ int avc_has_perm(u32 ssid, u32 tsid, u16
 	return rc;
 }
 
-static int __init avc_log_level_setup(char *str)
-{
-	avc_log_level = simple_strtol(str, NULL, 0);
-	if (avc_log_level > 7)
-		avc_log_level = 7;
-	return 1;
-}
-
-__setup("avc_log_level=", avc_log_level_setup);
 
--- diff/security/selinux/hooks.c	2004-03-11 10:20:29.000000000 +0000
+++ source/security/selinux/hooks.c	2004-03-16 09:37:58.108706304 +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/security/selinux/include/av_perm_to_string.h	2004-02-09 10:36:12.000000000 +0000
+++ source/security/selinux/include/av_perm_to_string.h	2004-03-16 09:37:58.109706152 +0000
@@ -84,6 +84,7 @@ static struct av_perm_to_string av_perm_
    { SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL, "compute_relabel" },
    { SECCLASS_SECURITY, SECURITY__COMPUTE_USER, "compute_user" },
    { SECCLASS_SECURITY, SECURITY__SETENFORCE, "setenforce" },
+   { SECCLASS_SECURITY, SECURITY__SETBOOL, "setbool" },
    { SECCLASS_SYSTEM, SYSTEM__IPC_INFO, "ipc_info" },
    { SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, "syslog_read" },
    { SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, "syslog_mod" },
--- diff/security/selinux/include/av_permissions.h	2004-02-09 10:36:12.000000000 +0000
+++ source/security/selinux/include/av_permissions.h	2004-03-16 09:37:58.109706152 +0000
@@ -512,6 +512,7 @@
 #define SECURITY__COMPUTE_RELABEL                 0x00000020UL
 #define SECURITY__COMPUTE_USER                    0x00000040UL
 #define SECURITY__SETENFORCE                      0x00000080UL
+#define SECURITY__SETBOOL                         0x00000100UL
 
 #define SYSTEM__IPC_INFO                          0x00000001UL
 #define SYSTEM__SYSLOG_READ                       0x00000002UL
--- diff/security/selinux/include/avc.h	2004-02-18 08:54:13.000000000 +0000
+++ source/security/selinux/include/avc.h	2004-03-16 09:37:58.110706000 +0000
@@ -114,9 +114,10 @@ static inline void avc_cache_stats_add(i
 /*
  * AVC display support
  */
-void avc_dump_av(u16 tclass, u32 av);
-void avc_dump_query(u32 ssid, u32 tsid, u16 tclass);
-void avc_dump_cache(char *tag);
+struct audit_buffer;
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av);
+void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tclass);
+void avc_dump_cache(struct audit_buffer *ab, char *tag);
 
 /*
  * AVC operations
--- diff/security/selinux/include/security.h	2004-02-18 08:54:13.000000000 +0000
+++ source/security/selinux/include/security.h	2004-03-16 09:37:58.110706000 +0000
@@ -2,7 +2,9 @@
  * Security server interface.
  *
  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ *
  */
+
 #ifndef _SELINUX_SECURITY_H_
 #define _SELINUX_SECURITY_H_
 
@@ -13,7 +15,8 @@
 #define SECCLASS_NULL			0x0000 /* no class */
 
 #define SELINUX_MAGIC 0xf97cff8c
-#define POLICYDB_VERSION 15
+#define POLICYDB_VERSION 16
+#define POLICYDB_VERSION_COMPAT 15
 
 #ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
 extern int selinux_enabled;
@@ -21,6 +24,12 @@ extern int selinux_enabled;
 #define selinux_enabled 1
 #endif
 
+#ifdef CONFIG_SECURITY_SELINUX_MLS
+#define selinux_mls_enabled 1
+#else
+#define selinux_mls_enabled 0
+#endif
+
 int security_load_policy(void * data, size_t len);
 
 struct av_decision {
--- diff/security/selinux/selinuxfs.c	2004-03-11 10:20:29.000000000 +0000
+++ source/security/selinux/selinuxfs.c	2004-03-16 09:37:58.112705696 +0000
@@ -1,5 +1,16 @@
+/* Updated: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * 	Added conditional policy language extensions
+ *
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ *	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, version 2.
+ */
+
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/pagemap.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
@@ -7,6 +18,7 @@
 #include <linux/string.h>
 #include <linux/security.h>
 #include <asm/uaccess.h>
+#include <asm/semaphore.h>
 
 /* selinuxfs pseudo filesystem for exporting the security policy API.
    Based on the proc code and the fs/nfsd/nfsctl.c code. */
@@ -16,6 +28,14 @@
 #include "avc_ss.h"
 #include "security.h"
 #include "objsec.h"
+#include "conditional.h"
+
+static DECLARE_MUTEX(sel_sem);
+
+/* global data for booleans */
+static struct dentry *bool_dir = NULL;
+static int bool_num = 0;
+static int *bool_pending_values = NULL;
 
 extern void selnl_notify_setenforce(int val);
 
@@ -40,7 +60,9 @@ enum sel_inos {
 	SEL_CREATE,	/* compute create labeling decision */
 	SEL_RELABEL,	/* compute relabeling decision */
 	SEL_USER,	/* compute reachable user contexts */
-	SEL_POLICYVERS	/* return policy version for this kernel */
+	SEL_POLICYVERS,	/* return policy version for this kernel */
+	SEL_COMMIT_BOOLS,
+	SEL_MLS		/* return if MLS policy is enabled */
 };
 
 static ssize_t sel_read_enforce(struct file *filp, char *buf,
@@ -169,24 +191,74 @@ static struct file_operations sel_policy
 	.read		= sel_read_policyvers,
 };
 
+/* declaration for sel_write_load */
+static int sel_make_bools(void);
+
+static ssize_t sel_read_mls(struct file *filp, char *buf,
+				size_t count, loff_t *ppos)
+{
+	char *page;
+	ssize_t length;
+	ssize_t end;
+
+	if (count < 0 || count > PAGE_SIZE)
+		return -EINVAL;
+	if (!(page = (char*)__get_free_page(GFP_KERNEL)))
+		return -ENOMEM;
+	memset(page, 0, PAGE_SIZE);
+
+	length = scnprintf(page, PAGE_SIZE, "%d", selinux_mls_enabled);
+	if (length < 0) {
+		free_page((unsigned long)page);
+		return length;
+	}
+
+	if (*ppos >= length) {
+		free_page((unsigned long)page);
+		return 0;
+	}
+	if (count + *ppos > length)
+		count = length - *ppos;
+	end = count + *ppos;
+	if (copy_to_user(buf, (char *) page + *ppos, count)) {
+		count = -EFAULT;
+		goto out;
+	}
+	*ppos = end;
+out:
+	free_page((unsigned long)page);
+	return count;
+}
+
+static struct file_operations sel_mls_ops = {
+	.read		= sel_read_mls,
+};
+
 static ssize_t sel_write_load(struct file * file, const char * buf,
 			      size_t count, loff_t *ppos)
 
 {
+	int ret;
 	ssize_t length;
-	void *data;
+	void *data = NULL;
+
+	down(&sel_sem);
 
 	length = task_has_security(current, SECURITY__LOAD_POLICY);
 	if (length)
-		return length;
+		goto out;
 
 	if (*ppos != 0) {
 		/* No partial writes. */
-		return -EINVAL;
+		length = -EINVAL;
+		goto out;
 	}
 
-	if ((count < 0) || (count > 64 * 1024 * 1024) || (data = vmalloc(count)) == NULL)
-		return -ENOMEM;
+	if ((count < 0) || (count > 64 * 1024 * 1024)
+	    || (data = vmalloc(count)) == NULL) {
+		length = -ENOMEM;
+		goto out;
+	}
 
 	length = -EFAULT;
 	if (copy_from_user(data, buf, count) != 0)
@@ -196,8 +268,13 @@ static ssize_t sel_write_load(struct fil
 	if (length)
 		goto out;
 
-	length = count;
+	ret = sel_make_bools();
+	if (ret)
+		length = ret;
+	else
+		length = count;
 out:
+	up(&sel_sem);
 	vfree(data);
 	return length;
 }
@@ -601,9 +678,322 @@ out:
 	return length;
 }
 
+static struct inode *sel_make_inode(struct super_block *sb, int mode)
+{
+	struct inode *ret = new_inode(sb);
+
+	if (ret) {
+		ret->i_mode = mode;
+		ret->i_uid = ret->i_gid = 0;
+		ret->i_blksize = PAGE_CACHE_SIZE;
+		ret->i_blocks = 0;
+		ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
+	}
+	return ret;
+}
+
+#define BOOL_INO_OFFSET 30
+
+static ssize_t sel_read_bool(struct file *filep, char *buf,
+			     size_t count, loff_t *ppos)
+{
+	char *page = NULL;
+	ssize_t length;
+	ssize_t end;
+	ssize_t ret;
+	int cur_enforcing;
+	struct inode *inode;
+
+	down(&sel_sem);
+
+	ret = -EFAULT;
+
+	/* check to see if this file has been deleted */
+	if (!filep->f_op)
+		goto out;
+
+	if (count < 0 || count > PAGE_SIZE) {
+		ret = -EINVAL;
+		goto out;
+	}
+	if (!(page = (char*)__get_free_page(GFP_KERNEL))) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	memset(page, 0, PAGE_SIZE);
+
+	inode = filep->f_dentry->d_inode;
+	cur_enforcing = security_get_bool_value(inode->i_ino - BOOL_INO_OFFSET);
+	if (cur_enforcing < 0) {
+		ret = cur_enforcing;
+		goto out;
+	}
+
+	length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
+			  bool_pending_values[inode->i_ino - BOOL_INO_OFFSET]);
+	if (length < 0) {
+		ret = length;
+		goto out;
+	}
+
+	if (*ppos >= length) {
+		ret = 0;
+		goto out;
+	}
+	if (count + *ppos > length)
+		count = length - *ppos;
+	end = count + *ppos;
+	if (copy_to_user(buf, (char *) page + *ppos, count)) {
+		ret = -EFAULT;
+		goto out;
+	}
+	*ppos = end;
+	ret = count;
+out:
+	up(&sel_sem);
+	if (page)
+		free_page((unsigned long)page);
+	return ret;
+}
+
+static ssize_t sel_write_bool(struct file *filep, const char *buf,
+			      size_t count, loff_t *ppos)
+{
+	char *page = NULL;
+	ssize_t length = -EFAULT;
+	int new_value;
+	struct inode *inode;
+
+	down(&sel_sem);
+
+	length = task_has_security(current, SECURITY__SETBOOL);
+	if (length)
+		goto out;
+
+	/* check to see if this file has been deleted */
+	if (!filep->f_op)
+		goto out;
+
+	if (count < 0 || count >= PAGE_SIZE) {
+		length = -ENOMEM;
+		goto out;
+	}
+	if (*ppos != 0) {
+		/* No partial writes. */
+		goto out;
+	}
+	page = (char*)__get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+	memset(page, 0, PAGE_SIZE);
+
+	if (copy_from_user(page, buf, count))
+		goto out;
+
+	length = -EINVAL;
+	if (sscanf(page, "%d", &new_value) != 1)
+		goto out;
+
+	if (new_value)
+		new_value = 1;
+
+	inode = filep->f_dentry->d_inode;
+	bool_pending_values[inode->i_ino - BOOL_INO_OFFSET] = new_value;
+	length = count;
+
+out:
+	up(&sel_sem);
+	if (page)
+		free_page((unsigned long) page);
+	return length;
+}
+
+static struct file_operations sel_bool_ops = {
+	.read           = sel_read_bool,
+	.write          = sel_write_bool,
+};
+
+static ssize_t sel_commit_bools_write(struct file *filep, const char *buf,
+				      size_t count, loff_t *ppos)
+{
+	char *page = NULL;
+	ssize_t length = -EFAULT;
+	int new_value;
+
+	down(&sel_sem);
+
+	length = task_has_security(current, SECURITY__SETBOOL);
+	if (length)
+		goto out;
+
+	/* check to see if this file has been deleted */
+	if (!filep->f_op)
+		goto out;
+
+	if (count < 0 || count >= PAGE_SIZE) {
+		length = -ENOMEM;
+		goto out;
+	}
+	if (*ppos != 0) {
+		/* No partial writes. */
+		goto out;
+	}
+	page = (char*)__get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	memset(page, 0, PAGE_SIZE);
+
+	if (copy_from_user(page, buf, count))
+		goto out;
+
+	length = -EINVAL;
+	if (sscanf(page, "%d", &new_value) != 1)
+		goto out;
+
+	if (new_value) {
+		security_set_bools(bool_num, bool_pending_values);
+	}
+
+	length = count;
+
+out:
+	up(&sel_sem);
+	if (page)
+		free_page((unsigned long) page);
+	return length;
+}
+
+static struct file_operations sel_commit_bools_ops = {
+	.write          = sel_commit_bools_write,
+};
+
+/* delete booleans - partial revoke() from
+ * fs/proc/generic.c proc_kill_inodes */
+static void sel_remove_bools(struct dentry *de)
+{
+	struct list_head *p, *node;
+	struct super_block *sb = de->d_sb;
+
+	spin_lock(&dcache_lock);
+	node = de->d_subdirs.next;
+	while (node != &de->d_subdirs) {
+		struct dentry *d = list_entry(node, struct dentry, d_child);
+		list_del_init(node);
+
+		if (d->d_inode) {
+			d = dget_locked(d);
+			spin_unlock(&dcache_lock);
+			d_delete(d);
+			simple_unlink(de->d_inode, d);
+			dput(d);
+			spin_lock(&dcache_lock);
+		}
+		node = de->d_subdirs.next;
+	}
+
+	spin_unlock(&dcache_lock);
+
+	file_list_lock();
+	list_for_each(p, &sb->s_files) {
+		struct file * filp = list_entry(p, struct file, f_list);
+		struct dentry * dentry = filp->f_dentry;
+
+		if (dentry->d_parent != de) {
+			continue;
+		}
+		filp->f_op = NULL;
+	}
+	file_list_unlock();
+}
+
+#define BOOL_DIR_NAME "booleans"
+
+static int sel_make_bools(void)
+{
+	int i, ret = 0;
+	ssize_t len;
+	struct dentry *dentry = NULL;
+	struct dentry *dir = bool_dir;
+	struct inode *inode = NULL;
+	struct inode_security_struct *isec;
+	struct qstr qname;
+	char **names = NULL, *page;
+	int num;
+	int *values = NULL;
+	u32 sid;
+
+	/* remove any existing files */
+	if (bool_pending_values)
+		kfree(bool_pending_values);
+
+	sel_remove_bools(dir);
+
+	if (!(page = (char*)__get_free_page(GFP_KERNEL)))
+		return -ENOMEM;
+	memset(page, 0, PAGE_SIZE);
+
+	ret = security_get_bools(&num, &names, &values);
+	if (ret != 0)
+		goto out;
+
+	for (i = 0; i < num; i++) {
+		qname.name = names[i];
+		qname.len = strlen(qname.name);
+		qname.hash = full_name_hash(qname.name, qname.len);
+		dentry = d_alloc(dir, &qname);
+		if (!dentry) {
+			ret = -ENOMEM;
+			goto err;
+		}
+		inode = sel_make_inode(dir->d_sb, S_IFREG | S_IRUGO | S_IWUSR);
+		if (!inode) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		len = snprintf(page, PAGE_SIZE, "/%s/%s", BOOL_DIR_NAME, names[i]);
+		if (len < 0) {
+			ret = -EINVAL;
+			goto err;
+		} else if (len >= PAGE_SIZE) {
+			ret = -ENAMETOOLONG;
+			goto err;
+		}
+		isec = (struct inode_security_struct*)inode->i_security;
+		if ((ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid)))
+			goto err;
+		isec->sid = sid;
+		isec->initialized = 1;
+		inode->i_fop = &sel_bool_ops;
+		inode->i_ino = i + BOOL_INO_OFFSET;
+		d_add(dentry, inode);
+	}
+	bool_num = num;
+	bool_pending_values = values;
+out:
+	free_page((unsigned long)page);
+	if (names) {
+		for (i = 0; i < num; i++) {
+			if (names[i])
+				kfree(names[i]);
+		}
+		kfree(names);
+	}
+	return ret;
+err:
+	d_genocide(dir);
+	ret = -ENOMEM;
+	goto out;
+}
 
 static int sel_fill_super(struct super_block * sb, void * data, int silent)
 {
+	int ret;
+	struct dentry *dentry;
+	struct inode *inode;
+	struct qstr qname;
+
 	static struct tree_descr selinux_files[] = {
 		[SEL_LOAD] = {"load", &sel_load_ops, S_IRUSR|S_IWUSR},
 		[SEL_ENFORCE] = {"enforce", &sel_enforce_ops, S_IRUGO|S_IWUSR},
@@ -613,9 +1003,37 @@ static int sel_fill_super(struct super_b
 		[SEL_RELABEL] = {"relabel", &transaction_ops, S_IRUGO|S_IWUGO},
 		[SEL_USER] = {"user", &transaction_ops, S_IRUGO|S_IWUGO},
 		[SEL_POLICYVERS] = {"policyvers", &sel_policyvers_ops, S_IRUGO},
+		[SEL_COMMIT_BOOLS] = {"commit_pending_bools", &sel_commit_bools_ops, S_IWUSR},
+		[SEL_MLS] = {"mls", &sel_mls_ops, S_IRUGO},
 		/* last one */ {""}
 	};
-	return simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
+	ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
+	if (ret)
+		return ret;
+
+	qname.name = BOOL_DIR_NAME;
+	qname.len = strlen(qname.name);
+	qname.hash = full_name_hash(qname.name, qname.len);
+	dentry = d_alloc(sb->s_root, &qname);
+	if (!dentry)
+		return -ENOMEM;
+
+	inode = sel_make_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO);
+	if (!inode)
+		goto out;
+	inode->i_op = &simple_dir_inode_operations;
+	inode->i_fop = &simple_dir_operations;
+	d_add(dentry, inode);
+	bool_dir = dentry;
+	ret = sel_make_bools();
+	if (ret)
+		goto out;
+
+	return 0;
+out:
+	dput(dentry);
+	printk(KERN_ERR "security:	error creating conditional out_dput\n");
+	return -ENOMEM;
 }
 
 static struct super_block *sel_get_sb(struct file_system_type *fs_type,
--- diff/security/selinux/ss/Makefile	2004-02-09 10:36:12.000000000 +0000
+++ source/security/selinux/ss/Makefile	2004-03-16 09:37:58.112705696 +0000
@@ -5,7 +5,7 @@
 EXTRA_CFLAGS += -Isecurity/selinux/include
 obj-y := ss.o
 
-ss-y := ebitmap.o hashtab.o symtab.o sidtab.o avtab.o policydb.o services.o
+ss-y := ebitmap.o hashtab.o symtab.o sidtab.o avtab.o policydb.o services.o conditional.o
 
 ss-$(CONFIG_SECURITY_SELINUX_MLS) += mls.o
 
--- diff/security/selinux/ss/avtab.c	2004-02-18 08:54:13.000000000 +0000
+++ source/security/selinux/ss/avtab.c	2004-03-16 09:37:58.114705392 +0000
@@ -3,10 +3,22 @@
  *
  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
  */
+
+/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * 	Added conditional policy language extensions
+ *
+ * Copyright (C) 2003 Tresys Technology, LLC
+ *	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, version 2.
+ */
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/errno.h>
+
 #include "avtab.h"
 #include "policydb.h"
 
@@ -16,6 +28,29 @@
  (keyp->source_type << 9)) & \
  AVTAB_HASH_MASK)
 
+static struct avtab_node*
+avtab_insert_node(struct avtab *h, int hvalue, struct avtab_node * prev, struct avtab_node * cur,
+		  struct avtab_key *key, struct avtab_datum *datum)
+{
+	struct avtab_node * newnode;
+	newnode = (struct avtab_node *) kmalloc(sizeof(struct avtab_node),GFP_KERNEL);
+	if (newnode == NULL)
+		return NULL;
+	memset(newnode, 0, sizeof(struct avtab_node));
+	newnode->key = *key;
+	newnode->datum = *datum;
+	if (prev) {
+		newnode->next = prev->next;
+		prev->next = newnode;
+	} else {
+		newnode->next = h->htable[hvalue];
+		h->htable[hvalue] = newnode;
+	}
+
+	h->nel++;
+	return newnode;
+}
+
 int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
 {
 	int hvalue;
@@ -44,24 +79,48 @@ int avtab_insert(struct avtab *h, struct
 			break;
 	}
 
-	newnode = kmalloc(sizeof(*newnode), GFP_KERNEL);
-	if (newnode == NULL)
+	newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
+	if(!newnode)
 		return -ENOMEM;
-	memset(newnode, 0, sizeof(*newnode));
-	newnode->key = *key;
-	newnode->datum = *datum;
-	if (prev) {
-		newnode->next = prev->next;
-		prev->next = newnode;
-	} else {
-		newnode->next = h->htable[hvalue];
-		h->htable[hvalue] = newnode;
-	}
 
-	h->nel++;
 	return 0;
 }
 
+/* Unlike avtab_insert(), this function allow multiple insertions of the same
+ * key/specified mask into the table, as needed by the conditional avtab.
+ * It also returns a pointer to the node inserted.
+ */
+struct avtab_node *
+avtab_insert_nonunique(struct avtab * h, struct avtab_key * key, struct avtab_datum * datum)
+{
+	int hvalue;
+	struct avtab_node *prev, *cur, *newnode;
+
+	if (!h)
+		return NULL;
+	hvalue = AVTAB_HASH(key);
+	for (prev = NULL, cur = h->htable[hvalue];
+	     cur;
+	     prev = cur, cur = cur->next) {
+		if (key->source_type == cur->key.source_type &&
+		    key->target_type == cur->key.target_type &&
+		    key->target_class == cur->key.target_class &&
+		    (datum->specified & cur->datum.specified))
+			break;
+		if (key->source_type < cur->key.source_type)
+			break;
+		if (key->source_type == cur->key.source_type &&
+		    key->target_type < cur->key.target_type)
+			break;
+		if (key->source_type == cur->key.source_type &&
+		    key->target_type == cur->key.target_type &&
+		    key->target_class < cur->key.target_class)
+			break;
+	}
+	newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
+
+	return newnode;
+}
 
 struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key, int specified)
 {
@@ -93,6 +152,67 @@ struct avtab_datum *avtab_search(struct 
 	return NULL;
 }
 
+/* This search function returns a node pointer, and can be used in
+ * conjunction with avtab_search_next_node()
+ */
+struct avtab_node*
+avtab_search_node(struct avtab *h, struct avtab_key *key, int specified)
+{
+	int hvalue;
+	struct avtab_node *cur;
+
+	if (!h)
+		return NULL;
+
+	hvalue = AVTAB_HASH(key);
+	for (cur = h->htable[hvalue]; cur; cur = cur->next) {
+		if (key->source_type == cur->key.source_type &&
+		    key->target_type == cur->key.target_type &&
+		    key->target_class == cur->key.target_class &&
+		    (specified & cur->datum.specified))
+			return cur;
+
+		if (key->source_type < cur->key.source_type)
+			break;
+		if (key->source_type == cur->key.source_type &&
+		    key->target_type < cur->key.target_type)
+			break;
+		if (key->source_type == cur->key.source_type &&
+		    key->target_type == cur->key.target_type &&
+		    key->target_class < cur->key.target_class)
+			break;
+	}
+	return NULL;
+}
+
+struct avtab_node*
+avtab_search_node_next(struct avtab_node *node, int specified)
+{
+	struct avtab_node *cur;
+
+	if (!node)
+		return NULL;
+
+	for (cur = node->next; cur; cur = cur->next) {
+		if (node->key.source_type == cur->key.source_type &&
+		    node->key.target_type == cur->key.target_type &&
+		    node->key.target_class == cur->key.target_class &&
+		    (specified & cur->datum.specified))
+			return cur;
+
+		if (node->key.source_type < cur->key.source_type)
+			break;
+		if (node->key.source_type == cur->key.source_type &&
+		    node->key.target_type < cur->key.target_type)
+			break;
+		if (node->key.source_type == cur->key.source_type &&
+		    node->key.target_type == cur->key.target_type &&
+		    node->key.target_class < cur->key.target_class)
+			break;
+	}
+	return NULL;
+}
+
 void avtab_destroy(struct avtab *h)
 {
 	int i;
@@ -179,13 +299,72 @@ void avtab_hash_eval(struct avtab *h, ch
 	       max_chain_len);
 }
 
+int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey)
+{
+	__u32 *buf;
+	__u32 items, items2;
+
+	memset(avkey, 0, sizeof(struct avtab_key));
+	memset(avdatum, 0, sizeof(struct avtab_datum));
+
+	buf = next_entry(fp, sizeof(__u32));
+	if (!buf) {
+		printk(KERN_ERR "security: avtab: truncated entry\n");
+		goto bad;
+	}
+	items2 = le32_to_cpu(buf[0]);
+	buf = next_entry(fp, sizeof(__u32)*items2);
+	if (!buf) {
+		printk(KERN_ERR "security: avtab: truncated entry\n");
+		goto bad;
+	}
+	items = 0;
+	avkey->source_type = le32_to_cpu(buf[items++]);
+	avkey->target_type = le32_to_cpu(buf[items++]);
+	avkey->target_class = le32_to_cpu(buf[items++]);
+	avdatum->specified = le32_to_cpu(buf[items++]);
+	if (!(avdatum->specified & (AVTAB_AV | AVTAB_TYPE))) {
+		printk(KERN_ERR "security: avtab: null entry\n");
+		goto bad;
+	}
+	if ((avdatum->specified & AVTAB_AV) &&
+	    (avdatum->specified & AVTAB_TYPE)) {
+		printk(KERN_ERR "security: avtab: entry has both access vectors and types\n");
+		goto bad;
+	}
+	if (avdatum->specified & AVTAB_AV) {
+		if (avdatum->specified & AVTAB_ALLOWED)
+			avtab_allowed(avdatum) = le32_to_cpu(buf[items++]);
+		if (avdatum->specified & AVTAB_AUDITDENY)
+			avtab_auditdeny(avdatum) = le32_to_cpu(buf[items++]);
+		if (avdatum->specified & AVTAB_AUDITALLOW)
+			avtab_auditallow(avdatum) = le32_to_cpu(buf[items++]);
+	} else {
+		if (avdatum->specified & AVTAB_TRANSITION)
+			avtab_transition(avdatum) = le32_to_cpu(buf[items++]);
+		if (avdatum->specified & AVTAB_CHANGE)
+			avtab_change(avdatum) = le32_to_cpu(buf[items++]);
+		if (avdatum->specified & AVTAB_MEMBER)
+			avtab_member(avdatum) = le32_to_cpu(buf[items++]);
+	}
+	if (items != items2) {
+		printk(KERN_ERR "security: avtab: entry only had %d items, expected %d\n",
+		       items2, items);
+		goto bad;
+	}
+
+	return 0;
+bad:
+	return -1;
+}
+
 int avtab_read(struct avtab *a, void *fp, u32 config)
 {
 	int i, rc = -EINVAL;
 	struct avtab_key avkey;
 	struct avtab_datum avdatum;
 	u32 *buf;
-	u32 nel, items, items2;
+	u32 nel;
 
 
 	buf = next_entry(fp, sizeof(u32));
@@ -199,55 +378,8 @@ int avtab_read(struct avtab *a, void *fp
 		goto bad;
 	}
 	for (i = 0; i < nel; i++) {
-		memset(&avkey, 0, sizeof(avkey));
-		memset(&avdatum, 0, sizeof(avdatum));
-
-		buf = next_entry(fp, sizeof(u32));
-		if (!buf) {
-			printk(KERN_ERR "security: avtab: truncated entry\n");
-			goto bad;
-		}
-		items2 = le32_to_cpu(buf[0]);
-		buf = next_entry(fp, sizeof(u32)*items2);
-		if (!buf) {
-			printk(KERN_ERR "security: avtab: truncated entry\n");
+		if (avtab_read_item(fp, &avdatum, &avkey))
 			goto bad;
-		}
-		items = 0;
-		avkey.source_type = le32_to_cpu(buf[items++]);
-		avkey.target_type = le32_to_cpu(buf[items++]);
-		avkey.target_class = le32_to_cpu(buf[items++]);
-		avdatum.specified = le32_to_cpu(buf[items++]);
-		if (!(avdatum.specified & (AVTAB_AV | AVTAB_TYPE))) {
-			printk(KERN_ERR "security: avtab: null entry\n");
-			goto bad;
-		}
-		if ((avdatum.specified & AVTAB_AV) &&
-		    (avdatum.specified & AVTAB_TYPE)) {
-			printk(KERN_ERR "security: avtab: entry has both "
-			       "access vectors and types\n");
-			goto bad;
-		}
-		if (avdatum.specified & AVTAB_AV) {
-			if (avdatum.specified & AVTAB_ALLOWED)
-				avtab_allowed(&avdatum) = le32_to_cpu(buf[items++]);
-			if (avdatum.specified & AVTAB_AUDITDENY)
-				avtab_auditdeny(&avdatum) = le32_to_cpu(buf[items++]);
-			if (avdatum.specified & AVTAB_AUDITALLOW)
-				avtab_auditallow(&avdatum) = le32_to_cpu(buf[items++]);
-		} else {
-			if (avdatum.specified & AVTAB_TRANSITION)
-				avtab_transition(&avdatum) = le32_to_cpu(buf[items++]);
-			if (avdatum.specified & AVTAB_CHANGE)
-				avtab_change(&avdatum) = le32_to_cpu(buf[items++]);
-			if (avdatum.specified & AVTAB_MEMBER)
-				avtab_member(&avdatum) = le32_to_cpu(buf[items++]);
-		}
-		if (items != items2) {
-			printk(KERN_ERR "security: avtab: entry only had %d "
-			       "items, expected %d\n", items2, items);
-			goto bad;
-		}
 		rc = avtab_insert(a, &avkey, &avdatum);
 		if (rc) {
 			if (rc == -ENOMEM)
--- diff/security/selinux/ss/avtab.h	2003-08-20 13:16:36.000000000 +0000
+++ source/security/selinux/ss/avtab.h	2004-03-16 09:37:58.114705392 +0000
@@ -7,6 +7,16 @@
  *
  *  Author : Stephen Smalley, <sds@epoch.ncsc.mil>
  */
+
+/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * 	Added conditional policy language extensions
+ *
+ * Copyright (C) 2003 Tresys Technology, LLC
+ *	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, version 2.
+ */
 #ifndef _SS_AVTAB_H_
 #define _SS_AVTAB_H_
 
@@ -25,6 +35,7 @@ struct avtab_datum {
 #define AVTAB_MEMBER     32
 #define AVTAB_CHANGE     64
 #define AVTAB_TYPE       (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
+#define AVTAB_ENABLED    0x80000000 /* reserved for used in cond_avtab */
 	u32 specified;	/* what fields are specified */
 	u32 data[3];	/* access vectors or types */
 #define avtab_allowed(x) (x)->data[0]
@@ -56,8 +67,17 @@ int avtab_map(struct avtab *h,
 			    void *args),
 	      void *args);
 void avtab_hash_eval(struct avtab *h, char *tag);
+
+int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey);
 int avtab_read(struct avtab *a, void *fp, u32 config);
 
+struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key,
+					  struct avtab_datum *datum);
+
+struct avtab_node *avtab_search_node(struct avtab *h, struct avtab_key *key, int specified);
+
+struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified);
+
 #define AVTAB_HASH_BITS 15
 #define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
 #define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1)
--- diff/security/selinux/ss/mls.h	2003-08-20 13:16:36.000000000 +0000
+++ source/security/selinux/ss/mls.h	2004-03-16 09:37:58.115705240 +0000
@@ -48,12 +48,12 @@ usercon.range = __ranges->range;
 
 #define mls_end_user_ranges } }
 
-#define mls_symtab_names , "levels", "categories"
-#define mls_symtab_sizes , 16, 16
-#define mls_index_f ,sens_index, cat_index
-#define mls_destroy_f ,sens_destroy, cat_destroy
-#define mls_read_f ,sens_read, cat_read
-#define mls_write_f ,sens_write, cat_write
+#define mls_symtab_names  "levels", "categories",
+#define mls_symtab_sizes  16, 16,
+#define mls_index_f sens_index, cat_index,
+#define mls_destroy_f sens_destroy, cat_destroy,
+#define mls_read_f sens_read, cat_read,
+#define mls_write_f sens_write, cat_write,
 #define mls_policydb_index_others(p) printk(", %d levels", p->nlevels);
 
 #define mls_set_config(config) config |= POLICYDB_CONFIG_MLS
--- diff/security/selinux/ss/policydb.c	2004-02-18 08:54:13.000000000 +0000
+++ source/security/selinux/ss/policydb.c	2004-03-16 09:37:58.116705088 +0000
@@ -3,12 +3,25 @@
  *
  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
  */
+
+/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * 	Added conditional policy language extensions
+ *
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ *	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, version 2.
+ */
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include "security.h"
+
 #include "policydb.h"
+#include "conditional.h"
 #include "mls.h"
 
 #define _DEBUG_HASHES
@@ -19,8 +32,9 @@ static char *symtab_name[SYM_NUM] = {
 	"classes",
 	"roles",
 	"types",
-	"users"
+	"users",
 	mls_symtab_names
+	"bools"
 };
 #endif
 
@@ -29,8 +43,9 @@ static unsigned int symtab_sizes[SYM_NUM
 	32,
 	16,
 	512,
-	128
+	128,
 	mls_symtab_sizes
+	16
 };
 
 /*
@@ -95,6 +110,10 @@ int policydb_init(struct policydb *p)
 	if (rc)
 		goto out_free_avtab;
 
+	rc = cond_policydb_init(p);
+	if (rc)
+		goto out_free_avtab;
+
 out:
 	return rc;
 
@@ -195,8 +214,9 @@ static int (*index_f[SYM_NUM]) (void *ke
 	class_index,
 	role_index,
 	type_index,
-	user_index
+	user_index,
 	mls_index_f
+	cond_index_bool
 };
 
 /*
@@ -267,8 +287,8 @@ int policydb_index_others(struct policyd
 {
 	int i, rc = 0;
 
-	printk(KERN_INFO "security:  %d users, %d roles, %d types",
-	       p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim);
+	printk(KERN_INFO "security:  %d users, %d roles, %d types, %d bools",
+	       p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim);
 	mls_policydb_index_others(p);
 	printk("\n");
 
@@ -296,6 +316,11 @@ int policydb_index_others(struct policyd
 		goto out;
 	}
 
+	if (cond_init_bool_indexes(p)) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
 	for (i = SYM_ROLES; i < SYM_NUM; i++) {
 		p->sym_val_to_name[i] =
 			kmalloc(p->symtab[i].nprim * sizeof(char *), GFP_KERNEL);
@@ -402,8 +427,9 @@ static int (*destroy_f[SYM_NUM]) (void *
 	class_destroy,
 	role_destroy,
 	type_destroy,
-	user_destroy
+	user_destroy,
 	mls_destroy_f
+	cond_destroy_bool
 };
 
 void ocontext_destroy(struct ocontext *c, int i)
@@ -467,6 +493,8 @@ void policydb_destroy(struct policydb *p
 		kfree(gtmp);
 	}
 
+	cond_policydb_destroy(p);
+
 	return;
 }
 
@@ -1040,8 +1068,9 @@ static int (*read_f[SYM_NUM]) (struct po
 	class_read,
 	role_read,
 	type_read,
-	user_read
+	user_read,
 	mls_read_f
+	cond_read_bool
 };
 
 #define mls_config(x) \
@@ -1057,7 +1086,7 @@ int policydb_read(struct policydb *p, vo
 	struct role_trans *tr, *ltr;
 	struct ocontext *l, *c, *newc;
 	struct genfs *genfs_p, *genfs, *newgenfs;
-	int i, j, rc;
+	int i, j, rc, policy_ver, num_syms;
 	u32 *buf, len, len2, config, nprim, nel, nel2;
 	char *policydb_str;
 
@@ -1122,7 +1151,8 @@ int policydb_read(struct policydb *p, vo
 	for (i = 0; i < 4; i++)
 		buf[i] = le32_to_cpu(buf[i]);
 
-	if (buf[0] != POLICYDB_VERSION) {
+	policy_ver = buf[0];
+	if (policy_ver != POLICYDB_VERSION && policy_ver != POLICYDB_VERSION_COMPAT) {
 		printk(KERN_ERR "security:  policydb version %d does not match "
 		       "my version %d\n", buf[0], POLICYDB_VERSION);
 		goto bad;
@@ -1134,18 +1164,30 @@ int policydb_read(struct policydb *p, vo
 		       mls_config(config));
 		goto bad;
 	}
-	if (buf[2] != SYM_NUM || buf[3] != OCON_NUM) {
-		printk(KERN_ERR "security:  policydb table sizes (%d,%d) do "
-		       "not match mine (%d,%d)\n",
-		       buf[2], buf[3], SYM_NUM, OCON_NUM);
-		goto bad;
+
+	if (policy_ver == POLICYDB_VERSION_COMPAT) {
+		if (buf[2] != (SYM_NUM - 1) || buf[3] != OCON_NUM) {
+			printk(KERN_ERR "security:  policydb table sizes (%d,%d) do "
+			       "not match mine (%d,%d)\n",
+			       buf[2], buf[3], SYM_NUM, OCON_NUM);
+			goto bad;
+		}
+		num_syms = SYM_NUM - 1;
+	} else {
+		if (buf[2] != SYM_NUM || buf[3] != OCON_NUM) {
+			printk(KERN_ERR "security:  policydb table sizes (%d,%d) do "
+			       "not match mine (%d,%d)\n",
+			       buf[2], buf[3], SYM_NUM, OCON_NUM);
+			goto bad;
+		}
+		num_syms = SYM_NUM;
 	}
 
 	rc = mls_read_nlevels(p, fp);
 	if (rc)
 		goto bad;
 
-	for (i = 0; i < SYM_NUM; i++) {
+	for (i = 0; i < num_syms; i++) {
 		buf = next_entry(fp, sizeof(u32)*2);
 		if (!buf) {
 			rc = -EINVAL;
@@ -1166,6 +1208,12 @@ int policydb_read(struct policydb *p, vo
 	if (rc)
 		goto bad;
 
+	if (policy_ver == POLICYDB_VERSION) {
+		rc = cond_read_list(p, fp);
+		if (rc)
+			goto bad;
+	}
+
 	buf = next_entry(fp, sizeof(u32));
 	if (!buf) {
 		rc = -EINVAL;
--- diff/security/selinux/ss/policydb.h	2003-10-27 09:20:39.000000000 +0000
+++ source/security/selinux/ss/policydb.h	2004-03-16 09:37:58.117704936 +0000
@@ -4,6 +4,17 @@
  *
  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
  */
+
+/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * 	Added conditional policy language extensions
+ *
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ *	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, version 2.
+ */
+
 #ifndef _SS_POLICYDB_H_
 #define _SS_POLICYDB_H_
 
@@ -100,6 +111,13 @@ struct cat_datum {
 };
 #endif
 
+/* Boolean data type */
+struct cond_bool_datum {
+	__u32 value;		/* internal type value */
+	int state;
+};
+
+struct cond_node;
 
 /*
  * The configuration data includes security contexts for
@@ -145,9 +163,11 @@ struct genfs {
 #ifdef CONFIG_SECURITY_SELINUX_MLS
 #define SYM_LEVELS  5
 #define SYM_CATS    6
-#define SYM_NUM     7
+#define SYM_BOOLS   7
+#define SYM_NUM     8
 #else
-#define SYM_NUM     5
+#define SYM_BOOLS   5
+#define SYM_NUM     6
 #endif
 
 /* object context array indices */
@@ -170,6 +190,7 @@ struct policydb {
 #define p_users symtab[SYM_USERS]
 #define p_levels symtab[SYM_LEVELS]
 #define p_cats symtab[SYM_CATS]
+#define p_bools symtab[SYM_BOOLS]
 
 	/* symbol names indexed by (value - 1) */
 	char **sym_val_to_name[SYM_NUM];
@@ -180,6 +201,7 @@ struct policydb {
 #define p_user_val_to_name sym_val_to_name[SYM_USERS]
 #define p_sens_val_to_name sym_val_to_name[SYM_LEVELS]
 #define p_cat_val_to_name sym_val_to_name[SYM_CATS]
+#define p_bool_val_to_name sym_val_to_name[SYM_BOOLS]
 
 	/* class, role, and user attributes indexed by (value - 1) */
 	struct class_datum **class_val_to_struct;
@@ -192,6 +214,13 @@ struct policydb {
 	/* role transitions */
 	struct role_trans *role_tr;
 
+	/* bools indexed by (value - 1) */
+	struct cond_bool_datum **bool_val_to_struct;
+	/* type enforcement conditional access vectors and transitions */
+	struct avtab te_cond_avtab;
+	/* linked list indexing te_cond_avtab by conditional */
+	struct cond_node* cond_list;
+
 	/* role allows */
 	struct role_allow *role_allow;
 
--- diff/security/selinux/ss/services.c	2004-03-11 10:20:29.000000000 +0000
+++ source/security/selinux/ss/services.c	2004-03-16 09:37:58.118704784 +0000
@@ -9,6 +9,15 @@
  *	This program is free software; you can redistribute it and/or modify
  *	it under the terms of the GNU General Public License version 2,
  *      as published by the Free Software Foundation.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * 	Added conditional policy language extensions
+ *
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ *	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, version 2.
  */
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -26,6 +35,7 @@
 #include "policydb.h"
 #include "sidtab.h"
 #include "services.h"
+#include "conditional.h"
 #include "mls.h"
 
 extern void selnl_notify_policyload(u32 seqno);
@@ -225,6 +235,9 @@ static int context_struct_compute_av(str
 			avd->auditallow = avtab_auditallow(avdatum);
 	}
 
+	/* Check conditional av table for additional permissions */
+	cond_compute_av(&policydb.te_cond_avtab, &avkey, avd);
+
 	/*
 	 * Remove any permissions prohibited by the MLS policy.
 	 */
@@ -249,7 +262,7 @@ static int context_struct_compute_av(str
 	 * pair.
 	 */
 	if (tclass == SECCLASS_PROCESS &&
-	    avd->allowed && PROCESS__TRANSITION &&
+	    (avd->allowed & PROCESS__TRANSITION) &&
 	    scontext->role != tcontext->role) {
 		for (ra = policydb.role_allow; ra; ra = ra->next) {
 			if (scontext->role == ra->role &&
@@ -386,7 +399,7 @@ int security_sid_to_context(u32 sid, cha
 			char *scontextp;
 
 			*scontext_len = strlen(initial_sid_to_string[sid]) + 1;
-			scontextp = kmalloc(*scontext_len,GFP_KERNEL);
+			scontextp = kmalloc(*scontext_len,GFP_ATOMIC);
 			strcpy(scontextp, initial_sid_to_string[sid]);
 			*scontext = scontextp;
 			goto out;
@@ -573,6 +586,7 @@ static int security_compute_sid(u32 ssid
 	struct role_trans *roletr = 0;
 	struct avtab_key avkey;
 	struct avtab_datum *avdatum;
+	struct avtab_node *node;
 	unsigned int type_change = 0;
 	int rc = 0;
 
@@ -639,6 +653,18 @@ static int security_compute_sid(u32 ssid
 	avkey.target_type = tcontext->type;
 	avkey.target_class = tclass;
 	avdatum = avtab_search(&policydb.te_avtab, &avkey, AVTAB_TYPE);
+
+	/* If no permanent rule, also check for enabled conditional rules */
+	if(!avdatum) {
+		node = avtab_search_node(&policydb.te_cond_avtab, &avkey, specified);
+		for (; node != NULL; node = avtab_search_node_next(node, specified)) {
+			if (node->datum.specified & AVTAB_ENABLED) {
+				avdatum = &node->datum;
+				break;
+			}
+		}
+	}
+
 	type_change = (avdatum && (avdatum->specified & specified));
 	if (type_change) {
 		/* Use the type from the type transition/member/change rule. */
@@ -1000,6 +1026,7 @@ int security_load_policy(void *data, siz
 			return -EINVAL;
 		}
 		ss_initialized = 1;
+
 		LOAD_UNLOCK;
 		selinux_complete_init();
 		return 0;
@@ -1046,6 +1073,7 @@ int security_load_policy(void *data, siz
 	memcpy(&policydb, &newpolicydb, sizeof policydb);
 	sidtab_set(&sidtab, &newsidtab);
 	seqno = ++latest_granting;
+
 	POLICY_WRUNLOCK;
 	LOAD_UNLOCK;
 
@@ -1428,3 +1456,116 @@ out:
 	POLICY_RDUNLOCK;
 	return rc;
 }
+
+int security_get_bools(int *len, char ***names, int **values)
+{
+	int i, rc = -ENOMEM;
+
+	POLICY_RDLOCK;
+	*names = NULL;
+	*values = NULL;
+
+	*len = policydb.p_bools.nprim;
+	if (!*len) {
+		rc = 0;
+		goto out;
+	}
+
+	*names = (char**)kmalloc(sizeof(char*) * *len, GFP_ATOMIC);
+	if (!*names)
+		goto err;
+	memset(*names, 0, sizeof(char*) * *len);
+
+	*values = (int*)kmalloc(sizeof(int) * *len, GFP_ATOMIC);
+	if (!*values)
+		goto err;
+
+	for (i = 0; i < *len; i++) {
+		size_t name_len;
+		(*values)[i] = policydb.bool_val_to_struct[i]->state;
+		name_len = strlen(policydb.p_bool_val_to_name[i]) + 1;
+		(*names)[i] = (char*)kmalloc(sizeof(char) * name_len, GFP_ATOMIC);
+		if (!(*names)[i])
+			goto err;
+		strncpy((*names)[i], policydb.p_bool_val_to_name[i], name_len);
+		(*names)[i][name_len - 1] = 0;
+	}
+	rc = 0;
+out:
+	POLICY_RDUNLOCK;
+	return rc;
+err:
+	if (*names) {
+		for (i = 0; i < *len; i++)
+			if ((*names)[i])
+				kfree((*names)[i]);
+	}
+	if (*values)
+		kfree(*values);
+	goto out;
+}
+
+
+int security_set_bools(int len, int *values)
+{
+	int i, rc = 0;
+	int lenp, seqno = 0;
+	struct cond_node *cur;
+
+	POLICY_WRLOCK;
+
+	lenp = policydb.p_bools.nprim;
+	if (len != lenp) {
+		rc = -EFAULT;
+		goto out;
+	}
+
+	printk(KERN_INFO "security: committed booleans { ");
+	for (i = 0; i < len; i++) {
+		if (values[i]) {
+			policydb.bool_val_to_struct[i]->state = 1;
+		} else {
+			policydb.bool_val_to_struct[i]->state = 0;
+		}
+		if (i != 0)
+			printk(", ");
+		printk("%s:%d", policydb.p_bool_val_to_name[i],
+		       policydb.bool_val_to_struct[i]->state);
+	}
+	printk(" }\n");
+
+	for (cur = policydb.cond_list; cur != NULL; cur = cur->next) {
+		rc = evaluate_cond_node(&policydb, cur);
+		if (rc)
+			goto out;
+	}
+
+	seqno = ++latest_granting;
+
+out:
+	POLICY_WRUNLOCK;
+	if (!rc) {
+		avc_ss_reset(seqno);
+		selnl_notify_policyload(seqno);
+	}
+	return rc;
+}
+
+int security_get_bool_value(int bool)
+{
+	int rc = 0;
+	int len;
+
+	POLICY_RDLOCK;
+
+	len = policydb.p_bools.nprim;
+	if (bool >= len) {
+		rc = -EFAULT;
+		goto out;
+	}
+
+	rc = policydb.bool_val_to_struct[bool]->state;
+out:
+	POLICY_RDUNLOCK;
+	return rc;
+}
--- diff/sound/arm/Kconfig	2002-11-11 11:09:38.000000000 +0000
+++ source/sound/arm/Kconfig	2004-03-16 09:37:58.119704632 +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 09:00:55.000000000 +0000
+++ source/sound/arm/sa11xx-uda1341.c	2004-03-16 09:37:58.119704632 +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 09:07:24.000000000 +0000
+++ source/sound/core/Kconfig	2004-03-16 09:37:58.120704480 +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-16 09:37:58.121704328 +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-16 09:37:58.121704328 +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 */
@@ -281,7 +281,7 @@ int snd_card_free(snd_card_t * card)
 	}
 	if (card->private_free)
 		card->private_free(card);
-	snd_info_free_entry(card->proc_id);
+	snd_info_unregister(card->proc_id);
 	if (snd_info_card_free(card) < 0) {
 		snd_printk(KERN_WARNING "unable to free card info\n");
 		/* Not fatal error */
--- diff/sound/core/memalloc.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/core/memalloc.c	2004-03-16 09:37:58.125703720 +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-16 09:37:58.128703264 +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-16 09:37:58.129703112 +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-16 09:37:58.132702656 +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-16 09:37:58.133702504 +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-16 09:37:58.133702504 +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_init.c	2003-05-21 10:49:56.000000000 +0000
+++ source/sound/core/seq/oss/seq_oss_init.c	2004-03-16 09:37:58.134702352 +0000
@@ -349,18 +349,11 @@ create_port(seq_oss_devinfo_t *dp)
 static int
 delete_port(seq_oss_devinfo_t *dp)
 {
-	snd_seq_port_info_t port_info;
-
 	if (dp->port < 0)
 		return 0;
 
 	debug_printk(("delete_port %i\n", dp->port));
-	memset(&port_info, 0, sizeof(port_info));
-	port_info.addr.client = dp->cseq;
-	port_info.addr.port = dp->port;
-	return snd_seq_kernel_client_ctl(dp->cseq,
-					 SNDRV_SEQ_IOCTL_DELETE_PORT,
-					 &port_info);
+	return snd_seq_event_port_detach(dp->cseq, dp->port);
 }
 
 /*
--- diff/sound/core/seq/oss/seq_oss_midi.c	2003-06-09 13:18:21.000000000 +0000
+++ source/sound/core/seq/oss/seq_oss_midi.c	2004-03-16 09:37:58.135702200 +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 13:18:21.000000000 +0000
+++ source/sound/core/seq/oss/seq_oss_synth.c	2004-03-16 09:37:58.135702200 +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-16 09:37:58.137701896 +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-16 09:37:58.137701896 +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-16 09:37:58.138701744 +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-16 09:37:58.139701592 +0000
@@ -257,17 +257,12 @@ static int midisynth_unuse(void *private
 /* delete given midi synth port */
 static void snd_seq_midisynth_delete(seq_midisynth_t *msynth)
 {
-	snd_seq_port_info_t port;
-	
 	if (msynth == NULL)
 		return;
 
 	if (msynth->seq_client > 0) {
 		/* delete port */
-		memset(&port, 0, sizeof(port));
-		port.addr.client = msynth->seq_client;
-		port.addr.port = msynth->seq_port;
-		snd_seq_kernel_client_ctl(port.addr.client, SNDRV_SEQ_IOCTL_DELETE_PORT, &port);
+		snd_seq_event_port_detach(msynth->seq_client, msynth->seq_port);
 	}
 
 	if (msynth->parser)
@@ -285,7 +280,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);
 }
 
@@ -443,7 +438,6 @@ snd_seq_midisynth_unregister_port(snd_se
 		up(&register_mutex);
 		return -ENODEV;
 	}
-	snd_seq_event_port_detach(client->seq_client, client->ports[device]->seq_port);
 	ports = client->ports_per_device[device];
 	client->ports_per_device[device] = 0;
 	msynth = client->ports[device];
--- diff/sound/core/sgbuf.c	2003-06-30 09:07:24.000000000 +0000
+++ source/sound/core/sgbuf.c	2004-03-16 09:37:58.139701592 +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-16 09:37:58.140701440 +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 09:07:24.000000000 +0000
+++ source/sound/drivers/mpu401/Makefile	2004-03-16 09:37:58.140701440 +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-16 09:37:58.141701288 +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 09:07:24.000000000 +0000
+++ source/sound/drivers/opl3/Makefile	2004-03-16 09:37:58.141701288 +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 09:07:24.000000000 +0000
+++ source/sound/drivers/opl4/Makefile	2004-03-16 09:37:58.142701136 +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 09:07:24.000000000 +0000
+++ source/sound/drivers/vx/Makefile	2004-03-16 09:37:58.142701136 +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-16 09:37:58.143700984 +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 09:07:24.000000000 +0000
+++ source/sound/drivers/vx/vx_mixer.c	2004-03-16 09:37:58.144700832 +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-16 09:37:58.145700680 +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-16 09:37:58.146700528 +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 09:07:24.000000000 +0000
+++ source/sound/isa/Kconfig	2004-03-16 09:37:58.166697488 +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-16 09:37:58.167697336 +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-16 09:37:58.168697184 +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-16 09:37:58.169697032 +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-16 09:37:58.177695816 +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/dt019x.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/isa/dt019x.c	2004-03-16 09:37:58.177695816 +0000
@@ -143,7 +143,7 @@ static int __devinit snd_card_dt019x_pnp
 	port[dev] = pnp_port_start(pdev, 0);
 	dma8[dev] = pnp_dma(pdev, 0);
 	irq[dev] = pnp_irq(pdev, 0);
-	snd_printdd("dt019x: found audio interface: port=0x%lx, irq=0x%lx, dma=0x%lx\n",
+	snd_printdd("dt019x: found audio interface: port=0x%lx, irq=0x%x, dma=0x%x\n",
 			port[dev],irq[dev],dma8[dev]);
 
 	pdev = acard->devmpu;
@@ -164,7 +164,7 @@ static int __devinit snd_card_dt019x_pnp
 		}
 		mpu_port[dev] = pnp_port_start(pdev, 0);
 		mpu_irq[dev] = pnp_irq(pdev, 0);
-		snd_printdd("dt019x: found MPU-401: port=0x%lx, irq=0x%lx\n",
+		snd_printdd("dt019x: found MPU-401: port=0x%lx, irq=0x%x\n",
 			 	mpu_port[dev],mpu_irq[dev]);
 	} else {
 	__mpu_error:
--- diff/sound/isa/es1688/es1688_lib.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/isa/es1688/es1688_lib.c	2004-03-16 09:37:58.178695664 +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-16 09:37:58.180695360 +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-16 09:37:58.181695208 +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-16 09:37:58.183694904 +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 10:50:17.000000000 +0000
+++ source/sound/isa/sb/sb16_main.c	2004-03-16 09:37:58.183694904 +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 09:07:24.000000000 +0000
+++ source/sound/isa/sb/sb8_main.c	2004-03-16 09:37:58.184694752 +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-16 09:37:58.185694600 +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 10:49:46.000000000 +0000
+++ source/sound/isa/wavefront/wavefront_synth.c	2004-03-16 09:37:58.187694296 +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/wavfront.c	2003-05-21 10:50:17.000000000 +0000
+++ source/sound/oss/wavfront.c	2004-03-16 09:37:58.189693992 +0000
@@ -75,6 +75,7 @@
 #include <linux/smp_lock.h>
 #include <linux/ptrace.h>
 #include <linux/fcntl.h>
+#include <linux/syscalls.h>
 #include <linux/ioport.h>    
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
@@ -2489,11 +2490,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 +2522,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 +2531,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 +2541,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 +2580,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 09:07:25.000000000 +0000
+++ source/sound/parisc/Kconfig	2004-03-16 09:37:58.189693992 +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 08:47:34.000000000 +0000
+++ source/sound/parisc/harmony.c	2004-03-16 09:37:58.190693840 +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;
@@ -357,7 +358,7 @@ static void snd_harmony_enable_interrupt
  * The interrupt routine must provide adresse of next physical pages 
  * used by harmony
  */
-void snd_card_harmony_interrupt(int irq, void *dev, struct pt_regs *regs)
+static int snd_card_harmony_interrupt(int irq, void *dev, struct pt_regs *regs)
 {
 	snd_card_harmony_t *harmony = (snd_card_harmony_t *)dev;
 	u32 dstatus = 0;
@@ -413,6 +414,8 @@ void snd_card_harmony_interrupt(int irq,
 		}
 	}
 	snd_harmony_enable_interrupts(harmony);
+
+	return IRQ_HANDLED;
 }
 
 /* 
@@ -844,22 +847,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-16 09:37:58.191693688 +0000
@@ -3,21 +3,62 @@
 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_ATIIXP
+	tristate "ATI IXP 150/200/250"
+	depends on SND
+	select SND_AC97_CODEC
+	help
+	  Say 'Y' or 'M' to include support for ATI IXP 150/200/250 AC97 controller.
+
+config SND_AU8810
+        tristate "Aureal Advantage"
+        depends on SND
+	select SND_MPU401_UART
+	select SND_AC97_CODEC
+        help
+          Say 'Y' or 'M' to include support for Aureal Advantage soundcards.
+ 
+config SND_AU8820
+        tristate "Aureal Vortex"
+        depends on SND
+	select SND_MPU401_UART
+	select SND_AC97_CODEC
+        help
+          Say 'Y' or 'M' to include support for Aureal Vortex soundcards.
+ 
+config SND_AU8830
+        tristate "Aureal Vortex 2"
+        depends on SND
+	select SND_MPU401_UART
+	select SND_AC97_CODEC
+        help
+          Say 'Y' or 'M' to include support for Aureal Vortex 2 soundcards.
+ 
 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 +66,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 +81,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 +100,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 +130,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 +138,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 +146,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 +156,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 +165,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 +175,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 +194,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 +211,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 +221,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 +253,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 +264,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,25 +275,41 @@ 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.
 
+config SND_INTEL8X0M
+	tristate "Intel i8x0/MX440; AMD768/8111 modems (EXPERIMENTAL)"
+	depends on SND && EXPERIMENTAL
+	select SND_AC97_CODEC
+	help
+	  Say 'Y' or 'M' to include support for Intel8x0 and AMD768/8111 based
+	  modems.
+
 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-16 09:37:58.191693688 +0000
@@ -4,6 +4,7 @@
 #
 
 snd-als4000-objs := als4000.o
+snd-atiixp-objs := atiixp.o
 snd-azt3328-objs := azt3328.o
 snd-bt87x-objs := bt87x.o
 snd-cmipci-objs := cmipci.o
@@ -14,6 +15,7 @@ snd-es1938-objs := es1938.o
 snd-es1968-objs := es1968.o
 snd-fm801-objs := fm801.o
 snd-intel8x0-objs := intel8x0.o
+snd-intel8x0m-objs := intel8x0m.o
 snd-maestro3-objs := maestro3.o
 snd-rme32-objs := rme32.o
 snd-rme96-objs := rme96.o
@@ -22,6 +24,7 @@ snd-via82xx-objs := via82xx.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_ALS4000) += snd-als4000.o
+obj-$(CONFIG_SND_ATIIXP) += snd-atiixp.o
 obj-$(CONFIG_SND_AZT3328) += snd-azt3328.o
 obj-$(CONFIG_SND_BT87X) += snd-bt87x.o
 obj-$(CONFIG_SND_CMIPCI) += snd-cmipci.o
@@ -32,10 +35,24 @@ obj-$(CONFIG_SND_ES1938) += snd-es1938.o
 obj-$(CONFIG_SND_ES1968) += snd-es1968.o
 obj-$(CONFIG_SND_FM801) += snd-fm801.o
 obj-$(CONFIG_SND_INTEL8X0) += snd-intel8x0.o
+obj-$(CONFIG_SND_INTEL8X0M) += snd-intel8x0m.o
 obj-$(CONFIG_SND_MAESTRO3) += snd-maestro3.o
 obj-$(CONFIG_SND_RME32) += snd-rme32.o
 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/ \
+	au88x0/ \
+	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-16 09:37:58.192693536 +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-16 09:37:58.195693080 +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-16 09:37:58.198692624 +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-16 09:37:58.198692624 +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-16 09:37:58.199692472 +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-16 09:37:58.199692472 +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-16 09:37:58.201692168 +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-16 09:37:58.202692016 +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-16 09:37:58.203691864 +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-16 09:37:58.204691712 +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-16 09:37:58.206691408 +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-16 09:37:58.208691104 +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-16 09:37:58.212690496 +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.c	2003-09-30 14:46:21.000000000 +0000
+++ source/sound/pci/emu10k1/emu10k1.c	2004-03-16 09:37:58.212690496 +0000
@@ -80,7 +80,9 @@ MODULE_PARM_SYNTAX(enable_ir, SNDRV_ENAB
 
 static struct pci_device_id snd_emu10k1_ids[] = {
 	{ 0x1102, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	/* EMU10K1 */
+#if 0 /* FIXME: not working! */
 	{ 0x1102, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	/* Dell OEM version (EMU10K1) */
+#endif
 	{ 0x1102, 0x0004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },	/* Audigy */
 	{ 0, }
 };
--- diff/sound/pci/emu10k1/emu10k1_callback.c	2002-10-16 03:27:49.000000000 +0000
+++ source/sound/pci/emu10k1/emu10k1_callback.c	2004-03-16 09:37:58.213690344 +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-16 09:37:58.215690040 +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-16 09:37:58.217689736 +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-16 09:37:58.218689584 +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-16 09:37:58.218689584 +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-16 09:37:58.219689432 +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-16 09:37:58.221689128 +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-16 09:37:58.222688976 +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-16 09:37:58.224688672 +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-16 09:37:58.225688520 +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-16 09:37:58.226688368 +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-16 09:37:58.226688368 +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-16 09:37:58.227688216 +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 13:16:35.000000000 +0000
+++ source/sound/pci/ice1712/ews.c	2004-03-16 09:37:58.228688064 +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-16 09:37:58.228688064 +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-16 09:37:58.231687608 +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-16 09:37:58.231687608 +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-16 09:37:58.234687152 +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-16 09:37:58.234687152 +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 14:46:21.000000000 +0000
+++ source/sound/pci/ice1712/revo.c	2004-03-16 09:37:58.235687000 +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-16 09:37:58.237686696 +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-16 09:37:58.240686240 +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-16 09:37:58.242685936 +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-16 09:37:58.244685632 +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-16 09:37:58.246685328 +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-16 09:37:58.249684872 +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-16 09:37:58.251684568 +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-16 09:37:58.252684416 +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-16 09:37:58.255683960 +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 10:49:56.000000000 +0000
+++ source/sound/pci/trident/trident_memory.c	2004-03-16 09:37:58.256683808 +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 09:07:25.000000000 +0000
+++ source/sound/pci/trident/trident_synth.c	2004-03-16 09:37:58.257683656 +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-16 09:37:58.260683200 +0000
@@ -107,7 +107,7 @@ MODULE_PARM_DESC(ac97_clock, "AC'97 code
 MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:48000");
 MODULE_PARM(ac97_quirk, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
-MODULE_PARM_SYNTAX(ac97_quirk, SNDRV_ENABLED ",allows:{{-1,3}},dialog:list,default:-1");
+MODULE_PARM_SYNTAX(ac97_quirk, SNDRV_ENABLED ",allows:{{-1,4}},dialog:list,default:-1");
 MODULE_PARM(dxs_support, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA)");
 MODULE_PARM_SYNTAX(dxs_support, SNDRV_ENABLED ",allows:{{0,4}},dialog:list");
@@ -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,74 @@ 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 */
+	unsigned int spdif_on: 1;	/* only spdif rates work to external DACs */
+
+	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 +424,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 +457,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 +470,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 +484,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 +759,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 +843,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 +925,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);
@@ -1069,7 +1070,11 @@ static int snd_via82xx_pcm_open(via82xx_
 	ratep = &chip->rates[viadev->direction];
 	spin_lock_irqsave(&ratep->lock, flags);
 	ratep->used++;
-	if (chip->dxs_fixed && viadev->reg_offset < 0x40) {
+	if (chip->spdif_on) {
+		runtime->hw.rates = SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000;
+		runtime->hw.rate_min = 32000;
+		runtime->hw.rate_max = 48000;
+	} else if (chip->dxs_fixed && viadev->reg_offset < 0x40) {
 		/* fixed DXS playback rate */
 		runtime->hw.rates = SNDRV_PCM_RATE_48000;
 		runtime->hw.rate_min = runtime->hw.rate_max = 48000;
@@ -1290,7 +1295,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 +1312,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 +1346,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 +1360,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 +1390,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;
@@ -1468,6 +1478,8 @@ static int snd_via8233_dxs3_spdif_put(sn
 	val = oval & ~VIA8233_SPDIF_DX3;
 	if (ucontrol->value.integer.value[0])
 		val |= VIA8233_SPDIF_DX3;
+	/* save the spdif flag for rate filtering */
+	chip->spdif_on = ucontrol->value.integer.value[0] ? 1 : 0;
 	if (val != oval) {
 		pci_write_config_byte(chip->pci, VIA8233_SPDIF_CTRL, val);
 		return 1;
@@ -1560,6 +1572,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 +1937,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 +2015,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-16 09:37:58.262682896 +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-16 09:37:58.263682744 +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 09:07:25.000000000 +0000
+++ source/sound/pcmcia/Makefile	2004-03-16 09:37:58.263682744 +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-16 09:37:58.263682744 +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 14:46:21.000000000 +0000
+++ source/sound/ppc/pmac.c	2004-03-16 09:37:58.264682592 +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-16 09:37:58.265682440 +0000
@@ -94,6 +94,7 @@ typedef struct pmac_tumbler_t {
 	unsigned int mix_vol[VOL_IDX_LAST_MIX][2]; /* stereo volumes for tas3004 */
 	int drc_range;
 	int drc_enable;
+	int capture_source;
 } pmac_tumbler_t;
 
 
@@ -135,7 +136,7 @@ static int snapper_init_client(pmac_keyw
 		TAS_REG_MCS, (1<<6)|(2<<4)|0,
 		/* normal operation, all-pass mode */
 		TAS_REG_MCS2, (1<<1),
-		/* normal output, no deemphasis, A input, power-up */
+		/* normal output, no deemphasis, A input, power-up, line-in */
 		TAS_REG_ACS, 0,
 		0, /* terminator */
 	};
@@ -681,6 +682,51 @@ static int tumbler_put_mute_switch(snd_k
 	return 0;
 }
 
+static int snapper_set_capture_source(pmac_tumbler_t *mix)
+{
+	return snd_pmac_keywest_write_byte(&mix->i2c, TAS_REG_ACS,
+					   mix->capture_source ? 2 : 0);
+}
+
+static int snapper_info_capture_source(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	static char *texts[2] = {
+		"Line", "Mic"
+	};
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item > 1)
+		uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snapper_get_capture_source(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	pmac_t *chip = snd_kcontrol_chip(kcontrol);
+	pmac_tumbler_t *mix = chip->mixer_data;
+
+	snd_assert(mix, return -ENODEV);
+	ucontrol->value.integer.value[0] = mix->capture_source;
+	return 0;
+}
+
+static int snapper_put_capture_source(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	pmac_t *chip = snd_kcontrol_chip(kcontrol);
+	pmac_tumbler_t *mix = chip->mixer_data;
+	int change;
+
+	snd_assert(mix, return -ENODEV);
+	change = ucontrol->value.integer.value[0] != mix->capture_source;
+	if (change) {
+		mix->capture_source = !!ucontrol->value.integer.value[0];
+		snapper_set_capture_source(mix);
+	}
+	return change;
+}
+
 #define DEFINE_SNAPPER_MIX(xname,idx,ofs) { \
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,\
 	.name = xname, \
@@ -754,6 +800,12 @@ static snd_kcontrol_new_t snapper_mixers
 	  .get = tumbler_get_drc_value,
 	  .put = tumbler_put_drc_value
 	},
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	  .name = "Input Source", /* FIXME: "Capture Source" doesn't work properly */
+	  .info = snapper_info_capture_source,
+	  .get = snapper_get_capture_source,
+	  .put = snapper_put_capture_source
+	},
 };
 
 static snd_kcontrol_new_t tumbler_hp_sw __initdata = {
@@ -929,9 +981,10 @@ 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);
+		snapper_set_capture_source(mix);
 	}
 	tumbler_set_master_volume(mix);
 	if (chip->update_automute)
--- diff/sound/sparc/Kconfig	2002-11-11 11:09:38.000000000 +0000
+++ source/sound/sparc/Kconfig	2004-03-16 09:37:58.266682288 +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 09:00:55.000000000 +0000
+++ source/sound/sparc/amd7930.c	2004-03-16 09:37:58.267682136 +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 09:00:55.000000000 +0000
+++ source/sound/sparc/cs4231.c	2004-03-16 09:37:58.268681984 +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-16 09:37:58.268681984 +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-16 09:37:58.269681832 +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-16 09:37:58.272681376 +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>
@@ -88,7 +87,7 @@ MODULE_PARM_DESC(pid, "Product ID for th
 MODULE_PARM_SYNTAX(pid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16");
 MODULE_PARM(nrpacks, "i");
 MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB.");
-MODULE_PARM_SYNTAX(nrpacks, SNDRV_ENABLED ",allows:{{2,10}}");
+MODULE_PARM_SYNTAX(nrpacks, SNDRV_ENABLED ",allows:{{1,10}}");
 MODULE_PARM(async_unlink, "i");
 MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
 MODULE_PARM_SYNTAX(async_unlink, SNDRV_BOOLEAN_TRUE_DESC);
@@ -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;
@@ -1832,9 +1837,11 @@ static void proc_dump_substream_status(s
 			snd_iprintf(buffer, "%d ", subs->dataurb[i].packets);
 		snd_iprintf(buffer, "]\n");
 		snd_iprintf(buffer, "    Packet Size = %d\n", subs->curpacksize);
-		snd_iprintf(buffer, "    Momentary freq = %d,%03d Hz\n",
-			    subs->freqm >> 14,
-			    ((subs->freqm & ((1 << 14) - 1)) * 1000) / ((1 << 14) - 1));
+		snd_iprintf(buffer, "    Momentary freq = %d.%d Hz\n",
+			    (subs->freqm * 125) >> 11,
+			    (subs->freqm >> 10) * 625
+			    + (((subs->freqm & ((1 << 10) - 1)) * 625) >> 10)
+			    - 10 * ((subs->freqm * 125) >> 11));
 	} else {
 		snd_iprintf(buffer, "  Status: Stop\n");
 	}
@@ -1886,7 +1893,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 +1904,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 +1963,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 +1978,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 +1997,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 +2223,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 +2248,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 +2333,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);
@@ -2963,7 +2973,7 @@ static void usb_audio_disconnect(struct 
 
 static int __init snd_usb_audio_init(void)
 {
-	if (nrpacks < 2 || nrpacks > MAX_PACKS) {
+	if (nrpacks < MIN_PACKS_URB || nrpacks > MAX_PACKS) {
 		printk(KERN_WARNING "invalid nrpacks value.\n");
 		return -EINVAL;
 	}
--- diff/sound/usb/usbaudio.h	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/usb/usbaudio.h	2004-03-16 09:37:58.272681376 +0000
@@ -136,6 +136,8 @@ struct snd_usb_audio {
 
 	struct list_head midi_list;	/* list of midi interfaces */
 	int next_midi_device;
+
+	unsigned int ignore_ctl_error;	/* for mixer */
 };  
 
 /*
--- diff/sound/usb/usbmidi.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/usb/usbmidi.c	2004-03-16 09:37:58.274681072 +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,
@@ -453,8 +453,16 @@ static void snd_usbmidi_output_trigger(s
 	usbmidi_out_port_t* port = (usbmidi_out_port_t*)substream->runtime->private_data;
 
 	port->active = up;
-	if (up)
+	if (up) {
+		if (port->ep->umidi->chip->shutdown) {
+			/* gobble up remaining bytes to prevent wait in
+			 * snd_rawmidi_drain_output */
+			while (!snd_rawmidi_transmit_empty(substream))
+				snd_rawmidi_transmit_ack(substream, 1);
+			return;
+		}
 		tasklet_hi_schedule(&port->ep->tasklet);
+	}
 }
 
 static int snd_usbmidi_input_open(snd_rawmidi_substream_t* substream)
@@ -727,18 +735,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/usbmixer.c	2003-10-27 09:20:39.000000000 +0000
+++ source/sound/usb/usbmixer.c	2004-03-16 09:37:58.276680768 +0000
@@ -667,13 +667,11 @@ static int mixer_ctl_feature_get(snd_kco
 		for (c = 0; c < MAX_CHANNELS; c++) {
 			if (cval->cmask & (1 << c)) {
 				err = get_cur_mix_value(cval, c + 1, &val);
-#ifdef IGNORE_CTL_ERROR
-				if (err < 0) {
-					ucontrol->value.integer.value[0] = cval->min;
-					return 0;
-				}
-#endif
 				if (err < 0) {
+					if (cval->chip->ignore_ctl_error) {
+						ucontrol->value.integer.value[0] = cval->min;
+						return 0;
+					}
 					snd_printd(KERN_ERR "cannot get current value for control %d ch %d: err = %d\n", cval->control, c + 1, err);
 					return err;
 				}
@@ -685,13 +683,11 @@ static int mixer_ctl_feature_get(snd_kco
 	} else {
 		/* master channel */
 		err = get_cur_mix_value(cval, 0, &val);
-#ifdef IGNORE_CTL_ERROR
-		if (err < 0) {
-			ucontrol->value.integer.value[0] = cval->min;
-			return 0;
-		}
-#endif
 		if (err < 0) {
+			if (cval->chip->ignore_ctl_error) {
+				ucontrol->value.integer.value[0] = cval->min;
+				return 0;
+			}
 			snd_printd(KERN_ERR "cannot get current value for control %d master ch: err = %d\n", cval->control, err);
 			return err;
 		}
@@ -713,12 +709,11 @@ static int mixer_ctl_feature_put(snd_kco
 		for (c = 0; c < MAX_CHANNELS; c++) {
 			if (cval->cmask & (1 << c)) {
 				err = get_cur_mix_value(cval, c + 1, &oval);
-#ifdef IGNORE_CTL_ERROR
-				if (err < 0)
-					return 0;
-#endif
-				if (err < 0)
+				if (err < 0) {
+					if (cval->chip->ignore_ctl_error)
+						return 0;
 					return err;
+				}
 				val = ucontrol->value.integer.value[cnt];
 				val = get_abs_value(cval, val);
 				if (oval != val) {
@@ -732,10 +727,8 @@ static int mixer_ctl_feature_put(snd_kco
 	} else {
 		/* master channel */
 		err = get_cur_mix_value(cval, 0, &oval);
-#ifdef IGNORE_CTL_ERROR
-		if (err < 0)
+		if (err < 0 && cval->chip->ignore_ctl_error)
 			return 0;
-#endif
 		if (err < 0)
 			return err;
 		val = ucontrol->value.integer.value[0];
@@ -1025,12 +1018,10 @@ static int mixer_ctl_procunit_get(snd_kc
 	int err, val;
 
 	err = get_cur_ctl_value(cval, cval->control << 8, &val);
-#ifdef IGNORE_CTL_ERROR
-	if (err < 0) {
+	if (err < 0 && cval->chip->ignore_ctl_error) {
 		ucontrol->value.integer.value[0] = cval->min;
 		return 0;
 	}
-#endif
 	if (err < 0)
 		return err;
 	val = get_relative_value(cval, val);
@@ -1045,12 +1036,11 @@ static int mixer_ctl_procunit_put(snd_kc
 	int val, oval, err;
 
 	err = get_cur_ctl_value(cval, cval->control << 8, &oval);
-#ifdef IGNORE_CTL_ERROR
-	if (err < 0)
-		return 0;
-#endif
-	if (err < 0)
+	if (err < 0) {
+		if (cval->chip->ignore_ctl_error)
+			return 0;
 		return err;
+	}
 	val = ucontrol->value.integer.value[0];
 	val = get_abs_value(cval, val);
 	if (val != oval) {
@@ -1274,14 +1264,13 @@ static int mixer_ctl_selector_get(snd_kc
 	int val, err;
 
 	err = get_cur_ctl_value(cval, 0, &val);
-#ifdef IGNORE_CTL_ERROR
 	if (err < 0) {
-		ucontrol->value.enumerated.item[0] = 0;
-		return 0;
-	}
-#endif
-	if (err < 0)
+		if (cval->chip->ignore_ctl_error) {
+			ucontrol->value.enumerated.item[0] = 0;
+			return 0;
+		}
 		return err;
+	}
 	val = get_relative_value(cval, val);
 	ucontrol->value.enumerated.item[0] = val;
 	return 0;
@@ -1294,12 +1283,11 @@ static int mixer_ctl_selector_put(snd_kc
 	int val, oval, err;
 
 	err = get_cur_ctl_value(cval, 0, &oval);
-#ifdef IGNORE_CTL_ERROR
-	if (err < 0)
-		return 0;
-#endif
-	if (err < 0)
+	if (err < 0) {
+		if (cval->chip->ignore_ctl_error)
+			return 0;
 		return err;
+	}
 	val = ucontrol->value.enumerated.item[0];
 	val = get_abs_value(cval, val);
 	if (val != oval) {
@@ -1509,9 +1497,13 @@ int snd_usb_create_mixer(snd_usb_audio_t
 	for (map = usbmix_ctl_maps; map->vendor; map++) {
 		if (map->vendor == dev->idVendor && map->product == dev->idProduct) {
 			state.map = map->map;
+			chip->ignore_ctl_error = map->ignore_ctl_error;
 			break;
 		}
 	}
+#ifdef IGNORE_CTL_ERROR
+	chip->ignore_ctl_error = 1;
+#endif
 
 	desc = NULL;
 	while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, OUTPUT_TERMINAL)) != NULL) {
--- diff/sound/usb/usbmixer_maps.c	2003-08-20 13:16:36.000000000 +0000
+++ source/sound/usb/usbmixer_maps.c	2004-03-16 09:37:58.276680768 +0000
@@ -30,6 +30,7 @@ struct usbmix_ctl_map {
 	int vendor;
 	int product;
 	const struct usbmix_name_map *map;
+	int ignore_ctl_error;
 };
 	
 /*
@@ -86,6 +87,7 @@ static struct usbmix_name_map extigy_map
 	{ 26, "IEC958 Optical Playback" }, /* OT */
 	{ 27, NULL }, /* DISABLED: EU (for what?) */
 	/* 28: FU speaker (mute) */
+	{ 29, NULL }, /* Digital Input Playback Source? */
 	{ 0 } /* terminator */
 };
 
@@ -117,8 +119,8 @@ static struct usbmix_name_map justlink_m
  */
 
 static struct usbmix_ctl_map usbmix_ctl_maps[] = {
-	{ 0x41e, 0x3000, extigy_map },
-	{ 0xc45, 0x1158, justlink_map },
+	{ 0x41e, 0x3000, extigy_map, 1 },
+	{ 0xc45, 0x1158, justlink_map, 0 },
 	{ 0 } /* terminator */
 };
 
--- diff/sound/usb/usbquirks.h	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/usb/usbquirks.h	2004-03-16 09:37:58.278680464 +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 00:00:00.000000000 +0000
+++ source/Documentation/i386/kgdb/andthen	2004-03-16 09:37:58.278680464 +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 00:00:00.000000000 +0000
+++ source/Documentation/i386/kgdb/debug-nmi.txt	2004-03-16 09:37:58.279680312 +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 00:00:00.000000000 +0000
+++ source/Documentation/i386/kgdb/gdb-globals.txt	2004-03-16 09:37:58.280680160 +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 00:00:00.000000000 +0000
+++ source/Documentation/i386/kgdb/gdbinit	2004-03-16 09:37:58.280680160 +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 00:00:00.000000000 +0000
+++ source/Documentation/i386/kgdb/gdbinit-modules	2004-03-16 09:37:58.280680160 +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 00:00:00.000000000 +0000
+++ source/Documentation/i386/kgdb/gdbinit.hw	2004-03-16 09:37:58.281680008 +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 00:00:00.000000000 +0000
+++ source/Documentation/i386/kgdb/kgdb.txt	2004-03-16 09:37:58.283679704 +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 00:00:00.000000000 +0000
+++ source/Documentation/i386/kgdb/kgdbeth.txt	2004-03-16 09:37:58.284679552 +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 00:00:00.000000000 +0000
+++ source/Documentation/i386/kgdb/loadmodule.sh	2004-03-16 09:37:58.284679552 +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 00:00:00.000000000 +0000
+++ source/Documentation/laptop-mode.txt	2004-03-16 09:37:58.286679248 +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 00:00:00.000000000 +0000
+++ source/Documentation/must-fix.txt	2004-03-16 09:37:58.286679248 +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 00:00:00.000000000 +0000
+++ source/Documentation/networking/netconsole.txt	2004-03-16 09:37:58.287679096 +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/power/tricks.txt	1970-01-01 00:00:00.000000000 +0000
+++ source/Documentation/power/tricks.txt	2004-03-16 09:37:58.287679096 +0000
@@ -0,0 +1,25 @@
+	swsusp/S3 tricks
+	~~~~~~~~~~~~~~~~
+Pavel Machek <pavel@suse.cz>
+
+If you want to trick swsusp/S3 into working, you might want to try:
+
+* go with minimal config, turn off drivers like USB, AGP you don't
+  really need
+
+* use ext2. At least it has working fsck. [If something seemes to go
+  wrong, force fsck when you have a chance]
+
+* turn off modules
+
+* use vga text console, shut down X. [If you really want X, you might
+  want to try vesafb later]
+
+* try running as few processes as possible, preferably go to single
+  user mode.
+
+* due to video issues, swsusp should be easier to get working than
+  S3. Try that first.
+
+When you make it work, try to find out what exactly was it that broke
+suspend, and preferably fix that.
--- diff/Documentation/sched-domains.txt	1970-01-01 00:00:00.000000000 +0000
+++ source/Documentation/sched-domains.txt	2004-03-16 09:37:58.288678944 +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 00:00:00.000000000 +0000
+++ source/Documentation/should-fix.txt	2004-03-16 09:37:58.289678792 +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 00:00:00.000000000 +0000
+++ source/Documentation/sound/alsa/MIXART.txt	2004-03-16 09:37:58.289678792 +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 00:00:00.000000000 +0000
+++ source/Documentation/usb/mtouchusb.txt	2004-03-16 09:37:58.290678640 +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 00:00:00.000000000 +0000
+++ source/arch/i386/kernel/entry_trampoline.c	2004-03-16 09:37:58.291678488 +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 00:00:00.000000000 +0000
+++ source/arch/i386/kernel/kgdb_stub.c	2004-03-16 09:37:58.320674080 +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 00:00:00.000000000 +0000
+++ source/arch/i386/lib/kgdb_serial.c	2004-03-16 09:37:58.322673776 +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/ia64/configs/zx1_defconfig	1970-01-01 00:00:00.000000000 +0000
+++ source/arch/ia64/configs/zx1_defconfig	2004-03-16 09:37:58.324673472 +0000
@@ -0,0 +1,1078 @@
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_CLEAN_COMPILE is not set
+CONFIG_STANDALONE=y
+CONFIG_BROKEN=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_SYSCTL=y
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_HOTPLUG=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Processor type and features
+#
+CONFIG_IA64=y
+CONFIG_64BIT=y
+CONFIG_MMU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_TIME_INTERPOLATION=y
+CONFIG_EFI=y
+# CONFIG_ITANIUM is not set
+CONFIG_MCKINLEY=y
+# CONFIG_IA64_GENERIC is not set
+# CONFIG_IA64_DIG is not set
+CONFIG_IA64_HP_ZX1=y
+# CONFIG_IA64_SGI_SN2 is not set
+# CONFIG_IA64_HP_SIM is not set
+# CONFIG_IA64_PAGE_SIZE_4KB is not set
+# CONFIG_IA64_PAGE_SIZE_8KB is not set
+CONFIG_IA64_PAGE_SIZE_16KB=y
+# CONFIG_IA64_PAGE_SIZE_64KB is not set
+CONFIG_ACPI=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_KERNEL_CONFIG=y
+CONFIG_IA64_L1_CACHE_SHIFT=7
+# CONFIG_MCKINLEY_ASTEP_SPECIFIC is not set
+# CONFIG_NUMA is not set
+CONFIG_VIRTUAL_MEM_MAP=y
+CONFIG_IA64_MCA=y
+# CONFIG_IA64_CYCLONE is not set
+CONFIG_PM=y
+CONFIG_IOSAPIC=y
+CONFIG_FORCE_MAX_ZONEORDER=18
+# CONFIG_HUGETLB_PAGE_SIZE_4GB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_1GB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_256MB is not set
+CONFIG_HUGETLB_PAGE_SIZE_64MB=y
+# CONFIG_HUGETLB_PAGE_SIZE_16MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_256KB is not set
+CONFIG_IA64_PAL_IDLE=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=16
+# CONFIG_PREEMPT is not set
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_IA32_SUPPORT=y
+CONFIG_COMPAT=y
+CONFIG_PERFMON=y
+CONFIG_IA64_PALINFO=y
+CONFIG_EFI_VARS=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+
+#
+# ACPI (Advanced Configuration and Power Interface) Support
+#
+CONFIG_ACPI_BOOT=y
+CONFIG_ACPI_BUTTON=y
+CONFIG_ACPI_FAN=y
+CONFIG_ACPI_PROCESSOR=y
+CONFIG_ACPI_THERMAL=y
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_ACPI_BUS=y
+CONFIG_ACPI_POWER=y
+CONFIG_ACPI_PCI=y
+CONFIG_ACPI_SYSTEM=y
+# CONFIG_ACPI_RELAXED_AML is not set
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+
+#
+# PCI Hotplug Support
+#
+CONFIG_HOTPLUG_PCI=y
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+CONFIG_HOTPLUG_PCI_ACPI=y
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+# CONFIG_HOTPLUG_PCI_PCIE is not set
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+# CONFIG_FW_LOADER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_DCSSBLK is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+CONFIG_BLK_DEV_ADMA=y
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+CONFIG_BLK_DEV_CMD64X=y
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+CONFIG_FUSION=y
+CONFIG_FUSION_BOOT=y
+CONFIG_FUSION_MAX_SGE=40
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_CHR_DEV_OSST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_REPORT_LUNS=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+CONFIG_SCSI_MEGARAID=y
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+CONFIG_SCSI_QLOGIC_1280=y
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_QLA6322 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_CONNTRACK is not set
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+CONFIG_IP_NF_ARPTABLES=y
+# CONFIG_IP_NF_ARPFILTER is not set
+# CONFIG_IP_NF_ARP_MANGLE is not set
+# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IPV6_SCTP__=y
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+CONFIG_NET_TULIP=y
+# CONFIG_DE2104X is not set
+CONFIG_TULIP=y
+CONFIG_TULIP_MWI=y
+CONFIG_TULIP_MMIO=y
+CONFIG_TULIP_NAPI=y
+CONFIG_TULIP_NAPI_HW_MITIGATION=y
+# CONFIG_DE4X5 is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
+# CONFIG_E100_NAPI is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+# CONFIG_E1000_NAPI is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SK98LIN is not set
+CONFIG_TIGON3=y
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_IXGB is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BT is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=y
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_HCDP=y
+CONFIG_SERIAL_8250_ACPI=y
+CONFIG_SERIAL_8250_NR_UARTS=8
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_GEN_RTC is not set
+CONFIG_EFI_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+CONFIG_AGP=y
+CONFIG_AGP_HP_ZX1=y
+CONFIG_DRM=y
+# CONFIG_DRM_TDFX is not set
+# CONFIG_DRM_GAMMA is not set
+# CONFIG_DRM_R128 is not set
+CONFIG_DRM_RADEON=y
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_SIS is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+CONFIG_I2C_ALGOPCF=y
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_ELV is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VELLEMAN is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# I2C Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V4 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_NEC98_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=y
+CONFIG_NLS_CODEPAGE_775=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=y
+CONFIG_NLS_CODEPAGE_855=y
+CONFIG_NLS_CODEPAGE_857=y
+CONFIG_NLS_CODEPAGE_860=y
+CONFIG_NLS_CODEPAGE_861=y
+CONFIG_NLS_CODEPAGE_862=y
+CONFIG_NLS_CODEPAGE_863=y
+CONFIG_NLS_CODEPAGE_864=y
+CONFIG_NLS_CODEPAGE_865=y
+CONFIG_NLS_CODEPAGE_866=y
+CONFIG_NLS_CODEPAGE_869=y
+CONFIG_NLS_CODEPAGE_936=y
+CONFIG_NLS_CODEPAGE_950=y
+CONFIG_NLS_CODEPAGE_932=y
+CONFIG_NLS_CODEPAGE_949=y
+CONFIG_NLS_CODEPAGE_874=y
+CONFIG_NLS_ISO8859_8=y
+# CONFIG_NLS_CODEPAGE_1250 is not set
+CONFIG_NLS_CODEPAGE_1251=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=y
+CONFIG_NLS_ISO8859_3=y
+CONFIG_NLS_ISO8859_4=y
+CONFIG_NLS_ISO8859_5=y
+CONFIG_NLS_ISO8859_6=y
+CONFIG_NLS_ISO8859_7=y
+CONFIG_NLS_ISO8859_9=y
+CONFIG_NLS_ISO8859_13=y
+CONFIG_NLS_ISO8859_14=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_KOI8_R=y
+CONFIG_NLS_KOI8_U=y
+CONFIG_NLS_UTF8=y
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON_OLD is not set
+CONFIG_FB_RADEON=y
+CONFIG_FB_RADEON_I2C=y
+CONFIG_FB_RADEON_DEBUG=y
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_PCI_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=y
+CONFIG_SND_SEQUENCER=y
+# CONFIG_SND_SEQ_DUMMY is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_YMFPCI is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_MAESTRO3 is not set
+CONFIG_SND_FM801=y
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VX222 is not set
+
+#
+# ALSA USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+CONFIG_USB_BANDWIDTH=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_UHCI_HCD=y
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_MIDI is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_XPAD is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_IA64_GRANULE_16MB=y
+# CONFIG_IA64_GRANULE_64MB is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_IA64_PRINT_HAZARDS=y
+# CONFIG_DISABLE_VHPT is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_IA64_DEBUG_CMPXCHG is not set
+# CONFIG_IA64_DEBUG_IRQ is not set
+# CONFIG_DEBUG_INFO is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
--- diff/arch/parisc/configs/b180_defconfig	1970-01-01 00:00:00.000000000 +0000
+++ source/arch/parisc/configs/b180_defconfig	2004-03-16 09:37:58.326673168 +0000
@@ -0,0 +1,776 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_PARISC=y
+CONFIG_MMU=y
+CONFIG_STACK_GROWSUP=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+# CONFIG_EXPERIMENTAL is not set
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_LOG_BUF_SHIFT=15
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_KMOD is not set
+
+#
+# Processor type and features
+#
+# CONFIG_PA7000 is not set
+# CONFIG_PA7100LC is not set
+CONFIG_PA7200=y
+# CONFIG_PA8X00 is not set
+CONFIG_PA11=y
+# CONFIG_64BIT is not set
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_HPUX is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, GSC, ISA)
+#
+CONFIG_GSC=y
+# CONFIG_HPPB is not set
+# CONFIG_IOMMU_CCIO is not set
+CONFIG_GSC_LASI=y
+CONFIG_GSC_WAX=y
+CONFIG_EISA=y
+CONFIG_EISA_NAMES=y
+CONFIG_ISA=y
+CONFIG_PCI=y
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+CONFIG_GSC_DINO=y
+# CONFIG_PCI_LBA is not set
+# CONFIG_CHASSIS_LCD_LED is not set
+# CONFIG_PDC_CHASSIS is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_DEBUG_DRIVER=y
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=y
+CONFIG_PARPORT_PC_CML1=y
+# CONFIG_PARPORT_SERIAL is not set
+CONFIG_PARPORT_GSC=y
+# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_1284 is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_REPORT_LUNS is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_NCR53C406A is not set
+CONFIG_SCSI_LASI700=y
+CONFIG_53C700_MEM_MAPPED=y
+CONFIG_53C700_LE_ON_BE=y
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_ZALON is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_QLA6322 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=y
+CONFIG_MD_RAID0=y
+CONFIG_MD_RAID1=y
+CONFIG_MD_RAID5=y
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_DM is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_NETLINK_DEV=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+CONFIG_INET_ECN=y
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_LASI_82596 is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+
+#
+# Tulip family network device support
+#
+CONFIG_NET_TULIP=y
+CONFIG_TULIP=y
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_TULIP_NAPI is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_IXGB is not set
+# CONFIG_FDDI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=y
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+# CONFIG_ARLAN is not set
+# CONFIG_WAVELAN is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+# CONFIG_AIRO is not set
+# CONFIG_HERMES is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BT is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PARKBD is not set
+CONFIG_SERIO_GSCPS2=y
+# CONFIG_HP_SDC is not set
+# CONFIG_SERIO_PCIPS2 is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_HIL_OLD is not set
+# CONFIG_KEYBOARD_HIL is not set
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_MOUSE_HIL is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_PCSPKR is not set
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_HP_SDC_RTC is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MUX is not set
+# CONFIG_PDC_CONSOLE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_PRINTER=y
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB 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_STI=y
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON_OLD is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_STI_CONSOLE=y
+CONFIG_DUMMY_CONSOLE_COLUMNS=160
+CONFIG_DUMMY_CONSOLE_ROWS=64
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_PCI_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_LOGO_PARISC_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_FAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_INFO is not set
+
+#
+# Security options
+#
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_SECURITY_SELINUX is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
--- diff/arch/ppc64/kernel/dma.c	1970-01-01 00:00:00.000000000 +0000
+++ source/arch/ppc64/kernel/dma.c	2004-03-16 09:37:58.327673016 +0000
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Implements the generic device dma API for ppc64. Handles
+ * the pci and vio busses
+ */
+
+#include <linux/config.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+/* Include the busses we support */
+#include <linux/pci.h>
+#ifdef CONFIG_PPC_PSERIES
+#include <asm/vio.h>
+#endif
+#include <asm/scatterlist.h>
+#include <asm/bug.h>
+
+int dma_supported(struct device *dev, u64 mask)
+{
+	if (dev->bus == &pci_bus_type)
+		return pci_dma_supported(to_pci_dev(dev), mask);
+#ifdef CONFIG_PPC_PSERIES
+	if (dev->bus == &vio_bus_type)
+		return vio_dma_supported(to_vio_dev(dev), mask);
+#endif
+	BUG();
+	return 0;
+}
+EXPORT_SYMBOL(dma_supported);
+
+int dma_set_mask(struct device *dev, u64 dma_mask)
+{
+	if (dev->bus == &pci_bus_type)
+		return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
+#ifdef CONFIG_PPC_PSERIES
+	if (dev->bus == &vio_bus_type)
+		return vio_set_dma_mask(to_vio_dev(dev), dma_mask);
+#endif
+	BUG();
+	return 0;
+}
+EXPORT_SYMBOL(dma_set_mask);
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+		dma_addr_t *dma_handle, int flag)
+{
+	if (dev->bus == &pci_bus_type)
+		return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle);
+#ifdef CONFIG_PPC_PSERIES
+	if (dev->bus == &vio_bus_type)
+		return vio_alloc_consistent(to_vio_dev(dev), size, dma_handle);
+#endif
+	BUG();
+	return 0;
+}
+EXPORT_SYMBOL(dma_alloc_coherent);
+
+void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
+		dma_addr_t dma_handle)
+{
+	if (dev->bus == &pci_bus_type)
+		pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle);
+#ifdef CONFIG_PPC_PSERIES
+	else if (dev->bus == &vio_bus_type)
+		vio_free_consistent(to_vio_dev(dev), size, cpu_addr, dma_handle);
+#endif
+	else
+		BUG();
+}
+EXPORT_SYMBOL(dma_free_coherent);
+
+dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size,
+		enum dma_data_direction direction)
+{
+	if (dev->bus == &pci_bus_type)
+		return pci_map_single(to_pci_dev(dev), cpu_addr, size, (int)direction);
+#ifdef CONFIG_PPC_PSERIES
+	if (dev->bus == &vio_bus_type)
+		return vio_map_single(to_vio_dev(dev), cpu_addr, size, (int)direction);
+#endif
+	BUG();
+	return (dma_addr_t)0;
+}
+EXPORT_SYMBOL(dma_map_single);
+
+void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+		enum dma_data_direction direction)
+{
+	if (dev->bus == &pci_bus_type)
+		pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction);
+#ifdef CONFIG_PPC_PSERIES
+	else if (dev->bus == &vio_bus_type)
+		vio_unmap_single(to_vio_dev(dev), dma_addr, size, (int)direction);
+#endif
+	else
+		BUG();
+}
+EXPORT_SYMBOL(dma_unmap_single);
+
+dma_addr_t dma_map_page(struct device *dev, struct page *page,
+		unsigned long offset, size_t size,
+		enum dma_data_direction direction)
+{
+	if (dev->bus == &pci_bus_type)
+		return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction);
+#ifdef CONFIG_PPC_PSERIES
+	if (dev->bus == &vio_bus_type)
+		return vio_map_page(to_vio_dev(dev), page, offset, size, (int)direction);
+#endif
+	BUG();
+	return (dma_addr_t)0;
+}
+EXPORT_SYMBOL(dma_map_page);
+
+void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
+		enum dma_data_direction direction)
+{
+	if (dev->bus == &pci_bus_type)
+		pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction);
+#ifdef CONFIG_PPC_PSERIES
+	else if (dev->bus == &vio_bus_type)
+		vio_unmap_page(to_vio_dev(dev), dma_address, size, (int)direction);
+#endif
+	else
+		BUG();
+}
+EXPORT_SYMBOL(dma_unmap_page);
+
+int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+		enum dma_data_direction direction)
+{
+	if (dev->bus == &pci_bus_type)
+		return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction);
+#ifdef CONFIG_PPC_PSERIES
+	if (dev->bus == &vio_bus_type)
+		return vio_map_sg(to_vio_dev(dev), sg, nents, (int)direction);
+#endif
+	BUG();
+	return 0;
+}
+EXPORT_SYMBOL(dma_map_sg);
+
+void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
+		enum dma_data_direction direction)
+{
+	if (dev->bus == &pci_bus_type)
+		pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction);
+#ifdef CONFIG_PPC_PSERIES
+	else if (dev->bus == &vio_bus_type)
+		vio_unmap_sg(to_vio_dev(dev), sg, nhwentries, (int)direction);
+#endif
+	else
+		BUG();
+}
+EXPORT_SYMBOL(dma_unmap_sg);
+
+void dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size,
+		enum dma_data_direction direction)
+{
+	if (dev->bus == &pci_bus_type)
+		pci_dma_sync_single(to_pci_dev(dev), dma_handle, size, (int)direction);
+#ifdef CONFIG_PPC_PSERIES
+	else if (dev->bus == &vio_bus_type)
+		vio_dma_sync_single(to_vio_dev(dev), dma_handle, size, (int)direction);
+#endif
+	else
+		BUG();
+}
+EXPORT_SYMBOL(dma_sync_single);
+
+void dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems,
+		enum dma_data_direction direction)
+{
+	if (dev->bus == &pci_bus_type)
+		pci_dma_sync_sg(to_pci_dev(dev), sg, nelems, (int)direction);
+#ifdef CONFIG_PPC_PSERIES
+	else if (dev->bus == &vio_bus_type)
+		vio_dma_sync_sg(to_vio_dev(dev), sg, nelems, (int)direction);
+#endif
+	else
+		BUG();
+}
+EXPORT_SYMBOL(dma_sync_sg);
--- diff/arch/x86_64/Kconfig.kgdb	1970-01-01 00:00:00.000000000 +0000
+++ source/arch/x86_64/Kconfig.kgdb	2004-03-16 09:37:58.327673016 +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/ia32/vsyscall-sigreturn.S	1970-01-01 00:00:00.000000000 +0000
+++ source/arch/x86_64/ia32/vsyscall-sigreturn.S	2004-03-16 09:37:58.328672864 +0000
@@ -0,0 +1,120 @@
+/*
+ * Common code for the sigreturn entry points on the vsyscall page.
+ * This code uses SYSCALL_ENTER_KERNEL (either syscall or int $0x80)
+ * to enter the kernel.
+ * This file is #include'd by vsyscall-*.S to define them after the
+ * vsyscall entry point.  The addresses we get for these entry points
+ * by doing ".balign 32" must match in both versions of the page.
+ */
+
+	.section .text.sigreturn,"ax"
+	.balign 32
+	.globl __kernel_sigreturn
+	.type __kernel_sigreturn,@function
+__kernel_sigreturn:
+.LSTART_sigreturn:
+	popl %eax
+	movl $__NR_ia32_sigreturn, %eax
+	SYSCALL_ENTER_KERNEL
+.LEND_sigreturn:
+	.size __kernel_sigreturn,.-.LSTART_sigreturn
+
+	.section .text.rtsigreturn,"ax"
+	.balign 32
+	.globl __kernel_rt_sigreturn
+	.type __kernel_rt_sigreturn,@function
+__kernel_rt_sigreturn:
+.LSTART_rt_sigreturn:
+	movl $__NR_ia32_rt_sigreturn, %eax
+	SYSCALL_ENTER_KERNEL
+.LEND_rt_sigreturn:
+	.size __kernel_rt_sigreturn,.-.LSTART_rt_sigreturn
+
+	.section .eh_frame,"a",@progbits
+	.long .LENDFDE2-.LSTARTFDE2	/* Length FDE */
+.LSTARTFDE2:
+	.long .LSTARTFDE2-.LSTARTFRAME	/* CIE pointer */
+	/* HACK: The dwarf2 unwind routines will subtract 1 from the
+	   return address to get an address in the middle of the
+	   presumed call instruction.  Since we didn't get here via
+	   a call, we need to include the nop before the real start
+	   to make up for it.  */
+	.long .LSTART_sigreturn-1-.	/* PC-relative start address */
+	.long .LEND_sigreturn-.LSTART_sigreturn+1
+	.uleb128 0			/* Augmentation length */
+	/* What follows are the instructions for the table generation.
+	   We record the locations of each register saved.  This is
+	   complicated by the fact that the "CFA" is always assumed to
+	   be the value of the stack pointer in the caller.  This means
+	   that we must define the CFA of this body of code to be the
+	   saved value of the stack pointer in the sigcontext.  Which
+	   also means that there is no fixed relation to the other 
+	   saved registers, which means that we must use DW_CFA_expression
+	   to compute their addresses.  It also means that when we 
+	   adjust the stack with the popl, we have to do it all over again.  */
+
+#define do_cfa_expr(offset)						\
+	.byte 0x0f;			/* DW_CFA_def_cfa_expression */	\
+	.uleb128 1f-0f;			/*   length */			\
+0:	.byte 0x74;			/*     DW_OP_breg4 */		\
+	.sleb128 offset;		/*      offset */		\
+	.byte 0x06;			/*     DW_OP_deref */		\
+1:
+
+#define do_expr(regno, offset)						\
+	.byte 0x10;			/* DW_CFA_expression */		\
+	.uleb128 regno;			/*   regno */			\
+	.uleb128 1f-0f;			/*   length */			\
+0:	.byte 0x74;			/*     DW_OP_breg4 */		\
+	.sleb128 offset;		/*       offset */		\
+1:
+
+	do_cfa_expr(IA32_SIGCONTEXT_esp+4)
+	do_expr(0, IA32_SIGCONTEXT_eax+4)
+	do_expr(1, IA32_SIGCONTEXT_ecx+4)
+	do_expr(2, IA32_SIGCONTEXT_edx+4)
+	do_expr(3, IA32_SIGCONTEXT_ebx+4)
+	do_expr(5, IA32_SIGCONTEXT_ebp+4)
+	do_expr(6, IA32_SIGCONTEXT_esi+4)
+	do_expr(7, IA32_SIGCONTEXT_edi+4)
+	do_expr(8, IA32_SIGCONTEXT_eip+4)
+
+	.byte 0x42	/* DW_CFA_advance_loc 2 -- nop; popl eax. */
+
+	do_cfa_expr(IA32_SIGCONTEXT_esp)
+	do_expr(0, IA32_SIGCONTEXT_eax)
+	do_expr(1, IA32_SIGCONTEXT_ecx)
+	do_expr(2, IA32_SIGCONTEXT_edx)
+	do_expr(3, IA32_SIGCONTEXT_ebx)
+	do_expr(5, IA32_SIGCONTEXT_ebp)
+	do_expr(6, IA32_SIGCONTEXT_esi)
+	do_expr(7, IA32_SIGCONTEXT_edi)
+	do_expr(8, IA32_SIGCONTEXT_eip)
+
+	.align 4
+.LENDFDE2:
+
+	.long .LENDFDE3-.LSTARTFDE3	/* Length FDE */
+.LSTARTFDE3:
+	.long .LSTARTFDE3-.LSTARTFRAME	/* CIE pointer */
+	/* HACK: See above wrt unwind library assumptions.  */
+	.long .LSTART_rt_sigreturn-1-.	/* PC-relative start address */
+	.long .LEND_rt_sigreturn-.LSTART_rt_sigreturn+1
+	.uleb128 0			/* Augmentation */
+	/* What follows are the instructions for the table generation.
+	   We record the locations of each register saved.  This is
+	   slightly less complicated than the above, since we don't
+	   modify the stack pointer in the process.  */
+
+	do_cfa_expr(IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_esp)
+	do_expr(0, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_eax)
+	do_expr(1, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ecx)
+	do_expr(2, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_edx)
+	do_expr(3, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ebx)
+	do_expr(5, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ebp)
+	do_expr(6, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_esi)
+	do_expr(7, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_edi)
+	do_expr(8, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_eip)
+
+	.align 4
+.LENDFDE3:
--- diff/arch/x86_64/ia32/vsyscall-syscall.S	1970-01-01 00:00:00.000000000 +0000
+++ source/arch/x86_64/ia32/vsyscall-syscall.S	2004-03-16 09:37:58.329672712 +0000
@@ -0,0 +1,68 @@
+/*
+ * Code for the vsyscall page.  This version uses the syscall instruction.
+ */
+
+#include <asm/ia32_unistd.h>
+#include <asm/offset.h>
+#include <asm/segment.h>
+
+	.text
+	.section .text.vsyscall,"ax"
+	.globl __kernel_vsyscall
+	.type __kernel_vsyscall,@function
+__kernel_vsyscall:
+.LSTART_vsyscall:
+	push	%ebp
+.Lpush_ebp:
+	movl	%ecx, %ebp
+	syscall
+	movl	$__USER32_DS, %ecx
+	movl	%ecx, %ss
+	movl	%ebp, %ecx
+	popl	%ebp
+.Lpop_ebp:
+	ret
+.LEND_vsyscall:
+	.size __kernel_vsyscall,.-.LSTART_vsyscall
+
+	.section .eh_frame,"a",@progbits
+.LSTARTFRAME:
+	.long .LENDCIE-.LSTARTCIE
+.LSTARTCIE:
+	.long 0			/* CIE ID */
+	.byte 1			/* Version number */
+	.string "zR"		/* NUL-terminated augmentation string */
+	.uleb128 1		/* Code alignment factor */
+	.sleb128 -4		/* Data alignment factor */
+	.byte 8			/* Return address register column */
+	.uleb128 1		/* Augmentation value length */
+	.byte 0x1b		/* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */
+	.byte 0x0c		/* DW_CFA_def_cfa */
+	.uleb128 4
+	.uleb128 4
+	.byte 0x88		/* DW_CFA_offset, column 0x8 */
+	.uleb128 1
+	.align 4
+.LENDCIE:
+
+	.long .LENDFDE1-.LSTARTFDE1	/* Length FDE */
+.LSTARTFDE1:
+	.long .LSTARTFDE1-.LSTARTFRAME	/* CIE pointer */
+	.long .LSTART_vsyscall-.	/* PC-relative start address */
+	.long .LEND_vsyscall-.LSTART_vsyscall
+	.uleb128 0			/* Augmentation length */
+	/* What follows are the instructions for the table generation.
+	   We have to record all changes of the stack pointer.  */
+	.byte 0x40 + .Lpush_ebp-.LSTART_vsyscall /* DW_CFA_advance_loc */
+	.byte 0x0e		/* DW_CFA_def_cfa_offset */
+	.uleb128 8
+	.byte 0x85, 0x02	/* DW_CFA_offset %ebp -8 */
+	.byte 0x40 + .Lpop_ebp-.Lpush_ebp /* DW_CFA_advance_loc */
+	.byte 0xc5		/* DW_CFA_restore %ebp */
+	.byte 0x0e		/* DW_CFA_def_cfa_offset */
+	.uleb128 4
+	.align 4
+.LENDFDE1:
+
+#define SYSCALL_ENTER_KERNEL	syscall
+#include "vsyscall-sigreturn.S"
--- diff/arch/x86_64/ia32/vsyscall-sysenter.S	1970-01-01 00:00:00.000000000 +0000
+++ source/arch/x86_64/ia32/vsyscall-sysenter.S	2004-03-16 09:37:58.330672560 +0000
@@ -0,0 +1,94 @@
+/*
+ * Code for the vsyscall page.  This version uses the sysenter instruction.
+ */
+
+#include <asm/ia32_unistd.h>
+#include <asm/offset.h>
+
+	.text
+	.section .text.vsyscall,"ax"
+	.globl __kernel_vsyscall
+	.type __kernel_vsyscall,@function
+__kernel_vsyscall:
+.LSTART_vsyscall:
+	push	%ecx
+.Lpush_ecx:
+	push	%edx
+.Lpush_edx:
+	push	%ebp
+.Lenter_kernel:
+	movl	%esp,%ebp
+	sysenter
+	.space 7,0x90
+	jmp	.Lenter_kernel
+	/* 16: System call normal return point is here! */
+	pop	%ebp
+.Lpop_ebp:
+	pop	%edx
+.Lpop_edx:
+	pop	%ecx
+.Lpop_ecx:
+	ret
+.LEND_vsyscall:
+	.size __kernel_vsyscall,.-.LSTART_vsyscall
+
+	.section .eh_frame,"a",@progbits
+.LSTARTFRAME:
+	.long .LENDCIE-.LSTARTCIE
+.LSTARTCIE:
+	.long 0			/* CIE ID */
+	.byte 1			/* Version number */
+	.string "zR"		/* NUL-terminated augmentation string */
+	.uleb128 1		/* Code alignment factor */
+	.sleb128 -4		/* Data alignment factor */
+	.byte 8			/* Return address register column */
+	.uleb128 1		/* Augmentation value length */
+	.byte 0x1b		/* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */
+	.byte 0x0c		/* DW_CFA_def_cfa */
+	.uleb128 4
+	.uleb128 4
+	.byte 0x88		/* DW_CFA_offset, column 0x8 */
+	.uleb128 1
+	.align 4
+.LENDCIE:
+
+	.long .LENDFDE1-.LSTARTFDE1	/* Length FDE */
+.LSTARTFDE1:
+	.long .LSTARTFDE1-.LSTARTFRAME	/* CIE pointer */
+	.long .LSTART_vsyscall-.	/* PC-relative start address */
+	.long .LEND_vsyscall-.LSTART_vsyscall
+	.uleb128 0			/* Augmentation length */
+	/* What follows are the instructions for the table generation.
+	   We have to record all changes of the stack pointer.  */
+	.byte 0x04		/* DW_CFA_advance_loc4 */
+	.long .Lpush_ecx-.LSTART_vsyscall
+	.byte 0x0e		/* DW_CFA_def_cfa_offset */
+	.byte 0x08		/* RA at offset 8 now */
+	.byte 0x04		/* DW_CFA_advance_loc4 */
+	.long .Lpush_edx-.Lpush_ecx
+	.byte 0x0e		/* DW_CFA_def_cfa_offset */
+	.byte 0x0c		/* RA at offset 12 now */
+	.byte 0x04		/* DW_CFA_advance_loc4 */
+	.long .Lenter_kernel-.Lpush_edx
+	.byte 0x0e		/* DW_CFA_def_cfa_offset */
+	.byte 0x10		/* RA at offset 16 now */
+	.byte 0x85, 0x04	/* DW_CFA_offset %ebp -16 */
+	/* Finally the epilogue.  */
+	.byte 0x04		/* DW_CFA_advance_loc4 */
+	.long .Lpop_ebp-.Lenter_kernel
+	.byte 0x0e		/* DW_CFA_def_cfa_offset */
+	.byte 0x12		/* RA at offset 12 now */
+	.byte 0xc5		/* DW_CFA_restore %ebp */
+	.byte 0x04		/* DW_CFA_advance_loc4 */
+	.long .Lpop_edx-.Lpop_ebp
+	.byte 0x0e		/* DW_CFA_def_cfa_offset */
+	.byte 0x08		/* RA at offset 8 now */
+	.byte 0x04		/* DW_CFA_advance_loc4 */
+	.long .Lpop_ecx-.Lpop_edx
+	.byte 0x0e		/* DW_CFA_def_cfa_offset */
+	.byte 0x04		/* RA at offset 4 now */
+	.align 4
+.LENDFDE1:
+
+#define SYSCALL_ENTER_KERNEL	int $0x80
+#include "vsyscall-sigreturn.S"
--- diff/arch/x86_64/kernel/kgdb_stub.c	1970-01-01 00:00:00.000000000 +0000
+++ source/arch/x86_64/kernel/kgdb_stub.c	2004-03-16 09:37:58.337671496 +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 00:00:00.000000000 +0000
+++ source/arch/x86_64/lib/kgdb_serial.c	2004-03-16 09:37:58.338671344 +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/arch/x86_64/pci/mmconfig.c	1970-01-01 00:00:00.000000000 +0000
+++ source/arch/x86_64/pci/mmconfig.c	2004-03-16 09:37:58.338671344 +0000
@@ -0,0 +1,98 @@
+/*
+ * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
+ * 
+ * This is an 64bit optimized version that always keeps the full mmconfig
+ * space mapped. This allows lockless config space operation.
+ */
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include "pci.h"
+
+#define MMCONFIG_APER_SIZE (256*1024*1024)
+
+/* The physical address of the MMCONFIG aperture.  Set from ACPI tables. */
+u32 pci_mmcfg_base_addr;
+
+/* Static virtual mapping of the MMCONFIG aperture */
+char *pci_mmcfg_virt;
+
+static inline char *pci_dev_base(int bus, int devfn)
+{
+	return pci_mmcfg_virt + ((bus << 20) | (devfn << 12));
+}
+
+static int pci_mmcfg_read(int seg, int bus, int devfn, int reg, int len, u32 *value)
+{
+	char *addr = pci_dev_base(bus, devfn); 
+
+	if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095)))
+		return -EINVAL;
+
+	switch (len) {
+	case 1:
+		*value = readb(addr + reg);
+		break;
+	case 2:
+		*value = readw(addr + reg);
+		break;
+	case 4:
+		*value = readl(addr + reg);
+		break;
+	}
+
+	return 0;
+}
+
+static int pci_mmcfg_write(int seg, int bus, int devfn, int reg, int len, u32 value)
+{
+	char *addr = pci_dev_base(bus,devfn);
+
+	if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
+		return -EINVAL;
+
+	switch (len) {
+	case 1:
+		writeb(value, addr + reg);
+		break;
+	case 2:
+		writew(value, addr + reg);
+		break;
+	case 4:
+		writel(value, addr + reg);
+		break;
+	}
+
+	/* Dummy read to flush PCI write */
+	readl(addr);
+
+	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)
+		return 0;
+	if (!pci_mmcfg_base_addr)
+		return 0;
+
+	/* RED-PEN i386 doesn't do _nocache right now */
+	pci_mmcfg_virt = ioremap_nocache(pci_mmcfg_base_addr, MMCONFIG_APER_SIZE);
+	if (!pci_mmcfg_virt) { 
+		printk("PCI: Cannot map mmconfig aperture\n");
+		return 0;
+	}	
+
+	printk(KERN_INFO "PCI: Using MMCONFIG at %lx\n", pci_mmcfg_base_addr);
+	raw_pci_ops = &pci_mmcfg;
+	pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
+
+	return 0;
+}
+
+arch_initcall(pci_mmcfg_init);
--- diff/drivers/block/carmel.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/block/carmel.c	2004-03-16 09:37:58.342670736 +0000
@@ -0,0 +1,1731 @@
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/blkdev.h>
+#include <linux/sched.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/interrupt.h>
+#include <linux/compiler.h>
+#include <linux/workqueue.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+#include <linux/hdreg.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Promise SX8 (carmel) block driver");
+
+#if 0
+#define CARM_DEBUG
+#define CARM_VERBOSE_DEBUG
+#else
+#undef CARM_DEBUG
+#undef CARM_VERBOSE_DEBUG
+#endif
+#undef CARM_NDEBUG
+
+#define DRV_NAME "carmel"
+#define DRV_VERSION "0.7"
+#define PFX DRV_NAME ": "
+
+#define NEXT_RESP(idx)	((idx + 1) % RMSG_Q_LEN)
+
+/* 0xf is just arbitrary, non-zero noise; this is sorta like poisoning */
+#define TAG_ENCODE(tag)	(((tag) << 16) | 0xf)
+#define TAG_DECODE(tag)	(((tag) >> 16) & 0x1f)
+#define TAG_VALID(tag)	((((tag) & 0xf) == 0xf) && (TAG_DECODE(tag) < 32))
+
+/* note: prints function name for you */
+#ifdef CARM_DEBUG
+#define DPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
+#ifdef CARM_VERBOSE_DEBUG
+#define VPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
+#else
+#define VPRINTK(fmt, args...)
+#endif	/* CARM_VERBOSE_DEBUG */
+#else
+#define DPRINTK(fmt, args...)
+#define VPRINTK(fmt, args...)
+#endif	/* CARM_DEBUG */
+
+#ifdef CARM_NDEBUG
+#define assert(expr)
+#else
+#define assert(expr) \
+        if(unlikely(!(expr))) {                                   \
+        printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \
+        #expr,__FILE__,__FUNCTION__,__LINE__);          \
+        }
+#endif
+
+/* defines only for the constants which don't work well as enums */
+struct carm_host;
+
+enum {
+	/* adapter-wide limits */
+	CARM_MAX_PORTS		= 8,
+	CARM_SHM_SIZE		= (4096 << 7),
+	CARM_MINORS_PER_MAJOR	= 256 / CARM_MAX_PORTS,
+	CARM_MAX_WAIT_Q		= CARM_MAX_PORTS + 1,
+
+	/* command message queue limits */
+	CARM_MAX_REQ		= 64,	       /* max command msgs per host */
+	CARM_MAX_Q		= 1,		   /* one command at a time */
+	CARM_MSG_LOW_WATER	= (CARM_MAX_REQ / 4),	     /* refill mark */
+
+	/* S/G limits, host-wide and per-request */
+	CARM_MAX_REQ_SG		= 32,	     /* max s/g entries per request */
+	CARM_SG_BOUNDARY	= 0xffffUL,	    /* s/g segment boundary */
+	CARM_MAX_HOST_SG	= 600,		/* max s/g entries per host */
+	CARM_SG_LOW_WATER	= (CARM_MAX_HOST_SG / 4),   /* re-fill mark */
+
+	/* hardware registers */
+	CARM_IHQP		= 0x1c,
+	CARM_INT_STAT		= 0x10, /* interrupt status */
+	CARM_INT_MASK		= 0x14, /* interrupt mask */
+	CARM_HMUC		= 0x18, /* host message unit control */
+	RBUF_ADDR_LO		= 0x20, /* response msg DMA buf low 32 bits */
+	RBUF_ADDR_HI		= 0x24, /* response msg DMA buf high 32 bits */
+	RBUF_BYTE_SZ		= 0x28,
+	CARM_RESP_IDX		= 0x2c,
+	CARM_CMS0		= 0x30, /* command message size reg 0 */
+	CARM_LMUC		= 0x48,
+	CARM_HMPHA		= 0x6c,
+	CARM_INITC		= 0xb5,
+
+	/* bits in CARM_INT_{STAT,MASK} */
+	INT_RESERVED		= 0xfffffff0,
+	INT_WATCHDOG		= (1 << 3),	/* watchdog timer */
+	INT_Q_OVERFLOW		= (1 << 2),	/* cmd msg q overflow */
+	INT_Q_AVAILABLE		= (1 << 1),	/* cmd msg q has free space */
+	INT_RESPONSE		= (1 << 0),	/* response msg available */
+	INT_ACK_MASK		= INT_WATCHDOG | INT_Q_OVERFLOW,
+	INT_DEF_MASK		= INT_RESERVED | INT_Q_OVERFLOW |
+				  INT_RESPONSE,
+
+	/* command messages, and related register bits */
+	CARM_HAVE_RESP		= 0x01,
+	CARM_MSG_READ		= 1,
+	CARM_MSG_WRITE		= 2,
+	CARM_MSG_VERIFY		= 3,
+	CARM_MSG_GET_CAPACITY	= 4,
+	CARM_MSG_FLUSH		= 5,
+	CARM_MSG_IOCTL		= 6,
+	CARM_MSG_ARRAY		= 8,
+	CARM_MSG_MISC		= 9,
+	CARM_CME		= (1 << 2),
+	CARM_RME		= (1 << 1),
+	CARM_WZBC		= (1 << 0),
+	CARM_RMI		= (1 << 0),
+	CARM_Q_FULL		= (1 << 3),
+	CARM_MSG_SIZE		= 288,
+	CARM_Q_LEN		= 48,
+
+	/* CARM_MSG_IOCTL messages */
+	CARM_IOC_SCAN_CHAN	= 5,	/* scan channels for devices */
+	CARM_IOC_GET_TCQ	= 13,	/* get tcq/ncq depth */
+	CARM_IOC_SET_TCQ	= 14,	/* set tcq/ncq depth */
+
+	IOC_SCAN_CHAN_NODEV	= 0x1f,
+	IOC_SCAN_CHAN_OFFSET	= 0x40,
+
+	/* CARM_MSG_ARRAY messages */
+	CARM_ARRAY_INFO		= 0,
+
+	ARRAY_NO_EXIST		= (1 << 31),
+
+	/* response messages */
+	RMSG_SZ			= 8,	/* sizeof(struct carm_response) */
+	RMSG_Q_LEN		= 48,	/* resp. msg list length */
+	RMSG_OK			= 1,	/* bit indicating msg was successful */
+					/* length of entire resp. msg buffer */
+	RBUF_LEN		= RMSG_SZ * RMSG_Q_LEN,
+
+	PDC_SHM_SIZE		= (4096 << 7), /* length of entire h/w buffer */
+
+	/* CARM_MSG_MISC messages */
+	MISC_GET_FW_VER		= 2,
+	MISC_ALLOC_MEM		= 3,
+	MISC_SET_TIME		= 5,
+
+	/* MISC_GET_FW_VER feature bits */
+	FW_VER_4PORT		= (1 << 2), /* 1=4 ports, 0=8 ports */
+	FW_VER_NON_RAID		= (1 << 1), /* 1=non-RAID firmware, 0=RAID */
+	FW_VER_ZCR		= (1 << 0), /* zero channel RAID (whatever that is) */
+
+	/* carm_host flags */
+	FL_DAC			= (1 << 0),
+	FL_NON_RAID		= FW_VER_NON_RAID,
+	FL_4PORT		= FW_VER_4PORT,
+	FL_FW_VER_MASK		= (FW_VER_NON_RAID | FW_VER_4PORT),
+};
+
+enum scatter_gather_types {
+	SGT_32BIT		= 0,
+	SGT_64BIT		= 1,
+};
+
+enum host_states {
+	HST_INVALID,		/* invalid state; never used */
+	HST_ALLOC_BUF,		/* setting up master SHM area */
+	HST_ERROR,		/* we never leave here */
+	HST_PORT_SCAN,		/* start dev scan */
+	HST_DEV_SCAN_START,	/* start per-device probe */
+	HST_DEV_SCAN,		/* continue per-device probe */
+	HST_DEV_ACTIVATE,	/* activate devices we found */
+	HST_PROBE_FINISHED,	/* probe is complete */
+	HST_PROBE_START,	/* initiate probe */
+	HST_SYNC_TIME,		/* tell firmware what time it is */
+	HST_GET_FW_VER,		/* get firmware version, adapter port cnt */
+};
+
+#ifdef CARM_DEBUG
+static const char *state_name[] = {
+	"HST_INVALID",
+	"HST_ALLOC_BUF",
+	"HST_ERROR",
+	"HST_PORT_SCAN",
+	"HST_DEV_SCAN_START",
+	"HST_DEV_SCAN",
+	"HST_DEV_ACTIVATE",
+	"HST_PROBE_FINISHED",
+	"HST_PROBE_START",
+	"HST_SYNC_TIME",
+	"HST_GET_FW_VER",
+};
+#endif
+
+struct carm_port {
+	unsigned int			port_no;
+	unsigned int			n_queued;
+	struct gendisk			*disk;
+	struct carm_host		*host;
+
+	/* attached device characteristics */
+	u64				capacity;
+	char				name[41];
+	u16				dev_geom_head;
+	u16				dev_geom_sect;
+	u16				dev_geom_cyl;
+};
+
+struct carm_request {
+	unsigned int			tag;
+	int				n_elem;
+	unsigned int			msg_type;
+	unsigned int			msg_subtype;
+	unsigned int			msg_bucket;
+	struct request			*rq;
+	struct carm_port		*port;
+	struct scatterlist		sg[CARM_MAX_REQ_SG];
+};
+
+struct carm_host {
+	unsigned long			flags;
+	void				*mmio;
+	void				*shm;
+	dma_addr_t			shm_dma;
+	int				major;
+	spinlock_t			lock;
+	struct pci_dev			*pdev;
+	unsigned int			state;
+	u32				fw_ver;
+
+	request_queue_t			*oob_q;
+	unsigned int			n_oob;
+
+	unsigned int			hw_sg_used;
+
+	unsigned int			resp_idx;
+
+	unsigned int			wait_q_prod;
+	unsigned int			wait_q_cons;
+	request_queue_t			*wait_q[CARM_MAX_WAIT_Q];
+
+	unsigned int			n_msgs;
+	u64				msg_alloc;
+	struct carm_request		req[CARM_MAX_REQ];
+	void				*msg_base;
+	dma_addr_t			msg_dma;
+
+	int				cur_scan_dev;
+	unsigned long			dev_active;
+	unsigned long			dev_present;
+	struct carm_port		port[CARM_MAX_PORTS];
+
+	struct work_struct		fsm_task;
+
+	struct semaphore		probe_sem;
+};
+
+struct carm_response {
+	u32 ret_handle;
+	u32 status;
+}  __attribute__((packed));
+
+struct carm_msg_sg {
+	u32 start;
+	u32 len;
+}  __attribute__((packed));
+
+struct carm_msg_rw {
+	u8 type;
+	u8 id;
+	u8 sg_count;
+	u8 sg_type;
+	u32 handle;
+	u32 lba;
+	u16 lba_count;
+	u16 lba_high;
+	struct carm_msg_sg sg[32];
+}  __attribute__((packed));
+
+struct carm_msg_allocbuf {
+	u8 type;
+	u8 subtype;
+	u8 n_sg;
+	u8 sg_type;
+	u32 handle;
+	u32 addr;
+	u32 len;
+	u32 evt_pool;
+	u32 n_evt;
+	u32 rbuf_pool;
+	u32 n_rbuf;
+	u32 msg_pool;
+	u32 n_msg;
+	struct carm_msg_sg sg[8];
+}  __attribute__((packed));
+
+struct carm_msg_ioctl {
+	u8 type;
+	u8 subtype;
+	u8 array_id;
+	u8 reserved1;
+	u32 handle;
+	u32 data_addr;
+	u32 reserved2;
+}  __attribute__((packed));
+
+struct carm_msg_sync_time {
+	u8 type;
+	u8 subtype;
+	u16 reserved1;
+	u32 handle;
+	u32 reserved2;
+	u32 timestamp;
+}  __attribute__((packed));
+
+struct carm_msg_get_fw_ver {
+	u8 type;
+	u8 subtype;
+	u16 reserved1;
+	u32 handle;
+	u32 data_addr;
+	u32 reserved2;
+}  __attribute__((packed));
+
+struct carm_fw_ver {
+	u32 version;
+	u8 features;
+	u8 reserved1;
+	u16 reserved2;
+}  __attribute__((packed));
+
+struct carm_array_info {
+	u32 size;
+
+	u16 size_hi;
+	u16 stripe_size;
+
+	u32 mode;
+
+	u16 stripe_blk_sz;
+	u16 reserved1;
+
+	u16 cyl;
+	u16 head;
+
+	u16 sect;
+	u8 array_id;
+	u8 reserved2;
+
+	char name[40];
+
+	u32 array_status;
+
+	/* device list continues beyond this point? */
+}  __attribute__((packed));
+
+static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static void carm_remove_one (struct pci_dev *pdev);
+static int carm_bdev_ioctl(struct inode *ino, struct file *fil,
+			   unsigned int cmd, unsigned long arg);
+
+static struct pci_device_id carm_pci_tbl[] = {
+	{ PCI_VENDOR_ID_PROMISE, 0x8000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{ PCI_VENDOR_ID_PROMISE, 0x8002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{ }	/* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, carm_pci_tbl);
+
+static struct pci_driver carm_driver = {
+	.name		= DRV_NAME,
+	.id_table	= carm_pci_tbl,
+	.probe		= carm_init_one,
+	.remove		= carm_remove_one,
+};
+
+static struct block_device_operations carm_bd_ops = {
+	.owner		= THIS_MODULE,
+	.ioctl		= carm_bdev_ioctl,
+};
+
+static unsigned int carm_host_id;
+
+
+
+static int carm_bdev_ioctl(struct inode *ino, struct file *fil,
+			   unsigned int cmd, unsigned long arg)
+{
+	void __user *usermem = (void *) arg;
+	struct carm_port *port = ino->i_bdev->bd_disk->private_data;
+	struct hd_geometry geom;
+
+	switch (cmd) {
+	case HDIO_GETGEO:
+		if (!usermem)
+			return -EINVAL;
+
+		geom.heads = (u8) port->dev_geom_head;
+		geom.sectors = (u8) port->dev_geom_sect;
+		geom.cylinders = port->dev_geom_cyl;
+		geom.start = get_start_sect(ino->i_bdev);
+
+		if (copy_to_user(usermem, &geom, sizeof(geom)))
+			return -EFAULT;
+		return 0;
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static inline unsigned long msecs_to_jiffies(unsigned long msecs)
+{
+	return ((HZ * msecs + 999) / 1000);
+}
+
+static void msleep(unsigned long msecs)
+{
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(msecs_to_jiffies(msecs));
+}
+
+static const u32 msg_sizes[] = { 32, 64, 128, CARM_MSG_SIZE };
+
+static inline int carm_lookup_bucket(u32 msg_size)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(msg_sizes); i++)
+		if (msg_size <= msg_sizes[i])
+			return i;
+	
+	return -ENOENT;
+}
+
+static void carm_init_buckets(void *mmio)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(msg_sizes); i++)
+		writel(msg_sizes[i], mmio + CARM_CMS0 + (4 * i));
+}
+
+static inline void *carm_ref_msg(struct carm_host *host,
+				 unsigned int msg_idx)
+{
+	return host->msg_base + (msg_idx * CARM_MSG_SIZE);
+}
+
+static inline dma_addr_t carm_ref_msg_dma(struct carm_host *host,
+					  unsigned int msg_idx)
+{
+	return host->msg_dma + (msg_idx * CARM_MSG_SIZE);
+}
+
+static int carm_send_msg(struct carm_host *host,
+			 struct carm_request *crq)
+{
+	void *mmio = host->mmio;
+	u32 msg = (u32) carm_ref_msg_dma(host, crq->tag);
+	u32 cm_bucket = crq->msg_bucket;
+	u32 tmp;
+	int rc = 0;
+
+	VPRINTK("ENTER\n");
+
+	tmp = readl(mmio + CARM_HMUC);
+	if (tmp & CARM_Q_FULL) {
+#if 0
+		tmp = readl(mmio + CARM_INT_MASK);
+		tmp |= INT_Q_AVAILABLE;
+		writel(tmp, mmio + CARM_INT_MASK);
+		readl(mmio + CARM_INT_MASK);	/* flush */
+#endif
+		DPRINTK("host msg queue full\n");
+		rc = -EBUSY;
+	} else {
+		writel(msg | (cm_bucket << 1), mmio + CARM_IHQP);
+		readl(mmio + CARM_IHQP);	/* flush */
+	}
+
+	return rc;
+}
+
+static struct carm_request *carm_get_request(struct carm_host *host)
+{
+	unsigned int i;
+
+	/* obey global hardware limit on S/G entries */
+	if (host->hw_sg_used >= (CARM_MAX_HOST_SG - CARM_MAX_REQ_SG))
+		return NULL;
+
+	for (i = 0; i < CARM_MAX_Q; i++)
+		if ((host->msg_alloc & (1ULL << i)) == 0) {
+			struct carm_request *crq = &host->req[i];
+			crq->port = NULL;
+			crq->n_elem = 0;
+
+			host->msg_alloc |= (1ULL << i);
+			host->n_msgs++;
+
+			assert(host->n_msgs <= CARM_MAX_REQ);
+			return crq;
+		}
+	
+	DPRINTK("no request available, returning NULL\n");
+	return NULL;
+}
+
+static int carm_put_request(struct carm_host *host, struct carm_request *crq)
+{
+	assert(crq->tag < CARM_MAX_Q);
+
+	if (unlikely((host->msg_alloc & (1ULL << crq->tag)) == 0))
+		return -EINVAL; /* tried to clear a tag that was not active */
+
+	assert(host->hw_sg_used >= crq->n_elem);
+
+	host->msg_alloc &= ~(1ULL << crq->tag);
+	host->hw_sg_used -= crq->n_elem;
+	host->n_msgs--;
+
+	return 0;
+}
+
+static struct carm_request *carm_get_special(struct carm_host *host)
+{
+	unsigned long flags;
+	struct carm_request *crq = NULL;
+	struct request *rq;
+	int tries = 5000;
+
+	while (tries-- > 0) {
+		spin_lock_irqsave(&host->lock, flags);
+		crq = carm_get_request(host);
+		spin_unlock_irqrestore(&host->lock, flags);
+
+		if (crq)
+			break;
+		msleep(10);
+	}
+
+	if (!crq)
+		return NULL;
+
+	rq = blk_get_request(host->oob_q, WRITE /* bogus */, GFP_KERNEL);
+	if (!rq) {
+		spin_lock_irqsave(&host->lock, flags);
+		carm_put_request(host, crq);
+		spin_unlock_irqrestore(&host->lock, flags);
+		return NULL;
+	}
+
+	crq->rq = rq;
+	return crq;
+}
+
+static int carm_array_info (struct carm_host *host, unsigned int array_idx)
+{
+	struct carm_msg_ioctl *ioc;
+	unsigned int idx;
+	u32 msg_data;
+	dma_addr_t msg_dma;
+	struct carm_request *crq;
+	int rc;
+
+	crq = carm_get_special(host);
+	if (!crq) {
+		rc = -ENOMEM;
+		goto err_out;
+	}
+
+	idx = crq->tag;
+
+	ioc = carm_ref_msg(host, idx);
+	msg_dma = carm_ref_msg_dma(host, idx);
+	msg_data = (u32) (msg_dma + sizeof(struct carm_array_info));
+
+	crq->msg_type = CARM_MSG_ARRAY;
+	crq->msg_subtype = CARM_ARRAY_INFO;
+	rc = carm_lookup_bucket(sizeof(struct carm_msg_ioctl) +
+				sizeof(struct carm_array_info));
+	BUG_ON(rc < 0);
+	crq->msg_bucket = (u32) rc;
+
+	memset(ioc, 0, sizeof(*ioc));
+	ioc->type	= CARM_MSG_ARRAY;
+	ioc->subtype	= CARM_ARRAY_INFO;
+	ioc->array_id	= (u8) array_idx;
+	ioc->handle	= cpu_to_le32(TAG_ENCODE(idx));
+	ioc->data_addr	= cpu_to_le32(msg_data);
+
+	spin_lock_irq(&host->lock);
+	assert(host->state == HST_DEV_SCAN_START ||
+	       host->state == HST_DEV_SCAN);
+	spin_unlock_irq(&host->lock);
+
+	DPRINTK("blk_insert_request, tag == %u\n", idx);
+	blk_insert_request(host->oob_q, crq->rq, 1, crq, 0);
+
+	return 0;
+
+err_out:
+	spin_lock_irq(&host->lock);
+	host->state = HST_ERROR;
+	spin_unlock_irq(&host->lock);
+	return rc;
+}
+
+typedef unsigned int (*carm_sspc_t)(struct carm_host *, unsigned int, void *);
+
+static int carm_send_special (struct carm_host *host, carm_sspc_t func)
+{
+	struct carm_request *crq;
+	struct carm_msg_ioctl *ioc;
+	void *mem;
+	unsigned int idx, msg_size;
+	int rc;
+
+	crq = carm_get_special(host);
+	if (!crq)
+		return -ENOMEM;
+
+	idx = crq->tag;
+
+	mem = carm_ref_msg(host, idx);
+
+	msg_size = func(host, idx, mem);
+
+	ioc = mem;
+	crq->msg_type = ioc->type;
+	crq->msg_subtype = ioc->subtype;
+	rc = carm_lookup_bucket(msg_size);
+	BUG_ON(rc < 0);
+	crq->msg_bucket = (u32) rc;
+
+	DPRINTK("blk_insert_request, tag == %u\n", idx);
+	blk_insert_request(host->oob_q, crq->rq, 1, crq, 0);
+
+	return 0;
+}
+
+static unsigned int carm_fill_sync_time(struct carm_host *host,
+					unsigned int idx, void *mem)
+{
+	struct timeval tv;
+	struct carm_msg_sync_time *st = mem;
+
+	do_gettimeofday(&tv);
+
+	memset(st, 0, sizeof(*st));
+	st->type	= CARM_MSG_MISC;
+	st->subtype	= MISC_SET_TIME;
+	st->handle	= cpu_to_le32(TAG_ENCODE(idx));
+	st->timestamp	= cpu_to_le32(tv.tv_sec);
+
+	return sizeof(struct carm_msg_sync_time);
+}
+
+static unsigned int carm_fill_alloc_buf(struct carm_host *host,
+					unsigned int idx, void *mem)
+{
+	struct carm_msg_allocbuf *ab = mem;
+
+	memset(ab, 0, sizeof(*ab));
+	ab->type	= CARM_MSG_MISC;
+	ab->subtype	= MISC_ALLOC_MEM;
+	ab->handle	= cpu_to_le32(TAG_ENCODE(idx));
+	ab->n_sg	= 1;
+	ab->sg_type	= SGT_32BIT;
+	ab->addr	= cpu_to_le32(host->shm_dma + (PDC_SHM_SIZE >> 1));
+	ab->len		= cpu_to_le32(PDC_SHM_SIZE >> 1);
+	ab->evt_pool	= cpu_to_le32(host->shm_dma + (16 * 1024));
+	ab->n_evt	= cpu_to_le32(1024);
+	ab->rbuf_pool	= cpu_to_le32(host->shm_dma);
+	ab->n_rbuf	= cpu_to_le32(RMSG_Q_LEN);
+	ab->msg_pool	= cpu_to_le32(host->shm_dma + RBUF_LEN);
+	ab->n_msg	= cpu_to_le32(CARM_Q_LEN);
+	ab->sg[0].start	= cpu_to_le32(host->shm_dma + (PDC_SHM_SIZE >> 1));
+	ab->sg[0].len	= cpu_to_le32(65536);
+
+	return sizeof(struct carm_msg_allocbuf);
+}
+
+static unsigned int carm_fill_scan_channels(struct carm_host *host,
+					    unsigned int idx, void *mem)
+{
+	struct carm_msg_ioctl *ioc = mem;
+	u32 msg_data = (u32) (carm_ref_msg_dma(host, idx) +
+			      IOC_SCAN_CHAN_OFFSET);
+
+	memset(ioc, 0, sizeof(*ioc));
+	ioc->type	= CARM_MSG_IOCTL;
+	ioc->subtype	= CARM_IOC_SCAN_CHAN;
+	ioc->handle	= cpu_to_le32(TAG_ENCODE(idx));
+	ioc->data_addr	= cpu_to_le32(msg_data);
+
+	/* fill output data area with "no device" default values */
+	mem += IOC_SCAN_CHAN_OFFSET;
+	memset(mem, IOC_SCAN_CHAN_NODEV, CARM_MAX_PORTS);
+
+	return IOC_SCAN_CHAN_OFFSET + CARM_MAX_PORTS;
+}
+
+static unsigned int carm_fill_get_fw_ver(struct carm_host *host,
+					 unsigned int idx, void *mem)
+{
+	struct carm_msg_get_fw_ver *ioc = mem;
+	u32 msg_data = (u32) (carm_ref_msg_dma(host, idx) + sizeof(*ioc));
+
+	memset(ioc, 0, sizeof(*ioc));
+	ioc->type	= CARM_MSG_MISC;
+	ioc->subtype	= MISC_GET_FW_VER;
+	ioc->handle	= cpu_to_le32(TAG_ENCODE(idx));
+	ioc->data_addr	= cpu_to_le32(msg_data);
+
+	return sizeof(struct carm_msg_get_fw_ver) +
+	       sizeof(struct carm_fw_ver);
+}
+
+static inline void carm_end_request_queued(struct carm_host *host,
+					   struct carm_request *crq,
+					   int uptodate)
+{
+	struct request *req = crq->rq;
+	int rc;
+
+	rc = end_that_request_first(req, uptodate, req->hard_nr_sectors);
+	assert(rc == 0);
+
+	end_that_request_last(req);
+
+	rc = carm_put_request(host, crq);
+	assert(rc == 0);
+}
+
+static inline void carm_push_q (struct carm_host *host, request_queue_t *q)
+{
+	unsigned int idx = host->wait_q_prod % CARM_MAX_WAIT_Q;
+
+	blk_stop_queue(q);
+	VPRINTK("STOPPED QUEUE %p\n", q);
+
+	host->wait_q[idx] = q;
+	host->wait_q_prod++;
+	BUG_ON(host->wait_q_prod == host->wait_q_cons); /* overrun */
+}
+
+static inline request_queue_t *carm_pop_q(struct carm_host *host)
+{
+	unsigned int idx;
+
+	if (host->wait_q_prod == host->wait_q_cons)
+		return NULL;
+
+	idx = host->wait_q_cons % CARM_MAX_WAIT_Q;
+	host->wait_q_cons++;
+
+	return host->wait_q[idx];
+}
+
+static inline void carm_round_robin(struct carm_host *host)
+{
+	request_queue_t *q = carm_pop_q(host);
+	if (q) {
+		blk_start_queue(q);
+		VPRINTK("STARTED QUEUE %p\n", q);
+	}
+}
+
+static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq,
+			int is_ok)
+{
+	carm_end_request_queued(host, crq, is_ok);
+	if (CARM_MAX_Q == 1)
+		carm_round_robin(host);
+	else if ((host->n_msgs <= CARM_MSG_LOW_WATER) &&
+		 (host->hw_sg_used <= CARM_SG_LOW_WATER)) {
+		carm_round_robin(host);
+	}
+}
+
+static void carm_oob_rq_fn(request_queue_t *q)
+{
+	struct carm_host *host = q->queuedata;
+	struct carm_request *crq;
+	struct request *rq;
+	int rc;
+
+	while (1) {
+		DPRINTK("get req\n");
+		rq = elv_next_request(q);
+		if (!rq)
+			break;
+
+		blkdev_dequeue_request(rq);
+
+		crq = rq->special;
+		assert(crq != NULL);
+		assert(crq->rq == rq);
+
+		crq->n_elem = 0;
+
+		DPRINTK("send req\n");
+		rc = carm_send_msg(host, crq);
+		if (rc) {
+			blk_requeue_request(q, rq);
+			carm_push_q(host, q);
+			return;		/* call us again later, eventually */
+		}
+	}
+}
+
+static void carm_rq_fn(request_queue_t *q)
+{
+	struct carm_port *port = q->queuedata;
+	struct carm_host *host = port->host;
+	struct carm_msg_rw *msg;
+	struct carm_request *crq;
+	struct request *rq;
+	struct scatterlist *sg;
+	int writing = 0, pci_dir, i, n_elem, rc;
+	u32 tmp;
+	unsigned int msg_size;
+
+queue_one_request:
+	VPRINTK("get req\n");
+	rq = elv_next_request(q);
+	if (!rq)
+		return;
+
+	crq = carm_get_request(host);
+	if (!crq) {
+		carm_push_q(host, q);
+		return;		/* call us again later, eventually */
+	}
+	crq->rq = rq;
+
+	blkdev_dequeue_request(rq);
+
+	if (rq_data_dir(rq) == WRITE) {
+		writing = 1;
+		pci_dir = PCI_DMA_TODEVICE;
+	} else {
+		pci_dir = PCI_DMA_FROMDEVICE;
+	}
+
+	/* get scatterlist from block layer */
+	sg = &crq->sg[0];
+	n_elem = blk_rq_map_sg(q, rq, sg);
+	if (n_elem <= 0) {
+		carm_end_rq(host, crq, 0);
+		return;		/* request with no s/g entries? */
+	}
+
+	/* map scatterlist to PCI bus addresses */
+	n_elem = pci_map_sg(host->pdev, sg, n_elem, pci_dir);
+	if (n_elem <= 0) {
+		carm_end_rq(host, crq, 0);
+		return;		/* request with no s/g entries? */
+	}
+	crq->n_elem = n_elem;
+	crq->port = port;
+	host->hw_sg_used += n_elem;
+
+	/*
+	 * build read/write message
+	 */
+
+	VPRINTK("build msg\n");
+	msg = (struct carm_msg_rw *) carm_ref_msg(host, crq->tag);
+
+	if (writing) {
+		msg->type = CARM_MSG_WRITE;
+		crq->msg_type = CARM_MSG_WRITE;
+	} else {
+		msg->type = CARM_MSG_READ;
+		crq->msg_type = CARM_MSG_READ;
+	}
+
+	msg->id		= port->port_no;
+	msg->sg_count	= n_elem;
+	msg->sg_type	= SGT_32BIT;
+	msg->handle	= cpu_to_le32(TAG_ENCODE(crq->tag));
+	msg->lba	= cpu_to_le32(rq->sector & 0xffffffff);
+	tmp		= (rq->sector >> 16) >> 16;
+	msg->lba_high	= cpu_to_le16( (u16) tmp );
+	msg->lba_count	= cpu_to_le16(rq->nr_sectors);
+
+	msg_size = sizeof(struct carm_msg_rw) - sizeof(msg->sg);
+	for (i = 0; i < n_elem; i++) {
+		struct carm_msg_sg *carm_sg = &msg->sg[i];
+		carm_sg->start = cpu_to_le32(sg_dma_address(&crq->sg[i]));
+		carm_sg->len = cpu_to_le32(sg_dma_len(&crq->sg[i]));
+		msg_size += sizeof(struct carm_msg_sg);
+	}
+
+	rc = carm_lookup_bucket(msg_size);
+	BUG_ON(rc < 0);
+	crq->msg_bucket = (u32) rc;
+
+	/*
+	 * queue read/write message to hardware
+	 */
+
+	VPRINTK("send msg, tag == %u\n", crq->tag);
+	rc = carm_send_msg(host, crq);
+	if (rc) {
+		carm_put_request(host, crq);
+		blk_requeue_request(q, rq);
+		carm_push_q(host, q);
+		return;		/* call us again later, eventually */
+	}
+
+	goto queue_one_request;
+}
+
+static void carm_handle_array_info(struct carm_host *host,
+				   struct carm_request *crq, u8 *mem,
+				   int is_ok)
+{
+	struct carm_port *port;
+	u8 *msg_data = mem + sizeof(struct carm_array_info);
+	struct carm_array_info *desc = (struct carm_array_info *) msg_data;
+	u64 lo, hi;
+	int cur_port;
+	size_t slen;
+
+	DPRINTK("ENTER\n");
+
+	carm_end_rq(host, crq, is_ok);
+
+	if (!is_ok)
+		goto out;
+	if (le32_to_cpu(desc->array_status) & ARRAY_NO_EXIST)
+		goto out;
+
+	cur_port = host->cur_scan_dev;
+
+	/* should never occur */
+	if ((cur_port < 0) || (cur_port >= CARM_MAX_PORTS)) {
+		printk(KERN_ERR PFX "BUG: cur_scan_dev==%d, array_id==%d\n",
+		       cur_port, (int) desc->array_id);
+		goto out;
+	}
+
+	port = &host->port[cur_port];
+
+	lo = (u64) le32_to_cpu(desc->size);
+	hi = (u64) le32_to_cpu(desc->size_hi);
+
+	port->capacity = lo | (hi << 32);
+	port->dev_geom_head = le16_to_cpu(desc->head);
+	port->dev_geom_sect = le16_to_cpu(desc->sect);
+	port->dev_geom_cyl = le16_to_cpu(desc->cyl);
+
+	host->dev_active |= (1 << cur_port);
+
+	strncpy(port->name, desc->name, sizeof(port->name));
+	port->name[sizeof(port->name) - 1] = 0;
+	slen = strlen(port->name);
+	while (slen && (port->name[slen - 1] == ' ')) {
+		port->name[slen - 1] = 0;
+		slen--;
+	}
+
+	printk(KERN_INFO DRV_NAME "(%s): port %u device %Lu sectors\n",
+	       pci_name(host->pdev), port->port_no, port->capacity);
+	printk(KERN_INFO DRV_NAME "(%s): port %u device \"%s\"\n",
+	       pci_name(host->pdev), port->port_no, port->name);
+
+out:
+	assert(host->state == HST_DEV_SCAN);
+	schedule_work(&host->fsm_task);
+}
+
+static void carm_handle_scan_chan(struct carm_host *host,
+				  struct carm_request *crq, u8 *mem,
+				  int is_ok)
+{
+	u8 *msg_data = mem + IOC_SCAN_CHAN_OFFSET;
+	unsigned int i, dev_count = 0;
+	int new_state = HST_DEV_SCAN_START;
+
+	DPRINTK("ENTER\n");
+
+	carm_end_rq(host, crq, is_ok);
+
+	if (!is_ok) {
+		new_state = HST_ERROR;
+		goto out;
+	}
+
+	/* TODO: scan and support non-disk devices */
+	for (i = 0; i < 8; i++)
+		if (msg_data[i] == 0) { /* direct-access device (disk) */
+			host->dev_present |= (1 << i);
+			dev_count++;
+		}
+
+	printk(KERN_INFO DRV_NAME "(%s): found %u interesting devices\n",
+	       pci_name(host->pdev), dev_count);
+
+out:
+	assert(host->state == HST_PORT_SCAN);
+	host->state = new_state;
+	schedule_work(&host->fsm_task);
+}
+
+static void carm_handle_generic(struct carm_host *host,
+				struct carm_request *crq, int is_ok,
+				int cur_state, int next_state)
+{
+	DPRINTK("ENTER\n");
+
+	carm_end_rq(host, crq, is_ok);
+
+	assert(host->state == cur_state);
+	if (is_ok)
+		host->state = next_state;
+	else
+		host->state = HST_ERROR;
+	schedule_work(&host->fsm_task);
+}
+
+static inline void carm_handle_rw(struct carm_host *host,
+				  struct carm_request *crq, int is_ok)
+{
+	int pci_dir;
+
+	VPRINTK("ENTER\n");
+
+	if (rq_data_dir(crq->rq) == WRITE)
+		pci_dir = PCI_DMA_TODEVICE;
+	else
+		pci_dir = PCI_DMA_FROMDEVICE;
+
+	pci_unmap_sg(host->pdev, &crq->sg[0], crq->n_elem, pci_dir);
+
+	carm_end_rq(host, crq, is_ok);
+}
+
+static inline void carm_handle_resp(struct carm_host *host,
+				    u32 ret_handle_le, u32 status)
+{
+	u32 handle = le32_to_cpu(ret_handle_le);
+	unsigned int msg_idx;
+	struct carm_request *crq;
+	int is_ok = (status == RMSG_OK);
+	u8 *mem;
+
+	VPRINTK("ENTER, handle == 0x%x\n", handle);
+
+	if (unlikely(!TAG_VALID(handle))) {
+		printk(KERN_ERR DRV_NAME "(%s): BUG: invalid tag 0x%x\n",
+		       pci_name(host->pdev), handle);
+		return;
+	}
+
+	msg_idx = TAG_DECODE(handle);
+	VPRINTK("tag == %u\n", msg_idx);
+
+	crq = &host->req[msg_idx];
+
+	/* fast path */
+	if (likely(crq->msg_type == CARM_MSG_READ ||
+		   crq->msg_type == CARM_MSG_WRITE)) {
+		carm_handle_rw(host, crq, is_ok);
+		return;
+	}
+
+	mem = carm_ref_msg(host, msg_idx);
+
+	switch (crq->msg_type) {
+	case CARM_MSG_IOCTL: {
+		switch (crq->msg_subtype) {
+		case CARM_IOC_SCAN_CHAN:
+			carm_handle_scan_chan(host, crq, mem, is_ok);
+			break;
+		default:
+			/* unknown / invalid response */
+			goto err_out;
+		}
+		break;
+	}
+
+	case CARM_MSG_MISC: {
+		switch (crq->msg_subtype) {
+		case MISC_ALLOC_MEM:
+			carm_handle_generic(host, crq, is_ok,
+					    HST_ALLOC_BUF, HST_SYNC_TIME);
+			break;
+		case MISC_SET_TIME:
+			carm_handle_generic(host, crq, is_ok,
+					    HST_SYNC_TIME, HST_GET_FW_VER);
+			break;
+		case MISC_GET_FW_VER: {
+			struct carm_fw_ver *ver = (struct carm_fw_ver *)
+				mem + sizeof(struct carm_msg_get_fw_ver);
+			if (is_ok) {
+				host->fw_ver = le32_to_cpu(ver->version);
+				host->flags |= (ver->features & FL_FW_VER_MASK);
+			}
+			carm_handle_generic(host, crq, is_ok,
+					    HST_GET_FW_VER, HST_PORT_SCAN);
+			break;
+		}
+		default:
+			/* unknown / invalid response */
+			goto err_out;
+		}
+		break;
+	}
+
+	case CARM_MSG_ARRAY: {
+		switch (crq->msg_subtype) {
+		case CARM_ARRAY_INFO:
+			carm_handle_array_info(host, crq, mem, is_ok);
+			break;
+		default:
+			/* unknown / invalid response */
+			goto err_out;
+		}
+		break;
+	}
+
+	default:
+		/* unknown / invalid response */
+		goto err_out;
+	}
+
+	return;
+
+err_out:
+	printk(KERN_WARNING DRV_NAME "(%s): BUG: unhandled message type %d/%d\n",
+	       pci_name(host->pdev), crq->msg_type, crq->msg_subtype);
+	carm_end_rq(host, crq, 0);
+}
+
+static inline void carm_handle_responses(struct carm_host *host)
+{
+	void *mmio = host->mmio;
+	struct carm_response *resp = (struct carm_response *) host->shm;
+	unsigned int work = 0;
+	unsigned int idx = host->resp_idx % RMSG_Q_LEN;
+
+	while (1) {
+		u32 status = le32_to_cpu(resp[idx].status);
+
+		if (status == 0xffffffff) {
+			VPRINTK("ending response on index %u\n", idx);
+			writel(idx << 3, mmio + CARM_RESP_IDX);
+			break;
+		}
+
+		/* response to a message we sent */
+		else if ((status & (1 << 31)) == 0) {
+			VPRINTK("handling msg response on index %u\n", idx);
+			carm_handle_resp(host, resp[idx].ret_handle, status);
+			resp[idx].status = 0xffffffff;
+		}
+
+		/* asynchronous events the hardware throws our way */
+		else if ((status & 0xff000000) == (1 << 31)) {
+			u8 *evt_type_ptr = (u8 *) &resp[idx];
+			u8 evt_type = *evt_type_ptr;
+			printk(KERN_WARNING DRV_NAME "(%s): unhandled event type %d\n",
+			       pci_name(host->pdev), (int) evt_type);
+			resp[idx].status = 0xffffffff;
+		}
+
+		idx = NEXT_RESP(idx);
+		work++;
+	}
+
+	VPRINTK("EXIT, work==%u\n", work);
+	host->resp_idx += work;
+}
+
+static irqreturn_t carm_interrupt(int irq, void *__host, struct pt_regs *regs)
+{
+	struct carm_host *host = __host;
+	void *mmio;
+	u32 mask;
+	int handled = 0;
+	unsigned long flags;
+
+	if (!host) {
+		VPRINTK("no host\n");
+		return IRQ_NONE;
+	}
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	mmio = host->mmio;
+
+	/* reading should also clear interrupts */
+	mask = readl(mmio + CARM_INT_STAT);
+
+	if (mask == 0 || mask == 0xffffffff) {
+		VPRINTK("no work, mask == 0x%x\n", mask);
+		goto out;
+	}
+
+	if (mask & INT_ACK_MASK)
+		writel(mask, mmio + CARM_INT_STAT);
+
+	if (unlikely(host->state == HST_INVALID)) {
+		VPRINTK("not initialized yet, mask = 0x%x\n", mask);
+		goto out;
+	}
+
+	if (mask & CARM_HAVE_RESP) {
+		handled = 1;
+		carm_handle_responses(host);
+	}
+
+out:
+	spin_unlock_irqrestore(&host->lock, flags);
+	VPRINTK("EXIT\n");
+	return IRQ_RETVAL(handled);
+}
+
+static void carm_fsm_task (void *_data)
+{
+	struct carm_host *host = _data;
+	unsigned long flags;
+	unsigned int state;
+	int rc, i, next_dev;
+	int reschedule = 0;
+	int new_state = HST_INVALID;
+
+	spin_lock_irqsave(&host->lock, flags);
+	state = host->state;
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	DPRINTK("ENTER, state == %s\n", state_name[state]);
+
+	switch (state) {
+	case HST_PROBE_START:
+		new_state = HST_ALLOC_BUF;
+		reschedule = 1;
+		break;
+
+	case HST_ALLOC_BUF:
+		rc = carm_send_special(host, carm_fill_alloc_buf);
+		if (rc) {
+			new_state = HST_ERROR;
+			reschedule = 1;
+		}
+		break;
+
+	case HST_SYNC_TIME:
+		rc = carm_send_special(host, carm_fill_sync_time);
+		if (rc) {
+			new_state = HST_ERROR;
+			reschedule = 1;
+		}
+		break;
+
+	case HST_GET_FW_VER:
+		rc = carm_send_special(host, carm_fill_get_fw_ver);
+		if (rc) {
+			new_state = HST_ERROR;
+			reschedule = 1;
+		}
+		break;
+
+	case HST_PORT_SCAN:
+		rc = carm_send_special(host, carm_fill_scan_channels);
+		if (rc) {
+			new_state = HST_ERROR;
+			reschedule = 1;
+		}
+		break;
+
+	case HST_DEV_SCAN_START:
+		host->cur_scan_dev = -1;
+		new_state = HST_DEV_SCAN;
+		reschedule = 1;
+		break;
+
+	case HST_DEV_SCAN:
+		next_dev = -1;
+		for (i = host->cur_scan_dev + 1; i < CARM_MAX_PORTS; i++)
+			if (host->dev_present & (1 << i)) {
+				next_dev = i;
+				break;
+			}
+
+		if (next_dev >= 0) {
+			host->cur_scan_dev = next_dev;
+			rc = carm_array_info(host, next_dev);
+			if (rc) {
+				new_state = HST_ERROR;
+				reschedule = 1;
+			}
+		} else {
+			new_state = HST_DEV_ACTIVATE;
+			reschedule = 1;
+		}
+		break;
+
+	case HST_DEV_ACTIVATE: {
+		int activated = 0;
+		for (i = 0; i < CARM_MAX_PORTS; i++)
+			if (host->dev_active & (1 << i)) {
+				struct carm_port *port = &host->port[i];
+				struct gendisk *disk = port->disk;
+
+				set_capacity(disk, port->capacity);
+				add_disk(disk);
+				activated++;
+			}
+
+		printk(KERN_INFO DRV_NAME "(%s): %d ports activated\n",
+		       pci_name(host->pdev), activated);
+
+		new_state = HST_PROBE_FINISHED;
+		reschedule = 1;
+		break;
+	}
+
+	case HST_PROBE_FINISHED:
+		up(&host->probe_sem);
+		break;
+
+	case HST_ERROR:
+		/* FIXME: TODO */
+		break;
+
+	default:
+		/* should never occur */
+		printk(KERN_ERR PFX "BUG: unknown state %d\n", state);
+		assert(0);
+		break;
+	}
+
+	if (new_state != HST_INVALID) {
+		spin_lock_irqsave(&host->lock, flags);
+		host->state = new_state;
+		spin_unlock_irqrestore(&host->lock, flags);
+	}
+	if (reschedule)
+		schedule_work(&host->fsm_task);
+}
+
+static int carm_init_wait(void *mmio, u32 bits, unsigned int test_bit)
+{
+	unsigned int i;
+
+	for (i = 0; i < 50000; i++) {
+		u32 tmp = readl(mmio + CARM_LMUC);
+		udelay(100);
+
+		if (test_bit) {
+			if ((tmp & bits) == bits)
+				return 0;
+		} else {
+			if ((tmp & bits) == 0)
+				return 0;
+		}
+
+		cond_resched();
+	}
+
+	printk(KERN_ERR PFX "carm_init_wait timeout, bits == 0x%x, test_bit == %s\n",
+	       bits, test_bit ? "yes" : "no");
+	return -EBUSY;
+}
+
+static void carm_init_responses(struct carm_host *host)
+{
+	void *mmio = host->mmio;
+	unsigned int i;
+	struct carm_response *resp = (struct carm_response *) host->shm;
+
+	for (i = 0; i < RMSG_Q_LEN; i++)
+		resp[i].status = 0xffffffff;
+
+	writel(0, mmio + CARM_RESP_IDX);
+}
+
+static int carm_init_host(struct carm_host *host)
+{
+	void *mmio = host->mmio;
+	u32 tmp;
+	u8 tmp8;
+	int rc;
+
+	DPRINTK("ENTER\n");
+
+	writel(0, mmio + CARM_INT_MASK);
+
+	tmp8 = readb(mmio + CARM_INITC);
+	if (tmp8 & 0x01) {
+		tmp8 &= ~0x01;
+		writeb(tmp8, CARM_INITC);
+		readb(mmio + CARM_INITC);	/* flush */
+
+		DPRINTK("snooze...\n");
+		msleep(5000);
+	}
+
+	tmp = readl(mmio + CARM_HMUC);
+	if (tmp & CARM_CME) {
+		DPRINTK("CME bit present, waiting\n");
+		rc = carm_init_wait(mmio, CARM_CME, 1);
+		if (rc) {
+			DPRINTK("EXIT, carm_init_wait 1 failed\n");
+			return rc;
+		}
+	}
+	if (tmp & CARM_RME) {
+		DPRINTK("RME bit present, waiting\n");
+		rc = carm_init_wait(mmio, CARM_RME, 1);
+		if (rc) {
+			DPRINTK("EXIT, carm_init_wait 2 failed\n");
+			return rc;
+		}
+	}
+
+	tmp &= ~(CARM_RME | CARM_CME);
+	writel(tmp, mmio + CARM_HMUC);
+	readl(mmio + CARM_HMUC);	/* flush */
+
+	rc = carm_init_wait(mmio, CARM_RME | CARM_CME, 0);
+	if (rc) {
+		DPRINTK("EXIT, carm_init_wait 3 failed\n");
+		return rc;
+	}
+
+	carm_init_buckets(mmio);
+
+	writel(host->shm_dma & 0xffffffff, mmio + RBUF_ADDR_LO);
+	writel((host->shm_dma >> 16) >> 16, mmio + RBUF_ADDR_HI);
+	writel(RBUF_LEN, mmio + RBUF_BYTE_SZ);
+
+	tmp = readl(mmio + CARM_HMUC);
+	tmp |= (CARM_RME | CARM_CME | CARM_WZBC);
+	writel(tmp, mmio + CARM_HMUC);
+	readl(mmio + CARM_HMUC);	/* flush */
+
+	rc = carm_init_wait(mmio, CARM_RME | CARM_CME, 1);
+	if (rc) {
+		DPRINTK("EXIT, carm_init_wait 4 failed\n");
+		return rc;
+	}
+
+	writel(0, mmio + CARM_HMPHA);
+	writel(INT_DEF_MASK, mmio + CARM_INT_MASK);
+
+	carm_init_responses(host);
+
+	/* start initialization, probing state machine */
+	spin_lock_irq(&host->lock);
+	assert(host->state == HST_INVALID);
+	host->state = HST_PROBE_START;
+	spin_unlock_irq(&host->lock);
+	schedule_work(&host->fsm_task);
+
+	DPRINTK("EXIT\n");
+	return 0;
+}
+
+static int carm_init_disks(struct carm_host *host)
+{
+	unsigned int i;
+	int rc = 0;
+
+	for (i = 0; i < CARM_MAX_PORTS; i++) {
+		struct gendisk *disk;
+		request_queue_t *q;
+		struct carm_port *port;
+
+		port = &host->port[i];
+		port->host = host;
+		port->port_no = i;
+
+		disk = alloc_disk(CARM_MINORS_PER_MAJOR);
+		if (!disk) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		port->disk = disk;
+		sprintf(disk->disk_name, DRV_NAME "%u_%u", carm_host_id, i);
+		sprintf(disk->devfs_name, DRV_NAME "/%u_%u", carm_host_id, i);
+		disk->major = host->major;
+		disk->first_minor = i * CARM_MINORS_PER_MAJOR;
+		disk->fops = &carm_bd_ops;
+		disk->private_data = port;
+
+		q = blk_init_queue(carm_rq_fn, &host->lock);
+		if (!q) {
+			rc = -ENOMEM;
+			break;
+		}
+		disk->queue = q;
+		blk_queue_max_hw_segments(q, CARM_MAX_REQ_SG);
+		blk_queue_max_phys_segments(q, CARM_MAX_REQ_SG);
+		blk_queue_segment_boundary(q, CARM_SG_BOUNDARY);
+
+		q->queuedata = port;
+	}
+
+	return rc;
+}
+
+static void carm_free_disks(struct carm_host *host)
+{
+	unsigned int i;
+
+	for (i = 0; i < CARM_MAX_PORTS; i++) {
+		struct gendisk *disk = host->port[i].disk;
+		if (disk) {
+			request_queue_t *q = disk->queue;
+			if (q)
+				blk_cleanup_queue(q);
+			put_disk(disk);
+		}
+	}
+}
+
+static int carm_init_shm(struct carm_host *host)
+{
+	host->shm = pci_alloc_consistent(host->pdev, CARM_SHM_SIZE,
+					 &host->shm_dma);
+	if (!host->shm)
+		return -ENOMEM;
+
+	host->msg_base = host->shm + RBUF_LEN;
+	host->msg_dma = host->shm_dma + RBUF_LEN;
+
+	memset(host->shm, 0xff, RBUF_LEN);
+	memset(host->msg_base, 0, PDC_SHM_SIZE - RBUF_LEN);
+
+	return 0;
+}
+
+static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static unsigned int printed_version;
+	struct carm_host *host;
+	unsigned int pci_dac;
+	int rc;
+	request_queue_t *q;
+	unsigned int i;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_out;
+
+#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */
+	rc = pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
+	if (!rc) {
+		rc = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
+		if (rc) {
+			printk(KERN_ERR DRV_NAME "(%s): consistent DMA mask failure\n",
+				pci_name(pdev));
+			goto err_out_regions;
+		}
+		pci_dac = 1;
+	} else {
+#endif
+		rc = pci_set_dma_mask(pdev, 0xffffffffULL);
+		if (rc) {
+			printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n",
+				pci_name(pdev));
+			goto err_out_regions;
+		}
+		pci_dac = 0;
+#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */
+	}
+#endif
+
+	host = kmalloc(sizeof(*host), GFP_KERNEL);
+	if (!host) {
+		printk(KERN_ERR DRV_NAME "(%s): memory alloc failure\n",
+		       pci_name(pdev));
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	memset(host, 0, sizeof(*host));
+	host->pdev = pdev;
+	host->flags = pci_dac ? FL_DAC : 0;
+	spin_lock_init(&host->lock);
+	INIT_WORK(&host->fsm_task, carm_fsm_task, host);
+	init_MUTEX_LOCKED(&host->probe_sem);
+
+	for (i = 0; i < ARRAY_SIZE(host->req); i++)
+		host->req[i].tag = i;
+
+	host->mmio = ioremap(pci_resource_start(pdev, 0),
+			     pci_resource_len(pdev, 0));
+	if (!host->mmio) {
+		printk(KERN_ERR DRV_NAME "(%s): MMIO alloc failure\n",
+		       pci_name(pdev));
+		rc = -ENOMEM;
+		goto err_out_kfree;
+	}
+
+	rc = carm_init_shm(host);
+	if (rc) {
+		printk(KERN_ERR DRV_NAME "(%s): DMA SHM alloc failure\n",
+		       pci_name(pdev));
+		goto err_out_iounmap;
+	}
+
+	q = blk_init_queue(carm_oob_rq_fn, &host->lock);
+	if (!q) {
+		printk(KERN_ERR DRV_NAME "(%s): OOB queue alloc failure\n",
+		       pci_name(pdev));
+		rc = -ENOMEM;
+		goto err_out_pci_free;
+	}
+	host->oob_q = q;
+	q->queuedata = host;
+
+	rc = register_blkdev(0, DRV_NAME);
+	if (rc < 0)
+		goto err_out_free_oob;
+	host->major = rc;
+
+	devfs_mk_dir(DRV_NAME);
+
+	rc = carm_init_disks(host);
+	if (rc)
+		goto err_out_blkdev_disks;
+
+	pci_set_master(pdev);
+
+	rc = request_irq(pdev->irq, carm_interrupt, SA_SHIRQ, DRV_NAME, host);
+	if (rc) {
+		printk(KERN_ERR DRV_NAME "(%s): irq alloc failure\n",
+		       pci_name(pdev));
+		goto err_out_blkdev_disks;
+	}
+
+	rc = carm_init_host(host);
+	if (rc)
+		goto err_out_free_irq;
+
+	DPRINTK("waiting for probe_sem\n");
+	down(&host->probe_sem);
+
+	/* TODO: wait for probing to end */
+
+	printk(KERN_ERR DRV_NAME "(%s): registered host, %d ports, mmio %lx\n",
+	       pci_name(pdev), (int) CARM_MAX_PORTS,
+	       pci_resource_start(pdev, 0));
+	carm_host_id++;
+	pci_set_drvdata(pdev, host);
+	return 0;
+
+err_out_free_irq:
+	free_irq(pdev->irq, host);
+err_out_blkdev_disks:
+	carm_free_disks(host);
+	unregister_blkdev(host->major, DRV_NAME);
+err_out_free_oob:
+	blk_cleanup_queue(host->oob_q);
+err_out_pci_free:
+	pci_free_consistent(pdev, CARM_SHM_SIZE, host->shm, host->shm_dma);
+err_out_iounmap:
+	iounmap(host->mmio);
+err_out_kfree:
+	kfree(host);
+err_out_regions:
+	pci_release_regions(pdev);
+err_out:
+	pci_disable_device(pdev);
+	return rc;
+}
+
+static void carm_remove_one (struct pci_dev *pdev)
+{
+	struct carm_host *host = pci_get_drvdata(pdev);
+
+	if (!host) {
+		printk(KERN_ERR PFX "BUG: no host data for PCI(%s)\n",
+		       pci_name(pdev));
+		return;
+	}
+
+	free_irq(pdev->irq, host);
+	carm_free_disks(host);
+	devfs_remove(DRV_NAME);
+	unregister_blkdev(host->major, DRV_NAME);
+	blk_cleanup_queue(host->oob_q);
+	pci_free_consistent(pdev, CARM_SHM_SIZE, host->shm, host->shm_dma);
+	iounmap(host->mmio);
+	kfree(host);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+}
+
+static int __init carm_init(void)
+{
+	return pci_module_init(&carm_driver);
+}
+
+static void __exit carm_exit(void)
+{
+	pci_unregister_driver(&carm_driver);
+}
+
+module_init(carm_init);
+module_exit(carm_exit);
+
+
--- diff/drivers/block/cfq-iosched.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/block/cfq-iosched.c	2004-03-16 09:37:58.343670584 +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/char/drm/drm_irq.h	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/char/drm/drm_irq.h	2004-03-16 09:37:58.344670432 +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 00:00:00.000000000 +0000
+++ source/drivers/char/ipmi/ipmi_bt_sm.c	2004-03-16 09:37:58.346670128 +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 00:00:00.000000000 +0000
+++ source/drivers/char/ipmi/ipmi_si_intf.c	2004-03-16 09:37:58.352669216 +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 00:00:00.000000000 +0000
+++ source/drivers/char/ipmi/ipmi_si_sm.h	2004-03-16 09:37:58.352669216 +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 00:00:00.000000000 +0000
+++ source/drivers/char/ipmi/ipmi_smb.c	2004-03-16 09:37:58.355668760 +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 00:00:00.000000000 +0000
+++ source/drivers/char/ipmi/ipmi_smic_sm.c	2004-03-16 09:37:58.357668456 +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/i2c/busses/i2c-ixp42x.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/i2c/busses/i2c-ixp42x.c	2004-03-16 09:37:58.358668304 +0000
@@ -0,0 +1,180 @@
+/*
+ * drivers/i2c/i2c-adap-ixp42x.c
+ *
+ * Intel's IXP42x XScale NPU chipsets (IXP420, 421, 422, 425) do not have
+ * an on board I2C controller but provide 16 GPIO pins that are often
+ * used to create an I2C bus. This driver provides an i2c_adapter 
+ * interface that plugs in under algo_bit and drives the GPIO pins
+ * as instructed by the alogorithm driver.
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright (c) 2003-2004 MontaVista Software Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public 
+ * License version 2. This program is licensed "as is" without any 
+ * warranty of any kind, whether express or implied.
+ *
+ * NOTE: Since different platforms will use different GPIO pins for
+ *       I2C, this driver uses an IXP42x-specific platform_data
+ *       pointer to pass the GPIO numbers to the driver. This 
+ *       allows us to support all the different IXP42x platforms
+ *       w/o having to put #ifdefs in this driver.
+ *
+ *       See arch/arm/mach-ixp42x/ixdp425.c for an example of building a 
+ *       device list and filling in the ixp42x_i2c_pins data structure 
+ *       that is passed as the platform_data to this driver.
+ */
+
+#include <linux/config.h>
+#ifdef CONFIG_I2C_DEBUG_BUS
+#define DEBUG	1
+#endif
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+
+#include <asm/hardware.h>	/* Pick up IXP42x-specific bits */
+
+static inline int ixp42x_scl_pin(void *data)
+{
+	return ((struct ixp42x_i2c_pins*)data)->scl_pin;
+}
+
+static inline int ixp42x_sda_pin(void *data)
+{
+	return ((struct ixp42x_i2c_pins*)data)->sda_pin;
+}
+
+static void ixp42x_bit_setscl(void *data, int val)
+{
+	gpio_line_set(ixp42x_scl_pin(data), 0);
+	gpio_line_config(ixp42x_scl_pin(data),
+		val ? IXP425_GPIO_IN : IXP425_GPIO_OUT );
+}
+
+static void ixp42x_bit_setsda(void *data, int val)
+{
+	gpio_line_set(ixp42x_sda_pin(data), 0);
+	gpio_line_config(ixp42x_sda_pin(data),
+		val ? IXP425_GPIO_IN : IXP425_GPIO_OUT );
+}
+
+static int ixp42x_bit_getscl(void *data)
+{
+	int scl;
+
+	gpio_line_config(ixp42x_scl_pin(data), IXP425_GPIO_IN );
+	gpio_line_get(ixp42x_scl_pin(data), &scl);
+
+	return scl;
+}	
+
+static int ixp42x_bit_getsda(void *data)
+{
+	int sda;
+
+	gpio_line_config(ixp42x_sda_pin(data), IXP425_GPIO_IN );
+	gpio_line_get(ixp42x_sda_pin(data), &sda);
+
+	return sda;
+}	
+
+struct ixp42x_i2c_data {
+	struct ixp42x_i2c_pins *gpio_pins;
+	struct i2c_adapter adapter;
+	struct i2c_algo_bit_data algo_data;
+};
+
+static int ixp42x_i2c_remove(struct device *dev)
+{
+	struct platform_device *plat_dev = to_platform_device(dev);
+	struct ixp42x_i2c_data *drv_data = dev_get_drvdata(&plat_dev->dev);
+
+	dev_set_drvdata(&plat_dev->dev, NULL);
+
+	i2c_bit_del_bus(&drv_data->adapter);
+
+	kfree(drv_data);
+
+	return 0;
+}
+
+static int ixp42x_i2c_probe(struct device *dev)
+{
+	int err;
+	struct platform_device *plat_dev = to_platform_device(dev);
+	struct ixp42x_i2c_pins *gpio = plat_dev->dev.platform_data;
+	struct ixp42x_i2c_data *drv_data = 
+		kmalloc(sizeof(struct ixp42x_i2c_data), GFP_KERNEL);
+
+	if(!drv_data)
+		return -ENOMEM;
+
+	memzero(drv_data, sizeof(struct ixp42x_i2c_data));
+	drv_data->gpio_pins = gpio;
+
+	/*
+	 * We could make a lot of these structures static, but
+	 * certain platforms may have multiple GPIO-based I2C
+	 * buses for various device domains, so we need per-device
+	 * algo_data->data. 
+	 */
+	drv_data->algo_data.data = gpio;
+	drv_data->algo_data.setsda = ixp42x_bit_setsda;
+	drv_data->algo_data.setscl = ixp42x_bit_setscl;
+	drv_data->algo_data.getsda = ixp42x_bit_getsda;
+	drv_data->algo_data.getscl = ixp42x_bit_getscl;
+	drv_data->algo_data.udelay = 10;
+	drv_data->algo_data.mdelay = 10;
+	drv_data->algo_data.timeout = 100;
+
+	drv_data->adapter.id = I2C_HW_B_IXP425,
+	drv_data->adapter.algo_data = &drv_data->algo_data,
+
+	drv_data->adapter.dev.parent = &plat_dev->dev;
+
+	gpio_line_config(gpio->scl_pin, IXP425_GPIO_IN);
+	gpio_line_config(gpio->sda_pin, IXP425_GPIO_IN);
+	gpio_line_set(gpio->scl_pin, 0);
+	gpio_line_set(gpio->sda_pin, 0);
+
+	if ((err = i2c_bit_add_bus(&drv_data->adapter) != 0)) {
+		printk(KERN_ERR "ERROR: Could not install %s\n", dev->bus_id);
+
+		kfree(drv_data);
+		return err;
+	}
+
+	dev_set_drvdata(&plat_dev->dev, drv_data);
+
+	return 0;
+}
+
+static struct device_driver ixp42x_i2c_driver = {
+	.name		= "IXP42X-I2C",
+	.bus		= &platform_bus_type,
+	.probe		= ixp42x_i2c_probe,
+	.remove		= ixp42x_i2c_remove,
+};
+
+static int __init ixp42x_i2c_init(void)
+{
+	return driver_register(&ixp42x_i2c_driver);
+}
+
+static void __exit ixp42x_i2c_exit(void)
+{
+	driver_unregister(&ixp42x_i2c_driver);
+}
+
+module_init(ixp42x_i2c_init);
+module_exit(ixp42x_i2c_exit);
+
+MODULE_DESCRIPTION("GPIO-based I2C driver for IXP42x systems");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
+
--- diff/drivers/i2c/chips/lm80.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/i2c/chips/lm80.c	2004-03-16 09:37:58.359668152 +0000
@@ -0,0 +1,558 @@
+/*
+ * lm80.c - From lm_sensors, Linux kernel modules for hardware
+ * monitoring
+ * Copyright (C) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+ * and Philip Edelbrock <phil@netroedge.com>
+ *
+ * Ported to Linux 2.6 by Tiago Sousa <mirage@kaotik.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#ifdef CONFIG_I2C_DEBUG_CHIP
+#define DEBUG	1
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { 0x28, 0x2f, I2C_CLIENT_END };
+static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
+static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };
+
+/* Insmod parameters */
+SENSORS_INSMOD_1(lm80);
+
+/* Many LM80 constants specified below */
+
+/* The LM80 registers */
+#define LM80_REG_IN_MAX(nr)		(0x2a + (nr) * 2)
+#define LM80_REG_IN_MIN(nr)		(0x2b + (nr) * 2)
+#define LM80_REG_IN(nr)			(0x20 + (nr))
+
+#define LM80_REG_FAN1_MIN		0x3c
+#define LM80_REG_FAN2_MIN		0x3d
+#define LM80_REG_FAN1			0x28
+#define LM80_REG_FAN2			0x29
+
+#define LM80_REG_TEMP			0x27
+#define LM80_REG_TEMP_HOT_MAX		0x38
+#define LM80_REG_TEMP_HOT_HYST		0x39
+#define LM80_REG_TEMP_OS_MAX		0x3a
+#define LM80_REG_TEMP_OS_HYST		0x3b
+
+#define LM80_REG_CONFIG			0x00
+#define LM80_REG_ALARM1			0x01
+#define LM80_REG_ALARM2			0x02
+#define LM80_REG_MASK1			0x03
+#define LM80_REG_MASK2			0x04
+#define LM80_REG_FANDIV			0x05
+#define LM80_REG_RES			0x06
+
+
+/* Conversions. Rounding and limit checking is only done on the TO_REG
+   variants. Note that you should be a bit careful with which arguments
+   these macros are called: arguments may be evaluated more than once.
+   Fixing this is just not worth it. */
+
+#define IN_TO_REG(val)		(SENSORS_LIMIT((val)/10,0,255))
+#define IN_FROM_REG(val)	((val)*10)
+
+static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div)
+{
+	if (rpm == 0)
+		return 255;
+	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
+	return SENSORS_LIMIT((1350000 + rpm*div / 2) / (rpm*div), 1, 254);
+}
+
+#define FAN_FROM_REG(val,div)	((val)==0?-1:\
+				(val)==255?0:1350000/((div)*(val)))
+
+static inline long TEMP_FROM_REG(u16 temp)
+{
+	long res;
+
+	temp >>= 4;
+	if (temp < 0x0800)
+		res = 625 * (long) temp;
+	else
+		res = ((long) temp - 0x01000) * 625;
+
+	return res / 10;
+}
+
+#define TEMP_LIMIT_FROM_REG(val)	(((val)>0x80?(val)-0x100:(val))*1000)
+
+#define TEMP_LIMIT_TO_REG(val)		SENSORS_LIMIT((val)<0?\
+					((val)-500)/1000:((val)+500)/1000,0,255)
+
+#define ALARMS_FROM_REG(val)		(val)
+
+#define DIV_FROM_REG(val)		(1 << (val))
+#define DIV_TO_REG(val)			((val)==8?3:(val)==4?2:(val)==1?0:1)
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct lm80_data {
+	struct semaphore update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	u8 in[7];		/* Register value */
+	u8 in_max[7];		/* Register value */
+	u8 in_min[7];		/* Register value */
+	u8 fan[2];		/* Register value */
+	u8 fan_min[2];		/* Register value */
+	u8 fan_div[2];		/* Register encoding, shifted right */
+	u16 temp;		/* Register values, shifted right */
+	u8 temp_hot_max;	/* Register value */
+	u8 temp_hot_hyst;	/* Register value */
+	u8 temp_os_max;		/* Register value */
+	u8 temp_os_hyst;	/* Register value */
+	u16 alarms;		/* Register encoding, combined */
+};
+
+/* 
+ * Functions declaration
+ */
+
+static int lm80_attach_adapter(struct i2c_adapter *adapter);
+static int lm80_detect(struct i2c_adapter *adapter, int address, int kind);
+static void lm80_init_client(struct i2c_client *client);
+static int lm80_detach_client(struct i2c_client *client);
+static struct lm80_data *lm80_update_device(struct device *dev);
+static int lm80_read_value(struct i2c_client *client, u8 reg);
+static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value);
+
+/*
+ * Internal variables
+ */
+
+static int lm80_id = 0;
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static struct i2c_driver lm80_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "lm80",
+	.id		= I2C_DRIVERID_LM80,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= lm80_attach_adapter,
+	.detach_client	= lm80_detach_client,
+};
+
+/*
+ * Sysfs stuff
+ */
+
+#define show_in(suffix, value) \
+static ssize_t show_in_##suffix(struct device *dev, char *buf) \
+{ \
+	struct lm80_data *data = lm80_update_device(dev); \
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->value)); \
+}
+show_in(min0, in_min[0]);
+show_in(min1, in_min[1]);
+show_in(min2, in_min[2]);
+show_in(min3, in_min[3]);
+show_in(min4, in_min[4]);
+show_in(min5, in_min[5]);
+show_in(min6, in_min[6]);
+show_in(max0, in_max[0]);
+show_in(max1, in_max[1]);
+show_in(max2, in_max[2]);
+show_in(max3, in_max[3]);
+show_in(max4, in_max[4]);
+show_in(max5, in_max[5]);
+show_in(max6, in_max[6]);
+show_in(input0, in[0]);
+show_in(input1, in[1]);
+show_in(input2, in[2]);
+show_in(input3, in[3]);
+show_in(input4, in[4]);
+show_in(input5, in[5]);
+show_in(input6, in[6]);
+
+#define set_in(suffix, value, reg) \
+static ssize_t set_in_##suffix(struct device *dev, const char *buf, \
+	size_t count) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct lm80_data *data = i2c_get_clientdata(client); \
+	long val = simple_strtol(buf, NULL, 10); \
+	data->value = IN_TO_REG(val); \
+	lm80_write_value(client, reg, data->value); \
+	return count; \
+}
+set_in(min0, in_min[0], LM80_REG_IN_MIN(0));
+set_in(min1, in_min[1], LM80_REG_IN_MIN(1));
+set_in(min2, in_min[2], LM80_REG_IN_MIN(2));
+set_in(min3, in_min[3], LM80_REG_IN_MIN(3));
+set_in(min4, in_min[4], LM80_REG_IN_MIN(4));
+set_in(min5, in_min[5], LM80_REG_IN_MIN(5));
+set_in(min6, in_min[6], LM80_REG_IN_MIN(6));
+set_in(max0, in_max[0], LM80_REG_IN_MAX(0));
+set_in(max1, in_max[1], LM80_REG_IN_MAX(1));
+set_in(max2, in_max[2], LM80_REG_IN_MAX(2));
+set_in(max3, in_max[3], LM80_REG_IN_MAX(3));
+set_in(max4, in_max[4], LM80_REG_IN_MAX(4));
+set_in(max5, in_max[5], LM80_REG_IN_MAX(5));
+set_in(max6, in_max[6], LM80_REG_IN_MAX(6));
+
+#define show_fan(suffix, value, div) \
+static ssize_t show_fan_##suffix(struct device *dev, char *buf) \
+{ \
+	struct lm80_data *data = lm80_update_device(dev); \
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->value, \
+		       DIV_FROM_REG(data->div))); \
+}
+show_fan(min1, fan_min[0], fan_div[0]);
+show_fan(min2, fan_min[1], fan_div[1]);
+show_fan(input1, fan[0], fan_div[0]);
+show_fan(input2, fan[1], fan_div[1]);
+
+#define show_fan_div(suffix, value) \
+static ssize_t show_fan_div##suffix(struct device *dev, char *buf) \
+{ \
+	struct lm80_data *data = lm80_update_device(dev); \
+	return sprintf(buf, "%d\n", DIV_FROM_REG(data->value)); \
+}
+show_fan_div(1, fan_div[0]);
+show_fan_div(2, fan_div[1]);
+
+#define set_fan(suffix, value, reg, div) \
+static ssize_t set_fan_##suffix(struct device *dev, const char *buf, \
+	size_t count) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct lm80_data *data = i2c_get_clientdata(client); \
+	long val = simple_strtoul(buf, NULL, 10); \
+	data->value = FAN_TO_REG(val, DIV_FROM_REG(data->div)); \
+	lm80_write_value(client, reg, data->value); \
+	return count; \
+}
+set_fan(min1, fan_min[0], LM80_REG_FAN1_MIN, fan_div[0]);
+set_fan(min2, fan_min[1], LM80_REG_FAN2_MIN, fan_div[1]);
+
+static ssize_t show_temp_input1(struct device *dev, char *buf)
+{
+	struct lm80_data *data = lm80_update_device(dev);
+	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp));
+}
+
+#define show_temp(suffix, value) \
+static ssize_t show_temp_##suffix(struct device *dev, char *buf) \
+{ \
+	struct lm80_data *data = lm80_update_device(dev); \
+	return sprintf(buf, "%d\n", TEMP_LIMIT_FROM_REG(data->value)); \
+}
+show_temp(hot_max, temp_hot_max);
+show_temp(hot_hyst, temp_hot_hyst);
+show_temp(os_max, temp_os_max);
+show_temp(os_hyst, temp_os_hyst);
+
+#define set_temp(suffix, value, reg) \
+static ssize_t set_temp_##suffix(struct device *dev, const char *buf, \
+	size_t count) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct lm80_data *data = i2c_get_clientdata(client); \
+	long val = simple_strtoul(buf, NULL, 10); \
+	data->value = TEMP_LIMIT_TO_REG(val); \
+	lm80_write_value(client, reg, data->value); \
+	return count; \
+}
+set_temp(hot_max, temp_hot_max, LM80_REG_TEMP_HOT_MAX);
+set_temp(hot_hyst, temp_hot_hyst, LM80_REG_TEMP_HOT_HYST);
+set_temp(os_max, temp_os_max, LM80_REG_TEMP_OS_MAX);
+set_temp(os_hyst, temp_os_hyst, LM80_REG_TEMP_OS_HYST);
+
+static ssize_t show_alarms(struct device *dev, char *buf)
+{
+	struct lm80_data *data = lm80_update_device(dev);
+	return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms));
+}
+
+static DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min0, set_in_min0);
+static DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min1, set_in_min1);
+static DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min2, set_in_min2);
+static DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min3, set_in_min3);
+static DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min4, set_in_min4);
+static DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min5, set_in_min5);
+static DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min6, set_in_min6);
+static DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max0, set_in_max0);
+static DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max1, set_in_max1);
+static DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max2, set_in_max2);
+static DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max3, set_in_max3);
+static DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max4, set_in_max4);
+static DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max5, set_in_max5);
+static DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max6, set_in_max6);
+static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input0, NULL);
+static DEVICE_ATTR(in1_input, S_IRUGO, show_in_input1, NULL);
+static DEVICE_ATTR(in2_input, S_IRUGO, show_in_input2, NULL);
+static DEVICE_ATTR(in3_input, S_IRUGO, show_in_input3, NULL);
+static DEVICE_ATTR(in4_input, S_IRUGO, show_in_input4, NULL);
+static DEVICE_ATTR(in5_input, S_IRUGO, show_in_input5, NULL);
+static DEVICE_ATTR(in6_input, S_IRUGO, show_in_input6, NULL);
+static DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min1,
+    set_fan_min1);
+static DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min2,
+    set_fan_min2);
+static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input1, NULL);
+static DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input2, NULL);
+static DEVICE_ATTR(fan1_div, S_IRUGO, show_fan_div1, NULL);
+static DEVICE_ATTR(fan2_div, S_IRUGO, show_fan_div2, NULL);
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL);
+static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_hot_max,
+    set_temp_hot_max);
+static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hot_hyst,
+    set_temp_hot_hyst);
+static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_os_max,
+    set_temp_os_max);
+static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_os_hyst,
+    set_temp_os_hyst);
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+/*
+ * Real code
+ */
+
+static int lm80_attach_adapter(struct i2c_adapter *adapter)
+{
+	if (!(adapter->class & I2C_ADAP_CLASS_SMBUS))
+		return 0;
+	return i2c_detect(adapter, &addr_data, lm80_detect);
+}
+
+int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	int i, cur;
+	struct i2c_client *new_client;
+	struct lm80_data *data;
+	int err = 0;
+	const char *name;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		goto exit;
+
+	/* OK. For now, we presume we have a valid client. We now create the
+	   client structure, even though we cannot fill it completely yet.
+	   But it allows us to access lm80_{read,write}_value. */
+	if (!(new_client = kmalloc(sizeof(struct i2c_client) +
+	    sizeof(struct lm80_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	memset(new_client, 0x00, sizeof(struct i2c_client) +
+	       sizeof(struct lm80_data));
+
+	data = (struct lm80_data *) (new_client + 1);
+	i2c_set_clientdata(new_client, data);
+	new_client->addr = address;
+	new_client->adapter = adapter;
+	new_client->driver = &lm80_driver;
+	new_client->flags = 0;
+
+	/* Now, we do the remaining detection. It is lousy. */
+	if (lm80_read_value(new_client, LM80_REG_ALARM2) & 0xc0)
+		goto error_free;
+	for (i = 0x2a; i <= 0x3d; i++) {
+		cur = i2c_smbus_read_byte_data(new_client, i);
+		if ((i2c_smbus_read_byte_data(new_client, i + 0x40) != cur)
+		 || (i2c_smbus_read_byte_data(new_client, i + 0x80) != cur)
+		 || (i2c_smbus_read_byte_data(new_client, i + 0xc0) != cur))
+		    goto error_free;
+	}
+
+	/* Determine the chip type - only one kind supported! */
+	kind = lm80;
+	name = "lm80";
+
+	/* Fill in the remaining client fields and put it into the global list */
+	strlcpy(new_client->name, name, I2C_NAME_SIZE);
+
+	new_client->id = lm80_id++;
+	data->valid = 0;
+	init_MUTEX(&data->update_lock);
+
+	/* Tell the I2C layer a new client has arrived */
+	if ((err = i2c_attach_client(new_client)))
+		goto error_free;
+
+	/* Initialize the LM80 chip */
+	lm80_init_client(new_client);
+
+	/* Register sysfs hooks */
+	device_create_file(&new_client->dev, &dev_attr_in0_min);
+	device_create_file(&new_client->dev, &dev_attr_in1_min);
+	device_create_file(&new_client->dev, &dev_attr_in2_min);
+	device_create_file(&new_client->dev, &dev_attr_in3_min);
+	device_create_file(&new_client->dev, &dev_attr_in4_min);
+	device_create_file(&new_client->dev, &dev_attr_in5_min);
+	device_create_file(&new_client->dev, &dev_attr_in6_min);
+	device_create_file(&new_client->dev, &dev_attr_in0_max);
+	device_create_file(&new_client->dev, &dev_attr_in1_max);
+	device_create_file(&new_client->dev, &dev_attr_in2_max);
+	device_create_file(&new_client->dev, &dev_attr_in3_max);
+	device_create_file(&new_client->dev, &dev_attr_in4_max);
+	device_create_file(&new_client->dev, &dev_attr_in5_max);
+	device_create_file(&new_client->dev, &dev_attr_in6_max);
+	device_create_file(&new_client->dev, &dev_attr_in0_input);
+	device_create_file(&new_client->dev, &dev_attr_in1_input);
+	device_create_file(&new_client->dev, &dev_attr_in2_input);
+	device_create_file(&new_client->dev, &dev_attr_in3_input);
+	device_create_file(&new_client->dev, &dev_attr_in4_input);
+	device_create_file(&new_client->dev, &dev_attr_in5_input);
+	device_create_file(&new_client->dev, &dev_attr_in6_input);
+	device_create_file(&new_client->dev, &dev_attr_fan1_min);
+	device_create_file(&new_client->dev, &dev_attr_fan2_min);
+	device_create_file(&new_client->dev, &dev_attr_fan1_input);
+	device_create_file(&new_client->dev, &dev_attr_fan2_input);
+	device_create_file(&new_client->dev, &dev_attr_fan1_div);
+	device_create_file(&new_client->dev, &dev_attr_fan2_div);
+	device_create_file(&new_client->dev, &dev_attr_temp1_input);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
+	device_create_file(&new_client->dev, &dev_attr_temp1_crit);
+	device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
+	device_create_file(&new_client->dev, &dev_attr_alarms);
+
+	return 0;
+
+error_free:
+	kfree(new_client);
+exit:
+	return err;
+}
+
+static int lm80_detach_client(struct i2c_client *client)
+{
+	int err;
+
+	if ((err = i2c_detach_client(client))) {
+		dev_err(&client->dev, "Client deregistration failed, "
+			"client not detached.\n");
+		return err;
+	}
+
+	kfree(client);
+	return 0;
+}
+
+static int lm80_read_value(struct i2c_client *client, u8 reg)
+{
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value)
+{
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/* Called when we have found a new LM80. */
+static void lm80_init_client(struct i2c_client *client)
+{
+	/* Reset all except Watchdog values and last conversion values
+	   This sets fan-divs to 2, among others. This makes most other
+	   initializations unnecessary */
+	lm80_write_value(client, LM80_REG_CONFIG, 0x80);
+	/* Set 11-bit temperature resolution */
+	lm80_write_value(client, LM80_REG_RES, 0x08);
+
+	/* Start monitoring */
+	lm80_write_value(client, LM80_REG_CONFIG, 0x01);
+}
+
+static struct lm80_data *lm80_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm80_data *data = i2c_get_clientdata(client);
+	int i;
+
+	down(&data->update_lock);
+
+	if ((jiffies - data->last_updated > 2 * HZ) ||
+	    (jiffies < data->last_updated) || !data->valid) {
+
+		dev_dbg(&client->dev, "Starting lm80 update\n");
+		for (i = 0; i <= 6; i++) {
+			data->in[i] =
+			    lm80_read_value(client, LM80_REG_IN(i));
+			data->in_min[i] =
+			    lm80_read_value(client, LM80_REG_IN_MIN(i));
+			data->in_max[i] =
+			    lm80_read_value(client, LM80_REG_IN_MAX(i));
+		}
+		data->fan[0] = lm80_read_value(client, LM80_REG_FAN1);
+		data->fan_min[0] =
+		    lm80_read_value(client, LM80_REG_FAN1_MIN);
+		data->fan[1] = lm80_read_value(client, LM80_REG_FAN2);
+		data->fan_min[1] =
+		    lm80_read_value(client, LM80_REG_FAN2_MIN);
+
+		data->temp =
+		    (lm80_read_value(client, LM80_REG_TEMP) << 8) |
+		    (lm80_read_value(client, LM80_REG_RES) & 0xf0);
+		data->temp_os_max =
+		    lm80_read_value(client, LM80_REG_TEMP_OS_MAX);
+		data->temp_os_hyst =
+		    lm80_read_value(client, LM80_REG_TEMP_OS_HYST);
+		data->temp_hot_max =
+		    lm80_read_value(client, LM80_REG_TEMP_HOT_MAX);
+		data->temp_hot_hyst =
+		    lm80_read_value(client, LM80_REG_TEMP_HOT_HYST);
+
+		i = lm80_read_value(client, LM80_REG_FANDIV);
+		data->fan_div[0] = (i >> 2) & 0x03;
+		data->fan_div[1] = (i >> 4) & 0x03;
+		data->alarms = lm80_read_value(client, LM80_REG_ALARM1) +
+		    (lm80_read_value(client, LM80_REG_ALARM2) << 8);
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	up(&data->update_lock);
+
+	return data;
+}
+
+static int __init sensors_lm80_init(void)
+{
+	return i2c_add_driver(&lm80_driver);
+}
+
+static void __exit sensors_lm80_exit(void)
+{
+	i2c_del_driver(&lm80_driver);
+}
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
+	"Philip Edelbrock <phil@netroedge.com>");
+MODULE_DESCRIPTION("LM80 driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_lm80_init);
+module_exit(sensors_lm80_exit);
--- diff/drivers/i2c/chips/w83627hf.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/i2c/chips/w83627hf.c	2004-03-16 09:37:58.363667544 +0000
@@ -0,0 +1,1354 @@
+/*
+    w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware
+                monitoring
+    Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
+    Philip Edelbrock <phil@netroedge.com>,
+    and Mark Studebaker <mdsxyz123@yahoo.com>
+    Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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.
+*/
+
+/*
+    Supports following chips:
+
+    Chip	#vin	#fanin	#pwm	#temp	wchipid	vendid	i2c	ISA
+    w83627hf	9	3	2	3	0x20	0x5ca3	no	yes(LPC)
+    w83627thf	7	3	3	3	0x90	0x5ca3	no	yes(LPC)
+    w83637hf	7	3	3	3	0x80	0x5ca3	no	yes(LPC)
+    w83697hf	8	2	2	2	0x60	0x5ca3	no	yes(LPC)
+
+    For other winbond chips, and for i2c support in the above chips,
+    use w83781d.c.
+
+    Note: automatic ("cruise") fan control for 697, 637 & 627thf not
+    supported yet.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+#include <linux/i2c-vid.h>
+#include <asm/io.h>
+#include "lm75.h"
+
+static int force_addr;
+MODULE_PARM(force_addr, "i");
+MODULE_PARM_DESC(force_addr,
+		 "Initialize the base address of the sensors");
+static int force_i2c = 0x1f;
+MODULE_PARM(force_i2c, "i");
+MODULE_PARM_DESC(force_i2c,
+		 "Initialize the i2c address of the sensors");
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END };
+static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };
+
+/* Insmod parameters */
+SENSORS_INSMOD_4(w83627hf, w83627thf, w83697hf, w83637hf);
+
+static int init = 1;
+MODULE_PARM(init, "i");
+MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
+
+/* modified from kernel/include/traps.c */
+#define	REG	0x2e	/* The register to read/write */
+#define	DEV	0x07	/* Register: Logical device select */
+#define	VAL	0x2f	/* The value to read/write */
+
+/* logical device numbers for superio_select (below) */
+#define W83627HF_LD_FDC		0x00
+#define W83627HF_LD_PRT		0x01
+#define W83627HF_LD_UART1	0x02
+#define W83627HF_LD_UART2	0x03
+#define W83627HF_LD_KBC		0x05
+#define W83627HF_LD_CIR		0x06 /* w83627hf only */
+#define W83627HF_LD_GAME	0x07
+#define W83627HF_LD_MIDI	0x07
+#define W83627HF_LD_GPIO1	0x07
+#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
+#define W83627HF_LD_GPIO2	0x08
+#define W83627HF_LD_GPIO3	0x09
+#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
+#define W83627HF_LD_ACPI	0x0a
+#define W83627HF_LD_HWM		0x0b
+
+#define	DEVID	0x20	/* Register: Device ID */
+
+#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
+#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
+#define W83627THF_GPIO5_INVR	0xf5 /* w83627thf only */
+
+static inline void
+superio_outb(int reg, int val)
+{
+	outb(reg, REG);
+	outb(val, VAL);
+}
+
+static inline int
+superio_inb(int reg)
+{
+	outb(reg, REG);
+	return inb(VAL);
+}
+
+static inline void
+superio_select(int ld)
+{
+	outb(DEV, REG);
+	outb(ld, VAL);
+}
+
+static inline void
+superio_enter(void)
+{
+	outb(0x87, REG);
+	outb(0x87, REG);
+}
+
+static inline void
+superio_exit(void)
+{
+	outb(0xAA, REG);
+}
+
+#define W627_DEVID 0x52
+#define W627THF_DEVID 0x82
+#define W697_DEVID 0x60
+#define W637_DEVID 0x70
+#define WINB_ACT_REG 0x30
+#define WINB_BASE_REG 0x60
+/* Constants specified below */
+
+/* Length of ISA address segment */
+#define WINB_EXTENT 8
+
+/* Where are the ISA address/data registers relative to the base address */
+#define W83781D_ADDR_REG_OFFSET 5
+#define W83781D_DATA_REG_OFFSET 6
+
+/* The W83781D registers */
+/* The W83782D registers for nr=7,8 are in bank 5 */
+#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
+					   (0x554 + (((nr) - 7) * 2)))
+#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
+					   (0x555 + (((nr) - 7) * 2)))
+#define W83781D_REG_IN(nr)     ((nr < 7) ? (0x20 + (nr)) : \
+					   (0x550 + (nr) - 7))
+
+#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr))
+#define W83781D_REG_FAN(nr) (0x27 + (nr))
+
+#define W83781D_REG_TEMP2_CONFIG 0x152
+#define W83781D_REG_TEMP3_CONFIG 0x252
+#define W83781D_REG_TEMP(nr)		((nr == 3) ? (0x0250) : \
+					((nr == 2) ? (0x0150) : \
+					             (0x27)))
+#define W83781D_REG_TEMP_HYST(nr)	((nr == 3) ? (0x253) : \
+					((nr == 2) ? (0x153) : \
+					             (0x3A)))
+#define W83781D_REG_TEMP_OVER(nr)	((nr == 3) ? (0x255) : \
+					((nr == 2) ? (0x155) : \
+					             (0x39)))
+
+#define W83781D_REG_BANK 0x4E
+
+#define W83781D_REG_CONFIG 0x40
+#define W83781D_REG_ALARM1 0x41
+#define W83781D_REG_ALARM2 0x42
+#define W83781D_REG_ALARM3 0x450
+
+#define W83781D_REG_IRQ 0x4C
+#define W83781D_REG_BEEP_CONFIG 0x4D
+#define W83781D_REG_BEEP_INTS1 0x56
+#define W83781D_REG_BEEP_INTS2 0x57
+#define W83781D_REG_BEEP_INTS3 0x453
+
+#define W83781D_REG_VID_FANDIV 0x47
+
+#define W83781D_REG_CHIPID 0x49
+#define W83781D_REG_WCHIPID 0x58
+#define W83781D_REG_CHIPMAN 0x4F
+#define W83781D_REG_PIN 0x4B
+
+#define W83781D_REG_VBAT 0x5D
+
+#define W83627HF_REG_PWM1 0x5A
+#define W83627HF_REG_PWM2 0x5B
+#define W83627HF_REG_PWMCLK12 0x5C
+
+#define W83627THF_REG_PWM1		0x01	/* 697HF and 637HF too */
+#define W83627THF_REG_PWM2		0x03	/* 697HF and 637HF too */
+#define W83627THF_REG_PWM3		0x11	/* 637HF too */
+
+#define W83627THF_REG_VRM_OVT_CFG 	0x18	/* 637HF too, unused yet */
+
+static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };
+static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
+                             W83627THF_REG_PWM3 };
+#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
+                                     regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1])
+
+#define W83781D_REG_I2C_ADDR 0x48
+#define W83781D_REG_I2C_SUBADDR 0x4A
+
+/* Sensor selection */
+#define W83781D_REG_SCFG1 0x5D
+static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
+#define W83781D_REG_SCFG2 0x59
+static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
+#define W83781D_DEFAULT_BETA 3435
+
+/* Conversions. Limit checking is only done on the TO_REG
+   variants. Note that you should be a bit careful with which arguments
+   these macros are called: arguments may be evaluated more than once.
+   Fixing this is just not worth it. */
+#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) + 8)/16),0,255))
+#define IN_FROM_REG(val) ((val) * 16 + 5)
+
+static inline u8 FAN_TO_REG(long rpm, int div)
+{
+	if (rpm == 0)
+		return 255;
+	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
+	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
+			     254);
+}
+
+#define TEMP_MIN (-128000)
+#define TEMP_MAX ( 127000)
+
+/* TEMP: 0.001C/bit (-128C to +127C)
+   REG: 1C/bit, two's complement */
+static u8 TEMP_TO_REG(int temp)
+{
+        int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
+        ntemp += (ntemp<0 ? -500 : 500);
+        return (u8)(ntemp / 1000);
+}
+
+static int TEMP_FROM_REG(u8 reg)
+{
+        return (s8)reg * 1000;
+}
+
+#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
+
+#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
+
+#define BEEP_MASK_FROM_REG(val)		 (val)
+#define BEEP_MASK_TO_REG(val)		((val) & 0xffffff)
+#define BEEP_ENABLE_TO_REG(val)		((val)?1:0)
+#define BEEP_ENABLE_FROM_REG(val)	((val)?1:0)
+
+#define DIV_FROM_REG(val) (1 << (val))
+
+static inline u8 DIV_TO_REG(long val)
+{
+	int i;
+	val = SENSORS_LIMIT(val, 1, 128) >> 1;
+	for (i = 0; i < 6; i++) {
+		if (val == 0)
+			break;
+		val >>= 1;
+	}
+	return ((u8) i);
+}
+
+/* For each registered chip, we need to keep some data in memory. That
+   data is pointed to by w83627hf_list[NR]->data. The structure itself is
+   dynamically allocated, at the same time when a new client is allocated. */
+struct w83627hf_data {
+	struct semaphore lock;
+	enum chips type;
+
+	struct semaphore update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	struct i2c_client *lm75;	/* for secondary I2C addresses */
+	/* pointer to array of 2 subclients */
+
+	u8 in[9];		/* Register value */
+	u8 in_max[9];		/* Register value */
+	u8 in_min[9];		/* Register value */
+	u8 fan[3];		/* Register value */
+	u8 fan_min[3];		/* Register value */
+	u8 temp;
+	u8 temp_max;		/* Register value */
+	u8 temp_max_hyst;	/* Register value */
+	u16 temp_add[2];	/* Register value */
+	u16 temp_max_add[2];	/* Register value */
+	u16 temp_max_hyst_add[2]; /* Register value */
+	u8 fan_div[3];		/* Register encoding, shifted right */
+	u8 vid;			/* Register encoding, combined */
+	u32 alarms;		/* Register encoding, combined */
+	u32 beep_mask;		/* Register encoding, combined */
+	u8 beep_enable;		/* Boolean */
+	u8 pwm[3];		/* Register value */
+	u8 pwmenable[3];	/* bool */
+	u16 sens[3];		/* 782D/783S only.
+				   1 = pentium diode; 2 = 3904 diode;
+				   3000-5000 = thermistor beta.
+				   Default = 3435.
+				   Other Betas unimplemented */
+	u8 vrm;
+};
+
+
+static int w83627hf_attach_adapter(struct i2c_adapter *adapter);
+static int w83627hf_detect(struct i2c_adapter *adapter, int address,
+			  int kind);
+static int w83627hf_detach_client(struct i2c_client *client);
+
+static int w83627hf_read_value(struct i2c_client *client, u16 register);
+static int w83627hf_write_value(struct i2c_client *client, u16 register,
+			       u16 value);
+static struct w83627hf_data *w83627hf_update_device(struct device *dev);
+static void w83627hf_init_client(struct i2c_client *client);
+
+static struct i2c_driver w83627hf_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "w83627hf",
+	.id		= I2C_DRIVERID_W83627HF,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= w83627hf_attach_adapter,
+	.detach_client	= w83627hf_detach_client,
+};
+
+/* following are the sysfs callback functions */
+#define show_in_reg(reg) \
+static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
+{ \
+	struct w83627hf_data *data = w83627hf_update_device(dev); \
+	return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr])); \
+}
+show_in_reg(in)
+show_in_reg(in_min)
+show_in_reg(in_max)
+
+#define store_in_reg(REG, reg) \
+static ssize_t \
+store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct w83627hf_data *data = i2c_get_clientdata(client); \
+	u32 val; \
+	 \
+	val = simple_strtoul(buf, NULL, 10); \
+	data->in_##reg[nr] = IN_TO_REG(val); \
+	w83627hf_write_value(client, W83781D_REG_IN_##REG(nr), \
+			    data->in_##reg[nr]); \
+	 \
+	return count; \
+}
+store_in_reg(MIN, min)
+store_in_reg(MAX, max)
+
+#define sysfs_in_offset(offset) \
+static ssize_t \
+show_regs_in_##offset (struct device *dev, char *buf) \
+{ \
+        return show_in(dev, buf, 0x##offset); \
+} \
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL)
+
+#define sysfs_in_reg_offset(reg, offset) \
+static ssize_t show_regs_in_##reg##offset (struct device *dev, char *buf) \
+{ \
+	return show_in_##reg (dev, buf, 0x##offset); \
+} \
+static ssize_t \
+store_regs_in_##reg##offset (struct device *dev, \
+			    const char *buf, size_t count) \
+{ \
+	return store_in_##reg (dev, buf, count, 0x##offset); \
+} \
+static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, \
+		  show_regs_in_##reg##offset, store_regs_in_##reg##offset)
+
+#define sysfs_in_offsets(offset) \
+sysfs_in_offset(offset) \
+sysfs_in_reg_offset(min, offset) \
+sysfs_in_reg_offset(max, offset)
+
+sysfs_in_offsets(0)
+sysfs_in_offsets(1)
+sysfs_in_offsets(2)
+sysfs_in_offsets(3)
+sysfs_in_offsets(4)
+sysfs_in_offsets(5)
+sysfs_in_offsets(6)
+sysfs_in_offsets(7)
+sysfs_in_offsets(8)
+
+#define device_create_file_in(client, offset) \
+do { \
+device_create_file(&client->dev, &dev_attr_in##offset##_input); \
+device_create_file(&client->dev, &dev_attr_in##offset##_min); \
+device_create_file(&client->dev, &dev_attr_in##offset##_max); \
+} while (0)
+
+#define show_fan_reg(reg) \
+static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
+{ \
+	struct w83627hf_data *data = w83627hf_update_device(dev); \
+	return sprintf(buf,"%ld\n", \
+		FAN_FROM_REG(data->reg[nr-1], \
+			    (long)DIV_FROM_REG(data->fan_div[nr-1]))); \
+}
+show_fan_reg(fan)
+show_fan_reg(fan_min)
+
+static ssize_t
+store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83627hf_data *data = i2c_get_clientdata(client);
+	u32 val;
+
+	val = simple_strtoul(buf, NULL, 10);
+	data->fan_min[nr - 1] =
+	    FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1]));
+	w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr),
+			    data->fan_min[nr - 1]);
+
+	return count;
+}
+
+#define sysfs_fan_offset(offset) \
+static ssize_t show_regs_fan_##offset (struct device *dev, char *buf) \
+{ \
+	return show_fan(dev, buf, 0x##offset); \
+} \
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL)
+
+#define sysfs_fan_min_offset(offset) \
+static ssize_t show_regs_fan_min##offset (struct device *dev, char *buf) \
+{ \
+	return show_fan_min(dev, buf, 0x##offset); \
+} \
+static ssize_t \
+store_regs_fan_min##offset (struct device *dev, const char *buf, size_t count) \
+{ \
+	return store_fan_min(dev, buf, count, 0x##offset); \
+} \
+static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+		  show_regs_fan_min##offset, store_regs_fan_min##offset)
+
+sysfs_fan_offset(1)
+sysfs_fan_min_offset(1)
+sysfs_fan_offset(2)
+sysfs_fan_min_offset(2)
+sysfs_fan_offset(3)
+sysfs_fan_min_offset(3)
+
+#define device_create_file_fan(client, offset) \
+do { \
+device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
+device_create_file(&client->dev, &dev_attr_fan##offset##_min); \
+} while (0)
+
+#define show_temp_reg(reg) \
+static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
+{ \
+	struct w83627hf_data *data = w83627hf_update_device(dev); \
+	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
+		return sprintf(buf,"%ld\n", \
+			(long)LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
+	} else {	/* TEMP1 */ \
+		return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \
+	} \
+}
+show_temp_reg(temp)
+show_temp_reg(temp_max)
+show_temp_reg(temp_max_hyst)
+
+#define store_temp_reg(REG, reg) \
+static ssize_t \
+store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct w83627hf_data *data = i2c_get_clientdata(client); \
+	u32 val; \
+	 \
+	val = simple_strtoul(buf, NULL, 10); \
+	 \
+	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
+		data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
+		w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \
+				data->temp_##reg##_add[nr-2]); \
+	} else {	/* TEMP1 */ \
+		data->temp_##reg = TEMP_TO_REG(val); \
+		w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \
+			data->temp_##reg); \
+	} \
+	 \
+	return count; \
+}
+store_temp_reg(OVER, max)
+store_temp_reg(HYST, max_hyst)
+
+#define sysfs_temp_offset(offset) \
+static ssize_t \
+show_regs_temp_##offset (struct device *dev, char *buf) \
+{ \
+	return show_temp(dev, buf, 0x##offset); \
+} \
+static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL)
+
+#define sysfs_temp_reg_offset(reg, offset) \
+static ssize_t show_regs_temp_##reg##offset (struct device *dev, char *buf) \
+{ \
+	return show_temp_##reg (dev, buf, 0x##offset); \
+} \
+static ssize_t \
+store_regs_temp_##reg##offset (struct device *dev, \
+			      const char *buf, size_t count) \
+{ \
+	return store_temp_##reg (dev, buf, count, 0x##offset); \
+} \
+static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \
+		  show_regs_temp_##reg##offset, store_regs_temp_##reg##offset)
+
+#define sysfs_temp_offsets(offset) \
+sysfs_temp_offset(offset) \
+sysfs_temp_reg_offset(max, offset) \
+sysfs_temp_reg_offset(max_hyst, offset)
+
+sysfs_temp_offsets(1)
+sysfs_temp_offsets(2)
+sysfs_temp_offsets(3)
+
+#define device_create_file_temp(client, offset) \
+do { \
+device_create_file(&client->dev, &dev_attr_temp##offset##_input); \
+device_create_file(&client->dev, &dev_attr_temp##offset##_max); \
+device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \
+} while (0)
+
+static ssize_t
+show_vid_reg(struct device *dev, char *buf)
+{
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL)
+#define device_create_file_vid(client) \
+device_create_file(&client->dev, &dev_attr_in0_ref)
+
+static ssize_t
+show_vrm_reg(struct device *dev, char *buf)
+{
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return sprintf(buf, "%ld\n", (long) data->vrm);
+}
+static ssize_t
+store_vrm_reg(struct device *dev, const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83627hf_data *data = i2c_get_clientdata(client);
+	u32 val;
+
+	val = simple_strtoul(buf, NULL, 10);
+	data->vrm = val;
+
+	return count;
+}
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg)
+#define device_create_file_vrm(client) \
+device_create_file(&client->dev, &dev_attr_vrm)
+
+static ssize_t
+show_alarms_reg(struct device *dev, char *buf)
+{
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return sprintf(buf, "%ld\n", (long) data->alarms);
+}
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL)
+#define device_create_file_alarms(client) \
+device_create_file(&client->dev, &dev_attr_alarms)
+
+#define show_beep_reg(REG, reg) \
+static ssize_t show_beep_##reg (struct device *dev, char *buf) \
+{ \
+	struct w83627hf_data *data = w83627hf_update_device(dev); \
+	return sprintf(buf,"%ld\n", \
+		      (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \
+}
+show_beep_reg(ENABLE, enable)
+show_beep_reg(MASK, mask)
+
+#define BEEP_ENABLE			0	/* Store beep_enable */
+#define BEEP_MASK			1	/* Store beep_mask */
+
+static ssize_t
+store_beep_reg(struct device *dev, const char *buf, size_t count,
+	       int update_mask)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83627hf_data *data = i2c_get_clientdata(client);
+	u32 val, val2;
+
+	val = simple_strtoul(buf, NULL, 10);
+
+	if (update_mask == BEEP_MASK) {	/* We are storing beep_mask */
+		data->beep_mask = BEEP_MASK_TO_REG(val);
+		w83627hf_write_value(client, W83781D_REG_BEEP_INTS1,
+				    data->beep_mask & 0xff);
+		w83627hf_write_value(client, W83781D_REG_BEEP_INTS3,
+				    ((data->beep_mask) >> 16) & 0xff);
+		val2 = (data->beep_mask >> 8) & 0x7f;
+	} else {		/* We are storing beep_enable */
+		val2 =
+		    w83627hf_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f;
+		data->beep_enable = BEEP_ENABLE_TO_REG(val);
+	}
+
+	w83627hf_write_value(client, W83781D_REG_BEEP_INTS2,
+			    val2 | data->beep_enable << 7);
+
+	return count;
+}
+
+#define sysfs_beep(REG, reg) \
+static ssize_t show_regs_beep_##reg (struct device *dev, char *buf) \
+{ \
+	return show_beep_##reg(dev, buf); \
+} \
+static ssize_t \
+store_regs_beep_##reg (struct device *dev, const char *buf, size_t count) \
+{ \
+	return store_beep_reg(dev, buf, count, BEEP_##REG); \
+} \
+static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \
+		  show_regs_beep_##reg, store_regs_beep_##reg)
+
+sysfs_beep(ENABLE, enable)
+sysfs_beep(MASK, mask)
+
+#define device_create_file_beep(client) \
+do { \
+device_create_file(&client->dev, &dev_attr_beep_enable); \
+device_create_file(&client->dev, &dev_attr_beep_mask); \
+} while (0)
+
+static ssize_t
+show_fan_div_reg(struct device *dev, char *buf, int nr)
+{
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return sprintf(buf, "%ld\n",
+		       (long) DIV_FROM_REG(data->fan_div[nr - 1]));
+}
+
+static ssize_t
+store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83627hf_data *data = i2c_get_clientdata(client);
+	u32 val, old, old2, old3 = 0;
+
+	val = simple_strtoul(buf, NULL, 10);
+	old = w83627hf_read_value(client, W83781D_REG_VID_FANDIV);
+	old3 = w83627hf_read_value(client, W83781D_REG_VBAT);
+	data->fan_div[nr - 1] = DIV_TO_REG(val);
+
+	if (nr >= 3 && data->type != w83697hf) {
+		old2 = w83627hf_read_value(client, W83781D_REG_PIN);
+		old2 = (old2 & 0x3f) | ((data->fan_div[2] & 0x03) << 6);
+		w83627hf_write_value(client, W83781D_REG_PIN, old2);
+		old3 = (old3 & 0x7f) | ((data->fan_div[2] & 0x04) << 5);
+	}
+	if (nr >= 2) {
+		old = (old & 0x3f) | ((data->fan_div[1] & 0x03) << 6);
+		old3 = (old3 & 0xbf) | ((data->fan_div[1] & 0x04) << 4);
+	}
+	if (nr >= 1) {
+		old = (old & 0xcf) | ((data->fan_div[0] & 0x03) << 4);
+		w83627hf_write_value(client, W83781D_REG_VID_FANDIV, old);
+		old3 = (old3 & 0xdf) | ((data->fan_div[0] & 0x04) << 3);
+		w83627hf_write_value(client, W83781D_REG_VBAT, old3);
+	}
+
+	return count;
+}
+
+#define sysfs_fan_div(offset) \
+static ssize_t show_regs_fan_div_##offset (struct device *dev, char *buf) \
+{ \
+	return show_fan_div_reg(dev, buf, offset); \
+} \
+static ssize_t \
+store_regs_fan_div_##offset (struct device *dev, \
+			    const char *buf, size_t count) \
+{ \
+	return store_fan_div_reg(dev, buf, count, offset); \
+} \
+static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
+		  show_regs_fan_div_##offset, store_regs_fan_div_##offset)
+
+sysfs_fan_div(1)
+sysfs_fan_div(2)
+sysfs_fan_div(3)
+
+#define device_create_file_fan_div(client, offset) \
+do { \
+device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
+} while (0)
+
+static ssize_t
+show_pwm_reg(struct device *dev, char *buf, int nr)
+{
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return sprintf(buf, "%ld\n", (long) data->pwm[nr - 1]);
+}
+
+static ssize_t
+store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83627hf_data *data = i2c_get_clientdata(client);
+	u32 val;
+
+	val = simple_strtoul(buf, NULL, 10);
+
+	if (data->type == w83627thf) {
+		/* bits 0-3 are reserved  in 627THF */
+		data->pwm[nr - 1] = PWM_TO_REG(val) & 0xf0;
+		w83627hf_write_value(client,
+				     W836X7HF_REG_PWM(data->type, nr),
+				     data->pwm[nr - 1] |
+				     (w83627hf_read_value(client,
+				     W836X7HF_REG_PWM(data->type, nr)) & 0x0f));
+	} else {
+		data->pwm[nr - 1] = PWM_TO_REG(val);
+		w83627hf_write_value(client,
+				     W836X7HF_REG_PWM(data->type, nr),
+				     data->pwm[nr - 1]);
+	}
+
+	return count;
+}
+
+#define sysfs_pwm(offset) \
+static ssize_t show_regs_pwm_##offset (struct device *dev, char *buf) \
+{ \
+	return show_pwm_reg(dev, buf, offset); \
+} \
+static ssize_t \
+store_regs_pwm_##offset (struct device *dev, const char *buf, size_t count) \
+{ \
+	return store_pwm_reg(dev, buf, count, offset); \
+} \
+static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, \
+		  show_regs_pwm_##offset, store_regs_pwm_##offset)
+
+sysfs_pwm(1)
+sysfs_pwm(2)
+sysfs_pwm(3)
+
+#define device_create_file_pwm(client, offset) \
+do { \
+device_create_file(&client->dev, &dev_attr_fan##offset##_pwm); \
+} while (0)
+
+static ssize_t
+show_sensor_reg(struct device *dev, char *buf, int nr)
+{
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]);
+}
+
+static ssize_t
+store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83627hf_data *data = i2c_get_clientdata(client);
+	u32 val, tmp;
+
+	val = simple_strtoul(buf, NULL, 10);
+
+	switch (val) {
+	case 1:		/* PII/Celeron diode */
+		tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
+		w83627hf_write_value(client, W83781D_REG_SCFG1,
+				    tmp | BIT_SCFG1[nr - 1]);
+		tmp = w83627hf_read_value(client, W83781D_REG_SCFG2);
+		w83627hf_write_value(client, W83781D_REG_SCFG2,
+				    tmp | BIT_SCFG2[nr - 1]);
+		data->sens[nr - 1] = val;
+		break;
+	case 2:		/* 3904 */
+		tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
+		w83627hf_write_value(client, W83781D_REG_SCFG1,
+				    tmp | BIT_SCFG1[nr - 1]);
+		tmp = w83627hf_read_value(client, W83781D_REG_SCFG2);
+		w83627hf_write_value(client, W83781D_REG_SCFG2,
+				    tmp & ~BIT_SCFG2[nr - 1]);
+		data->sens[nr - 1] = val;
+		break;
+	case W83781D_DEFAULT_BETA:	/* thermistor */
+		tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
+		w83627hf_write_value(client, W83781D_REG_SCFG1,
+				    tmp & ~BIT_SCFG1[nr - 1]);
+		data->sens[nr - 1] = val;
+		break;
+	default:
+		dev_err(&client->dev,
+		       "Invalid sensor type %ld; must be 1, 2, or %d\n",
+		       (long) val, W83781D_DEFAULT_BETA);
+		break;
+	}
+
+	return count;
+}
+
+#define sysfs_sensor(offset) \
+static ssize_t show_regs_sensor_##offset (struct device *dev, char *buf) \
+{ \
+    return show_sensor_reg(dev, buf, offset); \
+} \
+static ssize_t \
+store_regs_sensor_##offset (struct device *dev, const char *buf, size_t count) \
+{ \
+    return store_sensor_reg(dev, buf, count, offset); \
+} \
+static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
+		  show_regs_sensor_##offset, store_regs_sensor_##offset)
+
+sysfs_sensor(1)
+sysfs_sensor(2)
+sysfs_sensor(3)
+
+#define device_create_file_sensor(client, offset) \
+do { \
+device_create_file(&client->dev, &dev_attr_temp##offset##_type); \
+} while (0)
+
+
+/* This function is called when:
+     * w83627hf_driver is inserted (when this module is loaded), for each
+       available adapter
+     * when a new adapter is inserted (and w83627hf_driver is still present) */
+static int w83627hf_attach_adapter(struct i2c_adapter *adapter)
+{
+	return i2c_detect(adapter, &addr_data, w83627hf_detect);
+}
+
+static int w83627hf_find(int *address)
+{
+	u16 val;
+
+	superio_enter();
+	val= superio_inb(DEVID);
+	if(val != W627_DEVID &&
+	   val != W627THF_DEVID &&
+	   val != W697_DEVID &&
+	   val != W637_DEVID) {
+		superio_exit();
+		return -ENODEV;
+	}
+
+	superio_select(W83627HF_LD_HWM);
+	val = (superio_inb(WINB_BASE_REG) << 8) |
+	       superio_inb(WINB_BASE_REG + 1);
+	*address = val & ~(WINB_EXTENT - 1);
+	if (*address == 0 && force_addr == 0) {
+		superio_exit();
+		return -ENODEV;
+	}
+	if (force_addr)
+		*address = force_addr;	/* so detect will get called */
+
+	superio_exit();
+	return 0;
+}
+
+int w83627hf_detect(struct i2c_adapter *adapter, int address,
+		   int kind)
+{
+	int val;
+	struct i2c_client *new_client;
+	struct w83627hf_data *data;
+	int err = 0;
+	const char *client_name = "";
+
+	if (!i2c_is_isa_adapter(adapter)) {
+		err = -ENODEV;
+		goto ERROR0;
+	}
+
+	if(force_addr)
+		address = force_addr & ~(WINB_EXTENT - 1);
+
+	if (!request_region(address, WINB_EXTENT, "w83627hf")) {
+		err = -EBUSY;
+		goto ERROR0;
+	}
+
+	if(force_addr) {
+		printk("w83627hf.o: forcing ISA address 0x%04X\n", address);
+		superio_enter();
+		superio_select(W83627HF_LD_HWM);
+		superio_outb(WINB_BASE_REG, address >> 8);
+		superio_outb(WINB_BASE_REG+1, address & 0xff);
+		superio_exit();
+	}
+
+	superio_enter();
+	val= superio_inb(DEVID);
+	if(val == W627_DEVID)
+		kind = w83627hf;
+	else if(val == W697_DEVID)
+		kind = w83697hf;
+	else if(val == W627THF_DEVID)
+		kind = w83627thf;
+	else if(val == W637_DEVID)
+		kind = w83637hf;
+
+	superio_select(W83627HF_LD_HWM);
+	if((val = 0x01 & superio_inb(WINB_ACT_REG)) == 0)
+		superio_outb(WINB_ACT_REG, 1);
+	superio_exit();
+
+	/* OK. For now, we presume we have a valid client. We now create the
+	   client structure, even though we cannot fill it completely yet.
+	   But it allows us to access w83627hf_{read,write}_value. */
+
+	if (!(new_client = kmalloc(sizeof(struct i2c_client) +
+				   sizeof(struct w83627hf_data),
+				   GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto ERROR1;
+	}
+
+	memset(new_client, 0x00, sizeof (struct i2c_client) +
+	       sizeof (struct w83627hf_data));
+
+	data = (struct w83627hf_data *) (new_client + 1);
+	i2c_set_clientdata(new_client, data);
+	new_client->addr = address;
+	init_MUTEX(&data->lock);
+	new_client->adapter = adapter;
+	new_client->driver = &w83627hf_driver;
+	new_client->flags = 0;
+
+
+	if (kind == w83627hf) {
+		client_name = "w83627hf";
+	} else if (kind == w83627thf) {
+		client_name = "w83627thf";
+	} else if (kind == w83697hf) {
+		client_name = "w83697hf";
+	} else if (kind == w83637hf) {
+		client_name = "w83637hf";
+	} else {
+		dev_err(&new_client->dev, "Internal error: unknown "
+						"kind (%d)?!?", kind);
+		err = -ENODEV;
+		goto ERROR2;
+	}
+
+	/* Fill in the remaining client fields and put into the global list */
+	strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
+	data->type = kind;
+	data->valid = 0;
+	init_MUTEX(&data->update_lock);
+
+	/* Tell the I2C layer a new client has arrived */
+	if ((err = i2c_attach_client(new_client)))
+		goto ERROR2;
+
+	data->lm75 = NULL;
+
+	/* Initialize the chip */
+	w83627hf_init_client(new_client);
+
+	/* Register sysfs hooks */
+	device_create_file_in(new_client, 0);
+	if (kind != w83697hf)
+		device_create_file_in(new_client, 1);
+	device_create_file_in(new_client, 2);
+	device_create_file_in(new_client, 3);
+	device_create_file_in(new_client, 4);
+	if (kind != w83627thf && kind != w83637hf) {
+		device_create_file_in(new_client, 5);
+		device_create_file_in(new_client, 6);
+	}
+	device_create_file_in(new_client, 7);
+	device_create_file_in(new_client, 8);
+
+	device_create_file_fan(new_client, 1);
+	device_create_file_fan(new_client, 2);
+	if (kind != w83697hf)
+		device_create_file_fan(new_client, 3);
+
+	device_create_file_temp(new_client, 1);
+	device_create_file_temp(new_client, 2);
+	if (kind != w83697hf)
+		device_create_file_temp(new_client, 3);
+
+	if (kind != w83697hf)
+		device_create_file_vid(new_client);
+
+	if (kind != w83697hf)
+		device_create_file_vrm(new_client);
+
+	device_create_file_fan_div(new_client, 1);
+	device_create_file_fan_div(new_client, 2);
+	if (kind != w83697hf)
+		device_create_file_fan_div(new_client, 3);
+
+	device_create_file_alarms(new_client);
+
+	device_create_file_beep(new_client);
+
+	device_create_file_pwm(new_client, 1);
+	device_create_file_pwm(new_client, 2);
+	if (kind == w83627thf || kind == w83637hf)
+		device_create_file_pwm(new_client, 3);
+
+	device_create_file_sensor(new_client, 1);
+	device_create_file_sensor(new_client, 2);
+	if (kind != w83697hf)
+		device_create_file_sensor(new_client, 3);
+
+	return 0;
+
+      ERROR2:
+	kfree(new_client);
+      ERROR1:
+	release_region(address, WINB_EXTENT);
+      ERROR0:
+	return err;
+}
+
+static int w83627hf_detach_client(struct i2c_client *client)
+{
+	int err;
+
+	if ((err = i2c_detach_client(client))) {
+		dev_err(&client->dev,
+		       "Client deregistration failed, client not detached.\n");
+		return err;
+	}
+
+	release_region(client->addr, WINB_EXTENT);
+	kfree(client);
+
+	return 0;
+}
+
+
+/*
+   ISA access must always be locked explicitly!
+   We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
+   would slow down the W83781D access and should not be necessary.
+   There are some ugly typecasts here, but the good news is - they should
+   nowhere else be necessary! */
+static int w83627hf_read_value(struct i2c_client *client, u16 reg)
+{
+	struct w83627hf_data *data = i2c_get_clientdata(client);
+	int res, word_sized;
+
+	down(&data->lock);
+	word_sized = (((reg & 0xff00) == 0x100)
+		   || ((reg & 0xff00) == 0x200))
+		  && (((reg & 0x00ff) == 0x50)
+		   || ((reg & 0x00ff) == 0x53)
+		   || ((reg & 0x00ff) == 0x55));
+	if (reg & 0xff00) {
+		outb_p(W83781D_REG_BANK,
+		       client->addr + W83781D_ADDR_REG_OFFSET);
+		outb_p(reg >> 8,
+		       client->addr + W83781D_DATA_REG_OFFSET);
+	}
+	outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
+	res = inb_p(client->addr + W83781D_DATA_REG_OFFSET);
+	if (word_sized) {
+		outb_p((reg & 0xff) + 1,
+		       client->addr + W83781D_ADDR_REG_OFFSET);
+		res =
+		    (res << 8) + inb_p(client->addr +
+				       W83781D_DATA_REG_OFFSET);
+	}
+	if (reg & 0xff00) {
+		outb_p(W83781D_REG_BANK,
+		       client->addr + W83781D_ADDR_REG_OFFSET);
+		outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
+	}
+	up(&data->lock);
+	return res;
+}
+
+static int w83627thf_read_gpio5(struct i2c_client *client)
+{
+	struct w83627hf_data *data = i2c_get_clientdata(client);
+	int res, inv;
+
+	down(&data->lock);
+	superio_enter();
+	superio_select(W83627HF_LD_GPIO5);
+	res = superio_inb(W83627THF_GPIO5_DR);
+	inv = superio_inb(W83627THF_GPIO5_INVR);
+	superio_exit();
+	up(&data->lock);
+	return res;
+}
+
+static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value)
+{
+	struct w83627hf_data *data = i2c_get_clientdata(client);
+	int word_sized;
+
+	down(&data->lock);
+	word_sized = (((reg & 0xff00) == 0x100)
+		   || ((reg & 0xff00) == 0x200))
+		  && (((reg & 0x00ff) == 0x53)
+		   || ((reg & 0x00ff) == 0x55));
+	if (reg & 0xff00) {
+		outb_p(W83781D_REG_BANK,
+		       client->addr + W83781D_ADDR_REG_OFFSET);
+		outb_p(reg >> 8,
+		       client->addr + W83781D_DATA_REG_OFFSET);
+	}
+	outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
+	if (word_sized) {
+		outb_p(value >> 8,
+		       client->addr + W83781D_DATA_REG_OFFSET);
+		outb_p((reg & 0xff) + 1,
+		       client->addr + W83781D_ADDR_REG_OFFSET);
+	}
+	outb_p(value & 0xff,
+	       client->addr + W83781D_DATA_REG_OFFSET);
+	if (reg & 0xff00) {
+		outb_p(W83781D_REG_BANK,
+		       client->addr + W83781D_ADDR_REG_OFFSET);
+		outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
+	}
+	up(&data->lock);
+	return 0;
+}
+
+/* Called when we have found a new W83781D. It should set limits, etc. */
+static void w83627hf_init_client(struct i2c_client *client)
+{
+	struct w83627hf_data *data = i2c_get_clientdata(client);
+	int vid = 0, i;
+	int type = data->type;
+	u8 tmp;
+
+	if(init) {
+		/* save this register */
+		i = w83627hf_read_value(client, W83781D_REG_BEEP_CONFIG);
+		/* Reset all except Watchdog values and last conversion values
+		   This sets fan-divs to 2, among others */
+		w83627hf_write_value(client, W83781D_REG_CONFIG, 0x80);
+		/* Restore the register and disable power-on abnormal beep.
+		   This saves FAN 1/2/3 input/output values set by BIOS. */
+		w83627hf_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80);
+		/* Disable master beep-enable (reset turns it on).
+		   Individual beeps should be reset to off but for some reason
+		   disabling this bit helps some people not get beeped */
+		w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, 0);
+	}
+
+	/* Minimize conflicts with other winbond i2c-only clients...  */
+	/* disable i2c subclients... how to disable main i2c client?? */
+	/* force i2c address to relatively uncommon address */
+	w83627hf_write_value(client, W83781D_REG_I2C_SUBADDR, 0x89);
+	w83627hf_write_value(client, W83781D_REG_I2C_ADDR, force_i2c);
+
+	/* Read VID only once */
+	if (w83627hf == data->type || w83637hf == data->type) {
+		int lo = w83627hf_read_value(client, W83781D_REG_VID_FANDIV);
+		int hi = w83627hf_read_value(client, W83781D_REG_CHIPID);
+		data->vid = (lo & 0x0f) | ((hi & 0x01) << 4);
+	} else if (w83627thf == data->type) {
+		data->vid = w83627thf_read_gpio5(client) & 0x1f;
+	}
+
+	/* Convert VID to voltage based on default VRM */
+	data->vrm = DEFAULT_VRM;
+	if (type != w83697hf)
+		vid = vid_from_reg(vid, data->vrm);
+
+	tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
+	for (i = 1; i <= 3; i++) {
+		if (!(tmp & BIT_SCFG1[i - 1])) {
+			data->sens[i - 1] = W83781D_DEFAULT_BETA;
+		} else {
+			if (w83627hf_read_value
+			    (client,
+			     W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
+				data->sens[i - 1] = 1;
+			else
+				data->sens[i - 1] = 2;
+		}
+		if ((type == w83697hf) && (i == 2))
+			break;
+	}
+
+	data->pwmenable[0] = 1;
+	data->pwmenable[1] = 1;
+	data->pwmenable[2] = 1;
+
+	if(init) {
+		if (type == w83627hf) {
+			/* enable PWM2 control (can't hurt since PWM reg
+		           should have been reset to 0xff) */
+			w83627hf_write_value(client, W83627HF_REG_PWMCLK12,
+					    0x19);
+		}
+		/* enable comparator mode for temp2 and temp3 so
+	           alarm indication will work correctly */
+		i = w83627hf_read_value(client, W83781D_REG_IRQ);
+		if (!(i & 0x40))
+			w83627hf_write_value(client, W83781D_REG_IRQ,
+					    i | 0x40);
+	}
+
+	/* Start monitoring */
+	w83627hf_write_value(client, W83781D_REG_CONFIG,
+			    (w83627hf_read_value(client,
+						W83781D_REG_CONFIG) & 0xf7)
+			    | 0x01);
+}
+
+static struct w83627hf_data *w83627hf_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83627hf_data *data = i2c_get_clientdata(client);
+	int i;
+
+	down(&data->update_lock);
+
+	if ((jiffies - data->last_updated > HZ + HZ / 2) ||
+	    (jiffies < data->last_updated) || !data->valid) {
+		for (i = 0; i <= 8; i++) {
+			/* skip missing sensors */
+			if (((data->type == w83697hf) && (i == 1)) ||
+			    ((data->type == w83627thf || data->type == w83637hf)
+			    && (i == 4 || i == 5)))
+				continue;
+			data->in[i] =
+			    w83627hf_read_value(client, W83781D_REG_IN(i));
+			data->in_min[i] =
+			    w83627hf_read_value(client,
+					       W83781D_REG_IN_MIN(i));
+			data->in_max[i] =
+			    w83627hf_read_value(client,
+					       W83781D_REG_IN_MAX(i));
+		}
+		for (i = 1; i <= 3; i++) {
+			data->fan[i - 1] =
+			    w83627hf_read_value(client, W83781D_REG_FAN(i));
+			data->fan_min[i - 1] =
+			    w83627hf_read_value(client,
+					       W83781D_REG_FAN_MIN(i));
+		}
+		for (i = 1; i <= 3; i++) {
+			u8 tmp = w83627hf_read_value(client,
+				W836X7HF_REG_PWM(data->type, i));
+ 			/* bits 0-3 are reserved  in 627THF */
+ 			if (data->type == w83627thf)
+				tmp &= 0xf0;
+			data->pwm[i - 1] = tmp;
+			if(i == 2 &&
+			   (data->type == w83627hf || data->type == w83697hf))
+				break;
+		}
+
+		data->temp = w83627hf_read_value(client, W83781D_REG_TEMP(1));
+		data->temp_max =
+		    w83627hf_read_value(client, W83781D_REG_TEMP_OVER(1));
+		data->temp_max_hyst =
+		    w83627hf_read_value(client, W83781D_REG_TEMP_HYST(1));
+		data->temp_add[0] =
+		    w83627hf_read_value(client, W83781D_REG_TEMP(2));
+		data->temp_max_add[0] =
+		    w83627hf_read_value(client, W83781D_REG_TEMP_OVER(2));
+		data->temp_max_hyst_add[0] =
+		    w83627hf_read_value(client, W83781D_REG_TEMP_HYST(2));
+		if (data->type != w83697hf) {
+			data->temp_add[1] =
+			  w83627hf_read_value(client, W83781D_REG_TEMP(3));
+			data->temp_max_add[1] =
+			  w83627hf_read_value(client, W83781D_REG_TEMP_OVER(3));
+			data->temp_max_hyst_add[1] =
+			  w83627hf_read_value(client, W83781D_REG_TEMP_HYST(3));
+		}
+
+		i = w83627hf_read_value(client, W83781D_REG_VID_FANDIV);
+		data->fan_div[0] = (i >> 4) & 0x03;
+		data->fan_div[1] = (i >> 6) & 0x03;
+		if (data->type != w83697hf) {
+			data->fan_div[2] = (w83627hf_read_value(client,
+					       W83781D_REG_PIN) >> 6) & 0x03;
+		}
+		i = w83627hf_read_value(client, W83781D_REG_VBAT);
+		data->fan_div[0] |= (i >> 3) & 0x04;
+		data->fan_div[1] |= (i >> 4) & 0x04;
+		if (data->type != w83697hf)
+			data->fan_div[2] |= (i >> 5) & 0x04;
+		data->alarms =
+		    w83627hf_read_value(client, W83781D_REG_ALARM1) |
+		    (w83627hf_read_value(client, W83781D_REG_ALARM2) << 8) |
+		    (w83627hf_read_value(client, W83781D_REG_ALARM3) << 16);
+		i = w83627hf_read_value(client, W83781D_REG_BEEP_INTS2);
+		data->beep_enable = i >> 7;
+		data->beep_mask = ((i & 0x7f) << 8) |
+		    w83627hf_read_value(client, W83781D_REG_BEEP_INTS1) |
+		    w83627hf_read_value(client, W83781D_REG_BEEP_INTS3) << 16;
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	up(&data->update_lock);
+
+	return data;
+}
+
+static int __init sensors_w83627hf_init(void)
+{
+	int addr;
+
+	if (w83627hf_find(&addr)) {
+		return -ENODEV;
+	}
+	normal_isa[0] = addr;
+
+	return i2c_add_driver(&w83627hf_driver);
+}
+
+static void __exit sensors_w83627hf_exit(void)
+{
+	i2c_del_driver(&w83627hf_driver);
+}
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
+	      "Philip Edelbrock <phil@netroedge.com>, "
+	      "and Mark Studebaker <mdsxyz123@yahoo.com>");
+MODULE_DESCRIPTION("W83627HF driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_w83627hf_init);
+module_exit(sensors_w83627hf_exit);
--- diff/drivers/ide/pci/atiixp.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/ide/pci/atiixp.c	2004-03-16 09:37:58.365667240 +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 00:00:00.000000000 +0000
+++ source/drivers/input/keyboard/lkkbd.c	2004-03-16 09:37:58.367666936 +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 00:00:00.000000000 +0000
+++ source/drivers/input/mouse/vsxxxaa.c	2004-03-16 09:37:58.369666632 +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 00:00:00.000000000 +0000
+++ source/drivers/input/serio/gscps2.c	2004-03-16 09:37:58.370666480 +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/message/fusion/lsi/mpi_inb.h	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/message/fusion/lsi/mpi_inb.h	2004-03-16 09:37:58.371666328 +0000
@@ -0,0 +1,220 @@
+/*
+ *  Copyright (c) 2003 LSI Logic Corporation.
+ *
+ *
+ *           Name:  mpi_inb.h
+ *          Title:  MPI Inband structures and definitions
+ *  Creation Date:  September 30, 2003
+ *
+ *    mpi_inb.h Version:  01.03.xx
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  ??-??-??  01.03.01  Original release.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_INB_H
+#define MPI_INB_H
+
+/******************************************************************************
+*
+*        I n b a n d    M e s s a g e s
+*
+*******************************************************************************/
+
+
+/****************************************************************************/
+/* Inband Buffer Post Request                                               */
+/****************************************************************************/
+
+typedef struct _MSG_INBAND_BUFFER_POST_REQUEST
+{
+    U8                      Reserved1;          /* 00h */
+    U8                      BufferCount;        /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved2;          /* 04h */
+    U8                      Reserved3;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U32                     Reserved4;          /* 0Ch */
+    SGE_TRANS_SIMPLE_UNION  SGL;                /* 10h */
+} MSG_INBAND_BUFFER_POST_REQUEST, MPI_POINTER PTR_MSG_INBAND_BUFFER_POST_REQUEST,
+  MpiInbandBufferPostRequest_t , MPI_POINTER pMpiInbandBufferPostRequest_t;
+
+
+typedef struct _WWN_FC_FORMAT
+{
+    U64                     NodeName;           /* 00h */
+    U64                     PortName;           /* 08h */
+} WWN_FC_FORMAT, MPI_POINTER PTR_WWN_FC_FORMAT,
+  WwnFcFormat_t, MPI_POINTER pWwnFcFormat_t;
+
+typedef struct _WWN_SAS_FORMAT
+{
+    U64                     WorldWideID;        /* 00h */
+    U32                     Reserved1;          /* 08h */
+    U32                     Reserved2;          /* 0Ch */
+} WWN_SAS_FORMAT, MPI_POINTER PTR_WWN_SAS_FORMAT,
+  WwnSasFormat_t, MPI_POINTER pWwnSasFormat_t;
+
+typedef union _WWN_INBAND_FORMAT
+{
+    WWN_FC_FORMAT           Fc;
+    WWN_SAS_FORMAT          Sas;
+} WWN_INBAND_FORMAT, MPI_POINTER PTR_WWN_INBAND_FORMAT,
+  WwnInbandFormat, MPI_POINTER pWwnInbandFormat;
+
+
+/* Inband Buffer Post reply message */
+
+typedef struct _MSG_INBAND_BUFFER_POST_REPLY
+{
+    U16                     Reserved1;          /* 00h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved2;          /* 04h */
+    U8                      Reserved3;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved4;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     TransferLength;     /* 14h */
+    U32                     TransactionContext; /* 18h */
+    WWN_INBAND_FORMAT       Wwn;                /* 1Ch */
+    U32                     IOCIdentifier[4];   /* 2Ch */
+} MSG_INBAND_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_INBAND_BUFFER_POST_REPLY,
+  MpiInbandBufferPostReply_t, MPI_POINTER pMpiInbandBufferPostReply_t;
+
+
+/****************************************************************************/
+/* Inband Send Request                                                      */
+/****************************************************************************/
+
+typedef struct _MSG_INBAND_SEND_REQUEST
+{
+    U16                     Reserved1;          /* 00h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved2;          /* 04h */
+    U8                      Reserved3;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U32                     Reserved4;          /* 0Ch */
+    WWN_INBAND_FORMAT       Wwn;                /* 10h */
+    U32                     Reserved5;          /* 20h */
+    SGE_IO_UNION            SGL;                /* 24h */
+} MSG_INBAND_SEND_REQUEST, MPI_POINTER PTR_MSG_INBAND_SEND_REQUEST,
+  MpiInbandSendRequest_t , MPI_POINTER pMpiInbandSendRequest_t;
+
+
+/* Inband Send reply message */
+
+typedef struct _MSG_INBAND_SEND_REPLY
+{
+    U16                     Reserved1;          /* 00h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved2;          /* 04h */
+    U8                      Reserved3;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved4;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     ResponseLength;     /* 14h */
+} MSG_INBAND_SEND_REPLY, MPI_POINTER PTR_MSG_INBAND_SEND_REPLY,
+  MpiInbandSendReply_t, MPI_POINTER pMpiInbandSendReply_t;
+
+
+/****************************************************************************/
+/* Inband Response Request                                                  */
+/****************************************************************************/
+
+typedef struct _MSG_INBAND_RSP_REQUEST
+{
+    U16                     Reserved1;          /* 00h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved2;          /* 04h */
+    U8                      Reserved3;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U32                     Reserved4;          /* 0Ch */
+    WWN_INBAND_FORMAT       Wwn;                /* 10h */
+    U32                     IOCIdentifier[4];   /* 20h */
+    U32                     ResponseLength;     /* 30h */
+    SGE_IO_UNION            SGL;                /* 34h */
+} MSG_INBAND_RSP_REQUEST, MPI_POINTER PTR_MSG_INBAND_RSP_REQUEST,
+  MpiInbandRspRequest_t , MPI_POINTER pMpiInbandRspRequest_t;
+
+
+/* Inband Response reply message */
+
+typedef struct _MSG_INBAND_RSP_REPLY
+{
+    U16                     Reserved1;          /* 00h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved2;          /* 04h */
+    U8                      Reserved3;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved4;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+} MSG_INBAND_RSP_REPLY, MPI_POINTER PTR_MSG_INBAND_RSP_REPLY,
+  MpiInbandRspReply_t, MPI_POINTER pMpiInbandRspReply_t;
+
+
+/****************************************************************************/
+/* Inband Abort Request                                                     */
+/****************************************************************************/
+
+typedef struct _MSG_INBAND_ABORT_REQUEST
+{
+    U8                      Reserved1;          /* 00h */
+    U8                      AbortType;          /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved2;          /* 04h */
+    U8                      Reserved3;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U32                     Reserved4;          /* 0Ch */
+    U32                     ContextToAbort;     /* 10h */
+} MSG_INBAND_ABORT_REQUEST, MPI_POINTER PTR_MSG_INBAND_ABORT_REQUEST,
+  MpiInbandAbortRequest_t , MPI_POINTER pMpiInbandAbortRequest_t;
+
+#define MPI_INBAND_ABORT_TYPE_ALL_BUFFERS       (0x00)
+#define MPI_INBAND_ABORT_TYPE_EXACT_BUFFER      (0x01)
+#define MPI_INBAND_ABORT_TYPE_SEND_REQUEST      (0x02)
+#define MPI_INBAND_ABORT_TYPE_RESPONSE_REQUEST  (0x03)
+
+
+/* Inband Abort reply message */
+
+typedef struct _MSG_INBAND_ABORT_REPLY
+{
+    U8                      Reserved1;          /* 00h */
+    U8                      AbortType;          /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved2;          /* 04h */
+    U8                      Reserved3;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved4;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+} MSG_INBAND_ABORT_REPLY, MPI_POINTER PTR_MSG_INBAND_ABORT_REPLY,
+  MpiInbandAbortReply_t, MPI_POINTER pMpiInbandAbortReply_t;
+
+
+#endif
+
--- diff/drivers/message/fusion/lsi/mpi_sas.h	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/message/fusion/lsi/mpi_sas.h	2004-03-16 09:37:58.372666176 +0000
@@ -0,0 +1,181 @@
+/*
+ *  Copyright (c) 2003 LSI Logic Corporation.
+ *
+ *
+ *           Name:  mpi_sas.h
+ *          Title:  MPI Serial Attached SCSI structures and definitions
+ *  Creation Date:  April 23, 2003
+ *
+ *    mpi_sas.h Version:  01.05.xx
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  xx-yy-zz  01.05.01  Original release.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_SAS_H
+#define MPI_SAS_H
+
+/*****************************************************************************
+*
+*        S e r i a l    A t t a c h e d    S C S I     M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/* Serial Management Protocol Passthrough Request                           */
+/****************************************************************************/
+
+typedef struct _MSG_SMP_PASSTHROUGH_REQUEST
+{
+    U8                      PassthroughFlags;   /* 00h */
+    U8                      PhysicalPort;       /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     RequestDataLength;  /* 04h */
+    U8                      ConnectionRate;     /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U32                     Reserved1;          /* 0Ch */
+    U64                     SASAddress;         /* 10h */
+    U32                     Reserved2;          /* 18h */
+    U32                     Reserved3;          /* 1Ch */
+    SGE_SIMPLE_UNION        SGL;                /* 20h */
+} MSG_SMP_PASSTHROUGH_REQUEST, MPI_POINTER PTR_MSG_SMP_PASSTHROUGH_REQUEST,
+  SmpPassthroughRequest_t, MPI_POINTER pSmpPassthroughRequest_t;
+
+#define MPI_SMP_PT_REQ_PT_FLAGS_IMMEDIATE       (0x80)
+
+#define MPI_SMP_PT_REQ_CONNECT_RATE_NEGOTIATED  (0x00)
+#define MPI_SMP_PT_REQ_CONNECT_RATE_1_5         (0x08)
+#define MPI_SMP_PT_REQ_CONNECT_RATE_3_0         (0x09)
+
+
+/* Serial Management Protocol Passthrough Reply */
+typedef struct _MSG_SMP_PASSTHROUGH_REPLY
+{
+    U8                      PassthroughFlags;   /* 00h */
+    U8                      PhysicalPort;       /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     ResponseDataLength; /* 04h */
+    U8                      Reserved1;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U8                      Reserved2;          /* 0Ch */
+    U8                      SASStatus;          /* 0Dh */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     Reserved3;          /* 14h */
+    U8                      ResponseData[4];    /* 18h */
+} MSG_SMP_PASSTHROUGH_REPLY, MPI_POINTER PTR_MSG_SMP_PASSTHROUGH_REPLY,
+  SmpPassthroughReply_t, MPI_POINTER pSmpPassthroughReply_t;
+
+#define MPI_SMP_PT_REPLY_PT_FLAGS_IMMEDIATE     (0x80)
+
+/* values for the SASStatus field */
+#define MPI_SASSTATUS_SUCCESS                           (0x00)
+#define MPI_SASSTATUS_UNKNOWN_ERROR                     (0x01)
+#define MPI_SASSTATUS_INVALID_FRAME                     (0x02)
+#define MPI_SASSTATUS_UTC_BAD_DEST                      (0x03)
+#define MPI_SASSTATUS_UTC_BREAK_RECEIVED                (0x04)
+#define MPI_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED    (0x05)
+#define MPI_SASSTATUS_UTC_PORT_LAYER_REQUEST            (0x06)
+#define MPI_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED        (0x07)
+#define MPI_SASSTATUS_UTC_STP_RESOURCES_BUSY            (0x08)
+#define MPI_SASSTATUS_UTC_WRONG_DESTINATION             (0x09)
+#define MPI_SASSTATUS_SHORT_INFORMATION_UNIT            (0x0A)
+#define MPI_SASSTATUS_LONG_INFORMATION_UNIT             (0x0B)
+#define MPI_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA     (0x0C)
+#define MPI_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR     (0x0D)
+#define MPI_SASSTATUS_XFER_RDY_NOT_EXPECTED             (0x0E)
+#define MPI_SASSTATUS_DATA_INCORRECT_DATA_LENGTH        (0x0F)
+#define MPI_SASSTATUS_DATA_TOO_MUCH_READ_DATA           (0x10)
+#define MPI_SASSTATUS_DATA_OFFSET_ERROR                 (0x11)
+#define MPI_SASSTATUS_SDSF_NAK_RECEIVED                 (0x12)
+#define MPI_SASSTATUS_SDSF_CONNECTION_FAILED            (0x13)
+#define MPI_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT        (0x14)
+
+
+/*
+ * Values for the SAS DeviceInfo field used in SAS Device Status Change Event
+ * data and SAS IO Unit Configuration pages.
+ */
+#define MPI_SAS_DEVICE_INFO_ATAPI_DEVICE        (0x00002000)
+#define MPI_SAS_DEVICE_INFO_LSI_DEVICE          (0x00001000)
+#define MPI_SAS_DEVICE_INFO_DIRECT_ATTACH       (0x00000800)
+#define MPI_SAS_DEVICE_INFO_SSP_TARGET          (0x00000400)
+#define MPI_SAS_DEVICE_INFO_STP_TARGET          (0x00000200)
+#define MPI_SAS_DEVICE_INFO_SMP_TARGET          (0x00000100)
+#define MPI_SAS_DEVICE_INFO_SATA_DEVICE         (0x00000080)
+#define MPI_SAS_DEVICE_INFO_SSP_INITIATOR       (0x00000040)
+#define MPI_SAS_DEVICE_INFO_STP_INITIATOR       (0x00000020)
+#define MPI_SAS_DEVICE_INFO_SMP_INITIATOR       (0x00000010)
+#define MPI_SAS_DEVICE_INFO_SATA_HOST           (0x00000008)
+
+#define MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE    (0x00000007)
+#define MPI_SAS_DEVICE_INFO_NO_DEVICE           (0x00000000)
+#define MPI_SAS_DEVICE_INFO_END_DEVICE          (0x00000001)
+#define MPI_SAS_DEVICE_INFO_EDGE_EXPANDER       (0x00000002)
+#define MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER     (0x00000003)
+
+
+/****************************************************************************/
+/* SAS IO Unit Control Request                                              */
+/****************************************************************************/
+
+typedef struct _MSG_SAS_IOUNIT_CONTROL_REQUEST
+{
+    U8                      Operation;          /* 00h */
+    U8                      Reserved1;          /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved2;          /* 04h */
+    U8                      Reserved3;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U8                      TargetID;           /* 0Ch */
+    U8                      Bus;                /* 0Dh */
+    U8                      PhyNum;             /* 0Eh */
+    U8                      Reserved4;          /* 0Fh */
+    U32                     Reserved5;          /* 10h */
+    U64                     SASAddress;         /* 14h */
+    U32                     Reserved6;          /* 1Ch */
+} MSG_SAS_IOUNIT_CONTROL_REQUEST, MPI_POINTER PTR_MSG_SAS_IOUNIT_CONTROL_REQUEST,
+  SasIoUnitControlRequest_t, MPI_POINTER pSasIoUnitControlRequest_t;
+
+/* values for the ... field */
+#define MPI_SAS_OP_CLEAR_NOT_PRESENT             (0x01)
+#define MPI_SAS_OP_CLEAR_ALL                     (0x02)
+#define MPI_SAS_OP_MAP                           (0x03)
+#define MPI_SAS_OP_MOVE                          (0x04)
+#define MPI_SAS_OP_CLEAR                         (0x05)
+#define MPI_SAS_OP_PHY_LINK_RESET                (0x06)
+#define MPI_SAS_OP_PHY_HARD_RESET                (0x07)
+#define MPI_SAS_OP_PHY_CLEAR_ERROR_LOG           (0x08)
+
+
+/* SAS IO Unit Control Reply */
+typedef struct _MSG_SAS_IOUNIT_CONTROL_REPLY
+{
+    U8                      Operation;          /* 00h */
+    U8                      Reserved1;          /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved2;          /* 04h */
+    U8                      Reserved3;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved4;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+} MSG_SAS_IOUNIT_CONTROL_REPLY, MPI_POINTER PTR_MSG_SAS_IOUNIT_CONTROL_REPLY,
+  SasIoUnitControlReply_t, MPI_POINTER pSasIoUnitControlReply_t;
+
+#endif
+
+
--- diff/drivers/message/fusion/lsi/mpi_tool.h	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/message/fusion/lsi/mpi_tool.h	2004-03-16 09:37:58.373666024 +0000
@@ -0,0 +1,305 @@
+/*
+ *  Copyright (c) 2001-2003 LSI Logic Corporation.
+ *
+ *
+ *           Name:  mpi_tool.h
+ *          Title:  MPI Toolbox structures and definitions
+ *  Creation Date:  July 30, 2001
+ *
+ *    mpi_tool.h Version:  01.05.xx
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  08-08-01  01.02.01  Original release.
+ *  08-29-01  01.02.02  Added DIAG_DATA_UPLOAD_HEADER and related defines.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_TOOL_H
+#define MPI_TOOL_H
+
+#define MPI_TOOLBOX_CLEAN_TOOL                      (0x00)
+#define MPI_TOOLBOX_MEMORY_MOVE_TOOL                (0x01)
+#define MPI_TOOLBOX_DIAG_DATA_UPLOAD_TOOL           (0x02)
+#define MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL           (0x03)
+#define MPI_TOOLBOX_FC_MANAGEMENT_TOOL              (0x04)
+
+
+/****************************************************************************/
+/* Toolbox reply                                                            */
+/****************************************************************************/
+
+typedef struct _MSG_TOOLBOX_REPLY
+{
+    U8                      Tool;                       /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      MsgLength;                  /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U16                     Reserved3;                  /* 0Ch */
+    U16                     IOCStatus;                  /* 0Eh */
+    U32                     IOCLogInfo;                 /* 10h */
+} MSG_TOOLBOX_REPLY, MPI_POINTER PTR_MSG_TOOLBOX_REPLY,
+  ToolboxReply_t, MPI_POINTER pToolboxReply_t;
+
+
+/****************************************************************************/
+/* Toolbox Clean Tool request                                               */
+/****************************************************************************/
+
+typedef struct _MSG_TOOLBOX_CLEAN_REQUEST
+{
+    U8                      Tool;                       /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U32                     Flags;                      /* 0Ch */
+} MSG_TOOLBOX_CLEAN_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_CLEAN_REQUEST,
+  ToolboxCleanRequest_t, MPI_POINTER pToolboxCleanRequest_t;
+
+#define MPI_TOOLBOX_CLEAN_NVSRAM                    (0x00000001)
+#define MPI_TOOLBOX_CLEAN_SEEPROM                   (0x00000002)
+#define MPI_TOOLBOX_CLEAN_FLASH                     (0x00000004)
+#define MPI_TOOLBOX_CLEAN_BOOTLOADER                (0x04000000)
+#define MPI_TOOLBOX_CLEAN_FW_BACKUP                 (0x08000000)
+#define MPI_TOOLBOX_CLEAN_FW_CURRENT                (0x10000000)
+#define MPI_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES       (0x20000000)
+#define MPI_TOOLBOX_CLEAN_PERSIST_MANUFACT_PAGES    (0x40000000)
+#define MPI_TOOLBOX_CLEAN_BOOT_SERVICES             (0x80000000)
+
+
+/****************************************************************************/
+/* Toolbox Memory Move request                                              */
+/****************************************************************************/
+
+typedef struct _MSG_TOOLBOX_MEM_MOVE_REQUEST
+{
+    U8                      Tool;                       /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    SGE_SIMPLE_UNION        SGL;                        /* 0Ch */
+} MSG_TOOLBOX_MEM_MOVE_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_MEM_MOVE_REQUEST,
+  ToolboxMemMoveRequest_t, MPI_POINTER pToolboxMemMoveRequest_t;
+
+
+/****************************************************************************/
+/* Toolbox Diagnostic Data Upload request                                   */
+/****************************************************************************/
+
+typedef struct _MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST
+{
+    U8                      Tool;                       /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U32                     Flags;                      /* 0Ch */
+    U32                     Reserved3;                  /* 10h */
+    SGE_SIMPLE_UNION        SGL;                        /* 14h */
+} MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
+  ToolboxDiagDataUploadRequest_t, MPI_POINTER pToolboxDiagDataUploadRequest_t;
+
+typedef struct _DIAG_DATA_UPLOAD_HEADER
+{
+    U32                     DiagDataLength;             /* 00h */
+    U8                      FormatCode;                 /* 04h */
+    U8                      Reserved;                   /* 05h */
+    U16                     Reserved1;                  /* 06h */
+} DIAG_DATA_UPLOAD_HEADER, MPI_POINTER PTR_DIAG_DATA_UPLOAD_HEADER,
+  DiagDataUploadHeader_t, MPI_POINTER pDiagDataUploadHeader_t;
+
+#define MPI_TB_DIAG_FORMAT_SCSI_PRINTF_1            (0x01)
+#define MPI_TB_DIAG_FORMAT_SCSI_2                   (0x02)
+#define MPI_TB_DIAG_FORMAT_SCSI_3                   (0x03)
+#define MPI_TB_DIAG_FORMAT_FC_TRACE_1               (0x04)
+
+
+/****************************************************************************/
+/* Toolbox ISTWI Read Write request                                         */
+/****************************************************************************/
+
+typedef struct _MSG_TOOLBOX_ISTWI_READ_WRITE_REQUEST
+{
+    U8                      Tool;                       /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U8                      Flags;                      /* 0Ch */
+    U8                      BusNum;                     /* 0Dh */
+    U16                     Reserved3;                  /* 0Eh */
+    U8                      NumAddressBytes;            /* 10h */
+    U8                      Reserved4;                  /* 11h */
+    U16                     DataLength;                 /* 12h */
+    U8                      DeviceAddr;                 /* 14h */
+    U8                      Addr1;                      /* 15h */
+    U8                      Addr2;                      /* 16h */
+    U8                      Addr3;                      /* 17h */
+    U32                     Reserved5;                  /* 18h */
+    SGE_SIMPLE_UNION        SGL;                        /* 1Ch */
+} MSG_TOOLBOX_ISTWI_READ_WRITE_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_ISTWI_READ_WRITE_REQUEST,
+  ToolboxIstwiReadWriteRequest_t, MPI_POINTER pToolboxIstwiReadWriteRequest_t;
+
+#define MPI_TB_ISTWI_FLAGS_WRITE                    (0x00)
+#define MPI_TB_ISTWI_FLAGS_READ                     (0x01)
+
+
+/****************************************************************************/
+/* Toolbox FC Management request                                            */
+/****************************************************************************/
+
+/* ActionInfo for Bus and TargetId */
+typedef struct _MPI_TB_FC_MANAGE_BUS_TID_AI
+{
+    U16                     Reserved;                   /* 00h */
+    U8                      Bus;                        /* 02h */
+    U8                      TargetId;                   /* 03h */
+} MPI_TB_FC_MANAGE_BUS_TID_AI, MPI_POINTER PTR_MPI_TB_FC_MANAGE_BUS_TID_AI,
+  MpiTbFcManageBusTidAi_t, MPI_POINTER pMpiTbFcManageBusTidAi_t;
+
+/* ActionInfo for port identifier */
+typedef struct _MPI_TB_FC_MANAGE_PID_AI
+{
+    U32                     PortIdentifier;             /* 00h */
+} MPI_TB_FC_MANAGE_PID_AI, MPI_POINTER PTR_MPI_TB_FC_MANAGE_PID_AI,
+  MpiTbFcManagePidAi_t, MPI_POINTER pMpiTbFcManagePidAi_t;
+
+/* union of ActionInfo */
+typedef union _MPI_TB_FC_MANAGE_AI_UNION
+{
+    MPI_TB_FC_MANAGE_BUS_TID_AI     BusTid;
+    MPI_TB_FC_MANAGE_PID_AI         Port;
+} MPI_TB_FC_MANAGE_AI_UNION, MPI_POINTER PTR_MPI_TB_FC_MANAGE_AI_UNION,
+  MpiTbFcManageAiUnion_t, MPI_POINTER pMpiTbFcManageAiUnion_t;
+
+typedef struct _MSG_TOOLBOX_FC_MANAGE_REQUEST
+{
+    U8                          Tool;                   /* 00h */
+    U8                          Reserved;               /* 01h */
+    U8                          ChainOffset;            /* 02h */
+    U8                          Function;               /* 03h */
+    U16                         Reserved1;              /* 04h */
+    U8                          Reserved2;              /* 06h */
+    U8                          MsgFlags;               /* 07h */
+    U32                         MsgContext;             /* 08h */
+    U8                          Action;                 /* 0Ch */
+    U8                          Reserved3;              /* 0Dh */
+    U16                         Reserved4;              /* 0Eh */
+    MPI_TB_FC_MANAGE_AI_UNION   ActionInfo;             /* 10h */
+} MSG_TOOLBOX_FC_MANAGE_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_FC_MANAGE_REQUEST,
+  ToolboxFcManageRequest_t, MPI_POINTER pToolboxFcManageRequest_t;
+
+/* defines for the Action field */
+#define MPI_TB_FC_MANAGE_ACTION_DISC_ALL            (0x00)
+#define MPI_TB_FC_MANAGE_ACTION_DISC_PID            (0x01)
+#define MPI_TB_FC_MANAGE_ACTION_DISC_BUS_TID        (0x02)
+
+
+/****************************************************************************/
+/* Diagnostic Buffer Post request                                           */
+/****************************************************************************/
+
+typedef struct _MSG_DIAG_BUFFER_POST_REQUEST
+{
+    U8                      TraceLevel;                 /* 00h */
+    U8                      BufferType;                 /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U32                     ExtendedType;               /* 0Ch */
+    U32                     BufferLength;               /* 10h */
+    U32                     ProductSpecific[4];         /* 14h */
+    U32                     Reserved3;                  /* 18h */
+    SGE_SIMPLE_UNION        SGL;                        /* 28h */
+} MSG_DIAG_BUFFER_POST_REQUEST, MPI_POINTER PTR_MSG_DIAG_BUFFER_POST_REQUEST,
+  DiagBufferPostRequest_t, MPI_POINTER pDiagBufferPostRequest_t;
+
+#define MPI_DIAG_BUF_TYPE_TRACE                     (0x00)
+#define MPI_DIAG_BUF_TYPE_SNAPSHOT                  (0x01)
+#define MPI_DIAG_BUF_TYPE_EXTENDED                  (0x02)
+
+#define MPI_DIAG_EXTENDED_QTAG                      (0x00000001)
+
+
+/* Diagnostic Buffer Post reply */
+typedef struct _MSG_DIAG_BUFFER_POST_REPLY
+{
+    U8                      Reserved1;                  /* 00h */
+    U8                      BufferType;                 /* 01h */
+    U8                      MsgLength;                  /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved2;                  /* 04h */
+    U8                      Reserved3;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U16                     Reserved4;                  /* 0Ch */
+    U16                     IOCStatus;                  /* 0Eh */
+    U32                     IOCLogInfo;                 /* 10h */
+    U32                     TransferLength;             /* 14h */
+} MSG_DIAG_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_DIAG_BUFFER_POST_REPLY,
+  DiagBufferPostReply_t, MPI_POINTER pDiagBufferPostReply_t;
+
+
+/****************************************************************************/
+/* Diagnostic Release request                                               */
+/****************************************************************************/
+
+typedef struct _MSG_DIAG_RELEASE_REQUEST
+{
+    U8                      Reserved1;                  /* 00h */
+    U8                      BufferType;                 /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved2;                  /* 04h */
+    U8                      Reserved3;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+} MSG_DIAG_RELEASE_REQUEST, MPI_POINTER PTR_MSG_DIAG_RELEASE_REQUEST,
+  DiagReleaseRequest_t, MPI_POINTER pDiagReleaseRequest_t;
+
+
+/* Diagnostic Release reply */
+typedef struct _MSG_DIAG_RELEASE_REPLY
+{
+    U8                      Reserved1;                  /* 00h */
+    U8                      BufferType;                 /* 01h */
+    U8                      MsgLength;                  /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved2;                  /* 04h */
+    U8                      Reserved3;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U16                     Reserved4;                  /* 0Ch */
+    U16                     IOCStatus;                  /* 0Eh */
+    U32                     IOCLogInfo;                 /* 10h */
+} MSG_DIAG_RELEASE_REPLY, MPI_POINTER PTR_MSG_DIAG_RELEASE_REPLY,
+  DiagReleaseReply_t, MPI_POINTER pDiagReleaseReply_t;
+
+
+#endif
+
+
--- diff/drivers/net/kgdb_eth.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/net/kgdb_eth.c	2004-03-16 09:37:58.374665872 +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 00:00:00.000000000 +0000
+++ source/drivers/net/netconsole.c	2004-03-16 09:37:58.374665872 +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/net/wireless/prism54/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/net/wireless/prism54/Makefile	2004-03-16 09:37:58.375665720 +0000
@@ -0,0 +1,10 @@
+# $Id: Makefile.k26,v 1.7 2004/01/30 16:24:00 ajfa Exp $
+
+prism54-objs := islpci_eth.o islpci_mgt.o \
+                isl_38xx.o isl_ioctl.o islpci_dev.o \
+		islpci_hotplug.o oid_mgt.o
+
+obj-$(CONFIG_PRISM54) += prism54.o
+
+EXTRA_CFLAGS = -I$(PWD) #-DCONFIG_PRISM54_WDS
+
--- diff/drivers/net/wireless/prism54/isl_38xx.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/net/wireless/prism54/isl_38xx.c	2004-03-16 09:37:58.376665568 +0000
@@ -0,0 +1,397 @@
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/isl_38xx.c,v 1.22 2004/02/28 03:06:07 mcgrof Exp $
+ *  
+ *  Copyright (C) 2002 Intersil Americas Inc.
+ *  Copyright (C) 2003-2004 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>_
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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 __KERNEL_SYSCALLS__
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+
+#include "isl_38xx.h"
+#include <linux/firmware.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include <linux/config.h>
+#if !defined(CONFIG_FW_LOADER) && !defined(CONFIG_FW_LOADER_MODULE)
+#error No Firmware Loading configured in the kernel !
+#endif
+
+#include "islpci_dev.h"
+#include "islpci_mgt.h"
+
+/******************************************************************************
+    Device Interface & Control functions
+******************************************************************************/
+
+/**
+ * isl38xx_disable_interrupts - disable all interrupts
+ * @device: pci memory base address
+ *
+ *  Instructs the device to disable all interrupt reporting by asserting 
+ *  the IRQ line. New events may still show up in the interrupt identification
+ *  register located at offset %ISL38XX_INT_IDENT_REG.
+ */
+void
+isl38xx_disable_interrupts(void *device)
+{
+	isl38xx_w32_flush(device, 0x00000000, ISL38XX_INT_EN_REG);
+	udelay(ISL38XX_WRITEIO_DELAY);
+}
+
+void
+isl38xx_handle_sleep_request(isl38xx_control_block *control_block,
+			     int *powerstate, void *device_base)
+{
+	/* device requests to go into sleep mode
+	 * check whether the transmit queues for data and management are empty */
+	if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ))
+		/* data tx queue not empty */
+		return;
+
+	if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ))
+		/* management tx queue not empty */
+		return;
+
+	/* check also whether received frames are pending */
+	if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_DATA_LQ))
+		/* data rx queue not empty */
+		return;
+
+	if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_MGMTQ))
+		/* management rx queue not empty */
+		return;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_TRACING, "Device going to sleep mode\n");
+#endif
+
+	/* all queues are empty, allow the device to go into sleep mode */
+	*powerstate = ISL38XX_PSM_POWERSAVE_STATE;
+
+	/* assert the Sleep interrupt in the Device Interrupt Register */
+	isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_SLEEP,
+			  ISL38XX_DEV_INT_REG);
+	udelay(ISL38XX_WRITEIO_DELAY);
+}
+
+void
+isl38xx_handle_wakeup(isl38xx_control_block *control_block,
+		      int *powerstate, void *device_base)
+{
+	/* device is in active state, update the powerstate flag */
+	*powerstate = ISL38XX_PSM_ACTIVE_STATE;
+
+	/* now check whether there are frames pending for the card */
+	if (!isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ)
+	    && !isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ))
+		return;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_ANYTHING, "Wake up handler trigger the device\n");
+#endif
+
+	/* either data or management transmit queue has a frame pending
+	 * trigger the device by setting the Update bit in the Device Int reg */
+	isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE,
+			  ISL38XX_DEV_INT_REG);
+	udelay(ISL38XX_WRITEIO_DELAY);
+}
+
+void
+isl38xx_trigger_device(int asleep, void *device_base)
+{
+	struct timeval current_time;
+	u32 reg, counter = 0;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n");
+#endif
+
+	/* check whether the device is in power save mode */
+	if (asleep) {
+		/* device is in powersave, trigger the device for wakeup */
+#if VERBOSE > SHOW_ERROR_MESSAGES
+		do_gettimeofday(&current_time);
+		DEBUG(SHOW_TRACING, "%08li.%08li Device wakeup triggered\n",
+		      current_time.tv_sec, current_time.tv_usec);
+#endif
+
+		DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
+		      current_time.tv_sec, current_time.tv_usec,
+		      readl(device_base + ISL38XX_CTRL_STAT_REG));
+		udelay(ISL38XX_WRITEIO_DELAY);
+
+		if (reg = readl(device_base + ISL38XX_INT_IDENT_REG),
+		    reg == 0xabadface) {
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			do_gettimeofday(&current_time);
+			DEBUG(SHOW_TRACING,
+			      "%08li.%08li Device register abadface\n",
+			      current_time.tv_sec, current_time.tv_usec);
+#endif
+			/* read the Device Status Register until Sleepmode bit is set */
+			while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG),
+			       (reg & ISL38XX_CTRL_STAT_SLEEPMODE) == 0) {
+				udelay(ISL38XX_WRITEIO_DELAY);
+				counter++;
+			}
+
+			DEBUG(SHOW_TRACING,
+			      "%08li.%08li Device register read %08x\n",
+			      current_time.tv_sec, current_time.tv_usec,
+			      readl(device_base + ISL38XX_CTRL_STAT_REG));
+			udelay(ISL38XX_WRITEIO_DELAY);
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			do_gettimeofday(&current_time);
+			DEBUG(SHOW_TRACING,
+			      "%08li.%08li Device asleep counter %i\n",
+			      current_time.tv_sec, current_time.tv_usec,
+			      counter);
+#endif
+		}
+		/* assert the Wakeup interrupt in the Device Interrupt Register */
+		isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_WAKEUP,
+				  ISL38XX_DEV_INT_REG);
+		udelay(ISL38XX_WRITEIO_DELAY);
+
+		/* perform another read on the Device Status Register */
+		reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
+		udelay(ISL38XX_WRITEIO_DELAY);
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+		do_gettimeofday(&current_time);
+		DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
+		      current_time.tv_sec, current_time.tv_usec, reg);
+#endif
+	} else {
+		/* device is (still) awake  */
+#if VERBOSE > SHOW_ERROR_MESSAGES
+		DEBUG(SHOW_TRACING, "Device is in active state\n");
+#endif
+		/* trigger the device by setting the Update bit in the Device Int reg */
+
+		isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE,
+				  ISL38XX_DEV_INT_REG);
+		udelay(ISL38XX_WRITEIO_DELAY);
+	}
+}
+
+void
+isl38xx_interface_reset(void *device_base, dma_addr_t host_address)
+{
+	u32 reg;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset \n");
+#endif
+
+	/* load the address of the control block in the device */
+	isl38xx_w32_flush(device_base, host_address, ISL38XX_CTRL_BLK_BASE_REG);
+	udelay(ISL38XX_WRITEIO_DELAY);
+
+	/* set the reset bit in the Device Interrupt Register */
+	isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET,
+			  ISL38XX_DEV_INT_REG);
+	udelay(ISL38XX_WRITEIO_DELAY);
+
+	/* enable the interrupt for detecting initialization */
+
+	/* Note: Do not enable other interrupts here. We want the
+	 * device to have come up first 100% before allowing any other 
+	 * interrupts. */
+	reg = ISL38XX_INT_IDENT_INIT;
+
+	isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG);
+	udelay(ISL38XX_WRITEIO_DELAY);  /* allow complete full reset */
+}
+
+void
+isl38xx_enable_common_interrupts(void *device_base) {
+	u32 reg;
+	reg = ( ISL38XX_INT_IDENT_UPDATE | 
+			ISL38XX_INT_IDENT_SLEEP | ISL38XX_INT_IDENT_WAKEUP);
+	isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG);
+	udelay(ISL38XX_WRITEIO_DELAY);
+}
+
+int
+isl38xx_upload_firmware(char *fw_id, _REQ_FW_DEV_T dev, void *device_base,
+			dma_addr_t host_address)
+{
+	u32 reg, rc;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_ERROR_MESSAGES, "isl38xx_upload_firmware(0x%lx, 0x%lx)\n",
+	      (long) device_base, (long) host_address);
+#endif
+
+	/* clear the RAMBoot and the Reset bit */
+	reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
+	reg &= ~ISL38XX_CTRL_STAT_RESET;
+	reg &= ~ISL38XX_CTRL_STAT_RAMBOOT;
+	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
+	wmb();
+	udelay(ISL38XX_WRITEIO_DELAY);
+
+	/* set the Reset bit without reading the register ! */
+	reg |= ISL38XX_CTRL_STAT_RESET;
+	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
+	wmb();
+	udelay(ISL38XX_WRITEIO_DELAY);
+
+	/* clear the Reset bit */
+	reg &= ~ISL38XX_CTRL_STAT_RESET;
+	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
+	wmb();
+
+	/* wait a while for the device to reboot */
+	mdelay(50);
+
+	{
+		const struct firmware *fw_entry = 0;
+		long fw_len;
+		const u32 *fw_ptr;
+
+		rc = request_firmware(&fw_entry, fw_id, dev);
+		if (rc) {
+			printk(KERN_ERR
+			       "%s: request_firmware() failed for '%s'\n",
+			       "prism54", fw_id);
+			return rc;
+		}
+		/* prepare the Direct Memory Base register */
+		reg = ISL38XX_DEV_FIRMWARE_ADDRES;
+
+		fw_ptr = (u32 *) fw_entry->data;
+		fw_len = fw_entry->size;
+
+		if (fw_len % 4) {
+			printk(KERN_ERR
+			       "%s: firmware '%s' size is not multiple of 32bit, aborting!\n",
+			       "prism54", fw_id);
+			release_firmware(fw_entry);
+			return EILSEQ; /* Illegal byte sequence  */;
+		}
+
+		while (fw_len > 0) {
+			long _fw_len =
+			    (fw_len >
+			     ISL38XX_MEMORY_WINDOW_SIZE) ?
+			    ISL38XX_MEMORY_WINDOW_SIZE : fw_len;
+			u32 *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN;
+
+			/* set the cards base address for writting the data */
+			isl38xx_w32_flush(device_base, reg,
+					  ISL38XX_DIR_MEM_BASE_REG);
+			wmb();	/* be paranoid */
+
+			/* increment the write address for next iteration */
+			reg += _fw_len;
+			fw_len -= _fw_len;
+
+			/* write the data to the Direct Memory Window 32bit-wise */
+			/* memcpy_toio() doesn't guarantee 32bit writes :-| */
+			while (_fw_len > 0) {
+				/* use non-swapping writel() */
+				__raw_writel(*fw_ptr, dev_fw_ptr);
+				fw_ptr++, dev_fw_ptr++;
+				_fw_len -= 4;
+			}
+
+			/* flush PCI posting */
+			(void) readl(device_base + ISL38XX_PCI_POSTING_FLUSH);
+			wmb();	/* be paranoid again */
+
+			BUG_ON(_fw_len != 0);
+		}
+
+		BUG_ON(fw_len != 0);
+
+		release_firmware(fw_entry);
+	}
+
+	/* now reset the device
+	 * clear the Reset & ClkRun bit, set the RAMBoot bit */
+	reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
+	reg &= ~ISL38XX_CTRL_STAT_CLKRUN;
+	reg &= ~ISL38XX_CTRL_STAT_RESET;
+	reg |= ISL38XX_CTRL_STAT_RAMBOOT;
+	isl38xx_w32_flush(device_base, reg, ISL38XX_CTRL_STAT_REG);
+	wmb();
+	udelay(ISL38XX_WRITEIO_DELAY);
+
+	/* set the reset bit latches the host override and RAMBoot bits
+	 * into the device for operation when the reset bit is reset */
+	reg |= ISL38XX_CTRL_STAT_RESET;
+	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
+	/* don't do flush PCI posting here! */
+	wmb();
+	udelay(ISL38XX_WRITEIO_DELAY);
+
+	/* clear the reset bit should start the whole circus */
+	reg &= ~ISL38XX_CTRL_STAT_RESET;
+	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
+	/* don't do flush PCI posting here! */
+	wmb();
+	udelay(ISL38XX_WRITEIO_DELAY);
+
+	return 0;
+}
+
+int
+isl38xx_in_queue(isl38xx_control_block *cb, int queue)
+{
+	const s32 delta = (le32_to_cpu(cb->driver_curr_frag[queue]) -
+			   le32_to_cpu(cb->device_curr_frag[queue]));
+
+	/* determine the amount of fragments in the queue depending on the type
+	 * of the queue, either transmit or receive */
+
+	BUG_ON(delta < 0);	/* driver ptr must be ahead of device ptr */
+
+	switch (queue) {
+		/* send queues */
+	case ISL38XX_CB_TX_MGMTQ:
+		BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE);
+	case ISL38XX_CB_TX_DATA_LQ:
+	case ISL38XX_CB_TX_DATA_HQ:
+		BUG_ON(delta > ISL38XX_CB_TX_QSIZE);
+		return delta;
+		break;
+
+		/* receive queues */
+	case ISL38XX_CB_RX_MGMTQ:
+		BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE);
+		return ISL38XX_CB_MGMT_QSIZE - delta;
+		break;
+
+	case ISL38XX_CB_RX_DATA_LQ:
+	case ISL38XX_CB_RX_DATA_HQ:
+		BUG_ON(delta > ISL38XX_CB_RX_QSIZE);
+		return ISL38XX_CB_RX_QSIZE - delta;
+		break;
+	}
+	BUG();
+	return 0;
+}
--- diff/drivers/net/wireless/prism54/isl_38xx.h	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/net/wireless/prism54/isl_38xx.h	2004-03-16 09:37:58.377665416 +0000
@@ -0,0 +1,179 @@
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/isl_38xx.h,v 1.22 2004/02/28 03:06:07 mcgrof Exp $
+ *  
+ *  Copyright (C) 2002 Intersil Americas 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
+ *
+ *  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 _ISL_38XX_H
+#define _ISL_38XX_H
+
+#include <linux/version.h>
+#include <asm/io.h>
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,75))
+#include <linux/device.h>
+# define _REQ_FW_DEV_T struct device *
+#else
+# define _REQ_FW_DEV_T char *
+#endif
+
+#include <asm/byteorder.h>
+
+#define ISL38XX_CB_RX_QSIZE                     8
+#define ISL38XX_CB_TX_QSIZE                     32
+
+/* ISL38XX Access Point Specific definitions */
+#define ISL38XX_MAX_WDS_LINKS                   8
+
+/* ISL38xx Client Specific definitions */
+#define ISL38XX_PSM_ACTIVE_STATE                0
+#define ISL38XX_PSM_POWERSAVE_STATE             1
+
+/* ISL38XX Host Interface Definitions */
+#define ISL38XX_PCI_MEM_SIZE                    0x02000
+#define ISL38XX_MEMORY_WINDOW_SIZE              0x01000
+#define ISL38XX_DEV_FIRMWARE_ADDRES             0x20000
+#define ISL38XX_WRITEIO_DELAY                   10	/* in us */
+#define ISL38XX_RESET_DELAY                     50	/* in ms */
+#define ISL38XX_WAIT_CYCLE                      10	/* in 10ms */
+#define ISL38XX_MAX_WAIT_CYCLES                 10
+
+/* PCI Memory Area */
+#define ISL38XX_HARDWARE_REG                    0x0000
+#define ISL38XX_CARDBUS_CIS                     0x0800
+#define ISL38XX_DIRECT_MEM_WIN                  0x1000
+
+/* Hardware registers */
+#define ISL38XX_DEV_INT_REG                     0x0000
+#define ISL38XX_INT_IDENT_REG                   0x0010
+#define ISL38XX_INT_ACK_REG                     0x0014
+#define ISL38XX_INT_EN_REG                      0x0018
+#define ISL38XX_GEN_PURP_COM_REG_1              0x0020
+#define ISL38XX_GEN_PURP_COM_REG_2              0x0024
+#define ISL38XX_CTRL_BLK_BASE_REG               ISL38XX_GEN_PURP_COM_REG_1
+#define ISL38XX_DIR_MEM_BASE_REG                0x0030
+#define ISL38XX_CTRL_STAT_REG                   0x0078
+
+/* High end mobos queue up pci writes, the following
+ * is used to "read" from after a write to force flush */
+#define ISL38XX_PCI_POSTING_FLUSH		ISL38XX_INT_EN_REG
+
+/**
+ * isl38xx_w32_flush - PCI iomem write helper
+ * @base: (host) memory base address of the device
+ * @val: 32bit value (host order) to write
+ * @offset: byte offset into @base to write value to
+ * 
+ *  This helper takes care of writing a 32bit datum to the
+ *  specified offset into the device's pci memory space, and making sure 
+ *  the pci memory buffers get flushed by performing one harmless read 
+ *  from the %ISL38XX_PCI_POSTING_FLUSH offset.
+ */
+static inline void
+isl38xx_w32_flush(void *base, u32 val, unsigned long offset)
+{
+	writel(val, base + offset);
+	(void) readl(base + ISL38XX_PCI_POSTING_FLUSH);
+}
+
+/* Device Interrupt register bits */
+#define ISL38XX_DEV_INT_RESET                   0x0001
+#define ISL38XX_DEV_INT_UPDATE                  0x0002
+#define ISL38XX_DEV_INT_WAKEUP                  0x0008
+#define ISL38XX_DEV_INT_SLEEP                   0x0010
+
+/* Interrupt Identification/Acknowledge/Enable register bits */
+#define ISL38XX_INT_IDENT_UPDATE                0x0002
+#define ISL38XX_INT_IDENT_INIT                  0x0004
+#define ISL38XX_INT_IDENT_WAKEUP                0x0008
+#define ISL38XX_INT_IDENT_SLEEP                 0x0010
+#define ISL38XX_INT_SOURCES                     0x001E
+
+/* Control/Status register bits */
+#define ISL38XX_CTRL_STAT_SLEEPMODE             0x00000200
+#define	ISL38XX_CTRL_STAT_CLKRUN		0x00800000
+#define ISL38XX_CTRL_STAT_RESET                 0x10000000
+#define ISL38XX_CTRL_STAT_RAMBOOT               0x20000000
+#define ISL38XX_CTRL_STAT_STARTHALTED           0x40000000
+#define ISL38XX_CTRL_STAT_HOST_OVERRIDE         0x80000000
+
+/* Control Block definitions */
+#define ISL38XX_CB_RX_DATA_LQ                   0
+#define ISL38XX_CB_TX_DATA_LQ                   1
+#define ISL38XX_CB_RX_DATA_HQ                   2
+#define ISL38XX_CB_TX_DATA_HQ                   3
+#define ISL38XX_CB_RX_MGMTQ                     4
+#define ISL38XX_CB_TX_MGMTQ                     5
+#define ISL38XX_CB_QCOUNT                       6
+#define ISL38XX_CB_MGMT_QSIZE                   4
+#define ISL38XX_MIN_QTHRESHOLD                  4	/* fragments */
+
+/* Memory Manager definitions */
+#define MGMT_FRAME_SIZE                         1500	/* >= size struct obj_bsslist */
+#define MGMT_TX_FRAME_COUNT                     24	/* max 4 + spare 4 + 8 init */
+#define MGMT_RX_FRAME_COUNT                     24	/* 4*4 + spare 8 */
+#define MGMT_FRAME_COUNT                        (MGMT_TX_FRAME_COUNT + MGMT_RX_FRAME_COUNT)
+#define CONTROL_BLOCK_SIZE                      1024	/* should be enough */
+#define PSM_FRAME_SIZE                          1536
+#define PSM_MINIMAL_STATION_COUNT               64
+#define PSM_FRAME_COUNT                         PSM_MINIMAL_STATION_COUNT
+#define PSM_BUFFER_SIZE                         PSM_FRAME_SIZE * PSM_FRAME_COUNT
+#define MAX_TRAP_RX_QUEUE                       4
+#define HOST_MEM_BLOCK                          CONTROL_BLOCK_SIZE + PSM_BUFFER_SIZE
+
+/* Fragment package definitions */
+#define FRAGMENT_FLAG_MF                        0x0001
+#define MAX_FRAGMENT_SIZE                       1536
+
+/* In monitor mode frames have a header. I don't know exactly how big those
+ * frame can be but I've never seen any frame bigger than 1584... :
+ */
+#define MAX_FRAGMENT_SIZE_RX	                1600
+
+typedef struct {
+	u32 address;		/* physical address on host */
+	u16 size;		/* packet size */
+	u16 flags;		/* set of bit-wise flags */
+} isl38xx_fragment;
+
+struct isl38xx_cb {
+	u32 driver_curr_frag[ISL38XX_CB_QCOUNT];
+	u32 device_curr_frag[ISL38XX_CB_QCOUNT];
+	isl38xx_fragment rx_data_low[ISL38XX_CB_RX_QSIZE];
+	isl38xx_fragment tx_data_low[ISL38XX_CB_TX_QSIZE];
+	isl38xx_fragment rx_data_high[ISL38XX_CB_RX_QSIZE];
+	isl38xx_fragment tx_data_high[ISL38XX_CB_TX_QSIZE];
+	isl38xx_fragment rx_data_mgmt[ISL38XX_CB_MGMT_QSIZE];
+	isl38xx_fragment tx_data_mgmt[ISL38XX_CB_MGMT_QSIZE];
+};
+
+typedef struct isl38xx_cb isl38xx_control_block;
+
+/* determine number of entries currently in queue */
+int isl38xx_in_queue(isl38xx_control_block *cb, int queue);
+
+void isl38xx_disable_interrupts(void *);
+void isl38xx_enable_common_interrupts(void *);
+
+void isl38xx_handle_sleep_request(isl38xx_control_block *, int *,
+				  void *);
+void isl38xx_handle_wakeup(isl38xx_control_block *, int *, void *);
+void isl38xx_trigger_device(int, void *);
+void isl38xx_interface_reset(void *, dma_addr_t);
+
+int isl38xx_upload_firmware(char *, _REQ_FW_DEV_T, void *, dma_addr_t);
+
+#endif				/* _ISL_38XX_H */
--- diff/drivers/net/wireless/prism54/isl_ioctl.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/net/wireless/prism54/isl_ioctl.c	2004-03-16 09:37:58.382664656 +0000
@@ -0,0 +1,2155 @@
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/isl_ioctl.c,v 1.140 2004/02/28 03:06:07 mcgrof Exp $
+ *  
+ *  Copyright (C) 2002 Intersil Americas Inc.
+ *            (C) 2003 Aurelien Alleaume <slts@free.fr>
+ *            (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
+ *            (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/if_arp.h>
+#include <linux/pci.h>
+
+#include <asm/uaccess.h>
+
+#include "isl_ioctl.h"
+#include "islpci_mgt.h"
+#include "isl_oid.h"		/* additional types and defs for isl38xx fw */
+#include "oid_mgt.h"
+
+#include <net/iw_handler.h>	/* New driver API */
+
+static int init_mode = CARD_DEFAULT_IW_MODE;
+static int init_channel = CARD_DEFAULT_CHANNEL;
+static int init_wep = CARD_DEFAULT_WEP;
+static int init_filter = CARD_DEFAULT_FILTER;
+static int init_authen = CARD_DEFAULT_AUTHEN;
+static int init_dot1x = CARD_DEFAULT_DOT1X;
+static int init_conformance = CARD_DEFAULT_CONFORMANCE;
+static int init_mlme = CARD_DEFAULT_MLME_MODE;
+
+MODULE_PARM(init_mode, "i");
+MODULE_PARM_DESC(init_mode,
+		 "Set card mode:\n0: Auto\n1: Ad-Hoc\n2: Managed Client (Default)\n3: Master / Access Point\n4: Repeater (Not supported yet)\n5: Secondary (Not supported yet)\n6: Monitor");
+
+MODULE_PARM(init_channel, "i");
+MODULE_PARM_DESC(init_channel,
+		 "Check `iwpriv ethx channel` for available channels");
+
+MODULE_PARM(init_wep, "i");
+MODULE_PARM(init_filter, "i");
+
+MODULE_PARM(init_authen, "i");
+MODULE_PARM_DESC(init_authen,
+		 "Authentication method. Can be of seven types:\n0 0x0000: None\n1 0x0001: DOT11_AUTH_OS (Default)\n2 0x0002: DOT11_AUTH_SK\n3 0x0003: DOT11_AUTH_BOTH");
+
+MODULE_PARM(init_dot1x, "i");
+MODULE_PARM_DESC(init_dot1x,
+		 "\n0: None/not set	(Default)\n1: DOT11_DOT1X_AUTHENABLED\n2: DOT11_DOT1X_KEYTXENABLED");
+
+MODULE_PARM(init_mlme, "i");
+MODULE_PARM_DESC(init_mlme,
+		 "Sets the MAC layer management entity (MLME) mode of operation,\n0: DOT11_MLME_AUTO (Default)\n1: DOT11_MLME_INTERMEDIATE\n2: DOT11_MLME_EXTENDED");
+
+/**
+ * prism54_mib_mode_helper - MIB change mode helper function
+ * @mib: the &struct islpci_mib object to modify
+ * @iw_mode: new mode (%IW_MODE_*)
+ * 
+ *  This is a helper function, hence it does not lock. Make sure
+ *  caller deals with locking *if* necessary. This function sets the 
+ *  mode-dependent mib values and does the mapping of the Linux 
+ *  Wireless API modes to Device firmware modes. It also checks for 
+ *  correct valid Linux wireless modes. 
+ */
+int
+prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode)
+{
+	u32 config = INL_CONFIG_MANUALRUN;
+	u32 mode, bsstype;
+
+	/* For now, just catch early the Repeater and Secondary modes here */
+	if (iw_mode == IW_MODE_REPEAT || iw_mode == IW_MODE_SECOND) {
+		printk(KERN_DEBUG "%s(): Sorry, Repeater mode and Secondary mode "
+				"are not yet supported by this driver.\n",
+		       __FUNCTION__);
+		return -EINVAL;
+	}
+
+	priv->iw_mode = iw_mode;
+
+	switch (iw_mode) {
+	case IW_MODE_AUTO:
+		mode = INL_MODE_CLIENT;
+		bsstype = DOT11_BSSTYPE_ANY;
+		break;
+	case IW_MODE_ADHOC:
+		mode = INL_MODE_CLIENT;
+		bsstype = DOT11_BSSTYPE_IBSS;
+		break;
+	case IW_MODE_INFRA:
+		mode = INL_MODE_CLIENT;
+		bsstype = DOT11_BSSTYPE_INFRA;
+		break;
+	case IW_MODE_MASTER:
+		mode = INL_MODE_AP;
+		bsstype = DOT11_BSSTYPE_INFRA;
+		break;
+	case IW_MODE_MONITOR:
+		mode = INL_MODE_PROMISCUOUS;
+		bsstype = DOT11_BSSTYPE_ANY;
+		config |= INL_CONFIG_RXANNEX;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (init_wds)
+		config |= INL_CONFIG_WDS;
+	mgt_set(priv, DOT11_OID_BSSTYPE, &bsstype);
+	mgt_set(priv, OID_INL_CONFIG, &config);
+	mgt_set(priv, OID_INL_MODE, &mode);
+
+	return 0;
+}
+
+/**
+ * prism54_mib_init - fill MIB cache with defaults
+ *
+ *  this function initializes the struct given as @mib with defaults,
+ *  of which many are retrieved from the global module parameter
+ *  variables.  
+ */
+
+void
+prism54_mib_init(islpci_private *priv)
+{
+	u32 t;
+	struct obj_buffer psm_buffer = {
+		.size = cpu_to_le32(PSM_BUFFER_SIZE),
+		.addr = cpu_to_le32(priv->device_psm_buffer)
+	};
+
+	mgt_set(priv, DOT11_OID_CHANNEL, &init_channel);
+	mgt_set(priv, DOT11_OID_AUTHENABLE, &init_authen);
+	mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &init_wep);
+
+	mgt_set(priv, DOT11_OID_PSMBUFFER, &psm_buffer);
+	mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &init_filter);
+	mgt_set(priv, DOT11_OID_DOT1XENABLE, &init_dot1x);
+	mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &init_mlme);
+	mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &init_conformance);
+
+	t = 127;
+	mgt_set(priv, OID_INL_OUTPUTPOWER, &t);
+
+	/* Important: we are setting a default wireless mode and we are 
+	 * forcing a valid one, so prism54_mib_mode_helper should just set
+	 * mib values depending on what the wireless mode given is. No need
+	 * for it save old values */
+	if (init_mode > IW_MODE_MONITOR || init_mode < IW_MODE_AUTO) {
+		printk(KERN_DEBUG "%s(): You passed a non-valid init_mode. "
+				"Using default mode\n", __FUNCTION__);
+		init_mode = CARD_DEFAULT_IW_MODE;
+	}
+	/* This sets all of the mode-dependent values */
+	prism54_mib_mode_helper(priv, init_mode);
+}
+
+void
+prism54_mib_init_work(islpci_private *priv)
+{
+	down_write(&priv->mib_sem);
+	mgt_commit(priv);
+	up_write(&priv->mib_sem);
+}
+
+/* this will be executed outside of atomic context thanks to
+ * schedule_work(), thus we can as well use sleeping semaphore
+ * locking */
+void
+prism54_update_stats(islpci_private *priv)
+{
+	char *data;
+	int j;
+	struct obj_bss bss, *bss2;
+	union oid_res_t r;
+
+	if (down_interruptible(&priv->stats_sem))
+		return;
+
+/* missing stats are :
+ *  iwstatistics.qual.updated
+ *  iwstatistics.discard.nwid	    
+ *  iwstatistics.discard.fragment	    
+ *  iwstatistics.discard.misc
+ *  iwstatistics.miss.beacon */
+
+/* Noise floor.
+ * I'm not sure if the unit is dBm.
+ * Note : If we are not connected, this value seems to be irrevelant. */
+
+	mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
+	priv->local_iwstatistics.qual.noise = r.u;
+
+/* Get the rssi of the link. To do this we need to retrieve a bss. */
+
+	/* First get the MAC address of the AP we are associated with. */
+	mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r);
+	data = r.ptr;
+
+	/* copy this MAC to the bss */
+	for (j = 0; j < 6; j++)
+		bss.address[j] = data[j];
+	kfree(data);
+
+	/* now ask for the corresponding bss */
+	j = mgt_get_request(priv, DOT11_OID_BSSFIND, 0, (void *) &bss, &r);
+	bss2 = r.ptr;
+	/* report the rssi and use it to calculate
+	 *  link quality through a signal-noise
+	 *  ratio */
+	priv->local_iwstatistics.qual.level = bss2->rssi;
+	priv->local_iwstatistics.qual.qual =
+	    bss2->rssi - priv->iwstatistics.qual.noise;
+
+	kfree(bss2);
+
+	/* report that the stats are new */
+	priv->local_iwstatistics.qual.updated = 0x7;
+
+/* Rx : unable to decrypt the MPDU */
+	mgt_get_request(priv, DOT11_OID_PRIVRXFAILED, 0, NULL, &r);
+	priv->local_iwstatistics.discard.code = r.u;
+
+/* Tx : Max MAC retries num reached */
+	mgt_get_request(priv, DOT11_OID_MPDUTXFAILED, 0, NULL, &r);
+	priv->local_iwstatistics.discard.retries = r.u;
+
+	up(&priv->stats_sem);
+
+	return;
+}
+
+struct iw_statistics *
+prism54_get_wireless_stats(struct net_device *ndev)
+{
+	islpci_private *priv = ndev->priv;
+
+	/* If the stats are being updated return old data */
+	if (down_trylock(&priv->stats_sem) == 0) {
+		memcpy(&priv->iwstatistics, &priv->local_iwstatistics,
+		       sizeof (struct iw_statistics));
+		/* They won't be marked updated for the next time */
+		priv->local_iwstatistics.qual.updated = 0;
+		up(&priv->stats_sem);
+	} else
+		priv->iwstatistics.qual.updated = 0;
+
+	/* Update our wireless stats, but do not schedule to often 
+	 * (max 1 HZ) */
+	if ((priv->stats_timestamp == 0) ||
+	    time_after(jiffies, priv->stats_timestamp + 1 * HZ)) {
+		schedule_work(&priv->stats_work);
+		priv->stats_timestamp = jiffies;
+	}
+
+	return &priv->iwstatistics;
+}
+
+static int
+prism54_commit(struct net_device *ndev, struct iw_request_info *info,
+	       char *cwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+
+	/* simply re-set the last set SSID, this should commit most stuff */
+
+	/* Commit in Monitor mode is not necessary, also setting essid
+	 * in Monitor mode does not make sense and isn't allowed for this
+	 * device's firmware */
+	if(priv->iw_mode != IW_MODE_MONITOR)
+		return mgt_set_request(priv, DOT11_OID_SSID, 0, NULL);
+	return 0;
+}
+
+static int
+prism54_get_name(struct net_device *ndev, struct iw_request_info *info,
+		 char *cwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	char *capabilities;
+	union oid_res_t r;
+	int rvalue;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT) {
+		strncpy(cwrq, "NOT READY!", IFNAMSIZ);
+		return 0;
+	}
+	rvalue = mgt_get_request(priv, OID_INL_PHYCAPABILITIES, 0, NULL, &r);
+
+	switch (r.u) {
+	case INL_PHYCAP_5000MHZ:
+		capabilities = "IEEE 802.11a/b/g";
+		break;
+	case INL_PHYCAP_FAA:
+		capabilities = "IEEE 802.11b/g - FAA Support";
+		break;
+	case INL_PHYCAP_2400MHZ:
+	default:
+		capabilities = "IEEE 802.11b/g";	/* Default */
+		break;
+	}
+	strncpy(cwrq, capabilities, IFNAMSIZ);
+	return rvalue;
+}
+
+static int
+prism54_set_freq(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_freq *fwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	int rvalue;
+	u32 c = 0;
+
+	/* prepare the structure for the set object */
+	if (fwrq->m < 1000)
+		/* structure value contains a channel indication */
+		c = fwrq->m;
+	else {
+		/* structure contains a frequency indication and fwrq->e = 1 */
+		int f = fwrq->m / 100000;
+
+		if (fwrq->e != 1)
+			return -EINVAL;
+		if ((f >= 2412) && (f <= 2484)) {
+			while ((c < 14) && (f != frequency_list_bg[c]))
+				c++;
+			if (c >= 14)
+				return -EINVAL;
+		} else if ((f >= (int) 5170) && (f <= (int) 5320)) {
+			while ((c < 12) && (f != frequency_list_a[c]))
+				c++;
+			if (c >= 12)
+				return -EINVAL;
+		} else
+			return -EINVAL;
+		c++;
+	}
+
+	rvalue = mgt_set_request(priv, DOT11_OID_CHANNEL, 0, &c);
+
+	/* Call commit handler */
+	return (rvalue ? rvalue : -EINPROGRESS);
+}
+
+static int
+prism54_get_freq(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_freq *fwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	union oid_res_t r;
+	int rvalue;
+
+	rvalue = mgt_get_request(priv, DOT11_OID_CHANNEL, 0, NULL, &r);
+
+	fwrq->m = r.u;
+	fwrq->e = 0;
+
+	return rvalue;
+}
+
+static int
+prism54_set_mode(struct net_device *ndev, struct iw_request_info *info,
+		 __u32 * uwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	u32 mlmeautolevel = CARD_DEFAULT_MLME_MODE;
+
+	/* Let's see if the user passed a valid Linux Wireless mode */
+	if (*uwrq > IW_MODE_MONITOR || *uwrq < IW_MODE_AUTO) {
+		printk(KERN_DEBUG
+		       "%s: %s() You passed a non-valid init_mode.\n",
+		       priv->ndev->name, __FUNCTION__);
+		return -EINVAL;
+	}
+
+	down_write(&priv->mib_sem);
+
+	if (prism54_mib_mode_helper(priv, *uwrq)) {
+		up_write(&priv->mib_sem);
+		return -EOPNOTSUPP;
+	}
+
+	/* the ACL code needs an intermediate mlmeautolevel. The wpa stuff an
+	 * extended one.
+	 */
+	if ((*uwrq == IW_MODE_MASTER) && (priv->acl.policy != MAC_POLICY_OPEN))
+		mlmeautolevel = DOT11_MLME_INTERMEDIATE;
+	if (priv->wpa)
+		mlmeautolevel = DOT11_MLME_EXTENDED;
+
+	mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel);
+
+	mgt_commit(priv);
+	priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR)
+	    ? ARPHRD_IEEE80211 : ARPHRD_ETHER;
+	up_write(&priv->mib_sem);
+
+	return 0;
+}
+
+/* Use mib cache */
+static int
+prism54_get_mode(struct net_device *ndev, struct iw_request_info *info,
+		 __u32 * uwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+
+	BUG_ON((priv->iw_mode < IW_MODE_AUTO) || (priv->iw_mode >
+						  IW_MODE_MONITOR));
+	*uwrq = priv->iw_mode;
+
+	return 0;
+}
+
+/* we use DOT11_OID_EDTHRESHOLD. From what I guess the card will not try to
+ * emit data if (sensitivity > rssi - noise) (in dBm).
+ * prism54_set_sens does not seem to work.
+ */
+
+static int
+prism54_set_sens(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	u32 sens;
+
+	/* by default  the card sets this to 20. */
+	sens = vwrq->disabled ? 20 : vwrq->value;
+
+	/* set the ed threshold. */
+	return mgt_set_request(priv, DOT11_OID_EDTHRESHOLD, 0, &sens);
+}
+
+static int
+prism54_get_sens(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	union oid_res_t r;
+	int rvalue;
+
+	rvalue = mgt_get_request(priv, DOT11_OID_EDTHRESHOLD, 0, NULL, &r);
+
+	vwrq->value = r.u;
+	vwrq->disabled = (vwrq->value == 0);
+	vwrq->fixed = 1;
+
+	return rvalue;
+}
+
+static int
+prism54_get_range(struct net_device *ndev, struct iw_request_info *info,
+		  struct iw_point *dwrq, char *extra)
+{
+	struct iw_range *range = (struct iw_range *) extra;
+	islpci_private *priv = ndev->priv;
+	char *data;
+	int i, m, rvalue;
+	struct obj_frequencies *freq;
+	union oid_res_t r;
+
+	memset(range, 0, sizeof (struct iw_range));
+	dwrq->length = sizeof (struct iw_range);
+
+	/* set the wireless extension version number */
+	range->we_version_source = SUPPORTED_WIRELESS_EXT;
+	range->we_version_compiled = WIRELESS_EXT;
+
+	/* Now the encoding capabilities */
+	range->num_encoding_sizes = 3;
+	/* 64(40) bits WEP */
+	range->encoding_size[0] = 5;
+	/* 128(104) bits WEP */
+	range->encoding_size[1] = 13;
+	/* 256 bits for WPA-PSK */
+	range->encoding_size[2] = 32;
+	/* 4 keys are allowed */
+	range->max_encoding_tokens = 4;
+
+	/* we don't know the quality range... */
+	range->max_qual.level = 0;
+	range->max_qual.noise = 0;
+	range->max_qual.qual = 0;
+	/* these value describe an average quality. Needs more tweaking... */
+	range->avg_qual.level = -80;	/* -80 dBm */
+	range->avg_qual.noise = 0;	/* don't know what to put here */
+	range->avg_qual.qual = 0;
+
+	range->sensitivity = 200;
+
+	/* retry limit capabilities */
+	range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
+	range->retry_flags = IW_RETRY_LIMIT;
+	range->r_time_flags = IW_RETRY_LIFETIME;
+
+	/* I don't know the range. Put stupid things here */
+	range->min_retry = 1;
+	range->max_retry = 65535;
+	range->min_r_time = 1024;
+	range->max_r_time = 65535 * 1024;
+
+	/* txpower is supported in dBm's */
+	range->txpower_capa = IW_TXPOW_DBM;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT)
+		return 0;
+
+	/* Request the device for the supported frequencies
+	 * not really revelant since some devices will report the 5 GHz band
+	 * frequencies even if they don't support them.
+	 */
+	rvalue =
+	    mgt_get_request(priv, DOT11_OID_SUPPORTEDFREQUENCIES, 0, NULL, &r);
+	freq = r.ptr;
+
+	range->num_channels = le16_to_cpu(freq->nr);
+	range->num_frequency = le16_to_cpu(freq->nr);
+
+	/* Frequencies are not listed in the right order. The reordering is probably
+	 * firmware dependant and thus should work for everyone.
+	 */
+	m = min(IW_MAX_FREQUENCIES, (int) le16_to_cpu(freq->nr));
+	for (i = 0; i < m - 12; i++) {
+		range->freq[i].m = le16_to_cpu(freq->mhz[12 + i]);
+		range->freq[i].e = 6;
+		range->freq[i].i = i + 1;
+	}
+	for (i = m - 12; i < m; i++) {
+		range->freq[i].m = le16_to_cpu(freq->mhz[i - m + 12]);
+		range->freq[i].e = 6;
+		range->freq[i].i = i + 23;
+	}
+
+	kfree(freq);
+
+	rvalue |= mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r);
+	data = r.ptr;
+
+	/* We got an array of char. It is NULL terminated. */
+	i = 0;
+	while ((i < IW_MAX_BITRATES) && (*data != 0)) {
+		/*       the result must be in bps. The card gives us 500Kbps */
+		range->bitrate[i] = (__s32) (*data >> 1);
+		range->bitrate[i] *= 1000000;
+		i++;
+		data++;
+	}
+
+	range->num_bitrates = i;
+
+	kfree(r.ptr);
+
+	return rvalue;
+}
+
+/* Set AP address*/
+
+static int
+prism54_set_wap(struct net_device *ndev, struct iw_request_info *info,
+		struct sockaddr *awrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	char bssid[6];
+	int rvalue;
+
+	if (awrq->sa_family != ARPHRD_ETHER)
+		return -EINVAL;
+
+	/* prepare the structure for the set object */
+	memcpy(&bssid[0], awrq->sa_data, 6);
+
+	/* set the bssid -- does this make sense when in AP mode? */
+	rvalue = mgt_set_request(priv, DOT11_OID_BSSID, 0, &bssid);
+
+	return (rvalue ? rvalue : -EINPROGRESS);	/* Call commit handler */
+}
+
+/* get AP address*/
+
+static int
+prism54_get_wap(struct net_device *ndev, struct iw_request_info *info,
+		struct sockaddr *awrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	union oid_res_t r;
+	int rvalue;
+
+	rvalue = mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r);
+
+	memcpy(awrq->sa_data, r.ptr, 6);
+	awrq->sa_family = ARPHRD_ETHER;
+	kfree(r.ptr);
+
+	return rvalue;
+}
+
+static int
+prism54_set_scan(struct net_device *dev, struct iw_request_info *info,
+		 struct iw_param *vwrq, char *extra)
+{
+	/* hehe the device does this automagicaly */
+	return 0;
+}
+
+/* a little helper that will translate our data into a card independent
+ * format that the Wireless Tools will understand. This was inspired by
+ * the "Aironet driver for 4500 and 4800 series cards" (GPL)
+ */
+
+inline char *
+prism54_translate_bss(struct net_device *ndev, char *current_ev,
+		      char *end_buf, struct obj_bss *bss, char noise)
+{
+	struct iw_event iwe;	/* Temporary buffer */
+	short cap;
+	islpci_private *priv = ndev->priv;
+
+	/* The first entry must be the MAC address */
+	memcpy(iwe.u.ap_addr.sa_data, bss->address, 6);
+	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+	iwe.cmd = SIOCGIWAP;
+	current_ev =
+	    iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
+
+	/* The following entries will be displayed in the same order we give them */
+
+	/* The ESSID. */
+	iwe.u.data.length = bss->ssid.length;
+	iwe.u.data.flags = 1;
+	iwe.cmd = SIOCGIWESSID;
+	current_ev = iwe_stream_add_point(current_ev, end_buf,
+					  &iwe, bss->ssid.octets);
+
+	/* Capabilities */
+#define CAP_ESS 0x01
+#define CAP_IBSS 0x02
+#define CAP_CRYPT 0x10
+
+	/* Mode */
+	cap = le16_to_cpu(bss->capinfo);
+	iwe.u.mode = 0;
+	if (cap & CAP_ESS)
+		iwe.u.mode = IW_MODE_MASTER;
+	else if (cap & CAP_IBSS)
+		iwe.u.mode = IW_MODE_ADHOC;
+	iwe.cmd = SIOCGIWMODE;
+	if (iwe.u.mode)
+		current_ev =
+		    iwe_stream_add_event(current_ev, end_buf, &iwe,
+					 IW_EV_UINT_LEN);
+
+	/* Encryption capability */
+	if (cap & CAP_CRYPT)
+		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+	else
+		iwe.u.data.flags = IW_ENCODE_DISABLED;
+	iwe.u.data.length = 0;
+	iwe.cmd = SIOCGIWENCODE;
+	current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL);
+
+	/* Add frequency. (short) bss->channel is the frequency in MHz */
+	iwe.u.freq.m = bss->channel;
+	iwe.u.freq.e = 6;
+	iwe.cmd = SIOCGIWFREQ;
+	current_ev =
+	    iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
+
+	/* Add quality statistics */
+	iwe.u.qual.level = bss->rssi;
+	iwe.u.qual.noise = noise;
+	/* do a simple SNR for quality */
+	iwe.u.qual.qual = bss->rssi - noise;
+	iwe.cmd = IWEVQUAL;
+	current_ev =
+	    iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
+
+	if (priv->wpa) {
+		u8 wpa_ie[MAX_WPA_IE_LEN];
+		char *buf, *p;
+		size_t wpa_ie_len;
+		int i;
+
+		wpa_ie_len = prism54_wpa_ie_get(priv, bss->address, wpa_ie);
+		if (wpa_ie_len > 0 &&
+		    (buf = kmalloc(wpa_ie_len * 2 + 10, GFP_ATOMIC))) {
+			p = buf;
+			p += sprintf(p, "wpa_ie=");
+			for (i = 0; i < wpa_ie_len; i++) {
+				p += sprintf(p, "%02x", wpa_ie[i]);
+			}
+			memset(&iwe, 0, sizeof (iwe));
+			iwe.cmd = IWEVCUSTOM;
+			iwe.u.data.length = strlen(buf);
+			current_ev = iwe_stream_add_point(current_ev, end_buf,
+							  &iwe, buf);
+			kfree(buf);
+		}
+	}
+
+	return current_ev;
+}
+
+int
+prism54_get_scan(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_point *dwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	int i, rvalue;
+	struct obj_bsslist *bsslist;
+	u32 noise = 0;
+	char *current_ev = extra;
+	union oid_res_t r;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT) {
+		/* device is not ready, fail gently */
+		dwrq->length = 0;
+		return 0;
+	}
+
+	/* first get the noise value. We will use it to report the link quality */
+	rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
+	noise = r.u;
+
+	/* Ask the device for a list of known bss. We can report at most
+	 * IW_MAX_AP=64 to the range struct. But the device won't repport anything
+	 * if you change the value of MAXBSS=24. Anyway 24 AP It is probably enough.
+	 */
+	rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
+	bsslist = r.ptr;
+
+	/* ok now, scan the list and translate its info */
+	for (i = 0; i < min(IW_MAX_AP, (int) le32_to_cpu(bsslist->nr)); i++)
+		current_ev = prism54_translate_bss(ndev, current_ev,
+						   extra + IW_SCAN_MAX_DATA,
+						   &(bsslist->bsslist[i]),
+						   noise);
+	kfree(bsslist);
+	dwrq->length = (current_ev - extra);
+	dwrq->flags = 0;	/* todo */
+
+	return rvalue;
+}
+
+static int
+prism54_set_essid(struct net_device *ndev, struct iw_request_info *info,
+		  struct iw_point *dwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	struct obj_ssid essid;
+
+	memset(essid.octets, 0, 33);
+
+	/* Check if we were asked for `any' */
+	if (dwrq->flags && dwrq->length) {
+		if (dwrq->length > min(33, IW_ESSID_MAX_SIZE + 1))
+			return -E2BIG;
+		essid.length = dwrq->length - 1;
+		memcpy(essid.octets, extra, dwrq->length);
+	} else
+		essid.length = 0;
+	
+	if (priv->iw_mode != IW_MODE_MONITOR)
+		return mgt_set_request(priv, DOT11_OID_SSID, 0, &essid);
+
+	/* If in monitor mode, just save to mib */
+	mgt_set(priv, DOT11_OID_SSID, &essid);
+	return 0;
+
+}
+
+static int
+prism54_get_essid(struct net_device *ndev, struct iw_request_info *info,
+		  struct iw_point *dwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	struct obj_ssid *essid;
+	union oid_res_t r;
+	int rvalue;
+
+	rvalue = mgt_get_request(priv, DOT11_OID_SSID, 0, NULL, &r);
+	essid = r.ptr;
+
+	if (essid->length) {
+		dwrq->flags = 1;	/* set ESSID to ON for Wireless Extensions */
+		/* if it is to big, trunk it */
+		dwrq->length = min(IW_ESSID_MAX_SIZE, essid->length + 1);
+	} else {
+		dwrq->flags = 0;
+		dwrq->length = 0;
+	}
+	essid->octets[essid->length] = '\0';
+	memcpy(extra, essid->octets, dwrq->length);
+	kfree(essid);
+
+	return rvalue;
+}
+
+/* Provides no functionality, just completes the ioctl. In essence this is a 
+ * just a cosmetic ioctl.
+ */
+static int
+prism54_set_nick(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_point *dwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+
+	if (dwrq->length > IW_ESSID_MAX_SIZE)
+		return -E2BIG;
+
+	down_write(&priv->mib_sem);
+	memset(priv->nickname, 0, sizeof (priv->nickname));
+	memcpy(priv->nickname, extra, dwrq->length);
+	up_write(&priv->mib_sem);
+
+	return 0;
+}
+
+static int
+prism54_get_nick(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_point *dwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+
+	dwrq->length = 0;
+
+	down_read(&priv->mib_sem);
+	dwrq->length = strlen(priv->nickname) + 1;
+	memcpy(extra, priv->nickname, dwrq->length);
+	up_read(&priv->mib_sem);
+
+	return 0;
+}
+
+/* Set the allowed Bitrates */
+
+static int
+prism54_set_rate(struct net_device *ndev,
+		 struct iw_request_info *info,
+		 struct iw_param *vwrq, char *extra)
+{
+
+	islpci_private *priv = ndev->priv;
+	u32 rate, profile;
+	char *data;
+	int ret, i;
+	union oid_res_t r;
+	
+	if (vwrq->value == -1) {
+		/* auto mode. No limit. */
+		profile = 1;
+		return mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
+	}
+	
+	if((ret = mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r)))
+		return ret;
+		
+	rate = (u32) (vwrq->value / 500000);
+	data = r.ptr;
+	i = 0;
+	
+	while(data[i]) {
+		if(rate && (data[i] == rate)) {
+			break;
+		}
+		if(vwrq->value == i) {
+			break;
+		}
+		data[i] |= 0x80;
+		i++;
+	}
+		
+	if(!data[i]) {
+		return -EINVAL;
+	}
+	
+	data[i] |= 0x80;
+	data[i + 1] = 0;
+	
+	/* Now, check if we want a fixed or auto value */
+	if (vwrq->fixed) {
+		data[0] = data[i];
+		data[1] = 0;
+	}
+
+/*
+	i = 0;
+	printk("prism54 rate: ");
+	while(data[i]) {
+		printk("%u ", data[i]);
+		i++;
+	}
+	printk("0\n");
+*/	
+	profile = -1;
+	ret = mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
+	ret |= mgt_set_request(priv, DOT11_OID_EXTENDEDRATES, 0, data);
+	ret |= mgt_set_request(priv, DOT11_OID_RATES, 0, data);
+	
+	kfree(r.ptr);
+	
+	return ret;
+}
+
+/* Get the current bit rate */
+static int
+prism54_get_rate(struct net_device *ndev,
+		 struct iw_request_info *info,
+		 struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	int rvalue;
+	char *data;
+	union oid_res_t r;
+
+	/* Get the current bit rate */
+	if((rvalue = mgt_get_request(priv, GEN_OID_LINKSTATE, 0, NULL, &r)))
+		return rvalue;
+	vwrq->value = r.u * 500000;
+
+	/* request the device for the enabled rates */
+	if((rvalue = mgt_get_request(priv, DOT11_OID_RATES, 0, NULL, &r)))
+		return rvalue;
+	data = r.ptr;
+	vwrq->fixed = (data[0] != 0) && (data[1] == 0);
+	kfree(r.ptr);
+	
+	return 0;
+}
+
+static int
+prism54_set_rts(struct net_device *ndev, struct iw_request_info *info,
+		struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+
+	return mgt_set_request(priv, DOT11_OID_RTSTHRESH, 0, &vwrq->value);
+}
+
+static int
+prism54_get_rts(struct net_device *ndev, struct iw_request_info *info,
+		struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	union oid_res_t r;
+	int rvalue;
+
+	/* get the rts threshold */
+	rvalue = mgt_get_request(priv, DOT11_OID_RTSTHRESH, 0, NULL, &r);
+	vwrq->value = r.u;
+
+	return rvalue;
+}
+
+static int
+prism54_set_frag(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+
+	return mgt_set_request(priv, DOT11_OID_FRAGTHRESH, 0, &vwrq->value);
+}
+
+static int
+prism54_get_frag(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	union oid_res_t r;
+	int rvalue;
+
+	rvalue = mgt_get_request(priv, DOT11_OID_FRAGTHRESH, 0, NULL, &r);
+	vwrq->value = r.u;
+
+	return rvalue;
+}
+
+/* Here we have (min,max) = max retries for (small frames, big frames). Where
+ * big frame <=>  bigger than the rts threshold
+ * small frame <=>  smaller than the rts threshold
+ * This is not really the behavior expected by the wireless tool but it seems
+ * to be a common behavior in other drivers.
+ * 
+ * It seems that playing with this tends to hang the card -> DISABLED
+ */
+
+static int
+prism54_set_retry(struct net_device *ndev, struct iw_request_info *info,
+		  struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	u32 slimit = 0, llimit = 0;	/* short and long limit */
+	u32 lifetime = 0;
+	int rvalue = 0;
+
+	if (vwrq->disabled)
+		/* we cannot disable this feature */
+		return -EINVAL;
+
+	if (vwrq->flags & IW_RETRY_LIMIT) {
+		if (vwrq->flags & IW_RETRY_MIN)
+			slimit = vwrq->value;
+		else if (vwrq->flags & IW_RETRY_MAX)
+			llimit = vwrq->value;
+		else {
+			/* we are asked to set both */
+			slimit = vwrq->value;
+			llimit = vwrq->value;
+		}
+	}
+	if (vwrq->flags & IW_RETRY_LIFETIME)
+		/* Wireless tools use us unit while the device uses 1024 us unit */
+		lifetime = vwrq->value / 1024;
+
+	/* now set what is requested */
+
+	if (slimit != 0)
+		rvalue =
+		    mgt_set_request(priv, DOT11_OID_SHORTRETRIES, 0, &slimit);
+	if (llimit != 0)
+		rvalue |=
+		    mgt_set_request(priv, DOT11_OID_LONGRETRIES, 0, &llimit);
+	if (lifetime != 0)
+		rvalue |=
+		    mgt_set_request(priv, DOT11_OID_MAXTXLIFETIME, 0,
+				    &lifetime);
+
+	return rvalue;
+}
+
+static int
+prism54_get_retry(struct net_device *ndev, struct iw_request_info *info,
+		  struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	union oid_res_t r;
+	int rvalue = 0;
+	vwrq->disabled = 0;	/* It cannot be disabled */
+
+	if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+		/* we are asked for the life time */
+		rvalue =
+		    mgt_get_request(priv, DOT11_OID_MAXTXLIFETIME, 0, NULL, &r);
+		vwrq->value = r.u * 1024;
+		vwrq->flags = IW_RETRY_LIFETIME;
+	} else if ((vwrq->flags & IW_RETRY_MAX)) {
+		/* we are asked for the long retry limit */
+		rvalue |=
+		    mgt_get_request(priv, DOT11_OID_LONGRETRIES, 0, NULL, &r);
+		vwrq->value = r.u;
+		vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+	} else {
+		/* default. get the  short retry limit */
+		rvalue |=
+		    mgt_get_request(priv, DOT11_OID_SHORTRETRIES, 0, NULL, &r);
+		vwrq->value = r.u;
+		vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
+	}
+
+	return rvalue;
+}
+
+static int
+prism54_set_encode(struct net_device *ndev, struct iw_request_info *info,
+		   struct iw_point *dwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	int rvalue = 0, force = 0;
+	int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
+	union oid_res_t r;
+
+	/* with the new API, it's impossible to get a NULL pointer.
+	 * New version of iwconfig set the IW_ENCODE_NOKEY flag
+	 * when no key is given, but older versions don't. */
+
+	if (dwrq->length > 0) {
+		/* we have a key to set */
+		int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+		int current_index;
+		struct obj_key key = { DOT11_PRIV_WEP, 0, "" };
+
+		/* get the current key index */
+		rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
+		current_index = r.u;
+		/* Verify that the key is not marked as invalid */
+		if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
+			key.length = dwrq->length > sizeof (key.key) ?
+			    sizeof (key.key) : dwrq->length;
+			memcpy(key.key, extra, key.length);
+			if (key.length == 32)
+				/* we want WPA-PSK */
+				key.type = DOT11_PRIV_TKIP;
+			if ((index < 0) || (index > 3))
+				/* no index provided use the current one */
+				index = current_index;
+
+			/* now send the key to the card  */
+			rvalue |=
+			    mgt_set_request(priv, DOT11_OID_DEFKEYX, index,
+					    &key);
+		}
+		/*
+		 * If a valid key is set, encryption should be enabled 
+		 * (user may turn it off later).
+		 * This is also how "iwconfig ethX key on" works
+		 */
+		if ((index == current_index) && (key.length > 0))
+			force = 1;
+	} else {
+		int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+		if ((index >= 0) && (index <= 3)) {
+			/* we want to set the key index */
+			rvalue |=
+			    mgt_set_request(priv, DOT11_OID_DEFKEYID, 0,
+					    &index);
+		} else {
+			if (!dwrq->flags & IW_ENCODE_MODE) {
+				/* we cannot do anything. Complain. */
+				return -EINVAL;
+			}
+		}
+	}
+
+	/* now read the flags     */
+	if (dwrq->flags & IW_ENCODE_DISABLED) {
+		/* Encoding disabled, 
+		 * authen = DOT11_AUTH_OS;
+		 * invoke = 0;
+		 * exunencrypt = 0; */
+	}
+	if (dwrq->flags & IW_ENCODE_OPEN)
+		/* Encode but accept non-encoded packets. No auth */
+		invoke = 1;
+	if ((dwrq->flags & IW_ENCODE_RESTRICTED) || force) {
+		/* Refuse non-encoded packets. Auth */
+		authen = DOT11_AUTH_BOTH;
+		invoke = 1;
+		exunencrypt = 1;
+	}
+	/* do the change if requested  */
+	if ((dwrq->flags & IW_ENCODE_MODE) || force) {
+		rvalue |=
+		    mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
+		rvalue |=
+		    mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke);
+		rvalue |=
+		    mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
+				    &exunencrypt);
+	}
+	return rvalue;
+}
+
+static int
+prism54_get_encode(struct net_device *ndev, struct iw_request_info *info,
+		   struct iw_point *dwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	struct obj_key *key;
+	u32 devindex, index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+	u32 authen = 0, invoke = 0, exunencrypt = 0;
+	int rvalue;
+	union oid_res_t r;
+
+	/* first get the flags */
+	rvalue = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
+	authen = r.u;
+	rvalue |= mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
+	invoke = r.u;
+	rvalue |= mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
+	exunencrypt = r.u;
+
+	if (invoke && (authen == DOT11_AUTH_BOTH) && exunencrypt)
+		dwrq->flags = IW_ENCODE_RESTRICTED;
+	else if ((authen == DOT11_AUTH_OS) && !exunencrypt) {
+		if (invoke)
+			dwrq->flags = IW_ENCODE_OPEN;
+		else
+			dwrq->flags = IW_ENCODE_DISABLED;
+	} else
+		/* The card should not work in this state */
+		dwrq->flags = 0;
+
+	/* get the current device key index */
+	rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
+	devindex = r.u;
+	/* Now get the key, return it */
+	if ((index < 0) || (index > 3))
+		/* no index provided, use the current one */
+		index = devindex;
+	rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYX, index, NULL, &r);
+	key = r.ptr;
+	dwrq->length = key->length;
+	memcpy(extra, key->key, dwrq->length);
+	kfree(key);
+	/* return the used key index */
+	dwrq->flags |= devindex + 1;
+
+	return rvalue;
+}
+
+static int
+prism54_get_txpower(struct net_device *ndev, struct iw_request_info *info,
+		    struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	union oid_res_t r;
+	int rvalue;
+
+	rvalue = mgt_get_request(priv, OID_INL_OUTPUTPOWER, 0, NULL, &r);
+	/* intersil firmware operates in 0.25 dBm (1/4 dBm) */
+	vwrq->value = (s32)r.u / 4;
+	vwrq->fixed = 1;
+	/* radio is not turned of
+	 * btw: how is possible to turn off only the radio 
+	 */
+	vwrq->disabled = 0;
+
+	return rvalue;
+}
+
+static int
+prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info,
+		    struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	s32 u = vwrq->value;
+
+	/* intersil firmware operates in 0.25 dBm (1/4) */
+	u *= 4;
+	if (vwrq->disabled) {
+		/* don't know how to disable radio */
+		printk(KERN_DEBUG
+		       "%s: %s() disabling radio is not yet supported.\n",
+		       priv->ndev->name, __FUNCTION__);
+		return -ENOTSUPP;
+	} else if (vwrq->fixed)
+		/* currently only fixed value is supported */
+		return mgt_set_request(priv, OID_INL_OUTPUTPOWER, 0, &u);
+	else {
+		printk(KERN_DEBUG
+		       "%s: %s() auto power will be implemented later.\n",
+		       priv->ndev->name, __FUNCTION__);
+		return -ENOTSUPP;
+	}
+}
+
+static int
+prism54_reset(struct net_device *ndev, struct iw_request_info *info,
+	      __u32 * uwrq, char *extra)
+{
+	islpci_reset(ndev->priv, 0);
+
+	return 0;
+}
+
+static int
+prism54_set_beacon(struct net_device *ndev, struct iw_request_info *info,
+		   __u32 * uwrq, char *extra)
+{
+	int rvalue = mgt_set_request((islpci_private *) ndev->priv,
+				     DOT11_OID_BEACONPERIOD, 0, uwrq);
+
+	return (rvalue ? rvalue : -EINPROGRESS);
+}
+
+static int
+prism54_get_beacon(struct net_device *ndev, struct iw_request_info *info,
+		   __u32 * uwrq, char *extra)
+{
+	union oid_res_t r;
+	int rvalue;
+
+	rvalue =
+	    mgt_get_request((islpci_private *) ndev->priv,
+			    DOT11_OID_BEACONPERIOD, 0, NULL, &r);
+	*uwrq = r.u;
+
+	return rvalue;
+}
+
+void
+prism54_acl_init(struct islpci_acl *acl)
+{
+	sema_init(&acl->sem, 1);
+	INIT_LIST_HEAD(&acl->mac_list);
+	acl->size = 0;
+	acl->policy = MAC_POLICY_OPEN;
+}
+
+static void
+prism54_clear_mac(struct islpci_acl *acl)
+{
+	struct list_head *ptr, *next;
+	struct mac_entry *entry;
+
+	if (down_interruptible(&acl->sem))
+		return;
+
+	if (acl->size == 0) {
+		up(&acl->sem);
+		return;
+	}
+
+	for (ptr = acl->mac_list.next, next = ptr->next;
+	     ptr != &acl->mac_list; ptr = next, next = ptr->next) {
+		entry = list_entry(ptr, struct mac_entry, _list);
+		list_del(ptr);
+		kfree(entry);
+	}
+	acl->size = 0;
+	up(&acl->sem);
+}
+
+void
+prism54_acl_clean(struct islpci_acl *acl)
+{
+	prism54_clear_mac(acl);
+}
+
+static int
+prism54_add_mac(struct net_device *ndev, struct iw_request_info *info,
+		struct sockaddr *awrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	struct islpci_acl *acl = &priv->acl;
+	struct mac_entry *entry;
+	struct sockaddr *addr = (struct sockaddr *) extra;
+
+	if (addr->sa_family != ARPHRD_ETHER)
+		return -EOPNOTSUPP;
+
+	entry = kmalloc(sizeof (struct mac_entry), GFP_KERNEL);
+	if (entry == NULL)
+		return -ENOMEM;
+
+	memcpy(entry->addr, addr->sa_data, ETH_ALEN);
+
+	if (down_interruptible(&acl->sem)) {
+		kfree(entry);
+		return -ERESTARTSYS;
+	}
+	list_add_tail(&entry->_list, &acl->mac_list);
+	acl->size++;
+	up(&acl->sem);
+
+	return 0;
+}
+
+static int
+prism54_del_mac(struct net_device *ndev, struct iw_request_info *info,
+		struct sockaddr *awrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	struct islpci_acl *acl = &priv->acl;
+	struct mac_entry *entry;
+	struct list_head *ptr;
+	struct sockaddr *addr = (struct sockaddr *) extra;
+
+	if (addr->sa_family != ARPHRD_ETHER)
+		return -EOPNOTSUPP;
+
+	if (down_interruptible(&acl->sem))
+		return -ERESTARTSYS;
+	for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) {
+		entry = list_entry(ptr, struct mac_entry, _list);
+
+		if (memcmp(entry->addr, addr->sa_data, ETH_ALEN) == 0) {
+			list_del(ptr);
+			acl->size--;
+			kfree(entry);
+			up(&acl->sem);
+			return 0;
+		}
+	}
+	up(&acl->sem);
+	return -EINVAL;
+}
+
+static int
+prism54_get_mac(struct net_device *ndev, struct iw_request_info *info,
+		struct iw_point *dwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	struct islpci_acl *acl = &priv->acl;
+	struct mac_entry *entry;
+	struct list_head *ptr;
+	struct sockaddr *dst = (struct sockaddr *) extra;
+
+	dwrq->length = 0;
+
+	if (down_interruptible(&acl->sem))
+		return -ERESTARTSYS;
+
+	for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) {
+		entry = list_entry(ptr, struct mac_entry, _list);
+
+		memcpy(dst->sa_data, entry->addr, ETH_ALEN);
+		dst->sa_family = ARPHRD_ETHER;
+		dwrq->length++;
+		dst++;
+	}
+	up(&acl->sem);
+	return 0;
+}
+
+/* Setting policy also clears the MAC acl, even if we don't change the defaut
+ * policy
+ */
+
+static int
+prism54_set_policy(struct net_device *ndev, struct iw_request_info *info,
+		   __u32 * uwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	struct islpci_acl *acl = &priv->acl;
+	u32 mlmeautolevel;
+
+	prism54_clear_mac(acl);
+
+	if ((*uwrq < MAC_POLICY_OPEN) || (*uwrq > MAC_POLICY_REJECT))
+		return -EINVAL;
+
+	down_write(&priv->mib_sem);
+
+	acl->policy = *uwrq;
+
+	/* the ACL code needs an intermediate mlmeautolevel */
+	if ((priv->iw_mode == IW_MODE_MASTER) &&
+	    (acl->policy != MAC_POLICY_OPEN))
+		mlmeautolevel = DOT11_MLME_INTERMEDIATE;
+	else
+		mlmeautolevel = CARD_DEFAULT_MLME_MODE;
+	if (priv->wpa)
+		mlmeautolevel = DOT11_MLME_EXTENDED;
+	mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel);
+	/* restart the card with our new policy */
+	mgt_commit(priv);
+	up_write(&priv->mib_sem);
+
+	return 0;
+}
+
+static int
+prism54_get_policy(struct net_device *ndev, struct iw_request_info *info,
+		   __u32 * uwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	struct islpci_acl *acl = &priv->acl;
+
+	*uwrq = acl->policy;
+
+	return 0;
+}
+
+/* Return 1 only if client should be accepted. */
+
+static int
+prism54_mac_accept(struct islpci_acl *acl, char *mac)
+{
+	struct list_head *ptr;
+	struct mac_entry *entry;
+	int res = 0;
+
+	if (down_interruptible(&acl->sem))
+		return -ERESTARTSYS;
+
+	if (acl->policy == MAC_POLICY_OPEN) {
+		up(&acl->sem);
+		return 1;
+	}
+
+	for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) {
+		entry = list_entry(ptr, struct mac_entry, _list);
+		if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {
+			res = 1;
+			break;
+		}
+	}
+	res = (acl->policy == MAC_POLICY_ACCEPT) ? !res : res;
+	up(&acl->sem);
+
+	return res;
+}
+
+static int
+prism54_kick_all(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_point *dwrq, char *extra)
+{
+	struct obj_mlme *mlme;
+	int rvalue;
+
+	mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL);
+	if (mlme == NULL)
+		return -ENOMEM;
+
+	/* Tell the card to kick every client */
+	mlme->id = cpu_to_le16(0);
+	rvalue = mgt_set_request(ndev->priv, DOT11_OID_DISASSOCIATE, 0, mlme);
+	kfree(mlme);
+
+	return rvalue;
+}
+
+static int
+prism54_kick_mac(struct net_device *ndev, struct iw_request_info *info,
+		 struct sockaddr *awrq, char *extra)
+{
+	struct obj_mlme *mlme;
+	struct sockaddr *addr = (struct sockaddr *) extra;
+	int rvalue;
+
+	if (addr->sa_family != ARPHRD_ETHER)
+		return -EOPNOTSUPP;
+
+	mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL);
+	if (mlme == NULL)
+		return -ENOMEM;
+
+	/* Tell the card to only kick the corresponding bastard */
+	memcpy(mlme->address, addr->sa_data, ETH_ALEN);
+	mlme->id = cpu_to_le16(-1);
+	rvalue = mgt_set_request(ndev->priv, DOT11_OID_DISASSOCIATE, 0, mlme);
+
+	kfree(mlme);
+
+	return rvalue;
+}
+
+/* Translate a TRAP oid into a wireless event. Called in islpci_mgt_receive. */
+
+static inline void
+format_event(islpci_private *priv, char *dest, const char *str,
+	     const struct obj_mlme *mlme, u16 *length, int error)
+{
+	const u8 *a = mlme->address;
+	int n = snprintf(dest, IW_CUSTOM_MAX,
+			 "%s %s %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X %s",
+			 str,
+			 ((priv->iw_mode == IW_MODE_MASTER) ? "to" : "from"),
+			 a[0], a[1], a[2], a[3], a[4], a[5],
+			 (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ")
+			  : ""));
+	BUG_ON(n > IW_CUSTOM_MAX);
+	*length = n;
+}
+
+static void
+send_formatted_event(islpci_private *priv, const char *str,
+		     const struct obj_mlme *mlme, int error)
+{
+	union iwreq_data wrqu;
+
+	wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
+	if (!wrqu.data.pointer)
+		return;
+	wrqu.data.length = 0;
+	format_event(priv, wrqu.data.pointer, str, mlme, &wrqu.data.length,
+		     error);
+	wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer);
+	kfree(wrqu.data.pointer);
+}
+
+static void
+send_simple_event(islpci_private *priv, const char *str)
+{
+	union iwreq_data wrqu;
+	int n = strlen(str);
+
+	wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
+	if (!wrqu.data.pointer)
+		return;
+	BUG_ON(n > IW_CUSTOM_MAX);
+	wrqu.data.length = n;
+	strcpy(wrqu.data.pointer, str);
+	wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer);
+	kfree(wrqu.data.pointer);
+}
+
+static void
+link_changed(struct net_device *ndev, u32 bitrate)
+{
+	islpci_private *priv = ndev->priv;
+
+	if (le32_to_cpu(bitrate)) {
+		if (priv->iw_mode == IW_MODE_INFRA) {
+			union iwreq_data uwrq;
+			prism54_get_wap(ndev, NULL, (struct sockaddr *) &uwrq,
+					NULL);
+			wireless_send_event(ndev, SIOCGIWAP, &uwrq, NULL);
+		} else
+			send_simple_event(ndev->priv, "Link established");
+	} else
+		send_simple_event(ndev->priv, "Link lost");
+}
+
+/* Beacon/ProbeResp payload header */
+struct ieee80211_beacon_phdr {
+	u8 timestamp[8];
+	u16 beacon_int;
+	u16 capab_info;
+} __attribute__ ((packed));
+
+#define WLAN_EID_GENERIC 0xdd
+static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 };
+
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+
+void
+prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
+		   u8 *wpa_ie, size_t wpa_ie_len)
+{
+	struct list_head *ptr;
+	struct islpci_bss_wpa_ie *bss = NULL;
+
+	if (wpa_ie_len > MAX_WPA_IE_LEN)
+		wpa_ie_len = MAX_WPA_IE_LEN;
+
+	if (down_interruptible(&priv->wpa_sem))
+		return;
+
+	/* try to use existing entry */
+	list_for_each(ptr, &priv->bss_wpa_list) {
+		bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
+		if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) {
+			list_move(&bss->list, &priv->bss_wpa_list);
+			break;
+		}
+		bss = NULL;
+	}
+
+	if (bss == NULL) {
+		/* add a new BSS entry; if max number of entries is already
+		 * reached, replace the least recently updated */
+		if (priv->num_bss_wpa >= MAX_BSS_WPA_IE_COUNT) {
+			bss = list_entry(priv->bss_wpa_list.prev,
+					 struct islpci_bss_wpa_ie, list);
+			list_del(&bss->list);
+		} else {
+			bss = kmalloc(sizeof (*bss), GFP_ATOMIC);
+			if (bss != NULL) {
+				priv->num_bss_wpa++;
+				memset(bss, 0, sizeof (*bss));
+			}
+		}
+		if (bss != NULL) {
+			memcpy(bss->bssid, bssid, ETH_ALEN);
+			list_add(&bss->list, &priv->bss_wpa_list);
+		}
+	}
+
+	if (bss != NULL) {
+		memcpy(bss->wpa_ie, wpa_ie, wpa_ie_len);
+		bss->wpa_ie_len = wpa_ie_len;
+		bss->last_update = jiffies;
+	} else {
+		printk(KERN_DEBUG "Failed to add BSS WPA entry for " MACSTR
+		       "\n", MAC2STR(bssid));
+	}
+
+	/* expire old entries from WPA list */
+	while (priv->num_bss_wpa > 0) {
+		bss = list_entry(priv->bss_wpa_list.prev,
+				 struct islpci_bss_wpa_ie, list);
+		if (!time_after(jiffies, bss->last_update + 60 * HZ))
+			break;
+
+		list_del(&bss->list);
+		priv->num_bss_wpa--;
+		kfree(bss);
+	}
+
+	up(&priv->wpa_sem);
+}
+
+size_t
+prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
+{
+	struct list_head *ptr;
+	struct islpci_bss_wpa_ie *bss = NULL;
+	size_t len = 0;
+
+	if (down_interruptible(&priv->wpa_sem))
+		return 0;
+
+	list_for_each(ptr, &priv->bss_wpa_list) {
+		bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
+		if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
+			break;
+		bss = NULL;
+	}
+	if (bss) {
+		len = bss->wpa_ie_len;
+		memcpy(wpa_ie, bss->wpa_ie, len);
+	}
+	up(&priv->wpa_sem);
+
+	return len;
+}
+
+void
+prism54_wpa_ie_init(islpci_private *priv)
+{
+	INIT_LIST_HEAD(&priv->bss_wpa_list);
+	sema_init(&priv->wpa_sem, 1);
+}
+
+void
+prism54_wpa_ie_clean(islpci_private *priv)
+{
+	struct list_head *ptr, *n;
+
+	list_for_each_safe(ptr, n, &priv->bss_wpa_list) {
+		struct islpci_bss_wpa_ie *bss;
+		bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
+		kfree(bss);
+	}
+}
+
+static void
+prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr,
+			 u8 *payload, size_t len)
+{
+	struct ieee80211_beacon_phdr *hdr;
+	u8 *pos, *end;
+
+	if (!priv->wpa)
+		return;
+
+	hdr = (struct ieee80211_beacon_phdr *) payload;
+	pos = (u8 *) (hdr + 1);
+	end = payload + len;
+	while (pos < end) {
+		if (pos + 2 + pos[1] > end) {
+			printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed "
+			       "for " MACSTR "\n", MAC2STR(addr));
+			return;
+		}
+		if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&
+		    memcmp(pos + 2, wpa_oid, 4) == 0) {
+			prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2);
+			return;
+		}
+		pos += 2 + pos[1];
+	}
+}
+
+static void
+handle_request(islpci_private *priv, struct obj_mlme *mlme, enum oid_num_t oid)
+{
+	if (((le16_to_cpu(mlme->state) == DOT11_STATE_AUTHING) ||
+	     (le16_to_cpu(mlme->state) == DOT11_STATE_ASSOCING))
+	    && mgt_mlme_answer(priv)) {
+		/* Someone is requesting auth and we must respond. Just send back
+		 * the trap with error code set accordingly.
+		 */
+		mlme->code = cpu_to_le16(prism54_mac_accept(&priv->acl,
+							    mlme->
+							    address) ? 0 : 1);
+		mgt_set_request(priv, oid, 0, mlme);
+	}
+}
+
+int
+prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
+			    char *data)
+{
+	struct obj_mlme *mlme = (struct obj_mlme *) data;
+	size_t len;
+	u8 *payload, *pos = (u8 *) (mlme + 1);
+
+	len = pos[0] | (pos[1] << 8);	/* little endian data length */
+	payload = pos + 2;
+
+	/* I think all trapable objects are listed here.
+	 * Some oids have a EX version. The difference is that they are emitted
+	 * in DOT11_MLME_EXTENDED mode (set with DOT11_OID_MLMEAUTOLEVEL)
+	 * with more info.
+	 * The few events already defined by the wireless tools are not really
+	 * suited. We use the more flexible custom event facility.
+	 */
+
+	switch (oid) {
+
+	case GEN_OID_LINKSTATE:
+		link_changed(priv->ndev, (u32) *data);
+		break;
+
+	case DOT11_OID_MICFAILURE:
+		send_simple_event(priv, "Mic failure");
+		break;
+
+	case DOT11_OID_DEAUTHENTICATE:
+		send_formatted_event(priv, "DeAuthenticate request", mlme, 0);
+		break;
+
+	case DOT11_OID_AUTHENTICATE:
+		handle_request(priv, mlme, oid);
+		send_formatted_event(priv, "Authenticate request", mlme, 1);
+		break;
+
+	case DOT11_OID_DISASSOCIATE:
+		send_formatted_event(priv, "Disassociate request", mlme, 0);
+		break;
+
+	case DOT11_OID_ASSOCIATE:
+		handle_request(priv, mlme, oid);
+		send_formatted_event(priv, "Associate request", mlme, 1);
+		break;
+
+	case DOT11_OID_REASSOCIATE:
+		handle_request(priv, mlme, oid);
+		send_formatted_event(priv, "ReAssociate request", mlme, 1);
+		break;
+
+	case DOT11_OID_BEACON:
+		prism54_process_bss_data(priv, oid, mlme->address,
+					 payload, len);
+		send_formatted_event(priv,
+				     "Received a beacon from an unkown AP",
+				     mlme, 0);
+		break;
+
+	case DOT11_OID_PROBE:
+		/* we received a probe from a client. */
+		prism54_process_bss_data(priv, oid, mlme->address,
+					 payload, len);
+		send_formatted_event(priv, "Received a probe from client", mlme,
+				     0);
+		break;
+
+		/* Note : the following should never happen since we don't run the card in
+		 * extended mode.
+		 * Note : "mlme" is actually a "struct obj_mlmeex *" here, but this
+		 * is backward compatible layout-wise with "struct obj_mlme".
+		 */
+
+	case DOT11_OID_DEAUTHENTICATEEX:
+		send_formatted_event(priv, "DeAuthenticate request", mlme, 0);
+		break;
+
+	case DOT11_OID_AUTHENTICATEEX:
+		handle_request(priv, mlme, oid);
+		send_formatted_event(priv, "Authenticate request", mlme, 1);
+		break;
+
+	case DOT11_OID_DISASSOCIATEEX:
+		send_formatted_event(priv, "Disassociate request", mlme, 0);
+		break;
+
+	case DOT11_OID_ASSOCIATEEX:
+		handle_request(priv, mlme, oid);
+		send_formatted_event(priv, "Associate request", mlme, 1);
+		break;
+
+	case DOT11_OID_REASSOCIATEEX:
+		handle_request(priv, mlme, oid);
+		send_formatted_event(priv, "Reassociate request", mlme, 1);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Process a device trap.  This is called via schedule_work(), outside of
+ * interrupt context, no locks held.
+ */
+void
+prism54_process_trap(void *data)
+{
+	struct islpci_mgmtframe *frame = data;
+	enum oid_num_t n = mgt_oidtonum(frame->header->oid);
+
+	prism54_process_trap_helper(frame->ndev->priv, n, frame->data);
+	islpci_mgt_release(frame);
+}
+
+int
+prism54_set_mac_address(struct net_device *ndev, void *addr)
+{
+	islpci_private *priv = ndev->priv;
+	int ret;
+
+	if (ndev->addr_len != 6)
+		return -EINVAL;
+	ret = mgt_set_request(priv, GEN_OID_MACADDRESS, 0,
+			      &((struct sockaddr *) addr)->sa_data);
+	if (!ret)
+		memcpy(priv->ndev->dev_addr,
+		       &((struct sockaddr *) addr)->sa_data, 6);
+
+	return ret;
+}
+
+int
+prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
+{
+	/* should we really support this old stuff ? */
+	return -EOPNOTSUPP;
+}
+
+int
+prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info,
+		__u32 * uwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+
+	down_write(&priv->mib_sem);
+
+	priv->wpa = *uwrq;
+	if (priv->wpa) {
+		u32 l = DOT11_MLME_EXTENDED;
+		mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &l);
+	}
+	/* restart the card with new level. Needed ? */
+	mgt_commit(priv);
+	up_write(&priv->mib_sem);
+
+	return 0;
+}
+
+int
+prism54_get_wpa(struct net_device *ndev, struct iw_request_info *info,
+		__u32 * uwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	*uwrq = priv->wpa;
+	return 0;
+}
+
+int
+prism54_oid(struct net_device *ndev, struct iw_request_info *info,
+		__u32 *uwrq, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	
+	priv->priv_oid = *uwrq;
+	printk("%s: oid 0x%08X\n", ndev->name, *uwrq);
+
+	return 0;
+}
+
+int
+prism54_get_oid(struct net_device *ndev, struct iw_request_info *info,
+		struct iw_point *data, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	struct islpci_mgmtframe *response = NULL;
+	int ret = -EIO, response_op = PIMFOR_OP_ERROR;
+	
+	printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid);
+	data->length = 0;
+	
+	if (islpci_get_state(priv) >= PRV_STATE_INIT) {
+		ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, priv->priv_oid, extra, 256, &response);
+		response_op = response->header->operation;
+		printk("%s: ret: %i\n", ndev->name, ret);
+		printk("%s: response_op: %i\n", ndev->name, response_op);
+		if (ret || !response || response->header->operation == PIMFOR_OP_ERROR) {
+			if (response) {
+				islpci_mgt_release(response);
+			}
+			printk("%s: EIO\n", ndev->name);
+			ret = -EIO;
+		}
+		if (!ret) {
+			data->length = response->header->length;
+			memcpy(extra, response->data, data->length);
+			islpci_mgt_release(response);
+			printk("%s: len: %i\n", ndev->name, data->length);
+		}
+	}
+	
+	return ret;
+}
+
+int
+prism54_set_oid(struct net_device *ndev, struct iw_request_info *info,
+		struct iw_point *data, char *extra)
+{
+	islpci_private *priv = ndev->priv;
+	struct islpci_mgmtframe *response = NULL;
+	int ret = 0, response_op = PIMFOR_OP_ERROR;
+	
+	printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid, data->length);
+	
+	if (islpci_get_state(priv) >= PRV_STATE_INIT) {
+		ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, priv->priv_oid, extra, data->length, &response);
+		printk("%s: ret: %i\n", ndev->name, ret);
+		if (!ret) {
+			response_op = response->header->operation;
+			printk("%s: response_op: %i\n", ndev->name, response_op);
+			islpci_mgt_release(response);
+		}
+		if (ret || response_op == PIMFOR_OP_ERROR) {
+			printk("%s: EIO\n", ndev->name);
+		        ret = -EIO;
+		}
+	}
+	
+	return ret;
+}
+
+static const iw_handler prism54_handler[] = {
+	(iw_handler) prism54_commit,	/* SIOCSIWCOMMIT */
+	(iw_handler) prism54_get_name,	/* SIOCGIWNAME */
+	(iw_handler) NULL,	/* SIOCSIWNWID */
+	(iw_handler) NULL,	/* SIOCGIWNWID */
+	(iw_handler) prism54_set_freq,	/* SIOCSIWFREQ */
+	(iw_handler) prism54_get_freq,	/* SIOCGIWFREQ */
+	(iw_handler) prism54_set_mode,	/* SIOCSIWMODE */
+	(iw_handler) prism54_get_mode,	/* SIOCGIWMODE */
+	(iw_handler) prism54_set_sens,	/* SIOCSIWSENS */
+	(iw_handler) prism54_get_sens,	/* SIOCGIWSENS */
+	(iw_handler) NULL,	/* SIOCSIWRANGE */
+	(iw_handler) prism54_get_range,	/* SIOCGIWRANGE */
+	(iw_handler) NULL,	/* SIOCSIWPRIV */
+	(iw_handler) NULL,	/* SIOCGIWPRIV */
+	(iw_handler) NULL,	/* SIOCSIWSTATS */
+	(iw_handler) NULL,	/* SIOCGIWSTATS */
+	iw_handler_set_spy,	/* SIOCSIWSPY */
+	iw_handler_get_spy,	/* SIOCGIWSPY */
+	iw_handler_set_thrspy,	/* SIOCSIWTHRSPY */
+	iw_handler_get_thrspy,	/* SIOCGIWTHRSPY */
+	(iw_handler) prism54_set_wap,	/* SIOCSIWAP */
+	(iw_handler) prism54_get_wap,	/* SIOCGIWAP */
+	(iw_handler) NULL,	/* -- hole -- */
+	(iw_handler) NULL,	/* SIOCGIWAPLIST depreciated */
+	(iw_handler) prism54_set_scan,	/* SIOCSIWSCAN */
+	(iw_handler) prism54_get_scan,	/* SIOCGIWSCAN */
+	(iw_handler) prism54_set_essid,	/* SIOCSIWESSID */
+	(iw_handler) prism54_get_essid,	/* SIOCGIWESSID */
+	(iw_handler) prism54_set_nick,	/* SIOCSIWNICKN */
+	(iw_handler) prism54_get_nick,	/* SIOCGIWNICKN */
+	(iw_handler) NULL,	/* -- hole -- */
+	(iw_handler) NULL,	/* -- hole -- */
+	(iw_handler) prism54_set_rate,	/* SIOCSIWRATE */
+	(iw_handler) prism54_get_rate,	/* SIOCGIWRATE */
+	(iw_handler) prism54_set_rts,	/* SIOCSIWRTS */
+	(iw_handler) prism54_get_rts,	/* SIOCGIWRTS */
+	(iw_handler) prism54_set_frag,	/* SIOCSIWFRAG */
+	(iw_handler) prism54_get_frag,	/* SIOCGIWFRAG */
+	(iw_handler) prism54_set_txpower,	/* SIOCSIWTXPOW */
+	(iw_handler) prism54_get_txpower,	/* SIOCGIWTXPOW */
+	(iw_handler) prism54_set_retry,	/* SIOCSIWRETRY */
+	(iw_handler) prism54_get_retry,	/* SIOCGIWRETRY */
+	(iw_handler) prism54_set_encode,	/* SIOCSIWENCODE */
+	(iw_handler) prism54_get_encode,	/* SIOCGIWENCODE */
+	(iw_handler) NULL,	/* SIOCSIWPOWER */
+	(iw_handler) NULL,	/* SIOCGIWPOWER */
+};
+
+/* The low order bit identify a SET (0) or a GET (1) ioctl.  */
+
+#define PRISM54_RESET		SIOCIWFIRSTPRIV
+#define PRISM54_GET_BEACON	SIOCIWFIRSTPRIV+1
+#define PRISM54_SET_BEACON	SIOCIWFIRSTPRIV+2
+#define PRISM54_GET_POLICY SIOCIWFIRSTPRIV+3
+#define PRISM54_SET_POLICY SIOCIWFIRSTPRIV+4
+#define PRISM54_GET_MAC 	   SIOCIWFIRSTPRIV+5
+#define PRISM54_ADD_MAC 	   SIOCIWFIRSTPRIV+6
+
+#define PRISM54_DEL_MAC    SIOCIWFIRSTPRIV+8
+
+#define PRISM54_KICK_MAC   SIOCIWFIRSTPRIV+10
+
+#define PRISM54_KICK_ALL   SIOCIWFIRSTPRIV+12
+
+#define PRISM54_GET_WPA	   SIOCIWFIRSTPRIV+13
+#define PRISM54_SET_WPA	   SIOCIWFIRSTPRIV+14
+
+#define PRISM54_OID	   SIOCIWFIRSTPRIV+16
+#define PRISM54_GET_OID	   SIOCIWFIRSTPRIV+17
+#define PRISM54_SET_OID	   SIOCIWFIRSTPRIV+18
+
+static const struct iw_priv_args prism54_private_args[] = {
+/*{ cmd, set_args, get_args, name } */
+	{PRISM54_RESET, 0, 0, "reset"},
+	{PRISM54_GET_BEACON, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "getBeaconPeriod"},
+	{PRISM54_SET_BEACON, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
+	 "setBeaconPeriod"},
+	{PRISM54_GET_POLICY, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "getPolicy"},
+	{PRISM54_SET_POLICY, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
+	 "setPolicy"},
+	{PRISM54_GET_MAC, 0, IW_PRIV_TYPE_ADDR | 64, "getMac"},
+	{PRISM54_ADD_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
+	 "addMac"},
+	{PRISM54_DEL_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
+	 "delMac"},
+	{PRISM54_KICK_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
+	 "kickMac"},
+	{PRISM54_KICK_ALL, 0, 0, "kickAll"},
+	{PRISM54_GET_WPA, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "get_wpa"},
+	{PRISM54_SET_WPA, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
+	 "set_wpa"},
+	{PRISM54_OID, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "oid"},
+	{PRISM54_GET_OID, 0, IW_PRIV_TYPE_BYTE | 256, "get_oid"},
+	{PRISM54_SET_OID, IW_PRIV_TYPE_BYTE | 256, 0, "set_oid"},
+};
+
+static const iw_handler prism54_private_handler[] = {
+	(iw_handler) prism54_reset,
+	(iw_handler) prism54_get_beacon,
+	(iw_handler) prism54_set_beacon,
+	(iw_handler) prism54_get_policy,
+	(iw_handler) prism54_set_policy,
+	(iw_handler) prism54_get_mac,
+	(iw_handler) prism54_add_mac,
+	(iw_handler) NULL,
+	(iw_handler) prism54_del_mac,
+	(iw_handler) NULL,
+	(iw_handler) prism54_kick_mac,
+	(iw_handler) NULL,
+	(iw_handler) prism54_kick_all,
+	(iw_handler) prism54_get_wpa,
+	(iw_handler) prism54_set_wpa,
+	(iw_handler) NULL,
+	(iw_handler) prism54_oid,
+	(iw_handler) prism54_get_oid,
+	(iw_handler) prism54_set_oid,
+};
+
+const struct iw_handler_def prism54_handler_def = {
+	.num_standard = sizeof (prism54_handler) / sizeof (iw_handler),
+	.num_private = sizeof (prism54_private_handler) / sizeof (iw_handler),
+	.num_private_args =
+	    sizeof (prism54_private_args) / sizeof (struct iw_priv_args),
+	.standard = (iw_handler *) prism54_handler,
+	.private = (iw_handler *) prism54_private_handler,
+	.private_args = (struct iw_priv_args *) prism54_private_args,
+};
+
--- diff/drivers/net/wireless/prism54/isl_ioctl.h	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/net/wireless/prism54/isl_ioctl.h	2004-03-16 09:37:58.382664656 +0000
@@ -0,0 +1,55 @@
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/isl_ioctl.h,v 1.30 2004/01/30 16:24:00 ajfa Exp $
+ *  
+ *  Copyright (C) 2002 Intersil Americas Inc.
+ *            (C) 2003 Aurelien Alleaume <slts@free.fr>
+ *            (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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 _ISL_IOCTL_H
+#define _ISL_IOCTL_H
+
+#include "islpci_mgt.h"
+#include "islpci_dev.h"
+
+#include <net/iw_handler.h>	/* New driver API */
+
+#define SUPPORTED_WIRELESS_EXT                  16
+
+void prism54_mib_init(islpci_private *);
+void prism54_mib_init_work(islpci_private *);
+
+struct iw_statistics *prism54_get_wireless_stats(struct net_device *);
+void prism54_update_stats(islpci_private *);
+
+void prism54_acl_init(struct islpci_acl *);
+void prism54_acl_clean(struct islpci_acl *);
+
+void prism54_process_trap(void *);
+
+void prism54_wpa_ie_init(islpci_private *priv);
+void prism54_wpa_ie_clean(islpci_private *priv);
+void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
+			u8 *wpa_ie, size_t wpa_ie_len);
+size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
+
+int prism54_set_mac_address(struct net_device *, void *);
+
+int prism54_ioctl(struct net_device *, struct ifreq *, int);
+
+extern const struct iw_handler_def prism54_handler_def;
+
+#endif				/* _ISL_IOCTL_H */
--- diff/drivers/net/wireless/prism54/isl_oid.h	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/net/wireless/prism54/isl_oid.h	2004-03-16 09:37:58.383664504 +0000
@@ -0,0 +1,365 @@
+/*
+ *  $Id: isl_oid.h,v 1.2 2004/01/30 16:24:00 ajfa Exp $
+ *  
+ *  Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  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
+ *
+ */
+
+#if !defined(_ISL_OID_H)
+#define _ISL_OID_H
+
+/* 
+ * MIB related constant and structure definitions for communicating
+ * with the device firmware
+ */
+
+struct obj_ssid {
+	u8 length;
+	char octets[33];
+} __attribute__ ((packed));
+
+struct obj_key {
+	u8 type;		/* dot11_priv_t */
+	u8 length;
+	char key[32];
+} __attribute__ ((packed));
+
+struct obj_mlme {
+	u8 address[6];
+	u16 id;
+	u16 state;
+	u16 code;
+} __attribute__ ((packed));
+
+struct obj_mlmeex {
+	u8 address[6];
+	u16 id;
+	u16 state;
+	u16 code;
+	u16 size;
+	u8 data[0];
+} __attribute__ ((packed));
+
+struct obj_buffer {
+	u32 size;
+	u32 addr;		/* 32bit bus address */
+} __attribute__ ((packed));
+
+struct obj_bss {
+	u8 address[6];
+	int:16;			/* padding */
+
+	char state;
+	char reserved;
+	short age;
+
+	char quality;
+	char rssi;
+
+	struct obj_ssid ssid;
+	short channel;
+	char beacon_period;
+	char dtim_period;
+	short capinfo;
+	short rates;
+	short basic_rates;
+	int:16;			/* padding */
+} __attribute__ ((packed));
+
+struct obj_bsslist {
+	u32 nr;
+	struct obj_bss bsslist[0];
+} __attribute__ ((packed));
+
+struct obj_frequencies {
+	u16 nr;
+	u16 mhz[0];
+} __attribute__ ((packed));
+
+/* 
+ * in case everything's ok, the inlined function below will be
+ * optimized away by the compiler...
+ */
+static inline void
+__bug_on_wrong_struct_sizes(void)
+{
+	BUG_ON(sizeof (struct obj_ssid) != 34);
+	BUG_ON(sizeof (struct obj_key) != 34);
+	BUG_ON(sizeof (struct obj_mlme) != 12);
+	BUG_ON(sizeof (struct obj_mlmeex) != 14);
+	BUG_ON(sizeof (struct obj_buffer) != 8);
+	BUG_ON(sizeof (struct obj_bss) != 60);
+	BUG_ON(sizeof (struct obj_bsslist) != 4);
+	BUG_ON(sizeof (struct obj_frequencies) != 2);
+}
+
+enum dot11_state_t {
+	DOT11_STATE_NONE = 0,
+	DOT11_STATE_AUTHING = 1,
+	DOT11_STATE_AUTH = 2,
+	DOT11_STATE_ASSOCING = 3,
+
+	DOT11_STATE_ASSOC = 5,
+	DOT11_STATE_IBSS = 6,
+	DOT11_STATE_WDS = 7
+};
+
+enum dot11_bsstype_t {
+	DOT11_BSSTYPE_NONE = 0,
+	DOT11_BSSTYPE_INFRA = 1,
+	DOT11_BSSTYPE_IBSS = 2,
+	DOT11_BSSTYPE_ANY = 3
+};
+
+enum dot11_auth_t {
+	DOT11_AUTH_NONE = 0,
+	DOT11_AUTH_OS = 1,
+	DOT11_AUTH_SK = 2,
+	DOT11_AUTH_BOTH = 3
+};
+
+enum dot11_mlme_t {
+	DOT11_MLME_AUTO = 0,
+	DOT11_MLME_INTERMEDIATE = 1,
+	DOT11_MLME_EXTENDED = 2
+};
+
+enum dot11_priv_t {
+	DOT11_PRIV_WEP = 0,
+	DOT11_PRIV_TKIP = 1
+};
+
+/* The dot11d conformance level configures the 802.11d conformance levels.
+ * The following conformance levels exist:*/
+enum oid_inl_conformance_t {
+	OID_INL_CONFORMANCE_NONE = 0,	/* Perform active scanning */
+	OID_INL_CONFORMANCE_STRICT = 1,	/* Strictly adhere to 802.11d */
+	OID_INL_CONFORMANCE_FLEXIBLE = 2,	/* Use passed 802.11d info to
+						 * determine channel AND/OR just make 
+						 * assumption that active 
+						 * channels are valid  channels */
+};
+
+enum oid_inl_mode_t {
+	INL_MODE_NONE = -1,
+	INL_MODE_PROMISCUOUS = 0,
+	INL_MODE_CLIENT = 1,
+	INL_MODE_AP = 2,
+	INL_MODE_SNIFFER = 3
+};
+
+enum oid_inl_config_t {
+	INL_CONFIG_NOTHING = 0x00,
+	INL_CONFIG_MANUALRUN = 0x01,
+	INL_CONFIG_FRAMETRAP = 0x02,
+	INL_CONFIG_RXANNEX = 0x04,
+	INL_CONFIG_TXANNEX = 0x08,
+	INL_CONFIG_WDS = 0x10
+};
+
+enum oid_inl_phycap_t {
+	INL_PHYCAP_2400MHZ = 1,
+	INL_PHYCAP_5000MHZ = 2,
+	INL_PHYCAP_FAA = 0x80000000,	/* Means card supports the FAA switch */
+};
+
+enum oid_num_t {
+	GEN_OID_MACADDRESS = 0,
+	GEN_OID_LINKSTATE,
+	GEN_OID_WATCHDOG,
+	GEN_OID_MIBOP,
+	GEN_OID_OPTIONS,
+	GEN_OID_LEDCONFIG,
+
+	/* 802.11 */
+	DOT11_OID_BSSTYPE,
+	DOT11_OID_BSSID,
+	DOT11_OID_SSID,
+	DOT11_OID_STATE,
+	DOT11_OID_AID,
+	DOT11_OID_COUNTRYSTRING,
+	DOT11_OID_SSIDOVERRIDE,
+
+	DOT11_OID_MEDIUMLIMIT,
+	DOT11_OID_BEACONPERIOD,
+	DOT11_OID_DTIMPERIOD,
+	DOT11_OID_ATIMWINDOW,
+	DOT11_OID_LISTENINTERVAL,
+	DOT11_OID_CFPPERIOD,
+	DOT11_OID_CFPDURATION,
+
+	DOT11_OID_AUTHENABLE,
+	DOT11_OID_PRIVACYINVOKED,
+	DOT11_OID_EXUNENCRYPTED,
+	DOT11_OID_DEFKEYID,
+	DOT11_OID_DEFKEYX,	/* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */
+	DOT11_OID_STAKEY,
+	DOT11_OID_REKEYTHRESHOLD,
+	DOT11_OID_STASC,
+
+	DOT11_OID_PRIVTXREJECTED,
+	DOT11_OID_PRIVRXPLAIN,
+	DOT11_OID_PRIVRXFAILED,
+	DOT11_OID_PRIVRXNOKEY,
+
+	DOT11_OID_RTSTHRESH,
+	DOT11_OID_FRAGTHRESH,
+	DOT11_OID_SHORTRETRIES,
+	DOT11_OID_LONGRETRIES,
+	DOT11_OID_MAXTXLIFETIME,
+	DOT11_OID_MAXRXLIFETIME,
+	DOT11_OID_AUTHRESPTIMEOUT,
+	DOT11_OID_ASSOCRESPTIMEOUT,
+
+	DOT11_OID_ALOFT_TABLE,
+	DOT11_OID_ALOFT_CTRL_TABLE,
+	DOT11_OID_ALOFT_RETREAT,
+	DOT11_OID_ALOFT_PROGRESS,
+	DOT11_OID_ALOFT_FIXEDRATE,
+	DOT11_OID_ALOFT_RSSIGRAPH,
+	DOT11_OID_ALOFT_CONFIG,
+
+	DOT11_OID_VDCFX,
+	DOT11_OID_MAXFRAMEBURST,
+
+	DOT11_OID_PSM,
+	DOT11_OID_CAMTIMEOUT,
+	DOT11_OID_RECEIVEDTIMS,
+	DOT11_OID_ROAMPREFERENCE,
+
+	DOT11_OID_BRIDGELOCAL,
+	DOT11_OID_CLIENTS,
+	DOT11_OID_CLIENTSASSOCIATED,
+	DOT11_OID_CLIENTX,	/* DOT11_OID_CLIENTX,...DOT11_OID_CLIENT2007 */
+
+	DOT11_OID_CLIENTFIND,
+	DOT11_OID_WDSLINKADD,
+	DOT11_OID_WDSLINKREMOVE,
+	DOT11_OID_EAPAUTHSTA,
+	DOT11_OID_EAPUNAUTHSTA,
+	DOT11_OID_DOT1XENABLE,
+	DOT11_OID_MICFAILURE,
+	DOT11_OID_REKEYINDICATE,
+
+	DOT11_OID_MPDUTXSUCCESSFUL,
+	DOT11_OID_MPDUTXONERETRY,
+	DOT11_OID_MPDUTXMULTIPLERETRIES,
+	DOT11_OID_MPDUTXFAILED,
+	DOT11_OID_MPDURXSUCCESSFUL,
+	DOT11_OID_MPDURXDUPS,
+	DOT11_OID_RTSSUCCESSFUL,
+	DOT11_OID_RTSFAILED,
+	DOT11_OID_ACKFAILED,
+	DOT11_OID_FRAMERECEIVES,
+	DOT11_OID_FRAMEERRORS,
+	DOT11_OID_FRAMEABORTS,
+	DOT11_OID_FRAMEABORTSPHY,
+
+	DOT11_OID_SLOTTIME,
+	DOT11_OID_CWMIN,
+	DOT11_OID_CWMAX,
+	DOT11_OID_ACKWINDOW,
+	DOT11_OID_ANTENNARX,
+	DOT11_OID_ANTENNATX,
+	DOT11_OID_ANTENNADIVERSITY,
+	DOT11_OID_CHANNEL,
+	DOT11_OID_EDTHRESHOLD,
+	DOT11_OID_PREAMBLESETTINGS,
+	DOT11_OID_RATES,
+	DOT11_OID_CCAMODESUPPORTED,
+	DOT11_OID_CCAMODE,
+	DOT11_OID_RSSIVECTOR,
+	DOT11_OID_OUTPUTPOWERTABLE,
+	DOT11_OID_OUTPUTPOWER,
+	DOT11_OID_SUPPORTEDRATES,
+	DOT11_OID_FREQUENCY,
+	DOT11_OID_SUPPORTEDFREQUENCIES,
+	DOT11_OID_NOISEFLOOR,
+	DOT11_OID_FREQUENCYACTIVITY,
+	DOT11_OID_IQCALIBRATIONTABLE,
+	DOT11_OID_NONERPPROTECTION,
+	DOT11_OID_SLOTSETTINGS,
+	DOT11_OID_NONERPTIMEOUT,
+	DOT11_OID_PROFILES,
+	DOT11_OID_EXTENDEDRATES,
+
+	DOT11_OID_DEAUTHENTICATE,
+	DOT11_OID_AUTHENTICATE,
+	DOT11_OID_DISASSOCIATE,
+	DOT11_OID_ASSOCIATE,
+	DOT11_OID_SCAN,
+	DOT11_OID_BEACON,
+	DOT11_OID_PROBE,
+	DOT11_OID_DEAUTHENTICATEEX,
+	DOT11_OID_AUTHENTICATEEX,
+	DOT11_OID_DISASSOCIATEEX,
+	DOT11_OID_ASSOCIATEEX,
+	DOT11_OID_REASSOCIATE,
+	DOT11_OID_REASSOCIATEEX,
+
+	DOT11_OID_NONERPSTATUS,
+
+	DOT11_OID_STATIMEOUT,
+	DOT11_OID_MLMEAUTOLEVEL,
+	DOT11_OID_BSSTIMEOUT,
+	DOT11_OID_ATTACHMENT,
+	DOT11_OID_PSMBUFFER,
+
+	DOT11_OID_BSSS,
+	DOT11_OID_BSSX,		/*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */
+	DOT11_OID_BSSFIND,
+	DOT11_OID_BSSLIST,
+
+	OID_INL_TUNNEL,
+	OID_INL_MEMADDR,
+	OID_INL_MEMORY,
+	OID_INL_MODE,
+	OID_INL_COMPONENT_NR,
+	OID_INL_VERSION,
+	OID_INL_INTERFACE_ID,
+	OID_INL_COMPONENT_ID,
+	OID_INL_CONFIG,
+	OID_INL_DOT11D_CONFORMANCE,
+	OID_INL_PHYCAPABILITIES,
+	OID_INL_OUTPUTPOWER,
+
+	OID_NUM_LAST
+};
+
+/* We  could add more flags. eg: in which mode are they allowed, ro, rw, ...*/
+#define OID_FLAG_CACHED	0x01
+#define OID_FLAG_U32	0x02
+#define OID_FLAG_MLMEEX	0x04	/* this type is special because of a variable
+				   size field when sending. Not yet implemented (not used in driver). */
+
+struct oid_t {
+	enum oid_num_t oid;
+	short range;		/* to define a range of oid */
+	short size;		/* size of the associated data */
+	char flags;
+};
+
+union oid_res_t {
+	void *ptr;
+	u32 u;
+};
+
+#define	IWMAX_BITRATES	20
+#define	IWMAX_BSS	24
+#define IWMAX_FREQ	30
+
+#endif				/* !defined(_ISL_OID_H) */
+/* EOF */
--- diff/drivers/net/wireless/prism54/islpci_dev.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/net/wireless/prism54/islpci_dev.c	2004-03-16 09:37:58.385664200 +0000
@@ -0,0 +1,826 @@
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_dev.c,v 1.68 2004/02/28 03:06:07 mcgrof Exp $
+ *  
+ *  Copyright (C) 2002 Intersil Americas Inc.
+ *  Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
+ *  Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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/version.h>
+#include <linux/module.h>
+
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/if_arp.h>
+
+#include <asm/io.h>
+
+#include "isl_38xx.h"
+#include "isl_ioctl.h"
+#include "islpci_dev.h"
+#include "islpci_mgt.h"
+#include "islpci_eth.h"
+#include "oid_mgt.h"
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+#define prism54_synchronize_irq(irq) synchronize_irq()
+#else
+#define prism54_synchronize_irq(irq) synchronize_irq(irq)
+#endif
+
+#define ISL3877_IMAGE_FILE	"isl3877"
+#define ISL3890_IMAGE_FILE	"isl3890"
+
+/* Temporary dummy MAC address to use until firmware is loaded.
+ * The idea there is that some tools (such as nameif) may query
+ * the MAC address before the netdev is 'open'. By using a valid
+ * OUI prefix, they can process the netdev properly.
+ * Of course, this is not the final/real MAC address. It doesn't
+ * matter, as you are suppose to be able to change it anytime via
+ * ndev->set_mac_address. Jean II */
+const unsigned char	dummy_mac[6] = { 0x00, 0x30, 0xB4, 0x00, 0x00, 0x00 };
+
+/******************************************************************************
+    Device Interrupt Handler
+******************************************************************************/
+
+irqreturn_t
+islpci_interrupt(int irq, void *config, struct pt_regs *regs)
+{
+	u32 reg;
+	islpci_private *priv = config;
+	struct net_device *ndev = priv->ndev;
+	void *device = priv->device_base;
+	int powerstate = ISL38XX_PSM_POWERSAVE_STATE;
+
+	/* received an interrupt request on a shared IRQ line
+	 * first check whether the device is in sleep mode */
+	reg = readl(device + ISL38XX_CTRL_STAT_REG);
+	if (reg & ISL38XX_CTRL_STAT_SLEEPMODE)
+		/* device is in sleep mode, IRQ was generated by someone else */
+	{
+		printk(KERN_DEBUG "Assuming someone else called the IRQ\n");
+		return IRQ_NONE;
+	}
+
+	if (islpci_get_state(priv) != PRV_STATE_SLEEP)
+		powerstate = ISL38XX_PSM_ACTIVE_STATE;
+
+	/* lock the interrupt handler */
+	spin_lock(&priv->slock);
+
+	/* check whether there is any source of interrupt on the device */
+	reg = readl(device + ISL38XX_INT_IDENT_REG);
+
+	/* also check the contents of the Interrupt Enable Register, because this
+	 * will filter out interrupt sources from other devices on the same irq ! */
+	reg &= readl(device + ISL38XX_INT_EN_REG);
+	reg &= ISL38XX_INT_SOURCES;
+
+	if (reg != 0) {
+		/* reset the request bits in the Identification register */
+		isl38xx_w32_flush(device, reg, ISL38XX_INT_ACK_REG);
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+		DEBUG(SHOW_FUNCTION_CALLS,
+		      "IRQ: Identification register 0x%p 0x%x \n", device, reg);
+#endif
+
+		/* check for each bit in the register separately */
+		if (reg & ISL38XX_INT_IDENT_UPDATE) {
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			/* Queue has been updated */
+			DEBUG(SHOW_TRACING, "IRQ: Update flag \n");
+
+			DEBUG(SHOW_QUEUE_INDEXES,
+			      "CB drv Qs: [%i][%i][%i][%i][%i][%i]\n",
+			      le32_to_cpu(priv->control_block->
+					  driver_curr_frag[0]),
+			      le32_to_cpu(priv->control_block->
+					  driver_curr_frag[1]),
+			      le32_to_cpu(priv->control_block->
+					  driver_curr_frag[2]),
+			      le32_to_cpu(priv->control_block->
+					  driver_curr_frag[3]),
+			      le32_to_cpu(priv->control_block->
+					  driver_curr_frag[4]),
+			      le32_to_cpu(priv->control_block->
+					  driver_curr_frag[5])
+			    );
+
+			DEBUG(SHOW_QUEUE_INDEXES,
+			      "CB dev Qs: [%i][%i][%i][%i][%i][%i]\n",
+			      le32_to_cpu(priv->control_block->
+					  device_curr_frag[0]),
+			      le32_to_cpu(priv->control_block->
+					  device_curr_frag[1]),
+			      le32_to_cpu(priv->control_block->
+					  device_curr_frag[2]),
+			      le32_to_cpu(priv->control_block->
+					  device_curr_frag[3]),
+			      le32_to_cpu(priv->control_block->
+					  device_curr_frag[4]),
+			      le32_to_cpu(priv->control_block->
+					  device_curr_frag[5])
+			    );
+#endif
+
+			/* cleanup the data low transmit queue */
+			islpci_eth_cleanup_transmit(priv, priv->control_block);
+
+			/* device is in active state, update the
+			 * powerstate flag if necessary */
+			powerstate = ISL38XX_PSM_ACTIVE_STATE;
+
+			/* check all three queues in priority order
+			 * call the PIMFOR receive function until the
+			 * queue is empty */
+			if (isl38xx_in_queue(priv->control_block,
+						ISL38XX_CB_RX_MGMTQ) != 0) {
+#if VERBOSE > SHOW_ERROR_MESSAGES
+				DEBUG(SHOW_TRACING,
+				      "Received frame in Management Queue\n");
+#endif
+				islpci_mgt_receive(ndev);
+
+				islpci_mgt_cleanup_transmit(ndev);
+
+				/* Refill slots in receive queue */
+				islpci_mgmt_rx_fill(ndev);
+
+				/* no need to trigger the device, next
+                                   islpci_mgt_transaction does it */
+			}
+
+			while (isl38xx_in_queue(priv->control_block,
+						ISL38XX_CB_RX_DATA_LQ) != 0) {
+#if VERBOSE > SHOW_ERROR_MESSAGES
+				DEBUG(SHOW_TRACING,
+				      "Received frame in Data Low Queue \n");
+#endif
+				islpci_eth_receive(priv);
+			}
+
+			/* check whether the data transmit queues were full */
+			if (priv->data_low_tx_full) {
+				/* check whether the transmit is not full anymore */
+				if (ISL38XX_CB_TX_QSIZE -
+				    isl38xx_in_queue(priv->control_block,
+						     ISL38XX_CB_TX_DATA_LQ) >=
+				    ISL38XX_MIN_QTHRESHOLD) {
+					/* nope, the driver is ready for more network frames */
+					netif_wake_queue(priv->ndev);
+
+					/* reset the full flag */
+					priv->data_low_tx_full = 0;
+				}
+			}
+		}
+
+		if (reg & ISL38XX_INT_IDENT_INIT) {
+			/* Device has been initialized */
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			DEBUG(SHOW_TRACING,
+			      "IRQ: Init flag, device initialized \n");
+#endif
+			wake_up(&priv->reset_done);
+		}
+
+		if (reg & ISL38XX_INT_IDENT_SLEEP) {
+			/* Device intends to move to powersave state */
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			DEBUG(SHOW_TRACING, "IRQ: Sleep flag \n");
+#endif
+			isl38xx_handle_sleep_request(priv->control_block,
+						     &powerstate,
+						     priv->device_base);
+		}
+
+		if (reg & ISL38XX_INT_IDENT_WAKEUP) {
+			/* Device has been woken up to active state */
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			DEBUG(SHOW_TRACING, "IRQ: Wakeup flag \n");
+#endif
+
+			isl38xx_handle_wakeup(priv->control_block,
+					      &powerstate, priv->device_base);
+		}
+	}
+
+	/* sleep -> ready */
+	if (islpci_get_state(priv) == PRV_STATE_SLEEP
+	    && powerstate == ISL38XX_PSM_ACTIVE_STATE)
+		islpci_set_state(priv, PRV_STATE_READY);
+
+	/* !sleep -> sleep */
+	if (islpci_get_state(priv) != PRV_STATE_SLEEP
+	    && powerstate == ISL38XX_PSM_POWERSAVE_STATE)
+		islpci_set_state(priv, PRV_STATE_SLEEP);
+
+	/* unlock the interrupt handler */
+	spin_unlock(&priv->slock);
+
+	return IRQ_HANDLED;
+}
+
+/******************************************************************************
+    Network Interface Control & Statistical functions
+******************************************************************************/
+static int
+islpci_open(struct net_device *ndev)
+{
+	u32 rc;
+	islpci_private *priv = ndev->priv;
+
+	printk(KERN_DEBUG "%s: islpci_open()\n", ndev->name);
+
+	/* reset data structures, upload firmware and reset device */
+	rc = islpci_reset(priv,1);
+	if (rc) {
+		prism54_bring_down(priv);
+		return rc; /* Returns informative message */
+	}
+
+	netif_start_queue(ndev);
+/*      netif_mark_up( ndev ); */
+
+	return 0;
+}
+
+static int
+islpci_close(struct net_device *ndev)
+{
+	islpci_private *priv = ndev->priv;
+
+	printk(KERN_DEBUG "%s: islpci_close ()\n", ndev->name);
+
+	netif_stop_queue(ndev);
+
+	return prism54_bring_down(priv);
+}
+
+int
+prism54_bring_down(islpci_private *priv)
+{
+	void *device_base = priv->device_base;
+	u32 reg;
+	/* we are going to shutdown the device */
+	islpci_set_state(priv, PRV_STATE_PREBOOT);
+
+	/* disable all device interrupts in case they weren't */
+	isl38xx_disable_interrupts(priv->device_base);  
+
+	/* For safety reasons, we may want to ensure that no DMA transfer is
+	 * currently in progress by emptying the TX and RX queues. */
+
+	/* wait until interrupts have finished executing on other CPUs */
+	prism54_synchronize_irq(priv->pdev->irq);
+
+	reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
+	reg &= ~(ISL38XX_CTRL_STAT_RESET | ISL38XX_CTRL_STAT_RAMBOOT);
+	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
+	wmb();
+	udelay(ISL38XX_WRITEIO_DELAY);
+
+	reg |= ISL38XX_CTRL_STAT_RESET;
+	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
+	wmb();
+	udelay(ISL38XX_WRITEIO_DELAY);
+
+	/* clear the Reset bit */
+	reg &= ~ISL38XX_CTRL_STAT_RESET;
+	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
+	wmb();
+
+	/* wait a while for the device to reset */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(50*HZ/1000);
+
+	return 0;
+}
+
+static int
+islpci_upload_fw(islpci_private *priv)
+{
+	islpci_state_t old_state;
+	u32 rc;
+
+	old_state = islpci_set_state(priv, PRV_STATE_BOOT);
+
+	printk(KERN_DEBUG "%s: uploading firmware...\n", priv->ndev->name);
+
+	rc = isl38xx_upload_firmware(priv->firmware,
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,75))
+		&priv->pdev->dev,
+#else
+		pci_name(priv->pdev),
+#endif
+		priv->device_base,
+		priv->device_host_address);
+	if (rc) {
+		/* error uploading the firmware */
+		printk(KERN_ERR "%s: could not upload firmware ('%s')\n",
+		       priv->ndev->name, priv->firmware);
+
+		islpci_set_state(priv, old_state);
+		return rc;
+	}
+
+	printk(KERN_DEBUG
+	       "%s: firmware uploaded done, now triggering reset...\n",
+	       priv->ndev->name);
+
+	islpci_set_state(priv, PRV_STATE_POSTBOOT);
+
+	return 0;
+}
+
+static int
+islpci_reset_if(islpci_private *priv)
+{
+	long remaining;
+	int result = -ETIME;
+	int count;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+	/* This is 2.6 specific, nicer, shorter, but not in 2.4 yet */
+	DEFINE_WAIT(wait);
+	prepare_to_wait(&priv->reset_done, &wait, TASK_UNINTERRUPTIBLE);
+#else
+	DECLARE_WAITQUEUE(wait, current);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	add_wait_queue(&priv->reset_done, &wait);
+#endif
+	
+	/* now the last step is to reset the interface */
+	isl38xx_interface_reset(priv->device_base, priv->device_host_address);
+	islpci_set_state(priv, PRV_STATE_PREINIT);
+
+        for(count = 0; count < 2 && result; count++) {
+		/* The software reset acknowledge needs about 220 msec here.
+		 * Be conservative and wait for up to one second. */
+	
+		remaining = schedule_timeout(HZ);
+
+		if(remaining > 0) {
+			result = 0;
+			break;
+		}
+
+		/* If we're here it's because our IRQ hasn't yet gone through. 
+		 * Retry a bit more...
+		 */
+		 printk(KERN_ERR "%s: device soft reset timed out\n",
+		       priv->ndev->name);
+
+	}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+	/* 2.6 specific too */
+	finish_wait(&priv->reset_done, &wait);
+#else
+	remove_wait_queue(&priv->reset_done, &wait);
+	set_current_state(TASK_RUNNING);
+#endif
+
+	if(result)
+		return result;
+
+	islpci_set_state(priv, PRV_STATE_INIT);
+
+	/* Now that the device is 100% up, let's allow
+	 * for the other interrupts --
+	 * NOTE: this is not *yet* true since we've only allowed the 
+	 * INIT interrupt on the IRQ line. We can perhaps poll
+	 * the IRQ line until we know for sure the reset went through */
+	isl38xx_enable_common_interrupts(priv->device_base);
+
+	prism54_mib_init_work(priv);
+
+	islpci_set_state(priv, PRV_STATE_READY);
+
+	return 0;
+}
+
+int
+islpci_reset(islpci_private *priv, int reload_firmware)
+{
+	isl38xx_control_block *cb =    /* volatile not needed */
+		(isl38xx_control_block *) priv->control_block;
+	unsigned counter;
+	int rc;
+
+	if (reload_firmware)
+		islpci_set_state(priv, PRV_STATE_PREBOOT);
+	else
+		islpci_set_state(priv, PRV_STATE_POSTBOOT);
+
+	printk(KERN_DEBUG "%s: resetting device...\n", priv->ndev->name);
+
+	/* disable all device interrupts in case they weren't */
+	isl38xx_disable_interrupts(priv->device_base);
+
+	/* flush all management queues */
+	priv->index_mgmt_tx = 0;
+	priv->index_mgmt_rx = 0;
+
+	/* clear the indexes in the frame pointer */
+	for (counter = 0; counter < ISL38XX_CB_QCOUNT; counter++) {
+		cb->driver_curr_frag[counter] = cpu_to_le32(0);
+		cb->device_curr_frag[counter] = cpu_to_le32(0);
+	}
+
+	/* reset the mgmt receive queue */
+	for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) {
+		isl38xx_fragment *frag = &cb->rx_data_mgmt[counter];
+		frag->size = MGMT_FRAME_SIZE;
+		frag->flags = 0;
+		frag->address = priv->mgmt_rx[counter].pci_addr;
+	}
+
+	for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) {
+		cb->rx_data_low[counter].address =
+		    cpu_to_le32((u32) priv->pci_map_rx_address[counter]);
+	}
+
+	/* since the receive queues are filled with empty fragments, now we can
+	 * set the corresponding indexes in the Control Block */
+	priv->control_block->driver_curr_frag[ISL38XX_CB_RX_DATA_LQ] =
+	    cpu_to_le32(ISL38XX_CB_RX_QSIZE);
+	priv->control_block->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] =
+	    cpu_to_le32(ISL38XX_CB_MGMT_QSIZE);
+
+	/* reset the remaining real index registers and full flags */
+	priv->free_data_rx = 0;
+	priv->free_data_tx = 0;
+	priv->data_low_tx_full = 0;
+
+	if (reload_firmware) { /* Should we load the firmware ? */
+	/* now that the data structures are cleaned up, upload
+	 * firmware and reset interface */
+		rc = islpci_upload_fw(priv);
+		if (rc) 
+			return rc;
+	}
+
+	/* finally reset interface */
+	rc = islpci_reset_if(priv);
+	if (!rc) /* If successful */
+		return rc;
+	
+	printk(KERN_DEBUG  "prism54: Your card/socket may be faulty, or IRQ line too busy :(\n");
+	return rc;
+
+}
+
+struct net_device_stats *
+islpci_statistics(struct net_device *ndev)
+{
+	islpci_private *priv = ndev->priv;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics \n");
+#endif
+
+	return &priv->statistics;
+}
+
+/******************************************************************************
+    Network device configuration functions
+******************************************************************************/
+int
+islpci_alloc_memory(islpci_private *priv)
+{
+	int counter;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	printk(KERN_DEBUG "islpci_alloc_memory\n");
+#endif
+
+	/* remap the PCI device base address to accessable */
+	if (!(priv->device_base =
+	      ioremap(pci_resource_start(priv->pdev, 0),
+		      ISL38XX_PCI_MEM_SIZE))) {
+		/* error in remapping the PCI device memory address range */
+		printk(KERN_ERR "PCI memory remapping failed \n");
+		return -1;
+	}
+
+	/* memory layout for consistent DMA region:
+	 *
+	 * Area 1: Control Block for the device interface
+	 * Area 2: Power Save Mode Buffer for temporary frame storage. Be aware that
+	 *         the number of supported stations in the AP determines the minimal
+	 *         size of the buffer !
+	 */
+
+	/* perform the allocation */
+	priv->driver_mem_address = pci_alloc_consistent(priv->pdev,
+							HOST_MEM_BLOCK,
+							&priv->
+							device_host_address);
+
+	if (!priv->driver_mem_address) {
+		/* error allocating the block of PCI memory */
+		printk(KERN_ERR "%s: could not allocate DMA memory, aborting!",
+		       "prism54");
+		return -1;
+	}
+
+	/* assign the Control Block to the first address of the allocated area */
+	priv->control_block =
+	    (isl38xx_control_block *) priv->driver_mem_address;
+
+	/* set the Power Save Buffer pointer directly behind the CB */
+	priv->device_psm_buffer =
+		priv->device_host_address + CONTROL_BLOCK_SIZE;
+
+	/* make sure all buffer pointers are initialized */
+	for (counter = 0; counter < ISL38XX_CB_QCOUNT; counter++) {
+		priv->control_block->driver_curr_frag[counter] = cpu_to_le32(0);
+		priv->control_block->device_curr_frag[counter] = cpu_to_le32(0);
+	}
+
+	priv->index_mgmt_rx = 0;
+	memset(priv->mgmt_rx, 0, sizeof(priv->mgmt_rx));
+	memset(priv->mgmt_tx, 0, sizeof(priv->mgmt_tx));
+
+	/* allocate rx queue for management frames */
+	if (islpci_mgmt_rx_fill(priv->ndev) < 0)
+		goto out_free;
+
+	/* now get the data rx skb's */
+	memset(priv->data_low_rx, 0, sizeof (priv->data_low_rx));
+	memset(priv->pci_map_rx_address, 0, sizeof (priv->pci_map_rx_address));
+
+	for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) {
+		struct sk_buff *skb;
+
+		/* allocate an sk_buff for received data frames storage
+		 * each frame on receive size consists of 1 fragment
+		 * include any required allignment operations */
+		if (!(skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2))) {
+			/* error allocating an sk_buff structure elements */
+			printk(KERN_ERR "Error allocating skb.\n");
+			goto out_free;
+		}
+		/* add the new allocated sk_buff to the buffer array */
+		priv->data_low_rx[counter] = skb;
+
+		/* map the allocated skb data area to pci */
+		priv->pci_map_rx_address[counter] =
+		    pci_map_single(priv->pdev, (void *) skb->data,
+				   MAX_FRAGMENT_SIZE_RX + 2,
+				   PCI_DMA_FROMDEVICE);
+		if (!priv->pci_map_rx_address[counter]) {
+			/* error mapping the buffer to device
+			   accessable memory address */
+			printk(KERN_ERR "failed to map skb DMA'able\n");
+			goto out_free;
+		}
+	}
+
+	prism54_acl_init(&priv->acl);
+	prism54_wpa_ie_init(priv);
+	if (mgt_init(priv)) 
+		goto out_free;
+
+	return 0;
+ out_free:
+	islpci_free_memory(priv);
+	return -1;
+}
+
+int
+islpci_free_memory(islpci_private *priv)
+{
+	int counter;
+
+	if (priv->device_base)
+		iounmap(priv->device_base);
+	priv->device_base = 0;
+
+	/* free consistent DMA area... */
+	if (priv->driver_mem_address)
+		pci_free_consistent(priv->pdev, HOST_MEM_BLOCK,
+				    priv->driver_mem_address,
+				    priv->device_host_address);
+
+	/* clear some dangling pointers */
+	priv->driver_mem_address = 0;
+	priv->device_host_address = 0;
+	priv->device_psm_buffer = 0;
+	priv->control_block = 0;
+
+        /* clean up mgmt rx buffers */
+        for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) {
+		struct islpci_membuf *buf = &priv->mgmt_rx[counter];
+		if (buf->pci_addr)
+			pci_unmap_single(priv->pdev, buf->pci_addr,
+					 buf->size, PCI_DMA_FROMDEVICE);
+		buf->pci_addr = 0;
+		if (buf->mem)
+			kfree(buf->mem);
+		buf->size = 0;
+		buf->mem = NULL;
+        }
+
+	/* clean up data rx buffers */
+	for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) {
+		if (priv->pci_map_rx_address[counter])
+			pci_unmap_single(priv->pdev,
+					 priv->pci_map_rx_address[counter],
+					 MAX_FRAGMENT_SIZE_RX + 2,
+					 PCI_DMA_FROMDEVICE);
+		priv->pci_map_rx_address[counter] = 0;
+
+		if (priv->data_low_rx[counter])
+			dev_kfree_skb(priv->data_low_rx[counter]);
+		priv->data_low_rx[counter] = 0;
+	}
+
+	/* Free the acces control list and the WPA list */
+	prism54_acl_clean(&priv->acl);
+	prism54_wpa_ie_clean(priv);
+	mgt_clean(priv);
+
+	return 0;
+}
+
+#if 0
+static void
+islpci_set_multicast_list(struct net_device *dev)
+{
+	/* put device into promisc mode and let network layer handle it */
+}
+#endif
+
+struct net_device *
+islpci_setup(struct pci_dev *pdev)
+{
+	islpci_private *priv;
+	struct net_device *ndev = alloc_etherdev(sizeof (islpci_private));
+
+	if (!ndev)
+		return ndev;
+
+	SET_MODULE_OWNER(ndev);
+	pci_set_drvdata(pdev, ndev);
+#if defined(SET_NETDEV_DEV)
+	SET_NETDEV_DEV(ndev, &pdev->dev);
+#endif
+
+	/* setup the structure members */
+	ndev->base_addr = pci_resource_start(pdev, 0);
+	ndev->irq = pdev->irq;
+
+	/* initialize the function pointers */
+	ndev->open = &islpci_open;
+	ndev->stop = &islpci_close;
+	ndev->get_stats = &islpci_statistics;
+	ndev->get_wireless_stats = &prism54_get_wireless_stats;
+	ndev->do_ioctl = &prism54_ioctl;
+	ndev->wireless_handlers =
+	    (struct iw_handler_def *) &prism54_handler_def;
+
+	ndev->hard_start_xmit = &islpci_eth_transmit;
+	/* ndev->set_multicast_list = &islpci_set_multicast_list; */
+	ndev->addr_len = ETH_ALEN;
+	ndev->set_mac_address = &prism54_set_mac_address;
+	/* Get a non-zero dummy MAC address for nameif. Jean II */
+	memcpy(ndev->dev_addr, dummy_mac, 6);
+
+#ifdef HAVE_TX_TIMEOUT
+	ndev->watchdog_timeo = ISLPCI_TX_TIMEOUT;
+	ndev->tx_timeout = &islpci_eth_tx_timeout;
+#endif
+
+	/* allocate a private device structure to the network device  */
+	priv = ndev->priv;
+	priv->ndev = ndev;
+	priv->pdev = pdev;
+
+	priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ?
+		ARPHRD_IEEE80211: ARPHRD_ETHER;
+
+	/* save the start and end address of the PCI memory area */
+	ndev->mem_start = (unsigned long) priv->device_base;
+	ndev->mem_end = ndev->mem_start + ISL38XX_PCI_MEM_SIZE;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_TRACING, "PCI Memory remapped to 0x%p\n", priv->device_base);
+#endif
+
+	init_waitqueue_head(&priv->reset_done);
+
+	/* init the queue read locks, process wait counter */
+	sema_init(&priv->mgmt_sem, 1);
+	priv->mgmt_received = NULL;
+	init_waitqueue_head(&priv->mgmt_wqueue);
+	sema_init(&priv->stats_sem, 1);
+	spin_lock_init(&priv->slock);
+
+	/* init state machine with off#1 state */
+	priv->state = PRV_STATE_OFF;
+	priv->state_off = 1;
+
+	/* initialize workqueue's */
+	INIT_WORK(&priv->stats_work,
+		  (void (*)(void *)) prism54_update_stats, priv);
+
+	priv->stats_timestamp = 0;
+
+	/* allocate various memory areas */
+	if (islpci_alloc_memory(priv))
+		goto do_free_netdev;
+
+	/* select the firmware file depending on the device id */
+	switch (pdev->device) {
+	case PCIDEVICE_ISL3890:
+	case PCIDEVICE_3COM6001:
+		strcpy(priv->firmware, ISL3890_IMAGE_FILE);
+		break;
+	case PCIDEVICE_ISL3877:
+		strcpy(priv->firmware, ISL3877_IMAGE_FILE);
+		break;
+
+	default:
+		strcpy(priv->firmware, ISL3890_IMAGE_FILE);
+		break;
+	}
+
+	if (register_netdev(ndev)) {
+		DEBUG(SHOW_ERROR_MESSAGES,
+		      "ERROR: register_netdev() failed \n");
+		goto do_islpci_free_memory;
+	}
+
+	return ndev;
+
+      do_islpci_free_memory:
+	islpci_free_memory(priv);
+      do_free_netdev:
+	pci_set_drvdata(pdev, 0);
+	free_netdev(ndev);
+	priv = 0;
+	return NULL;
+}
+
+islpci_state_t
+islpci_set_state(islpci_private *priv, islpci_state_t new_state)
+{
+	islpci_state_t old_state;
+
+	/* lock */
+	old_state = priv->state;
+
+	/* this means either a race condition or some serious error in
+	 * the driver code */
+	switch (new_state) {
+	case PRV_STATE_OFF:
+		priv->state_off++;
+	default:
+		priv->state = new_state;
+		break;
+
+	case PRV_STATE_PREBOOT:
+		/* there are actually many off-states, enumerated by
+		 * state_off */
+		if (old_state == PRV_STATE_OFF)
+			priv->state_off--;
+
+		/* only if hw_unavailable is zero now it means we either
+		 * were in off#1 state, or came here from
+		 * somewhere else */
+		if (!priv->state_off)
+			priv->state = new_state;
+		break;
+	};
+#if 0
+	printk(KERN_DEBUG "%s: state transition %d -> %d (off#%d)\n",
+	       priv->ndev->name, old_state, new_state, priv->state_off);
+#endif
+
+	/* invariants */
+	BUG_ON(priv->state_off < 0);
+	BUG_ON(priv->state_off && (priv->state != PRV_STATE_OFF));
+	BUG_ON(!priv->state_off && (priv->state == PRV_STATE_OFF));
+
+	/* unlock */
+	return old_state;
+}
--- diff/drivers/net/wireless/prism54/islpci_dev.h	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/net/wireless/prism54/islpci_dev.h	2004-03-16 09:37:58.386664048 +0000
@@ -0,0 +1,228 @@
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_dev.h,v 1.53 2004/02/28 03:06:07 mcgrof Exp $
+ *  
+ *  Copyright (C) 2002 Intersil Americas Inc. 
+ *  Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
+ *  Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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 _ISLPCI_DEV_H
+#define _ISLPCI_DEV_H
+
+#include <linux/version.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/list.h>
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41)
+# include <linux/workqueue.h>
+#else
+# include <linux/tqueue.h>
+# define work_struct tq_struct
+# define INIT_WORK INIT_TQUEUE
+# define schedule_work schedule_task
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23)
+#define free_netdev(x) kfree(x) 
+#define pci_name(x) x->slot_name 
+#endif
+
+#include "isl_38xx.h"
+#include "isl_oid.h"
+#include "islpci_mgt.h"
+
+/* some states might not be superflous and may be removed when
+   design is finalized (hvr) */
+typedef enum {
+	PRV_STATE_OFF = 0,	/* this means hw_unavailable is != 0 */
+	PRV_STATE_PREBOOT,	/* we are in a pre-boot state (empty RAM) */
+	PRV_STATE_BOOT,		/* boot state (fw upload, run fw) */
+	PRV_STATE_POSTBOOT,	/* after boot state, need reset now */
+	PRV_STATE_PREINIT,	/* pre-init state */
+	PRV_STATE_INIT,		/* init state (restore MIB backup to device) */
+	PRV_STATE_READY,	/* driver&device are in operational state */
+	PRV_STATE_SLEEP		/* device in sleep mode */
+} islpci_state_t;
+
+/* ACL using MAC address */
+struct mac_entry {
+   struct list_head _list;
+   char addr[ETH_ALEN];
+};
+
+struct islpci_acl {
+   enum { MAC_POLICY_OPEN=0, MAC_POLICY_ACCEPT=1, MAC_POLICY_REJECT=2 } policy;
+   struct list_head mac_list;  /* a list of mac_entry */
+   int size;   /* size of queue */
+   struct semaphore sem;   /* accessed in ioctls and trap_work */
+};
+
+struct islpci_membuf {
+	int size;                   /* size of memory */
+	void *mem;                  /* address of memory as seen by CPU */
+	dma_addr_t pci_addr;        /* address of memory as seen by device */
+};
+
+#define MAX_BSS_WPA_IE_COUNT 64
+#define MAX_WPA_IE_LEN 64
+struct islpci_bss_wpa_ie {
+	struct list_head list;
+	unsigned long last_update;
+	u8 bssid[ETH_ALEN];
+	u8 wpa_ie[MAX_WPA_IE_LEN];
+	size_t wpa_ie_len;
+	
+};
+
+typedef struct {
+	spinlock_t slock;	/* generic spinlock; */
+	
+	u32 priv_oid;
+
+	/* our mib cache */
+	u32 iw_mode;
+        struct rw_semaphore mib_sem;
+	void **mib;
+	char nickname[IW_ESSID_MAX_SIZE+1];
+	
+	/* Take care of the wireless stats */
+	struct work_struct stats_work;
+	struct semaphore stats_sem;
+	/* remember when we last updated the stats */
+	unsigned long stats_timestamp;
+	/* The first is accessed under semaphore locking.
+	 * The second is the clean one we return to iwconfig.
+	 */
+	struct iw_statistics local_iwstatistics;
+	struct iw_statistics iwstatistics;
+
+	struct islpci_acl acl;
+
+	/* PCI bus allocation & configuration members */
+	struct pci_dev *pdev;	/* PCI structure information */
+	u32 pci_state[16];	/* used for suspend/resume */
+	char firmware[33];
+
+	void *device_base;	/* ioremapped device base address */
+
+	/* consistent DMA region */
+	void *driver_mem_address;	/* base DMA address */
+	dma_addr_t device_host_address;	/* base DMA address (bus address) */
+	dma_addr_t device_psm_buffer;	/* host memory for PSM buffering (bus address) */
+
+	/* our network_device structure  */
+	struct net_device *ndev;
+
+	/* device queue interface members */
+	struct isl38xx_cb *control_block;	/* device control block 
+							   (== driver_mem_address!) */
+
+	/* Each queue has three indexes:
+	 *   free/index_mgmt/data_rx/tx (called index, see below),
+	 *   driver_curr_frag, and device_curr_frag (in the control block)
+	 * All indexes are ever-increasing, but interpreted modulo the
+	 * device queue size when used.
+	 *   index <= device_curr_frag <= driver_curr_frag  at all times
+	 * For rx queues, [index, device_curr_frag) contains fragments
+	 * that the interrupt processing needs to handle (owned by driver).
+	 * [device_curr_frag, driver_curr_frag) is the free space in the
+	 * rx queue, waiting for data (owned by device).  The driver
+	 * increments driver_curr_frag to indicate to the device that more
+	 * buffers are available.
+	 * If device_curr_frag == driver_curr_frag, no more rx buffers are
+	 * available, and the rx DMA engine of the device is halted.
+	 * For tx queues, [index, device_curr_frag) contains fragments
+	 * where tx is done; they need to be freed (owned by driver).
+	 * [device_curr_frag, driver_curr_frag) contains the frames
+	 * that are being transferred (owned by device).  The driver
+	 * increments driver_curr_frag to indicate that more tx work
+	 * needs to be done.
+	 */
+	u32 index_mgmt_rx;              /* real index mgmt rx queue */
+	u32 index_mgmt_tx;              /* read index mgmt tx queue */
+	u32 free_data_rx;	/* free pointer data rx queue */
+	u32 free_data_tx;	/* free pointer data tx queue */
+	u32 data_low_tx_full;	/* full detected flag */
+
+	/* frame memory buffers for the device queues */
+	struct islpci_membuf mgmt_tx[ISL38XX_CB_MGMT_QSIZE];
+	struct islpci_membuf mgmt_rx[ISL38XX_CB_MGMT_QSIZE];
+	struct sk_buff *data_low_tx[ISL38XX_CB_TX_QSIZE];
+	struct sk_buff *data_low_rx[ISL38XX_CB_RX_QSIZE];
+	dma_addr_t pci_map_tx_address[ISL38XX_CB_TX_QSIZE];
+	dma_addr_t pci_map_rx_address[ISL38XX_CB_RX_QSIZE];
+
+	/* driver network interface members */
+	struct net_device_stats statistics;
+
+	/* wait for a reset interrupt */
+	wait_queue_head_t reset_done;
+
+	/* used by islpci_mgt_transaction */
+	struct semaphore mgmt_sem; /* serialize access to mailbox and wqueue */
+	struct islpci_mgmtframe *mgmt_received;	  /* mbox for incoming frame */
+	wait_queue_head_t mgmt_wqueue;            /* waitqueue for mbox */
+
+	/* state machine */
+	islpci_state_t state;
+	int state_off;		/* enumeration of off-state, if 0 then
+				 * we're not in any off-state */
+	
+	/* WPA stuff */
+	int wpa; /* WPA mode enabled */
+	struct list_head bss_wpa_list;
+	int num_bss_wpa;
+	struct semaphore wpa_sem;
+} islpci_private;
+
+static inline islpci_state_t
+islpci_get_state(islpci_private *priv)
+{
+	/* lock */
+	return priv->state;
+	/* unlock */
+}
+
+islpci_state_t islpci_set_state(islpci_private *priv, islpci_state_t new_state);
+
+#define ISLPCI_TX_TIMEOUT               (2*HZ)
+
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,75))
+# define irqreturn_t void
+# define IRQ_HANDLED
+# define IRQ_NONE
+#endif
+
+irqreturn_t islpci_interrupt(int, void *, struct pt_regs *);
+
+int prism54_post_setup(islpci_private *, int);
+int islpci_reset(islpci_private *, int);
+
+static inline void
+islpci_trigger(islpci_private *priv)
+{
+	isl38xx_trigger_device(islpci_get_state(priv) == PRV_STATE_SLEEP,
+			       priv->device_base);
+}
+
+struct net_device_stats *islpci_statistics(struct net_device *);
+
+int prism54_bring_down(islpci_private *);
+int islpci_alloc_memory(islpci_private *);
+int islpci_free_memory(islpci_private *);
+struct net_device *islpci_setup(struct pci_dev *);
+#endif				/* _ISLPCI_DEV_H */
--- diff/drivers/net/wireless/prism54/islpci_eth.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/net/wireless/prism54/islpci_eth.c	2004-03-16 09:37:58.387663896 +0000
@@ -0,0 +1,429 @@
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_eth.c,v 1.27 2004/01/30 16:24:00 ajfa Exp $
+ *  
+ *  Copyright (C) 2002 Intersil Americas 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
+ *
+ *  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/version.h>
+#include <linux/module.h>
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#include "isl_38xx.h"
+#include "islpci_eth.h"
+#include "islpci_mgt.h"
+
+/******************************************************************************
+    Network Interface functions
+******************************************************************************/
+void
+islpci_eth_cleanup_transmit(islpci_private *priv,
+			    isl38xx_control_block *control_block)
+{
+	struct sk_buff *skb;
+	u32 index;
+
+	/* compare the control block read pointer with the free pointer */
+	while (priv->free_data_tx !=
+	       le32_to_cpu(control_block->
+			   device_curr_frag[ISL38XX_CB_TX_DATA_LQ])) {
+		/* read the index of the first fragment to be freed */
+		index = priv->free_data_tx % ISL38XX_CB_TX_QSIZE;
+
+		/* check for holes in the arrays caused by multi fragment frames 
+		 * searching for the last fragment of a frame */
+		if (priv->pci_map_tx_address[index] != (dma_addr_t) NULL) {
+			/* entry is the last fragment of a frame
+			 * free the skb structure and unmap pci memory */
+			skb = priv->data_low_tx[index];
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			DEBUG(SHOW_TRACING,
+			      "cleanup skb %p skb->data %p skb->len %u truesize %u\n ",
+			      skb, skb->data, skb->len, skb->truesize);
+#endif
+
+			pci_unmap_single(priv->pdev,
+					 priv->pci_map_tx_address[index],
+					 skb->len, PCI_DMA_TODEVICE);
+			dev_kfree_skb_irq(skb);
+		}
+		/* increment the free data low queue pointer */
+		priv->free_data_tx++;
+	}
+}
+
+int
+islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
+{
+	islpci_private *priv = ndev->priv;
+	isl38xx_control_block *cb = priv->control_block;
+	u32 index;
+	dma_addr_t pci_map_address;
+	int frame_size;
+	isl38xx_fragment *fragment;
+	int offset;
+	struct sk_buff *newskb;
+	int newskb_offset;
+	unsigned long flags;
+	unsigned char wds_mac[6];
+	u32 curr_frag;
+	int err = 0;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit \n");
+#endif
+
+	/* lock the driver code */
+	spin_lock_irqsave(&priv->slock, flags);
+
+	/* determine the amount of fragments needed to store the frame */
+
+	frame_size = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
+	if (init_wds)
+		frame_size += 6;
+
+	/* check whether the destination queue has enough fragments for the frame */
+	curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ]);
+	if (curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE) {
+		printk(KERN_ERR "%s: transmit device queue full when awake\n",
+		       ndev->name);
+		netif_stop_queue(ndev);
+
+		/* trigger the device */
+		isl38xx_w32_flush(priv->device_base, ISL38XX_DEV_INT_UPDATE,
+				  ISL38XX_DEV_INT_REG);
+		udelay(ISL38XX_WRITEIO_DELAY);
+
+		err = -EBUSY;
+		goto drop_free;
+	}
+	/* Check alignment and WDS frame formatting. The start of the packet should
+	 * be aligned on a 4-byte boundary. If WDS is enabled add another 6 bytes
+	 * and add WDS address information */
+	if (((long) skb->data & 0x03) | init_wds) {
+		/* get the number of bytes to add and re-allign */
+		offset = (4 - (long) skb->data) & 0x03;
+		offset += init_wds ? 6 : 0;
+
+		/* check whether the current skb can be used  */
+		if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) {
+			unsigned char *src = skb->data;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			DEBUG(SHOW_TRACING, "skb offset %i wds %i\n", offset,
+			      init_wds);
+#endif
+
+			/* align the buffer on 4-byte boundary */
+			skb_reserve(skb, (4 - (long) skb->data) & 0x03);
+			if (init_wds) {
+				/* wds requires an additional address field of 6 bytes */
+				skb_put(skb, 6);
+#ifdef ISLPCI_ETH_DEBUG
+				printk("islpci_eth_transmit:wds_mac\n");
+#endif
+				memmove(skb->data + 6, src, skb->len);
+				memcpy(skb->data, wds_mac, 6);
+			} else {
+				memmove(skb->data, src, skb->len);
+			}
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			DEBUG(SHOW_TRACING, "memmove %p %p %i \n", skb->data,
+			      src, skb->len);
+#endif
+		} else {
+			newskb =
+			    dev_alloc_skb(init_wds ? skb->len + 6 : skb->len);
+			newskb_offset = (4 - (long) newskb->data) & 0x03;
+
+			/* Check if newskb->data is aligned */
+			if (newskb_offset)
+				skb_reserve(newskb, newskb_offset);
+
+			skb_put(newskb, init_wds ? skb->len + 6 : skb->len);
+			if (init_wds) {
+				memcpy(newskb->data + 6, skb->data, skb->len);
+				memcpy(newskb->data, wds_mac, 6);
+#ifdef ISLPCI_ETH_DEBUG
+				printk("islpci_eth_transmit:wds_mac\n");
+#endif
+			} else
+				memcpy(newskb->data, skb->data, skb->len);
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			DEBUG(SHOW_TRACING, "memcpy %p %p %i wds %i\n",
+			      newskb->data, skb->data, skb->len, init_wds);
+#endif
+
+			newskb->dev = skb->dev;
+			dev_kfree_skb(skb);
+			skb = newskb;
+		}
+	}
+	/* display the buffer contents for debugging */
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_BUFFER_CONTENTS, "\ntx %p ", skb->data);
+	display_buffer((char *) skb->data, skb->len);
+#endif
+
+	/* map the skb buffer to pci memory for DMA operation */
+	pci_map_address = pci_map_single(priv->pdev,
+					 (void *) skb->data, skb->len,
+					 PCI_DMA_TODEVICE);
+	if (pci_map_address == 0) {
+		printk(KERN_WARNING "%s: cannot map buffer to PCI\n",
+		       ndev->name);
+
+		err = -EIO;
+		goto drop_free;
+	}
+	/* Place the fragment in the control block structure. */
+	index = curr_frag % ISL38XX_CB_TX_QSIZE;
+	fragment = &cb->tx_data_low[index];
+
+	priv->pci_map_tx_address[index] = pci_map_address;
+	/* store the skb address for future freeing  */
+	priv->data_low_tx[index] = skb;
+	/* set the proper fragment start address and size information */
+	fragment->size = cpu_to_le16(frame_size);
+	fragment->flags = cpu_to_le16(0);  /* set to 1 if more fragments */
+	fragment->address = cpu_to_le32(pci_map_address);
+	curr_frag++;
+
+	/* The fragment address in the control block must have been
+	 * written before announcing the frame buffer to device. */
+	wmb();
+	cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ] = cpu_to_le32(curr_frag);
+
+	if (curr_frag - priv->free_data_tx + ISL38XX_MIN_QTHRESHOLD
+	                                           > ISL38XX_CB_TX_QSIZE) {
+		/* stop sends from upper layers */
+		netif_stop_queue(ndev);
+
+		/* set the full flag for the transmission queue */
+		priv->data_low_tx_full = 1;
+	}
+
+	/* trigger the device */
+	islpci_trigger(priv);
+
+	/* unlock the driver code */
+	spin_unlock_irqrestore(&priv->slock, flags);
+
+	/* set the transmission time */
+	ndev->trans_start = jiffies;
+	priv->statistics.tx_packets++;
+	priv->statistics.tx_bytes += skb->len;
+
+	return 0;
+
+ drop_free:
+	/* free the skbuf structure before aborting */
+	dev_kfree_skb(skb);
+
+	priv->statistics.tx_dropped++;
+	spin_unlock_irqrestore(&priv->slock, flags);
+	return err;
+}
+
+int
+islpci_eth_receive(islpci_private *priv)
+{
+	struct net_device *ndev = priv->ndev;
+	isl38xx_control_block *control_block = priv->control_block;
+	struct sk_buff *skb;
+	u16 size;
+	u32 index, offset;
+	unsigned char *src;
+	int discard = 0;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_receive \n");
+#endif
+
+	/* the device has written an Ethernet frame in the data area
+	 * of the sk_buff without updating the structure, do it now */
+	index = priv->free_data_rx % ISL38XX_CB_RX_QSIZE;
+	size = le16_to_cpu(control_block->rx_data_low[index].size);
+	skb = priv->data_low_rx[index];
+	offset = ((unsigned long) le32_to_cpu(control_block->rx_data_low[index].address) -
+		  (unsigned long) skb->data) & 3;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_TRACING,
+	      "frq->addr %x skb->data %p skb->len %u offset %u truesize %u\n ",
+	      control_block->rx_data_low[priv->free_data_rx].address, skb->data,
+	      skb->len, offset, skb->truesize);
+#endif
+
+	/* delete the streaming DMA mapping before processing the skb */
+	pci_unmap_single(priv->pdev,
+			 priv->pci_map_rx_address[index],
+			 MAX_FRAGMENT_SIZE_RX + 2, PCI_DMA_FROMDEVICE);
+
+	/* update the skb structure and allign the buffer */
+	skb_put(skb, size);
+	if (offset) {
+		/* shift the buffer allocation offset bytes to get the right frame */
+		skb_pull(skb, 2);
+		skb_put(skb, 2);
+	}
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	/* display the buffer contents for debugging */
+	DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data);
+	display_buffer((char *) skb->data, skb->len);
+#endif
+
+	/* check whether WDS is enabled and whether the data frame is a WDS frame */
+
+	if (init_wds) {
+		/* WDS enabled, check for the wds address on the first 6 bytes of the buffer */
+		src = skb->data + 6;
+		memmove(skb->data, src, skb->len - 6);
+		skb_trim(skb, skb->len - 6);
+	}
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_TRACING, "Fragment size %i in skb at %p\n", size, skb);
+	DEBUG(SHOW_TRACING, "Skb data at %p, length %i\n", skb->data, skb->len);
+
+	/* display the buffer contents for debugging */
+	DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data);
+	display_buffer((char *) skb->data, skb->len);
+#endif
+
+	/* do some additional sk_buff and network layer parameters */
+	skb->dev = ndev;
+
+	/* take care of monitor mode */
+	if (priv->iw_mode == IW_MODE_MONITOR) {
+		/* The card reports full 802.11 packets but with a 20 bytes
+		 * header and without the FCS. But there a is a bit that
+		 * indicates if the packet is corrupted :-) */
+		/* int i; */
+		if (skb->data[8] & 0x01){
+			/* This one is bad. Drop it !*/
+			discard = 1;
+			/* printk("BAD\n");*/
+		}
+		/*
+		for(i=0;i<50;i++)
+			printk("%2.2X:",skb->data[i]);
+		printk("\n");
+		*/		
+		skb_pull(skb, 20);
+		skb->protocol = htons(ETH_P_802_2);
+		skb->mac.raw = skb->data;
+		skb->pkt_type = PACKET_OTHERHOST;
+	} else
+		skb->protocol = eth_type_trans(skb, ndev);
+
+	skb->ip_summed = CHECKSUM_NONE;
+	priv->statistics.rx_packets++;
+	priv->statistics.rx_bytes += size;
+
+	/* deliver the skb to the network layer */
+#ifdef ISLPCI_ETH_DEBUG
+	printk
+	    ("islpci_eth_receive:netif_rx %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+	     skb->data[0], skb->data[1], skb->data[2], skb->data[3],
+	     skb->data[4], skb->data[5]);
+#endif
+	if (discard)
+		dev_kfree_skb(skb);
+	else
+		netif_rx(skb);
+
+	/* increment the read index for the rx data low queue */
+	priv->free_data_rx++;
+
+	/* add one or more sk_buff structures */
+	while (index =
+	       le32_to_cpu(control_block->
+			   driver_curr_frag[ISL38XX_CB_RX_DATA_LQ]),
+	       index - priv->free_data_rx < ISL38XX_CB_RX_QSIZE) {
+		/* allocate an sk_buff for received data frames storage
+		 * include any required allignment operations */
+		if (skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2), skb == NULL) {
+			/* error allocating an sk_buff structure elements */
+			DEBUG(SHOW_ERROR_MESSAGES, "Error allocating skb \n");
+			break;
+		}
+		/* store the new skb structure pointer */
+		index = index % ISL38XX_CB_RX_QSIZE;
+		priv->data_low_rx[index] = skb;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+		DEBUG(SHOW_TRACING,
+		      "new alloc skb %p skb->data %p skb->len %u index %u truesize %u\n ",
+		      skb, skb->data, skb->len, index, skb->truesize);
+#endif
+
+		/* set the streaming DMA mapping for proper PCI bus operation */
+		priv->pci_map_rx_address[index] =
+		    pci_map_single(priv->pdev, (void *) skb->data,
+				   MAX_FRAGMENT_SIZE_RX + 2,
+				   PCI_DMA_FROMDEVICE);
+		if (priv->pci_map_rx_address[index] == (dma_addr_t) NULL) {
+			/* error mapping the buffer to device accessable memory address */
+			DEBUG(SHOW_ERROR_MESSAGES,
+			      "Error mapping DMA address\n");
+
+			/* free the skbuf structure before aborting */
+			dev_kfree_skb((struct sk_buff *) skb);
+			break;
+		}
+		/* update the fragment address */
+		control_block->rx_data_low[index].address = cpu_to_le32((u32)
+									priv->
+									pci_map_rx_address
+									[index]);
+		wmb();
+
+		/* increment the driver read pointer */
+		add_le32p((u32 *) & control_block->
+			  driver_curr_frag[ISL38XX_CB_RX_DATA_LQ], 1);
+	}
+
+	/* trigger the device */
+	islpci_trigger(priv);
+
+	return 0;
+}
+
+void
+islpci_eth_tx_timeout(struct net_device *ndev)
+{
+	islpci_private *priv = ndev->priv;
+	struct net_device_stats *statistics = &priv->statistics;
+
+	/* increment the transmit error counter */
+	statistics->tx_errors++;
+
+#if 0
+	/* don't do this here! we are not allowed to sleep since we are in interrupt context */
+	if (islpci_reset(priv))
+		printk(KERN_ERR "%s: error on TX timeout card reset!\n",
+		       ndev->name);
+#endif
+
+	/* netif_wake_queue(ndev); */
+	return;
+}
--- diff/drivers/net/wireless/prism54/islpci_eth.h	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/net/wireless/prism54/islpci_eth.h	2004-03-16 09:37:58.388663744 +0000
@@ -0,0 +1,31 @@
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_eth.h,v 1.5 2004/01/12 22:16:32 jmaurer Exp $
+ *  
+ *  Copyright (C) 2002 Intersil Americas 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
+ *
+ *  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 _ISLPCI_ETH_H
+#define _ISLPCI_ETH_H
+
+#include "isl_38xx.h"
+#include "islpci_dev.h"
+
+void islpci_eth_cleanup_transmit(islpci_private *, isl38xx_control_block *);
+int islpci_eth_transmit(struct sk_buff *, struct net_device *);
+int islpci_eth_receive(islpci_private *);
+void islpci_eth_tx_timeout(struct net_device *);
+
+#endif				/* _ISL_GEN_H */
--- diff/drivers/net/wireless/prism54/islpci_hotplug.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/net/wireless/prism54/islpci_hotplug.c	2004-03-16 09:37:58.389663592 +0000
@@ -0,0 +1,428 @@
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_hotplug.c,v 1.56 2004/02/26 23:33:02 mcgrof Exp $
+ *  
+ *  Copyright (C) 2002 Intersil Americas Inc.
+ *  Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  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/version.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/init.h> /* For __init, __exit */
+
+#include "islpci_dev.h"
+#include "islpci_mgt.h"		/* for pc_debug */
+#include "isl_oid.h"
+
+#define DRV_NAME	"prism54"
+#define DRV_VERSION	"1.0.2.2"
+
+MODULE_AUTHOR("W.Termorshuizen, R.Bastings, H.V.Riedel, prism54.org team");
+MODULE_DESCRIPTION("Intersil 802.11 Wireless LAN adapter");
+MODULE_LICENSE("GPL");
+
+/* In this order: vendor, device, subvendor, subdevice, class, class_mask,
+ * driver_data 
+ * Note: for driver_data we put the device's name 
+ * If you have an update for this please contact prism54-devel@prism54.org 
+ * The latest list can be found at http://prism54.org/supported_cards.php */
+static const struct pci_device_id prism54_id_tbl[] = {
+	{
+	 PCIVENDOR_3COM, PCIDEVICE_3COM6001,
+	 PCIVENDOR_3COM, PCIDEVICE_3COM6001,
+	 0, 0,
+	 (unsigned long) "3COM 3CRWE154G72 Wireless LAN adapter"},
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_DLINK, 0x3202UL, 
+	 0, 0,
+	 (unsigned long) "D-Link Air Plus Xtreme G A1 - DWL-g650 A1"},
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_IODATA, 0xd019UL, 
+	 0, 0,
+	 (unsigned long) "I-O Data WN-G54/CB - WN-G54/CB"},
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_NETGEAR, 0x4800UL,
+	 0, 0,
+	 (unsigned long) "Netgear WG511"},
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_I4, 0x0020UL,
+	 0, 0,
+	 (unsigned long) "PLANEX GW-DS54G"},
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_SMC, 0x2802UL,
+	 0, 0,
+	 (unsigned long) "EZ Connect g 2.4GHz 54 Mbps Wireless PCI Card - SMC2802W"},
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_SMC, 0x2835UL,
+	 0, 0,
+	 (unsigned long) "EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Adapter - SMC2835W"},
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_INTERSIL, 0x0000UL, /* This was probably a bogus reading... */
+	 0, 0,
+	 (unsigned long) "SparkLAN WL-850F"},
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_I4, 0x0014UL,
+	 0, 0,
+	 (unsigned long) "I4 Z-Com XG-600"},
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_I4, 0x0020UL,
+	 0, 0,
+	 (unsigned long) "I4 Z-Com XG-900/PLANEX GW-DS54G"},
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_ACCTON, 0xee03UL,
+	 0, 0,
+	 (unsigned long) "SMC 2802Wv2"},
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3877,
+	 PCI_ANY_ID, PCI_ANY_ID,
+	 0, 0,
+	 (unsigned long) "Intersil PRISM Indigo Wireless LAN adapter"},
+	{ /* Default */
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCI_ANY_ID, PCI_ANY_ID,
+	 0, 0,
+	 (unsigned long) "Intersil PRISM Duette/Prism GT Wireless LAN adapter"},
+	{0,}
+};
+
+/* register the device with the Hotplug facilities of the kernel */
+MODULE_DEVICE_TABLE(pci, prism54_id_tbl);
+
+static int prism54_probe(struct pci_dev *, const struct pci_device_id *);
+static void prism54_remove(struct pci_dev *);
+static int prism54_suspend(struct pci_dev *, u32 state);
+static int prism54_resume(struct pci_dev *);
+
+static struct pci_driver prism54_driver = {
+	.name = DRV_NAME,
+	.id_table = prism54_id_tbl,
+	.probe = prism54_probe,
+	.remove = prism54_remove,
+	.suspend = prism54_suspend,
+	.resume = prism54_resume,
+	/* .enable_wake ; we don't support this yet */
+};
+
+static void
+prism54_get_card_model(struct net_device *ndev)
+{
+	islpci_private	*priv;
+	char		*modelp;
+
+	priv = ndev->priv;
+	switch (priv->pdev->subsystem_device) {
+	case PCIDEVICE_ISL3877:
+		modelp = "PRISM Indigo";
+		break;
+	case PCIDEVICE_3COM6001:
+		modelp = "3COM 3CRWE154G72";
+		break;
+	case 0x3202UL:
+		modelp = "D-Link DWL-g650 A1";
+		break;
+	case 0xd019UL:
+		modelp = "WN-G54/CB";
+		break;
+	case 0x4800UL:
+		modelp = "Netgear WG511";
+		break;
+	case 0x2802UL:
+		modelp = "SMC2802W";
+		break;
+	case 0xee03UL:
+		modelp = "SMC2802W V2";
+		break;
+	case 0x2835UL:
+		modelp = "SMC2835W";
+		break;
+	/* Let's leave this one out for now since it seems bogus/wrong 
+	 * Even if the manufacturer did use 0x0000UL it may not be correct
+	 * by their part, therefore deserving no name ;) */
+	/*      case 0x0000UL: 
+	 *              modelp = "SparkLAN WL-850F";
+	 *              break;*/
+
+	/* We have two reported for the one below :( */
+	case 0x0014UL:
+		modelp = "XG-600";
+		break;
+	case 0x0020UL:
+		modelp = "XG-900/GW-DS54G";
+		break;
+/* Default it */
+/*
+	case PCIDEVICE_ISL3890:
+		modelp = "PRISM Duette/GT";
+		break;
+*/
+	default:
+		modelp = "PRISM Duette/GT";
+	}
+	printk(KERN_DEBUG "%s: %s driver detected card model: %s\n",
+			ndev->name, DRV_NAME, modelp);
+	return;
+}
+
+/******************************************************************************
+    Module initialization functions
+******************************************************************************/
+
+int
+prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct net_device *ndev;
+	u8 latency_tmr;
+	u32 mem_addr;
+	islpci_private *priv;
+	int rvalue;
+
+	/* TRACE(DRV_NAME); */
+	
+	
+	/* Enable the pci device */
+	if (pci_enable_device(pdev)) {
+		printk(KERN_ERR "%s: pci_enable_device() failed.\n", DRV_NAME);
+		return -ENODEV;
+	}
+
+	/* check whether the latency timer is set correctly */
+	pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_tmr);
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_TRACING, "latency timer: %x\n", latency_tmr);
+#endif
+	if (latency_tmr < PCIDEVICE_LATENCY_TIMER_MIN) {
+		/* set the latency timer */
+		pci_write_config_byte(pdev, PCI_LATENCY_TIMER,
+				      PCIDEVICE_LATENCY_TIMER_VAL);
+	}
+
+	/* enable PCI DMA */
+	if (pci_set_dma_mask(pdev, 0xffffffff)) {
+		printk(KERN_ERR "%s: 32-bit PCI DMA not supported", DRV_NAME);
+		goto do_pci_disable_device;
+        }
+
+	/* 0x40 is the programmable timer to configure the response timeout (TRDY_TIMEOUT)
+	 * 0x41 is the programmable timer to configure the retry timeout (RETRY_TIMEOUT)
+	 * 	The RETRY_TIMEOUT is used to set the number of retries that the core, as a
+	 * 	Master, will perform before abandoning a cycle. The default value for
+	 * 	RETRY_TIMEOUT is 0x80, which far exceeds the PCI 2.1 requirement for new
+	 * 	devices. A write of zero to the RETRY_TIMEOUT register disables this
+	 * 	function to allow use with any non-compliant legacy devices that may
+	 * 	execute more retries.
+	 *
+	 * 	Writing zero to both these two registers will disable both timeouts and
+	 * 	*can* solve problems caused by devices that are slow to respond.
+	 */
+	pci_write_config_byte(pdev, 0x40, 0);
+	pci_write_config_byte(pdev, 0x41, 0);
+
+	/* request the pci device I/O regions */
+	rvalue = pci_request_regions(pdev, DRV_NAME);
+	if (rvalue) {
+		printk(KERN_ERR "%s: pci_request_regions failure (rc=%d)\n",
+		       DRV_NAME, rvalue);
+		goto do_pci_disable_device;
+	}
+
+	/* check if the memory window is indeed set */
+	rvalue = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &mem_addr);
+	if (rvalue || !mem_addr) {
+		printk(KERN_ERR "%s: PCI device memory region not configured; fix your BIOS or CardBus bridge/drivers\n",
+		       DRV_NAME);
+		goto do_pci_disable_device;
+	}
+
+	/* enable PCI bus-mastering */
+	DEBUG(SHOW_TRACING, "%s: pci_set_master(pdev)\n", DRV_NAME);
+	pci_set_master(pdev);
+
+	/* setup the network device interface and its structure */
+	if (!(ndev = islpci_setup(pdev))) {
+		/* error configuring the driver as a network device */
+		printk(KERN_ERR "%s: could not configure network device\n",
+		       DRV_NAME);
+		goto do_pci_release_regions;
+	}
+
+	priv = ndev->priv;
+	islpci_set_state(priv, PRV_STATE_PREBOOT); /* we are attempting to boot */
+
+	/* card is in unknown state yet, might have some interrupts pending */
+	isl38xx_disable_interrupts(priv->device_base);
+
+	/* request for the interrupt before uploading the firmware */
+	rvalue = request_irq(pdev->irq, &islpci_interrupt,
+			     SA_SHIRQ, ndev->name, priv);
+
+	if (rvalue) {
+		/* error, could not hook the handler to the irq */
+		printk(KERN_ERR "%s: could not install IRQ handler\n",
+		       ndev->name);
+		goto do_unregister_netdev;
+	}
+
+	/* firmware upload is triggered in islpci_open */
+
+	/* Pretty card model discovery output */
+	prism54_get_card_model(ndev);
+
+	return 0;
+
+      do_unregister_netdev:
+	unregister_netdev(ndev);
+	islpci_free_memory(priv);
+	pci_set_drvdata(pdev, 0);
+	free_netdev(ndev);
+	priv = 0;
+      do_pci_release_regions:
+	pci_release_regions(pdev);
+      do_pci_disable_device:
+	pci_disable_device(pdev);
+	return -EIO;
+}
+
+/* set by cleanup_module */
+static volatile int __in_cleanup_module = 0;
+
+/* this one removes one(!!) instance only */
+void
+prism54_remove(struct pci_dev *pdev)
+{
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	islpci_private *priv = ndev ? ndev->priv : 0;
+	BUG_ON(!priv);
+
+	if (!__in_cleanup_module) {
+		printk(KERN_DEBUG "%s: hot unplug detected\n", ndev->name);
+		islpci_set_state(priv, PRV_STATE_OFF);
+	}
+
+	printk(KERN_DEBUG "%s: removing device\n", ndev->name);
+
+	unregister_netdev(ndev);
+
+	/* free the interrupt request */
+
+	if (islpci_get_state(priv) != PRV_STATE_OFF) {
+		isl38xx_disable_interrupts(priv->device_base);
+		islpci_set_state(priv, PRV_STATE_OFF);
+		/* This bellow causes a lockup at rmmod time. It might be
+		 * because some interrupts still linger after rmmod time, 
+		 * see bug #17 */
+		/* pci_set_power_state(pdev, 3);*/	/* try to power-off */
+	}
+
+	free_irq(pdev->irq, priv);
+
+	/* free the PCI memory and unmap the remapped page */
+	islpci_free_memory(priv);
+
+	pci_set_drvdata(pdev, 0);
+	free_netdev(ndev);
+	priv = 0;
+
+	pci_release_regions(pdev);
+
+	pci_disable_device(pdev);
+}
+
+int
+prism54_suspend(struct pci_dev *pdev, u32 state)
+{
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	islpci_private *priv = ndev ? ndev->priv : 0;
+	BUG_ON(!priv);
+
+	printk(KERN_NOTICE "%s: got suspend request (state %d)\n",
+	       ndev->name, state);
+
+	pci_save_state(pdev, priv->pci_state);
+
+	/* tell the device not to trigger interrupts for now... */
+	isl38xx_disable_interrupts(priv->device_base);
+
+	/* from now on assume the hardware was already powered down
+	   and don't touch it anymore */
+	islpci_set_state(priv, PRV_STATE_OFF);
+
+	netif_stop_queue(ndev);
+	netif_device_detach(ndev);
+
+	return 0;
+}
+
+int
+prism54_resume(struct pci_dev *pdev)
+{
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	islpci_private *priv = ndev ? ndev->priv : 0;
+	BUG_ON(!priv);
+
+	printk(KERN_NOTICE "%s: got resume request\n", ndev->name);
+
+	pci_restore_state(pdev, priv->pci_state);
+
+	/* alright let's go into the PREBOOT state */
+	islpci_reset(priv, 1);
+
+	netif_device_attach(ndev);
+	netif_start_queue(ndev);
+
+	return 0;
+}
+
+static int __init
+prism54_module_init(void)
+{
+	printk(KERN_INFO "Loaded %s driver, version %s\n",
+	       DRV_NAME, DRV_VERSION);
+
+	__bug_on_wrong_struct_sizes ();
+
+	return pci_module_init(&prism54_driver);
+}
+
+/* by the time prism54_module_exit() terminates, as a postcondition
+ * all instances will have been destroyed by calls to
+ * prism54_remove() */
+static void __exit
+prism54_module_exit(void)
+{
+	__in_cleanup_module = 1;
+
+	pci_unregister_driver(&prism54_driver);
+
+	printk(KERN_INFO "Unloaded %s driver\n", DRV_NAME);
+
+	__in_cleanup_module = 0;
+}
+
+/* register entry points */
+module_init(prism54_module_init);
+module_exit(prism54_module_exit);
+/* EOF */
--- diff/drivers/net/wireless/prism54/islpci_mgt.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/net/wireless/prism54/islpci_mgt.c	2004-03-16 09:37:58.391663288 +0000
@@ -0,0 +1,510 @@
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_mgt.c,v 1.40 2004/02/01 10:57:23 mcgrof Exp $
+ *  
+ *  Copyright (C) 2002 Intersil Americas Inc.
+ *  Copyright 2004 Jens Maurer <Jens.Maurer@gmx.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  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/config.h>
+#include <linux/netdevice.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/if_arp.h>
+
+#include "isl_38xx.h"
+#include "islpci_mgt.h"
+#include "isl_oid.h"		/* additional types and defs for isl38xx fw */
+#include "isl_ioctl.h"
+
+#include <net/iw_handler.h>
+
+/******************************************************************************
+        Global variable definition section
+******************************************************************************/
+int pc_debug = VERBOSE;
+MODULE_PARM(pc_debug, "i");
+
+/******************************************************************************
+    Driver general functions
+******************************************************************************/
+void
+display_buffer(char *buffer, int length)
+{
+	if ((pc_debug & SHOW_BUFFER_CONTENTS) == 0)
+		return;
+
+	while (length > 0) {
+		printk("[%02x]", *buffer & 255);
+		length--;
+		buffer++;
+	}
+
+	printk("\n");
+}
+
+/*****************************************************************************
+    Queue handling for management frames
+******************************************************************************/
+
+  
+/*
+ * Helper function to create a PIMFOR management frame header.
+ */
+static void
+pimfor_encode_header(int operation, u32 oid, u32 length, pimfor_header_t *h)
+{
+	h->version = PIMFOR_VERSION;
+	h->operation = operation;
+	h->device_id = PIMFOR_DEV_ID_MHLI_MIB;
+	h->flags = 0;
+	h->oid = cpu_to_be32(oid);
+	h->length = cpu_to_be32(length);
+}
+
+/*
+ * Helper function to analyze a PIMFOR management frame header.
+ */
+static pimfor_header_t *
+pimfor_decode_header(void *data, int len)
+{
+	pimfor_header_t *h = data;
+
+        while ((void *) h < data + len) {
+		if(h->flags & PIMFOR_FLAG_LITTLE_ENDIAN) {
+			le32_to_cpus(&h->oid);
+			le32_to_cpus(&h->length);
+		} else {
+			be32_to_cpus(&h->oid);
+			be32_to_cpus(&h->length);
+		}
+		if (h->oid != OID_INL_TUNNEL)
+			return h;
+		h++;
+	}
+	return NULL;
+}
+
+/*
+ * Fill the receive queue for management frames with fresh buffers.
+ */
+int
+islpci_mgmt_rx_fill(struct net_device *ndev)
+{
+	islpci_private *priv = ndev->priv;
+	isl38xx_control_block *cb =    /* volatile not needed */
+		(isl38xx_control_block *) priv->control_block;
+	u32 curr = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ]);
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgmt_rx_fill \n");
+#endif
+
+	while (curr - priv->index_mgmt_rx < ISL38XX_CB_MGMT_QSIZE) {
+		u32 index = curr % ISL38XX_CB_MGMT_QSIZE;
+		struct islpci_membuf *buf = &priv->mgmt_rx[index];
+		isl38xx_fragment *frag = &cb->rx_data_mgmt[index];
+
+		if (buf->mem == NULL) {
+			buf->mem = kmalloc(MGMT_FRAME_SIZE, GFP_ATOMIC);
+			if (!buf->mem) {
+				printk(KERN_WARNING "Error allocating management frame.\n");
+				return -ENOMEM;
+			}
+			buf->size = MGMT_FRAME_SIZE;
+		}
+		if (buf->pci_addr == 0) {
+			buf->pci_addr = pci_map_single(priv->pdev, buf->mem,
+						       MGMT_FRAME_SIZE,
+						       PCI_DMA_FROMDEVICE);
+			if(!buf->pci_addr) {
+				printk(KERN_WARNING "Failed to make memory DMA'able\n.");
+				return -ENOMEM;
+			}
+		}
+
+                /* be safe: always reset control block information */
+		frag->size = cpu_to_le16(MGMT_FRAME_SIZE);
+		frag->flags = 0;
+		frag->address = cpu_to_le32(buf->pci_addr);
+		curr++;
+
+                /* The fragment address in the control block must have
+                 * been written before announcing the frame buffer to
+                 * device */
+		wmb();
+		cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] =
+			cpu_to_le32(curr);
+	}
+	return 0;
+}
+
+/*
+ * Create and transmit a management frame using "operation" and "oid",
+ * with arguments data/length.
+ * We either return an error and free the frame, or we return 0 and
+ * islpci_mgt_cleanup_transmit() frees the frame in the tx-done
+ * interrupt.
+ */
+static int
+islpci_mgt_transmit(struct net_device *ndev, int operation, unsigned long oid,
+		    void *data, int length)
+{
+	islpci_private *priv = ndev->priv;
+	isl38xx_control_block *cb =
+		(isl38xx_control_block *) priv->control_block;
+	void *p;
+	int err = -EINVAL;
+	unsigned long flags;
+	isl38xx_fragment *frag;
+	struct islpci_membuf buf;
+	u32 curr_frag;
+	int index;
+	int frag_len = length + PIMFOR_HEADER_SIZE;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_transmit\n");
+#endif
+
+	if (frag_len > MGMT_FRAME_SIZE) {
+		printk(KERN_DEBUG "%s: mgmt frame too large %d\n",
+		       ndev->name, frag_len);
+		goto error;
+	}
+
+	err = -ENOMEM;
+	p = buf.mem = kmalloc(frag_len, GFP_KERNEL);
+	if (!buf.mem) {
+		printk(KERN_DEBUG "%s: cannot allocate mgmt frame\n",
+		       ndev->name);
+		goto error;
+	}
+	buf.size = frag_len;
+
+	/* create the header directly in the fragment data area */
+	pimfor_encode_header(operation, oid, length, (pimfor_header_t *) p);
+	p += PIMFOR_HEADER_SIZE;
+
+	if (data)
+		memcpy(p, data, length);
+	else
+		memset(p, 0, length);
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	{
+		pimfor_header_t *h = buf.mem;
+		DEBUG(SHOW_PIMFOR_FRAMES,
+		      "PIMFOR: op %i, oid 0x%08lx, device %i, flags 0x%x length 0x%x \n",
+		      h->operation, oid, h->device_id, h->flags, length);
+
+		/* display the buffer contents for debugging */
+		display_buffer((char *) h, sizeof (pimfor_header_t));
+		display_buffer(p, length);
+	}
+#endif
+
+	err = -ENOMEM;
+	buf.pci_addr = pci_map_single(priv->pdev, buf.mem, frag_len,
+				      PCI_DMA_TODEVICE);
+	if (!buf.pci_addr) {
+		printk(KERN_WARNING "%s: cannot map PCI memory for mgmt\n",
+		       ndev->name);
+		goto error_free;
+	}
+
+	/* Protect the control block modifications against interrupts. */
+	spin_lock_irqsave(&priv->slock, flags);
+	curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ]);
+	if (curr_frag - priv->index_mgmt_tx >= ISL38XX_CB_MGMT_QSIZE) {
+		printk(KERN_WARNING "%s: mgmt tx queue is still full\n",
+		       ndev->name);
+		goto error_unlock;
+	}
+
+	/* commit the frame to the tx device queue */
+	index = curr_frag % ISL38XX_CB_MGMT_QSIZE;
+	priv->mgmt_tx[index] = buf;
+	frag = &cb->tx_data_mgmt[index];
+	frag->size = cpu_to_le16(frag_len);
+	frag->flags = 0;   /* for any other than the last fragment, set to 1 */
+	frag->address = cpu_to_le32(buf.pci_addr);
+
+	/* The fragment address in the control block must have
+	 * been written before announcing the frame buffer to
+	 * device */
+	wmb();
+	cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ] = cpu_to_le32(curr_frag+1);
+	spin_unlock_irqrestore(&priv->slock, flags);
+
+	/* trigger the device */
+	islpci_trigger(priv);
+	return 0;
+
+ error_unlock:
+	spin_unlock_irqrestore(&priv->slock, flags);
+ error_free:
+	kfree(buf.mem);
+ error:
+	return err;
+}
+
+/*
+ * Receive a management frame from the device.
+ * This can be an arbitrary number of traps, and at most one response
+ * frame for a previous request sent via islpci_mgt_transmit().
+ */
+int
+islpci_mgt_receive(struct net_device *ndev)
+{
+	islpci_private *priv = ndev->priv;
+	isl38xx_control_block *cb =
+		(isl38xx_control_block *) priv->control_block;
+	u32 curr_frag;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_receive \n");
+#endif
+
+
+        /* Only once per interrupt, determine fragment range to
+         * process.  This avoids an endless loop (i.e. lockup) if
+         * frames come in faster than we can process them. */
+	curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_RX_MGMTQ]);
+	barrier();
+
+	for ( ; priv->index_mgmt_rx < curr_frag; priv->index_mgmt_rx++) {
+		pimfor_header_t *header;
+		u32 index = priv->index_mgmt_rx % ISL38XX_CB_MGMT_QSIZE;
+		struct islpci_membuf *buf = &priv->mgmt_rx[index];
+		u16 frag_len;
+		int size;
+		struct islpci_mgmtframe *frame;
+              
+                /* I have no idea (and no documentation) if flags != 0
+                 * is possible.  Drop the frame, reuse the buffer. */
+                if(le16_to_cpu(cb->rx_data_mgmt[index].flags) != 0) {
+                        printk(KERN_WARNING "%s: unknown flags 0x%04x\n",
+                               ndev->name,
+                               le16_to_cpu(cb->rx_data_mgmt[index].flags));
+                        continue;
+                }
+
+		/* The device only returns the size of the header(s) here. */
+		frag_len = le16_to_cpu(cb->rx_data_mgmt[index].size);
+
+		/*
+                 * We appear to have no way to tell the device the
+                 * size of a receive buffer.  Thus, if this check
+                 * triggers, we likely have kernel heap corruption. */
+                if (frag_len > MGMT_FRAME_SIZE) {
+                        printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\
+n",
+                               ndev->name, frag_len, frag_len);
+                        frag_len = MGMT_FRAME_SIZE;
+                }
+
+		/* Ensure the results of device DMA are visible to the CPU. */
+		pci_dma_sync_single(priv->pdev, buf->pci_addr,
+				    buf->size, PCI_DMA_FROMDEVICE);
+
+		/* Perform endianess conversion for PIMFOR header in-place. */
+		header = pimfor_decode_header(buf->mem, frag_len);
+		if (!header) {
+			printk(KERN_WARNING "%s: no PIMFOR header found\n",
+			       ndev->name);
+			continue;
+		}
+
+		/* The device ID from the PIMFOR packet received from
+		 * the MVC is always 0.  We forward a sensible device_id.
+		 * Not that anyone upstream would care... */
+		header->device_id = priv->ndev->ifindex;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+		DEBUG(SHOW_PIMFOR_FRAMES,
+		      "PIMFOR: op %i, oid 0x%08x, device %i, flags 0x%x length 0x%x \n",
+		      header->operation, header->oid, header->device_id, 
+		      header->flags, header->length);
+
+		/* display the buffer contents for debugging */
+		display_buffer((char *) header, PIMFOR_HEADER_SIZE);
+		display_buffer((char *) header + PIMFOR_HEADER_SIZE, header->length);
+#endif
+
+		/* nobody sends these */
+		if (header->flags & PIMFOR_FLAG_APPLIC_ORIGIN) {
+			printk(KERN_DEBUG "%s: errant PIMFOR application frame\n",
+			       ndev->name);
+			continue;
+		}
+
+		/* Determine frame size, skipping OID_INL_TUNNEL headers. */
+		size = PIMFOR_HEADER_SIZE + header->length;
+		frame = kmalloc(sizeof(struct islpci_mgmtframe) + size,
+				GFP_ATOMIC);
+		if (!frame) {
+			printk(KERN_WARNING "%s: Out of memory, cannot handle oid 0x%08x\n",
+
+			       ndev->name, header->oid);
+			continue;        
+		}
+		frame->ndev = ndev;
+		memcpy(&frame->buf, header, size);
+		frame->header = (pimfor_header_t *) frame->buf;
+		frame->data = frame->buf + PIMFOR_HEADER_SIZE;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+		DEBUG(SHOW_PIMFOR_FRAMES,
+		      "frame: header: %p, data: %p, size: %d\n",
+		      frame->header, frame->data, size);
+#endif
+
+		if (header->operation == PIMFOR_OP_TRAP) {
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			printk(KERN_DEBUG
+			       "TRAP: oid 0x%x, device %i, flags 0x%x length %i\n",
+			       header->oid, header->device_id, header->flags,
+			       header->length);
+#endif
+                      
+			/* Create work to handle trap out of interrupt
+			 * context. */
+			INIT_WORK(&frame->ws, prism54_process_trap, frame);
+			schedule_work(&frame->ws);
+
+		} else {
+			/* Signal the one waiting process that a response
+			 * has been received. */
+			if ((frame = xchg(&priv->mgmt_received, frame)) != NULL) {
+				printk(KERN_WARNING "%s: mgmt response not collected\n",
+				       ndev->name);
+				kfree(frame);
+			}
+                              
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			DEBUG(SHOW_TRACING,
+			      "Wake up Mgmt Queue\n");
+#endif
+			wake_up(&priv->mgmt_wqueue);
+		}
+
+	}
+
+	return 0;
+}
+
+/*
+ * Cleanup the transmit queue by freeing all frames handled by the device.
+ */
+void
+islpci_mgt_cleanup_transmit(struct net_device *ndev)
+{
+	islpci_private *priv = ndev->priv;
+	isl38xx_control_block *cb =    /* volatile not needed */
+		(isl38xx_control_block *) priv->control_block;
+	u32 curr_frag;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+        DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_cleanup_transmit\n");
+#endif
+
+	/* Only once per cleanup, determine fragment range to
+	 * process.  This avoids an endless loop (i.e. lockup) if
+	 * the device became confused, incrementing device_curr_frag
+	 * rapidly. */
+	curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_TX_MGMTQ]); 
+	barrier();
+
+	for ( ; priv->index_mgmt_tx < curr_frag; priv->index_mgmt_tx++) {
+		int index = priv->index_mgmt_tx % ISL38XX_CB_MGMT_QSIZE;
+		struct islpci_membuf *buf = &priv->mgmt_tx[index];
+		pci_unmap_single(priv->pdev, buf->pci_addr, buf->size,
+				 PCI_DMA_TODEVICE);
+		buf->pci_addr = 0;
+		kfree(buf->mem);
+		buf->mem = NULL;
+		buf->size = 0;
+	}
+}
+
+/*
+ * Perform one request-response transaction to the device.
+ */
+int
+islpci_mgt_transaction(struct net_device *ndev,
+		       int operation, unsigned long oid,
+		       void *senddata, int sendlen,
+		       struct islpci_mgmtframe **recvframe)
+{
+	islpci_private *priv = ndev->priv;
+	const long wait_cycle_jiffies = (ISL38XX_WAIT_CYCLE * 10 * HZ) / 1000;
+	long timeout_left = ISL38XX_MAX_WAIT_CYCLES * wait_cycle_jiffies;
+	int err;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+	DEFINE_WAIT(wait);
+#else
+	DECLARE_WAITQUEUE(wait, current);
+#endif
+
+	if (down_interruptible(&priv->mgmt_sem))
+		return -ERESTARTSYS;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+	prepare_to_wait(&priv->mgmt_wqueue, &wait, TASK_UNINTERRUPTIBLE);
+#else
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	add_wait_queue(&priv->mgmt_wqueue, &wait);
+#endif
+	err = islpci_mgt_transmit(ndev, operation, oid, senddata, sendlen);
+	if(err)
+		goto out;
+
+	err = -ETIMEDOUT;
+	while (timeout_left > 0) {
+		int timeleft;
+		struct islpci_mgmtframe *frame;
+
+		timeleft = schedule_timeout(wait_cycle_jiffies);
+		frame = xchg(&priv->mgmt_received, NULL);
+		if (frame) {
+			*recvframe = frame;
+			err = 0;
+			goto out;
+		}
+		if(timeleft == 0) {
+			printk(KERN_DEBUG "%s: timeout waiting for mgmt response %lu, trigging device\n",
+			       ndev->name, timeout_left);
+			islpci_trigger(priv);
+		}
+		timeout_left += timeleft - wait_cycle_jiffies;
+	}
+	printk(KERN_WARNING "%s: timeout waiting for mgmt response\n",
+	       ndev->name);
+
+	/* TODO: we should reset the device here */     
+ out:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+	finish_wait(&priv->mgmt_wqueue, &wait);
+#else
+	remove_wait_queue(&priv->mgmt_wqueue, &wait);
+	set_current_state(TASK_RUNNING);
+#endif
+	up(&priv->mgmt_sem);
+	return err;
+}
+
--- diff/drivers/net/wireless/prism54/islpci_mgt.h	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/net/wireless/prism54/islpci_mgt.h	2004-03-16 09:37:58.392663136 +0000
@@ -0,0 +1,166 @@
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_mgt.h,v 1.22 2004/01/30 16:24:00 ajfa Exp $
+ *  
+ *  Copyright (C) 2002 Intersil Americas Inc.
+ *  Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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 _ISLPCI_MGT_H
+#define _ISLPCI_MGT_H
+
+#include <linux/wireless.h>
+#include <linux/skbuff.h>
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41)
+# include <linux/workqueue.h>
+#else
+# include <linux/tqueue.h>
+# define work_struct tq_struct
+# define INIT_WORK INIT_TQUEUE
+# define schedule_work schedule_task
+#endif
+
+/*
+ *  Function definitions
+ */
+
+#define K_DEBUG(f, m, args...) do { if(f & m) printk(KERN_DEBUG args); } while(0)
+#define DEBUG(f, args...) K_DEBUG(f, pc_debug, args)
+
+#define TRACE(devname)   K_DEBUG(SHOW_TRACING, VERBOSE, "%s:  -> " __FUNCTION__ "()\n", devname)
+
+extern int pc_debug;
+static const int init_wds = 0;	/* help compiler optimize away dead code */
+
+
+/* General driver definitions */
+#define PCIVENDOR_INTERSIL                      0x1260UL
+#define PCIVENDOR_3COM				0x10b7UL
+#define PCIVENDOR_DLINK				0x1186UL
+#define PCIVENDOR_I4				0x17cfUL
+#define PCIVENDOR_IODATA			0x10fcUL
+#define PCIVENDOR_NETGEAR			0x1385UL
+#define PCIVENDOR_SMC				0x10b8UL
+#define PCIVENDOR_ACCTON			0x1113UL
+
+#define PCIDEVICE_ISL3877                       0x3877UL
+#define PCIDEVICE_ISL3890                       0x3890UL
+#define	PCIDEVICE_3COM6001			0x6001UL
+#define PCIDEVICE_LATENCY_TIMER_MIN 		0x40
+#define PCIDEVICE_LATENCY_TIMER_VAL 		0x50
+
+/* Debugging verbose definitions */
+#define SHOW_NOTHING                            0x00	/* overrules everything */
+#define SHOW_ANYTHING                           0xFF
+#define SHOW_ERROR_MESSAGES                     0x01
+#define SHOW_TRAPS                              0x02
+#define SHOW_FUNCTION_CALLS                     0x04
+#define SHOW_TRACING                            0x08
+#define SHOW_QUEUE_INDEXES                      0x10
+#define SHOW_PIMFOR_FRAMES                      0x20
+#define SHOW_BUFFER_CONTENTS                    0x40
+#define VERBOSE                                 0x01
+
+/* Default card definitions */
+#define CARD_DEFAULT_CHANNEL                    6
+#define CARD_DEFAULT_MODE                       INL_MODE_CLIENT
+#define CARD_DEFAULT_IW_MODE			IW_MODE_INFRA
+#define CARD_DEFAULT_BSSTYPE                    DOT11_BSSTYPE_INFRA
+#define CARD_DEFAULT_CLIENT_SSID		""
+#define CARD_DEFAULT_AP_SSID			"default"
+#define CARD_DEFAULT_KEY1                       "default_key_1"
+#define CARD_DEFAULT_KEY2                       "default_key_2"
+#define CARD_DEFAULT_KEY3                       "default_key_3"
+#define CARD_DEFAULT_KEY4                       "default_key_4"
+#define CARD_DEFAULT_WEP                        0
+#define CARD_DEFAULT_FILTER                     0
+# define CARD_DEFAULT_WDS                        0
+#define	CARD_DEFAULT_AUTHEN                     DOT11_AUTH_OS
+#define	CARD_DEFAULT_DOT1X			0
+#define CARD_DEFAULT_MLME_MODE			DOT11_MLME_AUTO
+#define CARD_DEFAULT_CONFORMANCE                OID_INL_CONFORMANCE_NONE
+
+/* PIMFOR package definitions */
+#define PIMFOR_ETHERTYPE                        0x8828
+#define PIMFOR_HEADER_SIZE                      12
+#define PIMFOR_VERSION                          1
+#define PIMFOR_OP_GET                           0
+#define PIMFOR_OP_SET                           1
+#define PIMFOR_OP_RESPONSE                      2
+#define PIMFOR_OP_ERROR                         3
+#define PIMFOR_OP_TRAP                          4
+#define PIMFOR_OP_RESERVED                      5	/* till 255 */
+#define PIMFOR_DEV_ID_MHLI_MIB                  0
+#define PIMFOR_FLAG_APPLIC_ORIGIN               0x01
+#define PIMFOR_FLAG_LITTLE_ENDIAN               0x02
+
+static inline void
+add_le32p(u32 * le_number, u32 add)
+{
+	*le_number = cpu_to_le32(le32_to_cpup(le_number) + add);
+}
+
+void display_buffer(char *, int);
+
+/*
+ *  Type definition section
+ *
+ *  the structure defines only the header allowing copyless
+ *  frame handling
+ */
+typedef struct {
+	u8 version;
+	u8 operation;
+	u32 oid;
+	u8 device_id;
+	u8 flags;
+	u32 length;
+} __attribute__ ((packed))
+pimfor_header_t;
+
+/* A received and interrupt-processed management frame, either for
+ * schedule_work(prism54_process_trap) or for priv->mgmt_received,
+ * processed by islpci_mgt_transaction(). */
+struct islpci_mgmtframe {
+	struct net_device *ndev;      /* pointer to network device */
+	pimfor_header_t *header;      /* payload header, points into buf */
+	void *data;		      /* payload ex header, points into buf */
+        struct work_struct ws;	      /* argument for schedule_work() */
+	char buf[0];		      /* fragment buffer */
+};
+
+int
+islpci_mgt_receive(struct net_device *ndev);
+
+int
+islpci_mgmt_rx_fill(struct net_device *ndev);
+
+void
+islpci_mgt_cleanup_transmit(struct net_device *ndev);
+
+int
+islpci_mgt_transaction(struct net_device *ndev,
+                       int operation, unsigned long oid,
+		       void *senddata, int sendlen,
+		       struct islpci_mgmtframe **recvframe);
+
+static inline void
+islpci_mgt_release(struct islpci_mgmtframe *frame)
+{
+        kfree(frame);
+}
+
+#endif				/* _ISLPCI_MGT_H */
--- diff/drivers/net/wireless/prism54/oid_mgt.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/net/wireless/prism54/oid_mgt.c	2004-03-16 09:37:58.394662832 +0000
@@ -0,0 +1,532 @@
+/*   
+ *  Copyright (C) 2003 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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 "islpci_dev.h"
+#include "islpci_mgt.h"
+#include "isl_oid.h"
+#include "oid_mgt.h"
+#include "isl_ioctl.h"
+
+/* to convert between channel and freq */
+const int frequency_list_bg[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+	2447, 2452, 2457, 2462, 2467, 2472, 2484
+};
+
+const int frequency_list_a[] = { 5170, 5180, 5190, 5200, 5210, 5220, 5230,
+	5240, 5260, 5280, 5300, 5320
+};
+
+#define OID_U32(x) {x, 0, sizeof(u32), OID_FLAG_U32}
+#define OID_U32_C(x) {x, 0, sizeof(u32), OID_FLAG_U32 | OID_FLAG_CACHED}
+#define OID_STRUCT(x,s) {x, 0, sizeof(s), 0}
+#define OID_STRUCT_C(x,s) {x, 0, sizeof(s), OID_FLAG_CACHED}
+#define OID_STRUCT_MLME(x){x, 0, sizeof(struct obj_mlme), 0}
+#define OID_STRUCT_MLMEEX(x){x, 0, sizeof(struct obj_mlmeex), OID_FLAG_MLMEEX}
+
+#define OID_UNKNOWN(x) {x, 0, 0, 0}
+
+struct oid_t isl_oid[] = {
+	[GEN_OID_MACADDRESS] = OID_STRUCT(0x00000000, u8[6]),
+	[GEN_OID_LINKSTATE] = OID_U32(0x00000001),
+	[GEN_OID_WATCHDOG] = OID_UNKNOWN(0x00000002),
+	[GEN_OID_MIBOP] = OID_UNKNOWN(0x00000003),
+	[GEN_OID_OPTIONS] = OID_UNKNOWN(0x00000004),
+	[GEN_OID_LEDCONFIG] = OID_UNKNOWN(0x00000005),
+
+	/* 802.11 */
+	[DOT11_OID_BSSTYPE] = OID_U32_C(0x10000000),
+	[DOT11_OID_BSSID] = OID_STRUCT_C(0x10000001, u8[6]),
+	[DOT11_OID_SSID] = OID_STRUCT_C(0x10000002, struct obj_ssid),
+	[DOT11_OID_STATE] = OID_U32(0x10000003),
+	[DOT11_OID_AID] = OID_U32(0x10000004),
+	[DOT11_OID_COUNTRYSTRING] = OID_STRUCT(0x10000005, u8[4]),
+	[DOT11_OID_SSIDOVERRIDE] = OID_STRUCT_C(0x10000006, struct obj_ssid),
+
+	[DOT11_OID_MEDIUMLIMIT] = OID_U32(0x11000000),
+	[DOT11_OID_BEACONPERIOD] = OID_U32_C(0x11000001),
+	[DOT11_OID_DTIMPERIOD] = OID_U32(0x11000002),
+	[DOT11_OID_ATIMWINDOW] = OID_U32(0x11000003),
+	[DOT11_OID_LISTENINTERVAL] = OID_U32(0x11000004),
+	[DOT11_OID_CFPPERIOD] = OID_U32(0x11000005),
+	[DOT11_OID_CFPDURATION] = OID_U32(0x11000006),
+
+	[DOT11_OID_AUTHENABLE] = OID_U32_C(0x12000000),
+	[DOT11_OID_PRIVACYINVOKED] = OID_U32_C(0x12000001),
+	[DOT11_OID_EXUNENCRYPTED] = OID_U32_C(0x12000002),
+	[DOT11_OID_DEFKEYID] = OID_U32_C(0x12000003),
+	[DOT11_OID_DEFKEYX] = {0x12000004, 3, sizeof (struct obj_key), OID_FLAG_CACHED},	/* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */
+	[DOT11_OID_STAKEY] = OID_UNKNOWN(0x12000008),
+	[DOT11_OID_REKEYTHRESHOLD] = OID_U32(0x12000009),
+	[DOT11_OID_STASC] = OID_UNKNOWN(0x1200000a),
+
+	[DOT11_OID_PRIVTXREJECTED] = OID_U32(0x1a000000),
+	[DOT11_OID_PRIVRXPLAIN] = OID_U32(0x1a000001),
+	[DOT11_OID_PRIVRXFAILED] = OID_U32(0x1a000002),
+	[DOT11_OID_PRIVRXNOKEY] = OID_U32(0x1a000003),
+
+	[DOT11_OID_RTSTHRESH] = OID_U32_C(0x13000000),
+	[DOT11_OID_FRAGTHRESH] = OID_U32_C(0x13000001),
+	[DOT11_OID_SHORTRETRIES] = OID_U32_C(0x13000002),
+	[DOT11_OID_LONGRETRIES] = OID_U32_C(0x13000003),
+	[DOT11_OID_MAXTXLIFETIME] = OID_U32_C(0x13000004),
+	[DOT11_OID_MAXRXLIFETIME] = OID_U32(0x13000005),
+	[DOT11_OID_AUTHRESPTIMEOUT] = OID_U32(0x13000006),
+	[DOT11_OID_ASSOCRESPTIMEOUT] = OID_U32(0x13000007),
+
+	[DOT11_OID_ALOFT_TABLE] = OID_UNKNOWN(0x1d000000),
+	[DOT11_OID_ALOFT_CTRL_TABLE] = OID_UNKNOWN(0x1d000001),
+	[DOT11_OID_ALOFT_RETREAT] = OID_UNKNOWN(0x1d000002),
+	[DOT11_OID_ALOFT_PROGRESS] = OID_UNKNOWN(0x1d000003),
+	[DOT11_OID_ALOFT_FIXEDRATE] = OID_U32(0x1d000004),
+	[DOT11_OID_ALOFT_RSSIGRAPH] = OID_UNKNOWN(0x1d000005),
+	[DOT11_OID_ALOFT_CONFIG] = OID_UNKNOWN(0x1d000006),
+
+	[DOT11_OID_VDCFX] = {0x1b000000, 7, 0, 0},
+	[DOT11_OID_MAXFRAMEBURST] = OID_U32(0x1b000008),
+
+	[DOT11_OID_PSM] = OID_U32(0x14000000),
+	[DOT11_OID_CAMTIMEOUT] = OID_U32(0x14000001),
+	[DOT11_OID_RECEIVEDTIMS] = OID_U32(0x14000002),
+	[DOT11_OID_ROAMPREFERENCE] = OID_U32(0x14000003),
+
+	[DOT11_OID_BRIDGELOCAL] = OID_U32(0x15000000),
+	[DOT11_OID_CLIENTS] = OID_U32(0x15000001),
+	[DOT11_OID_CLIENTSASSOCIATED] = OID_U32(0x15000002),
+	[DOT11_OID_CLIENTX] = {0x15000003, 2006, 0, 0},	/* DOT11_OID_CLIENTX,...DOT11_OID_CLIENT2007 */
+
+	[DOT11_OID_CLIENTFIND] = OID_STRUCT(0x150007DB, u8[6]),
+	[DOT11_OID_WDSLINKADD] = OID_STRUCT(0x150007DC, u8[6]),
+	[DOT11_OID_WDSLINKREMOVE] = OID_STRUCT(0x150007DD, u8[6]),
+	[DOT11_OID_EAPAUTHSTA] = OID_STRUCT(0x150007DE, u8[6]),
+	[DOT11_OID_EAPUNAUTHSTA] = OID_STRUCT(0x150007DF, u8[6]),
+	[DOT11_OID_DOT1XENABLE] = OID_U32_C(0x150007E0),
+	[DOT11_OID_MICFAILURE] = OID_UNKNOWN(0x150007E1),
+	[DOT11_OID_REKEYINDICATE] = OID_UNKNOWN(0x150007E2),
+
+	[DOT11_OID_MPDUTXSUCCESSFUL] = OID_U32(0x16000000),
+	[DOT11_OID_MPDUTXONERETRY] = OID_U32(0x16000001),
+	[DOT11_OID_MPDUTXMULTIPLERETRIES] = OID_U32(0x16000002),
+	[DOT11_OID_MPDUTXFAILED] = OID_U32(0x16000003),
+	[DOT11_OID_MPDURXSUCCESSFUL] = OID_U32(0x16000004),
+	[DOT11_OID_MPDURXDUPS] = OID_U32(0x16000005),
+	[DOT11_OID_RTSSUCCESSFUL] = OID_U32(0x16000006),
+	[DOT11_OID_RTSFAILED] = OID_U32(0x16000007),
+	[DOT11_OID_ACKFAILED] = OID_U32(0x16000008),
+	[DOT11_OID_FRAMERECEIVES] = OID_U32(0x16000009),
+	[DOT11_OID_FRAMEERRORS] = OID_U32(0x1600000A),
+	[DOT11_OID_FRAMEABORTS] = OID_U32(0x1600000B),
+	[DOT11_OID_FRAMEABORTSPHY] = OID_U32(0x1600000C),
+
+	[DOT11_OID_SLOTTIME] = OID_U32(0x17000000),
+	[DOT11_OID_CWMIN] = OID_U32(0x17000001),
+	[DOT11_OID_CWMAX] = OID_U32(0x17000002),
+	[DOT11_OID_ACKWINDOW] = OID_U32(0x17000003),
+	[DOT11_OID_ANTENNARX] = OID_U32(0x17000004),
+	[DOT11_OID_ANTENNATX] = OID_U32(0x17000005),
+	[DOT11_OID_ANTENNADIVERSITY] = OID_U32(0x17000006),
+	[DOT11_OID_CHANNEL] = OID_U32_C(0x17000007),
+	[DOT11_OID_EDTHRESHOLD] = OID_U32_C(0x17000008),
+	[DOT11_OID_PREAMBLESETTINGS] = OID_U32(0x17000009),
+	[DOT11_OID_RATES] = OID_STRUCT(0x1700000A, u8[IWMAX_BITRATES + 1]),
+	[DOT11_OID_CCAMODESUPPORTED] = OID_U32(0x1700000B),
+	[DOT11_OID_CCAMODE] = OID_U32(0x1700000C),
+	[DOT11_OID_RSSIVECTOR] = OID_U32(0x1700000D),
+	[DOT11_OID_OUTPUTPOWERTABLE] = OID_U32(0x1700000E),
+	[DOT11_OID_OUTPUTPOWER] = OID_U32_C(0x1700000F),
+	[DOT11_OID_SUPPORTEDRATES] =
+	    OID_STRUCT(0x17000010, u8[IWMAX_BITRATES + 1]),
+	[DOT11_OID_FREQUENCY] = OID_U32_C(0x17000011),
+	[DOT11_OID_SUPPORTEDFREQUENCIES] = {0x17000012, 0, sizeof (struct
+								   obj_frequencies)
+					    + sizeof (u16) * IWMAX_FREQ, 0},
+
+	[DOT11_OID_NOISEFLOOR] = OID_U32(0x17000013),
+	[DOT11_OID_FREQUENCYACTIVITY] =
+	    OID_STRUCT(0x17000014, u8[IWMAX_FREQ + 1]),
+	[DOT11_OID_IQCALIBRATIONTABLE] = OID_UNKNOWN(0x17000015),
+	[DOT11_OID_NONERPPROTECTION] = OID_U32(0x17000016),
+	[DOT11_OID_SLOTSETTINGS] = OID_U32(0x17000017),
+	[DOT11_OID_NONERPTIMEOUT] = OID_U32(0x17000018),
+	[DOT11_OID_PROFILES] = OID_U32(0x17000019),
+	[DOT11_OID_EXTENDEDRATES] =
+	    OID_STRUCT(0x17000020, u8[IWMAX_BITRATES + 1]),
+
+	[DOT11_OID_DEAUTHENTICATE] = OID_STRUCT_MLME(0x18000000),
+	[DOT11_OID_AUTHENTICATE] = OID_STRUCT_MLME(0x18000001),
+	[DOT11_OID_DISASSOCIATE] = OID_STRUCT_MLME(0x18000002),
+	[DOT11_OID_ASSOCIATE] = OID_STRUCT_MLME(0x18000003),
+	[DOT11_OID_SCAN] = OID_UNKNOWN(0x18000004),
+	[DOT11_OID_BEACON] = OID_STRUCT_MLMEEX(0x18000005),
+	[DOT11_OID_PROBE] = OID_STRUCT_MLMEEX(0x18000006),
+	[DOT11_OID_DEAUTHENTICATEEX] = OID_STRUCT_MLMEEX(0x18000007),
+	[DOT11_OID_AUTHENTICATEEX] = OID_STRUCT_MLMEEX(0x18000008),
+	[DOT11_OID_DISASSOCIATEEX] = OID_STRUCT_MLMEEX(0x18000009),
+	[DOT11_OID_ASSOCIATEEX] = OID_STRUCT_MLMEEX(0x1800000A),
+	[DOT11_OID_REASSOCIATE] = OID_STRUCT_MLMEEX(0x1800000B),
+	[DOT11_OID_REASSOCIATEEX] = OID_STRUCT_MLMEEX(0x1800000C),
+
+	[DOT11_OID_NONERPSTATUS] = OID_U32(0x1E000000),
+
+	[DOT11_OID_STATIMEOUT] = OID_U32(0x19000000),
+	[DOT11_OID_MLMEAUTOLEVEL] = OID_U32_C(0x19000001),
+	[DOT11_OID_BSSTIMEOUT] = OID_U32(0x19000002),
+	[DOT11_OID_ATTACHMENT] = OID_UNKNOWN(0x19000003),
+	[DOT11_OID_PSMBUFFER] = OID_STRUCT_C(0x19000004, struct obj_buffer),
+
+	[DOT11_OID_BSSS] = OID_U32(0x1C000000),
+	[DOT11_OID_BSSX] = {0x1C000001, 63, sizeof (struct obj_bss), 0},	/*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */
+	[DOT11_OID_BSSFIND] = OID_STRUCT(0x1C000042, struct obj_bss),
+	[DOT11_OID_BSSLIST] = {0x1C000043, 0, sizeof (struct
+						      obj_bsslist) +
+			       sizeof (struct obj_bss[IWMAX_BSS]), 0},
+
+	[OID_INL_TUNNEL] = OID_UNKNOWN(0xFF020000),
+	[OID_INL_MEMADDR] = OID_UNKNOWN(0xFF020001),
+	[OID_INL_MEMORY] = OID_UNKNOWN(0xFF020002),
+	[OID_INL_MODE] = OID_U32_C(0xFF020003),
+	[OID_INL_COMPONENT_NR] = OID_UNKNOWN(0xFF020004),
+	[OID_INL_VERSION] = OID_UNKNOWN(0xFF020005),
+	[OID_INL_INTERFACE_ID] = OID_UNKNOWN(0xFF020006),
+	[OID_INL_COMPONENT_ID] = OID_UNKNOWN(0xFF020007),
+	[OID_INL_CONFIG] = OID_U32_C(0xFF020008),
+	[OID_INL_DOT11D_CONFORMANCE] = OID_U32_C(0xFF02000C),
+	[OID_INL_PHYCAPABILITIES] = OID_U32(0xFF02000D),
+	[OID_INL_OUTPUTPOWER] = OID_U32_C(0xFF02000F),
+
+};
+
+int
+mgt_init(islpci_private *priv)
+{
+	int i;
+
+	priv->mib = kmalloc(OID_NUM_LAST * sizeof (void *), GFP_KERNEL);
+	if (!priv->mib)
+		return -ENOMEM;
+
+	memset(priv->mib, 0, OID_NUM_LAST * sizeof (void *));
+
+	/* Alloc the cache */
+	for (i = 0; i < OID_NUM_LAST; i++) {
+		if (isl_oid[i].flags & OID_FLAG_CACHED) {
+			priv->mib[i] = kmalloc(isl_oid[i].size *
+					       (isl_oid[i].range + 1),
+					       GFP_KERNEL);
+			if (!priv->mib[i])
+				return -ENOMEM;
+			memset(priv->mib[i], 0,
+			       isl_oid[i].size * (isl_oid[i].range + 1));
+		} else
+			priv->mib[i] = NULL;
+	}
+
+	init_rwsem(&priv->mib_sem);
+	prism54_mib_init(priv);
+
+	return 0;
+}
+
+void
+mgt_clean(islpci_private *priv)
+{
+	int i;
+
+	if (!priv->mib)
+		return;
+	for (i = 0; i < OID_NUM_LAST; i++)
+		if (priv->mib[i]) {
+			kfree(priv->mib[i]);
+			priv->mib[i] = NULL;
+		}
+	kfree(priv->mib);
+	priv->mib = NULL;
+}
+
+int
+mgt_set_request(islpci_private *priv, enum oid_num_t n, int extra, void *data)
+{
+	int ret = 0;
+	struct islpci_mgmtframe *response;
+	int response_op = PIMFOR_OP_ERROR;
+	int dlen;
+	void *cache, *_data = data;
+	u32 oid, u;
+
+	BUG_ON(OID_NUM_LAST <= n);
+	BUG_ON(extra > isl_oid[n].range);
+
+	if (!priv->mib)
+		/* memory has been freed */
+		return -1;
+
+	dlen = isl_oid[n].size;
+	cache = priv->mib[n];
+	cache += (cache ? extra * dlen : 0);
+	oid = isl_oid[n].oid + extra;
+
+	if (data == NULL)
+		/* we are requested to re-set a cached value */
+		_data = cache;
+	if ((isl_oid[n].flags & OID_FLAG_U32) && data) {
+		u = cpu_to_le32(*(u32 *) data);
+		_data = &u;
+	}
+	/* If we are going to write to the cache, we don't want anyone to read
+	 * it -> acquire write lock.
+	 * Else we could acquire a read lock to be sure we don't bother the
+	 * commit process (which takes a write lock). But I'm not sure if it's
+	 * needed.
+	 */
+	if (cache)
+		down_write(&priv->mib_sem);
+
+	if (islpci_get_state(priv) >= PRV_STATE_INIT) {
+		ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid,
+					     _data, dlen, &response);
+		if (!ret) {
+			response_op = response->header->operation;
+			islpci_mgt_release(response);
+		}
+		if (ret || response_op == PIMFOR_OP_ERROR)
+		        ret = -EIO;
+	} else if (!cache)
+		ret = -EIO;
+
+	if (cache) {
+		if (!ret && data)
+			memcpy(cache, _data, dlen);
+		up_write(&priv->mib_sem);
+	}
+
+	return ret;
+}
+
+int
+mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data,
+		union oid_res_t *res)
+{
+
+	int ret = -EIO;
+	int reslen = 0;
+	struct islpci_mgmtframe *response = NULL;
+	
+	int dlen;
+	void *cache, *_res=NULL;
+	u32 oid;
+
+	BUG_ON(OID_NUM_LAST <= n);
+	BUG_ON(extra > isl_oid[n].range);
+
+	if (!priv->mib)
+		/* memory has been freed */
+		return -1;
+
+	dlen = isl_oid[n].size;
+	cache = priv->mib[n];
+	cache += cache ? extra * dlen : 0;
+	oid = isl_oid[n].oid + extra;
+	reslen = dlen;
+
+	if (cache)
+		down_read(&priv->mib_sem);
+
+	if (islpci_get_state(priv) >= PRV_STATE_INIT) {
+		ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
+					     oid, data, dlen, &response);
+		if (ret || !response ||
+			response->header->operation == PIMFOR_OP_ERROR) {
+			if (response)
+				islpci_mgt_release(response);
+			ret = -EIO;
+		}
+		if (!ret) {
+			_res = response->data;
+			reslen = response->header->length;
+		}
+	} else if (cache) {
+		_res = cache;
+		ret = 0;
+	}
+	if (isl_oid[n].flags & OID_FLAG_U32) {
+		if (ret)
+			res->u = 0;
+		else
+			res->u = le32_to_cpu(*(u32 *) _res);
+	} else {
+		res->ptr = kmalloc(reslen, GFP_KERNEL);
+		BUG_ON(res->ptr == NULL);
+		if (ret)
+			memset(res->ptr, 0, reslen);
+		else
+			memcpy(res->ptr, _res, reslen);
+	}
+
+	if (cache)
+		up_read(&priv->mib_sem);
+
+	if (response && !ret)
+		islpci_mgt_release(response);
+
+	if (reslen > isl_oid[n].size)
+		printk(KERN_DEBUG
+		       "mgt_get_request(0x%x): received data length was bigger "
+		       "than expected (%d > %d). Memory is probably corrupted... ",
+		       oid, reslen, isl_oid[n].size);
+	
+	return ret;
+}
+
+/* lock outside */
+int
+mgt_commit_list(islpci_private *priv, enum oid_num_t *l, int n)
+{
+	int i, ret = 0;
+	struct islpci_mgmtframe *response;
+
+	for (i = 0; i < n; i++) {
+		struct oid_t *t = &(isl_oid[l[i]]);
+		void *data = priv->mib[l[i]];
+		int j = 0;
+		u32 oid = t->oid;
+		BUG_ON(data == NULL);
+		while (j <= t->range){
+			response = NULL;
+			ret |= islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
+			                              oid, data, t->size,
+						      &response);
+			if (response) {
+				ret |= (response->header->operation ==
+				        PIMFOR_OP_ERROR);
+				islpci_mgt_release(response);
+			}
+			j++;
+			oid++;
+			data += t->size;
+		}
+	}
+	return ret;
+}
+
+/* Lock outside */
+
+void
+mgt_set(islpci_private *priv, enum oid_num_t n, void *data)
+{
+	BUG_ON(OID_NUM_LAST <= n);
+	BUG_ON(priv->mib[n] == NULL);
+
+	memcpy(priv->mib[n], data, isl_oid[n].size);
+	if (isl_oid[n].flags & OID_FLAG_U32)
+		*(u32 *) priv->mib[n] = cpu_to_le32(*(u32 *) priv->mib[n]);
+}
+
+/* Commits the cache. If something goes wrong, it restarts the device. Lock
+ * outside
+ */
+
+static enum oid_num_t commit_part1[] = {
+	OID_INL_CONFIG,
+	OID_INL_MODE,
+	DOT11_OID_BSSTYPE,
+	DOT11_OID_CHANNEL,
+	DOT11_OID_MLMEAUTOLEVEL
+};
+
+static enum oid_num_t commit_part2[] = {
+	DOT11_OID_SSID,
+	DOT11_OID_PSMBUFFER,
+	DOT11_OID_AUTHENABLE,
+	DOT11_OID_PRIVACYINVOKED,
+	DOT11_OID_EXUNENCRYPTED,
+	DOT11_OID_DEFKEYX,	/* MULTIPLE */
+	DOT11_OID_DEFKEYID,
+	DOT11_OID_DOT1XENABLE,
+	OID_INL_DOT11D_CONFORMANCE,
+	OID_INL_OUTPUTPOWER,
+};
+
+void
+mgt_commit(islpci_private *priv)
+{
+	int rvalue;
+	u32 u;
+	union oid_res_t r;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT)
+		return;
+
+	rvalue = mgt_commit_list(priv, commit_part1,
+				 sizeof (commit_part1) /
+				 sizeof (commit_part1[0]));
+
+	if (priv->iw_mode != IW_MODE_MONITOR)
+		rvalue |= mgt_commit_list(priv, commit_part2,
+					  sizeof (commit_part2) /
+					  sizeof (commit_part2[0]));
+
+	u = OID_INL_MODE;
+	rvalue |= mgt_commit_list(priv, &u, 1);
+
+	if (rvalue) {
+		/* some request have failed. The device might be in an
+		   incoherent state. We should reset it ! */
+		printk(KERN_DEBUG "%s: mgt_commit has failed. Restart the "
+                "device \n", priv->ndev->name);
+	}
+
+	/* update the MAC addr. As it's not cached, no lock will be acquired by
+	 * the mgt_get_request
+	 */
+	mgt_get_request(priv, GEN_OID_MACADDRESS, 0, NULL, &r);
+	memcpy(priv->ndev->dev_addr, r.ptr, 6);
+	kfree(r.ptr);
+
+}
+
+/* This will tell you if you are allowed to answer a mlme(ex) request .*/
+
+inline int
+mgt_mlme_answer(islpci_private *priv)
+{
+	u32 mlmeautolevel;
+	/* Acquire a read lock because if we are in a mode change, it's
+	 * possible to answer true, while the card is leaving master to managed
+	 * mode. Answering to a mlme in this situation could hang the card.
+	 */
+	down_read(&priv->mib_sem);
+	mlmeautolevel =
+	    le32_to_cpu(*(u32 *) priv->mib[DOT11_OID_MLMEAUTOLEVEL]);
+	up_read(&priv->mib_sem);
+
+	return ((priv->iw_mode == IW_MODE_MASTER) &&
+		(mlmeautolevel >= DOT11_MLME_INTERMEDIATE));
+}
+
+inline enum oid_num_t
+mgt_oidtonum(u32 oid)
+{
+	int i;
+
+	for (i = 0; i < OID_NUM_LAST - 1; i++)
+		if (isl_oid[i].oid == oid)
+			return i;
+
+	printk(KERN_DEBUG "looking for an unknown oid 0x%x", oid);
+
+	return 0;
+}
--- diff/drivers/net/wireless/prism54/oid_mgt.h	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/net/wireless/prism54/oid_mgt.h	2004-03-16 09:37:58.394662832 +0000
@@ -0,0 +1,51 @@
+/*   
+ *  Copyright (C) 2003 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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
+ *
+ */
+
+#if !defined(_OID_MGT_H)
+#define _OID_MGT_H
+
+#include "isl_oid.h"
+#include "islpci_dev.h"
+
+extern struct oid_t isl_oid[];
+
+int mgt_init(islpci_private *);
+
+void mgt_clean(islpci_private *);
+
+extern const int frequency_list_bg[];
+
+extern const int frequency_list_a[];
+
+int mgt_set_request(islpci_private *, enum oid_num_t, int, void *);
+
+int mgt_get_request(islpci_private *, enum oid_num_t, int, void *,
+                    union oid_res_t *);
+
+int mgt_commit_list(islpci_private *, enum oid_num_t *, int);
+
+void mgt_set(islpci_private *, enum oid_num_t, void *);
+
+void mgt_commit(islpci_private *);
+
+int mgt_mlme_answer(islpci_private *);
+
+enum oid_num_t mgt_oidtonum(u32 oid);
+
+#endif				/* !defined(_OID_MGT_H) */
+/* EOF */
--- diff/drivers/parisc/iommu-helpers.h	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/parisc/iommu-helpers.h	2004-03-16 09:37:58.395662680 +0000
@@ -0,0 +1,163 @@
+/**
+ * iommu_fill_pdir - Insert coalesced scatter/gather chunks into the I/O Pdir.
+ * @ioc: The I/O Controller.
+ * @startsg: The scatter/gather list of coalesced chunks.
+ * @nents: The number of entries in the scatter/gather list.
+ * @hint: The DMA Hint.
+ *
+ * This function inserts the coalesced scatter/gather list chunks into the
+ * I/O Controller's I/O Pdir.
+ */ 
+static inline unsigned int
+iommu_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents, 
+		unsigned long hint,
+		void (*iommu_io_pdir_entry)(u64 *, space_t, unsigned long,
+					    unsigned long))
+{
+	struct scatterlist *dma_sg = startsg;	/* pointer to current DMA */
+	unsigned int n_mappings = 0;
+	unsigned long dma_offset = 0, dma_len = 0;
+	u64 *pdirp = NULL;
+
+	/* Horrible hack.  For efficiency's sake, dma_sg starts one 
+	 * entry below the true start (it is immediately incremented
+	 * in the loop) */
+	 dma_sg--;
+
+	while (nents-- > 0) {
+		unsigned long vaddr;
+		long size;
+
+		DBG_RUN_SG(" %d : %08lx/%05x %08lx/%05x\n", nents,
+			   (unsigned long)sg_dma_address(startsg), cnt,
+			   sg_virt_addr(startsg), startsg->length
+		);
+
+
+		/*
+		** Look for the start of a new DMA stream
+		*/
+		
+		if (sg_dma_address(startsg) & PIDE_FLAG) {
+			u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG;
+
+			BUG_ON(pdirp && (dma_len != sg_dma_len(dma_sg)));
+
+			dma_sg++;
+
+			dma_len = sg_dma_len(startsg);
+			sg_dma_len(startsg) = 0;
+			dma_offset = (unsigned long) pide & ~IOVP_MASK;
+			n_mappings++;
+			sg_dma_address(dma_sg) = pide;
+			pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]);
+			prefetchw(pdirp);
+		}
+		
+		BUG_ON(pdirp == NULL);
+		
+		vaddr = sg_virt_addr(startsg);
+		sg_dma_len(dma_sg) += startsg->length;
+		size = startsg->length + dma_offset;
+		dma_offset = 0;
+#ifdef IOMMU_MAP_STATS
+		ioc->msg_pages += startsg->length >> IOVP_SHIFT;
+#endif
+		do {
+			iommu_io_pdir_entry(pdirp, KERNEL_SPACE, 
+					    vaddr, hint);
+			vaddr += IOVP_SIZE;
+			size -= IOVP_SIZE;
+			pdirp++;
+		} while(unlikely(size > 0));
+		startsg++;
+	}
+	return(n_mappings);
+}
+
+
+/*
+** First pass is to walk the SG list and determine where the breaks are
+** in the DMA stream. Allocates PDIR entries but does not fill them.
+** Returns the number of DMA chunks.
+**
+** Doing the fill separate from the coalescing/allocation keeps the
+** code simpler. Future enhancement could make one pass through
+** the sglist do both.
+*/
+
+static inline unsigned int
+iommu_coalesce_chunks(struct ioc *ioc, struct scatterlist *startsg, int nents,
+		      int (*iommu_alloc_range)(struct ioc *, size_t))
+{
+	struct scatterlist *contig_sg;	   /* contig chunk head */
+	unsigned long dma_offset, dma_len; /* start/len of DMA stream */
+	unsigned int n_mappings = 0;
+
+	while (nents > 0) {
+
+		/*
+		** Prepare for first/next DMA stream
+		*/
+		contig_sg = startsg;
+		dma_len = startsg->length;
+		dma_offset = sg_virt_addr(startsg) & ~IOVP_MASK;
+
+		/* PARANOID: clear entries */
+		sg_dma_address(startsg) = 0;
+		sg_dma_len(startsg) = 0;
+
+		/*
+		** This loop terminates one iteration "early" since
+		** it's always looking one "ahead".
+		*/
+		while(--nents > 0) {
+			unsigned long prevstartsg_end, startsg_end;
+
+			prevstartsg_end = sg_virt_addr(startsg) +
+				startsg->length;
+
+			startsg++;
+			startsg_end = sg_virt_addr(startsg) + 
+				startsg->length;
+
+			/* PARANOID: clear entries */
+			sg_dma_address(startsg) = 0;
+			sg_dma_len(startsg) = 0;
+
+			/*
+			** First make sure current dma stream won't
+			** exceed DMA_CHUNK_SIZE if we coalesce the
+			** next entry.
+			*/   
+			if(unlikely(ROUNDUP(dma_len + dma_offset + startsg->length,
+					    IOVP_SIZE) > DMA_CHUNK_SIZE))
+				break;
+
+			/*
+			** Next see if we can append the next chunk (i.e.
+			** it must end on one page and begin on another
+			*/
+			if (unlikely(((prevstartsg_end | sg_virt_addr(startsg)) & ~PAGE_MASK) != 0))
+				break;
+			
+			dma_len += startsg->length;
+		}
+
+		/*
+		** End of DMA Stream
+		** Terminate last VCONTIG block.
+		** Allocate space for DMA stream.
+		*/
+		sg_dma_len(contig_sg) = dma_len;
+		dma_len = ROUNDUP(dma_len + dma_offset, IOVP_SIZE);
+		sg_dma_address(contig_sg) =
+			PIDE_FLAG 
+			| (iommu_alloc_range(ioc, dma_len) << IOVP_SHIFT)
+			| dma_offset;
+		n_mappings++;
+	}
+
+	return n_mappings;
+}
+
--- diff/drivers/pci/hotplug/rpaphp_slot.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/pci/hotplug/rpaphp_slot.c	2004-03-16 09:37:58.396662528 +0000
@@ -0,0 +1,188 @@
+/*
+ * RPA Virtual I/O device functions 
+ * Copyright (C) 2004 Linda Xie <lxie@us.ibm.com>
+ *
+ * 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <lxie@us.ibm.com>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/pci.h>
+#include "rpaphp.h"
+
+/* free up the memory user by a slot */
+
+static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = hotplug_slot? (struct slot *) hotplug_slot->private:NULL;
+
+	if (slot == NULL)
+		return;
+
+	dealloc_slot_struct(slot);
+}
+
+void dealloc_slot_struct(struct slot *slot)
+{
+	kfree(slot->hotplug_slot->info);
+	kfree(slot->hotplug_slot->name);
+	kfree(slot->hotplug_slot);
+	kfree(slot);
+	return;
+}
+
+struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name,
+		  int power_domain)
+{
+	struct slot *slot;
+	
+	dbg("Enter alloc_slot_struct(): dn->full_name=%s drc_index=0x%x drc_name=%s\n",
+		dn->full_name, drc_index, drc_name);
+
+	slot = kmalloc(sizeof (struct slot), GFP_KERNEL);
+	if (!slot)
+		return (NULL);
+	memset(slot, 0, sizeof (struct slot));
+	slot->hotplug_slot = kmalloc(sizeof (struct hotplug_slot), GFP_KERNEL);
+	if (!slot->hotplug_slot) {
+		kfree(slot);
+		return (NULL);
+	}
+	memset(slot->hotplug_slot, 0, sizeof (struct hotplug_slot));
+	slot->hotplug_slot->info = kmalloc(sizeof (struct hotplug_slot_info),
+					   GFP_KERNEL);
+	if (!slot->hotplug_slot->info) {
+		kfree(slot->hotplug_slot);
+		kfree(slot);
+		return (NULL);
+	}
+	memset(slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info));
+	slot->hotplug_slot->name = kmalloc(strlen(drc_name) + 1, GFP_KERNEL);
+	if (!slot->hotplug_slot->name) {
+		kfree(slot->hotplug_slot->info);
+		kfree(slot->hotplug_slot);
+		kfree(slot);
+		return (NULL);
+	}
+	slot->name = slot->hotplug_slot->name;
+	slot->dn = dn;
+	slot->index = drc_index;
+	strcpy(slot->name, drc_name);
+	slot->power_domain = power_domain;
+	slot->magic = SLOT_MAGIC;
+	slot->hotplug_slot->private = slot;
+	slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops;
+	slot->hotplug_slot->release = &rpaphp_release_slot;
+	dbg("Exit alloc_slot_struct(): slot->dn->full_name=%s drc_index=0x%x drc_name=%s\n",
+		slot->dn->full_name, slot->index, slot->name);
+	return (slot);
+}
+
+int register_slot(struct slot *slot)
+{
+	int retval;
+	char *vio_uni_addr = NULL;
+
+	dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n", __FUNCTION__, slot->dn->full_name, slot->index, slot->name, slot->power_domain, slot->type);
+
+	retval = pci_hp_register(slot->hotplug_slot);
+	if (retval) {
+		err("pci_hp_register failed with error %d\n", retval);
+		rpaphp_release_slot(slot->hotplug_slot);
+		return (retval);
+	}
+	switch (slot->dev_type) {
+	case PCI_DEV:
+		/* create symlink between slot->name and it's bus_id */
+
+		dbg("%s: sysfs_create_link: %s --> %s\n", __FUNCTION__,
+		    pci_name(slot->bridge), slot->name);
+
+		retval = sysfs_create_link(slot->hotplug_slot->kobj.parent,
+					   &slot->hotplug_slot->kobj,
+					   pci_name(slot->bridge));
+		if (retval) {
+			err("sysfs_create_link failed with error %d\n", retval);
+			rpaphp_release_slot(slot->hotplug_slot);
+			return (retval);
+		}
+		break;
+	case VIO_DEV:
+		/* create symlink between slot->name and it's uni-address */
+		vio_uni_addr = strchr(slot->dn->full_name, '@');
+		if (!vio_uni_addr)
+			return (1);
+		dbg("%s: sysfs_create_link: %s --> %s\n", __FUNCTION__,
+		    vio_uni_addr, slot->name);
+		retval = sysfs_create_link(slot->hotplug_slot->kobj.parent,
+					   &slot->hotplug_slot->kobj,
+					   vio_uni_addr);
+		if (retval) {
+			err("sysfs_create_link failed with error %d\n", retval);
+			rpaphp_release_slot(slot->hotplug_slot);
+			return (retval);
+		}
+		break;
+	default:
+		return (1);
+	}
+
+	/* add slot to our internal list */
+	dbg("%s adding slot[%s] to rpaphp_slot_list\n",
+	    __FUNCTION__, slot->name);
+
+	list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
+
+	if (vio_uni_addr)
+		info("Slot [%s](vio_uni_addr=%s) registered\n",
+		     slot->name, vio_uni_addr);
+	else
+		info("Slot [%s](bus_id=%s) registered\n",
+		     slot->name, pci_name(slot->bridge));
+	num_slots++;
+	return (0);
+}
+
+int rpaphp_get_power_status(struct slot *slot, u8 * value)
+{
+	int rc;
+
+	rc = rtas_get_power_level(slot->power_domain, (int *) value);
+	if (rc)
+		err("failed to get power-level for slot(%s), rc=0x%x\n",
+		    slot->name, rc);
+
+	return rc;
+}
+
+int rpaphp_set_attention_status(struct slot *slot, u8 status)
+{
+	int rc;
+
+	/* status: LED_OFF or LED_ON */
+	rc = rtas_set_indicator(DR_INDICATOR, slot->index, status);
+	if (rc)
+		err("slot(%s) set attention-status(%d) failed! rc=0x%x\n",
+		    slot->name, status, rc);
+
+	return rc;
+}
--- diff/drivers/pci/hotplug/rpaphp_vio.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/pci/hotplug/rpaphp_vio.c	2004-03-16 09:37:58.398662224 +0000
@@ -0,0 +1,121 @@
+/*
+ * RPA Hot Plug Virtual I/O device functions 
+ * Copyright (C) 2004 Linda Xie <lxie@us.ibm.com>
+ *
+ * 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <lxie@us.ibm.com>
+ *
+ */
+#include <asm/vio.h>
+#include "rpaphp.h"
+
+/*
+ * get_vio_adapter_status - get  the status of a slot
+ * 
+ * status:
+ * 
+ * 1-- adapter is configured
+ * 2-- adapter is not configured
+ * 3-- not valid
+ */
+inline int rpaphp_get_vio_adapter_status(struct slot *slot, int is_init, u8 *value)
+{
+	*value = slot->state;
+	return 0;
+}
+
+int rpaphp_unconfig_vio_adapter(struct slot *slot)
+{
+	int retval = 0;
+
+	dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name);
+	if (!slot->dev.vio_dev) {
+		info("%s: no VIOA in slot[%s]\n", __FUNCTION__, slot->name);
+		retval = -EINVAL;
+		goto exit;
+	}
+	/* remove the device from the vio core */
+	vio_unregister_device(slot->dev.vio_dev);
+	slot->state = NOT_CONFIGURED;
+	info("%s: adapter in slot[%s] unconfigured.\n", __FUNCTION__, slot->name);
+exit:
+	dbg("Exit %s, rc=0x%x\n", __FUNCTION__, retval);
+	return retval;
+}
+
+static int setup_vio_hotplug_slot_info(struct slot *slot)
+{
+	slot->hotplug_slot->info->power_status = 1;
+	rpaphp_get_vio_adapter_status(slot, 1,
+		&slot->hotplug_slot->info->adapter_status); 
+	return 0;
+}
+
+int register_vio_slot(struct device_node *dn)
+{
+	u32 *index;
+	char *name;
+	int rc = 1;
+	struct slot *slot = NULL;
+	
+	index = (u32 *) get_property(dn, "ibm,my-drc-index", NULL);
+	if (!index)
+		goto exit_rc;
+	name = get_property(dn, "ibm,loc-code", NULL);
+	if (!name)
+		goto exit_rc;
+	if (!(slot = alloc_slot_struct(dn, *index, name, 0))) {
+		rc = -ENOMEM;
+		goto exit_rc;
+	}
+	slot->dev_type = VIO_DEV;
+	slot->dev.vio_dev = vio_find_node(dn);
+	if (!slot->dev.vio_dev)
+		slot->dev.vio_dev = vio_register_device(dn);
+	if (slot->dev.vio_dev)
+		slot->state = CONFIGURED;
+	else
+		slot->state = NOT_CONFIGURED;
+	if (setup_vio_hotplug_slot_info(slot))
+		goto exit_rc;
+	info("%s: registered VIO device[name=%s vio_dev=%p]\n",
+		__FUNCTION__, slot->name, slot->dev.vio_dev); 
+	rc = register_slot(slot);
+exit_rc:
+	if (rc && slot)
+		dealloc_slot_struct(slot);
+	return (rc);
+}
+
+int rpaphp_enable_vio_slot(struct slot *slot)
+{
+	int retval = 0;
+
+	if ((slot->dev.vio_dev = vio_register_device(slot->dn))) {
+		info("%s: VIO adapter %s in slot[%s] has been configured\n",
+			__FUNCTION__, slot->dn->name, slot->name);
+		slot->state = CONFIGURED;
+	} else {
+		info("%s: no vio_dev struct for adapter in slot[%s]\n",
+			__FUNCTION__, slot->name);
+		slot->state = NOT_CONFIGURED;
+	}
+	
+	return retval;
+}
--- diff/drivers/scsi/qlogicfas.h	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/scsi/qlogicfas.h	2004-03-16 09:37:58.399662072 +0000
@@ -0,0 +1,124 @@
+/* to be used by qlogicfas and qlogic_cs */
+#ifndef __QLOGICFAS_H
+#define __QLOGICFAS_H
+
+/*----------------------------------------------------------------*/
+/* Configuration */
+
+/* Set the following to 2 to use normal interrupt (active high/totempole-
+   tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
+   drain */
+
+#define QL_INT_ACTIVE_HIGH 2
+
+/* Set the following to max out the speed of the PIO PseudoDMA transfers,
+   again, 0 tends to be slower, but more stable.  */
+
+#define QL_TURBO_PDMA 1
+
+/* This should be 1 to enable parity detection */
+
+#define QL_ENABLE_PARITY 1
+
+/* This will reset all devices when the driver is initialized (during bootup).
+   The other linux drivers don't do this, but the DOS drivers do, and after
+   using DOS or some kind of crash or lockup this will bring things back
+   without requiring a cold boot.  It does take some time to recover from a
+   reset, so it is slower, and I have seen timeouts so that devices weren't
+   recognized when this was set. */
+
+#define QL_RESET_AT_START 0
+
+/* crystal frequency in megahertz (for offset 5 and 9)
+   Please set this for your card.  Most Qlogic cards are 40 Mhz.  The
+   Control Concepts ISA (not VLB) is 24 Mhz */
+
+#define XTALFREQ	40
+
+/**********/
+/* DANGER! modify these at your own risk */
+/* SLOWCABLE can usually be reset to zero if you have a clean setup and
+   proper termination.  The rest are for synchronous transfers and other
+   advanced features if your device can transfer faster than 5Mb/sec.
+   If you are really curious, email me for a quick howto until I have
+   something official */
+/**********/
+
+/*****/
+/* config register 1 (offset 8) options */
+/* This needs to be set to 1 if your cabling is long or noisy */
+#define SLOWCABLE 1
+
+/*****/
+/* offset 0xc */
+/* This will set fast (10Mhz) synchronous timing when set to 1
+   For this to have an effect, FASTCLK must also be 1 */
+#define FASTSCSI 0
+
+/* This when set to 1 will set a faster sync transfer rate */
+#define FASTCLK 0	/*(XTALFREQ>25?1:0)*/
+
+/*****/
+/* offset 6 */
+/* This is the sync transfer divisor, XTALFREQ/X will be the maximum
+   achievable data rate (assuming the rest of the system is capable
+   and set properly) */
+#define SYNCXFRPD 5	/*(XTALFREQ/5)*/
+
+/*****/
+/* offset 7 */
+/* This is the count of how many synchronous transfers can take place
+	i.e. how many reqs can occur before an ack is given.
+	The maximum value for this is 15, the upper bits can modify
+	REQ/ACK assertion and deassertion during synchronous transfers
+	If this is 0, the bus will only transfer asynchronously */
+#define SYNCOFFST 0
+/* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles
+	of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will
+	cause the deassertion to be early by 1/2 clock.  Bits 5&4 control
+	the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */
+
+/*----------------------------------------------------------------*/
+#ifdef PCMCIA
+#undef QL_INT_ACTIVE_HIGH
+#define QL_INT_ACTIVE_HIGH 0
+#endif
+
+struct qlogicfas_priv;
+typedef struct qlogicfas_priv *qlogicfas_priv_t;
+struct qlogicfas_priv {
+	 int		qbase;		/* Port */
+	 int		qinitid;	/* initiator ID */
+	 int		qabort;		/* Flag to cause an abort */
+	 int		qlirq;		/* IRQ being used */
+	 char		qinfo[80];	/* description */
+	 Scsi_Cmnd 	*qlcmd;		/* current command being processed */
+	 struct Scsi_Host	*shost;	/* pointer back to host */
+	 qlogicfas_priv_t	next;	/* next private struct */
+};
+
+extern int qlcfg5;
+extern int qlcfg6;
+extern int qlcfg7;
+extern int qlcfg8;
+extern int qlcfg9;
+extern int qlcfgc;
+
+/* The qlogic card uses two register maps - These macros select which one */
+#define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd ))
+#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd ))
+
+/* following is watchdog timeout in microseconds */
+#define WATCHDOG 5000000
+
+/*----------------------------------------------------------------*/
+/* the following will set the monitor border color (useful to find
+   where something crashed or gets stuck at and as a simple profiler) */
+
+#if 0
+#define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);}
+#else
+#define rtrc(i) {}
+#endif
+#endif	/* __QLOGICFAS_H */
+
--- diff/drivers/scsi/sata_vsc.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/scsi/sata_vsc.c	2004-03-16 09:37:58.400661920 +0000
@@ -0,0 +1,392 @@
+/*
+ *  sata_vsc.c - Vitesse VSC7174 4 port DPA SATA
+ *
+ *  Copyright 2004 SGI
+ *
+ *  Bits from Jeff Garzik, Copyright RedHat, Inc.
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include "scsi.h"
+#include "hosts.h"
+#include <linux/libata.h>
+
+#define DRV_NAME	"sata_vsc"
+#define DRV_VERSION	"0.01"
+
+/* Interrupt register offsets (from chip base address) */
+#define VSC_SATA_INT_STAT_OFFSET	0x00
+#define VSC_SATA_INT_MASK_OFFSET	0x04
+
+/* Taskfile registers offsets */
+#define VSC_SATA_TF_CMD_OFFSET		0x00
+#define VSC_SATA_TF_DATA_OFFSET		0x00
+#define VSC_SATA_TF_ERROR_OFFSET	0x04
+#define VSC_SATA_TF_FEATURE_OFFSET	0x06
+#define VSC_SATA_TF_NSECT_OFFSET	0x08
+#define VSC_SATA_TF_LBAL_OFFSET		0x0c
+#define VSC_SATA_TF_LBAM_OFFSET		0x10
+#define VSC_SATA_TF_LBAH_OFFSET		0x14
+#define VSC_SATA_TF_DEVICE_OFFSET	0x18
+#define VSC_SATA_TF_STATUS_OFFSET	0x1c
+#define VSC_SATA_TF_COMMAND_OFFSET	0x1d
+#define VSC_SATA_TF_ALTSTATUS_OFFSET	0x28
+#define VSC_SATA_TF_CTL_OFFSET		0x29
+
+/* DMA base */
+#define VSC_SATA_DMA_CMD_OFFSET		0x70
+
+/* SCRs base */
+#define VSC_SATA_SCR_STATUS_OFFSET	0x100
+#define VSC_SATA_SCR_ERROR_OFFSET	0x104
+#define VSC_SATA_SCR_CONTROL_OFFSET	0x108
+
+/* Port stride */
+#define VSC_SATA_PORT_OFFSET		0x200
+
+
+static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	if (sc_reg > SCR_CONTROL)
+		return 0xffffffffU;
+	return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+
+static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
+			       u32 val)
+{
+	if (sc_reg > SCR_CONTROL)
+		return;
+	writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+
+static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl)
+{
+	unsigned long mask_addr;
+	u8 mask;
+
+	mask_addr = (unsigned long) ap->host_set->mmio_base +
+		VSC_SATA_INT_MASK_OFFSET + ap->port_no;
+	mask = readb(mask_addr);
+	if (ctl & ATA_NIEN)
+		mask |= 0x80;
+	else
+		mask &= 0x7F;
+	writeb(mask, mask_addr);
+}
+
+
+static void vsc_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+	/*
+	 * The only thing the ctl register is used for is SRST.
+	 * That is not enabled or disabled via tf_load.
+	 * However, if ATA_NIEN is changed, then we need to change the interrupt register.
+	 */
+	if ((tf->ctl & ATA_NIEN) != (ap->last_ctl & ATA_NIEN)) {
+		ap->last_ctl = tf->ctl;
+		vsc_intr_mask_update(ap, tf->ctl & ATA_NIEN);
+	}
+	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+		writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr);
+		writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr);
+		writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr);
+		writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr);
+		writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr);
+	} else if (is_addr) {
+		writew(tf->feature, ioaddr->feature_addr);
+		writew(tf->nsect, ioaddr->nsect_addr);
+		writew(tf->lbal, ioaddr->lbal_addr);
+		writew(tf->lbam, ioaddr->lbam_addr);
+		writew(tf->lbah, ioaddr->lbah_addr);
+	}
+
+	if (tf->flags & ATA_TFLAG_DEVICE)
+		writeb(tf->device, ioaddr->device_addr);
+
+	ata_wait_idle(ap);
+}
+
+
+static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	u16 nsect, lbal, lbam, lbah;
+
+	nsect = tf->nsect = readw(ioaddr->nsect_addr);
+	lbal = tf->lbal = readw(ioaddr->lbal_addr);
+	lbam = tf->lbam = readw(ioaddr->lbam_addr);
+	lbah = tf->lbah = readw(ioaddr->lbah_addr);
+	tf->device = readw(ioaddr->device_addr);
+
+	if (tf->flags & ATA_TFLAG_LBA48) {
+		tf->hob_feature = readb(ioaddr->error_addr);
+		tf->hob_nsect = nsect >> 8;
+		tf->hob_lbal = lbal >> 8;
+		tf->hob_lbam = lbam >> 8;
+		tf->hob_lbah = lbah >> 8;
+        }
+}
+
+
+/*
+ * vsc_sata_interrupt
+ *
+ * Read the interrupt register and process for the devices that have them pending.
+ */
+irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct ata_host_set *host_set = dev_instance;
+	unsigned int i;
+	unsigned int handled = 0;
+	u32 int_status;
+
+	spin_lock(&host_set->lock);
+
+	int_status = readl(host_set->mmio_base + VSC_SATA_INT_STAT_OFFSET);
+
+	for (i = 0; i < host_set->n_ports; i++) {
+		if (int_status & ((u32) 0xFF << (8 * i))) {
+			struct ata_port *ap;
+
+			ap = host_set->ports[i];
+			if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+				struct ata_queued_cmd *qc;
+
+				qc = ata_qc_from_tag(ap, ap->active_tag);
+				if (qc && ((qc->flags & ATA_QCFLAG_POLL) == 0))
+					handled += ata_host_intr(ap, qc);
+			}
+		}
+	}
+
+	spin_unlock(&host_set->lock);
+
+	return IRQ_RETVAL(handled);
+}
+
+
+static Scsi_Host_Template vsc_sata_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ATA_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.bios_param		= ata_std_bios_param,
+};
+
+
+static struct ata_port_operations vsc_sata_ops = {
+	.port_disable		= ata_port_disable,
+	.tf_load		= vsc_sata_tf_load,
+	.tf_read		= vsc_sata_tf_read,
+	.exec_command		= ata_exec_command_mmio,
+	.check_status		= ata_check_status_mmio,
+	.phy_reset		= sata_phy_reset,
+	.phy_config		= pata_phy_config,	/* not a typo */
+	.bmdma_start            = ata_bmdma_start_mmio,
+	.fill_sg		= ata_fill_sg,
+	.eng_timeout		= ata_eng_timeout,
+	.irq_handler		= vsc_sata_interrupt,
+	.scr_read		= vsc_sata_scr_read,
+	.scr_write		= vsc_sata_scr_write,
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+};
+
+static void vsc_sata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+	port->cmd_addr		= base + VSC_SATA_TF_CMD_OFFSET;
+	port->data_addr		= base + VSC_SATA_TF_DATA_OFFSET;
+	port->error_addr	= base + VSC_SATA_TF_ERROR_OFFSET;
+	port->feature_addr	= base + VSC_SATA_TF_FEATURE_OFFSET;
+	port->nsect_addr	= base + VSC_SATA_TF_NSECT_OFFSET;
+	port->lbal_addr		= base + VSC_SATA_TF_LBAL_OFFSET;
+	port->lbam_addr		= base + VSC_SATA_TF_LBAM_OFFSET;
+	port->lbah_addr		= base + VSC_SATA_TF_LBAH_OFFSET;
+	port->device_addr	= base + VSC_SATA_TF_DEVICE_OFFSET;
+	port->status_addr	= base + VSC_SATA_TF_STATUS_OFFSET;
+	port->command_addr	= base + VSC_SATA_TF_COMMAND_OFFSET;
+	port->altstatus_addr	= base + VSC_SATA_TF_ALTSTATUS_OFFSET;
+	port->ctl_addr		= base + VSC_SATA_TF_CTL_OFFSET;
+	port->bmdma_addr	= base + VSC_SATA_DMA_CMD_OFFSET;
+	port->scr_addr		= base + VSC_SATA_SCR_STATUS_OFFSET;
+}
+
+
+static int vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	struct ata_probe_ent *probe_ent = NULL;
+	unsigned long base;
+	void *mmio_base;
+	int rc;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	/*
+	 * Check if we have needed resource mapped.
+	 */
+	if (pci_resource_len(pdev, 0) == 0) {
+		rc = -ENODEV;
+		goto err_out;
+	}
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_out;
+
+	/*
+	 * Use 32 bit DMA mask, because 64 bit address support is poor.
+	 */
+	rc = pci_set_dma_mask(pdev, 0xFFFFFFFF);
+	if (rc)
+		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, 0xFFFFFFFF);
+	if (rc)
+		goto err_out_regions;
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (probe_ent == NULL) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	probe_ent->pdev = pdev;
+	INIT_LIST_HEAD(&probe_ent->node);
+
+	mmio_base = ioremap(pci_resource_start(pdev, 0),
+		            pci_resource_len(pdev, 0));
+	if (mmio_base == NULL) {
+		rc = -ENOMEM;
+		goto err_out_free_ent;
+	}
+	base = (unsigned long) mmio_base;
+
+	/*
+	 * Due to a bug in the chip, the default cache line size can't be used
+	 */
+	pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80);
+
+	probe_ent->sht = &vsc_sata_sht;
+	probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				ATA_FLAG_MMIO | ATA_FLAG_SATA_RESET;
+	probe_ent->port_ops = &vsc_sata_ops;
+	probe_ent->n_ports = 4;
+	probe_ent->irq = pdev->irq;
+	probe_ent->irq_flags = SA_SHIRQ;
+	probe_ent->mmio_base = mmio_base;
+
+	/* We don't care much about the PIO/UDMA masks, but the core won't like us
+	 * if we don't fill these
+	 */
+	probe_ent->pio_mask = 0x1f;
+	probe_ent->udma_mask = 0x3f;
+
+	/* We have 4 ports per PCI function */
+	vsc_sata_setup_port(&probe_ent->port[0], base + 1 * VSC_SATA_PORT_OFFSET);
+	vsc_sata_setup_port(&probe_ent->port[1], base + 2 * VSC_SATA_PORT_OFFSET);
+	vsc_sata_setup_port(&probe_ent->port[2], base + 3 * VSC_SATA_PORT_OFFSET);
+	vsc_sata_setup_port(&probe_ent->port[3], base + 4 * VSC_SATA_PORT_OFFSET);
+
+	pci_set_master(pdev);
+
+	/* FIXME: check ata_device_add return value */
+	ata_device_add(probe_ent);
+	kfree(probe_ent);
+
+	return 0;
+
+err_out_free_ent:
+	kfree(probe_ent);
+err_out_regions:
+	pci_release_regions(pdev);
+err_out:
+	pci_disable_device(pdev);
+	return rc;
+}
+
+
+static struct pci_device_id vsc_sata_pci_tbl[] = {
+	{ 0x1725, 0x7174, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
+	{ 0x8086, 0x3200, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
+	{ }
+};
+
+
+static struct pci_driver vsc_sata_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= vsc_sata_pci_tbl,
+	.probe			= vsc_sata_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+
+static int __init vsc_sata_init(void)
+{
+	int rc;
+
+	rc = pci_module_init(&vsc_sata_pci_driver);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+
+static void __exit vsc_sata_exit(void)
+{
+	pci_unregister_driver(&vsc_sata_pci_driver);
+}
+
+
+MODULE_AUTHOR("Jeremy Higdon");
+MODULE_DESCRIPTION("low-level driver for Vitesse VSC7174 SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, vsc_sata_pci_tbl);
+
+module_init(vsc_sata_init);
+module_exit(vsc_sata_exit);
--- diff/drivers/scsi/scsi_transport_fc.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/scsi/scsi_transport_fc.c	2004-03-16 09:37:58.400661920 +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 00:00:00.000000000 +0000
+++ source/drivers/scsi/scsi_transport_spi.c	2004-03-16 09:37:58.402661616 +0000
@@ -0,0 +1,673 @@
+/* 
+ *  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 <linux/smp_lock.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/workqueue.h>
+#include <asm/scatterlist.h>
+#include <asm/io.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_request.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
+
+#define SPI_PRINTK(x, l, f, a...)	printk(l "scsi(%d:%d:%d:%d): " f, (x)->host->host_no, (x)->channel, (x)->id, (x)->lun , ##a)
+
+static void transport_class_release(struct class_device *class_dev);
+
+#define SPI_NUM_ATTRS 10	/* increase this if you add attributes */
+
+#define SPI_MAX_ECHO_BUFFER_SIZE	4096
+
+#define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->transport_data)->dv_pending)
+
+struct spi_internal {
+	struct scsi_transport_template t;
+	struct spi_function_template *f;
+	/* The actual attributes */
+	struct class_device_attribute private_attrs[SPI_NUM_ATTRS];
+	/* The array of null terminated pointers to attributes 
+	 * needed by scsi_sysfs.c */
+	struct class_device_attribute *attrs[SPI_NUM_ATTRS + 1];
+};
+
+#define to_spi_internal(tmpl)	container_of(tmpl, struct spi_internal, t)
+
+static const char *const ppr_to_ns[] = {
+	/* The PPR values 0-6 are reserved, fill them in when
+	 * the committee defines them */
+	NULL,			/* 0x00 */
+	NULL,			/* 0x01 */
+	NULL,			/* 0x02 */
+	NULL,			/* 0x03 */
+	NULL,			/* 0x04 */
+	NULL,			/* 0x05 */
+	NULL,			/* 0x06 */
+	"3.125",		/* 0x07 */
+	"6.25",			/* 0x08 */
+	"12.5",			/* 0x09 */
+	"25",			/* 0x0a */
+	"30.3",			/* 0x0b */
+	"50",			/* 0x0c */
+};
+/* The PPR values at which you calculate the period in ns by multiplying
+ * by 4 */
+#define SPI_STATIC_PPR	0x0c
+
+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)
+{
+	spi_period(sdev) = -1;	/* illegal value */
+	spi_offset(sdev) = 0;	/* async */
+	spi_width(sdev) = 0;	/* narrow */
+	spi_iu(sdev) = 0;	/* no IU */
+	spi_dt(sdev) = 0;	/* ST */
+	spi_qas(sdev) = 0;
+	spi_wr_flow(sdev) = 0;
+	spi_rd_strm(sdev) = 0;
+	spi_rti(sdev) = 0;
+	spi_pcomp_en(sdev) = 0;
+	spi_dv_pending(sdev) = 0;
+
+	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;					\
+	struct spi_internal *i = to_spi_internal(sdev->host->transportt); \
+	tp = (struct spi_transport_attrs *)&sdev->transport_data;	\
+	if (i->f->get_##field)						\
+		i->f->get_##field(sdev);				\
+	return snprintf(buf, 20, format_string, tp->field);		\
+}
+
+#define spi_transport_store_function(field, format_string)		\
+static ssize_t								\
+store_spi_transport_##field(struct class_device *cdev, const char *buf, \
+			    size_t count)				\
+{									\
+	int val;							\
+	struct scsi_device *sdev = transport_class_to_sdev(cdev);	\
+	struct spi_internal *i = to_spi_internal(sdev->host->transportt); \
+									\
+	val = simple_strtoul(buf, NULL, 0);				\
+	i->f->set_##field(sdev, val);					\
+	return count;							\
+}
+
+#define spi_transport_rd_attr(field, format_string)			\
+	spi_transport_show_function(field, format_string)		\
+	spi_transport_store_function(field, format_string)		\
+static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,			\
+			 show_spi_transport_##field,			\
+			 store_spi_transport_##field)
+
+/* The Parallel SCSI Tranport Attributes: */
+spi_transport_rd_attr(offset, "%d\n");
+spi_transport_rd_attr(width, "%d\n");
+spi_transport_rd_attr(iu, "%d\n");
+spi_transport_rd_attr(dt, "%d\n");
+spi_transport_rd_attr(qas, "%d\n");
+spi_transport_rd_attr(wr_flow, "%d\n");
+spi_transport_rd_attr(rd_strm, "%d\n");
+spi_transport_rd_attr(rti, "%d\n");
+spi_transport_rd_attr(pcomp_en, "%d\n");
+
+/* Translate the period into ns according to the current spec
+ * for SDTR/PPR messages */
+static ssize_t show_spi_transport_period(struct class_device *cdev, char *buf)
+
+{
+	struct scsi_device *sdev = transport_class_to_sdev(cdev);
+	struct spi_transport_attrs *tp;
+	const char *str;
+	struct spi_internal *i = to_spi_internal(sdev->host->transportt);
+
+	tp = (struct spi_transport_attrs *)&sdev->transport_data;
+
+	if (i->f->get_period)
+		i->f->get_period(sdev);
+
+	switch(tp->period) {
+
+	case 0x07 ... SPI_STATIC_PPR:
+		str = ppr_to_ns[tp->period];
+		if(!str)
+			str = "reserved";
+		break;
+
+
+	case (SPI_STATIC_PPR+1) ... 0xff:
+		return sprintf(buf, "%d\n", tp->period * 4);
+
+	default:
+		str = "unknown";
+	}
+	return sprintf(buf, "%s\n", str);
+}
+
+static ssize_t
+store_spi_transport_period(struct class_device *cdev, const char *buf,
+			    size_t count)
+{
+	struct scsi_device *sdev = transport_class_to_sdev(cdev);
+	struct spi_internal *i = to_spi_internal(sdev->host->transportt);
+	int j, period = -1;
+
+	for (j = 0; j < SPI_STATIC_PPR; j++) {
+		int len;
+
+		if(ppr_to_ns[j] == NULL)
+			continue;
+
+		len = strlen(ppr_to_ns[j]);
+
+		if(strncmp(ppr_to_ns[j], buf, len) != 0)
+			continue;
+
+		if(buf[len] != '\n')
+			continue;
+		
+		period = j;
+		break;
+	}
+
+	if (period == -1) {
+		int val = simple_strtoul(buf, NULL, 0);
+
+
+		/* Should probably check limits here, but this
+		 * gets reasonably close to OK for most things */
+		period = val/4;
+	}
+
+	if (period > 0xff)
+		period = 0xff;
+
+	i->f->set_period(sdev, period);
+
+	return count;
+}
+	
+static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR, 
+			 show_spi_transport_period,
+			 store_spi_transport_period);
+
+#define DV_SET(x, y)			\
+	if(i->f->set_##x)		\
+		i->f->set_##x(sdev, y)
+
+#define DV_LOOPS	3
+#define DV_TIMEOUT	(10*HZ)
+#define DV_RETRIES	5
+
+
+/* This is for read/write Domain Validation:  If the device supports
+ * an echo buffer, we do read/write tests to it */
+static int
+spi_dv_device_echo_buffer(struct scsi_request *sreq, u8 *buffer,
+			  u8 *ptr, const int retries)
+{
+	struct scsi_device *sdev = sreq->sr_device;
+	int len = ptr - buffer;
+	int j, k, r;
+	unsigned int pattern = 0x0000ffff;
+
+	const char spi_write_buffer[] = {
+		WRITE_BUFFER, 0x0a, 0, 0, 0, 0, 0, len >> 8, len & 0xff, 0
+	};
+	const char spi_read_buffer[] = {
+		READ_BUFFER, 0x0a, 0, 0, 0, 0, 0, len >> 8, len & 0xff, 0
+	};
+
+	/* set up the pattern buffer.  Doesn't matter if we spill
+	 * slightly beyond since that's where the read buffer is */
+	for (j = 0; j < len; ) {
+
+		/* fill the buffer with counting (test a) */
+		for ( ; j < min(len, 32); j++)
+			buffer[j] = j;
+		k = j;
+		/* fill the buffer with alternating words of 0x0 and
+		 * 0xffff (test b) */
+		for ( ; j < min(len, k + 32); j += 2) {
+			u16 *word = (u16 *)&buffer[j];
+			
+			*word = (j & 0x02) ? 0x0000 : 0xffff;
+		}
+		k = j;
+		/* fill with crosstalk (alternating 0x5555 0xaaa)
+                 * (test c) */
+		for ( ; j < min(len, k + 32); j += 2) {
+			u16 *word = (u16 *)&buffer[j];
+
+			*word = (j & 0x02) ? 0x5555 : 0xaaaa;
+		}
+		k = j;
+		/* fill with shifting bits (test d) */
+		for ( ; j < min(len, k + 32); j += 4) {
+			u32 *word = (unsigned int *)&buffer[j];
+			u32 roll = (pattern & 0x80000000) ? 1 : 0;
+			
+			*word = pattern;
+			pattern = (pattern << 1) | roll;
+		}
+		/* don't bother with random data (test e) */
+	}
+
+	for (r = 0; r < retries; r++) {
+		sreq->sr_cmd_len = 0;	/* wait_req to fill in */
+		sreq->sr_data_direction = DMA_TO_DEVICE;
+		scsi_wait_req(sreq, spi_write_buffer, buffer, len,
+			      DV_TIMEOUT, DV_RETRIES);
+		if(sreq->sr_result) {
+			SPI_PRINTK(sdev, KERN_ERR, "Write Buffer failure %x\n", sreq->sr_result);
+			return 0;
+		}
+
+		memset(ptr, 0, len);
+		sreq->sr_cmd_len = 0;	/* wait_req to fill in */
+		sreq->sr_data_direction = DMA_FROM_DEVICE;
+		scsi_wait_req(sreq, spi_read_buffer, ptr, len,
+			      DV_TIMEOUT, DV_RETRIES);
+
+		if (memcmp(buffer, ptr, len) != 0)
+			return 0;
+	}
+	return 1;
+}
+
+/* This is for the simplest form of Domain Validation: a read test
+ * on the inquiry data from the device */
+static int
+spi_dv_device_compare_inquiry(struct scsi_request *sreq, u8 *buffer,
+			      u8 *ptr, const int retries)
+{
+	int r;
+	const int len = sreq->sr_device->inquiry_len;
+	const char spi_inquiry[] = {
+		INQUIRY, 0, 0, 0, len, 0
+	};
+
+	for (r = 0; r < retries; r++) {
+		sreq->sr_cmd_len = 0;	/* wait_req to fill in */
+		sreq->sr_data_direction = DMA_FROM_DEVICE;
+
+		memset(ptr, 0, len);
+
+		scsi_wait_req(sreq, spi_inquiry, ptr, len,
+			      DV_TIMEOUT, DV_RETRIES);
+
+		/* If we don't have the inquiry data already, the
+		 * first read gets it */
+		if (ptr == buffer) {
+			ptr += len;
+			--r;
+			continue;
+		}
+
+		if (memcmp(buffer, ptr, len) != 0)
+			/* failure */
+			return 0;
+	}
+	return 1;
+}
+
+static int
+spi_dv_retrain(struct scsi_request *sreq, u8 *buffer, u8 *ptr,
+	       int (*compare_fn)(struct scsi_request *, u8 *, u8 *, int))
+{
+	struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt);
+	struct scsi_device *sdev = sreq->sr_device;
+	int period, prevperiod = 0; 
+
+
+	for (;;) {
+		if (compare_fn(sreq, buffer, ptr, DV_LOOPS))
+			/* Successful DV */
+			break;
+
+		/* OK, retrain, fallback */
+		if (i->f->get_period)
+			i->f->get_period(sdev);
+		period = spi_period(sdev);
+		if (period < 0x0d)
+			period++;
+		else
+			period += period >> 1;
+
+		if (unlikely(period > 0xff || period == prevperiod)) {
+			/* Total failure; set to async and return */
+			SPI_PRINTK(sdev, KERN_ERR, "Domain Validation Failure, dropping back to Asynchronous\n");
+			DV_SET(offset, 0);
+			return 0;
+		}
+		SPI_PRINTK(sdev, KERN_ERR, "Domain Validation detected failure, dropping back\n");
+		DV_SET(period, period);
+		prevperiod = period;
+	}
+	return 1;
+}
+
+static int
+spi_dv_device_get_echo_buffer(struct scsi_request *sreq, u8 *buffer)
+{
+	int l;
+
+	/* first off do a test unit ready.  This can error out 
+	 * because of reservations or some other reason.  If it
+	 * fails, the device won't let us write to the echo buffer
+	 * so just return failure */
+	
+	const char spi_test_unit_ready[] = {
+		TEST_UNIT_READY, 0, 0, 0, 0, 0
+	};
+
+	const char spi_read_buffer_descriptor[] = {
+		READ_BUFFER, 0x0b, 0, 0, 0, 0, 0, 0, 4, 0
+	};
+
+	
+	sreq->sr_cmd_len = 0;
+	sreq->sr_data_direction = DMA_NONE;
+
+	/* We send a set of three TURs to clear any outstanding 
+	 * unit attention conditions if they exist (Otherwise the
+	 * buffer tests won't be happy).  If the TUR still fails
+	 * (reservation conflict, device not ready, etc) just
+	 * skip the write tests */
+	for (l = 0; ; l++) {
+		scsi_wait_req(sreq, spi_test_unit_ready, NULL, 0,
+			      DV_TIMEOUT, DV_RETRIES);
+
+		if(sreq->sr_result) {
+			if(l >= 3)
+				return 0;
+		} else {
+			/* TUR succeeded */
+			break;
+		}
+	}
+
+	sreq->sr_cmd_len = 0;
+	sreq->sr_data_direction = DMA_FROM_DEVICE;
+
+	scsi_wait_req(sreq, spi_read_buffer_descriptor, buffer, 4,
+		      DV_TIMEOUT, DV_RETRIES);
+
+	if (sreq->sr_result)
+		/* Device has no echo buffer */
+		return 0;
+
+	return buffer[3] + ((buffer[2] & 0x1f) << 8);
+}
+
+static void
+spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer)
+{
+	struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt);
+	struct scsi_device *sdev = sreq->sr_device;
+	int len = sdev->inquiry_len;
+	/* first set us up for narrow async */
+	DV_SET(offset, 0);
+	DV_SET(width, 0);
+	
+	if (!spi_dv_device_compare_inquiry(sreq, buffer, buffer, DV_LOOPS)) {
+		SPI_PRINTK(sdev, KERN_ERR, "Domain Validation Initial Inquiry Failed\n");
+		/* FIXME: should probably offline the device here? */
+		return;
+	}
+
+	/* test width */
+	if (i->f->set_width) {
+		i->f->set_width(sdev, 1);
+
+		if (!spi_dv_device_compare_inquiry(sreq, buffer,
+						   buffer + len,
+						   DV_LOOPS)) {
+			SPI_PRINTK(sdev, KERN_ERR, "Wide Transfers Fail\n");
+			i->f->set_width(sdev, 0);
+		}
+	}
+
+	if (!i->f->set_period)
+		return;
+
+	/* now set up to the maximum */
+	DV_SET(offset, 255);
+	DV_SET(period, 1);
+	if (!spi_dv_retrain(sreq, buffer, buffer + len,
+			    spi_dv_device_compare_inquiry))
+		return;
+
+	/* OK, now we have our initial speed set by the read only inquiry
+	 * test, now try an echo buffer test (if the device allows it) */
+
+	if ((len = spi_dv_device_get_echo_buffer(sreq, buffer)) == 0) {
+		SPI_PRINTK(sdev, KERN_INFO, "Domain Validation skipping write tests\n");
+		return;
+	}
+	if (len > SPI_MAX_ECHO_BUFFER_SIZE) {
+		SPI_PRINTK(sdev, KERN_WARNING, "Echo buffer size %d is too big, trimming to %d\n", len, SPI_MAX_ECHO_BUFFER_SIZE);
+		len = SPI_MAX_ECHO_BUFFER_SIZE;
+	}
+
+	spi_dv_retrain(sreq, buffer, buffer + len,
+		       spi_dv_device_echo_buffer);
+}
+
+
+/**	spi_dv_device - Do Domain Validation on the device
+ *	@sdev:		scsi device to validate
+ *
+ *	Performs the domain validation on the given device in the
+ *	current execution thread.  Since DV operations may sleep,
+ *	the current thread must have user context.  Also no SCSI
+ *	related locks that would deadlock I/O issued by the DV may
+ *	be held.
+ */
+void
+spi_dv_device(struct scsi_device *sdev)
+{
+	struct scsi_request *sreq = scsi_allocate_request(sdev, GFP_KERNEL);
+	u8 *buffer;
+	const int len = SPI_MAX_ECHO_BUFFER_SIZE*2;
+
+	if (unlikely(!sreq))
+		return;
+
+	if (unlikely(scsi_device_get(sdev)))
+		goto out_free_req;
+
+	buffer = kmalloc(len, GFP_KERNEL);
+
+	if (unlikely(!buffer))
+		goto out_put;
+
+	memset(buffer, 0, len);
+
+	if (unlikely(scsi_device_quiesce(sdev)))
+		goto out_free;
+
+	SPI_PRINTK(sdev, KERN_INFO, "Beginning Domain Validation\n");
+
+	spi_dv_device_internal(sreq, buffer);
+
+	SPI_PRINTK(sdev, KERN_INFO, "Ending Domain Validation\n");
+
+	scsi_device_resume(sdev);
+
+ out_free:
+	kfree(buffer);
+ out_put:
+	scsi_device_put(sdev);
+ out_free_req:
+	scsi_release_request(sreq);
+}
+EXPORT_SYMBOL(spi_dv_device);
+
+struct work_queue_wrapper {
+	struct work_struct	work;
+	struct scsi_device	*sdev;
+};
+
+static void
+spi_dv_device_work_wrapper(void *data)
+{
+	struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data;
+	struct scsi_device *sdev = wqw->sdev;
+
+	kfree(wqw);
+	spi_dv_device(sdev);
+	spi_dv_pending(sdev) = 0;
+	scsi_device_put(sdev);
+}
+
+
+/**
+ *	spi_schedule_dv_device - schedule domain validation to occur on the device
+ *	@sdev:	The device to validate
+ *
+ *	Identical to spi_dv_device() above, except that the DV will be
+ *	scheduled to occur in a workqueue later.  All memory allocations
+ *	are atomic, so may be called from any context including those holding
+ *	SCSI locks.
+ */
+void
+spi_schedule_dv_device(struct scsi_device *sdev)
+{
+	struct work_queue_wrapper *wqw =
+		kmalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC);
+
+	if (unlikely(!wqw))
+		return;
+
+	if (unlikely(spi_dv_pending(sdev))) {
+		kfree(wqw);
+		return;
+	}
+
+	if (unlikely(scsi_device_get(sdev))) {
+		kfree(wqw);
+		spi_dv_pending(sdev) = 0;
+		return;
+	}
+
+	INIT_WORK(&wqw->work, spi_dv_device_work_wrapper, wqw);
+	wqw->sdev = sdev;
+
+	schedule_work(&wqw->work);
+}
+EXPORT_SYMBOL(spi_schedule_dv_device);
+
+#define SETUP_ATTRIBUTE(field)						\
+	i->private_attrs[count] = class_device_attr_##field;		\
+	if (!i->f->set_##field) {					\
+		i->private_attrs[count].attr.mode = S_IRUGO;		\
+		i->private_attrs[count].store = NULL;			\
+	}								\
+	i->attrs[count] = &i->private_attrs[count];			\
+	if (i->f->show_##field)						\
+		count++
+
+struct scsi_transport_template *
+spi_attach_transport(struct spi_function_template *ft)
+{
+	struct spi_internal *i = kmalloc(sizeof(struct spi_internal),
+					 GFP_KERNEL);
+	int count = 0;
+	if (unlikely(!i))
+		return NULL;
+
+	memset(i, 0, sizeof(struct spi_internal));
+
+
+	i->t.attrs = &i->attrs[0];
+	i->t.class = &spi_transport_class;
+	i->t.setup = &spi_setup_transport_attrs;
+	i->t.size = sizeof(struct spi_transport_attrs) - sizeof(unsigned long);
+	i->f = ft;
+
+	SETUP_ATTRIBUTE(period);
+	SETUP_ATTRIBUTE(offset);
+	SETUP_ATTRIBUTE(width);
+	SETUP_ATTRIBUTE(iu);
+	SETUP_ATTRIBUTE(dt);
+	SETUP_ATTRIBUTE(qas);
+	SETUP_ATTRIBUTE(wr_flow);
+	SETUP_ATTRIBUTE(rd_strm);
+	SETUP_ATTRIBUTE(rti);
+	SETUP_ATTRIBUTE(pcomp_en);
+
+	/* if you add an attribute but forget to increase SPI_NUM_ATTRS
+	 * this bug will trigger */
+	BUG_ON(count > SPI_NUM_ATTRS);
+
+	i->attrs[count] = NULL;
+
+	return &i->t;
+}
+EXPORT_SYMBOL(spi_attach_transport);
+
+void spi_release_transport(struct scsi_transport_template *t)
+{
+	struct spi_internal *i = to_spi_internal(t);
+
+	kfree(i);
+}
+EXPORT_SYMBOL(spi_release_transport);
+
+
+MODULE_AUTHOR("Martin Hicks");
+MODULE_DESCRIPTION("SPI Transport Attributes");
+MODULE_LICENSE("GPL");
+
+module_init(spi_transport_init);
+module_exit(spi_transport_exit);
--- diff/drivers/scsi/sym53c8xx_2/sym_nvram.h	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/scsi/sym53c8xx_2/sym_nvram.h	2004-03-16 09:37:58.403661464 +0000
@@ -0,0 +1,216 @@
+/*
+ * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
+ * of PCI-SCSI IO processors.
+ *
+ * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
+ *
+ * This driver is derived from the Linux sym53c8xx driver.
+ * Copyright (C) 1998-2000  Gerard Roudier
+ *
+ * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
+ * a port of the FreeBSD ncr driver to Linux-1.2.13.
+ *
+ * The original ncr driver has been written for 386bsd and FreeBSD by
+ *         Wolfgang Stanglmeier        <wolf@cologne.de>
+ *         Stefan Esser                <se@mi.Uni-Koeln.de>
+ * Copyright (C) 1994  Wolfgang Stanglmeier
+ *
+ * Other major contributions:
+ *
+ * NVRAM detection and reading.
+ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+ *
+ *-----------------------------------------------------------------------------
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef SYM_NVRAM_H
+#define SYM_NVRAM_H
+
+#include "sym_conf.h"
+
+/*
+ *	Symbios NVRAM data format
+ */
+#define SYMBIOS_NVRAM_SIZE 368
+#define SYMBIOS_NVRAM_ADDRESS 0x100
+
+struct Symbios_nvram {
+/* Header 6 bytes */
+	u_short type;		/* 0x0000 */
+	u_short byte_count;	/* excluding header/trailer */
+	u_short checksum;
+
+/* Controller set up 20 bytes */
+	u_char	v_major;	/* 0x00 */
+	u_char	v_minor;	/* 0x30 */
+	u32	boot_crc;
+	u_short	flags;
+#define SYMBIOS_SCAM_ENABLE	(1)
+#define SYMBIOS_PARITY_ENABLE	(1<<1)
+#define SYMBIOS_VERBOSE_MSGS	(1<<2)
+#define SYMBIOS_CHS_MAPPING	(1<<3)
+#define SYMBIOS_NO_NVRAM	(1<<3)	/* ??? */
+	u_short	flags1;
+#define SYMBIOS_SCAN_HI_LO	(1)
+	u_short	term_state;
+#define SYMBIOS_TERM_CANT_PROGRAM	(0)
+#define SYMBIOS_TERM_ENABLED		(1)
+#define SYMBIOS_TERM_DISABLED		(2)
+	u_short	rmvbl_flags;
+#define SYMBIOS_RMVBL_NO_SUPPORT	(0)
+#define SYMBIOS_RMVBL_BOOT_DEVICE	(1)
+#define SYMBIOS_RMVBL_MEDIA_INSTALLED	(2)
+	u_char	host_id;
+	u_char	num_hba;	/* 0x04 */
+	u_char	num_devices;	/* 0x10 */
+	u_char	max_scam_devices;	/* 0x04 */
+	u_char	num_valid_scam_devices;	/* 0x00 */
+	u_char	flags2;
+#define SYMBIOS_AVOID_BUS_RESET		(1<<2)
+
+/* Boot order 14 bytes * 4 */
+	struct Symbios_host{
+		u_short	type;		/* 4:8xx / 0:nok */
+		u_short	device_id;	/* PCI device id */
+		u_short	vendor_id;	/* PCI vendor id */
+		u_char	bus_nr;		/* PCI bus number */
+		u_char	device_fn;	/* PCI device/function number << 3*/
+		u_short	word8;
+		u_short	flags;
+#define	SYMBIOS_INIT_SCAN_AT_BOOT	(1)
+		u_short	io_port;	/* PCI io_port address */
+	} host[4];
+
+/* Targets 8 bytes * 16 */
+	struct Symbios_target {
+		u_char	flags;
+#define SYMBIOS_DISCONNECT_ENABLE	(1)
+#define SYMBIOS_SCAN_AT_BOOT_TIME	(1<<1)
+#define SYMBIOS_SCAN_LUNS		(1<<2)
+#define SYMBIOS_QUEUE_TAGS_ENABLED	(1<<3)
+		u_char	rsvd;
+		u_char	bus_width;	/* 0x08/0x10 */
+		u_char	sync_offset;
+		u_short	sync_period;	/* 4*period factor */
+		u_short	timeout;
+	} target[16];
+/* Scam table 8 bytes * 4 */
+	struct Symbios_scam {
+		u_short	id;
+		u_short	method;
+#define SYMBIOS_SCAM_DEFAULT_METHOD	(0)
+#define SYMBIOS_SCAM_DONT_ASSIGN	(1)
+#define SYMBIOS_SCAM_SET_SPECIFIC_ID	(2)
+#define SYMBIOS_SCAM_USE_ORDER_GIVEN	(3)
+		u_short status;
+#define SYMBIOS_SCAM_UNKNOWN		(0)
+#define SYMBIOS_SCAM_DEVICE_NOT_FOUND	(1)
+#define SYMBIOS_SCAM_ID_NOT_SET		(2)
+#define SYMBIOS_SCAM_ID_VALID		(3)
+		u_char	target_id;
+		u_char	rsvd;
+	} scam[4];
+
+	u_char	spare_devices[15*8];
+	u_char	trailer[6];		/* 0xfe 0xfe 0x00 0x00 0x00 0x00 */
+};
+typedef struct Symbios_nvram	Symbios_nvram;
+typedef struct Symbios_host	Symbios_host;
+typedef struct Symbios_target	Symbios_target;
+typedef struct Symbios_scam	Symbios_scam;
+
+/*
+ *	Tekram NvRAM data format.
+ */
+#define TEKRAM_NVRAM_SIZE 64
+#define TEKRAM_93C46_NVRAM_ADDRESS 0
+#define TEKRAM_24C16_NVRAM_ADDRESS 0x40
+
+struct Tekram_nvram {
+	struct Tekram_target {
+		u_char	flags;
+#define	TEKRAM_PARITY_CHECK		(1)
+#define TEKRAM_SYNC_NEGO		(1<<1)
+#define TEKRAM_DISCONNECT_ENABLE	(1<<2)
+#define	TEKRAM_START_CMD		(1<<3)
+#define TEKRAM_TAGGED_COMMANDS		(1<<4)
+#define TEKRAM_WIDE_NEGO		(1<<5)
+		u_char	sync_index;
+		u_short	word2;
+	} target[16];
+	u_char	host_id;
+	u_char	flags;
+#define TEKRAM_MORE_THAN_2_DRIVES	(1)
+#define TEKRAM_DRIVES_SUP_1GB		(1<<1)
+#define	TEKRAM_RESET_ON_POWER_ON	(1<<2)
+#define TEKRAM_ACTIVE_NEGATION		(1<<3)
+#define TEKRAM_IMMEDIATE_SEEK		(1<<4)
+#define	TEKRAM_SCAN_LUNS		(1<<5)
+#define	TEKRAM_REMOVABLE_FLAGS		(3<<6)	/* 0: disable; */
+						/* 1: boot device; 2:all */
+	u_char	boot_delay_index;
+	u_char	max_tags_index;
+	u_short	flags1;
+#define TEKRAM_F2_F6_ENABLED		(1)
+	u_short	spare[29];
+};
+typedef struct Tekram_nvram	Tekram_nvram;
+typedef struct Tekram_target	Tekram_target;
+
+/*
+ *  Union of supported NVRAM formats.
+ */
+struct sym_nvram {
+	int type;
+#define	SYM_SYMBIOS_NVRAM	(1)
+#define	SYM_TEKRAM_NVRAM	(2)
+#if SYM_CONF_NVRAM_SUPPORT
+	union {
+		Symbios_nvram Symbios;
+		Tekram_nvram Tekram;
+	} data;
+#endif
+};
+
+#if SYM_CONF_NVRAM_SUPPORT
+void sym_nvram_setup_host (struct sym_hcb *np, struct sym_nvram *nvram);
+void sym_nvram_setup_target (struct sym_hcb *np, int target, struct sym_nvram *nvp);
+int sym_read_nvram (struct sym_device *np, struct sym_nvram *nvp);
+#else
+static inline void sym_nvram_setup_host(struct sym_hcb *np, struct sym_nvram *nvram) { }
+static inline void sym_nvram_setup_target(struct sym_hcb *np, struct sym_nvram *nvram) { }
+static inline int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp)
+{
+	nvp->type = 0;
+	return 0;
+}
+#endif
+
+#endif /* SYM_NVRAM_H */
--- diff/drivers/usb/gadget/config.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/usb/gadget/config.c	2004-03-16 09:37:58.404661312 +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/gadget/gadget_chips.h	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/usb/gadget/gadget_chips.h	2004-03-16 09:37:58.404661312 +0000
@@ -0,0 +1,57 @@
+/*
+ * USB device controllers have lots of quirks.  Use these macros in
+ * gadget drivers or other code that needs to deal with them, and which
+ * autoconfigures instead of using early binding to the hardware.
+ *
+ * This could eventually work like the ARM mach_is_*() stuff, driven by
+ * some config file that gets updated as new hardware is supported.
+ *
+ * NOTE:  some of these controller drivers may not be available yet.
+ */
+#ifdef CONFIG_USB_GADGET_NET2280
+#define	gadget_is_net2280(g)	!strcmp("net2280", (g)->name)
+#else
+#define	gadget_is_net2280(g)	0
+#endif
+
+#ifdef CONFIG_USB_GADGET_PXA
+#define	gadget_is_pxa(g)	!strcmp("pxa2xx_udc", (g)->name)
+#else
+#define	gadget_is_pxa(g)	0
+#endif
+
+#ifdef CONFIG_USB_GADGET_GOKU
+#define	gadget_is_goku(g)	!strcmp("goku_udc", (g)->name)
+#else
+#define	gadget_is_goku(g)	0
+#endif
+
+#ifdef CONFIG_USB_GADGET_SUPERH
+#define	gadget_is_sh(g)		!strcmp("sh_udc", (g)->name)
+#else
+#define	gadget_is_sh(g)		0
+#endif
+
+#ifdef CONFIG_USB_GADGET_SA1100
+#define	gadget_is_sa1100(g)	!strcmp("sa1100_udc", (g)->name)
+#else
+#define	gadget_is_sa1100(g)	0
+#endif
+
+#ifdef CONFIG_USB_GADGET_MQ11XX
+#define	gadget_is_mq11xx(g)	!strcmp("mq11xx_udc", (g)->name)
+#else
+#define	gadget_is_mq11xx(g)	0
+#endif
+
+#ifdef CONFIG_USB_GADGET_OMAP
+#define	gadget_is_omap(g)	!strcmp("omap_udc", (g)->name)
+#else
+#define	gadget_is_omap(g)	0
+#endif
+
+// CONFIG_USB_GADGET_AT91RM9200
+// CONFIG_USB_GADGET_SX2
+// CONFIG_USB_GADGET_AU1X00
+// ...
+
--- diff/drivers/usb/input/ati_remote.c	1970-01-01 00:00:00.000000000 +0000
+++ source/drivers/usb/input/ati_remote.c	2004-03-16 09:37:58.406661008 +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 00:00:00.000000000 +0000
+++ source/drivers/usb/input/mtouchusb.c	2004-03-16 09:37:58.407660856 +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 00:00:00.000000000 +0000
+++ source/include/asm-alpha/lockmeter.h	2004-03-16 09:37:58.408660704 +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 00:00:00.000000000 +0000
+++ source/include/asm-generic/compat_signal.h	2004-03-16 09:37:58.408660704 +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/1	1970-01-01 00:00:00.000000000 +0000
+++ source/include/asm-i386/1	2004-03-16 09:37:58.409660552 +0000
@@ -0,0 +1,81 @@
+--- pgtable.h.orig	2004-03-10 11:47:23.000000000 +0100
++++ pgtable.h	2004-03-10 12:31:10.000000000 +0100
+@@ -21,15 +21,25 @@
+ #include <asm/bitops.h>
+ #endif
+
+-extern pgd_t swapper_pg_dir[1024];
+-extern void paging_init(void);
++#include <linux/slab.h>
++#include <linux/list.h>
++#include <linux/spinlock.h>
+
+ /*
+  * ZERO_PAGE is a global shared page that is always zero: used
+  * for zero-mapped memory areas etc..
+  */
+-extern unsigned long empty_zero_page[1024];
+ #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, *pmd_cache, *kpmd_cache;
++
++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 pgtable_cache_init(void);
++void paging_init(void);
++void setup_identity_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end);
+
+ #endif /* !__ASSEMBLY__ */
+
+@@ -39,22 +49,15 @@ extern unsigned long empty_zero_page[102
+  * newer 3-level PAE-mode page tables.
+  */
+ #ifndef __ASSEMBLY__
+-#ifdef CONFIG_X86_PAE
+-# include <asm/pgtable-3level.h>
+
+-/*
+- * Need to initialise the X86 PAE caches
+- */
+-extern void pgtable_cache_init(void);
++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
+ # include <asm/pgtable-2level.h>
+-
+-/*
+- * No page table caches to initialise
+- */
+-#define pgtable_cache_init()	do { } while (0)
+-
+ #endif
+ #endif
+
+@@ -63,7 +66,12 @@ extern void pgtable_cache_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)
+@@ -233,6 +241,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/atomic_kmap.h	1970-01-01 00:00:00.000000000 +0000
+++ source/include/asm-i386/atomic_kmap.h	2004-03-16 09:37:58.409660552 +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 00:00:00.000000000 +0000
+++ source/include/asm-i386/kgdb.h	2004-03-16 09:37:58.410660400 +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 00:00:00.000000000 +0000
+++ source/include/asm-i386/kgdb_local.h	2004-03-16 09:37:58.410660400 +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 00:00:00.000000000 +0000
+++ source/include/asm-i386/lockmeter.h	2004-03-16 09:37:58.411660248 +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 00:00:00.000000000 +0000
+++ source/include/asm-ia64/lockmeter.h	2004-03-16 09:37:58.412660096 +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 00:00:00.000000000 +0000
+++ source/include/asm-mips/lockmeter.h	2004-03-16 09:37:58.412660096 +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 00:00:00.000000000 +0000
+++ source/include/asm-sparc64/lockmeter.h	2004-03-16 09:37:58.413659944 +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 00:00:00.000000000 +0000
+++ source/include/asm-x86_64/kgdb.h	2004-03-16 09:37:58.414659792 +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 00:00:00.000000000 +0000
+++ source/include/asm-x86_64/kgdb_local.h	2004-03-16 09:37:58.414659792 +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/audit.h	1970-01-01 00:00:00.000000000 +0000
+++ source/include/linux/audit.h	2004-03-16 09:37:58.415659640 +0000
@@ -0,0 +1,202 @@
+/* audit.h -- Auditing support -*- linux-c -*-
+ *
+ * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
+ * 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
+ *
+ * Written by Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _LINUX_AUDIT_H_
+#define _LINUX_AUDIT_H_
+
+/* Request and reply types */
+#define AUDIT_GET      1000	/* Get status */
+#define AUDIT_SET      1001	/* Set status (enable/disable/auditd) */
+#define AUDIT_LIST     1002	/* List filtering rules */
+#define AUDIT_ADD      1003	/* Add filtering rule */
+#define AUDIT_DEL      1004	/* Delete filtering rule */
+#define AUDIT_USER     1005	/* Send a message from user-space */
+#define AUDIT_LOGIN    1006     /* Define the login id and informaiton */
+#define AUDIT_KERNEL   2000	/* Asynchronous audit record. NOT A REQUEST. */
+
+/* Rule flags */
+#define AUDIT_PER_TASK 0x01	/* Apply rule at task creation (not syscall) */
+#define AUDIT_AT_ENTRY 0x02	/* Apply rule at syscall entry */
+#define AUDIT_AT_EXIT  0x04	/* Apply rule at syscall exit */
+#define AUDIT_PREPEND  0x10	/* Prepend to front of list */
+
+/* Rule actions */
+#define AUDIT_NEVER    0	/* Do not build context if rule matches */
+#define AUDIT_POSSIBLE 1	/* Build context if rule matches  */
+#define AUDIT_ALWAYS   2	/* Generate audit record if rule matches */
+
+/* Rule structure sizes -- if these change, different AUDIT_ADD and
+ * AUDIT_LIST commands must be implemented. */
+#define AUDIT_MAX_FIELDS   64
+#define AUDIT_BITMASK_SIZE 64
+#define AUDIT_WORD(nr) ((__u32)((nr)/32))
+#define AUDIT_BIT(nr)  (1 << ((nr) - AUDIT_WORD(nr)*32))
+
+/* Rule fields */
+				/* These are useful when checking the
+				 * task structure at task creation time
+				 * (AUDIT_PER_TASK).  */
+#define AUDIT_PID	0
+#define AUDIT_UID	1
+#define AUDIT_EUID	2
+#define AUDIT_SUID	3
+#define AUDIT_FSUID	4
+#define AUDIT_GID	5
+#define AUDIT_EGID	6
+#define AUDIT_SGID	7
+#define AUDIT_FSGID	8
+#define AUDIT_LOGINUID	9
+
+				/* These are ONLY useful when checking
+				 * at syscall exit time (AUDIT_AT_EXIT). */
+#define AUDIT_DEVMAJOR	100
+#define AUDIT_DEVMINOR	101
+#define AUDIT_INODE	102
+#define AUDIT_EXIT	103
+#define AUDIT_NOTEXIT	104
+
+
+/* Status symbols */
+				/* Mask values */
+#define AUDIT_STATUS_ENABLED		0x0001
+#define AUDIT_STATUS_FAILURE		0x0002
+#define AUDIT_STATUS_PID		0x0004
+#define AUDIT_STATUS_RATE_LIMIT		0x0008
+#define AUDIT_STATUS_BACKLOG_LIMIT	0x0010
+				/* Failure-to-log actions */
+#define AUDIT_FAIL_SILENT	0
+#define AUDIT_FAIL_PRINTK	1
+#define AUDIT_FAIL_PANIC	2
+
+#ifndef __KERNEL__
+struct audit_message {
+	struct nlmsghdr nlh;
+	char		data[1200];
+};
+#endif
+
+struct audit_status {
+	__u32		mask;		/* Bit mask for valid entries */
+	__u32		enabled;	/* 1 = enabled, 0 = disbaled */
+	__u32		failure;	/* Failure-to-log action */
+	__u32		pid;		/* pid of auditd process */
+	__u32		rate_limit;	/* messages rate limit (per second) */
+	__u32		backlog_limit;	/* waiting messages limit */
+	__u32		lost;		/* messages lost */
+	__u32		backlog;	/* messages waiting in queue */
+};
+
+struct audit_login {
+	__u32		loginuid;
+	int		msglen;
+	char		msg[1024];
+};
+
+struct audit_rule {		/* for AUDIT_LIST, AUDIT_ADD, and AUDIT_DEL */
+	__u32		flags;	/* AUDIT_PER_{TASK,CALL}, AUDIT_PREPEND */
+	__u32		action;	/* AUDIT_NEVER, AUDIT_POSSIBLE, AUDIT_ALWAYS */
+	__u32		field_count;
+	__u32		mask[AUDIT_BITMASK_SIZE];
+	__u32		fields[AUDIT_MAX_FIELDS];
+	__u32		values[AUDIT_MAX_FIELDS];
+};
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_AUDIT
+struct audit_buffer;
+struct audit_context;
+#endif
+
+#ifdef CONFIG_AUDITSYSCALL
+/* These are defined in auditsc.c */
+				/* Public API */
+extern int  audit_alloc(struct task_struct *task);
+extern void audit_free(struct task_struct *task);
+extern void audit_syscall_entry(struct task_struct *task,
+				int major, int minor);
+extern void audit_syscall_exit(struct task_struct *task);
+extern void audit_getname(const char *name);
+extern void audit_putname(const char *name);
+extern void audit_inode(const char *name, unsigned long ino, dev_t rdev);
+
+				/* Private API (for audit.c only) */
+extern int  audit_receive_filter(int type, int pid, int uid, int seq,
+				 void *data);
+extern void audit_get_stamp(struct audit_context *ctx,
+			    struct timespec *t, int *serial);
+extern int  audit_set_loginuid(struct audit_context *ctx, uid_t loginuid);
+#else
+#define audit_alloc(t) ({ 0; })
+#define audit_free(t) do { ; } while (0)
+#define audit_syscall_entry(t,a,b) do { ; } while (0)
+#define audit_syscall_exit(t) do { ; } while (0)
+#define audit_getname(n) do { ; } while (0)
+#define audit_putname(n) do { ; } while (0)
+#define audit_inode(n,i,d) do { ; } while (0)
+#endif
+
+#ifdef CONFIG_AUDIT
+/* These are defined in audit.c */
+				/* Public API */
+extern void		    audit_log(struct audit_context *ctx,
+				      const char *fmt, ...)
+			    __attribute__((format(printf,2,3)));
+
+extern struct audit_buffer *audit_log_start(struct audit_context *ctx);
+extern void		    audit_log_format(struct audit_buffer *ab,
+					     const char *fmt, ...)
+			    __attribute__((format(printf,2,3)));
+extern void		    audit_log_end(struct audit_buffer *ab);
+extern void		    audit_log_end_fast(struct audit_buffer *ab);
+extern void		    audit_log_end_irq(struct audit_buffer *ab);
+extern void		    audit_log_d_path(struct audit_buffer *ab,
+					     const char *prefix,
+					     struct dentry *dentry,
+					     struct vfsmount *vfsmnt);
+extern int		    audit_set_rate_limit(int limit);
+extern int		    audit_set_backlog_limit(int limit);
+extern int		    audit_set_enabled(int state);
+extern int		    audit_set_failure(int state);
+
+				/* Private API (for auditsc.c only) */
+extern void		    audit_send_reply(int pid, int seq, int type,
+					     int done, int multi,
+					     void *payload, int size);
+extern void		    audit_log_lost(const char *message);
+#else
+#define audit_log(t,f,...) do { ; } while (0)
+#define audit_log_start(t) ({ NULL; })
+#define audit_log_vformat(b,f,a) do { ; } while (0)
+#define audit_log_format(b,f,...) do { ; } while (0)
+#define audit_log_end(b) do { ; } while (0)
+#define audit_log_end_fast(b) do { ; } while (0)
+#define audit_log_end_irq(b) do { ; } while (0)
+#define audit_log_d_path(b,p,d,v) do { ; } while (0)
+#define audit_set_rate_limit(l) do { ; } while (0)
+#define audit_set_backlog_limit(l) do { ; } while (0)
+#define audit_set_enabled(s) do { ; } while (0)
+#define audit_set_failure(s) do { ; } while (0)
+#endif
+#endif
+#endif
--- diff/include/linux/compat_siginfo.h	1970-01-01 00:00:00.000000000 +0000
+++ source/include/linux/compat_siginfo.h	2004-03-16 09:37:58.416659488 +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 00:00:00.000000000 +0000
+++ source/include/linux/dwarf2-lang.h	2004-03-16 09:37:58.416659488 +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 00:00:00.000000000 +0000
+++ source/include/linux/dwarf2.h	2004-03-16 09:37:58.418659184 +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 00:00:00.000000000 +0000
+++ source/include/linux/lockmeter.h	2004-03-16 09:37:58.420658880 +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 00:00:00.000000000 +0000
+++ source/include/linux/mqueue.h	2004-03-16 09:37:58.420658880 +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 00:00:00.000000000 +0000
+++ source/include/linux/netpoll.h	2004-03-16 09:37:58.421658728 +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/net/af_ipmi.h	1970-01-01 00:00:00.000000000 +0000
+++ source/include/net/af_ipmi.h	2004-03-16 09:37:58.421658728 +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 00:00:00.000000000 +0000
+++ source/include/scsi/scsi_transport.h	2004-03-16 09:37:58.422658576 +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 00:00:00.000000000 +0000
+++ source/include/scsi/scsi_transport_fc.h	2004-03-16 09:37:58.423658424 +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 00:00:00.000000000 +0000
+++ source/include/scsi/scsi_transport_spi.h	2004-03-16 09:37:58.423658424 +0000
@@ -0,0 +1,96 @@
+/* 
+ *  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;		/* value in the PPR/SDTR command */
+	int offset;
+	unsigned int width:1;	/* 0 - narrow, 1 - wide */
+	unsigned int iu:1;	/* Information Units enabled */
+	unsigned int dt:1;	/* DT clocking enabled */
+	unsigned int qas:1;	/* Quick Arbitration and Selection enabled */
+	unsigned int wr_flow:1;	/* Write Flow control enabled */
+	unsigned int rd_strm:1;	/* Read streaming enabled */
+	unsigned int rti:1;	/* Retain Training Information */
+	unsigned int pcomp_en:1;/* Precompensation enabled */
+	unsigned int dv_pending:1; /* Internal flag */
+};
+
+/* 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)
+#define spi_width(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->width)
+#define spi_iu(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->iu)
+#define spi_dt(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->dt)
+#define spi_qas(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->qas)
+#define spi_wr_flow(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->wr_flow)
+#define spi_rd_strm(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->rd_strm)
+#define spi_rti(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->rti)
+#define spi_pcomp_en(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->pcomp_en)
+
+/* The functions by which the transport class and the driver communicate */
+struct spi_function_template {
+	void	(*get_period)(struct scsi_device *);
+	void	(*set_period)(struct scsi_device *, int);
+	void	(*get_offset)(struct scsi_device *);
+	void	(*set_offset)(struct scsi_device *, int);
+	void	(*get_width)(struct scsi_device *);
+	void	(*set_width)(struct scsi_device *, int);
+	void	(*get_iu)(struct scsi_device *);
+	void	(*set_iu)(struct scsi_device *, int);
+	void	(*get_dt)(struct scsi_device *);
+	void	(*set_dt)(struct scsi_device *, int);
+	void	(*get_qas)(struct scsi_device *);
+	void	(*set_qas)(struct scsi_device *, int);
+	void	(*get_wr_flow)(struct scsi_device *);
+	void	(*set_wr_flow)(struct scsi_device *, int);
+	void	(*get_rd_strm)(struct scsi_device *);
+	void	(*set_rd_strm)(struct scsi_device *, int);
+	void	(*get_rti)(struct scsi_device *);
+	void	(*set_rti)(struct scsi_device *, int);
+	void	(*get_pcomp_en)(struct scsi_device *);
+	void	(*set_pcomp_en)(struct scsi_device *, int);
+	/* The driver sets these to tell the transport class it
+	 * wants the attributes displayed in sysfs.  If the show_ flag
+	 * is not set, the attribute will be private to the transport
+	 * class */
+	unsigned long	show_period:1;
+	unsigned long	show_offset:1;
+	unsigned long	show_width:1;
+	unsigned long	show_iu:1;
+	unsigned long	show_dt:1;
+	unsigned long	show_qas:1;
+	unsigned long	show_wr_flow:1;
+	unsigned long	show_rd_strm:1;
+	unsigned long	show_rti:1;
+	unsigned long	show_pcomp_en:1;
+};
+
+struct scsi_transport_template *spi_attach_transport(struct spi_function_template *);
+void spi_release_transport(struct scsi_transport_template *);
+void spi_schedule_dv_device(struct scsi_device *);
+void spi_dv_device(struct scsi_device *);
+
+#endif /* SCSI_TRANSPORT_SPI_H */
--- diff/include/sound/ak4117.h	1970-01-01 00:00:00.000000000 +0000
+++ source/include/sound/ak4117.h	2004-03-16 09:37:58.425658120 +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 00:00:00.000000000 +0000
+++ source/ipc/compat.c	2004-03-16 09:37:58.427657816 +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 00:00:00.000000000 +0000
+++ source/ipc/mqueue.c	2004-03-16 09:37:58.430657360 +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 00:00:00.000000000 +0000
+++ source/ipc/msgutil.c	2004-03-16 09:37:58.430657360 +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/audit.c	1970-01-01 00:00:00.000000000 +0000
+++ source/kernel/audit.c	2004-03-16 09:37:58.432657056 +0000
@@ -0,0 +1,816 @@
+/* audit.c -- Auditing support -*- linux-c -*-
+ * Gateway between the kernel (e.g., selinux) and the user-space audit daemon.
+ * System-call specific features have moved to auditsc.c
+ *
+ * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
+ * 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
+ *
+ * Written by Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ * Goals: 1) Integrate fully with SELinux.
+ *	  2) Minimal run-time overhead:
+ *	     a) Minimal when syscall auditing is disabled (audit_enable=0).
+ *	     b) Small when syscall auditing is enabled and no audit record
+ *		is generated (defer as much work as possible to record
+ *		generation time):
+ *		i) context is allocated,
+ *		ii) names from getname are stored without a copy, and
+ *		iii) inode information stored from path_lookup.
+ *	  3) Ability to disable syscall auditing at boot time (audit=0).
+ *	  4) Usable by other parts of the kernel (if audit_log* is called,
+ *	     then a syscall record will be generated automatically for the
+ *	     current syscall).
+ *	  5) Netlink interface to user-space.
+ *	  6) Support low-overhead kernel-based filtering to minimize the
+ *	     information that must be passed to user-space.
+ *
+ * Example user-space utilities: http://people.redhat.com/faith/audit/
+ */
+
+#include <linux/init.h>
+#include <asm/atomic.h>
+#include <asm/types.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+
+#include <linux/audit.h>
+
+#include <net/sock.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+
+/* No auditing will take place until audit_initialized != 0.
+ * (Initialization happens after skb_init is called.) */
+static int	audit_initialized;
+
+/* No syscall auditing will take place unless audit_enabled != 0. */
+int		audit_enabled;
+
+/* Default state when kernel boots without any parameters. */
+static int	audit_default;
+
+/* If auditing cannot proceed, audit_failure selects what happens. */
+static int	audit_failure = AUDIT_FAIL_PRINTK;
+
+/* If audit records are to be written to the netlink socket, audit_pid
+ * contains the (non-zero) pid. */
+static int	audit_pid;
+
+/* If audit_limit is non-zero, limit the rate of sending audit records
+ * to that number per second.  This prevents DoS attacks, but results in
+ * audit records being dropped. */
+static int	audit_rate_limit;
+
+/* Number of outstanding audit_buffers allowed. */
+static int	audit_backlog_limit = 64;
+static atomic_t	audit_backlog	    = ATOMIC_INIT(0);
+
+/* Records can be lost in several ways:
+   0) [suppressed in audit_alloc]
+   1) out of memory in audit_log_start [kmalloc of struct audit_buffer]
+   2) out of memory in audit_log_move [alloc_skb]
+   3) suppressed due to audit_rate_limit
+   4) suppressed due to audit_backlog_limit
+*/
+static atomic_t    audit_lost = ATOMIC_INIT(0);
+
+/* The netlink socket. */
+static struct sock *audit_sock;
+
+/* There are two lists of audit buffers.  The txlist contains audit
+ * buffers that cannot be sent immediately to the netlink device because
+ * we are in an irq context (these are sent later in a tasklet).
+ *
+ * The second list is a list of pre-allocated audit buffers (if more
+ * than AUDIT_MAXFREE are in use, the audit buffer is freed instead of
+ * being placed on the freelist). */
+static spinlock_t  audit_txlist_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t  audit_freelist_lock = SPIN_LOCK_UNLOCKED;
+static int	   audit_freelist_count = 0;
+static LIST_HEAD(audit_txlist);
+static LIST_HEAD(audit_freelist);
+
+/* There are three lists of rules -- one to search at task creation
+ * time, one to search at syscall entry time, and another to search at
+ * syscall exit time. */
+static LIST_HEAD(audit_tsklist);
+static LIST_HEAD(audit_entlist);
+static LIST_HEAD(audit_extlist);
+
+/* AUDIT_BUFSIZ is the size of the temporary buffer used for formatting
+ * audit records.  Since printk uses a 1024 byte buffer, this buffer
+ * should be at least that large. */
+#define AUDIT_BUFSIZ 1024
+
+/* AUDIT_MAXFREE is the number of empty audit_buffers we keep on the
+ * audit_freelist.  Doing so eliminates many kmalloc/kfree calls. */
+#define AUDIT_MAXFREE  (2*NR_CPUS)
+
+/* The audit_buffer is used when formatting an audit record.  The caller
+ * locks briefly to get the record off the freelist or to allocate the
+ * buffer, and locks briefly to send the buffer to the netlink layer or
+ * to place it on a transmit queue.  Multiple audit_buffers can be in
+ * use simultaneously. */
+struct audit_buffer {
+	struct list_head     list;
+	struct sk_buff_head  sklist;	/* formatted skbs ready to send */
+	struct audit_context *ctx;	/* NULL or associated context */
+	int		     len;	/* used area of tmp */
+	char		     tmp[AUDIT_BUFSIZ];
+
+				/* Pointer to header and contents */
+	struct nlmsghdr      *nlh;
+	int		     total;
+	int		     type;
+	int		     pid;
+	int		     count; /* Times requeued */
+};
+
+struct audit_entry {
+	struct list_head  list;
+	struct audit_rule rule;
+};
+
+static void audit_panic(const char *message)
+{
+	switch (audit_failure)
+	{
+	case AUDIT_FAIL_SILENT:
+		break;
+	case AUDIT_FAIL_PRINTK:
+		printk(KERN_ERR "audit: %s\n", message);
+		break;
+	case AUDIT_FAIL_PANIC:
+		panic(message);
+		break;
+	}
+}
+
+static inline int audit_rate_check(void)
+{
+	static unsigned long	last_check = 0;
+	static int		messages   = 0;
+	static spinlock_t	lock	   = SPIN_LOCK_UNLOCKED;
+	unsigned long		flags;
+	unsigned long		now;
+	unsigned long		elapsed;
+	int			retval	   = 0;
+
+	if (!audit_rate_limit) return 1;
+
+	spin_lock_irqsave(&lock, flags);
+	if (++messages < audit_rate_limit) {
+		retval = 1;
+	} else {
+		now     = jiffies;
+		elapsed = now - last_check;
+		if (elapsed > HZ) {
+			last_check = now;
+			messages   = 0;
+			retval     = 1;
+		}
+	}
+	spin_unlock_irqrestore(&lock, flags);
+
+	return retval;
+}
+
+/* Emit at least 1 message per second, even if audit_rate_check is
+ * throttling. */
+void audit_log_lost(const char *message)
+{
+	static unsigned long	last_msg = 0;
+	static spinlock_t	lock     = SPIN_LOCK_UNLOCKED;
+	unsigned long		flags;
+	unsigned long		now;
+	int			print;
+
+	atomic_inc(&audit_lost);
+
+	print = (audit_failure == AUDIT_FAIL_PANIC || !audit_rate_limit);
+
+	if (!print) {
+		spin_lock_irqsave(&lock, flags);
+		now = jiffies;
+		if (now - last_msg > HZ) {
+			print = 1;
+			last_msg = now;
+		}
+		spin_unlock_irqrestore(&lock, flags);
+	}
+
+	if (print) {
+		printk(KERN_WARNING
+		       "audit: audit_lost=%d audit_backlog=%d"
+		       " audit_rate_limit=%d audit_backlog_limit=%d\n",
+		       atomic_read(&audit_lost),
+		       atomic_read(&audit_backlog),
+		       audit_rate_limit,
+		       audit_backlog_limit);
+		audit_panic(message);
+	}
+
+}
+
+int audit_set_rate_limit(int limit)
+{
+	int old		 = audit_rate_limit;
+	audit_rate_limit = limit;
+	audit_log(current->audit_context, "audit_rate_limit=%d old=%d",
+		  audit_rate_limit, old);
+	return old;
+}
+
+int audit_set_backlog_limit(int limit)
+{
+	int old		 = audit_backlog_limit;
+	audit_backlog_limit = limit;
+	audit_log(current->audit_context, "audit_backlog_limit=%d old=%d",
+		  audit_backlog_limit, old);
+	return old;
+}
+
+int audit_set_enabled(int state)
+{
+	int old		 = audit_enabled;
+	if (state != 0 && state != 1)
+		return -EINVAL;
+	audit_enabled = state;
+	audit_log(current->audit_context, "audit_enabled=%d old=%d",
+		  audit_enabled, old);
+	return old;
+}
+
+int audit_set_failure(int state)
+{
+	int old		 = audit_failure;
+	if (state != AUDIT_FAIL_SILENT
+	    && state != AUDIT_FAIL_PRINTK
+	    && state != AUDIT_FAIL_PANIC)
+		return -EINVAL;
+	audit_failure = state;
+	audit_log(current->audit_context, "audit_failure=%d old=%d",
+		  audit_failure, old);
+	return old;
+}
+
+#ifdef CONFIG_NET
+void audit_send_reply(int pid, int seq, int type, int done, int multi,
+		      void *payload, int size)
+{
+	struct sk_buff	*skb;
+	struct nlmsghdr	*nlh;
+	int		len = NLMSG_SPACE(size);
+	void		*data;
+	int		flags = multi ? NLM_F_MULTI : 0;
+	int		t     = done  ? NLMSG_DONE  : type;
+
+	skb = alloc_skb(len, GFP_KERNEL);
+	if (!skb)
+		goto nlmsg_failure;
+
+	nlh		 = NLMSG_PUT(skb, pid, seq, t, len - sizeof(*nlh));
+	nlh->nlmsg_flags = flags;
+	data		 = NLMSG_DATA(nlh);
+	memcpy(data, payload, size);
+	netlink_unicast(audit_sock, skb, pid, MSG_DONTWAIT);
+	return;
+
+nlmsg_failure:			/* Used by NLMSG_PUT */
+	if (skb)
+		kfree_skb(skb);
+}
+
+static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+	u32			uid, pid, seq;
+	void			*data;
+	struct audit_status	*status_get, status_set;
+	struct audit_login	*login;
+	int			err = 0;
+	struct audit_buffer	*ab;
+
+	pid  = NETLINK_CREDS(skb)->pid;
+	uid  = NETLINK_CREDS(skb)->uid;
+	seq  = nlh->nlmsg_seq;
+	data = NLMSG_DATA(nlh);
+
+	switch (nlh->nlmsg_type) {
+	case AUDIT_GET:
+		status_set.enabled	 = audit_enabled;
+		status_set.failure	 = audit_failure;
+		status_set.pid		 = audit_pid;
+		status_set.rate_limit	 = audit_rate_limit;
+		status_set.backlog_limit = audit_backlog_limit;
+		status_set.lost		 = atomic_read(&audit_lost);
+		status_set.backlog	 = atomic_read(&audit_backlog);
+		audit_send_reply(pid, seq, AUDIT_GET, 0, 0,
+				 &status_set, sizeof(status_set));
+		break;
+	case AUDIT_SET:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		status_get   = (struct audit_status *)data;
+		if (status_get->mask & AUDIT_STATUS_ENABLED) {
+			err = audit_set_enabled(status_get->enabled);
+			if (err < 0) return err;
+		}
+		if (status_get->mask & AUDIT_STATUS_FAILURE) {
+			err = audit_set_failure(status_get->failure);
+			if (err < 0) return err;
+		}
+		if (status_get->mask & AUDIT_STATUS_PID) {
+			int old   = audit_pid;
+			audit_pid = status_get->pid;
+			audit_log(current->audit_context,
+				  "audit_pid=%d old=%d", audit_pid, old);
+		}
+		if (status_get->mask & AUDIT_STATUS_RATE_LIMIT)
+			audit_set_rate_limit(status_get->rate_limit);
+		if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT)
+			audit_set_backlog_limit(status_get->backlog_limit);
+		break;
+	case AUDIT_USER:
+		ab = audit_log_start(NULL);
+		if (!ab)
+			break;	/* audit_panic has been called */
+		audit_log_format(ab,
+				 "user pid=%d uid=%d length=%d msg='%.1024s'",
+				 pid, uid,
+				 (int)(nlh->nlmsg_len
+				       - ((char *)data - (char *)nlh)),
+				 (char *)data);
+		ab->type = AUDIT_USER;
+		ab->pid  = pid;
+		audit_log_end(ab);
+		break;
+	case AUDIT_LOGIN:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		login = (struct audit_login *)data;
+		ab = audit_log_start(NULL);
+		if (ab) {
+			audit_log_format(ab, "login pid=%d uid=%d loginuid=%d"
+					 " length=%d msg='%.1024s'",
+					 pid, uid,
+					 login->loginuid,
+					 login->msglen,
+					 login->msg);
+			ab->type = AUDIT_LOGIN;
+			ab->pid  = pid;
+			audit_log_end(ab);
+		}
+#ifdef CONFIG_AUDITSYSCALL
+		err = audit_set_loginuid(current->audit_context,
+					 login->loginuid);
+#endif
+		break;
+	case AUDIT_LIST:
+	case AUDIT_ADD:
+	case AUDIT_DEL:
+#ifdef CONFIG_AUDITSYSCALL
+		err = audit_receive_filter(nlh->nlmsg_type, pid, uid, seq,
+					   data);
+#else
+		err = -EOPNOTSUPP;
+#endif
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err < 0 ? err : 0;
+}
+
+/* Get message from skb (based on rtnetlink_rcv_skb).  Each message is
+ * processed by audit_receive_msg.  Malformed skbs with wrong length are
+ * discarded silently.  */
+static int audit_receive_skb(struct sk_buff *skb)
+{
+	int		err;
+	struct nlmsghdr	*nlh;
+	u32		rlen;
+
+	while (skb->len >= NLMSG_SPACE(0)) {
+		nlh = (struct nlmsghdr *)skb->data;
+		if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
+			return 0;
+		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+		if (rlen > skb->len)
+			rlen = skb->len;
+		if ((err = audit_receive_msg(skb, nlh))) {
+			netlink_ack(skb, nlh, -err);
+		} else if (nlh->nlmsg_flags & NLM_F_ACK)
+			netlink_ack(skb, nlh, 0);
+		skb_pull(skb, rlen);
+	}
+	return 0;
+}
+
+/* Receive messages from netlink socket. */
+static void audit_receive(struct sock *sk, int length)
+{
+	struct sk_buff  *skb;
+
+				/* FIXME: this must not cause starvation */
+	while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
+		if (audit_receive_skb(skb) && skb->len)
+			skb_queue_head(&sk->sk_receive_queue, skb);
+		else
+			kfree_skb(skb);
+	}
+}
+
+/* Move data from tmp buffer into an skb.  This is an extra copy, and
+ * that is unfortunate.  However, the copy will only occur when a record
+ * is being written to user space, which is already a high-overhead
+ * operation.  (Elimination of the copy is possible, for example, by
+ * writing directly into a pre-allocated skb, at the cost of wasting
+ * memory. */
+static void audit_log_move(struct audit_buffer *ab)
+{
+	struct sk_buff	*skb;
+	char		*start;
+	int		extra = ab->nlh ? 0 : NLMSG_SPACE(0);
+
+	skb = skb_peek(&ab->sklist);
+	if (!skb || skb_tailroom(skb) <= ab->len + extra) {
+		skb = alloc_skb(2 * ab->len + extra, GFP_ATOMIC);
+		if (!skb) {
+			ab->len = 0; /* Lose information in ab->tmp */
+			audit_log_lost("out of memory in audit_log_move");
+			return;
+		}
+		__skb_queue_tail(&ab->sklist, skb);
+		if (!ab->nlh)
+			ab->nlh = (struct nlmsghdr *)skb_put(skb,
+							     NLMSG_SPACE(0));
+	}
+	start = skb_put(skb, ab->len);
+	memcpy(start, ab->tmp, ab->len);
+	ab->len = 0;
+}
+
+/* Iterate over the skbuff in the audit_buffer, sending their contents
+ * to user space. */
+static inline int audit_log_drain(struct audit_buffer *ab)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&ab->sklist))) {
+		int retval = 0;
+
+		if (audit_pid) {
+			if (ab->nlh) {
+				ab->nlh->nlmsg_len   = ab->total;
+				ab->nlh->nlmsg_type  = ab->type;
+				ab->nlh->nlmsg_flags = 0;
+				ab->nlh->nlmsg_seq   = 0;
+				ab->nlh->nlmsg_pid   = ab->pid;
+			}
+			skb_get(skb); /* because netlink_* frees */
+			retval = netlink_unicast(audit_sock, skb, audit_pid,
+						 MSG_DONTWAIT);
+		}
+		if (retval == -EAGAIN && ab->count < 5) {
+			++ab->count;
+			audit_log_end_irq(ab);
+			return 1;
+		}
+		if (retval < 0) {
+			if (retval == -ECONNREFUSED) {
+				printk(KERN_ERR
+				       "audit: *NO* daemon at audit_pid=%d\n",
+				       audit_pid);
+				audit_pid = 0;
+			} else
+				audit_log_lost("netlink socket too busy");
+		}
+		if (!audit_pid) { /* No daemon */
+			int offset = ab->nlh ? NLMSG_SPACE(0) : 0;
+			int len    = skb->len - offset;
+			printk(KERN_ERR "%*.*s\n",
+			       len, len, skb->data + offset);
+		}
+		kfree_skb(skb);
+		ab->nlh = NULL;
+	}
+	return 0;
+}
+
+/* Initialize audit support at boot time. */
+int __init audit_init(void)
+{
+	printk(KERN_INFO "audit: initializing netlink socket (%s)\n",
+	       audit_default ? "enabled" : "disabled");
+	audit_sock = netlink_kernel_create(NETLINK_AUDIT, audit_receive);
+	if (!audit_sock)
+		audit_panic("cannot initialize netlink socket");
+
+	audit_initialized = 1;
+	audit_enabled = audit_default;
+	audit_log(NULL, "initialized");
+	return 0;
+}
+
+#else
+/* Without CONFIG_NET, we have no skbuffs.  For now, print what we have
+ * in the buffer. */
+static void audit_log_move(struct audit_buffer *ab)
+{
+	printk(KERN_ERR "%*.*s\n", ab->len, ab->len, ab->tmp);
+	ab->len = 0;
+}
+
+static inline int audit_log_drain(struct audit_buffer *ab)
+{
+	return 0;
+}
+
+/* Initialize audit support at boot time. */
+int __init audit_init(void)
+{
+	printk(KERN_INFO "audit: initializing WITHOUT netlink support\n");
+	audit_sock = NULL;
+	audit_pid  = 0;
+
+	audit_initialized = 1;
+	audit_enabled = audit_default;
+	audit_log(NULL, "initialized");
+	return 0;
+}
+#endif
+
+__initcall(audit_init);
+
+/* Process kernel command-line parameter at boot time.  audit=0 or audit=1. */
+static int __init audit_enable(char *str)
+{
+	audit_default = !!simple_strtol(str, NULL, 0);
+	printk(KERN_INFO "audit: %s%s\n",
+	       audit_default ? "enabled" : "disabled",
+	       audit_initialized ? "" : " (after initialization)");
+	if (audit_initialized)
+		audit_enabled = audit_default;
+	return 0;
+}
+
+__setup("audit=", audit_enable);
+
+
+/* Obtain an audit buffer.  This routine does locking to obtain the
+ * audit buffer, but then no locking is required for calls to
+ * audit_log_*format.  If the tsk is a task that is currently in a
+ * syscall, then the syscall is marked as auditable and an audit record
+ * will be written at syscall exit.  If there is no associated task, tsk
+ * should be NULL. */
+struct audit_buffer *audit_log_start(struct audit_context *ctx)
+{
+	struct audit_buffer	*ab	= NULL;
+	unsigned long		flags;
+	struct timespec		t;
+	int			serial	= 0;
+
+	if (!audit_initialized)
+		return NULL;
+
+	if (audit_backlog_limit
+	    && atomic_read(&audit_backlog) > audit_backlog_limit) {
+		if (audit_rate_check())
+			printk(KERN_WARNING
+			       "audit: audit_backlog=%d > "
+			       "audit_backlog_limit=%d\n",
+			       atomic_read(&audit_backlog),
+			       audit_backlog_limit);
+		audit_log_lost("backlog limit exceeded");
+		return NULL;
+	}
+
+	spin_lock_irqsave(&audit_freelist_lock, flags);
+	if (!list_empty(&audit_freelist)) {
+		ab = list_entry(audit_freelist.next,
+				struct audit_buffer, list);
+		list_del(&ab->list);
+		--audit_freelist_count;
+	}
+	spin_unlock_irqrestore(&audit_freelist_lock, flags);
+
+	if (!ab)
+		ab = kmalloc(sizeof(*ab), GFP_ATOMIC);
+	if (!ab)
+		audit_log_lost("audit: out of memory in audit_log_start");
+	if (!ab)
+		return NULL;
+
+	atomic_inc(&audit_backlog);
+	skb_queue_head_init(&ab->sklist);
+
+	ab->ctx   = ctx;
+	ab->len   = 0;
+	ab->nlh   = NULL;
+	ab->total = 0;
+	ab->type  = AUDIT_KERNEL;
+	ab->pid   = 0;
+	ab->count = 0;
+
+#ifdef CONFIG_AUDITSYSCALL
+	if (ab->ctx)
+		audit_get_stamp(ab->ctx, &t, &serial);
+	else
+#endif
+		t = CURRENT_TIME;
+
+	audit_log_format(ab, "audit(%lu.%03lu:%u): ",
+			 t.tv_sec, t.tv_nsec/1000000, serial);
+	return ab;
+}
+
+
+/* Format an audit message into the audit buffer.  If there isn't enough
+ * room in the audit buffer, more room will be allocated and vsnprint
+ * will be called a second time.  Currently, we assume that a printk
+ * can't format message larger than 1024 bytes, so we don't either. */
+static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
+			      va_list args)
+{
+	int len, avail;
+
+	if (!ab)
+		return;
+
+	avail = sizeof(ab->tmp) - ab->len;
+	if (avail <= 0) {
+		audit_log_move(ab);
+		avail = sizeof(ab->tmp) - ab->len;
+	}
+	len   = vsnprintf(ab->tmp + ab->len, avail, fmt, args);
+	if (len >= avail) {
+		/* The printk buffer is 1024 bytes long, so if we get
+		 * here and AUDIT_BUFSIZ is at least 1024, then we can
+		 * log everything that printk could have logged. */
+		audit_log_move(ab);
+		avail = sizeof(ab->tmp) - ab->len;
+		len   = vsnprintf(ab->tmp + ab->len, avail, fmt, args);
+	}
+	ab->len   += (len < avail) ? len : avail;
+	ab->total += (len < avail) ? len : avail;
+}
+
+/* Format a message into the audit buffer.  All the work is done in
+ * audit_log_vformat. */
+void audit_log_format(struct audit_buffer *ab, const char *fmt, ...)
+{
+	va_list args;
+
+	if (!ab)
+		return;
+	va_start(args, fmt);
+	audit_log_vformat(ab, fmt, args);
+	va_end(args);
+}
+
+/* This is a helper-function to print the d_path without using a static
+ * buffer or allocating another buffer in addition to the one in
+ * audit_buffer. */
+void audit_log_d_path(struct audit_buffer *ab, const char *prefix,
+		      struct dentry *dentry, struct vfsmount *vfsmnt)
+{
+	char *p;
+	int  len, avail;
+
+	if (prefix) audit_log_format(ab, " %s", prefix);
+
+	if (ab->len > 128)
+		audit_log_move(ab);
+	avail = sizeof(ab->tmp) - ab->len;
+	p = d_path(dentry, vfsmnt, ab->tmp + ab->len, avail);
+	if (p == ERR_PTR(-ENAMETOOLONG)) {
+		/* FIXME: can we save some information here? */
+		audit_log_format(ab, "<toolong>");
+	} else {
+				/* path isn't at start of buffer */
+		len	   = (ab->tmp + sizeof(ab->tmp) - 1) - p;
+		memmove(ab->tmp + ab->len, p, len);
+		ab->len   += len;
+		ab->total += len;
+	}
+}
+
+/* Remove queued messages from the audit_txlist and send them to userspace. */
+static void audit_tasklet_handler(unsigned long arg)
+{
+	LIST_HEAD(list);
+	struct audit_buffer *ab;
+	unsigned long	    flags;
+
+	spin_lock_irqsave(&audit_txlist_lock, flags);
+	list_splice_init(&audit_txlist, &list);
+	spin_unlock_irqrestore(&audit_txlist_lock, flags);
+
+	while (!list_empty(&list)) {
+		ab = list_entry(list.next, struct audit_buffer, list);
+		list_del(&ab->list);
+		audit_log_end_fast(ab);
+	}
+}
+
+static DECLARE_TASKLET(audit_tasklet, audit_tasklet_handler, 0);
+
+/* The netlink_* functions cannot be called inside an irq context, so
+ * the audit buffer is places on a queue and a tasklet is scheduled to
+ * remove them from the queue outside the irq context.  May be called in
+ * any context. */
+void audit_log_end_irq(struct audit_buffer *ab)
+{
+	unsigned long flags;
+
+	if (!ab)
+		return;
+	spin_lock_irqsave(&audit_txlist_lock, flags);
+	list_add_tail(&ab->list, &audit_txlist);
+	spin_unlock_irqrestore(&audit_txlist_lock, flags);
+
+	tasklet_schedule(&audit_tasklet);
+}
+
+/* Send the message in the audit buffer directly to user space.  May not
+ * be called in an irq context. */
+void audit_log_end_fast(struct audit_buffer *ab)
+{
+	unsigned long flags;
+
+	BUG_ON(in_irq());
+	if (!ab)
+		return;
+	if (!audit_rate_check()) {
+		audit_log_lost("rate limit exceeded");
+	} else {
+		audit_log_move(ab);
+		if (audit_log_drain(ab))
+			return;
+	}
+
+	atomic_dec(&audit_backlog);
+	spin_lock_irqsave(&audit_freelist_lock, flags);
+	if (++audit_freelist_count > AUDIT_MAXFREE)
+		kfree(ab);
+	else
+		list_add(&ab->list, &audit_freelist);
+	spin_unlock_irqrestore(&audit_freelist_lock, flags);
+}
+
+/* Send or queue the message in the audit buffer, depending on the
+ * current context.  (A convenience function that may be called in any
+ * context.) */
+void audit_log_end(struct audit_buffer *ab)
+{
+	if (in_irq())
+		audit_log_end_irq(ab);
+	else
+		audit_log_end_fast(ab);
+}
+
+/* Log an audit record.  This is a convenience function that calls
+ * audit_log_start, audit_log_vformat, and audit_log_end.  It may be
+ * called in any context. */
+void audit_log(struct audit_context *ctx, const char *fmt, ...)
+{
+	struct audit_buffer *ab;
+	va_list args;
+
+	ab = audit_log_start(ctx);
+	if (ab) {
+		va_start(args, fmt);
+		audit_log_vformat(ab, fmt, args);
+		va_end(args);
+		audit_log_end(ab);
+	}
+}
+
+EXPORT_SYMBOL_GPL(audit_set_rate_limit);
+EXPORT_SYMBOL_GPL(audit_set_backlog_limit);
+EXPORT_SYMBOL_GPL(audit_set_enabled);
+EXPORT_SYMBOL_GPL(audit_set_failure);
+
+EXPORT_SYMBOL_GPL(audit_log_start);
+EXPORT_SYMBOL_GPL(audit_log_format);
+EXPORT_SYMBOL_GPL(audit_log_end_irq);
+EXPORT_SYMBOL_GPL(audit_log_end_fast);
+EXPORT_SYMBOL_GPL(audit_log_end);
+EXPORT_SYMBOL_GPL(audit_log);
+EXPORT_SYMBOL_GPL(audit_log_d_path);
--- diff/kernel/auditsc.c	1970-01-01 00:00:00.000000000 +0000
+++ source/kernel/auditsc.c	2004-03-16 09:37:58.434656752 +0000
@@ -0,0 +1,869 @@
+/* auditsc.c -- System-call auditing support -*- linux-c -*-
+ * Handles all system-call specific auditing features.
+ *
+ * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
+ * 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
+ *
+ * Written by Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ * Many of the ideas implemented here are from Stephen C. Tweedie,
+ * especially the idea of avoiding a copy by using getname.
+ *
+ * The method for actual interception of syscall entry and exit (not in
+ * this file -- see entry.S) is based on a GPL'd patch written by
+ * okir@suse.de and Copyright 2003 SuSE Linux AG.
+ *
+ */
+
+#include <linux/init.h>
+#include <asm/atomic.h>
+#include <asm/types.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+
+#include <linux/audit.h>
+#include <linux/time.h>
+#include <asm/unistd.h>
+
+/* 0 = no checking
+   1 = put_count checking
+   2 = verbose put_count checking
+*/
+#define AUDIT_DEBUG 0
+
+/* No syscall auditing will take place unless audit_enabled != 0. */
+extern int audit_enabled;
+
+/* AUDIT_NAMES is the number of slots we reserve in the audit_context
+ * for saving names from getname(). */
+#define AUDIT_NAMES    20
+
+/* AUDIT_NAMES_RESERVED is the number of slots we reserve in the
+ * audit_context from being used for nameless inodes from
+ * path_lookup. */
+#define AUDIT_NAMES_RESERVED 7
+
+/* At task start time, the audit_state is set in the audit_context using
+   a per-task filter.  At syscall entry, the audit_state is augmented by
+   the syscall filter. */
+enum audit_state {
+	AUDIT_DISABLED,		/* Do not create per-task audit_context.
+				 * No syscall-specific audit records can
+				 * be generated. */
+	AUDIT_SETUP_CONTEXT,	/* Create the per-task audit_context,
+				 * but don't necessarily fill it in at
+				 * syscall entry time (i.e., filter
+				 * instead). */
+	AUDIT_BUILD_CONTEXT,	/* Create the per-task audit_context,
+				 * and always fill it in at syscall
+				 * entry time.  This makes a full
+				 * syscall record available if some
+				 * other part of the kernel decides it
+				 * should be recorded. */
+	AUDIT_RECORD_CONTEXT	/* Create the per-task audit_context,
+				 * always fill it in at syscall entry
+				 * time, and always write out the audit
+				 * record at syscall exit time.  */
+};
+
+/* When fs/namei.c:getname() is called, we store the pointer in name and
+ * we don't let putname() free it (instead we free all of the saved
+ * pointers at syscall exit time).
+ *
+ * Further, in fs/namei.c:path_lookup() we store the inode and device. */
+struct audit_names {
+	const char	*name;
+	unsigned long	ino;
+	dev_t		rdev;
+};
+
+/* The per-task audit context. */
+struct audit_context {
+	int		    in_syscall;	/* 1 if task is in a syscall */
+	enum audit_state    state;
+	unsigned int	    serial;     /* serial number for record */
+	struct timespec	    ctime;      /* time of syscall entry */
+	uid_t		    loginuid;   /* login uid (identity) */
+	int		    major;      /* syscall number */
+	int		    minor;      /* function for multiplex syscalls */
+	int		    auditable;  /* 1 if record should be written */
+	int		    name_count;
+	struct audit_names  names[AUDIT_NAMES];
+	struct audit_context *previous; /* For nested syscalls */
+
+				/* Save things to print about task_struct */
+	pid_t		    pid;
+	uid_t		    uid, euid, suid, fsuid;
+	gid_t		    gid, egid, sgid, fsgid;
+
+#if AUDIT_DEBUG
+	int		    put_count;
+	int		    ino_count;
+#endif
+};
+
+				/* Public API */
+/* There are three lists of rules -- one to search at task creation
+ * time, one to search at syscall entry time, and another to search at
+ * syscall exit time. */
+static LIST_HEAD(audit_tsklist);
+static LIST_HEAD(audit_entlist);
+static LIST_HEAD(audit_extlist);
+
+struct audit_entry {
+	struct list_head  list;
+	struct rcu_head   rcu;
+	struct audit_rule rule;
+};
+
+/* Check to see if two rules are identical.  It is called from
+ * audit_del_rule during AUDIT_DEL. */
+static int audit_compare_rule(struct audit_rule *a, struct audit_rule *b)
+{
+	int i;
+
+	if (a->flags != b->flags)
+		return 1;
+
+	if (a->action != b->action)
+		return 1;
+
+	if (a->field_count != b->field_count)
+		return 1;
+
+	for (i = 0; i < a->field_count; i++) {
+		if (a->fields[i] != b->fields[i]
+		    || a->values[i] != b->values[i])
+			return 1;
+	}
+
+	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
+		if (a->mask[i] != b->mask[i])
+			return 1;
+
+	return 0;
+}
+
+static inline int audit_add_rule(struct audit_entry *entry,
+				 struct list_head *list)
+{
+	if (entry->rule.flags & AUDIT_PREPEND) {
+		entry->rule.flags &= ~AUDIT_PREPEND;
+		list_add_rcu(&entry->list, list);
+	} else {
+		list_add_tail_rcu(&entry->list, list);
+	}
+	return 0;
+}
+
+static void audit_free_rule(void *arg)
+{
+	kfree(arg);
+}
+
+static inline int audit_del_rule(struct audit_rule *rule,
+				 struct list_head *list)
+{
+	struct audit_entry  *e;
+
+	list_for_each_entry_rcu(e, list, list) {
+		if (!audit_compare_rule(rule, &e->rule)) {
+			list_del_rcu(&e->list);
+			call_rcu(&e->rcu, audit_free_rule, e);
+			return 0;
+		}
+	}
+	return -EFAULT;		/* No matching rule */
+}
+
+#ifdef CONFIG_NET
+/* Copy rule from user-space to kernel-space.  Called during
+ * AUDIT_ADD. */
+static int audit_copy_rule(struct audit_rule *d, struct audit_rule *s)
+{
+	int i;
+
+	if (s->action != AUDIT_NEVER
+	    && s->action != AUDIT_POSSIBLE
+	    && s->action != AUDIT_ALWAYS)
+		return -1;
+	if (s->field_count < 0 || s->field_count > AUDIT_MAX_FIELDS)
+		return -1;
+
+	d->flags	= s->flags;
+	d->action	= s->action;
+	d->field_count	= s->field_count;
+	for (i = 0; i < d->field_count; i++) {
+		d->fields[i] = s->fields[i];
+		d->values[i] = s->values[i];
+	}
+	for (i = 0; i < AUDIT_BITMASK_SIZE; i++) d->mask[i] = s->mask[i];
+	return 0;
+}
+
+int audit_receive_filter(int type, int pid, int uid, int seq, void *data)
+{
+	u32		   flags;
+	struct audit_entry *entry;
+	int		   err = 0;
+
+	switch (type) {
+	case AUDIT_LIST:
+		list_for_each_entry_rcu(entry, &audit_tsklist, list)
+			audit_send_reply(pid, seq, AUDIT_LIST, 0, 1,
+					 &entry->rule, sizeof(entry->rule));
+		list_for_each_entry_rcu(entry, &audit_entlist, list)
+			audit_send_reply(pid, seq, AUDIT_LIST, 0, 1,
+					 &entry->rule, sizeof(entry->rule));
+		list_for_each_entry_rcu(entry, &audit_extlist, list)
+			audit_send_reply(pid, seq, AUDIT_LIST, 0, 1,
+					 &entry->rule, sizeof(entry->rule));
+		audit_send_reply(pid, seq, AUDIT_LIST, 1, 1, NULL, 0);
+		break;
+	case AUDIT_ADD:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL)))
+			return -ENOMEM;
+		if (audit_copy_rule(&entry->rule, data)) {
+			kfree(entry);
+			return -EINVAL;
+		}
+		flags = entry->rule.flags;
+		if (!err && (flags & AUDIT_PER_TASK))
+			err = audit_add_rule(entry, &audit_tsklist);
+		if (!err && (flags & AUDIT_AT_ENTRY))
+			err = audit_add_rule(entry, &audit_entlist);
+		if (!err && (flags & AUDIT_AT_EXIT))
+			err = audit_add_rule(entry, &audit_extlist);
+		break;
+	case AUDIT_DEL:
+		flags =((struct audit_rule *)data)->flags;
+		if (!err && (flags & AUDIT_PER_TASK))
+			err = audit_del_rule(data, &audit_tsklist);
+		if (!err && (flags & AUDIT_AT_ENTRY))
+			err = audit_del_rule(data, &audit_entlist);
+		if (!err && (flags & AUDIT_AT_EXIT))
+			err = audit_del_rule(data, &audit_extlist);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return err;
+}
+#endif
+
+/* Compare a task_struct with an audit_rule.  Return 1 on match, 0
+ * otherwise. */
+static int audit_filter_rules(struct task_struct *tsk,
+			      struct audit_rule *rule,
+			      struct audit_context *ctx,
+			      enum audit_state *state)
+{
+	int i, j;
+	int found;
+
+	for (i = 0; i < rule->field_count; i++) {
+		u32 value = rule->values[i];
+
+		switch (rule->fields[i]) {
+		case AUDIT_PID:
+			if (tsk->pid   != value)
+				return 0;
+			break;
+		case AUDIT_UID:
+			if (tsk->uid   != value)
+				return 0;
+			break;
+		case AUDIT_EUID:
+			if (tsk->euid  != value)
+				return 0;
+			break;
+		case AUDIT_SUID:
+			if (tsk->suid  != value)
+				return 0;
+			break;
+		case AUDIT_FSUID:
+			if (tsk->fsuid != value)
+				return 0;
+			break;
+		case AUDIT_GID:
+			if (tsk->gid   != value)
+				return 0;
+			break;
+		case AUDIT_EGID:
+			if (tsk->egid  != value)
+				return 0;
+			break;
+		case AUDIT_SGID:
+			if (tsk->sgid  != value)
+				return 0;
+			break;
+		case AUDIT_FSGID:
+			if (tsk->fsgid != value)
+				return 0;
+			break;
+		case AUDIT_EXIT:
+			if (tsk->exit_code!=value)
+				return 0;
+			break;
+		case AUDIT_NOTEXIT:
+			if (tsk->exit_code==value)
+				return 0;
+			break;
+		case AUDIT_DEVMAJOR:
+			if (!ctx)
+				return 0;
+			found = 0;
+			for (j = 0; !found && j < ctx->name_count; j++) {
+				if (MAJOR(ctx->names[j].rdev) == value)
+					++found;
+			}
+			if (!found)
+				return 0;
+			break;
+		case AUDIT_DEVMINOR:
+			if (!ctx)
+				return 0;
+			found = 0;
+			for (j = 0; !found && j < ctx->name_count; j++) {
+				if (MINOR(ctx->names[j].rdev) == value)
+					++found;
+			}
+			if (!found)
+				return 0;
+			break;
+		case AUDIT_INODE:
+			if (!ctx)
+				return 0;
+			found = 0;
+			for (j = 0; !found && j < ctx->name_count; j++) {
+				if (ctx->names[j].ino == value)
+					++found;
+			}
+			if (!found)
+				return 0;
+			break;
+		case AUDIT_LOGINUID:
+			if (!ctx || ctx->loginuid != value)
+				return 0;
+			break;
+		}
+	}
+	switch (rule->action) {
+	case AUDIT_NEVER:    *state = AUDIT_DISABLED;	    break;
+	case AUDIT_POSSIBLE: *state = AUDIT_BUILD_CONTEXT;  break;
+	case AUDIT_ALWAYS:   *state = AUDIT_RECORD_CONTEXT; break;
+	}
+	return 1;
+}
+
+/* At process creation time, we can determine if system-call auditing is
+ * completely disabled for this task.  Since we only have the task
+ * structure at this point, we can only check uid and gid.
+ */
+static enum audit_state audit_filter_task(struct task_struct *tsk)
+{
+	struct audit_entry *e;
+	enum audit_state   state;
+
+	list_for_each_entry_rcu(e, &audit_tsklist, list) {
+		if (audit_filter_rules(tsk, &e->rule, NULL, &state))
+			return state;
+	}
+	return AUDIT_BUILD_CONTEXT;
+}
+
+/* At syscall entry and exit time, this filter is called if the
+ * audit_state is not low enough that auditing cannot take place, but is
+ * also not high enough that we already know we have to write and audit
+ * record (i.e., the state is AUDIT_SETUP_CONTEXT or  AUDIT_BUILD_CONTEXT).
+ */
+static enum audit_state audit_filter_syscall(struct task_struct *tsk,
+					     struct audit_context *ctx,
+					     struct list_head *list)
+{
+	struct audit_entry *e;
+	enum audit_state   state;
+	int		   word = AUDIT_WORD(ctx->major);
+	int		   bit  = AUDIT_BIT(ctx->major);
+
+	list_for_each_entry_rcu(e, list, list) {
+		if ((e->rule.mask[word] & bit) == bit
+ 		    && audit_filter_rules(tsk, &e->rule, ctx, &state))
+			return state;
+	}
+	return AUDIT_BUILD_CONTEXT;
+}
+
+/* This should be called with task_lock() held. */
+static inline struct audit_context *audit_get_context(struct task_struct *tsk)
+{
+	struct audit_context *context = tsk->audit_context;
+
+	if (likely(!context))
+		return NULL;
+	if (context->in_syscall && !context->auditable) {
+		enum audit_state state;
+		state = audit_filter_syscall(tsk, context, &audit_extlist);
+		if (state == AUDIT_RECORD_CONTEXT)
+			context->auditable = 1;
+	}
+
+	context->pid = tsk->pid;
+	context->uid = tsk->uid;
+	context->gid = tsk->gid;
+	context->euid = tsk->euid;
+	context->suid = tsk->suid;
+	context->fsuid = tsk->fsuid;
+	context->egid = tsk->egid;
+	context->sgid = tsk->sgid;
+	context->fsgid = tsk->fsgid;
+	tsk->audit_context = NULL;
+	return context;
+}
+
+static inline void audit_free_names(struct audit_context *context)
+{
+	int i;
+
+#if AUDIT_DEBUG == 2
+	if (context->auditable
+	    ||context->put_count + context->ino_count != context->name_count) {
+		printk(KERN_ERR "audit.c:%d(:%d): major=%d in_syscall=%d"
+		       " name_count=%d put_count=%d"
+		       " ino_count=%d [NOT freeing]\n",
+		       __LINE__,
+		       context->serial, context->major, context->in_syscall,
+		       context->name_count, context->put_count,
+		       context->ino_count);
+		for (i = 0; i < context->name_count; i++)
+			printk(KERN_ERR "names[%d] = %p = %s\n", i,
+			       context->names[i].name,
+			       context->names[i].name);
+		dump_stack();
+		return;
+	}
+#endif
+#if AUDIT_DEBUG
+	context->put_count  = 0;
+	context->ino_count  = 0;
+#endif
+
+	for (i = 0; i < context->name_count; i++)
+		if (context->names[i].name)
+			__putname(context->names[i].name);
+	context->name_count = 0;
+}
+
+static inline void audit_zero_context(struct audit_context *context,
+				      enum audit_state state)
+{
+	uid_t loginuid = context->loginuid;
+
+	memset(context, 0, sizeof(*context));
+	context->state      = state;
+	context->loginuid   = loginuid;
+}
+
+static inline struct audit_context *audit_alloc_context(enum audit_state state)
+{
+	struct audit_context *context;
+
+	if (!(context = kmalloc(sizeof(*context), GFP_KERNEL)))
+		return NULL;
+	audit_zero_context(context, state);
+	return context;
+}
+
+/* Filter on the task information and allocate a per-task audit context
+ * if necessary.  Doing so turns on system call auditing for the
+ * specified task.  This is called from copy_process, so no lock is
+ * needed. */
+int audit_alloc(struct task_struct *tsk)
+{
+	struct audit_context *context;
+	enum audit_state     state;
+
+	if (likely(!audit_enabled))
+		return 0; /* Return if not auditing. */
+
+	state = audit_filter_task(tsk);
+	if (likely(state == AUDIT_DISABLED))
+		return 0;
+
+	if (!(context = audit_alloc_context(state))) {
+		audit_log_lost("out of memory in audit_alloc");
+		return -ENOMEM;
+	}
+
+				/* Preserve login uid */
+	context->loginuid = -1;
+	if (tsk->audit_context)
+		context->loginuid = tsk->audit_context->loginuid;
+
+	tsk->audit_context  = context;
+	set_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
+	return 0;
+}
+
+static inline void audit_free_context(struct audit_context *context)
+{
+	struct audit_context *previous;
+	int		     count = 0;
+
+	do {
+		previous = context->previous;
+		if (previous || (count &&  count < 10)) {
+			++count;
+			printk(KERN_ERR "audit(:%d): major=%d name_count=%d:"
+			       " freeing multiple contexts (%d)\n",
+			       context->serial, context->major,
+			       context->name_count, count);
+		}
+		audit_free_names(context);
+		kfree(context);
+		context  = previous;
+	} while (context);
+	if (count >= 10)
+		printk(KERN_ERR "audit: freed %d contexts\n", count);
+}
+
+static void audit_log_exit(struct audit_context *context)
+{
+	int i;
+
+	audit_log(context,
+		  "syscall=%d,0x%x items=%d"
+		  " pid=%d loginuid=%d uid=%d gid=%d"
+		  " euid=%d suid=%d fsuid=%d"
+		  " egid=%d sgid=%d fsgid=%d",
+		  context->major,
+		  context->minor,
+		  context->name_count,
+		  context->pid,
+		  context->loginuid,
+		  context->uid,
+		  context->gid,
+		  context->euid, context->suid, context->fsuid,
+		  context->egid, context->sgid, context->fsgid);
+	for (i = 0; i < context->name_count; i++) {
+		struct audit_buffer  *ab = audit_log_start(context);
+		if (!ab)
+			continue; /* audit_panic has been called */
+		audit_log_format(ab, "item=%d", i);
+		if (context->names[i].name)
+			audit_log_format(ab, " name=%s",
+					 context->names[i].name);
+		if (context->names[i].ino != (unsigned long)-1)
+			audit_log_format(ab, " inode=%lu",
+					 context->names[i].ino);
+		/* FIXME: should use format_dev_t, but ab structure is
+		 * opaque. */
+		if (context->names[i].rdev != -1)
+			audit_log_format(ab, " dev=%02x:%02x",
+					 MAJOR(context->names[i].rdev),
+					 MINOR(context->names[i].rdev));
+		audit_log_end(ab);
+	}
+}
+
+/* Free a per-task audit context.  Called from copy_process and
+ * __put_task_struct. */
+void audit_free(struct task_struct *tsk)
+{
+	struct audit_context *context;
+
+	task_lock(tsk);
+	context = audit_get_context(tsk);
+	task_unlock(tsk);
+
+	if (likely(!context))
+		return;
+
+	/* Check for system calls that do not go through the exit
+	 * function (e.g., exit_group), then free context block. */
+	if (context->in_syscall && context->auditable)
+		audit_log_exit(context);
+
+	audit_free_context(context);
+}
+
+/* Compute a serial number for the audit record.  Audit records are
+ * written to user-space as soon as they are generated, so a complete
+ * audit record may be written in several pieces.  The timestamp of the
+ * record and this serial number are used by the user-space daemon to
+ * determine which pieces belong to the same audit record.  The
+ * (timestamp,serial) tuple is unique for each syscall and is live from
+ * syscall entry to syscall exit.
+ *
+ * Atomic values are only guaranteed to be 24-bit, so we count down.
+ *
+ * NOTE: Another possibility is to store the formatted records off the
+ * audit context (for those records that have a context), and emit them
+ * all at syscall exit.  However, this could delay the reporting of
+ * significant errors until syscall exit (or never, if the system
+ * halts). */
+static inline unsigned int audit_serial(void)
+{
+	static atomic_t serial = ATOMIC_INIT(0xffffff);
+	unsigned int a, b;
+
+	do {
+		a = atomic_read(&serial);
+		if (atomic_dec_and_test(&serial))
+			atomic_set(&serial, 0xffffff);
+		b = atomic_read(&serial);
+	} while (b != a - 1);
+
+	return 0xffffff - b;
+}
+
+/* Fill in audit context at syscall entry.  This only happens if the
+ * audit context was created when the task was created and the state or
+ * filters demand the audit context be built.  If the state from the
+ * per-task filter or from the per-syscall filter is AUDIT_RECORD_CONTEXT,
+ * then the record will be written at syscall exit time (otherwise, it
+ * will only be written if another part of the kernel requests that it
+ * be written). */
+void audit_syscall_entry(struct task_struct *tsk, int major, int minor)
+{
+	struct audit_context *context = tsk->audit_context;
+	enum audit_state     state;
+
+	BUG_ON(!context);
+
+	/* This happens only on certain architectures that make system
+	 * calls in kernel_thread via the entry.S interface, instead of
+	 * with direct calls.  (If you are porting to a new
+	 * architecture, hitting this condition can indicate that you
+	 * got the _exit/_leave calls backward in entry.S.)
+	 *
+	 * i386     no
+	 * x86_64   no
+	 * ppc64    yes (see arch/ppc64/kernel/misc.S)
+	 *
+	 * This also happens with vm86 emulation in a non-nested manner
+	 * (entries without exits), so this case must be caught.
+	 */
+	if (context->in_syscall) {
+		struct audit_context *newctx;
+
+#if defined(__NR_vm86) && defined(__NR_vm86old)
+		/* vm86 mode should only be entered once */
+		if (major == __NR_vm86 || major == __NR_vm86old)
+			return;
+#endif
+#if AUDIT_DEBUG
+		printk(KERN_ERR
+		       "audit(:%d) pid=%d in syscall=%d;"
+		       " entering syscall=%d\n",
+		       context->serial, tsk->pid, context->major, major);
+#endif
+		newctx = audit_alloc_context(context->state);
+		if (newctx) {
+			newctx->previous   = context;
+			context		   = newctx;
+			tsk->audit_context = newctx;
+		} else	{
+			/* If we can't alloc a new context, the best we
+			 * can do is to leak memory (any pending putname
+			 * will be lost).  The only other alternative is
+			 * to abandon auditing. */
+			audit_zero_context(context, context->state);
+		}
+	}
+	BUG_ON(context->in_syscall || context->name_count);
+
+	if (!audit_enabled)
+		return;
+
+	context->major      = major;
+	context->minor      = minor; /* Only valid for some calls */
+
+	state = context->state;
+	if (state == AUDIT_SETUP_CONTEXT || state == AUDIT_BUILD_CONTEXT)
+		state = audit_filter_syscall(tsk, context, &audit_entlist);
+	if (likely(state == AUDIT_DISABLED))
+		return;
+
+	context->serial     = audit_serial();
+	context->ctime      = CURRENT_TIME;
+	context->in_syscall = 1;
+	context->auditable  = !!(state == AUDIT_RECORD_CONTEXT);
+}
+
+/* Tear down after system call.  If the audit context has been marked as
+ * auditable (either because of the AUDIT_RECORD_CONTEXT state from
+ * filtering, or because some other part of the kernel write an audit
+ * message), then write out the syscall information.  In call cases,
+ * free the names stored from getname(). */
+void audit_syscall_exit(struct task_struct *tsk)
+{
+	struct audit_context *context;
+
+	get_task_struct(tsk);
+	task_lock(tsk);
+	context = audit_get_context(tsk);
+	task_unlock(tsk);
+
+	/* Not having a context here is ok, since the parent may have
+	 * called __put_task_struct. */
+	if (likely(!context))
+		return;
+
+	if (context->in_syscall && context->auditable)
+		audit_log_exit(context);
+
+	context->in_syscall = 0;
+	context->auditable  = 0;
+	if (context->previous) {
+		struct audit_context *new_context = context->previous;
+		context->previous  = NULL;
+		audit_free_context(context);
+		tsk->audit_context = new_context;
+	} else {
+		audit_free_names(context);
+		audit_zero_context(context, context->state);
+		tsk->audit_context = context;
+	}
+	put_task_struct(tsk);
+}
+
+/* Add a name to the list.  Called from fs/namei.c:getname(). */
+void audit_getname(const char *name)
+{
+	struct audit_context *context = current->audit_context;
+
+	BUG_ON(!context);
+	if (!context->in_syscall) {
+#if AUDIT_DEBUG == 2
+		printk(KERN_ERR "audit.c:%d(:%d): ignoring getname(%p)\n",
+		       __LINE__, context->serial, name);
+		dump_stack();
+#endif
+		return;
+	}
+	BUG_ON(context->name_count >= AUDIT_NAMES);
+	context->names[context->name_count].name = name;
+	context->names[context->name_count].ino  = (unsigned long)-1;
+	context->names[context->name_count].rdev = -1;
+	++context->name_count;
+}
+
+/* Intercept a putname request.  Called from
+ * include/linux/fs.h:putname().  If we have stored the name from
+ * getname in the audit context, then we delay the putname until syscall
+ * exit. */
+void audit_putname(const char *name)
+{
+	struct audit_context *context = current->audit_context;
+
+	BUG_ON(!context);
+	if (!context->in_syscall) {
+#if AUDIT_DEBUG == 2
+		printk(KERN_ERR "audit.c:%d(:%d): __putname(%p)\n",
+		       __LINE__, context->serial, name);
+		if (context->name_count) {
+			int i;
+			for (i = 0; i < context->name_count; i++)
+				printk(KERN_ERR "name[%d] = %p = %s\n", i,
+				       context->names[i].name,
+				       context->names[i].name);
+		}
+#endif
+		__putname(name);
+	}
+#if AUDIT_DEBUG
+	else {
+		++context->put_count;
+		if (context->put_count > context->name_count) {
+			printk(KERN_ERR "audit.c:%d(:%d): major=%d"
+			       " in_syscall=%d putname(%p) name_count=%d"
+			       " put_count=%d\n",
+			       __LINE__,
+			       context->serial, context->major,
+			       context->in_syscall, name, context->name_count,
+			       context->put_count);
+			dump_stack();
+		}
+	}
+#endif
+}
+
+/* Store the inode and device from a lookup.  Called from
+ * fs/namei.c:path_lookup(). */
+void audit_inode(const char *name, unsigned long ino, dev_t rdev)
+{
+	int idx;
+	struct audit_context *context = current->audit_context;
+
+	if (context->name_count
+	    && context->names[context->name_count-1].name
+	    && context->names[context->name_count-1].name == name)
+		idx = context->name_count - 1;
+	else if (context->name_count > 1
+		 && context->names[context->name_count-2].name
+		 && context->names[context->name_count-2].name == name)
+		idx = context->name_count - 2;
+	else {
+		/* FIXME: how much do we care about inodes that have no
+		 * associated name? */
+		if (context->name_count >= AUDIT_NAMES - AUDIT_NAMES_RESERVED)
+			return;
+		idx = context->name_count++;
+		context->names[idx].name = NULL;
+#if AUDIT_DEBUG
+		++context->ino_count;
+#endif
+	}
+	context->names[idx].ino  = ino;
+	context->names[idx].rdev = rdev;
+}
+
+void audit_get_stamp(struct audit_context *ctx,
+		     struct timespec *t, int *serial)
+{
+	if (ctx) {
+		t->tv_sec  = ctx->ctime.tv_sec;
+		t->tv_nsec = ctx->ctime.tv_nsec;
+		*serial    = ctx->serial;
+		ctx->auditable = 1;
+	} else {
+		*t      = CURRENT_TIME;
+		*serial = 0;
+	}
+}
+
+int audit_set_loginuid(struct audit_context *ctx, uid_t loginuid)
+{
+	if (ctx) {
+		if (loginuid < 0)
+			return -EINVAL;
+		ctx->loginuid = loginuid;
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(audit_alloc);
+EXPORT_SYMBOL_GPL(audit_free);
+EXPORT_SYMBOL_GPL(audit_syscall_entry);
+EXPORT_SYMBOL_GPL(audit_syscall_exit);
+EXPORT_SYMBOL_GPL(audit_getname);
+EXPORT_SYMBOL_GPL(audit_putname);
+EXPORT_SYMBOL_GPL(audit_inode);
--- diff/kernel/compat_signal.c	1970-01-01 00:00:00.000000000 +0000
+++ source/kernel/compat_signal.c	2004-03-16 09:37:58.435656600 +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 00:00:00.000000000 +0000
+++ source/kernel/lockmeter.c	2004-03-16 09:37:58.437656296 +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/mm/usercopy.c	1970-01-01 00:00:00.000000000 +0000
+++ source/mm/usercopy.c	2004-03-16 09:37:58.469651432 +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 00:00:00.000000000 +0000
+++ source/net/core/netpoll.c	2004-03-16 09:37:58.471651128 +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 00:00:00.000000000 +0000
+++ source/net/ipmi/Makefile	2004-03-16 09:37:58.471651128 +0000
@@ -0,0 +1 @@
+obj-$(CONFIG_IPMI_SOCKET) = af_ipmi.o
--- diff/net/ipmi/af_ipmi.c	1970-01-01 00:00:00.000000000 +0000
+++ source/net/ipmi/af_ipmi.c	2004-03-16 09:37:58.473650824 +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/scripts/basic/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ source/scripts/basic/Makefile	2004-03-16 09:37:58.473650824 +0000
@@ -0,0 +1,18 @@
+###
+# Makefile.basic list the most basic programs used during the build process.
+# The programs listed herein is what is needed to do the basic stuff,
+# such as splitting .config and fix dependency file.
+# This initial step is needed to avoid files to be recompiled
+# when kernel configuration changes (which is what happens when
+# .config is included by main Makefile.
+# ---------------------------------------------------------------------------
+# fixdep: 	 Used to generate dependency information during build process
+# split-include: Divide all config symbols up in a number of files in
+#                include/config/...
+# docproc:	 Used in Documentation/docbook
+
+host-progs	:= fixdep split-include docproc
+always		:= $(host-progs)
+
+# fixdep is needed to compile other host programs
+$(addprefix $(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep
--- diff/scripts/basic/docproc.c	1970-01-01 00:00:00.000000000 +0000
+++ source/scripts/basic/docproc.c	2004-03-16 09:37:58.474650672 +0000
@@ -0,0 +1,387 @@
+/*
+ *	docproc is a simple preprocessor for the template files
+ *      used as placeholders for the kernel internal documentation.
+ *	docproc is used for documentation-frontend and
+ *      dependency-generator.
+ *	The two usages have in common that they require
+ *	some knowledge of the .tmpl syntax, therefore they
+ *	are kept together.
+ *
+ *	documentation-frontend
+ *		Scans the template file and call kernel-doc for
+ *		all occurrences of ![EIF]file
+ *		Beforehand each referenced file are scanned for
+ *		any exported sympols "EXPORT_SYMBOL()" statements.
+ *		This is used to create proper -function and
+ *		-nofunction arguments in calls to kernel-doc.
+ *		Usage: docproc doc file.tmpl
+ *
+ *	dependency-generator:
+ *		Scans the template file and list all files
+ *		referenced in a format recognized by make.
+ *		Usage:	docproc depend file.tmpl
+ *		Writes dependency information to stdout
+ *		in the following format:
+ *		file.tmpl src.c	src2.c
+ *		The filenames are obtained from the following constructs:
+ *		!Efilename
+ *		!Ifilename
+ *		!Dfilename
+ *		!Ffilename
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+/* exitstatus is used to keep track of any failing calls to kernel-doc,
+ * but execution continues. */
+int exitstatus = 0;
+
+typedef void DFL(char *);
+DFL *defaultline;
+
+typedef void FILEONLY(char * file);
+FILEONLY *internalfunctions;
+FILEONLY *externalfunctions;
+FILEONLY *symbolsonly;
+
+typedef void FILELINE(char * file, char * line);
+FILELINE * singlefunctions;
+FILELINE * entity_system;
+
+#define MAXLINESZ     2048
+#define MAXFILES      250
+#define KERNELDOCPATH "scripts/"
+#define KERNELDOC     "kernel-doc"
+#define DOCBOOK       "-docbook"
+#define FUNCTION      "-function"
+#define NOFUNCTION    "-nofunction"
+
+void usage (void)
+{
+	fprintf(stderr, "Usage: docproc {doc|depend} file\n");
+	fprintf(stderr, "Input is read from file.tmpl. Output is sent to stdout\n");
+	fprintf(stderr, "doc: frontend when generating kernel documentation\n");
+	fprintf(stderr, "depend: generate list of files referenced within file\n");
+}
+
+/*
+ * Execute kernel-doc with parameters givin in svec
+ */
+void exec_kernel_doc(char **svec)
+{
+	pid_t pid;
+	int ret;
+	/* Make sure output generated so far are flushed */
+	fflush(stdout);
+	switch(pid=fork()) {
+		case -1:
+			perror("fork");
+			exit(1);
+		case  0:
+			execvp(KERNELDOCPATH KERNELDOC, svec);
+			perror("exec " KERNELDOCPATH KERNELDOC);
+			exit(1);
+		default:
+			waitpid(pid, &ret ,0);
+	}
+	if (WIFEXITED(ret))
+		exitstatus |= WEXITSTATUS(ret);
+	else
+		exitstatus = 0xff;
+}
+
+/* Types used to create list of all exported symbols in a number of files */
+struct symbols
+{
+	char *name;
+};
+
+struct symfile
+{
+	char *filename;
+	struct symbols *symbollist;
+	int symbolcnt;
+};
+
+struct symfile symfilelist[MAXFILES];
+int symfilecnt = 0;
+
+void add_new_symbol(struct symfile *sym, char * symname)
+{
+	sym->symbollist =
+          realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *));
+	sym->symbollist[sym->symbolcnt++].name = strdup(symname);
+}
+
+/* Add a filename to the list */
+struct symfile * add_new_file(char * filename)
+{
+	symfilelist[symfilecnt++].filename = strdup(filename);
+	return &symfilelist[symfilecnt - 1];
+}
+/* Check if file already are present in the list */
+struct symfile * filename_exist(char * filename)
+{
+	int i;
+	for (i=0; i < symfilecnt; i++)
+		if (strcmp(symfilelist[i].filename, filename) == 0)
+			return &symfilelist[i];
+	return NULL;
+}
+
+/*
+ * List all files referenced within the template file.
+ * Files are separated by tabs.
+ */
+void adddep(char * file)		   { printf("\t%s", file); }
+void adddep2(char * file, char * line)     { line = line; adddep(file); }
+void noaction(char * line)		   { line = line; }
+void noaction2(char * file, char * line)   { file = file; line = line; }
+
+/* Echo the line without further action */
+void printline(char * line)               { printf("%s", line); }
+
+/*
+ * Find all symbols exported with EXPORT_SYMBOL and EXPORT_SYMBOL_GPL
+ * in filename.
+ * All symbols located are stored in symfilelist.
+ */
+void find_export_symbols(char * filename)
+{
+	FILE * fp;
+	struct symfile *sym;
+	char line[MAXLINESZ];
+	if (filename_exist(filename) == NULL) {
+		sym = add_new_file(filename);
+		fp = fopen(filename, "r");
+		if (fp == NULL)
+		{
+			fprintf(stderr, "docproc: ");
+			perror(filename);
+		}
+		while(fgets(line, MAXLINESZ, fp)) {
+			char *p;
+			char *e;
+			if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != 0) ||
+                            ((p = strstr(line, "EXPORT_SYMBOL")) != 0)) {
+				/* Skip EXPORT_SYMBOL{_GPL} */
+				while (isalnum(*p) || *p == '_')
+					p++;
+				/* Remove paranteses and additional ws */
+				while (isspace(*p))
+					p++;
+				if (*p != '(')
+					continue; /* Syntax error? */
+				else
+					p++;
+				while (isspace(*p))
+					p++;
+				e = p;
+				while (isalnum(*e) || *e == '_')
+					e++;
+				*e = '\0';
+				add_new_symbol(sym, p);
+			}
+		}
+		fclose(fp);
+	}
+}
+
+/*
+ * Document all external or internal functions in a file.
+ * Call kernel-doc with following parameters:
+ * kernel-doc -docbook -nofunction function_name1 filename
+ * function names are obtained from all the the src files
+ * by find_export_symbols.
+ * intfunc uses -nofunction
+ * extfunc uses -function
+ */
+void docfunctions(char * filename, char * type)
+{
+	int i,j;
+	int symcnt = 0;
+	int idx = 0;
+	char **vec;
+
+	for (i=0; i <= symfilecnt; i++)
+		symcnt += symfilelist[i].symbolcnt;
+	vec = malloc((2 + 2 * symcnt + 2) * sizeof(char*));
+	if (vec == NULL) {
+		perror("docproc: ");
+		exit(1);
+	}
+	vec[idx++] = KERNELDOC;
+	vec[idx++] = DOCBOOK;
+	for (i=0; i < symfilecnt; i++) {
+		struct symfile * sym = &symfilelist[i];
+		for (j=0; j < sym->symbolcnt; j++) {
+			vec[idx++]     = type;
+			vec[idx++] = sym->symbollist[j].name;
+		}
+	}
+	vec[idx++]     = filename;
+	vec[idx] = NULL;
+	printf("<!-- %s -->\n", filename);
+	exec_kernel_doc(vec);
+	fflush(stdout);
+	free(vec);
+}
+void intfunc(char * filename) {	docfunctions(filename, NOFUNCTION); }
+void extfunc(char * filename) { docfunctions(filename, FUNCTION);   }
+
+/*
+ * Document spåecific function(s) in a file.
+ * Call kernel-doc with the following parameters:
+ * kernel-doc -docbook -function function1 [-function function2]
+ */
+void singfunc(char * filename, char * line)
+{
+	char *vec[200]; /* Enough for specific functions */
+        int i, idx = 0;
+        int startofsym = 1;
+	vec[idx++] = KERNELDOC;
+	vec[idx++] = DOCBOOK;
+
+        /* Split line up in individual parameters preceeded by FUNCTION */
+        for (i=0; line[i]; i++) {
+                if (isspace(line[i])) {
+                        line[i] = '\0';
+                        startofsym = 1;
+                        continue;
+                }
+                if (startofsym) {
+                        startofsym = 0;
+                        vec[idx++] = FUNCTION;
+                        vec[idx++] = &line[i];
+                }
+        }
+	vec[idx++] = filename;
+	vec[idx] = NULL;
+	exec_kernel_doc(vec);
+}
+
+/*
+ * Parse file, calling action specific functions for:
+ * 1) Lines containing !E
+ * 2) Lines containing !I
+ * 3) Lines containing !D
+ * 4) Lines containing !F
+ * 5) Default lines - lines not matching the above
+ */
+void parse_file(FILE *infile)
+{
+	char line[MAXLINESZ];
+	char * s;
+	while(fgets(line, MAXLINESZ, infile)) {
+		if (line[0] == '!') {
+			s = line + 2;
+			switch (line[1]) {
+				case 'E':
+					while (*s && !isspace(*s)) s++;
+					*s = '\0';
+					externalfunctions(line+2);
+					break;
+				case 'I':
+					while (*s && !isspace(*s)) s++;
+					*s = '\0';
+					internalfunctions(line+2);
+					break;
+				case 'D':
+					while (*s && !isspace(*s)) s++;
+                                        *s = '\0';
+                                        symbolsonly(line+2);
+                                        break;
+				case 'F':
+					/* filename */
+					while (*s && !isspace(*s)) s++;
+					*s++ = '\0';
+                                        /* function names */
+					while (isspace(*s))
+						s++;
+					singlefunctions(line +2, s);
+					break;
+				default:
+					defaultline(line);
+			}
+		}
+		else {
+			defaultline(line);
+		}
+	}
+	fflush(stdout);
+}
+
+
+int main(int argc, char *argv[])
+{
+	FILE * infile;
+	if (argc != 3) {
+		usage();
+		exit(1);
+	}
+	/* Open file, exit on error */
+	infile = fopen(argv[2], "r");
+        if (infile == NULL) {
+                fprintf(stderr, "docproc: ");
+                perror(argv[2]);
+                exit(2);
+        }
+
+	if (strcmp("doc", argv[1]) == 0)
+	{
+		/* Need to do this in two passes.
+		 * First pass is used to collect all symbols exported
+		 * in the various files.
+		 * Second pass generate the documentation.
+		 * This is required because function are declared
+		 * and exported in different files :-((
+		 */
+		/* Collect symbols */
+		defaultline       = noaction;
+		internalfunctions = find_export_symbols;
+		externalfunctions = find_export_symbols;
+		symbolsonly       = find_export_symbols;
+		singlefunctions   = noaction2;
+		parse_file(infile);
+
+		/* Rewind to start from beginning of file again */
+		fseek(infile, 0, SEEK_SET);
+		defaultline       = printline;
+		internalfunctions = intfunc;
+		externalfunctions = extfunc;
+		symbolsonly       = printline;
+		singlefunctions   = singfunc;
+
+		parse_file(infile);
+	}
+	else if (strcmp("depend", argv[1]) == 0)
+	{
+		/* Create first part of dependency chain
+		 * file.tmpl */
+		printf("%s\t", argv[2]);
+		defaultline       = noaction;
+		internalfunctions = adddep;
+		externalfunctions = adddep;
+		symbolsonly       = adddep;
+		singlefunctions   = adddep2;
+		parse_file(infile);
+		printf("\n");
+	}
+	else
+	{
+		fprintf(stderr, "Unknown option: %s\n", argv[1]);
+		exit(1);
+	}
+	fclose(infile);
+	fflush(stdout);
+	return exitstatus;
+}
+
--- diff/scripts/basic/fixdep.c	1970-01-01 00:00:00.000000000 +0000
+++ source/scripts/basic/fixdep.c	2004-03-16 09:37:58.475650520 +0000
@@ -0,0 +1,381 @@
+/*
+ * "Optimize" a list of dependencies as spit out by gcc -MD
+ * for the kernel build
+ * ===========================================================================
+ *
+ * Author       Kai Germaschewski
+ * Copyright    2002 by Kai Germaschewski  <kai.germaschewski@gmx.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ *
+ * Introduction:
+ *
+ * gcc produces a very nice and correct list of dependencies which
+ * tells make when to remake a file.
+ *
+ * To use this list as-is however has the drawback that virtually
+ * every file in the kernel includes <linux/config.h> which then again
+ * includes <linux/autoconf.h>
+ *
+ * If the user re-runs make *config, linux/autoconf.h will be
+ * regenerated.  make notices that and will rebuild every file which
+ * includes autoconf.h, i.e. basically all files. This is extremely
+ * annoying if the user just changed CONFIG_HIS_DRIVER from n to m.
+ *
+ * So we play the same trick that "mkdep" played before. We replace
+ * the dependency on linux/autoconf.h by a dependency on every config
+ * option which is mentioned in any of the listed prequisites.
+ *
+ * To be exact, split-include populates a tree in include/config/,
+ * e.g. include/config/his/driver.h, which contains the #define/#undef
+ * for the CONFIG_HIS_DRIVER option.
+ *
+ * So if the user changes his CONFIG_HIS_DRIVER option, only the objects
+ * which depend on "include/linux/config/his/driver.h" will be rebuilt,
+ * so most likely only his driver ;-)
+ *
+ * The idea above dates, by the way, back to Michael E Chastain, AFAIK.
+ *
+ * So to get dependencies right, there two issues:
+ * o if any of the files the compiler read changed, we need to rebuild
+ * o if the command line given to the compile the file changed, we
+ *   better rebuild as well.
+ *
+ * The former is handled by using the -MD output, the later by saving
+ * the command line used to compile the old object and comparing it
+ * to the one we would now use.
+ *
+ * Again, also this idea is pretty old and has been discussed on
+ * kbuild-devel a long time ago. I don't have a sensibly working
+ * internet connection right now, so I rather don't mention names
+ * without double checking.
+ *
+ * This code here has been based partially based on mkdep.c, which
+ * says the following about its history:
+ *
+ *   Copyright abandoned, Michael Chastain, <mailto:mec@shout.net>.
+ *   This is a C version of syncdep.pl by Werner Almesberger.
+ *
+ *
+ * It is invoked as
+ *
+ *   fixdep <depfile> <target> <cmdline>
+ *
+ * and will read the dependency file <depfile>
+ *
+ * The transformed dependency snipped is written to stdout.
+ *
+ * It first generates a line
+ *
+ *   cmd_<target> = <cmdline>
+ *
+ * and then basically copies the .<target>.d file to stdout, in the
+ * process filtering out the dependency on linux/autoconf.h and adding
+ * dependencies on include/config/my/option.h for every
+ * CONFIG_MY_OPTION encountered in any of the prequisites.
+ *
+ * It will also filter out all the dependencies on *.ver. We need
+ * to make sure that the generated version checksum are globally up
+ * to date before even starting the recursive build, so it's too late
+ * at this point anyway.
+ *
+ * The algorithm to grep for "CONFIG_..." is bit unusual, but should
+ * be fast ;-) We don't even try to really parse the header files, but
+ * merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will
+ * be picked up as well. It's not a problem with respect to
+ * correctness, since that can only give too many dependencies, thus
+ * we cannot miss a rebuild. Since people tend to not mention totally
+ * unrelated CONFIG_ options all over the place, it's not an
+ * efficiency problem either.
+ *
+ * (Note: it'd be easy to port over the complete mkdep state machine,
+ *  but I don't think the added complexity is worth it)
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <ctype.h>
+#include <netinet/in.h>
+
+#define INT_CONF ntohl(0x434f4e46)
+#define INT_ONFI ntohl(0x4f4e4649)
+#define INT_NFIG ntohl(0x4e464947)
+#define INT_FIG_ ntohl(0x4649475f)
+
+char *target;
+char *depfile;
+char *cmdline;
+
+void usage(void)
+
+{
+	fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
+	exit(1);
+}
+
+void print_cmdline(void)
+{
+	printf("cmd_%s := %s\n\n", target, cmdline);
+}
+
+char * str_config  = NULL;
+int    size_config = 0;
+int    len_config  = 0;
+
+/*
+ * Grow the configuration string to a desired length.
+ * Usually the first growth is plenty.
+ */
+void grow_config(int len)
+{
+	while (len_config + len > size_config) {
+		if (size_config == 0)
+			size_config = 2048;
+		str_config = realloc(str_config, size_config *= 2);
+		if (str_config == NULL)
+			{ perror("fixdep:malloc"); exit(1); }
+	}
+}
+
+
+
+/*
+ * Lookup a value in the configuration string.
+ */
+int is_defined_config(const char * name, int len)
+{
+	const char * pconfig;
+	const char * plast = str_config + len_config - len;
+	for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) {
+		if (pconfig[ -1] == '\n'
+		&&  pconfig[len] == '\n'
+		&&  !memcmp(pconfig, name, len))
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * Add a new value to the configuration string.
+ */
+void define_config(const char * name, int len)
+{
+	grow_config(len + 1);
+
+	memcpy(str_config+len_config, name, len);
+	len_config += len;
+	str_config[len_config++] = '\n';
+}
+
+/*
+ * Clear the set of configuration strings.
+ */
+void clear_config(void)
+{
+	len_config = 0;
+	define_config("", 0);
+}
+
+/*
+ * Record the use of a CONFIG_* word.
+ */
+void use_config(char *m, int slen)
+{
+	char s[PATH_MAX];
+	char *p;
+
+	if (is_defined_config(m, slen))
+	    return;
+
+	define_config(m, slen);
+
+	memcpy(s, m, slen); s[slen] = 0;
+
+	for (p = s; p < s + slen; p++) {
+		if (*p == '_')
+			*p = '/';
+		else
+			*p = tolower((unsigned char)*p);
+	}
+	printf("    $(wildcard include/config/%s.h) \\\n", s);
+}
+
+void parse_config_file(char *map, size_t len)
+{
+	int *end = (int *) (map + len);
+	/* start at +1, so that p can never be < map */
+	int *m   = (int *) map + 1;
+	char *p, *q;
+
+	for (; m < end; m++) {
+		if (*m == INT_CONF) { p = (char *) m  ; goto conf; }
+		if (*m == INT_ONFI) { p = (char *) m-1; goto conf; }
+		if (*m == INT_NFIG) { p = (char *) m-2; goto conf; }
+		if (*m == INT_FIG_) { p = (char *) m-3; goto conf; }
+		continue;
+	conf:
+		if (p > map + len - 7)
+			continue;
+		if (memcmp(p, "CONFIG_", 7))
+			continue;
+		for (q = p + 7; q < map + len; q++) {
+			if (!(isalnum(*q) || *q == '_'))
+				goto found;
+		}
+		continue;
+
+	found:
+		use_config(p+7, q-p-7);
+	}
+}
+
+/* test is s ends in sub */
+int strrcmp(char *s, char *sub)
+{
+	int slen = strlen(s);
+	int sublen = strlen(sub);
+
+	if (sublen > slen)
+		return 1;
+
+	return memcmp(s + slen - sublen, sub, sublen);
+}
+
+void do_config_file(char *filename)
+{
+	struct stat st;
+	int fd;
+	void *map;
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0) {
+		fprintf(stderr, "fixdep: ");
+		perror(filename);
+		exit(2);
+	}
+	fstat(fd, &st);
+	if (st.st_size == 0) {
+		close(fd);
+		return;
+	}
+	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	if ((long) map == -1) {
+		perror("fixdep: mmap");
+		close(fd);
+		return;
+	}
+
+	parse_config_file(map, st.st_size);
+
+	munmap(map, st.st_size);
+
+	close(fd);
+}
+
+void parse_dep_file(void *map, size_t len)
+{
+	char *m = map;
+	char *end = m + len;
+	char *p;
+	char s[PATH_MAX];
+
+	p = strchr(m, ':');
+	if (!p) {
+		fprintf(stderr, "fixdep: parse error\n");
+		exit(1);
+	}
+	memcpy(s, m, p-m); s[p-m] = 0;
+	printf("deps_%s := \\\n", target);
+	m = p+1;
+
+	clear_config();
+
+	while (m < end) {
+		while (m < end && (*m == ' ' || *m == '\\' || *m == '\n'))
+			m++;
+		p = m;
+		while (p < end && *p != ' ') p++;
+		if (p == end) {
+			do p--; while (!isalnum(*p));
+			p++;
+		}
+		memcpy(s, m, p-m); s[p-m] = 0;
+		if (strrcmp(s, "include/linux/autoconf.h") &&
+		    strrcmp(s, ".ver")) {
+			printf("  %s \\\n", s);
+			do_config_file(s);
+		}
+		m = p + 1;
+	}
+	printf("\n%s: $(deps_%s)\n\n", target, target);
+	printf("$(deps_%s):\n", target);
+}
+
+void print_deps(void)
+{
+	struct stat st;
+	int fd;
+	void *map;
+
+	fd = open(depfile, O_RDONLY);
+	if (fd < 0) {
+		fprintf(stderr, "fixdep: ");
+		perror(depfile);
+		exit(2);
+	}
+	fstat(fd, &st);
+	if (st.st_size == 0) {
+		fprintf(stderr,"fixdep: %s is empty\n",depfile);
+		close(fd);
+		return;
+	}
+	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	if ((long) map == -1) {
+		perror("fixdep: mmap");
+		close(fd);
+		return;
+	}
+
+	parse_dep_file(map, st.st_size);
+
+	munmap(map, st.st_size);
+
+	close(fd);
+}
+
+void traps(void)
+{
+	static char test[] __attribute__((aligned(sizeof(int)))) = "CONF";
+
+	if (*(int *)test != INT_CONF) {
+		fprintf(stderr, "fixdep: sizeof(int) != 4 or wrong endianess? %#x\n",
+			*(int *)test);
+		exit(2);
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	traps();
+
+	if (argc != 4)
+		usage();
+
+	depfile = argv[1];
+	target = argv[2];
+	cmdline = argv[3];
+
+	print_cmdline();
+	print_deps();
+
+	return 0;
+}
--- diff/scripts/basic/split-include.c	1970-01-01 00:00:00.000000000 +0000
+++ source/scripts/basic/split-include.c	2004-03-16 09:37:58.476650368 +0000
@@ -0,0 +1,226 @@
+/*
+ * split-include.c
+ *
+ * Copyright abandoned, Michael Chastain, <mailto:mec@shout.net>.
+ * This is a C version of syncdep.pl by Werner Almesberger.
+ *
+ * This program takes autoconf.h as input and outputs a directory full
+ * of one-line include files, merging onto the old values.
+ *
+ * Think of the configuration options as key-value pairs.  Then there
+ * are five cases:
+ *
+ *    key      old value   new value   action
+ *
+ *    KEY-1    VALUE-1     VALUE-1     leave file alone
+ *    KEY-2    VALUE-2A    VALUE-2B    write VALUE-2B into file
+ *    KEY-3    -           VALUE-3     write VALUE-3  into file
+ *    KEY-4    VALUE-4     -           write an empty file
+ *    KEY-5    (empty)     -           leave old empty file alone
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define ERROR_EXIT(strExit)						\
+    {									\
+	const int errnoSave = errno;					\
+	fprintf(stderr, "%s: ", str_my_name);				\
+	errno = errnoSave;						\
+	perror((strExit));						\
+	exit(1);							\
+    }
+
+
+
+int main(int argc, const char * argv [])
+{
+    const char * str_my_name;
+    const char * str_file_autoconf;
+    const char * str_dir_config;
+
+    FILE * fp_config;
+    FILE * fp_target;
+    FILE * fp_find;
+
+    int buffer_size;
+
+    char * line;
+    char * old_line;
+    char * list_target;
+    char * ptarget;
+
+    struct stat stat_buf;
+
+    /* Check arg count. */
+    if (argc != 3)
+    {
+	fprintf(stderr, "%s: wrong number of arguments.\n", argv[0]);
+	exit(1);
+    }
+
+    str_my_name       = argv[0];
+    str_file_autoconf = argv[1];
+    str_dir_config    = argv[2];
+
+    /* Find a buffer size. */
+    if (stat(str_file_autoconf, &stat_buf) != 0)
+	ERROR_EXIT(str_file_autoconf);
+    buffer_size = 2 * stat_buf.st_size + 4096;
+
+    /* Allocate buffers. */
+    if ( (line        = malloc(buffer_size)) == NULL
+    ||   (old_line    = malloc(buffer_size)) == NULL
+    ||   (list_target = malloc(buffer_size)) == NULL )
+	ERROR_EXIT(str_file_autoconf);
+
+    /* Open autoconfig file. */
+    if ((fp_config = fopen(str_file_autoconf, "r")) == NULL)
+	ERROR_EXIT(str_file_autoconf);
+
+    /* Make output directory if needed. */
+    if (stat(str_dir_config, &stat_buf) != 0)
+    {
+	if (mkdir(str_dir_config, 0755) != 0)
+	    ERROR_EXIT(str_dir_config);
+    }
+
+    /* Change to output directory. */
+    if (chdir(str_dir_config) != 0)
+	ERROR_EXIT(str_dir_config);
+
+    /* Put initial separator into target list. */
+    ptarget = list_target;
+    *ptarget++ = '\n';
+
+    /* Read config lines. */
+    while (fgets(line, buffer_size, fp_config))
+    {
+	const char * str_config;
+	int is_same;
+	int itarget;
+
+	if (line[0] != '#')
+	    continue;
+	if ((str_config = strstr(line, "CONFIG_")) == NULL)
+	    continue;
+
+	/* Make the output file name. */
+	str_config += sizeof("CONFIG_") - 1;
+	for (itarget = 0; !isspace(str_config[itarget]); itarget++)
+	{
+	    int c = (unsigned char) str_config[itarget];
+	    if (isupper(c)) c = tolower(c);
+	    if (c == '_')   c = '/';
+	    ptarget[itarget] = c;
+	}
+	ptarget[itarget++] = '.';
+	ptarget[itarget++] = 'h';
+	ptarget[itarget++] = '\0';
+
+	/* Check for existing file. */
+	is_same = 0;
+	if ((fp_target = fopen(ptarget, "r")) != NULL)
+	{
+	    fgets(old_line, buffer_size, fp_target);
+	    if (fclose(fp_target) != 0)
+		ERROR_EXIT(ptarget);
+	    if (!strcmp(line, old_line))
+		is_same = 1;
+	}
+
+	if (!is_same)
+	{
+	    /* Auto-create directories. */
+	    int islash;
+	    for (islash = 0; islash < itarget; islash++)
+	    {
+		if (ptarget[islash] == '/')
+		{
+		    ptarget[islash] = '\0';
+		    if (stat(ptarget, &stat_buf) != 0
+		    &&  mkdir(ptarget, 0755)     != 0)
+			ERROR_EXIT( ptarget );
+		    ptarget[islash] = '/';
+		}
+	    }
+
+	    /* Write the file. */
+	    if ((fp_target = fopen(ptarget, "w" )) == NULL)
+		ERROR_EXIT(ptarget);
+	    fputs(line, fp_target);
+	    if (ferror(fp_target) || fclose(fp_target) != 0)
+		ERROR_EXIT(ptarget);
+	}
+
+	/* Update target list */
+	ptarget += itarget;
+	*(ptarget-1) = '\n';
+    }
+
+    /*
+     * Close autoconfig file.
+     * Terminate the target list.
+     */
+    if (fclose(fp_config) != 0)
+	ERROR_EXIT(str_file_autoconf);
+    *ptarget = '\0';
+
+    /*
+     * Fix up existing files which have no new value.
+     * This is Case 4 and Case 5.
+     *
+     * I re-read the tree and filter it against list_target.
+     * This is crude.  But it avoids data copies.  Also, list_target
+     * is compact and contiguous, so it easily fits into cache.
+     *
+     * Notice that list_target contains strings separated by \n,
+     * with a \n before the first string and after the last.
+     * fgets gives the incoming names a terminating \n.
+     * So by having an initial \n, strstr will find exact matches.
+     */
+
+    fp_find = popen("find * -type f -name \"*.h\" -print", "r");
+    if (fp_find == 0)
+	ERROR_EXIT( "find" );
+
+    line[0] = '\n';
+    while (fgets(line+1, buffer_size, fp_find))
+    {
+	if (strstr(list_target, line) == NULL)
+	{
+	    /*
+	     * This is an old file with no CONFIG_* flag in autoconf.h.
+	     */
+
+	    /* First strip the \n. */
+	    line[strlen(line)-1] = '\0';
+
+	    /* Grab size. */
+	    if (stat(line+1, &stat_buf) != 0)
+		ERROR_EXIT(line);
+
+	    /* If file is not empty, make it empty and give it a fresh date. */
+	    if (stat_buf.st_size != 0)
+	    {
+		if ((fp_target = fopen(line+1, "w")) == NULL)
+		    ERROR_EXIT(line);
+		if (fclose(fp_target) != 0)
+		    ERROR_EXIT(line);
+	    }
+	}
+    }
+
+    if (pclose(fp_find) != 0)
+	ERROR_EXIT("find");
+
+    return 0;
+}
--- diff/security/selinux/include/conditional.h	1970-01-01 00:00:00.000000000 +0000
+++ source/security/selinux/include/conditional.h	2004-03-16 09:37:58.476650368 +0000
@@ -0,0 +1,22 @@
+/*
+ * Interface to booleans in the security server. This is exported
+ * for the selinuxfs.
+ *
+ * Author: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ *	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, version 2.
+ */
+
+#ifndef _SELINUX_CONDITIONAL_H_
+#define _SELINUX_CONDITIONAL_H_
+
+int security_get_bools(int *len, char ***names, int **values);
+
+int security_set_bools(int len, int *values);
+
+int security_get_bool_value(int bool);
+
+#endif
--- diff/security/selinux/ss/conditional.c	1970-01-01 00:00:00.000000000 +0000
+++ source/security/selinux/ss/conditional.c	2004-03-16 09:37:58.478650064 +0000
@@ -0,0 +1,487 @@
+/* Authors: Karl MacMillan <kmacmillan@tresys.com>
+ *          Frank Mayer <mayerf@tresys.com>
+ *
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ *	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, version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <asm/semaphore.h>
+#include <linux/slab.h>
+
+#include "security.h"
+#include "conditional.h"
+
+/*
+ * cond_evaluate_expr evaluates a conditional expr
+ * in reverse polish notation. It returns true (1), false (0),
+ * or undefined (-1). Undefined occurs when the expression
+ * exceeds the stack depth of COND_EXPR_MAXDEPTH.
+ */
+static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr)
+{
+
+	struct cond_expr *cur;
+	int s[COND_EXPR_MAXDEPTH];
+	int sp = -1;
+
+	for (cur = expr; cur != NULL; cur = cur->next) {
+		switch (cur->expr_type) {
+		case COND_BOOL:
+			if (sp == (COND_EXPR_MAXDEPTH - 1))
+				return -1;
+			sp++;
+			s[sp] = p->bool_val_to_struct[cur->bool - 1]->state;
+			break;
+		case COND_NOT:
+			if (sp < 0)
+				return -1;
+			s[sp] = !s[sp];
+			break;
+		case COND_OR:
+			if (sp < 1)
+				return -1;
+			sp--;
+			s[sp] |= s[sp + 1];
+			break;
+		case COND_AND:
+			if (sp < 1)
+				return -1;
+			sp--;
+			s[sp] &= s[sp + 1];
+			break;
+		case COND_XOR:
+			if (sp < 1)
+				return -1;
+			sp--;
+			s[sp] ^= s[sp + 1];
+			break;
+		case COND_EQ:
+			if (sp < 1)
+				return -1;
+			sp--;
+			s[sp] = (s[sp] == s[sp + 1]);
+			break;
+		case COND_NEQ:
+			if (sp < 1)
+				return -1;
+			sp--;
+			s[sp] = (s[sp] != s[sp + 1]);
+			break;
+		default:
+			return -1;
+		}
+	}
+	return s[0];
+}
+
+/*
+ * evaluate_cond_node evaluates the conditional stored in
+ * a struct cond_node and if the result is different than the
+ * current state of the node it sets the rules in the true/false
+ * list appropriately. If the result of the expression is undefined
+ * all of the rules are disabled for safety.
+ */
+int evaluate_cond_node(struct policydb *p, struct cond_node *node)
+{
+	int new_state;
+	struct cond_av_list* cur;
+
+	new_state = cond_evaluate_expr(p, node->expr);
+	if (new_state != node->cur_state) {
+		node->cur_state = new_state;
+		if (new_state == -1)
+			printk(KERN_ERR "security: expression result was undefined - disabling all rules.\n");
+		/* turn the rules on or off */
+		for (cur = node->true_list; cur != NULL; cur = cur->next) {
+			if (new_state <= 0) {
+				cur->node->datum.specified &= ~AVTAB_ENABLED;
+			} else {
+				cur->node->datum.specified |= AVTAB_ENABLED;
+			}
+		}
+
+		for (cur = node->false_list; cur != NULL; cur = cur->next) {
+			/* -1 or 1 */
+			if (new_state) {
+				cur->node->datum.specified &= ~AVTAB_ENABLED;
+			} else {
+				cur->node->datum.specified |= AVTAB_ENABLED;
+			}
+		}
+	}
+	return 0;
+}
+
+int cond_policydb_init(struct policydb *p)
+{
+	p->bool_val_to_struct = NULL;
+	p->cond_list = NULL;
+	if (avtab_init(&p->te_cond_avtab))
+		return -1;
+
+	return 0;
+}
+
+static void cond_av_list_destroy(struct cond_av_list *list)
+{
+	struct cond_av_list *cur, *next;
+	for (cur = list; cur != NULL; cur = next) {
+		next = cur->next;
+		/* the avtab_ptr_t node is destroy by the avtab */
+		kfree(cur);
+	}
+}
+
+static void cond_node_destroy(struct cond_node *node)
+{
+	struct cond_expr *cur_expr, *next_expr;
+
+	for (cur_expr = node->expr; cur_expr != NULL; cur_expr = next_expr) {
+		next_expr = cur_expr->next;
+		kfree(cur_expr);
+	}
+	cond_av_list_destroy(node->true_list);
+	cond_av_list_destroy(node->false_list);
+	kfree(node);
+}
+
+static void cond_list_destroy(struct cond_node *list)
+{
+	struct cond_node *next, *cur;
+
+	if (list == NULL)
+		return;
+
+	for (cur = list; cur != NULL; cur = next) {
+		next = cur->next;
+		cond_node_destroy(cur);
+	}
+}
+
+void cond_policydb_destroy(struct policydb *p)
+{
+	if (p->bool_val_to_struct != NULL)
+		kfree(p->bool_val_to_struct);
+	avtab_destroy(&p->te_cond_avtab);
+	cond_list_destroy(p->cond_list);
+}
+
+int cond_init_bool_indexes(struct policydb *p)
+{
+	if (p->bool_val_to_struct)
+		kfree(p->bool_val_to_struct);
+	p->bool_val_to_struct = (struct cond_bool_datum**)
+		kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum*), GFP_KERNEL);
+	if (!p->bool_val_to_struct)
+		return -1;
+	return 0;
+}
+
+int cond_destroy_bool(void *key, void *datum, void *p)
+{
+	if (key)
+		kfree(key);
+	kfree(datum);
+	return 0;
+}
+
+int cond_index_bool(void *key, void *datum, void *datap)
+{
+	struct policydb *p;
+	struct cond_bool_datum *booldatum;
+
+	booldatum = datum;
+	p = datap;
+
+	if (!booldatum->value || booldatum->value > p->p_bools.nprim)
+		return -EINVAL;
+
+	p->p_bool_val_to_name[booldatum->value - 1] = key;
+	p->bool_val_to_struct[booldatum->value -1] = booldatum;
+
+	return 0;
+}
+
+int bool_isvalid(struct cond_bool_datum *b)
+{
+	if (!(b->state == 0 || b->state == 1))
+		return 0;
+	return 1;
+}
+
+int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp)
+{
+	char *key = 0;
+	struct cond_bool_datum *booldatum;
+	__u32 *buf, len;
+
+	booldatum = kmalloc(sizeof(struct cond_bool_datum), GFP_KERNEL);
+	if (!booldatum)
+		return -1;
+	memset(booldatum, 0, sizeof(struct cond_bool_datum));
+
+	buf = next_entry(fp, sizeof(__u32) * 3);
+	if (!buf)
+		goto err;
+
+	booldatum->value = le32_to_cpu(buf[0]);
+	booldatum->state = le32_to_cpu(buf[1]);
+
+	if (!bool_isvalid(booldatum))
+		goto err;
+
+	len = le32_to_cpu(buf[2]);
+
+	buf = next_entry(fp, len);
+	if (!buf)
+		goto err;
+	key = kmalloc(len + 1, GFP_KERNEL);
+	if (!key)
+		goto err;
+	memcpy(key, buf, len);
+	key[len] = 0;
+	if (hashtab_insert(h, key, booldatum))
+		goto err;
+
+	return 0;
+err:
+	cond_destroy_bool(key, booldatum, 0);
+	return -1;
+}
+
+static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list,
+			     struct cond_av_list *other)
+{
+	struct cond_av_list *list, *last = NULL, *cur;
+	struct avtab_key key;
+	struct avtab_datum datum;
+	struct avtab_node *node_ptr;
+	int len, i;
+	__u32 *buf;
+	__u8 found;
+
+	*ret_list = NULL;
+
+	len = 0;
+	buf = next_entry(fp, sizeof(__u32));
+	if (!buf)
+		return -1;
+
+	len = le32_to_cpu(buf[0]);
+	if (len == 0) {
+		return 0;
+	}
+
+	for (i = 0; i < len; i++) {
+		if (avtab_read_item(fp, &datum, &key))
+			goto err;
+
+		/*
+		 * For type rules we have to make certain there aren't any
+		 * conflicting rules by searching the te_avtab and the
+		 * cond_te_avtab.
+		 */
+		if (datum.specified & AVTAB_TYPE) {
+			if (avtab_search(&p->te_avtab, &key, AVTAB_TYPE)) {
+				printk("security: type rule already exists outside of a conditional.");
+				goto err;
+			}
+			/*
+			 * If we are reading the false list other will be a pointer to
+			 * the true list. We can have duplicate entries if there is only
+			 * 1 other entry and it is in our true list.
+			 *
+			 * If we are reading the true list (other == NULL) there shouldn't
+			 * be any other entries.
+			 */
+			if (other) {
+				node_ptr = avtab_search_node(&p->te_cond_avtab, &key, AVTAB_TYPE);
+				if (node_ptr) {
+					if (avtab_search_node_next(node_ptr, AVTAB_TYPE)) {
+						printk("security: too many conflicting type rules.");
+						goto err;
+					}
+					found = 0;
+					for (cur = other; cur != NULL; cur = cur->next) {
+						if (cur->node == node_ptr) {
+							found = 1;
+							break;
+						}
+					}
+					if (!found) {
+						printk("security: conflicting type rules.");
+						goto err;
+					}
+				}
+			} else {
+				if (avtab_search(&p->te_cond_avtab, &key, AVTAB_TYPE)) {
+					printk("security: conflicting type rules when adding type rule for true.");
+					goto err;
+				}
+			}
+		}
+		node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, &key, &datum);
+		if (!node_ptr) {
+			printk("security: could not insert rule.");
+			goto err;
+		}
+
+		list = kmalloc(sizeof(struct cond_av_list), GFP_KERNEL);
+		if (!list)
+			goto err;
+		memset(list, 0, sizeof(struct cond_av_list));
+
+		list->node = node_ptr;
+		if (i == 0)
+			*ret_list = list;
+		else
+			last->next = list;
+		last = list;
+
+	}
+
+	return 0;
+err:
+	cond_av_list_destroy(*ret_list);
+	*ret_list = NULL;
+	return -1;
+}
+
+static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
+{
+	if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
+		printk("security: conditional expressions uses unknown operator.\n");
+		return 0;
+	}
+
+	if (expr->bool > p->p_bools.nprim) {
+		printk("security: conditional expressions uses unknown bool.\n");
+		return 0;
+	}
+	return 1;
+}
+
+static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
+{
+	__u32 *buf;
+	int len, i;
+	struct cond_expr *expr = NULL, *last = NULL;
+
+	buf = next_entry(fp, sizeof(__u32));
+	if (!buf)
+		return -1;
+
+	node->cur_state = le32_to_cpu(buf[0]);
+
+	len = 0;
+	buf = next_entry(fp, sizeof(__u32));
+	if (!buf)
+		return -1;
+
+	/* expr */
+	len = le32_to_cpu(buf[0]);
+
+	for (i = 0; i < len; i++ ) {
+		buf = next_entry(fp, sizeof(__u32) * 2);
+		if (!buf)
+			goto err;
+
+		expr = kmalloc(sizeof(struct cond_expr), GFP_KERNEL);
+		if (!expr) {
+			goto err;
+		}
+		memset(expr, 0, sizeof(struct cond_expr));
+
+		expr->expr_type = le32_to_cpu(buf[0]);
+		expr->bool = le32_to_cpu(buf[1]);
+
+		if (!expr_isvalid(p, expr))
+			goto err;
+
+		if (i == 0) {
+			node->expr = expr;
+		} else {
+			last->next = expr;
+		}
+		last = expr;
+	}
+
+	if (cond_read_av_list(p, fp, &node->true_list, NULL) != 0)
+		goto err;
+	if (cond_read_av_list(p, fp, &node->false_list, node->true_list) != 0)
+		goto err;
+	return 0;
+err:
+	cond_node_destroy(node);
+	return -1;
+}
+
+int cond_read_list(struct policydb *p, void *fp)
+{
+	struct cond_node *node, *last = NULL;
+	__u32 *buf;
+	int i, len;
+
+	buf = next_entry(fp, sizeof(__u32));
+	if (!buf)
+		return -1;
+
+	len = le32_to_cpu(buf[0]);
+
+	for (i = 0; i < len; i++) {
+		node = kmalloc(sizeof(struct cond_node), GFP_KERNEL);
+		if (!node)
+			goto err;
+		memset(node, 0, sizeof(struct cond_node));
+
+		if (cond_read_node(p, node, fp) != 0)
+			goto err;
+
+		if (i == 0) {
+			p->cond_list = node;
+		} else {
+			last->next = node;
+		}
+		last = node;
+	}
+	return 0;
+err:
+	cond_list_destroy(p->cond_list);
+	return -1;
+}
+
+/* Determine whether additional permissions are granted by the conditional
+ * av table, and if so, add them to the result
+ */
+void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd)
+{
+	struct avtab_node *node;
+
+	if(!ctab || !key || !avd)
+		return;
+
+	for(node = avtab_search_node(ctab, key, AVTAB_AV); node != NULL;
+				node = avtab_search_node_next(node, AVTAB_AV)) {
+		if ( (__u32) (AVTAB_ALLOWED|AVTAB_ENABLED) ==
+		     (node->datum.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
+			avd->allowed |= avtab_allowed(&node->datum);
+		if ( (__u32) (AVTAB_AUDITDENY|AVTAB_ENABLED) ==
+		     (node->datum.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)))
+			/* Since a '0' in an auditdeny mask represents a
+			 * permission we do NOT want to audit (dontaudit), we use
+			 * the '&' operand to ensure that all '0's in the mask
+			 * are retained (much unlike the allow and auditallow cases).
+			 */
+			avd->auditdeny &= avtab_auditdeny(&node->datum);
+		if ( (__u32) (AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
+		     (node->datum.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
+			avd->auditallow |= avtab_auditallow(&node->datum);
+	}
+	return;
+}
--- diff/security/selinux/ss/conditional.h	1970-01-01 00:00:00.000000000 +0000
+++ source/security/selinux/ss/conditional.h	2004-03-16 09:37:58.479649912 +0000
@@ -0,0 +1,77 @@
+/* Authors: Karl MacMillan <kmacmillan@tresys.com>
+ *          Frank Mayer <mayerf@tresys.com>
+ *
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ *	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, version 2.
+ */
+
+#ifndef _CONDITIONAL_H_
+#define _CONDITIONAL_H_
+
+#include "avtab.h"
+#include "symtab.h"
+#include "policydb.h"
+
+#define COND_EXPR_MAXDEPTH 10
+
+/*
+ * A conditional expression is a list of operators and operands
+ * in reverse polish notation.
+ */
+struct cond_expr {
+#define COND_BOOL	1 /* plain bool */
+#define COND_NOT	2 /* !bool */
+#define COND_OR		3 /* bool || bool */
+#define COND_AND	4 /* bool && bool */
+#define COND_XOR	5 /* bool ^ bool */
+#define COND_EQ		6 /* bool == bool */
+#define COND_NEQ	7 /* bool != bool */
+#define COND_LAST	8
+	__u32 expr_type;
+	__u32 bool;
+	struct cond_expr *next;
+};
+
+/*
+ * Each cond_node contains a list of rules to be enabled/disabled
+ * depending on the current value of the conditional expression. This
+ * struct is for that list.
+ */
+struct cond_av_list {
+	struct avtab_node *node;
+	struct cond_av_list *next;
+};
+
+/*
+ * A cond node represents a conditional block in a policy. It
+ * contains a conditional expression, the current state of the expression,
+ * two lists of rules to enable/disable depending on the value of the
+ * expression (the true list corresponds to if and the false list corresponds
+ * to else)..
+ */
+struct cond_node {
+	int cur_state;
+	struct cond_expr *expr;
+	struct cond_av_list *true_list;
+	struct cond_av_list *false_list;
+	struct cond_node *next;
+};
+
+int cond_policydb_init(struct policydb* p);
+void cond_policydb_destroy(struct policydb* p);
+
+int cond_init_bool_indexes(struct policydb* p);
+int cond_destroy_bool(void *key, void *datum, void *p);
+
+int cond_index_bool(void *key, void *datum, void *datap);
+
+int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp);
+int cond_read_list(struct policydb *p, void *fp);
+
+void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd);
+
+int evaluate_cond_node(struct policydb *p, struct cond_node *node);
+
+#endif /* _CONDITIONAL_H_ */
--- diff/sound/i2c/other/ak4117.c	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/i2c/other/ak4117.c	2004-03-16 09:37:58.481649608 +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/atiixp.c	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/atiixp.c	2004-03-16 09:37:58.486648848 +0000
@@ -0,0 +1,1569 @@
+/*
+ *   ALSA driver for ATI IXP 150/200/250 AC97 controllers
+ *
+ *	Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   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 <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <sound/ac97_codec.h>
+#define SNDRV_GET_ID
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
+MODULE_DESCRIPTION("ATI IXP AC97 controller");
+MODULE_LICENSE("GPL");
+MODULE_CLASSES("{sound}");
+MODULE_DEVICES("{{ATI,IXP150/200/250}}");
+
+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 */
+static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000};
+static int spdif_aclink[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+
+MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(index, "Index value for ATI IXP controller.");
+MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
+MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+MODULE_PARM_DESC(id, "ID string for ATI IXP controller.");
+MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
+MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(enable, "Enable audio part of ATI IXP controller.");
+MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
+MODULE_PARM(ac97_clock, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz).");
+MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:48000");
+MODULE_PARM(spdif_aclink, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link.");
+MODULE_PARM_SYNTAX(spdif_aclink, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC);
+
+
+/*
+ */
+
+#define ATI_REG_ISR			0x00	/* interrupt source */
+#define  ATI_REG_ISR_IN_XRUN		(1U<<0)
+#define  ATI_REG_ISR_IN_STATUS		(1U<<1)
+#define  ATI_REG_ISR_OUT_XRUN		(1U<<2)
+#define  ATI_REG_ISR_OUT_STATUS		(1U<<3)
+#define  ATI_REG_ISR_SPDF_XRUN		(1U<<4)
+#define  ATI_REG_ISR_SPDF_STATUS	(1U<<5)
+#define  ATI_REG_ISR_PHYS_INTR		(1U<<8)
+#define  ATI_REG_ISR_PHYS_MISMATCH	(1U<<9)
+#define  ATI_REG_ISR_CODEC0_NOT_READY	(1U<<10)
+#define  ATI_REG_ISR_CODEC1_NOT_READY	(1U<<11)
+#define  ATI_REG_ISR_CODEC2_NOT_READY	(1U<<12)
+#define  ATI_REG_ISR_NEW_FRAME		(1U<<13)
+
+#define ATI_REG_IER			0x04	/* interrupt enable */
+#define  ATI_REG_IER_IN_XRUN_EN		(1U<<0)
+#define  ATI_REG_IER_IO_STATUS_EN	(1U<<1)
+#define  ATI_REG_IER_OUT_XRUN_EN	(1U<<2)
+#define  ATI_REG_IER_OUT_XRUN_COND	(1U<<3)
+#define  ATI_REG_IER_SPDF_XRUN_EN	(1U<<4)
+#define  ATI_REG_IER_SPDF_STATUS_EN	(1U<<5)
+#define  ATI_REG_IER_PHYS_INTR_EN	(1U<<8)
+#define  ATI_REG_IER_PHYS_MISMATCH_EN	(1U<<9)
+#define  ATI_REG_IER_CODEC0_INTR_EN	(1U<<10)
+#define  ATI_REG_IER_CODEC1_INTR_EN	(1U<<11)
+#define  ATI_REG_IER_CODEC2_INTR_EN	(1U<<12)
+#define  ATI_REG_IER_NEW_FRAME_EN	(1U<<13)	/* (RO */
+#define  ATI_REG_IER_SET_BUS_BUSY	(1U<<14)	/* (WO) audio is running */
+
+#define ATI_REG_CMD			0x08	/* command */
+#define  ATI_REG_CMD_POWERDOWN		(1U<<0)
+#define  ATI_REG_CMD_RECEIVE_EN		(1U<<1)
+#define  ATI_REG_CMD_SEND_EN		(1U<<2)
+#define  ATI_REG_CMD_STATUS_MEM		(1U<<3)
+#define  ATI_REG_CMD_SPDF_OUT_EN	(1U<<4)
+#define  ATI_REG_CMD_SPDF_STATUS_MEM	(1U<<5)
+#define  ATI_REG_CMD_SPDF_THRESHOLD	(3U<<6)
+#define  ATI_REG_CMD_SPDF_THRESHOLD_SHIFT	6
+#define  ATI_REG_CMD_IN_DMA_EN		(1U<<8)
+#define  ATI_REG_CMD_OUT_DMA_EN		(1U<<9)
+#define  ATI_REG_CMD_SPDF_DMA_EN	(1U<<10)
+#define  ATI_REG_CMD_SPDF_OUT_STOPPED	(1U<<11)
+#define  ATI_REG_CMD_SPDF_CONFIG_MASK	(7U<<12)
+#define   ATI_REG_CMD_SPDF_CONFIG_34	(1U<<12)
+#define   ATI_REG_CMD_SPDF_CONFIG_78	(2U<<12)
+#define   ATI_REG_CMD_SPDF_CONFIG_69	(3U<<12)
+#define   ATI_REG_CMD_SPDF_CONFIG_01	(4U<<12)
+#define  ATI_REG_CMD_INTERLEAVE_SPDF	(1U<<16)
+#define  ATI_REG_CMD_AUDIO_PRESENT	(1U<<20)
+#define  ATI_REG_CMD_INTERLEAVE_IN	(1U<<21)
+#define  ATI_REG_CMD_INTERLEAVE_OUT	(1U<<22)
+#define  ATI_REG_CMD_LOOPBACK_EN	(1U<<23)
+#define  ATI_REG_CMD_PACKED_DIS		(1U<<24)
+#define  ATI_REG_CMD_BURST_EN		(1U<<25)
+#define  ATI_REG_CMD_PANIC_EN		(1U<<26)
+#define  ATI_REG_CMD_MODEM_PRESENT	(1U<<27)
+#define  ATI_REG_CMD_ACLINK_ACTIVE	(1U<<28)
+#define  ATI_REG_CMD_AC_SOFT_RESET	(1U<<29)
+#define  ATI_REG_CMD_AC_SYNC		(1U<<30)
+#define  ATI_REG_CMD_AC_RESET		(1U<<31)
+
+#define ATI_REG_PHYS_OUT_ADDR		0x0c
+#define  ATI_REG_PHYS_OUT_CODEC_MASK	(3U<<0)
+#define  ATI_REG_PHYS_OUT_RW		(1U<<2)
+#define  ATI_REG_PHYS_OUT_ADDR_EN	(1U<<8)
+#define  ATI_REG_PHYS_OUT_ADDR_SHIFT	9
+#define  ATI_REG_PHYS_OUT_DATA_SHIFT	16
+
+#define ATI_REG_PHYS_IN_ADDR		0x10
+#define  ATI_REG_PHYS_IN_READ_FLAG	(1U<<8)
+#define  ATI_REG_PHYS_IN_ADDR_SHIFT	9
+#define  ATI_REG_PHYS_IN_DATA_SHIFT	16
+
+#define ATI_REG_SLOTREQ			0x14
+
+#define ATI_REG_COUNTER			0x18
+#define  ATI_REG_COUNTER_SLOT		(3U<<0)	/* slot # */
+#define  ATI_REG_COUNTER_BITCLOCK	(31U<<8)
+
+#define ATI_REG_IN_FIFO_THRESHOLD	0x1c
+
+#define ATI_REG_IN_DMA_LINKPTR		0x20
+#define ATI_REG_IN_DMA_DT_START		0x24	/* RO */
+#define ATI_REG_IN_DMA_DT_NEXT		0x28	/* RO */
+#define ATI_REG_IN_DMA_DT_CUR		0x2c	/* RO */
+#define ATI_REG_IN_DMA_DT_SIZE		0x30
+
+#define ATI_REG_OUT_DMA_SLOT		0x34
+#define  ATI_REG_OUT_DMA_SLOT_BIT(x)	(1U << ((x) - 3))
+#define  ATI_REG_OUT_DMA_SLOT_MASK	0x1ff
+#define  ATI_REG_OUT_DMA_THRESHOLD_MASK	0xf800
+#define  ATI_REG_OUT_DMA_THRESHOLD_SHIFT	11
+
+#define ATI_REG_OUT_DMA_LINKPTR		0x38
+#define ATI_REG_OUT_DMA_DT_START	0x3c	/* RO */
+#define ATI_REG_OUT_DMA_DT_NEXT		0x40	/* RO */
+#define ATI_REG_OUT_DMA_DT_CUR		0x44	/* RO */
+#define ATI_REG_OUT_DMA_DT_SIZE		0x48
+
+#define ATI_REG_SPDF_CMD		0x4c
+#define  ATI_REG_SPDF_CMD_LFSR		(1U<<4)
+#define  ATI_REG_SPDF_CMD_SINGLE_CH	(1U<<5)
+#define  ATI_REG_SPDF_CMD_LFSR_ACC	(0xff<<8)	/* RO */
+
+#define ATI_REG_SPDF_DMA_LINKPTR	0x50
+#define ATI_REG_SPDF_DMA_DT_START	0x54	/* RO */
+#define ATI_REG_SPDF_DMA_DT_NEXT	0x58	/* RO */
+#define ATI_REG_SPDF_DMA_DT_CUR		0x5c	/* RO */
+#define ATI_REG_SPDF_DMA_DT_SIZE	0x60
+
+#define ATI_REG_MODEM_MIRROR		0x7c
+#define ATI_REG_AUDIO_MIRROR		0x80
+
+#define ATI_REG_6CH_REORDER		0x84	/* reorder slots for 6ch */
+#define  ATI_REG_6CH_REORDER_EN		(1U<<0)	/* 3,4,7,8,6,9 -> 3,4,6,9,7,8 */
+
+#define ATI_REG_FIFO_FLUSH		0x88
+#define  ATI_REG_FIFO_OUT_FLUSH		(1U<<0)
+#define  ATI_REG_FIFO_IN_FLUSH		(1U<<1)
+
+/* LINKPTR */
+#define  ATI_REG_LINKPTR_EN		(1U<<0)
+
+/* [INT|OUT|SPDIF]_DMA_DT_SIZE */
+#define  ATI_REG_DMA_DT_SIZE		(0xffffU<<0)
+#define  ATI_REG_DMA_FIFO_USED		(0x1fU<<16)
+#define  ATI_REG_DMA_FIFO_FREE		(0x1fU<<21)
+#define  ATI_REG_DMA_STATE		(7U<<26)
+
+
+#define ATI_MEM_REGION		256	/* i/o memory size */
+#define ATI_MAX_DESCRIPTORS	256	/* max number of descriptor packets */
+
+
+/*
+ */
+
+typedef struct snd_atiixp atiixp_t;
+typedef struct snd_atiixp_dma atiixp_dma_t;
+typedef struct snd_atiixp_dma_ops atiixp_dma_ops_t;
+#define chip_t atiixp_t
+
+
+/*
+ * DMA packate descriptor
+ */
+
+typedef struct atiixp_dma_desc {
+	u32 addr;	/* DMA buffer address */
+	u16 status;	/* status bits */
+	u16 size;	/* size of the packet in dwords */
+	u32 next;	/* address of the next packet descriptor */
+} atiixp_dma_desc_t;
+
+/*
+ * stream enum
+ */
+enum { ATI_DMA_PLAYBACK, ATI_DMA_CAPTURE, ATI_DMA_SPDIF };
+
+/*
+ * constants and callbacks for each DMA type
+ */
+struct snd_atiixp_dma_ops {
+	int type;			/* ATI_DMA_XXX */
+	unsigned int llp_offset;	/* LINKPTR offset */
+	void (*enable_dma)(atiixp_t *chip, int on);	/* called from open callback */
+	void (*enable_transfer)(atiixp_t *chip, int on); /* called from trigger (START/STOP) */
+	void (*flush_dma)(atiixp_t *chip);		/* called from trigger (STOP only) */
+};
+
+/*
+ * DMA stream
+ */
+struct snd_atiixp_dma {
+	const atiixp_dma_ops_t *ops;
+	struct snd_dma_device desc_dev;
+	struct snd_dma_buffer desc_buf;
+	snd_pcm_substream_t *substream;	/* assigned PCM substream */
+	unsigned int buf_addr, buf_bytes;	/* DMA buffer address, bytes */
+	unsigned int period_bytes, periods;
+	int running;
+	struct ac97_pcm *pcm;
+	int pcm_open_flag;
+};
+
+/*
+ * ATI IXP chip
+ */
+struct snd_atiixp {
+	snd_card_t *card;
+	struct pci_dev *pci;
+
+	struct resource *res;		/* memory i/o */
+	unsigned long addr;
+	unsigned long remap_addr;
+	int irq;
+	
+	ac97_bus_t *ac97_bus;
+	ac97_t *ac97[3];		/* IXP can have up to 3 codecs */
+
+	spinlock_t reg_lock;
+	spinlock_t ac97_lock;
+
+	atiixp_dma_t dmas[3];		/* playback, capture, spdif */
+
+	int max_channels;		/* max. channels for PCM out */
+
+	unsigned int codec_not_ready_bits;	/* for codec detection */
+
+	int spdif_over_aclink;		/* passed from the module option */
+};
+
+
+/*
+ */
+static struct pci_device_id snd_atiixp_ids[] = {
+	{ 0x1002, 0x4341, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+};
+
+MODULE_DEVICE_TABLE(pci, snd_atiixp_ids);
+
+
+/*
+ * lowlevel functions
+ */
+
+/*
+ * update the bits of the given register.
+ * return 1 if the bits changed.
+ */
+static int snd_atiixp_update_bits(atiixp_t *chip, unsigned int reg,
+				 unsigned int mask, unsigned int value)
+{
+	unsigned long addr = chip->remap_addr + reg;
+	unsigned int data, old_data;
+	old_data = data = readl(addr);
+	data &= ~mask;
+	data |= value;
+	if (old_data == data)
+		return 0;
+	writel(data, addr);
+	return 1;
+}
+
+/*
+ * macros for easy use
+ */
+#define atiixp_write(chip,reg,value) \
+	writel(value, chip->remap_addr + ATI_REG_##reg)
+#define atiixp_read(chip,reg) \
+	readl(chip->remap_addr + ATI_REG_##reg)
+#define atiixp_update(chip,reg,mask,val) \
+	snd_atiixp_update_bits(chip, ATI_REG_##reg, mask, val)
+
+/* delay for one tick */
+#define do_delay() do { \
+	set_current_state(TASK_UNINTERRUPTIBLE); \
+	schedule_timeout(1); \
+} while (0)
+
+
+/*
+ * handling DMA packets
+ *
+ * we allocate a linear buffer for the DMA, and split it to  each packet.
+ * in a future version, a scatter-gather buffer should be implemented.
+ */
+
+#define ATI_DESC_LIST_SIZE \
+	PAGE_ALIGN(ATI_MAX_DESCRIPTORS * sizeof(atiixp_dma_desc_t))
+
+/*
+ * build packets ring for the given buffer size.
+ *
+ * IXP handles the buffer descriptors, which are connected as a linked
+ * list.  although we can change the list dynamically, in this version,
+ * a static RING of buffer descriptors is used.
+ *
+ * the ring is built in this function, and is set up to the hardware. 
+ */
+static int atiixp_build_dma_packets(atiixp_t *chip, atiixp_dma_t *dma,
+				   snd_pcm_substream_t *substream,
+				   unsigned int periods,
+				   unsigned int period_bytes)
+{
+	unsigned int i;
+	u32 addr, desc_addr;
+	unsigned long flags;
+
+	if (periods > ATI_MAX_DESCRIPTORS)
+		return -ENOMEM;
+
+	if (dma->desc_buf.area == NULL) {
+		memset(&dma->desc_dev, 0, sizeof(dma->desc_dev));
+		dma->desc_dev.type = SNDRV_DMA_TYPE_DEV;
+		dma->desc_dev.dev = snd_dma_pci_data(chip->pci);
+		if (snd_dma_alloc_pages(&dma->desc_dev, ATI_DESC_LIST_SIZE, &dma->desc_buf) < 0)
+			return -ENOMEM;
+		dma->period_bytes = dma->periods = 0; /* clear */
+	}
+
+	if (dma->periods == dma->periods && dma->period_bytes == period_bytes)
+		return 0;
+
+	/* reset DMA before changing the descriptor table */
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	writel(0, chip->remap_addr + dma->ops->llp_offset);
+	dma->ops->enable_dma(chip, 0);
+	dma->ops->enable_dma(chip, 1);
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+	/* fill the entries */
+	addr = (u32)substream->runtime->dma_addr;
+	desc_addr = (u32)dma->desc_buf.addr;
+	for (i = 0; i < periods; i++) {
+		atiixp_dma_desc_t *desc = &((atiixp_dma_desc_t *)dma->desc_buf.area)[i];
+		desc->addr = cpu_to_le32(addr);
+		desc->status = 0;
+		desc->size = period_bytes >> 2; /* in dwords */
+		desc_addr += sizeof(atiixp_dma_desc_t);
+		if (i == periods - 1)
+			desc->next = cpu_to_le32((u32)dma->desc_buf.addr);
+		else
+			desc->next = cpu_to_le32(desc_addr);
+		addr += period_bytes;
+	}
+
+	writel(cpu_to_le32((u32)dma->desc_buf.addr | ATI_REG_LINKPTR_EN),
+	       chip->remap_addr + dma->ops->llp_offset);
+
+	dma->period_bytes = period_bytes;
+	dma->periods = periods;
+
+	return 0;
+}
+
+/*
+ * remove the ring buffer and release it if assigned
+ */
+static void atiixp_clear_dma_packets(atiixp_t *chip, atiixp_dma_t *dma, snd_pcm_substream_t *substream)
+{
+	if (dma->desc_buf.area) {
+		writel(0, chip->remap_addr + dma->ops->llp_offset);
+		snd_dma_free_pages(&dma->desc_dev, &dma->desc_buf);
+		dma->desc_buf.area = NULL;
+	}
+}
+
+/*
+ * AC97 interface
+ */
+static int snd_atiixp_acquire_codec(atiixp_t *chip)
+{
+	int timeout = 1000;
+
+	while (atiixp_read(chip, PHYS_OUT_ADDR) & ATI_REG_PHYS_OUT_ADDR_EN) {
+		if (! timeout--) {
+			snd_printk(KERN_WARNING "atiixp: codec acquire timeout\n");
+			return -EBUSY;
+		}
+		udelay(1);
+	}
+	return 0;
+}
+
+static unsigned short snd_atiixp_codec_read(atiixp_t *chip, unsigned short codec, unsigned short reg)
+{
+	unsigned int data;
+	int timeout;
+
+	if (snd_atiixp_acquire_codec(chip) < 0)
+		return 0xffff;
+	data = (reg << ATI_REG_PHYS_OUT_ADDR_SHIFT) |
+		ATI_REG_PHYS_OUT_ADDR_EN |
+		ATI_REG_PHYS_OUT_RW |
+		codec;
+	atiixp_write(chip, PHYS_OUT_ADDR, data);
+	if (snd_atiixp_acquire_codec(chip) < 0)
+		return 0xffff;
+	timeout = 1000;
+	do {
+		data = atiixp_read(chip, PHYS_IN_ADDR);
+		if (data & ATI_REG_PHYS_IN_READ_FLAG)
+			return data >> ATI_REG_PHYS_IN_DATA_SHIFT;
+		udelay(1);
+	} while (--timeout);
+	snd_printk(KERN_WARNING "atiixp: codec read timeout\n");
+	return 0xffff;
+}
+
+
+static void snd_atiixp_codec_write(atiixp_t *chip, unsigned short codec, unsigned short reg, unsigned short val)
+{
+	unsigned int data;
+    
+	if (snd_atiixp_acquire_codec(chip) < 0)
+		return;
+	data = ((unsigned int)val << ATI_REG_PHYS_OUT_DATA_SHIFT) |
+		((unsigned int)reg << ATI_REG_PHYS_OUT_ADDR_SHIFT) |
+		ATI_REG_PHYS_OUT_ADDR_EN | codec;
+	atiixp_write(chip, PHYS_OUT_ADDR, data);
+}
+
+
+static unsigned short snd_atiixp_ac97_read(ac97_t *ac97, unsigned short reg)
+{
+	atiixp_t *chip = snd_magic_cast(atiixp_t, ac97->private_data, return 0xffff);
+	unsigned short data;
+	spin_lock(&chip->ac97_lock);
+	data = snd_atiixp_codec_read(chip, ac97->num, reg);
+	spin_unlock(&chip->ac97_lock);
+	return data;
+    
+}
+
+static void snd_atiixp_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val)
+{
+	atiixp_t *chip = snd_magic_cast(atiixp_t, ac97->private_data, return);
+	spin_lock(&chip->ac97_lock);
+	snd_atiixp_codec_write(chip, ac97->num, reg, val);
+	spin_unlock(&chip->ac97_lock);
+}
+
+/*
+ * reset AC link
+ */
+static int snd_atiixp_aclink_reset(atiixp_t *chip)
+{
+	int timeout;
+
+	/* reset powerdoewn */
+	if (atiixp_update(chip, CMD, ATI_REG_CMD_POWERDOWN, 0))
+		udelay(10);
+
+	/* perform a software reset */
+	atiixp_update(chip, CMD, ATI_REG_CMD_AC_SOFT_RESET, ATI_REG_CMD_AC_SOFT_RESET);
+	atiixp_read(chip, CMD);
+	udelay(10);
+	atiixp_update(chip, CMD, ATI_REG_CMD_AC_SOFT_RESET, 0);
+    
+	timeout = 10;
+	while (! (atiixp_read(chip, CMD) & ATI_REG_CMD_ACLINK_ACTIVE)) {
+		/* do a hard reset */
+		atiixp_update(chip, CMD, ATI_REG_CMD_AC_SYNC|ATI_REG_CMD_AC_RESET,
+			      ATI_REG_CMD_AC_SYNC);
+		atiixp_read(chip, CMD);
+		do_delay();
+		atiixp_update(chip, CMD, ATI_REG_CMD_AC_RESET, ATI_REG_CMD_AC_RESET);
+		if (--timeout) {
+			snd_printk(KERN_ERR "atiixp: codec reset timeout\n");
+			break;
+		}
+	}
+
+	/* deassert RESET and assert SYNC to make sure */
+	atiixp_update(chip, CMD, ATI_REG_CMD_AC_SYNC|ATI_REG_CMD_AC_RESET,
+		      ATI_REG_CMD_AC_SYNC|ATI_REG_CMD_AC_RESET);
+
+	return 0;
+}
+
+#if 0 /* for P/M */
+static int snd_atiixp_aclink_down(atiixp_t *chip)
+{
+	unsigned long flags;
+
+	if (atiixp_read(chip, MODEM_MIRROR) & ATI_REG_MODEM_MIRROR_RUNNING)
+		return -EBUSY;
+	atiixp_update(chip, CMD,
+		     ATI_REG_CMD_POWERDOWN | ATI_REG_CMD_AC_RESET,
+		     ATI_REG_CMD_POWERDOWN);
+	return 0;
+}
+#endif
+
+/*
+ * auto-detection of codecs
+ *
+ * the IXP chip can generate interrupts for the non-existing codecs.
+ * NEW_FRAME interrupt is used to make sure that the interrupt is generated
+ * even if all three codecs are connected.
+ */
+
+#define ALL_CODEC_NOT_READY \
+	    (ATI_REG_ISR_CODEC0_NOT_READY |\
+	     ATI_REG_ISR_CODEC1_NOT_READY |\
+	     ATI_REG_ISR_CODEC2_NOT_READY)
+#define CODEC_CHECK_BITS (ALL_CODEC_NOT_READY|ATI_REG_ISR_NEW_FRAME)
+
+static int snd_atiixp_codec_detect(atiixp_t *chip)
+{
+	int timeout;
+
+	chip->codec_not_ready_bits = 0;
+	atiixp_write(chip, IER, CODEC_CHECK_BITS);
+	/* wait for the interrupts */
+	timeout = HZ / 10;
+	while (timeout-- > 0) {
+		do_delay();
+		if (chip->codec_not_ready_bits)
+			break;
+	}
+	atiixp_write(chip, IER, 0); /* disable irqs */
+
+	if ((chip->codec_not_ready_bits & ALL_CODEC_NOT_READY) == ALL_CODEC_NOT_READY) {
+		snd_printk(KERN_ERR "atiixp: no codec detected!\n");
+		return -ENXIO;
+	}
+	return 0;
+}
+
+
+/*
+ * enable DMA and irqs
+ */
+static int snd_atiixp_chip_start(atiixp_t *chip)
+{
+	unsigned int reg;
+
+	/* enable burst mode */
+	reg = atiixp_read(chip, CMD);
+	reg |= 0x02 << ATI_REG_CMD_SPDF_THRESHOLD_SHIFT;
+	reg |= ATI_REG_CMD_BURST_EN;
+	atiixp_write(chip, CMD, reg);
+
+	/* clear all interrupt source */
+	atiixp_write(chip, ISR, 0xffffffff);
+	/* enable irqs */
+	atiixp_write(chip, IER,
+		     ATI_REG_IER_IO_STATUS_EN |
+		     ATI_REG_IER_IN_XRUN_EN |
+		     ATI_REG_IER_OUT_XRUN_EN |
+		     ATI_REG_IER_SPDF_XRUN_EN |
+		     ATI_REG_IER_SPDF_STATUS_EN);
+	return 0;
+}
+
+
+/*
+ * disable DMA and IRQs
+ */
+static int snd_atiixp_chip_stop(atiixp_t *chip)
+{
+	/* clear interrupt source */
+	atiixp_write(chip, ISR, atiixp_read(chip, ISR));
+	/* disable irqs */
+	atiixp_write(chip, IER, 0);
+	return 0;
+}
+
+
+/*
+ * PCM section
+ */
+
+/*
+ * pointer callback simplly reads XXX_DMA_DT_CUR register as the current
+ * position.  when SG-buffer is implemented, the offset must be calculated
+ * correctly...
+ */
+static snd_pcm_uframes_t snd_atiixp_pcm_pointer(snd_pcm_substream_t *substream)
+{
+	atiixp_t *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	atiixp_dma_t *dma = (atiixp_dma_t *)runtime->private_data;
+	unsigned int curptr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	curptr = readl(chip->remap_addr + dma->ops->llp_offset + 12); /* XXX_DMA_DT_CUR */
+	if (curptr < dma->buf_addr) {
+		snd_printdd("curptr = %x, base = %x\n", curptr, dma->buf_addr);
+		curptr = 0;
+	} else {
+		curptr -= dma->buf_addr;
+		if (curptr >= dma->buf_bytes) {
+			snd_printdd("curptr = %x, size = %x\n", curptr, dma->buf_bytes);
+			curptr = 0;
+		}
+	}
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	return bytes_to_frames(runtime, curptr);
+}
+
+/*
+ * XRUN detected, and stop the PCM substream
+ */
+static void snd_atiixp_xrun_dma(atiixp_t *chip, atiixp_dma_t *dma)
+{
+	if (! dma->substream || ! dma->running)
+		return;
+	snd_printd(KERN_DEBUG "atiixp: XRUN detected (DMA %d)\n", dma->ops->type);
+	snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN);
+}
+
+/*
+ * the period ack.  update the substream.
+ */
+static void snd_atiixp_update_dma(atiixp_t *chip, atiixp_dma_t *dma)
+{
+	if (! dma->substream || ! dma->running)
+		return;
+	snd_pcm_period_elapsed(dma->substream);
+}
+
+/* set BUS_BUSY interrupt bit if any DMA is running */
+/* call with spinlock held */
+static void snd_atiixp_check_bus_busy(atiixp_t *chip)
+{
+	unsigned int bus_busy;
+	if (atiixp_read(chip, CMD) & (ATI_REG_CMD_SEND_EN |
+				      ATI_REG_CMD_RECEIVE_EN |
+				      ATI_REG_CMD_SPDF_OUT_EN))
+		bus_busy = ATI_REG_IER_SET_BUS_BUSY;
+	else
+		bus_busy = 0;
+	atiixp_update(chip, IER, ATI_REG_IER_SET_BUS_BUSY, bus_busy);
+}
+
+/* common trigger callback
+ * calling the lowlevel callbacks in it
+ */
+static int snd_atiixp_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
+{
+	atiixp_t *chip = snd_pcm_substream_chip(substream);
+	atiixp_dma_t *dma = (atiixp_dma_t *)substream->runtime->private_data;
+	int err = 0;
+
+	snd_assert(dma->ops->enable_transfer && dma->ops->flush_dma, return -EINVAL);
+
+	spin_lock(&chip->reg_lock);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		dma->ops->enable_transfer(chip, 1);
+		dma->running = 1;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		dma->ops->enable_transfer(chip, 0);
+		dma->running = 0;
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+	if (! err) {
+		snd_atiixp_check_bus_busy(chip);
+		if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+			dma->ops->flush_dma(chip);
+			snd_atiixp_check_bus_busy(chip);
+		}
+	}
+	spin_unlock(&chip->reg_lock);
+	return err;
+}
+
+
+/*
+ * lowlevel callbacks for each DMA type
+ *
+ * every callback is supposed to be called in chip->reg_lock spinlock
+ */
+
+/* flush FIFO of analog OUT DMA */
+static void atiixp_out_flush_dma(atiixp_t *chip)
+{
+	atiixp_write(chip, FIFO_FLUSH, ATI_REG_FIFO_OUT_FLUSH);
+}
+
+/* enable/disable analog OUT DMA */
+static void atiixp_out_enable_dma(atiixp_t *chip, int on)
+{
+	unsigned int data;
+	data = atiixp_read(chip, CMD);
+	if (on) {
+		if (data & ATI_REG_CMD_OUT_DMA_EN)
+			return;
+		atiixp_out_flush_dma(chip);
+		data |= ATI_REG_CMD_OUT_DMA_EN;
+	} else
+		data &= ~ATI_REG_CMD_OUT_DMA_EN;
+	atiixp_write(chip, CMD, data);
+}
+
+/* start/stop transfer over OUT DMA */
+static void atiixp_out_enable_transfer(atiixp_t *chip, int on)
+{
+	atiixp_update(chip, CMD, ATI_REG_CMD_SEND_EN,
+		      on ? ATI_REG_CMD_SEND_EN : 0);
+}
+
+/* enable/disable analog IN DMA */
+static void atiixp_in_enable_dma(atiixp_t *chip, int on)
+{
+	atiixp_update(chip, CMD, ATI_REG_CMD_IN_DMA_EN,
+		      on ? ATI_REG_CMD_IN_DMA_EN : 0);
+}
+
+/* start/stop analog IN DMA */
+static void atiixp_in_enable_transfer(atiixp_t *chip, int on)
+{
+	if (on) {
+		unsigned int data = atiixp_read(chip, CMD);
+		if (! (data & ATI_REG_CMD_RECEIVE_EN)) {
+			data |= ATI_REG_CMD_RECEIVE_EN;
+#if 0 /* FIXME: this causes the endless loop */
+			/* wait until slot 3/4 are finished */
+			while ((atiixp_read(chip, COUNTER) &
+				ATI_REG_COUNTER_SLOT) != 5)
+				;
+#endif
+			atiixp_write(chip, CMD, data);
+		}
+	} else
+		atiixp_update(chip, CMD, ATI_REG_CMD_RECEIVE_EN, 0);
+}
+
+/* flush FIFO of analog IN DMA */
+static void atiixp_in_flush_dma(atiixp_t *chip)
+{
+	atiixp_write(chip, FIFO_FLUSH, ATI_REG_FIFO_IN_FLUSH);
+}
+
+/* enable/disable SPDIF OUT DMA */
+static void atiixp_spdif_enable_dma(atiixp_t *chip, int on)
+{
+	atiixp_update(chip, CMD, ATI_REG_CMD_SPDF_DMA_EN,
+		      on ? ATI_REG_CMD_SPDF_DMA_EN : 0);
+}
+
+/* start/stop SPDIF OUT DMA */
+static void atiixp_spdif_enable_transfer(atiixp_t *chip, int on)
+{
+	unsigned int data;
+	data = atiixp_read(chip, CMD);
+	if (on) {
+		data |= ATI_REG_CMD_SPDF_OUT_EN;
+		if (chip->spdif_over_aclink)
+			data |= ATI_REG_CMD_SEND_EN;
+	}  else {
+		data &= ~ATI_REG_CMD_SPDF_OUT_EN;
+		if (chip->spdif_over_aclink)
+			data &= ~ATI_REG_CMD_SEND_EN;
+	}
+	atiixp_write(chip, CMD, data);
+}
+
+/* flush FIFO of SPDIF OUT DMA */
+static void atiixp_spdif_flush_dma(atiixp_t *chip)
+{
+	int timeout;
+
+	/* DMA off, transfer on */
+	atiixp_spdif_enable_dma(chip, 0);
+	atiixp_spdif_enable_transfer(chip, 1);
+	
+	timeout = 100;
+	do {
+		if (! (atiixp_read(chip, SPDF_DMA_DT_SIZE) & ATI_REG_DMA_FIFO_USED))
+			break;
+		udelay(1);
+	} while (timeout-- > 0);
+
+	atiixp_spdif_enable_transfer(chip, 0);
+}
+
+/* set up slots and formats for SPDIF OUT */
+static int snd_atiixp_spdif_prepare(snd_pcm_substream_t *substream)
+{
+	atiixp_t *chip = snd_pcm_substream_chip(substream);
+	unsigned int data;
+
+	spin_lock(&chip->reg_lock);
+	if (chip->spdif_over_aclink) {
+		/* enable slots 10/11 */
+		atiixp_update(chip, CMD, ATI_REG_CMD_SPDF_CONFIG_MASK,
+			      ATI_REG_CMD_SPDF_CONFIG_01);
+		data = atiixp_read(chip, OUT_DMA_SLOT);
+		data |= ATI_REG_OUT_DMA_SLOT_BIT(10) |
+			ATI_REG_OUT_DMA_SLOT_BIT(11);
+		data |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT;
+		atiixp_write(chip, OUT_DMA_SLOT, data);
+	} else {
+		atiixp_update(chip, CMD, ATI_REG_CMD_SPDF_CONFIG_MASK, 0);
+	}
+
+	atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_SPDF,
+		      substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE ?
+		      ATI_REG_CMD_INTERLEAVE_SPDF : 0);
+	spin_unlock(&chip->reg_lock);
+	return 0;
+}
+
+/* set up slots and formats for analog OUT */
+static int snd_atiixp_playback_prepare(snd_pcm_substream_t *substream)
+{
+	atiixp_t *chip = snd_pcm_substream_chip(substream);
+	unsigned int data;
+
+	spin_lock(&chip->reg_lock);
+	data = atiixp_read(chip, OUT_DMA_SLOT) & ~ATI_REG_OUT_DMA_SLOT_MASK;
+	switch (substream->runtime->channels) {
+	case 8:
+		data |= ATI_REG_OUT_DMA_SLOT_BIT(10) |
+			ATI_REG_OUT_DMA_SLOT_BIT(11);
+		/* fallthru */
+	case 6:
+		data |= ATI_REG_OUT_DMA_SLOT_BIT(7) |
+			ATI_REG_OUT_DMA_SLOT_BIT(8);
+		/* fallthru */
+	case 4:
+		data |= ATI_REG_OUT_DMA_SLOT_BIT(6) |
+			ATI_REG_OUT_DMA_SLOT_BIT(9);
+		/* fallthru */
+	default:
+		data |= ATI_REG_OUT_DMA_SLOT_BIT(3) |
+			ATI_REG_OUT_DMA_SLOT_BIT(4);
+		break;
+	}
+
+	/* set output threshold */
+	data |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT;
+	atiixp_write(chip, OUT_DMA_SLOT, data);
+
+	atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_OUT,
+		      substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE ?
+		      ATI_REG_CMD_INTERLEAVE_OUT : 0);
+
+	/*
+	 * enable 6 channel re-ordering bit if needed
+	 */
+	atiixp_update(chip, 6CH_REORDER, ATI_REG_6CH_REORDER_EN,
+		      substream->runtime->channels >= 6 ? ATI_REG_6CH_REORDER_EN: 0);
+    
+	spin_unlock(&chip->reg_lock);
+	return 0;
+}
+
+/* set up slots and formats for analog IN */
+static int snd_atiixp_capture_prepare(snd_pcm_substream_t *substream)
+{
+	atiixp_t *chip = snd_pcm_substream_chip(substream);
+
+	spin_lock(&chip->reg_lock);
+	atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_IN,
+		      substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE ?
+		      ATI_REG_CMD_INTERLEAVE_IN : 0);
+	spin_unlock(&chip->reg_lock);
+	return 0;
+}
+
+/*
+ * hw_params - allocate the buffer and set up buffer descriptors
+ */
+static int snd_atiixp_pcm_hw_params(snd_pcm_substream_t *substream,
+				   snd_pcm_hw_params_t *hw_params)
+{
+	atiixp_t *chip = snd_pcm_substream_chip(substream);
+	atiixp_dma_t *dma = (atiixp_dma_t *)substream->runtime->private_data;
+	int err;
+
+	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+	if (err < 0)
+		return err;
+	dma->buf_addr = substream->runtime->dma_addr;
+	dma->buf_bytes = params_buffer_bytes(hw_params);
+
+	err = atiixp_build_dma_packets(chip, dma, substream,
+				       params_periods(hw_params),
+				       params_period_bytes(hw_params));
+	if (err < 0)
+		return err;
+
+	if (dma->pcm) {
+		/* PCM is bound to AC97 codec(s)
+		 * set up the AC97 codecs
+		 */
+		if (dma->pcm_open_flag) {
+			snd_ac97_pcm_close(dma->pcm);
+			dma->pcm_open_flag = 0;
+		}
+		err = snd_ac97_pcm_open(dma->pcm, params_rate(hw_params),
+					params_channels(hw_params),
+					dma->pcm->r[0].slots);
+		if (err >= 0)
+			dma->pcm_open_flag = 1;
+	}
+
+	return err;
+}
+
+static int snd_atiixp_pcm_hw_free(snd_pcm_substream_t * substream)
+{
+	atiixp_t *chip = snd_pcm_substream_chip(substream);
+	atiixp_dma_t *dma = (atiixp_dma_t *)substream->runtime->private_data;
+
+	if (dma->pcm_open_flag) {
+		snd_ac97_pcm_close(dma->pcm);
+		dma->pcm_open_flag = 0;
+	}
+	atiixp_clear_dma_packets(chip, dma, substream);
+	snd_pcm_lib_free_pages(substream);
+	return 0;
+}
+
+
+/*
+ * pcm hardware definition, identical for all DMA types
+ */
+static snd_pcm_hardware_t snd_atiixp_pcm_hw =
+{
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_MMAP_VALID),
+	.formats =		SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+	.rates =		SNDRV_PCM_RATE_48000,
+	.rate_min =		48000,
+	.rate_max =		48000,
+	.channels_min =		2,
+	.channels_max =		2,
+	.buffer_bytes_max =	256 * 1024,
+	.period_bytes_min =	32,
+	.period_bytes_max =	128 * 1024,
+	.periods_min =		2,
+	.periods_max =		ATI_MAX_DESCRIPTORS,
+};
+
+static int snd_atiixp_pcm_open(snd_pcm_substream_t *substream, atiixp_dma_t *dma)
+{
+	atiixp_t *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	unsigned long flags;
+	int err;
+
+	snd_assert(dma->ops && dma->ops->enable_dma, return -EINVAL);
+
+	dma->substream = substream;
+	runtime->hw = snd_atiixp_pcm_hw;
+	if (dma->pcm) {
+		runtime->hw.rates = dma->pcm->rates;
+		snd_pcm_limit_hw_rates(runtime);
+	} else {
+		/* SPDIF */
+		runtime->hw.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_32000;
+		runtime->hw.rate_min = 32000;
+	}
+	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+		return err;
+	runtime->private_data = dma;
+
+	/* enable DMA bits */
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	dma->ops->enable_dma(chip, 1);
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+	return 0;
+}
+
+static int snd_atiixp_pcm_close(snd_pcm_substream_t *substream, atiixp_dma_t *dma)
+{
+	atiixp_t *chip = snd_pcm_substream_chip(substream);
+	/* disable DMA bits */
+	snd_assert(dma->ops && dma->ops->enable_dma, return -EINVAL);
+	spin_lock_irq(&chip->reg_lock);
+	dma->ops->enable_dma(chip, 0);
+	spin_unlock_irq(&chip->reg_lock);
+	dma->substream = NULL;
+	return 0;
+}
+
+/*
+ */
+static int snd_atiixp_playback_open(snd_pcm_substream_t *substream)
+{
+	atiixp_t *chip = snd_pcm_substream_chip(substream);
+	int err;
+
+	err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
+	substream->runtime->hw.channels_max = chip->max_channels;
+	if (chip->max_channels > 2)
+		/* channels must be even */
+		snd_pcm_hw_constraint_step(substream->runtime, 0,
+					   SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+
+	return 0;
+}
+
+static int snd_atiixp_playback_close(snd_pcm_substream_t *substream)
+{
+	atiixp_t *chip = snd_pcm_substream_chip(substream);
+	return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
+}
+
+static int snd_atiixp_capture_open(snd_pcm_substream_t *substream)
+{
+	atiixp_t *chip = snd_pcm_substream_chip(substream);
+	return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_CAPTURE]);
+}
+
+static int snd_atiixp_capture_close(snd_pcm_substream_t *substream)
+{
+	atiixp_t *chip = snd_pcm_substream_chip(substream);
+	return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_CAPTURE]);
+}
+
+static int snd_atiixp_spdif_open(snd_pcm_substream_t *substream)
+{
+	atiixp_t *chip = snd_pcm_substream_chip(substream);
+	return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_SPDIF]);
+}
+
+static int snd_atiixp_spdif_close(snd_pcm_substream_t *substream)
+{
+	atiixp_t *chip = snd_pcm_substream_chip(substream);
+	return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_SPDIF]);
+}
+
+/* AC97 playback */
+static snd_pcm_ops_t snd_atiixp_playback_ops = {
+	.open =		snd_atiixp_playback_open,
+	.close =	snd_atiixp_playback_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_atiixp_pcm_hw_params,
+	.hw_free =	snd_atiixp_pcm_hw_free,
+	.prepare =	snd_atiixp_playback_prepare,
+	.trigger =	snd_atiixp_pcm_trigger,
+	.pointer =	snd_atiixp_pcm_pointer,
+};
+
+/* AC97 capture */
+static snd_pcm_ops_t snd_atiixp_capture_ops = {
+	.open =		snd_atiixp_capture_open,
+	.close =	snd_atiixp_capture_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_atiixp_pcm_hw_params,
+	.hw_free =	snd_atiixp_pcm_hw_free,
+	.prepare =	snd_atiixp_capture_prepare,
+	.trigger =	snd_atiixp_pcm_trigger,
+	.pointer =	snd_atiixp_pcm_pointer,
+};
+
+/* SPDIF playback */
+static snd_pcm_ops_t snd_atiixp_spdif_ops = {
+	.open =		snd_atiixp_spdif_open,
+	.close =	snd_atiixp_spdif_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_atiixp_pcm_hw_params,
+	.hw_free =	snd_atiixp_pcm_hw_free,
+	.prepare =	snd_atiixp_spdif_prepare,
+	.trigger =	snd_atiixp_pcm_trigger,
+	.pointer =	snd_atiixp_pcm_pointer,
+};
+
+static struct ac97_pcm atiixp_pcm_defs[] __devinitdata = {
+	/* front PCM */
+	{
+		.exclusive = 1,
+		.r = {	{
+				.slots = (1 << AC97_SLOT_PCM_LEFT) |
+					 (1 << AC97_SLOT_PCM_RIGHT) |
+					 (1 << AC97_SLOT_PCM_CENTER) |
+					 (1 << AC97_SLOT_PCM_SLEFT) |
+					 (1 << AC97_SLOT_PCM_SRIGHT) |
+					 (1 << AC97_SLOT_LFE)
+			}
+		}
+	},
+	/* PCM IN #1 */
+	{
+		.stream = 1,
+		.exclusive = 1,
+		.r = {	{
+				.slots = (1 << AC97_SLOT_PCM_LEFT) |
+					 (1 << AC97_SLOT_PCM_RIGHT)
+			}
+		}
+	},
+	/* S/PDIF OUT (optional) */
+	{
+		.exclusive = 1,
+		.spdif = 1,
+		.r = {	{
+				.slots = (1 << AC97_SLOT_SPDIF_LEFT2) |
+					 (1 << AC97_SLOT_SPDIF_RIGHT2)
+			}
+		}
+	},
+};
+
+static atiixp_dma_ops_t snd_atiixp_playback_dma_ops = {
+	.type = ATI_DMA_PLAYBACK,
+	.llp_offset = ATI_REG_OUT_DMA_LINKPTR,
+	.enable_dma = atiixp_out_enable_dma,
+	.enable_transfer = atiixp_out_enable_transfer,
+	.flush_dma = atiixp_out_flush_dma,
+};
+	
+static atiixp_dma_ops_t snd_atiixp_capture_dma_ops = {
+	.type = ATI_DMA_CAPTURE,
+	.llp_offset = ATI_REG_IN_DMA_LINKPTR,
+	.enable_dma = atiixp_in_enable_dma,
+	.enable_transfer = atiixp_in_enable_transfer,
+	.flush_dma = atiixp_in_flush_dma,
+};
+	
+static atiixp_dma_ops_t snd_atiixp_spdif_dma_ops = {
+	.type = ATI_DMA_SPDIF,
+	.llp_offset = ATI_REG_SPDF_DMA_LINKPTR,
+	.enable_dma = atiixp_spdif_enable_dma,
+	.enable_transfer = atiixp_spdif_enable_transfer,
+	.flush_dma = atiixp_spdif_flush_dma,
+};
+	
+
+static int __devinit snd_atiixp_pcm_new(atiixp_t *chip)
+{
+	snd_pcm_t *pcm;
+	ac97_bus_t *pbus = chip->ac97_bus;
+	int err, i, num_pcms;
+
+	/* initialize constants */
+	chip->dmas[ATI_DMA_PLAYBACK].ops = &snd_atiixp_playback_dma_ops;
+	chip->dmas[ATI_DMA_CAPTURE].ops = &snd_atiixp_capture_dma_ops;
+	chip->dmas[ATI_DMA_SPDIF].ops = &snd_atiixp_spdif_dma_ops;
+
+	/* assign AC97 pcm */
+	if (chip->spdif_over_aclink)
+		num_pcms = 3;
+	else
+		num_pcms = 2;
+	err = snd_ac97_pcm_assign(pbus, num_pcms, atiixp_pcm_defs);
+	if (err < 0)
+		return err;
+
+	chip->max_channels = 2;
+	if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_PCM_SLEFT)) {
+		if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_LFE))
+			chip->max_channels = 6;
+		else
+			chip->max_channels = 4;
+	}
+
+	chip->dmas[ATI_DMA_PLAYBACK].pcm = &pbus->pcms[0];
+	chip->dmas[ATI_DMA_CAPTURE].pcm = &pbus->pcms[1];
+	if (chip->spdif_over_aclink)
+		chip->dmas[ATI_DMA_SPDIF].pcm = &pbus->pcms[2];
+
+	/* PCM #0: analog I/O */
+	err = snd_pcm_new(chip->card, "ATI IXP AC97", 0, 1, 1, &pcm);
+	if (err < 0)
+		return err;
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_atiixp_playback_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_atiixp_capture_ops);
+	pcm->private_data = chip;
+	strcpy(pcm->name, "ATI IXP AC97");
+
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(chip->pci), 64*1024, 128*1024);
+
+	/* no SPDIF support on codec? */
+	if (chip->dmas[ATI_DMA_SPDIF].pcm && ! chip->dmas[ATI_DMA_SPDIF].pcm->rates)
+		return 0;
+		
+	/* PCM #1: spdif playback */
+	err = snd_pcm_new(chip->card, "ATI IXP IEC958", 1, 1, 0, &pcm);
+	if (err < 0)
+		return err;
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_atiixp_spdif_ops);
+	pcm->private_data = chip;
+	strcpy(pcm->name, "ATI IXP IEC958");
+
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(chip->pci), 64*1024, 128*1024);
+
+	/* pre-select AC97 SPDIF slots 10/11 */
+	for (i = 0; i < 3; i++) {
+		if (chip->ac97[i])
+			snd_ac97_update_bits(chip->ac97[i], AC97_EXTENDED_STATUS, 0x03 << 4, 0x03 << 4);
+	}
+
+	return 0;
+}
+
+
+
+/*
+ * interrupt handler
+ */
+static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	atiixp_t *chip = snd_magic_cast(atiixp_t, dev_id, return IRQ_NONE);
+	unsigned int status;
+
+	status = atiixp_read(chip, ISR);
+
+	if (! status)
+		return IRQ_NONE;
+
+	/* process audio DMA */
+	if (status & ATI_REG_ISR_OUT_XRUN)
+		snd_atiixp_xrun_dma(chip,  &chip->dmas[ATI_DMA_PLAYBACK]);
+	else if (status & ATI_REG_ISR_OUT_STATUS)
+		snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_PLAYBACK]);
+	if (status & ATI_REG_ISR_IN_XRUN)
+		snd_atiixp_xrun_dma(chip,  &chip->dmas[ATI_DMA_CAPTURE]);
+	else if (status & ATI_REG_ISR_IN_STATUS)
+		snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_CAPTURE]);
+	if (status & ATI_REG_ISR_SPDF_XRUN)
+		snd_atiixp_xrun_dma(chip,  &chip->dmas[ATI_DMA_SPDIF]);
+	else if (status & ATI_REG_ISR_SPDF_STATUS)
+		snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_SPDIF]);
+
+	/* for codec detection */
+	if (status & CODEC_CHECK_BITS) {
+		unsigned int detected;
+		detected = status & CODEC_CHECK_BITS;
+		spin_lock(&chip->reg_lock);
+		chip->codec_not_ready_bits |= detected;
+		atiixp_update(chip, IER, detected, 0); /* disable the detected irqs */
+		spin_unlock(&chip->reg_lock);
+	}
+
+	/* ack */
+	atiixp_write(chip, ISR, status);
+
+	return IRQ_HANDLED;
+}
+
+
+/*
+ * ac97 mixer section
+ */
+
+static int __devinit snd_atiixp_mixer_new(atiixp_t *chip, int clock)
+{
+	ac97_bus_t bus, *pbus;
+	ac97_t ac97;
+	int i, err;
+	static unsigned int codec_skip[3] = {
+		ATI_REG_ISR_CODEC0_NOT_READY,
+		ATI_REG_ISR_CODEC1_NOT_READY,
+		ATI_REG_ISR_CODEC2_NOT_READY,
+	};
+
+	if (snd_atiixp_codec_detect(chip) < 0)
+		return -ENXIO;
+
+	memset(&bus, 0, sizeof(bus));
+	bus.write = snd_atiixp_ac97_write;
+	bus.read = snd_atiixp_ac97_read;
+	bus.private_data = chip;
+	bus.clock = clock;
+	if ((err = snd_ac97_bus(chip->card, &bus, &pbus)) < 0)
+		return err;
+	chip->ac97_bus = pbus;
+
+	for (i = 0; i < 3; i++) {
+		if (chip->codec_not_ready_bits & codec_skip[i])
+			continue;
+		memset(&ac97, 0, sizeof(ac97));
+		ac97.private_data = chip;
+		ac97.pci = chip->pci;
+		ac97.num = i;
+		if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0)
+			return err;
+	}
+
+	/* snd_ac97_tune_hardware(chip->ac97, ac97_quirks); */
+
+	return 0;
+}
+
+
+/*
+ * proc interface for register dump
+ */
+
+static void snd_atiixp_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+{
+	atiixp_t *chip = snd_magic_cast(atiixp_t, entry->private_data, return);
+	int i;
+
+	for (i = 0; i < 256; i += 4)
+		snd_iprintf(buffer, "%02x: %08x\n", i, readl(chip->remap_addr + i));
+}
+
+static void __devinit snd_atiixp_proc_init(atiixp_t *chip)
+{
+	snd_info_entry_t *entry;
+
+	if (! snd_card_proc_new(chip->card, "atiixp", &entry))
+		snd_info_set_text_ops(entry, chip, 1024, snd_atiixp_proc_read);
+}
+
+
+
+/*
+ * destructor
+ */
+
+static int snd_atiixp_free(atiixp_t *chip)
+{
+	if (chip->irq < 0)
+		goto __hw_end;
+	snd_atiixp_chip_stop(chip);
+	synchronize_irq(chip->irq);
+      __hw_end:
+	if (chip->remap_addr)
+		iounmap((void *) chip->remap_addr);
+	if (chip->res) {
+		release_resource(chip->res);
+		kfree_nocheck(chip->res);
+	}
+	if (chip->irq >= 0)
+		free_irq(chip->irq, (void *)chip);
+	snd_magic_kfree(chip);
+	return 0;
+}
+
+static int snd_atiixp_dev_free(snd_device_t *device)
+{
+	atiixp_t *chip = snd_magic_cast(atiixp_t, device->device_data, return -ENXIO);
+	return snd_atiixp_free(chip);
+}
+
+/*
+ * constructor for chip instance
+ */
+static int __devinit snd_atiixp_create(snd_card_t *card,
+				      struct pci_dev *pci,
+				      atiixp_t **r_chip)
+{
+	static snd_device_ops_t ops = {
+		.dev_free =	snd_atiixp_dev_free,
+	};
+	atiixp_t *chip;
+	int err;
+
+	if ((err = pci_enable_device(pci)) < 0)
+		return err;
+
+	chip = snd_magic_kcalloc(atiixp_t, 0, GFP_KERNEL);
+	if (chip == NULL)
+		return -ENOMEM;
+
+	spin_lock_init(&chip->reg_lock);
+	spin_lock_init(&chip->ac97_lock);
+	chip->card = card;
+	chip->pci = pci;
+	chip->irq = -1;
+	chip->addr = pci_resource_start(pci, 0);
+	if ((chip->res = request_mem_region(chip->addr, ATI_MEM_REGION, "ATI IXP AC97")) == NULL) {
+		snd_printk("unable to grab I/O memory 0x%lx\n", chip->addr);
+		snd_atiixp_free(chip);
+		return -EBUSY;
+	}
+	chip->remap_addr = (unsigned long) ioremap_nocache(chip->addr, ATI_MEM_REGION);
+	if (chip->remap_addr == 0) {
+		snd_printk("AC'97 space ioremap problem\n");
+		snd_atiixp_free(chip);
+		return -EIO;
+	}
+
+	if (request_irq(pci->irq, snd_atiixp_interrupt, SA_INTERRUPT|SA_SHIRQ, card->shortname, (void *)chip)) {
+		snd_printk("unable to grab IRQ %d\n", pci->irq);
+		snd_atiixp_free(chip);
+		return -EBUSY;
+	}
+	chip->irq = pci->irq;
+	pci_set_master(pci);
+	synchronize_irq(chip->irq);
+
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
+		snd_atiixp_free(chip);
+		return err;
+	}
+
+	snd_card_set_dev(card, &pci->dev);
+
+	*r_chip = chip;
+	return 0;
+}
+
+
+static int __devinit snd_atiixp_probe(struct pci_dev *pci,
+				     const struct pci_device_id *pci_id)
+{
+	static int dev;
+	snd_card_t *card;
+	atiixp_t *chip;
+	unsigned char revision;
+	int err;
+
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+	if (card == NULL)
+		return -ENOMEM;
+
+	pci_read_config_byte(pci, PCI_REVISION_ID, &revision);
+
+	strcpy(card->driver, "ATIIXP");
+	strcpy(card->shortname, "ATI IXP");
+	if ((err = snd_atiixp_create(card, pci, &chip)) < 0)
+		goto __error;
+
+	if ((err = snd_atiixp_aclink_reset(chip)) < 0)
+		goto __error;
+
+	chip->spdif_over_aclink = spdif_aclink[dev];
+
+	if ((err = snd_atiixp_mixer_new(chip, ac97_clock[dev])) < 0)
+		goto __error;
+
+	if ((err = snd_atiixp_pcm_new(chip)) < 0)
+		goto __error;
+	
+	snd_atiixp_proc_init(chip);
+
+	snd_atiixp_chip_start(chip);
+
+	sprintf(card->longname, "%s rev %x at 0x%lx, irq %i",
+		card->shortname, revision, chip->addr, chip->irq);
+
+	if ((err = snd_card_register(card)) < 0)
+		goto __error;
+
+	pci_set_drvdata(pci, chip);
+	dev++;
+	return 0;
+
+ __error:
+	snd_card_free(card);
+	return err;
+}
+
+static void __devexit snd_atiixp_remove(struct pci_dev *pci)
+{
+	atiixp_t *chip = snd_magic_cast(atiixp_t, pci_get_drvdata(pci), return);
+	if (chip)
+		snd_card_free(chip->card);
+	pci_set_drvdata(pci, NULL);
+}
+
+static struct pci_driver driver = {
+	.name = "ATI IXP AC97 controller",
+	.id_table = snd_atiixp_ids,
+	.probe = snd_atiixp_probe,
+	.remove = __devexit_p(snd_atiixp_remove),
+};
+
+
+static int __init alsa_card_atiixp_init(void)
+{
+	int err;
+
+        if ((err = pci_module_init(&driver)) < 0) {
+#ifdef MODULE
+		printk(KERN_ERR "ATI IXP AC97 controller not found or device busy\n");
+#endif
+                return err;
+        }
+
+        return 0;
+}
+
+static void __exit alsa_card_atiixp_exit(void)
+{
+	pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_atiixp_init)
+module_exit(alsa_card_atiixp_exit)
+
+#ifndef MODULE
+
+/* format is: snd-atiixp=enable,index,id,ac97_clock,spdif_aclink */
+
+static int __init alsa_card_atiixp_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 &&
+	       get_option(&str,&ac97_clock[nr_dev]) == 2 &&
+	       get_option(&str,&spdif_aclink[nr_dev]) == 2
+	       );
+	nr_dev++;
+	return 1;
+}
+
+__setup("snd-atiixp=", alsa_card_atiixp_setup);
+
+#endif /* ifndef MODULE */
--- diff/sound/pci/au88x0/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/Makefile	2004-03-16 09:37:58.486648848 +0000
@@ -0,0 +1,7 @@
+snd-au8810-objs := au8810.o
+snd-au8820-objs := au8820.o
+snd-au8830-objs := au8830.o
+
+obj-$(CONFIG_SND_AU8810) += snd-au8810.o
+obj-$(CONFIG_SND_AU8820) += snd-au8820.o
+obj-$(CONFIG_SND_AU8830) += snd-au8830.o
--- diff/sound/pci/au88x0/au8810.c	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au8810.c	2004-03-16 09:37:58.486648848 +0000
@@ -0,0 +1,17 @@
+#include "au8810.h"
+#include "au88x0.h"
+static struct pci_device_id snd_vortex_ids[] = {
+	{PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1,},
+	{0,}
+};
+
+#include "au88x0_core.c"
+#include "au88x0_pcm.c"
+#include "au88x0_mixer.c"
+#include "au88x0_mpu401.c"
+#include "au88x0_game.c"
+#include "au88x0_eq.c"
+#include "au88x0_a3d.c"
+#include "au88x0_xtalk.c"
+#include "au88x0.c"
--- diff/sound/pci/au88x0/au8810.h	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au8810.h	2004-03-16 09:37:58.487648696 +0000
@@ -0,0 +1,221 @@
+/*
+    Aureal Advantage Soundcard driver.
+ */
+
+#define CHIP_AU8810
+
+#define CARD_NAME "Aureal Advantage 3D Sound Processor"
+#define CARD_NAME_SHORT "au8810"
+
+#ifndef PCI_VENDOR_ID_AUREAL
+#define PCI_VENDOR_ID_AUREAL 0x12eb
+#endif
+#ifndef PCI_VENDOR_ID_AUREAL_ADVANTAGE
+#define PCI_DEVICE_ID_AUREAL_ADVANTAGE 0x0003
+#endif
+
+#define hwread(x,y) readl((x)+((y)>>2))
+#define hwwrite(x,y,z) writel((z),(x)+((y)>>2))
+
+#define NR_ADB		0x20
+#define NR_WT		0x00
+#define NR_SRC		0x10
+#define NR_A3D		0x10
+#define NR_MIXIN	0x20
+#define NR_MIXOUT	0x10
+
+
+/* ADBDMA */
+#define VORTEX_ADBDMA_STAT 0x27e00	/* read only, subbuffer, DMA pos */
+#define		POS_MASK 0x00000fff
+#define     POS_SHIFT 0x0
+#define 	ADB_SUBBUF_MASK 0x00003000	/* ADB only. */
+#define     ADB_SUBBUF_SHIFT 0xc	/* ADB only. */
+#define VORTEX_ADBDMA_CTRL 0x27180	/* write only; format, flags, DMA pos */
+#define		OFFSET_MASK 0x00000fff
+#define     OFFSET_SHIFT 0x0
+#define		IE_MASK 0x00001000	/* interrupt enable. */
+#define     IE_SHIFT 0xc
+#define     DIR_MASK 0x00002000	/* Direction */
+#define     DIR_SHIFT 0xd
+#define		FMT_MASK 0x0003c000
+#define		FMT_SHIFT 0xe
+// The ADB masks and shift also are valid for the wtdma, except if specified otherwise.
+#define VORTEX_ADBDMA_BUFCFG0 0x27100
+#define VORTEX_ADBDMA_BUFCFG1 0x27104
+#define VORTEX_ADBDMA_BUFBASE 0x27000
+#define VORTEX_ADBDMA_START 0x27c00	/* Which subbuffer starts */
+
+#define VORTEX_ADBDMA_STATUS 0x27A90	/* stored at AdbDma->this_10 / 2 DWORD in size. */
+
+/* WTDMA */
+#define VORTEX_WTDMA_CTRL 0x27fd8	/* format, DMA pos */
+#define VORTEX_WTDMA_STAT 0x27fe8	/* DMA subbuf, DMA pos */
+#define     WT_SUBBUF_MASK 0x3
+#define     WT_SUBBUF_SHIFT 0xc
+#define VORTEX_WTDMA_BUFBASE 0x27fc0
+#define VORTEX_WTDMA_BUFCFG0 0x27fd0
+#define VORTEX_WTDMA_BUFCFG1 0x27fd4
+#define VORTEX_WTDMA_START 0x27fe4	/* which subbuffer is first */
+
+/* ADB */
+#define VORTEX_ADB_SR 0x28400	/* Samplerates enable/disable */
+#define VORTEX_ADB_RTBASE 0x28000
+#define VORTEX_ADB_RTBASE_SIZE (VORTEX_ADB_CHNBASE - VORTEX_ADB_RTBASE)
+#define VORTEX_ADB_CHNBASE 0x282b4
+#define VORTEX_ADB_CHNBASE_SIZE (ADB_MASK - VORTEX_ADB_RTBASE_SIZE)
+#define 	ROUTE_MASK	0xffff
+#define		SOURCE_MASK	0xff00
+#define     ADB_MASK   0xff
+#define		ADB_SHIFT 0x8
+/* ADB address */
+#define		OFFSET_ADBDMA	0x00
+#define		OFFSET_SRCIN	0x40
+#define		OFFSET_SRCOUT	0x20
+#define		OFFSET_MIXIN	0x50
+#define		OFFSET_MIXOUT	0x30
+#define		OFFSET_CODECIN	0x70
+#define		OFFSET_CODECOUT	0x88
+#define		OFFSET_SPORTIN	0x78	/* ch 0x13 */
+#define		OFFSET_SPORTOUT	0x90
+#define		OFFSET_SPDIFOUT	0x92	/* ch 0x14 check this! */
+#define		OFFSET_EQIN		0xa0
+#define		OFFSET_EQOUT	0x7e	/* 2 routes on ch 0x11 */
+#define		OFFSET_XTALKOUT	0x66	/* crosstalk canceller (source) */
+#define		OFFSET_XTALKIN	0x96	/* crosstalk canceller (sink) */
+#define		OFFSET_EFXIN	0x80	/* ADB sink. */
+#define		OFFSET_EFXOUT	0x68	/* ADB source. */
+
+/* ADB route translate helper */
+#define ADB_DMA(x) (x)
+#define ADB_SRCOUT(x) (x + OFFSET_SRCOUT)
+#define ADB_SRCIN(x) (x + OFFSET_SRCIN)
+#define ADB_MIXOUT(x) (x + OFFSET_MIXOUT)
+#define ADB_MIXIN(x) (x + OFFSET_MIXIN)
+#define ADB_CODECIN(x) (x + OFFSET_CODECIN)
+#define ADB_CODECOUT(x) (x + OFFSET_CODECOUT)
+#define ADB_SPORTIN(x) (x + OFFSET_SPORTIN)
+#define ADB_SPORTOUT(x) (x + OFFSET_SPORTOUT)
+#define ADB_SPDIFOUT(x)	(x + OFFSET_SPDIFOUT)
+#define ADB_EQIN(x) (x + OFFSET_EQIN)
+#define ADB_EQOUT(x) (x + OFFSET_EQOUT)
+#define ADB_A3DOUT(x) (x + 0x50)	/* A3D blocks */
+#define ADB_A3DIN(x) (x + 0x70)
+#define ADB_XTALKIN(x) (x + OFFSET_XTALKIN)
+#define ADB_XTALKOUT(x) (x + OFFSET_XTALKOUT)
+
+#define MIX_OUTL    0xe
+#define MIX_OUTR    0xf
+#define MIX_INL     0x1e
+#define MIX_INR     0x1f
+#define MIX_DEFIGAIN 0x08	/* 0x8 => 6dB */
+#define MIX_DEFOGAIN 0x08
+
+/* MIXER */
+#define VORTEX_MIXER_SR 0x21f00
+#define VORTEX_MIXER_CLIP 0x21f80
+#define VORTEX_MIXER_CHNBASE 0x21e40
+#define VORTEX_MIXER_RTBASE 0x21e00
+#define 	MIXER_RTBASE_SIZE 0x38
+#define VORTEX_MIX_ENIN 0x21a00	/* Input enable bits. 4 bits wide. */
+#define VORTEX_MIX_SMP 0x21c00	/* AU8820: 0x9c00 */
+
+/* MIX */
+#define VORTEX_MIX_INVOL_A 0x21000	/* in? */
+#define VORTEX_MIX_INVOL_B 0x20000	/* out? */
+#define VORTEX_MIX_VOL_A 0x21800
+#define VORTEX_MIX_VOL_B 0x20800
+
+#define 	VOL_MIN 0x80	/* Input volume when muted. */
+#define		VOL_MAX 0x7f	/* FIXME: Not confirmed! Just guessed. */
+
+/* SRC */
+#define VORTEX_SRCBLOCK_SR	0x26cc0
+#define VORTEX_SRC_CHNBASE	0x26c40
+#define VORTEX_SRC_RTBASE	0x26c00
+#define VORTEX_SRC_SOURCE	0x26cc4
+#define VORTEX_SRC_SOURCESIZE 0x26cc8
+#define VORTEX_SRC_CONVRATIO 0x26e40
+#define VORTEX_SRC_DRIFT0	0x26e80
+#define VORTEX_SRC_DRIFT1	0x26ec0
+#define VORTEX_SRC_DRIFT2	0x26f40
+#define VORTEX_SRC_U0		0x26e00
+#define VORTEX_SRC_U1		0x26f00
+#define VORTEX_SRC_U2		0x26f80
+#define VORTEX_SRC_DATA		0x26800	/* 0xc800 */
+#define VORTEX_SRC_DATA0	0x26000
+
+/* FIFO */
+#define VORTEX_FIFO_ADBCTRL 0x16100	/* Control bits. */
+#define VORTEX_FIFO_WTCTRL 0x16000
+#define		FIFO_RDONLY	0x00000001
+#define		FIFO_CTRL	0x00000002	/* Allow ctrl. ? */
+#define		FIFO_VALID	0x00000010
+#define 	FIFO_EMPTY	0x00000020
+#define		FIFO_U0		0x00001000	/* Unknown. */
+#define		FIFO_U1		0x00010000
+#define		FIFO_SIZE_BITS 5
+#define		FIFO_SIZE	(1<<FIFO_SIZE_BITS)	// 0x20
+#define 	FIFO_MASK	(FIFO_SIZE-1)	//0x1f    /* at shift left 0xc */
+//#define       FIFO_MASK       0x1f    /* at shift left 0xb */
+//#define               FIFO_SIZE       0x20
+#define 	FIFO_BITS	0x03880000
+#define VORTEX_FIFO_ADBDATA 0x14000
+#define VORTEX_FIFO_WTDATA 0x10000
+
+/* CODEC */
+#define VORTEX_CODEC_CTRL 0x29184
+#define VORTEX_CODEC_EN 0x29190
+#define		EN_CODEC0	0x00000300
+#define		EN_CODEC1	0x00003000
+#define		EN_CODEC	(EN_CODEC0 | EN_CODEC1)
+#define		EN_SPORT	0x00030000
+#define		EN_SPDIF	0x000c0000
+#define VORTEX_CODEC_CHN 0x29080
+#define VORTEX_CODEC_WRITE 0x00800000
+#define VORTEX_CODEC_ADDSHIFT 16
+#define VORTEX_CODEC_ADDMASK 0x7f0000	/* 0x000f0000 */
+#define VORTEX_CODEC_DATSHIFT 0
+#define VORTEX_CODEC_DATMASK 0xffff
+#define VORTEX_CODEC_IO 0x29188
+
+/* SPDIF */
+#define VORTEX_SPDIF_FLAGS		0x2205c
+#define VORTEX_SPDIF_CFG0		0x291D0
+#define VORTEX_SPDIF_CFG1		0x291D4
+#define VORTEX_SPDIF_SMPRATE	0x29194
+
+/* Sample timer */
+#define VORTEX_SMP_TIME  0x29198
+
+/* IRQ */
+#define VORTEX_IRQ_SOURCE 0x2a000	/* Interrupt source flags. */
+#define VORTEX_IRQ_CTRL 0x2a004	/* Interrupt source mask. */
+
+#define VORTEX_STAT	0x2a008	/* Status */
+
+#define VORTEX_CTRL		0x2a00c
+#define 	CTRL_MIDI_EN	0x00000001
+#define 	CTRL_MIDI_PORT	0x00000060
+#define 	CTRL_GAME_EN	0x00000008
+#define 	CTRL_GAME_PORT	0x00000e00
+//#define       CTRL_IRQ_ENABLE 0x01004000
+#define 	CTRL_IRQ_ENABLE	0x00004000
+
+/* write: Timer period config / read: TIMER IRQ ack. */
+#define VORTEX_IRQ_STAT 0x2919c
+
+/* DMA */
+#define VORTEX_ENGINE_CTRL 0x27ae8
+#define 	ENGINE_INIT 0x1380000
+
+		     /* MIDI *//* GAME. */
+#define VORTEX_MIDI_DATA 0x28800
+#define VORTEX_MIDI_CMD 0x28804	/* Write command / Read status */
+
+#define VORTEX_CTRL2 0x2880c
+#define		CTRL2_GAME_ADCMODE 0x40
+#define VORTEX_GAME_LEGACY 0x28808
+#define VORTEX_GAME_AXIS 0x28810
+#define		AXIS_SIZE 4
+#define		AXIS_RANGE 0x1fff
--- diff/sound/pci/au88x0/au8820.c	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au8820.c	2004-03-16 09:37:58.487648696 +0000
@@ -0,0 +1,15 @@
+#include "au8820.h"
+#include "au88x0.h"
+static struct pci_device_id snd_vortex_ids[] = {
+	{PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,},
+	{0,}
+};
+
+#include "au88x0_synth.c"
+#include "au88x0_core.c"
+#include "au88x0_pcm.c"
+#include "au88x0_mpu401.c"
+#include "au88x0_game.c"
+#include "au88x0_mixer.c"
+#include "au88x0.c"
--- diff/sound/pci/au88x0/au8820.h	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au8820.h	2004-03-16 09:37:58.488648544 +0000
@@ -0,0 +1,217 @@
+/*
+    Aureal Vortex Soundcard driver.
+
+    IO addr collected from asp4core.vxd:
+    function    address
+    0005D5A0    13004
+    00080674    14004
+    00080AFF    12818
+
+ */
+
+#define CHIP_AU8820
+
+#define CARD_NAME "Aureal Vortex 3D Sound Processor"
+#define CARD_NAME_SHORT "au8820"
+
+#ifndef PCI_VENDOR_ID_AUREAL
+#define PCI_VENDOR_ID_AUREAL 0x12eb
+#endif
+
+#ifndef PCI_VENDOR_ID_AUREAL_VORTEX
+#define PCI_DEVICE_ID_AUREAL_VORTEX 0x0001
+#endif
+
+/* Number of ADB and WT channels */
+#define NR_ADB		0x10
+#define NR_WT		0x20
+#define NR_SRC		0x10
+#define NR_A3D		0x00
+#define NR_MIXIN	0x10
+#define NR_MIXOUT 	0x10
+
+
+/* ADBDMA */
+#define VORTEX_ADBDMA_STAT 0x105c0	/* read only, subbuffer, DMA pos */
+#define		POS_MASK 0x00000fff
+#define     POS_SHIFT 0x0
+#define 	ADB_SUBBUF_MASK 0x00003000	/* ADB only. */
+#define     ADB_SUBBUF_SHIFT 0xc	/* ADB only. */
+#define VORTEX_ADBDMA_CTRL 0x10580	/* write only, format, flags, DMA pos */
+#define		OFFSET_MASK 0x00000fff
+#define     OFFSET_SHIFT 0x0
+#define		IE_MASK 0x00001000	/* interrupt enable. */
+#define     IE_SHIFT 0xc
+#define     DIR_MASK 0x00002000	/* Direction. */
+#define     DIR_SHIFT 0xd
+#define		FMT_MASK 0x0003c000
+#define		FMT_SHIFT 0xe
+// The masks and shift also work for the wtdma, if not specified otherwise.
+#define VORTEX_ADBDMA_BUFCFG0 0x10400
+#define VORTEX_ADBDMA_BUFCFG1 0x10404
+#define VORTEX_ADBDMA_BUFBASE 0x10200
+#define VORTEX_ADBDMA_START 0x106c0	/* Which subbuffer starts */
+#define VORTEX_ADBDMA_STATUS 0x10600	/* stored at AdbDma->this_10 / 2 DWORD in size. */
+
+/* ADB */
+#define VORTEX_ADB_SR 0x10a00	/* Samplerates enable/disable */
+#define VORTEX_ADB_RTBASE 0x10800
+#define VORTEX_ADB_RTBASE_SIZE (VORTEX_ADB_CHNBASE - VORTEX_ADB_RTBASE)
+#define VORTEX_ADB_CHNBASE 0x1099c
+#define VORTEX_ADB_CHNBASE_SIZE (ADB_MASK - VORTEX_ADB_RTBASE_SIZE)
+#define 	ROUTE_MASK	0x3fff
+#define     ADB_MASK   0x7f
+#define		ADB_SHIFT 0x7
+//#define     ADB_MIX_MASK 0xf
+/* ADB address */
+#define		OFFSET_ADBDMA	0x00
+#define		OFFSET_SRCOUT	0x10	/* on channel 0x11 */
+#define		OFFSET_SRCIN	0x10	/* on channel < 0x11 */
+#define		OFFSET_MIXOUT	0x20	/* source */
+#define		OFFSET_MIXIN	0x30	/* sink */
+#define		OFFSET_CODECIN	0x48	/* ADB source */
+#define		OFFSET_CODECOUT	0x58	/* ADB sink/target */
+#define		OFFSET_SPORTOUT	0x60	/* sink */
+#define		OFFSET_SPORTIN	0x50	/* source */
+#define		OFFSET_EFXOUT	0x50	/* sink */
+#define		OFFSET_EFXIN	0x40	/* source */
+#define		OFFSET_A3DOUT	0x00	/* This card has no HRTF :( */
+#define		OFFSET_A3DIN	0x00
+#define		OFFSET_WTOUT	0x58	/*  */
+
+/* ADB route translate helper */
+#define ADB_DMA(x) (x + OFFSET_ADBDMA)
+#define ADB_SRCOUT(x) (x + OFFSET_SRCOUT)
+#define ADB_SRCIN(x) (x + OFFSET_SRCIN)
+#define ADB_MIXOUT(x) (x + OFFSET_MIXOUT)
+#define ADB_MIXIN(x) (x + OFFSET_MIXIN)
+#define ADB_CODECIN(x) (x + OFFSET_CODECIN)
+#define ADB_CODECOUT(x) (x + OFFSET_CODECOUT)
+#define ADB_SPORTOUT(x) (x + OFFSET_SPORTOUT)
+#define ADB_SPORTIN(x) (x + OFFSET_SPORTIN)	/*  */
+#define ADB_A3DOUT(x) (x + OFFSET_A3DOUT)	/* 8 A3D blocks */
+#define ADB_A3DIN(x) (x + OFFSET_A3DIN)
+#define ADB_WTOUT(x,y) (y + OFFSET_WTOUT)
+
+/* WTDMA */
+#define VORTEX_WTDMA_CTRL 0x10500	/* format, DMA pos */
+#define VORTEX_WTDMA_STAT 0x10500	/* DMA subbuf, DMA pos */
+#define     WT_SUBBUF_MASK (0x3 << WT_SUBBUF_SHIFT)
+#define     WT_SUBBUF_SHIFT 0x15
+#define VORTEX_WTDMA_BUFBASE 0x10000
+#define VORTEX_WTDMA_BUFCFG0 0x10300
+#define VORTEX_WTDMA_BUFCFG1 0x10304
+#define VORTEX_WTDMA_START 0x10640	/* which subbuffer is first */
+
+#define VORTEX_WT_BASE 0x9000
+
+/* MIXER */
+#define VORTEX_MIXER_SR 0x9f00
+#define VORTEX_MIXER_CLIP 0x9f80
+#define VORTEX_MIXER_CHNBASE 0x9e40
+#define VORTEX_MIXER_RTBASE 0x9e00
+#define 	MIXER_RTBASE_SIZE 0x26
+#define VORTEX_MIX_ENIN 0x9a00	/* Input enable bits. 4 bits wide. */
+#define VORTEX_MIX_SMP 0x9c00
+
+/* MIX */
+#define VORTEX_MIX_INVOL_A 0x9000	/* in? */
+#define VORTEX_MIX_INVOL_B 0x8000	/* out? */
+#define VORTEX_MIX_VOL_A 0x9800
+#define VORTEX_MIX_VOL_B 0x8800
+
+#define 	VOL_MIN 0x80	/* Input volume when muted. */
+#define		VOL_MAX 0x7f	/* FIXME: Not confirmed! Just guessed. */
+
+//#define MIX_OUTL    0xe
+//#define MIX_OUTR    0xf
+//#define MIX_INL     0xe
+//#define MIX_INR     0xf
+#define MIX_DEFIGAIN 0x08	/* 0x8 => 6dB */
+#define MIX_DEFOGAIN 0x08
+
+/* SRC */
+#define VORTEX_SRCBLOCK_SR	0xccc0
+#define VORTEX_SRC_CHNBASE	0xcc40
+#define VORTEX_SRC_RTBASE	0xcc00
+#define VORTEX_SRC_SOURCE	0xccc4
+#define VORTEX_SRC_SOURCESIZE 0xccc8
+#define VORTEX_SRC_U0		0xce00
+#define VORTEX_SRC_DRIFT0	0xce80
+#define VORTEX_SRC_DRIFT1	0xcec0
+#define VORTEX_SRC_U1		0xcf00
+#define VORTEX_SRC_DRIFT2	0xcf40
+#define VORTEX_SRC_U2		0xcf80
+#define VORTEX_SRC_DATA		0xc800
+#define VORTEX_SRC_DATA0	0xc000
+#define VORTEX_SRC_CONVRATIO 0xce40
+//#define     SRC_RATIO(x) ((((x<<15)/48000) + 1)/2) /* Playback */
+//#define     SRC_RATIO2(x) ((((48000<<15)/x) + 1)/2) /* Recording */
+
+/* FIFO */
+#define VORTEX_FIFO_ADBCTRL 0xf800	/* Control bits. */
+#define VORTEX_FIFO_WTCTRL 0xf840
+#define		FIFO_RDONLY	0x00000001
+#define		FIFO_CTRL	0x00000002	/* Allow ctrl. ? */
+#define		FIFO_VALID	0x00000010
+#define 	FIFO_EMPTY	0x00000020
+#define		FIFO_U0		0x00001000	/* Unknown. */
+#define		FIFO_U1		0x00010000
+#define		FIFO_SIZE_BITS 5
+#define		FIFO_SIZE	(1<<FIFO_SIZE_BITS)	// 0x20
+#define 	FIFO_MASK	(FIFO_SIZE-1)	//0x1f    /* at shift left 0xc */
+#define VORTEX_FIFO_ADBDATA 0xe000
+#define VORTEX_FIFO_WTDATA 0xe800
+
+/* CODEC */
+#define VORTEX_CODEC_CTRL 0x11984
+#define VORTEX_CODEC_EN 0x11990
+#define		EN_CODEC	0x00000300
+#define		EN_SPORT	0x00030000
+#define		EN_SPDIF	0x000c0000
+#define VORTEX_CODEC_CHN 0x11880
+#define VORTEX_CODEC_WRITE 0x00800000
+#define VORTEX_CODEC_ADDSHIFT 16
+#define VORTEX_CODEC_ADDMASK 0x7f0000	/* 0x000f0000 */
+#define VORTEX_CODEC_DATSHIFT 0
+#define VORTEX_CODEC_DATMASK 0xffff
+#define VORTEX_CODEC_IO 0x11988
+
+#define VORTEX_SPDIF_FLAGS		0x1005c	/* FIXME */
+#define VORTEX_SPDIF_CFG0		0x119D0
+#define VORTEX_SPDIF_CFG1		0x119D4
+#define VORTEX_SPDIF_SMPRATE	0x11994
+
+/* Sample timer */
+#define VORTEX_SMP_TIME 0x11998
+
+/* IRQ */
+#define VORTEX_IRQ_SOURCE 0x12800	/* Interrupt source flags. */
+#define VORTEX_IRQ_CTRL 0x12804	/* Interrupt source mask. */
+
+#define VORTEX_STAT		0x12808	/* ?? */
+
+#define VORTEX_CTRL 0x1280c
+#define 	CTRL_MIDI_EN 0x00000001
+#define 	CTRL_MIDI_PORT 0x00000060
+#define 	CTRL_GAME_EN 0x00000008
+#define 	CTRL_GAME_PORT 0x00000e00
+#define 	CTRL_IRQ_ENABLE 0x4000
+
+/* write: Timer period config / read: TIMER IRQ ack. */
+#define VORTEX_IRQ_STAT 0x1199c
+
+/* DMA */
+#define VORTEX_DMA_BUFFER 0x10200
+#define VORTEX_ENGINE_CTRL 0x1060c
+#define 	ENGINE_INIT 0x0L
+
+		     /* MIDI *//* GAME. */
+#define VORTEX_MIDI_DATA 0x11000
+#define VORTEX_MIDI_CMD 0x11004	/* Write command / Read status */
+#define VORTEX_GAME_LEGACY 0x11008
+#define VORTEX_CTRL2 0x1100c
+#define 	CTRL2_GAME_ADCMODE 0x40
+#define VORTEX_GAME_AXIS 0x11010
+#define 	AXIS_SIZE 4
+#define		AXIS_RANGE 0x1fff
--- diff/sound/pci/au88x0/au8830.c	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au8830.c	2004-03-16 09:37:58.488648544 +0000
@@ -0,0 +1,18 @@
+#include "au8830.h"
+#include "au88x0.h"
+static struct pci_device_id snd_vortex_ids[] = {
+	{PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,},
+	{0,}
+};
+
+#include "au88x0_synth.c"
+#include "au88x0_core.c"
+#include "au88x0_pcm.c"
+#include "au88x0_mixer.c"
+#include "au88x0_mpu401.c"
+#include "au88x0_game.c"
+#include "au88x0_eq.c"
+#include "au88x0_a3d.c"
+#include "au88x0_xtalk.c"
+#include "au88x0.c"
--- diff/sound/pci/au88x0/au8830.h	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au8830.h	2004-03-16 09:37:58.489648392 +0000
@@ -0,0 +1,266 @@
+/*
+    Aureal Vortex Soundcard driver.
+
+    IO addr collected from asp4core.vxd:
+    function    address
+    0005D5A0    13004
+    00080674    14004
+    00080AFF    12818
+
+ */
+
+#define CHIP_AU8830
+
+#define CARD_NAME "Aureal Vortex 2 3D Sound Processor"
+#define CARD_NAME_SHORT "au8830"
+
+#ifndef PCI_VENDOR_ID_AUREAL
+#define PCI_VENDOR_ID_AUREAL 0x12eb
+#endif
+#ifndef PCI_VENDOR_ID_AUREAL_VORTEX2
+#define PCI_DEVICE_ID_AUREAL_VORTEX2 0x0002
+#endif
+
+#define hwread(x,y) readl((x)+((y)>>2))
+#define hwwrite(x,y,z) writel((z),(x)+((y)>>2))
+
+#define NR_ADB 0x20
+#define NR_SRC 0x10
+#define NR_A3D 0x10
+#define NR_MIXIN 0x20
+#define NR_MIXOUT 0x10
+#define NR_WT 0x40
+
+/* ADBDMA */
+#define VORTEX_ADBDMA_STAT 0x27e00	/* read only, subbuffer, DMA pos */
+#define		POS_MASK 0x00000fff
+#define     POS_SHIFT 0x0
+#define 	ADB_SUBBUF_MASK 0x00003000	/* ADB only. */
+#define     ADB_SUBBUF_SHIFT 0xc	/* ADB only. */
+#define VORTEX_ADBDMA_CTRL 0x27a00	/* write only; format, flags, DMA pos */
+#define		OFFSET_MASK 0x00000fff
+#define     OFFSET_SHIFT 0x0
+#define		IE_MASK 0x00001000	/* interrupt enable. */
+#define     IE_SHIFT 0xc
+#define     DIR_MASK 0x00002000	/* Direction. */
+#define     DIR_SHIFT 0xd
+#define		FMT_MASK 0x0003c000
+#define		FMT_SHIFT 0xe
+#define		ADB_FIFO_EN_SHIFT	0x15
+#define		ADB_FIFO_EN			(1 << 0x15)
+// The ADB masks and shift also are valid for the wtdma, except if specified otherwise.
+#define VORTEX_ADBDMA_BUFCFG0 0x27800
+#define VORTEX_ADBDMA_BUFCFG1 0x27804
+#define VORTEX_ADBDMA_BUFBASE 0x27400
+#define VORTEX_ADBDMA_START 0x27c00	/* Which subbuffer starts */
+
+#define VORTEX_ADBDMA_STATUS 0x27A90	/* stored at AdbDma->this_10 / 2 DWORD in size. */
+/* Starting at MSB, each pair seem to be the current DMA page. */
+/* This current page bits are consistent (same value) with VORTEX_ADBDMA_STAT) */
+
+/* DMA */
+#define VORTEX_ENGINE_CTRL 0x27ae8
+#define 	ENGINE_INIT 0x1380000
+
+/* WTDMA */
+#define VORTEX_WTDMA_CTRL 0x27900	/* format, DMA pos */
+#define VORTEX_WTDMA_STAT 0x27d00	/* DMA subbuf, DMA pos */
+#define     WT_SUBBUF_MASK 0x3
+#define     WT_SUBBUF_SHIFT 0xc
+#define VORTEX_WTDMA_BUFBASE 0x27000
+#define VORTEX_WTDMA_BUFCFG0 0x27600
+#define VORTEX_WTDMA_BUFCFG1 0x27604
+#define VORTEX_WTDMA_START 0x27b00	/* which subbuffer is first */
+
+/* ADB */
+#define VORTEX_ADB_SR 0x28400	/* Samplerates enable/disable */
+#define VORTEX_ADB_RTBASE 0x28000
+#define VORTEX_ADB_RTBASE_SIZE (VORTEX_ADB_CHNBASE - VORTEX_ADB_RTBASE)
+#define VORTEX_ADB_CHNBASE 0x282b4
+#define VORTEX_ADB_CHNBASE_SIZE (ADB_MASK - VORTEX_ADB_RTBASE_SIZE)
+#define 	ROUTE_MASK	0xffff
+#define		SOURCE_MASK	0xff00
+#define     ADB_MASK   0xff
+#define		ADB_SHIFT 0x8
+/* ADB address */
+#define		OFFSET_ADBDMA	0x00
+#define		OFFSET_ADBDMAB	0x20
+#define		OFFSET_SRCIN	0x40
+#define		OFFSET_SRCOUT	0x20	/* ch 0x11 */
+#define		OFFSET_MIXIN	0x50	/* ch 0x11 */
+#define		OFFSET_MIXOUT	0x30	/* ch 0x11 */
+#define		OFFSET_CODECIN	0x70 /* ch 0x11 */	/* adb source */
+#define		OFFSET_CODECOUT	0x88 /* ch 0x11 */	/* adb target */
+#define		OFFSET_SPORTIN	0x78	/* ch 0x13 ADB source. 2 routes. */
+#define		OFFSET_SPORTOUT	0x90	/* ch 0x13 ADB sink. 2 routes. */
+#define		OFFSET_SPDIFIN	0x7A	/* ch 0x14 ADB source. */
+#define		OFFSET_SPDIFOUT	0x92	/* ch 0x14 ADB sink. */
+#define		OFFSET_AC98IN	0x7c	/* ch 0x14 ADB source. */
+#define		OFFSET_AC98OUT	0x94	/* ch 0x14 ADB sink. */
+#define		OFFSET_EQIN		0xa0	/* ch 0x11 */
+#define		OFFSET_EQOUT	0x7e /* ch 0x11 */	/* 2 routes on ch 0x11 */
+#define		OFFSET_A3DIN	0x70	/* ADB sink. */
+#define		OFFSET_A3DOUT	0xA6	/* ADB source. 2 routes per slice = 8 */
+#define		OFFSET_WT0		0x40	/* WT bank 0 output. 0x40 - 0x65 */
+#define		OFFSET_WT1		0x80	/* WT bank 1 output. 0x80 - 0xA5 */
+/* WT sources offset : 0x00-0x1f Direct stream. */
+/* WT sources offset : 0x20-0x25 Mixed Output. */
+#define		OFFSET_XTALKOUT	0x66	/* crosstalk canceller (source) 2 routes */
+#define		OFFSET_XTALKIN	0x96	/* crosstalk canceller (sink). 10 routes */
+#define		OFFSET_EFXOUT	0x68	/* ADB source. 8 routes. */
+#define		OFFSET_EFXIN	0x80	/* ADB sink. 8 routes. */
+
+/* ADB route translate helper */
+#define ADB_DMA(x) (x)
+#define ADB_SRCOUT(x) (x + OFFSET_SRCOUT)
+#define ADB_SRCIN(x) (x + OFFSET_SRCIN)
+#define ADB_MIXOUT(x) (x + OFFSET_MIXOUT)
+#define ADB_MIXIN(x) (x + OFFSET_MIXIN)
+#define ADB_CODECIN(x) (x + OFFSET_CODECIN)
+#define ADB_CODECOUT(x) (x + OFFSET_CODECOUT)
+#define ADB_SPORTIN(x) (x + OFFSET_SPORTIN)
+#define ADB_SPORTOUT(x) (x + OFFSET_SPORTOUT)
+#define ADB_SPDIFIN(x)	(x + OFFSET_SPDIFIN)
+#define ADB_SPDIFOUT(x)	(x + OFFSET_SPDIFOUT)
+#define ADB_EQIN(x) (x + OFFSET_EQIN)
+#define ADB_EQOUT(x) (x + OFFSET_EQOUT)
+#define ADB_A3DOUT(x) (x + OFFSET_A3DOUT)	/* 0x10 A3D blocks */
+#define ADB_A3DIN(x) (x + OFFSET_A3DIN)
+//#define ADB_WTOUT(x) ((x<x20)?(x + OFFSET_WT0):(x + OFFSET_WT1))
+#define ADB_WTOUT(x,y) (((x)==0)?((y) + OFFSET_WT0):((y) + OFFSET_WT1))
+#define ADB_XTALKIN(x) ((x) + OFFSET_XTALKIN)
+#define ADB_XTALKOUT(x) ((x) + OFFSET_XTALKOUT)
+
+#define MIX_DEFIGAIN 0x08
+#define MIX_DEFOGAIN 0x08	/* 0x8->6dB  (6dB = x4) 16 to 18 bit conversion? */
+
+/* MIXER */
+#define VORTEX_MIXER_SR 0x21f00
+#define VORTEX_MIXER_CLIP 0x21f80
+#define VORTEX_MIXER_CHNBASE 0x21e40
+#define VORTEX_MIXER_RTBASE 0x21e00
+#define 	MIXER_RTBASE_SIZE 0x38
+#define VORTEX_MIX_ENIN 0x21a00	/* Input enable bits. 4 bits wide. */
+#define VORTEX_MIX_SMP 0x21c00	/* wave data buffers. AU8820: 0x9c00 */
+
+/* MIX */
+#define VORTEX_MIX_INVOL_B 0x20000	/* Input volume current */
+#define VORTEX_MIX_VOL_B 0x20800	/* Output Volume current */
+#define VORTEX_MIX_INVOL_A 0x21000	/* Input Volume target */
+#define VORTEX_MIX_VOL_A 0x21800	/* Output Volume target */
+
+#define 	VOL_MIN 0x80	/* Input volume when muted. */
+#define		VOL_MAX 0x7f	/* FIXME: Not confirmed! Just guessed. */
+
+/* SRC */
+#define VORTEX_SRC_CHNBASE		0x26c40
+#define VORTEX_SRC_RTBASE		0x26c00
+#define VORTEX_SRCBLOCK_SR		0x26cc0
+#define VORTEX_SRC_SOURCE		0x26cc4
+#define VORTEX_SRC_SOURCESIZE	0x26cc4
+/* Params
+	0x26e00	: 1 U0
+	0x26e40	: 2 CR
+	0x26e80	: 3 U3
+	0x26ec0	: 4 DRIFT1
+	0x26f00 : 5 U1
+	0x26f40	: 6 DRIFT2
+	0x26f80	: 7 U2 : Target rate, direction
+*/
+
+#define VORTEX_SRC_CONVRATIO	0x26e40
+#define VORTEX_SRC_DRIFT0		0x26e80
+#define VORTEX_SRC_DRIFT1		0x26ec0
+#define VORTEX_SRC_DRIFT2		0x26f40
+#define VORTEX_SRC_U0			0x26e00
+#define		U0_SLOWLOCK		0x200
+#define VORTEX_SRC_U1			0x26f00
+#define VORTEX_SRC_U2			0x26f80
+#define VORTEX_SRC_DATA			0x26800	/* 0xc800 */
+#define VORTEX_SRC_DATA0		0x26000
+
+/* FIFO */
+#define VORTEX_FIFO_ADBCTRL 0x16100	/* Control bits. */
+#define VORTEX_FIFO_WTCTRL 0x16000
+#define		FIFO_RDONLY	0x00000001
+#define		FIFO_CTRL	0x00000002	/* Allow ctrl. ? */
+#define		FIFO_VALID	0x00000010
+#define 	FIFO_EMPTY	0x00000020
+#define		FIFO_U0		0x00002000	/* Unknown. */
+#define		FIFO_U1		0x00040000
+#define		FIFO_SIZE_BITS 6
+#define		FIFO_SIZE	(1<<(FIFO_SIZE_BITS))	// 0x40
+#define 	FIFO_MASK	(FIFO_SIZE-1)	//0x3f    /* at shift left 0xc */
+#define 	FIFO_BITS	0x1c400000
+#define VORTEX_FIFO_ADBDATA 0x14000
+#define VORTEX_FIFO_WTDATA 0x10000
+
+#define VORTEX_FIFO_GIRT	0x17000	/* wt0, wt1, adb */
+#define		GIRT_COUNT	3
+
+/* CODEC */
+
+#define VORTEX_CODEC_CHN 0x29080	/* The name "CHN" is wrong. */
+
+#define VORTEX_CODEC_CTRL 0x29184
+#define VORTEX_CODEC_IO 0x29188
+#define 	VORTEX_CODEC_WRITE 0x00800000
+#define 	VORTEX_CODEC_ADDSHIFT 16
+#define 	VORTEX_CODEC_ADDMASK 0x7f0000	/* 0x000f0000 */
+#define 	VORTEX_CODEC_DATSHIFT 0
+#define 	VORTEX_CODEC_DATMASK 0xffff
+
+#define VORTEX_CODEC_SPORTCTRL 0x2918c
+
+#define VORTEX_CODEC_EN 0x29190
+#define		EN_AUDIO0		0x00000300
+#define		EN_MODEM		0x00000c00
+#define		EN_AUDIO1		0x00003000
+#define		EN_SPORT		0x00030000
+#define		EN_SPDIF		0x000c0000
+#define		EN_CODEC		(EN_AUDIO1 | EN_AUDIO0)
+
+#define VORTEX_SPDIF_SMPRATE	0x29194
+
+#define VORTEX_SPDIF_FLAGS		0x2205c
+#define VORTEX_SPDIF_CFG0		0x291D0	/* status data */
+#define VORTEX_SPDIF_CFG1		0x291D4
+
+#define VORTEX_SMP_TIME			0x29198	/* Sample counter/timer */
+#define VORTEX_SMP_TIMER		0x2919c
+#define VORTEX_CODEC2_CTRL		0x291a0
+
+#define VORTEX_MODEM_CTRL		0x291ac
+
+/* IRQ */
+#define VORTEX_IRQ_SOURCE 0x2a000	/* Interrupt source flags. */
+#define VORTEX_IRQ_CTRL 0x2a004	/* Interrupt source mask. */
+
+//#define VORTEX_IRQ_U0 0x2a008 /* ?? */
+#define VORTEX_STAT		0x2a008	/* Some sort of status */
+#define 	STAT_IRQ	0x00000001	/* This bitis set if the IRQ is valid. */
+
+#define VORTEX_CTRL		0x2a00c
+#define 	CTRL_MIDI_EN	0x00000001
+#define 	CTRL_MIDI_PORT	0x00000060
+#define 	CTRL_GAME_EN	0x00000008
+#define 	CTRL_GAME_PORT	0x00000e00
+#define 	CTRL_IRQ_ENABLE	0x00004000
+#define		CTRL_SPDIF		0x00000000	/* unknown. Please find this value */
+#define 	CTRL_SPORT		0x00200000
+#define 	CTRL_RST		0x00800000
+#define 	CTRL_UNKNOWN	0x01000000
+
+/* write: Timer period config / read: TIMER IRQ ack. */
+#define VORTEX_IRQ_STAT 0x2919c
+
+		     /* MIDI *//* GAME. */
+#define VORTEX_MIDI_DATA 0x28800
+#define VORTEX_MIDI_CMD 0x28804	/* Write command / Read status */
+
+#define VORTEX_GAME_LEGACY 0x28808
+#define VORTEX_CTRL2 0x2880c
+#define		CTRL2_GAME_ADCMODE 0x40
+#define VORTEX_GAME_AXIS 0x28810	/* Axis base register. 4 axis's */
+#define		AXIS_SIZE 4
+#define		AXIS_RANGE 0x1fff
--- diff/sound/pci/au88x0/au88x0.c	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au88x0.c	2004-03-16 09:37:58.490648240 +0000
@@ -0,0 +1,419 @@
+/*
+ * ALSA driver for the Aureal Vortex family of soundprocessors.
+ * Author: Manuel Jander (mjander@embedded.cl)
+ *
+ *   This driver is the result of the OpenVortex Project from Savannah
+ * (savannah.nongnu.org/projects/openvortex). I would like to thank
+ * the developers of OpenVortex, Jeff Muizelar and Kester Maddock, from
+ * whom i got plenty of help, and their codebase was invaluable.
+ *   Thanks to the ALSA developers, they helped a lot working out
+ * the ALSA part.
+ *   Thanks also to Sourceforge for maintaining the old binary drivers,
+ * and the forum, where developers could comunicate.
+ *
+ * Now at least i can play Legacy DOOM with MIDI music :-)
+ */
+
+#include "au88x0.h"
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#define SNDRV_GET_ID
+#include <sound/initval.h>
+
+// module parameters (see "Module Parameters")
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static int pcifix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 255 };
+
+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(pcifix, "1-255i");
+MODULE_PARM_DESC(pcifix, "Enable VIA-workaround for " CARD_NAME " soundcard.");
+MODULE_PARM_SYNTAX(pcifix,
+		   SNDRV_ENABLED
+		   ",allows:{{0,Disabled},{1,Latency},{2,Bridge},{3,Both},{255,Auto}},default:4,dialog:check");
+
+MODULE_DESCRIPTION("Aureal vortex");
+MODULE_CLASSES("{sound}");
+MODULE_LICENSE("GPL");
+MODULE_DEVICES("{{Aureal Semiconductor Inc., Aureal Vortex Sound Processor}}");
+
+#ifndef MODULE
+/* format is: snd-mychip=enable,index,id */
+static int __init alsa_card_vortex_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-au88x0=", alsa_card_vortex_setup);
+#endif				/* ifndef MODULE */
+
+MODULE_DEVICE_TABLE(pci, snd_vortex_ids);
+
+static void __devinit snd_vortex_workaround(struct pci_dev *vortex, int fix)
+{
+	struct pci_dev *via = NULL;
+	/* autodetect if workarounds are required */
+	while ((via = pci_find_device(PCI_VENDOR_ID_VIA,
+				      PCI_DEVICE_ID_VIA_8365_1, via))) {
+		if (fix == 255) {
+			printk(KERN_INFO CARD_NAME
+			       ": detected VIA KT133/KM133. activating workaround...\n");
+			fix = 3;	// do latency and via bridge workaround
+		}
+		break;
+	}
+
+	/* do not do anything if autodetection was enabled and found no VIA */
+	if (fix == 255)
+		return;
+
+	int rc;
+
+	/* fix vortex latency */
+	if (fix & 0x01) {
+		if (!(rc = pci_write_config_byte(vortex, 0x40, 0xff))) {
+			printk(KERN_INFO CARD_NAME
+			       ": vortex latency is 0xff\n");
+		} else {
+			printk(KERN_WARNING CARD_NAME
+			       ": could not set vortex latency: pci error 0x%x\n",
+			       rc);
+		}
+	}
+
+	/* fix via agp bridge */
+	if (via && (fix & 0x02)) {
+		u8 value;
+
+		/*
+		 * only set the bit (Extend PCI#2 Internal Master for
+		 * Efficient Handling of Dummy Requests) if the can
+		 * read the config and it is not already set
+		 */
+
+		if (!(rc = pci_read_config_byte(via, 0x42, &value))
+		    && ((value & 0x10)
+			|| !(rc =
+			     pci_write_config_byte(via, 0x42, value | 0x10)))) {
+
+			printk(KERN_INFO CARD_NAME
+			       ": bridge config is 0x%x\n", value | 0x10);
+		} else {
+			printk(KERN_WARNING CARD_NAME
+			       ": could not set vortex latency: pci error 0x%x\n",
+			       rc);
+		}
+	}
+}
+
+// component-destructor
+// (see "Management of Cards and Components")
+static int snd_vortex_dev_free(snd_device_t * device)
+{
+	vortex_t *vortex = snd_magic_cast(vortex_t, device->device_data,
+					  return -ENXIO);
+
+	vortex_gameport_unregister(vortex);
+	vortex_core_shutdown(vortex);
+	// Take down PCI interface.
+	synchronize_irq(vortex->irq);
+	free_irq(vortex->irq, vortex);
+	pci_release_regions(vortex->pci_dev);
+	pci_disable_device(vortex->pci_dev);
+	snd_magic_kfree(vortex);
+
+	return 0;
+}
+
+// chip-specific constructor
+// (see "Management of Cards and Components")
+static int __devinit
+snd_vortex_create(snd_card_t * card, struct pci_dev *pci, vortex_t ** rchip)
+{
+	vortex_t *chip;
+	int err;
+	static snd_device_ops_t ops = {
+		.dev_free = snd_vortex_dev_free,
+	};
+
+	*rchip = NULL;
+
+	// check PCI availability (DMA).
+	if ((err = pci_enable_device(pci)) < 0)
+		return err;
+	if (!pci_dma_supported(pci, VORTEX_DMA_MASK)) {
+		printk(KERN_ERR "error to set DMA mask\n");
+		return -ENXIO;
+	}
+	pci_set_dma_mask(pci, VORTEX_DMA_MASK);
+
+	chip = snd_magic_kcalloc(vortex_t, 0, GFP_KERNEL);
+	if (chip == NULL)
+		return -ENOMEM;
+
+	chip->card = card;
+
+	// initialize the stuff
+	chip->pci_dev = pci;
+	chip->io = pci_resource_start(pci, 0);
+	chip->vendor = pci->vendor;
+	chip->device = pci->device;
+	chip->card = card;
+	chip->irq = -1;
+
+	// (1) PCI resource allocation
+	// Get MMIO area
+	//
+	if ((err = pci_request_regions(pci, CARD_NAME_SHORT)) != 0)
+		goto regions_out;
+
+	chip->mmio =
+	    ioremap_nocache(pci_resource_start(pci, 0),
+			    pci_resource_len(pci, 0));
+	if (!chip->mmio) {
+		printk(KERN_ERR "MMIO area remap failed.\n");
+		err = -ENOMEM;
+		goto ioremap_out;
+	}
+
+	/* Init audio core.
+	 * This must be done before we do request_irq otherwise we can get spurious
+	 * interupts that we do not handle properly and make a mess of things */
+	if ((err = vortex_core_init(chip)) != 0) {
+		printk(KERN_ERR "hw core init failed\n");
+		goto core_out;
+	}
+
+	if ((err =
+	     request_irq(pci->irq, vortex_interrupt,
+			 SA_INTERRUPT | SA_SHIRQ, CARD_NAME_SHORT,
+			 (void *)chip)) != 0) {
+		printk(KERN_ERR "cannot grab irq\n");
+		goto irq_out;
+	}
+	chip->irq = pci->irq;
+
+	pci_set_master(pci);
+	// End of PCI setup.
+
+	// Register alsa root device.
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
+		goto alloc_out;
+	}
+
+	*rchip = chip;
+
+	return 0;
+
+      alloc_out:
+	synchronize_irq(chip->irq);
+	free_irq(chip->irq, chip);
+      irq_out:
+	vortex_core_shutdown(chip);
+      core_out:
+	//FIXME: the type of chip->mmio might need to be changed??
+	iounmap((void *)chip->mmio);
+      ioremap_out:
+	pci_release_regions(chip->pci_dev);
+      regions_out:
+	pci_disable_device(chip->pci_dev);
+	//FIXME: this not the right place to unregister the gameport
+	vortex_gameport_unregister(chip);
+	return err;
+}
+
+// constructor -- see "Constructor" sub-section
+static int __devinit
+snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+{
+	static int dev;
+	snd_card_t *card;
+	vortex_t *chip;
+	int err;
+
+	// (1)
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+	// (2)
+	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+	if (card == NULL)
+		return -ENOMEM;
+
+	// (3)
+	if ((err = snd_vortex_create(card, pci, &chip)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	snd_vortex_workaround(pci, pcifix[dev]);
+	// (4) Alloc components.
+	// ADB pcm.
+	if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_ADB, NR_ADB)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+#ifndef CHIP_AU8820
+	// ADB SPDIF
+	if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_SPDIF, 1)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	// A3D
+	if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_A3D, NR_A3D)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+#endif
+	/*
+	   // ADB I2S
+	   if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_I2S, 1)) < 0) {
+	   snd_card_free(card);
+	   return err;
+	   }
+	 */
+#ifndef CHIP_AU8810
+	// WT pcm.
+	if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_WT, NR_WT)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+#endif
+	// snd_ac97_mixer and Vortex mixer.
+	if ((err = snd_vortex_mixer(chip)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	if ((err = snd_vortex_midi(chip)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	if ((err = vortex_gameport_register(chip)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+#if 0
+	if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_VORTEX_SYNTH,
+			       sizeof(snd_vortex_synth_arg_t), &wave) < 0
+	    || wave == NULL) {
+		snd_printk("Can't initialize Aureal wavetable synth\n");
+	} else {
+		snd_vortex_synth_arg_t *arg;
+
+		arg = SNDRV_SEQ_DEVICE_ARGPTR(wave);
+		strcpy(wave->name, "Aureal Synth");
+		arg->hwptr = vortex;
+		arg->index = 1;
+		arg->seq_ports = seq_ports[dev];
+		arg->max_voices = max_synth_voices[dev];
+	}
+#endif
+
+	// (5)
+	strcpy(card->driver, "Aureal Vortex");
+	strcpy(card->shortname, CARD_NAME_SHORT);
+	sprintf(card->longname, "%s at 0x%lx irq %i",
+		card->shortname, chip->io, chip->irq);
+
+#ifdef CHIP_AU8830
+	{
+		unsigned char revision;
+		if ((err =
+		     pci_read_config_byte(pci, PCI_REVISION_ID,
+					  &revision)) < 0) {
+			snd_card_free(card);
+			return err;
+		}
+
+		if (revision != 0xfe && revision != 0xfa) {
+			printk(KERN_ALERT
+			       "vortex: The revision (%x) of your card has not been seen before.\n",
+			       revision);
+			printk(KERN_ALERT
+			       "vortex: Please email the results of 'lspci -vv' to openvortex-dev@nongnu.org.\n");
+			snd_card_free(card);
+			err = -ENODEV;
+			return err;
+		}
+	}
+#endif
+	// (6)
+	if ((err = snd_card_register(card)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	// (7)
+	pci_set_drvdata(pci, chip);
+	dev++;
+	vortex_connect_default(chip, 1);
+	vortex_enable_int(chip);
+	return 0;
+}
+
+// destructor -- see "Destructor" sub-section
+static void __devexit snd_vortex_remove(struct pci_dev *pci)
+{
+	vortex_t *vortex = snd_magic_cast(vortex_t,
+					  pci_get_drvdata(pci), return);
+
+	if (vortex) {
+		// Release ALSA stuff.
+		snd_card_free(vortex->card);
+		// Free Vortex struct.
+		pci_set_drvdata(pci, NULL);
+	} else
+		printk("snd_vortex_remove called more than one time!\n");
+}
+
+// pci_driver definition
+static struct pci_driver driver = {
+	.name = CARD_NAME_SHORT,
+	.id_table = snd_vortex_ids,
+	.probe = snd_vortex_probe,
+	.remove = __devexit_p(snd_vortex_remove),
+};
+
+// initialization of the module
+static int __init alsa_card_vortex_init(void)
+{
+	int err;
+
+	if ((err = pci_module_init(&driver)) < 0) {
+#ifdef MODULE
+		printk(KERN_ERR "Aureal soundcard not found "
+		       "or device busy\n");
+#endif
+		return err;
+	}
+	return 0;
+}
+
+// clean up the module
+static void __exit alsa_card_vortex_exit(void)
+{
+	pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_vortex_init)
+module_exit(alsa_card_vortex_exit)
--- diff/sound/pci/au88x0/au88x0.h	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au88x0.h	2004-03-16 09:37:58.491648088 +0000
@@ -0,0 +1,286 @@
+/*
+    Aureal Vortex Soundcard driver.
+
+    IO addr collected from asp4core.vxd:
+    function    address
+    0005D5A0    13004
+    00080674    14004
+    00080AFF    12818
+
+ */
+
+#ifndef __SOUND_AU88X0_H
+#define __SOUND_AU88X0_H
+
+#ifdef __KERNEL__
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/rawmidi.h>
+#include <sound/mpu401.h>
+#include <sound/hwdep.h>
+#include <sound/ac97_codec.h>
+
+/*
+#ifndef	PCI_VENDOR_ID_AUREAL
+#define	PCI_VENDOR_ID_AUREAL 0x12eb
+#endif
+#ifndef	PCI_VENDOR_ID_AUREAL_VORTEX
+#define	PCI_DEVICE_ID_AUREAL_VORTEX 0x0001
+#endif
+#ifndef	PCI_VENDOR_ID_AUREAL_VORTEX2
+#define	PCI_DEVICE_ID_AUREAL_VORTEX2 0x0002
+#endif
+#ifndef	PCI_VENDOR_ID_AUREAL_ADVANTAGE
+#define	PCI_DEVICE_ID_AUREAL_ADVANTAGE 0x0003
+#endif
+*/
+#endif
+
+#ifndef CHIP_AU8820
+#include "au88x0_eq.h"
+#include "au88x0_a3d.h"
+#endif
+#ifndef CHIP_AU8810
+#include "au88x0_wt.h"
+#endif
+
+#define	VORTEX_DMA_MASK	0xffffffff
+
+#define	hwread(x,y) readl((x)+((y)>>2))
+#define	hwwrite(x,y,z) writel((z),(x)+((y)>>2))
+
+/* Vortex MPU401 defines. */
+#define	MIDI_CLOCK_DIV		0x61
+/* Standart MPU401 defines. */
+#define	MPU401_RESET		0xff
+#define	MPU401_ENTER_UART	0x3f
+#define	MPU401_ACK		0xfe
+
+// Get src register value to convert from x to y.
+#define	SRC_RATIO(x,y)		((((x<<15)/y) + 1)/2)
+
+/* FIFO software state constants. */
+#define FIFO_STOP 0
+#define FIFO_START 1
+#define FIFO_PAUSE 2
+
+/* IRQ flags */
+#define IRQ_ERR_MASK	0x00ff
+#define IRQ_FATAL	0x0001
+#define IRQ_PARITY	0x0002
+#define IRQ_REG		0x0004
+#define IRQ_FIFO	0x0008
+#define IRQ_DMA		0x0010
+#define IRQ_PCMOUT	0x0020	/* PCM OUT page crossing */
+#define IRQ_TIMER	0x1000
+#define IRQ_MIDI	0x2000
+#define IRQ_MODEM	0x4000
+
+/* ADB Resource */
+#define VORTEX_RESOURCE_DMA		0x00000000
+#define VORTEX_RESOURCE_SRC		0x00000001
+#define VORTEX_RESOURCE_MIXIN	0x00000002
+#define VORTEX_RESOURCE_MIXOUT	0x00000003
+#define VORTEX_RESOURCE_A3D		0x00000004
+#define VORTEX_RESOURCE_LAST	0x00000005
+
+/* Check for SDAC bit in "Extended audio ID" AC97 register */
+#define VORTEX_IS_QUAD(x) ((x->codec == NULL) ?  0 : (x->codec->ext_id|0x80))
+
+/* PCM devices */
+#define VORTEX_PCM_ADB		0
+#define VORTEX_PCM_SPDIF	1
+#define VORTEX_PCM_A3D		2
+#define VORTEX_PCM_WT		3
+#define VORTEX_PCM_I2S		4
+#define VORTEX_PCM_LAST		5
+
+#define MIX_CAPT(x) (vortex->mixcapt[x])
+#define MIX_PLAYB(x) (vortex->mixplayb[x])
+#define MIX_SPDIF(x) (vortex->mixspdif[x])
+
+#define NR_WTPB 0x20		/* WT channels per eahc bank. */
+
+/* Structs */
+typedef struct {
+	//int this_08;          /* Still unknown */
+	int fifo_enabled;	/* this_24 */
+	int fifo_status;	/* this_1c */
+	int dma_ctrl;		/* this_78 (ADB), this_7c (WT) */
+	int dma_unknown;	/* this_74 (ADB), this_78 (WT). WDM: +8 */
+	int cfg0;
+	int cfg1;
+
+	int nr_ch;		/* Nr of PCM channels in use */
+	int type;		/* Output type (ac97, a3d, spdif, i2s, dsp) */
+	int dma;		/* Hardware DMA index. */
+	int dir;		/* Stream Direction. */
+	u32 resources[5];
+
+	/* Virtual page extender stuff */
+	int nr_periods;
+	int period_bytes;
+	snd_pcm_sgbuf_t *sgbuf;	/* DMA Scatter Gather struct */
+	int period_real;
+	int period_virt;
+
+	snd_pcm_substream_t *substream;
+} stream_t;
+
+typedef struct snd_vortex vortex_t;
+struct snd_vortex {
+	/* ALSA structs. */
+	snd_card_t *card;
+	snd_pcm_t *pcm[VORTEX_PCM_LAST];
+
+	snd_rawmidi_t *rmidi;	/* Legacy Midi interface. */
+	ac97_t *codec;
+
+	/* Stream structs. */
+	stream_t dma_adb[NR_ADB];
+	int spdif_sr;
+#ifndef CHIP_AU8810
+	stream_t dma_wt[NR_WT];
+	wt_voice_t wt_voice[NR_WT];	/* WT register cache. */
+	char mixwt[(NR_WT / NR_WTPB) * 6];	/* WT mixin objects */
+#endif
+
+	/* Global resources */
+	char mixcapt[2];
+	char mixplayb[4];
+#ifndef CHIP_AU8820
+	char mixspdif[2];
+	char mixa3d[2];		/* mixers which collect all a3d streams. */
+	char mixxtlk[2];	/* crosstalk canceler mixer inputs. */
+#endif
+	u32 fixed_res[5];
+
+#ifndef CHIP_AU8820
+	/* Hardware equalizer structs */
+	eqlzr_t eq;
+	/* A3D structs */
+	a3dsrc_t a3d[NR_A3D];
+	/* Xtalk canceler */
+	int xt_mode;		/* 1: speakers, 0:headphones. */
+#endif
+
+	/* Gameport stuff. */
+	struct gameport *gameport;
+
+	/* PCI hardware resources */
+	unsigned long io;
+	unsigned long *mmio;
+	unsigned int irq;
+	spinlock_t lock;
+
+	/* PCI device */
+	struct pci_dev *pci_dev;
+	u16 vendor;
+	u16 device;
+	u8 rev;
+};
+
+#define chip_t vortex_t
+
+/* Functions. */
+
+/* SRC */
+static void vortex_adb_setsrc(vortex_t * vortex, int adbdma,
+			      unsigned int cvrt, int dir);
+
+/* DMA Engines. */
+static void vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
+				     snd_pcm_sgbuf_t * sgbuf, int size,
+				     int count);
+static void vortex_adbdma_setmode(vortex_t * vortex, int adbdma, int ie,
+				  int dir, int fmt, int d,
+				  unsigned long offset);
+static void vortex_adbdma_setstartbuffer(vortex_t * vortex, int adbdma, int sb);
+#ifndef CHIP_AU8810
+static void vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma,
+				    snd_pcm_sgbuf_t * sgbuf, int size,
+				    int count);
+static void vortex_wtdma_setmode(vortex_t * vortex, int wtdma, int ie, int fmt, int d,	/*int e, */
+				 unsigned long offset);
+static void vortex_wtdma_setstartbuffer(vortex_t * vortex, int wtdma, int sb);
+#endif
+
+static void vortex_adbdma_startfifo(vortex_t * vortex, int adbdma);
+//static void vortex_adbdma_stopfifo(vortex_t *vortex, int adbdma);
+static void vortex_adbdma_pausefifo(vortex_t * vortex, int adbdma);
+static void vortex_adbdma_resumefifo(vortex_t * vortex, int adbdma);
+static int inline vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma);
+
+#ifndef CHIP_AU8810
+static void vortex_wtdma_startfifo(vortex_t * vortex, int wtdma);
+static void vortex_wtdma_stopfifo(vortex_t * vortex, int wtdma);
+static void vortex_wtdma_pausefifo(vortex_t * vortex, int wtdma);
+static void vortex_wtdma_resumefifo(vortex_t * vortex, int wtdma);
+static int inline vortex_wtdma_getlinearpos(vortex_t * vortex, int wtdma);
+#endif
+
+/* global stuff. */
+static void vortex_codec_init(vortex_t * vortex);
+static void vortex_codec_write(ac97_t * codec, unsigned short addr,
+			       unsigned short data);
+static unsigned short vortex_codec_read(ac97_t * codec, unsigned short addr);
+static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode);
+
+static int vortex_core_init(vortex_t * card);
+static int vortex_core_shutdown(vortex_t * card);
+static void vortex_enable_int(vortex_t * card);
+static irqreturn_t vortex_interrupt(int irq, void *dev_id,
+				    struct pt_regs *regs);
+static int vortex_alsafmt_aspfmt(int alsafmt);
+
+/* Connection  stuff. */
+static void vortex_connect_default(vortex_t * vortex, int en);
+static int vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch,
+				 int dir, int type);
+static char vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out,
+				  int restype);
+#ifndef CHIP_AU8810
+static int vortex_wt_allocroute(vortex_t * vortex, int dma, int nr_ch);
+static void vortex_wt_connect(vortex_t * vortex, int en);
+static void vortex_wt_init(vortex_t * vortex);
+#endif
+
+static void vortex_route(vortex_t * vortex, int en, unsigned char channel,
+			 unsigned char source, unsigned char dest);
+#if 0
+static void vortex_routes(vortex_t * vortex, int en, unsigned char channel,
+			  unsigned char source, unsigned char dest0,
+			  unsigned char dest1);
+#endif
+static void vortex_connection_mixin_mix(vortex_t * vortex, int en,
+					unsigned char mixin,
+					unsigned char mix, int a);
+static void vortex_mix_setinputvolumebyte(vortex_t * vortex,
+					  unsigned char mix, int mixin,
+					  unsigned char vol);
+static void vortex_mix_setvolumebyte(vortex_t * vortex, unsigned char mix,
+				     unsigned char vol);
+
+/* A3D functions. */
+#ifndef CHIP_AU8820
+static void vortex_Vort3D(vortex_t * v, int en);
+static void vortex_Vort3D_connect(vortex_t * vortex, int en);
+static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en);
+#endif
+
+/* Driver stuff. */
+static int __devinit vortex_gameport_register(vortex_t * card);
+static int __devexit vortex_gameport_unregister(vortex_t * card);
+#ifndef CHIP_AU8820
+static int __devinit vortex_eq_init(vortex_t * vortex);
+static int __devexit vortex_eq_free(vortex_t * vortex);
+#endif
+/* ALSA stuff. */
+static int __devinit snd_vortex_new_pcm(vortex_t * vortex, int idx, int nr);
+static int __devinit snd_vortex_mixer(vortex_t * vortex);
+static int __devinit snd_vortex_midi(vortex_t * vortex);
+#endif
--- diff/sound/pci/au88x0/au88x0_a3d.c	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au88x0_a3d.c	2004-03-16 09:37:58.494647632 +0000
@@ -0,0 +1,912 @@
+/***************************************************************************
+ *            au88x0_a3d.c
+ *
+ *  Fri Jul 18 14:16:22 2003
+ *  Copyright  2003  mjander
+ *  mjander@users.sourceforge.net
+ *
+ * A3D. You may think i'm crazy, but this may work someday. Who knows...
+ ****************************************************************************/
+
+/*
+ *  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 Library 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 "au88x0_a3d.h"
+#include "au88x0_a3ddata.c"
+#include "au88x0_xtalk.h"
+#include "au88x0.h"
+
+static void
+a3dsrc_SetTimeConsts(a3dsrc_t * a, short HrtfTrack, short ItdTrack,
+		     short GTrack, short CTrack)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	hwwrite(vortex->mmio,
+		a3d_addrA(a->slice, a->source, A3D_A_HrtfTrackTC), HrtfTrack);
+	hwwrite(vortex->mmio,
+		a3d_addrA(a->slice, a->source, A3D_A_ITDTrackTC), ItdTrack);
+	hwwrite(vortex->mmio,
+		a3d_addrA(a->slice, a->source, A3D_A_GainTrackTC), GTrack);
+	hwwrite(vortex->mmio,
+		a3d_addrA(a->slice, a->source, A3D_A_CoeffTrackTC), CTrack);
+}
+
+#if 0
+static void
+a3dsrc_GetTimeConsts(a3dsrc_t * a, short *HrtfTrack, short *ItdTrack,
+		     short *GTrack, short *CTrack)
+{
+	// stub!
+}
+
+#endif
+/* Atmospheric absorbtion. */
+
+static void
+a3dsrc_SetAtmosTarget(a3dsrc_t * a, short aa, short b, short c, short d,
+		      short e)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	hwwrite(vortex->mmio,
+		a3d_addrB(a->slice, a->source, A3D_B_A21Target),
+		(e << 0x10) | d);
+	hwwrite(vortex->mmio,
+		a3d_addrB(a->slice, a->source, A3D_B_B10Target),
+		(b << 0x10) | aa);
+	hwwrite(vortex->mmio,
+		a3d_addrB(a->slice, a->source, A3D_B_B2Target), c);
+}
+
+static void
+a3dsrc_SetAtmosCurrent(a3dsrc_t * a, short aa, short b, short c, short d,
+		       short e)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	hwwrite(vortex->mmio,
+		a3d_addrB(a->slice, a->source, A3D_B_A12Current),
+		(e << 0x10) | d);
+	hwwrite(vortex->mmio,
+		a3d_addrB(a->slice, a->source, A3D_B_B01Current),
+		(b << 0x10) | aa);
+	hwwrite(vortex->mmio,
+		a3d_addrB(a->slice, a->source, A3D_B_B2Current), c);
+}
+
+static void
+a3dsrc_SetAtmosState(a3dsrc_t * a, short x1, short x2, short y1, short y2)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_x1), x1);
+	hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_x2), x2);
+	hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_y1), y1);
+	hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_y2), y2);
+}
+
+#if 0
+static void
+a3dsrc_GetAtmosTarget(a3dsrc_t * a, short *aa, short *b, short *c,
+		      short *d, short *e)
+{
+}
+static void
+a3dsrc_GetAtmosCurrent(a3dsrc_t * a, short *bb01, short *ab01, short *b2,
+		       short *aa12, short *ba12)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	*aa12 =
+	    hwread(vortex->mmio,
+		   a3d_addrA(a->slice, a->source, A3D_A_A12Current));
+	*ba12 =
+	    hwread(vortex->mmio,
+		   a3d_addrB(a->slice, a->source, A3D_B_A12Current));
+	*ab01 =
+	    hwread(vortex->mmio,
+		   a3d_addrA(a->slice, a->source, A3D_A_B01Current));
+	*bb01 =
+	    hwread(vortex->mmio,
+		   a3d_addrB(a->slice, a->source, A3D_B_B01Current));
+	*b2 =
+	    hwread(vortex->mmio,
+		   a3d_addrA(a->slice, a->source, A3D_A_B2Current));
+}
+
+static void
+a3dsrc_GetAtmosState(a3dsrc_t * a, short *x1, short *x2, short *y1, short *y2)
+{
+
+}
+
+#endif
+/* HRTF */
+
+static void
+a3dsrc_SetHrtfTarget(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	int i;
+
+	for (i = 0; i < HRTF_SZ; i++)
+		hwwrite(vortex->mmio,
+			a3d_addrB(a->slice, a->source,
+				  A3D_B_HrtfTarget) + (i << 2),
+			(b[i] << 0x10) | aa[i]);
+}
+
+static void
+a3dsrc_SetHrtfCurrent(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	int i;
+
+	for (i = 0; i < HRTF_SZ; i++)
+		hwwrite(vortex->mmio,
+			a3d_addrB(a->slice, a->source,
+				  A3D_B_HrtfCurrent) + (i << 2),
+			(b[i] << 0x10) | aa[i]);
+}
+
+static void
+a3dsrc_SetHrtfState(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	int i;
+
+	for (i = 0; i < HRTF_SZ; i++)
+		hwwrite(vortex->mmio,
+			a3d_addrB(a->slice, a->source,
+				  A3D_B_HrtfDelayLine) + (i << 2),
+			(b[i] << 0x10) | aa[i]);
+}
+
+static void a3dsrc_SetHrtfOutput(a3dsrc_t * a, short left, short right)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	hwwrite(vortex->mmio,
+		a3d_addrA(a->slice, a->source, A3D_A_HrtfOutL), left);
+	hwwrite(vortex->mmio,
+		a3d_addrA(a->slice, a->source, A3D_A_HrtfOutR), right);
+}
+
+#if 0
+static void a3dsrc_GetHrtfTarget(a3dsrc_t * a, a3d_Hrtf_t aa, a3d_Hrtf_t b)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	int i;
+
+	for (i = 0; i < HRTF_SZ; i++)
+		aa[i] =
+		    hwread(vortex->mmio,
+			   a3d_addrA(a->slice, a->source,
+				     A3D_A_HrtfTarget + (i << 2)));
+	for (i = 0; i < HRTF_SZ; i++)
+		b[i] =
+		    hwread(vortex->mmio,
+			   a3d_addrB(a->slice, a->source,
+				     A3D_B_HrtfTarget + (i << 2)));
+}
+
+static void a3dsrc_GetHrtfCurrent(a3dsrc_t * a, a3d_Hrtf_t aa, a3d_Hrtf_t b)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	int i;
+
+	for (i = 0; i < HRTF_SZ; i++)
+		aa[i] =
+		    hwread(vortex->mmio,
+			   a3d_addrA(a->slice, a->source,
+				     A3D_A_HrtfCurrent + (i << 2)));
+	for (i = 0; i < HRTF_SZ; i++)
+		b[i] =
+		    hwread(vortex->mmio,
+			   a3d_addrB(a->slice, a->source,
+				     A3D_B_HrtfCurrent + (i << 2)));
+}
+
+static void a3dsrc_GetHrtfState(a3dsrc_t * a, a3d_Hrtf_t aa, a3d_Hrtf_t b)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	int i;
+	// FIXME: verify this!
+	for (i = 0; i < HRTF_SZ; i++)
+		aa[i] =
+		    hwread(vortex->mmio,
+			   a3d_addrA(a->slice, a->source,
+				     A3D_A_HrtfDelayLine + (i << 2)));
+	for (i = 0; i < HRTF_SZ; i++)
+		b[i] =
+		    hwread(vortex->mmio,
+			   a3d_addrB(a->slice, a->source,
+				     A3D_B_HrtfDelayLine + (i << 2)));
+}
+
+static void a3dsrc_GetHrtfOutput(a3dsrc_t * a, short *left, short *right)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	*left =
+	    hwread(vortex->mmio,
+		   a3d_addrA(a->slice, a->source, A3D_A_HrtfOutL));
+	*right =
+	    hwread(vortex->mmio,
+		   a3d_addrA(a->slice, a->source, A3D_A_HrtfOutR));
+}
+
+#endif
+
+/* Interaural Time Difference. 
+ * "The other main clue that humans use to locate sounds, is called 
+ * Interaural Time Difference (ITD). The differences in distance from 
+ * the sound source to a listeners ears means  that the sound will 
+ * reach one ear slightly before the other....", found somewhere with google.*/
+static void a3dsrc_SetItdTarget(a3dsrc_t * a, short litd, short ritd)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+
+	if (litd < 0)
+		litd = 0;
+	if (litd > 0x57FF)
+		litd = 0x57FF;
+	if (ritd < 0)
+		ritd = 0;
+	if (ritd > 0x57FF)
+		ritd = 0x57FF;
+	hwwrite(vortex->mmio,
+		a3d_addrB(a->slice, a->source, A3D_B_ITDTarget),
+		(ritd << 0x10) | litd);
+	//hwwrite(vortex->mmio, addr(0x191DF+5, this04, this08), (ritd<<0x10)|litd);
+}
+
+static void a3dsrc_SetItdCurrent(a3dsrc_t * a, short litd, short ritd)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+
+	if (litd < 0)
+		litd = 0;
+	if (litd > 0x57FF)
+		litd = 0x57FF;
+	if (ritd < 0)
+		ritd = 0;
+	if (ritd > 0x57FF)
+		ritd = 0x57FF;
+	hwwrite(vortex->mmio,
+		a3d_addrB(a->slice, a->source, A3D_B_ITDCurrent),
+		(ritd << 0x10) | litd);
+	//hwwrite(vortex->mmio, addr(0x191DF+1, this04, this08), (ritd<<0x10)|litd);
+}
+
+static void a3dsrc_SetItdDline(a3dsrc_t * a, a3d_ItdDline_t const dline)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	int i;
+	/* 45 != 40 -> Check this ! */
+	for (i = 0; i < DLINE_SZ; i++)
+		hwwrite(vortex->mmio,
+			a3d_addrA(a->slice, a->source,
+				  A3D_A_ITDDelayLine) + (i << 2), dline[i]);
+}
+
+#if 0
+static void a3dsrc_GetItdTarget(a3dsrc_t * a, short *litd, short *ritd)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	*ritd =
+	    hwread(vortex->mmio,
+		   a3d_addrA(a->slice, a->source, A3D_A_ITDTarget));
+	*litd =
+	    hwread(vortex->mmio,
+		   a3d_addrB(a->slice, a->source, A3D_B_ITDTarget));
+}
+
+static void a3dsrc_GetItdCurrent(a3dsrc_t * a, short *litd, short *ritd)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+
+	*ritd =
+	    hwread(vortex->mmio,
+		   a3d_addrA(a->slice, a->source, A3D_A_ITDCurrent));
+	*litd =
+	    hwread(vortex->mmio,
+		   a3d_addrB(a->slice, a->source, A3D_B_ITDCurrent));
+}
+
+static void a3dsrc_GetItdDline(a3dsrc_t * a, a3d_ItdDline_t dline)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	int i;
+
+	for (i = 0; i < DLINE_SZ; i++)
+		dline[i] =
+		    hwread(vortex->mmio,
+			   a3d_addrA(a->slice, a->source,
+				     A3D_A_ITDDelayLine + (i << 2)));
+}
+
+#endif
+/* This is may be used for ILD Interaural Level Difference. */
+
+static void a3dsrc_SetGainTarget(a3dsrc_t * a, short left, short right)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	hwwrite(vortex->mmio,
+		a3d_addrB(a->slice, a->source, A3D_B_GainTarget),
+		(right << 0x10) | left);
+}
+
+static void a3dsrc_SetGainCurrent(a3dsrc_t * a, short left, short right)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	hwwrite(vortex->mmio,
+		a3d_addrB(a->slice, a->source, A3D_B_GainCurrent),
+		(right << 0x10) | left);
+}
+
+#if 0
+static void a3dsrc_GetGainTarget(a3dsrc_t * a, short *left, short *right)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	*right =
+	    hwread(vortex->mmio,
+		   a3d_addrA(a->slice, a->source, A3D_A_GainTarget));
+	*left =
+	    hwread(vortex->mmio,
+		   a3d_addrB(a->slice, a->source, A3D_B_GainTarget));
+}
+
+static void a3dsrc_GetGainCurrent(a3dsrc_t * a, short *left, short *right)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	*right =
+	    hwread(vortex->mmio,
+		   a3d_addrA(a->slice, a->source, A3D_A_GainCurrent));
+	*left =
+	    hwread(vortex->mmio,
+		   a3d_addrB(a->slice, a->source, A3D_B_GainCurrent));
+}
+
+/* CA3dIO this func seems to be inlined all over this place. */
+static void CA3dIO_WriteReg(a3dsrc_t * a, unsigned long addr, short aa, short b)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	hwwrite(vortex->mmio, addr, (aa << 0x10) | b);
+}
+
+#endif
+/* Generic A3D stuff */
+
+static void a3dsrc_SetA3DSampleRate(a3dsrc_t * a, int sr)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	int esp0 = 0;
+
+	esp0 = (((esp0 & 0x7fffffff) | 0xB8000000) & 0x7) | ((sr & 0x1f) << 3);
+	hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), esp0);
+	//hwwrite(vortex->mmio, 0x19C38 + (this08<<0xd), esp0);
+}
+
+static void a3dsrc_EnableA3D(a3dsrc_t * a)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd),
+		0xF0000001);
+	//hwwrite(vortex->mmio, 0x19C38 + (this08<<0xd), 0xF0000001);
+}
+
+static void a3dsrc_DisableA3D(a3dsrc_t * a)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd),
+		0xF0000000);
+}
+
+static void a3dsrc_SetA3DControlReg(a3dsrc_t * a, unsigned long ctrl)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), ctrl);
+}
+
+static void a3dsrc_SetA3DPointerReg(a3dsrc_t * a, unsigned long ptr)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	hwwrite(vortex->mmio, A3D_SLICE_Pointers + ((a->slice) << 0xd), ptr);
+}
+
+#if 0
+static void a3dsrc_GetA3DSampleRate(a3dsrc_t * a, int *sr)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	*sr = ((hwread(vortex->mmio, A3D_SLICE_Control + (a->slice << 0xd))
+		>> 3) & 0x1f);
+	//*sr = ((hwread(vortex->mmio, 0x19C38 + (this08<<0xd))>>3)&0x1f);
+}
+
+static void a3dsrc_GetA3DControlReg(a3dsrc_t * a, unsigned long *ctrl)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	*ctrl = hwread(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd));
+}
+
+static void a3dsrc_GetA3DPointerReg(a3dsrc_t * a, unsigned long *ptr)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	*ptr = hwread(vortex->mmio, A3D_SLICE_Pointers + ((a->slice) << 0xd));
+}
+
+#endif
+static void a3dsrc_ZeroSliceIO(a3dsrc_t * a)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+	int i;
+
+	for (i = 0; i < 8; i++)
+		hwwrite(vortex->mmio,
+			A3D_SLICE_VDBDest +
+			((((a->slice) << 0xb) + i) << 2), 0);
+	for (i = 0; i < 4; i++)
+		hwwrite(vortex->mmio,
+			A3D_SLICE_VDBSource +
+			((((a->slice) << 0xb) + i) << 2), 0);
+}
+
+/* Reset Single A3D source. */
+static void a3dsrc_ZeroState(a3dsrc_t * a)
+{
+
+	//printk("vortex: ZeroState slice: %d, source %d\n", a->slice, a->source);
+
+	a3dsrc_SetAtmosState(a, 0, 0, 0, 0);
+	a3dsrc_SetHrtfState(a, A3dHrirZeros, A3dHrirZeros);
+	a3dsrc_SetItdDline(a, A3dItdDlineZeros);
+	a3dsrc_SetHrtfOutput(a, 0, 0);
+	a3dsrc_SetTimeConsts(a, 0, 0, 0, 0);
+
+	a3dsrc_SetAtmosCurrent(a, 0, 0, 0, 0, 0);
+	a3dsrc_SetAtmosTarget(a, 0, 0, 0, 0, 0);
+	a3dsrc_SetItdCurrent(a, 0, 0);
+	a3dsrc_SetItdTarget(a, 0, 0);
+	a3dsrc_SetGainCurrent(a, 0, 0);
+	a3dsrc_SetGainTarget(a, 0, 0);
+
+	a3dsrc_SetHrtfCurrent(a, A3dHrirZeros, A3dHrirZeros);
+	a3dsrc_SetHrtfTarget(a, A3dHrirZeros, A3dHrirZeros);
+}
+
+/* Reset entire A3D engine */
+static void a3dsrc_ZeroStateA3D(a3dsrc_t * a)
+{
+	int i, var, var2;
+
+	if ((a->vortex) == NULL) {
+		printk("vortex: ZeroStateA3D: ERROR: a->vortex is NULL\n");
+		return;
+	}
+
+	a3dsrc_SetA3DControlReg(a, 0);
+	a3dsrc_SetA3DPointerReg(a, 0);
+
+	var = a->slice;
+	var2 = a->source;
+	for (i = 0; i < 4; i++) {
+		a->slice = i;
+		a3dsrc_ZeroSliceIO(a);
+		//a3dsrc_ZeroState(a);
+	}
+	a->source = var2;
+	a->slice = var;
+}
+
+/* Program A3D block as pass through */
+static void a3dsrc_ProgramPipe(a3dsrc_t * a)
+{
+	a3dsrc_SetTimeConsts(a, 0, 0, 0, 0);
+	a3dsrc_SetAtmosCurrent(a, 0, 0x4000, 0, 0, 0);
+	a3dsrc_SetAtmosTarget(a, 0x4000, 0, 0, 0, 0);
+	a3dsrc_SetItdCurrent(a, 0, 0);
+	a3dsrc_SetItdTarget(a, 0, 0);
+	a3dsrc_SetGainCurrent(a, 0x7fff, 0x7fff);
+	a3dsrc_SetGainTarget(a, 0x7fff, 0x7fff);
+
+	/* SET HRTF HERE */
+
+	/* Single spike leads to identity transfer function. */
+	a3dsrc_SetHrtfCurrent(a, A3dHrirImpulse, A3dHrirImpulse);
+	a3dsrc_SetHrtfTarget(a, A3dHrirImpulse, A3dHrirImpulse);
+
+	/* Test: Sounds saturated. */
+	//a3dsrc_SetHrtfCurrent(a, A3dHrirSatTest, A3dHrirSatTest);
+	//a3dsrc_SetHrtfTarget(a, A3dHrirSatTest, A3dHrirSatTest);      
+}
+
+/* VDB = Vortex audio Dataflow Bus */
+#if 0
+static void a3dsrc_ClearVDBData(a3dsrc_t * a, unsigned long aa)
+{
+	vortex_t *vortex = (vortex_t *) (a->vortex);
+
+	// ((aa >> 2) << 8) - (aa >> 2)
+	hwwrite(vortex->mmio,
+		a3d_addrS(a->slice, A3D_SLICE_VDBDest) + (a->source << 2), 0);
+	hwwrite(vortex->mmio,
+		a3d_addrS(a->slice,
+			  A3D_SLICE_VDBDest + 4) + (a->source << 2), 0);
+	/*
+	   hwwrite(vortex->mmio, 0x19c00 + (((aa>>2)*255*4)+aa)*8, 0);
+	   hwwrite(vortex->mmio, 0x19c04 + (((aa>>2)*255*4)+aa)*8, 0);
+	 */
+}
+#endif
+
+/* A3D HwSource stuff. */
+
+static void vortex_A3dSourceHw_Initialize(vortex_t * v, int source, int slice)
+{
+	a3dsrc_t *a3dsrc = &(v->a3d[source + (slice * 4)]);
+	//a3dsrc_t *a3dsrc = &(v->a3d[source + (slice*4)]);
+
+	a3dsrc->vortex = (void *)v;
+	a3dsrc->source = source;	/* source */
+	a3dsrc->slice = slice;	/* slice */
+	a3dsrc_ZeroState(a3dsrc);
+	/* Added by me. */
+	a3dsrc_SetA3DSampleRate(a3dsrc, 0x11);
+}
+
+int Vort3DRend_Initialize(vortex_t * v, unsigned short mode)
+{
+	v->xt_mode = mode;	/* this_14 */
+
+	vortex_XtalkHw_init(v);
+	vortex_XtalkHw_SetGains(v, asXtalkGainsAllChan);
+	switch (v->xt_mode) {
+	case XT_SPEAKER0:
+		vortex_XtalkHw_ProgramXtalkNarrow(v);
+		break;
+	case XT_SPEAKER1:
+		vortex_XtalkHw_ProgramXtalkWide(v);
+		break;
+	default:
+	case XT_HEADPHONE:
+		vortex_XtalkHw_ProgramPipe(v);
+		break;
+	case XT_DIAMOND:
+		vortex_XtalkHw_ProgramDiamondXtalk(v);
+		break;
+	}
+	vortex_XtalkHw_SetSampleRate(v, 0x11);
+	vortex_XtalkHw_Enable(v);
+	return 0;
+}
+
+/* 3D Sound entry points. */
+
+static int vortex_a3d_register_controls(vortex_t * vortex);
+static void vortex_a3d_unregister_controls(vortex_t * vortex);
+/* A3D base support init/shudown */
+static void vortex_Vort3D(vortex_t * v, int en)
+{
+	int i;
+	if (en) {
+		Vort3DRend_Initialize(v, XT_HEADPHONE);
+		for (i = 0; i < NR_A3D; i++) {
+			vortex_A3dSourceHw_Initialize(v, i % 4, i >> 2);
+			a3dsrc_ZeroStateA3D(&(v->a3d[0]));
+		}
+	} else {
+		vortex_XtalkHw_Disable(v);
+	}
+	/* Register ALSA controls */
+	if (en) {
+		vortex_a3d_register_controls(v);
+	} else {
+		vortex_a3d_unregister_controls(v);
+	}
+}
+
+/* Make A3D subsystem connections. */
+static void vortex_Vort3D_connect(vortex_t * v, int en)
+{
+	int i;
+#if 1
+	/* Alloc Xtalk mixin resources */
+	v->mixxtlk[0] =
+	    vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN);
+	if (v->mixxtlk[0] < 0) {
+		printk
+		    ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n");
+		return;
+	}
+	v->mixxtlk[1] =
+	    vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN);
+	if (v->mixxtlk[1] < 0) {
+		printk
+		    ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n");
+		return;
+	}
+#endif
+
+	/* Connect A3D -> XTALK */
+	for (i = 0; i < 4; i++) {
+		// 2 outputs per each A3D slice. 
+		vortex_route(v, en, 0x11, ADB_A3DOUT(i * 2), ADB_XTALKIN(i));
+		vortex_route(v, en, 0x11, ADB_A3DOUT(i * 2) + 1, ADB_XTALKIN(5 + i));
+	}
+#if 0
+	vortex_route(v, en, 0x11, ADB_XTALKOUT(0), ADB_EQIN(2));
+	vortex_route(v, en, 0x11, ADB_XTALKOUT(1), ADB_EQIN(3));
+#else
+	/* Connect XTalk -> mixer */
+	vortex_route(v, en, 0x11, ADB_XTALKOUT(0), ADB_MIXIN(v->mixxtlk[0]));
+	vortex_route(v, en, 0x11, ADB_XTALKOUT(1), ADB_MIXIN(v->mixxtlk[1]));
+	vortex_connection_mixin_mix(v, en, v->mixxtlk[0], v->mixplayb[0], 0);
+	vortex_connection_mixin_mix(v, en, v->mixxtlk[1], v->mixplayb[1], 0);
+	vortex_mix_setinputvolumebyte(v, v->mixplayb[0], v->mixxtlk[0],
+				      en ? MIX_DEFIGAIN : VOL_MIN);
+	vortex_mix_setinputvolumebyte(v, v->mixplayb[1], v->mixxtlk[1],
+				      en ? MIX_DEFIGAIN : VOL_MIN);
+	if (VORTEX_IS_QUAD(v)) {
+		vortex_connection_mixin_mix(v, en, v->mixxtlk[0],
+					    v->mixplayb[2], 0);
+		vortex_connection_mixin_mix(v, en, v->mixxtlk[1],
+					    v->mixplayb[3], 0);
+		vortex_mix_setinputvolumebyte(v, v->mixplayb[2],
+					      v->mixxtlk[0],
+					      en ? MIX_DEFIGAIN : VOL_MIN);
+		vortex_mix_setinputvolumebyte(v, v->mixplayb[3],
+					      v->mixxtlk[1],
+					      en ? MIX_DEFIGAIN : VOL_MIN);
+	}
+#endif
+}
+
+/* Initialize one single A3D source. */
+static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en)
+{
+	if (a->vortex == NULL) {
+		printk
+		    ("vortex: Vort3D_InitializeSource: A3D source not initialized\n");
+		return;
+	}
+	if (en) {
+		a3dsrc_ProgramPipe(a);
+		a3dsrc_SetA3DSampleRate(a, 0x11);
+		a3dsrc_SetTimeConsts(a, HrtfTCDefault,
+				     ItdTCDefault, GainTCDefault,
+				     CoefTCDefault);
+		/* Remark: zero gain is muted. */
+		//a3dsrc_SetGainTarget(a,0,0);
+		//a3dsrc_SetGainCurrent(a,0,0);
+		a3dsrc_EnableA3D(a);
+	} else {
+		a3dsrc_DisableA3D(a);
+		a3dsrc_ZeroState(a);
+	}
+}
+
+/* Conversion of coordinates into 3D parameters. */
+
+static void vortex_a3d_coord2hrtf(a3d_Hrtf_t hrtf, int *coord)
+{
+	/* FIXME: implement this. */
+
+}
+static void vortex_a3d_coord2itd(a3d_Itd_t itd, int *coord)
+{
+	/* FIXME: implement this. */
+
+}
+static void vortex_a3d_coord2ild(a3d_LRGains_t ild, int left, int right)
+{
+	/* FIXME: implement this. */
+
+}
+static void vortex_a3d_translate_filter(a3d_atmos_t filter, int *params)
+{
+	/* FIXME: implement this. */
+
+}
+
+/* ALSA control interface.  */
+
+static int
+snd_vortex_a3d_hrtf_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 6;
+	uinfo->value.integer.min = 0x00000000;
+	uinfo->value.integer.max = 0xffffffff;
+	return 0;
+}
+static int
+snd_vortex_a3d_itd_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 = 0x00000000;
+	uinfo->value.integer.max = 0xffffffff;
+	return 0;
+}
+static int
+snd_vortex_a3d_ild_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 = 0x00000000;
+	uinfo->value.integer.max = 0xffffffff;
+	return 0;
+}
+static int
+snd_vortex_a3d_filter_info(snd_kcontrol_t *
+			   kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 4;
+	uinfo->value.integer.min = 0x00000000;
+	uinfo->value.integer.max = 0xffffffff;
+	return 0;
+}
+
+static int
+snd_vortex_a3d_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	//a3dsrc_t *a = (a3dsrc_t*)(kcontrol->private_value);
+	/* No read yet. Would this be really useable/needed ? */
+
+	return 0;
+}
+
+static int
+snd_vortex_a3d_hrtf_put(snd_kcontrol_t *
+			kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	a3dsrc_t *a = (a3dsrc_t *) (kcontrol->private_value);
+	int changed = 1, i;
+	int coord[6];
+	for (i = 0; i < 6; i++)
+		coord[i] = ucontrol->value.integer.value[i];
+	/* Translate orientation coordinates to a3d params. */
+	vortex_a3d_coord2hrtf(a->hrtf[0], coord);
+	vortex_a3d_coord2hrtf(a->hrtf[1], coord);
+	a3dsrc_SetHrtfTarget(a, a->hrtf[0], a->hrtf[1]);
+	a3dsrc_SetHrtfCurrent(a, a->hrtf[0], a->hrtf[1]);
+	return changed;
+}
+
+static int
+snd_vortex_a3d_itd_put(snd_kcontrol_t *
+		       kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	a3dsrc_t *a = (a3dsrc_t *) (kcontrol->private_value);
+	int coord[6];
+	int i, changed = 1;
+	for (i = 0; i < 6; i++)
+		coord[i] = ucontrol->value.integer.value[i];
+	/* Translate orientation coordinates to a3d params. */
+	vortex_a3d_coord2itd(a->hrtf[0], coord);
+	vortex_a3d_coord2itd(a->hrtf[1], coord);
+	/* Inter aural time difference. */
+	a3dsrc_SetItdTarget(a, a->itd[0], a->itd[1]);
+	a3dsrc_SetItdCurrent(a, a->itd[0], a->itd[1]);
+	a3dsrc_SetItdDline(a, a->dline);
+	return changed;
+}
+
+static int
+snd_vortex_a3d_ild_put(snd_kcontrol_t *
+		       kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	a3dsrc_t *a = (a3dsrc_t *) (kcontrol->private_value);
+	int changed = 1;
+	int l, r;
+	/* There may be some scale tranlation needed here. */
+	l = ucontrol->value.integer.value[0];
+	r = ucontrol->value.integer.value[1];
+	vortex_a3d_coord2ild(a->ild, l, r);
+	/* Left Right panning. */
+	a3dsrc_SetGainTarget(a, l, r);
+	a3dsrc_SetGainCurrent(a, l, r);
+	return changed;
+}
+
+static int
+snd_vortex_a3d_filter_put(snd_kcontrol_t
+			  * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	a3dsrc_t *a = (a3dsrc_t *) (kcontrol->private_value);
+	int i, changed = 1;
+	int params[6];
+	for (i = 0; i < 6; i++)
+		params[i] = ucontrol->value.integer.value[i];
+	/* Translate generic filter params to a3d filter params. */
+	vortex_a3d_translate_filter(a->filter, params);
+	/* Atmospheric absorbtion and filtering. */
+	a3dsrc_SetAtmosTarget(a, a->filter[0],
+			      a->filter[1], a->filter[2],
+			      a->filter[3], a->filter[4]);
+	a3dsrc_SetAtmosCurrent(a, a->filter[0],
+			       a->filter[1], a->filter[2],
+			       a->filter[3], a->filter[4]);
+	return changed;
+}
+
+static snd_kcontrol_new_t vortex_a3d_kcontrol __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_PCM,.name =
+	    "Playback PCM advanced processing",.index =
+	    0,.access =
+	    SNDRV_CTL_ELEM_ACCESS_READWRITE,.private_value =
+	    0,.info = snd_vortex_a3d_hrtf_info,.get =
+	    snd_vortex_a3d_get,.put = snd_vortex_a3d_hrtf_put
+};
+
+/* Control (un)registration. */
+static int vortex_a3d_register_controls(vortex_t * vortex)
+{
+	snd_kcontrol_t *kcontrol;
+	int err, i;
+	/* HRTF controls. */
+	for (i = 0; i < NR_A3D; i++) {
+		if ((kcontrol =
+		     snd_ctl_new1(&vortex_a3d_kcontrol, vortex)) == NULL)
+			return -ENOMEM;
+		kcontrol->private_value = (int)&(vortex->a3d[i]);
+		kcontrol->id.numid = CTRLID_HRTF;
+		kcontrol->info = snd_vortex_a3d_hrtf_info;
+		kcontrol->put = snd_vortex_a3d_hrtf_put;
+		if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
+			return err;
+	}
+	/* ITD controls. */
+	for (i = 0; i < NR_A3D; i++) {
+		if ((kcontrol =
+		     snd_ctl_new1(&vortex_a3d_kcontrol, vortex)) == NULL)
+			return -ENOMEM;
+		kcontrol->private_value = (int)&(vortex->a3d[i]);
+		kcontrol->id.numid = CTRLID_ITD;
+		kcontrol->info = snd_vortex_a3d_itd_info;
+		kcontrol->put = snd_vortex_a3d_itd_put;
+		if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
+			return err;
+	}
+	/* ILD (gains) controls. */
+	for (i = 0; i < NR_A3D; i++) {
+		if ((kcontrol =
+		     snd_ctl_new1(&vortex_a3d_kcontrol, vortex)) == NULL)
+			return -ENOMEM;
+		kcontrol->private_value = (int)&(vortex->a3d[i]);
+		kcontrol->id.numid = CTRLID_GAINS;
+		kcontrol->info = snd_vortex_a3d_ild_info;
+		kcontrol->put = snd_vortex_a3d_ild_put;
+		if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
+			return err;
+	}
+	/* Filter controls. */
+	for (i = 0; i < NR_A3D; i++) {
+		if ((kcontrol =
+		     snd_ctl_new1(&vortex_a3d_kcontrol, vortex)) == NULL)
+			return -ENOMEM;
+		kcontrol->private_value = (int)&(vortex->a3d[i]);
+		kcontrol->id.numid = CTRLID_FILTER;
+		kcontrol->info = snd_vortex_a3d_filter_info;
+		kcontrol->put = snd_vortex_a3d_filter_put;
+		if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
+			return err;
+	}
+	return 0;
+}
+
+static void vortex_a3d_unregister_controls(vortex_t * vortex)
+{
+
+}
+
+/* End of File*/
--- diff/sound/pci/au88x0/au88x0_a3d.h	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au88x0_a3d.h	2004-03-16 09:37:58.494647632 +0000
@@ -0,0 +1,123 @@
+/***************************************************************************
+ *            au88x0_a3d.h
+ *
+ *  Fri Jul 18 14:16:03 2003
+ *  Copyright  2003  mjander
+ *  mjander@users.sourceforge.net
+ ****************************************************************************/
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library 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 _AU88X0_A3D_H
+#define _AU88X0_A3D_H
+
+//#include <openal.h>
+
+#define HRTF_SZ 0x38
+#define DLINE_SZ 0x28
+
+#define CTRLID_HRTF		1
+#define CTRLID_ITD		2
+#define CTRLID_ILD		4
+#define CTRLID_FILTER	8
+#define CTRLID_GAINS	16
+
+/* 3D parameter structs */
+typedef unsigned short int a3d_Hrtf_t[HRTF_SZ];
+typedef unsigned short int a3d_ItdDline_t[DLINE_SZ];
+typedef unsigned short int a3d_atmos_t[5];
+typedef unsigned short int a3d_LRGains_t[2];
+typedef unsigned short int a3d_Itd_t[2];
+typedef unsigned short int a3d_Ild_t[2];
+
+typedef struct {
+	void *vortex;		// Formerly CAsp4HwIO*, now vortex_t*.
+	unsigned int source;	/* this_04 */
+	unsigned int slice;	/* this_08 */
+	a3d_Hrtf_t hrtf[2];
+	a3d_Itd_t itd;
+	a3d_Ild_t ild;
+	a3d_ItdDline_t dline;
+	a3d_atmos_t filter;
+} a3dsrc_t;
+
+/* First Register bank */
+
+#define A3D_A_HrtfCurrent	0x18000	/* 56 ULONG */
+#define A3D_A_GainCurrent	0x180E0
+#define A3D_A_GainTarget	0x180E4
+#define A3D_A_A12Current	0x180E8	/* Atmospheric current. */
+#define A3D_A_A21Target		0x180EC	/* Atmospheric target */
+#define A3D_A_B01Current	0x180F0	/* Atmospheric current */
+#define A3D_A_B10Target		0x180F4	/* Atmospheric target */
+#define A3D_A_B2Current		0x180F8	/* Atmospheric current */
+#define A3D_A_B2Target		0x180FC	/* Atmospheric target */
+#define A3D_A_HrtfTarget	0x18100	/* 56 ULONG */
+#define A3D_A_ITDCurrent	0x181E0
+#define A3D_A_ITDTarget		0x181E4
+#define A3D_A_HrtfDelayLine	0x181E8	/* 56 ULONG */
+#define A3D_A_ITDDelayLine	0x182C8	/* 40/45 ULONG */
+#define A3D_A_HrtfTrackTC	0x1837C	/* Time Constants */
+#define A3D_A_GainTrackTC	0x18380
+#define A3D_A_CoeffTrackTC	0x18384
+#define A3D_A_ITDTrackTC	0x18388
+#define A3D_A_x1			0x1838C
+#define A3D_A_x2			0x18390
+#define A3D_A_y1			0x18394
+#define A3D_A_y2			0x18398
+#define A3D_A_HrtfOutL		0x1839C
+#define A3D_A_HrtfOutR		0x183A0
+#define 	A3D_A_TAIL		0x183A4
+
+/* Second register bank */
+#define A3D_B_HrtfCurrent	0x19000	/* 56 ULONG */
+#define A3D_B_GainCurrent	0x190E0
+#define A3D_B_GainTarget	0x190E4
+#define A3D_B_A12Current	0x190E8
+#define A3D_B_A21Target		0x190EC
+#define A3D_B_B01Current	0x190F0
+#define A3D_B_B10Target		0x190F4
+#define A3D_B_B2Current		0x190F8
+#define A3D_B_B2Target		0x190FC
+#define A3D_B_HrtfTarget	0x19100	/* 56 ULONG */
+#define A3D_B_ITDCurrent	0x191E0
+#define A3D_B_ITDTarget		0x191E4
+#define A3D_B_HrtfDelayLine	0x191E8	/* 56 ULONG */
+#define 	A3D_B_TAIL		0x192C8
+
+/* There are 4 slices, 4 a3d each = 16 a3d sources. */
+#define A3D_SLICE_BANK_A		0x18000	/* 4 sources */
+#define A3D_SLICE_BANK_B		0x19000	/* 4 sources */
+#define A3D_SLICE_VDBDest		0x19C00	/* 8 ULONG */
+#define A3D_SLICE_VDBSource		0x19C20	/* 4 ULONG */
+#define A3D_SLICE_ABReg			0x19C30
+#define A3D_SLICE_CReg			0x19C34
+#define A3D_SLICE_Control		0x19C38
+#define A3D_SLICE_DebugReserved	0x19C3c	/* Dangerous! */
+#define A3D_SLICE_Pointers		0x19C40
+#define 	A3D_SLICE_TAIL		0x1A000
+
+// Slice size: 0x2000
+// Source size: 0x3A4, 0x2C8
+
+/* Address generator macro. */
+#define a3d_addrA(slice,source,reg) (((slice)<<0xd)+((source)*0x3A4)+(reg))
+#define a3d_addrB(slice,source,reg) (((slice)<<0xd)+((source)*0x2C8)+(reg))
+#define a3d_addrS(slice,reg) (((slice)<<0xd)+(reg))
+//#define a3d_addr(slice,source,reg) (((reg)>=0x19000) ? a3d_addr2((slice),(source),(reg)) : a3d_addr1((slice),(source),(reg)))
+
+#endif				/* _AU88X0_A3D_H */
--- diff/sound/pci/au88x0/au88x0_a3ddata.c	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au88x0_a3ddata.c	2004-03-16 09:37:58.495647480 +0000
@@ -0,0 +1,91 @@
+/***************************************************************************
+ *            au88x0_a3ddata.c
+ *
+ *  Wed Nov 19 21:11:32 2003
+ *  Copyright  2003  mjander
+ *  mjander@users.sourceforge.org
+ ****************************************************************************/
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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 Library 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.
+ */
+
+/* Constant initializer values. */
+
+static const a3d_Hrtf_t A3dHrirZeros = {
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0,
+	0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0,
+	0, 0, 0
+};
+
+static const a3d_Hrtf_t A3dHrirImpulse = {
+	0x7fff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0,
+	0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0,
+	0, 0, 0
+};
+
+static const a3d_Hrtf_t A3dHrirOnes = {
+	0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
+	0x7fff,
+	0x7fff,
+	0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
+	0x7fff,
+	0x7fff,
+	0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
+	0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
+	0x7fff,
+	0x7fff,
+	0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
+	0x7fff,
+	0x7fff,
+	0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff
+};
+
+static const a3d_Hrtf_t A3dHrirSatTest = {
+	0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
+	0x7fff,
+	0x7fff,
+	0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001,
+	0x8001,
+	0x8001,
+	0x7fff, 0x0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const a3d_Hrtf_t A3dHrirDImpulse = {
+	0, 0x7fff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0,
+	0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0,
+	0, 0, 0
+};
+
+static const a3d_ItdDline_t A3dItdDlineZeros = {
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static short const GainTCDefault = 0x300;
+static short const ItdTCDefault = 0x0C8;
+static short const HrtfTCDefault = 0x147;
+static short const CoefTCDefault = 0x300;
--- diff/sound/pci/au88x0/au88x0_core.c	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au88x0_core.c	2004-03-16 09:37:58.501646568 +0000
@@ -0,0 +1,2822 @@
+/*
+ *  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 Library 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.
+ */
+
+/*
+    Vortex core low level functions.
+	
+ Author: Manuel Jander (mjander@users.sourceforge.cl)
+ These functions are mainly the result of translations made
+ from the original disassembly of the au88x0 binary drivers,
+ written by Aureal before they went down.
+ Many thanks to the Jeff Muizelar, Kester Maddock, and whoever
+ contributed to the OpenVortex project.
+ The author of this file, put the few available pieces together
+ and translated the rest of the riddle (Mix, Src and connection stuff).
+ Some things are still to be discovered, and their meanings are unclear.
+
+ Some of these functions aren't intended to be really used, rather
+ to help to understand how does the AU88X0 chips work. Keep them in, because
+ they could be used somewhere in the future.
+
+ This code hasn't been tested or proof read thoroughly. If you wanna help,
+ take a look at the AU88X0 assembly and check if this matches.
+ Functions tested ok so far are (they show the desired effect
+ at least):
+   vortex_routes(); (1 bug fixed).
+   vortex_adb_addroute();
+   vortex_adb_addroutes();
+   vortex_connect_codecplay();
+   vortex_src_flushbuffers();
+   vortex_adbdma_setmode();  note: still some unknown arguments!
+   vortex_adbdma_startfifo();
+   vortex_adbdma_stopfifo();
+   vortex_fifo_setadbctrl(); note: still some unknown arguments!
+   vortex_mix_setinputvolumebyte();
+   vortex_mix_enableinput();
+   vortex_mixer_addWTD(); (fixed)
+   vortex_connection_adbdma_src_src();
+   vortex_connection_adbdma_src();
+   vortex_src_change_convratio();
+   vortex_src_addWTD(); (fixed)
+
+ History:
+
+ 01-03-2003 First revision.
+ 01-21-2003 Some bug fixes.
+ 17-02-2003 many bugfixes after a big versioning mess.
+ 18-02-2003 JAAAAAHHHUUUUUU!!!! The mixer works !! I'm just so happy !
+			 (2 hours later...) I cant believe it! Im really lucky today.
+			 Now the SRC is working too! Yeah! XMMS works !
+ 20-02-2003 First steps into the ALSA world.
+ 28-02-2003 As my birthday present, i discovered how the DMA buffer pages really
+            work :-). It was all wrong.
+ 12-03-2003 ALSA driver starts working (2 channels).
+ 16-03-2003 More srcblock_setupchannel discoveries.
+ 12-04-2003 AU8830 playback support. Recording in the works.
+ 17-04-2003 vortex_route() and vortex_routes() bug fixes. AU8830 recording
+ 			works now, but chipn' dale effect is still there.
+ 16-05-2003 SrcSetupChannel cleanup. Moved the Src setup stuff entirely
+            into au88x0_pcm.c .
+ 06-06-2003 Buffer shifter bugfix. Mixer volume fix.
+ 07-12-2003 A3D routing finally fixed. Believed to be OK.
+ 
+*/
+
+#include "au88x0.h"
+#include "au88x0_a3d.h"
+#include <linux/delay.h>
+
+/*  MIXER (CAsp4Mix.s and CAsp4Mixer.s) */
+
+// FIXME: get rid of this.
+int mchannels[NR_MIXIN];
+int rampchs[NR_MIXIN];
+
+static void vortex_mixer_en_sr(vortex_t * vortex, int channel)
+{
+	hwwrite(vortex->mmio, VORTEX_MIXER_SR,
+		hwread(vortex->mmio, VORTEX_MIXER_SR) | (0x1 << channel));
+}
+static void vortex_mixer_dis_sr(vortex_t * vortex, int channel)
+{
+	hwwrite(vortex->mmio, VORTEX_MIXER_SR,
+		hwread(vortex->mmio, VORTEX_MIXER_SR) & ~(0x1 << channel));
+}
+
+#if 0
+static void
+vortex_mix_muteinputgain(vortex_t * vortex, unsigned char mix,
+			 unsigned char channel)
+{
+	hwwrite(vortex->mmio, VORTEX_MIX_INVOL_A + ((mix << 5) + channel),
+		0x80);
+	hwwrite(vortex->mmio, VORTEX_MIX_INVOL_B + ((mix << 5) + channel),
+		0x80);
+}
+
+static int vortex_mix_getvolume(vortex_t * vortex, unsigned char mix)
+{
+	int a;
+	a = hwread(vortex->mmio, VORTEX_MIX_VOL_A + (mix << 2)) & 0xff;
+	//FP2LinearFrac(a);
+	return (a);
+}
+
+static int
+vortex_mix_getinputvolume(vortex_t * vortex, unsigned char mix,
+			  int channel, int *vol)
+{
+	int a;
+	if (!(mchannels[mix] & (1 << channel)))
+		return 0;
+	a = hwread(vortex->mmio,
+		   VORTEX_MIX_INVOL_A + (((mix << 5) + channel) << 2));
+	/*
+	   if (rampchs[mix] == 0)
+	   a = FP2LinearFrac(a);
+	   else
+	   a = FP2LinearFracWT(a);
+	 */
+	*vol = a;
+	return (0);
+}
+
+static unsigned int vortex_mix_boost6db(unsigned char vol)
+{
+	return (vol + 8);	/* WOW! what a complex function! */
+}
+
+static void vortex_mix_rampvolume(vortex_t * vortex, int mix)
+{
+	int ch;
+	char a;
+	// This function is intended for ramping down only (see vortex_disableinput()).
+	for (ch = 0; ch < 0x20; ch++) {
+		if (((1 << ch) & rampchs[mix]) == 0)
+			continue;
+		a = hwread(vortex->mmio,
+			   VORTEX_MIX_INVOL_B + (((mix << 5) + ch) << 2));
+		if (a > -126) {
+			a -= 2;
+			hwwrite(vortex->mmio,
+				VORTEX_MIX_INVOL_A +
+				(((mix << 5) + ch) << 2), a);
+			hwwrite(vortex->mmio,
+				VORTEX_MIX_INVOL_B +
+				(((mix << 5) + ch) << 2), a);
+		} else
+			vortex_mix_killinput(vortex, mix, ch);
+	}
+}
+
+static int
+vortex_mix_getenablebit(vortex_t * vortex, unsigned char mix, int mixin)
+{
+	int addr, temp;
+	if (mixin >= 0)
+		addr = mixin;
+	else
+		addr = mixin + 3;
+	addr = ((mix << 3) + (addr >> 2)) << 2;
+	temp = hwread(vortex->mmio, VORTEX_MIX_ENIN + addr);
+	return ((temp >> (mixin & 3)) & 1);
+}
+#endif
+static void
+vortex_mix_setvolumebyte(vortex_t * vortex, unsigned char mix,
+			 unsigned char vol)
+{
+	int temp;
+	hwwrite(vortex->mmio, VORTEX_MIX_VOL_A + (mix << 2), vol);
+	if (1) {		/*if (this_10) */
+		temp = hwread(vortex->mmio, VORTEX_MIX_VOL_B + (mix << 2));
+		if ((temp != 0x80) || (vol == 0x80))
+			return;
+	}
+	hwwrite(vortex->mmio, VORTEX_MIX_VOL_B + (mix << 2), vol);
+}
+
+static void
+vortex_mix_setinputvolumebyte(vortex_t * vortex, unsigned char mix,
+			      int mixin, unsigned char vol)
+{
+	int temp;
+
+	hwwrite(vortex->mmio,
+		VORTEX_MIX_INVOL_A + (((mix << 5) + mixin) << 2), vol);
+	if (1) {		/* this_10, initialized to 1. */
+		temp =
+		    hwread(vortex->mmio,
+			   VORTEX_MIX_INVOL_B + (((mix << 5) + mixin) << 2));
+		if ((temp != 0x80) || (vol == 0x80))
+			return;
+	}
+	hwwrite(vortex->mmio,
+		VORTEX_MIX_INVOL_B + (((mix << 5) + mixin) << 2), vol);
+}
+
+static void
+vortex_mix_setenablebit(vortex_t * vortex, unsigned char mix, int mixin, int en)
+{
+	int temp, addr;
+
+	if (mixin < 0)
+		addr = (mixin + 3);
+	else
+		addr = mixin;
+	addr = ((mix << 3) + (addr >> 2)) << 2;
+	temp = hwread(vortex->mmio, VORTEX_MIX_ENIN + addr);
+	if (en)
+		temp |= (1 << (mixin & 3));
+	else
+		temp &= ~(1 << (mixin & 3));
+	/* Mute input. Astatic void crackling? */
+	hwwrite(vortex->mmio,
+		VORTEX_MIX_INVOL_B + (((mix << 5) + mixin) << 2), 0x80);
+	/* Looks like clear buffer. */
+	hwwrite(vortex->mmio, VORTEX_MIX_SMP + (mixin << 2), 0x0);
+	hwwrite(vortex->mmio, VORTEX_MIX_SMP + 4 + (mixin << 2), 0x0);
+	/* Write enable bit. */
+	hwwrite(vortex->mmio, VORTEX_MIX_ENIN + addr, temp);
+}
+
+static void
+vortex_mix_killinput(vortex_t * vortex, unsigned char mix, int mixin)
+{
+	rampchs[mix] &= ~(1 << mixin);
+	vortex_mix_setinputvolumebyte(vortex, mix, mixin, 0x80);
+	mchannels[mix] &= ~(1 << mixin);
+	vortex_mix_setenablebit(vortex, mix, mixin, 0);
+}
+
+static void
+vortex_mix_enableinput(vortex_t * vortex, unsigned char mix, int mixin)
+{
+	vortex_mix_killinput(vortex, mix, mixin);
+	if ((mchannels[mix] & (1 << mixin)) == 0) {
+		vortex_mix_setinputvolumebyte(vortex, mix, mixin, 0x80);	/*0x80 : mute */
+		mchannels[mix] |= (1 << mixin);
+	}
+	vortex_mix_setenablebit(vortex, mix, mixin, 1);
+}
+
+static void
+vortex_mix_disableinput(vortex_t * vortex, unsigned char mix, int channel,
+			int ramp)
+{
+	if (ramp) {
+		rampchs[mix] |= (1 << channel);
+		// Register callback.
+		//vortex_mix_startrampvolume(vortex);
+		vortex_mix_killinput(vortex, mix, channel);
+	} else
+		vortex_mix_killinput(vortex, mix, channel);
+}
+
+static int
+vortex_mixer_addWTD(vortex_t * vortex, unsigned char mix, unsigned char ch)
+{
+	int temp, lifeboat = 0, prev;
+
+	temp = hwread(vortex->mmio, VORTEX_MIXER_SR);
+	if ((temp & (1 << ch)) == 0) {
+		hwwrite(vortex->mmio, VORTEX_MIXER_CHNBASE + (ch << 2), mix);
+		vortex_mixer_en_sr(vortex, ch);
+		return 1;
+	}
+	prev = VORTEX_MIXER_CHNBASE + (ch << 2);
+	temp = hwread(vortex->mmio, prev);
+	while (temp & 0x10) {
+		prev = VORTEX_MIXER_RTBASE + ((temp & 0xf) << 2);
+		temp = hwread(vortex->mmio, prev);
+		//printk(KERN_INFO "vortex: mixAddWTD: while addr=%x, val=%x\n", prev, temp);
+		if ((++lifeboat) > 0xf) {
+			printk(KERN_ERR
+			       "vortex_mixer_addWTD: lifeboat overflow\n");
+			return 0;
+		}
+	}
+	hwwrite(vortex->mmio, VORTEX_MIXER_RTBASE + ((temp & 0xf) << 2), mix);
+	hwwrite(vortex->mmio, prev, (temp & 0xf) | 0x10);
+	return 1;
+}
+
+static int
+vortex_mixer_delWTD(vortex_t * vortex, unsigned char mix, unsigned char ch)
+{
+	int esp14 = -1, esp18, eax, ebx, edx, ebp, esi = 0;
+	//int esp1f=edi(while)=src, esp10=ch;
+
+	eax = hwread(vortex->mmio, VORTEX_MIXER_SR);
+	if (((1 << ch) & eax) == 0) {
+		printk(KERN_ERR "mix ALARM %x\n", eax);
+		return 0;
+	}
+	ebp = VORTEX_MIXER_CHNBASE + (ch << 2);
+	esp18 = hwread(vortex->mmio, ebp);
+	if (esp18 & 0x10) {
+		ebx = (esp18 & 0xf);
+		if (mix == ebx) {
+			ebx = VORTEX_MIXER_RTBASE + (mix << 2);
+			edx = hwread(vortex->mmio, ebx);
+			//7b60
+			hwwrite(vortex->mmio, ebp, edx);
+			hwwrite(vortex->mmio, ebx, 0);
+		} else {
+			//7ad3
+			edx =
+			    hwread(vortex->mmio,
+				   VORTEX_MIXER_RTBASE + (ebx << 2));
+			//printk(KERN_INFO "vortex: mixdelWTD: 1 addr=%x, val=%x, src=%x\n", ebx, edx, src);
+			while ((edx & 0xf) != mix) {
+				if ((esi) > 0xf) {
+					printk(KERN_ERR
+					       "vortex: mixdelWTD: error lifeboat overflow\n");
+					return 0;
+				}
+				esp14 = ebx;
+				ebx = edx & 0xf;
+				ebp = ebx << 2;
+				edx =
+				    hwread(vortex->mmio,
+					   VORTEX_MIXER_RTBASE + ebp);
+				//printk(KERN_INFO "vortex: mixdelWTD: while addr=%x, val=%x\n", ebp, edx);
+				esi++;
+			}
+			//7b30
+			ebp = ebx << 2;
+			if (edx & 0x10) {	/* Delete entry in between others */
+				ebx = VORTEX_MIXER_RTBASE + ((edx & 0xf) << 2);
+				edx = hwread(vortex->mmio, ebx);
+				//7b60
+				hwwrite(vortex->mmio,
+					VORTEX_MIXER_RTBASE + ebp, edx);
+				hwwrite(vortex->mmio, ebx, 0);
+				//printk(KERN_INFO "vortex mixdelWTD between addr= 0x%x, val= 0x%x\n", ebp, edx);
+			} else {	/* Delete last entry */
+				//7b83
+				if (esp14 == -1)
+					hwwrite(vortex->mmio,
+						VORTEX_MIXER_CHNBASE +
+						(ch << 2), esp18 & 0xef);
+				else {
+					ebx = (0xffffffe0 & edx) | (0xf & ebx);
+					hwwrite(vortex->mmio,
+						VORTEX_MIXER_RTBASE +
+						(esp14 << 2), ebx);
+					//printk(KERN_INFO "vortex mixdelWTD last addr= 0x%x, val= 0x%x\n", esp14, ebx);
+				}
+				hwwrite(vortex->mmio,
+					VORTEX_MIXER_RTBASE + ebp, 0);
+				return 1;
+			}
+		}
+	} else {
+		//printk(KERN_INFO "removed last mix\n");
+		//7be0
+		vortex_mixer_dis_sr(vortex, ch);
+		hwwrite(vortex->mmio, ebp, 0);
+	}
+	return 1;
+}
+
+static void vortex_mixer_init(vortex_t * vortex)
+{
+	unsigned long addr;
+	int x;
+
+	// FIXME: get rid of this crap.
+	memset(mchannels, 0, NR_MIXOUT * sizeof(int));
+	memset(rampchs, 0, NR_MIXOUT * sizeof(int));
+
+	addr = VORTEX_MIX_SMP + 0x17c;
+	for (x = 0x5f; x >= 0; x--) {
+		hwwrite(vortex->mmio, addr, 0);
+		addr -= 4;
+	}
+	addr = VORTEX_MIX_ENIN + 0x1fc;
+	for (x = 0x7f; x >= 0; x--) {
+		hwwrite(vortex->mmio, addr, 0);
+		addr -= 4;
+	}
+	addr = VORTEX_MIX_SMP + 0x17c;
+	for (x = 0x5f; x >= 0; x--) {
+		hwwrite(vortex->mmio, addr, 0);
+		addr -= 4;
+	}
+	addr = VORTEX_MIX_INVOL_A + 0x7fc;
+	for (x = 0x1ff; x >= 0; x--) {
+		hwwrite(vortex->mmio, addr, 0x80);
+		addr -= 4;
+	}
+	addr = VORTEX_MIX_VOL_A + 0x3c;
+	for (x = 0xf; x >= 0; x--) {
+		hwwrite(vortex->mmio, addr, 0x80);
+		addr -= 4;
+	}
+	addr = VORTEX_MIX_INVOL_B + 0x7fc;
+	for (x = 0x1ff; x >= 0; x--) {
+		hwwrite(vortex->mmio, addr, 0x80);
+		addr -= 4;
+	}
+	addr = VORTEX_MIX_VOL_B + 0x3c;
+	for (x = 0xf; x >= 0; x--) {
+		hwwrite(vortex->mmio, addr, 0x80);
+		addr -= 4;
+	}
+	addr = VORTEX_MIXER_RTBASE + (MIXER_RTBASE_SIZE - 1) * 4;
+	for (x = (MIXER_RTBASE_SIZE - 1); x >= 0; x--) {
+		hwwrite(vortex->mmio, addr, 0x0);
+		addr -= 4;
+	}
+	hwwrite(vortex->mmio, VORTEX_MIXER_SR, 0);
+
+	/* Set clipping ceiling (this may be all wrong). */
+	/*
+	for (x = 0; x > 0x80; x++) {
+		hwwrite(vortex->mmio, VORTEX_MIXER_CLIP + (x << 2), 0x3ffff);
+	}
+	*/
+	/*
+	   call CAsp4Mix__Initialize_CAsp4HwIO____CAsp4Mixer____
+	   Register ISR callback for volume smooth fade out.
+	   Maybe this avoids clicks when press "stop" ?
+	 */
+}
+
+/*  SRC (CAsp4Src.s and CAsp4SrcBlock) */
+
+static void vortex_src_en_sr(vortex_t * vortex, int channel)
+{
+	hwwrite(vortex->mmio, VORTEX_SRCBLOCK_SR,
+		hwread(vortex->mmio, VORTEX_SRCBLOCK_SR) | (0x1 << channel));
+}
+
+static void vortex_src_dis_sr(vortex_t * vortex, int channel)
+{
+	hwwrite(vortex->mmio, VORTEX_SRCBLOCK_SR,
+		hwread(vortex->mmio, VORTEX_SRCBLOCK_SR) & ~(0x1 << channel));
+}
+
+static void vortex_src_flushbuffers(vortex_t * vortex, unsigned char src)
+{
+	int i;
+
+	for (i = 0x1f; i >= 0; i--)
+		hwwrite(vortex->mmio,
+			VORTEX_SRC_DATA0 + (src << 7) + (i << 2), 0);
+	hwwrite(vortex->mmio, VORTEX_SRC_DATA + (src << 3), 0);
+	hwwrite(vortex->mmio, VORTEX_SRC_DATA + (src << 3) + 4, 0);
+}
+
+static void vortex_src_cleardrift(vortex_t * vortex, unsigned char src)
+{
+	hwwrite(vortex->mmio, VORTEX_SRC_DRIFT0 + (src << 2), 0);
+	hwwrite(vortex->mmio, VORTEX_SRC_DRIFT1 + (src << 2), 0);
+	hwwrite(vortex->mmio, VORTEX_SRC_DRIFT2 + (src << 2), 1);
+}
+
+static void
+vortex_src_set_throttlesource(vortex_t * vortex, unsigned char src, int en)
+{
+	int temp;
+
+	temp = hwread(vortex->mmio, VORTEX_SRC_SOURCE);
+	if (en)
+		temp |= 1 << src;
+	else
+		temp &= ~(1 << src);
+	hwwrite(vortex->mmio, VORTEX_SRC_SOURCE, temp);
+}
+
+static int
+vortex_src_persist_convratio(vortex_t * vortex, unsigned char src, int ratio)
+{
+	int temp, lifeboat = 0;
+
+	do {
+		hwwrite(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2), ratio);
+		temp = hwread(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2));
+		if ((++lifeboat) > 0x9) {
+			printk(KERN_ERR "Vortex: Src cvr fail\n");
+			break;
+		}
+	}
+	while (temp != ratio);
+	return temp;
+}
+
+#if 0
+static void vortex_src_slowlock(vortex_t * vortex, unsigned char src)
+{
+	int temp;
+
+	hwwrite(vortex->mmio, VORTEX_SRC_DRIFT2 + (src << 2), 1);
+	hwwrite(vortex->mmio, VORTEX_SRC_DRIFT0 + (src << 2), 0);
+	temp = hwread(vortex->mmio, VORTEX_SRC_U0 + (src << 2));
+	if (temp & 0x200)
+		hwwrite(vortex->mmio, VORTEX_SRC_U0 + (src << 2),
+			temp & ~0x200L);
+}
+
+static void
+vortex_src_change_convratio(vortex_t * vortex, unsigned char src, int ratio)
+{
+	int temp, a;
+
+	if ((ratio & 0x10000) && (ratio != 0x10000)) {
+		if (ratio & 0x3fff)
+			a = (0x11 - ((ratio >> 0xe) & 0x3)) - 1;
+		else
+			a = (0x11 - ((ratio >> 0xe) & 0x3)) - 2;
+	} else
+		a = 0xc;
+	temp = hwread(vortex->mmio, VORTEX_SRC_U0 + (src << 2));
+	if (((temp >> 4) & 0xf) != a)
+		hwwrite(vortex->mmio, VORTEX_SRC_U0 + (src << 2),
+			(temp & 0xf) | ((a & 0xf) << 4));
+
+	vortex_src_persist_convratio(vortex, src, ratio);
+}
+
+static int
+vortex_src_checkratio(vortex_t * vortex, unsigned char src,
+		      unsigned int desired_ratio)
+{
+	int hw_ratio, lifeboat = 0;
+
+	hw_ratio = hwread(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2));
+
+	while (hw_ratio != desired_ratio) {
+		hwwrite(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2), desired_ratio);
+
+		if ((lifeboat++) > 15) {
+			printk(KERN_ERR "Vortex: could not set src-%d from %d to %d\n",
+			       src, hw_ratio, desired_ratio);
+			break;
+		}
+	}
+
+	return hw_ratio;
+}
+
+#endif
+/*
+ Objective: Set samplerate for given SRC module.
+ Arguments:
+	card:	pointer to vortex_t strcut.
+	src:	Integer index of the SRC module.
+	cr:		Current sample rate conversion factor.
+	b:		unknown 16 bit value.
+	sweep:	Enable Samplerate fade from cr toward tr flag.
+	dirplay: 1: playback, 0: recording.
+	sl:		Slow Lock flag.
+	tr:		Target samplerate conversion.
+	thsource: Throttle source flag (no idea what that means).
+*/
+static void vortex_src_setupchannel(vortex_t * card, unsigned char src,
+			unsigned int cr, unsigned int b, int sweep, int d,
+			int dirplay, int sl, unsigned int tr, int thsource)
+{
+	// noplayback: d=2,4,7,0xa,0xb when using first 2 src's.
+	// c: enables pitch sweep.
+	// looks like g is c related. Maybe g is a sweep parameter ?
+	// g = cvr
+	// dirplay: 0 = recording, 1 = playback
+	// d = src hw index.
+
+	int esi, ebp = 0, esp10;
+
+	vortex_src_flushbuffers(card, src);
+
+	if (sweep) {
+		if ((tr & 0x10000) && (tr != 0x10000)) {
+			tr = 0;
+			esi = 0x7;
+		} else {
+			if ((((short)tr) < 0) && (tr != 0x8000)) {
+				tr = 0;
+				esi = 0x8;
+			} else {
+				tr = 1;
+				esi = 0xc;
+			}
+		}
+	} else {
+		if ((cr & 0x10000) && (cr != 0x10000)) {
+			tr = 0;	/*ebx = 0 */
+			esi = 0x11 - ((cr >> 0xe) & 7);
+			if (cr & 0x3fff)
+				esi -= 1;
+			else
+				esi -= 2;
+		} else {
+			tr = 1;
+			esi = 0xc;
+		}
+	}
+	vortex_src_cleardrift(card, src);
+	vortex_src_set_throttlesource(card, src, thsource);
+
+	if ((dirplay == 0) && (sweep == 0)) {
+		if (tr)
+			esp10 = 0xf;
+		else
+			esp10 = 0xc;
+		ebp = 0;
+	} else {
+		if (tr)
+			ebp = 0xf;
+		else
+			ebp = 0xc;
+		esp10 = 0;
+	}
+	hwwrite(card->mmio, VORTEX_SRC_U0 + (src << 2),
+		(sl << 0x9) | (sweep << 0x8) | ((esi & 0xf) << 4) | d);
+	/* 0xc0   esi=0xc c=f=0 d=0 */
+	vortex_src_persist_convratio(card, src, cr);
+	hwwrite(card->mmio, VORTEX_SRC_U1 + (src << 2), b & 0xffff);
+	/* 0   b=0 */
+	hwwrite(card->mmio, VORTEX_SRC_U2 + (src << 2),
+		(tr << 0x11) | (dirplay << 0x10) | (ebp << 0x8) | esp10);
+	/* 0x30f00 e=g=1 esp10=0 ebp=f */
+	//printk(KERN_INFO "vortex: SRC %d, d=0x%x, esi=0x%x, esp10=0x%x, ebp=0x%x\n", src, d, esi, esp10, ebp);
+}
+
+static void vortex_srcblock_init(vortex_t * vortex)
+{
+	unsigned long addr;
+	int x;
+	hwwrite(vortex->mmio, VORTEX_SRC_SOURCESIZE, 0x1ff);
+	/*
+	   for (x=0; x<0x10; x++) {
+	   vortex_src_init(&vortex_src[x], x);
+	   }
+	 */
+	//addr = 0xcc3c;
+	//addr = 0x26c3c;
+	addr = VORTEX_SRC_RTBASE + 0x3c;
+	for (x = 0xf; x >= 0; x--) {
+		hwwrite(vortex->mmio, addr, 0);
+		addr -= 4;
+	}
+	//addr = 0xcc94;
+	//addr = 0x26c94;
+	addr = VORTEX_SRC_CHNBASE + 0x54;
+	for (x = 0x15; x >= 0; x--) {
+		hwwrite(vortex->mmio, addr, 0);
+		addr -= 4;
+	}
+}
+
+static int
+vortex_src_addWTD(vortex_t * vortex, unsigned char src, unsigned char ch)
+{
+	int temp, lifeboat = 0, prev;
+	// esp13 = src
+
+	temp = hwread(vortex->mmio, VORTEX_SRCBLOCK_SR);
+	if ((temp & (1 << ch)) == 0) {
+		hwwrite(vortex->mmio, VORTEX_SRC_CHNBASE + (ch << 2), src);
+		vortex_src_en_sr(vortex, ch);
+		return 1;
+	}
+	prev = VORTEX_SRC_CHNBASE + (ch << 2);	/*ebp */
+	temp = hwread(vortex->mmio, prev);
+	//while (temp & NR_SRC) {
+	while (temp & 0x10) {
+		prev = VORTEX_SRC_RTBASE + ((temp & 0xf) << 2);	/*esp12 */
+		//prev = VORTEX_SRC_RTBASE + ((temp & (NR_SRC-1)) << 2); /*esp12*/
+		temp = hwread(vortex->mmio, prev);
+		//printk(KERN_INFO "vortex: srcAddWTD: while addr=%x, val=%x\n", prev, temp);
+		if ((++lifeboat) > 0xf) {
+			printk(KERN_ERR
+			       "vortex_src_addWTD: lifeboat overflow\n");
+			return 0;
+		}
+	}
+	hwwrite(vortex->mmio, VORTEX_SRC_RTBASE + ((temp & 0xf) << 2), src);
+	//hwwrite(vortex->mmio, prev, (temp & (NR_SRC-1)) | NR_SRC);
+	hwwrite(vortex->mmio, prev, (temp & 0xf) | 0x10);
+	return 1;
+}
+
+static int
+vortex_src_delWTD(vortex_t * vortex, unsigned char src, unsigned char ch)
+{
+	int esp14 = -1, esp18, eax, ebx, edx, ebp, esi = 0;
+	//int esp1f=edi(while)=src, esp10=ch;
+
+	eax = hwread(vortex->mmio, VORTEX_SRCBLOCK_SR);
+	if (((1 << ch) & eax) == 0) {
+		printk(KERN_ERR "src alarm\n");
+		return 0;
+	}
+	ebp = VORTEX_SRC_CHNBASE + (ch << 2);
+	esp18 = hwread(vortex->mmio, ebp);
+	if (esp18 & 0x10) {
+		ebx = (esp18 & 0xf);
+		if (src == ebx) {
+			ebx = VORTEX_SRC_RTBASE + (src << 2);
+			edx = hwread(vortex->mmio, ebx);
+			//7b60
+			hwwrite(vortex->mmio, ebp, edx);
+			hwwrite(vortex->mmio, ebx, 0);
+		} else {
+			//7ad3
+			edx =
+			    hwread(vortex->mmio,
+				   VORTEX_SRC_RTBASE + (ebx << 2));
+			//printk(KERN_INFO "vortex: srcdelWTD: 1 addr=%x, val=%x, src=%x\n", ebx, edx, src);
+			while ((edx & 0xf) != src) {
+				if ((esi) > 0xf) {
+					printk
+					    ("vortex: srcdelWTD: error, lifeboat overflow\n");
+					return 0;
+				}
+				esp14 = ebx;
+				ebx = edx & 0xf;
+				ebp = ebx << 2;
+				edx =
+				    hwread(vortex->mmio,
+					   VORTEX_SRC_RTBASE + ebp);
+				//printk(KERN_INFO "vortex: srcdelWTD: while addr=%x, val=%x\n", ebp, edx);
+				esi++;
+			}
+			//7b30
+			ebp = ebx << 2;
+			if (edx & 0x10) {	/* Delete entry in between others */
+				ebx = VORTEX_SRC_RTBASE + ((edx & 0xf) << 2);
+				edx = hwread(vortex->mmio, ebx);
+				//7b60
+				hwwrite(vortex->mmio,
+					VORTEX_SRC_RTBASE + ebp, edx);
+				hwwrite(vortex->mmio, ebx, 0);
+				//printk(KERN_INFO "vortex srcdelWTD between addr= 0x%x, val= 0x%x\n", ebp, edx);
+			} else {	/* Delete last entry */
+				//7b83
+				if (esp14 == -1)
+					hwwrite(vortex->mmio,
+						VORTEX_SRC_CHNBASE +
+						(ch << 2), esp18 & 0xef);
+				else {
+					ebx = (0xffffffe0 & edx) | (0xf & ebx);
+					hwwrite(vortex->mmio,
+						VORTEX_SRC_RTBASE +
+						(esp14 << 2), ebx);
+					//printk(KERN_INFO"vortex srcdelWTD last addr= 0x%x, val= 0x%x\n", esp14, ebx);
+				}
+				hwwrite(vortex->mmio,
+					VORTEX_SRC_RTBASE + ebp, 0);
+				return 1;
+			}
+		}
+	} else {
+		//7be0
+		vortex_src_dis_sr(vortex, ch);
+		hwwrite(vortex->mmio, ebp, 0);
+	}
+	return 1;
+}
+
+ /*FIFO*/ static void
+vortex_fifo_clearadbdata(vortex_t * vortex, int fifo, int x)
+{
+	for (x--; x >= 0; x--)
+		hwwrite(vortex->mmio,
+			VORTEX_FIFO_ADBDATA +
+			(((fifo << FIFO_SIZE_BITS) + x) << 2), 0);
+}
+
+#if 0
+static void vortex_fifo_adbinitialize(vortex_t * vortex, int fifo, int j)
+{
+	vortex_fifo_clearadbdata(vortex, fifo, FIFO_SIZE);
+#ifdef CHIP_AU8820
+	hwwrite(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2),
+		(FIFO_U1 | ((j & FIFO_MASK) << 0xb)));
+#else
+	hwwrite(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2),
+		(FIFO_U1 | ((j & FIFO_MASK) << 0xc)));
+#endif
+}
+#endif
+static void vortex_fifo_setadbvalid(vortex_t * vortex, int fifo, int en)
+{
+	hwwrite(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2),
+		(hwread(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2)) &
+		 0xffffffef) | ((1 & en) << 4) | FIFO_U1);
+}
+
+static void
+vortex_fifo_setadbctrl(vortex_t * vortex, int fifo, int b, int priority,
+		       int empty, int valid, int f)
+{
+	int temp, lifeboat = 0;
+	//int this_8[NR_ADB] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* position */
+	int this_4 = 0x2;
+	/* f seems priority related.
+	 * CAsp4AdbDma::SetPriority is the only place that calls SetAdbCtrl with f set to 1
+	 * every where else it is set to 0. It seems, however, that CAsp4AdbDma::SetPriority
+	 * is never called, thus the f related bits remain a mystery for now.
+	 */
+	do {
+		temp = hwread(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2));
+		if (lifeboat++ > 0xbb8) {
+			printk(KERN_ERR
+			       "Vortex: vortex_fifo_setadbctrl fail\n");
+			break;
+		}
+	}
+	while (temp & FIFO_RDONLY);
+
+	// AU8830 semes to take some special care about fifo content (data).
+	// But i'm just to lazy to translate that :)
+	if (valid) {
+		if ((temp & FIFO_VALID) == 0) {
+			//this_8[fifo] = 0;
+			vortex_fifo_clearadbdata(vortex, fifo, FIFO_SIZE);	// this_4
+#ifdef CHIP_AU8820
+			temp = (this_4 & 0x1f) << 0xb;
+#else
+			temp = (this_4 & 0x3f) << 0xc;
+#endif
+			temp = (temp & 0xfffffffd) | ((b & 1) << 1);
+			temp = (temp & 0xfffffff3) | ((priority & 3) << 2);
+			temp = (temp & 0xffffffef) | ((valid & 1) << 4);
+			temp |= FIFO_U1;
+			temp = (temp & 0xffffffdf) | ((empty & 1) << 5);
+#ifdef CHIP_AU8820
+			temp = (temp & 0xfffbffff) | ((f & 1) << 0x12);
+#endif
+#ifdef CHIP_AU8830
+			temp = (temp & 0xf7ffffff) | ((f & 1) << 0x1b);
+			temp = (temp & 0xefffffff) | ((f & 1) << 0x1c);
+#endif
+#ifdef CHIP_AU8810
+			temp = (temp & 0xfeffffff) | ((f & 1) << 0x18);
+			temp = (temp & 0xfdffffff) | ((f & 1) << 0x19);
+#endif
+		}
+	} else {
+		if (temp & FIFO_VALID) {
+#ifdef CHIP_AU8820
+			temp = ((f & 1) << 0x12) | (temp & 0xfffbffef);
+#endif
+#ifdef CHIP_AU8830
+			temp =
+			    ((f & 1) << 0x1b) | (temp & 0xe7ffffef) | FIFO_BITS;
+#endif
+#ifdef CHIP_AU8810
+			temp =
+			    ((f & 1) << 0x18) | (temp & 0xfcffffef) | FIFO_BITS;
+#endif
+		} else
+			/*if (this_8[fifo]) */
+			vortex_fifo_clearadbdata(vortex, fifo, FIFO_SIZE);
+	}
+	hwwrite(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2), temp);
+	hwread(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2));
+}
+
+#ifndef CHIP_AU8810
+static void vortex_fifo_clearwtdata(vortex_t * vortex, int fifo, int x)
+{
+	if (x < 1)
+		return;
+	for (x--; x >= 0; x--)
+		hwwrite(vortex->mmio,
+			VORTEX_FIFO_WTDATA +
+			(((fifo << FIFO_SIZE_BITS) + x) << 2), 0);
+}
+
+static void vortex_fifo_wtinitialize(vortex_t * vortex, int fifo, int j)
+{
+	vortex_fifo_clearwtdata(vortex, fifo, FIFO_SIZE);
+#ifdef CHIP_AU8820
+	hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2),
+		(FIFO_U1 | ((j & FIFO_MASK) << 0xb)));
+#else
+	hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2),
+		(FIFO_U1 | ((j & FIFO_MASK) << 0xc)));
+#endif
+}
+
+static void vortex_fifo_setwtvalid(vortex_t * vortex, int fifo, int en)
+{
+	hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2),
+		(hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2)) &
+		 0xffffffef) | ((en & 1) << 4) | FIFO_U1);
+}
+
+static void
+vortex_fifo_setwtctrl(vortex_t * vortex, int fifo, int ctrl, int priority,
+		      int empty, int valid, int f)
+{
+	int temp = 0, lifeboat = 0;
+	int this_4 = 2;
+
+	do {
+		temp = hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2));
+		if (lifeboat++ > 0xbb8) {
+			printk(KERN_ERR "Vortex: vortex_fifo_setwtctrl fail\n");
+			break;
+		}
+	}
+	while (temp & FIFO_RDONLY);
+
+	if (valid) {
+		if ((temp & FIFO_VALID) == 0) {
+			vortex_fifo_clearwtdata(vortex, fifo, FIFO_SIZE);	// this_4
+#ifdef CHIP_AU8820
+			temp = (this_4 & 0x1f) << 0xb;
+#else
+			temp = (this_4 & 0x3f) << 0xc;
+#endif
+			temp = (temp & 0xfffffffd) | ((ctrl & 1) << 1);
+			temp = (temp & 0xfffffff3) | ((priority & 3) << 2);
+			temp = (temp & 0xffffffef) | ((valid & 1) << 4);
+			temp |= FIFO_U1;
+			temp = (temp & 0xffffffdf) | ((empty & 1) << 5);
+#ifdef CHIP_AU8820
+			temp = (temp & 0xfffbffff) | ((f & 1) << 0x12);
+#endif
+#ifdef CHIP_AU8830
+			temp = (temp & 0xf7ffffff) | ((f & 1) << 0x1b);
+			temp = (temp & 0xefffffff) | ((f & 1) << 0x1c);
+#endif
+#ifdef CHIP_AU8810
+			temp = (temp & 0xfeffffff) | ((f & 1) << 0x18);
+			temp = (temp & 0xfdffffff) | ((f & 1) << 0x19);
+#endif
+		}
+	} else {
+		if (temp & FIFO_VALID) {
+#ifdef CHIP_AU8820
+			temp = ((f & 1) << 0x12) | (temp & 0xfffbffef);
+#endif
+#ifdef CHIP_AU8830
+			temp =
+			    ((f & 1) << 0x1b) | (temp & 0xe7ffffef) | FIFO_BITS;
+#endif
+#ifdef CHIP_AU8810
+			temp =
+			    ((f & 1) << 0x18) | (temp & 0xfcffffef) | FIFO_BITS;
+#endif
+		} else
+			/*if (this_8[fifo]) */
+			vortex_fifo_clearwtdata(vortex, fifo, FIFO_SIZE);
+	}
+	hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2), temp);
+	hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2));
+
+/*	
+    do {
+		temp = hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2));
+		if (lifeboat++ > 0xbb8) {
+			printk(KERN_ERR "Vortex: vortex_fifo_setwtctrl fail (hanging)\n");
+			break;
+		}
+    } while ((temp & FIFO_RDONLY)&&(temp & FIFO_VALID)&&(temp != 0xFFFFFFFF));
+	
+	
+	if (valid) {
+		if (temp & FIFO_VALID) {
+			temp = 0x40000;
+			//temp |= 0x08000000;
+			//temp |= 0x10000000;
+			//temp |= 0x04000000;
+			//temp |= 0x00400000;
+			temp |= 0x1c400000;
+			temp &= 0xFFFFFFF3;
+			temp &= 0xFFFFFFEF;
+			temp |= (valid & 1) << 4;
+			hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2), temp);
+			return;
+		} else {
+			vortex_fifo_clearwtdata(vortex, fifo, FIFO_SIZE);
+			return;
+		}
+	} else {
+		temp &= 0xffffffef;
+		temp |= 0x08000000;
+		temp |= 0x10000000;
+		temp |= 0x04000000;
+		temp |= 0x00400000;
+		hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2), temp);
+		temp = hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2));
+		//((temp >> 6) & 0x3f) 
+		
+		priority = 0;
+		if (((temp & 0x0fc0) ^ ((temp >> 6) & 0x0fc0)) & 0FFFFFFC0)
+			vortex_fifo_clearwtdata(vortex, fifo, FIFO_SIZE);
+		valid = 0xfb;
+		temp = (temp & 0xfffffffd) | ((ctrl & 1) << 1);
+		temp = (temp & 0xfffdffff) | ((f & 1) << 0x11);
+		temp = (temp & 0xfffffff3) | ((priority & 3) << 2);
+		temp = (temp & 0xffffffef) | ((valid & 1) << 4);
+		temp = (temp & 0xffffffdf) | ((empty & 1) << 5);
+		hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2), temp);
+	}
+	
+	*/
+
+	/*
+	   temp = (temp & 0xfffffffd) | ((ctrl & 1) << 1);
+	   temp = (temp & 0xfffdffff) | ((f & 1) << 0x11);
+	   temp = (temp & 0xfffffff3) | ((priority & 3) << 2);
+	   temp = (temp & 0xffffffef) | ((valid & 1) << 4);
+	   temp = (temp & 0xffffffdf) | ((empty & 1) << 5);
+	   #ifdef FIFO_BITS
+	   temp = temp | FIFO_BITS | 40000;
+	   #endif
+	   // 0x1c440010, 0x1c400000
+	   hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2), temp);
+	 */
+}
+
+#endif
+static void vortex_fifo_init(vortex_t * vortex)
+{
+	int x;
+	unsigned long addr;
+
+	/* ADB DMA channels fifos. */
+	addr = VORTEX_FIFO_ADBCTRL + ((NR_ADB - 1) * 4);
+	for (x = NR_ADB - 1; x >= 0; x--) {
+		hwwrite(vortex->mmio, addr, (FIFO_U0 | FIFO_U1));
+		if (hwread(vortex->mmio, addr) != (FIFO_U0 | FIFO_U1))
+			printk(KERN_ERR "bad adb fifo reset!");
+		vortex_fifo_clearadbdata(vortex, x, FIFO_SIZE);
+		addr -= 4;
+	}
+
+#ifndef CHIP_AU8810
+	/* WT DMA channels fifos. */
+	addr = VORTEX_FIFO_WTCTRL + ((NR_WT - 1) * 4);
+	for (x = NR_WT - 1; x >= 0; x--) {
+		hwwrite(vortex->mmio, addr, FIFO_U0);
+		if (hwread(vortex->mmio, addr) != FIFO_U0)
+			printk(KERN_ERR
+			       "bad wt fifo reset (0x%08lx, 0x%08x)!\n",
+			       addr, hwread(vortex->mmio, addr));
+		vortex_fifo_clearwtdata(vortex, x, FIFO_SIZE);
+		addr -= 4;
+	}
+#endif
+	/* trigger... */
+#ifdef CHIP_AU8820
+	hwwrite(vortex->mmio, 0xf8c0, 0xd03);	//0x0843 0xd6b
+#else
+#ifdef CHIP_AU8830
+	hwwrite(vortex->mmio, 0x17000, 0x61);	/* wt a */
+	hwwrite(vortex->mmio, 0x17004, 0x61);	/* wt b */
+#endif
+	hwwrite(vortex->mmio, 0x17008, 0x61);	/* adb */
+#endif
+}
+
+/* ADBDMA */
+
+static void vortex_adbdma_init(vortex_t * vortex)
+{
+}
+
+static void vortex_adbdma_setfirstbuffer(vortex_t * vortex, int adbdma)
+{
+	stream_t *dma = &vortex->dma_adb[adbdma];
+
+	hwwrite(vortex->mmio, VORTEX_ADBDMA_CTRL + (adbdma << 2),
+		dma->dma_ctrl);
+}
+
+static void vortex_adbdma_setstartbuffer(vortex_t * vortex, int adbdma, int sb)
+{
+	stream_t *dma = &vortex->dma_adb[adbdma];
+	//hwwrite(vortex->mmio, VORTEX_ADBDMA_START + (adbdma << 2), sb << (((NR_ADB-1)-((adbdma&0xf)*2))));
+	hwwrite(vortex->mmio, VORTEX_ADBDMA_START + (adbdma << 2),
+		sb << ((0xf - (adbdma & 0xf)) * 2));
+	dma->period_real = dma->period_virt = sb;
+}
+
+static void
+vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
+			 snd_pcm_sgbuf_t * sgbuf, int psize, int count)
+{
+	stream_t *dma = &vortex->dma_adb[adbdma];
+
+	if (sgbuf == NULL) {
+		printk(KERN_INFO "vortex: FATAL: sgbuf is NULL!\n");
+		return;
+	}
+	//printk(KERN_INFO "vortex: page count = %d, tblcount = %d\n", count, sgbuf->tblsize);
+
+	dma->period_bytes = psize;
+	dma->nr_periods = count;
+	dma->sgbuf = sgbuf;
+
+	dma->cfg0 = 0;
+	dma->cfg1 = 0;
+	switch (count) {
+		/* Four or more pages */
+	default:
+	case 4:
+		dma->cfg1 |= 0x88000000 | 0x44000000 | 0x30000000 | (psize - 1);
+		hwwrite(vortex->mmio,
+			VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0xc,
+			snd_sgbuf_get_addr(sgbuf, psize * 3));
+		/* 3 pages */
+	case 3:
+		dma->cfg0 |= 0x12000000;
+		dma->cfg1 |= 0x80000000 | 0x40000000 | ((psize - 1) << 0xc);
+		hwwrite(vortex->mmio,
+			VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x8,
+			snd_sgbuf_get_addr(sgbuf, psize * 2));
+		/* 2 pages */
+	case 2:
+		dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize - 1);
+		hwwrite(vortex->mmio,
+			VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x4,
+			snd_sgbuf_get_addr(sgbuf, psize));
+		/* 1 page */
+	case 1:
+		dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize - 1) << 0xc);
+		hwwrite(vortex->mmio,
+			VORTEX_ADBDMA_BUFBASE + (adbdma << 4),
+			snd_sgbuf_get_addr(sgbuf, 0));
+		break;
+	}
+	//printk("vortex: cfg0 = 0x%x\nvortex: cfg1=0x%x\n", dma->cfg0, dma->cfg1);
+	hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFCFG0 + (adbdma << 3), dma->cfg0);
+	hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFCFG1 + (adbdma << 3), dma->cfg1);
+
+	vortex_adbdma_setfirstbuffer(vortex, adbdma);
+	vortex_adbdma_setstartbuffer(vortex, adbdma, 0);
+}
+
+static void
+vortex_adbdma_setmode(vortex_t * vortex, int adbdma, int ie, int dir,
+		      int fmt, int d, unsigned long offset)
+{
+	stream_t *dma = &vortex->dma_adb[adbdma];
+
+	dma->dma_unknown = d;
+	dma->dma_ctrl =
+	    ((offset & OFFSET_MASK) | (dma->dma_ctrl & ~OFFSET_MASK));
+	/* Enable PCMOUT interrupts. */
+	dma->dma_ctrl =
+	    (dma->dma_ctrl & ~IE_MASK) | ((ie << IE_SHIFT) & IE_MASK);
+
+	dma->dma_ctrl =
+	    (dma->dma_ctrl & ~DIR_MASK) | ((dir << DIR_SHIFT) & DIR_MASK);
+	dma->dma_ctrl =
+	    (dma->dma_ctrl & ~FMT_MASK) | ((fmt << FMT_SHIFT) & FMT_MASK);
+
+	hwwrite(vortex->mmio, VORTEX_ADBDMA_CTRL + (adbdma << 2),
+		dma->dma_ctrl);
+	hwread(vortex->mmio, VORTEX_ADBDMA_CTRL + (adbdma << 2));
+}
+
+static int vortex_adbdma_bufshift(vortex_t * vortex, int adbdma)
+{
+	stream_t *dma = &vortex->dma_adb[adbdma];
+	int page, p, pp, delta, i;
+
+	page =
+	    (hwread(vortex->mmio, VORTEX_ADBDMA_STAT + (adbdma << 2)) &
+	     ADB_SUBBUF_MASK) >> ADB_SUBBUF_SHIFT;
+	if (dma->nr_periods >= 4)
+		delta = (page - dma->period_real) & 3;
+	else {
+		delta = (page - dma->period_real);
+		if (delta < 0)
+			delta += dma->nr_periods;
+	}
+	if (delta == 0)
+		return 0;
+
+	/* refresh hw page table */
+	if (dma->nr_periods > 4) {
+		for (i = 0; i < delta; i++) {
+			/* p: audio buffer page index */
+			p = dma->period_virt + i + 4;
+			if (p >= dma->nr_periods)
+				p -= dma->nr_periods;
+			/* pp: hardware DMA page index. */
+			pp = dma->period_real + i;
+			if (pp >= 4)
+				pp -= 4;
+			//hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFBASE+(((adbdma << 2)+pp) << 2), dma->table[p].addr);
+			hwwrite(vortex->mmio,
+				VORTEX_ADBDMA_BUFBASE + (((adbdma << 2) + pp) << 2),
+				snd_sgbuf_get_addr(dma->sgbuf,
+				dma->period_bytes * p));
+			/* Force write thru cache. */
+			hwread(vortex->mmio, VORTEX_ADBDMA_BUFBASE +
+			       (((adbdma << 2) + pp) << 2));
+		}
+	}
+	dma->period_virt += delta;
+	dma->period_real = page;
+	if (dma->period_virt >= dma->nr_periods)
+		dma->period_virt -= dma->nr_periods;
+	if (delta != 1)
+		printk(KERN_INFO "vortex: %d virt=%d, real=%d, delta=%d\n",
+		       adbdma, dma->period_virt, dma->period_real, delta);
+
+	return delta;
+}
+
+static int inline vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma)
+{
+	stream_t *dma = &vortex->dma_adb[adbdma];
+	int temp;
+
+	temp = hwread(vortex->mmio, VORTEX_ADBDMA_STAT + (adbdma << 2));
+	temp = (dma->period_virt * dma->period_bytes) + (temp & POS_MASK);
+	return (temp);
+}
+
+static void vortex_adbdma_startfifo(vortex_t * vortex, int adbdma)
+{
+	int this_8 = 0 /*empty */ , this_4 = 0 /*priority */ ;
+	stream_t *dma = &vortex->dma_adb[adbdma];
+
+	switch (dma->fifo_status) {
+	case FIFO_START:
+		vortex_fifo_setadbvalid(vortex, adbdma,
+					dma->fifo_enabled ? 1 : 0);
+		break;
+	case FIFO_STOP:
+		this_8 = 1;
+		hwwrite(vortex->mmio, VORTEX_ADBDMA_CTRL + (adbdma << 2),
+			dma->dma_ctrl);
+		vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown,
+				       this_4, this_8,
+				       dma->fifo_enabled ? 1 : 0, 0);
+		break;
+	case FIFO_PAUSE:
+		vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown,
+				       this_4, this_8,
+				       dma->fifo_enabled ? 1 : 0, 0);
+		break;
+	}
+	dma->fifo_status = FIFO_START;
+}
+
+static void vortex_adbdma_resumefifo(vortex_t * vortex, int adbdma)
+{
+	stream_t *dma = &vortex->dma_adb[adbdma];
+
+	int this_8 = 1, this_4 = 0;
+	switch (dma->fifo_status) {
+	case FIFO_STOP:
+		hwwrite(vortex->mmio, VORTEX_ADBDMA_CTRL + (adbdma << 2),
+			dma->dma_ctrl);
+		vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown,
+				       this_4, this_8,
+				       dma->fifo_enabled ? 1 : 0, 0);
+		break;
+	case FIFO_PAUSE:
+		vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown,
+				       this_4, this_8,
+				       dma->fifo_enabled ? 1 : 0, 0);
+		break;
+	}
+	dma->fifo_status = FIFO_START;
+}
+
+static void vortex_adbdma_pausefifo(vortex_t * vortex, int adbdma)
+{
+	stream_t *dma = &vortex->dma_adb[adbdma];
+
+	int this_8 = 0, this_4 = 0;
+	switch (dma->fifo_status) {
+	case FIFO_START:
+		vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown,
+				       this_4, this_8, 0, 0);
+		break;
+	case FIFO_STOP:
+		hwwrite(vortex->mmio, VORTEX_ADBDMA_CTRL + (adbdma << 2),
+			dma->dma_ctrl);
+		vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown,
+				       this_4, this_8, 0, 0);
+		break;
+	}
+	dma->fifo_status = FIFO_PAUSE;
+}
+
+#if 0				// Using pause instead
+static void vortex_adbdma_stopfifo(vortex_t * vortex, int adbdma)
+{
+	stream_t *dma = &vortex->dma_adb[adbdma];
+
+	int this_4 = 0, this_8 = 0;
+	if (dma->fifo_status == FIFO_START)
+		vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown,
+				       this_4, this_8, 0, 0);
+	else if (dma->fifo_status == FIFO_STOP)
+		return;
+	dma->fifo_status = FIFO_STOP;
+	dma->fifo_enabled = 0;
+}
+
+#endif
+/* WTDMA */
+
+#ifndef CHIP_AU8810
+static void vortex_wtdma_setfirstbuffer(vortex_t * vortex, int wtdma)
+{
+	//int this_7c=dma_ctrl;
+	stream_t *dma = &vortex->dma_wt[wtdma];
+
+	hwwrite(vortex->mmio, VORTEX_WTDMA_CTRL + (wtdma << 2), dma->dma_ctrl);
+}
+
+static void vortex_wtdma_setstartbuffer(vortex_t * vortex, int wtdma, int sb)
+{
+	stream_t *dma = &vortex->dma_wt[wtdma];
+	//hwwrite(vortex->mmio, VORTEX_WTDMA_START + (wtdma << 2), sb << ((0x1f-(wtdma&0xf)*2)));
+	hwwrite(vortex->mmio, VORTEX_WTDMA_START + (wtdma << 2),
+		sb << ((0xf - (wtdma & 0xf)) * 2));
+	dma->period_real = dma->period_virt = sb;
+}
+
+static void
+vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma,
+			snd_pcm_sgbuf_t * sgbuf, int psize, int count)
+{
+	stream_t *dma = &vortex->dma_wt[wtdma];
+
+	dma->period_bytes = psize;
+	dma->nr_periods = count;
+	dma->sgbuf = sgbuf;
+
+	psize--;
+
+	dma->cfg0 = 0;
+	dma->cfg1 = 0;
+	switch (count) {
+		/* Four or more pages */
+	default:
+	case 4:
+		dma->cfg1 |= 0x88000000 | 0x44000000 | 0x30000000 | psize;
+		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4),
+			snd_sgbuf_get_addr(sgbuf, psize * 3));
+		/* 3 pages */
+	case 3:
+		dma->cfg0 |= 0x12000000;
+		dma->cfg1 |= 0x80000000 | 0x40000000 | (psize << 0xc);
+		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4),
+			snd_sgbuf_get_addr(sgbuf, psize * 2));
+		/* 2 pages */
+	case 2:
+		dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | psize;
+		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4),
+			snd_sgbuf_get_addr(sgbuf, psize));
+		/* 1 page */
+	case 1:
+		dma->cfg0 |= 0x80000000 | 0x40000000 | (psize << 0xc);
+		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4),
+			snd_sgbuf_get_addr(sgbuf, 0));
+		break;
+	}
+	hwwrite(vortex->mmio, VORTEX_WTDMA_BUFCFG0 + (wtdma << 3), dma->cfg0);
+	hwwrite(vortex->mmio, VORTEX_WTDMA_BUFCFG1 + (wtdma << 3), dma->cfg1);
+
+	vortex_wtdma_setfirstbuffer(vortex, wtdma);
+	vortex_wtdma_setstartbuffer(vortex, wtdma, 0);
+}
+
+static void
+vortex_wtdma_setmode(vortex_t * vortex, int wtdma, int ie, int fmt, int d,
+		     /*int e, */ unsigned long offset)
+{
+	stream_t *dma = &vortex->dma_wt[wtdma];
+
+	//dma->this_08 = e;
+	dma->dma_unknown = d;
+	dma->dma_ctrl = 0;
+	dma->dma_ctrl =
+	    ((offset & OFFSET_MASK) | (dma->dma_ctrl & ~OFFSET_MASK));
+	/* PCMOUT interrupt */
+	dma->dma_ctrl =
+	    (dma->dma_ctrl & ~IE_MASK) | ((ie << IE_SHIFT) & IE_MASK);
+	/* Always playback. */
+	dma->dma_ctrl |= (1 << DIR_SHIFT);
+	/* Audio Format */
+	dma->dma_ctrl =
+	    (dma->dma_ctrl & FMT_MASK) | ((fmt << FMT_SHIFT) & FMT_MASK);
+	/* Write into hardware */
+	hwwrite(vortex->mmio, VORTEX_WTDMA_CTRL + (wtdma << 2), dma->dma_ctrl);
+}
+
+static int vortex_wtdma_bufshift(vortex_t * vortex, int wtdma)
+{
+	stream_t *dma = &vortex->dma_wt[wtdma];
+	int page, p, pp, delta, i;
+
+	page =
+	    (hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2)) &
+	     WT_SUBBUF_MASK)
+	    >> WT_SUBBUF_SHIFT;
+	if (dma->nr_periods >= 4)
+		delta = (page - dma->period_real) & 3;
+	else {
+		delta = (page - dma->period_real);
+		if (delta < 0)
+			delta += dma->nr_periods;
+	}
+	if (delta == 0)
+		return 0;
+
+	/* refresh hw page table */
+	if (dma->nr_periods > 4) {
+		for (i = 0; i < delta; i++) {
+			/* p: audio buffer page index */
+			p = dma->period_virt + i + 4;
+			if (p >= dma->nr_periods)
+				p -= dma->nr_periods;
+			/* pp: hardware DMA page index. */
+			pp = dma->period_real + i;
+			if (pp >= 4)
+				pp -= 4;
+			hwwrite(vortex->mmio,
+				VORTEX_WTDMA_BUFBASE +
+				(((wtdma << 2) + pp) << 2),
+				snd_sgbuf_get_addr(dma->sgbuf, dma->period_bytes * p));
+			/* Force write thru cache. */
+			hwread(vortex->mmio, VORTEX_WTDMA_BUFBASE +
+			       (((wtdma << 2) + pp) << 2));
+		}
+	}
+	dma->period_virt += delta;
+	if (dma->period_virt >= dma->nr_periods)
+		dma->period_virt -= dma->nr_periods;
+	dma->period_real = page;
+
+	if (delta != 1)
+		printk(KERN_WARNING "vortex: wt virt = %d, delta = %d\n",
+		       dma->period_virt, delta);
+
+	return delta;
+}
+
+#if 0
+static void
+vortex_wtdma_getposition(vortex_t * vortex, int wtdma, int *subbuf, int *pos)
+{
+	int temp;
+	temp = hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2));
+	*subbuf = (temp >> WT_SUBBUF_SHIFT) & WT_SUBBUF_MASK;
+	*pos = temp & POS_MASK;
+}
+
+static int vortex_wtdma_getcursubuffer(vortex_t * vortex, int wtdma)
+{
+	return ((hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2)) >>
+		 POS_SHIFT) & POS_MASK);
+}
+#endif
+static int inline vortex_wtdma_getlinearpos(vortex_t * vortex, int wtdma)
+{
+	stream_t *dma = &vortex->dma_wt[wtdma];
+	int temp;
+
+	temp = hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2));
+	//temp = (temp & POS_MASK) + (((temp>>WT_SUBBUF_SHIFT) & WT_SUBBUF_MASK)*(dma->cfg0&POS_MASK));
+	temp = (temp & POS_MASK) + ((dma->period_virt) * (dma->period_bytes));
+	return temp;
+}
+
+static void vortex_wtdma_startfifo(vortex_t * vortex, int wtdma)
+{
+	stream_t *dma = &vortex->dma_wt[wtdma];
+	int this_8 = 0, this_4 = 0;
+
+	switch (dma->fifo_status) {
+	case FIFO_START:
+		vortex_fifo_setwtvalid(vortex, wtdma,
+				       dma->fifo_enabled ? 1 : 0);
+		break;
+	case FIFO_STOP:
+		this_8 = 1;
+		hwwrite(vortex->mmio, VORTEX_WTDMA_CTRL + (wtdma << 2),
+			dma->dma_ctrl);
+		vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown,
+				      this_4, this_8,
+				      dma->fifo_enabled ? 1 : 0, 0);
+		break;
+	case FIFO_PAUSE:
+		vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown,
+				      this_4, this_8,
+				      dma->fifo_enabled ? 1 : 0, 0);
+		break;
+	}
+	dma->fifo_status = FIFO_START;
+}
+
+static void vortex_wtdma_resumefifo(vortex_t * vortex, int wtdma)
+{
+	stream_t *dma = &vortex->dma_wt[wtdma];
+
+	int this_8 = 0, this_4 = 0;
+	switch (dma->fifo_status) {
+	case FIFO_STOP:
+		hwwrite(vortex->mmio, VORTEX_WTDMA_CTRL + (wtdma << 2),
+			dma->dma_ctrl);
+		vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown,
+				      this_4, this_8,
+				      dma->fifo_enabled ? 1 : 0, 0);
+		break;
+	case FIFO_PAUSE:
+		vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown,
+				      this_4, this_8,
+				      dma->fifo_enabled ? 1 : 0, 0);
+		break;
+	}
+	dma->fifo_status = FIFO_START;
+}
+
+static void vortex_wtdma_pausefifo(vortex_t * vortex, int wtdma)
+{
+	stream_t *dma = &vortex->dma_wt[wtdma];
+
+	int this_8 = 0, this_4 = 0;
+	switch (dma->fifo_status) {
+	case FIFO_START:
+		vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown,
+				      this_4, this_8, 0, 0);
+		break;
+	case FIFO_STOP:
+		hwwrite(vortex->mmio, VORTEX_WTDMA_CTRL + (wtdma << 2),
+			dma->dma_ctrl);
+		vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown,
+				      this_4, this_8, 0, 0);
+		break;
+	}
+	dma->fifo_status = FIFO_PAUSE;
+}
+
+static void vortex_wtdma_stopfifo(vortex_t * vortex, int wtdma)
+{
+	stream_t *dma = &vortex->dma_wt[wtdma];
+
+	int this_4 = 0, this_8 = 0;
+	if (dma->fifo_status == FIFO_START)
+		vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown,
+				      this_4, this_8, 0, 0);
+	else if (dma->fifo_status == FIFO_STOP)
+		return;
+	dma->fifo_status = FIFO_STOP;
+	dma->fifo_enabled = 0;
+}
+
+#endif
+/* ADB Routes */
+
+typedef int ADBRamLink;
+static void vortex_adb_init(vortex_t * vortex)
+{
+	int i;
+	/* it looks like we are writing more than we need to...
+	 * if we write what we are supposed to it breaks things... */
+	hwwrite(vortex->mmio, VORTEX_ADB_SR, 0);
+	for (i = 0; i < VORTEX_ADB_RTBASE_SIZE; i++)
+		hwwrite(vortex->mmio, VORTEX_ADB_RTBASE + (i << 2),
+			hwread(vortex->mmio,
+			       VORTEX_ADB_RTBASE + (i << 2)) | ROUTE_MASK);
+	for (i = 0; i < VORTEX_ADB_CHNBASE_SIZE; i++) {
+		hwwrite(vortex->mmio, VORTEX_ADB_CHNBASE + (i << 2),
+			hwread(vortex->mmio,
+			       VORTEX_ADB_CHNBASE + (i << 2)) | ROUTE_MASK);
+	}
+}
+
+static void vortex_adb_en_sr(vortex_t * vortex, int channel)
+{
+	hwwrite(vortex->mmio, VORTEX_ADB_SR,
+		hwread(vortex->mmio, VORTEX_ADB_SR) | (0x1 << channel));
+}
+
+static void vortex_adb_dis_sr(vortex_t * vortex, int channel)
+{
+	hwwrite(vortex->mmio, VORTEX_ADB_SR,
+		hwread(vortex->mmio, VORTEX_ADB_SR) & ~(0x1 << channel));
+}
+
+static void
+vortex_adb_addroutes(vortex_t * vortex, unsigned char channel,
+		     ADBRamLink * route, int rnum)
+{
+	int temp, prev, lifeboat = 0;
+
+	if ((rnum <= 0) || (route == NULL))
+		return;
+	/* Write last routes. */
+	rnum--;
+	hwwrite(vortex->mmio,
+		VORTEX_ADB_RTBASE + ((route[rnum] & ADB_MASK) << 2),
+		ROUTE_MASK);
+	while (rnum > 0) {
+		hwwrite(vortex->mmio,
+			VORTEX_ADB_RTBASE +
+			((route[rnum - 1] & ADB_MASK) << 2), route[rnum]);
+		rnum--;
+	}
+	/* Write first route. */
+	temp =
+	    hwread(vortex->mmio,
+		   VORTEX_ADB_CHNBASE + (channel << 2)) & ADB_MASK;
+	if (temp == ADB_MASK) {
+		/* First entry on this channel. */
+		hwwrite(vortex->mmio, VORTEX_ADB_CHNBASE + (channel << 2),
+			route[0]);
+		vortex_adb_en_sr(vortex, channel);
+		return;
+	}
+	/* Not first entry on this channel. Need to link. */
+	do {
+		prev = temp;
+		temp =
+		    hwread(vortex->mmio,
+			   VORTEX_ADB_RTBASE + (temp << 2)) & ADB_MASK;
+		if ((lifeboat++) > ADB_MASK) {
+			printk(KERN_ERR
+			       "vortex_adb_addroutes: unending route! 0x%x\n",
+			       *route);
+			return;
+		}
+	}
+	while (temp != ADB_MASK);
+	hwwrite(vortex->mmio, VORTEX_ADB_RTBASE + (prev << 2), route[0]);
+}
+
+static void
+vortex_adb_delroutes(vortex_t * vortex, unsigned char channel,
+		     ADBRamLink route0, ADBRamLink route1)
+{
+	int temp, lifeboat = 0, prev;
+
+	/* Find route. */
+	temp =
+	    hwread(vortex->mmio,
+		   VORTEX_ADB_CHNBASE + (channel << 2)) & ADB_MASK;
+	if (temp == (route0 & ADB_MASK)) {
+		temp =
+		    hwread(vortex->mmio,
+			   VORTEX_ADB_RTBASE + ((route1 & ADB_MASK) << 2));
+		if ((temp & ADB_MASK) == ADB_MASK)
+			vortex_adb_dis_sr(vortex, channel);
+		hwwrite(vortex->mmio, VORTEX_ADB_CHNBASE + (channel << 2),
+			temp);
+		return;
+	}
+	do {
+		prev = temp;
+		temp =
+		    hwread(vortex->mmio,
+			   VORTEX_ADB_RTBASE + (prev << 2)) & ADB_MASK;
+		if (((lifeboat++) > ADB_MASK) || (temp == ADB_MASK)) {
+			printk(KERN_ERR
+			       "vortex_adb_delroutes: route not found! 0x%x\n",
+			       route0);
+			return;
+		}
+	}
+	while (temp != (route0 & ADB_MASK));
+	temp = hwread(vortex->mmio, VORTEX_ADB_RTBASE + (temp << 2));
+	if ((temp & ADB_MASK) == route1)
+		temp = hwread(vortex->mmio, VORTEX_ADB_RTBASE + (temp << 2));
+	/* Make bridge over deleted route. */
+	hwwrite(vortex->mmio, VORTEX_ADB_RTBASE + (prev << 2), temp);
+}
+
+static void
+vortex_route(vortex_t * vortex, int en, unsigned char channel,
+	     unsigned char source, unsigned char dest)
+{
+	ADBRamLink route;
+
+	route = ((source & ADB_MASK) << ADB_SHIFT) | (dest & ADB_MASK);
+	if (en) {
+		vortex_adb_addroutes(vortex, channel, &route, 1);
+		if ((source < (OFFSET_SRCOUT + NR_SRC))
+		    && (source >= OFFSET_SRCOUT))
+			vortex_src_addWTD(vortex, (source - OFFSET_SRCOUT),
+					  channel);
+		else if ((source < (OFFSET_MIXOUT + NR_MIXOUT))
+			 && (source >= OFFSET_MIXOUT))
+			vortex_mixer_addWTD(vortex,
+					    (source - OFFSET_MIXOUT), channel);
+	} else {
+		vortex_adb_delroutes(vortex, channel, route, route);
+		if ((source < (OFFSET_SRCOUT + NR_SRC))
+		    && (source >= OFFSET_SRCOUT))
+			vortex_src_delWTD(vortex, (source - OFFSET_SRCOUT),
+					  channel);
+		else if ((source < (OFFSET_MIXOUT + NR_MIXOUT))
+			 && (source >= OFFSET_MIXOUT))
+			vortex_mixer_delWTD(vortex,
+					    (source - OFFSET_MIXOUT), channel);
+	}
+}
+
+#if 0
+static void
+vortex_routes(vortex_t * vortex, int en, unsigned char channel,
+	      unsigned char source, unsigned char dest0, unsigned char dest1)
+{
+	ADBRamLink route[2];
+
+	route[0] = ((source & ADB_MASK) << ADB_SHIFT) | (dest0 & ADB_MASK);
+	route[1] = ((source & ADB_MASK) << ADB_SHIFT) | (dest1 & ADB_MASK);
+
+	if (en) {
+		vortex_adb_addroutes(vortex, channel, route, 2);
+		if ((source < (OFFSET_SRCOUT + NR_SRC))
+		    && (source >= (OFFSET_SRCOUT)))
+			vortex_src_addWTD(vortex, (source - OFFSET_SRCOUT),
+					  channel);
+		else if ((source < (OFFSET_MIXOUT + NR_MIXOUT))
+			 && (source >= (OFFSET_MIXOUT)))
+			vortex_mixer_addWTD(vortex,
+					    (source - OFFSET_MIXOUT), channel);
+	} else {
+		vortex_adb_delroutes(vortex, channel, route[0], route[1]);
+		if ((source < (OFFSET_SRCOUT + NR_SRC))
+		    && (source >= (OFFSET_SRCOUT)))
+			vortex_src_delWTD(vortex, (source - OFFSET_SRCOUT),
+					  channel);
+		else if ((source < (OFFSET_MIXOUT + NR_MIXOUT))
+			 && (source >= (OFFSET_MIXOUT)))
+			vortex_mixer_delWTD(vortex,
+					    (source - OFFSET_MIXOUT), channel);
+	}
+}
+
+#endif
+/* Route two sources to same target. Sources must be of same class !!! */
+static void
+vortex_routeLRT(vortex_t * vortex, int en, unsigned char ch,
+		unsigned char source0, unsigned char source1,
+		unsigned char dest)
+{
+	ADBRamLink route[2];
+
+	route[0] = ((source0 & ADB_MASK) << ADB_SHIFT) | (dest & ADB_MASK);
+	route[1] = ((source1 & ADB_MASK) << ADB_SHIFT) | (dest & ADB_MASK);
+
+	if (dest < 0x10)
+		route[1] = (route[1] & ~ADB_MASK) | (dest + 0x20);	/* fifo A */
+
+	if (en) {
+		vortex_adb_addroutes(vortex, ch, route, 2);
+		if ((source0 < (OFFSET_SRCOUT + NR_SRC))
+		    && (source0 >= OFFSET_SRCOUT)) {
+			vortex_src_addWTD(vortex,
+					  (source0 - OFFSET_SRCOUT), ch);
+			vortex_src_addWTD(vortex,
+					  (source1 - OFFSET_SRCOUT), ch);
+		} else if ((source0 < (OFFSET_MIXOUT + NR_MIXOUT))
+			   && (source0 >= OFFSET_MIXOUT)) {
+			vortex_mixer_addWTD(vortex,
+					    (source0 - OFFSET_MIXOUT), ch);
+			vortex_mixer_addWTD(vortex,
+					    (source1 - OFFSET_MIXOUT), ch);
+		}
+	} else {
+		vortex_adb_delroutes(vortex, ch, route[0], route[1]);
+		if ((source0 < (OFFSET_SRCOUT + NR_SRC))
+		    && (source0 >= OFFSET_SRCOUT)) {
+			vortex_src_delWTD(vortex,
+					  (source0 - OFFSET_SRCOUT), ch);
+			vortex_src_delWTD(vortex,
+					  (source1 - OFFSET_SRCOUT), ch);
+		} else if ((source0 < (OFFSET_MIXOUT + NR_MIXOUT))
+			   && (source0 >= OFFSET_MIXOUT)) {
+			vortex_mixer_delWTD(vortex,
+					    (source0 - OFFSET_MIXOUT), ch);
+			vortex_mixer_delWTD(vortex,
+					    (source1 - OFFSET_MIXOUT), ch);
+		}
+	}
+}
+
+/* Connection stuff */
+
+// Connect adbdma to src('s).
+static void
+vortex_connection_adbdma_src(vortex_t * vortex, int en, unsigned char ch,
+			     unsigned char adbdma, unsigned char src)
+{
+	vortex_route(vortex, en, ch, ADB_DMA(adbdma), ADB_SRCIN(src));
+}
+
+// Connect SRC to mixin.
+static void
+vortex_connection_src_mixin(vortex_t * vortex, int en,
+			    unsigned char channel, unsigned char src,
+			    unsigned char mixin)
+{
+	vortex_route(vortex, en, channel, ADB_SRCOUT(src), ADB_MIXIN(mixin));
+}
+
+// Connect mixin with mix output.
+static void
+vortex_connection_mixin_mix(vortex_t * vortex, int en, unsigned char mixin,
+			    unsigned char mix, int a)
+{
+	if (en) {
+		vortex_mix_enableinput(vortex, mix, mixin);
+		vortex_mix_setinputvolumebyte(vortex, mix, mixin, MIX_DEFIGAIN);	// added to original code.
+	} else
+		vortex_mix_disableinput(vortex, mix, mixin, a);
+}
+
+// Connect absolut address to mixin.
+static void
+vortex_connection_adb_mixin(vortex_t * vortex, int en,
+			    unsigned char channel, unsigned char source,
+			    unsigned char mixin)
+{
+	vortex_route(vortex, en, channel, source, ADB_MIXIN(mixin));
+}
+
+static void
+vortex_connection_src_adbdma(vortex_t * vortex, int en, unsigned char ch,
+			     unsigned char src, unsigned char adbdma)
+{
+	vortex_route(vortex, en, ch, ADB_SRCOUT(src), ADB_DMA(adbdma));
+}
+
+static void
+vortex_connection_src_src_adbdma(vortex_t * vortex, int en,
+				 unsigned char ch, unsigned char src0,
+				 unsigned char src1, unsigned char adbdma)
+{
+
+	vortex_routeLRT(vortex, en, ch, ADB_SRCOUT(src0), ADB_SRCOUT(src1),
+			ADB_DMA(adbdma));
+}
+
+// mix to absolut address.
+static void
+vortex_connection_mix_adb(vortex_t * vortex, int en, unsigned char ch,
+			  unsigned char mix, unsigned char dest)
+{
+	vortex_route(vortex, en, ch, ADB_MIXOUT(mix), dest);
+	vortex_mix_setvolumebyte(vortex, mix, MIX_DEFOGAIN);	// added to original code.
+}
+
+// mixer to src.
+static void
+vortex_connection_mix_src(vortex_t * vortex, int en, unsigned char ch,
+			  unsigned char mix, unsigned char src)
+{
+	vortex_route(vortex, en, ch, ADB_MIXOUT(mix), ADB_SRCIN(src));
+	vortex_mix_setvolumebyte(vortex, mix, MIX_DEFOGAIN);	// added to original code.
+}
+
+#if 0
+static void
+vortex_connection_adbdma_src_src(vortex_t * vortex, int en,
+				 unsigned char channel,
+				 unsigned char adbdma, unsigned char src0,
+				 unsigned char src1)
+{
+	vortex_routes(vortex, en, channel, ADB_DMA(adbdma),
+		      ADB_SRCIN(src0), ADB_SRCIN(src1));
+}
+
+// Connect two mix to AdbDma.
+static void
+vortex_connection_mix_mix_adbdma(vortex_t * vortex, int en,
+				 unsigned char ch, unsigned char mix0,
+				 unsigned char mix1, unsigned char adbdma)
+{
+
+	ADBRamLink routes[2];
+	routes[0] =
+	    (((mix0 +
+	       OFFSET_MIXOUT) & ADB_MASK) << ADB_SHIFT) | (adbdma & ADB_MASK);
+	routes[1] =
+	    (((mix1 + OFFSET_MIXOUT) & ADB_MASK) << ADB_SHIFT) | ((adbdma +
+								   0x20) &
+								  ADB_MASK);
+	if (en) {
+		vortex_adb_addroutes(vortex, ch, routes, 0x2);
+		vortex_mixer_addWTD(vortex, mix0, ch);
+		vortex_mixer_addWTD(vortex, mix1, ch);
+	} else {
+		vortex_adb_delroutes(vortex, ch, routes[0], routes[1]);
+		vortex_mixer_delWTD(vortex, mix0, ch);
+		vortex_mixer_delWTD(vortex, mix1, ch);
+	}
+}
+#endif
+
+/* CODEC connect. */
+
+static void
+vortex_connect_codecplay(vortex_t * vortex, int en, unsigned char mixers[])
+{
+#ifdef CHIP_AU8820
+	vortex_connection_mix_adb(vortex, en, 0x11, mixers[0], ADB_CODECOUT(0));
+	vortex_connection_mix_adb(vortex, en, 0x11, mixers[1], ADB_CODECOUT(1));
+#else
+#if 1
+	// Connect front channels through EQ.
+	vortex_connection_mix_adb(vortex, en, 0x11, mixers[0], ADB_EQIN(0));
+	vortex_connection_mix_adb(vortex, en, 0x11, mixers[1], ADB_EQIN(1));
+	vortex_route(vortex, en, 0x11, ADB_EQOUT(0), ADB_CODECOUT(0));
+	vortex_route(vortex, en, 0x11, ADB_EQOUT(1), ADB_CODECOUT(1));
+
+	/* Check if reg 0x28 has SDAC bit set. */
+	if (VORTEX_IS_QUAD(vortex)) {
+		/* Rear channel. Note: ADB_CODECOUT(0+2) and (1+2) is for AC97 modem */
+		vortex_connection_mix_adb(vortex, en, 0x11, mixers[2],
+					  ADB_CODECOUT(0 + 4));
+		vortex_connection_mix_adb(vortex, en, 0x11, mixers[3],
+					  ADB_CODECOUT(1 + 4));
+		//printk("SDAC detected ");
+	}
+#else
+	// Use plain direct output to codec.
+	vortex_connection_mix_adb(vortex, en, 0x11, mixers[0], ADB_CODECOUT(0));
+	vortex_connection_mix_adb(vortex, en, 0x11, mixers[1], ADB_CODECOUT(1));
+#endif
+#endif
+}
+
+static void
+vortex_connect_codecrec(vortex_t * vortex, int en, unsigned char mixin0,
+			unsigned char mixin1)
+{
+	/*
+	   Enable: 0x1, 0x1
+	   Channel: 0x11, 0x11
+	   ADB Source address: 0x48, 0x49
+	   Destination Asp4Topology_0x9c,0x98
+	 */
+	vortex_connection_adb_mixin(vortex, en, 0x11, ADB_CODECIN(0), mixin0);
+	vortex_connection_adb_mixin(vortex, en, 0x11, ADB_CODECIN(1), mixin1);
+}
+
+// Higher level ADB audio path (de)allocator.
+
+/* Resource manager */
+static int resnum[VORTEX_RESOURCE_LAST] =
+    { NR_ADB, NR_SRC, NR_MIXIN, NR_MIXOUT, NR_A3D };
+/*
+ Checkout/Checkin resource of given type. 
+ resmap: resource map to be used. If NULL means that we want to allocate
+ a DMA resource (root of all other resources of a dma channel).
+ out: Mean checkout if != 0. Else mean Checkin resource.
+ restype: Indicates type of resource to be checked in or out.
+*/
+static char
+vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype)
+{
+	int i, qty = resnum[restype], resinuse = 0;
+
+	if (out) {
+		/* Gather used resources by all streams. */
+		for (i = 0; i < NR_ADB; i++) {
+			resinuse |= vortex->dma_adb[i].resources[restype];
+		}
+		resinuse |= vortex->fixed_res[restype];
+		/* Find and take free resource. */
+		for (i = 0; i < qty; i++) {
+			if ((resinuse & (1 << i)) == 0) {
+				if (resmap != NULL)
+					resmap[restype] |= (1 << i);
+				else
+					vortex->dma_adb[i].resources[restype] |= (1 << i);
+				//printk("vortex: ResManager: type %d out %d\n", restype, i);
+				return i;
+			}
+		}
+	} else {
+		if (resmap == NULL)
+			return -EINVAL;
+		/* Checkin first resource of type restype. */
+		for (i = 0; i < qty; i++) {
+			if (resmap[restype] & (1 << i)) {
+				resmap[restype] &= ~(1 << i);
+				//printk("vortex: ResManager: type %d in %d\n",restype, i);
+				return i;
+			}
+		}
+	}
+	printk("vortex: FATAL: ResManager: resource type %d exhausted.\n", restype);
+	return -ENOMEM;
+}
+
+/* Default Connections  */
+static void vortex_connect_default(vortex_t * vortex, int en)
+{
+	// FIXME: check if checkout was succesful.
+	// Connect AC97 codec.
+	vortex->mixplayb[0] = vortex_adb_checkinout(vortex, vortex->fixed_res, en,
+				  VORTEX_RESOURCE_MIXOUT);
+	vortex->mixplayb[1] = vortex_adb_checkinout(vortex, vortex->fixed_res, en,
+				  VORTEX_RESOURCE_MIXOUT);
+	if (VORTEX_IS_QUAD(vortex)) {
+		vortex->mixplayb[2] = vortex_adb_checkinout(vortex, vortex->fixed_res, en,
+					  VORTEX_RESOURCE_MIXOUT);
+		vortex->mixplayb[3] = vortex_adb_checkinout(vortex, vortex->fixed_res, en,
+					  VORTEX_RESOURCE_MIXOUT);
+	}
+	vortex_connect_codecplay(vortex, en, vortex->mixplayb);
+
+	vortex->mixcapt[0] = vortex_adb_checkinout(vortex, vortex->fixed_res, en,
+				  VORTEX_RESOURCE_MIXIN);
+	vortex->mixcapt[1] = vortex_adb_checkinout(vortex, vortex->fixed_res, en,
+				  VORTEX_RESOURCE_MIXIN);
+	vortex_connect_codecrec(vortex, en, MIX_CAPT(0), MIX_CAPT(1));
+
+	// Connect SPDIF
+#ifndef CHIP_AU8820
+	vortex->mixspdif[0] = vortex_adb_checkinout(vortex, vortex->fixed_res, en,
+				  VORTEX_RESOURCE_MIXOUT);
+	vortex->mixspdif[1] = vortex_adb_checkinout(vortex, vortex->fixed_res, en,
+				  VORTEX_RESOURCE_MIXOUT);
+	vortex_connection_mix_adb(vortex, en, 0x14, vortex->mixspdif[0],
+				  ADB_SPDIFOUT(0));
+	vortex_connection_mix_adb(vortex, en, 0x14, vortex->mixspdif[1],
+				  ADB_SPDIFOUT(1));
+#endif
+	// Connect WT
+#ifndef CHIP_AU8810
+	vortex_wt_connect(vortex, en);
+#endif
+	// A3D (crosstalk canceler and A3D slices).
+#ifndef CHIP_AU8820
+	vortex_Vort3D_connect(vortex, en);
+#endif
+	// Connect I2S
+
+	// Connect DSP interface for SQ3500 turbo (not here i think...)
+
+	// Connect AC98 modem codec
+
+	/* Fast Play Workaround */
+#ifndef CHIP_AU8820
+	vortex->fixed_res[VORTEX_RESOURCE_DMA] = 0x00000001;
+#endif
+	// Channel swapping workaround. We are nuking registers somewhere, or
+	// its a hardware bug.
+	vortex->fixed_res[VORTEX_RESOURCE_SRC] = 0x00000001;
+}
+
+/*
+  Allocate nr_ch pcm audio routes if dma < 0. If dma >= 0, existing routes
+  are deallocated.
+  dma: DMA engine routes to be deallocated when dma >= 0.
+  nr_ch: Number of channels to be de/allocated.
+  dir: direction of stream. Uses same values as substream->stream.
+  type: Type of audio output/source (codec, spdif, i2s, dsp, etc)
+  Return: Return allocated DMA or same DMA passed as "dma" when dma >= 0.
+*/
+static int
+vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type)
+{
+	stream_t *stream;
+	int i, en;
+
+	if ((nr_ch == 3)
+	    || ((dir == SNDRV_PCM_STREAM_CAPTURE) && (nr_ch > 2)))
+		return -EBUSY;
+
+	spin_lock(&vortex->lock);
+	if (dma >= 0) {
+		en = 0;
+		vortex_adb_checkinout(vortex,
+				      vortex->dma_adb[dma].resources, en,
+				      VORTEX_RESOURCE_DMA);
+	} else {
+		en = 1;
+		if ((dma =
+		     vortex_adb_checkinout(vortex, NULL, en,
+					   VORTEX_RESOURCE_DMA)) < 0)
+			return -EBUSY;
+	}
+
+	stream = &vortex->dma_adb[dma];
+	stream->dma = dma;
+	stream->dir = dir;
+	stream->type = type;
+
+	// FIXME: check for success of checkout or checkin.
+	/* PLAYBACK ROUTES. */
+	if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+		int src[4], mix[4], ch_top;
+#ifndef CHIP_AU8820
+		int a3d = 0;
+#endif
+		/* Get SRC and MIXER hardware resources. */
+		if (stream->type != VORTEX_PCM_SPDIF) {
+			for (i = 0; i < nr_ch; i++) {
+				if ((src[i] = vortex_adb_checkinout(vortex,
+							   stream->resources, en,
+							   VORTEX_RESOURCE_SRC)) < 0) {
+					memset(stream->resources, 0,
+					       sizeof(unsigned char) *
+					       VORTEX_RESOURCE_LAST);
+					return -EBUSY;
+				}
+				if (stream->type != VORTEX_PCM_A3D) {
+					if ((mix[i] = vortex_adb_checkinout(vortex,
+								   stream->resources,
+								   en,
+								   VORTEX_RESOURCE_MIXIN)) < 0) {
+						memset(stream->resources,
+						       0,
+						       sizeof(unsigned char) * VORTEX_RESOURCE_LAST);
+						return -EBUSY;
+					}
+				}
+			}
+		}
+#ifndef CHIP_AU8820
+		if (stream->type == VORTEX_PCM_A3D) {
+			if ((a3d =
+			     vortex_adb_checkinout(vortex,
+						   stream->resources, en,
+						   VORTEX_RESOURCE_A3D)) < 0) {
+				memset(stream->resources, 0,
+				       sizeof(unsigned char) *
+				       VORTEX_RESOURCE_LAST);
+				printk("vortex: out of A3D sources. Sorry\n");
+				return -EBUSY;
+			}
+			/* (De)Initialize A3D hardware source. */
+			vortex_Vort3D_InitializeSource(&(vortex->a3d[a3d]), en);
+		}
+		/* Make SPDIF out exclusive to "spdif" device when in use. */
+		if ((stream->type == VORTEX_PCM_SPDIF) && (en)) {
+			vortex_route(vortex, 0, 0x14,
+				     ADB_MIXOUT(vortex->mixspdif[0]),
+				     ADB_SPDIFOUT(0));
+			vortex_route(vortex, 0, 0x14,
+				     ADB_MIXOUT(vortex->mixspdif[1]),
+				     ADB_SPDIFOUT(1));
+		}
+#endif
+		/* Make playback routes. */
+		for (i = 0; i < nr_ch; i++) {
+			if (stream->type == VORTEX_PCM_ADB) {
+				vortex_connection_adbdma_src(vortex, en,
+							     //src[nr_ch - 1], 
+							     src[0], 
+							     dma,
+							     src[i]);
+				vortex_connection_src_mixin(vortex, en,
+							    0x11, src[i],
+							    mix[i]);
+				vortex_connection_mixin_mix(vortex, en,
+							    mix[i],
+							    MIX_PLAYB(i), 0);
+#ifndef CHIP_AU8820
+				vortex_connection_mixin_mix(vortex, en,
+							    mix[i],
+							    MIX_SPDIF(i % 2), 0);
+				vortex_mix_setinputvolumebyte(vortex,
+							      MIX_SPDIF(i % 2),
+							      mix[i],
+							      MIX_DEFIGAIN);
+#endif
+			}
+#ifndef CHIP_AU8820
+			if (stream->type == VORTEX_PCM_A3D) {
+				vortex_connection_adbdma_src(vortex, en,
+							     src[0], 
+								 dma,
+							     src[i]);
+				vortex_route(vortex, en, 0x11, ADB_SRCOUT(src[i]), ADB_A3DIN(a3d));
+				/* XTalk test. */
+				//vortex_route(vortex, en, 0x11, dma, ADB_XTALKIN(i?9:4));
+				//vortex_route(vortex, en, 0x11, ADB_SRCOUT(src[i]), ADB_XTALKIN(i?4:9));
+			}
+			if (stream->type == VORTEX_PCM_SPDIF)
+				vortex_route(vortex, en, 0x14,
+					     ADB_DMA(stream->dma),
+					     ADB_SPDIFOUT(i));
+#endif
+		}
+		if (stream->type != VORTEX_PCM_SPDIF && stream->type != VORTEX_PCM_A3D) {
+			ch_top = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
+			for (i = nr_ch; i < ch_top; i++) {
+				vortex_connection_mixin_mix(vortex, en,
+							    mix[i % nr_ch],
+							    MIX_PLAYB(i), 0);
+#ifndef CHIP_AU8820
+				vortex_connection_mixin_mix(vortex, en,
+							    mix[i % nr_ch],
+							    MIX_SPDIF(i % 2),
+								0);
+				vortex_mix_setinputvolumebyte(vortex,
+							      MIX_SPDIF(i % 2),
+							      mix[i % nr_ch],
+							      MIX_DEFIGAIN);
+#endif
+			}
+		}
+#ifndef CHIP_AU8820
+		else {
+			if (nr_ch == 1 && stream->type == VORTEX_PCM_SPDIF)
+				vortex_route(vortex, en, 0x14,
+					     ADB_DMA(stream->dma),
+					     ADB_SPDIFOUT(1));
+		}
+		/* Reconnect SPDIF out when "spdif" device is down. */
+		if ((stream->type == VORTEX_PCM_SPDIF) && (!en)) {
+			vortex_route(vortex, 1, 0x14,
+				     ADB_MIXOUT(vortex->mixspdif[0]),
+				     ADB_SPDIFOUT(0));
+			vortex_route(vortex, 1, 0x14,
+				     ADB_MIXOUT(vortex->mixspdif[1]),
+				     ADB_SPDIFOUT(1));
+		}
+#endif
+		/* CAPTURE ROUTES. */
+	} else {
+		int src[2], mix[2];
+
+		/* Get SRC and MIXER hardware resources. */
+		for (i = 0; i < nr_ch; i++) {
+			if ((mix[i] =
+			     vortex_adb_checkinout(vortex,
+						   stream->resources, en,
+						   VORTEX_RESOURCE_MIXOUT))
+			    < 0) {
+				memset(stream->resources, 0,
+				       sizeof(unsigned char) *
+				       VORTEX_RESOURCE_LAST);
+				return -EBUSY;
+			}
+			if ((src[i] =
+			     vortex_adb_checkinout(vortex,
+						   stream->resources, en,
+						   VORTEX_RESOURCE_SRC)) < 0) {
+				memset(stream->resources, 0,
+				       sizeof(unsigned char) *
+				       VORTEX_RESOURCE_LAST);
+				return -EBUSY;
+			}
+		}
+
+		/* Make capture routes. */
+		vortex_connection_mixin_mix(vortex, en, MIX_CAPT(0), mix[0], 0);
+		vortex_connection_mix_src(vortex, en, 0x11, mix[0], src[0]);
+		if (nr_ch == 1) {
+			vortex_connection_mixin_mix(vortex, en,
+						    MIX_CAPT(1), mix[0], 0);
+			vortex_connection_src_adbdma(vortex, en,
+						     src[nr_ch - 1],
+						     src[0], dma);
+		} else {
+			vortex_connection_mixin_mix(vortex, en,
+						    MIX_CAPT(1), mix[1], 0);
+			vortex_connection_mix_src(vortex, en, 0x11, mix[1],
+						  src[1]);
+			vortex_connection_src_src_adbdma(vortex, en,
+							 src[0], src[0],
+							 src[1], dma);
+		}
+	}
+	vortex->dma_adb[dma].nr_ch = nr_ch;
+	spin_unlock(&vortex->lock);
+
+#if 0
+	/* AC97 Codec channel setup. FIXME: this has no effect on some cards !! */
+	if (nr_ch < 4) {
+		/* Copy stereo to rear channel (surround) */
+		snd_ac97_write_cache(vortex->codec,
+				     AC97_SIGMATEL_DAC2INVERT,
+				     snd_ac97_read(vortex->codec,
+						   AC97_SIGMATEL_DAC2INVERT)
+				     | 4);
+	} else {
+		/* Allow separate front and rear channels. */
+		snd_ac97_write_cache(vortex->codec,
+				     AC97_SIGMATEL_DAC2INVERT,
+				     snd_ac97_read(vortex->codec,
+						   AC97_SIGMATEL_DAC2INVERT)
+				     & ~((u32)
+					 4));
+	}
+#endif
+	return dma;
+}
+
+/*
+ Set the SampleRate of the SRC's attached to the given DMA engine.
+ */
+static void
+vortex_adb_setsrc(vortex_t * vortex, int adbdma, unsigned int rate, int dir)
+{
+	stream_t *stream = &(vortex->dma_adb[adbdma]);
+	int i, cvrt;
+
+	/* dir=1:play ; dir=0:rec */
+	if (dir)
+		cvrt = SRC_RATIO(rate, 48000);
+	else
+		cvrt = SRC_RATIO(48000, rate);
+
+	/* Setup SRC's */
+	for (i = 0; i < NR_SRC; i++) {
+		if (stream->resources[VORTEX_RESOURCE_SRC] & (1 << i))
+			vortex_src_setupchannel(vortex, i, cvrt, 0, 0, i, dir, 1, cvrt, dir);
+	}
+}
+
+// Timer and ISR functions.
+
+static void vortex_settimer(vortex_t * vortex, int period)
+{
+	//set the timer period to <period> 48000ths of a second.
+	hwwrite(vortex->mmio, VORTEX_IRQ_STAT, period);
+}
+
+#if 0
+static void vortex_enable_timer_int(vortex_t * card)
+{
+	hwwrite(card->mmio, VORTEX_IRQ_CTRL,
+		hwread(card->mmio, VORTEX_IRQ_CTRL) | IRQ_TIMER | 0x60);
+}
+
+static void vortex_disable_timer_int(vortex_t * card)
+{
+	hwwrite(card->mmio, VORTEX_IRQ_CTRL,
+		hwread(card->mmio, VORTEX_IRQ_CTRL) & ~IRQ_TIMER);
+}
+
+#endif
+static void vortex_enable_int(vortex_t * card)
+{
+	// CAsp4ISR__EnableVortexInt_void_
+	hwwrite(card->mmio, VORTEX_CTRL,
+		hwread(card->mmio, VORTEX_CTRL) | CTRL_IRQ_ENABLE);
+	hwwrite(card->mmio, VORTEX_IRQ_CTRL,
+		(hwread(card->mmio, VORTEX_IRQ_CTRL) & 0xffffefc0) | 0x24);
+}
+
+static void vortex_disable_int(vortex_t * card)
+{
+	hwwrite(card->mmio, VORTEX_CTRL,
+		hwread(card->mmio, VORTEX_CTRL) & ~CTRL_IRQ_ENABLE);
+}
+
+static irqreturn_t vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	vortex_t *vortex = snd_magic_cast(vortex_t, dev_id, return IRQ_NONE);
+	int i, handled;
+	u32 source;
+
+	//check if the interrupt is ours.
+	if (!(hwread(vortex->mmio, VORTEX_STAT) & 0x1))
+		return IRQ_NONE;
+
+	// This is the Interrrupt Enable flag we set before (consistency check).
+	if (!(hwread(vortex->mmio, VORTEX_CTRL) & CTRL_IRQ_ENABLE))
+		return IRQ_NONE;
+
+	source = hwread(vortex->mmio, VORTEX_IRQ_SOURCE);
+	// Reset IRQ flags.
+	hwwrite(vortex->mmio, VORTEX_IRQ_SOURCE, source);
+	hwread(vortex->mmio, VORTEX_IRQ_SOURCE);
+	// Is at least one IRQ flag set?
+	if (source == 0) {
+		printk(KERN_ERR "vortex: missing irq source\n");
+		return IRQ_NONE;
+	}
+
+	handled = 0;
+	// Attend every interrupt source.
+	if (unlikely(source & IRQ_ERR_MASK)) {
+		if (source & IRQ_FATAL) {
+			printk(KERN_ERR "vortex: IRQ fatal error\n");
+		}
+		if (source & IRQ_PARITY) {
+			printk(KERN_ERR "vortex: IRQ parity error\n");
+		}
+		if (source & IRQ_REG) {
+			printk(KERN_ERR "vortex: IRQ reg error\n");
+		}
+		if (source & IRQ_FIFO) {
+			printk(KERN_ERR "vortex: IRQ fifo error\n");
+		}
+		if (source & IRQ_DMA) {
+			printk(KERN_ERR "vortex: IRQ dma error\n");
+		}
+		handled = 1;
+	}
+	if (source & IRQ_PCMOUT) {
+		/* ALSA period acknowledge. */
+		for (i = 0; i < NR_ADB; i++) {
+			if (vortex->dma_adb[i].fifo_status == FIFO_START) {
+				if (vortex_adbdma_bufshift(vortex, i)) ;
+				snd_pcm_period_elapsed(vortex->dma_adb[i].
+						       substream);
+			}
+		}
+#ifndef CHIP_AU8810
+		for (i = 0; i < NR_WT; i++) {
+			if (vortex->dma_wt[i].fifo_status == FIFO_START) {
+				if (vortex_wtdma_bufshift(vortex, i)) ;
+				snd_pcm_period_elapsed(vortex->dma_wt[i].
+						       substream);
+			}
+		}
+#endif
+		handled = 1;
+	}
+	//Acknowledge the Timer interrupt
+	if (source & IRQ_TIMER) {
+		hwread(vortex->mmio, VORTEX_IRQ_STAT);
+		handled = 1;
+	}
+	if (source & IRQ_MIDI) {
+		snd_mpu401_uart_interrupt(vortex->irq,
+					  vortex->rmidi->private_data, regs);
+		handled = 1;
+	}
+
+	if (!handled) {
+		printk(KERN_ERR "vortex: unknown irq source %x\n", source);
+	}
+	return IRQ_RETVAL(handled);
+}
+
+/* Codec */
+
+#define POLL_COUNT 1000
+static void vortex_codec_init(vortex_t * vortex)
+{
+	int i;
+
+	for (i = 0; i < 32; i++) {
+		hwwrite(vortex->mmio, (VORTEX_CODEC_CHN + (i << 2)), 0);
+		udelay(2000);
+	}
+	if (0) {
+		hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x8068);
+		udelay(1000);
+		hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x00e8);
+		udelay(1000);
+	} else {
+		hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x00a8);
+		udelay(2000);
+		hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x80a8);
+		udelay(2000);
+		hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x80e8);
+		udelay(2000);
+		hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x80a8);
+		udelay(2000);
+		hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x00a8);
+		udelay(2000);
+		hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x00e8);
+	}
+	for (i = 0; i < 32; i++) {
+		hwwrite(vortex->mmio, (VORTEX_CODEC_CHN + (i << 2)), 0);
+		udelay(5000);
+	}
+	hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0xe8);
+	udelay(1000);
+	/* Enable codec channels 0 and 1. */
+	hwwrite(vortex->mmio, VORTEX_CODEC_EN,
+		hwread(vortex->mmio, VORTEX_CODEC_EN) | EN_CODEC);
+}
+
+static void
+vortex_codec_write(ac97_t * codec, unsigned short addr, unsigned short data)
+{
+
+	vortex_t *card = (vortex_t *) codec->private_data;
+	unsigned long flags;
+	unsigned int lifeboat = 0;
+	spin_lock_irqsave(&card->lock, flags);
+
+	/* wait for transactions to clear */
+	while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) {
+		udelay(100);
+		if (lifeboat++ > POLL_COUNT) {
+			printk(KERN_ERR "vortex: ac97 codec stuck busy\n");
+			spin_unlock_irqrestore(&card->lock, flags);
+			return;
+		}
+	}
+	/* write register */
+	hwwrite(card->mmio, VORTEX_CODEC_IO,
+		((addr << VORTEX_CODEC_ADDSHIFT) & VORTEX_CODEC_ADDMASK) |
+		((data << VORTEX_CODEC_DATSHIFT) & VORTEX_CODEC_DATMASK) |
+		VORTEX_CODEC_WRITE);
+
+	/* Flush Caches. */
+	hwread(card->mmio, VORTEX_CODEC_IO);
+
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static unsigned short vortex_codec_read(ac97_t * codec, unsigned short addr)
+{
+
+	vortex_t *card = (vortex_t *) codec->private_data;
+	u32 read_addr, data;
+	unsigned long flags;
+	unsigned lifeboat = 0;
+
+	spin_lock_irqsave(&card->lock, flags);
+
+	/* wait for transactions to clear */
+	while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) {
+		udelay(100);
+		if (lifeboat++ > POLL_COUNT) {
+			printk(KERN_ERR "vortex: ac97 codec stuck busy\n");
+			spin_unlock_irqrestore(&card->lock, flags);
+			return 0xffff;
+		}
+	}
+	/* set up read address */
+	read_addr = ((addr << VORTEX_CODEC_ADDSHIFT) & VORTEX_CODEC_ADDMASK);
+	hwwrite(card->mmio, VORTEX_CODEC_IO, read_addr);
+
+	/* wait for address */
+	{
+		udelay(100);
+		data = hwread(card->mmio, VORTEX_CODEC_IO);
+		if (lifeboat++ > POLL_COUNT) {
+			printk(KERN_ERR "vortex: ac97 address never arrived\n");
+			spin_unlock_irqrestore(&card->lock, flags);
+			return 0xffff;
+		}
+	}
+	while ((data & VORTEX_CODEC_ADDMASK) !=
+	       (addr << VORTEX_CODEC_ADDSHIFT)) ;
+
+	/* Unlock. */
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	/* return data. */
+	return (u16) (data & VORTEX_CODEC_DATMASK);
+}
+
+/* SPDIF support  */
+
+static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode)
+{
+	int i, this_38 = 0, this_04 = 0, this_08 = 0, this_0c = 0;
+
+	/* CAsp4Spdif::InitializeSpdifHardware(void) */
+	hwwrite(vortex->mmio, VORTEX_SPDIF_FLAGS,
+		hwread(vortex->mmio, VORTEX_SPDIF_FLAGS) & 0xfff3fffd);
+	//for (i=0x291D4; i<0x29200; i+=4)
+	for (i = 0; i < 11; i++)
+		hwwrite(vortex->mmio, VORTEX_SPDIF_CFG1 + (i << 2), 0);
+	//hwwrite(vortex->mmio, 0x29190, hwread(vortex->mmio, 0x29190) | 0xc0000);
+	hwwrite(vortex->mmio, VORTEX_CODEC_EN,
+		hwread(vortex->mmio, VORTEX_CODEC_EN) | EN_SPDIF);
+
+	/* CAsp4Spdif::ProgramSRCInHardware(enum  SPDIF_SR,enum  SPDIFMODE) */
+	if (this_04 && this_08) {
+		int edi;
+
+		i = (((0x5DC00000 / spdif_sr) + 1) >> 1);
+		if (i > 0x800) {
+			if (i < 0x1ffff)
+				edi = (i >> 1);
+			else
+				edi = 0x1ffff;
+		} else {
+			i = edi = 0x800;
+		}
+		/* this_04 and this_08 are the CASp4Src's (samplerate converters) */
+		vortex_src_setupchannel(vortex, this_04, edi, 0, 1,
+					this_0c, 1, 0, edi, 1);
+		vortex_src_setupchannel(vortex, this_08, edi, 0, 1,
+					this_0c, 1, 0, edi, 1);
+	}
+
+	i = spdif_sr;
+	spdif_sr |= 0x8c;
+	switch (i) {
+	case 32000:
+		this_38 &= 0xFFFFFFFE;
+		this_38 &= 0xFFFFFFFD;
+		this_38 &= 0xF3FFFFFF;
+		this_38 |= 0x03000000;	/* set 32khz samplerate */
+		this_38 &= 0xFFFFFF3F;
+		spdif_sr &= 0xFFFFFFFD;
+		spdif_sr |= 1;
+		break;
+	case 44100:
+		this_38 &= 0xFFFFFFFE;
+		this_38 &= 0xFFFFFFFD;
+		this_38 &= 0xF0FFFFFF;
+		this_38 |= 0x03000000;
+		this_38 &= 0xFFFFFF3F;
+		spdif_sr &= 0xFFFFFFFC;
+		break;
+	case 48000:
+		if (spdif_mode == 1) {
+			this_38 &= 0xFFFFFFFE;
+			this_38 &= 0xFFFFFFFD;
+			this_38 &= 0xF2FFFFFF;
+			this_38 |= 0x02000000;	/* set 48khz samplerate */
+			this_38 &= 0xFFFFFF3F;
+		} else {
+			/* J. Gordon Wolfe: I think this stuff is for AC3 */
+			this_38 |= 0x00000003;
+			this_38 &= 0xFFFFFFBF;
+			this_38 |= 0x80;
+		}
+		spdif_sr |= 2;
+		spdif_sr &= 0xFFFFFFFE;
+		break;
+
+	}
+	/* looks like the next 2 lines transfer a 16-bit value into 2 8-bit 
+	   registers. seems to be for the standard IEC/SPDIF initialization 
+	   stuff */
+	hwwrite(vortex->mmio, VORTEX_SPDIF_CFG0, this_38 & 0xffff);
+	hwwrite(vortex->mmio, VORTEX_SPDIF_CFG1, this_38 >> 0x10);
+	hwwrite(vortex->mmio, VORTEX_SPDIF_SMPRATE, spdif_sr);
+}
+
+/* Initialization */
+
+static int vortex_core_init(vortex_t * vortex)
+{
+
+	printk(KERN_INFO "Vortex: hardware init.... ");
+	/* Hardware Init. */
+	hwwrite(vortex->mmio, VORTEX_CTRL, 0xffffffff);
+	udelay(5000);
+	hwwrite(vortex->mmio, VORTEX_CTRL,
+		hwread(vortex->mmio, VORTEX_CTRL) & 0xffdfffff);
+	udelay(5000);
+	/* Reset IRQ flags */
+	hwwrite(vortex->mmio, VORTEX_IRQ_SOURCE, 0xffffffff);
+	hwread(vortex->mmio, VORTEX_IRQ_STAT);
+
+	vortex_codec_init(vortex);
+
+#ifdef CHIP_AU8830
+	hwwrite(vortex->mmio, VORTEX_CTRL,
+		hwread(vortex->mmio, VORTEX_CTRL) | 0x1000000);
+#endif
+
+	/* Init audio engine. */
+	vortex_adbdma_init(vortex);
+	hwwrite(vortex->mmio, VORTEX_ENGINE_CTRL, 0x0);	//, 0xc83c7e58, 0xc5f93e58
+	vortex_adb_init(vortex);
+	/* Init processing blocks. */
+	vortex_fifo_init(vortex);
+	vortex_mixer_init(vortex);
+	vortex_srcblock_init(vortex);
+#ifndef CHIP_AU8820
+	vortex_eq_init(vortex);
+	vortex_spdif_init(vortex, 48000, 1);
+	vortex_Vort3D(vortex, 1);
+#endif
+#ifndef CHIP_AU8810
+	vortex_wt_init(vortex);
+#endif
+	// Moved to au88x0.c
+	//vortex_connect_default(vortex, 1);
+
+	vortex_settimer(vortex, 0x90);
+	// Enable Interrupts.
+	// vortex_enable_int() must be first !!
+	//  hwwrite(vortex->mmio, VORTEX_IRQ_CTRL, 0);
+	// vortex_enable_int(vortex);
+	//vortex_enable_timer_int(vortex);
+	//vortex_disable_timer_int(vortex);
+
+	printk(KERN_INFO "done.\n");
+	spin_lock_init(&vortex->lock);
+
+	return 0;
+}
+
+static int vortex_core_shutdown(vortex_t * vortex)
+{
+
+	printk(KERN_INFO "Vortex: hardware shutdown...");
+#ifndef CHIP_AU8820
+	vortex_eq_free(vortex);
+	vortex_Vort3D(vortex, 0);
+#endif
+	//vortex_disable_timer_int(vortex);
+	vortex_disable_int(vortex);
+	vortex_connect_default(vortex, 0);
+	/* Reset all DMA fifos. */
+	vortex_fifo_init(vortex);
+	/* Erase all audio routes. */
+	vortex_adb_init(vortex);
+
+	/* Disable MPU401 */
+	//hwwrite(vortex->mmio, VORTEX_IRQ_CTRL, hwread(vortex->mmio, VORTEX_IRQ_CTRL) & ~IRQ_MIDI);
+	//hwwrite(vortex->mmio, VORTEX_CTRL, hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_EN);
+
+	hwwrite(vortex->mmio, VORTEX_IRQ_CTRL, 0);
+	hwwrite(vortex->mmio, VORTEX_CTRL, 0);
+	udelay(5000);
+	hwwrite(vortex->mmio, VORTEX_IRQ_SOURCE, 0xffff);
+
+	printk(KERN_INFO "done.\n");
+	return 0;
+}
+
+/* Alsa support. */
+
+static int vortex_alsafmt_aspfmt(int alsafmt)
+{
+	int fmt;
+
+	switch (alsafmt) {
+	case SNDRV_PCM_FORMAT_U8:
+		fmt = 0x1;
+		break;
+	case SNDRV_PCM_FORMAT_MU_LAW:
+		fmt = 0x2;
+		break;
+	case SNDRV_PCM_FORMAT_A_LAW:
+		fmt = 0x3;
+		break;
+	case SNDRV_PCM_FORMAT_SPECIAL:
+		fmt = 0x4;	/* guess. */
+		break;
+	case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
+		fmt = 0x5;	/* guess. */
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		fmt = 0x8;
+		break;
+	case SNDRV_PCM_FORMAT_S16_BE:
+		fmt = 0x9;	/* check this... */
+		break;
+	default:
+		fmt = 0x8;
+		printk(KERN_ERR "vortex: format unsupported %d\n", alsafmt);
+		break;
+	}
+	return fmt;
+}
+
+/* Some not yet useful translations. */
+#if 0
+typedef enum {
+	ASPFMTLINEAR16 = 0,	/* 0x8 */
+	ASPFMTLINEAR8,		/* 0x1 */
+	ASPFMTULAW,		/* 0x2 */
+	ASPFMTALAW,		/* 0x3 */
+	ASPFMTSPORT,		/* ? */
+	ASPFMTSPDIF,		/* ? */
+} ASPENCODING;
+
+static int
+vortex_translateformat(vortex_t * vortex, char bits, char nch, int encod)
+{
+	int a, this_194;
+
+	if ((bits != 8) || (bits != 16))
+		return -1;
+
+	switch (encod) {
+	case 0:
+		if (bits == 0x10)
+			a = 8;	// 16 bit
+		break;
+	case 1:
+		if (bits == 8)
+			a = 1;	// 8 bit
+		break;
+	case 2:
+		a = 2;		// U_LAW
+		break;
+	case 3:
+		a = 3;		// A_LAW
+		break;
+	}
+	switch (nch) {
+	case 1:
+		this_194 = 0;
+		break;
+	case 2:
+		this_194 = 1;
+		break;
+	case 4:
+		this_194 = 1;
+		break;
+	case 6:
+		this_194 = 1;
+		break;
+	}
+	return (a);
+}
+
+static void vortex_cdmacore_setformat(vortex_t * vortex, int bits, int nch)
+{
+	short int d, this_148;
+
+	d = ((bits >> 3) * nch);
+	this_148 = 0xbb80 / d;
+}
+#endif
--- diff/sound/pci/au88x0/au88x0_eq.c	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au88x0_eq.c	2004-03-16 09:37:58.503646264 +0000
@@ -0,0 +1,1001 @@
+/***************************************************************************
+ *            au88x0_eq.c
+ *  Aureal Vortex Hardware EQ control/access.
+ *
+ *  Sun Jun  8 18:19:19 2003
+ *  2003  Manuel Jander (mjander@users.sourceforge.net)
+ *  
+ *  02 July 2003: First time something works :)
+ *  November 2003: A3D Bypass code completed but untested.
+ *
+ *  TODO:
+ *     - Debug (testing)
+ *     - Test peak visualization support.
+ *
+ ****************************************************************************/
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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 Library 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.
+ */
+
+/*
+ The Aureal Hardware EQ is found on AU8810 and AU8830 chips only.
+ it has 4 inputs (2 for general mix, 2 for A3D) and 2 outputs (supposed 
+ to be routed to the codec).
+*/
+
+#include "au88x0.h"
+#include "au88x0_eq.h"
+#include "au88x0_eqdata.c"
+
+/* CEqHw.s */
+static void vortex_EqHw_SetTimeConsts(vortex_t * vortex, u16 a, u16 b)
+{
+	hwwrite(vortex->mmio, 0x2b3c4, a);
+	hwwrite(vortex->mmio, 0x2b3c8, b);
+}
+
+static void vortex_EqHw_SetLeftCoefs(vortex_t * vortex, u16 a[])
+{
+	eqhw_t *eqhw = &(vortex->eq.this04);
+	int eax, i = 0, n /*esp2c */  = 0;
+
+	if (eqhw->this04 <= n)
+		return;
+
+	do {
+		hwwrite(vortex->mmio, 0x2b000 + n * 0x30, a[i + 0]);
+		hwwrite(vortex->mmio, 0x2b004 + n * 0x30, a[i + 1]);
+
+		if (eqhw->this08 == 0) {
+			hwwrite(vortex->mmio, 0x2b008 + n * 0x30, a[i + 2]);
+			hwwrite(vortex->mmio, 0x2b00c + n * 0x30, a[i + 3]);
+			eax = a[i + 4];	//esp24;
+		} else {
+			if (a[2 + i] == 0x8000)
+				eax = 0x7fff;
+			else
+				eax = ~a[2 + i];
+			hwwrite(vortex->mmio, 0x2b008 + n * 0x30, eax & 0xffff);
+			if (a[3 + i] == 0x8000)
+				eax = 0x7fff;
+			else
+				eax = ~a[3 + i];
+			hwwrite(vortex->mmio, 0x2b00c + n * 0x30, eax & 0xffff);
+			if (a[4 + i] == 0x8000)
+				eax = 0x7fff;
+			else
+				eax = ~a[4 + i];
+		}
+		hwwrite(vortex->mmio, 0x2b010 + n * 0x30, eax);
+
+		n++;
+		i += 5;
+	}
+	while (n < eqhw->this04);
+}
+
+static void vortex_EqHw_SetRightCoefs(vortex_t * vortex, u16 a[])
+{
+	eqhw_t *eqhw = &(vortex->eq.this04);
+	int i = 0, n /*esp2c */  = 0, eax;
+
+	if (eqhw->this04 <= n)
+		return;
+
+	do {
+		hwwrite(vortex->mmio, 0x2b1e0 + n * 0x30, a[0 + i]);
+		hwwrite(vortex->mmio, 0x2b1e4 + n * 0x30, a[1 + i]);
+
+		if (eqhw->this08 == 0) {
+			hwwrite(vortex->mmio, 0x2b1e8 + n * 0x30, a[2 + i]);
+			hwwrite(vortex->mmio, 0x2b1ec + n * 0x30, a[3 + i]);
+			eax = a[4 + i];	//*esp24;
+		} else {
+			if (a[2 + i] == 0x8000)
+				eax = 0x7fff;
+			else
+				eax = ~(a[2 + i]);
+			hwwrite(vortex->mmio, 0x2b1e8 + n * 0x30, eax & 0xffff);
+			if (a[3 + i] == 0x8000)
+				eax = 0x7fff;
+			else
+				eax = ~a[3 + i];
+			hwwrite(vortex->mmio, 0x2b1ec + n * 0x30, eax & 0xffff);
+			if (a[4 + i] == 0x8000)
+				eax = 0x7fff;
+			else
+				eax = ~a[4 + i];
+		}
+		hwwrite(vortex->mmio, 0x2b1f0 + n * 0x30, eax);
+		i += 5;
+		n++;
+	}
+	while (n < eqhw->this04);
+
+}
+
+static void vortex_EqHw_SetLeftStates(vortex_t * vortex, u16 a[], u16 b[])
+{
+	eqhw_t *eqhw = &(vortex->eq.this04);
+	int i = 0, ebx = 0;
+
+	hwwrite(vortex->mmio, 0x2b3fc, a[0]);
+	hwwrite(vortex->mmio, 0x2b400, a[1]);
+
+	if (eqhw->this04 < 0)
+		return;
+
+	do {
+		hwwrite(vortex->mmio, 0x2b014 + (i * 0xc), b[i]);
+		hwwrite(vortex->mmio, 0x2b018 + (i * 0xc), b[1 + i]);
+		hwwrite(vortex->mmio, 0x2b01c + (i * 0xc), b[2 + i]);
+		hwwrite(vortex->mmio, 0x2b020 + (i * 0xc), b[3 + i]);
+		i += 4;
+		ebx++;
+	}
+	while (eqhw->this04 > ebx);
+}
+
+static void vortex_EqHw_SetRightStates(vortex_t * vortex, u16 a[], u16 b[])
+{
+	eqhw_t *eqhw = &(vortex->eq.this04);
+	int i = 0, ebx = 0;
+
+	hwwrite(vortex->mmio, 0x2b404, a[0]);
+	hwwrite(vortex->mmio, 0x2b408, a[1]);
+
+	if (eqhw->this04 < 0)
+		return;
+
+	do {
+		hwwrite(vortex->mmio, 0x2b1f4 + (i * 0xc), b[i]);
+		hwwrite(vortex->mmio, 0x2b1f8 + (i * 0xc), b[1 + i]);
+		hwwrite(vortex->mmio, 0x2b1fc + (i * 0xc), b[2 + i]);
+		hwwrite(vortex->mmio, 0x2b200 + (i * 0xc), b[3 + i]);
+		i += 4;
+		ebx++;
+	}
+	while (ebx < eqhw->this04);
+}
+
+#if 0
+static void vortex_EqHw_GetTimeConsts(vortex_t * vortex, u16 * a, u16 * b)
+{
+	*a = hwread(vortex->mmio, 0x2b3c4);
+	*b = hwread(vortex->mmio, 0x2b3c8);
+}
+
+static void vortex_EqHw_GetLeftCoefs(vortex_t * vortex, u16 a[])
+{
+
+}
+
+static void vortex_EqHw_GetRightCoefs(vortex_t * vortex, u16 a[])
+{
+
+}
+
+static void vortex_EqHw_GetLeftStates(vortex_t * vortex, u16 * a, u16 b[])
+{
+
+}
+
+static void vortex_EqHw_GetRightStates(vortex_t * vortex, u16 * a, u16 b[])
+{
+
+}
+
+#endif
+/* Mix Gains */
+static void vortex_EqHw_SetBypassGain(vortex_t * vortex, u16 a, u16 b)
+{
+	eqhw_t *eqhw = &(vortex->eq.this04);
+	int eax;
+
+	if (eqhw->this08 == 0) {
+		hwwrite(vortex->mmio, 0x2b3d4, a);
+		hwwrite(vortex->mmio, 0x2b3ec, b);
+	} else {
+		if (a == 0x8000)
+			eax = 0x7fff;
+		else
+			eax = ~a;
+		hwwrite(vortex->mmio, 0x2b3d4, eax & 0xffff);
+		if (b == 0x8000)
+			eax = 0x7fff;
+		else
+			eax = ~b;
+		hwwrite(vortex->mmio, 0x2b3ec, eax & 0xffff);
+	}
+}
+
+static void vortex_EqHw_SetA3DBypassGain(vortex_t * vortex, u16 a, u16 b)
+{
+
+	hwwrite(vortex->mmio, 0x2b3e0, a);
+	hwwrite(vortex->mmio, 0x2b3f8, b);
+}
+
+#if 0
+static void vortex_EqHw_SetCurrBypassGain(vortex_t * vortex, u16 a, u16 b)
+{
+
+	hwwrite(vortex->mmio, 0x2b3d0, a);
+	hwwrite(vortex->mmio, 0x2b3e8, b);
+}
+
+static void vortex_EqHw_SetCurrA3DBypassGain(vortex_t * vortex, u16 a, u16 b)
+{
+
+	hwwrite(vortex->mmio, 0x2b3dc, a);
+	hwwrite(vortex->mmio, 0x2b3f4, b);
+}
+
+#endif
+static void
+vortex_EqHw_SetLeftGainsSingleTarget(vortex_t * vortex, u16 index, u16 b)
+{
+	hwwrite(vortex->mmio, 0x2b02c + (index * 0x30), b);
+}
+
+static void
+vortex_EqHw_SetRightGainsSingleTarget(vortex_t * vortex, u16 index, u16 b)
+{
+	hwwrite(vortex->mmio, 0x2b20c + (index * 0x30), b);
+}
+
+static void vortex_EqHw_SetLeftGainsTarget(vortex_t * vortex, u16 a[])
+{
+	eqhw_t *eqhw = &(vortex->eq.this04);
+	int ebx = 0;
+
+	if (eqhw->this04 < 0)
+		return;
+	do {
+		hwwrite(vortex->mmio, 0x2b02c + ebx * 0x30, a[ebx]);
+		ebx++;
+	}
+	while (ebx < eqhw->this04);
+}
+
+static void vortex_EqHw_SetRightGainsTarget(vortex_t * vortex, u16 a[])
+{
+	eqhw_t *eqhw = &(vortex->eq.this04);
+	int ebx = 0;
+
+	if (eqhw->this04 < 0)
+		return;
+
+	do {
+		hwwrite(vortex->mmio, 0x2b20c + ebx * 0x30, a[ebx]);
+		ebx++;
+	}
+	while (ebx < eqhw->this04);
+}
+
+static void vortex_EqHw_SetLeftGainsCurrent(vortex_t * vortex, u16 a[])
+{
+	eqhw_t *eqhw = &(vortex->eq.this04);
+	int ebx = 0;
+
+	if (eqhw->this04 < 0)
+		return;
+
+	do {
+		hwwrite(vortex->mmio, 0x2b028 + ebx * 0x30, a[ebx]);
+		ebx++;
+	}
+	while (ebx < eqhw->this04);
+}
+
+static void vortex_EqHw_SetRightGainsCurrent(vortex_t * vortex, u16 a[])
+{
+	eqhw_t *eqhw = &(vortex->eq.this04);
+	int ebx = 0;
+
+	if (eqhw->this04 < 0)
+		return;
+
+	do {
+		hwwrite(vortex->mmio, 0x2b208 + ebx * 0x30, a[ebx]);
+		ebx++;
+	}
+	while (ebx < eqhw->this04);
+}
+
+#if 0
+static void vortex_EqHw_GetLeftGainsTarget(vortex_t * vortex, u16 a[])
+{
+	eqhw_t *eqhw = &(vortex->eq.this04);
+	int ebx = 0;
+
+	if (eqhw->this04 < 0)
+		return;
+
+	do {
+		a[ebx] = hwread(vortex->mmio, 0x2b02c + ebx * 0x30);
+		ebx++;
+	}
+	while (ebx < eqhw->this04);
+}
+
+static void vortex_EqHw_GetRightGainsTarget(vortex_t * vortex, u16 a[])
+{
+	eqhw_t *eqhw = &(vortex->eq.this04);
+	int ebx = 0;
+
+	if (eqhw->this04 < 0)
+		return;
+
+	do {
+		a[ebx] = hwread(vortex->mmio, 0x2b20c + ebx * 0x30);
+		ebx++;
+	}
+	while (ebx < eqhw->this04);
+}
+
+static void vortex_EqHw_GetLeftGainsCurrent(vortex_t * vortex, u16 a[])
+{
+	eqhw_t *eqhw = &(vortex->eq.this04);
+	int ebx = 0;
+
+	if (eqhw->this04 < 0)
+		return;
+
+	do {
+		a[ebx] = hwread(vortex->mmio, 0x2b028 + ebx * 0x30);
+		ebx++;
+	}
+	while (ebx < eqhw->this04);
+}
+
+static void vortex_EqHw_GetRightGainsCurrent(vortex_t * vortex, u16 a[])
+{
+	eqhw_t *eqhw = &(vortex->eq.this04);
+	int ebx = 0;
+
+	if (eqhw->this04 < 0)
+		return;
+
+	do {
+		a[ebx] = hwread(vortex->mmio, 0x2b208 + ebx * 0x30);
+		ebx++;
+	}
+	while (ebx < eqhw->this04);
+}
+
+#endif
+/* EQ band levels settings */
+static void vortex_EqHw_SetLevels(vortex_t * vortex, u16 a[])
+{
+	eqhw_t *eqhw = &(vortex->eq.this04);
+	int ebx;
+
+	if (eqhw->this04 < 0)
+		return;
+
+	ebx = 0;
+	do {
+		hwwrite(vortex->mmio, 0x2b024 + ebx * 0x30, a[ebx]);
+		ebx++;
+	}
+	while (ebx < eqhw->this04);
+
+	hwwrite(vortex->mmio, 0x2b3cc, a[eqhw->this04]);
+	hwwrite(vortex->mmio, 0x2b3d8, a[eqhw->this04 + 1]);
+
+	ebx = 0;
+	do {
+		hwwrite(vortex->mmio, 0x2b204 + ebx * 0x30,
+			a[ebx + (eqhw->this04 + 2)]);
+		ebx++;
+	}
+	while (ebx < eqhw->this04);
+
+	hwwrite(vortex->mmio, 0x2b3e4, a[2 + (eqhw->this04 * 2)]);
+	hwwrite(vortex->mmio, 0x2b3f0, a[3 + (eqhw->this04 * 2)]);
+}
+
+#if 0
+static void vortex_EqHw_GetLevels(vortex_t * vortex, u16 a[])
+{
+	eqhw_t *eqhw = &(vortex->eq.this04);
+	int ebx;
+
+	if (eqhw->this04 < 0)
+		return;
+
+	ebx = 0;
+	do {
+		a[ebx] = hwread(vortex->mmio, 0x2b024 + ebx * 0x30);
+		ebx++;
+	}
+	while (ebx < eqhw->this04);
+
+	a[eqhw->this04] = hwread(vortex->mmio, 0x2b3cc);
+	a[eqhw->this04 + 1] = hwread(vortex->mmio, 0x2b3d8);
+
+	ebx = 0;
+	do {
+		a[ebx + (eqhw->this04 + 2)] =
+		    hwread(vortex->mmio, 0x2b204 + ebx * 0x30);
+		ebx++;
+	}
+	while (ebx < eqhw->this04);
+
+	a[2 + (eqhw->this04 * 2)] = hwread(vortex->mmio, 0x2b3e4);
+	a[3 + (eqhw->this04 * 2)] = hwread(vortex->mmio, 0x2b3f0);
+}
+
+#endif
+/* Global Control */
+static void vortex_EqHw_SetControlReg(vortex_t * vortex, unsigned long reg)
+{
+	hwwrite(vortex->mmio, 0x2b440, reg);
+}
+
+static void vortex_EqHw_SetSampleRate(vortex_t * vortex, int sr)
+{
+	hwwrite(vortex->mmio, 0x2b440, ((sr & 0x1f) << 3) | 0xb800);
+}
+
+#if 0
+static void vortex_EqHw_GetControlReg(vortex_t * vortex, unsigned long *reg)
+{
+	*reg = hwread(vortex->mmio, 0x2b440);
+}
+
+static void vortex_EqHw_GetSampleRate(vortex_t * vortex, int *sr)
+{
+	*sr = (hwread(vortex->mmio, 0x2b440) >> 3) & 0x1f;
+}
+
+#endif
+static void vortex_EqHw_Enable(vortex_t * vortex)
+{
+	hwwrite(vortex->mmio, 0x2b440, 0xf001);
+}
+
+static void vortex_EqHw_Disable(vortex_t * vortex)
+{
+	hwwrite(vortex->mmio, 0x2b440, 0xf000);
+}
+
+/* Reset (zero) buffers */
+static void vortex_EqHw_ZeroIO(vortex_t * vortex)
+{
+	int i;
+	for (i = 0; i < 0x8; i++)
+		hwwrite(vortex->mmio, 0x2b410 + (i << 2), 0x0);
+	for (i = 0; i < 0x4; i++)
+		hwwrite(vortex->mmio, 0x2b430 + (i << 2), 0x0);
+}
+
+static void vortex_EqHw_ZeroA3DIO(vortex_t * vortex)
+{
+	int i;
+	for (i = 0; i < 0x4; i++)
+		hwwrite(vortex->mmio, 0x2b410 + (i << 2), 0x0);
+}
+
+static void vortex_EqHw_ZeroState(vortex_t * vortex)
+{
+
+	vortex_EqHw_SetControlReg(vortex, 0);
+	vortex_EqHw_ZeroIO(vortex);
+	hwwrite(vortex->mmio, 0x2b3c0, 0);
+
+	vortex_EqHw_SetTimeConsts(vortex, 0, 0);
+
+	vortex_EqHw_SetLeftCoefs(vortex, asEqCoefsZeros);
+	vortex_EqHw_SetRightCoefs(vortex, asEqCoefsZeros);
+
+	vortex_EqHw_SetLeftGainsCurrent(vortex, eq_gains_zero);
+	vortex_EqHw_SetRightGainsCurrent(vortex, eq_gains_zero);
+	vortex_EqHw_SetLeftGainsTarget(vortex, eq_gains_zero);
+	vortex_EqHw_SetRightGainsTarget(vortex, eq_gains_zero);
+
+	vortex_EqHw_SetBypassGain(vortex, 0, 0);
+	//vortex_EqHw_SetCurrBypassGain(vortex, 0, 0);
+	vortex_EqHw_SetA3DBypassGain(vortex, 0, 0);
+	//vortex_EqHw_SetCurrA3DBypassGain(vortex, 0, 0);
+	vortex_EqHw_SetLeftStates(vortex, eq_states_zero, asEqOutStateZeros);
+	vortex_EqHw_SetRightStates(vortex, eq_states_zero, asEqOutStateZeros);
+	vortex_EqHw_SetLevels(vortex, (u16 *) eq_levels);
+}
+
+/* Program coeficients as pass through */
+static void vortex_EqHw_ProgramPipe(vortex_t * vortex)
+{
+	vortex_EqHw_SetTimeConsts(vortex, 0, 0);
+
+	vortex_EqHw_SetLeftCoefs(vortex, asEqCoefsPipes);
+	vortex_EqHw_SetRightCoefs(vortex, asEqCoefsPipes);
+
+	vortex_EqHw_SetLeftGainsCurrent(vortex, eq_gains_current);
+	vortex_EqHw_SetRightGainsCurrent(vortex, eq_gains_current);
+	vortex_EqHw_SetLeftGainsTarget(vortex, eq_gains_current);
+	vortex_EqHw_SetRightGainsTarget(vortex, eq_gains_current);
+}
+
+/* Program EQ block as 10 band Equalizer */
+static void
+vortex_EqHw_Program10Band(vortex_t * vortex, auxxEqCoeffSet_t * coefset)
+{
+
+	vortex_EqHw_SetTimeConsts(vortex, 0xc, 0x7fe0);
+
+	vortex_EqHw_SetLeftCoefs(vortex, coefset->LeftCoefs);
+	vortex_EqHw_SetRightCoefs(vortex, coefset->RightCoefs);
+
+	vortex_EqHw_SetLeftGainsCurrent(vortex, coefset->LeftGains);
+
+	vortex_EqHw_SetRightGainsTarget(vortex, coefset->RightGains);
+	vortex_EqHw_SetLeftGainsTarget(vortex, coefset->LeftGains);
+
+	vortex_EqHw_SetRightGainsCurrent(vortex, coefset->RightGains);
+}
+
+/* Read all EQ peaks. (think VU meter) */
+static void vortex_EqHw_GetTenBandLevels(vortex_t * vortex, u16 peaks[])
+{
+	eqhw_t *eqhw = &(vortex->eq.this04);
+	int i;
+
+	if (eqhw->this04 <= 0)
+		return;
+
+	for (i = 0; i < eqhw->this04; i++)
+		peaks[i] = hwread(vortex->mmio, 0x2B024 + i * 0x30);
+	for (i = 0; i < eqhw->this04; i++)
+		peaks[i + eqhw->this04] =
+		    hwread(vortex->mmio, 0x2B204 + i * 0x30);
+}
+
+/* CEqlzr.s */
+
+static int vortex_Eqlzr_GetLeftGain(vortex_t * vortex, u16 index, u16 * gain)
+{
+	eqlzr_t *eq = &(vortex->eq);
+
+	if (eq->this28) {
+		*gain = eq->this130[index];
+		return 0;
+	}
+	return 1;
+}
+
+static void vortex_Eqlzr_SetLeftGain(vortex_t * vortex, u16 index, u16 gain)
+{
+	eqlzr_t *eq = &(vortex->eq);
+
+	if (eq->this28 == 0)
+		return;
+
+	eq->this130[index] = gain;
+	if (eq->this54)
+		return;
+
+	vortex_EqHw_SetLeftGainsSingleTarget(vortex, index, gain);
+}
+
+static int vortex_Eqlzr_GetRightGain(vortex_t * vortex, u16 index, u16 * gain)
+{
+	eqlzr_t *eq = &(vortex->eq);
+
+	if (eq->this28) {
+		*gain = eq->this130[index + eq->this10];
+		return 0;
+	}
+	return 1;
+}
+
+static void vortex_Eqlzr_SetRightGain(vortex_t * vortex, u16 index, u16 gain)
+{
+	eqlzr_t *eq = &(vortex->eq);
+
+	if (eq->this28 == 0)
+		return;
+
+	eq->this130[index + eq->this10] = gain;
+	if (eq->this54)
+		return;
+
+	vortex_EqHw_SetRightGainsSingleTarget(vortex, index, gain);
+}
+
+#if 0
+static int
+vortex_Eqlzr_GetAllBands(vortex_t * vortex, u16 * gains, unsigned long *cnt)
+{
+	eqlzr_t *eq = &(vortex->eq);
+	int si = 0;
+
+	if (eq->this10 == 0)
+		return 1;
+
+	{
+		if (vortex_Eqlzr_GetLeftGain(vortex, si, &gains[si]))
+			return 1;
+		if (vortex_Eqlzr_GetRightGain
+		    (vortex, si, &gains[si + eq->this10]))
+			return 1;
+		si++;
+	}
+	while (eq->this10 > si) ;
+	*cnt = si * 2;
+	return 0;
+}
+#endif
+static int vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex_t * vortex)
+{
+	eqlzr_t *eq = &(vortex->eq);
+
+	vortex_EqHw_SetLeftGainsTarget(vortex, eq->this130);
+	vortex_EqHw_SetRightGainsTarget(vortex, &(eq->this130[eq->this10]));
+
+	return 0;
+}
+
+static int
+vortex_Eqlzr_SetAllBands(vortex_t * vortex, u16 gains[], unsigned long count)
+{
+	eqlzr_t *eq = &(vortex->eq);
+	int i;
+
+	if (((eq->this10) * 2 != count) || (eq->this28 == 0))
+		return 1;
+
+	if (0 < count) {
+		for (i = 0; i < count; i++) {
+			eq->this130[i] = gains[i];
+		}
+	}
+	if (eq->this54)
+		return 0;
+	return vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex);
+}
+
+static void
+vortex_Eqlzr_SetA3dBypassGain(vortex_t * vortex, unsigned long a,
+			      unsigned long b)
+{
+	eqlzr_t *eq = &(vortex->eq);
+	int eax, ebx;
+
+	eq->this58 = a;
+	eq->this5c = b;
+	if (eq->this54)
+		eax = eq->this0e;
+	else
+		eax = eq->this0a;
+	ebx = (eax * eq->this58) >> 0x10;
+	eax = (eax * eq->this5c) >> 0x10;
+	vortex_EqHw_SetA3DBypassGain(vortex, ebx, eax);
+}
+
+static void vortex_Eqlzr_ProgramA3dBypassGain(vortex_t * vortex)
+{
+	eqlzr_t *eq = &(vortex->eq);
+	int eax, ebx;
+
+	if (eq->this54)
+		eax = eq->this0e;
+	else
+		eax = eq->this0a;
+	ebx = (eax * eq->this58) >> 0x10;
+	eax = (eax * eq->this5c) >> 0x10;
+	vortex_EqHw_SetA3DBypassGain(vortex, ebx, eax);
+}
+
+static void vortex_Eqlzr_ShutDownA3d(vortex_t * vortex)
+{
+	if (vortex != NULL)
+		vortex_EqHw_ZeroA3DIO(vortex);
+}
+
+static void vortex_Eqlzr_SetBypass(vortex_t * vortex, long bp)
+{
+	eqlzr_t *eq = &(vortex->eq);
+
+	if ((eq->this28) && (bp == 0)) {
+		vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex);
+		vortex_EqHw_SetBypassGain(vortex, eq->this08, eq->this08);
+	} else {
+		vortex_EqHw_SetLeftGainsTarget(vortex, (u16 *) (eq->this14));
+		vortex_EqHw_SetRightGainsTarget(vortex, (u16 *) (eq->this14));
+		vortex_EqHw_SetBypassGain(vortex, eq->this0c, eq->this0c);
+	}
+	vortex_Eqlzr_ProgramA3dBypassGain(vortex);
+}
+
+static void vortex_Eqlzr_ReadAndSetActiveCoefSet(vortex_t * vortex)
+{
+	eqlzr_t *eq = &(vortex->eq);
+
+	/* Set EQ BiQuad filter coeficients */
+	memcpy(&(eq->coefset), &asEqCoefsNormal, sizeof(auxxEqCoeffSet_t));
+	/* Set EQ Band gain levels and dump into hardware registers. */
+	vortex_Eqlzr_SetAllBands(vortex, eq_gains_normal, eq->this10 * 2);
+}
+
+static int vortex_Eqlzr_GetAllPeaks(vortex_t * vortex, u16 * peaks, int *count)
+{
+	eqlzr_t *eq = &(vortex->eq);
+
+	if (eq->this10 == 0)
+		return 1;
+	*count = eq->this10 * 2;
+	vortex_EqHw_GetTenBandLevels(vortex, peaks);
+	return 0;
+}
+
+#if 0
+static auxxEqCoeffSet_t *vortex_Eqlzr_GetActiveCoefSet(vortex_t * vortex)
+{
+	eqlzr_t *eq = &(vortex->eq);
+
+	return (&(eq->coefset));
+}
+#endif
+static void vortex_Eqlzr_init(vortex_t * vortex)
+{
+	eqlzr_t *eq = &(vortex->eq);
+
+	/* Object constructor */
+	//eq->this04 = 0;
+	eq->this08 = 0;		/* Bypass gain with EQ in use. */
+	eq->this0a = 0x5999;
+	eq->this0c = 0x5999;	/* Bypass gain with EQ disabled. */
+	eq->this0e = 0x5999;
+
+	eq->this10 = 0xa;	/* 10 eq frequency bands. */
+	eq->this04.this04 = eq->this10;
+	eq->this28 = 0x1;	/* if 1 => Allow read access to this130 (gains) */
+	eq->this54 = 0x0;	/* if 1 => Dont Allow access to hardware (gains) */
+	eq->this58 = 0xffff;
+	eq->this5c = 0xffff;
+
+	/* Set gains. */
+	memset(eq->this14, 0, 2 * 10);
+
+	/* Actual init. */
+	vortex_EqHw_ZeroState(vortex);
+	vortex_EqHw_SetSampleRate(vortex, 0x11);
+	vortex_Eqlzr_ReadAndSetActiveCoefSet(vortex);
+
+	vortex_EqHw_Program10Band(vortex, &(eq->coefset));
+	vortex_Eqlzr_SetBypass(vortex, eq->this54);
+	vortex_Eqlzr_SetA3dBypassGain(vortex, 0, 0);
+	vortex_EqHw_Enable(vortex);
+}
+
+static void vortex_Eqlzr_shutdown(vortex_t * vortex)
+{
+	vortex_Eqlzr_ShutDownA3d(vortex);
+	vortex_EqHw_ProgramPipe(vortex);
+	vortex_EqHw_Disable(vortex);
+}
+
+/* ALSA interface */
+
+/* Control interface */
+static int
+snd_vortex_eqtoggle_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_vortex_eqtoggle_get(snd_kcontrol_t * kcontrol,
+			snd_ctl_elem_value_t * ucontrol)
+{
+	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
+	eqlzr_t *eq = &(vortex->eq);
+	//int i = kcontrol->private_value;
+
+	ucontrol->value.integer.value[0] = eq->this54 ? 0 : 1;
+
+	return 0;
+}
+
+static int
+snd_vortex_eqtoggle_put(snd_kcontrol_t * kcontrol,
+			snd_ctl_elem_value_t * ucontrol)
+{
+	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
+	eqlzr_t *eq = &(vortex->eq);
+	//int i = kcontrol->private_value;
+
+	eq->this54 = ucontrol->value.integer.value[0] ? 0 : 1;
+	vortex_Eqlzr_SetBypass(vortex, eq->this54);
+
+	return 1;		/* Allways changes */
+}
+
+static snd_kcontrol_new_t vortex_eqtoggle_kcontrol __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "EQ Enable",
+	.index = 0,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.private_value = 0,
+	.info = snd_vortex_eqtoggle_info,
+	.get = snd_vortex_eqtoggle_get,
+	.put = snd_vortex_eqtoggle_put
+};
+
+static int
+snd_vortex_eq_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 = 0x0000;
+	uinfo->value.integer.max = 0x7fff;
+	return 0;
+}
+
+static int
+snd_vortex_eq_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
+	int i = kcontrol->private_value;
+	u16 gainL, gainR;
+
+	vortex_Eqlzr_GetLeftGain(vortex, i, &gainL);
+	vortex_Eqlzr_GetRightGain(vortex, i, &gainR);
+	ucontrol->value.integer.value[0] = gainL;
+	ucontrol->value.integer.value[1] = gainR;
+	return 0;
+}
+
+static int
+snd_vortex_eq_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
+	int changed = 0, i = kcontrol->private_value;
+	u16 gainL, gainR;
+
+	vortex_Eqlzr_GetLeftGain(vortex, i, &gainL);
+	vortex_Eqlzr_GetRightGain(vortex, i, &gainR);
+
+	if (gainL != ucontrol->value.integer.value[0]) {
+		vortex_Eqlzr_SetLeftGain(vortex, i,
+					 ucontrol->value.integer.value[0]);
+		changed = 1;
+	}
+	if (gainR != ucontrol->value.integer.value[1]) {
+		vortex_Eqlzr_SetRightGain(vortex, i,
+					  ucontrol->value.integer.value[1]);
+		changed = 1;
+	}
+	return changed;
+}
+
+static snd_kcontrol_new_t vortex_eq_kcontrol __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "                        .",
+	.index = 0,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.private_value = 0,
+	.info = snd_vortex_eq_info,
+	.get = snd_vortex_eq_get,
+	.put = snd_vortex_eq_put
+};
+
+static int
+snd_vortex_peaks_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 20;
+	uinfo->value.integer.min = 0x0000;
+	uinfo->value.integer.max = 0x7fff;
+	return 0;
+}
+
+static int
+snd_vortex_peaks_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
+	int i, count;
+	u16 peaks[20];
+
+	vortex_Eqlzr_GetAllPeaks(vortex, peaks, &count);
+	if (count != 20) {
+		printk("vortex: peak count error 20 != %d \n", count);
+		return -1;
+	}
+	for (i = 0; i < 20; i++)
+		ucontrol->value.integer.value[i] = peaks[i];
+
+	return 0;
+}
+
+static snd_kcontrol_new_t vortex_levels_kcontrol __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "EQ Peaks",
+	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info = snd_vortex_peaks_info,
+	.get = snd_vortex_peaks_get,
+};
+
+/* EQ band gain labels. */
+static char *EqBandLabels[10] __devinitdata = {
+	"EQ0 31Hz\0",
+	"EQ1 63Hz\0",
+	"EQ2 125Hz\0",
+	"EQ3 250Hz\0",
+	"EQ4 500Hz\0",
+	"EQ5 1KHz\0",
+	"EQ6 2KHz\0",
+	"EQ7 4KHz\0",
+	"EQ8 8KHz\0",
+	"EQ9 16KHz\0",
+};
+
+/* ALSA driver entry points. Init and exit. */
+static int vortex_eq_init(vortex_t * vortex)
+{
+	snd_kcontrol_t *kcontrol;
+	int err, i;
+
+	vortex_Eqlzr_init(vortex);
+
+	if ((kcontrol =
+	     snd_ctl_new1(&vortex_eqtoggle_kcontrol, vortex)) == NULL)
+		return -ENOMEM;
+	kcontrol->private_value = 0;
+	if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
+		return err;
+
+	/* EQ gain controls */
+	for (i = 0; i < 10; i++) {
+		if ((kcontrol =
+		     snd_ctl_new1(&vortex_eq_kcontrol, vortex)) == NULL)
+			return -ENOMEM;
+		strcpy(kcontrol->id.name, EqBandLabels[i]);
+		kcontrol->private_value = i;
+		if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
+			return err;
+		//vortex->eqctrl[i] = kcontrol;
+	}
+	/* EQ band levels */
+	if ((kcontrol = snd_ctl_new1(&vortex_levels_kcontrol, vortex)) == NULL)
+		return -ENOMEM;
+	if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
+		return err;
+
+	return 0;
+}
+
+static int vortex_eq_free(vortex_t * vortex)
+{
+	/*
+	   //FIXME: segfault because vortex->eqctrl[i] == 4
+	   int i;
+	   for (i=0; i<10; i++) {
+	   if (vortex->eqctrl[i])
+	   snd_ctl_remove(vortex->card, vortex->eqctrl[i]);
+	   }
+	 */
+	vortex_Eqlzr_shutdown(vortex);
+	return 0;
+}
+
+/* End */
--- diff/sound/pci/au88x0/au88x0_eq.h	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au88x0_eq.h	2004-03-16 09:37:58.503646264 +0000
@@ -0,0 +1,46 @@
+#ifndef AU88X0_EQ_H
+#define AU88X0_EQ_H
+
+/***************************************************************************
+ *            au88x0_eq.h
+ *
+ *  Definitions and constant data for the Aureal Hardware EQ.
+ *
+ *  Sun Jun  8 18:23:38 2003
+ *  Author: Manuel Jander (mjander@users.sourceforge.net)
+ ****************************************************************************/
+
+typedef struct {
+	u16 LeftCoefs[50];	//0x4
+	u16 RightCoefs[50];	// 0x68
+	u16 LeftGains[20];	//0xd0
+	u16 RightGains[20];	//0xe4
+} auxxEqCoeffSet_t;
+
+typedef struct {
+	unsigned int *this00;	/*CAsp4HwIO */
+	long this04;		/* How many filters for each side (default = 10) */
+	long this08;		/* inited to cero. Stereo flag? */
+} eqhw_t;
+
+typedef struct {
+	unsigned int *this00;	/*CAsp4Core */
+	eqhw_t this04;		/* CHwEq */
+	short this08;		/* Bad codec flag ? SetBypassGain: bypass gain */
+	short this0a;
+	short this0c;		/* SetBypassGain: bypass gain when this28 is not set. */
+	short this0e;
+
+	long this10;		/* How many gains are used for each side (right or left). */
+	u16 this14[32];		/* SetLeftGainsTarget: Left (and right?) EQ gains  */
+	long this24;
+	long this28;		/* flag related to EQ enabled or not. Gang flag ? */
+	long this54;		/* SetBypass */
+	long this58;
+	long this5c;
+	/*0x60 */ auxxEqCoeffSet_t coefset;
+	/* 50 u16 word each channel. */
+	u16 this130[20];	/* Left and Right gains */
+} eqlzr_t;
+
+#endif
--- diff/sound/pci/au88x0/au88x0_eqdata.c	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au88x0_eqdata.c	2004-03-16 09:37:58.504646112 +0000
@@ -0,0 +1,112 @@
+/* Data structs */
+
+static u16 asEqCoefsZeros[50] = {
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static u16 asEqCoefsPipes[64] = {
+	0x0000, 0x0000,
+	0x0000, 0x0666, 0x0000, 0x0000, 0x0666,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0666, 0x0000, 0x0000, 0x0666,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0666, 0x0000, 0x0000, 0x0666,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0666, 0x0000, 0x0000, 0x0666,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0666, 0x0000, 0x0000, 0x066a,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000
+};
+
+/* More coef sets can be found in the win2k "inf" file. */
+static auxxEqCoeffSet_t asEqCoefsNormal = {
+	.LeftCoefs = {
+		      0x7e60, 0xc19e, 0x0001, 0x0002, 0x0001,
+		      0x7fa0, 0xc05f, 0x004f, 0x0000, 0xffb1,
+		      0x7f3f, 0xc0bc, 0x00c2, 0x0000, 0xff3e,
+		      0x7e78, 0xc177, 0x011f, 0x0000, 0xfee1,
+		      0x7cd6, 0xc2e5, 0x025c, 0x0000, 0xfda4,
+		      0x7949, 0xc5aa, 0x0467, 0x0000, 0xfb99,
+		      0x7120, 0xcadf, 0x0864, 0x0000, 0xf79c,
+		      0x5d33, 0xd430, 0x0f7e, 0x0000, 0xf082,
+		      0x2beb, 0xe3ca, 0x1bd3, 0x0000, 0xe42d,
+		      0xd740, 0xf01d, 0x2ac5, 0x0000, 0xd53b},
+
+	.RightCoefs = {
+		       0x7e60, 0xc19e, 0x0001, 0x0002, 0x0001,
+		       0x7fa0, 0xc05f, 0x004f, 0x0000, 0xffb1,
+		       0x7f3f, 0xc0bc, 0x00c2, 0x0000, 0xff3e,
+		       0x7e78, 0xc177, 0x011f, 0x0000, 0xfee1,
+		       0x7cd6, 0xc2e5, 0x025c, 0x0000, 0xfda4,
+		       0x7949, 0xc5aa, 0x0467, 0x0000, 0xfb99,
+		       0x7120, 0xcadf, 0x0864, 0x0000, 0xf79c,
+		       0x5d33, 0xd430, 0x0f7e, 0x0000, 0xf082,
+		       0x2beb, 0xe3ca, 0x1bd3, 0x0000, 0xe42d,
+		       0xd740, 0xf01d, 0x2ac5, 0x0000, 0xd53b},
+
+	.LeftGains = {
+		      0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96,
+		      0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96},
+	.RightGains = {
+		       0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96,
+		       0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96}
+};
+
+static u16 eq_gains_normal[20] = {
+	0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96,
+	0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96,
+	0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96,
+	0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96
+};
+
+/* _rodatab60 */
+static u16 eq_gains_zero[10] = {
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+/* _rodatab7c:  ProgramPipe */
+static u16 eq_gains_current[12] = {
+	0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
+	0x7fff,
+	0x7fff, 0x7fff, 0x7fff
+};
+
+/* _rodatab78 */
+static u16 eq_states_zero[2] = { 0x0000, 0x0000 };
+
+static u16 asEqOutStateZeros[48] = {
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000
+};
+
+/*_rodataba0:*/
+static long eq_levels[32] = {
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+};
--- diff/sound/pci/au88x0/au88x0_game.c	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au88x0_game.c	2004-03-16 09:37:58.505645960 +0000
@@ -0,0 +1,121 @@
+/*
+ * $Id: au88x0_game.c,v 1.9 2003/09/22 03:51:28 mjander Exp $
+ *
+ *  Manuel Jander.
+ *
+ *  Based on the work of:
+ *  Vojtech Pavlik
+ *  Raymond Ingles
+ *
+ * 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
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ *
+ * Based 90% on Vojtech Pavlik pcigame driver.
+ * Merged and modified by Manuel Jander, for the OpenVortex
+ * driver. (email: mjander@embedded.cl).
+ */
+
+#include <sound/driver.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <sound/core.h>
+#include "au88x0.h"
+#include <linux/gameport.h>
+
+#define VORTEX_GAME_DWAIT	20	/* 20 ms */
+
+static struct gameport gameport;
+
+static unsigned char vortex_game_read(struct gameport *gameport)
+{
+	vortex_t *vortex = gameport->driver;
+	return hwread(vortex->mmio, VORTEX_GAME_LEGACY);
+}
+
+static void vortex_game_trigger(struct gameport *gameport)
+{
+	vortex_t *vortex = gameport->driver;
+	hwwrite(vortex->mmio, VORTEX_GAME_LEGACY, 0xff);
+}
+
+static int
+vortex_game_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+{
+	vortex_t *vortex = gameport->driver;
+	int i;
+
+	*buttons = (~hwread(vortex->mmio, VORTEX_GAME_LEGACY) >> 4) & 0xf;
+
+	for (i = 0; i < 4; i++) {
+		axes[i] =
+		    hwread(vortex->mmio, VORTEX_GAME_AXIS + (i * AXIS_SIZE));
+		if (axes[i] == AXIS_RANGE)
+			axes[i] = -1;
+	}
+	return 0;
+}
+
+static int vortex_game_open(struct gameport *gameport, int mode)
+{
+	vortex_t *vortex = gameport->driver;
+
+	switch (mode) {
+	case GAMEPORT_MODE_COOKED:
+		hwwrite(vortex->mmio, VORTEX_CTRL2,
+			hwread(vortex->mmio,
+			       VORTEX_CTRL2) | CTRL2_GAME_ADCMODE);
+		wait_ms(VORTEX_GAME_DWAIT);
+		return 0;
+	case GAMEPORT_MODE_RAW:
+		hwwrite(vortex->mmio, VORTEX_CTRL2,
+			hwread(vortex->mmio,
+			       VORTEX_CTRL2) & ~CTRL2_GAME_ADCMODE);
+		return 0;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+static int vortex_gameport_register(vortex_t * vortex)
+{
+	vortex->gameport = &gameport;
+
+	vortex->gameport->driver = vortex;
+	vortex->gameport->fuzz = 64;
+
+	vortex->gameport->read = vortex_game_read;
+	vortex->gameport->trigger = vortex_game_trigger;
+	vortex->gameport->cooked_read = vortex_game_cooked_read;
+	vortex->gameport->open = vortex_game_open;
+
+	gameport_register_port((struct gameport *)vortex->gameport);
+
+/*	printk(KERN_INFO "gameport%d: %s at speed %d kHz\n",
+		vortex->gameport->number, vortex->pci_dev->name, vortex->gameport->speed);
+*/
+	return 0;
+}
+
+static int vortex_gameport_unregister(vortex_t * vortex)
+{
+	if (vortex->gameport != NULL)
+		gameport_unregister_port(vortex->gameport);
+	return 0;
+}
--- diff/sound/pci/au88x0/au88x0_mixer.c	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au88x0_mixer.c	2004-03-16 09:37:58.505645960 +0000
@@ -0,0 +1,29 @@
+/*
+ * Vortex Mixer support.
+ *
+ * There is much more than just the AC97 mixer...
+ *
+ */
+
+#include <sound/driver.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <sound/core.h>
+#include "au88x0.h"
+
+static int __devinit snd_vortex_mixer(vortex_t * vortex)
+{
+	ac97_bus_t bus, *pbus;
+	ac97_t ac97;
+	int err;
+
+	memset(&bus, 0, sizeof(bus));
+	bus.write = vortex_codec_write;
+	bus.read = vortex_codec_read;
+	if ((err = snd_ac97_bus(vortex->card, &bus, &pbus)) < 0)
+		return err;
+	memset(&ac97, 0, sizeof(ac97));
+	// Intialize AC97 codec stuff.
+	ac97.private_data = vortex;
+	return snd_ac97_mixer(pbus, &ac97, &vortex->codec);
+}
--- diff/sound/pci/au88x0/au88x0_mpu401.c	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au88x0_mpu401.c	2004-03-16 09:37:58.506645808 +0000
@@ -0,0 +1,112 @@
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *  Routines for control of MPU-401 in UART mode
+ *
+ *   Modified for the Aureal Vortex based Soundcards
+ *   by Manuel Jander (mjande@embedded.cl).
+ *
+ *   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/init.h>
+#include <sound/core.h>
+#include <sound/mpu401.h>
+#include "au88x0.h"
+
+/* Check for mpu401 mmio support. */
+/* MPU401 legacy support is only provided as a emergency fallback *
+ * for older versions of ALSA. Its usage is strongly discouraged. */
+#ifndef MPU401_HW_AUREAL
+#define VORTEX_MPU401_LEGACY
+#endif
+
+/* Vortex MPU401 defines. */
+#define MIDI_CLOCK_DIV      0x61
+/* Standart MPU401 defines. */
+#define MPU401_RESET		0xff
+#define MPU401_ENTER_UART	0x3f
+#define MPU401_ACK		    0xfe
+
+static int __devinit snd_vortex_midi(vortex_t * vortex)
+{
+	snd_rawmidi_t *rmidi;
+	int temp, mode;
+	mpu401_t *mpu;
+	int port;
+
+#ifdef VORTEX_MPU401_LEGACY
+	/* EnableHardCodedMPU401Port() */
+	/* Enable Legacy MIDI Interface port. */
+	port = (0x03 << 5);	/* FIXME: static address. 0x330 */
+	temp =
+	    (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) |
+	    CTRL_MIDI_EN | port;
+	hwwrite(vortex->mmio, VORTEX_CTRL, temp);
+#else
+	/* Disable Legacy MIDI Interface port. */
+	temp =
+	    (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) &
+	    ~CTRL_MIDI_EN;
+	hwwrite(vortex->mmio, VORTEX_CTRL, temp);
+#endif
+	/* Mpu401UartInit() */
+	mode = 1;
+	temp = hwread(vortex->mmio, VORTEX_CTRL2) & 0xffff00cf;
+	temp |= (MIDI_CLOCK_DIV << 8) | ((mode >> 24) & 0xff) << 4;
+	hwwrite(vortex->mmio, VORTEX_CTRL2, temp);
+	hwwrite(vortex->mmio, VORTEX_MIDI_CMD, MPU401_RESET);
+	/* Set some kind of mode */
+	if (mode)
+		hwwrite(vortex->mmio, VORTEX_MIDI_CMD, MPU401_ENTER_UART);
+
+	/* Check if anything is OK. */
+	temp = hwread(vortex->mmio, VORTEX_MIDI_DATA);
+	if (temp != MPU401_ACK /*0xfe */ ) {
+		printk(KERN_ERR "midi port doesn't acknowledge!\n");
+		return -ENODEV;
+	}
+	/* Enable MPU401 interrupts. */
+	hwwrite(vortex->mmio, VORTEX_IRQ_CTRL,
+		hwread(vortex->mmio, VORTEX_IRQ_CTRL) | IRQ_MIDI);
+
+	/* Create MPU401 instance. */
+#ifdef VORTEX_MPU401_LEGACY
+	if ((temp =
+	     snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_MPU401, 0x330,
+				 0, 0, 0, &rmidi)) != 0) {
+		hwwrite(vortex->mmio, VORTEX_CTRL,
+			(hwread(vortex->mmio, VORTEX_CTRL) &
+			 ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN);
+		return temp;
+	}
+#else
+	port = (unsigned long)(vortex->mmio + (VORTEX_MIDI_DATA >> 2));
+	if ((temp =
+	     snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port,
+				 1, 0, 0, &rmidi)) != 0) {
+		hwwrite(vortex->mmio, VORTEX_CTRL,
+			(hwread(vortex->mmio, VORTEX_CTRL) &
+			 ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN);
+		return temp;
+	}
+	mpu = snd_magic_cast(mpu401_t, rmidi->private_data, return -ENOMEM);
+	mpu->cport = (unsigned long)(vortex->mmio + (VORTEX_MIDI_CMD >> 2));
+#endif
+	vortex->rmidi = rmidi;
+	return 0;
+}
--- diff/sound/pci/au88x0/au88x0_pcm.c	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au88x0_pcm.c	2004-03-16 09:37:58.508645504 +0000
@@ -0,0 +1,509 @@
+/*
+ * Vortex PCM ALSA driver.
+ *
+ * Supports ADB and WT DMA. Unfortunately, WT routing is still a
+ * mistery. To discover that, we need to disassemble the windoze
+ * driver too.
+ *
+ *
+ */
+
+#include <sound/driver.h>
+#include <linux/time.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include "au88x0.h"
+
+#define chip_t vortex_t
+#define VORTEX_PCM_TYPE(x) (x->name[40])
+
+/* hardware definition */
+static snd_pcm_hardware_t snd_vortex_playback_hw_adb = {
+	.info =
+	    (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME |
+	     SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
+	     SNDRV_PCM_INFO_MMAP_VALID),
+	.formats =
+	    SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |
+	    SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW,
+	.rates = SNDRV_PCM_RATE_CONTINUOUS,
+	.rate_min = 5000,
+	.rate_max = 48000,
+	.channels_min = 1,
+#ifdef CHIP_AU8830
+	.channels_max = 4,
+#else
+	.channels_max = 2,
+#endif
+	.buffer_bytes_max = 0x10000,
+	.period_bytes_min = 0x1,
+	.period_bytes_max = 0x1000,
+	.periods_min = 2,
+	.periods_max = 32,
+};
+
+#ifndef CHIP_AU8820
+static snd_pcm_hardware_t snd_vortex_playback_hw_a3d = {
+	.info =
+	    (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME |
+	     SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
+	     SNDRV_PCM_INFO_MMAP_VALID),
+	.formats =
+	    SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |
+	    SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW,
+	.rates = SNDRV_PCM_RATE_CONTINUOUS,
+	.rate_min = 5000,
+	.rate_max = 48000,
+	.channels_min = 1,
+	.channels_max = 1,
+	.buffer_bytes_max = 0x10000,
+	.period_bytes_min = 0x100,
+	.period_bytes_max = 0x1000,
+	.periods_min = 2,
+	.periods_max = 64,
+};
+#endif
+static snd_pcm_hardware_t snd_vortex_playback_hw_spdif = {
+	.info =
+	    (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME |
+	     SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
+	     SNDRV_PCM_INFO_MMAP_VALID),
+	.formats =
+	    SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |
+	    SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | SNDRV_PCM_FMTBIT_MU_LAW |
+	    SNDRV_PCM_FMTBIT_A_LAW,
+	.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 = 0x10000,
+	.period_bytes_min = 0x100,
+	.period_bytes_max = 0x1000,
+	.periods_min = 2,
+	.periods_max = 64,
+};
+
+#ifndef CHIP_AU8810
+static snd_pcm_hardware_t snd_vortex_playback_hw_wt = {
+	.info = (SNDRV_PCM_INFO_MMAP |
+		 SNDRV_PCM_INFO_INTERLEAVED |
+		 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID),
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	.rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_CONTINUOUS,	// SNDRV_PCM_RATE_48000,
+	.rate_min = 8000,
+	.rate_max = 48000,
+	.channels_min = 1,
+	.channels_max = 2,
+	.buffer_bytes_max = 0x10000,
+	.period_bytes_min = 0x0400,
+	.period_bytes_max = 0x1000,
+	.periods_min = 2,
+	.periods_max = 64,
+};
+#endif
+/* open callback */
+static int snd_vortex_pcm_open(snd_pcm_substream_t * substream)
+{
+	vortex_t *vortex = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	int err;
+
+	/* Force equal size periods */
+	if ((err =
+	     snd_pcm_hw_constraint_integer(runtime,
+					   SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+		return err;
+	/* Avoid PAGE_SIZE boundary to fall inside of a period. */
+	if ((err =
+	     snd_pcm_hw_constraint_pow2(runtime, 0,
+					SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
+		return err;
+
+	if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
+#ifndef CHIP_AU8820
+		if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_A3D) {
+			runtime->hw = snd_vortex_playback_hw_a3d;
+		}
+#endif
+		if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_SPDIF) {
+			runtime->hw = snd_vortex_playback_hw_spdif;
+			switch (vortex->spdif_sr) {
+			case 32000:
+				runtime->hw.rates = SNDRV_PCM_RATE_32000;
+				break;
+			case 44100:
+				runtime->hw.rates = SNDRV_PCM_RATE_44100;
+				break;
+			case 48000:
+				runtime->hw.rates = SNDRV_PCM_RATE_48000;
+				break;
+			}
+		}
+		if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB
+		    || VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_I2S)
+			runtime->hw = snd_vortex_playback_hw_adb;
+		substream->runtime->private_data = NULL;
+	}
+#ifndef CHIP_AU8810
+	else {
+		runtime->hw = snd_vortex_playback_hw_wt;
+		substream->runtime->private_data = NULL;
+	}
+#endif
+	return 0;
+}
+
+/* close callback */
+static int snd_vortex_pcm_close(snd_pcm_substream_t * substream)
+{
+	//vortex_t *chip = snd_pcm_substream_chip(substream);
+	stream_t *stream = (stream_t *) substream->runtime->private_data;
+
+	// the hardware-specific codes will be here
+	if (stream != NULL) {
+		stream->substream = NULL;
+		stream->nr_ch = 0;
+	}
+	substream->runtime->private_data = NULL;
+	return 0;
+}
+
+/* hw_params callback */
+static int
+snd_vortex_pcm_hw_params(snd_pcm_substream_t * substream,
+			 snd_pcm_hw_params_t * hw_params)
+{
+	chip_t *chip = snd_pcm_substream_chip(substream);
+	stream_t *stream = (stream_t *) (substream->runtime->private_data);
+	snd_pcm_sgbuf_t *sgbuf;
+	int err;
+
+	// Alloc buffer memory.
+	err =
+	    snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+	if (err < 0) {
+		printk(KERN_ERR "Vortex: pcm page alloc failed!\n");
+		return err;
+	}
+	//sgbuf = (snd_pcm_sgbuf_t *) substream->runtime->dma_private;
+	sgbuf = snd_pcm_substream_sgbuf(substream);
+	/*
+	   printk(KERN_INFO "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params),
+	   params_period_bytes(hw_params), params_channels(hw_params));
+	 */
+	// Make audio routes and config buffer DMA.
+	if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
+		int dma, type = VORTEX_PCM_TYPE(substream->pcm);
+		/* Dealloc any routes. */
+		if (stream != NULL)
+			vortex_adb_allocroute(chip, stream->dma,
+					      stream->nr_ch, stream->dir,
+					      stream->type);
+		/* Alloc routes. */
+		dma =
+		    vortex_adb_allocroute(chip, -1,
+					  params_channels(hw_params),
+					  substream->stream, type);
+		if (dma < 0)
+			return dma;
+		stream = substream->runtime->private_data = &chip->dma_adb[dma];
+		stream->substream = substream;
+		/* Setup Buffers. */
+		vortex_adbdma_setbuffers(chip, dma, sgbuf,
+					 params_period_bytes(hw_params),
+					 params_periods(hw_params));
+	}
+#ifndef CHIP_AU8810
+	else {
+		/*if (stream != NULL)
+		   vortex_wt_allocroute(chip, substream->number, 0); */
+		vortex_wt_allocroute(chip, substream->number,
+				     params_channels(hw_params));
+		stream = substream->runtime->private_data =
+		    &chip->dma_wt[substream->number];
+		stream->substream = substream;
+		vortex_wtdma_setbuffers(chip, substream->number, sgbuf,
+					params_period_bytes(hw_params),
+					params_periods(hw_params));
+	}
+#endif
+	return 0;
+}
+
+/* hw_free callback */
+static int snd_vortex_pcm_hw_free(snd_pcm_substream_t * substream)
+{
+	chip_t *chip = snd_pcm_substream_chip(substream);
+	stream_t *stream = (stream_t *) (substream->runtime->private_data);
+
+	// Delete audio routes.
+	if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
+		if (stream != NULL)
+			vortex_adb_allocroute(chip, stream->dma,
+					      stream->nr_ch, stream->dir,
+					      stream->type);
+	}
+#ifndef CHIP_AU8810
+	else {
+		if (stream != NULL)
+			vortex_wt_allocroute(chip, stream->dma, 0);
+	}
+#endif
+	substream->runtime->private_data = NULL;
+
+	return snd_pcm_lib_free_pages(substream);
+}
+
+/* prepare callback */
+static int snd_vortex_pcm_prepare(snd_pcm_substream_t * substream)
+{
+	vortex_t *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	stream_t *stream = (stream_t *) substream->runtime->private_data;
+	int dma = stream->dma, fmt, dir;
+
+	// set up the hardware with the current configuration.
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir = 1;
+	else
+		dir = 0;
+	fmt = vortex_alsafmt_aspfmt(runtime->format);
+	if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
+		vortex_adbdma_setmode(chip, dma, 1, dir, fmt, 0 /*? */ ,
+				      0);
+		vortex_adbdma_setstartbuffer(chip, dma, 0);
+		if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_SPDIF)
+			vortex_adb_setsrc(chip, dma, runtime->rate, dir);
+	}
+#ifndef CHIP_AU8810
+	else {
+		vortex_wtdma_setmode(chip, dma, 1, fmt, 0, 0);
+		// FIXME: Set rate (i guess using vortex_wt_writereg() somehow).
+		vortex_wtdma_setstartbuffer(chip, dma, 0);
+	}
+#endif
+	return 0;
+}
+
+/* trigger callback */
+static int snd_vortex_pcm_trigger(snd_pcm_substream_t * substream, int cmd)
+{
+	chip_t *chip = snd_pcm_substream_chip(substream);
+	stream_t *stream = (stream_t *) substream->runtime->private_data;
+	int dma = stream->dma;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		// do something to start the PCM engine
+		//printk(KERN_INFO "vortex: start %d\n", dma);
+		stream->fifo_enabled = 1;
+		if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
+			vortex_adbdma_startfifo(chip, dma);
+#ifndef CHIP_AU8810
+		else {
+			printk(KERN_INFO "vortex: wt start %d\n", dma);
+			vortex_wtdma_startfifo(chip, dma);
+		}
+#endif
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		// do something to stop the PCM engine
+		//printk(KERN_INFO "vortex: stop %d\n", dma)
+		stream->fifo_enabled = 0;
+		if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
+			vortex_adbdma_pausefifo(chip, dma);
+		//vortex_adbdma_stopfifo(chip, dma);
+#ifndef CHIP_AU8810
+		else {
+			printk(KERN_INFO "vortex: wt stop %d\n", dma);
+			vortex_wtdma_stopfifo(chip, dma);
+		}
+#endif
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		//printk(KERN_INFO "vortex: pause %d\n", dma);
+		if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
+			vortex_adbdma_pausefifo(chip, dma);
+#ifndef CHIP_AU8810
+		else
+			vortex_wtdma_pausefifo(chip, dma);
+#endif
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		//printk(KERN_INFO "vortex: resume %d\n", dma);
+		if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
+			vortex_adbdma_resumefifo(chip, dma);
+#ifndef CHIP_AU8810
+		else
+			vortex_wtdma_resumefifo(chip, dma);
+#endif
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* pointer callback */
+static snd_pcm_uframes_t snd_vortex_pcm_pointer(snd_pcm_substream_t * substream)
+{
+	vortex_t *chip = snd_pcm_substream_chip(substream);
+	stream_t *stream = (stream_t *) substream->runtime->private_data;
+	int dma = stream->dma;
+	snd_pcm_uframes_t current_ptr = 0;
+
+	spin_lock(&chip->lock);
+	if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
+		current_ptr = vortex_adbdma_getlinearpos(chip, dma);
+#ifndef CHIP_AU8810
+	else
+		current_ptr = vortex_wtdma_getlinearpos(chip, dma);
+#endif
+	//printk(KERN_INFO "vortex: pointer = 0x%x\n", current_ptr);
+	spin_unlock(&chip->lock);
+	return (bytes_to_frames(substream->runtime, current_ptr));
+}
+
+/* Page callback. */
+/*
+static struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset) {
+	
+	
+}
+*/
+/* operators */
+static snd_pcm_ops_t snd_vortex_playback_ops = {
+	.open = snd_vortex_pcm_open,
+	.close = snd_vortex_pcm_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_vortex_pcm_hw_params,
+	.hw_free = snd_vortex_pcm_hw_free,
+	.prepare = snd_vortex_pcm_prepare,
+	.trigger = snd_vortex_pcm_trigger,
+	.pointer = snd_vortex_pcm_pointer,
+	.page = snd_pcm_sgbuf_ops_page,
+};
+
+/*
+*  definitions of capture are omitted here...
+*/
+
+static char *vortex_pcm_prettyname[VORTEX_PCM_LAST] = {
+	"AU88x0 ADB",
+	"AU88x0 SPDIF",
+	"AU88x0 A3D",
+	"AU88x0 WT",
+	"AU88x0 I2S",
+};
+static char *vortex_pcm_name[VORTEX_PCM_LAST] = {
+	"adb",
+	"spdif",
+	"a3d",
+	"wt",
+	"i2s",
+};
+
+/* SPDIF kcontrol */
+static int
+snd_vortex_spdif_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	static char *texts[] = { "32000", "44100", "48000" };
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 3;
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item =
+		    uinfo->value.enumerated.items - 1;
+	strcpy(uinfo->value.enumerated.name,
+	       texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+static int
+snd_vortex_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
+
+	if (vortex->spdif_sr == 32000)
+		ucontrol->value.enumerated.item[0] = 0;
+	if (vortex->spdif_sr == 44100)
+		ucontrol->value.enumerated.item[0] = 1;
+	if (vortex->spdif_sr == 48000)
+		ucontrol->value.enumerated.item[0] = 2;
+	return 0;
+}
+static int
+snd_vortex_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
+	static unsigned int sr[3] = { 32000, 44100, 48000 };
+
+	//printk("vortex: spdif sr = %d\n", ucontrol->value.enumerated.item[0]);
+	vortex->spdif_sr = sr[ucontrol->value.enumerated.item[0] % 3];
+	vortex_spdif_init(vortex,
+			  sr[ucontrol->value.enumerated.item[0] % 3], 1);
+	return 1;
+}
+static snd_kcontrol_new_t vortex_spdif_kcontrol __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "SPDIF SR",
+	.index = 0,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.private_value = 0,
+	.info = snd_vortex_spdif_info,
+	.get = snd_vortex_spdif_get,
+	.put = snd_vortex_spdif_put
+};
+
+/* create a pcm device */
+static int __devinit snd_vortex_new_pcm(vortex_t * chip, int idx, int nr)
+{
+	snd_pcm_t *pcm;
+	int err, nr_capt;
+
+	if ((chip == 0) || (idx < 0) || (idx > VORTEX_PCM_LAST))
+		return -ENODEV;
+
+	/* idx indicates which kind of PCM device. ADB, SPDIF, I2S and A3D share the 
+	 * same dma engine. WT uses it own separate dma engine whcih cant capture. */
+	if (idx == VORTEX_PCM_ADB)
+		nr_capt = nr;
+	else
+		nr_capt = 0;
+	if ((err =
+	     snd_pcm_new(chip->card, vortex_pcm_prettyname[idx], idx, nr,
+			 nr_capt, &pcm)) < 0)
+		return err;
+	strcpy(pcm->name, vortex_pcm_name[idx]);
+	chip->pcm[idx] = pcm;
+	// This is an evil hack, but it saves a lot of duplicated code.
+	VORTEX_PCM_TYPE(pcm) = idx;
+	pcm->private_data = chip;
+	/* set operators */
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+			&snd_vortex_playback_ops);
+	if (idx == VORTEX_PCM_ADB)
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+				&snd_vortex_playback_ops);
+	/* pre-allocation of linear buffers */
+	//snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+	//				      snd_dma_pci_data(chip->pci_dev), 0x10000, 0x10000);
+	/* pre-allocation of Scatter-Gather buffers */
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+					      snd_dma_pci_data(chip->pci_dev),
+					      0x10000, 0x10000);
+
+	if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_SPDIF) {
+		snd_kcontrol_t *kcontrol;
+
+		if ((kcontrol =
+		     snd_ctl_new1(&vortex_spdif_kcontrol, chip)) == NULL)
+			return -ENOMEM;
+		if ((err = snd_ctl_add(chip->card, kcontrol)) < 0)
+			return err;
+	}
+	return 0;
+}
--- diff/sound/pci/au88x0/au88x0_sb.h	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au88x0_sb.h	2004-03-16 09:37:58.508645504 +0000
@@ -0,0 +1,40 @@
+/***************************************************************************
+ *            au88x0_sb.h
+ *
+ *  Wed Oct 29 22:10:42 2003
+ *  
+ ****************************************************************************/
+
+#ifdef CHIP_AU8820
+/* AU8820 starting @ 64KiB offset */
+#define SBEMU_BASE 0x10000
+#else
+/* AU8810? and AU8830 starting @ 164KiB offset */
+#define SBEMU_BASE 0x29000
+#endif
+
+#define FM_A_STATUS			(SBEMU_BASE + 0x00)	/* read */
+#define FM_A_ADDRESS		(SBEMU_BASE + 0x00)	/* write */
+#define FM_A_DATA			(SBEMU_BASE + 0x04)
+#define FM_B_STATUS			(SBEMU_BASE + 0x08)
+#define FM_B_ADDRESS		(SBEMU_BASE + 0x08)
+#define FM_B_DATA			(SBEMU_BASE + 0x0C)
+#define SB_MIXER_ADDR		(SBEMU_BASE + 0x10)
+#define SB_MIXER_DATA		(SBEMU_BASE + 0x14)
+#define SB_RESET			(SBEMU_BASE + 0x18)
+#define SB_RESET_ALIAS		(SBEMU_BASE + 0x1C)
+#define FM_STATUS2			(SBEMU_BASE + 0x20)
+#define FM_ADDR2			(SBEMU_BASE + 0x20)
+#define FM_DATA2			(SBEMU_BASE + 0x24)
+#define SB_DSP_READ			(SBEMU_BASE + 0x28)
+#define SB_DSP_WRITE		(SBEMU_BASE + 0x30)
+#define SB_DSP_WRITE_STATUS	(SBEMU_BASE + 0x30)	/* bit 7 */
+#define SB_DSP_READ_STATUS	(SBEMU_BASE + 0x38)	/* bit 7 */
+#define SB_LACR				(SBEMU_BASE + 0x40)	/* ? */
+#define SB_LADCR			(SBEMU_BASE + 0x44)	/* ? */
+#define SB_LAMR				(SBEMU_BASE + 0x48)	/* ? */
+#define SB_LARR				(SBEMU_BASE + 0x4C)	/* ? */
+#define SB_VERSION			(SBEMU_BASE + 0x50)
+#define SB_CTRLSTAT			(SBEMU_BASE + 0x54)
+#define SB_TIMERSTAT		(SBEMU_BASE + 0x58)
+#define FM_RAM				(SBEMU_BASE + 0x100)	/* 0x40 ULONG */
--- diff/sound/pci/au88x0/au88x0_synth.c	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au88x0_synth.c	2004-03-16 09:37:58.510645200 +0000
@@ -0,0 +1,393 @@
+/*
+ *  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 Library 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.
+ */
+
+/*
+ * Someday its supposed to make use of the WT DMA engine
+ * for a Wavetable synthesizer.
+ */
+
+#include "au88x0.h"
+#include "au88x0_wt.h"
+
+static void vortex_fifo_setwtvalid(vortex_t * vortex, int fifo, int en);
+static void vortex_connection_adb_mixin(vortex_t * vortex, int en,
+					unsigned char channel,
+					unsigned char source,
+					unsigned char mixin);
+static void vortex_connection_mixin_mix(vortex_t * vortex, int en,
+					unsigned char mixin,
+					unsigned char mix, int a);
+static void vortex_fifo_wtinitialize(vortex_t * vortex, int fifo, int j);
+static int vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
+			    unsigned long val);
+
+/* WT */
+
+static void vortex_wt_setstereo(vortex_t * vortex, u32 wt, u32 stereo)
+{
+	int temp;
+
+	//temp = hwread(vortex->mmio, 0x80 + ((wt >> 0x5)<< 0xf) + (((wt & 0x1f) >> 1) << 2));
+	temp = hwread(vortex->mmio, WT_STEREO(wt));
+	temp = (temp & 0xfe) | (stereo & 1);
+	//hwwrite(vortex->mmio, 0x80 + ((wt >> 0x5)<< 0xf) + (((wt & 0x1f) >> 1) << 2), temp);
+	hwwrite(vortex->mmio, WT_STEREO(wt), temp);
+}
+
+static void vortex_wt_setdsout(vortex_t * vortex, u32 wt, int en)
+{
+	int temp;
+
+	/* There is one DSREG register for each bank (32 voices each). */
+	temp = hwread(vortex->mmio, WT_DSREG((wt >= 0x20) ? 1 : 0));
+	if (en)
+		temp |= (1 << (wt & 0x1f));
+	else
+		temp &= (1 << ~(wt & 0x1f));
+	hwwrite(vortex->mmio, WT_DSREG((wt >= 0x20) ? 1 : 0), temp);
+}
+
+// WT routing is still a mistery.
+static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch)
+{
+	wt_voice_t *voice = &(vortex->wt_voice[wt]);
+	int temp;
+
+	//FIXME: WT audio routing.
+	if (nr_ch) {
+		vortex_fifo_wtinitialize(vortex, wt, 2);
+		vortex_fifo_setwtvalid(vortex, wt, 1);
+		vortex_wt_setstereo(vortex, wt, nr_ch - 1);
+	} else
+		vortex_fifo_setwtvalid(vortex, wt, 0);
+
+	vortex_wt_setdsout(vortex, wt, 0);
+	hwwrite(vortex->mmio, WT_SRAMP(0), 0x880000);
+	//hwwrite(vortex->mmio, WT_GMODE(0), 0xffffffff);
+#ifdef CHIP_AU8830
+	hwwrite(vortex->mmio, WT_SRAMP(1), 0x880000);
+	//hwwrite(vortex->mmio, WT_GMODE(1), 0xffffffff);
+#endif
+	hwwrite(vortex->mmio, WT_PARM(wt, 0), 0);
+	hwwrite(vortex->mmio, WT_PARM(wt, 1), 0);
+	hwwrite(vortex->mmio, WT_PARM(wt, 2), 0);
+
+	temp = hwread(vortex->mmio, WT_PARM(wt, 3));
+	printk("vortex: WT PARM3: %x\n", temp);
+	hwwrite(vortex->mmio, WT_PARM(wt, 3), temp);
+
+	hwwrite(vortex->mmio, WT_DELAY(wt, 0), 0);
+	hwwrite(vortex->mmio, WT_DELAY(wt, 1), 0);
+	hwwrite(vortex->mmio, WT_DELAY(wt, 2), 0);
+	hwwrite(vortex->mmio, WT_DELAY(wt, 3), 0);
+
+	printk("vortex: WT GMODE: %x\n", hwread(vortex->mmio, WT_GMODE(wt)));
+
+	hwwrite(vortex->mmio, WT_PARM(wt, 2), 0xffffffff);
+	hwwrite(vortex->mmio, WT_PARM(wt, 3), 0xcff1c810);
+
+	voice->parm0 = voice->parm1 = 0xcfb23e2f;
+	hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0);
+	hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1);
+	printk("vortex: WT GMODE 2 : %x\n", hwread(vortex->mmio, WT_GMODE(wt)));
+	return 0;
+}
+
+static void vortex_wt_connect(vortex_t * vortex, int en)
+{
+	int i, ii, mix;
+
+#define NR_WTROUTES 6
+#ifdef CHIP_AU8830
+#define NR_WTBLOCKS 2
+#else
+#define NR_WTBLOCKS 1
+#endif
+
+	for (i = 0; i < NR_WTBLOCKS; i++) {
+		for (ii = 0; ii < NR_WTROUTES; ii++) {
+			mix =
+			    vortex_adb_checkinout(vortex,
+						  vortex->fixed_res, en,
+						  VORTEX_RESOURCE_MIXIN);
+			vortex->mixwt[(i * NR_WTROUTES) + ii] = mix;
+
+			vortex_route(vortex, en, 0x11,
+				     ADB_WTOUT(i, ii + 0x20), ADB_MIXIN(mix));
+
+			vortex_connection_mixin_mix(vortex, en, mix,
+						    vortex->mixplayb[ii %
+								     2], 0);
+			if (VORTEX_IS_QUAD(vortex))
+				vortex_connection_mixin_mix(vortex, en,
+							    mix,
+							    vortex->
+							    mixplayb[2 +
+								     (ii %
+								      2)], 0);
+		}
+	}
+	for (i = 0; i < NR_WT; i++) {
+		hwwrite(vortex->mmio, WT_RUN(i), 1);
+	}
+}
+
+/* Read WT Register */
+#if 0
+static int vortex_wt_GetReg(vortex_t * vortex, char reg, int wt)
+{
+	//int eax, esi;
+
+	if (reg == 4) {
+		return hwread(vortex->mmio, WT_PARM(wt, 3));
+	}
+	if (reg == 7) {
+		return hwread(vortex->mmio, WT_GMODE(wt));;
+	}
+
+	return 0;
+}
+
+/* WT hardware abstraction layer generic register interface. */
+static int
+vortex_wt_SetReg2(vortex_t * vortex, unsigned char reg, int wt,
+		  unsigned short val)
+{
+	/*
+	   int eax, edx;
+
+	   if (wt >= NR_WT)  // 0x40 -> NR_WT
+	   return 0;
+
+	   if ((reg - 0x20) > 0) {
+	   if ((reg - 0x21) != 0) 
+	   return 0;
+	   eax = ((((b & 0xff) << 0xb) + (edx & 0xff)) << 4) + 0x208; // param 2
+	   } else {
+	   eax = ((((b & 0xff) << 0xb) + (edx & 0xff)) << 4) + 0x20a; // param 3
+	   }
+	   hwwrite(vortex->mmio, eax, c);
+	 */
+	return 1;
+}
+
+/*public: static void __thiscall CWTHal::SetReg(unsigned char,int,unsigned long) */
+#endif
+static int
+vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
+		 unsigned long val)
+{
+	int ecx;
+
+	if ((reg == 5) || ((reg >= 7) && (reg <= 10)) || (reg == 0xc)) {
+		if (wt >= (NR_WT / NR_WT_PB)) {
+			printk
+			    ("vortex: WT SetReg: bank out of range. reg=0x%x, wt=%d\n",
+			     reg, wt);
+			return 0;
+		}
+	} else {
+		if (wt >= NR_WT) {
+			printk("vortex: WT SetReg: voice out of range\n");
+			return 0;
+		}
+	}
+	if (reg > 0xc)
+		return 0;
+
+	switch (reg) {
+		/* Voice specific parameters */
+	case 0:		/* running */
+		//printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_RUN(wt), (int)val);
+		hwwrite(vortex->mmio, WT_RUN(wt), val);
+		return 0xc;
+		break;
+	case 1:		/* param 0 */
+		//printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,0), (int)val);
+		hwwrite(vortex->mmio, WT_PARM(wt, 0), val);
+		return 0xc;
+		break;
+	case 2:		/* param 1 */
+		//printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,1), (int)val);
+		hwwrite(vortex->mmio, WT_PARM(wt, 1), val);
+		return 0xc;
+		break;
+	case 3:		/* param 2 */
+		//printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,2), (int)val);
+		hwwrite(vortex->mmio, WT_PARM(wt, 2), val);
+		return 0xc;
+		break;
+	case 4:		/* param 3 */
+		//printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,3), (int)val);
+		hwwrite(vortex->mmio, WT_PARM(wt, 3), val);
+		return 0xc;
+		break;
+	case 6:		/* mute */
+		//printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_MUTE(wt), (int)val);
+		hwwrite(vortex->mmio, WT_MUTE(wt), val);
+		return 0xc;
+		break;
+	case 0xb:
+		{		/* delay */
+			//printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_DELAY(wt,0), (int)val);
+			hwwrite(vortex->mmio, WT_DELAY(wt, 3), val);
+			hwwrite(vortex->mmio, WT_DELAY(wt, 2), val);
+			hwwrite(vortex->mmio, WT_DELAY(wt, 1), val);
+			hwwrite(vortex->mmio, WT_DELAY(wt, 0), val);
+			return 0xc;
+		}
+		break;
+		/* Global WT block parameters */
+	case 5:		/* sramp */
+		ecx = WT_SRAMP(wt);
+		break;
+	case 8:		/* aramp */
+		ecx = WT_ARAMP(wt);
+		break;
+	case 9:		/* mramp */
+		ecx = WT_MRAMP(wt);
+		break;
+	case 0xa:		/* ctrl */
+		ecx = WT_CTRL(wt);
+		break;
+	case 0xc:		/* ds_reg */
+		ecx = WT_DSREG(wt);
+		break;
+	default:
+		return 0;
+		break;
+	}
+	//printk("vortex: WT SetReg(0x%x) = 0x%08x\n", ecx, (int)val);
+	hwwrite(vortex->mmio, ecx, val);
+	return 1;
+}
+
+static void vortex_wt_init(vortex_t * vortex)
+{
+	int var4, var8, varc, var10 = 0, edi;
+
+	var10 &= 0xFFFFFFE3;
+	var10 |= 0x22;
+	var10 &= 0xFFFFFEBF;
+	var10 |= 0x80;
+	var10 |= 0x200;
+	var10 &= 0xfffffffe;
+	var10 &= 0xfffffbff;
+	var10 |= 0x1800;
+	// var10 = 0x1AA2
+	var4 = 0x10000000;
+	varc = 0x00830000;
+	var8 = 0x00830000;
+
+	/* Init Bank registers. */
+	for (edi = 0; edi < (NR_WT / NR_WT_PB); edi++) {
+		vortex_wt_SetReg(vortex, 0xc, edi, 0);	/* ds_reg */
+		vortex_wt_SetReg(vortex, 0xa, edi, var10);	/* ctrl  */
+		vortex_wt_SetReg(vortex, 0x9, edi, var4);	/* mramp */
+		vortex_wt_SetReg(vortex, 0x8, edi, varc);	/* aramp */
+		vortex_wt_SetReg(vortex, 0x5, edi, var8);	/* sramp */
+	}
+	/* Init Voice registers. */
+	for (edi = 0; edi < NR_WT; edi++) {
+		vortex_wt_SetReg(vortex, 0x4, edi, 0);	/* param 3 0x20c */
+		vortex_wt_SetReg(vortex, 0x3, edi, 0);	/* param 2 0x208 */
+		vortex_wt_SetReg(vortex, 0x2, edi, 0);	/* param 1 0x204 */
+		vortex_wt_SetReg(vortex, 0x1, edi, 0);	/* param 0 0x200 */
+		vortex_wt_SetReg(vortex, 0xb, edi, 0);	/* delay 0x400 - 0x40c */
+	}
+	var10 |= 1;
+	for (edi = 0; edi < (NR_WT / NR_WT_PB); edi++)
+		vortex_wt_SetReg(vortex, 0xa, edi, var10);	/* ctrl */
+}
+
+/* Extract of CAdbTopology::SetVolume(struct _ASPVOLUME *) */
+#if 0
+static void vortex_wt_SetVolume(vortex_t * vortex, int wt, int vol[])
+{
+	wt_voice_t *voice = &(vortex->wt_voice[wt]);
+	int ecx = vol[1], eax = vol[0];
+
+	/* This is pure guess */
+	voice->parm0 &= 0xff00ffff;
+	voice->parm0 |= (vol[0] & 0xff) << 0x10;
+	voice->parm1 &= 0xff00ffff;
+	voice->parm1 |= (vol[1] & 0xff) << 0x10;
+
+	/* This is real */
+	hwwrite(vortex, WT_PARM(wt, 0), voice->parm0);
+	hwwrite(vortex, WT_PARM(wt, 1), voice->parm0);
+
+	if (voice->this_1D0 & 4) {
+		eax >>= 8;
+		ecx = eax;
+		if (ecx < 0x80)
+			ecx = 0x7f;
+		voice->parm3 &= 0xFFFFC07F;
+		voice->parm3 |= (ecx & 0x7f) << 7;
+		voice->parm3 &= 0xFFFFFF80;
+		voice->parm3 |= (eax & 0x7f);
+	} else {
+		voice->parm3 &= 0xFFE03FFF;
+		voice->parm3 |= (eax & 0xFE00) << 5;
+	}
+
+	hwwrite(vortex, WT_PARM(wt, 3), voice->parm3);
+}
+
+/* Extract of CAdbTopology::SetFrequency(unsigned long arg_0) */
+static void vortex_wt_SetFrequency(vortex_t * vortex, int wt, unsigned int sr)
+{
+	wt_voice_t *voice = &(vortex->wt_voice[wt]);
+	long int eax, edx;
+
+	//FIXME: 64 bit operation.
+	eax = ((sr << 0xf) * 0x57619F1) & 0xffffffff;
+	edx = (((sr << 0xf) * 0x57619F1)) >> 0x20;
+
+	edx >>= 0xa;
+	edx <<= 1;
+	if (edx) {
+		if (edx & 0x0FFF80000)
+			eax = 0x7fff;
+		else {
+			edx <<= 0xd;
+			eax = 7;
+			while ((edx & 0x80000000) == 0) {
+				edx <<= 1;
+				eax--;
+				if (eax == 0) ;
+				break;
+			}
+			if (eax)
+				edx <<= 1;
+			eax <<= 0xc;
+			edx >>= 0x14;
+			eax |= edx;
+		}
+	} else
+		eax = 0;
+	voice->parm0 &= 0xffff0001;
+	voice->parm0 |= (eax & 0x7fff) << 1;
+	voice->parm1 = voice->parm0 | 1;
+	// Wt: this_1D4
+	//AuWt::WriteReg((ulong)(this_1DC<<4)+0x200, (ulong)this_1E4);
+	//AuWt::WriteReg((ulong)(this_1DC<<4)+0x204, (ulong)this_1E8);
+	hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0);
+	hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1);
+}
+#endif
+
+/* End of File */
--- diff/sound/pci/au88x0/au88x0_wt.h	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au88x0_wt.h	2004-03-16 09:37:58.511645048 +0000
@@ -0,0 +1,65 @@
+/***************************************************************************
+ *           WT register offsets.
+ *
+ *  Wed Oct 22 13:50:20 2003
+ *  Copyright  2003  mjander
+ *  mjander@users.sourceforge.org
+ ****************************************************************************/
+#ifndef _AU88X0_WT_H
+#define _AU88X0_WT_H
+
+/* WT channels are grouped in banks. Each bank has 0x20 channels. */
+/* Bank register address boundary is 0x8000 */
+
+#define NR_WT_PB 0x20
+
+/* WT bank base register (as dword address). */
+#define WT_BAR(x) (((x)&0xffe0)<<0x8)
+#define WT_BANK(x) (x>>5)
+/* WT Bank registers */
+#define WT_CTRL(bank)	(((((bank)&1)<<0xd) + 0x00)<<2)	/* 0x0000 */
+#define WT_SRAMP(bank)	(((((bank)&1)<<0xd) + 0x01)<<2)	/* 0x0004 */
+#define WT_DSREG(bank)	(((((bank)&1)<<0xd) + 0x02)<<2)	/* 0x0008 */
+#define WT_MRAMP(bank)	(((((bank)&1)<<0xd) + 0x03)<<2)	/* 0x000c */
+#define WT_GMODE(bank)	(((((bank)&1)<<0xd) + 0x04)<<2)	/* 0x0010 */
+#define WT_ARAMP(bank)	(((((bank)&1)<<0xd) + 0x05)<<2)	/* 0x0014 */
+/* WT Voice registers */
+#define WT_STEREO(voice)	((WT_BAR(voice)+ 0x20 +(((voice)&0x1f)>>1))<<2)	/* 0x0080 */
+#define WT_MUTE(voice)		((WT_BAR(voice)+ 0x40 +((voice)&0x1f))<<2)	/* 0x0100 */
+#define WT_RUN(voice)		((WT_BAR(voice)+ 0x60 +((voice)&0x1f))<<2)	/* 0x0180 */
+/* Some kind of parameters. */
+/* PARM0, PARM1 : Filter (0xFF000000), SampleRate (0x0000FFFF) */
+/* PARM2, PARM3 : Still unknown */
+#define WT_PARM(x,y)	(((WT_BAR(x))+ 0x80 +(((x)&0x1f)<<2)+(y))<<2)	/* 0x0200 */
+#define WT_DELAY(x,y)	(((WT_BAR(x))+ 0x100 +(((x)&0x1f)<<2)+(y))<<2)	/* 0x0400 */
+
+/* Numeric indexes used by SetReg() and GetReg() */
+#if 0
+enum {
+	run = 0,		/* 0  W 1:run 0:stop */
+	parm0,			/* 1  W filter, samplerate */
+	parm1,			/* 2  W filter, samplerate */
+	parm2,			/* 3  W  */
+	parm3,			/* 4  RW volume. This value is calculated using floating point ops. */
+	sramp,			/* 5  W */
+	mute,			/* 6  W 1:mute, 0:unmute */
+	gmode,			/* 7  RO Looks like only bit0 is used. */
+	aramp,			/* 8  W */
+	mramp,			/* 9  W */
+	ctrl,			/* a  W */
+	delay,			/* b  W All 4 values are written at once with same value. */
+	dsreg,			/* c  (R)W */
+} wt_reg;
+#endif
+
+typedef struct {
+	unsigned int parm0;	/* this_1E4 */
+	unsigned int parm1;	/* this_1E8 */
+	unsigned int parm2;	/* this_1EC */
+	unsigned int parm3;	/* this_1F0 */
+	unsigned int this_1D0;
+} wt_voice_t;
+
+#endif				/* _AU88X0_WT_H */
+
+/* End of file */
--- diff/sound/pci/au88x0/au88x0_xtalk.c	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au88x0_xtalk.c	2004-03-16 09:37:58.513644744 +0000
@@ -0,0 +1,781 @@
+/***************************************************************************
+ *            au88x0_cxtalk.c
+ *
+ *  Wed Nov 19 16:29:47 2003
+ *  Copyright  2003  mjander
+ *  mjander@users.sourceforge.org
+ ****************************************************************************/
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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 Library 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 "au88x0_xtalk.h"
+
+/* Data (a whole lot of data.... ) */
+
+static short const sXtalkWideKLeftEq = 0x269C;
+static short const sXtalkWideKRightEq = 0x269C;
+static short const sXtalkWideKLeftXt = 0xF25E;
+static short const sXtalkWideKRightXt = 0xF25E;
+static short const sXtalkWideShiftLeftEq = 1;
+static short const sXtalkWideShiftRightEq = 1;
+static short const sXtalkWideShiftLeftXt = 0;
+static short const sXtalkWideShiftRightXt = 0;
+static unsigned short const wXtalkWideLeftDelay = 0xd;
+static unsigned short const wXtalkWideRightDelay = 0xd;
+static short const sXtalkNarrowKLeftEq = 0x468D;
+static short const sXtalkNarrowKRightEq = 0x468D;
+static short const sXtalkNarrowKLeftXt = 0xF82E;
+static short const sXtalkNarrowKRightXt = 0xF82E;
+static short const sXtalkNarrowShiftLeftEq = 0x3;
+static short const sXtalkNarrowShiftRightEq = 0x3;
+static short const sXtalkNarrowShiftLeftXt = 0;
+static short const sXtalkNarrowShiftRightXt = 0;
+static unsigned short const wXtalkNarrowLeftDelay = 0x7;
+static unsigned short const wXtalkNarrowRightDelay = 0x7;
+
+static xtalk_gains_t const asXtalkGainsDefault = {
+	0x4000, 0x4000, 4000, 0x4000, 4000, 0x4000, 4000, 0x4000, 4000,
+	0x4000
+};
+
+static xtalk_gains_t const asXtalkGainsTest = {
+	0x8000, 0x7FFF, 0, 0xFFFF, 0x0001, 0xC000, 0x4000, 0xFFFE, 0x0002,
+	0
+};
+static xtalk_gains_t const asXtalkGains1Chan = {
+	0x7FFF, 0, 0, 0, 0x7FFF, 0, 0, 0, 0, 0
+};
+
+// Input gain for 4 A3D slices. One possible input pair is left zero.
+static xtalk_gains_t const asXtalkGainsAllChan = {
+	0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
+	0
+	    //0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff,0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff
+};
+static xtalk_gains_t const asXtalkGainsZeros = {
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static xtalk_dline_t const alXtalkDlineZeros = {
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0
+};
+static xtalk_dline_t const alXtalkDlineTest = {
+	0xFC18, 0x03E8FFFF, 0x186A0, 0x7960FFFE, 1, 0xFFFFFFFF,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0
+};
+
+static xtalk_instate_t const asXtalkInStateZeros = { 0, 0, 0, 0 };
+static xtalk_instate_t const asXtalkInStateTest =
+    { 0xFF80, 0x0080, 0xFFFF, 0x0001 };
+static xtalk_state_t const asXtalkOutStateZeros = {
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0}
+};
+static short const sDiamondKLeftEq = 0x401d;
+static short const sDiamondKRightEq = 0x401d;
+static short const sDiamondKLeftXt = 0xF90E;
+static short const sDiamondKRightXt = 0xF90E;
+static short const sDiamondShiftLeftEq = 1;	/* 0xF90E Is this a bug ??? */
+static short const sDiamondShiftRightEq = 1;
+static short const sDiamondShiftLeftXt = 0;
+static short const sDiamondShiftRightXt = 0;
+static unsigned short const wDiamondLeftDelay = 0xb;
+static unsigned short const wDiamondRightDelay = 0xb;
+
+static xtalk_coefs_t const asXtalkWideCoefsLeftEq = {
+	{0xEC4C, 0xDCE9, 0xFDC2, 0xFEEC, 0},
+	{0x5F60, 0xCBCB, 0xFC26, 0x0305, 0},
+	{0x340B, 0xf504, 0x6CE8, 0x0D23, 0x00E4},
+	{0xD500, 0x8D76, 0xACC7, 0x5B05, 0x00FA},
+	{0x7F04, 0xC0FA, 0x0263, 0xFDA2, 0}
+};
+static xtalk_coefs_t const asXtalkWideCoefsRightEq = {
+	{0xEC4C, 0xDCE9, 0xFDC2, 0xFEEC, 0},
+	{0x5F60, 0xCBCB, 0xFC26, 0x0305, 0},
+	{0x340B, 0xF504, 0x6CE8, 0x0D23, 0x00E4},
+	{0xD500, 0x8D76, 0xACC7, 0x5B05, 0x00FA},
+	{0x7F04, 0xC0FA, 0x0263, 0xFDA2, 0}
+};
+static xtalk_coefs_t const asXtalkWideCoefsLeftXt = {
+	{0x86C3, 0x7B55, 0x89C3, 0x005B, 0x0047},
+	{0x6000, 0x206A, 0xC6CA, 0x40FF, 0},
+	{0x1100, 0x1164, 0xA1D7, 0x90FC, 0x0001},
+	{0xDC00, 0x9E77, 0xB8C7, 0x0AFF, 0},
+	{0, 0, 0, 0, 0}
+};
+static xtalk_coefs_t const asXtalkWideCoefsRightXt = {
+	{0x86C3, 0x7B55, 0x89C3, 0x005B, 0x0047},
+	{0x6000, 0x206A, 0xC6CA, 0x40FF, 0},
+	{0x1100, 0x1164, 0xA1D7, 0x90FC, 0x0001},
+	{0xDC00, 0x9E77, 0xB8C7, 0x0AFF, 0},
+	{0, 0, 0, 0, 0}
+};
+static xtalk_coefs_t const asXtalkNarrowCoefsLeftEq = {
+	{0x50B5, 0xD07C, 0x026D, 0xFD21, 0},
+	{0x460F, 0xE44F, 0xF75E, 0xEFA6, 0},
+	{0x556D, 0xDCAB, 0x2098, 0xF0F2, 0},
+	{0x7E03, 0xC1F0, 0x007D, 0xFF89, 0},
+	{0x383E, 0xFD9D, 0xB278, 0x4547, 0}
+};
+
+static xtalk_coefs_t const asXtalkNarrowCoefsRightEq = {
+	{0x50B5, 0xD07C, 0x026D, 0xFD21, 0},
+	{0x460F, 0xE44F, 0xF75E, 0xEFA6, 0},
+	{0x556D, 0xDCAB, 0x2098, 0xF0F2, 0},
+	{0x7E03, 0xC1F0, 0x007D, 0xFF89, 0},
+	{0x383E, 0xFD9D, 0xB278, 0x4547, 0}
+};
+
+static xtalk_coefs_t const asXtalkNarrowCoefsLeftXt = {
+	{0x3CB2, 0xDF49, 0xF6EA, 0x095B, 0},
+	{0x6777, 0xC915, 0xFEAF, 0x00B1, 0},
+	{0x7762, 0xC7D9, 0x025B, 0xFDA6, 0},
+	{0x6B7A, 0xD2AA, 0xF2FB, 0x0B64, 0},
+	{0, 0, 0, 0, 0}
+};
+
+static xtalk_coefs_t const asXtalkNarrowCoefsRightXt = {
+	{0x3CB2, 0xDF49, 0xF6EA, 0x095B, 0},
+	{0x6777, 0xC915, 0xFEAF, 0x00B1, 0},
+	{0x7762, 0xC7D9, 0x025B, 0xFDA6, 0},
+	{0x6B7A, 0xD2AA, 0xF2FB, 0x0B64, 0},
+	{0, 0, 0, 0, 0}
+};
+
+static xtalk_coefs_t const asXtalkCoefsZeros = {
+	{0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0}
+};
+static xtalk_coefs_t const asXtalkCoefsPipe = {
+	{0, 0, 0x0FA0, 0, 0},
+	{0, 0, 0x0FA0, 0, 0},
+	{0, 0, 0x0FA0, 0, 0},
+	{0, 0, 0x0FA0, 0, 0},
+	{0, 0, 0x1180, 0, 0},
+};
+static xtalk_coefs_t const asXtalkCoefsNegPipe = {
+	{0, 0, 0xF380, 0, 0},
+	{0, 0, 0xF380, 0, 0},
+	{0, 0, 0xF380, 0, 0},
+	{0, 0, 0xF380, 0, 0},
+	{0, 0, 0xF200, 0, 0}
+};
+
+static xtalk_coefs_t const asXtalkCoefsNumTest = {
+	{0, 0, 0xF380, 0x8000, 0x6D60},
+	{0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0}
+};
+
+static xtalk_coefs_t const asXtalkCoefsDenTest = {
+	{0xC000, 0x2000, 0x4000, 0, 0},
+	{0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0}
+};
+
+static xtalk_state_t const asXtalkOutStateTest = {
+	{0x7FFF, 0x0004, 0xFFFC, 0},
+	{0xFE00, 0x0008, 0xFFF8, 0x4000},
+	{0x200, 0x0010, 0xFFF0, 0xC000},
+	{0x8000, 0x0020, 0xFFE0, 0},
+	{0, 0, 0, 0}
+};
+
+static xtalk_coefs_t const asDiamondCoefsLeftEq = {
+	{0x0F1E, 0x2D05, 0xF8E3, 0x07C8, 0},
+	{0x45E2, 0xCA51, 0x0448, 0xFCE7, 0},
+	{0xA93E, 0xDBD5, 0x022C, 0x028A, 0},
+	{0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0}
+};
+
+static xtalk_coefs_t const asDiamondCoefsRightEq = {
+	{0x0F1E, 0x2D05, 0xF8E3, 0x07C8, 0},
+	{0x45E2, 0xCA51, 0x0448, 0xFCE7, 0},
+	{0xA93E, 0xDBD5, 0x022C, 0x028A, 0},
+	{0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0}
+};
+
+static xtalk_coefs_t const asDiamondCoefsLeftXt = {
+	{0x3B50, 0xFE08, 0xF959, 0x0060, 0},
+	{0x9FCB, 0xD8F1, 0x00A2, 0x003A, 0},
+	{0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0}
+};
+
+static xtalk_coefs_t const asDiamondCoefsRightXt = {
+	{0x3B50, 0xFE08, 0xF959, 0x0060, 0},
+	{0x9FCB, 0xD8F1, 0x00A2, 0x003A, 0},
+	{0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0}
+};
+
+ /**/
+/* XTalk EQ and XT */
+static void
+vortex_XtalkHw_SetLeftEQ(vortex_t * vortex, short arg_0, short arg_4,
+			 xtalk_coefs_t const coefs)
+{
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		hwwrite(vortex->mmio, 0x24200 + i * 0x24, coefs[i][0]);
+		hwwrite(vortex->mmio, 0x24204 + i * 0x24, coefs[i][1]);
+		hwwrite(vortex->mmio, 0x24208 + i * 0x24, coefs[i][2]);
+		hwwrite(vortex->mmio, 0x2420c + i * 0x24, coefs[i][3]);
+		hwwrite(vortex->mmio, 0x24210 + i * 0x24, coefs[i][4]);
+	}
+	hwwrite(vortex->mmio, 0x24538, arg_0 & 0xffff);
+	hwwrite(vortex->mmio, 0x2453C, arg_4 & 0xffff);
+}
+
+static void
+vortex_XtalkHw_SetRightEQ(vortex_t * vortex, short arg_0, short arg_4,
+			  xtalk_coefs_t const coefs)
+{
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		hwwrite(vortex->mmio, 0x242b4 + i * 0x24, coefs[i][0]);
+		hwwrite(vortex->mmio, 0x242b8 + i * 0x24, coefs[i][1]);
+		hwwrite(vortex->mmio, 0x242bc + i * 0x24, coefs[i][2]);
+		hwwrite(vortex->mmio, 0x242c0 + i * 0x24, coefs[i][3]);
+		hwwrite(vortex->mmio, 0x242c4 + i * 0x24, coefs[i][4]);
+	}
+	hwwrite(vortex->mmio, 0x24540, arg_0 & 0xffff);
+	hwwrite(vortex->mmio, 0x24544, arg_4 & 0xffff);
+}
+
+static void
+vortex_XtalkHw_SetLeftXT(vortex_t * vortex, short arg_0, short arg_4,
+			 xtalk_coefs_t const coefs)
+{
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		hwwrite(vortex->mmio, 0x24368 + i * 0x24, coefs[i][0]);
+		hwwrite(vortex->mmio, 0x2436c + i * 0x24, coefs[i][1]);
+		hwwrite(vortex->mmio, 0x24370 + i * 0x24, coefs[i][2]);
+		hwwrite(vortex->mmio, 0x24374 + i * 0x24, coefs[i][3]);
+		hwwrite(vortex->mmio, 0x24378 + i * 0x24, coefs[i][4]);
+	}
+	hwwrite(vortex->mmio, 0x24548, arg_0 & 0xffff);
+	hwwrite(vortex->mmio, 0x2454C, arg_4 & 0xffff);
+}
+
+static void
+vortex_XtalkHw_SetRightXT(vortex_t * vortex, short arg_0, short arg_4,
+			  xtalk_coefs_t const coefs)
+{
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		hwwrite(vortex->mmio, 0x2441C + i * 0x24, coefs[i][0]);
+		hwwrite(vortex->mmio, 0x24420 + i * 0x24, coefs[i][1]);
+		hwwrite(vortex->mmio, 0x24424 + i * 0x24, coefs[i][2]);
+		hwwrite(vortex->mmio, 0x24428 + i * 0x24, coefs[i][3]);
+		hwwrite(vortex->mmio, 0x2442C + i * 0x24, coefs[i][4]);
+	}
+	hwwrite(vortex->mmio, 0x24550, arg_0 & 0xffff);
+	hwwrite(vortex->mmio, 0x24554, arg_4 & 0xffff);
+}
+
+static void
+vortex_XtalkHw_SetLeftEQStates(vortex_t * vortex,
+			       xtalk_instate_t const arg_0,
+			       xtalk_state_t const coefs)
+{
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		hwwrite(vortex->mmio, 0x24214 + i * 0x24, coefs[i][0]);
+		hwwrite(vortex->mmio, 0x24218 + i * 0x24, coefs[i][1]);
+		hwwrite(vortex->mmio, 0x2421C + i * 0x24, coefs[i][2]);
+		hwwrite(vortex->mmio, 0x24220 + i * 0x24, coefs[i][3]);
+	}
+	hwwrite(vortex->mmio, 0x244F8 + i * 0x24, arg_0[0]);
+	hwwrite(vortex->mmio, 0x244FC + i * 0x24, arg_0[1]);
+	hwwrite(vortex->mmio, 0x24500 + i * 0x24, arg_0[2]);
+	hwwrite(vortex->mmio, 0x24504 + i * 0x24, arg_0[3]);
+}
+
+static void
+vortex_XtalkHw_SetRightEQStates(vortex_t * vortex,
+				xtalk_instate_t const arg_0,
+				xtalk_state_t const coefs)
+{
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		hwwrite(vortex->mmio, 0x242C8 + i * 0x24, coefs[i][0]);
+		hwwrite(vortex->mmio, 0x242CC + i * 0x24, coefs[i][1]);
+		hwwrite(vortex->mmio, 0x242D0 + i * 0x24, coefs[i][2]);
+		hwwrite(vortex->mmio, 0x244D4 + i * 0x24, coefs[i][3]);
+	}
+	hwwrite(vortex->mmio, 0x24508 + i * 0x24, arg_0[0]);
+	hwwrite(vortex->mmio, 0x2450C + i * 0x24, arg_0[1]);
+	hwwrite(vortex->mmio, 0x24510 + i * 0x24, arg_0[2]);
+	hwwrite(vortex->mmio, 0x24514 + i * 0x24, arg_0[3]);
+}
+
+static void
+vortex_XtalkHw_SetLeftXTStates(vortex_t * vortex,
+			       xtalk_instate_t const arg_0,
+			       xtalk_state_t const coefs)
+{
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		hwwrite(vortex->mmio, 0x2437C + i * 0x24, coefs[i][0]);
+		hwwrite(vortex->mmio, 0x24380 + i * 0x24, coefs[i][1]);
+		hwwrite(vortex->mmio, 0x24384 + i * 0x24, coefs[i][2]);
+		hwwrite(vortex->mmio, 0x24388 + i * 0x24, coefs[i][3]);
+	}
+	hwwrite(vortex->mmio, 0x24518 + i * 0x24, arg_0[0]);
+	hwwrite(vortex->mmio, 0x2451C + i * 0x24, arg_0[1]);
+	hwwrite(vortex->mmio, 0x24520 + i * 0x24, arg_0[2]);
+	hwwrite(vortex->mmio, 0x24524 + i * 0x24, arg_0[3]);
+}
+
+static void
+vortex_XtalkHw_SetRightXTStates(vortex_t * vortex,
+				xtalk_instate_t const arg_0,
+				xtalk_state_t const coefs)
+{
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		hwwrite(vortex->mmio, 0x24430 + i * 0x24, coefs[i][0]);
+		hwwrite(vortex->mmio, 0x24434 + i * 0x24, coefs[i][1]);
+		hwwrite(vortex->mmio, 0x24438 + i * 0x24, coefs[i][2]);
+		hwwrite(vortex->mmio, 0x2443C + i * 0x24, coefs[i][3]);
+	}
+	hwwrite(vortex->mmio, 0x24528 + i * 0x24, arg_0[0]);
+	hwwrite(vortex->mmio, 0x2452C + i * 0x24, arg_0[1]);
+	hwwrite(vortex->mmio, 0x24530 + i * 0x24, arg_0[2]);
+	hwwrite(vortex->mmio, 0x24534 + i * 0x24, arg_0[3]);
+}
+
+#if 0
+static void
+vortex_XtalkHw_GetLeftEQ(vortex_t * vortex, short *arg_0, short *arg_4,
+			 xtalk_coefs_t coefs)
+{
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		coefs[i][0] = hwread(vortex->mmio, 0x24200 + i * 0x24);
+		coefs[i][1] = hwread(vortex->mmio, 0x24204 + i * 0x24);
+		coefs[i][2] = hwread(vortex->mmio, 0x24208 + i * 0x24);
+		coefs[i][3] = hwread(vortex->mmio, 0x2420c + i * 0x24);
+		coefs[i][4] = hwread(vortex->mmio, 0x24210 + i * 0x24);
+	}
+	*arg_0 = hwread(vortex->mmio, 0x24538) & 0xffff;
+	*arg_4 = hwread(vortex->mmio, 0x2453c) & 0xffff;
+}
+
+static void
+vortex_XtalkHw_GetRightEQ(vortex_t * vortex, short *arg_0, short *arg_4,
+			  xtalk_coefs_t coefs)
+{
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		coefs[i][0] = hwread(vortex->mmio, 0x242b4 + i * 0x24);
+		coefs[i][1] = hwread(vortex->mmio, 0x242b8 + i * 0x24);
+		coefs[i][2] = hwread(vortex->mmio, 0x242bc + i * 0x24);
+		coefs[i][3] = hwread(vortex->mmio, 0x242c0 + i * 0x24);
+		coefs[i][4] = hwread(vortex->mmio, 0x242c4 + i * 0x24);
+	}
+	*arg_0 = hwread(vortex->mmio, 0x24540) & 0xffff;
+	*arg_4 = hwread(vortex->mmio, 0x24544) & 0xffff;
+}
+
+static void
+vortex_XtalkHw_GetLeftXT(vortex_t * vortex, short *arg_0, short *arg_4,
+			 xtalk_coefs_t coefs)
+{
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		coefs[i][0] = hwread(vortex->mmio, 0x24368 + i * 0x24);
+		coefs[i][1] = hwread(vortex->mmio, 0x2436C + i * 0x24);
+		coefs[i][2] = hwread(vortex->mmio, 0x24370 + i * 0x24);
+		coefs[i][3] = hwread(vortex->mmio, 0x24374 + i * 0x24);
+		coefs[i][4] = hwread(vortex->mmio, 0x24378 + i * 0x24);
+	}
+	*arg_0 = hwread(vortex->mmio, 0x24548) & 0xffff;
+	*arg_4 = hwread(vortex->mmio, 0x2454C) & 0xffff;
+}
+
+static void
+vortex_XtalkHw_GetRightXT(vortex_t * vortex, short *arg_0, short *arg_4,
+			  xtalk_coefs_t coefs)
+{
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		coefs[i][0] = hwread(vortex->mmio, 0x2441C + i * 0x24);
+		coefs[i][1] = hwread(vortex->mmio, 0x24420 + i * 0x24);
+		coefs[i][2] = hwread(vortex->mmio, 0x24424 + i * 0x24);
+		coefs[i][3] = hwread(vortex->mmio, 0x24428 + i * 0x24);
+		coefs[i][4] = hwread(vortex->mmio, 0x2442C + i * 0x24);
+	}
+	*arg_0 = hwread(vortex->mmio, 0x24550) & 0xffff;
+	*arg_4 = hwread(vortex->mmio, 0x24554) & 0xffff;
+}
+
+static void
+vortex_XtalkHw_GetLeftEQStates(vortex_t * vortex, xtalk_instate_t arg_0,
+			       xtalk_state_t coefs)
+{
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		coefs[i][0] = hwread(vortex->mmio, 0x24214 + i * 0x24);
+		coefs[i][1] = hwread(vortex->mmio, 0x24218 + i * 0x24);
+		coefs[i][2] = hwread(vortex->mmio, 0x2421C + i * 0x24);
+		coefs[i][3] = hwread(vortex->mmio, 0x24220 + i * 0x24);
+	}
+	arg_0[0] = hwread(vortex->mmio, 0x244F8 + i * 0x24);
+	arg_0[1] = hwread(vortex->mmio, 0x244FC + i * 0x24);
+	arg_0[2] = hwread(vortex->mmio, 0x24500 + i * 0x24);
+	arg_0[3] = hwread(vortex->mmio, 0x24504 + i * 0x24);
+}
+
+static void
+vortex_XtalkHw_GetRightEQStates(vortex_t * vortex, xtalk_instate_t arg_0,
+				xtalk_state_t coefs)
+{
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		coefs[i][0] = hwread(vortex->mmio, 0x242C8 + i * 0x24);
+		coefs[i][1] = hwread(vortex->mmio, 0x242CC + i * 0x24);
+		coefs[i][2] = hwread(vortex->mmio, 0x242D0 + i * 0x24);
+		coefs[i][3] = hwread(vortex->mmio, 0x242D4 + i * 0x24);
+	}
+	arg_0[0] = hwread(vortex->mmio, 0x24508 + i * 0x24);
+	arg_0[1] = hwread(vortex->mmio, 0x2450C + i * 0x24);
+	arg_0[2] = hwread(vortex->mmio, 0x24510 + i * 0x24);
+	arg_0[3] = hwread(vortex->mmio, 0x24514 + i * 0x24);
+}
+
+static void
+vortex_XtalkHw_GetLeftXTStates(vortex_t * vortex, xtalk_instate_t arg_0,
+			       xtalk_state_t coefs)
+{
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		coefs[i][0] = hwread(vortex->mmio, 0x2437C + i * 0x24);
+		coefs[i][1] = hwread(vortex->mmio, 0x24380 + i * 0x24);
+		coefs[i][2] = hwread(vortex->mmio, 0x24384 + i * 0x24);
+		coefs[i][3] = hwread(vortex->mmio, 0x24388 + i * 0x24);
+	}
+	arg_0[0] = hwread(vortex->mmio, 0x24518 + i * 0x24);
+	arg_0[1] = hwread(vortex->mmio, 0x2451C + i * 0x24);
+	arg_0[2] = hwread(vortex->mmio, 0x24520 + i * 0x24);
+	arg_0[3] = hwread(vortex->mmio, 0x24524 + i * 0x24);
+}
+
+static void
+vortex_XtalkHw_GetRightXTStates(vortex_t * vortex, xtalk_instate_t arg_0,
+				xtalk_state_t coefs)
+{
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		coefs[i][0] = hwread(vortex->mmio, 0x24430 + i * 0x24);
+		coefs[i][1] = hwread(vortex->mmio, 0x24434 + i * 0x24);
+		coefs[i][2] = hwread(vortex->mmio, 0x24438 + i * 0x24);
+		coefs[i][3] = hwread(vortex->mmio, 0x2443C + i * 0x24);
+	}
+	arg_0[0] = hwread(vortex->mmio, 0x24528 + i * 0x24);
+	arg_0[1] = hwread(vortex->mmio, 0x2452C + i * 0x24);
+	arg_0[2] = hwread(vortex->mmio, 0x24530 + i * 0x24);
+	arg_0[3] = hwread(vortex->mmio, 0x24534 + i * 0x24);
+}
+
+#endif
+/* Gains */
+
+static void
+vortex_XtalkHw_SetGains(vortex_t * vortex, xtalk_gains_t const gains)
+{
+	int i;
+
+	for (i = 0; i < XTGAINS_SZ; i++) {
+		hwwrite(vortex->mmio, 0x244D0 + (i * 4), gains[i]);
+	}
+}
+
+#if 0
+static void vortex_XtalkHw_GetGains(vortex_t * vortex, xtalk_gains_t gains)
+{
+	int i;
+
+	for (i = 0; i < XTGAINS_SZ; i++)
+		gains[i] = hwread(vortex->mmio, 0x244D0 + i * 4);
+}
+
+#endif
+/* Delay parameters */
+
+static void
+vortex_XtalkHw_SetDelay(vortex_t * vortex, unsigned short right,
+			unsigned short left)
+{
+	int esp0 = 0;
+
+	esp0 &= 0x1FFFFFFF;
+	esp0 |= 0xA0000000;
+	esp0 = (esp0 & 0xffffE0ff) | ((right & 0x1F) << 8);
+	esp0 = (esp0 & 0xfffc1fff) | ((left & 0x1F) << 0xd);
+
+	hwwrite(vortex->mmio, 0x24660, esp0);
+}
+
+static void
+vortex_XtalkHw_SetLeftDline(vortex_t * vortex, xtalk_dline_t const dline)
+{
+	int i;
+
+	for (i = 0; i < 0x20; i++) {
+		hwwrite(vortex->mmio, 0x24000 + (i << 2), dline[i] & 0xffff);
+		hwwrite(vortex->mmio, 0x24080 + (i << 2), dline[i] >> 0x10);
+	}
+}
+
+static void
+vortex_XtalkHw_SetRightDline(vortex_t * vortex, xtalk_dline_t const dline)
+{
+	int i;
+
+	for (i = 0; i < 0x20; i++) {
+		hwwrite(vortex->mmio, 0x24100 + (i << 2), dline[i] & 0xffff);
+		hwwrite(vortex->mmio, 0x24180 + (i << 2), dline[i] >> 0x10);
+	}
+}
+
+#if 0
+static void
+vortex_XtalkHw_GetDelay(vortex_t * vortex, unsigned short *right,
+			unsigned short *left)
+{
+	int esp0;
+
+	esp0 = hwread(vortex->mmio, 0x24660);
+	*right = (esp0 >> 8) & 0x1f;
+	*left = (esp0 >> 0xd) & 0x1f;
+}
+
+static void vortex_XtalkHw_GetLeftDline(vortex_t * vortex, xtalk_dline_t dline)
+{
+	int i;
+
+	for (i = 0; i < 0x20; i++) {
+		dline[i] =
+		    (hwread(vortex->mmio, 0x24000 + (i << 2)) & 0xffff) |
+		    (hwread(vortex->mmio, 0x24080 + (i << 2)) << 0x10);
+	}
+}
+
+static void vortex_XtalkHw_GetRightDline(vortex_t * vortex, xtalk_dline_t dline)
+{
+	int i;
+
+	for (i = 0; i < 0x20; i++) {
+		dline[i] =
+		    (hwread(vortex->mmio, 0x24100 + (i << 2)) & 0xffff) |
+		    (hwread(vortex->mmio, 0x24180 + (i << 2)) << 0x10);
+	}
+}
+
+#endif
+/* Control/Global stuff */
+
+#if 0
+static void vortex_XtalkHw_SetControlReg(vortex_t * vortex, unsigned long ctrl)
+{
+	hwwrite(vortex->mmio, 0x24660, ctrl);
+}
+static void vortex_XtalkHw_GetControlReg(vortex_t * vortex, unsigned long *ctrl)
+{
+	*ctrl = hwread(vortex->mmio, 0x24660);
+}
+#endif
+static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, int sr)
+{
+	int temp;
+
+	temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000;
+	temp = (temp & 0xffffff07) | ((sr & 0x1f) << 3);
+	hwwrite(vortex->mmio, 0x24660, temp);
+}
+
+#if 0
+static void vortex_XtalkHw_GetSampleRate(vortex_t * vortex, int *sr)
+{
+	*sr = (hwread(vortex->mmio, 0x24660) >> 3) & 0x1f;
+}
+
+#endif
+static void vortex_XtalkHw_Enable(vortex_t * vortex)
+{
+	int temp;
+
+	temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000;
+	temp |= 1;
+	hwwrite(vortex->mmio, 0x24660, temp);
+
+}
+
+static void vortex_XtalkHw_Disable(vortex_t * vortex)
+{
+	int temp;
+
+	temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000;
+	temp &= 0xfffffffe;
+	hwwrite(vortex->mmio, 0x24660, temp);
+
+}
+
+static void vortex_XtalkHw_ZeroIO(vortex_t * vortex)
+{
+	int i;
+
+	for (i = 0; i < 20; i++)
+		hwwrite(vortex->mmio, 0x24600 + (i << 2), 0);
+	for (i = 0; i < 4; i++)
+		hwwrite(vortex->mmio, 0x24650 + (i << 2), 0);
+}
+
+static void vortex_XtalkHw_ZeroState(vortex_t * vortex)
+{
+	vortex_XtalkHw_ZeroIO(vortex);	// inlined
+
+	vortex_XtalkHw_SetLeftEQ(vortex, 0, 0, asXtalkCoefsZeros);
+	vortex_XtalkHw_SetRightEQ(vortex, 0, 0, asXtalkCoefsZeros);
+
+	vortex_XtalkHw_SetLeftXT(vortex, 0, 0, asXtalkCoefsZeros);
+	vortex_XtalkHw_SetRightXT(vortex, 0, 0, asXtalkCoefsZeros);
+
+	vortex_XtalkHw_SetGains(vortex, asXtalkGainsZeros);	// inlined
+
+	vortex_XtalkHw_SetDelay(vortex, 0, 0);	// inlined
+
+	vortex_XtalkHw_SetLeftDline(vortex, alXtalkDlineZeros);	// inlined
+	vortex_XtalkHw_SetRightDline(vortex, alXtalkDlineZeros);	// inlined
+	vortex_XtalkHw_SetLeftDline(vortex, alXtalkDlineZeros);	// inlined
+	vortex_XtalkHw_SetRightDline(vortex, alXtalkDlineZeros);	// inlined
+
+	vortex_XtalkHw_SetLeftEQStates(vortex, asXtalkInStateZeros,
+				       asXtalkOutStateZeros);
+	vortex_XtalkHw_SetRightEQStates(vortex, asXtalkInStateZeros,
+					asXtalkOutStateZeros);
+	vortex_XtalkHw_SetLeftXTStates(vortex, asXtalkInStateZeros,
+				       asXtalkOutStateZeros);
+	vortex_XtalkHw_SetRightXTStates(vortex, asXtalkInStateZeros,
+					asXtalkOutStateZeros);
+}
+
+static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex)
+{
+
+	vortex_XtalkHw_SetLeftEQ(vortex, 0, 1, asXtalkCoefsPipe);
+	vortex_XtalkHw_SetRightEQ(vortex, 0, 1, asXtalkCoefsPipe);
+	vortex_XtalkHw_SetLeftXT(vortex, 0, 0, asXtalkCoefsZeros);
+	vortex_XtalkHw_SetRightXT(vortex, 0, 0, asXtalkCoefsZeros);
+
+	vortex_XtalkHw_SetDelay(vortex, 0, 0);	// inlined
+}
+
+static void vortex_XtalkHw_ProgramXtalkWide(vortex_t * vortex)
+{
+
+	vortex_XtalkHw_SetLeftEQ(vortex, sXtalkWideKLeftEq,
+				 sXtalkWideShiftLeftEq, asXtalkWideCoefsLeftEq);
+	vortex_XtalkHw_SetRightEQ(vortex, sXtalkWideKRightEq,
+				  sXtalkWideShiftRightEq,
+				  asXtalkWideCoefsRightEq);
+	vortex_XtalkHw_SetLeftXT(vortex, sXtalkWideKLeftXt,
+				 sXtalkWideShiftLeftXt, asXtalkWideCoefsLeftXt);
+	vortex_XtalkHw_SetRightXT(vortex, sXtalkWideKLeftXt,
+				  sXtalkWideShiftLeftXt,
+				  asXtalkWideCoefsLeftXt);
+
+	vortex_XtalkHw_SetDelay(vortex, wXtalkWideRightDelay, wXtalkWideLeftDelay);	// inlined
+}
+
+static void vortex_XtalkHw_ProgramXtalkNarrow(vortex_t * vortex)
+{
+
+	vortex_XtalkHw_SetLeftEQ(vortex, sXtalkNarrowKLeftEq,
+				 sXtalkNarrowShiftLeftEq,
+				 asXtalkNarrowCoefsLeftEq);
+	vortex_XtalkHw_SetRightEQ(vortex, sXtalkNarrowKRightEq,
+				  sXtalkNarrowShiftRightEq,
+				  asXtalkNarrowCoefsRightEq);
+	vortex_XtalkHw_SetLeftXT(vortex, sXtalkNarrowKLeftXt,
+				 sXtalkNarrowShiftLeftXt,
+				 asXtalkNarrowCoefsLeftXt);
+	vortex_XtalkHw_SetRightXT(vortex, sXtalkNarrowKLeftXt,
+				  sXtalkNarrowShiftLeftXt,
+				  asXtalkNarrowCoefsLeftXt);
+
+	vortex_XtalkHw_SetDelay(vortex, wXtalkNarrowRightDelay, wXtalkNarrowLeftDelay);	// inlined
+}
+
+static void vortex_XtalkHw_ProgramDiamondXtalk(vortex_t * vortex)
+{
+
+	//sDiamondKLeftEq,sDiamondKRightXt,asDiamondCoefsLeftEq
+	vortex_XtalkHw_SetLeftEQ(vortex, sDiamondKLeftEq,
+				 sDiamondShiftLeftEq, asDiamondCoefsLeftEq);
+	vortex_XtalkHw_SetRightEQ(vortex, sDiamondKRightEq,
+				  sDiamondShiftRightEq, asDiamondCoefsRightEq);
+	vortex_XtalkHw_SetLeftXT(vortex, sDiamondKLeftXt,
+				 sDiamondShiftLeftXt, asDiamondCoefsLeftXt);
+	vortex_XtalkHw_SetRightXT(vortex, sDiamondKLeftXt,
+				  sDiamondShiftLeftXt, asDiamondCoefsLeftXt);
+
+	vortex_XtalkHw_SetDelay(vortex, wDiamondRightDelay, wDiamondLeftDelay);	// inlined
+}
+
+static void vortex_XtalkHw_init(vortex_t * vortex)
+{
+	vortex_XtalkHw_ZeroState(vortex);
+}
+
+/* End of file */
--- diff/sound/pci/au88x0/au88x0_xtalk.h	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/au88x0/au88x0_xtalk.h	2004-03-16 09:37:58.513644744 +0000
@@ -0,0 +1,62 @@
+/***************************************************************************
+ *            au88x0_cxtalk.h
+ *
+ *  Wed Nov 19 19:07:17 2003
+ *  Copyright  2003  mjander
+ *  mjander@users.sourceforge.org
+ ****************************************************************************/
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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 Library 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.
+ */
+
+/* The crosstalk canceler supports 5 stereo input channels. The result is 
+   available at one single output route pair (stereo). */
+
+#ifndef _AU88X0_CXTALK_H
+#define _AU88X0_CXTALK_H
+
+#include "au88x0.h"
+
+#define XTDLINE_SZ 32
+#define XTGAINS_SZ 10
+#define XTINST_SZ 4
+
+#define XT_HEADPHONE	1
+#define XT_SPEAKER0		2
+#define XT_SPEAKER1		3
+#define XT_DIAMOND		4
+
+typedef long xtalk_dline_t[XTDLINE_SZ];
+typedef short xtalk_gains_t[XTGAINS_SZ];
+typedef short xtalk_instate_t[XTINST_SZ];
+typedef short xtalk_coefs_t[5][5];
+typedef short xtalk_state_t[5][4];
+
+extern xtalk_gains_t const asXtalkGainsAllChan;
+
+static void vortex_XtalkHw_SetGains(vortex_t * vortex,
+				    xtalk_gains_t const gains);
+static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, int sr);
+static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex);
+static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex);
+static void vortex_XtalkHw_ProgramXtalkWide(vortex_t * vortex);
+static void vortex_XtalkHw_ProgramXtalkNarrow(vortex_t * vortex);
+static void vortex_XtalkHw_ProgramDiamondXtalk(vortex_t * vortex);
+static void vortex_XtalkHw_Enable(vortex_t * vortex);
+static void vortex_XtalkHw_Disable(vortex_t * vortex);
+static void vortex_XtalkHw_init(vortex_t * vortex);
+
+#endif				/* _AU88X0_CXTALK_H */
--- diff/sound/pci/intel8x0m.c	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/intel8x0m.c	2004-03-16 09:37:58.517644136 +0000
@@ -0,0 +1,1507 @@
+/*
+ *   ALSA modem driver for Intel ICH (i8x0) chipsets
+ *
+ *	Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz>
+ *
+ *   This is modified (by Sasha Khapyorsky <sashak@smlink.com>) version
+ *   of ALSA ICH sound driver intel8x0.c .
+ *
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, 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 <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/gameport.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/info.h>
+#include <sound/mpu401.h>
+#define SNDRV_GET_ID
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440 modem");
+MODULE_LICENSE("GPL");
+MODULE_CLASSES("{sound}");
+MODULE_DEVICES("{{Intel,82801AA-ICH},"
+		"{Intel,82901AB-ICH0},"
+		"{Intel,82801BA-ICH2},"
+		"{Intel,82801CA-ICH3},"
+		"{Intel,82801DB-ICH4},"
+		"{Intel,ICH5},"
+	        "{Intel,MX440}}");
+
+
+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 */
+static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+
+MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(index, "Index value for Intel i8x0 modemcard.");
+MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
+MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+MODULE_PARM_DESC(id, "ID string for Intel i8x0 modemcard.");
+MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
+MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(enable, "Enable Intel i8x0 modemcard.");
+MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
+MODULE_PARM(ac97_clock, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect).");
+MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:0");
+
+/*
+ *  Direct registers
+ */
+
+#ifndef PCI_DEVICE_ID_INTEL_82801_6
+#define PCI_DEVICE_ID_INTEL_82801_6     0x2416
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_82901_6
+#define PCI_DEVICE_ID_INTEL_82901_6     0x2426
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_82801BA_6
+#define PCI_DEVICE_ID_INTEL_82801BA_6   0x2446
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_440MX_6
+#define PCI_DEVICE_ID_INTEL_440MX_6     0x7196
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_ICH3_6
+#define PCI_DEVICE_ID_INTEL_ICH3_6	0x2486
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_ICH4_6
+#define PCI_DEVICE_ID_INTEL_ICH4_6	0x24c6
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_ICH5_6
+#define PCI_DEVICE_ID_INTEL_ICH5_6	0x24d6
+#endif
+#ifndef PCI_DEVICE_ID_SI_7013
+#define PCI_DEVICE_ID_SI_7013		0x7013
+#endif
+#if 0
+#ifndef PCI_DEVICE_ID_NVIDIA_MCP_AUDIO
+#define PCI_DEVICE_ID_NVIDIA_MCP_AUDIO	0x01b1
+#endif
+#ifndef PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO
+#define PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO	0x006a
+#endif
+#ifndef PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO
+#define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO	0x00da
+#endif
+#endif
+
+enum { DEVICE_INTEL, DEVICE_SIS, DEVICE_ALI, DEVICE_NFORCE };
+
+#define ICHREG(x) ICH_REG_##x
+
+#define DEFINE_REGSET(name,base) \
+enum { \
+	ICH_REG_##name##_BDBAR	= base + 0x0,	/* dword - buffer descriptor list base address */ \
+	ICH_REG_##name##_CIV	= base + 0x04,	/* byte - current index value */ \
+	ICH_REG_##name##_LVI	= base + 0x05,	/* byte - last valid index */ \
+	ICH_REG_##name##_SR	= base + 0x06,	/* byte - status register */ \
+	ICH_REG_##name##_PICB	= base + 0x08,	/* word - position in current buffer */ \
+	ICH_REG_##name##_PIV	= base + 0x0a,	/* byte - prefetched index value */ \
+	ICH_REG_##name##_CR	= base + 0x0b,	/* byte - control register */ \
+};
+
+/* busmaster blocks */
+DEFINE_REGSET(OFF, 0);		/* offset */
+
+/* values for each busmaster block */
+
+/* LVI */
+#define ICH_REG_LVI_MASK		0x1f
+
+/* SR */
+#define ICH_FIFOE			0x10	/* FIFO error */
+#define ICH_BCIS			0x08	/* buffer completion interrupt status */
+#define ICH_LVBCI			0x04	/* last valid buffer completion interrupt */
+#define ICH_CELV			0x02	/* current equals last valid */
+#define ICH_DCH				0x01	/* DMA controller halted */
+
+/* PIV */
+#define ICH_REG_PIV_MASK		0x1f	/* mask */
+
+/* CR */
+#define ICH_IOCE			0x10	/* interrupt on completion enable */
+#define ICH_FEIE			0x08	/* fifo error interrupt enable */
+#define ICH_LVBIE			0x04	/* last valid buffer interrupt enable */
+#define ICH_RESETREGS			0x02	/* reset busmaster registers */
+#define ICH_STARTBM			0x01	/* start busmaster operation */
+
+
+/* global block */
+#define ICH_REG_GLOB_CNT		0x3c	/* dword - global control */
+#define   ICH_TRIE		0x00000040	/* tertiary resume interrupt enable */
+#define   ICH_SRIE		0x00000020	/* secondary resume interrupt enable */
+#define   ICH_PRIE		0x00000010	/* primary resume interrupt enable */
+#define   ICH_ACLINK		0x00000008	/* AClink shut off */
+#define   ICH_AC97WARM		0x00000004	/* AC'97 warm reset */
+#define   ICH_AC97COLD		0x00000002	/* AC'97 cold reset */
+#define   ICH_GIE		0x00000001	/* GPI interrupt enable */
+#define ICH_REG_GLOB_STA		0x40	/* dword - global status */
+#define   ICH_TRI		0x20000000	/* ICH4: tertiary (AC_SDIN2) resume interrupt */
+#define   ICH_TCR		0x10000000	/* ICH4: tertiary (AC_SDIN2) codec ready */
+#define   ICH_BCS		0x08000000	/* ICH4: bit clock stopped */
+#define   ICH_SPINT		0x04000000	/* ICH4: S/PDIF interrupt */
+#define   ICH_P2INT		0x02000000	/* ICH4: PCM2-In interrupt */
+#define   ICH_M2INT		0x01000000	/* ICH4: Mic2-In interrupt */
+#define   ICH_SAMPLE_CAP	0x00c00000	/* ICH4: sample capability bits (RO) */
+#define   ICH_MULTICHAN_CAP	0x00300000	/* ICH4: multi-channel capability bits (RO) */
+#define   ICH_MD3		0x00020000	/* modem power down semaphore */
+#define   ICH_AD3		0x00010000	/* audio power down semaphore */
+#define   ICH_RCS		0x00008000	/* read completion status */
+#define   ICH_BIT3		0x00004000	/* bit 3 slot 12 */
+#define   ICH_BIT2		0x00002000	/* bit 2 slot 12 */
+#define   ICH_BIT1		0x00001000	/* bit 1 slot 12 */
+#define   ICH_SRI		0x00000800	/* secondary (AC_SDIN1) resume interrupt */
+#define   ICH_PRI		0x00000400	/* primary (AC_SDIN0) resume interrupt */
+#define   ICH_SCR		0x00000200	/* secondary (AC_SDIN1) codec ready */
+#define   ICH_PCR		0x00000100	/* primary (AC_SDIN0) codec ready */
+#define   ICH_MCINT		0x00000080	/* MIC capture interrupt */
+#define   ICH_POINT		0x00000040	/* playback interrupt */
+#define   ICH_PIINT		0x00000020	/* capture interrupt */
+#define   ICH_NVSPINT		0x00000010	/* nforce spdif interrupt */
+#define   ICH_MOINT		0x00000004	/* modem playback interrupt */
+#define   ICH_MIINT		0x00000002	/* modem capture interrupt */
+#define   ICH_GSCI		0x00000001	/* GPI status change interrupt */
+#define ICH_REG_ACC_SEMA		0x44	/* byte - codec write semaphore */
+#define   ICH_CAS		0x01		/* codec access semaphore */
+
+#define ICH_MAX_FRAGS		32		/* max hw frags */
+
+
+/*
+ *  
+ */
+
+enum { ICHD_MDMIN, ICHD_MDMOUT, ICHD_MDMLAST = ICHD_MDMOUT };
+enum { ALID_MDMIN, ALID_MDMOUT, ALID_MDMLAST = ALID_MDMOUT };
+
+#define get_ichdev(substream) (ichdev_t *)(substream->runtime->private_data)
+
+typedef struct {
+	unsigned int ichd;			/* ich device number */
+	unsigned long reg_offset;		/* offset to bmaddr */
+	u32 *bdbar;				/* CPU address (32bit) */
+	unsigned int bdbar_addr;		/* PCI bus address (32bit) */
+	snd_pcm_substream_t *substream;
+	unsigned int physbuf;			/* physical address (32bit) */
+        unsigned int size;
+        unsigned int fragsize;
+        unsigned int fragsize1;
+        unsigned int position;
+        int frags;
+        int lvi;
+        int lvi_frag;
+	int civ;
+	int ack;
+	int ack_reload;
+	unsigned int ack_bit;
+	unsigned int roff_sr;
+	unsigned int roff_picb;
+	unsigned int int_sta_mask;		/* interrupt status mask */
+	unsigned int ali_slot;			/* ALI DMA slot */
+	ac97_t *ac97;
+} ichdev_t;
+
+typedef struct _snd_intel8x0m intel8x0_t;
+#define chip_t intel8x0_t
+
+struct _snd_intel8x0m {
+	unsigned int device_type;
+	char ac97_name[64];
+	char ctrl_name[64];
+
+	int irq;
+
+	unsigned int mmio;
+	unsigned long addr;
+	unsigned long remap_addr;
+	struct resource *res;
+	unsigned int bm_mmio;
+	unsigned long bmaddr;
+	unsigned long remap_bmaddr;
+	struct resource *res_bm;
+
+	struct pci_dev *pci;
+	snd_card_t *card;
+
+	int pcm_devs;
+	snd_pcm_t *pcm[2];
+	ichdev_t ichd[2];
+
+	int in_ac97_init: 1;
+
+	ac97_bus_t *ac97_bus;
+	ac97_t *ac97;
+
+	spinlock_t reg_lock;
+	spinlock_t ac97_lock;
+	
+	struct snd_dma_device dma_dev;
+	struct snd_dma_buffer bdbars;
+	u32 bdbars_count;
+	u32 int_sta_reg;		/* interrupt status register */
+	u32 int_sta_mask;		/* interrupt status mask */
+	unsigned int pcm_pos_shift;
+	
+#ifdef CONFIG_PM
+	int in_suspend;
+#endif
+};
+
+static struct pci_device_id snd_intel8x0m_ids[] = {
+	{ 0x8086, 0x2416, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* 82801AA */
+	{ 0x8086, 0x2426, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* 82901AB */
+	{ 0x8086, 0x2446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* 82801BA */
+	{ 0x8086, 0x2486, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* ICH3 */
+	{ 0x8086, 0x24c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH4 */
+	{ 0x8086, 0x24d6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH5 */
+	{ 0x8086, 0x7196, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* 440MX */
+	{ 0x1022, 0x7446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* AMD768 */
+#if 0
+	/* TODO: support needed */
+	{ 0x1039, 0x7013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_SIS },	/* SI7013 */
+	{ 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 */
+	{ 0x1022, 0x746d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* AMD8111 */
+	{ 0x10b9, 0x5455, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALI },   /* Ali5455 */
+#endif
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, snd_intel8x0m_ids);
+
+/*
+ *  Lowlevel I/O - busmaster
+ */
+
+static u8 igetbyte(intel8x0_t *chip, u32 offset)
+{
+	if (chip->bm_mmio)
+		return readb(chip->remap_bmaddr + offset);
+	else
+		return inb(chip->bmaddr + offset);
+}
+
+static u16 igetword(intel8x0_t *chip, u32 offset)
+{
+	if (chip->bm_mmio)
+		return readw(chip->remap_bmaddr + offset);
+	else
+		return inw(chip->bmaddr + offset);
+}
+
+static u32 igetdword(intel8x0_t *chip, u32 offset)
+{
+	if (chip->bm_mmio)
+		return readl(chip->remap_bmaddr + offset);
+	else
+		return inl(chip->bmaddr + offset);
+}
+
+static void iputbyte(intel8x0_t *chip, u32 offset, u8 val)
+{
+	if (chip->bm_mmio)
+		writeb(val, chip->remap_bmaddr + offset);
+	else
+		outb(val, chip->bmaddr + offset);
+}
+
+static void iputdword(intel8x0_t *chip, u32 offset, u32 val)
+{
+	if (chip->bm_mmio)
+		writel(val, chip->remap_bmaddr + offset);
+	else
+		outl(val, chip->bmaddr + offset);
+}
+
+/*
+ *  Lowlevel I/O - AC'97 registers
+ */
+
+static u16 iagetword(intel8x0_t *chip, u32 offset)
+{
+	if (chip->mmio)
+		return readw(chip->remap_addr + offset);
+	else
+		return inw(chip->addr + offset);
+}
+
+static void iaputword(intel8x0_t *chip, u32 offset, u16 val)
+{
+	if (chip->mmio)
+		writew(val, chip->remap_addr + offset);
+	else
+		outw(val, chip->addr + offset);
+}
+
+/*
+ *  Basic I/O
+ */
+
+/*
+ * access to AC97 codec via normal i/o (for ICH and SIS7013)
+ */
+
+/* return the GLOB_STA bit for the corresponding codec */
+static unsigned int get_ich_codec_bit(intel8x0_t *chip, unsigned int codec)
+{
+	static unsigned int codec_bit[3] = {
+		ICH_PCR, ICH_SCR, ICH_TCR
+	};
+	snd_assert(codec < 3, return ICH_PCR);
+	return codec_bit[codec];
+}
+
+static int snd_intel8x0m_codec_semaphore(intel8x0_t *chip, unsigned int codec)
+{
+	int time;
+	
+	if (codec > 1)
+		return -EIO;
+	codec = get_ich_codec_bit(chip, codec);
+
+	/* codec ready ? */
+	if ((igetdword(chip, ICHREG(GLOB_STA)) & codec) == 0)
+		return -EIO;
+
+	/* Anyone holding a semaphore for 1 msec should be shot... */
+	time = 100;
+      	do {
+      		if (!(igetbyte(chip, ICHREG(ACC_SEMA)) & ICH_CAS))
+      			return 0;
+		udelay(10);
+	} while (time--);
+
+	/* access to some forbidden (non existant) ac97 registers will not
+	 * reset the semaphore. So even if you don't get the semaphore, still
+	 * continue the access. We don't need the semaphore anyway. */
+	snd_printk("codec_semaphore: semaphore is not ready [0x%x][0x%x]\n",
+			igetbyte(chip, ICHREG(ACC_SEMA)), igetdword(chip, ICHREG(GLOB_STA)));
+	iagetword(chip, 0);	/* clear semaphore flag */
+	/* I don't care about the semaphore */
+	return -EBUSY;
+}
+ 
+static void snd_intel8x0_codec_write(ac97_t *ac97,
+				     unsigned short reg,
+				     unsigned short val)
+{
+	intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return);
+	
+	spin_lock(&chip->ac97_lock);
+	if (snd_intel8x0m_codec_semaphore(chip, ac97->num) < 0) {
+		if (! chip->in_ac97_init)
+			snd_printk("codec_write %d: semaphore is not ready for register 0x%x\n", ac97->num, reg);
+	}
+	iaputword(chip, reg + ac97->num * 0x80, val);
+	spin_unlock(&chip->ac97_lock);
+}
+
+static unsigned short snd_intel8x0_codec_read(ac97_t *ac97,
+					      unsigned short reg)
+{
+	intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return ~0);
+	unsigned short res;
+	unsigned int tmp;
+
+	spin_lock(&chip->ac97_lock);
+	if (snd_intel8x0m_codec_semaphore(chip, ac97->num) < 0) {
+		if (! chip->in_ac97_init)
+			snd_printk("codec_read %d: semaphore is not ready for register 0x%x\n", ac97->num, reg);
+		res = 0xffff;
+	} else {
+		res = iagetword(chip, reg + ac97->num * 0x80);
+		if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) {
+			/* reset RCS and preserve other R/WC bits */
+			iputdword(chip, ICHREG(GLOB_STA), tmp & ~(ICH_SRI|ICH_PRI|ICH_TRI|ICH_GSCI));
+			if (! chip->in_ac97_init)
+				snd_printk("codec_read %d: read timeout for register 0x%x\n", ac97->num, reg);
+			res = 0xffff;
+		}
+	}
+	spin_unlock(&chip->ac97_lock);
+	return res;
+}
+
+
+/*
+ * DMA I/O
+ */
+static void snd_intel8x0_setup_periods(intel8x0_t *chip, ichdev_t *ichdev) 
+{
+	int idx;
+	u32 *bdbar = ichdev->bdbar;
+	unsigned long port = ichdev->reg_offset;
+
+	iputdword(chip, port + ICH_REG_OFF_BDBAR, ichdev->bdbar_addr);
+	if (ichdev->size == ichdev->fragsize) {
+		ichdev->ack_reload = ichdev->ack = 2;
+		ichdev->fragsize1 = ichdev->fragsize >> 1;
+		for (idx = 0; idx < (ICH_REG_LVI_MASK + 1) * 2; idx += 4) {
+			bdbar[idx + 0] = cpu_to_le32(ichdev->physbuf);
+			bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */
+						     ichdev->fragsize1 >> chip->pcm_pos_shift);
+			bdbar[idx + 2] = cpu_to_le32(ichdev->physbuf + (ichdev->size >> 1));
+			bdbar[idx + 3] = cpu_to_le32(0x80000000 | /* interrupt on completion */
+						     ichdev->fragsize1 >> chip->pcm_pos_shift);
+		}
+		ichdev->frags = 2;
+	} else {
+		ichdev->ack_reload = ichdev->ack = 1;
+		ichdev->fragsize1 = ichdev->fragsize;
+		for (idx = 0; idx < (ICH_REG_LVI_MASK + 1) * 2; idx += 2) {
+			bdbar[idx + 0] = cpu_to_le32(ichdev->physbuf + (((idx >> 1) * ichdev->fragsize) % ichdev->size));
+			bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */
+						     ichdev->fragsize >> chip->pcm_pos_shift);
+			// printk("bdbar[%i] = 0x%x [0x%x]\n", idx + 0, bdbar[idx + 0], bdbar[idx + 1]);
+		}
+		ichdev->frags = ichdev->size / ichdev->fragsize;
+	}
+	iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi = ICH_REG_LVI_MASK);
+	ichdev->civ = 0;
+	iputbyte(chip, port + ICH_REG_OFF_CIV, 0);
+	ichdev->lvi_frag = ICH_REG_LVI_MASK % ichdev->frags;
+	ichdev->position = 0;
+#if 0
+	printk("lvi_frag = %i, frags = %i, period_size = 0x%x, period_size1 = 0x%x\n",
+			ichdev->lvi_frag, ichdev->frags, ichdev->fragsize, ichdev->fragsize1);
+#endif
+	/* clear interrupts */
+	iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
+}
+
+/*
+ *  Interrupt handler
+ */
+
+static inline void snd_intel8x0_update(intel8x0_t *chip, ichdev_t *ichdev)
+{
+	unsigned long port = ichdev->reg_offset;
+	int civ, i, step;
+	int ack = 0;
+
+	civ = igetbyte(chip, port + ICH_REG_OFF_CIV);
+	if (civ == ichdev->civ) {
+		// snd_printd("civ same %d\n", civ);
+		step = 1;
+		ichdev->civ++;
+		ichdev->civ &= ICH_REG_LVI_MASK;
+	} else {
+		step = civ - ichdev->civ;
+		if (step < 0)
+			step += ICH_REG_LVI_MASK + 1;
+		// if (step != 1)
+		//	snd_printd("step = %d, %d -> %d\n", step, ichdev->civ, civ);
+		ichdev->civ = civ;
+	}
+
+	ichdev->position += step * ichdev->fragsize1;
+	ichdev->position %= ichdev->size;
+	ichdev->lvi += step;
+	ichdev->lvi &= ICH_REG_LVI_MASK;
+	iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi);
+	for (i = 0; i < step; i++) {
+		ichdev->lvi_frag++;
+		ichdev->lvi_frag %= ichdev->frags;
+		ichdev->bdbar[ichdev->lvi * 2] = cpu_to_le32(ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1);
+	// printk("new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n", ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2], ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port), inl(port + 4), inb(port + ICH_REG_OFF_CR));
+		if (--ichdev->ack == 0) {
+			ichdev->ack = ichdev->ack_reload;
+			ack = 1;
+		}
+	}
+	if (ack && ichdev->substream) {
+		spin_unlock(&chip->reg_lock);
+		snd_pcm_period_elapsed(ichdev->substream);
+		spin_lock(&chip->reg_lock);
+	}
+	iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
+}
+
+static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	intel8x0_t *chip = snd_magic_cast(intel8x0_t, dev_id, return IRQ_NONE);
+	ichdev_t *ichdev;
+	unsigned int status;
+	unsigned int i;
+
+	spin_lock(&chip->reg_lock);
+	status = igetdword(chip, chip->int_sta_reg);
+	if ((status & chip->int_sta_mask) == 0) {
+		if (status)
+			iputdword(chip, chip->int_sta_reg, status);
+		spin_unlock(&chip->reg_lock);
+		return IRQ_NONE;
+	}
+
+	for (i = 0; i < chip->bdbars_count; i++) {
+		ichdev = &chip->ichd[i];
+		if (status & ichdev->int_sta_mask)
+			snd_intel8x0_update(chip, ichdev);
+	}
+
+	/* ack them */
+	iputdword(chip, chip->int_sta_reg, status & chip->int_sta_mask);
+	spin_unlock(&chip->reg_lock);
+	
+	return IRQ_HANDLED;
+}
+
+/*
+ *  PCM part
+ */
+
+static int snd_intel8x0_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
+{
+	intel8x0_t *chip = snd_pcm_substream_chip(substream);
+	ichdev_t *ichdev = get_ichdev(substream);
+	unsigned char val = 0;
+	unsigned long port = ichdev->reg_offset;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		val = ICH_IOCE | ICH_STARTBM;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		val = 0;
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		val = ICH_IOCE;
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		val = ICH_IOCE | ICH_STARTBM;
+		break;
+	default:
+		return -EINVAL;
+	}
+	iputbyte(chip, port + ICH_REG_OFF_CR, val);
+	if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+		/* wait until DMA stopped */
+		while (!(igetbyte(chip, port + ichdev->roff_sr) & ICH_DCH)) ;
+		/* reset whole DMA things */
+		iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS);
+	}
+	return 0;
+}
+
+static int snd_intel8x0_hw_params(snd_pcm_substream_t * substream,
+				  snd_pcm_hw_params_t * hw_params)
+{
+	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+}
+
+static int snd_intel8x0_hw_free(snd_pcm_substream_t * substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(snd_pcm_substream_t * substream)
+{
+	intel8x0_t *chip = snd_pcm_substream_chip(substream);
+	ichdev_t *ichdev = get_ichdev(substream);
+	size_t ptr1, ptr;
+
+	ptr1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << chip->pcm_pos_shift;
+	if (ptr1 != 0)
+		ptr = ichdev->fragsize1 - ptr1;
+	else
+		ptr = 0;
+	ptr += ichdev->position;
+	if (ptr >= ichdev->size)
+		return 0;
+	return bytes_to_frames(substream->runtime, ptr);
+}
+
+static int snd_intel8x0m_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
+{
+	ichdev_t *ichdev = get_ichdev(substream);
+	/* hook off/on on start/stop */
+	/* TODO: move it to ac97 controls */
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		snd_ac97_update_bits(ichdev->ac97, AC97_GPIO_STATUS,
+				     AC97_GPIO_LINE1_OH, AC97_GPIO_LINE1_OH);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		snd_ac97_update_bits(ichdev->ac97, AC97_GPIO_STATUS,
+				     AC97_GPIO_LINE1_OH, ~AC97_GPIO_LINE1_OH);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return snd_intel8x0_pcm_trigger(substream,cmd);
+}
+
+static int snd_intel8x0m_pcm_prepare(snd_pcm_substream_t * substream)
+{
+	intel8x0_t *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	ichdev_t *ichdev = get_ichdev(substream);
+
+	ichdev->physbuf = runtime->dma_addr;
+	ichdev->size = snd_pcm_lib_buffer_bytes(substream);
+	ichdev->fragsize = snd_pcm_lib_period_bytes(substream);
+	snd_ac97_write(ichdev->ac97, AC97_LINE1_RATE, runtime->rate);
+	snd_ac97_write(ichdev->ac97, AC97_LINE1_LEVEL, 0);
+	snd_intel8x0_setup_periods(chip, ichdev);
+	return 0;
+}
+
+static snd_pcm_hardware_t snd_intel8x0m_stream =
+{
+	.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_RESUME),
+	.formats =		SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =		SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_KNOT,
+	.rate_min =		8000,
+	.rate_max =		16000,
+	.channels_min =		1,
+	.channels_max =		1,
+	.buffer_bytes_max =	32 * 1024,
+	.period_bytes_min =	32,
+	.period_bytes_max =	32 * 1024,
+	.periods_min =		1,
+	.periods_max =		1024,
+	.fifo_size =		0,
+};
+
+
+static int snd_intel8x0m_pcm_open(snd_pcm_substream_t * substream, ichdev_t *ichdev)
+{
+	static unsigned int rates[] = { 8000,  9600, 12000, 16000 };
+	static snd_pcm_hw_constraint_list_t hw_constraints_rates = {
+		.count = ARRAY_SIZE(rates),
+		.list = rates,
+		.mask = 0,
+	};
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	int err;
+
+	ichdev->substream = substream;
+	runtime->hw = snd_intel8x0m_stream;
+	err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
+	if ( err < 0 )
+		return err;
+	runtime->private_data = ichdev;
+	return 0;
+}
+
+static int snd_intel8x0m_playback_open(snd_pcm_substream_t * substream)
+{
+	intel8x0_t *chip = snd_pcm_substream_chip(substream);
+
+	return snd_intel8x0m_pcm_open(substream, &chip->ichd[ICHD_MDMOUT]);
+}
+
+static int snd_intel8x0m_playback_close(snd_pcm_substream_t * substream)
+{
+	intel8x0_t *chip = snd_pcm_substream_chip(substream);
+
+	chip->ichd[ICHD_MDMOUT].substream = NULL;
+	return 0;
+}
+
+static int snd_intel8x0m_capture_open(snd_pcm_substream_t * substream)
+{
+	intel8x0_t *chip = snd_pcm_substream_chip(substream);
+
+	return snd_intel8x0m_pcm_open(substream, &chip->ichd[ICHD_MDMIN]);
+}
+
+static int snd_intel8x0m_capture_close(snd_pcm_substream_t * substream)
+{
+	intel8x0_t *chip = snd_pcm_substream_chip(substream);
+
+	chip->ichd[ICHD_MDMIN].substream = NULL;
+	return 0;
+}
+
+
+static snd_pcm_ops_t snd_intel8x0m_playback_ops = {
+	.open =		snd_intel8x0m_playback_open,
+	.close =	snd_intel8x0m_playback_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_intel8x0_hw_params,
+	.hw_free =	snd_intel8x0_hw_free,
+	.prepare =	snd_intel8x0m_pcm_prepare,
+	.trigger =	snd_intel8x0m_pcm_trigger,
+	.pointer =	snd_intel8x0_pcm_pointer,
+};
+
+static snd_pcm_ops_t snd_intel8x0m_capture_ops = {
+	.open =		snd_intel8x0m_capture_open,
+	.close =	snd_intel8x0m_capture_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_intel8x0_hw_params,
+	.hw_free =	snd_intel8x0_hw_free,
+	.prepare =	snd_intel8x0m_pcm_prepare,
+	.trigger =	snd_intel8x0m_pcm_trigger,
+	.pointer =	snd_intel8x0_pcm_pointer,
+};
+
+
+struct ich_pcm_table {
+	char *suffix;
+	snd_pcm_ops_t *playback_ops;
+	snd_pcm_ops_t *capture_ops;
+	size_t prealloc_size;
+	size_t prealloc_max_size;
+	int ac97_idx;
+};
+
+static int __devinit snd_intel8x0_pcm1(intel8x0_t *chip, int device, struct ich_pcm_table *rec)
+{
+	snd_pcm_t *pcm;
+	int err;
+	char name[32];
+
+	if (rec->suffix)
+		sprintf(name, "Intel ICH - %s", rec->suffix);
+	else
+		strcpy(name, "Intel ICH");
+	err = snd_pcm_new(chip->card, name, device,
+			  rec->playback_ops ? 1 : 0,
+			  rec->capture_ops ? 1 : 0, &pcm);
+	if (err < 0)
+		return err;
+
+	if (rec->playback_ops)
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, rec->playback_ops);
+	if (rec->capture_ops)
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, rec->capture_ops);
+
+	pcm->private_data = chip;
+	pcm->info_flags = 0;
+	if (rec->suffix)
+		sprintf(pcm->name, "%s - %s", chip->card->shortname, rec->suffix);
+	else
+		strcpy(pcm->name, chip->card->shortname);
+	chip->pcm[device] = pcm;
+
+	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;
+}
+
+static struct ich_pcm_table intel_pcms[] __devinitdata = {
+	{
+		.suffix = "Modem",
+		.playback_ops = &snd_intel8x0m_playback_ops,
+		.capture_ops = &snd_intel8x0m_capture_ops,
+		.prealloc_size = 4 * 1024,
+		.prealloc_max_size = 16 * 1024,
+	},
+};
+
+static int __devinit snd_intel8x0_pcm(intel8x0_t *chip)
+{
+	int i, tblsize, device, err;
+	struct ich_pcm_table *tbl, *rec;
+
+#if 1
+	tbl = intel_pcms;
+	tblsize = 1;
+#else
+	switch (chip->device_type) {
+	case DEVICE_NFORCE:
+		tbl = nforce_pcms;
+		tblsize = ARRAY_SIZE(nforce_pcms);
+		break;
+	case DEVICE_ALI:
+		tbl = ali_pcms;
+		tblsize = ARRAY_SIZE(ali_pcms);
+		break;
+	default:
+		tbl = intel_pcms;
+		tblsize = 2;
+		break;
+	}
+#endif
+	device = 0;
+	for (i = 0; i < tblsize; i++) {
+		rec = tbl + i;
+		if (i > 0 && rec->ac97_idx) {
+			/* activate PCM only when associated AC'97 codec */
+			if (! chip->ichd[rec->ac97_idx].ac97)
+				continue;
+		}
+		err = snd_intel8x0_pcm1(chip, device, rec);
+		if (err < 0)
+			return err;
+		device++;
+	}
+
+	chip->pcm_devs = device;
+	return 0;
+}
+	
+
+/*
+ *  Mixer part
+ */
+
+static void snd_intel8x0_mixer_free_ac97_bus(ac97_bus_t *bus)
+{
+	intel8x0_t *chip = snd_magic_cast(intel8x0_t, bus->private_data, return);
+	chip->ac97_bus = NULL;
+}
+
+static void snd_intel8x0_mixer_free_ac97(ac97_t *ac97)
+{
+	intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return);
+	chip->ac97 = NULL;
+}
+
+
+static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
+{
+	ac97_bus_t bus, *pbus;
+	ac97_t ac97, *x97;
+	int err;
+	unsigned int glob_sta = 0;
+
+	chip->in_ac97_init = 1;
+	memset(&bus, 0, sizeof(bus));
+	bus.private_data = chip;
+	bus.private_free = snd_intel8x0_mixer_free_ac97_bus;
+	if (ac97_clock >= 8000 && ac97_clock <= 48000)
+		bus.clock = ac97_clock;
+	else
+		bus.clock = 48000;
+	
+	memset(&ac97, 0, sizeof(ac97));
+	ac97.private_data = chip;
+	ac97.private_free = snd_intel8x0_mixer_free_ac97;
+
+	glob_sta = igetdword(chip, ICHREG(GLOB_STA));
+	bus.write = snd_intel8x0_codec_write;
+	bus.read = snd_intel8x0_codec_read;
+	bus.vra = 1;
+
+	if ((err = snd_ac97_bus(chip->card, &bus, &pbus)) < 0)
+		goto __err;
+	chip->ac97_bus = pbus;
+	ac97.pci = chip->pci;
+	ac97.num = glob_sta & ICH_SCR ? 1 : 0;
+	if ((err = snd_ac97_mixer(pbus, &ac97, &x97)) < 0) {
+		snd_printk(KERN_ERR "Unable to initialize codec #%d\n", ac97.num);
+		if (ac97.num == 0)
+			goto __err;
+		return err;
+	}
+	chip->ac97 = x97;
+	if(ac97_is_modem(x97) && !chip->ichd[ICHD_MDMIN].ac97 ) {
+		chip->ichd[ICHD_MDMIN].ac97 = x97;
+		chip->ichd[ICHD_MDMOUT].ac97 = x97;
+	}
+
+	chip->in_ac97_init = 0;
+	return 0;
+
+ __err:
+	/* clear the cold-reset bit for the next chance */
+	if (chip->device_type != DEVICE_ALI)
+		iputdword(chip, ICHREG(GLOB_CNT), igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_AC97COLD);
+	return err;
+}
+
+
+/*
+ *
+ */
+
+#define do_delay(chip) do {\
+	set_current_state(TASK_UNINTERRUPTIBLE);\
+	schedule_timeout(1);\
+} while (0)
+
+static int snd_intel8x0m_ich_chip_init(intel8x0_t *chip, int probing)
+{
+	unsigned long end_time;
+	unsigned int cnt, status, nstatus;
+	
+	/* put logic to right state */
+	/* first clear status bits */
+	status = ICH_RCS | ICH_MIINT | ICH_MOINT;
+	cnt = igetdword(chip, ICHREG(GLOB_STA));
+	iputdword(chip, ICHREG(GLOB_STA), cnt & status);
+
+	/* ACLink on, 2 channels */
+	cnt = igetdword(chip, ICHREG(GLOB_CNT));
+	cnt &= ~(ICH_ACLINK);
+	/* finish cold or do warm reset */
+	cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM;
+	iputdword(chip, ICHREG(GLOB_CNT), cnt);
+	end_time = (jiffies + (HZ / 4)) + 1;
+	do {
+		if ((igetdword(chip, ICHREG(GLOB_CNT)) & ICH_AC97WARM) == 0)
+			goto __ok;
+		do_delay(chip);
+	} while (time_after_eq(end_time, jiffies));
+	snd_printk("AC'97 warm reset still in progress? [0x%x]\n", igetdword(chip, ICHREG(GLOB_CNT)));
+	return -EIO;
+
+      __ok:
+	if (probing) {
+		/* wait for any codec ready status.
+		 * Once it becomes ready it should remain ready
+		 * as long as we do not disable the ac97 link.
+		 */
+		end_time = jiffies + HZ;
+		do {
+			status = igetdword(chip, ICHREG(GLOB_STA)) & (ICH_PCR | ICH_SCR | ICH_TCR);
+			if (status)
+				break;
+			do_delay(chip);
+		} while (time_after_eq(end_time, jiffies));
+		if (! status) {
+			/* no codec is found */
+			snd_printk(KERN_ERR "codec_ready: codec is not ready [0x%x]\n", igetdword(chip, ICHREG(GLOB_STA)));
+			return -EIO;
+		}
+
+		/* up to two codecs (modem cannot be tertiary with ICH4) */
+		nstatus = ICH_PCR | ICH_SCR;
+
+		/* wait for other codecs ready status. */
+		end_time = jiffies + HZ / 4;
+		while (status != nstatus && time_after_eq(end_time, jiffies)) {
+			do_delay(chip);
+			status |= igetdword(chip, ICHREG(GLOB_STA)) & nstatus;
+		}
+
+	} else {
+		/* resume phase */
+		status = 0;
+		if (chip->ac97)
+			status |= get_ich_codec_bit(chip, chip->ac97->num);
+		/* wait until all the probed codecs are ready */
+		end_time = jiffies + HZ;
+		do {
+			nstatus = igetdword(chip, ICHREG(GLOB_STA)) & (ICH_PCR | ICH_SCR | ICH_TCR);
+			if (status == nstatus)
+				break;
+			do_delay(chip);
+		} while (time_after_eq(end_time, jiffies));
+	}
+
+      	return 0;
+}
+
+static int snd_intel8x0_chip_init(intel8x0_t *chip, int probing)
+{
+	unsigned int i;
+	int err;
+	
+	if ((err = snd_intel8x0m_ich_chip_init(chip, probing)) < 0)
+		return err;
+	iagetword(chip, 0);	/* clear semaphore flag */
+
+	/* disable interrupts */
+	for (i = 0; i < chip->bdbars_count; i++)
+		iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, 0x00);
+	/* reset channels */
+	for (i = 0; i < chip->bdbars_count; i++)
+		iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS);
+	/* initialize Buffer Descriptor Lists */
+	for (i = 0; i < chip->bdbars_count; i++)
+		iputdword(chip, ICH_REG_OFF_BDBAR + chip->ichd[i].reg_offset, chip->ichd[i].bdbar_addr);
+	return 0;
+}
+
+static int snd_intel8x0_free(intel8x0_t *chip)
+{
+	unsigned int i;
+
+	if (chip->irq < 0)
+		goto __hw_end;
+	/* disable interrupts */
+	for (i = 0; i < chip->bdbars_count; i++)
+		iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, 0x00);
+	/* reset channels */
+	for (i = 0; i < chip->bdbars_count; i++)
+		iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS);
+	/* --- */
+	synchronize_irq(chip->irq);
+      __hw_end:
+	if (chip->bdbars.area)
+		snd_dma_free_pages(&chip->dma_dev, &chip->bdbars);
+	if (chip->remap_addr)
+		iounmap((void *) chip->remap_addr);
+	if (chip->remap_bmaddr)
+		iounmap((void *) chip->remap_bmaddr);
+	if (chip->res) {
+		release_resource(chip->res);
+		kfree_nocheck(chip->res);
+	}
+	if (chip->res_bm) {
+		release_resource(chip->res_bm);
+		kfree_nocheck(chip->res_bm);
+	}
+	if (chip->irq >= 0)
+		free_irq(chip->irq, (void *)chip);
+	snd_magic_kfree(chip);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * power management
+ */
+static void intel8x0_suspend(intel8x0_t *chip)
+{
+	snd_card_t *card = chip->card;
+	int i;
+
+	if (chip->in_suspend ||
+	    card->power_state == SNDRV_CTL_POWER_D3hot)
+		return;
+
+	chip->in_suspend = 1;
+	for (i = 0; i < chip->pcm_devs; i++)
+		snd_pcm_suspend_all(chip->pcm[i]);
+	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+}
+
+static void intel8x0_resume(intel8x0_t *chip)
+{
+	snd_card_t *card = chip->card;
+
+	if (! chip->in_suspend ||
+	    card->power_state == SNDRV_CTL_POWER_D0)
+		return;
+
+	pci_enable_device(chip->pci);
+	pci_set_master(chip->pci);
+	snd_intel8x0_chip_init(chip, 0);
+	if (chip->ac97)
+		snd_ac97_resume(chip->ac97);
+
+	chip->in_suspend = 0;
+	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+}
+
+static int snd_intel8x0m_suspend(struct pci_dev *dev, u32 state)
+{
+	intel8x0_t *chip = snd_magic_cast(intel8x0_t, pci_get_drvdata(dev), return -ENXIO);
+	intel8x0_suspend(chip);
+	return 0;
+}
+static int snd_intel8x0m_resume(struct pci_dev *dev)
+{
+	intel8x0_t *chip = snd_magic_cast(intel8x0_t, pci_get_drvdata(dev), return -ENXIO);
+	intel8x0_resume(chip);
+	return 0;
+}
+
+/* callback */
+static int snd_intel8x0_set_power_state(snd_card_t *card, unsigned int power_state)
+{
+	intel8x0_t *chip = snd_magic_cast(intel8x0_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:
+		intel8x0_resume(chip);
+		break;
+	case SNDRV_CTL_POWER_D3hot:
+	case SNDRV_CTL_POWER_D3cold:
+		intel8x0_suspend(chip);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+#endif /* CONFIG_PM */
+
+static void snd_intel8x0m_proc_read(snd_info_entry_t * entry,
+				   snd_info_buffer_t * buffer)
+{
+	intel8x0_t *chip = snd_magic_cast(intel8x0_t, entry->private_data, return);
+	unsigned int tmp;
+
+	snd_iprintf(buffer, "Intel8x0m\n\n");
+	if (chip->device_type == DEVICE_ALI)
+		return;
+	tmp = igetdword(chip, ICHREG(GLOB_STA));
+	snd_iprintf(buffer, "Global control        : 0x%08x\n", igetdword(chip, ICHREG(GLOB_CNT)));
+	snd_iprintf(buffer, "Global status         : 0x%08x\n", tmp);
+	snd_iprintf(buffer, "AC'97 codecs ready    :%s%s%s%s\n",
+			tmp & ICH_PCR ? " primary" : "",
+			tmp & ICH_SCR ? " secondary" : "",
+			tmp & ICH_TCR ? " tertiary" : "",
+			(tmp & (ICH_PCR | ICH_SCR | ICH_TCR)) == 0 ? " none" : "");
+}
+
+static void __devinit snd_intel8x0m_proc_init(intel8x0_t * chip)
+{
+	snd_info_entry_t *entry;
+
+	if (! snd_card_proc_new(chip->card, "intel8x0m", &entry))
+		snd_info_set_text_ops(entry, chip, 1024, snd_intel8x0m_proc_read);
+}
+
+static int snd_intel8x0_dev_free(snd_device_t *device)
+{
+	intel8x0_t *chip = snd_magic_cast(intel8x0_t, device->device_data, return -ENXIO);
+	return snd_intel8x0_free(chip);
+}
+
+struct ich_reg_info {
+	unsigned int int_sta_mask;
+	unsigned int offset;
+};
+
+static int __devinit snd_intel8x0m_create(snd_card_t * card,
+					 struct pci_dev *pci,
+					 unsigned long device_type,
+					 intel8x0_t ** r_intel8x0)
+{
+	intel8x0_t *chip;
+	int err;
+	unsigned int i;
+	unsigned int int_sta_masks;
+	ichdev_t *ichdev;
+	static snd_device_ops_t ops = {
+		.dev_free =	snd_intel8x0_dev_free,
+	};
+	static struct ich_reg_info intel_regs[2] = {
+		{ ICH_MIINT, 0 },
+		{ ICH_MOINT, 0x10 },
+	};
+	struct ich_reg_info *tbl;
+
+	*r_intel8x0 = NULL;
+
+	if ((err = pci_enable_device(pci)) < 0)
+		return err;
+
+	chip = snd_magic_kcalloc(intel8x0_t, 0, GFP_KERNEL);
+	if (chip == NULL)
+		return -ENOMEM;
+	spin_lock_init(&chip->reg_lock);
+	spin_lock_init(&chip->ac97_lock);
+	chip->device_type = device_type;
+	chip->card = card;
+	chip->pci = pci;
+	chip->irq = -1;
+	snd_intel8x0m_proc_init(chip);
+	sprintf(chip->ac97_name, "%s - AC'97", card->shortname);
+	sprintf(chip->ctrl_name, "%s - Controller", card->shortname);
+	if (device_type == DEVICE_ALI) {
+		/* ALI5455 has no ac97 region */
+		chip->bmaddr = pci_resource_start(pci, 0);
+		if ((chip->res_bm = request_region(chip->bmaddr, 256, chip->ctrl_name)) == NULL) {
+			snd_printk("unable to grab ports 0x%lx-0x%lx\n", chip->bmaddr, chip->bmaddr + 256 - 1);
+			snd_intel8x0_free(chip);
+			return -EBUSY;
+		}
+		goto port_inited;
+	}
+
+	if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) {	/* ICH4 and Nforce */
+		chip->mmio = 1;
+		chip->addr = pci_resource_start(pci, 2);
+		if ((chip->res = request_mem_region(chip->addr, 512, chip->ac97_name)) == NULL) {
+			snd_printk("unable to grab I/O memory 0x%lx-0x%lx\n", chip->addr, chip->addr + 512 - 1);
+			snd_intel8x0_free(chip);
+			return -EBUSY;
+		}
+		chip->remap_addr = (unsigned long) ioremap_nocache(chip->addr, 512);
+		if (chip->remap_addr == 0) {
+			snd_printk("AC'97 space ioremap problem\n");
+			snd_intel8x0_free(chip);
+			return -EIO;
+		}
+	} else {
+		chip->addr = pci_resource_start(pci, 0);
+		if ((chip->res = request_region(chip->addr, 256, chip->ac97_name)) == NULL) {
+			snd_printk("unable to grab ports 0x%lx-0x%lx\n", chip->addr, chip->addr + 256 - 1);
+			snd_intel8x0_free(chip);
+			return -EBUSY;
+		}
+	}
+	if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) {	/* ICH4 */
+		chip->bm_mmio = 1;
+		chip->bmaddr = pci_resource_start(pci, 3);
+		if ((chip->res_bm = request_mem_region(chip->bmaddr, 256, chip->ctrl_name)) == NULL) {
+			snd_printk("unable to grab I/O memory 0x%lx-0x%lx\n", chip->bmaddr, chip->bmaddr + 512 - 1);
+			snd_intel8x0_free(chip);
+			return -EBUSY;
+		}
+		chip->remap_bmaddr = (unsigned long) ioremap_nocache(chip->bmaddr, 256);
+		if (chip->remap_bmaddr == 0) {
+			snd_printk("Controller space ioremap problem\n");
+			snd_intel8x0_free(chip);
+			return -EIO;
+		}
+	} else {
+		chip->bmaddr = pci_resource_start(pci, 1);
+		if ((chip->res_bm = request_region(chip->bmaddr, 128, chip->ctrl_name)) == NULL) {
+			snd_printk("unable to grab ports 0x%lx-0x%lx\n", chip->bmaddr, chip->bmaddr + 128 - 1);
+			snd_intel8x0_free(chip);
+			return -EBUSY;
+		}
+	}
+
+ port_inited:
+	if (request_irq(pci->irq, snd_intel8x0_interrupt, SA_INTERRUPT|SA_SHIRQ, card->shortname, (void *)chip)) {
+		snd_printk("unable to grab IRQ %d\n", pci->irq);
+		snd_intel8x0_free(chip);
+		return -EBUSY;
+	}
+	chip->irq = pci->irq;
+	pci_set_master(pci);
+	synchronize_irq(chip->irq);
+
+	/* initialize offsets */
+	chip->bdbars_count = 2;
+	tbl = intel_regs;
+
+	for (i = 0; i < chip->bdbars_count; i++) {
+		ichdev = &chip->ichd[i];
+		ichdev->ichd = i;
+		ichdev->reg_offset = tbl[i].offset;
+		ichdev->int_sta_mask = tbl[i].int_sta_mask;
+		if (device_type == DEVICE_SIS) {
+			/* SiS 7013 swaps the registers */
+			ichdev->roff_sr = ICH_REG_OFF_PICB;
+			ichdev->roff_picb = ICH_REG_OFF_SR;
+		} else {
+			ichdev->roff_sr = ICH_REG_OFF_SR;
+			ichdev->roff_picb = ICH_REG_OFF_PICB;
+		}
+		if (device_type == DEVICE_ALI)
+			ichdev->ali_slot = (ichdev->reg_offset - 0x40) / 0x10;
+	}
+	/* SIS7013 handles the pcm data in bytes, others are in words */
+	chip->pcm_pos_shift = (device_type == DEVICE_SIS) ? 0 : 1;
+
+	/* allocate buffer descriptor lists */
+	/* the start of each lists must be aligned to 8 bytes */
+	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);
+	if (snd_dma_alloc_pages(&chip->dma_dev, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, &chip->bdbars) < 0) {
+		snd_intel8x0_free(chip);
+		return -ENOMEM;
+	}
+	/* tables must be aligned to 8 bytes here, but the kernel pages
+	   are much bigger, so we don't care (on i386) */
+	int_sta_masks = 0;
+	for (i = 0; i < chip->bdbars_count; i++) {
+		ichdev = &chip->ichd[i];
+		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 = ICH_REG_GLOB_STA;
+	chip->int_sta_mask = int_sta_masks;
+
+	if ((err = snd_intel8x0_chip_init(chip, 1)) < 0) {
+		snd_intel8x0_free(chip);
+		return err;
+	}
+
+#ifdef CONFIG_PM
+	card->set_power_state = snd_intel8x0_set_power_state;
+	card->power_state_private_data = chip;
+#endif
+
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
+		snd_intel8x0_free(chip);
+		return err;
+	}
+
+	snd_card_set_dev(card, &pci->dev);
+
+	*r_intel8x0 = chip;
+	return 0;
+}
+
+static struct shortname_table {
+	unsigned int id;
+	const char *s;
+} shortnames[] __devinitdata = {
+	{ PCI_DEVICE_ID_INTEL_82801_6, "Intel 82801AA-ICH" },
+	{ PCI_DEVICE_ID_INTEL_82901_6, "Intel 82901AB-ICH0" },
+	{ PCI_DEVICE_ID_INTEL_82801BA_6, "Intel 82801BA-ICH2" },
+	{ PCI_DEVICE_ID_INTEL_440MX_6, "Intel 440MX" },
+	{ PCI_DEVICE_ID_INTEL_ICH3_6, "Intel 82801CA-ICH3" },
+	{ PCI_DEVICE_ID_INTEL_ICH4_6, "Intel 82801DB-ICH4" },
+	{ PCI_DEVICE_ID_INTEL_ICH5_6, "Intel ICH5" },
+	{ 0x7446, "AMD AMD768" },
+#if 0
+	{ PCI_DEVICE_ID_SI_7013, "SiS SI7013" },
+	{ PCI_DEVICE_ID_NVIDIA_MCP_AUDIO, "NVidia nForce" },
+	{ PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO, "NVidia nForce2" },
+	{ PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO, "NVidia nForce3" },
+	{ 0x5455, "ALi M5455" },
+	{ 0x746d, "AMD AMD8111" },
+#endif
+	{ 0, 0 },
+};
+
+static int __devinit snd_intel8x0m_probe(struct pci_dev *pci,
+					const struct pci_device_id *pci_id)
+{
+	static int dev;
+	snd_card_t *card;
+	intel8x0_t *chip;
+	int err;
+	struct shortname_table *name;
+
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+	if (card == NULL)
+		return -ENOMEM;
+
+	switch (pci_id->driver_data) {
+	case DEVICE_NFORCE:
+		strcpy(card->driver, "NFORCE");
+		break;
+	default:
+		strcpy(card->driver, "ICH");
+		break;
+	}
+
+	strcpy(card->shortname, "Intel ICH");
+	for (name = shortnames; name->id; name++) {
+		if (pci->device == name->id) {
+			strcpy(card->shortname, name->s);
+			break;
+		}
+	}
+	strcat(card->shortname," Modem");
+
+	if ((err = snd_intel8x0m_create(card, pci, pci_id->driver_data, &chip)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	if ((err = snd_intel8x0_mixer(chip, ac97_clock[dev])) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	if ((err = snd_intel8x0_pcm(chip)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	
+	sprintf(card->longname, "%s at 0x%lx, irq %i",
+		card->shortname, chip->addr, chip->irq);
+
+	if ((err = snd_card_register(card)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	pci_set_drvdata(pci, chip);
+	dev++;
+	return 0;
+}
+
+static void __devexit snd_intel8x0m_remove(struct pci_dev *pci)
+{
+	intel8x0_t *chip = snd_magic_cast(intel8x0_t, pci_get_drvdata(pci), return);
+	if (chip)
+		snd_card_free(chip->card);
+	pci_set_drvdata(pci, NULL);
+}
+
+static struct pci_driver driver = {
+	.name = "Intel ICH Modem",
+	.id_table = snd_intel8x0m_ids,
+	.probe = snd_intel8x0m_probe,
+	.remove = __devexit_p(snd_intel8x0m_remove),
+#ifdef CONFIG_PM
+	.suspend = snd_intel8x0m_suspend,
+	.resume = snd_intel8x0m_resume,
+#endif
+};
+
+
+static int __init alsa_card_intel8x0m_init(void)
+{
+	int err;
+
+        if ((err = pci_module_init(&driver)) < 0) {
+#ifdef MODULE
+		printk(KERN_ERR "Intel ICH modemcard not found or device busy\n");
+#endif
+                return err;
+        }
+
+        return 0;
+}
+
+static void __exit alsa_card_intel8x0m_exit(void)
+{
+	pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_intel8x0m_init)
+module_exit(alsa_card_intel8x0m_exit)
+
+#ifndef MODULE
+
+/* format is: snd-intel8x0=enable,index,id,ac97_clock,mpu_port,joystick */
+
+static int __init alsa_card_intel8x0m_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 &&
+	       get_option(&str,&ac97_clock[nr_dev]) == 2
+	       );
+	nr_dev++;
+	return 1;
+}
+
+__setup("snd-intel8x0m=", alsa_card_intel8x0m_setup);
+
+#endif /* ifndef MODULE */
--- diff/sound/pci/mixart/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ source/sound/pci/mixart/Makefile	2004-03-16 09:37:58.517644136 +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 00:00:00.000000000 +0000
+++ source/sound/pci/mixart/mixart.c	2004-03-16 09:37:58.521643528 +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 00:00:00.000000000 +0000
+++ source/sound/pci/mixart/mixart.h	2004-03-16 09:37:58.522643376 +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 00:00:00.000000000 +0000
+++ source/sound/pci/mixart/mixart_core.c	2004-03-16 09:37:58.523643224 +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, (void *)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 00:00:00.000000000 +0000
+++ source/sound/pci/mixart/mixart_core.h	2004-03-16 09:37:58.525642920 +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 00:00:00.000000000 +0000
+++ source/sound/pci/mixart/mixart_hwdep.c	2004-03-16 09:37:58.527642616 +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 00:00:00.000000000 +0000
+++ source/sound/pci/mixart/mixart_hwdep.h	2004-03-16 09:37:58.527642616 +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 00:00:00.000000000 +0000
+++ source/sound/pci/mixart/mixart_mixer.c	2004-03-16 09:37:58.531642008 +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 00:00:00.000000000 +0000
+++ source/sound/pci/mixart/mixart_mixer.h	2004-03-16 09:37:58.531642008 +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 00:00:00.000000000 +0000
+++ source/sound/pcmcia/pdaudiocf/Makefile	2004-03-16 09:37:58.532641856 +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 00:00:00.000000000 +0000
+++ source/sound/pcmcia/pdaudiocf/pdaudiocf.c	2004-03-16 09:37:58.533641704 +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 00:00:00.000000000 +0000
+++ source/sound/pcmcia/pdaudiocf/pdaudiocf.h	2004-03-16 09:37:58.534641552 +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 00:00:00.000000000 +0000
+++ source/sound/pcmcia/pdaudiocf/pdaudiocf_core.c	2004-03-16 09:37:58.535641400 +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 00:00:00.000000000 +0000
+++ source/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c	2004-03-16 09:37:58.536641248 +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 00:00:00.000000000 +0000
+++ source/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c	2004-03-16 09:37:58.537641096 +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/brlvger.txt	2002-10-16 03:27:49.000000000 +0000
+++ source/Documentation/usb/brlvger.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1,36 +0,0 @@
-Kernel Driver for the Tieman Voyager Braille Display (USB)
-
-Authors:
-Stéphane Dalton <sdalton@videotron.ca>
-Stéphane Doyon  <s.doyon@videotron.ca>
-
-Version 0.8, April 17, 2002
-
-The brlvger driver supports a Braille display (aka Braille terminal)
-model Voyager from Tieman.
-
-The driver has been in heavy use for about six months now (as of April
-17th 2002) by a very few users (about 3-4), who say it has worked very
-well for them.
-
-We have tested it with a Voyager 44, but it should also support
-the Voyager 70.
-
-This driver implements a character device which allows userspace programs
-access to the braille displays raw functions. You still need a userspace
-program to perform the screen-review functions and control the
-display. Get BRLTTY from http://mielke.cc/brltty/ (version 2.99.8 or
-later). It has a Voyager driver which interfaces with this kernel driver.
-
-The interface is through a character device, major 180, minor 128, called
-"brlvger" under devfs.
-
-Many thanks to the Tieman people: Corand van Strien, Ivar Illing, Daphne
-Vogelaar and Ingrid Vogel. They provided us with a Braille display (as
-well as programming information) so that we could write this driver. They
-replaced the display when it broke and they answered our technical
-questions. It is very motivating when companies take an interest in such
-projects and are so supportive.
-
-Thanks to Andor Demarteau <ademarte@students.cs.uu.nl> who got this whole
-project started and beta-tested all our early buggy attempts.
--- diff/Documentation/usb/scanner.txt	2004-03-11 10:20:19.000000000 +0000
+++ source/Documentation/usb/scanner.txt	1970-01-01 00:00:00.000000000 +0000
@@ -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 03:29:02.000000000 +0000
+++ source/arch/i386/lib/iodebug.c	1970-01-01 00:00:00.000000000 +0000
@@ -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/ia32/vsyscall.S	2003-06-30 09:07:29.000000000 +0000
+++ source/arch/x86_64/ia32/vsyscall.S	1970-01-01 00:00:00.000000000 +0000
@@ -1,172 +0,0 @@
-/*
- * Code for the vsyscall page.  This version uses the syscall instruction.
- */
-
-#include <asm/ia32_unistd.h>
-#include <asm/offset.h>
-
-	.text
-	.section .text.vsyscall,"ax"
-	.globl __kernel_vsyscall
-	.type __kernel_vsyscall,@function
-__kernel_vsyscall:
-.LSTART_vsyscall:
-	push	%ebp
-.Lpush_ebp:
-	movl	%ecx, %ebp
-	syscall
-	popl	%ebp
-.Lpop_ebp:
-	ret
-.LEND_vsyscall:
-	.size __kernel_vsyscall,.-.LSTART_vsyscall
-
-	.section .text.sigreturn,"ax"
-	.balign 32
-	.globl __kernel_sigreturn
-	.type __kernel_sigreturn,@function
-__kernel_sigreturn:
-.LSTART_sigreturn:
-	popl %eax
-	movl $__NR_ia32_sigreturn, %eax
-	syscall
-.LEND_sigreturn:
-	.size __kernel_sigreturn,.-.LSTART_sigreturn
-
-	.section .text.rtsigreturn,"ax"
-	.balign 32
-	.globl __kernel_rt_sigreturn
-	.type __kernel_rt_sigreturn,@function
-__kernel_rt_sigreturn:
-.LSTART_rt_sigreturn:
-	movl $__NR_ia32_rt_sigreturn, %eax
-	syscall
-.LEND_rt_sigreturn:
-	.size __kernel_rt_sigreturn,.-.LSTART_rt_sigreturn
-
-	.section .eh_frame,"a",@progbits
-.LSTARTFRAME:
-	.long .LENDCIE-.LSTARTCIE
-.LSTARTCIE:
-	.long 0			/* CIE ID */
-	.byte 1			/* Version number */
-	.string "zR"		/* NUL-terminated augmentation string */
-	.uleb128 1		/* Code alignment factor */
-	.sleb128 -4		/* Data alignment factor */
-	.byte 8			/* Return address register column */
-	.uleb128 1		/* Augmentation value length */
-	.byte 0x1b		/* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */
-	.byte 0x0c		/* DW_CFA_def_cfa */
-	.uleb128 4
-	.uleb128 4
-	.byte 0x88		/* DW_CFA_offset, column 0x8 */
-	.uleb128 1
-	.align 4
-.LENDCIE:
-
-	.long .LENDFDE1-.LSTARTFDE1	/* Length FDE */
-.LSTARTFDE1:
-	.long .LSTARTFDE1-.LSTARTFRAME	/* CIE pointer */
-	.long .LSTART_vsyscall-.	/* PC-relative start address */
-	.long .LEND_vsyscall-.LSTART_vsyscall
-	.uleb128 0			/* Augmentation length */
-	/* What follows are the instructions for the table generation.
-	   We have to record all changes of the stack pointer.  */
-	.byte 0x40 + .Lpush_ebp-.LSTART_vsyscall /* DW_CFA_advance_loc */
-	.byte 0x0e		/* DW_CFA_def_cfa_offset */
-	.uleb128 8
-	.byte 0x85, 0x02	/* DW_CFA_offset %ebp -8 */
-	.byte 0x40 + .Lpop_ebp-.Lpush_ebp /* DW_CFA_advance_loc */
-	.byte 0xc5		/* DW_CFA_restore %ebp */
-	.byte 0x0e		/* DW_CFA_def_cfa_offset */
-	.uleb128 4
-	.align 4
-.LENDFDE1:
-
-	.long .LENDFDE2-.LSTARTFDE2	/* Length FDE */
-.LSTARTFDE2:
-	.long .LSTARTFDE2-.LSTARTFRAME	/* CIE pointer */
-	/* HACK: The dwarf2 unwind routines will subtract 1 from the
-	   return address to get an address in the middle of the
-	   presumed call instruction.  Since we didn't get here via
-	   a call, we need to include the nop before the real start
-	   to make up for it.  */
-	.long .LSTART_sigreturn-1-.	/* PC-relative start address */
-	.long .LEND_sigreturn-.LSTART_sigreturn+1
-	.uleb128 0			/* Augmentation length */
-	/* What follows are the instructions for the table generation.
-	   We record the locations of each register saved.  This is
-	   complicated by the fact that the "CFA" is always assumed to
-	   be the value of the stack pointer in the caller.  This means
-	   that we must define the CFA of this body of code to be the
-	   saved value of the stack pointer in the sigcontext.  Which
-	   also means that there is no fixed relation to the other 
-	   saved registers, which means that we must use DW_CFA_expression
-	   to compute their addresses.  It also means that when we 
-	   adjust the stack with the popl, we have to do it all over again.  */
-
-#define do_cfa_expr(offset)						\
-	.byte 0x0f;			/* DW_CFA_def_cfa_expression */	\
-	.uleb128 1f-0f;			/*   length */			\
-0:	.byte 0x74;			/*     DW_OP_breg4 */		\
-	.sleb128 offset;		/*      offset */		\
-	.byte 0x06;			/*     DW_OP_deref */		\
-1:
-
-#define do_expr(regno, offset)						\
-	.byte 0x10;			/* DW_CFA_expression */		\
-	.uleb128 regno;			/*   regno */			\
-	.uleb128 1f-0f;			/*   length */			\
-0:	.byte 0x74;			/*     DW_OP_breg4 */		\
-	.sleb128 offset;		/*       offset */		\
-1:
-
-	do_cfa_expr(IA32_SIGCONTEXT_esp+4)
-	do_expr(0, IA32_SIGCONTEXT_eax+4)
-	do_expr(1, IA32_SIGCONTEXT_ecx+4)
-	do_expr(2, IA32_SIGCONTEXT_edx+4)
-	do_expr(3, IA32_SIGCONTEXT_ebx+4)
-	do_expr(5, IA32_SIGCONTEXT_ebp+4)
-	do_expr(6, IA32_SIGCONTEXT_esi+4)
-	do_expr(7, IA32_SIGCONTEXT_edi+4)
-	do_expr(8, IA32_SIGCONTEXT_eip+4)
-
-	.byte 0x42	/* DW_CFA_advance_loc 2 -- nop; popl eax. */
-
-	do_cfa_expr(IA32_SIGCONTEXT_esp)
-	do_expr(0, IA32_SIGCONTEXT_eax)
-	do_expr(1, IA32_SIGCONTEXT_ecx)
-	do_expr(2, IA32_SIGCONTEXT_edx)
-	do_expr(3, IA32_SIGCONTEXT_ebx)
-	do_expr(5, IA32_SIGCONTEXT_ebp)
-	do_expr(6, IA32_SIGCONTEXT_esi)
-	do_expr(7, IA32_SIGCONTEXT_edi)
-	do_expr(8, IA32_SIGCONTEXT_eip)
-
-	.align 4
-.LENDFDE2:
-
-	.long .LENDFDE3-.LSTARTFDE3	/* Length FDE */
-.LSTARTFDE3:
-	.long .LSTARTFDE3-.LSTARTFRAME	/* CIE pointer */
-	/* HACK: See above wrt unwind library assumptions.  */
-	.long .LSTART_rt_sigreturn-1-.	/* PC-relative start address */
-	.long .LEND_rt_sigreturn-.LSTART_rt_sigreturn+1
-	.uleb128 0			/* Augmentation */
-	/* What follows are the instructions for the table generation.
-	   We record the locations of each register saved.  This is
-	   slightly less complicated than the above, since we don't
-	   modify the stack pointer in the process.  */
-
-	do_cfa_expr(IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_esp)
-	do_expr(0, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_eax)
-	do_expr(1, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ecx)
-	do_expr(2, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_edx)
-	do_expr(3, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ebx)
-	do_expr(5, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ebp)
-	do_expr(6, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_esi)
-	do_expr(7, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_edi)
-	do_expr(8, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_eip)
-
-	.align 4
-.LENDFDE3:
--- diff/arch/x86_64/lib/iodebug.c	2002-10-16 03:28:24.000000000 +0000
+++ source/arch/x86_64/lib/iodebug.c	1970-01-01 00:00:00.000000000 +0000
@@ -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-11 10:20:23.000000000 +0000
+++ source/drivers/char/ipmi/ipmi_kcs_intf.c	1970-01-01 00:00:00.000000000 +0000
@@ -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 00:00:00.000000000 +0000
@@ -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 17:54:27.000000000 +0000
+++ source/drivers/input/misc/gsc_ps2.c	1970-01-01 00:00:00.000000000 +0000
@@ -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/net/wan/lmc/lmc_ver.h	2003-09-30 14:46:16.000000000 +0000
+++ source/drivers/net/wan/lmc/lmc_ver.h	1970-01-01 00:00:00.000000000 +0000
@@ -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/drivers/usb/misc/brlvger.c	2003-10-27 09:20:44.000000000 +0000
+++ source/drivers/usb/misc/brlvger.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1016 +0,0 @@
-/*
- *      Tieman Voyager braille display USB driver.
- *
- *      Copyright 2001-2002 Stephane Dalton <sdalton@videotron.ca>
- *                      and Stéphane Doyon  <s.doyon@videotron.ca>
- *            Maintained by Stéphane Doyon  <s.doyon@videotron.ca>.
- */
-/*
- *  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
- */
-/* History:
- * 0.8 April 2002: Integration into the kernel tree.
- * 0.7 October 2001: First public release as a module, distributed with
- *     the BRLTTY package (beta versions around 2.99y).
- */
-
-#define DRIVER_VERSION "v0.8"
-#define DATE "April 2002"
-#define DRIVER_AUTHOR \
-	"Stephane Dalton <sdalton@videotron.ca> " \
-	"and Stéphane Doyon <s.doyon@videotron.ca>"
-#define DRIVER_DESC "Tieman Voyager braille display USB driver for Linux 2.4"
-#define DRIVER_SHORTDESC "Voyager"
-
-#define BANNER \
-	KERN_INFO DRIVER_SHORTDESC " " DRIVER_VERSION " (" DATE ")\n" \
-	KERN_INFO "   by " DRIVER_AUTHOR "\n"
-
-static const char longbanner[] = {
-	DRIVER_DESC ", " DRIVER_VERSION " (" DATE "), by " DRIVER_AUTHOR
-};
-
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <asm/uaccess.h>
-#include <asm/atomic.h>
-#include <linux/poll.h>
-#include <linux/brlvger.h>
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
-
-/* Module parameters */
-
-static int debug = 1;
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "Debug level, 0-3");
-
-static int write_repeats = 2;
-MODULE_PARM(write_repeats, "i");
-MODULE_PARM_DESC(write_repeats, "Hack: repetitions for command to "
-		 "display braille pattern");
-		 /* to get rid of weird extra dots (perhaps only on
-		    early hardware versions?) */
-
-static int stall_tries = 3;
-MODULE_PARM(stall_tries, "i");
-MODULE_PARM_DESC(stall_tries, "Hack: retransmits of stalled USB "
-		 "control messages");
-                 /* broken early hardware versions? */
-
-#define BRLVGER_RAW_VOLTAGE 89
-/* from 0->300V to 255->200V, we are told 265V is normal operating voltage,
-   but we don't know the scale. Assuming it is linear. */
-static int raw_voltage = BRLVGER_RAW_VOLTAGE;
-MODULE_PARM(raw_voltage, "i");
-MODULE_PARM_DESC(raw_voltage, "Parameter for the call to SET_DISPLAY_VOLTAGE");
-
-
-/* protocol and display type defines */
-#define MAX_BRLVGER_CELLS 72
-#define MAX_INTERRUPT_DATA 8
-/* control message request types */
-#define BRLVGER_READ_REQ 0xC2
-#define BRLVGER_WRITE_REQ 0x42
-/* control message request codes */
-#define BRLVGER_SET_DISPLAY_ON 0
-#define BRLVGER_SET_DISPLAY_VOLTAGE 1
-#define BRLVGER_GET_SERIAL 3
-#define BRLVGER_GET_HWVERSION 4
-#define BRLVGER_GET_FWVERSION 5
-#define BRLVGER_GET_LENGTH 6
-#define BRLVGER_SEND_BRAILLE 7
-#define BRLVGER_BEEP 9
-#if 0 /* not used and not sure they're working */
-#define BRLVGER_GET_DISPLAY_VOLTAGE 2
-#define BRLVGER_GET_CURRENT 8
-#endif
-
-/* Prototypes */
-static int brlvger_probe (struct usb_interface *intf,
-			  const struct usb_device_id *id);
-static void brlvger_disconnect(struct usb_interface *intf);
-static int brlvger_open(struct inode *inode, struct file *file);
-static int brlvger_release(struct inode *inode, struct file *file);
-static ssize_t brlvger_write(struct file *file, const char __user *buffer,
-			     size_t count, loff_t *pos);
-static ssize_t brlvger_read(struct file *file, char __user *buffer,
-			    size_t count, loff_t *unused_pos);
-static int brlvger_ioctl(struct inode *inode, struct file *file,
-			 unsigned cmd, unsigned long arg);
-static unsigned brlvger_poll(struct file *file, poll_table *wait);
-static loff_t brlvger_llseek(struct file * file, loff_t offset, int orig);
-static void intr_callback(struct urb *urb, struct pt_regs *regs);
-struct brlvger_priv;
-static int brlvger_get_hw_version(struct brlvger_priv *priv,
-				  unsigned char *verbuf);
-static int brlvger_get_fw_version(struct brlvger_priv *priv,
-				  unsigned char *buf);
-static int brlvger_get_serial(struct brlvger_priv *priv,
-			      unsigned char *buf);
-static int brlvger_get_display_length(struct brlvger_priv *priv);
-static int brlvger_set_display_on_off(struct brlvger_priv *priv, __u16 on);
-static int brlvger_beep(struct brlvger_priv *priv, __u16 duration);
-static int brlvger_set_display_voltage(struct brlvger_priv *priv,
-				       __u16 voltage);
-static int mycontrolmsg(const char *funcname,
-                        struct brlvger_priv *priv, unsigned pipe_dir,
-                        __u8 request, __u8 requesttype, __u16 value,
-                        __u16 index, void *data, __u16 size);
-
-#define controlmsg(priv,pipe_dir,a,b,c,d,e,f) \
-     mycontrolmsg(__FUNCTION__, priv, pipe_dir, \
-                  a,b,c,d,e,f)
-#define sndcontrolmsg(priv,a,b,c,d,e,f) \
-    controlmsg(priv, 0, a,b,c,d,e,f)
-#define rcvcontrolmsg(priv,a,b,c,d,e,f) \
-    controlmsg(priv, USB_DIR_IN, a,b,c,d,e,f)
-
-/* ----------------------------------------------------------------------- */
-
-/* Data */
-
-/* key event queue size */
-#define MAX_INTERRUPT_BUFFER 10
-
-/* private state */
-struct brlvger_priv {
-	struct usb_device   *dev; /* USB device handle */
-	struct usb_endpoint_descriptor *in_interrupt;
-	struct urb *intr_urb;
-
-	int subminor; /* which minor dev #? */
-
-	unsigned char hwver[BRLVGER_HWVER_SIZE]; /* hardware version */
-	unsigned char fwver[BRLVGER_FWVER_SIZE]; /* firmware version */
-	unsigned char serialnum[BRLVGER_SERIAL_SIZE];
-
-	int llength; /* logical length */
-	int plength; /* physical length */
-
-	__u8 obuf[MAX_BRLVGER_CELLS];
-	__u8 intr_buff[MAX_INTERRUPT_DATA];
-	__u8 event_queue[MAX_INTERRUPT_BUFFER][MAX_INTERRUPT_DATA];
-	atomic_t intr_idx, read_idx;
-	spinlock_t intr_idx_lock; /* protects intr_idx */
-	wait_queue_head_t read_wait;
-
-	int opened;
-	struct semaphore open_sem; /* protects ->opened */
-	struct semaphore dev_sem; /* protects ->dev */
-};
-
-/* Globals */
-
-/* For blocking open */
-static DECLARE_WAIT_QUEUE_HEAD(open_wait);
-
-/* Some print macros */
-#ifdef dbg
-#undef dbg
-#endif
-#ifdef info
-#undef info
-#endif
-#ifdef err
-#undef err
-#endif
-#define info(args...) \
-    ({ printk(KERN_INFO "Voyager: " args); \
-       printk("\n"); })
-#define err(args...) \
-    ({ printk(KERN_ERR "Voyager: " args); \
-       printk("\n"); })
-#define dbgprint(fmt, args...) \
-    ({ printk(KERN_DEBUG "Voyager: %s: " fmt, __FUNCTION__ , ##args); \
-       printk("\n"); })
-#define dbg(args...) \
-    ({ if(debug >= 1) dbgprint(args); })
-#define dbg2(args...) \
-    ({ if(debug >= 2) dbgprint(args); })
-#define dbg3(args...) \
-    ({ if(debug >= 3) dbgprint(args); })
-
-/* ----------------------------------------------------------------------- */
-
-/* Driver registration */
-
-static struct usb_device_id brlvger_ids [] = {
-	{ USB_DEVICE(0x0798, 0x0001) },
-	{ }                     /* Terminating entry */
-};
-MODULE_DEVICE_TABLE (usb, brlvger_ids);
-
-static struct file_operations brlvger_fops =
-{
-	.owner =	THIS_MODULE,
-	.llseek =	brlvger_llseek,
-	.read =		brlvger_read,
-	.write =	brlvger_write,
-	.ioctl =	brlvger_ioctl,
-	.open =		brlvger_open,
-	.release =	brlvger_release,
-	.poll =		brlvger_poll,
-};
-
-static struct usb_class_driver brlvger_class = {
-	.name =		"usb/brlvger%d",
-	.fops =		&brlvger_fops,
-	.mode =		S_IFCHR | S_IRUSR |S_IWUSR | S_IRGRP | S_IWGRP,
-	.minor_base =	BRLVGER_MINOR,
-};
-
-static struct usb_driver brlvger_driver =
-{
-	.owner =	THIS_MODULE,
-	.name =		"brlvger",
-	.probe =	brlvger_probe,
-	.disconnect =	brlvger_disconnect,
-	.id_table =	brlvger_ids,
-};
-
-static int
-__init brlvger_init (void)
-{
-	int retval;
-	printk(BANNER);
-
-	if(stall_tries < 1 || write_repeats < 1)
-	  return -EINVAL;
-
-	retval = usb_register(&brlvger_driver);
-	if (retval) {
-		err("USB registration failed");
-		goto out;
-	}
-
-out:
-	return retval;
-}
-
-static void
-__exit brlvger_cleanup (void)
-{
-	usb_deregister (&brlvger_driver);
-	dbg("Driver unregistered");
-}
-
-module_init (brlvger_init);
-module_exit (brlvger_cleanup);
-
-/* ----------------------------------------------------------------------- */
-
-/* Probe and disconnect functions */
-
-static int
-brlvger_probe (struct usb_interface *intf,
-	       const struct usb_device_id *id)
-{
-	struct usb_device *dev = interface_to_usbdev(intf);
-	struct brlvger_priv *priv = NULL;
-	int retval;
-	struct usb_endpoint_descriptor *endpoint;
-	struct usb_host_interface *actifsettings;
-	/* protects against reentrance: once we've found a free slot
-	   we reserve it.*/
-	static DECLARE_MUTEX(reserve_sem);
-
-	actifsettings = dev->actconfig->interface[0]->altsetting;
-
-	if( dev->descriptor.bNumConfigurations != 1
-			|| dev->config->desc.bNumInterfaces != 1 
-			|| actifsettings->desc.bNumEndpoints != 1 ) {
-		err ("Bogus braille display config info");
-		return -ENODEV;
-	}
-
-	endpoint = &actifsettings->endpoint [0].desc;
-	if (!(endpoint->bEndpointAddress & 0x80) ||
-		((endpoint->bmAttributes & 3) != 0x03)) {
-		err ("Bogus braille display config info, wrong endpoints");
-		return -ENODEV;
-	}
-
-	down(&reserve_sem);
-
-	retval = usb_register_dev(intf, &brlvger_class);
-	if (retval) {
-		err("Not able to get a minor for this device.");
-		goto error;
-	}
-
-	if( !(priv = kmalloc (sizeof *priv, GFP_KERNEL)) ){
-		err("No more memory");
-		goto error;
-	}
-
-	memset(priv, 0, sizeof(*priv));
-	atomic_set(&priv->intr_idx, 0);
-	atomic_set(&priv->read_idx, MAX_INTERRUPT_BUFFER-1);
-	spin_lock_init(&priv->intr_idx_lock);
-	init_waitqueue_head(&priv->read_wait);
-	/* opened is memset'ed to 0 */
-	init_MUTEX(&priv->open_sem);
-	init_MUTEX(&priv->dev_sem);
-
-	priv->subminor = intf->minor;
-
-	/* we found a interrupt in endpoint */
-	priv->in_interrupt = endpoint;
-
-	priv->dev = dev;
-
-	if(brlvger_get_hw_version(priv, priv->hwver) <0) {
-		err("Unable to get hardware version");
-		goto error;
-	}
-	dbg("Hw ver %d.%d", priv->hwver[0], priv->hwver[1]);
-	if(brlvger_get_fw_version(priv, priv->fwver) <0) {
-		err("Unable to get firmware version");
-		goto error;
-	}
-	dbg("Fw ver: %s", priv->fwver);
-
-	if(brlvger_get_serial(priv, priv->serialnum) <0) {
-		err("Unable to get serial number");
-		goto error;
-	}
-	dbg("Serial number: %s", priv->serialnum);
-
-	if( (priv->llength = brlvger_get_display_length(priv)) <0 ){
-		err("Unable to get display length");
-		goto error;
-	}
-	switch(priv->llength) {
-	case 48:
-		priv->plength = 44;
-		break;
-	case 72:
-		priv->plength = 70;
-		break;
-	default:
-		err("Unsupported display length: %d", priv->llength);
-		goto error;
-	};
-	dbg("Display length: %d", priv->plength);
-
-	usb_set_intfdata (intf, priv);
-	info( "Braille display %d is device major %d minor %d",
-				intf->minor, USB_MAJOR, BRLVGER_MINOR + intf->minor);
-
-	/* Tell anyone waiting on a blocking open */
-	wake_up_interruptible(&open_wait);
-
-	goto out;
-
- error:
-	if(priv) {
-		kfree( priv );
-		priv = NULL;
-	}
-
- out:
-	up(&reserve_sem);
-	if (priv) {
-		usb_set_intfdata (intf, priv);
-		return 0;
-	}
-	return -EIO;
-}
-
-static void
-brlvger_disconnect(struct usb_interface *intf)
-{
-	struct brlvger_priv *priv = usb_get_intfdata (intf);
-	int r;
-
-	usb_set_intfdata (intf, NULL);
-	if(priv){
-		info("Display %d disconnecting", priv->subminor);
-
-		usb_deregister_dev(intf, &brlvger_class);
-
-		down(&priv->open_sem);
-		down(&priv->dev_sem);
-		if(priv->opened) {
-			/* Disable interrupts */
-			if((r = usb_unlink_urb(priv->intr_urb)) <0)
-				err("usb_unlink_urb returns %d", r);
-			usb_free_urb(priv->intr_urb);
-			/* mark device as dead and prevent control
-			   messages to it */
-			priv->dev = NULL;
-			/* Tell anyone hung up on a read that it
-			   won't be coming */
-			wake_up_interruptible(&priv->read_wait);
-			up(&priv->dev_sem);
-			up(&priv->open_sem);
-		}else
-			/* no corresponding up()s */
-			kfree(priv);
-	}
-}
-
-/* ----------------------------------------------------------------------- */
-
-/* fops implementation */
-
-static int
-brlvger_open(struct inode *inode, struct file *file)
-{
-	int devnum = iminor(inode);
-	struct usb_interface *intf = NULL;
-	struct brlvger_priv *priv = NULL;
-	int n, ret;
-
-	if (devnum < 0)
-		return -ENXIO;
-
-	n = devnum - BRLVGER_MINOR;
-
-	do {
-		intf = usb_find_interface(&brlvger_driver, devnum);
-		if (!intf) {
-			if (file->f_flags & O_NONBLOCK) {
-				dbg3("Failing non-blocking open: "
-				     "device %d not connected", n);
-				return -EAGAIN;
-			}
-			/* Blocking open. One global wait queue will
-			   suffice. We wait until a device for the selected
-			   minor is connected. */
-			dbg2("Waiting for device %d to be connected", n);
-			ret = wait_event_interruptible(open_wait,
-						       (intf = usb_find_interface(&brlvger_driver, devnum)));
-			if (ret) {
-				dbg2("Interrupted wait for device %d", n);
-				return ret;
-			}
-		}
-	} while(!intf);
-	priv = usb_get_intfdata(intf);
-
-	/* We grabbed an existing device. */
-	if(down_interruptible(&priv->open_sem))
-		return -ERESTARTSYS;
-
-	/* Only one process can open each device, no sharing. */
-	ret = -EBUSY;
-	if(priv->opened)
-		goto out;
-
-	dbg("Opening display %d", priv->subminor);
-
-	/* Setup interrupt handler for receiving key input */
-	priv->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if(!priv->intr_urb) {
-		err("Unable to allocate URB");
-		goto out;
-	}
-	usb_fill_int_urb( priv->intr_urb, priv->dev,
-			usb_rcvintpipe(priv->dev,
-				       priv->in_interrupt->bEndpointAddress),
-			priv->intr_buff, sizeof(priv->intr_buff),
-			intr_callback, priv, priv->in_interrupt->bInterval);
-	if((ret = usb_submit_urb(priv->intr_urb, GFP_KERNEL)) <0){
-		err("Error %d while submitting URB", ret);
-		goto out;
-	}
-
-	/* Set voltage */
-	if(brlvger_set_display_voltage(priv, raw_voltage) <0) {
-		err("Unable to set voltage");
-		goto out;
-	}
-
-	/* Turn display on */
-	if((ret = brlvger_set_display_on_off(priv, 1)) <0) {
-		err("Error %d while turning display on", ret);
-		goto out;
-	}
-
-	/* Mark as opened, so disconnect cannot free priv. */
-	priv->opened = 1;
-
-	file->private_data = priv;
-
-	ret = 0;
-	goto out;
-
- out:
-	up(&priv->open_sem);
-	return ret;
-}
-
-static int
-brlvger_release(struct inode *inode, struct file *file)
-{
-	struct brlvger_priv *priv = file->private_data;
-	int r;
-
-	/* Turn display off. Safe even if disconnected. */
-	brlvger_set_display_on_off(priv, 0);
-
-	/* mutex with disconnect and with open */
-	down(&priv->open_sem);
-
-	if(!priv->dev) {
-		dbg("Releasing disconnected device %d", priv->subminor);
-		/* no up(&priv->open_sem) */
-		kfree(priv);
-	}else{
-		dbg("Closing display %d", priv->subminor);
-		/* Disable interrupts */
-		if((r = usb_unlink_urb(priv->intr_urb)) <0)
-			err("usb_unlink_urb returns %d", r);
-		usb_free_urb(priv->intr_urb);
-		priv->opened = 0;
-		up(&priv->open_sem);
-	}
-
-	return 0;
-}
-
-static ssize_t
-brlvger_write(struct file *file, const char __user *buffer,
-	      size_t count, loff_t *pos)
-{
-	struct brlvger_priv *priv = file->private_data;
-	char buf[MAX_BRLVGER_CELLS];
-	int ret;
-	size_t rs;
-	loff_t off;
-	__u16 written;
-
-	if(!priv->dev)
-		return -ENOLINK;
-
-	off = *pos;
-
-	if(off > priv->plength)
-		return -ESPIPE;;
-
-	rs = priv->plength - off;
-
-	if(count > rs)
-		count = rs;
-	written = count;
-
-	if (copy_from_user (buf, buffer, count ) )
-		return -EFAULT;
-
-	memset(priv->obuf, 0xaa, sizeof(priv->obuf));
-
-	/* Firmware supports multiples of 8cells, so some cells are absent
-	   and for some reason there actually are holes! euurkkk! */
-
-	if( priv->plength == 44 ) {
-		/* Two ghost cells at the beginning of the display, plus
-		   two more after the sixth physical cell. */
-		if(off > 5) {
-			off +=4;
-			memcpy(priv->obuf, buf, count);
-		}else{
-			int firstpart = 6 - off;
-			
-#ifdef WRITE_DEBUG
-			dbg3("off: %lld, rs: %d, count: %d, firstpart: %d",
-			     off, rs, count, firstpart);
-#endif
-
-			firstpart = (firstpart < count) ? firstpart : count;
-
-#ifdef WRITE_DEBUG
-			dbg3("off: %lld", off);
-			dbg3("firstpart: %d", firstpart);
-#endif
-
-			memcpy(priv->obuf, buf, firstpart);
-
-			if(firstpart != count) {
-				int secondpart = count - firstpart;
-#ifdef WRITE_DEBUG
-				dbg3("secondpart: %d", secondpart);
-#endif
-
-				memcpy(priv->obuf+(firstpart+2),
-				       buf+firstpart, secondpart);
-				written +=2;
-			}
-
-			off +=2;
-
-#ifdef WRITE_DEBUG
-			dbg3("off: %lld, rs: %d, count: %d, firstpart: %d, "
-				"written: %d", 	off, rs, count, firstpart, written);
-#endif
-		}
-	}else{
-		/* Two ghost cells at the beginningg of the display. */
-		memcpy(priv->obuf, buf, count);
-		off += 2;
-	}
-
-	{
-		int repeat = write_repeats;
-		/* Dirty hack: sometimes some of the dots are wrong and somehow
-		   right themselves if the command is repeated. */
-		while(repeat--) {
-			ret = sndcontrolmsg(priv,
-				BRLVGER_SEND_BRAILLE, BRLVGER_WRITE_REQ, 0,
-				off, priv->obuf, written);
-			if(ret <0)
-				return ret;
-		}
-	}
-
-	return count;
-}
-
-static int
-read_index(struct brlvger_priv *priv)
-{
-	int intr_idx, read_idx;
-
-	read_idx = atomic_read(&priv->read_idx);
-	read_idx = ++read_idx == MAX_INTERRUPT_BUFFER ? 0 : read_idx;
-
-	intr_idx = atomic_read(&priv->intr_idx);
-
-	return(read_idx == intr_idx ? -1 : read_idx);
-}
-
-static ssize_t
-brlvger_read(struct file *file, char __user *buffer,
-	     size_t count, loff_t *unused_pos)
-{
-	struct brlvger_priv *priv = file->private_data;
-	int read_idx;
-
-	if(count != MAX_INTERRUPT_DATA)
-		return -EINVAL;
-
-	if(!priv->dev)
-		return -ENOLINK;
-
-	if((read_idx = read_index(priv)) == -1) {
-		/* queue empty */
-		if (file->f_flags & O_NONBLOCK)
-			return -EAGAIN;
-		else{
-			int r = wait_event_interruptible(priv->read_wait,
-							 (!priv->dev || (read_idx = read_index(priv)) != -1));
-			if(!priv->dev)
-				return -ENOLINK;
-			if(r)
-				return r;
-			if(read_idx == -1)
-				/* should not happen */
-				return 0;
-		}
-	}
-
-	if (copy_to_user (buffer, priv->event_queue[read_idx], count) )
-		return( -EFAULT);
-
-	atomic_set(&priv->read_idx, read_idx);
-	/* Multiple opens are not allowed. Yet on SMP, two processes could
-	   read at the same time (on a shared file descriptor); then it is not
-	   deterministic whether or not they will get duplicates of a key
-	   event. */
-	return MAX_INTERRUPT_DATA;
-}
-
-static int
-brlvger_ioctl(struct inode *inode, struct file *file,
-	      unsigned cmd, unsigned long arg)
-{
-	struct brlvger_priv *priv = file->private_data;
-
-	if(!priv->dev)
-		return -ENOLINK;
-
-	switch(cmd) {
-	case BRLVGER_GET_INFO: {
-		struct brlvger_info vi;
-
-		memset(&vi, 0, sizeof(vi));
-		strlcpy(vi.driver_version, DRIVER_VERSION,
-			sizeof(vi.driver_version));
-		strlcpy(vi.driver_banner, longbanner,
-			sizeof(vi.driver_banner));
-
-		vi.display_length = priv->plength;
-		
-		memcpy(&vi.hwver, priv->hwver, BRLVGER_HWVER_SIZE);
-		memcpy(&vi.fwver, priv->fwver, BRLVGER_FWVER_SIZE);
-		memcpy(&vi.serialnum, priv->serialnum, BRLVGER_SERIAL_SIZE);
-
-		if(copy_to_user((void __user *)arg, &vi, sizeof(vi)))
-			return -EFAULT;
-		return 0;
-	}
-	case BRLVGER_DISPLAY_ON:
-		return brlvger_set_display_on_off(priv, 1);
-	case BRLVGER_DISPLAY_OFF:
-		return brlvger_set_display_on_off(priv, 0);
-	case BRLVGER_BUZZ: {
-		__u16 duration;
-		if(get_user(duration, (__u16 *)arg))
-			return -EFAULT;
-		return brlvger_beep(priv, duration);
-	}
-
-#if 0 /* Underlying commands don't seem to work for some reason; not clear if
-	 we'd want to export these anyway. */
-	case BRLVGER_SET_VOLTAGE: {
-		__u16 voltage;
-		if(get_user(voltage, (__u16 *)arg))
-			return -EFAULT;
-		return brlvger_set_display_voltage(priv, voltage);
-	}
-	case BRLVGER_GET_VOLTAGE: {
-		__u8 voltage;
-		int r = brlvger_get_display_voltage(priv);
-		if(r <0)
-			return r;
-		voltage = r;
-		if(put_user(voltage, (__u8 *)arg))
-			return -EFAULT;
-		return 0;
-	}
-#endif
-	default:
-		return -EINVAL;
-	};
-}
-
-static loff_t
-brlvger_llseek(struct file *file, loff_t offset, int orig)
-{
-	struct brlvger_priv *priv = file->private_data;
-
-	if(!priv->dev)
-		return -ENOLINK;
-
-	switch (orig) {
-		case 0:
-			/*  nothing to do */
-			break;
-		case 1:
-			offset +=file->f_pos;
-			break;
-		case 2:
-			offset += priv->plength;
-		default:
-			return -EINVAL;
-	}
-
-	if((offset >= priv->plength) || (offset < 0))
-		return -EINVAL;
-
-	return (file->f_pos = offset);
-}
-
-static unsigned
-brlvger_poll(struct file *file, poll_table *wait) 
-{
-	struct brlvger_priv *priv = file->private_data;
-
-	if(!priv->dev)
-		return POLLERR | POLLHUP;
-
-	poll_wait(file, &priv->read_wait, wait);
-
-	if(!priv->dev)
-		return POLLERR | POLLHUP;
-	if(read_index(priv) != -1)
-		return POLLIN | POLLRDNORM;
-
-	return 0;
-}
-
-static void
-intr_callback(struct urb *urb, struct pt_regs *regs)
-{
-	struct brlvger_priv *priv = urb->context;
-	int intr_idx, read_idx;
-	int status;
-
-	switch (urb->status) {
-	case 0:
-		/* success */
-		break;
-	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;
-	}
-
-	read_idx = atomic_read(&priv->read_idx);
-	spin_lock(&priv->intr_idx_lock);
-	intr_idx = atomic_read(&priv->intr_idx);
-	if(read_idx == intr_idx) {
-		dbg2("Queue full, dropping braille display input");
-		spin_unlock(&priv->intr_idx_lock);
-		goto exit;	/* queue full */
-	}
-
-	memcpy(priv->event_queue[intr_idx], urb->transfer_buffer,
-	       MAX_INTERRUPT_DATA);
-
-	intr_idx = (++intr_idx == MAX_INTERRUPT_BUFFER)? 0 : intr_idx;
-	atomic_set(&priv->intr_idx, intr_idx);
-	spin_unlock(&priv->intr_idx_lock);
-
-	wake_up_interruptible(&priv->read_wait);
-
-exit:
-	status = usb_submit_urb (urb, GFP_ATOMIC);
-	if (status)
-		err ("%s - usb_submit_urb failed with result %d",
-		     __FUNCTION__, status);
-}
-
-/* ----------------------------------------------------------------------- */
-
-/* Hardware access functions */
-
-static int
-mycontrolmsg(const char *funcname,
-	     struct brlvger_priv *priv, unsigned pipe_dir,
-	     __u8 request, __u8 requesttype, __u16 value,
-	     __u16 index, void *data, __u16 size)
-{
-	int ret=0, tries = stall_tries;
-
-	/* Make sure the device was not disconnected */
-	if(down_interruptible(&priv->dev_sem))
-		return -ERESTARTSYS;
-	if(!priv->dev) {
-		up(&priv->dev_sem);
-		return -ENOLINK;
-	}
-
-	/* Dirty hack for retransmission: stalls and fails all the time
-	   without this on the hardware we tested. */
-	while(tries--) {
-		ret = usb_control_msg(priv->dev,
-		    usb_sndctrlpipe(priv->dev,0) |pipe_dir,
-		    request, requesttype, value,
-		    index, data, size,
-		    HZ);
-		if(ret != -EPIPE)
-			break;
-		dbg2("Stalled, remaining %d tries", tries);
-	}
-	up(&priv->dev_sem);
-	if(ret <0) {
-		err("%s: usb_control_msg returns %d",
-				funcname, ret);
-		return -EIO;
-	}
-	return 0;
-}
-
-static int
-brlvger_get_hw_version(struct brlvger_priv *priv, unsigned char *verbuf)
-{
-	return rcvcontrolmsg(priv,
-	    BRLVGER_GET_HWVERSION, BRLVGER_READ_REQ, 0,
-	    0, verbuf, BRLVGER_HWVER_SIZE);
-	/* verbuf should be 2 bytes */
-}
-
-static int
-brlvger_get_fw_version(struct brlvger_priv *priv, unsigned char *buf)
-{
-	unsigned char rawbuf[(BRLVGER_FWVER_SIZE-1)*2+2];
-	int i, len;
-	int r = rcvcontrolmsg(priv,
-			      BRLVGER_GET_FWVERSION, BRLVGER_READ_REQ, 0,
-			      0, rawbuf, sizeof(rawbuf));
-	if(r<0)
-		return r;
-
-	/* If I guess correctly: succession of 16bit words, the string is
-           formed of the first byte of each of these words. First byte in
-           buffer indicates total length of data; not sure what second byte is
-           for. */
-	len = rawbuf[0]-2;
-	if(len<0)
-		len = 0;
-	else if(len+1 > BRLVGER_FWVER_SIZE)
-		len = BRLVGER_FWVER_SIZE-1;
-	for(i=0; i<len; i++)
-		buf[i] = rawbuf[2+2*i];
-	buf[i] = 0;
-	return 0;
-}
-
-static int
-brlvger_get_serial(struct brlvger_priv *priv, unsigned char *buf)
-{
-	unsigned char rawserial[BRLVGER_SERIAL_BIN_SIZE];
-	int i;
-	int r = rcvcontrolmsg(priv,
-			      BRLVGER_GET_SERIAL, BRLVGER_READ_REQ, 0,
-			      0, rawserial, sizeof(rawserial));
-	if(r<0)
-		return r;
-
-	for(i=0; i<BRLVGER_SERIAL_BIN_SIZE; i++) {
-#define NUM_TO_HEX(n) (((n)>9) ? (n)+'A' : (n)+'0')
-		buf[2*i] = NUM_TO_HEX(rawserial[i] >>4);
-		buf[2*i+1] = NUM_TO_HEX(rawserial[i] &0xf);
-	}
-	buf[2*i] = 0;
-	return 0;
-}
-
-static int
-brlvger_get_display_length(struct brlvger_priv *priv)
-{
-	unsigned char data[2];
-	int ret = rcvcontrolmsg(priv,
-	    BRLVGER_GET_LENGTH, BRLVGER_READ_REQ, 0,
-	    0, data, 2);
-	if(ret<0)
-		return ret;
-	return data[1];
-}
-
-static int
-brlvger_beep(struct brlvger_priv *priv, __u16 duration)
-{
-	return sndcontrolmsg(priv,
-	    BRLVGER_BEEP, BRLVGER_WRITE_REQ, duration,
-	    0, NULL, 0);
-}
-
-static int
-brlvger_set_display_on_off(struct brlvger_priv *priv, __u16 on)
-{
-	dbg2("Turning display %s", ((on) ? "on" : "off"));
-	return sndcontrolmsg(priv,
-	    BRLVGER_SET_DISPLAY_ON,	BRLVGER_WRITE_REQ, on,
-	    0, NULL, 0);
-}
-
-static int
-brlvger_set_display_voltage(struct brlvger_priv *priv, __u16 voltage)
-{
-	dbg("SET_DISPLAY_VOLTAGE to %u", voltage);
-        return sndcontrolmsg(priv,
-	     BRLVGER_SET_DISPLAY_VOLTAGE, BRLVGER_WRITE_REQ, voltage,
-	     0, NULL, 0);
-}
-
-#if 0 /* Had problems testing these commands. Not particularly useful anyway.*/
-
-static int
-brlvger_get_display_voltage(struct brlvger_priv *priv)
-{
-	__u8 voltage = 0;
-	int ret = rcvcontrolmsg(priv,
-	    BRLVGER_GET_DISPLAY_VOLTAGE, BRLVGER_READ_REQ, 0,
-	    0, &voltage, 1);
-	if(ret<0)
-		return ret;
-	return voltage;
-}
-
-static int
-brlvger_get_current(struct brlvger_priv *priv)
-{
-	unsigned char data;
-	int ret = rcvcontrolmsg(priv,
-	    BRLVGER_GET_CURRENT,	BRLVGER_READ_REQ,	0,
-	    0, &data, 1);
-	if(ret<0)
-		return ret;
-	return data;
-}
-#endif
--- diff/include/asm-parisc/keyboard.h	2003-10-09 08:47:34.000000000 +0000
+++ source/include/asm-parisc/keyboard.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,82 +0,0 @@
-/*
- *  WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
- *  ---------------------------------------------------------------
- *  This file will be removed as soon as we have converted
- *  hp_psaux.c and hp_keyb.c to the input layer !
- *  
- */
-
-
-/*
- *  linux/include/asm-parisc/keyboard.h
- *
- *  Original by Geert Uytterhoeven
- *  updates by Alex deVries <adevries@thepuffingroup.com>
- *  portions copyright (1999) The Puffin Group
- *  mostly rewritten by Philipp Rumpf <prumpf@tux.org>,
- *   Copyright 2000 Philipp Rumpf
- */
-
-/*
- *  We try to keep the amount of generic code as low as possible -
- *  we want to support all HIL, PS/2, and untranslated USB keyboards
- */
-
-#ifndef _PARISC_KEYBOARD_H
-#define _PARISC_KEYBOARD_H
-
-#ifdef __KERNEL__
-
-#include <linux/kernel.h>
-#include <linux/kd.h>
-
-/*  These are basically the generic functions / variables.  The only
- *  unexpected detail is the initialization sequence for the keyboard
- *  driver is something like this:
- *
- *  detect keyboard port
- *  detect keyboard
- *  call register_kbd_ops 
- *  wait for init_hw
- *
- *  only after init_hw has been called you're allowed to call
- *  handle_scancode.  This means you either have to be extremely
- *  careful or use a global flag or something - I strongly suggest
- *  the latter.    prumpf */
-
-extern struct kbd_ops {
-	int (*setkeycode)(unsigned int, unsigned int);
-	int (*getkeycode)(unsigned int);
-	int (*translate)(unsigned char, unsigned char *, char);
-	char (*unexpected_up)(unsigned char);
-	void (*leds)(unsigned char);
-	void (*init_hw)(void);
-
-	/* Keyboard driver resource allocation  */
-	int (*kbd_request_irq)(void (*handler)(int, void *, struct pt_regs *));
-
-	unsigned char sysrq_key;
-	unsigned char *sysrq_xlate;
-} kbd_ops;
-
-#define kbd_setkeycode		(*kbd_ops->setkeycode)
-#define kbd_getkeycode		(*kbd_ops->getkeycode)
-#define kbd_translate		(*kbd_ops->translate)
-#define kbd_unexpected_up	(*kbd_ops->unexpected_up)
-#define kbd_leds		(*kbd_ops->leds)
-#define kbd_init_hw		(*kbd_ops->init_hw)
-
-#define SYSRQ_KEY		(kbd_ops->sysrq_key)
-#define	kbd_sysrq_xlate		(kbd_ops->sysrq_xlate)
-
-/* Do the actual calls via kbd_ops vector  */
-#define kbd_request_irq(handler) kbd_ops->kbd_request_irq(handler)
-
-extern unsigned char hp_ps2kbd_sysrq_xlate[128]; 	/* from drivers/char/hp_keyb.c */
-
-extern void unregister_kbd_ops(void);
-extern void register_kbd_ops(struct kbd_ops *ops);
-
-#endif /* __KERNEL__ */
-
-#endif /* __ASMPARISC_KEYBOARD_H */
--- diff/include/asm-parisc/md.h	2002-10-16 03:27:50.000000000 +0000
+++ source/include/asm-parisc/md.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,13 +0,0 @@
-/* $Id: md.h,v 1.1.1.1 1999/03/15 19:41:02 pjlahaie Exp $
- * md.h: High speed xor_block operation for RAID4/5 
- *
- */
- 
-#ifndef __ASM_MD_H
-#define __ASM_MD_H
-
-/* #define HAVE_ARCH_XORBLOCK */
-
-#define MD_XORBLOCK_ALIGNMENT	sizeof(long)
-
-#endif /* __ASM_MD_H */
--- diff/include/linux/brlvger.h	2003-06-09 13:18:20.000000000 +0000
+++ source/include/linux/brlvger.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,54 +0,0 @@
-/*
- *      Tieman Voyager braille display USB driver.
- *
- *      Copyright 2001-2002 Stephane Dalton <sdalton@videotron.ca>
- *                      and Stéphane Doyon  <s.doyon@videotron.ca>
- *            Maintained by Stéphane Doyon  <s.doyon@videotron.ca>.
- */
-/*
- *  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 _LINUX_BRLVGER_H
-#define _LINUX_BRLVGER_H
-
-/* Ioctl request codes */
-#define BRLVGER_GET_INFO	0
-#define BRLVGER_DISPLAY_ON	2
-#define BRLVGER_DISPLAY_OFF	3
-#define BRLVGER_BUZZ		4
-
-/* Base minor for the char devices */
-#define BRLVGER_MINOR		128
-
-/* Size of some fields */
-#define BRLVGER_HWVER_SIZE	2
-#define BRLVGER_FWVER_SIZE	200 /* arbitrary, a long string */
-#define BRLVGER_SERIAL_BIN_SIZE	8
-#define BRLVGER_SERIAL_SIZE	((2*BRLVGER_SERIAL_BIN_SIZE)+1)
-
-struct brlvger_info {
-	__u8 driver_version[12];
-	__u8 driver_banner[200];
-
-	__u32 display_length;
-	/* All other char[] fields are strings except this one.
-	   Hardware version: first byte is major, second byte is minor. */
-	__u8 hwver[BRLVGER_HWVER_SIZE];
-	__u8 fwver[BRLVGER_FWVER_SIZE];
-	__u8 serialnum[BRLVGER_SERIAL_SIZE];
-};
-
-#endif
--- diff/scripts/docproc.c	2003-06-30 09:07:24.000000000 +0000
+++ source/scripts/docproc.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,387 +0,0 @@
-/*
- *	docproc is a simple preprocessor for the template files
- *      used as placeholders for the kernel internal documentation.
- *	docproc is used for documentation-frontend and
- *      dependency-generator.
- *	The two usages have in common that they require
- *	some knowledge of the .tmpl syntax, therefore they
- *	are kept together.
- *
- *	documentation-frontend
- *		Scans the template file and call kernel-doc for
- *		all occurrences of ![EIF]file
- *		Beforehand each referenced file are scanned for
- *		any exported sympols "EXPORT_SYMBOL()" statements.
- *		This is used to create proper -function and
- *		-nofunction arguments in calls to kernel-doc.
- *		Usage: docproc doc file.tmpl
- *
- *	dependency-generator:
- *		Scans the template file and list all files
- *		referenced in a format recognized by make.
- *		Usage:	docproc depend file.tmpl
- *		Writes dependency information to stdout
- *		in the following format:
- *		file.tmpl src.c	src2.c
- *		The filenames are obtained from the following constructs:
- *		!Efilename
- *		!Ifilename
- *		!Dfilename
- *		!Ffilename
- *		
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-/* exitstatus is used to keep track of any failing calls to kernel-doc,
- * but execution continues. */
-int exitstatus = 0;
-
-typedef void DFL(char *);
-DFL *defaultline;
-
-typedef void FILEONLY(char * file);
-FILEONLY *internalfunctions;
-FILEONLY *externalfunctions;
-FILEONLY *symbolsonly;
-
-typedef void FILELINE(char * file, char * line);
-FILELINE * singlefunctions;
-FILELINE * entity_system;
-
-#define MAXLINESZ     2048
-#define MAXFILES      250
-#define KERNELDOCPATH "scripts/"
-#define KERNELDOC     "kernel-doc"
-#define DOCBOOK       "-docbook"
-#define FUNCTION      "-function"
-#define NOFUNCTION    "-nofunction"
-
-void usage (void)
-{
-	fprintf(stderr, "Usage: docproc {doc|depend} file\n");
-	fprintf(stderr, "Input is read from file.tmpl. Output is sent to stdout\n");
-	fprintf(stderr, "doc: frontend when generating kernel documentation\n");
-	fprintf(stderr, "depend: generate list of files referenced within file\n");
-}
-
-/*
- * Execute kernel-doc with parameters givin in svec
- */
-void exec_kernel_doc(char **svec)
-{
-	pid_t pid;
-	int ret;
-	/* Make sure output generated so far are flushed */
-	fflush(stdout);
-	switch(pid=fork()) {
-		case -1:
-			perror("fork");
-			exit(1);
-		case  0:
-			execvp(KERNELDOCPATH KERNELDOC, svec);
-			perror("exec " KERNELDOCPATH KERNELDOC);
-			exit(1);
-		default:
-			waitpid(pid, &ret ,0);
-	}
-	if (WIFEXITED(ret))
-		exitstatus |= WEXITSTATUS(ret);
-	else
-		exitstatus = 0xff;
-}
-
-/* Types used to create list of all exported symbols in a number of files */
-struct symbols
-{
-	char *name;
-};
-
-struct symfile
-{
-	char *filename;
-	struct symbols *symbollist;
-	int symbolcnt;
-};
-
-struct symfile symfilelist[MAXFILES];
-int symfilecnt = 0;
-
-void add_new_symbol(struct symfile *sym, char * symname)
-{
-	sym->symbollist =
-          realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *));
-	sym->symbollist[sym->symbolcnt++].name = strdup(symname);
-}
-
-/* Add a filename to the list */
-struct symfile * add_new_file(char * filename)
-{
-	symfilelist[symfilecnt++].filename = strdup(filename);
-	return &symfilelist[symfilecnt - 1];					
-}
-/* Check if file already are present in the list */
-struct symfile * filename_exist(char * filename)
-{
-	int i;
-	for (i=0; i < symfilecnt; i++)
-		if (strcmp(symfilelist[i].filename, filename) == 0)
-			return &symfilelist[i];
-	return NULL;
-}
-
-/*
- * List all files referenced within the template file.
- * Files are separated by tabs.
- */
-void adddep(char * file)		   { printf("\t%s", file); }
-void adddep2(char * file, char * line)     { line = line; adddep(file); }
-void noaction(char * line)		   { line = line; }
-void noaction2(char * file, char * line)   { file = file; line = line; }
-
-/* Echo the line without further action */
-void printline(char * line)               { printf("%s", line); }
-
-/* 
- * Find all symbols exported with EXPORT_SYMBOL and EXPORT_SYMBOL_GPL 
- * in filename.
- * All symbols located are stored in symfilelist.
- */
-void find_export_symbols(char * filename)
-{
-	FILE * fp;
-	struct symfile *sym;
-	char line[MAXLINESZ];
-	if (filename_exist(filename) == NULL) {
-		sym = add_new_file(filename);
-		fp = fopen(filename, "r");
-		if (fp == NULL)
-		{
-			fprintf(stderr, "docproc: ");
-			perror(filename);
-		}
-		while(fgets(line, MAXLINESZ, fp)) {
-			char *p;
-			char *e;
-			if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != 0) ||
-                            ((p = strstr(line, "EXPORT_SYMBOL")) != 0)) {
-				/* Skip EXPORT_SYMBOL{_GPL} */
-				while (isalnum(*p) || *p == '_')
-					p++;
-				/* Remove paranteses and additional ws */
-				while (isspace(*p))
-					p++;
-				if (*p != '(')
-					continue; /* Syntax error? */
-				else
-					p++;
-				while (isspace(*p))
-					p++;
-				e = p;
-				while (isalnum(*e) || *e == '_')
-					e++;
-				*e = '\0';
-				add_new_symbol(sym, p);
-			}
-		}
-		fclose(fp);
-	}
-}
-
-/*
- * Document all external or internal functions in a file.
- * Call kernel-doc with following parameters:
- * kernel-doc -docbook -nofunction function_name1 filename
- * function names are obtained from all the the src files
- * by find_export_symbols.
- * intfunc uses -nofunction
- * extfunc uses -function
- */
-void docfunctions(char * filename, char * type)
-{
-	int i,j;
-	int symcnt = 0;
-	int idx = 0;
-	char **vec;
-	
-	for (i=0; i <= symfilecnt; i++)
-		symcnt += symfilelist[i].symbolcnt;
-	vec = malloc((2 + 2 * symcnt + 2) * sizeof(char*));
-	if (vec == NULL) {
-		perror("docproc: ");
-		exit(1);
-	}
-	vec[idx++] = KERNELDOC;
-	vec[idx++] = DOCBOOK;
-	for (i=0; i < symfilecnt; i++) {
-		struct symfile * sym = &symfilelist[i];
-		for (j=0; j < sym->symbolcnt; j++) {
-			vec[idx++]     = type;
-			vec[idx++] = sym->symbollist[j].name;
-		}
-	}
-	vec[idx++]     = filename;
-	vec[idx] = NULL;
-	printf("<!-- %s -->\n", filename);
-	exec_kernel_doc(vec);
-	fflush(stdout);
-	free(vec);
-}
-void intfunc(char * filename) {	docfunctions(filename, NOFUNCTION); }
-void extfunc(char * filename) { docfunctions(filename, FUNCTION);   }
-
-/*
- * Document spåecific function(s) in a file.
- * Call kernel-doc with the following parameters:
- * kernel-doc -docbook -function function1 [-function function2]
- */
-void singfunc(char * filename, char * line)
-{
-	char *vec[200]; /* Enough for specific functions */
-        int i, idx = 0;
-        int startofsym = 1;
-	vec[idx++] = KERNELDOC;
-	vec[idx++] = DOCBOOK;
-
-        /* Split line up in individual parameters preceeded by FUNCTION */        
-        for (i=0; line[i]; i++) {
-                if (isspace(line[i])) {
-                        line[i] = '\0';
-                        startofsym = 1;
-                        continue;
-                }
-                if (startofsym) {
-                        startofsym = 0;
-                        vec[idx++] = FUNCTION;
-                        vec[idx++] = &line[i];
-                }
-        }
-	vec[idx++] = filename;
-	vec[idx] = NULL;
-	exec_kernel_doc(vec);
-}
-
-/*
- * Parse file, calling action specific functions for:
- * 1) Lines containing !E
- * 2) Lines containing !I
- * 3) Lines containing !D
- * 4) Lines containing !F
- * 5) Default lines - lines not matching the above
- */
-void parse_file(FILE *infile)
-{
-	char line[MAXLINESZ];
-	char * s;
-	while(fgets(line, MAXLINESZ, infile)) {
-		if (line[0] == '!') {
-			s = line + 2;
-			switch (line[1]) {
-				case 'E':
-					while (*s && !isspace(*s)) s++;
-					*s = '\0';
-					externalfunctions(line+2);
-					break;
-				case 'I':
-					while (*s && !isspace(*s)) s++;
-					*s = '\0';
-					internalfunctions(line+2);
-					break;
-				case 'D':
-					while (*s && !isspace(*s)) s++;
-                                        *s = '\0';
-                                        symbolsonly(line+2);
-                                        break;
-				case 'F':
-					/* filename */
-					while (*s && !isspace(*s)) s++;
-					*s++ = '\0';
-                                        /* function names */
-					while (isspace(*s))
-						s++;
-					singlefunctions(line +2, s);
-					break;
-				default:
-					defaultline(line);
-			}
-		}
-		else {
-			defaultline(line);
-		}
-	}
-	fflush(stdout);
-}
-		
-
-int main(int argc, char *argv[])
-{
-	FILE * infile;
-	if (argc != 3) {
-		usage();
-		exit(1);
-	}
-	/* Open file, exit on error */
-	infile = fopen(argv[2], "r");
-        if (infile == NULL) {
-                fprintf(stderr, "docproc: ");
-                perror(argv[2]);
-                exit(2);
-        }
-
-	if (strcmp("doc", argv[1]) == 0)
-	{
-		/* Need to do this in two passes.
-		 * First pass is used to collect all symbols exported
-		 * in the various files.
-		 * Second pass generate the documentation.
-		 * This is required because function are declared
-		 * and exported in different files :-((
-		 */
-		/* Collect symbols */
-		defaultline       = noaction;
-		internalfunctions = find_export_symbols;
-		externalfunctions = find_export_symbols;
-		symbolsonly       = find_export_symbols;
-		singlefunctions   = noaction2;
-		parse_file(infile);
-
-		/* Rewind to start from beginning of file again */
-		fseek(infile, 0, SEEK_SET);
-		defaultline       = printline;
-		internalfunctions = intfunc;
-		externalfunctions = extfunc;
-		symbolsonly       = printline;
-		singlefunctions   = singfunc;
-		
-		parse_file(infile);
-	}
-	else if (strcmp("depend", argv[1]) == 0)
-	{
-		/* Create first part of dependency chain
-		 * file.tmpl */
-		printf("%s\t", argv[2]);
-		defaultline       = noaction;
-		internalfunctions = adddep;
-		externalfunctions = adddep;
-		symbolsonly       = adddep;
-		singlefunctions   = adddep2;
-		parse_file(infile);
-		printf("\n");
-	}
-	else
-	{
-		fprintf(stderr, "Unknown option: %s\n", argv[1]);
-		exit(1);
-	}
-	fclose(infile);
-	fflush(stdout);
-	return exitstatus;
-}
-
--- diff/scripts/fixdep.c	2003-06-09 13:18:21.000000000 +0000
+++ source/scripts/fixdep.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,381 +0,0 @@
-/*
- * "Optimize" a list of dependencies as spit out by gcc -MD 
- * for the kernel build
- * ===========================================================================
- *
- * Author       Kai Germaschewski
- * Copyright    2002 by Kai Germaschewski  <kai.germaschewski@gmx.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- *
- * Introduction:
- * 
- * gcc produces a very nice and correct list of dependencies which
- * tells make when to remake a file.
- *
- * To use this list as-is however has the drawback that virtually
- * every file in the kernel includes <linux/config.h> which then again
- * includes <linux/autoconf.h>
- *
- * If the user re-runs make *config, linux/autoconf.h will be
- * regenerated.  make notices that and will rebuild every file which
- * includes autoconf.h, i.e. basically all files. This is extremely
- * annoying if the user just changed CONFIG_HIS_DRIVER from n to m.
- * 
- * So we play the same trick that "mkdep" played before. We replace
- * the dependency on linux/autoconf.h by a dependency on every config
- * option which is mentioned in any of the listed prequisites.
- *  
- * To be exact, split-include populates a tree in include/config/,
- * e.g. include/config/his/driver.h, which contains the #define/#undef
- * for the CONFIG_HIS_DRIVER option.
- *
- * So if the user changes his CONFIG_HIS_DRIVER option, only the objects
- * which depend on "include/linux/config/his/driver.h" will be rebuilt,
- * so most likely only his driver ;-) 
- *
- * The idea above dates, by the way, back to Michael E Chastain, AFAIK.
- * 
- * So to get dependencies right, there two issues:
- * o if any of the files the compiler read changed, we need to rebuild
- * o if the command line given to the compile the file changed, we
- *   better rebuild as well.
- *
- * The former is handled by using the -MD output, the later by saving
- * the command line used to compile the old object and comparing it
- * to the one we would now use.
- *
- * Again, also this idea is pretty old and has been discussed on
- * kbuild-devel a long time ago. I don't have a sensibly working
- * internet connection right now, so I rather don't mention names
- * without double checking.
- *
- * This code here has been based partially based on mkdep.c, which
- * says the following about its history:
- *
- *   Copyright abandoned, Michael Chastain, <mailto:mec@shout.net>.
- *   This is a C version of syncdep.pl by Werner Almesberger.
- *
- *
- * It is invoked as
- *
- *   fixdep <depfile> <target> <cmdline>
- *
- * and will read the dependency file <depfile>
- *
- * The transformed dependency snipped is written to stdout.
- *
- * It first generates a line
- *
- *   cmd_<target> = <cmdline>
- *
- * and then basically copies the .<target>.d file to stdout, in the
- * process filtering out the dependency on linux/autoconf.h and adding
- * dependencies on include/config/my/option.h for every
- * CONFIG_MY_OPTION encountered in any of the prequisites.
- *
- * It will also filter out all the dependencies on *.ver. We need
- * to make sure that the generated version checksum are globally up
- * to date before even starting the recursive build, so it's too late
- * at this point anyway.
- *
- * The algorithm to grep for "CONFIG_..." is bit unusual, but should
- * be fast ;-) We don't even try to really parse the header files, but
- * merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will
- * be picked up as well. It's not a problem with respect to
- * correctness, since that can only give too many dependencies, thus
- * we cannot miss a rebuild. Since people tend to not mention totally
- * unrelated CONFIG_ options all over the place, it's not an
- * efficiency problem either.
- * 
- * (Note: it'd be easy to port over the complete mkdep state machine,
- *  but I don't think the added complexity is worth it)
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <limits.h>
-#include <ctype.h>
-#include <netinet/in.h>
-
-#define INT_CONF ntohl(0x434f4e46)
-#define INT_ONFI ntohl(0x4f4e4649)
-#define INT_NFIG ntohl(0x4e464947)
-#define INT_FIG_ ntohl(0x4649475f)
-
-char *target;
-char *depfile;
-char *cmdline;
-
-void usage(void)
-
-{
-	fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
-	exit(1);
-}
-
-void print_cmdline(void)
-{
-	printf("cmd_%s := %s\n\n", target, cmdline);
-}
-
-char * str_config  = NULL;
-int    size_config = 0;
-int    len_config  = 0;
-
-/*
- * Grow the configuration string to a desired length.
- * Usually the first growth is plenty.
- */
-void grow_config(int len)
-{
-	while (len_config + len > size_config) {
-		if (size_config == 0)
-			size_config = 2048;
-		str_config = realloc(str_config, size_config *= 2);
-		if (str_config == NULL)
-			{ perror("fixdep:malloc"); exit(1); }
-	}
-}
-
-
-
-/*
- * Lookup a value in the configuration string.
- */
-int is_defined_config(const char * name, int len)
-{
-	const char * pconfig;
-	const char * plast = str_config + len_config - len;
-	for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) {
-		if (pconfig[ -1] == '\n'
-		&&  pconfig[len] == '\n'
-		&&  !memcmp(pconfig, name, len))
-			return 1;
-	}
-	return 0;
-}
-
-/*
- * Add a new value to the configuration string.
- */
-void define_config(const char * name, int len)
-{
-	grow_config(len + 1);
-
-	memcpy(str_config+len_config, name, len);
-	len_config += len;
-	str_config[len_config++] = '\n';
-}
-
-/*
- * Clear the set of configuration strings.
- */
-void clear_config(void)
-{
-	len_config = 0;
-	define_config("", 0);
-}
-
-/*
- * Record the use of a CONFIG_* word.
- */
-void use_config(char *m, int slen)
-{
-	char s[PATH_MAX];
-	char *p;
-
-	if (is_defined_config(m, slen))
-	    return;
-
-	define_config(m, slen);
-
-	memcpy(s, m, slen); s[slen] = 0;
-
-	for (p = s; p < s + slen; p++) {
-		if (*p == '_')
-			*p = '/';
-		else
-			*p = tolower((unsigned char)*p);
-	}
-	printf("    $(wildcard include/config/%s.h) \\\n", s);
-}
-
-void parse_config_file(char *map, size_t len)
-{
-	int *end = (int *) (map + len);
-	/* start at +1, so that p can never be < map */
-	int *m   = (int *) map + 1;
-	char *p, *q;
-
-	for (; m < end; m++) {
-		if (*m == INT_CONF) { p = (char *) m  ; goto conf; }
-		if (*m == INT_ONFI) { p = (char *) m-1; goto conf; }
-		if (*m == INT_NFIG) { p = (char *) m-2; goto conf; }
-		if (*m == INT_FIG_) { p = (char *) m-3; goto conf; }
-		continue;
-	conf:
-		if (p > map + len - 7)
-			continue;
-		if (memcmp(p, "CONFIG_", 7))
-			continue;
-		for (q = p + 7; q < map + len; q++) {
-			if (!(isalnum(*q) || *q == '_'))
-				goto found;
-		}
-		continue;
-
-	found: 
-		use_config(p+7, q-p-7);
-	}
-}
-
-/* test is s ends in sub */
-int strrcmp(char *s, char *sub)
-{
-	int slen = strlen(s);
-	int sublen = strlen(sub);
-  
-	if (sublen > slen)
-		return 1;
-	
-	return memcmp(s + slen - sublen, sub, sublen);
-}
-
-void do_config_file(char *filename)
-{
-	struct stat st;
-	int fd;
-	void *map;
-
-	fd = open(filename, O_RDONLY);
-	if (fd < 0) {
-		fprintf(stderr, "fixdep: ");
-		perror(filename);
-		exit(2);
-	}
-	fstat(fd, &st);
-	if (st.st_size == 0) {
-		close(fd);
-		return;
-	}
-	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
-	if ((long) map == -1) {
-		perror("fixdep: mmap");
-		close(fd);
-		return;
-	}
-	
-	parse_config_file(map, st.st_size);
-
-	munmap(map, st.st_size);
-
-	close(fd);
-}
-
-void parse_dep_file(void *map, size_t len)
-{
-	char *m = map;
-	char *end = m + len;
-	char *p;
-	char s[PATH_MAX];
-
-	p = strchr(m, ':');
-	if (!p) {
-		fprintf(stderr, "fixdep: parse error\n");
-		exit(1);
-	}
-	memcpy(s, m, p-m); s[p-m] = 0;
-	printf("deps_%s := \\\n", target);
-	m = p+1;
-
-	clear_config();
-
-	while (m < end) {
-		while (m < end && (*m == ' ' || *m == '\\' || *m == '\n'))
-			m++;
-		p = m;
-		while (p < end && *p != ' ') p++;
-		if (p == end) {
-			do p--; while (!isalnum(*p));
-			p++;
-		}
-		memcpy(s, m, p-m); s[p-m] = 0;
-		if (strrcmp(s, "include/linux/autoconf.h") &&
-		    strrcmp(s, ".ver")) {
-			printf("  %s \\\n", s);
-			do_config_file(s);
-		}
-		m = p + 1;
-	}
-	printf("\n%s: $(deps_%s)\n\n", target, target);
-	printf("$(deps_%s):\n", target);
-}
-
-void print_deps(void)
-{
-	struct stat st;
-	int fd;
-	void *map;
-
-	fd = open(depfile, O_RDONLY);
-	if (fd < 0) {
-		fprintf(stderr, "fixdep: ");
-		perror(depfile);
-		exit(2);
-	}
-	fstat(fd, &st);
-	if (st.st_size == 0) {
-		fprintf(stderr,"fixdep: %s is empty\n",depfile);
-		close(fd);
-		return;
-	}
-	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
-	if ((long) map == -1) {
-		perror("fixdep: mmap");
-		close(fd);
-		return;
-	}
-	
-	parse_dep_file(map, st.st_size);
-
-	munmap(map, st.st_size);
-
-	close(fd);
-}
-
-void traps(void)
-{
-	static char test[] __attribute__((aligned(sizeof(int)))) = "CONF";
-
-	if (*(int *)test != INT_CONF) {
-		fprintf(stderr, "fixdep: sizeof(int) != 4 or wrong endianess? %#x\n",
-			*(int *)test);
-		exit(2);
-	}
-}
-
-int main(int argc, char *argv[])
-{
-	traps();
-
-	if (argc != 4)
-		usage();
-		
-	depfile = argv[1];
-	target = argv[2];
-	cmdline = argv[3];
-
-	print_cmdline();
-	print_deps();
-
-	return 0;
-}
--- diff/scripts/split-include.c	2002-10-16 03:27:52.000000000 +0000
+++ source/scripts/split-include.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,226 +0,0 @@
-/*
- * split-include.c
- *
- * Copyright abandoned, Michael Chastain, <mailto:mec@shout.net>.
- * This is a C version of syncdep.pl by Werner Almesberger.
- *
- * This program takes autoconf.h as input and outputs a directory full
- * of one-line include files, merging onto the old values.
- *
- * Think of the configuration options as key-value pairs.  Then there
- * are five cases:
- *
- *    key      old value   new value   action
- *
- *    KEY-1    VALUE-1     VALUE-1     leave file alone
- *    KEY-2    VALUE-2A    VALUE-2B    write VALUE-2B into file
- *    KEY-3    -           VALUE-3     write VALUE-3  into file
- *    KEY-4    VALUE-4     -           write an empty file
- *    KEY-5    (empty)     -           leave old empty file alone
- */
-
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#define ERROR_EXIT(strExit)						\
-    {									\
-	const int errnoSave = errno;					\
-	fprintf(stderr, "%s: ", str_my_name);				\
-	errno = errnoSave;						\
-	perror((strExit));						\
-	exit(1);							\
-    }
-
-
-
-int main(int argc, const char * argv [])
-{
-    const char * str_my_name;
-    const char * str_file_autoconf;
-    const char * str_dir_config;
-
-    FILE * fp_config;
-    FILE * fp_target;
-    FILE * fp_find;
-
-    int buffer_size;
-
-    char * line;
-    char * old_line;
-    char * list_target;
-    char * ptarget;
-
-    struct stat stat_buf;
-
-    /* Check arg count. */
-    if (argc != 3)
-    {
-	fprintf(stderr, "%s: wrong number of arguments.\n", argv[0]);
-	exit(1);
-    }
-
-    str_my_name       = argv[0];
-    str_file_autoconf = argv[1];
-    str_dir_config    = argv[2];
-
-    /* Find a buffer size. */
-    if (stat(str_file_autoconf, &stat_buf) != 0)
-	ERROR_EXIT(str_file_autoconf);
-    buffer_size = 2 * stat_buf.st_size + 4096;
-
-    /* Allocate buffers. */
-    if ( (line        = malloc(buffer_size)) == NULL
-    ||   (old_line    = malloc(buffer_size)) == NULL
-    ||   (list_target = malloc(buffer_size)) == NULL )
-	ERROR_EXIT(str_file_autoconf);
-
-    /* Open autoconfig file. */
-    if ((fp_config = fopen(str_file_autoconf, "r")) == NULL)
-	ERROR_EXIT(str_file_autoconf);
-
-    /* Make output directory if needed. */
-    if (stat(str_dir_config, &stat_buf) != 0)
-    {
-	if (mkdir(str_dir_config, 0755) != 0)
-	    ERROR_EXIT(str_dir_config);
-    }
-
-    /* Change to output directory. */
-    if (chdir(str_dir_config) != 0)
-	ERROR_EXIT(str_dir_config);
-	
-    /* Put initial separator into target list. */
-    ptarget = list_target;
-    *ptarget++ = '\n';
-
-    /* Read config lines. */
-    while (fgets(line, buffer_size, fp_config))
-    {
-	const char * str_config;
-	int is_same;
-	int itarget;
-
-	if (line[0] != '#')
-	    continue;
-	if ((str_config = strstr(line, "CONFIG_")) == NULL)
-	    continue;
-
-	/* Make the output file name. */
-	str_config += sizeof("CONFIG_") - 1;
-	for (itarget = 0; !isspace(str_config[itarget]); itarget++)
-	{
-	    int c = (unsigned char) str_config[itarget];
-	    if (isupper(c)) c = tolower(c);
-	    if (c == '_')   c = '/';
-	    ptarget[itarget] = c;
-	}
-	ptarget[itarget++] = '.';
-	ptarget[itarget++] = 'h';
-	ptarget[itarget++] = '\0';
-
-	/* Check for existing file. */
-	is_same = 0;
-	if ((fp_target = fopen(ptarget, "r")) != NULL)
-	{
-	    fgets(old_line, buffer_size, fp_target);
-	    if (fclose(fp_target) != 0)
-		ERROR_EXIT(ptarget);
-	    if (!strcmp(line, old_line))
-		is_same = 1;
-	}
-
-	if (!is_same)
-	{
-	    /* Auto-create directories. */
-	    int islash;
-	    for (islash = 0; islash < itarget; islash++)
-	    {
-		if (ptarget[islash] == '/')
-		{
-		    ptarget[islash] = '\0';
-		    if (stat(ptarget, &stat_buf) != 0
-		    &&  mkdir(ptarget, 0755)     != 0)
-			ERROR_EXIT( ptarget );
-		    ptarget[islash] = '/';
-		}
-	    }
-
-	    /* Write the file. */
-	    if ((fp_target = fopen(ptarget, "w" )) == NULL)
-		ERROR_EXIT(ptarget);
-	    fputs(line, fp_target);
-	    if (ferror(fp_target) || fclose(fp_target) != 0)
-		ERROR_EXIT(ptarget);
-	}
-
-	/* Update target list */
-	ptarget += itarget;
-	*(ptarget-1) = '\n';
-    }
-
-    /*
-     * Close autoconfig file.
-     * Terminate the target list.
-     */
-    if (fclose(fp_config) != 0)
-	ERROR_EXIT(str_file_autoconf);
-    *ptarget = '\0';
-
-    /*
-     * Fix up existing files which have no new value.
-     * This is Case 4 and Case 5.
-     *
-     * I re-read the tree and filter it against list_target.
-     * This is crude.  But it avoids data copies.  Also, list_target
-     * is compact and contiguous, so it easily fits into cache.
-     *
-     * Notice that list_target contains strings separated by \n,
-     * with a \n before the first string and after the last.
-     * fgets gives the incoming names a terminating \n.
-     * So by having an initial \n, strstr will find exact matches.
-     */
-
-    fp_find = popen("find * -type f -name \"*.h\" -print", "r");
-    if (fp_find == 0)
-	ERROR_EXIT( "find" );
-
-    line[0] = '\n';
-    while (fgets(line+1, buffer_size, fp_find))
-    {
-	if (strstr(list_target, line) == NULL)
-	{
-	    /*
-	     * This is an old file with no CONFIG_* flag in autoconf.h.
-	     */
-
-	    /* First strip the \n. */
-	    line[strlen(line)-1] = '\0';
-
-	    /* Grab size. */
-	    if (stat(line+1, &stat_buf) != 0)
-		ERROR_EXIT(line);
-
-	    /* If file is not empty, make it empty and give it a fresh date. */
-	    if (stat_buf.st_size != 0)
-	    {
-		if ((fp_target = fopen(line+1, "w")) == NULL)
-		    ERROR_EXIT(line);
-		if (fclose(fp_target) != 0)
-		    ERROR_EXIT(line);
-	    }
-	}
-    }
-
-    if (pclose(fp_find) != 0)
-	ERROR_EXIT("find");
-
-    return 0;
-}
